ByteCraft COP8C Compiler

General compiler notes

BITS and CHAR /*The use of CHAR to define an unsigned int8 is OK, but BITS allows you to take easy advantage of the bit test capability of the COP8.  Bit postionions can then be specified on the fly instead of defining a bit with a variable*/

UNSIGNED BITS test_data;

if (test_data.0)                //if lsb=1 then...
    {
    //code
    }

UNSIGNED INT8 test_dat
BIT test_dat0 @ test_dat.0;

if (test_dat0)                  //if lsb=1 then...
    {
    //code
    }
For-Next Loops /*The compiler does not handle loops very efficiently, even when using the faster registers from 0xF0-0xFB.  The DRSZ opcode is never used for a loop that terminates after zero is hit but a bit of inline assembly can fix that... saves about 10 instructions*/

#DEFINE loop_counter_a    0xF8    //need this for DRSZ to compile correctly

this_is_loop:
     //loop code
#asm "DRSZ loop_counter
_a"
#asm "JP this_is_loop"
#DEFINE Don't put a comment right next to the last character of a #DEFINE parameter.  The parser needs a space because a "\\" will be interpreted as part of the parameter, generating a random error.
INT8 vs CHAR /*The use of "i>0" in the loop and "INT8 i;" for the variable declaration will make the compiler do the end of loop test as a signed integer which will require two tests instead of just one.  Use unsigned int8 to be absolutely sure*/

CHAR i;
For (i=8;i!=0;i--)
    {
    //CODE
    }
STOP If the linker ever sees the word "STOP" in upper case and preceeded by one or more spaces, it will litterally choke on it and fail the linking process.  If in lower case, or just after any other charater than a space and the linker won't see it.  The error code is "UNKNOWN" so it's not clear why it does not like it!
NOINIT /*The compiler can be made to skip the creation on initialization code, at 0x0000 by putting the following directive at the beginning of the source code, before any functions are defined:*/
#pragma option NOINIT;

/*Your own reset code then follows...*/
#asm                                 //starts code at reset vector
   ORG 0            ;Start at 0000
#endasm
void reset(void){
PSW.GIE = 0;                         //interrupts off
SP = 0x6F;                           //stack, must agree with compiler
//more C code here!
#asm
    JMP main                         ;Jump to main()
#endasm
}


//Alternatively, but seems less relaible in this compiler...
void reset(void) @ 0x0000;

plus "void reset(void){
//------------------------------------------------------------------------------
void reset(void){
PSW.GIE = 0;                         //interrupts off
SP = 0x6F;                           //stack, must agree with compiler
//more C code here!
//------------------------------------------------------------------------------
#asm
    JMP main        ;Jump to main()
#endasm
}

Low level initialization

__STARTUP If the compiler finds a function called exactly "__STARTUP" during compile time, it will modify it's code to include a call to this function after reset.  There must be an actual function, not just a prototype of the function for the compiler to recognize it.  The jump table for this function will be after the last byte of ROM code used...

If  __STARTUP( ) function, the compiler will do the following:


0000 DD 6F      LD    SP,#06F  ;setup stack pointer
0002 AC 02 00   JMPL  00200    ;jump to function main()
...
                __MAIN:
0200 ...                       ;standard location of function main()

If __STARTUP( ) is found, and no ROM constant data is found, the compiler will do the following:

0000 DD 6F      LD    SP,#06F  ;setup stack pointer
0002 AC 02 01   JMPL  00401    ;jump to __MAIN, not the same as main()!
...
0200 ...                       ;standard location of function main()

0400 ...                       ;end of function main()
                __MAIN:
0401 AD 01 30   JSRL  00130    ;call __STARTUP(), just happened to be at 0x0130
0404 AC 02 00   JMPL  00200    ;jump to function main()


If  __STARTUP( ) is found and ROM constant data has been defined, the last byte of compiled code will actually be the end of the ROM lookup table which is usually placed in the last page of ROM at 0x0F00 (For the COP8TAC9).  Once setup, the same data table structure is used for all constant data up to the limit of fitting within a single 256byte page starting on an 0xNN00 boundary.  This example has a 16 byte constant data table defined:

0000 DD 6F      LD    SP,#06F  ;reset vector
0002 AC 0F 1D   JMPL  00F1D    ;jump to __MAIN, not the same as main()!
...
0200 ...                       ;standard location of function main()
...
0F00 9D FC      LD    A,X      ;See below {1}
0F02 A4         LAID           ;Entry point if index is A
0F03 8E         RET
0F04 3B         ??             ;start of constant data (index 0)
0F05 31         ??
0F06 33         ??
0F07 33         ??
0F08 00         ??
0F09 00         ??
0F0A 00         ??
0F0B 00         ??
0F0C 3F         ??
0F0D 00         ??
0F0E 00         ??
0F0F 00         ??
0F10 00         ??
0F11 00         ??
0F12 00         ??
0F13 00         ??             ;end of constant data (index F)
0F14 BE         LD    A,[X]    ;See below {2}
0F15 8E         RET
0F16 93 0E      IFGT  A,#00E   ;{1}/{2} Entry point for [X]
0F18 93 0F      IFGT  A,#00F
0F1A F9         JP    00F14    ;{2} If A !=0x0F then get RAM at location [X]
0F1B 2F 00      JMP   00F00    ;{1} If A  =0x0F then get ROM at location [X]
                __MAIN:
0F1D AD 01 30   JSRL  00130    ;call __STARTUP(), just happened to be at 0x0130
0F20 AC 02 00   JMPL  00200
    ;jump to function main()

Any questions or comments?
 This page last updated on September 04, 2011