- Posts: 7
- Joined: 16-December 17
- Gender:Not Telling
- Project:Sonic Union

This is my first topic!

~~Unfortunately I was unable to find the c equivalent to the bset, bclr, bchg, bvc and bvs..~~ No, it was just laziness.

If you want to know how to do ROL (bit rotate left) and ROR (bit rotate right), look: there.

Variable width

Local variables

Conditions

Addiction and subtraction

The clear, swap and exchange instruction

Bitwise operators

The neg and ext

Multiplication and division

Branch on sign

If you want to know how to do ROL (bit rotate left) and ROR (bit rotate right), look: there.

Variable width

Spoiler

Most 68k assembly instructions ends with ".something", it can be:

.b: BYTE (8-bit, int8_t, char)

.w: WORD (16-bit, int16_t, short)

.l: LONG (32-bit, int32_t, int (on 32-bit and 64-bit systems), long (on 16-bit systems))

Since it's a 16-bit system, there's no natural 64-bit integer.

Most 68k assembly instructions ends with ".something", it can be:

.b: BYTE (8-bit, int8_t, char)

.w: WORD (16-bit, int16_t, short)

.l: LONG (32-bit, int32_t, int (on 32-bit and 64-bit systems), long (on 16-bit systems))

Since it's a 16-bit system, there's no natural 64-bit integer.

Local variables

Spoiler

Consider the following 68k code:

Here we're moving the value of the constant 'hello' to the register d0 and we're setting the value of the constant 'world' to the register d1.

(move long #hello to d0)

(move long #world to d1)

Translating it we get this:

~~You probably wondered (why the register keyword?), simple. It tells the compiler that the variable value should be a register (if possible) instead of being allocated in the stack. This keyword is not needed when this is a release build though. (which normally has the O2 build option).~~

Nevermind, it shows a warning in c17 target.

Consider the following 68k code:

Generic: move.l #hello, d0 move.l #world, d1

Here we're moving the value of the constant 'hello' to the register d0 and we're setting the value of the constant 'world' to the register d1.

(move long #hello to d0)

(move long #world to d1)

Translating it we get this:

int32_t d0; int32_t d1; d0 = hello; d1 = world;

Nevermind, it shows a warning in c17 target.

Conditions

Spoiler

Instructions:

cmp.something y, z: "Compare the register z with register x".

cmpi.something y, z: "Compare the register z with short y"

tst.something y: "Test if register y is zero"

Signed branches:

beq x: branch (goto x) if the cmp x, y are equal.

bne x: branch (goto x) if the cmp x, y are not equal.

bge x: branch (goto x) if the cmp x is greater or equal to y.

bgt x: branch (goto x) if the cmp x is greater than y.

ble x: branch (goto x) if the cmp x is less or equal to y.

blt x: branch (goto x) if the cmp x is less or equal to y.

Unsigned branches:

bcc x: branch (goto x) if the cmp x is greater or equal to y.

bhi x: branch (goto x) if the cmp x is greater than y.

bls x: branch (goto x) if the cmp x is less or equal to y.

bcs x: branch (goto x) if the cmp x is less or equal to y.

Consider the following code:

Translating, we get:

...But it's wrong. Because there's a useless label there, which makes the code ugly (OH NO). So, to translate it we should negate the compare instructions! Look:

Instructions:

cmp.something y, z: "Compare the register z with register x".

cmpi.something y, z: "Compare the register z with short y"

tst.something y: "Test if register y is zero"

Signed branches:

beq x: branch (goto x) if the cmp x, y are equal.

bne x: branch (goto x) if the cmp x, y are not equal.

bge x: branch (goto x) if the cmp x is greater or equal to y.

bgt x: branch (goto x) if the cmp x is greater than y.

ble x: branch (goto x) if the cmp x is less or equal to y.

blt x: branch (goto x) if the cmp x is less or equal to y.

Unsigned branches:

bcc x: branch (goto x) if the cmp x is greater or equal to y.

bhi x: branch (goto x) if the cmp x is greater than y.

bls x: branch (goto x) if the cmp x is less or equal to y.

bcs x: branch (goto x) if the cmp x is less or equal to y.

Consider the following code:

Generic: move.l #hello, d0 move.l #world, d1 cmp.l d0, d1 beq.s Generic2 move.l #$0, d0 Generic2: move.l #$0, d1

Translating, we get:

int d0 = hello; int d1 = world; if (d0 == d1) { goto Generic2; } d0 = 0; Generic2: d1 = 0;

...But it's wrong. Because there's a useless label there, which makes the code ugly (OH NO). So, to translate it we should negate the compare instructions! Look:

int d0 = hello; int d1 = world; if (d0 != d1) { d0 = 0; } d1 = 0;

Addiction and subtraction

Spoiler

It's easy.

Instructions:

add.something y, z: "Add register y to register z".

addi.something y, z: "Add short y to register z"

add.something x, y(z): "Add register x to adress (y + z)"

addi.something x, y(z): "Add short x to adress (y + z)"

add.something y, z: "Subtract register y from register z".

addi.something y, z: "Subtract short y from register z"

add.something x, y(z): "Subtract register x from adress (y + z)"

addi.something x, y(z): "Subtract short x from adress (y + z)"

The following 68k code:

Translated should be like this:

Don't forget that a POINTER points to a ADRESS.

It's easy.

Instructions:

add.something y, z: "Add register y to register z".

addi.something y, z: "Add short y to register z"

add.something x, y(z): "Add register x to adress (y + z)"

addi.something x, y(z): "Add short x to adress (y + z)"

add.something y, z: "Subtract register y from register z".

addi.something y, z: "Subtract short y from register z"

add.something x, y(z): "Subtract register x from adress (y + z)"

addi.something x, y(z): "Subtract short x from adress (y + z)"

The following 68k code:

add.b d0, d0 add.b #$0001, d0 add.b d0, (a0) add.b #$0001, (a0) sub.b d0, d0 subi.b #$0001, (a0) sub.b d0, (d1) subi.b #$0001, (a0)

Translated should be like this:

char d0; char* a0; d0 += d0; d0 += 0x0001; *a0 += d0; *a0 += 0x0001; d0 -= d0; d0 -= 0x0001; (*a0) -= d0; (*a0) -= 0x0001;

Don't forget that a POINTER points to a ADRESS.

The clear, swap and exchange instruction

Spoiler

Instructions:

clr.something y: sets zero to the value of y. (x should be l or w or b)

swap x: swaps the upper word (0xXXXX0000) with the lower word (0x0000XXXX) of register x.

exg.something y, z: swaps register y with register z

clr is basically:

Swap is just a shift trick, it's like this:

(x & 0xFFFF0000) >> 16 is anding x to 0xFFFF0000 and then shifting to right by 16 bits, so, if the value of x is 0xDEADBEEF, after doing this it's value will be 0x0000DEAD.

(x << 16) is shifting x to left by 16 bits, so, if the value of x is 0xDEADBEEF, after doing this it's value will be 0xBEEF0000.

After doing the two operations, you will "OR (|)" them to get the final result. (0xBEEF0000 | 0x0000DEAD = 0xBEEFDEAD);

Instructions:

clr.something y: sets zero to the value of y. (x should be l or w or b)

swap x: swaps the upper word (0xXXXX0000) with the lower word (0x0000XXXX) of register x.

exg.something y, z: swaps register y with register z

clr is basically:

x = 0; // Clear x

Swap is just a shift trick, it's like this:

x = ((x & 0xFFFF0000) >> 16) | (x << 16);

(x & 0xFFFF0000) >> 16 is anding x to 0xFFFF0000 and then shifting to right by 16 bits, so, if the value of x is 0xDEADBEEF, after doing this it's value will be 0x0000DEAD.

(x << 16) is shifting x to left by 16 bits, so, if the value of x is 0xDEADBEEF, after doing this it's value will be 0xBEEF0000.

After doing the two operations, you will "OR (|)" them to get the final result. (0xBEEF0000 | 0x0000DEAD = 0xBEEFDEAD);

Bitwise operators

Spoiler

Another easy one.

Instructions:

not.something y: nots register y (!y).

and.something y, z: ands register y to register z.

andi.something y, z: ands short y to register z.

and.something x, y(z): ands register x to the adress in register y + short z.

andi.something x, y(z): ands short x to the adress in register y + short z.

or.something y, z: ors register y to register z.

ori.something y, z: ors short y to register z.

or.something x, y(z): ors register x to the adress in register y + short z.

ori.something x, y(z): ors short x to the adress in register y + short z.

xor.something y, z: xors register y to register z.

xori.something y, z: xors short y to register z.

xor.something x, y(z): xors register x to the adress in register y + short z.

xori.something x, y(z): xors short x to the adress in register y + short z.

The following 68k code:

Translated should be like this:

Another easy one.

Instructions:

not.something y: nots register y (!y).

and.something y, z: ands register y to register z.

andi.something y, z: ands short y to register z.

and.something x, y(z): ands register x to the adress in register y + short z.

andi.something x, y(z): ands short x to the adress in register y + short z.

or.something y, z: ors register y to register z.

ori.something y, z: ors short y to register z.

or.something x, y(z): ors register x to the adress in register y + short z.

ori.something x, y(z): ors short x to the adress in register y + short z.

xor.something y, z: xors register y to register z.

xori.something y, z: xors short y to register z.

xor.something x, y(z): xors register x to the adress in register y + short z.

xori.something x, y(z): xors short x to the adress in register y + short z.

The following 68k code:

add.b $#0x0002, d0

Translated should be like this:

d0 ^= 0x0002;

The neg and ext

Spoiler

Instructions:

neg.something x negates x (positive becomes negative and negative becomes positive)

ext.something x extends x (will be explained later)

The neg instruction is basically this:

The ext instruction is already handled in c, it extends for example, char to short and short to int.

Instructions:

neg.something x negates x (positive becomes negative and negative becomes positive)

ext.something x extends x (will be explained later)

The neg instruction is basically this:

x = -x;

The ext instruction is already handled in c, it extends for example, char to short and short to int.

Multiplication and division

Spoiler

muls.something y, z: multiplies z with y. (x should be l or w or b)

mulu.something y, z: multiplies z with y. (x should be l or w or b) (unsigned)

divs.something y, z: divides z with y, the remainder will be saved in the upper word of z and the quotient will be saved in the lower word. (x should be l or w or b)

divu.something y, z: divides z with y, the remainder will be saved in the upper word of z and the quotient will be saved in the lower word. (x should be l or w or b) (unsigned)

The division is clearly different in c.

In this c code, we're declaring a variable with the result value of the division of d1 with 2 and declaring another variable with the remainder of the division d1 with 2 (modulo).

muls.something y, z: multiplies z with y. (x should be l or w or b)

mulu.something y, z: multiplies z with y. (x should be l or w or b) (unsigned)

divs.something y, z: divides z with y, the remainder will be saved in the upper word of z and the quotient will be saved in the lower word. (x should be l or w or b)

divu.something y, z: divides z with y, the remainder will be saved in the upper word of z and the quotient will be saved in the lower word. (x should be l or w or b) (unsigned)

The division is clearly different in c.

int d0 = d1 / 2; int d2 = d1 % 2;

In this c code, we're declaring a variable with the result value of the division of d1 with 2 and declaring another variable with the remainder of the division d1 with 2 (modulo).

Branch on sign

Spoiler

Instructions:

bpl x: branch (goto x) if the result of cmp x, y (x minus y) is positive.

bmi x: branch (goto x) if the result of cmp x, y (x minus y) is negative.

The following 68k code:

Will look like this:

How to find if a label is a function or just a... label.

Set conditions

[spoiler]

Instructions:

seq x: set x if the cmp x, y are equal.

sne x: set x if the cmp x, y are not equal.

spl x: set x if the result of cmp x, y (x minus y) is positive.

smi x: set x if the result of cmp x, y (x minus y) is negative.

sge x: set x if the cmp x is greater or equal to y.

sgt x: set x if the cmp x is greater than y.

sle x: set x if the cmp x is less or equal to y.

slt x: set x if the cmp x is less or equal to y.

scc x: set x if the cmp x is greater or equal to y. (unsigned)

shi x: set x if the cmp x is greater than y. (unsigned)

sls x: set x if the cmp x is less or equal to y. (unsigned)

scs x: set x if the cmp x is less or equal to y. (unsigned)

for example, seq d0 sets d0 to 0xFFFFFFFF if it's true, otherwise it's cleared (set to zero).

Consider the following code

Translating it, we get:

Instructions:

bpl x: branch (goto x) if the result of cmp x, y (x minus y) is positive.

bmi x: branch (goto x) if the result of cmp x, y (x minus y) is negative.

The following 68k code:

Generic: move.l #hello, d0 move.l #world, d1 cmp.l d0, d1 beq.s Generic2 move.l #$0, d0 Generic2: move.l #$0, d1 cmpi.l #0x0020, d0 bpl Generic4 Generic3: clr.l d0 Generic4: clr.l d1

Will look like this:

int d0 = hello; int d1 = world; if (d0 != d1) { d0 = 0; } d1 = 0; if (d0 - 0x0020 < 0) { d0 = 0; } d1 = 0;

How to find if a label is a function or just a... label.

Spoiler

Routines and subroutines in 68k are functions, but they don't have a difference to labels, so it can be confusing, but it's not that hard, generally routines have a 'rts' (return) in the end, and that's the end of a function, and the instruction that tells the preprocessor that certain label we'll be jumping to is a routine, are the bsr and jsr, the others (jmp, bra, branches...) are just for labels.

Routines and subroutines in 68k are functions, but they don't have a difference to labels, so it can be confusing, but it's not that hard, generally routines have a 'rts' (return) in the end, and that's the end of a function, and the instruction that tells the preprocessor that certain label we'll be jumping to is a routine, are the bsr and jsr, the others (jmp, bra, branches...) are just for labels.

Set conditions

[spoiler]

Instructions:

seq x: set x if the cmp x, y are equal.

sne x: set x if the cmp x, y are not equal.

spl x: set x if the result of cmp x, y (x minus y) is positive.

smi x: set x if the result of cmp x, y (x minus y) is negative.

sge x: set x if the cmp x is greater or equal to y.

sgt x: set x if the cmp x is greater than y.

sle x: set x if the cmp x is less or equal to y.

slt x: set x if the cmp x is less or equal to y.

scc x: set x if the cmp x is greater or equal to y. (unsigned)

shi x: set x if the cmp x is greater than y. (unsigned)

sls x: set x if the cmp x is less or equal to y. (unsigned)

scs x: set x if the cmp x is less or equal to y. (unsigned)

for example, seq d0 sets d0 to 0xFFFFFFFF if it's true, otherwise it's cleared (set to zero).

Consider the following code

Generic: move.l #hello, d0 move.l #world, d1 cmp.l d0, d1 beq.s Generic2 move.l #$0, d0 Generic2: move.l #$0, d1 cmpi.l #0x0020, d0 bpl Generic4 Generic3: clr.l d0 Generic4: clr.l d1 cmp d1, d0 seq d0

Translating it, we get:

int d0 = hello; int d1 = world; if (d0 != d1) { d0 = 0; } d1 = 0; d0 = (d0 == d1) ? 0xFFFFFFFF : 0x00000000;

This post has been edited by

**Chris Pancake**: 31 March 2018 - 08:15 AM