]>
wirehaze git hosting - MS-DOS.git/blob - v1.25/source/ASM.ASM
1 ; Seattle Computer Products 8086 Assembler version 2.44
3 ; Runs on the 8086 under MS-DOS
5 ;* * * * * * REVISION HISTORY * * * * * *
7 ; 12/29/80 2.01 General release with 86-DOS version 0.34
8 ; 02/22/81 2.10 Increased buffer size from 128 bytes to 1024 bytes
9 ; 03/18/81 2.11 General cleanup and more documentation
10 ; 03/24/81 2.20 Modify ESC handling for full 8087 operation
11 ; 04/01/81 2.21 Fix date in HEX and PRN files; modify buffer handling
12 ; 04/03/81 2.22 Fix 2.21 buffer handling
13 ; 04/13/81 2.23 Re-open source file for listing to allow assembling CON:
14 ; 04/28/81 2.24 Allow nested IFs
15 ; 07/30/81 2.25 Add Intel string mnemonics; clean up a little
16 ; 08/02/81 2.30 Re-write pass 2:
17 ; Always report errors to console
18 ; Exact byte lengths for HEX and PRN files
19 ; 11/08/81 2.40 Add 8087 mnemonics; print full error messages;
20 ; allow expressions with *, /, and ()
21 ; 07/04/82 2.41 Fix Intel's 8087 "reverse-bit" bug; don't copy date
22 ; 08/18/82 2.42 Increase stack from 80 to 256 (Damn! Overflowed again!)
23 ; 01/05/83 2.43 Correct over-zealous optimization in 2.42
24 ; 05/09/83 2.44 Add memory usage report
26 ;* * * * * * * * * * * * * * * * * * * * *
28 SYMWID: EQU
5 ;5 symbols per line in dump
30 BUFSIZ: EQU
1024 ;Source code buffer
31 LSTBUFSIZ:EQU BUFSIZ
;List file buffer
32 HEXBUFSIZ:EQU
70 ;Hex file buffer (26*2 + 5*2 + 3 + EXTRA)
33 EOL: EQU
13 ;ASCII carriage return
34 OBJECT: EQU 100H
;DEFAULT "PUT" ADDRESS
36 ;System call function codes
45 ;The following equates define some token values returned by GETSYM
46 UNDEFID:EQU
0 ;Undefined identifier (including no nearby RET)
47 CONST: EQU
1 ;Constant (including $)
48 REG: EQU
2 ;8-bit register
49 XREG: EQU
3 ;16-bit register (except segment registers)
50 SREG: EQU
4 ;Segment register
51 FREG: EQU
6 ;8087 floating point register
53 ;Bits to build 8087 opcode table entries
54 ONEREG: EQU 40H
;Single ST register OK as operand
55 NEEDOP: EQU 80H
;Must have an operand
56 INTEGER:EQU 20H
;For integer operations
57 REAL: EQU 28H
;For real operations
58 EXTENDED EQU 10H
;For Long integers or Temporary real
59 MEMORY: EQU 18H
;For general memory operations
60 STACKOP:EQU 10H
;Two register arithmetic with pop
61 ARITH: EQU
8 ;Non-pop arithmetic operations
68 HEADER: DB 13,10,'Seattle Computer Products 8086 Assembler Version 2.44'
69 DB 13,10,'Copyright 1979-1983 by Seattle Computer Products, Inc.'
78 MOV [SYMFLG
],AL ;Save symbol table request flag
79 MOV SI,FCB
+9 ;Point to file extension
80 LODB
;Get source drive letter
81 CALL CHKDSK
;Valid drive?
83 JZ DEFAULT
;If no extension, use existing drive spec
86 LODB
;Get HEX file drive letter
87 CMP AL,'Z' ;Suppress HEX file?
92 LODB
;Get PRN file drive letter
93 MOV AH,0 ;Signal no PRN file
94 CMP AL,'Z' ;Suppress PRN file?
96 CMP AL,'Y' ;Print errors only on console?
99 CMP AL,'X' ;PRN file to console?
102 CMP AL,'P' ;PRN file to printer?
108 MOV [LSTDEV
],AH ;Flag device for list ouput
112 MOVB
;Set extension to ASM
113 MOVW
;Zero extent field
126 MOV [FCB
+12],AX ;Zero CURRENT BLOCK field
127 MOV [FCB
+32],AL ;Zero Next Record field
128 MOV [FCB
+14],BUFSIZ
;Set record size
129 MOV [BUFPT
],SRCBUF
;Initialize buffer pointer
130 MOV [CODE],START
+1 ;POINTER TO NEXT BYTE OF INTERMEDIATE CODE
131 MOV [IY
],START
;POINTER TO CURRENT RELOCATION BYTE
133 MOV [PC
],AX ;DEFAULT PROGRAM COUNTER
134 MOV [BASE
],AX ;POINTER TO ROOT OF ID TREE=NIL
135 MOV [RETPT
],AX ;Pointer to last RET record
136 MOV [IFFLG
],AL ;NOT WITHIN IF/ENDIF
137 MOV [CHKLAB
],AL ;LOOKUP ALL LABELS
139 MOV [LSTRET
],AX ;Location of last RET
140 MOV AX,[6] ;HL=END OF MEMORY
141 MOV [HEAP],AX ;BACK END OF SYMBOL TABLE SPACE
142 MOV [BCOUNT
],4 ;CODE BYTES PER RELOCATION BYTE
144 ;Assemble each line of code
147 CALL NEXTCHR
;Get first character on line
150 MOV AL,-1 ;Flag that no tokens have been read yet
152 CALL ASMLIN
;Assemble the line
154 CMP AL,-1 ;Any tokens found on line?
156 CALL GETSYM
;If no tokens read yet, read first one
162 MOV AL,14H
;Garbage at end of line error
167 XOR AL,AL ;Flag no errors on line
169 ;AL = error code for line. Stack depth unknown
175 MOV CH,0C0H ;Put end of line marker and error code (AL)
184 CALL NEXTCHR
;Scan over comments for linefeed
197 LODB
;Get drive select byte
198 CMP AL,20H
;If not valid, don't make file
204 MOVW
;Copy source file name
207 MOV [DI-9+14],1 ;Set record length to 1 byte
214 SUB AL,' ' ;If not present, set zero flag
217 JZ DSKERR
;Must be in range A-O
232 ;Buffer empty so refill it
234 PUSH AX ;AH must be saved
241 XCHG AX,DX ;Put error code in DL
243 MOV AL,DL ;Error code back in AL
246 MOV AL,1
AH ;Possibly signal End of File
247 JZ NOMOD
;If nothing read
261 ; Get two operands and check for certain types, according to flag byte
262 ; in CL. OP code in CH. Returns only if immediate operation.
264 PUSH CX ;Save type flags
266 PUSH DX ;Save first operand
268 POP BX ;First op in BX, second op in DX
269 MOV AL,SREG
;Check for a segment register
274 MOV AL,CONST
;Check if the first operand is immediate
277 JZ ERROR
;Error if so
278 POP CX ;Restore type flags
279 CMP AL,DH ;If second operand is immediate, then done
281 MOV AL,UNDEFID
;Check for memory reference
283 JZ STORE ;Is destination memory?
285 JZ LOAD ;Is source memory?
286 TEST CL,1 ;Check if register-to-register operation OK
290 CMP AL,BH ;Registers must be of same length
295 AND AL,1 ;Get register length (1=16 bits)
296 OR AL,CH ;Or in to OP code
297 CALL PUT
;And write it
298 POP CX ;Dump return address
300 ADD AL,AL ;Rotate register number into middle position
303 OR AL,0C0H ;Set register-to-register mode
304 OR AL,DL ;Combine with other register number
308 ;Come here if at least one operand is a segment register
309 POP CX ;Restore flags
310 TEST CL,8 ;Check if segment register OK
313 MOV CX,8E03H
;Segment register move OP code
315 CMP AL,DH ;Check if source is memory
317 CMP AL,BH ;Check if destination is memory
320 SUB AL,DH ;Check if source is 16-bit register
321 JZ RR
;If so, AL must be zero
322 MOV CH,8
CH ;Change direction
323 XCHG DX,BX ;Flip which operand is first and second
325 SUB AL,DH ;Let RR perform finish the test
329 TEST CL,004H ;Check if storing is OK
331 XCHG DX,BX ;If so, flip operands
332 AND CH,0FDH ; and zero direction bit
335 CMP AL,BH ;Check if memory-to-memory
338 CMP AL,REG
;Check if 8-bit operation
341 TEST CL,1 ;See if 8-bit operation is OK
345 SUB AL,6 ;Check for R/M mode 6 and register 0
346 OR AL,BL ; meaning direct load/store of accumulator
348 TEST CL,8 ;See if direct load/store of accumulator
349 JZ NOTAC
; means anything in this case
350 ; Process direct load/store of accumulator
352 AND AL,2 ;Preserve direction bit only
353 XOR AL,2 ; but flip it
354 OR AL,0A0H ;Combine with OP code
356 MOV AL,BH ;Check byte/word operation
359 POP CX ;Dump return address
360 JMP PUTADD
;Write the address
364 AND AL,1 ;Get byte/word bit
365 AND AL,CL ;But don't use it in word-only operations
366 OR AL,CH ;Combine with OP code
369 ADD AL,AL ;Rotate to middle position
372 OR AL,DL ;Combine register field
373 POP CX ;Dump return address
374 JMP PUTADD
;Write the address
384 ;Get the second operand: look for a comma and drop into GETOP
393 ; Get one operand. Operand may be a memory reference in brackets, a register,
394 ; or a constant. If a flag (such as "B" for byte operation) is encountered,
395 ; it is noted and processing continues to find the operand.
397 ; On exit, AL (=DH) has the type of operand. Other information depends
398 ; on the actual operand:
400 ; AL=DH=0 Memory Reference. DL has the address mode properly prepared in
401 ; the 8086 R/M format (middle bits zero). The constant part of the address
402 ; is in ADDR. If an undefined label needs to be added to this, a pointer to
403 ; its information fields is in ALABEL, otherwise ALABEL is zero.
405 ; AL=DH=1 Value. The constant part is in DATA. If an undefined label needs
406 ; to be added to this, a pointer to its information fields is in DLABEL,
407 ; otherwise DLABEL is zero. "$" and "RET" are in this class.
409 ; AL=DH=2 8-bit Register. DL has the register number.
411 ; AL=DH=3 16-bit Register. DL has the register number.
413 ; AL=DH=4 Segment Register. DL has the register number.
417 ;Enter here if we don't need a GETSYM first
418 CMP AL,'[' ;Memory reference?
420 CMP AL,5 ;Flag ("B", "W", etc.)?
422 CMP AL,REG
;8-Bit register?
424 CMP AL,XREG
;16-Bit register?
426 CMP AL,SREG
;Segment register?
428 VAL: ;Must be immediate
429 XOR AL,AL ;No addressing modes allowed
432 MOV AX,[CON
] ;Defined part
434 MOV AX,[UNDEF
] ;Undefined part
464 CMP DL,[MAXFLG
] ;Invalid flag for this operation?
475 ; Expression analyzer. On entry, if AL=0 then do not allow base or index
476 ; registers. If AL=1, we are analyzing a memory reference, so allow base
477 ; and index registers, and compute addressing mode when done. The constant
478 ; part of the expression will be found in CON. If an undefined label is to
479 ; be added to this, a pointer to its information fields will be found in
482 MOV AH,AL ;Flag is kept in AH
488 MOV CH,0 ;Initial mode
489 TEST AL,10H
;Test INDEX bit
490 RCL AL ;BASE bit (zero flag not affected)
491 JZ NOIND
;Jump if not indexed, with BASE bit in carry
493 RCL CH ;Rotate in BASE bit
497 RCL CH ;The low 3 bits now have indexing mode
499 OR CH,080H ;If undefined label, force 16-bit displacement
505 CMP AX,BX ;Is it a signed 8-bit number?
506 JNZ RET ;If not, use 16-bit displacement
507 AND CH,07FH ;Reset 16-bit displacement
508 OR CH,040H ;Set 8-bit displacement
510 JNZ RET ;Use it if not zero displacement
511 AND CH,7 ;Specify no displacement
512 CMP CH,6 ;Check for BP+0 addressing mode
514 OR CH,040H ;If BP+0, use 8-bit displacement
518 MOV CH,6 ;Try direct address mode
519 JNC RET ;If no base register, that's right
522 INC CH ;If not, must be BX
526 ;Analyze arbitrary expression. Flag byte in AH.
527 ;On exit, AL has type byte: 0=register or undefined label
528 MOV CH,-1 ;Initial type
530 XOR DX,DX ;Initial value
544 OR AH,4 ;Flag that a sign was found
548 POP CX ;Recover operator
549 POP BX ;Recover current value
552 OR AL,AL ;Is it register or undefined label?
553 JZ NOCON
;If so, then no constant part
554 CMP CL,"-" ;Subtract it?
586 OR CL,CL ;Can we operate on this type?
588 PUSH AX ;Save operator
589 CALL GETSYM
;Get past operator
593 POP CX ;Recover operator
594 POP BP ;And current value
595 XCHG AX,BP ;Save AH in BP
596 CMP CL,"/" ;Do we divide?
598 OR DX,DX ;Dividing by zero?
602 XOR DX,DX ;Make 32-bit dividend
608 MOV DX,AX ;Result in DX
609 XCHG AX,BP ;Restore flags to AH
610 MOV AL,-1 ;Indicate a number
629 CMP AL,XREG
;Only 16-bit register may index
632 TEST AH,1 ;Check to see if indexing is OK
637 SUB AL,3 ;Check for BX
639 SUB AL,2 ;Check for BP
646 MOV CL,2 ;Invalid base/index register
650 OR AH,20H
;Flag seeing index register DI
652 TEST AH,10H
;Check if already seen index register
654 OR AH,10H
;Flag seeing index register
658 OR AH,40H
;Flag seeing base register BP
660 TEST AH,80H
;Check if already seen base register
662 OR AH,80H
;Flag seeing base register
666 CALL GETSYM
;Eat the "("
668 CMP B
,[SYM
],")" ;Better have closing paren
675 TEST AH,8 ;Check if undefined label has been seen
677 OR AH,8 ;Flag seeing undefined label
730 POP BX ;Kill return address to STRGDAT loop
731 MOV AL,-1 ;Flag type as constant
737 ; The lexical scanner. Used only in the operand field. Returns with the token
738 ; in SYM and AL, sometimes with additional info in BX or DX.
740 ; AL=SYM=0 Undefined label. BX has pointer to information fields.
742 ; AL=SYM=1 Constant (or defined label). DX has value.
744 ; AL=SYM=2,3,4 8-bit register, 16-bit register, or segment register,
745 ; respectively. DL has register number.
747 ; AL=SYM=5 A mode flag (such as "B" for byte operation). Type of flag in DL
748 ; and also stored in FLAG: -1=no flags, 0=B, 1=W, 2=S, 3=L, 4=T.
750 ; AL=SYM=6 8087 floating point register, ST(n) or ST. DL has register number.
752 ; All other values are the ASCII code of the character. Note that this may
753 ; never be a letter or number.
902 SCAB
;See if one of B,W,S,L,T
903 JZ SAVFLG
;Go save flag
921 MOV DL,CL ;Need flag type in DL
932 ;Have detected "ST" for 8087 floating point stack register
933 MOV DL,0 ;Default is ST(0)
934 CALL SCANB
;Get next character
935 CMP AL,"(" ;Specifying register number?
938 CALL NEXTCHR
;Skip over the "("
939 CALL GETOP
;A little recursion never hurt anybody
940 CMP AL,CONST
;Better have found a constant
941 MOV CL,20 ;Operand error if not
943 CMP [DLABEL
],0 ;Constant must be defined
946 MOV DX,[DATA] ;Get constant
947 CMP DX,7 ;Constant must be in range 0-7
956 XOR AL,AL ;Zero set means register found
961 CMP [BX],"s"+7400H
;"st"
1028 ROL AL ;Make end-of-symbol bit least significant
1053 CMP AL,3 ;RET has 3 letters
1076 CMP AX,BX ;Signed 8-bit number?
1116 PUSH BX ;Save pointer to link field
1117 CALL CREATE
;Add the node
1119 MOV [SI-1],DX ;Link new node
1120 RET ;Zero was set by CREATE
1130 ; Add a new node to the identifier tree. The identifier is at ID with
1131 ; bit 7 of the last character set to one. The length of the identifier is
1132 ; in LENID, which is ID-1.
1135 ; 1. Length of identifier (1 byte)
1136 ; 2. Identifier (1-80 bytes)
1137 ; 3. Left link (2-byte pointer to alphabetically smaller identifiers)
1138 ; 4. Right link (0 if none larger)
1140 ; a. Defined flag (0=undefined, 1=defined)
1141 ; b. Value (2 bytes)
1143 ; This routine returns with AL=zero and zero flag set (which indicates
1144 ; on return from LOOKUP that it has not yet been defined), DX points
1145 ; to start of new node, and BX points to data field of new node.
1148 ADD AL,8 ;Storage needed for the node
1152 SUB BX,DX ;Heap grows downward
1155 MOV BX,[CODE] ;Check to make sure there's enough
1168 MOVB
;Move identifier and length into node
1174 MOV [BX],CL ;Zero left and right links
1178 XOR AL,AL ;Set zero flag
1179 MOV [BX],AL ;Zero defined flag
1180 POP DX ;Restore pointer to node
1234 MOV B
,[MAXFLG
],1 ;Allow only B and W flags normally
1247 CMP B
,[BX],"f" ;See if an 8087 mnemonic
1273 XCHG AX,BP ;Save count of opcodes in BP
1289 MOV AL,[BX+2] ;Get opcode
1292 NDPOP: ;First letter is "F" so must be 8087 opcode ("Numeric Data Processor")
1293 MOV B
,[MAXFLG
],4 ;Allow all type flags
1295 CMP B
,[BX],"n" ;"No-wait" form?
1300 INC BX ;Skip over the "N"
1302 MOV [NOWAIT
],AH ;0 for wait, 1 for no wait
1304 JB OPERR
;Not enough char left for valid opcode?
1308 XCHG AX,DX ;Save length in DX
1310 OR B
,[SI+BX],80H
;Set high bit of last character
1311 MOV AL,[BX] ;Get first char of opcode
1314 JB TRY2XM1
;Go see if opcode starts with "2"
1318 SHL AX ;Double to index into address table
1319 XCHG AX,SI ;Put in index register
1320 MOV DI,[SI+NDPTAB
] ;Get start of opcode table for this letter
1322 MOV AH,[DI] ;Number of opcodes starting with this letter
1324 JZ OPERR
;Any start with this letter?
1327 MOV SI,BX ;Pointer to start of opcode
1328 MOV CX,DX ;Get length of opcode
1330 CMPB
;Compare opcode to table entry
1332 DEC DI ;Back up in case that was last letter
1333 MOV AL,80H
;Look for char with high bit set
1337 INC DI ;Skip over info about opcode
1349 AND AL,7 ;Mask to special op number
1350 JZ FWAIT ;If zero, go handle FWAIT
1352 CMP B
,[NOWAIT
],0 ;Was "N" present (If not opcode was "FOP")
1354 MOV AL,9
BH ;Need Wait opcode after all
1362 CMP B
,[NOWAIT
],0 ;"FNWAIT" not legal
1364 RET ;Nothing to do - "WAIT" already sent
1370 MOV AL,9
BH ;Wait opcode
1373 LODW
;Get opcode info
1374 TEST AL,0F8H ;Any operand bits set?
1375 JZ NOOPS
;If no operands, output code
1376 TEST AL,78H
;Special case?
1379 CALL GETSYM
;See if any operands
1385 CMP AL,FREG
;Is it 8087 register?
1388 TEST AL,ONEREG
;One register OK as operand?
1389 JNZ PUTREG
;Yes - save it
1390 TEST AL,20H
;Memory-only operation?
1393 TEST AL,18H
;Two-register operation?
1394 JPE ERRJ4
;Must be exactly one bit set
1395 PUSH DX ;Save register number
1396 PUSH AX ;Save opcode
1407 XOR AL,2 ;Flip "POP" bit
1408 AND AL,0FBH ;Reset direction bit to ST(0)
1409 OR BL,BL ;Is first register ST(0)?
1412 OR BL,BL ;One of these must be ST(0)
1414 XOR AL,4 ;Flip direction
1417 TEST AL,2 ;Is POP bit set?
1418 JNZ ERRJ4
;Don't allow destination ST(0) then pop
1420 AND AH,0F8H ;Zero out register field
1424 CALL GETSYM
;Get to next symbol
1430 TEST AL,80H
;Is no operands OK?
1434 ;First test for FDIV or FSUB and reverse "R" bit if "D" bit is set
1440 XOR AH,8 ;Reverse "R" bit
1443 OR AL,0D8H ;ESC hook
1453 PUSH CX ;Save opcode
1454 CALL GETOP1
;Get memory operand
1455 CMP AL,UNDEFID
;Is it?
1459 TEST AL,20H
;Does it have memory format field?
1461 TEST AL,8 ;Check if any memory operand legal
1463 TEST AL,10H
;Check for 2-op arithmetic
1464 JNZ PUTMEM
;If not, just use as plain memory op
1466 AND AL,0F9H ;Zero memory format bits
1468 DEC CL ;Must now be in range 0-3
1470 MOV CH,AL ;Save opcode byte
1471 SHR AL ;Put format bits in bits 2 & 3
1473 OR AL,CL ;Combine format bits with flag
1476 OR AL,AL ;Valid combination?
1478 OR AH,AL ;Possibly set new bits in second byte
1479 OR AL,CH ;Set memory format bits
1486 OR AL,DL ;Combine addressing mode
1490 ;There are 16 entries in this table. The 4-bit index is built like this:
1491 ; Bit 3 0 for normal memory ops, 1 if extended is OK
1492 ; Bit 2 0 for integer, 1 for real
1493 ; Bit 0 & 1 Flag: 00=W, 01=S, 10=L, 11=T
1495 ;The entries in the table are used as two 3-bit fields. Bits 0-2 are ORed
1496 ;into the first byte of the opcode for the Memory Format field. Bits 3-6
1497 ;are ORed into the second byte to modify the opcode for extended operands.
1498 ;If bit 7 is set, then that combination is illegal.
1500 DB 6,2,80H
,80H
;Normal integers
1501 DB 80H
,0,4,80H
;Normal reals
1502 DB 6,2,2EH
,80H
;Extended integers
1503 DB 80H
,0,4,2
BH ;Extended reals
1564 ;Save byte in AL as pure code, with intermediate code bits 00. AL and
1565 ;DI destroyed, no other registers affected.
1568 MOV CH,0 ;Flag as pure code
1575 ;Save byte of code in AL, given intermediate code bits in bits 7&8 of CH.
1576 CALL PUTINC
;Save it and bump code pointer
1608 ;Save the word value described by [DLABEL] and [DATA] as code. If defined,
1609 ;two bytes of pure code will be produced. Otherwise, appropriate intermediate
1610 ;code will be generated.
1618 ;Same as PUTWOR, above, but for byte value.
1675 ;Save complete addressing mode. Addressing mode is in AL; if this is a register
1676 ;operation (>=C0), then the one byte will be saved as pure code. Otherwise,
1677 ;the details of the addressing mode will be investigated and the optional one-
1678 ;or two-byte displacement will be added, as described by [ADDR] and [ALABEL].
1684 CALL GEN
;Save the addressing mode as pure code
1689 JZ TWOBT
;Direct address?
1691 JZ PRET
;Indirect through reg, no displacement?
1693 JZ PRET
;Register to register operation?
1694 MOV CH,AL ;Save whether one- or two-byte displacement
1755 L0008: ;RR1 never returns
1775 MOV CL,1 ;Flag word as OK
1776 CALL NOTAC
;NOTAC never returns
2002 ;JMP and CALL mnemonics
2007 MOV B
,[MAXFLG
],3 ;Allow "L" flag
2020 ;Indirect jump. DL has addressing mode.
2029 CMP CH,3 ;Flag "L" present?
2030 JZ PUTADDJ
;If so, do inter-segment
2032 CMP CH,-1 ;Better not be a flag
2034 AND AL,0F7H ;Convert to intra-segment
2091 CMP DL,3 ;Is flag "L"?
2093 JNZ ERR10
;If not, bad flag
2114 ;Return is intra-segment (short) without add to SP.
2115 ;Record position for RET symbol.
2153 CMP AX,BX ;Signed 8-bit number?
2182 JNZ ERRJ
;First operand must be immediate
2184 TEST [DLABEL
],-1 ;See if all labels have been defined
2187 CMP AX,64 ;Must only be 6 bits
2190 MOV BL,AL ;Save for second byte
2194 OR AL,0D8H ;ESC opcode
2199 AND BL,7 ;Low 3 bits of first operand
2203 CMP AL,UNDEFID
;Check for memory operand
2205 CMP AL,CONST
;Check for another immediate
2211 OR BL,DL ;Combine mode with first operand
2217 TEST [DLABEL
],-1 ;See if second operand is fully defined
2221 CMP AX,8 ;Must only be 3 bit value
2223 OR AL,BL ;Combine first and second operands
2224 OR AL,0C0H ;Force "register" mode
2337 ;*********************************************************************
2341 ;*********************************************************************
2352 MOV B
,[HEXCNT
],-5 ;FLAG HEX BUFFER AS EMPTY
2358 MOV [LINE
],AX ;Current line number
2362 INT 33 ;Re-open source file
2364 MOV [FCB
+12],AX ;Set CURRENT BLOCK to zero
2365 MOV [FCB
+20H
],AL ;Set NEXT RECORD field to zero
2371 MOV DI,START
;Store code over used up intermediate code
2373 MOV [SPC
],AL ;No "special" yet (ORG, PUT, DS)
2374 MOV [ERR],AL ;No second pass errors yet
2376 SHL CL ;Shift out last bit of previous code
2377 DEC CH ;Still have codes left?
2379 LODB
;Get next flag byte
2383 SHL CL ;Set flags based on two bits
2392 ;Either a word or byte fixup is needed from a forward reference
2393 LODW
;Get pointer to symbol
2395 LODW
;Get constant part
2396 ADD AX,[BX+1] ;Add symbol value to constant part
2397 CMP B
,[BX],0 ;See if symbol got defined
2399 MOV B
,[ERR],100 ;Undefined - flag error
2402 OR CL,CL ;See if word or byte fixup
2410 CMP AX,DX ;See if in range +127 to -128
2411 JZ OBJBT
;If so, it's always OK
2412 NOT AH ;Check for range +255 to -256
2414 JNZ RNGERR
;Must always be in this range
2415 ;Check for short jump. If so, we're out of range; otherwise we're OK
2416 CMP DI,START
+1 ;Only one other byte on line?
2417 JNZ OBJBT
;Can't be short jump if not
2418 MOV AL,[START
] ;Get the first byte of this line
2419 CMP AL,0EBH ;Direct short jump?
2422 CMP AL,0E0H ;LOOP or JCXZ instruction?
2425 CMP AL,70H
;Conditional jump?
2426 MOV AL,DL ;Get code byte in AL
2427 JNZ OBJBT
;If not, we're OK
2429 MOV B
,[ERR],101 ;Value out of range
2435 CMP AL,-1 ;End of file?
2437 CMP AL,-10 ;Special item?
2441 PUSH AX ;Save error code
2443 AND AH,0FEH ;Reset error indicator
2444 OR AL,[ERR] ;See if any errors on this line
2446 OR AH,1 ;Send line to console if error occured
2450 CALL STRTLIN
;Print address of line
2452 SUB CX,SI ;Get count of bytes of code
2456 CALL SAVCD
;Ouput code to HEX and PRN files
2461 MOV CX,7 ;Allow 7 bytes of code per line
2465 BLNK: ;Put in 3 blanks for each byte not present
2472 POP AX ;Restore error code
2478 MOV AL,[SPC
] ;Any special funtion?
2484 MOV [SPC
],AL ;Record special function
2496 ;Handle DS pseudo-op
2502 ;Handle ORG pseudo-op
2507 ;Handle PUT pseudo-op
2512 ;Copy the source line to the ouput device. Line will be preceded by
2513 ;assembler-generated line number. This routine may be called several times
2514 ;on one line (once for each line of object code bytes), so it sets a flag
2515 ;so the line will only be output on the first call.
2519 JNZ CRLF
;Output line only if first time
2523 MOV BH,0 ;No leading zero suppression
2529 JZ CRLF
;Don't call NEXTCHR if listing suppressed
2530 PUSH SI ;Save the only register destroyed by NEXTCHR
2534 CMP AL,10 ;Output until linefeed found
2546 MOV BH,"0"-" " ;Enable leading zero suppression
2560 SUB AL,"0"-" " ;Convert leading zero to blank
2568 CALL HIDIG
;Convert to decimal and print 1000s digit
2569 CALL DIGIT
;Print 100s digit
2571 CALL HIDIG
;Convert to decimal and print 10s digit
2572 MOV BH,0 ;Ensure leading zero suppression is off
2576 AAM ;Convert binary to unpacked BCD
2577 OR AX,3030H
;Add "0" bias
2582 MOV BH,0 ;Turn off zero suppression if not zero
2584 SUB AL,BH ;Convert leading zeros to blanks
2601 TEST B
,[LSTDEV
],3 ;See if output goes to console
2604 INT 33 ;Output to console
2606 TEST B
,[LSTDEV
],4 ;See if output goes to printer
2609 INT 33 ;Output to printer
2613 TEST B
,[LSTDEV
],80H
;See if output goes to a file
2624 CMP DI,LSTBUF
+LSTBUFSIZ
2651 SUB AX,[HEAP] ;Size of symbol table
2655 SUB AX,[CODE] ;Free space remaining
2682 CALL WRTHEX
;Flush HEX file buffer
2691 OR AL,AL ;Any output device for symbol table dump?
2693 OR AL,1 ;If not, send it to console
2702 MOV B
,[SYMLIN
],SYMWID
;No symbols on this line yet
2704 MOV SP,BX ;Need maximum stack for recursive tree walk
2707 TEST B
,[LSTDEV
],80H
;Print listing to file?
2710 CALL WRTBUF
;Write end-of-file mark
2738 INC CL ;Invert last bit
2739 AND CL,1 ;Number of extra tabs needed (0 or 1)
2740 SHR AL ;Number of positions wide this symbol needs
2742 JNC WRTSYM
;Will it fit?
2746 CALL CRLF
;Start new line if not
2765 CMP B
,[SYMLIN
],0 ;Will any more fit on line?
2772 MOV B
,[SYMLIN
],SYMWID
2811 OR AL,AL ;Did an error occur?
2815 MOV BX,ERRMES
;Print "ERROR"
2818 ;We have error number in AL. See if there's an error message for it
2822 SCASB ;Do we have the error message
2823 JBE HAVMES
;Quit looking if we have it or passed it
2824 XCHG AX,BX ;Put 80H in AL to look for end of this message
2826 SCASB ;Look for high bit set in message
2827 JA NEXTMES
; which means we've reached the end
2828 XCHG AX,BX ;Restore error number to AL
2829 JMPS ERRLOOK
;Keep looking
2832 MOV BX,DI ;Put address of message in BX
2833 JZ PRNERR
;Do we have a message for this error?
2834 CALL PHEX
;If not, just print error number
2930 SUB DI,DX ;Length of buffer
2950 JZ RET ;Buffer empty?
2977 ; 8086 MNEMONIC TABLE
2979 ; This table is actually a sequence of subtables, each starting with a label.
2980 ; The label signifies which mnemonics the subtable applies to--A3, for example,
2981 ; means all 3-letter mnemonics beginning with A.
3520 ; 8087 MNEMONIC TABLE
3521 ; Similar to 8086 table above, except NOT distinguished by opcode length
3540 DB 7+NEEDOP
+MEMORY
,20H
3542 DB 7+NEEDOP
+MEMORY
,30H
3547 DB 0+ONEREG
+REAL
,0D1H
3549 DB 0+ONEREG
+REAL
,0D9H
3562 DB NEEDOP
+STACKOP
,30H
3566 DB NEEDOP
+STACKOP
,38H
3580 DB 5+NEEDOP
+ONEREG
,0
3585 DB 2+NEEDOP
+INTEGER
,0
3587 DB 3+NEEDOP
+INTEGER
+EXTENDED
,0
3589 DB 2+NEEDOP
+INTEGER
,20H
3591 DB 3+NEEDOP
+INTEGER
+EXTENDED
,18H
3593 DB 3+NEEDOP
+INTEGER
,10H
3595 DB 2+NEEDOP
+INTEGER
,8
3597 DB 2+NEEDOP
+INTEGER
,30H
3599 DB 2+NEEDOP
+INTEGER
,28H
3601 DB 2+NEEDOP
+INTEGER
,38H
3603 DB 2+NEEDOP
+INTEGER
,10H
3605 DB 2+NEEDOP
+INTEGER
,18H
3614 DB 1+NEEDOP
+ONEREG
+REAL
+EXTENDED
,0
3630 DB 1+NEEDOP
+MEMORY
,28H
3632 DB 1+NEEDOP
+MEMORY
,20H
3644 DB NEEDOP
+1,0 ;Flag special handling
3665 DB 5+NEEDOP
+MEMORY
,20H
3670 DB 5+NEEDOP
+ONEREG
+REAL
,0D0H
3672 DB 7+NEEDOP
+ONEREG
+REAL
+EXTENDED
,0D8H
3676 DB NEEDOP
+STACKOP
,0E0H
3680 DB NEEDOP
+STACKOP
,0E8H
3686 DB 5+NEEDOP
+MEMORY
,30H
3688 DB 1+NEEDOP
+MEMORY
,38H
3690 DB 1+NEEDOP
+MEMORY
,30H
3692 DB 5+NEEDOP
+MEMORY
,38H
3702 DB NEEDOP
,0 ;Flag special handling
3722 ; Table of pointers to mnemonics. For each letter of the alphabet (the
3723 ; starting letter of the mnemonic), there are 5 entries. Each entry
3724 ; corresponds to a mnemonic whose length is 2, 3, 4, 5, and 6 characters
3725 ; long, respectively. If there are no mnemonics for a given combination
3726 ; of first letter and length (such as A-2), then the corresponding entry
3727 ; points to NONE. Otherwise, it points to a place in the mnemonic table
3730 ; This table only needs to be modified if a mnemonic is added to a group
3731 ; previously marked NONE. Change the NONE to a label made up of the first
3732 ; letter of the mnemonic and its length, then add a new subsection to
3733 ; the mnemonic table in alphabetical order.
3867 ;Lookup table for 8087 mnemonics. There is one entry for each letter of the
3896 ;Error message table
3899 DM
1,"Register not allowed in immediate value"
3900 DM
2,"Index or base register must be BP, BX, SI, or DI"
3901 DM
3,"Only one base register (BX, BP) allowed"
3902 DM
4,"Only one index register (SI or DI) allowed"
3903 DM
5,"Only addition allowed on register or undefined label"
3904 DM
6,"Only one undefined label per expression allowed"
3905 DM
7,"Illegal digit in hexadecimal number"
3906 DM
8,"Illegal digit in decimal number"
3907 DM
10,"Illegal character in label or opcode"
3908 DM
11,"Label defined twice"
3909 DM
12,"Opcode not recognized"
3910 DM
20,"Invalid operand"
3911 DM
21,'"," and second operand expected'
3912 DM
22,"Register mismatch"
3913 DM
23,"Immediate operand not allowed"
3914 DM
24,'"]" expected'
3915 DM
25,"Two memory operands not allowed"
3916 DM
26,"Destination must not be immediate value"
3917 DM
27,"Both operands must not be registers"
3918 DM
28,"Operand must be segment register"
3919 DM
29,"First operand must be register"
3920 DM
30,"Undefined label not allowed"
3921 DM
31,"Value out of range"
3922 DM
32,"Missing or illegal operand size flag"
3923 DM
33,"Must have label on same line"
3924 DM
35,"Zero-length string illegal"
3925 DM
36,"ENDIF without IF"
3926 DM
37,"One-character strings only"
3927 DM
38,"Illegal expression"
3928 DM
39,"End of string not found"
3929 DM
100,"Undefined label"
3930 DM
101,"Value out of range (forward)"
3933 ERRMES: DM
'***** ERROR: '
3934 NOSPAC: DB 13,10,'File creation error',13,10,"$"
3935 NOMEM: DB 13,10,'Insufficient memory',13,10,'$'
3936 NOFILE: DB 13,10,'File not found',13,10,'$'
3937 WRTERR: DB 13,10,'Disk full',13,10,'$'
3938 BADDSK: DB 13,10,'Bad disk specifier',13,10,'$'
3939 ERCNTM: DM
13,10,13,10,'Error Count ='
3940 SYMSIZE DM
13,10,'Symbol Table size = '
3941 FRESIZE DM
'Free space = '
3942 SYMMES: DM
13,10,'Symbol Table',13,10,13,10
3943 EXTEND: DB 'ASM',0,0
3947 HEXFCB: DB 0,' HEX',0,0,0,0
3950 LSTFCB: DB 0,' PRN',0,0,0,0
3998 HEXBUF: DS HEXBUFSIZ
3999 LSTBUF: DS LSTBUFSIZ