Separate control of the tape reader and punch into its own program
This commit is contained in:
parent
7316f8ad79
commit
b3d043d43c
3 changed files with 189 additions and 42 deletions
114
emulator.pas
114
emulator.pas
|
@ -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
|
||||
|
|
24
readme.md
24
readme.md
|
@ -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
93
settape.pas
Normal 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.
|
Loading…
Reference in a new issue