Add auto-answering and auto-hanging functionality as well as the ability to control answering and hanging via a memory-mapped device to the emulated modem
This commit is contained in:
parent
e626369a16
commit
64ddf705ea
296
emulator.pas
296
emulator.pas
|
@ -26,8 +26,9 @@ type
|
|||
//Modem connection state
|
||||
type
|
||||
Connection = record
|
||||
Call: boolean;
|
||||
Originate: boolean;
|
||||
Answer: boolean;
|
||||
Dial: boolean;
|
||||
Addr: longword;
|
||||
Port: word;
|
||||
Hang: boolean;
|
||||
|
@ -51,7 +52,7 @@ const
|
|||
{$endif}
|
||||
|
||||
var
|
||||
Hlt, Echo{$ifdef floppy}, DiscRead, DiscWrite, DiscTrackSet, DiscSectSet{$endif}{$ifdef modem}, Calling, Answering{$endif}: boolean; //Halt and echo flags, disc system flags, and modem connection flags
|
||||
Hlt, Echo{$ifdef floppy}, DiscRead, DiscWrite, DiscTrackSet, DiscSectSet{$endif}{$ifdef modem}, Listening, Connected{$endif}: boolean; //Halt and echo flags, disc system flags, and modem connection flags
|
||||
Op, Regs: 0 .. $f; //Opcode
|
||||
X, Y: 0 .. 3; //Register arguments
|
||||
Addr, IP, RP: word; //Immediate or address argument and instruction and return pointers
|
||||
|
@ -77,8 +78,9 @@ var
|
|||
DiscDrive: 0 .. 1; //Current disc drive number
|
||||
{$endif}
|
||||
{$ifdef modem}
|
||||
ModemConn: Connection; //State of the modem
|
||||
ModemState: file of Connection; //File storing the state of the modem
|
||||
ConnVar: Connection; //State of the modem
|
||||
ConnFile: file of Connection; //File storing the state of the modem
|
||||
Mode: (Originate, Answer); //Modem mode
|
||||
ServerSocket, ListenSocket, ClientSocket, ClientAddrSize: longint; //Server socket
|
||||
ServerAddr, ClientAddr: TInetSockAddr; //Server address
|
||||
SigPipeHandler: pSigActionRec; //SIGPIPE handler
|
||||
|
@ -128,98 +130,116 @@ end;
|
|||
{$endif}
|
||||
|
||||
{$ifdef modem}
|
||||
//Connect
|
||||
procedure CallServer;
|
||||
//Check the modem state
|
||||
procedure CheckModem;
|
||||
begin
|
||||
assign (ModemState, ExpandFileName ('~/.thingamajig/connection'));
|
||||
assign (ConnFile, ExpandFileName ('~/.thingamajig/connection'));
|
||||
//Check the modem state
|
||||
if FileExists (ExpandFileName ('~/.thingamajig/connection')) then begin
|
||||
try
|
||||
reset (ModemState);
|
||||
read (ModemState, ModemConn);
|
||||
close (ModemState);
|
||||
reset (ConnFile);
|
||||
read (ConnFile, ConnVar);
|
||||
close (ConnFile);
|
||||
except
|
||||
end;
|
||||
end;
|
||||
//Hang
|
||||
if ModemConn.Hang then begin
|
||||
if Calling then begin
|
||||
CloseSocket (ServerSocket);
|
||||
ModemConn.Hang := false;
|
||||
Calling := false;
|
||||
end
|
||||
else if Answering then begin
|
||||
CloseSocket (ClientSocket);
|
||||
CloseSocket (ListenSocket);
|
||||
ModemConn.Hang := false;
|
||||
Answering := false;
|
||||
end;
|
||||
end
|
||||
else if ModemConn.Call then begin
|
||||
if Calling then begin
|
||||
CloseSocket (ServerSocket);
|
||||
Calling := false;
|
||||
end
|
||||
else if Answering then begin
|
||||
CloseSocket (ClientSocket);
|
||||
CloseSocket (ListenSocket);
|
||||
Answering := false;
|
||||
end;
|
||||
end
|
||||
else if ModemConn.Answer then begin
|
||||
if Calling then begin
|
||||
CloseSocket (ServerSocket);
|
||||
Calling := false;
|
||||
end
|
||||
else if Answering then begin
|
||||
CloseSocket (ClientSocket);
|
||||
CloseSocket (ListenSocket);
|
||||
Answering := false;
|
||||
end;
|
||||
//Auto-set things when dialing
|
||||
if ConnVar.Dial then begin
|
||||
//Auto-change to originate mode if dialing in answer mode
|
||||
if Mode = Answer then ConnVar.Originate := true;
|
||||
//Auto-hang if dialing
|
||||
if Mode = Originate then if Connected then ConnVar.Hang := true;
|
||||
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
|
||||
//Call
|
||||
//Mode change
|
||||
//Originate
|
||||
if ConnVar.Originate then begin
|
||||
//Change the mode
|
||||
if Mode = Originate then begin
|
||||
if Connected then begin
|
||||
CloseSocket (ServerSocket);
|
||||
Connected := false;
|
||||
end;
|
||||
end
|
||||
else if Mode = Answer then begin
|
||||
if Connected then begin
|
||||
CloseSocket (ClientSocket);
|
||||
Connected := false;
|
||||
end;
|
||||
CloseSocket (ListenSocket);
|
||||
Listening := false;
|
||||
Mode := Originate;
|
||||
end;
|
||||
ConnVar.Originate := false;
|
||||
end
|
||||
//Answer
|
||||
else if ConnVar.Answer then begin
|
||||
//Change the mode
|
||||
if Mode = Originate then begin
|
||||
if Connected then begin
|
||||
CloseSocket (ServerSocket);
|
||||
Connected := false;
|
||||
end;
|
||||
Mode := Answer;
|
||||
end
|
||||
else if Mode = Answer then begin
|
||||
if Connected then begin
|
||||
CloseSocket (ClientSocket);
|
||||
Connected := false;
|
||||
end;
|
||||
CloseSocket (ListenSocket);
|
||||
Listening := false;
|
||||
end;
|
||||
//Create a listening socket
|
||||
ListenSocket := fpSocket (AF_INET, SOCK_STREAM, 0);
|
||||
if ListenSocket <> -1 then begin
|
||||
ServerAddr.sin_family := AF_INET;
|
||||
ServerAddr.sin_addr.s_addr := htonl (ModemConn.Addr);
|
||||
ServerAddr.sin_port := htons (ModemConn.Port);
|
||||
if fpConnect (ServerSocket, @ServerAddr, Sizeof (ServerAddr)) <> -1 then begin
|
||||
ModemConn.Call := false;
|
||||
Calling := true;
|
||||
ServerAddr.sin_addr.s_addr := htonl (ConnVar.Addr);
|
||||
ServerAddr.sin_port := htons (ConnVar.Port);
|
||||
if fpBind (ListenSocket, @ServerAddr, Sizeof (ServerAddr)) <> -1 then begin
|
||||
if fpListen (ListenSocket, 1) <> -1 then begin
|
||||
ConnVar.Answer := false;
|
||||
Listening := true;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
//Listen and answer
|
||||
if ModemConn.Answer then if Answering = false then begin
|
||||
//Create a socket
|
||||
ListenSocket := fpSocket (AF_INET, SOCK_STREAM, 0);
|
||||
if ListenSocket <> -1 then begin
|
||||
//Listen
|
||||
//Hang
|
||||
if ConnVar.Hang then begin
|
||||
if Mode = Originate then begin
|
||||
if Connected then begin
|
||||
CloseSocket (ServerSocket);
|
||||
Connected := false;
|
||||
end;
|
||||
end
|
||||
else if Mode = Answer then begin
|
||||
if Connected then begin
|
||||
CloseSocket (ClientSocket);
|
||||
Connected := false;
|
||||
end;
|
||||
end;
|
||||
ConnVar.Hang := false;
|
||||
end;
|
||||
//Dial
|
||||
if ConnVar.Dial then if Connected = false then begin
|
||||
//Create a server socket
|
||||
ServerSocket := fpSocket (AF_INET, SOCK_STREAM, 0);
|
||||
if ServerSocket <> -1 then begin
|
||||
//Connect
|
||||
ServerAddr.sin_family := AF_INET;
|
||||
ServerAddr.sin_addr.s_addr := htonl (ModemConn.Addr);
|
||||
ServerAddr.sin_port := htons (ModemConn.Port);
|
||||
if fpBind (ListenSocket, @ServerAddr, Sizeof (ServerAddr)) <> -1 then begin
|
||||
if fpListen (ListenSocket, 1) <> -1 then begin
|
||||
//Answer
|
||||
ClientAddrSize := sizeof (ClientAddr);
|
||||
ClientSocket := fpAccept (ListenSocket, @ClientAddr, @ClientAddrSize) ;
|
||||
if ClientSocket <> -1 then begin
|
||||
ModemConn.Answer := false;
|
||||
Answering := true;
|
||||
end;
|
||||
end;
|
||||
ServerAddr.sin_addr.s_addr := htonl (ConnVar.Addr);
|
||||
ServerAddr.sin_port := htons (ConnVar.Port);
|
||||
if fpConnect (ServerSocket, @ServerAddr, Sizeof (ServerAddr)) <> -1 then begin
|
||||
ConnVar.Dial := false;
|
||||
Connected := true;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
//Save the modem state
|
||||
if FileExists (ExpandFileName ('~/.thingamajig/connection')) then begin
|
||||
try
|
||||
rewrite (ModemState);
|
||||
write (ModemState, ModemConn);
|
||||
close (ModemState);
|
||||
rewrite (ConnFile);
|
||||
write (ConnFile, ConnVar);
|
||||
close (ConnFile);
|
||||
except
|
||||
end;
|
||||
end;
|
||||
|
@ -316,21 +336,44 @@ begin
|
|||
{$endif}
|
||||
{$ifdef modem}
|
||||
//Modem
|
||||
//Data
|
||||
else if W = $fffa then begin
|
||||
{$ifndef fast}
|
||||
wait (33);
|
||||
{$endif}
|
||||
//Connect
|
||||
CallServer;
|
||||
//Check the modem state
|
||||
CheckModem;
|
||||
//Recieve
|
||||
if Calling then begin
|
||||
if fpRecv (ServerSocket, @B, 1, 0) <> 1 then B := 0;
|
||||
if Mode = Originate then begin
|
||||
if Connected then begin
|
||||
if fpRecv (ServerSocket, @B, 1, 0) <> 1 then begin
|
||||
CloseSocket (ServerSocket);
|
||||
Connected := false;
|
||||
B := 0;
|
||||
end;
|
||||
end
|
||||
else B := 0;
|
||||
end
|
||||
else if Answering then begin
|
||||
if fpRecv (ClientSocket, @B, 1, 0) <> 1 then B := 0;
|
||||
else if Mode = Answer then begin
|
||||
if Connected then begin
|
||||
if fpRecv (ClientSocket, @B, 1, 0) <> 1 then begin
|
||||
CloseSocket (ClientSocket);
|
||||
Connected := false;
|
||||
B := 0;
|
||||
end;
|
||||
end
|
||||
else B := 0;
|
||||
end
|
||||
else B := 0;
|
||||
end
|
||||
//Status
|
||||
else if W = $fff9 then begin
|
||||
//Check the modem state
|
||||
CheckModem;
|
||||
//Load the status
|
||||
if Connected then B := 1
|
||||
else B := 0;
|
||||
end
|
||||
{$endif}
|
||||
{$ifdef status}
|
||||
//Input status register
|
||||
|
@ -354,20 +397,25 @@ begin
|
|||
B := B or $10;
|
||||
//FFFA: Modem or no input
|
||||
{$ifdef modem}
|
||||
//Connect
|
||||
CallServer;
|
||||
//Check the modem state
|
||||
CheckModem;
|
||||
//Check connection status
|
||||
if Calling then begin
|
||||
fpfd_zero (FileDescs);
|
||||
fpfd_set (ServerSocket, FileDescs);
|
||||
if fpSelect (ServerSocket + 1, @FileDescs, nil, nil, 0) > 0 then B := B or $20;
|
||||
if Mode = Originate then begin
|
||||
if Connected then begin
|
||||
fpfd_zero (FileDescs);
|
||||
fpfd_set (ServerSocket, FileDescs);
|
||||
if fpSelect (ServerSocket + 1, @FileDescs, nil, nil, 0) > 0 then B := B or $20;
|
||||
end
|
||||
else B := B or $20;
|
||||
end
|
||||
else if Answering then begin
|
||||
fpfd_zero (FileDescs);
|
||||
fpfd_set (ClientSocket, FileDescs);
|
||||
if fpSelect (ClientSocket + 1, @FileDescs, nil, nil, 0) > 0 then B := B or $20;
|
||||
end
|
||||
else B := B or $20;
|
||||
else if Mode = Answer then begin
|
||||
if Connected then begin
|
||||
fpfd_zero (FileDescs);
|
||||
fpfd_set (ClientSocket, FileDescs);
|
||||
if fpSelect (ClientSocket + 1, @FileDescs, nil, nil, 0) > 0 then B := B or $20;
|
||||
end
|
||||
else B := B or $20;
|
||||
end;
|
||||
{$endif}
|
||||
{$ifndef modem}
|
||||
B := B or $20;
|
||||
|
@ -717,15 +765,56 @@ begin
|
|||
{$endif}
|
||||
{$ifdef modem}
|
||||
//Modem
|
||||
//Data
|
||||
else if W = $fffa then begin
|
||||
{$ifndef fast}
|
||||
wait (33);
|
||||
{$endif}
|
||||
//Connect
|
||||
CallServer;
|
||||
//Check the modem state
|
||||
CheckModem;
|
||||
//Send
|
||||
if Calling then fpSend (ServerSocket, @B, 1, 0)
|
||||
else if Answering then fpSend (ClientSocket, @B, 1, 0);
|
||||
if Mode = Originate then begin
|
||||
if Connected then begin
|
||||
if fpSend (ServerSocket, @B, 1, 0) <> 1 then begin
|
||||
CloseSocket (ServerSocket);
|
||||
Connected := false;
|
||||
end;
|
||||
end;
|
||||
end
|
||||
else if Mode = Answer then begin
|
||||
if Connected then begin
|
||||
if fpSend (ClientSocket, @B, 1, 0) <> 1 then begin
|
||||
CloseSocket (ClientSocket);
|
||||
Connected := false;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end
|
||||
//Status
|
||||
else if W = $fff9 then begin
|
||||
//Check the modem state
|
||||
CheckModem;
|
||||
//Change the status
|
||||
if Mode = Originate then begin
|
||||
if Connected then if (B and 1) = 0 then begin
|
||||
CloseSocket (ServerSocket);
|
||||
Connected := false;
|
||||
end;
|
||||
end
|
||||
else if Mode = Answer then begin
|
||||
if Connected then begin
|
||||
CloseSocket (ClientSocket);
|
||||
Connected := false;
|
||||
end;
|
||||
if Listening then if (B and 1) = 1 then begin
|
||||
//Connect
|
||||
ClientAddrSize := sizeof (ClientAddr);
|
||||
ClientSocket := fpAccept (ListenSocket, @ClientAddr, @ClientAddrSize) ;
|
||||
if ClientSocket <> -1 then begin
|
||||
Connected := true;
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
end
|
||||
{$endif}
|
||||
//Regular store
|
||||
|
@ -780,8 +869,9 @@ begin
|
|||
|
||||
{$ifdef modem}
|
||||
//Initialise the modem
|
||||
Calling := false;
|
||||
Answering := false;
|
||||
Mode := Originate;
|
||||
Listening := false;
|
||||
Connected := false;
|
||||
//Initialise the SIGPIPE handler
|
||||
new (SigPipeHandler);
|
||||
SigPipeHandler^.sa_Handler := SigActionHandler (@DoSig);
|
||||
|
@ -957,8 +1047,8 @@ begin
|
|||
|
||||
{$ifdef modem}
|
||||
//Disconnect the modem
|
||||
if Calling then CloseSocket (ServerSocket)
|
||||
else if Answering then begin
|
||||
if Mode = Originate then if Connected then CloseSocket (ServerSocket);
|
||||
if Mode = Answer then if Connected then begin
|
||||
CloseSocket (ClientSocket);
|
||||
CloseSocket (ListenSocket);
|
||||
end;
|
||||
|
|
100
modemctl.pas
100
modemctl.pas
|
@ -7,98 +7,110 @@ uses SysUtils, StrUtils, Sockets;
|
|||
type
|
||||
//Connection state
|
||||
Connection = record
|
||||
Call: boolean;
|
||||
Originate: boolean;
|
||||
Answer: boolean;
|
||||
Dial: boolean;
|
||||
Addr: longword;
|
||||
Port: word;
|
||||
Hang: boolean;
|
||||
end;
|
||||
|
||||
var
|
||||
ModemConn: Connection; //State of the modem
|
||||
State: file of Connection; //File storing the state of the modem
|
||||
ConnVar: Connection; //State of the modem
|
||||
ConnFile: 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 ParamStr (1) = '-a' then begin
|
||||
if ParamCount <> 2 then begin
|
||||
writeln ('Usage: modemctl [-c address:port]/[-a address:port]/-h');
|
||||
writeln ('Usage: modemctl -o/[-a address:port]/[-d address:port]/-h');
|
||||
halt (1);
|
||||
end;
|
||||
end
|
||||
else if ParamStr (1) = '-a' then begin
|
||||
else if ParamStr (1) = '-d' then begin
|
||||
if ParamCount <> 2 then begin
|
||||
writeln ('Usage: modemctl [-c address:port]/[-a address:port]/-h');
|
||||
writeln ('Usage: modemctl -o/[-a address:port]/[-d address:port]/-h');
|
||||
halt (1);
|
||||
end;
|
||||
end
|
||||
else begin
|
||||
if ParamCount > 1 then begin
|
||||
writeln ('Usage: modemctl [-c address:port]/[-a address:port]/-h');
|
||||
writeln ('Usage: modemctl -o/[-a address:port]/[-d address:port]/-h');
|
||||
halt (1);
|
||||
end;
|
||||
end;
|
||||
|
||||
//Assign the state file
|
||||
assign (State, ExpandFileName ('~/.thingamajig/connection'));
|
||||
assign (ConnFile, ExpandFileName ('~/.thingamajig/connection'));
|
||||
|
||||
//Set the connection
|
||||
if ParamStr (1) = '-c' then begin
|
||||
ModemConn.Call := true;
|
||||
ModemConn.Answer := false;
|
||||
try
|
||||
Addr := StrToHostAddr (ExtractDelimited (1, ParamStr (2), [':']));
|
||||
ModemConn.Addr := Addr.s_addr;
|
||||
except
|
||||
writeln ('Usage: modemctl [-c address:port]/[-a address:port]/-h');
|
||||
halt (1);
|
||||
end;
|
||||
try
|
||||
ModemConn.Port := StrToInt (ExtractDelimited (2, ParamStr (2), [':']));
|
||||
except
|
||||
writeln ('Usage: modemctl [-c address:port]/[-a address:port]/-h');
|
||||
halt (1);
|
||||
end;
|
||||
ModemConn.Hang := false;
|
||||
end
|
||||
if ParamStr (1) = '-o' then begin
|
||||
ConnVar.Originate := true;
|
||||
ConnVar.Answer := false;
|
||||
ConnVar.Dial := false;
|
||||
ConnVar.Addr := 0;
|
||||
ConnVar.Port := 0;
|
||||
ConnVar.Hang := false;
|
||||
end
|
||||
else if ParamStr (1) = '-a' then begin
|
||||
ModemConn.Call := false;
|
||||
ModemConn.Answer := true;
|
||||
ConnVar.Originate := false;
|
||||
ConnVar.Answer := true;
|
||||
ConnVar.Dial := false;
|
||||
try
|
||||
Addr := StrToHostAddr (ExtractDelimited (1, ParamStr (2), [':']));
|
||||
ModemConn.Addr := Addr.s_addr;
|
||||
ConnVar.Addr := Addr.s_addr;
|
||||
except
|
||||
writeln ('Usage: modemctl [-c address:port]/[-a address:port]/-h');
|
||||
writeln ('Usage: modemctl -o/[-a address:port]/[-d address:port]/-h');
|
||||
halt (1);
|
||||
end;
|
||||
try
|
||||
ModemConn.Port := StrToInt (ExtractDelimited (2, ParamStr (2), [':']));
|
||||
ConnVar.Port := StrToInt (ExtractDelimited (2, ParamStr (2), [':']));
|
||||
except
|
||||
writeln ('Usage: modemctl [-c address:port]/[-a address:port]/-h');
|
||||
writeln ('Usage: modemctl -o/[-a address:port]/[-d address:port]/-h');
|
||||
halt (1);
|
||||
end;
|
||||
ModemConn.Hang := false;
|
||||
ModemConn.Hang := false;
|
||||
ConnVar.Hang := false;
|
||||
ConnVar.Hang := false;
|
||||
end
|
||||
else if ParamStr (1) = '-d' then begin
|
||||
ConnVar.Originate := false;
|
||||
ConnVar.Answer := false;
|
||||
ConnVar.Dial := true;
|
||||
try
|
||||
Addr := StrToHostAddr (ExtractDelimited (1, ParamStr (2), [':']));
|
||||
ConnVar.Addr := Addr.s_addr;
|
||||
except
|
||||
writeln ('Usage: modemctl -o/[-a address:port]/[-d address:port]/-h');
|
||||
halt (1);
|
||||
end;
|
||||
try
|
||||
ConnVar.Port := StrToInt (ExtractDelimited (2, ParamStr (2), [':']));
|
||||
except
|
||||
writeln ('Usage: modemctl -o/[-a address:port]/[-d address:port]/-h');
|
||||
halt (1);
|
||||
end;
|
||||
ConnVar.Hang := false;
|
||||
end
|
||||
else if ParamStr (1) = '-h' then begin
|
||||
ModemConn.Call := false;
|
||||
ModemConn.Answer := false;
|
||||
ModemConn.Addr := 0;
|
||||
ModemConn.Port := 0;
|
||||
ModemConn.Hang := true;
|
||||
ConnVar.Originate := false;
|
||||
ConnVar.Answer := false;
|
||||
ConnVar.Dial := false;
|
||||
ConnVar.Addr := 0;
|
||||
ConnVar.Port := 0;
|
||||
ConnVar.Hang := true;
|
||||
end
|
||||
else begin
|
||||
writeln ('Usage: modemctl [-c address:port]/[-a address:port]/-h');
|
||||
writeln ('Usage: modemctl -o/[-a address:port]/[-d address:port]/-h');
|
||||
halt (1);
|
||||
end;
|
||||
|
||||
//Write the state
|
||||
try
|
||||
rewrite (State);
|
||||
write (State, ModemConn);
|
||||
close (State);
|
||||
rewrite (ConnFile);
|
||||
write (ConnFile, ConnVar);
|
||||
close (ConnFile);
|
||||
except
|
||||
writeln ('Error: could not set the connection');
|
||||
end;
|
||||
|
|
50
readme.md
50
readme.md
|
@ -98,7 +98,7 @@ Usage:
|
|||
* emulator (-v) program (2> verbose_output)
|
||||
* tapectl (-r tape) (-p tape)
|
||||
* floppyctl (-0 disc) (-1 disc)
|
||||
* modemctl [-c address:port]/[-a address:port]/-h
|
||||
* modemctl -o/[-a address:port]/[-d address:port]/-h
|
||||
|
||||
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
|
||||
|
@ -118,25 +118,29 @@ standard uses. The backspace and delete keys input their respective
|
|||
characters and non-character keys null.
|
||||
|
||||
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)
|
||||
8-bit paper tape reader and punch, an emulated two-drive 8" floppy disc
|
||||
system, a roughly 300 b/s modem, and an input status register with the
|
||||
arguments -dprinter, -dtape, -dfloppy, -dmodem, and -dstatus
|
||||
respectively. Full 64 KiB of RAM and all of these options can also be
|
||||
enabled with the argument -dfull. The printer is mapped to address FFFE,
|
||||
the tape reader and punch to FFFD, the disc system to FFFB and FFFC, the
|
||||
modem to FFFA, and the input status register to FFF8. The printer prints
|
||||
into /dev/usb/lp0. The tape files read from and punched to are (re)set
|
||||
using the program tapectl with the arguments -r and -p respectively and
|
||||
the disc files in drives 0 and 1 using the program 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 get ready for answering a call to a loopback or
|
||||
local IP address and port, and -h to hang. Hanging manually is not
|
||||
necessary when making or getting ready to answer a new call, switching
|
||||
between calling and answering, or shutting down the emulator.
|
||||
printer, an emulated high speed 8-bit paper tape reader and punch, an
|
||||
emulated two-drive 8" floppy disc system, a modem, and an input status
|
||||
register with the arguments -dprinter, -dtape, -dfloppy, -dmodem, and
|
||||
-dstatus respectively. Full 64 KiB of RAM and all of these options can
|
||||
also be enabled with the argument -dfull. The printer is mapped to
|
||||
address FFFE, the tape reader and punch to FFFD, the disc system to FFFB
|
||||
and FFFC, the modem to FFF9 and FFFA, and the input status register to
|
||||
FFF8.
|
||||
|
||||
The printer prints into /dev/usb/lp0. The tape files read from and
|
||||
punched to are (re)set using the program tapectl with the arguments -r
|
||||
and -p respectively and the disc files in drives 0 and 1 using the
|
||||
program 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
|
||||
options -o and -a are used to set the originate and answer modes, the
|
||||
latter with the address and port to be listened; -d to dial an address
|
||||
and port to be called; and -h to hang. Dialing when in answer mode
|
||||
automatically switches the modem to originate mode. The modem hangs
|
||||
automatically if the connection is lost or hanged from the other side,
|
||||
if another address and port are dialed, if a mode change command is
|
||||
given, or if the emulator is halted.
|
||||
|
||||
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
|
||||
|
@ -158,6 +162,12 @@ The commands for the disc system are:
|
|||
6: Read a sector from a disc to the buffer.
|
||||
7: Write a sector from the buffer to a disc.
|
||||
|
||||
The modem also uses two ports: status at FFF9 and data at FFFA. Only the
|
||||
least significant bit of the status port is used, indicating whether
|
||||
the modem is connected or not. Unsetting the bit hangs the modem while
|
||||
setting it in answer mode listens for an incoming connection to answer.
|
||||
Setting the bit in originate mode is ignored.
|
||||
|
||||
The input status register can be used to check if a device is ready to
|
||||
be read from. The reserved addresses FFF8-FFFF are mapped to the bits
|
||||
7-0: a set bit means either that the device is ready or that no input
|
||||
|
|
Loading…
Reference in New Issue