AiChip Compiler for the Propeller Chip - DRAFT 0.00 =================================================== This is a Windows OS based compiler for the Propeller (TM) Chip from Parallax Inc. It is intended to eventually support compilation of Spin, Spin Bytecode and Assembler. This an early release for evaluation and public demonstration of what is on the way. The necessary files ( including example sources ) can be found in the AIPROP16.ZIP archive. The compiler currently only supports Assembler programming and automatically adds a bootload wrapper to launch the code into Cog 0. A typical Assembler program will be something like - _CLKMODE RCFAST ; Set clock mode ORG 0 ; Put a count to OUTA CLR OUTA ; Initially zero the outputs MOV DIRA,#[0xFFFF_FFFF] ; Make all outputs Loop CALL #Output ; Update the outputs CALL #Delay ; Add a delay JMP #Loop ; Put out the next count Output MOV OUTA,count ; Put out the count INC count ; Update the count RET ; Then return count LONG 0 ; The count to display Delay MOV dTime,#[0xFFFF] ; A short delay routine DJNZ dTime,#$ ; Count delay time down RET ; Then return dTime LONG 0 ; Delay timer The Assembler supports standard Parallax syntax and also enhanced syntax as can be seen in the above example. These syntax enhancements are added for the author's own productivity gains; if you don't like them, don't use them, they are entirely optional. This is designed to be a standalone command line compiler which can also be called from another application, GUI or IDE. A self-contained minimal GUI is included for evaluation and debugging. Tested under Windows 3.11 (WfW), Windows 95, Windows 98 SE, Windows 2000 Pro, and Windows XP Pro SP2. Should work on any Windows 16-bit or 32-bit OS, but not tested under Windows Vista. Should also work under WINE but that has not been tested either. Usage Instructions ================== This is a 16-Bit Windows Application so does not support long filenames; use only 8-dot-3 filenames. VBRUN300.DLL will need to be installed on your system in the Windows System directory. No other *.VBX or *.DLL files should be required. Usage : {path\}AiProp16 {path\}file.ext {/switches} Any source file extension can be used. Creates *.EEP, *.ERR and an optional *.LST file. The *.EEP file must be renamed to *.EEEPROM for importing into the Propeller Tool. The *.ERR file will be zero bytes long if no error, otherwise it contains a multi-line textual error report. If /LIST is not specified, any existing listing file will be deleted. If the compilation fails, no image file will be produced. Usage : {path\}AiProp16 /DEBUG:EDIT This will bring up a basic GUI debugging environment so assembler can be typed in and assembled. Error messages are popped-up on the screen as message boxes. Valid Switches, with default settings ( command line / basic GUI ) are /BOOT:MINIMAL N / N Use minimal bootloader ( needed for Propeller Tool ) /DEBUG:ARGS N / N Show pop-up with calling arguments ( debugging use ) /DEBUG:EDIT N / Y Invoke the basic GUI for evaluation and debugging /LIST N / Y Create a *.LST listing file /LIST:ALL N / N Include pre-defined symbols in symbol table /LIST:CODE N / Y Show disassembled instructions for verification /LIST:PASS1 N / N Keep Pass 1 results in listing ( debugging use ) /LIST:SYMBOLS N / Y Include Symbol table in listing /LIST:SORT N / N Sort into alphanumeric group order /LIST:STAT N / N Show symbol table access statistics ( debugging use ) /LIST:VIEW N / Y Show a pop-up window with the listing included /MPASM N / N Use Microchip MPASM Opcodes /STRICT Y / Y Enforce usage compliance with the PropTool ************** The /BOOT:MINIMAL command line switch must be used and the IMPORTANT NOTE *.EEP files renamed to *.EEPROM to use the Propeller Tool ************** to import and download the created image files. Differences to Official Propeller Assembler =========================================== Any conflicts with the official Parallax Propeller Assembler will be resolved in favour of the Parallax usage where necessary. Enhancement is meant to mean just that, additional to what Parallax specify, not a change to the Propeller Assembler Language except where the programmer chooses that. An Assembler program compiled within the Propeller Tool should produce the same instruction codes as when compiled through the AiChip Compiler. Lines are completely free format with labels and opcodes starting in the first or later positions. C-style /* */ multi-line comments can be used. A semi-colon can be used as well as an apostrophe to start a single line comment - IncSp INC sp,#1 ; Increment the stack pointer ... RET ; ... and return Labels cannot be opcode names or IF conditions. Please take care when attempting to use opcode names ( ie TEST ) as labels, or mistyping opcode names, as the error message may not be immediately clear - Test ADD d,#1 ; "Cannot use opcode as a label name" DJZ d,#:Done ; "Opcode expected ( d )" TEST is actually an opcode in its own right, and the mistyped DJNZ caused the DJZ to be taken as a label, the following 'd' as the expected opcode. A wider variety of number format prefixes are supported - Bin Quat Oct Dec Hex Hex % %% $ &b &q &o &d &x &h 0b 0q 0o 0d 0x 0h Non-Strict mode changes the operation of Opcodes which use an address ( ie JMP, DJNZ etc ). Rather than using a # to indicate an address, a value is always taken as an address unless wrapped in []. Example - OPTION +STRICT OPTION -STRICT ; Determine strictness JMP #$123 JMP $123 ; Jump to specified address JMP #label JMP label ; Jump to label JMP reg JMP [reg] ; Jump to address held in reg The non-strict mode is a productivity gain for those programmers who are used to branch instructions always expecting and having an implied immediate address with indirect jumps to an address held within a register being explicitly stated when necessary. Handling of JMPRET changed to allow an optional # before the destination register - JMPRET d,#s JMPRET #d,#s JMPRET d,s JMPRET #d,s JMPRET d,s JMPRET #d,[s] ; When not strict mode IF conditions (IF_C) etc can be placed before the opode, between the opcode and operand or after the operand. Example, these are all the same - IF_C ADD d,#1 ADD IF_C d,#1 ADD d,#1 IF_C Local labels can be numeric as well as textual. They do not need to go in an ascending order. MySub JMP #:10 :10 JMP #:2 :2 RET Be careful with numeric labels because the underscore in numbers is discounted, so this would create a duplicate label error, both 1_2 and 12 are the same - MySub JMP #:1_2 :1_2 JMP #:12 :12 RET Label definitions can be followed by an optional colon - MySub: JMP #:10 :10: JMP #:2 :2: RET Constants greater than $1FF can be auto-allocated by placing them within [] - MOV d,#[$12345678] ADD d,#[-1] AND d,#[$80000000] RET opcodes within a block of code will automatically be found if there are no non-local labels between the start of the routine and the RET. Example - MySub MOV d,#1 RET Caller CALL #MySub A specific local ":ret" label is the same as having used an explict label with a '_ret' postfix. Example, these are the same - MySub MOV d,#1 MySub MOV d,#1 :ret RET MySub_ret RET The MODULE directive allows all labels between MODULE and END MODULE to be local to that module. MySub MODULE Start MOV d,#0 JMP #:MyRet :MyRet RET END MODULE NODULE can either have a label before or after it or none at all. If no label is used it is an anonymous module and will show in the symbol table as "" where 'n' is the asigned number for the anonymous module. Using "label EXPORT" defines and exports a label, "EXPORT label" exports a label which has previously been defined. An exported label will be accessible by any other part of the source code. MySub MODULE one NOP RET :two EXPORT ; Creates 'two' as a global label EXPORT one ; Creates 'one' as a global label END MODULE CALL one ; 'one' can be called from outside The ORG and '$' reference gives the adddress of the current opcode - a JMP #ORG+2 ; Same as JMP #c b JMP #ORG-1 ; Same as JMP #a c JMP #ORG ; Same as JMP #c a JMP #$+2 ; Same as JMP #c b JMP #$-1 ; Same as JMP #a c JMP #$ ; Same as JMP #c The MEM and '@' reference gives the adddress of the current opcode in the image while the '@label' reference gives teh address of the label in the image. LONG MEM+5 LONG @+5 LONG @Loop Opcodes BYTE, WORD, LONG and TEXT allow data to be added. TEXT adds a null ($00) byte after the string. They do not force any alignment. If labelled, the bad alignment will be detected when the label is used when alignment is required - MyByte BYTE 1 WORD 2 BYTE 1, 2, 3 WORD 1, 2, LONG 3,4, TEXT "Hello", "This is fun!" Note that text with a number converts the number to a sequence of characters representing the decimal value of the number. The following are the same - TEXT $FF TEXT 255 TEXT "255" Single line BYTE, WORD and LONG can be used without a specified value as this is used in some peoples example code. A default value of zero is used - Here BYTE 0 ; Byte of value zero There BYTE ; Byte of value zero Multiple bytes, words, longs and text strings can be allocated by following the value with a repeat count enclosed in [] - Bytes BYTE 1[2] ; Two bytes of value 1 Words WORD $1A[10] ; Ten words of value $1A Chars TEXT "AB"[6] ; The null terminated string six times The RES opcode reserves 1 or more longs, each zero filled. "RES n" is usually the same as using "LONG 0[n]" - Here RES 2 ; Reserve two zero value longs There LONG 0[2] ; Reserve two zero value longs The ALIGN directive is used to force alignment - "ALIGN BYTE", "ALIGN WORD" and "ALIGN LONG". Synonyms of "ALIGN BYTES", "ALIGN WORDS" and "ALIGN LONGS" are also provided. Labels used with ALIGN and ORG are placed at their address after the alignment or program counter position has been changed. ORG $000 BYTE 0 First ; First placed at $000.1 Second ORG $100 ; Second placed at $100 BYTE 0 Third ALIGN LONG ; Third placed at $101 The OPCODE directive creates an opcode specified by a long number. The opcodes and IF conditions are all defined as constants so can be used with the OPCODE opcode ( and elsewhere ). If the operand starts with # then the immediate bit is toggled within the opcode specified. Any opcode which results in an IF_NEVER condition is converted to an IF_ALWAYS. It is not possible to create an IF_NEVER opcode. Using other IF consitions works as would be expected. OPCODE IF_C + ADD ; Creates "IF_C ADD 0,0" OPCODE #IF_C + ADD ; Creates "IF_C ADD 0,#0" OPCODE ADD ; Creates "IF_ALWAYS ADD 0,0" OPCODE #ADD+1 ; Creates "IF_ALWAYS ADD 0,#1" OPCODE $A0BC0000 ; Creates "MOV 0,0" OPCODE $A0FC0000 ; Creates "MOV 0,#0" OPCODE #$A0BC0000 ; Creates "MOV 0,#0" OPCODE #$A0FC0000 ; Creates "MOV 0,0" The EQU directive allows a label to be assigned a value - MyNum EQU $12345678 The SET directive is similar to EQU but allows a value to be changed during the source code assembly - MyNum SET 1 MyNum SET MyNum+1 The OPTION directive allows command line switches to be overridden during compilation. A name by itself or preceeded by '+' or '/' will turn on the named option, when preceeded by '-' it will turn off the option. Additionally a selection may follow the option - OPTION opt1:all, /opt2 +opt3 -opt4, opt5 In this case opt1:all, opt2, opt3 and opt5 are set and opt4 is cleared. The OVERLAY directive is used to reserve an area of memory into which another page of memory will be loaded at execution time. The directive specifies the name of the overlay and its size. This can be used in conjunction with the 'ORG OVERLAY' directive which will compile the code ready for being overlaid into OVERLAY specified. MySub NOP RET Here OVERLAY 128 Ovlay1 ORG OVERLAY Here ADD d,s RET Ovlay2 ORG OVERLAY Here SUB d,s RET The programmer is responsible for implementing and writing the correct code which will copy any overlay into the Cog's memory for execution. REBOOT and its RESET synonym have been added to allow a Cog to reboot the Propeller Chip. SUB count,#1 ; Decrement the counter IF_Z REBOOT ; Reboot the Propeller chip A number of opcodes have been introduced to make stack handling easier - STKINIT sp,#n ; Initialise stack pointer to n-1 STKINIT sp,reg ; Initialise stack to value in reg less one PUSH sp,#n ; Push number to stack PUSH sp,reg ; Push contents of reg to stack POP ; Pop and discard top of stack POP sp,reg ; Pop top of stack into reg PUSHRET #label ; Pushes the return address of a subroutine POPRET #label ; Pops the return address of a subroutine SETTOS sp,#n ; Set top of stack to value SETTOS sp,reg ; Set top of stack to contents of register PUTTOS sp,#n ; Set top of stack to value PUTTOS sp,reg ; Set top of stack to contents of register GETTOS sp,reg ; Put top of stack into register These all generate multi-long opcodes. They can be used with IF conditions but not with WZ, WC, WR or NR effects. The 'sp' register is any register the programmer cares to define. At least one STKINIT opcode must be used before the other opcodes can be used. The stack grows up in cog memory and sp will always point to current top of stack and is initialised to point to one less than first long used for stack - MySub STKINIT sp,#stk PUSH sp,#10 POP sp RET sp LONG 0 stk EQU $ Using the above convention, an empty stack can be identified when sp == #sp. The PUT opcode is the reverse of a MOV. GET and LET are synonyms for MOV - MOV temp,source ; dest := source MOV dest,temp GET temp,source ; dest := source PUT temp,dest Three special multi-long opcodes for register indirection have been added; GTI STI and MOVII. GTI d,s ; d := whatever is in what s points to STI s,d ; whatever d points to := s MOVII d,s ; both indirect to do : MOV d,[s] => GTI d,s MOV [d],s => STI s,d MOV [d],[s] => MOVII d,s GET d,[s] => GTI d,s PUT s,[d] => STI s,d Microchip MPASM Support ======================= Additional opcodes are added for those familiar with Microchip PICmicro programming for the 14-bit CPU range ( 16F88 etc ). This is neither code efficient nor necessarily recommened but does give PICmicro programmers a fast-track route ( and some encouragement ) into Propeller Assembler coding. The example code at the start of this document, rewriten to use the MPASM opcodes - _CLKMODE RCFAST ; Set clock mode ORG 0 ; Put a count to PORTA W EQU 0x1EF ; Create a W register CLRF PORTA ; Initially zero the outputs MOVLW 0x0000_0000 ; Make all outputs TRISA ; Or use "MOVWF TRISA" Loop CALL Output ; Update the outputs CALL Delay ; Add a delay GOTO Loop ; Put out the next count Output MOVF count,W ; Get the count MOVWF PORTA ; Put to PORTA (OUTA) INCF count,F ; Update the count RETURN ; Then return count LONG 0 ; The count to display Delay MOVLW [0xFFFF] ; A short delay routine MOVWF dTime :Dloop DECFSZ dTime ; Count delay time down GOTO :Dloop RETURN ; Then return dTime LONG 0 ; Delay timer MPASM support is enabled by specifying the /MPASM switch on the command line. PORTA and PORTB are added as the I/O interface registers. Read and write access to PORTA and PORTB are automatically altered to use INA/INB or OUTA/OUTB as appropriate for the command operation. TRISA and TRISB exist as MPASM equivalents to DIRA and DIRB but with the bit meaning inverted; a zero bit means output, a one bit means input. The following are equivalent - MOV DIRA,#[$FFFF_0000] ; 0-15 Inputs, 8-31 Outputs MOVLW [$FFFF_0000] ; 0-15 Inputs, 8-31 Outputs MOVWF DIRA MOVLW [$0000_FFFF] ; 0-15 Inputs, 8-31 Outputs MOVWF TRISA MOVLW [$0000_FFFF] ; 0-15 Inputs, 8-31 Outputs TRISA MOVF DIRA,W ; Read ( W := $FFFF_0000 ) MOVF TRISA,W ; Read ( W := $0000_FFFF ) The majority of MPASM opcodes can be used in conjuction with IF conditions - MOVF count,W ADDLW 1 IF_Z JMP IsZero The C and Z flags can be manipulated and tested by referencing "STATUS,CARRY" and "STATUS,ZERO", or "STATUS,0" and "STATUS,2" respectively - BCF STATUS,CARRY ; Clear Carry flag BSF STATUS,ZERO ; Set Zero flag BTFSS STATUS,CARRY ; Skip if Carry flag set BTFSC STATUS,ZERO ; Skip if Zero flag clear BCF STATUS,0 ; Clear Carry flag BSF STATUS,2 ; Set Zero flag BTFSS STATUS,0 ; Skip if Carry flag set BTFSC STATUS,2 ; Skip if Zero flag clear Error Report ( *.ERR File ) =========================== The *.ERR file will be zero bytes long if no error, otherwise it contains a eleven line textual error report - Meaning Example lines Source Line CALL MySub Source file MPASM.ASM Line Number 26 Character Position 6 Error Message Label not found ( 'MySub' ) Compiler Name AiChip Compiler for the Propeller Chip Compiler Version 0.00 (00005) Compiler Type VB3 16-Bit Compiler Directory C:\PROPTEST\AIPROP Compiler Executable AIPROP16 Command Line Used MPASM.ASM /LIST /LIST:SYMBOLS /BOOT:MINIMAL /MPASM Line Numbers ascend from 1 which is the first line in the file. A line number of zero indicates an error which cannot be attributed to any particular line of source code. Bootloader Code =============== The default bootloader code to start Cog 0 executing the assembler code is 40 bytes long, eight bytes longer than the bootloader suggested by Chip Gracey of Parallax Inc. This is to achieve best compatibility and dissassembly results with the AiChip Disassembler ( PROPVIEW.EXE ) and the loss of two longs is considered to be an acceptable penalty to bear to achieve that. Chip's minimal bootloader can be used by specifying /BOOT:MINIMAL on the command line. ************** The /BOOT:MINIMAL command line switch must be used and the IMPORTANT NOTE *.EEP files renamed to *.EEPROM to use the Propeller Tool ************** to import and download the created image files. A 16-Bit Application ! ====================== AIPROP16.EXE is written in Visual Basic 3, for a number of reasons; to target the majority of Windows OS' including 16-bit ( Windows 3.0 upwards ) and to provide a lowest common denominator for auto-generating 32-bit and .Net source and executables. These will be made available as final deliveries. It also has to be said that compilation of source code is considerably quicker under Visual Basic 3 than for later compilers. This is quite handy when having to recompile frequently to test interaction from a GUI or IDE. Known Bugs and Limitations ========================== All the things in 'things to do' below ( the "show stoppers" for the unwary programmer using them ) need to be done. There are probably other bugs not yet identified. Generated images have not been tested on a physical Propeller chip nor in any of the Propeller simulators. The generated code has been verified using the AiChip Disassembler. No long filename support. All expression evaluation ( "MOV d,#3*2+1" ) is done strictly left to right without precedence unless parenthesis are used; the result for "3*2+1" is 7, not 9, the result for "(3*2)+1" is 9. The ** operator returns the upper 16-bits of a 32-bit result, not the upper 32-bits of a 64-bit result. Currently most auto-allocated constants get their own allocation. This will be improved upon in a later version if possible ( it's not easy with unknown forward references ) meaning only one long will be used for each allocation of the same number. Relative addressing ( "JMP #$+1" ) and MPASM skip opcodes may cause incorrect code to be generated under some circumstances. STKINIT and associated opcodes plus GTI, STI and MOVII have not been fully tested. MPASM opcodes have not been fully tested and may not set the required C or Z bits as would be expected by those instructions in all cases. Things to do ============ Only allocate auto-allocated numbers ( "ADD d,#[$12345678]" ) once per use. Prevent MOVS, MOVD, MOVI from altering parts of multi-long opcodes. Auto-correct relative jumps ( "JMP #$+5" ) to take into account auto-allocated numbers and multi-long opcodes. Auto-correct MPASM skips ( "DECFSZ r", "BTFSC r,b" ) to take into account auto-allocated numbers and multi-long opcodes. Should fall out as part of the above. Auto-update label for MPASM "RETLW n" so it points to the "RET" not the "MOV W,#n" before it. Ensure all MPASM opcodes set the required C or Z bits as would be expected by those instructions. MPASM "SWAPF" opcode not implemented. Include bootloader dump in *.LST Files included in AIPROP16.ZIP ============================== AIPROP16.EXE Application executable AIPROP16.TXT This documentation file VBRUN300.DLL Copy to Windows System directory STANDARD.ASM Parallax Standard Assembler Source code STANDARD.LST Listing Output STANDARD.EEP Eeprom Image Output STANDARD.ASM Enhanced Assembler Syntax Source code STANDARD.LST Listing Output STANDARD.EEP Eeprom Image Output NOSTRICT.ASM Non-Strict Assembler Syntax Source code NOSTRICT.LST Listing Output NOSTRICT.EEP Eeprom Image Output MPASM.ASM MPASM-style Assembler Syntax Source code MPASM.LST Listing Output MPASM.EEP Eeprom Image Output