The bots are programmed using asm, here I will go through the basics...
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
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.
"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