How to translate basic 68k assembly to c++ code

This is my first topic!
Unfortunately I was unable to find the c++ equivalent to the bset, bclr, bchg, bvc and bvs..
If you want to know how to do rol and ror, look there.

Local variables

Spoiler

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.
Moves are basically the equal (=) operator in c++, move.l is int (or long), move.w is short and move.b is char (or byte).
Translating it to c++ we get this:

int d0 = hello;
int d1 = world;

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 c++17 (or c++0z) target.

Conditions

Spoiler

Instructions:
cmp.x y, z: compares a register with another. (x should be l or w or b)
cmpi.x y, z: compares z with y (a short number, 0-65535 or -32768-32767). (x should be l or w or b)
tst.x y: compares a register with zero. (x should be l or w or b)
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.
bcc x: branch (goto x) if the cmp x is greater or equal to y. (unsigned)
bhi x: branch (goto x) if the cmp x is greater than y. (unsigned)
bls x: branch (goto x) if the cmp x is less or equal to y. (unsigned)
bcs x: branch (goto x) if the cmp x is less or equal to y. (unsigned)
Consider the following code

It's easy.
Instructions:
add.x y, z: adds y to z. (x should be l or w or b)
addi.x y, z: adds y (a short number, 0-65535 or -32768-32767) to z. (x should be l or w or b)
add.z x, y(z): adds x to the adress in y + z. (w should be l or w or b)
addi.z x, y(z): adds x (a short number, 0-65535 or -32768-32767) to the adress in y (a register) plus z (a short number, 0-65535 or -32768-32767). (w should be l or w or b)
sub.x y, z: subs y to z. (x should be l or w or b)
subi.x y, z: subs y (a short number, 0-65535 or -32768-32767) to z. (x should be l or w or b)
sub.z x, y(z): subs x to the adress in y + z. (w should be l or w or b)
subi.z x, y(z): subs x (a short number, 0-65535 or -32768-32767) to the adress in y (a register) plus z (a short number, 0-65535 or -32768-32767). (w should be l or w or b)

Instructions:
clr.x 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 x.
exg.x y, z: swaps y with z (x should be l or w or b)

clear in c++ is basically:

x = 0;

So it's not that hard. But the swap is not that simple. 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 0xDEAD.
(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. (0xDEAD0000 | 0xBEEF = 0xBEEFDEAD);

Bitwise operators

Spoiler

Another easy one.
Instructions:
not.x y: nots y (!y). (x should be l or w or b)
and.x y, z: ands y to z. (x should be l or w or b)
andi.x y, z: ands y (a short number, 0-65535 or -32768-32767) to z. (x should be l or w or b)
and.z x, y(z): ands x to the adress in y + z. (w should be l or w or b)
andi.z x, y(z): ands x (a short number, 0-65535 or -32768-32767) to the adress in y (a register) plus z (a short number, 0-65535 or -32768-32767). (w should be l or w or b)
or.x y, z: ors y to z. (x should be l or w or b)
ori.x y, z: ors y (a short number, 0-65535 or -32768-32767) to z. (x should be l or w or b)
or.z x, y(z): ors x to the adress in y + z. (w should be l or w or b)
ori.z x, y(z): ors x (a short number, 0-65535 or -32768-32767) to the adress in y (a register) plus z (a short number, 0-65535 or -32768-32767). (w should be l or w or b)
xor.x y, z: xors y to z. (x should be l or w or b)
xori.x y, z: xors y (a short number, 0-65535 or -32768-32767) to z. (x should be l or w or b)
xor.z x, y(z): xors x to the adress in y + z. (w should be l or w or b)
xori.z x, y(z): xors x (a short number, 0-65535 or -32768-32767) to the adress in y (a register) plus z (a short number, 0-65535 or -32768-32767). (w should be l or w or b)

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

Multiplication and division

Spoiler

muls.x y, z: multiplies z with y. (x should be l or w or b)
mulu.x y, z: multiplies z with y. (x should be l or w or b) (unsigned)
divs.x 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)
divs.x 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++.

register int d0 = d1 / 2;
register 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).

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

Set conditions
[spoiler]
Instructions:
seq x: set if the cmp x, y are equal.
sne x: set if the cmp x, y are not equal.
spl x: set if the result of cmp x, y (x minus y) is positive.
smi x: set if the result of cmp x, y (x minus y) is negative.
sge x: set if the cmp x is greater or equal to y.
sgt x: set if the cmp x is greater than y.
sle x: set if the cmp x is less or equal to y.
slt x: set if the cmp x is less or equal to y.
scc x: set if the cmp x is greater or equal to y. (unsigned)
shi x: set if the cmp x is greater than y. (unsigned)
sls x: set if the cmp x is less or equal to y. (unsigned)
scs x: set 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).

Your "Addition and Subtraction" section uses d1 as a pointer, which is not permitted on 68000. Aside from that, a lot of this is just common sense stuff that you'd figure out if you know C and 68000 ASM.
The equivalent to bset #X,d0 is d0 |= 1 << X;
The equivalent to bclr #X,d0 is d0 &= ~(1 << X);
The equivalent to bchg #X,d0 is d0 ^= 1 << X;

Your "Addition and Subtraction" section uses d1 as a pointer, which is not permitted on 68000. Aside from that, a lot of this is just common sense stuff that you'd figure out if you know C and 68000 ASM.
The equivalent to bset #X,d0 is d0 |= 1 << X;
The equivalent to bclr #X,d0 is d0 &= ~(1 << X);
The equivalent to bchg #X,d0 is d0 ^= 1 << X;

To be honest, I didn't have so much practice with the 68k, already fixed that.

For what is worth, "register" keyword is mostly ignored by C and C++ compilers and, since C++11, it has the same semantics as whitespace in C++. C, even C11, still pretends it does something but, in practice, it does not.

For what is worth, "register" keyword is mostly ignored by C and C++ compilers and, since C++11, it has the same semantics as whitespace in C++. C, even C11, still pretends it does something but, in practice, it does not.

With optimization on of course (MSVC /Ox and GCC -Ox for example), that's why I said:

Quote

This keyword is not needed when this is a release build though. (which normally has the O2 build option).

I also changed the name of this topic because this guide is really basic.

This certainly seems correct, but this is something that could be done by an automatic translator. Aside from folding some lines into one-another the result of that would almost exactly match the original assembly on a line-by-line basis. It would be far from idiomatic C++.

If a direct translation of a whole program from 68k ASM to C++ were intended, it would probably be better to make drastic changes - abandon manipulation of global variables representing the registers, for example, and instead make the subroutines pass data as actual arguments. The modern optimising C++ compiler could probably match the performance of the original assembly.

The modern optimising C++ compiler could probably match the performance of the original assembly.

They cannot, unless you are talking about really bad assembly; mostly because the modern C++ compilers which support 68k family at all are more oriented towards later models of the 68k family (which have pipelines), as well as using an ABI which makes heavy use of the stack.