From 087c88d8ceede36a23b8122e01b3b7128040ba99 Mon Sep 17 00:00:00 2001 From: CrazyEttin <> Date: Mon, 8 Aug 2022 20:06:43 +0300 Subject: [PATCH] Add the addr pseudo-instruction to the assembler and spin the calculator off into a project of its own --- assembler.pas | 41 ++++- examples/calc.asm | 427 ---------------------------------------------- readme.md | 10 +- 3 files changed, 39 insertions(+), 439 deletions(-) delete mode 100644 examples/calc.asm diff --git a/assembler.pas b/assembler.pas index 452ce17..179b6e8 100644 --- a/assembler.pas +++ b/assembler.pas @@ -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 diff --git a/examples/calc.asm b/examples/calc.asm deleted file mode 100644 index 9b73cb9..0000000 --- a/examples/calc.asm +++ /dev/null @@ -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 diff --git a/readme.md b/readme.md index 9c89f22..404e56a 100644 --- a/readme.md +++ b/readme.md @@ -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.