Add option for emulated modem
This commit is contained in:
parent
23b32d7835
commit
da67a19ac6
118
emulator.pas
118
emulator.pas
|
@ -2,17 +2,35 @@ program Emulator;
|
||||||
|
|
||||||
{$MODE OBJFPC}
|
{$MODE OBJFPC}
|
||||||
|
|
||||||
uses SysUtils, Crt;
|
{$ifdef full}
|
||||||
|
{$define RAM64}
|
||||||
|
{$define printer}
|
||||||
|
{$define tape}
|
||||||
|
{$define floppy}
|
||||||
|
{$define modem}
|
||||||
|
{$endif}
|
||||||
|
|
||||||
|
uses SysUtils, Crt{$ifdef modem}, Sockets{$endif};
|
||||||
|
|
||||||
{$ifdef tape}
|
|
||||||
type
|
type
|
||||||
|
{$ifdef tape}
|
||||||
//Tape file path and reset state
|
//Tape file path and reset state
|
||||||
Tape = record
|
Tape = record
|
||||||
Path: shortstring;
|
Path: shortstring;
|
||||||
Reset: boolean;
|
Reset: boolean;
|
||||||
Pos: integer;
|
Pos: integer;
|
||||||
end;
|
end;
|
||||||
{$endif}
|
{$endif}
|
||||||
|
{$ifdef modem}
|
||||||
|
//Modem connection state
|
||||||
|
Connection = record
|
||||||
|
Call: boolean;
|
||||||
|
Addr: longword;
|
||||||
|
Port: word;
|
||||||
|
Answer: boolean;
|
||||||
|
Hang: boolean;
|
||||||
|
end;
|
||||||
|
{$endif}
|
||||||
|
|
||||||
const
|
const
|
||||||
//The last address of RAM
|
//The last address of RAM
|
||||||
|
@ -31,7 +49,7 @@ const
|
||||||
{$endif}
|
{$endif}
|
||||||
|
|
||||||
var
|
var
|
||||||
Hlt, Echo{$ifdef floppy}, DiscRead, DiscWrite, DiscTrackSet, DiscSectSet{$endif}: boolean; //Halt and echo flags and disc system flags
|
Hlt, Echo{$ifdef floppy}, DiscRead, DiscWrite, DiscTrackSet, DiscSectSet{$endif}{$ifdef modem}, Calling{$endif}: boolean; //Halt and echo flags, disc system flags, and modem connection flag
|
||||||
Op, Regs: 0 .. $f; //Opcode
|
Op, Regs: 0 .. $f; //Opcode
|
||||||
X, Y: 0 .. 3; //Register arguments
|
X, Y: 0 .. 3; //Register arguments
|
||||||
Addr, IP, RP: word; //Immediate or address argument and instruction and return pointers
|
Addr, IP, RP: word; //Immediate or address argument and instruction and return pointers
|
||||||
|
@ -56,6 +74,12 @@ var
|
||||||
{$ifdef floppy}
|
{$ifdef floppy}
|
||||||
DiscDrive: 0 .. 1; //Current disc drive number
|
DiscDrive: 0 .. 1; //Current disc drive number
|
||||||
{$endif}
|
{$endif}
|
||||||
|
{$ifdef modem}
|
||||||
|
ModemConn: Connection; //State of the modem
|
||||||
|
ModemState: file of Connection; //File storing the state of the modem
|
||||||
|
ServerSocket: longint; //Server socket
|
||||||
|
ServerAddr: TInetSockAddr; //Server address
|
||||||
|
{$endif}
|
||||||
|
|
||||||
//Terminal output
|
//Terminal output
|
||||||
procedure Output;
|
procedure Output;
|
||||||
|
@ -90,6 +114,57 @@ begin
|
||||||
end;
|
end;
|
||||||
{$endif}
|
{$endif}
|
||||||
|
|
||||||
|
{$ifdef modem}
|
||||||
|
//Connect
|
||||||
|
procedure CallServer;
|
||||||
|
begin
|
||||||
|
assign (ModemState, ExpandFileName ('~/.thingamajig/connection'));
|
||||||
|
//Check the modem state
|
||||||
|
if FileExists (ExpandFileName ('~/.thingamajig/connection')) then begin
|
||||||
|
try
|
||||||
|
reset (ModemState);
|
||||||
|
read (ModemState, ModemConn);
|
||||||
|
close (ModemState);
|
||||||
|
except
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
//Hang
|
||||||
|
if ModemConn.Hang then if Calling then begin
|
||||||
|
CloseSocket (ServerSocket);
|
||||||
|
ModemConn.Hang := false;
|
||||||
|
Calling := false;
|
||||||
|
end
|
||||||
|
else if ModemConn.Call then if Calling then begin
|
||||||
|
CloseSocket (ServerSocket);
|
||||||
|
Calling := false;
|
||||||
|
end;
|
||||||
|
//Call
|
||||||
|
if ModemConn.Call then if Calling = false then begin
|
||||||
|
//Create a socket
|
||||||
|
ServerSocket := fpSocket (AF_INET, SOCK_STREAM, 0);
|
||||||
|
if ServerSocket <> -1 then begin
|
||||||
|
//Connect
|
||||||
|
ServerAddr.sin_family := AF_INET;
|
||||||
|
ServerAddr.sin_port := htons (ModemConn.Port);
|
||||||
|
ServerAddr.sin_addr.s_addr := htonl (ModemConn.Addr);
|
||||||
|
if fpconnect (ServerSocket, @ServerAddr, Sizeof (ServerAddr)) <> -1 then begin
|
||||||
|
ModemConn.Call := false;
|
||||||
|
Calling := true;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
//Save the modem state
|
||||||
|
if FileExists (ExpandFileName ('~/.thingamajig/connection')) then begin
|
||||||
|
try
|
||||||
|
rewrite (ModemState);
|
||||||
|
write (ModemState, ModemConn);
|
||||||
|
close (ModemState);
|
||||||
|
except
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
{$endif}
|
||||||
|
|
||||||
//Load a byte from memory
|
//Load a byte from memory
|
||||||
function LoadByte (W: word): byte;
|
function LoadByte (W: word): byte;
|
||||||
var
|
var
|
||||||
|
@ -178,6 +253,19 @@ begin
|
||||||
else B := 0;
|
else B := 0;
|
||||||
end
|
end
|
||||||
{$endif}
|
{$endif}
|
||||||
|
{$ifdef modem}
|
||||||
|
//Modem
|
||||||
|
else if W = $fffa then begin
|
||||||
|
{$ifndef fast}
|
||||||
|
wait (26);
|
||||||
|
{$endif}
|
||||||
|
//Connect
|
||||||
|
CallServer;
|
||||||
|
//Recieve
|
||||||
|
if Calling then fpRecv (ServerSocket, @B, 1, 0)
|
||||||
|
else B := 0;
|
||||||
|
end
|
||||||
|
{$endif}
|
||||||
//Unused addresses
|
//Unused addresses
|
||||||
else if W > LastRAM then B := 0
|
else if W > LastRAM then B := 0
|
||||||
//Regular load
|
//Regular load
|
||||||
|
@ -515,6 +603,18 @@ begin
|
||||||
end;
|
end;
|
||||||
end
|
end
|
||||||
{$endif}
|
{$endif}
|
||||||
|
{$ifdef modem}
|
||||||
|
//Modem
|
||||||
|
else if W = $fffa then begin
|
||||||
|
{$ifndef fast}
|
||||||
|
wait (26);
|
||||||
|
{$endif}
|
||||||
|
//Connect
|
||||||
|
CallServer;
|
||||||
|
//Send
|
||||||
|
if Calling then fpSend (ServerSocket, @B, 1, 0);
|
||||||
|
end
|
||||||
|
{$endif}
|
||||||
//Regular store
|
//Regular store
|
||||||
else if W <= LastRAM then Mem [W] := B;
|
else if W <= LastRAM then Mem [W] := B;
|
||||||
end;
|
end;
|
||||||
|
@ -565,6 +665,11 @@ begin
|
||||||
Disc1Sect := 0;
|
Disc1Sect := 0;
|
||||||
{$endif}
|
{$endif}
|
||||||
|
|
||||||
|
{$ifdef modem}
|
||||||
|
//Initialise the modem
|
||||||
|
Calling := false;
|
||||||
|
{$endif}
|
||||||
|
|
||||||
//Check the arguments
|
//Check the arguments
|
||||||
if ParamCount = 0 then begin
|
if ParamCount = 0 then begin
|
||||||
writeln ('Usage: emulator (-v) program (2> verbose_output)');
|
writeln ('Usage: emulator (-v) program (2> verbose_output)');
|
||||||
|
@ -726,6 +831,11 @@ begin
|
||||||
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{$ifdef modem}
|
||||||
|
//Disconnect the modem
|
||||||
|
if Calling then CloseSocket (ServerSocket);
|
||||||
|
{$endif}
|
||||||
|
|
||||||
{$ifndef fast}
|
{$ifndef fast}
|
||||||
wait (1);
|
wait (1);
|
||||||
{$endif}
|
{$endif}
|
||||||
|
|
|
@ -0,0 +1,106 @@
|
||||||
|
program ModemCtl;
|
||||||
|
|
||||||
|
{$MODE OBJFPC}
|
||||||
|
|
||||||
|
uses SysUtils, StrUtils, Sockets;
|
||||||
|
|
||||||
|
type
|
||||||
|
//Connection state
|
||||||
|
Connection = record
|
||||||
|
Call: boolean;
|
||||||
|
Addr: longword;
|
||||||
|
Port: word;
|
||||||
|
Answer: boolean;
|
||||||
|
Hang: boolean;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
ModemConn: Connection; //State of the modem
|
||||||
|
State: file of Connection; //File storing the state of the modem
|
||||||
|
Addr: in_addr; //Temporary variable
|
||||||
|
|
||||||
|
begin
|
||||||
|
|
||||||
|
//Check the arguments
|
||||||
|
if ParamStr (1) = '-c' then begin
|
||||||
|
if ParamCount > 2 then begin
|
||||||
|
writeln ('Usage: modemctl [-c address:port]/-a/-h');
|
||||||
|
halt (1);
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
if ParamCount > 1 then begin
|
||||||
|
writeln ('Usage: modemctl [-c address:port]/-a/-h');
|
||||||
|
halt (1);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
//Assign the state file
|
||||||
|
assign (State, ExpandFileName ('~/.thingamajig/connection'));
|
||||||
|
|
||||||
|
//Read existing state if any
|
||||||
|
if FileExists (ExpandFileName ('~/.thingamajig/connection')) then begin
|
||||||
|
try
|
||||||
|
reset (State);
|
||||||
|
read (State, ModemConn);
|
||||||
|
close (State);
|
||||||
|
except
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
//Or else assign a default state
|
||||||
|
else begin
|
||||||
|
ModemConn.Call := false;
|
||||||
|
ModemConn.Addr := 0;
|
||||||
|
ModemConn.Port := 0;
|
||||||
|
ModemConn.Answer := false;
|
||||||
|
ModemConn.Hang := false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
//Set the connection
|
||||||
|
if ParamStr (1) = '-c' then begin
|
||||||
|
ModemConn.Call := true;
|
||||||
|
try
|
||||||
|
Addr := StrToHostAddr (ExtractDelimited (1, ParamStr (2), [':']));
|
||||||
|
ModemConn.Addr := Addr.s_addr;
|
||||||
|
except
|
||||||
|
writeln ('Usage: modemctl [-c address:port]/-a/-h');
|
||||||
|
halt (1);
|
||||||
|
end;
|
||||||
|
try
|
||||||
|
ModemConn.Port := StrToInt (ExtractDelimited (2, ParamStr (2), [':']));
|
||||||
|
except
|
||||||
|
writeln ('Usage: modemctl [-c address:port]/-a/-h');
|
||||||
|
halt (1);
|
||||||
|
end;
|
||||||
|
ModemConn.Answer := false;
|
||||||
|
ModemConn.Hang := false;
|
||||||
|
end
|
||||||
|
else if ParamStr (1) = '-a' then begin
|
||||||
|
ModemConn.Call := false;
|
||||||
|
ModemConn.Addr := 0;
|
||||||
|
ModemConn.Port := 0;
|
||||||
|
ModemConn.Answer := true;
|
||||||
|
ModemConn.Hang := false;
|
||||||
|
end
|
||||||
|
else if ParamStr (1) = '-h' then begin
|
||||||
|
ModemConn.Call := false;
|
||||||
|
ModemConn.Addr := 0;
|
||||||
|
ModemConn.Port := 0;
|
||||||
|
ModemConn.Answer := false;
|
||||||
|
ModemConn.Hang := true;
|
||||||
|
end
|
||||||
|
else begin
|
||||||
|
writeln ('Usage: modemctl [-c address:port]/-a/-h');
|
||||||
|
halt (1);
|
||||||
|
end;
|
||||||
|
|
||||||
|
//Write the state
|
||||||
|
try
|
||||||
|
rewrite (State);
|
||||||
|
write (State, ModemConn);
|
||||||
|
close (State);
|
||||||
|
except
|
||||||
|
writeln ('Error: could not set the connection');
|
||||||
|
end;
|
||||||
|
|
||||||
|
end.
|
36
readme.md
36
readme.md
|
@ -9,8 +9,8 @@ Included Software
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
The repository includes an emulator implementation of Thingamajig with
|
The repository includes an emulator implementation of Thingamajig with
|
||||||
storage device control programs, and an assembler and a disassembler,
|
device control programs, and an assembler and a disassembler, all
|
||||||
all written in FreePascal. It also includes couple of simple example
|
written in FreePascal. It also includes couple of simple example
|
||||||
programs for Thingamajig written in assembly.
|
programs for Thingamajig written in assembly.
|
||||||
|
|
||||||
Registers and Memory
|
Registers and Memory
|
||||||
|
@ -91,13 +91,14 @@ implementation has a front panel the IPL is optional. The instruction
|
||||||
and return pointers are initialised as 0 and the first address after RAM
|
and return pointers are initialised as 0 and the first address after RAM
|
||||||
respectively, while other registers and RAM are uninitialised.
|
respectively, while other registers and RAM are uninitialised.
|
||||||
|
|
||||||
Emulator and Storage Device Control Programs
|
Emulator and Device Control Programs
|
||||||
--------------------------------------------
|
------------------------------------
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
* emulator (-v) program (2> verbose_output)
|
* emulator (-v) program (2> verbose_output)
|
||||||
* tapectl (-r tape) (-p tape)
|
* tapectl (-r tape) (-p tape)
|
||||||
* floppyctl (-0 disc) (-1 disc)
|
* floppyctl (-0 disc) (-1 disc)
|
||||||
|
* modemctl [-c address:port]/-a/-h
|
||||||
|
|
||||||
By default the emulator runs at roughly 500 KIPS and has 2 KiB of RAM.
|
By default the emulator runs at roughly 500 KIPS and has 2 KiB of RAM.
|
||||||
The arguments -dRAM4, -dRAM8, -dRAM16, -dRAM32, and -dRAM64 can be used
|
The arguments -dRAM4, -dRAM8, -dRAM16, -dRAM32, and -dRAM64 can be used
|
||||||
|
@ -118,16 +119,23 @@ characters and non-character keys null.
|
||||||
|
|
||||||
In Linux the emulator can be compiled with support for a character
|
In Linux the emulator can be compiled with support for a character
|
||||||
printer, an emulated high speed (roughly 500 CPS in and 50 CPS out)
|
printer, an emulated high speed (roughly 500 CPS in and 50 CPS out)
|
||||||
8-bit paper tape reader and punch, and an emulated two-drive 8" floppy
|
8-bit paper tape reader and punch, an emulated two-drive 8" floppy disc
|
||||||
disc system with the arguments -dprinter, -dtape, and -dfloppy
|
system, and a roughly 300 b/s modem with the arguments -dprinter,
|
||||||
respectively. The printer is mapped to address FFFE, the tape reader and
|
-dtape, -dfloppy, and -dmodem respectively. Full 64 KiB of RAM and all
|
||||||
punch to FFFD, and the disc system to FFFB and FFFC. The printer prints
|
of these options can also be enabled with the argument -dfull. The
|
||||||
into /dev/usb/lp0. The tape files read from and punched to are (re)set
|
printer is mapped to address FFFE, the tape reader and punch to FFFD,
|
||||||
using the program tapectl with the arguments -r and -p respectively and
|
the disc system to FFFB and FFFC, and the modem to FFFA. The printer
|
||||||
the disc files in drives 0 and 1 using the program floppyctl with the
|
prints into /dev/usb/lp0. The tape files read from and punched to are
|
||||||
arguments -0 and -1 respectively. The disc system uses hard sectored
|
(re)set using the program tapectl with the arguments -r and -p
|
||||||
single-sided discs with 77 tracks of 32 sectors of 137 bytes, or 337568
|
respectively and the disc files in drives 0 and 1 using the program
|
||||||
bytes in total: the disc files must be of this size.
|
floppyctl with the arguments -0 and -1 respectively. The disc system
|
||||||
|
uses hard sectored single-sided discs with 77 tracks of 32 sectors of
|
||||||
|
137 bytes, or 337568 bytes in total: the disc files must be of this
|
||||||
|
size. The modem is controlled by the program modemctl: the option -c is
|
||||||
|
used to "call" an IP address and port, -a to set the modem ready for
|
||||||
|
"answering" "calls" to port 1337, and -h to "hang". "Hanging" manually
|
||||||
|
is not necessary when "calling" a different address or switching between
|
||||||
|
"calling" and "answering". Note: "Answering" is not functional yet.
|
||||||
|
|
||||||
The floppy disc system uses two ports: command at FFFB and data at FFFC.
|
The floppy disc system uses two ports: command at FFFB and data at FFFC.
|
||||||
Only the low nibble of the command port is used, consisting of a
|
Only the low nibble of the command port is used, consisting of a
|
||||||
|
|
Loading…
Reference in New Issue