home *** CD-ROM | disk | FTP | other *** search
- RPN Assembler
-
- This is a classic Forth assembler that utilizes RPN syntax. During
- assembly, the arguments and opcodes are executed to produce
- instructions which are added to the code segment. Those who prefer
- normal assembler syntax, should use the newer third party assembler
- facility. This RPN assembler is included only for older code, or code
- appearing on screens.
-
- Though this assembler is large, this penalty is minimised by including
- it as a virtual vocabulary. When the interpreter encounters either the
- word CODE or ;CODE, the assembler will be called into upper memory and
- the assembling of code will start. When no longer needed it can be
- removed by the word FORGET-SYS. It is automatically removed by SAVE"
- or any word that calls another virtual subsystem.
-
- It is assumed that the user has access to an 8086/8088 handbook such
- as: "iAPX 86,88 User's Manual" by Intel Corporation or "THE 8086 BOOK
- includes the 8088" by R.Rector and G.Alexy, OSBORNE/McGraw-Hill (though
- the latter has many errors).
-
- Using the RPN assembler
-
- Normally the external assembler/linker is provided for assembling
- code. In order for the RPN assembler to be used, it must be loaded
- in. The source code is provided for this. Type the following:
- INCLUDE" LOADRASM.TXT" (enter)
- To make the change permanent, simply save the forth system with
- SAVE" filename.EXE"
-
- Format for Code Words
-
- Assembling is initiated by either CODE or ;CODE and terminated by C;
- (or its alias END-CODE). The exit point(s) in a code word must be
- either APUSH-JMP or NEXT-JMP. APUSH-JMP (the hyphen is necessary) will
- assemble code to push the AX register onto the parameter stack and then
- do NEXT-JMP. NEXT-JMP assembles the following in-line code:
-
- WORD LODS BX, AX MOV WORD [BX] JMP
-
- The following are examples of usage:
-
- CODE U/MOD BX POP DX POP AX POP DX, BX CMP
- IFU< BX DIV DX PUSH APUSH-JMP
- THEN AX, # -1 MOV AX PUSH APUSH-JMP C;
-
- : CONSTANT CREATE: TS:,
- ;CODE
- 2 [BX] PUSH NEXT-JMP C;
-
- Logical Operators
-
- Logical operators have been added to the Assembler to simplify writing
- and reading the assembly code. They also obviate labels and forward
- referencing. The logical test words can be used after any operation
- code that causes the appropriate status flags to be set or cleared;
- i.e. CMP, CMPS, OR, ADD, SUB, etc.
-
- With the exception of REPEAT and AGAIN, which assemble unconditional
- signed relative two-byte jumps, these logical operators assemble
- one-byte jumps. The assembler will detect an attempt to assemble an
- out-of-range jump and will print an appropriate error message and stop
- assembling.
-
- DO..LEAVE..LOOP. This construct differs from the high-level FORTH
- construct in that only one argument is used. The CX register must
- contain the count upon reaching LOOP. The LEAVE operation will set the
- CX register to 1 which is first decremented upon reaching LOOP; then,
- an exit from the loop is made if the CX register is 0. If the CX
- register is not 0 upon reaching LOOP, the program counter will be set
- to the instruction just after DO. The count placed in the CX register
- can vary from 1 to FFFF (65535 decimal). The following is a simple
- illustration of usage.
-
- ( starting at addr, searches n bytes for char)
- ( addr n char --- addr -1 or 0 )
- CODE CHARSRCH
- AX POP CX POP DX, DI MOV DI POP
- DO SCAS
- IF= DI DEC DI PUSH DI, DX MOV AX, # -1 MOV APUSH-JMP
- THEN
- LOOP CX PUSH DI, DX MOV NEXT-JMP C;
-
- The sequence: IF= (or) IF< (or) IF0< (or) IFU< ... ELSE ... THEN
- will calculate the relative one-byte jumps and assemble the appropriate
- code, ie. JNZ, JNL, JNB, or JMP. The IF operators can be used after
- any operation that sets the appropriate flags. (Note that AX, AX OR
- has the same effect as AX, # 0 CMP but requires one less cycle).
-
- If the logical test is immediately followed by the word 'non' ('not'
- was not used to avoid conflict with the NOT op code), the test is
- negated. For example, AX, BX CMP IF= non ... would perform the
- operation following IF= if the AX and the BX registers were not equal.
-
- The following are examples of usage.
-
- CODE MAX AX POP BX POP AX, BX CMP
- IF< BX PUSH ELSE AX PUSH THEN NEXT-JMP C;
-
- CODE U< CX POP BX POP AX, AX XOR BX, CX CMP
- IFU< AX DEC THEN APUSH-JMP C;
-
- CODE ABS AX POP AX, AX OR
- IF0< AX NEG THEN APUSH-JMP C;
-
- CODE DIGIT DX POP BX POP AX, AX XOR BL, # 48 SUB
- IF< non BL, # 10 CMP
- IF< non BL, # 7 CMP
- IF< APUSH-JMP THEN
- THEN BL, DL CMP
- IF< AX DEC DX, DX XOR DL, BL MOV DX PUSH
- THEN
- THEN APUSH-JMP C;
-
- In a similar manner, the following logical sequences will compile the
- appropriate offsets and jump codes.
-
- BEGIN .. AGAIN
- BEGIN .. UNTIL= (or) UNTIL< (or) UNTILU< (or) UNTIL0<
- BEGIN .. WHILE= (or) WHILE< (or) WHILEU< (or) WHILE0< ... REPEAT
-
- Because the operation code word TEST produces a logical result that
- appears to be the reverse of the foregoing conditional branch words, a
- separate set of words are provided to replace them, namely: IFTEST
- IFNOTEST, WHILETEST, WHILENOTEST. Do not use the word 'non' to negate
- these words. For example IFNOTEST is the negative of IFTEST.
-
- The following word from the EDITOR illustrates a combined usage of
- these operators. The word <#SPCS?> will determine the number of blank
- spaces at the end of a 64 character line on the display. The operation
- is performed during retrace cycles.
-
- ( L#ADDR X-offset llength -- n )
- CODE <#SPCS?>
- -2 [BP], DI MOV
- CX POP AX POP AX, CX ADD AX, 1 SHL AX DEC
- DI POP ES PUSH ES: DX, CRTPORT MOV ES: ES, CRTSEG MOV
- DI, AX ADD BX, BX XOR STD
- BEGIN DI DEC CX DEC
- BEGIN AL, DX IN AL, # 1 TEST UNTILNOTEST CLI
- BEGIN AL, DX IN AL, # 1 TEST UNTILTEST AL, # 20 MOV SCAS
- IF= BX INC ELSE CX, CX XOR THEN CX, # 0 CMP
- UNTIL= CLD STI ES POP BX PUSH
- DI, -2 [BP] MOV NEXT-JMP C;
-
- Assembler Addressing
-
- The following nomenclature is used in defining the arguments for the
- assembler operation codes.
-
- ac = AX or AL
-
- reg = AX AH AL BX BH BL CX CH CL DX DH DL SI DI BP or SP
-
- mem/reg = any register, a direct memory address,
- [BX+SI] [BX+DI] [BP+SI] [BP+DI] [SI] [DI]
- [BX] [BP], or any bracketed expression plus a
- preceding displacement.
-
- port = a number, 0 through FFFF (hex)
-
- data = a number, 0 through FFFF (hex)
-
- segreg = CS DS ES or SS
-
- size = BYTE or WORD (if unspecified, BYTE is assumed)
-
- n = 0 to FF (hex)
-
- Assembler operation codes
-
- On the following page are the operation codes that can be assembled by
- the assembler and the required formats for the arguments. Note that
- the symbol # followed by a space must precede data. Also, when two
- arguments are used, they must be separated by a comma followed by a
- space. If a register is the first argument, the comma is part of the
- register label, eg:
- AX, BX MOV
- If the first argument is a number for a port or an address, a space
- must precede the comma, eg.
- 0FE42 , BX MOV.
-
- Where there is a one-byte versus two byte ambiguity, the default is one
- byte. To force a two byte operation, precede the operation code with
- the word WORD, eg.
- WORD [BX] NEG.
-
- Note that when using addresses with JMPs and CALLs the best size offset
- (8 or 16 bit) is selected by the assembler. To specify intersegment
- JMPs, CALLs +RETs and RETs the prefix FAR is used. For example to
- perform an intersegment indirect branch the following sequence is used
- FAR [BX] JMP
- When FAR is not used an intrasegment branch is assumed.
-
- Segment overrides are specified by placing CS: DS: ES: or SS: in front
- of the operation they are to modify.
-
- Before exiting from a code word via NEXT-JMP or APUSH-JMP, you must
- restore the following registers to the values they had upon entry to
- the routine:
- SI, DI
- CS, DS, SS, ES
- The flags DF, IM must both be restored with the instructions:
- STI and CLD.
- The following registers must not have unreasonable changes:
- SP, BP
- For more information on register usage see the implementation notes.
-
- Assembler LABELs
-
- In order to create branching or other labels within a code
- word, the declaration LABEL can be used. This creates a CONSTANT based
- on the current code segment dictionary pointer. This can be refered to
- in other code words or in high level Forth. This relys on the L.O.V.E.
- Forth characteristic, that CONSTANTs only add code to the thread and
- head segments. Example:
- CODE S>D ( signed conversion ( n -- d )
- AX POP CWD
- LABEL DXAX-PUSH ( push dx and ax )
- DX PUSH AX PUSH NEXT-JMP C;
-
- CODE D2* ( double double ( d-- d)
- AX POP DX POP DX, 1 SHL AX, 1 ROL DXAX-PUSH JMP C;
-
- Operation Codes
- AAA AAD AAM
- AAS
- ac, # data ADC mem/reg, # data ADC * mem/reg, mem/reg ADC
- ac, # data ADD mem/reg, # data ADD * mem/reg, mem/reg ADD
- ac, # data AND mem/reg, # data AND * mem/reg, mem/reg AND
- address CALL mem/reg CALL CBW
- CLC CLD CLI
- CMC
- ac, # data CMP mem/reg, # data CMP * mem/reg, mem/reg CMP
- size CMPS CWD DAA
- DAS reg DEC mem/reg DEC *
- mem/reg DIV * HLT mem/reg IDIV *
- mem/reg IMUL * ac, DX IN ac, port IN
- reg INC mem/reg INC * n INT
- INTO IRET
- address JA address JAE address JB
- address JBE address JCXZ address JE
- address JB address JGE address JL
- address JLE address JMP mem/reg JMP
- address JNA address JNAE address JNB
- address JNBE address JNE address JNG
- address JNGE address JNL address JNLE
- address JNO address JNP address JNS
- address JNZ address JO address JP
- address JPE address JPO address JS
- address JZ LAHF
- reg, mem/reg LDS reg, mem/reg LES reg, mem/reg LEA
- LOCK size LODS address LOOP
- address LOOPNE address LOOPNZ address LOOPZ
- reg, # data MOV mem/reg, # data MOV * mem/reg, mem/reg MOV
- ac, address MOV segreg, mem/reg MOV mem/reg, segreg MOV
- address , ac MOV size MOVS mem/reg MUL *
- mem/reg NEG * NOP mem/reg NOT *
- ac, # data OR mem/reg, # data OR * mem/reg, mem/reg OR
- DX, ac OUT port , ac OUT
- reg POP mem/reg POP segreg (not CS) POP
- POPF PUSHF
- reg PUSH mem/reg PUSH segreg PUSH
- mem/reg, 1 RCL * mem/reg, CL RCL *
- mem/reg, 1 RCR * mem/reg, CL RCR *
- REP REPE REPNE
- REPNZ REPZ RET
- mem/reg, 1 ROL * mem/reg, CL ROL *
- mem/reg, 1 ROR * mem/reg, CL ROR *
- SAHF
- mem/reg, 1 SAL * mem/reg, CL SAL *
- mem/reg, 1 SAR * mem/reg, CL SAR *
- ac, # data SBB mem/reg, # data SBB * mem/reg, mem/reg SBB
- size SCAS
- mem/reg, 1 SHL * mem/reg, CL SHL *
- mem/reg, 1 SHR * mem/reg, CL SHR *
- STC STD STI
- size STOS
- ac, # data SUB mem/reg, # data SUB * mem/reg, mem/reg SUB
- ac, # data TEST mem/reg, # data TEST * reg, mem/reg TEST
- WAIT AX, reg XCHG reg, mem/reg XCHG
- XLAT
- ac, # data XOR mem/reg, # data XOR * mem/reg, mem/reg XOR
- n +RET
- * these operations require a size (BYTE, WORD) when the operand is
- a memory location(s).