From 3eba71ab0e57f107cfa77d22b339046c05b1873b Mon Sep 17 00:00:00 2001 From: CrazyEttin <> Date: Thu, 25 Aug 2022 17:19:32 +0300 Subject: [PATCH] Add immediate loading and change the register argument placement in store --- assembler.pas | 31 ++++++- disassembler.pas | 34 ++++++-- emulator.pas | 205 ++++++++++++++++++++++++--------------------- examples/ascii.asm | 128 +++++++++------------------- examples/echo.asm | 159 +++++++++++++++++++++++------------ readme.md | 13 ++- 6 files changed, 317 insertions(+), 253 deletions(-) diff --git a/assembler.pas b/assembler.pas index b647db3..339422d 100644 --- a/assembler.pas +++ b/assembler.pas @@ -349,14 +349,33 @@ begin //First argument OneArgReg (2); //Second argument - AddrArg (3, 1); + //Immediate + if LeftStr (Elem [3], 1) = '#' then begin + Elem [3] := TrimLeftSet (Elem [3], ['#']); + if (BP + 1) >= $fff0 then MemError; + try + if Hex2Dec (Elem [3]) <= $ff then begin + Bin [BP] := Bin [BP] + 3; + Bin [BP + 1] := Hex2Dec (Elem [3]); + end + else ArgError; + except + ArgError; + end; + end + //Address + else AddrArg (3, 1); end; //Store if Bin [BP] = $b0 then begin //First argument AddrArg (2, 1); //Second argument - OneArgReg (3); + if CompareText (Elem [3], 'R0') = 0 then Bin [BP] := Bin [BP] + 0 + else if CompareText (Elem [3], 'R1') = 0 then Bin [BP] := Bin [BP] + 1 + else if CompareText (Elem [3], 'R2') = 0 then Bin [BP] := Bin [BP] + 2 + else if CompareText (Elem [3], 'R3') = 0 then Bin [BP] := Bin [BP] + 3 + else ArgError; end; //Branches and calls if Bin [BP] >= $c0 then begin @@ -367,7 +386,13 @@ begin end; //Increment the byte pointer - if Bin [BP] >= $a0 then BP := BP + 3 + if Bin [BP] >= $a0 then begin + if Bin [BP] <= $af then begin + if (Bin [BP] and 3) <> 0 then BP := BP + 2 + else BP := BP + 3; + end + else BP := BP + 3; + end else BP := BP + 1; end; diff --git a/disassembler.pas b/disassembler.pas index 0ea27f6..9ebed96 100644 --- a/disassembler.pas +++ b/disassembler.pas @@ -75,18 +75,36 @@ begin X := Bin [BP] and $c shr 2; Y := Bin [BP] and 3; BP := BP + 1; - //Address argument + //Immediate or address argument if Op >= $a then begin + //Immediate or high byte of address Addr := Bin [BP]; Addr := Addr shl 8; BP := BP + 1; - Addr := Addr + Bin [BP]; - BP := BP - 1; + //Low byte of address + if Op = $a then begin + if Y = 0 then begin + Addr := Addr + Bin [BP]; + BP := BP - 1; + end + else BP := BP - 1; + end + else begin + Addr := Addr + Bin [BP]; + BP := BP - 1; + end; end; //Print the data write (IntToHex (Op, 1), IntToHex (Regs, 1)); - if Op >= $a then write (IntToHex (Addr, 4)) else write (' '); + if Op >= $a then begin + if Op = $a then begin + if Y = 0 then write (IntToHex (Addr, 4)) + else write (IntToHex (Addr shr 8, 2), ' '); + end + else write (IntToHex (Addr, 4)); + end + else write (' '); write (' '); //Print the instruction @@ -96,7 +114,13 @@ begin if Op >= 2 then write ('R', X); if Op >= 6 then if Op <= 9 then write (', R', Y); if OP >= $c then write (', R', Y); - if Op >= $a then write (', ', IntToHex (Addr, 1)); + if Op >= $a then begin + if Op = $a then begin + if Y = 0 then write (', ', IntToHex (Addr, 1)) + else write (', #', IntToHex (Addr shr 8, 1)) + end + else write (', ', IntToHex (Addr, 1)); + end; writeln (); end; diff --git a/emulator.pas b/emulator.pas index d878156..6aeed38 100644 --- a/emulator.pas +++ b/emulator.pas @@ -21,7 +21,7 @@ var Hlt, ASCII, Verbose: boolean; //Halt, ASCII, and verbose flags Op, Regs: 0 .. $f; //Opcode X, Y: 0 .. 3; //Register arguments - Addr, IP, RP: word; //Address argument and instruction and return pointers + Addr, IP, RP: word; //Immediate or address argument and instruction and return pointers R: array [0 .. 3] of byte; //General-purpose registers Mem: array [0 .. $ffef] of byte; //Memory Prog{$ifdef printer}, Prn{$endif}{$ifdef tape}, TapeIn, TapeOut{$endif}: file of byte; //Program file, line printer, and tape reader and punch tapes @@ -138,9 +138,9 @@ begin writeln ('Error: illegal instruction pointer value'); halt; end; - //Address argument + //Immediate or address argument if Op >= $a then begin - //High byte + //Immediate or high byte of address Addr := Mem [IP]; Addr := Addr shl 8; IP := IP + 1; @@ -148,12 +148,24 @@ begin writeln ('Error: illegal instruction pointer value'); halt; end; - //Low byte - Addr := Addr + Mem [IP]; - IP := IP + 1; - if IP > $ffef then begin - writeln ('Error: illegal instruction pointer value'); - halt; + //Low byte of address + if Op = $a then begin + if Y = 0 then begin + Addr := Addr + Mem [IP]; + IP := IP + 1; + if IP > $ffef then begin + writeln ('Error: illegal instruction pointer value'); + halt; + end; + end; + end + else begin + Addr := Addr + Mem [IP]; + IP := IP + 1; + if IP > $ffef then begin + writeln ('Error: illegal instruction pointer value'); + halt; + end; end; end else Addr := 0; @@ -197,99 +209,104 @@ begin else if Op = 9 then R [X] := R [X] xor R [Y] //Load else if Op = $a then begin - //Terminal input - if Addr = IO then begin - wait; - //Read a keypress - repeat - Ch := ReadKey; - //Check for non-ASCII keys - if Ch = ansichar (0) then begin - //Non-ASCII - if keypressed then begin - Scan := ReadKey; - //The delete key inserts the delete character - if Scan = ansichar ($53) then begin - Ch := ansichar ($7f); - ASCII := true; + //Immediate + if Y <> 0 then R [X] := Addr shr 8 + //Address + else begin + //Terminal input + if Addr = IO then begin + wait; + //Read a keypress + repeat + Ch := ReadKey; + //Check for non-ASCII keys + if Ch = ansichar (0) then begin + //Non-ASCII + if keypressed then begin + Scan := ReadKey; + //The delete key inserts the delete character + if Scan = ansichar ($53) then begin + Ch := ansichar ($7f); + ASCII := true; + end + //Unused function keys insert a null + else ASCII := true; end - //Unused function keys insert a null + //Null else ASCII := true; end - //Null + //Other ASCII else ASCII := true; + until ASCII = true; + //Bodge for the home and end keys + if Ch = ansichar ($37) then begin + if keypressed then begin + Scan := ReadKey; + Scan := ReadKey; + Scan := ReadKey; + Ch := ansichar (0); + end; end - //Other ASCII - else ASCII := true; - until ASCII = true; - //Bodge for the home and end keys - if Ch = ansichar ($37) then begin - if keypressed then begin - Scan := ReadKey; - Scan := ReadKey; - Scan := ReadKey; - Ch := ansichar (0); + else if Ch = ansichar ($38) then begin + if keypressed then begin + Scan := ReadKey; + Scan := ReadKey; + Scan := ReadKey; + Ch := ansichar (0); + end; + end; + //Process the keypress + Output; //Local echo + R [X] := byte (Ch); + end + //Tape reader + {$ifdef tape} + else if Addr = $fffd then begin + wait; + assign (State, ExpandFileName ('~/.tapes.thingamajig')); + //Check the reader state + if FileExists (ExpandFileName ('~/.tapes.thingamajig')) then begin + try + reset (State); + read (State, Reader); + read (State, Punch); + close (State); + except + end; + end; + //Read + assign (TapeIn, Reader.Path); + try + reset (TapeIn); + seek (TapeIn, Reader.Pos); + read (TapeIn, R [X]); + close (TapeIn); + Reader.Pos := Reader.Pos + 1; + except + R [X] := $ff; + end; + //Save the reader state + if FileExists (ExpandFileName ('~/.tapes.thingamajig')) then begin + try + rewrite (State); + write (State, Reader); + write (State, Punch); + close (State); + except + end; end; end - else if Ch = ansichar ($38) then begin - if keypressed then begin - Scan := ReadKey; - Scan := ReadKey; - Scan := ReadKey; - Ch := ansichar (0); - end; - end; - //Process the keypress - Output; //Local echo - R [X] := byte (Ch); - end - //Tape reader - {$ifdef tape} - else if Addr = $fffd then begin - wait; - assign (State, ExpandFileName ('~/.tapes.thingamajig')); - //Check the reader state - if FileExists (ExpandFileName ('~/.tapes.thingamajig')) then begin - try - reset (State); - read (State, Reader); - read (State, Punch); - close (State); - except - end; - end; - //Read - assign (TapeIn, Reader.Path); - try - reset (TapeIn); - seek (TapeIn, Reader.Pos); - read (TapeIn, R [X]); - close (TapeIn); - Reader.Pos := Reader.Pos + 1; - except - R [X] := $ff; - end; - //Save the reader state - if FileExists (ExpandFileName ('~/.tapes.thingamajig')) then begin - try - rewrite (State); - write (State, Reader); - write (State, Punch); - close (State); - except - end; - end; - end - {$endif} - //Regular load - else R [X] := Mem [Addr]; + {$endif} + //Regular load + else R [X] := Mem [Addr]; + end; end //Store else if Op = $b then begin //Terminal output if Addr = IO then begin wait; - Ch := ansichar (R [X]); + Ch := ansichar (R [Y]); Output; end //Printer @@ -299,7 +316,7 @@ begin assign (Prn, '/dev/usb/lp0'); try rewrite (Prn); - write (Prn, R [X]); + write (Prn, R [Y]); close (Prn); except end; @@ -326,7 +343,7 @@ begin if FileExists (Punch.Path) = false then begin try rewrite (TapeOut); - write (TapeOut, R [X]); + write (TapeOut, R [Y]); close (TapeOut); Punch.Reset := false; except @@ -335,7 +352,7 @@ begin else if Punch.Reset then begin try rewrite (TapeOut); - write (TapeOut, R [X]); + write (TapeOut, R [Y]); close (TapeOut); Punch.Reset := false; except @@ -345,7 +362,7 @@ begin try reset (TapeOut); seek (TapeOut, FileSize (TapeOut)); - write (TapeOut, R [X]); + write (TapeOut, R [Y]); close (TapeOut); except end; @@ -364,7 +381,7 @@ begin end {$endif} //Regular store - else Mem [Addr] := R [X]; + else Mem [Addr] := R [Y]; end //Breq else if Op = $c then begin diff --git a/examples/ascii.asm b/examples/ascii.asm index 81e24b7..d258871 100644 --- a/examples/ascii.asm +++ b/examples/ascii.asm @@ -1,9 +1,9 @@ ;ASCII code printer ;Print a prompt - load r0, prompt + load r0, #3e store ffff, r0 - load r0, space + load r0, #20 store ffff, r0 ;Read a character to r0 and load it to r2 @@ -11,11 +11,8 @@ xor r2, r2 xor r2, r0 - ;Print a newline and align + ;Print a newline cleq r0, r0, newln - load r1, space - store ffff, r1 - store ffff, r1 ;Convert and print the high nibble ;Convert @@ -46,9 +43,9 @@ ;*** ;Print a newline -newln: load r1, cr +newln: load r1, #d store ffff, r1 - load r1, lf + load r1, #a store ffff, r1 ret @@ -57,126 +54,77 @@ newln: load r1, cr ;Get the hexadecimal digit of a nibble ;Extract the low nibble -n2hex: load r1, mask +n2hex: load r1, #f and r0, r1 ;Locate the nibble in the table - load r1, nbl0 + load r1, #0 breq r0, r1, dgt0 - load r1, nbl1 + load r1, #1 breq r0, r1, dgt1 - load r1, nbl2 + load r1, #2 breq r0, r1, dgt2 - load r1, nbl3 + load r1, #3 breq r0, r1, dgt3 - load r1, nbl4 + load r1, #4 breq r0, r1, dgt4 - load r1, nbl5 + load r1, #5 breq r0, r1, dgt5 - load r1, nbl6 + load r1, #6 breq r0, r1, dgt6 - load r1, nbl7 + load r1, #7 breq r0, r1, dgt7 - load r1, nbl8 + load r1, #8 breq r0, r1, dgt8 - load r1, nbl9 + load r1, #9 breq r0, r1, dgt9 - load r1, nbla + load r1, #a breq r0, r1, dgta - load r1, nblb + load r1, #b breq r0, r1, dgtb - load r1, nblc + load r1, #c breq r0, r1, dgtc - load r1, nbld + load r1, #d breq r0, r1, dgtd - load r1, nble + load r1, #e breq r0, r1, dgte - load r1, nblf + load r1, #f breq r0, r1, dgtf ;Load the hexadecimal digit of the nibble -dgt0: load r0, hex0 +dgt0: load r0, #30 breq r0, r0, n2hend -dgt1: load r0, hex1 +dgt1: load r0, #31 breq r0, r0, n2hend -dgt2: load r0, hex2 +dgt2: load r0, #32 breq r0, r0, n2hend -dgt3: load r0, hex3 +dgt3: load r0, #33 breq r0, r0, n2hend -dgt4: load r0, hex4 +dgt4: load r0, #34 breq r0, r0, n2hend -dgt5: load r0, hex5 +dgt5: load r0, #35 breq r0, r0, n2hend -dgt6: load r0, hex6 +dgt6: load r0, #36 breq r0, r0, n2hend -dgt7: load r0, hex7 +dgt7: load r0, #37 breq r0, r0, n2hend -dgt8: load r0, hex8 +dgt8: load r0, #38 breq r0, r0, n2hend -dgt9: load r0, hex9 +dgt9: load r0, #39 breq r0, r0, n2hend -dgta: load r0, hexa +dgta: load r0, #41 breq r0, r0, n2hend -dgtb: load r0, hexb +dgtb: load r0, #42 breq r0, r0, n2hend -dgtc: load r0, hexc +dgtc: load r0, #43 breq r0, r0, n2hend -dgtd: load r0, hexd +dgtd: load r0, #44 breq r0, r0, n2hend -dgte: load r0, hexe +dgte: load r0, #45 breq r0, r0, n2hend -dgtf: load r0, hexf +dgtf: load r0, #46 breq r0, r0, n2hend ;Return n2hend: ret - - ;*** - - ;Data - - ;Characters -cr: data d -lf: data a -space: data 20 -prompt: data 3e - - ;Mask -mask: data f - - ;Nibble table -nbl0: data 0 -nbl1: data 1 -nbl2: data 2 -nbl3: data 3 -nbl4: data 4 -nbl5: data 5 -nbl6: data 6 -nbl7: data 7 -nbl8: data 8 -nbl9: data 9 -nbla: data a -nblb: data b -nblc: data c -nbld: data d -nble: data e -nblf: data f - - ;Hexadecimal table -hex0: data 30 -hex1: data 31 -hex2: data 32 -hex3: data 33 -hex4: data 34 -hex5: data 35 -hex6: data 36 -hex7: data 37 -hex8: data 38 -hex9: data 39 -hexa: data 41 -hexb: data 42 -hexc: data 43 -hexd: data 44 -hexe: data 45 -hexf: data 46  \ No newline at end of file diff --git a/examples/echo.asm b/examples/echo.asm index 4c4fc4a..736e919 100644 --- a/examples/echo.asm +++ b/examples/echo.asm @@ -4,6 +4,12 @@ ;Input + ;Print a prompt + load r0, #3e + store ffff, r0 + load r0, #20 + store ffff, r0 + ;Restore the buffer start address ;High byte input: load r0, bfstrt @@ -12,12 +18,6 @@ input: load r0, bfstrt load r0, bfstrt + 1 store chstor + 2, r0 - ;Print a prompt - load r0, prompt - store ffff, r0 - load r0, space - store ffff, r0 - ;Initialise the character counter xor r0, r0 @@ -25,18 +25,24 @@ input: load r0, bfstrt inloop: load r1, ffff ;Check for control characters and the buffer end + ;Delete + load r2, #7f + breq r1, r2, delbr ;Escape - load r2, esc + load r2, #1b breq r1, r2, escbr ;Carriage return - load r2, cr + load r2, #d breq r1, r2, crbr + ;Line feed + load r2, #a + breq r1, r2, lfbr ;Buffer end load r2, bfsize brneq r0, r2, chstor ;Backtrack if at the buffer end - load r2, bs + load r2, #8 store ffff, r2 breq r0, r0, inloop @@ -45,7 +51,7 @@ chstor: store buffer, r1 ;Increment the character counter and store it in r3 ;Increment - load r2, one + load r2, #1 cleq r0, r0, sum ;Store xor r3, r3 @@ -54,7 +60,48 @@ chstor: store buffer, r1 ;Increment the buffer address ;Low byte load r0, chstor + 2 - load r2, one + load r2, #1 + cleq r0, r0, sum + store chstor + 2, r0 + ;Add the overflow to the high byte + load r0, chstor + 1 + xor r2, r2 + xor r2, r1 + cleq r0, r0, sum + store chstor + 1, r0 + + ;Reload the character counter to r0 + xor r0, r0 + xor r0, r3 + + ;Read the next character + breq r0, r0, inloop + + ;Print an underscore +delbr: load r2, #5f + store ffff, r2 + + ;Check for buffer start + xor r2, r2 + breq r0, r2, inloop + + ;Decrement the character counter and store it in r3 + ;Decrement + load r2, #ff + cleq r0, r0, sum + ;Store + xor r3, r3 + xor r3, r0 + + ;Decrement the buffer address + ;High byte + load r0, chstor + 1 + load r2, #ff + cleq r0, r0, sum + store chstor + 1, r0 + ;Low byte + load r0, chstor + 2 + load r2, #ff cleq r0, r0, sum store chstor + 2, r0 ;Add the overflow to the high byte @@ -73,56 +120,78 @@ chstor: store buffer, r1 ;Print a backslash and a newline ;Backslash -escbr: load r0, space +escbr: load r0, #20 store ffff, r0 - load r0, bslash + load r0, #5c store ffff, r0 ;Newline - load r0, cr + load r0, #d + store ffff, r0 + load r0, #a + store ffff, r0 + + ;Align + load r0, #20 store ffff, r0 - load r0, lf store ffff, r0 ;Start a new input line breq r0, r0, input - ;Store a string-terminating zero in the buffer + ;Print a line feed +crbr: load r0, #a + store ffff, r0 + breq r0, r0, endnul + + ;Print a carriage return +lfbr: load r0, #d + store ffff, r0 + + ;Store a carriage return in the buffer ;Get the buffer address -crbr: load r1, chstor + 1 +endnul: load r1, chstor + 1 store endsto + 1, r1 load r1, chstor + 2 store endsto + 2, r1 ;Store - xor r0, r0 -endsto: store 0000, r0 + load r0, #d +endsto: store 0, r0 + + ;Increment the buffer address + ;Low byte + load r0, endsto + 2 + load r2, #1 + cleq r0, r0, sum + store endlf + 2, r0 + ;Add the overflow to the high byte + load r0, endsto + 1 + xor r2, r2 + xor r2, r1 + cleq r0, r0, sum + store endlf + 1, r0 + + ;Store a line feed in the buffer + load r0, #a +endlf: store 0, r0 ;*** ;Print - ;Print a line feed and align with the input - ;Line feed - load r0, lf - store ffff, r0 - ;Align - load r0, space - store ffff, r0 - store ffff, r0 - ;Load a character from the buffer chprnt: load r1, buffer - ;Check for string end - xor r2, r2 - breq r1, r2, end - ;Print the character store ffff, r1 + ;Check for string end + load r2, #a + breq r1, r2, end + ;Increment the buffer address ;Low byte load r0, chprnt + 2 - load r2, one + load r2, #1 cleq r0, r0, sum store chprnt + 2, r0 ;Add the overflow to the high byte @@ -135,14 +204,8 @@ chprnt: load r1, buffer ;Print the next character breq r0, r0, chprnt - ;Print a newline -end: load r0, cr - store ffff, r0 - load r0, lf - store ffff, r0 - ;Halt - halt +end: halt ;*** @@ -172,7 +235,7 @@ sumlop: xor r1, r1 rol r1 breq r1, r2, nvrflw ;Store - load r1, one + load r1, #1 store ovrflw, r1 ;Check for no carry @@ -190,24 +253,12 @@ sumend: load r1, ovrflw ;Data - ;Constants -one: data 1 - - ;Characters -bs: data 8 -lf: data a -cr: data d -esc: data 1b -space: data 20 -prompt: data 3e -bslash: data 5c - ;Variables ovrflw: data 0 ;Buffer bfstrt: addr buffer -bfsize: data ff +bfsize: data fe buffer:  \ No newline at end of file diff --git a/readme.md b/readme.md index 75e06f7..ccf4dcf 100644 --- a/readme.md +++ b/readme.md @@ -37,9 +37,9 @@ respectively, while other registers and memory are unitialised. Instructions ------------ -Instructions without an address argument are 8-bit and those with one -24-bit. The instruction pointer is incremented before being accessed or -modified. +Instructions without an immediate or address argument are 8-bit, those +with an immediate one 16-bit, and those with an address one 24-bit. The +instruction pointer is incremented before being accessed or modified. 0 HALT 1 RET IP = *RP; RP += 2 @@ -54,10 +54,9 @@ modified. 8 OR RX, RY RX |= RY 9 XOR RX, RY RX ^= RY -A LOAD RX, ADDR RX = *ADDR -B STORE RX, ADDR *ADDR = RX Written as "STORE ADDR, RX" in - assembly for the sake of - consistency. +A LOAD RX, ~0, IMM RX = IMM Written as "LOAD RX, #IMM" + 0, ADDR RX = *ADDR Written as "LOAD RX, ADDR" +B STORE RY, ADDR *ADDR = RY Written as "STORE ADDR, RY" C BREQ RX, RY, ADDR if (RX == RY) IP = ADDR D BRNEQ RX, RY, ADDR if (RX != RY) IP = ADDR