Next Previous Contents

6. The BattleBots assembler language

The bots are programmed using asm, here I will go through the basics...

6.1 Basics of the mnemonics

All the real work is done by assembler 'mnemonics' These are instructions like for example
mov, add, in or out. Each mnemonic has between 0-3 arguments.

Which argument combinations are possible depend on the instruction; but in general there are
four different types of arguments:

registers
registers pointing to memory,
value
memory adress

Registers are small memory cells within the CPU (that DON'T exist in RAM).
Some of them are "general purpose registers" and can be used for almost
anything,  some of them are used for special purposes... they are
either 16 or 8-bit here's a short list:

ax : general purpose register, also used by some instruction as result
containers (div, mul, idiv, imul), it's also used by STOSW as the source of the value
ah : the high byte of AX, Used by STOSB as the source
al : the low byte of AX

bx : general purpose register
bh : high byte of bx
bl : low byte of bx

cx : general purpose register, used as counting register for some instruktions that needs
     to know how many iterations they should make (STOSW,STOSB,MOVSB,MOVSW,CMPSB)
ch : high byte of cx
cl : low byte of cx

dx : general purpose register, used as result register for some instruktions (DIV,MUL)
dh : high byte of dx
dl : low byte of dx

eip : Instruktion Pointer, points to the current point of execution in RAM

sp : Stack Pointer, points to the current stack point in RAM

bp : Base Pointer, general purpose register (often used as temporary save for sp)

si : Source Index, used as memory pointer, (MOVSB,MOVSW,CMPSB)

di : Destination Index, used as memory pointer, (MOVSW,MOVSB,STOSW,STOSB,CMPSB)

flags : contains the state flags for the CPU

Registers pointing to memory is a register with an @ before it:

mov bx,100 ;100 -> bx
mov ax,@bx ;Mov the contents of memory cell 100 to ax

Values is just that...:

mov bx,100

Note that pure values can't be the destination in an instruction

Memory adresses are values with an @ before it:

mov ax,@100 ;Mov the contents of memory cell 100 to ax

6.2 Symbols:

In most places where you use values you can use constants/symbols/labels:

$myconst 45
Declares a constant with the name 'myconst' and the value 45. It can be used as such:

mov ax,@myconst  ;Move contents of memory cell 45 to ax
mov ax,myconst   ;Move value 45 into ax

:label
Declares a constant with the name 'label and the value of the position in RAM that the current
assembly point is at. This is useful for jumping in code:

:label
mov ax,bx
add dx,cx
jmp label

(Nothing stops you from doing 'jmp myconst' or 'jmp 100' or mov ax,label but it's not
recommended)

#variable
Functions about the same as :label, it defines a constant named 'variable' with the value of
the current position in RAM. It is intended for declaring variables:

#myvar
dw 5

mov ax,myvar puts the _ADRESS_ of myvar into ax and
mov ax,@myvar puts the _CONTENTS_ of myvar int ax

There are a number of predefined constants (from version 0.4.1). These are named after your
hardware and contains the values of the ports they use:

If you have two CPU:s and they are devices 0 and 5 the following constants are automatically
declared:
Name         Value
CPU0_GetXSize 0
CPU0_GetYSize 1
CPU0_GetBattleType 2
CPU0_GetMyTeam 3

CPU1_GetXSize 20
CPU1_GetYSize 21
CPU1_GetBattleType 22
CPU1_GetMyTeam 23

All hardware gets symbols declared like this. If you change your mind and want the second
CPU in slot 3 instead you would have to change all the values in your code if you didn't
use these constants.

This way your code won't be depending on the exact number of your device. (And will as such
be more portable between different "hardware"). Not to mention it gets easier to read.

6.3 The "Red Tape" tags:

"Red tape" tags are code that in general doesn't assemble directly into runnable code
but instead affect how the following code is generated.

%org number
All code and such is placed in the RAM mem of the bot.
%org number makes the code that comes after to start being
assembled to position number.

Example:

nop
nop
%org 100
nop
nop

If this is the only code in the bot then nop:s are inserted at
positions 0,1,100 and 101 in the RAM memory

also, you can make a relative org.
Example:

%org 0
nop
nop
%org 100
nop
nop
%org +100
nop

nop:s are inserted at positions 0,1,100,101 and 202

%CPUboot devicenumber

This tag makes the device devicenumber (assuming it is an CPU) to
boot at the current position in the code.

example:

%CPUboot 0
:start
...
...
...
...
jmp start

%CPUboot 1
:navigate
...
...
...
...
...
jmp navigate

This causes the CPU:s to execute "simultaneously" in different functions
in the code.

%CPUstack devicenumber:
If you use PUSH/POP/CALL or something like that you must set this.
It functions as %CPUboot only this one sets stack mem.
If it isn't set stackmem will default to 0.
And in that case it WILL overwrite code if you execute a PUSH.

%interrupt interruptnumber:

If certain events occur, the hardware can
"interrupt" the current CPU computing and take it to a "service routine".

Example bot :

Hardware:

CPU
Plasmagun
timedev

code:

:start
cli       ;No interrupts when we initialize
out 8,0   ;Set the timers current tick count to 0
out 9,100 ;Set the interrupt count to 100
out 10,1  ;enable this device interrupt
sti       ;enable interrupts

:loop
jmp loop  ;infinite loop

%interrupt 1 ;Here the code for interrupt 1 (timer interrupt) starts
:service

out 8,0   ; reset clock count
out 4,1   ; shoot

iret
%CPUstack 0

This code will make the bot fire a shot every 100 clock ticks.
Available interrupts are:

0: Collision/hit (issued by armor device)
1: Time interrupt (issued by timedev)
2: Message received (issued by radio)
3: Armor below a certain level (issued by armor dev) !OBS only enable this int in ONE armor device
4: Fuel below a certain level (issued by fuel dev) !OBS only enable this int in ONE fuel device
5: Heat above level interrupt (issued by armor dev) !OBS only enable this int in ONE fuel device

If you have multiple CPU:s the first CPU with the interrupt flag set
will get the int (set the flag with sti, clear it with cli).
If no CPU has the interrupt flag on, no interrupt is issued.
Entering an interrupt clears the interrupt flag, and executing
an iret sets the interrupt flag.

Remember that you need to specify CPUstack if you use interrupts, as
the adress of where the CPU where when he got interrupted is saved on
the stack.

The adresses of your interrupt vectors are stored at the end of your RAM,
So if you use interrupts 0 & 1 you shouldn't do something with the 4 last
bytes of your RAM

db/dw:

declare byte/declare word...
Sets the current bytes to the values after db/dw.
You may have up to 12 values after each db/dw

example:

db 0,1,200,3,4,5,4,3,2,1
dw 12045,10000,14000,950

comments:

comments is started with the ; sign

example:
; This is a comment
  nop        ;wait
;  ^           ^
; mnemonic   comment

Next Previous Contents