home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
forth
/
compiler
/
fpc
/
source
/
pasm.seq
< prev
next >
Wrap
Text File
|
1990-05-28
|
33KB
|
950 lines
\ PASM.SEQ PREFIX & POSTFIX assembler by Robert L. Smith & Tom Zimmer
comment:
An assembler for the 8086/8088, with both Prefix and Postfix syntax.
PASM defaults to Prefix notation, but can be switched to F83 style
Postfix notation with the word POSTFIX. To revert back to Prefix notation,
use PREFIX.
See the file ASSEM.TXT for a further description of the syntax.
comment;
0 VALUE ?LISTING
0 VALUE LRUNSAVE
0 VALUE LINESTRT
DEFER LIHERE ' HERE IS LIHERE
DEFER LIC@ ' C@ IS LIC@
: <LRUN> ( -- )
LIHERE =: LINESTRT
<RUN>
BASE @ >R HEX
CR LINESTRT 4 U.R SPACE
LIHERE
IF LINESTRT LIHERE OVER - 5 MIN BOUNDS
?DO I LIC@ 0 <# # # BL HOLD #> TYPE
LOOP
THEN 22 #OUT @ - SPACES
TIB #TIB @ TYPE
R> BASE ! ;
: /LISTING ( -- )
ON> ?LISTING
LRUNSAVE ABORT" Already LISTING!"
@> RUN =: LRUNSAVE
['] <LRUN> IS RUN ;
: /NOLISTING ( -- )
OFF> ?LISTING
LRUNSAVE IS RUN
OFF> LRUNSAVE ;
DEFER .INST ' NOOP IS .INST
\ The ASSEMBLER follows:
ONLY FORTH ALSO ASSEMBLER DEFINITIONS ALSO
2VARIABLE APRIOR 4 ALLOT
' DROP APRIOR ! ' DROP APRIOR 4 + !
: <A;!> ( A1 A2 --- ) \ Set up assembly instruction
APRIOR 4 + 2! ; \ completion function
: <A;> ( --- )
APRIOR 2@ EXECUTE \ perform assembly completion
APRIOR 4 + 2@ APRIOR 2! \ SET UP FOR NEXT PREVIOUS
['] DROP APRIOR 4 + ! \ Make it not care if it is redone.
.INST
\ LIHERE =: LINESTRT
;
: <RUN-A;> ( --- ) \ make sure we complete instruction
?LISTING
IF LIHERE =: LINESTRT
<RUN> <A;>
BASE @ >R HEX
CR LINESTRT 4 U.R SPACE
LIHERE
IF LINESTRT LIHERE OVER - 5 MIN BOUNDS
?DO I LIC@ 0 <# # # BL HOLD #> TYPE
LOOP
THEN 22 #OUT @ - SPACES
TIB #TIB @ TYPE
R> BASE !
ELSE <RUN> <A;> \ at the end of each line.
THEN ;
VARIABLE POSTVAR \ is this post fix notation?
FORTH DEFINITIONS
DEFER A;! ' <A;!> IS A;!
DEFER A; ' <A;> IS A;
DEFER RUN-A; ' <RUN-A;> IS RUN-A;
: PREFIX ( --- )
['] <A;!> IS A;!
['] <A;> IS A;
['] <RUN-A;> IS RUN-A; POSTVAR OFF ;
: POSTFIX ( --- )
['] EXECUTE IS A;!
['] NOOP IS A;
['] <RUN> IS RUN-A; POSTVAR ON ;
PREFIX \ Default is PREFIX assembler.
: >PRE 2R> POSTVAR @ >R 2>R PREFIX ; \ SAVE AND SET PREFIX
: PRE> 2R> R> IF POSTFIX THEN 2>R ; \ RESTORE PREVIOUS FIX
ASSEMBLER DEFINITIONS
DEFER C, FORTH ' C, ASSEMBLER IS C,
DEFER , FORTH ' , ASSEMBLER IS ,
DEFER HERE FORTH ' HERE ASSEMBLER IS HERE ' HERE IS LIHERE
DEFER TC! FORTH ' C! ASSEMBLER IS TC!
DEFER TC@ FORTH ' C@ ASSEMBLER IS TC@ ' TC@ IS LIC@
DEFER T! FORTH ' ! ASSEMBLER IS T!
DEFER ?>MARK
DEFER ?>RESOLVE
DEFER ?<MARK
DEFER ?<RESOLVE
comment:
The assembler contains the following routines for labels,
with +/- 127 byte offsets. They are used as follows:
CLEAR_LABELS \ Reset label mechanism
SUB AX, AX
JNE 2 $ \ Jump on not equal to label # 2
...
... \ You can have up to 127 bytes between
...
2 $: MOV AX, BX \ Destination of labeled jump.
A total of 32 short labels are currently supported.
The assembler also supports ONE long label.
Use L$ as follows: \ Usable with JMP or CALL
JMP L$ \ Does a long jump to L$:
...
... \ A bunch of bytes occur between these
... \ instructions
...
L$: MOV X, X \ Destination of long jump
comment;
\ =========================================================
\ BEGIN LOCAL LABELS SECTION:
\ =========================================================
\ "max-llabs" defines the maximum number of local labels
\ allowed (per CODE word or LABEL word). The labels may be
\ any of the values 0, 1, ..., (max-llabs - 1)
$20 value max-llabs
5 value b/llab
false value ll-global? \ are local labels available globally?
\ The local label table consists of one line per entry.
\ Each line consists of:
\
\ 1. The label dictionary location, ( 2 bytes)
\
\ 2. a pointer to the location of the first forward
\ reference (if any), and ( 2 bytes)
\
\ 3. an "ever referenced?" flag. ( 1 byte )
create %llab[] max-llabs b/llab * allot
%llab[] value llab[] \ default to %llab[] array
\ This flag is set if local labels are ever used (i.e., the
\ "$" or the "$:" word is used within a CODE word or a LABEL
\ word). The idea is simply to add a smidgen more time to the
\ "$" and "$:" words to save time later when checking for
\ local label errors when END-CODE is called.
false value ll-used?
: llab-init ( -- ) \ initializes local labels
llab[] max-llabs b/llab * erase
false !> ll-used? ;
\ Given a label number, returns pointer to line in table.
\ Aborts if label out of range.
: llab>line ( n -- ^line )
dup max-llabs 1- u> abort" Bad Label"
b/llab * llab[] + ;
\ Translates a label reference to the appropriate dictionary
\ location and sets the "ever referenced?" flag.
\
\ If the reference is a forward reference, then a linked list
\ of the forward references themselves is built using the
\ dictionary byte locations where the jump offsets are
\ "compiled". The reason for using this technique at all is
\ that it allows an arbitrary number of forward references per
\ label to be made (within the jump offset limitations of
\ course) and that it requires table space only for the linked
\ list head pointer. The technique is eloquent if convoluted
\ and, as a minimum, needs explanation.
: $ ( n1 -- n2 )
true !> ll-used? \ set "labels used?" flag
llab>line 1 over 4 + c! \ set "ever referenced?" flag
dup @ IF \ if the label is already defined:
@ \ then return it for resolution
ELSE \ otherwise:
2+ \ move to head of list pointer
dup @ >r \ save old head of list on rstack
here swap ! \ set new head of list
r> \ retrieve old head of list
dup 0= IF \ if list is empty:
here + \ pass current dictionary location
THEN \ end-if
THEN ; \ end-if
\ Resolves all local label forward references for a given
\ label.
: >res ( ^line -- )
2+ @ dup 0= IF \ if nothing to resolve
drop exit \ then exit
THEN
1+ BEGIN \ stack contains directory address of
\ displacement to be resolved
dup TC@ >r \ save link for now
here over - 1- \ calculate displacement
dup $7f > abort" Branch out of range"
over TC! \ and put in jump instruction
r> \ now ready for next link
$fe over <> WHILE \ $fe value signifies end of list
$ff00 or \ sign extend since link is backward
+ 2+ \ now move to next item on list
REPEAT 2drop ;
: $:f ( n -- ) \ defines a local label
true !> ll-used? \ set "labels used?" flag
llab>line
dup @ 0<> abort" Label can't be multiply defined"
dup >res \ resolve forward references if needed
here swap ! ; \ and set label for subsequent refs
: $: ( n -- ) \ allow use as prefix/postfix
['] $:f a;! a; ;
: _ll-errs? ( -- ) \ final error checking for local labels
false max-llabs 0 DO \ check each label
i b/llab * llab[] +
dup 4 + c@ 0<> IF \ if jumps to label
@ 0= IF \ and no label to jump to
cr ." jump(s) to label " i .
." and label not defined"
drop true \ set error flag
THEN
ELSE \ if no jumps to label
@ 0<> IF \ and label defined
cr ." warning - label " i .
." defined, but no jumps to it"
THEN
THEN
LOOP
IF abort THEN ; \ abort if fatal error
: ll-errs? ( -- ) \ final error checking for local labels
ll-used? IF _ll-errs? THEN ;
\ =========================================================
\ END LOCAL LABELS SECTION:
\ =========================================================
: L$ ( --- a1 ) \ Pass a1 to L$:
0 A; HERE ;
: L$: ( a1 --- ) \ a1 = addr passed by L$
A; HERE OVER - SWAP 2- T! ;
\ End of Local Label definitions
FORTH DEFINITIONS
' <RUN> VALUE ARUNSAVE
: DOASSEM ( --- )
@> RUN =: ARUNSAVE
['] RUN-A; IS RUN
0 ['] DROP A;!
APRIOR 4 + 2@ APRIOR 2!
LIHERE =: LINESTRT
ll-global? 0=
if llab-init \ in case labels used
then
ALSO ASSEMBLER ;
' DOASSEM IS SETASSEM
' LLAB-INIT ALIAS CLEAR_LABELS
: LOCAL_REF ( --- )
OFF> LL-GLOBAL? ; LOCAL_REF
\ default to LOCAL references only
: GLOBAL_REF ( --- )
ON> LL-GLOBAL? ;
: LABEL ( NAME --- ) \ Really just a constant addr
SETASSEM CREATE ;
: CODE ( NAME --- )
LABEL -3 DP +! HIDE ;
ASSEMBLER DEFINITIONS
: END-CODE
ll-global? 0=
if ll-errs? \ check for local label errors
then
ARUNSAVE IS RUN
PREVIOUS A; REVEAL ;
' END-CODE ALIAS C;
headerless
\ 8088 Assembler, based on Ray Duncan's Dr. Dobb's article.
: ERROR3 ( --- )
['] DROP APRIOR 4 + ! \ Make it not care if it is redone.
TRUE ABORT" Illegal Operand " ;
: ?ORDERERROR ( F1 --- )
IF ['] DROP APRIOR 4 + !
TRUE ABORT" Wrong Operand Order! "
THEN ;
VARIABLE <TD> VARIABLE <TS> VARIABLE <RD> VARIABLE <RS>
VARIABLE <W> VARIABLE <WD> VARIABLE <OD> VARIABLE <OS> VARIABLE <D>
VARIABLE <FR> VARIABLE <AO> VARIABLE <ND> VARIABLE <DST>
VARIABLE <SST> VARIABLE <WS> VARIABLE <ID>
: D>S ( --- ) \ Move destination to source.
<TD> @ <TS> !
<RD> @ <RS> !
<OD> @ <OS> ! ;
: ?D>S ( --- ) \ Move Dest to Src if postfix
<TS> @ 0= \ If no source specified
POSTVAR @ 0<> AND \ and we are in postfix mode
IF D>S \ Move destination to source
THEN ;
: ?D><S ( --- ) \ If no destinatiion specified
<DST> @ \ yet, then swap source and dest.
IF <TD> <TS> 2DUP @ SWAP @ ROT ! SWAP !
<RD> <RS> 2DUP @ SWAP @ ROT ! SWAP !
<OD> <OS> 2DUP @ SWAP @ ROT ! SWAP !
THEN <DST> OFF ;
: <SREG> ( A1 --- )
POSTVAR @
IF <DST> OFF \ Only reset dest if postfix
THEN <SST> ON
DUP C@ DUP $0FF = IF DROP ELSE DUP <W> ! <WS> ! THEN
1+ DUP C@ <TS> !
1+ C@ <RS> ! <TS> @ 4 = IF <OS> ! THEN ;
: <DREG> ( A1 --- )
<DST> ON
DUP C@ DUP $0FF = IF DROP ELSE DUP <W> ! <WD> ! THEN
1+ DUP C@ <TD> ! 1+ C@ <RD> !
<TD> @ 4 = IF <OD> ! THEN ;
HEADERS \ 05/28/90 21:20:16.87 TJZ
\ Destination Register processing.
: DREG CREATE C, C, C, DOES> POSTVAR @
IF <SREG>
ELSE <DREG>
THEN ;
\ Source Register processing.
: SREG CREATE C, C, C, DOES> POSTVAR @
IF <SST> @ IF <DREG> ELSE <SREG> THEN
ELSE <SREG>
THEN ;
\ Source Register Definitions
\ Reg Type W Name Reg Type W Name
0 2 0 SREG AL 0 3 1 SREG AX
1 2 0 SREG CL 1 3 1 SREG CX
2 2 0 SREG DL 2 3 1 SREG DX
3 2 0 SREG BL 3 3 1 SREG BX
4 2 0 SREG AH 4 3 1 SREG SP
5 2 0 SREG CH 5 3 1 SREG BP ' BP ALIAS RP
6 2 0 SREG DH 6 3 1 SREG SI ' SI ALIAS IP
7 2 0 SREG BH 7 3 1 SREG DI
0 4 -1 SREG [BX+SI] ' [BX+SI] ALIAS [SI+BX]
' [BX+SI] ALIAS [BX+IP]
' [BX+SI] ALIAS [IP+BX]
1 4 -1 SREG [BX+DI] ' [BX+DI] ALIAS [DI+BX]
2 4 -1 SREG [BP+SI] ' [BP+SI] ALIAS [SI+BP]
' [BP+SI] ALIAS [BP+IP]
' [BP+SI] ALIAS [IP+BP]
' [BP+SI] ALIAS [RP+IP]
' [BP+SI] ALIAS [IP+RP]
' [BP+SI] ALIAS [RP+SI]
' [BP+SI] ALIAS [SI+RP]
3 4 -1 SREG [BP+DI] ' [BP+DI] ALIAS [DI+BP]
' [BP+DI] ALIAS [DI+RP]
' [BP+DI] ALIAS [RP+DI]
4 4 -1 SREG [SI] ' [SI] ALIAS [IP]
5 4 -1 SREG [DI]
6 4 -1 SREG [BP] ' [BP] ALIAS [RP]
7 4 -1 SREG [BX]
0 5 -1 SREG ES
1 5 -1 SREG CS
2 5 -1 SREG SS
3 5 -1 SREG DS
\ Destination Register Definitions
0 5 -1 DREG ES,
1 5 -1 DREG CS,
2 5 -1 DREG SS,
3 5 -1 DREG DS,
0 2 0 DREG AL,
1 2 0 DREG CL,
2 2 0 DREG DL,
3 2 0 DREG BL,
4 2 0 DREG AH,
5 2 0 DREG CH,
6 2 0 DREG DH,
7 2 0 DREG BH,
0 3 1 DREG AX,
1 3 1 DREG CX,
2 3 1 DREG DX,
3 3 1 DREG BX,
4 3 1 DREG SP,
5 3 1 DREG BP, ' BP, ALIAS RP,
6 3 1 DREG SI, ' SI, ALIAS IP,
7 3 1 DREG DI,
0 4 -1 DREG [BX+SI], ' [BX+SI], ALIAS [SI+BX],
' [BX+SI], ALIAS [BX+IP],
' [BX+SI], ALIAS [IP+BX],
1 4 -1 DREG [BX+DI], ' [BX+DI], ALIAS [DI+BX],
2 4 -1 DREG [BP+SI], ' [BP+SI], ALIAS [SI+BP],
' [BP+SI], ALIAS [BP+IP],
' [BP+SI], ALIAS [IP+BP],
' [BP+SI], ALIAS [RP+SI],
' [BP+SI], ALIAS [SI+RP],
' [BP+SI], ALIAS [RP+IP],
' [BP+SI], ALIAS [IP+RP],
3 4 -1 DREG [BP+DI], ' [BP+DI], ALIAS [DI+BP],
' [BP+DI], ALIAS [DI+RP],
' [BP+DI], ALIAS [RP+DI],
4 4 -1 DREG [SI], ' [SI], ALIAS [IP],
5 4 -1 DREG [DI],
6 4 -1 DREG [BP], ' [BP], ALIAS [RP],
7 4 -1 DREG [BX],
\ Miscellaneous Operators
: TS@ <TS> @ ;
: TD@ <TD> @ ;
: RD@ <RD> @ ;
: RS@ <RS> @ ;
HEADERLESS \ 05/28/90 21:20:52.57 TJZ
: +D <D> @ 2* + ;
: +W <W> @ + ;
: +RD <RD> @ + ;
: +RS <RS> @ + ;
: MOD1 $03F AND $040 OR ;
: MOD2 $03F AND $080 OR ;
: MOD3 $03F AND $0C0 OR ;
: RS0 <RS> @ 8 * ;
: RSD RS0 +RD ;
: MD, RS0 6 + C, ;
: MS, RD@ 8 * 6 + C, ;
: RDS RD@ 8 * +RS ;
: CXD, C@ MOD3 +RD C, ;
: CXS, C@ MOD3 +RS C, ;
\ Equates to Addressing Modes
0 CONSTANT DIRECT 1 CONSTANT IMMED 2 CONSTANT REG8
3 CONSTANT REG16 4 CONSTANT INDEXED 5 CONSTANT SEGREG
\ Initialize all variables and flags
headers
: RESET 0 <W> ! 0 <OS> ! 0 <RD> !
0 <TD> ! 0 <TS> ! 0 <OD> !
0 <D> ! 0 <WD> ! 0 <RS> ! 0 <FR> ! 0 <ND> !
0 <DST> ! 0 <SST> ! 0 <WS> ! 0 <ID> ! ;
headerless
: REG? REG8 OVER = SWAP REG16 = OR ;
: DREG? TD@ REG? ;
: ADREG? DREG? RD@ ( 3 AND ) 0= AND ;
: ASREG? TS@ REG? RS@ ( 3 AND ) 0= AND ;
: SUBREG C@ $038 AND ;
\ Init. Direction Pointer
: DSET TS@ DUP INDEXED = SWAP DIRECT = OR NEGATE <D> ! ;
: DT 1 <D> ! ; \ Set Direction Flag True.
: OFFSET8, HERE 1+ - DUP ABS OVER 0< + $07F >
ABORT" Address out of range " C, ;
: OFFSET16, HERE 2+ - , ;
\ Calculate and store displacement for MEM/REG Instructions.
: DISP, <D> @ IF <OS> ELSE <OD> THEN @ DUP
IF DUP ABS $07F > IF SWAP MOD2 C, , ELSE SWAP MOD1 C, C, THEN
ELSE DROP DUP 7 AND 6 = IF MOD1 C, 0 THEN C, THEN ;
HEADERS \ 05/28/90 21:21:36.34 TJZ
\ Calculate the M/R 2nd operator byte
: M/RS, $038 AND TS@
CASE DIRECT OF 6 + C, , ENDOF
REG8 OF $0C0 + +RS C, ENDOF
REG16 OF $0C0 + +RS C, ENDOF
INDEXED OF <OS> @ 0= RS@ 6 <> AND
IF +RS C,
ELSE <OS> @ $080 + $0100 U<
IF $040 + +RS C, <OS> @ C,
ELSE $080 + +RS C, <OS> @ ,
THEN
THEN ENDOF
ERROR3
drop
ENDCASE ;
HEADERLESS \ 05/28/90 21:21:52.99 TJZ
: M/RD, ( ? --- ) D>S M/RS, ;
: 8/16, <W> @ IF , ELSE C, THEN ;
\ Words to build the instructions:
: 1MIF ( A1 --- )
C@ C, RESET ; \ Single Byte Inst.
: 1MI CREATE C, DOES> ['] 1MIF A;! A; ;
: 1AMIF ( A1 --- ) \ AX LODS or AX STOS
C@ +W C, RESET ; \ Single Byte Inst.
: 1AMI CREATE C, DOES> ['] 1AMIF A;! A; ;
: 2MIF ( A1 --- )
C@ C, OFFSET8, RESET ; \ Cond Jumps, Loops
: 2MI CREATE C, DOES> ['] 2MIF A;! A; ;
: 3MI CREATE C, DOES> C@ C, ; \ Segment Over-ride
: 4MIF ( A1 --- )
?D>S TS@ \ Reg. Push and Pop
CASE
SEGREG OF C@ RS@ 8 * + C, ENDOF \ SEGMENT
REG16 OF 1+ C@ +RS C, ENDOF \ REGISTER
REG8 OF ERROR3 ENDOF \ 8 BIT ILLEGAL
DROP 2+ C@ DUP C, $030 AND M/RS,
ENDCASE \ MEMORY
RESET ;
: 4MI CREATE C, C, C, DOES> ['] 4MIF A;! A; ;
: 5MIF ( A1 --- )
?D>S TS@ \ Iseg. Jump, Call
CASE DIRECT OF <ND> @
IF $0FF C, C@ <FR> @
IF 8 + THEN M/RS,
ELSE <FR> @
IF 2+ C@ C, , ,
ELSE OVER HERE 3 + - $080 + $0100 U<
OVER C@ $020 = AND
<WD> @ 0= AND
IF DROP $0EB C, OFFSET8,
ELSE 1+ C@ C, OFFSET16,
THEN
THEN
THEN ENDOF
REG16 OF $0FF C, CXS, ENDOF
INDEXED OF DSET $0FF C, C@ <FR> @
IF 8 + THEN +RS DISP, ENDOF
ERROR3 DROP
ENDCASE RESET ;
: 5MI CREATE C, C, C, DOES> ['] 5MIF A;! A; ;
: 6MIF ( A1 --- ) \ IN and OUT
DUP C@ 2 AND \ IN or OUT?
IF <WS> @ \ This is an OUT
ADREG? ?ORDERERROR
ELSE <WD> @ \ This is an IN
ASREG? ?ORDERERROR
THEN SWAP <ID> @ \ WAS THERE IMMEDIATE DATA ?
IF C@ + ( +W ) C, C,
ELSE 1+ C@ + ( +W ) C,
THEN RESET ;
: 6MI CREATE C, C, DOES> ['] 6MIF A;! A; ;
\ ADC, ADD, AND, etc.
: 7MIF ( A1 --- )
DUP 1+ C@ 1 AND <AO> !
TS@ IMMED =
IF ADREG?
IF 2+ C@ +W C, TD@ REG8 = IF C, ELSE , THEN
ELSE DUP 1+ C@ $0FE AND +W ROT >R \ Save IMMEDiate data
<AO> @
<W> @ AND \ *** 07/22/88 10:07:40.64
IF R@ $080 + $0100 U<
IF 2 OR C, C@ M/RD, R@ C,
ELSE C, C@ M/RD, R@ ,
THEN
ELSE C, C@ M/RD, R@ 8/16,
THEN r>drop \ Clean Return stack
THEN
ELSE C@ TS@ REG?
IF +W C, RS@ 8 * M/RD,
ELSE $084 OVER - IF 2 OR THEN +W C, TD@ REG?
IF RD@ 8 * M/RS, ELSE ERROR3 THEN
THEN
THEN RESET ;
: 7MI CREATE C, C, C, DOES> ['] 7MIF A;! A; ;
: 8MIF ( A1 --- )
?D>S
DUP 1+ C@ +W C, C@ M/RS, RESET ;
: 8MI CREATE C, C, DOES> ['] 8MIF A;! A; ;
: 9MIF ( A1 --- )
<DST> @ 0=
IF 1 <DST> ! ?D><S
1 <TS> ! 1 <SST> ! \ : # 1 <TS> ! 1 <SST> ! ;
1 SWAP <W> @ <WD> !
ELSE POSTVAR @ \ If postfix, reverse
IF ?D><S \ the operands
<WS> @ <WD> ! \ Correct word mode
THEN
THEN
DUP 1+ C@ <WD> @ +
TS@ 1 > IF 2+ C, ELSE C, NIP THEN C@ M/RD, RESET ;
: 9MI CREATE C, C, DOES> ['] 9MIF A;! A; ;
: 10MIF ( A1 --- )
DUP 1+ C@ C, C@ C, RESET ;
: 10MI CREATE C, C, DOES> ['] 10MIF A;! A; ;
: 11MIF ( A1 --- )
?D>S TS@ REG? <W> @ 0<> AND
IF C@ +RS C, ELSE 1+ C@ $0FE +W C, M/RS, THEN RESET ;
: 11MI CREATE C, C, DOES> ['] 11MIF A;! A; ;
: 12MIF ( A1 --- )
DROP \ MOV Instruction
TD@ SEGREG = IF $08E C, RD@ 8 * M/RS, ELSE
TS@ SEGREG = IF $08C C, RS@ 8 * M/RD, ELSE
TS@ IMMED = TD@ REG? AND
IF $016 +W 8 * +RD C, 8/16, ELSE
TS@ 0= TD@ 0= OR ADREG? ASREG? OR AND
IF $0A0 +W TS@ IF 2+ THEN C, , ( 8/16, ) ELSE
TS@ IMMED =
IF postvar @
\ ***** 09/26/88 18:33:25.98 ******* ZIMMER ***********
TD@ INDEXED <> AND
if swap then
$0C6 +W C, >R 0 M/RD, R> 8/16, ELSE
$088 +W TD@ REG?
IF 2+ C, RD@ 8 * M/RS, ELSE
TS@ REG? IF C, RS@ 8 * M/RD, ELSE ERROR3 THEN THEN THEN THEN
THEN THEN THEN
RESET ;
: 12MI CREATE DOES> ['] 12MIF A;! A; ;
: 13MIF ( A1 --- )
DROP TS@ REG? TD@ REG? AND \ Both are registers
RS@ 0= RD@ 0= OR AND \ Either register is AX
<W> @ 1 = AND \ And it is AX not AL.
IF RS@ 0=
IF RD@
ELSE RS@
THEN $090 + C,
ELSE $086 +W \ XCHG Instruction
TS@ REG? 0=
IF TD@ REG? 0=
IF ERROR3
ELSE C,
RD@ 8 * M/RS,
THEN
ELSE C, RS@ 8 * M/RD,
THEN
THEN RESET ;
: 13MI CREATE DOES> ['] 13MIF A;! A; ;
: 14MIF ( A1 --- )
C@ C, TD@ REG?
IF RD@ 8 * M/RS, ELSE ERROR3 THEN RESET ;
: 14MI CREATE C, DOES> ['] 14MIF A;! A; ;
: 15MIF ( A1 --- )
DROP DUP 3 =
IF DROP $0CC C, ELSE $0CD C, C, THEN RESET ;
: 15MI CREATE DOES> ['] 15MIF A;! A; ;
headers
\ Now let's create the actual instructions.
$37 1MI AAA $FC 1MI CLD
$D5 $0A 10MI AAD $FA 1MI CLI
$D4 $0A 10MI AAM $F5 1MI CMC
$3F 1MI AAS $3C $81 $38 7MI CMP
$14 $81 $10 7MI ADC $A6 1MI CMPSB
$04 $81 $00 7MI ADD $A7 1MI CMPSW
$24 $80 $20 7MI AND $99 1MI CWD
$9A $E8 $10 5MI CALL $27 1MI DAA
$98 1MI CBW $2F 1MI DAS
$F8 1MI CLC $08 $48 11MI DEC
$F6 $30 8MI DIV $73 2MI JAE
$F4 1MI HLT $72 2MI JB
$F6 $38 8MI IDIV $76 2MI JBE
$F6 $28 8MI IMUL $72 2MI JC
$EC $E4 6MI IN $E3 2MI JCXZ
$00 $40 11MI INC $74 2MI JE
15MI INT $7F 2MI JG
$CE 1MI INTO $7D 2MI JGE
$CF 1MI IRET $7C 2MI JL
$77 2MI JA $7E 2MI JLE
$EA $E9 $20 5MI JMP $7F 2MI JNLE
$76 2MI JNA $71 2MI JNO
$72 2MI JNAE $7B 2MI JNP
$73 2MI JNB $79 2MI JNS
$77 2MI JNBE $75 2MI JNZ
$73 2MI JNC $70 2MI JO
$75 2MI JNE $7A 2MI JP
$7E 2MI JNG $7A 2MI JPE
$7C 2MI JNGE $7B 2MI JPO
$7D 2MI JNL $78 2MI JS
$74 2MI JZ $E0 2MI LOOPNE
$9F 1MI LAHF $E0 2MI LOOPNZ
$C5 14MI LDS $E1 2MI LOOPZ
$8D 14MI LEA 12MI MOV
$C4 14MI LES $A4 1MI MOVSB
$F0 1MI LOCK $A5 1MI MOVSW $A5 1MI MOVS
$AC 1MI LODSB $F6 $20 8MI MUL $AC 1AMI LODS
$AD 1MI LODSW $F6 $18 8MI NEG
$E2 2MI LOOP $90 1MI NOP
$E1 2MI LOOPE $F6 $10 8MI NOT
$0C $80 $08 7MI OR $F2 1MI REPNE
$EE $E6 6MI OUT $F2 1MI REPNZ
$8F $58 $07 4MI POP $F3 1MI REPZ
$9D 1MI POPF $C3 1MI RET
$CB 1MI RETF
$FF $50 $06 4MI PUSH $D0 $00 9MI ROL
$9C 1MI PUSHF $D0 $08 9MI ROR
$D0 $10 9MI RCL $9E 1MI SAHF
$D0 $18 9MI RCR $D0 $38 9MI SAR
$F3 1MI REP $1C $81 $18 7MI SBB
$F3 1MI REPE $AE 1MI SCASB
$AF 1MI SCASW $AB 1MI STOSW $AA 1AMI STOS
$D0 $20 9MI SAL $2C $81 $28 7MI SUB
$D0 $20 9MI SHL $A8 $F6 $84 7MI TEST
$D0 $28 9MI SHR $9B 1MI WAIT
$F9 1MI STC 13MI XCHG
$FD 1MI STD $D7 1MI XLAT
$FB 1MI STI $34 $80 $30 7MI XOR
$AA 1MI STOSB \ ESC
\ =========================================================
\ BEGIN MNEMONIC JUMP SECTION:
\ =========================================================
\ The jump mnemonics:
' jmp alias j ( JMP )
' jne alias j0<> ( JNE )
' jz alias j0= ( JZ )
' jns alias j0>= ( JNS )
' js alias j0< ( JS )
' jne alias j<> ( JNE )
' jz alias j= ( JZ )
' jnl alias j>= ( JNL )
' jnge alias j< ( JNGE )
' jnle alias j> ( JNLE )
' jng alias j<= ( JNG )
' jnc alias ju>= ( JNC )
' jnae alias ju< ( JNAE )
' jnbe alias ju> ( JNBE )
' jna alias ju<= ( JNA )
\ =========================================================
\ END MNEMONIC JUMP SECTION:
\ =========================================================
\ Segment over-ride commands:
$26 3MI ES:
$2E 3MI CS:
$36 3MI SS:
$3E 3MI DS:
: FAR 1 <FR> ! ;
: BYTE 0 <W> ! 0 <WD> ! ;
: WORD 1 <W> ! 1 <WD> ! ;
: # 1 <TS> ! -1 <SST> ! 1 <ID> ! ;
: #) ( ?D><S ) -1 <SST> ! \ Swap source and dest if no dest spec'ed.
1 <W> ! ; \ Default to word mode
: [] 0 <W> ! 1 <ND> ! ;
: 3* DUP 2* + ;
\ MACROS for NEXT, 1PUSH, and 2PUSH.
VARIABLE INLN \ Flag to determine if we are compiling IN_LINE next.
: INLINEON INLN ON ;
: INLINEOFF INLN OFF ; INLINEOFF \ Default to NO INLINE NEXT.
: NEXT ( -- )
>PRE INLN @
IF LODSW ES: JMP AX A;
ELSE JMP >NEXT A;
THEN PRE> ;
: 1PUSH ( -- )
>PRE INLN @
IF PUSH AX LODSW ES: JMP AX A;
ELSE JMP >NEXT 1- A;
THEN PRE> ;
: 2PUSH ( -- )
>PRE INLN @
IF PUSH DX PUSH AX LODSW ES: JMP AX A;
ELSE JMP >NEXT 2- A;
THEN PRE> ;
headerless
: A?>MARK ( -- f addr ) TRUE HERE 0 C, ;
: A?>RESOLVE ( f addr -- ) HERE OVER 1+ - SWAP TC! ?CONDITION ;
: A?<MARK ( -- f addr ) TRUE HERE ;
: A?<RESOLVE ( f addr -- ) HERE 1+ - C, ?CONDITION ;
' A?>MARK ASSEMBLER IS ?>MARK
' A?>RESOLVE ASSEMBLER IS ?>RESOLVE
' A?<MARK ASSEMBLER IS ?<MARK
' A?<RESOLVE ASSEMBLER IS ?<RESOLVE
headers
$75 CONSTANT 0= $74 CONSTANT 0<> $79 CONSTANT 0<
$78 CONSTANT 0>= $7D CONSTANT < $7C CONSTANT >=
$7F CONSTANT <= $7E CONSTANT > $73 CONSTANT U<
$72 CONSTANT U>= $77 CONSTANT U<= $76 CONSTANT U>
$70 CONSTANT OV<> $71 CONSTANT OV $E3 CONSTANT CX<>0
$7B CONSTANT PE $7A CONSTANT PO
\ : DO ( n --- ) MOV CX # A; HERE ;
: BEGIN ( - a f ) A; ?<MARK ;
: UNTIL ( a f n - ) >R A; R> C, ?<RESOLVE A; ; \ ** ADDED A;
: AGAIN ( a f - ) $0EB UNTIL ;
: IF ( n - A f ) >R A; R> C, ?>MARK A; ; \ ** ADDED A;
: FORWARD ( - A f ) $0EB IF ;
: THEN ( A f - ) A; ?>RESOLVE ;
: AFT ( a f - a f A f ) 2DROP FORWARD BEGIN 2SWAP ;
: ELSE ( A f - A f ) FORWARD 2SWAP THEN ;
: REPEAT ( A f a f - ) A; AGAIN THEN ;
: CONTINUE ( a f A f - a f ) 2OVER REPEAT ;
: WHILE ( a f - A f a f ) IF 2SWAP ;
FORTH DEFINITIONS
: INLINE [COMPILE] [ SETASSEM HERE X, ; IMMEDIATE
ASSEMBLER DEFINITIONS
: END-INLINE [ ASSEMBLER ] END-CODE ] ;
COMMENT:
\ Here is an example of how to use INLINE and END-INLINE to add
\ assembly code in the middle of a CODE definition.
: TEST ( --- )
5 0
DO I
INLINE
pop ax
add ax, # 23
1push
END-INLINE
.
LOOP ;
COMMENT;
behead
ONLY FORTH DEFINITIONS ALSO
DECIMAL