( Copyrighted by eMAST Technology Corp, 2000 )
( All rights reserved )
( EPROM Programmer, Chuck Moore, 1993 Aug 16)
( modified from ok28 for P16, 08dec98cht )
( 29nov00cht, P24, 6 bit fields )

comment:

This file contains the Structured, Optimized Assembler for P24
CPU.  It packs up to four machine instructions into one 24-bit
program word.  It also builds structures similar to those in
high level Forth.  The structures are build in a single pass,
without labels.

P24 eForth adopts the Subroutine Thread Model, in which the colon
words contain lists of subroutine calls, instead of lists of
addresses.  Using this model, the assembler assumes the duties
of the compiler.  Another advantage of the Subroutine Thread
Model is that machine instructions can be assembled in-line
in the colon words.

Comment;

\ Put all the assembly words and words in the P24 target into
\ the ASM24 vocabulary.
ONLY FORTH ALSO ASM24
ASM24 DEFINITIONS

\ H points to the next free location in the target image to
\ receive new code or data.
\ LOC marks a target location to be reference later. It is not
\ used in the P24 system.
VARIABLE H
: LOC   CONSTANT  DOES> @  H ! ;

\ LASTH contains the link field address of the last word
\ to build the linked list of Forth words.
variable lastH 0 lastH !        \ init linkfield address lfa

\ NAMER! stored n into the next location in target.
\ It was useful if you want to assemble names in a separated
\ names dictionary.
: nameR! ( n -- )
   H @ RAM!                     \ store double to code buffer
   1 H +!                       \ bump nameH
   ;

\ COMPILE-ONLY marks the current word so it can only be compiled
\ in a colon word.  It cannot be executed interactively.
\ IMMEDIATE marks the current word so it will be executed in
\ a colon word.  All structure building words are so marked.
: compile-only 400000 lastH @ RAM@ -OR lastH @ RAM! ;
: immediate    800000 lastH @ RAM@ -OR lastH @ RAM! ;

\ Derived from Chuck Moore's P21 20 bit assembler
\ HI selects one of four masks to assemble a machine instruction
\ into one of the four slots in a 24-bit program word.
\ HW points to the program word into which new machine instructions
\ are to be assembled.  H may advance from HW as literal values
\ are assembled following the program word.
\ BI points to one of the 3 bytes in a 24-bit program word.  It
\ allows the assembler to pack 3 ASCII characters into one word.
VARIABLE Hi   VARIABLE Hw
VARIABLE Bi ( for packing)

\ ALIGN forces the next instruction to be assembled into the next
\ word.
\ ORG ( a ) changes H to a, to start assembling at a new location.
: ALIGN  10 Hi ! ;
: ORG    DUP . CR H !  ALIGN ;

\ MASK contains four mask patterns to assemble a machine instruction
\ into one 6-bit slot of a program word.  The mask is selected by
\ HI.
\ #, ( n ) assembles n into the next free location pointed by H.
\ Advance H afterwards.
\ ,W ( n ) assembles a machine instruction to the next free slot
\ in the current program word pointed to by HW.
\ ,I ( n ) assembles a machine instruction.  It the current word
\ is full, assemble the instruction into the next word.
\ ,B ( c ) packs a character c into the current word.  Uses BI to
\ determine the character postion in a 24-bit word.  Pack it to
\ the next word if the current word is full.
CREATE mask  FC0000 ,  3F000 ,  FC0 ,  3F ,
: #,     FFFFFF AND H @ RAM!  1 H +! ;
: ,w     Hw @ RAM@  -OR  FFFFFF AND Hw @ RAM! ;
: ,I     Hi @ 10 AND IF  0 Hi !  H @ Hw !  0 #,  THEN
         Hi @ mask + @ AND  ,w  4 Hi +! ;
: ,B   ( c ) Bi @ 0 = IF 1 Bi ! H @ Hw ! 0 #, 10000 * ,w EXIT THEN
             Bi @ 1 = IF 2 Bi ! 100 * ,w EXIT THEN
             0 Bi ! ,w ;

\ INST A defining word to define a single slot machine instruction.
\ When the machine instruction word is executed, it assembles the
\ desired machine instruction into the current program word.  If
\ the current word is full, start a new program word.  The constant
\ contained in the machine instruction word has four identical
\ machine code patterns in the four slots, so that the word ,I
\ can select one of them and add it to the current program word.
\ NOP machine instruction word has 1E in all four slots.  They
\ make up the 24-bit pattern 79E79E.
: INST   CONSTANT   DOES> @  ,I ;
79E79E INST nop

\ ANEW starts a new program word by filling the current word with
\ NOPs.  It is required when we have to assemble a 4-slot
\ instruction like CALL, BZ, or BNZ.
: anew   BEGIN Hi @ 10 AND 0= WHILE nop REPEAT 0 Bi !
         H @ Hw ! ;

\ JMP A defining word to assemble a 4-slot long instruction.  The
\ machine instruction thus defined will take an address on the
\ stack and assemble the least significant 18 bits of the address
\ into the address field of the instruction.
: JMP    CONSTANT  DOES> @  anew SWAP 3FFFF AND -OR #, ALIGN ;

\ BEGIN starts a new program word and marks its address on stack.
\ -;' terminates a colon word by changing the last subroutine
\ call into a jump.  This is tail-recursion, which saves the
\ return instruction at the end of a colon word.
\ LDI ( n ) assembles a Load-Immediate machine instruction and
\ add the literal value to the next word.
: begin  anew  H @ ;
: -;'    Hw @ RAM@ DUP $FC0000 AND 100000 =
         IF 100000 -OR Hw @ RAM! ELSE DROP THEN ;
: ldi    28A28A ,I  #, ;

\ CALL assembles a 18-bit call instruction to a location in the
\ current page of 256K words.
\ JUMP assembles a 18-bit jump instruction to a location in the
\ current page of 256K words.
\ BZ assembles a 18-bit conditional branch to a location in the
\ current page of 256K words.  Branch on T=0.
\ BNC assembles a 18-bit conditional branch to a location in the
\ current page of 256K words.  Branch on Carry Not Set.
\ UNTIL assembles a branch on T=0.
\ -UNTIL assembles a branch on no carry.
100000 JMP call
0 JMP jump   80000 JMP bz    C0000 JMP bnc
             80000 JMP until  C0000 JMP -until

\ The following words build structures in assembly code words,
\ much like those in the high level code.  Since we use the
\ Subroutine Thread Model for colon words, these structure words
\ will be used in the colon words as well.  The structures are:
\       IF ... THEN
\       IF ... ELSE ,,, THEN
\       SKIP ... THEN
\       BEGIN ... AGIAN
\       BEGIN ... UNTIL
\       BEGIN ... WHILE ... REPEAT
\ -IF, -WHILE, -UNTIL are similar to IF, WHILE, UNTIL, except
\ that they assemble BNC instead of BZ.
: if     begin 0 bz ;
: -if    begin 0 bnc ;
: skip   begin 0 jump ;
: then   DUP >R >R  begin  3FFFF AND  R> RAM@ -OR  R> RAM! ;
: else   skip SWAP then ;
: while   if  SWAP ;
: -while -if  SWAP ;
: repeat jump then ;
: again  jump ;

\ Here is the list of all the single slot machine instructions.
\ RET returns from subroutine call.
\ LDP loads a word and pushes it to T.  Address of word is in A.
\     A is auto-incremented.
\ LD load a word and pushes it to T.  Address of word is in A.
\ STP pops a word from T and stores it to memory.  Address of
\     word is in A.  A is auto-incremented.
\ ST pops a word from T and stores it to memory.  Address of
\     word is in A.
\ COM compliments T, ones compliment.
\ SHL left shifts T by one bit.
\ SHR right shifts T by one bit.  Arithmetic right shift.
\ MUL multiply step.
\ XOR pops data stack and XORs it to T.
\ AND pops data stack and ANDs it to T.
\ DIV divide step.
\ ADD pops data stack and ADDs it to T.
\ POP pushes T on data stack, and pops return stack to T.
\ LDA pushes T on data stack, and copy A to T.
\ DUP pushes T on data stack.
\ PUSH pushes T on return stack, and pops data stack to T.
\ STA Copies T to A and pops data stack to T.
\ DROP pops data stack to T.

                 41041 INST ret
249249 INST ldp   2CB2CB INST ld    34D34D INST stp   3CF3CF INST st
410410 INST com   451451 INST shl   492492 INST shr   4D34D3 INST mul
514514 INST xor   555555 INST and   596596 INST div   5D75D7 INST add
618618 INST pop   659659 INST lda   69A69A INST dup
71C71C INST push  75D75D INST sta ( 79E79E INST nop ) 7DF7DF INST drop

\ POPS alias of DROP, useful after high level DROP is defined.
\ PUSHS alias of DUP, useful after high level DUP is defined.
: pops drop ;
: pushs dup ;

\ LJUMP a long jump to a 24-bit address.  Pushes the address
\ on the return stack and then execute RET.
: ljump  ' >body @ ldi           \ get address of target word
   push  ret ;                    \ long jump

\ (MAKEHEAD) builds a header for a new word.  First builds the
\ link field using LASTH, and then packs the name count and name
\ into the name field, three bytes per word.
\ MAKEHEAD builds a header while retains the word pointer so
\ that the name string is still available to be printed.
: (makeHead)
   anew
   20 word                      \ get name of new definition
   lastH @ nameR!               \ fill link field of last word
   H @ lastH !                  \ save nfa in lastH
   forthdup c@ ,B                \ store count
   count 0 do
      count ,B              \ fill name field
   loop forthdrop anew
   ;
: makeHead
   >IN @ >R                     \ save interpreter pointer
   (makeHead)
   R> >IN !                     \ restore word pointer
   ;

\ $LIT packs a counted string into the next available space
\ in the target image, three bytes to a word.
: $LIT ( -- )
   anew
   22 WORD
   forthDUP c@ ,B ( compile count )
   count 0 DO
      count ,B ( compile characters )
   LOOP
   forthDROP anew ;

\ ': builds a new subroutine in the target without a header.
\ CODE builds a new code word in the target with a header.
\ :: builds a new colon word in the target with a header.  As
\ we are using the Subroutine Thread Model, :: is the same as
\ CODE, and colon words shared all the structure building tools
\ with code words.
: ':     begin  .head CONSTANT  DOES> @  call ;
: CODE makeHead ': ;
: :: CODE ;

cr

