home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
CPM
/
TURBOPAS
/
TP
/
UTL3
/
Z80.PZS
/
Z80.PAS
Wrap
Pascal/Delphi Source File
|
2000-06-30
|
63KB
|
1,907 lines
PROGRAM z80_assembler; {$V-,R+}
{
05 April 1985 - Dap
Z80 Assembler
}
CONST
Null = #00;
cr = #13;
end_ch = #27;
space = ' ';
tab = #09;
version = '[1.01] 10 October 1985';
TYPE
hex = 0 .. 15;
CONST
value : ARRAY ['0' .. 'F'] OF Byte =
( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
0, 0, 0, 0, 0, 0, 0, { :;<=>?@ }
10, 11, 12, 13, 14, 15 );
digit : ARRAY [hex] OF Char =
( '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F' );
TYPE
registers =
(
A, B, C, D, E, F, H, L, R,
IV, AF, BC, DE, HL, IX, IY, PC, SP,
null_reg
);
mnemonics =
(
ADC, ADD, AND_, BIT, CALL, CCF, CP, CPD, CPDR, CPI, CPIR, CPL,
DAA, DEC, DI, DJNZ, EI, EX, EXX, HLT, IM, IN_, INC,
IND, INDR, INI, INIR, JP, JR, LD, LDD, LDDR, LDI, LDIR,
NEG, NOP, OR_, OTDR, OTIR, OUT, OUTD, OUTI, POP, PUSH, RES,
RET, RETI, RETN, RL, RLA, RLC, RLCA, RLD, RR, RRA, RRC,
RRCA, RRD, RST, SBC, SCF, SET_, SLA, SRA, SRL, SUB, XOR_,
null_op
);
OtherSymbols =
(
DefineByte, DefineChar, DefineWord, Originate, Macro,
EndMacro, EndAssembly, TheRadix, Equate, IncludeFile,
PageSet, TitleSet, TypeSet, NullOther
);
symbols =
(
null_sym, identifier, number, operation, equal,
str_data, comma, semicolon, period, location,
colon, left_bp, right_bp, end_file, EndLine
);
reg_str = String[ 2];
mnem_str = String[ 4];
val_str = String[ 16];
file_name = String[ 23];
_String = String[ 80];
big_str = String[255];
LabelStr = String[ 15];
LabelPtr = ^LabelType;
LabelType =
RECORD
Name : LabelStr;
Loc : Integer;
Left : LabelPtr;
Right : LabelPtr;
END;
PLocPtr = ^PatchLoc;
PatchLoc =
RECORD
PLoc : Integer;
Oprtion : Char;
PAdj : Integer;
OSet : Boolean;
TwoBytes : Boolean;
PNext : PLocPtr
END;
PatchPtr = ^Patch;
Patch =
RECORD
PName : LabelStr;
FixLoc : PLocPtr;
LeftPatch : PatchPtr;
RightPatch : PatchPtr
END;
VAR
ops : ARRAY [mnemonics] OF mnem_str;
reg : ARRAY [registers] OF reg_str;
line : big_str;
ch_pos : Byte;
radix : Byte;
ch : Char;
io_error : Integer;
PosCnt : Integer; { Position Counter }
GenFile : FILE OF Byte;
in_name : file_name;
in_file : Text;
Labels : LabelPtr;
Patches : PatchPtr;
PROCEDURE init_ops;
BEGIN { init_ops }
ops[ADC ] := 'ADC';
ops[ADD ] := 'ADD';
ops[AND_] := 'AND';
ops[BIT ] := 'BIT';
ops[CALL] := 'CALL';
ops[CCF ] := 'CCF';
ops[CP ] := 'CP';
ops[CPD ] := 'CPD';
ops[CPDR] := 'CPDR';
ops[CPI ] := 'CPI';
ops[CPIR] := 'CPIR';
ops[CPL ] := 'CPL';
ops[DAA ] := 'DAA';
ops[DEC ] := 'DEC';
ops[DI ] := 'DI';
ops[DJNZ] := 'DJNZ';
ops[EI ] := 'EI';
ops[EX ] := 'EX';
ops[EXX ] := 'EXX';
ops[HLT ] := 'HALT';
ops[IM ] := 'IM';
ops[IN_ ] := 'IN';
ops[INC ] := 'INC';
ops[IND ] := 'IND';
ops[INDR] := 'INDR';
ops[INI ] := 'INI';
ops[INIR] := 'INIR';
ops[JP ] := 'JP';
ops[JR ] := 'JR';
ops[LD ] := 'LD';
ops[LDD ] := 'LDD';
ops[LDDR] := 'LDDR';
ops[LDI ] := 'LDI';
ops[LDIR] := 'LDIR';
ops[NEG ] := 'NEG';
ops[NOP ] := 'NOP';
ops[OR_ ] := 'OR';
ops[OTDR] := 'OTDR';
ops[OTIR] := 'OTIR';
ops[OUT ] := 'OUT';
ops[OUTD] := 'OUTD';
ops[OUTI] := 'OUTI';
ops[POP ] := 'POP';
ops[PUSH] := 'PUSH';
ops[RES ] := 'RES';
ops[RET ] := 'RET';
ops[RETI] := 'RETI';
ops[RETN] := 'RETN';
ops[RL ] := 'RL';
ops[RLA ] := 'RLA';
ops[RLC ] := 'RLC';
ops[RLCA] := 'RLCA';
ops[RLD ] := 'RLD';
ops[RR ] := 'RR';
ops[RRA ] := 'RRA';
ops[RRC ] := 'RRC';
ops[RRCA] := 'RRCA';
ops[RRD ] := 'RRD';
ops[RST ] := 'RST';
ops[SBC ] := 'SBC';
ops[SCF ] := 'SCF';
ops[SET_] := 'SET';
ops[SLA ] := 'SLA';
ops[SRA ] := 'SRA';
ops[SRL ] := 'SRL';
ops[SUB ] := 'SUB';
ops[XOR_] := 'XOR';
ops[null_op] := ''
END; { init_ops }
PROCEDURE init_reg;
BEGIN { init_reg }
reg[A ] := 'A';
reg[B ] := 'B';
reg[C ] := 'C';
reg[D ] := 'D';
reg[E ] := 'E';
reg[F ] := 'F';
reg[H ] := 'H';
reg[L ] := 'L';
reg[R ] := 'R';
reg[IV] := 'I';
reg[AF] := 'AF';
reg[BC] := 'BC';
reg[DE] := 'DE';
reg[HL] := 'HL';
reg[IX] := 'IX';
reg[IY] := 'IY';
reg[PC] := 'PC';
reg[SP] := 'SP';
reg[null_reg] := ''
END; { init_reg }
PROCEDURE usage;
BEGIN { usage }
WriteLn;
WriteLn ('Usage:');
WriteLn;
WriteLn (' Z80 <filename>[.ASM],[filename][.COM],[filename][.LST],[filename][.CRF][;]');
WriteLn;
WriteLn (' ie: Z80 test,,A:test;');
WriteLn;
Halt
END; { usage }
FUNCTION upper_ch ( ch : Char ) : Char;
BEGIN { upper_ch }
IF ch IN ['a' .. 'z'] THEN
ch := Chr (Ord (ch) - Ord ('a') + Ord ('A') );
upper_ch := ch
END; { upper_ch }
FUNCTION upper_str ( s : big_str ) : big_str;
VAR
i : Byte;
BEGIN { upper_str }
FOR i := 1 TO Length (s) DO
s[i] := upper_ch (s[i] );
upper_str := s
END; { upper_str }
PROCEDURE Error ( Message : _String );
BEGIN { Error }
WriteLn;
WriteLn (Message);
Halt
END; { Error }
PROCEDURE initialize;
VAR
i : Integer;
GenName : File_Name;
ErrorNum : _String;
BEGIN { initialize }
WriteLn;
WriteLn ('Z80 Assembler ', version);
IF ParamCount < 1 THEN
usage;
in_name := upper_str (ParamStr (1) );
IF (Pos ('.ASM', in_name) = 0) AND (Pos ('.', In_Name) = 0) THEN
in_name := in_name + '.ASM';
Assign (in_file, in_name);
{$I-}
Reset (in_file);
io_error := IoResult;
{$I+}
Str (Io_Error, ErrorNum);
IF io_error <> 0 THEN
Error ('Unable to open ' + in_name + ' due to I/O error #' + ErrorNum);
GenName := Copy (In_Name, 1, Pos ('.', In_Name) ) + 'Bin';
Assign (GenFile, GenName);
Rewrite (GenFile);
init_ops;
init_reg;
ch := ' ';
line := '';
ch_pos := 0;
radix := 10;
PosCnt := 0; { Position Counter }
Labels := Nil;
Patches := Nil;
END; { initialize }
FUNCTION val_radix ( s : val_str;
rdx : Byte ) : Integer;
VAR
i : Integer;
BEGIN { val_radix }
i := 0;
s := upper_str (s);
WHILE Length (s) > 0 DO
BEGIN
i := i * rdx + value[s[1] ];
Delete (s, 1, 1)
END;
val_radix := i
END; { val_radix }
FUNCTION str_radix ( i, wide : Integer;
rdx, pwr : Byte ) : val_str;
VAR
r : Real;
s : val_str;
FUNCTION power ( x : Real;
y : Byte ) : Real;
BEGIN { power }
IF y = 0 THEN
x := 1
ELSE
WHILE y > 1 DO
BEGIN
x := x * x;
y := y - 1
END;
power := x
END; { power }
BEGIN { str_radix }
s := '';
IF i < 0 THEN
BEGIN
r := power (256.0, pwr) + i;
WHILE r > 0.0 DO
BEGIN
i := Trunc (r - Int (r / rdx) * rdx);
r := Int (r / rdx);
s := digit[i] + s
END
END
ELSE
WHILE i > 0 DO
BEGIN
s := digit[i MOD rdx] + s;
i := i DIV rdx;
END;
WHILE Length (s) < wide DO
s := '0' + s;
str_radix := s
END; { str_radix }
PROCEDURE get_line;
BEGIN { get_line }
ReadLn (in_file, line);
ch_pos := 0
END; { get_line }
PROCEDURE get_ch;
BEGIN { get_ch }
ch_pos := ch_pos + 1;
IF ch_pos <= Length (line) THEN
ch := line[ch_pos]
ELSE IF Eof (in_file) THEN
ch := end_ch
ELSE
BEGIN
get_line;
ch := cr
END
END; { get_ch }
FUNCTION next_ch : Char;
BEGIN { next_ch }
IF ch_pos < Length (line) THEN
next_ch := line[ch_pos + 1]
ELSE
next_ch := cr
END; { next_ch }
PROCEDURE parser;
VAR
start_ch : Char;
TempOpCh : Char;
chars : big_str;
ident : LabelStr;
LabelId : LabelStr;
num : String[16];
p_radix : Byte;
CurChPos : Byte;
sym : symbols;
PROCEDURE get_symbol;
BEGIN { get_symbol }
sym := null_sym;
chars := '';
ident := '';
num := '';
REPEAT
get_ch
UNTIL NOT (ch IN [space, tab] );
IF ch IN ['A' .. 'Z', 'a' .. 'z'] THEN { Identifier }
BEGIN
sym := identifier;
ident := ch;
WHILE next_ch IN ['A' .. 'Z', 'a' .. 'z', '0' .. '9', '_'] DO
BEGIN
get_ch;
ident := ident + ch
END
END
ELSE IF ch IN ['0' .. '9'] THEN { Number }
BEGIN
sym := number;
num := ch;
WHILE next_ch IN ['0' .. '9', 'A' .. 'F', 'a' .. 'f'] DO
BEGIN
get_ch;
num := num + ch
END;
IF next_ch IN ['H', 'O', 'Q', 'h', 'o', 'q'] THEN
BEGIN
get_ch;
CASE ch OF
'H', 'h' : p_radix := 16; { Hexidecimal }
'O', 'o',
'Q', 'q' : p_radix := 8; { Octal }
END
END
ELSE
CASE num[Length (num) ] OF
'B', 'b' :
BEGIN
p_radix := 2; { Binary }
Delete (num, Length (num), 1)
END;
'D', 'd' :
BEGIN
p_radix := 10; { Decimal }
Delete (num, Length (num), 1)
END
ELSE
p_radix := radix
END
END
ELSE IF ch IN ['/', '+', '-', '*'] THEN { Arith }
sym := operation
ELSE IF ch IN ['[', '('] THEN { Memory or parenthesis in expression }
sym := left_bp
ELSE IF ch IN [']', ')'] THEN
sym := right_bp
ELSE IF ch IN ['''', '"'] THEN { String or Char }
BEGIN
sym := str_data;
start_ch := ch;
get_ch;
WHILE NOT (ch IN [start_ch, cr] ) DO
BEGIN
chars := chars + ch;
get_ch
END;
IF ch = cr THEN
Error ('Strings must not exceed current line.')
END
ELSE IF ch = ':' THEN { Label }
sym := colon
ELSE IF ch = ',' THEN { Seperator }
sym := comma
ELSE IF ch = '.' THEN { Special commands }
sym := period
ELSE IF ch = ';' THEN { Comment -- ignore rest of line }
BEGIN
sym := semicolon;
WriteLn;
Write (Copy (Line, Ch_Pos, Length (Line) ) );
ch_pos := Length (line)
END
ELSE IF ch = '$' THEN { Current location value }
sym := location
ELSE IF ch = '=' THEN { EQU -- another form }
sym := equal
ELSE IF ch = end_ch THEN { End of file }
sym := end_file
ELSE IF Ch = Cr THEN { End of line }
Sym := EndLine
END; { get_symbol }
FUNCTION check_op : mnemonics;
VAR
op_is : mnemonics;
id : String[31];
BEGIN { check_op }
op_is := ADC;
id := upper_str (ident);
WHILE (ops[op_is] <> id) AND (op_is < null_op) DO
op_is := Succ (op_is);
check_op := op_is
END; { check_op }
FUNCTION check_reg : registers;
VAR
reg_is : registers;
id : String[31];
BEGIN { check_reg }
reg_is := A;
id := upper_str (ident);
WHILE (reg[reg_is] <> id) AND (reg_is < null_reg) DO
reg_is := Succ (reg_is);
check_reg := reg_is
END; { check_reg }
FUNCTION Others : OtherSymbols;
VAR
id : String[31];
BEGIN { Others }
id := upper_str (ident);
IF (id = 'DB') OR (id = 'DEFB') OR (id = 'DEFBYTE') THEN { Define byte data }
Others := DefineByte
ELSE IF (id = 'DC') OR (id = 'DEFC') OR (id = 'DEFCHAR') THEN { Define char data }
Others := DefineChar
ELSE IF (id = 'DM') OR (id = 'DEFM') OR (id = 'DEFMEM') THEN { Define char data }
Others := DefineChar
ELSE IF (id = 'DW') OR (id = 'DEFW') OR (id = 'DEFWORD') THEN { Define word data }
Others := DefineWord
ELSE IF id = 'ORG' THEN { Originate code at this address }
Others := Originate
ELSE IF id = 'MACRO' THEN { Indicate this is a macro }
Others := Macro
ELSE IF id = 'ENDM' THEN { End of macro }
Others := EndMacro
ELSE IF id = 'END' THEN { End of assembly text file }
Others := EndAssembly
ELSE IF id = 'RADIX' THEN { Default base for all numbers }
Others := TheRadix
ELSE IF id = 'EQU' THEN { Set identifier to be equal to this value }
Others := Equate
ELSE IF id = 'INCLUDE' THEN { Use the text from the following file name }
Others := IncludeFile
ELSE IF id = 'PAGE' THEN { Either force page break or set page height, width }
Others := PageSet
ELSE IF id = 'TITLE' THEN { Use the follow as the title line on assembler listing }
Others := TitleSet
ELSE IF id = 'TYPE' THEN { Force use of incompatible types, ie. BYTE < WORD }
Others := TypeSet
ELSE
Others := NullOther
END; { Others }
PROCEDURE Generate ( Code : _String );
VAR
Loc : Byte;
OrV : Byte;
BEGIN { Generate }
FOR Loc := 1 TO Length (Code) DO
BEGIN
OrV := Ord (Code[Loc] );
Write (GenFile, OrV);
PosCnt := PosCnt + 1
END
END; { Generate }
PROCEDURE ParseMnemonic ( OpIs : Mnemonics );
CONST
Skip = #00;
VAR
Value : Integer;
Sym2 : Symbols;
Ident2 : String[31];
Num2 : String[16];
PROCEDURE AddLoc ( VAR ALoc : PLocPtr;
NLoc : PLocPtr );
BEGIN { AddLoc }
IF ALoc = Nil THEN
Aloc := NLoc
ELSE
AddLoc (ALoc^.PNext, NLoc)
END; { AddLoc }
PROCEDURE AddPatch ( VAR APatch : PatchPtr;
Both : Boolean;
Id : LabelStr;
AOffset : Boolean;
OprCh : Char;
PAValue : Integer );
VAR
TPatch : PatchPtr;
TPLoc : PLocPtr;
BEGIN { AddPatch }
IF APatch = Nil THEN
BEGIN
New (TPLoc);
WITH TPLoc^ DO
BEGIN
PLoc := PosCnt;
Oprtion := OprCh;
PAdj := PAValue;
OSet := AOffset;
TwoBytes := Both;
PNext := Nil
END;
New (TPatch);
WITH TPatch^ DO
BEGIN
PName := Id;
FixLoc := TPLoc;
LeftPatch := Nil;
RightPatch := Nil
END;
APatch := TPatch
END
ELSE IF Id < APatch^.PName THEN
AddPatch (APatch^.LeftPatch, Both, Id, AOffset, OprCh, PAValue)
ELSE IF Id > APatch^.PName THEN
AddPatch (APatch^.RightPatch, Both, Id, AOffset, OprCh, PAValue)
ELSE
BEGIN
New (TPLoc);
WITH TPLoc^ DO
BEGIN
PLoc := PosCnt;
Oprtion := OprCh;
PAdj := PAValue;
OSet := AOffset;
TwoBytes := Both;
PNext := Nil
END;
AddLoc (APatch^.FixLoc, TPLoc)
END
END; { AddPatch }
PROCEDURE ViaLabel ( LeadIn : _String;
Both : Boolean;
Id : LabelStr;
AOffset : Boolean;
OprCh : Char;
PAValue : Integer );
BEGIN { ViaLabel }
Write (' Via label [', Id, ']');
Generate (LeadIn);
AddPatch (Patches, Both, Id, AOffset, OprCh, PAValue);
Generate (Null);
IF Both THEN
Generate (Null)
END; { ViaLabel }
PROCEDURE OperLabel ( LeadIn : _String;
Both : Boolean;
Id : LabelStr;
AOffset : Boolean );
BEGIN { OperLabel }
Get_Symbol; { Operation | ? }
IF Sym <> Operation THEN
ViaLabel (LeadIn, Both, Id, AOffset, '+', 0)
ELSE
BEGIN
TempOpCh := Ch;
Get_Symbol; { Number }
IF Sym <> Number THEN
Write ('Number expected');
ViaLabel (LeadIn, Both, Id, AOffset, TempOpCh, Val_Radix (Num, P_Radix) )
END
END; { OperLabel }
PROCEDURE DoReg1 ( LeadIn : Char;
StartOp : Byte );
BEGIN { DoReg1 }
IF LeadIn <> Skip THEN
Generate (LeadIn);
CASE Check_Reg OF
A : Generate (Chr (StartOp - 0) );
B : Generate (Chr (StartOp - 7) );
C : Generate (Chr (StartOp - 6) );
D : Generate (Chr (StartOp - 5) );
E : Generate (Chr (StartOp - 4) );
H : Generate (Chr (StartOp - 3) );
L : Generate (Chr (StartOp - 2) );
END
END; { DoReg1 }
PROCEDURE DoONCR ( StartOp : Byte );
BEGIN { DoONCR }
CASE Sym OF
Identifier : DoReg1 (#$CB, StartOp);
Left_Bp :
BEGIN
Get_Symbol;
IF Sym <> Identifier THEN
Error ('Op code expected')
ELSE
CASE Check_Reg OF
HL : Generate (#$CB + Chr (StartOp - 1) );
IX :
BEGIN
Get_Symbol;
IF Sym <> Operation THEN
Error ('+ Expected')
ELSE
Get_Symbol;
Generate (#$DD + #$CB + Chr (Val_Radix (Num, P_Radix) ) + Chr (StartOp - 1) )
END;
IY :
BEGIN
Get_Symbol;
IF Sym <> Operation THEN
Error ('+ Expected')
ELSE
Get_Symbol;
Generate (#$FD + #$CB + Chr (Val_Radix (Num, P_Radix) ) + Chr (StartOp - 1) )
END
END;
Get_Symbol { Right_BP }
END
END
END; { DoONCR }
PROCEDURE DoOR;
BEGIN { DoOR }
Sym := Sym2;
Ident := Ident2;
Num := Num2;
CASE OpIs OF
AND_ :
IF Check_Reg IN [A .. L] THEN
DoReg1 (Skip, $A7)
ELSE IF Sym = Number THEN
Generate (#$E6 + Chr (Val_Radix (Num, P_Radix) ) )
ELSE
ViaLabel (#$E6, False, Ident, False, '+', 0);
CALL :
IF Sym = Number THEN
Generate (#$CD + Chr (Lo (Val_Radix (Num, P_Radix) ) ) + Chr (Hi (Val_Radix (Num, P_Radix) ) ) )
ELSE
ViaLabel (#$CD, True, Ident, False, '+', 0);
CP :
IF Check_Reg IN [A .. L] THEN
DoReg1 (Skip, $BF)
ELSE IF Sym = Number THEN
Generate (#$FE + Chr (Val_Radix (Num, P_Radix) ) )
ELSE
ViaLabel (#$FE, False, Ident, False, '+', 0);
DEC :
CASE Check_Reg OF
A : Generate (#$3D);
B : Generate (#$05);
BC : Generate (#$0B);
C : Generate (#$0D);
D : Generate (#$15);
DE : Generate (#$1B);
E : Generate (#$1D);
H : Generate (#$25);
HL : Generate (#$2B);
IX : Generate (#$DD + #$2B);
IY : Generate (#$FD + #$2B);
L : Generate (#$2D);
SP : Generate (#$3B);
END;
IM :
CASE Val_Radix (Num, P_Radix) OF
0 : Generate (#$ED + #$46);
1 : Generate (#$ED + #$56);
2 : Generate (#$ED + #$5E);
END;
INC :
CASE Check_Reg OF
A : Generate (#$3C);
B : Generate (#$04);
BC : Generate (#$03);
C : Generate (#$0C);
D : Generate (#$14);
DE : Generate (#$13);
E : Generate (#$1C);
H : Generate (#$24);
HL : Generate (#$23);
IX : Generate (#$DD + #$23);
IY : Generate (#$FD + #$23);
L : Generate (#$2C);
SP : Generate (#$33);
END;
JP :
IF Sym = Number THEN
Generate (#$C3 + Chr (Lo (Val_Radix (Num, P_Radix) ) ) + Chr (Hi (Val_Radix (Num, P_Radix) ) ) )
ELSE
ViaLabel (#$C3, True, Ident, False, '+', 0);
JR :
IF Sym = Number THEN
Generate (#$18 + Chr (Val_Radix (Num, P_Radix) ) )
ELSE
ViaLabel (#$18, False, Ident, True, '+', 0);
OR_ :
IF Check_Reg IN [A .. L] THEN
DoReg1 (Skip, $B7)
ELSE IF Sym = Number THEN
Generate (#$F6 + Chr (Val_Radix (Num, P_Radix) ) )
ELSE
ViaLabel (#$F6, False, Ident, False, '+', 0);
POP :
CASE Check_Reg OF
AF : Generate (#$F1);
BC : Generate (#$C1);
DE : Generate (#$D1);
HL : Generate (#$E1);
IX : Generate (#$DD + #$E1);
IY : Generate (#$FD + #$E1);
END;
PUSH :
CASE Check_Reg OF
AF : Generate (#$F5);
BC : Generate (#$C5);
DE : Generate (#$D5);
HL : Generate (#$E5);
IX : Generate (#$DD + #$E5);
IY : Generate (#$FD + #$E5);
END;
RET :
IF Ident = 'C' THEN { Carry }
Generate (#$D8)
ELSE IF Ident = 'M' THEN { Minus }
Generate (#$F8)
ELSE IF Ident = 'NC' THEN { No Carry }
Generate (#$D0)
ELSE IF Ident = 'NZ' THEN { Not Zero }
Generate (#$C0)
ELSE IF Ident = 'P' THEN { Plus }
Generate (#$F0)
ELSE IF Ident = 'PE' THEN { Plus & Equal }
Generate (#$E8)
ELSE IF Ident = 'PO' THEN
Generate (#$E0)
ELSE IF Ident = 'Z' THEN { Zero }
Generate (#$C8)
ELSE
Error (' Conditional expected for RET');
RL :
IF Check_Reg IN [A .. L] THEN
DoReg1 (#$CB, $17);
RLC :
IF Check_Reg IN [A .. L] THEN
DoReg1 (#$CB, $07);
RR :
IF Check_Reg IN [A .. L] THEN
DoReg1 (#$CB, $1F);
RRC :
IF Check_Reg IN [A .. L] THEN
DoReg1 (#$CB, $0F);
RST :
CASE Val_Radix (Num, P_Radix) OF
$00 : Generate (#$C7);
$08 : Generate (#$CF);
$10 : Generate (#$D7);
$18 : Generate (#$DF);
$20 : Generate (#$E7);
$28 : Generate (#$EF);
$30 : Generate (#$F7);
$38 : Generate (#$FF);
END;
SLA :
IF Check_Reg IN [A .. L] THEN
DoReg1 (#$CB, $27);
SRA :
IF Check_Reg IN [A .. L] THEN
DoReg1 (#$CB, $2F);
SRL :
IF Check_Reg IN [A .. L] THEN
DoReg1 (#$CB, $3F);
SUB :
IF Check_Reg IN [A .. L] THEN
DoReg1 (Skip, $97)
ELSE IF Sym = Number THEN
Generate (#$D6 + Chr (Val_Radix (Num, P_Radix) ) )
ELSE
ViaLabel (#$D6, False, Ident, False, '+', 0);
XOR_ :
IF Check_Reg IN [A .. L] THEN
DoReg1 (Skip, $AF)
ELSE IF Sym = Number THEN
Generate (#$EE + Chr (Val_Radix (Num, P_Radix) ) )
ELSE
ViaLabel (#$EE, False, Ident, False, '+', 0);
END
END; { DoOR }
PROCEDURE DoOM_Sub ( LeadIn : Char;
OpByte : Byte );
BEGIN { DoOM_Sub }
CASE Check_Reg OF
HL :
IF LeadIn = Skip THEN
Generate (Chr (OpByte) )
ELSE
Generate (LeadIn + Chr (OpByte) );
IX :
BEGIN
Get_Symbol; { Operation }
Get_Symbol; { Offset }
IF Sym = Number THEN
IF LeadIn = Skip THEN
Generate (#$DD + Chr (OpByte) + Chr (Val_Radix (Num, P_Radix) ) )
ELSE
Generate (#$DD + LeadIn + Chr (Val_Radix (Num, P_Radix) ) + Chr (OpByte) )
ELSE
IF LeadIn = Skip THEN
ViaLabel (#$DD + Chr (OpByte), False, Ident, True, '+', 0)
ELSE
BEGIN
ViaLabel (#$DD + LeadIn, False, Ident, True, '+', 0);
Generate (Chr (OpByte) )
END
END;
IY :
BEGIN
Get_Symbol; { Operation }
Get_Symbol; { Offset }
IF Sym = Number THEN
IF LeadIn = Skip THEN
Generate (#$FD + Chr (OpByte) + Chr (Val_Radix (Num, P_Radix) ) )
ELSE
Generate (#$FD + LeadIn + Chr (Val_Radix (Num, P_Radix) ) + Chr (OpByte) )
ELSE
IF LeadIn = Skip THEN
ViaLabel (#$DD + Chr (OpByte), False, Ident, True, '+', 0)
ELSE
BEGIN
ViaLabel (#$DD + LeadIn, False, Ident, True, '+', 0);
Generate (Chr (OpByte) )
END
END
END;
Get_Symbol { Right_BP }
END; { DoOM_Sub }
PROCEDURE DoOM;
BEGIN { DoOM }
CASE OpIs OF
AND_ : DoOM_Sub (Skip, $A6);
CALL : Error ('Conditional expected');
CP : DoOM_Sub (Skip, $BE);
DEC : DoOM_Sub (Skip, $35);
IM : Error ('Should be numeric');
INC : DoOM_Sub (Skip, $34);
JP : DoOM_Sub (Skip, $E9);
JR : Error ('Conditional expected');
OR_ : DoOM_Sub (Skip, $B6);
POP : Error ('Word register expected');
PUSH : Error ('Word register expected');
RET : Error ('Conditional expected');
RL : DoOM_Sub (#$CB, $16);
RLC : DoOM_Sub (#$CB, $06);
RR : DoOM_Sub (#$CB, $1E);
RRC : DoOM_Sub (#$CB, $0E);
RST : Error ('Should be numeric');
SLA : DoOM_Sub (#$CB, $26);
SRA : DoOM_Sub (#$CB, $2E);
SRL : DoOM_Sub (#$CB, $3E);
SUB : DoOM_Sub (Skip, $96);
XOR_ : DoOM_Sub (Skip, $AE)
END
END; { DoOM }
PROCEDURE DoArith;
PROCEDURE DoRegPair ( LeadIn : Char;
OpByte : Byte );
BEGIN { DoRegPair }
IF LeadIn <> Skip THEN
Generate (LeadIn);
Get_Symbol; { Comma }
Get_Symbol; { Register }
CASE Check_Reg OF
BC : Generate (Chr (OpByte + $00) );
DE : Generate (Chr (OpByte + $10) );
HL : Generate (Chr (OpByte + $20) );
SP : Generate (Chr (OpByte + $30) );
END
END; { DoRegPair }
BEGIN { DoArith }
CASE OpIs OF
ADC :
CASE Check_Reg OF
A :
BEGIN
Get_Symbol; { Comma }
Get_Symbol; { Reg | data | Memory }
IF Check_Reg IN [A .. L] THEN
DoReg1 (Skip, $8F)
ELSE IF Sym = Number THEN
Generate (#$CE + Chr (Val_Radix (Num, P_Radix) ) )
ELSE IF Sym = Left_BP THEN
BEGIN
Get_Symbol; { HL | IX | IY }
DoOM_Sub (Skip, $8E)
END
ELSE
ViaLabel (#$CE, False, Ident, False, '+', 0)
END;
HL : DoRegPair (#$ED, $4A)
ELSE
Error ('Illegal register')
END;
ADD :
CASE Check_Reg OF
A :
BEGIN
Get_Symbol; { Comma }
Get_Symbol; { Reg | data | Memory }
IF Check_Reg IN [A .. L] THEN
DoReg1 (Skip, $87)
ELSE IF Sym = Number THEN
Generate (#$C6 + Chr (Val_Radix (Num, P_Radix) ) )
ELSE IF Sym = Left_BP THEN
BEGIN
Get_Symbol; { HL | IX | IY }
DoOM_Sub (Skip, $86)
END
ELSE
ViaLabel (#$C6, False, Ident, False, '+', 0)
END;
HL : DoRegPair (Skip, $09);
IX : DoRegPair (#$DD, $09);
IY : DoRegPair (#$FD, $09)
ELSE
Error ('Illegal register')
END;
SBC :
CASE Check_Reg OF
A :
BEGIN
Get_Symbol; { Comma }
Get_Symbol; { Reg | data | Memory }
IF Check_Reg IN [A .. L] THEN
DoReg1 (Skip, $9F)
ELSE IF Sym = Number THEN
Generate (#$DE + Chr (Val_Radix (Num, P_Radix) ) )
ELSE IF Sym = Left_BP THEN
BEGIN
Get_Symbol; { HL | IX | IY }
DoOM_Sub (Skip, $9E)
END
ELSE
ViaLabel (#$DE, False, Ident, False, '+', 0)
END;
HL : DoRegPair (#$ED, $42)
ELSE
Error ('Illegal register')
END
END
END; { DoArith }
PROCEDURE DoConditions;
VAR
DoJRIt : Boolean;
PROCEDURE HandleAddress ( OpByte : Byte;
Adrs : Char );
VAR
DoIt : Boolean;
I : Integer;
BEGIN { HandleAddress }
DoIt := True;
IF Ident = 'C' THEN
Generate (Chr (OpByte + $00) )
ELSE IF Ident = 'M' THEN
Generate (Chr (OpByte + $20) )
ELSE IF Ident = 'NC' THEN
Generate (Chr (OpByte - $08) )
ELSE IF Ident = 'NZ' THEN
Generate (Chr (OpByte - $18) )
ELSE IF Ident = 'P' THEN
Generate (Chr (OpByte + $18) )
ELSE IF Ident = 'PE' THEN
Generate (Chr (OpByte + $10) )
ELSE IF Ident = 'PO' THEN
Generate (Chr (OpByte + $08) )
ELSE IF Ident = 'Z' THEN
Generate (Chr (OpByte - $10) )
ELSE
BEGIN
Write (' Address ');
DoIt := False;
LabelId := Ident;
Get_Symbol; { Operation | ? }
IF Sym <> Operation THEN
ViaLabel (Adrs, True, LabelId, False, '+', 0)
ELSE
BEGIN
TempOpCh := Ch;
Get_Symbol; { Number }
ViaLabel (Adrs, True, LabelId, False, Ch, Val_Radix (Num, P_Radix) )
END
END;
IF DoIt THEN
BEGIN
Get_Symbol; { Comma }
Get_Symbol; { Address }
I := Val_Radix (Num, P_Radix);
Generate (Chr (Lo (I) ) + Chr (Hi (I) ) )
END
END; { HandleAddress }
BEGIN { DoConditions }
CASE OpIs OF
CALL : HandleAddress ($DC, #$CD);
JP :
IF Sym = Left_BP THEN
BEGIN
Get_Symbol;
CASE Check_Reg OF
HL : Generate (#$E9);
IX : Generate (#$DD + #$E9);
IY : Generate (#$FD + #$E9);
END;
Get_Symbol { Right_BP }
END
ELSE
HandleAddress ($DA, #$C3);
JR :
BEGIN
DoJRIt := True;
IF Ident = 'C' THEN
Generate (#$38)
ELSE IF Ident = 'NC' THEN
Generate (#$30)
ELSE IF Ident = 'NZ' THEN
Generate (#$20)
ELSE IF Ident = 'Z' THEN
Generate (#$28)
ELSE
BEGIN
DoJRIt := False;
OperLabel (#18, False, Ident, True)
END;
IF DoJRIt THEN
BEGIN
Get_Symbol; { Comma }
Get_Symbol; { Number }
IF Sym = Number THEN
Generate (Chr (Val_Radix (Num, P_Radix) ) )
ELSE
ViaLabel ('', False, Ident, True, '+', 0)
END
END
END
END; { DoConditions }
PROCEDURE DoIN;
VAR
FinishUp : Boolean;
BEGIN { DoIN }
FinishUp := True;
CASE Check_Reg OF
A :
BEGIN
FinishUp := False;
Get_Symbol; { Comma }
Get_Symbol; { Number | Label | Left_BP }
IF Sym = Number THEN
Generate (#$DB + Chr (Val_Radix (Num, P_Radix) ) )
ELSE IF Sym = Left_BP THEN
BEGIN
Generate (#$ED + #$78);
Get_Symbol; { C }
Get_Symbol { Right_BP }
END
ELSE { Must be a label ! }
BEGIN
Write (' IN ');
ViaLabel (#$DB, False, Ident, False, '+', 0)
END
END;
B : Generate (#$ED + #$40);
C : Generate (#$ED + #$48);
D : Generate (#$ED + #$50);
E : Generate (#$ED + #$58);
H : Generate (#$ED + #$60);
L : Generate (#$ED + #$68);
END;
IF FinishUp THEN
BEGIN
Get_Symbol; { Comma }
Get_Symbol; { Left_BP }
Get_Symbol; { C }
Get_Symbol { Right_BP }
END
END; { DoIN }
PROCEDURE DoOUT;
BEGIN { DoOUT }
IF Sym = Number THEN
BEGIN
Generate (#$D3 + Chr (Val_Radix (Num, P_Radix) ) );
Get_Symbol; { Comma }
Get_Symbol { A }
END
ELSE IF Sym = Left_BP THEN
BEGIN
Get_Symbol; { C }
Get_Symbol; { Right_BP }
Get_Symbol; { Comma }
Get_Symbol; { Register }
CASE Check_Reg OF
A : Generate (#$ED + #$79);
B : Generate (#$ED + #$41);
C : Generate (#$ED + #$49);
D : Generate (#$ED + #$51);
E : Generate (#$ED + #$59);
H : Generate (#$ED + #$61);
L : Generate (#$ED + #$69);
END
END
ELSE
BEGIN
Write (' OUT ');
ViaLabel (#$D3, False, Ident, False, '+', 0);
Get_Symbol; { Comma }
Get_Symbol { A }
END
END; { DoOUT }
PROCEDURE HandleLD;
VAR
SetPatch : Boolean;
I : Integer;
OffValue : Integer;
PROCEDURE DoRegs ( Reg1, Reg2 : Byte );
BEGIN { DoRegs }
Get_Symbol; { Comma }
Get_Symbol; { Reg | data | Memory }
IF Check_Reg IN [A .. L] THEN
DoReg1 (Skip, Reg1)
ELSE IF Sym = Number THEN
Generate (Chr (Reg2) + Chr (Val_Radix (Num, P_Radix) ) )
ELSE IF Sym = Left_BP THEN
BEGIN
Get_Symbol; { HL | IX | IY }
DoOM_Sub (Skip, Reg1 - 1)
END
ELSE
ViaLabel (Chr (Reg2), False, Ident, False, '+', 0)
END; { DoRegs }
PROCEDURE DoPairs ( RegIs : Registers;
Adrs, Dta : Char );
VAR
CleanUp : Boolean;
Send : _String;
BEGIN { DoPairs }
CleanUp := False;
Send := Dta;
Get_Symbol; { Comma }
Get_Symbol; { Number | Left_BP | Label }
IF Sym = Left_BP THEN
BEGIN
CleanUp := True;
Get_Symbol; { Number | Label }
CASE RegIs OF
HL : Send := Adrs;
IX : Send := #$DD + Adrs;
IY : Send := #$FD + Adrs;
ELSE
Send := #$ED + Adrs
END
END;
IF Sym = Number THEN
BEGIN
I := Val_Radix (Num, P_Radix);
Generate (Send + Chr (Lo (I) ) + Chr (Hi (I) ) )
END
ELSE
OperLabel (Send, True, Ident, False);
IF CleanUp AND (Sym <> EndLine) THEN
Get_Symbol { Right_BP }
END; { DoPairs }
PROCEDURE DoHXY ( LeadIn : Char );
PROCEDURE HandleSkip ( Ch : Char );
BEGIN { HandleSkip }
IF LeadIn = Skip THEN
Generate (Ch)
ELSE
Generate (Ch + Chr (I) )
END; { HandleSkip }
BEGIN { DoHXY }
IF LeadIn = Skip THEN
BEGIN
Get_Symbol; { Right_BP }
Get_Symbol; { Comma }
Get_Symbol { Register | Number | Label }
END
ELSE
BEGIN
Generate (LeadIn);
Get_Symbol; { + }
Get_Symbol; { Label | Number }
IF Sym = Number THEN
I := Val_Radix (Num, P_Radix)
ELSE
I := 0;
Get_Symbol; { Right_BP }
Get_Symbol; { Comma }
Get_Symbol { Register | Number | Label }
END;
CASE Check_Reg OF
A : HandleSkip (#$77);
B : HandleSkip (#$70);
C : HandleSkip (#$71);
D : HandleSkip (#$72);
E : HandleSkip (#$73);
H : HandleSkip (#$74);
L : HandleSkip (#$75)
ELSE
IF Sym = Number THEN
IF LeadIn = Skip THEN
Generate (#$36 + Chr (Val_Radix (Num, P_Radix) ) )
ELSE
Generate (#$36 + Chr (I) + Chr (Val_Radix (Num, P_Radix) ) )
ELSE
IF LeadIn = Skip THEN
OperLabel (#$36, False, Ident, True)
ELSE
OperLabel (#$36 + Chr (I), False, Ident, True)
END
END; { DoHXY }
BEGIN { HandleLD }
IF Sym = Left_BP THEN
BEGIN
Get_Symbol; { Register | Label | Number }
CASE Check_Reg OF
BC :
BEGIN
Get_Symbol; { Right_BP }
Get_Symbol; { Comma }
Get_Symbol; { A }
Generate (#$02)
END;
DE :
BEGIN
Get_Symbol; { Right_BP }
Get_Symbol; { Comma }
Get_Symbol; { A }
Generate (#$12)
END;
HL : DoHXY (Skip);
IX : DoHXY (#$DD);
IY : DoHXY (#$FD)
ELSE
BEGIN
SetPatch := False;
IF Sym = Number THEN
I := Val_Radix (Num, P_Radix)
ELSE
BEGIN
SetPatch := True;
LabelId := Ident;
I := 0
END;
Get_Symbol; { Right_BP | Operation }
IF Sym = Operation THEN
BEGIN
TempOpCh := Ch;
Get_Symbol; { Number }
OffValue := Val_Radix (Num, P_Radix);
Get_Symbol { Right_BP }
END;
Get_Symbol; { Comma }
Get_Symbol; { Reg }
CASE Check_Reg OF
A : Generate (#$32);
BC : Generate (#$ED + #$43);
DE : Generate (#$ED + #$53);
HL : Generate (#$22);
IX : Generate (#$DD + #$22);
IY : Generate (#$FD + #$22);
SP : Generate (#$ED + #$73);
END;
IF SetPatch THEN
IF OffValue > 0 THEN
ViaLabel ('', True, LabelId, False, TempOpCh, OffValue)
ELSE
ViaLabel ('', True, LabelId, False, '+', 0)
ELSE
Generate (Chr (Lo (I) ) + Chr (Hi (I) ) )
END
END
END
ELSE
CASE Check_Reg OF
A :
BEGIN
Get_Symbol; { Comma }
Get_Symbol; { Reg | data | Left_BP | Label }
IF Check_Reg IN [A .. L] THEN
DoReg1 (Skip, $7F)
ELSE IF Check_Reg = R THEN
Generate (#$ED + #$5F)
ELSE IF Sym = Number THEN
Generate (#$3E + Chr (Val_Radix (Num, P_Radix) ) )
ELSE IF Sym = Left_BP THEN
BEGIN
Get_Symbol; { HL | IX | IY | BC | DE }
IF Check_Reg IN [HL, IX, IY] THEN
DoOM_Sub (Skip, $7E)
ELSE IF Sym = Number THEN
BEGIN
I := Val_Radix (Num, P_Radix);
Generate (#$3A + Chr (Lo (I) ) + Chr (Hi (I) ) )
END
ELSE IF Check_Reg IN [BC, DE] THEN
CASE Check_Reg OF
BC : Generate (#$0A);
DE : Generate (#$1A)
END
ELSE
OperLabel (#$3A, True, Ident, False);
Get_Symbol { Right_BP }
END
ELSE
ViaLabel (#$3E, True, Ident, False, '+', 0)
END;
B : DoRegs ($47, $06);
BC : DoPairs (BC, #$4B, #$01);
C : DoRegs ($4F, $0E);
D : DoRegs ($57, $16);
DE : DoPairs (DE, #$5B, #$11);
E : DoRegs ($5F, $1E);
H : DoRegs ($67, $26);
HL : DoPairs (HL, #$2A, #$21);
IV :
BEGIN
Get_Symbol; { Comma }
Get_Symbol; { A }
Generate (#$ED + #$47)
END;
IX : DoPairs (IX, #$2A, #$21);
IY : DoPairs (IY, #$2A, #$21);
L : DoRegs ($47, $06);
R :
BEGIN
Get_Symbol; { Comma }
Get_Symbol; { A }
Generate (#$ED + #$4F)
END;
SP :
BEGIN
Get_Symbol; { Comma }
Get_Symbol; { Reg | Number | Left_BP }
IF Sym = Left_BP THEN
BEGIN
Get_Symbol;
IF Sym = Number THEN
BEGIN
I := Val_Radix (Num, P_Radix);
Generate (#$ED + #$7B + Chr (Lo (I) ) + Chr (Hi (I) ) )
END
ELSE
OperLabel (#$ED + #$7B, True, Ident, False);
Get_Symbol { Right_BP }
END
ELSE IF Sym = Number THEN
BEGIN
I := Val_Radix (Num, P_Radix);
Generate (#$31 + Chr (Lo (I) ) + Chr (Hi (I) ) )
END
ELSE IF Check_Reg IN [HL, IX, IY] THEN
DoOM_Sub (Skip, $F9)
ELSE
ViaLabel (#$31, True, Ident, False, '+', 0)
END
END
END; { HandleLD }
BEGIN { ParseMnemonic }
Get_Symbol;
IF OpIs = LD THEN
HandleLD
4) );
ShowLabels (Right)
END
END; { ShowPatches }
PROCEDURE FixPatches ( APatch : PatchPtr );
VAR
Value : Integer; { Address or Data of Label }
OValue : Integer;
BEGIN { FixPatches }
IF APatch <> Nil THEN
WITH APatch^ DO
BEGIN
FixPatches (LeftPatch);
IF NOT FoundLabel (Labels, PName, OValue) THEN
Error ('Unable to locate label ' + PName)
ELSE
BEGIN
WriteLn;
Write ('':2, PName);
REPEAT
WITH FixLoc^ DO
BEGIN
Value := OValue;
IF OSet THEN
Value := Value - PLoc - 1;
CASE Oprtion OF
'+' : Value := Value + PAdj;
'-' : Value := Value - PAdj;
'*' : Value := Value * PAdj;
'/' : Value := Value DIV PAdj
END;
SetValue (PLoc, Value, TwoBytes)
END;
FixLoc := FixLoc^.PNext
UNTIL FixLoc = Nil
END;
FixPatches (RightPatch)
END
END; { FixPatches }
BEGIN { z80_assembler }
initialize;
parser;
WriteLn;
WriteLn;
WriteLn ('Labels');
ShowLabels (Labels);
WriteLn;
WriteLn;
WriteLn ('Second pass');
FixPatches (Patches);
WriteLn;
WriteLn ('End assembly');
Close (GenFile)
END { z80_assembler }. WriteLn;
WriteLn ('Labels');
ShowLabels (Labels);
WriteLn;
WriteLn;
WriteLn ('Second pass');
FiRRD : Generate (#$ED + #$67);
SCF : Generate (#$37)
ELSE
Error ('Extra info on line')
END
ELSE IF (OpIs IN [BIT, RES, SET_] ) AND
(Sym = Number) THEN { Op Number Comma Register }
number : Write ('Number : ', num:4, ' Radix : ', p_radix:2, ' Value : ', val_radix (num, p_radix):5);
str_data : Generate (chars);
operation : Write ('Operation : ', ch);
left_bp : Write ('Memory go : ', ch);
right_bp : Write ('Memory end : ', ch);
comma : Write (' Comma');
period : Write ('Directive');
colon : Write (' Label');
location : Write ('Location counter ', PosCnt);
equal : Write ('Equal')
END;
get_symbol
END
END; { parser }
FUNCTION FoundLabel ( ALabel : LabelPtr;
AName : LabelStr;
VAR Value : Integer ) : Boolean;
BEGIN { FoundLabel }
IF ALabel = Nil THEN
FoundLabel := False
ELSE IF AName < ALabel^.Name THEN
FoundLabel := FoundLabel (ALabel^.Left, AName, Value)
ELSE IF AName > ALabel^.Name THEN
FoundLabel := FoundLabel (ALabel^.Right, AName, Value)
ELSE
BEGIN
Value := ALabel^.Loc;
FoundLabel := True
END
END; { FoundLabel }
PROCEDURE SetValue ( RecNum : Integer;
Value : Integer;
Both : Boolean );
VAR
LoByte : Byte;
HiByte : Byte;
BEGIN { SetValue }
LoByte := Lo (Value);
HiByte := Hi (Value);
IF Both THEN
Write ('':3, Str_Radix (Value, 4, 16, 4) )
ELSE
Write ('':3, Str_Radix (LoByte, 2, 16, 4) );
Seek (GenFile, RecNum);
IF Both THEN
Write (GenFile, LoByte, HiByte)
ELSE
Write (GenFile, LoByte)
END; { SetValue }
PROCEDURE ShowLabels ( ALabel : LabelPtr );
BEGIN { ShowLabels }
IF ALabel <> Nil THEN
WITH ALabel^ DO
BEGIN
ShowLabels (Left);
WriteLn ('':2, Name:16, '':2, Str_Radix (Loc, 4, 16, BEGIN
WriteLn;
Write (ident:31);
IF check_op <> null_op THEN
ParseMnemonic (Check_Op)
ELSE IF check_reg <> null_reg THEN
Write (' Register')
ELSE IF Others <> NullOther THEN
ParseOthers
ELSE
BEGIN
CurChPos := Ch_Pos;
LabelId := Ident;
Get_Symbol;
IF Sym = Colon THEN
BEGIN
Write (' Label declared at ', Str_Radix (PosCnt, 4, 16, 4), ' ');
AddLabel (Labels, PosCnt)
END
ELSE IF (Others = Equate) OR (Sym = Equal) THEN
BEGIN
Write (' Label via ');
IF Sym = Equal THEN
Write ('= ')
ELSE
Write ('EQU ');
Get_Symbol;
IF Sym = Number THEN
BEGIN
Write (Str_Radix (Val_Radix (Num, P_Radix), 4, 16, 4), ' ');
AddLabel (Labels, Val_Radix (Num, P_Radix) )
END
ELSE IF Sym = Location THEN
BEGIN
Write (' $ ');
AddLabel (Labels, PosCnt)
END
ELSE
Error (' Number or $ expected')
END
ELSE
BEGIN
Write (' Location Label at ', Str_Radix (PosCnt, 4, 16, 4), ' ');
AddLabel (Labels, PosCnt);
Ch_Pos := CurChPos;
Sym := Null_Sym
END
END
END;program ziptest;
(* *)
(* Released to the public domain for any use whatsoever *)
(* By : William L. Mabee, CRNA *)
(* *)
type
str2 = string[2];
str12 = string[12];
procedure validate_state(state : str2; var good : boolean;
var ziprange : str12; var statenum : byte);
VAR
STATESET : SET OF BYTE;
BEGIN
IF STATE = 'AL' THEN STATENUM := 1;
IF STATE = 'AK' THEN STATENUM := 2; (* Alaska *)
IF STATE = 'AZ' THEN STATENUM := 3;
IF STATE = 'AR' THEN STATENUM := 4;
IF STATE = 'CA' THEN STATENUM := 5;
IF STATE = 'CO' THEN STATENUM := 6;
IF STATE = 'CT' THEN STATENUM := 7;
IF STATE = 'DE' THEN STATENUM := 8;
IF STATE = 'DC' THEN STATENUM := 9;
IF STATE = 'FL' THEN STATENUM := 10;
IF STATE = 'GA' THEN STATENUM := 11;
IF STATE = 'HI' THEN STATENUM := 12;
IF STATE = 'ID' THEN STATENUM := 13;
IF STATE = 'IL' THEN STATENUM := 14;
IF STATE = 'IN' THEN STATENUM := 15;
IF STATE = 'IA' THEN STATENUM := 16;
IF STATE = 'KS' THEN STATENUM := 17;
IF STATE = 'KY' THEN STATENUM := 18;
IF STATE = 'LA' THEN STATENUM := 19;
IF STATE = 'ME' THEN STATENUM := 20; (* Maine *)
IF STATE = 'MD' THEN STATENUM := 21;
IF STATE = 'MA' THEN STATENUM := 22;
IF STATE = 'MI' THEN STATENUM := 23; (* Mich *)
IF STATE = 'MN' THEN STATENUM := 24;
IF STATE = 'MS' THEN STATENUM := 25;
IF STATE = 'MO' THEN STATENUM := 26;
IF STATE = 'MT' THEN STATENUM := 27;
IF STATE = 'NE' THEN STATENUM := 28;
IF STATE = 'NV' THEN STATENUM := 29;
IF STATE = 'NH' THEN STATENUM := 30;
IF STATE = 'NJ' THEN STATENUM := 31;
IF STATE = 'NM' THEN STATENUM := 32;
IF STATE = 'NY' THEN STATENUM := 33;
IF STATE = 'NC' THEN STATENUM := 34;
IF STATE = 'ND' THEN STATENUM := 35;
IF STATE = 'OH' THEN STATENUM := 36;
IF STATE = 'OK' THEN STATENUM := 37;
IF STATE = 'OR' THEN STATENUM BEGIN
WriteLn;
Write (ident:31);
IF check_op <> null_op THEN
ParseMnemonic (Check_Op)
ELSE IF check_reg <> null_reg THEN
Write (' Register')
ELSE IF Others <> NullOther THEN
ParseOthers
ELSE
BEGIN
CurChPos := Ch_Pos;
LabelId := Ident;
Get_Symbol;
IF Sym = Colon THEN
BEGIN
Write (' Label declared at ', Str_Radix (PosCnt, 4, 16, 4), ' ');
AddLabel (Labels, PosCnt)
END
ELSE IF (Others = Equate) OR (Sym = Equal) THEN
BEGIN
Write (' Label via ');
IF Sym = Equal THEN
Write ('= ')
ELSE
Write ('EQU ');
Get_Symbol;
IF Sym = Number THEN
BEGIN
Write (Str_Radix (Val_Radix (Num, P_Radix), 4, 16, 4), ' ');
AddLabel (Labels, Val_Radix (Num, P_Radix) )
END
ELSE IF Sym = Location THEN
BEGIN
Write (' $ ');
AddLabel (Labels, PosCnt)
END
ELSE
Error (' Number or $ expected')
END
ELSE
BEGIN
Write (' Location Label at ', Str_Radix (PosCnt, 4, 16, 4), ' ');
AddLabel (Labels, PosCnt);
Ch_Pos := CurChPos;
Sym := Null_Sym
END
END
END;
number : Write ('Number : ', num:4, ' Radix : ', p_radix:2, ' Value : ', val_radix (num, p_radix):5);
str_data : Generate (chars);
operation : Write ('Operation : ', ch);
left_bp : Write ('Memory go : ', ch);
right_bp : Write ('Memory end : ', ch);
comma : Write (' Comma');
period : Write ('Directive');
colon : Write (' Label');
location : Write ('Location counter ', PosCnt);
equal : Write ('Equal')
END;
get_symbol
END
END; { parser }
FUNCTION FoundLabel ( ALabel : LabelPtr;
AName : LabelStr;
VAR Value : Integer ) : Boolean;
BEGIN { FoundLabel }
IF ALabel = Nil THEN
FoundLabel := False
ELSE IF AName < ALabel^.Name THEN
FoundLabel := FoundLabel (ALabel^.Left, AName, Value)
ELSE IF AName > ALabel^.Name THEN
FoundLabel := FoundLabel (ALabel^.Right, AName, Value)
ELSE
BEGIN
Value := ALabel^.Loc;
FoundLabel := True
END
END; { FoundLabel }
PROCEDURE SetValue ( RecNum : Integer;
Value : Integer;
Both : Boolean );
VAR
LoByte : Byte;
HiByte : Byte;
BEGIN { SetValue }
LoByte := Lo (Value);
HiByte := Hi (Value);
IF Both THEN
Write ('':3, Str_Radix (Value, 4, 16, 4) )
ELSE
Write ('':3, Str_Radix (LoByte, 2, 16, 4) );
Seek (GenFile, RecNum);
IF Both THEN
Write (GenFile, LoByte, HiByte)
ELSE
Write (GenFile, LoByte)
END; { SetValue }
PROCEDURE ShowLabels ( ALabel : LabelPtr );
BEGIN { ShowLabels }
IF ALabel <> Nil THEN
WITH ALabel^ DO
BEGIN
ShowLabels (Left);
WriteLn ('':2, Name:16, '':2, Str_Radix (Loc, 4, 16, 4) );
ShowLabels (Right)
END
END; { ShowPatches }
PROCEDURE FixPatches ( APatch : PatchPtr );
VAR
Value : Integer; { Address or Data of Label }
OValue : Integer;
BEGIN { FixPatches }
IF APatch <> Nil THEN
WITH APatch^ DO
BEGIN
FixPatches (LeftPatch);
IF NOT FoundLabel (Labels, PName, OValue) THEN
Error ('Unable to locate label ' + PName)
ELSE
BEGIN
WriteLn;
Write ('':2, PName);
REPEAT
WITH FixLoc^ DO
BEGIN
Value := OValue;
IF OSet THEN
Value := Value - PLoc - 1;
CASE Oprtion OF
'+' : Value := Value + PAdj;
'-' : Value := Value - PAdj;
'*' : Value := Value * PAdj;
'/' : Value := Value DIV PAdj
END;
SetValue (PLoc, Value, TwoBytes)
END;
FixLoc := FixLoc^.PNext
UNTIL FixLoc = Nil
END;
FixPatches (RightPatch)
END
END; { FixPatches }
BEGIN { z80_assembler }
initialize;
parser;
WriteLn;
WriteLn;
WriteLn ('Labels');
ShowLabels (Labels);
WriteLn;
WriteLn;
WriteLn ('Second pass');
FixPatches (Patches);
WriteLn;
WriteLn ('End assembly');
Close (GenFile)
END { z80_assembler }.