------------------------------------------------------------ il65 - "Intermediate Language for 6502/6510 microprocessors" ------------------------------------------------------------ Written by Irmen de Jong (irmen@razorvine.net) License: GNU GPL 3.0, see LICENSE ------------------------------------------------------------ The python program parses it and generates 6502 assembler code. It uses the 64tass macro cross assembler to assemble it into binary files. Memory Model ------------ Zero page: $00 - $ff Hardware stack: $100 - $1ff Free RAM/ROM: $0200 - $ffff Reserved: data direction $00 bank select $01 NMI VECTOR $fffa RESET VECTOR $fffc IRQ VECTOR $fffe A particular 6502/6510 machine such as the Commodore-64 will have many other special addresses due to: - ROMs installed in the machine (basic, kernel and character generator roms) - memory-mapped I/O registers (for the video and sound chip for example) - RAM areas used for screen graphics and sprite data. Usable Hardware registers: A, X, Y, AX, AY, XY (16-bit combined register pairs) SC (status register Carry flag) These cannot occur as variable names - they will always refer to the hardware registers. The zero page locations $02-$ff can be regarded as 254 other registers. Free zero page addresses on the C-64: $02,$03 # reserved as scratch addresses $04,$05 $06 $0a $2a $52 $93 $f7,$f8 $f9,$fa $fb,$fc $fd,$fe IL program parsing structure: ----------------------------- OUTPUT MODES: ------------- output raw ; no load address bytes output prg ; include the first two load address bytes, (default is $0801), no basic program output prg,sys ; include the first two load address bytes, basic start program with sys call to code, default code start ; immediately after the basic program at $081d, or beyond. address $0801 ; override program start address (default is set to $c000 for raw mode and $0801 for c-64 prg mode) ; cannot be used if output mode is prg,sys because basic programs always have to start at $0801 data types: byte 8 bits $8f (unsigned, @todo signed bytes) int 16 bits $8fee (unsigned, @todo signed ints) bool true/false (aliases for the integer values 1 and 0, not a true datatype by itself) char '@' (converted to a byte) float 40 bits 1.2345 (stored in 5-byte cbm MFLPT format) @todo 24 and 32 bits integers, unsigned and signed? string 0-terminated sequence of bytes "hello." (implicit 0-termination byte) pstring sequence of bytes where first byte is the length. (no 0-termination byte) For strings, both petscii and screencode variants can be written in source, they will be translated at compile/assembler time. Note: for many floating point operations, the compiler uses routines in the C64 BASIC and KERNAL ROMs. So they will only work if the BASIC ROM (and KERNAL ROM) are banked in. largest 5-byte MFLPT float: 1.7014118345e+38 (negative: -1.7014118345e+38) Note: with the # prefix you can take the address of something. This is sometimes useful, for instance when you want to manipulate the ADDRESS of a memory mapped variable rather than the value it represents. You can take the address of a string as well, but the compiler already treats those as a value that you manipulate via its address, so the # is ignored here. BLOCKS ------ ~ blockname [address] { statements } The blockname "ZP" is reserved and always means the ZeroPage. Its start address is always set to $04, because $00/$01 are used by the hardware and $02/$03 are reserved as general purpose scratch registers. Block names cannot occur more than once, EXCEPT 'ZP' where the contents of every occurrence of it are merged. Block address must be >= $0200 (because $00-$fff is the ZP and $100-$200 is the cpu stack) You can omit the blockname but then you can only refer to the contents of the block via its absolute address, which is required in this case. If you omit both, the block is ignored altogether (and a warning is displayed). IMPORTING, INCLUDING and BINARY-INCLUDING files ----------------------------------------------- import "filename[.ill]" Can only be used outside of a block (usually at the top of your file). Reads everything from the named IL65 file at this point and compile it as a normal part of the program. asminclude "filename.txt", scopelabel Can only be used in a block. The assembler will include the file as asm source text at this point, il65 will not process this at all. The scopelabel will be used as a prefix to access the labels from the included source code, otherwise you would risk symbol redefinitions or duplications. asmbinary "filename.bin" [, [, ]] Can only be used in a block. The assembler will include the file as binary bytes at this point, il65 will not process this at all. The optional offset and length can be used to select a particular piece of the file. MACROS ------ @todo macros are meta-code (written in Python syntax) that actually runs in a preprecessing step during the compilation, and produces output value that is then replaced on that point in the input source. Allows us to create pre calculated sine tables and such. Something like: var .array sinetable ``[sin(x) * 10 for x in range(100)]`` EXPRESSIONS ----------- In most places where a number or other value is expected, you can use just the number, or a full constant expression. The expression is parsed and evaluated by Python itself at compile time, and the (constant) resulting value is used in its place. Ofcourse the special il65 syntax for hexadecimal numbers ($xxxx), binary numbers (%bbbbbb), and the address-of (#xxxx) is supported. Other than that it must be valid Python syntax. Expressions can contain function calls to the math library (sin, cos, etc) and you can also use all builtin functions (max, avg, min, sum etc). They can also reference idendifiers defined elsewhere in your code, if this makes sense. The syntax "[address]" means: the contents of the memory at address. By default, if not otherwise known, a single byte is assumed. You can add the ".byte" or ".word" or ".float" suffix to make it clear what data type the address points to. Everything after a semicolon ';' is a comment and is ignored, however the comment (if it is the only thing on the line) is copied into the resulting assembly source code. FLOW CONTROL ------------ Required building blocks: additional forms of 'go' statement: including an if clause, comparison statement. - a primitive conditional branch instruction (special case of 'go'): directly translates to a branch instruction: if[_XX] go