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;
{$ifdef tape}
type
//Tape file path and reset state
Tape = record
Path: shortstring;
Reset: boolean;
Pos: integer;
end;
{$endif}
const
IO = $ffff;
@ -14,10 +24,10 @@ var
Addr, IP, RP: word; //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 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}
TapeInFile: string; //Punched tape reader source file
TapeInPos: integer; //Punched tape reader position pointer
Reader, Punch: Tape; //States of the tape reader and punch
State: file of Tape; //File storing the states of the tape reader and punch
{$endif}
Ch, Scan: ansichar; //Character for input and output and scancode for non-ASCII keys
@ -27,9 +37,15 @@ begin
Hlt := false;
IP := 0;
RP := $fff0;
//Initialise the tape reader and punch
{$ifdef tape}
TapeInFile := ' ';
TapeInPos := 0;
Reader.Path := '';
Reader.Reset := true;
Reader.Pos := 0;
Punch.Path := '';
Punch.Reset := true;
Punch.Pos := 0;
{$endif}
//Read a program file and check for errors
@ -144,17 +160,6 @@ begin
Ch := ansichar ($7f);
ASCII := true;
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
else ASCII := true;
end
@ -188,16 +193,39 @@ begin
//Tape reader
{$ifdef tape}
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
reset (TapeIn);
seek (TapeIn, TapeInPos);
seek (TapeIn, Reader.Pos);
read (TapeIn, R [X]);
TapeInPos := TapeInPos + 1;
close (TapeIn);
Reader.Pos := Reader.Pos + 1;
except
R [X] := 0;
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
@ -225,26 +253,52 @@ begin
//Tape punch
{$ifdef tape}
else if Addr = $fffd then begin
assign (TapeOut, 'tapeout');
if FileExists ('tapeout') = false then begin
assign (State, ExpandFileName ('~/.tapes.thingamajig'));
//Check the punch state
if FileExists (ExpandFileName ('~/.tapes.thingamajig')) then begin
try
rewrite (TapeOut);
write (TapeOut, R [X]);
close (TapeOut);
reset (State);
read (State, Reader);
read (State, Punch);
close (State);
except
end;
end
else begin
end;
//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
reset (TapeOut);
seek (TapeOut, FileSize (TapeOut));
write (TapeOut, R [X]);
close (TapeOut);
rewrite (State);
write (State, Reader);
write (State, Punch);
close (State);
except
end;
end;
end
{$endif}
//Regular store
else Mem [Addr] := R [X];
end

View file

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