Separate control of the tape reader and punch into its own program

This commit is contained in:
CrazyEttin 2022-08-18 13:55:38 +03:00
parent 7316f8ad79
commit b3d043d43c
3 changed files with 189 additions and 42 deletions

View File

@ -4,6 +4,16 @@ program Emulator;
uses SysUtils, Crt; uses SysUtils, Crt;
{$ifdef tape}
type
//Tape file path and reset state
Tape = record
Path: shortstring;
Reset: boolean;
Pos: integer;
end;
{$endif}
const const
IO = $ffff; IO = $ffff;
@ -14,10 +24,10 @@ var
Addr, IP, RP: word; //Address argument and instruction and return pointers Addr, IP, RP: word; //Address argument and instruction and return pointers
R: array [0 .. 3] of byte; //General-purpose registers R: array [0 .. 3] of byte; //General-purpose registers
Mem: array [0 .. $ffef] of byte; //Memory 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 punched tape reader and punch Prog{$ifdef printer}, Prn{$endif}{$ifdef tape}, TapeIn, TapeOut{$endif}: file of byte; //Program file, line printer, and tape reader and punch tapes
{$ifdef tape} {$ifdef tape}
TapeInFile: string; //Punched tape reader source file Reader, Punch: Tape; //States of the tape reader and punch
TapeInPos: integer; //Punched tape reader position pointer State: file of Tape; //File storing the states of the tape reader and punch
{$endif} {$endif}
Ch, Scan: ansichar; //Character for input and output and scancode for non-ASCII keys Ch, Scan: ansichar; //Character for input and output and scancode for non-ASCII keys
@ -27,9 +37,15 @@ begin
Hlt := false; Hlt := false;
IP := 0; IP := 0;
RP := $fff0; RP := $fff0;
//Initialise the tape reader and punch
{$ifdef tape} {$ifdef tape}
TapeInFile := ' '; Reader.Path := '';
TapeInPos := 0; Reader.Reset := true;
Reader.Pos := 0;
Punch.Path := '';
Punch.Reset := true;
Punch.Pos := 0;
{$endif} {$endif}
//Read a program file and check for errors //Read a program file and check for errors
@ -144,17 +160,6 @@ begin
Ch := ansichar ($7f); Ch := ansichar ($7f);
ASCII := true; ASCII := true;
end end
{$ifdef tape}
//The insert key sets a tape to be read
else if Scan = ansichar ($52) then begin
writeln ();
write ('Tape to be read: ');
readln (TapeInFile);
if TapeInFile = '' then TapeInFile := ' ';
TapeInPos := 0;
ASCII := false;
end
{$endif}
//Unused function keys insert a null //Unused function keys insert a null
else ASCII := true; else ASCII := true;
end end
@ -188,16 +193,39 @@ begin
//Tape reader //Tape reader
{$ifdef tape} {$ifdef tape}
else if Addr = $fffd then begin else if Addr = $fffd then begin
assign (TapeIn, TapeInFile); 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 try
reset (TapeIn); reset (TapeIn);
seek (TapeIn, TapeInPos); seek (TapeIn, Reader.Pos);
read (TapeIn, R [X]); read (TapeIn, R [X]);
TapeInPos := TapeInPos + 1;
close (TapeIn); close (TapeIn);
Reader.Pos := Reader.Pos + 1;
except except
R [X] := 0; R [X] := 0;
end; 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 end
{$endif} {$endif}
//Regular load //Regular load
@ -225,26 +253,52 @@ begin
//Tape punch //Tape punch
{$ifdef tape} {$ifdef tape}
else if Addr = $fffd then begin else if Addr = $fffd then begin
assign (TapeOut, 'tapeout'); assign (State, ExpandFileName ('~/.tapes.thingamajig'));
if FileExists ('tapeout') = false then begin //Check the punch state
if FileExists (ExpandFileName ('~/.tapes.thingamajig')) then begin
try try
rewrite (TapeOut); reset (State);
write (TapeOut, R [X]); read (State, Reader);
close (TapeOut); read (State, Punch);
close (State);
except except
end; end;
end end;
else begin //Punch
if Punch.Path <> '' then begin
assign (TapeOut, Punch.Path);
if Punch.Reset then begin
try
rewrite (TapeOut);
write (TapeOut, R [X]);
close (TapeOut);
Punch.Reset := false;
except
end;
end
else begin
try
reset (TapeOut);
seek (TapeOut, FileSize (TapeOut));
write (TapeOut, R [X]);
close (TapeOut);
except
end;
end;
end;
//Save the punch state
if FileExists (ExpandFileName ('~/.tapes.thingamajig')) then begin
try try
reset (TapeOut); rewrite (State);
seek (TapeOut, FileSize (TapeOut)); write (State, Reader);
write (TapeOut, R [X]); write (State, Punch);
close (TapeOut); close (State);
except except
end; end;
end; end;
end end
{$endif} {$endif}
//Regular store //Regular store
else Mem [Addr] := R [X]; else Mem [Addr] := R [X];
end end

View File

@ -8,10 +8,11 @@ https://ahti.space/git/crazyettin/Thingamajig.
Included Software Included Software
----------------- -----------------
The repository includes an emulator implementation of Thingamajig as The repository includes an emulator implementation of Thingamajig, a
well as an assembler and a disassembler, all written in FreePascal. It control program for the emulated punched tape reader and punch, and an
also includes couple of simple example programs for Thingamajig written assembler and a disassembler, all written in FreePascal. It also
in Assembly. includes couple of simple example programs for Thingamajig written in
Assembly.
Registers and Memory Registers and Memory
-------------------- --------------------
@ -91,14 +92,13 @@ this.
Arbitrary devices can be mapped to the other reserved addresses. Arbitrary devices can be mapped to the other reserved addresses.
The emulator can be compiled with support for a line printer and an In Linux the emulator can be compiled with support for a line printer
emulated punched tape reader and punch with the arguments -dprinter and and an emulated punched tape reader and punch with the arguments
-dtape respectively. The printer outputs into /dev/usb/lp0 and the tape -dprinter and -dtape respectively. The printer prints into /dev/usb/lp0
punch to tapeout. To (re)set the tape to be read press the insert key at and the tape files read from and punched to are (re)set using the
any input and enter a file name; the input will resume after this. The settape program. The printer is mapped to address FFFE in the emulator
printer is mapped to address FFFE in the emulator and the tape reader and the tape reader and punch to FFFD. If you wish to use a different
and punch to FFFD. If you wish to use a different setup you have to setup you have to modify the code yourself.
modify the code yourself.
Initial Program Loader Initial Program Loader
---------------------- ----------------------

93
settape.pas Normal file
View File

@ -0,0 +1,93 @@
program Settape;
{$MODE OBJFPC}
uses SysUtils;
type
//Tape file path and reset state
Tape = record
Path: shortstring;
Reset: boolean;
Pos: integer;
end;
var
Reader, Punch: Tape; //States of the reader and punch
State: file of Tape; //File storing the states of the reader and punch
DoRead, DoPunch: boolean; //Whether to reset the reader or the punch
begin
//Check whether to set the reader, the punch, or both
if ParamCount <> 1 then begin
writeln ('Usage: settape reader/punch/both');
halt;
end;
if ParamStr (1) = 'reader' then begin
DoRead := true;
DoPunch := false;
end
else if ParamStr (1) = 'punch' then begin
DoRead := false;
DoPunch := true;
end
else if ParamStr (1) = 'both' then begin
DoRead := true;
DoPunch := true;
end
else begin
writeln ('Usage: settape reader/punch/both');
halt;
end;
//Assign the state file
assign (State, ExpandFileName ('~/.tapes.thingamajig'));
//Read existing state if any
if FileExists (ExpandFileName ('~/.tapes.thingamajig')) then begin
try
reset (State);
read (State, Reader);
read (State, Punch);
close (State);
except
end;
end
//Or else assign a default state
else begin
Reader.Path := '';
Reader.Reset := true;
Reader.Pos := 0;
Punch.Path := '';
Punch.Reset := true;
Punch.Pos := 0;
end;
//Input the files to be read from or punched to
if DoRead then begin
write ('Reader: ');
readln (Reader.Path);
Reader.Path := ExpandFileName (Reader.Path);
Reader.Reset := true;
Reader.Pos := 0;
end;
if DoPunch then begin
write ('Punch: ');
readln (Punch.Path);
Punch.Path := ExpandFileName (Punch.Path);
Punch.Reset := true;
Punch.Pos := 0;
end;
//Write the state
try
rewrite (State);
write (State, Reader);
write (State, Punch);
close (State);
except
writeln ('Error: could not set the tape(s)');
end;
end.