Add the addr pseudo-instruction to the assembler and spin the calculator off into a project of its own

This commit is contained in:
CrazyEttin 2022-08-08 20:06:43 +03:00
parent 38080674f5
commit 087c88d8ce
3 changed files with 39 additions and 439 deletions

View File

@ -21,6 +21,16 @@ var
Bin: array [0 .. $ffef] of byte; //Assembled binary
Prog: file of byte; //Program file
//Check if a string is numeric
function IsNumeric (S: string): boolean;
var
I: integer;
begin
for I := 1 to length (S) do
if not (S [I] in ['a' .. 'f', 'A' .. 'F', '0' .. '9']) then exit (false);
exit (true);
end;
//Check if a string is alphanumeric
function IsAlphaNum (S: string): boolean;
var
@ -83,7 +93,7 @@ begin
end;
//Assemble an address argument
procedure AddrArg (I: integer);
procedure AddrArg (I, A: integer);
begin
Offset := 0;
try
@ -107,6 +117,8 @@ begin
if Trim (ExtractDelimited (2, Elem [I], ['-'])) <> '' then Offset := -Offset;
Elem [I] := Trim (ExtractDelimited (1, Elem [I], ['+', '-']));
end;
//Check if the reference is numeric
if IsNumeric (Elem [I]) = true then ArgError;
//Check if the reference is alphanumeric
if IsAlphaNum (Elem [I]) = false then ArgError;
//Backwards
@ -122,7 +134,7 @@ begin
Count := 0;
while Ref [Count] .Lbl <> '' do Count := Count + 1;
//Store the reference in the table
Ref [Count] .Addr := BP + 1;
Ref [Count] .Addr := BP + A;
Ref [Count] .Lbl := Elem [I];
Ref [Count] .Offset := Offset;
//Placeholder
@ -130,15 +142,15 @@ begin
Offset := 0;
end;
end;
if (BP + 2) >= $fff0 then MemError;
if (BP + 1 + A) >= $fff0 then MemError;
//Add the offset
if Addr + Offset >= 0 then begin
if Addr + Offset <= $ffff then Addr := Addr + Offset
else ArgError;
end
else ArgError;
Bin [BP + 1] := Addr shr 8;
Bin [BP + 2] := Addr and $00ff;
Bin [BP + A] := Addr shr 8;
Bin [BP + 1 + A] := Addr and $00ff;
end;
begin
@ -260,6 +272,19 @@ begin
BP := BP + 1;
end
//Check for the addr pseudo-instruction
else if CompareText (ExtractWord (1, Line, [' ']), 'ADDR') = 0 then begin
//Extract the reference
Elem [1] := Copy2SpaceDel (Line);
Elem [2] := Trim (Line);
//Check if the reference is numeric
if IsNumeric (Elem [2]) = true then ArgError;
//Extract and store the address
AddrArg (2, 0);
//Increment the byte pointer
BP := BP + 2;
end
//Check for an instruction
else if Line <> '' then begin
@ -318,12 +343,12 @@ begin
//First argument
OneArgReg (2);
//Second argument
AddrArg (3);
AddrArg (3, 1);
end;
//Store
if Bin [BP] = $b0 then begin
//First argument
AddrArg (2);
AddrArg (2, 1);
//Second argument
OneArgReg (3);
end;
@ -332,7 +357,7 @@ begin
//First and second arguments
TwoArgRegs;
//Third argument
AddrArg (4);
AddrArg (4, 1);
end;
//Increment the byte pointer

View File

@ -1,427 +0,0 @@
;Hexadecimal adder and subtractor for two-digit unsigned values
;Print a prompt
start: load r0, prompt
store ffff, r0
load r0, space
store ffff, r0
;Read and convert the first argument and store it to arg1
cleq r0, r0, rarg
store arg1, r0
;Print a newline
cleq r0, r0, newln
;Read the operation sign
load r0, ffff
load r1, plus
breq r0, r1, storsg
load r1, minus
breq r0, r1, storsg
;Error and halt if the character is not a sign
breq r0, r0, error
storsg: store sign, r0
;Print a space
load r0, space
store ffff, r0
;Read and convert the second argument and load it to r2
cleq r0, r0, rarg
xor r2, r2
xor r2, r0
;Reload the first argument to r0
load r0, arg1
;Print a newline
cleq r0, r0, newln
;Print an equals sign
load r3, equals
store ffff, r3
;Check the operation
load r3, sign
load r1, minus
breq r1, r3, brsub
;Add and load the result to r3
;Addition
cleq r0, r0, adder
;Load the result to r3
xor r3, r3
xor r3, r0
;Skip the subtraction code
breq r0, r0, nosign
;Subtract and load the result to r3
;Subtraction
brsub: cleq r0, r0, sub
;Load the result to r3
xor r3, r3
xor r3, r0
;Print a minus sign and unnegate the result if negative
;Check the sign
xor r0, r0
breq r0, r1, nosign
;Print a minus sign
load r0, minus
store ffff, r0
;Un-negate the result
store arg1, r3
load r2, one
cleq r0, r0, sub
nand r0, r0
;Reload the result to r3
xor r3, r3
xor r3, r0
;Skip printing the first digit
breq r0, r0, skip
;Print the overflow for addition or zero for positive results of
;subtraction
nosign: xor r0, r0
xor r0, r1
cleq r0, r0, n2hex
store ffff, r0
;Convert and print the result
;Restore the result back to r0
skip: xor r0, r0
xor r0, r3
;High nibble
shr r0
shr r0
shr r0
shr r0
cleq r0, r0, n2hex
store ffff, r0
;Restore the result to r0
xor r0, r0
xor r0, r3
;Low nibble
cleq r0, r0, n2hex
store ffff, r0
;Print a newline
cleq r0, r0, newln
;Loop
breq r0, r0, start
;Error
error: cleq r0, r0, newln
load r0, qmark
store ffff, r0
cleq r0, r0, newln
halt
;Read and convert an argument and load it to r0
;First digit
rarg: load r0, ffff
cleq r0, r0, hex2n
xor r2, r2
xor r2, r0
shl r2
shl r2
shl r2
shl r2
;Second digit
rarg2: load r0, ffff
load r1, backsp
breq r0, r1, rarg
cleq r0, r0, hex2n
;Confirm
load r3, ffff
load r1, backsp
breq r3, r1, rarg2
load r1, cr
breq r3, r1, rarg3
breq r0, r0, error
;Combine the digits
rarg3: or r0, r2
;Return
ret
;Print a newline
newln: load r3, cr
store ffff, r3
load r3, lf
store ffff, r3
ret
;Get the value of a hexadecimal digit
;Locate the hexadecimal digit in the table
hex2n: load r1, tbl01
breq r0, r1, val0
load r1, tbl03
breq r0, r1, val1
load r1, tbl05
breq r0, r1, val2
load r1, tbl07
breq r0, r1, val3
load r1, tbl09
breq r0, r1, val4
load r1, tbl0b
breq r0, r1, val5
load r1, tbl0d
breq r0, r1, val6
load r1, tbl0f
breq r0, r1, val7
load r1, tbl11
breq r0, r1, val8
load r1, tbl13
breq r0, r1, val9
load r1, tbl15
breq r0, r1, vala
load r1, tbl17
breq r0, r1, valb
load r1, tbl19
breq r0, r1, valc
load r1, tbl1b
breq r0, r1, vald
load r1, tbl1d
breq r0, r1, vale
load r1, tbl1f
breq r0, r1, valf
load r1, tbl21
breq r0, r1, vala
load r1, tbl23
breq r0, r1, valb
load r1, tbl25
breq r0, r1, valc
load r1, tbl27
breq r0, r1, vald
load r1, tbl29
breq r0, r1, vale
load r1, tbl2b
breq r0, r1, valf
;Error and halt if the character is not a digit
breq r0, r0, error
;Load the value of the hexadecimal digit
val0: load r0, tbl00
breq r0, r0, h2nend
val1: load r0, tbl02
breq r0, r0, h2nend
val2: load r0, tbl04
breq r0, r0, h2nend
val3: load r0, tbl06
breq r0, r0, h2nend
val4: load r0, tbl08
breq r0, r0, h2nend
val5: load r0, tbl0a
breq r0, r0, h2nend
val6: load r0, tbl0c
breq r0, r0, h2nend
val7: load r0, tbl0e
breq r0, r0, h2nend
val8: load r0, tbl10
breq r0, r0, h2nend
val9: load r0, tbl12
breq r0, r0, h2nend
vala: load r0, tbl14
breq r0, r0, h2nend
valb: load r0, tbl16
breq r0, r0, h2nend
valc: load r0, tbl18
breq r0, r0, h2nend
vald: load r0, tbl1a
breq r0, r0, h2nend
vale: load r0, tbl1c
breq r0, r0, h2nend
valf: load r0, tbl1e
breq r0, r0, h2nend
;Return
h2nend: ret
;Add r2 to r0 with the overflow stored in r1
;Reset overflow
adder: xor r3, r3
store ovrflw, r3
;Copy the first argument to r1
addlop: xor r1, r1
xor r1, r0
;Calculate the sum and carry and copy the pre-shift carry to r1
xor r0, r2
and r2, r1
xor r1, r1
xor r1, r2
shl r2
;Check for overflow
rol r1
breq r1, r2, nvrflw
;Store overflow
load r1, one
store ovrflw, r1
;Check for no carry
nvrflw: breq r2, r3, addend
;Loop
breq r0, r0, addlop
;Load overflow and return
addend: load r1, ovrflw
ret
;Subtract r2 from arg1 and store the result in r0 with the sign
;bit stored in r1
;Negate the second argument
sub: load r0, one
nand r2, r2
cleq r0, r0, adder
;Load the first argument to r2
load r2, arg1
;Subtract
cleq r0, r0, adder
;Invert the sign bit
xor r3, r3
breq r3, r1, submin
xor r1, r1
breq r0, r0, subend
submin: load r1, one
;Return
subend: ret
;Get the hexadecimal digit of a nibble
;Extract the low nibble
n2hex: load r1, mask
and r0, r1
;Locate the nibble in the table
load r1, tbl00
breq r0, r1, dgt0
load r1, tbl02
breq r0, r1, dgt1
load r1, tbl04
breq r0, r1, dgt2
load r1, tbl06
breq r0, r1, dgt3
load r1, tbl08
breq r0, r1, dgt4
load r1, tbl0a
breq r0, r1, dgt5
load r1, tbl0c
breq r0, r1, dgt6
load r1, tbl0e
breq r0, r1, dgt7
load r1, tbl10
breq r0, r1, dgt8
load r1, tbl12
breq r0, r1, dgt9
load r1, tbl14
breq r0, r1, dgta
load r1, tbl16
breq r0, r1, dgtb
load r1, tbl18
breq r0, r1, dgtc
load r1, tbl1a
breq r0, r1, dgtd
load r1, tbl1c
breq r0, r1, dgte
load r1, tbl1e
breq r0, r1, dgtf
;Load the hexadecimal digit of the nibble
dgt0: load r0, tbl01
breq r0, r0, n2hend
dgt1: load r0, tbl03
breq r0, r0, n2hend
dgt2: load r0, tbl05
breq r0, r0, n2hend
dgt3: load r0, tbl07
breq r0, r0, n2hend
dgt4: load r0, tbl09
breq r0, r0, n2hend
dgt5: load r0, tbl0b
breq r0, r0, n2hend
dgt6: load r0, tbl0d
breq r0, r0, n2hend
dgt7: load r0, tbl0f
breq r0, r0, n2hend
dgt8: load r0, tbl11
breq r0, r0, n2hend
dgt9: load r0, tbl13
breq r0, r0, n2hend
dgta: load r0, tbl15
breq r0, r0, n2hend
dgtb: load r0, tbl17
breq r0, r0, n2hend
dgtc: load r0, tbl19
breq r0, r0, n2hend
dgtd: load r0, tbl1b
breq r0, r0, n2hend
dgte: load r0, tbl1d
breq r0, r0, n2hend
dgtf: load r0, tbl1f
breq r0, r0, n2hend
;Return
n2hend: ret
;Characters
space: data 20
prompt: data 3e
plus: data 2b
minus: data 2d
equals: data 3d
qmark: data 3f
backsp: data 8
cr: data d
lf: data a
;Mask
mask: data f
;One
one: data 1
;Hexadecimal table
;Numeric digits
tbl00: data 0
tbl01: data 30
tbl02: data 1
tbl03: data 31
tbl04: data 2
tbl05: data 32
tbl06: data 3
tbl07: data 33
tbl08: data 4
tbl09: data 34
tbl0a: data 5
tbl0b: data 35
tbl0c: data 6
tbl0d: data 36
tbl0e: data 7
tbl0f: data 37
tbl10: data 8
tbl11: data 38
tbl12: data 9
tbl13: data 39
;Upper case letter digits
tbl14: data a
tbl15: data 41
tbl16: data b
tbl17: data 42
tbl18: data c
tbl19: data 43
tbl1a: data d
tbl1b: data 44
tbl1c: data e
tbl1d: data 45
tbl1e: data f
tbl1f: data 46
;Lower case letter digits
tbl20: data a
tbl21: data 61
tbl22: data b
tbl23: data 62
tbl24: data c
tbl25: data 63
tbl26: data d
tbl27: data 64
tbl28: data e
tbl29: data 65
tbl2a: data f
tbl2b: data 66
;Variables
ovrflw: data 0
arg1: data 0
sign: data 0

View File

@ -66,10 +66,12 @@ Address arguments can be either absolute addresses or references to or
relative to a label. Relative references are of the form LABEL +/- N,
the spacing being optional.
In addition to the true instructions there are two pseudo-instructions.
ORG defines the starting address of the program: it can only occur as
the first instruction and cannot have a label, and is not required if
the starting address is 0. DATA introduces a byte of data.
In addition to the true instructions there are three
pseudo-instructions. ORG defines the starting address of the program: it
can only occur as the first instruction and cannot have a label, and is
not required if the starting address is 0. DATA introduces a byte of
data. ADDR introduces two bytes of data containing the address of its
argument, a reference to or relative to a label.
Note that the assembler does not check for addresses or references to
reserved addresses or references to or relative to non-existing labels.