From 2c2dd5ea33f2dc18a096f0eba18529b764f1a22c Mon Sep 17 00:00:00 2001 From: Bob Supnik Date: Sun, 17 Nov 2002 15:54:00 -0800 Subject: [PATCH] Notes For V2.10-0 WARNING: V2.10 has reorganized and renamed some of the definition files for the PDP-10, PDP-11, and VAX. Be sure to delete all previous source files before you unpack the Zip archive, or unpack it into a new directory structure. WARNING: V2.10 has a new, more comprehensive save file format. Restoring save files from previous releases will cause 'invalid register' errors and loss of CPU option flags, device enable/ disable flags, unit online/offline flags, and unit writelock flags. WARNING: If you are using Visual Studio .NET through the IDE, be sure to turn off the /Wp64 flag in the project settings, or dozens of spurious errors will be generated. WARNING: Compiling Ethernet support under Windows requires extra steps; see the Ethernet readme file. Ethernet support is currently available only for Windows, Linux, NetBSD, and OpenBSD. 1. New Features 1.1 SCP and Libraries - The VT emulation package has been replaced by the capability to remote the console to a Telnet session. Telnet clients typically have more complete and robust VT100 emulation. - Simulated devices may now have statically allocated buffers, in addition to dynamically allocated buffers or disk-based data stores. - The DO command now takes substitutable arguments (max 9). In command files, %n represents substitutable argument n. - The initial command line is now interpreted as the command name and substitutable arguments for a DO command. This is backward compatible to prior versions. - The initial command line parses switches. -Q is interpreted as quiet mode; informational messages are suppressed. - The HELP command now takes an optional argument. HELP types help on the specified command. - Hooks have been added for implementing GUI-based consoles, as well as simulator-specific command extensions. A few internal data structures and definitions have changed. - Two new routines (tmxr_open_master, tmxr_close_master) have been added to sim_tmxr.c. The calling sequence for sim_accept_conn has been changed in sim_sock.c. - The calling sequence for the VM boot routine has been modified to add an additional parameter. - SAVE now saves, and GET now restores, controller and unit flags. - Library sim_ether.c has been added for Ethernet support. 1.2 VAX - Non-volatile RAM (NVR) can behave either like a memory or like a disk-based peripheral. If unattached, it behaves like memory and is saved and restored by SAVE and RESTORE, respectively. If attached, its contents are loaded from disk by ATTACH and written back to disk at DETACH and EXIT. - SHOW VECTOR displays the device's interrupt vector. A few devices allow the vector to be changed with SET VECTOR=nnn. - SHOW CPU IOSPACE displays the I/O space address map. - The TK50 (TMSCP tape) has been added. - The DEQNA/DELQA (Qbus Ethernet controllers) have been added. - Autoconfiguration support has been added. - The paper tape reader has been removed from vax_stddev.c and now references a common implementation file, dec_pt.h. - Examine and deposit switches now work on all devices, not just the CPU. - Device address conflicts are not detected until simulation starts. 1.3 PDP-11 - SHOW VECTOR displays the device's interrupt vector. Most devices allow the vector to be changed with SET VECTOR=nnn. - SHOW CPU IOSPACE displays the I/O space address map. - The TK50 (TMSCP tape), RK611/RK06/RK07 (cartridge disk), RX211 (double density floppy), and KW11P programmable clock have been added. - The DEQNA/DELQA (Qbus Ethernet controllers) have been added. - Autoconfiguration support has been added. - The paper tape reader has been removed from pdp11_stddev.c and now references a common implementation file, dec_pt.h. - Device bootstraps now use the actual CSR specified by the SET ADDRESS command, rather than just the default CSR. Note that PDP-11 operating systems may NOT support booting with non-standard addresses. - Specifying more than 256KB of memory, or changing the bus configuration, causes all peripherals that are not compatible with the current bus configuration to be disabled. - Device address conflicts are not detected until simulation starts. 1.4 PDP-10 - SHOW VECTOR displays the device's interrupt vector. A few devices allow the vector to be changed with SET VECTOR=nnn. - SHOW CPU IOSPACE displays the I/O space address map. - The RX211 (double density floppy) has been added; it is off by default. - The paper tape now references a common implementation file, dec_pt.h. - Device address conflicts are not detected until simulation starts. 1.5 PDP-1 - DECtape (then known as MicroTape) support has been added. - The line printer and DECtape can be disabled and enabled. 1.6 PDP-8 - The RX28 (double density floppy) has been added as an option to the existing RX8E controller. - SHOW DEVNO displays the device's device number. Most devices allow the device number to be changed with SET DEVNO=nnn. - Device number conflicts are not detected until simulation starts. 1.7 IBM 1620 - The IBM 1620 simulator has been released. 1.8 AltairZ80 - A hard drive has been added for increased storage. - Several bugs have been fixed. 1.9 HP 2100 - The 12845A has been added and made the default line printer (LPT). The 12653A has been renamed LPS and is off by default. It also supports the diagnostic functions needed to run the DCPC and DMS diagnostics. - The 12557A/13210A disk defaults to the 13210A (7900/7901). - The 12559A magtape is off by default. - New CPU options (EAU/NOEAU) enable/disable the extended arithmetic instructions for the 2116. These instructions are standard on the 2100 and 21MX. - New CPU options (MPR/NOMPR) enable/disable memory protect for the 2100 and 21MX. - New CPU options (DMS/NODMS) enable/disable the dynamic mapping instructions for the 21MX. - The 12539 timebase generator autocalibrates. 1.10 Simulated Magtapes - Simulated magtapes recognize end of file and the marker 0xFFFFFFFF as end of medium. Only the TMSCP tape simulator can generate an end of medium marker. - The error handling in simulated magtapes was overhauled to be consistent through all simulators. 1.11 Simulated DECtapes - Added support for RT11 image file format (256 x 16b) to DECtapes. 2. Release Notes 2.1 Bugs Fixed - TS11/TSV05 was not simulating the XS0_MOT bit, causing failures under VMS. In addition, two of the CTL options were coded interchanged. - IBM 1401 tape was not setting a word mark under group mark for load mode reads. This caused the diagnostics to crash. - SCP bugs in ssh_break and set_logon were fixed (found by Dave Hittner). - Numerous bugs in the HP 2100 extended arithmetic, floating point, 21MX, DMS, and IOP instructions were fixed. Bugs were also fixed in the memory protect and DMS functions. The moving head disks (DP, DQ) were revised to simulate the hardware more accurately. Missing functions in DQ (address skip, read address) were added. 2.2 HP 2100 Debugging - The HP 2100 CPU nows runs all of the CPU diagnostics. - The peripherals run most of the peripheral diagnostics. There is still a problem in overlapped seek operation on the disks. See the file hp2100_diag.txt for details. 3. In Progress These simulators are not finished and are available in a separate Zip archive distribution. - Interdata 16b/32b: coded, partially tested. See the file id_diag.txt for details. - SDS 940: coded, partially tested. --- 0readme29.txt | 48 - 0readme_210.txt | 189 ++ 0readme_ethernet.txt | 181 ++ ALTAIR/altair_cpu.c | 39 +- ALTAIR/altair_defs.h | 24 +- ALTAIR/altair_dsk.c | 25 +- ALTAIR/altair_sio.c | 25 + ALTAIR/altair_sys.c | 27 +- AltairZ80/altairZ80.txt | 175 +- AltairZ80/altairZ80_cpu.c | 427 ++- AltairZ80/altairZ80_defs.h | 95 +- AltairZ80/altairZ80_dsk.c | 209 +- AltairZ80/altairZ80_sio.c | 49 +- AltairZ80/altairZ80_sys.c | 66 +- AltairZ80/altairz80_hdsk.c | 384 +++ GRI/gri_cpu.c | 7 +- GRI/gri_defs.h | 10 +- GRI/gri_doc.txt | 30 +- GRI/gri_stddev.c | 57 +- GRI/gri_sys.c | 4 +- H316/h316_cpu.c | 14 +- H316/h316_defs.h | 2 +- H316/h316_doc.txt | 23 +- H316/h316_lp.c | 6 +- H316/h316_stddev.c | 60 +- HP2100/hp2100_cpu.c | 2491 ++++++++------ HP2100/hp2100_defs.h | 52 +- HP2100/hp2100_diag.txt | 148 + HP2100/hp2100_doc.txt | 361 ++- HP2100/hp2100_dp.c | 701 ++-- HP2100/hp2100_dq.c | 705 ++-- HP2100/hp2100_dr.c | 183 +- HP2100/hp2100_fp.c | 349 +- HP2100/hp2100_lps.c | 174 + HP2100/{hp2100_lp.c => hp2100_lpt.c} | 98 +- HP2100/hp2100_ms.c | 626 ++-- HP2100/hp2100_mt.c | 348 +- HP2100/hp2100_mux.c | 203 +- HP2100/hp2100_stddev.c | 355 +- HP2100/hp2100_sys.c | 123 +- I1401/i1401_cd.c | 30 +- I1401/i1401_cpu.c | 8 +- I1401/i1401_defs.h | 2 +- I1401/i1401_doc.txt | 27 +- I1401/i1401_dp.c | 82 +- I1401/i1401_iq.c | 2 + I1401/i1401_lp.c | 4 +- I1401/i1401_mt.c | 156 +- I1401/i1401_sys.c | 4 +- I1620/i1620_cd.c | 403 +++ I1620/i1620_cpu.c | 1861 +++++++++++ I1620/i1620_defs.h | 221 ++ I1620/i1620_doc.txt | 518 +++ I1620/i1620_dp.c | 463 +++ I1620/i1620_fp.c | 388 +++ I1620/i1620_lp.c | 314 ++ I1620/i1620_pt.c | 434 +++ I1620/i1620_sys.c | 491 +++ I1620/i1620_tty.c | 345 ++ Ibm1130/asm1130.c | 4496 ++++++++++++++++++++++++++ Ibm1130/asm1130.mak | 161 + Ibm1130/bindump.c | 752 +++++ Ibm1130/bindump.mak | 161 + Ibm1130/checkdisk.c | 264 ++ Ibm1130/checkdisk.mak | 177 + Ibm1130/diskview.c | 614 ++++ Ibm1130/diskview.mak | 175 + Ibm1130/dmsr2v12phases.h | 171 + Ibm1130/dmsr2v12slet.h | 129 + Ibm1130/ibm1130.mak | 118 +- Ibm1130/ibm1130_conin.h | 11 + Ibm1130/ibm1130_conout.h | 12 +- Ibm1130/ibm1130_cpu.c | 1866 ++++------- Ibm1130/ibm1130_cr.c | 357 +- Ibm1130/ibm1130_defs.h | 123 +- Ibm1130/ibm1130_disk.c | 516 ++- Ibm1130/ibm1130_gdu.c | 1118 +++++++ Ibm1130/ibm1130_gui.c | 1231 +++++++ Ibm1130/ibm1130_prt.c | 773 +++++ Ibm1130/ibm1130_prtwheel.h | 138 +- Ibm1130/ibm1130_stddev.c | 472 +-- Ibm1130/ibm1130_sys.c | 161 +- Ibm1130/makefile | 72 + Ibm1130/mkboot.c | 705 ++++ Ibm1130/mkboot.mak | 161 + Ibm1130/readme1130.txt | 261 +- Ibm1130/readme_update.txt | 35 + Ibm1130/scp.c | 3116 ------------------ Ibm1130/sim_defs.h | 373 --- Ibm1130/viewdeck.c | 144 + Ibm1130/viewdeck.mak | 161 + NOVA/eclipse_cpu.c | 120 +- NOVA/eclipse_tt.c | 15 +- NOVA/nova_clk.c | 9 +- NOVA/nova_cpu.c | 151 +- NOVA/nova_defs.h | 31 +- NOVA/nova_dkp.c | 101 +- NOVA/nova_doc.txt | 20 +- NOVA/nova_dsk.c | 40 +- NOVA/nova_lp.c | 8 +- NOVA/nova_mta.c | 286 +- NOVA/nova_plt.c | 20 +- NOVA/nova_pt.c | 15 +- NOVA/nova_tt.c | 16 +- NOVA/nova_tt1.c | 56 +- PDP1/pdp1_cpu.c | 28 +- PDP1/pdp1_defs.h | 1 + PDP1/pdp1_doc.txt | 74 +- PDP1/pdp1_dt.c | 976 ++++++ PDP1/pdp1_lp.c | 27 +- PDP1/pdp1_stddev.c | 20 +- PDP1/pdp1_sys.c | 22 +- PDP10/pdp10_cpu.c | 23 +- PDP10/pdp10_defs.h | 54 +- PDP10/pdp10_doc.txt | 93 +- PDP10/pdp10_dz.c | 3 + PDP10/pdp10_ksio.c | 345 +- PDP10/pdp10_lp20.c | 46 +- PDP10/pdp10_mdfp.c | 54 +- PDP10/pdp10_pag.c | 3 +- PDP10/pdp10_pt.c | 284 +- PDP10/pdp10_rp.c | 104 +- PDP10/pdp10_sys.c | 4 +- PDP10/pdp10_tim.c | 29 +- PDP10/pdp10_tu.c | 256 +- PDP11/pdp11_cis.c | 93 +- PDP11/pdp11_cpu.c | 99 +- PDP11/pdp11_defs.h | 162 +- PDP11/pdp11_doc.txt | 629 +++- PDP11/pdp11_dz.c | 3 + PDP11/pdp11_fp.c | 82 +- PDP11/pdp11_hk.c | 1141 +++++++ PDP11/pdp11_io.c | 416 ++- PDP11/pdp11_lp.c | 20 +- dec_mscp.h => PDP11/pdp11_mscp.h | 298 +- PDP11/pdp11_pclk.c | 292 ++ sim_vt.h => PDP11/pdp11_pt.c | 30 +- PDP11/pdp11_rk.c | 137 +- PDP11/pdp11_rl.c | 142 +- PDP11/pdp11_rp.c | 207 +- PDP11/pdp11_rq.c | 1696 ++++++---- PDP11/pdp11_rx.c | 202 +- PDP11/pdp11_ry.c | 631 ++++ PDP11/pdp11_stddev.c | 409 +-- PDP11/pdp11_sys.c | 85 +- PDP11/pdp11_tc.c | 369 ++- PDP11/pdp11_tm.c | 300 +- PDP11/pdp11_tq.c | 1984 ++++++++++++ PDP11/pdp11_ts.c | 250 +- dec_uqssp.h => PDP11/pdp11_uqssp.h | 13 +- PDP11/pdp11_xq.c | 1376 ++++++++ PDP11/pdp11_xq.h | 184 ++ PDP18B/pdp18b_cpu.c | 274 +- PDP18B/pdp18b_defs.h | 60 +- PDP18B/pdp18b_doc.txt | 101 +- PDP18B/pdp18b_drm.c | 41 +- PDP18B/pdp18b_dt.c | 407 ++- PDP18B/pdp18b_lp.c | 62 +- PDP18B/pdp18b_mt.c | 243 +- PDP18B/pdp18b_rf.c | 31 +- PDP18B/pdp18b_rp.c | 70 +- PDP18B/pdp18b_stddev.c | 232 +- PDP18B/pdp18b_sys.c | 29 +- PDP18B/pdp18b_tt1.c | 117 +- PDP8/pdp8_clk.c | 25 +- PDP8/pdp8_cpu.c | 222 +- PDP8/pdp8_defs.h | 36 +- PDP8/pdp8_df.c | 59 +- PDP8/pdp8_doc.txt | 117 +- PDP8/pdp8_dt.c | 323 +- PDP8/pdp8_lp.c | 22 +- PDP8/pdp8_mt.c | 296 +- PDP8/pdp8_pt.c | 46 +- PDP8/pdp8_rf.c | 65 +- PDP8/pdp8_rk.c | 86 +- PDP8/pdp8_rl.c | 127 +- PDP8/pdp8_rx.c | 554 +++- PDP8/pdp8_sys.c | 3 +- PDP8/pdp8_tt.c | 81 +- PDP8/pdp8_ttx.c | 96 +- S3/s3_cd.c | 17 +- S3/s3_cpu.c | 10 +- S3/s3_defs.h | 6 +- S3/s3_disk.c | 29 +- S3/s3_lp.c | 16 +- S3/s3_pkb.c | 10 +- S3/s3_sys.c | 28 +- VAX/vax_cpu.c | 37 +- VAX/vax_cpu1.c | 2 +- VAX/vax_defs.h | 7 +- VAX/vax_doc.txt | 262 +- VAX/vax_fpa.c | 178 +- VAX/vax_io.c | 373 ++- VAX/vax_stddev.c | 338 +- VAX/vax_sys.c | 83 +- VAX/vax_sysdev.c | 84 +- VAX/vaxmod_defs.h | 108 +- build_mingw.bat | 31 +- build_mingw_ether.bat | 86 + build_vms.com | 1112 ------- dec_dz.h | 88 +- dec_pt.h | 303 ++ descrip.mms | 1000 ++++++ makefile | 113 +- makefile_ether | 313 ++ scp.c | 1895 ++++++----- scp_tty.c | 125 +- sim_defs.h | 84 +- sim_ether.c | 493 +++ sim_ether.h | 105 + sim_rev.h | 222 +- sim_sock.c | 34 +- sim_sock.h | 36 +- sim_tmxr.c | 291 +- sim_tmxr.h | 11 +- sim_vt.c | 508 --- simh_doc.txt | 471 ++- simh_swre.txt | 27 +- 218 files changed, 44103 insertions(+), 17112 deletions(-) delete mode 100644 0readme29.txt create mode 100644 0readme_210.txt create mode 100644 0readme_ethernet.txt create mode 100644 AltairZ80/altairz80_hdsk.c create mode 100644 HP2100/hp2100_diag.txt create mode 100644 HP2100/hp2100_lps.c rename HP2100/{hp2100_lp.c => hp2100_lpt.c} (59%) create mode 100644 I1620/i1620_cd.c create mode 100644 I1620/i1620_cpu.c create mode 100644 I1620/i1620_defs.h create mode 100644 I1620/i1620_doc.txt create mode 100644 I1620/i1620_dp.c create mode 100644 I1620/i1620_fp.c create mode 100644 I1620/i1620_lp.c create mode 100644 I1620/i1620_pt.c create mode 100644 I1620/i1620_sys.c create mode 100644 I1620/i1620_tty.c create mode 100644 Ibm1130/asm1130.c create mode 100644 Ibm1130/asm1130.mak create mode 100644 Ibm1130/bindump.c create mode 100644 Ibm1130/bindump.mak create mode 100644 Ibm1130/checkdisk.c create mode 100644 Ibm1130/checkdisk.mak create mode 100644 Ibm1130/diskview.c create mode 100644 Ibm1130/diskview.mak create mode 100644 Ibm1130/dmsr2v12phases.h create mode 100644 Ibm1130/dmsr2v12slet.h create mode 100644 Ibm1130/ibm1130_gdu.c create mode 100644 Ibm1130/ibm1130_gui.c create mode 100644 Ibm1130/ibm1130_prt.c create mode 100644 Ibm1130/makefile create mode 100644 Ibm1130/mkboot.c create mode 100644 Ibm1130/mkboot.mak create mode 100644 Ibm1130/readme_update.txt delete mode 100644 Ibm1130/scp.c delete mode 100644 Ibm1130/sim_defs.h create mode 100644 Ibm1130/viewdeck.c create mode 100644 Ibm1130/viewdeck.mak create mode 100644 PDP1/pdp1_dt.c create mode 100644 PDP11/pdp11_hk.c rename dec_mscp.h => PDP11/pdp11_mscp.h (50%) create mode 100644 PDP11/pdp11_pclk.c rename sim_vt.h => PDP11/pdp11_pt.c (69%) create mode 100644 PDP11/pdp11_ry.c create mode 100644 PDP11/pdp11_tq.c rename dec_uqssp.h => PDP11/pdp11_uqssp.h (92%) create mode 100644 PDP11/pdp11_xq.c create mode 100644 PDP11/pdp11_xq.h create mode 100644 build_mingw_ether.bat delete mode 100644 build_vms.com create mode 100644 dec_pt.h create mode 100644 descrip.mms create mode 100644 makefile_ether create mode 100644 sim_ether.c create mode 100644 sim_ether.h delete mode 100644 sim_vt.c diff --git a/0readme29.txt b/0readme29.txt deleted file mode 100644 index 94397546..00000000 --- a/0readme29.txt +++ /dev/null @@ -1,48 +0,0 @@ -Notes For V2.9-11 - -1. New Features - -1.1 GRI-909 - -- This is a new simulator for the GRI-909. -- It has been hand-tested; so far, no software has been discovered. - -1.2 VAX - -- SET CPU CONHALT will cause a HALT instruction to return to the - boot ROM console rather than to SIMH. SET CPU SIMHALT restores - the default behavior. -- BRB/W self at IPL 1F stops the simulator. This is the default - behavior of VMS at exit. - -1.3 PDP-18b - -- ATTACH -A PTR/PTP attaches the reader and punch in ASCII mode. - In ASCII mode, the reader automatically sets the high order bit - of incoming alphabetic data, and the punch clears the high order - bit of outgoing data. - -1.4 SCP - -- DO -V echoes commands from the file as they are executed. -- Under Windows, execution priority is set BELOW_NORMAL when the - simulator is running. - -2. Release Notes - -2.1 Bugs Fixed - -- PDP-11 CPU: fixed updating of MMR0 on a memory management error. -- VAX FPA: changed function names to avoid conflict with C math library. -- 1401 MT: read end of record generates group mark without word mark. -- 1401 DP: fixed address generation and checking. -- SCP: an EXIT within a DO command will cause the simulator to exit. - -3. In Progress - -- Interdata 16b/32b: coded, not tested. -- SDS 940: coded, not tested. -- IBM 1620: coded, not tested. - -If you would like to help with the debugging of the untested simulators, -they can be made available by special request. diff --git a/0readme_210.txt b/0readme_210.txt new file mode 100644 index 00000000..a08980b2 --- /dev/null +++ b/0readme_210.txt @@ -0,0 +1,189 @@ +Notes For V2.10-0 + +WARNING: V2.10 has reorganized and renamed some of the definition +files for the PDP-10, PDP-11, and VAX. Be sure to delete all +previous source files before you unpack the Zip archive, or +unpack it into a new directory structure. + +WARNING: V2.10 has a new, more comprehensive save file format. +Restoring save files from previous releases will cause 'invalid +register' errors and loss of CPU option flags, device enable/ +disable flags, unit online/offline flags, and unit writelock +flags. + +WARNING: If you are using Visual Studio .NET through the IDE, +be sure to turn off the /Wp64 flag in the project settings, or +dozens of spurious errors will be generated. + +WARNING: Compiling Ethernet support under Windows requires +extra steps; see the Ethernet readme file. Ethernet support is +currently available only for Windows, Linux, NetBSD, and OpenBSD. + +1. New Features + +1.1 SCP and Libraries + +- The VT emulation package has been replaced by the capability + to remote the console to a Telnet session. Telnet clients + typically have more complete and robust VT100 emulation. +- Simulated devices may now have statically allocated buffers, + in addition to dynamically allocated buffers or disk-based + data stores. +- The DO command now takes substitutable arguments (max 9). + In command files, %n represents substitutable argument n. +- The initial command line is now interpreted as the command + name and substitutable arguments for a DO command. This is + backward compatible to prior versions. +- The initial command line parses switches. -Q is interpreted + as quiet mode; informational messages are suppressed. +- The HELP command now takes an optional argument. HELP + types help on the specified command. +- Hooks have been added for implementing GUI-based consoles, + as well as simulator-specific command extensions. A few + internal data structures and definitions have changed. +- Two new routines (tmxr_open_master, tmxr_close_master) have + been added to sim_tmxr.c. The calling sequence for + sim_accept_conn has been changed in sim_sock.c. +- The calling sequence for the VM boot routine has been modified + to add an additional parameter. +- SAVE now saves, and GET now restores, controller and unit flags. +- Library sim_ether.c has been added for Ethernet support. + +1.2 VAX + +- Non-volatile RAM (NVR) can behave either like a memory or like + a disk-based peripheral. If unattached, it behaves like memory + and is saved and restored by SAVE and RESTORE, respectively. + If attached, its contents are loaded from disk by ATTACH and + written back to disk at DETACH and EXIT. +- SHOW VECTOR displays the device's interrupt vector. + A few devices allow the vector to be changed with SET + VECTOR=nnn. +- SHOW CPU IOSPACE displays the I/O space address map. +- The TK50 (TMSCP tape) has been added. +- The DEQNA/DELQA (Qbus Ethernet controllers) have been added. +- Autoconfiguration support has been added. +- The paper tape reader has been removed from vax_stddev.c and + now references a common implementation file, dec_pt.h. +- Examine and deposit switches now work on all devices, not just + the CPU. +- Device address conflicts are not detected until simulation starts. + +1.3 PDP-11 + +- SHOW VECTOR displays the device's interrupt vector. + Most devices allow the vector to be changed with SET + VECTOR=nnn. +- SHOW CPU IOSPACE displays the I/O space address map. +- The TK50 (TMSCP tape), RK611/RK06/RK07 (cartridge disk), + RX211 (double density floppy), and KW11P programmable clock + have been added. +- The DEQNA/DELQA (Qbus Ethernet controllers) have been added. +- Autoconfiguration support has been added. +- The paper tape reader has been removed from pdp11_stddev.c and + now references a common implementation file, dec_pt.h. +- Device bootstraps now use the actual CSR specified by the + SET ADDRESS command, rather than just the default CSR. Note + that PDP-11 operating systems may NOT support booting with + non-standard addresses. +- Specifying more than 256KB of memory, or changing the bus + configuration, causes all peripherals that are not compatible + with the current bus configuration to be disabled. +- Device address conflicts are not detected until simulation starts. + +1.4 PDP-10 + +- SHOW VECTOR displays the device's interrupt vector. + A few devices allow the vector to be changed with SET + VECTOR=nnn. +- SHOW CPU IOSPACE displays the I/O space address map. +- The RX211 (double density floppy) has been added; it is off + by default. +- The paper tape now references a common implementation file, + dec_pt.h. +- Device address conflicts are not detected until simulation starts. + +1.5 PDP-1 + +- DECtape (then known as MicroTape) support has been added. +- The line printer and DECtape can be disabled and enabled. + +1.6 PDP-8 + +- The RX28 (double density floppy) has been added as an option to + the existing RX8E controller. +- SHOW DEVNO displays the device's device number. Most + devices allow the device number to be changed with SET + DEVNO=nnn. +- Device number conflicts are not detected until simulation starts. + +1.7 IBM 1620 + +- The IBM 1620 simulator has been released. + +1.8 AltairZ80 + +- A hard drive has been added for increased storage. +- Several bugs have been fixed. + +1.9 HP 2100 + +- The 12845A has been added and made the default line printer (LPT). + The 12653A has been renamed LPS and is off by default. It also + supports the diagnostic functions needed to run the DCPC and DMS + diagnostics. +- The 12557A/13210A disk defaults to the 13210A (7900/7901). +- The 12559A magtape is off by default. +- New CPU options (EAU/NOEAU) enable/disable the extended arithmetic + instructions for the 2116. These instructions are standard on + the 2100 and 21MX. +- New CPU options (MPR/NOMPR) enable/disable memory protect for the + 2100 and 21MX. +- New CPU options (DMS/NODMS) enable/disable the dynamic mapping + instructions for the 21MX. +- The 12539 timebase generator autocalibrates. + +1.10 Simulated Magtapes + +- Simulated magtapes recognize end of file and the marker + 0xFFFFFFFF as end of medium. Only the TMSCP tape simulator + can generate an end of medium marker. +- The error handling in simulated magtapes was overhauled to be + consistent through all simulators. + +1.11 Simulated DECtapes + +- Added support for RT11 image file format (256 x 16b) to DECtapes. + +2. Release Notes + +2.1 Bugs Fixed + +- TS11/TSV05 was not simulating the XS0_MOT bit, causing failures + under VMS. In addition, two of the CTL options were coded + interchanged. +- IBM 1401 tape was not setting a word mark under group mark for + load mode reads. This caused the diagnostics to crash. +- SCP bugs in ssh_break and set_logon were fixed (found by Dave + Hittner). +- Numerous bugs in the HP 2100 extended arithmetic, floating point, + 21MX, DMS, and IOP instructions were fixed. Bugs were also fixed + in the memory protect and DMS functions. The moving head disks + (DP, DQ) were revised to simulate the hardware more accurately. + Missing functions in DQ (address skip, read address) were added. + +2.2 HP 2100 Debugging + +- The HP 2100 CPU nows runs all of the CPU diagnostics. +- The peripherals run most of the peripheral diagnostics. There + is still a problem in overlapped seek operation on the disks. + See the file hp2100_diag.txt for details. + +3. In Progress + +These simulators are not finished and are available in a separate +Zip archive distribution. + +- Interdata 16b/32b: coded, partially tested. See the file + id_diag.txt for details. +- SDS 940: coded, partially tested. diff --git a/0readme_ethernet.txt b/0readme_ethernet.txt new file mode 100644 index 00000000..0dfc0a98 --- /dev/null +++ b/0readme_ethernet.txt @@ -0,0 +1,181 @@ +This file contains information about the XQ/SIM_ETHER package. + +------------------------------------------------------------------------------- + +GOLD Changes: (08-Nov-02) + 1. Added USE_NETWORK conditional to Sim_Ether + 2. Fixed behaviour of SHOW XQ ETH if no devices exist + 3. Added OpenBSD support to Sim_Ether (courtesy of Federico Schwindt) + 4. Added ethX detection simplification (from Megan Gentry) + +------------------------------------------------------------------------------- + +BETA 5 Changes: (23-Oct-02) + 1. Added all_multicast and promiscuous mode support + 2. Finished DEQNA emulation + 3. Verified LAT functionality + 4. Added NXM (Non-eXistant Memory) protection (suggested by Robert Supnik) + 5. Added NetBSD support to Sim_Ether (courtesy of Jason Thorpe) + 6. Fixed write buffer overflow bug (discovered by Jason Thorpe) + 7. Fixed unattached device behavior (discovered by Patrick Caulfield) + 8. Extensive rewrite of this README + 9. Debugged sanity timer + +------------------------------------------------------------------------------- + +BETA 4 Changes: (16-Oct-02) + 1. Added stub support for all_multicast and promiscuous modes + 2. Integrated with SIMH v2.10-0b1 + 3. Added VAX network bootstrap support + 4. Added SET/SHOW XQ TYPE and SANITY commands + 5. Added stub support for DEQNA mode + +------------------------------------------------------------------------------- + +BETA 3 Changes: (10-Oct-02) + 1. Fixed off-by-one bug in setup address processing + 2. Added rejection of multicast addresses to SET XQ MAC + 3. Added linux support to Sim_Ether (courtesy of Patrick Caulfield) + +------------------------------------------------------------------------------- + +BETA 2 Changes: (08-Oct-02) + 1. Integrated with SIMH v2.10-0p4 + 2. Added floating vectors; this also fixes pdp11 emulation problem + 3. Cleaned up codebase; 100% of packet driver code moved to Sim_Ether + 4. Verified TCP/IP functionality + 5. Added Copyrights + +------------------------------------------------------------------------------- + +BETA 1 Changes: (03-Oct-02) + 1. Moved most of packet driver functionality from XQ to Sim_Ether + 2. Verified DECNET functionality + 3. Added SET/SHOW MAC command + 4. Added SHOW ETH command + +------------------------------------------------------------------------------- + +The XQ emulator is a host-independant software emulation of Digital's +DELQA (M7516) and DEQNA (M7504) Q-bus ethernet cards for the SIMH emulator. + +See the last section of this document for XQ usage instructions. + +The XQ emulator uses the Sim_Ether module to execute host-specific ethernet +packet reads and writes, since all operating systems talk to real ethernet +cards/controllers differently. The host-dependant Sim_Ether module currently +supports Windows, Linux, and NetBSD. + +Currently, the Sim_Ether module sets the selected ethernet card into +promiscuous mode to gather all packets, then filters out the packets that it +doesn't want. This method is somewhat inefficient and will be looked at in +future versions. Packets having the same source MAC address as the +controller are ignored for WinPCAP compatibility (see Windows notes below). + +If your ethernet card is plugged into a switch, the promiscuous mode setting +should not cause much of a problem, since the switch will still filter out +most of the undesirable traffic. You will only see "excessive" traffic if you +are on a hub(repeater) or a direct lan (thickwire/thinwire) segment. + +------------------------------------------------------------------------------- + +Windows notes: + 1. The Windows-specific code uses the WinPCAP 3.0 package from + http://winpcap.polito.it. This package for windows simulates the libpcap + package that is freely available for unix systems. + 2. You must *install* WinPCAP. + 3. Note that WinPCAP DOES NOT support dual CPU environments. + 4. WinPCAP loops packet writes back into the read queue. This causes problems + since the XQ controller is not expecting to read it's own packet. A fix + to the packet read filter was added to reject packets from the current MAC, + but this defeats DECNET's duplicate node number detection scheme. A more + correct fix for WinPCAP will be explored as time allows. + 5. The first time the WinPCAP driver is used, it will be dynamically loaded, + and the user must be an Administrator on the machine to do so. See the + WinPCAP documentation for a static load workaround if needed. + +Building on Windows: + 1. Install WinPCAP 3.0. + 2. Get the required .h files (bittypes.h, devioctl.h, ip6_misc.h, packet32.h, + pcap.h, pcap-stdinc.h) from the WinPCAP 3.0 developer's kit + 3. Get the required .lib files (packet.lib, wpcap.lib) from the WinPCAP 3.0 + developer's kit. If you're using Borland C++, use COFF2OMF to convert + the .lib files into a format that can be used by the compiler. + 4. Define USE_NETWORK if you want the network functionality. + 5. Build it! + +------------------------------------------------------------------------------- + +Linux, NetBSD, and OpenBSD notes: + + 1. You must run SIMH(scp) as root so that the ethernet card can be set into + promiscuous mode by the driver. + + +------------------------------------------------------------------------------- + +THE XQ/SIM_ETHER modules have been successfully tested on a Windows 2000 host, +emulating an OpenVMS 7.2 VAX system with DECNET Phase IV, MultiNet 4.4a, and +LAT 5.3. + +Regression test criteria: + 1. VAX shows device correctly (passed) + 2. VMS boots successfully with new device emulation (passed) + 3. VMS initializes device correctly (passed) + 4. DECNET loads successfully (passed) + 5. DECNET line stays up (passed) + 6. SET HOST x.y:: works from SIMH to real DECNET machine (passed) + 7. SET HOST x.y:: works from real DECNET machine to SIMH (passed) + 8. DECNET copy works from SIMH to real DECNET machine (passed) + 9. DECNET copy works from real DECNET machine to SIMH (passed) +10. MultiNet TCP/IP loads successfully (passed) +11. Multinet TCP/IP initializes device successfully (passed) +12. SET HOST/TELNET x.y.z.w works from SIMH to real VAX IP machine (passed) +13. SET HOST/TELNET x.y.z.w works from real VAX IP machine to SIMH (passed) +14. FTP GET from a real VAX IP machine (passed) +15. LAT loads sucessfully (passed) +16. SET HOST/LAT works from SIMH to real VAX LAT machine (passed) +17. SET HOST/LAT works from real VAX LAT machine to SIMH (passed) + +I have NOT tested the following, but have reports that the following work: + 1. Operation with the PDP-11 emulator (RSX) + 2. Remote booting of NetBSD (via >>> B XQA0) + +I have tested the following, and they do NOT work correctly: + 1. VMS NI Clustering (LAVC) + 2. Remote VAX booting (>>>B XQA0) into a VMScluster; + the remote boot works, but VMS BUGCHECKs when joining the cluster + +------------------------------------------------------------------------------- + +Things planned for future releases: + 1. Loopback packet processing + 2. Full MOP implementation + 3. Identity broadcast, which should occur every 8-10 minutes + 4. Full support for network boot (>> B XQA0) + 5. VMS NI Cluster (LAVC) support + 6. More efficient Sim_Ether module implementation for windows + 7. PDP-11 bootstrap + 8. DESQA support (if someone can get me the user manuals) + 9. DETQA support [DELQA-Turbo] (I have the manual) + +------------------------------------------------------------------------------- + +Things which I need help with: + 1. Porting Sim_Ether packet driver to other platforms, especially VMS. + 2. Information about Remote MOP processing + 3. PDP-11 bootstrap code. + 4. VAX hardware diagnotics image file and docs, to test XQ thoroughly. + 5. Feedback on the ethernet timing clock interval. + 6. Feedback on operation with other VAX OS's. + 7. Feedback on operation of PDP-11 OS's. + +------------------------------------------------------------------------------- + +Please send all patches, questions, feedback, clarifications, and help to: + dhittner AT northropgrumman DOT com + +NOTE: I _have_ corrected my email address!! Sorry about the confusion! + +Thanks, and Enjoy!! +Dave diff --git a/ALTAIR/altair_cpu.c b/ALTAIR/altair_cpu.c index 53502b0b..fc7f0475 100644 --- a/ALTAIR/altair_cpu.c +++ b/ALTAIR/altair_cpu.c @@ -1,8 +1,31 @@ /* altair_cpu.c: MITS Altair Intel 8080 CPU simulator - Copyright (c) 1997, - Charles E. Owen, Jr. - Commercial use prohibited + Copyright (c) 1997, Charles E. Owen + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Charles E. Owen shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Charles E. Owen. + + cpu 8080 CPU + + 08-Oct-02 RMS Tied off spurious compiler warnings The register state for the 8080 CPU is: @@ -247,8 +270,6 @@ REG cpu_reg[] = { { FLDATA (S, S, 16) }, { FLDATA (P, P, 16) }, { FLDATA (INTE, INTE, 16) }, - { FLDATA (Z80, cpu_unit.flags, UNIT_V_CHIP), REG_HRO }, - { FLDATA (OPSTOP, cpu_unit.flags, UNIT_V_OPSTOP), REG_HRO }, { ORDATA (SR, SR, 16) }, { ORDATA (WRU, sim_int_char, 8) }, { NULL } }; @@ -718,7 +739,7 @@ int32 sim_instr (void) } case 017: { /* RRC */ C = 0; - if (A & 0x01 == 1) + if ((A & 0x01) == 1) C |= 0200000; A = (A >> 1) & 0xFF; if (C) @@ -739,7 +760,7 @@ int32 sim_instr (void) case 037: { /* RAR */ DAR = C; C = 0; - if (A & 0x01 == 1) + if ((A & 0x01) == 1) C |= 0200000; A = (A >> 1) & 0xFF; if (DAR) @@ -975,6 +996,7 @@ int32 getreg(int32 reg) default: break; } + return 0; } /* Put a value into an 8080 register from memory */ @@ -1030,6 +1052,7 @@ int32 getpair(int32 reg) default: break; } + return 0; } /* Return the value of a selected register pair, in PUSH @@ -1057,6 +1080,7 @@ int32 getpush(int32 reg) default: break; } + return 0; } @@ -1160,5 +1184,6 @@ int32 nulldev(int32 flag, int32 data) { if (flag == 0) return (0377); + return 0; } diff --git a/ALTAIR/altair_defs.h b/ALTAIR/altair_defs.h index 548249f0..7c43d563 100644 --- a/ALTAIR/altair_defs.h +++ b/ALTAIR/altair_defs.h @@ -1,9 +1,27 @@ /* altair_defs.h: MITS Altair simulator definitions - Copyright (c) 1997, - Charles E Owen - Commercial use prohibited + Copyright (c) 1997, Charles E. Owen + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Charles E. Owen shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Charles E. Owen. */ #include "sim_defs.h" /* simulator defns */ diff --git a/ALTAIR/altair_dsk.c b/ALTAIR/altair_dsk.c index dd1acbc1..57008803 100644 --- a/ALTAIR/altair_dsk.c +++ b/ALTAIR/altair_dsk.c @@ -1,5 +1,28 @@ /* altair_dsk.c: MITS Altair 88-DISK Simulator + Copyright (c) 1997, Charles E. Owen + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Charles E. Owen shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Charles E. Owen. + The 88_DISK is a 8-inch floppy controller which can control up to 16 daisy-chained Pertec FD-400 hard-sectored floppy drives. Each diskette has physically 77 tracks of 32 137-byte sectors @@ -280,7 +303,7 @@ int32 dsk11(int32 io, int32 data) cur_byte[cur_disk] = 0; cur_flags[cur_disk] |= 0x01; /* enter new write data on */ } - + return 0; } /* Disk Data In/Out*/ diff --git a/ALTAIR/altair_sio.c b/ALTAIR/altair_sio.c index 0591b0fe..aa2c45a0 100644 --- a/ALTAIR/altair_sio.c +++ b/ALTAIR/altair_sio.c @@ -1,5 +1,28 @@ /* altair_sio: MITS Altair serial I/O card + Copyright (c) 1997, Charles E. Owen + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Charles E. Owen shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Charles E. Owen. + These functions support a simulated MITS 2SIO interface card. The card had two physical I/O ports which could be connected to any serial I/O device that would connect to a current loop, @@ -187,6 +210,7 @@ int32 sio0d(int32 io, int32 data) } else { sim_putchar(data); } + return 0; } /* Port 2 controls the PTR/PTP devices */ @@ -234,5 +258,6 @@ int32 sio1d(int32 io, int32 data) putc(data, uptr -> fileref); ptp_unit.pos++; } + return 0; } diff --git a/ALTAIR/altair_sys.c b/ALTAIR/altair_sys.c index cfba428b..94d4926a 100644 --- a/ALTAIR/altair_sys.c +++ b/ALTAIR/altair_sys.c @@ -1,15 +1,32 @@ /* altair_sys.c: MITS Altair system interface - (C) Copyright 1997 by Charles E. Owen - Commercial use prohibited + Copyright (c) 1997, Charles E. Owen + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Charles E. Owen shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Charles E. Owen. */ - #include - #include "altair_defs.h" - extern DEVICE cpu_dev; extern DEVICE dsk_dev; extern UNIT cpu_unit; diff --git a/AltairZ80/altairZ80.txt b/AltairZ80/altairZ80.txt index 15edf9cf..7705451b 100644 --- a/AltairZ80/altairZ80.txt +++ b/AltairZ80/altairZ80.txt @@ -4,6 +4,10 @@ Altair 8800 Simulator with Z80 support 0. Revision History Original version of this document written by Charles E Owen +- 9-Oct-2002, Peter Schorn (added support for simulated hard disk) +- 28-Sep-2002, Peter Schorn (number of tracks per disk can be configured) +- 19-Sep-2002, Peter Schorn (added WARNROM feature) +- 31-Aug-2002, Peter Schorn (added extended ROM features suggested by Scott LaBombard) - 4-May-2002, Peter Schorn (added description of MP/M II sample software) - 28-Apr-2002, Peter Schorn (added periodic timer interrupts and three additional consoles) @@ -78,7 +82,7 @@ a minimum of 24K. present and will always boot. SET CPU BANKED Enables the banked memory support. The simulated memory - has four banks with address range 0..'common' (see registers below) + has eight banks with address range 0..'common' (see registers below) and a common area from 'common' to 0xfff which is common to all banks. The currently active bank is determined by register 'bank' (see below). You can only switch to banked memory if the memory @@ -86,18 +90,31 @@ a minimum of 24K. SET CPU NONBANKED Disables banked memory support. - SET CPU ROM Enables the boot EPROM at address 0FF00H and prevents - write access to the locations from 0FF00H to 0FFFFH. This is the - default setting. + SET CPU ROM Enables the ROM from address 'ROMLOW' to 'ROMHIGH' + (see below under CPU Registers) and prevents write access + to these locations. This is the default setting. - SET CPU NOROM Disables the boot EPROM at address 0FF00H and enables - write access to the locations from 0FF00H to 0FFFFH. + SET CPU NOROM Disables the ROM. -The BOOT EPROM card starts at address 0FF00H. Jumping to this address -will boot drive 0 of the floppy controller (CPU must be set to ROM or -equivalent code must be present). If no valid bootable software is -present there the machine crashes. This is historically accurate -behavior. + SET CPU ALTAIRROM Enables the slightly modified but downwards compatible + Altair boot ROM at addresses 0FF00 to 0FFFF. This is the default. + + SET CPU NOALTAIRROM Disables standard Altair ROM behavior. + + SET CPU WARNROM Enables warning messages to be printed when the CPU + attempts to write into ROM or into non-existing memory. Also prints + a warning message if the CPU attempts to read from non-existing + memory. + + SET CPU NOWARNROM Suppreses all warning message of "WARNROM". Note that + some software tries on purpose to write to ROM in order to detect + the available RAM. + +The BOOT EPROM card starts at address 0FF00 if it has been enabled by 'SET +CPU ALTAIRROM'. Jumping to this address will boot drive 0 of the floppy +controller (CPU must be set to ROM or equivalent code must be present). If +no valid bootable software is present there the machine crashes. This is +historically accurate behavior. The real 8080, on receiving a HLT (Halt) instruction, freezes the processor and only an interrupt or CPU hardware reset will restore it. The simulator @@ -105,7 +122,7 @@ is alot nicer, it will halt but send you back to the simulator command line. CPU Registers include the following: - name size comments + Name Size Comment PC 16 The Program Counter AF 16 The accumulator and the flag register @@ -144,6 +161,8 @@ CPU Registers include the following: COMMON 16 The starting address of common memory. Originally set to 0xc000 (note this setting must agree with the value supplied to GENCPM for CP/M 3 system generation) + ROMLOW 16 The starting address of the ROM. Default is 0FF00. + ROMHIGH 16 The final address of the ROM. Default is 0FFFF. 2.2 The Serial I/O Card (2SIO) @@ -213,7 +232,11 @@ source file. The only difference is that the simulated disks may be larger than the original ones: The original disk had 77 tracks while the simulated disks -support up to 254 tracks (only relevant for CP/M). +support up to 254 tracks (only relevant for CP/M). You can change the +number of tracks per disk by setting the appropriate value in TRACKS[..]. +For example "D TRACKS[0] 77" sets the number of tracks for disk 0 to +the original number of 77. The command "D TRACKS[0-7] 77" changes the +highest track number for all disks to 77. For debugging purposes you can set the trace level of some disk I/O functions. To do so the following bits in TRACE (a register of the disk) @@ -242,6 +265,26 @@ For example the command "D TRACE 10" will trace options 2+8 from above. will be allowed. +2.5 The simulated hard disk + + In order to increase the available storage capacity, the simulator +features 8 simulated hard disks with a capacity of 8MB (HDSK0 to HDSK7). +Currently only CP/M supports two hard disks as devices I: and J:. + + For debugging purposes one can set the trace flag by executing the +command "D HDTRACE 1". The default for "HDTRACE" is 0 (no trace). + + The HDSK device can be configured with + + SET HDSK QUIET Do not print warning messages for hard disk + SET HDSK VERBOSE Print warning messages for hard disk + (useful for debugging) + + SET HDSK WRITEENABLED Allow write operations for hard disk + SET HDSK LOCKED Hard disk is locked, i.e. no + write operations will be allowed. + + 3. Sample Software Running an Altair in 1977 you would be running either MITS Disk @@ -282,74 +325,78 @@ R FOO.EXT under CP/M will transfer the file onto the CP/M disk. Transferring a file from the CP/M environment to the SIMH environment is accomplished by W . + If you need more storage space you can use a simulated hard disk on +drives I: and J:. To use do "attach HDSK0 hdi.dsk" and issue the +"XFORMAT I:" resp. "XFORMAT J:" command from CP/M do initialize the disk +to an empty state. + The disk "cpm2.dsk" contains the following files: Name Ext Size Comment ASM .COM 8K ; CP/M assembler -BDOS .MAC 66K ; Basic Disk Operating System assembler source code +BDOS .MAC 68K ; Basic Disk Operating System assembler source code BOOT .COM 1K ; transfer control to boot ROM BOOT .MAC 2K ; source for BOOT.COM BOOTGEN .COM 2K ; put a program on the boot sectors -CBIOSX .MAC 10K ; CP/M 2 BIOS source for Altair +CBIOSX .MAC 48K ; CP/M 2 BIOS source for Altair CCP .MAC 26K ; Console Command Processor assembler source code -COPY .COM 1K ; copy disks +COPY .COM 2K ; copy disks CPMBOOT .COM 12K ; CP/M operating system CREF80 .COM 4K ; cross reference utility -DDT .COM 5K ; 8080 debugger +DDT .COM 6K ; 8080 debugger DDTZ .COM 10K ; Z80 debugger -DIF .COM 3K ; determine differences between two files +DIF .COM 4K ; determine differences between two files DO .COM 2K ; batch processing -DSKBOOT .COM 1K ; code for boot ROM -DSKBOOT .MAC 3K ; source for boot ROM -DUMP .COM 1K ; hex dump a file -ED .COM 7K ; line editor -ELIZA .BAS 9K ; Elisa game in Basic -EX8080 .COM 9K ; exercise 8080 instruction set -EX8080 .MAC 47K ; source for EX8080.COM -EX8080 .SUB 1K ; benchmark execution of EX8080.COM -EXZ80 .COM 9K ; exercise Z80 instruction set -EXZ80 .MAC 47K ; source for EXZ80.COM -EXZ80 .SUB 1K ; benchmark execution of EXZ80.COM +DSKBOOT .MAC 8K ; source for boot ROM +DUMP .COM 2K ; hex dump a file +ED .COM 8K ; line editor +ELIZA .BAS 10K ; Elisa game in Basic +EX8080 .COM 10K ; exercise 8080 instruction set +EX8080 .MAC 48K ; source for EX8080.COM +EX8080 .SUB 2K ; benchmark execution of EX8080.COM +EXZ80 .COM 10K ; exercise Z80 instruction set +EXZ80 .MAC 48K ; source for EXZ80.COM +EXZ80 .SUB 2K ; benchmark execution of EXZ80.COM FORMAT .COM 2K ; format disks GO .COM 0K ; start the currently loaded program at 100H -L80 .COM 11K ; Microsoft linker +HDSKBOOT.MAC 6K ; boot code for hard disk +L80 .COM 12K ; Microsoft linker LADDER .COM 40K ; game -LADDER .DAT 1K ; high score file for LADDER.COM +LADDER .DAT 2K ; high score file for LADDER.COM LIB80 .COM 6K ; library utility LOAD .COM 2K ; load hex files -LS .COM 3K ; directory utility +LS .COM 4K ; directory utility LU .COM 20K ; library utility M80 .COM 20K ; Microsoft macro assembler MBASIC .COM 24K ; Microsoft Basic interpreter -MC .SUB 1K ; assemble and link an assmbler program -MCC .SUB 1K ; read, assemble and link an assmbler program +MC .SUB 2K ; assemble and link an assembler program +MCC .SUB 2K ; read, assemble and link an assembler program +MCCL .SUB 2K ; assemble, link and produce listing +MEMCFG .LIB 2K ; defines the memory configuration MOVER .MAC 2K ; moves operating system in place OTHELLO .COM 12K ; Othello (Reversi) game PIP .COM 8K ; Peripheral Interchange Program -R .COM 3K ; read files from SIMH environment -RSETSIMH.COM 1K ; reset SIMH interface -RSETSIMH.MAC 1K ; assembler source for RSETSIMH.COM +R .COM 4K ; read files from SIMH environment +RSETSIMH.COM 2K ; reset SIMH interface +RSETSIMH.MAC 2K ; assembler source for RSETSIMH.COM SHOWSEC .COM 3K ; show sectors on a disk SID .COM 8K ; debugger for 8080 STAT .COM 6K ; provide information about currently logged disks SURVEY .COM 2K ; system survey -SURVEY .MAC 15K ; assembler source for SURVEY.COM +SURVEY .MAC 16K ; assembler source for SURVEY.COM SYSCOPY .COM 2K ; copy system tracks between disks -SYSCPM2 .SUB 1K ; create CP/M 2 on drive A: -TSHOW .COM 1K ; show split time -TSHOW .MAC 1K ; assembler source for TSHOW.COM -TSTART .COM 1K ; create timer and start it -TSTART .MAC 1K ; assembler source for TSTART.COM -TSTOP .COM 1K ; show final time and stop timer -TSTOP .MAC 1K ; assembler source for TSTOP.COM -UNCR .COM 7K ; un-crunch utility +SYSCPM2 .SUB 2K ; create CP/M 2 on drive A: +TIMER .COM 2K ; perform various timer operations +TIMER .MAC 2K ; source code for TIMER.COM +UNCR .COM 8K ; un-crunch utility UNERA .COM 2K ; un-erase a file UNERA .MAC 16K ; source for UNERA.COM USQ .COM 2K ; un-squeeze utility -W .COM 3K ; write files to SIMH environment -WM .COM 11K ; word master screen editor +W .COM 4K ; write files to SIMH environment +WM .COM 12K ; word master screen editor WM .HLP 3K ; help file for WM.COM WORM .COM 4K ; worm game for VT100 terminal -XSUB .COM 1K ; support for DO.COM +XFORMAT .COM 2K ; initialise a drive (floppy or hard disk) +XSUB .COM 2K ; support for DO.COM ZSID .COM 10K ; debugger for Z80 ZTRAN4 .COM 4K ; translate 8080 mnemonics into Z80 equivalents @@ -457,6 +504,7 @@ version supports four terminals available via Telnet. To boot: sim> set cpu rom sim> set cpu banked sim> attach sio 23 + sim> d common b000 sim> boot dsk Now connect a Telnet session to the simulator and type "MPM" at the "A>" @@ -622,6 +670,8 @@ TERMBDOS.SPL 2K ; terminal interface to CP/M for PROLOGZ, SPL source UTIL .SPL 18K ; utility functions for PROLOGZ, SPL source WRITE .COM 4K WRITE .SPL 8K ; SPL source for W.COM +XFORMAT .COM 2K +XFORMAT .SPL 6K ; SPL source for XFORMAT.COM 3.6 MITS Disk Extended BASIC Version 4.1 @@ -658,6 +708,8 @@ ran under. To boot: irrelevant. A short attempted tour will reveal it to be a dog, far inferior to CP/M. To boot: + sim> d tracks[0-7] 77 ;set to Altair settings + sim> set cpu altairrom sim> attach dsk altdos.dsk sim> set sio upper sim> go ff00 @@ -723,7 +775,7 @@ is to get the Switch Register right). 3.10 Altair Basic 4.0 - Execute the following commands to run Altair Extended Basic. + Execute the following commands to run Altair Extended Basic: sim> set sio upper ;Extended Basic does not like lower case letters as input sim> set sio ansi ;Extended Basic produces 8-bit output, strip to seven bits @@ -742,6 +794,29 @@ is to get the Switch Register right). OK +3.11 Altair Disk Extended Basic Version 300-5-C + This version of Basic was provided by Scott LaBombard. To execute use the + following commands: + + sim> d tracks[0-7] 77 ;set to Altair settings + sim> at dsk extbas5.dsk + sim> g 0 + + MEMORY SIZE? [return] + LINEPRINTER? [C] + HIGHEST DISK NUMBER? [0] + HOW MANY FILES? [3] + HOW MANY RANDOM FILES? [3] + + 42082 BYTES FREE + + ALTAIR DISK EXTENDED BASIC + VERSION 300-5-C [01NOV78] + COPYRIGHT 1978 BY MITS INC. + + OK + + 4. Special simulator features In addition to the regular SIMH features such as PC queue, breakpoints etc., this simulator supports memory access breakpoints. A memory access diff --git a/AltairZ80/altairZ80_cpu.c b/AltairZ80/altairZ80_cpu.c index f1684dc2..2bae2eff 100644 --- a/AltairZ80/altairZ80_cpu.c +++ b/AltairZ80/altairZ80_cpu.c @@ -1,27 +1,46 @@ /* altairz80_cpu.c: MITS Altair CPU (8080 and Z80) - Written by Peter Schorn, 2001-2002 - Based on work by Charles E Owen ((c) 1997 - Commercial use prohibited) - Code for Z80 CPU from Frank D. Cringle ((c) 1995 under GNU license) + + Copyright (c) 2002, Peter Schorn + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Peter Schorn shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Peter Schorn. + + Based on work by Charles E Owen (c) 1997 + Code for Z80 CPU from Frank D. Cringle ((c) 1995 under GNU license) */ #include -#include "altairZ80_defs.h" +#include "altairz80_defs.h" -#define PCQ_SIZE 64 /* must be 2**n */ +#define PCQ_SIZE 64 /* must be 2**n */ #define PCQ_MASK (PCQ_SIZE - 1) #define PCQ_ENTRY(PC) pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC -#define MEMSIZE (cpu_unit.capac) /* actual memory size */ -#define KB 1024 /* kilo byte */ -#define bootrom_origin 0xff00 /* start address of boot rom */ - /* Simulator stop codes */ -#define STOP_HALT 2 /* HALT */ -#define STOP_IBKPT 3 /* breakpoint (program counter) */ -#define STOP_MEM 4 /* breakpoint (memory access) */ -#define STOP_OPCODE 5 /* unknown 8080 or Z80 instruction */ +#define STOP_HALT 2 /* HALT */ +#define STOP_IBKPT 3 /* breakpoint (program counter) */ +#define STOP_MEM 4 /* breakpoint (memory access) */ +#define STOP_OPCODE 5 /* unknown 8080 or Z80 instruction */ -/*-------------------------------- definitions for memory space ------------------*/ +/*-------------------------------- definitions for memory space --------------------*/ uint8 M[MAXMEMSIZE][MAXBANKS]; /* RAM which is present */ @@ -55,12 +74,12 @@ uint16 IFF; #define TSTFLAG(f) ((AF & FLAG_ ## f) != 0) #define ldig(x) ((x) & 0xf) -#define hdig(x) (((x)>>4)&0xf) -#define lreg(x) ((x)&0xff) -#define hreg(x) (((x)>>8)&0xff) +#define hdig(x) (((x) >> 4) & 0xf) +#define lreg(x) ((x) & 0xff) +#define hreg(x) (((x) >> 8) & 0xff) -#define Setlreg(x, v) x = (((x)&0xff00) | ((v)&0xff)) -#define Sethreg(x, v) x = (((x)&0xff) | (((v)&0xff) << 8)) +#define Setlreg(x, v) x = (((x) & 0xff00) | ((v) & 0xff)) +#define Sethreg(x, v) x = (((x) & 0xff) | (((v) & 0xff) << 8)) /* SetPV and SetPV2 are used to provide correct parity flag semantics for the 8080 in cases where the Z80 uses the overflow flag @@ -70,7 +89,7 @@ uint16 IFF; /* checkCPU8080 must be invoked whenever a Z80 only instruction is executed */ #define checkCPU8080 \ - if ((cpu_unit.flags & UNIT_CHIP == 0) && (cpu_unit.flags & UNIT_OPSTOP)) { \ + if (((cpu_unit.flags & UNIT_CHIP) == 0) && (cpu_unit.flags & UNIT_OPSTOP)) { \ reason = STOP_OPCODE; \ goto end_decode; \ } @@ -101,7 +120,7 @@ static const uint8 partab[256] = { 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, }; -#define parity(x) partab[(x)&0xff] +#define parity(x) partab[(x) & 0xff] #define POP(x) do { \ register uint32 y = RAM_pp(SP); \ @@ -132,11 +151,13 @@ static const uint8 partab[256] = { } \ } -int32 saved_PC = 0; /* program counter */ -int32 SR = 0; /* switch register */ -int32 PCX; /* External view of PC */ -int32 bankSelect = 0; /* determines selected memory bank */ -uint32 common = 0xc000; /* addresses >= 'common' are in common memory */ +int32 saved_PC = 0; /* program counter */ +int32 SR = 0; /* switch register */ +int32 PCX; /* External view of PC */ +int32 bankSelect = 0; /* determines selected memory bank */ +uint32 common = 0xc000; /* addresses >= 'common' are in common memory */ +uint32 ROMLow = defaultROMLow; /* lowest address of ROM */ +uint32 ROMHigh = defaultROMHigh; /* highest address of ROM */ extern int32 sim_int_char; extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ @@ -148,10 +169,13 @@ extern int32 dsk10 (int32 port, int32 io, int32 data); extern int32 dsk11 (int32 port, int32 io, int32 data); extern int32 dsk12 (int32 port, int32 io, int32 data); extern int32 nulldev (int32 port, int32 io, int32 data); +extern int32 hdsk_io (int32 port, int32 io, int32 data); extern int32 simh_dev (int32 port, int32 io, int32 data); extern int32 sr_dev (int32 port, int32 io, int32 data); extern int32 bootrom[bootrom_size]; extern char memoryAccessMessage[]; +extern char messageBuffer[]; +extern void printMessage(void); /* function prototypes */ t_stat cpu_ex(t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); @@ -160,22 +184,32 @@ t_stat cpu_reset(DEVICE *dptr); t_stat cpu_set_size(UNIT *uptr, int32 val, char *cptr, void *desc); t_stat cpu_set_banked(UNIT *uptr, int32 value, char *cptr, void *desc); t_stat cpu_set_rom(UNIT *uptr, int32 value, char *cptr, void *desc); +t_stat cpu_set_norom(UNIT *uptr, int32 value, char *cptr, void *desc); +t_stat cpu_set_altairrom(UNIT *uptr, int32 value, char *cptr, void *desc); uint32 in(uint32 Port); void out(uint32 Port, uint32 Value); uint8 GetBYTE(register uint32 Addr); void PutBYTE(register uint32 Addr, register uint32 Value); void PutBYTEForced(register uint32 Addr, register uint32 Value); +int32 addressIsInROM(uint32 Addr); +int32 addressExists(uint32 Addr); uint16 GetWORD(register uint32 a); void PutWORD(register uint32 a, register uint32 v); -int32 sim_instr (void); -void install_bootrom(void); -void clear_memory(int32 starting); +int32 sim_instr(void); +int32 install_bootrom(void); +void reset_memory(void); t_bool sim_brk_lookup (t_addr bloc, int32 btyp); void prepareMemoryAccessMessage(t_addr loc); +void checkROMBoundaries(void); +void warnUnsuccessfulWriteAttempt(uint32 Addr); +uint8 warnUnsuccessfulReadAttempt(uint32 Addr); +t_stat cpu_set_warnrom(UNIT *uptr, int32 value, char *cptr, void *desc); +void protect(int32 l, int32 h); +void resetCell(int32 address, int32 bank); +#ifndef NO_INLINE /* in case of using inline we need to ensure that the GetBYTE and PutBYTE are accessible externally */ -#ifndef NO_INLINE uint8 GetBYTEWrapper(register uint32 Addr); void PutBYTEWrapper(register uint32 Addr, register uint32 Value); #endif @@ -187,7 +221,7 @@ void PutBYTEWrapper(register uint32 Addr, register uint32 Value); cpu_mod CPU modifiers list */ -UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK + UNIT_ROM, MAXMEMSIZE) }; +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK + UNIT_ROM + UNIT_ALTAIRROM, MAXMEMSIZE) }; int32 AF_S; int32 BC_S; @@ -226,37 +260,50 @@ REG cpu_reg[] = { { HRDATA (SR, SR, 8) }, { HRDATA (BANK, bankSelect, MAXBANKSLOG2) }, { HRDATA (COMMON, common, 16) }, + { HRDATA (ROMLOW, ROMLow, 16) }, + { HRDATA (ROMHIGH, ROMHigh, 16) }, + { HRDATA (CAPACITY, cpu_unit.capac, 17), REG_RO }, { BRDATA (PCQ, pcq, 16, 16, PCQ_SIZE), REG_RO + REG_CIRC }, { DRDATA (PCQP, pcq_p, 6), REG_HRO }, { HRDATA (WRU, sim_int_char, 8) }, { NULL } }; MTAB cpu_mod[] = { - { UNIT_CHIP, UNIT_CHIP, "Z80", "Z80", NULL }, - { UNIT_CHIP, 0, "8080", "8080", NULL }, - { UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL }, - { UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL }, - { UNIT_BANKED, UNIT_BANKED, "BANKED", "BANKED", &cpu_set_banked }, - { UNIT_BANKED, 0, "NONBANKED", "NONBANKED", NULL }, - { UNIT_ROM, UNIT_ROM, "ROM", "ROM", &cpu_set_rom }, - { UNIT_ROM, 0, "NOROM", "NOROM", NULL }, - { UNIT_MSIZE, 4 * KB, NULL, "4K", &cpu_set_size }, - { UNIT_MSIZE, 8 * KB, NULL, "8K", &cpu_set_size }, - { UNIT_MSIZE, 12 * KB, NULL, "12K", &cpu_set_size }, - { UNIT_MSIZE, 16 * KB, NULL, "16K", &cpu_set_size }, - { UNIT_MSIZE, 20 * KB, NULL, "20K", &cpu_set_size }, - { UNIT_MSIZE, 24 * KB, NULL, "24K", &cpu_set_size }, - { UNIT_MSIZE, 28 * KB, NULL, "28K", &cpu_set_size }, - { UNIT_MSIZE, 32 * KB, NULL, "32K", &cpu_set_size }, - { UNIT_MSIZE, 48 * KB, NULL, "48K", &cpu_set_size }, - { UNIT_MSIZE, 64 * KB, NULL, "64K", &cpu_set_size }, + { UNIT_CHIP, UNIT_CHIP, "Z80", "Z80", NULL }, + { UNIT_CHIP, 0, "8080", "8080", NULL }, + { UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL }, + { UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL }, + { UNIT_BANKED, UNIT_BANKED, "BANKED", "BANKED", &cpu_set_banked }, + { UNIT_BANKED, 0, "NONBANKED", "NONBANKED", NULL }, + { UNIT_ROM, UNIT_ROM, "ROM", "ROM", &cpu_set_rom }, + { UNIT_ROM, 0, "NOROM", "NOROM", &cpu_set_norom }, + { UNIT_ALTAIRROM, UNIT_ALTAIRROM, "ALTAIRROM", "ALTAIRROM", &cpu_set_altairrom }, + { UNIT_ALTAIRROM, 0, "NOALTAIRROM", "NOALTAIRROM", NULL }, + { UNIT_WARNROM, UNIT_WARNROM, "WARNROM", "WARNROM", &cpu_set_warnrom }, + { UNIT_WARNROM, 0, "NOWARNROM", "NOWARNROM", NULL }, + { UNIT_MSIZE, 4 * KB, NULL, "4K", &cpu_set_size }, + { UNIT_MSIZE, 8 * KB, NULL, "8K", &cpu_set_size }, + { UNIT_MSIZE, 12 * KB, NULL, "12K", &cpu_set_size }, + { UNIT_MSIZE, 16 * KB, NULL, "16K", &cpu_set_size }, + { UNIT_MSIZE, 20 * KB, NULL, "20K", &cpu_set_size }, + { UNIT_MSIZE, 24 * KB, NULL, "24K", &cpu_set_size }, + { UNIT_MSIZE, 28 * KB, NULL, "28K", &cpu_set_size }, + { UNIT_MSIZE, 32 * KB, NULL, "32K", &cpu_set_size }, + { UNIT_MSIZE, 36 * KB, NULL, "36K", &cpu_set_size }, + { UNIT_MSIZE, 40 * KB, NULL, "40K", &cpu_set_size }, + { UNIT_MSIZE, 44 * KB, NULL, "44K", &cpu_set_size }, + { UNIT_MSIZE, 48 * KB, NULL, "48K", &cpu_set_size }, + { UNIT_MSIZE, 52 * KB, NULL, "52K", &cpu_set_size }, + { UNIT_MSIZE, 56 * KB, NULL, "56K", &cpu_set_size }, + { UNIT_MSIZE, 60 * KB, NULL, "60K", &cpu_set_size }, + { UNIT_MSIZE, 64 * KB, NULL, "64K", &cpu_set_size }, { 0 } }; DEVICE cpu_dev = { "CPU", &cpu_unit, cpu_reg, cpu_mod, 1, 16, 16, 1, 16, 8, &cpu_ex, &cpu_dep, &cpu_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, NULL, 0 }; /* data structure for IN/OUT instructions */ struct idev { @@ -331,7 +378,7 @@ struct idev dev_table[256] = { {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F0 */ {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F4 */ {&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F8 */ -{&nulldev}, {&nulldev}, {&simh_dev}, {&sr_dev} }; /* FC */ +{&nulldev}, {&hdsk_io}, {&simh_dev}, {&sr_dev} }; /* FC */ INLINE void out(uint32 Port, uint32 Value) { dev_table[Port].routine(Port, 1, Value); @@ -341,13 +388,52 @@ INLINE uint32 in(uint32 Port) { return dev_table[Port].routine(Port, 0, 0); } +void warnUnsuccessfulWriteAttempt(uint32 Addr) { + if (cpu_unit.flags & UNIT_WARNROM) { + if (addressIsInROM(Addr)) { + message2("Attempt to write to ROM " AddressFormat ".\n", Addr); + } + else { + message2("Attempt to write to non existing memory " AddressFormat ".\n", Addr); + } + } +} + +uint8 warnUnsuccessfulReadAttempt(uint32 Addr) { + if (cpu_unit.flags & UNIT_WARNROM) { + message2("Attempt to read from non existing memory " AddressFormat ".\n", Addr); + } + return 0xff; +} + +/* Determine whether Addr points to Read Only Memory */ +int32 addressIsInROM(uint32 Addr) { + Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ + return (cpu_unit.flags & UNIT_ROM) && ( /* must have ROM enabled */ + /* in banked case we have standard Altair ROM */ + ((cpu_unit.flags & UNIT_BANKED) && (defaultROMLow <= Addr)) || + /* in non-banked case we check the bounds of the ROM */ + (((cpu_unit.flags & UNIT_BANKED) == 0) && (ROMLow <= Addr) && (Addr <= ROMHigh))); +} + +/* Determine whether Addr points to a valid memory address */ +int32 addressExists(uint32 Addr) { + Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ + return (cpu_unit.flags & UNIT_BANKED) || (Addr < MEMSIZE) || + ((cpu_unit.flags & UNIT_BANKED) == 0) && (cpu_unit.flags & UNIT_ROM) + && (ROMLow <= Addr) && (Addr <= ROMHigh); +} + INLINE uint8 GetBYTE(register uint32 Addr) { Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ - if (cpu_unit.flags & UNIT_BANKED) { + if (cpu_unit.flags & UNIT_BANKED) { /* banked memory case */ + /* if Addr below "common" take from selected bank, otherwise from bank 0 */ return Addr < common ? M[Addr][bankSelect] : M[Addr][0]; } - else { - return ((Addr < MEMSIZE) || (bootrom_origin <= Addr)) ? M[Addr][0] : 0xff; + else { /* non-banked memory case */ + return ((Addr < MEMSIZE) || + (cpu_unit.flags & UNIT_ROM) && (ROMLow <= Addr) && (Addr <= ROMHigh)) ? + M[Addr][0] : warnUnsuccessfulReadAttempt(Addr); } } @@ -357,26 +443,27 @@ INLINE void PutBYTE(register uint32 Addr, register uint32 Value) { if (Addr < common) { M[Addr][bankSelect] = Value; } - else if ((Addr < bootrom_origin) || ((cpu_unit.flags & UNIT_ROM) == 0)) { + else if ((Addr < defaultROMLow) || ((cpu_unit.flags & UNIT_ROM) == 0)) { M[Addr][0] = Value; } + else { + warnUnsuccessfulWriteAttempt(Addr); + } } else { - if ((Addr < MEMSIZE) && ((Addr < bootrom_origin) || ((cpu_unit.flags & UNIT_ROM) == 0))) { + if ((Addr < MEMSIZE) && ((Addr < ROMLow) || (Addr > ROMHigh) || ((cpu_unit.flags & UNIT_ROM) == 0))) { M[Addr][0] = Value; } + else { + warnUnsuccessfulWriteAttempt(Addr); + } } } void PutBYTEForced(register uint32 Addr, register uint32 Value) { Addr &= ADDRMASK; /* registers are NOT guaranteed to be always 16-bit values */ - if (cpu_unit.flags & UNIT_BANKED) { - if (Addr < common) { - M[Addr][bankSelect] = Value; - } - else { - M[Addr][0] = Value; - } + if ((cpu_unit.flags & UNIT_BANKED) && (Addr < common)) { + M[Addr][bankSelect] = Value; } else { M[Addr][0] = Value; @@ -389,25 +476,37 @@ INLINE void PutWORD(register uint32 Addr, register uint32 Value) { if (Addr < common) { M[Addr][bankSelect] = Value; } - else if ((Addr < bootrom_origin) || ((cpu_unit.flags & UNIT_ROM) == 0)) { + else if ((Addr < defaultROMLow) || ((cpu_unit.flags & UNIT_ROM) == 0)) { M[Addr][0] = Value; } + else { + warnUnsuccessfulWriteAttempt(Addr); + } Addr = (Addr + 1) & ADDRMASK; if (Addr < common) { M[Addr][bankSelect] = Value >> 8; } - else if ((Addr < bootrom_origin) || ((cpu_unit.flags & UNIT_ROM) == 0)) { + else if ((Addr < defaultROMLow) || ((cpu_unit.flags & UNIT_ROM) == 0)) { M[Addr][0] = Value >> 8; } + else { + warnUnsuccessfulWriteAttempt(Addr); + } } else { - if ((Addr < MEMSIZE) && ((Addr < bootrom_origin) || ((cpu_unit.flags & UNIT_ROM) == 0))) { + if ((Addr < MEMSIZE) && ((Addr < ROMLow) || (Addr > ROMHigh) || ((cpu_unit.flags & UNIT_ROM) == 0))) { M[Addr][0] = Value; } + else { + warnUnsuccessfulWriteAttempt(Addr); + } Addr = (Addr + 1) & ADDRMASK; - if ((Addr < MEMSIZE) && ((Addr < bootrom_origin) || ((cpu_unit.flags & UNIT_ROM) == 0))) { + if ((Addr < MEMSIZE) && ((Addr < ROMLow) || (Addr > ROMHigh) || ((cpu_unit.flags & UNIT_ROM) == 0))) { M[Addr][0] = Value >> 8; } + else { + warnUnsuccessfulWriteAttempt(Addr); + } } } @@ -574,11 +673,11 @@ int32 sim_instr (void) { PCX = PC; sim_interval--; - /* make sure that each instructions properly sets sim_brk_pend: - 1) Either directly to FALSE if no memory access takes place or - 2) through a call to a Check... routine - */ - switch(RAM_pp(PC)) { + /* make sure that each instructions properly sets sim_brk_pend: + 1) Either directly to FALSE if no memory access takes place or + 2) through a call to a Check... routine + */ + switch(RAM_pp(PC)) { case 0x00: /* NOP */ sim_brk_pend = FALSE; break; @@ -966,7 +1065,7 @@ int32 sim_instr (void) { break; case 0x37: /* SCF */ sim_brk_pend = FALSE; - AF = (AF&~0x3b)|((AF>>8)&0x28)|1; + AF = (AF & ~0x3b) | ((AF>>8) & 0x28) | 1; break; case 0x38: /* JR C,dd */ sim_brk_pend = FALSE; @@ -1023,7 +1122,8 @@ int32 sim_instr (void) { break; case 0x3f: /* CCF */ sim_brk_pend = FALSE; - AF = (AF&~0x3b)|((AF>>8)&0x28)|((AF&1)<<4)|(~AF&1); + AF = (AF & ~0x3b) | ((AF >> 8) & 0x28) | + ((AF & 1) << 4) | (~AF & 1); break; case 0x40: /* LD B,B */ sim_brk_pend = FALSE; @@ -1982,7 +2082,7 @@ int32 sim_instr (void) { else { AF = (AF & ~0xfe) | 0x54; } - if ((op&7) != 6) { + if ((op & 7) != 6) { AF |= (acu & 0x28); } temp = acu; @@ -2689,7 +2789,7 @@ int32 sim_instr (void) { else { AF = (AF & ~0xfe) | 0x54; } - if ((op&7) != 6) { + if ((op & 7) != 6) { AF |= (acu & 0x28); } temp = acu; @@ -3142,7 +3242,7 @@ int32 sim_instr (void) { sum = acu - temp; cbits = acu ^ temp ^ sum; AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | - (((sum - ((cbits&16)>>4))&2) << 4) | (cbits & 16) | + (((sum - ((cbits & 16)>>4)) & 2) << 4) | (cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) | ((--BC & ADDRMASK) != 0) << 2 | 2; if ((sum & 15) == 8 && (cbits & 16) != 0) { @@ -3177,7 +3277,7 @@ int32 sim_instr (void) { sum = acu - temp; cbits = acu ^ temp ^ sum; AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | - (((sum - ((cbits&16)>>4))&2) << 4) | (cbits & 16) | + (((sum - ((cbits & 16)>>4)) & 2) << 4) | (cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) | ((--BC & ADDRMASK) != 0) << 2 | 2; if ((sum & 15) == 8 && (cbits & 16) != 0) { @@ -3220,7 +3320,7 @@ int32 sim_instr (void) { } while (op && sum != 0); cbits = acu ^ temp ^ sum; AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | - (((sum - ((cbits&16)>>4))&2) << 4) | + (((sum - ((cbits & 16)>>4)) & 2) << 4) | (cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) | op << 2 | 2; if ((sum & 15) == 8 && (cbits & 16) != 0) { @@ -3268,7 +3368,7 @@ int32 sim_instr (void) { } while (op && sum != 0); cbits = acu ^ temp ^ sum; AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | - (((sum - ((cbits&16)>>4))&2) << 4) | + (((sum - ((cbits & 16)>>4)) & 2) << 4) | (cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) | op << 2 | 2; if ((sum & 15) == 8 && (cbits & 16) != 0) { @@ -3327,7 +3427,6 @@ int32 sim_instr (void) { sim_brk_pend = FALSE; JPC(!TSTFLAG(S)); break; - case 0xf3: /* DI */ sim_brk_pend = FALSE; IFF = 0; @@ -3959,7 +4058,7 @@ int32 sim_instr (void) { else { AF = (AF & ~0xfe) | 0x54; } - if ((op&7) != 6) { + if ((op & 7) != 6) { AF |= (acu & 0x28); } temp = acu; @@ -4055,28 +4154,60 @@ int32 sim_instr (void) { return reason; } -void install_bootrom(void) { - int32 i; +int32 install_bootrom(void) { + int32 i, cnt = 0; for (i = 0; i < bootrom_size; i++) { - M[i + bootrom_origin][0] = bootrom[i] & 0xff; + if (M[i + defaultROMLow][0] != (bootrom[i] & 0xff)) { + cnt++; + M[i + defaultROMLow][0] = bootrom[i] & 0xff; + } + } + return cnt; +} + +int32 lowProtect; +int32 highProtect; +int32 isProtected = FALSE; + +void protect(int32 l, int32 h) { + isProtected = TRUE; + lowProtect = l; + highProtect = h; +} + +void resetCell(int32 address, int32 bank) { + if (!(isProtected && (bank == 0) && (lowProtect <= address) && (address <= highProtect))) { + M[address][bank] = 0; } } -void clear_memory(int32 starting) { - int32 i, j; +void reset_memory(void) { + uint32 i, j; + checkROMBoundaries(); if (cpu_unit.flags & UNIT_BANKED) { for (i = 0; i < MAXMEMSIZE; i++) { for (j = 0; j < MAXBANKS; j++) { - M[i][j] = 0; + resetCell(i, j); } } } - else { - for (i = starting; i < MAXMEMSIZE; i++) { - M[i][0] = 0; + else if (cpu_unit.flags & UNIT_ROM) { + for (i = 0; i < ROMLow; i++) { + resetCell(i, 0); + } + for (i = ROMHigh+1; i < MAXMEMSIZE; i++) { + resetCell(i, 0); } } - install_bootrom(); + else { + for (i = 0; i < MAXMEMSIZE; i++) { + resetCell(i, 0); + } + } + if (cpu_unit.flags & (UNIT_ALTAIRROM | UNIT_BANKED)) { + install_bootrom(); + } + isProtected = FALSE; } /* Reset routine */ @@ -4091,8 +4222,7 @@ t_stat cpu_reset(DEVICE *dptr) { INT_S = IX_S = IY_S = SP_S = 0; IFF_S = 3; bankSelect = 0; - saved_PC = 0; - clear_memory(0); + reset_memory(); sim_brk_types = (SWMASK('E') | SWMASK('M')); sim_brk_dflt = SWMASK('E'); for (i = 0; i < PCQ_SIZE; i++) { @@ -4111,62 +4241,109 @@ t_stat cpu_reset(DEVICE *dptr) { /* Memory examine */ t_stat cpu_ex(t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) { - if (cpu_unit.flags & UNIT_BANKED) { - if (addr >= MAXMEMSIZE) { - return SCPE_NXM; + if (addressExists(addr)) { + if (vptr != NULL) { + *vptr = GetBYTE(addr) & 0xff; } + return SCPE_OK; } else { - if ((addr >= MEMSIZE) && (addr < bootrom_origin)) { - return SCPE_NXM; - } + return SCPE_NXM; } - if (vptr != NULL) { - *vptr = GetBYTE(addr) & 0xff; - } - return SCPE_OK; } /* Memory deposit */ t_stat cpu_dep(t_value val, t_addr addr, UNIT *uptr, int32 sw) { - if (cpu_unit.flags & UNIT_BANKED) { - if ((addr >= bootrom_origin) && (cpu_unit.flags & UNIT_ROM)) { - return SCPE_NXM; - } + if (addressExists(addr) && (!addressIsInROM(addr))) { + PutBYTE(addr, val & 0xff); + return SCPE_OK; } else { - if ((addr >= MEMSIZE) || ((addr >= bootrom_origin) && (cpu_unit.flags & UNIT_ROM))) { - return SCPE_NXM; + return SCPE_NXM; + } +} + +void checkROMBoundaries(void) { + uint32 temp; + if (ROMLow > ROMHigh) { + printf("ROMLOW [%04X] must be less than or equal to ROMHIGH [%04X]. Values exchanged.\n", + ROMLow, ROMHigh); + temp = ROMLow; + ROMLow = ROMHigh; + ROMHigh = temp; + } + if (cpu_unit.flags & UNIT_ALTAIRROM) { + if (defaultROMLow < ROMLow) { + printf("ROMLOW [%04X] reset to %04X since Altair ROM was desired.\n", ROMLow, defaultROMLow); + ROMLow = defaultROMLow; + } + if (ROMHigh < defaultROMHigh) { + printf("ROMHIGH [%04X] reset to %04X since Altair ROM was desired.\n", ROMHigh, defaultROMHigh); + ROMHigh = defaultROMHigh; } } - PutBYTE(addr, val & 0xff); - return SCPE_OK; } t_stat cpu_set_rom(UNIT *uptr, int32 value, char *cptr, void *desc) { + checkROMBoundaries(); + return SCPE_OK; +} + +t_stat cpu_set_norom(UNIT *uptr, int32 value, char *cptr, void *desc) { + if (cpu_unit.flags & UNIT_ALTAIRROM) { + printf("\"SET CPU NOALTAIRROM\" also executed.\n"); + cpu_unit.flags &= ~UNIT_ALTAIRROM; + } + return SCPE_OK; +} + +t_stat cpu_set_altairrom(UNIT *uptr, int32 value, char *cptr, void *desc) { install_bootrom(); + if (ROMLow != defaultROMLow) { + printf("\"D ROMLOW %04X\" also executed.\n", defaultROMLow); + ROMLow = defaultROMLow; + } + if (ROMHigh != defaultROMHigh) { + printf("\"D ROMHIGH %04X\" also executed.\n", defaultROMHigh); + ROMHigh = defaultROMHigh; + } + if (!(cpu_unit.flags & UNIT_ROM)) { + printf("\"SET CPU ROM\" also executed.\n"); + cpu_unit.flags |= UNIT_ROM; + } + return SCPE_OK; +} + +t_stat cpu_set_warnrom(UNIT *uptr, int32 value, char *cptr, void *desc) { + if ((!(cpu_unit.flags & UNIT_ROM)) && (MEMSIZE == 64*KB)) { + printf("CPU has currently 64 Kb available for writing.\n"); + } return SCPE_OK; } t_stat cpu_set_banked(UNIT *uptr, int32 value, char *cptr, void *desc) { - return MEMSIZE < MAXMEMSIZE ? SCPE_ARG : SCPE_OK; + if (common > defaultROMLow) { + printf("Warning: COMMON [%04X] must not be greater than %04X. Reset to %04X.\n", + common, defaultROMLow, defaultROMLow); + common = defaultROMLow; + } + if (MEMSIZE < MAXMEMSIZE) { + printf("\"SET CPU 64K\" also executed.\n"); + MEMSIZE = MAXMEMSIZE; + reset_memory(); + } + return SCPE_OK; } t_stat cpu_set_size(UNIT *uptr, int32 value, char *cptr, void *desc) { - int32 i, limit, mc = 0; - - if ((cpu_unit.flags & UNIT_BANKED) || - (value <= 0) || (value > MAXMEMSIZE) || ((value & 0xfff) != 0)) { - return SCPE_ARG; + if ((cpu_unit.flags & UNIT_BANKED) && (value < MAXMEMSIZE)) { + printf("\"SET CPU NONBANKED\" also executed.\n"); + cpu_unit.flags &= ~UNIT_BANKED; } - limit = (bootrom_origin < MEMSIZE) ? bootrom_origin : MEMSIZE; - for (i = value; i < limit; i++) { - mc |= GetBYTE(i); - } - if (mc && (!get_yn("Really truncate memory [N]?", FALSE))) { - return SCPE_OK; + if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 0xfff) != 0)) { + return SCPE_ARG; } MEMSIZE = value; - clear_memory(value); + reset_memory(); return SCPE_OK; } diff --git a/AltairZ80/altairZ80_defs.h b/AltairZ80/altairZ80_defs.h index 931a291e..83a37004 100644 --- a/AltairZ80/altairZ80_defs.h +++ b/AltairZ80/altairZ80_defs.h @@ -1,38 +1,83 @@ /* altairZ80_defs.h: MITS Altair simulator definitions - Written by Peter Schorn, 2001-2002 - Based on work by Charles E Owen ((c) 1997, Commercial use prohibited) + + Copyright (c) 2002, Peter Schorn + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Peter Schorn shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Peter Schorn. + + Based on work by Charles E Owen (c) 1997 */ -#include "sim_defs.h" /* simulator definitions */ +#include "sim_defs.h" /* simulator definitions */ /* Memory */ -#define MAXMEMSIZE 65536 /* max memory size */ -#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */ -#define bootrom_size 256 /* size of boot rom */ -#define MAXBANKS 8 /* max number of memory banks */ -#define MAXBANKSLOG2 3 /* log2 of MAXBANKS */ -#define BANKMASK (MAXBANKS-1) /* bank mask */ +#define MAXMEMSIZE 65536 /* max memory size */ +#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */ +#define bootrom_size 256 /* size of boot rom */ +#define MAXBANKS 8 /* max number of memory banks */ +#define MAXBANKSLOG2 3 /* log2 of MAXBANKS */ +#define BANKMASK (MAXBANKS-1) /* bank mask */ +#define MEMSIZE (cpu_unit.capac) /* actual memory size */ +#define KB 1024 /* kilo byte */ +#define defaultROMLow 0xff00 /* default for lowest addres of ROM */ +#define defaultROMHigh 0xffff /* default for highest addres of ROM */ -#define UNIT_V_OPSTOP (UNIT_V_UF) /* Stop on Invalid OP? */ -#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP) -#define UNIT_V_CHIP (UNIT_V_UF+1) /* 8080 or Z80 */ -#define UNIT_CHIP (1 << UNIT_V_CHIP) -#define UNIT_V_MSIZE (UNIT_V_UF+2) /* Memory Size */ -#define UNIT_MSIZE (1 << UNIT_V_MSIZE) -#define UNIT_V_BANKED (UNIT_V_UF+3) /* Banked memory is used */ -#define UNIT_BANKED (1 << UNIT_V_BANKED) -#define UNIT_V_ROM (UNIT_V_UF+4) /* ROM exists */ -#define UNIT_ROM (1 << UNIT_V_ROM) +#define NUM_OF_DSK 8 /* NUM_OF_DSK must be power of two */ +#define LDAInstruction 0x3e /* op-code for LD A,<8-bit value> instruction */ +#define unitNoOffset1 0x37 /* LD A, */ +#define unitNoOffset2 0xb4 /* LD a,80h | */ -#define PCformat "\n[%04xh] " -#define message1(p1) sprintf(messageBuffer,PCformat p1,PCX); printMessage() -#define message2(p1,p2) sprintf(messageBuffer,PCformat p1,PCX,p2); printMessage() -#define message3(p1,p2,p3) sprintf(messageBuffer,PCformat p1,PCX,p2,p3); printMessage() -#define message4(p1,p2,p3,p4) sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4); printMessage() +#define UNIT_V_OPSTOP (UNIT_V_UF+0) /* Stop on Invalid OP? */ +#define UNIT_OPSTOP (1 << UNIT_V_OPSTOP) +#define UNIT_V_CHIP (UNIT_V_UF+1) /* 8080 or Z80 */ +#define UNIT_CHIP (1 << UNIT_V_CHIP) +#define UNIT_V_MSIZE (UNIT_V_UF+2) /* Memory Size */ +#define UNIT_MSIZE (1 << UNIT_V_MSIZE) +#define UNIT_V_BANKED (UNIT_V_UF+3) /* Banked memory is used */ +#define UNIT_BANKED (1 << UNIT_V_BANKED) +#define UNIT_V_ROM (UNIT_V_UF+4) /* ROM exists */ +#define UNIT_ROM (1 << UNIT_V_ROM) +#define UNIT_V_ALTAIRROM (UNIT_V_UF+5) /* ALTAIR ROM exists */ +#define UNIT_ALTAIRROM (1 << UNIT_V_ALTAIRROM) +#define UNIT_V_WARNROM (UNIT_V_UF+6) /* Warn if ROM is written to */ +#define UNIT_WARNROM (1 << UNIT_V_WARNROM) + +#define AddressFormat "[%04xh]" +#define PCformat "\n" AddressFormat " " +#define message1(p1) \ + sprintf(messageBuffer,PCformat p1,PCX); printMessage() +#define message2(p1,p2) \ + sprintf(messageBuffer,PCformat p1,PCX,p2); printMessage() +#define message3(p1,p2,p3) \ + sprintf(messageBuffer,PCformat p1,PCX,p2,p3); printMessage() +#define message4(p1,p2,p3,p4) \ + sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4); printMessage() +#define message5(p1,p2,p3,p4,p5) \ + sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4,p5); printMessage() +#define message6(p1,p2,p3,p4,p5,p6) \ + sprintf(messageBuffer,PCformat p1,PCX,p2,p3,p4,p5,p6); printMessage() /* The Default is to use "inline". In this case the wrapper functions for GetBYTE and PutBYTE need to be created. Otherwise they are not needed - and the calls map to the original functions. */ + and the calls map to the original functions. */ #ifdef NO_INLINE #define INLINE #define GetBYTEWrapper GetBYTE diff --git a/AltairZ80/altairZ80_dsk.c b/AltairZ80/altairZ80_dsk.c index 3eef5a73..a5b1f2ef 100644 --- a/AltairZ80/altairZ80_dsk.c +++ b/AltairZ80/altairZ80_dsk.c @@ -1,6 +1,29 @@ /* altairZ80_dsk.c: MITS Altair 88-DISK Simulator - Written by Charles E Owen ((c) 1997, Commercial use prohibited) - Modifications to improve robustness by Peter Schorn, 2001-2002 + + Copyright (c) 2002, Peter Schorn + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Peter Schorn shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Peter Schorn. + + Based on work by Charles E Owen (c) 1997 The 88_DISK is a 8-inch floppy controller which can control up to 16 daisy-chained Pertec FD-400 hard-sectored floppy drives. @@ -42,7 +65,7 @@ M - When 0, head movement is allowed H - When 0, indicates head is loaded for read/write X - not used (will be 0) - I - When 0, indicates interrupts enabled (not used this simulator) + I - When 0, indicates interrupts enabled (not used by this simulator) Z - When 0, indicates head is on track 0 R - When 0, indicates that read circuit has new byte to read @@ -86,30 +109,29 @@ */ #include -#include "altairZ80_defs.h" +#include "altairz80_defs.h" -#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_WLK (1 << UNIT_V_UF) +#define UNIT_V_DSKWLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_DSKWLK (1 << UNIT_V_DSKWLK) #define UNIT_V_DSK_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ #define UNIT_DSK_VERBOSE (1 << UNIT_V_DSK_VERBOSE) #define DSK_SECTSIZE 137 /* size of sector */ #define DSK_SECT 32 /* sectors per track */ -#define TRACKS 254 /* number of tracks, +#define MAX_TRACKS 254 /* number of tracks, original Altair has 77 tracks only */ #define DSK_TRACSIZE (DSK_SECTSIZE * DSK_SECT) -#define DSK_SIZE (DSK_TRACSIZE * TRACKS) +#define MAX_DSK_SIZE (DSK_TRACSIZE * MAX_TRACKS) #define TRACE_IN_OUT 1 #define TRACE_READ_WRITE 2 #define TRACE_SECTOR_STUCK 4 #define TRACE_TRACK_STUCK 8 -#define NUM_OF_DSK 8 /* NUM_OF_DSK must be power of two */ #define NUM_OF_DSK_MASK (NUM_OF_DSK - 1) int32 dsk10(int32 port, int32 io, int32 data); int32 dsk11(int32 port, int32 io, int32 data); int32 dsk12(int32 port, int32 io, int32 data); int32 dskseek(UNIT *xptr); -t_stat dsk_boot(int32 unitno); +t_stat dsk_boot(int32 unitno, DEVICE *dptr); t_stat dsk_reset(DEVICE *dptr); t_stat dsk_svc(UNIT *uptr); void writebuf(void); @@ -124,101 +146,101 @@ extern FILE *sim_log; extern void PutBYTEWrapper(register uint32 Addr, register uint32 Value); extern void printMessage(void); extern char messageBuffer[]; -extern void install_bootrom(void); +extern int32 install_bootrom(void); +extern UNIT cpu_unit; /* Global data on status */ -int32 cur_disk = NUM_OF_DSK; /* Currently selected drive (values are 0 .. NUM_OF_DSK) +int32 cur_disk = NUM_OF_DSK; /* Currently selected drive (values are 0 .. NUM_OF_DSK) cur_disk < NUM_OF_DSK implies that the corresponding disk is attached to a file */ int32 cur_track [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; int32 cur_sect [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; int32 cur_byte [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; int32 cur_flags [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint8 tracks [NUM_OF_DSK] = { MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, + MAX_TRACKS, MAX_TRACKS, MAX_TRACKS, MAX_TRACKS }; int32 trace_flag = 0; int32 in9_count = 0; int32 in9_message = FALSE; -int32 dirty = 0; /* 1 when buffer has unwritten data in it */ +int32 dirty = FALSE; /* TRUE when buffer has unwritten data in it */ int32 warnLevelDSK = 3; int32 warnLock [NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; int32 warnAttached[NUM_OF_DSK] = {0, 0, 0, 0, 0, 0, 0, 0}; int32 warnDSK10 = 0; int32 warnDSK11 = 0; int32 warnDSK12 = 0; -int8 dskbuf[DSK_SECTSIZE]; /* Data Buffer */ - -#define LDAInstruction 0x3e /* op-code for LD A,<8-bit value> instruction */ -#define unitNoOffset1 0x37 /* LD A, */ -#define unitNoOffset2 0xb4 /* LD a,80h | */ +int8 dskbuf[DSK_SECTSIZE]; /* Data Buffer */ /* Altair MITS modified BOOT EPROM, fits in upper 256 byte of memory */ int32 bootrom[bootrom_size] = { - 0xf3, 0x06, 0x80, 0x3e, 0x0e, 0xd3, 0xfe, 0x05, /* fe00-fe07 */ - 0xc2, 0x05, 0xff, 0x3e, 0x16, 0xd3, 0xfe, 0x3e, /* fe08-fe0f */ - 0x12, 0xd3, 0xfe, 0xdb, 0xfe, 0xb7, 0xca, 0x20, /* fe10-fe17 */ - 0xff, 0x3e, 0x0c, 0xd3, 0xfe, 0xaf, 0xd3, 0xfe, /* fe18-fe1f */ - 0x21, 0x00, 0x5c, 0x11, 0x33, 0xff, 0x0e, 0x88, /* fe20-fe27 */ - 0x1a, 0x77, 0x13, 0x23, 0x0d, 0xc2, 0x28, 0xff, /* fe28-fe2f */ - 0xc3, 0x00, 0x5c, 0x31, 0x21, 0x5d, 0x3e, 0x00, /* fe30-fe37 */ - 0xd3, 0x08, 0x3e, 0x04, 0xd3, 0x09, 0xc3, 0x19, /* fe38-fe3f */ - 0x5c, 0xdb, 0x08, 0xe6, 0x02, 0xc2, 0x0e, 0x5c, /* fe40-fe47 */ - 0x3e, 0x02, 0xd3, 0x09, 0xdb, 0x08, 0xe6, 0x40, /* fe48-fe4f */ - 0xc2, 0x0e, 0x5c, 0x11, 0x00, 0x00, 0x06, 0x08, /* fe50-fe57 */ - 0xc5, 0xd5, 0x11, 0x86, 0x80, 0x21, 0x88, 0x5c, /* fe58-fe5f */ - 0xdb, 0x09, 0x1f, 0xda, 0x2d, 0x5c, 0xe6, 0x1f, /* fe60-fe67 */ - 0xb8, 0xc2, 0x2d, 0x5c, 0xdb, 0x08, 0xb7, 0xfa, /* fe68-fe6f */ - 0x39, 0x5c, 0xdb, 0x0a, 0x77, 0x23, 0x1d, 0xc2, /* fe70-fe77 */ - 0x39, 0x5c, 0xd1, 0x21, 0x8b, 0x5c, 0x06, 0x80, /* fe78-fe7f */ - 0x7e, 0x12, 0x23, 0x13, 0x05, 0xc2, 0x4d, 0x5c, /* fe80-fe87 */ - 0xc1, 0x21, 0x00, 0x5c, 0x7a, 0xbc, 0xc2, 0x60, /* fe88-fe8f */ - 0x5c, 0x7b, 0xbd, 0xd2, 0x80, 0x5c, 0x04, 0x04, /* fe90-fe97 */ - 0x78, 0xfe, 0x20, 0xda, 0x25, 0x5c, 0x06, 0x01, /* fe98-fe9f */ - 0xca, 0x25, 0x5c, 0xdb, 0x08, 0xe6, 0x02, 0xc2, /* fea0-fea7 */ - 0x70, 0x5c, 0x3e, 0x01, 0xd3, 0x09, 0x06, 0x00, /* fea8-feaf */ - 0xc3, 0x25, 0x5c, 0x3e, 0x80, 0xd3, 0x08, 0xfb, /* feb0-feb7 */ - 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* feb8-febf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fec0-fec7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fec8-fecf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fed0-fed7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fed8-fedf */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fee0-fee7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fee8-feef */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fef0-fef7 */ - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fef8-feff */ + 0xf3, 0x06, 0x80, 0x3e, 0x0e, 0xd3, 0xfe, 0x05, /* ff00-ff07 */ + 0xc2, 0x05, 0xff, 0x3e, 0x16, 0xd3, 0xfe, 0x3e, /* ff08-ff0f */ + 0x12, 0xd3, 0xfe, 0xdb, 0xfe, 0xb7, 0xca, 0x20, /* ff10-ff17 */ + 0xff, 0x3e, 0x0c, 0xd3, 0xfe, 0xaf, 0xd3, 0xfe, /* ff18-ff1f */ + 0x21, 0x00, 0x5c, 0x11, 0x33, 0xff, 0x0e, 0x88, /* ff20-ff27 */ + 0x1a, 0x77, 0x13, 0x23, 0x0d, 0xc2, 0x28, 0xff, /* ff28-ff2f */ + 0xc3, 0x00, 0x5c, 0x31, 0x21, 0x5d, 0x3e, 0x00, /* ff30-ff37 */ + 0xd3, 0x08, 0x3e, 0x04, 0xd3, 0x09, 0xc3, 0x19, /* ff38-ff3f */ + 0x5c, 0xdb, 0x08, 0xe6, 0x02, 0xc2, 0x0e, 0x5c, /* ff40-ff47 */ + 0x3e, 0x02, 0xd3, 0x09, 0xdb, 0x08, 0xe6, 0x40, /* ff48-ff4f */ + 0xc2, 0x0e, 0x5c, 0x11, 0x00, 0x00, 0x06, 0x08, /* ff50-ff57 */ + 0xc5, 0xd5, 0x11, 0x86, 0x80, 0x21, 0x88, 0x5c, /* ff58-ff5f */ + 0xdb, 0x09, 0x1f, 0xda, 0x2d, 0x5c, 0xe6, 0x1f, /* ff60-ff67 */ + 0xb8, 0xc2, 0x2d, 0x5c, 0xdb, 0x08, 0xb7, 0xfa, /* ff68-ff6f */ + 0x39, 0x5c, 0xdb, 0x0a, 0x77, 0x23, 0x1d, 0xc2, /* ff70-ff77 */ + 0x39, 0x5c, 0xd1, 0x21, 0x8b, 0x5c, 0x06, 0x80, /* ff78-ff7f */ + 0x7e, 0x12, 0x23, 0x13, 0x05, 0xc2, 0x4d, 0x5c, /* ff80-ff87 */ + 0xc1, 0x21, 0x00, 0x5c, 0x7a, 0xbc, 0xc2, 0x60, /* ff88-ff8f */ + 0x5c, 0x7b, 0xbd, 0xd2, 0x80, 0x5c, 0x04, 0x04, /* ff90-ff97 */ + 0x78, 0xfe, 0x20, 0xda, 0x25, 0x5c, 0x06, 0x01, /* ff98-ff9f */ + 0xca, 0x25, 0x5c, 0xdb, 0x08, 0xe6, 0x02, 0xc2, /* ffa0-ffa7 */ + 0x70, 0x5c, 0x3e, 0x01, 0xd3, 0x09, 0x06, 0x00, /* ffa8-ffaf */ + 0xc3, 0x25, 0x5c, 0x3e, 0x80, 0xd3, 0x08, 0xfb, /* ffb0-ffb7 */ + 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffb8-ffbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffc0-ffc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffc8-ffcf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffd0-ffd7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffd8-ffdf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffe0-ffe7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* ffe8-ffef */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fff0-fff7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* fff8-ffff */ }; /* 88DSK Standard I/O Data Structures */ UNIT dsk_unit[] = { - { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, DSK_SIZE) } }; + { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) }, + { UDATA (&dsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, MAX_DSK_SIZE) } }; REG dsk_reg[] = { - { DRDATA (DISK, cur_disk, 4) }, - { DRDATA (DSKWL, warnLevelDSK, 32) }, - { ORDATA (TRACE, trace_flag, 8) }, - { DRDATA (IN9, in9_count, 4), REG_RO }, + { DRDATA (DISK, cur_disk, 4) }, + { DRDATA (DSKWL, warnLevelDSK, 32) }, + { ORDATA (TRACE, trace_flag, 8) }, + { BRDATA (TRACKS, tracks, 10, 8, NUM_OF_DSK), REG_CIRC }, + { DRDATA (IN9, in9_count, 4), REG_RO }, { NULL } }; MTAB dsk_mod[] = { - { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, + { UNIT_DSKWLK, 0, "write enabled", "WRITEENABLED", NULL }, + { UNIT_DSKWLK, UNIT_DSKWLK, "write locked", "LOCKED", NULL }, /* quiet, no warning messages */ { UNIT_DSK_VERBOSE, 0, "QUIET", "QUIET", NULL }, /* verbose, show warning messages */ { UNIT_DSK_VERBOSE, UNIT_DSK_VERBOSE, "VERBOSE", "VERBOSE", &dsk_set_verbose }, - { 0 } }; + { 0 } }; DEVICE dsk_dev = { "DSK", dsk_unit, dsk_reg, dsk_mod, 8, 10, 31, 1, 8, 8, NULL, NULL, &dsk_reset, - &dsk_boot, NULL, NULL }; + &dsk_boot, NULL, NULL, NULL, 0 }; void resetDSKWarningFlags(void) { int32 i; @@ -251,7 +273,7 @@ char* selectInOut(int32 io) { return io == 0 ? "IN" : "OUT"; } -/* Service routines to handle simlulator functions */ +/* Service routines to handle simulator functions */ /* service routine - actually gets char & places in buffer */ @@ -271,22 +293,25 @@ t_stat dsk_reset(DEVICE *dptr) { } /* The boot routine modifies the boot ROM in such a way that subsequently - the specified disk is used for boot purposes. The program counter will reach - the boot ROM by executing NOP instructions starting from address 0 until - it reaches 0xff00. + the specified disk is used for boot purposes. */ -t_stat dsk_boot(int32 unitno) { - install_bootrom(); - /* check whether we are really modifying an LD A,<> instruction */ - if ((bootrom[unitNoOffset1 - 1] == LDAInstruction) && (bootrom[unitNoOffset2 - 1] == LDAInstruction)) { - bootrom[unitNoOffset1] = unitno & 0xff; /* LD A, */ - bootrom[unitNoOffset2] = 0x80 | (unitno & 0xff); /* LD a,80h | */ - return SCPE_OK; - } - else { /* Attempt to modify non LD A,<> instructions is refused. */ - printf("Incorrect boot ROM offsets detected.\n"); - return SCPE_IERR; +t_stat dsk_boot(int32 unitno, DEVICE *dptr) { + if (cpu_unit.flags & (UNIT_ALTAIRROM | UNIT_BANKED)) { + if (install_bootrom()) { + printf("ALTAIR boot ROM installed.\n"); + } + /* check whether we are really modifying an LD A,<> instruction */ + if ((bootrom[unitNoOffset1 - 1] == LDAInstruction) && (bootrom[unitNoOffset2 - 1] == LDAInstruction)) { + bootrom[unitNoOffset1] = unitno & 0xff; /* LD A, */ + bootrom[unitNoOffset2] = 0x80 | (unitno & 0xff); /* LD a,80h | */ + } + else { /* Attempt to modify non LD A,<> instructions is refused. */ + printf("Incorrect boot ROM offsets detected.\n"); + return SCPE_IERR; + } } + saved_PC = defaultROMLow; + return SCPE_OK; } /* I/O instruction handlers, called from the CPU module when an @@ -323,7 +348,7 @@ int32 dsk10(int32 port, int32 io, int32 data) { } /* OUT: Controller set/reset/enable/disable */ - if (dirty == 1) {/* implies that cur_disk < NUM_OF_DSK */ + if (dirty) {/* implies that cur_disk < NUM_OF_DSK */ writebuf(); } if (trace_flag & TRACE_IN_OUT) { @@ -369,7 +394,7 @@ int32 dsk11(int32 port, int32 io, int32 data) { if (trace_flag & TRACE_IN_OUT) { message1("IN 0x09\n"); } - if (dirty == 1) {/* implies that cur_disk < NUM_OF_DSK */ + if (dirty) {/* implies that cur_disk < NUM_OF_DSK */ writebuf(); } if (cur_flags[cur_disk] & 0x04) { /* head loaded? */ @@ -393,15 +418,15 @@ int32 dsk11(int32 port, int32 io, int32 data) { } if (data & 0x01) { /* Step head in */ if (trace_flag & TRACE_TRACK_STUCK) { - if (cur_track[cur_disk] == (TRACKS - 1)) { + if (cur_track[cur_disk] == (tracks[cur_disk] - 1)) { message2("Unnecessary step in for disk %d\n", cur_disk); } } cur_track[cur_disk]++; - if (cur_track[cur_disk] > (TRACKS - 1)) { - cur_track[cur_disk] = (TRACKS - 1); + if (cur_track[cur_disk] > (tracks[cur_disk] - 1)) { + cur_track[cur_disk] = (tracks[cur_disk] - 1); } - if (dirty == 1) { /* implies that cur_disk < NUM_OF_DSK */ + if (dirty) { /* implies that cur_disk < NUM_OF_DSK */ writebuf(); } cur_sect[cur_disk] = 0xff; @@ -419,14 +444,14 @@ int32 dsk11(int32 port, int32 io, int32 data) { cur_track[cur_disk] = 0; cur_flags[cur_disk] |= 0x40; /* track 0 if there */ } - if (dirty == 1) { /* implies that cur_disk < NUM_OF_DSK */ + if (dirty) { /* implies that cur_disk < NUM_OF_DSK */ writebuf(); } cur_sect[cur_disk] = 0xff; cur_byte[cur_disk] = 0xff; } - if (dirty == 1) { /* implies that cur_disk < NUM_OF_DSK */ + if (dirty) { /* implies that cur_disk < NUM_OF_DSK */ writebuf(); } @@ -493,7 +518,7 @@ int32 dsk12(int32 port, int32 io, int32 data) { writebuf(); /* from above we have that cur_disk < NUM_OF_DSK */ } else { - dirty = 1; /* this guarantees for the next call to writebuf that cur_disk < NUM_OF_DSK */ + dirty = TRUE; /* this guarantees for the next call to writebuf that cur_disk < NUM_OF_DSK */ dskbuf[cur_byte[cur_disk]++] = data & 0xff; } return 0; /* ignored since OUT */ @@ -509,7 +534,7 @@ void writebuf(void) { dskbuf[i++] = 0; } uptr = dsk_dev.units + cur_disk; - if (((uptr -> flags) & UNIT_WLK) == 0) { /* write enabled */ + if (((uptr -> flags) & UNIT_DSKWLK) == 0) { /* write enabled */ if (trace_flag & TRACE_READ_WRITE) { message4("OUT 0x0a (WRITE) D%d T%d S%d\n", cur_disk, cur_track[cur_disk], cur_sect[cur_disk]); } @@ -529,5 +554,5 @@ void writebuf(void) { } cur_flags[cur_disk] &= 0xfe; /* ENWD off */ cur_byte[cur_disk] = 0xff; - dirty = 0; + dirty = FALSE; } diff --git a/AltairZ80/altairZ80_sio.c b/AltairZ80/altairZ80_sio.c index 698149c3..621c9de3 100644 --- a/AltairZ80/altairZ80_sio.c +++ b/AltairZ80/altairZ80_sio.c @@ -1,6 +1,29 @@ /* altairZ80_sio: MITS Altair serial I/O card - Written by Peter Schorn, 2001-2002 - Based on work by Charles E Owen ((c) 1997, Commercial use prohibited) + + Copyright (c) 2002, Peter Schorn + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Peter Schorn shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Peter Schorn. + + Based on work by Charles E Owen (c) 1997 These functions support a simulated MITS 2SIO interface card. The card had two physical I/O ports which could be connected @@ -29,7 +52,7 @@ #include #include -#include "altairZ80_defs.h" +#include "altairz80_defs.h" #include "sim_sock.h" #include "sim_tmxr.h" #include @@ -164,7 +187,7 @@ SIO_TERMINAL sio_terminals[Terminals] = { {0, 0, 0x10, 0x11, 0x02}, {0, 0, 0x16, 0x17, 0x00}, {0, 0, 0x18, 0x19, 0x00} }; TMLN TerminalLines[Terminals] = { {0} }; /* four terminals */ -TMXR altairTMXR = {Terminals, 0, NULL }; /* mux descriptor */ +TMXR altairTMXR = {Terminals, 0, 0 }; /* mux descriptor */ UNIT sio_unit = { UDATA (&sio_svc, UNIT_ATTABLE, 0), KBD_POLL_WAIT }; @@ -200,7 +223,7 @@ DEVICE sio_dev = { "SIO", &sio_unit, sio_reg, sio_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &sio_reset, - NULL, &sio_attach, &sio_detach }; + NULL, &sio_attach, &sio_detach, NULL, 0 }; UNIT ptr_unit = { UDATA (NULL, UNIT_SEQ + UNIT_ATTABLE + UNIT_ROABLE, 0), KBD_POLL_WAIT }; @@ -215,7 +238,7 @@ DEVICE ptr_dev = { "PTR", &ptr_unit, ptr_reg, NULL, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptr_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, NULL, 0 }; UNIT ptp_unit = { UDATA (NULL, UNIT_SEQ + UNIT_ATTABLE, 0), KBD_POLL_WAIT }; @@ -230,7 +253,7 @@ DEVICE ptp_dev = { "PTP", &ptp_unit, ptp_reg, NULL, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptp_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, NULL, 0 }; /* Synthetic device SIMH for communication between Altair and SIMH environment using port 0xfe */ @@ -269,7 +292,7 @@ DEVICE simh_device = { "SIMH", &simh_unit, simh_reg, simh_mod, 1, 10, 31, 1, 16, 4, NULL, NULL, &simh_dev_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, NULL, 0 }; void resetSIOWarningFlags(void) { @@ -317,10 +340,10 @@ t_stat sio_svc(UNIT *uptr) { sim_activate(&sio_unit, sio_unit.wait); /* continue poll */ if (sio_unit.flags & UNIT_ATT) { - if (sim_poll_kbd() == SCPE_STOP) { /* listen for ^E */ + if (sim_poll_kbd() == SCPE_STOP) { /* listen for ^E */ return SCPE_STOP; } - temp = tmxr_poll_conn(&altairTMXR, &sio_unit); /* poll connection */ + temp = tmxr_poll_conn(&altairTMXR); /* poll connection */ if (temp >= 0) { altairTMXR.ldsc[temp] -> rcve = 1; /* enable receive */ } @@ -584,7 +607,7 @@ int32 fromBCD(int32 x) { the pseudo device is left in an unexpected state. 4) Commands requiring parameters and returning results do not exist currently. - + */ #define splimit 10 @@ -747,8 +770,8 @@ int32 simh_in(void) { currentTime -> tm_year - 100 : currentTime -> tm_year); break; case 1: result = toBCD(currentTime -> tm_mon + 1); break; - case 2: result = toBCD(currentTime -> tm_mday); break; - case 3: result = toBCD(currentTime -> tm_hour); break; + case 2: result = toBCD(currentTime -> tm_mday); break; + case 3: result = toBCD(currentTime -> tm_hour); break; case 4: result = toBCD(currentTime -> tm_min); break; case 5: result = toBCD(currentTime -> tm_sec); break; default: result = 0; diff --git a/AltairZ80/altairZ80_sys.c b/AltairZ80/altairZ80_sys.c index 6794889e..6c3a7aa1 100644 --- a/AltairZ80/altairZ80_sys.c +++ b/AltairZ80/altairZ80_sys.c @@ -1,14 +1,38 @@ /* altairz80_sys.c: MITS Altair system interface - Written by Peter Schorn, 2001-2002 - Based on work by Charles E Owen ((c) 1997 - Commercial use prohibited) - Disassembler from Marat Fayzullin ((c) 1995, 1996, 1997 - Commercial use prohibited) + + Copyright (c) 2002, Peter Schorn + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Peter Schorn shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Peter Schorn. + + Based on work by Charles E Owen (c) 1997 + Disassembler from Marat Fayzullin ((c) 1995, 1996, 1997 - Commercial use prohibited) */ #include -#include "altairZ80_defs.h" +#include "altairz80_defs.h" extern DEVICE cpu_dev; extern DEVICE dsk_dev; +extern DEVICE hdsk_dev; extern UNIT cpu_unit; extern REG cpu_reg[]; extern DEVICE sio_dev; @@ -20,7 +44,12 @@ extern char *get_range(char *cptr, t_addr *lo, t_addr *hi, int rdx, t_addr max, char term); extern t_value get_uint(char *cptr, int radix, t_value max, t_stat *status); extern void PutBYTEWrapper(register uint32 Addr, register uint32 Value); +extern void PutBYTEForced(register uint32 Addr, register uint32 Value); extern uint8 GetBYTEWrapper(register uint32 Addr); +extern int32 addressIsInROM(uint32 Addr); +extern int32 addressExists(uint32 Addr); +extern uint32 ROMLow; +extern uint32 ROMHigh; int32 sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag); int32 fprint_sym(FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw); @@ -45,7 +74,7 @@ int32 checkXY(char xy); char sim_name[] = "Altair 8800 (Z80)"; REG *sim_PC = &cpu_reg[0]; int32 sim_emax = 4; -DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &simh_device, &ptr_dev, &ptp_dev, &dsk_dev, NULL }; +DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &simh_device, &ptr_dev, &ptp_dev, &dsk_dev, &hdsk_dev, NULL }; char memoryAccessMessage[80]; const char *sim_stop_messages[] = { @@ -693,18 +722,18 @@ int32 parse_sym(char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw) { val[0] = (uint32) cptr[0]; return SCPE_OK; } - return (cpu_unit.flags & UNIT_CHIP) ? - parse_X80(cptr, addr, val, MnemonicsZ80) : parse_X80(cptr, addr, val, Mnemonics8080); + return parse_X80(cptr, addr, val, cpu_unit.flags & UNIT_CHIP ? MnemonicsZ80 : Mnemonics8080); } /* This is the binary loader. The input file is considered to be a string of literal bytes with no format special format. The - load starts at the current value of the PC. + load starts at the current value of the PC. ROM/NOROM and + ALTAIRROM/NOALTAIRROM settings are ignored. */ int32 sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag) { - int32 i, addr = 0, cnt = 0, org; + int32 i, addr = 0, cnt = 0, org, cntROM = 0, cntNonExist = 0; t_addr j, lo, hi; char *result; t_stat status; @@ -718,7 +747,7 @@ int32 sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag) { return SCPE_IOERR; } } - printf("%d Bytes dumped [%x - %x].\n", hi + 1 - lo, lo, hi); + printf("%d bytes dumped [%x - %x].\n", hi + 1 - lo, lo, hi); } else { if (*cptr == 0) { @@ -732,11 +761,24 @@ int32 sim_load(FILE *fileref, char *cptr, char *fnam, int32 flag) { } org = addr; while ((addr < MAXMEMSIZE) && ((i = getc(fileref)) != EOF)) { - PutBYTEWrapper(addr, i); + PutBYTEForced(addr, i); + if (addressIsInROM(addr)) { + cntROM++; + } + if (!addressExists(addr)) { + cntNonExist++; + } addr++; cnt++; } /* end while */ - printf("%d Bytes loaded at %x.\n", cnt, org); + printf("%d bytes [%d page%s] loaded at %x.\n", cnt, (cnt + 255) >> 8, + ((cnt + 255) >> 8) == 1 ? "" : "s", org); + if (cntROM) { + printf("Warning: %d bytes written to ROM [%04X - %04X].\n", cntROM, ROMLow, ROMHigh); + } + if (cntNonExist) { + printf("Warning: %d bytes written to non-existing memory (for this configuration).\n", cntNonExist); + } } return SCPE_OK; } diff --git a/AltairZ80/altairz80_hdsk.c b/AltairZ80/altairz80_hdsk.c new file mode 100644 index 00000000..2560b8a7 --- /dev/null +++ b/AltairZ80/altairz80_hdsk.c @@ -0,0 +1,384 @@ +/* altairZ80_hdsk.c: simulated hard disk device to increase capacity + + Copyright (c) 2002, Peter Schorn + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Peter Schorn shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Peter Schorn. +*/ + +#include +#include "altairz80_defs.h" + +#define UNIT_V_HDSKWLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_HDSKWLK (1 << UNIT_V_HDSKWLK) +#define UNIT_V_HDSK_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */ +#define UNIT_HDSK_VERBOSE (1 << UNIT_V_HDSK_VERBOSE) +#define HDSK_SECTOR_SIZE 128 /* size of sector */ +#define HDSK_SECTORS_PER_TRACK 32 /* sectors per track */ +#define HDS_MAX_TRACKS 2048 /* number of tracks */ +#define HDSK_TRACK_SIZE (HDSK_SECTOR_SIZE * HDSK_SECTORS_PER_TRACK) +#define HDSK_CAPACITY (HDSK_TRACK_SIZE * HDS_MAX_TRACKS) +#define HDSK_NUMBER 8 /* number of hard disks */ +#define CPM_OK 0 /* indicates to CP/M everything ok */ +#define CPM_ERROR 1 /* indicates to CP/M an error condition */ +#define CPM_EMPTY 0xe5 /* default value for non-existing bytes */ +#define hdsk_none 0 +#define hdsk_reset 1 +#define hdsk_read 2 +#define hdsk_write 3 +#define hdsk_boot_address 0x5c00 + +extern char messageBuffer[]; +extern int32 PCX; +extern UNIT cpu_unit; +extern uint8 M[MAXMEMSIZE][MAXBANKS]; +extern int32 saved_PC; + +extern int32 install_bootrom(void); +extern void printMessage(void); +extern void PutBYTEWrapper(register uint32 Addr, register uint32 Value); +extern void protect(int32 l, int32 h); +extern uint8 GetBYTEWrapper(register uint32 Addr); +extern int32 bootrom[bootrom_size]; + +t_stat hdsk_svc(UNIT *uptr); +t_stat hdsk_boot(int32 unitno, DEVICE *dptr); +int32 hdsk_hasVerbose(void); +int32 hdsk_io(int32 port, int32 io, int32 data); +int32 hdsk_in(void); +int32 hdsk_out(int32 data); +int32 checkParameters(void); +int32 doSeek(void); +int32 doRead(void); +int32 doWrite(void); + +uint8 hdskbuf[HDSK_SECTOR_SIZE]; /* Data Buffer */ +int32 hdskLastCommand = hdsk_none; +int32 hdskCommandPosition = 0; +int32 selectedDisk; +int32 selectedSector; +int32 selectedTrack; +int32 selectedDMA; +int32 hdskTrace; + +UNIT hdsk_unit[] = { + { UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, + { UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, + { UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, + { UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, + { UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, + { UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, + { UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) }, + { UDATA (&hdsk_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_DISABLE + UNIT_ROABLE, HDSK_CAPACITY) } }; + +REG hdsk_reg[] = { + { DRDATA (HDCMD, hdskLastCommand, 32), REG_RO }, + { DRDATA (HDPOS, hdskCommandPosition, 32), REG_RO }, + { DRDATA (HDDSK, selectedDisk, 32), REG_RO }, + { DRDATA (HDSEC, selectedSector, 32), REG_RO }, + { DRDATA (HDTRK, selectedTrack, 32), REG_RO }, + { DRDATA (HDDMA, selectedDMA, 32), REG_RO }, + { DRDATA (HDTRACE, hdskTrace, 8), }, + { NULL } }; + +MTAB hdsk_mod[] = { + { UNIT_HDSKWLK, 0, "write enabled", "WRITEENABLED", NULL }, + { UNIT_HDSKWLK, UNIT_HDSKWLK, "write locked", "LOCKED", NULL }, + /* quiet, no warning messages */ + { UNIT_HDSK_VERBOSE, 0, "QUIET", "QUIET", NULL }, + /* verbose, show warning messages */ + { UNIT_HDSK_VERBOSE, UNIT_HDSK_VERBOSE, "VERBOSE", "VERBOSE", NULL }, + { 0 } }; + +DEVICE hdsk_dev = { + "HDSK", hdsk_unit, hdsk_reg, hdsk_mod, + 8, 10, 31, 1, 8, 8, + NULL, NULL, NULL, + &hdsk_boot, NULL, NULL, NULL, 0 }; + +t_stat hdsk_svc(UNIT *uptr) { + return SCPE_OK; +} + +int32 hdskBoot[bootrom_size] = { + 0xf3, 0x06, 0x80, 0x3e, 0x0e, 0xd3, 0xfe, 0x05, /* 5c00-5c07 */ + 0xc2, 0x05, 0x5c, 0x3e, 0x16, 0xd3, 0xfe, 0x3e, /* 5c08-5c0f */ + 0x12, 0xd3, 0xfe, 0xdb, 0xfe, 0xb7, 0xca, 0x20, /* 5c10-5c17 */ + 0x5c, 0x3e, 0x0c, 0xd3, 0xfe, 0xaf, 0xd3, 0xfe, /* 5c18-5c1f */ + 0x06, 0x20, 0x3e, 0x01, 0xd3, 0xfd, 0x05, 0xc2, /* 5c20-5c27 */ + 0x24, 0x5c, 0x11, 0x08, 0x00, 0x21, 0x00, 0x00, /* 5c28-5c2f */ + 0x0e, 0xb8, 0x3e, 0x02, 0xd3, 0xfd, 0x3a, 0x37, /* 5c30-5c37 */ + 0xff, 0xd6, 0x08, 0xd3, 0xfd, 0x7b, 0xd3, 0xfd, /* 5c38-5c3f */ + 0x7a, 0xd3, 0xfd, 0xaf, 0xd3, 0xfd, 0x7d, 0xd3, /* 5c40-5c47 */ + 0xfd, 0x7c, 0xd3, 0xfd, 0xdb, 0xfd, 0xb7, 0xca, /* 5c48-5c4f */ + 0x53, 0x5c, 0x76, 0x79, 0x0e, 0x80, 0x09, 0x4f, /* 5c50-5c57 */ + 0x0d, 0xc2, 0x60, 0x5c, 0xfb, 0xc3, 0x00, 0x00, /* 5c58-5c5f */ + 0x1c, 0x1c, 0x7b, 0xfe, 0x20, 0xca, 0x73, 0x5c, /* 5c60-5c67 */ + 0xfe, 0x21, 0xc2, 0x32, 0x5c, 0x1e, 0x00, 0x14, /* 5c68-5c6f */ + 0xc3, 0x32, 0x5c, 0x1e, 0x01, 0xc3, 0x32, 0x5c, /* 5c70-5c77 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c78-5c7f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c80-5c87 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c88-5c8f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c90-5c97 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5c98-5c9f */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ca0-5ca7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ca8-5caf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cb0-5cb7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cb8-5cbf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cc0-5cc7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cc8-5ccf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cd0-5cd7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cd8-5cdf */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ce0-5ce7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5ce8-5cef */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cf0-5cf7 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 5cf8-5cff */ +}; + +t_stat hdsk_boot(int32 unitno, DEVICE *dptr) { + int32 i; + if (MEMSIZE < 24*KB) { + printf("Need at least 24KB RAM to boot from hard disk.\n"); + return SCPE_ARG; + } + if (cpu_unit.flags & (UNIT_ALTAIRROM | UNIT_BANKED)) { + if (install_bootrom()) { + printf("ALTAIR boot ROM installed.\n"); + } + /* check whether we are really modifying an LD A,<> instruction */ + if (bootrom[unitNoOffset1 - 1] == LDAInstruction) { + bootrom[unitNoOffset1] = (unitno+NUM_OF_DSK) & 0xff; /* LD A, */ + } + else { /* Attempt to modify non LD A,<> instructions is refused. */ + printf("Incorrect boot ROM offset detected.\n"); + return SCPE_IERR; + } + } + for (i = 0; i < bootrom_size; i++) { + M[i + hdsk_boot_address][0] = hdskBoot[i] & 0xff; + } + saved_PC = hdsk_boot_address; + protect(hdsk_boot_address, hdsk_boot_address + bootrom_size - 1); + return SCPE_OK; +} + +/* returns TRUE iff there exists a disk with VERBOSE */ +int32 hdsk_hasVerbose(void) { + int32 i; + for (i = 0; i < HDSK_NUMBER; i++) { + if (((hdsk_dev.units + i) -> flags) & UNIT_HDSK_VERBOSE) { + return TRUE; + } + } + return FALSE; +} + +/* The hard disk port is 0xfd. It understands the following commands. + +1. reset + ld b,32 + ld a,hdsk_reset +l out (0fdh),a + dec b + jp nz,l + +2. read / write + ; parameter block + cmd: db hdsk_read or hdsk_write + hd: db 0 ; 0 .. 7, defines hard disk to be used + sector: db 0 ; 0 .. 31, defines sector + track: dw 0 ; 0 .. 2047, defines track + dma: dw 0 ; defines where result is placed in memory + + ; routine to execute + ld b,7 ; size of parameter block + ld hl,cmd ; start address of parameter block +l ld a,(hl) ; get byte of parameter block + out (0fdh),a ; send it to port + inc hl ; point to next byte + dec b ; decrement counter + jp nz,l ; again, if not done + in a,(0fdh) ; get result code + +*/ + +/* check the parameters and return TRUE iff parameters are correct or have been repaired */ +int32 checkParameters(void) { + int32 currentFlag; + if ((selectedDisk < 0) || (selectedDisk >= HDSK_NUMBER)) { + if (hdsk_hasVerbose()) { + message2("HDSK%d does not exist, will use HDSK0 instead.\n", selectedDisk); + } + selectedDisk = 0; + } + currentFlag = (hdsk_dev.units + selectedDisk) -> flags; + if ((currentFlag & UNIT_ATT) == 0) { + if (currentFlag & UNIT_HDSK_VERBOSE) { + message2("HDSK%d is not attached.\n", selectedDisk); + } + return FALSE; /* cannot read or write */ + } + if ((selectedSector < 0) || (selectedSector >= HDSK_SECTORS_PER_TRACK)) { + if (currentFlag & UNIT_HDSK_VERBOSE) { + message4("HDSK%d: 0 <= Sector=%02d < %d violated, will use 0 instead.\n", + selectedDisk, selectedSector, HDSK_SECTORS_PER_TRACK); + } + selectedSector = 0; + } + if ((selectedTrack < 0) || (selectedTrack >= HDS_MAX_TRACKS)) { + if (currentFlag & UNIT_HDSK_VERBOSE) { + message4("HDSK%d: 0 <= Track=%04d < %04d violated, will use 0 instead.\n", + selectedDisk, selectedTrack, HDS_MAX_TRACKS); + } + selectedTrack = 0; + } + selectedDMA &= ADDRMASK; + if (hdskTrace) { + message6("%s HDSK%d Sector=%02d Track=%04d DMA=%04x\n", + (hdskLastCommand == hdsk_read) ? "Read" : "Write", + selectedDisk, selectedSector, selectedTrack, selectedDMA); + } + return TRUE; +} + +int32 doSeek(void) { + UNIT *uptr = hdsk_dev.units + selectedDisk; + if (fseek(uptr -> fileref, + HDSK_TRACK_SIZE * selectedTrack + HDSK_SECTOR_SIZE * selectedSector, SEEK_SET)) { + if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { + message4("Could not access HDSK%d Sector=%02d Track=%04d.\n", + selectedDisk, selectedSector, selectedTrack); + } + return CPM_ERROR; + } + else { + return CPM_OK; + } +} + +int32 doRead(void) { + int32 i; + UNIT *uptr = hdsk_dev.units + selectedDisk; + if (doSeek()) { + return CPM_ERROR; + } + if (fread(hdskbuf, HDSK_SECTOR_SIZE, 1, uptr -> fileref) != 1) { + for (i = 0; i < HDSK_SECTOR_SIZE; i++) { + hdskbuf[i] = CPM_EMPTY; + } + if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { + message4("Could not read HDSK%d Sector=%02d Track=%04d.\n", + selectedDisk, selectedSector, selectedTrack); + } + return CPM_OK; /* allows the creation of empty hard disks */ + } + for (i = 0; i < HDSK_SECTOR_SIZE; i++) { + PutBYTEWrapper(selectedDMA + i, hdskbuf[i]); + } + return CPM_OK; +} + +int32 doWrite(void) { + int32 i; + UNIT *uptr = hdsk_dev.units + selectedDisk; + if (((uptr -> flags) & UNIT_HDSKWLK) == 0) { /* write enabled */ + if (doSeek()) { + return CPM_ERROR; + } + for (i = 0; i < HDSK_SECTOR_SIZE; i++) { + hdskbuf[i] = GetBYTEWrapper(selectedDMA + i); + } + if (fwrite(hdskbuf, HDSK_SECTOR_SIZE, 1, uptr -> fileref) != 1) { + if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { + message4("Could not write HDSK%d Sector=%02d Track=%04d.\n", + selectedDisk, selectedSector, selectedTrack); + } + return CPM_ERROR; + } + } + else { + if ((uptr -> flags) & UNIT_HDSK_VERBOSE) { + message4("Could not write to locked HDSK%d Sector=%02d Track=%04d.\n", + selectedDisk, selectedSector, selectedTrack); + } + return CPM_ERROR; + } + return CPM_OK; +} + +int32 hdsk_in(void) { + int32 result; + if ((hdskCommandPosition == 6) && ((hdskLastCommand == hdsk_read) || (hdskLastCommand == hdsk_write))) { + result = checkParameters() ? ((hdskLastCommand == hdsk_read) ? doRead() : doWrite()) : CPM_ERROR; + hdskLastCommand = hdsk_none; + hdskCommandPosition = 0; + return result; + } + else if (hdsk_hasVerbose()) { + message3("Illegal IN command detected (cmd=%d, pos=%d).\n", hdskLastCommand, hdskCommandPosition); + } + return CPM_OK; +} + +int32 hdsk_out(int32 data) { + switch(hdskLastCommand) { + case hdsk_read: + case hdsk_write: + switch(hdskCommandPosition) { + case 0: + selectedDisk = data; + hdskCommandPosition++; + break; + case 1: + selectedSector = data; + hdskCommandPosition++; + break; + case 2: + selectedTrack = data; + hdskCommandPosition++; + break; + case 3: + selectedTrack += (data << 8); + hdskCommandPosition++; + break; + case 4: + selectedDMA = data; + hdskCommandPosition++; + break; + case 5: + selectedDMA += (data << 8); + hdskCommandPosition++; + break; + default: + hdskLastCommand = hdsk_none; + hdskCommandPosition = 0; + } + break; + default: + hdskLastCommand = data; + hdskCommandPosition = 0; + } + return 0; /* ignored, since OUT */ +} + +int32 hdsk_io(int32 port, int32 io, int32 data) { + return io == 0 ? hdsk_in() : hdsk_out(data); +} diff --git a/GRI/gri_cpu.c b/GRI/gri_cpu.c index 26b5dbb9..9bb2ead3 100644 --- a/GRI/gri_cpu.c +++ b/GRI/gri_cpu.c @@ -134,8 +134,8 @@ 4. Adding I/O devices. These modules must be modified: gri_defs.h add interrupt request definition - gri_cpu.c add dispatches to dev_tab - gri_sys.c add pointer to data structures to sim_devices + gri_cpu.c add dev_tab table entry + gri_sys.c add sim_devices table entry */ #include "gri_defs.h" @@ -342,7 +342,6 @@ REG cpu_reg[] = { { FLDATA (BKP, bkp, 0) }, { BRDATA (SCQ, scq, 8, 15, SCQ_SIZE), REG_RO+REG_CIRC }, { ORDATA (SCQP, scq_p, 6), REG_HRO }, - { FLDATA (NOEAO, cpu_unit.flags, UNIT_V_NOEAO), REG_HRO }, { FLDATA (STOP_OPR, stop_opr, 0) }, { ORDATA (WRU, sim_int_char, 8) }, { NULL } }; @@ -845,7 +844,7 @@ BSW = BPK = 0; for (i = 0; i < 6; i++) GR[i] = 0; dev_done = dev_done & ~INT_PENDING; scq_r = find_reg ("SCQ", NULL, dptr); -if (scq_r) scq_r -> qptr = 0; +if (scq_r) scq_r->qptr = 0; else return SCPE_IERR; sim_brk_types = sim_brk_dflt = SWMASK ('E'); return SCPE_OK; diff --git a/GRI/gri_defs.h b/GRI/gri_defs.h index 4e211075..f74c96cb 100644 --- a/GRI/gri_defs.h +++ b/GRI/gri_defs.h @@ -23,6 +23,8 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 19-Sep-02 RMS Fixed declarations in gdev structure + There are several discrepancies between the original GRI-909 Reference Manual of 1969 and the only surviving code sample, the MIT Crystal Growing System of 1972: @@ -113,10 +115,10 @@ #define U_TTY 077 /* console */ struct gdev { - int32 (*Src)(); /* source */ - t_stat (*Dst)(); /* dest */ - t_stat (*FO)(); /* func out */ - int32 (*SF)(); /* skip func */ + uint32 (*Src)(uint32); /* source */ + t_stat (*Dst)(uint32, uint32); /* dest */ + t_stat (*FO)(uint32); /* func out */ + uint32 (*SF)(uint32); /* skip func */ }; /* Trap (jump) */ diff --git a/GRI/gri_doc.txt b/GRI/gri_doc.txt index 626453e1..dcbd7b44 100644 --- a/GRI/gri_doc.txt +++ b/GRI/gri_doc.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik Subj: GRI-909 Simulator Usage -Date: 15-Jul-02 +Date: 15-Nov-2002 COPYRIGHT NOTICE @@ -37,9 +37,13 @@ This memorandum documents the GRI-909 simulator. 1. Simulator Files sim/ sim_defs.h + sim_rev.h + sim_sock.h + sim_tmxr.h scp.c scp_tty.c - sim_rev.c + sim_sock.c + sim_tmxr.c sim/gri/ gri_defs.h gri_cpu.c @@ -66,7 +70,13 @@ The GRI-909 simulator implements the following unique stop conditions: STOP_OPR is set - an invalid interrupt request is made -The LOAD and DUMP commands are not implemented. +The LOAD commands has an optional argument to specify the load address: + + LOAD {} + +The LOAD command loads a paper-tape bootstrap format file at the specified +address. If no address is specified, loading starts at location 200. The +DUMP command is not supported. 2.1 CPU @@ -129,9 +139,6 @@ The paper tape reader (HSR) reads data from or a disk file. The POS register specifies the number of the next data item to be read. Thus, by changing POS, the user can backspace or advance the reader. -The paper tape reader supports the BOOT command. BOOT HSR copies the -boot loader into memory and starts it running. - The paper tape reader implements these registers: name size comments @@ -183,6 +190,13 @@ Error handling is as follows: 2.2.3 S42-001 Teletype Input (TTI) +The Teletype interfaces (TTI, TTO) can be set to one of three modes: +KSR, 7B, or 8B. In KSR mode, lower case input and output characters +are automatically converted to upper case, and the high order bit is +forced to one on input. In 7B mode, input and output characters are +masked to 7 bits. In 8B mode, characters are not modified. Changing +the mode of either interface changes both. The default mode is KSR. + The Teletype input (TTI) polls the console keyboard for input. It implements these registers: @@ -196,8 +210,8 @@ implements these registers: 2.2.4 S42-002 Teletype Output (TTO) -The Teletype output (TTO) writes to the simulator console window. -It implements these registers: +The Teletype output (TTO) writes to the simulator console window. It +implements these registers: name size comments diff --git a/GRI/gri_stddev.c b/GRI/gri_stddev.c index 6cda663a..fa880be8 100644 --- a/GRI/gri_stddev.c +++ b/GRI/gri_stddev.c @@ -28,13 +28,17 @@ hsr S42-004 high speed reader hsp S42-006 high speed punch rtc real time clock + + 01-Nov-02 RMS Added 7b/8B support to terminal */ #include "gri_defs.h" #include -#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */ -#define UNIT_UC (1 << UNIT_V_UC) +#define UNIT_V_8B (UNIT_V_UF + 0) /* 8B */ +#define UNIT_V_KSR (UNIT_V_UF + 1) /* KSR33 */ +#define UNIT_8B (1 << UNIT_V_8B) +#define UNIT_KSR (1 << UNIT_V_KSR) uint32 hsr_stopioe = 1, hsp_stopioe = 1; @@ -45,6 +49,7 @@ t_stat tti_svc (UNIT *uhsr); t_stat tto_svc (UNIT *uhsr); t_stat tti_reset (DEVICE *dhsr); t_stat tto_reset (DEVICE *dhsr); +t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat hsr_svc (UNIT *uhsr); t_stat hsp_svc (UNIT *uhsr); t_stat hsr_reset (DEVICE *dhsr); @@ -61,7 +66,7 @@ int32 rtc_tps = 1000; tti_mod TTI modifiers list */ -UNIT tti_unit = { UDATA (&tti_svc, UNIT_UC, 0), KBD_POLL_WAIT }; +UNIT tti_unit = { UDATA (&tti_svc, UNIT_KSR, 0), KBD_POLL_WAIT }; REG tti_reg[] = { { ORDATA (BUF, tti_unit.buf, 8) }, @@ -69,12 +74,13 @@ REG tti_reg[] = { { FLDATA (IENB, ISR, INT_V_TTI) }, { DRDATA (POS, tti_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, - { FLDATA (UC, tti_unit.flags, UNIT_V_UC), REG_HRO }, + { FLDATA (UC, tti_unit.flags, UNIT_V_KSR), REG_HRO }, { NULL } }; MTAB tti_mod[] = { - { UNIT_UC, 0, "lower case", "LC", NULL }, - { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, + { UNIT_KSR+UNIT_8B, UNIT_KSR, "KSR", "KSR", &tty_set_mode }, + { UNIT_KSR+UNIT_8B, 0 , "7b" , "7B" , &tty_set_mode }, + { UNIT_KSR+UNIT_8B, UNIT_8B , "8b" , "8B" , &tty_set_mode }, { 0 } }; DEVICE tti_dev = { @@ -90,7 +96,7 @@ DEVICE tti_dev = { tto_reg TTO register list */ -UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT }; +UNIT tto_unit = { UDATA (&tto_svc, UNIT_KSR, 0), SERIAL_OUT_WAIT }; REG tto_reg[] = { { ORDATA (BUF, tto_unit.buf, 8) }, @@ -100,8 +106,14 @@ REG tto_reg[] = { { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT }, { NULL } }; +MTAB tto_mod[] = { + { UNIT_KSR+UNIT_8B, UNIT_KSR, "KSR", "KSR", &tty_set_mode }, + { UNIT_KSR+UNIT_8B, 0 , "7b" , "7B" , &tty_set_mode }, + { UNIT_KSR+UNIT_8B, UNIT_8B , "8b" , "8B" , &tty_set_mode }, + { 0 } }; + DEVICE tto_dev = { - "TTO", &tto_unit, tto_reg, NULL, + "TTO", &tto_unit, tto_reg, tto_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &tto_reset, NULL, NULL, NULL }; @@ -212,14 +224,15 @@ return 0; t_stat tti_svc (UNIT *uhsr) { -int32 temp; +int32 c; sim_activate (&tti_unit, tti_unit.wait); /* continue poll */ -if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */ -temp = temp & 0177; -if ((tti_unit.flags & UNIT_UC) && islower (temp)) - temp = toupper (temp); -tti_unit.buf = temp | 0200; /* got char */ +if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */ +if (tti_unit.flags & UNIT_KSR) { /* KSR? */ + c = c & 0177; /* force 7b */ + if (islower (c)) c = toupper (c); /* cvt to UC */ + tti_unit.buf = c | 0200; } /* add TTY bit */ +else tti_unit.buf = c & ((tti_unit.flags & UNIT_8B)? 0377: 0177); dev_done = dev_done | INT_TTI; /* set ready */ tti_unit.pos = tti_unit.pos + 1; return SCPE_OK; @@ -227,10 +240,15 @@ return SCPE_OK; t_stat tto_svc (UNIT *uhsr) { -int32 temp; +int32 c; +t_stat r; dev_done = dev_done | INT_TTO; /* set ready */ -if ((temp = sim_putchar (tto_unit.buf & 0177)) != SCPE_OK) return temp; +if (tto_unit.flags & UNIT_KSR) { /* KSR? */ + c = tto_unit.buf & 0177; /* force 7b */ + if (islower (c)) c = toupper (c); } /* cvt to UC */ +else c = tto_unit.buf & ((tto_unit.flags & UNIT_8B)? 0377: 0177); +if ((r = sim_putchar (c)) != SCPE_OK) return r; /* output */ tto_unit.pos = tto_unit.pos + 1; return SCPE_OK; } @@ -252,6 +270,13 @@ dev_done = dev_done | INT_TTO; /* set ready */ sim_cancel (&tto_unit); /* deactivate unit */ return SCPE_OK; } + +t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +tti_unit.flags = (tti_unit.flags & ~(UNIT_KSR | UNIT_8B)) | val; +tto_unit.flags = (tto_unit.flags & ~(UNIT_KSR | UNIT_8B)) | val; +return SCPE_OK; +} /* High speed paper tape function processors */ diff --git a/GRI/gri_sys.c b/GRI/gri_sys.c index e8c75c23..6fab34e3 100644 --- a/GRI/gri_sys.c +++ b/GRI/gri_sys.c @@ -22,6 +22,8 @@ Except as contained in this notice, the name of Robert M Supnik shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + + 18-Oct-02 RMS Fixed bug in symbolic decode (found by Hans Pufal) */ #include "gri_defs.h" @@ -320,7 +322,7 @@ src = I_GETSRC (inst); /* get fields */ op = I_GETOP (inst); dst = I_GETDST (inst); bop = op >> 2; /* bus op */ -for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ +for (i = 0; opcode[i] != NULL; i++) { /* loop thru ops */ j = (opc_val[i] >> F_V_FL) & F_M_FL; /* get class */ if ((opc_val[i] & DMASK) == (inst & masks[j])) { /* match? */ diff --git a/H316/h316_cpu.c b/H316/h316_cpu.c index f0d5c33f..f232b25f 100644 --- a/H316/h316_cpu.c +++ b/H316/h316_cpu.c @@ -184,7 +184,7 @@ 4. Adding I/O devices. These modules must be modified: h316_defs.h add interrupt request definition - h316_cpu.c add device information table entry + h316_cpu.c add device dispatch table entry h316_sys.c add sim_devices table entry */ @@ -280,8 +280,6 @@ REG cpu_reg[] = { { ORDATA (PCQP, pcq_p, 6), REG_HRO }, { ORDATA (WRU, sim_int_char, 8) }, { FLDATA (DLOG, dlog, 0), REG_HIDDEN }, - { FLDATA (HEXT, cpu_unit.flags, UNIT_V_EXT), REG_HRO }, - { FLDATA (HSA, cpu_unit.flags, UNIT_V_HSA), REG_HRO }, { NULL } }; MTAB cpu_mod[] = { @@ -767,7 +765,7 @@ case 060: saved_AR = AR & DMASK; saved_BR = BR & DMASK; saved_XR = XR & DMASK; -pcq_r -> qptr = pcq_p; /* update pc q ptr */ +pcq_r->qptr = pcq_p; /* update pc q ptr */ return reason; } @@ -788,7 +786,7 @@ return reason; t_stat Ea (int32 IR, int32 *addr) { -int32 i = 0; +int32 i; int32 Y = IR & (IA | DISP); /* ind + disp */ if (IR & SC) Y = ((PC - 1) & PAGENO) | Y; /* cur sec? + pageno */ @@ -972,8 +970,8 @@ if (cbitl) { /* ovflo to C */ 0 x x can't overflow A 0 0 can't overflow A -1 1 can't overflow - A 0 1 overflow if 77777 -> 100000 - A -1 0 overflow if 100000 -> 77777 + A 0 1 overflow if 77777->100000 + A -1 0 overflow if 100000->77777 */ if (!jamkn && @@ -995,7 +993,7 @@ ext = pme = extoff_pending = 0; dev_ready = dev_ready & ~INT_PENDING; dev_enable = 0; pcq_r = find_reg ("PCQ", NULL, dptr); -if (pcq_r) pcq_r -> qptr = 0; +if (pcq_r) pcq_r->qptr = 0; else return SCPE_IERR; sim_brk_types = sim_brk_dflt = SWMASK ('E'); return SCPE_OK; diff --git a/H316/h316_defs.h b/H316/h316_defs.h index 1ee39506..cc2061bf 100644 --- a/H316/h316_defs.h +++ b/H316/h316_defs.h @@ -55,8 +55,8 @@ /* CPU options */ #define UNIT_V_EXT (UNIT_V_UF + 1) /* extended mem */ -#define UNIT_EXT (1 << UNIT_V_EXT) #define UNIT_V_HSA (UNIT_V_UF + 2) /* high speed arith */ +#define UNIT_EXT (1 << UNIT_V_EXT) #define UNIT_HSA (1 << UNIT_V_HSA) /* Instruction format */ diff --git a/H316/h316_doc.txt b/H316/h316_doc.txt index 924a6a94..e050f53f 100644 --- a/H316/h316_doc.txt +++ b/H316/h316_doc.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik Subj: H316 Simulator Usage -Date: 15-Jun-2002 +Date: 15-Nov-2002 COPYRIGHT NOTICE @@ -31,7 +31,7 @@ The following copyright notice applies to both the SIMH source and binary: be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. -This memorandum documents Honeywell 316/516 simulator. +This memorandum documents the Honeywell 316/516 simulator. 1. Simulator Files @@ -39,9 +39,13 @@ This memorandum documents Honeywell 316/516 simulator. The H316 requires the following files: sim/ sim_defs.h + sim_rev.h + sim_sock.h + sim_tmxr.h scp.c scp_tty.c - sim_rev.c + sim_sock.c + sim_tmxr.c sim/h316/ h316_defs.h h316_cpu.c @@ -183,12 +187,15 @@ Error handling is as follows: 2.2.3 316/516-33 Console Teletype (TTY) -The terminal reads from the console keyboard and writes to the -simulator console window. The terminal has one option, UC; when -set, the terminal automatically converts lower case input to upper -case. This is on by default. +The Teletype units (TTY0, TTY1) can be set to one of three modes: +KSR, 7B, or 8B. In KSR mode, lower case input and output characters +are automatically converted to upper case, and the high order bit is +forced to one on input. In 7B mode, input and output characters are +masked to 7 bits. In 8B mode, characters are not modified. Changing +the mode of either unit changes both. The default mode is KSR. -The terminal implements these registers: +The Teletype reads from the console keyboard and writes to the +simulator console window. It implements these registers: name size comments diff --git a/H316/h316_lp.c b/H316/h316_lp.c index f0ea4541..efd9e8e8 100644 --- a/H316/h316_lp.c +++ b/H316/h316_lp.c @@ -228,9 +228,9 @@ if (lpt_svcst & LPT_SVCPA) { /* paper advance */ for (i = LPT_WIDTH - 1; i >= 0; i++) { if (lpt_buf[i] != ' ') break; } lpt_buf[i + 1] = 0; - fputs (lpt_buf, uptr -> fileref); /* output buf */ - fputs (lpt_cc[lpt_svcch & 03], uptr -> fileref); /* output eol */ - uptr -> pos = ftell (uptr -> fileref); /* update pos */ + fputs (lpt_buf, uptr->fileref); /* output buf */ + fputs (lpt_cc[lpt_svcch & 03], uptr->fileref); /* output eol */ + uptr->pos = ftell (uptr->fileref); /* update pos */ for (i = 0; i < LPT_WIDTH; i++) lpt_buf[i] = ' '; /* clear buf */ } lpt_svcst = 0; diff --git a/H316/h316_stddev.c b/H316/h316_stddev.c index 87655f11..a54cf8e4 100644 --- a/H316/h316_stddev.c +++ b/H316/h316_stddev.c @@ -28,6 +28,7 @@ tty 316/516-33 teleprinter clk/options 316/516-12 real time clocks/internal options + 01-Nov-02 RMS Added 7b/8b support to terminal 30-May-02 RMS Widened POS to 32b 03-Nov-01 RMS Implemented upper case for console output 29-Nov-01 RMS Added read only unit support @@ -36,8 +37,11 @@ #include "h316_defs.h" #include -#define UNIT_V_UC (UNIT_V_UF + 1) /* UC only */ -#define UNIT_UC (1 << UNIT_V_UC) + +#define UNIT_V_8B (UNIT_V_UF + 0) /* 8B */ +#define UNIT_V_KSR (UNIT_V_UF + 1) /* KSR33 */ +#define UNIT_8B (1 << UNIT_V_8B) +#define UNIT_KSR (1 << UNIT_V_KSR) extern uint16 M[]; extern int32 PC; @@ -45,18 +49,21 @@ extern int32 stop_inst; extern int32 C, dp, ext, extoff_pending, sc; extern int32 dev_ready, dev_enable; extern UNIT cpu_unit; + int32 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */ int32 ptp_power = 0, ptp_ptime; /* punch power, time */ int32 tty_mode = 0, tty_buf = 0; /* tty mode, buf */ int32 clk_tps = 60; /* ticks per second */ + t_stat ptr_svc (UNIT *uptr); t_stat ptr_reset (DEVICE *dptr); -t_stat ptr_boot (int32 unitno); +t_stat ptr_boot (int32 unitno, DEVICE *dptr); t_stat ptp_svc (UNIT *uptr); t_stat ptp_reset (DEVICE *dptr); t_stat tti_svc (UNIT *uptr); t_stat tto_svc (UNIT *uptr); t_stat tty_reset (DEVICE *dptr); +t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat clk_svc (UNIT *uptr); t_stat clk_reset (DEVICE *dptr); @@ -128,8 +135,8 @@ DEVICE ptp_dev = { #define TTO 1 UNIT tty_unit[] = { - { UDATA (&tti_svc, UNIT_UC, 0), KBD_POLL_WAIT }, - { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT } }; + { UDATA (&tti_svc, UNIT_KSR, 0), KBD_POLL_WAIT }, + { UDATA (&tto_svc, UNIT_KSR, 0), SERIAL_OUT_WAIT } }; REG tty_reg[] = { { ORDATA (BUF, tty_buf, 8) }, @@ -140,12 +147,12 @@ REG tty_reg[] = { { DRDATA (KTIME, tty_unit[TTI].wait, 24), REG_NZ + PV_LEFT }, { DRDATA (TPOS, tty_unit[TTO].pos, 32), PV_LEFT }, { DRDATA (TTIME, tty_unit[TTO].wait, 24), REG_NZ + PV_LEFT }, - { FLDATA (UC, tty_unit[TTI].flags, UNIT_V_UC), REG_HRO }, { NULL } }; MTAB tty_mod[] = { - { UNIT_UC, 0, "lower case", "LC", NULL }, - { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, + { UNIT_KSR+UNIT_8B, UNIT_KSR, "KSR", "KSR", &tty_set_mode }, + { UNIT_KSR+UNIT_8B, 0 , "7b" , "7B" , &tty_set_mode }, + { UNIT_KSR+UNIT_8B, UNIT_8B , "8b" , "8B" , &tty_set_mode }, { 0 } }; DEVICE tty_dev = { @@ -259,7 +266,7 @@ static const int32 pboot[] = { 0100040 /* SZE */ }; -t_stat ptr_boot (int32 unit) +t_stat ptr_boot (int32 unitno, DEVICE *dptr) { int32 i; @@ -384,30 +391,34 @@ return dat; t_stat tti_svc (UNIT *uptr) { -int32 temp; +int32 out, c; sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* continue poll */ -if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */ -temp = temp & 0177; -if ((tty_unit[TTI].flags & UNIT_UC) && islower (temp)) /* force upper case? */ - temp = toupper (temp); +if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */ +out = c & 0177; /* mask echo to 7b */ +if (tty_unit[TTI].flags & UNIT_KSR) { /* KSR? */ + if (islower (out)) out = toupper (out); /* cvt to UC */ + c = out | 0200; } /* add TTY bit */ +else c = c & ((tty_unit[TTI].flags & UNIT_8B)? 0377: 0177); if (tty_mode == 0) { /* input mode? */ - tty_buf = temp | 0200; /* put char in buf */ + tty_buf = c; /* put char in buf */ tty_unit[TTI].pos = tty_unit[TTI].pos + 1; SET_READY (INT_TTY); /* set flag */ - sim_putchar (temp); } /* echo */ + sim_putchar (out); } /* echo */ return SCPE_OK; } t_stat tto_svc (UNIT *uptr) { -int32 ch, temp; +int32 c; +t_stat r; SET_READY (INT_TTY); /* set done flag */ -ch = tty_buf & 0177; /* get char */ -if ((tty_unit[TTO].flags & UNIT_UC) && islower (ch)) /* force upper case? */ - ch = toupper (ch); -if ((temp = sim_putchar (ch)) != SCPE_OK) return temp; /* output char */ +if (tty_unit[TTO].flags & UNIT_KSR) { /* UC only? */ + c = tty_buf & 0177; /* mask to 7b */ + if (islower (c)) c = toupper (c); } /* cvt to UC */ +else c = tty_buf & ((tty_unit[TTO].flags & UNIT_8B)? 0377: 0177); +if ((r = sim_putchar (c)) != SCPE_OK) return r; /* output char */ tty_unit[TTO].pos = tty_unit[TTO].pos + 1; return SCPE_OK; } @@ -424,6 +435,13 @@ sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* activate poll */ sim_cancel (&tty_unit[TTO]); /* cancel output */ return SCPE_OK; } + +t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +tty_unit[TTI].flags = (tty_unit[TTI].flags & ~(UNIT_KSR | UNIT_8B)) | val; +tty_unit[TTO].flags = (tty_unit[TTO].flags & ~(UNIT_KSR | UNIT_8B)) | val; +return SCPE_OK; +} /* Clock/options: IO routine */ diff --git a/HP2100/hp2100_cpu.c b/HP2100/hp2100_cpu.c index 85d9694a..f9017369 100644 --- a/HP2100/hp2100_cpu.c +++ b/HP2100/hp2100_cpu.c @@ -23,6 +23,11 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 24-Oct-02 RMS Fixed bugs in IOP and extended instructions + Fixed bugs in memory protection and DMS + Added clock calibration + 25-Sep-02 RMS Fixed bug in DMS decode (found by Robert Alan Byer) + 26-Jul-02 RMS Restructured extended instructions, added IOP support 22-Mar-02 RMS Changed to allocate memory array dynamically 11-Mar-02 RMS Cleaned up setjmp/auto variable interaction 17-Feb-02 RMS Added DMS support @@ -41,19 +46,26 @@ 21-Nov-00 RMS Fixed bug in reset routine 15-Oct-00 RMS Added dynamic device number support - The register state for the HP 2100 CPU is: + The register state for the HP 2116 CPU is: - AR<15:0> A register - addressable as location 0 - BR<15:0> B register - addressable as location 1 - PC<14:0> P register (program counter) - SR<15:0> S register - E extend flag (carry out) - O overflow flag + AR<15:0> A register - addressable as location 0 + BR<15:0> B register - addressable as location 1 + PC<14:0> P register (program counter) + SR<15:0> S register + E extend flag (carry out) + O overflow flag - The 21MX adds a pair of index registers: + The 2100 adds memory protection logic: - XR<15:0> X register - YR<15:0> Y register + mp_fence<14:0> memory fence register + mp_viol<15:0> memory protection violation register (F register) + + The 21MX adds a pair of index registers and memory expansion logic: + + XR<15:0> X register + YR<15:0> Y register + dms_sr<15:0> dynamic memory system status register + dms_vr<15:0> dynamic memory system violation register The original HP 2116 has four instruction formats: memory reference, shift, alter/skip, and I/O. The HP 2100 added extended memory reference @@ -245,8 +257,17 @@ 4. Adding I/O devices. These modules must be modified: hp2100_defs.h add interrupt request definition - hp2100_cpu.c add device information table entry hp2100_sys.c add sim_devices table entry + + 5. Instruction interruptibility. The simulator is fast enough, compared + to the run-time of the longest instructions, for interruptibility not + to matter. But the HP diagnostics explicitly test interruptibility in + EIS and DMS instructions, and long indirect address chains. Accordingly, + the simulator does "just enough" to pass these tests. In particular, if + an interrupt is pending but deferred at the beginning of an interruptible + instruction, the interrupt is taken at the appropriate point; but there + is no testing for new interrupts during execution (that is, the event + timer is not called). */ #include "hp2100_defs.h" @@ -255,97 +276,126 @@ #define PCQ_SIZE 64 /* must be 2**n */ #define PCQ_MASK (PCQ_SIZE - 1) #define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = err_PC -#define UNIT_V_MSIZE (UNIT_V_UF) /* dummy mask */ -#define UNIT_MSIZE (1 << UNIT_V_MSIZE) -#define UNIT_V_2100 (UNIT_V_UF + 1) /* 2100 vs 2116 */ + +#define UNIT_V_2100 (UNIT_V_UF + 0) /* 2100 */ +#define UNIT_V_21MX (UNIT_V_UF + 1) /* 21MX */ +#define UNIT_V_EAU (UNIT_V_UF + 2) /* EAU */ +#define UNIT_V_FP (UNIT_V_UF + 3) /* FP */ +#define UNIT_V_MPR (UNIT_V_UF + 4) /* mem prot */ +#define UNIT_V_DMS (UNIT_V_UF + 5) /* DMS */ +#define UNIT_V_IOP (UNIT_V_UF + 6) /* IOP */ +#define UNIT_V_MSIZE (UNIT_V_UF + 7) /* dummy mask */ #define UNIT_2100 (1 << UNIT_V_2100) -#define UNIT_V_21MX (UNIT_V_UF + 2) /* 21MX vs 2100 */ #define UNIT_21MX (1 << UNIT_V_21MX) +#define UNIT_EAU (1 << UNIT_V_EAU) +#define UNIT_FP (1 << UNIT_V_FP) +#define UNIT_MPR (1 << UNIT_V_MPR) +#define UNIT_DMS (1 << UNIT_V_DMS) +#define UNIT_IOP (1 << UNIT_V_IOP) +#define UNIT_MSIZE (1 << UNIT_V_MSIZE) + +#define MOD_2116 1 +#define MOD_2100 2 +#define MOD_21MX 4 + #define ABORT(val) longjmp (save_env, (val)) #define DMAR0 1 #define DMAR1 2 -#define SEXT(x) (((x) & SIGN)? (((int32) (x)) | ~DMASK): ((int32) (x))) - -/* Memory protection tests */ - -#define MP_TEST(x) (CTL (PRO) && ((x) > 1) && ((x) < mfence)) - -#define MP_TESTJ(x) (CTL (PRO) && ((x) < mfence)) uint16 *M = NULL; /* memory */ -int32 saved_AR = 0; /* A register */ -int32 saved_BR = 0; /* B register */ -int32 PC = 0; /* P register */ -int32 SR = 0; /* S register */ -int32 XR = 0; /* X register */ -int32 YR = 0; /* Y register */ -int32 E = 0; /* E register */ -int32 O = 0; /* O register */ -int32 dev_cmd[2] = { 0 }; /* device command */ -int32 dev_ctl[2] = { 0 }; /* device control */ -int32 dev_flg[2] = { 0 }; /* device flags */ -int32 dev_fbf[2] = { 0 }; /* device flag bufs */ +uint32 saved_AR = 0; /* A register */ +uint32 saved_BR = 0; /* B register */ +uint32 PC = 0; /* P register */ +uint32 SR = 0; /* S register */ +uint32 XR = 0; /* X register */ +uint32 YR = 0; /* Y register */ +uint32 E = 0; /* E register */ +uint32 O = 0; /* O register */ +uint32 dev_cmd[2] = { 0 }; /* device command */ +uint32 dev_ctl[2] = { 0 }; /* device control */ +uint32 dev_flg[2] = { 0 }; /* device flags */ +uint32 dev_fbf[2] = { 0 }; /* device flag bufs */ struct DMA dmac[2] = { { 0 }, { 0 } }; /* DMA channels */ -int32 ion = 0; /* interrupt enable */ -int32 ion_defer = 0; /* interrupt defer */ -int32 intaddr = 0; /* interrupt addr */ -int32 mfence = 0; /* mem prot fence */ -int32 maddr = 0; /* mem prot err addr */ -int32 err_PC = 0; /* error PC */ -int32 dms_enb = 0; /* dms enable */ -int32 dms_ump = 0; /* dms user map */ -int32 dms_sr = 0; /* dms status register */ -int32 dms_fence = 0; /* dms base page fence */ -int32 dms_vr = 0; /* dms violation register */ -int32 dms_sma = 0; /* dms saved ma */ -int32 dms_map[MAP_NUM * MAP_LNT] = { 0 }; /* dms maps */ -int32 ind_max = 16; /* iadr nest limit */ -int32 stop_inst = 1; /* stop on ill inst */ -int32 stop_dev = 2; /* stop on ill dev */ +uint32 ion = 0; /* interrupt enable */ +uint32 ion_defer = 0; /* interrupt defer */ +uint32 intaddr = 0; /* interrupt addr */ +uint32 mp_fence = 0; /* mem prot fence */ +uint32 mp_viol = 0; /* mem prot viol reg */ +uint32 mp_mevff = 0; /* mem exp (dms) viol */ +uint32 mp_evrff = 1; /* update mp_viol */ +uint32 err_PC = 0; /* error PC */ +uint32 dms_enb = 0; /* dms enable */ +uint32 dms_ump = 0; /* dms user map */ +uint32 dms_sr = 0; /* dms status reg */ +uint32 dms_vr = 0; /* dms violation reg */ +uint32 dms_map[MAP_NUM * MAP_LNT] = { 0 }; /* dms maps */ +uint32 ind_max = 16; /* iadr nest limit */ +uint32 stop_inst = 1; /* stop on ill inst */ +uint32 stop_dev = 0; /* stop on ill dev */ uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ -int32 pcq_p = 0; /* PC queue ptr */ +uint32 pcq_p = 0; /* PC queue ptr */ REG *pcq_r = NULL; /* PC queue reg ptr */ jmp_buf save_env; /* abort handler */ +struct opt_table { /* options table */ + int32 optf; + int32 cpuf; }; + +static struct opt_table opt_val[] = { + { UNIT_EAU, MOD_2116 }, + { UNIT_FP, MOD_2100 }, + { UNIT_MPR, MOD_2100 | MOD_21MX }, + { UNIT_DMS, MOD_21MX }, + { UNIT_IOP, MOD_2100 }, + { 0, 0 } }; + extern int32 sim_interval; extern int32 sim_int_char; extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ extern FILE *sim_log; +extern DEVICE *sim_devices[]; -uint8 ReadB (int32 addr); -uint8 ReadBA (int32 addr); -uint16 ReadW (int32 addr); -uint16 ReadWA (int32 addr); -uint32 ReadF (int32 addr); -uint16 ReadIO (int32 addr, int32 map); -void WriteB (int32 addr, int32 dat); -void WriteBA (int32 addr, int32 dat); -void WriteW (int32 addr, int32 dat); -void WriteWA (int32 addr, int32 dat); -void WriteIO (int32 addr, int32 dat, int32 map); -int32 dms (int32 va, int32 map, int32 prot); -uint16 dms_rmap (int32 mapi); -void dms_wmap (int32 mapi, int32 dat); -void dms_viol (int32 va, int32 st, t_bool io); -int32 dms_upd_sr (void); -int32 shift (int32 inval, int32 flag, int32 oper); -int32 calc_dma (void); -int32 calc_int (void); -void dma_cycle (int32 chan, int32 map); +t_stat Ea (uint32 IR, uint32 *addr, uint32 irq); +t_stat Ea1 (uint32 *addr, uint32 irq); +uint8 ReadB (uint32 addr); +uint8 ReadBA (uint32 addr); +uint16 ReadW (uint32 addr); +uint16 ReadWA (uint32 addr); +uint32 ReadF (uint32 addr); +uint16 ReadIO (uint32 addr, uint32 map); +void WriteB (uint32 addr, uint32 dat); +void WriteBA (uint32 addr, uint32 dat); +void WriteW (uint32 addr, uint32 dat); +void WriteWA (uint32 addr, uint32 dat); +void WriteIO (uint32 addr, uint32 dat, uint32 map); +t_stat iogrp (uint32 ir, uint32 iotrap); +uint32 dms (uint32 va, uint32 map, uint32 prot); +uint32 dms_io (uint32 va, uint32 map); +void mp_dms_jmp (uint32 va); +uint16 dms_rmap (uint32 mapi); +void dms_wmap (uint32 mapi, uint32 dat); +void dms_viol (uint32 va, uint32 st); +uint32 dms_upd_sr (void); +uint32 shift (uint32 inval, uint32 flag, uint32 oper); +uint32 calc_dma (void); +uint32 calc_int (void); +void dma_cycle (uint32 chan, uint32 map); t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); t_stat dma0_reset (DEVICE *dptr); t_stat dma1_reset (DEVICE *dptr); t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc); t_bool dev_conflict (void); -extern int32 f_as (uint32 op, t_bool sub); -extern int32 f_mul (uint32 op); -extern int32 f_div (uint32 op); -extern int32 f_fix (void); -extern void f_flt (void); +extern uint32 f_as (uint32 op, t_bool sub); +extern uint32 f_mul (uint32 op); +extern uint32 f_div (uint32 op); +extern uint32 f_fix (void); +extern uint32 f_flt (void); +extern int32 clk_delay (int32 flg); /* CPU data structures @@ -364,6 +414,7 @@ REG cpu_reg[] = { { ORDATA (X, XR, 16) }, { ORDATA (Y, YR, 16) }, { ORDATA (S, SR, 16) }, + { ORDATA (F, mp_fence, 15) }, { FLDATA (E, E, 0) }, { FLDATA (O, O, 0) }, { FLDATA (ION, ion, 0) }, @@ -372,13 +423,13 @@ REG cpu_reg[] = { { FLDATA (MPCTL, dev_ctl[PRO/32], INT_V (PRO)) }, { FLDATA (MPFLG, dev_flg[PRO/32], INT_V (PRO)) }, { FLDATA (MPFBF, dev_fbf[PRO/32], INT_V (PRO)) }, - { ORDATA (MFENCE, mfence, 15) }, - { ORDATA (MADDR, maddr, 16) }, + { ORDATA (MPVR, mp_viol, 16) }, + { FLDATA (MPMEV, mp_mevff, 0) }, + { FLDATA (MPEVR, mp_evrff, 0) }, { FLDATA (DMSENB, dms_enb, 0) }, { FLDATA (DMSCUR, dms_ump, VA_N_PAG) }, { ORDATA (DMSSR, dms_sr, 16) }, { ORDATA (DMSVR, dms_vr, 16) }, - { ORDATA (DMSSMA, dms_sma, 15), REG_HIDDEN }, { BRDATA (DMSMAP, dms_map, 8, PA_N_SIZE, MAP_NUM * MAP_LNT) }, { FLDATA (STOP_INST, stop_inst, 0) }, { FLDATA (STOP_DEV, stop_dev, 1) }, @@ -386,8 +437,6 @@ REG cpu_reg[] = { { BRDATA (PCQ, pcq, 8, 15, PCQ_SIZE), REG_RO+REG_CIRC }, { ORDATA (PCQP, pcq_p, 6), REG_HRO }, { ORDATA (WRU, sim_int_char, 8) }, - { FLDATA (T2100, cpu_unit.flags, UNIT_V_2100), REG_HRO }, - { FLDATA (T21MX, cpu_unit.flags, UNIT_V_21MX), REG_HRO }, { ORDATA (HCMD, dev_cmd[0], 32), REG_HRO }, { ORDATA (LCMD, dev_cmd[1], 32), REG_HRO }, { ORDATA (HCTL, dev_ctl[0], 32), REG_HRO }, @@ -399,9 +448,35 @@ REG cpu_reg[] = { { NULL } }; MTAB cpu_mod[] = { - { UNIT_2100 + UNIT_21MX, 0, "2116", "2116", NULL }, - { UNIT_2100 + UNIT_21MX, UNIT_2100, "2100", "2100", NULL }, - { UNIT_2100 + UNIT_21MX, UNIT_21MX, "21MX", "21MX", NULL }, + { UNIT_2100+UNIT_21MX+UNIT_EAU+UNIT_FP+UNIT_MPR+UNIT_DMS+UNIT_IOP, + 0, NULL, "2116", NULL }, + { UNIT_2100+UNIT_21MX+UNIT_EAU+UNIT_FP+UNIT_MPR+UNIT_DMS+UNIT_IOP, + UNIT_2100+UNIT_EAU, NULL, "2100", NULL }, + { UNIT_2100+UNIT_21MX+UNIT_EAU+UNIT_FP+UNIT_MPR+UNIT_DMS+UNIT_IOP, + UNIT_21MX+UNIT_EAU+UNIT_FP+UNIT_MPR+UNIT_DMS, NULL, "21MX", NULL }, + { UNIT_2100+UNIT_21MX, 0, "2116", NULL, NULL }, + { UNIT_2100+UNIT_21MX, UNIT_2100, "2100", NULL, NULL }, + { UNIT_2100+UNIT_21MX, UNIT_21MX, "21MX", NULL, NULL }, + { UNIT_EAU, UNIT_EAU, "EAU", "EAU", &cpu_set_opt, + NULL, (void *) UNIT_EAU }, + { UNIT_EAU, 0, "NOEAU", "NOEAU", &cpu_set_opt, + NULL, (void *) UNIT_EAU }, + { UNIT_FP, UNIT_FP, "FP", "FP", &cpu_set_opt, + NULL, (void *) UNIT_FP }, + { UNIT_FP, 0, "NOFP", "NOFP", &cpu_set_opt, + NULL, (void *) UNIT_FP }, + { UNIT_MPR, UNIT_MPR, "MPR", "MPR", &cpu_set_opt, + NULL, (void *) UNIT_MPR }, + { UNIT_MPR, 0, "NOMPR", "NOMPR", &cpu_set_opt, + NULL, (void *) UNIT_MPR }, + { UNIT_DMS, UNIT_DMS, "DMS", "DMS", &cpu_set_opt, + NULL, (void *) UNIT_DMS }, + { UNIT_DMS, 0, "NODMS", "NODMS", &cpu_set_opt, + NULL, (void *) UNIT_DMS }, + { UNIT_IOP, UNIT_IOP, "IOP", "IOP", &cpu_set_opt, + NULL, (void *) UNIT_IOP }, + { UNIT_IOP, 0, "NOIOP", "NOIOP", &cpu_set_opt, + NULL, (void *) UNIT_IOP }, { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size }, { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size }, { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size }, @@ -463,31 +538,86 @@ DEVICE dma1_dev = { /* Extended instruction decode tables */ -static const uint8 ext_addr[192] = { /* ext inst format */ - 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, /* 1: 2 word inst */ - 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0, - 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, - 1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0, - 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; +#define E_V_FL 0 /* flags */ +#define E_M_FL 0xFF +#define E_FP (UNIT_FP >> (UNIT_V_UF - E_V_FL)) +#define E_21MX (UNIT_21MX >> (UNIT_V_UF - E_V_FL)) +#define E_DMS (UNIT_DMS >> (UNIT_V_UF - E_V_FL)) +#define E_IOP (UNIT_IOP >> (UNIT_V_UF - E_V_FL)) +#define E_V_TY 8 /* type */ +#define E_M_TY 0xF +#define E_NO 0 /* no operands */ +#define E_CN 1 /* PC+1: count */ +#define E_AD 2 /* PC+1: addr */ +#define E_AA 3 /* PC+1,2: addr */ +#define E_AC 4 /* PC+1: addr, +2: count */ +#define E_AZ 5 /* PC+1: addr, +2: zero */ +#define ET_NO (E_NO << E_V_TY) +#define ET_AD (E_AD << E_V_TY) +#define ET_AA (E_AA << E_V_TY) +#define ET_CN (E_CN << E_V_TY) +#define ET_AC (E_AC << E_V_TY) +#define ET_AZ (E_AZ << E_V_TY) +#define E_V_TYI 12 /* type if IOP */ +#define E_GETFL(x) (((x) >> E_V_FL) & E_M_FL) +#define E_GETTY(f,x) (((x) >> \ + ((((f) & E_IOP) && (cpu_unit.flags & UNIT_IOP))? \ + E_V_TYI: E_V_TY)) & E_M_TY) +#define F_NO E_FP | ET_NO +#define F_MR E_FP | ET_AD +#define X_NO E_21MX | ET_NO +#define X_MR E_21MX | ET_AD +#define X_AA E_21MX | ET_AA +#define X_AZ E_21MX | ET_AZ +#define D_NO E_DMS | ET_NO +#define D_MR E_DMS | ET_AD +#define D_AA E_DMS | ET_AA +#define I_NO E_IOP | (ET_NO << (E_V_TYI - E_V_TY)) +#define I_CN E_IOP | (ET_CN << (E_V_TYI - E_V_TY)) +#define I_AC E_IOP | (ET_AC << (E_V_TYI - E_V_TY)) +#define I_AZ E_IOP | (ET_AZ << (E_V_TYI - E_V_TY)) -static const uint8 exg_breq[64] = { /* ext grp B only */ - 1,1,1,1,1,1,1,1,0,0,0,0,1,1,1,1, /* 1: <11> must be 1 */ - 1,1,0,1,0,0,0,0,0,0,1,1,1,1,1,1, - 0,0,0,1,0,1,1,0,0,0,0,1,0,1,1,0, - 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }; - -static const uint8 exg_addr[64] = { /* ext grp format */ - 0,0,0,0,0,0,0,0,0,0,0,0,1,3,0,0, /* 1: 2 word inst */ - 0,0,0,0,1,1,1,0,0,0,1,1,1,1,1,1, /* 2: 3 word with count */ - 1,0,1,1,0,1,1,0,1,0,1,1,0,1,1,0, /* 3: 3 word inst */ - 0,0,1,0,0,2,2,0,0,0,1,3,3,3,2,2 }; +static const uint32 e_inst[512] = { + F_MR | I_AC,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* FAD/ILIST */ + F_MR | I_NO,I_NO,I_NO,I_NO,I_NO,I_NO,I_NO,I_NO, /* FSB/LAI- */ + I_NO,I_NO,I_NO,I_NO,I_NO,I_NO,I_NO,I_NO, + F_MR | I_NO,I_NO,I_NO,I_NO,I_NO,I_NO,I_NO,I_NO, /* FMP/LAI+ */ + I_NO,I_NO,I_NO,I_NO,I_NO,I_NO,I_NO,I_NO, + F_MR | I_NO,I_NO,I_NO,I_NO,I_NO,I_NO,I_NO,I_NO, /* FDV/SAI- */ + I_NO,I_NO,I_NO,I_NO,I_NO,I_NO,I_NO,I_NO, + F_NO | I_NO,I_NO,I_NO,I_NO,I_NO,I_NO,I_NO,I_NO, /* FIX/SAI+ */ + I_NO,I_NO,I_NO,I_NO,I_NO,I_NO,I_NO,I_NO, + F_NO | I_AZ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* FLT/MBYTE */ + 0,0,0,0,0,0,0,0,I_CN,0,0,0,0,0,0,0, /* CRC */ + I_CN,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* TRSLT */ + I_AZ,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* WMOVE */ + I_NO,I_NO,I_NO,I_NO,0,0,0,0,0,0,0,0,0,0,0,0, /* READF,PFRIO,PFREI,PFRIO */ + I_NO,0,0,0,0,0,0,0,0,0,0,0,0,0,0,I_NO, /* ENQ,ENPQ */ + I_NO,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* DEQ */ + I_NO,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* SBYTE */ + I_NO,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* LBYTE */ + I_NO,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* REST */ + 0,0,I_NO,0,0,0,0,0,0,0,0,0,0,0,0,0, /* SAVE */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0400 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0420 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0440 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0460 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0500 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0520 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0540 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0560 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0600 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0620 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0640 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0660 */ + D_NO,D_NO,D_NO,D_NO,D_NO,D_NO,D_NO,D_NO, /* XMM,test,MBI,MBF,MBW,MWI,MWF,MWW */ + D_NO,D_NO,D_NO,D_NO,D_MR,D_AA,D_NO,D_NO, /* SY*,US*,PA*,PB*,SSM,JRS,nop,nop */ + D_NO,D_NO,D_NO,D_NO,D_MR,D_MR,D_MR,D_NO, /* XMM,XMS,XM*,nop,XL*,XS*,XC*,LF* */ + D_NO,D_NO,D_MR,D_MR,D_MR,D_MR,D_MR,D_MR, /* RS*,RV*,DJP,DJS,SJP,SJS,UJP,UJS */ + X_MR,X_NO,X_MR,X_MR,X_NO,X_MR,X_MR,X_NO, /* S*X,C*X,L*X,STX,CX*,LDX,ADX,X*X */ + X_MR,X_NO,X_MR,X_MR,X_NO,X_MR,X_MR,X_NO, /* S*Y,C*Y,L*Y,STY,CY*,LDY,ADY,X*Y */ + X_NO,X_NO,X_MR,X_NO,X_NO,X_AZ,X_AZ,X_NO, /* ISX,DSX,JLY,LBT,SBT,MBT,CBT,SFB */ + X_NO,X_NO,X_MR,X_AA,X_AA,X_AA,X_AZ,X_AZ }; /* ISY,DSY,JPY,SBS,CBS,TBS,CMW,MVW */ /* Interrupt defer table */ @@ -495,7 +625,7 @@ static const int32 defer_tab[] = { 0, 1, 1, 1, 0, 0, 0, 1 }; /* Device dispatch table */ -int32 devdisp (int32 devno, int32 inst, int32 IR, int32 outdat); +uint32 devdisp (uint32 devno, uint32 inst, uint32 IR, uint32 outdat); int32 cpuio (int32 op, int32 IR, int32 outdat); int32 ovfio (int32 op, int32 IR, int32 outdat); int32 pwrio (int32 op, int32 IR, int32 outdat); @@ -513,47 +643,13 @@ int32 (*dtab[64])() = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; - -/* Device information blocks */ - -extern DIB ptr_dib, ptp_dib; -extern DIB tty_dib; -extern DIB clk_dib; -extern DIB lpt_dib; -extern DIB dp_dib[]; -extern DIB dq_dib[]; -extern DIB dr_dib[]; -extern DIB mt_dib[]; -extern DIB ms_dib[]; -extern DIB mux_dib[]; -extern DIB muxc_dib; - -DIB *dib_tab[] = { - &ptr_dib, - &ptp_dib, - &tty_dib, - &clk_dib, - &lpt_dib, - &dp_dib[0], - &dp_dib[1], - &dq_dib[0], - &dq_dib[1], - &dr_dib[0], - &dr_dib[1], - &mt_dib[0], - &mt_dib[1], - &ms_dib[0], - &ms_dib[1], - &mux_dib[0], - &mux_dib[1], - &muxc_dib, - NULL }; t_stat sim_instr (void) { -int32 intrq, dmarq; /* set after setjmp */ +uint32 intrq, dmarq; /* set after setjmp */ t_stat reason; /* set after setjmp */ int32 i, dev; /* temp */ +DEVICE *dptr; /* temp */ DIB *dibp; /* temp */ int abortval; @@ -562,27 +658,28 @@ int abortval; if (dev_conflict ()) return SCPE_STOP; /* check consistency */ AR = saved_AR & DMASK; /* restore reg */ BR = saved_BR & DMASK; -dms_fence = dms_sr & MST_FENCE; /* separate fence */ err_PC = PC = PC & VAMASK; /* load local PC */ reason = 0; /* Restore I/O state */ -for (i = VARDEV; i <= DEVMASK; i++) dtab[i] = NULL; /* clr disp table */ +for (i = VARDEV; i <= I_DEVMASK; i++) dtab[i] = NULL; /* clr disp table */ dev_cmd[0] = dev_cmd[0] & M_FXDEV; /* clear dynamic info */ dev_ctl[0] = dev_ctl[0] & M_FXDEV; dev_flg[0] = dev_flg[0] & M_FXDEV; dev_fbf[0] = dev_fbf[0] & M_FXDEV; dev_cmd[1] = dev_ctl[1] = dev_flg[1] = dev_fbf[1] = 0; -for (i = 0; dibp = dib_tab[i]; i++) { /* loop thru dev */ - if (dibp -> enb) { /* enabled? */ - dev = dibp -> devno; /* get dev # */ - if (dibp -> cmd) { setCMD (dev); } /* restore cmd */ - if (dibp -> ctl) { setCTL (dev); } /* restore ctl */ - if (dibp -> flg) { setFLG (dev); } /* restore flg */ - clrFBF (dev); /* also sets fbf */ - if (dibp -> fbf) { setFBF (dev); } /* restore fbf */ - dtab[dev] = dibp -> iot; } } /* set I/O dispatch */ +for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru dev */ + dibp = (DIB *) dptr->ctxt; /* get DIB */ + if (dibp && !(dptr->flags & DEV_DIS)) { /* exist, enabled? */ + dev = dibp->devno; /* get dev # */ + if (dibp->cmd) { setCMD (dev); } /* restore cmd */ + if (dibp->ctl) { setCTL (dev); } /* restore ctl */ + if (dibp->flg) { setFLG (dev); } /* restore flg */ + clrFBF (dev); /* also sets fbf */ + if (dibp->fbf) { setFBF (dev); } /* restore fbf */ + dtab[dev] = dibp->iot; } } /* set I/O dispatch */ +sim_rtc_init (clk_delay (0)); /* recalibrate clock */ /* Abort handling @@ -595,22 +692,22 @@ for (i = 0; dibp = dib_tab[i]; i++) { /* loop thru dev */ abortval = setjmp (save_env); /* set abort hdlr */ if (abortval != 0) { /* mem mgt abort? */ - if (abortval > 0) { setFLG (PRO); } /* dms abort? */ - else maddr = err_PC | 0100000; /* mprot abort */ - intrq = PRO; } /* protection intr */ + setFLG (PRO); /* req interrupt */ + mp_evrff = 0; } /* block mp_viol upd */ dmarq = calc_dma (); /* recalc DMA masks */ intrq = calc_int (); /* recalc interrupts */ /* Main instruction fetch/decode loop */ while (reason == 0) { /* loop until halted */ -int32 IR, MA, absel, i, dev, t, opnd; -int32 M1, iodata, op, sc, q, r, wc; -int32 mapi, mapj; -uint32 fop; +uint32 IR, MA, M1, absel, v1, v2, t; +uint32 fop, eop, etype, eflag; +uint32 skip, mapi, mapj, qs, rs; +uint32 awc, sc, wc, hp, tp, iotrap; +int32 sop1, sop2; if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) break; + if (reason = sim_process_event ()) break; dmarq = calc_dma (); /* recalc DMA reqs */ intrq = calc_int (); } /* recalc interrupts */ @@ -621,763 +718,1108 @@ if (dmarq) { intrq = calc_int (); } /* recalc interrupts */ if (intrq && ((intrq <= PRO) || !ion_defer)) { /* interrupt request? */ + iotrap = 1; /* I/O trap cell instr */ clrFBF (intrq); /* clear flag buffer */ intaddr = intrq; /* save int addr */ - err_PC = PC; /* save PC for error */ if (dms_enb) dms_sr = dms_sr | MST_ENBI; /* dms enabled? */ else dms_sr = dms_sr & ~MST_ENBI; if (dms_ump) { /* user map? */ - dms_sr = dms_sr | MST_UMPI; - dms_ump = 0; } /* switch to system */ + dms_sr = dms_sr | MST_UMPI; + dms_ump = SMAP; } /* switch to system */ else dms_sr = dms_sr & ~MST_UMPI; IR = ReadW (intrq); /* get dispatch instr */ ion_defer = 1; /* defer interrupts */ intrq = 0; /* clear request */ - clrCTL (PRO); } /* protection off */ + if (((IR & I_NMRMASK) != I_IO) || /* if not I/O or */ + (I_GETIOOP (IR) == ioHLT)) /* if halt, */ + clrCTL (PRO); } /* protection off */ -else { if (sim_brk_summ && - sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; } +else { iotrap = 0; /* normal instruction */ err_PC = PC; /* save PC for error */ + if (sim_brk_summ && + sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; } + if (mp_evrff) mp_viol = PC; /* if ok, upd mp_viol */ IR = ReadW (PC); /* fetch instr */ PC = (PC + 1) & VAMASK; sim_interval = sim_interval - 1; ion_defer = 0; } -absel = (IR & AB)? 1: 0; /* get A/B select */ + +/* Instruction decode. The 21MX does a 256-way decode on IR<15:8> + + 15 14 13 12 11 10 09 08 instruction + + x <-!= 0-> x x x x memory reference + 0 0 0 0 x 0 x x shift + 0 0 0 0 x 0 x x alter-skip + 1 0 0 0 x 1 x x IO + 1 0 0 0 0 0 x 0 extended arithmetic + 1 0 0 0 0 0 0 1 divide (decoded as 100400) + 1 0 0 0 1 0 0 0 double load (decoded as 104000) + 1 0 0 0 1 0 0 1 double store (decoded as 104400) + 1 0 0 0 1 0 1 0 extended instr group 0 (A/B must be set) + 1 0 0 0 x 0 1 1 extended instr group 1 (A/B ignored) */ + +absel = (IR & I_AB)? 1: 0; /* get A/B select */ +switch ((IR >> 8) & 0377) { /* decode IR<15:8> */ /* Memory reference instructions */ -if (IR & MROP) { /* mem ref? */ - MA = IR & (IA | DISP); /* ind + disp */ - if (IR & CP) MA = ((PC - 1) & PAGENO) | MA; /* current page? */ - for (i = 0; (i < ind_max) && (MA & IA); i++) /* resolve multi- */ - MA = ReadW (MA & VAMASK); /* level indirect */ - if (i >= ind_max) { /* indirect loop? */ - reason = STOP_IND; - break; } - - switch ((IR >> 11) & 017) { /* decode IR<14:11> */ - case 002: /* AND */ - AR = AR & ReadW (MA); - break; - case 003: /* JSB */ - WriteW (MA, PC); - PCQ_ENTRY; - PC = (MA + 1) & VAMASK; - if (IR & IA) ion_defer = 1; - break; - case 004: /* XOR */ - AR = AR ^ ReadW (MA); - break; - case 005: /* JMP */ - if (MP_TESTJ (MA)) ABORT (ABORT_FENCE); - PCQ_ENTRY; - PC = MA; - if (IR & IA) ion_defer = 1; - break; - case 006: /* IOR */ - AR = AR | ReadW (MA); - break; - case 007: /* ISZ */ - t = (ReadW (MA) + 1) & DMASK; - WriteW (MA, t); - if (t == 0) PC = (PC + 1) & VAMASK; - break; +case 0020:case 0021:case 0022:case 0023: +case 0024:case 0025:case 0026:case 0027: +case 0220:case 0221:case 0222:case 0223: +case 0224:case 0225:case 0226:case 0227: + if (reason = Ea (IR, &MA, intrq)) break; /* AND */ + AR = AR & ReadW (MA); + break; +case 0030:case 0031:case 0032:case 0033: +case 0034:case 0035:case 0036:case 0037: +case 0230:case 0231:case 0232:case 0233: +case 0234:case 0235:case 0236:case 0237: + if (reason = Ea (IR, &MA, intrq)) break; /* JSB */ + WriteW (MA, PC); /* store PC */ + PCQ_ENTRY; + PC = (MA + 1) & VAMASK; /* jump */ + if (IR & I_IA) ion_defer = 1; /* ind? defer intr */ + break; +case 0040:case 0041:case 0042:case 0043: +case 0044:case 0045:case 0046:case 0047: +case 0240:case 0241:case 0242:case 0243: +case 0244:case 0245:case 0246:case 0247: + if (reason = Ea (IR, &MA, intrq)) break; /* XOR */ + AR = AR ^ ReadW (MA); + break; +case 0050:case 0051:case 0052:case 0053: +case 0054:case 0055:case 0056:case 0057: +case 0250:case 0251:case 0252:case 0253: +case 0254:case 0255:case 0256:case 0257: + if (reason = Ea (IR, &MA, intrq)) break; /* JMP */ + mp_dms_jmp (MA); /* validate jump addr */ + PCQ_ENTRY; + PC = MA; /* jump */ + if (IR & I_IA) ion_defer = 1; /* ind? defer int */ + break; +case 0060:case 0061:case 0062:case 0063: +case 0064:case 0065:case 0066:case 0067: +case 0260:case 0261:case 0262:case 0263: +case 0264:case 0265:case 0266:case 0267: + if (reason = Ea (IR, &MA, intrq)) break; /* IOR */ + AR = AR | ReadW (MA); + break; +case 0070:case 0071:case 0072:case 0073: +case 0074:case 0075:case 0076:case 0077: +case 0270:case 0271:case 0272:case 0273: +case 0274:case 0275:case 0276:case 0277: + if (reason = Ea (IR, &MA, intrq)) break; /* ISZ */ + t = (ReadW (MA) + 1) & DMASK; + WriteW (MA, t); + if (t == 0) PC = (PC + 1) & VAMASK; + break; /* Memory reference instructions, continued */ - case 010: /* ADA */ - opnd = (int32) ReadW (MA); - t = (int32) AR + opnd; - if (t > DMASK) E = 1; - if (((~AR ^ opnd) & (AR ^ t)) & SIGN) O = 1; - AR = t & DMASK; - break; - case 011: /* ADB */ - opnd = (int32) ReadW (MA); - t = (int32) BR + opnd; - if (t > DMASK) E = 1; - if (((~BR ^ opnd) & (BR ^ t)) & SIGN) O = 1; - BR = t & DMASK; - break; - case 012: /* CPA */ - if (AR != ReadW (MA)) PC = (PC + 1) & VAMASK; - break; - case 013: /* CPB */ - if (BR != ReadW (MA)) PC = (PC + 1) & VAMASK; - break; - case 014: /* LDA */ - AR = ReadW (MA); - break; - case 015: /* LDB */ - BR = ReadW (MA); - break; - case 016: /* STA */ - WriteW (MA, AR); - break; - case 017: /* STB */ - WriteW (MA, BR); - break; } /* end case IR */ - } /* end if mem ref */ +case 0100:case 0101:case 0102:case 0103: +case 0104:case 0105:case 0106:case 0107: +case 0300:case 0301:case 0302:case 0303: +case 0304:case 0305:case 0306:case 0307: + if (reason = Ea (IR, &MA, intrq)) break; /* ADA */ + v1 = ReadW (MA); + t = AR + v1; + if (t > DMASK) E = 1; + if (((~AR ^ v1) & (AR ^ t)) & SIGN) O = 1; + AR = t & DMASK; + break; +case 0110:case 0111:case 0112:case 0113: +case 0114:case 0115:case 0116:case 0117: +case 0310:case 0311:case 0312:case 0313: +case 0314:case 0315:case 0316:case 0317: + if (reason = Ea (IR, &MA, intrq)) break; /* ADB */ + v1 = ReadW (MA); + t = BR + v1; + if (t > DMASK) E = 1; + if (((~BR ^ v1) & (BR ^ t)) & SIGN) O = 1; + BR = t & DMASK; + break; +case 0120:case 0121:case 0122:case 0123: +case 0124:case 0125:case 0126:case 0127: +case 0320:case 0321:case 0322:case 0323: +case 0324:case 0325:case 0326:case 0327: + if (reason = Ea (IR, &MA, intrq)) break; /* CPA */ + if (AR != ReadW (MA)) PC = (PC + 1) & VAMASK; + break; +case 0130:case 0131:case 0132:case 0133: +case 0134:case 0135:case 0136:case 0137: +case 0330:case 0331:case 0332:case 0333: +case 0334:case 0335:case 0336:case 0337: + if (reason = Ea (IR, &MA, intrq)) break; /* CPB */ + if (BR != ReadW (MA)) PC = (PC + 1) & VAMASK; + break; +case 0140:case 0141:case 0142:case 0143: +case 0144:case 0145:case 0146:case 0147: +case 0340:case 0341:case 0342:case 0343: +case 0344:case 0345:case 0346:case 0347: + if (reason = Ea (IR, &MA, intrq)) break; /* LDA */ + AR = ReadW (MA); + break; +case 0150:case 0151:case 0152:case 0153: +case 0154:case 0155:case 0156:case 0157: +case 0350:case 0351:case 0352:case 0353: +case 0354:case 0355:case 0356:case 0357: + if (reason = Ea (IR, &MA, intrq)) break; /* LDB */ + BR = ReadW (MA); + break; +case 0160:case 0161:case 0162:case 0163: +case 0164:case 0165:case 0166:case 0167: +case 0360:case 0361:case 0362:case 0363: +case 0364:case 0365:case 0366:case 0367: + if (reason = Ea (IR, &MA, intrq)) break; /* STA */ + WriteW (MA, AR); + break; +case 0170:case 0171:case 0172:case 0173: +case 0174:case 0175:case 0176:case 0177: +case 0370:case 0371:case 0372:case 0373: +case 0374:case 0375:case 0376:case 0377: + if (reason = Ea (IR, &MA, intrq)) break; /* STB */ + WriteW (MA, BR); + break; /* Alter/skip instructions */ -else if ((IR & NMROP) == ASKP) { /* alter/skip? */ - int32 skip = 0; /* no skip */ - +case 0004:case 0005:case 0006:case 0007: +case 0014:case 0015:case 0016:case 0017: + skip = 0; /* no skip */ if (IR & 000400) t = 0; /* CLx */ else t = ABREG[absel]; if (IR & 001000) t = t ^ DMASK; /* CMx */ if (IR & 000001) { /* RSS? */ - if ((IR & 000040) && (E != 0)) skip = 1;/* SEZ,RSS */ - if (IR & 000100) E = 0; /* CLE */ - if (IR & 000200) E = E ^ 1; /* CME */ - if (((IR & 000030) == 000030) && /* SSx,SLx,RSS */ - ((t & 0100001) == 0100001)) skip = 1; - if (((IR & 000030) == 000020) && /* SSx,RSS */ - ((t & SIGN) != 0)) skip = 1; - if (((IR & 000030) == 000010) && /* SLx,RSS */ - ((t & 1) != 0)) skip = 1; - if (IR & 000004) { /* INx */ - t = (t + 1) & DMASK; - if (t == 0) E = 1; - if (t == SIGN) O = 1; } - if ((IR & 000002) && (t != 0)) skip = 1;/* SZx,RSS */ - if ((IR & 000072) == 0) skip = 1; /* RSS */ - } /* end if RSS */ - else { if ((IR & 000040) && (E == 0)) skip = 1;/* SEZ */ - if (IR & 000100) E = 0; /* CLE */ - if (IR & 000200) E = E ^ 1; /* CME */ - if ((IR & 000020) && /* SSx */ - ((t & SIGN) == 0)) skip = 1; - if ((IR & 000010) && /* SLx */ - ((t & 1) == 0)) skip = 1; - if (IR & 000004) { /* INx */ - t = (t + 1) & DMASK; - if (t == 0) E = 1; - if (t == SIGN) O = 1; } - if ((IR & 000002) && (t == 0)) skip = 1;/* SZx */ - } /* end if ~RSS */ + if ((IR & 000040) && (E != 0)) skip = 1; /* SEZ,RSS */ + if (IR & 000100) E = 0; /* CLE */ + if (IR & 000200) E = E ^ 1; /* CME */ + if (((IR & 000030) == 000030) && /* SSx,SLx,RSS */ + ((t & 0100001) == 0100001)) skip = 1; + if (((IR & 000030) == 000020) && /* SSx,RSS */ + ((t & SIGN) != 0)) skip = 1; + if (((IR & 000030) == 000010) && /* SLx,RSS */ + ((t & 1) != 0)) skip = 1; + if (IR & 000004) { /* INx */ + t = (t + 1) & DMASK; + if (t == 0) E = 1; + if (t == SIGN) O = 1; } + if ((IR & 000002) && (t != 0)) skip = 1; /* SZx,RSS */ + if ((IR & 000072) == 0) skip = 1; /* RSS */ + } /* end if RSS */ + else { + if ((IR & 000040) && (E == 0)) skip = 1; /* SEZ */ + if (IR & 000100) E = 0; /* CLE */ + if (IR & 000200) E = E ^ 1; /* CME */ + if ((IR & 000020) && /* SSx */ + ((t & SIGN) == 0)) skip = 1; + if ((IR & 000010) && /* SLx */ + ((t & 1) == 0)) skip = 1; + if (IR & 000004) { /* INx */ + t = (t + 1) & DMASK; + if (t == 0) E = 1; + if (t == SIGN) O = 1; } + if ((IR & 000002) && (t == 0)) skip = 1;/* SZx */ + } /* end if ~RSS */ ABREG[absel] = t; /* store result */ PC = (PC + skip) & VAMASK; /* add in skip */ - } /* end if alter/skip */ + break; /* end if alter/skip */ /* Shift instructions */ -else if ((IR & NMROP) == SHFT) { /* shift? */ +case 0000:case 0001:case 0002:case 0003: +case 0010:case 0011:case 0012:case 0013: t = shift (ABREG[absel], IR & 01000, IR >> 6); /* do first shift */ if (IR & 000040) E = 0; /* CLE */ if ((IR & 000010) && ((t & 1) == 0)) /* SLx */ - PC = (PC + 1) & VAMASK; + PC = (PC + 1) & VAMASK; ABREG[absel] = shift (t, IR & 00020, IR); /* do second shift */ - } /* end if shift */ + break; /* end if shift */ /* I/O instructions */ -else if ((IR & NMROP) == IOT) { /* I/O? */ - dev = IR & DEVMASK; /* get device */ - t = (IR >> 6) & 07; /* get subopcode */ - if (CTL (PRO) && ((t == ioHLT) || (dev != OVF))) { - ABORT (ABORT_FENCE); } - iodata = devdisp (dev, t, IR, ABREG[absel]); /* process I/O */ - if ((t == ioMIX) || (t == ioLIX)) /* store ret data */ - ABREG[absel] = iodata & DMASK; - if (t == ioHLT) reason = STOP_HALT; - else reason = iodata >> IOT_V_REASON; - ion_defer = defer_tab[t]; /* set defer */ +case 0204:case 0205:case 0206:case 0207: +case 0214:case 0215:case 0216:case 0217: + reason = iogrp (IR, iotrap); /* execute instr */ dmarq = calc_dma (); /* recalc DMA */ intrq = calc_int (); /* recalc interrupts */ - } /* end if I/O */ + break; /* end if I/O */ + +/* Extended arithmetic */ + +case 0200: /* EAU group 0 */ + if ((cpu_unit.flags & UNIT_EAU) == 0) { /* implemented? */ + reason = stop_inst; + break; } + switch ((IR >> 4) & 017) { /* decode IR<7:4> */ + case 000: /* diagnostic */ + break; + case 001: /* ASL */ + sc = (IR & 017)? (IR & 017): 16; /* get sc */ + O = 0; /* clear ovflo */ + while (sc-- != 0) { /* bit by bit */ + t = BR << 1; /* shift B */ + BR = (BR & SIGN) | (t & 077777) | (AR >> 15); + AR = (AR << 1) & DMASK; + if ((BR ^ t) & SIGN) O = 1; } + break; + case 002: /* LSL */ + sc = (IR & 017)? (IR & 017): 16; /* get sc */ + BR = ((BR << sc) | (AR >> (16 - sc))) & DMASK; + AR = (AR << sc) & DMASK; /* BR'AR lsh left */ + break; + case 003: /* TIMER */ + BR = (BR + 1) & DMASK; /* increment B */ + if (BR) PC = err_PC; /* if !=0, repeat */ + break; + case 004: /* RRL */ + sc = (IR & 017)? (IR & 017): 16; /* get sc */ + t = BR; /* BR'AR rot left */ + BR = ((BR << sc) | (AR >> (16 - sc))) & DMASK; + AR = ((AR << sc) | (t >> (16 - sc))) & DMASK; + break; + case 010: /* MPY */ + if (reason = Ea1 (&MA, intrq)) break; /* get opnd addr */ + sop1 = SEXT (AR); /* sext AR */ + sop2 = SEXT (ReadW (MA)); /* sext mem */ + sop1 = sop1 * sop2; /* signed mpy */ + BR = (sop1 >> 16) & DMASK; /* to BR'AR */ + AR = sop1 & DMASK; + O = 0; /* no overflow */ + break; + default: + reason = stop_inst; + break; } + break; +case 0201: /* divide */ + if ((cpu_unit.flags & UNIT_EAU) == 0) { /* implemented? */ + reason = stop_inst; + break; } + if (reason = Ea1 (&MA, intrq)) break; /* get opnd addr */ + if (rs = qs = BR & SIGN) { /* save divd sign, neg? */ + AR = (~AR + 1) & DMASK; /* make B'A pos */ + BR = (~BR + (AR == 0)) & DMASK; } /* make divd pos */ + v2 = ReadW (MA); /* divr = mem */ + if (v2 & SIGN) { /* neg? */ + v2 = (~v2 + 1) & DMASK; /* make divr pos */ + qs = qs ^ SIGN; } /* sign of quotient */ + if (BR >= v2) O = 1; /* divide work? */ + else { /* maybe... */ + O = 0; /* assume ok */ + v1 = (BR << 16) | AR; /* 32b divd */ + AR = (v1 / v2) & DMASK; /* quotient */ + BR = (v1 % v2) & DMASK; /* remainder */ + if (AR) { /* quotient > 0? */ + if (qs) AR = (~AR + 1) & DMASK; /* apply quo sign */ + if ((AR ^ qs) & SIGN) O = 1; } /* still wrong? ovflo */ + if (rs) BR = (~BR + 1) & DMASK; } /* apply rem sign */ + break; +case 0202: /* EAU group 2 */ + if ((cpu_unit.flags & UNIT_EAU) == 0) { /* implemented? */ + reason = stop_inst; + break; } + switch ((IR >> 4) & 017) { /* decode IR<7:4> */ + case 001: /* ASR */ + sc = (IR & 017)? (IR & 017): 16; /* get sc */ + AR = ((BR << (16 - sc)) | (AR >> sc)) & DMASK; + BR = (SEXT (BR) >> sc) & DMASK; /* BR'AR ash right */ + O = 0; + break; + case 002: /* LSR */ + sc = (IR & 017)? (IR & 017): 16; /* get sc */ + AR = ((BR << (16 - sc)) | (AR >> sc)) & DMASK; + BR = BR >> sc; /* BR'AR log right */ + break; + case 004: /* RRR */ + sc = (IR & 017)? (IR & 017): 16; /* get sc */ + t = AR; /* BR'AR rot right */ + AR = ((AR >> sc) | (BR << (16 - sc))) & DMASK; + BR = ((BR >> sc) | (t << (16 - sc))) & DMASK; + break; + default: + reason = stop_inst; + break; } + break; +case 0210: /* DLD */ + if ((cpu_unit.flags & UNIT_EAU) == 0) { /* implemented? */ + reason = stop_inst; + break; } + if (reason = Ea1 (&MA, intrq)) break; /* get opnd addr */ + AR = ReadW (MA); /* load AR */ + MA = (MA + 1) & VAMASK; + BR = ReadW (MA); /* load BR */ + break; +case 0211: /* DST */ + if ((cpu_unit.flags & UNIT_EAU) == 0) { /* get opnd addr */ + reason = stop_inst; + break; } + if (reason = Ea1 (&MA, intrq)) break; /* get opnd addr */ + WriteW (MA, AR); /* store AR */ + MA = (MA + 1) & VAMASK; + WriteW (MA, BR); /* store BR */ + break; /* Extended instructions */ -else if (cpu_unit.flags & (UNIT_2100 | UNIT_21MX)) { /* ext instr? */ - int32 awc; +case 0212: /* MAC0 ext */ +case 0203:case 0213: /* MAC1 ext */ + eop = IR & 0777; /* extended opcode */ + eflag = E_GETFL (e_inst[eop]); /* get flags */ + if ((eflag & (cpu_unit.flags >> UNIT_V_UF)) == 0) { + reason = stop_inst; /* invalid? error */ + break; } + etype = E_GETTY (eflag, e_inst[eop]); /* get format */ + if (etype > E_CN) { /* at least 1 addr? */ + if (reason = Ea1 (&MA, intrq)) break; } /* get first address */ + if ((etype == E_AC) || (etype == E_CN)) { /* addr + cnt, cnt */ + wc = ReadW (PC); /* get count */ + awc = PC; /* addr of count */ + PC = (PC + 1) & VAMASK; } + else if (etype == E_AZ) { /* addr + zero */ + wc = ReadW (MA); /* get wc */ + awc = PC; /* addr of interim */ + if (wc) { /* wc > 0? */ + if (t = ReadW (PC)) wc = t; } /* use interim if nz */ + WriteW (awc, 0); /* clear interim */ + PC = (PC + 1) & VAMASK; } + else if (etype == E_AA) { /* second addr */ + if (reason = Ea1 (&M1, intrq)) break; } /* get second address */ - op = (IR >> 4) & 0277; /* get opcode */ - if (ext_addr[op]) { /* extended mem ref? */ - MA = ReadW (PC); /* get next address */ - PC = (PC + 1) & VAMASK; - for (i = 0; (i < ind_max) && (MA & IA); i++) - MA = ReadW (MA & VAMASK); - if (i >= ind_max) { - reason = STOP_IND; - break; } } - sc = (IR & 017); /* get shift count */ - if (sc == 0) sc = 16; - switch (op) { /* decode IR<11:4> */ - case 0010: /* MUL */ - t = SEXT (AR) * SEXT (ReadW (MA)); - BR = (t >> 16) & DMASK; - AR = t & DMASK; - O = 0; - break; - case 0020: /* DIV */ - t = (SEXT (BR) << 16) | (int32) AR; /* get divd */ - opnd = SEXT (ReadW (MA)); /* get divisor */ - if ((opnd == 0) || /* divide by zero? */ - ((t == SIGN32) && (opnd == -1)) || /* -2**32 / -1? */ - ((q = t / opnd) > 077777) || /* quo too big? */ - (q < -0100000)) { /* quo too small? */ - O = 1; /* set overflow */ - if (BR & SIGN) { /* divd negative? */ - BR = (-BR) & DMASK; /* make B'A pos */ - AR = (~AR + (BR == 0)) & DMASK; } - } /* end if div fail */ - else { AR = q & DMASK; /* set quo, rem */ - BR = (t % opnd) & DMASK; - O = 0; } /* end else ok */ - break; - case 0210: /* DLD */ - AR = ReadW (MA); - MA = (MA + 1) & VAMASK; - BR = ReadW (MA); - break; - case 0220: /* DST */ - WriteW (MA, AR); - MA = (MA + 1) & VAMASK; - WriteW (MA, BR); - break; + switch (eop) { /* decode IR<8:0> */ -/* Extended arithmetic instructions */ - - case 0001: /* ASL */ - t = (SEXT (BR) >> (16 - sc)) & DMASK; - if (t != ((BR & SIGN)? DMASK: 0)) O = 1; - else O = 0; - BR = (BR & SIGN) || ((BR << sc) & 077777) || - (AR >> (16 - sc)); - AR = (AR << sc) & DMASK; - break; - case 0002: /* LSL */ - BR = ((BR << sc) | (AR >> (16 - sc))) & DMASK; - AR = (AR << sc) & DMASK; - break; - case 0004: /* RRL */ - t = BR; - BR = ((BR << sc) | (AR >> (16 - sc))) & DMASK; - AR = ((AR << sc) | (t >> (16 - sc))) & DMASK; - break; - case 0041: /* ASR */ - AR = ((BR << (16 - sc)) | (AR >> sc)) & DMASK; - BR = (SEXT (BR) >> sc) & DMASK; - O = 0; - break; - case 0042: /* LSR */ - AR = ((BR << (16 - sc)) | (AR >> sc)) & DMASK; - BR = BR >> sc; - break; - case 0044: /* RRR */ - t = AR; - AR = ((AR >> sc) | (BR << (16 - sc))) & DMASK; - BR = ((BR >> sc) | (t << (16 - sc))) & DMASK; - break; - /* Floating point instructions */ - case 0240: /* FAD */ + case 0000: /* IOP ILIST/FAD */ + if (cpu_unit.flags & UNIT_IOP) { /* ILIST (E_AC) */ + do { /* for count */ + WriteW (MA, AR); /* write AR to mem */ + AR = (AR + 1) & DMASK; /* incr AR */ + MA = (MA + 1) & VAMASK; /* incr MA */ + wc = (wc - 1) & DMASK; } /* decr count */ + while (wc != 0); } + else { /* FAD (E_AD) */ fop = ReadF (MA); /* get fop */ - O = O | f_as (fop, 0); /* add */ - break; - case 0241: /* FSB */ + O = f_as (fop, 0); } /* add, upd ovflo */ + break; + case 0020: /* IOP LAI-/FSB */ + if (cpu_unit.flags & UNIT_IOP) /* LAI -20 (I_NO) */ + AR = ReadW ((BR - 020) & VAMASK); /* load AR */ + else { /* FSB (E_AD) */ fop = ReadF (MA); /* get fop */ - O = O | f_as (fop, 1); /* subtract */ - break; - case 0242: /* FMP */ + O = f_as (fop, 1); } /* sub, upd ovflo */ + break; + case 0040: /* IOP LAI+/FMP */ + if (cpu_unit.flags & UNIT_IOP) /* LAI 0 (I_NO) */ + AR = ReadW (BR & VAMASK); /* load AR */ + else { /* FMP (E_AD) */ fop = ReadF (MA); /* get fop */ - O = O | f_mul (fop); /* multiply */ - break; - case 0243: /* FDV */ + O = f_mul (fop); } /* mul, upd ovflo */ + break; + case 0060: /* IOP SAI-/FDV */ + if (cpu_unit.flags & UNIT_IOP) /* SAI -20 (I_NO) */ + WriteW ((BR - 020) & VAMASK, AR); /* store AR */ + else { /* FDV (E_AD) */ fop = ReadF (MA); /* get fop */ - O = O | f_div (fop); /* divide */ - break; - case 0244: /* FIX */ - O = O | f_fix (); /* fix */ - break; - case 0245: /* FLT */ - f_flt (); /* float */ - break; + O = f_div (fop); } /* div, upd ovflo */ + break; + case 0100: /* IOP SAI+/FIX */ + if (cpu_unit.flags & UNIT_IOP) /* SAI 0 (I_NO) */ + WriteW (BR & VAMASK, AR); /* store AR */ + else O = f_fix (); /* FIX (E_NO) */ + break; + case 0120: /* IOP MBYTE/FLT */ + if (cpu_unit.flags & UNIT_IOP) /* MBYTE (I_AZ) */ + goto IOP_MBYTE; + O = f_flt (); /* FLT (E_NO) */ + break; -/* Extended instruction group, including DMS */ +/* IOP instructions */ - case 0074: case 0075: /* DMS inst grp, A */ - case 0076: case 0077: /* ext inst grp, A */ - if (exg_breq[IR & 077]) { /* must have B set? */ - reason = stop_inst; - break; } - case 0274: case 0275: /* DMS inst grp, B */ - case 0276: case 0277: /* ext inst grp, B */ - if ((cpu_unit.flags & UNIT_21MX) == 0) { - reason = stop_inst; - break; } - op = IR & 077; /* get sub opcode */ - if (exg_addr[op]) { /* mem addr? */ - MA = ReadW (PC); /* get next address */ - PC = (PC + 1) & VAMASK; - for (i = 0; (i < ind_max) && (MA & IA); i++) - MA = ReadW (MA & VAMASK); - if (i >= ind_max) { - reason = STOP_IND; - break; } } - if (exg_addr[op] == 2) { /* word of zero? */ - wc = ReadW (MA); /* get count */ - if (ReadW (PC) == 0) WriteW (PC, wc); - awc = PC; /* and addr */ - PC = (PC + 1) & VAMASK; } - if (exg_addr[op] == 3) { /* second address? */ - M1 = ReadW (PC); /* get next address */ - PC = (PC + 1) & VAMASK; - for (i = 0; (i < ind_max) && (M1 & IA); i++) - M1 = ReadW (M1 & VAMASK); - if (i >= ind_max) { - reason = STOP_IND; - break; } } - switch (op) { /* case on sub op */ + case 0021: case 0022: case 0023: /* IOP LAI- (I_NO) */ + case 0024: case 0025: case 0026: case 0027: + case 0030: case 0031: case 0032: case 0033: + case 0034: case 0035: case 0036: case 0037: + MA = ((IR | 0177760) + BR) & VAMASK; /* IR<3:0> = -offset */ + AR = ReadW (MA); /* load AR */ + break; + case 0041: case 0042: case 0043: /* IOP LAI+ (I_NO) */ + case 0044: case 0045: case 0046: case 0047: + case 0050: case 0051: case 0052: case 0053: + case 0054: case 0055: case 0056: case 0057: + MA = ((IR & 017) + BR) & VAMASK; /* IR<3:0> = +offset */ + AR = ReadW (MA); /* load AR */ + break; + case 0061: case 0062: case 0063: /* IOP SAI- (I_NO) */ + case 0064: case 0065: case 0066: case 0067: + case 0070: case 0071: case 0072: case 0073: + case 0074: case 0075: case 0076: case 0077: + MA = ((IR | 0177760) + BR) & VAMASK; /* IR<3:0> = -offset */ + WriteW (MA, AR); /* store AR */ + break; + case 0101: case 0102: case 0103: /* IOP SAI+ (I_NO) */ + case 0104: case 0105: case 0106: case 0107: + case 0110: case 0111: case 0112: case 0113: + case 0114: case 0115: case 0116: case 0117: + MA = ((IR & 017) + BR) & VAMASK; /* IR<3:0> = +offset */ + WriteW (MA, AR); /* store AR */ + break; + case 0150: /* IOP CRC (I_CN) */ + t = (AR & 0xFF) ^ wc; /* start CRC */ + for (i = 0; i < 8; i++) { /* apply polynomial */ + t = (t >> 1) | ((t & 1) << 15); /* rotate right */ + if (t & SIGN) t = t ^ 020001; } /* old t<0>? xor */ + WriteW (awc, t); /* rewrite CRC */ + break; + case 0160: /* IOP TRSLT (I_CN) */ + if (wc & SIGN) break; /* cnt < 0? */ + while (wc != 0) { /* loop */ + MA = (AR + AR + ReadB (BR)) & VAMASK; + t = ReadB (MA); /* xlate */ + WriteB (BR, t); /* store char */ + BR = (BR + 1) & DMASK; /* incr ptr */ + wc = (wc - 1) & DMASK; /* decr cnt */ + WriteW (awc, wc); } + break; + case 0220: /* IOP READF (I_NO) */ + AR = mp_fence; /* copy mp_fence */ + break; + case 0221: /* IOP PRFIO (I_NO) */ + IR = ReadW (PC); /* get IO instr */ + PC = (PC + 1) & VAMASK; + WriteW (PC, 1); /* set flag */ + PC = (PC + 1) & VAMASK; + reason = iogrp (IR, 0); /* execute instr */ + break; + case 0222: /* IOP PRFIE (I_NO) */ + IR = ReadW (PC); /* get IO instr */ + PC = (PC + 1) & VAMASK; + WriteW (PC, 1); /* set flag */ + PC = (PC + 1) & VAMASK; + reason = iogrp (IR, 0); /* execute instr */ + /* fall through */ + case 0223: /* IOP PRFEX (I_NO) */ + MA = ReadW (PC); /* exit addr */ + PCQ_ENTRY; + PC = ReadW (MA) & VAMASK; /* jump indirect */ + WriteW (MA, 0); /* clear exit */ + break; + case 0240: /* IOP ENQ (I_NO) */ + hp = ReadW (AR & VAMASK); /* addr of head */ + tp = ReadW ((AR + 1) & VAMASK); /* addr of tail */ + WriteW ((BR - 1) & VAMASK, 0); /* entry link */ + WriteW ((tp - 1) & VAMASK, BR); /* tail link */ + WriteW ((AR + 1) & VAMASK, BR); /* queue tail */ + if (hp != 0) PC = (PC + 1) & VAMASK; /* q not empty? skip */ + break; + case 0257: /* IOP ENQP (I_NO) */ + hp = ReadW (AR & VAMASK); /* addr of head */ + WriteW ((BR - 1) & VAMASK, hp); /* becomes entry link */ + WriteW (AR & VAMASK, BR); /* queue head */ + if (hp == 0) /* q empty? */ + WriteW ((AR + 1) & VAMASK, BR); /* queue tail */ + else PC = (PC + 1) & VAMASK; /* skip */ + break; + case 0260: /* IOP DEQ (I_NO) */ + BR = ReadW (AR & VAMASK); /* addr of head */ + if (BR) { /* queue not empty? */ + hp = ReadW ((BR - 1) & VAMASK); /* read hd entry link */ + WriteW (AR & VAMASK, hp); /* becomes queue head */ + if (hp == 0) /* q now empty? */ + WriteW ((AR + 1) & VAMASK, (AR + 1) & DMASK); + PC = (PC + 1) & VAMASK; } /* skip */ + break; + case 0300: /* IOP SBYTE (I_NO) */ + WriteB (BR, AR); /* store byte */ + BR = (BR + 1) & DMASK; /* incr ptr */ + break; + case 0320: /* IOP LBYTE (I_NO) */ + AR = ReadB (BR); /* load byte */ + BR = (BR + 1) & DMASK; /* incr ptr */ + break; + case 0340: /* IOP REST (I_NO) */ + mp_fence = (mp_fence - 1) & VAMASK; /* pop E/~O,BR,AR */ + t = ReadW (mp_fence); + O = ((t >> 1) ^ 1) & 1; + E = t & 1; + mp_fence = (mp_fence - 1) & VAMASK; + BR = ReadW (mp_fence); + mp_fence = (mp_fence - 1) & VAMASK; + AR = ReadW (mp_fence); + break; + case 0362: /* IOP SAVE (I_NO) */ + WriteW (mp_fence, AR); /* push AR,BR,E/~O */ + mp_fence = (mp_fence + 1) & VAMASK; + WriteW (mp_fence, BR); + mp_fence = (mp_fence + 1) & VAMASK; + t = ((O ^ 1) << 1) | E; + WriteW (mp_fence, t); + mp_fence = (mp_fence + 1) & VAMASK; + break; -/* Extended instruction group: DMS */ +/* DMS instructions, move alternate - interruptible - case 002: /* MBI */ - dms_viol (err_PC, MVI_PRV, 0); /* priv if PRO */ - if (XR == 0) break; /* nop if X = 0 */ - AR = AR & ~1; /* force A, B even */ - BR = BR & ~1; - for ( ; XR == 0; XR--) { /* loop */ - t = ReadB (AR); /* read curr */ - WriteBA (BR, t); /* write alt */ - AR = (AR + 1) & DMASK; /* inc ptrs */ - BR = (BR + 1) & DMASK; } - break; - case 003: /* MBF */ - if (XR == 0) break; - AR = AR & ~1; /* force A, B even */ - BR = BR & ~1; - for ( ; XR == 0; XR--) { - t = ReadBA (AR); - WriteB (BR, t); - AR = (AR + 1) & DMASK; - BR = (BR + 1) & DMASK; } - break; - case 004: /* MBW */ - dms_viol (err_PC, MVI_PRV, 0); - if (XR == 0) break; - AR = AR & ~1; /* force A, B even */ - BR = BR & ~1; - for ( ; XR == 0; XR--) { - t = ReadBA (AR); - WriteBA (BR, t); - AR = (AR + 1) & DMASK; - BR = (BR + 1) & DMASK; } - break; - case 005: /* MWI */ - dms_viol (err_PC, MVI_PRV, 0); - if (XR == 0) break; - for ( ; XR == 0; XR--) { - t = ReadW (AR & VAMASK); - WriteWA (BR & VAMASK, t); - AR = (AR + 1) & DMASK; - BR = (BR + 1) & DMASK; } - break; - case 006: /* MWF */ - if (XR == 0) break; - for ( ; XR == 0; XR--) { - t = ReadWA (AR & VAMASK); - WriteW (BR & VAMASK, t); - AR = (AR + 1) & DMASK; - BR = (BR + 1) & DMASK; } - break; - case 007: /* MWW */ - dms_viol (err_PC, MVI_PRV, 0); - if (XR == 0) break; - for ( ; XR == 0; XR--) { - t = ReadWA (AR & VAMASK); - WriteWA (BR & VAMASK, t); - AR = (AR + 1) & DMASK; - BR = (BR + 1) & DMASK; } - break; + DMS privilege violation rules are + - load map and CTL set (XMM, XMS, XM*, SY*, US*, PA*, PB*) + - load state or fence and UMAP set (JRS, DJP, DJS, SJP, SJS, UJP, UJS, LF*) + + The 21MX manual is incorrect in stating that M*I, M*W, XS* are privileged */ + + case 0701: /* self test */ + ABREG[absel] = ABREG[absel] ^ DMASK; /* CMA or CMB */ + break; + case 0702: /* MBI (E_NO) */ + AR = AR & ~1; /* force A, B even */ + BR = BR & ~1; + while (XR != 0) { /* loop */ + t = ReadB (AR); /* read curr */ + WriteBA (BR, t); /* write alt */ + AR = (AR + 1) & DMASK; /* incr ptrs */ + BR = (BR + 1) & DMASK; + XR = (XR - 1) & DMASK; + if (XR && intrq && !(AR & 1)) { /* more, int, even? */ + PC = err_PC; /* stop for now */ + break; } } + break; + case 0703: /* MBF (E_NO) */ + AR = AR & ~1; /* force A, B even */ + BR = BR & ~1; + while (XR != 0) { /* loop */ + t = ReadBA (AR); /* read alt */ + WriteB (BR, t); /* write curr */ + AR = (AR + 1) & DMASK; /* incr ptrs */ + BR = (BR + 1) & DMASK; + XR = (XR - 1) & DMASK; + if (XR && intrq && !(AR & 1)) { /* more, int, even? */ + PC = err_PC; /* stop for now */ + break; } } + break; + case 0704: /* MBW (E_NO) */ + AR = AR & ~1; /* force A, B even */ + BR = BR & ~1; + while (XR != 0) { /* loop */ + t = ReadBA (AR); /* read alt */ + WriteBA (BR, t); /* write alt */ + AR = (AR + 1) & DMASK; /* incr ptrs */ + BR = (BR + 1) & DMASK; + XR = (XR - 1) & DMASK; + if (XR && intrq && !(AR & 1)) { /* more, int, even? */ + PC = err_PC; /* stop for now */ + break; } } + break; + case 0705: /* MWI (E_NO) */ + while (XR != 0) { /* loop */ + t = ReadW (AR & VAMASK); /* read curr */ + WriteWA (BR & VAMASK, t); /* write alt */ + AR = (AR + 1) & DMASK; /* incr ptrs */ + BR = (BR + 1) & DMASK; + XR = (XR - 1) & DMASK; + if (XR && intrq) { /* more and intr? */ + PC = err_PC; /* stop for now */ + break; } } + break; + case 0706: /* MWF (E_NO) */ + while (XR != 0) { /* loop */ + t = ReadWA (AR & VAMASK); /* read alt */ + WriteW (BR & VAMASK, t); /* write curr */ + AR = (AR + 1) & DMASK; /* incr ptrs */ + BR = (BR + 1) & DMASK; + XR = (XR - 1) & DMASK; + if (XR && intrq) { /* more and intr? */ + PC = err_PC; /* stop for now */ + break; } } + break; + case 0707: /* MWW (E_NO) */ + while (XR != 0) { /* loop */ + t = ReadWA (AR & VAMASK); /* read alt */ + WriteWA (BR & VAMASK, t); /* write alt */ + AR = (AR + 1) & DMASK; /* incr ptrs */ + BR = (BR + 1) & DMASK; + XR = (XR - 1) & DMASK; + if (XR && intrq) { /* more and intr? */ + PC = err_PC; /* stop for now */ + break; } } + break; -/* Extended instruction group: DMS, continued */ +/* DMS, continued */ - case 010: /* SYA, SYB */ - case 011: /* USA, USB */ - case 012: /* PAA, PAB */ - case 013: /* PBA, PBB */ - mapi = (op & 03) << VA_N_PAG; /* map base */ - if (ABREG[absel] & SIGN) { /* store? */ - for (i = 0; i < MAP_LNT; i++) { - t = dms_rmap (mapi + i); - WriteW ((ABREG[absel] + i) & VAMASK, t); } } - else { /* load */ - dms_viol (err_PC, MVI_PRV, 0); /* priv if PRO */ - for (i = 0; i < MAP_LNT; i++) { - t = ReadW (ABREG[absel] + i & VAMASK); - dms_wmap (mapi + i, t); } } - ABREG[absel] = (ABREG[absel] + MAP_LNT) & DMASK; - break; - case 014: /* SSM */ - WriteW (MA, dms_upd_sr ()); /* store stat */ - break; - case 015: /* JRS */ - if (dms_ump) dms_viol (err_PC, MVI_PRV, 0); - t = ReadW (MA); /* get status */ - if (t & 0100000) dms_enb = 1; /* set/clr enb */ - else dms_enb = 0; - if (t & 0040000) dms_ump = 1; /* set/clr usr */ - else dms_ump = 0; - PCQ_ENTRY; /* save old PC */ - PC = M1; /* jump */ - ion_defer = 1; /* defer intr */ - break; + case 0710: /* SYA, SYB (E_NO) */ + case 0711: /* USA, USB (E_NO) */ + case 0712: /* PAA, PAB (E_NO) */ + case 0713: /* PBA, PBB (E_NO) */ + mapi = (IR & 03) << VA_N_PAG; /* map base */ + if (ABREG[absel] & SIGN) { /* store? */ + for (i = 0; i < MAP_LNT; i++) { + t = dms_rmap (mapi + i); /* map to memory */ + WriteW ((ABREG[absel] + i) & VAMASK, t); } } + else { /* load */ + dms_viol (err_PC, MVI_PRV); /* priv if PRO */ + for (i = 0; i < MAP_LNT; i++) { + t = ReadW ((ABREG[absel] + i) & VAMASK); + dms_wmap (mapi + i, t); } } /* mem to map */ + ABREG[absel] = (ABREG[absel] + MAP_LNT) & DMASK; + break; + case 0714: /* SSM (E_AD) */ + WriteW (MA, dms_upd_sr ()); /* store stat */ + break; + case 0715: /* JRS (E_AA) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); + t = ReadW (MA); /* get status */ + dms_enb = 0; /* assume off */ + dms_ump = SMAP; + if (t & 0100000) { /* set enable? */ + dms_enb = 1; + if (t & 0040000) dms_ump = UMAP; } /* set/clr usr */ + PCQ_ENTRY; /* save old PC */ + PC = M1; /* jump */ + ion_defer = 1; /* defer intr */ + break; -/* Extended instruction group: DMS, continued */ +/* DMS, continued */ - case 020: /* XMM */ - if (XR == 0) break; /* nop? */ - if (XR & SIGN) { /* store? */ - for ( ; XR == 0; XR = (XR + 1) & DMASK) { - t = dms_rmap (AR & MAP_MASK); - WriteW (BR & VAMASK, t); - AR = (AR + 1) & DMASK; - BR = (BR + 1) & DMASK; } } - else { /* load */ - for ( ; XR == 0; XR--) { - t = ReadW (BR & VAMASK); - dms_wmap (AR & MAP_MASK, t); - AR = (AR + 1) & DMASK; - BR = (BR + 1) & DMASK; } } - break; - case 021: /* XMS */ - if (XR & SIGN) break; /* nop? */ - for ( ; XR == 0; XR = (XR - 1) & DMASK) { - dms_wmap (AR & MAP_MASK, BR); - AR = (AR + 1) & DMASK; - BR = (BR + 1) & DMASK; } - break; - case 022: /* XMA, XMB */ - if (ABREG[absel] & 0100000) mapi = SMAP; - else mapi = UMAP; - if (ABREG[absel] & 0040000) mapj = PAMAP; - else mapj = PBMAP; - for (i = 0; i < MAP_LNT; i++) { - t = dms_rmap (mapi + i); - dms_wmap (mapj + i, t); } - break; - case 024: /* XLA, XLB */ - ABREG[absel] = ReadWA (MA); /* load alt */ - break; - case 025: /* XSA, XSB */ - dms_viol (err_PC, MVI_PRV, 0); /* priv if PRO */ - WriteWA (MA, ABREG[absel]); /* store alt */ - break; - case 026: /* XCA, XCB */ - if (ABREG[absel] != ReadWA (MA)) - PC = (PC + 1) & VAMASK; - break; - case 027: /* LFA, LFB */ - if (dms_ump) dms_viol (err_PC, MVI_PRV, 0); - dms_sr = (dms_sr & ~(MST_FLT | MST_FENCE)) | - (ABREG[absel] & (MST_FLT | MST_FENCE)); - dms_fence = dms_sr & MST_FENCE; - break; + case 0700: case 0720: /* XMM (E_NO) */ + if (XR == 0) break; /* nop? */ + while (XR != 0) { /* loop */ + if (XR & SIGN) { /* store? */ + t = dms_rmap (AR); /* map to mem */ + WriteW (BR & VAMASK, t); + XR = (XR + 1) & DMASK; } + else { /* load */ + dms_viol (err_PC, MVI_PRV); /* priv if PRO */ + t = ReadW (BR & VAMASK); /* mem to map */ + dms_wmap (AR, t); + XR = (XR - 1) & DMASK; } + AR = (AR + 1) & DMASK; + BR = (BR + 1) & DMASK; + if (intrq && ((XR & 0xF) == 0xF)) { /* intr, cnt4 = F? */ + PC = err_PC; /* stop for now */ + break; } } + break; + case 0721: /* XMS (E_NO) */ + if ((XR & SIGN) || (XR == 0)) break; /* nop? */ + dms_viol (err_PC, MVI_PRV); /* priv if PRO */ + while (XR != 0) { + dms_wmap (AR, BR); /* AR to map */ + XR = (XR - 1) & DMASK; + AR = (AR + 1) & DMASK; + BR = (BR + 1) & DMASK; + if (intrq && ((XR & 0xF) == 0xF)) { /* intr, cnt4 = F? */ + PC = err_PC; + break; } } + break; + case 0722: /* XMA, XMB (E_NO) */ + dms_viol (err_PC, MVI_PRV); /* priv if PRO */ + if (ABREG[absel] & 0100000) mapi = UMAP; + else mapi = SMAP; + if (ABREG[absel] & 0000001) mapj = PBMAP; + else mapj = PAMAP; + for (i = 0; i < MAP_LNT; i++) { + t = dms_rmap (mapi + i); /* read map */ + dms_wmap (mapj + i, t); } /* write map */ + break; + case 0724: /* XLA, XLB (E_AD) */ + ABREG[absel] = ReadWA (MA); /* load alt */ + break; + case 0725: /* XSA, XSB (E_AD) */ + WriteWA (MA, ABREG[absel]); /* store alt */ + break; + case 0726: /* XCA, XCB (E_AD) */ + if (ABREG[absel] != ReadWA (MA)) /* compare alt */ + PC = (PC + 1) & VAMASK; + break; + case 0727: /* LFA, LFB (E_NO) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); + dms_sr = (dms_sr & ~(MST_FLT | MST_FENCE)) | + (ABREG[absel] & (MST_FLT | MST_FENCE)); + break; -/* Extended instruction group: DMS, continued */ +/* DMS, continued */ - case 030: /* RSA, RSB */ - ABREG[absel] = dms_upd_sr (); /* save stat */ - break; - case 031: /* RVA, RVB */ - ABREG[absel] = dms_vr; /* save viol */ - break; - case 032: /* DJP */ - if (dms_ump) dms_viol (err_PC, MVI_PRV, 0); - if (MP_TESTJ (MA)) ABORT (ABORT_FENCE); - dms_enb = 0; - PCQ_ENTRY; - PC = MA; - ion_defer = 1; - break; - case 033: /* DJS */ - if (dms_ump) dms_viol (err_PC, MVI_PRV, 0); - dms_enb = 0; - WriteW (MA, PC); - PCQ_ENTRY; - PC = (MA + 1) & VAMASK; - ion_defer = 1; - break; - case 034: /* SJP */ - if (dms_ump) dms_viol (err_PC, MVI_PRV, 0); - if (MP_TESTJ (MA)) ABORT (ABORT_FENCE); - dms_enb = 1; - dms_ump = 0; - PCQ_ENTRY; - PC = MA; - ion_defer = 1; - break; - case 035: /* SJS */ - if (dms_ump) dms_viol (err_PC, MVI_PRV, 0); - dms_enb = 1; - dms_ump = 0; - WriteW (MA, PC); - PCQ_ENTRY; - PC = (MA + 1) & VAMASK; - ion_defer = 1; - break; - case 036: /* UJP */ - if (dms_ump) dms_viol (err_PC, MVI_PRV, 0); - if (MP_TESTJ (MA)) ABORT (ABORT_FENCE); - dms_enb = 1; - dms_ump = 1; - PCQ_ENTRY; - PC = MA; - ion_defer = 1; - break; - case 037: /* UJS */ - if (dms_ump) dms_viol (err_PC, MVI_PRV, 0); - dms_enb = 1; - dms_ump = 1; - WriteW (MA, PC); - PCQ_ENTRY; - PC = (MA + 1) & VAMASK; - ion_defer = 1; - break; + case 0730: /* RSA, RSB (E_NO) */ + ABREG[absel] = dms_upd_sr (); /* save stat */ + break; + case 0731: /* RVA, RVB (E_NO) */ + ABREG[absel] = dms_vr; /* save viol */ + break; + case 0732: /* DJP (E_AD) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); + mp_dms_jmp (MA); /* validate jump addr */ + PCQ_ENTRY; /* save curr PC */ + PC = MA; /* new PC */ + dms_enb = 0; /* disable map */ + dms_ump = SMAP; + ion_defer = 1; + break; + case 0733: /* DJS (E_AD) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); + WriteW (MA, PC); /* store ret addr */ + PCQ_ENTRY; /* save curr PC */ + PC = (MA + 1) & VAMASK; /* new PC */ + dms_enb = 0; /* disable map */ + dms_ump = SMAP; + ion_defer = 1; /* defer intr */ + break; + case 0734: /* SJP (E_AD) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); + mp_dms_jmp (MA); /* validate jump addr */ + PCQ_ENTRY; /* save curr PC */ + PC = MA; /* jump */ + dms_enb = 1; /* enable system */ + dms_ump = SMAP; + ion_defer = 1; /* defer intr */ + break; + case 0735: /* SJS (E_AD) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); + t = PC; /* save retn addr */ + PCQ_ENTRY; /* save curr PC */ + PC = (MA + 1) & VAMASK; /* new PC */ + dms_enb = 1; /* enable system */ + dms_ump = SMAP; + WriteW (MA, t); /* store ret addr */ + ion_defer = 1; /* defer intr */ + break; + case 0736: /* UJP (E_AD) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); + mp_dms_jmp (MA); /* validate jump addr */ + PCQ_ENTRY; /* save curr PC */ + PC = MA; /* jump */ + dms_enb = 1; /* enable user */ + dms_ump = UMAP; + ion_defer = 1; /* defer intr */ + break; + case 0737: /* UJS (E_AD) */ + if (dms_ump) dms_viol (err_PC, MVI_PRV); + t = PC; /* save retn addr */ + PCQ_ENTRY; /* save curr PC */ + PC = (MA + 1) & VAMASK; /* new PC */ + dms_enb = 1; /* enable user */ + dms_ump = UMAP; + WriteW (MA, t); /* store ret addr */ + ion_defer = 1; /* defer intr */ + break; -/* Extended instruction group: index register instructions */ +/* Index register instructions */ - case 040: /* SAX, SBX */ - MA = (MA + XR) & VAMASK; - WriteW (MA, ABREG[absel]); - break; - case 041: /* CAX, CBX */ - XR = ABREG[absel]; - break; - case 042: /* LAX, LBX */ - MA = (MA + XR) & VAMASK; - ABREG[absel] = ReadW (MA); - break; - case 043: /* STX */ - WriteW (MA, XR); - break; - case 044: /* CXA, CXB */ - ABREG[absel] = XR; - break; - case 045: /* LDX */ - XR = ReadW (MA); - break; - case 046: /* ADX */ - opnd = ReadW (MA); - t = XR + opnd; - if (t > DMASK) E = 1; - if (((~XR ^ opnd) & (XR ^ t)) & SIGN) O = 1; - XR = t & DMASK; - break; - case 047: /* XAX, XBX */ - t = XR; - XR = ABREG[absel]; - ABREG[absel] = t; - break; - case 050: /* SAY, SBY */ - MA = (MA + YR) & VAMASK; - WriteW (MA, ABREG[absel]); - break; - case 051: /* CAY, CBY */ - YR = ABREG[absel]; - break; - case 052: /* LAY, LBY */ - MA = (MA + YR) & VAMASK; - ABREG[absel] = ReadW (MA); - break; - case 053: /* STY */ - WriteW (MA, YR); - break; - case 054: /* CYA, CYB */ - ABREG[absel] = YR; - break; - case 055: /* LDY */ - YR = ReadW (MA); - break; - case 056: /* ADY */ - opnd = ReadW (MA); - t = YR + opnd; - if (t > DMASK) E = 1; - if (((~YR ^ opnd) & (YR ^ t)) & SIGN) O = 1; - YR = t & DMASK; - break; - case 057: /* XAY, XBY */ - t = YR; - YR = ABREG[absel]; - ABREG[absel] = t; - break; - case 060: /* ISX */ - XR = (XR + 1) & DMASK; - if (XR == 0) PC = (PC + 1) & VAMASK; - break; - case 061: /* DSX */ - XR = (XR - 1) & DMASK; - if (XR == 0) PC = (PC + 1) & VAMASK; - break; - case 062: /* JLY */ - if (MP_TESTJ (MA)) ABORT (ABORT_FENCE); - PCQ_ENTRY; - YR = PC; - PC = MA; - break; - case 070: /* ISY */ - YR = (YR + 1) & DMASK; - if (YR == 0) PC = (PC + 1) & VAMASK; - break; - case 071: /* DSY */ - YR = (YR - 1) & DMASK; - if (YR == 0) PC = (PC + 1) & VAMASK; - break; - case 072: /* JPY */ - MA = (ReadW (PC) + YR) & VAMASK; /* no indirect */ - PC = (PC + 1) & VAMASK; - if (MP_TESTJ (MA)) ABORT (ABORT_FENCE); - PCQ_ENTRY; - PC = MA; - break; + case 0740: /* SAX, SBX (E_AD) */ + MA = (MA + XR) & VAMASK; /* indexed addr */ + WriteW (MA, ABREG[absel]); /* store */ + break; + case 0741: /* CAX, CBX (E_NO) */ + XR = ABREG[absel]; /* copy to XR */ + break; + case 0742: /* LAX, LBX (E_AD) */ + MA = (MA + XR) & VAMASK; /* indexed addr */ + ABREG[absel] = ReadW (MA); /* load */ + break; + case 0743: /* STX (E_AD) */ + WriteW (MA, XR); /* store XR */ + break; + case 0744: /* CXA, CXB (E_NO) */ + ABREG[absel] = XR; /* copy from XR */ + break; + case 0745: /* LDX (E_AD)*/ + XR = ReadW (MA); /* load XR */ + break; + case 0746: /* ADX (E_AD) */ + v1 = ReadW (MA); /* add to XR */ + t = XR + v1; + if (t > DMASK) E = 1; /* set E, O */ + if (((~XR ^ v1) & (XR ^ t)) & SIGN) O = 1; + XR = t & DMASK; + break; + case 0747: /* XAX, XBX (E_NO) */ + t = XR; /* exchange XR */ + XR = ABREG[absel]; + ABREG[absel] = t; + break; + case 0750: /* SAY, SBY (E_AD) */ + MA = (MA + YR) & VAMASK; /* indexed addr */ + WriteW (MA, ABREG[absel]); /* store */ + break; + case 0751: /* CAY, CBY (E_NO) */ + YR = ABREG[absel]; /* copy to YR */ + break; + case 0752: /* LAY, LBY (E_AD) */ + MA = (MA + YR) & VAMASK; /* indexed addr */ + ABREG[absel] = ReadW (MA); /* load */ + break; + case 0753: /* STY (E_AD) */ + WriteW (MA, YR); /* store YR */ + break; + case 0754: /* CYA, CYB (E_NO) */ + ABREG[absel] = YR; /* copy from YR */ + break; + case 0755: /* LDY (E_AD) */ + YR = ReadW (MA); /* load YR */ + break; + case 0756: /* ADY (E_AD) */ + v1 = ReadW (MA); /* add to YR */ + t = YR + v1; + if (t > DMASK) E = 1; /* set E, O */ + if (((~YR ^ v1) & (YR ^ t)) & SIGN) O = 1; + YR = t & DMASK; + break; + case 0757: /* XAY, XBY (E_NO) */ + t = YR; /* exchange YR */ + YR = ABREG[absel]; + ABREG[absel] = t; + break; + case 0760: /* ISX (E_NO) */ + XR = (XR + 1) & DMASK; /* incr XR */ + if (XR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */ + break; + case 0761: /* DSX (E_NO) */ + XR = (XR - 1) & DMASK; /* decr XR */ + if (XR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */ + break; + case 0762: /* JLY (E_AD) */ + mp_dms_jmp (MA); /* validate jump addr */ + PCQ_ENTRY; + YR = PC; /* ret addr to YR */ + PC = MA; /* jump */ + break; + case 0770: /* ISY (E_NO) */ + YR = (YR + 1) & DMASK; /* incr YR */ + if (YR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */ + break; + case 0771: /* DSY (E_NO) */ + YR = (YR - 1) & DMASK; /* decr YR */ + if (YR == 0) PC = (PC + 1) & VAMASK; /* skip if zero */ + break; + case 0772: /* JPY (E_NO) */ + MA = (ReadW (PC) + YR) & VAMASK; /* index, no indir */ + PC = (PC + 1) & VAMASK; + mp_dms_jmp (MA); /* validate jump addr */ + PCQ_ENTRY; + PC = MA; /* jump */ + break; -/* Extended instruction group: byte */ +/* Byte instructions */ - case 063: /* LBT */ - AR = ReadB (BR); - BR = (BR + 1) & DMASK; - break; - case 064: /* SBT */ - WriteB (BR, AR); - BR = (BR + 1) & DMASK; - break; - case 065: /* MBT */ - t = ReadW (awc); /* get wc */ - while (t) { /* while count */ - q = ReadB (AR); /* move byte */ - WriteB (BR, q); - AR = (AR + 1) & DMASK; /* incr src */ - BR = (BR + 1) & DMASK; /* incr dst */ - t = (t - 1) & DMASK; /* decr cnt */ - WriteW (awc, t); } - break; - case 066: /* CBT */ - t = ReadW (awc); /* get wc */ - while (t) { /* while count */ - q = ReadB (AR); /* get src1 */ - r = ReadB (BR); /* get src2 */ - if (q != r) { /* compare */ - PC = (PC + 1 + (q > r)) & VAMASK; - BR = (BR + t) & DMASK; /* update BR */ - WriteW (awc, 0); /* clr awc */ - break; } - AR = (AR + 1) & DMASK; /* incr src1 */ - BR = (BR + 1) & DMASK; /* incr src2 */ - t = (t - 1) & DMASK; /* decr cnt */ - WriteW (awc, t); } - break; - case 067: /* SFB */ - q = AR & 0377; /* test byte */ - r = (AR >> 8) & 0377; /* term byte */ - for (;;) { /* scan */ - t = ReadB (BR); /* get byte */ - if (t == q) break; /* test match? */ - BR = (BR + 1) & DMASK; - if (t == r) { /* term match? */ - PC = (PC + 1) & VAMASK; - break; } } - break; + case 0763: /* LBT (E_NO) */ + AR = ReadB (BR); /* load byte */ + BR = (BR + 1) & DMASK; /* incr ptr */ + break; + case 0764: /* SBT (E_NO) */ + WriteB (BR, AR); /* store byte */ + break; + IOP_MBYTE: /* IOP MBYTE (I_AZ) */ + if (wc & SIGN) break; /* must be positive */ + case 0765: /* MBT (E_AZ) */ + while (wc != 0) { /* while count */ + WriteW (awc, wc); /* for abort */ + t = ReadB (AR); /* move byte */ + WriteB (BR, t); + AR = (AR + 1) & DMASK; /* incr src */ + BR = (BR + 1) & DMASK; /* incr dst */ + wc = (wc - 1) & DMASK; /* decr cnt */ + if (intrq && wc) { /* intr, more to do? */ + PC = err_PC; /* back up PC */ + break; } } /* take intr */ + WriteW (awc, wc); /* clean up inline */ + break; + case 0766: /* CBT (E_AZ) */ + while (wc != 0) { /* while count */ + WriteW (awc, wc); /* for abort */ + v1 = ReadB (AR); /* get src1 */ + v2 = ReadB (BR); /* get src2 */ + if (v1 != v2) { /* compare */ + PC = (PC + 1 + (v1 > v2)) & VAMASK; + BR = (BR + wc) & DMASK; /* update BR */ + wc = 0; /* clr interim */ + break; } + AR = (AR + 1) & DMASK; /* incr src1 */ + BR = (BR + 1) & DMASK; /* incr src2 */ + wc = (wc - 1) & DMASK; /* decr cnt */ + if (intrq && wc) { /* intr, more to do? */ + PC = err_PC; /* back up PC */ + break; } } /* take intr */ + WriteW (awc, wc); /* clean up inline */ + break; + case 0767: /* SFB (E_NO) */ + v1 = AR & 0377; /* test byte */ + v2 = (AR >> 8) & 0377; /* term byte */ + for (;;) { /* scan */ + t = ReadB (BR); /* read byte */ + if (t == v1) break; /* test match? */ + BR = (BR + 1) & DMASK; + if (t == v2) { /* term match? */ + PC = (PC + 1) & VAMASK; + break; } + if (intrq) { /* int pending? */ + PC = err_PC; /* back up PC */ + break; } } /* take intr */ + break; -/* Extended instruction group: bit, word */ +/* Bit, word instructions */ - case 073: /* SBS */ - WriteW (M1, M[M1] | M [MA]); - break; - case 074: /* CBS */ - WriteW (M1, M[M1] & ~M[MA]); - break; - case 075: /* TBS */ - if ((M[M1] & M[MA]) != M[MA]) PC = (PC + 1) & VAMASK; - break; - case 076: /* CMW */ - t = ReadW (awc); /* get wc */ - while (t) { /* while count */ - q = SEXT (M[AR & VAMASK]); - r = SEXT (M[BR & VAMASK]); - if (q != r) { /* compare */ - PC = (PC + 1 + (q > r)) & VAMASK; - BR = (BR + t) & DMASK; /* update BR */ - WriteW (awc, 0); /* clr awc */ - break; } - AR = (AR + 1) & DMASK; /* incr src1 */ - BR = (BR + 1) & DMASK; /* incr src2 */ - t = (t - 1) & DMASK; /* decr cnt */ - WriteW (awc, t); } - break; - case 077: /* MVW */ - t = ReadW (awc); /* get wc */ - while (t) { /* while count */ - q = ReadW (AR & VAMASK); /* move word */ - WriteW (BR & VAMASK, q); - AR = (AR + 1) & DMASK; /* incr src */ - BR = (BR + 1) & DMASK; /* incr dst */ - t = (t - 1) & DMASK; /* decr cnt */ - WriteW (awc, t); } - break; } /* end ext group */ - default: - reason = stop_inst; } /* end switch IR */ - } /* end if extended */ + case 0773: /* SBS (E_AA) */ + WriteW (M1, M[M1] | M [MA]); /* set bit */ + break; + case 0774: /* CBS (E_AA) */ + WriteW (M1, M[M1] & ~M[MA]); /* clear bit */ + break; + case 0775: /* TBS (E_AA) */ + if ((M[MA] & M[M1]) != M[MA]) /* test bit */ + PC = (PC + 1) & VAMASK; + break; + case 0776: /* CMW (E_AZ) */ + while (wc != 0) { /* while count */ + WriteW (awc, wc); /* for abort */ + v1 = ReadW (AR & VAMASK); /* first op */ + v2 = ReadW (BR & VAMASK); /* second op */ + sop1 = (int32) SEXT (v1); /* signed */ + sop2 = (int32) SEXT (v2); + if (sop1 != sop2) { /* compare */ + PC = (PC + 1 + (sop1 > sop2)) & VAMASK; + BR = (BR + wc) & DMASK; /* update BR */ + wc = 0; /* clr interim */ + break; } + AR = (AR + 1) & DMASK; /* incr src1 */ + BR = (BR + 1) & DMASK; /* incr src2 */ + wc = (wc - 1) & DMASK; /* decr cnt */ + if (intrq && wc) { /* intr, more to do? */ + PC = err_PC; /* back up PC */ + break; } } /* take intr */ + WriteW (awc, wc); /* clean up inline */ + break; + case 0200: /* IOP WMOVE (I_AZ) */ + if (wc & SIGN) break; /* must be positive */ + case 0777: /* MVW (E_AZ) */ + while (wc != 0) { /* while count */ + WriteW (awc, wc); /* for abort */ + t = ReadW (AR & VAMASK); /* move word */ + WriteW (BR & VAMASK, t); + AR = (AR + 1) & DMASK; /* incr src */ + BR = (BR + 1) & DMASK; /* incr dst */ + wc = (wc - 1) & DMASK; /* decr cnt */ + if (intrq && wc) { /* intr, more to do? */ + PC = err_PC; /* back up PC */ + break; } } /* take intr */ + WriteW (awc, wc); /* clean up inline */ + break; + default: /* all others NOP */ + break; } /* end case ext */ + break; } /* end case IR */ + +if (reason == STOP_INDINT) { /* indirect intr? */ + PC = err_PC; /* back out of inst */ + ion_defer = 0; /* clear defer */ + reason = 0; } /* continue */ } /* end while */ /* Simulation halted */ saved_AR = AR & DMASK; saved_BR = BR & DMASK; -for (i = 0; dibp = dib_tab[i]; i++) { /* loop thru dev */ - dev = dibp -> devno; - dibp -> cmd = CMD (dev); - dibp -> ctl = CTL (dev); - dibp -> flg = FLG (dev); - dibp -> fbf = FBF (dev); } -pcq_r -> qptr = pcq_p; /* update pc q ptr */ +for (i = 0; dptr = sim_devices[i]; i++) { /* loop thru dev */ + dibp = (DIB *) dptr->ctxt; /* get DIB */ + if (dibp) { /* exist? */ + dev = dibp->devno; + dibp->cmd = CMD (dev); + dibp->ctl = CTL (dev); + dibp->flg = FLG (dev); + dibp->fbf = FBF (dev); } } +pcq_r->qptr = pcq_p; /* update pc q ptr */ return reason; } +/* Effective address calculation */ + +t_stat Ea (uint32 IR, uint32 *addr, uint32 irq) +{ +uint32 i, MA; + +MA = IR & (I_IA | I_DISP); /* ind + disp */ +if (IR & I_CP) MA = ((PC - 1) & I_PAGENO) | MA; /* current page? */ +for (i = 0; (i < ind_max) && (MA & I_IA); i++) { /* resolve multilevel */ + if ((i >= 2) && irq && /* >3 levels, int req, */ + (cpu_unit.flags & UNIT_MPR)) /* mprot installed? */ + return STOP_INDINT; /* break out */ + MA = ReadW (MA & VAMASK); } +if (i >= ind_max) return STOP_IND; /* indirect loop? */ +*addr = MA; +return SCPE_OK; +} + +/* Effective address, two words */ + +t_stat Ea1 (uint32 *addr, uint32 irq) +{ +uint32 i, MA; + +MA = ReadW (PC); /* get next address */ +PC = (PC + 1) & VAMASK; +for (i = 0; (i < ind_max) && (MA & I_IA); i++) { /* resolve multilevel */ + if ((i >= 2) && irq && /* >3 levels, int req, */ + (cpu_unit.flags & UNIT_MPR)) /* mprot installed? */ + return STOP_INDINT; /* break out */ + MA = ReadW (MA & VAMASK); } +if (i >= ind_max) return STOP_IND; /* indirect loop? */ +*addr = MA; +return SCPE_OK; +} + /* Shift micro operation */ -int32 shift (int32 t, int32 flag, int32 op) +uint32 shift (uint32 t, uint32 flag, uint32 op) { -int32 oldE; +uint32 oldE; op = op & 07; /* get shift op */ if (flag) { /* enabled? */ switch (op) { /* case on operation */ case 00: /* signed left shift */ - return ((t & SIGN) | ((t << 1) & 077777)); + return ((t & SIGN) | ((t << 1) & 077777)); case 01: /* signed right shift */ - return ((t & SIGN) | (t >> 1)); + return ((t & SIGN) | (t >> 1)); case 02: /* rotate left */ - return (((t << 1) | (t >> 15)) & DMASK); + return (((t << 1) | (t >> 15)) & DMASK); case 03: /* rotate right */ - return (((t >> 1) | (t << 15)) & DMASK); + return (((t >> 1) | (t << 15)) & DMASK); case 04: /* left shift, 0 sign */ - return ((t << 1) & 077777); + return ((t << 1) & 077777); case 05: /* ext right rotate */ - oldE = E; - E = t & 1; - return ((t >> 1) | (oldE << 15)); + oldE = E; + E = t & 1; + return ((t >> 1) | (oldE << 15)); case 06: /* ext left rotate */ - oldE = E; - E = (t >> 15) & 1; - return (((t << 1) | oldE) & DMASK); + oldE = E; + E = (t >> 15) & 1; + return (((t << 1) | oldE) & DMASK); case 07: /* rotate left four */ - return (((t << 4) | (t >> 12)) & DMASK); - } /* end case */ + return (((t << 4) | (t >> 12)) & DMASK); + } /* end case */ } /* end if */ if (op == 05) E = t & 1; /* disabled ext rgt rot */ if (op == 06) E = (t >> 15) & 1; /* disabled ext lft rot */ return t; /* input unchanged */ } +/* IO instruction decode */ + +t_stat iogrp (uint32 ir, uint32 iotrap) +{ +uint32 dev, sop, iodata, ab; + +ab = (ir & I_AB)? 1: 0; /* get A/B select */ +dev = ir & I_DEVMASK; /* get device */ +sop = I_GETIOOP (ir); /* get subopcode */ +if (!iotrap && CTL (PRO) && ((sop == ioHLT) || (dev != OVF))) { /* protected? */ + if (sop == ioLIX) ABREG[ab] = 0; /* A/B writes anyway */ + ABORT (ABORT_PRO); } +iodata = devdisp (dev, sop, ir, ABREG[ab]); /* process I/O */ +ion_defer = defer_tab[sop]; /* set defer */ +if ((sop == ioMIX) || (sop == ioLIX)) /* store ret data */ + ABREG[ab] = iodata & DMASK; +if (sop == ioHLT) return STOP_HALT; /* halt? */ +return (iodata >> IOT_V_REASON); /* return status */ +} + /* Device dispatch */ -int32 devdisp (int32 devno, int32 inst, int32 IR, int32 dat) +uint32 devdisp (uint32 devno, uint32 inst, uint32 IR, uint32 dat) { if (dtab[devno]) return dtab[devno] (inst, IR, dat); else return nulio (inst, IR, dat); @@ -1385,14 +1827,14 @@ else return nulio (inst, IR, dat); /* Calculate DMA requests */ -int32 calc_dma (void) +uint32 calc_dma (void) { -int32 r = 0; +uint32 r = 0; -if (CMD (DMA0) && dmac[0].cw3 && /* check DMA0 cycle */ - FLG (dmac[0].cw1 & DEVMASK)) r = r | DMAR0; -if (CMD (DMA0) && dmac[1].cw3 && /* check DMA1 cycle */ - FLG (dmac[1].cw1 & DEVMASK)) r = r | DMAR1; +if (CMD (DMA0) && FLG (dmac[0].cw1 & I_DEVMASK)) /* check DMA0 cycle */ + r = r | DMAR0; +if (CMD (DMA1) && FLG (dmac[1].cw1 & I_DEVMASK)) /* check DMA1 cycle */ + r = r | DMAR1; return r; } @@ -1416,7 +1858,7 @@ return r; if any. */ -int32 calc_int (void) +uint32 calc_int (void) { int32 j, lomask, mask[2], req[2]; @@ -1427,26 +1869,26 @@ mask[0] = lomask | (lomask - 1); /* enabled devices */ req[0] = req[0] & mask[0]; /* highest request */ if (ion) { /* ion? */ if (lomask == 0) { /* no break in chn? */ - mask[1] = dev_flg[1] & dev_ctl[1]; /* do all devices */ - req[1] = mask[1] & dev_fbf[1]; - mask[1] = mask[1] & (-mask[1]); - mask[1] = mask[1] | (mask[1] - 1); - req[1] = req[1] & mask[1]; } + mask[1] = dev_flg[1] & dev_ctl[1]; /* do all devices */ + req[1] = mask[1] & dev_fbf[1]; + mask[1] = mask[1] & (-mask[1]); + mask[1] = mask[1] | (mask[1] - 1); + req[1] = req[1] & mask[1]; } else req[1] = 0; } else { req[0] = req[0] & (INT_M (PWR) | INT_M (PRO)); req[1] = 0; } if (req[0]) { /* if low request */ for (j = 0; j < 32; j++) { /* find dev # */ - if (req[0] & INT_M (j)) return j; } } + if (req[0] & INT_M (j)) return j; } } if (req[1]) { /* if hi request */ for (j = 0; j < 32; j++) { /* find dev # */ - if (req[1] & INT_M (j)) return (32 + j); } } + if (req[1] & INT_M (j)) return (32 + j); } } return 0; } /* Memory access routines */ -uint8 ReadB (int32 va) +uint8 ReadB (uint32 va) { int32 pa; @@ -1456,9 +1898,9 @@ if (va & 1) return (M[pa] & 0377); else return ((M[pa] >> 8) & 0377); } -uint8 ReadBA (int32 va) +uint8 ReadBA (uint32 va) { -int32 pa; +uint32 pa; if (dms_enb) pa = dms (va >> 1, dms_ump ^ MAP_LNT, RD); else pa = va >> 1; @@ -1466,129 +1908,186 @@ if (va & 1) return (M[pa] & 0377); else return ((M[pa] >> 8) & 0377); } -uint16 ReadW (int32 va) +uint16 ReadW (uint32 va) { -int32 pa; +uint32 pa; if (dms_enb) pa = dms (va, dms_ump, RD); else pa = va; return M[pa]; } -uint16 ReadWA (int32 va) +uint16 ReadWA (uint32 va) { -int32 pa; +uint32 pa; if (dms_enb) pa = dms (va, dms_ump ^ MAP_LNT, RD); else pa = va; return M[pa]; } -uint32 ReadF (int32 va) +uint32 ReadF (uint32 va) { uint32 t = ReadW (va); uint32 t1 = ReadW ((va + 1) & VAMASK); return (t << 16) | t1; } -uint16 ReadIO (int32 va, int32 map) +uint16 ReadIO (uint32 va, uint32 map) { -int32 pa; +uint32 pa; -if (dms_enb) pa = dms (va, map, RD); +if (dms_enb) pa = dms_io (va, map); else pa = va; return M[pa]; } -void WriteB (int32 va, int32 dat) -{ -int32 pa; +/* Memory protection test for writes */ -if (MP_TEST (va)) ABORT (ABORT_FENCE); -if (dms_enb) pa = dms (va >> 1, dms_ump ^ MAP_LNT, WR); -else pa = va >> 1; +#define MP_TEST(x) (CTL (PRO) && ((x) > 1) && ((x) < mp_fence)) + +void WriteB (uint32 va, uint32 dat) +{ +uint32 pa; + +if (dms_enb) pa = dms (va >> 1, dms_ump, WR); +else { if (MP_TEST (va >> 1)) ABORT (ABORT_PRO); + pa = va >> 1; } if (MEM_ADDR_OK (pa)) { if (va & 1) M[pa] = (M[pa] & 0177400) | (dat & 0377); else M[pa] = (M[pa] & 0377) | ((dat & 0377) << 8); } return; } -void WriteBA (int32 va, int32 dat) +void WriteBA (uint32 va, uint32 dat) { -int32 pa; +uint32 pa; -if (MP_TEST (va)) ABORT (ABORT_FENCE); -if (dms_enb) pa = dms (va >> 1, dms_ump ^ MAP_LNT, WR); -else pa = va >> 1; +if (dms_enb) { + dms_viol (va >> 1, MVI_WPR); /* viol if prot */ + pa = dms (va >> 1, dms_ump ^ MAP_LNT, WR); } +else { if (MP_TEST (va >> 1)) ABORT (ABORT_PRO); + pa = va >> 1; } if (MEM_ADDR_OK (pa)) { if (va & 1) M[pa] = (M[pa] & 0177400) | (dat & 0377); else M[pa] = (M[pa] & 0377) | ((dat & 0377) << 8); } return; } -void WriteW (int32 va, int32 dat) +void WriteW (uint32 va, uint32 dat) { -int32 pa; +uint32 pa; -if (MP_TEST (va)) ABORT (ABORT_FENCE); if (dms_enb) pa = dms (va, dms_ump, WR); -else pa = va; +else { if (MP_TEST (va)) ABORT (ABORT_PRO); + pa = va; } if (MEM_ADDR_OK (pa)) M[pa] = dat; return; } -void WriteWA (int32 va, int32 dat) +void WriteWA (uint32 va, uint32 dat) { int32 pa; -if (MP_TEST (va)) ABORT (ABORT_FENCE); -if (dms_enb) pa = dms (va, dms_ump ^ MAP_LNT, WR); -else pa = va; +if (dms_enb) { + dms_viol (va, MVI_WPR); /* viol if prot */ + pa = dms (va, dms_ump ^ MAP_LNT, WR); } +else { if (MP_TEST (va)) ABORT (ABORT_PRO); + pa = va; } if (MEM_ADDR_OK (pa)) M[pa] = dat; return; } -void WriteIO (int32 va, int32 dat, int32 map) +void WriteIO (uint32 va, uint32 dat, uint32 map) { -int32 pa; +uint32 pa; -if (dms_enb) pa = dms (va, map, WR); +if (dms_enb) pa = dms_io (va, map); else pa = va; if (MEM_ADDR_OK (pa)) M[pa] = dat; return; } -/* DMS relocation */ +/* DMS relocation for CPU access */ -int32 dms (int32 va, int32 map, int32 prot) +uint32 dms (uint32 va, uint32 map, uint32 prot) { -int32 pgn, mpr; +uint32 pgn, mpr; if (va <= 1) return va; /* A, B */ pgn = VA_GETPAG (va); /* get page num */ if (pgn == 0) { /* base page? */ + uint32 dms_fence = dms_sr & MST_FENCE; /* get fence value */ if ((dms_sr & MST_FLT)? /* check unmapped */ (va >= dms_fence): /* 1B10: >= fence */ (va < dms_fence)) { /* 0B10: < fence */ - if (prot == WR) dms_viol (va, MVI_BPG, 0); /* if W, viol */ - return va; } } /* no mapping */ + if (prot == WR) dms_viol (va, MVI_BPG); /* if W, viol */ + return va; } } /* no mapping */ mpr = dms_map[map + pgn]; /* get map reg */ -if (mpr & prot) dms_viol (va, prot << (MVI_V_WPR - MAPA_V_WPR), 0); +if (mpr & prot) dms_viol (va, prot << (MVI_V_WPR - MAPA_V_WPR)); return (PA_GETPAG (mpr) | VA_GETOFF (va)); } +/* DMS relocation for IO access */ + +uint32 dms_io (uint32 va, uint32 map) +{ +uint32 pgn, mpr; + +if (va <= 1) return va; /* A, B */ +pgn = VA_GETPAG (va); /* get page num */ +if (pgn == 0) { /* base page? */ + uint32 dms_fence = dms_sr & MST_FENCE; /* get fence value */ + if ((dms_sr & MST_FLT)? /* check unmapped */ + (va >= dms_fence): /* 1B10: >= fence */ + (va < dms_fence)) { /* 0B10: < fence */ + return va; } } /* no mapping */ +mpr = dms_map[map + pgn]; /* get map reg */ +return (PA_GETPAG (mpr) | VA_GETOFF (va)); +} + +/* DMS relocation for console access */ + +uint32 dms_cons (uint32 va, int32 sw) +{ +if (sw & SWMASK ("V")) return dms_io (va, dms_ump); +if (sw & SWMASK ("S")) return dms_io (va, SMAP); +if (sw & SWMASK ("U")) return dms_io (va, UMAP); +if (sw & SWMASK ("P")) return dms_io (va, PAMAP); +if (sw & SWMASK ("Q")) return dms_io (va, PBMAP); +return va; +} + +/* Mem protect and DMS validation for jumps */ + +void mp_dms_jmp (uint32 va) +{ +uint32 pgn = VA_GETPAG (va); /* get page num */ + +if ((pgn == 0) && (va > 1)) { /* base page? */ + uint32 dms_fence = dms_sr & MST_FENCE; /* get fence value */ + if ((dms_sr & MST_FLT)? /* check unmapped */ + (va >= dms_fence): /* 1B10: >= fence */ + (va < dms_fence)) { /* 0B10: < fence */ + dms_viol (va, MVI_BPG); /* if W, viol */ + return; } } /* PRO not set */ +if (CTL (PRO) && (va < mp_fence)) ABORT (ABORT_PRO); /* base page MPR */ +return; +} + /* DMS read and write maps */ -uint16 dms_rmap (int32 mapi) +uint16 dms_rmap (uint32 mapi) { int32 t; + mapi = mapi & MAP_MASK; t = (((dms_map[mapi] >> VA_N_OFF) & PA_M_PAG) | ((dms_map[mapi] & (RD | WR)) << (MAPM_V_WPR - MAPA_V_WPR))); return (uint16) t; } -void dms_wmap (int32 mapi, int32 dat) +void dms_wmap (uint32 mapi, uint32 dat) { mapi = mapi & MAP_MASK; dms_map[mapi] = ((dat & PA_M_PAG) << VA_N_OFF) | @@ -1596,33 +2095,23 @@ dms_map[mapi] = ((dat & PA_M_PAG) << VA_N_OFF) | return; } -/* DMS violation +/* DMS violation */ - DMS violation processing occurs in two parts - - The violation register is set based on DMS status - - An interrupt (abort) occurs only if CTL (PRO) is set - - Bit 7 (ME bus disabled/enabled) records whether relocation - actually occurred in the aborted cycle. For read and write - violations, bit 7 will be set; for base page and privilege - violations, it will be clear - - I/O map references set status bits but never abort -*/ - -void dms_viol (int32 va, int32 st, t_bool io) +void dms_viol (uint32 va, uint32 st) { -dms_sr = st | VA_GETPAG (va) | +dms_vr = st | VA_GETPAG (va) | ((st & (MVI_RPR | MVI_WPR))? MVI_MEB: 0) | /* set MEB */ (dms_enb? MVI_MEM: 0) | /* set MEM */ (dms_ump? MVI_UMP: 0); /* set UMAP */ -if (CTL (PRO) && !io) ABORT (ABORT_DMS); +if (CTL (PRO)) { /* protected? */ + mp_mevff = 1; /* signal dms */ + ABORT (ABORT_PRO); } /* abort */ return; } /* DMS update status */ -int32 dms_upd_sr (void) +uint32 dms_upd_sr (void) { dms_sr = dms_sr & ~(MST_ENB | MST_UMP | MST_PRO); if (dms_enb) dms_sr = dms_sr | MST_ENB; @@ -1639,7 +2128,7 @@ int i; switch (inst) { /* case on opcode */ case ioFLG: /* flag */ - ion = (IR & HC)? 0: 1; /* interrupts off/on */ + ion = (IR & I_HC)? 0: 1; /* interrupts off/on */ return dat; case ioSFC: /* skip flag clear */ if (!ion) PC = (PC + 1) & VAMASK; @@ -1651,12 +2140,15 @@ case ioLIX: /* load */ dat = 0; /* returns 0 */ break; case ioCTL: /* control */ - if (IR & AB) { /* = CLC 06..77 */ - for (i = 6; i <= DEVMASK; i++) devdisp (i, inst, AB + i, 0); } + if (IR & I_CTL) { /* =CLC 02,03,06..77 */ + devdisp (DMALT0, inst, I_CTL + DMALT0, 0); + devdisp (DMALT1, inst, I_CTL + DMALT1, 0); + for (i = 6; i <= I_DEVMASK; i++) + devdisp (i, inst, I_CTL + i, 0); } break; default: break; } -if (IR & HC) ion = 0; /* HC option */ +if (IR & I_HC) ion = 0; /* HC option */ return dat; } @@ -1666,7 +2158,7 @@ int32 ovfio (int32 inst, int32 IR, int32 dat) { switch (inst) { /* case on opcode */ case ioFLG: /* flag */ - O = (IR & HC)? 0: 1; /* clear/set overflow */ + O = (IR & I_HC)? 0: 1; /* clear/set overflow */ return dat; case ioSFC: /* skip flag clear */ if (!O) PC = (PC + 1) & VAMASK; @@ -1685,7 +2177,7 @@ case ioOTX: /* output */ break; default: break; } -if (IR & HC) O = 0; /* HC option */ +if (IR & I_HC) O = 0; /* HC option */ return dat; } @@ -1709,28 +2201,36 @@ return dat; int32 proio (int32 inst, int32 IR, int32 dat) { +if ((cpu_unit.flags & UNIT_MPR) == 0) /* not installed? */ + return nulio (inst, IR, dat); /* non-existent dev */ switch (inst) { /* case on opcode */ case ioSFC: /* skip flag clear */ - if (FLG (PRO)) PC = (PC + 1) & VAMASK; + if (FLG (PRO) && !mp_mevff) /* skip if mem prot */ + PC = (PC + 1) & VAMASK; return dat; case ioSFS: /* skip flag set */ + if (FLG (PRO) && mp_mevff) /* skip if DMS */ + PC = (PC + 1) & VAMASK; return dat; case ioMIX: /* merge */ - dat = dat | maddr; + dat = dat | mp_viol; break; case ioLIX: /* load */ - dat = maddr; + dat = mp_viol; break; case ioOTX: /* output */ - mfence = dat & VAMASK; + mp_fence = dat & VAMASK; break; case ioCTL: /* control clear/set */ - if ((IR & AB) == 0) { /* STC */ - setCTL (PRO); - clrFLG (PRO); } + if ((IR & I_CTL) == 0) { /* STC */ + setCTL (PRO); + dms_vr = 0; + mp_evrff = 1; /* allow mp_viol upd */ + mp_mevff = 0; } /* clear DMS flag */ break; default: break; } +if (IR & I_HC) { clrFLG (PRO); } /* HC option */ return dat; } @@ -1753,7 +2253,7 @@ case ioOTX: /* output */ else dmac[ch].cw2 = dat; break; case ioCTL: /* control clear/set */ - if (IR & AB) { clrCTL (DMALT0 + ch); } /* CLC */ + if (IR & I_CTL) { clrCTL (DMALT0 + ch); } /* CLC */ else { setCTL (DMALT0 + ch); } /* STC */ break; default: @@ -1765,13 +2265,14 @@ return dat; int32 dmpio (int32 inst, int32 IR, int32 dat) { -int32 ch, ddev; +int32 ch; ch = IR & 1; /* get channel number */ -ddev = dmac[ch].cw1 & DEVMASK; /* get target device */ switch (inst) { /* case on opcode */ case ioFLG: /* flag */ - if ((IR & HC) == 0) { clrCMD (DMA0 + ch); } /* set -> abort */ + if ((IR & I_HC) == 0) { /* set->abort */ + setFLG (DMA0 + ch); /* set flag */ + clrCMD (DMA0 + ch); } /* clr cmd */ break; case ioSFC: /* skip flag clear */ if (FLG (DMA0 + ch) == 0) PC = (PC + 1) & VAMASK; @@ -1786,35 +2287,42 @@ case ioOTX: /* output */ dmac[ch].cw1 = dat; break; case ioCTL: /* control */ - if (IR & AB) { clrCTL (DMA0 + ch); } /* CLC: cmd unchgd */ - else { setCTL (DMA0 + ch); /* STC: set ctl, cmd */ - setCMD (DMA0 + ch); } + if (IR & I_CTL) { clrCTL (DMA0 + ch); } /* CLC: cmd unchgd */ + else { /* STC */ + setCTL (DMA0 + ch); /* set ctl, cmd */ + setCMD (DMA0 + ch); } break; default: break; } -if (IR & HC) { clrFLG (DMA0 + ch); } /* HC option */ +if (IR & I_HC) { clrFLG (DMA0 + ch); } /* HC option */ return dat; } /* DMA cycle routine */ -void dma_cycle (int32 ch, int32 map) +void dma_cycle (uint32 ch, uint32 map) { int32 temp, dev, MA; +int32 inp = dmac[ch].cw2 & DMA2_OI; /* input flag */ -dev = dmac[ch].cw1 & DEVMASK; /* get device */ +dev = dmac[ch].cw1 & I_DEVMASK; /* get device */ MA = dmac[ch].cw2 & VAMASK; /* get mem addr */ -if (dmac[ch].cw2 & DMA2_OI) { /* input? */ - temp = devdisp (dev, ioLIX, HC + dev, 0); /* do LIA dev,C */ - WriteIO (MA, temp & DMASK, map); } /* store data */ -else devdisp (dev, ioOTX, HC + dev, ReadIO (MA, map)); /* do OTA dev,C */ +if (inp) { /* input? */ + temp = devdisp (dev, ioLIX, dev, 0); /* do LIA dev */ + WriteIO (MA, temp, map); } /* store data */ +else { temp = ReadIO (MA, map); /* read data */ + devdisp (dev, ioOTX, dev, temp); } /* do OTA dev */ dmac[ch].cw2 = (dmac[ch].cw2 & DMA2_OI) | ((dmac[ch].cw2 + 1) & VAMASK); dmac[ch].cw3 = (dmac[ch].cw3 + 1) & DMASK; /* incr wcount */ if (dmac[ch].cw3) { /* more to do? */ - if (dmac[ch].cw1 & DMA1_STC) devdisp (dev, ioCTL, dev, 0); } -else { if (dmac[ch].cw1 & DMA1_CLC) devdisp (dev, ioCTL, AB + dev, 0); - else if ((dmac[ch].cw1 & DMA1_STC) && ((dmac[ch].cw2 & DMA2_OI) == 0)) - devdisp (dev, ioCTL, dev, 0); + if (dmac[ch].cw1 & DMA1_STC) /* if STC flag, */ + devdisp (dev, ioCTL, I_HC + dev, 0); /* do STC,C dev */ + else devdisp (dev, ioFLG, I_HC + dev, 0); } /* else CLF dev */ +else { if (!inp) devdisp (dev, ioFLG, I_HC + dev, 0); /* output? clr flag */ + if (dmac[ch].cw1 & DMA1_CLC) /* CLC at end? */ + devdisp (dev, ioCTL, I_CTL + dev, 0); /* yes */ + else if (!inp && (dmac[ch].cw1 & DMA1_STC)) /* STC && output? */ + devdisp (dev, ioCTL, I_HC + dev, 0); /* STC,C */ setFLG (DMA0 + ch); /* set DMA flg */ clrCMD (DMA0 + ch); } /* clr DMA cmd */ return; @@ -1832,7 +2340,7 @@ case ioSFS: /* skip flag set */ return (stop_dev << IOT_V_REASON) | dat; default: break; } -if (IR & HC) { clrFLG (IR & DEVMASK); } /* HC option */ +if (IR & I_HC) { clrFLG (IR & I_DEVMASK); } /* HC option */ return (stop_dev << IOT_V_REASON) | dat; } @@ -1840,8 +2348,6 @@ return (stop_dev << IOT_V_REASON) | dat; t_stat cpu_reset (DEVICE *dptr) { -saved_AR = saved_BR = 0; -XR = YR = 0; E = 0; O = 0; ion = ion_defer = 0; @@ -1853,16 +2359,18 @@ clrCMD (PRO); clrCTL (PRO); clrFLG (PRO); clrFBF (PRO); -mfence = 0; -maddr = 0; -dms_enb = dms_ump = 0; -dms_sr = dms_fence = 0; -dms_vr = dms_sma = 0; +mp_fence = 0; /* init mprot */ +mp_viol = 0; +mp_mevff = 0; +mp_evrff = 1; +dms_enb = dms_ump = 0; /* init DMS */ +dms_sr = 0; +dms_vr = 0; pcq_r = find_reg ("PCQ", NULL, dptr); sim_brk_types = sim_brk_dflt = SWMASK ('E'); if (M == NULL) M = calloc (PASIZE, sizeof (unsigned int16)); if (M == NULL) return SCPE_MEM; -if (pcq_r) pcq_r -> qptr = 0; +if (pcq_r) pcq_r->qptr = 0; else return SCPE_IERR; return SCPE_OK; } @@ -1871,8 +2379,7 @@ t_stat dma0_reset (DEVICE *tptr) { clrCMD (DMA0); clrCTL (DMA0); -clrFLG (DMA0); -clrFBF (DMA0); +setFLG (DMA0); dmac[0].cw1 = dmac[0].cw2 = dmac[0].cw3 = 0; return SCPE_OK; } @@ -1881,8 +2388,7 @@ t_stat dma1_reset (DEVICE *tptr) { clrCMD (DMA1); clrCTL (DMA1); -clrFLG (DMA1); -clrFBF (DMA1); +setFLG (DMA1); dmac[1].cw1 = dmac[1].cw2 = dmac[1].cw3 = 0; return SCPE_OK; } @@ -1894,6 +2400,7 @@ t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) int32 d; if (addr >= MEMSIZE) return SCPE_NXM; +addr = dms_cons (addr, sw); if (addr == 0) d = saved_AR; else if (addr == 1) d = saved_BR; else d = M[addr]; @@ -1906,6 +2413,7 @@ return SCPE_OK; t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) { if (addr >= MEMSIZE) return SCPE_NXM; +addr = dms_cons (addr, sw); if (addr == 0) saved_AR = val & DMASK; else if (addr == 1) saved_BR = val & DMASK; else M[addr] = val & DMASK; @@ -1918,7 +2426,7 @@ int32 mc = 0; t_addr i; if ((val <= 0) || (val > PASIZE) || ((val & 07777) != 0) || - (!(uptr -> flags & UNIT_21MX) && (val > 32768))) + (!(uptr->flags & UNIT_21MX) && (val > 32768))) return SCPE_ARG; for (i = val; i < MEMSIZE; i++) mc = mc | M[i]; if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) @@ -1928,92 +2436,91 @@ for (i = MEMSIZE; i < PASIZE; i++) M[i] = 0; return SCPE_OK; } -/* Set/show device number */ +/* Set device number */ t_stat hp_setdev (UNIT *uptr, int32 num, char *cptr, void *desc) { +DEVICE *dptr = (DEVICE *) desc; +DIB *dibp; int32 i, newdev; -DIB *dibp = (DIB *) desc; t_stat r; if (cptr == NULL) return SCPE_ARG; -if ((dibp == NULL) || (num > 1)) return SCPE_IERR; -newdev = get_uint (cptr, 8, DEVMASK - num, &r); +if ((desc == NULL) || (num > 1)) return SCPE_IERR; +dibp = (DIB *) dptr->ctxt; +if (dibp == NULL) return SCPE_IERR; +newdev = get_uint (cptr, 8, I_DEVMASK - num, &r); if (r != SCPE_OK) return r; if (newdev < VARDEV) return SCPE_ARG; -for (i = 0; i <= num; i++, dibp++) dibp -> devno = newdev + i; +for (i = 0; i <= num; i++, dibp++) dibp->devno = newdev + i; return SCPE_OK; } +/* Show device number */ + t_stat hp_showdev (FILE *st, UNIT *uptr, int32 num, void *desc) { +DEVICE *dptr = (DEVICE *) desc; +DIB *dibp; int32 i; -DIB *dibp = (DIB *) desc; +if ((desc == NULL) || (num > 1)) return SCPE_IERR; +dibp = (DIB *) dptr->ctxt; if (dibp == NULL) return SCPE_IERR; -fprintf (st, "devno=%o", dibp -> devno); -for (i = 1; i <= num; i++) fprintf (st, "/%o", dibp -> devno + i); +fprintf (st, "devno=%o", dibp->devno); +for (i = 1; i <= num; i++) fprintf (st, "/%o", dibp->devno + i); return SCPE_OK; } -/* Enable a device */ +/* Make a pair of devices consistent */ -t_stat set_enb (UNIT *uptr, int32 num, char *cptr, void *desc) +void hp_enbdis_pair (DEVICE *ccp, DEVICE *dcp) { -int32 i; -DEVICE *dptr; -DIB *dibp; - -if (cptr != NULL) return SCPE_ARG; -if ((uptr == NULL) || (desc == NULL)) return SCPE_IERR; -dptr = find_dev_from_unit (uptr); /* find device */ -if (dptr == NULL) return SCPE_IERR; -dibp = (DIB *) desc; -if (dibp -> enb) return SCPE_OK; /* already enb? */ -for (i = 0; i <= num; i++, dibp++) dibp -> enb = 1; -if (dptr -> reset) return dptr -> reset (dptr); -else return SCPE_OK; -} - -/* Disable a device */ - -t_stat set_dis (UNIT *uptr, int32 num, char *cptr, void *desc) -{ -int32 i; -DEVICE *dptr; -DIB *dibp; -UNIT *up; - -if (cptr != NULL) return SCPE_ARG; -if ((uptr == NULL) || (desc == NULL)) return SCPE_IERR; -dptr = find_dev_from_unit (uptr); /* find device */ -if (dptr == NULL) return SCPE_IERR; -dibp = (DIB *) desc; -if (dibp -> enb == 0) return SCPE_OK; /* already dis? */ -for (i = 0; i < dptr -> numunits; i++) { /* check units */ - up = (dptr -> units) + i; - if ((up -> flags & UNIT_ATT) || sim_is_active (up)) - return SCPE_NOFNC; } -for (i = 0; i <= num; i++, dibp++) dibp -> enb = 0; -if (dptr -> reset) return dptr -> reset (dptr); -else return SCPE_OK; +if (ccp->flags & DEV_DIS) dcp->flags = dcp->flags | DEV_DIS; +else dcp->flags = dcp->flags & ~DEV_DIS; +return; } /* Test for device conflict */ t_bool dev_conflict (void) { +DEVICE *dptr, *cdptr; DIB *dibp, *chkp; int32 i, j, dno; -for (i = 0; chkp = dib_tab[i]; i++) { - if (chkp -> enb) { - dno = chkp -> devno; - for (j = 0; dibp = dib_tab[j]; j++) { - if (dibp -> enb && (chkp != dibp) && (dno == dibp -> devno)) { - printf ("Device number conflict, devno = %d\n", dno); - if (sim_log) fprintf (sim_log, - "Device number conflict, devno = %d\n", dno); +for (i = 0; cdptr = sim_devices[i]; i++) { + chkp = (DIB *) cdptr->ctxt; + if (chkp && !(cdptr->flags & DEV_DIS)) { + dno = chkp->devno; + for (j = 0; dptr = sim_devices[j]; j++) { + dibp = (DIB *) dptr->ctxt; + if (dibp && !(dptr->flags & DEV_DIS) && + (chkp != dibp) && (dno == dibp->devno)) { + printf ("%s device number conflict, devno = %d\n", dptr->name, dno); + if (sim_log) fprintf (sim_log, + "%s device number conflict, devno = %d\n", dptr->name, dno); return TRUE; } } } } return FALSE; } + +/* Configuration validation */ + +t_bool cpu_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 opt = (int32) desc; +int32 mod, i; + +mod = MOD_2116; +if (uptr->flags & UNIT_2100) mod = MOD_2100; +else if (uptr->flags & UNIT_21MX) mod = MOD_21MX; +for (i = 0; opt_val[i].optf != 0; i++) { + if ((val == opt_val[i].optf) && (mod & opt_val[i].cpuf)) { + if (mod == MOD_2100) { + if (val == UNIT_FP) uptr->flags = uptr->flags & ~UNIT_IOP; + if (val == UNIT_IOP) uptr->flags = uptr->flags & ~UNIT_FP; } + if (val == UNIT_DMS) uptr->flags = uptr->flags | UNIT_MPR; + return SCPE_OK; } } +return SCPE_NOFNC; +} + diff --git a/HP2100/hp2100_defs.h b/HP2100/hp2100_defs.h index f9c771d4..b820de8c 100644 --- a/HP2100/hp2100_defs.h +++ b/HP2100/hp2100_defs.h @@ -23,6 +23,7 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 24-Oct-02 RMS Added indirect address interrupt 08-Feb-02 RMS Added DMS definitions 01-Feb-02 RMS Added terminal multiplexor support 16-Jan-02 RMS Added additional device support @@ -43,9 +44,9 @@ #define STOP_HALT 3 /* HALT */ #define STOP_IBKPT 4 /* breakpoint */ #define STOP_IND 5 /* indirect loop */ +#define STOP_INDINT 6 /* indirect intr */ -#define ABORT_DMS 1 /* DMS abort */ -#define ABORT_FENCE -1 /* fence abort */ +#define ABORT_PRO 1 /* protection abort */ /* Memory */ @@ -66,25 +67,27 @@ #define AR M[0] /* A = location 0 */ #define BR M[1] /* B = location 1 */ #define ABREG M /* register array */ +#define SEXT(x) ((int32) (((x) & SIGN)? ((x) | ~DMASK): ((x) & DMASK))) /* Memory reference instructions */ -#define IA 0100000 /* indirect address */ -#define MROP 0070000 /* opcode */ -#define AB 0004000 /* A/B select */ -#define CP 0002000 /* current page */ -#define DISP 0001777 /* page displacement */ -#define PAGENO 0076000 /* page number */ +#define I_IA 0100000 /* indirect address */ +#define I_AB 0004000 /* A/B select */ +#define I_CP 0002000 /* current page */ +#define I_DISP 0001777 /* page displacement */ +#define I_PAGENO 0076000 /* page number */ /* Other instructions */ -#define NMROP 0102000 /* non-mrf opcode */ -#define SHFT 0000000 /* shift */ -#define ASKP 0002000 /* alter/skip */ -#define XTND 0100000 /* extend */ -#define IOT 0102000 /* I/O */ -#define HC 0001000 /* hold/clear */ -#define DEVMASK 0000077 /* device mask */ +#define I_NMRMASK 0102000 /* non-mrf opcode */ +#define I_SRG 0000000 /* shift */ +#define I_ASKP 0002000 /* alter/skip */ +#define I_EXTD 0100000 /* extend */ +#define I_IO 0102000 /* I/O */ +#define I_CTL 0004000 /* CTL on/off */ +#define I_HC 0001000 /* hold/clear */ +#define I_DEVMASK 0000077 /* device mask */ +#define I_GETIOOP(x) (((x) >> 6) & 07) /* I/O sub op */ /* DMA channels */ @@ -192,7 +195,8 @@ struct DMA { /* DMA channel */ #define TTY 011 /* console */ #define PTP 012 /* paper tape punch */ #define CLK 013 /* clock */ -#define LPT 014 /* line printer */ +#define LPS 014 /* 12653 line printer */ +#define LPT 015 /* 12845 line printer */ #define MTD 020 /* 12559A data */ #define MTC 021 /* 12559A control */ #define DPD 022 /* 12557A data */ @@ -207,11 +211,22 @@ struct DMA { /* DMA channel */ #define MUXU 041 /* 12920A upper data */ #define MUXC 042 /* 12920A control */ +/* IBL assignments */ + +#define IBL_PTR 0000000 /* PTR */ +#define IBL_DP 0040000 /* DP */ +#define IBL_DQ 0060000 /* DQ */ +#define IBL_MS 0100000 /* MS */ +#define IBL_TBD 0140000 /* tbd */ +#define IBL_V_DEV 6 /* dev in <11:6> */ +#define IBL_FIX 0000001 /* DP fixed */ +#define IBL_LNT 64 /* boot length */ +#define IBL_MASK (IBL_LNT - 1) /* boot length mask */ + /* Dynamic device information table */ struct hp_dib { int32 devno; /* device number */ - int32 enb; /* enabled */ int32 cmd; /* saved command */ int32 ctl; /* saved control */ int32 flg; /* saved flag */ @@ -247,5 +262,4 @@ typedef struct hp_dib DIB; t_stat hp_setdev (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat hp_showdev (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat set_enb (UNIT *uptr, int32 num, char *cptr, void *desc); -t_stat set_dis (UNIT *uptr, int32 num, char *cptr, void *desc); +void hp_enbdis_pair (DEVICE *ccp, DEVICE *dcp); diff --git a/HP2100/hp2100_diag.txt b/HP2100/hp2100_diag.txt new file mode 100644 index 00000000..ac9e03e7 --- /dev/null +++ b/HP2100/hp2100_diag.txt @@ -0,0 +1,148 @@ +CPU status writeup sources + +24315 Memory reference group passed in 21MX CE no + - LOAD diagnostic + - RUN 100 + - HLT 77, PC = 3353 + +24316 Alter/skip group passed in 21MX CE no + - LOAD diagnostic + - RUN 100 + - HLT 77, PC = 633 + +24317 Shift/rotate group passed in 21MX CE no + - LOAD diagnostic + - RUN 100 + - HLT 77, PC = 1726 + +24296 Diagnostic configurator passed in 21MX CE no + - LOAD configurator + - SET CPU 21MX + - ATTACH PTR binary image of + diagnostic to be configured + - D S XXYY, where XX = device number + of PTR, YY = device number of TTY + - RUN 2 + - HLT 77, PC = 77237 (for 32K mem) + +24319 Extended arithmetic group passed in 21MX CE no + - load diagnostic via configurator + - D S 0 + - RUN 100 + - prints diagnostic name + - prints END OF PASS 1 and halts + +13206 IOP for 2100 group passed 13206 manual no + +24320 Floating point passed in 21MX CE no + - load diagnostic via configurator + - D S 0 + - RUN 100 + - prints diagnostic name + - prints PASS 000001 and halts + +12943-1 Extended instruction group, part 1 passed 12943 manual no + - load diagnostic via configurator + - D S 0 + - RUN 100 + - prints diagnostic name + - prints PASS 000001 and halts + +12943-2 Extended instruction group, part 2 passed 12943 manual no + - load diagnostic via configurator + - D S XX, where XX = device number + of TTY + - RUN 100 + - HLT 74, PC = 2406 + - D S 0 + - CONTINUE + - prints diagnostic name + - prints PASS 000001 and halts + +24322 Dual channel port controller passed in 21MX CE no + - load diagnostic via configurator + - SET LPS ENA + - SET LPS DIAG + - D S XX, where XX = device number + of LPS + - RUN 100 + - HALT 74, PC = 1541 + - D S 0 + - CONTINUE + - prints diagnostic name + - prints H324 PRESS PRESET AND RUN + - HLT 24, PC = 2312 + - RESET ALL + - CONTINUE + - prints PASS 000001 and halts + +12892 Memory protect-parity error passed in 21MX CE no + - load diagnostic via configurator + - disable all I/O devices except + PTR, TTY, clock + - D S 1400XX, where XX = device number + of PTR + - RUN 100 + - HLT 74, PC = 2444 + - D S 1000 (test select mode) + - CONTINUE + - prints diagnostic name + - HLT 75, PC = 2026 + - D S 0 + - D A 31777 (tests 10-11 can't be run) + - Rings bell and prints + H314 PRESS HALT,PRESET AND RUN WITHIN 30 SECONDS + - WRU (CTRL+E) to interrupt simulation + - RESET ALL + - CONTINUE + - prints PASS 000001 and halts + +12929 Memory expansion unit (DMS) passed in 21MX CE no + - load diagnostic via configurator + - SET CPU 64K + - SET LPS ENA + - SET LPS DIAG + - D S XX, where XX = device number + of LPS + - RUN 100 + - HLT 74, PC = 2435 + - D S 0 + - CONTINUE + - Prints H115 PRESS HALT-PRESET-RUN IN LESS THAN 10 SECONDS + - WRU (CTRL+E) to interrupt simulation + - RESET ALL + - CONTINUE + - Prints H117 PRESET TEST COMPLETE + - Prints PASS 000001 and halts + - Test 23 won't run at >256K mem + (real 21MX limited to 304K) + +Peripherals + +12531 TTY test passed in 21MX CE no + - set TTY TTIME to 100 + - run with test select = 173 + - remaining tests can't be run +12539 time base generator passed in 21MX CE no + - runs with CLK in diag mode +12597 reader/punch passed in 21MX CE no + - set PTP TIME to 100 + - run with test select a=4017 + - remaining tests can't be run +12984 2767 line printer passed in 21MX CE no + - set LPS PTIME, CTIME to 100 + - run with test select a = 15 + - remaining tests can't be run +12960 7900/7901 disk passed in 21MX CE no +12965 2883/2884 disk passed 12965 manual no +12559 3030 magtape not run no documentation +13181 7970B magtape partial in 21MX CE no + - set MSC CTIME to 180000 + - do not change MSC XTIME + - attach scratch tapes to units 0,1 + - set s = 2000 (suppress CRC/LRC) + - run with test select a = 37737, b = 7767 + - tests 4, 14, 15 are timing dependent + - test 19 uses non-supported read rev +13183 7970E magtape not run in 21MX CE no +12920 multiplexor not run in 21MX CE no diff --git a/HP2100/hp2100_doc.txt b/HP2100/hp2100_doc.txt index 31bd6d98..5f4d75c4 100644 --- a/HP2100/hp2100_doc.txt +++ b/HP2100/hp2100_doc.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik Subj: HP2100 Simulator Usage -Date: 15-Jun-2002 +Date: 15-Nov-2002 COPYRIGHT NOTICE @@ -37,9 +37,13 @@ This memorandum documents the HP 2100 simulator. 1. Simulator Files sim/ sim_defs.h + sim_rev.h + sim_sock.h + sim_tmxr.h scp.c scp_tty.c - sim_rev.c + sim_sock.c + sim_tmxr.c sim/hp2100/ hp2100_defs.h hp2100_cpu.c @@ -47,7 +51,8 @@ sim/hp2100/ hp2100_defs.h hp2100_dp.c hp2100_dq.c hp2100_dr.c - hp2100_lp.c + hp2100_lps.c + hp2100_lpt.c hp2100_mt.c hp2100_ms.c hp2100_mux.c @@ -61,18 +66,25 @@ The HP2100 simulator is configured as follows: device simulates name(s) -CPU 2116, 2100, or 21MX CPU with 32KW memory +CPU 2116 CPU with 32KW memory + 2100 CPU with 32KW memory, FP or IOP instructions + 21MX CPU with 1024KW memory, FP or DMS instructions DMA0, DMA1 dual channel DMA controller PTR,PTP 12597A paper tape reader/punch -TTY 12631C buffered teleprinter -LPT 12653A line printer +TTY 12631C buffered terminal controller +LPS 12653A printer controller with 2767 printer + 12566B microcircuit interface for diagnostics +LPT 12845A printer controller CLK 12539A/B/C time base generator MUXL,MUXU,MUXC 12920A terminal multiplexor -DP 12557A/13210A disk controller with four drives -DQ 12565A disk controller with two drives -DR 12606A/12610A fixed head disk/drum controller -MT 12559C magnetic tape controller with one drives -MS 13181A magnetic tape controller with four drives +DP 12557A disk controller with four 2871 drives + 13210A disk controller with four 7900 drives +DQ 12565A disk controller with two 2883 drives +DR 12606B fixed head disk controller with 2770/2771 disks + 12610B drum controller with 2773/2774/2775 drums +MT 12559C magnetic tape controller with one 3030 drive +MS 13181A magnetic tape controller with four 7970B drives + 13183A magnetic tape controller with four 7970E drives The HP2100 simulator implements several unique stop conditions: @@ -88,46 +100,78 @@ command is not implemented. CPU options include choice of instruction set and memory size. - SET CPU 2116 2116 instructions - SET CPU 2100 2100 instructions - SET CPU 21MX 21MX instructions + SET CPU 2116 2116 CPU + SET CPU 2100 2100 CPU + SET CPU 21MX 21MX CPU + SET CPU EAU EAU instructions (2116 only) + SET CPU NOEAU no EAU instructions (2116 only) + SET CPU FP FP instructions (2100 only) + SET CPU NOFP no FP instructions (2100 only) + SET CPU IOP IOP instructions (2100 only) + SET CPU NOIOP no IOP instructions (2100 only) + SET CPU DMS DMS instructions (21MX only) + SET CPU NODMS no DMS instructions (21MX only) SET CPU 4K set memory size = 4K SET CPU 8K set memory size = 8K SET CPU 16K set memory size = 16K - SET CPU 24K set memory size = 24K SET CPU 32K set memory size = 32K + SET CPU 64K set memory size = 64K (21MX only) + SET CPU 128K set memory size = 128K (21MX only) + SET CPU 256K set memory size = 256K (21MX only) + SET CPU 512K set memory size = 512K (21MX only) + SET CPU 1024K set memory size = 1024K (21MX only) + +On the 2100, EAU is standard, and the FP and IOP options are mutually +exclusive. On the 21MX, EAU and FP are standard. The 2100 and 21MX +include memory protection as standard; the 21MX optionally includes +DMS (dynamic memory system). If memory size is being reduced, and the memory being truncated contains non-zero data, the simulator asks for confirmation. Data in the truncated portion of memory is lost. Initial memory size is 32K. +These switches are recognized when examining or depositing in CPU memory: + + -v if DMS enabled, interpret address as virtual + -s if DMS enabled, force system map + -u if DMS enabled, force user map + -p if DMS enabled, force port A map + -q if DMS enabled, force port B map + CPU registers include the visible state of the processor as well as the control registers for the interrupt system. - name size comments + name models size comments - P 15 program counter - A 16 A register - B 16 B register - X 16 X index register (21MX) - Y 16 Y index register (21MX) - S 16 switch/display register - E 1 extend flag - O 1 overflow flag - ION 1 interrupt enable flag - ION_DEFER 1 interrupt defer flag - IADDR 6 most recent interrupting device - MPCTL 1 memory protection enable (2100, 21MX) - MPFLG 1 memory protection flag (2100, 21MX) - MPFBF 1 memory protection flag buffer (2100, 21MX) - MFENCE 15 memory protection fence (2100, 21MX) - MADDR 16 memory protection error address (2100, 21MX) - STOP_INST 1 stop on undefined instruction - STOP_DEV 1 stop on undefined device - INDMAX 1 indirect address limit - PCQ[0:63] 15 PC of last JMP, JSB, or interrupt; - most recent PC change first - WRU 8 interrupt character + P all 15 program counter + A all 16 A register + B all 16 B register + X 21MX 16 X index register + Y 21MX 16 Y index register + S all 16 switch/display register + F 2100,21MX 15 memory protection fence + E all 1 extend flag + O all 1 overflow flag + ION all 1 interrupt enable flag + ION_DEFER all 1 interrupt defer flag + IADDR all 6 most recent interrupting device + MPCTL 2100,21MX 1 memory protection enable + MPFLG 2100,21MX 1 memory protection flag + MPFBF 2100,21MX 1 memory protection flag buffer + MPVR 2100,21MX 16 memory protection violation reg + MPEVR 2100,21MX 1 memory protection freeze flag + MPMEV 2100,21MX 1 memory protection DMS error flag + DMSENB 21MX 1 DMS enable + DMSCUR 21MX 1 DMS current mode + DMSSR 21MX 16 DMS status register + DMSVR 21MX 16 DMS violation register + DMSMAP[4][32] 21MX 20 DMS maps + STOP_INST all 1 stop on undefined instruction + STOP_DEV all 1 stop on undefined device + INDMAX all 16 indirect address limit + PCQ[0:63] all 15 P of last JMP, JSB, or interrupt; + most recent P change first + WRU all 8 interrupt character 2.2 DMA Controllers @@ -140,9 +184,9 @@ DMA channel has the following visible state: CTL 1 interrupt enabled FLG 1 channel ready FBF 1 channel ready buffer - CW1 1 command word 1 - CW2 1 command word 2 - CW3 1 command word 3 + CW1 16 command word 1 + CW2 16 command word 2 + CW3 16 command word 3 2.3 Variable Device Assignments @@ -165,7 +209,7 @@ The new device number must be in the range 010..077 (octal). For devices with two device numbers, only the lower numbered device number can be changed; the higher is automatically set to the lower + 1. If a device number conflict occurs, the simulator will return an error -message when started. +when started. In addition, most devices can be enabled or disabled. To enable a device, use the SET ENABLED command: @@ -176,8 +220,8 @@ To disable a device, use the SET DISABLED command: sim> SET DP DISABLED -For devices with two device numbers, disabling or enabling one device -in the pair disables or enables the other. +For devices with more than one device number, disabling or enabling any +device in the set disables all the devices. 2.4 Programmed I/O Devices @@ -243,16 +287,19 @@ Error handling is as follows: OS I/O error x report error and stop -2.4.3 12631C Buffered Teleprinter (TTY) +2.4.3 12631C Buffered Terminal (TTY) -The console teleprinter has three units: keyboard (unit 0), printer +The console terminal has three units: keyboard (unit 0), printer (unit 1), and punch (unit 2). The keyboard reads from the console keyboard; the printer writes to the simulator console window. The -punch writes to a disk file. The keyboard has one option, UC; when -set, it automatically converts lower case input to upper case. This -is on by default. +punch writes to a disk file. The keyboard and printer units (TTY0, +TTY1) can be set to one of three modes: UC, 7B, or 8B. In UC mode, +lower case input and output characters are automatically converted to +upper case. In 7B mode, input and output characters are masked to 7 +bits. In 8B mode, characters are not modified. Changing the mode +of either unit changes both. The default mode is UC. -The terminal implements these registers: +The console teleprinter implements these registers: name size comments @@ -277,7 +324,52 @@ Error handling for the punch is as follows: OS I/O error x report error and stop -2.4.4 12653A Line Printer (LPT) +2.4.4 12653A Printer Controller (LPS) with 2767 Printer + 12566B Microcircuit Interface + +The 12653A line printer uses the 12566B microcircuit interface as +its controller. As a line printer, LPS writes data to a disk file. +The POS register specifies the number of the next data item to be +written. Thus, by changing POS, the user can backspace or advance +the printer. + +As a microcircuit interface, LPS provides the DMA test device for +running the dual channel port controller and DMS diagnostics. Printer +mode verus diagnostic mode is controlled by the commands: + + SET LPS PRINTER configure as line printer + SET LPS DIAG configure for diagnostic tests + +The 12653A is disabled by default. + +The 12653A implements these registers: + + name size comments + + BUF 16 output buffer + STA 16 input buffer or status + CMD 1 printer enable + CTL 1 device/interrupt enable + FLG 1 device ready + FBF 1 device ready buffer + POS 32 position in the output file + CTIME 24 time between characters + PTIME 24 time for a print operation + STOP_IOE 1 stop on I/O error + +In printer mode, error handling is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 out of tape or paper + + OS I/O error x report error and stop + +In diagnostic mode, there are no errors; data sent to the output +buffer is looped back to the status register with a fixed delay of 1. + +2.4.5 12845A Printer Controller (LPT) The line printer (LPT) writes data to a disk file. The POS register specifies the number of the next data item to be written. Thus, @@ -292,6 +384,7 @@ The line printer implements these registers: CTL 1 device/interrupt enable FLG 1 device ready FBF 1 device ready buffer + LCNT 7 line count within page POS 32 position in the output file CTIME 24 time between characters PTIME 24 time for a print operation @@ -306,13 +399,14 @@ Error handling is as follows: OS I/O error x report error and stop -2.4.5 12539A/B/C Time Base Generator (CLK) +2.4.6 12539A/B/C Time Base Generator (CLK) The time base generator (CLK) implements these registers: name size comments SEL 3 time base select + CTR 14 repeat counter for < 1Hz operation CTL 1 device/interrupt enable FLG 1 device ready FBF 1 device ready buffer @@ -320,7 +414,11 @@ The time base generator (CLK) implements these registers: TIME[0:7] 31 clock intervals, select = 0..7 DEVNO 6 current device number (read only) -2.4.6 12920A Terminal Multiplexor (MUXL, MUXU, MUXC) +The time base generator autocalibrates; the clock interval is adjusted +up or down so that the clock tracks actual elapsed time. Operation at +the fastest rates (100 usec, 1 msec) is not recommended. + +2.4.7 12920A Terminal Multiplexor (MUXL, MUXU, MUXC) The 12920A is a 16-line terminal multiplexor, with five additional receive-only diagnostic lines. It consists of three devices: @@ -341,10 +439,13 @@ the port to be used: where port is a decimal number between 1 and 65535 that is not being used for other TCP/IP activities. -Each line (each unit of MUXL) supports two options. UC, when set, causes -lower case input characters to be automatically converted to upper case. -DATASET, when set, enables modem control. By default, UC is on, and -DATASET is off. +Each line (each unit of MUXL) can be set to one of three modes: UC, 7B, +or 8B. In UC mode, lower case input and output characters are converted +automatically to upper case. In 7B mode, input and output characters +are masked to 7 bits. In 8B mode, characters are not modified. The +default mode is UC. In addition, each line supports the DATASET option. +DATASET, when set, enables modem control. The default settings are UC +mode and DATASET disabled. The modem controls model a simplified Bell 103A dataset with just four lines: data terminal ready and request to send from the computer to the @@ -404,7 +505,8 @@ The modem control (MUXM) implements these registers: The terminal multiplexor does not support save and restore. All open connections are lost when the simulator shuts down or MUXU is detached. -2.5 12557A/13210A Disk Controller (DP) +2.5 12557A Disk Controller (DPC, DPD) with 2781 Drives + 13210A Disk Controller (DPC, DPD) with 7900 Drives The 12557A/13210A disk controller can be configured as either a 12557A, supporting 2.5MB drives, or a 13210A, supporting 5MB drives, @@ -414,13 +516,25 @@ with the commands: SET DP 13210A 5.0MB drives Drive types cannot be intermixed; the controller is configured for -one type or the other. +one type or the other. The 13210A (for 7900/7901 disks) is selected +by default. The simulated controller has two separate devices, a data channel and a device controller. The data channel includes a 128-word (one sector) buffer for reads and writes. The device controller includes the four disk drives. Disk drives can be set ONLINE or OFFLINE. +The 12557A/13210A supports the BOOT command. BOOT DP loads the IBL +for 7900 class disks into memory and starts it running. BOOT -F DP +boots from the fixed platter (head 2). The switch register (S) is +set automatically to the value expected by the IBL loader: + + <15:14> = 01 + <13:12> = 00 + <11:6> = data channel device code + <5:1> = 00000 + <0> = 1 if booting from the fixed platter + The data channel implements these registers: name size comments @@ -433,6 +547,8 @@ The data channel implements these registers: CTL 1 interrupt enable FLG 1 channel ready FBF 1 channel ready buffer + XFER 1 transfer in progress flag + WVAL 1 write data valid flag The device controller implements these registers: @@ -440,19 +556,20 @@ The device controller implements these registers: OBUF 16 output buffer BUSY 3 busy (unit #, + 1, of active unit) - RARC 8 record address register cylinder - RARH 2 record address register head - RARS 4 record address register sector CNT 5 check record count CMD 1 controller enable CTL 1 interrupt enable FLG 1 controller ready FBF 1 controller ready buffer EOC 1 end of cylinder pending - CTIME 24 command delay time + RARC[0:3] 8 record address register cylinder, drives 0-3 + RARH[0:3] 2 record address register head, drives 0-3 + RARS[0:3] 4 record address register sector, drives 0-3 + STA[0:3] 16 drive status, drives 0-3 + CTIME 24 data transfer command delay time + DTIME 24 data channel command delay time STIME 24 seek delay time, per cylinder XTIME 24 interword transfer time - STA[0:3] 16 drive status, drives 0-3 Error handling is as follows: @@ -464,13 +581,22 @@ Error handling is as follows: OS I/O error report error and stop -2.6 12565A Disk Controller (DP) +2.6 12565A Disk Controller (DQC, DRC) with 2883 Drives The 12565A disk controller has two separate devices, a data channel and a device controller. The data channel includes a 128-word (one sector) buffer for reads and writes. The device controller includes the two disk drives. Disk drives can be set ONLINE or OFFLINE. +The 12565A supports the BOOT command. BOOT DQ loads the IBL for 2883 +class disks into memory and starts it running. The switch register (S) +is set automatically to the value expected by the IBL loader: + + <15:14> = 01 + <13:12> = 10 + <11:6> = data channel device code + <5:0> = 00000 + The data channel implements these registers: name size comments @@ -483,6 +609,8 @@ The data channel implements these registers: CTL 1 interrupt enable FLG 1 channel ready FBF 1 channel ready buffer + XFER 1 transfer in progress flag + WVAL 1 write data valid flag The device controller implements these registers: @@ -490,19 +618,19 @@ The device controller implements these registers: OBUF 16 output buffer BUSY 2 busy (unit #, + 1, of active unit) - RARC 8 record address register cylinder - RARH 5 record address register head - RARS 5 record address register sector - CNT 5 check record count + CNT 9 check record count CMD 1 controller enable CTL 1 interrupt enable FLG 1 controller ready FBF 1 controller ready buffer - EOC 1 end of cylinder pending - CTIME 24 command delay time + RARC[0:1] 8 record address register cylinder, drives 0-1 + RARH[0:1] 5 record address register head, drives 0-1 + RARS[0:1] 5 record address register sector, drives 0-1 + STA[0:1] 16 drive status, drives 0-3 + CTIME 24 data transfer command delay time + DTIME 24 data channel command delay time STIME 24 seek delay time, per cylinder XTIME 24 interword transfer time - STA[0:3] 16 drive status, drives 0-3 Error handling is as follows: @@ -514,22 +642,28 @@ Error handling is as follows: OS I/O error report error and stop -2.7 12606A/12610A Fixed Head Disk/Drum Controller (DR) +2.7 12606B Fixed Head Disk Controller (DRC, DRD) with 2770/2771 Disk + 12610B Drum Controller (DRC, DRD) with 2773/2774/2775 Drum -The 12606A/12610A fixed head disk/drum controller has two separate devices, +The 12606B/12610B fixed head disk/drum controller has two separate devices, a data channel and a device controller. The device controller includes the actual drive. Ten different models are supported: - SET DR 180K 12606A, 180K words - SET DR 360K 12606A, 360K words - SET DR 720K 12606A, 720K words - SET DR 384K 12610A, 384K words - SET DR 512K 12610A, 512K words - SET DR 640K 12610A, 640K words - SET DR 768K 12610A, 768K words - SET DR 896K 12610A, 896K words - SET DR 1024K 12610A, 1024K words - SET DR 1536K 12610A, 1536K words + SET DRC 180K 12606B, 180K words + SET DRC 360K 12606B, 360K words + SET DRC 720K 12606B, 720K words + SET DRC 384K 12610B, 84K words + SET DRC 512K 12610B, 512K words + SET DRC 640K 12610B, 640K words + SET DRC 768K 12610B, 768K words + SET DRC 896K 12610B, 896K words + SET DRC 1024K 12610B, 1024K words + SET DRC 1536K 12610B, 1536K words + +The 12606B/12610B support the BOOT command. The BOOT command loads the +first sector from the disk or drum into locations 0-77 and then jumps to 77. +This is very different from the IBL loader protocol used by the 12565A and +the 12557A/13210A. The data channel implements these registers: @@ -562,19 +696,26 @@ Error handling is as follows: not attached disk not ready -2.8 12559C Magnetic Tape (MT) +12606B/12610B data files are buffered in memory; therefore, end of file +and OS I/O errors cannot occur. + +2.8 12559C Magnetic Tape Controller (MTC, MTD) with 3030 Drive Magnetic tape options include the ability to make the unit write enabled or write locked. - SET MT LOCKED set unit write locked - SET MT WRITEENABLED set unit write enabled + SET MTC LOCKED set unit write locked + SET MTC WRITEENABLED set unit write enabled The 12559C mag tape drive has two separate devices, a data channel and a device controller. The data channel includes a maximum record sized buffer for reads and writes. The device controller includes the tape unit. +The BOOT command is not supported. The 12559C was HP's earliest tape +drive and is not supported by most of its operating systems. It is +disabled by default. + The data channel implements these registers: name size comments @@ -605,25 +746,40 @@ Error handling is as follows: error processed as - not attached tape not ready + not attached tape not ready; if STOP_IOE, stop - end of file (read or space) end of physical tape - (write) ignored + end of file parity error - OS I/O error report error and stop + OS I/O error parity error; if STOP_IOE, stop -2.9 13181A Magnetic Tape (MS) +2.9 13181A Magnetic Tape Controller (MSC, MSD) with 7970B Drives + 18183A Magnetic Tape Controller (MSC, MSD) with 7970E Drives Magnetic tape options include the ability to make the unit write enabled -or write locked. +or write locked, and the ability to select the 13181A (800 bpi) controller +or the 13183A (1600 bpi) controller. - SET MT LOCKED set unit write locked - SET MT WRITEENABLED set unit write enabled + SET MTn LOCKED set unit n write locked + SET MTn WRITEENABLED set unit n write enabled + SET MT 13181A set controller to 13181A + SET MT 13183A set controller to 13183A -The 13181A mag tape drive has two separate devices, a data channel and -a device controller. The data channel includes a maximum record sized -buffer for reads and writes. The device controller includes the tape -units. +The 13181A/13183A mag tape drive has two separate devices, a data channel +and a device controller. The data channel includes a maximum record +sized buffer for reads and writes. The device controller includes the +tape units. + +The 13181A/13183A supports the BOOT command. BOOT MS loads the IBL for +7970B/E magnetic tape drives into memory and starts it running. BOOT -S +MS causes the loader to space forward the number of files specified in +the A register before starting to load data. The switch register (S) is +set automatically to the value expected by the IBL loader: + + <15:14> = 10 + <13:12> = 00 + <11:6> = data channel device code + <5:1> = 00000 + <0> = 1 if space forward before loading The data channel implements these registers: @@ -657,12 +813,11 @@ Error handling is as follows: error processed as - not attached tape not ready + not attached tape not ready; if STOP_IOE, stop - end of file (read or space) end of physical tape - (write) ignored + end of file parity error - OS I/O error report error and stop + OS I/O error parity error; if STOP_IOE, stop 2.10 Symbolic Display and Input diff --git a/HP2100/hp2100_dp.c b/HP2100/hp2100_dp.c index 514dc891..deebad73 100644 --- a/HP2100/hp2100_dp.c +++ b/HP2100/hp2100_dp.c @@ -1,4 +1,4 @@ -/* hp2100_dp.c: HP 2100 12557A/13210A disk pack simulator +/* hp2100_dp.c: HP 2100 12557A/13210A disk simulator Copyright (c) 1993-2002, Robert M. Supnik @@ -23,8 +23,10 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - dp 12557A/13210A disk pack subsystem + dp 12557A 2871 disk subsystem + 13210A 7900 disk subsystem + 10-Nov-02 RMS Added BOOT command, fixed numerous bugs 15-Jan-02 RMS Fixed INIT handling (found by Bill McDermith) 10-Jan-02 RMS Fixed f(x)write call (found by Bill McDermith) 03-Dec-01 RMS Changed DEVNO to use extended SET/SHOW @@ -38,9 +40,9 @@ #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ #define UNIT_WLK (1 << UNIT_V_WLK) -#define UNIT_W_UF 2 /* # flags */ #define FNC u3 /* saved function */ #define CYL u4 /* cylinder */ +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */ #define DP_N_NUMWD 7 #define DP_NUMWD (1 << DP_N_NUMWD) /* words/sector */ @@ -68,8 +70,9 @@ #define FNC_AR 013 /* address */ #define FNC_SEEK1 020 /* fake - seek1 */ #define FNC_SEEK2 021 /* fake - seek2 */ -#define FNC_CHK1 022 /* fake - check1 */ -#define FNC_AR1 023 /* fake - arec1 */ +#define FNC_SEEK3 022 /* fake - seek3 */ +#define FNC_CHK1 023 /* fake - check1 */ +#define FNC_AR1 024 /* fake - arec1 */ #define CW_V_DRV 0 /* drive */ #define CW_M_DRV 03 #define CW_GETDRV(x) (((x) >> CW_V_DRV) & CW_M_DRV) @@ -91,53 +94,66 @@ #define DA_CKMASK3 077 #define DA_CKMASK (dp_ctype? DA_CKMASK3: DA_CKMASK2) -/* Status */ +/* Status in dpc_sta[drv], (u) = unused in 13210, (d) = dynamic */ -#define STA_ATN 0100000 /* attention */ -#define STA_1ST 0040000 /* first seek */ +#define STA_ATN 0100000 /* attention (u) */ +#define STA_1ST 0040000 /* first status */ #define STA_OVR 0020000 /* overrun */ -#define STA_RWU 0010000 /* rw unsafe */ -#define STA_ACU 0004000 /* access unsafe */ -#define STA_HUNT 0002000 /* hunting NI */ -#define STA_SKI 0001000 /* incomplete NI */ +#define STA_RWU 0010000 /* rw unsafe NI (u) */ +#define STA_ACU 0004000 /* access unsafe NI */ +#define STA_HUNT 0002000 /* hunting NI (12557) */ +#define STA_PROT 0002000 /* protected (13210) */ +#define STA_SKI 0001000 /* incomplete NI (u) */ #define STA_SKE 0000400 /* seek error */ /* 0000200 /* unused */ -#define STA_NRDY 0000100 /* not ready */ +#define STA_NRDY 0000100 /* not ready (d) */ #define STA_EOC 0000040 /* end of cylinder */ #define STA_AER 0000020 /* addr error */ #define STA_FLG 0000010 /* flagged */ #define STA_BSY 0000004 /* seeking */ #define STA_DTE 0000002 /* data error */ -#define STA_ERR 0000001 /* any error */ +#define STA_ERR 0000001 /* any error (d) */ #define STA_ALLERR (STA_ATN + STA_1ST + STA_OVR + STA_RWU + STA_ACU + \ - STA_HUNT + STA_SKI + STA_SKE + STA_NRDY + STA_EOC + \ - STA_FLG + STA_DTE) + STA_SKI + STA_SKE + STA_NRDY + STA_EOC + STA_AER + \ + STA_FLG + STA_BSY + STA_DTE) #define STA_MBZ13 (STA_ATN + STA_RWU + STA_SKI) /* zero in 13210 */ -extern int32 PC; +extern uint16 *M; +extern int32 PC, SR; extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; -int32 dp_ctype = 0; /* ctrl type */ -int32 dpc_busy = 0; /* cch busy */ +extern int32 sim_switches; +extern UNIT cpu_unit; + +int32 dp_ctype = 1; /* ctrl type */ +int32 dpc_busy = 0; /* cch unit */ int32 dpc_cnt = 0; /* check count */ int32 dpc_eoc = 0; /* end of cyl */ -int32 dpc_sta[DP_NUMDRV] = { 0 }; /* status regs */ -int32 dpc_stime = 10; /* seek time */ -int32 dpc_ctime = 10; /* command time */ +int32 dpc_stime = 100; /* seek time */ +int32 dpc_ctime = 100; /* command time */ int32 dpc_xtime = 5; /* xfer time */ -int32 dpc_rarc = 0, dpc_rarh = 0, dpc_rars = 0; /* record addr */ +int32 dpc_dtime = 2; /* dch time */ int32 dpd_obuf = 0, dpd_ibuf = 0; /* dch buffers */ int32 dpc_obuf = 0; /* cch buffers */ +int32 dpd_xfer = 0; /* xfer in prog */ +int32 dpd_wval = 0; /* write data valid */ int32 dp_ptr = 0; /* buffer ptr */ +uint8 dpc_rarc[DP_NUMDRV] = { 0 }; /* cylinder */ +uint8 dpc_rarh[DP_NUMDRV] = { 0 }; /* head */ +uint8 dpc_rars[DP_NUMDRV] = { 0 }; /* sector */ +uint16 dpc_sta[DP_NUMDRV] = { 0 }; /* status regs */ uint16 dpxb[DP_NUMWD]; /* sector buffer */ +DEVICE dpd_dev, dpc_dev; int32 dpdio (int32 inst, int32 IR, int32 dat); int32 dpcio (int32 inst, int32 IR, int32 dat); t_stat dpc_svc (UNIT *uptr); +t_stat dpd_svc (UNIT *uptr); t_stat dpc_reset (DEVICE *dptr); t_stat dpc_vlock (UNIT *uptr, int32 val); t_stat dpc_attach (UNIT *uptr, char *cptr); -t_stat dpc_detach (UNIT *uptr); -void dp_go (int32 fnc, int32 drv, int32 time, int32 attdev); +t_stat dpc_boot (int32 unitno, DEVICE *dptr); +void dp_god (int32 fnc, int32 drv, int32 time); +void dp_goc (int32 fnc, int32 drv, int32 time); t_stat dp_settype (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc); @@ -149,13 +165,13 @@ t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc); */ DIB dp_dib[] = { - { DPD, 1, 0, 0, 0, 0, &dpdio }, - { DPC, 1, 0, 0, 0, 0, &dpcio } }; + { DPD, 0, 0, 0, 0, &dpdio }, + { DPC, 0, 0, 0, 0, &dpcio } }; #define dpd_dib dp_dib[0] #define dpc_dib dp_dib[1] -UNIT dpd_unit = { UDATA (NULL, 0, 0) }; +UNIT dpd_unit = { UDATA (&dpd_svc, 0, 0) }; REG dpd_reg[] = { { ORDATA (IBUF, dpd_ibuf, 16) }, @@ -164,22 +180,24 @@ REG dpd_reg[] = { { FLDATA (CTL, dpd_dib.ctl, 0) }, { FLDATA (FLG, dpd_dib.flg, 0) }, { FLDATA (FBF, dpd_dib.fbf, 0) }, + { FLDATA (XFER, dpd_xfer, 0) }, + { FLDATA (WVAL, dpd_wval, 0) }, { BRDATA (DBUF, dpxb, 8, 16, DP_NUMWD) }, { DRDATA (BPTR, dp_ptr, DP_N_NUMWD) }, { ORDATA (DEVNO, dpd_dib.devno, 6), REG_HRO }, - { FLDATA (*DEVENB, dpd_dib.enb, 0), REG_HRO }, { NULL } }; MTAB dpd_mod[] = { { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &dpd_dib }, + &hp_setdev, &hp_showdev, &dpd_dev }, { 0 } }; DEVICE dpd_dev = { "DPD", &dpd_unit, dpd_reg, dpd_mod, 1, 10, DP_N_NUMWD, 1, 8, 16, NULL, NULL, &dpc_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &dpd_dib, 0 }; /* DPC data structures @@ -190,58 +208,61 @@ DEVICE dpd_dev = { */ UNIT dpc_unit[] = { - { UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE2) }, - { UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE2) }, - { UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE2) }, - { UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DP_SIZE2) } }; + { UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, DP_SIZE3) }, + { UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, DP_SIZE3) }, + { UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, DP_SIZE3) }, + { UDATA (&dpc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, DP_SIZE3) } }; REG dpc_reg[] = { { ORDATA (OBUF, dpc_obuf, 16) }, { ORDATA (BUSY, dpc_busy, 3), REG_RO }, - { ORDATA (RARC, dpc_rarc, 8) }, - { ORDATA (RARH, dpc_rarh, 2) }, - { ORDATA (RARS, dpc_rars, 4) }, { ORDATA (CNT, dpc_cnt, 5) }, { FLDATA (CMD, dpc_dib.cmd, 0) }, { FLDATA (CTL, dpc_dib.ctl, 0) }, { FLDATA (FLG, dpc_dib.flg, 0) }, { FLDATA (FBF, dpc_dib.fbf, 0) }, { FLDATA (EOC, dpc_eoc, 0) }, + { BRDATA (RARC, dpc_rarc, 8, 8, DP_NUMDRV) }, + { BRDATA (RARH, dpc_rarh, 8, 2, DP_NUMDRV) }, + { BRDATA (RARS, dpc_rars, 8, 4, DP_NUMDRV) }, + { BRDATA (STA, dpc_sta, 8, 16, DP_NUMDRV) }, { DRDATA (CTIME, dpc_ctime, 24), PV_LEFT }, + { DRDATA (DTIME, dpc_dtime, 24), PV_LEFT }, { DRDATA (STIME, dpc_stime, 24), PV_LEFT }, { DRDATA (XTIME, dpc_xtime, 24), REG_NZ + PV_LEFT }, - { BRDATA (STA, dpc_sta, 8, 16, DP_NUMDRV) }, { FLDATA (CTYPE, dp_ctype, 0), REG_HRO }, + { URDATA (UCYL, dpc_unit[0].CYL, 10, 8, 0, + DP_NUMDRV, PV_LEFT | REG_HRO) }, + { URDATA (UFNC, dpc_unit[0].FNC, 8, 8, 0, + DP_NUMDRV, REG_HRO) }, { URDATA (CAPAC, dpc_unit[0].capac, 10, 31, 0, DP_NUMDRV, PV_LEFT | REG_HRO) }, - { URDATA (UFLG, dpc_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, - DP_NUMDRV, REG_HRO) }, { ORDATA (DEVNO, dpc_dib.devno, 6), REG_HRO }, - { FLDATA (*DEVENB, dpc_dib.enb, 0), REG_HRO }, { NULL } }; MTAB dpc_mod[] = { -/* { UNIT_WLK, 0, "write enabled", "ENABLED", &dpc_vlock }, */ -/* { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &dpc_vlock }, */ + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, + { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, { MTAB_XTD | MTAB_VDV, 1, NULL, "13210A", &dp_settype, NULL, NULL }, { MTAB_XTD | MTAB_VDV, 0, NULL, "12557A", &dp_settype, NULL, NULL }, { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, NULL, &dp_showtype, NULL }, - { MTAB_XTD | MTAB_VDV, 1, NULL, "ENABLED", - &set_enb, NULL, &dpd_dib }, - { MTAB_XTD | MTAB_VDV, 1, NULL, "DISABLED", - &set_dis, NULL, &dpd_dib }, { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &dpd_dib }, + &hp_setdev, &hp_showdev, &dpd_dev }, { 0 } }; DEVICE dpc_dev = { "DPC", dpc_unit, dpc_reg, dpc_mod, DP_NUMDRV, 8, 24, 1, 8, 16, NULL, NULL, &dpc_reset, - NULL, &dpc_attach, &dpc_detach }; + &dpc_boot, &dpc_attach, NULL, + &dpc_dib, DEV_DISABLE }; /* IOT routines */ @@ -249,10 +270,10 @@ int32 dpdio (int32 inst, int32 IR, int32 dat) { int32 devd; -devd = IR & DEVMASK; /* get device no */ +devd = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & HC) == 0) { setFLG (devd); } /* STF */ + if ((IR & I_HC) == 0) { setFLG (devd); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (devd) == 0) PC = (PC + 1) & VAMASK; @@ -262,6 +283,7 @@ case ioSFS: /* skip flag set */ return dat; case ioOTX: /* output */ dpd_obuf = dat; + if (!dpc_busy || dpd_xfer) dpd_wval = 1; /* if !overrun, valid */ break; case ioMIX: /* merge */ dat = dat | dpd_ibuf; @@ -270,15 +292,19 @@ case ioLIX: /* load */ dat = dpd_ibuf; break; case ioCTL: /* control clear/set */ - if (IR & AB) { /* CLC */ - clrCTL (devd); /* clr ctl, cmd */ - clrCMD (devd); } - else { setCTL (devd); /* STC */ - setCMD (devd); } /* set ctl, cmd */ + if (IR & I_CTL) { /* CLC */ + clrCTL (devd); /* clr ctl, cmd */ + clrCMD (devd); + dpd_xfer = 0; } /* clr xfer */ + else { /* STC */ + if (!dp_ctype) setCTL (devd); /* 12557: set ctl */ + setCMD (devd); /* set cmd */ + if (dpc_busy && !dpd_xfer) /* overrun? */ + dpc_sta[dpc_busy - 1] |= STA_OVR; } break; default: break; } -if (IR & HC) { clrFLG (devd); } /* H/C option */ +if (IR & I_HC) { clrFLG (devd); } /* H/C option */ return dat; } @@ -286,10 +312,10 @@ int32 dpcio (int32 inst, int32 IR, int32 dat) { int32 i, devc, fnc, drv; -devc = IR & DEVMASK; /* get device no */ +devc = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & HC) == 0) { setFLG (devc); } /* STF */ + if ((IR & I_HC) == 0) { setFLG (devc); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (devc) == 0) PC = (PC + 1) & VAMASK; @@ -304,59 +330,187 @@ case ioLIX: /* load */ dat = 0; case ioMIX: /* merge */ for (i = 0; i < DP_NUMDRV; i++) - if (dpc_sta[i] & STA_ATN) dat = dat | (1 << i); + if (dpc_sta[i] & STA_ATN) dat = dat | (1 << i); break; case ioCTL: /* control clear/set */ - if (IR & AB) { /* CLC? */ - clrCMD (devc); /* clr cmd, ctl */ - clrCTL (devc); /* cancel non-seek */ - if (dpc_busy) sim_cancel (&dpc_unit[dpc_busy - 1]); - dpc_busy = 0; } /* clr busy */ - else if (!CTL (devc)) { /* set and now clr? */ - setCMD (devc); /* set cmd, ctl */ - setCTL (devc); - drv = CW_GETDRV (dpc_obuf); /* get fnc, drv */ - fnc = CW_GETFNC (dpc_obuf); /* from cmd word */ - switch (fnc) { /* case on fnc */ - case FNC_SEEK: /* seek */ - dpc_sta[drv] = (dpc_sta[drv] | STA_BSY) & - ~(STA_SKE | STA_SKI | STA_HUNT | STA_1ST); - dp_go (fnc, drv, dpc_xtime, devc); - break; - case FNC_STA: case FNC_AR: /* rd sta, addr rec */ - dp_go (fnc, drv, dpc_xtime, 0); - break; - case FNC_CHK: /* check */ - dp_go (fnc, drv, dpc_xtime, devc); - break; - case FNC_REF: case FNC_RD: case FNC_WD: /* ref, read, write */ - case FNC_INIT: /* init */ - dp_go (fnc, drv, dpc_ctime, devc); - break; - } /* end case */ + if (IR & I_CTL) { /* CLC? */ + clrCTL (devc); /* clr cmd, ctl */ + clrCMD (devc); /* cancel non-seek */ + if (dpc_busy) sim_cancel (&dpc_unit[dpc_busy - 1]); + sim_cancel (&dpd_unit); /* cancel dch */ + dpd_xfer = 0; /* clr dch xfer */ + dpc_busy = 0; } /* clr cch busy */ + else if (!CTL (devc)) { /* set and was clr? */ + setCTL (devc); /* set ctl */ + setCMD (devc); /* set cmd */ + drv = CW_GETDRV (dpc_obuf); /* get fnc, drv */ + fnc = CW_GETFNC (dpc_obuf); /* from cmd word */ + switch (fnc) { /* case on fnc */ + case FNC_SEEK: case FNC_CHK: /* seek, check */ + case FNC_STA: case FNC_AR: /* rd sta, addr rec */ + dp_god (fnc, drv, dpc_dtime); /* sched dch xfr */ + break; + case FNC_RD: case FNC_WD: /* read, write */ + case FNC_REF: case FNC_INIT: /* refine, init */ + dp_goc (fnc, drv, dpc_ctime); /* sched drive */ + break; + } /* end case */ } /* end else */ break; default: break; } -if (IR & HC) { clrFLG (devc); } /* H/C option */ +if (IR & I_HC) { clrFLG (devc); } /* H/C option */ return dat; } -/* Unit service +/* Start data channel operation */ - Unit must be attached; detach cancels operation. +void dp_god (int32 fnc, int32 drv, int32 time) +{ +dpd_unit.CYL = drv; /* save unit */ +dpd_unit.FNC = fnc; /* save function */ +sim_activate (&dpd_unit, time); +return; +} + +/* Start controller operation */ + +void dp_goc (int32 fnc, int32 drv, int32 time) +{ +if (sim_is_active (&dpc_unit[drv])) { /* still seeking? */ + sim_cancel (&dpc_unit[drv]); /* stop seek */ + dpc_sta[drv] = dpc_sta[drv] & ~STA_BSY; /* clear busy */ + time = time + dpc_stime; } /* take longer */ +dp_ptr = 0; /* init buf ptr */ +dpc_eoc = 0; /* clear end cyl */ +dpc_busy = drv + 1; /* set busy */ +dpd_xfer = 1; /* xfer in prog */ +dpc_unit[drv].FNC = fnc; /* save function */ +sim_activate (&dpc_unit[drv], time); /* activate unit */ +return; +} + +/* Data channel unit service + + This routine handles the data channel transfers. It also handles + data transfers that are blocked by seek in progress. + + uptr->CYL = target drive + uptr->FNC = target function Seek substates seek - transfer cylinder seek1 - transfer head/surface - seek2 - done Address record ar - transfer cylinder ar1 - transfer head/surface, finish operation Status check - transfer status, finish operation - Refine sector - erase sector, finish operation Check data chk - transfer sector count +*/ + +t_stat dpd_svc (UNIT *uptr) +{ +int32 drv, devc, devd, st; + +drv = uptr->CYL; /* get drive no */ +devc = dpc_dib.devno; /* get cch devno */ +devd = dpd_dib.devno; /* get dch devno */ +switch (uptr->FNC) { /* case function */ + +case FNC_SEEK: /* seek, need cyl */ + if (CMD (devd)) { /* dch active? */ + dpc_rarc[drv] = DA_GETCYL (dpd_obuf); /* take cyl word */ + dpd_wval = 0; /* clr data valid */ + setFLG (devd); /* set dch flg */ + clrCMD (devd); /* clr dch cmd */ + uptr->FNC = FNC_SEEK1; } /* advance state */ + sim_activate (uptr, dpc_xtime); /* no, wait more */ + break; +case FNC_SEEK1: /* seek, need hd/sec */ + if (CMD (devd)) { /* dch active? */ + dpc_rarh[drv] = DA_GETHD (dpd_obuf); /* get head */ + dpc_rars[drv] = DA_GETSC (dpd_obuf); /* get sector */ + dpd_wval = 0; /* clr data valid */ + setFLG (devd); /* set dch flg */ + clrCMD (devd); /* clr dch cmd */ + if (sim_is_active (&dpc_unit[drv])) { /* if busy, */ + dpc_sta[drv] = dpc_sta[drv] | STA_SKE; + break; } /* error, ignore */ + st = abs (dpc_rarc[drv] - dpc_unit[drv].CYL) * dpc_stime; + if (st == 0) st = dpc_stime; /* min time */ + sim_activate (&dpc_unit[drv], st); /* schedule drive */ + dpc_sta[drv] = (dpc_sta[drv] | STA_BSY) & + ~(STA_SKE | STA_SKI | STA_HUNT); + dpc_unit[drv].CYL = dpc_rarc[drv]; /* on cylinder */ + dpc_unit[drv].FNC = FNC_SEEK2; } /* set operation */ + else sim_activate (uptr, dpc_xtime); /* no, wait more */ + break; + +case FNC_AR: /* arec, need cyl */ + if (CMD (devd)) { /* dch active? */ + dpc_rarc[drv] = DA_GETCYL (dpd_obuf); /* take cyl word */ + dpd_wval = 0; /* clr data valid */ + setFLG (devd); /* set dch flg */ + clrCMD (devd); /* clr dch cmd */ + uptr->FNC = FNC_AR1; } /* advance state */ + sim_activate (uptr, dpc_xtime); /* no, wait more */ + break; +case FNC_AR1: /* arec, need hd/sec */ + if (CMD (devd)) { /* dch active? */ + dpc_rarh[drv] = DA_GETHD (dpd_obuf); /* get head */ + dpc_rars[drv] = DA_GETSC (dpd_obuf); /* get sector */ + dpd_wval = 0; /* clr data valid */ + setFLG (devc); /* set cch flg */ + clrCMD (devc); /* clr cch cmd */ + setFLG (devd); /* set dch flg */ + clrCMD (devd); } /* clr dch cmd */ + else sim_activate (uptr, dpc_xtime); /* no, wait more */ + break; + +case FNC_STA: /* read status */ + if (CMD (devd)) { /* dch active? */ + if (dpc_unit[drv].flags & UNIT_ATT) { /* attached? */ + dpd_ibuf = dpc_sta[drv] & ~STA_ERR; /* clear err */ + if (dp_ctype) dpd_ibuf = /* 13210? */ + (dpd_ibuf & ~(STA_MBZ13 | STA_PROT)) | + (uptr->flags & UNIT_WPRT? STA_PROT: 0); } + else dpd_ibuf = STA_NRDY; /* not ready */ + if (dpd_ibuf & STA_ALLERR) /* errors? set flg */ + dpd_ibuf = dpd_ibuf | STA_ERR; + setFLG (devd); /* set dch flg */ + clrCMD (devd); /* clr dch cmd */ + dpc_sta[drv] = dpc_sta[drv] & /* clr sta flags */ + ~(STA_ATN | STA_1ST | STA_OVR | + STA_RWU | STA_ACU | STA_EOC | + STA_AER | STA_FLG | STA_DTE); } + else sim_activate (uptr, dpc_xtime); /* wait more */ + break; + +case FNC_CHK: /* check, need cnt */ + if (CMD (devd)) { /* dch active? */ + dpc_cnt = dpd_obuf & DA_CKMASK; /* get count */ + dpd_wval = 0; /* clr data valid */ +/* setFLG (devd); /* set dch flg */ +/* clrCMD (devd); /* clr dch cmd */ + dp_goc (FNC_CHK1, drv, dpc_xtime); } /* sched drv */ + else sim_activate (uptr, dpc_xtime); /* wait more */ + break; + +default: + return SCPE_IERR; } + +return SCPE_OK; +} + +/* Drive unit service + + This routine handles the data transfers. + + Seek substates + seek2 - done + Refine sector - erase sector, finish operation + Check data chk1 - finish operation Read Write @@ -367,221 +521,144 @@ return dat; t_stat dpc_svc (UNIT *uptr) { -int32 i, da, drv, devc, devd, err, st, maxsc; +int32 da, drv, devc, devd, err; err = 0; /* assume no err */ drv = uptr - dpc_dev.units; /* get drive no */ devc = dpc_dib.devno; /* get cch devno */ devd = dpd_dib.devno; /* get dch devno */ -switch (uptr -> FNC) { /* case function */ +if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ + setFLG (devc); /* set cch flg */ + clrCMD (devc); /* clr cch cmd */ + dpc_sta[drv] = 0; /* clr status */ + dpc_busy = 0; /* ctlr is free */ + dpd_xfer = dpd_wval = 0; + return SCPE_OK; } +switch (uptr->FNC) { /* case function */ -case FNC_SEEK: /* seek, need cyl */ - if (CMD (devd)) { /* dch active? */ - dpc_rarc = DA_GETCYL (dpd_obuf); /* take cyl word */ - setFLG (devd); /* set dch flg */ - clrCMD (devd); /* clr dch cmd */ - uptr -> FNC = FNC_SEEK1; } /* advance state */ - sim_activate (uptr, dpc_xtime); /* no, wait more */ - return SCPE_OK; -case FNC_SEEK1: /* seek, need hd/sec */ - if (CMD (devd)) { /* dch active? */ - dpc_rarh = DA_GETHD (dpd_obuf); /* get head */ - dpc_rars = DA_GETSC (dpd_obuf); /* get sector */ - setFLG (devd); /* set dch flg */ - clrCMD (devd); /* clr dch cmd */ - st = abs (dpc_rarc - uptr -> CYL) * dpc_stime; /* calc diff */ - if (st == 0) st = dpc_xtime; /* min time */ - sim_activate (uptr, st); /* schedule op */ - uptr -> CYL = dpc_rarc; /* on cylinder */ - dpc_busy = 0; /* ctrl is free */ - uptr -> FNC = FNC_SEEK2; } /* advance state */ - else sim_activate (uptr, dpc_xtime); /* no, wait more */ - return SCPE_OK; case FNC_SEEK2: /* seek done */ - if (dpc_busy) sim_activate (uptr, dpc_xtime); /* ctrl busy? wait */ - else { dpc_sta[drv] = (dpc_sta[drv] | STA_ATN) & ~STA_BSY; - if (uptr -> CYL >= DP_NUMCY) { /* invalid cyl? */ - dpc_sta[drv] = dpc_sta[drv] | STA_SKE; - uptr -> CYL = 0; } - if (dpc_rars >= DP_NUMSC) /* invalid sec? */ - dpc_sta[drv] = dpc_sta[drv] | STA_SKE; - setFLG (devc); /* set cch flg */ - clrCMD (devc); } /* clr cch cmd */ - return SCPE_OK; - -case FNC_AR: /* arec, need cyl */ - if (CMD (devd)) { /* dch active? */ - dpc_rarc = DA_GETCYL (dpd_obuf); /* take cyl word */ - setFLG (devd); /* set dch flg */ - clrCMD (devd); /* clr dch cmd */ - uptr -> FNC = FNC_AR1; } /* advance state */ - sim_activate (uptr, dpc_xtime); /* no, wait more */ - return SCPE_OK; -case FNC_AR1: /* arec, need hd/sec */ - if (CMD (devd)) { /* dch active? */ - dpc_rarh = DA_GETHD (dpd_obuf); /* get head */ - dpc_rars = DA_GETSC (dpd_obuf); /* get sector */ - setFLG (devd); /* set dch flg */ - clrCMD (devd); } /* clr dch cmd */ - else { sim_activate (uptr, dpc_xtime); /* no, wait more */ - return SCPE_OK; } - break; /* done */ - -case FNC_STA: /* read status */ - if (CMD (devd)) { /* dch active? */ - dpd_ibuf = dpc_sta[drv] & ~(dp_ctype? STA_MBZ13: 0); - if (dpc_sta[drv] & STA_ALLERR) dpd_ibuf = dpd_ibuf | STA_ERR; - setFLG (devd); /* set dch flg */ - clrCMD (devd); /* clr dch cmd */ - dpc_sta[drv] = dpc_sta[drv] & /* clr sta flags */ - ~(STA_ATN | STA_DTE | STA_FLG | STA_AER | STA_EOC); - dpc_busy = 0; } /* ctlr is free */ - else sim_activate (uptr, dpc_xtime); /* wait more */ + dpc_sta[drv] = (dpc_sta[drv] | STA_ATN) & ~STA_BSY; + if (uptr->CYL >= DP_NUMCY) { /* invalid cyl? */ + dpc_sta[drv] = dpc_sta[drv] | STA_SKE; + uptr->CYL = DP_NUMCY - 1; } +case FNC_SEEK3: /* waiting for flag */ + if (dpc_busy || FLG (devc)) { /* ctrl busy? wait */ + uptr->FNC = FNC_SEEK3; /* next state */ + sim_activate (uptr, dpc_xtime); } + else setFLG (devc); /* set cch flg */ return SCPE_OK; case FNC_REF: /* refine sector */ - if ((uptr -> CYL != dpc_rarc) || (dpc_rars >= DP_NUMSC)) - dpc_sta[drv] = dpc_sta[drv] | STA_AER; - else { for (i = 0; i < DP_NUMWD; i++) dpxb[i] = 0; - da = GETDA (dpc_rarc, dpc_rarh, dpc_rars); /* get addr */ - dpc_rars = dpc_rars + 1; /* incr sector */ - if (dpc_rars >= DP_NUMSC) { /* end of trk? */ - dpc_rars = 0; /* wrap to */ - dpc_rarh = dpc_rarh ^ 1; } /* next surf */ - if (err = fseek (uptr -> fileref, da * sizeof (int16), - SEEK_SET)) break; - fxwrite (dpxb, sizeof (int16), DP_NUMWD, uptr -> fileref); - err = ferror (uptr -> fileref); } - break; - -case FNC_CHK: /* check, need cnt */ - if (CMD (devd)) { /* dch active? */ - dpc_cnt = dpd_obuf & DA_CKMASK; /* get count */ - setFLG (devd); /* set dch flg */ - clrCMD (devd); /* clr dch cmd */ - sim_activate (uptr, dpc_ctime); /* schedule op */ - uptr -> FNC = FNC_CHK1; } /* advance state */ - else sim_activate (uptr, dpc_xtime); /* wait more */ - return SCPE_OK; -case FNC_CHK1: - if ((uptr -> CYL != dpc_rarc) || (dpc_rars >= DP_NUMSC)) - dpc_sta[drv] = dpc_sta[drv] | STA_AER; - else { maxsc = ((2 - (dpc_rarh & 1)) * DP_NUMSC) - dpc_rars; - if (dpc_cnt > maxsc) { /* too many sec? */ - dpc_sta[drv] = dpc_sta[drv] | STA_EOC; - dpc_rarh = dpc_rarh & ~1; /* rar = 0/2, 0 */ - dpc_rars = 0; } - else { i = dpc_rars + dpc_cnt; /* final sector */ - dpc_rars = i % DP_NUMSC; /* reposition */ - dpc_rarh = dpc_rarh ^ ((i / DP_NUMSC) & 1); } } - break; /* done */ + break; /* just a NOP */ case FNC_RD: /* read */ - if (!CMD (devd)) break; /* dch clr? done */ - if (FLG (devd)) dpc_sta[drv] = dpc_sta[drv] | STA_OVR; +case FNC_CHK1: /* check */ if (dp_ptr == 0) { /* new sector? */ - if ((uptr -> CYL != dpc_rarc) || (dpc_rars >= DP_NUMSC)) { - dpc_sta[drv] = dpc_sta[drv] | STA_AER; - break; } - if (dpc_eoc) { /* end of cyl? */ - dpc_sta[drv] = dpc_sta[drv] | STA_EOC; - break; } - da = GETDA (dpc_rarc, dpc_rarh, dpc_rars); /* get addr */ - dpc_rars = dpc_rars + 1; /* incr address */ - if (dpc_rars >= DP_NUMSC) { /* end of trk? */ - dpc_rars = 0; /* wrap to */ - dpc_rarh = dpc_rarh ^ 1; /* next cyl */ - dpc_eoc = ((dpc_rarh & 1) == 0); } /* calc eoc */ - if (err = fseek (uptr -> fileref, da * sizeof (int16), - SEEK_SET)) break; - fxread (dpxb, sizeof (int16), DP_NUMWD, uptr -> fileref); - if (err = ferror (uptr -> fileref)) break; } + if (!CMD (devd) && (uptr->FNC != FNC_CHK1)) break; + if (uptr->CYL != dpc_rarc[drv]) /* wrong cyl? */ + dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* set flag, read */ + if (dpc_rars[drv] >= DP_NUMSC) { /* bad sector? */ + dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* set flag, stop */ + break; } + if (dpc_eoc) { /* end of cyl? */ + dpc_sta[drv] = dpc_sta[drv] | STA_EOC; + break; } + da = GETDA (dpc_rarc[drv], dpc_rarh[drv], dpc_rars[drv]); + dpc_rars[drv] = dpc_rars[drv] + 1; /* incr address */ + if (dpc_rars[drv] >= DP_NUMSC) { /* end of surf? */ + dpc_rars[drv] = 0; /* wrap to */ + dpc_rarh[drv] = dpc_rarh[drv] ^ 1; /* next head */ + dpc_eoc = ((dpc_rarh[drv] & 1) == 0); }/* calc eoc */ + if (err = fseek (uptr->fileref, da * sizeof (int16), + SEEK_SET)) break; + fxread (dpxb, sizeof (int16), DP_NUMWD, uptr->fileref); + if (err = ferror (uptr->fileref)) break; } dpd_ibuf = dpxb[dp_ptr++]; /* get word */ - if (dp_ptr >= DP_NUMWD) dp_ptr = 0; /* wrap if last */ - setFLG (devd); /* set dch flg */ + if (dp_ptr >= DP_NUMWD) { /* end of sector? */ + if (uptr->FNC == FNC_CHK1) { /* check? */ + dpc_cnt = (dpc_cnt - 1) & DA_CKMASK; /* decr count */ + if (dpc_cnt == 0) break; } /* stop at zero */ + dp_ptr = 0; } /* wrap buf ptr */ + if (CMD (devd) && dpd_xfer) { /* dch on, xfer? */ + setFLG (devd); } /* set flag */ clrCMD (devd); /* clr dch cmd */ sim_activate (uptr, dpc_xtime); /* sched next word */ return SCPE_OK; case FNC_INIT: /* init */ case FNC_WD: /* write */ - if (dpc_eoc) { /* end of cyl? */ - dpc_sta[drv] = dpc_sta[drv] | STA_EOC; /* set status */ + if (dp_ptr == 0) { /* start sector? */ + if (!CMD (devd) && !dpd_wval) break; /* xfer done? */ + if (uptr->flags & UNIT_WPRT) { /* wr prot? */ + dpc_sta[drv] = dpc_sta[drv] | STA_FLG; /* set status */ break; } /* done */ - if (FLG (devd)) dpc_sta[drv] = dpc_sta[drv] | STA_OVR; - dpxb[dp_ptr++] = dpd_obuf; /* store word */ - if (!CMD (devd)) { /* dch clr? done */ - for ( ; dp_ptr < DP_NUMWD; dp_ptr++) dpxb[dp_ptr] = 0; } + if ((uptr->CYL != dpc_rarc[drv]) || /* wrong cyl or */ + (dpc_rars[drv] >= DP_NUMSC)) { /* bad sector? */ + dpc_sta[drv] = dpc_sta[drv] | STA_AER; /* set flag, stop */ + break; } + if (dpc_eoc) { /* end of cyl? */ + dpc_sta[drv] = dpc_sta[drv] | STA_EOC; /* set status */ + break; } } /* done */ + dpxb[dp_ptr++] = dpd_wval? dpd_obuf: 0; /* store word/fill */ + dpd_wval = 0; /* clr data valid */ if (dp_ptr >= DP_NUMWD) { /* buffer full? */ - if ((uptr -> CYL != dpc_rarc) || (dpc_rars >= DP_NUMSC)) { - dpc_sta[drv] = dpc_sta[drv] | STA_AER; - break; } - da = GETDA (dpc_rarc, dpc_rarh, dpc_rars); /* get addr */ - dpc_rars = dpc_rars + 1; /* incr address */ - if (dpc_rars >= DP_NUMSC) { /* end of trk? */ - dpc_rars = 0; /* wrap to */ - dpc_rarh = dpc_rarh ^ 1; /* next cyl */ - dpc_eoc = ((dpc_rarh & 1) == 0); } /* calc eoc */ - if (err = fseek (uptr -> fileref, da * sizeof (int16), - SEEK_SET)) return TRUE; - fxwrite (dpxb, sizeof (int16), DP_NUMWD, uptr -> fileref); - if (err = ferror (uptr -> fileref)) break; - dp_ptr = 0; } - if (CMD (devd)) { /* dch active? */ - setFLG (devd); /* set dch flg */ - clrCMD (devd); /* clr dch cmd */ - sim_activate (uptr, dpc_xtime); /* sched next word */ - return SCPE_OK; } - break; } /* end case fnc */ + da = GETDA (dpc_rarc[drv], dpc_rarh[drv], dpc_rars[drv]); + dpc_rars[drv] = dpc_rars[drv] + 1; /* incr address */ + if (dpc_rars[drv] >= DP_NUMSC) { /* end of surf? */ + dpc_rars[drv] = 0; /* wrap to */ + dpc_rarh[drv] = dpc_rarh[drv] ^ 1; /* next head */ + dpc_eoc = ((dpc_rarh[drv] & 1) == 0); }/* calc eoc */ + if (err = fseek (uptr->fileref, da * sizeof (int16), + SEEK_SET)) break; + fxwrite (dpxb, sizeof (int16), DP_NUMWD, uptr->fileref); + if (err = ferror (uptr->fileref)) break; /* error? */ + dp_ptr = 0; } /* next sector */ + if (CMD (devd) && dpd_xfer) { /* dch on, xfer? */ + setFLG (devd); } /* set flag */ + clrCMD (devd); /* clr dch cmd */ + sim_activate (uptr, dpc_xtime); /* sched next word */ + return SCPE_OK; -dpc_sta[drv] = dpc_sta[drv] | STA_ATN; /* request attn */ +default: + return SCPE_IERR; } /* end case fnc */ + +if (!dp_ctype) dpc_sta[drv] = dpc_sta[drv] | STA_ATN; /* 12559 sets ATN */ setFLG (devc); /* set cch flg */ clrCMD (devc); /* clr cch cmd */ dpc_busy = 0; /* ctlr is free */ +dpd_xfer = dpd_wval = 0; if (err != 0) { /* error? */ perror ("DP I/O error"); - clearerr (uptr -> fileref); + clearerr (uptr->fileref); return SCPE_IOERR; } return SCPE_OK; } -/* Start disk operation */ - -void dp_go (int32 fnc, int32 drv, int32 time, int32 dev) -{ -if (dev && ((dpc_unit[drv].flags & UNIT_ATT) == 0)) { /* attach check? */ - dpc_sta[drv] = STA_NRDY; /* not attached */ - setFLG (dev); /* set cch flag */ - clrCMD (dev); } /* clr cch cmd */ -else { dpc_busy = drv + 1; /* set busy */ - dp_ptr = 0; /* init buf ptr */ - dpc_eoc = 0; /* clear end cyl */ - dpc_unit[drv].FNC = fnc; /* save function */ - sim_activate (&dpc_unit[drv], time); } /* activate unit */ -return; -} - /* Reset routine */ t_stat dpc_reset (DEVICE *dptr) { int32 i; +hp_enbdis_pair (&dpc_dev, &dpd_dev); /* make pair cons */ dpd_ibuf = dpd_obuf = 0; /* clear buffers */ dpc_busy = dpc_obuf = 0; dpc_eoc = 0; +dpd_xfer = dpd_wval = 0; dp_ptr = 0; -dpc_rarc = dpc_rarh = dpc_rars = 0; /* clear rar */ dpc_dib.cmd = dpd_dib.cmd = 0; /* clear cmd */ dpc_dib.ctl = dpd_dib.ctl = 0; /* clear ctl */ dpc_dib.fbf = dpd_dib.fbf = 1; /* set fbf */ dpc_dib.flg = dpd_dib.flg = 1; /* set flg */ +sim_cancel (&dpd_unit); /* cancel dch */ for (i = 0; i < DP_NUMDRV; i++) { /* loop thru drives */ sim_cancel (&dpc_unit[i]); /* cancel activity */ dpc_unit[i].FNC = 0; /* clear function */ dpc_unit[i].CYL = 0; - dpc_sta[i] = (dpc_sta[i] & STA_1ST) | - ((dpc_unit[i].flags & UNIT_ATT)? 0: STA_NRDY); } + dpc_rarc[i] = dpc_rarh[i] = dpc_rars[i] = 0; + if (dpc_unit[i].flags & UNIT_ATT) + dpc_sta[i] = dpc_sta[i] & STA_1ST; + else dpc_sta[i] = 0; } return SCPE_OK; } @@ -595,31 +672,10 @@ t_stat r; drv = uptr - dpc_dev.units; /* get drive no */ r = attach_unit (uptr, cptr); /* attach unit */ if (r != SCPE_OK) return r; -dpc_sta[drv] = (dpc_sta[drv] | STA_1ST) & ~STA_NRDY; /* update status */ +dpc_sta[drv] = dpc_sta[drv] | STA_1ST; /* update status */ return r; } -/* Detach routine */ - -t_stat dpc_detach (UNIT* uptr) -{ -int32 drv; - -drv = uptr - dpc_dev.units; /* get drive no */ -dpc_sta[drv] = (dpc_sta[drv] | STA_NRDY) & ~STA_1ST; /* update status */ -if (drv == (dpc_busy + 1)) dpc_busy = 0; /* update busy */ -sim_cancel (uptr); /* cancel op */ -return detach_unit (uptr); /* detach unit */ -} - -/* Write lock/enable routine */ - -t_stat dpc_vlock (UNIT *uptr, int32 val) -{ -if (uptr -> flags & UNIT_ATT) return SCPE_ARG; -return SCPE_OK; -} - /* Set controller type */ t_stat dp_settype (UNIT *uptr, int32 val, char *cptr, void *desc) @@ -644,4 +700,89 @@ else fprintf (st, "12557A"); return SCPE_OK; } +/* 7900/7901 bootstrap routine (HP 12992F ROM) */ + +#define CHANGE_DEV (1 << 24) +#define CHANGE_ADDR (1 << 23) + +static const int32 dboot[IBL_LNT] = { + 0106700+CHANGE_DEV, /*ST CLC DC ; clr dch */ + 0106701+CHANGE_DEV, /* CLC CC ; clr cch */ + 0017757, /* JSB STAT ; get status */ + 0067746, /*SK LDB SKCMD ; seek cmd */ + 0106600+CHANGE_DEV, /* OTB DC ; cyl # */ + 0103700+CHANGE_DEV, /* STC DC,C ; to dch */ + 0106601+CHANGE_DEV, /* OTB CC ; seek cmd */ + 0103701+CHANGE_DEV, /* STC CC,C ; to cch */ + 0102300+CHANGE_DEV, /* SFS DC ; addr wd ok? */ + 0027710, /* JMP *-1 ; no, wait */ + 0006400, /* CLB */ + 0102501, /* LIA 1 ; read switches */ + 0002011, /* SLA,RSS ; <0> set? */ + 0047747, /* ADB BIT9 ; head 2 = fixed */ + 0106600+CHANGE_DEV, /* OTB DC ; head/sector */ + 0103700+CHANGE_DEV, /* STC DC,C ; to dch */ + 0102301+CHANGE_DEV, /* SFS CC ; seek done? */ + 0027720, /* JMP *-1 ; no, wait */ + 0017757, /* JSB STAT ; get status */ + 0067776, /* LDB DMACW ; DMA control */ + 0106606, /* OTB 6 */ + 0067750, /* LDB ADDR1 ; memory addr */ + 0106602, /* OTB 2 */ + 0102702, /* STC 2 ; flip DMA ctrl */ + 0067752, /* LDB CNT ; word count */ + 0106602, /* OTB 2 */ + 0063745, /* LDB RDCMD ; read cmd */ + 0102601+CHANGE_DEV, /* OTA CC ; to cch */ + 0103700+CHANGE_DEV, /* STC DC,C ; start dch */ + 0103606, /* STC 6,C ; start DMA */ + 0103701+CHANGE_DEV, /* STC CC,C ; start cch */ + 0102301+CHANGE_DEV, /* SFS CC ; done? */ + 0027737, /* JMP *-1 ; no, wait */ + 0017757, /* JSB STAT ; get status */ + 0027775, /* JMP XT ; done */ + 0037766, /*FSMSK 037766 ; status mask */ + 0004000, /*STMSK 004000 ; unsafe mask */ + 0020000, /*RDCMD 020000 ; read cmd */ + 0030000, /*SKCMD 030000 ; seek cmd */ + 0001000, /*BIT9 001000 ; head 2 select */ + 0102011, /*ADDR1 102011 */ + 0102055, /*ADDR2 102055 */ + 0164000, /*CNT -6144. */ + 0, 0, 0, 0, /* unused */ + 0000000, /*STAT 0 */ + 0002400, /* CLA ; status request */ + 0102601+CHANGE_DEV, /* OTC CC ; to cch */ + 0103701+CHANGE_DEV, /* STC CC,C ; start cch */ + 0102300+CHANGE_DEV, /* SFS DC ; done? */ + 0027763, /* JMP *-1 */ + 0102500+CHANGE_DEV, /* LIA DC ; get status */ + 0013743, /* AND FSMSK ; mask 15,14,3,0 */ + 0002003, /* SZA,RSS ; drive ready? */ + 0127757, /* JMP STAT,I ; yes */ + 0013744, /* AND STMSK ; fault? */ + 0002002, /* SZA */ + 0102030, /* HLT 30 ; yes */ + 0027700, /* JMP ST ; no, retry */ + 0117751, /*XT JSB ADDR2,I ; start program */ + 0120000+CHANGE_DEV, /*DMACW 120000+DC */ + CHANGE_ADDR }; /* -ST */ + +t_stat dpc_boot (int32 unitno, DEVICE *dptr) +{ +int32 i, dev; + +if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */ +dev = dpd_dib.devno; /* get data chan dev */ +PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */ +SR = IBL_DP + (dev << IBL_V_DEV); /* set SR */ +if (sim_switches & SWMASK ('F')) SR = SR | IBL_FIX; /* boot from fixed? */ +for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */ + if (dboot[i] & CHANGE_ADDR) /* memory limit? */ + M[PC + i] = (-PC) & DMASK; + else if (dboot[i] & CHANGE_DEV) /* IO instr? */ + M[PC + i] = (dboot[i] + dev) & DMASK; + else M[PC + i] = dboot[i]; } +return SCPE_OK; +} diff --git a/HP2100/hp2100_dq.c b/HP2100/hp2100_dq.c index 1bd6384b..a1c36051 100644 --- a/HP2100/hp2100_dq.c +++ b/HP2100/hp2100_dq.c @@ -1,7 +1,6 @@ /* hp2100_dq.c: HP 2100 12565A disk simulator - Copyright (c) 1993-2002, Robert M. Supnik - Modified from hp2100_dp.c by Bill McDermith; used by permission + Copyright (c) 1993-2002, Bill McDermith Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -20,22 +19,29 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - Except as contained in this notice, the name of Robert M Supnik shall not + Except as contained in this notice, the name of the author shall not be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. + in this Software without prior written authorization from the author. - dq 12565A 2883/2884 disk system + dq 12565A 2883 disk system + 10-Nov-02 RMS Added boot command, rebuilt like 12559/13210 09-Jan-02 WOM Copied dp driver and mods for 2883 + + Differences between 12559/13210 and 12565 controllers + - 12565 stops transfers on address miscompares; 12559/13210 only stops writes + - 12565 does not set error on positioner busy + - 12565 does not set positioner busy if already on cylinder + - 12565 does not need eoc logic, it will hit an invalid head number */ #include "hp2100_defs.h" #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ #define UNIT_WLK (1 << UNIT_V_WLK) -#define UNIT_W_UF 2 /* # flags */ #define FNC u3 /* saved function */ #define CYL u4 /* cylinder */ +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */ #define DQ_N_NUMWD 7 #define DQ_NUMWD (1 << DQ_N_NUMWD) /* words/sector */ @@ -64,9 +70,9 @@ #define FNC_SEEK1 020 /* fake - seek1 */ #define FNC_SEEK2 021 /* fake - seek2 */ -#define FNC_CHK1 022 /* fake - check1 */ -#define FNC_LA1 023 /* fake - arec1 */ -#define FNC_RCL1 024 /* fake - recal1 */ +#define FNC_SEEK3 022 /* fake - seek3 */ +#define FNC_CHK1 023 /* fake - check1 */ +#define FNC_LA1 024 /* fake - ldaddr1 */ #define CW_V_DRV 0 /* drive */ #define CW_M_DRV 01 @@ -85,42 +91,50 @@ #define DA_GETSC(x) (((x) >> DA_V_SC) & DA_M_SC) #define DA_CKMASK 0777 /* check mask */ -/* Status */ +/* Status in dqc_sta[drv] - (d) = dynamic */ -#define STA_DID 0000200 /* drive ID */ -#define STA_NRDY 0000100 /* not ready */ +#define STA_DID 0000200 /* drive ID (d) */ +#define STA_NRDY 0000100 /* not ready (d) */ #define STA_EOC 0000040 /* end of cylinder */ #define STA_AER 0000020 /* addr error */ #define STA_FLG 0000010 /* flagged */ #define STA_BSY 0000004 /* seeking */ #define STA_DTE 0000002 /* data error */ #define STA_ERR 0000001 /* any error */ -#define STA_ALLERR (STA_DID + STA_NRDY + STA_EOC + \ - STA_FLG + STA_DTE) +#define STA_ALLERR (STA_NRDY + STA_EOC + STA_AER + STA_FLG + STA_DTE) -extern int32 PC; +extern uint16 *M; +extern int32 PC, SR; extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; -int32 dqc_busy = 0; /* cch busy */ +extern int32 sim_switches; +extern UNIT cpu_unit; + +int32 dqc_busy = 0; /* cch xfer */ int32 dqc_cnt = 0; /* check count */ -int32 dqc_eoc = 0; /* end of cyl */ -int32 dqc_sta[DQ_NUMDRV] = { 0 }; /* status regs */ -int32 dqc_stime = 10; /* seek time */ -int32 dqc_ctime = 10; /* command time */ +int32 dqc_stime = 100; /* seek time */ +int32 dqc_ctime = 100; /* command time */ int32 dqc_xtime = 5; /* xfer time */ -int32 dqc_rarc = 0, dqc_rarh = 0, dqc_rars = 0; /* record addr */ +int32 dqc_dtime = 2; /* dch time */ int32 dqd_obuf = 0, dqd_ibuf = 0; /* dch buffers */ int32 dqc_obuf = 0; /* cch buffers */ +int32 dqd_xfer = 0; /* xfer in prog */ +int32 dqd_wval = 0; /* write data valid */ int32 dq_ptr = 0; /* buffer ptr */ +uint8 dqc_rarc[DQ_NUMDRV] = { 0 }; /* cylinder */ +uint8 dqc_rarh[DQ_NUMDRV] = { 0 }; /* head */ +uint8 dqc_rars[DQ_NUMDRV] = { 0 }; /* sector */ +uint16 dqc_sta[DQ_NUMDRV] = { 0 }; /* status regs */ uint16 dqxb[DQ_NUMWD]; /* sector buffer */ +DEVICE dqd_dev, dqc_dev; int32 dqdio (int32 inst, int32 IR, int32 dat); int32 dqcio (int32 inst, int32 IR, int32 dat); t_stat dqc_svc (UNIT *uptr); +t_stat dqd_svc (UNIT *uptr); t_stat dqc_reset (DEVICE *dptr); -t_stat dqc_vlock (UNIT *uptr, int32 val); -t_stat dqc_attach (UNIT *uptr, char *cptr); -t_stat dqc_detach (UNIT *uptr); -void dq_go (int32 fnc, int32 drv, int32 time, int32 attdev); +t_stat dqc_boot (int32 unitno, DEVICE *dptr); +void dq_god (int32 fnc, int32 drv, int32 time); +void dq_goc (int32 fnc, int32 drv, int32 time); /* DQD data structures @@ -130,13 +144,13 @@ void dq_go (int32 fnc, int32 drv, int32 time, int32 attdev); */ DIB dq_dib[] = { - { DQD, 1, 0, 0, 0, 0, &dqdio }, - { DQC, 1, 0, 0, 0, 0, &dqcio } }; + { DQD, 0, 0, 0, 0, &dqdio }, + { DQC, 0, 0, 0, 0, &dqcio } }; #define dqd_dib dq_dib[0] #define dqc_dib dq_dib[1] -UNIT dqd_unit = { UDATA (NULL, 0, 0) }; +UNIT dqd_unit = { UDATA (&dqd_svc, 0, 0) }; REG dqd_reg[] = { { ORDATA (IBUF, dqd_ibuf, 16) }, @@ -145,22 +159,24 @@ REG dqd_reg[] = { { FLDATA (CTL, dqd_dib.ctl, 0) }, { FLDATA (FLG, dqd_dib.flg, 0) }, { FLDATA (FBF, dqd_dib.fbf, 0) }, + { FLDATA (XFER, dqd_xfer, 0) }, + { FLDATA (WVAL, dqd_wval, 0) }, { BRDATA (DBUF, dqxb, 8, 16, DQ_NUMWD) }, { DRDATA (BPTR, dq_ptr, DQ_N_NUMWD) }, { ORDATA (DEVNO, dqd_dib.devno, 6), REG_HRO }, - { FLDATA (*DEVENB, dqd_dib.enb, 0), REG_HRO }, { NULL } }; MTAB dqd_mod[] = { { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &dqd_dib }, + &hp_setdev, &hp_showdev, &dqd_dev }, { 0 } }; DEVICE dqd_dev = { "DQD", &dqd_unit, dqd_reg, dqd_mod, 1, 10, DQ_N_NUMWD, 1, 8, 16, NULL, NULL, &dqc_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &dqd_dib, 0 }; /* DQC data structures @@ -171,47 +187,47 @@ DEVICE dqd_dev = { */ UNIT dqc_unit[] = { - { UDATA (&dqc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DQ_SIZE) }, - { UDATA (&dqc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DQ_SIZE) } }; + { UDATA (&dqc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, DQ_SIZE) }, + { UDATA (&dqc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, DQ_SIZE) } }; REG dqc_reg[] = { { ORDATA (OBUF, dqc_obuf, 16) }, { ORDATA (BUSY, dqc_busy, 2), REG_RO }, - { ORDATA (RARC, dqc_rarc, 8) }, - { ORDATA (RARH, dqc_rarh, 5) }, - { ORDATA (RARS, dqc_rars, 5) }, - { ORDATA (CNT, dqc_cnt, 5) }, + { ORDATA (CNT, dqc_cnt, 9) }, { FLDATA (CMD, dqc_dib.cmd, 0) }, { FLDATA (CTL, dqc_dib.ctl, 0) }, { FLDATA (FLG, dqc_dib.flg, 0) }, { FLDATA (FBF, dqc_dib.fbf, 0) }, - { FLDATA (EOC, dqc_eoc, 0) }, + { BRDATA (RARC, dqc_rarc, 8, 8, DQ_NUMDRV) }, + { BRDATA (RARH, dqc_rarh, 8, 5, DQ_NUMDRV) }, + { BRDATA (RARS, dqc_rars, 8, 5, DQ_NUMDRV) }, + { BRDATA (STA, dqc_sta, 8, 16, DQ_NUMDRV) }, { DRDATA (CTIME, dqc_ctime, 24), PV_LEFT }, + { DRDATA (DTIME, dqc_dtime, 24), PV_LEFT }, { DRDATA (STIME, dqc_stime, 24), PV_LEFT }, { DRDATA (XTIME, dqc_xtime, 24), REG_NZ + PV_LEFT }, - { BRDATA (STA, dqc_sta, 8, 16, DQ_NUMDRV) }, - { URDATA (UFLG, dqc_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, - DQ_NUMDRV, REG_HRO) }, + { URDATA (UCYL, dqc_unit[0].CYL, 10, 8, 0, + DQ_NUMDRV, PV_LEFT | REG_HRO) }, + { URDATA (UFNC, dqc_unit[0].FNC, 8, 8, 0, + DQ_NUMDRV, REG_HRO) }, { ORDATA (DEVNO, dqc_dib.devno, 6), REG_HRO }, - { FLDATA (*DEVENB, dqc_dib.enb, 0), REG_HRO }, { NULL } }; MTAB dqc_mod[] = { -/* { UNIT_WLK, 0, "write enabled", "ENABLED", &dqc_vlock }, */ -/* { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &dqc_vlock }, */ - { MTAB_XTD | MTAB_VDV, 1, NULL, "ENABLED", - &set_enb, NULL, &dqd_dib }, - { MTAB_XTD | MTAB_VDV, 1, NULL, "DISABLED", - &set_dis, NULL, &dqd_dib }, + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, + { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &dqd_dib }, + &hp_setdev, &hp_showdev, &dqd_dev }, { 0 } }; DEVICE dqc_dev = { "DQC", dqc_unit, dqc_reg, dqc_mod, DQ_NUMDRV, 8, 24, 1, 8, 16, NULL, NULL, &dqc_reset, - NULL, &dqc_attach, &dqc_detach }; + &dqc_boot, NULL, NULL, + &dqc_dib, DEV_DISABLE }; /* IOT routines */ @@ -219,10 +235,10 @@ int32 dqdio (int32 inst, int32 IR, int32 dat) { int32 devd; -devd = IR & DEVMASK; /* get device no */ +devd = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & HC) == 0) { setFLG (devd); } /* STF */ + if ((IR & I_HC) == 0) { setFLG (devd); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (devd) == 0) PC = (PC + 1) & VAMASK; @@ -232,6 +248,7 @@ case ioSFS: /* skip flag set */ return dat; case ioOTX: /* output */ dqd_obuf = dat; + if (!dqc_busy || dqd_xfer) dqd_wval = 1; /* if !overrun, valid */ break; case ioMIX: /* merge */ dat = dat | dqd_ibuf; @@ -240,15 +257,19 @@ case ioLIX: /* load */ dat = dqd_ibuf; break; case ioCTL: /* control clear/set */ - if (IR & AB) { /* CLC */ - clrCTL (devd); /* clr ctl, cmd */ - clrCMD (devd); } - else { setCTL (devd); /* STC */ - setCMD (devd); } /* set ctl, cmd */ + if (IR & I_CTL) { /* CLC */ + clrCTL (devd); /* clr ctl, cmd */ + clrCMD (devd); + dqd_xfer = 0; } /* clr xfer */ + else { /* STC */ + setCTL (devd); /* set ctl, cmd */ + setCMD (devd); + if (dqc_busy && !dqd_xfer) /* overrun? */ + dqc_sta[dqc_busy - 1] |= STA_DTE | STA_ERR; } break; default: break; } -if (IR & HC) { clrFLG (devd); } /* H/C option */ +if (IR & I_HC) { clrFLG (devd); } /* H/C option */ return dat; } @@ -256,10 +277,10 @@ int32 dqcio (int32 inst, int32 IR, int32 dat) { int32 devc, fnc, drv; -devc = IR & DEVMASK; /* get device no */ +devc = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & HC) == 0) { setFLG (devc); } /* STF */ + if ((IR & I_HC) == 0) { setFLG (devc); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (devc) == 0) PC = (PC + 1) & VAMASK; @@ -275,56 +296,197 @@ case ioLIX: /* load */ case ioMIX: /* merge */ break; /* no data */ case ioCTL: /* control clear/set */ - if (IR & AB) { /* CLC? */ - clrCMD (devc); /* clr cmd, ctl */ - clrCTL (devc); /* cancel non-seek */ - if (dqc_busy) sim_cancel (&dqc_unit[dqc_busy - 1]); - dqc_busy = 0; } /* clr busy */ - else if (!CTL (devc)) { /* set and now clr? */ - setCMD (devc); /* set cmd, ctl */ - setCTL (devc); - drv = CW_GETDRV (dqc_obuf); /* get fnc, drv */ - fnc = CW_GETFNC (dqc_obuf); /* from cmd word */ - switch (fnc) { /* case on fnc */ - case FNC_SEEK: case FNC_RCL: /* seek, recal */ - dqc_sta[drv] = dqc_sta[drv] | STA_BSY; - dq_go (fnc, drv, dqc_xtime, devc); - break; - case FNC_STA: case FNC_LA: /* rd sta, load addr */ - dq_go (fnc, drv, dqc_xtime, 0); - break; - case FNC_CHK: /* check */ - dq_go (fnc, drv, dqc_xtime, devc); - break; - case FNC_RD: case FNC_WD: case FNC_WA: /* read, write, wr addr */ - dq_go (fnc, drv, dqc_ctime, devc); - break; - } /* end case */ + if (IR & I_CTL) { /* CLC? */ + clrCMD (devc); /* clr cmd, ctl */ + clrCTL (devc); /* cancel non-seek */ + if (dqc_busy) sim_cancel (&dqc_unit[dqc_busy - 1]); + sim_cancel (&dqd_unit); /* cancel dch */ + dqd_xfer = 0; /* clr dch xfer */ + dqc_busy = 0; } /* clr busy */ + else if (!CTL (devc)) { /* set and was clr? */ + setCMD (devc); /* set cmd, ctl */ + setCTL (devc); + drv = CW_GETDRV (dqc_obuf); /* get fnc, drv */ + fnc = CW_GETFNC (dqc_obuf); /* from cmd word */ + switch (fnc) { /* case on fnc */ + case FNC_SEEK: case FNC_RCL: /* seek, recal */ + case FNC_CHK: /* check */ + dqc_sta[drv] = 0; /* clear status */ + case FNC_STA: case FNC_LA: /* rd sta, load addr */ + dq_god (fnc, drv, dqc_dtime); /* sched dch xfer */ + break; + case FNC_RD: case FNC_WD: /* read, write */ + case FNC_RA: case FNC_WA: /* rd addr, wr addr */ + case FNC_AS: /* address skip */ + dq_goc (fnc, drv, dqc_ctime); /* sched drive */ + break; + } /* end case */ } /* end else */ break; default: break; } -if (IR & HC) { clrFLG (devc); } /* H/C option */ +if (IR & I_HC) { clrFLG (devc); } /* H/C option */ return dat; } -/* Unit service +/* Start data channel operation */ - Unit must be attached; detach cancels operation. +void dq_god (int32 fnc, int32 drv, int32 time) +{ +dqd_unit.CYL = drv; /* save unit */ +dqd_unit.FNC = fnc; /* save function */ +sim_activate (&dqd_unit, time); +return; +} + +/* Start controller operation */ + +void dq_goc (int32 fnc, int32 drv, int32 time) +{ +if (sim_is_active (&dqc_unit[drv])) { /* still seeking? */ + sim_cancel (&dqc_unit[drv]); /* cancel */ + time = time + dqc_stime; } /* take longer */ +dqc_sta[drv] = 0; /* clear status */ +dq_ptr = 0; /* init buf ptr */ +dqc_busy = drv + 1; /* set busy */ +dqd_xfer = 1; /* xfer in prog */ +dqc_unit[drv].FNC = fnc; /* save function */ +sim_activate (&dqc_unit[drv], time); /* activate unit */ +return; +} + +/* Data channel unit service + + This routine handles the data channel transfers. It also handles + data transfers that are blocked by seek in progress. + + uptr->CYL = target drive + uptr->FNC = target function Seek substates seek - transfer cylinder - seek1 - transfer head/surface - seek2 - done + seek1 - transfer head/surface, sched drive + Recalibrate substates + rcl - clear cyl/head/surface, sched drive Load address la - transfer cylinder la1 - transfer head/surface, finish operation Status check - transfer status, finish operation Check data - chk - transfer sector count + chk - transfer sector count, sched drive +*/ + +t_stat dqd_svc (UNIT *uptr) +{ +int32 drv, devc, devd, st; + +drv = uptr->CYL; /* get drive no */ +devc = dqc_dib.devno; /* get cch devno */ +devd = dqd_dib.devno; /* get dch devno */ +switch (uptr->FNC) { /* case function */ + +case FNC_SEEK: /* seek, need cyl */ + if (CMD (devd)) { /* dch active? */ + dqc_rarc[drv] = DA_GETCYL (dqd_obuf); /* take cyl word */ + dqd_wval = 0; /* clr data valid */ + setFLG (devd); /* set dch flg */ + clrCMD (devd); /* clr dch cmd */ + uptr->FNC = FNC_SEEK1; } /* advance state */ + sim_activate (uptr, dqc_xtime); /* no, wait more */ + break; +case FNC_SEEK1: /* seek, need hd/sec */ + if (CMD (devd)) { /* dch active? */ + dqc_rarh[drv] = DA_GETHD (dqd_obuf); /* get head */ + dqc_rars[drv] = DA_GETSC (dqd_obuf); /* get sector */ + dqd_wval = 0; /* clr data valid */ + setFLG (devd); /* set dch flg */ + clrCMD (devd); /* clr dch cmd */ + if (sim_is_active (&dqc_unit[drv])) break; /* if busy */ + st = abs (dqc_rarc[drv] - dqc_unit[drv].CYL) * dqc_stime; + if (st == 0) st = dqc_xtime; /* if on cyl, min time */ + else dqc_sta[drv] = dqc_sta[drv] | STA_BSY; /* set busy */ + sim_activate (&dqc_unit[drv], st); /* schedule op */ + dqc_unit[drv].CYL = dqc_rarc[drv]; /* on cylinder */ + dqc_unit[drv].FNC = FNC_SEEK2; } /* advance state */ + else sim_activate (uptr, dqc_xtime); /* no, wait more */ + break; + +case FNC_RCL: /* recalibrate */ + dqc_rarc[drv] = dqc_rarh[drv] = dqc_rars[drv] = 0; /* clear RAR */ + if (sim_is_active (&dqc_unit[drv])) break; /* ignore if busy */ + st = dqc_unit[drv].CYL * dqc_stime; /* calc diff */ + if (st == 0) st = dqc_xtime; /* if on cyl, min time */ + else dqc_sta[drv] = dqc_sta[drv] | STA_BSY; /* set busy */ + sim_activate (&dqc_unit[drv], st); /* schedule drive */ + dqc_unit[drv].CYL = 0; /* on cylinder */ + dqc_unit[drv].FNC = FNC_SEEK2; /* advance state */ + break; + +case FNC_LA: /* arec, need cyl */ + if (CMD (devd)) { /* dch active? */ + dqc_rarc[drv] = DA_GETCYL (dqd_obuf); /* take cyl word */ + dqd_wval = 0; /* clr data valid */ + setFLG (devd); /* set dch flg */ + clrCMD (devd); /* clr dch cmd */ + uptr->FNC = FNC_LA1; } /* advance state */ + sim_activate (uptr, dqc_xtime); /* no, wait more */ + break; +case FNC_LA1: /* arec, need hd/sec */ + if (CMD (devd)) { /* dch active? */ + dqc_rarh[drv] = DA_GETHD (dqd_obuf); /* get head */ + dqc_rars[drv] = DA_GETSC (dqd_obuf); /* get sector */ + dqd_wval = 0; /* clr data valid */ + setFLG (devc); /* set cch flg */ + clrCMD (devc); /* clr cch cmd */ + setFLG (devd); /* set dch flg */ + clrCMD (devd); } /* clr dch cmd */ + else sim_activate (uptr, dqc_xtime); /* no, wait more */ + break; + +case FNC_STA: /* read status */ + if (CMD (devd)) { /* dch active? */ + if (dqc_unit[drv].flags & UNIT_ATT) /* attached? */ + dqd_ibuf = dqc_sta[drv] & ~STA_DID; + else dqd_ibuf = STA_NRDY; + if (drv) dqd_ibuf = dqd_ibuf | STA_DID; + setFLG (devd); /* set dch flg */ + clrCMD (devd); /* clr dch cmd */ + dqc_sta[drv] = dqc_sta[drv] & /* clr sta flags */ + ~(STA_DTE | STA_FLG | STA_AER | STA_EOC | STA_ERR); + } + else sim_activate (uptr, dqc_xtime); /* wait more */ + break; + +case FNC_CHK: /* check, need cnt */ + if (CMD (devd)) { /* dch active? */ + dqc_cnt = dqd_obuf & DA_CKMASK; /* get count */ + dqd_wval = 0; /* clr data valid */ +/* setFLG (devd); /* set dch flg */ +/* clrCMD (devd); /* clr dch cmd */ + dq_goc (FNC_CHK1, drv, dqc_ctime); } /* sched drv */ + else sim_activate (uptr, dqc_xtime); /* wait more */ + break; + +default: + return SCPE_IERR; } +return SCPE_OK; +} + +/* Drive unit service + + This routine handles the data transfers. + + Seek substates + seek2 - done + Recalibrate substate + rcl1 - done + Check data substates chk1 - finish operation Read + Read address + Address skip (read without header check) Write + Write address */ #define GETDA(x,y,z) \ @@ -332,252 +494,225 @@ return dat; t_stat dqc_svc (UNIT *uptr) { -int32 i, da, drv, devc, devd, err, st, maxsc; +int32 da, drv, devc, devd, err; err = 0; /* assume no err */ drv = uptr - dqc_dev.units; /* get drive no */ devc = dqc_dib.devno; /* get cch devno */ devd = dqd_dib.devno; /* get dch devno */ -switch (uptr -> FNC) { /* case function */ +if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ + setFLG (devc); /* set cch flg */ + clrCMD (devc); /* clr cch cmd */ + dqc_sta[drv] = 0; /* clr status */ + dqc_busy = 0; /* ctlr is free */ + dqd_xfer = dqd_wval = 0; + return SCPE_OK; } +switch (uptr->FNC) { /* case function */ -case FNC_SEEK: /* seek, need cyl */ - if (CMD (devd)) { /* dch active? */ - dqc_rarc = DA_GETCYL (dqd_obuf); /* take cyl word */ - setFLG (devd); /* set dch flg */ - clrCMD (devd); /* clr dch cmd */ - uptr -> FNC = FNC_SEEK1; } /* advance state */ - sim_activate (uptr, dqc_xtime); /* no, wait more */ - return SCPE_OK; -case FNC_SEEK1: /* seek, need hd/sec */ - if (CMD (devd)) { /* dch active? */ - dqc_rarh = DA_GETHD (dqd_obuf); /* get head */ - dqc_rars = DA_GETSC (dqd_obuf); /* get sector */ - setFLG (devd); /* set dch flg */ - clrCMD (devd); /* clr dch cmd */ - st = abs (dqc_rarc - uptr -> CYL) * dqc_stime; /* calc diff */ - if (st == 0) st = dqc_xtime; /* min time */ - sim_activate (uptr, st); /* schedule op */ - uptr -> CYL = dqc_rarc; /* on cylinder */ - dqc_busy = 0; /* ctrl is free */ - uptr -> FNC = FNC_SEEK2; } /* advance state */ - else sim_activate (uptr, dqc_xtime); /* no, wait more */ - return SCPE_OK; case FNC_SEEK2: /* seek done */ - if (dqc_busy) sim_activate (uptr, dqc_xtime); /* ctrl busy? wait */ - else { dqc_sta[drv] = dqc_sta[drv] & ~STA_BSY; - if (uptr -> CYL >= DQ_NUMCY) { /* invalid cyl? */ - dqc_sta[drv] = dqc_sta[drv] | STA_AER; - uptr -> CYL = 0; } - if (dqc_rars >= DQ_NUMSC) /* invalid sec? */ - dqc_sta[drv] = dqc_sta[drv] | STA_AER; - setFLG (devc); /* set cch flg */ - clrCMD (devc); } /* clr cch cmd */ - return SCPE_OK; -case FNC_RCL: /* recalibrate */ - if (dqc_busy) sim_activate (uptr, dqc_xtime); /* ctrl busy? wait */ - else { st = uptr -> CYL * dqc_stime; /* calc diff */ - if (st == 0) st = dqc_xtime; /* min time */ - sim_activate (uptr, st); /* schedule op */ - uptr -> CYL = 0; /* on cylinder */ - dqc_busy = 0; /* ctrl is free */ - uptr -> FNC = FNC_RCL1; } /* advance state */ - return SCPE_OK; -case FNC_RCL1: /* recal done */ - if (dqc_busy) sim_activate (uptr, dqc_xtime); /* ctrl busy? wait */ - else { dqc_sta[drv] = dqc_sta[drv] & ~STA_BSY; - setFLG (devc); /* set cch flg */ - clrCMD (devc); } /* clr cch cmd */ - return SCPE_OK; - -case FNC_LA: /* arec, need cyl */ - if (CMD (devd)) { /* dch active? */ - dqc_rarc = DA_GETCYL (dqd_obuf); /* take cyl word */ - setFLG (devd); /* set dch flg */ - clrCMD (devd); /* clr dch cmd */ - uptr -> FNC = FNC_LA1; } /* advance state */ - sim_activate (uptr, dqc_xtime); /* no, wait more */ - return SCPE_OK; -case FNC_LA1: /* arec, need hd/sec */ - if (CMD (devd)) { /* dch active? */ - dqc_rarh = DA_GETHD (dqd_obuf); /* get head */ - dqc_rars = DA_GETSC (dqd_obuf); /* get sector */ - setFLG (devd); /* set dch flg */ - clrCMD (devd); } /* clr dch cmd */ - else { sim_activate (uptr, dqc_xtime); /* no, wait more */ - return SCPE_OK; } - break; /* done */ - -case FNC_STA: /* read status */ - if (CMD (devd)) { /* dch active? */ - dqd_ibuf = dqc_sta[drv] | ((dqc_sta[drv] & STA_ALLERR)? STA_ERR: 0); - setFLG (devd); /* set dch flg */ - clrCMD (devd); /* clr dch cmd */ - dqc_sta[drv] = dqc_sta[drv] & /* clr sta flags */ - ~(STA_DTE | STA_FLG | STA_AER | STA_EOC); - dqc_busy = 0; } /* ctlr is free */ - else sim_activate (uptr, dqc_xtime); /* wait more */ + if (uptr->CYL >= DQ_NUMCY) { /* out of range? */ + dqc_sta[drv] = dqc_sta[drv] | STA_BSY | STA_ERR; + dqc_unit[drv].CYL = 0; } + else dqc_sta[drv] = dqc_sta[drv] & ~STA_BSY; /* drive not busy */ +case FNC_SEEK3: + if (dqc_busy || FLG (devc)) { /* ctrl busy? */ + uptr->FNC = FNC_SEEK3; /* next state */ + sim_activate (uptr, dqc_xtime); } /* ctrl busy? wait */ + else { + setFLG (devc); /* set cch flg */ + clrCMD (devc); } /* clr cch cmd */ return SCPE_OK; -case FNC_CHK: /* check, need cnt */ - if (CMD (devd)) { /* dch active? */ - dqc_cnt = dqd_obuf & DA_CKMASK; /* get count */ - setFLG (devd); /* set dch flg */ - clrCMD (devd); /* clr dch cmd */ - sim_activate (uptr, dqc_ctime); /* schedule op */ - uptr -> FNC = FNC_CHK1; } /* advance state */ - else sim_activate (uptr, dqc_xtime); /* wait more */ - return SCPE_OK; -case FNC_CHK1: - if ((uptr -> CYL != dqc_rarc) || (dqc_rars >= DQ_NUMSC)) - dqc_sta[drv] = dqc_sta[drv] | STA_AER; - else { maxsc = ((2 - (dqc_rarh & 1)) * DQ_NUMSC) - dqc_rars; - if (dqc_cnt > maxsc) { /* too many sec? */ - dqc_sta[drv] = dqc_sta[drv] | STA_EOC; - dqc_rarh = dqc_rarh & ~1; /* rar = 0/2, 0 */ - dqc_rars = 0; } - else { i = dqc_rars + dqc_cnt; /* final sector */ - dqc_rars = i % DQ_NUMSC; /* reposition */ - dqc_rarh = dqc_rarh ^ ((i / DQ_NUMSC) & 1); } } - break; /* done */ - -case FNC_RD: /* read */ +case FNC_RA: /* read addr */ if (!CMD (devd)) break; /* dch clr? done */ - if (FLG (devd)) dqc_sta[drv] = dqc_sta[drv] | STA_DTE; - if (dq_ptr == 0) { /* new sector? */ - if ((uptr -> CYL != dqc_rarc) || (dqc_rars >= DQ_NUMSC)) { - dqc_sta[drv] = dqc_sta[drv] | STA_AER; - break; } - if (dqc_eoc) { /* end of cyl? */ - dqc_sta[drv] = dqc_sta[drv] | STA_EOC; - break; } - da = GETDA (dqc_rarc, dqc_rarh, dqc_rars); /* get addr */ - dqc_rars = dqc_rars + 1; /* incr address */ - if (dqc_rars >= DQ_NUMSC) { /* end of trk? */ - dqc_rars = 0; /* wrap to */ - dqc_rarh = dqc_rarh ^ 1; /* next cyl */ - dqc_eoc = ((dqc_rarh & 1) == 0); } /* calc eoc */ - if (err = fseek (uptr -> fileref, da * sizeof (int16), - SEEK_SET)) break; - fxread (dqxb, sizeof (int16), DQ_NUMWD, uptr -> fileref); - if (err = ferror (uptr -> fileref)) break; } - dqd_ibuf = dqxb[dq_ptr++]; /* get word */ - if (dq_ptr >= DQ_NUMWD) dq_ptr = 0; /* wrap if last */ + if (dq_ptr == 0) dqd_ibuf = uptr->CYL; /* 1st word? */ + else if (dq_ptr == 1) { /* second word? */ + dqd_ibuf = (dqc_rarh[drv] << DA_V_HD) | + (dqc_rars[drv] << DA_V_SC); + dqc_rars[drv] = dqc_rars[drv] + 1; /* incr address */ + if (dqc_rars[drv] >= DQ_NUMSC) /* end of surf? */ + dqc_rars[drv] = 0; } + else break; + dq_ptr = dq_ptr + 1; setFLG (devd); /* set dch flg */ clrCMD (devd); /* clr dch cmd */ sim_activate (uptr, dqc_xtime); /* sched next word */ return SCPE_OK; + +case FNC_AS: /* address skip */ +case FNC_RD: /* read */ +case FNC_CHK1: /* check */ + if (dq_ptr == 0) { /* new sector? */ + if (!CMD (devd) && (uptr->FNC != FNC_CHK1)) break; + if ((uptr->CYL != dqc_rarc[drv]) || /* wrong cyl or */ + (dqc_rars[drv] >= DQ_NUMSC)) { /* bad sector? */ + dqc_sta[drv] = dqc_sta[drv] | STA_AER | STA_ERR; + break; } + if (dqc_rarh[drv] >= DQ_NUMSF) { /* bad head? */ + dqc_sta[drv] = dqc_sta[drv] | STA_EOC | STA_ERR; + break; } + da = GETDA (dqc_rarc[drv], dqc_rarh[drv], dqc_rars[drv]); + dqc_rars[drv] = dqc_rars[drv] + 1; /* incr address */ + if (dqc_rars[drv] >= DQ_NUMSC) { /* end of surf? */ + dqc_rars[drv] = 0; /* wrap to */ + dqc_rarh[drv] = dqc_rarh[drv] + 1; } /* next head */ + if (err = fseek (uptr->fileref, da * sizeof (int16), + SEEK_SET)) break; + fxread (dqxb, sizeof (int16), DQ_NUMWD, uptr->fileref); + if (err = ferror (uptr->fileref)) break; } + dqd_ibuf = dqxb[dq_ptr++]; /* get word */ + if (dq_ptr >= DQ_NUMWD) { /* end of sector? */ + if (uptr->FNC == FNC_CHK1) { /* check? */ + dqc_cnt = (dqc_cnt - 1) & DA_CKMASK; /* decr count */ + if (dqc_cnt == 0) break; } /* if zero, done */ + dq_ptr = 0; } /* wrap buf ptr */ + if (CMD (devd) && dqd_xfer) { /* dch on, xfer? */ + setFLG (devd); } /* set flag */ + clrCMD (devd); /* clr dch cmd */ + sim_activate (uptr, dqc_xtime); /* sched next word */ + return SCPE_OK; case FNC_WA: /* write address */ case FNC_WD: /* write */ - if (dqc_eoc) { /* end of cyl? */ - dqc_sta[drv] = dqc_sta[drv] | STA_EOC; /* set status */ + if (dq_ptr == 0) { /* sector start? */ + if (!CMD (devd) && !dqd_wval) break; /* xfer done? */ + if(uptr->flags & UNIT_WPRT) { /* write protect? */ + dqc_sta[drv] = dqc_sta[drv] | STA_FLG | STA_ERR; break; } /* done */ - if (FLG (devd)) dqc_sta[drv] = dqc_sta[drv] | STA_DTE; - dqxb[dq_ptr++] = dqd_obuf; /* store word */ - if (!CMD (devd)) { /* dch clr? done */ - for ( ; dq_ptr < DQ_NUMWD; dq_ptr++) dqxb[dq_ptr] = 0; } + if ((uptr->CYL != dqc_rarc[drv]) || /* wrong cyl or */ + (dqc_rars[drv] >= DQ_NUMSC)) { /* bad sector? */ + dqc_sta[drv] = dqc_sta[drv] | STA_AER | STA_ERR; + break; } + if (dqc_rarh[drv] >= DQ_NUMSF) { /* bad head? */ + dqc_sta[drv] = dqc_sta[drv] | STA_EOC | STA_ERR; + break; } } /* done */ + dqxb[dq_ptr++] = dqd_wval? dqd_obuf: 0; /* store word/fill */ + dqd_wval = 0; /* clr data valid */ if (dq_ptr >= DQ_NUMWD) { /* buffer full? */ - if ((uptr -> CYL != dqc_rarc) || (dqc_rars >= DQ_NUMSC)) { - dqc_sta[drv] = dqc_sta[drv] | STA_AER; - break; } - da = GETDA (dqc_rarc, dqc_rarh, dqc_rars); /* get addr */ - dqc_rars = dqc_rars + 1; /* incr address */ - if (dqc_rars >= DQ_NUMSC) { /* end of trk? */ - dqc_rars = 0; /* wrap to */ - dqc_rarh = dqc_rarh ^ 1; /* next cyl */ - dqc_eoc = ((dqc_rarh & 1) == 0); } /* calc eoc */ - if (err = fseek (uptr -> fileref, da * sizeof (int16), - SEEK_SET)) return TRUE; - fxwrite (dqxb, sizeof (int16), DQ_NUMWD, uptr -> fileref); - if (err = ferror (uptr -> fileref)) break; - dq_ptr = 0; } - if (CMD (devd)) { /* dch active? */ - setFLG (devd); /* set dch flg */ - clrCMD (devd); /* clr dch cmd */ - sim_activate (uptr, dqc_xtime); /* sched next word */ - return SCPE_OK; } - break; } /* end case fnc */ + da = GETDA (dqc_rarc[drv], dqc_rarh[drv], dqc_rars[drv]); + dqc_rars[drv] = dqc_rars[drv] + 1; /* incr address */ + if (dqc_rars[drv] >= DQ_NUMSC) { /* end of surf? */ + dqc_rars[drv] = 0; /* wrap to */ + dqc_rarh[drv] = dqc_rarh[drv] + 1; } /* next head */ + if (err = fseek (uptr->fileref, da * sizeof (int16), + SEEK_SET)) return TRUE; + fxwrite (dqxb, sizeof (int16), DQ_NUMWD, uptr->fileref); + if (err = ferror (uptr->fileref)) break; + dq_ptr = 0; } + if (CMD (devd) && dqd_xfer) { /* dch on, xfer? */ + setFLG (devd); } /* set flag */ + clrCMD (devd); /* clr dch cmd */ + sim_activate (uptr, dqc_xtime); /* sched next word */ + return SCPE_OK; + +default: + return SCPE_IERR; } /* end case fnc */ setFLG (devc); /* set cch flg */ clrCMD (devc); /* clr cch cmd */ dqc_busy = 0; /* ctlr is free */ +dqd_xfer = dqd_wval = 0; if (err != 0) { /* error? */ perror ("DQ I/O error"); - clearerr (uptr -> fileref); + clearerr (uptr->fileref); return SCPE_IOERR; } return SCPE_OK; } -/* Start disk operation */ - -void dq_go (int32 fnc, int32 drv, int32 time, int32 dev) -{ -if (dev && ((dqc_unit[drv].flags & UNIT_ATT) == 0)) { /* attach check? */ - dqc_sta[drv] = STA_NRDY; /* not attached */ - setFLG (dev); /* set cch flag */ - clrCMD (dev); } /* clr cch cmd */ -else { dqc_busy = drv + 1; /* set busy */ - dq_ptr = 0; /* init buf ptr */ - dqc_eoc = 0; /* clear end cyl */ - dqc_unit[drv].FNC = fnc; /* save function */ - sim_activate (&dqc_unit[drv], time); } /* activate unit */ -return; -} - /* Reset routine */ t_stat dqc_reset (DEVICE *dptr) { int32 i; +hp_enbdis_pair (&dqc_dev, &dqd_dev); /* make pair cons */ dqd_ibuf = dqd_obuf = 0; /* clear buffers */ dqc_busy = dqc_obuf = 0; -dqc_eoc = 0; +dqd_xfer = dqd_wval = 0; dq_ptr = 0; -dqc_rarc = dqc_rarh = dqc_rars = 0; /* clear rar */ dqc_dib.cmd = dqd_dib.cmd = 0; /* clear cmd */ dqc_dib.ctl = dqd_dib.ctl = 0; /* clear ctl */ dqc_dib.fbf = dqd_dib.fbf = 1; /* set fbf */ dqc_dib.flg = dqd_dib.flg = 1; /* set flg */ +sim_cancel (&dqd_unit); /* cancel dch */ for (i = 0; i < DQ_NUMDRV; i++) { /* loop thru drives */ sim_cancel (&dqc_unit[i]); /* cancel activity */ dqc_unit[i].FNC = 0; /* clear function */ dqc_unit[i].CYL = 0; - dqc_sta[i] = (dqc_unit[i].flags & UNIT_ATT)? 0: STA_NRDY; } + dqc_rarc[i] = dqc_rarh[i] = dqc_rars[i] = 0; /* clear rar */ + dqc_sta[i] = 0; } return SCPE_OK; } -/* Attach routine */ - -t_stat dqc_attach (UNIT *uptr, char *cptr) -{ -int32 drv; -t_stat r; - -drv = uptr - dqc_dev.units; /* get drive no */ -r = attach_unit (uptr, cptr); /* attach unit */ -if (r != SCPE_OK) return r; -dqc_sta[drv] = dqc_sta[drv] & ~STA_NRDY; /* update status */ -return r; -} - -/* Detach routine */ - -t_stat dqc_detach (UNIT* uptr) -{ -int32 drv; - -drv = uptr - dqc_dev.units; /* get drive no */ -dqc_sta[drv] = dqc_sta[drv] | STA_NRDY; /* update status */ -if (drv == (dqc_busy + 1)) dqc_busy = 0; /* update busy */ -sim_cancel (uptr); /* cancel op */ -return detach_unit (uptr); /* detach unit */ -} - /* Write lock/enable routine */ t_stat dqc_vlock (UNIT *uptr, int32 val) { -if (uptr -> flags & UNIT_ATT) return SCPE_ARG; +if (uptr->flags & UNIT_ATT) return SCPE_ARG; +return SCPE_OK; +} + +/* 2883/2884 bootstrap routine (subset HP 12992A ROM) */ + +#define CHANGE_DEV (1 << 24) +#define CHANGE_ADDR (1 << 23) + +static const int32 dboot[IBL_LNT] = { + 0106700+CHANGE_DEV, /*ST CLC DC ; clr dch */ + 0106701+CHANGE_DEV, /* CLC CC ; clr cch */ + 0067771, /* LDA SKCMD ; seek cmd */ + 0106600+CHANGE_DEV, /* OTB DC ; cyl # */ + 0103700+CHANGE_DEV, /* STC DC,C ; to dch */ + 0106601+CHANGE_DEV, /* OTB CC ; seek cmd */ + 0103701+CHANGE_DEV, /* STC CC,C ; to cch */ + 0102300+CHANGE_DEV, /* SFS DC ; addr wd ok? */ + 0027707, /* JMP *-1 ; no, wait */ + 0006400, /* CLB */ + 0106600+CHANGE_DEV, /* OTB DC ; head/sector */ + 0103700+CHANGE_DEV, /* STC DC,C ; to dch */ + 0102301+CHANGE_DEV, /* SFS CC ; seek done? */ + 0027714, /* JMP *-1 ; no, wait */ + 0063770, /* LDA RDCMD ; get read read */ + 0067776, /* LDB DMACW ; DMA control */ + 0106606, /* OTB 6 */ + 0067772, /* LDB ADDR1 ; memory addr */ + 0106602, /* OTB 2 */ + 0102702, /* STC 2 ; flip DMA ctrl */ + 0067774, /* LDB CNT ; word count */ + 0106602, /* OTB 2 */ + 0102601+CHANGE_DEV, /* OTA CC ; to cch */ + 0103700+CHANGE_DEV, /* STC DC,C ; start dch */ + 0103606, /* STC 6,C ; start DMA */ + 0103701+CHANGE_DEV, /* STC CC,C ; start cch */ + 0102301+CHANGE_DEV, /* SFS CC ; done? */ + 0027732, /* JMP *-1 ; no, wait */ + 0027775, /* JMP XT ; done */ + 0, 0, 0, /* unused */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0020000, /*RDCMD 020000 ; read cmd */ + 0030000, /*SKCMD 030000 ; seek cmd */ + 0102011, /*ADDR1 102011 */ + 0102055, /*ADDR2 102055 */ + 0164000, /*CNT -6144. */ + 0117773, /*XT JSB ADDR2,I ; start program */ + 0120000+CHANGE_DEV, /*DMACW 120000+DC */ + CHANGE_ADDR }; /* -ST */ + +t_stat dqc_boot (int32 unitno, DEVICE *dptr) +{ +int32 i, dev; + +if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */ +dev = dqd_dib.devno; /* get data chan dev */ +PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */ +SR = IBL_DQ + (dev << IBL_V_DEV); /* set SR */ +for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */ + if (dboot[i] & CHANGE_ADDR) /* memory limit? */ + M[PC + i] = (-PC) & DMASK; + else if (dboot[i] & CHANGE_DEV) /* IO instr? */ + M[PC + i] = (dboot[i] + dev) & DMASK; + else M[PC + i] = dboot[i]; } return SCPE_OK; } diff --git a/HP2100/hp2100_dr.c b/HP2100/hp2100_dr.c index 5fce8f7a..cefb6655 100644 --- a/HP2100/hp2100_dr.c +++ b/HP2100/hp2100_dr.c @@ -23,16 +23,19 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - fhd 12606B fixed head disk - 12619B drum + fhd 12606B 2770/2771 fixed head disk + 12610B 2773/2774/2775 drum These head-per-track devices are buffered in memory, to minimize overhead. - The drum data channel does not have a command flip-flop. Further, its - control flip-flop is not wired into the interrupt chain. Accordingly, - the simulator uses command rather than control for the data channel. + The drum data channel does not have a command flip-flop. Its control + flip-flop is not wired into the interrupt chain; accordingly, the + simulator uses command rather than control for the data channel. Its + flag does not respond to SFS, SFC, or STF. The drum control channel does not have any of the traditional flip-flops. + + 10-Nov-02 RMS Added BOOT command */ #include "hp2100_defs.h" @@ -51,9 +54,9 @@ /* Command word */ #define CW_WR 0100000 /* write vs read */ -#define CW_V_FTRK 7 +#define CW_V_FTRK 7 /* fhd track */ #define CW_M_FTRK 0177 -#define CW_V_DTRK 5 +#define CW_V_DTRK 5 /* drum track */ #define CW_M_DTRK 01777 #define MAX_TRK (((drc_unit.flags & UNIT_DR)? CW_M_DTRK: CW_M_FTRK) + 1) #define CW_GETTRK(x) ((drc_unit.flags & UNIT_DR)? \ @@ -62,9 +65,9 @@ #define CW_PUTTRK(x) ((drc_unit.flags & UNIT_DR)? \ (((x) & CW_M_DTRK) << CW_V_DTRK): \ (((x) & CW_M_FTRK) << CW_V_FTRK)) -#define CW_V_FSEC 0 +#define CW_V_FSEC 0 /* fhd sector */ #define CW_M_FSEC 0177 -#define CW_V_DSEC 0 +#define CW_V_DSEC 0 /* drum sector */ #define CW_M_DSEC 037 #define CW_GETSEC(x) ((drc_unit.flags & UNIT_DR)? \ (((x) >> CW_V_DSEC) & CW_M_DSEC): \ @@ -90,20 +93,24 @@ ((double) ((drc_unit.flags & UNIT_DR)? DR_DNUMSC: DR_FNUMSC)))) extern UNIT cpu_unit; +extern uint16 *M; extern int32 PC; extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; + int32 drc_cw = 0; /* fnc, addr */ int32 drc_sta = 0; /* status */ int32 drd_ibuf = 0; /* input buffer */ int32 drd_obuf = 0; /* output buffer */ int32 drd_ptr = 0; /* sector pointer */ int32 dr_stopioe = 1; /* stop on error */ -int32 dr_time = 5; /* time per word*/ +int32 dr_time = 10; /* time per word */ +DEVICE drd_dev, drc_dev; int32 drdio (int32 inst, int32 IR, int32 dat); int32 drcio (int32 inst, int32 IR, int32 dat); t_stat drc_svc (UNIT *uptr); t_stat drc_reset (DEVICE *dptr); +t_stat drc_boot (int32 unitno, DEVICE *dptr); int32 dr_incda (int32 trk, int32 sec, int32 ptr); t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); @@ -115,8 +122,8 @@ t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); */ DIB dr_dib[] = { - { DRD, 1, 0, 0, 0, 0, &drdio }, - { DRC, 1, 0, 0, 0, 0, &drcio } }; + { DRD, 0, 0, 0, 0, &drdio }, + { DRC, 0, 0, 0, 0, &drcio } }; #define drd_dib dr_dib[0] #define drc_dib dr_dib[1] @@ -132,19 +139,19 @@ REG drd_reg[] = { { FLDATA (FBF, drd_dib.fbf, 0) }, { ORDATA (BPTR, drd_ptr, 6) }, { ORDATA (DEVNO, drd_dib.devno, 6), REG_HRO }, - { FLDATA (*DEVENB, drd_dib.enb, 0), REG_HRO }, { NULL } }; MTAB drd_mod[] = { { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &drd_dib }, + &hp_setdev, &hp_showdev, &drd_dev }, { 0 } }; DEVICE drd_dev = { "DRD", &drd_unit, drd_reg, drd_mod, 1, 0, 0, 0, 0, 0, NULL, NULL, NULL, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &drd_dib, DEV_DISABLE }; /* DRC data structures @@ -168,7 +175,6 @@ REG drc_reg[] = { { DRDATA (TIME, dr_time, 24), REG_NZ + PV_LEFT }, { FLDATA (STOP_IOE, dr_stopioe, 0) }, { ORDATA (DEVNO, drc_dib.devno, 6), REG_HRO }, - { FLDATA (*DEVENB, drc_dib.enb, 0), REG_HRO }, { NULL } }; MTAB drc_mod[] = { @@ -184,19 +190,16 @@ MTAB drc_mod[] = { { UNIT_DR, 917504+1, NULL, "896K", &dr_set_size }, { UNIT_DR, 1048576+1, NULL, "1024K", &dr_set_size }, { UNIT_DR, 1572864+1, NULL, "1536K", &dr_set_size }, - { MTAB_XTD | MTAB_VDV, 1, NULL, "ENABLED", - &set_enb, NULL, &drd_dib }, - { MTAB_XTD | MTAB_VDV, 1, NULL, "DISABLED", - &set_dis, NULL, &drd_dib }, { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &drd_dib }, + &hp_setdev, &hp_showdev, &drd_dev }, { 0 } }; DEVICE drc_dev = { "DRC", &drc_unit, drc_reg, drc_mod, 1, 8, 21, 1, 8, 16, NULL, NULL, &drc_reset, - NULL, NULL, NULL }; + &drc_boot, NULL, NULL, + &drc_dib, DEV_DISABLE }; /* IOT routines */ @@ -204,17 +207,8 @@ int32 drdio (int32 inst, int32 IR, int32 dat) { int32 devd, t; -devd = IR & DEVMASK; /* get device no */ +devd = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ -case ioFLG: /* flag clear/set */ - if ((IR & HC) == 0) { setFLG (devd); } /* STF */ - break; -case ioSFC: /* skip flag clear */ - if (FLG (devd) == 0) PC = (PC + 1) & VAMASK; - return dat; -case ioSFS: /* skip flag set */ - if (FLG (devd) != 0) PC = (PC + 1) & VAMASK; - return dat; case ioOTX: /* output */ drd_obuf = dat; break; @@ -225,31 +219,30 @@ case ioLIX: /* load */ dat = drd_ibuf; break; case ioCTL: /* control clear/set */ - if (IR & AB) { /* CLC */ - clrCMD (devd); /* clr "ctl" */ - clrFLG (devd); /* clr flg */ - drc_sta = drc_sta & ~DRS_SAC; } /* clear SAC flag */ + if (IR & I_AB) { /* CLC */ + clrCMD (devd); /* clr "ctl" */ + clrFLG (devd); /* clr flg */ + drc_sta = drc_sta & ~DRS_SAC; } /* clear SAC flag */ else if (!CMD (devd)) { /* STC, not set? */ - setCMD (devd); /* set "ctl" */ - if (drc_cw & CW_WR) setFLG (devd); /* prime DMA */ - drc_sta = 0; /* clear errors */ - drd_ptr = 0; /* clear sec ptr */ - sim_cancel (&drc_unit); /* cancel curr op */ - t = CW_GETSEC (drc_cw) - GET_CURSEC (dr_time * DR_NUMWD); - if (t <= 0) t = t + DR_NUMSC; - sim_activate (&drc_unit, t * DR_NUMWD * dr_time); } + setCMD (devd); /* set "ctl" */ + if (drc_cw & CW_WR) { setFLG (devd); } /* prime DMA */ + drc_sta = 0; /* clear errors */ + drd_ptr = 0; /* clear sec ptr */ + sim_cancel (&drc_unit); /* cancel curr op */ + t = CW_GETSEC (drc_cw) - GET_CURSEC (dr_time * DR_NUMWD); + if (t <= 0) t = t + DR_NUMSC; + sim_activate (&drc_unit, t * DR_NUMWD * dr_time); } break; default: break; } -if (IR & HC) { clrFLG (devd); } /* H/C option */ +if (IR & I_HC) { clrFLG (devd); } /* H/C option */ return dat; } int32 drcio (int32 inst, int32 IR, int32 dat) { -int32 devc, st; +int32 st; -devc = IR & DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioSFC: /* skip flag clear */ PC = (PC + 1) & VAMASK; @@ -260,10 +253,11 @@ case ioOTX: /* output */ case ioLIX: /* load */ dat = 0; case ioMIX: /* merge */ - if (drc_unit.flags & UNIT_ATT) - st = GET_CURSEC (dr_time) | DRS_RDY | drc_sta | - (sim_is_active (&drc_unit)? DRS_BSY: 0); + if (drc_unit.flags & UNIT_ATT) /* attached? */ + st = GET_CURSEC (dr_time) | DRS_RDY | drc_sta | + (sim_is_active (&drc_unit)? DRS_BSY: 0); else st = drc_sta; + dat = dat | st; /* merge status */ break; default: break; } @@ -274,40 +268,39 @@ return dat; t_stat drc_svc (UNIT *uptr) { -int32 devc, devd, trk, sec; +int32 devd, trk, sec; uint32 da; -if ((uptr -> flags & UNIT_ATT) == 0) { +if ((uptr->flags & UNIT_ATT) == 0) { drc_sta = DRS_ABO; return IORETURN (dr_stopioe, SCPE_UNATT); } drc_sta = drc_sta | DRS_SAC; -devc = drc_dib.devno; /* get cch devno */ devd = drd_dib.devno; /* get dch devno */ trk = CW_GETTRK (drc_cw); sec = CW_GETSEC (drc_cw); da = ((trk * DR_NUMSC) + sec) * DR_NUMWD; if (drc_cw & CW_WR) { /* write? */ - if ((da < uptr -> capac) && (sec < DR_NUMSC)) { - *(((uint16 *) uptr -> filebuf) + da + drd_ptr) = drd_obuf; - if (((t_addr) (da + drd_ptr)) >= uptr -> hwmark) - uptr -> hwmark = da + drd_ptr + 1; } + if ((da < uptr->capac) && (sec < DR_NUMSC)) { + *(((uint16 *) uptr->filebuf) + da + drd_ptr) = drd_obuf; + if (((t_addr) (da + drd_ptr)) >= uptr->hwmark) + uptr->hwmark = da + drd_ptr + 1; } drd_ptr = dr_incda (trk, sec, drd_ptr); /* inc disk addr */ if (CMD (devd)) { /* dch active? */ - setFLG (devd); /* set dch flg */ - sim_activate (uptr, dr_time); } /* sched next word */ + setFLG (devd); /* set dch flg */ + sim_activate (uptr, dr_time); } /* sched next word */ else if (drd_ptr) { /* done, need to fill? */ - for ( ; drd_ptr < DR_NUMWD; drd_ptr++) - *(((uint16 *) uptr -> filebuf) + da + drd_ptr) = 0; } + for ( ; drd_ptr < DR_NUMWD; drd_ptr++) + *(((uint16 *) uptr->filebuf) + da + drd_ptr) = 0; } } /* end write */ else { /* read */ if (CMD (devd)) { /* dch active? */ - if ((da >= uptr -> capac) || (sec >= DR_NUMSC)) drd_ibuf = 0; - else drd_ibuf = *(((uint16 *) uptr -> filebuf) + da + drd_ptr); - drd_ptr = dr_incda (trk, sec, drd_ptr); - setFLG (devd); /* set dch flg */ - sim_activate (uptr, dr_time); } /* sched next word */ + if ((da >= uptr->capac) || (sec >= DR_NUMSC)) drd_ibuf = 0; + else drd_ibuf = *(((uint16 *) uptr->filebuf) + da + drd_ptr); + drd_ptr = dr_incda (trk, sec, drd_ptr); + setFLG (devd); /* set dch flg */ + sim_activate (uptr, dr_time); } /* sched next word */ } return SCPE_OK; } @@ -321,9 +314,9 @@ if (ptr >= DR_NUMWD) { /* end sector? */ ptr = 0; /* new sector */ sec = sec + 1; /* adv sector */ if (sec >= DR_NUMSC) { /* end track? */ - sec = 0; /* new track */ - trk = trk + 1; /* adv track */ - if (trk >= MAX_TRK) trk = 0; } /* wraps at max */ + sec = 0; /* new track */ + trk = trk + 1; /* adv track */ + if (trk >= MAX_TRK) trk = 0; } /* wraps at max */ drc_cw = (drc_cw & CW_WR) | CW_PUTTRK (trk) | CW_PUTSEC (sec); } return ptr; @@ -333,6 +326,7 @@ return ptr; t_stat drc_reset (DEVICE *dptr) { +hp_enbdis_pair (&drc_dev, &drd_dev); /* make pair cons */ drc_sta = drc_cw = drd_ptr = 0; drc_dib.cmd = drd_dib.cmd = 0; /* clear cmd */ drc_dib.ctl = drd_dib.ctl = 0; /* clear ctl */ @@ -344,13 +338,52 @@ return SCPE_OK; /* Set size routine */ -/* Set size command validation routine */ - t_stat dr_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { -if (uptr -> flags & UNIT_ATT) return SCPE_ALATT; -if (val & 1) uptr -> flags = uptr -> flags | UNIT_DR; -else uptr -> flags = uptr -> flags & ~UNIT_DR; -uptr -> capac = val & ~1; +if (uptr->flags & UNIT_ATT) return SCPE_ALATT; +if (val & 1) uptr->flags = uptr->flags | UNIT_DR; +else uptr->flags = uptr->flags & ~UNIT_DR; +uptr->capac = val & ~1; +return SCPE_OK; +} + +/* Fixed head disk/drum bootstrap routine (disc subset of disc/paper tape loader) */ + +#define CHANGE_DEV (1 << 24) +#define BOOT_BASE 056 +#define BOOT_START 060 + +static const int32 dboot[IBL_LNT - BOOT_BASE] = { + 0020000+CHANGE_DEV, /*DMA 20000+DC */ + 0000000, /* 0 */ + 0107700, /* CLC 0,C */ + 0063756, /* LDA DMA ; DMA ctrl */ + 0102606, /* OTA 6 */ + 0002700, /* CLA,CCE */ + 0102601+CHANGE_DEV, /* OTA CC ; trk = sec = 0 */ + 0001500, /* ERA ; A = 100000 */ + 0102602, /* OTA 2 ; DMA in, addr */ + 0063777, /* LDA M64 */ + 0102702, /* STC 2 */ + 0102602, /* OTA 2 ; DMA wc = -64 */ + 0103706, /* STC 6,C ; start DMA */ + 0067776, /* LDB JSF ; get JMP . */ + 0074077, /* STB 77 ; in base page */ + 0102700+CHANGE_DEV, /* STC DC ; start disc */ + 0024077, /*JSF JMP 77 ; go wait */ + 0177700 }; /*M64 -100 */ + +t_stat drc_boot (int32 unitno, DEVICE *dptr) +{ +int32 i, dev, ad; + +if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */ +dev = drd_dib.devno; /* get data chan dev */ +ad = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */ +for (i = 0; i < (IBL_LNT - BOOT_BASE); i++) { /* copy bootstrap */ + if (dboot[i] & CHANGE_DEV) /* IO instr? */ + M[ad + BOOT_BASE + i] = (dboot[i] + dev) & DMASK; + else M[ad + BOOT_BASE + i] = dboot[i]; } +PC = ad + BOOT_START; return SCPE_OK; } diff --git a/HP2100/hp2100_fp.c b/HP2100/hp2100_fp.c index eba04975..8e552c60 100644 --- a/HP2100/hp2100_fp.c +++ b/HP2100/hp2100_fp.c @@ -23,6 +23,8 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 21-Oct-02 RMS Recoded for compatibility with 21MX microcode algorithms + The HP2100 uses a unique binary floating point format: 15 14 0 @@ -43,253 +45,266 @@ Unpacked floating point numbers are stored in structure ufp - sign = fraction sign, 0 = +, 1 = - exp = exponent, 2's complement - h'l = fraction, 2's comp, with 1 high guard bit + h'l = fraction, 2's comp, left justified - Questions: - 1. Are fraction and exponent magnitude or 2's complement? 2's complement - 2. Do operations round? yes, with IEEE like standards (sticky bits) + This routine tries to reproduce the algorithms of the 2100/21MX + microcode in order to achieve 'bug-for-bug' compatibility. In + particular, + + - The FIX code produces various results in B. + - The fraction multiply code uses 16b x 16b multiplies to produce + a 31b result. It always loses the low order bit of the product. + - The fraction divide code is an approximation that may produce + an error of 1 LSB. + - Signs are tracked implicitly as part of the fraction. Unnormalized + inputs may cause the packup code to produce the wrong sign. + - "Unclean" zeros (zero fraction, non-zero exponent) are processed + like normal operands. */ #include "hp2100_defs.h" struct ufp { /* unpacked fp */ - int32 sign; /* sign */ int32 exp; /* exp */ - uint32 h; /* frac */ - uint32 l; }; + uint32 fr; }; /* frac */ #define FP_V_SIGN 31 /* sign */ #define FP_M_SIGN 01 -#define FP_GETSIGN(x) (((x) >> FP_V_SIGN) & FP_M_SIGN) -#define FP_V_FRH 8 /* fraction */ -#define FP_M_FRH 077777777 -#define FP_FRH (FP_M_FRH << FP_V_FRH) +#define FP_V_FR 8 /* fraction */ +#define FP_M_FR 077777777 #define FP_V_EXP 1 /* exponent */ #define FP_M_EXP 0177 -#define FP_GETEXP(x) (((x) >> FP_V_EXP) & FP_M_EXP) #define FP_V_EXPS 0 /* exp sign */ #define FP_M_EXPS 01 +#define FP_SIGN (FP_M_SIGN << FP_V_SIGN) +#define FP_FR (FP_M_FR << FP_V_FR) +#define FP_EXP (FP_M_EXP << FP_V_EXP) +#define FP_EXPS (FP_M_EXPS << FP_V_EXPS) +#define FP_GETSIGN(x) (((x) >> FP_V_SIGN) & FP_M_SIGN) +#define FP_GETEXP(x) (((x) >> FP_V_EXP) & FP_M_EXP) #define FP_GETEXPS(x) (((x) >> FP_V_EXPS) & FP_M_EXPS) -#define UFP_GUARD 1 /* 1 extra left */ -#define UFP_V_SIGN (FP_V_SIGN - UFP_GUARD) /* sign */ -#define UFP_SIGN (1 << UFP_V_SIGN) -#define UFP_CRY (1 << (UFP_V_SIGN + 1)) /* carry */ -#define UFP_NORM (1 << (UFP_V_SIGN - 1)) /* normalized */ -#define UFP_V_LOW (FP_V_FRH - UFP_GUARD) /* low bit */ -#define UFP_LOW (1 << UFP_V_LOW) -#define UFP_RND (1 << (UFP_V_LOW - 1)) /* round */ -#define UFP_STKY (UFP_RND - 1) /* sticky bits */ +#define FP_NORM (1 << (FP_V_SIGN - 1)) /* normalized */ +#define FP_LOW (1 << FP_V_FR) +#define FP_RNDP (1 << (FP_V_FR - 1)) /* round for plus */ +#define FP_RNDM (FP_RNDP - 1) /* round for minus */ #define FPAB ((((uint32) AR) << 16) | ((uint32) BR)) -#define HFMASK 0x7FFFFFFF /* hi frac mask */ -#define LFMASK 0xFFFFFFFF /* lo frac mask */ +#define DMASK32 0xFFFFFFFF /* Fraction shift; 0 < shift < 32 */ -#define FR_ARSH(v,s) v.l = ((v.l >> (s)) | \ - (v.h << (32 - (s)))) & LFMASK; \ - v.h = ((v.h >> (s)) | ((v.h & UFP_SIGN)? \ - (LFMASK << (32 - (s))): 0)) & HFMASK +#define FR_ARS(v,s) (((v) >> (s)) | (((v) & FP_SIGN)? \ + (DMASK32 << (32 - (s))): 0)) & DMASK32 -#define FR_LRSH(v,s) v.l = ((v.l >> (s)) | \ - (v.h << (32 - (s)))) & LFMASK; \ - v.h = (v.h >> (s)) & HFMASK - -#define FR_NEG(v) v.l = (~v.l + 1) & LFMASK; \ - v.h = (~v.h + (v.l == 0)) & HFMASK - -#define FR_NEGH(v) v = (~v + 1) & HFMASK +#define FR_NEG(v) ((~(v) + 1) & DMASK32) extern uint16 *M; -void UnpackFP (struct ufp *fop, uint32 opnd, t_bool abs); +uint32 UnpackFP (struct ufp *fop, uint32 opnd); +void NegFP (struct ufp *fop); void NormFP (struct ufp *fop); -int32 StoreFP (struct ufp *fop, t_bool rnd); +uint32 StoreFP (struct ufp *fop); /* Floating to integer conversion */ -int32 f_fix (void) +uint32 f_fix (void) { -struct ufp res; +struct ufp fop; +uint32 res = 0; -UnpackFP (&res, FPAB, 0); /* unpack A-B, norm */ -if ((res.h == 0) || (res.exp <= 0)) { /* result zero? */ - AR = 0; - return 0; } -if (res.exp > 15) { - AR = 077777; - return 1; } -FR_ARSH (res, (30 - res.exp)); /* right align frac */ -if (res.sign && res.l) res.h = res.h + 1; /* round? */ -AR = res.h & DMASK; /* store result */ +UnpackFP (&fop, FPAB); /* unpack op */ +if (fop.exp < 0) { /* exp < 0? */ + AR = 0; /* result = 0 */ + return 0; } /* B unchanged */ +if (fop.exp > 15) { /* exp > 15? */ + BR = AR; /* B has high bits */ + AR = 077777; /* result = 77777 */ + return 1; } /* overflow */ +if (fop.exp < 15) { /* if not aligned */ + res = FR_ARS (fop.fr, 15 - fop.exp); /* shift right */ + AR = (res >> 16) & DMASK; } /* AR gets result */ +BR = AR; +if ((AR & SIGN) && ((fop.fr | res) & DMASK)) /* any low bits lost? */ + AR = (AR + 1) & DMASK; /* round up */ return 0; } /* Integer to floating conversion */ -void f_flt (void) +uint32 f_flt (void) { -struct ufp res = { 0, 15, 0, 0 }; /* +, 2**15 */ +struct ufp res = { 15, 0 }; /* +, 2**15 */ -res.h = ((uint32) AR) << 15; /* left justify */ -if (res.h & UFP_SIGN) res.sign = 1; /* set sign */ -NormFP (&res); /* normalize */ -StoreFP (&res, 0); /* store result */ -return; +res.fr = ((uint32) AR) << 16; /* left justify */ +StoreFP (&res); /* store result */ +return 0; /* clr overflow */ } /* Floating point add/subtract */ -int32 f_as (uint32 opnd, t_bool sub) +uint32 f_as (uint32 opnd, t_bool sub) { struct ufp fop1, fop2, t; int32 ediff; -UnpackFP (&fop1, FPAB, 0); /* unpack A-B, norm */ -UnpackFP (&fop2, opnd, 0); /* get op, norm */ +UnpackFP (&fop1, FPAB); /* unpack A-B */ +UnpackFP (&fop2, opnd); /* get op */ if (sub) { /* subtract? */ - fop2.sign = fop2.sign ^ 1; /* negate sign */ - fop2.h = FR_NEGH (fop2.h); /* negate frac */ - if (fop2.h & UFP_SIGN) { /* -1/2? */ - fop2.h = UFP_NORM; /* special case */ - fop2.exp = fop2.exp + 1; } } -if (fop1.h == 0) fop1 = fop2; /* op1 = 0? res = op2 */ -else if (fop2.h != 0) { /* op2 = 0? no add */ - if (fop1.exp < fop2.exp) { /* |op1| < |op2|? */ - t = fop2; /* swap operands */ - fop2 = fop1; - fop1 = t; } - ediff = fop1.exp - fop2.exp; /* get exp diff */ - if (ediff <= 24) { - if (ediff) { FR_ARSH (fop2, ediff); } /* denorm, signed */ - fop1.h = fop1.h + fop2.h; /* add fractions */ - if (fop1.sign ^ fop2.sign) { /* eff subtract */ - if (fop1.h & UFP_SIGN) fop1.sign = 1; /* result neg? */ - else fop1.sign = 0; - NormFP (&fop1); } /* normalize result */ - else if (fop1.h & (fop1.sign? UFP_CRY: UFP_SIGN)) { /* add, cry out? */ - fop1.h = fop1.h >> 1; /* renormalize */ - fop1.exp = fop1.exp + 1; } /* incr exp */ - } /* end if ediff */ - } /* end if fop2 */ -return StoreFP (&fop1, 1); /* store result */ + fop2.fr = FR_NEG (fop2.fr); /* negate frac */ + if (fop2.fr == FP_SIGN) { /* -1/2? */ + fop2.fr = fop2.fr >> 1; /* special case */ + fop2.exp = fop2.exp + 1; } } +if (fop1.fr == 0) fop1 = fop2; /* op1 = 0? res = op2 */ +else if (fop2.fr != 0) { /* op2 = 0? no add */ + if (fop1.exp < fop2.exp) { /* |op1| < |op2|? */ + t = fop2; /* swap operands */ + fop2 = fop1; + fop1 = t; } + ediff = fop1.exp - fop2.exp; /* get exp diff */ + if (ediff <= 24) { + if (ediff) fop2.fr = FR_ARS (fop2.fr, ediff); /* denorm, signed */ + if ((fop1.fr ^ fop2.fr) & FP_SIGN) /* unlike signs? */ + fop1.fr = fop1.fr + fop2.fr; /* eff subtract */ + else { /* like signs */ + fop1.fr = fop1.fr + fop2.fr; /* eff add */ + if (fop2.fr & FP_SIGN) { /* both -? */ + if ((fop1.fr & FP_SIGN) == 0) { /* overflow? */ + fop1.fr = FP_SIGN | (fop1.fr >> 1); /* renormalize */ + fop1.exp = fop1.exp + 1; } } /* incr exp */ + else if (fop1.fr & FP_SIGN) { /* both +, cry out? */ + fop1.fr = fop1.fr >> 1; /* renormalize */ + fop1.exp = fop1.exp + 1; } /* incr exp */ + } /* end else like */ + } /* end if ediff */ + } /* end if fop2 */ +return StoreFP (&fop1); /* store result */ } -/* Floating point multiply */ +/* Floating point multiply - passes diagnostic */ -int32 f_mul (uint32 opnd) +uint32 f_mul (uint32 opnd) { struct ufp fop1, fop2; -struct ufp res = { 0, 0, 0, 0 }; -int32 i; +struct ufp res = { 0, 0 }; +int32 shi1, shi2, t1, t2, t3, t4, t5; -UnpackFP (&fop1, FPAB, 1); /* unpack |A-B|, norm */ -UnpackFP (&fop2, opnd, 1); /* unpack |op|, norm */ -if (fop1.h && fop2.h) { /* if both != 0 */ - res.sign = fop1.sign ^ fop2.sign; /* sign = diff */ - res.exp = fop1.exp + fop2.exp; /* exp = sum */ - for (i = 0; i < 24; i++) { /* 24 iterations */ - if (fop2.h & UFP_LOW) /* mplr bit set? */ - res.h = res.h + fop1.h; /* add mpcn to res */ - fop2.h = fop2.h >> 1; /* shift mplr */ - FR_LRSH (res, 1); } /* shift res */ - if (res.sign) FR_NEG (res); /* correct sign */ - NormFP (&res); /* normalize */ - } -return StoreFP (&res, 1); /* store */ +UnpackFP (&fop1, FPAB); /* unpack A-B */ +UnpackFP (&fop2, opnd); /* unpack op */ +if (fop1.fr && fop2.fr) { /* if both != 0 */ + res.exp = fop1.exp + fop2.exp + 1; /* exp = sum */ + shi1 = SEXT (fop1.fr >> 16); /* mpy hi */ + shi2 = SEXT (fop2.fr >> 16); /* mpc hi */ + t1 = shi2 * ((int32) ((fop1.fr >> 1) & 077600));/* mpc hi * (mpy lo/2) */ + t2 = shi1 * ((int32) ((fop2.fr >> 1) & 077600));/* mpc lo * (mpy hi/2) */ + t3 = t1 + t2; /* cross product */ + t4 = (shi1 * shi2) & ~1; /* mpy hi * mpc hi */ + t5 = (SEXT (t3 >> 16)) << 1; /* add in cross */ + res.fr = (t4 + t5) & DMASK32; } /* bit<0> is lost */ +return StoreFP (&res); /* store */ } -/* Floating point divide */ +/* Floating point divide - reverse engineered from diagnostic */ -int32 f_div (uint32 opnd) +uint32 divx (uint32 ba, uint32 dvr, uint32 *rem) +{ +int32 sdvd = 0, sdvr = 0; +uint32 q, r; + +if (ba & FP_SIGN) sdvd = 1; /* 32b/16b signed dvd */ +if (dvr & SIGN) sdvr = 1; /* use old-fashioned */ +if (sdvd) ba = (~ba + 1) & DMASK32; /* unsigned divides, */ +if (sdvr) dvr = (~dvr + 1) & DMASK; /* as results may ovflo */ +q = ba / dvr; +r = ba % dvr; +if (sdvd ^ sdvr) q = (~q + 1) & DMASK; +if (sdvd) r = (~r + 1) & DMASK; +if (rem) *rem = r; +return q; +} + +uint32 f_div (uint32 opnd) { struct ufp fop1, fop2; -struct ufp quo = { 0, 0, 0, 0 }; -int32 i; +struct ufp quo = { 0, 0 }; +uint32 ba, q0, q1, q2, dvrh; -UnpackFP (&fop1, FPAB, 1); /* unpack |A-B|, norm */ -UnpackFP (&fop2, opnd, 1); /* unpack |op|, norm */ -if (fop2.h == 0) return 1; /* div by zero? */ -if (fop1.h) { /* dvd != 0? */ - quo.sign = fop1.sign ^ fop2.sign; /* sign = diff */ - quo.exp = fop1.exp - fop2.exp; /* exp = diff */ - if (fop1.h < fop2.h) { /* will sub work? */ - fop1.h = fop1.h << 1; /* ensure success */ - quo.exp = quo.exp - 1; } - for (i = 0; i < 24; i++) { /* 24 digits */ - quo.h = quo.h << 1; /* shift quotient */ - if (fop1.h >= fop2.h) { /* subtract work? */ - fop1.h = fop1.h - fop2.h; /* decrement */ - quo.h = quo.h + UFP_RND; } /* add quo bit */ - fop1.h = fop1.h << 1; } /* shift divd */ - } /* end if fop1.h */ -if (quo.sign) quo.h = FR_NEGH (quo.h); /* correct sign */ -NormFP (&quo); /* negate */ -return StoreFP (&quo, 1); /* store result */ +UnpackFP (&fop1, FPAB); /* unpack A-B */ +UnpackFP (&fop2, opnd); /* unpack op */ +dvrh = (fop2.fr >> 16) & DMASK; /* high divisor */ +if (dvrh == 0) { /* div by zero? */ + AR = 0077777; /* return most pos */ + BR = 0177776; + return 1; } +if (fop1.fr) { /* dvd != 0? */ + quo.exp = fop1.exp - fop2.exp + 1; /* exp = diff */ + ba = FR_ARS (fop1.fr, 2); /* prevent ovflo */ + q0 = divx (ba, dvrh, &ba); /* Q0 = dvd / dvrh */ + ba = (ba & ~1) << 16; /* remainder */ + ba = FR_ARS (ba, 1); /* prevent ovflo */ + q1 = divx (ba, dvrh, NULL); /* Q1 = rem / dvrh */ + ba = (fop2.fr & 0xFF00) << 13; /* dvrl / 8 */ + q2 = divx (ba, dvrh, NULL); /* dvrl / dvrh */ + ba = -(SEXT (q2)) * (SEXT (q0)); /* -Q0 * Q2 */ + ba = (ba >> 16) & 0xFFFF; /* save ms half */ + if (q1 & SIGN) quo.fr = quo.fr - 0x00010000; /* Q1 < 0? -1 */ + if (ba & SIGN) quo.fr = quo.fr - 0x00010000; /* -Q0*Q2 < 0? */ + quo.fr = quo.fr + ((ba << 2) & 0xFFFF) + q1; /* rest prod, add Q1 */ + quo.fr = quo.fr << 1; /* shift result */ + quo.fr = quo.fr + (q0 << 16); /* add Q0 */ + } /* end if fop1.h */ +return StoreFP (&quo); /* store result */ } /* Utility routines */ /* Unpack operand */ -void UnpackFP (struct ufp *fop, uint32 opnd, t_bool abs) +uint32 UnpackFP (struct ufp *fop, uint32 opnd) { -fop -> h = (opnd & FP_FRH) >> UFP_GUARD; /* get frac, guard */ -if (fop -> h) { /* non-zero? */ - fop -> sign = FP_GETSIGN (opnd); /* get sign */ - fop -> exp = FP_GETEXP (opnd); /* get exp */ - if (FP_GETEXPS (opnd)) /* get exp sign */ - fop -> exp = fop -> exp | ~FP_M_EXP; /* if -, sext */ - if (abs && fop -> sign) { /* want abs val? */ - fop -> h = FR_NEGH (fop -> h); /* negate frac*/ - if (fop -> h == UFP_SIGN) { /* -1/2? */ - fop -> h = fop -> h >> 1; /* special case */ - fop -> exp = fop -> exp + 1; } } - NormFP (fop); } /* normalize */ -else fop -> sign = fop -> exp = 0; /* clean zero */ -fop -> l = 0; -return; +fop->fr = opnd & FP_FR; /* get frac */ +fop->exp = FP_GETEXP (opnd); /* get exp */ +if (FP_GETEXPS (opnd)) fop->exp = fop->exp | ~FP_M_EXP; /* < 0? sext */ +return FP_GETSIGN (opnd); /* return sign */ } /* Normalize unpacked floating point number */ void NormFP (struct ufp *fop) { -if (fop -> h | fop -> l) { /* any fraction? */ - uint32 test = (fop -> h >> 1) & UFP_NORM; - while ((fop -> h & UFP_NORM) == test) { /* until norm */ - fop -> exp = fop -> exp - 1; - fop -> h = (fop -> h << 1) | (fop -> l >> 31); - fop -> l = fop -> l << 1; } } -else fop -> sign = fop -> exp = 0; /* clean 0 */ +if (fop->fr) { /* any fraction? */ + uint32 test = (fop->fr >> 1) & FP_NORM; + while ((fop->fr & FP_NORM) == test) { /* until norm */ + fop->exp = fop->exp - 1; + fop->fr = (fop->fr << 1); } } +else fop->exp = 0; /* clean 0 */ return; } /* Round fp number, store, generate overflow */ -int32 StoreFP (struct ufp *fop, t_bool rnd) +uint32 StoreFP (struct ufp *fop) { -int32 hi, ov; +uint32 sign, svfr, hi, ov = 0; -if (rnd && (fop -> h & UFP_RND) && - ((fop -> sign == 0) || (fop -> h & UFP_STKY) || fop -> l)) { - fop -> h = fop -> h + UFP_RND; /* round */ - if (fop -> h & ((fop -> sign)? UFP_CRY: UFP_SIGN)) { - fop -> h = fop -> h >> 1; - fop -> exp = fop -> exp + 1; } } -if (fop -> h == 0) hi = ov = 0; /* result 0? */ -else if (fop -> exp < -(FP_M_EXP + 1)) { /* underflow? */ - hi = 0; /* store clean 0 */ - ov = 1; } -else if (fop -> exp > FP_M_EXP) { /* overflow? */ - hi = 0x7FFFFFFE; /* all 1's */ - ov = 1; } -else { hi = ((fop -> h << UFP_GUARD) & FP_FRH) | /* merge frac */ - ((fop -> exp & FP_M_EXP) << FP_V_EXP); /* and exp */ - if (fop -> exp < 0) hi = hi | (1 << FP_V_EXPS); } /* add exp sign */ +NormFP (fop); /* normalize */ +svfr = fop->fr; /* save fraction */ +sign = FP_GETSIGN (fop->fr); /* save sign */ +fop->fr = (fop->fr + (sign? FP_RNDM: FP_RNDP)) & FP_FR; /* round */ +if ((fop->fr ^ svfr) & FP_SIGN) { /* sign change? */ + fop->fr = (fop->fr >> 1) | (sign? FP_SIGN: 0); /* renormalize */ + fop->exp = fop->exp + 1; } +if (fop->fr == 0) hi = 0; /* result 0? */ +else if (fop->exp < -(FP_M_EXP + 1)) { /* underflow? */ + hi = 0; /* store clean 0 */ + ov = 1; } +else if (fop->exp > FP_M_EXP) { /* overflow? */ + hi = 0x7FFFFFFE; /* all 1's */ + ov = 1; } +else hi = (fop->fr & FP_FR) | /* merge frac */ + ((fop->exp & FP_M_EXP) << FP_V_EXP) | /* and exp */ + ((fop->exp < 0)? (1 << FP_V_EXPS): 0); /* add exp sign */ AR = (hi >> 16) & DMASK; BR = hi & DMASK; return ov; diff --git a/HP2100/hp2100_lps.c b/HP2100/hp2100_lps.c new file mode 100644 index 00000000..ec034c4e --- /dev/null +++ b/HP2100/hp2100_lps.c @@ -0,0 +1,174 @@ +/* hp2100_lps.c: HP 2100 12653A line printer simulator + + Copyright (c) 1993-2002, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + lps 12653A 2767 line printer + (based on 12556B microcircuit interface) + + 24-Oct-02 RMS Added microcircuit test features + 30-May-02 RMS Widened POS to 32b + 03-Dec-01 RMS Changed DEVNO to use extended SET/SHOW + 07-Sep-01 RMS Moved function prototypes + 21-Nov-00 RMS Fixed flag, fbf power up state + Added command flop + 15-Oct-00 RMS Added variable device number support +*/ + +#include "hp2100_defs.h" + +#define LPS_BUSY 0000001 /* busy */ +#define LPS_NRDY 0100000 /* not ready */ +#define UNIT_V_DIAG (UNIT_V_UF + 0) /* diagnostic mode */ +#define UNIT_DIAG (1 << UNIT_V_DIAG) + +extern int32 PC; +extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; +int32 lps_ctime = 1000; /* char time */ +int32 lps_stopioe = 0; /* stop on error */ +int32 lps_sta = 0; + +DEVICE lps_dev; +int32 lpsio (int32 inst, int32 IR, int32 dat); +t_stat lps_svc (UNIT *uptr); +t_stat lps_reset (DEVICE *dptr); + +/* LPS data structures + + lps_dev LPS device descriptor + lps_unit LPS unit descriptor + lps_reg LPS register list +*/ + +DIB lps_dib = { LPS, 0, 0, 0, 0, &lpsio }; + +UNIT lps_unit = { + UDATA (&lps_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; + +REG lps_reg[] = { + { ORDATA (BUF, lps_unit.buf, 16) }, + { ORDATA (STA, lps_sta, 16) }, + { FLDATA (CMD, lps_dib.cmd, 0) }, + { FLDATA (CTL, lps_dib.ctl, 0) }, + { FLDATA (FLG, lps_dib.flg, 0) }, + { FLDATA (FBF, lps_dib.fbf, 0) }, + { DRDATA (POS, lps_unit.pos, 32), PV_LEFT }, + { DRDATA (CTIME, lps_ctime, 31), PV_LEFT }, + { DRDATA (PTIME, lps_unit.wait, 24), PV_LEFT }, + { FLDATA (STOP_IOE, lps_stopioe, 0) }, + { ORDATA (DEVNO, lps_dib.devno, 6), REG_HRO }, + { NULL } }; + +MTAB lps_mod[] = { + { UNIT_DIAG, UNIT_DIAG, "DIAG", "DIAG", NULL }, + { UNIT_DIAG, 0, "PRINTER", "PRINTER", NULL }, + { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, &lps_dev }, + { 0 } }; + +DEVICE lps_dev = { + "LPS", &lps_unit, lps_reg, lps_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &lps_reset, + NULL, NULL, NULL, + &lps_dib, DEV_DISABLE | DEV_DIS }; + +/* Line printer IOT routine */ + +int32 lpsio (int32 inst, int32 IR, int32 dat) +{ +int32 dev; + +dev = IR & I_DEVMASK; /* get device no */ +switch (inst) { /* case on opcode */ +case ioFLG: /* flag clear/set */ + if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */ + break; +case ioSFC: /* skip flag clear */ + if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; + return dat; +case ioSFS: /* skip flag set */ + if (FLG (dev) != 0) PC = (PC + 1) & VAMASK; + return dat; +case ioOTX: /* output */ + lps_unit.buf = dat; + break; +case ioLIX: /* load */ + dat = 0; /* default sta = 0 */ +case ioMIX: /* merge */ + if ((lps_unit.flags & UNIT_DIAG) == 0) { /* real lpt? */ + lps_sta = 0; /* create status */ + if ((lps_unit.flags & UNIT_ATT) == 0) + lps_sta = lps_sta | LPS_BUSY | LPS_NRDY; + else if (sim_is_active (&lps_unit)) + lps_sta = lps_sta | LPS_BUSY; } + dat = dat | lps_sta; /* diag, rtn status */ + break; +case ioCTL: /* control clear/set */ + if (IR & I_CTL) { /* CLC */ + clrCMD (dev); /* clear ctl, cmd */ + clrCTL (dev); } + else { setCMD (dev); /* STC */ + setCTL (dev); /* set ctl, cmd */ + if (lps_unit.flags & UNIT_DIAG) /* diagnostic? */ + sim_activate (&lps_unit, 1); /* loop back */ + else sim_activate (&lps_unit, /* real lpt, sched */ + (lps_unit.buf < 040)? lps_unit.wait: lps_ctime); } + break; +default: + break; } +if (IR & I_HC) { clrFLG (dev); } /* H/C option */ +return dat; +} + +t_stat lps_svc (UNIT *uptr) +{ +int32 dev; +int32 c = lps_unit.buf & 0177; + +dev = lps_dib.devno; /* get dev no */ +clrCMD (dev); /* clear cmd */ +setFLG (dev); /* set flag, fbf */ +if (lps_unit.flags & UNIT_DIAG) { /* diagnostic? */ + lps_sta = lps_unit.buf; /* loop back */ + return SCPE_OK; } /* done */ +if ((lps_unit.flags & UNIT_ATT) == 0) /* real lpt, att? */ + return IORETURN (lps_stopioe, SCPE_UNATT); +if (fputc (c, lps_unit.fileref) == EOF) { + perror ("LPS I/O error"); + clearerr (lps_unit.fileref); + return SCPE_IOERR; } +lps_unit.pos = ftell (lps_unit.fileref); /* update pos */ +return SCPE_OK; +} + +/* Reset routine - called from SCP, flags in DIB */ + +t_stat lps_reset (DEVICE *dptr) +{ +lps_dib.cmd = lps_dib.ctl = 0; /* clear cmd, ctl */ +lps_dib.flg = lps_dib.fbf = 1; /* set flg, fbf */ +lps_sta = lps_unit.buf = 0; +sim_cancel (&lps_unit); /* deactivate unit */ +return SCPE_OK; +} diff --git a/HP2100/hp2100_lp.c b/HP2100/hp2100_lpt.c similarity index 59% rename from HP2100/hp2100_lp.c rename to HP2100/hp2100_lpt.c index bf7981d8..bd09d145 100644 --- a/HP2100/hp2100_lp.c +++ b/HP2100/hp2100_lpt.c @@ -1,4 +1,4 @@ -/* hp2100_lp.c: HP 2100 12653A line printer simulator +/* hp2100_lpt.c: HP 2100 12845A line printer simulator Copyright (c) 1993-2002, Robert M. Supnik @@ -23,29 +23,37 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - lpt 12653A line printer + lpt 12845A line printer - 30-May-02 RMS Widened POS to 32b - 03-Dec-01 RMS Changed DEVNO to use extended SET/SHOW - 07-Sep-01 RMS Moved function prototypes - 21-Nov-00 RMS Fixed flag, fbf power up state - Added command flop - 15-Oct-00 RMS Added variable device number support + 24-Oct-02 RMS Cloned from 12653A */ #include "hp2100_defs.h" -#define LPT_BUSY 0000001 /* busy */ -#define LPT_NRDY 0100000 /* not ready */ +#define LPT_PAGELNT 60 /* page length */ + +#define LPT_NBSY 0000001 /* not busy */ +#define LPT_PAPO 0040000 /* paper out */ +#define LPT_RDY 0100000 /* ready */ + +#define LPT_CTL 0100000 /* control output */ +#define LPT_CHAN 0000100 /* skip to chan */ +#define LPT_SKIPM 0000077 /* line count mask */ +#define LPT_CHANM 0000007 /* channel mask */ extern int32 PC; extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; -int32 lpt_ctime = 10; /* char time */ +int32 lpt_ctime = 1000; /* char time */ int32 lpt_stopioe = 0; /* stop on error */ +int32 lpt_lcnt = 0; /* line count */ +static int32 lpt_cct[8] = { + 1, 1, 1, 2, 3, LPT_PAGELNT/2, LPT_PAGELNT/4, LPT_PAGELNT/6 }; +DEVICE lpt_dev; int32 lptio (int32 inst, int32 IR, int32 dat); t_stat lpt_svc (UNIT *uptr); t_stat lpt_reset (DEVICE *dptr); +t_stat lpt_attach (UNIT *uptr, char *cptr); /* LPT data structures @@ -54,7 +62,7 @@ t_stat lpt_reset (DEVICE *dptr); lpt_reg LPT register list */ -DIB lpt_dib = { LPT, 1, 0, 0, 0, 0, &lptio }; +DIB lpt_dib = { LPT, 0, 0, 0, 0, &lptio }; UNIT lpt_unit = { UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; @@ -65,28 +73,25 @@ REG lpt_reg[] = { { FLDATA (CTL, lpt_dib.ctl, 0) }, { FLDATA (FLG, lpt_dib.flg, 0) }, { FLDATA (FBF, lpt_dib.fbf, 0) }, + { DRDATA (LCNT, lpt_lcnt, 7) }, { DRDATA (POS, lpt_unit.pos, 32), PV_LEFT }, { DRDATA (CTIME, lpt_ctime, 31), PV_LEFT }, { DRDATA (PTIME, lpt_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, lpt_stopioe, 0) }, { ORDATA (DEVNO, lpt_dib.devno, 6), REG_HRO }, - { FLDATA (*DEVENB, lpt_dib.enb, 0), REG_HRO }, { NULL } }; MTAB lpt_mod[] = { - { MTAB_XTD | MTAB_VDV, 0, NULL, "ENABLED", - &set_enb, NULL, &lpt_dib }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "DISABLED", - &set_dis, NULL, &lpt_dib }, { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &lpt_dib }, + &hp_setdev, &hp_showdev, &lpt_dev }, { 0 } }; DEVICE lpt_dev = { "LPT", &lpt_unit, lpt_reg, lpt_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &lpt_reset, - NULL, NULL, NULL }; + NULL, &lpt_attach, NULL, + &lpt_dib, DEV_DISABLE }; /* Line printer IOT routine */ @@ -94,10 +99,10 @@ int32 lptio (int32 inst, int32 IR, int32 dat) { int32 dev; -dev = IR & DEVMASK; /* get device no */ +dev = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & HC) == 0) { setFLG (dev); } /* STF */ + if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; @@ -106,43 +111,64 @@ case ioSFS: /* skip flag set */ if (FLG (dev) != 0) PC = (PC + 1) & VAMASK; return dat; case ioOTX: /* output */ - lpt_unit.buf = dat & 0177; + lpt_unit.buf = dat & (LPT_CTL | 0177); break; case ioLIX: /* load */ dat = 0; /* default sta = 0 */ case ioMIX: /* merge */ - if ((lpt_unit.flags & UNIT_ATT) == 0) dat = dat | LPT_BUSY | LPT_NRDY; - else if (sim_is_active (&lpt_unit)) dat = dat | LPT_BUSY; + if (lpt_unit.flags & UNIT_ATT) { + dat = dat | LPT_RDY; + if (!sim_is_active (&lpt_unit)) + dat = dat | LPT_NBSY; } + else dat = dat | LPT_PAPO; break; case ioCTL: /* control clear/set */ - if (IR & AB) { /* CLC */ + if (IR & I_CTL) { /* CLC */ clrCMD (dev); /* clear ctl, cmd */ clrCTL (dev); } else { setCMD (dev); /* STC */ setCTL (dev); /* set ctl, cmd */ sim_activate (&lpt_unit, /* schedule op */ - (lpt_unit.buf < 040)? lpt_unit.wait: lpt_ctime); } + (lpt_unit.buf & LPT_CTL)? lpt_unit.wait: lpt_ctime); } break; default: break; } -if (IR & HC) { clrFLG (dev); } /* H/C option */ +if (IR & I_HC) { clrFLG (dev); } /* H/C option */ return dat; } t_stat lpt_svc (UNIT *uptr) { -int32 dev; +int32 i, skip, chan, dev; dev = lpt_dib.devno; /* get dev no */ clrCMD (dev); /* clear cmd */ -if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */ +if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ return IORETURN (lpt_stopioe, SCPE_UNATT); setFLG (dev); /* set flag, fbf */ -if (putc (lpt_unit.buf & 0177, lpt_unit.fileref) == EOF) { +if (uptr->buf & LPT_CTL) { /* control word? */ + if (uptr->buf & LPT_CHAN) { + chan = uptr->buf & LPT_CHANM; + if (chan == 0) { /* top of form? */ + fputc ('\f', uptr->fileref); /* ffeed */ + lpt_lcnt = 0; /* reset line cnt */ + skip = 1; } + else if (chan == 1) skip = LPT_PAGELNT - lpt_lcnt - 1; + else skip = lpt_cct[chan] - (lpt_lcnt % lpt_cct[chan]); + } + else { + skip = uptr->buf & LPT_SKIPM; + if (skip == 0) fputc ('\r', uptr->fileref); + } + for (i = 0; i < skip; i++) fputc ('\n', uptr->fileref); + lpt_lcnt = (lpt_lcnt + skip) % LPT_PAGELNT; + } +else fputc (uptr->buf & 0177, uptr->fileref); /* no, just add char */ +if (ferror (uptr->fileref)) { perror ("LPT I/O error"); - clearerr (lpt_unit.fileref); + clearerr (uptr->fileref); return SCPE_IOERR; } -lpt_unit.pos = ftell (lpt_unit.fileref); /* update pos */ +lpt_unit.pos = ftell (uptr->fileref); /* update pos */ return SCPE_OK; } @@ -156,3 +182,11 @@ lpt_unit.buf = 0; sim_cancel (&lpt_unit); /* deactivate unit */ return SCPE_OK; } + +/* Attach routine */ + +t_stat lpt_attach (UNIT *uptr, char *cptr) +{ +lpt_lcnt = 0; /* top of form */ +return attach_unit (uptr, cptr); +} diff --git a/HP2100/hp2100_ms.c b/HP2100/hp2100_ms.c index 9160f499..976499d7 100644 --- a/HP2100/hp2100_ms.c +++ b/HP2100/hp2100_ms.c @@ -1,4 +1,4 @@ -/* hp2100_ms.c: HP 2100 13181A magnetic tape simulator +/* hp2100_ms.c: HP 2100 13181A/13183A magnetic tape simulator Copyright (c) 1993-2002, Robert M. Supnik @@ -23,8 +23,12 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - ms 13181A nine track magnetic tape + ms 13181A 7970B 800bpi nine track magnetic tape + 13183A 7970E 1600bpi nine track magnetic tape + 18-Oct-02 RMS Added BOOT command, added 13183A support + 30-Sep-02 RMS Revamped error handling + 29-Aug-02 RMS Added end of medium support 30-May-02 RMS Widened POS to 32b 22-Apr-02 RMS Added maximum record length test @@ -50,7 +54,9 @@ #define MS_NUMDR 4 /* number of drives */ #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_V_PNU (UNIT_V_UF + 1) /* pos not updated */ #define UNIT_WLK (1 << UNIT_V_WLK) +#define UNIT_PNU (1 << UNIT_V_PNU) #define DB_N_SIZE 16 /* max data buf */ #define DBSIZE (1 << DB_N_SIZE) /* max data cmd */ #define DBMASK (DBSIZE - 1) @@ -60,66 +66,87 @@ /* Command - msc_fnc */ -#define FNC_CLR 0110 /* clear */ -#define FNC_GAP 0015 /* write gap */ -#define FNC_GFM 0215 /* gap+file mark */ -#define FNC_RC 0023 /* read */ -#define FNC_WC 0031 /* write */ -#define FNC_FSR 0003 /* forward space */ -#define FNC_BSR 0041 /* backward space */ -#define FNC_FSF 0203 /* forward file */ -#define FNC_BSF 0241 /* backward file */ -#define FNC_REW 0101 /* rewind */ -#define FNC_RWS 0105 /* rewind and offline */ -#define FNC_WFM 0211 /* write file mark */ -#define FNC_CHS 0400 /* change select */ +#define FNC_CLR 00110 /* clear */ +#define FNC_GAP 00015 /* write gap */ +#define FNC_GFM 00215 /* gap+file mark */ +#define FNC_RC 00023 /* read */ +#define FNC_WC 00031 /* write */ +#define FNC_FSR 00003 /* forward space */ +#define FNC_BSR 00041 /* backward space */ +#define FNC_FSF 00203 /* forward file */ +#define FNC_BSF 00241 /* backward file */ +#define FNC_REW 00101 /* rewind */ +#define FNC_RWS 00105 /* rewind and offline */ +#define FNC_WFM 00211 /* write file mark */ +#define FNC_RFF 00223 /* "read file fwd" */ #define FNC_V_SEL 9 /* select */ #define FNC_M_SEL 017 #define FNC_GETSEL(x) (((x) >> FNC_V_SEL) & FNC_M_SEL) -#define FNF_MOT 0001 /* motion */ -#define FNF_OFL 0004 -#define FNF_WRT 0010 /* write */ -#define FNF_REV 0040 /* reverse */ -#define FNF_RWD 0100 /* rewind */ +#define FNF_MOT 00001 /* motion */ +#define FNF_OFL 00004 +#define FNF_WRT 00010 /* write */ +#define FNF_REV 00040 /* reverse */ +#define FNF_RWD 00100 /* rewind */ +#define FNF_CHS 00400 /* change select */ /* Status - stored in msc_sta, unit.UST (u), or dynamic (d) */ -#define STA_ODD 04000 /* odd bytes */ -#define STA_REW 02000 /* rewinding (u) */ -#define STA_TBSY 01000 /* transport busy (d) */ -#define STA_BUSY 00400 /* ctrl busy */ -#define STA_EOF 00200 /* end of file */ -#define STA_BOT 00100 /* beg of tape (d) */ -#define STA_EOT 00040 /* end of tape (u) */ -#define STA_TIM 00020 /* timing error */ -#define STA_REJ 00010 /* programming error */ -#define STA_WLK 00004 /* write locked (d) */ -#define STA_PAR 00002 /* parity error */ -#define STA_LOCAL 00001 /* local (d) */ -#define STA_STATIC (STA_ODD|STA_BUSY|STA_EOF|STA_TIM|STA_REJ|STA_PAR) +#define STA_PE 0100000 /* 1600 bpi (d) */ +#define STA_V_SEL 13 /* unit sel (d) */ +#define STA_M_SEL 03 +#define STA_SEL (STA_M_SEL << STA_V_SEL) +#define STA_ODD 0004000 /* odd bytes */ +#define STA_REW 0002000 /* rewinding (u) */ +#define STA_TBSY 0001000 /* transport busy (d) */ +#define STA_BUSY 0000400 /* ctrl busy */ +#define STA_EOF 0000200 /* end of file */ +#define STA_BOT 0000100 /* beg of tape (u) */ +#define STA_EOT 0000040 /* end of tape (u) */ +#define STA_TIM 0000020 /* timing error */ +#define STA_REJ 0000010 /* programming error */ +#define STA_WLK 0000004 /* write locked (d) */ +#define STA_PAR 0000002 /* parity error */ +#define STA_LOCAL 0000001 /* local (d) */ +#define STA_DYN (STA_PE|STA_SEL|STA_TBSY|STA_WLK|STA_LOCAL) -extern int32 PC; +extern uint16 *M; +extern int32 PC, SR; extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; +extern int32 sim_switches; +extern UNIT cpu_unit; + +int32 ms_ctype = 0; /* ctrl type */ int32 msc_sta = 0; /* status */ int32 msc_buf = 0; /* buffer */ int32 msc_usl = 0; /* unit select */ int32 msc_1st = 0; int32 msc_ctime = 1000; /* command wait */ -int32 msc_xtime = 10; /* data xfer time */ +int32 msc_gtime = 1000; /* gap stop time */ +int32 msc_rtime = 1000; /* rewind wait */ +int32 msc_xtime = 15; /* data xfer time */ int32 msc_stopioe = 1; /* stop on error */ int32 msd_buf = 0; /* data buffer */ uint8 msxb[DBSIZE] = { 0 }; /* data buffer */ t_mtrlnt ms_ptr = 0, ms_max = 0; /* buffer ptrs */ +DEVICE msd_dev, msc_dev; int32 msdio (int32 inst, int32 IR, int32 dat); int32 mscio (int32 inst, int32 IR, int32 dat); t_stat msc_svc (UNIT *uptr); t_stat msc_reset (DEVICE *dptr); +t_stat msc_attach (UNIT *uptr, char *cptr); +t_stat msc_detach (UNIT *uptr); +t_stat msc_boot (int32 unitno, DEVICE *dptr); t_stat msc_vlock (UNIT *uptr, int32 val, char *cptr, void *desc); +t_bool ms_rdlntf (UNIT *uptr, t_mtrlnt *tbc, int32 *err); +t_bool ms_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err); t_bool ms_forwsp (UNIT *uptr, int32 *err); t_bool ms_backsp (UNIT *uptr, int32 *err); - +int32 ms_wrtrec (UNIT *uptr, t_mtrlnt lnt); +t_stat ms_settype (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat ms_showtype (FILE *st, UNIT *uptr, int32 val, void *desc); + /* MSD data structures msd_dev MSD device descriptor @@ -128,8 +155,8 @@ t_bool ms_backsp (UNIT *uptr, int32 *err); */ DIB ms_dib[] = { - { MSD, 1, 0, 0, 0, 0, &msdio }, - { MSC, 1, 0, 0, 0, 0, &mscio } }; + { MSD, 0, 0, 0, 0, &msdio }, + { MSC, 0, 0, 0, 0, &mscio } }; #define msd_dib ms_dib[0] #define msc_dib ms_dib[1] @@ -146,19 +173,19 @@ REG msd_reg[] = { { DRDATA (BPTR, ms_ptr, DB_N_SIZE + 1) }, { DRDATA (BMAX, ms_max, DB_N_SIZE + 1) }, { ORDATA (DEVNO, msd_dib.devno, 6), REG_HRO }, - { FLDATA (*DEVENB, msd_dib.enb, 0), REG_HRO }, { NULL } }; MTAB msd_mod[] = { { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &msd_dib }, + &hp_setdev, &hp_showdev, &msd_dev }, { 0 } }; DEVICE msd_dev = { "MSD", &msd_unit, msd_reg, msd_mod, 1, 10, DB_N_SIZE, 1, 8, 8, NULL, NULL, &msc_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &msd_dib, 0 }; /* MSC data structures @@ -183,33 +210,37 @@ REG msc_reg[] = { { FLDATA (CTL, msc_dib.ctl, 0) }, { FLDATA (FLG, msc_dib.flg, 0) }, { FLDATA (FBF, msc_dib.fbf, 0) }, - { URDATA (POS, msc_unit[0].pos, 8, 32, 0, MS_NUMDR, PV_LEFT) }, - { URDATA (FNC, msc_unit[0].FNC, 8, 12, 0, MS_NUMDR, REG_HRO) }, + { URDATA (POS, msc_unit[0].pos, 10, 32, 0, MS_NUMDR, PV_LEFT) }, + { URDATA (FNC, msc_unit[0].FNC, 8, 8, 0, MS_NUMDR, REG_HRO) }, { URDATA (UST, msc_unit[0].UST, 8, 12, 0, MS_NUMDR, REG_HRO) }, { DRDATA (CTIME, msc_ctime, 24), REG_NZ + PV_LEFT }, + { DRDATA (GTIME, msc_gtime, 24), REG_NZ + PV_LEFT }, + { DRDATA (RTIME, msc_rtime, 24), REG_NZ + PV_LEFT }, { DRDATA (XTIME, msc_xtime, 24), REG_NZ + PV_LEFT }, { FLDATA (STOP_IOE, msc_stopioe, 0) }, - { URDATA (WLK, msc_unit[0].flags, 8, 1, UNIT_V_WLK, MS_NUMDR, REG_HRO) }, + { FLDATA (CTYPE, ms_ctype, 0), REG_HRO }, { ORDATA (DEVNO, msc_dib.devno, 6), REG_HRO }, - { FLDATA (*DEVENB, msc_dib.enb, 0), REG_HRO }, { NULL } }; MTAB msc_mod[] = { { UNIT_WLK, 0, "write enabled", "WRITEENABLED", &msc_vlock }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &msc_vlock }, - { MTAB_XTD | MTAB_VDV, 1, NULL, "ENABLED", - &set_enb, NULL, &msd_dib }, - { MTAB_XTD | MTAB_VDV, 1, NULL, "DISABLED", - &set_dis, NULL, &msd_dib }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "13181A", + &ms_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "13183A", + &ms_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, + NULL, &ms_showtype, NULL }, { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &msd_dib }, + &hp_setdev, &hp_showdev, &msd_dev }, { 0 } }; DEVICE msc_dev = { "MSC", msc_unit, msc_reg, msc_mod, MS_NUMDR, 10, 31, 1, 8, 8, NULL, NULL, &msc_reset, - NULL, NULL, NULL }; + &msc_boot, &msc_attach, &msc_detach, + &msc_dib, DEV_DISABLE }; /* IOT routines */ @@ -217,10 +248,10 @@ int32 msdio (int32 inst, int32 IR, int32 dat) { int32 devd; -devd = IR & DEVMASK; /* get device no */ +devd = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & HC) == 0) { setFLG (devd); } /* STF */ + if ((IR & I_HC) == 0) { setFLG (devd); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (devd) == 0) PC = (PC + 1) & VAMASK; @@ -238,15 +269,16 @@ case ioLIX: /* load */ dat = msd_buf; break; case ioCTL: /* control clear/set */ - if (IR & AB) { /* CLC */ - clrCTL (devd); /* clr ctl, cmd */ - clrCMD (devd); } - else { setCTL (devd); /* STC */ - setCMD (devd); } /* set ctl, cmd */ + if (IR & I_CTL) { /* CLC */ + clrCTL (devd); /* clr ctl, cmd */ + clrCMD (devd); } + else { /* STC */ + setCTL (devd); /* set ctl, cmd */ + setCMD (devd); } break; default: break; } -if (IR & HC) { clrFLG (devd); } /* H/C option */ +if (IR & I_HC) { clrFLG (devd); } /* H/C option */ return dat; } @@ -258,11 +290,11 @@ static const uint8 map_sel[16] = { 0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3 }; -devc = IR & DEVMASK; /* get device no */ +devc = IR & I_DEVMASK; /* get device no */ devd = devc - 1; switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & HC) == 0) { setFLG (devc); } /* STF */ + if ((IR & I_HC) == 0) { setFLG (devc); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (devc) == 0) PC = (PC + 1) & VAMASK; @@ -271,57 +303,61 @@ case ioSFS: /* skip flag set */ if (FLG (devc) != 0) PC = (PC + 1) & VAMASK; return dat; case ioOTX: /* output */ - msc_buf = dat = dat & 07777; - if (dat == FNC_CLR) { /* clear? */ - for (i = 0; i < MS_NUMDR; i++) { - if ((msc_unit[i].UST & STA_REW) == 0) - sim_cancel (&msc_unit[i]); } - clrCTL (devc); /* init device */ - clrFLG (devc); - clrCTL (devd); - clrFLG (devd); - msc_sta = msd_buf = msc_buf = msc_1st = 0; - break; } - if (msc_sta & STA_BUSY) { - msc_sta = msc_sta | STA_REJ; - break; } - if (dat & FNC_CHS) { - msc_usl = map_sel[FNC_GETSEL (dat)]; - uptr = msc_dev.units + msc_usl; } + msc_buf = dat; + msc_sta = msc_sta & ~STA_REJ; /* clear reject */ + if ((dat & 0377) == FNC_CLR) break; /* clear always ok */ + if (msc_sta & STA_BUSY) { /* busy? reject */ + msc_sta = msc_sta | STA_REJ; /* dont chg select */ + break; } + if (dat & FNF_CHS) { /* select change */ + msc_usl = map_sel[FNC_GETSEL (dat)]; /* is immediate */ + uptr = msc_dev.units + msc_usl; } if (((dat & FNF_MOT) && sim_is_active (uptr)) || - ((dat & FNF_REV) && (uptr -> pos == 0)) || - ((dat & FNF_WRT) && (uptr -> flags & UNIT_WPRT))) - msc_sta = msc_sta | STA_REJ; + ((dat & FNF_REV) && (uptr->UST & STA_BOT)) || + ((dat & FNF_WRT) && (uptr->flags & UNIT_WPRT))) + msc_sta = msc_sta | STA_REJ; /* reject? */ break; case ioLIX: /* load */ dat = 0; case ioMIX: /* merge */ - msc_sta = (msc_sta & STA_STATIC) | uptr -> UST; - if (uptr -> flags & UNIT_ATT) { - msc_sta = msc_sta & ~(STA_LOCAL | STA_WLK | STA_TBSY); - if (sim_is_active (uptr)) - msc_sta = msc_sta | STA_TBSY; - if (uptr -> flags & UNIT_WPRT) - msc_sta = msc_sta | STA_WLK; } - else msc_sta = msc_sta | STA_TBSY | STA_LOCAL; - dat = dat | msc_sta; + dat = dat | ((msc_sta | uptr->UST) & ~STA_DYN); + if (uptr->flags & UNIT_ATT) { /* online? */ + if (sim_is_active (uptr)) /* busy */ + dat = dat | STA_TBSY; + if (uptr->flags & UNIT_WPRT) /* write prot? */ + dat = dat | STA_WLK; } + else dat = dat | STA_TBSY | STA_LOCAL; + if (ms_ctype) dat = dat | STA_PE | /* 13183A? */ + (msc_usl << STA_V_SEL); break; case ioCTL: /* control clear/set */ - if (IR & AB) { clrCTL (devc); } /* CLC */ - else if (!CTL (devc)) { /* STC, not busy? */ - uptr -> FNC = msc_buf; /* save function */ - if (uptr -> FNC & FNF_RWD) { - uptr -> UST = STA_REW; - sim_activate (uptr, msc_xtime); } - else { uptr -> UST = 0; /* clr unit status */ - sim_activate (uptr, msc_ctime); } - msc_sta = STA_BUSY; - msc_1st = 1; - setCTL (devc); } + if (IR & I_CTL) { clrCTL (devc); } /* CLC */ + else { /* STC */ + if ((msc_buf & 0377) == FNC_CLR) { /* clear? */ + for (i = 0; i < MS_NUMDR; i++) { /* loop thru units */ + if (sim_is_active (&msc_unit[i]) && /* write in prog? */ + (msc_unit[i].FNC == FNC_WC) && (ms_ptr > 0)) + ms_wrtrec (uptr, ms_ptr | MTR_ERF); + if ((msc_unit[i].UST & STA_REW) == 0) + sim_cancel (&msc_unit[i]); } /* stop if now rew */ + clrCTL (devc); /* init device */ + setFLG (devc); + clrCTL (devd); + setFLG (devd); + msc_sta = msd_buf = msc_buf = msc_1st = 0; + return SCPE_OK; } + uptr->FNC = msc_buf & 0377; /* save function */ + if (uptr->FNC & FNF_RWD) /* rewind? */ + sim_activate (uptr, msc_rtime); /* fast response */ + else sim_activate (uptr, msc_ctime); /* schedule op */ + uptr->UST = 0; /* clear status */ + msc_sta = STA_BUSY; /* ctrl is busy */ + msc_1st = 1; + setCTL (devc); } /* go */ break; default: break; } -if (IR & HC) { clrFLG (devc); } /* H/C option */ +if (IR & I_HC) { clrFLG (devc); } /* H/C option */ return dat; } @@ -335,128 +371,182 @@ return dat; t_stat msc_svc (UNIT *uptr) { -int32 devc, devd, err, i; -static t_mtrlnt bceof = { 0 }; +int32 devc, devd, err, pnu; +static t_mtrlnt i, bceof = { MTR_TMK }; -if ((uptr -> flags & UNIT_ATT) == 0) { /* offline? */ - msc_sta = STA_LOCAL | STA_BUSY | STA_REJ; - return IORETURN (msc_stopioe, SCPE_UNATT); } +err = 0; /* assume no errors */ devc = msc_dib.devno; /* get device nos */ devd = msd_dib.devno; -if (uptr -> UST & STA_REW) { /* rewinding? */ - if (msc_sta & STA_BUSY) { /* controller busy? */ - sim_activate (uptr, msc_ctime); /* do real rewind */ - setFLG (devc); /* set cch flg */ - msc_sta = msc_sta & ~STA_BUSY; } /* update status */ - else { uptr -> pos = 0; /* rewind done */ - uptr -> UST = 0; /* offline? */ - if (uptr -> FNC & FNF_OFL) detach_unit (uptr); } - return SCPE_OK; } +if ((uptr->flags & UNIT_ATT) == 0) { /* offline? */ + msc_sta = (msc_sta | STA_REJ) & ~STA_BUSY; /* reject */ + setFLG (devc); /* set cch flg */ + return IORETURN (msc_stopioe, SCPE_UNATT); } + +pnu = MT_TST_PNU (uptr); /* get pos not upd */ +MT_CLR_PNU (uptr); /* and clear */ + +switch (uptr->FNC) { /* case on function */ +case FNC_REW: /* rewind */ +case FNC_RWS: /* rewind offline */ + if (uptr->UST & STA_REW) { /* rewind in prog? */ + uptr->pos = 0; /* done */ + uptr->UST = STA_BOT; /* set BOT status */ + if (uptr->FNC & FNF_OFL) detach_unit (uptr); + return SCPE_OK; } + uptr->UST = STA_REW; /* set rewinding */ + sim_activate (uptr, msc_ctime); /* sched completion */ + break; /* "done" */ -err = 0; /* assume no errors */ -switch (uptr -> FNC & 07777) { /* case on function */ case FNC_GFM: /* gap file mark */ case FNC_WFM: /* write file mark */ - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); - fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr -> fileref); - err = ferror (uptr -> fileref); - uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); /* update tape pos */ - msc_sta = msc_sta | STA_EOF; /* set EOF status */ + fseek (uptr->fileref, uptr->pos, SEEK_SET); + fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr->fileref); + msc_sta = STA_EOF; /* set EOF status */ + if (err = ferror (uptr->fileref)) MT_SET_PNU (uptr); + else uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* update tape pos */ + break; + case FNC_GAP: /* erase gap */ break; case FNC_FSF: while (ms_forwsp (uptr, &err)) ; /* spc until EOF/EOT */ break; + case FNC_FSR: /* space forward */ ms_forwsp (uptr, &err); break; + case FNC_BSF: - while (ms_backsp (uptr, &err)) ; /* spc until EOF/EOT */ + while (ms_backsp (uptr, &err)) ; /* spc until EOF/BOT */ break; + case FNC_BSR: /* space reverse */ - ms_backsp (uptr, &err); + if (!pnu) { /* position ok? */ + ms_backsp (uptr, &err); /* backspace */ + if (msc_sta & STA_ODD) msc_sta = msc_sta | STA_PAR; } break; /* Unit service, continued */ +case FNC_RFF: /* diagnostic read */ case FNC_RC: /* read */ if (msc_1st) { /* first svc? */ - msc_1st = ms_ptr = 0; /* clr 1st flop */ - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); - fxread (&ms_max, sizeof (t_mtrlnt), 1, uptr -> fileref); - if ((err = ferror (uptr -> fileref)) || - feof (uptr -> fileref)) { /* error or eof? */ - uptr -> UST = STA_EOT; - break; } - if (ms_max == 0) { /* tape mark? */ - uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); - msc_sta = msc_sta | STA_EOF; - break; } - ms_max = MTRL (ms_max); /* ignore errors */ - uptr -> pos = uptr -> pos + ((ms_max + 1) & ~1) + - (2 * sizeof (t_mtrlnt)); /* update position */ - if (ms_max > DBSIZE) return SCPE_MTRLNT;/* record too long? */ - i = fxread (msxb, sizeof (int8), ms_max, uptr -> fileref); - for ( ; i < ms_max; i++) msxb[i] = 0; /* fill with 0's */ - err = ferror (uptr -> fileref); } + msc_1st = ms_ptr = 0; /* clr 1st flop */ + if (ms_rdlntf (uptr, &ms_max, &err)) { /* read rec lnt */ + if (!err) { /* tmk or eom? */ + sim_activate (uptr, msc_gtime); /* sched IRG */ + uptr->FNC = 0; /* NOP func */ + return SCPE_OK; } + break; } /* err, done */ + if (ms_max > DBSIZE) return SCPE_MTRLNT; /* record too long? */ + i = fxread (msxb, sizeof (int8), ms_max, uptr->fileref); + if (err = ferror (uptr->fileref)) { /* error? */ + msc_sta = msc_sta | STA_PAR; /* set flag */ + MT_SET_PNU (uptr); /* pos not upd */ + break; } + for ( ; i < ms_max; i++) msxb[i] = 0; /* fill with 0's */ + uptr->pos = uptr->pos + ((ms_max + 1) & ~1) + + (2 * sizeof (t_mtrlnt)); } /* update position */ if (ms_ptr < ms_max) { /* more chars? */ - if (FLG (devd)) msc_sta = msc_sta | STA_TIM; - msd_buf = ((uint16) msxb[ms_ptr] << 8) | - msxb[ms_ptr + 1]; - ms_ptr = ms_ptr + 2; - setFLG (devd); /* set dch flg */ - sim_activate (uptr, msc_xtime); /* re-activate */ - return SCPE_OK; } - if (ms_max & 1) msc_sta = msc_sta | STA_ODD; - break; + if (FLG (devd)) msc_sta = msc_sta | STA_TIM | STA_PAR; + msd_buf = ((uint16) msxb[ms_ptr] << 8) | msxb[ms_ptr + 1]; + ms_ptr = ms_ptr + 2; + setFLG (devd); /* set dch flg */ + sim_activate (uptr, msc_xtime); /* re-activate */ + return SCPE_OK; } + sim_activate (uptr, msc_gtime); /* sched IRG */ + if (uptr->FNC == FNC_RFF) msc_1st = 1; /* diagnostic? */ + else uptr->FNC = 0; /* NOP func */ + return SCPE_OK; + case FNC_WC: /* write */ - if (msc_1st) msc_1st = ms_ptr = 0; - else { if (ms_ptr < DBSIZE) { /* room in buffer? */ - msxb[ms_ptr] = msd_buf >> 8; - msxb[ms_ptr + 1] = msd_buf & 0377; - ms_ptr = ms_ptr + 2; } - else msc_sta = msc_sta | STA_PAR; } + if (msc_1st) msc_1st = ms_ptr = 0; /* no xfer on first */ + else { /* not 1st, next char */ + if (ms_ptr < DBSIZE) { /* room in buffer? */ + msxb[ms_ptr] = msd_buf >> 8; /* store 2 char */ + msxb[ms_ptr + 1] = msd_buf & 0377; + ms_ptr = ms_ptr + 2; + uptr->UST = 0; } + else msc_sta = msc_sta | STA_PAR; } if (CTL (devd)) { /* xfer flop set? */ - setFLG (devd); /* set dch flag */ - sim_activate (uptr, msc_xtime); /* re-activate */ - return SCPE_OK; } - if (ms_ptr) { /* write buffer */ - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); - fxwrite (&ms_ptr, sizeof (t_mtrlnt), 1, uptr -> fileref); - fxwrite (msxb, sizeof (int8), ms_ptr, uptr -> fileref); - fxwrite (&ms_ptr, sizeof (t_mtrlnt), 1, uptr -> fileref); - err = ferror (uptr -> fileref); - uptr -> pos = uptr -> pos + ((ms_ptr + 1) & ~1) + - (2 * sizeof (t_mtrlnt)); } + setFLG (devd); /* set dch flag */ + sim_activate (uptr, msc_xtime); /* re-activate */ + return SCPE_OK; } + if (ms_ptr) { /* any data? write */ + if (err = ms_wrtrec (uptr, ms_ptr)) break; } + sim_activate (uptr, msc_gtime); /* sched IRG */ + uptr->FNC = 0; /* NOP func */ + return SCPE_OK; + +default: /* unknown */ break; } - -/* Unit service, continued */ setFLG (devc); /* set cch flg */ msc_sta = msc_sta & ~STA_BUSY; /* update status */ if (err != 0) { /* I/O error */ perror ("MT I/O error"); - clearerr (uptr -> fileref); - IORETURN (msc_stopioe, SCPE_IOERR); } + clearerr (uptr->fileref); + if (msc_stopioe) return SCPE_IOERR; } return SCPE_OK; } + +/* Tape motion routines */ + +t_bool ms_rdlntf (UNIT *uptr, t_mtrlnt *tbc, int32 *err) +{ +fseek (uptr->fileref, uptr->pos, SEEK_SET); /* position */ +fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); /* get bc */ +if ((*err = ferror (uptr->fileref)) || /* error or eom? */ + feof (uptr->fileref) || (*tbc == MTR_EOM)) { + msc_sta = msc_sta | STA_PAR; /* error */ + MT_SET_PNU (uptr); /* pos not upd */ + return TRUE; } +if (*tbc == MTR_TMK) { /* tape mark? */ + uptr->pos = uptr->pos + sizeof (t_mtrlnt); + msc_sta = msc_sta | STA_EOF | STA_ODD; /* eof (also sets odd) */ + return TRUE; } +if (MTRF (*tbc)) msc_sta = msc_sta | STA_PAR; /* error in rec? */ +*tbc = MTRL (*tbc); /* clear err flag */ +if (*tbc & 1) msc_sta = msc_sta | STA_ODD; +else msc_sta = msc_sta & ~STA_ODD; +return FALSE; +} + +t_bool ms_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err) +{ +if (uptr->pos < sizeof (t_mtrlnt)) { /* at bot? */ + uptr->UST = STA_BOT; /* set status */ + return TRUE; } /* error */ +fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt), SEEK_SET); +fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); /* get bc */ +if ((*err = ferror (uptr->fileref)) || /* error or eof? */ + feof (uptr->fileref)) { + msc_sta = msc_sta | STA_PAR; /* error */ + return TRUE; } +if (*tbc == MTR_EOM) { /* eom? */ + msc_sta = msc_sta | STA_PAR; /* error */ + uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over eom */ + return TRUE; } +if (*tbc == MTR_TMK) { /* tape mark? */ + msc_sta = msc_sta | STA_EOF; /* eof */ + uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over tmk */ + return TRUE; } +if (MTRF (*tbc)) msc_sta = msc_sta | STA_PAR; /* error in rec? */ +*tbc = MTRL (*tbc); /* clear err flag */ +if (*tbc & 1) msc_sta = msc_sta | STA_ODD; +else msc_sta = msc_sta & ~STA_ODD; +return FALSE; +} t_bool ms_forwsp (UNIT *uptr, int32 *err) { t_mtrlnt tbc; -fseek (uptr -> fileref, uptr -> pos, SEEK_SET); /* position */ -fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); /* get bc */ -if ((*err = ferror (uptr -> fileref)) || feof (uptr -> fileref)) { - uptr -> UST = STA_EOT; - return FALSE; } -if (tbc == 0) { /* zero bc? */ - uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); - msc_sta = msc_sta | STA_EOF; /* eof */ - return FALSE; } -uptr -> pos = uptr -> pos + ((MTRL (tbc) + 1) & ~1) + (2 * sizeof (t_mtrlnt)); +if (ms_rdlntf (uptr, &tbc, err)) return FALSE; /* read rec lnt, err? */ +uptr->pos = uptr->pos + ((tbc + 1) & ~1) + /* incr tape position */ + (2 * sizeof (t_mtrlnt)); return TRUE; } @@ -464,20 +554,26 @@ t_bool ms_backsp (UNIT *uptr, int32 *err) { t_mtrlnt tbc; -if (uptr -> pos == 0) return FALSE; /* at bot? */ -fseek (uptr -> fileref, uptr -> pos - sizeof (t_mtrlnt), SEEK_SET); -fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); /* get bc */ -if ((*err = ferror (uptr -> fileref)) || feof (uptr -> fileref)) { - uptr -> UST = STA_EOT; - uptr -> pos = 0; - return FALSE; } -if (tbc == 0) { /* zero bc? */ - uptr -> pos = uptr -> pos - sizeof (t_mtrlnt); - msc_sta = msc_sta | STA_EOF; /* eof */ - return FALSE; } -uptr -> pos = uptr -> pos - ((MTRL (tbc) + 1) & ~1) - (2 * sizeof (t_mtrlnt)); +if (ms_rdlntr (uptr, &tbc, err)) return FALSE; /* read rec lnt, err? */ +uptr->pos = uptr->pos - ((MTRL (tbc) + 1) & ~1) - /* decr tape position */ + (2 * sizeof (t_mtrlnt)); return TRUE; } + +int32 ms_wrtrec (UNIT *uptr, t_mtrlnt lnt) +{ +int32 elnt = MTRL ((lnt + 1) & ~1); /* even lnt, no err */ + +fseek (uptr->fileref, uptr->pos, SEEK_SET); /* seek to record */ +fxwrite (&lnt, sizeof (t_mtrlnt), 1, uptr->fileref); /* write rec lnt */ +fxwrite (msxb, sizeof (int8), elnt, uptr->fileref); /* write data */ +fxwrite (&lnt, sizeof (t_mtrlnt), 1, uptr->fileref); /* write rec lnt */ +if (ferror (uptr->fileref)) { /* error? */ + MT_SET_PNU (uptr); /* pos not updated */ + return 1; } +else uptr->pos = uptr->pos + elnt + (2 * sizeof (t_mtrlnt)); /* no, upd pos */ +return 0; +} /* Reset routine */ @@ -486,24 +582,156 @@ t_stat msc_reset (DEVICE *dptr) int32 i; UNIT *uptr; +hp_enbdis_pair (&msc_dev, &msd_dev); /* make pair cons */ msc_buf = msd_buf = 0; msc_sta = msc_usl = 0; msc_1st = 0; msc_dib.cmd = msd_dib.cmd = 0; /* clear cmd */ msc_dib.ctl = msd_dib.ctl = 0; /* clear ctl */ -msc_dib.flg = msd_dib.flg = 0; /* clear flg */ -msc_dib.fbf = msd_dib.fbf = 0; /* clear fbf */ +msc_dib.flg = msd_dib.flg = 1; /* set flg */ +msc_dib.fbf = msd_dib.fbf = 1; /* set fbf */ for (i = 0; i < MS_NUMDR; i++) { uptr = msc_dev.units + i; + MT_CLR_PNU (uptr); sim_cancel (uptr); - uptr -> UST = 0; } + uptr->UST = 0; } return SCPE_OK; } +/* Attach routine */ + +t_stat msc_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +r = attach_unit (uptr, cptr); /* attach unit */ +if (r != SCPE_OK) return r; /* update status */ +MT_CLR_PNU (uptr); +uptr->UST = STA_BOT; +return r; +} + +/* Detach routine */ + +t_stat msc_detach (UNIT* uptr) +{ +uptr->UST = 0; /* update status */ +MT_CLR_PNU (uptr); +return detach_unit (uptr); /* detach unit */ +} + /* Write lock/enable routine */ t_stat msc_vlock (UNIT *uptr, int32 val, char *cptr, void *desc) { -if (val && (uptr -> flags & UNIT_ATT)) return SCPE_ARG; +if (val && (uptr->flags & UNIT_ATT)) return SCPE_ARG; +return SCPE_OK; +} + +/* Set controller type */ + +t_stat ms_settype (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 i; + +if ((val < 0) || (val > 1) || (cptr != NULL)) return SCPE_ARG; +for (i = 0; i < MS_NUMDR; i++) { + if (msc_unit[i].flags & UNIT_ATT) return SCPE_ALATT; } +ms_ctype = val; +return SCPE_OK; +} + +/* Show controller type */ + +t_stat ms_showtype (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +if (ms_ctype) fprintf (st, "13183A"); +else fprintf (st, "13181A"); +return SCPE_OK; +} + +/* 7970B/7970E bootstrap routine (HP 12992D ROM) */ + +#define CHANGE_DEV (1 << 24) + +static const int32 mboot[IBL_LNT] = { + 0106501, /*ST LIB 1 ; read sw */ + 0006011, /* SLB,RSS ; bit 0 set? */ + 0027714, /* JMP RD ; no read */ + 0003004, /* CMA,INA ; A is ctr */ + 0073775, /* STA WC ; save */ + 0067772, /* LDA SL0RW ; sel 0, rew */ + 0017762, /*FF JSB CMD ; do cmd */ + 0102301+CHANGE_DEV, /* SFS CC ; done? */ + 0027707, /* JMP *-1 ; wait */ + 0067774, /* LDB FFC ; get file fwd */ + 0037775, /* ISZ WC ; done files? */ + 0027706, /* JMP FF ; no */ + 0067773, /*RD LDB RDCMD ; read cmd */ + 0017762, /* JSB CMD ; do cmd */ + 0103700+CHANGE_DEV, /* STC DC,C ; start dch */ + 0102201+CHANGE_DEV, /* SFC CC ; read done? */ + 0027752, /* JMP STAT ; no, get stat */ + 0102300+CHANGE_DEV, /* SFS DC ; any data? */ + 0027717, /* JMP *-3 ; wait */ + 0107500+CHANGE_DEV, /* LIB DC,C ; get rec cnt */ + 0005727, /* BLF,BLF ; move to lower */ + 0007000, /* CMB ; make neg */ + 0077775, /* STA WC ; save */ + 0102201+CHANGE_DEV, /* SFC CC ; read done? */ + 0027752, /* JMP STAT ; no, get stat */ + 0102300+CHANGE_DEV, /* SFS DC ; any data? */ + 0027727, /* JMP *-3 ; wait */ + 0107500+CHANGE_DEV, /* LIB DC,C ; get load addr */ + 0074000, /* STB 0 ; start csum */ + 0077762, /* STA CMD ; save address */ + 0027742, /* JMP *+4 */ + 0177762, /*NW STB CMD,I ; store data */ + 0040001, /* ADA 1 ; add to csum */ + 0037762, /* ISZ CMD ; adv addr ptr */ + 0102300+CHANGE_DEV, /* SFS DC ; any data? */ + 0027742, /* JMP *-1 ; wait */ + 0107500+CHANGE_DEV, /* LIB DC,C ; get word */ + 0037775, /* ISZ WC ; done? */ + 0027737, /* JMP NW ; no */ + 0054000, /* CPB 0 ; csum ok? */ + 0027717, /* JMP RD+3 ; yes, cont */ + 0102011, /* HLT 11 ; no, halt */ + 0102501+CHANGE_DEV, /*ST LIA CC ; get status */ + 0001727, /* ALF,ALF ; get eof bit */ + 0002020, /* SSA ; set? */ + 0102077, /* HLT 77 ; done */ + 0001727, /* ALF,ALF ; put status back */ + 0001310, /* RAR,SLA ; read ok? */ + 0102000, /* HLT 0 ; no */ + 0027714, /* JMP RD ; read next */ + 0000000, /*CMD 0 */ + 0106601+CHANGE_DEV, /* OTB CC ; output cmd */ + 0102501+CHANGE_DEV, /* LIA CC ; check for reject */ + 0001323, /* RAR,RAR */ + 0001310, /* RAR,SLA */ + 0027763, /* JMP CMD+1 ; try again */ + 0103701+CHANGE_DEV, /* STC CC,C ; start command */ + 0127762, /* JMP CMD,I ; exit */ + 0001501, /*SL0RW 001501 ; select 0, rewind */ + 0001423, /*RDCMD 001423 ; read record */ + 0000203, /*FFC 000203 ; space forward file */ + 0000000, /*WC 000000 */ + 0000000, + 0000000 }; + +t_stat msc_boot (int32 unitno, DEVICE *dptr) +{ +int32 i, dev; + +if (unitno != 0) return SCPE_NOFNC; /* only unit 0 */ +dev = msd_dib.devno; /* get data chan dev */ +PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */ +SR = IBL_MS + (dev << IBL_V_DEV); /* set SR */ +if ((sim_switches & SWMASK ('S')) && AR) SR = SR | 1; /* skip? */ +for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */ + if (mboot[i] & CHANGE_DEV) /* IO instr? */ + M[PC + i] = (mboot[i] + dev) & DMASK; + else M[PC + i] = mboot[i]; } return SCPE_OK; } diff --git a/HP2100/hp2100_mt.c b/HP2100/hp2100_mt.c index 9838902b..440765ca 100644 --- a/HP2100/hp2100_mt.c +++ b/HP2100/hp2100_mt.c @@ -23,8 +23,10 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - mt 12559A nine track magnetic tape + mt 12559A 3030 nine track magnetic tape + 30-Sep-02 RMS Revamped error handling + 28-Aug-02 RMS Added end of medium support 30-May-02 RMS Widened POS to 32b 22-Apr-02 RMS Added maximum record length test 20-Jan-02 RMS Fixed bug on last character write @@ -54,7 +56,9 @@ #include "hp2100_defs.h" #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_V_PNU (UNIT_V_UF + 1) /* pos not updated */ #define UNIT_WLK (1 << UNIT_V_WLK) +#define UNIT_PNU (1 << UNIT_V_PNU) #define DB_V_SIZE 16 /* max data buf */ #define DBSIZE (1 << DB_V_SIZE) /* max data cmd */ #define DBMASK (DBSIZE - 1) @@ -72,17 +76,17 @@ #define FNC_RWS 0101 /* rewind and offline */ #define FNC_WFM 0035 /* write file mark */ -/* Status - stored in mtc_sta */ +/* Status - stored in mtc_sta, (d) = dynamic */ -#define STA_LOCAL 0400 /* local */ +#define STA_LOCAL 0400 /* local (d) */ #define STA_EOF 0200 /* end of file */ #define STA_BOT 0100 /* beginning of tape */ #define STA_EOT 0040 /* end of tape */ #define STA_TIM 0020 /* timing error */ #define STA_REJ 0010 /* programming error */ -#define STA_WLK 0004 /* write locked */ +#define STA_WLK 0004 /* write locked (d) */ #define STA_PAR 0002 /* parity error */ -#define STA_BUSY 0001 /* busy */ +#define STA_BUSY 0001 /* busy (d) */ extern int32 PC; extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; @@ -91,13 +95,15 @@ int32 mtc_sta = 0; /* status register */ int32 mtc_dtf = 0; /* data xfer flop */ int32 mtc_1st = 0; /* first svc flop */ int32 mtc_ctime = 1000; /* command wait */ -int32 mtc_xtime = 10; /* data xfer time */ +int32 mtc_gtime = 1000; /* gap stop time */ +int32 mtc_xtime = 15; /* data xfer time */ int32 mtc_stopioe = 1; /* stop on error */ uint8 mtxb[DBSIZE] = { 0 }; /* data buffer */ t_mtrlnt mt_ptr = 0, mt_max = 0; /* buffer ptrs */ static const int32 mtc_cmd[] = { FNC_WC, FNC_RC, FNC_GAP, FNC_FSR, FNC_BSR, FNC_REW, FNC_RWS, FNC_WFM }; +DEVICE mtd_dev, mtc_dev; int32 mtdio (int32 inst, int32 IR, int32 dat); int32 mtcio (int32 inst, int32 IR, int32 dat); t_stat mtc_svc (UNIT *uptr); @@ -105,6 +111,9 @@ t_stat mtc_reset (DEVICE *dptr); t_stat mtc_vlock (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat mtc_attach (UNIT *uptr, char *cptr); t_stat mtc_detach (UNIT *uptr); +t_bool mt_rdlntf (UNIT *uptr, t_mtrlnt *tbc, int32 *err); +t_bool mt_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err); +int32 mt_wrtrec (UNIT *uptr, t_mtrlnt lnt); /* MTD data structures @@ -114,8 +123,8 @@ t_stat mtc_detach (UNIT *uptr); */ DIB mt_dib[] = { - { MTD, 1, 0, 0, 0, 0, &mtdio }, - { MTC, 1, 0, 0, 0, 0, &mtcio } }; + { MTD, 0, 0, 0, 0, &mtdio }, + { MTC, 0, 0, 0, 0, &mtcio } }; #define mtd_dib mt_dib[0] #define mtc_dib mt_dib[1] @@ -131,19 +140,19 @@ REG mtd_reg[] = { { DRDATA (BPTR, mt_ptr, DB_V_SIZE + 1) }, { DRDATA (BMAX, mt_max, DB_V_SIZE + 1) }, { ORDATA (DEVNO, mtd_dib.devno, 6), REG_HRO }, - { FLDATA (*DEVENB, mtd_dib.enb, 0), REG_HRO }, { NULL } }; MTAB mtd_mod[] = { { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &mtd_dib }, + &hp_setdev, &hp_showdev, &mtd_dev }, { 0 } }; DEVICE mtd_dev = { "MTD", &mtd_unit, mtd_reg, mtd_mod, 1, 10, 16, 1, 8, 8, NULL, NULL, &mtc_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &mtd_dib, DEV_DISABLE | DEV_DIS }; /* MTC data structures @@ -167,29 +176,25 @@ REG mtc_reg[] = { { FLDATA (FSVC, mtc_1st, 0) }, { DRDATA (POS, mtc_unit.pos, 32), PV_LEFT }, { DRDATA (CTIME, mtc_ctime, 24), REG_NZ + PV_LEFT }, + { DRDATA (GTIME, mtc_gtime, 24), REG_NZ + PV_LEFT }, { DRDATA (XTIME, mtc_xtime, 24), REG_NZ + PV_LEFT }, { FLDATA (STOP_IOE, mtc_stopioe, 0) }, - { FLDATA (WLK, mtc_unit.flags, UNIT_V_WLK), REG_HRO }, { ORDATA (DEVNO, mtc_dib.devno, 6), REG_HRO }, - { FLDATA (*DEVENB, mtc_dib.enb, 0), REG_HRO }, { NULL } }; MTAB mtc_mod[] = { { UNIT_WLK, 0, "write enabled", "WRITEENABLED", &mtc_vlock }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &mtc_vlock }, - { MTAB_XTD | MTAB_VDV, 1, NULL, "ENABLED", - &set_enb, NULL, &mtd_dib }, - { MTAB_XTD | MTAB_VDV, 1, NULL, "DISABLED", - &set_dis, NULL, &mtd_dib }, { MTAB_XTD | MTAB_VDV, 1, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &mtd_dib }, + &hp_setdev, &hp_showdev, &mtd_dev }, { 0 } }; DEVICE mtc_dev = { "MTC", &mtc_unit, mtc_reg, mtc_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &mtc_reset, - NULL, &mtc_attach, &mtc_detach }; + NULL, &mtc_attach, &mtc_detach, + &mtc_dib, DEV_DISABLE | DEV_DIS }; /* IOT routines */ @@ -197,10 +202,10 @@ int32 mtdio (int32 inst, int32 IR, int32 dat) { int32 devd; -devd = IR & DEVMASK; /* get device no */ +devd = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & HC) == 0) { setFLG (devd); } /* STF */ + if ((IR & I_HC) == 0) { setFLG (devd); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (devd) == 0) PC = (PC + 1) & VAMASK; @@ -218,11 +223,11 @@ case ioLIX: /* load */ dat = mtc_unit.buf; break; case ioCTL: /* control clear/set */ - if (IR & AB) mtc_dtf = 0; /* CLC: clr xfer flop */ + if (IR & I_CTL) mtc_dtf = 0; /* CLC: clr xfer flop */ break; default: break; } -if (IR & HC) { clrFLG (devd); } /* H/C option */ +if (IR & I_HC) { clrFLG (devd); } /* H/C option */ return dat; } @@ -230,11 +235,11 @@ int32 mtcio (int32 inst, int32 IR, int32 dat) { int32 i, devc, devd, valid; -devc = IR & DEVMASK; /* get device no */ +devc = IR & I_DEVMASK; /* get device no */ devd = devc - 1; switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & HC) == 0) { setFLG (devc); } /* STF */ + if ((IR & I_HC) == 0) { setFLG (devc); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (devc) == 0) PC = (PC + 1) & VAMASK; @@ -244,50 +249,53 @@ case ioSFS: /* skip flag set */ return dat; case ioOTX: /* output */ dat = dat & 0377; + mtc_sta = mtc_sta & ~STA_REJ; /* clear reject */ if (dat == FNC_CLR) { /* clear? */ - if (((mtc_fnc == FNC_REW) || (mtc_fnc == FNC_RWS)) && - sim_is_active (&mtc_unit)) break; - mtc_reset (&mtc_dev); /* if not rewind, */ - clrCTL (devc); /* init device */ - clrFLG (devc); - clrCTL (devd); - clrFLG (devd); - break; } + if (sim_is_active (&mtc_unit) && /* write in prog? */ + (mtc_fnc == FNC_WC) && (mt_ptr > 0)) /* yes, bad rec */ + mt_wrtrec (&mtc_unit, mt_ptr | MTR_ERF); + if (((mtc_fnc == FNC_REW) || (mtc_fnc == FNC_RWS)) && + sim_is_active (&mtc_unit)) sim_cancel (&mtc_unit); + mtc_1st = mtc_dtf = 0; + mtc_sta = mtc_sta & STA_BOT; + clrCTL (devc); /* init device */ + clrFLG (devc); + clrCTL (devd); + clrFLG (devd); + return SCPE_OK; } for (i = valid = 0; i < sizeof (mtc_cmd); i++) /* is fnc valid? */ - if (dat == mtc_cmd[i]) valid = 1; + if (dat == mtc_cmd[i]) valid = 1; if (!valid || sim_is_active (&mtc_unit) || /* is cmd valid? */ - ((mtc_unit.flags & UNIT_ATT) == 0) || - ((mtc_sta & STA_BOT) && - ((dat == FNC_BSR) || (dat == FNC_REW) || (dat == FNC_RWS))) || - ((mtc_unit.flags & UNIT_WPRT) && - ((dat == FNC_WC) || (dat == FNC_GAP) || (dat == FNC_WFM)))) - mtc_sta = mtc_sta | STA_REJ; - else { sim_activate (&mtc_unit, mtc_ctime); /* start tape */ - mtc_fnc = dat; /* save function */ - mtc_sta = STA_BUSY; /* unit busy */ - mt_ptr = 0; /* init buffer ptr */ - clrFLG (devc); /* clear flags */ - clrFLG (devd); - mtc_1st = 1; /* set 1st flop */ - mtc_dtf = 1; } /* set xfer flop */ + ((mtc_sta & STA_BOT) && (dat == FNC_BSR)) || + ((mtc_unit.flags & UNIT_WPRT) && + ((dat == FNC_WC) || (dat == FNC_GAP) || (dat == FNC_WFM)))) + mtc_sta = mtc_sta | STA_REJ; + else { + sim_activate (&mtc_unit, mtc_ctime); /* start tape */ + mtc_fnc = dat; /* save function */ + mtc_sta = STA_BUSY; /* unit busy */ + mt_ptr = 0; /* init buffer ptr */ + clrFLG (devc); /* clear flags */ + clrFLG (devd); + mtc_1st = 1; /* set 1st flop */ + mtc_dtf = 1; } /* set xfer flop */ break; case ioLIX: /* load */ dat = 0; case ioMIX: /* merge */ + dat = dat | (mtc_sta & ~(STA_LOCAL | STA_WLK | STA_BUSY)); if (mtc_unit.flags & UNIT_ATT) { /* construct status */ - mtc_sta = mtc_sta & ~(STA_LOCAL | STA_WLK | STA_BUSY); - if (sim_is_active (&mtc_unit)) mtc_sta = mtc_sta | STA_BUSY; - if (mtc_unit.flags & UNIT_WPRT) mtc_sta = mtc_sta | STA_WLK; } - else mtc_sta = STA_BUSY | STA_LOCAL; - dat = dat | mtc_sta; + if (sim_is_active (&mtc_unit)) dat = dat | STA_BUSY; + if (mtc_unit.flags & UNIT_WPRT) dat = dat | STA_WLK; } + else dat = dat | STA_BUSY | STA_LOCAL; break; case ioCTL: /* control clear/set */ - if (IR & AB) { clrCTL (devc); } /* CLC */ + if (IR & I_CTL) { clrCTL (devc); } /* CLC */ else { setCTL (devc); } /* STC */ break; default: break; } -if (IR & HC) { clrFLG (devc); } /* H/C option */ +if (IR & I_HC) { clrFLG (devc); } /* H/C option */ return dat; } @@ -301,138 +309,188 @@ return dat; t_stat mtc_svc (UNIT *uptr) { -int32 devc, devd, err, i; -static t_mtrlnt bceof = { 0 }; - -if ((mtc_unit.flags & UNIT_ATT) == 0) { /* offline? */ - mtc_sta = STA_LOCAL | STA_BUSY | STA_REJ; - return IORETURN (mtc_stopioe, SCPE_UNATT); } -devc = mtc_dib.devno; /* get device nos */ -devd = mtd_dib.devno; +int32 devc, devd, err, pnu; +static t_mtrlnt i, bceof = { MTR_TMK }; err = 0; /* assume no errors */ -switch (mtc_fnc & 0377) { /* case on function */ +devc = mtc_dib.devno; /* get device nos */ +devd = mtd_dib.devno; +if ((mtc_unit.flags & UNIT_ATT) == 0) { /* offline? */ + mtc_sta = STA_LOCAL | STA_REJ; /* rejected */ + setFLG (devc); /* set cch flg */ + return IORETURN (mtc_stopioe, SCPE_UNATT); } + +pnu = MT_TST_PNU (uptr); /* get pos not upd */ +MT_CLR_PNU (uptr); /* and clear */ +switch (mtc_fnc) { /* case on function */ + case FNC_REW: /* rewind */ mtc_unit.pos = 0; /* BOT */ - mtc_sta = mtc_sta | STA_BOT; /* update status */ + mtc_sta = STA_BOT; /* update status */ break; + case FNC_RWS: /* rewind and offline */ - mtc_unit.pos = 0; /* BOT */ - mtc_sta = STA_LOCAL | STA_BUSY; /* set status */ + mtc_unit.pos = 0; /* clear position */ return detach_unit (uptr); /* don't set cch flg */ + case FNC_WFM: /* write file mark */ fseek (mtc_unit.fileref, mtc_unit.pos, SEEK_SET); fxwrite (&bceof, sizeof (t_mtrlnt), 1, mtc_unit.fileref); - err = ferror (mtc_unit.fileref); - mtc_unit.pos = mtc_unit.pos + sizeof (t_mtrlnt); /* update tape pos */ - mtc_sta = mtc_sta | STA_EOF; /* set EOF status */ + mtc_sta = STA_EOF; /* set EOF status */ + if (err = ferror (mtc_unit.fileref)) MT_SET_PNU (uptr); + else mtc_unit.pos = mtc_unit.pos + sizeof (t_mtrlnt); /* update tape pos */ + break; + case FNC_GAP: /* erase gap */ break; - -/* Unit service, continued */ case FNC_FSR: /* space forward */ - fseek (mtc_unit.fileref, mtc_unit.pos, SEEK_SET); - fxread (&mt_max, sizeof (t_mtrlnt), 1, mtc_unit.fileref); - if ((err = ferror (mtc_unit.fileref)) || /* error or eof? */ - feof (mtc_unit.fileref)) mtc_sta = mtc_sta | STA_EOT; - else if (mt_max == 0) { /* zero bc? */ - mtc_sta = mtc_sta | STA_EOF; /* EOF */ - mtc_unit.pos = mtc_unit.pos + sizeof (t_mtrlnt); } - else mtc_unit.pos = mtc_unit.pos + ((MTRL (mt_max) + 1) & ~1) + - (2 * sizeof (t_mtrlnt)); /* update position */ - break; -case FNC_BSR: /* space reverse */ - if (mtc_unit.pos == 0) { /* at BOT? */ - mtc_sta = mtc_sta | STA_BOT; /* update status */ - break; } - fseek (mtc_unit.fileref, mtc_unit.pos - sizeof (t_mtrlnt), SEEK_SET); - fxread (&mt_max, sizeof (t_mtrlnt), 1, mtc_unit.fileref); - if ((err = ferror (mtc_unit.fileref)) || /* error or eof? */ - feof (mtc_unit.fileref)) mtc_unit.pos = 0; - else if (mt_max == 0) { /* zero bc? */ - mtc_sta = mtc_sta | STA_EOF; /* EOF */ - mtc_unit.pos = mtc_unit.pos - sizeof (t_mtrlnt); } - else mtc_unit.pos = mtc_unit.pos - ((MTRL (mt_max) + 1) & ~1) - + if (mt_rdlntf (uptr, &mt_max, &err)) break; /* read rec lnt, err? */ + mtc_unit.pos = mtc_unit.pos + ((mt_max + 1) & ~1) + (2 * sizeof (t_mtrlnt)); /* update position */ - if (mtc_unit.pos == 0) mtc_sta = mtc_sta | STA_BOT; + break; + +case FNC_BSR: /* space reverse */ + if (pnu) break; /* pnu? do nothing */ + if (mt_rdlntr (uptr, &mt_max, &err)) break; /* read rec lnt, err? */ + mtc_unit.pos = mtc_unit.pos - ((mt_max + 1) & ~1) - + (2 * sizeof (t_mtrlnt)); /* update position */ break; /* Unit service, continued */ case FNC_RC: /* read */ if (mtc_1st) { /* first svc? */ - mtc_1st = 0; /* clr 1st flop */ - fseek (mtc_unit.fileref, mtc_unit.pos, SEEK_SET); - fxread (&mt_max, sizeof (t_mtrlnt), 1, mtc_unit.fileref); - if ((err = ferror (mtc_unit.fileref)) || - feof (mtc_unit.fileref)) { /* error or eof? */ - setFLG (devc); /* set cch flg */ - mtc_sta = (mtc_sta | STA_EOT) & ~STA_BUSY; - break; } - if (mt_max == 0) { /* tape mark? */ - mtc_unit.pos = mtc_unit.pos + sizeof (t_mtrlnt); - setFLG (devc); /* set cch flg */ - mtc_sta = (mtc_sta | STA_EOF) & ~STA_BUSY; - break; } - mt_max = MTRL (mt_max); /* ignore errors */ - mtc_unit.pos = mtc_unit.pos + ((mt_max + 1) & ~1) + - (2 * sizeof (t_mtrlnt)); /* update position */ - if (mt_max > DBSIZE) return SCPE_MTRLNT;/* record too long? */ - if (mt_max < 12) { /* record too short? */ - setFLG (devc); /* set cch flg */ - mtc_sta = (mtc_sta | STA_PAR) & ~STA_BUSY; - break; } - i = fxread (mtxb, sizeof (int8), mt_max, mtc_unit.fileref); - for ( ; i < mt_max; i++) mtxb[i] = 0; /* fill with 0's */ - err = ferror (mtc_unit.fileref); } + mtc_1st = 0; /* clr 1st flop */ + if (mt_rdlntf (uptr, &mt_max, &err)) { /* read rec lnt */ + if (!err) { /* tmk or eom? */ + sim_activate (uptr, mtc_gtime); /* sched IRG */ + mtc_fnc = 0; /* NOP func */ + return SCPE_OK; } + break; } /* error, done */ + if (mt_max > DBSIZE) return SCPE_MTRLNT; /* record too long? */ + if (mt_max < 12) { /* record too short? */ + mtc_sta = mtc_sta | STA_PAR; /* set flag */ + break; } + i = fxread (mtxb, sizeof (int8), mt_max, mtc_unit.fileref); + for ( ; i < mt_max; i++) mtxb[i] = 0; /* fill with 0's */ + if (err = ferror (mtc_unit.fileref)) { /* error? */ + mtc_sta = mtc_sta | STA_PAR; /* set flag */ + MT_SET_PNU (uptr); /* pos not upd */ + break; } + mtc_unit.pos = mtc_unit.pos + ((mt_max + 1) & ~1) + + (2 * sizeof (t_mtrlnt)); } /* update position */ if (mt_ptr < mt_max) { /* more chars? */ - if (FLG (devd)) mtc_sta = mtc_sta | STA_TIM; - mtc_unit.buf = mtxb[mt_ptr++]; /* fetch next */ - setFLG (devd); /* set dch flg */ - sim_activate (uptr, mtc_xtime); /* re-activate */ - return SCPE_OK; } - break; + if (FLG (devd)) mtc_sta = mtc_sta | STA_TIM; + mtc_unit.buf = mtxb[mt_ptr++]; /* fetch next */ + setFLG (devd); /* set dch flg */ + sim_activate (uptr, mtc_xtime); /* re-activate */ + return SCPE_OK; } + sim_activate (uptr, mtc_gtime); /* schedule gap */ + mtc_fnc = 0; /* nop */ + return SCPE_OK; + case FNC_WC: /* write */ if (mtc_1st) mtc_1st = 0; /* no xfr on first */ - else { if (mt_ptr < DBSIZE) /* room in buffer? */ - mtxb[mt_ptr++] = mtc_unit.buf; - else mtc_sta = mtc_sta | STA_PAR; } + else { + if (mt_ptr < DBSIZE) { /* room in buffer? */ + mtxb[mt_ptr++] = mtc_unit.buf; + mtc_sta = mtc_sta & ~STA_BOT; } /* clear BOT */ + else mtc_sta = mtc_sta | STA_PAR; } if (mtc_dtf) { /* xfer flop set? */ - setFLG (devd); /* set dch flag */ - sim_activate (uptr, mtc_xtime); /* re-activate */ - return SCPE_OK; } + setFLG (devd); /* set dch flag */ + sim_activate (uptr, mtc_xtime); /* re-activate */ + return SCPE_OK; } if (mt_ptr) { /* write buffer */ - fseek (mtc_unit.fileref, mtc_unit.pos, SEEK_SET); - fxwrite (&mt_ptr, sizeof (t_mtrlnt), 1, mtc_unit.fileref); - fxwrite (mtxb, sizeof (int8), mt_ptr, mtc_unit.fileref); - fxwrite (&mt_ptr, sizeof (t_mtrlnt), 1, mtc_unit.fileref); - err = ferror (mtc_unit.fileref); - mtc_unit.pos = mtc_unit.pos + ((mt_ptr + 1) & ~1) + - (2 * sizeof (t_mtrlnt)); } + if (err = mt_wrtrec (uptr, mt_ptr)) break; } + sim_activate (uptr, mtc_gtime); /* schedule gap */ + mtc_fnc = 0; /* nop */ + return SCPE_OK; + +default: /* unknown */ break; } - -/* Unit service, continued */ setFLG (devc); /* set cch flg */ mtc_sta = mtc_sta & ~STA_BUSY; /* not busy */ if (err != 0) { /* I/O error */ perror ("MT I/O error"); clearerr (mtc_unit.fileref); - IORETURN (mtc_stopioe, SCPE_IOERR); } + if (mtc_stopioe) return SCPE_IOERR; } return SCPE_OK; } + +/* Tape motion routines */ +t_bool mt_rdlntf (UNIT *uptr, t_mtrlnt *tbc, int32 *err) +{ +fseek (uptr->fileref, uptr->pos, SEEK_SET); /* position */ +fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); /* get bc */ +if ((*err = ferror (uptr->fileref)) || /* error or eom? */ + feof (uptr->fileref) || (*tbc == MTR_EOM)) { + mtc_sta = mtc_sta | STA_PAR; /* error */ + MT_SET_PNU (uptr); /* pos not upd */ + return TRUE; } +if (*tbc == MTR_TMK) { /* tape mark? */ + mtc_sta = mtc_sta | STA_EOF; /* eof */ + uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* spc over tmk */ + return TRUE; } +if (MTRF (*tbc)) mtc_sta = mtc_sta | STA_PAR; /* error in rec? */ +*tbc = MTRL (*tbc); /* clear err flag */ +return FALSE; +} + +t_bool mt_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err) +{ +if (uptr->pos < sizeof (t_mtrlnt)) { /* no data to read? */ + mtc_sta = mtc_sta | STA_BOT; /* update status */ + return TRUE; } +fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt), SEEK_SET); +fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); /* get bc */ +if ((*err = ferror (uptr->fileref)) || /* error or eof? */ + feof (uptr->fileref)) { + mtc_sta = mtc_sta | STA_PAR; /* error */ + return TRUE; } +if (*tbc == MTR_EOM) { /* eom? */ + mtc_sta = mtc_sta | STA_PAR; /* error */ + uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over eom */ + return TRUE; } +if (*tbc == MTR_TMK) { /* tape mark? */ + mtc_sta = mtc_sta | STA_EOF; /* eof */ + uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over tmk */ + return TRUE; } +if (MTRF (*tbc)) mtc_sta = mtc_sta | STA_PAR; /* error in rec? */ +*tbc = MTRL (*tbc); /* clear err flag */ +return FALSE; +} + +int32 mt_wrtrec (UNIT *uptr, t_mtrlnt lnt) +{ +int32 elnt = MTRL ((lnt + 1) & ~1); /* even lnt, no err */ + +fseek (uptr->fileref, uptr->pos, SEEK_SET); /* seek to record */ +fxwrite (&lnt, sizeof (t_mtrlnt), 1, uptr->fileref); /* write rec lnt */ +fxwrite (mtxb, sizeof (int8), elnt, uptr->fileref); /* write data */ +fxwrite (&lnt, sizeof (t_mtrlnt), 1, uptr->fileref); /* write rec lnt */ +if (ferror (uptr->fileref)) { /* error? */ + MT_SET_PNU (uptr); /* pos not updated */ + return 1; } +else uptr->pos = uptr->pos + elnt + (2 * sizeof (t_mtrlnt)); /* no, upd pos */ +return 0; +} + /* Reset routine */ t_stat mtc_reset (DEVICE *dptr) { +hp_enbdis_pair (&mtc_dev, &mtd_dev); /* make pair cons */ mtc_fnc = 0; +mtc_1st = mtc_dtf = 0; mtc_dib.cmd = mtd_dib.cmd = 0; /* clear cmd */ mtc_dib.ctl = mtd_dib.ctl = 0; /* clear ctl */ mtc_dib.flg = mtd_dib.flg = 0; /* clear flg */ mtc_dib.fbf = mtd_dib.fbf = 0; /* clear fbf */ sim_cancel (&mtc_unit); /* cancel activity */ +mtc_unit.flags = mtc_unit.flags & ~UNIT_PNU; /* clear pos flag */ if (mtc_unit.flags & UNIT_ATT) mtc_sta = ((mtc_unit.pos)? 0: STA_BOT) | ((mtc_unit.flags & UNIT_WPRT)? STA_WLK: 0); else mtc_sta = STA_LOCAL | STA_BUSY; @@ -447,7 +505,8 @@ t_stat r; r = attach_unit (uptr, cptr); /* attach unit */ if (r != SCPE_OK) return r; /* update status */ -mtc_sta = STA_BOT | ((uptr -> flags & UNIT_WPRT)? STA_WLK: 0); +MT_CLR_PNU (uptr); +mtc_sta = STA_BOT; return r; } @@ -455,7 +514,8 @@ return r; t_stat mtc_detach (UNIT* uptr) { -mtc_sta = STA_LOCAL | STA_BUSY; /* update status */ +mtc_sta = 0; /* update status */ +MT_CLR_PNU (uptr); return detach_unit (uptr); /* detach unit */ } @@ -463,6 +523,6 @@ return detach_unit (uptr); /* detach unit */ t_stat mtc_vlock (UNIT *uptr, int32 val, char *cptr, void *desc) { -if (val && (uptr -> flags & UNIT_ATT)) return SCPE_ARG; +if (val && (uptr->flags & UNIT_ATT)) return SCPE_ARG; return SCPE_OK; } diff --git a/HP2100/hp2100_mux.c b/HP2100/hp2100_mux.c index 3b1fc4d1..8e267fee 100644 --- a/HP2100/hp2100_mux.c +++ b/HP2100/hp2100_mux.c @@ -25,6 +25,9 @@ mux,muxl,muxc 12920A terminal multiplexor + 01-Nov-02 RMS Added 7B/8B support + 22-Aug-02 RMS Updated for changes to sim_tmxr + The 12920A consists of three separate devices mux scanner (upper data card) @@ -42,8 +45,10 @@ #define MUX_LINES 16 /* user lines */ #define MUX_ILINES 5 /* diag rcv only */ -#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */ -#define UNIT_V_MDM (UNIT_V_UF + 1) /* modem control */ +#define UNIT_V_8B (UNIT_V_UF + 0) /* 8B */ +#define UNIT_V_UC (UNIT_V_UF + 1) /* UC only */ +#define UNIT_V_MDM (UNIT_V_UF + 2) /* modem control */ +#define UNIT_8B (1 << UNIT_V_8B) #define UNIT_UC (1 << UNIT_V_UC) #define UNIT_MDM (1 << UNIT_V_MDM) #define MUXU_INIT_POLL 8000 @@ -145,8 +150,9 @@ uint32 muxc_chan = 0; /* ctrl chan */ uint32 muxc_scan = 0; /* ctrl scan */ TMLN mux_ldsc[MUX_LINES] = { 0 }; /* line descriptors */ -TMXR mux_desc = { MUX_LINES, 0, NULL }; /* mux descriptor */ +TMXR mux_desc = { MUX_LINES, 0, 0, NULL }; /* mux descriptor */ +DEVICE muxl_dev, muxu_dev, muxc_dev; int32 muxlio (int32 inst, int32 IR, int32 dat); int32 muxuio (int32 inst, int32 IR, int32 dat); int32 muxcio (int32 inst, int32 IR, int32 dat); @@ -160,8 +166,6 @@ t_stat mux_show (FILE *st, UNIT *uptr, int32 val, void *desc); void mux_data_int (void); void mux_ctrl_int (void); void mux_diag (int32 c); -t_stat mux_enb (UNIT *uptr, int32 num, char *cptr, void *desc); -t_stat mux_dis (UNIT *uptr, int32 num, char *cptr, void *desc); static uint8 odd_par[256] = { 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 000-017 */ @@ -183,9 +187,9 @@ static uint8 odd_par[256] = { #define RCV_PAR(x) (odd_par[(x) & 0377]? LIL_PAR: 0) - DIB mux_dib[] = { - { MUXL, 1, 0, 0, 0, 0, &muxlio }, - { MUXU, 1, 0, 0, 0, 0, &muxuio } }; +DIB mux_dib[] = { + { MUXL, 0, 0, 0, 0, &muxlio }, + { MUXU, 0, 0, 0, 0, &muxuio } }; #define muxl_dib mux_dib[0] #define muxu_dib mux_dib[1] @@ -208,30 +212,26 @@ REG muxu_reg[] = { { FLDATA (FLG, muxu_dib.flg, 0), REG_HRO }, { FLDATA (FBF, muxu_dib.fbf, 0), REG_HRO }, { ORDATA (DEVNO, muxu_dib.devno, 6), REG_HRO }, - { FLDATA (*DEVENB, muxu_dib.enb, 0), REG_HRO }, { NULL } }; MTAB muxu_mod[] = { - { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", - &tmxr_dscln, NULL, &mux_desc }, { UNIT_ATT, UNIT_ATT, "connections", NULL, NULL, &mux_summ }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, NULL, &mux_show, NULL }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, NULL, &mux_show, NULL }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "ENABLED", - &mux_enb, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "DISABLED", - &mux_dis, NULL, NULL }, { MTAB_XTD|MTAB_VDV, 1, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &mux_dib }, + &hp_setdev, &hp_showdev, &muxl_dev }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", + &tmxr_dscln, NULL, &mux_desc }, { 0 } }; DEVICE muxu_dev = { "MUX", &muxu_unit, muxu_reg, muxu_mod, 1, 10, 31, 1, 8, 8, &tmxr_ex, &tmxr_dep, &mux_reset, - NULL, &mux_attach, &mux_detach }; + NULL, &mux_attach, &mux_detach, + &muxu_dib, DEV_DISABLE }; /* MUXL data structures @@ -261,16 +261,13 @@ UNIT muxl_unit[] = { { UDATA (&muxo_svc, UNIT_UC, 0), MUXL_WAIT } }; MTAB muxl_mod[] = { - { UNIT_UC, 0, "lower case", "LC", NULL }, - { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, + { UNIT_UC+UNIT_8B, UNIT_UC, "UC", "UC", NULL }, + { UNIT_UC+UNIT_8B, 0 , "7b", "7B", NULL }, + { UNIT_UC+UNIT_8B, UNIT_8B, "8b", "8B", NULL }, { UNIT_MDM, 0, "no dataset", "NODATASET", NULL }, { UNIT_MDM, UNIT_MDM, "dataset", "DATASET", NULL }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "ENABLED", - &mux_enb, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "DISABLED", - &mux_dis, NULL, NULL }, { MTAB_XTD|MTAB_VDV, 1, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &mux_dib }, + &hp_setdev, &hp_showdev, &muxl_dev }, { 0 } }; REG muxl_reg[] = { @@ -287,17 +284,15 @@ REG muxl_reg[] = { { BRDATA (XDON, mux_xdon, 8, 1, MUX_LINES) }, { URDATA (TIME, muxl_unit[0].wait, 10, 24, 0, MUX_LINES, REG_NZ + PV_LEFT) }, - { URDATA (FLGS, muxl_unit[0].flags, 8, 2, UNIT_V_UF, - MUX_LINES, REG_HRO) }, { ORDATA (DEVNO, muxl_dib.devno, 6), REG_HRO }, - { FLDATA (*DEVENB, muxl_dib.enb, 0), REG_HRO }, { NULL } }; DEVICE muxl_dev = { "MUXL", muxl_unit, muxl_reg, muxl_mod, MUX_LINES, 10, 31, 1, 8, 8, NULL, NULL, &mux_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &muxl_dib, 0 }; /* MUXM data structures @@ -307,7 +302,7 @@ DEVICE muxl_dev = { muxc_mod MUXM modifiers list */ -DIB muxc_dib = { MUXC, 1, 0, 0, 0, 0, &muxcio }; +DIB muxc_dib = { MUXC, 0, 0, 0, 0, &muxcio }; UNIT muxc_unit = { UDATA (NULL, 0, 0) }; @@ -321,23 +316,19 @@ REG muxc_reg[] = { { BRDATA (DSO, muxc_ota, 8, 6, MUX_LINES) }, { BRDATA (DSI, muxc_lia, 8, 2, MUX_LINES) }, { ORDATA (DEVNO, muxc_dib.devno, 6), REG_HRO }, - { FLDATA (*DEVENB, muxc_dib.enb, 0), REG_HRO }, { NULL } }; MTAB muxc_mod[] = { - { MTAB_XTD | MTAB_VDV, 0, NULL, "ENABLED", - &mux_enb, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "DISABLED", - &mux_dis, NULL, NULL }, { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &muxc_dib }, + &hp_setdev, &hp_showdev, &muxc_dev }, { 0 } }; DEVICE muxc_dev = { "MUXM", &muxc_unit, muxc_reg, muxc_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &mux_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &muxc_dib, 0 }; /* IOT routines: data cards */ @@ -345,10 +336,10 @@ int32 muxlio (int32 inst, int32 IR, int32 dat) { int32 dev, ln; -dev = IR & DEVMASK; /* get device no */ +dev = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & HC) == 0) { setFLG (dev); } /* STF */ + if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; @@ -366,7 +357,7 @@ case ioLIX: /* load */ dat = muxl_ibuf; break; case ioCTL: /* control clear/set */ - if (IR & AB) { clrCTL (dev); } /* CLC */ + if (IR & I_CTL) { clrCTL (dev); } /* CLC */ else { /* STC */ setCTL (dev); /* set ctl */ ln = MUX_CHAN (muxu_obuf); /* get chan # */ @@ -386,7 +377,7 @@ case ioCTL: /* control clear/set */ break; default: break; } -if (IR & HC) { /* H/C option */ +if (IR & I_HC) { /* H/C option */ clrFLG (dev); /* clear flag */ mux_data_int (); } /* look for new int */ return dat; @@ -415,10 +406,10 @@ int32 muxcio (int32 inst, int32 IR, int32 dat) { int32 dev, ln, t, old; -dev = IR & DEVMASK; /* get device no */ +dev = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & HC) == 0) { setFLG (dev); } /* STF */ + if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; @@ -456,12 +447,12 @@ case ioMIX: /* merge */ muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* incr channel */ break; case ioCTL: /* ctrl clear/set */ - if (IR & AB) { clrCTL (dev); } /* CLC */ + if (IR & I_CTL) { clrCTL (dev); } /* CLC */ else { setCTL (dev); } /* STC */ break; default: break; } -if (IR & HC) { /* H/C option */ +if (IR & I_HC) { /* H/C option */ clrFLG (dev); /* clear flag */ mux_ctrl_int (); } /* look for new int */ return dat; @@ -477,31 +468,33 @@ t_stat muxi_svc (UNIT *uptr) { int32 ln, c, t; -if ((uptr -> flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */ +if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */ t = sim_rtcn_calb (mux_tps, TMR_MUX); /* calibrate */ sim_activate (uptr, t); /* continue poll */ -ln = tmxr_poll_conn (&mux_desc, uptr); /* look for connect */ +ln = tmxr_poll_conn (&mux_desc); /* look for connect */ if (ln >= 0) { /* got one? */ - if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */ - (muxc_ota[ln] & DTR)) /* DTR? */ - muxc_lia[ln] = muxc_lia[ln] | CDET; /* set cdet */ - muxc_lia[ln] = muxc_lia[ln] | DSR; /* set dsr */ - mux_ldsc[ln].rcve = 1; } /* rcv enabled */ + if ((muxl_unit[ln].flags & UNIT_MDM) && /* modem ctrl? */ + (muxc_ota[ln] & DTR)) /* DTR? */ + muxc_lia[ln] = muxc_lia[ln] | CDET; /* set cdet */ + muxc_lia[ln] = muxc_lia[ln] | DSR; /* set dsr */ + mux_ldsc[ln].rcve = 1; } /* rcv enabled */ tmxr_poll_rx (&mux_desc); /* poll for input */ for (ln = 0; ln < MUX_LINES; ln++) { /* loop thru lines */ - if (mux_ldsc[ln].conn) { /* connected? */ - if (c = tmxr_getc_ln (&mux_ldsc[ln])) { /* get char */ - if (mux_rchp[ln]) mux_sta[ln] = mux_sta[ln] | LIU_LOST; - if ((muxl_unit[ln].flags & UNIT_UC) && /* cvt to UC? */ - islower (c & 0177)) c = toupper (c); - if (mux_rpar[ln] & OTL_ECHO) { /* echo? */ - TMLN *lp = &mux_ldsc[ln]; /* get line */ - tmxr_putc_ln (lp, c); /* output char */ - tmxr_poll_tx (&mux_desc); } /* poll xmt */ - if (mux_rpar[ln] & OTL_DIAG) mux_diag (c); /* rcv diag? */ - mux_rbuf[ln] = c; /* save char */ - mux_rchp[ln] = 1; } } /* char pending */ - else muxc_lia[ln] = 0; } /* disconnected */ /* end for */ + if (mux_ldsc[ln].conn) { /* connected? */ + if (c = tmxr_getc_ln (&mux_ldsc[ln])) { /* get char */ + if (mux_rchp[ln]) mux_sta[ln] = mux_sta[ln] | LIU_LOST; + if (muxl_unit[ln].flags & UNIT_UC) { /* cvt to UC? */ + c = c & 0177; + if (islower (c)) c = toupper (c); } + else c = c & ((muxl_unit[ln].flags & UNIT_8B)? 0377: 0177); + if (mux_rpar[ln] & OTL_ECHO) { /* echo? */ + TMLN *lp = &mux_ldsc[ln]; /* get line */ + tmxr_putc_ln (lp, c); /* output char */ + tmxr_poll_tx (&mux_desc); } /* poll xmt */ + if (mux_rpar[ln] & OTL_DIAG) mux_diag (c); /* rcv diag? */ + mux_rbuf[ln] = c; /* save char */ + mux_rchp[ln] = 1; } } /* char pending */ + else muxc_lia[ln] = 0; } /* disconnected */ /* end for */ if (!FLG (muxl_dib.devno)) mux_data_int (); /* scan for data int */ if (!FLG (muxc_dib.devno)) mux_ctrl_int (); /* scan modem */ return SCPE_OK; @@ -514,21 +507,23 @@ t_stat muxo_svc (UNIT *uptr) int32 c, ln = uptr - muxl_unit; /* line # */ if (mux_ldsc[ln].conn) { /* connected? */ - if (mux_ldsc[ln].xmte) { /* xmt enabled? */ - if ((mux_xbuf[ln] & OTL_SYNC) == 0) { /* start bit 0? */ - TMLN *lp = &mux_ldsc[ln]; /* get line */ - c = mux_xbuf[ln] & 0177; /* get char */ - if ((muxl_unit[ln].flags & UNIT_UC) && islower (c)) - c = toupper (c); /* cvt to UC? */ - if (mux_xpar[ln] & OTL_DIAG) /* xmt diag? */ - mux_diag (mux_xbuf[ln]); /* before munge */ - mux_xdon[ln] = 1; /* set done */ - tmxr_putc_ln (lp, c); /* output char */ - tmxr_poll_tx (&mux_desc); } } /* poll xmt */ - else { /* buf full */ - tmxr_poll_tx (&mux_desc); /* poll xmt */ - sim_activate (uptr, muxl_unit[ln].wait); /* wait */ - return SCPE_OK; } } + if (mux_ldsc[ln].xmte) { /* xmt enabled? */ + if ((mux_xbuf[ln] & OTL_SYNC) == 0) { /* start bit 0? */ + TMLN *lp = &mux_ldsc[ln]; /* get line */ + c = mux_xbuf[ln]; /* get char */ + if (muxl_unit[ln].flags & UNIT_UC) { /* cvt to UC? */ + c = c & 0177; + if (islower (c)) c = toupper (c); } + else c = c & ((muxl_unit[ln].flags & UNIT_8B)? 0377: 0177); + if (mux_xpar[ln] & OTL_DIAG) /* xmt diag? */ + mux_diag (mux_xbuf[ln]); /* before munge */ + mux_xdon[ln] = 1; /* set done */ + tmxr_putc_ln (lp, c); /* output char */ + tmxr_poll_tx (&mux_desc); } } /* poll xmt */ + else { /* buf full */ + tmxr_poll_tx (&mux_desc); /* poll xmt */ + sim_activate (uptr, muxl_unit[ln].wait); /* wait */ + return SCPE_OK; } } if (!FLG (muxl_dib.devno)) mux_data_int (); /* scan for int */ return SCPE_OK; } @@ -542,7 +537,7 @@ int32 i; for (i = 0; i < MUX_LINES; i++) { /* rcv lines */ if ((mux_rpar[i] & OTL_ENB) && mux_rchp[i]) { /* enabled, char? */ muxl_ibuf = PUT_CCH (i) | mux_rbuf[i] | /* lo buf = char */ - RCV_PAR (mux_rbuf[i]); + RCV_PAR (mux_rbuf[i]); muxu_ibuf = PUT_CCH (i) | mux_sta[i]; /* hi buf = stat */ mux_rchp[i] = 0; /* clr char, stat */ mux_sta[i] = 0; @@ -558,7 +553,7 @@ for (i = 0; i < MUX_LINES; i++) { /* xmt lines */ for (i = MUX_LINES; i < (MUX_LINES + MUX_ILINES); i++) { /* diag lines */ if ((mux_rpar[i] & OTL_ENB) && mux_rchp[i]) { /* enabled, char? */ muxl_ibuf = PUT_CCH (i) | mux_rbuf[i] | /* lo buf = char */ - RCV_PAR (mux_rbuf[i]); + RCV_PAR (mux_rbuf[i]); muxu_ibuf = PUT_CCH (i) | mux_sta[i] | LIU_DG; /* hi buf = stat */ mux_rchp[i] = 0; /* clr char, stat */ mux_sta[i] = 0; @@ -577,8 +572,8 @@ if (muxc_scan == 0) return; for (i = 0; i < MUX_LINES; i++) { muxc_chan = (muxc_chan + 1) & LIC_M_CHAN; /* step channel */ if (LIC_TSTI (muxc_chan)) { /* status change? */ - setFLG (muxc_dib.devno); /* set flag */ - break; } } + setFLG (muxc_dib.devno); /* set flag */ + break; } } return; } @@ -617,6 +612,11 @@ t_stat mux_reset (DEVICE *dptr) { int32 i, t; +if (muxu_dev.flags & DEV_DIS) { /* enb/dis dev */ + muxl_dev.flags = muxu_dev.flags | DEV_DIS; + muxc_dev.flags = muxc_dev.flags | DEV_DIS; } +else { muxl_dev.flags = muxl_dev.flags & ~DEV_DIS; + muxc_dev.flags = muxc_dev.flags & ~DEV_DIS; } muxl_dib.cmd = muxl_dib.ctl = 0; /* init lower */ muxl_dib.flg = muxl_dib.fbf = 1; muxu_dib.cmd = muxu_dib.ctl = 0; /* upper not */ @@ -626,8 +626,8 @@ muxc_dib.flg = muxc_dib.fbf = 1; muxc_chan = muxc_scan = 0; /* init modem scan */ if (muxu_unit.flags & UNIT_ATT) { /* master att? */ if (!sim_is_active (&muxu_unit)) { - t = sim_rtcn_init (muxu_unit.wait, TMR_MUX); - sim_activate (&muxu_unit, t); } } /* activate */ + t = sim_rtcn_init (muxu_unit.wait, TMR_MUX); + sim_activate (&muxu_unit, t); } } /* activate */ else sim_cancel (&muxu_unit); /* else stop */ for (i = 0; i < MUX_LINES; i++) { mux_desc.ldsc[i] = &mux_ldsc[i]; @@ -659,7 +659,7 @@ t_stat r; r = tmxr_detach (&mux_desc, uptr); /* detach */ for (i = 0; i < MUX_LINES; i++) mux_ldsc[i].rcve = 0; /* disable rcv */ sim_cancel (uptr); /* stop poll */ -return SCPE_OK; +return r; } /* Show summary processor */ @@ -682,34 +682,11 @@ int32 i; for (i = 0; (i < MUX_LINES) && (mux_ldsc[i].conn == 0); i++) ; if (i < MUX_LINES) { - for (i = 0; i < MUX_LINES; i++) { - if (mux_ldsc[i].conn) - if (val) tmxr_fconns (st, &mux_ldsc[i], i); - else tmxr_fstats (st, &mux_ldsc[i], i); } } + for (i = 0; i < MUX_LINES; i++) { + if (mux_ldsc[i].conn) { + if (val) tmxr_fconns (st, &mux_ldsc[i], i); + else tmxr_fstats (st, &mux_ldsc[i], i); } } } else fprintf (st, "all disconnected\n"); return SCPE_OK; } -/* Enable device */ - -t_stat mux_enb (UNIT *uptr, int32 num, char *cptr, void *desc) -{ -if (cptr != NULL) return SCPE_ARG; -muxl_dib.enb = 1; -muxu_dib.enb = 1; -muxc_dib.enb = 1; -return mux_reset (&muxl_dev); -} - -/* Disable device */ - -t_stat mux_dis (UNIT *uptr, int32 num, char *cptr, void *desc) -{ -if (cptr != NULL) return SCPE_ARG; -if (muxu_unit.flags & UNIT_ATT) return SCPE_NOFNC; -muxl_dib.enb = 0; -muxu_dib.enb = 0; -muxc_dib.enb = 0; -return mux_reset (&muxl_dev); -} - diff --git a/HP2100/hp2100_stddev.c b/HP2100/hp2100_stddev.c index cc8445e5..4c1762c1 100644 --- a/HP2100/hp2100_stddev.c +++ b/HP2100/hp2100_stddev.c @@ -13,9 +13,9 @@ all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTI_CTLILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + ROBERT M SUPNIK BE LII_CTLLE FOR ANY CLAIM, DAMAGES OR OTHER LII_CTLILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -26,8 +26,13 @@ ptr 12597A-002 paper tape reader ptp 12597A-005 paper tape punch tty 12531C buffered teleprinter interface - clk 12539A/B/C time base generator + clk 12539C time base generator + 01-Nov-02 RMS Revised BOOT command for IBL ROMs + Fixed bug in TTY reset, TTY starts in input mode + Fixed bug in TTY mode OTA, stores data as well + Fixed clock to add calibration, proper start/stop + Added UC option to TTY output 30-May-02 RMS Widened POS to 32b 22-Mar-02 RMS Revised for dynamically allocated memory 03-Nov-01 RMS Changed DEVNO to use extended SET/SHOW @@ -40,37 +45,60 @@ The reader and punch, like most HP devices, have a command flop. The teleprinter and clock do not. + + The clock autocalibrates. If the specified clock frequency is below + 10Hz, the clock service routine runs at 10Hz and counts down a repeat + counter before generating an interrupt. Autocalibration will not work + if the clock is running at 1Hz or less. + + Clock diagnostic mode corresponds to inserting jumper W2 on the 12539C. + This turns off autocalibration and divides the longest time intervals down + by 10**3. The clk_time values were chosen to allow the diagnostic to + pass its clock calibration test. */ #include "hp2100_defs.h" #include +#define UNIT_V_8B (UNIT_V_UF + 0) /* 8B */ #define UNIT_V_UC (UNIT_V_UF + 1) /* UC only */ +#define UNIT_V_DIAG (UNIT_V_UF + 2) /* diag mode */ +#define UNIT_8B (1 << UNIT_V_8B) #define UNIT_UC (1 << UNIT_V_UC) +#define UNIT_DIAG (1 << UNIT_V_DIAG) + #define PTP_LOW 0000040 /* low tape */ #define TM_MODE 0100000 /* mode change */ #define TM_KBD 0040000 /* enable keyboard */ #define TM_PRI 0020000 /* enable printer */ #define TM_PUN 0010000 /* enable punch */ #define TP_BUSY 0100000 /* busy */ + #define CLK_V_ERROR 4 /* clock overrun */ #define CLK_ERROR (1 << CLK_V_ERROR) extern uint16 *M; -extern int32 PC; +extern int32 PC, SR; extern int32 dev_cmd[2], dev_ctl[2], dev_flg[2], dev_fbf[2]; extern UNIT cpu_unit; + int32 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */ int32 ttp_stopioe = 0; int32 tty_buf = 0, tty_mode = 0; /* tty buffer, mode */ int32 clk_select = 0; /* clock time select */ int32 clk_error = 0; /* clock error */ -int32 clk_delay[8] = /* clock intervals */ - { 50, 500, 5000, 50000, 500000, 5000000, 50000000, 50000000 }; +int32 clk_ctr = 0; /* clock counter */ +int32 clk_time[8] = /* clock intervals */ + { 155, 1550, 15500, 155000, 155000, 155000, 155000, 155000 }; +int32 clk_tps[8] = /* clock tps */ + { 10000, 1000, 100, 10, 10, 10, 10, 10 }; +int32 clk_rpt[8] = /* number of repeats */ + { 1, 1, 1, 1, 10, 100, 1000, 10000 }; +DEVICE ptr_dev, ptp_dev, tty_dev, clk_dev; int32 ptrio (int32 inst, int32 IR, int32 dat); t_stat ptr_svc (UNIT *uptr); t_stat ptr_reset (DEVICE *dptr); -t_stat ptr_boot (int32 unitno); +t_stat ptr_boot (int32 unitno, DEVICE *dptr); int32 ptpio (int32 inst, int32 IR, int32 dat); t_stat ptp_svc (UNIT *uptr); t_stat ptp_reset (DEVICE *dptr); @@ -78,9 +106,11 @@ int32 ttyio (int32 inst, int32 IR, int32 dat); t_stat tti_svc (UNIT *uptr); t_stat tto_svc (UNIT *uptr); t_stat tty_reset (DEVICE *dptr); +t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); int32 clkio (int32 inst, int32 IR, int32 dat); t_stat clk_svc (UNIT *uptr); t_stat clk_reset (DEVICE *dptr); +int32 clk_delay (int32 flg); /* PTR data structures @@ -90,7 +120,7 @@ t_stat clk_reset (DEVICE *dptr); ptr_reg PTR register list */ -DIB ptr_dib = { PTR, 1, 0, 0, 0, 0, &ptrio }; +DIB ptr_dib = { PTR, 0, 0, 0, 0, &ptrio }; UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), @@ -106,23 +136,19 @@ REG ptr_reg[] = { { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptr_stopioe, 0) }, { ORDATA (DEVNO, ptr_dib.devno, 6), REG_HRO }, - { FLDATA (*DEVENB, ptr_dib.enb, 0), REG_HRO }, { NULL } }; MTAB ptr_mod[] = { - { MTAB_XTD | MTAB_VDV, 0, NULL, "ENABLED", - &set_enb, NULL, &ptr_dib }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "DISABLED", - &set_dis, NULL, &ptr_dib }, { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &ptr_dib }, + &hp_setdev, &hp_showdev, &ptr_dev }, { 0 } }; DEVICE ptr_dev = { "PTR", &ptr_unit, ptr_reg, ptr_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptr_reset, - &ptr_boot, NULL, NULL }; + &ptr_boot, NULL, NULL, + &ptr_dib, DEV_DISABLE }; /* PTP data structures @@ -132,7 +158,7 @@ DEVICE ptr_dev = { ptp_reg PTP register list */ -DIB ptp_dib = { PTP, 1, 0, 0, 0, 0, &ptpio }; +DIB ptp_dib = { PTP, 0, 0, 0, 0, &ptpio }; UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; @@ -147,23 +173,19 @@ REG ptp_reg[] = { { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptp_stopioe, 0) }, { ORDATA (DEVNO, ptp_dib.devno, 6), REG_HRO }, - { FLDATA (*DEVENB, ptr_dib.enb, 0), REG_HRO }, { NULL } }; MTAB ptp_mod[] = { - { MTAB_XTD | MTAB_VDV, 0, NULL, "ENABLED", - &set_enb, NULL, &ptp_dib }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "DISABLED", - &set_dis, NULL, &ptp_dib }, { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &ptp_dib }, + &hp_setdev, &hp_showdev, &ptp_dev }, { 0 } }; DEVICE ptp_dev = { "PTP", &ptp_unit, ptp_reg, ptp_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptp_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &ptp_dib, DEV_DISABLE }; /* TTY data structures @@ -177,12 +199,12 @@ DEVICE ptp_dev = { #define TTO 1 #define TTP 2 -DIB tty_dib = { TTY, 1, 0, 0, 0, 0, &ttyio }; +DIB tty_dib = { TTY, 0, 0, 0, 0, &ttyio }; UNIT tty_unit[] = { { UDATA (&tti_svc, UNIT_UC, 0), KBD_POLL_WAIT }, - { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT }, - { UDATA (&tto_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT } }; + { UDATA (&tto_svc, UNIT_UC, 0), SERIAL_OUT_WAIT }, + { UDATA (&tto_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_8B, 0), SERIAL_OUT_WAIT } }; REG tty_reg[] = { { ORDATA (BUF, tty_buf, 8) }, @@ -198,21 +220,22 @@ REG tty_reg[] = { { DRDATA (PPOS, tty_unit[TTP].pos, 32), PV_LEFT }, { FLDATA (STOP_IOE, ttp_stopioe, 0) }, { ORDATA (DEVNO, tty_dib.devno, 6), REG_HRO }, - { FLDATA (UC, tty_unit[TTI].flags, UNIT_V_UC), REG_HRO }, { NULL } }; MTAB tty_mod[] = { - { UNIT_UC, 0, "lower case", "LC", NULL }, - { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, + { UNIT_UC+UNIT_8B, UNIT_UC, "UC", "UC", &tty_set_mode }, + { UNIT_UC+UNIT_8B, 0 , "7b", "7B", &tty_set_mode }, + { UNIT_UC+UNIT_8B, UNIT_8B, "8b", "8B", &tty_set_mode }, { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &tty_dib }, + &hp_setdev, &hp_showdev, &tty_dev }, { 0 } }; DEVICE tty_dev = { "TTY", tty_unit, tty_reg, tty_mod, 3, 10, 31, 1, 8, 8, NULL, NULL, &tty_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &tty_dib, 0 }; /* CLK data structures @@ -222,32 +245,36 @@ DEVICE tty_dev = { clk_reg CLK register list */ -DIB clk_dib = { CLK, 1, 0, 0, 0, 0, &clkio }; +DIB clk_dib = { CLK, 0, 0, 0, 0, &clkio }; UNIT clk_unit = { UDATA (&clk_svc, 0, 0) }; REG clk_reg[] = { { ORDATA (SEL, clk_select, 3) }, + { DRDATA (CTR, clk_ctr, 14) }, { FLDATA (CMD, clk_dib.cmd, 0), REG_HRO }, { FLDATA (CTL, clk_dib.ctl, 0) }, { FLDATA (FLG, clk_dib.flg, 0) }, { FLDATA (FBF, clk_dib.fbf, 0) }, { FLDATA (ERR, clk_error, CLK_V_ERROR) }, - { BRDATA (TIME, clk_delay, 8, 31, 8) }, + { BRDATA (TIME, clk_time, 10, 24, 8) }, { ORDATA (DEVNO, clk_dib.devno, 6), REG_HRO }, { NULL } }; MTAB clk_mod[] = { + { UNIT_DIAG, UNIT_DIAG, "DIAG", "DIAG", NULL }, + { UNIT_DIAG, 0, "CALIBRATED", "CALIBRATED", NULL }, { MTAB_XTD | MTAB_VDV, 0, "DEVNO", "DEVNO", - &hp_setdev, &hp_showdev, &clk_dib }, + &hp_setdev, &hp_showdev, &clk_dev }, { 0 } }; DEVICE clk_dev = { "CLK", &clk_unit, clk_reg, clk_mod, 1, 0, 0, 0, 0, 0, NULL, NULL, &clk_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &clk_dib, 0 }; /* Paper tape reader: IOT routine */ @@ -255,10 +282,10 @@ int32 ptrio (int32 inst, int32 IR, int32 dat) { int32 dev; -dev = IR & DEVMASK; /* get device no */ +dev = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & HC) == 0) { setFLG (dev); } /* STF */ + if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; @@ -273,16 +300,17 @@ case ioLIX: /* load */ dat = ptr_unit.buf; break; case ioCTL: /* control clear/set */ - if (IR & AB) { /* CLC */ - clrCMD (dev); /* clear cmd, ctl */ - clrCTL (dev); } - else { setCMD (dev); /* STC */ - setCTL (dev); /* set cmd, ctl */ - sim_activate (&ptr_unit, ptr_unit.wait); } + if (IR & I_CTL) { /* CLC */ + clrCMD (dev); /* clear cmd, ctl */ + clrCTL (dev); } + else { /* STC */ + setCMD (dev); /* set cmd, ctl */ + setCTL (dev); + sim_activate (&ptr_unit, ptr_unit.wait); } break; default: break; } -if (IR & HC) { clrFLG (dev); } /* H/C option */ +if (IR & I_HC) { clrFLG (dev); } /* H/C option */ return dat; } @@ -298,8 +326,8 @@ if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */ return IORETURN (ptr_stopioe, SCPE_UNATT); if ((temp = getc (ptr_unit.fileref)) == EOF) { /* read byte */ if (feof (ptr_unit.fileref)) { - if (ptr_stopioe) printf ("PTR end of file\n"); - else return SCPE_OK; } + if (ptr_stopioe) printf ("PTR end of file\n"); + else return SCPE_OK; } else perror ("PTR I/O error"); clearerr (ptr_unit.fileref); return SCPE_IOERR; } @@ -320,38 +348,76 @@ sim_cancel (&ptr_unit); /* deactivate unit */ return SCPE_OK; } -/* Paper tape reader bootstrap routine */ +/* Paper tape reader bootstrap routine (HP 12992K ROM) */ #define CHANGE_DEV (1 << 24) -#define PBOOT_MASK 077 -#define PBOOT_SIZE (sizeof (pboot) / sizeof (int32)) +#define CHANGE_ADDR (1 << 23) -static const int32 pboot[] = { -0107700, 0063770, 0106501, 0004010, -0002400, 0006020, 0063771, 0073736, -0006401, 0067773, 0006006, 0027717, -0107700, 0102077, 0027700, 0017762, -0002003, 0027712, 0003104, 0073774, -0017762, 0017753, 0070001, 0073775, -0063775, 0043772, 0002040, 0027751, -0017753, 0044000, 0000000, 0002101, -0102000, 0037775, 0037774, 0027730, -0017753, 0054000, 0027711, 0102011, -0027700, 0102055, 0027700, 0000000, -0017762, 0001727, 0073776, 0017762, -0033776, 0127753, 0000000, 0103700+CHANGE_DEV, -0102300+CHANGE_DEV, 0027764, 0102500+CHANGE_DEV, 0127762, -0173775, 0153775, 0170100, 0177765 }; +static const int32 pboot[IBL_LNT] = { + 0107700, /*ST CLC 0,C ; intr off */ + 0002401, /* CLA,RSS ; skip in */ + 0063756, /*CN LDA M11 ; feed frame */ + 0006700, /* CLB,CCE ; set E to rd byte */ + 0017742, /* JSB READ ; get #char */ + 0007306, /* CMB,CCE,INB,SZB ; 2's comp */ + 0027713, /* JMP *+5 ; non-zero byte */ + 0002006, /* INA,SZA ; feed frame ctr */ + 0027703, /* JMP *-3 */ + 0102077, /* HLT 77B ; stop */ + 0027700, /* JMP ST ; next */ + 0077754, /* STA WC ; word in rec */ + 0017742, /* JSB READ ; get feed frame */ + 0017742, /* JSB READ ; get address */ + 0074000, /* STB 0 ; init csum */ + 0077755, /* STB AD ; save addr */ + 0067755, /*CK LDB AD ; check addr */ + 0047777, /* ADB MAXAD ; below loader */ + 0002040, /* SEZ ; E =0 => OK */ + 0027740, /* JMP H55 */ + 0017742, /* JSB READ ; get word */ + 0040001, /* ADA 1 ; cont checksum */ + 0177755, /* STA AD,I ; store word */ + 0037755, /* ISZ AD */ + 0000040, /* CLE ; force wd read */ + 0037754, /* ISZ WC ; block done? */ + 0027720, /* JMP CK ; no */ + 0017742, /* JSB READ ; get checksum */ + 0054000, /* CPB 0 ; ok? */ + 0027702, /* JMP CN ; next block */ + 0102011, /* HLT 11 ; bad csum */ + 0027700, /* JMP ST ; next */ + 0102055, /*H55 HALT 55 ; bad address */ + 0027700, /* JMP ST ; next */ + 0000000, /*RD 0 */ + 0006600, /* CLB,CME ; E reg byte ptr */ + 0103700+CHANGE_DEV, /* STC RDR,C ; start reader */ + 0102300+CHANGE_DEV, /* SFS RDR ; wait */ + 0027745, /* JMP *-1 */ + 0106400+CHANGE_DEV, /* MIB RDR ; get byte */ + 0002041, /* SEZ,RSS ; E set? */ + 0127742, /* JMP RD,I ; no, done */ + 0005767, /* BLF,CLE,BLF ; shift byte */ + 0027744, /* JMP RD+2 ; again */ + 0000000, /*WC 000000 ; word count */ + 0000000, /*AD 000000 ; address */ + 0177765, /*M11 -11 ; feed count */ + 0, 0, 0, 0, 0, 0, 0, 0, /* unused */ + 0, 0, 0, 0, 0, 0, 0, /* unused */ + CHANGE_ADDR }; /*MAXAD -ST ; max addr */ -t_stat ptr_boot (int32 unit) +t_stat ptr_boot (int32 unitno, DEVICE *dptr) { int32 i, dev; dev = ptr_dib.devno; /* get device no */ -PC = (MEMSIZE - 1) & ~PBOOT_MASK; /* start at mem top */ -for (i = 0; i < PBOOT_SIZE; i++) /* copy bootstrap */ - M[PC + i] = (pboot[i] & CHANGE_DEV)? /* insert ptr dev no */ - ((pboot[i] | dev) & DMASK): pboot[i]; +PC = ((MEMSIZE - 1) & ~IBL_MASK) & VAMASK; /* start at mem top */ +SR = IBL_PTR + (dev << IBL_V_DEV); /* set SR */ +for (i = 0; i < IBL_LNT; i++) { /* copy bootstrap */ + if (pboot[i] & CHANGE_ADDR) /* memory limit? */ + M[PC + i] = (-PC) & DMASK; + else if (pboot[i] & CHANGE_DEV) /* IO instr? */ + M[PC + i] = (pboot[i] + dev) & DMASK; + else M[PC + i] = pboot[i]; } return SCPE_OK; } @@ -361,10 +427,10 @@ int32 ptpio (int32 inst, int32 IR, int32 dat) { int32 dev; -dev = IR & DEVMASK; /* get device no */ +dev = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & HC) == 0) { setFLG (dev); } /* STF */ + if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; @@ -376,22 +442,23 @@ case ioLIX: /* load */ dat = 0; case ioMIX: /* merge */ if ((ptp_unit.flags & UNIT_ATT) == 0) - dat = dat | PTP_LOW; /* out of tape? */ + dat = dat | PTP_LOW; /* out of tape? */ break; case ioOTX: /* output */ ptp_unit.buf = dat; break; case ioCTL: /* control clear/set */ - if (IR & AB) { /* CLC */ - clrCMD (dev); /* clear cmd, ctl */ - clrCTL (dev); } - else { setCMD (dev); /* STC */ - setCTL (dev); /* set cmd, ctl */ - sim_activate (&ptp_unit, ptp_unit.wait); } + if (IR & I_CTL) { /* CLC */ + clrCMD (dev); /* clear cmd, ctl */ + clrCTL (dev); } + else { /* STC */ + setCMD (dev); /* set cmd, ctl */ + setCTL (dev); + sim_activate (&ptp_unit, ptp_unit.wait); } break; default: break; } -if (IR & HC) { clrFLG (dev); } /* H/C option */ +if (IR & I_HC) { clrFLG (dev); } /* H/C option */ return dat; } @@ -431,10 +498,10 @@ int32 ttyio (int32 inst, int32 IR, int32 dat) { int32 dev; -dev = IR & DEVMASK; /* get device no */ +dev = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & HC) == 0) { setFLG (dev); } /* STF */ + if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; @@ -447,74 +514,77 @@ case ioLIX: /* load */ case ioMIX: /* merge */ dat = dat | tty_buf; if (!(tty_mode & TM_KBD) && sim_is_active (&tty_unit[TTO])) - dat = dat | TP_BUSY; + dat = dat | TP_BUSY; break; case ioOTX: /* output */ - if (dat & TM_MODE) tty_mode = dat; - else tty_buf = dat & 0377; + if (dat & TM_MODE) tty_mode = dat & (TM_KBD|TM_PRI|TM_PUN); + tty_buf = dat & 0377; break; case ioCTL: /* control clear/set */ - if (IR & AB) { clrCTL (dev); } /* CLC */ - else { setCTL (dev); /* STC */ - if (!(tty_mode & TM_KBD)) /* output? */ - sim_activate (&tty_unit[TTO], tty_unit[TTO].wait); } + if (IR & I_CTL) { clrCTL (dev); } /* CLC */ + else { /* STC */ + setCTL (dev); + if (!(tty_mode & TM_KBD)) /* output? */ + sim_activate (&tty_unit[TTO], tty_unit[TTO].wait); } break; default: break; } -if (IR & HC) { clrFLG (dev); } /* H/C option */ +if (IR & I_HC) { clrFLG (dev); } /* H/C option */ return dat; } /* Unit service routines */ -t_stat tto_out (int32 ch) +t_stat tto_out (int32 c) { t_stat ret = SCPE_OK; if (tty_mode & TM_PRI) { /* printing? */ - ch = ch & 0177; - if ((tty_unit[TTI].flags & UNIT_UC) && islower (ch)) /* upper case? */ - ch = toupper (ch); - ret = sim_putchar (ch & 0177); /* output char */ + if (tty_unit[TTO].flags & UNIT_UC) { /* UC only? */ + c = c & 0177; + if (islower (c)) c = toupper (c); } + else c = c & ((tty_unit[TTO].flags & UNIT_8B)? 0377: 0177); + ret = sim_putchar (c); /* output char */ tty_unit[TTO].pos = tty_unit[TTO].pos + 1; } if (tty_mode & TM_PUN) { /* punching? */ if ((tty_unit[TTP].flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (ttp_stopioe, SCPE_UNATT); - if (putc (ch, tty_unit[TTP].fileref) == EOF) { /* output char */ - perror ("TTP I/O error"); - clearerr (tty_unit[TTP].fileref); - return SCPE_IOERR; } + return IORETURN (ttp_stopioe, SCPE_UNATT); + if (putc (c, tty_unit[TTP].fileref) == EOF) { /* output char */ + perror ("TTP I/O error"); + clearerr (tty_unit[TTP].fileref); + return SCPE_IOERR; } tty_unit[TTP].pos = ftell (tty_unit[TTP].fileref); } return ret; } t_stat tti_svc (UNIT *uptr) { -int32 temp, dev; +int32 c, dev; dev = tty_dib.devno; /* get device no */ sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* continue poll */ -if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */ -temp = temp & 0177; -if ((tty_unit[TTI].flags & UNIT_UC) && islower (temp)) /* force upper case? */ - temp = toupper (temp); +if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */ +if (tty_unit[TTI].flags & UNIT_UC) { /* UC only? */ + c = c & 0177; + if (islower (c)) c = toupper (c); } +else c = c & ((tty_unit[TTI].flags & UNIT_8B)? 0377: 0177); if (tty_mode & TM_KBD) { /* keyboard enabled? */ - tty_buf = temp; /* put char in buf */ + tty_buf = c; /* put char in buf */ tty_unit[TTI].pos = tty_unit[TTI].pos + 1; setFLG (dev); /* set flag */ - return tto_out (temp); } /* echo or punch? */ + return tto_out (c); } /* echo or punch? */ return SCPE_OK; } t_stat tto_svc (UNIT *uptr) { -int32 ch, dev; +int32 c, dev; dev = tty_dib.devno; /* get device no */ setFLG (dev); /* set done flag */ -ch = tty_buf; +c = tty_buf; tty_buf = 0377; /* defang buf */ -return tto_out (ch); /* print and/or punch */ +return tto_out (c); /* print and/or punch */ } /* Reset routine */ @@ -523,12 +593,22 @@ t_stat tty_reset (DEVICE *dptr) { tty_dib.cmd = tty_dib.ctl = 0; /* clear cmd, ctl */ tty_dib.flg = tty_dib.fbf = 1; /* set flg, fbf */ -tty_mode = 0; +tty_mode = TM_KBD; /* enable input */ tty_buf = 0; sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* activate poll */ sim_cancel (&tty_unit[TTO]); /* cancel output */ return SCPE_OK; } + +t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 u = uptr - tty_dev.units; + +if (u > 1) return SCPE_NOFNC; +tty_unit[TTI].flags = (tty_unit[TTI].flags & ~(UNIT_UC | UNIT_8B)) | val; +tty_unit[TTO].flags = (tty_unit[TTO].flags & ~(UNIT_UC | UNIT_8B)) | val; +return SCPE_OK; +} /* Clock: IOT routine */ @@ -536,10 +616,10 @@ int32 clkio (int32 inst, int32 IR, int32 dat) { int32 dev; -dev = IR & DEVMASK; /* get device no */ +dev = IR & I_DEVMASK; /* get device no */ switch (inst) { /* case on opcode */ case ioFLG: /* flag clear/set */ - if ((IR & HC) == 0) { setFLG (dev); } /* STF */ + if ((IR & I_HC) == 0) { setFLG (dev); } /* STF */ break; case ioSFC: /* skip flag clear */ if (FLG (dev) == 0) PC = (PC + 1) & VAMASK; @@ -554,19 +634,25 @@ case ioLIX: /* load */ dat = clk_error; break; case ioOTX: /* output */ - clk_select = dat & 07; + clk_select = dat & 07; /* save select */ + sim_cancel (&clk_unit); /* stop the clock */ + clrCTL (dev); /* clear control */ break; case ioCTL: /* control clear/set */ - if (IR & AB) { /* CLC */ - clrCTL (dev); /* turn off clock */ - sim_cancel (&clk_unit); } /* deactivate unit */ - else { setCTL (dev); /* turn on clock */ - clk_error = 0; /* clear error */ - sim_activate (&clk_unit, clk_delay[clk_select]); } + if (IR & I_CTL) { /* CLC */ + clrCTL (dev); /* turn off clock */ + sim_cancel (&clk_unit); } /* deactivate unit */ + else { /* STC */ + setCTL (dev); /* set CTL */ + if (!sim_is_active (&clk_unit)) { /* clock running? */ + sim_activate (&clk_unit, + sim_rtc_init (clk_delay (0))); /* no, start clock */ + clk_ctr = clk_delay (1); } /* set repeat ctr */ + clk_error = 0; } /* clear error */ break; default: break; } -if (IR & HC) { clrFLG (dev); } /* H/C option */ +if (IR & I_HC) { clrFLG (dev); } /* H/C option */ return dat; } @@ -574,11 +660,20 @@ return dat; t_stat clk_svc (UNIT *uptr) { -int32 dev; +int32 tim, dev; dev = clk_dib.devno; /* get device no */ -if (FLG (dev)) clk_error = CLK_ERROR; /* overrun? */ -setFLG (dev); /* set device flag */ +if (!CTL (dev)) return SCPE_OK; /* CTL off? done */ +if (clk_unit.flags & UNIT_DIAG) /* diag mode? */ + tim = clk_delay (0); /* get fixed delay */ +else tim = sim_rtc_calb (clk_tps[clk_select]); /* calibrate delay */ +sim_activate (uptr, tim); /* reactivate */ +clk_ctr = clk_ctr - 1; /* decrement counter */ +if (clk_ctr <= 0) { /* end of interval? */ + tim = FLG (dev); + if (FLG (dev)) clk_error = CLK_ERROR; /* overrun? error */ + else { setFLG (dev); } /* else set flag */ + clk_ctr = clk_delay (1); } /* reset counter */ return SCPE_OK; } @@ -590,6 +685,18 @@ clk_dib.cmd = clk_dib.ctl = 0; /* clear cmd, ctl */ clk_dib.flg = clk_dib.fbf = 1; /* set flg, fbf */ clk_error = 0; /* clear error */ clk_select = 0; /* clear select */ +clk_ctr = 0; /* clear counter */ sim_cancel (&clk_unit); /* deactivate unit */ return SCPE_OK; } + +/* Clock delay routine */ + +int32 clk_delay (int32 flg) +{ +int32 sel = clk_select; + +if ((clk_unit.flags & UNIT_DIAG) && (sel >= 4)) sel = sel - 3; +if (flg) return clk_rpt[sel]; +else return clk_time[sel]; +} diff --git a/HP2100/hp2100_sys.c b/HP2100/hp2100_sys.c index 287d8180..5b335e80 100644 --- a/HP2100/hp2100_sys.c +++ b/HP2100/hp2100_sys.c @@ -43,7 +43,8 @@ extern DEVICE cpu_dev; extern UNIT cpu_unit; extern DEVICE dma0_dev, dma1_dev; extern DEVICE ptr_dev, ptp_dev; -extern DEVICE tty_dev, clk_dev, lpt_dev; +extern DEVICE tty_dev, clk_dev; +extern DEVICE lps_dev, lpt_dev; extern DEVICE mtd_dev, mtc_dev; extern DEVICE msd_dev, msc_dev; extern DEVICE dpd_dev, dpc_dev; @@ -69,17 +70,22 @@ REG *sim_PC = &cpu_reg[0]; int32 sim_emax = 3; -DEVICE *sim_devices[] = { &cpu_dev, - &dma0_dev, &dma1_dev, - &ptr_dev, &ptp_dev, +DEVICE *sim_devices[] = { + &cpu_dev, + &dma0_dev, + &dma1_dev, + &ptr_dev, + &ptp_dev, &tty_dev, - &clk_dev, &lpt_dev, + &clk_dev, + &lps_dev, + &lpt_dev, &dpd_dev, &dpc_dev, &dqd_dev, &dqc_dev, &drd_dev, &drc_dev, &mtd_dev, &mtc_dev, &msd_dev, &msc_dev, - &muxu_dev, &muxl_dev, &muxc_dev, + &muxl_dev, &muxu_dev, &muxc_dev, NULL }; const char *sim_stop_messages[] = { @@ -88,7 +94,8 @@ const char *sim_stop_messages[] = { "Non-existent I/O device", "HALT instruction", "Breakpoint", - "Indirect address loop" }; + "Indirect address loop", + "Indirect address interrupt (should not happen!)" }; /* Binary loader @@ -121,17 +128,17 @@ int32 origin, csum, zerocnt, count, word, i; if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; for (zerocnt = 1;; zerocnt = -10) { /* block loop */ for (;; zerocnt++) { /* skip 0's */ - if ((count = fgetc (fileref)) == EOF) return SCPE_OK; - else if (count) break; - else if (zerocnt == 0) return SCPE_OK; } + if ((count = fgetc (fileref)) == EOF) return SCPE_OK; + else if (count) break; + else if (zerocnt == 0) return SCPE_OK; } if (fgetc (fileref) == EOF) return SCPE_FMT; if ((origin = fgetw (fileref)) < 0) return SCPE_FMT; csum = origin; /* seed checksum */ for (i = 0; i < count; i++) { /* get data words */ - if ((word = fgetw (fileref)) < 0) return SCPE_FMT; - if (MEM_ADDR_OK (origin)) M[origin] = word; - origin = origin + 1; - csum = csum + word; } + if ((word = fgetw (fileref)) < 0) return SCPE_FMT; + if (MEM_ADDR_OK (origin)) M[origin] = word; + origin = origin + 1; + csum = csum + word; } if ((word = fgetw (fileref)) < 0) return SCPE_FMT; if ((word ^ csum) & DMASK) return SCPE_CSUM; } return SCPE_OK; @@ -172,8 +179,8 @@ static const char *opcode[] = { "XOR", "JMP", "IOR", "ISZ", "ADA", "ADB" ,"CPA", "CPB", "LDA", "LDB", "STA", "STB", - "ASL", "LSL", "RRL", - "ASR", "LSR", "RRR", + "DIAG", "ASL", "LSL", "TIMER", + "RRL", "ASR", "LSR", "RRR", "MPY", "DIV", "DLD", "DST", "FAD", "FSB", "FMP", "FDV", "FIX", "FLT", @@ -214,8 +221,8 @@ static const int32 opc_val[] = { 0020000+I_MRF, 0024000+I_MRF, 0030000+I_MRF, 0034000+I_MRF, 0040000+I_MRF, 0044000+I_MRF, 0050000+I_MRF, 0054000+I_MRF, 0060000+I_MRF, 0064000+I_MRF, 0070000+I_MRF, 0074000+I_MRF, - 0100020+I_ESH, 0100040+I_ESH, 0100100+I_ESH, - 0101020+I_ESH, 0101040+I_ESH, 0101100+I_ESH, + 0100000+I_NPN, 0100020+I_ESH, 0100040+I_ESH, 0100060+I_NPN, + 0100100+I_ESH, 0101020+I_ESH, 0101040+I_ESH, 0101100+I_ESH, 0100200+I_EMR, 0100400+I_EMR, 0104200+I_EMR, 0104400+I_EMR, 0105000+I_EMR, 0105020+I_EMR, 0105040+I_EMR, 0105060+I_EMR, 0105100+I_NPN, 0105120+I_NPN, @@ -329,16 +336,16 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ break; case I_V_NPC: /* no operands + C */ fprintf (of, "%s", opcode[i]); - if (inst & HC) fprintf (of, " C"); + if (inst & I_HC) fprintf (of, " C"); break; case I_V_MRF: /* mem ref */ - disp = inst & DISP; /* displacement */ + disp = inst & I_DISP; /* displacement */ fprintf (of, "%s ", opcode[i]); /* opcode */ - if (inst & CP) { /* current page? */ - if (cflag) fprintf (of, "%-o", (addr & PAGENO) | disp); - else fprintf (of, "C %-o", disp); } + if (inst & I_CP) { /* current page? */ + if (cflag) fprintf (of, "%-o", (addr & I_PAGENO) | disp); + else fprintf (of, "C %-o", disp); } else fprintf (of, "%-o", disp); /* page zero */ - if (inst & IA) fprintf (of, ",I"); + if (inst & I_IA) fprintf (of, ",I"); break; case I_V_ASH: /* shift, alter-skip */ cm = FALSE; @@ -357,24 +364,24 @@ for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ break; case I_V_EMR: /* extended mem ref */ fprintf (of, "%s %-o", opcode[i], val[1] & VAMASK); - if (val[1] & IA) fprintf (of, ",I"); + if (val[1] & I_IA) fprintf (of, ",I"); return -1; /* extra word */ case I_V_IO1: /* IOT with H/C */ - fprintf (of, "%s %-o", opcode[i], inst & DEVMASK); - if (inst & HC) fprintf (of, ",C"); + fprintf (of, "%s %-o", opcode[i], inst & I_DEVMASK); + if (inst & I_HC) fprintf (of, ",C"); break; case I_V_IO2: /* IOT */ - fprintf (of, "%s %-o", opcode[i], inst & DEVMASK); + fprintf (of, "%s %-o", opcode[i], inst & I_DEVMASK); break; case I_V_EGZ: /* ext grp 1 op + 0 */ fprintf (of, "%s %-o", opcode[i], val[1] & VAMASK); - if (val[1] & IA) fprintf (of, ",I"); + if (val[1] & I_IA) fprintf (of, ",I"); return -2; /* extra words */ case I_V_EG2: /* ext grp 2 op */ fprintf (of, "%s %-o", opcode[i], val[1] & VAMASK); - if (val[1] & IA) fprintf (of, ",I"); + if (val[1] & I_IA) fprintf (of, ",I"); fprintf (of, " %-o", val[2] & VAMASK); - if (val[2] & IA) fprintf (of, ",I"); + if (val[2] & I_IA) fprintf (of, ",I"); return -2; } /* extra words */ return SCPE_OK; } /* end if */ } /* end for */ @@ -401,8 +408,9 @@ d = get_uint (gbuf, 8, VAMASK, &r); /* construe as addr */ if (r != SCPE_OK) return -1; if (*cptr != 0) { /* more? */ cptr = get_glyph (cptr, gbuf, 0); /* look for indirect */ - if (strcmp (gbuf, "I")) return -1; - d = d | IA; } + if (*cptr != 0) return -1; /* should be done */ + if (strcmp (gbuf, "I")) return -1; /* I? */ + d = d | I_IA; } return d; } @@ -450,21 +458,21 @@ if (opcode[i]) { /* found opcode? */ break; case I_V_NPC: /* no operand + C */ if (*cptr != 0) { - cptr = get_glyph (cptr, gbuf, 0); - if (strcmp (gbuf, "C")) return SCPE_ARG; - val[0] = val[0] | HC; } + cptr = get_glyph (cptr, gbuf, 0); + if (strcmp (gbuf, "C")) return SCPE_ARG; + val[0] = val[0] | I_HC; } break; case I_V_MRF: /* mem ref */ cptr = get_glyph (cptr, gbuf, 0); /* get next field */ if (k = (strcmp (gbuf, "C") == 0)) { /* C specified? */ - val[0] = val[0] | CP; - cptr = get_glyph (cptr, gbuf, 0); } + val[0] = val[0] | I_CP; + cptr = get_glyph (cptr, gbuf, 0); } else if (k = (strcmp (gbuf, "Z") == 0)) { /* Z specified? */ - cptr = get_glyph (cptr, gbuf, ','); } + cptr = get_glyph (cptr, gbuf, ','); } if ((d = get_addr (gbuf)) < 0) return SCPE_ARG; - if ((d & VAMASK) <= DISP) val[0] = val[0] | d; - else if (cflag && !k && (((addr ^ d) & PAGENO) == 0)) - val[0] = val[0] | (d & (IA | DISP)) | CP; + if ((d & VAMASK) <= I_DISP) val[0] = val[0] | d; + else if (cflag && !k && (((addr ^ d) & I_PAGENO) == 0)) + val[0] = val[0] | (d & (I_IA | I_DISP)) | I_CP; else return SCPE_ARG; break; case I_V_ESH: /* extended shift */ @@ -481,17 +489,17 @@ if (opcode[i]) { /* found opcode? */ break; case I_V_IO1: /* IOT + optional C */ cptr = get_glyph (cptr, gbuf, ','); /* get device */ - d = get_uint (gbuf, 8, DEVMASK, &r); + d = get_uint (gbuf, 8, I_DEVMASK, &r); if (r != SCPE_OK) return SCPE_ARG; val[0] = val[0] | d; if (*cptr != 0) { - cptr = get_glyph (cptr, gbuf, 0); - if (strcmp (gbuf, "C")) return SCPE_ARG; - val[0] = val[0] | HC; } + cptr = get_glyph (cptr, gbuf, 0); + if (strcmp (gbuf, "C")) return SCPE_ARG; + val[0] = val[0] | I_HC; } break; case I_V_IO2: /* IOT */ cptr = get_glyph (cptr, gbuf, 0); /* get device */ - d = get_uint (gbuf, 8, DEVMASK, &r); + d = get_uint (gbuf, 8, I_DEVMASK, &r); if (r != SCPE_OK) return SCPE_ARG; val[0] = val[0] | d; break; @@ -548,21 +556,22 @@ val[0] = 0; for (cptr = get_glyph (iptr, gbuf, ','); gbuf[0] != 0; cptr = get_glyph (cptr, gbuf, ',')) { /* loop thru glyphs */ if (strcmp (gbuf, "CLE") == 0) { /* CLE? */ - if (clef) return SCPE_ARG; /* already seen? */ - clef = TRUE; /* set flag */ - continue; } + if (clef) return SCPE_ARG; /* already seen? */ + clef = TRUE; /* set flag */ + continue; } for (i = 0; stab[i] != NULL; i++) { /* find subopcode */ - if ((strcmp (gbuf, stab[i]) == 0) && - ((i >= 16) || (!clef && ((val[0] & 001710) == 0)))) break; } + if ((strcmp (gbuf, stab[i]) == 0) && + ((i >= 16) || (!clef && ((val[0] & 001710) == 0)))) break; } if (stab[i] == NULL) return SCPE_ARG; - if (tbits & mtab[i] & (AB | ASKP) & (vtab[i] ^ val[0])) return SCPE_ARG; - if (tbits & mtab[i] & ~(AB | ASKP)) return SCPE_ARG; + if (tbits & mtab[i] & (I_AB | I_ASKP) & (vtab[i] ^ val[0])) + return SCPE_ARG; + if (tbits & mtab[i] & ~(I_AB | I_ASKP)) return SCPE_ARG; tbits = tbits | mtab[i]; /* fill type+mask */ val[0] = val[0] | vtab[i]; } /* fill value */ if (clef) { /* CLE seen? */ - if (val[0] & ASKP) { /* alter-skip? */ - if (tbits & 0100) return SCPE_ARG; /* already filled in? */ - else val[0] = val[0] | 0100; } + if (val[0] & I_ASKP) { /* alter-skip? */ + if (tbits & 0100) return SCPE_ARG; /* already filled in? */ + else val[0] = val[0] | 0100; } else val[0] = val[0] | 040; } /* fill in shift */ return ret; } diff --git a/I1401/i1401_cd.c b/I1401/i1401_cd.c index 7501859d..a6c6c990 100644 --- a/I1401/i1401_cd.c +++ b/I1401/i1401_cd.c @@ -51,7 +51,7 @@ extern char ascii_to_bcd[128]; int32 s1sel, s2sel, s4sel, s8sel; char rbuf[CBUFSIZE]; /* > CDR_WIDTH */ t_stat cdr_svc (UNIT *uptr); -t_stat cdr_boot (int32 unitno); +t_stat cdr_boot (int32 unitno, DEVICE *dptr); t_stat cdr_attach (UNIT *uptr, char *cptr); t_stat cd_reset (DEVICE *dptr); @@ -158,7 +158,7 @@ if (ferror (cdr_unit.fileref)) { /* error? */ return SCPE_OK; } cdr_unit.pos = ftell (cdr_unit.fileref); /* update position */ if (ssa) { /* if last cd on */ - i = getc (cdr_unit.fileref); /* see if more */ + getc (cdr_unit.fileref); /* see if more */ if (feof (cdr_unit.fileref)) ind[IN_LST] = 1; /* eof? set flag */ fseek (cdr_unit.fileref, cdr_unit.pos, SEEK_SET); } for (i = 0; i < CDR_WIDTH; i++) { /* cvt to BCD */ @@ -181,17 +181,17 @@ int32 i; if (s1sel) uptr = &stack_unit[1]; /* stacker 1? */ else if (s2sel) uptr = &stack_unit[2]; /* stacker 2? */ else uptr = &stack_unit[0]; /* then default */ -if ((uptr -> flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */ +if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */ for (i = 0; i < CDR_WIDTH; i++) rbuf[i] = bcd_to_ascii[rbuf[i]]; for (i = CDR_WIDTH - 1; (i >= 0) && (rbuf[i] == ' '); i--) rbuf[i] = 0; rbuf[CDR_WIDTH] = 0; /* null at end */ -fputs (rbuf, uptr -> fileref); /* write card */ -fputc ('\n', uptr -> fileref); /* plus new line */ -if (ferror (uptr -> fileref)) { /* error? */ +fputs (rbuf, uptr->fileref); /* write card */ +fputc ('\n', uptr->fileref); /* plus new line */ +if (ferror (uptr->fileref)) { /* error? */ perror ("Card stacker I/O error"); - clearerr (uptr -> fileref); + clearerr (uptr->fileref); if (iochk) return SCPE_IOERR; } -uptr -> pos = ftell (uptr -> fileref); /* update position */ +uptr->pos = ftell (uptr->fileref); /* update position */ return SCPE_OK; } @@ -210,21 +210,21 @@ UNIT *uptr; if (s8sel) uptr = &stack_unit[2]; /* stack 8? */ else if (s4sel) uptr = &stack_unit[4]; /* stack 4? */ else uptr = &cdp_unit; /* normal output */ -if ((uptr -> flags & UNIT_ATT) == 0) return SCPE_UNATT; /* attached? */ +if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; /* attached? */ ind[IN_PNCH] = s4sel = s8sel = 0; /* clear flags */ M[CDP_BUF - 1] = 012; /* set prev loc */ for (i = 0; i < CDP_WIDTH; i++) pbuf[i] = bcd_to_ascii[M[CDP_BUF + i] & CHAR]; for (i = CDP_WIDTH - 1; (i >= 0) && (pbuf[i] == ' '); i--) pbuf[i] = 0; pbuf[CDP_WIDTH] = 0; /* trailing null */ -fputs (pbuf, uptr -> fileref); /* output card */ -fputc ('\n', uptr -> fileref); /* plus new line */ -if (ferror (uptr -> fileref)) { /* error? */ +fputs (pbuf, uptr->fileref); /* output card */ +fputc ('\n', uptr->fileref); /* plus new line */ +if (ferror (uptr->fileref)) { /* error? */ perror ("Card punch I/O error"); - clearerr (uptr -> fileref); + clearerr (uptr->fileref); if (iochk) return SCPE_IOERR; ind[IN_PNCH] = 1; } -uptr -> pos = ftell (uptr -> fileref); /* update position */ +uptr->pos = ftell (uptr->fileref); /* update position */ return SCPE_OK; } @@ -269,7 +269,7 @@ return attach_unit (uptr, cptr); static const unsigned char boot_rom[] = { OP_R + WM, OP_NOP + WM }; /* R, NOP */ -t_stat cdr_boot (int32 unitno) +t_stat cdr_boot (int32 unitno, DEVICE *dptr) { int32 i; extern int32 saved_IS; diff --git a/I1401/i1401_cpu.c b/I1401/i1401_cpu.c index 5c95ca37..c3fb6890 100644 --- a/I1401/i1401_cpu.c +++ b/I1401/i1401_cpu.c @@ -103,8 +103,8 @@ 4. Adding I/O devices. These modules must be modified: - i1401_cpu.c add IO dispatches to iodisp - i1401_sys.c add pointer to data structures to sim_devices + i1401_cpu.c add device dispatching code to iodisp + i1401_sys.c add sim_devices table entry */ #include "i1401_defs.h" @@ -1178,7 +1178,7 @@ as_err = ADDR_ERR (AS); /* get addr err flags */ bs_err = ADDR_ERR (BS); AS = AS & ADDRMASK; /* clean addresses */ BS = BS & ADDRMASK; -pcq_r -> qptr = pcq_p; /* update pc q ptr */ +pcq_r->qptr = pcq_p; /* update pc q ptr */ return reason; } /* end sim_instr */ @@ -1314,7 +1314,7 @@ ind[IN_UNC] = 1; AS = 0; as_err = 1; BS = 0; bs_err = 1; pcq_r = find_reg ("ISQ", NULL, dptr); -if (pcq_r) pcq_r -> qptr = 0; +if (pcq_r) pcq_r->qptr = 0; else return SCPE_IERR; sim_brk_types = sim_brk_dflt = SWMASK ('E'); return SCPE_OK; diff --git a/I1401/i1401_defs.h b/I1401/i1401_defs.h index 5480d674..2ef6e87d 100644 --- a/I1401/i1401_defs.h +++ b/I1401/i1401_defs.h @@ -273,4 +273,4 @@ #define IN_SSG 067 /* sense switch G */ #define IN_READ 072 /* reader error */ -#define CRETIOE(f,c) return ((f)? (c): SCPE_OK) \ No newline at end of file +#define CRETIOE(f,c) return ((f)? (c): SCPE_OK) diff --git a/I1401/i1401_doc.txt b/I1401/i1401_doc.txt index f3100532..0880c940 100644 --- a/I1401/i1401_doc.txt +++ b/I1401/i1401_doc.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik Subj: IBM 1401 Simulator Usage -Date: 15-Jun-2002 +Date: 15-Nov-2002 COPYRIGHT NOTICE @@ -37,9 +37,13 @@ This memorandum documents the IBM 1401 simulator. 1. Simulator Files sim/ sim_defs.h + sim_rev.h + sim_sock.h + sim_tmxr.h scp.c scp_tty.c - sim_rev.c + sim_sock.c + sim_tmxr.c sim/i1401/ i1401_defs.h i1401_cpu.c @@ -297,8 +301,7 @@ pack options include the ability to enable address writing (formatting). SET DPn ADDROFF set unit n address enable off SET DPn ADDRON set unit n address enable on -Units can also be set ONLINE or OFFLINE. Disk data is buffered in -memory; IO errors cannot occur. +Units can also be set ONLINE or OFFLINE. Unlike most simulated disks, the 1311 includes explicit representation for sector addresses. This is to support non-standard formats, such as @@ -327,6 +330,11 @@ The disk pack controller implements these registers: LASTF 3 most recent function TIME 24 seek time +The 1311 has a primative overlapped seek capability. If TIME is set +non-zero, the 1311 will report itself busy for the specified amount +of time following a seek. This allows programs to utilize the seek +time for processing. + Error handling is as follows: error processed as @@ -334,10 +342,8 @@ Error handling is as follows: not attached set DSK indicator if IOCHK set, report error and stop -The 1311 has a primative overlapped seek capability. If TIME is set -non-zero, the 1311 will report itself busy for the specified amount -of time following a seek. This allows programs to utilize the seek -time for processing. +1311 data files are buffered in memory; therefore, end of file and OS +I/O errors cannot occur. 2.6 729 Magnetic Tape (MT) @@ -367,12 +373,11 @@ Error handling is as follows: not attached report error and stop - end of file (read or space) end of physical tape - (write) ignored + end of file set error indicator OS I/O error print error message + set error indicator if IOCHK set, report error and stop - otherwise, set ERR indicator 2.7 Symbolic Display and Input diff --git a/I1401/i1401_dp.c b/I1401/i1401_dp.c index 72270ef1..26dd6a50 100644 --- a/I1401/i1401_dp.c +++ b/I1401/i1401_dp.c @@ -25,7 +25,9 @@ dp 1311 disk pack - 15-Jun-02 Reworked address comparison logic + 18-Oct-02 RMS Fixed bug in address comparison logic + 19-Sep-02 RMS Minor edit for consistency with 1620 + 15-Jun-02 RMS Reworked address comparison logic The 1311 disk pack has 100 cylinders, 10 tracks/cylinder, 20 sectors/track. Each sector contains 106 characters of information: @@ -49,7 +51,6 @@ #define DP_NUMDR 5 /* #drives */ #define UNIT_V_WAE (UNIT_V_UF + 0) /* write addr enab */ #define UNIT_WAE (1 << UNIT_V_WAE) -#define UNIT_W_UF 2 /* #save flags */ /* Disk format */ @@ -105,10 +106,10 @@ t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 flg, int32 wchk); t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 flg, int32 wchk); t_stat dp_wradr (UNIT *uptr, int32 sec, int32 flg); t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 flg); -int32 dp_fndsec (UNIT *uptr, int32 sec, int32 dcf, int32 flg); -t_stat dp_nexsec (UNIT *uptr, int32 psec, int32 dcf, int32 flg); +int32 dp_fndsec (UNIT *uptr, int32 sec, int32 dcf); +t_stat dp_nexsec (UNIT *uptr, int32 psec, int32 dcf); t_bool dp_zeroad (uint8 *ap); -t_bool dp_cmp_ad (uint8 *ap, int32 dcf, int32 flg); +t_bool dp_cmp_ad (uint8 *ap, int32 dcf); int32 dp_trkop (int32 drv, int32 sec); int32 dp_cvt_bcd (int32 ad, int32 len); void dp_cvt_bin (int32 ad, int32 len, int32 val, int32 flg); @@ -146,8 +147,6 @@ REG dp_reg[] = { { DRDATA (TIME, dp_time, 24), PV_LEFT }, { URDATA (CYL, dp_unit[0].CYL, 10, 8, 0, DP_NUMDR, PV_LEFT + REG_RO) }, - { URDATA (FLG, dp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, - DP_NUMDR, REG_HRO) }, { NULL } }; MTAB dp_mod[] = { @@ -175,7 +174,7 @@ t_stat dp_io (int32 fnc, int32 flg, int32 mod) { int32 dcf, drv, sec, psec, cnt, qwc, qzr, diff; UNIT *uptr; -t_stat r = SCPE_OK; +t_stat r; dcf = BS; /* save DCF addr */ qwc = 0; /* not wcheck */ @@ -194,7 +193,7 @@ if ((drv == 0) || (drv & 1) || (drv > BCD_ZERO)) /* bad drive #? */ return STOP_INVDSK; drv = bcd_to_bin[drv] >> 1; /* convert */ uptr = dp_dev.units + drv; /* get unit ptr */ -if ((uptr -> flags & UNIT_ATT) == 0) { /* attached? */ +if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */ ind[IN_DSK] = ind[IN_ACC] = 1; /* no, error */ CRETIOE (iochk, SCPE_UNATT); } @@ -205,10 +204,10 @@ if ((fnc == FNC_SEEK) && /* seek and */ diff = diff >> 1; /* diff is *2 */ if ((M[dcf + DCF_DIR + DCF_DIR_LEN - 1] & ZONE) == BBIT) diff = -diff; /* get sign */ - uptr -> CYL = uptr -> CYL + diff; /* bound seek */ - if (uptr -> CYL < 0) uptr -> CYL = 0; - else if (uptr -> CYL >= DP_NUMCY) { /* too big? */ - uptr -> CYL = 0; /* system hangs */ + uptr->CYL = uptr->CYL + diff; /* bound seek */ + if (uptr->CYL < 0) uptr->CYL = 0; + else if (uptr->CYL >= DP_NUMCY) { /* too big? */ + uptr->CYL = 0; /* system hangs */ return STOP_INVDCY; } sim_activate (&dp_unit[0], dp_time); /* set ctlr busy */ return SCPE_OK; } /* done! */ @@ -217,7 +216,7 @@ sec = dp_cvt_bcd (dcf + DCF_SEC, DCF_SEC_LEN); /* cvt sector */ if ((sec < 0) || (sec >= (DP_NUMDR * DP_TOTSC))) /* bad sector? */ return STOP_INVDSC; if (fnc == FNC_SEEK) { /* seek? */ - uptr -> CYL = (sec / (DP_NUMSF * DP_NUMSC)) % /* set cyl # */ + uptr->CYL = (sec / (DP_NUMSF * DP_NUMSC)) % /* set cyl # */ DP_NUMCY; sim_activate (&dp_unit[0], dp_time); /* set ctlr busy */ return SCPE_OK; } /* done! */ @@ -236,13 +235,13 @@ if (mod == BCD_W) { /* write? */ fnc = fnc + FNC_WOFF; } } /* change to write */ else if (mod == BCD_R) dp_lastf = fnc; /* read? save func */ else return STOP_INVM; /* other? error */ -psec = dp_fndsec (uptr, sec, dcf, flg); /* find sector */ switch (fnc) { /* case on function */ case FNC_RSCO: /* read sec cnt ov */ BS = dcf + DCF_CNT; /* set count back */ /* fall thru */ case FNC_READ: /* read */ + psec = dp_fndsec (uptr, sec, dcf); /* find sector */ if (psec < 0) CRETIOE (iochk, STOP_INVDAD); /* addr cmp error? */ for (;;) { /* loop */ qzr = (--cnt == 0); /* set zero latch */ @@ -254,7 +253,7 @@ case FNC_READ: /* read */ if (qzr) break; /* zero latch? done */ sec++; psec++; /* next sector */ dp_cvt_bin (dcf + DCF_SEC, DCF_SEC_LEN, sec, flg); /* rewr sec */ - if (r = dp_nexsec (uptr, psec, dcf, flg)) break; /* find next */ + if (r = dp_nexsec (uptr, psec, dcf)) break; /* find next */ } break; /* done, clean up */ @@ -278,6 +277,7 @@ case FNC_WRSCO: /* write sec cnt ov */ BS = dcf + DCF_CNT; /* set count back */ /* fall through */ case FNC_WRITE: /* read */ + psec = dp_fndsec (uptr, sec, dcf); /* find sector */ if (psec < 0) CRETIOE (iochk, STOP_INVDAD); /* addr cmp error? */ for (;;) { /* loop */ qzr = (--cnt == 0); /* set zero latch */ @@ -286,12 +286,12 @@ case FNC_WRITE: /* read */ if (qzr) break; /* zero latch? done */ sec++; psec++; /* next sector */ dp_cvt_bin (dcf + DCF_SEC, DCF_SEC_LEN, sec, flg); /* rewr sec */ - if (r = dp_nexsec (uptr, psec, dcf, flg)) break; /* find next */ + if (r = dp_nexsec (uptr, psec, dcf)) break; /* find next */ } break; /* done, clean up */ case FNC_WRTRK: /* write track */ - if ((uptr -> flags & UNIT_WAE) == 0) /* enabled? */ + if ((uptr->flags & UNIT_WAE) == 0) /* enabled? */ return STOP_WRADIS; AS = dcf + 9; /* special AS */ psec = dp_trkop (drv, sec); /* start of track */ @@ -323,7 +323,7 @@ t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 flg, int32 qwc) int32 i; uint8 ac; int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */ -uint8 *ap = ((uint8 *) uptr -> filebuf) + da; /* buf ptr */ +uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */ t_bool zad = dp_zeroad (ap); /* zero address */ static const int32 dec_tab[DP_ADDR] = /* powers of 10 */ { 100000, 10000, 1000, 100, 10, 1} ; @@ -337,13 +337,13 @@ for (i = 0; i < DP_ADDR; i++) { /* copy address */ sec = sec % dec_tab[i]; /* get remainder */ ac = bcd_to_bin[ac]; } /* cvt to BCD */ else ac = *ap; /* addr char */ - if (qwc) { /* wr chk? zad ok */ - if (!zad && (flg? (M[BS] != *ap): /* L? cmp with WM */ - ((M[BS] & CHAR) != (*ap & CHAR)))) { /* M? cmp w/o WM */ + if (qwc) { /* wr chk? skip if zad */ + if (!zad && (flg? (M[BS] != ac): /* L? cmp with WM */ + ((M[BS] & CHAR) != (ac & CHAR)))) { /* M? cmp w/o WM */ ind[IN_DPW] = ind[IN_DSK] = 1; return STOP_WRCHKE; } } - else if (flg) M[BS] = *ap & CHAR; /* load mode */ - else M[BS] = (M[BS] & WM) | (*ap & CHAR); /* move mode */ + else if (flg) M[BS] = ac & CHAR; /* load mode */ + else M[BS] = (M[BS] & WM) | (ac & CHAR); /* move mode */ ap++; BS++; /* adv ptrs */ if (ADDR_ERR (BS)) return STOP_WRAP; } return SCPE_OK; @@ -355,7 +355,7 @@ t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 flg, int32 qwc) { int32 i, lim; int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */ -uint8 *ap = ((uint8 *) uptr -> filebuf) + da + DP_ADDR; /* buf ptr */ +uint8 *ap = ((uint8 *) uptr->filebuf) + da + DP_ADDR; /* buf ptr */ lim = flg? (DP_DATA - 10): DP_DATA; /* load vs move */ for (i = 0; i < lim; i++) { /* copy data */ @@ -380,7 +380,7 @@ t_stat dp_wradr (UNIT *uptr, int32 sec, int32 flg) { int32 i; uint32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */ -uint8 *ap = ((uint8 *) uptr -> filebuf) + da; /* buf ptr */ +uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */ for (i = 0; i < DP_ADDR; i++) { /* copy address */ if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */ @@ -389,7 +389,7 @@ for (i = 0; i < DP_ADDR; i++) { /* copy address */ return STOP_INVDLN; } if (flg) *ap = M[BS] & (WM | CHAR); /* L? copy WM */ else *ap = M[BS] & CHAR; /* M? strip WM */ - if (da >= uptr -> hwmark) uptr -> hwmark = da + 1; + if (da >= uptr->hwmark) uptr->hwmark = da + 1; da++; ap++; BS++; /* adv ptrs */ if (ADDR_ERR (BS)) return STOP_WRAP; } return SCPE_OK; @@ -401,7 +401,7 @@ t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 flg) { int32 i, lim; uint32 da = ((sec % DP_TOTSC) * DP_NUMCH) + DP_ADDR; /* char number */ -uint8 *ap = ((uint8 *) uptr -> filebuf) + da; /* buf ptr */ +uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */ lim = flg? (DP_DATA - 10): DP_DATA; /* load vs move */ for (i = 0; i < lim; i++) { /* copy data */ @@ -411,7 +411,7 @@ for (i = 0; i < lim; i++) { /* copy data */ return STOP_INVDLN; } if (flg) *ap = M[BS] & (WM | CHAR); /* load, copy WM */ else *ap = M[BS] & CHAR; /* move, strip WM */ - if (da >= uptr -> hwmark) uptr -> hwmark = da + 1; + if (da >= uptr->hwmark) uptr->hwmark = da + 1; da++; ap++; BS++; /* adv ptrs */ if (ADDR_ERR (BS)) return STOP_WRAP; } return SCPE_OK; @@ -419,37 +419,37 @@ return SCPE_OK; /* Find sector */ -int32 dp_fndsec (UNIT *uptr, int32 sec, int32 dcf, int32 flg) +int32 dp_fndsec (UNIT *uptr, int32 sec, int32 dcf) { int32 ctrk = sec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */ -int32 psec = ((uptr -> CYL) * (DP_NUMSF * DP_NUMSC)) + ctrk; +int32 psec = ((uptr->CYL) * (DP_NUMSF * DP_NUMSC)) + ctrk; int32 da = psec * DP_NUMCH; /* char number */ -uint8 *ap = ((uint8 *) uptr -> filebuf) + da; /* buf ptr */ +uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */ int32 i; if (dp_zeroad (ap)) return psec; /* addr zero? ok */ -if (dp_cmp_ad (ap, dcf, flg)) return psec; /* addr comp? ok */ +if (dp_cmp_ad (ap, dcf)) return psec; /* addr comp? ok */ psec = psec - (psec % DP_NUMSC); /* sector 0 */ for (i = 0; i < DP_NUMSC; i++, psec++) { /* check track */ da = psec * DP_NUMCH; /* char number */ - ap = ((uint8 *) uptr -> filebuf) + da; /* word pointer */ + ap = ((uint8 *) uptr->filebuf) + da; /* word pointer */ if (dp_zeroad (ap)) continue; /* no implicit match */ - if (dp_cmp_ad (ap, dcf, flg)) return psec; } /* match? */ + if (dp_cmp_ad (ap, dcf)) return psec; } /* match? */ ind[IN_UNA] = ind[IN_DSK] = 1; /* no match */ return -1; } /* Find next sector - must be sequential, cannot cross cylinder boundary */ -t_stat dp_nexsec (UNIT *uptr, int32 psec, int32 dcf, int32 flg) +t_stat dp_nexsec (UNIT *uptr, int32 psec, int32 dcf) { int32 ctrk = psec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */ int32 da = psec * DP_NUMCH; /* word number */ -uint8 *ap = ((uint8 *) uptr -> filebuf) + da; /* buf ptr */ +uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */ if (ctrk) { /* not trk zero? */ if (dp_zeroad (ap)) return SCPE_OK; /* addr zero? ok */ - if (dp_cmp_ad (ap, dcf, flg)) return SCPE_OK; }/* addr comp? ok */ + if (dp_cmp_ad (ap, dcf)) return SCPE_OK; } /* addr comp? ok */ ind[IN_UNA] = ind[IN_DSK] = 1; /* no, error */ return STOP_INVDAD; } @@ -467,7 +467,7 @@ return TRUE; /* all zeroes */ /* Compare disk address to memory sector address - always omit word marks */ -t_bool dp_cmp_ad (uint8 *ap, int32 dcf, int32 flg) +t_bool dp_cmp_ad (uint8 *ap, int32 dcf) { int32 i; uint8 c; @@ -533,8 +533,8 @@ return cnt; void dp_fill (UNIT *uptr, uint32 da, int32 cnt) { while (cnt-- > 0) { /* fill with blanks */ - *(((uint8 *) uptr -> filebuf) + da) = BCD_BLANK; - if (da >= uptr -> hwmark) uptr -> hwmark = da + 1; + *(((uint8 *) uptr->filebuf) + da) = BCD_BLANK; + if (da >= uptr->hwmark) uptr->hwmark = da + 1; da++; } return; } diff --git a/I1401/i1401_iq.c b/I1401/i1401_iq.c index bd30d8ef..b12556bc 100644 --- a/I1401/i1401_iq.c +++ b/I1401/i1401_iq.c @@ -37,9 +37,11 @@ extern uint8 M[]; extern int32 BS, iochk, ind[64]; extern char ascii_to_bcd[128], bcd_to_ascii[64]; extern UNIT cpu_unit; + int32 inq_char = 033; /* request inq */ t_stat inq_svc (UNIT *uptr); t_stat inq_reset (DEVICE *dptr); + void puts_tty (char *cptr); /* INQ data structures diff --git a/I1401/i1401_lp.c b/I1401/i1401_lp.c index 432338ef..c93e21f2 100644 --- a/I1401/i1401_lp.c +++ b/I1401/i1401_lp.c @@ -34,11 +34,14 @@ extern uint8 M[]; extern char bcd_to_ascii[64]; extern int32 iochk, ind[64]; + int32 cct[CCT_LNT] = { 03 }; int32 cctlnt = 66, cctptr = 0, lines = 0, lflag = 0; + t_stat lpt_reset (DEVICE *dptr); t_stat lpt_attach (UNIT *uptr, char *cptr); t_stat space (int32 lines, int32 lflag); + char bcd_to_pca[64] = { ' ', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '#', '@', ' ', ' ', ' ', @@ -89,7 +92,6 @@ REG lpt_reg[] = { { DRDATA (LINES, lines, 8), PV_LEFT }, { DRDATA (CCTP, cctptr, 8), PV_LEFT }, { DRDATA (CCTL, cctlnt, 8), REG_RO + PV_LEFT }, - { GRDATA (CHAIN, lpt_unit.flags, 10, 2, UNIT_V_PCHAIN), REG_HRO }, { NULL } }; MTAB lpt_mod[] = { diff --git a/I1401/i1401_mt.c b/I1401/i1401_mt.c index 8965923f..980d63ff 100644 --- a/I1401/i1401_mt.c +++ b/I1401/i1401_mt.c @@ -25,7 +25,11 @@ mt 7-track magtape - 12-Jun-02 RMS End-of-record on read sets GM without WM + 31-Oct-02 RMS Added error record handling + 10-Oct-02 RMS Fixed end-of-record on load read writes WM plus GM + 30-Sep-02 RMS Revamped error handling + 28-Aug-02 RMS Added end of medium support + 12-Jun-02 RMS End-of-record on move read preserves old WM under GM (found by Van Snyder) 03-Jun-02 RMS Modified for 1311 support 30-May-02 RMS Widened POS to 32b @@ -58,8 +62,9 @@ #define MT_NUMDR 7 /* #drives */ #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_V_PNU (UNIT_V_UF + 1) /* pos not upd */ #define UNIT_WLK (1 << UNIT_V_WLK) -#define UNIT_W_UF 2 /* #save flags */ +#define UNIT_PNU (1 << UNIT_V_PNU) #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ #define MT_MAXFR (MAXMEMSIZE * 2) /* max transfer */ @@ -69,7 +74,8 @@ extern int32 BS, iochk; extern UNIT cpu_unit; uint8 dbuf[MT_MAXFR]; /* tape buffer */ t_stat mt_reset (DEVICE *dptr); -t_stat mt_boot (int32 unitno); +t_stat mt_boot (int32 unitno, DEVICE *dptr); +t_stat mt_attach (UNIT *uptr, char *cptr); UNIT *get_unit (int32 unit); /* MT data structures @@ -104,18 +110,6 @@ REG mt_reg[] = { { DRDATA (POS4, mt_unit[4].pos, 32), PV_LEFT + REG_RO }, { DRDATA (POS5, mt_unit[5].pos, 32), PV_LEFT + REG_RO }, { DRDATA (POS6, mt_unit[6].pos, 32), PV_LEFT + REG_RO }, - { GRDATA (FLG1, mt_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG2, mt_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG3, mt_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG4, mt_unit[4].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG5, mt_unit[5].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG6, mt_unit[6].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, { NULL } }; MTAB mt_mod[] = { @@ -127,7 +121,7 @@ DEVICE mt_dev = { "MT", mt_unit, mt_reg, mt_mod, MT_NUMDR, 10, 31, 1, 8, 8, NULL, NULL, &mt_reset, - &mt_boot, NULL, NULL }; + &mt_boot, &mt_attach, NULL }; /* Function routine @@ -140,50 +134,59 @@ DEVICE mt_dev = { t_stat mt_func (int32 unit, int32 mod) { -int32 err; +int32 err, pnu; t_mtrlnt tbc; UNIT *uptr; -static t_mtrlnt bceof = { 0 }; +static t_mtrlnt bceof = { MTR_TMK }; if ((uptr = get_unit (unit)) == NULL) return STOP_INVMTU; /* valid unit? */ -if ((uptr -> flags & UNIT_ATT) == 0) return SCPE_UNATT; /* attached? */ +pnu = MT_TST_PNU (uptr); /* get pos not upd */ +MT_CLR_PNU (uptr); /* and clear */ +if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; /* attached? */ switch (mod) { /* case on modifier */ case BCD_B: /* backspace */ ind[IN_END] = 0; /* clear end of reel */ - if (uptr -> pos == 0) return SCPE_OK; /* at bot? */ - fseek (uptr -> fileref, uptr -> pos - sizeof (t_mtrlnt), + if (pnu || (uptr->pos < sizeof (t_mtrlnt))) /* bot or pnu? */ + return SCPE_OK; + fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt), SEEK_SET); - fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - if ((err = ferror (uptr -> fileref)) || - (feof (uptr -> fileref))) break; - if (tbc == 0) /* file mark? */ - uptr -> pos = uptr -> pos - sizeof (t_mtrlnt); - else uptr -> pos = uptr -> pos - ((MTRL (tbc) + 1) & ~1) - + fxread (&tbc, sizeof (t_mtrlnt), 1, uptr->fileref); + if ((err = ferror (uptr->fileref)) || /* err or eof? */ + feof (uptr->fileref)) break; + if ((tbc == MTR_TMK) || (tbc == MTR_EOM)) /* tmk or eom? */ + uptr->pos = uptr->pos - sizeof (t_mtrlnt); + else uptr->pos = uptr->pos - ((MTRL (tbc) + 1) & ~1) - (2 * sizeof (t_mtrlnt)); break; /* end case */ + case BCD_E: /* erase = nop */ - if (uptr -> flags & UNIT_WPRT) return STOP_MTL; + if (uptr->flags & UNIT_WPRT) return STOP_MTL; return SCPE_OK; + case BCD_M: /* write tapemark */ - if (uptr -> flags & UNIT_WPRT) return STOP_MTL; - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); - fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr -> fileref); - err = ferror (uptr -> fileref); - uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); + if (uptr->flags & UNIT_WPRT) return STOP_MTL; + fseek (uptr->fileref, uptr->pos, SEEK_SET); + fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr->fileref); + if (err = ferror (uptr->fileref)) MT_SET_PNU (uptr); /* error */ + else uptr->pos = uptr->pos + sizeof (t_mtrlnt); break; + case BCD_R: /* rewind */ - uptr -> pos = 0; /* update position */ + uptr->pos = 0; /* update position */ return SCPE_OK; + case BCD_U: /* unload */ - uptr -> pos = 0; /* update position */ + uptr->pos = 0; /* update position */ return detach_unit (uptr); /* detach */ + default: return STOP_INVM; } + if (err != 0) { /* I/O error */ perror ("MT I/O error"); - clearerr (uptr -> fileref); - if (iochk) return SCPE_IOERR; - ind[IN_TAP] = 1; } + clearerr (uptr->fileref); + ind[IN_TAP] = 1; /* set indicator */ + if (iochk) return SCPE_IOERR; } return SCPE_OK; } @@ -199,31 +202,36 @@ return SCPE_OK; t_stat mt_io (int32 unit, int32 flag, int32 mod) { -int32 err, i, t, wm_seen; -t_mtrlnt tbc; +int32 err, t, wm_seen; +t_mtrlnt i, tbc, ebc; UNIT *uptr; if ((uptr = get_unit (unit)) == NULL) return STOP_INVMTU; /* valid unit? */ -if ((uptr -> flags & UNIT_ATT) == 0) return SCPE_UNATT; /* attached? */ +uptr->flags = uptr->flags & ~UNIT_PNU; /* clr pos not upd */ +if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; /* attached? */ + switch (mod) { case BCD_R: /* read */ ind[IN_TAP] = ind[IN_END] = 0; /* clear error */ wm_seen = 0; /* no word mk seen */ - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); - fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - if ((err = ferror (uptr -> fileref)) || (feof (uptr -> fileref))) { - ind[IN_END] = 1; /* err or eof? */ + fseek (uptr->fileref, uptr->pos, SEEK_SET); + fxread (&tbc, sizeof (t_mtrlnt), 1, uptr->fileref); + if (err = ferror (uptr->fileref)) break; /* error? */ + if (feof (uptr->fileref) || (tbc == MTR_EOM)) { /* eom or eof? */ + ind[IN_TAP] = 1; /* pretend error */ + MT_SET_PNU (uptr); /* pos not upd */ break; } - if (tbc == 0) { /* tape mark? */ + if (tbc == MTR_TMK) { /* tape mark? */ ind[IN_END] = 1; /* set end mark */ - uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); + uptr->pos = uptr->pos + sizeof (t_mtrlnt); break; } - tbc = MTRL (tbc); /* ignore error flag */ + if (MTRF (tbc)) ind[IN_TAP] = 1; /* error? set flag */ + tbc = MTRL (tbc); /* clear error flag */ if (tbc > MT_MAXFR) return SCPE_MTRLNT; /* record too long? */ - i = fxread (dbuf, sizeof (int8), tbc, uptr -> fileref); + i = fxread (dbuf, sizeof (int8), tbc, uptr->fileref); + if (err = ferror (uptr->fileref)) break; /* I/O error? */ for ( ; i < tbc; i++) dbuf[i] = 0; /* fill with 0's */ - if (err = ferror (uptr -> fileref)) break; /* I/O error? */ - uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) + + uptr->pos = uptr->pos + ((tbc + 1) & ~1) + (2 * sizeof (t_mtrlnt)); for (i = 0; i < tbc; i++) { /* loop thru buf */ if (M[BS] == (BCD_GRPMRK + WM)) { /* GWM in memory? */ @@ -243,12 +251,16 @@ case BCD_R: /* read */ if (ADDR_ERR (BS)) { /* check next BS */ BS = BA | (BS % MAXMEMSIZE); return STOP_WRAP; } } - if (flag == MD_WM) M[BS] = BCD_GRPMRK; /* load? clear WM */ + if (flag == MD_WM) M[BS] = WM | BCD_GRPMRK; /* load? set WM */ else M[BS] = (M[BS] & WM) | BCD_GRPMRK; /* move? save WM */ + BS++; /* adv BS */ + if (ADDR_ERR (BS)) { /* check final BS */ + BS = BA | (BS % MAXMEMSIZE); + return STOP_WRAP; } break; - + case BCD_W: - if (uptr -> flags & UNIT_WPRT) return STOP_MTL; /* locked? */ + if (uptr->flags & UNIT_WPRT) return STOP_MTL; /* locked? */ if (M[BS] == (BCD_GRPMRK + WM)) return STOP_MTZ; /* eor? */ ind[IN_TAP] = ind[IN_END] = 0; /* clear error */ for (tbc = 0; (t = M[BS++]) != (BCD_GRPMRK + WM); ) { @@ -259,13 +271,13 @@ case BCD_W: if (ADDR_ERR (BS)) { /* check next BS */ BS = BA | (BS % MAXMEMSIZE); return STOP_WRAP; } } - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); - fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - fxwrite (dbuf, sizeof (int8), (tbc + 1) & ~1, uptr -> fileref); - fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - if (err = ferror (uptr -> fileref)) break; /* I/O error? */ - uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) + - (2 * sizeof (t_mtrlnt)); + ebc = (tbc + 1) & ~1; /* force even */ + fseek (uptr->fileref, uptr->pos, SEEK_SET); + fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr->fileref); + fxwrite (dbuf, sizeof (int8), ebc, uptr->fileref); + fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr->fileref); + if (err = ferror (uptr->fileref)) break; /* I/O error? */ + uptr->pos = uptr->pos + ebc + (2 * sizeof (t_mtrlnt)); if (ADDR_ERR (BS)) { /* check final BS */ BS = BA | (BS % MAXMEMSIZE); return STOP_WRAP; } @@ -273,14 +285,15 @@ case BCD_W: default: return STOP_INVM; } -if (err != 0) { /* I/O error */ +if (err != 0) { /* I/O error? */ perror ("MT I/O error"); - clearerr (uptr -> fileref); + clearerr (uptr->fileref); + MT_SET_PNU (uptr); /* pos not upd */ ind[IN_TAP] = 1; /* flag error */ if (iochk) return SCPE_IOERR; } return SCPE_OK; } - + /* Get unit pointer from unit number */ UNIT *get_unit (int32 unit) @@ -293,13 +306,26 @@ else return mt_dev.units + unit; t_stat mt_reset (DEVICE *dptr) { +int32 i; +UNIT *uptr; + +for (i = 0; i < MT_NUMDR; i++) { /* clear pos flag */ + if (uptr = get_unit (i)) MT_CLR_PNU (uptr); } ind[IN_END] = ind[IN_TAP] = 0; /* clear indicators */ return SCPE_OK; } +/* Attach routine */ + +t_stat mt_attach (UNIT *uptr, char *cptr) +{ +MT_CLR_PNU (uptr); +return attach_unit (uptr, cptr); +} + /* Bootstrap routine */ -t_stat mt_boot (int32 unitno) +t_stat mt_boot (int32 unitno, DEVICE *dptr) { extern int32 saved_IS; diff --git a/I1401/i1401_sys.c b/I1401/i1401_sys.c index c897d1aa..6ad4cf84 100644 --- a/I1401/i1401_sys.c +++ b/I1401/i1401_sys.c @@ -202,7 +202,7 @@ extern int32 op_table[64], len_table[9]; if (sw & SWMASK ('C')) { /* character? */ t = val[0]; - if (uptr -> flags & UNIT_BCD) + if (uptr->flags & UNIT_BCD) fprintf (of, (t & WM)? "~%c": "%c", bcd_to_ascii[t & CHAR]); else fprintf (of, FMTASC (t & 0177)); return SCPE_OK; } @@ -302,7 +302,7 @@ if ((sw & SWMASK ('C')) || (sw & SWMASK ('S')) || (*cptr == '~') || for (i = 0; (i < sim_emax) && (*cptr != 0); ) { t = *cptr++; /* get character */ if (cflag && (wm_seen == 0) && (t == '~')) wm_seen = WM; - else if (uptr -> flags & UNIT_BCD) { + else if (uptr->flags & UNIT_BCD) { if (t < 040) return SCPE_ARG; val[i++] = ascii_to_bcd[t] | wm_seen; wm_seen = 0; } diff --git a/I1620/i1620_cd.c b/I1620/i1620_cd.c new file mode 100644 index 00000000..43990d8a --- /dev/null +++ b/I1620/i1620_cd.c @@ -0,0 +1,403 @@ +/* i1620_cd.c: IBM 1622 card reader/punch + + Copyright (c) 2002, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + cdr 1622 card reader + cdp 1622 card punch + + Cards are represented as ASCII text streams terminated by newlines. + This allows cards to be created and edited as normal files. +*/ + +#include "i1620_defs.h" + +#define CD_LEN 80 + +extern uint8 M[MAXMEMSIZE]; +extern uint8 ind[NUM_IND]; +extern UNIT cpu_unit; +extern int32 io_stop; + +char cdr_buf[CD_LEN + 2]; +char cdp_buf[CD_LEN + 2]; + +t_stat cdr_reset (DEVICE *dptr); +t_stat cdr_attach (UNIT *uptr, char *cptr); +t_stat cdr_boot (int32 unitno, DEVICE *dptr); +t_stat cdr_read (void); +t_stat cdp_reset (DEVICE *dptr); +t_stat cdp_write (uint32 len); +t_stat cdp_num (uint32 pa, uint32 ndig, t_bool dump); + +/* Card reader data structures + + cdr_dev CDR descriptor + cdr_unit CDR unit descriptor + cdr_reg CDR register list +*/ + +UNIT cdr_unit = { + UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0) }; + +REG cdr_reg[] = { + { FLDATA (LAST, ind[IN_LAST], 0) }, + { DRDATA (POS, cdr_unit.pos, 32), PV_LEFT }, + { NULL } }; + +DEVICE cdr_dev = { + "CDR", &cdr_unit, cdr_reg, NULL, + 1, 10, 31, 1, 8, 7, + NULL, NULL, &cdr_reset, + &cdr_boot, &cdr_attach, NULL }; + +/* CDP data structures + + cdp_dev CDP device descriptor + cdp_unit CDP unit descriptor + cdp_reg CDP register list +*/ + +UNIT cdp_unit = { + UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) }; + +REG cdp_reg[] = { + { DRDATA (POS, cdp_unit.pos, 32), PV_LEFT }, + { NULL } }; + +DEVICE cdp_dev = { + "CDP", &cdp_unit, cdp_reg, NULL, + 1, 10, 31, 1, 8, 7, + NULL, NULL, &cdp_reset, + NULL, NULL, NULL }; + +/* Data tables. The card reader presents unusual problems. + - Unique codes needed for 11-2-8 (uses !) and 12-7-8 (uses ") . + - Can punch both 11 (-) and 11-0 (uses ]). + On input, the nul and nl generated by C are converted to + spaces; tabs and line feeds are also converted to spaces. + +/* Card reader (ASCII) to numeric (one digit) */ + +const char cdr_to_num[128] = { + 0x00, -1, -1, -1, -1, -1, -1, -1, /* 00 */ + -1, 0x00, 0x00, -1, -1, 0x00, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* 10 */ + -1, -1, -1, -1, -1, -1, -1, -1, + 0x00, 0x1A, 0x1F, 0x00, 0x1B, 0x0A, 0x0F, 0x0A, /* !"#$%&' */ + 0x0C, 0x0C, 0x1C, 0x00, 0x0B, 0x10, 0x1B, 0x01, /* ()*+,-./ */ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 01234567 */ + 0x08, 0x09, 0x00, 0x1E, 0x1E, 0x0B, 0x0E, 0x1A, /* 89:;<=>? */ + 0x0C, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* @ABCDEFG */ + 0x08, 0x09, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* HIJKLMNO */ + 0x17, 0x18, 0x19, 0x02, 0x03, 0x04, 0x05, 0x06, /* PQRSTUVW */ + 0x07, 0x08, 0x09, 0x00, 0x0E, 0x10, 0x0F, 0x1F, /* XYZ[\]^_ */ + -1, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* abcdefg */ + 0x08, 0x09, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* hijklmno */ + 0x17, 0x18, 0x19, 0x02, 0x03, 0x04, 0x05, 0x06, /* pqrstuvw */ + 0x07, 0x08, 0x09, -1, -1, -1, -1, -1 }; /* xyz */ + +/* Numeric (flag + digit) to card punch (ASCII) */ + +const char num_to_cdp[32] = { + '0', '1', '2', '3', '4', '5', '6', '7', /* 0 */ + '8', '9', '\'', ',', ' ', '&', ' ', '&', + ']', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* F + 0 */ + 'Q', 'R', '!', '$', -1, -1, -1, '"' }; + +/* Card reader (ASCII) to alphameric (two digits) + + 11-2-8 (!) reads as 5A + 11-7-8 (_) reads as 5F + 12-2-8 (?) reads inconsistently (here 02) + 12-6-8 (<) reads inconsistently (here 5E) + 12-7-8 (") reads as 5F +*/ + +const char cdr_to_alp[128] = { + 0x00, -1, -1, -1, -1, -1, -1, -1, /* 00 */ + -1, 0x00, 0x00, -1, -1, 0x00, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* 10 */ + -1, -1, -1, -1, -1, -1, -1, -1, + 0x00, 0x5A, 0x5F, 0x60, 0x13, 0x0A, 0x0F, 0x0A, /* !"#$%&' */ + 0x24, 0x04, 0x14, 0x10, 0x23, 0x20, 0x03, 0x21, /* ()*+,-./ */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 01234567 */ + 0x78, 0x79, 0x70, 0x5E, 0x5E, 0x33, 0x0E, 0x02, /* 89:;<=>? */ + 0x34, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* @ABCDEFG */ + 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* HIJKLMNO */ + 0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* PQRSTUVW */ + 0x67, 0x68, 0x69, 0x40, 0x0E, 0x50, 0x0F, 0x5F, /* XYZ[\]^_ */ + -1, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* abcdefg */ + 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* hijklmno */ + 0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* pqrstuvw */ + 0x67, 0x68, 0x69, -1, -1, -1, -1, -1 }; /* xyz */ + +/* Alphameric (two digits) to card punch (ASCII). Oddities: + + 02 -> 12-2-8 (?), symmetric + 07 -> 12-7-8 ("), reads as 5F + 12 -> 11-2-8 (!), reads as 5A + 15 -> 11,0 (]), reads as 50 + 22 -> 0-2-8 ('), reads as 0A + 32 -> 2-8 (%), reads as 0A + 5B -> 11-3-8 (=), reads as 13 + 6A -> 0-2-8 ('), reads as 0A + 6B -> 0-3-8 (,), reads as 23 + AA -> 0-2-8 ('), reads as 0A + + There is no way to punch 0-5-8 (#), 0-6-8 (\), + 11-5-8 (]), 11-6-8 (;), 11-7-8 (_), + 12-5-8 ([), or 12-6-8 (<) +*/ + +const char alp_to_cdp[256] = { + ' ', -1, '?', '.', ')', -1, -1, '"', /* 00 */ + -1, -1, '\'', -1, -1, -1, -1, '&', + '+', -1, '!', '$', '*', ']', -1, -1, /* 10 */ + -1, -1, -1, -1, -1, -1, -1, -1, + '-', '/', '\'', ',', '(', -1, -1, -1, /* 20 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, '%', '=', '@', ':', ' ', -1, /* 30 */ + -1, -1, '\'', -1, -1, -1, -1, '&', + -1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 40 */ + 'H', 'I', -1, -1, -1, -1, -1, -1, + '_', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 50 */ + 'Q', 'R', '?', '=', -1, -1, -1, '"', + -1, '/', 'S', 'T', 'U', 'V', 'W', 'X', /* 60 */ + 'Y', 'Z', '\'', ',', -1, -1, -1, -1, + '0', '1', '2', '3', '4', '5', '6', '7', /* 70 */ + '8', '9', -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* 90 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* A0 */ + -1, -1, '\'', -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* B0 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* C0 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* D0 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* E0 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* F0 */ + -1, -1, -1, -1, -1, -1, -1, -1 }; + +/* Card reader IO routine + + - Hard errors stop the operation and halt the system. + - Invalid characters place a blank in memory and set RDCHK. + If IO stop is set, the system halts at the end of the operation. +*/ + +t_stat cdr (uint32 op, uint32 pa, uint32 f0, uint32 f1) +{ +int32 i; +int8 cdc; +t_stat r, inv = SCPE_OK; + +switch (op) { /* case on op */ +case OP_RN: /* read numeric */ + r = cdr_read (); /* fill reader buf */ + if (r != SCPE_OK) return r; /* error? */ + for (i = 0; i < CD_LEN; i++) { /* transfer to mem */ + cdc = cdr_to_num[cdr_buf[i]]; /* translate */ + if (cdc < 0) { /* invalid? */ + ind[IN_RDCHK] = 1; /* set read check */ + inv = STOP_INVCHR; /* set return status */ + cdc = 0; } + M[pa] = cdc; /* store digit */ + PP (pa); } /* incr mem addr */ + break; +case OP_RA: /* read alphameric */ + r = cdr_read (); /* fill reader buf */ + if (r != SCPE_OK) return r; /* error? */ + for (i = 0; i < CD_LEN; i++) { /* transfer to mem */ + cdc = cdr_to_alp[cdr_buf[i]]; /* translate */ + if (cdc < 0) { /* invalid? */ + ind[IN_RDCHK] = 1; /* set read check */ + inv = STOP_INVCHR; /* set return status */ + cdc = 0; }; + M[pa] = (M[pa] & FLAG) | (cdc & DIGIT); /* store 2 digits */ + M[pa - 1] = (M[pa - 1] & FLAG) | ((cdc >> 4) & DIGIT); + pa = ADDR_A (pa, 2); } /* incr mem addr */ + break; +default: /* invalid function */ + return STOP_INVFNC; } +CRETIOE (io_stop, inv); +} + +/* Fill card reader buffer - all errors are hard errors */ + +t_stat cdr_read (void) +{ +int32 i; + +ind[IN_LAST] = 0; /* clear last card */ +if ((cdr_unit.flags & UNIT_ATT) == 0) { /* attached? */ + ind[IN_RDCHK] = 1; /* no, error */ + return SCPE_UNATT; } + +for (i = 0; i < CD_LEN + 1; i++) cdr_buf[i] = ' '; /* clear buffer */ +fgets (cdr_buf, CD_LEN, cdr_unit.fileref); /* read card */ +if (feof (cdr_unit.fileref)) return STOP_NOCD; /* eof? */ +if (ferror (cdr_unit.fileref)) { /* error? */ + ind[IN_RDCHK] = 1; /* set read check */ + perror ("CDR I/O error"); + clearerr (cdr_unit.fileref); + return SCPE_IOERR; } +cdr_unit.pos = ftell (cdr_unit.fileref); /* update position */ +getc (cdr_unit.fileref); /* see if more */ +if (feof (cdr_unit.fileref)) ind[IN_LAST] = 1; /* eof? set last */ +fseek (cdr_unit.fileref, cdr_unit.pos, SEEK_SET); /* "backspace" */ +return SCPE_OK; +} + +/* Card reader attach */ + +t_stat cdr_attach (UNIT *uptr, char *cptr) +{ +ind[IN_LAST] = 0; /* clear last card */ +return attach_unit (uptr, cptr); +} + +/* Card reader reset */ + +t_stat cdr_reset (DEVICE *dptr) +{ +ind[IN_LAST] = 0; /* clear last card */ +return SCPE_OK; +} + +/* Bootstrap routine */ + +const static uint8 boot_rom[] = { + 3, 6, 1, 9, 9, 0, 1, 0, 0, 5, 0, 0, /* RNCD 19901 */ + 2, 5, 0, 0, 0, 8, 0, 1, 9, 9, 1, 0x10, /* TD 80,-19910 */ + 3, 1, 1, 9, 9, 0, 0x15, 1, 9, 9, 2, 0, /* TR -19905,19920 */ + 2, 5, 1, 9, 9, 1, 0x10, 0, 0, 0, 8, 0, /* TD -19910,80 */ + 4, 9, 1, 9, 9, 1, 0x15, 0, 0, 0, 0, 0 }; /* BR -19915 */ + +#define BOOT_START 0 +#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint8)) + +t_stat cdr_boot (int32 unitno, DEVICE *dptr) +{ +int32 i; +extern int32 saved_PC; + +if ((cpu_unit.flags & IF_IA) == 0) return SCPE_NOFNC; /* must have IA */ +for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i]; +saved_PC = BOOT_START; +return SCPE_OK; +} + +/* Card punch IO routine + + - Hard errors stop the operation and halt the system. + - Invalid characters stop the operation and set WRCHK. + If IO stop is set, the system halts. +*/ + +t_stat cdp (uint32 op, uint32 pa, uint32 f0, uint32 f1) +{ +int32 i; +int8 cdc; +uint8 z, d; + +switch (op) { /* decode op */ +case OP_DN: + return cdp_num (pa, 20000 - (pa % 20000), TRUE); /* dump numeric */ +case OP_WN: + return cdp_num (pa, CD_LEN, FALSE); /* write numeric */ +case OP_WA: + for (i = 0; i < CD_LEN; i++) { /* one card */ + d = M[pa] & DIGIT; /* get digit pair */ + z = M[pa - 1] & DIGIT; + cdc = alp_to_cdp[(z << 4) | d]; /* translate */ + if (cdc < 0) { /* bad char? */ + ind[IN_WRCHK] = 1; /* set write check */ + CRETIOE (io_stop, STOP_INVCHR); } + cdp_buf[i] = cdc; /* store in buf */ + pa = ADDR_A (pa, 2); } /* incr mem addr */ + return cdp_write (CD_LEN); /* punch buffer */ +default: /* invalid function */ + return STOP_INVFNC; } +return SCPE_OK; +} + +/* Punch card numeric */ + +t_stat cdp_num (uint32 pa, uint32 ndig, t_bool dump) +{ +int32 i, ncd, len; +uint8 d; +int8 cdc; +t_stat r; + +ncd = ndig / CD_LEN; /* number of cards */ +while (ncd-- >= 0) { /* until done */ + len = (ncd >= 0)? CD_LEN: (ndig % CD_LEN); /* card length */ + if (len == 0) break; + for (i = 0; i < len; i++) { /* one card */ + d = M[pa] & (FLAG | DIGIT); /* get char */ + if (dump && (d == FLAG)) cdc = '-'; /* dump? F+0 is diff */ + else cdc = num_to_cdp[d]; /* translate */ + if (cdc < 0) { /* bad char? */ + ind[IN_WRCHK] = 1; /* set write check */ + CRETIOE (io_stop, STOP_INVCHR); } /* stop */ + cdp_buf[i] = cdc; /* store in buf */ + PP (pa); } /* incr mem addr */ + r = cdp_write (len); /* punch card */ + if (r != SCPE_OK) return r; } /* error? */ +return SCPE_OK; +} + +/* Write punch card buffer - all errors are hard errors */ + +t_stat cdp_write (uint32 len) +{ +if ((cdp_unit.flags & UNIT_ATT) == 0) { /* attached? */ + ind[IN_WRCHK] = 1; /* no, error */ + return SCPE_UNATT; } + +while ((len > 0) && (cdp_buf[len - 1] == ' ')) --len; /* trim spaces */ +cdp_buf[len] = '\n'; /* newline, null */ +cdp_buf[len + 1] = 0; + +if (fputs (cdp_buf, cdp_unit.fileref) == EOF) { /* write card */ + ind[IN_WRCHK] = 1; /* error? */ + perror ("CDP I/O error"); + clearerr (cdp_unit.fileref); + return SCPE_IOERR; } +cdp_unit.pos = ftell (cdp_unit.fileref); /* count char */ +return SCPE_OK; +} + +/* Reset card punch */ + +t_stat cdp_reset (DEVICE *dptr) +{ +return SCPE_OK; +} diff --git a/I1620/i1620_cpu.c b/I1620/i1620_cpu.c new file mode 100644 index 00000000..b9b88287 --- /dev/null +++ b/I1620/i1620_cpu.c @@ -0,0 +1,1861 @@ +/* i1620_cpu.c: IBM 1620 CPU simulator + + Copyright (c) 2002, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + This CPU module incorporates code and comments from the 1620 simulator by + Geoff Kuenning, with his permission. + + 18-Oct-02 RMS Fixed bugs in invalid result testing (found by Hans Pufal) + + The simulated register state for the IBM 1620 is: + + 1620 sim comment + + IR1 [PC] program counter + IR2 instruction register 2 (subroutine return address) + OR1 [QAR] Q address + OR2 [PAR] P address + PR1 manual save address + ind[0:99] indicators + + Additional internal registers OR3, PR2, and PR3 are not simulated. + + The IBM 1620 is a fixed instruction length, variable data length, decimal + data system. Memory consists of 20000 - 60000 BCD digits, each containing + four bits of data and a flag. There are no general registers; all + instructions are memory to memory. + + The 1620 uses a fixed, 12 digit instruction format: + + oo ppppp qqqqq + + where + + oo = opcode + ppppp = P (usually destination) address + qqqqq = Q (usually source) address + + Immediate instructions use the qqqqq field as the second operand. + + The 1620 Model 1 uses table lookups for add and multiply; for that reason, + it was nicknamed CADET (Can't Add, Doesn't Even Try). The Model 2 does + adds in hardware and uses the add table memory for index registers. +*/ + +/* This routine is the instruction decode routine for the IBM 1620. + It is called from the simulator control program to execute + instructions in simulated memory, starting at the simulated PC. + It runs until 'reason' is set non-zero. + + General notes: + + 1. Reasons to stop. The simulator can be stopped by: + + HALT instruction + breakpoint encountered + illegal addresses or instruction formats + I/O error in I/O simulator + + 2. Interrupts. The 1620 has no interrupt structure. + + 3. Non-existent memory. On the 1620, all memory references + are modulo the memory size. + + 4. Adding I/O devices. These modules must be modified: + + i1620_cpu.c add iodisp table entry + i1620_sys.c add sim_devices table entry +*/ + +#include "i1620_defs.h" + +#define PCQ_SIZE 64 /* must be 2**n */ +#define PCQ_MASK (PCQ_SIZE - 1) +#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = saved_PC + +uint8 M[MAXMEMSIZE] = { 0 }; /* main memory */ +uint32 saved_PC = 0; /* saved PC */ +uint32 IR2 = 1; /* inst reg 2 */ +uint32 PAR = 0; /* P address */ +uint32 QAR = 0; /* Q address */ +uint32 PR1 = 1; /* proc reg 1 */ +uint32 iae = 1; /* ind addr enb */ +uint32 idxe = 0; /* index enable */ +uint32 idxb = 0; /* index band */ +uint32 io_stop = 1; /* I/O stop */ +uint32 ar_stop = 1; /* arith stop */ +int32 ind_max = 16; /* iadr nest limit */ +uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ +int32 pcq_p = 0; /* PC queue ptr */ +REG *pcq_r = NULL; /* PC queue reg ptr */ +uint8 ind[NUM_IND] = { 0 }; /* indicators */ + +extern int32 sim_int_char; +extern int32 sim_interval; +extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern FILE *sim_log; + +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); +t_stat cpu_reset (DEVICE *dptr); +t_stat cpu_set_opt1 (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_set_opt2 (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_set_save (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_set_table (UNIT *uptr, int32 val, char *cptr, void *desc); + +int32 get_2d (uint32 ad); +t_stat get_addr (uint32 alast, int32 lnt, t_bool indexok, uint32 *addr); +t_stat cvt_addr (uint32 alast, int32 lnt, t_bool signok, int32 *val); +t_stat get_idx (uint32 aidx); +t_stat xmt_field (uint32 d, uint32 s, uint32 skp); +t_stat xmt_record (uint32 d, uint32 s, t_bool cpy); +t_stat xmt_index (uint32 d, uint32 s); +t_stat xmt_divd (uint32 d, uint32 s); +t_stat xmt_tns (uint32 d, uint32 s); +t_stat xmt_tnf (uint32 d, uint32 s); +t_stat add_field (uint32 d, uint32 s, t_bool sub, t_bool sto, int32 *sta); +uint32 add_one_digit (uint32 dst, uint32 src, uint32 *cry); +t_stat mul_field (uint32 mpc, uint32 mpy); +t_stat mul_one_digit (uint32 mpyd, uint32 mpcp, uint32 prop, uint32 last); +t_stat div_field (uint32 dvd, uint32 dvr, int32 *ez); +t_stat div_one_digit (uint32 dvd, uint32 dvr, uint32 max, uint32 *quod, uint32 *quop); +t_stat oct_to_dec (uint32 tbl, uint32 s); +t_stat dec_to_oct (uint32 d, uint32 tbl, int32 *ez); +t_stat or_field (uint32 d, uint32 s); +t_stat and_field (uint32 d, uint32 s); +t_stat xor_field (uint32 d, uint32 s); +t_stat com_field (uint32 d, uint32 s); +void upd_ind (void); + +extern tty (uint32 op, uint32 pa, uint32 f0, uint32 f1); +extern ptp (uint32 op, uint32 pa, uint32 f0, uint32 f1); +extern ptr (uint32 op, uint32 pa, uint32 f0, uint32 f1); +extern cdp (uint32 op, uint32 pa, uint32 f0, uint32 f1); +extern cdr (uint32 op, uint32 pa, uint32 f0, uint32 f1); +extern dp (uint32 op, uint32 pa, uint32 f0, uint32 f1); +extern lpt (uint32 op, uint32 pa, uint32 f0, uint32 f1); +extern btp (uint32 op, uint32 pa, uint32 f0, uint32 f1); +extern btr (uint32 op, uint32 pa, uint32 f0, uint32 f1); + +extern t_stat fp_add (uint32 d, uint32 s, t_bool sub); +extern t_stat fp_mul (uint32 d, uint32 s); +extern t_stat fp_div (uint32 d, uint32 s); +extern t_stat fp_fsl (uint32 d, uint32 s); +extern t_stat fp_fsr (uint32 d, uint32 s); + +/* CPU data structures + + cpu_dev CPU device descriptor + cpu_unit CPU unit descriptor + cpu_reg CPU register list + cpu_mod CPU modifier list +*/ + +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX+UNIT_BCD+MI_STD, MAXMEMSIZE) }; + +REG cpu_reg[] = { + { DRDATA (PC, saved_PC, 16), PV_LEFT }, + { DRDATA (IR2, IR2, 16), PV_LEFT }, + { DRDATA (PR1, PR1, 16), PV_LEFT }, + { DRDATA (PAR, PAR, 16), PV_LEFT + REG_RO }, + { DRDATA (QAR, QAR, 16), PV_LEFT + REG_RO }, + { FLDATA (SW1, ind[IN_SW1], 0) }, + { FLDATA (SW2, ind[IN_SW2], 0) }, + { FLDATA (SW3, ind[IN_SW3], 0) }, + { FLDATA (SW4, ind[IN_SW4], 0) }, + { FLDATA (HP, ind[IN_HP], 0) }, + { FLDATA (EZ, ind[IN_EZ], 0) }, + { FLDATA (OVF, ind[IN_OVF], 0) }, + { FLDATA (EXPCHK, ind[IN_EXPCHK], 0) }, + { FLDATA (RDCHK, ind[IN_RDCHK], 0) }, + { FLDATA (WRCHK, ind[IN_WRCHK], 0) }, + { FLDATA (ARSTOP, ar_stop, 0) }, + { FLDATA (IOSTOP, io_stop, 0) }, + { BRDATA (IND, ind, 10, 1, NUM_IND) }, + { FLDATA (IAE, iae, 0) }, + { FLDATA (IDXE, idxe, 0) }, + { FLDATA (IDXB, idxb, 0) }, + { DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT }, + { BRDATA (PCQ, pcq, 10, 14, PCQ_SIZE), REG_RO+REG_CIRC }, + { ORDATA (PCQP, pcq_p, 6), REG_HRO }, + { ORDATA (WRU, sim_int_char, 8) }, + { NULL } }; + +MTAB cpu_mod[] = { + { IF_IA, IF_IA, "IA", "IA", &cpu_set_opt1 }, + { IF_IA, 0, "no IA", "NOIA", &cpu_set_opt1 }, + { IF_EDT, IF_EDT, "EDT", "EDT", &cpu_set_opt1 }, + { IF_EDT, 0, "no EDT", "NOEDT", &cpu_set_opt1 }, + { IF_DIV, IF_DIV, "DIV", "DIV", &cpu_set_opt1 }, + { IF_DIV, 0, "no DIV", "NODIV", &cpu_set_opt1 }, + { IF_FP, IF_FP, "FP", "FP", NULL }, + { IF_FP, 0, "no FP", "NOFP", NULL }, + { IF_BIN, IF_BIN, "BIN", "BIN", &cpu_set_opt2 }, + { IF_BIN, 0, "no BIN", "NOBIN", &cpu_set_opt2 }, + { IF_IDX, IF_IDX, "IDX", "IDX", &cpu_set_opt2 }, + { IF_IDX, 0, "no IDX", "NOIDX", &cpu_set_opt2 }, + { IF_MII, IF_MII, "Model 2", "MOD2", &cpu_set_model }, + { IF_MII, 0, "Model 1", "MOD1", &cpu_set_model }, + { UNIT_MSIZE, 20000, NULL, "20K", &cpu_set_size }, + { UNIT_MSIZE, 40000, NULL, "40K", &cpu_set_size }, + { UNIT_MSIZE, 60000, NULL, "60K", &cpu_set_size }, + { UNIT_MSIZE, 0, NULL, "SAVE", &cpu_set_save }, + { UNIT_MSIZE, 0, NULL, "TABLE", &cpu_set_table }, + { 0 } }; + +DEVICE cpu_dev = { + "CPU", &cpu_unit, cpu_reg, cpu_mod, + 1, 10, 18, 1, 16, 5, + &cpu_ex, &cpu_dep, &cpu_reset, + NULL, NULL, NULL }; + +/* Instruction table */ + +const int32 op_table[100] = { + 0, /* 0 */ + IF_FP + IF_VPA + IF_VQA, /* FADD */ + IF_FP + IF_VPA + IF_VQA, /* FSUB */ + IF_FP + IF_VPA + IF_VQA, /* FMUL */ + 0, + IF_FP + IF_VPA + IF_VQA, /* FSL */ + IF_FP + IF_MII + IF_VPA + IF_VQA, /* TFL */ + IF_FP + IF_MII + IF_VPA + IF_VQA, /* BTFL */ + IF_FP + IF_VPA + IF_VQA, /* FSR */ + IF_FP + IF_VPA + IF_VQA, /* FDV */ + IF_MII + IF_VPA + IF_IMM, /* 10: BTAM */ + IF_VPA + IF_IMM, /* AM */ + IF_VPA + IF_IMM, /* SM */ + IF_VPA + IF_IMM, /* MM */ + IF_VPA + IF_IMM, /* CM */ + IF_VPA + IF_IMM, /* TDM */ + IF_VPA + IF_IMM, /* TFM */ + IF_VPA + IF_IMM, /* BTM */ + IF_DIV + IF_VPA + IF_IMM, /* LDM */ + IF_DIV + IF_VPA + IF_IMM, /* DM */ + IF_MII + IF_VPA + IF_VQA, /* 20: BTA */ + IF_VPA + IF_VQA, /* A */ + IF_VPA + IF_VQA, /* S */ + IF_VPA + IF_VQA, /* M */ + IF_VPA + IF_VQA, /* C */ + IF_VPA + IF_VQA, /* TD */ + IF_VPA + IF_VQA, /* TF */ + IF_VPA + IF_VQA, /* BT */ + IF_DIV + IF_VPA + IF_VQA, /* LD */ + IF_DIV + IF_VPA + IF_VQA, /* D */ + IF_MII + IF_VPA + IF_VQA, /* 30: TRNM */ + IF_VPA + IF_VQA, /* TR */ + IF_VPA, /* SF */ + IF_VPA, /* CF */ + IF_VPA, /* K */ + IF_VPA, /* DN */ + IF_VPA, /* RN */ + IF_VPA, /* RA */ + IF_VPA, /* WN */ + IF_VPA, /* WA */ + 0, /* 40 */ + 0, /* NOP */ + 0, /* BB */ + IF_VPA + IF_VQA, /* BD */ + IF_VPA + IF_VQA, /* BNF */ + IF_VPA + IF_VQA, /* BNR */ + IF_VPA, /* BI */ + IF_VPA, /* BNI */ + 0, /* H */ + IF_VPA, /* B */ + 0, /* 50 */ + 0, + 0, + 0, + 0, + IF_VPA + IF_VQA, /* BNG - disk sys */ + 0, + 0, + 0, + 0, + IF_MII + IF_VPA, /* 60: BS */ + IF_IDX + IF_VPA + IF_NQX, /* BX */ + IF_IDX + IF_VPA + IF_IMM, /* BXM */ + IF_IDX + IF_VPA + IF_NQX, /* BCX */ + IF_IDX + IF_VPA + IF_IMM, /* BCXM */ + IF_IDX + IF_VPA + IF_NQX, /* BLX */ + IF_IDX + IF_VPA + IF_IMM, /* BLXM */ + IF_IDX + IF_VPA + IF_NQX, /* BSX */ + 0, + 0, + IF_IDX + IF_VPA + IF_VQA, /* 70: MA */ + IF_EDT + IF_VPA + IF_VQA, /* MF */ + IF_EDT + IF_VPA + IF_VQA, /* MF */ + IF_EDT + IF_VPA + IF_VQA, /* TNF */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, /* 80 */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + IF_BIN + IF_VPA + IF_4QA, /* 90: BBT */ + IF_BIN + IF_VPA + IF_4QA, /* BMK */ + IF_BIN + IF_VPA + IF_VQA, /* ORF */ + IF_BIN + IF_VPA + IF_VQA, /* ANDF */ + IF_BIN + IF_VPA + IF_VQA, /* CPLF */ + IF_BIN + IF_VPA + IF_VQA, /* EORF */ + IF_BIN + IF_VPA + IF_VQA, /* OTD */ + IF_BIN + IF_VPA + IF_VQA, /* DTO */ + 0, + 0 + }; + +/* IO dispatch table */ + +t_stat (*iodisp[NUM_IO])(uint32 op, uint32 pa, uint32 f0, uint32 f1) = { + NULL, &tty, &ptp, &ptr, &cdp, /* 00 - 09 */ + &cdr, NULL, &dp, NULL, &lpt, + NULL, NULL, NULL, NULL, NULL, /* 10 - 19 */ + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, /* 20 - 29 */ + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, &btp, &btr, NULL, /* 30 - 39 */ + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, /* 40 - 49 */ + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, /* 50 - 59 */ + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, /* 60 - 69 */ + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, /* 70 - 79 */ + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, /* 80 - 89 */ + NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, /* 90 - 99 */ + NULL, NULL, NULL, NULL, NULL }; + +/* Indicator table: -1 = illegal, +1 = resets when tested */ + +const int32 ind_table[NUM_IND] = { + -1, 0, 0, 0, 0, -1, 1, 1, -1, 1, /* 00 - 09 */ + -1, 0, 0, 0, 1, 1, 1, 1, -1, 0, /* 10 - 19 */ + -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, /* 20 - 29 */ + 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, /* 30 - 39 */ + -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, /* 40 - 49 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 50 - 59 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 60 - 69 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 70 - 79 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80 - 89 */ + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; /* 90 - 99 */ + +/* Add table for 1620 Model 1 */ + +const uint8 std_add_table[ADD_TABLE_LEN] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, + 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, + 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, + 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, + 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, + 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, + 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 }; + + +/* Add table for 1620 Model 2 ("hardware add") */ + +const uint8 sum_table[20] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19 }; + +/* Multiply table */ + +const uint8 std_mul_table[MUL_TABLE_LEN] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, + 0, 0, 2, 0, 4, 0, 6, 0, 8, 0, + 0, 0, 3, 0, 6, 0, 9, 0, 2, 1, + 0, 0, 4, 0, 8, 0, 2, 1, 6, 1, + 0, 0, 5, 0, 0, 1, 5, 1, 0, 2, + 0, 0, 6, 0, 2, 1, 8, 1, 4, 2, + 0, 0, 7, 0, 4, 1, 1, 2, 8, 2, + 0, 0, 8, 0, 6, 1, 4, 2, 2, 3, + 0, 0, 9, 0, 8, 1, 7, 2, 6, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, + 0, 1, 2, 1, 4, 1, 6, 1, 8, 1, + 5, 1, 8, 1, 1, 2, 4, 2, 7, 2, + 0, 2, 4, 2, 8, 2, 2, 3, 6, 3, + 5, 2, 0, 3, 5, 3, 0, 4, 5, 4, + 0, 3, 6, 3, 2, 4, 8, 4, 4, 5, + 5, 3, 2, 4, 9, 4, 6, 5, 3, 6, + 0, 4, 8, 4, 6, 5, 4, 6, 2, 7, + 5, 4, 4, 5, 3, 6, 2, 7, 1, 8 }; + +#define BRANCH(x) PCQ_ENTRY; PC = (x) +#define GET_IDXADDR(x) ((idxb? IDX_B: IDX_A) + ((x) * ADDR_LEN) + (ADDR_LEN - 1)) + +t_stat sim_instr (void) +{ +uint32 PC, pla, qla, f0, f1; +int32 i, t, idx, flags, sta, dev, op; +t_stat reason; + +/* Restore saved state */ + +PC = saved_PC; +if ((cpu_unit.flags & IF_IA) == 0) iae = 0; +if ((cpu_unit.flags & IF_IDX) == 0) idxe = idxb = 0; +upd_ind (); /* update indicators */ +reason = 0; + +/* Main instruction fetch/decode loop */ + +while (reason == 0) { /* loop until halted */ +saved_PC = PC; /* commit prev instr */ +if (sim_interval <= 0) { /* check clock queue */ + if (reason = sim_process_event ()) break; } + +if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; } + +sim_interval = sim_interval - 1; + +/* Instruction fetch and address decode */ + +if (PC & 1) { /* PC odd? */ + reason = STOP_INVIAD; /* stop */ + break; } + +op = get_2d (PC); /* get opcode */ +if (op < 0) { /* invalid? */ + reason = STOP_INVINS; + break; } +flags = op_table[op]; /* get op, flags */ +if ((flags & ALLOPT) && /* need option? */ + !(flags & ALLOPT & cpu_unit.flags)) { /* any set? */ + reason = STOP_INVINS; /* no, error */ + break; } + +pla = ADDR_A (PC, I_PL); /* P last addr */ +qla = ADDR_A (PC, I_QL); /* Q last addr */ +if (flags & IF_VPA) { /* need P? */ + reason = get_addr (pla, 5, TRUE, &PAR); /* get P addr */ + if (reason != SCPE_OK) break; } /* stop if error */ +if (flags & (IF_VQA | IF_4QA | IF_NQX)) { /* need Q? */ + reason = get_addr (qla, /* get Q addr */ + ((flags & IF_4QA)? 4: 5), /* 4 or 5 digits */ + ((flags & IF_NQX)? FALSE: TRUE), /* not or indexed */ + &QAR); + if (reason != SCPE_OK) { /* stop if invalid */ + reason = reason + (STOP_INVQDG - STOP_INVPDG); + break; } } +else if (flags & IF_IMM) QAR = qla; /* immediate? */ +PC = PC + INST_LEN; /* advance PC */ +switch (op) { /* case on op */ + +/* Transmit digit - P,Q are valid */ + +case OP_TD: +case OP_TDM: + M[PAR] = M[QAR] & (FLAG | DIGIT); /* move dig, flag */ + break; + +/* Transmit field - P,Q are valid */ + +case OP_TF: +case OP_TFM: + reason = xmt_field (PAR, QAR, 1); /* xmit field */ + break; + +/* Transmit record - P,Q are valid */ + +case OP_TR: + reason = xmt_record (PAR, QAR, TRUE); /* xmit record */ + break; + +/* Transmit record no record mark - P,Q are valid */ + +case OP_TRNM: + reason = xmt_record (PAR, QAR, FALSE); /* xmit record but */ + break; /* not rec mark */ + +/* Set flag - P is valid */ + +case OP_SF: + M[PAR] = M[PAR] | FLAG; /* set flag on P */ + break; + +/* Clear flag - P is valid */ + +case OP_CF: + M[PAR] = M[PAR] & ~FLAG; /* clear flag on P */ + break; + +/* Branch - P is valid */ + +case OP_B: + BRANCH (PAR); /* branch to P */ + break; + +/* Branch and transmit - P,Q are valid */ + +case OP_BT: +case OP_BTM: + reason = xmt_field (ADDR_S (PAR, 1), QAR, 1); /* xmit field to P-1 */ + IR2 = PC; /* save PC */ + BRANCH (PAR); /* branch to P */ + break; + +/* Branch and transmit floating - P,Q are valid */ + +case OP_BTFL: + reason = xmt_field (ADDR_S (PAR, 1), QAR, 3); /* skip 3 flags */ + IR2 = PC; /* save PC */ + BRANCH (PAR); /* branch to P */ + break; + +/* Branch and transmit address - P,Q are valid */ + +case OP_BTA: +case OP_BTAM: + reason = xmt_field (ADDR_S (PAR, 1), QAR, 4); /* skip 4 flags */ + IR2 = PC; /* save PC */ + BRANCH (PAR); /* branch to P */ + break; + +/* Branch back */ + +case OP_BB: + if (PR1 != 1) { /* PR1 valid? */ + BRANCH (PR1); /* return to PR1 */ + PR1 = 1; } /* invalidate */ + else if (IR2 != 1) { /* IR2 valid? */ + BRANCH (IR2); /* return to IR2 */ + IR2 = 1; } /* invalidate */ + else reason = STOP_INVRTN; /* MAR check */ + break; + +/* Branch on digit (zero) - P,Q are valid */ + +case OP_BD: + if ((M[QAR] & DIGIT) == 0) { /* digit == 0? */ + BRANCH (PAR); } /* branch */ + break; + +/* Branch no flag - P,Q are valid */ + +case OP_BNF: + if ((M[QAR] & FLAG) == 0) { /* flag == 0? */ + BRANCH (PAR); } /* branch */ + break; + +/* Branch no record mark (8-2 not set) - P,Q are valid */ + +case OP_BNR: + if ((M[QAR] & REC_MARK) != REC_MARK) { /* not rec mark? */ + BRANCH (PAR); } /* branch */ + break; + +/* Branch no group mark - P,Q are valid */ + +case OP_BNG: + if ((M[QAR] & DIGIT) != GRP_MARK) { /* not grp mark? */ + BRANCH (PAR); } /* branch */ + break; + +/* Branch (no) indicator - P is valid */ + +case OP_BI: +case OP_BNI: + upd_ind (); /* update indicators */ + t = get_2d (ADDR_A (saved_PC, I_BR)); /* get ind number */ + if ((t < 0) || (ind_table[t] < 0)) { /* not valid? */ + reason = STOP_INVIND; /* stop */ + break; } + if ((ind[t] != 0) ^ (op == OP_BNI)) { /* ind value correct? */ + BRANCH (PAR); } /* branch */ + if (ind_table[t] > 0) ind[t] = 0; /* reset if needed */ + break; + +/* Add/subtract/compare - P,Q are valid */ + +case OP_A: +case OP_AM: + reason = add_field (PAR, QAR, FALSE, TRUE, &sta); /* add, store */ + if (sta == ADD_CARRY) ind[IN_OVF] = 1; /* cout => ovflo */ + if (ar_stop && ind[IN_OVF]) reason = STOP_OVERFL; + break; + +case OP_S: +case OP_SM: + reason = add_field (PAR, QAR, TRUE, TRUE, &sta); /* sub, store */ + if (sta == ADD_CARRY) ind[IN_OVF] = 1; /* cout => ovflo */ + if (ar_stop && ind[IN_OVF]) reason = STOP_OVERFL; + break; + +case OP_C: +case OP_CM: + reason = add_field (PAR, QAR, TRUE, FALSE, &sta); /* sub, nostore */ + if (sta == ADD_CARRY) ind[IN_OVF] = 1; /* cout => ovflo */ + if (ar_stop && ind[IN_OVF]) reason = STOP_OVERFL; + break; + +/* Multiply - P,Q are valid */ + +case OP_M: +case OP_MM: + reason = mul_field (PAR, QAR); /* multiply */ + break; + +/* IO instructions - P is valid */ + +case OP_RA: +case OP_WA: + if ((PAR & 1) == 0) { /* P even? */ + reason = STOP_INVEAD; /* stop */ + break; } +case OP_K: +case OP_DN: +case OP_RN: +case OP_WN: + dev = get_2d (ADDR_A (saved_PC, I_IO)); /* get IO dev */ + f0 = M[ADDR_A (saved_PC, I_CTL)] & DIGIT; /* get function */ + f1 = M[ADDR_A (saved_PC, I_CTL + 1)] & DIGIT; + if ((dev < 0) || (iodisp[dev] == NULL)) /* undefined dev? */ + reason = STOP_INVIO; /* stop */ + else reason = iodisp[dev] (op, PAR, f0, f1); /* call device */ + break; + +/* Divide special feature instructions */ + +case OP_LD: +case OP_LDM: + for (i = 0; i < PROD_AREA_LEN; i++) /* clear prod area */ + M[PROD_AREA + i] = 0; + t = M[QAR] & FLAG; /* save Q sign */ + reason = xmt_divd (PAR, QAR); /* xmit dividend */ + M[PROD_AREA + PROD_AREA_LEN - 1] |= t; /* set sign */ + break; + +/* Divide - P,Q are valid */ + +case OP_D: +case OP_DM: + reason = div_field (PAR, QAR, &t); /* divide */ + ind[IN_EZ] = t; /* set indicator */ + if ((reason == STOP_OVERFL) && !ar_stop) /* ovflo stop? */ + reason = SCPE_OK; /* no */ + break; + +/* Edit special feature instructions */ + +/* Move flag - P,Q are valid */ + +case OP_MF: + M[PAR] = (M[PAR] & ~FLAG) | (M[QAR] & FLAG); /* copy Q flag */ + M[QAR] = M[QAR] & ~FLAG; /* clr Q flag */ + break; + +/* Transmit numeric strip - P,Q are valid, P is source */ + +case OP_TNS: + if ((PAR & 1) == 0) { /* P must be odd */ + reason = STOP_INVEAD; + break; } + reason = xmt_tns (QAR, PAR); /* xmit and strip */ + break; + +/* Transmit numeric fill - P,Q are valid */ + +case OP_TNF: + if ((PAR & 1) == 0) { /* P must be odd */ + reason = STOP_INVEAD; + break; } + reason = xmt_tnf (PAR, QAR); /* xmit and strip */ + break; + +/* Index special feature instructions */ + +/* Move address - P,Q are valid */ + +case OP_MA: + for (i = 0; i < ADDR_LEN; i++) { /* move 5 digits */ + M[PAR] = (M[PAR] & FLAG) | (M[QAR] & DIGIT); + MM (PAR); MM (QAR); } + break; + +/* Branch load index - P,Q are valid, Q not indexed */ + +case OP_BLX: +case OP_BLXM: + idx = get_idx (ADDR_A (saved_PC, I_QL - 1)); /* get index */ + if (idx < 0) { /* invalid? */ + reason = STOP_INVIDX; /* stop for now */ + break; } + xmt_index (GET_IDXADDR (idx), QAR); /* copy Q to idx */ + BRANCH (PAR); /* branch to P */ + break; + +/* Branch store index - P,Q are valid, Q not indexed */ + +case OP_BSX: + idx = get_idx (ADDR_A (saved_PC, I_QL - 1)); /* get index */ + if (idx < 0) { /* invalid? */ + reason = STOP_INVIDX; /* stop for now */ + break; } + xmt_index (QAR, GET_IDXADDR (idx)); /* copy idx to Q */ + BRANCH (PAR); /* branch to P */ + break; + +/* Branch and modify index - P,Q are valid, Q not indexed */ + +case OP_BX: +case OP_BXM: + idx = get_idx (ADDR_A (saved_PC, I_QL - 1)); /* get index */ + if (idx < 0) { /* invalid? */ + reason = STOP_INVIDX; /* stop for now */ + break; } + reason = add_field (GET_IDXADDR (idx), QAR, FALSE, TRUE, &sta); + if (ar_stop && ind[IN_OVF]) reason = STOP_OVERFL; + BRANCH (PAR); /* branch to P */ + break; + +/* Branch conditionally and modify index - P,Q are valid, Q not indexed */ + +case OP_BCX: +case OP_BCXM: + idx = get_idx (ADDR_A (saved_PC, I_QL - 1)); /* get index */ + if (idx < 0) { /* invalid? */ + reason = STOP_INVIDX; /* stop for now */ + break; } + reason = add_field (GET_IDXADDR (idx), QAR, FALSE, TRUE, &sta); + if (ar_stop && ind[IN_OVF]) reason = STOP_OVERFL; + if ((ind[IN_EZ] == 0) && (sta == ADD_NOCRY)) { /* ~z, ~c, ~schg? */ + BRANCH (PAR); } /* branch */ + break; + +/* Branch and select - P is valid */ + +case OP_BS: + t = M[ADDR_A (saved_PC, I_SEL)] & DIGIT; /* get select */ + switch (t) { /* case on select */ + case 0: + idxe = idxb = 0; /* indexing off */ + break; + case 1: + idxe = 1; idxb = 0; /* index band A */ + break; + case 2: + idxe = idxb = 1; /* index band B */ + break; + case 8: + iae = 0; /* indirect off */ + break; + case 9: + iae = 1; /* indirect on */ + break; + default: + reason = STOP_INVSEL; /* undefined */ + break; } + BRANCH (PAR); + break; + +/* Binary special feature instructions */ + +/* Branch on bit - P,Q are valid, Q is 4d address */ + +case OP_BBT: + t = M[ADDR_A (saved_PC, I_Q)]; /* get Q0 digit */ + if (t & M[QAR] & DIGIT) { /* match to mem? */ + BRANCH (PAR); } /* branch */ + break; + +/* Branch on mask - P,Q are valid, Q is 4d address */ + +case OP_BMK: + t = M[ADDR_A (saved_PC, I_Q)]; /* get Q0 digit */ + if (((t ^ M[QAR]) & /* match to mem? */ + ((t & FLAG)? (FLAG + DIGIT): DIGIT)) == 0) { + BRANCH (PAR); } /* branch */ + break; + +/* Or - P,Q are valid */ + +case OP_ORF: + reason = or_field (PAR, QAR); /* OR fields */ + break; + +/* AND - P,Q are valid */ + +case OP_ANDF: + reason = and_field (PAR, QAR); /* AND fields */ + break; + +/* Exclusive or - P,Q are valid */ + +case OP_EORF: + reason = xor_field (PAR, QAR); /* XOR fields */ + break; + +/* Complement - P,Q are valid */ + +case OP_CPLF: + reason = com_field (PAR, QAR); /* COM field */ + break; + +/* Octal to decimal - P,Q are valid */ + +case OP_OTD: + reason = oct_to_dec (PAR, QAR); /* convert */ + break; + +/* Decimal to octal - P,Q are valid */ + +case OP_DTO: + reason = dec_to_oct (PAR, QAR, &t); /* convert */ + ind[IN_EZ] = t; /* set indicator */ + if (ar_stop && ind[IN_OVF]) reason = STOP_OVERFL; + break; + +/* Floating point special feature instructions */ + +case OP_FADD: + reason = fp_add (PAR, QAR, FALSE); /* add */ + if (ar_stop && ind[IN_EXPCHK]) reason = STOP_EXPCHK; + break; + +case OP_FSUB: + reason = fp_add (PAR, QAR, TRUE); /* subtract */ + if (ar_stop && ind[IN_EXPCHK]) reason = STOP_EXPCHK; + break; + +case OP_FMUL: + reason = fp_mul (PAR, QAR); /* multiply */ + if (ar_stop && ind[IN_EXPCHK]) reason = STOP_EXPCHK; + break; + +case OP_FDIV: + reason = fp_div (PAR, QAR); /* divide */ + if (ar_stop && ind[IN_OVF]) reason = STOP_FPDVZ; + if (ar_stop && ind[IN_EXPCHK]) reason = STOP_EXPCHK; + break; + +case OP_FSL: + reason = fp_fsl (PAR, QAR); /* shift left */ + break; + +case OP_FSR: + reason = fp_fsr (PAR, QAR); /* shift right */ + break; + +/* Halt */ + +case OP_H: + saved_PC = PC; /* commit inst */ + reason = STOP_HALT; /* stop */ + break; + +/* NOP */ + +case OP_NOP: + break; + +/* Invalid instruction code */ + +default: + reason = STOP_INVINS; /* stop */ + break; } /* end switch */ + } /* end while */ + +/* Simulation halted */ + +pcq_r->qptr = pcq_p; /* update pc q ptr */ +upd_ind (); +return reason; +} + +/* Utility routines */ + +/* Get 2 digit field + + Inputs: + ad = address of high digit + Outputs: + val = field converted to binary + -1 if bad digit +*/ + +int32 get_2d (uint32 ad) +{ +int32 d, d1; + +d = M[ad] & DIGIT; /* get 1st digit */ +d1 = M[ADDR_A (ad, 1)] & DIGIT; /* get 2nd digit */ +if (BAD_DIGIT (d) || BAD_DIGIT (d1)) return -1; /* bad? error */ +return ((d * 10) + d1); /* cvt to binary */ +} + +/* Get address routine + + Inputs: + alast = address of low digit + lnt = length + indexok = TRUE if indexing allowed + &addr = pointer to address output + Output: + return = error status (in terms of P address) + addr = address converted to binary + + Notes: + - If indexing produces a negative result, the effective address is + the 10's complement of the result + - An address that exceeds memory produces a MAR check stop +*/ + +t_stat get_addr (uint32 alast, int32 lnt, t_bool indexok, uint32 *reta) +{ +uint8 indir; +int32 cnt, idx, idxa, idxv, addr; + +if (iae) indir = FLAG; /* init indirect */ +else indir = 0; + +cnt = 0; /* count depth */ +do { indir = indir & M[alast]; /* get indirect */ + if (cvt_addr (alast, lnt, FALSE, &addr)) /* cvt addr to bin */ + return STOP_INVPDG; /* bad? */ + idx = get_idx (ADDR_S (alast, 1)); /* get index addr */ + if (indexok && (idx > 0)) { /* indexable? */ + idxa = GET_IDXADDR (idx); /* get idx addr */ + if (cvt_addr (idxa, ADDR_LEN, TRUE, &idxv)) /* cvt idx */ + return STOP_INVPDG; + addr = addr + idxv; /* add in index */ + if (addr < 0) addr = addr + 100000; } /* -? 10's comp */ + if (addr >= (int32) MEMSIZE) return STOP_INVPAD;/* invalid addr? */ + alast = addr; /* new address */ + lnt = ADDR_LEN; } /* std len */ +while (indir && (cnt++ < ind_max)); +if (cnt > ind_max) return STOP_INVPIA; /* indir too deep? */ +*reta = addr; /* return address */ +return SCPE_OK; +} + +/* Convert address to binary + + Inputs: + alast = address of low digit + lnt = length + signok = TRUE if signed + val = address of output + Outputs: + status = 0 if ok, != 0 if error +*/ + +t_stat cvt_addr (uint32 alast, int32 lnt, t_bool signok, int32 *val) +{ +int32 sign = 0, addr = 0, t; + +if (signok && (M[alast] & FLAG)) sign = 1; /* signed? */ +alast = alast - lnt; /* find start */ +do { PP (alast); /* incr mem addr */ + t = M[alast] & DIGIT; /* get digit */ + if (BAD_DIGIT (t)) return STOP_INVDIG; /* bad? error */ + addr = (addr * 10) + t; } /* cvt to bin */ +while (--lnt > 0); +if (sign) *val = -addr; /* minus? */ +else *val = addr; +return SCPE_OK; +} + +/* Get index register number + + Inputs: + aidx = address of low digit + Outputs: + index = >0 if indexed + =0 if not indexed + <0 if indexing disabled +*/ + +t_stat get_idx (uint32 aidx) +{ +int32 i, idx = 0; + +if (idxe == 0) return -1; /* indexing off? */ +for (i = 0; i < 3; i++) { /* 3 flags worth */ + if (M[aidx] & FLAG) idx = idx | (1 << i); /* test flag */ + MM (aidx); } /* next digit */ +return idx; +} + +/* Update indicators routine */ + +void upd_ind (void) +{ +ind[IN_HPEZ] = ind[IN_HP] | ind[IN_EZ]; /* HPEZ = HP | EZ */ +ind[IN_DERR] = ind[IN_DACH] | ind[IN_DWLR] | ind[IN_DCYO]; +ind[IN_ANYCHK] = ind[IN_RDCHK] | ind[IN_WRCHK] | /* ANYCHK = all chks */ + ind[IN_MBREVEN] | ind[IN_MBRODD] | + ind[IN_PRCHK] | ind[IN_DACH]; +ind[IN_IXN] = ind[IN_IXA] = ind[IN_IXB] = 0; /* clr index indics */ +if (!idxe) ind[IN_IXN] = 1; /* off? */ +else if (!idxb) ind[IN_IXA] = 1; /* on, band A? */ +else ind[IN_IXB] = 1; /* no, band B */ +return; +} + +/* Transmit routines */ + +/* Transmit field from 's' to 'd' - ignore first 'skp' flags */ + +t_stat xmt_field (uint32 d, uint32 s, uint32 skp) +{ +t_addr cnt = 0; +uint8 t; + +do { t = M[d] = M[s] & (FLAG | DIGIT); /* copy src to dst */ + MM (d); MM (s); /* decr mem addrs */ + if (cnt++ >= MEMSIZE) return STOP_FWRAP; } /* (stop runaway) */ +while (((t & FLAG) == 0) || (cnt <= skp)); /* until flag */ +return SCPE_OK; +} + +/* Transmit record from 's' to 'd' - copy record mark if 'cpy' = TRUE */ + +t_stat xmt_record (uint32 d, uint32 s, t_bool cpy) +{ +t_addr cnt = 0; + +while ((M[s] & REC_MARK) != REC_MARK) { /* until rec mark */ + M[d] = M[s] & (FLAG | DIGIT); /* copy src to dst */ + PP (d); PP (s); /* incr mem addrs */ + if (cnt++ >= MEMSIZE) return STOP_RWRAP; } /* (stop runaway) */ +if (cpy) M[d] = M[s] & (FLAG | DIGIT); /* copy rec mark */ +return SCPE_OK; +} + +/* Transmit index from 's' to 'd' - fixed five character field */ + +t_stat xmt_index (uint32 d, uint32 s) +{ +int32 i; + +M[d] = M[s] & (FLAG | DIGIT); /* preserve sign */ +MM (d); MM (s); /* decr mem addrs */ +for (i = 0; i < ADDR_LEN - 2; i++) { /* copy 3 digits */ + M[d] = M[s] & DIGIT; /* without flags */ + MM (d); MM (s); } /* decr mem addrs */ +M[d] = (M[s] & DIGIT) | FLAG; /* set flag on last */ +return SCPE_OK; +} + +/* Transmit dividend from 'd' to 's' - clear flag on first digit */ + +t_stat xmt_divd (uint32 d, uint32 s) +{ +t_addr cnt = 0; + +M[d] = M[s] & DIGIT; /* first w/o flag */ +do { MM (d); MM (s); /* decr mem addrs */ + M[d] = M[s] & (FLAG | DIGIT); /* copy src to dst */ + if (cnt++ >= MEMSIZE) return STOP_FWRAP; } /* (stop runaway) */ +while ((M[d] & FLAG) == 0); /* until src flag */ +return SCPE_OK; +} + +/* Transmit numeric strip from 's' to 'd' - s is odd */ + +t_stat xmt_tns (uint32 d, uint32 s) +{ +t_addr cnt = 0; +uint8 t, z; + +t = M[s] & DIGIT; /* get units */ +z = M[s - 1] & DIGIT; /* get zone */ +if ((z == 1) || (z == 5) || ((z == 2) && (t == 0))) /* 1x, 5x, 20? */ + M[d] = t | FLAG; /* set flag */ +else M[d] = t; /* else clear flag */ +do { MM (d); /* decr mem addrs */ + s = ADDR_S (s, 2); + t = M[d] & FLAG; /* save dst flag */ + M[d] = M[s] & (FLAG | DIGIT); /* copy src to dst */ + if (cnt >= MEMSIZE) return STOP_FWRAP; /* (stop runaway) */ + cnt = cnt + 2; } +while (t == 0); /* until dst flag */ +M[d] = M[d] | FLAG; /* set flag at end */ +return SCPE_OK; +} + +/* Transmit numeric fill from 's' to 'd' - d is odd */ + +t_stat xmt_tnf (uint32 d, uint32 s) +{ +t_addr cnt = 0; +uint8 t; + +t = M[s]; /* get 1st digit */ +M[d] = t & DIGIT; /* store */ +M[d - 1] = (t & FLAG)? 5: 7; /* set sign from flag */ +do { MM (s); /* decr mem addr */ + d = ADDR_S (d, 2); + t = M[s]; /* get src digit */ + M[d] = t & DIGIT; /* move to dst, no flag */ + M[d - 1] = 7; /* set zone */ + if (cnt >= MEMSIZE) return STOP_FWRAP; /* (stop runaway) */ + cnt = cnt + 2; } +while ((t & FLAG) == 0); /* until src flag */ +return SCPE_OK; +} + +/* Add routine + + Inputs: + d = destination field low (P) + s = source field low (Q) + sub = TRUE if subtracting + sto = TRUE if storing + Output: + return = status + sta = ADD_NOCRY: no carry out, no sign change + ADD_SCHNG: sign change + ADD_CARRY: carry out + + Reference Manual: "When the sum is zero, the sign of the P field + is retained." +*/ + +t_stat add_field (uint32 d, uint32 s, t_bool sub, t_bool sto, int32 *sta) +{ +uint32 cry, src, dst, res, comp, dp, dsv; +uint32 src_f = 0, cnt = 0, dst_f; + +*sta = ADD_NOCRY; /* assume no cry */ +dsv = d; /* save dst */ +comp = ((M[d] ^ M[s]) & FLAG) ^ (sub? FLAG: 0); /* set compl flag */ +cry = 0; /* clr carry */ +ind[IN_HP] = ((M[d] & FLAG) == 0); /* set sign from res */ +ind[IN_EZ] = 1; /* assume zero */ + +dst = M[d] & DIGIT; /* 1st digits */ +src = M[s] & DIGIT; +if (BAD_DIGIT (dst) || BAD_DIGIT (src)) /* bad digit? */ + return STOP_INVDIG; +if (comp) src = 10 - src; /* complement? */ +res = add_one_digit (dst, src, &cry); /* add */ +if (sto) M[d] = (M[d] & FLAG) | res; /* store */ +MM (d); MM (s); /* decr mem addrs */ +do { dst = M[d] & DIGIT; /* get dst digit */ + dst_f = M[d] & FLAG; /* get dst flag */ + if (src_f) src = 0; /* src done? src = 0 */ + else { + src = M[s] & DIGIT; /* get src digit */ + src_f = M[s] & FLAG; /* get src flag */ + MM (s); } /* decr src addr */ + if (BAD_DIGIT (dst) || BAD_DIGIT (src)) /* bad digit? */ + return STOP_INVDIG; + if (comp) src = 9 - src; /* complement? */ + res = add_one_digit (dst, src, &cry); /* add */ + if (sto) M[d] = dst_f | res; /* store */ + MM (d); /* decr dst addr */ + if (cnt++ >= MEMSIZE) return STOP_FWRAP; } /* (stop runaway) */ +while (dst_f == 0); /* until dst done */ +if (!src_f) ind[IN_OVF] = 1; /* !src done? ovf */ +if (comp && !cry && !ind[IN_EZ]) { /* recomp needed? */ + ind[IN_HP] = ind[IN_HP] ^ 1; /* flip indicator */ + if (sto) { /* storing? */ + for (cry = 1, dp = dsv; dp != d; ) { /* rescan */ + dst = M[dp] & DIGIT; /* get dst digit */ + res = add_one_digit (9 - dst, 0, &cry); /* "add" */ + M[dp] = (M[dp] & FLAG) | res; /* store */ + MM (dp); } /* decr dst addr */ + M[dsv] = M[dsv] ^ FLAG; } /* compl sign */ + *sta = ADD_SIGNC; /* sign changed */ + return SCPE_OK; } /* end if recomp */ +if (ind[IN_EZ]) ind[IN_HP] = 0; /* res = 0? clr HP */ +if (!comp && cry) *sta = ADD_CARRY; /* set status */ +return SCPE_OK; +} + +/* Add one digit via table (Model 1) or "hardware" (Model 2) */ + +uint32 add_one_digit (uint32 dst, uint32 src, uint32 *cry) +{ +uint32 res; + +if (*cry) src = src + 1; /* cry in? incr src */ +if (src >= 10) { /* src > 10? */ + src = src - 10; /* src -= 10 */ + *cry = 1; } /* carry out */ +else *cry = 0; /* else no carry */ +if (cpu_unit.flags & IF_MII) /* Model 2? */ + res = sum_table[dst + src]; /* "hardware" */ +else res = M[ADD_TABLE + (dst * 10) + src]; /* table lookup */ +if (res & FLAG) *cry = 1; /* carry out? */ +if (res & DIGIT) ind[IN_EZ] = 0; /* nz? clr ind */ +return res & DIGIT; +} + +/* Multiply routine + + Inputs: + mpc = multiplicand address + mpy = multiplier address + Outputs: + return = status + + Reference manual: "A zero product may have a negative or positive sign, + depending on the signs of the fields at the P and Q addresses." +*/ + +t_stat mul_field (uint32 mpc, uint32 mpy) +{ +int32 i; +uint32 pro; /* prod pointer */ +uint32 mpyd, mpyf; /* mpy digit, flag */ +t_addr cnt = 0; /* counter */ +uint8 sign; /* final sign */ +t_stat r; + +PR1 = 1; /* step on PR1 */ +for (i = 0; i < PROD_AREA_LEN; i++) /* clr prod area */ + M[PROD_AREA + i] = 0; +sign = (M[mpc] & FLAG) ^ (M[mpy] & FLAG); /* get final sign */ +ind[IN_HP] = (sign == 0); /* set indicators */ +ind[IN_EZ] = 1; +pro = PROD_AREA + PROD_AREA_LEN - 1; /* product ptr */ + +/* Loop on multiplier (mpy) and product (pro) digits */ + +do { mpyd = M[mpy] & DIGIT; /* multiplier digit */ + mpyf = (M[mpy] & FLAG) && (cnt != 0); /* last digit flag */ + if (BAD_DIGIT (mpyd)) return STOP_INVDIG; /* bad? */ + r = mul_one_digit (mpyd, mpc, pro, mpyf); /* prod += mpc*mpy_dig */ + if (r != SCPE_OK) return r; /* error? */ + MM (mpy); MM (pro); /* decr mpyr, prod addrs */ + if (cnt++ > MEMSIZE) return STOP_FWRAP; } /* (stop runaway) */ +while ((mpyf == 0) || (cnt <= 1)); /* until mpyr flag */ + +if (ind[IN_EZ]) ind[IN_HP] = 0; /* res = 0? clr HP */ +M[PROD_AREA + PROD_AREA_LEN - 1] |= sign; /* set final sign */ +return SCPE_OK; +} + +/* Multiply step + + Inputs: + mpyd = multiplier digit (tested valid) + mpcp = multiplicand low address + prop = product low address + last = last iteration flag (set flag on high product) + Outputs: + prod += multiplicand * multiplier_digit + return = status + + The multiply table address is constructed as follows: + - double the multiplier digit + - use the 10's digit of the doubled result, + 1, as the 100's digit + of the table address + - use the multiplicand digit as the 10's digit of the table address + - use the unit digit of the doubled result as the unit digit of the + table address + EZ indicator is cleared if a non-zero digit is ever generated +*/ + +t_stat mul_one_digit (uint32 mpyd, uint32 mpcp, uint32 prop, uint32 last) +{ +uint32 mpta, mptb; /* mult table */ +uint32 mptd; /* mult table digit */ +uint32 mpcd, mpcf; /* mpc digit, flag */ +uint32 prwp; /* prod working ptr */ +uint32 prod; /* product digit */ +uint32 cry; /* carry */ +t_addr mpcc, cryc; /* counters */ + +mptb = MUL_TABLE + ((mpyd <= 4)? (mpyd * 2): /* set mpy table 100's, */ + (((mpyd - 5) * 2) + 100)); /* 1's digits */ + +/* Inner loop on multiplicand (mpcp) and product (prop) digits */ + +mpcc = 0; /* multiplicand ctr */ +do { prwp = prop; /* product working ptr */ + mpcd = M[mpcp] & DIGIT; /* multiplicand digit */ + mpcf = M[mpcp] & FLAG; /* multiplicand flag */ + if (BAD_DIGIT (mpcd)) return STOP_INVDIG; /* bad? */ + mpta = mptb + (mpcd * 10); /* mpy table 10's digit */ + cry = 0; /* init carry */ + mptd = M[mpta] & DIGIT; /* mpy table digit */ + if (BAD_DIGIT (mptd)) return STOP_INVDIG; /* bad? */ + prod = M[prwp] & DIGIT; /* product digit */ + if (BAD_DIGIT (prod)) return STOP_INVDIG; /* bad? */ + M[prwp] = add_one_digit (prod, mptd, &cry); /* add mpy tbl to prod */ + MM (prwp); /* decr working ptr */ + mptd = M[mpta + 1] & DIGIT; /* mpy table digit */ + if (BAD_DIGIT (mptd)) return STOP_INVDIG; /* bad? */ + prod = M[prwp] & DIGIT; /* product digit */ + if (BAD_DIGIT (prod)) return STOP_INVDIG; /* bad? */ + M[prwp] = add_one_digit (prod, mptd, &cry); /* add mpy tbl to prod */ + cryc = 0; /* (stop runaway) */ + while (cry) { /* propagate carry */ + MM (prwp); /* decr working ptr */ + prod = M[prwp] & DIGIT; /* product digit */ + if (BAD_DIGIT (prod)) return STOP_INVDIG; /* bad? */ + M[prwp] = add_one_digit (prod, 0, &cry); /* add cry */ + if (cryc++ > MEMSIZE) return STOP_FWRAP; } + MM (mpcp); MM (prop); /* decr mpc, prod ptrs */ + if (mpcc++ > MEMSIZE) return STOP_FWRAP; } +while ((mpcf == 0) || (mpcc <= 1)); /* until mpcf flag */ +if (last) + M[prop] = M[prop] | FLAG; /* flag high product */ +return SCPE_OK; +} + +/* Divide routine - comments from Geoff Kuenning's 1620 simulator + + The destination of the divide is given by: + + 100 - <# digits in quotient> + + Which is more easily calculated as: + + 100 - <# digits in divisor> - <# digits in dividend> + + The quotient goes into 99 minus the divisor length. The + remainder goes into 99. The load dividend instruction (above) + should have specified a P address of 99 minus the size of the + divisor. + + Note that this all implies that "dest" points to the *leftmost* + digit of the dividend. + + After the division, the assumed decimal point will be as many + positions to the left as there are digits in the divisor. In + other words, a 4-digit divisor will produce 4 (assumed) decimal + places. + + There are other ways to do these things. In particular, the + load-dividend instruction doesn't have to specify the above + formula; if it's done differently, then you don't have to get + decimal places. This is not well-explained in the books I have. + + How to divide on a 1620: + + The dividend is the field at 99: + + 90 = _1234567890 + + The divisor is somewhere else in memory: + + _03 + + The divide operation specifies the left-most digit of the + dividend as the place to begin trial subtractions: + + DM 90,3 + + The loop works as follows: + + 1. Call the left-most digit of the dividend "current_dividend". + Call the location current_dividend - + "quotient_digit". + 2. Clear the flag at current_dividend, and set one at + quotient_digit. + + 88 = _001234567890, q_d = 88, c_d = 90 + [Not actually done; divisor length controls subtract.] + 3. Subtract the divisor from the field at current-dividend, + using normal 1620 rules, except that signs are ignored. + Continue these subtractions until either 10 subtractions + have been done, or you get a negative result: + + 88 = _00_2234567890, q_d = 88, c_d = 90 + 4. If 10 subtractions have been done, set the overflow + indicator and abort. Otherwise, add the divisor back to + correct for the oversubtraction: + + 88 = _001234567890, q_d = 88, c_d = 90 + 5. Store the (net) number of subtractions in quotient_digit: + + 88 = _001234567890, q_d = 88, c_d = 90 + 6. If this is not the first pass, clear the flag at + quotient_digit. Increment quotient_digit and + current_dividend, and set a flag at the new + quotient_digit: + + 88 = _0_01234567890, q_d = 89, c_d = 91 + [If first pass, set a flag at quotient digit.] + 7. If current_dividend is not 100, repeat steps 3 through 7. + 8. Set flags at 99 and quotient_digit - 1 according to the + rules of algebra: the quotient's sign is the exclusive-or + of the signs of the divisor and dividend, and the + remainder has the sign of the dividend: + + 10 / 3 = 3 remainder 1 + 10 / -3 = -3 remainder 1 + -10 / 3 = -3 remainder -1 + -10 / -3 = 3 remainder -1 + + This preserves the relationship dd = q * dv + r. + + Our example continues as follows for steps 3 through 7: + + 3. 88 = _0_00_334567890, q_d = 89, c_d = 91 + 4. 88 = _0_00034567890 + 5. 88 = _0_40034567890 + 6. 88 = _04_0034567890, q_d = 90, c_d = 92 + 3. 88 = _04_00_34567890 + 4. 88 = _04_0004567890 + 5. 88 = _04_1004567890 + 6. 88 = _041_004567890, q_d = 91, c_d = 93 + 3. 88 = _041_00_2567890 + 4. 88 = _041_001567890 + 5. 88 = _041_101567890 + 6. 88 = _0411_01567890, q_d = 92, c_d = 94 + 3. 88 = _0411_00_367890 + 4. 88 = _0411_00067890 + 5. 88 = _0411_50067890 + 6. 88 = _04115_0067890, q_d = 93, c_d = 95 + 3. 88 = _04115_00_37890 + 4. 88 = _04115_0007890 + 5. 88 = _04115_2007890 + 6. 88 = _041152_007890, q_d = 94, c_d = 96 + 3. 88 = _041152_00_2890 + 4. 88 = _041152_001890 + 5. 88 = _041152_201890 + 6. 88 = _0411522_01890, q_d = 95, c_d = 97 + 3. 88 = _0411522_00_390 + 4. 88 = _0411522_00090 + 5. 88 = _0411522_60090 + 6. 88 = _04115226_0090, q_d = 96, c_d = 98 + 3. 88 = _04115226_00_30 + 4. 88 = _04115226_0000 + 5. 88 = _04115226_3000 + 6. 88 = _041152263_000, q_d = 97, c_d = 99 + 3. 88 = _041152263_00_3 + 4. 88 = _041152263_000 + 5. 88 = _041152263_000 + 6. 88 = _0411522630_00, q_d = 98, c_d = 100 + + In the actual code below, we elide several of these steps in + various ways for convenience and efficiency. + + Note that the EZ indicator is NOT valid for divide, because it + is cleared by any non-zero result in an intermediate add. The + code maintains its own EZ indicator for the quotient. +*/ + +t_stat div_field (uint32 dvd, uint32 dvr, int32 *ez) +{ +uint32 quop, quod, quos; /* quo ptr, dig, sign */ +uint32 dvds; /* dvd sign */ +t_bool first = TRUE; /* first pass */ +t_stat r; + +dvds = (M[PROD_AREA + PROD_AREA_LEN - 1]) & FLAG; /* dividend sign */ +quos = dvds ^ (M[dvr] & FLAG); /* quotient sign */ +ind[IN_HP] = (quos == 0); /* set indicators */ +*ez = 1; + +/* Loop on current dividend, high order digit at dvd */ + +do { r = div_one_digit (dvd, dvr, 10, &quod, &quop); /* dev quo digit */ + if (r != SCPE_OK) return r; /* error? */ + +/* Store quotient digit and advance current dividend pointer */ + + if (first) { /* first pass? */ + if (quod >= 10) { /* overflow? */ + ind[IN_OVF] = 1; /* set indicator */ + return STOP_OVERFL; } /* stop */ + M[quop] = FLAG | quod; /* set flag on quo */ + first = FALSE; } + else M[quop] = quod; /* store quo digit */ + if (quod) *ez = 0; /* if nz, clr ind */ + PP (dvd); } /* incr dvd ptr */ +while (dvd != (PROD_AREA + PROD_AREA_LEN)); /* until end prod */ + +/* Division done. Set signs of quo, rem, set flag on high order remainder */ + +if (*ez) ind[IN_HP] = 0; /* res = 0? clr HP */ +M[PROD_AREA + PROD_AREA_LEN - 1] |= dvds; /* remainder sign */ +M[quop] = M[quop] | quos; /* quotient sign */ +PP (quop); /* high remainder */ +M[quop] = M[quop] | FLAG; /* set flag */ +return SCPE_OK; +} + +/* Divide step + + Inputs: + dvd = current dividend address (high digit) + dvr = divisor address (low digit) + max = max number of iterations before overflow + &quod = address to store quotient digit + &quop = address to store quotient pointer (can be NULL) + Outputs: + return = status + + Divide step calculates a quotient digit by repeatedly subtracting the + divisor from the current dividend. The divisor's length controls the + subtraction; dividend flags are ignored. +*/ + +t_stat div_one_digit (uint32 dvd, uint32 dvr, uint32 max, + uint32 *quod, uint32 *quop) +{ +uint32 dvrp, dvrd, dvrf; /* dvr ptr, dig, flag */ +uint32 dvdp, dvdd; /* dvd ptr, dig */ +uint32 qd, cry; /* quo dig, carry */ +t_addr cnt; + +for (qd = 0; qd < max; qd++) { /* devel quo dig */ + dvrp = dvr; /* divisor ptr */ + dvdp = dvd; /* dividend ptr */ + cnt = 0; + cry = 1; /* carry in = 1 */ + do { /* sub dvr fm dvd */ + dvdd = M[dvdp] & DIGIT; /* dividend digit */ + if (BAD_DIGIT (dvdd)) return STOP_INVDIG; /* bad? */ + dvrd = M[dvrp] & DIGIT; /* divisor digit */ + dvrf = M[dvrp] & FLAG; /* divisor flag */ + if (BAD_DIGIT (dvrd)) return STOP_INVDIG; /* bad? */ + M[dvdp] = add_one_digit (dvdd, 9 - dvrd, &cry); /* sub */ + MM (dvdp); MM (dvrp); /* decr ptrs */ + if (cnt++ > MEMSIZE) return STOP_FWRAP; } /* (stop runaway) */ + while ((dvrf == 0) || (cnt <= 1)); /* until dvr flag */ + if (!cry) { /* !cry = borrow */ + dvdd = M[dvdp] & DIGIT; /* borrow digit */ + if (BAD_DIGIT (dvdd)) return STOP_INVDIG; /* bad? */ + M[dvdp] = add_one_digit (dvdd, 9, &cry); } /* sub */ + if (!cry) break; } /* !cry = negative */ + +/* Add back the divisor to correct for the negative result */ + +dvrp = dvr; /* divisor ptr */ +dvdp = dvd; /* dividend ptr */ +cnt = 0; +cry = 0; /* carry in = 0 */ +do { dvdd = M[dvdp] & DIGIT; /* dividend digit */ + dvrd = M[dvrp] & DIGIT; /* divisor digit */ + dvrf = M[dvrp] & FLAG; /* divisor flag */ + M[dvdp] = add_one_digit (dvdd, dvrd, &cry); /* add */ + MM (dvdp); MM (dvrp); cnt++; } /* decr ptrs */ +while ((dvrf == 0) || (cnt <= 1)); /* until dvr flag */ +if (cry) { /* carry out? */ + dvdd = M[dvdp] & DIGIT; /* borrow digit */ + M[dvdp] = add_one_digit (dvdd, 0, &cry); } /* add */ +if (quop != NULL) *quop = dvdp; /* set quo addr */ +*quod = qd; /* set quo digit */ +return SCPE_OK; +} + +/* Logical operation routines (and, or, xor, complement) + + Inputs: + d = destination address + s = source address + Output: + return = status + + Destination flags are preserved; EZ reflects the result. + COM does not obey normal field length restrictions. +*/ + +t_stat or_field (uint32 d, uint32 s) +{ +t_addr cnt = 0; +int32 t; + +ind[IN_EZ] = 1; /* assume result zero */ +do { t = M[s]; /* get src */ + M[d] = (M[d] & FLAG) | ((M[d] | t) & 07); /* OR src to dst */ + if (M[d] & DIGIT) ind[IN_EZ] = 0; /* nz dig? clr ind */ + MM (d); MM (s); /* decr pointers */ + if (cnt++ >= MEMSIZE) return STOP_FWRAP; } /* (stop runaway) */ +while (((t & FLAG) == 0) || (cnt <= 1)); /* until src flag */ +return SCPE_OK; +} + +t_stat and_field (uint32 d, uint32 s) +{ +t_addr cnt = 0; +int32 t; + +ind[IN_EZ] = 1; /* assume result zero */ +do { t = M[s]; /* get src */ + M[d] = (M[d] & FLAG) | ((M[d] & t) & 07); /* AND src to dst */ + if (M[d] & DIGIT) ind[IN_EZ] = 0; /* nz dig? clr ind */ + MM (d); MM (s); /* decr pointers */ + if (cnt++ >= MEMSIZE) return STOP_FWRAP; } /* (stop runaway) */ +while (((t & FLAG) == 0) || (cnt <= 1)); /* until src flag */ +return SCPE_OK; +} + +t_stat xor_field (uint32 d, uint32 s) +{ +t_addr cnt = 0; +int32 t; + +ind[IN_EZ] = 1; /* assume result zero */ +do { t = M[s]; /* get src */ + M[d] = (M[d] & FLAG) | ((M[d] ^ t) & 07); /* XOR src to dst */ + if (M[d] & DIGIT) ind[IN_EZ] = 0; /* nz dig? clr ind */ + MM (d); MM (s); /* decr pointers */ + if (cnt++ >= MEMSIZE) return STOP_FWRAP; } /* (stop runaway) */ +while (((t & FLAG) == 0) || (cnt <= 1)); /* until src flag */ +return SCPE_OK; +} + +t_stat com_field (uint32 d, uint32 s) +{ +t_addr cnt = 0; +int32 t; + +ind[IN_EZ] = 1; /* assume result zero */ +do { t = M[s]; /* get src */ + M[d] = (t & FLAG) | ((t ^ 07) & 07); /* comp src to dst */ + if (M[d] & DIGIT) ind[IN_EZ] = 0; /* nz dig? clr ind */ + MM (d); MM (s); /* decr pointers */ + if (cnt++ >= MEMSIZE) return STOP_FWRAP; } /* (stop runaway) */ +while ((t & FLAG) == 0); /* until src flag */ +return SCPE_OK; +} + +/* Octal to decimal + + Inputs: + tbl = conversion table address (low digit) + s = source address + Outputs: + product area = converted source + result = status + + OTD is a cousin of multiply. The octal digits in the source are + multiplied by successive values in the conversion table, and the + results are accumulated in the product area. Although the manual + does not say, this code assumes that EZ and HP are affected. + */ + +t_stat oct_to_dec (uint32 tbl, uint32 s) +{ +t_addr cnt = 0, tblc; +uint32 i, sd, sf, tf, sign; +t_stat r; + +for (i = 0; i < PROD_AREA_LEN; i++) /* clr prod area */ + M[PROD_AREA + i] = 0; +sign = M[s] & FLAG; /* save sign */ +ind[IN_EZ] = 1; /* set indicators */ +ind[IN_HP] = (sign == 0); +do { sd = M[s] & DIGIT; /* src digit */ + sf = M[s] & FLAG; /* src flag */ + r = mul_one_digit (sd, tbl, PROD_AREA + PROD_AREA_LEN - 1, sf); + if (r != SCPE_OK) return r; /* err? */ + MM (s); /* decr src addr */ + MM (tbl); /* skip 1st tbl dig */ + tblc = 0; /* count */ + do { tf = M[tbl] & FLAG; /* get next */ + MM (tbl); /* decr ptr */ + if (tblc++ > MEMSIZE) return STOP_FWRAP; } + while (tf == 0); /* until flag */ + if (cnt++ > MEMSIZE) return STOP_FWRAP; } /* (stop runaway) */ +while (sf == 0); +if (ind[IN_EZ]) ind[IN_HP] = 0; /* res = 0? clr HP */ +M[PROD_AREA + PROD_AREA_LEN - 1] |= sign; /* set sign */ +return SCPE_OK; +} + +/* Decimal to octal + + Inputs: + d = destination address + tbl = conversion table address (low digit of highest power) + &ez = address of soft EZ indicator + product area = field to convert + Outputs: + return = status + + DTO is a cousin to divide. The number in the product area is repeatedly + divided by successive values in the conversion table, and the quotient + digits are stored in the destination. Although the manual does not say, + this code assumes that EZ and HP are affected. + */ + +t_stat dec_to_oct (uint32 d, uint32 tbl, int32 *ez) +{ +uint32 sign, octd, t; +t_bool first = TRUE; +t_addr ctr = 0; +t_stat r; + +sign = M[PROD_AREA + PROD_AREA_LEN - 1] & FLAG; /* input sign */ +*ez = 1; /* set indicators */ +ind[IN_HP] = (sign == 0); +for ( ;; ) { + r = div_one_digit (PROD_AREA + PROD_AREA_LEN - 1, /* divide */ + tbl, 8, &octd, NULL); + if (r != SCPE_OK) return r; /* error? */ + if (first) { /* first pass? */ + if (octd >= 8) { /* overflow? */ + ind[IN_OVF] = 1; /* set indicator */ + return SCPE_OK; } /* stop */ + M[d] = FLAG | octd; /* set flag on quo */ + first = FALSE; } + else M[d] = octd; /* store quo digit */ + if (octd) *ez = 0; /* if nz, clr ind */ + PP (tbl); /* incr tbl addr */ + if ((M[tbl] & REC_MARK) == REC_MARK) break; /* record mark? */ + PP (tbl); /* skip flag */ + if ((M[tbl] & REC_MARK) == REC_MARK) break; /* record mark? */ + do { PP (tbl); /* look for F, rec mk */ + t = M[tbl]; } + while (((t & FLAG) == 0) && ((t & REC_MARK) != REC_MARK)); + MM (tbl); /* step back one */ + PP (d); /* incr quo addr */ + if (ctr++ > MEMSIZE) return STOP_FWRAP; } /* (stop runaway) */ +if (*ez) ind[IN_HP] = 0; /* res = 0? clr HP */ +M[d] = M[d] | sign; /* set result sign */ +return SCPE_OK; +} + +/* Reset routine */ + +t_stat cpu_reset (DEVICE *dptr) +{ +int32 i; +static t_bool one_time = TRUE; + +PR1 = IR2 = 1; /* invalidate PR1,IR2 */ +ind[0] = 0; +for (i = IN_SW4 + 1; i < NUM_IND; i++) ind[i] = 0; /* init indicators */ +if (cpu_unit.flags & IF_IA) iae = 1; /* indirect enabled? */ +else iae = 0; +idxe = idxb = 0; /* indexing off */ +pcq_r = find_reg ("PCQ", NULL, dptr); /* init old PC queue */ +if (pcq_r) pcq_r->qptr = 0; +else return SCPE_IERR; +sim_brk_types = sim_brk_dflt = SWMASK ('E'); /* init breakpoints */ +upd_ind (); /* update indicators */ +if (one_time) cpu_set_table (&cpu_unit, 1, NULL, NULL); /* set default tables */ +one_time = FALSE; +return SCPE_OK; +} + +/* Memory examine */ + +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ +if (addr >= MEMSIZE) return SCPE_NXM; +if (vptr != NULL) *vptr = M[addr] & (FLAG | DIGIT); +return SCPE_OK; +} + +/* Memory deposit */ + +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ +if (addr >= MEMSIZE) return SCPE_NXM; +M[addr] = val & (FLAG | DIGIT); +return SCPE_OK; +} + +/* Memory size change */ + +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 mc = 0; +t_addr i; + +if ((val <= 0) || (val > MAXMEMSIZE) || ((val % 1000) != 0)) + return SCPE_ARG; +for (i = val; i < MEMSIZE; i++) mc = mc | M[i]; +if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) + return SCPE_OK; +MEMSIZE = val; +for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; +return SCPE_OK; +} + +/* Model change */ + +t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (val) cpu_unit.flags = (cpu_unit.flags & (UNIT_SCP | UNIT_BCD | MII_OPT)) | + IF_DIV | IF_IA | IF_EDT; +else cpu_unit.flags = cpu_unit.flags & (UNIT_SCP | UNIT_BCD | MI_OPT); +return SCPE_OK; +} + +/* Set/clear Model 1 option */ + +t_stat cpu_set_opt1 (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (cpu_unit.flags & IF_MII) { + printf ("Feature is standard on 1620 Model 2\n"); + if (sim_log) fprintf (sim_log, "Feature is standard on 1620 Model 2\n"); + return SCPE_NOFNC; } +return SCPE_OK; +} + +/* Set/clear Model 2 option */ + +t_stat cpu_set_opt2 (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (!(cpu_unit.flags & IF_MII)) { + printf ("Feature is not available on 1620 Model 1\n"); + if (sim_log) fprintf (sim_log, "Feature is not available on 1620 Model 1\n"); + return SCPE_NOFNC; } +return SCPE_OK; +} + +/* Front panel save */ + +t_stat cpu_set_save (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (saved_PC & 1) return SCPE_NOFNC; +PR1 = saved_PC; +return SCPE_OK; +} + +/* Set standard add/multiply tables */ + +t_stat cpu_set_table (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 i; + +for (i = 0; i < MUL_TABLE_LEN; i++) /* set mul table */ + M[MUL_TABLE + i] = std_mul_table[i]; +if (((cpu_unit.flags & IF_MII) == 0) || val) { /* set add table */ + for (i = 0; i < ADD_TABLE_LEN; i++) + M[ADD_TABLE + i] = std_add_table[i]; } +return SCPE_OK; +} diff --git a/I1620/i1620_defs.h b/I1620/i1620_defs.h new file mode 100644 index 00000000..b61368f5 --- /dev/null +++ b/I1620/i1620_defs.h @@ -0,0 +1,221 @@ +/* i1620_defs.h: IBM 1620 simulator definitions + + Copyright (c) 2002, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + This simulator is based on the 1620 simulator written by Geoff Kuenning. + I am grateful to Al Kossow, the Computer History Museum, and the IBM Corporate + Archives for their help in gathering documentation about the IBM 1620. + + 18-Oct-02 RMS Fixed bug in ADDR_S macro (found by Hans Pufal) +*/ + +#include "sim_defs.h" /* simulator defns */ + +/* Simulator stop codes */ + +#define STOP_HALT 1 /* HALT */ +#define STOP_IBKPT 2 /* breakpoint */ +#define STOP_INVINS 3 /* invalid instruction */ +#define STOP_INVDIG 4 /* invalid digit */ +#define STOP_INVCHR 5 /* invalid char */ +#define STOP_INVIND 6 /* invalid indicator */ +#define STOP_INVPDG 7 /* invalid P addr digit */ +#define STOP_INVPAD 8 /* invalid P addr */ +#define STOP_INVPIA 9 /* invalid P indir addr */ +#define STOP_INVQDG 10 /* invalid Q addr digits */ +#define STOP_INVQAD 11 /* invalid Q addr */ +#define STOP_INVQIA 12 /* invalid Q indir addr */ +#define STOP_INVIO 13 /* invalid IO address */ +#define STOP_INVRTN 14 /* invalid return */ +#define STOP_INVFNC 15 /* invalid function */ +#define STOP_INVIAD 16 /* invalid instr addr */ +#define STOP_INVSEL 17 /* invalid select */ +#define STOP_INVIDX 18 /* invalid index instr */ +#define STOP_INVEAD 19 /* invalid even addr */ +#define STOP_INVDCF 20 /* invalid DCF addr */ +#define STOP_INVDRV 21 /* invalid disk drive */ +#define STOP_INVDSC 22 /* invalid disk sector */ +#define STOP_INVDCN 23 /* invalid disk count */ +#define STOP_INVDBA 24 /* invalid disk buf addr */ +#define STOP_DACERR 25 /* disk addr comp err */ +#define STOP_DWCERR 26 /* disk wr check err */ +#define STOP_CYOERR 27 /* cylinder ovflo err */ +#define STOP_WRLERR 28 /* wrong rec lnt err */ +#define STOP_CCT 29 /* runaway CCT */ +#define STOP_FWRAP 30 /* field wrap */ +#define STOP_RWRAP 31 /* record wrap */ +#define STOP_NOCD 32 /* no card in reader */ +#define STOP_OVERFL 33 /* overflow */ +#define STOP_EXPCHK 34 /* exponent error */ +#define STOP_WRADIS 35 /* write addr disabled */ +#define STOP_FPLNT 36 /* invalid fp length */ +#define STOP_FPUNL 37 /* fp lengths unequal */ +#define STOP_FPMF 38 /* no flag on exp */ +#define STOP_FPDVZ 39 /* divide by zero */ + +/* Memory */ + +#define MAXMEMSIZE 60000 /* max mem size */ +#define MEMSIZE (cpu_unit.capac) /* act memory size */ + +/* Processor parameters */ + +#define INST_LEN 12 /* inst length */ +#define ADDR_LEN 5 /* addr length */ +#define MUL_TABLE 100 /* multiply table */ +#define MUL_TABLE_LEN 200 +#define ADD_TABLE 300 /* add table */ +#define ADD_TABLE_LEN 100 +#define IDX_A 300 /* index A base */ +#define IDX_B 340 /* index B base */ +#define PROD_AREA 80 /* product area */ +#define PROD_AREA_LEN 20 /* product area */ +#define PROD_AREA_END (PROD_AREA + PROD_AREA_LEN) + +/* Branch indicator codes */ + +#define NUM_IND 100 /* number of indicators */ + +#define IN_SW1 1 /* sense switch 1 */ +#define IN_SW2 2 /* sense switch 2 */ +#define IN_SW3 3 /* sense switch 3 */ +#define IN_SW4 4 /* sense switch 4 */ +#define IN_RDCHK 6 /* read check (I/O error) */ +#define IN_WRCHK 7 /* write check (I/O error) */ +#define IN_LAST 9 /* last card was just read */ +#define IN_HP 11 /* high or positive result */ +#define IN_EZ 12 /* equal or zero result */ +#define IN_HPEZ 13 /* high/positive or equal/zero */ +#define IN_OVF 14 /* overflow */ +#define IN_EXPCHK 15 /* floating exponent check */ +#define IN_MBREVEN 16 /* even parity check */ +#define IN_MBRODD 17 /* odd parity check */ +#define IN_ANYCHK 19 /* any of read, write, even/odd */ +#define IN_PRCHK 25 /* printer check */ +#define IN_IXN 30 /* IX neither */ +#define IN_IXA 31 /* IX A band */ +#define IN_IXB 32 /* IX B band */ +#define IN_PRCH9 33 /* printer chan 9 */ +#define IN_PRCH12 34 /* printer chan 12 */ +#define IN_PRBSY 35 /* printer busy */ +#define IN_DACH 36 /* disk addr/data check */ +#define IN_DWLR 37 /* disk rec length */ +#define IN_DCYO 38 /* disk cyl overflow */ +#define IN_DERR 39 /* disk any error */ + +/* I/O channel codes */ + +#define NUM_IO 100 /* number of IO chan */ + +#define IO_TTY 1 /* console typewriter */ +#define IO_PTP 2 /* paper-tape punch */ +#define IO_PTR 3 /* paper-tape reader */ +#define IO_CDP 4 /* card punch */ +#define IO_CDR 5 /* card reader */ +#define IO_DSK 7 /* disk */ +#define IO_LPT 9 /* line printer */ +#define IO_BTP 32 /* binary ptp */ +#define IO_BTR 33 /* binary ptr */ + +#define LPT_WIDTH 120 /* line print width */ +#define CCT_LNT 132 /* car ctrl length */ + +#define CRETIOE(f,c) return ((f)? (c): SCPE_OK) + +/* Memory representation: flag + BCD digit per byte */ + +#define FLAG 0x10 +#define DIGIT 0x0F +#define REC_MARK 0xA +#define NUM_BLANK 0xC +#define GRP_MARK 0xF +#define BAD_DIGIT(x) ((x) > 9) + +/* Instruction format */ + +#define I_OP 0 /* opcode */ +#define I_P 2 /* P start */ +#define I_PL 6 /* P end */ +#define I_Q 7 /* Q start */ +#define I_QL 11 /* Q end */ +#define I_IO 8 /* IO select */ +#define I_BR 8 /* indicator select */ +#define I_CTL 10 /* control select */ +#define I_SEL 11 /* BS select */ + +#define ADDR_A(x,a) ((((x) + (a)) >= MEMSIZE)? ((x) + (a) - MEMSIZE): ((x) + (a))) +#define ADDR_S(x,a) (((x) < (a))? ((x) - (a) + MEMSIZE): ((x) - (a))) +#define PP(x) x = ADDR_A(x,1) +#define MM(x) x = ADDR_S(x,1) + +/* CPU options, stored in cpu_unit.flags */ +/* Decoding flags must be part of the same definition set */ + +#define UNIT_SCP ((1 << UNIT_V_UF) - 1) /* mask of SCP flags */ +#define IF_MII (1 << (UNIT_V_UF + 0)) /* model 2 */ +#define IF_DIV (1 << (UNIT_V_UF + 1)) /* automatic divide */ +#define IF_IA (1 << (UNIT_V_UF + 2)) /* indirect addressing */ +#define IF_EDT (1 << (UNIT_V_UF + 3)) /* edit */ +#define IF_FP (1 << (UNIT_V_UF + 4)) /* floating point */ +#define IF_BIN (1 << (UNIT_V_UF + 5)) /* binary */ +#define IF_IDX (1 << (UNIT_V_UF + 6)) /* indexing */ +#define IF_VPA (1 << (UNIT_V_UF + 7)) /* valid P addr */ +#define IF_VQA (1 << (UNIT_V_UF + 8)) /* valid Q addr */ +#define IF_4QA (1 << (UNIT_V_UF + 9)) /* 4 char Q addr */ +#define IF_NQX (1 << (UNIT_V_UF + 10)) /* no Q indexing */ +#define IF_IMM (1 << (UNIT_V_UF + 11)) /* immediate */ +#define UNIT_BCD (1 << (UNIT_V_UF + 12)) /* BCD coded */ +#define UNIT_MSIZE (1 << (UNIT_V_UF + 13)) /* fake flag */ +#define ALLOPT (IF_DIV + IF_IA + IF_EDT + IF_FP + IF_BIN + IF_IDX) +#define MI_OPT (IF_DIV + IF_IA + IF_EDT + IF_FP) +#define MI_STD (IF_DIV + IF_IA + IF_EDT) +#define MII_OPT (ALLOPT) +#define MII_STD (IF_DIV + IF_IA + IF_EDT + IF_BIN + IF_IDX) + +/* Add status codes */ + +#define ADD_NOCRY 0 /* no carry out */ +#define ADD_CARRY 1 /* carry out */ +#define ADD_SIGNC 2 /* sign change */ + +/* Opcodes */ + +enum opcodes { + OP_FADD = 1, OP_FSUB, OP_FMUL, /* 00 - 09 */ + OP_FSL = 5, OP_TFL, OP_BTFL, OP_FSR, OP_FDIV, + OP_BTAM = 10, OP_AM, OP_SM, OP_MM, OP_CM, /* 10 - 19 */ + OP_TDM, OP_TFM, OP_BTM, OP_LDM, OP_DM, + OP_BTA = 20, OP_A, OP_S, OP_M, OP_C, /* 20 - 29 */ + OP_TD, OP_TF, OP_BT, OP_LD, OP_D, + OP_TRNM = 30, OP_TR, OP_SF, OP_CF, OP_K, /* 30 - 39 */ + OP_DN, OP_RN, OP_RA, OP_WN, OP_WA, + OP_NOP = 41, OP_BB, OP_BD, OP_BNF, /* 40 - 49 */ + OP_BNR, OP_BI, OP_BNI, OP_H, OP_B, + OP_BNG = 55, + OP_BS = 60, OP_BX, OP_BXM, OP_BCX, OP_BCXM, /* 60 - 69 */ + OP_BLX, OP_BLXM, OP_BSX, + OP_MA = 70, OP_MF, OP_TNS, OP_TNF, /* 70 - 79 */ + /* 80 - 89 */ + OP_BBT = 90, OP_BMK, OP_ORF, OP_ANDF, OP_CPLF, /* 90 - 99 */ + OP_EORF, OP_OTD, OP_DTO }; diff --git a/I1620/i1620_doc.txt b/I1620/i1620_doc.txt new file mode 100644 index 00000000..e3d23fca --- /dev/null +++ b/I1620/i1620_doc.txt @@ -0,0 +1,518 @@ +To: Users +From: Bob Supnik +Subj: IBM 1620 Simulator Usage +Date: 15-Nov-2002 + + COPYRIGHT NOTICE + +The following copyright notice applies to both the SIMH source and binary: + + Original code published in 1993-2002, written by Robert M Supnik + Copyright (c) 1993-2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + +This memorandum documents the IBM 1620 simulator. This simulator is based on +Geoff Kuenning's 1620 simulator, which is used by permission. + +1. Simulator Files + +sim/ sim_defs.h + sim_rev.h + sim_sock.h + sim_tmxr.h + scp.c + scp_tty.c + sim_sock.c + sim_tmxr.c + +sim/i1620/ i1620_defs.h + i1620_cpu.c + i1620_fp.c + i1620_tty.c + i1620_pt.c + i1620_cd.c + i1620_lp.c + i1620_dp.c + i1620_sys.c + +2. IBM 1620 Features + +The IBM 1620 simulator is configured as follows: + +device simulates +name(s) + +CPU IBM 1620 Model 1 or Model 2 CPU with 20K to 60K of memory + Model 1 options: indirect addressing, automatic divide, + edit instructions, floating point + Model 2 options: indexing, binary capability, floating point +TTY IBM console terminal +PTR IBM 1621 paper tape reader +PTP IBM 1624 paper tape punch +CDR,CDP IBM 1622 card reader/punch +LPT IBM 1443 line printer +DP IBM 1311 disk pack with four drives + +The IBM 1620 simulator implements many unique stop conditions. On almost +any kind of error the simulator stops: + + unimplemented opcode + reference to non-existent device + invalid digit + invalid alphameric character + invalid P address digit + invalid Q address digit + indirect address limit exceeded + invalid odd address + invalid even address + invalid function + invalid indicator + invalid return address register + skip to unpunched carriage control tape channel + card reader hopper empty + overflow with arithmetic stop switch set + I/O error with I/O stop switch set + invalid disk drive + invalid disk sector address + invalid disk sector count + invalid disk buffer address + disk address compare error + disk cylinder overflow error + disk write check error + field exceeds memory + record exceeds memory + floating point mantissa exceeds maximum length + floating point mantissas not the same length + floating point exponent check with arithmetic stop switch set + floating point exponent missing high flag + +The LOAD command is used to load a line printer carriage-control tape. +The DUMP command is not implemented. + +2.1 CPU + +The CPU options include the CPU model (Model 1 or Model 2), a number of +special features, and the size of main memory. + + SET CPU IA enable indirect addressing + SET CPU NOIA disable indirect addressing + SET CPU EDT enable extra editing instructions + SET CPU NOEDT disable extra editing instructions + SET CPU DIV enable divide instructions + SET CPU NODIV disable divide instructions + SET CPU IDX enable indexing + SET CPU NOIDX disable indexing + SET CPU BIN enable binary instructions + SET CPU NOBIN disable binary instructions + SET CPU FP enable floating point instructions + SET CPU NOFP disable floating point instructions + SET CPU MOD1 set Model 1 + SET CPU MOD2 set Model 2 + SET CPU 20K set memory size = 20K + SET CPU 40K set memory size = 40K + SET CPU 60K set memory size = 60K + +Model 1 options include IA, EDT, DIV, and FP; the first three are on by +default. Model 2 options include IDX, BIN, and FP; IA, EDT, and DIV are +standard on the Model 2. + +If memory size is being reduced, and the memory being truncated contains +non-zero data, the simulator asks for confirmation. Data in the truncated +portion of memory is lost. Initially, memory size is 16K, and all special +features are enabled. + +Memory is implemented as 5 bit BCD characters, as follows: + + 4 3 2 1 0 + + flag 8 4 2 1 + <-------- digit --------> + +In BCD, the decimal digits 0-9 are (hex) values 0x0, 0x1, 0x2, 0x3, 0x4, +0x5, 0x6, 0x7, 0x8, 0x9, respectively. 0xA is record mark, 0xC non- +punching blank, and 0xF group mark, respectively. + +CPU registers include the visible state of the processor. The 1620 has no +interrupt system. + + name size comments + + IR1 16 instruction storage address register (PC) + IR2 16 return register + PR1 16 processor register 1 + PAR 16 P address register (OR2) + QAR 16 Q address register (OR1) + SS1 1 sense switch 1 + SS2 1 sense switch 2 + SS3 1 sense switch 3 + SS4 1 sense switch 4 + HP 1 high/positive indicator + EZ 1 equal/zero indicator + ARCHK 1 arithmetic check (overflow) indicator + EXPCHK 1 exponent check indicator + RDCHK 1 read check indicator + WRCHK 1 write check indicator + ARSTOP 1 arithmetic check stop switch + IOSTOP 1 I/O check stop switch + IND[0:99] 1 indicator array + IAE 1 indirect address enable (Model 2 only) + IDXE 1 indexing enable (Model 2 only) + IDXB 1 indexinb band select (Model 2 only) + IR1Q 1 IR1 prior to last branch; + most recent IR1 change first + WRU 8 interrupt character + +2.2 Console Typewriter (TTY) + +The console typewriter (TTY) is a half-duplex console. The typewriter +registers are: + + name size comments + + COL 7 current column + TIME 24 polling interval + +When the 1620 CPU requests input from the keyboard, a reverse apostrophe +(`) is printed. The CPU hangs waiting for input until the return/enter +key is pressed. The typewriter has no errors. + +2.3 1621 Paper Tape Reader (PTR) + +The paper tape reader (PTR) reads data from a disk file. The POS +register specifies the number of the next data item to be read. Thus, +by changing POS, the user can backspace or advance the reader. + +The paper tape reader supports the BOOT command. BOOT PTR starts the +specified instruction sequence at location 0. + +The paper tape reader implements these registers: + + name size comments + + POS 32 position in the input file + +Error handling is as follows: + + error IOCHK processed as + + not attached x set RDCHK indicator, report error, stop + + end of file x set RDCHK indicator, report error, stop + + OS I/O error x set RDCHK indicator, report error, stop + + parity error 1 set RDCHK indicator, report error, stop + 0 set RDCHK indicator + +2.4 1624 Paper Tape Punch (PTP) + +The paper tape punch (PTP) writes data to a disk file. The POS register +specifies the number of the next data item to bewritten. Thus, by +changing POS, the user can backspace or advance the punch. + +The paper tape punch implements these registers: + + name size comments + + POS 32 position in the output file + +Error handling is as follows: + + error IOCHK processed as + + not attached x set WRCHK indicator, report error, stop + + OS I/O error x set WRCHK indicator, report error, stop + + invalid char 1 set WRCHK indicator, report error, stop + 0 set WRCHK indicator + +2.5 1622 Card Reader/Punch (CDR, CDP) + +The IBM 1402 card/reader punch is simulated as two independent devices: +the card reader (CDR) and the card punch (CDP). + +The card reader supports the BOOT command. BOOT CDR starts the +specified instruction sequence at location 0. + +The card reader reads data from a disk file, while the punch writes data +to a disk file. Cards are simulated as ASCII text lines with terminating +newlines. For each unit, the POS register specifies the number of the +next data item to be read or written. Thus, by changing POS, the user +can backspace or advance these devices. + +The card reader registers are: + + name size comments + + LAST 1 last card indicator + POS 32 position + +The card punch registes are: + + name size comments + + POS 32 position + +Card reader error handling is as follows: + + error IOCHK processed as + + end of file x set RDCHK indicator, report error, stop + + not attached x set RDCHK indicator, report error, stop + + OS I/O error x set RDCHK indicator, report error, stop + + invalid char 1 set RDCHK indicator, report error, stop + 0 set RDCHK indicator + +Card punch error handling is as follows: + + error IOCHK processed as + + not attached x set WRCHK indicator, report error, stop + + OS I/O error x set WRCHK indicator, report error, stop + + invalid char 1 set WRCHK indicator, report error, stop + 0 set WRCHK indicator + +2.6 1443 Line Printer (LPT) + +The IBM 1443 line printer (LPT) writes its data, converted to ASCII, to +a disk file. The line printer can be programmed with a carriage control +tape. The LOAD command loads a new carriage control tape: + + LOAD load carriage control tape file + +The format of a carriage control tape consists of multiple lines. Each +line contains an optional repeat count, enclosed in parentheses, optionally +followed by a series of column numbers separated by commas. Column numbers +must be between 1 and 12; a column number of zero denotes top of form. The +following are all legal carriage control specifications: + + no punch + (5) 5 lines with no punches + 1,5,7,8 columns 1, 5, 7, 8 punched + (10)2 10 lines with column 2 punched + 1,0 column 1 punched; top of form + +The default form is 66 lines long, with column 1 and the top of form mark +on line 1, and the rest blank. + +The line printer registers are: + + name size comments + + LBUF[0:119] 7 line buffer + BPTR 7 buffer pointer + PCTL 8 saved print control directive + PRCHK 1 print check indicator + PRCH9 1 channel 9 indicator + PRCH12 1 channel 12 indicator + POS 32 position + CCT[0:131] 32 carriage control tape array + CCTP 8 carriage control tape pointer + CCTL 8 carriage control tape length (read only) + +Error handling is as follows: + + error IOCHK processed as + + not attached x set PRCHK, WRCHK indicators, report error, stop + + OS I/O error x set PRCHK, WRCHK indicators, report error, stop + + invalid char 1 set PRCHK, WRCHK indicator, report error, stop + 0 set PRCHK, WRCHK indicator + +2.7 1311 Disk Pack (DP) + +The disk pack controller supports 4 drives, numbered 0 through 3. Disk +pack options include the ability to enable address writing (formatting). + + SET DPn ADDROFF set unit n address enable off + SET DPn ADDRON set unit n address enable on + +Units can also be set ONLINE or OFFLINE. + +Unlike most simulated disks, the 1311 includes explicit representation +for sector addresses. This is to support non-standard formats, such as +the inclusion of the drive number in the sector address. As a result, +1311 sectors are 105 digits long: 5 address digits and 100 data digits. +If the 1311 has not been formatted, the addresses are zeroes and are +synthesized, if needed, based on the sector number. + +The disk pack controller implements these registers: + + name size comments + + ADCHK 1 address check (compare error) indicator + WLRC 1 wrong length record check indicator + CYLO 1 cylinder overflow check indicator + ERR 1 disk error indicator + DPSTOP 1 disk check stop + +Error handling is as follows: + + error DPCHK processed as + + not attached x set ERR indicator, report error, stop + +1311 data files are buffered in memory; therefore, end of file and OS +I/O errors cannot occur. + +2.8 Symbolic Display and Input + +The IBM 1620 simulator implements symbolic display and input. Display is +controlled by command line switches: + + -c display as single character (alphameric + for CPU and DP, ASCII for others) + -s display as flag terminated numeric string + (CPU and DP only) + -m display instruction mnemonics + (CPU and only) + -d display 50 characters per line, with word + marks denoted by "_" on the line above + +In a CPU string display, word marks are denoted by ~. + +Input parsing is controlled by the first character typed in or by command +line switches: + + ' or -c character (alphameric for CPU and DP, ASCII + for others) + " or -s numeric string (CPU and DP only) + alphabetic instruction mnemonic (CPU and DP only) + numeric octal number + +Instruction input is free format and consists of an opcode and up to +three operands: + + op {+/-}ppppp{(idx)},{+-}qqqqq{(idx)},flags + +The p address and, if present, the q address, are always decimal. A +plus sign is ignored; a minus sign denotes indirect addressing (or a +negative immediate operand). If indexing is enabled, addresses may +be indexed; index registers are decimal numbers between 1 and 7. The +flags field is used to set extra flags on the instruction. It consists +of digit numbers in ascending order, with no separators. For example, + + AM -12345(5),67890,110 + +translates into + _ _ ___ _ + 111234567890 + +The flag over digits 3 and 5 specify the P index register; the flag +over digit 6 specifies the P indirect address; the flag over digit 7 +marks the end of the immediate Q operand; and the flags over digits +1 and 10 are specified by the third field. + +2.9 Character Sets + +The IBM 1620 uses single digits to represent numbers, and pairs of +digits to represent characters (alphameric coding). Only a small +number of the 256 possible alphameric codings have legitimate values. +Further, the translation between alphameric and devices varied +from device to device. The simulator implements a code called +which allows all 64 possible card codes to be represented by upper +case ASCII characters. In addition, lower case alphabetic +characters are accepted on input as equivalent to upper case. + +Card code PT code RA RN LPT WA ASCII representation + + C 0 0 blank blank +12 XOC 10 0 + + +11 X 20 F+0 - - +0 O 70 0 0 0 +1 1 71 1 1 1 +2 2 72 2 2 2 +3 C21 73 3 3 3 +4 4 74 4 4 4 +5 C41 75 5 5 5 +6 C42 76 6 6 6 +7 421 77 7 7 7 +8 8 78 8 8 8 +9 C81 79 9 9 9 +12 + 1 XO1 41 1 A A +12 + 2 XO2 42 2 B B +12 + 3 XOC21 43 3 C C +12 + 4 XO4 44 4 D D +12 + 5 XOC41 45 5 E E +12 + 6 XOC42 46 6 F F +12 + 7 XO421 47 7 G G +12 + 8 XO8 48 8 H H +12 + 9 XOC81 49 9 I I +11 + 1 XC1 51 F+1 J J +11 + 2 XC2 52 F+2 K K +11 + 3 X21 53 F+3 L L +11 + 4 XC4 54 F+4 M M +11 + 5 X41 55 F+5 N N +11 + 6 X42 56 F+6 O O +11 + 7 XC421 57 F+7 P P +11 + 8 XC8 58 F+8 Q Q +11 + 9 X81 59 F+9 R R +0 + 1 OC1 21 1 / / +0 + 2 OC2 62 2 S S +0 + 3 O21 63 3 T T +0 + 4 OC4 64 4 U U +0 + 5 O41 65 5 V V +0 + 6 O42 66 6 W W +0 + 7 OC421 67 7 X X +0 + 8 OC8 68 8 Y Y +0 + 9 O81 69 9 Z Z +2 + 8 C82 ? 0A A na % +3 + 8 821 33 B = = +4 + 8 C84 34 C @ @ +5 + 8 841 70 0 0 : +6 + 8 842 ? 0E E na > +7 + 8 C8421 ? 0F F na ^ +12 + 2 + 8 XOC82 ? 5A ? F+A na ? +12 + 3 + 8 XO821 3 ? F+B . . +12 + 4 + 8 XOC84 4 C ) ) +12 + 5 + 8 XO841 40 0 na [ +12 + 6 + 8 XO842 ? 5E ? F+E na < +12 + 7 + 8 XOC8421 5F F+F na " +11 + 2 + 8 X82 5A F+A na ! +11 + 3 + 8 XC821 13 F+B $ $ +11 + 4 + 8 X84 14 F+C * * +11 + 5 + 8 XC841 50 F+0 - ] +11 + 6 + 8 XC842 ? 5E ? F+E na ; +11 + 7 + 8 X8421 5F F+F na _ +0 + 2 + 8 O82 0A A na ' +0 + 3 + 8 OC821 23 B , , +0 + 4 + 8 O84 24 C ( ( +0 + 5 + 8 OC841 60 0 na # +0 + 6 + 8 OC842 0E E na \ +0 + 7 + 8 O8421 0F F na & + + 2 ? + 12 ! + 22 ' + 32 0 + 35 : + 36 blank +11 + 0 50 - ] diff --git a/I1620/i1620_dp.c b/I1620/i1620_dp.c new file mode 100644 index 00000000..8496189e --- /dev/null +++ b/I1620/i1620_dp.c @@ -0,0 +1,463 @@ +/* i1620_dp.c: IBM 1311 disk simulator + + Copyright (c) 2002, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + dp 1311 disk pack + + The 1311 disk pack has 100 cylinders, 10 tracks/cylinder, 20 sectors/track. + Each sector contains 105 characters of information: + + 5c sector address + 100c sector data + + By default, a sector's address field will be '00000', which is interpreted + to mean the implied sector number that would be in place if the disk pack + had been formatted with sequential sector numbers. + + 18-Oct-02 RMS Fixed bug in error testing (found by Hans Pufal) +*/ + +#include "i1620_defs.h" + +#define DP_NUMDR 4 /* #drives */ +#define UNIT_V_WAE (UNIT_V_UF + 0) /* write addr enab */ +#define UNIT_WAE (1 << UNIT_V_WAE) + +/* Disk format */ + +#define DP_ADDR 5 /* address */ +#define DP_DATA 100 /* data */ +#define DP_NUMCH (DP_ADDR + DP_DATA) + +#define DP_NUMSC 20 /* #sectors */ +#define DP_NUMSF 10 /* #surfaces */ +#define DP_NUMCY 100 /* #cylinders */ +#define DP_TOTSC (DP_NUMCY * DP_NUMSF * DP_NUMSC) +#define DP_SIZE (DP_TOTSC * DP_NUMCH) + +/* Disk control field */ + +#define DCF_DRV 0 /* drive select */ +#define DCF_SEC 1 /* sector addr */ +#define DCF_SEC_LEN 5 +#define DCF_CNT (DCF_SEC + DCF_SEC_LEN) /* sector count */ +#define DCF_CNT_LEN 3 +#define DCF_ADR (DCF_CNT + DCF_CNT_LEN) /* buffer address */ +#define DCF_ADR_LEN 5 +#define DCF_LEN (DCF_ADR + DCF_ADR_LEN) + +/* Functions */ + +#define FNC_SEEK 1 /* seek */ +#define FNC_SEC 0 /* sectors */ +#define FNC_WCH 1 /* write check */ +#define FNC_NRL 2 /* no rec lnt chk */ +#define FNC_TRK 4 /* tracks */ +#define FNC_WRI 8 /* write offset */ + +#define CYL u3 /* current cylinder */ + +extern uint8 M[MAXMEMSIZE]; /* memory */ +extern uint8 ind[NUM_IND]; +extern UNIT cpu_unit; + +int32 dp_stop = 1; /* disk err stop */ +t_addr dp_ba = 0; /* buffer addr */ + +t_stat dp_reset (DEVICE *dptr); +t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 qnr, int32 qwc); +t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 qnr, int32 qwc); +t_stat dp_wradr (UNIT *uptr, int32 sec, int32 qnr); +t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 qnr); +int32 dp_fndsec (UNIT *uptr, int32 sec, t_bool rd); +t_stat dp_nexsec (UNIT *uptr, int32 sec, int32 psec, t_bool rd); +t_bool dp_zeroad (uint8 *ap); +int32 dp_cvt_ad (uint8 *ap); +int32 dp_trkop (int32 drv, int32 sec); +int32 dp_cvt_bcd (uint32 ad, int32 len); +void dp_fill (UNIT *uptr, uint32 da, int32 cnt); +t_stat dp_tstgm (uint32 c, int32 qnr); + +/* DP data structures + + dp_dev DP device descriptor + dp_unit DP unit list + dp_reg DP register list + dp_mod DP modifier list +*/ + +UNIT dp_unit[] = { + { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE + + UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE + + UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE + + UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) }, + { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE + + UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) } }; + +REG dp_reg[] = { + { FLDATA (ADCHK, ind[IN_DACH], 0) }, + { FLDATA (WLRC, ind[IN_DWLR], 0) }, + { FLDATA (CYLO, ind[IN_DCYO], 0) }, + { FLDATA (ERR, ind[IN_DERR], 0) }, + { FLDATA (DPSTOP, dp_stop, 0) }, + { URDATA (CYL, dp_unit[0].CYL, 10, 8, 0, + DP_NUMDR, PV_LEFT + REG_RO) }, + { NULL } }; + +MTAB dp_mod[] = { + { UNIT_WAE, 0, "write address disabled", "ADDROFF", NULL }, + { UNIT_WAE, UNIT_WAE, "write address enabled", "ADDRON", NULL }, + { 0 } }; + +DEVICE dp_dev = { + "DP", dp_unit, dp_reg, dp_mod, + DP_NUMDR, 10, 21, 1, 16, 5, + NULL, NULL, &dp_reset, + NULL, NULL, NULL }; + +/* Disk IO routine */ + +t_stat dp (uint32 op, uint32 pa, uint32 f0, uint32 f1) +{ +int32 drv, sa, sec, psec, cnt, qwc, qnr, t; +UNIT *uptr; +t_stat r; + +if (pa & 1) return STOP_INVDCF; /* dcf must be even */ +ind[IN_DACH] = ind[IN_DWLR] = 0; /* clr indicators */ +ind[IN_DERR] = ind[IN_DCYO] = 0; +sa = ADDR_A (pa, DCF_SEC); /* ptr to sector */ +if (((dp_unit[0].flags & UNIT_DIS) == 0) && /* only drive 0? */ + (dp_unit[1].flags & UNIT_DIS) && + (dp_unit[2].flags & UNIT_DIS) && + (dp_unit[3].flags & UNIT_DIS)) drv = 0; /* ignore drv select */ +else drv = (((M[pa] & 1)? M[pa]: M[sa]) & 0xE) >> 1; /* drive # */ +if (drv >= DP_NUMDR) return STOP_INVDRV; /* invalid? */ +uptr = dp_dev.units + drv; /* get unit ptr */ +if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */ + ind[IN_DERR] = 1; /* no, error */ + CRETIOE (dp_stop, SCPE_UNATT); } + +sec = dp_cvt_bcd (sa, DCF_SEC_LEN); /* cvt sector */ +if ((sec < 0) || (sec >= (DP_NUMDR * DP_TOTSC))) /* bad sector? */ + return STOP_INVDSC; +if (op == OP_K) { /* seek? */ + if (f1 != FNC_SEEK) return STOP_INVFNC; /* really? */ + uptr->CYL = (sec / (DP_NUMSF * DP_NUMSC)) % /* set cyl # */ + DP_NUMCY; + return SCPE_OK; } /* done! */ + +cnt = dp_cvt_bcd (ADDR_A (pa, DCF_CNT), DCF_CNT_LEN); /* get count */ +t = dp_cvt_bcd (ADDR_A (pa, DCF_ADR), DCF_ADR_LEN); /* get address */ +if ((t < 0) || (t & 1)) return STOP_INVDBA; /* bad address? */ +dp_ba = t; /* save addr */ + +if (f1 >= FNC_WRI) return STOP_INVFNC; /* invalid func? */ +if (op == OP_RN) qwc = f1 & FNC_WCH; /* read? set wch */ +else if (op == OP_WN) { /* write? */ + if (op & FNC_WCH) return STOP_INVFNC; /* cant check */ + f1 = f1 + FNC_WRI; } /* offset fnc */ +else return STOP_INVFNC; /* not R or W */ +qnr = f1 & FNC_NRL; /* no rec check? */ + +switch (f1 & ~(FNC_WCH | FNC_NRL)) { /* case on function */ +case FNC_SEC: /* read sectors */ + if (cnt <= 0) return STOP_INVDCN; /* bad count? */ + psec = dp_fndsec (uptr, sec, TRUE); /* find sector */ + if (psec < 0) CRETIOE (dp_stop, STOP_DACERR); /* error? */ + do { /* loop on count */ + if (r = dp_rdsec (uptr, psec, qnr, qwc)) /* read sector */ + break; + sec++; psec++; } /* next sector */ + while ((--cnt > 0) && + ((r = dp_nexsec (uptr, sec, psec, TRUE)) == SCPE_OK)); + break; /* done, clean up */ + +case FNC_TRK: /* read track */ + psec = dp_trkop (drv, sec); /* start of track */ + for (cnt = 0; cnt < DP_NUMSC; cnt++) { /* full track */ + if (r = dp_rdadr (uptr, psec, qnr, qwc)) /* read addr */ + break; /* error? */ + if (r = dp_rdsec (uptr, psec, qnr, qwc)) /* read data */ + break; /* error? */ + psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC); } + break; /* done, clean up */ + +case FNC_SEC + FNC_WRI: /* write */ + if (cnt <= 0) return STOP_INVDCN; /* bad count? */ + psec = dp_fndsec (uptr, sec, FALSE); /* find sector */ + if (psec < 0) CRETIOE (dp_stop, STOP_DACERR); /* error? */ + do { /* loop on count */ + if (r = dp_tstgm (M[dp_ba], qnr)) break; /* start with gm? */ + if (r = dp_wrsec (uptr, psec, qnr)) break; /* write data */ + sec++; psec++; } /* next sector */ + while ((--cnt > 0) && + ((r = dp_nexsec (uptr, sec, psec, FALSE)) == SCPE_OK)); + break; /* done, clean up */ + +case FNC_TRK + FNC_WRI: /* write track */ + if ((uptr->flags & UNIT_WAE) == 0) /* enabled? */ + return STOP_WRADIS; + psec = dp_trkop (drv, sec); /* start of track */ + for (cnt = 0; cnt < DP_NUMSC; cnt++) { /* full track */ + if (r = dp_tstgm (M[dp_ba], qnr)) break; /* start with gm? */ + if (r = dp_wradr (uptr, psec, qnr)) break; /* write addr */ + if (r = dp_wrsec (uptr, psec, qnr)) break; /* write data */ + psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC); } + break; /* done, clean up */ + +default: /* unknown */ + return STOP_INVFNC; } + +if ((r == SCPE_OK) && !qnr) { /* eor check? */ + if ((M[dp_ba] & DIGIT) != GRP_MARK) { /* GM at end? */ + ind[IN_DWLR] = ind[IN_DERR] = 1; /* no, error */ + r = STOP_WRLERR; } } +if ((r != SCPE_OK) && /* error? */ + (dp_stop || !ind[IN_DERR])) return r; /* iochk or stop? */ +return SCPE_OK; /* continue */ +} + +/* Read or compare address with memory */ + +t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 qnr, int32 qwc) +{ +int32 i; +uint8 ad; +int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */ +uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */ +t_bool zad = dp_zeroad (ap); /* zero address */ +static const int32 dec_tab[DP_ADDR] = /* powers of 10 */ + { 10000, 1000, 100, 10, 1} ; + +for (i = 0; i < DP_ADDR; i++) { /* copy/check addr */ + if (zad) { /* addr zero? */ + ad = sec / dec_tab[i]; /* get addr digit */ + sec = sec % dec_tab[i]; } /* get remainder */ + else ad = *ap; /* addr digit */ + if (qwc) { /* write check? */ + if (dp_tstgm (M[dp_ba], qnr)) /* grp mrk in mem? */ + return STOP_WRLERR; /* yes, error */ + if (!zad && (M[dp_ba] != ad)) { /* digits equal? */ + ind[IN_DACH] = ind[IN_DERR] = 1; /* no, error */ + return STOP_DWCERR; } } + else M[dp_ba] = ad & (FLAG | DIGIT); /* store digit */ + if (dp_tstgm (*ap, qnr)) return STOP_WRLERR; /* grp mrk on disk? */ + ap++; PP (dp_ba); } /* adv ptrs */ +return SCPE_OK; +} + +/* Read or compare data with memory */ + +t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 qnr, int32 qwc) +{ +int32 i; +int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */ +uint8 *ap = ((uint8 *) uptr->filebuf) + da + DP_ADDR; /* buf ptr */ + +for (i = 0; i < DP_DATA; i++) { /* copy data */ + if (qwc) { /* write check? */ + if (dp_tstgm (M[dp_ba], qnr)) /* grp mrk in mem? */ + return STOP_WRLERR; /* yes, error */ + if (M[dp_ba] != *ap) { /* dig+flags equal? */ + ind[IN_DACH] = ind[IN_DERR] = 1; /* no, error */ + return STOP_DWCERR; } } + else M[dp_ba] = *ap & (FLAG | DIGIT); /* flag + digit */ + if (dp_tstgm (*ap, qnr)) return STOP_WRLERR; /* grp mrk on disk? */ + ap++; PP (dp_ba); } /* adv ptrs */ +return SCPE_OK; +} + +/* Write address to disk */ + +t_stat dp_wradr (UNIT *uptr, int32 sec, int32 qnr) +{ +int32 i; +uint32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */ +uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */ + +for (i = 0; i < DP_ADDR; i++) { /* copy address */ + *ap = M[dp_ba] & (FLAG | DIGIT); /* flag + digit */ + if (da >= uptr->hwmark) uptr->hwmark = da + 1; + if (dp_tstgm (*ap, qnr)) { /* grp mrk fm mem? */ + dp_fill (uptr, da + 1, DP_NUMCH - i - 1); /* fill addr+data */ + return STOP_WRLERR; } /* error */ + da++; ap++; PP (dp_ba); /* adv ptrs */ + } +return SCPE_OK; +} + +/* Write data to disk */ + +t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 qnr) +{ +int32 i; +uint32 da = ((sec % DP_TOTSC) * DP_NUMCH) + DP_ADDR; /* char number */ +uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */ + +for (i = 0; i < DP_DATA; i++) { /* copy data */ + *ap = M[dp_ba] & (FLAG | DIGIT); /* get character */ + if (da >= uptr->hwmark) uptr->hwmark = da + 1; + if (dp_tstgm (*ap, qnr)) { /* grp mrk fm mem? */ + dp_fill (uptr, da + 1, DP_DATA - i - 1); /* fill data */ + return STOP_WRLERR; } /* error */ + da++; ap++; PP (dp_ba); /* adv ptrs */ + } +return SCPE_OK; +} + +/* Find sector */ + +int32 dp_fndsec (UNIT *uptr, int32 sec, t_bool rd) +{ +int32 ctrk = sec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */ +int32 psec = ((uptr->CYL) * (DP_NUMSF * DP_NUMSC)) + ctrk; +int32 da = psec * DP_NUMCH; /* char number */ +uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */ +int32 dskad, i; + +if (dp_zeroad (ap)) return psec; /* addr zero? ok */ +dskad = dp_cvt_ad (ap); /* cvt addr */ +if (dskad == sec) { /* match? */ + if (rd || ((*ap & FLAG) == 0)) return psec; /* read or !wprot? */ + ind[IN_DACH] = ind[IN_DERR] = 1; /* no match */ + return -1; } +psec = psec - (psec % DP_NUMSC); /* sector 0 */ +for (i = 0; i < DP_NUMSC; i++, psec++) { /* check track */ + da = psec * DP_NUMCH; /* char number */ + ap = ((uint8 *) uptr->filebuf) + da; /* word pointer */ + if (dp_zeroad (ap)) continue; /* no implicit match */ + dskad = dp_cvt_ad (ap); /* cvt addr */ + if (dskad == sec) { /* match? */ + if (rd || ((*ap & FLAG) == 0)) return psec; /* read or !wprot? */ + ind[IN_DACH] = ind[IN_DERR] = 1; /* no match */ + return -1; } } +ind[IN_DACH] = ind[IN_DERR] = 1; /* no match */ +return -1; +} + +/* Find next sector - must be sequential, cannot cross cylinder boundary */ + +t_stat dp_nexsec (UNIT *uptr, int32 sec, int32 psec, t_bool rd) +{ +int32 ctrk = psec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */ +int32 da = psec * DP_NUMCH; /* word number */ +uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */ +int32 dskad; + +if (ctrk) { /* not trk zero? */ + if (dp_zeroad (ap)) return SCPE_OK; /* addr zero? ok */ + dskad = dp_cvt_ad (ap); /* cvt addr */ + if ((dskad == sec) && /* match? */ + (rd || ((*ap & FLAG) == 0))) return SCPE_OK; /* read or !wprot? */ + ind[IN_DACH] = ind[IN_DERR] = 1; /* no, error */ + return STOP_DACERR; } +ind[IN_DCYO] = ind[IN_DERR] = 1; /* cyl overflow */ +return STOP_CYOERR; +} + +/* Test for zero address */ + +t_bool dp_zeroad (uint8 *ap) +{ +int32 i; + +for (i = 0; i < DP_ADDR; i++, ap++) { /* loop thru addr */ + if (*ap & DIGIT) return FALSE; } /* nonzero? lose */ +return TRUE; /* all zeroes */ +} + +/* Test for group mark when enabled */ + +t_stat dp_tstgm (uint32 c, int32 qnr) +{ +if (!qnr && ((c & DIGIT) == GRP_MARK)) { /* premature GM? */ + ind[IN_DWLR] = ind[IN_DERR] = 1; /* error */ + return STOP_WRLERR; } +return SCPE_OK; +} + +/* Convert disk address to binary - invalid char force bad address */ + +int32 dp_cvt_ad (uint8 *ap) +{ +int32 i, r; +uint8 c; + +for (i = r = 0; i < DP_ADDR; i++, ap++) { /* loop thru addr */ + c = *ap & DIGIT; /* get digit */ + if (BAD_DIGIT (c)) return -1; /* bad digit? */ + r = (r * 10) + c; } /* bcd to binary */ +return r; +} + +/* Track operation setup */ + +int32 dp_trkop (int32 drv, int32 sec) +{ +int32 ctrk = (sec / DP_NUMSC) % DP_NUMSF; + +return ((drv * DP_TOTSC) + (dp_unit[drv].CYL * DP_NUMSF * DP_NUMSC) + + (ctrk * DP_NUMSC)); +} + +/* Convert DCF BCD field to binary */ + +int32 dp_cvt_bcd (uint32 ad, int32 len) +{ +uint8 c; +int32 r; + +for (r = 0; len > 0; len--) { /* loop thru char */ + c = M[ad] & DIGIT; /* get digit */ + if (BAD_DIGIT (c)) return -1; /* invalid? */ + r = (r * 10) + c; /* cvt to bin */ + PP (ad); } /* next digit */ +return r; +} + +/* Fill sector buffer with zero */ + +void dp_fill (UNIT *uptr, uint32 da, int32 cnt) +{ +while (cnt-- > 0) { /* fill with zeroes*/ + *(((uint8 *) uptr->filebuf) + da) = 0; + if (da >= uptr->hwmark) uptr->hwmark = da + 1; + da++; } +return; +} + +/* Reset routine */ + +t_stat dp_reset (DEVICE *dptr) +{ +int32 i; + +for (i = 0; i < DP_NUMDR; i++) dp_unit[i].CYL = 0; /* reset cylinder */ +ind[IN_DACH] = ind[IN_DWLR] = 0; /* clr indicators */ +ind[IN_DERR] = ind[IN_DCYO] = 0; +return SCPE_OK; +} diff --git a/I1620/i1620_fp.c b/I1620/i1620_fp.c new file mode 100644 index 00000000..02e93a62 --- /dev/null +++ b/I1620/i1620_fp.c @@ -0,0 +1,388 @@ +/* i1620_fp.c: IBM 1620 floating point simulator + + Copyright (c) 2002, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + The IBM 1620 uses a variable length floating point format, with a fixed + two digit decimal exponent and a variable length decimal mantissa: + + _ S_S + M.......MEE + + where S represents flag bits if the mantissa or exponent are negative. +*/ + +#include "i1620_defs.h" + +#define FP_LMAX 100 /* max fp mant lnt */ +#define FP_EMAX 99 /* max fp exponent */ + +/* Unpacked floating point operand */ + +struct fp_opnd { + int32 sign; /* 0 => +, 1 => - */ + int32 exp; /* binary exponent */ + uint32 lnt; /* mantissa length */ + uint32 addr; /* mantissa addr */ + uint32 zero; /* 0 => nz, 1 => zero */ +}; + +typedef struct fp_opnd FPA; + +extern uint8 M[MAXMEMSIZE]; /* main memory */ +extern uint8 ind[NUM_IND]; /* indicators */ +extern UNIT cpu_unit; + +t_stat fp_scan_mant (uint32 ad, uint32 *lnt, uint32 *zro); +t_stat fp_zero (FPA *fp); + +extern t_stat xmt_field (uint32 d, uint32 s, uint32 skp); +extern t_stat add_field (uint32 d, uint32 s, t_bool sub, t_bool sto, int32 *sta); +extern t_stat mul_field (uint32 d, uint32 s); +extern t_stat xmt_divd (uint32 d, uint32 s); +extern t_stat div_field (uint32 dvd, uint32 dvr, int32 *ez); + +/* Unpack and validate a floating point argument */ + +t_stat fp_unpack (uint32 ad, FPA *fp) +{ +uint8 d0, d1, esign; + +esign = M[ad] & FLAG; /* get exp sign */ +d0 = M[ad] & DIGIT; /* get exp lo digit */ +MM (ad); +if ((M[ad] & FLAG) == 0) return STOP_FPMF; /* no flag on hi exp? */ +d1 = M[ad] & DIGIT; /* get exp hi digit */ +MM (ad); +fp->addr = ad; /* save mant addr */ +if (BAD_DIGIT (d1) || BAD_DIGIT (d0)) return STOP_INVDIG; /* exp bad dig? */ +fp->exp = ((d1 * 10) + d0) * (esign? -1: 1); /* convert exponent */ +fp->sign = (M[ad] & FLAG)? 1: 0; /* get mantissa sign */ +return fp_scan_mant (fp->addr, &(fp->lnt), &(fp->zero)); +} + +/* Unpack and validate source and destination arguments */ + +t_stat fp_unpack_two (uint32 dad, uint32 sad, FPA *dfp, FPA *sfp) +{ +t_stat r; + +if ((r = fp_unpack (dad, dfp)) != SCPE_OK) return r; /* unpack dst */ +if ((r = fp_unpack (sad, sfp)) != SCPE_OK) return r; /* unpack src */ +if (sfp->lnt != dfp->lnt) return STOP_FPUNL; /* lnts must be equal */ +return SCPE_OK; +} + +/* Pack floating point result */ + +t_stat fp_pack (FPA *fp) +{ +int32 e; +uint32 i, mad; + +e = (fp->exp >= 0)? fp->exp: -fp->exp; /* get |exp| */ +if (e > FP_EMAX) { /* too big? */ + ind[IN_EXPCHK] = 1; /* set indicator */ + if (fp->exp < 0) return fp_zero (fp); /* underflow? */ + mad = fp->addr; + for (i = 0; i < fp->lnt; i++) { /* mant = 99...99 */ + M[mad] = (M[mad] & FLAG) | 9; + MM (mad); } + e = FP_EMAX; } /* cap at max */ +M[ADDR_A (fp->addr, 1)] = (e / 10) | FLAG; /* high exp digit */ +M[ADDR_A (fp->addr, 2)] = (e % 10) | /* low exp digit */ + ((fp->exp < 0)? FLAG: 0); +return SCPE_OK; +} + +/* Shift mantissa right n positions */ + +void fp_rsh (FPA *fp, uint32 n) +{ +uint32 i, sad, dad; + +if (n == 0) return; /* zero? done */ +sad = ADDR_S (fp->addr, n); /* src = addr - n */ +dad = fp->addr; /* dst = n */ +for (i = 0; i < fp->lnt; i++) { /* move digits */ + if (i >= (fp->lnt - n)) M[dad] = M[dad] & FLAG; + else M[dad] = (M[dad] & FLAG) | (M[sad] & DIGIT); + MM (dad); + MM (sad); } +return; +} + +/* Shift mantissa left 1 position */ + +void fp_lsh_1 (FPA *fp) +{ +uint32 i, mad, nxt; + +mad = ADDR_S (fp->addr, fp->lnt - 1); /* hi order digit */ +for (i = 0; i < (fp->lnt - 1); i++) { /* move lnt-1 digits */ + nxt = ADDR_A (mad, 1); + M[mad] = (M[mad] & FLAG) | (M[nxt] & DIGIT); + mad = nxt; } +M[mad] = M[mad] & FLAG; /* clear last digit */ +return; +} + +/* Clear floating point number */ + +t_stat fp_zero (FPA *fp) +{ +uint32 i, mad = fp->addr; + +for (i = 0; i < fp->lnt; i++) { /* clear mantissa */ + M[mad] = (i? M[mad] & FLAG: 0); /* clear sign bit */ + MM (mad); } +M[ADDR_A (fp->addr, 1)] = FLAG + 9; /* exp = -99 */ +M[ADDR_A (fp->addr, 2)] = FLAG + 9; /* exp = -99 */ +ind[IN_EZ] = 1; /* result = 0 */ +ind[IN_HP] = 0; +return SCPE_OK; +} + +/* Scan floating point mantissa for length and (optionally) zero */ + +t_stat fp_scan_mant (uint32 ad, uint32 *lnt, uint32 *zro) +{ +uint8 d, l, z; + +z = 1; /* assume zero */ +for (l = 1; l <= FP_LMAX; l++) { /* scan to get length */ + d = M[ad] & DIGIT; /* get mant digit */ + if (d) z = 0; /* non-zero? */ + if ((l != 1) && (M[ad] & FLAG)) { /* flag past first dig? */ + *lnt = l; /* set returns */ + if (zro) *zro = z; + return SCPE_OK; } + MM (ad); } +return STOP_FPLNT; /* too long */ +} + +/* Copy floating point mantissa */ + +void fp_copy_mant (uint32 d, uint32 s, uint32 l) +{ +uint32 i; + +if (ind[IN_HP]) M[d] = M[d] & ~FLAG; /* clr/set sign */ +else M[d] = M[d] | FLAG; +for (i = 0; i < l; i++) { /* copy src */ + M[d] = (M[d] & FLAG) | (M[s] & DIGIT); /* preserve flags */ + MM (d); + MM (s); } +return; +} + +/* Compare floating point mantissa */ + +int32 fp_comp_mant (uint32 d, uint32 s, uint32 l) +{ +uint8 i, dd, sd; + +d = ADDR_S (d, l - 1); /* start of mantissa */ +s = ADDR_S (s, l - 1); +for (i = 0; i < l; i++) { /* compare dst:src */ + dd = M[d] & DIGIT; /* get dst digit */ + sd = M[s] & DIGIT; /* get src digit */ + if (dd > sd) return 1; /* >? done */ + if (dd < sd) return -1; /* = ((int32) dfp.lnt))) { /* src = 0, or too small? */ + if (dfp.zero) return fp_zero (&dfp); /* res = dst, zero? */ + ind[IN_EZ] = 0; /* res nz, set EZ, HP */ + ind[IN_HP] = (dfp.sign == 0); + return SCPE_OK; } +if (dfp.zero || (dif <= -((int32) dfp.lnt))) { /* dst = 0, or too small? */ + if (sfp.zero) return fp_zero (&dfp); /* res = src, zero? */ + r = xmt_field (d, s, 3); /* copy src to dst */ + ind[IN_EZ] = 0; /* res nz, set EZ, HP */ + ind[IN_HP] = (dfp.sign == 0); + return r; } + +if (dif > 0) { /* dst exp > src exp? */ + sad = sfp.addr; /* save src in save area */ + for (i = 0; i < sfp.lnt; i++) { + sav_src[i] = M[sad]; + MM (sad); } + fp_rsh (&sfp, dif); } /* denormalize src */ +else if (dif < 0) { /* dst exp < src exp? */ + dfp.exp = sfp.exp; /* res exp = src exp */ + fp_rsh (&dfp, -dif); } /* denormalize dst */ +r = add_field (dfp.addr, sfp.addr, sub, TRUE, &sta); /* add mant, set EZ, HP */ +if (dif > 0) { /* src denormalized? */ + sad = sfp.addr; /* restore src from */ + for (i = 0; i < sfp.lnt; i++) { /* save area */ + M[sad] = sav_src[i]; + MM (sad); } } +if (r != SCPE_OK) return r; /* add error? */ + +hi = ADDR_S (dfp.addr, dfp.lnt - 1); /* addr of hi digit */ +if (sta == ADD_CARRY) { /* carry out? */ + fp_rsh (&dfp, 1); /* shift mantissa */ + M[hi] = FLAG + 1; /* high order 1 */ + dfp.exp = dfp.exp + 1; + ind[IN_EZ] = 0; /* not zero */ + ind[IN_HP] = (dfp.sign == 0); } /* set HP */ +else if (ind[IN_EZ]) return fp_zero (&dfp); /* result zero? */ +else { while ((M[hi] & DIGIT) == 0) { /* until normalized */ + fp_lsh_1 (&dfp); /* left shift */ + dfp.exp = dfp.exp - 1; } } /* decr exponent */ + +return fp_pack (&dfp); /* pack and exit */ +} + +/* Floating point multiply */ + +t_stat fp_mul (uint32 d, uint32 s) +{ +FPA sfp, dfp; +uint32 pad; +t_stat r; + +r = fp_unpack_two (d, s, &dfp, &sfp); /* unpack operands */ +if (r != SCPE_OK) return r; /* error? */ +if (sfp.zero || dfp.zero) return fp_zero (&dfp); /* either zero? */ + +r = mul_field (dfp.addr, sfp.addr); /* mul, set EZ, HP */ +if (r != SCPE_OK) return r; +if (M[ADDR_S (PROD_AREA_END, 2 * dfp.lnt)] & DIGIT) { /* hi prod dig set? */ + pad = ADDR_S (PROD_AREA_END - 1, dfp.lnt); /* no normalization */ + dfp.exp = dfp.exp + sfp.exp; } /* res exp = sum */ +else { pad = ADDR_S (PROD_AREA_END, dfp.lnt); /* 'normalize' 1 */ + dfp.exp = dfp.exp + sfp.exp - 1; } /* res exp = sum - 1 */ +fp_copy_mant (dfp.addr, pad, dfp.lnt); /* copy prod to mant */ + +return fp_pack (&dfp); /* pack and exit */ +} + +/* Floating point divide */ + +t_stat fp_div (uint32 d, uint32 s) +{ +FPA sfp, dfp; +uint32 i, pad, a100ml, a99ml; +int32 ez; +t_stat r; + +r = fp_unpack_two (d, s, &dfp, &sfp); /* unpack operands */ +if (r != SCPE_OK) return r; /* error? */ +if (sfp.zero) { /* divide by zero? */ + ind[IN_OVF] = 1; /* dead jim */ + return SCPE_OK; } +if (dfp.zero) return fp_zero (&dfp); /* divide into zero? */ + +for (i = 0; i < PROD_AREA_LEN; i++) /* clear prod area */ + M[PROD_AREA + i] = 0; +a100ml = ADDR_S (PROD_AREA_END, dfp.lnt); /* 100 - lnt */ +a99ml = ADDR_S (PROD_AREA_END - 1, dfp.lnt); /* 99 - lnt */ +if (fp_comp_mant (dfp.addr, sfp.addr, dfp.lnt) >= 0) { /* |Mdst| >= |Msrc|? */ + pad = a100ml; + dfp.exp = dfp.exp - sfp.exp + 1; } /* res exp = diff + 1 */ +else { pad = a99ml; + dfp.exp = dfp.exp - sfp.exp; } /* res exp = diff */ +r = xmt_divd (pad, dfp.addr); /* xmt dividend */ +if (r != SCPE_OK) return r; /* error? */ +r = div_field (a100ml, sfp.addr, &ez); /* divide fractions */ +if (r != SCPE_OK) return r; /* error? */ +if (ez) return fp_zero (&dfp); /* result zero? */ + +ind[IN_HP] = ((dfp.sign ^ sfp.sign) == 0); /* set res sign */ +ind[IN_EZ] = 0; /* not zero */ +fp_copy_mant (dfp.addr, a99ml, dfp.lnt); /* copy result */ + +return fp_pack (&dfp); +} + +/* Floating shift right */ + +t_stat fp_fsr (uint32 d, uint32 s) +{ +uint32 cnt; +uint8 t; + +if (d == s) return SCPE_OK; /* no move? */ + +cnt = 0; +M[d] = (M[d] & FLAG) | (M[s] & DIGIT); /* move 1st wo flag */ +do { MM (d); /* decr ptrs */ + MM (s); + t = M[d] = M[s] & (FLAG | DIGIT); /* copy others */ + if (cnt++ > MEMSIZE) return STOP_FWRAP; } /* (stop runaway) */ +while ((t & FLAG) == 0); /* until src flag */ + +cnt = 0; +do { MM (d); /* decr pointer */ + t = M[d]; /* save old val */ + M[d] = 0; /* zero field */ + if (cnt++ > MEMSIZE) return STOP_FWRAP; } /* (stop runaway) */ +while ((t & FLAG) == 0); /* until dst flag */ +return SCPE_OK; +} + +/* Floating shift left - note that dst is addr of high order digit */ + +t_stat fp_fsl (uint32 d, uint32 s) +{ +uint32 i, lnt; +uint8 sign; +t_stat r; + +if (d == s) return SCPE_OK; +sign = M[s] & FLAG; /* get src sign */ +r = fp_scan_mant (s, &lnt, NULL); /* get src length */ +if (r != SCPE_OK) return r; /* error? */ +s = ADDR_S (s, lnt - 1); /* hi order src */ +M[d] = M[s] & (FLAG | DIGIT); /* move 1st w flag */ +M[s] = M[s] & ~FLAG; /* clr flag from src */ +for (i = 1; i < lnt; i++) { /* move src to dst */ + PP (d); /* incr ptrs */ + PP (s); + M[d] = M[s] & DIGIT; } /* move just digit */ +PP (d); /* incr pointer */ +while ((M[d] & FLAG) == 0) { /* until flag */ + M[d] = 0; /* clear field */ + PP (d); } +if (sign) M[d] = FLAG; /* -? zero under sign */ +return SCPE_OK; +} diff --git a/I1620/i1620_lp.c b/I1620/i1620_lp.c new file mode 100644 index 00000000..f120a2dc --- /dev/null +++ b/I1620/i1620_lp.c @@ -0,0 +1,314 @@ +/* i1620_lp.c: IBM 1443 line printer simulator + + Copyright (c) 2002, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + lpt 1443 line printer +*/ + +#include "i1620_defs.h" + +#define LPT_BSIZE 197 /* buffer size */ + +#define K_IMM 0x10 /* control now */ +#define K_LIN 0x20 /* spc lines */ +#define K_CH10 0x40 /* chan 10 */ +#define K_LCNT 0x03 /* line count */ +#define K_CHAN 0x0F /* channel */ + +extern uint8 M[MAXMEMSIZE]; +extern uint8 ind[NUM_IND]; +extern UNIT cpu_unit; +extern uint32 io_stop; + +uint32 cct[CCT_LNT] = { 03 }; /* car ctrl tape */ +int32 cct_lnt = 66, cct_ptr = 0; /* cct len, ptr */ +int32 lpt_bptr = 0; /* lpt buf ptr */ +char lpt_buf[LPT_BSIZE + 1]; /* lpt buf */ +int32 lpt_savctrl = 0; /* saved spc ctrl */ + +t_stat lpt_svc (UNIT *uptr); +t_stat lpt_reset (DEVICE *dptr); +t_stat lpt_attach (UNIT *uptr, char *cptr); +void lpt_buf_init (void); +t_stat lpt_num (uint32 pa, uint32 len, uint32 f1); +t_stat lpt_print (void); +t_stat lpt_space (int32 lines, int32 lflag); + +#define CHP(ch,val) ((val) & (1 << (ch))) + +/* LPT data structures + + lpt_dev LPT device descriptor + lpt_unit LPT unit descriptor + lpt_reg LPT register list +*/ + +UNIT lpt_unit = { + UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 50) }; + +REG lpt_reg[] = { + { BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE + 1) }, + { DRDATA (BPTR, lpt_bptr, 8) }, + { HRDATA (PCTL, lpt_savctrl, 8) }, + { FLDATA (PRCHK, ind[IN_PRCHK], 0) }, + { FLDATA (PRCH9, ind[IN_PRCH9], 0) }, + { FLDATA (PRCH12, ind[IN_PRCH12], 0) }, + { FLDATA (PRBSY, ind[IN_PRBSY], 0) }, + { DRDATA (POS, lpt_unit.pos, 32), PV_LEFT }, + { BRDATA (CCT, cct, 8, 32, CCT_LNT) }, + { DRDATA (CCTP, cct_ptr, 8), PV_LEFT }, + { DRDATA (CCTL, cct_lnt, 8), REG_RO + PV_LEFT }, + { NULL } }; + +DEVICE lpt_dev = { + "LPT", &lpt_unit, lpt_reg, NULL, + 1, 10, 31, 1, 8, 7, + NULL, NULL, &lpt_reset, + NULL, &lpt_attach, NULL }; + +/* Data tables */ + +/* Numeric (flag plus digit) to lineprinter (ASCII) */ + +const char num_to_lpt[32] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '\'', ' ', '@', ':', ' ', 'G', + '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'W', ' ', '*', ' ', -1, 'X' }; + +/* Alphameric (digit pair) to lineprinter (ASCII) */ + +const char alp_to_lpt[256] = { + ' ', -1, '?', '.', ')', -1, -1, -1, /* 00 */ + -1, -1, -1, -1, -1, -1, -1, -1, + '+', -1, '!', '$', '*', ' ', -1, -1, /* 10 */ + -1, -1, -1, -1, -1, -1, -1, -1, + '-', '/', '\'', ',', '(', -1, -1, -1, /* 20 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, '0', '=', '@', ':', -1, -1, /* 30 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 40 */ + 'H', 'I', -1, -1, -1, -1, -1, -1, + '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 50 */ + 'Q', 'R', -1, -1, -1, -1, -1, -1, + -1, '/', 'S', 'T', 'U', 'V', 'W', 'X', /* 60 */ + 'Y', 'Z', -1, -1, -1, -1, -1, -1, + '0', '1', '2', '3', '4', '5', '6', '7', /* 70 */ + '8', '9', -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* 90 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* A0 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* B0 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* C0 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* D0 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* E0 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* F0 */ + -1, -1, -1, -1, -1, -1, -1, -1 }; + +/* Line printer IO routine + + - Hard errors halt the system. + - Invalid characters print a blank, set the WRCHK and PRCHK + flags, and halt the system if IO stop is set. +*/ + +t_stat lpt (uint32 op, uint32 pa, uint32 f0, uint32 f1) +{ +int8 lpc; +uint8 z, d; +t_stat r, inv = SCPE_OK; + +sim_cancel (&lpt_unit); /* "stall" until */ +ind[IN_PRBSY] = 0; /* printer free */ + +switch (op) { /* decode op */ +case OP_K: /* control */ + lpt_savctrl = (f0 << 4) | f1; /* form ctrl */ + if (lpt_savctrl & K_IMM) return lpt_print (); /* immediate? */ + break; +case OP_DN: + return lpt_num (pa, 20000 - (pa % 20000), f1); /* dump numeric */ +case OP_WN: + return lpt_num (pa, 0, f1); /* write numeric */ +case OP_WA: + for ( ; lpt_bptr < LPT_BSIZE; lpt_bptr++) { /* only fill buf */ + d = M[pa] & DIGIT; /* get digit */ + z = M[pa - 1] & DIGIT; /* get zone */ + if ((d & REC_MARK) == REC_MARK) break; /* 8-2 char? */ + lpc = alp_to_lpt[(z << 4) | d]; /* translate pair */ + if (lpc < 0) { /* bad char? */ + ind[IN_WRCHK] = ind[IN_PRCHK] = 1; /* wr chk */ + inv = STOP_INVCHR; } /* set return status */ + lpt_buf[lpt_bptr] = lpc & 0x7F; /* fill buffer */ + pa = ADDR_A (pa, 2); } /* incr mem addr */ + if ((f1 & 1) == 0) { ; /* print now? */ + r = lpt_print (); /* print line */ + if (r != SCPE_OK) return r; } + CRETIOE (io_stop, inv); +default: /* invalid function */ + return STOP_INVFNC; } +return SCPE_OK; +} + +/* Print numeric */ + +t_stat lpt_num (uint32 pa, uint32 len, uint32 f1) +{ +uint32 end; +uint8 d; +int8 lpc; +t_stat r, inv = SCPE_OK; + +end = pa + len; +for ( ; lpt_bptr < LPT_BSIZE; lpt_bptr++) { /* only fill buf */ + d = M[pa]; /* get digit */ + if (len? (pa >= end): /* end reached? */ + ((d & REC_MARK) == REC_MARK)) break; + lpc = num_to_lpt[d]; /* translate */ + if (lpc < 0) { /* bad char? */ + ind[IN_WRCHK] = ind[IN_PRCHK] = 1; /* wr chk */ + inv = STOP_INVCHR; } /* set return status */ + lpt_buf[lpt_bptr++] = lpc & 0x7F; /* fill buffer */ + PP (pa); } /* incr mem addr */ +if ((f1 & 1) == 0) { /* print now? */ + r = lpt_print (); /* print line */ + if (r != SCPE_OK) return r; } +CRETIOE (io_stop, inv); +} + +/* Print and space */ + +t_stat lpt_print (void) +{ +int32 i, chan, ctrl = lpt_savctrl; + +if ((lpt_unit.flags & UNIT_ATT) == 0) { /* not attached? */ + ind[IN_PRCHK] = ind[IN_WRCHK] = 1; /* wr, pri check */ + return SCPE_UNATT; } + +ind[IN_PRBSY] = 1; /* print busy */ +sim_activate (&lpt_unit, lpt_unit.time); /* start timer */ + +for (i = LPT_WIDTH; i <= LPT_BSIZE; i++) /* clear unprintable */ + lpt_buf[i] = ' '; +while ((lpt_bptr > 0) && (lpt_buf[lpt_bptr - 1] == ' ')) + lpt_buf[--lpt_bptr] = 0; /* trim buffer */ +if (lpt_bptr) { /* any line? */ + fputs (lpt_buf, lpt_unit.fileref); /* print */ + lpt_unit.pos = ftell (lpt_unit.fileref); /* update pos */ + lpt_buf_init (); /* reinit buf */ + if (ferror (lpt_unit.fileref)) { /* error? */ + ind[IN_PRCHK] = ind[IN_WRCHK] = 1; /* wr, pri check */ + perror ("LPT I/O error"); + clearerr (lpt_unit.fileref); + return SCPE_IOERR; } } + +lpt_savctrl = 0x61; /* reset ctrl */ +if ((ctrl & K_LIN) == ((ctrl & K_IMM)? 0: K_LIN)) /* space lines? */ + return lpt_space (ctrl & K_LCNT, FALSE); +chan = lpt_savctrl & K_CHAN; /* basic chan */ +if (lpt_savctrl & K_CH10) { /* chan 10-12? */ + if (chan == 0) chan = 10; + else if (chan == 3) chan = 11; + else if (chan == 4) chan = 12; + else chan = 0; } +if ((chan == 0) || (chan > 12)) return STOP_INVFNC; +for (i = 1; i < cct_lnt + 1; i++) { /* sweep thru cct */ + if (CHP (chan, cct[(cct_ptr + i) % cct_lnt])) + return lpt_space (i, TRUE); } +return STOP_CCT; /* runaway channel */ +} + +/* Space routine - space or skip n lines + + Inputs: + count = number of lines to space or skip + sflag = skip (TRUE) or space (FALSE) +*/ + +t_stat lpt_space (int32 count, int32 sflag) +{ +int32 i; + +cct_ptr = (cct_ptr + count) % cct_lnt; /* adv cct, mod lnt */ +if (sflag && CHP (0, cct[cct_ptr])) /* skip, top of form? */ + fputs ("\n\f", lpt_unit.fileref); /* nl, ff */ +else { for (i = 0; i < count; i++) /* count lines */ + fputc ('\n', lpt_unit.fileref); } +lpt_unit.pos = ftell (lpt_unit.fileref); /* update position */ +ind[IN_PRCH9] = CHP (9, cct[cct_ptr]) != 0; /* set indicators */ +ind[IN_PRCH12] = CHP (12, cct[cct_ptr]) != 0; +if (ferror (lpt_unit.fileref)) { /* error? */ + ind[IN_PRCHK] = ind[IN_WRCHK] = 1; /* wr, pri check */ + perror ("LPT I/O error"); + clearerr (lpt_unit.fileref); + return SCPE_IOERR; } +return SCPE_OK; +} + +/* Unit service - clear printer busy */ + +t_stat lpt_svc (UNIT *uptr) +{ +ind[IN_PRBSY] = 0; +return SCPE_OK; +} + +/* Initialize lpt buffer */ + +void lpt_buf_init (void) +{ +int32 i; + +lpt_bptr = 0; +for (i = 0; i < LPT_WIDTH + 1; i++) lpt_buf[i] = 0; +return; +} + +/* Reset routine */ + +t_stat lpt_reset (DEVICE *dptr) +{ +lpt_buf_init (); /* clear buffer */ +cct_ptr = 0; /* clear cct ptr */ +lpt_savctrl = 0x61; /* clear cct action */ +ind[IN_PRCHK] = ind[IN_PRBSY] = 0; /* clear indicators */ +ind[IN_PRCH9] = ind[IN_PRCH12] = 0; +return SCPE_OK; +} + +/* Attach routine */ + +t_stat lpt_attach (UNIT *uptr, char *cptr) +{ +lpt_reset (&lpt_dev); +return attach_unit (uptr, cptr); +} diff --git a/I1620/i1620_pt.c b/I1620/i1620_pt.c new file mode 100644 index 00000000..40b9a7e3 --- /dev/null +++ b/I1620/i1620_pt.c @@ -0,0 +1,434 @@ +/* i1620_pt.c: IBM 1621/1624 paper tape reader/punch simulator + + Copyright (c) 2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + ptr 1621 paper tape reader + ptp 1624 paper tape punch +*/ + +#include "i1620_defs.h" + +#define PT_EL 0x80 /* end record */ +#define PT_X 0x40 /* X */ +#define PT_O 0x20 /* O */ +#define PT_C 0x10 /* C */ +#define PT_FD 0x7F /* deleted */ + +extern uint8 M[MAXMEMSIZE]; +extern uint8 ind[NUM_IND]; +extern UNIT cpu_unit; +extern uint32 io_stop; + +t_stat ptr_reset (DEVICE *dptr); +t_stat ptr_boot (int32 unitno, DEVICE *dptr); +t_stat ptr_read (uint8 *c, t_bool ignfeed); +t_stat ptp_reset (DEVICE *dptr); +t_stat ptp_write (uint32 c); +t_stat ptp_num (uint32 pa, uint32 len); + +/* PTR data structures + + ptr_dev PTR device descriptor + ptr_unit PTR unit descriptor + ptr_reg PTR register list +*/ + +UNIT ptr_unit = { + UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0) }; + +REG ptr_reg[] = { + { DRDATA (POS, ptr_unit.pos, 32), PV_LEFT }, + { NULL } }; + +DEVICE ptr_dev = { + "PTR", &ptr_unit, ptr_reg, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ptr_reset, + &ptr_boot, NULL, NULL }; + +/* PTP data structures + + ptp_dev PTP device descriptor + ptp_unit PTP unit descriptor + ptp_reg PTP register list +*/ + +UNIT ptp_unit = { + UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) }; + +REG ptp_reg[] = { + { DRDATA (POS, ptp_unit.pos, 32), PV_LEFT }, + { NULL } }; + +DEVICE ptp_dev = { + "PTP", &ptp_unit, ptp_reg, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ptp_reset, + NULL, NULL, NULL }; + +/* Data tables */ + +/* Paper tape reader odd parity chart: 1 = bad, 0 = ok */ + +const int8 bad_par[128] = { + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 00 */ + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 10 */ + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 20 */ + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 30 */ + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 40 */ + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 50 */ + 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 60 */ + 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 }; /* 70 */ + +/* Paper tape read (7b) to numeric (one digit) */ + +const int8 ptr_to_num[128] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* - */ + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* C */ + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* O */ + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* OC */ + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* X */ + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x10, 0x1E, 0x1F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, /* XC */ + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x10, 0x1E, 0x1F, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* XO */ + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* XOC */ + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x00, 0x0E, 0x0F }; + +/* Paper tape read (7b) to alphameric (two digits) + Codes XO82, 82, XO842, 842 do not have consistent translations +*/ + +const int8 ptr_to_alp[128] = { + 0x00, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* - */ + 0x78, 0x79, -1, 0x33, 0x34, 0x70, -1, 0x0F, + 0x00, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* C */ + 0x78, 0x79, -1, 0x33, 0x34, 0x70, -1, 0x0F, + 0x70, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* O */ + 0x68, 0x69, 0x0A, 0x23, 0x24, 0x60, 0x0E, 0x0F, + 0x70, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* OC */ + 0x68, 0x69, 0x0A, 0x23, 0x24, 0x60, 0x0E, 0x0F, + 0x20, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* X */ + 0x58, 0x59, 0x5A, 0x13, 0x14, 0x50, 0x5E, 0x5F, + 0x20, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* XC */ + 0x58, 0x59, 0x5A, 0x13, 0x14, 0x50, 0x5E, 0x5F, + 0x10, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* XO */ + 0x48, 0x49, -1, 0x03, 0x04, 0x40, -1, 0x7F, + 0x10, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* XOC */ + 0x48, 0x49, -1, 0x03, 0x04, 0x40, -1, 0x7F }; + +/* Numeric (flag + digit) to paper tape punch */ + +const int8 num_to_ptp[32] = { + 0x20, 0x01, 0x02, 0x13, 0x04, 0x15, 0x16, 0x07, /* 0 */ + 0x08, 0x19, 0x2A, 0x3B, 0x1C, 0x0D, 0x3E, 0x3F, + 0x40, 0x51, 0x52, 0x43, 0x54, 0x45, 0x46, 0x57, /* F + 0 */ + 0x58, 0x49, 0x4A, 0x5B, 0x4C, 0x5D, 0x5E, 0x4F }; + +/* Alphameric (two digits) to paper tape punch */ + +const int8 alp_to_ptp[256] = { + 0x10, -1, 0x7A, 0x6B, 0x7C, -1, -1, 0x7F, /* 00 */ + -1, -1, 0x2A, -1, -1, -1, -1, 0x1F, + 0x70, -1, 0x4A, 0x5B, 0x4C, -1, -1, -1, /* 10 */ + -1, -1, -1, -1, -1, -1, -1, -1, + 0x40, 0x31, 0x2A, 0x3B, 0x2C, -1, -1, -1, /* 20 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 0x1A, 0x0B, 0x1C, 0x0D, 0x0E, -1, /* 30 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 0x61, 0x62, 0x73, 0x64, 0x75, 0x76, 0x67, /* 40 */ + 0x68, 0x79, -1, -1, -1, -1, -1, -1, + 0x40, 0x51, 0x52, 0x43, 0x54, 0x45, 0x46, 0x57, /* 50 */ + 0x58, 0x49, 0x4A, -1, -1, -1, -1, 0x4F, + -1, 0x31, 0x32, 0x23, 0x34, 0x25, 0x26, 0x37, /* 60 */ + 0x38, 0x29, -1, -1, -1, -1, -1, -1, + 0x20, 0x01, 0x02, 0x13, 0x04, 0x15, 0x16, 0x07, /* 70 */ + 0x08, 0x19, 0x7A, -1, -1, -1, -1, 0x7F, + -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* 90 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* A0 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* B0 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* C0 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* D0 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* E0 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* F0 */ + -1, -1, -1, -1, -1, -1, -1, -1 }; + +/* Paper tape reader IO routine + + - Hard errors halt the operation and the system. + - Parity errors place an invalid character in memory and set + RDCHK, but the read continues until end of record. If IO + stop is set, the system then halts. +*/ + +t_stat ptr (uint32 op, uint32 pa, uint32 f0, uint32 f1) +{ +t_addr i; +int8 mc; +uint8 ptc; +t_stat r, inv = SCPE_OK; + +switch (op) { /* case on op */ +case OP_RN: /* read numeric */ + for (i = 0; i < MEMSIZE; i++) { /* (stop runaway) */ + r = ptr_read (&ptc, TRUE); /* read frame */ + if (r != SCPE_OK) return r; /* error? */ + if (ptc & PT_EL) { /* end record? */ + M[pa] = REC_MARK; /* store rec mark */ + CRETIOE (io_stop, inv); } /* done */ + if (bad_par[ptc]) { /* bad parity? */ + ind[IN_RDCHK] = 1; /* set read check */ + inv = STOP_INVCHR; /* set return status */ + M[pa] = 0; } /* store zero */ + else M[pa] = ptr_to_num[ptc]; /* translate, store */ + PP (pa); } /* incr mem addr */ + break; +case OP_RA: /* read alphameric */ + for (i = 0; i < MEMSIZE; i = i + 2) { /* (stop runaway) */ + r = ptr_read (&ptc, TRUE); /* read frame */ + if (r != SCPE_OK) return r; /* error? */ + if (ptc & PT_EL) { /* end record? */ + M[pa] = REC_MARK; /* store rec mark */ + M[pa - 1] = 0; + CRETIOE (io_stop, inv); } /* done */ + mc = ptr_to_alp[ptc]; /* translate */ + if (bad_par[ptc] || (mc < 0)) { /* bad par or char? */ + ind[IN_RDCHK] = 1; /* set read check */ + inv = STOP_INVCHR; /* set return status */ + mc = 0; } /* store blank */ + M[pa] = (M[pa] & FLAG) | (mc & DIGIT); /* store 2 digits */ + M[pa - 1] = (M[pa - 1] & FLAG) | ((mc >> 4) & DIGIT); + pa = ADDR_A (pa, 2); } /* incr mem addr */ + break; +default: /* invalid function */ + return STOP_INVFNC; } +return STOP_RWRAP; +} + +/* Binary paper tape reader IO routine - see above for error handling */ + +t_stat btr (uint32 op, uint32 pa, uint32 f0, uint32 f1) +{ +t_addr i; +uint8 ptc; +t_stat r, inv = SCPE_OK; + +if ((cpu_unit.flags & IF_BIN) == 0) return STOP_INVIO; +switch (op) { /* case on op */ +case OP_RA: /* read alphameric */ + for (i = 0; i < MEMSIZE; i = i + 2) { /* (stop runaway) */ + r = ptr_read (&ptc, FALSE); /* read frame */ + if (r != SCPE_OK) return r; /* error? */ + if (ptc & PT_EL) { /* end record? */ + M[pa] = REC_MARK; /* store rec mark */ + M[pa - 1] = 0; + CRETIOE (io_stop, inv); } /* done */ + if (bad_par[ptc]) { /* bad parity? */ + ind[IN_RDCHK] = 1; /* set read check */ + inv = STOP_INVCHR; } /* set return status */ + M[pa] = (M[pa] & FLAG) | (ptc & 07); /* store 2 digits */ + M[pa - 1] = (M[pa - 1] & FLAG) | + (((ptc >> 5) & 06) | ((ptc >> 3) & 1)); + pa = ADDR_A (pa, 2); } /* incr mem addr */ + break; +default: /* invalid function */ + return STOP_INVFNC; } +return STOP_RWRAP; +} + +/* Read ptr frame - all errors are 'hard' errors and halt the system */ + +t_stat ptr_read (uint8 *c, t_bool ignfeed) +{ +int32 temp; + +if ((ptr_unit.flags & UNIT_ATT) == 0) { /* attached? */ + ind[IN_RDCHK] = 1; /* no, error */ + return SCPE_UNATT; } + +do { if ((temp = getc (ptr_unit.fileref)) == EOF) { /* read char */ + ind[IN_RDCHK] = 1; /* err, rd chk */ + if (feof (ptr_unit.fileref)) + printf ("PTR end of file\n"); + else perror ("PTR I/O error"); + clearerr (ptr_unit.fileref); + return SCPE_IOERR; } + *c = temp & 0377; /* save char */ + ptr_unit.pos = ptr_unit.pos + 1; } /* incr file addr */ +while (ignfeed && (*c == PT_FD)); /* until not feed */ +return SCPE_OK; +} + +/* Reset routine */ + +t_stat ptr_reset (DEVICE *dptr) +{ +return SCPE_OK; +} + +/* Bootstrap routine */ + +const static uint8 boot_rom[] = { + 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* NOP */ + 3, 6, 0, 0, 0, 3, 1, 0, 0, 3, 0, 0, /* RNPT 31 */ + 2, 5, 0, 0, 0, 7, 1, 0, 0, 0, 0, 0, /* TD 71,loc */ + 3, 6, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, /* RNPT loc1 */ + 2, 6, 0, 0, 0, 6, 6, 0, 0, 0, 3, 5, /* TF 66,35 */ + 1, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* TDM loc2,loc3 */ + 4, 9, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0 }; /* BR 12 */ + +#define BOOT_START 0 +#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint8)) + +t_stat ptr_boot (int32 unitno, DEVICE *dptr) +{ +int32 i; +extern int32 saved_PC; + +for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i]; +saved_PC = BOOT_START; +return SCPE_OK; +} + +/* Paper tape punch IO routine + + - Hard errors halt the operation and the system. + - Parity errors stop the operation and set WRCHK. + If IO stop is set, the system then halts. +*/ + +t_stat ptp (uint32 op, uint32 pa, uint32 f0, uint32 f1) +{ +t_addr i; +int8 ptc; +uint8 z, d; +t_stat r; + +switch (op) { /* decode op */ +case OP_DN: + return ptp_num (pa, 20000 - (pa % 20000)); /* dump numeric */ +case OP_WN: + return ptp_num (pa, 0); /* punch numeric */ +case OP_WA: + for (i = 0; i < MEMSIZE; i = i + 2) { /* stop runaway */ + d = M[pa] & DIGIT; /* get digit */ + z = M[pa - 1] & DIGIT; /* get zone */ + if ((d & REC_MARK) == REC_MARK) /* 8-2 char? */ + return ptp_write (PT_EL); /* end record */ + ptc = alp_to_ptp[(z << 4) | d]; /* translate pair */ + if (ptc < 0) { /* bad char? */ + ind[IN_WRCHK] = 1; /* write check */ + CRETIOE (io_stop, STOP_INVCHR); } + r = ptp_write (ptc); /* write char */ + if (r != SCPE_OK) return r; /* error? */ + pa = ADDR_A (pa, 2); } /* incr mem addr */ + break; +default: /* invalid function */ + return STOP_INVFNC; } +return STOP_RWRAP; +} + +/* Binary paper tape punch IO routine - see above for error handling */ + +t_stat btp (uint32 op, uint32 pa, uint32 f0, uint32 f1) +{ +t_addr i; +uint8 ptc, z, d; +t_stat r; + +if ((cpu_unit.flags & IF_BIN) == 0) return STOP_INVIO; +switch (op) { /* decode op */ +case OP_WA: + for (i = 0; i < MEMSIZE; i = i + 2) { /* stop runaway */ + d = M[pa] & DIGIT; /* get digit */ + z = M[pa - 1] & DIGIT; /* get zone */ + if ((d & REC_MARK) == REC_MARK) /* 8-2 char? */ + return ptp_write (PT_EL); /* end record */ + ptc = ((z & 06) << 5) | ((z & 01) << 3) | (d & 07); + if (bad_par[ptc]) ptc = ptc | PT_C; /* set parity */ + r = ptp_write (ptc); /* write char */ + if (r != SCPE_OK) return r; /* error? */ + pa = ADDR_A (pa, 2); } /* incr mem addr */ + break; +default: /* invalid function */ + return STOP_INVFNC; } +return STOP_RWRAP; +} + +/* Punch tape numeric - cannot generate parity errors */ + +t_stat ptp_num (uint32 pa, uint32 len) +{ +t_stat r; +uint8 d; +uint32 i, end; + +end = pa + len; +for (i = 0; i < MEMSIZE; i++) { /* stop runaway */ + d = M[pa] & (FLAG | DIGIT); /* get char */ + if (len? (pa >= end): /* dump: end reached? */ + ((d & REC_MARK) == REC_MARK)) /* write: rec mark? */ + return ptp_write (PT_EL); /* end record */ + r = ptp_write (num_to_ptp[d]); /* write */ + if (r != SCPE_OK) return r; /* error? */ + PP (pa); } /* incr mem addr */ +return STOP_RWRAP; +} + +/* Write ptp frame - all errors are hard errors */ + +t_stat ptp_write (uint32 c) +{ +if ((ptp_unit.flags & UNIT_ATT) == 0) { /* attached? */ + ind[IN_WRCHK] = 1; /* no, error */ + return SCPE_UNATT; } + +if (putc (c, ptp_unit.fileref) == EOF) { /* write char */ + ind[IN_WRCHK] = 1; /* error? */ + perror ("PTP I/O error"); + clearerr (ptp_unit.fileref); + return SCPE_IOERR; } +ptp_unit.pos = ptp_unit.pos + 1; /* count char */ +return SCPE_OK; +} + +/* Reset routine */ + +t_stat ptp_reset (DEVICE *dptr) +{ +return SCPE_OK; +} diff --git a/I1620/i1620_sys.c b/I1620/i1620_sys.c new file mode 100644 index 00000000..831d495a --- /dev/null +++ b/I1620/i1620_sys.c @@ -0,0 +1,491 @@ +/* i1620_sys.c: IBM 1620 simulator interface + + Copyright (c) 2002, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. +*/ + +#include "i1620_defs.h" +#include + +#define LINE_LNT 50 + +extern DEVICE cpu_dev, tty_dev; +extern DEVICE ptr_dev, ptp_dev; +extern DEVICE lpt_dev; +extern DEVICE cdr_dev, cdp_dev; +extern DEVICE dp_dev; +extern UNIT cpu_unit; +extern REG cpu_reg[]; +extern uint8 M[MAXMEMSIZE]; +extern char cdr_to_alp[128], alp_to_cdp[256]; + +/* SCP data structures and interface routines + + sim_name simulator name string + sim_PC pointer to saved PC register descriptor + sim_emax maximum number of words for examine/deposit + sim_devices array of pointers to simulated devices + sim_stop_messages array of pointers to stop messages + sim_load binary loader +*/ + +char sim_name[] = "IBM 1620"; + +REG *sim_PC = &cpu_reg[0]; + +int32 sim_emax = LINE_LNT; + +DEVICE *sim_devices[] = { + &cpu_dev, + &tty_dev, + &ptr_dev, + &ptp_dev, + &cdr_dev, + &cdp_dev, + &lpt_dev, + &dp_dev, + NULL }; + +const char *sim_stop_messages[] = { + "Unknown error", + "HALT instruction", + "Breakpoint", + "Invalid instruction", + "Invalid digit", + "Invalid character", + "Invalid indicator", + "Invalid digit in P address", + "Invalid P address", + "P address exceeds indirect address limit", + "Invalid digit in Q address", + "Invalid Q address", + "Q address exceeds indirect address limit", + "Invalid IO device", + "Invalid return register", + "Invalid IO function", + "Instruction address must be even", + "Invalid select code", + "Index instruction with no band selected", + "P address must be odd", + "DCF address must be even", + "Invalid disk drive", + "Invalid disk sector address", + "Invalid disk sector count", + "Invalid disk buffer address", + "Disk address compare error", + "Disk write check error", + "Disk cylinder overflow error", + "Disk wrong length record error", + "Invalid CCT", + "Field exceeds memory", + "Record exceeds memory", + "No card in reader", + "Overflow check", + "Exponent check", + "Write address function disabled", + "Floating point mantissa too long", + "Floating point mantissa lengths unequal", + "Floating point exponent flag missing", + "Floating point divide by zero" }; + +/* Binary loader -- load carriage control tape + + A carriage control tape consists of entries of the form + + (repeat count) column number,column number,column number,... + + The CCT entries are stored in cct[0:lnt-1], cctlnt contains the + number of entries +*/ + +t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) +{ +int32 col, rpt, ptr, mask, cctbuf[CCT_LNT]; +t_stat r; +extern int32 cct_lnt, cct_ptr, cct[CCT_LNT]; +char cbuf[CBUFSIZE], gbuf[CBUFSIZE]; + +if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; +ptr = 0; +for ( ; (cptr = fgets (cbuf, CBUFSIZE, fileref)) != NULL; ) { /* until eof */ + mask = 0; + if (*cptr == '(') { /* repeat count? */ + cptr = get_glyph (cptr + 1, gbuf, ')'); /* get 1st field */ + rpt = get_uint (gbuf, 10, CCT_LNT, &r); /* repeat count */ + if (r != SCPE_OK) return SCPE_FMT; } + else rpt = 1; + while (*cptr != 0) { /* get col no's */ + cptr = get_glyph (cptr, gbuf, ','); /* get next field */ + col = get_uint (gbuf, 10, 12, &r); /* column number */ + if (r != SCPE_OK) return SCPE_FMT; + mask = mask | (1 << col); } /* set bit */ + for ( ; rpt > 0; rpt--) { /* store vals */ + if (ptr >= CCT_LNT) return SCPE_FMT; + cctbuf[ptr++] = mask; } } +if (ptr == 0) return SCPE_FMT; +cct_lnt = ptr; +cct_ptr = 0; +for (rpt = 0; rpt < cct_lnt; rpt++) cct[rpt] = cctbuf[rpt]; +return SCPE_OK; +} + +/* Symbol table */ + +struct opc { + char *str; /* mnemonic */ + uint32 opv; /* opcode & flags */ + uint32 qv; /* q field */ +}; + +#define I_V_FL 16 /* flags */ +#define I_M_QX 0x01 /* Q indexable */ +#define I_M_QM 0x02 /* Q immediate */ +#define I_M_QNP 0x00 /* Q no print */ +#define I_M_QCP 0x04 /* Q cond print */ +#define I_M_QP 0x08 /* Q print */ +#define I_M_PCP 0x00 /* P cond print */ +#define I_M_PP 0x10 /* P print */ +#define I_GETQF(x) (((x) >> I_V_FL) & 0x03) +#define I_GETQP(x) (((x) >> I_V_FL) & 0x0C) +#define I_GETPP(x) (((x) >> I_V_FL) & 0x10) + +#define I_2 ((I_M_PP | I_M_QP | I_M_QX) << I_V_FL) +#define I_2M ((I_M_PP | I_M_QP | I_M_QM) << I_V_FL) +#define I_2X ((I_M_PP | I_M_QP | I_M_QX | I_M_QM) << I_V_FL) +#define I_2S ((I_M_PP | I_M_QP) << I_V_FL) +#define I_1 ((I_M_PP | I_M_QCP) << I_V_FL) +#define I_1E ((I_M_PP | I_M_QNP) << I_V_FL) +#define I_0 ((I_M_PCP | I_M_QCP) << I_V_FL) +#define I_0E ((I_M_PCP | I_M_QNP) << I_V_FL) + +struct opc opcode[] = { + { "RNTY", 36+I_1E, 100 }, { "RATY", 37+I_1E, 100 }, + { "WNTY", 38+I_1E, 100 }, { "WATY", 39+I_1E, 100 }, + { "DNTY", 35+I_1E, 100 }, { "SPTY", 34+I_0E, 101 }, + { "RCTY", 34+I_0E, 102 }, { "BKTY", 34+I_0E, 103 }, + { "IXTY", 34+I_0E, 104 }, { "TBTY", 34+I_0E, 108 }, + { "RNPT", 36+I_1E, 300 }, { "RAPT", 37+I_1E, 300 }, + { "WNPT", 38+I_1E, 200 }, { "WAPT", 39+I_1E, 200 }, + { "DNPT", 35+I_1E, 200 }, + { "RNCD", 36+I_1E, 500 }, { "RACD", 37+I_1E, 500 }, + { "WNCD", 38+I_1E, 400 }, { "WACD", 39+I_1E, 400 }, + { "DNCD", 35+I_1E, 400 }, + { "PRN", 38+I_1E, 900 }, { "PRNS", 38+I_1E, 901 }, + { "PRA", 39+I_1E, 900 }, { "PRAS", 39+I_1E, 901 }, + { "PRD", 35+I_1E, 900 }, { "PRDS", 35+I_1E, 901 }, + { "SK", 34+I_1E, 701 }, + { "RDGN", 36+I_1E, 700 }, { "CDGN", 36+I_1E, 701 }, + { "RDN", 36+I_1E, 702 }, { "CDN", 36+I_1E, 703 }, + { "RTGN", 36+I_1E, 704 }, { "CTGN", 36+I_1E, 705 }, + { "RTN", 36+I_1E, 706 }, { "CTN", 36+I_1E, 707 }, + { "WDGN", 38+I_1E, 700 }, { "WDN", 38+I_1E, 702 }, + { "WTGN", 38+I_1E, 704 }, { "WTN", 38+I_1E, 706 }, + { "RBPT", 37+I_1E, 3300 }, { "WBPT", 39+I_1E, 3200 }, + { "BC1", 46+I_1E, 100 }, { "BNC1", 47+I_1E, 100 }, + { "BC2", 46+I_1E, 200 }, { "BNC2", 47+I_1E, 200 }, + { "BC3", 46+I_1E, 300 }, { "BNC3", 47+I_1E, 300 }, + { "BC4", 46+I_1E, 400 }, { "BNC4", 47+I_1E, 400 }, + { "BLC", 46+I_1E, 900 }, { "BNLC", 47+I_1E, 900 }, + { "BH", 46+I_1E, 1100 }, { "BNH", 47+I_1E, 1100 }, + { "BP", 46+I_1E, 1100 }, { "BNP", 47+I_1E, 1100 }, + { "BE", 46+I_1E, 1200 }, { "BNE", 47+I_1E, 1200 }, + { "BZ", 46+I_1E, 1200 }, { "BNZ", 47+I_1E, 1200 }, + { "BNL", 46+I_1E, 1300 }, { "BL", 47+I_1E, 1300 }, + { "BNN", 46+I_1E, 1300 }, { "BN", 47+I_1E, 1300 }, + { "BV", 46+I_1E, 1400 }, { "BNV", 47+I_1E, 1400 }, + { "BXV", 46+I_1E, 1500 }, { "BNXV", 47+I_1E, 1500 }, + { "BA", 46+I_1E, 1900 }, { "BNA", 47+I_1E, 1900 }, + { "BNBS", 46+I_1E, 3000 }, { "BEBS", 47+I_1E, 3000 }, + { "BBAS", 46+I_1E, 3100 }, { "BANS", 47+I_1E, 3100 }, + { "BBBS", 46+I_1E, 3200 }, { "BBNS", 47+I_1E, 3200 }, + { "BCH9", 46+I_1E, 3300 }, + { "BCOV", 46+I_1E, 3400 }, + { "BSNX", 60+I_1E, 0 }, { "BSBA", 60+I_1E, 1 }, + { "BSBB", 60+I_1E, 2 }, + { "BSNI", 60+I_1E, 8 }, { "BSIA", 60+I_1E, 9 }, + + { "FADD", 1+I_2, 0 }, { "FSUB", 2+I_2, 0 }, + { "FMUL", 3+I_2, 0 }, { "FSL", 5+I_2, 0 }, + { "TFL", 6+I_2, 0 }, { "BTFL", 7+I_2, 0 }, + { "FSR", 8+I_2, 0 }, { "FDIV", 9+I_2, 0 }, + { "BTAM", 10+I_2M, 0 }, { "AM", 11+I_2M, 0 }, + { "SM", 12+I_2M, 0 }, { "MM", 13+I_2M, 0 }, + { "CM", 14+I_2M, 0 }, { "TDM", 15+I_2S, 0 }, + { "TFM", 16+I_2M, 0 }, { "BTM", 17+I_2M, 0 }, + { "LDM", 18+I_2M, 0 }, { "DM", 19+I_2M, 0 }, + { "BTA", 20+I_2, 0 }, { "A", 21+I_2, 0 }, + { "S", 22+I_2, 0 }, { "M", 23+I_2, 0 }, + { "C", 24+I_2, 0 }, { "TD", 25+I_2, 0 }, + { "TF", 26+I_2, 0 }, { "BT", 27+I_2, 0 }, + { "LD", 28+I_2, 0 }, { "D", 29+I_2, 0 }, + { "TRNM", 30+I_2, 0 }, { "TR", 31+I_2, 0 }, + { "SF", 32+I_1, 0 }, { "CF", 33+I_1, 0 }, + { "K", 34+I_2S, 0 }, { "DN", 35+I_2S, 0 }, + { "RN", 36+I_2S, 0 }, { "RA", 37+I_2S, 0 }, + { "WN", 38+I_2S, 0 }, { "WA", 39+I_2S, 0 }, + { "NOP", 41+I_0, 0 }, { "BB", 42+I_0, 0 }, + { "BD", 43+I_2, 0 }, { "BNF", 44+I_2, 0 }, + { "BNR", 45+I_2, 0 }, { "BI", 46+I_2S, 0 }, + { "BNI", 47+I_2S, 0 }, { "H", 48+I_0, 0 }, + { "B", 49+I_1, 0 }, { "BNG", 55+I_2, 0 }, + { "BS", 60+I_2S, 0 }, { "BX", 61+I_2, 0 }, + { "BXM", 62+I_2X, 0 }, { "BCX", 63+I_2, 0 }, + { "BCXM", 64+I_2X, 0 }, { "BLX", 65+I_2, 0 }, + { "BLXM", 66+I_2X, 0 }, { "BSX", 67+I_2, 0 }, + { "MA", 70+I_2, 0 }, { "MF", 71+I_2, 0 }, + { "TNS", 72+I_2, 0 }, { "TNF", 73+I_2, 0 }, + { "BBT", 90+I_2, 0 }, { "BMK", 91+I_2, 0 }, + { "ORF", 92+I_2, 0 }, { "ANDF", 93+I_2, 0 }, + { "CPFL", 94+I_2, 0 }, { "EORF", 95+I_2, 0 }, + { "OTD", 96+I_2, 0 }, { "DTO", 97+I_2, 0 }, + { NULL, 0, 0 } }; + +/* Print an address from five characters */ + +void fprint_addr (FILE *of, int32 spc, t_value *dig, t_bool flg) +{ +int32 i, idx; + +fputc (spc, of); /* spacer */ +if (dig[ADDR_LEN - 1] & FLAG) { /* signed? */ + fputc ('-', of); /* print minus */ + dig[ADDR_LEN - 1] = dig[ADDR_LEN - 1] & ~FLAG; } +for (i = 0; i < ADDR_LEN; i++) /* print digits */ + fprintf (of, "%X", dig[i] & DIGIT); +if ((cpu_unit.flags & IF_IDX) && flg) { /* indexing? */ + for (i = idx = 0; i < ADDR_LEN - 2; i++) { /* get index reg */ + if (dig[ADDR_LEN - 2 - i] & FLAG) + idx = idx | (1 << i); + dig[ADDR_LEN - 2 - i] = dig[ADDR_LEN - 2 - i] & ~FLAG; } + if (idx) fprintf (of, "(%d)", idx); } /* print */ +return; +} + +/* Symbolic decode + + Inputs: + *of = output stream + addr = current address + *val = values to decode + *uptr = pointer to unit + sw = switches + Outputs: + return = if >= 0, error code + if < 0, number of extra words retired +*/ + +#define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x) + +t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, + UNIT *uptr, int32 sw) +{ +int32 pmp, qmp, i, c, d, any; +uint32 op, qv, opfl; + +if (uptr == NULL) uptr = &cpu_unit; +if (sw & SWMASK ('C')) { /* character? */ + if (uptr->flags & UNIT_BCD) { + if (addr & 1) return SCPE_ARG; /* must be even */ + c = ((val[0] & DIGIT) << 4) | (val[1] & DIGIT); + if (alp_to_cdp[c] > 0) + fprintf (of, "%c", alp_to_cdp[c]); + else fprintf (of, "<%02x>", c); + return -1; } + else fprintf (of, FMTASC (val[0] & 0177)); + return SCPE_OK; } +if ((uptr->flags & UNIT_BCD) == 0) return SCPE_ARG; /* CPU or disk? */ +if (sw & SWMASK ('D')) { /* dump? */ + for (i = d = 0; i < LINE_LNT; i++) d = d | val[i]; + if (d & FLAG) { /* any flags? */ + for (i = 0; i < LINE_LNT; i++) /* print flags */ + fprintf (of, (val[i] & FLAG)? "_": " "); + fprintf (of, "\n\t"); } + for (i = 0; i < LINE_LNT; i++) /* print digits */ + fprintf (of, "%X", val[i] & DIGIT) ; + return -(i - 1); } +if (sw & SWMASK ('S')) { /* string? */ + if (addr & 1) return SCPE_ARG; /* must be even */ + for (i = 0; i < LINE_LNT; i = i + 2) { + c = ((val[i] & DIGIT) << 4) | (val[i + 1] & DIGIT); + if (alp_to_cdp[c] < 0) break; + fprintf (of, "%c", alp_to_cdp[c]); } + if (i == 0) { + fprintf (of, "<%02X>", c); + return -1; } + return -(i - 1); } +if ((sw & SWMASK ('M')) == 0) return SCPE_ARG; + +if (addr & 1) return SCPE_ARG; /* must be even */ +op = ((val[0] & DIGIT) * 10) + (val[1] & DIGIT); /* get opcode */ +for (i = qv = pmp = qmp = 0; i < ADDR_LEN; i++) { /* test addr */ + if (val[I_P + i]) pmp = 1; + if (val[I_Q + i]) qmp = 1; + qv = (qv * 10) + (val[I_Q + i] & DIGIT); } +if ((val[0] | val[1]) & FLAG) pmp = qmp = 1; /* flags force */ +for (i = 0; opcode[i].str != NULL; i++) { /* find opcode */ + opfl = opcode[i].opv & 0xFF0000; + if ((op == (opcode[i].opv & 0xFF)) && + ((qv == opcode[i].qv) || + ((opfl != I_1E) && (opfl != I_0E)))) break; } +if (opcode[i].str == NULL) return SCPE_ARG; +if (I_GETQP (opfl) == I_M_QNP) qmp = 0; /* Q no print? */ + +fprintf (of, opcode[i].str); /* print opcode */ +if (I_GETPP (opfl) == I_M_PP) /* P required? */ + fprint_addr (of, ' ', &val[I_P], I_M_QX); +else if ((I_GETPP (opfl) == I_M_PCP) && (pmp || qmp)) /* P opt & needed? */ + fprint_addr (of, ' ', &val[I_P], 0); +if (I_GETQP (opfl) == I_M_QP) { /* Q required? */ + fprint_addr (of, ',', &val[I_Q], I_GETQF (opfl)); + if (I_GETQF (opfl) & I_M_QM) /* immediate? */ + val[I_Q] = val[I_Q] & ~FLAG; } /* clr hi Q flag */ +else if ((I_GETQP (opfl) == I_M_QCP) && (pmp || qmp)) /* Q opt & needed? */ + fprint_addr (of, ',', &val[I_Q], 0); +for (i = any = 0; i < INST_LEN; i++) { /* print rem flags */ + if (val[i] & FLAG) { + if (!any) fputc (',', of); + any = 1; + fprintf (of, "%d", i); } } +return -(INST_LEN - 1); +} + +/* parse_addr - get sign + address + index */ + +t_stat parse_addr (char *cptr, t_value *val, int32 flg) +{ +int32 i, sign = 0, addr, index; +static int32 idx_tst[ADDR_LEN] = { 0, 4, 2, 1, 0 }; +char *tptr; + +if (*cptr == '+') cptr++; /* +? skip */ +else if (*cptr == '-') { /* -? skip, flag */ + sign = 1; + cptr++; } +errno = 0; /* get address */ +addr = strtoul (cptr, &tptr, 16); +if (errno || (cptr == tptr) || (addr > 0xFFFFF)) /* err or too big? */ + return SCPE_ARG; +if ((cpu_unit.flags & IF_IDX) && (flg & I_M_QX) && /* index allowed? */ + (*tptr == '(')) { /* index specified */ + errno = 0; + index = strtoul (cptr = tptr + 1, &tptr, 10); /* get index */ + if (errno || (cptr == tptr) || (index > 7)) /* err or too big? */ + return SCPE_ARG; + if (*tptr++ != ')') return SCPE_ARG; } +else index = 0; +if (*tptr != 0) return SCPE_ARG; /* all done? */ +for (i = ADDR_LEN - 1; i >= 0; i--) { /* cvt addr to dig */ + val[i] = (addr & 0xF) | ((index & idx_tst[i])? FLAG: 0); + addr = addr >> 4; } +if (sign) val[ADDR_LEN - 1] = val[ADDR_LEN - 1] | FLAG; /* set sign */ +if (flg & I_M_QM) val[0] = val[0] | FLAG; /* set immediate */ +return SCPE_OK; +} + +/* Symbolic input + + Inputs: + *cptr = pointer to input string + addr = current PC + *uptr = pointer to unit + *val = pointer to output values + sw = switches + Outputs: + status = > 0 error code + <= 0 -number of extra words +*/ + +t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) +{ +int32 i, qv, opfl, last; +char t, la, *fptr, gbuf[CBUFSIZE]; + +while (isspace (*cptr)) cptr++; /* absorb spaces */ +if ((sw & SWMASK ('C')) || ((*cptr == '\'') && cptr++)) { /* character? */ + if ((t = *cptr & 0x7F) == 0) return SCPE_ARG; /* get char */ + if (uptr->flags & UNIT_BCD) { /* BCD? */ + if (addr & 1) return SCPE_ARG; + t = cdr_to_alp[t]; /* convert */ + if (t < 0) return SCPE_ARG; /* invalid? */ + val[0] = (t >> 4) & DIGIT; /* store */ + val[1] = t & DIGIT; + return -1; } + else val[0] = t; /* store ASCII */ + return SCPE_OK; } + +if ((uptr->flags & UNIT_BCD) == 0) return SCPE_ARG; /* CPU or disk? */ +if ((sw & SWMASK ('S')) || ((*cptr == '"') && cptr++)) { /* string? */ + if (addr & 1) return SCPE_ARG; /* must be even */ + for (i = 0; (i < sim_emax) && (*cptr != 0); i = i + 2) { + t = *cptr++ & 0x7F; /* get character */ + t = cdr_to_alp[t]; /* convert */ + if (t < 0) return SCPE_ARG; /* invalid? */ + val[i] = (t >> 4) & DIGIT; /* store */ + val[i + 1] = t & DIGIT; } + if (i == 0) return SCPE_ARG; /* final check */ + return -(i - 1); } + +if (addr & 1) return SCPE_ARG; /* even addr? */ +cptr = get_glyph (cptr, gbuf, 0); /* get opcode */ +for (i = 0; opcode[i].str != NULL; i++) { /* look it up */ + if (strcmp (gbuf, opcode[i].str) == 0) break; } +if (opcode[i].str == NULL) return SCPE_ARG; /* successful? */ +opfl = opcode[i].opv & 0xFF0000; /* get flags */ +val[0] = (opcode[i].opv & 0xFF) / 10; /* store opcode */ +val[1] = (opcode[i].opv & 0xFF) % 10; +qv = opcode[i].qv; +for (i = ADDR_LEN - 1; i >= 0; i--) { /* set P,Q fields */ + val[I_P + i] = 0; + val[I_Q + i] = qv % 10; + qv = qv /10; } + +cptr = get_glyph (cptr, gbuf, ','); /* get P field */ +if (gbuf[0]) { /* any? */ + if (parse_addr (gbuf, &val[I_P], (I_GETPP (opfl)? + I_M_QX: 0))) return SCPE_ARG; } +else if (I_GETPP (opfl) == I_M_PP) return SCPE_ARG; + +if (I_GETQP (opfl) != I_M_QNP) { /* Q field allowed? */ + cptr = get_glyph (cptr, gbuf, ','); /* get Q field */ + if (gbuf[0]) { /* any? */ + if (parse_addr (gbuf, &val[I_Q], I_GETQF (opfl))) + return SCPE_ARG; } + else if (I_GETQP (opfl) == I_M_QP) return SCPE_ARG; } + +cptr = get_glyph (cptr, fptr = gbuf, ' '); /* get flag field */ +last = -1; /* none yet */ +while (t = *fptr++) { /* loop through */ + if ((t < '0') || (t > '9')) return SCPE_ARG; /* must be digit */ + t = t - '0'; /* convert */ + if (t == 1) { /* ambiguous? */ + la = *fptr++; /* get next */ + if (la == '0') t = 10; /* 10? */ + else if ((la == '1') && (*fptr == 0)) t = 11; /* 11 & end field? */ + else --fptr; } /* dont lookahead */ + if (t <= last) return SCPE_ARG; /* in order? */ + val[t] = val[t] | FLAG; /* set flag */ + last = t; } /* continue */ + +if (*cptr != 0) return SCPE_ARG; +return -(INST_LEN - 1); +} diff --git a/I1620/i1620_tty.c b/I1620/i1620_tty.c new file mode 100644 index 00000000..5520968a --- /dev/null +++ b/I1620/i1620_tty.c @@ -0,0 +1,345 @@ +/* i1620_tty.c: IBM 1620 typewriter + + Copyright (c) 2002, Robert M. Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + tty console typewriter +*/ + +#include "i1620_defs.h" + +#define TTO_COLMAX 80 + +int32 tto_col = 0; + +extern uint8 M[MAXMEMSIZE]; +extern uint8 ind[NUM_IND]; +extern UNIT cpu_unit; +extern uint32 io_stop; + +void tti_unlock (void); +t_stat tti_rnum (int8 *c); +t_stat tti_ralp (int8 *c); +t_stat tti_read (int8 *c); +t_stat tto_num (uint32 pa, uint32 len); +t_stat tto_write (uint32 c); +t_stat tty_svc (UNIT *uptr); +t_stat tty_reset (DEVICE *dptr); + +/* TTY data structures + + tty_dev TTY device descriptor + tty_unit TTY unit descriptor + tty_reg TTY register list +*/ + +UNIT tty_unit = { UDATA (&tty_svc, 0, 0), KBD_POLL_WAIT }; + +REG tty_reg[] = { + { DRDATA (COL, tto_col, 7) }, + { DRDATA (TIME, tty_unit.wait, 24), REG_NZ + PV_LEFT }, + { NULL } }; + +DEVICE tty_dev = { + "TTY", &tty_unit, tty_reg, NULL, + 1, 10, 31, 1, 8, 7, + NULL, NULL, &tty_reset, + NULL, NULL, NULL }; + +/* Data tables */ + +/* Keyboard to numeric */ + +const char *tti_to_num = "0123456789'=@:;\""; + +/* Keyboard to alphameric (digit pair) - translates LC to UC */ + +const int8 tti_to_alp[128] = { + -1, -1, -1, -1, -1, -1, -1, -1, /* 00 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* 10 */ + -1, -1, -1, -1, -1, -1, -1, -1, + 0x00, 0x02, 0x0F, -1, 0x13, -1, -1, -1, /* !"#$%&' */ + 0x24, 0x04, 0x14, 0x10, 0x23, 0x20, 0x03, 0x21, /* ()*+,-./ */ + 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 01234567 */ + 0x78, 0x79, -1, -1, -1, 0x33, -1, -1, /* 89:;<=>? */ + 0x34, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* @ABCDEFG */ + 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* HIJKLMNO */ + 0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* PQRSTUVW */ + 0x67, 0x68, 0x69, -1, -1, -1, -1, -1, /* XYZ[\]^_ */ + -1, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* abcdefg */ + 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* hijklmno */ + 0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* pqrstuvw */ + 0x67, 0x68, 0x69, -1, -1, -1, -1, -1 }; /* xyz */ + +/* Numeric (digit) to typewriter */ + +const char num_to_tto[16] = { + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', '\'', '=', '@', ':', ';', '"' }; + +/* Alphameric (digit pair) to typewriter */ + +const char alp_to_tto[256] = { + ' ', -1, '?', '.', ')', -1, -1, -1, /* 00 */ + -1, -1, -1, -1, -1, -1, -1, -1, + '+', -1, '!', '$', '*', ' ', -1, -1, /* 10 */ + -1, -1, -1, -1, -1, -1, -1, -1, + '-', '/', '\'', ',', '(', -1, -1, -1, /* 20 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, '0', '=', '@', ':', -1, -1, /* 30 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 40 */ + 'H', 'I', -1, -1, -1, -1, -1, -1, + '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 50 */ + 'Q', 'R', -1, -1, -1, -1, -1, -1, + -1, '/', 'S', 'T', 'U', 'V', 'W', 'X', /* 60 */ + 'Y', 'Z', -1, -1, -1, -1, -1, -1, + '0', '1', '2', '3', '4', '5', '6', '7', /* 70 */ + '8', '9', -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* 90 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* A0 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* B0 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* C0 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* D0 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* E0 */ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, /* F0 */ + -1, -1, -1, -1, -1, -1, -1, -1 }; + +/* Terminal IO + + - On input, parity errors cannot occur. + - On input, release-start does NOT cause a record mark to be stored. + - On output, invalid characters type an invalid character and set WRCHK. + If IO stop is set, the system halts at the end of the operation. +*/ + +t_stat tty (uint32 op, uint32 pa, uint32 f0, uint32 f1) +{ +t_addr i; +uint8 d; +int8 ttc; +t_stat r, inv = SCPE_OK; + +switch (op) { /* case on op */ +case OP_K: /* control */ + switch (f1) { /* case on control */ + case 1: /* space */ + tto_write (' '); + break; + case 2: /* return */ + tto_write ('\r'); + break; + case 3: /* backspace */ + if ((cpu_unit.flags & IF_MII) == 0) return STOP_INVFNC; + tto_write ('\b'); + break; + case 4: /* index */ + if ((cpu_unit.flags & IF_MII) == 0) return STOP_INVFNC; + tto_write ('\n'); + break; + case 8: /* tab */ + tto_write ('\t'); + break; + default: + return STOP_INVFNC; } + return SCPE_OK; +case OP_RN: /* read numeric */ + tti_unlock (); /* unlock keyboard */ + for (i = 0; i < MEMSIZE; i++) { /* (stop runaway) */ + r = tti_rnum (&ttc); /* read char */ + if (r != SCPE_OK) return r; /* error? */ + if (ttc == 0x7F) return SCPE_OK; /* end record? */ + M[pa] = ttc & (FLAG | DIGIT); /* store char */ + PP (pa); } /* incr mem addr */ + break; +case OP_RA: /* read alphameric */ + tti_unlock (); + for (i = 0; i < MEMSIZE; i = i + 2) { /* (stop runaway) */ + r = tti_ralp (&ttc); /* read char */ + if (r != SCPE_OK) return r; /* error? */ + if (ttc == 0x7F) return SCPE_OK; /* end record? */ + M[pa] = (M[pa] & FLAG) | (ttc & DIGIT); /* store 2 digits */ + M[pa - 1] = (M[pa - 1] & FLAG) | ((ttc >> 4) & DIGIT); + pa = ADDR_A (pa, 2); } /* incr mem addr */ + break; +case OP_DN: + return tto_num (pa, 20000 - (pa % 20000)); /* dump numeric */ +case OP_WN: + return tto_num (pa, 0); /* type numeric */ +case OP_WA: + for (i = 0; i < MEMSIZE; i = i + 2) { /* stop runaway */ + d = M[pa] & DIGIT; /* get digit */ + if ((d & 0xA) == REC_MARK) /* 8-2 char? */ + CRETIOE (io_stop, inv); /* end record */ + d = ((M[pa - 1] & DIGIT) << 4) | d; /* get digit pair */ + ttc = alp_to_tto[d]; /* translate */ + if (ttc < 0) { /* bad char? */ + ind[IN_WRCHK] = 1; /* set write check */ + inv = STOP_INVCHR; } /* set return status */ + tto_write (ttc & 0x7F); /* write */ + pa = ADDR_A (pa, 2); } /* incr mem addr */ + break; +default: /* invalid function */ + return STOP_INVFNC; } +return STOP_RWRAP; +} + +/* Read numerically - cannot generate parity errors */ + +t_stat tti_rnum (int8 *c) +{ +int8 flg = 0; +char *cp, raw; +t_stat r; + +*c = -1; /* no char yet */ +do { r = tti_read (&raw); /* get char */ + if (r != SCPE_OK) return r; /* error? */ + if (raw == '\r') *c = 0x7F; /* return? mark */ + else if (raw == '~') flg = FLAG; /* flag? mark */ + else if (cp = strchr (tti_to_num, raw)) /* legal? */ + *c = ((int8) (cp - tti_to_num)) | flg; /* assemble char */ + else raw = 007; /* beep! */ + tto_write (raw); } /* echo */ +while (*c == -1); +return SCPE_OK; +} + +/* Read alphamerically - cannot generate parity errors */ + +t_stat tti_ralp (int8 *c) +{ +char raw; +t_stat r; + +*c = -1; /* no char yet */ +do { r = tti_read (&raw); /* get char */ + if (r != SCPE_OK) return r; /* error? */ + if (raw == '\r') *c = 0x7F; /* return? mark */ + else if (tti_to_alp[raw] >= 0) /* legal char? */ + *c = tti_to_alp[raw]; /* xlate */ + else raw = 007; /* beep! */ + tto_write (raw); } /* echo */ +while (*c == -1); +return SCPE_OK; +} + +/* Read from keyboard */ + +t_stat tti_read (int8 *c) +{ +int32 t; + +do { t = sim_poll_kbd (); } /* get character */ +while (t == SCPE_OK); +if (t < SCPE_KFLAG) return t; /* error? */ +*c = t & 0177; /* store character */ +return SCPE_OK; +} + +/* Write numerically - cannot generate parity errors */ + +t_stat tto_num (uint32 pa, uint32 len) +{ +t_stat r; +uint8 d; +uint32 i, end; + +end = pa + len; +for (i = 0; i < MEMSIZE; i++) { /* (stop runaway) */ + d = M[pa]; /* get char */ + if (len? (pa >= end): /* dump: end reached? */ + ((d & REC_MARK) == REC_MARK)) /* write: rec mark? */ + return SCPE_OK; /* end operation */ + if (d & FLAG) tto_write ('~'); /* flag? */ + r = tto_write (num_to_tto[d & DIGIT]); /* write */ + if (r != SCPE_OK) return r; /* error? */ + PP (pa); } /* incr mem addr */ +return STOP_RWRAP; +} + +/* Write, maintaining position */ + +t_stat tto_write (uint32 c) +{ +int32 rpt; + +if (c == '\t') { /* tab? */ + rpt = 8 - (tto_col % 8); /* distance to next */ + tto_col = tto_col + rpt; /* tab over */ + while (rpt-- > 0) sim_putchar (' '); /* use spaces */ + return SCPE_OK; } +if (c == '\r') { /* return? */ + sim_putchar ('\r'); /* crlf */ + sim_putchar ('\n'); + tto_col = 0; /* clear colcnt */ + return SCPE_OK; } +if ((c == '\n') || (c == 007)) { /* non-spacing? */ + sim_putchar (c); + return SCPE_OK; } +if (c == '\b') tto_col = tto_col? tto_col - 1: 0; /* backspace? */ +else tto_col++; /* normal */ +if (tto_col > TTO_COLMAX) { /* line wrap? */ + sim_putchar ('\r'); + sim_putchar ('\n'); + tto_col = 0; } +sim_putchar (c); +return SCPE_OK; +} + +/* Unit service - polls for WRU */ + +t_stat tty_svc (UNIT *uptr) +{ +int32 temp; + +sim_activate (&tty_unit, tty_unit.wait); /* continue poll */ +if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */ +return SCPE_OK; +} + +/* Reset routine */ + +t_stat tty_reset (DEVICE *dptr) +{ +sim_activate (&tty_unit, tty_unit.wait); /* activate poll */ +tto_col = 0; +return SCPE_OK; +} + +/* TTI unlock - signals that we are ready for keyboard input */ + +void tti_unlock (void) +{ +tto_write ('`'); +return; +} diff --git a/Ibm1130/asm1130.c b/Ibm1130/asm1130.c new file mode 100644 index 00000000..4c35dee2 --- /dev/null +++ b/Ibm1130/asm1130.c @@ -0,0 +1,4496 @@ +/* + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org + */ + +// --------------------------------------------------------------------------------- +// ASM1130 - IBM 1130 Cross Assembler +// +// Version +// 1.06 - 2002May02 - Fixed bug in ebdic constants (data goes into low byte) +// First stab at adding ISS level # info, this is iffy +// 1.05 - 2002Apr24 - Made negative BSS size a warning not an error, as it +// it's looking like it happens twice in PTMASMBL. +// This version still doesn't do fixed point numbers and +// negative floats may be wrong. +// 1.04 - 2002Apr18 - Added binary (card loader format) output, removed +// interim IPL output formats and moved that to MKBOOT. +// Enhanced relocatable code handling. Added floating +// point constants, but don't know how to make fixed point +// constants yet. Made amenable to syntax variations found +// in the DMS sources. Doesn't properly handle ILS +// modules yet and ISS is probably wrong. +// 1.03 - 2002Apr10 - numerous fixes, began to add relative/absolute support +// 1.02 - 2002Feb26 - replaced "strupr" with "upcase" for compatibility +// 1.01 - 2002Feb25 - minor compiler compatibility changes +// 1.00 - 2002Feb01 - first release. Tested only under Win32. +// --------------------------------------------------------------------------------- +// +// Usage: +// asm1130 [-bvsx] [-o[file]] [-l[file]] [-rN.M] file... +// +// Description: +// -b binary output (.bin, relocatable absolute format) +// -v verbose +// -s print symbol table +// -x print cross references +// -o output file (default is name of first source file + extension .out or .bin) +// -l listing file (default is name of first source file + extension .lst) +// -y preload system symbol table SYMBOLS.SYS (from the current directory) +// -w write the system symbol table SYMBOLS.SYS in the current directory +// -W same as -w but don't prompt to confirm overwriting existing file +// -r set DMS release to release N version M, for sbrk cards +// +// Listing and symbol table output can be turned on by *LIST directives in the source, too +// Listing file default extension is .LST +// +// Input files can use strict IBM 1130 Assembler column format, or loose formatting +// with tabs, or any mix on a line-by-line basis. Input files default extension is .ASM. +// +// Strict specification is: +// +// label columns 1 - 5 +// opcode 7 - 10 +// tag 12 +// index 13 +// arguments 15 - 51 +// +// Loose, indicated by presence of ascii tab character(s): +// +// labelopcodeindex and format indicatorsarguments +// +// In both cases, the IBM convention that the arguments section ends with the +// first nonblank applies. This means that ".DC 1, 2, 3" assembles only the 1! +// +// Output file format is that used by the LOAD command in my 1130 +// simulator. Lines are any of the following. All values are in hex: +// +// @addr load address for subsequent words is addr +// Znwords Zero the next "nwords" and increment load address by nwords. +// =addr set IAR register to address addr (a convenience) +// value load value at load address and increment load address +// +// Output file default extension is .OUT or .BIN for binary assemblies +// +// Note: this version does not handle relative assembly, and so doesn't carry +// absolute/relative indication through expression calculation. +// +// Seems to work. Was able to assemble the resident monitor OK. +// >>> Look for "bug here" though, for things to check out. +// +// Notes: +// org_advanced tells whether * in an expression refers to the address AFTER the +// instruction (1 or 2 words, depending on length). This is the case for opcodes +// but not all directives. +// +// Added special coldstart format directives: +// +// .IPL 1130,XXXXXXXX +// .IPL 1800,XXXXXXXX +// +// (these are not standard IBM) +// +// These directives cause the output file to be written in binary in either 1130 or +// 1800 IPL format. In 1130 format, the index bits are lost and the displacement +// is sign extended. In 1800 format, the data are punched 8 bits at a time into +// two columns per word. If an identifier is not given, data are punched into +// all 80 columns. If an identifier is given, data is punched in columns 0 through +// 72, and the identification XXXXXXXX is punched in columns 73 through 80. (If +// there are multiple output cards the last ident character is incremented). A +// warning is issued if 1130 assembly results in lost bits. These directives +// should be the first in the file as you don't want text and binary mixed in +// the same output file. +// +// Revision History +// 16Apr02 1.03 Added sector break, relocation flag output +// 02Apr02 1.02 Fixed bug in BOSC: it CAN be a short instruction. +// Added directives for 1130 and 1800 IPL output formats +// Added conditional assembly directives +// --------------------------------------------------------------------------------- + +#include +#include +#include +#include +#include +#include +#include + +// ---------------------------------------------------------------1------------------ +// DEFINITIONS +// --------------------------------------------------------------------------------- + +// I have found some IBM source code where @ and ' seem interchangable. +// Comment out this define to make @ and ' different in symbol names, keep to make equivalent + +#if defined(VMS) + # include /* to pick up 'unlink' */ +#endif + +#define BETWEEN(v,a,b) (((v) >= (a)) && ((v) <= (b))) +#define MIN(a,b) (((a) <= (b)) ? (a) : (b)) +#define MAX(a,b) (((a) >= (b)) ? (a) : (b)) + +#ifndef WIN32 + int strnicmp (char *a, char *b, int n); + int strcmpi (char *a, char *b); +#endif + +#define FIX_ATS + +#define DMSVERSION "V2M12" /* required 5 characters on sector break card col 67-71 */ + +#define DOLLAREXIT "/38" // hmmm, are these really fixed absolutely in all versions? +#define DOLLARDUMP "/3F" + +#define SYSTEM_TABLE "SYMBOLS.SYS" + +#define BOOL int +#define TRUE 1 +#define FALSE 0 + +#define VERSION "ASM1130 CROSS ASSEMBLER V1.06" + +#define ISTV 0x33 // magic number from DMS R2V12 monitorm symbol @ISTV + +#define MAXLITERALS 300 +#define MAXENTRIES 14 + +#define LINEFORMAT " %4ld | %s" +#define LEFT_MARGIN " |" + // XXXX XXXX XXXX XXXX XXXX XXXX + // org w1 w2 w3 w4 w5 + // XXXX 1111 2222 3333 4444 LLLL | + // 12345678901234567890123456789012 + +typedef enum {ABSOLUTE = 0, RELATIVE = 1, LIBF = 2, CALL = 3} RELOC; + +typedef struct tag_symbol { // symbol table entry: + char *name; // name of symbol + int value; // value (absolute) + int pass; // defined during pass # + int defined; // definition state, see #defines below + RELOC relative; // ABSOLUTE = absolute, RELATIVE = relative + struct tag_symbol *next; // next symbol in list + struct tag_xref *xrefs; // cross references +} SYMBOL, *PSYMBOL; + +#define S_UNDEFINED 0 // values of 'defined' +#define S_PROVISIONAL 1 // usually an expression with forward references +#define S_DEFINED 2 // ordering must be undef < prov < def + +typedef struct tag_xref { // cross reference entry + char *fname; // filename + int lno; // line number + BOOL definition; // true = definition, false = reference + struct tag_xref *next; // next reference +} XREF, *PXREF; + +typedef struct tag_expr { // expression result: absolute or relative + int value; + RELOC relative; +} EXPR; + +typedef enum {PROGTYPE_ABSOLUTE = 1, PROGTYPE_RELOCATABLE = 2, PROGTYPE_LIBF = 3, PROGTYPE_CALL = 4, + PROGTYPE_ISSLIBF = 5, PROGTYPE_ISSCALL = 6, PROGTYPE_ILS = 7} PROGTYPE; + +typedef enum {SUBTYPE_INCORE = 0, SUBTYPE_FORDISK = 1, SUBTYPE_ARITH = 2, + SUBTYPE_FORNONDISK = 3, SUBTYPE_FUNCTION=8} SUBTYPE; + +typedef enum {INTMODE_UNSPECIFIED = 0, INTMODE_MATCHREAL = 0x0080, INTMODE_ONEWORD = 0x0090} INTMODE; +typedef enum {REALMODE_UNSPECIFIED = 0, REALMODE_STANDARD = 0x0001, REALMODE_EXTENDED = 0x0002} REALMODE; + +#define OP_INDEXED 0x0300 // 1130 opcode modifier bits +#define OP_LONG 0x0400 +#define OP_INDIRECT 0x0080 + +typedef enum {OUTMODE_LOAD, OUTMODE_1130, OUTMODE_1800, OUTMODE_BINARY} OUTMODE; + +#ifdef WIN32 +# define OUTWRITEMODE "wb" // write outfile in binary mode +# define ENDLINE "\r\n" // explictly write CR/LF +#else +# define OUTWRITEMODE "w" // use native mode +# define ENDLINE "\n" +#endif + +// --------------------------------------------------------------------------------- +// GLOBALS +// --------------------------------------------------------------------------------- + +// command line syntax +char *usestr = +"Usage: asm1130 [-bpsvwxy] [-o[file]] [-l[file]] [-rN.M] file...\n\n" +"-b binary (relocatable format) output; default is simulator LOAD format\n" +"-p count passes required; no assembly output is created with this flag" +"-s add symbol table to listing\n" +"-v verbose mode\n" +"-w write system symbol table as SYMBOLS.SYS\n" +"-W same as -w but do not confirm overwriting previous file\n" +"-x add cross reference table to listing\n" +"-y preload system symbol table SYMBOLS.SYS\n" +"-o set output file; default is first input file + .out or .bin\n" +"-l create listing file; default is first input file + .lst\n" +"-r set dms version to VN RM for system SBRK cards"; + +BOOL verbose = FALSE; // verbose mode flag +BOOL tabformat = FALSE; // TRUE if tabs were seen in the file +int pass; // current assembler pass (1 or 2) +char curfn[256]; // current input file name +char progname[8]; // base name of primary input file +char *outfn = NULL; // output file name +int lno; // current input file line number +BOOL preload = FALSE; // preload system symbol table +BOOL savetable = FALSE; // write system symbol table +BOOL saveprompt = TRUE; // prompt before overwriting +int nerrors = 0; // count of errors +int nwarnings = 0; // count of warnings +FILE *fin = NULL; // current input file +FILE *fout = NULL; // output file stream +OUTMODE outmode = OUTMODE_LOAD; // output file mode +int outcols = 0; // columns written in using card output +int maxiplcols = 80; +char cardid[9]; // characters used for IPL card ID +FILE *flist = NULL; // listing file stream +char *listfn = NULL; // listing filename +BOOL do_list = FALSE; // flag: create listing +BOOL passcount = FALSE; // flag: count passes only +BOOL list_on = TRUE; // listing is currently enabled +BOOL do_xref = FALSE; // cross reference listing +BOOL do_syms = FALSE; // symbol table listing +BOOL ended = FALSE; // end of current file +BOOL hasforward = FALSE; // true if there are any forward references +char listline[350]; // output listing line +BOOL line_error; // already saw an error on current line +RELOC relocate = RELATIVE; // relocatable assembly mode +BOOL assembled = FALSE; // true if any output has been generated +int nwout; // number of words written on current line +int org = 0; // output address (origin) +int org_advanced; // if TRUE, * means instruction addr+(value) during evaluation +int pta = -1; // program transfer address +BOOL cexpr = FALSE; // "C" expression syntax +PSYMBOL symbols = NULL; // the symbol table (linear search) +BOOL check_control = TRUE; // check for control cards +PROGTYPE progtype = PROGTYPE_RELOCATABLE; // program type +INTMODE intmode = INTMODE_UNSPECIFIED; // integer mode +REALMODE realmode = REALMODE_UNSPECIFIED; // real mode +int nintlevels = 0; // # of interrupt levels for ISS +int intlevel_primary = 0; // primary level for ISS and level for ILS +int intlevel_secondary = 0; // secondary level for ISS +int iss_number = 0; // ISS number +PSYMBOL entry[MAXENTRIES]; // entries for subroutines +int nentries = 0; +int ndefined_files = 0; + +struct lit { // accumulated literals waiting to be output + int value; // constant value + int tagno; // constant symbol tag number (e.g. _L001) + BOOL hex; // constant was expressed in hex + BOOL even; // constant was operand of a double-width instruction (e.g. AD) +} literal[MAXLITERALS]; + +int n_literals = 0, lit_tag = 0; +BOOL requires_even_address; // target of current instruction +BOOL dmes_saved; // odd character left over from dmes ending in ' +int dmes_savew; +char opfield[256]; // extracted operand field from source line +char dmsversion[12] = DMSVERSION; // version number for SBRK cards +const char whitespace[] = " \t"; // whitespace + +int ascii_to_ebcdic_table[128] = +{ +// + 0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f, 0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f, +// + 0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26, 0x18,0x19,0x3f,0x27,0x1c,0x1d,0x1e,0x1f, +// spac ! " # $ % & ' ( ) * + , - . / + 0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d, 0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61, +// 0 1 2 3 4 5 6 7 8 9 : ; < = > ? + 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, 0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f, +// @ A B C D E F G H I J K L M N O + 0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, 0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6, +// P Q R S T U V W X Y Z [ \ ] & _ + 0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6, 0xe7,0xe8,0xe9,0xba,0xe0,0xbb,0xb0,0x6d, +// a b c d e f g h i j k l m n o + 0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87, 0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96, +// p q r s t u v w x y z { | } ~ + 0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6, 0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07, +}; + +int ascii_to_1403_table[128] = +{ /* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f */ + 0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f, 0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f, + 0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f, 0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f,0x7f, + 0x7f,0x7f,0x7f,0x7f,0x62,0x7f,0x15,0x0b, 0x57,0x2f,0x23,0x6d,0x16,0x61,0x6e,0x4c, + 0x49,0x40,0x01,0x02,0x43,0x04,0x45,0x46, 0x07,0x08,0x7f,0x7f,0x7f,0x4a,0x7f,0x7f, + 0x7f,0x64,0x25,0x26,0x67,0x68,0x29,0x2a, 0x6b,0x2c,0x58,0x19,0x1a,0x5b,0x1c,0x5d, + 0x5e,0x1f,0x20,0x0d,0x0e,0x4f,0x10,0x51, 0x52,0x13,0x54,0x7f,0x7f,0x7f,0x7f,0x7f, + 0x7f,0x64,0x25,0x26,0x67,0x68,0x29,0x2a, 0x6b,0x2c,0x58,0x19,0x1a,0x5b,0x1c,0x5d, + 0x5e,0x1f,0x20,0x0d,0x0e,0x4f,0x10,0x51, 0x52,0x13,0x54,0x7f,0x7f,0x7f,0x7f,0x7f +}; + +#include "../ibm1130_conout.h" /* conout_to_ascii_table */ +#include "../ibm1130_prtwheel.h" /* 1132 printer printwheel data */ + +// --------------------------------------------------------------------------------- +// PROTOTYPES +// --------------------------------------------------------------------------------- + +void bail (char *msg); +void flag (char *arg); +void proc (char *fname); +void startpass (int n); +void errprintf (char *fmt, ...); +void asm_error (char *fmt, ...); +void asm_warning (char *fmt, ...); +char *astring (char *str); +PSYMBOL lookup_symbol (char *name, BOOL define); +void add_xref (PSYMBOL s, BOOL definition); +int get_symbol (char *name); +void set_symbol (char *name, int value, int known, RELOC relative); +char * gtok (char **pc, char *tok); +char *skipbl (char *c); +void sym_list (void); +void xref_list (void); +void listhdr (void); +int getexpr (char *pc, BOOL undefined_ok, EXPR *expr); +void passreport (void); +void listout (BOOL reset); +void output_literals (BOOL eof); +char *upcase (char *str); +void prep_line (char *line); +int ascii_to_hollerith (int ch); +char *detab (char *str); +void preload_symbols (void); +void save_symbols (void); +void bincard_init (void); +void bincard_writecard (char *sbrk_text); +void bincard_writedata (void); +void bincard_flush (void); +void bincard_sbrk (char *line); +void bincard_setorg (int neworg); +void bincard_writew (int word, RELOC relative); +void bincard_endcard (void); +void handle_sbrk (char *line); +void bincard_typecard (void); +void namecode (unsigned short *words, char *tok); + +// --------------------------------------------------------------------------------- +// main routine +// --------------------------------------------------------------------------------- + +int main (int argc, char **argv) +{ + int i, sawfile = FALSE; + + for (i = 1; i < argc; i++) // process command line switches + if (*argv[i] == '-') + flag(argv[i]+1); + + startpass(1); // first pass, process files + + for (i = 1; i < argc; i++) + if (*argv[i] != '-') + proc(argv[i]), sawfile = TRUE; + + if (! sawfile) // should have seen at least one file + bail(usestr); + + if (passcount) { + passreport(); + return 0; + } + + startpass(2); // second pass, process files again + + for (i = 1; i < argc; i++) + if (*argv[i] != '-') + proc(argv[i]); + + if (outmode == OUTMODE_LOAD) { + if (pta >= 0) // write start address to the load file + fprintf(fout, "=%04x" ENDLINE, pta & 0xFFFF); + } + else + bincard_endcard(); + + if (flist) { + if (nerrors || nwarnings) { // summarize (or summarise) + if (nerrors == 0) + fprintf(flist, "There %s ", (nwarnings == 1) ? "was" : "were"); + else + fprintf(flist, "\nThere %s %d error%s %s", + (nerrors == 1) ? "was" : "were", nerrors, (nerrors == 1) ? "" : "s", nwarnings ? "and " : ""); + + if (nwarnings > 0) + fprintf(flist, "%d warning%s ", nwarnings, (nwarnings == 1) ? "" : "s"); + + fprintf(flist, "in this assembly\n"); + } + else + fprintf(flist, "\nThere were no errors in this assembly\n"); + } + + if (flist) { // finish the listing + if (pta >= 0) + fprintf(flist, "\nProgram transfer address = %04x\n", pta); + + if (do_xref) + xref_list(); + else if (do_syms) + sym_list(); + } + + if (savetable) + save_symbols(); + + return 0; // all done +} + +// --------------------------------------------------------------------------------- +// flag - process one command line switch +// --------------------------------------------------------------------------------- + +void flag (char *arg) +{ + int major, minor; + + while (*arg) { + switch (*arg++) { + case 'o': // output (load) file name + if (! *arg) + bail(usestr); + outfn = arg; + return; + + case 'p': + passcount = TRUE; + break; + + case 'v': // mumble while running + verbose = TRUE; + break; + + case 'x': // print cross reference table + do_xref = TRUE; + break; + + case 's': // print symbol table + do_syms = TRUE; + break; + + case 'l': // listing file name + listfn = (* arg) ? arg : NULL; + do_list = TRUE; + return; + + case 'W': + saveprompt = FALSE; + // fall through + case 'w': + savetable = TRUE; + break; + + case 'y': + preload = TRUE; + break; + + case 'b': + outmode = OUTMODE_BINARY; + break; + + case 'r': + if (sscanf(arg, "%d.%d", &major, &minor) != 2) + bail(usestr); + sprintf(dmsversion, "V%01.1dM%02.2d", major, minor); + return; + + default: + bail(usestr); + break; + } + } +} + +// --------------------------------------------------------------------------------- +// bail - print error message on stderr (only) and exit +// --------------------------------------------------------------------------------- + +void bail (char *msg) +{ + fprintf(stderr, "%s\n", msg); + exit(1); +} + +// --------------------------------------------------------------------------------- +// errprintf - print error message to stderr +// --------------------------------------------------------------------------------- + +void errprintf (char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); // get pointer to argument list + + vfprintf(stderr, fmt, args); // write errors to terminal (stderr) + + va_end(args); +} + +// --------------------------------------------------------------------------------- +// asm_error - report an error to listing file and to user's console +// --------------------------------------------------------------------------------- + +void asm_error (char *fmt, ...) +{ + va_list args; + + if (pass == 1) // only print on pass 2 + return; + + va_start(args, fmt); // get pointer to argument list + + fprintf(stderr, "E: %s (%d): ", curfn, lno); + vfprintf(stderr, fmt, args); // write errors to terminal (stderr) + putc('\n', stderr); + + if (flist != NULL && list_on) { + listout(FALSE); + line_error = TRUE; + + fprintf(flist, "**** Error: "); + vfprintf(flist, fmt, args); // write errors to listing file + putc('\n', flist); + } + + nerrors++; + va_end(args); +} + +// --------------------------------------------------------------------------------- +// asm_warning - same but warnings are not counted +// --------------------------------------------------------------------------------- + +void asm_warning (char *fmt, ...) +{ + va_list args; + + if (pass == 1) // only print on pass 2 + return; + + va_start(args, fmt); // get pointer to argument list + + fprintf(stderr, "W: %s (%d): ", curfn, lno); + vfprintf(stderr, fmt, args); // write errors to terminal (stderr) + putc('\n', stderr); + + if (flist != NULL && list_on) { + listout(FALSE); + line_error = TRUE; + + fprintf(flist, "**** Warning: "); + vfprintf(flist, fmt, args); // write errors to listing file + putc('\n', flist); + } + + nwarnings++; +} + +// --------------------------------------------------------------------------------- +// sym_list - print the symbol table +// --------------------------------------------------------------------------------- + +void sym_list (void) +{ + PSYMBOL s; + int n = 5; + + if (symbols == NULL || flist == NULL) + return; + + fprintf(flist, "\n=== SYMBOL TABLE ==============================================================\n"); + + for (s = symbols, n = 0; s != NULL; s = s->next) { + if (n >= 5) { + putc('\n', flist); + n = 0; + } + else if (n > 0) + fprintf(flist, " "); + + fprintf(flist, "%-6s ", s->name); + if (s->defined == S_DEFINED) + fprintf(flist, "%04x%s", s->value & 0xFFFF, s->relative ? "R" : " "); + else + fprintf(flist, "UUUU "); + + n++; + } + fprintf(flist, "\n"); +} + +// --------------------------------------------------------------------------------- +// passreport - report # of passes required for assembly on the 1130 +// --------------------------------------------------------------------------------- + +void passreport (void) +{ + PSYMBOL s; + + for (s = symbols; s != NULL; s = s->next) { + if (s->defined == S_UNDEFINED || s->defined == S_PROVISIONAL) { + printf("There are undefined symbols. Cannot determine pass requirement.\n"); + return; + } + } + + if (hasforward) + printf("There are forward references. Two passes are required.\n"); + else + printf("There are no forward references. Only one pass is required.\n"); +} + +// --------------------------------------------------------------------------------- +// xref_list - print the cross-reference table +// --------------------------------------------------------------------------------- + +void xref_list (void) +{ + int n = 0; + PXREF x; + PSYMBOL s; + + if (flist == NULL || symbols == NULL) + return; + + fprintf(flist, "\n=== CROSS REFERENCES ==========================================================\n"); + + if (symbols == NULL || flist == NULL) + return; + + fprintf(flist, "Name Val Defd Referenced\n"); + + for (s = symbols; s != NULL; s = s->next) { + fprintf(flist, "%-5s %04x%s", s->name, s->value & 0xFFFF, s->relative ? "R" : " "); + + for (x = s->xrefs; x != NULL; x = x->next) + if (x->definition) + break; + + if (x == NULL) + fprintf(flist, "----"); + else + fprintf(flist, " %4d", x->lno); + + for (n = 0, x = s->xrefs; x != NULL; x = x->next) { + if (x->definition) + continue; + + if (n >= 12) { + n = 0; + fprintf(flist, "\n "); + } + fprintf(flist, " %4d", x->lno); + n++; + } + putc('\n', flist); + } +} + +// --------------------------------------------------------------------------------- +// listhdr - print a banner header in the listing file. Since it's not paginated +// at this time, this is not used often. +// --------------------------------------------------------------------------------- + +void listhdr (void) +{ + time_t t; + + time(&t); + fprintf(flist, "%s -- %s -- %s\n", VERSION, dmsversion, ctime(&t)); +} + +// --------------------------------------------------------------------------------- +// astring - allocate a copy of a string +// --------------------------------------------------------------------------------- + +char *astring (char *str) +{ + static char *s = NULL; + + if (s != NULL) + if (strcmp(s, str) == 0) // if same as immediately previous allocation + return s; // return same pointer (why did I do this?) + + if ((s = malloc(strlen(str)+1)) == NULL) + bail("out of memory"); + + strcpy(s, str); + return s; +} + +// --------------------------------------------------------------------------------- +// lookup_symbol - get pointer to a symbol. +// If define is TRUE, creates and marks 'undefined' if not previously defined. +// --------------------------------------------------------------------------------- + +PSYMBOL lookup_symbol (char *name, BOOL define) +{ + PSYMBOL s, n, prv = NULL; + int c; + char *at; + + if (strlen(name) > 5) { // (sigh) + asm_error("Symbol '%s' is longer than 5 letters", name); + name[5] = '\0'; + } + +#ifdef FIX_ATS + while ((at = strchr(name, '@')) != NULL) + *at = '\''; +#endif + // search sorted list of symbols + for (s = symbols; s != NULL; prv = s, s = s->next) { + c = strcmpi(s->name, name); + if (c == 0) + return s; + if (c > 0) + break; + } + + if (! define) + return NULL; // not found + + if ((n = malloc(sizeof(SYMBOL))) == NULL) + bail("out of memory"); + + n->name = astring(name); // symbol was undefined -- add it now + n->value = 0; + n->defined = FALSE; + n->xrefs = NULL; + n->defined = FALSE; + + n->next = s; // link in alpha order + + if (prv == NULL) // we stopped before first item in list + symbols = n; + else + prv->next = n; // insert after item before place we stopped + + return n; +} + +// --------------------------------------------------------------------------------- +// add_xref - add a cross reference entry to a symbol +// --------------------------------------------------------------------------------- + +void add_xref (PSYMBOL s, BOOL definition) +{ + PXREF x, prv = NULL, n; + + if (pass == 1 || ! do_xref) // define only during 2nd pass and only if listing was requested + return; + + for (x = s->xrefs; x != NULL; prv = x, x = x->next) + if (strcmpi(x->fname, curfn) == 0 && x->lno == lno) + return; // ignore multiple refs on same line + + if ((n = malloc(sizeof(XREF))) == NULL) + bail("out of memory"); + + n->fname = astring(curfn); + n->lno = lno; + n->definition = definition; + + n->next = x; // link at end of existing list + + if (prv == NULL) + s->xrefs = n; + else + prv->next = n; +} + +// --------------------------------------------------------------------------------- +// get_symbol - get a symbol value, defining if necessary +// --------------------------------------------------------------------------------- + +int get_symbol (char *name) +{ + PSYMBOL s; + + s = lookup_symbol(name, TRUE); // lookup, define if necessary + + if (pass == 2) // should be defined by now + if (! s->defined) + asm_error("Symbol '%s' is undefined", name); + + add_xref(s, FALSE); // note the reference + + return s->value; +} + +// --------------------------------------------------------------------------------- +// set_symbol - set a symbol value. Known = TRUE means we really know the value; +// FALSE means we're calculating it with forward referenced values or something like +// that. +// --------------------------------------------------------------------------------- + +void set_symbol (char *name, int value, int known, RELOC relative) +{ + PSYMBOL s; + char *at; + + if (strlen(name) > 5) { + asm_error("Symbol '%s' is longer than 5 letters", name); + name[5] = '\0'; + } + +#ifdef FIX_ATS + while ((at = strchr(name, '@')) != NULL) + *at = '\''; +#endif + + s = lookup_symbol(name, TRUE); + + if (s->defined == S_DEFINED) // once defined, it should not change + if (s->value != value) + asm_error("Symbol '%s' %s", name, (s->pass == pass) ? "is multiply defined" : "changed between passes"); + + s->value = value; + s->relative = relative; + s->defined = known ? S_DEFINED : S_PROVISIONAL; + s->pass = pass; + + if (! known) + hasforward = TRUE; + + add_xref(s, TRUE); // record the place of definition +} + +// --------------------------------------------------------------------------------- +// skipbl - return pointer to first nonblank character in string s +// --------------------------------------------------------------------------------- + +char *skipbl (char *s) +{ + while (*s && *s <= ' ') + s++; + + return s; +} + +// --------------------------------------------------------------------------------- +// gtok - extracts a whitespace-delimited token from the string pointed to by *pc; +// stores the token into the buffer tok and returns pointer to same. Returns NULL +// when there are no tokens. Best to call repeatedly with a pointer to the source +// buffer, e.g. +// char *pbuf = buf; +// while (gtok(&pbuf, token) != NULL) ... +// --------------------------------------------------------------------------------- + +char * gtok (char **pc, char *tok) +{ + char *s = *pc, *otok = tok; + + while (*s && *s <= ' ') // skip blanks + s++; + + if (! *s) { // no tokens to be found + *tok = '\0'; + *pc = s; + return NULL; + } + + while (*s > ' ') // save nonblanks into 'tok' + *tok++ = *s++; + + *tok = '\0'; // terminate + *pc = s; // adjust caller's pointer + + return otok; // return pointer to token +} + +// listing format: +// +// ADDR CODE SOURCE +// 0000 0000 0000 0000 0000 | XXXXXXXXXXXXXXXXX + +// --------------------------------------------------------------------------------- +// trim - remove trailing whitespace from string s +// --------------------------------------------------------------------------------- + +char *trim (char *s) +{ + char *os = s, *nb; + + for (nb = s-1; *s; s++) + if (*s > ' ') + nb = s; + + nb[1] = '\0'; + return os; +} + +// --------------------------------------------------------------------------------- +// listout - emit current constructed output listing line held in "listline" and +// if "reset" is true, prepare listline for second and subsequent listing lines +// for a given input statement. +// --------------------------------------------------------------------------------- + +void listout (BOOL reset) +{ + if (flist && list_on && ! line_error) { + trim(listline); + fputs(listline, flist); + putc('\n', flist); + if (reset) + sprintf(listline, LEFT_MARGIN, org); + } +} + +// --------------------------------------------------------------------------------- +// storew - store a word in the output medium (hex or binary file). Most of the time +// writew is used. Advances the origin! +// --------------------------------------------------------------------------------- + +void storew (int word, RELOC relative) +{ + if (pass == 2) { // save in output (load) file. + switch (outmode) { + case OUTMODE_BINARY: + bincard_writew(word, relative); + break; + + case OUTMODE_LOAD: + fprintf(fout, " %04x%s" ENDLINE, word & 0xFFFF, + (relative == ABSOLUTE) ? "" : (relative == RELATIVE) ? "R" : + (relative == LIBF) ? "L" : (relative == CALL) ? "$" : "?"); + break; + + default: + bail("in storew, can't happen"); + } + } + + if (relative != LIBF) + org++; + + assembled = TRUE; // remember that we wrote something +} + +// --------------------------------------------------------------------------------- +// setw - store a word value in the current listing output line in position 'pos'. +// --------------------------------------------------------------------------------- + +void setw (int pos, int word, RELOC relative) +{ + char tok[10], *p; + int i; + + if (flist == NULL || ! list_on) + return; + + sprintf(tok, "%04x", word & 0xFFFF); + + for (i = 0, p = listline + 5*pos; i < 4; i++) + p[i] = tok[i]; + + if (relative == RELATIVE) + p[i] = 'R'; + else if (relative != ABSOLUTE) + p[i] = '*'; +} + +// --------------------------------------------------------------------------------- +// writew - emit an assembled word value. Words are also displayed in the listing file. +// if relative is true, a relocation entry should be recorded. +// --------------------------------------------------------------------------------- + +void writew (int word, RELOC relative) +{ // first, the listing stuff... + if (nwout == 0) { // on first output word, display address in column 0 + setw(0, org, FALSE); + } + else if (nwout >= 4) { // if 4 words have already been written, start new line + listout(TRUE); + nwout = 0; + } + + nwout++; + setw(nwout, word, relative); // display word in the listing line + + storew(word, relative); // write it to the output medium +} + +// --------------------------------------------------------------------------------- +// setorg - take note of new load address +// --------------------------------------------------------------------------------- + +void setorg (int neworg) +{ + if (pass == 2) { + setw(0, neworg, FALSE); // display in listing file in column 0 + + if (outmode == OUTMODE_LOAD) { // write new load address to the output file + fprintf(fout, "@%04x%s" ENDLINE, neworg & 0xFFFF, relocate ? "R" : ""); + } + else { + bincard_setorg(neworg); + } + } + + org = neworg; +} + +// --------------------------------------------------------------------------------- +// org_even - force load address to an even address +// --------------------------------------------------------------------------------- + +void org_even (void) +{ + if (org & 1) + setorg(org+1); +} + +// --------------------------------------------------------------------------------- +// tabtok - get the token in tab-delimited column number i, from source string c, +// saving in string 'tok'. If save is nonnull, we copy the entire remainder of +// the input string in buffer 'save' (in contrast to 'tok' which gets only the +// first whitespace delimited token). +// --------------------------------------------------------------------------------- + +void tabtok (char *c, char *tok, int i, char *save) +{ + *tok = '\0'; + + while (--i >= 0) { // skip to i'th tab-delimited field + if ((c = strchr(c, '\t')) == NULL) { + if (save) // was none + *save = '\0'; + return; + } + c++; + } + + while (*c == ' ') // skip leading blanks + c++; + + if (save != NULL) // save copy of entire remainder + strcpy(save, c); + + while (*c > ' ') { // take up to any whitespace + if (*c == '(') { // if we start with a paren, take all up to closing paren including spaces + while (*c && *c != ')') + *tok++ = *c++; + } + else if (*c == '.') { // period means literal character following + *tok++ = *c++; + if (*c) + *tok++ = *c++; + } + else + *tok++ = *c++; + } + + *tok = '\0'; +} + +// --------------------------------------------------------------------------------- +// coltok - extract a token from string c, saving to buffer tok, by examining +// columns ifrom through ito only. If save is nonnull, the entire remainder +// of the input from ifrom to the end is saved there. In this routine +// if condense is true, we save all nonwhite characters in the column range; +// not the usual thing. This helps us coalesce the format, tag, & index things +// nto one string for the simple minded parser. If condense is FALSE, we terminate +// on the first nonblank, except that if we start with a (, we take up to ) and +// then terminate on a space. +// +// ifrom and ito on entry are column numbers, not indices; we change that right away +// --------------------------------------------------------------------------------- + +void coltok (char *c, char *tok, int ifrom, int ito, BOOL condense, char *save) +{ + char *otok = tok; + int i; + + ifrom--; + ito--; + + for (i = 0; i < ifrom; i++) { + if (c[i] == '\0') { // line ended before this column + *tok = '\0'; + if (save) + *save = '\0'; + return; + } + } + + if (save) // save from ifrom on + strcpy(save, c+i); + + if (condense) { + for (; i <= ito; i++) { // save only nonwhite characters + if (c[i] > ' ') + *tok++ = c[i]; + } + } + else { + if (c[i] == ' ' && save != NULL)// if it starts with a space, it's empty + *save = '\0'; + + while (i <= ito) { // take up to any whitespace + if (c[i] <= ' ') + break; + else if (c[i] == '(') { // starts with paren? take to close paren + while (i <= ito && c[i]) { + if ((*tok++ = c[i++]) == ')') + break; + } + } + else if (c[i] == '.') { // period means literal character following + *tok++ = c[i++]; + if (i <= ito && c[i]) + *tok++ = c[i++]; + } + else + *tok++ = c[i++]; + } + } + + *tok = '\0'; + trim(otok); +} + +// --------------------------------------------------------------------------------- +// opcode table +// --------------------------------------------------------------------------------- + +// modifiers for the opcode definition table: + +#define L "L" // long +#define X "X" // absolute displacement +#define I "I" // indirect +#define IDX "0123" // indexed (some LDX commands in the DMS source say LDX L0, so accept 0 +#define E "E" // even address +#define NONE "" +#define ALL L X I IDX // hope non-Microsoft C accepts and concatenates strings like this +#define ANY "\xFF" +#define NUMS "0123456789" + +#define IS_DBL 0x0001 // double word operand implies even address +#define IS_ABS 0x0002 // always uses absolute addressing mode (implied X) +#define NO_IDX 0x0004 // even with 1 or 2 modifier, this is not really indexed (for STX/LDX) +#define NO_ARGS 0x0008 // statement takes no arguments +#define TRAP 0x1000 // debug this instruction + +struct tag_op { // OPCODE TABLE + char *mnem; + int opcode; + void (*handler)(struct tag_op *op, char *label, char *mods, char *arg); + char *mods_allowed; + char *mods_implied; + int flags; +}; + // special opcode handlers +void std_op (struct tag_op *op, char *label, char *mods, char *arg); +void b_op (struct tag_op *op, char *label, char *mods, char *arg); +void bsc_op (struct tag_op *op, char *label, char *mods, char *arg); +void bsi_op (struct tag_op *op, char *label, char *mods, char *arg); +void mdx_op (struct tag_op *op, char *label, char *mods, char *arg); +void shf_op (struct tag_op *op, char *label, char *mods, char *arg); + +void x_aif (struct tag_op *op, char *label, char *mods, char *arg); +void x_aifb (struct tag_op *op, char *label, char *mods, char *arg); +void x_ago (struct tag_op *op, char *label, char *mods, char *arg); +void x_agob (struct tag_op *op, char *label, char *mods, char *arg); +void x_anop (struct tag_op *op, char *label, char *mods, char *arg); +void x_abs (struct tag_op *op, char *label, char *mods, char *arg); +void x_call (struct tag_op *op, char *label, char *mods, char *arg); +void x_dsa (struct tag_op *op, char *label, char *mods, char *arg); +void x_file (struct tag_op *op, char *label, char *mods, char *arg); +void x_link (struct tag_op *op, char *label, char *mods, char *arg); +void x_libf (struct tag_op *op, char *label, char *mods, char *arg); +void x_org (struct tag_op *op, char *label, char *mods, char *arg); +void x_opt (struct tag_op *op, char *label, char *mods, char *arg); +void x_ces (struct tag_op *op, char *label, char *mods, char *arg); +void x_bes (struct tag_op *op, char *label, char *mods, char *arg); +void x_bss (struct tag_op *op, char *label, char *mods, char *arg); +void x_dc (struct tag_op *op, char *label, char *mods, char *arg); +void x_dec (struct tag_op *op, char *label, char *mods, char *arg); +void x_ebc (struct tag_op *op, char *label, char *mods, char *arg); +void x_end (struct tag_op *op, char *label, char *mods, char *arg); +void x_ent (struct tag_op *op, char *label, char *mods, char *arg); +void x_epr (struct tag_op *op, char *label, char *mods, char *arg); +void x_equ (struct tag_op *op, char *label, char *mods, char *arg); +void x_exit (struct tag_op *op, char *label, char *mods, char *arg); +void x_ils (struct tag_op *op, char *label, char *mods, char *arg); +void x_iss (struct tag_op *op, char *label, char *mods, char *arg); +void x_libr (struct tag_op *op, char *label, char *mods, char *arg); +void x_lorg (struct tag_op *op, char *label, char *mods, char *arg); +void x_dmes (struct tag_op *op, char *label, char *mods, char *arg); +void x_dn (struct tag_op *op, char *label, char *mods, char *arg); +void x_dump (struct tag_op *op, char *label, char *mods, char *arg); +void x_pdmp (struct tag_op *op, char *label, char *mods, char *arg); +void x_hdng (struct tag_op *op, char *label, char *mods, char *arg); +void x_list (struct tag_op *op, char *label, char *mods, char *arg); +void x_spac (struct tag_op *op, char *label, char *mods, char *arg); +void x_spr (struct tag_op *op, char *label, char *mods, char *arg); +void x_ejct (struct tag_op *op, char *label, char *mods, char *arg); +void x_trap (struct tag_op *op, char *label, char *mods, char *arg); +void x_xflc (struct tag_op *op, char *label, char *mods, char *arg); + +struct tag_op ops[] = { + ".OPT", 0, x_opt, NONE, NONE, 0, // non-IBM extensions + "TRAP", 0, x_trap, NONE, NONE, 0, // assembler breakpoint trap + ".CES", 0, x_ces, NONE, NONE, 0, // lets us specify simulated console entry switch values for startup + + "ABS", 0, x_abs, NONE, NONE, 0, + "BES", 0, x_bes, E, NONE, 0, // standard pseudo-ops + "BSS", 0, x_bss, E, NONE, 0, + "DC", 0, x_dc, NONE, NONE, 0, + "DEC", 0, x_dec, E, E, IS_DBL, + "DMES", 0, x_dmes, ANY, NONE, 0, + "DN", 0, x_dn, NONE, NONE, 0, + "DSA", 0, x_dsa, NONE, NONE, 0, + "DUMP", 0, x_dump, NONE, NONE, 0, + "EBC", 0, x_ebc, NONE, NONE, 0, + "EJCT", 0, x_ejct, NONE, NONE, 0, + "END", 0, x_end, NONE, NONE, 0, + "ENT", 0, x_ent, NONE, NONE, 0, + "EPR", 0, x_epr, NONE, NONE, 0, + "EQU", 0, x_equ, NONE, NONE, 0, + "EXIT", 0, x_exit, NONE, NONE, 0, // alias for call $exit since we don't have macros yet + "FILE", 0, x_file, NONE, NONE, 0, + "HDNG", 0, x_hdng, ANY, NONE, 0, + "ILS", 0, x_ils, NUMS, NONE, 0, + "ISS", 0, x_iss, NUMS, NONE, 0, + "LIBF", 0, x_libf, NONE, NONE, 0, + "LIBR", 0, x_libr, NONE, NONE, 0, + "LINK", 0, x_link, NONE, NONE, 0, + "LIST", 0, x_list, NONE, NONE, 0, + "LORG", 0, x_lorg, NONE, NONE, 0, + "ORG", 0, x_org, NONE, NONE, 0, + "PDMP", 0, x_pdmp, NONE, NONE, 0, + "SPAC", 0, x_spac, NONE, NONE, 0, + "SPR", 0, x_spr, NONE, NONE, 0, + "XFLC", 0, x_xflc, NONE, NONE, 0, + + "A", 0x8000, std_op, ALL, NONE, 0, // standard addressing ops + "AD", 0x8800, std_op, ALL, NONE, IS_DBL, + "AND", 0xE000, std_op, ALL, NONE, 0, + "BSI", 0x4000, bsi_op, ALL, NONE, 0, + "CALL", 0x4000, x_call, ALL, L, 0, // alias for BSI L, or external call + "D" , 0xA800, std_op, ALL, NONE, 0, + "EOR", 0xF000, std_op, ALL, NONE, 0, + "LD", 0xC000, std_op, ALL, NONE, 0, + "LDD", 0xC800, std_op, ALL, NONE, IS_DBL, + "LDS", 0x2000, std_op, NONE, NONE, IS_ABS, + "LDX", 0x6000, std_op, ALL, NONE, IS_ABS|NO_IDX, + "M", 0xA000, std_op, ALL, NONE, 0, + "MDX", 0x7000, mdx_op, ALL, NONE, 0, + "MDM", 0x7000, mdx_op, L, L, 0, // like MDX L + "NOP", 0x1000, std_op, NONE, NONE, NO_ARGS, + "OR", 0xE800, std_op, ALL, NONE, 0, + "S", 0x9000, std_op, ALL, NONE, 0, + "SD", 0x9800, std_op, ALL, NONE, IS_DBL, + "STD", 0xD800, std_op, ALL, NONE, IS_DBL, + "STO", 0xD000, std_op, ALL, NONE, 0, + "STS", 0x2800, std_op, ALL, NONE, 0, + "STX", 0x6800, std_op, ALL, NONE, NO_IDX, + "WAIT", 0x3000, std_op, NONE, NONE, NO_ARGS, + "XCH", 0x1810, std_op, NONE, NONE, 0, // same as RTE 16 + "XIO", 0x0800, std_op, ALL, NONE, IS_DBL, + + "BSC", 0x4800, bsc_op, ALL, NONE, 0, // branch family + "BOSC", 0x4840, bsc_op, ALL, NONE, 0, // is BOSC always long form? No. + "SKP", 0x4800, bsc_op, NONE, NONE, 0, // alias for BSC one word version + + "B", 0x4800, b_op, ALL, NONE, 0, // alias for MDX or BSC L + "BC", 0x4802, std_op, ALL, L, 0, // alias for BSC L + "BN", 0x4828, std_op, ALL, L, 0, // alias for BSC L + "BNN", 0x4810, std_op, ALL, L, 0, // alias for BSC L + "BNP", 0x4808, std_op, ALL, L, 0, // alias for BSC L + "BNZ", 0x4820, std_op, ALL, L, 0, // alias for BSC L + "BO", 0x4801, std_op, ALL, L, 0, // alias for BSC L + "BOD", 0x4840, std_op, ALL, L, 0, // alias for BSC L + "BP", 0x4830, std_op, ALL, L, 0, // alias for BSC L + "BZ", 0x4818, std_op, ALL, L, 0, // alias for BSC L + + "RTE", 0x18C0, shf_op, IDX X, X, 0, // shift family + "SLA", 0x1000, shf_op, IDX X, X, 0, + "SLC", 0x10C0, shf_op, IDX X, X, 0, + "SLCA", 0x1040, shf_op, IDX X, X, 0, + "SLT", 0x1080, shf_op, IDX X, X, 0, + "SRA", 0x1800, shf_op, IDX X, X, 0, + "SRT", 0x1880, shf_op, IDX X, X, 0, + + "AIF", 0, x_aif, NONE, NONE, 0, // assemble if + "AIFB", 0, x_aifb, NONE, NONE, 0, // assemble if + "AGO", 0, x_ago, NONE, NONE, 0, // assemble goto + "AGOB", 0, x_agob, NONE, NONE, 0, // assemble goto + "ANOP", 0, x_anop, NONE, NONE, 0, // assemble target + + NULL // end of table +}; + +// --------------------------------------------------------------------------------- +// addextn - apply file extension 'extn' to filename 'fname' and put result in 'outbuf' +// if outbuf is NULL, we allocate a buffer +// --------------------------------------------------------------------------------- + +char *addextn (char *fname, char *extn, char *outbuf) +{ + char *buf, line[500], *c; + + buf = (outbuf == NULL) ? line : outbuf; + + strcpy(buf, fname); // create listfn from first source filename (e.g. xxx.lst); + if ((c = strrchr(buf, '\\')) == NULL) + if ((c = strrchr(buf, '/')) == NULL) + if ((c = strrchr(buf, ':')) == NULL) + c = buf; + + if ((c = strrchr(c, '.')) == NULL) + strcat(buf, extn); + else + strcpy(c, extn); + + return (outbuf == NULL) ? astring(line) : outbuf; +} + +// --------------------------------------------------------------------------------- +// controlcard - examine an assembler control card (* in column 1) +// --------------------------------------------------------------------------------- + +BOOL controlcard (char *line) +{ + if (strnicmp(line, "*LIST", 5) == 0) { // turn on listing file even if not specified on command line + do_list = list_on = TRUE; + return TRUE; + } + + if (strnicmp(line, "*XREF", 5) == 0) { + do_xref = TRUE; + return TRUE; + } + + if (strnicmp(line, "*PRINT SYMBOL TABLE", 19) == 0) { + do_syms = TRUE; + return TRUE; + } + + if (strnicmp(line, "*SAVE SYMBOL TABLE", 18) == 0) { + savetable = TRUE; + return TRUE; + } + + if (strnicmp(line, "*SYSTEM SYMBOL TABLE", 20) == 0) { + preload = TRUE; + preload_symbols(); + return TRUE; + } + + return FALSE; +} + +// --------------------------------------------------------------------------------- +// stuff - insert characters into a line +// --------------------------------------------------------------------------------- + +void stuff (char *buf, char *tok, int maxchars) +{ + while (*tok) { + *buf++ = *tok++; + + if (maxchars) + if (--maxchars <= 0) + break; + } +} + +// --------------------------------------------------------------------------------- +// format_line - construct a source code input line from components +// --------------------------------------------------------------------------------- + +void format_line (char *buf, char *label, char *op, char *mods, char *args, char *remarks) +{ + int i; + + if (tabformat) { + sprintf(buf, "%s\t%s\t%s\t%s\t%s", label, op, mods, args, remarks); + } + else { + for (i = 0; i < 72; i++) + buf[i] = ' '; + buf[i] = '\0'; + + stuff(buf+20, label, 5); + stuff(buf+26, op, 4); + stuff(buf+31, mods, 2); + stuff(buf+34, args, 72-34); + } +} + +// --------------------------------------------------------------------------------- +// lookup_op - find an opcode +// --------------------------------------------------------------------------------- + +struct tag_op * lookup_op (char *mnem) +{ + struct tag_op *op; + int i; + + for (op = ops; op->mnem != NULL; op++) { + if ((i = strcmp(op->mnem, mnem)) == 0) + return op; + + if (i > 0) + break; + } + return NULL; +} + +// --------------------------------------------------------------------------------- +// bincard - routines to write IBM 1130 Card object format +// --------------------------------------------------------------------------------- + +unsigned short bincard[54]; // the 54 data words that can fit on a binary format card +char binflag[45]; // the relocation flags of the 45 buffered object words (0, 1, 2, 3) +int bincard_n = 0; // number of object words stored in bincard (0-45) +int bincard_seq = 0; // card output sequence number +int bincard_org = 0; // origin of current card-full +int bincard_maxaddr = 0; +BOOL bincard_first = TRUE; // TRUE when we're to write the program type card + +// bincard_init - prepare a new object data output card + +void bincard_init (void) +{ + memset(bincard, 0, sizeof(bincard)); // clear card data + memset(binflag, 0, sizeof(binflag)); // clear relocation data + bincard_n = 0; // no data + bincard[0] = bincard_org; // store load address + bincard_maxaddr = MAX(bincard_maxaddr, bincard_org-1); // save highest address written-to (this may be a BSS) +} + +// binard_writecard - emit a card. sbrk_text = NULL for normal data cards, points to comment text for sbrk card +// note: sbrk_text if not NULL MUST be a writeable buffer of at LEAST 71 characters + +void bincard_writecard (char *sbrk_text) +{ + unsigned short binout[80]; + char ident[12]; + int i, j; + + if (sbrk_text != NULL) { // sbrk card has 4 binary words followed by comment text + for (j = 66; j < 71; j++) // be sure input columns 67..71 are nonblank (have version number) + if (sbrk_text[j] <= ' ') + break; + + if (j < 71) // sbrk card didn't have the info, stuff in current release + for (j = 0; j < 5; j++) + sbrk_text[66+j] = dmsversion[j]; + + binout[0] = 0; + binout[1] = 0; + binout[2] = 0; + binout[3] = 0x1000; + + sbrk_text += 5; // start at the real column 6 (after *SBRK + for (j = 5; j < 72; j++) + binout[j] = (*sbrk_text) ? ascii_to_hollerith(*sbrk_text++) : 0; + + } + else { // binary card format packs 54 words into 72 columns + for (i = j = 0; i < 54; i += 3, j += 4) { + binout[j ] = ( bincard[i] & 0xFFF0); + binout[j+1] = ((bincard[i] << 12) & 0xF000) | ((bincard[i+1] >> 4) & 0x0FF0); + binout[j+2] = ((bincard[i+1] << 8) & 0xFF00) | ((bincard[i+2] >> 8) & 0x00F0); + binout[j+3] = ((bincard[i+2] << 4) & 0xFFF0); + } + } + + sprintf(ident, "%08ld", ++bincard_seq); // append sequence text + memmove(ident, progname, MIN(strlen(progname), 4)); + + for (i = 0; i < 8; i++) + binout[j++] = ascii_to_hollerith(ident[i]); + + fwrite(binout, sizeof(binout[0]), 80, fout); // write card image +} + +// binard_writedata - emit an object data card + +void bincard_writedata (void) +{ + unsigned short rflag = 0; + int i, j, nflag = 0; + + bincard[1] = 0; // checksum + bincard[2] = 0x0A00 | bincard_n; // data card type + word count + + for (i = 0, j = 3; i < bincard_n; i++) { // construct relocation indicator bitmap + if (nflag == 8) { + bincard[j++] = rflag; + rflag = 0; + nflag = 0; + } + rflag = (rflag << 2) | (binflag[i] & 3); + nflag++; + } + + if (nflag > 0) + bincard[j] = rflag << (16 - 2*nflag); + + bincard_writecard(FALSE); // emit the card +} + +// bincard_flush - flush any pending binary data + +void bincard_flush (void) +{ + if (bincard_n > 0) + bincard_writedata(); + + bincard_init(); +} + +// bincard_sbrk - emit an SBRK card + +void bincard_sbrk (char *line) +{ + if (bincard_first) + bincard_typecard(); + else + bincard_flush(); + + bincard_writecard(line); +} + +// bincard_setorg - set the origin + +void bincard_setorg (int neworg) +{ + bincard_org = neworg; // set origin for next card + bincard_flush(); // flush any current data & store origin +} + +// bincard_endcard - write end of program card + +void bincard_endcard (void) +{ + bincard_flush(); + + bincard[0] = (bincard_maxaddr + 2) & ~1; // effective length: add 1 to max origin, then 1 more to round up + bincard[1] = 0; + bincard[2] = 0x0F00; + bincard[3] = pta & 0xFFFF; + + bincard_writecard(NULL); +} + +// bincard_typecard - write the program type + +void bincard_typecard (void) +{ + int i; + + if (! bincard_first) + return; + + bincard_first = FALSE; + + memset(bincard, 0, sizeof(bincard)); + + bincard[2] = (unsigned short) ((progtype << 8) | intmode | realmode); + +// all indices not listed are documented as 'reserved' + + switch (progtype) { + case PROGTYPE_ABSOLUTE: + case PROGTYPE_RELOCATABLE: +// bincard[ 4] = 0; // length of common (fortran only) + bincard[ 5] = 0x0003; +// bincard[ 6] = 0; // length of work area (fortran only) + bincard[ 8] = ndefined_files; + namecode(&bincard[9], progname); + bincard[11] = (pta < 0) ? 0 : pta; + break; + + case PROGTYPE_LIBF: + case PROGTYPE_CALL: + bincard[ 5] = 3*nentries; + for (i = 0; i < nentries; i++) { + namecode(&bincard[9+3*i], entry[i]->name); + bincard[11+3*i] = entry[i]->value; + } + break; + + case PROGTYPE_ISSLIBF: + case PROGTYPE_ISSCALL: + bincard[ 5] = 6+nintlevels; + namecode(&bincard[9], entry[0]->name); + bincard[11] = entry[0]->value; + bincard[12] = iss_number + ISTV; // magic number ISTV is 0x33 in DMS R2V12 + bincard[13] = iss_number; + bincard[14] = nintlevels; + bincard[15] = intlevel_primary; + bincard[16] = intlevel_secondary; + bincard[29] = 1; + break; + + case PROGTYPE_ILS: + bincard[ 2] = (unsigned short) (progtype << 8); + bincard[ 5] = 4; + bincard[12] = intlevel_primary; + break; + + default: + bail("in bincard_typecard, can't happen"); + } + + bincard[1] = 0; // checksum + + bincard_writecard(NULL); + + bincard_init(); +} + +// bincard_writew - write a word to the current output card. + +void bincard_writew (int word, RELOC relative) +{ + if (pass != 2) + return; + + if (bincard_first) + bincard_typecard(); + else if (bincard_n >= 45) // flush full card buffer + bincard_flush(); + + binflag[bincard_n] = relative & 3; // store relocation bits and data word + bincard[9+bincard_n++] = word; + + if (relative != LIBF) { + bincard_maxaddr = MAX(bincard_maxaddr, bincard_org); + bincard_org++; + } +} + +// writetwo - notification that we are about to write two words which must stay together + +void writetwo (void) +{ + if (pass == 2 && outmode == OUTMODE_BINARY && bincard_n >= 44) + bincard_flush(); +} + +// handle_sbrk - handle an SBRK directive. +// This was not part of the 1130 assembler; they assembled DMS on a 360 + +void handle_sbrk (char *line) +{ + char rline[90]; + + if (pass != 2) + return; + + strncpy(rline, line, 81); // get a copy and pad it if necessary to 80 characters + rline[80] = '\0'; + while (strlen(rline) < 80) + strcat(rline, " "); + + switch (outmode) { + case OUTMODE_LOAD: + fprintf(fout, "#SBRK%s\n", trim(rline+5)); + + case OUTMODE_BINARY: + bincard_sbrk(rline); + break; + + default: + bail("in handle_sbrk, can't happen"); + } +} + +// --------------------------------------------------------------------------------- +// namecode - turn a string into a two-word packed name +// --------------------------------------------------------------------------------- + +void namecode (unsigned short *words, char *tok) +{ + long val = 0; + int i, ch; + + for (i = 0; i < 5; i++) { // pick up bits + if (*tok) + ch = *tok++; + else + ch = ' '; + + val = (val << 6) | (ascii_to_ebcdic_table[ch] & 0x3F); + } + + words[0] = (unsigned short) (val >> 16); + words[1] = (unsigned short) val; +} + +// --------------------------------------------------------------------------------- +// parse_line - parse one input line. +// --------------------------------------------------------------------------------- + +void parse_line (char *line) +{ + char label[100], mnem[100], arg[200], mods[20], *c; + struct tag_op *op; + + if (line[0] == '/' && line[1] == '/') // job control card? probably best to ignore it + return; + + if (line[0] == '*') { // control card comment or comment in tab-format file + if (check_control) // pay attention to control cards only at top of file + if (! controlcard(line)) + check_control = FALSE; // first non-control card shuts off sensitivity to them + + if (strnicmp(line+1, "SBRK", 4) == 0) + handle_sbrk(line); + + return; + } + + check_control = FALSE; // non-control card, consider them no more + + label[0] = '\0'; // prepare to extract fields + mods[0] = '\0'; + mnem[0] = '\0'; + arg[0] = '\0'; + + if (tabformat || strchr(line, '\t') != NULL) { // if input line has tabs, parse loosely + tabformat = TRUE; // this is a tab-formatted file + + for (c = line; *c && *c <= ' '; c++) // find first nonblank + ; + + if (*c == '*' || ! *c) // ignore as a comment + return; + + tabtok(line, label, 0, NULL); + tabtok(line, mnem, 1, NULL); + tabtok(line, mods, 2, NULL); + tabtok(line, arg, 3, opfield); + } + else { // if no tabs, use strict card-column format + if (line[20] == '*') // comment + return; + + line[72] = '\0'; // clip off sequence + + coltok(line, label, 21, 25, TRUE, NULL); + coltok(line, mnem, 27, 30, TRUE, NULL); + coltok(line, mods, 32, 33, TRUE, NULL); + coltok(line, arg, 35, 72, FALSE, opfield); + } + +// I don't know where I got this idea, but it's wrong... +// if (strchr(mods, '1') || strchr(mods, '2') || strchr(mods, '3')) { // index + X means ignore X +// if ((c = strchr(mods, 'X')) != NULL) +// strcpy(c, c+1); // remove the X +// } + + if (*label) // display org in any line with a label + setw(0, org, FALSE); + + if (! *mnem) { // label w/o mnemonic, just define the symbol + if (*label) + set_symbol(label, org, TRUE, relocate); + return; + } + + if ((op = lookup_op(mnem)) == NULL) { // look up mnemonic + if (*label) + set_symbol(label, org, TRUE, relocate);// at least define the label + + asm_error("Unknown opcode '%s'", mnem); + return; + } + + if (op->flags & TRAP) // assembler debugging breakpoint + x_trap(op, label, mods, arg); + + if (*op->mods_allowed != '\xFF') { // validate modifiers against list of allowed characters + for (c = mods; *c; ) { + if (strchr(op->mods_allowed, *c) == NULL) { + asm_warning("Modifier '%c' not permitted", *c); + strcpy(c, c+1); // remove it and keep parsing + } + else + c++; + } + } + + strcat(mods, op->mods_implied); // tack on implied modifiers + + if (strchr(mods, 'I')) // indirect implies long + strcat(mods, "L"); + + requires_even_address = op->flags & IS_DBL; + + org_advanced = strchr(mods, 'L') ? 2 : 1; // by default, * means address + 1 or 2. Sometimes it doesn't + (op->handler)(op, label, mods, arg); +} + +// --------------------------------------------------------------------------------- +// get one input line from current file or macro +// --------------------------------------------------------------------------------- + +BOOL get_line (char *buf, int nbuf, BOOL onelevel) +{ + char *retval; + + if (ended) // we hit the END command + return FALSE; + + // if macro active, return line from macro buffer, otherwise read from file + // do not pop end-of-macro if onelevel is TRUE + + if ((retval = fgets(buf, nbuf, fin)) == NULL) + return FALSE; + + lno++; // count the line + return TRUE; +} + +// --------------------------------------------------------------------------------- +// proc - process one pass of one source file +// --------------------------------------------------------------------------------- + +void proc (char *fname) +{ + char line[256], *c; + int i; + + if (strchr(fname, '.') == NULL) // if input file has no extension, + addextn(fname, ".asm", curfn); // set appropriate file extension + else + strcpy(curfn, fname); // otherwise use extension specified + +#if (defined(WIN32) || defined(VMS)) + upcase(curfn); // only force uppercase of name on Windows and VMS +#endif + + if (progname[0] == '\0') { // pick up primary filename + if ((c = strrchr(curfn, '\\')) == NULL) + if ((c = strrchr(curfn, '/')) == NULL) + if ((c = strrchr(curfn, ':')) == NULL) + c = curfn; + + strncpy(progname, c, sizeof(progname)); // take name after path + progname[sizeof(progname)-1] = '\0'; + if ((c = strchr(progname, '.')) != NULL)// remove extension + *c = '\0'; + } + + lno = 0; // reset global input line number + ended = FALSE; // have not seen END statement + + if (listfn == NULL) // if list file name is undefined, + listfn = addextn(fname, ".lst", NULL); // create from first filename + + if (verbose) + fprintf(stderr, "--- Starting file %s pass %d\n", curfn, pass); + + if ((fin = fopen(curfn, "r")) == NULL) { + perror(curfn); // oops + exit(1); + } + + if (flist) { // put banner in listing file + strcpy(listline,"=== FILE ======================================================================"); + for (i = 9, c = curfn; *c;) + listline[i++] = *c++; + listline[i] = ' '; + fputs(listline, flist); + putc('\n', flist); + list_on = TRUE; + } + // read all lines till EOF or END statement + while (get_line(line, sizeof(line), FALSE)) { + prep_line(line); // preform standard line prep + parse_line(line); // parse + listout(FALSE); // complete the listing + } + + fclose(fin); + + if (n_literals > 0) { // force out any pending literal constants at end of file + output_literals(TRUE); + listout(FALSE); + } +} + +// --------------------------------------------------------------------------------- +// prep_line - prepare input line for parsing +// --------------------------------------------------------------------------------- + +void prep_line (char *line) +{ + char *c; + + upcase(line); // uppercase it + nwout = 0; // number of words output so far + line_error = FALSE; // no errors on this line so far + + for (c = line; *c; c++) { // truncate at newline + if (*c == '\r' || *c == '\n') { + *c = '\0'; + break; + } + } + + if (flist && list_on) { // construct beginning of listing line + if (tabformat) + sprintf(listline, LINEFORMAT, lno, detab(line)); + else { + if (strlen(line) > 20) // get the part where the commands start + c = line+20; + else + c = ""; + + sprintf(listline, LINEFORMAT, lno, c); + stuff(listline, line, 20); // stuff the left margin in to the left side + } + } +} + +// --------------------------------------------------------------------------------- +// opcmp - operand name comparison routine for qsort +// --------------------------------------------------------------------------------- + +int opcmp (const void *a, const void *b) +{ + return strcmp(((struct tag_op *) a)->mnem, ((struct tag_op *) b)->mnem); +} + +// --------------------------------------------------------------------------------- +// preload_symbols - load a saved symbol table +// --------------------------------------------------------------------------------- + +void preload_symbols (void) +{ + FILE *fd; + char str[200], sym[20]; + int v; + static BOOL preloaded_already = FALSE; + + if (pass > 1 || preloaded_already) + return; + + preloaded_already = TRUE; + + if ((fd = fopen(SYSTEM_TABLE, "r")) == NULL) // read the system symbol tabl + perror(SYSTEM_TABLE); + else { + while (fgets(str, sizeof(str), fd) != NULL) { + if (sscanf(str, "%s %x", sym, &v) == 2) + set_symbol(sym, v, TRUE, FALSE); + } + fclose(fd); + } +} + +// --------------------------------------------------------------------------------- +// save_symbols - save a symbol table +// --------------------------------------------------------------------------------- + +void save_symbols (void) +{ + FILE *fd; + char str[20]; + PSYMBOL s; + + if (relocate) { + fprintf(stderr, "Can't save symbol table unless ABS assembly\n"); + return; + } + + if ((fd = fopen(SYSTEM_TABLE, "r")) != NULL) { + fclose(fd); + if (saveprompt) { + printf("Overwrite system symbol table %s? ", SYSTEM_TABLE); + fgets(str, sizeof(str), stdin); + if (str[0] != 'y' && str[0] != 'Y') + return; + } + unlink(SYSTEM_TABLE); + } + + if ((fd = fopen(SYSTEM_TABLE, "w")) == NULL) { + perror(SYSTEM_TABLE); + return; + } + + for (s = symbols; s != NULL; s = s->next) + fprintf(fd, "%-5s %04x\n", s->name, s->value); + + fclose(fd); +} + +// --------------------------------------------------------------------------------- +// startpass - initialize data structures, prepare to start a pass +// --------------------------------------------------------------------------------- + +void startpass (int n) +{ + int nops; + struct tag_op *p; + + pass = n; // reset globals: pass number + nerrors = 0; // error count + org = 0; // load address (origin) + lno = 0; // input line number + relocate = TRUE; // relocatable assembly mode + assembled = FALSE; // true if any output has been generated + list_on = do_list; // listing enable + dmes_saved = FALSE; // partial character strings output + + n_literals = 0; // literal values pending output + lit_tag = 0; + + if (pass == 1) { // first pass only + for (nops = 0, p = ops; p->mnem != NULL; p++, nops++) // count opcodes + ; + + qsort(ops, nops, sizeof(*p), opcmp); // sort the opcode table + + if (preload) + preload_symbols(); + } + else { // second pass only + if (outfn == NULL) + outfn = addextn(curfn, (outmode == OUTMODE_LOAD) ? ".out" : ".bin" , NULL); + + if ((fout = fopen(outfn, OUTWRITEMODE)) == NULL) { // open output file + perror(outfn); + exit(1); + } + + if (do_list) { // open listing file + if ((flist = fopen(listfn, "w")) == NULL) { + perror(listfn); + exit(1); + } + listhdr(); // print banner + } + } +} + +// --------------------------------------------------------------------------------- +// x_dc - DC define constant directive +// --------------------------------------------------------------------------------- + +void x_dc (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR expr; +// char *tok; + + org_advanced = 1; // assume * means this address+1 +// doesn't make sense, but I think I found DMS listings to support it + + if (strchr(mods, 'E') != NULL) // force even address + org_even(); + + setw(0, org, FALSE); // display org in listing line + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + +// just one!? + getexpr(arg, FALSE, &expr); + writew(expr.value, expr.relative); // store value + + // pick up values, comma delimited +// for (tok = strtok(arg, ","); tok != NULL; tok = strtok(NULL, ",")) { +// getexpr(tok, FALSE, &expr); +// writew(expr.value, expr.relative); // store value +// } +} + +// --------------------------------------------------------------------------------- +// x_dec - DEC define double word constant directive. +// --------------------------------------------------------------------------------- + +// wd[0]: 8 unused bits | characteristic (= exponent+128) +// wd[1]: sign + 15 msb of mantissa in 2's complement +// wd[2]: 16 lsb of mantissa + +// NOTE: these are wrong with Fixed point numbers + +void convert_double_to_extended (double d, unsigned short *wd) +{ + int neg, exp; + unsigned long mantissa; + unsigned char *byte = (unsigned char *) &d; + + if (d == 0.) { + wd[0] = wd[1] = wd[2] = 0; + return; + } + // 7 6 5 4 0 + // d = ansi real*8 SXXX XXXX XXXX MMMM MMMM MMMM MMMM MMMM ... MMMM MMMM + + neg = byte[7] & 0x80; + exp = ((byte[7] & 0x7F) << 4) | ((byte[6] & 0xF0) >> 4); // extract exponent + exp -= 1023; // remove bias + + exp++; // shift to account for implied 1 we added + + // get 32 bits worth of mantissa. add the implied point + mantissa = 0x80000000L | ((byte[6] & 0x0F) << 27) | (byte[5] << 19) | (byte[4] << 11) | (byte[3] << 3) | ((byte[2] & 0xE0) >> 5); + + if (mantissa & (0x80000000L >> 31)) // keep 31 bits, round if necessary + mantissa += (0x80000000L >> 31); + + mantissa >>= (32-31); // get into low 31 bits + + // now turn into IBM 1130 extended precision + + exp += 128; + + if (neg) + mantissa = (unsigned long) (- (long) mantissa); // two's complement + + wd[0] = (unsigned short) (exp & 0xFF); + wd[1] = (unsigned short) ((neg ? 0x8000 : 0) | ((mantissa >> (31-15)) & 0x7FFF)); + wd[2] = (unsigned short) (mantissa & 0xFFFF); +} + +void convert_double_to_standard (double d, unsigned short *wd) +{ + int neg, exp; + unsigned long mantissa; + unsigned char *byte = (unsigned char *) &d; + + if (d == 0.) { + wd[0] = wd[1] = 0; + return; + } + // 7 6 5 4 0 + // d = ansi real*8 SXXX XXXX XXXX MMMM MMMM MMMM MMMM MMMM ... MMMM MMMM + + neg = byte[7] & 0x80; + exp = ((byte[7] & 0x7F) << 4) | ((byte[6] & 0xF0) >> 4); // extract exponent + exp -= 1023; // remove bias + + exp++; // shift to account for implied 1 we added + + // get 32 bits worth of mantissa. add the implied point + mantissa = 0x80000000L | ((byte[6] & 0x0F) << 27) | (byte[5] << 19) | (byte[4] << 11) | (byte[3] << 3) | ((byte[2] & 0xE0) >> 5); + +// if (mantissa & (0x80000000L >> 23)) // keep 23 bits, round if necessary +// mantissa += (0x80000000L >> 23); + +// DEBUG +// printf("%8.4lf: %08lx %d\n", d, mantissa, exp); + + mantissa >>= (32-23); // get into low 23 bits + + // now turn into IBM 1130 standard precision + + exp += 128; + + if (neg) + mantissa = (unsigned long) (- (long) mantissa); // two's complement + + wd[0] = (unsigned short) ((neg ? 0x8000 : 0) | ((mantissa >> (23-15)) & 0x7FFF)); + wd[1] = (unsigned short) ((mantissa & 0x00FF) << 8) | (exp & 0xFF); + +// DEBUG +// printf(" D %04x%04x\n", wd[0], wd[1]); +} + +void convert_double_to_fixed (double d, unsigned short *wd, int bexp) +{ + int neg, exp, rshift; + unsigned long mantissa; + unsigned char *byte = (unsigned char *) &d; + + if (d == 0.) { + wd[0] = wd[1] = 0; + return; + } + // 7 6 5 4 0 + // d = ansi real*8 SXXX XXXX XXXX MMMM MMMM MMMM MMMM MMMM ... MMMM MMMM + + neg = byte[7] & 0x80; + exp = ((byte[7] & 0x7F) << 4) | ((byte[6] & 0xF0) >> 4); // extract exponent + exp -= 1023; // remove bias + + exp++; // shift to account for implied 1 we added + + // get 32 bits worth of mantissa. add the implied point + mantissa = 0x80000000L | ((byte[6] & 0x0F) << 27) | (byte[5] << 19) | (byte[4] << 11) | (byte[3] << 3) | ((byte[2] & 0xE0) >> 5); + + mantissa >>= 1; // shift it out of the sign bit + +// DEBUG +// printf("%8.4lf: %08lx %d\n", d, mantissa, exp); + + rshift = bexp - exp; + + if (rshift > 0) { + mantissa >>= rshift; + } + else if (rshift < 0) { + mantissa >>= (-rshift); + asm_warning("Fixed point overflow"); + } + + if (neg) + mantissa = (unsigned long) (- (long) mantissa); // two's complement + +// DEBUG +// printf(" B %08lx\n", mantissa); + + wd[0] = (unsigned short) ((mantissa >> 16) & 0xFFFF); // return all of the bits; no exponent here + wd[1] = (unsigned short) (mantissa & 0xFFFF); +} + +void getDconstant (char *tok, unsigned short *wd) +{ + unsigned long l; + char *b, *fmt; + double d; + int bexp, fixed; + + wd[0] = 0; + wd[1] = 0; + + if (strchr(tok, '.') == NULL && strchr(tok, 'B') == NULL && strchr(tok, 'E') == NULL) { + fmt = "%ld"; + if (*tok == '/') { // I don't see that this is legal but can't hurt to allow it + fmt = "%lx"; + tok++; + } + if (sscanf(tok, fmt, &l) != 1) { // no decimal means it's an integer? + asm_error("Syntax error in constant"); + } + else { + wd[0] = (unsigned short) ((l >> 16) & 0xFFFF); // high word + wd[1] = (unsigned short) (l & 0xFFFF); // low word + } + return; + } + + fixed = 0; + if ((b = strchr(tok, 'B')) != NULL) { + fixed = 1; + bexp = atoi(b+1); + *b = '\0'; // truncate at the b + } + if (sscanf(tok, "%lg", &d) != 1) { + asm_error("Syntax error in constant"); + return; + } + + if (fixed) + convert_double_to_fixed(d, wd, bexp); + else + convert_double_to_standard(d, wd); +} + +// If the input value is an integer with no decimal point and no B or E, +// DEC generates a double INTEGER value. +// IBM documentation ranges from ambiguous to wrong on this point, but +// examination of the DMS microfiche supports this. + +void x_dec (struct tag_op *op, char *label, char *mods, char *arg) +{ +// char *tok; + unsigned short wd[2]; + + org_advanced = 2; // assume * means address after this location, since it's +1 for dc? + + org_even(); // even address is implied + setw(0, org, FALSE); // display the origin + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + +// just one!? + getDconstant(arg, wd); + writew(wd[0], FALSE); // write hiword, then loword + writew(wd[1], FALSE); + + // pick up values, comma delimited +// for (tok = strtok(arg, ","); tok != NULL; tok = strtok(NULL, ",")) { +// getDconstant(tok, wd); +// +// writew(wd[0], FALSE); // write hiword, then loword +// writew(wd[1], FALSE); +} + +void x_xflc (struct tag_op *op, char *label, char *mods, char *arg) +{ + char *tok, *b; + double d; + int bexp, fixed; + unsigned short wd[3]; + + org_advanced = 2; // who knows? + + setw(0, org, FALSE); // display the origin + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + // pick up values, comma delimited + for (tok = strtok(arg, ","); tok != NULL; tok = strtok(NULL, ",")) { + bexp = 0; + if ((b = strchr(tok, 'B')) != NULL) { + bexp = atoi(b+1); + fixed = TRUE; + *b = '\0'; // truncate at the b + asm_warning("Fixed point extended floating constant?"); + } + + if (sscanf(tok, "%lg", &d) != 1) { + asm_error("Syntax error in constant"); + d = 0.; + } + + convert_double_to_extended(d, wd); + + writew(wd[0], ABSOLUTE); + writew(wd[1], ABSOLUTE); + writew(wd[2], ABSOLUTE); + } +} + +// --------------------------------------------------------------------------------- +// x_equ - EQU directive +// --------------------------------------------------------------------------------- + +void x_equ (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR expr; + + org_advanced = FALSE; // * means this address, not incremented + + getexpr(arg, FALSE, &expr); + + setw(0, expr.value, expr.relative); // show this as address + + if (*label) // EQU is all about defining labels, better have one + set_symbol(label, expr.value, TRUE, expr.relative); +// else // IBM assembler doesn't complain about this +// asm_error("EQU without label?"); +} + +// --------------------------------------------------------------------------------- +// x_lorg - LORG directive -- output queued literal values +// --------------------------------------------------------------------------------- + +void x_lorg (struct tag_op *op, char *label, char *mods, char *arg) +{ + org_advanced = FALSE; // * means this address (not used, though) + output_literals(FALSE); // generate .DC's for queued literal values +} + +// --------------------------------------------------------------------------------- +// x_abs - ABS directive +// --------------------------------------------------------------------------------- + +void x_abs (struct tag_op *op, char *label, char *mods, char *arg) +{ + if (assembled) + asm_error("ABS must be first statement"); + + relocate = ABSOLUTE; + + switch (progtype) { + case PROGTYPE_ABSOLUTE: + case PROGTYPE_RELOCATABLE: + progtype = PROGTYPE_ABSOLUTE; // change program type, still assumed to be mainline + break; + + case PROGTYPE_LIBF: + case PROGTYPE_CALL: + case PROGTYPE_ISSLIBF: + case PROGTYPE_ISSCALL: + case PROGTYPE_ILS: + asm_error("ABS not allowed with LIBF, ENT, ILS or ISS"); + break; + + default: + bail("in x_libr, can't happen"); + } +} + +// --------------------------------------------------------------------------------- +// x_call - ORG pseudo-op +// --------------------------------------------------------------------------------- + +void x_call (struct tag_op *op, char *label, char *mods, char *arg) +{ + unsigned short words[2]; + static struct tag_op *bsi = NULL; + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + if (! *arg) { + asm_error("CALL missing argument"); + return; + } + + if (pass == 1) { // it will take two words in any case + org += 2; + return; + } + + setw(0, org, FALSE); // display origin + + if (lookup_symbol(arg, FALSE) != NULL) { // it's a defined symbol? + if (bsi == NULL) + if ((bsi = lookup_op("BSI")) == NULL) + bail("Can't find BSI op"); + + (bsi->handler)(bsi, "", "L", arg); + } + else { + namecode(words, arg); // emit namecode for loader + + writetwo(); + writew(words[0], CALL); + writew(words[1], ABSOLUTE); + } +} + +// --------------------------------------------------------------------------------- +// x_org - ORG directive +// --------------------------------------------------------------------------------- + +void x_org (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR expr; + + org_advanced = FALSE; // * means this address + + if (*label) // label is defined BEFORE the new origin is set!!! + set_symbol(label, org, TRUE, relocate); + + if (getexpr(arg, FALSE, &expr) != S_DEFINED) + return; + + setorg(expr.value); // set origin to this value +} + +// --------------------------------------------------------------------------------- +// x_end - END directive +// --------------------------------------------------------------------------------- + +void x_end (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR expr; + + org_advanced = FALSE; // * means this address + + if (*arg) { // they're specifing the program start address + if (getexpr(arg, FALSE, &expr) == S_DEFINED) + pta = expr.value; + } + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + setw(0, org, FALSE); // display origin + + ended = TRUE; // assembly is done, stop reading file +} + +// --------------------------------------------------------------------------------- +// x_ent - ENT op +// --------------------------------------------------------------------------------- + +void x_ent (struct tag_op *op, char *label, char *mods, char *arg) +{ + PSYMBOL s; + + org_advanced = FALSE; // * means this address + + if (pass < 2) + return; + +// if (*label) // define label +// set_symbol(label, org, TRUE, relocate); +// +// setw(0, org, FALSE); // display origin + + if (! *arg) + asm_error("No entry label specified"); + + else if ((s = lookup_symbol(arg, FALSE)) == NULL) + asm_error("Entry symbol %s not defined", arg); + + else if (nentries >= MAXENTRIES) + asm_error("Too many entries, limit is %d", MAXENTRIES); + + else + entry[nentries++] = s; // save symbol pointer + + switch (progtype) { + case PROGTYPE_ABSOLUTE: + asm_error("ENT not allowed with ABS"); + break; + case PROGTYPE_RELOCATABLE: + progtype = PROGTYPE_CALL; + break; + case PROGTYPE_LIBF: + case PROGTYPE_CALL: + case PROGTYPE_ISSLIBF: + case PROGTYPE_ISSCALL: + break; + case PROGTYPE_ILS: + asm_error("Can't mix ENT and ILS, can you?"); + break; + default: + bail("in x_libr, can't happen"); + } +} + +// --------------------------------------------------------------------------------- +// declare a libf-type subprogram +// --------------------------------------------------------------------------------- + +void x_libr (struct tag_op *op, char *label, char *mods, char *arg) +{ + switch (progtype) { + case PROGTYPE_ABSOLUTE: + asm_error("LIBR not allowed with ABS"); + break; + case PROGTYPE_RELOCATABLE: + case PROGTYPE_LIBF: + case PROGTYPE_CALL: + progtype = PROGTYPE_LIBF; + break; + case PROGTYPE_ISSLIBF: + case PROGTYPE_ISSCALL: + progtype = PROGTYPE_ISSLIBF; + break; + case PROGTYPE_ILS: + asm_error("Can't use LIBR in an ILS"); + break; + default: + bail("in x_libr, can't happen"); + } +} + +// --------------------------------------------------------------------------------- +// x_ils - ILS directive +// --------------------------------------------------------------------------------- + +void x_ils (struct tag_op *op, char *label, char *mods, char *arg) +{ + switch (progtype) { + case PROGTYPE_ABSOLUTE: + asm_error("ILS not allowed with ABS"); + break; + case PROGTYPE_RELOCATABLE: + case PROGTYPE_ILS: + progtype = PROGTYPE_ILS; + break; + case PROGTYPE_LIBF: + case PROGTYPE_CALL: + asm_error("Invalid placement of ILS"); + break; + case PROGTYPE_ISSLIBF: + case PROGTYPE_ISSCALL: + break; + default: + bail("in x_libr, can't happen"); + } + + intlevel_primary = atoi(mods); +} + +// --------------------------------------------------------------------------------- +// x_iss - ISS directive +// --------------------------------------------------------------------------------- + +void x_iss (struct tag_op *op, char *label, char *mods, char *arg) +{ + char *tok; + + switch (progtype) { + case PROGTYPE_ABSOLUTE: + asm_error("ISS not allowed with ABS"); + break; + case PROGTYPE_RELOCATABLE: + case PROGTYPE_CALL: + case PROGTYPE_ISSCALL: + progtype = PROGTYPE_ISSCALL; + break; + case PROGTYPE_LIBF: + case PROGTYPE_ISSLIBF: + progtype = PROGTYPE_ISSLIBF; + break; + case PROGTYPE_ILS: + asm_error("Can't mix ISS and ILS"); + default: + bail("in x_libr, can't happen"); + } + + iss_number = atoi(mods); // get ISS number + + opfield[16] = '\0'; // be sure not to look too far into this + + nintlevels = 0; // # of interrupt levels for ISS + intlevel_primary = 0; // primary level for ISS and level for ILS + intlevel_secondary = 0; // secondary level for ISS + + if ((tok = strtok(opfield, " ")) == NULL) + asm_error("ISS missing entry label"); + else + x_ent(NULL, label, "", arg); // process as an ENT + + if ((tok = strtok(NULL, " ")) != NULL) { // get associated levels + nintlevels++; + intlevel_primary = atoi(tok); + } + + if ((tok = strtok(NULL, " ")) != NULL) { + nintlevels++; + intlevel_secondary = atoi(tok); + } +} + +void x_spr (struct tag_op *op, char *label, char *mods, char *arg) +{ + realmode = REALMODE_STANDARD; +} + +void x_epr (struct tag_op *op, char *label, char *mods, char *arg) +{ + realmode = REALMODE_EXTENDED; +} + +void x_dsa (struct tag_op *op, char *label, char *mods, char *arg) +{ + unsigned short words[2]; + + setw(0, org, FALSE); // display origin + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + if (! *arg) { + asm_error("DSA missing filename"); + } + else { + namecode(words, arg); + writetwo(); + writew(words[0], CALL); // special relocation bits here 3 and 1 + writew(words[1], RELATIVE); + } +} + +void x_link (struct tag_op *op, char *label, char *mods, char *arg) +{ + unsigned short words[2]; + char nline[128]; + + setw(0, org, FALSE); // display origin + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + if (! *arg) { + asm_error("LINK missing program name"); + } + else { + format_line(nline, label, "CALL", "", "$LINK", ""); + parse_line(nline); + + namecode(words, arg); + writew(words[0], ABSOLUTE); // special relocation bits here 3 and 1 + writew(words[1], ABSOLUTE); + } +} + +void x_libf (struct tag_op *op, char *label, char *mods, char *arg) +{ + unsigned short words[2]; + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + if (! *arg) { + asm_error("LIBF missing argument"); + return; + } + + if (pass == 1) { // it will take one words in any case + org++; + return; + } + + setw(0, org, FALSE); // display origin + + namecode(words, arg); // emit namecode for loader + + writetwo(); + writew(words[0], LIBF); // this one does NOT advance org! + writew(words[1], ABSOLUTE); +} + +void x_file (struct tag_op *op, char *label, char *mods, char *arg) +{ + int i, n, r; + EXPR vals[5]; + char *tok; + + for (i = 0; i < 5; i++) { + if ((tok = strtok(arg, ",")) == NULL) { + asm_error("FILE has insufficient arguments"); + return; + } + arg = NULL; // for next strtok call + + if (i == 3) { + if (strcmpi(tok, "U") != 0) + asm_error("Argument 4 must be the letter U"); + } + else if (getexpr(tok, FALSE, &vals[i]) == S_DEFINED) { + if (i <= 3 && vals[i].relative) + asm_error("Argument %d must be absolute", i+1); + else if (pass == 2 && vals[i].value == 0) + asm_error("Argument %d must be nonzero", i+1); + } + } + + writew(vals[0].value, ABSOLUTE); + writew(vals[1].value, ABSOLUTE); + writew(vals[2].value, ABSOLUTE); + writew(vals[4].value, vals[i].relative); + writew(0, ABSOLUTE); + n = MAX(1, vals[2].value); + r = 320/n; + writew(r, ABSOLUTE); + r = MAX(1, r); + writew((16*vals[1].value)/r, ABSOLUTE); + + if (pass == 2) + ndefined_files++; +} + +// --------------------------------------------------------------------------------- +// x_trap - place to set a breakpoint +// --------------------------------------------------------------------------------- + +void x_trap (struct tag_op *op, char *label, char *mods, char *arg) +{ + // debugging breakpoint +} + +// --------------------------------------------------------------------------------- +// x_ces - .CES directive (nonstandard). Specify a value for the console entry +// switches. When this program is loaded into the simulator, the switches will +// be set accordingly. Handy for bootstraps and other programs that read +// the switches. +// --------------------------------------------------------------------------------- + +void x_ces (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR expr; + + if (outmode != OUTMODE_LOAD) // this works only in our loader format + return; + + if (getexpr(arg, FALSE, &expr) != S_DEFINED) + return; + + if (pass == 2) + fprintf(fout, "S%04x" ENDLINE, expr.value & 0xFFFF); +} + +// --------------------------------------------------------------------------------- +// x_bss - BSS directive - reserve space in core +// --------------------------------------------------------------------------------- + +void x_bss (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR expr; + + org_advanced = FALSE; // * means this address + + if (! *arg) { + expr.value = 0; + expr.relative = ABSOLUTE; + } + else if (getexpr(arg, FALSE, &expr) != S_DEFINED) + return; + + if (strchr(mods, 'E') != NULL) // force even address + org_even(); + + if (expr.relative) + asm_error("BSS size must be an absolute value"); + + setw(0, org, FALSE); // display origin + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + if (expr.value < 0) + asm_warning("Negative BSS size"); + + else if (expr.value > 0) { + if (outmode == OUTMODE_LOAD) { + org += expr.value; // advance the origin by appropriate number of words + if (pass == 2) // emit new load address in output file + fprintf(fout, "@%04x%s" ENDLINE, org & 0xFFFF, relocate ? "R" : ""); + } + else { + org += expr.value; // advance the origin by appropriate number of words + if (pass == 2) + bincard_setorg(org); + } + } +} + +// --------------------------------------------------------------------------------- +// x_bes - Block Ended by Symbol directive. Like BSS but label gets address AFTER the space, instead of first address +// --------------------------------------------------------------------------------- + +void x_bes (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR expr; + + org_advanced = FALSE; // * means this address + + if (! *arg) { // arg field = space + expr.value = 0; + expr.relative = ABSOLUTE; + } + else if (getexpr(arg, FALSE, &expr) != S_DEFINED) + return; + + if (strchr(mods, 'E') != NULL && (org & 1) != 0) + org_even(); // force even address + + if (expr.relative) + asm_error("BES size must be an absolute value"); + + if (expr.value < 0) + asm_warning("Negative BES size"); + + else if (expr.value > 0) { + setw(0, org+expr.value, FALSE); // display NEW origin + + if (outmode == OUTMODE_LOAD) { + org += expr.value; // advance the origin + if (pass == 2) // emit new load address in output file + fprintf(fout, "@%04x%s" ENDLINE, org & 0xFFFF, relocate ? "R" : ""); + } + else { + org += expr.value; // advance the origin + bincard_setorg(org); + } + } + + if (*label) // NOW define the label + set_symbol(label, org, TRUE, relocate); +} + +// --------------------------------------------------------------------------------- +// x_dmes - DMES define message directive. Various encodings, none pretty. +// --------------------------------------------------------------------------------- + +int dmes_wd; +int dmes_nc; +enum {CODESET_CONSOLE, CODESET_1403, CODESET_1132, CODESET_EBCDIC} dmes_cs; +void stuff_dmes (int ch, int rpt); + +void x_dmes (struct tag_op *op, char *label, char *mods, char *arg) +{ + int rpt; + char *c = opfield; + BOOL cont = FALSE; + + if (dmes_saved) { // previous DMES had an odd character saved + dmes_wd = dmes_savew; + dmes_nc = 1; // stick it into the outbut buffer + } + else + dmes_nc = dmes_wd = 0; // clear output buffer + + trim(opfield); // remove trailing blanks from rest of input line (use whole thing) + setw(0, org, FALSE); // display origin + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + if (strchr(mods, '1') != NULL) // determine the encoding scheme + dmes_cs = CODESET_1403; + else if (strchr(mods, '2') != NULL) + dmes_cs = CODESET_1132; + else if (strchr(mods, '0') != NULL || ! *mods) + dmes_cs = CODESET_CONSOLE; + else { + asm_error("Invalid printer code in tag field"); + dmes_cs = CODESET_EBCDIC; + } + + while (*c) { // pick up characters + if (*c == '\'') { // quote (') is the escape character + c++; + + rpt = 0; // get repeat count + while (BETWEEN(*c, '0', '9')) { + rpt = rpt*10 + *c++ - '0'; + } + if (rpt <= 0) // no count = insert one copy + rpt = 1; + + switch (*c) { // handle escape codes + case '\'': + stuff_dmes(*c, 1); + break; + + case 'E': + *c = '\0'; // end + break; + + case 'X': + case 'S': + stuff_dmes(' ', rpt); + break; + + case 'F': + stuff_dmes(*++c, rpt); // repeat character + break; + + case ' ': + case '\0': + cont = TRUE; + *c = '\0'; // end + break; + + case 'T': + if (dmes_cs != CODESET_CONSOLE) { +badcode: asm_error("Invalid ' escape for selected printer"); + break; + } + stuff_dmes(0x41, -rpt); // tab + break; + + case 'D': + if (dmes_cs != CODESET_CONSOLE) goto badcode; + stuff_dmes(0x11, -rpt); // backspace + break; + + case 'B': + if (dmes_cs != CODESET_CONSOLE) goto badcode; + stuff_dmes(0x05, -rpt); // black + break; + + case 'A': + if (dmes_cs != CODESET_CONSOLE) goto badcode; + stuff_dmes(0x09, -rpt); // red + break; + + case 'R': + if (dmes_cs != CODESET_CONSOLE) goto badcode; + stuff_dmes(0x81, -rpt); // return + break; + + case 'L': + if (dmes_cs != CODESET_CONSOLE) goto badcode; + stuff_dmes(0x03, -rpt); // line feed + break; + + default: + asm_error("Invalid ' escape in DMES"); + *c = '\0'; + break; + } + } + else // just copy literal character + stuff_dmes(*c, 1); + + if (*c) + c++; + } + + dmes_saved = FALSE; + + if (dmes_nc) { // odd number of characters + if (cont) { + dmes_saved = TRUE; + dmes_savew = dmes_wd; // save for next time + } + else + stuff_dmes(' ', 1); // pad with a space to force out even # of characters + } +} + +// --------------------------------------------------------------------------------- +// stuff_dmes - insert 'rpt' copies of character 'ch' into output words +// --------------------------------------------------------------------------------- + +void stuff_dmes (int ch, int rpt) +{ + int nch, i; // nch is translated output value + + if (rpt < 0) { // negative repeat means no translation needed + rpt = -rpt; + nch = ch; + } + else { + switch (dmes_cs) { + case CODESET_CONSOLE: + nch = 0x21; + for (i = 0; i < 256; i++) { + if (conout_to_ascii[i] == ch) { + nch = i; + break; + } + } + break; + + case CODESET_EBCDIC: + nch = ascii_to_ebcdic_table[ch & 0x7F]; + if (nch == 0) + nch = 0x7F; + break; + + case CODESET_1403: + nch = ascii_to_1403_table[ch & 0x7F]; + if (nch == 0) + nch = 0x7F; + break; + + case CODESET_1132: + nch = 0x40; + for (i = 0; i < WHEELCHARS_1132; i++) { + if (codewheel1132[i].ascii == ch) { + nch = codewheel1132[i].ebcdic; + break; + } + } + break; + + default: + bail("bad cs in x_dmes, can't happen"); + break; + } + } + + while (--rpt >= 0) { // pack them into words, output when we have two + if (dmes_nc == 0) { + dmes_wd = (nch & 0xFF) << 8; + dmes_nc = 1; + } + else { + dmes_wd |= (nch & 0xFF); + writew(dmes_wd, FALSE); + dmes_nc = 0; + } + } +} + +// --------------------------------------------------------------------------------- +// x_ebc - handle EBCDIC string definition (delimited with periods) +// --------------------------------------------------------------------------------- + +void x_ebc (struct tag_op *op, char *label, char *mods, char *arg) +{ + char *p; + +// setw(0, org, FALSE); + if (*label) + set_symbol(label, org, TRUE, relocate); + + p = trim(opfield); // remove trailing blanks from rest of input line (use whole thing) + + if (*p != '.') { + asm_error("EBC data must start with ."); + return; + } + p++; // skip leading period + + dmes_nc = dmes_wd = 0; // clear output buffer (we're borrowing the DMES packer) + dmes_cs = CODESET_EBCDIC; + + while (*p && *p != '.') // store packed ebcdic + stuff_dmes(*p++, 1); + + if (dmes_nc) // odd number of characters + stuff_dmes(' ', 1); // pad with a space to force out even # of characters + + if (*p != '.') + asm_error("EBC missing closing ."); +} + +// --------------------------------------------------------------------------------- +// x_dn - define name DN directive. Pack 5 characters into two words. This by the +// way is the reason the language Forth is not Fourth. +// --------------------------------------------------------------------------------- + +void x_dn (struct tag_op *op, char *label, char *mods, char *arg) +{ + unsigned short words[2]; + + setw(0, org, FALSE); // display origin + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + namecode(words, arg); + + writew(words[0], ABSOLUTE); + writew(words[1], ABSOLUTE); +} + +// --------------------------------------------------------------------------------- +// x_dump - DUMP directive - pretend we saw "call $dump, call $exit" +// --------------------------------------------------------------------------------- + +void x_dump (struct tag_op *op, char *label, char *mods, char *arg) +{ + x_pdmp(op, label, mods, arg); + x_exit(NULL, "", "", ""); // compile "call $exit" +} + +// --------------------------------------------------------------------------------- +// x_pdmp - PDMP directive - like DUMP but without the call $exit +// --------------------------------------------------------------------------------- + +void x_pdmp (struct tag_op *op, char *label, char *mods, char *arg) +{ + char nline[200], *tok; + EXPR addr[3]; + int i; + + for (i = 0, tok = strtok(arg, ","); i < 3 && tok != NULL; i++, tok = strtok(NULL, ",")) { + if (getexpr(tok, FALSE, addr+i) != S_DEFINED) { + addr[i].value = (i == 1) ? 0x3FFF : 0; + addr[i].relative = ABSOLUTE; + } + } + + org_advanced = FALSE; // * means this address+1 + + format_line(nline, label, "BSI", "L", DOLLARDUMP, ""); + parse_line(nline); // compile "call $dump" + + writew(addr[2].value, ABSOLUTE); // append arguments (0, start, end address) + writew(addr[0].value, addr[0].relative); + writew(addr[1].value, addr[1].relative); +} + +// --------------------------------------------------------------------------------- +// x_hdng - HDNG directive +// --------------------------------------------------------------------------------- + +void x_hdng (struct tag_op *op, char *label, char *mods, char *arg) +{ + char *c; + + // label is not entered into the symbol table + + if (flist == NULL || ! list_on) { + line_error = TRUE; // inhibit listing: don't print the HDNG statement + return; + } + + line_error = TRUE; // don't print the statement + + c = skipbl(opfield); + trim(c); + fprintf(flist, "\f%s\n\n", c); // print page header +} + +// --------------------------------------------------------------------------------- +// x_list - LIST directive. enable or disable listing +// --------------------------------------------------------------------------------- + +void x_list (struct tag_op *op, char *label, char *mods, char *arg) +{ + BOOL on; + + // label is not entered into the symbol table + + line_error = TRUE; // don't print the LIST statement + + if (flist == NULL || ! list_on) { + return; + } + + if (strcmpi(arg, "ON") == 0) + on = TRUE; + else if (strcmpi(arg, "OFF") == 0) + on = FALSE; + else + on = do_list; + + list_on = on; +} + +// --------------------------------------------------------------------------------- +// x_spac - SPAC directive. Put blank lines in listing +// --------------------------------------------------------------------------------- + +void x_spac (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR expr; + + // label is not entered into the symbol table + + if (flist == NULL || ! list_on) { + line_error = TRUE; // don't print the SPAC statement + return; + } + + if (getexpr(arg, FALSE, &expr) != S_DEFINED) + return; + + line_error = TRUE; // don't print the statement + + while (--expr.value >= 0) + putc('\n', flist); +} + +// --------------------------------------------------------------------------------- +// x_ejct - EJCT directive - put formfeed in listing +// --------------------------------------------------------------------------------- + +void x_ejct (struct tag_op *op, char *label, char *mods, char *arg) +{ + // label is not entered into the symbol table + + if (flist == NULL || ! list_on) { + line_error = TRUE; // don't print the EJCT statement + return; + } + + line_error = TRUE; // don't print the statement + + putc('\f', flist); +} + +// --------------------------------------------------------------------------------- +// basic_opcode - construct a standard opcode value from op table entry and modifier chars +// --------------------------------------------------------------------------------- + +int basic_opcode (struct tag_op *op, char *mods) +{ + int opcode = op->opcode; // basic code value + + if (strchr(mods, '1') != 0) // indexing + opcode |= 0x0100; + else if (strchr(mods, '2') != 0) + opcode |= 0x0200; + else if (strchr(mods, '3') != 0) + opcode |= 0x0300; + + if (strchr(mods, 'L')) { // two-word format + opcode |= OP_LONG; + if (strchr(mods, 'I') != 0) // and indirect to boot + opcode |= OP_INDIRECT; + } + + return opcode; +} + +// --------------------------------------------------------------------------------- +// std_op - assemble a vanilla opcode +// --------------------------------------------------------------------------------- + +void std_op (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR expr; + int opcode = basic_opcode(op, mods); + BOOL val_ok = FALSE; + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + if (*arg && ! (op->flags & NO_ARGS)) { // get value argument + if (getexpr(arg, FALSE, &expr) == S_DEFINED) + val_ok = TRUE; + } + else { + expr.value = 0; + expr.relative = FALSE; + } + + if (opcode & OP_LONG) { // two-word format, just write code and value + writew(opcode, FALSE); + writew(expr.value, expr.relative); + } + else { // one-word format + if (strchr(mods, 'I') != 0) + asm_error("Indirect mode not permitted on one-word instructions"); + + if (val_ok && ! (strchr(mods, 'X') || (op->flags & IS_ABS) || ((opcode & OP_INDEXED) && ! (op->flags & NO_IDX)))) + expr.value -= (org+1); // compute displacement + + if (expr.value < -128 || expr.value > 127) {// check range + asm_error("Offset of %d is too large", expr.value); + expr.value = 0; + } + + writew(opcode | (expr.value & 0x00FF), FALSE);// that's the code + } +} + +// --------------------------------------------------------------------------------- +// mdx_op - assemble a MDX family instruction +// --------------------------------------------------------------------------------- + +void mdx_op (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR dest, incr = {0, FALSE}; + int opcode = basic_opcode(op, mods); + char *tok; + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + if ((tok = strtok(arg, ",")) == NULL) { // argument format is dest[,increment] +// asm_error("Destination not specified"); // seems not to be an error, IBM omits it sometimes + dest.value = 0; + dest.relative = ABSOLUTE; + } + else + getexpr(tok, FALSE, &dest); // parse the address + + tok = strtok(NULL, ","); // look for second argument + + if (opcode & OP_LONG) { // two word format + if (opcode & OP_INDEXED) { // format: MDX 2 dest + if (tok != NULL) + asm_error("This format takes only one argument"); + } + else { // format: MDX dest,increment + if (opcode & OP_INDIRECT) + asm_error("Indirect can't be used without indexing"); + + if (tok == NULL) { +// asm_error("This format takes two arguments"); + incr.value = 0; + incr.relative = ABSOLUTE; + } + else + getexpr(tok, FALSE, &incr); + + if (incr.value < -128 || incr.value >= 127) // displacement style + asm_error("Invalid increment value (8 bits signed)"); + + opcode |= (incr.value & 0xFF); + } + + writew(opcode, ABSOLUTE); + writew(dest.value, dest.relative); + } + else { // one word format MDX val + if (tok != NULL) + asm_error("This format takes only one argument"); + + if (! (strchr(mods, 'X') || (opcode & OP_INDEXED))) + dest.value -= (org+1); // compute displacement + + if (dest.value < -128 || dest.value > 127) + asm_error("Offset/Increment of %d is too large", dest.value); + + writew(opcode | (dest.value & 0xFF), FALSE); + } +} + +// --------------------------------------------------------------------------------- +// bsi_op - BSI long instruction is like a BSC L, short is standard +// --------------------------------------------------------------------------------- + +void bsi_op (struct tag_op *op, char *label, char *mods, char *arg) +{ + if (strchr(mods, 'L') || strchr(mods, 'I')) + bsc_op(op, label, mods, arg); + else + std_op(op, label, mods, arg); +} + +// --------------------------------------------------------------------------------- +// b_op - branch; use short or long version +// -------------------------------------------------------------------------------- + +void b_op (struct tag_op *op, char *label, char *mods, char *arg) +{ + static struct tag_op *mdx = NULL; + + if (strchr(mods, 'L') || strchr(mods, 'I')) { + bsi_op(op, label, mods, arg); + return; + } + + if (mdx == NULL) + if ((mdx = lookup_op("MDX")) == NULL) + bail("Can't find MDX op"); + + (mdx->handler)(mdx, label, mods, arg); +} + +// --------------------------------------------------------------------------------- +// bsc_op - compute a BSC family instruction +// --------------------------------------------------------------------------------- + +void bsc_op (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR dest; + int opcode = basic_opcode(op, mods); + char *tok, *tests; + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + if (opcode & OP_LONG) { // two word format + if ((tok = strtok(arg, ",")) == NULL) { // format is BSC dest[,tests] + asm_error("Destination not specified"); + dest.value = 0; + dest.relative = ABSOLUTE; + } + else + getexpr(tok, FALSE, &dest); + + tests = strtok(NULL, ","); // get test characters + } + else + tests = arg; // short format is BSC tests + + if (tests != NULL) { // stick in the testing bits + for (; *tests; tests++) { + switch (*tests) { + // bit 0x40 is the BOSC bit + case 'Z': opcode |= 0x20; break; + case '-': opcode |= 0x10; break; + case '+': + case '&': opcode |= 0x08; break; + case 'E': opcode |= 0x04; break; + case 'C': opcode |= 0x02; break; + case 'O': opcode |= 0x01; break; + default: + asm_error("Invalid test flag: '%c'", *tests); + } + } + } + + writew(opcode, ABSOLUTE); // emit code + if (opcode & OP_LONG) + writew(dest.value, dest.relative); +} + +// --------------------------------------------------------------------------------- +// shf_op - assemble a shift instruction +// --------------------------------------------------------------------------------- + +void shf_op (struct tag_op *op, char *label, char *mods, char *arg) +{ + EXPR expr; + int opcode = basic_opcode(op, mods); + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + + if (opcode & OP_INDEXED) { // shift value comes from index register + expr.value = 0; + expr.relative = ABSOLUTE; + } + else + getexpr(arg, FALSE, &expr); + + if (expr.relative) { + asm_error("Shift value is a relative address"); + expr.relative = ABSOLUTE; + } + + if (expr.value < 0 || expr.value > 32) { // check range + asm_error("Shift count of %d is invalid", expr.value); + expr.value = 0; + } + + writew(opcode | (expr.value & 0x3F), FALSE); // put shift count into displacement field +} + +// --------------------------------------------------------------------------------- +// x_mdm - MDM instruction +// --------------------------------------------------------------------------------- + +void x_mdm (struct tag_op *op, char *label, char *mods, char *arg) +{ + int opcode = basic_opcode(op, mods); + + if (*label) // define label + set_symbol(label, org, TRUE, relocate); + // oh dear: bug here + asm_error("'%s' is not yet supported", op->mnem); +} + +// --------------------------------------------------------------------------------- +// x_exit - EXIT directive. Assembler manual says it treats like CALL $EXIT, but +// object code reveals the truth: jump to $EXIT, which is a small value, so we can use LDX. +// --------------------------------------------------------------------------------- + +void x_exit (struct tag_op *op, char *label, char *mods, char *arg) +{ + char nline[120]; + + format_line(nline, label, "LDX", "X", DOLLAREXIT, ""); + parse_line(nline); +} + +// --------------------------------------------------------------------------------- +// x_opt - .OPT directive. Nonstandard. Possible values: +// +// .OPT CEXPR - use C precedence in evaluating expressions rather than strict left-right +// --------------------------------------------------------------------------------- + +void x_opt (struct tag_op *op, char *label, char *mods, char *arg) +{ + char *tok; + + org_advanced = FALSE; // * means this address + + if (*label) { + asm_error("Label not permitted on .OPT statement"); + return; + } + // look for OPT arguments + for (tok = strtok(arg, ","); tok != NULL; tok = strtok(NULL, ",")) { + if (strcmp(tok, "CEXPR") == 0) { + cexpr = TRUE; // use C expression precedence (untested) + } + else + asm_error("Unknown .OPT: '%s'", tok); + } +} + +// --------------------------------------------------------------------------------- +// askip - skip input lines until a line with the target label appears +// --------------------------------------------------------------------------------- + +void askip (char *target) +{ + char nline[200], cur_label[20], *c; + + while (get_line(nline, sizeof(nline), TRUE)) { // read next line (but don't exit a macro) + listout(FALSE); // end listing of previous input line + + prep_line(nline); // preform standard line prep + + strncpy(cur_label, nline, 6); // get first 5 characters + cur_label[5] = '\0'; + + for (c = cur_label; *c > ' '; c++) // truncate at first whitespace + ; + *c = '\0'; + // stop if there's a match + if ((target == NULL) ? (cur_label[0] == '\0') : strcmp(target, cur_label) == 0) { + parse_line(nline); // process this line + return; + } + } + + if (target != NULL) + asm_error("Label %s not found", target); +} + +// --------------------------------------------------------------------------------- +// x_aif - process conditional assembly jump +// --------------------------------------------------------------------------------- + +void x_aif (struct tag_op *op, char *label, char *mods, char *arg) +{ + char *target, *tok; + EXPR expr1, expr2; + BOOL istrue; + enum {OP_EQ, OP_LT, OP_GT, OP_NE, OP_LE, OP_GE} cmp_op; + + // label is not entered into the symbol table + + arg = skipbl(arg); + if (*arg != '(') { + asm_error("AIF operand must start with ("); + return; + } + + arg++; // skip the paren + + // normally whitespace is never found in the arg string (see tabtok and coltok). + // However, spaces inside parens are permitted. + + if ((tok = strtok(arg, whitespace)) == NULL) { + asm_error("AIF missing first expression"); + return; + } + + getexpr(tok, FALSE, &expr1); + + if ((tok = strtok(NULL, whitespace)) == NULL) { + asm_error("AIF missing conditional operator"); + return; + } + + if (strcmp(tok, "EQ") == 0) + cmp_op = OP_EQ; + else if (strcmp(tok, "LT") == 0) + cmp_op = OP_LT; + else if (strcmp(tok, "GT") == 0) + cmp_op = OP_GT; + else if (strcmp(tok, "NE") == 0) + cmp_op = OP_NE; + else if (strcmp(tok, "LE") == 0) + cmp_op = OP_LE; + else if (strcmp(tok, "GE") == 0) + cmp_op = OP_GE; + else { + asm_error("AIF: %s is not a valid conditional operator", tok); + return; + } + + if ((tok = strtok(NULL, ")")) == NULL) { + asm_error("AIF missing second expression"); + return; + } + + getexpr(tok, FALSE, &expr2); + + switch (cmp_op) { // test the condition + case OP_EQ: istrue = expr1.value == expr2.value; break; + case OP_LT: istrue = expr1.value < expr2.value; break; + case OP_GT: istrue = expr1.value > expr2.value; break; + case OP_NE: istrue = expr1.value != expr2.value; break; + case OP_LE: istrue = expr1.value <= expr2.value; break; + case OP_GE: istrue = expr1.value >= expr2.value; break; + default: bail("in aif, can't happen"); + } + + // After the closing paren coltok and tabtok guarantee we will have no whitespace + + if ((target = strtok(arg, ",")) == NULL) // get target label + asm_warning("Missing target label"); + + if (istrue) + askip(target); // skip to the target +} + +// --------------------------------------------------------------------------------- +// x_aifb - conditional assembly jump back (macro only) +// --------------------------------------------------------------------------------- + +void x_aifb (struct tag_op *op, char *label, char *mods, char *arg) +{ + asm_error("aifb valid in macros only and not implemented in any case"); +} + +// --------------------------------------------------------------------------------- +// x_ago +// --------------------------------------------------------------------------------- + +void x_ago (struct tag_op *op, char *label, char *mods, char *arg) +{ + char *target; + + // label is not entered into the symbol table + + // handle differently in a macro + + if ((target = strtok(arg, ",")) == NULL) // get target label + asm_warning("Missing target label"); + + askip(target); // skip to the target +} + +// --------------------------------------------------------------------------------- +// --------------------------------------------------------------------------------- + +void x_agob (struct tag_op *op, char *label, char *mods, char *arg) +{ + asm_error("agob valid in macros only and not implemented in any case"); +} + +// --------------------------------------------------------------------------------- +// --------------------------------------------------------------------------------- + +void x_anop (struct tag_op *op, char *label, char *mods, char *arg) +{ + // label is not entered into the symbol table + // do nothing else +} + +// --------------------------------------------------------------------------------- +// expression parser, borrowed from older code, no comments, sorry +// --------------------------------------------------------------------------------- + +char *exprptr, *oexprptr; + +#define GETNEXT (*exprptr++) +#define UNGET --exprptr + +#define LETTER 0 /* character types */ +#define DIGIT 1 +#define ETC 2 +#define ILL 3 +#define SPACE 4 +#define MULOP 5 +#define ADDOP 6 +#define EXPOP 7 + +int getnb (void); +void c_expr (EXPR *ap); +void c_expr_m (EXPR *ap); +void c_expr_e (EXPR *ap); +void c_expr_u (EXPR *ap); +void c_term (EXPR *ap); +int c_number (int c, int r, int nchar); +int digit (int c, int r); +int c_esc (int c); +void exprerr (int n); +void a1130_expr (EXPR *ap); +void a1130_term (EXPR *ap); + +char ctype[128] = { // character types +/*^0ABCDEFG */ ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, +/*^HIJKLMNO */ ILL, SPACE, SPACE, ILL, SPACE, SPACE, ILL, ILL, +/*^PQRSTUVW */ ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, +/*^XYZ */ ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL, +/* !"#$%&' */ SPACE, ETC, ETC, LETTER, LETTER, MULOP, MULOP, LETTER, /* $ # @ and ' are letters here */ +/* ()*+,-./ */ ETC, ETC, MULOP, ADDOP, ETC, ADDOP, ETC, MULOP, +/* 01234567 */ DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, DIGIT, +/* 89:;<=>? */ DIGIT, DIGIT, ETC, ETC, MULOP, ETC, MULOP, ETC, +/* @ABCDEFG */ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/* HIJKLMNO */ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/* PQRSTUVW */ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/* XYZ[\]^_ */ LETTER, LETTER, LETTER, ETC, ETC, ETC, EXPOP, LETTER, +/* `abcdefg */ ETC, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/* hijklmno */ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/* pqrstuvw */ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, +/* xyz{|}~ */ LETTER, LETTER, LETTER, ETC, ADDOP, ETC, ETC, ETC +}; + +char *errstr[] = { + "Missing exponent", // 0 + "Undefined symbol", // 1 + "Division by zero", // 2 + "Illegal operator", // 3 + ") expected", // 4 + "Char expected after '", // 5 + "Char expected after .", // 6 + "Number expected after =", // 7 + "Syntax error", // 8 + "Number syntax", // 9 + "Char expected after \\", // 10 + "Relocation error" // 11 +}; + +int getnb () { + int c; + + if (cexpr) { // in C mode, handle normally + while (ctype[(c = GETNEXT)] == SPACE) + ; + } // in 1130 mode, a space terminates the expression. Here, eat the rest + else if ((c = GETNEXT) == ' ') { + while ((c = GETNEXT) != '\0') + ; + } + + return c; +} + +int symbest, exprerrno; +jmp_buf exprjmp; + +// --------------------------------------------------------------------------------- +// getexpr +// --------------------------------------------------------------------------------- + +int getexpr (char *pc, BOOL undefined_ok, EXPR *pval) +{ + symbest = S_DEFINED; // assume no questionable symbols + + pval->value = 0; + pval->relative = ABSOLUTE; + + if (! *pc) // blank expression is same as zero, ok? + return S_DEFINED; + + if (setjmp(exprjmp) != 0) { // encountered a syntax error & bailed + pval->value = 0; + pval->relative = ABSOLUTE; + return S_UNDEFINED; + } + + exprptr = oexprptr = pc; // make global the buffer pointer + + c_expr(pval); + + if (GETNEXT) // expression should have been entirely eaten + exprerr(8); // if characters are left, it's an error + + if (pval->relative < 0 || pval->relative > 1) + exprerr(11); // has to work out to an absolute or a single relative term + + if (symbest == S_DEFINED) // tell how it came out + return S_DEFINED; + + pval->value = 0; + pval->relative = ABSOLUTE; + return (pass == 1 && undefined_ok) ? S_PROVISIONAL : S_UNDEFINED; +} + +// --------------------------------------------------------------------------------- +// output_literals - construct .DC assembler lines to assemble pending literal +// constant values that have accumulated. +// --------------------------------------------------------------------------------- + +void output_literals (BOOL eof) +{ + char line[120], label[12], num[20]; + int i; + + for (i = 0; i < n_literals; i++) { // generate DC statements for any pending literal constants + if (literal[i].even && literal[i].hex) // create the value string + sprintf(num, "/%08lx", literal[i].value); + else if (literal[i].even) + sprintf(num, "%ld", literal[i].value); + else if (literal[i].hex) + sprintf(num, "/%04x", literal[i].value & 0xFFFF); + else + sprintf(num, "%d", literal[i].value); + + sprintf(label, "_L%03d", literal[i].tagno); + format_line(line, label, literal[i].even ? "DEC" : "DC", "", num, "GENERATED LITERAL CONSTANT"); + + if (eof) { + eof = FALSE; // at end of file, for first literal, only prepare blank line + sprintf(listline, LEFT_MARGIN, org); + } + else + listout(TRUE); // push out any pending line(s) + + if (flist && list_on) // this makes stuff appear in the listing + sprintf(listline, LEFT_MARGIN " %s", detab(line)); + + nwout = 0; + + parse_line(line); // assemble the constant definition + } + + n_literals = 0; // clear list +} + +// --------------------------------------------------------------------------------- +// a1130_term - extract one term of an expression +// --------------------------------------------------------------------------------- + +void a1130_term (EXPR *ap) +{ + PSYMBOL s; + char token[80], *t; + int c; + + if (cexpr) { // use C syntax + c_term(ap); + return; + } + + c = GETNEXT; + + if (ctype[c] == DIGIT) { /* number */ + ap->value = c_number(c,10,-1); + ap->relative = ABSOLUTE; + } + else if (c == '+') { /* unary + */ + a1130_term(ap); + } + else if (c == '-') { /* unary - */ + a1130_term(ap); + ap->value = - ap->value; + } + else if (c == '/') { /* / starts a hex constant */ + ap->value = c_number(c,16,-1); + ap->relative = ABSOLUTE; + } + else if (c == '*') { /* asterisk alone = org */ + ap->value = org + org_advanced; // here is where that offset matters! + ap->relative = relocate; + } + else if (c == '.') { /* EBCDIC constant */ + c = GETNEXT; + if (c == '\0') { + UNGET; + c = ' '; + } + c = ascii_to_ebcdic_table[c]; + ap->value = c; // VALUE IS IN LOW BYTE!!! + ap->relative = ABSOLUTE; + } + else if (ctype[c] == LETTER) { /* symbol */ + t = token; + do { + *t++ = c; + c = GETNEXT; + } while (ctype[c] == LETTER || ctype[c] == DIGIT); + UNGET; + *t++ = '\0'; + + s = lookup_symbol(token, TRUE); + add_xref(s, FALSE); + ap->value = s->value; + ap->relative = s->relative; + + symbest = MIN(symbest, s->defined); // this goes to lowest value (undefined < provisional < defined) + if (pass == 2 && s->defined != S_DEFINED) + exprerr(1); + } + else + exprerr(8); +} + +// --------------------------------------------------------------------------------- +// c_expr - evalate an expression +// --------------------------------------------------------------------------------- + +void c_expr (EXPR *ap) +{ + int c; + EXPR rop; + + c_expr_m(ap); // get combined multiplicative terms + for (;;) { // handle +/- precedence operators + if (ctype[c=getnb()] != ADDOP) { + UNGET; + break; + } + c_expr_m(&rop); // right hand operand + switch (c) { + case '+': + ap->value += rop.value; + ap->relative += rop.relative; + break; + + case '-': + ap->value -= rop.value; + ap->relative -= rop.relative; + break; + + case '|': + if (ap->relative || rop.relative) + exprerr(11); + ap->value = ((long) (ap->value)) | ((long) rop.value); + break; + + default: + printf("In expr, can't happen\n"); + } + } +} + +// --------------------------------------------------------------------------------- +// c_expr_m - get multiplicative precedence terms. Again, this is not usually used +// --------------------------------------------------------------------------------- + +void c_expr_m (EXPR *ap) +{ + int c; + EXPR rop; + + c_expr_e(ap); // get exponential precedence term + for (;;) { // get operator + c = getnb(); + if ((c=='<') || (c=='>')) + if (c != getnb()) // << or >> + exprerr(3); + if (ctype[c] != MULOP) { + UNGET; + break; + } + c_expr_e(&rop); // right hand operand + + switch(c) { + case '*': + if (ap->relative && rop.relative) + exprerr(11); + + ap->value *= rop.value; + ap->relative = (ap->relative || rop.relative) ? RELATIVE : ABSOLUTE; + break; + + case '/': + if (rop.value == 0) + exprerr(2); + if (ap->relative || rop.relative) + exprerr(11); + + ap->value /= rop.value; + break; + + case '%': + if (rop.value == 0) + exprerr(2); + if (ap->relative || rop.relative) + exprerr(11); + + ap->value = ((long) (ap->value)) % ((long) rop.value); + break; + + case '&': + if (ap->relative || rop.relative) + exprerr(11); + + ap->value = ((long) (ap->value)) & ((long) rop.value); + break; + + case '>': + if (ap->relative || rop.relative) + exprerr(11); + + ap->value = ((long) (ap->value)) >> ((long) rop.value); + break; + + case '<': + if (ap->relative || rop.relative) + exprerr(11); + + ap->value = ((long) (ap->value)) << ((long) rop.value); + break; + + default: + printf("In expr_m, can't happen\n"); + } + } +} + +// --------------------------------------------------------------------------------- +// c_expr_e - get exponential precedence terms. Again, this is not usually used +// --------------------------------------------------------------------------------- + +void c_expr_e (EXPR *ap) +{ + int c, i, v; + EXPR rop; + + c_expr_u(ap); + for (;;) { + c = getnb(); + if (ctype[c] != EXPOP) { + UNGET; + break; + } + c_expr_u(&rop); + + switch(c) { + case '^': + if (ap->relative || rop.relative) + exprerr(11); + + v = ap->value; + ap->value = 1; + for (i = 0; i < rop.value; i++) + ap->value *= v; + break; + + default: + printf("In expr_e, can't happen\n"); + } + } +} + +// --------------------------------------------------------------------------------- +// c_expr_u - get unary precedence terms. Again, this is not usually used +// --------------------------------------------------------------------------------- + +void c_expr_u (EXPR *ap) +{ + int c; + + if ((c = getnb()) == '!') { + a1130_term(ap); + ap->value = ~ ((long)(ap->value)); + if (ap->relative) + exprerr(11); + } + else if (c == '-') { + a1130_term(ap); + ap->value = - ap->value; + if (ap->relative) + exprerr(11); + } + else { + UNGET; + a1130_term(ap); + } +} + +// --------------------------------------------------------------------------------- +// c_term - get basic operand or parenthesized expression. Again, this is not usually used +// --------------------------------------------------------------------------------- + +void c_term (EXPR *ap) +{ + int c, cc; + PSYMBOL s; + char token[80], *t; + + ap->relative = ABSOLUTE; /* assume absolute */ + + if ((c = getnb()) == '(') { /* parenthesized expr */ + c_expr(ap); /* start over at the top! */ + if ((cc = getnb()) != ')') + exprerr(4); + } + else if (c == '\'') { /* single quote: char */ + if ((c = GETNEXT) == '\0') + c = ' '; + ap->value = c_esc(c); + } + else if (ctype[c] == DIGIT) { /* number */ + ap->value = c_number(c,10,-1); + } + else if (c == '0') { /* 0 starts a hex or octal constant */ + if ((c = GETNEXT) == 'x') { + c = GETNEXT; + ap->value = c_number(c,16,-1); + } + else { + ap->value = c_number(c,8,-1); + } + } + else if (c == '*') { /* asterisk alone = org */ + ap->value = org + org_advanced; + ap->relative = relocate; + } + else if (ctype[c] == LETTER) { /* symbol */ + t = token; + do { + *t++ = c; + c = GETNEXT; + } while (ctype[c] == LETTER || ctype[c] == DIGIT); + UNGET; + *t++ = '\0'; + + s = lookup_symbol(token, TRUE); + ap->value = s->value; + ap->relative = s->relative; + add_xref(s, FALSE); + symbest = MIN(symbest, s->defined); // this goes to lowest value (undefined < provisional < defined) + + if (pass == 2 && s->defined != S_DEFINED) + exprerr(1); + } + else + exprerr(8); +} + +// --------------------------------------------------------------------------------- +// c_number - get a C format constant value. Again, this is not usually used +// --------------------------------------------------------------------------------- + +int c_number (int c, int r, int nchar) +{ + int v, n; + + nchar--; + + if (c == '/' && ! cexpr) { /* special radix stuff */ + r = 16; + c = GETNEXT; + } + else if (r == 10 && c == '0' && cexpr) { /* accept C style 0x## also */ + c = GETNEXT; + if (c == 'x') { + r = 16; + c = GETNEXT; + } + else { + r = 8; + UNGET; + c = '0'; + } + } + + n = 0; /* decode number */ + while ((nchar-- != 0) && (v = digit(c, r)) >= 0) { + if (v >= r) /* out of range! */ + exprerr(9); + + n = r*n + v; + + c = GETNEXT; + if (c == '.') { // maybe make it decimal? + c = GETNEXT; + break; + } + } + + UNGET; + return (n); +} + +// --------------------------------------------------------------------------------- +// digit - get digit value of character c in radix r +// --------------------------------------------------------------------------------- + +int digit (int c, int r) +{ + if (r == 16) { + if (c >= 'A' && c <= 'F') + return (c - 'A' + 10); + } + + if (c >= '0' && c <= '9') + return (c - '0'); + + return (-1); +} + +// --------------------------------------------------------------------------------- +// c_esc - handle C character escape +// --------------------------------------------------------------------------------- + +int c_esc (int c) +{ + if (c != '\\') /* not escaped */ + return(c); + + if ((c = GETNEXT) == '\0') /* must be followed by something */ + exprerr(10); + if ((c >= 'A') && (c <= 'Z')) /* handle upper case */ + c += 'a'-'A'; + if (ctype[c] == LETTER) /* control character abbrevs */ + switch (c) { + case 'b': c = '\b'; break; /* backspace */ + case 'e': c = 27 ; break; /* escape */ + case 'f': c = '\f'; break; /* formfeed */ + case 'n': c = '\n'; break; /* newline */ + case 'r': c = '\r'; break; /* return */ + case 't': c = '\t'; break; /* horiz. tab */ + } + else if (ctype[c] == DIGIT) { /* get character by the numbers */ + c = c_number(c,8,3); /* force octal */ + } + + return c; +} + +// --------------------------------------------------------------------------------- +// exprerr - note an expression syntax error. Longjumps back to caller with failure code +// --------------------------------------------------------------------------------- + +void exprerr (int n) +{ + char msg[256]; + int nex = exprptr-oexprptr; + + strncpy(msg, oexprptr, nex); // show where the problem was + msg[nex] = '\0'; + strcat(msg, " << "); + strcat(msg, errstr[n]); + + asm_error(msg); + + exprerrno = n; + longjmp(exprjmp, 1); +} + +/* ------------------------------------------------------------------------ + * upcase - force a string to uppercase (ASCII) + * ------------------------------------------------------------------------ */ + +char *upcase (char *str) +{ + char *s; + + for (s = str; *s; s++) { + if (*s >= 'a' && *s <= 'z') + *s -= 32; + } + + return str; +} + +/* ------------------------------------------------------------------------ + * hollerith table for IPL card ident field + * ------------------------------------------------------------------------ */ + +typedef struct { + int hollerith; + char ascii; +} CPCODE; + +static CPCODE cardcode_029[] = +{ + 0x0000, ' ', + 0x8000, '&', // + in 026 Fortran + 0x4000, '-', + 0x2000, '0', + 0x1000, '1', + 0x0800, '2', + 0x0400, '3', + 0x0200, '4', + 0x0100, '5', + 0x0080, '6', + 0x0040, '7', + 0x0020, '8', + 0x0010, '9', + 0x9000, 'A', + 0x8800, 'B', + 0x8400, 'C', + 0x8200, 'D', + 0x8100, 'E', + 0x8080, 'F', + 0x8040, 'G', + 0x8020, 'H', + 0x8010, 'I', + 0x5000, 'J', + 0x4800, 'K', + 0x4400, 'L', + 0x4200, 'M', + 0x4100, 'N', + 0x4080, 'O', + 0x4040, 'P', + 0x4020, 'Q', + 0x4010, 'R', + 0x3000, '/', + 0x2800, 'S', + 0x2400, 'T', + 0x2200, 'U', + 0x2100, 'V', + 0x2080, 'W', + 0x2040, 'X', + 0x2020, 'Y', + 0x2010, 'Z', + 0x0820, ':', + 0x0420, '#', // = in 026 Fortran + 0x0220, '@', // ' in 026 Fortran + 0x0120, '\'', + 0x00A0, '=', + 0x0060, '"', + 0x8820, 'c', // cent + 0x8420, '.', + 0x8220, '<', // ) in 026 Fortran + 0x8120, '(', + 0x80A0, '+', + 0x8060, '|', + 0x4820, '!', + 0x4420, '$', + 0x4220, '*', + 0x4120, ')', + 0x40A0, ';', + 0x4060, 'n', // not + 0x2820, 'x', // what? + 0x2420, ',', + 0x2220, '%', // ( in 026 Fortran + 0x2120, '_', + 0x20A0, '>', + 0x2060, '>', +}; + +int ascii_to_hollerith (int ch) +{ + int i; + + for (i = 0; i < sizeof(cardcode_029) / sizeof(CPCODE); i++) + if (cardcode_029[i].ascii == ch) + return cardcode_029[i].hollerith; + + return 0; +} + +/* ------------------------------------------------------------------------ + * detab - replace tabs with spaces for listing files + * ------------------------------------------------------------------------ */ + +char *detab (char *instr) +{ + static char outstr[256]; + char *out = outstr; + int col = 0; + + while (*instr) { + if (*instr == '\t') { + do { + *out++ = ' '; + col++; + } + while (col & 7); + } + else { + *out++ = *instr; + col++; + } + + instr++; + } + + *out = '\0'; + + return outstr; +} + + +#ifndef WIN32 + +int strnicmp (char *a, char *b, int n) +{ + int ca, cb; + + for (;;) { + if (--n < 0) // still equal after n characters? quit now + return 0; + + if ((ca = *a) == 0) // get character, stop on null terminator + return *b ? -1 : 0; + + if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase + ca -= 32; + + cb = *b; + if (cb >= 'a' && cb <= 'z') + cb -= 32; + + if ((ca -= cb) != 0) // if different, return comparison + return ca; + + a++, b++; + } +} + +int strcmpi (char *a, char *b) +{ + int ca, cb; + + for (;;) { + if ((ca = *a) == 0) // get character, stop on null terminator + return *b ? -1 : 0; + + if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase + ca -= 32; + + cb = *b; + if (cb >= 'a' && cb <= 'z') + cb -= 32; + + if ((ca -= cb) != 0) // if different, return comparison + return ca; + + a++, b++; + } +} + +#endif diff --git a/Ibm1130/asm1130.mak b/Ibm1130/asm1130.mak new file mode 100644 index 00000000..b072c224 --- /dev/null +++ b/Ibm1130/asm1130.mak @@ -0,0 +1,161 @@ +# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=Win32 Debug +!MESSAGE No configuration specified. Defaulting to Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "asm1130.mak" CFG="Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "Win32 Debug" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "WinRel" +# PROP BASE Intermediate_Dir "WinRel" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "WinRel" +# PROP Intermediate_Dir "WinRel" +OUTDIR=.\WinRel +INTDIR=.\WinRel + +ALL : $(OUTDIR)/asm1130.exe $(OUTDIR)/asm1130.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"asm1130.pch" /Fo$(INTDIR)/ /c +CPP_OBJS=.\WinRel/ +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"asm1130.bsc" +BSC32_SBRS= \ + $(INTDIR)/asm1130.sbr + +$(OUTDIR)/asm1130.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\ + /INCREMENTAL:no /PDB:$(OUTDIR)/"asm1130.pdb" /MACHINE:I386\ + /OUT:$(OUTDIR)/"asm1130.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/asm1130.obj + +$(OUTDIR)/asm1130.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "WinDebug" +# PROP BASE Intermediate_Dir "WinDebug" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "WinDebug" +# PROP Intermediate_Dir "WinDebug" +OUTDIR=.\WinDebug +INTDIR=.\WinDebug + +ALL : $(OUTDIR)/asm1130.exe $(OUTDIR)/asm1130.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"asm1130.pch" /Fo$(INTDIR)/\ + /Fd$(OUTDIR)/"asm1130.pdb" /c +CPP_OBJS=.\WinDebug/ +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"asm1130.bsc" +BSC32_SBRS= \ + $(INTDIR)/asm1130.sbr + +$(OUTDIR)/asm1130.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\ + /INCREMENTAL:yes /PDB:$(OUTDIR)/"asm1130.pdb" /DEBUG /MACHINE:I386\ + /OUT:$(OUTDIR)/"asm1130.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/asm1130.obj + +$(OUTDIR)/asm1130.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Group "Source Files" + +################################################################################ +# Begin Source File + +SOURCE=.\asm1130.c + +$(INTDIR)/asm1130.obj : $(SOURCE) $(INTDIR) + +# End Source File +# End Group +# End Project +################################################################################ diff --git a/Ibm1130/bindump.c b/Ibm1130/bindump.c new file mode 100644 index 00000000..478f3e3c --- /dev/null +++ b/Ibm1130/bindump.c @@ -0,0 +1,752 @@ +/* + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org + */ + +// --------------------------------------------------------------------------------- +// BINDUMP - dumps card deck files in assembler object format +// +// Usage: +/// bindump deckfile lists object header info & sector break cards +// bindump -v deckfile lists object data records as well +// bindump -p deckfile for system program, lists phase IDs in the deck +// bindump -s deckfile >outfile for system program, sorts the phases & writes to stdout + +#include +#include +#ifdef WIN32 +# include +# include +# include +#endif + +#ifndef TRUE + #define BOOL int + #define TRUE 1 + #define FALSE 0 +#endif + +typedef enum {R_ABSOLUTE = 0, R_RELATIVE = 1, R_LIBF = 2, R_CALL = 3} RELOC; + +BOOL verbose = FALSE; +BOOL phid = FALSE; +BOOL sort = FALSE; +unsigned short card[80], buf[54], cardtype; + +// bindump - dump a binary (card format) deck to verify sbrks, etc + +void bail (char *msg); +void dump (char *fname); +void dump_data (char *fname); +void dump_phids (char *fname); +char *getname (unsigned short *ptr); +char *getseq (void); +int hollerith_to_ascii (unsigned short h); +void process (char *fname); +void show_raw (char *name); +void show_data (void); +void show_core (void); +void show_endc (void); +void show_81 (void); +void show_main (void); +void show_sub (void); +void show_ils (void); +void show_iss (void); +void show_end (void); +void sort_phases (char *fname); +void trim (char *s); +void unpack (unsigned short *card, unsigned short *buf); +void verify_checksum(unsigned short *buf); + +int main (int argc, char **argv) +{ + char *arg; + static char usestr[] = "Usage: bindump [-psv] filename..."; + int i; + + for (i = 1; i < argc; i++) { + arg = argv[i]; + if (*arg == '-') { + arg++; + while (*arg) { + switch (*arg++) { + case 'v': + verbose = TRUE; + break; + case 'p': + phid = TRUE; // print only phase ID's + break; + case 's': + sort = TRUE; // sort deck by phases, writing to stdout + break; + default: + bail(usestr); + } + } + } + } + + for (i = 1; i < argc; i++) { + arg = argv[i]; + if (*arg != '-') + process(arg); + } + return 0; +} + +void process (char *nm) +{ +#ifdef WIN32 + WIN32_FIND_DATA fd; + HANDLE hFind; + char *c, buf[256]; + + if (strchr(nm, '*') == NULL && strchr(nm, '?') == NULL) + dump(nm); + + else if ((hFind = FindFirstFile(nm, &fd)) == INVALID_HANDLE_VALUE) + fprintf(stderr, "No files matching '%s'\n", nm); + + else { + if ((c = strrchr(nm, '\\')) == NULL) + c = strrchr(nm, ':'); + + do { + if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + continue; + + if (c == NULL) + dump(fd.cFileName); + else { + strcpy(buf, nm); + strcpy(buf + (c-nm+1), fd.cFileName); + dump(buf); + } + + } while (FindNextFile(hFind, &fd)); + + FindClose(hFind); + } +#else + dump(nm); // on unices, sh globs for us +#endif +} + +void dump (char *fname) +{ + if (sort) + sort_phases(fname); + else if (phid) + dump_phids(fname); + else + dump_data(fname); +} + +struct tag_card { + int phid, seq; + unsigned short card[80]; +}; + +int cardcomp (const void *a, const void *b) +{ + short diff; + + diff = ((struct tag_card *) a)->phid - ((struct tag_card *) b)->phid; + + return diff ? diff : (((struct tag_card *) a)->seq - ((struct tag_card *) b)->seq); +} + +void sort_phases (char *fname) +{ + int i, ncards, cardtype, len, seq = 0, phid; + struct tag_card *deck; + FILE *fd; + BOOL saw_sbrk = TRUE; + + if ((fd = fopen(fname, "rb")) == NULL) { + perror(fname); + return; + } + + fseek(fd, 0, SEEK_END); + len = ftell(fd); // get length of file + fseek(fd, 0, SEEK_SET); + + if (len <= 0 || (len % 160) != 0) { + fprintf(stderr, "%s is not a binard deck image\n"); + fclose(fd); + return; + } + + ncards = len / 160; + + if ((deck = (struct tag_card *) malloc(ncards*sizeof(struct tag_card))) == NULL) { + fprintf(stderr, "%s: can't sort, insufficient memory\n"); + fclose(fd); + return; + } + + phid = 0; + for (i = 0; i < ncards; i++) { + if (fread(deck[i].card, sizeof(card[0]), 80, fd) != 80) { + free(deck); + fprintf(stderr, "%s: error reading deck\n"); + fclose(fd); + return; + } + + unpack(deck[i].card, buf); + deck[i].seq = seq++; + deck[i].phid = phid; + + verify_checksum(buf); + + cardtype = (buf[2] >> 8) & 0xFF; + + if (cardtype == 1 || cardtype == 2) { // start of deck is same as sector break + saw_sbrk = TRUE; + } + else if (cardtype == 0) { + fprintf(stderr, "%s is a core image deck\n"); + free(deck); + fclose(fd); + return; + } + else if (cardtype == 0x0A && saw_sbrk) { + phid = (int) (signed short) buf[10]; + if (phid < 0) + phid = -phid; + + deck[i].phid = phid; // this belongs to the new phase + deck[i-1].phid = phid; // as does previous card + saw_sbrk = FALSE; + } + } + fclose(fd); + + qsort(deck, ncards, sizeof(struct tag_card), cardcomp); // sort the deck + +#ifdef WIN32 + _setmode(_fileno(stdout), _O_BINARY); // set standard output to binary mode +#endif + + for (i = 0; i < ncards; i++) // write to stdout + fwrite(deck[i].card, sizeof(card[0]), 80, stdout); + + free(deck); +} + +void dump_phids (char *fname) +{ + FILE *fp; + BOOL first = TRUE; + BOOL saw_sbrk = TRUE, neg; + short id; + + if ((fp = fopen(fname, "rb")) == NULL) { + perror(fname); + return; + } + + printf("\n%s:\n", fname); + + while (fread(card, sizeof(card[0]), 80, fp) > 0) { + unpack(card, buf); + verify_checksum(buf); + + cardtype = (buf[2] >> 8) & 0xFF; + + if (cardtype == 1 && ! first) { // sector break + saw_sbrk = TRUE; + continue; + } + else { + switch (cardtype) { + case 0x00: + printf(" This is a core image deck\n"); + goto done; + break; + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x0F: + break; + + case 0x0A: + if (saw_sbrk) { + id = buf[10]; + if (id < 0) + id = -id, neg = TRUE; + else + neg = FALSE; + printf(" : %3d / %02x%s\n", id, id, neg ? " (neg)" : ""); + saw_sbrk = FALSE; + } + break; + + default: + show_raw("??? "); + } + } +done: + first = FALSE; + } + + fclose(fp); +} + +void dump_data (char *fname) +{ + FILE *fp; + BOOL first = TRUE; + char str[80]; + int i; + + if ((fp = fopen(fname, "rb")) == NULL) { + perror(fname); + return; + } + + printf("\n%s:\n", fname); + + while (fread(card, sizeof(card[0]), 80, fp) > 0) { + unpack(card, buf); + verify_checksum(buf); + + cardtype = (buf[2] >> 8) & 0xFF; + + if (cardtype == 1 && ! first) { // sector break + for (i = 4; i < 72; i++) + str[i] = hollerith_to_ascii(card[i]); + + str[i] = '\0'; + trim(str+4); + printf("*SBRK %s\n", str+4); + continue; + } + else { + switch (cardtype) { + case 0x00: + if (first) + show_raw("CORE"); + if (verbose) + show_core(); + break; + + case 0x01: + show_raw("ABS "); + show_main(); + break; + case 0x02: + show_raw("REL "); + show_main(); + break; + case 0x03: + show_raw("LIB "); + show_sub(); + break; + case 0x04: + show_raw("SUB "); + show_sub(); + break; + case 0x05: + show_raw("ISSL"); + show_iss(); + break; + case 0x06: + show_raw("ISSC"); + show_iss(); + break; + case 0x07: + show_raw("ILS "); + show_ils(); + break; + case 0x0F: + show_raw("END "); + show_end(); + break; + case 0x80: + show_raw("ENDC"); + show_endc(); + break; + case 0x81: + show_raw("81 "); + show_81(); + break; + case 0x0A: + if (verbose) + show_data(); + break; + default: + show_raw("??? "); + } + } + + first = FALSE; + } + + fclose(fp); +} + +void show_data (void) +{ + int i, n, jrel, rflag, nout, ch, reloc; + BOOL first = TRUE; + + n = buf[2] & 0x00FF; + + printf("%04x: ", buf[0]); + + jrel = 3; + nout = 0; + rflag = buf[jrel++]; + for (i = 0; i < n; i++) { + if (nout >= 8) { + rflag = buf[jrel++]; + if (first) { + printf(" %s", getseq()); + first = FALSE; + } + printf("\n "); + nout = 0; + } + reloc = (rflag >> 14) & 0x03; + ch = (reloc == R_ABSOLUTE) ? ' ' : + (reloc == R_RELATIVE) ? 'R' : + (reloc == R_LIBF) ? 'L' : '@'; + + printf("%04x%c ", buf[9+i], ch); + rflag << 2; + nout++; + } + putchar('\n'); +} + +void show_core (void) +{ + int i, n, nout; + BOOL first = TRUE; + + n = buf[2] & 0x00FF; + + printf("%04x: ", buf[0]); + + nout = 0; + for (i = 0; i < n; i++) { + if (nout >= 8) { + if (first) { + printf(" %s", getseq()); + first = FALSE; + } + printf("\n "); + nout = 0; + } + printf("%04x ", buf[9+i]); + nout++; + } + putchar('\n'); +} + +void info (int i, char *nm, char type) +{ + if (nm) + printf("%s ", nm); + + switch (type) { + case 'd': + printf("%d ", buf[i]); + break; + + case 'x': + printf("%04x ", buf[i]); + break; + + case 'b': + printf("%02x ", buf[i] & 0xFF); + break; + + case 'n': + printf("%s ", getname(buf+i)); + break; + + default: + bail("BAD TYPE"); + } +} + +void show_main (void) +{ + printf(" "); + info(2, "prec", 'b'); + info(4, "common", 'd'); + info(6, "work", 'd'); + info(8, "files", 'd'); + info(9, "name", 'n'); + info(11, "pta", 'x'); + putchar('\n'); +} + +void show_sub (void) +{ + int i, n; + + printf(" "); + info( 2, "prec", 'b'); + + n = buf[5] / 3; + for (i = 0; i < n; i++) { + info( 9+3*i, "ent", 'n'); + info(11+3*i, NULL, 'x'); + } + + putchar('\n'); +} + +void show_iss (void) +{ + printf(" "); + info(12, "level", 'd'); + putchar('\n'); +} + +void show_ils (void) +{ + printf(" "); + info( 2, "prec", 'b'); + info( 5, "nint6", 'd'); + info( 9, "ent", 'n'); + info(11, NULL, 'x'); + info(14, "nint", 'd'); + info(15, "il1", 'd'); + info(16, "il2", 'd'); + putchar('\n'); +} + +void show_end (void) +{ + printf(" "); + info(0, "size", 'd'); + info(3, "pta", 'x'); + putchar('\n'); +} + +void show_endc(void) +{ + printf(" "); + info(52, "IX3", 'x'); + info(53, "pta", 'x'); + putchar('\n'); +} + +void show_81(void) +{ +} + +void show_raw (char *name) +{ + int i; + printf("*%s", name); + + for (i = 0; i < 12; i++) + printf(" %04x", buf[i]); + + printf(" %s\n", getseq()); +} + +char * getseq (void) +{ + static char seq[10]; + int i; + + for (i = 0; i < 8; i++) + seq[i] = hollerith_to_ascii(card[72+i]); + + seq[i] = '\0'; + return seq; +} + + +void bail (char *msg) +{ + fprintf(stderr, "%s\n", msg); + exit(1); +} + +void unpack (unsigned short *icard, unsigned short *obuf) +{ + int i, j; + unsigned short wd1, wd2, wd3, wd4; + + for (i = j = 0; i < 54; i += 3, j += 4) { + wd1 = icard[j]; + wd2 = icard[j+1]; + wd3 = icard[j+2]; + wd4 = icard[j+3]; + + obuf[i ] = (wd1 & 0xFFF0) | ((wd2 >> 12) & 0x000F); + obuf[i+1] = ((wd2 << 4) & 0xFF00) | ((wd3 >> 8) & 0x00FF); + obuf[i+2] = ((wd3 << 8) & 0xF000) | ((wd4 >> 4) & 0x0FFF); + } +} + +void verify_checksum (unsigned short *obuf) +{ +// unsigned short sum; + + if (obuf[1] == 0) // no checksum + return; + +// if (sum != card[1]) +// printf("Checksum %04x doesn't match card %04x\n", sum, card[1]); +} + +typedef struct { + unsigned short hollerith; + char ascii; +} CPCODE; + +static CPCODE cardcode_029[] = +{ + 0x0000, ' ', + 0x8000, '&', // + in 026 Fortran + 0x4000, '-', + 0x2000, '0', + 0x1000, '1', + 0x0800, '2', + 0x0400, '3', + 0x0200, '4', + 0x0100, '5', + 0x0080, '6', + 0x0040, '7', + 0x0020, '8', + 0x0010, '9', + 0x9000, 'A', + 0x8800, 'B', + 0x8400, 'C', + 0x8200, 'D', + 0x8100, 'E', + 0x8080, 'F', + 0x8040, 'G', + 0x8020, 'H', + 0x8010, 'I', + 0x5000, 'J', + 0x4800, 'K', + 0x4400, 'L', + 0x4200, 'M', + 0x4100, 'N', + 0x4080, 'O', + 0x4040, 'P', + 0x4020, 'Q', + 0x4010, 'R', + 0x3000, '/', + 0x2800, 'S', + 0x2400, 'T', + 0x2200, 'U', + 0x2100, 'V', + 0x2080, 'W', + 0x2040, 'X', + 0x2020, 'Y', + 0x2010, 'Z', + 0x0820, ':', + 0x0420, '#', // = in 026 Fortran + 0x0220, '@', // ' in 026 Fortran + 0x0120, '\'', + 0x00A0, '=', + 0x0060, '"', + 0x8820, 'c', // cent + 0x8420, '.', + 0x8220, '<', // ) in 026 Fortran + 0x8120, '(', + 0x80A0, '+', + 0x8060, '|', + 0x4820, '!', + 0x4420, '$', + 0x4220, '*', + 0x4120, ')', + 0x40A0, ';', + 0x4060, 'n', // not + 0x2820, 'x', // what? + 0x2420, ',', + 0x2220, '%', // ( in 026 Fortran + 0x2120, '_', + 0x20A0, '>', + 0x2060, '>', +}; + +int hollerith_to_ascii (unsigned short h) +{ + int i; + + h &= 0xFFF0; + + for (i = 0; i < sizeof(cardcode_029) / sizeof(CPCODE); i++) + if (cardcode_029[i].hollerith == h) + return cardcode_029[i].ascii; + + return '?'; +} + +// --------------------------------------------------------------------------------- +// trim - remove trailing whitespace from string s +// --------------------------------------------------------------------------------- + +void trim (char *s) +{ + char *nb; + + for (nb = s-1; *s; s++) + if (*s > ' ') + nb = s; + + nb[1] = '\0'; +} + +int ascii_to_ebcdic_table[128] = +{ + 0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f, 0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26, 0x18,0x19,0x3f,0x27,0x1c,0x1d,0x1e,0x1f, + 0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d, 0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61, + 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, 0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f, + + 0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, 0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6, + 0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6, 0xe7,0xe8,0xe9,0xba,0xe0,0xbb,0xb0,0x6d, + 0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87, 0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96, + 0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6, 0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07, +}; + +char *getname (unsigned short *ptr) +{ + static char str[6]; + int i, j, ch; + long v; + + v = (ptr[0] << 16L) | ptr[1]; + + for (i = 0; i < 5; i++) { + ch = ((v >> 24) & 0x3F) | 0xC0; // recover those lost two bits + v <<= 6; + + str[i] = ' '; + + for (j = 0; j < (sizeof(ascii_to_ebcdic_table)/sizeof(ascii_to_ebcdic_table[0])); j++) { + if (ascii_to_ebcdic_table[j] == ch) { + str[i] = j; + break; + } + } + } + + str[5] = '\0'; + return str; +} + diff --git a/Ibm1130/bindump.mak b/Ibm1130/bindump.mak new file mode 100644 index 00000000..192cd550 --- /dev/null +++ b/Ibm1130/bindump.mak @@ -0,0 +1,161 @@ +# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=Win32 Debug +!MESSAGE No configuration specified. Defaulting to Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "bindump.mak" CFG="Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "Win32 Debug" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "WinRel" +# PROP BASE Intermediate_Dir "WinRel" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "WinRel" +# PROP Intermediate_Dir "WinRel" +OUTDIR=.\WinRel +INTDIR=.\WinRel + +ALL : $(OUTDIR)/bindump.exe $(OUTDIR)/bindump.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"bindump.pch" /Fo$(INTDIR)/ /c +CPP_OBJS=.\WinRel/ +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"bindump.bsc" +BSC32_SBRS= \ + $(INTDIR)/bindump.sbr + +$(OUTDIR)/bindump.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + /NOLOGO /SUBSYSTEM:console /INCREMENTAL:no /PDB:$(OUTDIR)/"bindump.pdb"\ + /MACHINE:I386 /OUT:$(OUTDIR)/"bindump.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/bindump.obj + +$(OUTDIR)/bindump.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "WinDebug" +# PROP BASE Intermediate_Dir "WinDebug" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "WinDebug" +# PROP Intermediate_Dir "WinDebug" +OUTDIR=.\WinDebug +INTDIR=.\WinDebug + +ALL : $(OUTDIR)/bindump.exe $(OUTDIR)/bindump.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"bindump.pch" /Fo$(INTDIR)/\ + /Fd$(OUTDIR)/"bindump.pdb" /c +CPP_OBJS=.\WinDebug/ +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"bindump.bsc" +BSC32_SBRS= \ + $(INTDIR)/bindump.sbr + +$(OUTDIR)/bindump.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + /NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes /PDB:$(OUTDIR)/"bindump.pdb" /DEBUG\ + /MACHINE:I386 /OUT:$(OUTDIR)/"bindump.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/bindump.obj + +$(OUTDIR)/bindump.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Group "Source Files" + +################################################################################ +# Begin Source File + +SOURCE=.\bindump.c + +$(INTDIR)/bindump.obj : $(SOURCE) $(INTDIR) + +# End Source File +# End Group +# End Project +################################################################################ diff --git a/Ibm1130/checkdisk.c b/Ibm1130/checkdisk.c new file mode 100644 index 00000000..82a879e0 --- /dev/null +++ b/Ibm1130/checkdisk.c @@ -0,0 +1,264 @@ +/* + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org + */ + +// checkdisk - validates and optionally dumps an IBM1130 DMS2 disk image file +// +// Usage: +// checkdisk [-f] [-d cyl.sec|abssec] [-n count] filename +// +// Examples: +// checkdisk file.dsk +// report any misnumbered sectors in file.dsk +// +// checkdisk -f file.dsk +// report and fix any misnumbered sectors +// +// checkdisk -d 198.0 file.dsk +// dump cylinder 198 sector 0 +// +// checkdisk -d 0 file.dsk +// dump absolute sector 0 +// +// checkdisk -d 198.0 -n 4 file.dsk +// dump 4 sectors starting at m.n +// ----------------------------------------------------------------------------------------- +#include +#include +#include +#include "util_io.h" + +#ifdef WIN32 +# include +#else + long filelength (int fno); +# include +# include +#endif + +#ifndef TRUE +# define BOOL int +# define TRUE 1 +# define FALSE 0 +#endif + +#define DSK_NUMWD 321 /* words/sector */ +#define DSK_NUMSC 4 /* sectors/surface */ +#define DSK_NUMSF 2 /* surfaces/cylinder */ +#define DSK_NUMCY 203 /* cylinders/drive */ +#define DSK_NUMDR 5 /* drives/controller */ +#define DSK_SIZE (DSK_NUMCY * DSK_NUMSF * DSK_NUMSC * DSK_NUMWD) /* words/drive */ + +char *usestr = "Usage: checkdisk [-f] [-d cyl.sec|abssec] [-n count] diskfile"; +char *baddisk = "Cannot fix this"; + +void bail (char *msg); +char *lowcase (char *str); + +int main (int argc, char **argv) +{ + FILE *fp; + char *fname = NULL, *arg, *argval; + int i, j, cyl, sec, pos, asec, retry, nbad = 0, nfixed = 0, nline; + BOOL fixit = FALSE, dump = FALSE; + int dsec, nsec = 1; + unsigned short wd, buf[DSK_NUMWD]; + + util_io_init(); + + for (i = 1; i < argc;) { + arg = argv[i++]; + if (*arg == '-') { + arg++; + lowcase(arg); + while (*arg) { + switch (*arg++) { + case 'f': + fixit = TRUE; + break; + + case 'd': + dump = TRUE; + + if (i >= argc) + bail(usestr); + + argval = argv[i++]; + if (strchr(argval, '.') != NULL) { + if (sscanf(argval, "%d.%d", &cyl, &sec) != 2) + bail(usestr); + + dsec = cyl*(DSK_NUMSF*DSK_NUMSC) + sec; + } + else if (sscanf(argval, "%d", &dsec) != 1) + bail(usestr); + + if (dsec < 0 || dsec >= (DSK_NUMCY*DSK_NUMSF*DSK_NUMSC)) + bail("No such sector"); + + break; + + case 'n': + if (i >= argc) + bail(usestr); + + argval = argv[i++]; + if (sscanf(argval, "%d", &nsec) != 1) + bail(usestr); + + if (nsec <= 0) + bail(usestr); + + break; + + default: + bail(usestr); + } + } + } + else if (fname == NULL) + fname = arg; + else + bail(usestr); + } + + if (fname == NULL) + bail(usestr); + + if ((fp = fopen(fname, "rb+")) == NULL) { + perror(fname); + return 1; + } + + if (filelength(fileno(fp)) != 2*DSK_SIZE) { + fprintf(stderr, "File is wrong length, expected %d\n", DSK_SIZE); + bail(baddisk); + } + + for (cyl = 0; cyl < DSK_NUMCY; cyl++) { + for (sec = 0; sec < (DSK_NUMSF*DSK_NUMSC); sec++) { + retry = 1; +again: + asec = cyl*(DSK_NUMSF*DSK_NUMSC) + sec; + pos = asec*2*DSK_NUMWD; + + if (fseek(fp, pos, SEEK_SET) != 0) { + fprintf(stderr, "Error seeking to pos %x\n", pos); + bail(baddisk); + } + + if (fxread(&wd, sizeof(wd), 1, fp) != 1) { + fprintf(stderr, "Error reading word at abs sec %x, cyl %x, sec %x at offset %x\n", asec, cyl, sec, pos); + bail(baddisk); + } + + if (wd != asec) { + fprintf(stderr, "Bad sector #%x at abs sec %x, cyl %x, sec %x at offset %x\n", wd, asec, cyl, sec, pos); + nbad++; + + if (fixit) { + if (fseek(fp, pos, SEEK_SET) != 0) { + fprintf(stderr, "Error seeking to pos %x\n", pos); + bail(baddisk); + } + + if (fxwrite(&asec, sizeof(wd), 1, fp) != 1) { + fprintf(stderr, "Error writing sector # to abs sec %x, cyl %x, sec %x at offset %x\n", asec, cyl, sec, pos); + bail(baddisk); + } + + if (retry) { + retry = 0; + nfixed++; + goto again; + } + + fprintf(stderr, "Failed after retry\n"); + bail(baddisk); + } + } + } + } + + if (nbad) + printf("%d bad sector mark%s %s\n", nbad, (nbad == 1) ? "" : "s", fixit ? "fixed" : "found"); + else if (! dump) + printf("All sector marks OK\n"); + + if (! dump) + return 0; + + pos = dsec*2*DSK_NUMWD; + if (fseek(fp, pos, SEEK_SET) != 0) { + fprintf(stderr, "Error seeking to pos %x\n", pos); + bail(baddisk); + } + + for (i = 0; i < nsec; i++) { + cyl = dsec / (DSK_NUMSF*DSK_NUMSC); + sec = dsec - cyl*(DSK_NUMSF*DSK_NUMSC); + + if (fxread(&buf, sizeof(buf[0]), DSK_NUMWD, fp) != DSK_NUMWD) { + fprintf(stderr, "Error reading abs sec %x, cyl %x, sec %x at offset %x\n", dsec, cyl, sec, pos); + bail(baddisk); + } + + printf("\nSector %d.%d - %d - /%04x label %04x\n", cyl, sec, dsec, dsec, buf[0]); + for (nline = 0, j = 1; j < DSK_NUMWD; j++) { + printf("%04x", buf[j]); + if (++nline == 16) { + putchar('\n'); + nline = 0; + } + else + putchar(' '); + } + + dsec++; + } + + return 0; +} + +void bail (char *msg) +{ + fprintf(stderr, "%s\n", msg); + exit(1); +} + +/* ------------------------------------------------------------------------ + * lowcase - force a string to lower case (ASCII) + * ------------------------------------------------------------------------ */ + +char *lowcase (char *str) +{ + char *s; + + for (s = str; *s; s++) { + if (*s >= 'A' && *s <= 'Z') + *s += 32; + } + + return str; +} + +#ifndef WIN32 + +long filelength (int fno) +{ + struct stat sb; + + if (fstat(fno, &sb) != 0) + return 0; + + return (long) sb.st_size; +} +#endif + diff --git a/Ibm1130/checkdisk.mak b/Ibm1130/checkdisk.mak new file mode 100644 index 00000000..e03d955b --- /dev/null +++ b/Ibm1130/checkdisk.mak @@ -0,0 +1,177 @@ +# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=Win32 Debug +!MESSAGE No configuration specified. Defaulting to Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "checkdisk.mak" CFG="Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "Win32 Release" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "WinRel" +# PROP BASE Intermediate_Dir "WinRel" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "WinRel" +# PROP Intermediate_Dir "WinRel" +OUTDIR=.\WinRel +INTDIR=.\WinRel + +ALL : $(OUTDIR)/checkdisk.exe $(OUTDIR)/checkdisk.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"checkdisk.pch" /Fo$(INTDIR)/ /c +CPP_OBJS=.\WinRel/ +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"checkdisk.bsc" +BSC32_SBRS= \ + $(INTDIR)/checkdisk.sbr \ + $(INTDIR)/util_io.sbr + +$(OUTDIR)/checkdisk.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib /NOLOGO\ + /SUBSYSTEM:console /INCREMENTAL:no /PDB:$(OUTDIR)/"checkdisk.pdb" /MACHINE:I386\ + /OUT:$(OUTDIR)/"checkdisk.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/checkdisk.obj \ + $(INTDIR)/util_io.obj + +$(OUTDIR)/checkdisk.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "WinDebug" +# PROP BASE Intermediate_Dir "WinDebug" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "WinDebug" +# PROP Intermediate_Dir "WinDebug" +OUTDIR=.\WinDebug +INTDIR=.\WinDebug + +ALL : $(OUTDIR)/checkdisk.exe $(OUTDIR)/checkdisk.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"checkdisk.pch" /Fo$(INTDIR)/\ + /Fd$(OUTDIR)/"checkdisk.pdb" /c +CPP_OBJS=.\WinDebug/ +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"checkdisk.bsc" +BSC32_SBRS= \ + $(INTDIR)/checkdisk.sbr \ + $(INTDIR)/util_io.sbr + +$(OUTDIR)/checkdisk.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib /NOLOGO\ + /SUBSYSTEM:console /INCREMENTAL:yes /PDB:$(OUTDIR)/"checkdisk.pdb" /DEBUG\ + /MACHINE:I386 /OUT:$(OUTDIR)/"checkdisk.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/checkdisk.obj \ + $(INTDIR)/util_io.obj + +$(OUTDIR)/checkdisk.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Group "Source Files" + +################################################################################ +# Begin Source File + +SOURCE=.\checkdisk.c +DEP_CHECK=\ + .\util_io.h\ + \MSVC20\INCLUDE\sys\types.h\ + \MSVC20\INCLUDE\sys\stat.h + +$(INTDIR)/checkdisk.obj : $(SOURCE) $(DEP_CHECK) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\util_io.c + +$(INTDIR)/util_io.obj : $(SOURCE) $(INTDIR) + +# End Source File +# End Group +# End Project +################################################################################ diff --git a/Ibm1130/diskview.c b/Ibm1130/diskview.c new file mode 100644 index 00000000..65ee850e --- /dev/null +++ b/Ibm1130/diskview.c @@ -0,0 +1,614 @@ +/* + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org + */ + +// DISKVIEW - lists contents of an 1130 system disk image file. Not finished yet. +// needs LET/SLET listing routine. +// +// usage: +// diskview -v diskfile + +#include +#include +#include +#include +#include "util_io.h" + +#define BETWEEN(v,a,b) (((v) >= (a)) && ((v) <= (b))) +#define MIN(a,b) (((a) <= (b)) ? (a) : (b)) +#define MAX(a,b) (((a) >= (b)) ? (a) : (b)) + +#ifndef TRUE +# define TRUE 1 +# define FALSE 0 +# define BOOL int +#endif + +#define NOT_DEF 0x0658 // defective cylinder table entry means no defect + +#define DSK_NUMWD 321 /* words/sector */ +#define DSK_NUMCY 203 /* cylinders/drive */ +#define DSK_SECCYL 8 /* sectors per cylinder */ +#define SECLEN 320 /* data words per sector */ +#define SLETLEN ((3*SECLEN)/4) /* length of slet in records */ + +typedef unsigned short WORD; + +FILE *fp; +WORD buf[DSK_NUMWD]; +WORD dcom[DSK_NUMWD]; + +#pragma pack(2) +struct tag_slet { + WORD phid; + WORD addr; + WORD nwords; + WORD sector; +} slet[SLETLEN]; + +#pragma pack() + +WORD dcyl[3]; +BOOL verbose = FALSE; + +void checksectors (void); +void dump_id (void); +void dump_dcom (void); +void dump_resmon (void); +void dump_slet (void); +void dump_hdng (void); +void dump_scra (void); +void dump_let (void); +void dump_flet (void); +void dump_cib (void); +void getsector (int sec, WORD *sbuf); +void getdcyl (void); +char *lowcase (char *str); + +void bail(char *fmt, ...); +char *trim (char *s); + +int main (int argc, char **argv) +{ + char *fname = NULL, *arg; + static char usestr[] = "Usage: diskview [-v] filename"; + int i; + + util_io_init(); + + for (i = 1; i < argc;) { + arg = argv[i++]; + if (*arg == '-') { + arg++; + lowcase(arg); + while (*arg) { + switch (*arg++) { + case 'v': + verbose = TRUE; + break; + + default: + bail(usestr); + } + } + } + else if (fname == NULL) + fname = arg; + else + bail(usestr); + } + + if (fname == NULL) + bail(usestr); + + if ((fp = fopen(fname, "rb")) == NULL) { + perror(fname); + return 2; + } + + printf("%s:\n", fname); + + checksectors(); + getdcyl(); + + dump_id(); // ID & coldstart + dump_dcom(); // DCOM + dump_resmon(); // resident image + dump_slet(); // SLET + dump_hdng(); // heading sector + dump_scra(); + dump_flet(); + dump_cib(); + dump_let(); + + fclose(fp); + return 0; +} + +// checksectors - verify that all sectors are properly numbered + +void checksectors () +{ + WORD sec = 0; + + fseek(fp, 0, SEEK_SET); + + for (sec = 0; sec < DSK_NUMCY*DSK_SECCYL; sec++) { + if (fxread(buf, sizeof(WORD), DSK_NUMWD, fp) != DSK_NUMWD) + bail("File read error or not a disk image file"); + + if (buf[0] != sec) + bail("Sector /%x is misnumbered, run checkdisk [-f]", sec); + } +} + +// get defective cylinder list + +void getdcyl (void) +{ + fseek(fp, sizeof(WORD), SEEK_SET); // skip sector count + if (fxread(dcyl, sizeof(WORD), 3, fp) != 3) + bail("Unable to read defective cylinder table"); +} + +// getsector - read specified absolute sector + +void getsector (int sec, WORD *sbuf) +{ + int i, cyl, ssec; + + sec &= 0x7FF; // mask of drive bits, if any + + cyl = sec / DSK_SECCYL; // get cylinder + ssec = sec & ~(DSK_SECCYL-1); // mask to get starting sector of cylinder + for (i = 0; i < 3; i++) { // map through defective cylinder table + if (dcyl[i] == ssec) { + sec &= (DSK_SECCYL-1); // mask to get base sector + cyl = DSK_NUMCY-3+i; // replacements are last three on disk + sec += cyl*DSK_SECCYL; // add new cylinder offset + break; + } + } + // read the sector + if (fseek(fp, (sec*DSK_NUMWD+1)*sizeof(WORD), SEEK_SET) != 0) + bail("File seek failed"); + + if (fxread(sbuf, sizeof(WORD), DSK_NUMWD, fp) != DSK_NUMWD) + bail("File read error or not a disk image file"); +} + +void dump (int nwords) +{ + int i, nline = 0; + + for (i = 0; i < nwords; i++) { + if (nline == 16) { + putchar('\n'); + nline = 0; + } + + printf("%04x", buf[i]); + nline++; + } + putchar('\n'); +} + +void showmajor (char *label) +{ + int i; + + printf("\n--- %s ", label); + + for (i = strlen(label); i < 40; i++) + putchar('-'); + + putchar('\n'); + putchar('\n'); +} + +void name (char *label) +{ + printf("%-32.32s ", label); +} + +void pbf (char *label, WORD *buf, int nwords) +{ + int i, nout; + + name(label); + + for (i = nout = 0; i < nwords; i++, nout++) { + if (nout == 8) { + putchar('\n'); + name(""); + nout = 0; + } + printf(" %04x", buf[i]); + } + + putchar('\n'); +} + +void prt (char *label, char *fmt, ...) +{ + va_list args; + + name(label); + + putchar(' '); + va_start(args, fmt); + vprintf(fmt, args); + va_end(args); + + putchar('\n'); +} + +void dump_id (void) +{ + showmajor("Sector 0 - ID & coldstart"); + getsector(0, buf); + + pbf("DCYL def cyl table", buf+ 0, 3); + pbf("CIDN cart id", buf+ 3, 1); + pbf(" copy code", buf+ 4, 1); + pbf("DTYP disk type", buf+ 7, 1); + pbf(" diskz copy", buf+ 30, 8); + pbf(" cold start pgm",buf+270, 8); +} + +// EQUIVALENCES FOR DCOM PARAMETERS +#define NAME 4 // NAME OF PROGRAM/CORE LOAD +#define DBCT 6 // BLOCK CT OF PROGRAM/CORE LOAD +#define FCNT 7 // FILES SWITCH +#define SYSC 8 // SYSTEM/NON-SYSTEM CARTRIDGE INDR +#define JBSW 9 // JOBT SWITCH +#define CBSW 10 // CLB-RETURN SWITCH +#define LCNT 11 // NO. OF LOCALS +#define MPSW 12 // CORE MAP SWITCH +#define MDF1 13 // NO. DUP CTRL RECORDS (MODIF) +#define MDF2 14 // ADDR OF MODIF BUFFER +#define NCNT 15 // NO. OF NOCALS +#define ENTY 16 // RLTV ENTRY ADDR OF PROGRAM +#define RP67 17 // 1442-5 SWITCH +#define TODR 18 // OBJECT WORK STORAGE DRIVE CODE +#define FHOL 20 // ADDR LARGEST HOLE IN FIXED AREA +#define FSZE 21 // BLK CNT LARGEST HOLE IN FXA +#define UHOL 22 // ADDR LAST HOLE IN USER AREA 2-10 +#define USZE 23 // BLK CNT LAST HOLE IN UA 2-10 +#define DCSW 24 // DUP CALL SWITCH +#define PIOD 25 // PRINCIPAL I/O DEVICE INDICATOR +#define PPTR 26 // PRINCIPAL PRINT DEVICE INDICATOR +#define CIAD 27 // RLTV ADDR IN @STRT OF CIL ADDR +#define ACIN 28 // AVAILABLE CARTRIDGE INDICATOR +#define GRPH 29 // 2250 INDICATOR 2G2 +#define GCNT 30 // NO. G2250 RECORDS 2G2 +#define LOSW 31 // LOCAL-CALLS-LOCAL SWITCH 2-2 +#define X3SW 32 // SPECIAL ILS SWITCH 2-2 +#define ECNT 33 // NO. OF *EQUAT RCDS 2-4 +#define ANDU 35 // 1+BLK ADDR END OF UA (ADJUSTED) +#define BNDU 40 // 1+BLK ADDR END OF UA (BASE) +#define FPAD 45 // FILE PROTECT ADDR +#define PCID 50 // CARTRIDGE ID, PHYSICAL DRIVE +#define CIDN 55 // CARTRIDGE ID, LOGICAL DRIVE +#define CIBA 60 // SCTR ADDR OF CIB +#define SCRA 65 // SCTR ADDR OF SCRA +#define FMAT 70 // FORMAT OF PROG IN WORKING STG +#define FLET 75 // SCTR ADDR 1ST SCTR OF FLET +#define ULET 80 // SCTR ADDR 1ST SCTR OF LET +#define WSCT 85 // BLK CNT OF PROG IN WORKING STG +#define CSHN 90 // NO. SCTRS IN CUSHION AREA + +struct tag_dcominfo { + char *nm; + int offset; + char *descr; +} dcominfo[] = { + "NAME", 4, "NAME OF PROGRAM/CORE LOAD", + "DBCT", 6, "BLOCK CT OF PROGRAM/CORE LOAD", + "FCNT", 7, "FILES SWITCH", + "SYSC", 8, "SYSTEM/NON-SYSTEM CARTRIDGE INDR", + "JBSW", 9, "JOBT SWITCH", + "CBSW", 10, "CLB-RETURN SWITCH", + "LCNT", 11, "NO. OF LOCALS", + "MPSW", 12, "CORE MAP SWITCH", + "MDF1", 13, "NO. DUP CTRL RECORDS (MODIF)", + "MDF2", 14, "ADDR OF MODIF BUFFER", + "NCNT", 15, "NO. OF NOCALS", + "ENTY", 16, "RLTV ENTRY ADDR OF PROGRAM", + "RP67", 17, "1442-5 SWITCH", + "TODR", 18, "OBJECT WORK STORAGE DRIVE CODE", + "FHOL", 20, "ADDR LARGEST HOLE IN FIXED AREA", + "FSZE", 21, "BLK CNT LARGEST HOLE IN FXA", + "UHOL", 22, "ADDR LAST HOLE IN USER AREA", + "USZE", 23, "BLK CNT LAST HOLE IN UA", + "DCSW", 24, "DUP CALL SWITCH", + "PIOD", 25, "PRINCIPAL I/O DEVICE INDICATOR", + "PPTR", 26, "PRINCIPAL PRINT DEVICE INDICATOR", + "CIAD", 27, "RLTV ADDR IN @STRT OF CIL ADDR", + "ACIN", 28, "AVAILABLE CARTRIDGE INDICATOR", + "GRPH", 29, "2250 INDICATOR", + "GCNT", 30, "NO. G2250 RECORDS", + "LOSW", 31, "LOCAL-CALLS-LOCAL SWITCH", + "X3SW", 32, "SPECIAL ILS SWITCH", + "ECNT", 33, "NO. OF *EQUAT RCDS", + "ANDU", 35, "1+BLK ADDR END OF UA (ADJUSTED)", + "BNDU", 40, "1+BLK ADDR END OF UA (BASE)", + "FPAD", 45, "FILE PROTECT ADDR", + "PCID", 50, "CARTRIDGE ID, PHYSICAL DRIVE", + "CIDN", 55, "CARTRIDGE ID, LOGICAL DRIVE", + "CIBA", 60, "SCTR ADDR OF CIB", + "SCRA", 65, "SCTR ADDR OF SCRA", + "FMAT", 70, "FORMAT OF PROG IN WORKING STG", + "FLET", 75, "SCTR ADDR 1ST SCTR OF FLET", + "ULET", 80, "SCTR ADDR 1ST SCTR OF LET", + "WSCT", 85, "BLK CNT OF PROG IN WORKING STG", + "CSHN", 90, "NO. SCTRS IN CUSHION AREA", + NULL +}; + +void dump_dcom (void) +{ + struct tag_dcominfo *d; + char txt[50]; + + showmajor("Sector 1 - DCOM"); + getsector(1, dcom); + + for (d = dcominfo; d->nm != NULL; d++) { + sprintf(txt, "%-4.4s %s", d->nm, d->descr); + pbf(txt, dcom+d->offset, 1); + } +} + +void dump_resmon (void) +{ + showmajor("Sector 2 - Resident Image"); + getsector(2, buf); + dump(verbose ? SECLEN : 32); +} + +struct { + int pfrom, pto; + int printed; + char *name; +} sletinfo[] = { + 0x01, 0x12, FALSE, "DUP", + 0x1F, 0x39, FALSE, "Fortran", + 0x51, 0x5C, FALSE, "Cobol", + 0x6E, 0x74, FALSE, "Supervisor", + 0x78, 0x84, FALSE, "Core Load Builder", + 0x8C, 0x8C, FALSE, "Sys 1403 prt", + 0x8D, 0x8D, FALSE, "Sys 1132 prt", + 0x8E, 0x8E, FALSE, "Sys console prt", + 0x8F, 0x8F, FALSE, "Sys 2501 rdr", + 0x90, 0x90, FALSE, "Sys 1442 rdr/pun", + 0x91, 0x91, FALSE, "Sys 1134 paper tape", + 0x92, 0x92, FALSE, "Sys kbd", + 0x93, 0x93, FALSE, "Sys 2501/1442 conv", + 0x94, 0x94, FALSE, "Sys 1134 conv", + 0x95, 0x95, FALSE, "Sys kbd conv", + 0x96, 0x96, FALSE, "Sys diskz", + 0x97, 0x97, FALSE, "Sys disk1", + 0x98, 0x98, FALSE, "Sys diskn", + 0x99, 0x99, FALSE, "(primary print)", + 0x9A, 0x9A, FALSE, "(primary input)", + 0x9B, 0x9B, FALSE, "(primary input excl kbd)", + 0x9C, 0x9C, FALSE, "(primary sys conv)", + 0x9D, 0x9D, FALSE, "(primary conv excl kbd)", + 0xA0, 0xA1, FALSE, "Core Image Loader", + 0xB0, 0xCC, FALSE, "RPG", + 0xCD, 0xCE, FALSE, "Dup Part 2", + 0xCF, 0xF6, FALSE, "Macro Assembler", + 0 +}; + +void dump_slet (void) +{ + int i, j, iphase, nsecs, sec, max_sec = 0; + char sstr[16], *smark; + + showmajor("Sectors 3-5 - SLET"); + for (i = 0; i < 3; i++) { + getsector(3+i, buf); + memmove(((WORD *) slet)+SECLEN*i, buf, SECLEN*sizeof(WORD)); + } + + printf("# PHID Addr Len Sector Secs\n"); + printf("------------------------------------------\n"); + for (i = 0; i < SLETLEN; i++) { + if (slet[i].phid == 0) + break; + + sec = slet[i].sector; + iphase = (int) (signed short) slet[i].phid; + nsecs = (slet[i].nwords + SECLEN-1)/SECLEN; + + if (sec & 0xF800) { + smark = "*"; + sec &= 0x7FF; + } + else + smark = " "; + + for (j = 0; sletinfo[j].pfrom != 0; j++) + if (sletinfo[j].pfrom <= iphase && sletinfo[j].pto >= iphase) + break; + + sprintf(sstr, "(%d.%d)", sec / DSK_SECCYL, slet[i].sector % DSK_SECCYL); + + printf("%3d %04x %4d %04x %04x %04x %s %-7s %3x", + i, slet[i].phid, iphase, slet[i].addr, slet[i].nwords, slet[i].sector, smark, sstr, nsecs); + + if (iphase < 0) + iphase = -iphase; + + if (sletinfo[j].pfrom == 0) + printf(" ???"); + else if (! sletinfo[j].printed) { + printf(" %s", sletinfo[j].name); + sletinfo[j].printed = TRUE; + } + + for (j = 0; j < i; j++) { + if (sec == (slet[j].sector & 0x7FF)) { + printf(" (same as %04x)", slet[j].phid); + break; + } + } + + max_sec = MAX(max_sec, sec+nsecs-1); // find last sector used + + putchar('\n'); + + if (i >= 15 && ! verbose) { + printf("...\n"); + break; + } + } +} + +int ascii_to_ebcdic_table[128] = +{ + 0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f, 0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26, 0x18,0x19,0x3f,0x27,0x1c,0x1d,0x1e,0x1f, + 0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d, 0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61, + 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, 0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f, + + 0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, 0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6, + 0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6, 0xe7,0xe8,0xe9,0xba,0xe0,0xbb,0xb0,0x6d, + 0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87, 0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96, + 0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6, 0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07, +}; + +int ebcdic_to_ascii (int ch) +{ + int j; + + for (j = 32; j < 128; j++) + if (ascii_to_ebcdic_table[j] == ch) + return j; + + return '?'; +} + +#define HDR_LEN 120 + +void dump_hdng(void) +{ + int i; + char str[HDR_LEN+1], *p = str; + + showmajor("Sector 7 - Heading"); + getsector(7, buf); + + for (i = 0; i < (HDR_LEN/2); i++) { + *p++ = ebcdic_to_ascii((buf[i] >> 8) & 0xFF); + *p++ = ebcdic_to_ascii( buf[i] & 0xFF); + } + + *p = '\0'; + trim(str); + printf("%s\n", str); +} + +BOOL mget (int offset, char *name) +{ + char title[80]; + + if (dcom[offset] == 0) + return FALSE; + + getsector(dcom[offset], buf); + sprintf(title, "Sector %x - %s", dcom[offset], name); + showmajor(title); + return TRUE; +} + +void dump_scra (void) +{ + if (! mget(SCRA, "SCRA")) + return; + + dump(verbose ? SECLEN : 32); +} + +void dump_let (void) +{ + if (! mget(ULET, "LET")) + return; +} + +void dump_flet (void) +{ + if (! mget(FLET, "FLET")) + return; +} + +void dump_cib (void) +{ + if (! mget(CIBA, "CIB")) + return; + + dump(verbose ? SECLEN : 32); +} + +#define LFHD 5 // WORD COUNT OF LET/FLET HEADER PMN09970 +#define LFEN 3 // NO OF WDS PER LET/FLET ENTRY PMN09980 +#define SCTN 0 // RLTY ADDR OF LET/FLET SCTR NO. PMN09990 +#define UAFX 1 // RLTV ADDR OF SCTR ADDR OF UA/FXA PMN10000 +#define WDSA 3 // RLTV ADDR OF WDS AVAIL IN SCTR PMN10010 +#define NEXT 4 // RLTV ADDR OF ADDR NEXT SCTR PMN10020 +#define LFNM 0 // RLTV ADDR OF LET/FLET ENTRY NAME PMN10030 +#define BLCT 2 // RLTV ADDR OF LET/FLET ENTRY DBCT PMN10040 + +void bail (char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + fprintf(stderr, fmt, args); + va_end(args); + putchar('\n'); + + exit(1); +} + +// --------------------------------------------------------------------------------- +// trim - remove trailing whitespace from string s +// --------------------------------------------------------------------------------- + +char *trim (char *s) +{ + char *os = s, *nb; + + for (nb = s-1; *s; s++) + if (*s > ' ') + nb = s; + + nb[1] = '\0'; + return os; +} + +/* ------------------------------------------------------------------------ + * lowcase - force a string to lowercase (ASCII) + * ------------------------------------------------------------------------ */ + +char *lowcase (char *str) +{ + char *s; + + for (s = str; *s; s++) { + if (*s >= 'A' && *s <= 'Z') + *s += 32; + } + + return str; +} + diff --git a/Ibm1130/diskview.mak b/Ibm1130/diskview.mak new file mode 100644 index 00000000..ef9a8cf3 --- /dev/null +++ b/Ibm1130/diskview.mak @@ -0,0 +1,175 @@ +# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=Win32 Debug +!MESSAGE No configuration specified. Defaulting to Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "diskview.mak" CFG="Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "Win32 Debug" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "WinRel" +# PROP BASE Intermediate_Dir "WinRel" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "WinRel" +# PROP Intermediate_Dir "WinRel" +OUTDIR=.\WinRel +INTDIR=.\WinRel + +ALL : $(OUTDIR)/diskview.exe $(OUTDIR)/diskview.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"diskview.pch" /Fo$(INTDIR)/ /c +CPP_OBJS=.\WinRel/ +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"diskview.bsc" +BSC32_SBRS= \ + $(INTDIR)/diskview.sbr \ + $(INTDIR)/util_io.sbr + +$(OUTDIR)/diskview.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\ + /INCREMENTAL:no /PDB:$(OUTDIR)/"diskview.pdb" /MACHINE:I386\ + /OUT:$(OUTDIR)/"diskview.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/diskview.obj \ + $(INTDIR)/util_io.obj + +$(OUTDIR)/diskview.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "WinDebug" +# PROP BASE Intermediate_Dir "WinDebug" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "WinDebug" +# PROP Intermediate_Dir "WinDebug" +OUTDIR=.\WinDebug +INTDIR=.\WinDebug + +ALL : $(OUTDIR)/diskview.exe $(OUTDIR)/diskview.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"diskview.pch" /Fo$(INTDIR)/\ + /Fd$(OUTDIR)/"diskview.pdb" /c +CPP_OBJS=.\WinDebug/ +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"diskview.bsc" +BSC32_SBRS= \ + $(INTDIR)/diskview.sbr \ + $(INTDIR)/util_io.sbr + +$(OUTDIR)/diskview.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\ + /INCREMENTAL:yes /PDB:$(OUTDIR)/"diskview.pdb" /DEBUG /MACHINE:I386\ + /OUT:$(OUTDIR)/"diskview.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/diskview.obj \ + $(INTDIR)/util_io.obj + +$(OUTDIR)/diskview.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Group "Source Files" + +################################################################################ +# Begin Source File + +SOURCE=.\diskview.c + +$(INTDIR)/diskview.obj : $(SOURCE) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\util_io.c +DEP_UTIL_=\ + .\util_io.h + +$(INTDIR)/util_io.obj : $(SOURCE) $(DEP_UTIL_) $(INTDIR) + +# End Source File +# End Group +# End Project +################################################################################ diff --git a/Ibm1130/dmsr2v12phases.h b/Ibm1130/dmsr2v12phases.h new file mode 100644 index 00000000..47fbb2d9 --- /dev/null +++ b/Ibm1130/dmsr2v12phases.h @@ -0,0 +1,171 @@ +0x01, "DUP - COMMON SUBROUTINES", +0x02, "DUP - CTRL RECORD PROCESSOR", +0x03, "DUP - STORE PHASE", +0x04, "DUP - *FILES, *LOCAL, *NOCAL PHASE", +0x05, "DUP - DUMP PHASE", +0x06, "DUP - DUMP LET/FLET PHASE", +0x07, "DUP - DELETE PHASE", +0x08, "DUP - DEFINE PHASE", +0x09, "DUP - EXIT PHASE", +0x0A, "DUP - CARD I/O INTERFACE", +0x0B, "DUP - KEYBOARD INPUT INTERFACE", +0x0C, "DUP - PAPER TAPE I/O INTERFACE", +0x0D, "DUP - SAVED UPCOR PHASE", +0x0E, "DUP - PRINCIPAL I/O DUMMY PHASE", +0x0F, "DUP - PRINCIPAL I/O (W/O KB) DUMMY PHASE", +0x10, "DUP - PAPER TAPE I/O DUMMY PHASE", +0x11, "DUP - MOVE DCI PROGRAMS TO UA OR FXA", +0x12, "DUP - EXIT TO MODIF DUMMY PHASE", + +0x1F, "FOR - INPUT PHASE", +0x20, "FOR - CLASSIFIERPHASE", +0x21, "FOR - CHECK ORDER/ST NO PHASE", +0x22, "FOR - COMMON SUBR OR FUNCTION PHASE", +0x23, "FOR - DIMENSION/REAL/INTEGER PHASE", +0x24, "FOR - REAL CONSTANT PHASE", +0x25, "FOR - DEFINE FILE, CALL LINK/EXIT PHASE", +0x26, "FOR - VARIABLE, STMT FUNC PHASE", +0x27, "FOR - DATA STATEMENT PHASE", +0x28, "FOR - FORMAT STATEMENT PHASE", +0x29, "FOR - SUBTRACT DECOMPOSITION PHASE", +0x2A, "FOR - ASCAN I PHASE", +0x2B, "FOR - ASCAN II PHASE", +0x2C, "FOR - DO/CONTINUE/ETC PHASE", +0x2D, "FOR - SUBSCRIPT OPTIMIZATION PHASE", +0x2E, "FOR - SCAN PHASE", +0x2F, "FOR - EXPANDER I PHASE", +0x30, "FOR - EXPANDER II PHASE", +0x31, "FOR - DATA ALLOCATION PHASE", +0x32, "FOR - COMPILATION ERROR PHASE", +0x33, "FOR - STATEMENT ALLOCATION PHASE", +0x34, "FOR - LIST STATEMENT PHASE", +0x35, "FOR - LIST SYMBOL TABLE PHASE", +0x36, "FOR - LIST CONSTANTS PHASE", +0x37, "FOR - OUTPUT I PHASE", +0x38, "FOR - OUTPUT II PHASE", +0x39, "FOR - RECOVERY/EXIT PHASE", + +0X51, "COBOL 51", +0X52, "COBOL 52", +0X53, "COBOL 53", +0X54, "COBOL 54", +0X55, "COBOL 55", +0X56, "COBOL 56", +0X57, "COBOL 57", +0X58, "COBOL 58", +0X59, "COBOL 59", +0X5A, "COBOL 5A", +0X5B, "COBOL 5B", +0X5C, "COBOL 5C", + +0X6E, "SUP PHASE 1 - MONITOR CONTROL RECORD ANALYZER", +0x6F, "SUP PHASE 2 - JOB PROCESSING", +0x70, "SUP PHASE 3 - DELETE TEMPORARY LET", +0x71, "SUP PHASE 4 - XEQ PROCESSING", +0x72, "SUP PHASE 5 - SUPV CONTROL REC PROCESSING", +0X73, "SYSTEM DUMP-CORE-TO-PRINTER", +0X74, "AUXILIARY SUPERVISOR", +0X78, "CORE LOAD BUILDER, PHASE 1", +0x79, "CORE LOAD BUILDER, PHASE 2", +0x7A, "CORE LOAD BUILDER, PHASE 3", +0x7B, "CORE LOAD BUILDER, PHASE 4", +0x7C, "CORE LOAD BUILDER, PHASE 5", +0x7D, "CORE LOAD BUILDER, PHASE 6", +0x7E, "CORE LOAD BUILDER, PHASE 7", +0x7F, "CORE LOAD BUILDER, PHASE 8", +0x80, "CORE LOAD BUILDER, PHASE 9", +0x81, "CORE LOAD BUILDER, PHASE 10", +0x82, "CORE LOAD BUILDER, PHASE 11", +0x83, "CORE LOAD BUILDER, PHASE 12", +0x84, "CORE LOAD BUILDER, PHASE 13", + +0X8C, "SYS 1403 READER", +0x8D, "SYS 1132 PRINTER", +0x8E, "SYS CONSOLE PRINTER", +0x8F, "SYS 2501/1442 READER", +0x90, "SYS 1442/1442 READER", +0x91, "SYS 1134/1055 PAPER TAPE IO", +0x92, "SYS KEYBOARD", +0x93, "SYS 2501/1442 CONVERSION", +0x94, "SYS 1134/1055 CONVERSION", +0x95, "SYS KEYBOARD CONVERSION", +0x96, "DISKZ", +0x97, "SYS DISK1", +0x98, "SYS DISKN", + +0xA0, "CIL CORE IMAGE LOADER - PHASE 1", +0xA1, "CIL CORE IMAGE LOADER - PHASE 2", + +0XB0, "RPG B0", +0XB1, "RPG B1", +0XB2, "RPG B2", +0XB3, "RPG B3", +0XB4, "RPG B4", +0XB5, "RPG B5", +0XB6, "RPG B6", +0XB7, "RPG B7", +0XB8, "RPG B8", +0XB9, "RPG B9", +0XBA, "RPG BA", +0XBB, "RPG BB", +0XBC, "RPG BC", +0XBD, "RPG BD", +0XBE, "RPG BE", +0XBF, "RPG BF", +0XC0, "RPG C0", +0XC1, "RPG C1", +0XC2, "RPG C2", +0XC3, "RPG C3", +0XC4, "RPG C4", +0XC5, "RPG C5", +0XC6, "RPG C6", +0XC7, "RPG C7", +0XC8, "RPG C8", +0XC9, "RPG C9", +0XCA, "RPG CA", +0XCB, "RPG CB", +0XCC, "RPG CC", + +0XCD, "DUP PART 2 - CTRL", +0XCE, "DUP PART 2 - MACRO UPDATE", + +0XCF, "ASM INITIALIZATION PHASE", +0xD0, "ASM CARD CONVERSION PHASE", +0xD1, "ASM DSF OUTPUT PHASE", +0xD2, "ASM INTERMEDIATE INPUT PHASE", +0xD3, "ASM END STATEMENT PHASE", +0xD4, "ASM ASSEMBLY ERROR PHASE", +0xD5, "ASM CONTROL CARDS I", +0xD6, "ASM CONTROL CARDS 2", +0xD7, "ASM DUMMY SYST SYMBOL TBL", +0xD8, "ASM SYMBOL TABLE OPTIONS PHASE", +0xD9, "ASM EXIT PHASE", +0xDA, "ASM PROG HEADER MNEMONICS PH", +0xDB, "ASM FILE STATEMENT PHASE", +0xDC, "ASM COMMON SUBROUTINES,ASCOM", +0xE4, "ASM INTERMEDIATE I/O", +0xE5, "ASM SYMBOL TABLE OVERFLOW", +0xDD, "ASM PROG CONTROL MNEMONICS PH", +0xDE, "ASM IMPERATIVE STATEMENTS PH", +0xDF, "ASM DECML,XFLC PROCESSING PH", +0xE0, "ASM DECIMAL CONVERSION PH", +0xE1, "ASM PROG LINKAGE PHASE", +0xE2, "ASM DMES PROCESSING PHASE", +0xE3, "ASM PUNCH CONVERSION PHASE", +0xE6, "ASM GRAPHIC ORDER PHASE", +0xE8, "ASM CONTROL CARDS III", +0xE9, "ASM MACRO PH 1 - SPECIAL OP AND PREPROCESSI", +0xEA, "MACRO PHASE 1A - SPECIAL PSEUDO OPS", +0xEB, "MACRO PHASE 1B - CONDITIONAL ASM PSEUDO OPS", +0xEC, "ASM MACRO PHASE 2 - MACRO DEFINITION", +0xED, "MACRO PHASE 2A - MACRO DEFINITION", +0xEE, "MACRO PHASE 2B - MACRO DEFINITION", +0xEF, "MACRO PHASE 3 - MACRO EXPANSION", +0xF0, "MACRO PHASE 3A - MACRO EXPANSION", +0xF1, "MACRO PHASE 3B - MACRO EXPANSION", +0xE7, "ASM DIVISION OPERATOR", +0xF2, "ASM CROSS-REFERENCE PART I", +0xF3, "ASM CROSS-REFERENCE PART 2A", +0xF4, "ASM CROSS-REFERENCE PART 2B", +0xF5, "ASM CROSS-REFERENCE PART 2C", +0xF6, "ASM CROSS-REFERENCE PART III", diff --git a/Ibm1130/dmsr2v12slet.h b/Ibm1130/dmsr2v12slet.h new file mode 100644 index 00000000..326baa06 --- /dev/null +++ b/Ibm1130/dmsr2v12slet.h @@ -0,0 +1,129 @@ +// DMS R2V12 SLET without RPG, for debugging only + +0x0001, 0x7c50, 0x032f, 0x0008, +0x0002, 0x11de, 0x05a2, 0x000b, +0x0003, 0x21de, 0x05a2, 0x0010, +0x0004, 0x01de, 0x03c0, 0x0015, +0x0005, 0x41de, 0x0550, 0x0018, +0x0006, 0x01de, 0x03c0, 0x001d, +0x0007, 0x01de, 0x05a2, 0x0020, +0x0008, 0x01de, 0x05a2, 0x0025, +0x0009, 0x01de, 0x0500, 0x002a, +0x000a, 0x7a06, 0x00db, 0x002e, +0x000b, 0x7a06, 0x0035, 0x002f, +0x000c, 0x7a06, 0x00d8, 0x0030, +0x000d, 0x7782, 0x087c, 0x0031, +0x000e, 0x7a06, 0x0248, 0x0038, +0x000f, 0x7a06, 0x0248, 0x003a, +0x0010, 0x7a06, 0x0248, 0x003c, +0x0011, 0x01de, 0x0280, 0x003e, +0x0012, 0x0e6e, 0x0140, 0x0040, +0x001f, 0x760c, 0x09f1, 0x0041, +0x0020, 0x7a34, 0x0500, 0x0049, +0x0021, 0x7a34, 0x0280, 0x004d, +0x0022, 0x7a34, 0x03c0, 0x004f, +0x0023, 0x7a34, 0x0500, 0x0052, +0x0024, 0x7a34, 0x03c0, 0x0056, +0x0025, 0x7a34, 0x0280, 0x0059, +0x0026, 0x7a34, 0x0500, 0x005b, +0x0027, 0x7a34, 0x03f0, 0x005f, +0x0028, 0x7a34, 0x03c0, 0x0063, +0x0029, 0x7a34, 0x03c0, 0x0066, +0x002a, 0x7a34, 0x03c0, 0x0069, +0x002b, 0x7a34, 0x03c0, 0x006c, +0x002c, 0x7a34, 0x0500, 0x006f, +0x002d, 0x7a34, 0x0500, 0x0073, +0x002e, 0x7a34, 0x0500, 0x0077, +0x002f, 0x7a34, 0x0500, 0x007b, +0x0030, 0x7a34, 0x0500, 0x007f, +0x0031, 0x7a34, 0x0404, 0x0083, +0x0032, 0x7a34, 0x03c0, 0x0087, +0x0033, 0x7a34, 0x03c0, 0x008a, +0x0034, 0x7a34, 0x0280, 0x008d, +0x0035, 0x7a34, 0x03c0, 0x008f, +0x0036, 0x7a34, 0x03c0, 0x0092, +0x0037, 0x7a34, 0x0500, 0x0095, +0x0038, 0x7b96, 0x03c0, 0x0099, +0x0039, 0x766e, 0x013e, 0x009c, +0x006e, 0x04fe, 0x02fe, 0x009d, +0x006f, 0x07fe, 0x052b, 0x00a0, +0x0070, 0x07fe, 0x0280, 0x00a5, +0x0071, 0x07fe, 0x0280, 0x00a7, +0x0072, 0x07fe, 0x03ea, 0x00a9, +0x0073, 0x0506, 0x04f8, 0x00ad, +0x0074, 0x0400, 0x0189, 0x00b1, +0x0078, 0x01e0, 0x0782, 0x00b3, +0x0079, 0x05bc, 0x04dd, 0x00ba, +0x007a, 0x08b6, 0x01e8, 0x00be, +0x007b, 0x08b6, 0x01e8, 0x00c0, +0x007c, 0x08b6, 0x01e8, 0x00c2, +0x007d, 0x08b6, 0x01e8, 0x00c4, +0x007e, 0x0aa0, 0x0140, 0x00c6, +0x007f, 0x0aa0, 0x0140, 0x00c7, +0x0080, 0x0aa0, 0x0140, 0x00c8, +0x0081, 0x0aa0, 0x0140, 0x00c9, +0x0082, 0x0be2, 0x0140, 0x00ca, +0x0083, 0x08b6, 0x01e8, 0x00cb, +0x0084, 0x0aa0, 0x0140, 0x00cd, +0x008c, 0x0000, 0x0134, 0x80ceU, +0x008d, 0x0000, 0x0113, 0x00cf, +0x008e, 0x0000, 0x011f, 0x00d0, +0x008f, 0x0000, 0x009c, 0x80d1U, +0x0090, 0x0000, 0x00ab, 0x00d2, +0x0091, 0x0000, 0x016c, 0x80d3U, +0x0092, 0x0000, 0x0174, 0x00d5, +0x0093, 0x0000, 0x00b9, 0x00d7, +0x0094, 0x0000, 0x0003, 0x80d8U, +0x0095, 0x0000, 0x0003, 0x00d9, +0x0096, 0x00f0, 0x00ec, 0x00da, +0x0097, 0x00f0, 0x01a2, 0x00db, +0x0098, 0x00f0, 0x02b0, 0x00dd, +0x0099, 0x0000, 0x0113, 0x00cf, +0x009a, 0x0000, 0x00ab, 0x00d2, +0x009b, 0x0000, 0x00ab, 0x00d2, +0x009c, 0x0000, 0x00b9, 0x00d7, +0x009d, 0x0000, 0x00b9, 0x00d7, +0x00a0, 0x0000, 0x016c, 0x00e0, +0x00a1, 0x0000, 0x01c0, 0x00e2, +0x00cd, 0x11de, 0x0280, 0x00e4, +0x00ce, 0x01de, 0x11df, 0x00e6, +0x00cf, 0x01e0, 0x026b, 0x00f5, +0x00d0, 0x01e8, 0x00bb, 0x00f7, +0x00d1, 0x01e8, 0x005f, 0x00f8, +0x00d2, 0x01e8, 0x005f, 0x00f9, +0x00d3, 0x0280, 0x01d5, 0x00fa, +0x00d4, 0x0ad0, 0x0145, 0x00fc, +0x00d5, 0x0280, 0x01d6, 0x00fe, +0x00d6, 0x0280, 0x0113, 0x0100, +0x00d7, 0x0000, 0x0130, 0x0101, +0x00d8, 0x07a8, 0x0254, 0x0102, +0x00d9, 0x0280, 0x01d7, 0x0104, +0x00da, 0x0280, 0x01a0, 0x0106, +0x00db, 0x0282, 0x00a3, 0x0108, +0x00dc, 0x0458, 0x05a7, 0x0109, +0x00dd, 0x0280, 0x01d5, 0x010e, +0x00de, 0x0280, 0x01d6, 0x0110, +0x00df, 0x0280, 0x017c, 0x0112, +0x00e0, 0x0282, 0x0127, 0x0114, +0x00e1, 0x0280, 0x0196, 0x0115, +0x00e2, 0x0280, 0x01d8, 0x0117, +0x00e3, 0x0280, 0x0099, 0x0119, +0x00e4, 0x098a, 0x005f, 0x011a, +0x00e5, 0x098a, 0x0062, 0x011b, +0x00e6, 0x0eca, 0x03c1, 0x011c, +0x00e7, 0x0280, 0x00b8, 0x0120, +0x00e8, 0x0280, 0x017f, 0x0121, +0x00e9, 0x0280, 0x01d6, 0x0123, +0x00ea, 0x0280, 0x01d9, 0x0125, +0x00eb, 0x0280, 0x01d9, 0x0127, +0x00ec, 0x0280, 0x01ca, 0x0129, +0x00ed, 0x0280, 0x01c2, 0x012b, +0x00ee, 0x05dc, 0x0158, 0x012d, +0x00ef, 0x07ac, 0x0051, 0x012f, +0x00f0, 0x0280, 0x01af, 0x0130, +0x00f1, 0x12f4, 0x027f, 0x0132, +0x00f2, 0x0280, 0x01c7, 0x0134, +0x00f3, 0x07a8, 0x0052, 0x0136, +0x00f4, 0x0924, 0x005b, 0x0137, +0x00f5, 0x0886, 0x003d, 0x0138, +0x00f6, 0x0eca, 0x03b2, 0x0139, diff --git a/Ibm1130/ibm1130.mak b/Ibm1130/ibm1130.mak index b7101148..e9938321 100644 --- a/Ibm1130/ibm1130.mak +++ b/Ibm1130/ibm1130.mak @@ -66,8 +66,13 @@ BSC32_SBRS= \ $(INTDIR)/ibm1130_cr.sbr \ $(INTDIR)/ibm1130_stddev.sbr \ $(INTDIR)/ibm1130_disk.sbr \ + $(INTDIR)/ibm1130_gdu.sbr \ + $(INTDIR)/ibm1130_gui.sbr \ + $(INTDIR)/ibm1130_prt.sbr \ + $(INTDIR)/scp.sbr \ $(INTDIR)/scp_tty.sbr \ - $(INTDIR)/scp.sbr + $(INTDIR)/sim_tmxr.sbr \ + $(INTDIR)/sim_sock.sbr $(OUTDIR)/ibm1130.bsc : $(OUTDIR) $(BSC32_SBRS) $(BSC32) @<< @@ -76,10 +81,10 @@ $(OUTDIR)/ibm1130.bsc : $(OUTDIR) $(BSC32_SBRS) LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib wsock32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib\ - /NOLOGO /SUBSYSTEM:console /INCREMENTAL:no /PDB:$(OUTDIR)/"ibm1130.pdb"\ - /MACHINE:I386 /OUT:$(OUTDIR)/"ibm1130.exe" + wsock32.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:no\ + /PDB:$(OUTDIR)/"ibm1130.pdb" /MACHINE:I386 /OUT:$(OUTDIR)/"ibm1130.exe" DEF_FILE= LINK32_OBJS= \ $(INTDIR)/ibm1130_cpu.obj \ @@ -88,8 +93,13 @@ LINK32_OBJS= \ $(INTDIR)/ibm1130_stddev.obj \ $(INTDIR)/ibm1130.res \ $(INTDIR)/ibm1130_disk.obj \ + $(INTDIR)/ibm1130_gdu.obj \ + $(INTDIR)/ibm1130_gui.obj \ + $(INTDIR)/ibm1130_prt.obj \ + $(INTDIR)/scp.obj \ $(INTDIR)/scp_tty.obj \ - $(INTDIR)/scp.obj + $(INTDIR)/sim_tmxr.obj \ + $(INTDIR)/sim_sock.obj $(OUTDIR)/ibm1130.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) $(LINK32) @<< @@ -133,8 +143,13 @@ BSC32_SBRS= \ $(INTDIR)/ibm1130_cr.sbr \ $(INTDIR)/ibm1130_stddev.sbr \ $(INTDIR)/ibm1130_disk.sbr \ + $(INTDIR)/ibm1130_gdu.sbr \ + $(INTDIR)/ibm1130_gui.sbr \ + $(INTDIR)/ibm1130_prt.sbr \ + $(INTDIR)/scp.sbr \ $(INTDIR)/scp_tty.sbr \ - $(INTDIR)/scp.sbr + $(INTDIR)/sim_tmxr.sbr \ + $(INTDIR)/sim_sock.sbr $(OUTDIR)/ibm1130.bsc : $(OUTDIR) $(BSC32_SBRS) $(BSC32) @<< @@ -143,10 +158,10 @@ $(OUTDIR)/ibm1130.bsc : $(OUTDIR) $(BSC32_SBRS) LINK32=link.exe # ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 -# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib wsock32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib comdlg32.lib advapi32.lib\ - /NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes /PDB:$(OUTDIR)/"ibm1130.pdb" /DEBUG\ - /MACHINE:I386 /OUT:$(OUTDIR)/"ibm1130.exe" + wsock32.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes\ + /PDB:$(OUTDIR)/"ibm1130.pdb" /DEBUG /MACHINE:I386 /OUT:$(OUTDIR)/"ibm1130.exe" DEF_FILE= LINK32_OBJS= \ $(INTDIR)/ibm1130_cpu.obj \ @@ -155,8 +170,13 @@ LINK32_OBJS= \ $(INTDIR)/ibm1130_stddev.obj \ $(INTDIR)/ibm1130.res \ $(INTDIR)/ibm1130_disk.obj \ + $(INTDIR)/ibm1130_gdu.obj \ + $(INTDIR)/ibm1130_gui.obj \ + $(INTDIR)/ibm1130_prt.obj \ + $(INTDIR)/scp.obj \ $(INTDIR)/scp_tty.obj \ - $(INTDIR)/scp.obj + $(INTDIR)/sim_tmxr.obj \ + $(INTDIR)/sim_sock.obj $(OUTDIR)/ibm1130.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) $(LINK32) @<< @@ -218,7 +238,6 @@ DEP_IBM1130_=\ .\ibm1130_defs.h\ .\ibm1130_conout.h\ .\ibm1130_conin.h\ - .\ibm1130_prtwheel.h\ ..\sim_defs.h $(INTDIR)/ibm1130_stddev.obj : $(SOURCE) $(DEP_IBM1130_) $(INTDIR) @@ -242,6 +261,8 @@ $(INTDIR)/ibm1130.res : $(SOURCE) $(DEP_IBM1130_R) $(INTDIR) SOURCE=.\ibm1130_disk.c DEP_IBM1130_D=\ .\ibm1130_defs.h\ + .\dmsr2v12phases.h\ + .\dmsr2v12slet.h\ ..\sim_defs.h $(INTDIR)/ibm1130_disk.obj : $(SOURCE) $(DEP_IBM1130_D) $(INTDIR) @@ -250,6 +271,55 @@ $(INTDIR)/ibm1130_disk.obj : $(SOURCE) $(DEP_IBM1130_D) $(INTDIR) ################################################################################ # Begin Source File +SOURCE=.\ibm1130_gdu.c +DEP_IBM1130_G=\ + .\ibm1130_defs.h\ + ..\sim_defs.h + +$(INTDIR)/ibm1130_gdu.obj : $(SOURCE) $(DEP_IBM1130_G) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\ibm1130_gui.c +DEP_IBM1130_GU=\ + .\ibm1130_defs.h\ + ..\sim_defs.h + +$(INTDIR)/ibm1130_gui.obj : $(SOURCE) $(DEP_IBM1130_GU) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\ibm1130_prt.c +DEP_IBM1130_P=\ + .\ibm1130_defs.h\ + .\ibm1130_prtwheel.h\ + ..\sim_defs.h + +$(INTDIR)/ibm1130_prt.obj : $(SOURCE) $(DEP_IBM1130_P) $(INTDIR) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\pdp11\supnik\scp.c +DEP_SCP_C=\ + ..\sim_defs.h\ + \pdp11\supnik\sim_rev.h\ + \pdp11\supnik\sim_sock.h\ + \pdp11\supnik\sim_tmxr.h\ + \MSVC20\INCLUDE\sys\TYPES.H + +$(INTDIR)/scp.obj : $(SOURCE) $(DEP_SCP_C) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + SOURCE=..\scp_tty.c DEP_SCP_T=\ ..\sim_defs.h @@ -261,12 +331,28 @@ $(INTDIR)/scp_tty.obj : $(SOURCE) $(DEP_SCP_T) $(INTDIR) ################################################################################ # Begin Source File -SOURCE=.\scp.c -DEP_SCP_C=\ - .\sim_defs.h\ - ..\sim_rev.h +SOURCE=\pdp11\supnik\sim_tmxr.c +DEP_SIM_T=\ + ..\sim_defs.h\ + \pdp11\supnik\sim_sock.h\ + \pdp11\supnik\sim_tmxr.h\ + \MSVC20\INCLUDE\sys\TYPES.H -$(INTDIR)/scp.obj : $(SOURCE) $(DEP_SCP_C) $(INTDIR) +$(INTDIR)/sim_tmxr.obj : $(SOURCE) $(DEP_SIM_T) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\pdp11\supnik\sim_sock.c +DEP_SIM_S=\ + ..\sim_defs.h\ + \pdp11\supnik\sim_sock.h\ + \MSVC20\INCLUDE\sys\TYPES.H + +$(INTDIR)/sim_sock.obj : $(SOURCE) $(DEP_SIM_S) $(INTDIR) + $(CPP) $(CPP_PROJ) $(SOURCE) # End Source File # End Group diff --git a/Ibm1130/ibm1130_conin.h b/Ibm1130/ibm1130_conin.h index de39ae22..beaef7c9 100644 --- a/Ibm1130/ibm1130_conin.h +++ b/Ibm1130/ibm1130_conin.h @@ -1,3 +1,14 @@ +/* + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org + */ + // ctrl-M (Enter) => EOF // ctrl-U => Erase field // ctrl-Q => Interrupt request (not here) diff --git a/Ibm1130/ibm1130_conout.h b/Ibm1130/ibm1130_conout.h index 4bbc6df7..dc46f765 100644 --- a/Ibm1130/ibm1130_conout.h +++ b/Ibm1130/ibm1130_conout.h @@ -1,4 +1,14 @@ -/* IBM1130 CONSOLE OUTPUT TO ASCII CONVERSION TABLE */ +/* IBM1130 CONSOLE OUTPUT TO ASCII CONVERSION TABLE + * + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org + */ #define _0_ '\0' diff --git a/Ibm1130/ibm1130_cpu.c b/Ibm1130/ibm1130_cpu.c index e9ee607f..a41001a1 100644 --- a/Ibm1130/ibm1130_cpu.c +++ b/Ibm1130/ibm1130_cpu.c @@ -1,27 +1,20 @@ /* ibm1130_cpu.c: IBM 1130 CPU simulator - Copyright (c) 2002, Brian Knittel - Based on PDP-11 simulator written by Robert M Supnik + Based on the SIMH package written by Robert M Supnik - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org 25-Jun-01 BLK Written + 10-May-02 BLK Fixed bug in MDX instruction 27-Mar-02 BLK Made BOSC work even in short form + 16-Aug-02 BLK Fixed bug in multiply instruction; didn't work with negative values The register state for the IBM 1130 CPU is: @@ -40,7 +33,6 @@ WRU simulator-break character IntRun Int Run flag (causes level 5 interrupt after every instruction) ILSW0..5 interrupt level status words - IPS instructions per second throttle (not a real 1130 register) The SAR (storage address register) and SBR (storage buffer register) are updated but not saved in the CPU state; they matter only to the GUI. @@ -129,7 +121,28 @@ #define save_ibkpt (cpu_unit.u3) /* will be SAVEd */ -#define UPDATE_INTERVAL 2500 // GUI: set to 100000/f where f = desired updates/second of 1130 time +#define UPDATE_BY_TIMER +#define ENABLE_BACKTRACE +#define CGI_SUPPORT + +static void cgi_start(void); +static void cgi_stop(t_stat reason); + +// hook pointers from scp.c +void (*sim_vm_init) (void) = &sim_init; +extern char* (*sim_vm_read) (char *ptr, int32 size, FILE *stream); +extern void (*sim_vm_post) (t_bool from_scp); +extern CTAB *sim_vm_cmd; + +// space to store extra simulator-specific commands +#define MAX_EXTRA_COMMANDS 10 +CTAB x_cmds[MAX_EXTRA_COMMANDS]; + +#ifdef WIN32 +# define CRLF "\r\n" +#else +# define CRLF "\n" +#endif /* ------------------------------------------------------------------------ * initializers for globals @@ -138,17 +151,10 @@ #define SIGN_BIT(v) ((v) & 0x8000) #define DWSIGN_BIT(v) ((v) & 0x80000000) -#define MODE_SS 3 /* RUNMODE values. SS and SMC are not implemented in this simulator */ -#define MODE_SMC 2 -#define MODE_INT_RUN 1 -#define MODE_RUN 0 -#define MODE_SI -1 -#define MODE_DISP -2 -#define MODE_LOAD -3 - -uint16 M[MAXMEMSIZE]; /* core memory, up to 32Kwords */ +uint16 M[MAXMEMSIZE]; /* core memory, up to 32Kwords (note: don't even think about trying 64K) */ uint16 ILSW[6] = {0,0,0,0,0,0}; /* interrupt level status words */ int32 IAR; /* instruction address register */ +int32 prev_IAR; /* instruction address register at start of current instruction */ int32 SAR, SBR; /* storage address/buffer registers */ int32 OP, TAG, CCC; /* instruction decoded pieces */ int32 CES; /* console entry switches */ @@ -159,15 +165,22 @@ int32 iplpending = 0; /* interrupted IPL's */ int32 tbit = 0; /* trace flag (causes level 5 IRQ after each instr) */ int32 V = 0, C = 0; /* condition codes */ int32 wait_state = 0; /* wait state (waiting for an IRQ) */ +int32 wait_lamp = TRUE; /* alternate indicator to light the wait lamp on the GUI */ int32 int_req = 0; /* sum of interrupt request levels active */ +int32 int_lamps = 0; /* accumulated version of int_req - gives lamp persistence */ int32 int_mask; /* current active interrupt mask (ipl sensitive) */ -int32 SR = 0; /* switch register */ -int32 DR = 0; /* display register */ int32 mem_mask; -int32 IPS = 0; /* throttle: instructions per second */ +int32 cpu_dsw = 0; /* CPU device status word */ int32 ibkpt_addr = -1; /* breakpoint addr */ +int32 sim_gui = TRUE; /* enable gui */ +t_bool running = FALSE; /* TRUE if CPU is running */ +t_bool power = TRUE; /* TRUE if CPU power is on */ +t_bool cgi = FALSE; /* TRUE if we are running as a CGI program */ +t_stat reason; /* CPU execution loop control */ -t_bool display_console = 1; +static int32 int_masks[6] = { + 0x00, 0x20, 0x30, 0x38, 0x3C, 0x3E /* IPL 0 is highest prio (sees no other interrupts) */ +}; /* ------------------------------------------------------------------------ * Function declarations @@ -178,33 +191,33 @@ t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); t_stat cpu_svc (UNIT *uptr); t_stat cpu_set_size (UNIT *uptr, int32 value); - -t_stat console_reset (DEVICE *dptr); - -extern t_stat ts_wr (int32 data, int32 addr, int32 access); - -extern UNIT cr_unit; - void calc_ints (void); +extern t_stat ts_wr (int32 data, int32 addr, int32 access); +extern t_stat detach_cmd (int flags, char *cptr); +extern UNIT cr_unit; +extern int32 sim_switches; + +#ifdef ENABLE_BACKTRACE + static void archive_backtrace(char *inst); + static void reset_backtrace (void); + static void show_backtrace (int nshow); + static t_stat backtrace_cmd (int flag, char *cptr); +#else + #define archive_backtrace(inst) + #define reset_backtrace() + #define show_backtrace(ntrace) +#endif + +static void init_console_window (void); +static void destroy_console_window (void); +static t_stat view_cmd (int flag, char *cptr); +static t_stat cgi_cmd (int flag, char *cptr); +static t_stat cpu_attach (UNIT *uptr, char *cptr); static t_bool bsctest (int32 DSPLC, t_bool reset_V); static void exit_irq (void); static void trace_instruction (void); -static int32 int_masks[6] = { - 0x00, 0x20, 0x30, 0x38, 0x3C, 0x3E /* IPL 0 is highest prio (sees no other interrupts) */ -}; - -static void init_console_window (void); -static void destroy_console_window (void); -static void sleep_msec (int msec); - -/* ------------------------------------------------------------------------ - * cpu IO state - * ------------------------------------------------------------------------ */ - -static int con_dsw = 0; - /* ------------------------------------------------------------------------ * CPU data structures: * cpu_dev CPU device descriptor @@ -213,7 +226,7 @@ static int con_dsw = 0; * cpu_mod CPU modifier list * ------------------------------------------------------------------------ */ -UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK, INIMEMSIZE) }; +UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX | UNIT_BINK | UNIT_ATTABLE | UNIT_SEQ, INIMEMSIZE) }; REG cpu_reg[] = { { HRDATA (IAR, IAR, 32) }, @@ -225,7 +238,7 @@ REG cpu_reg[] = { { HRDATA (ipl, ipl, 32), REG_RO }, { HRDATA (iplpending, iplpending, 32), REG_RO }, { HRDATA (wait_state, wait_state, 32)}, - { HRDATA (DSW, con_dsw, 32), REG_RO }, + { HRDATA (DSW, cpu_dsw, 32), REG_RO }, { HRDATA (RUNMODE, RUNMODE, 32) }, { HRDATA (BREAK, ibkpt_addr, 32) }, { ORDATA (WRU, sim_int_char, 8) }, @@ -238,8 +251,6 @@ REG cpu_reg[] = { { HRDATA (ILSW4, ILSW[4], 32), REG_RO }, { HRDATA (ILSW5, ILSW[5], 32), REG_RO }, - { HRDATA (IPS, IPS, 32) }, - { NULL} }; @@ -254,18 +265,7 @@ DEVICE cpu_dev = { "CPU", &cpu_unit, cpu_reg, cpu_mod, 1, 16, 16, 1, 16, 16, &cpu_ex, &cpu_dep, &cpu_reset, - NULL, NULL, NULL }; - -REG console_reg[] = { // the GUI, so you can use Enable/Disable console - {HRDATA (*DEVENB, display_console, 1) }, - {NULL} -}; - -DEVICE console_dev = { - "CONSOLE", NULL, console_reg, NULL, - 0, 16, 16, 1, 16, 16, - NULL, NULL, console_reset, - NULL, NULL, NULL }; + NULL, cpu_attach, NULL}; // attaching to CPU creates cpu log file /* ------------------------------------------------------------------------ Memory read/write -- save SAR and SBR on the way in and out @@ -335,8 +335,9 @@ void calc_ints (void) newbits |= 0x20; } - int_req = newbits; - int_mask = (ipl < 0) ? 0xFFFF : int_masks[ipl]; /* be sure this is set correctly */ + int_req = newbits; + int_lamps |= int_req; + int_mask = (ipl < 0) ? 0xFFFF : int_masks[ipl]; /* be sure this is set correctly */ GUI_END_CRITICAL_SECTION } @@ -350,13 +351,13 @@ void calc_ints (void) void bail (char *msg) { - fprintf(stderr, "%s\n", msg); + printf("%s\n", msg); exit(1); } static void weirdop (char *msg, int offset) { - fprintf(stderr, "Weird opcode: %s at %04x\n", msg, IAR+offset); + printf("Weird opcode: %s at %04x\n", msg, IAR+offset); } static char *xio_devs[] = { @@ -375,10 +376,6 @@ static char *xio_funcs[] = { "control", "initw", "initr", "sense" }; -static t_stat reason; /* execution loop control */ -static t_bool running = FALSE; -static t_bool power = TRUE; - t_stat sim_instr (void) { extern int32 sim_interval; @@ -386,8 +383,14 @@ t_stat sim_instr (void) int32 i, eaddr, INDIR, IR, F, DSPLC, word2, oldval, newval, src, src2, dst, abit, xbit; int32 iocc_addr, iocc_op, iocc_dev, iocc_func, iocc_mod; char msg[50]; - int cwincount = 0, idelay, status; + int cwincount = 0, status; static long ninstr = 0; + static char *intlabel[] = {"INT0","INT1","INT2","INT3","INT4","INT5"}; + +#ifdef CGI_SUPPORT + if (cgi) + cgi_start(); +#endif if (running) /* this is definitely not reentrant */ return -1; @@ -403,20 +406,18 @@ t_stat sim_instr (void) /* Main instruction fetch/decode loop */ reason = 0; - - idelay = (IPS == 0) ? 0 : 1000/IPS; + wait_lamp = 0; /* release lock on wait lamp */ #ifdef GUI_SUPPORT update_gui(TRUE); + gui_run(TRUE); #endif while (reason == 0) { + IAR &= mem_mask; + #ifdef GUI_SUPPORT - if (idelay) { /* if we're running in slow mode, update GUI every time */ - update_gui(TRUE); - sleep_msec(idelay); - } - else { +#ifndef UPDATE_BY_TIMER #if (UPDATE_INTERVAL > 0) if (--cwincount <= 0) { update_gui(FALSE); /* update console lamps only every so many instructions */ @@ -424,9 +425,9 @@ t_stat sim_instr (void) } #else update_gui(FALSE); -#endif // UPDATE_INTERVAL - } -#endif // GUI_SUPPORT +#endif // ifdef UPDATE_INTERVAL +#endif // ifndef UPDATE_BY_TIMER +#endif // ifdef GUI_SUPPORT if (sim_interval <= 0) { /* any events timed out? */ if (sim_clock_queue != NULL) { @@ -459,6 +460,7 @@ t_stat sim_instr (void) wait_state = 0; /* exit wait state */ eaddr = ReadW(8+i); /* get IRQ vector */ + archive_backtrace(intlabel[i]); WriteW(eaddr, IAR); /* save IAR */ IAR = (eaddr+1) & mem_mask; /* go to next address */ continue; /* now continue processing */ @@ -486,6 +488,9 @@ t_stat sim_instr (void) reason = STOP_INVALID_INSTR; } + if (gdu_active()) /* but don't stop simulator if 2250 GDU is running */ + reason = 0; + continue; } @@ -499,7 +504,10 @@ t_stat sim_instr (void) } ninstr++; - trace_instruction(); /* log CPU details if logging is enabled */ + if (cpu_unit.flags & UNIT_ATT) + trace_instruction(); /* log CPU details if logging is enabled */ + + prev_IAR = IAR; /* save IAR before incrementing it */ IR = ReadW(IAR); /* fetch 1st word of instruction */ INCREMENT_IAR; @@ -549,13 +557,14 @@ t_stat sim_instr (void) iocc_func = (iocc_op >> 8) & 0x0007; iocc_mod = iocc_op & 0x00FF; - trace_io("* XIO %s %s mod %02x addr %04x", xio_funcs[iocc_func], xio_devs[iocc_dev], iocc_mod, iocc_addr); + if (cpu_unit.flags & UNIT_ATT) + trace_io("* XIO %s %s mod %02x addr %04x", xio_funcs[iocc_func], xio_devs[iocc_dev], iocc_mod, iocc_addr); ACC = 0; /* ACC is destroyed, and default XIO_SENSE_DEV result is 0 */ switch (iocc_func) { case XIO_UNUSED: - sprintf(msg, "Unknown XIO op %x on XIO device %02x", iocc_func, iocc_dev); + sprintf(msg, "Unknown op %x on device %02x", iocc_func, iocc_dev); xio_error(msg); break; @@ -623,7 +632,7 @@ t_stat sim_instr (void) xio_2250_display(iocc_addr, iocc_func, iocc_mod); break; default: - sprintf(msg, "XIO on unknown device %02x", iocc_dev); + sprintf(msg, "unknown device %02x", iocc_dev); xio_error(msg); break; } @@ -775,6 +784,7 @@ t_stat sim_instr (void) break; /* if any condition is true, do nothing */ } WriteW(eaddr, IAR); /* do subroutine call */ + archive_backtrace("BSI"); /* save info in back-trace buffer */ IAR = (eaddr + 1) & mem_mask; break; @@ -783,11 +793,14 @@ t_stat sim_instr (void) if (bsctest(IR, F)) /* long format; any indicator cancels branch */ break; + archive_backtrace((DSPLC & 0x40) ? "BOSC" : "BSC"); /* save info in back-trace buffer */ IAR = eaddr; /* no indicator means branch taken */ } else { /* short format: skip if any indicator hits */ - if (bsctest(IR, F)) + if (bsctest(IR, F)) { + archive_backtrace((DSPLC & 0x40) ? "BOSC" : "BSC"); /* save info in back-trace buffer */ INCREMENT_IAR; + } } // 27Mar02: moved this test out of the (F) condition; BOSC works even in the // short form. The displacement field in this instruction is always the set of @@ -806,8 +819,10 @@ t_stat sim_instr (void) if (TAG) WriteW(TAG, eaddr); - else + else { + archive_backtrace("LDX"); /* save info in back-trace buffer */ IAR = eaddr; /* what happens in short form? can onlyjump to low addresses? */ + } break; case 0x0d: /* --- STX - Store Index --- */ @@ -845,13 +860,15 @@ t_stat sim_instr (void) else { oldval = IAR; /* add displacement to IAR */ newval = IAR + DSPLC; + archive_backtrace("MDX"); IAR = newval & mem_mask; } } - if ((F || TAG) && ((newval == 0) || ((oldval & 0x8000) != (newval & 0x8000)))) + if ((F || TAG) && (((newval & 0xFFFF) == 0) || ((oldval & 0x8000) != (newval & 0x8000)))) { + archive_backtrace("SKP"); INCREMENT_IAR; /* skip if index sign change or zero */ - + } break; case 0x10: /* --- A - Add --- */ @@ -900,9 +917,14 @@ t_stat sim_instr (void) break; case 0x14: /* --- M - Multiply --- */ - dst = ACC * ReadW(eaddr); - ACC = (dst >> 16) & 0xFFFF; - EXT = dst & 0xFFFF; + if ((src = ACC & 0xFFFF) & 0x8000) /* sign extend the values */ + src |= 0xFFFF0000; + if ((src2 = ReadW(eaddr)) & 0x8000) + src2 |= 0xFFFF0000; + + dst = src * src2; + ACC = (dst >> 16) & 0xFFFF; /* split the results */ + EXT = dst & 0xFFFF; break; case 0x15: /* --- D - Divide --- */ @@ -969,19 +991,29 @@ t_stat sim_instr (void) if (tbit && (ipl < 0)) { /* if INT_RUN mode, set IRQ5 after this instr */ GUI_BEGIN_CRITICAL_SECTION - SETBIT(con_dsw, CON_DSW_INT_RUN); + SETBIT(cpu_dsw, CPU_DSW_INT_RUN); SETBIT(ILSW[5], ILSW_5_INT_RUN); int_req |= INT_REQ_5; GUI_END_CRITICAL_SECTION } } /* end main loop */ - running = FALSE; +#ifdef GUI_SUPPORT + gui_run(FALSE); +#endif + + running = FALSE; + int_lamps = 0; /* display only currently active interrupts while halted */ if (reason == STOP_WAIT || reason == STOP_INVALID_INSTR) { wait_state = 0; // on resume, don't wait + wait_lamp = TRUE; // but keep the lamp lit on the GUI } +#ifdef CGI_SUPPORT + if (cgi) + cgi_stop(reason); +#endif return reason; } @@ -1019,7 +1051,7 @@ static t_bool bsctest (int32 DSPLC, t_bool reset_V) return TRUE; if (DSPLC & 0x20) /* Zero */ - if (ACC == 0) + if ((ACC & 0xFFFF) == 0) return TRUE; return FALSE; @@ -1053,6 +1085,13 @@ static void exit_irq (void) calc_ints(); /* recompute pending interrupt mask */ } /* because we probably cleared some ILSW bits before this instruction */ +/* let a device halt the simulation */ + +void break_simulation (t_stat stopreason) +{ + reason = stopreason; +} + /* ------------------------------------------------------------------------ * SIMH required routines * ------------------------------------------------------------------------ */ @@ -1064,16 +1103,25 @@ static void exit_irq (void) t_stat cpu_reset (DEVICE *dptr) { wait_state = 0; /* cancel wait */ + wait_lamp = TRUE; /* but keep the wait lamp lit on the GUI */ + + if (cpu_unit.flags & UNIT_ATT) { /* record reset in CPU log */ + fseek(cpu_unit.fileref, 0, SEEK_END); + fprintf(cpu_unit.fileref, "---RESET---" CRLF); + } GUI_BEGIN_CRITICAL_SECTION - int_req = 0; /* reset all interrupts */ + reset_backtrace(); + ipl = -1; int_mask = 0xFFFF; + int_req = 0; /* hmmm, it SHOULD reset the int req, right? */ + int_lamps = 0; iplpending = 0; memset(ILSW, 0, sizeof(ILSW)); - con_dsw = 0; /* clear int req and prot stop bits */ + cpu_dsw = 0; /* clear int req and prot stop bits */ tbit = 0; /* cancel INT_RUN mode */ C = V = 0; /* clear processor flags */ @@ -1087,18 +1135,6 @@ t_stat cpu_reset (DEVICE *dptr) return cpu_svc(&cpu_unit); /* reset breakpoint */ } -// reset for the "console" display device - -t_stat console_reset (DEVICE *dptr) -{ - if (display_console) - init_console_window(); - else - destroy_console_window(); - - return SCPE_OK; -} - /* ------------------------------------------------------------------------ * Memory examine * ------------------------------------------------------------------------ */ @@ -1187,15 +1223,15 @@ void xio_1131_switches (int32 addr, int32 func, int32 modify) break; case XIO_SENSE_DEV: - ACC = con_dsw; + ACC = cpu_dsw; if (modify & 0x01) { /* reset interrupts */ - CLRBIT(con_dsw, CON_DSW_PROGRAM_STOP|CON_DSW_INT_RUN); + CLRBIT(cpu_dsw, CPU_DSW_PROGRAM_STOP|CPU_DSW_INT_RUN); CLRBIT(ILSW[5], ILSW_5_INT_RUN); /* (these bits are set in the keyboard handler in 1130_stddev.c) */ } break; default: - sprintf(msg, "Invalid console switch XIO function %x", func); + sprintf(msg, "Invalid console switch function %x", func); xio_error(msg); } } @@ -1206,1119 +1242,633 @@ void xio_1131_switches (int32 addr, int32 func, int32 modify) void xio_error (char *msg) { - fprintf(stderr, "*** XIO error: %s\n", msg); + printf("*** XIO error at %04x: %s\n", prev_IAR, msg); + if (cgi) + break_simulation(STOP_CRASH); } /* ------------------------------------------------------------------------ - * LOG device - if attached to a file, records a CPU trace + * register_cmd - add a command to the extensible command table * ------------------------------------------------------------------------ */ -static t_stat log_reset (DEVICE *dptr); -static t_stat log_attach (UNIT *uptr, char *cptr); +t_stat register_cmd (char *name, t_stat (*action)(), int arg, char *help) +{ + int i; -UNIT log_unit = { UDATA (NULL, UNIT_ATTABLE + UNIT_SEQ, 0) }; + for (i = 0; i < MAX_EXTRA_COMMANDS; i++) { // find end of command table + if (x_cmds[i].action == action) + return SCPE_OK; // command is already there, just return + if (x_cmds[i].name == NULL) + break; + } -DEVICE log_dev = { - "LOG", &log_unit, NULL, NULL, - 1, 16, 16, 1, 16, 16, - NULL, NULL, log_reset, - NULL, log_attach, NULL }; + if (i >= (MAX_EXTRA_COMMANDS-1)) { // no more room (we need room for the NULL) + fprintf(stderr, "The command table is full - rebuild the simulator with more free slots\n"); + return SCPE_ARG; + } + + x_cmds[i].action = action; // add new command + x_cmds[i].name = name; + x_cmds[i].arg = arg; + x_cmds[i].help = help; + + i++; + x_cmds[i].action = NULL; // move the NULL terminator + x_cmds[i].name = NULL; + + return SCPE_OK; +} + +/* ------------------------------------------------------------------------ + * echo_cmd - just echo the command line + * ------------------------------------------------------------------------ */ + +static t_stat echo_cmd (int flag, char *cptr) +{ + printf("%s\n", cptr); + return SCPE_OK; +} + +/* ------------------------------------------------------------------------ + * sim_init - initialize simulator upon startup of scp, before reset + * ------------------------------------------------------------------------ */ + +void sim_init (void) +{ + sim_gui = ! (sim_switches & SWMASK('G')); /* -g means no GUI */ + + sim_vm_cmd = x_cmds; /* provide list of additional commands */ + +#ifdef GUI_SUPPORT + // set hook routines for GUI command processing + if (sim_gui) { + sim_vm_read = &read_cmdline; + sim_vm_post = &update_gui; + } +#endif + +#ifdef ENABLE_BACKTRACE + // add the BACKTRACE command + register_cmd("BACKTRACE", &backtrace_cmd, 0, "ba{cktrace} {n} list last n branches/skips/interrupts\n"); +#endif + + register_cmd("VIEW", &view_cmd, 0, "v{iew} filename view a text file with notepad\n"); + +#ifdef CGI_SUPPORT + register_cmd("CGI", &cgi_cmd, 0, "cgi run simulator in CGI mode\n"); +#endif + + register_cmd("ECHO", &echo_cmd, 0, "echo args... echo arguments passed to command\n"); +} + +/* ------------------------------------------------------------------------ + * archive_backtrace - record a jump, skip, branch or whatever + * ------------------------------------------------------------------------ */ + +#ifdef ENABLE_BACKTRACE + +#define MAXARCHIVE 16 + +static struct tag_arch { + int iar; + char *inst; +} arch[MAXARCHIVE]; +int narchived = 0, archind = 0; + +static void archive_backtrace (char *inst) +{ + static int prevind; + + if (narchived < MAXARCHIVE) + narchived++; + + if (narchived > 0 && arch[prevind].iar == prev_IAR) + return; + + arch[archind].iar = prev_IAR; + arch[archind].inst = inst; + + prevind = archind; + archind = (archind+1) % MAXARCHIVE; +} + +static void reset_backtrace (void) +{ + narchived = 0; + archind = 0; +} + +void void_backtrace (int afrom, int ato) +{ + int i; + + afrom &= mem_mask; + ato &= mem_mask; + + for (i = 0; i < narchived; i++) + if (arch[i].iar >= afrom && arch[i].iar <= ato) + arch[i].inst = "OVERWRITTEN"; +} + +static void show_backtrace (int nshow) +{ + int n = narchived, i = archind; + + if (n > nshow) n = nshow; + + while (--n >= 0) { + i = (i > 0) ? (i-1) : (MAXARCHIVE-1); + printf("from %04x (%s) ", arch[i].iar, arch[i].inst); + } + + if (narchived) + putchar('\n'); +} + +static t_stat backtrace_cmd (int flag, char *cptr) +{ + int n; + + if ((n = atoi(cptr)) <= 0) + n = 6; + + show_backtrace(n); + return SCPE_OK; +} +#else + +// stub this for the disk routine + +void void_backtrace (int afrom, int ato) +{ +} + +#endif + +// CPU log routines -- attaching a file to the CPU creates a trace of instructions and register values +// +// Syntax is WEIRD: +// +// attach cpu logfile log instructions and registers to file "logfile" +// attach -f cpu cpu.log log instructions, registers and floating point acc +// attach -m cpu mapfile logfile read addresses from "mapfile", log instructions to "logfile" +// attach -f -m cpu mapfile logfile same and log floating point stuff too +// +// mapfile if specified is a list of symbols and addresses of the form: +// symbol hexval +// +// e.g. +// FSIN 082E +// FARC 09D4 +// FMPY 09A4 +// NORM 0976 +// XMDS 095A +// START 021A +// +// These values are easily obtained from a load map created by +// XEQ L +// +// The log output is of the form +// +// IAR ACC EXT (flt) XR1 XR2 XR3 CVI FAC OPERATION +// --------------- ---- ---- -------- ---- ---- ---- --- ------------- ----------------------- +// 002a 002a 1234 5381 0.14222 00b3 0236 3f7e CV 1.04720e+000 4c80 BSC I ,0028 +// 081d PAUSE+000d 1234 5381 0.14222 00b3 0236 3f7e CV 1.04720e+000 7400 MDM L 00f0,0 (0) +// 0820 PAUSE+0010 1234 5381 0.14222 00b3 0236 3f7e CV 1.04720e+000 7201 MDX 2 0001 +// 0821 PAUSE+0011 1234 5381 0.14222 00b3 0237 3f7e CV 1.04720e+000 6a03 STX 2 0003 +// 0822 PAUSE+0012 1234 5381 0.14222 00b3 0237 3f7e CV 1.04720e+000 6600 LDX L2 0231 +// 0824 PAUSE+0014 1234 5381 0.14222 00b3 0231 3f7e CV 1.04720e+000 4c00 BSC L ,0237 +// 0237 START+001d 1234 5381 0.14222 00b3 0231 3f7e CV 1.04720e+000 4480 BSI I ,3fff +// 082f FSIN +0001 1234 5381 0.14222 00b3 0231 3f7e CV 1.04720e+000 4356 BSI 3 0056 +// 3fd5 ILS01+35dd 1234 5381 0.14222 00b3 0231 3f7e CV 1.04720e+000 4c00 BSC L ,08de +// +// IAR - instruction address register value, optionally including symbol and offset +// ACC - accumulator +// EXT - extension +// flt - ACC+EXT interpreted as the mantissa of a floating pt number (value 0.5 -> 1) +// XR* - index registers +// CVI - carry, overflow and interrupt indicators +// FAC - floating point accumulator (exponent at 125+XR3, mantissa at 126+XR3 and 127+XR3) +// OP - opcode value and crude disassembly +// +// flt and FAC are displayed only when the -f flag is specified in the attach command +// The label and offset and displayed only when the -m flag is specified in the attach command +// +// The register values shown are the values BEFORE the instruction is executed. +// t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw); -#ifdef WIN32 -# define CRLF "\r\n" -#else -# define CRLF "\n" -#endif +typedef struct tag_symentry { + struct tag_symentry *next; + int addr; + char sym[6]; +} SYMENTRY, *PSYMENTRY; -static t_bool new_log; +static PSYMENTRY syms = NULL; +static t_bool new_log, log_fac; -static t_stat log_attach (UNIT *uptr, char *cptr) +static t_stat cpu_attach (UNIT *uptr, char *cptr) { + char mapfile[200], buf[200], sym[100]; + int addr; + PSYMENTRY n, prv, s; + FILE *fd; + unlink(cptr); // delete old log file, if present new_log = TRUE; + log_fac = sim_switches & SWMASK ('F'); // display the FAC and the ACC/EXT as fixed point. + + for (s = syms; s != NULL; s = n) { // free any old map entries + n = s->next; + free(s); + } + syms = NULL; + + if (sim_switches & SWMASK('M')) { // use a map file to display relative addresses + cptr = get_glyph(cptr, mapfile, 0); + if (! *mapfile) { + printf("/m must be followed by a filename\n"); + return SCPE_ARG; + } + if ((fd = fopen(mapfile, "r")) == NULL) { + perror(mapfile); + return SCPE_OPENERR; + } + + while (fgets(buf, sizeof(buf), fd) != NULL) { // read symbols & addresses, link in descending address order + if (sscanf(buf, "%s %x", sym, &addr) != 2) + continue; + if (*buf == ';') + continue; + + for (prv = NULL, s = syms; s != NULL; prv = s, s = s->next) { + if (s->addr < addr) + break; + } + + if ((n = malloc(sizeof(SYMENTRY))) == NULL) { + printf("out of memory reading map!\n"); + break; + } + + sym[5] = '\0'; + strcpy(n->sym, sym); + upcase(n->sym); + n->addr = addr; + + if (prv == NULL) { + n->next = syms; + syms = n; + } + else { + n->next = prv->next; + prv ->next = n; + } + } + fclose(fd); + } + return attach_unit(uptr, cptr); } static void trace_instruction (void) { t_value v[2]; + float fac; + short exp; + int addr; + PSYMENTRY s; + long mant, sign; + char facstr[20], fltstr[20]; - if ((log_unit.flags & UNIT_ATT) == 0) + if ((cpu_unit.flags & UNIT_ATT) == 0) return; if (new_log) { - fseek(log_unit.fileref, 0, SEEK_END); - fprintf(log_unit.fileref, " IAR ACC EXT XR1 XR2 XR3 CVI OPERATION" CRLF); - fprintf(log_unit.fileref, "---- ---- ---- ---- ---- ---- --- ---------" CRLF); + fseek(cpu_unit.fileref, 0, SEEK_END); new_log = FALSE; + + fprintf(cpu_unit.fileref, " IAR%s ACC EXT %s XR1 XR2 XR3 CVI %sOPERATION" CRLF, + syms ? " " : "", log_fac ? " (flt) " : "", log_fac ? " FAC " : ""); + fprintf(cpu_unit.fileref, "----%s ---- ---- %s---- ---- ---- --- %s-----------------------" CRLF, + syms ? "-----------" : "", log_fac ? "-------- " : "", log_fac ? "------------- " : ""); } - fprintf(log_unit.fileref, "%04x %04x %04x %04x %04x %04x %c%c%c ", - IAR & 0xFFFF, ACC & 0xFFFF, EXT & 0xFFFF, M[1] & 0xFFFF, M[2] & 0xFFFF, M[3] & 0xFFFF, - C ? 'C' : ' ', V ? 'V' : ' ', - (ipl < 0) ? ' ' : (ipl+'0')); + if (! log_fac) + facstr[0] = fltstr[0] = '\0'; + else { + mant = ((ACC & 0xFFFF) << 16) | (EXT & 0xFFFF); + if (mant == 0x80000000) { + sign = TRUE; + fac = 1.f; + } + else { + if ((sign = mant & 0x80000000)) + mant = -mant; + fac = (float) mant * ((float) 1./ (float) (unsigned long) 0x80000000); + } + sprintf(fltstr, "%c%.5f ", sign ? '-' : ' ', fac); + + if (BETWEEN(M[3], 0x300, MEMSIZE-128)) { + exp = (M[M[3]+125] & 0xFF) - 128; + mant = (M[M[3]+126] << 8) | ((M[M[3]+127] >> 8) & 0xFF); + if ((sign = (mant & 0x00800000))) + mant = (-mant) & 0x00FFFFFF; + + fac = (float) mant * ((float) 1. / (float) 0x00800000); + + if (exp > 30) { + fac *= (float) (1 << 30); + exp -= 30; + while (exp > 0) + fac *= 2; + } + else if (exp > 0) + fac *= (float) (1 << exp); + else if (exp < -30) { + fac /= (float) (1 << 30); + exp += 30; + while (exp < 0) + fac /= 2; + } + else if (exp < 0) + fac /= (float) (1 << -exp); + + sprintf(facstr, "%c%.5e ", sign ? '-' : ' ', fac); + } + else + strcpy(facstr, " "); + } + + addr = IAR & 0xFFFF; + fprintf(cpu_unit.fileref, "%04x ", addr); + + if (syms) { + for (s = syms; s != NULL; s = s->next) + if (s->addr <= addr) + break; + + if (s == NULL) + fprintf(cpu_unit.fileref, " %04x ", addr); + else + fprintf(cpu_unit.fileref, "%-5s+%04x ", s->sym, addr - s->addr); + } + + fprintf(cpu_unit.fileref, "%04x %04x %s%04x %04x %04x %c%c%c %s", + ACC & 0xFFFF, EXT & 0xFFFF, fltstr, M[1] & 0xFFFF, M[2] & 0xFFFF, M[3] & 0xFFFF, + C ? 'C' : ' ', V ? 'V' : ' ', (ipl < 0) ? ' ' : (ipl+'0'), facstr); v[0] = M[ IAR & mem_mask]; v[1] = M[(IAR+1) & mem_mask]; - fprint_sym(log_unit.fileref, IAR & mem_mask, v, NULL, SWMASK('M')); + fprint_sym(cpu_unit.fileref, IAR & mem_mask, v, NULL, SWMASK('M')); /* disassemble instruction */ - fputs(CRLF, log_unit.fileref); + fputs(CRLF, cpu_unit.fileref); } void trace_io (char *fmt, ...) { va_list args; - if ((log_unit.flags & UNIT_ATT) == 0) + if ((cpu_unit.flags & UNIT_ATT) == 0) return; va_start(args, fmt); // get pointer to argument list - vfprintf(log_unit.fileref, fmt, args); // write errors to terminal (stderr) + vfprintf(cpu_unit.fileref, fmt, args); // write errors to terminal (stderr) va_end(args); - fputs(CRLF, log_unit.fileref); + fputs(CRLF, cpu_unit.fileref); } -static t_stat log_reset (DEVICE *dptr) -{ - if ((log_unit.flags & UNIT_ATT) == 0) - return SCPE_OK; +/* debugging */ - fseek(log_unit.fileref, 0, SEEK_END); - fprintf(log_unit.fileref, "---RESET---" CRLF); +void debug_print (char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + vprintf(fmt, args); + if (cpu_unit.flags & UNIT_ATT) + vfprintf(cpu_unit.fileref, fmt, args); + va_end(args); + + if (strchr(fmt, '\n') == NULL) { // be sure to emit a newline + putchar('\n'); + if (cpu_unit.flags & UNIT_ATT) + putc('\n', cpu_unit.fileref); + } +} + +#ifdef WIN32 +#include +#endif + +// view_cmd - let user view and/or edit a file (e.g. a printer output file, script, or source deck) + +static t_stat view_cmd (int flag, char *cptr) +{ +#ifdef WIN32 + char cmdline[256]; + + sprintf(cmdline, "notepad %s", cptr); + WinExec(cmdline, SW_SHOWNORMAL); +#endif return SCPE_OK; } -/* ------------------------------------------------------------------------ - * Console display - on Windows builds (only) this code displays the 1130 console - * and toggle switches. It really enhances the experience. - * - * Currently, when the IPS throttle is nonzero, I update the display after every - * UPDATE_INTERVAL instructions, plus or minus a random amount to avoid aliased - * sampling in loops. When UPDATE_INTERVAL is defined as zero, we update every - * instruction no matter what the throttle. This makes the simulator too slow - * but it's cool and helpful during development. - * ------------------------------------------------------------------------ */ +#ifdef CGI_SUPPORT -#ifndef GUI_SUPPORT +int cgi_maxsec = 0; // default run time limit -void update_gui (int force) {} /* stubs for non-GUI builds */ -void forms_check (int set) {} -void print_check (int set) {} -void keyboard_select (int select) {} -void keyboard_selected (int select) {} -void disk_ready (int ready) {} -void disk_unlocked (int unlocked) {} -static void init_console_window (void) {} -static void destroy_console_window (void) {} -static void sleep_msec (int msec) {} +// cgi_cmd - enable cgi mode. Specify time limit on command line if desired + +static t_stat cgi_cmd (int flag, char *cptr) +{ + cgi = TRUE; // set CGI flag + + while (*cptr && *cptr <= ' ') + cptr++; + + if (*cptr) + cgi_maxsec = atoi(cptr); // set time limit, if specified + + return SCPE_OK; +} + +// cgi_timeout - called when timer runs out + +static void cgi_timeout (int dummy) +{ + break_simulation(STOP_TIMED_OUT); // stop the simulator +} + +// cgi_clockfail - report failure to set alarm + +static void cgi_clockfail (void) +{ + printf("Set CGI time limit failed!"); +} + +// cgi_start_timer - OS dependent routine to set things up so that +// cgi_timeout() will be called after cgi_maxsec seconds. + +#if defined(WIN32) + static DWORD WINAPI cgi_timer_thread (LPVOID arg) + { + Sleep(cgi_maxsec*1000); // timer thread -- wait, then call timeout routine + cgi_timeout(0); + return 0; + } + + static void cgi_start_timer (void) + { + DWORD dwThreadID; + + if (CreateThread(NULL, 0, cgi_timer_thread, NULL, 0, &dwThreadID) == NULL) + cgi_clockfail(); + } #else + #include -#ifdef WIN32 + #if defined(SIGVTALRM) && defined(ITMER_VIRTUAL) -// only have a WIN32 gui right now + // setitimer counts actual runtime CPU seconds, so is insensitive to + // system load and is a better timer to use. Be sure to check, though, + // that it actually works on your OS. Note that time spent performing + // I/O does not count -- this counts user mode CPU time only, so + // the elapsed time it allows could be much larger, especially if + // the job is spewing output. -#include -#include -#include "ibm1130res.h" + #include -static BOOL class_defined = FALSE; -static HWND hConsoleWnd = NULL; -static HBITMAP hBitmap = NULL; -static HFONT hFont = NULL; -static HFONT hBtnFont = NULL; -static HBRUSH hbLampOut = NULL; -static HBRUSH hbWhite = NULL; -static HBRUSH hbBlack = NULL; -static HBRUSH hbGray = NULL; -static HPEN hSwitchPen = NULL; -static HPEN hWhitePen = NULL; -static HPEN hBlackPen = NULL; -static HPEN hLtGreyPen = NULL; -static HPEN hGreyPen = NULL; -static HPEN hDkGreyPen = NULL; + static void cgi_start_timer (void) + { + struct itimerval rtime, otime; -static HCURSOR hcArrow = NULL; -static HCURSOR hcHand = NULL; -static HINSTANCE hInstance; -static HDC hCDC = NULL; -static char szConsoleClassName[] = "1130CONSOLE"; -static DWORD PumpID = 0; -static HANDLE hPump = INVALID_HANDLE_VALUE; -static int bmwid, bmht; + rtime.it_value.tv_sec = cgi_maxsec; + rtime.it_value.tv_usec = 0; + rtime.it_interval.tv_sec = cgi_maxsec; + rtime.it_interval.tv_usec = 0; -#define BUTTON_WIDTH 90 -#define BUTTON_HEIGHT 50 + if (signal(SIGVTALRM, cgi_timeout) == SIG_ERR) // set alarm handler + cgi_clockfail(); + else if (setitimer(ITIMER_VIRTUAL, &rtime, &otime)) // start timer + cgi_clockfail(); + } -#define IDC_KEYBOARD_SELECT 0 -#define IDC_DISK_UNLOCK 1 -#define IDC_RUN 2 -#define IDC_PARITY_CHECK 3 -#define IDC_UNUSED 4 -#define IDC_FILE_READY 5 -#define IDC_FORMS_CHECK 6 -#define IDC_POWER_ON 7 -#define IDC_POWER 8 -#define IDC_PROGRAM_START 9 -#define IDC_PROGRAM_STOP 10 -#define IDC_LOAD_IAR 11 -#define IDC_KEYBOARD 12 -#define IDC_IMM_STOP 13 -#define IDC_RESET 14 -#define IDC_PROGRAM_LOAD 15 + #elif defined(SIGALRM) + #include -#define LAMPTIME 500 // 500 msec delay on updating -#define UPDATE_TIMER_ID 1 + // if it's all we have, standard POSIX alarm will do the trick too -static struct tag_btn { - int x, y; - char *txt; - BOOL pushable, immed_off; - DWORD offtime; - COLORREF clr; - HBRUSH hbrLit, hbrDark; - HWND hBtn; -} btn[] = { - 0, 0, "KEYBOARD\nSELECT", FALSE, TRUE, 0, RGB(255,255,180), NULL, NULL, NULL, - 0, 1, "DISK\nUNLOCK", FALSE, TRUE, 0, RGB(255,255,180), NULL, NULL, NULL, - 0, 2, "RUN", FALSE, FALSE, 0, RGB(0,255,0), NULL, NULL, NULL, - 0, 3, "PARITY\nCHECK", FALSE, TRUE, 0, RGB(255,0,0), NULL, NULL, NULL, + static void cgi_start_timer (void) + { + if (signal(SIGALRM, cgi_timeout) == SIG_ERR) // set alarm handler + cgi_clockfail(); + else if (alarm(cgi_maxsec)) // start timer + cgi_clockfail(); + } - 1, 0, "", FALSE, TRUE, 0, RGB(255,255,180), NULL, NULL, NULL, - 1, 1, "FILE\nREADY", FALSE, TRUE, 0, RGB(0,255,0), NULL, NULL, NULL, - 1, 2, "FORMS\nCHECK", FALSE, TRUE, 0, RGB(255,255,0), NULL, NULL, NULL, - 1, 3, "POWER\nON", FALSE, TRUE, 0, RGB(255,255,180), NULL, NULL, NULL, + #else + // don't seem to have a clock available. Better say so. - 2, 0, "POWER", TRUE, TRUE, 0, RGB(255,255,180), NULL, NULL, NULL, - 2, 1, "PROGRAM\nSTART", TRUE, TRUE, 0, RGB(0,255,0), NULL, NULL, NULL, - 2, 2, "PROGRAM\nSTOP", TRUE, TRUE, 0, RGB(255,0,0), NULL, NULL, NULL, - 2, 3, "LOAD\nIAR", TRUE, TRUE, 0, RGB(0,0,255), NULL, NULL, NULL, + static void cgi_start_timer (void) + { + printf("CGI time limit is not supported by this build\n"); + } - 3, 0, "KEYBOARD", TRUE, TRUE, 0, RGB(255,255,180), NULL, NULL, NULL, - 3, 1, "IMM\nSTOP", TRUE, TRUE, 0, RGB(255,0,0), NULL, NULL, NULL, - 3, 2, "CHECK\nRESET", TRUE, TRUE, 0, RGB(0,0,255), NULL, NULL, NULL, - 3, 3, "PROGRAM\nLOAD", TRUE, TRUE, 0, RGB(0,0,255), NULL, NULL, NULL, -}; -#define NBUTTONS (sizeof(btn) / sizeof(btn[0])) + #endif +#endif -LRESULT CALLBACK ConsoleWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); -static DWORD WINAPI Pump (LPVOID arg); - -/* ------------------------------------------------------------------------ - * sleep_msec - delay msec to throttle the cpu down - * ------------------------------------------------------------------------ */ - -static void sleep_msec (int msec) +static void cgi_start(void) { - Sleep(msec); + if (cgi_maxsec > 0) // if time limit was specified, set timer now + cgi_start_timer(); + +// printf("Content-type: text/html\n\n\n\n IBM 1130 Simulation Results\n\n\n
");
 }
 
-/* ------------------------------------------------------------------------ 
- * init_console_window - display the 1130 console. Actually just creates a thread 
- * to run the Pump routine which does the actual work.
- * ------------------------------------------------------------------------ */
-
-static void init_console_window (void)
-{
-	static BOOL did_atexit = FALSE;
-
-	if (hConsoleWnd != NULL)
-		return;
-
-	if (PumpID == 0)
-		hPump = CreateThread(NULL, 0, Pump, 0, 0, &PumpID);
-
-	if (! did_atexit) {
-		atexit(destroy_console_window);
-		did_atexit = TRUE;
-	}
-}
-
-/* ------------------------------------------------------------------------ 
- * destroy_console_window - delete GDI objects.
- * ------------------------------------------------------------------------ */
-
-#define NIXOBJECT(hObj) if (hObj != NULL) {DeleteObject(hObj); hObj = NULL;}
-
-static void destroy_console_window (void)
+static void cgi_stop(t_stat reason)
 {
+	typedef enum {O_END, O_FORTRAN, O_MONITOR} ORIGIN;
+	char *errmsg = "";
+	static struct tag_pretstop {
+		int acc;
+		ORIGIN orig;
+		char *msg;
+	} pretstop[] = {
+		0xF000, O_FORTRAN, "No *IOCS was specified but I/O was attempted",
+		0xF001, O_FORTRAN, "Local unit defined incorrectly, or no *IOCS for specified device",
+		0xF002, O_FORTRAN, "Requested record exceeds buffer size",
+		0xF003, O_FORTRAN, "Illegal character encountered in input record",
+		0xF004, O_FORTRAN, "Exponent too large or too small in input",
+		0xF005, O_FORTRAN, "More than one exponent encountered in input",
+		0xF006, O_FORTRAN, "More than one sign encountered in input",
+		0xF007, O_FORTRAN, "More than one decimal point encountered in input",
+		0xF008, O_FORTRAN, "Read of output-only device, or write to input-only device",
+		0xF009, O_FORTRAN, "Real variable transmitted with I format or integer transmitted with E or F",
+		0xF020, O_FORTRAN, "Illegal unit reference",
+		0xF021, O_FORTRAN, "Read list exceeds length of write list",
+		0xF022, O_FORTRAN, "Record does not exist in read list",
+		0xF023, O_FORTRAN, "Maximum length of $$$$$ area on disk has been exceeded",
+		0xF024, O_FORTRAN, "*IOCS (UDISK) was not specified",
+		0xF100, O_FORTRAN, "File not defined by DEFINE FILE statement",
+		0xF101, O_FORTRAN, "File record number too large, zero or negative",
+		0xF103, O_FORTRAN, "*IOCS(DISK) was not specified",
+		0xF105, O_FORTRAN, "Length of a list element exceeds record length in DEFINE FILE",
+		0xF107, O_FORTRAN, "Attempt to read or write an invalid sector address (may occur if a core image program is run with too little room in working storage)",
+		0xF10A, O_FORTRAN, "Define file table and/or core image header corrupted, probably by an out-of-bounds array subscript",
+		0x1000, O_MONITOR, "1442 card read/punch or 1442 punch: not ready or hopper empty. [emulator: attach a file to CR or CP and go]",
+		0x1001, O_MONITOR, "Illegal device, function or word count",
+		0x100F, O_MONITOR, "Occurs in a DUP operation after DUP error D112",
+		0x2000, O_MONITOR, "Keyboard/Console Printer not ready",
+		0x2001, O_MONITOR, "Illegal device, function or word count",
+		0x3000, O_MONITOR, "1134/1055 Paper Tape not ready",
+		0x3001, O_MONITOR, "Illegal device, function or word count, or invalid check digit",
+		0x4000, O_MONITOR, "2501 Card Reader not ready",
+		0x4001, O_MONITOR, "Illegal device, function or word count",
+		0x5000, O_MONITOR, "Disk not ready",
+		0x5001, O_MONITOR, "Illegal device, function or word count, or attempt to write in protected area",
+		0x5002, O_MONITOR, "Write select or power unsafe",
+		0x5003, O_MONITOR, "Read/write/seek failure after 16 attempts or disk overflow. Extension may display logical drive number in bits 0..3 and working storage address in bits 4..15. Program Start retries 16 more times.",
+		0x5004, O_MONITOR, "Same as above from routine DISK1 and DISKN, or, an uninitialized cartridge is online during a cold start.",
+		0x6000, O_MONITOR, "1132 Printer not ready or out of paper",
+		0x6001, O_MONITOR, "Illegal device, function or word count",
+		0x7000, O_MONITOR, "1627 Plotter not ready",
+		0x7001, O_MONITOR, "Illegal device, function or word count",
+		0x8001, O_MONITOR, "SCA error: Illegal function or word count",
+		0x8002, O_MONITOR, "SCA error: if STR mode, receive or transmit operation not completed;\n"
+						   "if BSC mode, invalid start characters in the I/O area for a transmit operation",
+		0x8003, O_MONITOR, "SCA error: if STR mode, failed to synchronize before attempt to read or write, or, attempted to receive before receiving INQ sequence;\n"
+						   "if BSC mode, invalid number of identification characters for an identification specification operation",
+		0x9000, O_MONITOR, "1403 printer no ready or out of paper",
+		0x9001, O_MONITOR, "Illegal device, function or word count",
+		0x9002, O_MONITOR, "Parity check, scan check or ring check",
+		0xA000, O_MONITOR, "1231 Optical Mark Reader not ready",
+		0xA001, O_MONITOR, "Illegal device, function or word count",
+		0xA002, O_MONITOR, "Feed check, last document was processed. Clear jam, do not refeed",
+		0xA003, O_MONITOR, "Feed check, last document not  processed. Clear jam and refeed",
+		0,      O_END, 	   NULL
+	};
 	int i;
 
-	if (hConsoleWnd != NULL)
-		SendMessage(hConsoleWnd, WM_CLOSE, 0, 0);	// cross thread call is OK
+	detach_cmd(0, "prt");		/* flush last print line */
 
-	if (hPump != INVALID_HANDLE_VALUE) {			// this is not the most graceful way to do it
-		TerminateThread(hPump, 0);
-		hPump  = INVALID_HANDLE_VALUE;
-		PumpID = 0;
-		hConsoleWnd = NULL;
-	}
-	if (hCDC != NULL) {
-		DeleteDC(hCDC);
-		hCDC = NULL;
-	}
-
-	NIXOBJECT(hBitmap)
-	NIXOBJECT(hbLampOut)
-	NIXOBJECT(hFont)
-	NIXOBJECT(hBtnFont);
-	NIXOBJECT(hcHand)
-	NIXOBJECT(hSwitchPen)
-	NIXOBJECT(hLtGreyPen)
-	NIXOBJECT(hGreyPen)
-	NIXOBJECT(hDkGreyPen)
-
-	for (i = 0; i < NBUTTONS; i++) {
-		NIXOBJECT(btn[i].hbrLit);
-		NIXOBJECT(btn[i].hbrDark);
-	}
-
-//	if (class_defined) {
-//		UnregisterClass(hInstance, szConsoleClassName);
-//		class_defined = FALSE;
-//	}
-}
-
-/* ------------------------------------------------------------------------ 
- * these variables hold the displayed versions of the system registers 
- * ------------------------------------------------------------------------ */
-
-static int shown_iar = 0, shown_sar = 0, shown_sbr = 0, shown_afr = 0, shown_acc = 0, shown_ext  = 0;
-static int shown_op  = 0, shown_tag = 0, shown_irq = 0, shown_ccc = 0, shown_cnd = 0, shown_wait = 0;
-static int shown_ces = 0, shown_runmode = MODE_RUN;
-static int CND;
-
-/* ------------------------------------------------------------------------ 
- * RedrawRegion - mark a region for redrawing without background erase
- * ------------------------------------------------------------------------ */
-
-static void RedrawRegion (HWND hWnd, int left, int top, int right, int bottom)
-{
-	RECT r;
-
-	r.left   = left;
-	r.top    = top;
-	r.right  = right;
-	r.bottom = bottom;
-
-	InvalidateRect(hWnd, &r, FALSE);
-}
-
-/* ------------------------------------------------------------------------ 
- * RepaintRegion - mark a region for redrawing with background erase
- * ------------------------------------------------------------------------ */
-
-static void RepaintRegion (HWND hWnd, int left, int top, int right, int bottom)
-{
-	RECT r;
-
-	r.left   = left;
-	r.top    = top;
-	r.right  = right;
-	r.bottom = bottom;
-
-	InvalidateRect(hWnd, &r, TRUE);
-}
-
-/* ------------------------------------------------------------------------ 
- * update_gui - sees if anything on the console display has changed, and invalidates 
- * the changed regions. Then it calls UpdateWindow to force an immediate repaint. This
- * function (update_gui) should probably not be called every time through the main
- * instruction loop but it should be called at least whenever wait_state or int_req change, and then
- * every so many instructions.  It's also called after every simh command so manual changes are
- * reflected instantly.
- * ------------------------------------------------------------------------ */
-
-void update_gui (BOOL force)
-{	
-	int i, sts;
-
-	if (hConsoleWnd == NULL)
-		return;
-
-	CND = 0;	/* combine carry and V as two bits */
-	if (C)
-		CND |= 2;
-	if (V)
-		CND |= 1;
-
-	if (RUNMODE == MODE_LOAD)
-		SBR = CES;			/* in load mode, SBR follows the console switches */
-
-	if (IAR != shown_iar)
-			{shown_iar = IAR; 		 RedrawRegion(hConsoleWnd, 75,    8, 364,  32);}	/* lamps: don't bother erasing bkgnd */
-	if (SAR != shown_sar)
-			{shown_sar = SAR; 		 RedrawRegion(hConsoleWnd, 75,   42, 364,  65);}
-	if (ACC != shown_acc)
-			{shown_acc = ACC; 		 RedrawRegion(hConsoleWnd, 75,  141, 364, 164);}
-	if (EXT != shown_ext)
-			{shown_ext = EXT; 		 RedrawRegion(hConsoleWnd, 75,  174, 364, 197);}
-	if (SBR != shown_sbr)
-			{shown_sbr = SBR; 		 RedrawRegion(hConsoleWnd, 75,   77, 364,  97);}
-	if (OP  != shown_op)		  			 
-			{shown_op  = OP;  		 RedrawRegion(hConsoleWnd, 501,   8, 595,  32);}
-	if (TAG != shown_tag)
-			{shown_tag = TAG; 		 RedrawRegion(hConsoleWnd, 501,  77, 595,  97);}
-	if (int_req != shown_irq)
-			{shown_irq = int_req;    RedrawRegion(hConsoleWnd, 501, 108, 595, 130);}
-	if (CCC != shown_ccc)
-			{shown_ccc = CCC;		 RedrawRegion(hConsoleWnd, 501, 141, 595, 164);}
-	if (CND != shown_cnd)
-			{shown_cnd = CND;        RedrawRegion(hConsoleWnd, 501, 174, 595, 197);}
-	if (wait_state != shown_wait)
-			{shown_wait= wait_state; RedrawRegion(hConsoleWnd, 380,  77, 414,  97);}
-	if (CES != shown_ces)
-			{shown_ces = CES; 		 RepaintRegion(hConsoleWnd, 115, 230, 478, 275);}	/* console entry sw: do erase bkgnd */
-	if (RUNMODE != shown_runmode)
-			{shown_runmode = RUNMODE;RepaintRegion(hConsoleWnd, 270, 359, 330, 418);}
-
-	for (i = 0; i < NBUTTONS; i++) {
-		if (btn[i].pushable)
-			continue;
-
-		switch (i) {
-			case IDC_RUN:				sts = running && ! wait_state;		break;
-//			case IDC_PARITY_CHECK:		sts = FALSE;		break;
-//			case IDC_POWER_ON:			sts = TRUE;			break;
-			default:
-				continue;
-
-//			case IDC_FILE_READY:		these windows are enabled&disabled directly
-//			case IDC_FORMS_CHECK:
-//			case IDC_KEYBOARD_SELECT:
-//			case IDC_DISK_UNLOCK:
-		}
-
-		if (sts != IsWindowEnabled(btn[i].hBtn)) {		// status has changed
-			if (sts || force || btn[i].immed_off) {		// if lamp should be on or must be set now
-				EnableWindow(btn[i].hBtn, sts);			// set it and reset cumulative off-time
-				btn[i].offtime = 0;
-			}
-			else if (btn[i].offtime == 0) {				// it just went out, note the time
-				btn[i].offtime = GetTickCount();
-			}
-			else if ((GetTickCount()-btn[i].offtime) >= LAMPTIME) {
-				EnableWindow(btn[i].hBtn, FALSE);		// it's been long enough -- switch the lamp off
+	if (reason == STOP_TIMED_OUT)
+		printf("\n
Sorry, emulation run time exceeded %d second%s\n", cgi_maxsec, (cgi_maxsec == 1) ? "" : "s"); + else if (IAR != 0x2a || ACC != 0x1000) { + ACC &= 0xFFFF; + for (i = 0; pretstop[i].orig != O_END; i++) { + if (pretstop[i].acc == ACC) { + errmsg = pretstop[i].msg; + break; } } + printf("\n
Abnormal exit: %s\nIAR = %04x, ACC = %04x\n", errmsg, IAR, ACC); } -/* UpdateWindow(hConsoleWnd); */ +// printf("
\n\n\n"); + exit(0); /* save w/o writing disk image */ } -WNDPROC oldButtonProc = NULL; - -/* ------------------------------------------------------------------------ - * ------------------------------------------------------------------------ */ - -LRESULT CALLBACK ButtonProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - int i; - - i = GetWindowLong(hWnd, GWL_ID); - - if (! btn[i].pushable) { - if (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP || uMsg == WM_LBUTTONDBLCLK) - return 0; - if (uMsg == WM_CHAR) - if ((TCHAR) wParam == ' ') - return 0; - } - - return CallWindowProc(oldButtonProc, hWnd, uMsg, wParam, lParam); -} - -static int occurs (char *txt, char ch) -{ - int count = 0; - - while (*txt) - if (*txt++ == ch) - count++; - - return count; -} - -// turns out to get properly colored buttons you have to paint them yourself. Sheesh. -// On the plus side, this lets do a better job of aligning the button text than -// the button would by itself. - -void PaintButton (LPDRAWITEMSTRUCT dis) -{ - int i = dis->CtlID, nc, nlines, x, y, dy; - BOOL down = dis->itemState & ODS_SELECTED; - HPEN hOldPen; - HFONT hOldFont; - UINT oldAlign; - COLORREF oldBk; - char *txt, *tstart; - - if (! BETWEEN(i, 0, NBUTTONS-1)) - return; - - FillRect(dis->hDC, &dis->rcItem, ((btn[i].pushable || power) && IsWindowEnabled(btn[i].hBtn)) ? btn[i].hbrLit : btn[i].hbrDark); - - if (! btn[i].pushable) { - hOldPen = SelectObject(dis->hDC, hBlackPen); - MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.top, NULL); - LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top); - LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.bottom-1); - LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-1); - LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.top); - } - else if (down) { - // do the three-D thing - hOldPen = SelectObject(dis->hDC, hDkGreyPen); - MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-2, NULL); - LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.top); - LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top); - - SelectObject(dis->hDC, hWhitePen); - MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-1, NULL); - LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.bottom-1); - LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top); - - SelectObject(dis->hDC, hGreyPen); - MoveToEx(dis->hDC, dis->rcItem.left+1, dis->rcItem.bottom-3, NULL); - LineTo(dis->hDC, dis->rcItem.left+1, dis->rcItem.top+1); - LineTo(dis->hDC, dis->rcItem.right-3, dis->rcItem.top+1); - } - else { - hOldPen = SelectObject(dis->hDC, hWhitePen); - MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-2, NULL); - LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.top); - LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top); - - SelectObject(dis->hDC, hDkGreyPen); - MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-1, NULL); - LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.bottom-1); - LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top); - - SelectObject(dis->hDC, hGreyPen); - MoveToEx(dis->hDC, dis->rcItem.left+1, dis->rcItem.bottom-2, NULL); - LineTo(dis->hDC, dis->rcItem.right-2, dis->rcItem.bottom-2); - LineTo(dis->hDC, dis->rcItem.right-2, dis->rcItem.top+1); - } - - SelectObject(dis->hDC, hOldPen); - - hOldFont = SelectObject(dis->hDC, hBtnFont); - oldAlign = SetTextAlign(dis->hDC, TA_CENTER|TA_TOP); - oldBk = SetBkMode(dis->hDC, TRANSPARENT); - - txt = btn[i].txt; - nlines = occurs(txt, '\n')+1; - x = (dis->rcItem.left + dis->rcItem.right) / 2; - y = (dis->rcItem.top + dis->rcItem.bottom) / 2; - - dy = 14; - y = y - (nlines*dy)/2; - - if (down) { - x += 1; - y += 1; - } - - for (;;) { - for (nc = 0, tstart = txt; *txt && *txt != '\n'; txt++, nc++) - ; - - TextOut(dis->hDC, x, y, tstart, nc); - - if (*txt == '\0') - break; - - txt++; - y += dy; - } - - SetTextAlign(dis->hDC, oldAlign); - SetBkMode(dis->hDC, oldBk); - SelectObject(dis->hDC, hOldFont); -} - -/* ------------------------------------------------------------------------ - * ------------------------------------------------------------------------ */ - -HWND CreateSubclassedButton (HWND hwParent, int i) -{ - HWND hBtn; - int x, y; - int r, g, b; - - y = bmht - (4*BUTTON_HEIGHT) + BUTTON_HEIGHT * btn[i].y; - x = (btn[i].x < 2) ? (btn[i].x*BUTTON_WIDTH) : (bmwid - (4-btn[i].x)*BUTTON_WIDTH); - - if ((hBtn = CreateWindow("BUTTON", btn[i].txt, WS_CHILD|WS_VISIBLE|BS_CENTER|BS_MULTILINE|BS_OWNERDRAW, - x, y, BUTTON_WIDTH, BUTTON_HEIGHT, hwParent, (HMENU) i, hInstance, NULL)) == NULL) - return NULL; - - btn[i].hBtn = hBtn; - - if (oldButtonProc == NULL) - oldButtonProc = (WNDPROC) GetWindowLong(hBtn, GWL_WNDPROC); - - btn[i].hbrLit = CreateSolidBrush(btn[i].clr); - - if (! btn[i].pushable) { - r = GetRValue(btn[i].clr) / 4; - g = GetGValue(btn[i].clr) / 4; - b = GetBValue(btn[i].clr) / 4; - - btn[i].hbrDark = CreateSolidBrush(RGB(r,g,b)); - EnableWindow(hBtn, FALSE); - } - - SetWindowLong(hBtn, GWL_WNDPROC, (LONG) ButtonProc); - return hBtn; -} - -/* ------------------------------------------------------------------------ - * Pump - thread that takes care of the console window. It has to be a separate thread so that it gets - * execution time even when the simulator is compute-bound or IO-blocked. This routine creates the window - * and runs a standard Windows message pump. The window function does the actual display work. - * ------------------------------------------------------------------------ */ - -static DWORD WINAPI Pump (LPVOID arg) -{ - MSG msg; - int wx, wy, i; - RECT r, ra; - BITMAP bm; - WNDCLASS cd; - HDC hDC; - HWND hActWnd; - - hActWnd = GetForegroundWindow(); - - if (! class_defined) { /* register Window class */ - hInstance = GetModuleHandle(NULL); - - memset(&cd, 0, sizeof(cd)); - cd.style = CS_NOCLOSE; - cd.lpfnWndProc = ConsoleWndProc; - cd.cbClsExtra = 0; - cd.cbWndExtra = 0; - cd.hInstance = hInstance; - cd.hIcon = NULL; - cd.hCursor = hcArrow; - cd.hbrBackground = NULL; - cd.lpszMenuName = NULL; - cd.lpszClassName = szConsoleClassName; - - if (! RegisterClass(&cd)) { - PumpID = 0; - return 0; - } - - class_defined = TRUE; - } - - hbWhite = GetStockObject(WHITE_BRUSH); /* create or fetch useful GDI objects */ - hbBlack = GetStockObject(BLACK_BRUSH); /* create or fetch useful GDI objects */ - hbGray = GetStockObject(GRAY_BRUSH); - hSwitchPen = CreatePen(PS_SOLID, 5, RGB(255,255,255)); - - hWhitePen = GetStockObject(WHITE_PEN); - hBlackPen = GetStockObject(BLACK_PEN); - hLtGreyPen = CreatePen(PS_SOLID, 1, RGB(190,190,190)); - hGreyPen = CreatePen(PS_SOLID, 1, RGB(128,128,128)); - hDkGreyPen = CreatePen(PS_SOLID, 1, RGB(64,64,64)); - - hcArrow = LoadCursor(NULL, IDC_ARROW); - hcHand = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_HAND)); - - if (hBitmap == NULL) - hBitmap = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_CONSOLE)); - if (hbLampOut == NULL) - hbLampOut = CreateSolidBrush(RGB(50,50,50)); - if (hFont == NULL) - hFont = CreateFont(-10, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, FIXED_PITCH, FF_SWISS, "Arial"); - if (hBtnFont == NULL) - hBtnFont = CreateFont(-12, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, FIXED_PITCH, FF_SWISS, "Arial"); - - if (hConsoleWnd == NULL) { /* create window */ - if ((hConsoleWnd = CreateWindow(szConsoleClassName, "IBM 1130", WS_OVERLAPPED, 0, 0, 200, 200, NULL, NULL, hInstance, NULL)) == NULL) { - PumpID = 0; - return 0; - } - } - - GetObject(hBitmap, sizeof(bm), &bm); /* get bitmap size */ - bmwid = bm.bmWidth; - bmht = bm.bmHeight; - - for (i = 0; i < NBUTTONS; i++) - CreateSubclassedButton(hConsoleWnd, i); - - EnableWindow(btn[IDC_POWER_ON].hBtn, TRUE); - EnableWindow(btn[IDC_DISK_UNLOCK].hBtn, TRUE); - - GetWindowRect(hConsoleWnd, &r); /* get window size as created */ - wx = r.right - r.left + 1; - wy = r.bottom - r.top + 1; - - if (hCDC == NULL) { /* get a memory DC and select the bitmap into ti */ - hDC = GetDC(hConsoleWnd); - hCDC = CreateCompatibleDC(hDC); - SelectObject(hCDC, hBitmap); - ReleaseDC(hConsoleWnd, hDC); - } - - GetClientRect(hConsoleWnd, &r); - wx = (wx - r.right - 1) + bmwid; /* compute new desired size based on how client area came out */ - wy = (wy - r.bottom - 1) + bmht; - MoveWindow(hConsoleWnd, 0, 0, wx, wy, FALSE); /* resize window */ - - ShowWindow(hConsoleWnd, SW_SHOWNOACTIVATE); /* display it */ - UpdateWindow(hConsoleWnd); - - if (hActWnd != NULL) { /* bring console (sim) window back to top */ - GetWindowRect(hConsoleWnd, &r); - ShowWindow(hActWnd, SW_NORMAL); /* and move it just below the display window */ - SetWindowPos(hActWnd, HWND_TOP, 0, r.bottom, 0, 0, SWP_NOSIZE); - GetWindowRect(hActWnd, &ra); - if (ra.bottom >= GetSystemMetrics(SM_CYSCREEN)) { /* resize if it goes of bottom of screen */ - ra.bottom = GetSystemMetrics(SM_CYSCREEN) - 1; - SetWindowPos(hActWnd, 0, 0, 0, ra.right-ra.left+1, ra.bottom-ra.top+1, SWP_NOZORDER|SWP_NOMOVE); - } - } - - while (GetMessage(&msg, hConsoleWnd, 0, 0)) { /* message pump - this basically loops forevermore */ - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - if (hConsoleWnd != NULL) { - DestroyWindow(hConsoleWnd); /* but if a quit message got posted, clean up */ - hConsoleWnd = NULL; - } - - PumpID = 0; - return 0; -} - -/* ------------------------------------------------------------------------ - * DrawBits - starting at position (x,y), draw lamps for nbits bits of word 'bits', looking only at masked bits - * ------------------------------------------------------------------------ */ - -static void DrawBits (HDC hDC, int x, int y, int bits, int nbits, int mask, char *syms) -{ - int i, b = 0x0001 << (nbits-1); - - for (i = 0; i < nbits; i++, b >>= 1) { - if (mask & b) { /* select white or black lettering then write 2 chars */ - SetTextColor(hDC, (b & bits && power) ? RGB(255,255,255) : RGB(0,0,0)); - TextOut(hDC, x, y, syms, 2); - } - syms += 2; /* go to next symbol pair */ - - if (i < 10) - x += 15; /* step between lamps */ - else - x += 19; - - if (x < 500) { - if (b & 0x1110) - x += 10; /* step over nibble divisions on left side */ - else if (b & 0x0001) - x += 9; - } - } -} - -/* ------------------------------------------------------------------------ - * DrawToggles - display the console sense switches - * ------------------------------------------------------------------------ */ - -static void DrawToggles (HDC hDC, int bits) -{ - int b, x; - - for (b = 0x8000, x = 122; b != 0; b >>= 1) { - if (shown_ces & b) { /* up */ - SelectObject(hDC, hbWhite); - Rectangle(hDC, x, 232, x+9, 240); - SelectObject(hDC, hbGray); - Rectangle(hDC, x, 239, x+9, 255); - } - else { /* down */ - SelectObject(hDC, hbWhite); - Rectangle(hDC, x, 263, x+9, 271); - SelectObject(hDC, hbGray); - Rectangle(hDC, x, 248, x+9, 264); - } - - x += (b & 0x1111) ? 31 : 21; - } -} - -/* ------------------------------------------------------------------------ - * DrawRunmode - draw the run mode rotary switch's little tip - * ------------------------------------------------------------------------ */ - -void DrawRunmode (HDC hDC, int mode) -{ - double angle = (mode*45. + 90.) * 3.1415926 / 180.; /* convert mode position to angle in radians */ - double ca, sa; /* sine and cosine */ - int x0, y0, x1, y1; - HPEN hOldPen; - - ca = cos(angle); - sa = sin(angle); - - x0 = 301 + (int) (20.*ca + 0.5); /* inner radius */ - y0 = 389 - (int) (20.*sa + 0.5); - x1 = 301 + (int) (25.*ca + 0.5); /* outer radius */ - y1 = 389 - (int) (25.*sa + 0.5); - - hOldPen = SelectObject(hDC, hSwitchPen); - - MoveToEx(hDC, x0, y0, NULL); - LineTo(hDC, x1, y1); - - SelectObject(hDC, hOldPen); -} - -/* ------------------------------------------------------------------------ - * HandleClick - handle mouse clicks on the console window. Now we just - * look at the console sense switches. Actual says this is a real click, rather - * than a mouse-region test. Return value TRUE means the cursor is over a hotspot. - * ------------------------------------------------------------------------ */ - -static BOOL HandleClick (HWND hWnd, int xh, int yh, BOOL actual) -{ - int b, x, r, ang, i; - - for (b = 0x8000, x = 122; b != 0; b >>= 1) { - if (BETWEEN(xh, x-3, x+8+3) && BETWEEN(yh, 230, 275)) { - if (actual) { - CES ^= b; /* a hit. Invert the bit and redisplay */ - update_gui(TRUE); - } - return TRUE; - } - x += (b & 0x1111) ? 31 : 21; - } - - if (BETWEEN(xh, 245, 355) && BETWEEN(yh, 345, 425)) { /* hit near rotary switch */ - ang = (int) (atan2(301.-xh, 389.-yh)*180./3.1415926); /* this does implicit 90 deg rotation by the way */ - r = (int) sqrt((xh-301)*(xh-301)+(yh-389)*(yh-389)); - if (r > 12) { - for (i = MODE_LOAD; i <= MODE_INT_RUN; i++) { - if (BETWEEN(ang, i*45-12, i*45+12)) { - if (actual) { - RUNMODE = i; - update_gui(TRUE); - } - return TRUE; - } - } - - } - } - - return FALSE; -} - -/* ------------------------------------------------------------------------ - * DrawConsole - refresh the console display. (This routine could be sped up by intersecting - * the various components' bounding rectangles with the repaint rectangle. The bounding rects - * could be put into an array and used both here and in the refresh routine). - * - * RedrawRegion -> force repaint w/o background redraw. used for lamps which are drawn in the same place in either state - * RepaintRegion-> repaint with background redraw. Used for toggles which change position. - * ------------------------------------------------------------------------ */ - -static void DrawConsole (HDC hDC) -{ - static char digits[] = " 0 1 2 3 4 5 6 7 8 9101112131415"; - static char cccs[] = "3216 8 4 2 1"; - static char cnds[] = " C V"; - static char waits[] = " W"; - HFONT hOldFont, hOldBrush; - - hOldFont = SelectObject(hDC, hFont); /* use that tiny font */ - hOldBrush = SelectObject(hDC, hbWhite); - - SetBkMode(hDC, TRANSPARENT); /* overlay letters w/o changing background */ - - DrawBits(hDC, 76, 15, shown_iar, 16, 0x3FFF, digits); - DrawBits(hDC, 76, 48, shown_sar, 16, 0x3FFF, digits); - DrawBits(hDC, 76, 81, shown_sbr, 16, 0xFFFF, digits); - DrawBits(hDC, 76, 147, shown_acc, 16, 0xFFFF, digits); - DrawBits(hDC, 76, 180, shown_ext, 16, 0xFFFF, digits); - - DrawBits(hDC, 506, 15, shown_op, 5, 0x001F, digits); - DrawBits(hDC, 506, 81, shown_tag, 4, 0x0007, digits); - DrawBits(hDC, 506, 114, shown_irq, 6, 0x003F, digits); - DrawBits(hDC, 506, 147, shown_ccc, 6, 0x003F, cccs); - DrawBits(hDC, 506, 180, shown_cnd, 2, 0x0003, cnds); - - DrawBits(hDC, 390, 81, shown_wait?1:0,1, 0x0001, waits); - - DrawToggles(hDC, shown_ces); - - DrawRunmode(hDC, shown_runmode); - - SelectObject(hDC, hOldFont); - SelectObject(hDC, hOldBrush); -} - -/* ------------------------------------------------------------------------ - * Handles button presses. Remember that this occurs in the context of - * the Pump thread, not the simulator thread. - * ------------------------------------------------------------------------ */ - -extern void stuff_cmd (char *cmd); -extern void remark_cmd (char *cmd); - -void flash_run (void) -{ - EnableWindow(btn[IDC_RUN].hBtn, TRUE); // enable the run lamp - btn[IDC_RUN].offtime = GetTickCount(); // reset timeout - - KillTimer(hConsoleWnd, UPDATE_TIMER_ID); // (re)schedule lamp update - SetTimer(hConsoleWnd, UPDATE_TIMER_ID, LAMPTIME+1, NULL); -} - -void HandleCommand (HWND hWnd, WPARAM wParam, LPARAM lParam) -{ - int i; - - switch (wParam) { - case IDC_POWER: /* toggle system power */ - power = ! power; - reset_all(0); - if (running && ! power) { /* turning off */ - reason = STOP_POWER_OFF; - while (running) - Sleep(10); /* wait for execution thread to exit */ - } - EnableWindow(btn[IDC_POWER_ON].hBtn, power); - for (i = 0; i < NBUTTONS; i++) - InvalidateRect(btn[i].hBtn, NULL, TRUE); - break; - - case IDC_PROGRAM_START: /* begin execution */ - if (! running) { - switch (RUNMODE) { - case MODE_INT_RUN: - case MODE_RUN: - case MODE_SI: - stuff_cmd("go"); - break; - - case MODE_DISP: /* display core and advance IAR */ - ReadW(IAR); - IAR = IAR+1; - flash_run(); /* illuminate run lamp for .5 sec */ - break; - - case MODE_LOAD: /* store to core and advance IAR */ - WriteW(IAR, CES); - IAR = IAR+1; - flash_run(); - break; - } - } - break; - - case IDC_PROGRAM_STOP: - if (running) { /* potential race condition here */ - GUI_BEGIN_CRITICAL_SECTION - SETBIT(con_dsw, CON_DSW_PROGRAM_STOP); - SETBIT(ILSW[5], ILSW_5_PROGRAM_STOP); - int_req |= INT_REQ_5; - GUI_END_CRITICAL_SECTION - } - break; - - case IDC_LOAD_IAR: - if (! running) { - IAR = CES & 0x3FFF; /* set IAR from console entry switches */ - } - break; - - case IDC_KEYBOARD: /* toggle between console/keyboard mode */ - break; - - case IDC_IMM_STOP: - if (running) { - reason = STOP_WAIT; /* terminate execution without setting wait_mode */ - while (running) - Sleep(10); /* wait for execution thread to exit */ - } - break; - - case IDC_RESET: - if (! running) { /* check-reset is disabled while running */ - reset_all(0); - forms_check(0); /* clear forms-check status */ - print_check(0); - } - break; - - case IDC_PROGRAM_LOAD: - if (! running) { /* if card reader is attached to a file, do cold start read of one card */ - IAR = 0; /* reset IAR */ -// stuff_cmd("boot cr"); - if (cr_boot(0) != SCPE_OK) /* load boot card */ - remark_cmd("IPL failed"); - } - break; - } - - update_gui(FALSE); -} - -/* ------------------------------------------------------------------------ - * ConsoleWndProc - window process for the console display - * ------------------------------------------------------------------------ */ - -LRESULT CALLBACK ConsoleWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) -{ - HDC hDC; - PAINTSTRUCT ps; - POINT p; - RECT clip, xsect, rbmp; - int i; - - switch (uMsg) { - case WM_CLOSE: - DestroyWindow(hWnd); - break; - - case WM_DESTROY: - hConsoleWnd = NULL; - break; - - case WM_ERASEBKGND: - hDC = (HDC) wParam; - GetClipBox(hDC, &clip); - SetRect(&rbmp, 0, 0, bmwid, bmht); - if (IntersectRect(&xsect, &clip, &rbmp)) - BitBlt(hDC, xsect.left, xsect.top, xsect.right-xsect.left+1, xsect.bottom-xsect.top+1, hCDC, xsect.left, xsect.top, SRCCOPY); -// rbmp.top = rbmp.bottom; -// rbmp.bottom += 200; -// if (IntersectRect(&xsect, &clip, &rbmp)) -// FillRect(hDC, &xsect, hbBlack); - return TRUE; /* let Paint do this so we know what the update region is (ps.rcPaint) */ - - case WM_PAINT: - hDC = BeginPaint(hWnd, &ps); - DrawConsole(hDC); - EndPaint(hWnd, &ps); - break; - - case WM_COMMAND: /* button click */ - HandleCommand(hWnd, wParam, lParam); - break; - - case WM_DRAWITEM: - PaintButton((LPDRAWITEMSTRUCT) lParam); - break; - - case WM_SETCURSOR: - GetCursorPos(&p); - ScreenToClient(hWnd, &p); - SetCursor(HandleClick(hWnd, p.x, p.y, FALSE) ? hcHand : hcArrow); - return TRUE; - - case WM_LBUTTONDOWN: - HandleClick(hWnd, LOWORD(lParam), HIWORD(lParam), TRUE); - break; - - case WM_CTLCOLORBTN: - i = GetWindowLong((HWND) lParam, GWL_ID); - if (BETWEEN(i, 0, NBUTTONS-1)) - return (LRESULT) (power && IsWindowEnabled((HWND) lParam) ? btn[i].hbrLit : btn[i].hbrDark); - - case WM_TIMER: - if (wParam == UPDATE_TIMER_ID) { - update_gui(FALSE); - KillTimer(hWnd, UPDATE_TIMER_ID); - } - break; - - default: - return DefWindowProc(hWnd, uMsg, wParam, lParam); - } - - return 0; -} - -enum {PRINTER_OK = 0, FORMS_CHECK = 1, PRINT_CHECK = 2, BOTH_CHECK = 3} printerstatus = PRINTER_OK; - -void forms_check (int set) -{ - COLORREF oldcolor = btn[IDC_FORMS_CHECK].clr; - - if (set) - SETBIT(printerstatus, FORMS_CHECK); - else - CLRBIT(printerstatus, FORMS_CHECK); - - btn[IDC_FORMS_CHECK].clr = (printerstatus & PRINT_CHECK) ? RGB(255,0,0) : RGB(255,255,0); - - EnableWindow(btn[IDC_FORMS_CHECK].hBtn, printerstatus); - - if (btn[IDC_FORMS_CHECK].clr != oldcolor) - InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); // change color in any case -} - -void print_check (int set) -{ - COLORREF oldcolor = btn[IDC_FORMS_CHECK].clr; - - if (set) - SETBIT(printerstatus, PRINT_CHECK); - else - CLRBIT(printerstatus, PRINT_CHECK); - - btn[IDC_FORMS_CHECK].clr = (printerstatus & PRINT_CHECK) ? RGB(255,0,0) : RGB(255,255,0); - - EnableWindow(btn[IDC_FORMS_CHECK].hBtn, printerstatus); - - if (btn[IDC_FORMS_CHECK].clr != oldcolor) - InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); // change color in any case -} - -void keyboard_selected (int select) -{ - EnableWindow(btn[IDC_KEYBOARD_SELECT].hBtn, select); -} - -void disk_ready (int ready) -{ - EnableWindow(btn[IDC_FILE_READY].hBtn, ready); -} - -void disk_unlocked (int unlocked) -{ - EnableWindow(btn[IDC_DISK_UNLOCK].hBtn, unlocked); -} - -CRITICAL_SECTION critsect; - -void begin_critical_section (void) -{ - static BOOL mustinit = TRUE; - - if (mustinit) { - InitializeCriticalSection(&critsect); - mustinit = FALSE; - } - - EnterCriticalSection(&critsect); -} - -void end_critical_section (void) -{ - LeaveCriticalSection(&critsect); -} - -#endif // WIN32 -#endif // GUI_SUPPORT +#endif // ifdef CGI_SUPPORT diff --git a/Ibm1130/ibm1130_cr.c b/Ibm1130/ibm1130_cr.c index 7b18616f..9223b85f 100644 --- a/Ibm1130/ibm1130_cr.c +++ b/Ibm1130/ibm1130_cr.c @@ -2,8 +2,16 @@ /* ibm1130_cr.c: IBM 1130 1442 Card Reader simulator - Copyright (c) 2002, Brian Knittel - Based on PDP-11 simulator written by Robert M Supnik + Based on the SIMH package written by Robert M Supnik + + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org NOTE - there is a problem with this code. The Device Status Word (DSW) is computed from current conditions when requested by an XIO load status @@ -77,7 +85,7 @@ commands may NOT be accurate. This should probably be fixed. || Hmmm -- what takes the place of the Start button on \\ the card reader? - Binary format is stored using fwrite of short ints, in this format: + Binary format is stored using fxwrite of short ints, in this format: 1 1 2 2 0 1 2 3 4 5 6 7 8 9 @@ -131,12 +139,14 @@ commands may NOT be accurate. This should probably be fixed. deck will not be very helpful. */ -#define READ_DELAY 100 -#define PUNCH_DELAY 300 -#define FEED_DELAY 500 +#define READ_DELAY 35 // see how small a number we can get away with +#define PUNCH_DELAY 35 +#define FEED_DELAY 25 // #define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT) +extern int32 sim_switches; + static t_stat cr_svc (UNIT *uptr); static t_stat cr_reset (DEVICE *dptr); static t_stat cr_set_code (UNIT *uptr, int32 match); @@ -155,12 +165,18 @@ static int32 cp_wait = FEED_DELAY; /* feed op wait */ #define UNIT_V_OPERATION (UNIT_V_UF + 0) /* operation in progress */ #define UNIT_V_CODE (UNIT_V_UF + 2) #define UNIT_V_EMPTY (UNIT_V_UF + 4) +#define UNIT_V_SCRATCH (UNIT_V_UF + 5) +#define UNIT_V_QUIET (UNIT_V_UF + 6) +#define UNIT_V_DEBUG (UNIT_V_UF + 7) #define UNIT_V_LASTPUNCH (UNIT_V_UF + 0) /* bit in unit_cp flags */ #define UNIT_OP (3u << UNIT_V_OPERATION) /* two bits */ #define UNIT_CODE (3u << UNIT_V_CODE) /* two bits */ #define UNIT_EMPTY (1u << UNIT_V_EMPTY) +#define UNIT_SCRATCH (1u << UNIT_V_SCRATCH) /* temp file */ +#define UNIT_QUIET (1u << UNIT_V_QUIET) +#define UNIT_DEBUG (1u << UNIT_V_DEBUG) #define UNIT_LASTPUNCH (1u << UNIT_V_LASTPUNCH) @@ -171,6 +187,8 @@ static int32 cp_wait = FEED_DELAY; /* feed op wait */ #define SET_OP(op) {cr_unit.flags &= ~UNIT_OP; cr_unit.flags |= op;} +#define CURRENT_OP (cr_unit.flags & UNIT_OP) + #define CODE_029 (0u << UNIT_V_CODE) #define CODE_026F (1u << UNIT_V_CODE) #define CODE_026C (2u << UNIT_V_CODE) @@ -180,7 +198,7 @@ static int32 cp_wait = FEED_DELAY; /* feed op wait */ #define COLUMN u4 /* column field in unit record */ -UNIT cr_unit = { UDATA (&cr_svc, UNIT_ATTABLE, 0) }; +UNIT cr_unit = { UDATA (&cr_svc, UNIT_ATTABLE|UNIT_ROABLE, 0) }; UNIT cp_unit = { UDATA (NULL, UNIT_ATTABLE, 0) }; MTAB cr_mod[] = { @@ -405,12 +423,22 @@ static CPCODE cardcode_026C[] = // 026 commercial 0x2220, '(', }; +extern int cgi; +extern void sub_args (char *instr, char *tmpbuf, int32 maxstr, int32 nargs, char *arg[]); + static int16 ascii_to_card[256]; -CPCODE *cardcode; -int ncardcode; -int32 active_cr_code; /* the code most recently specified */ -FILE *deckfile = NULL; +static CPCODE *cardcode; +static int ncardcode; +static int32 active_cr_code; /* the code most recently specified */ +static FILE *deckfile = NULL; +static char tempfile[128]; +static int cardnum; +static int any_punched = 0; + +#define MAXARG 80 /* saved arguments to attach command */ +static char list_save[MAXARG][10], *list_arg[MAXARG]; +static int list_nargs = 0; static int16 punchstation[80]; static int16 readstation[80]; @@ -516,7 +544,8 @@ t_stat load_cr_boot (int drvno) WriteW(i, boot2_data[i]); #ifdef GUI_SUPPORT - remark_cmd("Loaded BOOT2 cold start card\n"); + if (! cgi) + remark_cmd("Loaded BOOT2 cold start card\n"); #endif return SCPE_OK; } @@ -538,7 +567,7 @@ t_stat cr_boot (int unitno) return SCPE_IOERR; } - if (fread(buf, sizeof(short), 80, cr_unit.fileref) != 80) + if (fxread(buf, sizeof(short), 80, cr_unit.fileref) != 80) return SCPE_IOERR; IAR = 0; /* Program Load sets IAR = 0 */ @@ -560,6 +589,19 @@ char card_to_ascii (int16 hol) return ' '; } +// hollerith_to_ascii - provide a generic conversion for simulator debugging + +char hollerith_to_ascii (int16 hol) +{ + int i; + + for (i = 0; i < ncardcode; i++) + if (cardcode_029[i].hollerith == hol) + return cardcode[i].ascii; + + return ' '; +} + /* feedcycle - move cards to next station */ static void feedcycle (t_bool load, t_bool punching) @@ -569,9 +611,9 @@ static void feedcycle (t_bool load, t_bool punching) /* write punched card if punch is attached to a file */ if (cp_unit.flags & UNIT_ATT) { - if (punchstate != STATION_EMPTY) { + if (any_punched && punchstate != STATION_EMPTY) { if ((cp_unit.flags & UNIT_CODE) == CODE_BINARY) { - fwrite(punchstation, sizeof(short), 80, cp_unit.fileref); + fxwrite(punchstation, sizeof(short), 80, cp_unit.fileref); } else { for (i = 80; --i >= 0; ) { /* find last nonblank column */ @@ -588,7 +630,7 @@ static void feedcycle (t_bool load, t_bool punching) /* nwrite is now number of characters to output */ buf[nwrite++] = '\n'; /* append newline */ - fwrite(buf, sizeof(char), nwrite, cp_unit.fileref); + fxwrite(buf, sizeof(char), nwrite, cp_unit.fileref); } } } @@ -621,48 +663,57 @@ again: /* jump here if we've loaded a new deck after emptying the previous one memset(readstation, 0, sizeof(readstation)); /* blank out the card image */ - if (cr_unit.fileref == NULL) { + if (cr_unit.fileref == NULL) nread = 0; - } - else if ((active_cr_code & UNIT_CODE) == CODE_BINARY) { /* binary read is straightforward */ - nread = fread(readstation, sizeof(short), 80, cr_unit.fileref); - } - else { /* text read is harder: */ - if (fgets(buf, 81, cr_unit.fileref) == NULL) /* read up to 80 chars */ - nread = 0; /* hmm, end of file */ - else { /* check for newline */ - if ((x = strchr(buf, '\r')) == NULL) - x = strchr(buf, '\n'); - if (x == NULL) { /* there were no delimiters, check for newline after the 80 chars, eat if present */ - ch = getc(cr_unit.fileref); - if (ch != '\r' && ch != '\n' && ch != EOF) - ungetc(ch, cr_unit.fileref); + else if ((active_cr_code & UNIT_CODE) == CODE_BINARY) /* binary read is straightforward */ + nread = fxread(readstation, sizeof(short), 80, cr_unit.fileref); - nread = 80; - } - else { - *x = ' '; /* replace with blank */ - nread = x-buf+1; + else if (fgets(buf, sizeof(buf), cr_unit.fileref) == NULL) /* read up to 80 chars */ + nread = 0; /* hmm, end of file */ + + else { /* check for newline */ + if ((x = strchr(buf, '\r')) == NULL) + x = strchr(buf, '\n'); + + if (x == NULL) { /* there were no delimiters, burn rest of line */ + while ((ch = getc(cr_unit.fileref)) != EOF) { /* get character */ + if (ch == '\n') /* newline, done */ + break; + + if (ch == '\r') { /* CR, try to take newline too */ + ch = getc(cr_unit.fileref); + if (ch != EOF && ch != '\n') /* hmm, put it back */ + ungetc(ch, cr_unit.fileref); + + break; + } } + nread = 80; /* take just the first 80 characters */ } + else + nread = x-buf; /* reduce length of string */ - upcase(buf); /* force uppercase */ + upcase(buf); /* force uppercase */ - for (i = 0; i < nread; i++) /* convert ascii to punch code */ + for (i = 0; i < nread; i++) /* convert ascii to punch code */ readstation[i] = ascii_to_card[buf[i]]; + + nread = 80; /* even if line was blank consider it present */ } - if (nread <= 0) { /* set hopper flag accordingly */ + if (nread <= 0) { /* set hopper flag accordingly */ if (deckfile != NULL && nextdeck()) goto again; SETBIT(cr_unit.flags, UNIT_EMPTY); readstate = STATION_EMPTY; + cardnum = -1; /* nix the card counter */ } else { CLRBIT(cr_unit.flags, UNIT_EMPTY); readstate = STATION_LOADED; + cardnum++; /* advance card counter */ } } else @@ -685,6 +736,8 @@ static void npro (void) if (deckfile != NULL) fseek(deckfile, 0, SEEK_END); /* skip to end of deck list */ + cardnum = -1; /* nix the card counter */ + if (punchstate == STATION_PUNCHED) feedcycle(FALSE, FALSE); /* flush out card just punched */ @@ -737,6 +790,7 @@ static void checkdeck (void) fseek(cr_unit.fileref, 0, SEEK_END); empty = ftell(cr_unit.fileref) <= 0; /* see if file has anything) */ fseek(cr_unit.fileref, 0, SEEK_SET); /* rewind deck */ + cardnum = 0; /* reset card counter */ } if (empty) { @@ -752,17 +806,26 @@ static void checkdeck (void) static t_bool nextdeck (void) { - char buf[200], *e; + char buf[200], tmpbuf[200], *fname, *mode, *tn; int code; + long fpos; + static char white[] = " \t\r\n"; + + cardnum = 0; /* reset card counter */ if (deckfile == NULL) /* we can't help */ return FALSE; code = cr_unit.flags & UNIT_CODE; /* default code */ - if (cr_unit.fileref != NULL) { - fclose(cr_unit.fileref); + if (cr_unit.fileref != NULL) { /* this pulls the rug out from under scp */ + fclose(cr_unit.fileref); /* since the attach flag is still set. be careful! */ cr_unit.fileref = NULL; + + if (cr_unit.flags & UNIT_SCRATCH) { + unlink(tempfile); + CLRBIT(cr_unit.flags, UNIT_SCRATCH); + } } for (;;) { /* get a filename */ @@ -773,24 +836,76 @@ static t_bool nextdeck (void) if (! *buf) continue; /* empty line */ - e = buf + strlen(buf) - 1; /* last character in name */ - if (e > (buf+1) && e[-1] <= ' ') { /* if there is at least a name + blank + character, and 2nd to last is blank */ - if (*e == 'b' || *e == 'B') { - code = CODE_BINARY; - e[-1] = '\0'; /* clip at the space and re-trim */ - alltrim(buf); - } - else if (*e == 'a' || *e == 'A') { - code = CODE_029; - e[-1] = '\0'; - alltrim(buf); - } + if (strnicmp(buf, "!BREAK", 6) == 0) { /* stop the simulation */ + break_simulation(STOP_DECK_BREAK); + continue; } - if ((cr_unit.fileref = fopen(buf, "rb")) == NULL) - printf("File '%s' specified in deck file '%s' cannot be opened\n", buf, cr_unit.filename+1); - else + if (buf[0] == '!') { /* literal text line, make a temporary file */ + if (*tempfile == '\0') { + if ((tn = tempnam(".", "1130")) == NULL) { + printf("Cannot create temporary card file name\n"); + break_simulation(STOP_DECK_BREAK); + return 0; + } + strcpy(tempfile, tn); + strcat(tempfile, ".tmp"); + } + + if ((cr_unit.fileref = fopen(tempfile, "wb+")) == NULL) { + printf("Cannot create temporary file %s\n", tempfile); + break_simulation(STOP_DECK_BREAK); + return 0; + } + + SETBIT(cr_unit.flags, UNIT_SCRATCH); + + for (;;) { /* store literal cards into temporary file */ + upcase(buf+1); + fputs(buf+1, cr_unit.fileref); + putc('\n', cr_unit.fileref); + + trace_io("(Literal card %s\n)", buf+1); + if (! (cr_unit.flags & UNIT_QUIET)) + printf("(Literal card %s)\n", buf+1); + + fpos = ftell(deckfile); + if (fgets(buf, sizeof(buf), deckfile) == NULL) + break; /* oops, end of file */ + if (buf[0] != '!' || strnicmp(buf, "!BREAK", 6) == 0) + break; + alltrim(buf); + } + fseek(deckfile, fpos, SEEK_SET); /* restore deck file to just before non-literal card */ + + fseek(cr_unit.fileref, 0, SEEK_SET); /* rewind scratch file for reading */ + code = CODE_029; /* assume keycode 029 */ break; + } + + sub_args(buf, tmpbuf, sizeof(buf), list_nargs, list_arg); /* substitute in stuff from the attach command line */ + + if ((fname = strtok(buf, white)) == NULL) + continue; + + if (*fname == '#' || *fname == '*' || *fname == ';') + continue; /* comment */ + + if ((mode = strtok(NULL, white)) != NULL) { + if (*mode == 'b' || *mode == 'B') + code = CODE_BINARY; + else if (*mode == 'a' || *mode == 'A') + code = CODE_029; + } + + if ((cr_unit.fileref = fopen(fname, "rb")) == NULL) + printf("File '%s' specified in deck file '%s' cannot be opened\n", fname, cr_unit.filename+1); + else { + trace_io("(Opened %s deck %s)\n", (code == CODE_BINARY) ? "binary" : "text", fname); + if (! (cr_unit.flags & UNIT_QUIET)) + printf("(Opened %s deck %s)\n", (code == CODE_BINARY) ? "binary" : "text", fname); + break; + } } checkdeck(); @@ -844,19 +959,61 @@ static t_stat cr_attach (UNIT *uptr, char *cptr) { t_stat rval; t_bool use_decklist; + char *c, *arg, quote; // no - don't cancel pending read? // sim_cancel(uptr); /* cancel pending operations */ - cr_detach(uptr); /* detach file and possibly deckfile */ - cptr = skipbl(cptr); /* skip any leading whitespace */ + CLRBIT(uptr->flags, UNIT_QUIET|UNIT_DEBUG); /* set debug/quiet flags */ + if (sim_switches & SWMASK('D')) SETBIT(uptr->flags, UNIT_DEBUG); + else if (sim_switches & SWMASK('Q')) SETBIT(uptr->flags, UNIT_QUIET); + + cr_detach(uptr); /* detach file and possibly deckfile */ + CLRBIT(uptr->flags, UNIT_SCRATCH); + + c = cptr; + for (list_nargs = 0; list_nargs < 10; ) { /* extract arguments */ + while (*c && (*c <= ' ')) /* skip blanks */ + c++; + if (! *c) + break; /* all done */ + + arg = c; /* save start */ + + while (*c && (*c > ' ')) { + if (*c == '\'' || *c == '"') { /* quoted string */ + for (quote = *c++; *c;) + if (*c++ == quote) + break; + } + else c++; + } + if (*c) + *c++ = 0; /* term arg at space */ + + list_arg[list_nargs] = list_save[list_nargs]; /* set pointer to permanent storage location */ + strncpy(list_arg[list_nargs++], arg, MAXARG); /* store copy */ + } + + if (list_nargs <= 0) /* need at least 1 */ + return SCPE_2FARG; + + cptr = list_arg[0]; /* filename is first argument */ use_decklist = (*cptr == '@'); /* filename starts with @: it's a deck list */ if (use_decklist) cptr++; - if ((rval = attach_unit(uptr, cptr)) != SCPE_OK) + if (strcmp(cptr, "-") == 0 && ! use_decklist) { /* standard input */ + if (uptr -> flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ + uptr->filename = calloc(CBUFSIZE, sizeof(char)); + strcpy(uptr->filename, "(stdin)"); + uptr->fileref = stdin; + SETBIT(uptr->flags, UNIT_ATT); + uptr->pos = 0; + } + else if ((rval = attach_unit(uptr, cptr)) != SCPE_OK) return rval; if (use_decklist) { /* if we skipped the '@', store the actually-specified name */ @@ -868,34 +1025,63 @@ static t_stat cr_attach (UNIT *uptr, char *cptr) else checkdeck(); + // there is a read pending. Pull the card in to make it go + if (CURRENT_OP == OP_READING || CURRENT_OP == OP_PUNCHING || CURRENT_OP == OP_FEEDING) + feedcycle(TRUE, CURRENT_OP == OP_PUNCHING); + // no - don't reset the reader // cr_reset(&cr_dev); /* reset the whole thing */ // cp_reset(&cp_dev); + cardnum = 0; /* reset card counter */ + return SCPE_OK; } static t_stat cr_detach (UNIT *uptr) { - if (deckfile != NULL) { - fclose(deckfile); - deckfile = NULL; + t_stat rval; + + if (cr_unit.flags & UNIT_ATT && deckfile != NULL) { + if (cr_unit.fileref != NULL) /* close the active card deck */ + fclose(cr_unit.fileref); + + if (cr_unit.flags & UNIT_SCRATCH) { + unlink(tempfile); + CLRBIT(cr_unit.flags, UNIT_SCRATCH); + } + + cr_unit.fileref = deckfile; /* give scp a file to close */ } - return detach_unit(uptr); + if (uptr->fileref == stdout) { + CLRBIT(uptr->flags, UNIT_ATT); + free(uptr->filename); + uptr->filename = NULL; + rval = SCPE_OK; + } + else + rval = detach_unit(uptr); + + return rval; } static t_stat cp_detach (UNIT *uptr) { if (cp_unit.flags & UNIT_ATT) if (punchstate == STATION_PUNCHED) - feedcycle(FALSE, FALSE); /* flush out card just punched */ + feedcycle(FALSE, FALSE); /* flush out card just punched */ + + any_punched = 0; /* reset punch detected */ return detach_unit(uptr); } static void op_done (void) { + if (cr_unit.flags & UNIT_DEBUG) + DEBUG_PRINT("!CR Op Complete, card %d", cardnum); + SET_OP(OP_IDLE); SETBIT(cr_dsw, CR_DSW_OP_COMPLETE); SETBIT(ILSW[4], ILSW_4_1442_CARD); @@ -904,7 +1090,7 @@ static void op_done (void) static t_stat cr_svc (UNIT *uptr) { - switch (cr_unit.flags & UNIT_OP) { + switch (CURRENT_OP) { case OP_IDLE: break; @@ -923,6 +1109,8 @@ static t_stat cr_svc (UNIT *uptr) SETBIT(ILSW[0], ILSW_0_1442_CARD); calc_ints(); sim_activate(&cr_unit, cr_wait); + if (cr_unit.flags & UNIT_DEBUG) + DEBUG_PRINT("!CR Read Response %d : %d", cardnum, cr_unit.COLUMN+1); } else { readstate = STATION_READ; @@ -945,6 +1133,8 @@ static t_stat cr_svc (UNIT *uptr) SETBIT(ILSW[0], ILSW_0_1442_CARD); calc_ints(); sim_activate(&cr_unit, cp_wait); + if (cr_unit.flags & UNIT_DEBUG) + DEBUG_PRINT("!CR Punch Response"); } break; } @@ -963,23 +1153,29 @@ void xio_1142_card (int32 addr, int32 func, int32 modify) case XIO_SENSE_DEV: if (cp_unit.flags & UNIT_ATT) lastcard = FALSE; /* if punch file is open, assume infinite blank cards in reader */ - else if (readstate == STATION_EMPTY || (cr_unit.flags & UNIT_ATT) == 0) + else if ((cr_unit.flags & UNIT_ATT) == 0) lastcard = TRUE; /* if nothing to read, hopper's empty */ - else if ((ch = getc(cr_unit.fileref)) == EOF) - lastcard = TRUE; /* there is nothing left to read for a next card */ - else { + else if (readstate == STATION_LOADED) + lastcard = FALSE; + else if (cr_unit.fileref == NULL) + lastcard = TRUE; + else if ((ch = getc(cr_unit.fileref)) != EOF) { ungetc(ch, cr_unit.fileref); /* put character back; hopper's not empty */ lastcard = FALSE; } + else if (deckfile != NULL && nextdeck()) + lastcard = FALSE; + else + lastcard = TRUE; /* there is nothing left to read for a next card */ CLRBIT(cr_dsw, CR_DSW_LAST_CARD|CR_DSW_BUSY|CR_DSW_NOT_READY); if (lastcard) SETBIT(cr_dsw, CR_DSW_LAST_CARD); - if ((cr_unit.flags & UNIT_OP) != OP_IDLE) + if (CURRENT_OP != OP_IDLE) SETBIT(cr_dsw, CR_DSW_BUSY|CR_DSW_NOT_READY); - else if (readstate == STATION_EMPTY && punchstate == STATION_EMPTY && ! lastcard) + else if (readstate == STATION_EMPTY && punchstate == STATION_EMPTY && lastcard) SETBIT(cr_dsw, CR_DSW_NOT_READY); if (modify & 0x01) { /* reset interrupts */ @@ -993,6 +1189,9 @@ void xio_1142_card (int32 addr, int32 func, int32 modify) } ACC = cr_dsw; /* return the DSW */ + + if (cr_unit.flags & UNIT_DEBUG) + DEBUG_PRINT("#CR Sense %04x%s%s", cr_dsw, (modify & 1) ? " RESET0" : "", (modify & 2) ? " RESET4" : ""); break; case XIO_READ: /* get card data into word pointed to in IOCC packet */ @@ -1002,6 +1201,8 @@ void xio_1142_card (int32 addr, int32 func, int32 modify) } else if (cr_unit.COLUMN < 80) { WriteW(addr, readstation[cr_unit.COLUMN]); + if (cr_unit.flags & UNIT_DEBUG) + DEBUG_PRINT("#CR Read %03x", (readstation[cr_unit.COLUMN] >> 4)); } else if (cr_unit.COLUMN == 80) { xio_error("1442: Read past column 80!"); @@ -1027,6 +1228,8 @@ void xio_1142_card (int32 addr, int32 func, int32 modify) punchstation[cp_unit.COLUMN] = wd & 0xFFF0; if (wd & 0x0008) /* mark this as last column to be punched */ SETBIT(cp_unit.flags, UNIT_LASTPUNCH); + if (cr_unit.flags & UNIT_DEBUG) + DEBUG_PRINT("#CR Punch %03x%s", (wd >> 4) & 0xFFF, (wd & 8) ? " LAST" : ""); } else if (cp_unit.COLUMN == 80) { xio_error("1442: Punch past column 80!"); @@ -1041,6 +1244,8 @@ void xio_1142_card (int32 addr, int32 func, int32 modify) case XIO_CONTROL: switch (modify & 7) { case 1: /* start punch */ + if (cr_unit.flags & UNIT_DEBUG) + DEBUG_PRINT("#CR Start Punch"); if (punchstate != STATION_LOADED) feedcycle(TRUE, TRUE); @@ -1049,11 +1254,15 @@ void xio_1142_card (int32 addr, int32 func, int32 modify) CLRBIT(cp_unit.flags, UNIT_LASTPUNCH); + any_punched = 1; /* we've started punching, so enable writing to output deck file */ + sim_cancel(&cr_unit); sim_activate(&cr_unit, cp_wait); break; case 2: /* feed cycle */ + if (cr_unit.flags & UNIT_DEBUG) + DEBUG_PRINT("#CR Feed"); feedcycle(TRUE, FALSE); SET_OP(OP_FEEDING); @@ -1063,6 +1272,8 @@ void xio_1142_card (int32 addr, int32 func, int32 modify) break; case 4: /* start read */ + if (cr_unit.flags & UNIT_DEBUG) + DEBUG_PRINT("#CR Start read"); if (readstate != STATION_LOADED) feedcycle(TRUE, FALSE); @@ -1074,6 +1285,8 @@ void xio_1142_card (int32 addr, int32 func, int32 modify) break; case 0: + if (cr_unit.flags & UNIT_DEBUG) + DEBUG_PRINT("#CR NOP"); break; default: diff --git a/Ibm1130/ibm1130_defs.h b/Ibm1130/ibm1130_defs.h index 570e82a4..c317f7d9 100644 --- a/Ibm1130/ibm1130_defs.h +++ b/Ibm1130/ibm1130_defs.h @@ -1,3 +1,14 @@ +/* + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org + */ + /* ibm1130_defs.h: IBM-1130 simulator definitions */ @@ -12,7 +23,12 @@ #define MIN(a,b) (((a) <= (b)) ? (a) : (b)) #define MAX(a,b) (((a) >= (b)) ? (a) : (b)) -// #define ENABLE_GUI // uncomment to compile the GUI extensions +#ifndef WIN32 + int strnicmp (char *a, char *b, int n); + int strcmpi (char *a, char *b); +#endif + +// #define GUI_SUPPORT // uncomment to compile the GUI extensions. It's defined in the windows ibm1130.mak makefile /* ------------------------------------------------------------------------ */ /* Architectural constants */ @@ -28,28 +44,65 @@ /* ------------------------------------------------------------------------ */ /* Global state */ -extern uint16 M[]; /* core memory, up to 32Kwords */ -extern uint16 ILSW[]; /* interrupt level status words */ -extern int32 IAR; /* instruction address register */ -extern int32 CES; /* console entry switches */ -extern int32 ACC, EXT; /* accumulator and extension */ -extern int32 ipl; /* current interrupt level (-1 = not handling irq) */ -extern int32 iplpending; /* bitfield: interrupted IPL's */ -extern int32 tbit; /* trace flag (causes level 5 IRQ after each instr) */ -extern int32 V, C; /* condition codes: overflow, carry */ -extern int32 wait_state; /* wait state (waiting for an IRQ or processor halted) */ -extern int32 int_req; /* bitfield: interrupt request levels active */ -extern int32 int_mask; /* current active interrupt mask (ipl sensitive) */ -extern int32 SR; /* switch register */ -extern int32 DR; /* display register */ -extern int32 wait_enable; /* wait state enable */ -extern int32 mem_mask; /* mem_mask - valid address mask (memsize-1) */ -extern int32 ibkpt_addr; /* breakpoint addr */ -extern int32 sim_int_char; +extern int cgi; // TRUE if we are running as a CGI program +extern int sim_gui; + +extern uint16 M[]; /* core memory, up to 32Kwords (note: don't even think about trying 64K) */ +extern uint16 ILSW[]; /* interrupt level status words */ +extern int32 IAR; /* instruction address register */ +extern int32 prev_IAR; /* instruction address register at start of current instruction */ +extern int32 SAR, SBR; /* storage address/buffer registers */ +extern int32 OP, TAG, CCC; /* instruction decoded pieces */ +extern int32 CES; /* console entry switches */ +extern int32 ACC, EXT; /* accumulator and extension */ +extern int32 RUNMODE; /* processor run/step mode */ +extern int32 ipl; /* current interrupt level (-1 = not handling irq) */ +extern int32 iplpending; /* interrupted IPL's */ +extern int32 tbit; /* trace flag (causes level 5 IRQ after each instr) */ +extern int32 V, C; /* condition codes */ +extern int32 wait_state; /* wait state (waiting for an IRQ) */ +extern int32 wait_lamp; /* alternate indicator to light the wait lamp on the GUI */ +extern int32 int_req; /* sum of interrupt request levels active */ +extern int32 int_lamps; /* accumulated version of int_req - gives lamp persistence */ +extern int32 int_mask; /* current active interrupt mask (ipl sensitive) */ +extern int32 mem_mask; +extern int32 cpu_dsw; /* CPU device status word */ +extern int32 sim_int_char; /* interrupt character */ +extern t_bool running; +extern t_bool power; +extern t_bool cgi; /* TRUE if we are running as a CGI program */ +extern t_stat reason; /* CPU execution loop control */ #define WAIT_OP 1 /* wait state causes: wait instruction, invalid instruction*/ #define WAIT_INVALID_OP 2 +#define MODE_SS 3 /* RUNMODE values. SS and SMC are not implemented in this simulator */ +#define MODE_SMC 2 +#define MODE_INT_RUN 1 +#define MODE_RUN 0 +#define MODE_SI -1 +#define MODE_DISP -2 +#define MODE_LOAD -3 + +/* ------------------------------------------------------------------------ */ +/* debugging */ +/* ------------------------------------------------------------------------ */ + +#define ENABLE_DEBUG_PRINT +#define ENABLE_DEBUG_TO_LOG + +#ifdef ENABLE_DEBUG_PRINT +# define DEBUG_PRINT debug_print +#else +# ifdef ENABLE_DEBUG_TO_LOG +# define DEBUG_PRINT trace_io +# else +# define DEBUG_PRINT if (0) debug_print +# endif +#endif + +void debug_print(char *fmt, ...); + /* ------------------------------------------------------------------------ */ /* memory IO routines */ @@ -71,6 +124,10 @@ void WriteW (int32 a, int32 d); #define STOP_IBKPT 3 /* simulator breakpoint */ #define STOP_INCOMPLETE 4 /* simulator coding not complete here */ #define STOP_POWER_OFF 5 /* no power */ +#define STOP_DECK_BREAK 6 /* !BREAK in deck file */ +#define STOP_PHASE_BREAK 7 /* phase load break */ +#define STOP_CRASH 8 /* program has crashed badly */ +#define STOP_TIMED_OUT 9 /* simulation time limit exceeded */ #define IORETURN(f,v) ((f)? (v): SCPE_OK) /* cond error return */ @@ -94,10 +151,10 @@ void WriteW (int32 a, int32 d); /* ILSW bits - set by appropriate device whenever an interrupt is outstanding */ -#define ILSW_0_1442_CARD 0x8000 /* not actually used */ +#define ILSW_0_1442_CARD 0x8000 /* ILSW 0 is not really defined on the 1130 */ -#define ILSW_1_SCA 0x8000 -#define ILSW_1_1132_PRINTER 0x4000 +#define ILSW_1_1132_PRINTER 0x8000 // had these backwards! +#define ILSW_1_SCA 0x4000 #define ILSW_2_1131_DISK 0x8000 @@ -178,10 +235,10 @@ void WriteW (int32 a, int32 d); #define ILSW_5_SAC_BIT_14 0x0002 #define ILSW_5_SAC_BIT_15 0x0001 -//* console DSW bits +//* CPU DSW bits -#define CON_DSW_PROGRAM_STOP 0x8000 -#define CON_DSW_INT_RUN 0x4000 +#define CPU_DSW_PROGRAM_STOP 0x8000 +#define CPU_DSW_INT_RUN 0x4000 /* prototypes: xio handlers */ @@ -205,20 +262,28 @@ t_stat load_cr_boot (int drv); t_stat cr_boot (int unitno); void calc_ints (void); /* recalculate interrupt bitmask */ void trace_io (char *fmt, ...); /* debugging printout */ -void panic (char *msg); /* bail out of simulator */ +void scp_panic (char *msg); /* bail out of simulator */ char *upcase(char *str); - -/* GUI interface routines */ +void break_simulation (t_stat reason); /* let a device halt the simulation */ +char hollerith_to_ascii (int16 hol); /* for debugging use only */ +t_bool gdu_active (void); void remark_cmd (char *remark); void stuff_cmd (char *cmd); +void update_gui (t_bool force); +void sim_init (void); +t_stat register_cmd (char *name, t_stat (*action)(), int arg, char *help); + +/* GUI interface routines */ t_bool keyboard_is_locked (void); void forms_check (int set); /* device notification to console lamp display */ void print_check (int set); void keyboard_selected (int select); void disk_ready (int ready); void disk_unlocked (int unlocked); +void gui_run(int running); +char *read_cmdline (char *ptr, int size, FILE *stream); -#ifdef ENABLE_GUI +#ifdef GUI_SUPPORT # define GUI_BEGIN_CRITICAL_SECTION begin_critical_section(); # define GUI_END_CRITICAL_SECTION end_critical_section(); void begin_critical_section (void); diff --git a/Ibm1130/ibm1130_disk.c b/Ibm1130/ibm1130_disk.c index 9e7dad99..23c56fd0 100644 --- a/Ibm1130/ibm1130_disk.c +++ b/Ibm1130/ibm1130_disk.c @@ -5,37 +5,39 @@ computed from current conditions when requested by an XIO load status command; the value of DSW available to the simulator's examine & save commands may NOT be accurate. This should probably be fixed. - Copyright (c) 2002, Brian Knittel - Based on PDP-11 simulator written by Robert M Supnik + Based on the SIMH package written by Robert M Supnik - Revision History - - 31July2001 - Derived from pdp11_stddev.c, which carries this disclaimer: - Copyright (c) 1993-2001, Robert M Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. -*/ + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org + * + * Revision History + * 01-sep-02 corrected treatment of -m and -r flags in dsk_attach + * in cgi mode, so that file is opened readonly but emulated + * disk is writable. + * + */ #include "ibm1130_defs.h" +#include "memory.h" + +#define TRACE_DMS_IO // define to enable debug of DMS phase IO + +#ifdef TRACE_DMS_IO +extern int32 sim_switches; +extern int32 sim_quiet; +static int trace_dms = 0; +static void tracesector (int iswrite, int nwords, int addr, int sector); +static t_stat where_cmd (int flag, char *ptr); +static t_stat phdebug_cmd (int flag, char *ptr); +static t_stat fdump_cmd (int flags, char *cptr); +static void enable_dms_tracing (int newsetting); +#endif /* Constants */ @@ -54,10 +56,11 @@ commands may NOT be accurate. This should probably be fixed. #define UNIT_OPERR (1u << UNIT_V_OPERR) #define UNIT_HARDERR (1u << UNIT_V_HARDERR) -static int16 dsk_dsw[DSK_NUMDR] = {0}; /* device status words */ -static int16 dsk_sec[DSK_NUMDR] = {0}; /* next-sector-up */ -int32 dsk_swait = 10; /* seek time */ -int32 dsk_rwait = 10; /* rotate time */ +#define MEM_MAPPED(uptr) (uptr->flags & UNIT_BUF) /* disk buffered in memory */ + +#define IO_NONE 0 /* last operation, used to ensure fseek between read and write */ +#define IO_READ 1 +#define IO_WRITE 2 #define DSK_DSW_DATA_ERROR 0x8000 /* device status word bits */ #define DSK_DSW_OP_COMPLETE 0x4000 @@ -65,7 +68,14 @@ int32 dsk_rwait = 10; /* rotate time */ #define DSK_DSW_DISK_BUSY 0x1000 #define DSK_DSW_CARRIAGE_HOME 0x0800 #define DSK_DSW_SECTOR_MASK 0x0003 - + + /* device status words */ +static int16 dsk_dsw[DSK_NUMDR] = {DSK_DSW_NOT_READY, DSK_DSW_NOT_READY, DSK_DSW_NOT_READY, DSK_DSW_NOT_READY, DSK_DSW_NOT_READY}; +static int16 dsk_sec[DSK_NUMDR] = {0}; /* next-sector-up */ +static char dsk_lastio[DSK_NUMDR]; /* last stdio operation: IO_READ or IO_WRITE */ +int32 dsk_swait = 50; /* seek time -- see how short a delay we can get away with */ +int32 dsk_rwait = 50; /* rotate time */ + static t_stat dsk_svc (UNIT *uptr); static t_stat dsk_reset (DEVICE *dptr); static t_stat dsk_attach (UNIT *uptr, char *cptr); @@ -152,6 +162,8 @@ static int32 dsk_ilswlevel[DSK_NUMDR] = * 15-16: number of next sector spinning into position. */ +extern void void_backtrace (int afrom, int ato); + void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv) { int i, rev, nsteps, newcyl, sec, nwords; @@ -162,8 +174,9 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv) if (! BETWEEN(drv, 0, DSK_NUMDR-1)) { // hmmm, invalid drive */ if (func != XIO_SENSE_DEV) { // tried to use it, too - sprintf(msg, "Op %x on invalid drive number %d", func, drv); - xio_error(msg); + // just do nothing, as if the controller isn't there. NAMCRA at N0116300 tests for drives by attempting reads +// sprintf(msg, "Op %x on invalid drive number %d", func, drv); +// xio_error(msg); } return; } @@ -185,7 +198,6 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv) if (nwords == 0) /* this is bad -- locks up disk controller ! */ break; - nwords &= 1023; /* sanity check */ if (! BETWEEN(nwords, 1, DSK_NUMWD)) { /* count bad */ SETBIT(uptr->flags, UNIT_OPERR); /* set data error DSW bit when op complete */ nwords = DSK_NUMWD; /* limit xfer to proper sector size */ @@ -195,20 +207,43 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv) if ((modify & 0x0080) == 0) { /* it's real if not a read check */ newpos = (uptr->CYL*DSK_NUMSC*DSK_NUMSF + sec)*2*DSK_NUMWD; - if (uptr->pos != newpos) - fseek(uptr->fileref, newpos, SEEK_SET); - - fread(buf, 2, DSK_NUMWD, uptr->fileref); // read whole sector so we're in position for next read - uptr->pos = newpos + 2*DSK_NUMWD; - trace_io("* DSK%d read %d words from %d.%d (%x) to M[%04x-%04x]", uptr-dsk_unit, nwords, uptr->CYL, sec, newpos, iocc_addr & mem_mask, + if (MEM_MAPPED(uptr)) { + memcpy(buf, (char *) uptr->filebuf + newpos, 2*DSK_NUMWD); + } + else { + if (uptr->pos != newpos || dsk_lastio[drv] != IO_READ) { + fseek(uptr->fileref, newpos, SEEK_SET); + dsk_lastio[drv] = IO_READ; + } + fxread(buf, 2, DSK_NUMWD, uptr->fileref); // read whole sector so we're in position for next read + uptr->pos = newpos + 2*DSK_NUMWD; + } + + void_backtrace(iocc_addr, iocc_addr + nwords - 1); // mark prev instruction as altered + + trace_io("* DSK%d read %d words from %d.%d (%x, %x) to M[%04x-%04x]", drv, nwords, uptr->CYL, sec, uptr->CYL*8 + sec, newpos, iocc_addr & mem_mask, (iocc_addr + nwords - 1) & mem_mask); - + +// // this will help debug the monitor by letting me watch phase loading +// if (nwords >= 3) +// printf("* DSK%d XIO @ %04x read %d words from %d.%d (%x, %x) to M[%04x-%04x]\n", drv, prev_IAR, nwords, uptr->CYL, sec, uptr->CYL*8 + sec, newpos, iocc_addr & mem_mask, +// (iocc_addr + nwords - 1) & mem_mask); + + i = uptr->CYL*8 + sec; + if (buf[0] != i) + printf("*DSK read bad sector#\n"); + for (i = 0; i < nwords; i++) - M[iocc_addr++ & mem_mask] = buf[i]; + M[(iocc_addr+i) & mem_mask] = buf[i]; + +#ifdef TRACE_DMS_IO + if (trace_dms) + tracesector(0, nwords, iocc_addr & mem_mask, uptr->CYL*8 + sec); +#endif } else - trace_io("* DSK%d verify %d.%d", uptr-dsk_unit, uptr->CYL, sec); + trace_io("* DSK%d verify %d.%d (%x)", drv, uptr->CYL, sec, uptr->CYL*8 + sec); uptr->FUNC = func; sim_activate(uptr, dsk_rwait); @@ -234,7 +269,6 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv) if (nwords == 0) /* this is bad -- locks up disk controller ! */ break; - nwords &= 1023; /* sanity check */ if (! BETWEEN(nwords, 1, DSK_NUMWD)) { /* count bad */ SETBIT(uptr->flags, UNIT_OPERR); /* set data error DSW bit when op complete */ nwords = DSK_NUMWD; /* limit xfer to proper sector size */ @@ -242,19 +276,38 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv) sec = modify & 0x07; /* get sector on cylinder */ newpos = (uptr->CYL*DSK_NUMSC*DSK_NUMSF + sec)*2*DSK_NUMWD; - if (uptr->pos != newpos) - fseek(uptr->fileref, newpos, SEEK_SET); - - trace_io("* DSK%d wrote %d words from M[%04x-%04x] to %d.%d (%x)", uptr-dsk_unit, nwords, iocc_addr & mem_mask, (iocc_addr + nwords - 1) & mem_mask, uptr->CYL, sec, newpos); + trace_io("* DSK%d wrote %d words from M[%04x-%04x] to %d.%d (%x, %x)", drv, nwords, iocc_addr & mem_mask, (iocc_addr + nwords - 1) & mem_mask, uptr->CYL, sec, uptr->CYL*8 + sec, newpos); + +// printf("* DSK%d XIO @ %04x wrote %d words from M[%04x-%04x] to %d.%d (%x, %x)\n", drv, prev_IAR, nwords, iocc_addr & mem_mask, (iocc_addr + nwords - 1) & mem_mask, uptr->CYL, sec, uptr->CYL*8 + sec, newpos); + +#ifdef TRACE_DMS_IO + if (trace_dms) + tracesector(1, nwords, iocc_addr & mem_mask, uptr->CYL*8 + sec); +#endif for (i = 0; i < nwords; i++) buf[i] = M[iocc_addr++ & mem_mask]; for (; i < DSK_NUMWD; i++) /* rest of sector gets zeroed */ buf[i] = 0; - fwrite(buf, 2, DSK_NUMWD, uptr->fileref); - uptr->pos = newpos + 2*DSK_NUMWD; + i = uptr->CYL*8 + sec; + if (buf[0] != i) + printf("*DSK writing bad sector#\n"); + + if (MEM_MAPPED(uptr)) { + memcpy((char *) uptr->filebuf + newpos, buf, 2*DSK_NUMWD); + uptr->hwmark = newpos + 2*DSK_NUMWD; + } + else { + if (uptr->pos != newpos || dsk_lastio[drv] != IO_WRITE) { + fseek(uptr->fileref, newpos, SEEK_SET); + dsk_lastio[drv] = IO_WRITE; + } + + fxwrite(buf, 2, DSK_NUMWD, uptr->fileref); + uptr->pos = newpos + 2*DSK_NUMWD; + } uptr->FUNC = func; sim_activate(uptr, dsk_rwait); @@ -284,7 +337,7 @@ void xio_disk (int32 iocc_addr, int32 func, int32 modify, int drv) sim_activate(uptr, dsk_swait); /* schedule interrupt */ dsk_dsw[drv] |= DSK_DSW_DISK_BUSY; - trace_io("* DSK%d at cyl %d", uptr-dsk_unit, newcyl); + trace_io("* DSK%d at cyl %d", drv, newcyl); break; case XIO_SENSE_DEV: @@ -360,6 +413,14 @@ t_stat dsk_reset (DEVICE *dptr) int drv; UNIT *uptr; +#ifdef TRACE_DMS_IO + // add the WHERE command. It finds the phase that was loaded at given address and indicates + // the offset in the phase + register_cmd("WHERE", &where_cmd, 0, "w{here} address find phase and offset of an address\n"); + register_cmd("PHDEBUG", &phdebug_cmd, 0, "ph{debug} off|phlo phhi break on phase load\n"); + register_cmd("FDUMP", &fdump_cmd, 0, NULL); +#endif + for (drv = 0, uptr = dsk_dev.units; drv < DSK_NUMDR; drv++, uptr++) { sim_cancel(uptr); @@ -381,24 +442,44 @@ static t_stat dsk_attach (UNIT *uptr, char *cptr) int drv = uptr - dsk_unit; t_stat rval; - sim_cancel(uptr); + sim_cancel(uptr); // cancel current IO + dsk_lastio[drv] = IO_NONE; - if ((rval = attach_unit(uptr, cptr)) != SCPE_OK) - return rval; + if (uptr->flags & UNIT_ATT) // dismount current disk + if ((rval = dsk_detach(uptr)) != SCPE_OK) + return rval; - CLRBIT(ILSW[2], dsk_ilswbit[drv]); - CLRBIT(uptr->flags, UNIT_OPERR|UNIT_HARDERR); - calc_ints(); - - uptr->CYL = 0; + uptr->CYL = 0; // reset the device uptr->FUNC = -1; dsk_dsw[drv] = DSK_DSW_CARRIAGE_HOME; + CLRBIT(uptr->flags, UNIT_RO|UNIT_ROABLE|UNIT_BUFABLE|UNIT_BUF|UNIT_RONLY|UNIT_OPERR|UNIT_HARDERR); + CLRBIT(ILSW[2], dsk_ilswbit[drv]); + calc_ints(); + + if (sim_switches & SWMASK('M')) // if memory mode (e.g. for CGI), buffer the file + SETBIT(uptr->flags, UNIT_BUFABLE); + + if (sim_switches & SWMASK('R')) // read lock mode + SETBIT(uptr->flags, UNIT_RO|UNIT_ROABLE|UNIT_RONLY); + + if (cgi && (sim_switches & SWMASK('M'))) { // if cgi and memory mode, + sim_switches |= SWMASK('R'); // have attach_unit open file in readonly mode + SETBIT(uptr->flags, UNIT_ROABLE|UNIT_MUSTBUF); // but don't set the UNIT_RONLY flag so DMS can write to the buffered image + } + + if ((rval = attach_unit(uptr, cptr)) != SCPE_OK) { // mount new disk + SETBIT(dsk_dsw[drv], DSK_DSW_NOT_READY); + return rval; + } + if (drv == 0) { disk_ready(TRUE); disk_unlocked(FALSE); } + enable_dms_tracing(sim_switches & SWMASK('D')); + return SCPE_OK; } @@ -416,9 +497,9 @@ static t_stat dsk_detach (UNIT *uptr) CLRBIT(uptr->flags, UNIT_OPERR|UNIT_HARDERR); calc_ints(); - uptr->CYL = 0; - uptr->FUNC = -1; - dsk_dsw[drv] = 0; + uptr->CYL = 0; + uptr->FUNC = -1; + dsk_dsw[drv] = DSK_DSW_NOT_READY; if (drv == 0) { disk_unlocked(TRUE); @@ -439,3 +520,310 @@ static t_stat dsk_boot (int unitno) return load_cr_boot(unitno); } + +#ifdef TRACE_DMS_IO + +static struct { + int phid; + char *name; +} phase[] = { +# include "dmsr2v12phases.h" + 0xFFFF, "" +}; + +#pragma pack(2) +#define MAXSLET ((3*320)/4) +struct tag_slet { + int16 phid; + int16 addr; + int16 nwords; + int16 sector; +} slet[MAXSLET] = { +# include "dmsr2v12slet.h" // without RPG, use this info until overwritten by actual data from disk +}; + +#pragma pack() + +#define MAXMSEG 100 +struct tag_mseg { + char *name; + int addr, offset, len, phid; +} mseg[MAXMSEG]; +int nseg = 0; + +static void enable_dms_tracing (int newsetting) +{ + nseg = 0; // clear the segment map + + if ((newsetting && trace_dms) || ! (newsetting || trace_dms)) + return; + + trace_dms = newsetting; + if (! sim_quiet) + printf("DMS disk tracing is now %sabled\n", trace_dms ? "en" : "dis"); +} + +char * saywhere (int addr) +{ + int i; + static char buf[150]; + + for (i = 0; i < nseg; i++) { + if (addr >= mseg[i].addr && addr < (mseg[i].addr+mseg[i].len)) { + sprintf(buf, "/%04x = /%04x + /%x in ", addr, mseg[i].addr - mseg[i].offset, addr-mseg[i].addr + mseg[i].offset); + if (mseg[i].phid > 0) + sprintf(buf+strlen(buf), "phase %02x (%s)", mseg[i].phid, mseg[i].name); + else + sprintf(buf+strlen(buf), "%s", mseg[i].name); + + return buf; + } + } + return NULL; +} + +static int phdebug_lo = -1, phdebug_hi = -1; + +static t_stat phdebug_cmd (int flag, char *ptr) +{ + int val1, val2; + + if (strcmpi(ptr, "off") == 0) + phdebug_lo = phdebug_hi = -1; + else { + switch(sscanf(ptr, "%x%x", &val1, &val2)) { + case 1: + phdebug_lo = phdebug_hi = val1; + enable_dms_tracing(TRUE); + break; + + case 2: + phdebug_lo = val1; + phdebug_hi = val2; + enable_dms_tracing(TRUE); + break; + + default: + printf("Usage: phdebug off | phdebug phfrom [phto]\n"); + break; + } + } + return SCPE_OK; +} + +static t_stat where_cmd (int flag, char *ptr) +{ + int addr; + char *where; + + if (! trace_dms) { + printf("Tracing is disabled. To enable, attach disk with -d switch\n"); + return SCPE_OK; + } + + if (sscanf(ptr, "%x", &addr) != 1) + return SCPE_ARG; + + if ((where = saywhere(addr)) == NULL) + printf("/%04x not found\n", addr); + else + printf("%s\n", where); + + return SCPE_OK; +} + +// savesector - save info on a sector just read. THIS IS NOT YET TESTED + +static void addseg (int i) +{ + if (! trace_dms) + return; + + if (nseg >= MAXMSEG) { + printf("(Memory map full, disabling tracing)\n"); + trace_dms = 0; + nseg = -1; + return; + } + memcpy(mseg+i+1, mseg+i, (nseg-i)*sizeof(mseg[0])); + nseg++; +} + +static void delseg (int i) +{ + if (! trace_dms) + return; + + if (nseg > 0) { + nseg--; + memcpy(mseg+i, mseg+i+1, (nseg-i)*sizeof(mseg[0])); + } +} + +static void savesector (int addr, int offset, int len, int phid, char *name) +{ + int i; + + if (! trace_dms) + return; + + addr++; // first word is sector address, so account for that + len--; + + for (i = 0; i < nseg; i++) { + if (addr >= (mseg[i].addr+mseg[i].len)) // entirely after this entry + continue; + + if (mseg[i].addr < addr) { // old one starts before this. split it + addseg(i); + mseg[i].len = addr-mseg[i].addr; + i++; + mseg[i].addr = addr; + mseg[i].len -= mseg[i-1].len; + } + + break; + } + + addseg(i); // add new segment. Old one ends up after this + + if (i >= MAXMSEG) + return; + + mseg[i].addr = addr; + mseg[i].offset = offset; + mseg[i].phid = phid; + mseg[i].len = len; + mseg[i].name = name; + + i++; // delete any segments completely covered + + while (i < nseg && (mseg[i].addr+mseg[i].len) <= (addr+len)) + delseg(i); + + if (i < nseg && mseg[i].addr < (addr+len)) { // old one extends past this. Retain the end + mseg[i].len = (mseg[i].addr+mseg[i].len) - (addr+len); + mseg[i].addr = addr+len; + } +} + +static void tracesector (int iswrite, int nwords, int addr, int sector) +{ + int i, phid = 0, sletind = -1, offset = 0; + char *name = NULL; + + if (nwords < 3 || ! trace_dms) + return; + + switch (sector) { // explicitly known sector name + case 0: name = "ID/COLD START"; break; + case 1: name = "DCOM"; break; + case 2: name = "RESIDENT IMAGE"; break; + case 3: + case 4: + case 5: name = "SLET"; // save just-read or written SLET info + memmove(&slet[(320/4)*(sector-3)], &M[addr+1], nwords*2); + break; + case 6: name = "RELOAD TABLE"; break; + case 7: name = "PAGE HEADER"; break; + } + + printf("* %04x: %3d /%04x %c %3d.%d ", + prev_IAR, nwords, addr, iswrite ? '>' : '<', sector/8, sector%8); + + if (name == NULL) { // look up sector in SLET + for (i = 0; i < MAXSLET; i++) { + if (slet[i].phid == 0) // not found + goto done; + else if (slet[i].sector > sector) { + if (--i >= 0) { + if (sector >= slet[i].sector && sector <= (slet[i].sector + slet[i].nwords/320)) { + phid = slet[i].phid; + offset = (sector-slet[i].sector)*320; + break; + } + } + goto done; + } + if (slet[i].sector == sector) { + phid = slet[i].phid; // we found the starting sector + break; + } + } + + if (i >= MAXSLET) // was not found + goto done; + + name = "?"; + for (i = sizeof(phase)/sizeof(phase[0]); --i >= 0; ) { + if (phase[i].phid == phid) { // look up name + name = phase[i].name; + break; + } + } + printf("%02x %s", phid, name); + } + else + printf("%s", name); + +done: + putchar('\n'); + + if (phid >= phdebug_lo && phid <= phdebug_hi && offset == 0) + break_simulation(STOP_PHASE_BREAK); // break on read of first sector of indicated phases + + if (name != NULL && *name != '?' && ! iswrite) + savesector(addr, offset, nwords, phid, name); +} + +static t_stat fdump_cmd (int flags, char *cptr) +{ + int addr = 0x7a24; // address of next statement; + int sofst = 0x7a26, symaddr; + int cword, nwords, stype, has_stnum, strel = 1, laststno = 0; + + addr = M[addr & mem_mask] & mem_mask; // get address of first statement + sofst = M[sofst & mem_mask] & mem_mask; // get address of symbol table + + for (;;) { + cword = M[addr]; + nwords = (cword >> 2) & 0x01FF; + stype = (cword >> 1) & 0x7C00; + has_stnum = (cword & 1); + + if (has_stnum) { + laststno++; + strel = 0; + } + + printf("/%04x [%4d +%3d] %3d - %04x", addr, laststno, strel, nwords, stype); + + if (has_stnum) { + addr++; + nwords--; + symaddr = sofst - (M[addr] & 0x7FF)*3 + 3; + printf(" [%04x %04x %04x]", M[symaddr], M[symaddr+1], M[symaddr+2]); + } + + if (stype == 0x5000) { // error record + printf(" (err %d)", M[addr+1]); + } + + if (stype == 0x0800) + break; + + addr += nwords; + putchar('\n'); + + if (nwords == 0) { + printf("0 words?\n"); + break; + } + strel++; + } + + printf("\nEnd found at /%04x, EOFS = /%04x\n", addr, M[0x7a25 & mem_mask]); + return SCPE_OK; +} + +#endif // TRACE_DMS_IO diff --git a/Ibm1130/ibm1130_gdu.c b/Ibm1130/ibm1130_gdu.c new file mode 100644 index 00000000..2a1a155f --- /dev/null +++ b/Ibm1130/ibm1130_gdu.c @@ -0,0 +1,1118 @@ +#include "ibm1130_defs.h" + +/* ibm1130_gdu.c: IBM 1130 2250 Graphical Display Unit + + (Under construction) +// stuff to fix: +// "store revert" might be backwards? +// alpha keyboard is not implemented +// pushbuttons are not implemented +// there is something about interrupts being deferred during a subroutine transition? + + Based on the SIMH package written by Robert M Supnik + + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org + */ + +#define BLIT_MODE // normally defined, undefine when debugging generate_image() +//#define DEBUG_LIGHTPEN // normally undefined, define to visualize light-pen sensing + +#define DEFAULT_GDU_RATE 20 // default frame rate +#define DEFAULT_PEN_THRESHOLD 3 // default looseness of light-pen hit +#define INDWIDTH 32 // width of an indicator (there are two columns of these) +#define INITSIZE 512 // initial window size + +#define GDU_DSW_ORDER_CONTROLLED_INTERRUPT 0x8000 +#define GDU_DSW_KEYBOARD_INTERUPT 0x4000 +#define GDU_DSW_DETECT_INTERRUPT 0x2000 +#define GDU_DSW_CYCLE_STEAL_CHECK 0x1000 +#define GDU_DSW_DETECT_STATUS 0x0800 +#define GDU_DSW_LIGHT_PEN_SWITCH 0x0100 +#define GDU_DSW_BUSY 0x0080 +#define GDU_DSW_CHARACTER_MODE 0x0040 +#define GDU_DSW_POINT_MODE 0x0020 +#define GDU_DSW_ADDR_DISP 0x0003 + +#define GDU_FKEY_DATA_AVAILABLE 0x8000 +#define GDU_FKEY_KEY_CODE 0x1F00 +#define GDU_FKEY_OVERLAY_CODE 0x00FF + +#define GDU_AKEY_DATA_AVAILABLE 0x8000 +#define GDU_AKEY_END 0x1000 +#define GDU_AKEY_CANCEL 0x0800 +#define GDU_AKEY_ADVANCE 0x0400 +#define GDU_AKEY_BACKSPACE 0x0200 +#define GDU_AKEY_JUMP 0x0100 +#define GDU_AKEY_KEY_CODE 0x00FF + +/* -------------------------------------------------------------------------------------- */ + +#define UNIT_V_DISPLAYED (UNIT_V_UF + 0) +#define UNIT_V_DETECTS_ENABLED (UNIT_V_UF + 1) +#define UNIT_V_INTERRUPTS_DEFERRED (UNIT_V_UF + 2) +#define UNIT_V_LARGE_CHARS (UNIT_V_UF + 3) + +#define UNIT_DISPLAYED (1u << UNIT_V_DISPLAYED) /* display windows is up */ +#define UNIT_DETECTS_ENABLED (1u << UNIT_V_DETECTS_ENABLED) /* light pen detects are enabled */ +#define UNIT_INTERRUPTS_DEFERRED (1u << UNIT_V_INTERRUPTS_DEFERRED) /* light pen interrupts are deferred */ +#define UNIT_LARGE_CHARS (1u << UNIT_V_LARGE_CHARS) /* large character mode */ + +static t_stat gdu_reset (DEVICE *dptr); + +static int16 gdu_dsw = 1; /* device status word */ +static int16 gdu_ar = 0; /* address register */ +static int16 gdu_x = 0; /* X deflection */ +static int16 gdu_y = 0; /* Y deflection */ +static int16 gdu_fkey = 0; /* function keyboard register */ +static int16 gdu_akey = 0; /* alphanumeric keyboard register */ +static int16 gdu_revert = 0; /* revert address register */ +static int32 gdu_indicators = 0; /* programmed indicator lamps */ +static int32 gdu_threshold = DEFAULT_PEN_THRESHOLD; /* mouse must be within 3/1024 of line to be a hit */ +static int32 gdu_rate = DEFAULT_GDU_RATE; /* refresh rate. 0 = default */ + +UNIT gdu_unit = { UDATA (NULL, 0, 0) }; + +REG gdu_reg[] = { + { HRDATA (GDUDSW, gdu_dsw, 16) }, /* device status word */ + { HRDATA (GDUAR, gdu_ar, 16) }, /* address register */ + { HRDATA (GDUXREG, gdu_x, 16) }, /* X deflection register */ + { HRDATA (GDUYREG, gdu_y, 16) }, /* Y deflection register */ + { HRDATA (GDUFKEY, gdu_fkey, 16) }, /* function keyboard register */ + { HRDATA (GDUAKEY, gdu_akey, 16) }, /* alphanumeric keyboard register */ + { HRDATA (GDUREVERT,gdu_revert, 16) }, /* revert address register */ + { HRDATA (GDUAKEY, gdu_indicators, 32) }, /* programmed indicators */ + { DRDATA (GDUTHRESH,gdu_threshold, 32) }, /* mouse closeness threshhold */ + { DRDATA (GDURATE, gdu_rate, 32) }, /* refresh rate in frames/sec */ + { NULL } }; + +DEVICE gdu_dev = { + "GDU", &gdu_unit, gdu_reg, NULL, + 1, 16, 16, 1, 16, 16, + NULL, NULL, gdu_reset, + NULL, NULL, NULL}; + +/* -------------------------------------------------------------------------------------- */ + +#ifndef GUI_SUPPORT + +static t_stat gdu_reset (DEVICE *dptr) +{ + return SCPE_OK; +} + +void xio_2250_display (int32 addr, int32 func, int32 modify) +{ + // ignore commands to nonexistent device +} + +t_bool gdu_active (void) +{ + return 0; +} + +/* -------------------------------------------------------------------------------------- */ +#else // GUI_SUPPORT defined + +/******* PLATFORM INDEPENDENT CODE ********************************************************/ + +static int32 gdu_instaddr; // address of first word of instruction +static int xmouse, ymouse, lpen_dist, lpen_dist2; // current mouse pointer, scaled closeness threshhold, same squared +static double sfactor; // current scaling factor +static t_bool last_abs = TRUE; // last positioning instruction was absolute +static t_bool mouse_present = FALSE; // mouse is/is not in the window + +static void clear_interrupts (void); +static void set_indicators (int32 new_inds); +static void start_regeneration (void); +static void halt_regeneration (void); +static void draw_characters (void); +static void notify_window_closed (void); + +// routines that must be implemented per-platform + +static void DrawLine(int x0, int y0, int x1, int y1); +static void DrawPoint(int x, int y); +static void CheckGDUKeyboard(void); +static t_bool CreateGDUWindow(void); +static void StartGDUUpdates(void); +static void StopGDUUpdates(void); +static void GetMouseCoordinates(void); +static void UpdateGDUIndicators(void); +static void ShowPenHit (int x, int y); +static void EraseGDUScreen (void); + +/* -------------------------------------------------------------------------------------- */ + +void xio_2250_display (int32 addr, int32 func, int32 modify) +{ + switch (func) { + case XIO_SENSE_DEV: + ACC = (gdu_dsw & GDU_DSW_BUSY) ? GDU_DSW_BUSY : gdu_dsw; + if (modify & 1) + clear_interrupts(); + break; + + case XIO_READ: /* store status data into word pointed to by IOCC packet */ + if (gdu_dsw & GDU_DSW_BUSY) /* not permitted while device is busy */ + break; + + WriteW(addr, gdu_ar); /* save status information */ + WriteW(addr+1, gdu_dsw); + WriteW(addr+2, gdu_x & 0x7FF); + WriteW(addr+3, gdu_y & 0x7FF); + WriteW(addr+4, gdu_fkey); + WriteW(addr+5, gdu_akey); + gdu_ar = addr+6; /* this alters the channel address register? */ + + clear_interrupts(); /* read status clears the interrupts */ + break; + + case XIO_WRITE: + if (gdu_dsw & GDU_DSW_BUSY) /* treated as no-op if display is busy */ + break; + + if (modify & 0x80) { /* bit 8 on means set indicators, 0 means start regeneration */ + set_indicators((ReadW(addr) << 16) | ReadW(addr+1)); + } + else { + gdu_ar = addr; + gdu_fkey = 0; + gdu_akey = 0; + clear_interrupts(); + start_regeneration(); + } + break; + + case XIO_CONTROL: + if (modify & 0x80) { /* bit 8 on means reset, off is no-op */ + gdu_reset(&gdu_dev); + set_indicators((addr << 16) | addr); + } + break; + + default: /* all other commands are no-ops */ + break; + } +} + +static t_stat gdu_reset (DEVICE *dptr) +{ + halt_regeneration(); + clear_interrupts(); + set_indicators(0); + gdu_x = gdu_y = 512; + CLRBIT(gdu_unit.flags, UNIT_INTERRUPTS_DEFERRED | UNIT_DETECTS_ENABLED | UNIT_LARGE_CHARS); + gdu_dsw = 1; + return SCPE_OK; +} + +static void clear_interrupts (void) +{ + CLRBIT(gdu_dsw, GDU_DSW_ORDER_CONTROLLED_INTERRUPT | GDU_DSW_KEYBOARD_INTERUPT | GDU_DSW_DETECT_INTERRUPT); + CLRBIT(ILSW[3], ILSW_3_2250_DISPLAY); + calc_ints(); +} + +static void gdu_interrupt (int32 dswbit) +{ + SETBIT(gdu_dsw, dswbit); + SETBIT(ILSW[3], ILSW_3_2250_DISPLAY); + calc_ints(); + halt_regeneration(); +} + +static void set_indicators (int32 new_inds) +{ + gdu_indicators = new_inds; + if (gdu_unit.flags & UNIT_DISPLAYED) + UpdateGDUIndicators(); +} + +static void start_regeneration (void) +{ + SETBIT(gdu_dsw, GDU_DSW_BUSY); + + if (gdu_unit.flags & UNIT_DISPLAYED) { + StartGDUUpdates(); + } + else { + if (! CreateGDUWindow()) + return; + SETBIT(gdu_unit.flags, UNIT_DISPLAYED); + } +} + +static void halt_regeneration (void) +{ + if (gdu_dsw & GDU_DSW_BUSY) { + StopGDUUpdates(); + CLRBIT(gdu_dsw, GDU_DSW_BUSY); + } + EraseGDUScreen(); +} + +static void notify_window_closed (void) +{ + if (gdu_dsw & GDU_DSW_BUSY) { + StopGDUUpdates(); + CLRBIT(gdu_dsw, GDU_DSW_BUSY); + } + CLRBIT(gdu_unit.flags, UNIT_DISPLAYED); + gdu_reset(&gdu_dev); +} + +static int32 read_gduword (void) +{ + int32 w; + + w = M[gdu_ar++ & mem_mask]; + gdu_dsw = (gdu_dsw & ~GDU_DSW_ADDR_DISP) | ((gdu_ar - gdu_instaddr) & GDU_DSW_ADDR_DISP); + + return w; +} + +#define DIST2(x0,y0,x1,y1) (((x1)-(x0))*((x1)-(x0))+((y1)-(y0))*((y1)-(y0))) + +static void draw (int32 newx, int32 newy, t_bool beam) +{ + int xmin, xmax, ymin, ymax, xd, yd; + double s; + int hit = FALSE; + + if (beam) { + if (gdu_dsw & GDU_DSW_POINT_MODE) { + DrawPoint(newx, newy); + +#ifdef DEBUG_LIGHTPEN + if (DIST2(newx, newy, xmouse, ymouse) <= lpen_dist2) + hit = TRUE; +#else + if (gdu_unit.flags & UNIT_DETECTS_ENABLED && mouse_present) + if (DIST2(newx, newy, xmouse, ymouse) <= lpen_dist2) + hit = TRUE; +#endif + } + else { + DrawLine(gdu_x, gdu_y, newx, newy); + + // calculate proximity of light pen to the line +#ifndef DEBUG_LIGHTPEN + if (gdu_unit.flags & UNIT_DETECTS_ENABLED && mouse_present) { +#endif + if (gdu_x <= newx) + xmin = gdu_x, xmax = newx; + else + xmin = newx, xmax = gdu_x; + + if (gdu_y <= newy) + ymin = gdu_y, ymax = newy; + else + ymin = newy, ymax = gdu_y; + + if (newx == gdu_x) { + // line is vertical. Nearest point is an endpoint if the mouse is above or + // below the line segment, otherwise the segment point at the same y as the mouse + xd = gdu_x; + yd = (ymouse <= ymin) ? ymin : (ymouse >= ymax) ? ymax : ymouse; + + if (DIST2(xd, yd, xmouse, ymouse) <= lpen_dist2) + hit = TRUE; + } + else if (newy == gdu_y) { + // line is horizontal. Nearest point is an endpoint if the mouse is to the left or + // the right of the line segment, otherwise the segment point at the same x as the mouse + xd = (xmouse <= xmin) ? xmin : (xmouse >= xmax) ? xmax : xmouse; + yd = gdu_y; + + if (DIST2(xd, yd, xmouse, ymouse) <= lpen_dist2) + hit = TRUE; + } + else { + // line is diagonal. See if the mouse is inside the box lpen_dist wider than the line segment's bounding rectangle + if (xmouse >= (xmin-lpen_dist) && xmouse <= (xmax+lpen_dist) && ymouse >= (ymin-lpen_dist) || ymouse <= (ymax+lpen_dist)) { + // compute the point at the intersection of the line through the line segment and the normal + // to that line through the mouse. This is the point on the line through the line segment + // nearest the mouse + + s = (double)(newy - gdu_y) / (double)(newx - gdu_x); // slope of line segment + xd = (int) ((ymouse + xmouse/s - gdu_y + s*gdu_x) / (s + 1./s) + 0.5); + + // if intersection is beyond either end of the line segment, the nearest point to the + // mouse is nearest segment end, otherwise it's the computed intersection point + if (xd < xmin || xd > xmax) { +#ifdef DEBUG_LIGHTPEN + // if it's a hit, set xd and yd so we can display the hit + if (DIST2(gdu_x, gdu_y, xmouse, ymouse) <= lpen_dist2) { + hit = TRUE; + xd = gdu_x; + yd = gdu_y; + } + else if (DIST2(newx, newy, xmouse, ymouse) <= lpen_dist2) { + hit = TRUE; + xd = newx; + yd = newy; + } +#else + if (DIST2(gdu_x, gdu_y, xmouse, ymouse) <= lpen_dist2 || DIST2(newx, newy, xmouse, ymouse) <= lpen_dist2) + hit = TRUE; +#endif + } + else { + yd = (int) (gdu_y + s*(xd - gdu_x) + 0.5); + if (DIST2(xd, yd, xmouse, ymouse) <= lpen_dist2) + hit = TRUE; + } + } + } +#ifndef DEBUG_LIGHTPEN + } +#endif + } + } + + if (hit) { +#ifdef DEBUG_LIGHTPEN + ShowPenHit(xd, yd); + if (gdu_unit.flags & UNIT_DETECTS_ENABLED && mouse_present) + SETBIT(gdu_dsw, GDU_DSW_DETECT_STATUS); +#else + SETBIT(gdu_dsw, GDU_DSW_DETECT_STATUS); +#endif + } + + gdu_x = newx; + gdu_y = newy; +} + +static void generate_image (void) +{ + int32 instr, new_addr, newx, newy; + t_bool run = TRUE, accept; + + if (! (gdu_dsw & GDU_DSW_BUSY)) + return; + + GetMouseCoordinates(); + + lpen_dist = (int) (gdu_threshold/sfactor + 0.5); // mouse-to-line threshhold at current scaling factor + lpen_dist2 = lpen_dist * lpen_dist; + + while (run) { + if ((gdu_dsw & GDU_DSW_DETECT_STATUS) && ! (gdu_unit.flags & UNIT_INTERRUPTS_DEFERRED)) { + CLRBIT(gdu_dsw, GDU_DSW_DETECT_STATUS); // clear when interrupt is activated + gdu_interrupt(GDU_DSW_DETECT_INTERRUPT); + run = FALSE; + break; + } + + gdu_instaddr = gdu_ar; // remember address of GDU instruction + instr = read_gduword(); // fetch instruction (and we really are cycle stealing here!) + + switch ((instr >> 12) & 0xF) { // decode instruction + case 0: // short branch + case 1: + gdu_revert = gdu_ar; // save revert address & get new address + gdu_ar = read_gduword() & 0x1FFF; + if (gdu_dsw & GDU_DSW_CHARACTER_MODE) { + draw_characters(); // in character mode this means we are at character data + gdu_ar = gdu_revert; + } + break; + + case 2: // long branch/interrupt + new_addr = read_gduword(); // get next word + accept = ((instr & 1) ? (gdu_dsw & GDU_DSW_LIGHT_PEN_SWITCH) : TRUE) && ((instr & 2) ? (gdu_dsw & GDU_DSW_DETECT_STATUS) : TRUE); + + if (instr & 2) // clear after testing + CLRBIT(gdu_dsw, GDU_DSW_DETECT_STATUS); + + if (instr & 0x0400) // NOP + accept = FALSE; + + if (accept) { + if (instr & 0x0800) { // branch + gdu_revert = gdu_ar; + + if (instr & 0x0080) // indirect + new_addr = M[new_addr & mem_mask]; + + gdu_ar = new_addr; + + if (gdu_dsw & GDU_DSW_CHARACTER_MODE) { + draw_characters(); + gdu_ar = gdu_revert; + } + } + else { // interrupt + gdu_interrupt(GDU_DSW_ORDER_CONTROLLED_INTERRUPT); + run = FALSE; + } + } + break; + + case 3: // control instructions + CLRBIT(gdu_dsw, GDU_DSW_CHARACTER_MODE); + + switch ((instr >> 8) & 0xF) { + case 1: // set pen mode + if ((instr & 0xC) == 8) + SETBIT(gdu_unit.flags, UNIT_DETECTS_ENABLED); + else if ((instr & 0xC) == 4) + CLRBIT(gdu_unit.flags, UNIT_DETECTS_ENABLED); + + if ((instr & 0x3) == 2) + SETBIT(gdu_unit.flags, UNIT_INTERRUPTS_DEFERRED); + else if ((instr & 0x3) == 1) + CLRBIT(gdu_unit.flags, UNIT_INTERRUPTS_DEFERRED); + break; + + case 2: // set graphic mode + if (instr & 1) + SETBIT(gdu_dsw, GDU_DSW_POINT_MODE); + else + CLRBIT(gdu_dsw, GDU_DSW_POINT_MODE); + break; + + case 3: // set character mode + SETBIT(gdu_dsw, GDU_DSW_CHARACTER_MODE); + if (instr & 1) + SETBIT(gdu_unit.flags, UNIT_LARGE_CHARS); + else + CLRBIT(gdu_unit.flags, UNIT_LARGE_CHARS); + break; + + case 4: // start timer + run = FALSE; // (which, for us, means stop processing until next timer message) + CheckGDUKeyboard(); + break; + + case 5: // store revert + M[gdu_ar & mem_mask] = gdu_revert; + read_gduword(); // skip to next address + break; + + case 6: // revert + gdu_ar = gdu_revert; + break; + + default: // all others treated as no-ops + break; + } + break; + + case 4: // long absolute + case 5: + CLRBIT(gdu_dsw, GDU_DSW_CHARACTER_MODE); + newx = instr & 0x3FF; + newy = read_gduword() & 0x3FF; + draw(newx, newy, instr & 0x1000); + last_abs = TRUE; + break; + + case 6: // short absolute + case 7: + CLRBIT(gdu_dsw, GDU_DSW_CHARACTER_MODE); + newx = gdu_x; + newy = gdu_y; + if (instr & 0x0800) + newy = instr & 0x3FF; + else + newx = instr & 0x3FF; + draw(newx, newy, instr & 0x1000); + last_abs = TRUE; + break; + + default: // high bit set - it's a relative instruction + CLRBIT(gdu_dsw, GDU_DSW_CHARACTER_MODE); + newx = (instr >> 8) & 0x3F; + newy = instr & 0x3F; + + if (instr & 0x4000) // sign extend x - values are in 2's complement + newx |= -1 & ~0x3F; // although documentation doesn't make that clear + + if (instr & 0x0040) // sign extend y + newy |= -1 & ~0x3F; + + newx = gdu_x + newx; + newy = gdu_y + newy; + draw(newx, newy, instr & 0x0080); + last_abs = FALSE; + break; + } + } +} + +static struct charinfo { // character mode scaling info: + int dx, dy; // character and line spacing + double sx, sy; // scaling factors: character units to screen units + int xoff, yoff; // x and y offset to lower left corner of character + int suby; // subscript/superscript offset +} cx[2] = { + {14, 20, 1.7, 2.0, -6, -7, 6}, // regular + {21, 30, 2.5, 3.0, -9, -11, 9} // large +}; + +static void draw_characters (void) +{ + int32 w, x0, y0, x1, y1, yoff = 0, ninstr = 0; + t_bool dospace, didstroke = FALSE; + struct charinfo *ci; + + ci = &cx[(gdu_unit.flags & UNIT_LARGE_CHARS) ? 1 : 0]; + x0 = gdu_x + ci->xoff; // starting position + y0 = gdu_y + ci->yoff; + + do { + if (++ninstr > 29) { // too many control words + gdu_interrupt(GDU_DSW_CYCLE_STEAL_CHECK); + return; + } + + dospace = TRUE; + w = M[gdu_ar++ & mem_mask]; // get next stroke or control word + + x1 = (w >> 12) & 7; + y1 = (w >> 8) & 7; + + if (x1 == 7) { // this is a character control word + dospace = FALSE; // inhibit character spacing + + switch (y1) { + case 1: // subscript + if (yoff == 0) // (ignored if superscript is in effect) + yoff = -ci->suby; + break; + +// case 2: // no-op or null (nothing to do) +// default: // all unknowns are no-ops +// break; + + case 4: // superscript + yoff = ci->suby; + break; + + case 7: // new line + gdu_x = 0; + gdu_y -= ci->dy; + if (gdu_y < 0 && last_abs) + gdu_y = 1024 - ci->dy; // this is a guess + break; + } + } + else { // this is stroke data -- extract two strokes + x1 = gdu_x + (int) (x1*ci->sx + 0.5); + y1 = gdu_y + (int) ((y1+yoff)*ci->sy + 0.5); + + if (w & 0x0800) { + didstroke = TRUE; + DrawLine(x0, y0, x1, y1); + } + + x0 = (w >> 4) & 7; + y0 = w & 7; + + x0 = gdu_x + (int) (x0*ci->sx + 0.5); + y0 = gdu_y + (int) ((y0+yoff)*ci->sy + 0.5); + + if (w & 0x0008) { + didstroke = TRUE; + DrawLine(x1, y1, x0, y0); + } + } + + if (dospace) { + gdu_x += ci->dx; + if (gdu_x > 1023 && last_abs) { // line wrap + gdu_x = 0; + gdu_y -= ci->dy; + } + } + } while ((w & 0x0080) == 0); // repeat until we hit revert bit + + if (didstroke && mouse_present && (gdu_unit.flags & UNIT_DETECTS_ENABLED)) { + if (xmouse >= (gdu_x - ci->xoff/2) && xmouse <= (gdu_x + ci->xoff/2) && + ymouse >= (gdu_y - ci->yoff/2) && ymouse <= (gdu_y + ci->yoff/2)) + SETBIT(gdu_dsw, GDU_DSW_DETECT_STATUS); + } +} + +/******* PLATFORM SPECIFIC CODE ***********************************************************/ + +#ifdef WIN32 + +#include +#include + +#define APPCLASS "IBM2250GDU" // window class name + +#define RGB_GREEN RGB(0,255,0) // handy colors +#define RGB_RED RGB(255,0,0) + +static HINSTANCE hInstance; +static HWND hwGDU = NULL; +static HDC hdcGDU = NULL; +static HBITMAP hBmp = NULL; +static int curwid = 0; +static int curht = 0; +static BOOL wcInited = FALSE; +static int GDUPumpID = 0; +static HANDLE hGDUPump = INVALID_HANDLE_VALUE; +static HPEN hGreenPen = NULL; +static HBRUSH hRedBrush = NULL; +#ifdef DEBUG_LIGHTPEN +static HPEN hRedPen = NULL; +#endif +static HBRUSH hGrayBrush, hDarkBrush; +static HPEN hBlackPen; + +static LRESULT APIENTRY GDUWndProc (HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam); +static DWORD WINAPI GDUPump (LPVOID arg); + +static void destroy_GDU_window (void) +{ + if (hwGDU != NULL) + SendMessage(hwGDU, WM_CLOSE, 0, 0); // cross thread call is OK + + if (hGDUPump != INVALID_HANDLE_VALUE) { // this is not the most graceful way to do it + TerminateThread(hGDUPump, 0); + hGDUPump = INVALID_HANDLE_VALUE; + GDUPumpID = 0; + hwGDU = NULL; + } + + if (hdcGDU != NULL) { + DeleteDC(hdcGDU); + hdcGDU = NULL; + } + + if (hBmp != NULL) { + DeleteObject(hBmp); + hBmp = NULL; + } + + if (hGreenPen != NULL) { + DeleteObject(hGreenPen); + hGreenPen = NULL; + } + + if (hRedBrush != NULL) { + DeleteObject(hRedBrush); + hRedBrush = NULL; + } + +#ifdef DEBUG_LIGHTPEN + if (hRedPen != NULL) { + DeleteObject(hRedPen); + hRedPen = NULL; + } +#endif +} + +static t_bool CreateGDUWindow (void) +{ + static BOOL did_atexit = FALSE; + + if (hwGDU != NULL) { // window already exists + StartGDUUpdates(); + return TRUE; + } + + hInstance = GetModuleHandle(NULL); + + if (hGDUPump == INVALID_HANDLE_VALUE) + hGDUPump = CreateThread(NULL, 0, GDUPump, 0, 0, &GDUPumpID); + + if (! did_atexit) { + atexit(destroy_GDU_window); + did_atexit = TRUE; + } + + return TRUE; +} + +// windows message handlers ---------------------------------------------------- + +// close the window + +static void gdu_WM_CLOSE (HWND hWnd) +{ + DestroyWindow(hWnd); +} + +// the window is being destroyed + +static void gdu_WM_DESTROY (HWND hWnd) +{ + notify_window_closed(); + hwGDU = NULL; +} + +// adjust the min and max resizing boundaries + +static void gdu_WM_GETMINMAXINFO (HWND hWnd, LPMINMAXINFO mm) +{ + mm->ptMinTrackSize.x = 100 + 2*INDWIDTH; + mm->ptMinTrackSize.y = 100; +} + +static void PaintImage (HDC hDC, BOOL draw_indicators) +{ + HPEN hOldPen; + RECT r; + int wid, ht, x, y, dy, i, j, ycirc; + unsigned long bit; + + GetClientRect(hwGDU, &r); + wid = r.right+1 - 2*INDWIDTH; + ht = r.bottom+1; + sfactor = (double) MIN(wid,ht) / 1024.; + + if (gdu_dsw & GDU_DSW_BUSY) { +#ifdef BLIT_MODE + // if compiled for BLIT_MODE, draw the image into a memory display context, then + // blit the new image over window. This eliminates the flicker that a normal erase-and- + // repaint would cause. + + if (wid != curwid || ht != curht) { // dimensions have changed, discard old memory display context + if (hdcGDU != NULL) { + DeleteDC(hdcGDU); + hdcGDU = NULL; + } + curwid = wid; + curht = ht; + } + + if (hdcGDU == NULL) { // allocate memory display context & select a bitmap into it + hdcGDU = CreateCompatibleDC(hDC); + if (hBmp != NULL) + DeleteObject(hBmp); + hBmp = CreateCompatibleBitmap(hDC, wid, ht); + SelectObject(hdcGDU, hBmp); + } + + PatBlt(hdcGDU, 0, 0, wid, ht, BLACKNESS); // start with a black screen + + hOldPen = SelectObject(hdcGDU, hGreenPen); + + SetMapMode(hdcGDU, MM_ANISOTROPIC); + SetWindowExtEx(hdcGDU, 1024, -1024, NULL); + SetViewportExtEx(hdcGDU, wid, ht, NULL); + SetWindowOrgEx(hdcGDU, 0, 1023, NULL); + + generate_image(); // run the display program to paint the image into the memory context + + SetWindowExtEx(hdcGDU, wid, ht, NULL); // undo the scaling so the blit isn't distorted + SetViewportExtEx(hdcGDU, wid, ht, NULL); + SetWindowOrgEx(hdcGDU, 0, 0, NULL); + BitBlt(hDC, 0, 0, wid, ht, hdcGDU, 0, 0, SRCCOPY); // blit the new image over the old + + SelectObject(hdcGDU, hOldPen); +#else + // for testing purposes -- draw the image directly onto the screen. + // Compile this way when you want to single-step through the image drawing routine, + // so you can see the draws occur. + hdcGDU = hDC; + hOldPen = SelectObject(hdcGDU, hGreenPen); + + SetMapMode(hdcGDU, MM_ANISOTROPIC); + SetWindowExtEx(hdcGDU, 1024, -1024, NULL); + SetViewportExtEx(hdcGDU, wid, ht, NULL); + SetWindowOrgEx(hdcGDU, 0, 1023, NULL); + + generate_image(); + + SelectObject(hdcGDU, hOldPen); + hdcGDU = NULL; +#endif + } + + if (draw_indicators) { + x = r.right-2*INDWIDTH+1; + dy = ht / 16; + ycirc = MIN(dy-2, 8); + + r.left = x; + FillRect(hDC, &r, hGrayBrush); + SelectObject(hDC, hBlackPen); + + bit = 0x80000000L; + for (i = 0; i < 2; i++) { + MoveToEx(hDC, x, 0, NULL); + LineTo(hDC, x, r.bottom); + y = 0; + for (j = 0; j < 16; j++) { + MoveToEx(hDC, x, y, NULL); + LineTo(hDC, x+INDWIDTH, y); + + SelectObject(hDC, (gdu_indicators & bit) ? hRedBrush : hDarkBrush); + Pie(hDC, x+1, y+1, x+1+ycirc, y+1+ycirc, x+1, y+1, x+1, y+1); + + y += dy; + bit >>= 1; + } + x += INDWIDTH; + } + } +} + +// repaint the window + +static void gdu_WM_PAINT (HWND hWnd) +{ + PAINTSTRUCT ps; + HDC hDC; + // code for display + hDC = BeginPaint(hWnd, &ps); + PaintImage(hDC, TRUE); + EndPaint(hWnd, &ps); +} + +// the window has been resized + +static void gdu_WM_SIZE (HWND hWnd, UINT state, int cx, int cy) +{ + InvalidateRect(hWnd, NULL, FALSE); +} + +// tweak the sizing rectangle during a resize to guarantee a square window + +static void gdu_WM_SIZING (HWND hWnd, WPARAM fwSide, LPRECT r) +{ + switch (fwSide) { + case WMSZ_LEFT: + case WMSZ_RIGHT: + case WMSZ_BOTTOMLEFT: + case WMSZ_BOTTOMRIGHT: + r->bottom = r->right - r->left - 2*INDWIDTH + r->top; + break; + + case WMSZ_TOP: + case WMSZ_BOTTOM: + case WMSZ_TOPRIGHT: + r->right = r->bottom - r->top + r->left + 2*INDWIDTH; + break; + + case WMSZ_TOPLEFT: + r->left = r->top - r->bottom + r->right - 2*INDWIDTH; + break; + } +} + +// the refresh timer has gone off + +static void gdu_WM_TIMER (HWND hWnd, UINT id) +{ + HDC hDC; + + if (running) { // if CPU is running, update picture +#ifdef BLIT_MODE + hDC = GetDC(hWnd); // blit the new image right over the old + PaintImage(hDC, FALSE); + ReleaseDC(hWnd, hDC); +#else + InvalidateRect(hWnd, NULL, TRUE); // repaint +#endif + } +} + +// window procedure ------------------------------------------------------------ + +#define HANDLE(msg) case msg: return HANDLE_##msg(hWnd, wParam, lParam, gdu_##msg); + +#ifndef HANDLE_WM_SIZING +// void Cls_OnSizing(HWND hwnd, UINT fwSide, LPRECT r) +# define HANDLE_WM_SIZING(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), (UINT)(wParam), (LPRECT)(lParam)), 0L) +#endif + +static LRESULT APIENTRY GDUWndProc (HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) +{ + switch (iMessage) { + HANDLE(WM_CLOSE); + HANDLE(WM_GETMINMAXINFO); + HANDLE(WM_DESTROY); + HANDLE(WM_PAINT); + HANDLE(WM_SIZE); + HANDLE(WM_SIZING); + HANDLE(WM_TIMER); + default: // any message we don't process + return DefWindowProc(hWnd, iMessage, wParam, lParam); + } + return 0L; +} + +// graphic calls ---------------------------------------------------------------- + +static void DrawLine (int x0, int y0, int x1, int y1) +{ + MoveToEx(hdcGDU, x0, y0, NULL); + LineTo(hdcGDU, x1, y1); +} + +static void DrawPoint (int x, int y) +{ + SetPixel(hdcGDU, x, y, RGB_GREEN); +} + +static void UpdateGDUIndicators(void) +{ + if (hwGDU != NULL) + InvalidateRect(hwGDU, NULL, TRUE); +} + +static void CheckGDUKeyboard (void) +{ +} + +static UINT idTimer = 0; + +static void StartGDUUpdates (void) +{ + int msec; + + if (idTimer == 0) { + msec = (gdu_rate == 0) ? (1000 / DEFAULT_GDU_RATE) : 1000/gdu_rate; + idTimer = SetTimer(hwGDU, 1, msec, NULL); + } +} + +static void StopGDUUpdates (void) +{ + if (idTimer != 0) { + KillTimer(hwGDU, 1); + idTimer = 0; + } +} + +static void GetMouseCoordinates() +{ + POINT p; + RECT r; + + GetCursorPos(&p); + GetClientRect(hwGDU, &r); + if (! ScreenToClient(hwGDU, &p)) { + xmouse = ymouse = -2000; + mouse_present = FALSE; + return; + } + + if (p.x < r.left || p.x >= r.right || p.y < r.top || p.y > r.bottom) { + mouse_present = FALSE; + return; + } + + // convert mouse coordinates to scaled coordinates + + xmouse = (int) (1024./(r.right+1.-2*INDWIDTH)*p.x + 0.5); + ymouse = 1023 - (int) (1024./(r.bottom+1.)*p.y + 0.5); + mouse_present = TRUE; +} + +t_bool gdu_active (void) +{ + return gdu_dsw & GDU_DSW_BUSY; +} + +static void EraseGDUScreen (void) +{ + if (hwGDU != NULL) /* redraw screen. it will be blank if GDU is not running */ + InvalidateRect(hwGDU, NULL, TRUE); +} + +/* GDUPump - thread responsible for creating and displaying the graphics window */ + +static DWORD WINAPI GDUPump (LPVOID arg) +{ + MSG msg; + WNDCLASS wc; + + if (! wcInited) { /* register Window class */ + memset(&wc, 0, sizeof(wc)); + wc.style = CS_NOCLOSE; + wc.lpfnWndProc = GDUWndProc; + wc.hInstance = hInstance; + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + wc.hbrBackground = GetStockObject(BLACK_BRUSH); + wc.lpszClassName = APPCLASS; + + if (! RegisterClass(&wc)) { + GDUPumpID = 0; + return 0; + } + + wcInited = TRUE; + } + + if (hGreenPen == NULL) + hGreenPen = CreatePen(PS_SOLID, 1, RGB_GREEN); + +#ifdef DEBUG_LIGHTPEN + if (hRedPen == NULL) + hRedPen = CreatePen(PS_SOLID, 1, RGB_RED); +#endif + + if (hRedBrush == NULL) + hRedBrush = CreateSolidBrush(RGB_RED); + + hGrayBrush = GetStockObject(GRAY_BRUSH); + hDarkBrush = GetStockObject(DKGRAY_BRUSH); + hBlackPen = GetStockObject(BLACK_PEN); + + if (hwGDU == NULL) { /* create window */ + hwGDU = CreateWindow(APPCLASS, + "2250 Display", + WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN, + CW_USEDEFAULT, CW_USEDEFAULT, // initial x, y position + INITSIZE+2*INDWIDTH, INITSIZE, // initial width and height + NULL, // parent window handle + NULL, // use class menu + hInstance, // program instance handle + NULL); // create parameters + + if (hwGDU == NULL) { + GDUPumpID = 0; + return 0; + } + } + + ShowWindow(hwGDU, SW_SHOWNOACTIVATE); /* display it */ + UpdateWindow(hwGDU); + + StartGDUUpdates(); + + while (GetMessage(&msg, hwGDU, 0, 0)) { /* message pump - this basically loops forevermore */ + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + if (hwGDU != NULL) { + DestroyWindow(hwGDU); /* but if a quit message got posted, clean up */ + hwGDU = NULL; + } + + GDUPumpID = 0; + return 0; +} + +#ifdef DEBUG_LIGHTPEN +static void ShowPenHit (int x, int y) +{ + HPEN hOldPen; + + hOldPen = SelectObject(hdcGDU, hRedPen); + DrawLine(x-10, y-10, x+10, y+10); + DrawLine(x-10, y+10, x+10, y-10); + SelectObject(hdcGDU, hOldPen); +} +#endif + +#endif // WIN32 defined +#endif // GUI_SUPPORT defined diff --git a/Ibm1130/ibm1130_gui.c b/Ibm1130/ibm1130_gui.c new file mode 100644 index 00000000..7266d469 --- /dev/null +++ b/Ibm1130/ibm1130_gui.c @@ -0,0 +1,1231 @@ +/* ibm1130_gui.c: IBM 1130 CPU simulator Console Display + * + * Based on the SIMH package written by Robert M Supnik + * + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org + * + * 17-May-02 BLK Pulled out of ibm1130_cpu.c + */ + +/* ------------------------------------------------------------------------ + * Definitions + * ------------------------------------------------------------------------ */ + +#include +#include + +#include "ibm1130_defs.h" +#include "ibm1130res.h" + +#define UPDATE_BY_TIMER + +#ifdef UPDATE_BY_TIMER +# define UPDATE_INTERVAL 20 // set to desired number of updates/second +#else +# define UPDATE_INTERVAL 5000 // GUI: set to 100000/f where f = desired updates/second of 1130 time +#endif + +/* ------------------------------------------------------------------------ + * Function declarations + * ------------------------------------------------------------------------ */ + +t_stat console_reset (DEVICE *dptr); + +/* ------------------------------------------------------------------------ + * Console display - on Windows builds (only) this code displays the 1130 console + * and toggle switches. It really enhances the experience. + * + * Currently, when the IPS throttle is nonzero, I update the display after every + * UPDATE_INTERVAL instructions, plus or minus a random amount to avoid aliased + * sampling in loops. When UPDATE_INTERVAL is defined as zero, we update every + * instruction no matter what the throttle. This makes the simulator too slow + * but it's cool and helpful during development. + * ------------------------------------------------------------------------ */ + +#define UNIT_V_DISPLAY (UNIT_V_UF + 0) +#define UNIT_DISPLAY (1u << UNIT_V_DISPLAY) + +MTAB console_mod[] = { + { UNIT_DISPLAY, 0, "off", "OFF", NULL }, + { UNIT_DISPLAY, UNIT_DISPLAY, "on", "ON", NULL }, + { 0 } +}; + +UNIT console_unit = {UDATA (NULL, UNIT_DISABLE|UNIT_DISPLAY, 0) }; + +DEVICE console_dev = { + "GUI", &console_unit, NULL, console_mod, + 1, 16, 16, 1, 16, 16, + NULL, NULL, console_reset, + NULL, NULL, NULL +}; + +// reset for the "console" display device + +extern char *read_line (char *cptr, int size, FILE *stream); +extern FILE *sim_log; + +#ifndef GUI_SUPPORT + void update_gui (int force) {} /* stubs for non-GUI builds */ + void forms_check (int set) {} + void print_check (int set) {} + void keyboard_select (int select) {} + void keyboard_selected (int select) {} + void disk_ready (int ready) {} + void disk_unlocked (int unlocked) {} + void gui_run (int running) {} + static void init_console_window (void) {} + static void destroy_console_window (void) {} + + t_stat console_reset (DEVICE *dptr) {return SCPE_OK;} + void stuff_cmd (char *cmd) {} + char *read_cmdline (char *ptr, int size, FILE *stream) {return read_line(ptr, size, stream);} + void remark_cmd (char *remark) {printf("%s\n", remark); if (sim_log) fprintf(sim_log, "%s\n", remark);} +#else + +t_stat console_reset (DEVICE *dptr) +{ + if (! sim_gui) { + SETBIT(console_unit.flags, UNIT_DIS); // disable the GUI + CLRBIT(console_unit.flags, UNIT_DISPLAY); // turn the GUI off + } + + update_gui(FALSE); + return SCPE_OK; +} + +/* scp_panic - report fatal internal programming error */ + +void scp_panic (char *msg) +{ + fprintf(stderr, "%s\n", msg); + exit(1); +} + +#ifdef WIN32 + /* only WIN32 is defined right now */ + +#include + +#define BUTTON_WIDTH 90 +#define BUTTON_HEIGHT 50 + +#define IDC_KEYBOARD_SELECT 0 +#define IDC_DISK_UNLOCK 1 +#define IDC_RUN 2 +#define IDC_PARITY_CHECK 3 +#define IDC_UNUSED 4 +#define IDC_FILE_READY 5 +#define IDC_FORMS_CHECK 6 +#define IDC_POWER_ON 7 +#define IDC_POWER 8 +#define IDC_PROGRAM_START 9 +#define IDC_PROGRAM_STOP 10 +#define IDC_LOAD_IAR 11 +#define IDC_KEYBOARD 12 +#define IDC_IMM_STOP 13 +#define IDC_RESET 14 +#define IDC_PROGRAM_LOAD 15 + +#define LAMPTIME 500 // 500 msec delay on updating +#define FLASH_TIMER_ID 1 +#define UPDATE_TIMER_ID 2 + +static BOOL class_defined = FALSE; +static HWND hConsoleWnd = NULL; +static HBITMAP hBitmap = NULL; +static HFONT hFont = NULL; +static HFONT hBtnFont = NULL; +static HBRUSH hbLampOut = NULL; +static HBRUSH hbWhite = NULL; +static HBRUSH hbBlack = NULL; +static HBRUSH hbGray = NULL; +static HPEN hSwitchPen = NULL; +static HPEN hWhitePen = NULL; +static HPEN hBlackPen = NULL; +static HPEN hLtGreyPen = NULL; +static HPEN hGreyPen = NULL; +static HPEN hDkGreyPen = NULL; +static int hUpdateTimer = 0; +static int hFlashTimer = 0; + +static HCURSOR hcArrow = NULL; +static HCURSOR hcHand = NULL; +static HINSTANCE hInstance; +static HDC hCDC = NULL; +static char szConsoleClassName[] = "1130CONSOLE"; +static DWORD PumpID = 0; +static HANDLE hPump = INVALID_HANDLE_VALUE; +static int bmwid, bmht; + +static struct tag_btn { + int x, y; + char *txt; + BOOL pushable; + COLORREF clr; + HBRUSH hbrLit, hbrDark; + HWND hBtn; +} btn[] = { + 0, 0, "KEYBOARD\nSELECT", FALSE, RGB(255,255,180), NULL, NULL, NULL, + 0, 1, "DISK\nUNLOCK", FALSE, RGB(255,255,180), NULL, NULL, NULL, + 0, 2, "RUN", FALSE, RGB(0,255,0), NULL, NULL, NULL, + 0, 3, "PARITY\nCHECK", FALSE, RGB(255,0,0), NULL, NULL, NULL, + + 1, 0, "", FALSE, RGB(255,255,180), NULL, NULL, NULL, + 1, 1, "FILE\nREADY", FALSE, RGB(0,255,0), NULL, NULL, NULL, + 1, 2, "FORMS\nCHECK", FALSE, RGB(255,255,0), NULL, NULL, NULL, + 1, 3, "POWER\nON", FALSE, RGB(255,255,180), NULL, NULL, NULL, + + 2, 0, "POWER", TRUE, RGB(255,255,180), NULL, NULL, NULL, + 2, 1, "PROGRAM\nSTART", TRUE, RGB(0,255,0), NULL, NULL, NULL, + 2, 2, "PROGRAM\nSTOP", TRUE, RGB(255,0,0), NULL, NULL, NULL, + 2, 3, "LOAD\nIAR", TRUE, RGB(0,0,255), NULL, NULL, NULL, + + 3, 0, "KEYBOARD", TRUE, RGB(255,255,180), NULL, NULL, NULL, + 3, 1, "IMM\nSTOP", TRUE, RGB(255,0,0), NULL, NULL, NULL, + 3, 2, "CHECK\nRESET", TRUE, RGB(0,0,255), NULL, NULL, NULL, + 3, 3, "PROGRAM\nLOAD", TRUE, RGB(0,0,255), NULL, NULL, NULL, +}; +#define NBUTTONS (sizeof(btn) / sizeof(btn[0])) + +static void init_console_window (void); +static void destroy_console_window (void); +LRESULT CALLBACK ConsoleWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +static DWORD WINAPI Pump (LPVOID arg); + +#define NIXOBJECT(hObj) if (hObj != NULL) {DeleteObject(hObj); hObj = NULL;} + +/* ------------------------------------------------------------------------ + * init_console_window - display the 1130 console. Actually just creates a thread + * to run the Pump routine which does the actual work. + * ------------------------------------------------------------------------ */ + +static void init_console_window (void) +{ + static BOOL did_atexit = FALSE; + + if (hConsoleWnd != NULL) + return; + + if (PumpID == 0) + hPump = CreateThread(NULL, 0, Pump, 0, 0, &PumpID); + + if (! did_atexit) { + atexit(destroy_console_window); + did_atexit = TRUE; + } +} + +/* ------------------------------------------------------------------------ + * destroy_console_window - delete GDI objects. + * ------------------------------------------------------------------------ */ + +static void destroy_console_window (void) +{ + int i; + + if (hConsoleWnd != NULL) + SendMessage(hConsoleWnd, WM_CLOSE, 0, 0); // cross thread call is OK + + if (hPump != INVALID_HANDLE_VALUE) { // this is not the most graceful way to do it + TerminateThread(hPump, 0); + hPump = INVALID_HANDLE_VALUE; + PumpID = 0; + hConsoleWnd = NULL; + } + if (hCDC != NULL) { + DeleteDC(hCDC); + hCDC = NULL; + } + + NIXOBJECT(hBitmap) + NIXOBJECT(hbLampOut) + NIXOBJECT(hFont) + NIXOBJECT(hBtnFont); + NIXOBJECT(hcHand) + NIXOBJECT(hSwitchPen) + NIXOBJECT(hLtGreyPen) + NIXOBJECT(hGreyPen) + NIXOBJECT(hDkGreyPen) + + for (i = 0; i < NBUTTONS; i++) { + NIXOBJECT(btn[i].hbrLit); + NIXOBJECT(btn[i].hbrDark); + } + +// if (class_defined) { +// UnregisterClass(hInstance, szConsoleClassName); +// class_defined = FALSE; +// } +} + +/* ------------------------------------------------------------------------ + * these variables hold the displayed versions of the system registers + * ------------------------------------------------------------------------ */ + +static int shown_iar = 0, shown_sar = 0, shown_sbr = 0, shown_afr = 0, shown_acc = 0, shown_ext = 0; +static int shown_op = 0, shown_tag = 0, shown_irq = 0, shown_ccc = 0, shown_cnd = 0, shown_wait = 0; +static int shown_ces = 0, shown_runmode = MODE_RUN; +static int CND; + +/* ------------------------------------------------------------------------ + * RedrawRegion - mark a region for redrawing without background erase + * ------------------------------------------------------------------------ */ + +static void RedrawRegion (HWND hWnd, int left, int top, int right, int bottom) +{ + RECT r; + + r.left = left; + r.top = top; + r.right = right; + r.bottom = bottom; + + InvalidateRect(hWnd, &r, FALSE); +} + +/* ------------------------------------------------------------------------ + * RepaintRegion - mark a region for redrawing with background erase + * ------------------------------------------------------------------------ */ + +static void RepaintRegion (HWND hWnd, int left, int top, int right, int bottom) +{ + RECT r; + + r.left = left; + r.top = top; + r.right = right; + r.bottom = bottom; + + InvalidateRect(hWnd, &r, TRUE); +} + +/* ------------------------------------------------------------------------ + * update_gui - sees if anything on the console display has changed, and invalidates + * the changed regions. Then it calls UpdateWindow to force an immediate repaint. This + * function (update_gui) should probably not be called every time through the main + * instruction loop but it should be called at least whenever wait_state or int_req change, and then + * every so many instructions. It's also called after every simh command so manual changes are + * reflected instantly. + * ------------------------------------------------------------------------ */ + +void update_gui (BOOL force) +{ + int i, sts; + static int in_here = FALSE; + static int32 displayed = 0; + + if ((int32)(console_unit.flags & UNIT_DISPLAY) != displayed) { // setting has changed + displayed = console_unit.flags & UNIT_DISPLAY; + if (displayed) + init_console_window(); + else + destroy_console_window(); + } + + if (hConsoleWnd == NULL) + return; + + GUI_BEGIN_CRITICAL_SECTION /* only one thread at a time, please */ + if (in_here) { + GUI_END_CRITICAL_SECTION + return; + } + in_here = TRUE; + GUI_END_CRITICAL_SECTION + + CND = 0; /* combine carry and V as two bits */ + if (C) + CND |= 2; + if (V) + CND |= 1; + + int_lamps |= int_req; + if (ipl >= 0) + int_lamps |= (0x20 >> ipl); + + if (RUNMODE == MODE_LOAD) + SBR = CES; /* in load mode, SBR follows the console switches */ + + if (IAR != shown_iar) + {shown_iar = IAR; RedrawRegion(hConsoleWnd, 75, 8, 364, 32);} /* lamps: don't bother erasing bkgnd */ + if (SAR != shown_sar) + {shown_sar = SAR; RedrawRegion(hConsoleWnd, 75, 42, 364, 65);} + if (ACC != shown_acc) + {shown_acc = ACC; RedrawRegion(hConsoleWnd, 75, 141, 364, 164);} + if (EXT != shown_ext) + {shown_ext = EXT; RedrawRegion(hConsoleWnd, 75, 174, 364, 197);} + if (SBR != shown_sbr) + {shown_sbr = SBR; RedrawRegion(hConsoleWnd, 75, 77, 364, 97);} + if (OP != shown_op) + {shown_op = OP; RedrawRegion(hConsoleWnd, 501, 8, 595, 32);} + if (TAG != shown_tag) + {shown_tag = TAG; RedrawRegion(hConsoleWnd, 501, 77, 595, 97);} + + if (int_lamps != shown_irq) + {shown_irq = int_lamps; RedrawRegion(hConsoleWnd, 501, 108, 595, 130);} + + if (CCC != shown_ccc) + {shown_ccc = CCC; RedrawRegion(hConsoleWnd, 501, 141, 595, 164);} + if (CND != shown_cnd) + {shown_cnd = CND; RedrawRegion(hConsoleWnd, 501, 174, 595, 197);} + if ((wait_state|wait_lamp) != shown_wait) + {shown_wait= (wait_state|wait_lamp); RedrawRegion(hConsoleWnd, 380, 77, 414, 97);} + if (CES != shown_ces) + {shown_ces = CES; RepaintRegion(hConsoleWnd, 115, 230, 478, 275);} /* console entry sw: do erase bkgnd */ + if (RUNMODE != shown_runmode) + {shown_runmode = RUNMODE;RepaintRegion(hConsoleWnd, 270, 359, 330, 418);} + + int_lamps = 0; + + for (i = 0; i < NBUTTONS; i++) { + if (btn[i].pushable) + continue; + + switch (i) { + case IDC_RUN: sts = hFlashTimer || (running && ! wait_state); break; +// case IDC_PARITY_CHECK: sts = FALSE; break; +// case IDC_POWER_ON: sts = TRUE; break; + default: + continue; + +// case IDC_FILE_READY: these windows are enabled&disabled directly +// case IDC_FORMS_CHECK: +// case IDC_KEYBOARD_SELECT: +// case IDC_DISK_UNLOCK: + } + + if (sts != IsWindowEnabled(btn[i].hBtn)) // status has changed + EnableWindow(btn[i].hBtn, sts); + } + + in_here = FALSE; +} + +WNDPROC oldButtonProc = NULL; + +/* ------------------------------------------------------------------------ + * ------------------------------------------------------------------------ */ + +LRESULT CALLBACK ButtonProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + int i; + + i = GetWindowLong(hWnd, GWL_ID); + + if (! btn[i].pushable) { + if (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP || uMsg == WM_LBUTTONDBLCLK) + return 0; + if (uMsg == WM_CHAR) + if ((TCHAR) wParam == ' ') + return 0; + } + + return CallWindowProc(oldButtonProc, hWnd, uMsg, wParam, lParam); +} + +/* ------------------------------------------------------------------------ + * ------------------------------------------------------------------------ */ + +static int occurs (char *txt, char ch) +{ + int count = 0; + + while (*txt) + if (*txt++ == ch) + count++; + + return count; +} + +/* ------------------------------------------------------------------------ +// turns out to get properly colored buttons you have to paint them yourself. Sheesh. +// On the plus side, this lets do a better job of aligning the button text than +// the button would by itself. + * ------------------------------------------------------------------------ */ + +void PaintButton (LPDRAWITEMSTRUCT dis) +{ + int i = dis->CtlID, nc, nlines, x, y, dy; + BOOL down = dis->itemState & ODS_SELECTED; + HPEN hOldPen; + HFONT hOldFont; + UINT oldAlign; + COLORREF oldBk; + char *txt, *tstart; + + if (! BETWEEN(i, 0, NBUTTONS-1)) + return; + + FillRect(dis->hDC, &dis->rcItem, ((btn[i].pushable || power) && IsWindowEnabled(btn[i].hBtn)) ? btn[i].hbrLit : btn[i].hbrDark); + + if (! btn[i].pushable) { + hOldPen = SelectObject(dis->hDC, hBlackPen); + MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.top, NULL); + LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top); + LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.bottom-1); + LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-1); + LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.top); + } + else if (down) { + // do the three-D thing + hOldPen = SelectObject(dis->hDC, hDkGreyPen); + MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-2, NULL); + LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.top); + LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top); + + SelectObject(dis->hDC, hWhitePen); + MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-1, NULL); + LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.bottom-1); + LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top); + + SelectObject(dis->hDC, hGreyPen); + MoveToEx(dis->hDC, dis->rcItem.left+1, dis->rcItem.bottom-3, NULL); + LineTo(dis->hDC, dis->rcItem.left+1, dis->rcItem.top+1); + LineTo(dis->hDC, dis->rcItem.right-3, dis->rcItem.top+1); + } + else { + hOldPen = SelectObject(dis->hDC, hWhitePen); + MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-2, NULL); + LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.top); + LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top); + + SelectObject(dis->hDC, hDkGreyPen); + MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-1, NULL); + LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.bottom-1); + LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top); + + SelectObject(dis->hDC, hGreyPen); + MoveToEx(dis->hDC, dis->rcItem.left+1, dis->rcItem.bottom-2, NULL); + LineTo(dis->hDC, dis->rcItem.right-2, dis->rcItem.bottom-2); + LineTo(dis->hDC, dis->rcItem.right-2, dis->rcItem.top+1); + } + + SelectObject(dis->hDC, hOldPen); + + hOldFont = SelectObject(dis->hDC, hBtnFont); + oldAlign = SetTextAlign(dis->hDC, TA_CENTER|TA_TOP); + oldBk = SetBkMode(dis->hDC, TRANSPARENT); + + txt = btn[i].txt; + nlines = occurs(txt, '\n')+1; + x = (dis->rcItem.left + dis->rcItem.right) / 2; + y = (dis->rcItem.top + dis->rcItem.bottom) / 2; + + dy = 14; + y = y - (nlines*dy)/2; + + if (down) { + x += 1; + y += 1; + } + + for (;;) { + for (nc = 0, tstart = txt; *txt && *txt != '\n'; txt++, nc++) + ; + + TextOut(dis->hDC, x, y, tstart, nc); + + if (*txt == '\0') + break; + + txt++; + y += dy; + } + + SetTextAlign(dis->hDC, oldAlign); + SetBkMode(dis->hDC, oldBk); + SelectObject(dis->hDC, hOldFont); +} + +/* ------------------------------------------------------------------------ + * ------------------------------------------------------------------------ */ + +HWND CreateSubclassedButton (HWND hwParent, int i) +{ + HWND hBtn; + int x, y; + int r, g, b; + + y = bmht - (4*BUTTON_HEIGHT) + BUTTON_HEIGHT * btn[i].y; + x = (btn[i].x < 2) ? (btn[i].x*BUTTON_WIDTH) : (bmwid - (4-btn[i].x)*BUTTON_WIDTH); + + if ((hBtn = CreateWindow("BUTTON", btn[i].txt, WS_CHILD|WS_VISIBLE|BS_CENTER|BS_MULTILINE|BS_OWNERDRAW, + x, y, BUTTON_WIDTH, BUTTON_HEIGHT, hwParent, (HMENU) i, hInstance, NULL)) == NULL) + return NULL; + + btn[i].hBtn = hBtn; + + if (oldButtonProc == NULL) + oldButtonProc = (WNDPROC) GetWindowLong(hBtn, GWL_WNDPROC); + + btn[i].hbrLit = CreateSolidBrush(btn[i].clr); + + if (! btn[i].pushable) { + r = GetRValue(btn[i].clr) / 4; + g = GetGValue(btn[i].clr) / 4; + b = GetBValue(btn[i].clr) / 4; + + btn[i].hbrDark = CreateSolidBrush(RGB(r,g,b)); + EnableWindow(hBtn, FALSE); + } + + SetWindowLong(hBtn, GWL_WNDPROC, (LONG) ButtonProc); + return hBtn; +} + +/* ------------------------------------------------------------------------ + * Pump - thread that takes care of the console window. It has to be a separate thread so that it gets + * execution time even when the simulator is compute-bound or IO-blocked. This routine creates the window + * and runs a standard Windows message pump. The window function does the actual display work. + * ------------------------------------------------------------------------ */ + +static DWORD WINAPI Pump (LPVOID arg) +{ + MSG msg; + int wx, wy, i; + RECT r, ra; + BITMAP bm; + WNDCLASS cd; + HDC hDC; + HWND hActWnd; + + hActWnd = GetForegroundWindow(); + + if (! class_defined) { /* register Window class */ + hInstance = GetModuleHandle(NULL); + + memset(&cd, 0, sizeof(cd)); + cd.style = CS_NOCLOSE; + cd.lpfnWndProc = ConsoleWndProc; + cd.cbClsExtra = 0; + cd.cbWndExtra = 0; + cd.hInstance = hInstance; + cd.hIcon = NULL; + cd.hCursor = hcArrow; + cd.hbrBackground = NULL; + cd.lpszMenuName = NULL; + cd.lpszClassName = szConsoleClassName; + + if (! RegisterClass(&cd)) { + PumpID = 0; + return 0; + } + + class_defined = TRUE; + } + + hbWhite = GetStockObject(WHITE_BRUSH); /* create or fetch useful GDI objects */ + hbBlack = GetStockObject(BLACK_BRUSH); /* create or fetch useful GDI objects */ + hbGray = GetStockObject(GRAY_BRUSH); + hSwitchPen = CreatePen(PS_SOLID, 5, RGB(255,255,255)); + + hWhitePen = GetStockObject(WHITE_PEN); + hBlackPen = GetStockObject(BLACK_PEN); + hLtGreyPen = CreatePen(PS_SOLID, 1, RGB(190,190,190)); + hGreyPen = CreatePen(PS_SOLID, 1, RGB(128,128,128)); + hDkGreyPen = CreatePen(PS_SOLID, 1, RGB(64,64,64)); + + hcArrow = LoadCursor(NULL, IDC_ARROW); + hcHand = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_HAND)); + + if (hBitmap == NULL) + hBitmap = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_CONSOLE)); + if (hbLampOut == NULL) + hbLampOut = CreateSolidBrush(RGB(50,50,50)); + if (hFont == NULL) + hFont = CreateFont(-10, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, FIXED_PITCH, FF_SWISS, "Arial"); + if (hBtnFont == NULL) + hBtnFont = CreateFont(-12, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, FIXED_PITCH, FF_SWISS, "Arial"); + + if (hConsoleWnd == NULL) { /* create window */ + if ((hConsoleWnd = CreateWindow(szConsoleClassName, "IBM 1130", WS_OVERLAPPED, 0, 0, 200, 200, NULL, NULL, hInstance, NULL)) == NULL) { + PumpID = 0; + return 0; + } + } + + GetObject(hBitmap, sizeof(bm), &bm); /* get bitmap size */ + bmwid = bm.bmWidth; + bmht = bm.bmHeight; + + for (i = 0; i < NBUTTONS; i++) + CreateSubclassedButton(hConsoleWnd, i); + + EnableWindow(btn[IDC_POWER_ON].hBtn, TRUE); + EnableWindow(btn[IDC_DISK_UNLOCK].hBtn, TRUE); + + GetWindowRect(hConsoleWnd, &r); /* get window size as created */ + wx = r.right - r.left + 1; + wy = r.bottom - r.top + 1; + + if (hCDC == NULL) { /* get a memory DC and select the bitmap into ti */ + hDC = GetDC(hConsoleWnd); + hCDC = CreateCompatibleDC(hDC); + SelectObject(hCDC, hBitmap); + ReleaseDC(hConsoleWnd, hDC); + } + + GetClientRect(hConsoleWnd, &r); + wx = (wx - r.right - 1) + bmwid; /* compute new desired size based on how client area came out */ + wy = (wy - r.bottom - 1) + bmht; + MoveWindow(hConsoleWnd, 0, 0, wx, wy, FALSE); /* resize window */ + + ShowWindow(hConsoleWnd, SW_SHOWNOACTIVATE); /* display it */ + UpdateWindow(hConsoleWnd); + + if (hActWnd != NULL) { /* bring console (sim) window back to top */ + GetWindowRect(hConsoleWnd, &r); + ShowWindow(hActWnd, SW_NORMAL); /* and move it just below the display window */ + SetWindowPos(hActWnd, HWND_TOP, 0, r.bottom, 0, 0, SWP_NOSIZE); + GetWindowRect(hActWnd, &ra); + if (ra.bottom >= GetSystemMetrics(SM_CYSCREEN)) { /* resize if it goes of bottom of screen */ + ra.bottom = GetSystemMetrics(SM_CYSCREEN) - 1; + SetWindowPos(hActWnd, 0, 0, 0, ra.right-ra.left+1, ra.bottom-ra.top+1, SWP_NOZORDER|SWP_NOMOVE); + } + } + + if (running) /* if simulator is already running, start update timer */ + gui_run(TRUE); + + while (GetMessage(&msg, hConsoleWnd, 0, 0)) { /* message pump - this basically loops forevermore */ + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + if (hConsoleWnd != NULL) { + DestroyWindow(hConsoleWnd); /* but if a quit message got posted, clean up */ + hConsoleWnd = NULL; + } + + PumpID = 0; + return 0; +} + +/* ------------------------------------------------------------------------ + * DrawBits - starting at position (x,y), draw lamps for nbits bits of word 'bits', looking only at masked bits + * ------------------------------------------------------------------------ */ + +static void DrawBits (HDC hDC, int x, int y, int bits, int nbits, int mask, char *syms) +{ + int i, b = 0x0001 << (nbits-1); + + for (i = 0; i < nbits; i++, b >>= 1) { + if (mask & b) { /* select white or black lettering then write 2 chars */ + SetTextColor(hDC, (b & bits && power) ? RGB(255,255,255) : RGB(0,0,0)); + TextOut(hDC, x, y, syms, 2); + } + syms += 2; /* go to next symbol pair */ + + if (i < 10) + x += 15; /* step between lamps */ + else + x += 19; + + if (x < 500) { + if (b & 0x1110) + x += 10; /* step over nibble divisions on left side */ + else if (b & 0x0001) + x += 9; + } + } +} + +/* ------------------------------------------------------------------------ + * DrawToggles - display the console sense switches + * ------------------------------------------------------------------------ */ + +static void DrawToggles (HDC hDC, int bits) +{ + int b, x; + + for (b = 0x8000, x = 122; b != 0; b >>= 1) { + if (shown_ces & b) { /* up */ + SelectObject(hDC, hbWhite); + Rectangle(hDC, x, 232, x+9, 240); + SelectObject(hDC, hbGray); + Rectangle(hDC, x, 239, x+9, 255); + } + else { /* down */ + SelectObject(hDC, hbWhite); + Rectangle(hDC, x, 263, x+9, 271); + SelectObject(hDC, hbGray); + Rectangle(hDC, x, 248, x+9, 264); + } + + x += (b & 0x1111) ? 31 : 21; + } +} + +/* ------------------------------------------------------------------------ + * DrawRunmode - draw the run mode rotary switch's little tip + * ------------------------------------------------------------------------ */ + +void DrawRunmode (HDC hDC, int mode) +{ + double angle = (mode*45. + 90.) * 3.1415926 / 180.; /* convert mode position to angle in radians */ + double ca, sa; /* sine and cosine */ + int x0, y0, x1, y1; + HPEN hOldPen; + + ca = cos(angle); + sa = sin(angle); + + x0 = 301 + (int) (20.*ca + 0.5); /* inner radius */ + y0 = 389 - (int) (20.*sa + 0.5); + x1 = 301 + (int) (25.*ca + 0.5); /* outer radius */ + y1 = 389 - (int) (25.*sa + 0.5); + + hOldPen = SelectObject(hDC, hSwitchPen); + + MoveToEx(hDC, x0, y0, NULL); + LineTo(hDC, x1, y1); + + SelectObject(hDC, hOldPen); +} + +/* ------------------------------------------------------------------------ + * HandleClick - handle mouse clicks on the console window. Now we just + * look at the console sense switches. Actual says this is a real click, rather + * than a mouse-region test. Return value TRUE means the cursor is over a hotspot. + * ------------------------------------------------------------------------ */ + +static BOOL HandleClick (HWND hWnd, int xh, int yh, BOOL actual) +{ + int b, x, r, ang, i; + + for (b = 0x8000, x = 122; b != 0; b >>= 1) { + if (BETWEEN(xh, x-3, x+8+3) && BETWEEN(yh, 230, 275)) { + if (actual) { + CES ^= b; /* a hit. Invert the bit and redisplay */ + update_gui(TRUE); + } + return TRUE; + } + x += (b & 0x1111) ? 31 : 21; + } + + if (BETWEEN(xh, 245, 355) && BETWEEN(yh, 345, 425)) { /* hit near rotary switch */ + ang = (int) (atan2(301.-xh, 389.-yh)*180./3.1415926); /* this does implicit 90 deg rotation by the way */ + r = (int) sqrt((xh-301)*(xh-301)+(yh-389)*(yh-389)); + if (r > 12) { + for (i = MODE_LOAD; i <= MODE_INT_RUN; i++) { + if (BETWEEN(ang, i*45-12, i*45+12)) { + if (actual) { + RUNMODE = i; + update_gui(TRUE); + } + return TRUE; + } + } + + } + } + + return FALSE; +} + +/* ------------------------------------------------------------------------ + * DrawConsole - refresh the console display. (This routine could be sped up by intersecting + * the various components' bounding rectangles with the repaint rectangle. The bounding rects + * could be put into an array and used both here and in the refresh routine). + * + * RedrawRegion -> force repaint w/o background redraw. used for lamps which are drawn in the same place in either state + * RepaintRegion-> repaint with background redraw. Used for toggles which change position. + * ------------------------------------------------------------------------ */ + +static void DrawConsole (HDC hDC) +{ + static char digits[] = " 0 1 2 3 4 5 6 7 8 9101112131415"; + static char cccs[] = "3216 8 4 2 1"; + static char cnds[] = " C V"; + static char waits[] = " W"; + HFONT hOldFont, hOldBrush; + + hOldFont = SelectObject(hDC, hFont); /* use that tiny font */ + hOldBrush = SelectObject(hDC, hbWhite); + + SetBkMode(hDC, TRANSPARENT); /* overlay letters w/o changing background */ + + DrawBits(hDC, 76, 15, shown_iar, 16, 0x3FFF, digits); + DrawBits(hDC, 76, 48, shown_sar, 16, 0x3FFF, digits); + DrawBits(hDC, 76, 81, shown_sbr, 16, 0xFFFF, digits); + DrawBits(hDC, 76, 147, shown_acc, 16, 0xFFFF, digits); + DrawBits(hDC, 76, 180, shown_ext, 16, 0xFFFF, digits); + + DrawBits(hDC, 506, 15, shown_op, 5, 0x001F, digits); + DrawBits(hDC, 506, 81, shown_tag, 4, 0x0007, digits); + DrawBits(hDC, 506, 114, shown_irq, 6, 0x003F, digits); + DrawBits(hDC, 506, 147, shown_ccc, 6, 0x003F, cccs); + DrawBits(hDC, 506, 180, shown_cnd, 2, 0x0003, cnds); + + DrawBits(hDC, 390, 81, shown_wait?1:0,1, 0x0001, waits); + + DrawToggles(hDC, shown_ces); + + DrawRunmode(hDC, shown_runmode); + + SelectObject(hDC, hOldFont); + SelectObject(hDC, hOldBrush); +} + +/* ------------------------------------------------------------------------ + * Handles button presses. Remember that this occurs in the context of + * the Pump thread, not the simulator thread. + * ------------------------------------------------------------------------ */ + +void flash_run (void) +{ + EnableWindow(btn[IDC_RUN].hBtn, TRUE); // enable the run lamp + + if (hFlashTimer != 0) + KillTimer(hConsoleWnd, FLASH_TIMER_ID); // (re)schedule lamp update + + hFlashTimer = SetTimer(hConsoleWnd, FLASH_TIMER_ID, LAMPTIME, NULL); +} + +void gui_run (int running) +{ + if (running && hUpdateTimer == 0 && hConsoleWnd != NULL) { + hUpdateTimer = SetTimer(hConsoleWnd, UPDATE_TIMER_ID, 1000/UPDATE_INTERVAL, NULL); + } + else if (hUpdateTimer != 0 && ! running) { + KillTimer(hConsoleWnd, UPDATE_TIMER_ID); + hUpdateTimer = 0; + } + flash_run(); /* keep run lamp active for a while after we stop running */ +} + +void HandleCommand (HWND hWnd, WPARAM wParam, LPARAM lParam) +{ + int i; + + switch (wParam) { + case IDC_POWER: /* toggle system power */ + power = ! power; + reset_all(0); + if (running && ! power) { /* turning off */ + reason = STOP_POWER_OFF; + while (running) + Sleep(10); /* wait for execution thread to exit */ + } + EnableWindow(btn[IDC_POWER_ON].hBtn, power); + for (i = 0; i < NBUTTONS; i++) + InvalidateRect(btn[i].hBtn, NULL, TRUE); + break; + + case IDC_PROGRAM_START: /* begin execution */ + if (! running) { + switch (RUNMODE) { + case MODE_INT_RUN: + case MODE_RUN: + case MODE_SI: + stuff_cmd("go"); + break; + + case MODE_DISP: /* display core and advance IAR */ + ReadW(IAR); + IAR = IAR+1; + flash_run(); /* illuminate run lamp for .5 sec */ + break; + + case MODE_LOAD: /* store to core and advance IAR */ + WriteW(IAR, CES); + IAR = IAR+1; + flash_run(); + break; + } + } + break; + + case IDC_PROGRAM_STOP: + if (running) { /* potential race condition here */ + GUI_BEGIN_CRITICAL_SECTION + SETBIT(cpu_dsw, CPU_DSW_PROGRAM_STOP); + SETBIT(ILSW[5], ILSW_5_PROGRAM_STOP); + int_req |= INT_REQ_5; + GUI_END_CRITICAL_SECTION + } + break; + + case IDC_LOAD_IAR: + if (! running) { + IAR = CES & 0x3FFF; /* set IAR from console entry switches */ + } + break; + + case IDC_KEYBOARD: /* toggle between console/keyboard mode */ + break; + + case IDC_IMM_STOP: + if (running) { + reason = STOP_WAIT; /* terminate execution without setting wait_mode */ + while (running) + Sleep(10); /* wait for execution thread to exit */ + } + break; + + case IDC_RESET: + if (! running) { /* check-reset is disabled while running */ + reset_all(0); + forms_check(0); /* clear forms-check status */ + print_check(0); + } + break; + + case IDC_PROGRAM_LOAD: + if (! running) { /* if card reader is attached to a file, do cold start read of one card */ + IAR = 0; /* reset IAR */ +// stuff_cmd("boot cr"); + if (cr_boot(0) != SCPE_OK) /* load boot card */ + remark_cmd("IPL failed"); + } + break; + } + + update_gui(FALSE); +} + +/* ------------------------------------------------------------------------ + * ConsoleWndProc - window process for the console display + * ------------------------------------------------------------------------ */ + +LRESULT CALLBACK ConsoleWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + HDC hDC; + PAINTSTRUCT ps; + POINT p; + RECT clip, xsect, rbmp; + int i; + + switch (uMsg) { + case WM_CLOSE: + DestroyWindow(hWnd); + break; + + case WM_DESTROY: + gui_run(FALSE); + hConsoleWnd = NULL; + break; + + case WM_ERASEBKGND: + hDC = (HDC) wParam; + GetClipBox(hDC, &clip); + SetRect(&rbmp, 0, 0, bmwid, bmht); + if (IntersectRect(&xsect, &clip, &rbmp)) + BitBlt(hDC, xsect.left, xsect.top, xsect.right-xsect.left+1, xsect.bottom-xsect.top+1, hCDC, xsect.left, xsect.top, SRCCOPY); +// rbmp.top = rbmp.bottom; +// rbmp.bottom += 200; +// if (IntersectRect(&xsect, &clip, &rbmp)) +// FillRect(hDC, &xsect, hbBlack); + return TRUE; /* let Paint do this so we know what the update region is (ps.rcPaint) */ + + case WM_PAINT: + hDC = BeginPaint(hWnd, &ps); + DrawConsole(hDC); + EndPaint(hWnd, &ps); + break; + + case WM_COMMAND: /* button click */ + HandleCommand(hWnd, wParam, lParam); + break; + + case WM_DRAWITEM: + PaintButton((LPDRAWITEMSTRUCT) lParam); + break; + + case WM_SETCURSOR: + GetCursorPos(&p); + ScreenToClient(hWnd, &p); + SetCursor(HandleClick(hWnd, p.x, p.y, FALSE) ? hcHand : hcArrow); + return TRUE; + + case WM_LBUTTONDOWN: + HandleClick(hWnd, LOWORD(lParam), HIWORD(lParam), TRUE); + break; + + case WM_CTLCOLORBTN: + i = GetWindowLong((HWND) lParam, GWL_ID); + if (BETWEEN(i, 0, NBUTTONS-1)) + return (LRESULT) (power && IsWindowEnabled((HWND) lParam) ? btn[i].hbrLit : btn[i].hbrDark); + + case WM_TIMER: + if (wParam == FLASH_TIMER_ID && hFlashTimer != 0) { + KillTimer(hWnd, FLASH_TIMER_ID); + hFlashTimer = 0; + } + update_gui(FALSE); + break; + + default: + return DefWindowProc(hWnd, uMsg, wParam, lParam); + } + + return 0; +} + +enum {PRINTER_OK = 0, FORMS_CHECK = 1, PRINT_CHECK = 2, BOTH_CHECK = 3} printerstatus = PRINTER_OK; + +void forms_check (int set) +{ + COLORREF oldcolor = btn[IDC_FORMS_CHECK].clr; + + if (set) + SETBIT(printerstatus, FORMS_CHECK); + else + CLRBIT(printerstatus, FORMS_CHECK); + + btn[IDC_FORMS_CHECK].clr = (printerstatus & PRINT_CHECK) ? RGB(255,0,0) : RGB(255,255,0); + + EnableWindow(btn[IDC_FORMS_CHECK].hBtn, printerstatus); + + if (btn[IDC_FORMS_CHECK].clr != oldcolor) + InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); // change color in any case +} + +void print_check (int set) +{ + COLORREF oldcolor = btn[IDC_FORMS_CHECK].clr; + + if (set) + SETBIT(printerstatus, PRINT_CHECK); + else + CLRBIT(printerstatus, PRINT_CHECK); + + btn[IDC_FORMS_CHECK].clr = (printerstatus & PRINT_CHECK) ? RGB(255,0,0) : RGB(255,255,0); + + EnableWindow(btn[IDC_FORMS_CHECK].hBtn, printerstatus); + + if (btn[IDC_FORMS_CHECK].clr != oldcolor) + InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); // change color in any case +} + +void keyboard_selected (int select) +{ + EnableWindow(btn[IDC_KEYBOARD_SELECT].hBtn, select); +} + +void disk_ready (int ready) +{ + EnableWindow(btn[IDC_FILE_READY].hBtn, ready); +} + +void disk_unlocked (int unlocked) +{ + EnableWindow(btn[IDC_DISK_UNLOCK].hBtn, unlocked); +} + +CRITICAL_SECTION critsect; + +void begin_critical_section (void) +{ + static BOOL mustinit = TRUE; + + if (mustinit) { + InitializeCriticalSection(&critsect); + mustinit = FALSE; + } + + EnterCriticalSection(&critsect); +} + +void end_critical_section (void) +{ + LeaveCriticalSection(&critsect); +} + +#ifndef MIN +# define MIN(a,b) (((a) <= (b)) ? (a) : (b)) +#endif + +/* win32 - use a separate thread to read command lines so the GUI + * can insert commands as well */ + +static HANDLE hCmdThread = NULL; +static DWORD iCmdThreadID = 0; +static HANDLE hCmdReadEvent = NULL; +static HANDLE hCmdReadyEvent = NULL; +static BOOL scp_stuffed = FALSE, scp_reading = FALSE; +static char cmdbuffer[256]; + +/* CmdThread - separate thread to read commands from stdin upon request */ + +static DWORD WINAPI CmdThread (LPVOID arg) +{ + for (;;) { + WaitForSingleObject(hCmdReadEvent, INFINITE); /* wait for request */ + read_line(cmdbuffer, sizeof(cmdbuffer), stdin); /* read one line */ + scp_stuffed = FALSE; /* say how we got it */ + SetEvent(hCmdReadyEvent); /* notify main thread a line is ready */ + } + return 0; +} + +char *read_cmdline (char *ptr, int size, FILE *stream) +{ + char *cptr; + + if (hCmdThread == NULL) { /* set up command-reading thread */ + if ((hCmdReadEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) + scp_panic("Can't create command line read event"); + + if ((hCmdReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) + scp_panic("Can't create command line ready event"); + /* start up the command thread */ + if ((hCmdThread = CreateThread(NULL, 0, CmdThread, NULL, 0, &iCmdThreadID)) == NULL) + scp_panic("Unable to create command line reading thread"); + } + + scp_reading = TRUE; + + SetEvent(hCmdReadEvent); /* let read thread get one line */ + WaitForSingleObject(hCmdReadyEvent, INFINITE); /* wait for read thread or GUI to respond */ + + scp_reading = FALSE; + + strncpy(ptr, cmdbuffer, MIN(size, sizeof(cmdbuffer))); /* copy line to caller's buffer */ + + for (cptr = ptr; isspace(*cptr); cptr++) /* absorb spaces */ + ; + + if (scp_stuffed) { /* stuffed command needs to be echoed */ + printf("%s\n", cptr); + if (sim_log) fprintf(sim_log, "%s\n", cptr); + } + + return cptr; +} + +/* stuff_cmd - force a command into the read_cmdline output buffer. Called asynchronously by GUI */ + +void stuff_cmd (char *cmd) +{ + strcpy(cmdbuffer, cmd); /* save the string */ + scp_stuffed = TRUE; /* note where it came from */ + SetEvent(hCmdReadyEvent); /* notify main thread a line is ready */ +} + +/* remark_cmd - print a remark from inside a command processor. This routine takes + * into account the possiblity that the command might have been stuffed, in which + * case the sim> prompt needs to be reprinted. + */ + +void remark_cmd (char *remark) +{ + printf("%s\n", remark); + if (sim_log) fprintf(sim_log, "%s\n", remark); + if (scp_reading) { + printf("sim> "); + if (sim_log) fprintf(sim_log, "sim> "); + } +} + +#endif // WIN32 defined +#endif // GUI_SUPPORT defined diff --git a/Ibm1130/ibm1130_prt.c b/Ibm1130/ibm1130_prt.c new file mode 100644 index 00000000..8340d273 --- /dev/null +++ b/Ibm1130/ibm1130_prt.c @@ -0,0 +1,773 @@ +/* ibm1130_prt.c: IBM 1130 line printer emulation + + Based on the SIMH simulator package written by Robert M Supnik + + Brian Knittel + Revision History + 2002.09.13 - Added 1403 support. New file, taken from part of ibm1130_stddev.c + + Note: The 1403 is much faster, even in emulation, because it takes much + less CPU power to run it. DMS doesn't use the WAIT command when waiting for + printer operations to complete, so it ends up burning LOTS of cpu cycles. + The 1403 printer doesn't require as many. HOWEVER: DMS must be loaded for the 1403, + and Fortran IOCS control cards must specify it. + + The 1132 is still the default printer. + + As written, we can't have two printers. + + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org + */ + +#include "ibm1130_defs.h" + +/*************************************************************************************** + * 1132 PRINTER + ***************************************************************************************/ + +#define PRT1132_DSW_READ_EMITTER_RESPONSE 0x8000 +#define PRT1132_DSW_SKIP_RESPONSE 0x4000 +#define PRT1132_DSW_SPACE_RESPONSE 0x2000 +#define PRT1132_DSW_CARRIAGE_BUSY 0x1000 +#define PRT1132_DSW_PRINT_SCAN_CHECK 0x0800 +#define PRT1132_DSW_NOT_READY 0x0400 +#define PRT1132_DSW_PRINTER_BUSY 0x0200 + +#define PRT1132_DSW_CHANNEL_MASK 0x00FF /* 1132 printer DSW bits */ +#define PRT1132_DSW_CHANNEL_1 0x0080 +#define PRT1132_DSW_CHANNEL_2 0x0040 +#define PRT1132_DSW_CHANNEL_3 0x0020 +#define PRT1132_DSW_CHANNEL_4 0x0010 +#define PRT1132_DSW_CHANNEL_5 0x0008 +#define PRT1132_DSW_CHANNEL_6 0x0004 +#define PRT1132_DSW_CHANNEL_9 0x0002 +#define PRT1132_DSW_CHANNEL_12 0x0001 + +#define PRT1403_DSW_PARITY_CHECK 0x8000 /* 1403 printer DSW bits */ +#define PRT1403_DSW_TRANSFER_COMPLETE 0x4000 +#define PRT1403_DSW_PRINT_COMPLETE 0x2000 +#define PRT1403_DSW_CARRIAGE_COMPLETE 0x1000 +#define PRT1403_DSW_RING_CHECK 0x0400 +#define PRT1403_DSW_SYNC_CHECK 0x0200 +#define PRT1403_DSW_CH9 0x0010 +#define PRT1403_DSW_CH12 0x0008 +#define PRT1403_DSW_CARRIAGE_BUSY 0x0004 +#define PRT1403_DSW_PRINTER_BUSY 0x0002 +#define PRT1403_DSW_NOT_READY 0x0001 + +#define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT) + +static t_stat prt1132_svc(UNIT *uptr); +static t_stat prt1403_svc(UNIT *uptr); +static t_stat prt_svc (UNIT *uptr); +static t_stat prt_reset (DEVICE *dptr); +static t_stat prt_attach (UNIT *uptr, char *cptr); +static t_stat prt_detach (UNIT *uptr); + +static int16 PRT_DSW = 0; /* device status word */ +static int32 prt_swait = 500; /* line skip wait */ +static int32 prt_cwait = 1250; /* character rotation wait */ +static int32 prt_fwait = 100; /* fast wait, for 1403 operations */ +static int32 prt_twait = 50; /* transfer wait, for 1403 operations */ +#define SKIPTARGET (uptr->u4) /* target for skip operation */ + +#define UNIT_V_FORMCHECK (UNIT_V_UF + 0) /* out of paper error */ +#define UNIT_V_DATACHECK (UNIT_V_UF + 1) /* printer overrun error */ +#define UNIT_V_SKIPPING (UNIT_V_UF + 2) /* printer skipping */ +#define UNIT_V_SPACING (UNIT_V_UF + 3) /* printer is spacing */ +#define UNIT_V_PRINTING (UNIT_V_UF + 4) /* printer printing */ +#define UNIT_V_TRANSFERRING (UNIT_V_UF + 5) /* unit is transferring print buffer (1403 only) */ +#define UNIT_V_1403 (UNIT_V_UF + 6) /* printer model is 1403 rather than 1132 */ +#define UNIT_V_PARITYCHECK (UNIT_V_UF + 7) /* error flags for 1403 */ +#define UNIT_V_RINGCHECK (UNIT_V_UF + 8) +#define UNIT_V_SYNCCHECK (UNIT_V_UF + 9) + +#define UNIT_FORMCHECK (1u << UNIT_V_FORMCHECK) +#define UNIT_DATACHECK (1u << UNIT_V_DATACHECK) +#define UNIT_SKIPPING (1u << UNIT_V_SKIPPING) +#define UNIT_SPACING (1u << UNIT_V_SPACING) +#define UNIT_PRINTING (1u << UNIT_V_PRINTING) +#define UNIT_TRANSFERRING (1u << UNIT_V_TRANSFERRING) +#define UNIT_1403 (1u << UNIT_V_1403) +#define UNIT_PARITYCHECK (1u << UNIT_V_PARITYCHECK) +#define UNIT_RINGCHECK (1u << UNIT_V_RINGCHECK) +#define UNIT_SYNCCHECK (1u << UNIT_V_SYNCCHECK) + +UNIT prt_unit[] = { + { UDATA (&prt_svc, UNIT_ATTABLE, 0) }, +}; + +#define IS_1403(uptr) (uptr->flags & UNIT_1403) /* model test */ +#define IS_1132(uptr) ((uptr->flags & UNIT_1403) == 0) /* model test */ + +/* Parameter in the unit descriptor (1132 printer) */ + +#define CMD_NONE 0 +#define CMD_SPACE 1 +#define CMD_SKIP 2 +#define CMD_PRINT 3 + +REG prt_reg[] = { + { HRDATA (PRTDSW, PRT_DSW, 16) }, /* device status word */ + { DRDATA (STIME, prt_swait, 24), PV_LEFT }, /* line skip wait */ + { DRDATA (CTIME, prt_cwait, 24), PV_LEFT }, /* character rotation wait */ + { DRDATA (CTIME, prt_fwait, 24), PV_LEFT }, /* 1403 fast wait */ + { DRDATA (CTIME, prt_twait, 24), PV_LEFT }, /* 1403 transfer wait */ + { NULL } }; + +MTAB prt_mod[] = { + { UNIT_1403, 0, "1132", "1132", NULL }, /* model option */ + { UNIT_1403, UNIT_1403, "1403", "1403", NULL }, + { 0 } }; + +DEVICE prt_dev = { + "PRT", prt_unit, prt_reg, prt_mod, + 1, 16, 16, 1, 16, 16, + NULL, NULL, &prt_reset, + NULL, prt_attach, prt_detach}; + +#define PRT_COLUMNS 120 +#define PRT_ROWLEN 120 +#define MAX_OVPRINT 20 + +static char prtbuf[PRT_ROWLEN*MAX_OVPRINT]; +static int nprint[PRT_COLUMNS], ncol[MAX_OVPRINT], maxnp; +static int prt_nchar, prt_row; /* current printwheel position, current page row */ +static int prt_nnl; /* number of queued newlines */ + +#define CC_CHANNEL_1 0x0800 /* carriage control tape punch values */ +#define CC_CHANNEL_2 0x0400 +#define CC_CHANNEL_3 0x0200 +#define CC_CHANNEL_4 0x0100 +#define CC_CHANNEL_5 0x0080 +#define CC_CHANNEL_6 0x0040 /* 7, 8, 10 and 11 are not used on 1132 printer */ +#define CC_CHANNEL_7 0x0020 +#define CC_CHANNEL_8 0x0010 +#define CC_CHANNEL_9 0x0008 +#define CC_CHANNEL_10 0x0004 +#define CC_CHANNEL_11 0x0002 +#define CC_CHANNEL_12 0x0001 + +#define CC_1403_BITS 0x0FFF /* all bits for 1403, most for 1132 */ +#define CC_1132_BITS (CC_1403_BITS & ~(CC_CHANNEL_7|CC_CHANNEL_8|CC_CHANNEL_10|CC_CHANNEL_11)) + +#define PRT_PAGELENGTH 66 + +static int cctape[PRT_PAGELENGTH]; /* standard carriage control tape */ + +static struct tag_ccpunches { /* list of rows and punches on tape */ + int row, channels; +} +ccpunches[] = { + 2, CC_CHANNEL_1, // channel 1 = top of form + 62, CC_CHANNEL_12 // channel 12 = bottom of form +}, +cccgi[] = { + 2, CC_CHANNEL_1 // channel 1 = top of form; no bottom of form +}; + +#include "ibm1130_prtwheel.h" + +// cc_format_1132 and cc_format_1403 - turn cctape bits into proper format for DSW or status read + +static int cc_format_1132 (int bits) +{ + return ((bits & (CC_CHANNEL_1|CC_CHANNEL_2|CC_CHANNEL_3|CC_CHANNEL_4|CC_CHANNEL_5|CC_CHANNEL_6)) >> 4) | + ((bits & CC_CHANNEL_9) >> 3) | + (bits & CC_CHANNEL_12); +} + +#define cc_format_1403(bits) (bits) + +// reset_prt_line - clear the print line following paper advancement + +static void reset_prt_line (void) +{ + memset(nprint, 0, sizeof(nprint)); + memset(ncol, 0, sizeof(ncol)); + maxnp = 0; +} + +// save_1132_prt_line - fire hammers for character 'ch' + +static t_bool save_1132_prt_line (int ch) +{ + int i, r, addr = 32; + int32 mask = 0, wd = 0; + + for (i = 0; i < PRT_COLUMNS; i++) { + if (mask == 0) { // fetch next word from memory + mask = 0x8000; + wd = M[addr++]; + } + + if (wd & mask) { // hammer is to fire in this column + if ((r = nprint[i]) < MAX_OVPRINT) { + if (ncol[r] <= i) { // we haven't moved this far yet + if (ncol[r] == 0) // first char in this row? + memset(prtbuf+r*PRT_ROWLEN, ' ', PRT_COLUMNS); // blank out the new row + ncol[r] = i+1; // remember new row length + } + prtbuf[r*PRT_ROWLEN + i] = (char) ch; // save the character + + nprint[i]++; // remember max overprintings for this column + maxnp = MAX(maxnp, nprint[i]); + } + } + + mask >>= 1; // prepare to examine next bit + } + + return wd & 1; // return TRUE if the last word has lsb set, which means all bits had been set +} + +// write_line - write collected line to output file. No need to trim spaces as the hammers +// are never fired for them, so ncol[r] is the last printed position on each line. + +static void newpage (FILE *fd) +{ + if (cgi) + fputs("
\n", fd); + else + putc('\f', fd); // formfeed +} + +static void flush_prt_line (FILE *fd, int spacemode) +{ + int r; + + if (! (spacemode || maxnp)) // nothing to do + return; + + prt_row = (prt_row+1) % PRT_PAGELENGTH; // NEXT line + + if (spacemode && ! maxnp) { // spacing only + if (prt_row == 0 && prt_nnl) { +#ifdef WIN32 + if (! cgi) + putc('\r', fd); // DOS/Windows: end with cr/lf +#endif + putc('\n', fd); // otherwise end with lf + if (spacemode & UNIT_SKIPPING) // add formfeed if we crossed page boundary while skipping + newpage(fd); + prt_nnl = 0; + } + else + prt_nnl++; + + return; + } + + if (prt_nnl) { // there are queued newlines +// if we spaced to top of form, don't emit formfeed. We'd only ever emit the formfeed if we skipped via control tape channels +// if (prt_row == 0 && prt_nnl) { // we spaced to top of form +//#ifdef WIN32 +// if (! cgi) +// putc('\r', fd); // DOS/Windows: end with cr/lf +//#endif +// putc('\n', fd); // otherwise end with lf +// newpage(fd); +// prt_nnl = 0; +// } +// else { + while (prt_nnl > 0) { // spit out queued newlines +#ifdef WIN32 + if (! cgi) + putc('\r', fd); // DOS/Windows: end with cr/lf +#endif + putc('\n', fd); // otherwise end with lf + prt_nnl--; + } +// } + } + + for (r = 0; r < maxnp; r++) { + if (r > 0) + putc('\r', fd); // carriage return between overprinted lines + fxwrite(&prtbuf[r*PRT_ROWLEN], 1, ncol[r], fd); + } + + reset_prt_line(); + + prt_nnl++; // queue a newline +} + +// 1132 printer commands + +#define PRT_CMD_START_PRINTER 0x0080 +#define PRT_CMD_STOP_PRINTER 0x0040 +#define PRT_CMD_START_CARRIAGE 0x0004 +#define PRT_CMD_STOP_CARRIAGE 0x0002 +#define PRT_CMD_SPACE 0x0001 + +#define PRT_CMD_MASK 0x00C7 + +extern char * saywhere (int addr); + +static void mytrace (int start, char *what) +{ + char *where; + + if ((where = saywhere(prev_IAR)) == NULL) where = "?"; + trace_io("%s %s at %04x: %s\n", start ? "start" : "stop", what, prev_IAR, where); +} + +/* xio_1132_printer - XIO command interpreter for the 1132 printer */ + +void xio_1132_printer (int32 iocc_addr, int32 func, int32 modify) +{ + char msg[80]; + UNIT *uptr = &prt_unit[0]; + + switch (func) { + case XIO_READ: + M[iocc_addr & mem_mask] = codewheel1132[prt_nchar].ebcdic << 8; + + if ((uptr->flags & UNIT_PRINTING) == 0) /* if we're not printing, advance this after every test */ + prt_nchar = (prt_nchar + 1) % WHEELCHARS_1132; + break; + + case XIO_SENSE_DEV: + ACC = PRT_DSW; + if (modify & 0x01) { /* reset interrupts */ + CLRBIT(PRT_DSW, PRT1132_DSW_READ_EMITTER_RESPONSE | PRT1132_DSW_SKIP_RESPONSE | PRT1132_DSW_SPACE_RESPONSE); + CLRBIT(ILSW[1], ILSW_1_1132_PRINTER); + } + break; + + case XIO_CONTROL: + if (modify & PRT_CMD_START_PRINTER) { + SETBIT(uptr->flags, UNIT_PRINTING); +// mytrace(1, "printing"); + } + + if (modify & PRT_CMD_STOP_PRINTER) { + CLRBIT(uptr->flags, UNIT_PRINTING); +// mytrace(0, "printing"); + } + + if (modify & PRT_CMD_START_CARRIAGE) { + SETBIT(uptr->flags, UNIT_SKIPPING); +// mytrace(1, "skipping"); + } + + if (modify & PRT_CMD_STOP_CARRIAGE) { + CLRBIT(uptr->flags, UNIT_SKIPPING); +// mytrace(0, "skipping"); + } + + if (modify & PRT_CMD_SPACE) { + SETBIT(uptr->flags, UNIT_SPACING); +// mytrace(1, "space"); + } + + sim_cancel(uptr); + if (uptr->flags & (UNIT_SKIPPING|UNIT_SPACING|UNIT_PRINTING)) { // busy bits = doing something + SETBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY); + sim_activate(uptr, prt_cwait); + } + else + CLRBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY); + + if (uptr->flags & (UNIT_SKIPPING|UNIT_SPACING)) + SETBIT(PRT_DSW, PRT1132_DSW_CARRIAGE_BUSY); + else + CLRBIT(PRT_DSW, PRT1132_DSW_CARRIAGE_BUSY); + + if ((uptr->flags & (UNIT_SKIPPING|UNIT_SPACING)) == (UNIT_SKIPPING|UNIT_SPACING)) { + sprintf(msg, "1132 printer skip and space at same time?"); + xio_error(msg); + } + break; + + default: + sprintf(msg, "Invalid 1132 printer XIO function %x", func); + xio_error(msg); + } +} + +#define SET_ACTION(u,a) {(u)->flags &= ~(UNIT_SKIPPING|UNIT_SPACING|UNIT_PRINTING|UNIT_TRANSFERRING); (u)->flags |= a;} + +static t_stat prt_svc (UNIT *uptr) +{ + return IS_1403(uptr) ? prt1403_svc(uptr) : prt1132_svc(uptr); +} + +// prt1132_svc - emulated timeout for 1132 operation + +static t_stat prt1132_svc (UNIT *uptr) +{ + if (PRT_DSW & PRT1132_DSW_NOT_READY) { // cancel operation if printer went offline + SETBIT(uptr->flags, UNIT_FORMCHECK); + SET_ACTION(uptr, 0); + forms_check(TRUE); // and turn on forms check lamp + return SCPE_OK; + } + + if (uptr->flags & UNIT_SPACING) { + flush_prt_line(uptr->fileref, UNIT_SPACING); + + CLRBIT(PRT_DSW, PRT1132_DSW_CHANNEL_MASK|PRT1132_DSW_PRINTER_BUSY|PRT1132_DSW_CARRIAGE_BUSY); + SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]) | PRT1132_DSW_SPACE_RESPONSE); + SETBIT(ILSW[1], ILSW_1_1132_PRINTER); + CLRBIT(uptr->flags, UNIT_SPACING); // done with this + calc_ints(); + } + + if (uptr->flags & UNIT_SKIPPING) { + do { + flush_prt_line(uptr->fileref, UNIT_SKIPPING); + CLRBIT(PRT_DSW, PRT1132_DSW_CHANNEL_MASK); + SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row])); + } while ((cctape[prt_row] & CC_1132_BITS) == 0); // slew directly to a cc tape punch + + SETBIT(PRT_DSW, cc_format_1132(cctape[prt_row]) | PRT1132_DSW_SKIP_RESPONSE); + SETBIT(ILSW[1], ILSW_1_1132_PRINTER); + calc_ints(); + } + + if (uptr->flags & UNIT_PRINTING) { + if (! save_1132_prt_line(codewheel1132[prt_nchar].ascii)) { // save previous printed line + SETBIT(uptr->flags, UNIT_DATACHECK); // buffer wasn't set in time + SET_ACTION(uptr, 0); + print_check(TRUE); // and turn on forms check lamp + return SCPE_OK; + } + + prt_nchar = (prt_nchar + 1) % WHEELCHARS_1132; // advance print drum + + SETBIT(PRT_DSW, PRT1132_DSW_READ_EMITTER_RESPONSE); // issue interrupt to tell printer to set buffer + SETBIT(ILSW[1], ILSW_1_1132_PRINTER); // we'll save the printed stuff just before next emitter response (later than on real 1130) + calc_ints(); + } + + if (uptr->flags & (UNIT_SPACING|UNIT_SKIPPING|UNIT_PRINTING)) { // still doing something + SETBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY); + sim_activate(uptr, prt_cwait); + } + else + CLRBIT(PRT_DSW, PRT1132_DSW_PRINTER_BUSY); + + return SCPE_OK; +} + +void save_1403_prt_line (int32 addr) +{ + int i, j, r, ch, even = TRUE; + unsigned char ebcdic; + int32 wd; + + for (i = 0; i < PRT_COLUMNS; i++) { + if (even) { // fetch next word from memory + wd = M[addr++]; + ebcdic = (unsigned char) ((wd >> 8) & 0x7F); + even = FALSE; + } + else { + ebcdic = (unsigned char) (wd & 0x7F); // use low byte of previously fetched word + even = TRUE; + } + + ch = ' '; // translate ebcdic to ascii. Don't bother checking for parity errors + for (j = 0; j < WHEELCHARS_1403; j++) { + if (codewheel1403[j].ebcdic == ebcdic) { + ch = codewheel1403[j].ascii; + break; + } + } + + if (ch > ' ') { + if ((r = nprint[i]) < MAX_OVPRINT) { + if (ncol[r] <= i) { // we haven't moved this far yet + if (ncol[r] == 0) // first char in this row? + memset(prtbuf+r*PRT_ROWLEN, ' ', PRT_COLUMNS); // blank out the new row + ncol[r] = i+1; // remember new row length + } + prtbuf[r*PRT_ROWLEN + i] = (char) ch; // save the character + + nprint[i]++; // remember max overprintings for this column + maxnp = MAX(maxnp, nprint[i]); + } + } + } +} + +void xio_1403_printer (int32 iocc_addr, int32 func, int32 modify) +{ + UNIT *uptr = &prt_unit[0]; + + switch (func) { + case XIO_INITW: /* print a line */ + save_1403_prt_line(iocc_addr); /* put formatted line into our print buffer */ + + SETBIT(uptr->flags, UNIT_TRANSFERRING); /* schedule transfer complete interrupt */ + SETBIT(PRT_DSW, PRT1403_DSW_PRINTER_BUSY); + sim_activate(uptr, prt_twait); + break; + + case XIO_CONTROL: /* initiate single space */ + if (uptr->flags & UNIT_SKIPPING) { + xio_error("1403 printer skip and space at same time?"); + } + else { + SETBIT(uptr->flags, UNIT_SPACING); + SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY); + sim_activate(uptr, prt_fwait); + } + break; + + case XIO_WRITE: /* initiate skip */ + if (uptr->flags & UNIT_SPACING) { + xio_error("1403 printer skip and space at same time?"); + } + else { + SETBIT(uptr->flags, UNIT_SKIPPING); + SKIPTARGET = ReadW(iocc_addr) & CC_1403_BITS; /* get CC bits that we're to match */ + SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY); + sim_activate(uptr, prt_fwait); + } + break; + + case XIO_SENSE_DEV: /* get device status word */ + ACC = PRT_DSW; + if (modify & 0x01) { /* reset interrupts */ + CLRBIT(PRT_DSW, PRT1403_DSW_PARITY_CHECK | PRT1403_DSW_TRANSFER_COMPLETE | + PRT1403_DSW_PRINT_COMPLETE | PRT1403_DSW_CARRIAGE_COMPLETE | + PRT1403_DSW_RING_CHECK | PRT1403_DSW_SYNC_CHECK); + CLRBIT(ILSW[4], ILSW_4_1403_PRINTER); + } + break; + } +} + +static t_stat prt1403_svc(UNIT *uptr) +{ + if (PRT_DSW & PRT1403_DSW_NOT_READY) { // cancel operation if printer went offline + SET_ACTION(uptr, 0); + forms_check(TRUE); // and turn on forms check lamp + } + else if (uptr->flags & UNIT_TRANSFERRING) { // end of transfer + CLRBIT(uptr->flags, UNIT_TRANSFERRING); + SETBIT(uptr->flags, UNIT_PRINTING); // schedule "print complete" + + SETBIT(PRT_DSW, PRT1403_DSW_TRANSFER_COMPLETE); // issue transfer complete interrupt + SETBIT(ILSW[4], ILSW_4_1403_PRINTER); + } + else if (uptr->flags & UNIT_PRINTING) { + CLRBIT(uptr->flags, UNIT_PRINTING); + CLRBIT(PRT_DSW, PRT1403_DSW_PRINTER_BUSY); + + SETBIT(PRT_DSW, PRT1403_DSW_PRINT_COMPLETE); + SETBIT(ILSW[4], ILSW_4_1403_PRINTER); // issue print complete interrupt + } + else if (uptr->flags & UNIT_SKIPPING) { + do { // find line with exact match of tape punches + flush_prt_line(uptr->fileref, UNIT_SKIPPING); + } while (cctape[prt_row] != SKIPTARGET); // slew directly to requested cc tape punch + + CLRBIT(uptr->flags, UNIT_SKIPPING); // done with this + CLRBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY); + + SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_COMPLETE); + SETBIT(ILSW[4], ILSW_4_1403_PRINTER); + } + else if (uptr->flags & UNIT_SPACING) { + flush_prt_line(uptr->fileref, UNIT_SPACING); + + CLRBIT(uptr->flags, UNIT_SPACING); // done with this + CLRBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_BUSY); + + SETBIT(PRT_DSW, PRT1403_DSW_CARRIAGE_COMPLETE); + SETBIT(ILSW[4], ILSW_4_1403_PRINTER); + } + + if (uptr->flags & (UNIT_PRINTING|UNIT_SKIPPING|UNIT_SPACING|UNIT_TRANSFERRING)) + sim_activate(uptr, prt_fwait); + + CLRBIT(PRT_DSW, PRT1403_DSW_CH9|PRT1403_DSW_CH12); // set the two CC bits in the DSW + if (cctape[prt_row] & CC_CHANNEL_9) + SETBIT(PRT_DSW, PRT1403_DSW_CH9); + if (cctape[prt_row] & CC_CHANNEL_12) + SETBIT(PRT_DSW, PRT1403_DSW_CH12); + + calc_ints(); + return SCPE_OK; +} + +/* delete_cmd - SCP command to delete a file */ + +static t_stat delete_cmd (int flag, char *cptr) +{ + char gbuf[CBUFSIZE]; + int status; + + cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ + if (*gbuf == 0) return SCPE_2FARG; + if (*cptr != 0) return SCPE_2MARG; /* now eol? */ + + status = unlink(gbuf); /* delete the file */ + + if (status != 0 && errno != ENOENT) /* print message if failed and file exists */ + perror(gbuf); + + return SCPE_OK; +} + +/* prt_reset - reset emulated printer */ + +static t_stat prt_reset (DEVICE *dptr) +{ + UNIT *uptr = &prt_unit[0]; + int i; + +// add a DELETE filename command so we can be sure to have clean listings + register_cmd("DELETE", &delete_cmd, 0, "del{ete} filename remove file\n"); + + sim_cancel(uptr); + + memset(cctape, 0, sizeof(cctape)); // copy punch list into carriage control tape image + + if (cgi) + for (i = 0; i < (sizeof(cccgi)/sizeof(cccgi[0])); i++) + cctape[cccgi[i].row-1] |= cccgi[i].channels; + else + for (i = 0; i < (sizeof(ccpunches)/sizeof(ccpunches[0])); i++) + cctape[ccpunches[i].row-1] |= ccpunches[i].channels; + + prt_nchar = 0; + prt_row = 0; + prt_nnl = 0; + + CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK|UNIT_PRINTING|UNIT_SPACING|UNIT_SKIPPING| + UNIT_TRANSFERRING|UNIT_PARITYCHECK|UNIT_RINGCHECK|UNIT_SYNCCHECK); + + if (IS_1132(uptr)) { + CLRBIT(ILSW[1], ILSW_1_1132_PRINTER); + PRT_DSW = cc_format_1132(cctape[prt_row]); + if (! IS_ONLINE(uptr)) + SETBIT(PRT_DSW, PRT1132_DSW_NOT_READY); + } + else { + CLRBIT(ILSW[4], ILSW_4_1403_PRINTER); + PRT_DSW = 0; + if (cctape[prt_row] & CC_CHANNEL_9) + SETBIT(PRT_DSW, PRT1403_DSW_CH9); + if (cctape[prt_row] & CC_CHANNEL_12) + SETBIT(PRT_DSW, PRT1403_DSW_CH12); + if (! IS_ONLINE(uptr)) + SETBIT(PRT_DSW, PRT1403_DSW_NOT_READY); + } + + SET_ACTION(uptr, 0); + calc_ints(); + reset_prt_line(); + + forms_check(FALSE); + return SCPE_OK; +} + +static t_stat prt_attach (UNIT *uptr, char *cptr) +{ + t_stat rval; + /* assume failure */ + SETBIT(PRT_DSW, IS_1132(uptr) ? PRT1132_DSW_NOT_READY : PRT1403_DSW_NOT_READY); + + if (uptr->flags & UNIT_ATT) { + if ((rval = prt_detach(uptr)) != SCPE_OK) { + return rval; + } + } + + sim_cancel(uptr); + + if (strcmp(cptr, "-") == 0) { /* connect printer to stdout */ + if (uptr -> flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ + uptr->filename = calloc(CBUFSIZE, sizeof(char)); + strcpy(uptr->filename, "(stdout)"); + uptr->fileref = stdout; + SETBIT(uptr->flags, UNIT_ATT); + uptr->pos = 0; + } + else if ((rval = attach_unit(uptr, cptr)) != SCPE_OK) { + return rval; + } + + fseek(uptr->fileref, 0, SEEK_END); /* if we opened an existing file, append to it */ + + if (IS_1132(uptr)) { + CLRBIT(ILSW[1], ILSW_1_1132_PRINTER); + CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK); + } + else { + CLRBIT(ILSW[4], ILSW_4_1403_PRINTER); + CLRBIT(uptr->flags, UNIT_PARITYCHECK|UNIT_RINGCHECK|UNIT_SYNCCHECK); + } + + SET_ACTION(uptr, 0); + calc_ints(); + + prt_nchar = 0; + prt_nnl = 0; + prt_row = 0; + reset_prt_line(); + + if (IS_1132(uptr)) { + PRT_DSW = (PRT_DSW & ~PRT1132_DSW_CHANNEL_MASK) | cc_format_1132(cctape[prt_row]); + + if (IS_ONLINE(uptr)) + CLRBIT(PRT_DSW, PRT1132_DSW_NOT_READY); + } + else { + CLRBIT(PRT_DSW, PRT1403_DSW_CH9 | PRT1403_DSW_CH12); + if (cctape[prt_row] & CC_CHANNEL_9) + SETBIT(PRT_DSW, PRT1403_DSW_CH9); + if (cctape[prt_row] & CC_CHANNEL_12) + SETBIT(PRT_DSW, PRT1403_DSW_CH12); + + if (IS_ONLINE(uptr)) + CLRBIT(PRT_DSW, PRT1132_DSW_NOT_READY); + } + + forms_check(FALSE); + return SCPE_OK; +} + +static t_stat prt_detach (UNIT *uptr) +{ + t_stat rval; + + flush_prt_line(uptr->fileref, TRUE); + + if (uptr->fileref == stdout) { + CLRBIT(uptr->flags, UNIT_ATT); + free(uptr->filename); + uptr->filename = NULL; + } + else if ((rval = detach_unit(uptr)) != SCPE_OK) + return rval; + + sim_cancel(uptr); + + if (IS_1132(uptr)) { + CLRBIT(ILSW[1], ILSW_1_1132_PRINTER); + CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK); + SETBIT(PRT_DSW, PRT1132_DSW_NOT_READY); + } + else { + CLRBIT(ILSW[4], ILSW_4_1403_PRINTER); + SETBIT(PRT_DSW, PRT1403_DSW_NOT_READY); + } + SET_ACTION(uptr, 0); + + calc_ints(); + + forms_check(FALSE); + return SCPE_OK; +} diff --git a/Ibm1130/ibm1130_prtwheel.h b/Ibm1130/ibm1130_prtwheel.h index b57e5d37..c39c1e59 100644 --- a/Ibm1130/ibm1130_prtwheel.h +++ b/Ibm1130/ibm1130_prtwheel.h @@ -1,20 +1,126 @@ -static struct tag_codewheel { +/* + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org + */ + +struct tag_codewheel { unsigned char ascii; unsigned char ebcdic; -} codewheel1132[] = -{ /* characters and EBCDIC codes in printwheel order */ - 'A', 0xC1, 'B', 0xC2, 'C', 0xC3, 'D', 0xC4, - 'E', 0xC5, 'F', 0xC6, 'G', 0xC7, 'H', 0xC8, - 'I', 0xC9, 'J', 0xD1, 'K', 0xD2, 'L', 0xD3, - 'M', 0xD4, 'N', 0xD5, 'O', 0xD6, 'P', 0xD7, - 'Q', 0xD8, 'R', 0xD9, 'S', 0xE2, 'T', 0xE3, - 'U', 0xE4, 'V', 0xE5, 'W', 0xE6, 'X', 0xE7, - 'Y', 0xE8, 'Z', 0xE9, '0', 0xF0, '1', 0xF1, - '2', 0xF2, '3', 0xF3, '4', 0xF4, '5', 0xF5, - '6', 0xF6, '7', 0xF7, '8', 0xF8, '9', 0xF9, - '&', 0x50, '-', 0x60, '/', 0x61, '.', 0x4B, - '$', 0x5B, ',', 0x6B, '*', 0x5C, '(', 0x4D, - ')', 0x5D, '\'', 0x7D, '+', 0x4E, '=', 0x7E }; -#define WHEELCHARS (sizeof(codewheel1132)/sizeof(codewheel1132[0])) +static struct tag_codewheel codewheel1132[] = +{ /* characters and EBCDIC codes in printwheel order */ + 'A', 0xC1, + 'B', 0xC2, + 'C', 0xC3, + 'D', 0xC4, + 'F', 0xC6, + 'H', 0xC8, + 'I', 0xC9, + 'S', 0xE2, + 'T', 0xE3, + 'U', 0xE4, + 'V', 0xE5, + '1', 0xF1, + '2', 0xF2, + '3', 0xF3, + '4', 0xF4, + '5', 0xF5, + '6', 0xF6, + '7', 0xF7, + '8', 0xF8, + '9', 0xF9, + '0', 0xF0, + '=', 0x7E, + '$', 0x5B, + '.', 0x4B, + '\'', 0x7D, + ',', 0x6B, + ')', 0x5D, + '-', 0x60, + '(', 0x4D, + '+', 0x4E, + '/', 0x61, + '*', 0x5C, + '&', 0x50, + 'J', 0xD1, + 'K', 0xD2, + 'L', 0xD3, + 'M', 0xD4, + 'N', 0xD5, + 'O', 0xD6, + 'P', 0xD7, + 'Q', 0xD8, + 'R', 0xD9, + 'E', 0xC5, + 'G', 0xC7, + 'W', 0xE6, + 'X', 0xE7, + 'Y', 0xE8, + 'Z', 0xE9, +}; + +#define WHEELCHARS_1132 (sizeof(codewheel1132)/sizeof(codewheel1132[0])) + +static struct tag_codewheel codewheel1403[] = +{ + 'A', 0x64, + 'B', 0x25, + 'C', 0x26, + 'D', 0x67, + 'E', 0x68, + 'F', 0x29, + 'G', 0x2A, + 'H', 0x6B, + 'I', 0x2C, + 'J', 0x58, + 'K', 0x19, + 'L', 0x1A, + 'M', 0x5B, + 'N', 0x1C, + 'O', 0x5D, + 'P', 0x5E, + 'Q', 0x1F, + 'R', 0x20, + 'S', 0x0D, + 'T', 0x0E, + 'U', 0x4F, + 'V', 0x10, + 'W', 0x51, + 'X', 0x52, + 'Y', 0x13, + 'Z', 0x54, + '0', 0x49, + '1', 0x40, + '2', 0x01, + '3', 0x02, + '4', 0x43, + '5', 0x04, + '6', 0x45, + '7', 0x46, + '8', 0x07, + '9', 0x08, + ' ', 0x7F, + '.', 0x6E, + '(', 0x57, + '+', 0x6D, + '&', 0x15, + '$', 0x62, + '*', 0x23, + ')', 0x2F, + '-', 0x61, + '/', 0x4C, + ',', 0x16, + '\'', 0x0B, + '=', 0x4A, +}; + +#define WHEELCHARS_1403 (sizeof(codewheel1403)/sizeof(codewheel1403[0])) + + diff --git a/Ibm1130/ibm1130_stddev.c b/Ibm1130/ibm1130_stddev.c index 7d8fa67a..464bb958 100644 --- a/Ibm1130/ibm1130_stddev.c +++ b/Ibm1130/ibm1130_stddev.c @@ -1,36 +1,21 @@ /* ibm1130_stddev.c: IBM 1130 standard I/O devices simulator - Copyright (c) 2001, Brian Knittel - Based on PDP-11 simulator written by Robert M Supnik + Based on the SIMH simulator package written by Robert M Supnik Brian Knittel - Revision History - 31July2001 - Derived from pdp11_stddev.c, which carries this disclaimer: - - Copyright (c) 1993-2001, Robert M Supnik + Revision History: + 2002.09.13 - pulled 1132 printer out of this file into ibm1130_prt.c - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. -*/ + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org + */ #include "ibm1130_defs.h" @@ -50,13 +35,6 @@ void xio_1231_optical (int32 addr, int32 func, int32 modify) {badio("optical m void xio_2501_card (int32 addr, int32 func, int32 modify) {badio("2501 card");} void xio_1131_synch (int32 addr, int32 func, int32 modify) {badio("SCA");} void xio_system7 (int32 addr, int32 func, int32 modify) {badio("System 7");} -void xio_1403_printer (int32 addr, int32 func, int32 modify) {badio("1403 printer");} - -void xio_2250_display (int32 addr, int32 func, int32 modify) -{ - if (func != XIO_CONTROL) - badio("2250 display"); // resmon issues stop control, so ignore XIO_CONTROL -} /* ---------------------------------------------------------------------------- */ @@ -74,13 +52,14 @@ extern t_stat sim_wait_kbd (void); extern t_stat sim_putchar (int32 out); extern UNIT *sim_clock_queue; +extern int cgi; #define CSET_MASK 1 /* character set */ #define CSET_NORMAL 0 #define CSET_ASCII 1 #define IRQ_KEY 0x11 /* ctrl-Q */ -#define PROGRAM_STOP_KEY 0x03 /* ctrl-C */ +#define PROGRAM_STOP_KEY 0x10 /* ctrl-P */ #include "ibm1130_conout.h" /* conout_to_ascii table */ #include "ibm1130_conin.h" /* ascii_to_conin table */ @@ -97,7 +76,7 @@ UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT }; REG tti_reg[] = { { ORDATA (BUF, tti_unit.buf, 8) }, { ORDATA (DSW, tti_dsw, 16) }, - { DRDATA (POS, tti_unit.pos, 32), PV_LEFT }, + { DRDATA (POS, tti_unit.pos, 31), PV_LEFT }, { DRDATA (STIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, { NULL } }; @@ -124,7 +103,7 @@ UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT }; REG tto_reg[] = { { ORDATA (BUF, tto_unit.buf, 8) }, { ORDATA (DSW, tto_dsw, 16) }, - { DRDATA (POS, tto_unit.pos, 32), PV_LEFT }, + { DRDATA (POS, tto_unit.pos, 31), PV_LEFT }, { DRDATA (STIME, tto_unit.wait, 24), PV_LEFT }, { NULL } }; @@ -231,7 +210,7 @@ t_stat tti_svc (UNIT *uptr) } if (temp == PROGRAM_STOP_KEY) { /* simulate the program stop button */ - SETBIT(con_dsw, CON_DSW_PROGRAM_STOP); + SETBIT(con_dsw, CPU_DSW_PROGRAM_STOP); SETBIT(ILSW[5], ILSW_5_PROGRAM_STOP); calc_ints(); @@ -301,8 +280,9 @@ t_stat tto_svc (UNIT *uptr) break; case CRLF: - if ((temp = sim_putchar('\r')) != SCPE_OK) - return temp; + if (! cgi) + if ((temp = sim_putchar('\r')) != SCPE_OK) + return temp; if ((temp = sim_putchar('\n')) != SCPE_OK) return temp; @@ -333,416 +313,4 @@ t_stat tto_reset (DEVICE *dptr) return SCPE_OK; } -/*************************************************************************************** - * 1132 PRINTER - ***************************************************************************************/ -#define PRT_DSW_READ_EMITTER_RESPONSE 0x8000 -#define PRT_DSW_SKIP_RESPONSE 0x4000 -#define PRT_DSW_SPACE_RESPONSE 0x2000 -#define PRT_DSW_CARRIAGE_BUSY 0x1000 -#define PRT_DSW_PRINT_SCAN_CHECK 0x0800 -#define PRT_DSW_NOT_READY 0x0400 -#define PRT_DSW_PRINTER_BUSY 0x0200 - -#define PRT_DSW_CHANNEL_MASK 0x00FF -#define PRT_DSW_CHANNEL_1 0x0080 -#define PRT_DSW_CHANNEL_2 0x0040 -#define PRT_DSW_CHANNEL_3 0x0020 -#define PRT_DSW_CHANNEL_4 0x0010 -#define PRT_DSW_CHANNEL_5 0x0008 -#define PRT_DSW_CHANNEL_6 0x0004 -#define PRT_DSW_CHANNEL_9 0x0002 -#define PRT_DSW_CHANNEL_12 0x0001 - -#define IS_ONLINE(u) (((u)->flags & (UNIT_ATT|UNIT_DIS)) == UNIT_ATT) - -static t_stat prt_svc (UNIT *uptr); -static t_stat prt_reset (DEVICE *dptr); -static t_stat prt_attach (UNIT *uptr, char *cptr); -static t_stat prt_detach (UNIT *uptr); - -static int16 prt_dsw = 0; /* device status word */ -static int32 prt_swait = 500; /* line skip wait */ -static int32 prt_cwait = 1000; /* character rotation wait */ - -#define UNIT_V_FORMCHECK (UNIT_V_UF + 0) /* out of paper error */ -#define UNIT_V_DATACHECK (UNIT_V_UF + 1) /* printer overrun error */ -#define UNIT_V_SKIPPING (UNIT_V_UF + 2) /* printer skipping */ -#define UNIT_V_SPACING (UNIT_V_UF + 3) /* printer is spacing */ -#define UNIT_V_PRINTING (UNIT_V_UF + 4) /* printer printing */ - -#define UNIT_FORMCHECK (1u << UNIT_V_FORMCHECK) -#define UNIT_DATACHECK (1u << UNIT_V_DATACHECK) -#define UNIT_SKIPPING (1u << UNIT_V_SKIPPING) -#define UNIT_SPACING (1u << UNIT_V_SPACING) -#define UNIT_PRINTING (1u << UNIT_V_PRINTING) - -UNIT prt_unit[] = { - { UDATA (&prt_svc, UNIT_ATTABLE, 0) }, -}; - -/* Parameter in the unit descriptor */ - -#define CMD_NONE 0 -#define CMD_SPACE 1 -#define CMD_SKIP 2 -#define CMD_PRINT 3 - -REG prt_reg[] = { - { HRDATA (PRTDSW, prt_dsw, 16) }, /* device status word */ - { DRDATA (STIME, prt_swait, 24), PV_LEFT }, /* line skip wait */ - { DRDATA (CTIME, prt_cwait, 24), PV_LEFT }, /* character rotation wait */ - { NULL } }; - -DEVICE prt_dev = { - "PRT", prt_unit, prt_reg, NULL, - 1, 16, 16, 1, 16, 16, - NULL, NULL, &prt_reset, - NULL, prt_attach, prt_detach}; - -#define PRT_COLUMNS 120 -#define PRT_ROWLEN 120 -#define MAX_OVPRINT 20 - -static char prtbuf[PRT_ROWLEN*MAX_OVPRINT]; -static int nprint[PRT_COLUMNS], ncol[MAX_OVPRINT], maxnp; -static int prt_nchar, prt_row; /* current printwheel position, current page row */ -static int prt_nnl; /* number of queued newlines */ - -#define CC_CHANNEL_1 0x0080 /* carriage control tape punch values */ -#define CC_CHANNEL_2 0x0040 -#define CC_CHANNEL_3 0x0020 -#define CC_CHANNEL_4 0x0010 -#define CC_CHANNEL_5 0x0008 -#define CC_CHANNEL_6 0x0004 -#define CC_CHANNEL_9 0x0002 -#define CC_CHANNEL_12 0x0001 - -#define PRT_PAGELENGTH 66 - -// glunk need to fill these two arrays in -- cctape and codewheel1132 - -static int cctape[PRT_PAGELENGTH]; /* standard carriage control tape */ - -static struct tag_ccpunches { /* list of rows and punches on tape */ - int row, channels; -} ccpunches[] = { - 7, CC_CHANNEL_12, /* these came from the tape in our printer */ - 13, CC_CHANNEL_1 /* modulo 66 */ -}; - -#include "ibm1130_prtwheel.h" - -// reset_prt_line - clear the print line following paper advancement - -static void reset_prt_line (void) -{ - memset(nprint, 0, sizeof(nprint)); - memset(ncol, 0, sizeof(ncol)); - maxnp = 0; -} - -// save_prt_line - fire hammers for character 'ch' - -static t_bool save_prt_line (int ch) -{ - int i, r, addr = 32; - int32 mask = 0, wd = 0; - - for (i = 0; i < PRT_COLUMNS; i++) { - if (mask == 0) { // fetch next word from memory - mask = 0x8000; - wd = M[addr++]; - } - - if (wd & mask) { // hammer is to fire in this column - if ((r = nprint[i]) < MAX_OVPRINT) { - if (ncol[r] <= i) { // we haven't moved this far yet - if (ncol[r] == 0) // first char in this row? - memset(prtbuf+r*PRT_ROWLEN, ' ', PRT_COLUMNS); // blank out the new row - ncol[r] = i+1; // remember new row length - } - prtbuf[r*PRT_ROWLEN + i] = (char) ch; // save the character - - nprint[i]++; // remember max overprintings for this column - maxnp = MAX(maxnp, nprint[i]); - } - } - - mask >>= 1; // prepare to examine next bit - } - - return wd & 1; // return TRUE if the last word has lsb set, which means all bits had been set -} - -// write_line - write collected line to output file. No need to trim spaces as the hammers -// are never fired for them, so ncol[r] is the last printed position on each line. - -static void flush_prt_line (FILE *fd, t_bool space) -{ - int r; - - if (! (space || maxnp)) // nothing to do - return; - - prt_row = (prt_row+1) % PRT_PAGELENGTH; // NEXT line - - if (space && ! maxnp) { // spacing only - if (prt_row == 0 && prt_nnl) { - putc('\f', fd); - prt_nnl = 0; - } - else - prt_nnl++; - - return; - } - - if (prt_nnl) { // there are queued newlines - if (prt_row == 0 && prt_nnl) { // we spaced to top of form: use formfeed - putc('\f', fd); - prt_nnl = 0; - } - else { - while (prt_nnl > 0) { // spit out queued newlines -#ifdef WIN32 - putc('\r', fd); // DOS/Windows: end with cr/lf -#endif - putc('\n', fd); // otherwise end with lf - prt_nnl--; - } - } - } - - for (r = 0; r < maxnp; r++) { - if (r > 0) - putc('\r', fd); // carriage return between overprinted lines - fwrite(&prtbuf[r*PRT_ROWLEN], 1, ncol[r], fd); - } - - reset_prt_line(); - - prt_nnl++; // queue a newline -} - -#define PRT_CMD_START_PRINTER 0x0080 -#define PRT_CMD_STOP_PRINTER 0x0040 -#define PRT_CMD_START_CARRIAGE 0x0004 -#define PRT_CMD_STOP_CARRIAGE 0x0002 -#define PRT_CMD_SPACE 0x0001 - -#define PRT_CMD_MASK 0x00C7 - -/* xio_1132_printer - XIO command interpreter for the 1132 printer */ - -void xio_1132_printer (int32 iocc_addr, int32 func, int32 modify) -{ - char msg[80]; - UNIT *uptr = &prt_unit[0]; - - switch (func) { - case XIO_READ: - M[iocc_addr & mem_mask] = codewheel1132[prt_nchar].ebcdic << 8; - - if ((uptr->flags & UNIT_PRINTING) == 0) /* if we're not printing, advance this after every test */ - prt_nchar = (prt_nchar + 1) % WHEELCHARS; - break; - - case XIO_SENSE_DEV: - ACC = prt_dsw; - if (modify & 0x01) { /* reset interrupts */ - CLRBIT(prt_dsw, PRT_DSW_READ_EMITTER_RESPONSE | PRT_DSW_SKIP_RESPONSE | PRT_DSW_SPACE_RESPONSE); - CLRBIT(ILSW[1], ILSW_1_1132_PRINTER); - } - break; - - case XIO_CONTROL: - if (modify & PRT_CMD_START_PRINTER) - SETBIT(uptr->flags, UNIT_PRINTING); - - if (modify & PRT_CMD_STOP_PRINTER) - CLRBIT(uptr->flags, UNIT_PRINTING); - - if (modify & PRT_CMD_START_CARRIAGE) - SETBIT(uptr->flags, UNIT_SKIPPING); - - if (modify & PRT_CMD_STOP_CARRIAGE) - CLRBIT(uptr->flags, UNIT_SKIPPING); - - if (modify & PRT_CMD_SPACE) - SETBIT(uptr->flags, UNIT_SPACING); - - sim_cancel(uptr); - if (uptr->flags & PRT_CMD_MASK) { // busy bit = doing something - SETBIT(prt_dsw, PRT_DSW_PRINTER_BUSY); - sim_activate(uptr, prt_cwait); - } - else - CLRBIT(prt_dsw, PRT_DSW_PRINTER_BUSY); - - if (uptr->flags & (UNIT_SKIPPING|UNIT_SPACING)) - SETBIT(prt_dsw, PRT_DSW_CARRIAGE_BUSY); - else - CLRBIT(prt_dsw, PRT_DSW_CARRIAGE_BUSY); - - if ((uptr->flags & (UNIT_SKIPPING|UNIT_SPACING)) == (UNIT_SKIPPING|UNIT_SPACING)) { - sprintf(msg, "1132 printer skip and space at same time?"); - xio_error(msg); - } - break; - - default: - sprintf(msg, "Invalid 1132 printer XIO function %x", func); - xio_error(msg); - } -} - -#define SET_ACTION(u,a) {(u)->flags &= ~(UNIT_SKIPPING|UNIT_SPACING|UNIT_PRINTING); (u)->flags |= a;} - -static t_stat prt_svc (UNIT *uptr) -{ - if (prt_dsw & PRT_DSW_NOT_READY) { // cancel operation if printer went offline - SETBIT(uptr->flags, UNIT_FORMCHECK); - SET_ACTION(uptr, 0); - forms_check(TRUE); // and turn on forms check lamp - return SCPE_OK; - } - - if (uptr->flags & UNIT_SPACING) { - flush_prt_line(uptr->fileref, TRUE); - - prt_dsw = prt_dsw & ~PRT_DSW_CHANNEL_MASK; - prt_dsw |= cctape[prt_row]; - - SETBIT(prt_dsw, PRT_DSW_SPACE_RESPONSE); - SETBIT(ILSW[1], ILSW_1_1132_PRINTER); - calc_ints(); - - CLRBIT(uptr->flags, UNIT_SPACING); // done with this - CLRBIT(prt_dsw, PRT_DSW_PRINTER_BUSY|PRT_DSW_CARRIAGE_BUSY); - } - - if (uptr->flags & UNIT_SKIPPING) { - do { - flush_prt_line(uptr->fileref, TRUE); - prt_dsw = (prt_dsw & ~PRT_DSW_CHANNEL_MASK) | cctape[prt_row]; - } while (cctape[prt_row] == 0); // slew directly to a cc tape punch - - SETBIT(prt_dsw, PRT_DSW_SKIP_RESPONSE); - SETBIT(ILSW[1], ILSW_1_1132_PRINTER); - calc_ints(); - } - - if (uptr->flags & UNIT_PRINTING) { - if (! save_prt_line(codewheel1132[prt_nchar].ascii)) { // save previous printed line - SETBIT(uptr->flags, UNIT_DATACHECK); // buffer wasn't set in time - SET_ACTION(uptr, 0); - print_check(TRUE); // and turn on forms check lamp - return SCPE_OK; - } - - prt_nchar = (prt_nchar + 1) % WHEELCHARS; // advance print drum - - SETBIT(prt_dsw, PRT_DSW_READ_EMITTER_RESPONSE); // issue interrupt to tell printer to set buffer - SETBIT(ILSW[1], ILSW_1_1132_PRINTER); // we'll save the printed stuff just before next emitter response (later than on real 1130) - calc_ints(); - } - - if (uptr->flags & (UNIT_SPACING|UNIT_SKIPPING|UNIT_PRINTING)) { // still doing something - SETBIT(prt_dsw, PRT_DSW_PRINTER_BUSY); - sim_activate(uptr, prt_cwait); - } - else - CLRBIT(prt_dsw, PRT_DSW_PRINTER_BUSY); - - return SCPE_OK; -} - -static t_stat prt_reset (DEVICE *dptr) -{ - UNIT *uptr = &prt_unit[0]; - int i; - - sim_cancel(uptr); - - memset(cctape, 0, sizeof(cctape)); // copy punch list into carriage control tape image - for (i = 0; i < (sizeof(ccpunches)/sizeof(ccpunches[0])); i++) - cctape[ccpunches[i].row-1] |= ccpunches[i].channels; - - CLRBIT(ILSW[1], ILSW_1_1132_PRINTER); - CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK); - SET_ACTION(uptr, 0); - calc_ints(); - - prt_nchar = 0; - prt_row = 0; - prt_nnl = 0; - prt_dsw = cctape[prt_row]; - reset_prt_line(); - - if (! IS_ONLINE(uptr)) - SETBIT(prt_dsw, PRT_DSW_NOT_READY); - - forms_check(FALSE); - return SCPE_OK; -} - -static t_stat prt_attach (UNIT *uptr, char *cptr) -{ - t_stat rval; - - if (uptr->flags & UNIT_ATT) { - if ((rval = prt_detach(uptr)) != SCPE_OK) { - prt_dsw |= PRT_DSW_NOT_READY; - return rval; - } - } - - sim_cancel(uptr); - - if ((rval = attach_unit(uptr, cptr)) != SCPE_OK) { - prt_dsw |= PRT_DSW_NOT_READY; - return rval; - } - - CLRBIT(ILSW[1], ILSW_1_1132_PRINTER); - CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK); - SET_ACTION(uptr, 0); - calc_ints(); - - prt_nchar = 0; - prt_nnl = 0; - prt_row = 0; - prt_dsw = (prt_dsw & ~PRT_DSW_CHANNEL_MASK) | cctape[prt_row]; - if (IS_ONLINE(uptr)) - CLRBIT(prt_dsw, PRT_DSW_NOT_READY); - else - SETBIT(prt_dsw, PRT_DSW_NOT_READY); - - reset_prt_line(); - forms_check(FALSE); - return SCPE_OK; -} - -static t_stat prt_detach (UNIT *uptr) -{ - t_stat rval; - - flush_prt_line(uptr->fileref, FALSE); - - if ((rval = detach_unit(uptr)) != SCPE_OK) - return rval; - - sim_cancel(uptr); - - CLRBIT(ILSW[1], ILSW_1_1132_PRINTER); - CLRBIT(uptr->flags, UNIT_FORMCHECK|UNIT_DATACHECK); - SET_ACTION(uptr, 0); - calc_ints(); - - SETBIT(prt_dsw, PRT_DSW_NOT_READY); - - forms_check(FALSE); - return SCPE_OK; -} diff --git a/Ibm1130/ibm1130_sys.c b/Ibm1130/ibm1130_sys.c index f46a7864..0a382e45 100644 --- a/Ibm1130/ibm1130_sys.c +++ b/Ibm1130/ibm1130_sys.c @@ -1,9 +1,11 @@ /* ibm1130_sys.c: IBM 1130 simulator interface - Copyright (c) 2002, Brian Knittel Based on PDP-11 simulator written by Robert M Supnik Revision History + 0.26 2002Apr24 - Added !BREAK in card deck file to stop simulator + 0.25 2002Apr18 - Fixed some card reader problems. It starts the reader + properly if you attach a deck while it's waiting to a read. 0.24 2002Mar27 - Fixed BOSC bug; BOSC works in short instructions too 0.23 2002Feb26 - Added @decklist feature for ATTACH CR. 0.22 2002Feb26 - Replaced "strupr" with "upcase" for compatibility. @@ -11,36 +13,26 @@ bugs 0.01 2001Jul31 - Derived from pdp11_sys.c, which carries this disclaimer: - Copyright (c) 1993-2001, Robert M Supnik - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. -*/ + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org + */ #include "ibm1130_defs.h" #include +#include extern DEVICE cpu_dev, console_dev, dsk_dev, cr_dev, cp_dev; extern DEVICE tti_dev, tto_dev, prt_dev, log_dev; -extern UNIT cpu_unit; -extern REG cpu_reg[]; +extern DEVICE gdu_dev, console_dev; + +extern UNIT cpu_unit; +extern REG cpu_reg[]; extern int32 saved_PC; /* SCP data structures and interface routines @@ -54,7 +46,7 @@ extern int32 saved_PC; */ char sim_name[] = "IBM 1130"; -char sim_version[] = "V0.24"; +char sim_version[] = "V0.30"; REG *sim_PC = &cpu_reg[0]; @@ -62,16 +54,14 @@ int32 sim_emax = 4; DEVICE *sim_devices[] = { &cpu_dev, /* the cpu */ - &log_dev, /* cpu logging virtual device */ -#ifdef GUI_SUPPORT - &console_dev, /* console display (windows GUI) */ -#endif &dsk_dev, /* disk drive(s) */ &cr_dev, /* card reader/punch */ &cp_dev, &tti_dev, /* console keyboard, selectric printer */ &tto_dev, &prt_dev, /* 1132 printer */ + &console_dev, /* console display (windows GUI) */ + &gdu_dev, /* 2250 display */ NULL }; @@ -81,6 +71,11 @@ const char *sim_stop_messages[] = { "Invalid command", "Simulator breakpoint", "Use of incomplete simulator function", + "Power off", + "!BREAK in card deck file", + "Phase load break", + "Program has run amok", + "Run time limit exceeded" }; /* Loader. IPL is normally performed by card reader (boot command). This function @@ -238,7 +233,7 @@ static char *opcode[] = { "?00 ", "XIO ", "SLA ", "SRA ", "LDS ", "STS ", "WAIT", "?07 ", "BSI ", "BSC ", "?0A ", "?0B ", - "LDX ", "STD ", "MDX ", "?0F ", + "LDX ", "STX ", "MDX ", "?0F ", "A ", "AD ", "S ", "SD ", "M ", "D ", "?16 ", "?17 ", "LD ", "LDD ", "STO ", "STD ", @@ -260,23 +255,56 @@ static char *lsopcode[] = {"SLA ", "SLCA ", "SLT ", "SLC "}; static char *rsopcode[] = {"SRA ", "?188 ", "SRT ", "RTE "}; static char tagc[] = " 123"; +static int ascii_to_ebcdic_table[128] = +{ + 0x00,0x01,0x02,0x03,0x37,0x2d,0x2e,0x2f, 0x16,0x05,0x25,0x0b,0x0c,0x0d,0x0e,0x0f, + 0x10,0x11,0x12,0x13,0x3c,0x3d,0x32,0x26, 0x18,0x19,0x3f,0x27,0x1c,0x1d,0x1e,0x1f, + 0x40,0x5a,0x7f,0x7b,0x5b,0x6c,0x50,0x7d, 0x4d,0x5d,0x5c,0x4e,0x6b,0x60,0x4b,0x61, + 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, 0xf8,0xf9,0x7a,0x5e,0x4c,0x7e,0x6e,0x6f, + + 0x7c,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, 0xc8,0xc9,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6, + 0xd7,0xd8,0xd9,0xe2,0xe3,0xe4,0xe5,0xe6, 0xe7,0xe8,0xe9,0xba,0xe0,0xbb,0xb0,0x6d, + 0x79,0x81,0x82,0x83,0x84,0x85,0x86,0x87, 0x88,0x89,0x91,0x92,0x93,0x94,0x95,0x96, + 0x97,0x98,0x99,0xa2,0xa3,0xa4,0xa5,0xa6, 0xa7,0xa8,0xa9,0xc0,0x4f,0xd0,0xa1,0x07, +}; + +static int ebcdic_to_ascii (int ch) +{ + int j; + + for (j = 32; j < 128; j++) + if (ascii_to_ebcdic_table[j] == ch) + return j; + + return '?'; +} + t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) { - int32 cflag, c1, c2, OP, F, TAG, INDIR, DSPLC, IR, eaddr; + int32 cflag, ch, OP, F, TAG, INDIR, DSPLC, IR, eaddr; char *mnem, tst[12]; cflag = (uptr == NULL) || (uptr == &cpu_unit); - c1 = val[0] & 0177; - c2 = (val[0] >> 8) & 0177; - if (sw & SWMASK ('A')) { /* ASCII? */ - fprintf (of, (c1 < 040)? "<%03o>": "%c", c1); +// if (sw & SWMASK ('A')) { /* ASCII? not useful */ +// fprintf (of, (c1 < 040)? "<%03o>": "%c", c1); +// return SCPE_OK; +// } + + if (sw & SWMASK ('C')) /* character? not useful -- make it EBCDIC */ + sw |= SWMASK('E'); + + if (sw & SWMASK ('E')) { /* EBCDIC! */ + ch = ebcdic_to_ascii((val[0] >> 8) & 0xFF); /* take high byte first */ + fprintf (of, (ch < ' ')? "<%03o>": "%c", ch); + ch = ebcdic_to_ascii(val[0] & 0xFF); + fprintf (of, (ch < ' ')? "<%03o>": "%c", ch); return SCPE_OK; } - if (sw & SWMASK ('C')) { /* character? */ - fprintf (of, (c1 < 040)? "<%03o>": "%c", c1); - fprintf (of, (c2 < 040)? "<%03o>": "%c", c2); + if (sw & SWMASK ('H')) { /* HOLLERITH! now THIS is useful! */ + ch = hollerith_to_ascii((int16) val[0]); + fprintf (of, (ch < ' ')? "<%03o>": "%c", ch); return SCPE_OK; } @@ -320,8 +348,8 @@ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) DSPLC &= 0x003F; eaddr = DSPLC; } - else if (OP == 0x09) { - if (IR & 0x40) + else if ((OP == 0x08 && F)|| OP == 0x09) { // BSI L and BSC any + if (OP == 0x09 && (IR & 0x40)) mnem = "BOSC"; tst[0] = '\0'; @@ -414,3 +442,54 @@ t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) { return SCPE_ARG; } + +#ifndef WIN32 + +int strnicmp (char *a, char *b, int n) +{ + int ca, cb; + + for (;;) { + if (--n < 0) // still equal after n characters? quit now + return 0; + + if ((ca = *a) == 0) // get character, stop on null terminator + return *b ? -1 : 0; + + if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase + ca -= 32; + + cb = *b; + if (cb >= 'a' && cb <= 'z') + cb -= 32; + + if ((ca -= cb) != 0) // if different, return comparison + return ca; + + a++, b++; + } +} + +int strcmpi (char *a, char *b) +{ + int ca, cb; + + for (;;) { + if ((ca = *a) == 0) // get character, stop on null terminator + return *b ? -1 : 0; + + if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase + ca -= 32; + + cb = *b; + if (cb >= 'a' && cb <= 'z') + cb -= 32; + + if ((ca -= cb) != 0) // if different, return comparison + return ca; + + a++, b++; + } +} + +#endif diff --git a/Ibm1130/makefile b/Ibm1130/makefile new file mode 100644 index 00000000..e00a5af5 --- /dev/null +++ b/Ibm1130/makefile @@ -0,0 +1,72 @@ +# (This makefile is for operating systems other than Windows, +# or compilers other than Microsoft's. For MS builds, use the +# .mak files found in this directory and the utils directory). +# +# If you are building the emulator and utilities as part of +# the SIMH package, please: +# +# Be sure that you there are NO copies of scp.c, scp_tty.c, +# sim_sock.c, sim_tmxr.c, sim_rev.h, sim_defs.h, sim_sock.h and +# sim_tmxr.h in the ibm1130 subdirectory. Delete them if there +# are. +# +# Do not use this makefile with "make all" or "make ibm1130". +# Use the SIMH build files instead. +# +# If and when you download updates for this simulator from +# www.ibm1130.org, get ibm1130code.zip and ibm1130software.zip +# separately. +# +# If you have downloaded the emulator independently of SIMH (e.g, from +# www.ibm1130.org), please: +# +# Be sure that you DO have copies of scp.c, scp_tty.c, sim_sock.c, +# sim_tmxr.c, sim_rev.h, sim_defs.h, sim_sock.h and sim_tmxr.h +# in this folder. +# +# Use this file to make the emulator. +# +# If and when you download updates for this simulator from +# www.ibm1130.org, get ibm1130.zip. When you expand it, +# also expand ibm1130sofware.zip, which is inside. +# +# In either case, if you want to build DMS or work with assembly +# language programs outside of DMS, you'll want to make the utilities +# by cd'ing to the utils directory and running make there. + +# CC Command +# +# Note: -O2 is sometimes broken in GCC when setjump/longjump is being +# used. Try -O2 only with released simulators. +# +CC = gcc -O0 -lm -I . +#CC = gcc -O2 -g -lm -I . + + +# +# Common Libraries +# +BIN = +SIM = scp.c scp_tty.c sim_sock.c sim_tmxr.c +SIM_INC = sim_defs.h sim_rev.h sim_sock.h sim_tmxr.h + +# +# Emulator source files and compile time options +# + +ibm1130D = ./ +ibm1130 = ${ibm1130D}ibm1130_sys.c ${ibm1130D}ibm1130_cpu.c \ + ${ibm1130D}ibm1130_cr.c ${ibm1130D}ibm1130_disk.c \ + ${ibm1130D}ibm1130_stddev.c ${ibm1130D}ibm1130_gdu.c \ + ${ibm1130D}ibm1130_gui.c ${ibm1130D}ibm1130_prt.c +ibm1130_INC = ibm1130res.h ibm1130_conin.h ibm1130_conout.h \ + ibm1130_defs.h ibm1130_prtwheel.h \ + dmsr2v12phases.h dmsr2v12slet.h + +# +# Build the emulator +# + +${BIN}ibm1130 : ${ibm1130} ${SIM} ${ibm1130_INC} ${SIM_INC} + ${CC} ${ibm1130} ${SIM} -o $@ + diff --git a/Ibm1130/mkboot.c b/Ibm1130/mkboot.c new file mode 100644 index 00000000..d945d63c --- /dev/null +++ b/Ibm1130/mkboot.c @@ -0,0 +1,705 @@ +/* + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org + */ + +// --------------------------------------------------------------------------------- +// MKBOOT - reads card loader format cards and produces an absolute core image that +// can then be dumped out in 1130 IPL, 1800 IPL or Core Image loader formats. +// +// Usage: mkboot [-v] binfile outfile [1130|1800|core [loaddr [hiaddr [ident]]]]" +// +// Arguments: +// binfile - name of assembler output file (card loader format, absolute output) +// outfile - name of output file to create +// mode - output mode, default is 1130 IPL format +// loaddr - low address to dump. Default is lowest address loaded from binfile +// hiaddr - high address to dump. Defult is highest address loaded from binfile +// ident - ident string to write in last 8 columns. Omit when when writing an +// 1130 IPL card that requires all 80 columns of data. +// +// Examples: +// mkboot somefile.bin somefile.ipl 1130 +// +// loads somefile.bin, writes object in 1130 IPL format to somefile.ipl +// Up to 80 columns will be written depending on what the object actually uses +// +// mkboot somefile.bin somefile.ipl 1130 0 48 SOMEF +// +// loads somefile.bin. Writes 72 columns (hex 48), with ident columns 73-80 = SOMEF001 +// +// mkboot somefile.bin somefile.dat core 0 0 SOMEF001 +// +// loads somefile.bin and writes a core image format deck with ident SOMEF001, SOMEF002, etc +// +// For other examples of usage, see MKDMS.BAT +// +// 1.00 - 2002Apr18 - first release. Tested only under Win32. The core image +// loader format is almost certainly wrong. Cannot handle +// relocatable input decks, but it works well enough to +// load DSYSLDR1 which is what we are after here. +// --------------------------------------------------------------------------------- + +#include +#include +#include +#include + +#ifndef TRUE + #define BOOL int + #define TRUE 1 + #define FALSE 0 +#endif + +#ifndef WIN32 + int strnicmp (char *a, char *b, int n); + int strcmpi (char *a, char *b); +#endif + +#define BETWEEN(v,a,b) (((v) >= (a)) && ((v) <= (b))) +#define MIN(a,b) (((a) <= (b)) ? (a) : (b)) +#define MAX(a,b) (((a) >= (b)) ? (a) : (b)) + +#define MAXADDR 4096 + +typedef enum {R_ABSOLUTE = 0, R_RELATIVE = 1, R_LIBF = 2, R_CALL = 3} RELOC; + +typedef enum {B_1130, B_1800, B_CORE} BOOTMODE; + +BOOL verbose = FALSE; +char *infile = NULL, *outfile = NULL; +BOOTMODE mode = B_1130; +int addr_from = 0, addr_to = 79; +int outcols = 0; // columns written in using card output +int maxiplcols = 80; +char cardid[9]; // characters used for IPL card ID +int pta = 0; +int load_low = 0x7FFFFFF; +int load_high = 0; +unsigned short mem[MAXADDR]; // small core! + +// mkboot - load a binary object deck into core and dump requested bytes as a boot card + +void bail (char *msg); +void verify_checksum(unsigned short *card); +char *upcase (char *str); +void unpack (unsigned short *card, unsigned short *buf); +void dump (char *fname); +void loaddata (char *fname); +void write_1130 (void); +void write_1800 (void); +void write_core (void); +void flushcard(void); +int ascii_to_hollerith (int ch); +void corecard_init (void); +void corecard_writecard (char *sbrk_text); +void corecard_writedata (void); +void corecard_flush (void); +void corecard_setorg (int neworg); +void corecard_writew (int word, RELOC relative); +void corecard_endcard (void); + +char *fname = NULL; +FILE *fout; + +int main (int argc, char **argv) +{ + char *arg; + static char usestr[] = "Usage: mkboot [-v] binfile outfile [1130|1800|core [loaddr [hiaddr [ident]]]]"; + int i, ano = 0, ok; + + for (i = 1; i < argc; i++) { + arg = argv[i]; + if (*arg == '-') { + arg++; + while (*arg) { + switch (*arg++) { + case 'v': + verbose = TRUE; + break; + default: + bail(usestr); + } + } + } + else { + switch (ano++) { + case 0: + infile = arg; + break; + + case 1: + outfile = arg; + break; + + case 2: + if (strcmp(arg, "1130") == 0) mode = B_1130; + else if (strcmp(arg, "1800") == 0) mode = B_1800; + else if (strcmpi(arg, "core") == 0) mode = B_CORE; + else bail(usestr); + break; + + case 3: + if (strnicmp(arg, "0x", 2) == 0) ok = sscanf(arg+2, "%x", &addr_from); + else if (arg[0] == '/') ok = sscanf(arg+1, "%x", &addr_from); + else ok = sscanf(arg, "%d", &addr_from); + if (ok != 1) bail(usestr); + break; + + case 4: + if (strnicmp(arg, "0x", 2) == 0) ok = sscanf(arg+2, "%x", &addr_to); + else if (arg[0] == '/') ok = sscanf(arg+1, "%x", &addr_to); + else ok = sscanf(arg, "%d", &addr_to); + if (ok != 1) bail(usestr); + break; + + case 5: + strncpy(cardid, arg, 9); + cardid[8] = '\0'; + upcase(cardid); + break; + + default: + bail(usestr); + } + } + } + + if (*cardid == '\0') + maxiplcols = (mode == B_1130) ? 80 : 72; + else { + while (strlen(cardid) < 8) + strcat(cardid, "0"); + maxiplcols = 72; + } + + loaddata(infile); + + if (mode == B_1800) + write_1800(); + else if (mode == B_CORE) + write_core(); + else + write_1130(); + + return 0; +} + +void write_1130 (void) +{ + int addr; + unsigned short word; + + if ((fout = fopen(outfile, "wb")) == NULL) { + perror(outfile); + exit(1); + } + + for (addr = addr_from; addr <= addr_to; addr++) { + if (outcols >= maxiplcols) + flushcard(); + + word = mem[addr]; + + // if F or L bits are set, or if high 2 bits of displacement are unequal, it's bad + if ((word & 0x0700) || ! (((word & 0x00C0) == 0) || ((word & 0x00C0) == 0x00C0))) + printf("Warning: word %04x @ %04x may not IPL properly\n", word & 0xFFFF, addr); + + word = ((word & 0xF800) >> 4) | (word & 0x7F); // convert to 1130 IPL format + + putc((word & 0x000F) << 4, fout); // write the 12 bits in little-endian binary AABBCC00 as CC00 AABB + putc((word & 0x0FF0) >> 4, fout); + outcols++; + } + flushcard(); + fclose(fout); +} + +void write_1800 (void) +{ + int addr; + unsigned short word; + + if ((fout = fopen(outfile, "wb")) == NULL) { + perror(outfile); + exit(1); + } + + for (addr = addr_from; addr <= addr_to; addr++) { + word = mem[addr]; + + if (outcols >= maxiplcols) + flushcard(); + + putc(0, fout); + putc(word & 0xFF, fout); // write the low 8 bits in little-endian binary + outcols++; + + putc(0, fout); + putc((word >> 8) & 0xFF, fout); // write the high 8 bits in little-endian binary + outcols++; + } + flushcard(); + fclose(fout); +} + +void write_core (void) +{ + int addr; + + if ((fout = fopen(outfile, "wb")) == NULL) { + perror(outfile); + exit(1); + } + + addr_from = load_low; + addr_to = load_high; + + maxiplcols = 72; + corecard_init(); + corecard_setorg(addr_from); + + for (addr = addr_from; addr <= addr_to; addr++) { + corecard_writew(mem[addr], 0); + } + + corecard_flush(); + corecard_endcard(); + fclose(fout); +} + +void flushcard (void) +{ + int i, hol, ndig; + char fmt[20], newdig[20]; + + if (outcols <= 0) + return; // nothing to flush + + while (outcols < maxiplcols) { // pad to required number of columns with blanks (no punches) + putc(0, fout); + putc(0, fout); + outcols++; + } + + if (*cardid) { // add label + for (i = 0; i < 8; i++) { // write label as specified + hol = ascii_to_hollerith(cardid[i] & 0x7F); + putc(hol & 0xFF, fout); + putc((hol >> 8) & 0xFF, fout); + } + + ndig = 0; // count trailing digits in the label + for (i = 8; --i >= 0; ndig++) + if (! isdigit(cardid[i])) + break; + + i++; // index of first digit in trailing sequence + + if (ndig > 0) { // if any, increment them + sprintf(fmt, "%%0%dd", ndig); // make, e.g. %03d + sprintf(newdig, fmt, atoi(cardid+i)+1); + newdig[ndig] = '\0'; // clip if necessary + strcpy(cardid+i, newdig); // replace for next card's sequence number + } + } + + outcols = 0; +} + +void show_data (unsigned short *buf) +{ + int i, n, jrel, rflag, nout, ch, reloc; + + n = buf[2] & 0x00FF; + + printf("%04x: ", buf[0]); + + jrel = 3; + nout = 0; + rflag = buf[jrel++]; + for (i = 0; i < n; i++) { + if (nout >= 8) { + rflag = buf[jrel++]; + putchar('\n'); + printf(" "); + nout = 0; + } + reloc = (rflag >> 14) & 0x03; + ch = (reloc == R_ABSOLUTE) ? ' ' : + (reloc == R_RELATIVE) ? 'R' : + (reloc == R_LIBF) ? 'L' : '@'; + + printf("%04x%c ", buf[9+i], ch); + rflag << 2; + nout++; + } + putchar('\n'); +} + +void loadcard (unsigned short *buf) +{ + int addr, n, i; + + addr = buf[0]; + n = buf[2] & 0x00FF; + + for (i = 0; i < n; i++) { + if (addr >= MAXADDR) + bail("Program doesn't fit into 4K"); + mem[addr] = buf[9+i]; + + load_low = MIN(addr, load_low); + load_high = MAX(addr, load_high); + addr++; + } +} + +void loaddata (char *fname) +{ + FILE *fp; + BOOL first = TRUE; + unsigned short card[80], buf[54], cardtype; + + if ((fp = fopen(fname, "rb")) == NULL) { + perror(fname); + exit(1); + } + + if (verbose) + printf("\n%s:\n", fname); + + while (fread(card, sizeof(card[0]), 80, fp) > 0) { + unpack(card, buf); + verify_checksum(card); + + cardtype = (buf[2] >> 8) & 0xFF; + + if (cardtype == 1 && ! first) { // sector break + if (verbose) + printf("*SBRK\n"); + continue; + } + else { + switch (cardtype) { + case 0x01: + if (verbose) + printf("*ABS\n"); + break; + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + bail("Data must be in absolute format"); + break; + + case 0x0F: + pta = buf[3]; // save program transfer address + if (verbose) + printf("*END\n"); + break; + + case 0x0A: + if (verbose) + show_data(buf); + loadcard(buf); + break; + default: + bail("Unexpected card type"); + } + } + first = FALSE; + } + + fclose(fp); +} + +void bail (char *msg) +{ + fprintf(stderr, "%s\n", msg); + exit(1); +} + +void unpack (unsigned short *card, unsigned short *buf) +{ + int i, j; + unsigned short wd1, wd2, wd3, wd4; + + for (i = j = 0; i < 54; i += 3, j += 4) { + wd1 = card[j]; + wd2 = card[j+1]; + wd3 = card[j+2]; + wd4 = card[j+3]; + + buf[i ] = (wd1 & 0xFFF0) | ((wd2 >> 12) & 0x000F); + buf[i+1] = ((wd2 << 4) & 0xFF00) | ((wd3 >> 8) & 0x00FF); + buf[i+2] = ((wd3 << 8) & 0xF000) | ((wd4 >> 4) & 0x0FFF); + } +} + +void verify_checksum (unsigned short *card) +{ +// unsigned short sum; + + if (card[1] == 0) // no checksum + return; + +// if (sum != card[1]) +// printf("Checksum %04x doesn't match card %04x\n", sum, card[1]); +} + +typedef struct { + int hollerith; + char ascii; +} CPCODE; + +static CPCODE cardcode_029[] = +{ + 0x0000, ' ', + 0x8000, '&', // + in 026 Fortran + 0x4000, '-', + 0x2000, '0', + 0x1000, '1', + 0x0800, '2', + 0x0400, '3', + 0x0200, '4', + 0x0100, '5', + 0x0080, '6', + 0x0040, '7', + 0x0020, '8', + 0x0010, '9', + 0x9000, 'A', + 0x8800, 'B', + 0x8400, 'C', + 0x8200, 'D', + 0x8100, 'E', + 0x8080, 'F', + 0x8040, 'G', + 0x8020, 'H', + 0x8010, 'I', + 0x5000, 'J', + 0x4800, 'K', + 0x4400, 'L', + 0x4200, 'M', + 0x4100, 'N', + 0x4080, 'O', + 0x4040, 'P', + 0x4020, 'Q', + 0x4010, 'R', + 0x3000, '/', + 0x2800, 'S', + 0x2400, 'T', + 0x2200, 'U', + 0x2100, 'V', + 0x2080, 'W', + 0x2040, 'X', + 0x2020, 'Y', + 0x2010, 'Z', + 0x0820, ':', + 0x0420, '#', // = in 026 Fortran + 0x0220, '@', // ' in 026 Fortran + 0x0120, '\'', + 0x00A0, '=', + 0x0060, '"', + 0x8820, 'c', // cent + 0x8420, '.', + 0x8220, '<', // ) in 026 Fortran + 0x8120, '(', + 0x80A0, '+', + 0x8060, '|', + 0x4820, '!', + 0x4420, '$', + 0x4220, '*', + 0x4120, ')', + 0x40A0, ';', + 0x4060, 'n', // not + 0x2820, 'x', // what? + 0x2420, ',', + 0x2220, '%', // ( in 026 Fortran + 0x2120, '_', + 0x20A0, '>', + 0x2060, '>', +}; + +int ascii_to_hollerith (int ch) +{ + int i; + + for (i = 0; i < sizeof(cardcode_029) / sizeof(CPCODE); i++) + if (cardcode_029[i].ascii == ch) + return cardcode_029[i].hollerith; + + return 0; +} + +// --------------------------------------------------------------------------------- +// corecard - routines to write IBM 1130 Card object format +// --------------------------------------------------------------------------------- + +unsigned short corecard[54]; // the 54 data words that can fit on a binary format card +int corecard_n = 0; // number of object words stored in corecard (0-45) +int corecard_seq = 1; // card output sequence number +int corecard_org = 0; // origin of current card-full +int corecard_maxaddr = 0; +BOOL corecard_first = TRUE; // TRUE when we're to write the program type card + +// corecard_init - prepare a new object data output card + +void corecard_init (void) +{ + memset(corecard, 0, sizeof(corecard)); // clear card data + corecard_n = 0; // no data + corecard[0] = corecard_org; // store load address + corecard_maxaddr = MAX(corecard_maxaddr, corecard_org-1); // save highest address written-to (this may be a BSS) +} + +// binard_writecard - emit a card. sbrk_text = NULL for normal data cards, points to comment text for sbrk card + +void corecard_writecard (char *sbrk_text) +{ + unsigned short binout[80]; + int i, j; + + for (i = j = 0; i < 54; i += 3, j += 4) { + binout[j ] = ( corecard[i] & 0xFFF0); + binout[j+1] = ((corecard[i] << 12) & 0xF000) | ((corecard[i+1] >> 4) & 0x0FF0); + binout[j+2] = ((corecard[i+1] << 8) & 0xFF00) | ((corecard[i+2] >> 8) & 0x00F0); + binout[j+3] = ((corecard[i+2] << 4) & 0xFFF0); + } + + for (i = 0; i < 72; i++) { + putc(binout[i] & 0xFF, fout); + putc((binout[i] >> 8) & 0xFF, fout); + } + + outcols = 72; // add the ident + flushcard(); +} + +// binard_writedata - emit an object data card + +void corecard_writedata (void) +{ + corecard[1] = 0; // checksum + corecard[2] = 0x0000 | corecard_n; // data card type + word count + corecard_writecard(FALSE); // emit the card +} + +// corecard_flush - flush any pending binary data + +void corecard_flush (void) +{ + if (corecard_n > 0) + corecard_writedata(); + + corecard_init(); +} + +// corecard_setorg - set the origin + +void corecard_setorg (int neworg) +{ + corecard_org = neworg; // set origin for next card + corecard_flush(); // flush any current data & store origin +} + +// corecard_writew - write a word to the current output card. + +void corecard_writew (int word, RELOC relative) +{ + if (corecard_n >= 50) // flush full card buffer (must be even) + corecard_flush(); + + corecard[3+corecard_n++] = word; + corecard_org++; +} + +// corecard_endcard - write end of program card + +void corecard_endcard (void) +{ + corecard_flush(); + + corecard[0] = 0; // effective length: add 1 to max origin, then 1 more to round up + corecard[1] = 0; + corecard[2] = 0x8000; // they look for negative bit but all else must be zero + corecard[52] = 0xabcd; // index register 3 value, this is for fun + corecard[53] = pta; // hmmm + + corecard_writecard(NULL); +} + +/* ------------------------------------------------------------------------ + * upcase - force a string to uppercase (ASCII) + * ------------------------------------------------------------------------ */ + +char *upcase (char *str) +{ + char *s; + + for (s = str; *s; s++) { + if (*s >= 'a' && *s <= 'z') + *s -= 32; + } + + return str; +} + +#ifndef WIN32 + +int strnicmp (char *a, char *b, int n) +{ + int ca, cb; + + for (;;) { + if (--n < 0) // still equal after n characters? quit now + return 0; + + if ((ca = *a) == 0) // get character, stop on null terminator + return *b ? -1 : 0; + + if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase + ca -= 32; + + cb = *b; + if (cb >= 'a' && cb <= 'z') + cb -= 32; + + if ((ca -= cb) != 0) // if different, return comparison + return ca; + + a++, b++; + } +} + +int strcmpi (char *a, char *b) +{ + int ca, cb; + + for (;;) { + if ((ca = *a) == 0) // get character, stop on null terminator + return *b ? -1 : 0; + + if (ca >= 'a' && ca <= 'z') // fold lowercase to uppercase + ca -= 32; + + cb = *b; + if (cb >= 'a' && cb <= 'z') + cb -= 32; + + if ((ca -= cb) != 0) // if different, return comparison + return ca; + + a++, b++; + } +} + +#endif diff --git a/Ibm1130/mkboot.mak b/Ibm1130/mkboot.mak new file mode 100644 index 00000000..a7a784d1 --- /dev/null +++ b/Ibm1130/mkboot.mak @@ -0,0 +1,161 @@ +# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=Win32 Debug +!MESSAGE No configuration specified. Defaulting to Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "mkboot.mak" CFG="Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "Win32 Debug" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "WinRel" +# PROP BASE Intermediate_Dir "WinRel" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "WinRel" +# PROP Intermediate_Dir "WinRel" +OUTDIR=.\WinRel +INTDIR=.\WinRel + +ALL : $(OUTDIR)/mkboot.exe $(OUTDIR)/mkboot.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"mkboot.pch" /Fo$(INTDIR)/ /c +CPP_OBJS=.\WinRel/ +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"mkboot.bsc" +BSC32_SBRS= \ + $(INTDIR)/mkboot.sbr + +$(OUTDIR)/mkboot.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\ + /INCREMENTAL:no /PDB:$(OUTDIR)/"mkboot.pdb" /MACHINE:I386\ + /OUT:$(OUTDIR)/"mkboot.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/mkboot.obj + +$(OUTDIR)/mkboot.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "WinDebug" +# PROP BASE Intermediate_Dir "WinDebug" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "WinDebug" +# PROP Intermediate_Dir "WinDebug" +OUTDIR=.\WinDebug +INTDIR=.\WinDebug + +ALL : $(OUTDIR)/mkboot.exe $(OUTDIR)/mkboot.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"mkboot.pch" /Fo$(INTDIR)/ /Fd$(OUTDIR)/"mkboot.pdb"\ + /c +CPP_OBJS=.\WinDebug/ +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"mkboot.bsc" +BSC32_SBRS= \ + $(INTDIR)/mkboot.sbr + +$(OUTDIR)/mkboot.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib /NOLOGO /SUBSYSTEM:console\ + /INCREMENTAL:yes /PDB:$(OUTDIR)/"mkboot.pdb" /DEBUG /MACHINE:I386\ + /OUT:$(OUTDIR)/"mkboot.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/mkboot.obj + +$(OUTDIR)/mkboot.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Group "Source Files" + +################################################################################ +# Begin Source File + +SOURCE=.\mkboot.c + +$(INTDIR)/mkboot.obj : $(SOURCE) $(INTDIR) + +# End Source File +# End Group +# End Project +################################################################################ diff --git a/Ibm1130/readme1130.txt b/Ibm1130/readme1130.txt index 33686d01..31c94fd1 100644 --- a/Ibm1130/readme1130.txt +++ b/Ibm1130/readme1130.txt @@ -1,18 +1,31 @@ Here's the 1130 simulator as it stands now. -Status: 10 April 2002 +Status: 13Sep2002 - * The 1132 printer now works (at least printing numbers) - and there are some corrections to the assembler. The - Disk Cartridge Initialiation Program (DCIP) is now - included and works. See notes below. + * Added support for 1403 printer. It's MUCH faster + even in emulation. Not important for general use, + but it will help the CGI version a lot. - * For updated information about the 1130 and for - future simulator, 1130 OS and application software - developments, check www.ibm1130.org periodically. - Sign up for the mailing list to get updates as they occur! +Status: 16Aug2002 - * I still haven't written any documentation. + * Disk Monitor System R2V12 is available including the + Macro Assembler, Fortran Compiler and System Library. + + * There was a bug in the multiply instruction. This has + been fixed, and now the single precision trig functions + work correctly. + + * The card punch does not yet work correctly. + + * The card reader, punch and disk don't compute their device + status word until an XIO requests it; this is probably bad + as the "examine" command will show the wrong value. Doesn't + affect functioning of emulated software, though. + + * Documentation is a work in progress, see ibm1130.doc + in ibm1130software.zip. We hope to have it finished in + October. This is a Word document. Will distribute as a + PDF when it's finished. * Thanks to Oscar E Wyss (www.cosecans.ch) for the DMS V12 source code listings and one card @@ -23,150 +36,133 @@ Status: 10 April 2002 to the simh makefiles & testing the builds on several platforms. - * I now have the source code for the 1130 Disk - Monitor System and compilers in the software package. - The asm1130 assembler is not quite up to the task of - compiling it yet. We have located a copy of the binary - disk load deck that will let us build a working disk - image. I hope to have these available online and as part - of this distribution, respectively, by Summer, 2002. - At that point the source code will be included too. + * For updated information about the 1130 and for + future 1130 OS and application software developments, + check www.ibm1130.org periodically. Sign up for the + mailing list to get updates as they occur! - * Assembler has been updated to handle card image input + * Cross-assembler has been updated to handle card image input correctly. The DMS sources seems to mix up @ and ' as a leading symbol in labels, I have to find out why this is. - * see bug list below +BUILD NOTES: if you download this simulator directly from +IBM1130.org, the makefile, source, and binaries are all in +the main directory. If you use the version from Bob Supnik's +SIMH distribution, the makefile is in the main simh +directory, and the SCP files used are Bob's. For a +Windows build, use the .mak file in the IBM1130 directory, +as this incorporates the GUI. + +Make the utilities in the utils directory if you want +to actually build and load DMS from scratch. Move the +executables to a common directory in your search path Brian Knittel brian@ibm1130.org -------------------------------------------------------------------------- +Some sample things to run: +(it's best to hit CHECK RESET or type "reset" between program runs!) +* Run a Fortran Program + ibm1130 + do job roots + do job csort + +* List the monitor system disk's contents + ibm1130 + do job list + +* Look into the files "job", "roots.job" and "csort.job" and "list.job" + to see the actual input files + +* When the jobs have run (stop at 2A with 1000 in the + accumulator), detach the printer (det prt) and look at + the output file: for.lst or asm.lst. The supplied "job" + script displays the print output automatically on Windows + builds. + +-------------------------------------------------------------------------- Contents: -There are two programs: +There are several programs: ibm1130 the simulator asm1130 cross assembler + bindump dumps contents of relocatable format object decks (xxx.bin) + checkdisk validates DMS disk format + diskview dumps contents of DMS disk directory + mkboot creates IPL and Core Image Format Decks from .bin + viewdeck displays contents of Hollerith-format binary decks + +Files in the software (sw) directory: actual 1130 software: - zdcip.asm "disk cartridge initialization program" - - dmsboot.asm the DMS cold start loader - + dms.dsk disk image file containing Disk Monitor System + zdcip.asm disk cartridge initialization program zcrdumpc.asm a cold-start-mode one card memory dump program + dmsboot.asm source code for the DMS cold start loader -And several files in the software (sw) directory: - - test.dsk disk image, a formatted but empty 1130 disk + contributed software: onecard/* one-card programs from Oscar Wyss - boot2 script to boot the 1130 - boot2.ldr an older DMS cold start loader - boot1.ldr APL cold start loader - - type.asm program to type on console printer - prtcr.asm program to copy card deck to console printer - -------------------------------------------------------------------------- Status of the simulator: -* bugs: +* There is a reasonably fun console GUI available for Windows builds, + as well as support for the 2250 graphical display. - (1) Deck files may not work correctly; have to check. When second deck file - is loaded it appears that the second file is not read correctly? +* The card reader emulator now supports deck files with literal cards and + breakpoints. The command "attach cr @filename" tells the simulator to + read data from the files named in the specified file. Input lines are of + the following form: -* the card punch is untested - -* the card reader emulator now supports deck files: a list of multiple files from - which to read; this makes it possible to assemble complex decks of mixed - text and binary cards without having to actually combine the components - into one file. - -* the card reader, punch and disk don't compute their device status word - until an XIO requests it; this is probably bad as the examine command - will show the wrong value. - -* there is a reasonably fun GUI available for Windows builds; this requires - the use of modified scp.c and scp_tty.c. These are enclosed. You should - merge the noted modifications into the current versions of scp and scp_tty. - You will also need to define symbol GUI_SUPPORT during the builds; the Visual - C makefile has this set. - --------------------------------------------------------------------------- -Some sample things to run: - -* Disk Cartridge Initialization: - - asm1130 zdcip.asm - ibm1130 - -then: attach dsk0 test.dsk - attach prt 1132.lst - load zdcip.out - go - -then: on GUI: on console: - ---------------- ----------------- - raise switch 6 dep ces 0200 - program start go - lower 6 dep ces 0 - program start go - raise 3, 6, 10, 11, 13 dep ces 1234 - program start go - program start go - - (this formats the disk) - - program start go - - lower all switches - raise switch 2 dep ces 2000 - program start go - lower all switches dep ces 0 - program start go - raise switch 14 dep ces 2 - program start go - - (this dumps two sectors to printer output file 1132.lst) - - (now try to boot the disk) - - lower all switches dep ces 0 - check reset reset - program load load dmsboot.out - program start go - -* echo console keyboard to console printer. This one is really fun -* with the GUI enabled; the lights flash in a pleasing manner. - - asm1130 type - ibm1130 - load type.out - go - -* copy card deck to console printer - - asm1130 prtcr - ibm1130 - load prtcr.out - attach cr - go + filename a -- input file to be read as ascii text + filename b -- input file to be read as binary card images + !xyz... -- literal text xyz..., treated as a card + !break -- halts the simulator + #comment -- remarks +* The do command may have arguments after the filename. These may be + interpolated in the script and in card reader deck files with %1, %2, etc -------------------------------------------------------------------------- sample usage -------------------------------------------------------------------------- -asm1130 -l resmon.asm +ibm1130 + starts SIMH-based simulator. + Optional command line arguments: -q quiet mode, -g no GUI + + Enhancements: + + * Windows builds display a console window + + * CPU activity log + + the command "attach cpu file.log" will make the simulator + write a detailed log of CPU and IO activity, good for + debugging. Turn off with "detach cpu". + + * DO command [arg1 arg2...] + reads file 'filename' for SIMH commands. Lets you write + simh command files to be run from the prompt rather + than just the command line. In the do command file, %1 will + be replaced by the first command line argument, etc. This + applies to the script run from the ibm1130 command line too. + + * DELETE filename + deletes the named file + + * VIEW filename + displays the named file with "notepad." (Windows only). + +-------------------------------------------------------------------------- +asm1130 -l program.asm compiles source file, creates simulator load - file (resmon.out) and listing file (resmon.lst) - - I had to type in the resident monitor, so it's missing - the comments. I'll add them later. + file (program.out) and listing file (program.lst) The cross assembler wants files either in strict column layout matching the IBM spec, or, if tabs are present in the @@ -178,32 +174,11 @@ asm1130 -l resmon.asm load command. -------------------------------------------------------------------------- -cardscan -x image.bmp - where x = b for binary interpretation - a for ascii interpretation - l for boot loader interpretation +Note: the DMS disk is built with the Windows batch file "mkdms.bat". --------------------------------------------------------------------------- -ibm1130 - starts SIMH-based simulator. - - Enhancements: - - * Displays a console window (you can hide with DISABLE CONSOLE) - with buttons & lights. - - * CPU activity log - - the command "attach log file.log" will make the simulator - write a detailed log of CPU and IO activity, good for - debugging. Turn off with "detach log". - - * DO command - reads file 'filename' for SIMH commands. Lets you write - simh command files to be run from the prompt rather - than just the command line. Bob Supnik has added this to - the main simh code tree. +Subnote: DMS cannot be built with the 1130's native assembler. + -------------------------------------------------------------------------- check www.ibm1130.org for updates... \ No newline at end of file diff --git a/Ibm1130/readme_update.txt b/Ibm1130/readme_update.txt new file mode 100644 index 00000000..53400d1d --- /dev/null +++ b/Ibm1130/readme_update.txt @@ -0,0 +1,35 @@ +Interim 1130 distribution: +-------------------------------------------- + +folders: + . sources + winrel windows executables + windebug windows executables + utils accessory programs + utils\winrel windows executables + utils\windebug windows executables + sw working directory for DMS build & execution + sw\dmsR2V12 Disk Monitor System sources + +programs: + asm1130 cross assembler + bindump object deck dump tool, also used to sort decks by phase id + checkdisk DMS disk image check and dump + diskview work in progress, interpreted disk image dump + ibm1130 emulator + mkboot object deck to IPL and core image converter + viewdeck binary to hollerith deck viewer if needed to view phase ID cards and ident fields + +batch file: + mkdms.bat builds DMS objects and binary cards. Need a shell script version of this. + +IBM1130 simulator DO command scripts: + format format a disk image named DMS.DSK + loaddms format and install DMS onto the formatted DMS.DSK + for run a Fortran program + list list the disk contents + asm assemble a program + +ancillary files: + loaddms.deck list of files stacked into the card reader for loaddms + *.deck other sample deck files diff --git a/Ibm1130/scp.c b/Ibm1130/scp.c deleted file mode 100644 index f7705bb6..00000000 --- a/Ibm1130/scp.c +++ /dev/null @@ -1,3116 +0,0 @@ -/* scp.c: simulator control program - - Copyright (c) 1993-2002, Robert M Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - 04-Feb-02 BLK Added GUI_SUPPORT code and read_cmdline changes - 06-Jan-02 RMS Moved device enable/disable to simulators - 30-Dec-01 RMS Generalized timer packaged, added circular arrays - 19-Dec-01 RMS Fixed DO command bug (found by John Dundas) - 07-Dec-01 RMS Implemented breakpoint package - 05-Dec-01 RMS Fixed bug in universal register logic - 03-Dec-01 RMS Added read-only units, extended SET/SHOW, universal registers - 24-Nov-01 RMS Added unit-based registers - 16-Nov-01 RMS Added DO command - 28-Oct-01 RMS Added relative range addressing - 08-Oct-01 RMS Added SHOW VERSION - 30-Sep-01 RMS Relaxed attach test in BOOT - 27-Sep-01 RMS Added queue count routine, fixed typo in ex/mod - 17-Sep-01 RMS Removed multiple console support - 07-Sep-01 RMS Removed conditional externs on function prototypes - Added special modifier print - 31-Aug-01 RMS Changed int64 to t_int64 for Windoze (V2.7) - 18-Jul-01 RMS Minor changes for Macintosh port - 12-Jun-01 RMS Fixed bug in big-endian I/O (found by Dave Conroy) - 27-May-01 RMS Added multiple console support - 16-May-01 RMS Added logging - 15-May-01 RMS Added features from Tim Litt - 12-May-01 RMS Fixed missing return in disable_cmd - 25-Mar-01 RMS Added ENABLE/DISABLE - 14-Mar-01 RMS Revised LOAD/DUMP interface (again) - 05-Mar-01 RMS Added clock calibration support - 05-Feb-01 RMS Fixed bug, DETACH buffered unit with hwmark = 0 - 04-Feb-01 RMS Fixed bug, RESTORE not using device's attach routine - 21-Jan-01 RMS Added relative time - 22-Dec-00 RMS Fixed find_device for devices ending in numbers - 08-Dec-00 RMS V2.5a changes - 30-Oct-00 RMS Added output file option to examine - 11-Jul-99 RMS V2.5 changes - 13-Apr-99 RMS Fixed handling of 32b addresses - 04-Oct-98 RMS V2.4 changes - 20-Aug-98 RMS Added radix commands - 05-Jun-98 RMS Fixed bug in ^D handling for UNIX - 10-Apr-98 RMS Added switches to all commands - 26-Oct-97 RMS Added search capability - 25-Jan-97 RMS Revised data types - 23-Jan-97 RMS Added bi-endian I/O - 06-Sep-96 RMS Fixed bug in variable length IEXAMINE - 16-Jun-96 RMS Changed interface to parse/print_sym - 06-Apr-96 RMS Added error checking in reset all - 07-Jan-96 RMS Added register buffers in save/restore - 11-Dec-95 RMS Fixed ordering bug in save/restore - 22-May-95 RMS Added symbolic input - 13-Apr-95 RMS Added symbolic printouts -*/ - -#if defined(VMS) - # define FOPEN(file_spec, mode) fopen(file_spec, mode, "MBF=6", "MBC=128", "ROP=rah,wbh") -#else - # define FOPEN(file_spec, mode) fopen(file_spec, mode) -#endif - -#include "sim_defs.h" -#include "sim_rev.h" -#include -#include - -#define EX_D 0 /* deposit */ -#define EX_E 1 /* examine */ -#define EX_I 2 /* interactive */ -#define SCH_OR 0 /* search logicals */ -#define SCH_AND 1 -#define SCH_XOR 2 -#define SCH_E 0 /* search booleans */ -#define SCH_N 1 -#define SCH_G 2 -#define SCH_L 3 -#define SCH_EE 4 -#define SCH_NE 5 -#define SCH_GE 6 -#define SCH_LE 7 -#define SSH_ST 0 /* set */ -#define SSH_SH 1 /* show */ -#define SSH_CL 2 /* clear */ -#define RU_RUN 0 /* run */ -#define RU_GO 1 /* go */ -#define RU_STEP 2 /* step */ -#define RU_CONT 3 /* continue */ -#define RU_BOOT 4 /* boot */ - -#define SWHIDE (1u << 26) /* enable hiding */ -#define SRBSIZ 1024 /* save/restore buffer */ -#define SIM_BRK_INILNT 1024 /* bpt tbl length */ -#define SIM_BRK_ALLTYP 0xFFFFFFFF -#define SIM_NTIMERS 8 /* # timers */ -#define SIM_TMAX 500 /* max timer makeup */ -#define UPDATE_SIM_TIME(x) sim_time = sim_time + (x - sim_interval); \ - sim_rtime = sim_rtime + ((uint32) (x - sim_interval)); \ - x = sim_interval - -struct brktab { - t_addr addr; - int32 typ; - int32 cnt; - char *act; -}; - -typedef struct brktab BRKTAB; - -extern char sim_name[]; -extern DEVICE *sim_devices[]; -extern REG *sim_PC; -extern char *sim_stop_messages[]; -extern t_stat sim_instr (void); -extern t_stat sim_load (FILE *ptr, char *cptr, char *fnam, int flag); -extern int32 sim_emax; -extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, - UNIT *uptr, int32 sw); -extern t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, - int32 sw); -extern t_stat ttinit (void); -extern t_stat ttrunstate (void); -extern t_stat ttcmdstate (void); -extern t_stat ttclose (void); -extern t_stat sim_putchar (int32 out); -extern uint32 sim_os_msec (void); -UNIT *sim_clock_queue = NULL; -int32 sim_interval = 0; -int32 sim_switches = 0; -int32 sim_is_running = 0; -uint32 sim_brk_summ = 0; -uint32 sim_brk_types = 0; -uint32 sim_brk_dflt = 0; -BRKTAB *sim_brk_tab = NULL; -int32 sim_brk_ent = 0; -int32 sim_brk_lnt = 0; -int32 sim_brk_ins = 0; -t_bool sim_brk_pend = FALSE; -t_addr sim_brk_ploc = 0; -static double sim_time; -static uint32 sim_rtime; -static int32 noqueue_time; -volatile int32 stop_cpu = 0; -t_value *sim_eval = NULL; -int32 sim_end = 1; /* 1 = little */ -FILE *sim_log = NULL; /* log file */ -unsigned char sim_flip[FLIP_SIZE]; - -t_stat sim_brk_init (void); -t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt); -t_stat sim_brk_clr (t_addr loc, int32 sw); -t_stat sim_brk_clrall (int32 sw); -t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw); -t_stat sim_brk_showall (FILE *st, int32 sw); -void sim_brk_npc (void); -#define print_val(a,b,c,d) fprint_val (stdout, (a), (b), (c), (d)) -#define SZ_D(dp) (size_map[((dp) -> dwidth + CHAR_BIT - 1) / CHAR_BIT]) -#define SZ_R(rp) \ - (size_map[((rp) -> width + (rp) -> offset + CHAR_BIT - 1) / CHAR_BIT]) -#if defined (t_int64) -#define SZ_LOAD(sz,v,mb,j) \ - if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + j); \ - else if (sz == sizeof (uint16)) v = *(((uint16 *) mb) + j); \ - else if (sz == sizeof (uint32)) v = *(((uint32 *) mb) + j); \ - else v = *(((t_uint64 *) mb) + j); -#define SZ_STORE(sz,v,mb,j) \ - if (sz == sizeof (uint8)) *(((uint8 *) mb) + j) = (uint8) v; \ - else if (sz == sizeof (uint16)) *(((uint16 *) mb) + j) = (uint16) v; \ - else if (sz == sizeof (uint32)) *(((uint32 *) mb) + j) = (uint32) v; \ - else *(((t_uint64 *) mb) + j) = v; -#else -#define SZ_LOAD(sz,v,mb,j) \ - if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + j); \ - else if (sz == sizeof (uint16)) v = *(((uint16 *) mb) + j); \ - else v = *(((uint32 *) mb) + j); -#define SZ_STORE(sz,v,mb,j) \ - if (sz == sizeof (uint8)) *(((uint8 *) mb) + j) = (uint8) v; \ - else if (sz == sizeof (uint16)) *(((uint16 *) mb) + j) = (uint16) v; \ - else *(((uint32 *) mb) + j) = v; -#endif -#define GET_SWITCHES(cp,gb) \ - sim_switches = 0; \ - while (*cp == '-') { \ - int32 lsw; \ - cp = get_glyph (cp, gb, 0); \ - if ((lsw = get_switches (gb)) <= 0) return SCPE_INVSW; \ - sim_switches = sim_switches | lsw; } -#define GET_RADIX(val,dft) \ - if (sim_switches & SWMASK ('O')) val = 8; \ - else if (sim_switches & SWMASK ('D')) val = 10; \ - else if (sim_switches & SWMASK ('H')) val = 16; \ - else val = dft; - -t_stat set_glob (CTAB *tab, char *gbuf, DEVICE *dptr, UNIT *uptr); -t_stat ssh_break (FILE *st, char *cptr, int32 flg); -t_stat set_radix (DEVICE *dptr, UNIT *uptr, int flag); -t_stat set_onoff (DEVICE *dptr, UNIT *uptr, int32 flag); -t_stat show_config (FILE *st, int32 flag); -t_stat show_queue (FILE *st, int32 flag); -t_stat show_time (FILE *st, int32 flag); -t_stat show_mod_names (FILE *st, int32 flag); -t_stat show_device (FILE *st, DEVICE *dptr, int32 flag); -t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag); -t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flg); -t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr, int32 flag); -int32 get_switches (char *cptr); -t_value get_rval (REG *rptr, int idx); -void put_rval (REG *rptr, int idx, t_value val); -t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr); -t_value strtotv (char *inptr, char **endptr, int radix); -t_stat fprint_val (FILE *stream, t_value val, int rdx, int wid, int fmt); -void fprint_stopped (FILE *stream, t_stat r); -char *read_line (char *ptr, int size, FILE *stream); -DEVICE *find_dev (char *ptr); -DEVICE *find_unit (char *ptr, UNIT **uptr); -REG *find_reg_glob (char *ptr, char **optr, DEVICE **gdptr); -t_bool qdisable (DEVICE *dptr); -t_stat attach_err (UNIT *uptr, t_stat stat); -t_stat detach_all (int32 start_device, t_bool shutdown); -t_stat ex_reg (FILE *ofile, t_value val, int flag, REG *rptr, t_addr idx); -t_stat dep_reg (int flag, char *cptr, REG *rptr, t_addr idx); -t_stat ex_addr (FILE *ofile, int flag, t_addr addr, DEVICE *dptr, UNIT *uptr); -t_stat dep_addr (int flag, char *cptr, t_addr addr, DEVICE *dptr, - UNIT *uptr, int dfltinc); -char *get_range (char *cptr, t_addr *lo, t_addr *hi, int rdx, - t_addr max, char term); -SCHTAB *get_search (char *cptr, DEVICE *dptr, SCHTAB *schptr); -int test_search (t_value val, SCHTAB *schptr); -t_stat step_svc (UNIT *ptr); -t_stat show_version (FILE *st, int flag); -char *read_cmdline (char *ptr, int size); /* BLK - added */ - -UNIT step_unit = { UDATA (&step_svc, 0, 0) }; -const char save_vercur[] = "V2.6"; -const char save_ver25[] = "V2.5"; -const char *scp_error_messages[] = { - "Address space exceeded", - "Unit not attached", - "I/O error", - "Checksum error", - "Format error", - "Unit not attachable", - "File open error", - "Memory exhausted", - "Invalid argument", - "Step expired", - "Unknown command", - "Read only argument", - "Command not completed", - "Simulation stopped", - "Goodbye", - "Console input I/O error", - "Console output I/O error", - "End of file", - "Relocation error", - "No settable parameters", - "Unit already attached", - "Hardware timer error", - "SIGINT handler setup error", - "Console terminal setup error", - "Subscript out of range", - "Command not allowed", - "Unit disabled", - "Logging enabled", - "Logging disabled", - "Read only operation not allowed", - "Invalid switch", - "Missing value", - "Too few arguments", - "Too many arguments", - "Non-existent device", - "Non-existent unit", - "Non-existent register", - "Non-existent parameter", - "Nested DO commands", - "Internal error" -}; - -const size_t size_map[] = { sizeof (int8), - sizeof (int8), sizeof (int16), sizeof (int32), sizeof (int32) -#if defined (t_int64) - , sizeof (t_int64), sizeof (t_int64), sizeof (t_int64), sizeof (t_int64) -#endif -}; - -const t_value width_mask[] = { 0, - 0x1, 0x3, 0x7, 0xF, - 0x1F, 0x3F, 0x7F, 0xFF, - 0x1FF, 0x3FF, 0x7FF, 0xFFF, - 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, - 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF, - 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF, - 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, - 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF -#if defined (t_int64) - , 0x1FFFFFFFF, 0x3FFFFFFFF, 0x7FFFFFFFF, 0xFFFFFFFFF, - 0x1FFFFFFFFF, 0x3FFFFFFFFF, 0x7FFFFFFFFF, 0xFFFFFFFFFF, - 0x1FFFFFFFFFF, 0x3FFFFFFFFFF, 0x7FFFFFFFFFF, 0xFFFFFFFFFFF, - 0x1FFFFFFFFFFF, 0x3FFFFFFFFFFF, 0x7FFFFFFFFFFF, 0xFFFFFFFFFFFF, - 0x1FFFFFFFFFFFF, 0x3FFFFFFFFFFFF, 0x7FFFFFFFFFFFF, 0xFFFFFFFFFFFFF, - 0x1FFFFFFFFFFFFF, 0x3FFFFFFFFFFFFF, 0x7FFFFFFFFFFFFF, 0xFFFFFFFFFFFFFF, - 0x1FFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFF, - 0x7FFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFF, - 0x1FFFFFFFFFFFFFFF, 0x3FFFFFFFFFFFFFFF, - 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF -#endif -}; - -t_stat reset_cmd (int flag, char *ptr); -t_stat exdep_cmd (int flag, char *ptr); -t_stat load_cmd (int flag, char *ptr); -t_stat run_cmd (int flag, char *ptr); -t_stat attach_cmd (int flag, char *ptr); -t_stat detach_cmd (int flag, char *ptr); -t_stat save_cmd (int flag, char *ptr); -t_stat restore_cmd (int flag, char *ptr); -t_stat exit_cmd (int flag, char *ptr); -t_stat set_cmd (int flag, char *ptr); -t_stat show_cmd (int flag, char *ptr); -t_stat log_cmd (int flag, char *ptr); -t_stat nolog_cmd (int flag, char *ptr); -t_stat brk_cmd (int flag, char *ptr); -t_stat do_cmd (int flag, char *ptr); -t_stat help_cmd (int flag, char *ptr); - -static CTAB cmd_table[] = { - { "RESET", &reset_cmd, 0 }, - { "EXAMINE", &exdep_cmd, EX_E }, - { "IEXAMINE", &exdep_cmd, EX_E+EX_I }, - { "DEPOSIT", &exdep_cmd, EX_D }, - { "IDEPOSIT", &exdep_cmd, EX_D+EX_I }, - { "RUN", &run_cmd, RU_RUN }, - { "GO", &run_cmd, RU_GO }, - { "STEP", &run_cmd, RU_STEP }, - { "CONT", &run_cmd, RU_CONT }, - { "BOOT", &run_cmd, RU_BOOT }, - { "ATTACH", &attach_cmd, 0 }, - { "DETACH", &detach_cmd, 0 }, - { "SAVE", &save_cmd, 0 }, - { "RESTORE", &restore_cmd, 0 }, - { "GET", &restore_cmd, 0 }, - { "LOAD", &load_cmd, 0 }, - { "DUMP", &load_cmd, 1 }, - { "EXIT", &exit_cmd, 0 }, - { "QUIT", &exit_cmd, 0 }, - { "BYE", &exit_cmd, 0 }, - { "SET", &set_cmd, 0 }, - { "SHOW", &show_cmd, 0 }, - { "LOG", &log_cmd, 0 }, - { "NOLOG", &nolog_cmd, 0 }, - { "BREAK", &brk_cmd, SSH_ST }, - { "NOBREAK", &brk_cmd, SSH_CL }, - { "DO", &do_cmd, 0 }, - { "HELP", &help_cmd, 0 }, - { NULL, NULL, 0 } }; - -/* Main command loop */ - -int main (int argc, char *argv[]) -{ -char cbuf[CBUFSIZE], gbuf[CBUFSIZE], *cptr; -int32 i; -t_stat stat; -union {int32 i; char c[sizeof (int32)]; } end_test; - -#if defined (__MWERKS__) && defined (macintosh) -argc = ccommand(&argv); -#endif - -if ((stat = ttinit ()) != SCPE_OK) { - printf ("Fatal terminal initialization error\n%s\n", - scp_error_messages[stat - SCPE_BASE]); - return 0; } -printf ("\n"); -show_version (stdout, 0); -end_test.i = 1; /* test endian-ness */ -sim_end = end_test.c[0]; -stop_cpu = 0; -sim_interval = 0; -sim_time = sim_rtime = 0; -noqueue_time = 0; -sim_clock_queue = NULL; -sim_is_running = 0; -sim_log = NULL; -if (sim_emax <= 0) sim_emax = 1; -if ((sim_eval = calloc (sim_emax, sizeof (t_value))) == NULL) { - printf ("Unable to allocate examine buffer\n"); - return 0; }; -if ((stat = reset_all (0)) != SCPE_OK) { - printf ("Fatal simulator initialization error\n%s\n", - scp_error_messages[stat - SCPE_BASE]); - return 0; } -if ((stat = sim_brk_init ()) != SCPE_OK) { - printf ("Fatal breakpoint table initialization error\n%s\n", - scp_error_messages[stat - SCPE_BASE]); - return 0; } - -if ((argc > 1) && argv[1]) { /* cmd file arg? */ - stat = do_cmd (0, argv[1]); /* proc cmd file */ - if (stat == SCPE_OPENERR) fprintf (stderr, /* error? */ - "Can't open file %s\n", argv[1]); } - -do { printf ("sim> "); /* prompt */ -#ifdef GUI_SUPPORT - cptr = read_cmdline (cbuf, CBUFSIZE); /* read command line */ -#else - cptr = read_line (cbuf, CBUFSIZE, stdin); /* read command line */ -#endif - stat = SCPE_UNK; - if (cptr == NULL) continue; /* ignore EOF */ - if (*cptr == 0) continue; /* ignore blank */ - if (sim_log) fprintf (sim_log, "sim> %s\n", cbuf); /* log cmd */ - cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */ - for (i = 0; cmd_table[i].name != NULL; i++) { - if (MATCH_CMD (gbuf, cmd_table[i].name) == 0) { - stat = cmd_table[i].action (cmd_table[i].arg, cptr); - break; } } - if (stat >= SCPE_BASE) { /* error? */ - printf ("%s\n", scp_error_messages[stat - SCPE_BASE]); - if (sim_log) fprintf (sim_log, "%s\n", - scp_error_messages[stat - SCPE_BASE]); } -#ifdef GUI_SUPPORT - update_gui(TRUE); -#endif -} while (stat != SCPE_EXIT); - -detach_all (0, TRUE); /* close files */ -nolog_cmd (0, NULL); /* close log */ -ttclose (); /* close console */ -return 0; -} - -/* Exit command */ - -t_stat exit_cmd (int flag, char *cptr) -{ -return SCPE_EXIT; -} - -/* Help command */ - -void fprint_help (FILE *st) -{ -fprintf (st, "r{eset} {ALL|} reset simulator\n"); -fprintf (st, "e{xamine} examine memory or registers\n"); -fprintf (st, "ie{xamine} interactive examine memory or registers\n"); -fprintf (st, "d{eposit} deposit in memory or registers\n"); -fprintf (st, "id{eposit} interactive deposit in memory or registers\n"); -fprintf (st, "l{oad} {} load binary file\n"); -fprintf (st, "du(mp) {} dump binary file\n"); -fprintf (st, "ru{n} {new PC} reset and start simulation\n"); -fprintf (st, "go {new PC} start simulation\n"); -fprintf (st, "c{ont} continue simulation\n"); -fprintf (st, "s{tep} {n} simulate n instructions\n"); -fprintf (st, "b{oot} bootstrap unit\n"); -fprintf (st, "br{eak} set breakpoints\n"); -fprintf (st, "nobr{eak} clear breakpoints\n"); -fprintf (st, "at{tach} attach file to simulated unit\n"); -fprintf (st, "det{ach} detach file from simulated unit\n"); -fprintf (st, "sa{ve} save simulator to file\n"); -fprintf (st, "rest{ore}|ge{t} restore simulator from file\n"); -fprintf (st, "exi{t}|q{uit}|by{e} exit from simulation\n"); -fprintf (st, "set | set device/unit parameter\n"); -fprintf (st, "sh{ow} | show device parameters\n"); -fprintf (st, "sh{ow} c{onfiguration} show configuration\n"); -fprintf (st, "sh{ow} d{evices} show devices\n"); -fprintf (st, "sh{ow} m{odifiers} show modifiers\n"); -fprintf (st, "sh{ow} q{ueue} show event queue\n"); -fprintf (st, "sh{ow} t{ime} show simulated time\n"); -fprintf (st, "sh{ow} v{ersion} show simulator version\n"); -fprintf (st, "log enable logging to file\n"); -fprintf (st, "nolog disable logging\n"); -fprintf (st, "do process command file\n"); -fprintf (st, "h{elp} type this message\n"); -return; -} - -t_stat help_cmd (int flag, char *cptr) -{ -fprint_help (stdout); -if (sim_log) fprint_help (sim_log); -return SCPE_OK; -} - -/* Do command */ - -t_stat do_cmd (int flag, char *fcptr) -{ -char *cptr, cbuf[CBUFSIZE], gbuf[CBUFSIZE]; -FILE *fpin; -int32 i; -t_stat stat; - -if ((fpin = fopen (fcptr, "r")) != NULL) { /* cmd file open? */ - do { - cptr = read_line (cbuf, CBUFSIZE, fpin); /* get cmd line */ - if (cptr == NULL) break; /* exit on eof */ - if (*cptr == 0) continue; /* ignore blank */ - if (sim_log) fprintf (sim_log, "do> %s\n", cptr); - cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */ - if (strcmp (gbuf, "do") == 0) { /* don't recurse */ - fclose (fpin); - return SCPE_NEST; } - stat = SCPE_BASE; - for (i = 0; cmd_table[i].name != NULL; i++) { /* find cmd */ - if (MATCH_CMD (gbuf, cmd_table[i].name) == 0) { - stat = cmd_table[i].action (cmd_table[i].arg, cptr); - break; } } - if (stat >= SCPE_BASE) /* error? */ - printf ("%s\n", scp_error_messages[stat - SCPE_BASE]); -#ifdef GUI_SUPPORT - update_gui(TRUE); -#endif - } while (stat != SCPE_EXIT); - fclose (fpin); /* close file */ - return SCPE_OK; } /* end if cmd file */ -return SCPE_OPENERR; -} - -/* Set command */ - -t_stat set_cmd (int flag, char *cptr) -{ -int32 lvl; -t_stat r; -char gbuf[CBUFSIZE], *cvptr; -DEVICE *dptr; -UNIT *uptr; -MTAB *mptr; -CTAB *ctbr; -static CTAB set_dev_tab[] = { - { "OCTAL", &set_radix, 8 }, - { "DECIMAL", &set_radix, 10 }, - { "HEX", &set_radix, 16 }, - { NULL, NULL, 0 } }; -static CTAB set_unit_tab[] = { - { "ONLINE", &set_onoff, 1 }, - { "OFFLINE", &set_onoff, 0 }, - { NULL, NULL, 0 } }; - -GET_SWITCHES (cptr, gbuf); /* get switches */ -if (*cptr == 0) return SCPE_2FARG; /* must be more */ -cptr = get_glyph (cptr, gbuf, 0); /* get glob/dev/unit */ -if (*cptr == 0) return SCPE_2FARG; /* must be more */ - -if (dptr = find_dev (gbuf)) { /* device match? */ - uptr = dptr -> units; /* first unit */ - ctbr = set_dev_tab; /* global table */ - lvl = MTAB_VDV; } /* device match */ -else if (dptr = find_unit (gbuf, &uptr)) { /* unit match? */ - if (uptr == NULL) return SCPE_NXUN; /* invalid unit */ - ctbr = set_unit_tab; /* global table */ - lvl = MTAB_VUN; } /* unit match */ -else return SCPE_NXDEV; /* no match */ -if (dptr -> modifiers == NULL) return SCPE_NOPARAM; /* any modifiers? */ - -while (*cptr != 0) { /* do all mods */ - cptr = get_glyph (cptr, gbuf, ','); /* get modifier */ - if (cvptr = strchr (gbuf, '=')) *cvptr++ = 0; /* = value? */ - if (set_glob (ctbr, gbuf, dptr, uptr) == SCPE_OK) /* global match? */ - return SCPE_OK; - for (mptr = dptr -> modifiers; mptr -> mask != 0; mptr++) { - if ((mptr -> mstring) && /* match string */ - (MATCH_CMD (gbuf, mptr -> mstring) == 0)) { /* matches option? */ - if (mptr -> mask & MTAB_XTD) { /* extended? */ - if ((lvl & mptr -> mask) == 0) return SCPE_ARG; - if ((lvl & MTAB_VUN) && (uptr -> flags & UNIT_DIS)) - return SCPE_UDIS; /* unit disabled? */ - if (mptr -> valid) { /* validation rtn? */ - r = mptr -> valid (uptr, mptr -> match, cvptr, mptr -> desc); - if (r != SCPE_OK) return r; } - else if (!mptr -> desc) break; /* value desc? */ - else if (mptr -> mask & MTAB_VAL) { /* take a value? */ - if (!cvptr) return SCPE_MISVAL; /* none? error */ - r = dep_reg (0, cvptr, (REG *) mptr -> desc, 0); - if (r != SCPE_OK) return r; } - else if (cvptr) return SCPE_ARG; /* = value? */ - else *((int32 *) mptr -> desc) = mptr -> match; - } /* end if xtd */ - else { /* old style */ - if (cvptr) return SCPE_ARG; /* = value? */ - if (uptr -> flags & UNIT_DIS) /* disabled? */ - return SCPE_UDIS; - if ((mptr -> valid) && ((r = mptr -> valid - (uptr, mptr -> match, cvptr, mptr -> desc)) - != SCPE_OK)) return r; /* invalid? */ - uptr -> flags = (uptr -> flags & ~(mptr -> mask)) | - (mptr -> match & mptr -> mask); /* set new value */ - } /* end else xtd */ - break; /* terminate for */ - } /* end if match */ - } /* end for */ - if (mptr -> mask == 0) return SCPE_NXPAR; /* any match? */ - } /* end while */ -return SCPE_OK; /* done all */ -} - -t_stat set_glob (CTAB *tab, char *gbuf, DEVICE *dptr, UNIT *uptr) -{ -for (; tab -> name != NULL; tab++) { - if (MATCH_CMD (gbuf, tab -> name) == 0) - return tab -> action (dptr, uptr, tab -> arg); } -return SCPE_NXPAR; -} - -/* Set radix routine */ - -t_stat set_radix (DEVICE *dptr, UNIT *uptr, int32 flag) -{ -dptr -> dradix = flag & 017; -return SCPE_OK; -} - -/* Set online/offline routine */ - -t_stat set_onoff (DEVICE *dptr, UNIT *uptr, int32 flag) -{ -if (!(uptr -> flags & UNIT_DISABLE)) return SCPE_NOFNC; /* allowed? */ -if (flag) uptr -> flags = uptr -> flags & ~UNIT_DIS; /* onl? enable */ -else { /* offline? */ - if ((uptr -> flags & UNIT_ATT) || sim_is_active (uptr)) - return SCPE_NOFNC; /* more tests */ - uptr -> flags = uptr -> flags | UNIT_DIS; } /* disable */ -return SCPE_OK; -} - -/* Show command */ - -t_stat show_cmd (int flag, char *cptr) -{ -int32 i, lvl; -t_stat r; -char gbuf[CBUFSIZE]; -DEVICE *dptr; -UNIT *uptr; -MTAB *mptr; - -static CTAB show_table[] = { - { "CONFIGURATION", &show_config, 0 }, - { "DEVICES", &show_config, 1 }, - { "QUEUE", &show_queue, 0 }, - { "TIME", &show_time, 0 }, - { "MODIFIERS", &show_mod_names, 0 }, - { "VERSION", &show_version, 0 }, - { NULL, NULL, 0 } }; - -GET_SWITCHES (cptr, gbuf); /* test for switches */ -if (*cptr == 0) return SCPE_2FARG; /* must be more */ -cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ -for (i = 0; show_table[i].name != NULL; i++) { /* find command */ - if (MATCH_CMD (gbuf, show_table[i].name) == 0) { - if (*cptr != 0) return SCPE_2MARG; /* now eol? */ - r = show_table[i].action (stdout, show_table[i].arg); - if (sim_log) show_table[i].action (sim_log, show_table[i].arg); - return r; } } - -if (MATCH_CMD (gbuf, "BREAK") == 0) { /* SHOW BREAK? */ - r = ssh_break (stdout, cptr, 1); - if (sim_log) ssh_break (sim_log, cptr, SSH_SH); - return r; } -if (dptr = find_dev (gbuf)) { /* device match? */ - uptr = dptr -> units; /* first unit */ - lvl = MTAB_VDV; } /* device match */ -else if (dptr = find_unit (gbuf, &uptr)) { /* unit match? */ - if (uptr == NULL) return SCPE_NXUN; /* invalid unit */ - if (uptr -> flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ - lvl = MTAB_VUN; } /* unit match */ -else return SCPE_NXDEV; /* no match */ - -if (*cptr == 0) { /* now eol? */ - if (lvl == MTAB_VDV) { /* show dev? */ - r = show_device (stdout, dptr, 0); - if (sim_log) show_device (sim_log, dptr, 0); - return r; } - else { - r = show_unit (stdout, dptr, uptr, -1); - if (sim_log) show_unit (sim_log, dptr, uptr, -1); - return r; } } -if (dptr -> modifiers == NULL) return SCPE_NOPARAM; /* any modifiers? */ - -while (*cptr != 0) { /* do all mods */ - cptr = get_glyph (cptr, gbuf, ','); /* get modifier */ - for (mptr = dptr -> modifiers; mptr -> mask != 0; mptr++) { - if (((mptr -> mask & MTAB_XTD)? /* right level? */ - (mptr -> mask & lvl): (MTAB_VUN & lvl)) && - ((mptr -> disp && mptr -> pstring && /* named disp? */ - (MATCH_CMD (gbuf, mptr -> pstring) == 0)) || - ((mptr -> mask & MTAB_VAL) && /* named value? */ - mptr -> mstring && - (MATCH_CMD (gbuf, mptr -> mstring) == 0)))) { - show_one_mod (stdout, dptr, uptr, mptr, 1); - if (sim_log) show_one_mod (sim_log, dptr, uptr, mptr, 1); - break; - } /* end if */ - } /* end for */ - if (mptr -> mask == 0) return SCPE_ARG; /* any match? */ - } /* end while */ -return SCPE_OK; -} - -/* Show processors */ - -t_stat show_device (FILE *st, DEVICE *dptr, int32 flag) -{ -int32 j, ucnt; -UNIT *uptr; - -fprintf (st, "%s", dptr -> name); /* print dev name */ -if (qdisable (dptr)) { /* disabled? */ - fprintf (st, ", disabled\n"); - return SCPE_OK; } -for (j = ucnt = 0; j < dptr -> numunits; j++) { /* count units */ - uptr = (dptr -> units) + j; - if (!(uptr -> flags & UNIT_DIS)) ucnt++; } -show_all_mods (st, dptr, dptr -> units, MTAB_VDV); /* show dev mods */ -if (dptr -> numunits == 0) fprintf (st, "\n"); -else { if (ucnt == 0) fprintf (st, ", all units disabled\n"); - else if (ucnt > 1) fprintf (st, ", %d units\n", ucnt); - else if (flag) fprintf (st, "\n"); } -if (flag) return SCPE_OK; /* dev only? */ -for (j = 0; j < dptr -> numunits; j++) { /* loop thru units */ - uptr = (dptr -> units) + j; - if ((uptr -> flags & UNIT_DIS) == 0) - show_unit (st, dptr, uptr, ucnt); } -return SCPE_OK; -} - -t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag) -{ -t_addr kval = (uptr -> flags & UNIT_BINK)? 1024: 1000; -int32 u = uptr - dptr -> units; - -if (flag > 1) fprintf (st, " %s%d", dptr -> name, u); -else if (flag < 0) fprintf (st, "%s%d", dptr -> name, u); -if (uptr -> flags & UNIT_FIX) { - if (uptr -> capac < kval) - fprintf (st, ", %d%s", uptr -> capac, - ((dptr -> dwidth / dptr -> aincr) > 8)? "W": "B"); - else fprintf (st, ", %dK%s", uptr -> capac / kval, - ((dptr -> dwidth / dptr -> aincr) > 8)? "W": "B"); } -if (uptr -> flags & UNIT_ATT) { - fprintf (st, ", attached to %s", uptr -> filename); - if (uptr -> flags & UNIT_RO) fprintf (st, ", read only"); } -else if (uptr -> flags & UNIT_ATTABLE) - fprintf (st, ", not attached"); -show_all_mods (st, dptr, uptr, MTAB_VUN); /* show unit mods */ -fprintf (st, "\n"); -return SCPE_OK; -} - -t_stat show_version (FILE *st, int32 flag) -{ -int32 vmaj = SIM_MAJOR, vmin = SIM_MINOR, vpat = SIM_PATCH; - -fprintf (st, "%s simulator V%d.%d-%d\n", sim_name, vmaj, vmin, vpat); -return SCPE_OK; -} - -t_stat show_config (FILE *st, int32 flag) -{ -int32 i; -DEVICE *dptr; - -fprintf (st, "%s simulator configuration\n\n", sim_name); -for (i = 0; (dptr = sim_devices[i]) != NULL; i++) - show_device (st, dptr, flag); -return SCPE_OK; -} - -t_stat show_queue (FILE *st, int32 flag) -{ -DEVICE *dptr; -UNIT *uptr; -int32 accum; - -if (sim_clock_queue == NULL) { - fprintf (st, "%s event queue empty, time = %-16.0f\n", - sim_name, sim_time); - return SCPE_OK; } -fprintf (st, "%s event queue status, time = %-16.0f\n", - sim_name, sim_time); -accum = 0; -for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr -> next) { - if (uptr == &step_unit) fprintf (st, " Step timer"); - else if ((dptr = find_dev_from_unit (uptr)) != NULL) { - fprintf (st, " %s", dptr -> name); - if (dptr -> numunits > 1) fprintf (st, " unit %d", - uptr - dptr -> units); } - else fprintf (st, " Unknown"); - fprintf (st, " at %d\n", accum + uptr -> time); - accum = accum + uptr -> time; } -return SCPE_OK; -} - -t_stat show_time (FILE *st, int32 flag) -{ -fprintf (st, "Time: %-16.0f\n", sim_time); -return SCPE_OK; -} - -t_stat show_mod_names (FILE *st, int32 flag) -{ -int i, any; -DEVICE *dptr; -MTAB *mptr; - -for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { - if (dptr -> modifiers) { - any = 0; - for (mptr = dptr -> modifiers; mptr -> mask != 0; mptr++) { - if (mptr -> mstring) { - if (any++) fprintf (st, ", %s", mptr -> mstring); - else fprintf (st, "%s\t%s", dptr -> name, mptr -> mstring); } } - if (any) fprintf (st, "\n"); } } -return SCPE_OK; -} - -t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag) -{ -MTAB *mptr; - -if (dptr -> modifiers == NULL) return SCPE_OK; -for (mptr = dptr -> modifiers; mptr -> mask != 0; mptr++) { - if (mptr -> pstring && ((mptr -> mask & MTAB_XTD)? - ((mptr -> mask & flag) && !(mptr -> mask & MTAB_NMO)): - ((MTAB_VUN & flag) && ((uptr -> flags & mptr -> mask) == mptr -> match)))) { - fputs (", ", st); - show_one_mod (st, dptr, uptr, mptr, 0); } } -return SCPE_OK; -} - -t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr, int32 flag) -{ -t_value val; - -if (mptr -> disp) mptr -> disp (st, uptr, mptr -> match, mptr -> desc); -else if ((mptr -> mask & MTAB_XTD) && (mptr -> mask & MTAB_VAL)) { - REG *rptr = (REG *) mptr -> desc; - fprintf (st, "%s=", mptr -> pstring); - val = get_rval (rptr, 0); - fprint_val (st, val, rptr -> radix, rptr -> width, - rptr -> flags & REG_FMT); } -else fputs (mptr -> pstring, st); -if (flag && !((mptr -> mask & MTAB_XTD) && - (mptr -> mask & MTAB_NMO))) fputc ('\n', st); -return SCPE_OK; -} - -/* Breakpoint commands */ - -t_stat brk_cmd (int flg, char *cptr) -{ -char gbuf[CBUFSIZE]; - -GET_SWITCHES (cptr, gbuf); /* test for switches */ -if (*cptr == 0) return SCPE_2FARG; /* must be more */ -return ssh_break (NULL, cptr, flg); /* call common code */ -} - -t_stat ssh_break (FILE *st, char *cptr, int32 flg) -{ -char gbuf[CBUFSIZE], *tptr, *t1ptr; -DEVICE *dptr = sim_devices[0]; -UNIT *uptr = dptr -> units; -t_stat r; -t_addr lo, hi, max = uptr -> capac - dptr -> aincr; -int32 cnt; - -if (*cptr == 0) return SCPE_2FARG; -if (sim_brk_types == 0) return SCPE_NOFNC; -if ((dptr == NULL) || (uptr == NULL)) return SCPE_IERR; -while (*cptr) { - cptr = get_glyph (cptr, gbuf, ','); - tptr = get_range (gbuf, &lo, &hi, dptr -> aradix, max, 0); - if (tptr == NULL) return SCPE_ARG; - if (*tptr == '[') { - errno = 0; - cnt = strtoul (tptr + 1, &t1ptr, 10); - if (errno || (tptr == t1ptr) || (*t1ptr != ']') || - (flg != SSH_ST)) return SCPE_ARG; - tptr = t1ptr + 1; } - else cnt = 0; - if (*tptr != 0) return SCPE_ARG; - if ((lo == 0) && (hi == max)) { - if (flg == SSH_CL) sim_brk_clrall (sim_switches); - else if (flg == SSH_SH) sim_brk_showall (st, sim_switches); - else return SCPE_ARG; } - else { - for ( ; lo <= hi; lo = lo + dptr -> aincr) { - if (flg == SSH_ST) r = sim_brk_set (lo, sim_switches, cnt); - else if (flg == SSH_CL) r = sim_brk_clr (lo, sim_switches); - else if (flg == SSH_SH) r = sim_brk_show (st, lo, sim_switches); - else return SCPE_ARG; - } - } - } -return SCPE_OK; -} - -/* Logging commands - - log filename open log file - nolog close log file -*/ - -t_stat log_cmd (int flag, char *cptr) -{ -char gbuf[CBUFSIZE]; - -GET_SWITCHES (cptr, gbuf); /* test for switches */ -if (*cptr == 0) return (sim_log? SCPE_LOGON: SCPE_LOGOFF); -cptr = get_glyph_nc (cptr, gbuf, 0); /* get file name */ -if (*cptr != 0) return SCPE_2MARG; /* now eol? */ -nolog_cmd (0, NULL); /* close cur log */ -sim_log = fopen (gbuf, "a"); /* open log */ -if (sim_log == NULL) return SCPE_OPENERR; /* error? */ -printf ("Logging to file \"%s\"\n", gbuf); /* start of log */ -fprintf (sim_log, "Logging to file \"%s\"\n", gbuf); -return SCPE_OK; -} - -t_stat nolog_cmd (int flag, char *cptr) -{ -char gbuf[CBUFSIZE]; - -if (cptr) { - GET_SWITCHES (cptr, gbuf); /* test for switches */ - if (*cptr != 0) return SCPE_2MARG; } /* now eol? */ -if (sim_log == NULL) return SCPE_OK; /* no log? */ -printf ("Log file closed\n"); -fprintf (sim_log, "Log file closed\n"); /* close log */ -fclose (sim_log); -sim_log = NULL; -return SCPE_OK; -} - -/* Reset command and routines - - re[set] reset all devices - re[set] all reset all devices - re[set] device reset specific device -*/ - -t_stat reset_cmd (int flag, char *cptr) -{ -char gbuf[CBUFSIZE]; -DEVICE *dptr; - -GET_SWITCHES (cptr, gbuf); /* test for switches */ -if (*cptr == 0) return (reset_all (0)); /* reset(cr) */ -cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ -if (*cptr != 0) return SCPE_2MARG; /* now eol? */ -if (strcmp (gbuf, "ALL") == 0) return (reset_all (0)); -dptr = find_dev (gbuf); /* locate device */ -if (dptr == NULL) return SCPE_NXDEV; /* found it? */ -if (dptr -> reset != NULL) return dptr -> reset (dptr); -else return SCPE_OK; -} - -/* Reset devices start..end - - Inputs: - start = number of starting device - Outputs: - status = error status -*/ - -t_stat reset_all (int start) -{ -DEVICE *dptr; -int32 i; -t_stat reason; - -if (start < 0) return SCPE_IERR; -for (i = 0; i < start; i++) { - if (sim_devices[i] == NULL) return SCPE_IERR; } -for (i = start; (dptr = sim_devices[i]) != NULL; i++) { - if (dptr -> reset != NULL) { - reason = dptr -> reset (dptr); - if (reason != SCPE_OK) return reason; } } -return SCPE_OK; -} - -/* Load and dump commands - - lo[ad] filename {arg} load specified file - du[mp] filename {arg} dump to specified file -*/ - -t_stat load_cmd (int flag, char *cptr) -{ -char gbuf[CBUFSIZE]; -FILE *loadfile; -t_stat reason; - -GET_SWITCHES (cptr, gbuf); /* test for switches */ -if (*cptr == 0) return SCPE_2FARG; /* must be more */ -cptr = get_glyph_nc (cptr, gbuf, 0); /* get file name */ -loadfile = fopen (gbuf, flag? "wb": "rb"); /* open for wr/rd */ -if (loadfile == NULL) return SCPE_OPENERR; -reason = sim_load (loadfile, cptr, gbuf, flag); /* load or dump */ -fclose (loadfile); -return reason; -} - -/* Attach command - - at[tach] unit file attach specified unit to file -*/ - -t_stat attach_cmd (int flag, char *cptr) -{ -char gbuf[CBUFSIZE]; -DEVICE *dptr; -UNIT *uptr; - -GET_SWITCHES (cptr, gbuf); /* test for switches */ -if (*cptr == 0) return SCPE_2FARG; /* must be more */ -cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ -if (*cptr == 0) return SCPE_2MARG; /* now eol? */ -dptr = find_unit (gbuf, &uptr); /* locate unit */ -if (dptr == NULL) return SCPE_NXDEV; /* found dev? */ -if (uptr == NULL) return SCPE_NXUN; /* valid unit? */ -if (dptr -> attach != NULL) return dptr -> attach (uptr, cptr); -return attach_unit (uptr, cptr); -} - -t_stat attach_unit (UNIT *uptr, char *cptr) -{ -DEVICE *dptr; -t_stat reason; - -if (uptr -> flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ -if (!(uptr -> flags & UNIT_ATTABLE)) return SCPE_NOATT; /* not attachable? */ -if ((dptr = find_dev_from_unit (uptr)) == NULL) return SCPE_NOATT; -if (uptr -> flags & UNIT_ATT) { /* already attached? */ - reason = detach_unit (uptr); - if (reason != SCPE_OK) return reason; } -uptr -> filename = calloc (CBUFSIZE, sizeof (char)); -if (uptr -> filename == NULL) return SCPE_MEM; -strncpy (uptr -> filename, cptr, CBUFSIZE); -if (sim_switches & SWMASK ('R')) { /* read only? */ - if ((uptr -> flags & UNIT_ROABLE) == 0) /* allowed? */ - return attach_err (uptr, SCPE_NORO); /* no, error */ - uptr -> fileref = FOPEN (cptr, "rb"); /* open rd only */ - if (uptr -> fileref == NULL) /* open fail? */ - return attach_err (uptr, SCPE_OPENERR); /* yes, error */ - uptr -> flags = uptr -> flags | UNIT_RO; /* set rd only */ - printf ("%s: unit is read only\n", dptr -> name); } -else { /* normal */ - uptr -> fileref = FOPEN (cptr, "rb+"); /* open r/w */ - if (uptr -> fileref == NULL) { /* open fail? */ - if (errno == EROFS) { /* read only? */ - if ((uptr -> flags & UNIT_ROABLE) == 0) /* allowed? */ - return attach_err (uptr, SCPE_NORO); /* no error */ - uptr -> fileref = FOPEN (cptr, "rb"); /* open rd only */ - if (uptr -> fileref == NULL) /* open fail? */ - return attach_err (uptr, SCPE_OPENERR); /* yes, error */ - uptr -> flags = uptr -> flags | UNIT_RO; /* set rd only */ - printf ("%s: unit is read only\n", dptr -> name); } - else { /* doesn't exist */ - if (sim_switches & SWMASK ('E')) /* must exist? */ - return attach_err (uptr, SCPE_OPENERR); /* yes, error */ - uptr -> fileref = FOPEN (cptr, "wb+"); /* open new file */ - if (uptr -> fileref == NULL) /* open fail? */ - return attach_err (uptr, SCPE_OPENERR); /* yes, error */ - printf ("%s: creating new file\n", dptr -> name); } - } /* end if null */ - } /* end else */ -if (uptr -> flags & UNIT_BUFABLE) { /* buffer? */ - if ((uptr -> filebuf = calloc (uptr -> capac, SZ_D (dptr))) != NULL) { - printf ("%s: buffering file in memory\n", dptr -> name); - uptr -> hwmark = fxread (uptr -> filebuf, SZ_D (dptr), - uptr -> capac, uptr -> fileref); - uptr -> flags = uptr -> flags | UNIT_BUF; } - else if (uptr -> flags & UNIT_MUSTBUF) /* must buf? */ - return attach_err (uptr, SCPE_MEM); } -uptr -> flags = uptr -> flags | UNIT_ATT; -uptr -> pos = 0; -return SCPE_OK; -} - -t_stat attach_err (UNIT *uptr, t_stat stat) -{ -free (uptr -> filename); -uptr -> filename = NULL; -return stat; -} - -/* Detach command - - det[ach] all detach all units - det[ach] unit detach specified unit -*/ - -t_stat detach_cmd (int flag, char *cptr) -{ -char gbuf[CBUFSIZE]; -DEVICE *dptr; -UNIT *uptr; - -GET_SWITCHES (cptr, gbuf); /* test for switches */ -if (*cptr == 0) return SCPE_2FARG; /* must be more */ -cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ -if (*cptr != 0) return SCPE_2MARG; /* now eol? */ -if (strcmp (gbuf, "ALL") == 0) return (detach_all (0, FALSE)); -dptr = find_unit (gbuf, &uptr); /* locate unit */ -if (dptr == NULL) return SCPE_NXDEV; /* found dev? */ -if (uptr == NULL) return SCPE_NXUN; /* valid unit? */ -if (!(uptr -> flags & UNIT_ATTABLE)) return SCPE_NOATT; -if (dptr -> detach != NULL) return dptr -> detach (uptr); -return detach_unit (uptr); -} - -/* Detach devices start..end - - Inputs: - start = number of starting device - shutdown = TRUE if simulator shutting down - Outputs: - status = error status -*/ - -t_stat detach_all (int32 start, t_bool shutdown) -{ -int32 i, j; -t_stat reason; -DEVICE *dptr; -UNIT *uptr; - -if ((start < 0) || (start > 1)) return SCPE_IERR; -for (i = start; (dptr = sim_devices[i]) != NULL; i++) { - for (j = 0; j < dptr -> numunits; j++) { - uptr = (dptr -> units) + j; - if ((uptr -> flags & UNIT_ATTABLE) || shutdown) { - if (dptr -> detach != NULL) reason = dptr -> detach (uptr); - else reason = detach_unit (uptr); - if (reason != SCPE_OK) return reason; } } } -return SCPE_OK; -} - -t_stat detach_unit (UNIT *uptr) -{ -DEVICE *dptr; - -if (uptr == NULL) return SCPE_IERR; -if (!(uptr -> flags & UNIT_ATT)) return SCPE_OK; -if ((dptr = find_dev_from_unit (uptr)) == NULL) return SCPE_OK; -if (uptr -> flags & UNIT_BUF) { - if (uptr -> hwmark && ((uptr -> flags & UNIT_RO) == 0)) { - printf ("%s: writing buffer to file\n", dptr -> name); - rewind (uptr -> fileref); - fxwrite (uptr -> filebuf, SZ_D (dptr), uptr -> hwmark, uptr -> fileref); - if (ferror (uptr -> fileref)) perror ("I/O error"); } - free (uptr -> filebuf); - uptr -> flags = uptr -> flags & ~UNIT_BUF; - uptr -> filebuf = NULL; } -uptr -> flags = uptr -> flags & ~(UNIT_ATT | UNIT_RO); -free (uptr -> filename); -uptr -> filename = NULL; -return (fclose (uptr -> fileref) == EOF)? SCPE_IOERR: SCPE_OK; -} - -/* Save command - - sa[ve] filename save state to specified file -*/ - -t_stat save_cmd (int flag, char *cptr) -{ -char gbuf[CBUFSIZE]; -void *mbuf; -FILE *sfile; -int32 i, j, l, t; -t_addr k, high; -t_value val; -t_stat r; -t_bool zeroflg; -size_t sz; -DEVICE *dptr; -UNIT *uptr; -REG *rptr; - -#define WRITE_I(xx) fxwrite (&(xx), sizeof (xx), 1, sfile) - -GET_SWITCHES (cptr, gbuf); /* test for switches */ -if (*cptr == 0) return SCPE_2FARG; /* must be more */ -if ((sfile = fopen (cptr, "wb")) == NULL) return SCPE_OPENERR; -fputs (save_vercur, sfile); /* save format version */ -fputc ('\n', sfile); -fputs (sim_name, sfile); /* sim name */ -fputc ('\n', sfile); -WRITE_I (sim_time); /* sim time */ -WRITE_I (sim_rtime); /* sim relative time */ - -for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru devices */ - fputs (dptr -> name, sfile); /* device name */ - fputc ('\n', sfile); - for (j = 0; j < dptr -> numunits; j++) { - uptr = (dptr -> units) + j; - t = sim_is_active (uptr); - WRITE_I (j); /* unit number */ - WRITE_I (t); /* activation time */ - WRITE_I (uptr -> u3); /* unit specific */ - WRITE_I (uptr -> u4); - if (uptr -> flags & UNIT_ATT) fputs (uptr -> filename, sfile); - fputc ('\n', sfile); - if (((uptr -> flags & (UNIT_FIX + UNIT_ATTABLE)) == UNIT_FIX) && - (dptr -> examine != NULL) && - ((high = uptr -> capac) != 0)) { /* memory-like unit? */ - WRITE_I (high); /* write size */ - sz = SZ_D (dptr); - if ((mbuf = calloc (SRBSIZ, sz)) == NULL) { - fclose (sfile); - return SCPE_MEM; } - for (k = 0; k < high; ) { - zeroflg = TRUE; - for (l = 0; (l < SRBSIZ) && (k < high); - l++, k = k + (dptr -> aincr)) { - r = dptr -> examine (&val, k, uptr, 0); - if (r != SCPE_OK) return r; - if (val) zeroflg = FALSE; - SZ_STORE (sz, val, mbuf, l); - } /* end for l */ - if (zeroflg) { /* all zero's? */ - l = -l; /* invert block count */ - WRITE_I (l); } /* write only count */ - else { - WRITE_I (l); /* block count */ - fxwrite (mbuf, l, sz, sfile); } - } /* end for k */ - free (mbuf); /* dealloc buffer */ - } /* end if mem */ - else { high = 0; - WRITE_I (high); } /* no memory */ - } /* end unit loop */ - j = -1; /* write marker */ - WRITE_I (j); - for (rptr = dptr -> registers; /* loop thru regs */ - (rptr != NULL) && (rptr -> name != NULL); rptr++) { - fputs (rptr -> name, sfile); /* name */ - fputc ('\n', sfile); - for (j = 0; j < rptr -> depth; j++) { /* loop thru values */ - val = get_rval (rptr, j); /* get value */ - WRITE_I (val); } } /* store */ - fputc ('\n', sfile); } /* end registers */ -fputc ('\n', sfile); /* end devices */ -r = (ferror (sfile))? SCPE_IOERR: SCPE_OK; /* error during save? */ -fclose (sfile); -return r; -} - -/* Restore command - - re[store] filename restore state from specified file -*/ - -t_stat restore_cmd (int flag, char *cptr) -{ -char buf[CBUFSIZE]; -void *mbuf; -FILE *rfile; -int32 i, j, blkcnt, limit, unitno, time; -t_addr k, high; -t_value val, mask, vzro = 0; -t_stat r; -size_t sz; -t_bool v26 = FALSE, v25 = FALSE; -DEVICE *dptr; -UNIT *uptr; -REG *rptr; - -#define READ_S(xx) if (read_line ((xx), CBUFSIZE, rfile) == NULL) \ - { fclose (rfile); return SCPE_IOERR; } -#define READ_I(xx) if (fxread (&xx, sizeof (xx), 1, rfile) <= 0) \ - { fclose (rfile); return SCPE_IOERR; } - -GET_SWITCHES (cptr, buf); /* test for switches */ -if (*cptr == 0) return SCPE_2FARG; /* must be more */ -if ((rfile = fopen (cptr, "rb")) == NULL) return SCPE_OPENERR; -READ_S (buf); /* save ver or sim name */ -if (strcmp (buf, save_vercur) == 0) { /* version 2.6? */ - v26 = v25 = TRUE; /* set flag */ - READ_S (buf); } /* read name */ -else if (strcmp (buf, save_ver25) == 0) { /* version 2.5? */ - v25 = TRUE; /* set flag */ - READ_S (buf); } /* read name */ -if (strcmp (buf, sim_name)) { /* name match? */ - printf ("Wrong system type: %s\n", buf); - fclose (rfile); - return SCPE_INCOMP; } -READ_I (sim_time); /* sim time */ -if (v26) { READ_I (sim_rtime); } /* sim relative time */ - -for ( ;; ) { /* device loop */ - READ_S (buf); /* read device name */ - if (buf[0] == 0) break; /* last? */ - if ((dptr = find_dev (buf)) == NULL) { /* locate device */ - printf ("Invalid device name: %s\n", buf); - fclose (rfile); - return SCPE_INCOMP; } - for ( ;; ) { /* unit loop */ - READ_I (unitno); /* unit number */ - if (unitno < 0) break; - if (unitno >= dptr -> numunits) { - printf ("Invalid unit number %s%d\n", dptr -> name, - unitno); - fclose (rfile); - return SCPE_INCOMP; } - READ_I (time); /* event time */ - uptr = (dptr -> units) + unitno; - sim_cancel (uptr); - if (time > 0) sim_activate (uptr, time - 1); - READ_I (uptr -> u3); /* device specific */ - READ_I (uptr -> u4); - READ_S (buf); /* attached file */ - if (buf[0] != 0) { - uptr -> flags = uptr -> flags & ~UNIT_DIS; - if (dptr -> attach != NULL) r = dptr -> attach (uptr, buf); - else r = attach_unit (uptr, buf); - if (r != SCPE_OK) return r; } - READ_I (high); /* memory capacity */ - if (high > 0) { /* any memory? */ - if (((uptr -> flags & (UNIT_FIX + UNIT_ATTABLE)) != UNIT_FIX) || - (high > uptr -> capac) || (dptr -> deposit == NULL)) { - printf ("Invalid memory bound: %u\n", high); - fclose (rfile); - return SCPE_INCOMP; } - if (v25) { - sz = SZ_D (dptr); - if ((mbuf = calloc (SRBSIZ, sz)) == NULL) { - fclose (rfile); - return SCPE_MEM; } - for (k = 0; k < high; ) { - READ_I (blkcnt); - if (blkcnt < 0) limit = -blkcnt; - else limit = fxread (mbuf, sz, blkcnt, rfile); - if (limit <= 0) { - fclose (rfile); - return SCPE_IOERR; } - for (j = 0; j < limit; j++, k = k + (dptr -> aincr)) { - if (blkcnt < 0) val = 0; - else SZ_LOAD (sz, val, mbuf, j); - r = dptr -> deposit (val, k, uptr, 0); - if (r != SCPE_OK) return r; - } /* end for j */ - } /* end for k */ - free (mbuf); /* dealloc buffer */ - } /* end if v25 */ - else { for (k = 0; k < high; k = k + (dptr -> aincr)) { - READ_I (val); - if (((t_svalue) val) < 0) { - for (j = (int32) val + 1; j < 0; j++) { - r = dptr -> deposit (vzro, k, uptr, 0); - if (r != SCPE_OK) return r; - k = k + (dptr -> aincr); } - val = 0; } - r = dptr -> deposit (val, k, uptr, 0); - if (r != SCPE_OK) return r; } - } /* end else v25 */ - } /* end if high */ - } /* end unit loop */ - for ( ;; ) { /* register loop */ - READ_S (buf); /* read reg name */ - if (buf[0] == 0) break; /* last? */ - if ((rptr = find_reg (buf, NULL, dptr)) == NULL) { - printf ("Invalid register name: %s\n", buf); - READ_I (val); /* assume depth=1 */ - continue; } /* and pray! */ - mask = width_mask[rptr -> width]; - for (i = 0; i < rptr -> depth; i++) { /* loop thru values */ - READ_I (val); /* read value */ - if (val > mask) - printf ("Invalid register value: %s\n", buf); - else put_rval (rptr, i, val); } } - } /* end device loop */ -fclose (rfile); -return SCPE_OK; -} - -/* Run, go, cont, step commands - - ru[n] [new PC] reset and start simulation - go [new PC] start simulation - co[nt] start simulation - s[tep] [step limit] start simulation for 'limit' instructions - b[oot] device bootstrap from device and start simulation -*/ - -t_stat run_cmd (int flag, char *cptr) -{ -char gbuf[CBUFSIZE]; -int32 i, j, step, unitno; -t_stat r; -DEVICE *dptr; -UNIT *uptr; -void int_handler (int signal); - -GET_SWITCHES (cptr, gbuf); /* test for switches */ -step = 0; -if (((flag == RU_RUN) || (flag == RU_GO)) && (*cptr != 0)) { /* run or go */ - cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ - if ((r = dep_reg (0, gbuf, sim_PC, 0)) != SCPE_OK) return r; } - -if (flag == RU_STEP) { /* step */ - if (*cptr == 0) step = 1; - else { cptr = get_glyph (cptr, gbuf, 0); - step = (int32) get_uint (gbuf, 10, INT_MAX, &r); - if ((r != SCPE_OK) || (step == 0)) return SCPE_ARG; } } - -if (flag == RU_BOOT) { /* boot */ - if (*cptr == 0) return SCPE_2FARG; /* must be more */ - cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ - dptr = find_unit (gbuf, &uptr); /* locate unit */ - if (dptr == NULL) return SCPE_NXDEV; /* found dev? */ - if (uptr == NULL) return SCPE_NXUN; /* valid unit? */ - if (dptr -> boot == NULL) return SCPE_NOFNC; /* can it boot? */ - if (uptr -> flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ - if ((uptr -> flags & UNIT_ATTABLE) && - !(uptr -> flags & UNIT_ATT)) return SCPE_UNATT; - unitno = uptr - dptr -> units; /* recover unit# */ - if ((r = dptr -> boot (unitno)) != SCPE_OK) return r; } - -if (*cptr != 0) return SCPE_2MARG; /* now eol? */ - -if ((flag == RU_RUN) || (flag == RU_BOOT)) { /* run or boot */ - sim_interval = 0; /* reset queue */ - sim_time = sim_rtime = 0; - noqueue_time = 0; - sim_clock_queue = NULL; - if ((r = reset_all (0)) != SCPE_OK) return r; } -for (i = 1; (dptr = sim_devices[i]) != NULL; i++) { - for (j = 0; j < dptr -> numunits; j++) { - uptr = (dptr -> units) + j; - if ((uptr -> flags & (UNIT_ATT + UNIT_SEQ)) == - (UNIT_ATT + UNIT_SEQ)) - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); } } -stop_cpu = 0; -if ((int) signal (SIGINT, int_handler) == -1) { /* set WRU */ - return SCPE_SIGERR; } -if (ttrunstate () != SCPE_OK) { /* set console */ - ttcmdstate (); - return SCPE_TTYERR; } -if (step) sim_activate (&step_unit, step); /* set step timer */ -sim_is_running = 1; /* flag running */ -r = sim_instr(); - -sim_is_running = 0; /* flag idle */ -ttcmdstate (); /* restore console */ -signal (SIGINT, SIG_DFL); /* cancel WRU */ -sim_cancel (&step_unit); /* cancel step timer */ -if (sim_clock_queue != NULL) { /* update sim time */ - UPDATE_SIM_TIME (sim_clock_queue -> time); } -else { UPDATE_SIM_TIME (noqueue_time); } -#if defined (VMS) -printf ("\n"); -#endif -fprint_stopped (stdout, r); /* print msg */ -if (sim_log) fprint_stopped (sim_log, r); /* log if enabled */ -return SCPE_OK; -} - -/* Print stopped message */ - -void fprint_stopped (FILE *stream, t_stat v) -{ -int32 i; -t_stat r; -t_addr k; -t_value pcval; -DEVICE *dptr; - -if (v >= SCPE_BASE) fprintf (stream, "\n%s, %s: ", - scp_error_messages[v - SCPE_BASE], sim_PC -> name); -else fprintf (stream, "\n%s, %s: ", sim_stop_messages[v], sim_PC -> name); -pcval = get_rval (sim_PC, 0); -fprint_val (stream, pcval, sim_PC -> radix, sim_PC -> width, - sim_PC -> flags & REG_FMT); -if (((dptr = sim_devices[0]) != NULL) && (dptr -> examine != NULL)) { - for (i = 0; i < sim_emax; i++) sim_eval[i] = 0; - for (i = 0, k = (t_addr) pcval; i < sim_emax; i++, k = k + dptr -> aincr) { - if (r = dptr -> examine (&sim_eval[i], k, dptr -> units, - SWMASK ('V')) != SCPE_OK) break; } - if ((r == SCPE_OK) || (i > 0)) { - fprintf (stream, " ("); - if (fprint_sym (stream, (t_addr) pcval, sim_eval, NULL, SWMASK('M')) > 0) - fprint_val (stream, sim_eval[0], dptr -> dradix, - dptr -> dwidth, PV_RZRO); - fprintf (stream, ")"); } } -fprintf (stream, "\n"); -return; -} - -/* Unit service for step timeout, originally scheduled by STEP n command - - Return step timeout SCP code, will cause simulation to stop -*/ - -t_stat step_svc (UNIT *uptr) -{ -return SCPE_STEP; -} - -/* Signal handler for ^C signal - - Set stop simulation flag -*/ - -void int_handler (int sig) -{ -stop_cpu = 1; -return; -} - -/* Examine/deposit commands - - ex[amine] [modifiers] list examine - de[posit] [modifiers] list val deposit - ie[xamine] [modifiers] list interactive examine - id[eposit] [modifiers] list interactive deposit - - modifiers - @filename output file - -letter(s) switches - devname'n device name and unit number - [{&|^}value]{=|==|!|!=|>|>=|<|<=} value search specification - - list list of addresses and registers - addr[:addr|-addr] address range - ALL all addresses - register[:register|-register] register range - STATE all registers -*/ - -t_stat exdep_cmd (int flag, char *cptr) -{ -char gbuf[CBUFSIZE], *gptr, *tptr; -int32 t; -t_bool exd2f; -t_addr low, high; -t_stat reason; -DEVICE *dptr, *tdptr; -UNIT *uptr, *tuptr; -REG *lowr, *highr; -SCHTAB stab, *schptr; -FILE *ofile; -t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int flag, char *ptr, - t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr); -t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int flag, char *ptr, - REG *lowr, REG *highr, t_addr lows, t_addr highs); - -ofile = NULL; /* no output file */ -exd2f = FALSE; -sim_switches = 0; /* no switches */ -schptr = NULL; /* no search */ -stab.logic = SCH_OR; /* default search params */ -stab.bool = SCH_GE; -stab.mask = stab.comp = 0; -dptr = sim_devices[0]; /* default device, unit */ -uptr = dptr -> units; -for (;;) { /* loop through modifiers */ - if (*cptr == 0) return SCPE_2FARG; /* must be more */ - if (*cptr == '@') { /* output file spec? */ - if (flag != EX_E) return SCPE_ARG; /* examine only */ - if (exd2f) { /* already got one? */ - fclose (ofile); /* one per customer */ - return SCPE_ARG; } - cptr = get_glyph_nc (cptr + 1, gbuf, 0); - ofile = fopen (gbuf, "a"); /* open for append */ - if (ofile == NULL) return SCPE_OPENERR; - exd2f = TRUE; - continue; } /* look for more */ - cptr = get_glyph (cptr, gbuf, 0); - if ((t = get_switches (gbuf)) != 0) { /* try for switches */ - if (t < 0) return SCPE_INVSW; /* err if bad switch */ - sim_switches = sim_switches | t; } /* or in new switches */ - else if (get_search (gbuf, dptr, &stab) != NULL) { /* try for search */ - schptr = &stab; } /* set search */ - else if (((tdptr = find_unit (gbuf, &tuptr)) != NULL) && - (tuptr != NULL)) { /* try for unit */ - dptr = tdptr; /* set as default */ - uptr = tuptr; } - else break; } /* not rec, break out */ -if (uptr == NULL) return SCPE_NXUN; /* got a unit? */ -if ((*cptr == 0) == (flag == 0)) return SCPE_ARG; /* eol if needed? */ - -if (ofile == NULL) ofile = stdout; /* no file? stdout */ -for (gptr = gbuf, reason = SCPE_OK; - (*gptr != 0) && (reason == SCPE_OK); gptr = tptr) { - tdptr = dptr; /* working dptr */ - if (strncmp (gptr, "STATE", strlen ("STATE")) == 0) { - tptr = gptr + strlen ("STATE"); - if (*tptr && (*tptr++ != ',')) return SCPE_ARG; - if ((lowr = dptr -> registers) == NULL) return SCPE_NXREG; - for (highr = lowr; highr -> name != NULL; highr++) ; - sim_switches = sim_switches | SWHIDE; - reason = exdep_reg_loop (ofile, schptr, flag, cptr, - lowr, --highr, 0, 0); - continue; } - - if ((lowr = find_reg (gptr, &tptr, tdptr)) || - (lowr = find_reg_glob (gptr, &tptr, &tdptr))) { - low = high = 0; - if ((*tptr == '-') || (*tptr == ':')) { - highr = find_reg (tptr + 1, &tptr, tdptr); - if (highr == NULL) return SCPE_NXREG; } - else { highr = lowr; - if (*tptr == '[') { - if (lowr -> depth <= 1) return SCPE_ARG; - tptr = get_range (tptr + 1, &low, &high, - 10, lowr -> depth - 1, ']'); - if (tptr == NULL) return SCPE_ARG; } } - if (*tptr && (*tptr++ != ',')) return SCPE_ARG; - reason = exdep_reg_loop (ofile, schptr, flag, cptr, - lowr, highr, low, high); - continue; } - - tptr = get_range (gptr, &low, &high, dptr -> aradix, - (((uptr -> capac == 0) || (flag == EX_E))? 0: - uptr -> capac - dptr -> aincr), 0); - if (tptr == NULL) return SCPE_ARG; - if (*tptr && (*tptr++ != ',')) return SCPE_ARG; - reason = exdep_addr_loop (ofile, schptr, flag, cptr, low, high, - dptr, uptr); - } /* end for */ -if (exd2f) fclose (ofile); /* close output file */ -return reason; -} - -/* Loop controllers for examine/deposit - - exdep_reg_loop examine/deposit range of registers - exdep_addr_loop examine/deposit range of addresses -*/ - -t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int flag, char *cptr, - REG *lowr, REG *highr, t_addr lows, t_addr highs) -{ -t_stat reason; -t_addr idx; -t_value val; -REG *rptr; - -if ((lowr == NULL) || (highr == NULL)) return SCPE_IERR; -if (lowr > highr) return SCPE_ARG; -for (rptr = lowr; rptr <= highr; rptr++) { - if ((sim_switches & SWHIDE) && - (rptr -> flags & REG_HIDDEN)) continue; - for (idx = lows; idx <= highs; idx++) { - if (idx >= (t_addr) rptr -> depth) return SCPE_SUB; - val = get_rval (rptr, idx); - if (schptr && !test_search (val, schptr)) continue; - if (flag != EX_D) { - reason = ex_reg (ofile, val, flag, rptr, idx); - if (reason != SCPE_OK) return reason; - if (sim_log && (ofile == stdout)) - ex_reg (sim_log, val, flag, rptr, idx); } - if (flag != EX_E) { - reason = dep_reg (flag, cptr, rptr, idx); - if (reason != SCPE_OK) return reason; } } } -return SCPE_OK; -} - -t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int flag, char *cptr, - t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr) -{ -t_addr i, mask; -t_stat reason; - -if (uptr -> flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ -reason = 0; -mask = (t_addr) width_mask[dptr -> awidth]; -if ((low > mask) || (high > mask) || (low > high)) return SCPE_ARG; -for (i = low; i <= high; i = i + (dptr -> aincr)) { - reason = get_aval (i, dptr, uptr); /* get data */ - if (reason != SCPE_OK) return reason; /* return if error */ - if (schptr && !test_search (sim_eval[0], schptr)) continue; - if (flag != EX_D) { - reason = ex_addr (ofile, flag, i, dptr, uptr); - if (reason > SCPE_OK) return reason; - if (sim_log && (ofile == stdout)) - ex_addr (sim_log, flag, i, dptr, uptr); } - if (flag != EX_E) { - reason = dep_addr (flag, cptr, i, dptr, uptr, reason); - if (reason > SCPE_OK) return reason; } - if (reason < SCPE_OK) i = i - (reason * dptr -> aincr); } -return SCPE_OK; -} - -/* Examine register routine - - Inputs: - ofile = output stream - val = current register value - flag = type of ex/mod command (ex, iex, idep) - rptr = pointer to register descriptor - idx = index - Outputs: - return = error status -*/ - -t_stat ex_reg (FILE *ofile, t_value val, int flag, REG *rptr, t_addr idx) -{ -int32 rdx; - -if (rptr == NULL) return SCPE_IERR; -if (rptr -> depth > 1) fprintf (ofile, "%s[%d]: ", rptr -> name, idx); -else fprintf (ofile, "%s: ", rptr -> name); -if (!(flag & EX_E)) return SCPE_OK; -GET_RADIX (rdx, rptr -> radix); -fprint_val (ofile, val, rdx, rptr -> width, rptr -> flags & REG_FMT); -if (flag & EX_I) fprintf (ofile, " "); -else fprintf (ofile, "\n"); -return SCPE_OK; -} - -/* Get register value - - Inputs: - rptr = pointer to register descriptor - idx = index - Outputs: - return = register value -*/ - -t_value get_rval (REG *rptr, int idx) -{ -size_t sz; -t_value val; -UNIT *uptr; - -sz = SZ_R (rptr); -if ((rptr -> depth > 1) && (rptr -> flags & REG_CIRC)) { - idx = idx + rptr -> qptr; - if (idx >= rptr -> depth) idx = idx - rptr -> depth; } -if ((rptr -> depth > 1) && (rptr -> flags & REG_UNIT)) { - uptr = ((UNIT *) rptr -> loc) + idx; - val = *((uint32 *) uptr); } -else if ((rptr -> depth > 1) && (sz == sizeof (uint8))) - val = *(((uint8 *) rptr -> loc) + idx); -else if ((rptr -> depth > 1) && (sz == sizeof (uint16))) - val = *(((uint16 *) rptr -> loc) + idx); -#if !defined (t_int64) -else val = *(((uint32 *) rptr -> loc) + idx); -#else -else if (sz <= sizeof (uint32)) - val = *(((uint32 *) rptr -> loc) + idx); -else val = *(((t_uint64 *) rptr -> loc) + idx); -#endif -val = (val >> rptr -> offset) & width_mask[rptr -> width]; -return val; -} - -/* Deposit register routine - - Inputs: - flag = type of deposit (normal/interactive) - cptr = pointer to input string - rptr = pointer to register descriptor - idx = index - Outputs: - return = error status -*/ - -t_stat dep_reg (int flag, char *cptr, REG *rptr, t_addr idx) -{ -t_stat r; -t_value val, mask; -int32 rdx; -char gbuf[CBUFSIZE]; - -if ((cptr == NULL) || (rptr == NULL)) return SCPE_IERR; -if (rptr -> flags & REG_RO) return SCPE_RO; -if (flag & EX_I) { - cptr = read_line (gbuf, CBUFSIZE, stdin); - if (sim_log) fprintf (sim_log, (cptr? "%s\n": "\n"), cptr); - if (cptr == NULL) return 1; /* force exit */ - if (*cptr == 0) return SCPE_OK; } /* success */ -mask = width_mask[rptr -> width]; -GET_RADIX (rdx, rptr -> radix); -val = get_uint (cptr, rdx, mask, &r); -if (r != SCPE_OK) return SCPE_ARG; -if ((rptr -> flags & REG_NZ) && (val == 0)) return SCPE_ARG; -put_rval (rptr, idx, val); -return SCPE_OK; -} - -/* Put register value - - Inputs: - rptr = pointer to register descriptor - idx = index - val = new value - mask = mask - Outputs: - none -*/ - -void put_rval (REG *rptr, int idx, t_value val) -{ -size_t sz; -t_value mask; -UNIT *uptr; - -#define PUT_RVAL(sz,rp,id,v,m) \ - *(((sz *) rp -> loc) + id) = \ - (*(((sz *) rp -> loc) + id) & \ - ~((m) << (rp) -> offset)) | ((v) << (rp) -> offset) - -if (rptr == sim_PC) sim_brk_npc (); -sz = SZ_R (rptr); -mask = width_mask[rptr -> width]; -if ((rptr -> depth > 1) && (rptr -> flags & REG_CIRC)) { - idx = idx + rptr -> qptr; - if (idx >= rptr -> depth) idx = idx - rptr -> depth; } -if ((rptr -> depth > 1) && (rptr -> flags & REG_UNIT)) { - uptr = ((UNIT *) rptr -> loc) + idx; - *((uint32 *) uptr) = - (*((uint32 *) uptr) & - ~(((uint32) mask) << rptr -> offset)) | - (((uint32) val) << rptr -> offset); } -else if ((rptr -> depth > 1) && (sz == sizeof (uint8))) - PUT_RVAL (uint8, rptr, idx, (uint32) val, (uint32) mask); -else if ((rptr -> depth > 1) && (sz == sizeof (uint16))) - PUT_RVAL (uint16, rptr, idx, (uint32) val, (uint32) mask); -#if !defined (t_int64) -else PUT_RVAL (uint32, rptr, idx, val, mask); -#else -else if (sz <= sizeof (uint32)) - PUT_RVAL (uint32, rptr, idx, (int32) val, (uint32) mask); -else PUT_RVAL (t_uint64, rptr, idx, val, mask); -#endif -return; -} - -/* Examine address routine - - Inputs: (sim_eval is an implicit argument) - ofile = output stream - flag = type of ex/mod command (ex, iex, idep) - addr = address to examine - dptr = pointer to device - uptr = pointer to unit - Outputs: - return = if >= 0, error status - if < 0, number of extra words retired -*/ - -t_stat ex_addr (FILE *ofile, int flag, t_addr addr, DEVICE *dptr, UNIT *uptr) -{ -t_stat reason; -int32 rdx; - -fprint_val (ofile, addr, dptr -> aradix, dptr -> awidth, PV_LEFT); -fprintf (ofile, ": "); -if (!(flag & EX_E)) return SCPE_OK; - -GET_RADIX (rdx, dptr -> dradix); -if ((reason = fprint_sym (ofile, addr, sim_eval, uptr, sim_switches)) > 0) - reason = fprint_val (ofile, sim_eval[0], rdx, dptr -> dwidth, PV_RZRO); -if (flag & EX_I) fprintf (ofile, " "); -else fprintf (ofile, "\n"); -return reason; -} - -/* Get address routine - - Inputs: - flag = type of ex/mod command (ex, iex, idep) - addr = address to examine - dptr = pointer to device - uptr = pointer to unit - Outputs: (sim_eval is an implicit output) - return = error status -*/ - -t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr) -{ -int32 i; -t_value mask; -t_addr j, loc; -t_stat reason = SCPE_OK; -size_t sz; - -if ((dptr == NULL) || (uptr == NULL)) return SCPE_IERR; -mask = width_mask[dptr -> dwidth]; -for (i = 0; i < sim_emax; i++) sim_eval[i] = 0; -for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr -> aincr) { - if (dptr -> examine != NULL) { - reason = dptr -> examine (&sim_eval[i], j, uptr, sim_switches); - if (reason != SCPE_OK) break; } - else { if (!(uptr -> flags & UNIT_ATT)) return SCPE_UNATT; - if ((uptr -> flags & UNIT_FIX) && (j >= uptr -> capac)) { - reason = SCPE_NXM; - break; } - sz = SZ_D (dptr); - loc = j / dptr -> aincr; - if (uptr -> flags & UNIT_BUF) { - SZ_LOAD (sz, sim_eval[i], uptr -> filebuf, loc); } - else { fseek (uptr -> fileref, sz * loc, SEEK_SET); - fxread (&sim_eval[i], sz, 1, uptr -> fileref); - if ((feof (uptr -> fileref)) && - !(uptr -> flags & UNIT_FIX)) { - reason = SCPE_EOF; - break; } - else if (ferror (uptr -> fileref)) { - clearerr (uptr -> fileref); - reason = SCPE_IOERR; - break; } } } - sim_eval[i] = sim_eval[i] & mask; } -if ((reason != SCPE_OK) && (i == 0)) return reason; -return SCPE_OK; -} - -/* Deposit address routine - - Inputs: - flag = type of deposit (normal/interactive) - cptr = pointer to input string - addr = address to examine - dptr = pointer to device - uptr = pointer to unit - dfltinc = value to return on cr input - Outputs: - return = if >= 0, error status - if < 0, number of extra words retired -*/ - -t_stat dep_addr (int flag, char *cptr, t_addr addr, DEVICE *dptr, - UNIT *uptr, int dfltinc) -{ -int32 i, count, rdx; -t_addr j, loc; -t_stat r, reason; -t_value mask; -size_t sz; -char gbuf[CBUFSIZE]; - -if (dptr == NULL) return SCPE_IERR; -if (flag & EX_I) { - cptr = read_line (gbuf, CBUFSIZE, stdin); - if (sim_log) fprintf (sim_log, (cptr? "%s\n": "\n"), cptr); - if (cptr == NULL) return 1; /* force exit */ - if (*cptr == 0) return dfltinc; } /* success */ -if (uptr -> flags & UNIT_RO) return SCPE_RO; /* read only? */ -mask = width_mask[dptr -> dwidth]; - -GET_RADIX (rdx, dptr -> dradix); -if ((reason = parse_sym (cptr, addr, uptr, sim_eval, sim_switches)) > 0) { - sim_eval[0] = get_uint (cptr, rdx, mask, &reason); - if (reason != SCPE_OK) return reason; } -count = 1 - reason; - -for (i = 0, j = addr; i < count; i++, j = j + dptr -> aincr) { - sim_eval[i] = sim_eval[i] & mask; - if (dptr -> deposit != NULL) { - r = dptr -> deposit (sim_eval[i], j, uptr, sim_switches); - if (r != SCPE_OK) return r; } - else { if (!(uptr -> flags & UNIT_ATT)) return SCPE_UNATT; - if ((uptr -> flags & UNIT_FIX) && (j >= uptr -> capac)) - return SCPE_NXM; - sz = SZ_D (dptr); - loc = j / dptr -> aincr; - if (uptr -> flags & UNIT_BUF) { - SZ_STORE (sz, sim_eval[i], uptr -> filebuf, loc); - if (loc >= uptr -> hwmark) uptr -> hwmark = loc + 1; } - else { fseek (uptr -> fileref, sz * loc, SEEK_SET); - fxwrite (sim_eval, sz, 1, uptr -> fileref); - if (ferror (uptr -> fileref)) { - clearerr (uptr -> fileref); - return SCPE_IOERR; } } } } -return reason; -} - -/* String processing routines - - read_line read line - - Inputs: - cptr = pointer to buffer - size = maximum size - stream = pointer to input stream - Outputs: - optr = pointer to first non-blank character - NULL if EOF -*/ - -char *read_line (char *cptr, int size, FILE *stream) -{ -char *tptr; - -cptr = fgets (cptr, size, stream); /* get cmd line */ -if (cptr == NULL) { - clearerr (stream); /* clear error */ - return NULL; } /* ignore EOF */ -for (tptr = cptr; tptr < (cptr + size); tptr++) /* remove cr */ - if (*tptr == '\n') *tptr = 0; -while (isspace (*cptr)) cptr++; /* absorb spaces */ -if (*cptr == ';') *cptr = 0; /* ignore comment */ -return cptr; -} - -/* get_glyph get next glyph (force upper case) - get_glyph_nc get next glyph (no conversion) - get_glyph_gen get next glyph (general case) - - Inputs: - iptr = pointer to input string - optr = pointer to output string - mchar = optional end of glyph character - flag = TRUE for convert to upper case (_gen only) - Outputs - result = pointer to next character in input string -*/ - -char *get_glyph_gen (char *iptr, char *optr, char mchar, t_bool uc) -{ -while ((isspace (*iptr) == 0) && (*iptr != 0) && (*iptr != mchar)) { - if (islower (*iptr) && uc) *optr = toupper (*iptr); - else *optr = *iptr; - iptr++; optr++; } -*optr = 0; -if (mchar && (*iptr == mchar)) iptr++; /* skip terminator */ -while (isspace (*iptr)) iptr++; /* absorb spaces */ -return iptr; -} - -char *get_glyph (char *iptr, char *optr, char mchar) -{ -return get_glyph_gen (iptr, optr, mchar, TRUE); -} - -char *get_glyph_nc (char *iptr, char *optr, char mchar) -{ -return get_glyph_gen (iptr, optr, mchar, FALSE); -} - -/* get_yn yes/no question - - Inputs: - cptr = pointer to question - deflt = default answer - Outputs: - result = true if yes, false if no -*/ - -t_stat get_yn (char *ques, t_stat deflt) -{ -char cbuf[CBUFSIZE], *cptr; - -printf ("%s ", ques); -cptr = read_line (cbuf, CBUFSIZE, stdin); -if ((cptr == NULL) || (*cptr == 0)) return deflt; -if ((*cptr == 'Y') || (*cptr == 'y')) return TRUE; -return FALSE; -} - -/* get_uint unsigned number - - Inputs: - cptr = pointer to input string - radix = input radix - max = maximum acceptable value - *status = pointer to error status - Outputs: - val = value -*/ - -t_value get_uint (char *cptr, int radix, t_value max, t_stat *status) -{ -t_value val; -char *tptr; - -val = strtotv (cptr, &tptr, radix); -if ((cptr == tptr) || (val > max) || (*tptr != 0)) *status = SCPE_ARG; -else *status = SCPE_OK; -return val; -} - -/* get_range range specification - - Inputs: - cptr = pointer to input string - *lo = pointer to low result - *hi = pointer to high result - aradix = address radix - max = default high value - term = terminating character, 0 if none - Outputs: - tptr = input pointer after processing - NULL if error -*/ - -char *get_range (char *cptr, t_addr *lo, t_addr *hi, int rdx, - t_addr max, char term) -{ -char *tptr; -t_addr hb; - -*lo = *hi = hb = 0; -if (max && strncmp (cptr, "ALL", strlen ("ALL")) == 0) { /* ALL? */ - tptr = cptr + strlen ("ALL"); - *hi = max; } -else { errno = 0; - *lo = strtoul (cptr, &tptr, rdx); /* get low */ - if (errno || (cptr == tptr)) return NULL; /* error? */ - if ((*tptr == '-') || (*tptr == ':') || (*tptr == '/')) { - if (*tptr == '/') hb = *lo; /* relative? */ - cptr = tptr + 1; - errno = 0; - *hi = hb + strtoul (cptr, &tptr, rdx); /* get high */ - if (errno || (cptr == tptr)) return NULL; - if (*lo > *hi) return NULL; } - else *hi = *lo; } -if (term && (*tptr++ != term)) return NULL; -return tptr; -} - -/* Find_device find device matching input string - - Inputs: - cptr = pointer to input string - Outputs: - result = pointer to device -*/ - -DEVICE *find_dev (char *cptr) -{ -int32 i; -DEVICE *dptr; - -for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { - if (strcmp (cptr, dptr -> name) == 0) return dptr; } -return NULL; -} - -/* Find_unit find unit matching input string - - Inputs: - cptr = pointer to input string - uptr = pointer to unit pointer - Outputs: - result = pointer to device (null if no dev) - *iptr = pointer to unit (null if nx unit) -*/ - -DEVICE *find_unit (char *cptr, UNIT **uptr) -{ -int32 i, lenn, u; -t_stat r; -DEVICE *dptr; - -if (uptr == NULL) return NULL; /* arg error? */ -for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* exact match? */ - if (strcmp (cptr, dptr -> name) == 0) { - if (qdisable (dptr)) return NULL; /* disabled? */ - *uptr = dptr -> units; /* unit 0 */ - return dptr; } } - -for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* base + unit#? */ - lenn = strlen (dptr -> name); - if ((dptr -> numunits == 0) || /* no units? */ - (strncmp (cptr, dptr -> name, lenn) != 0)) continue; - if (qdisable (dptr)) return NULL; /* disabled? */ - cptr = cptr + lenn; /* skip devname */ - u = (int32) get_uint (cptr, 10, dptr -> numunits - 1, &r); - if (r != SCPE_OK) *uptr = NULL; /* error? */ - else *uptr = dptr -> units + u; - return dptr; } -return NULL; -} - -/* Find_dev_from_unit find device for unit - - Inputs: - uptr = pointer to unit - Outputs: - result = pointer to device -*/ - -DEVICE *find_dev_from_unit (UNIT *uptr) -{ -DEVICE *dptr; -int32 i, j; - -if (uptr == NULL) return NULL; -for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { - for (j = 0; j < dptr -> numunits; j++) { - if (uptr == (dptr -> units + j)) return dptr; } } -return NULL; -} - -/* Test for disabled device */ - -t_bool qdisable (DEVICE *dptr) -{ -REG *rptr; - -rptr = find_reg ("*DEVENB", NULL, dptr); /* locate enable */ -if (rptr == NULL) return FALSE; /* found it? */ -return (get_rval (rptr, 0)? FALSE: TRUE); /* return flag */ -} - -/* find_reg_glob find globally unique register - - Inputs: - cptr = pointer to input string - optr = pointer to output pointer (can be null) - gdptr = pointer to global device - Outputs: - result = pointer to register, NULL if error - *optr = pointer to next character in input string - *gdptr = pointer to device where found -*/ - -REG *find_reg_glob (char *cptr, char **optr, DEVICE **gdptr) -{ -int32 i; -DEVICE *dptr; -REG *rptr, *srptr = NULL; - -for (i = 0; (dptr = sim_devices[i]) != 0; i++) { /* all dev */ - if (rptr = find_reg (cptr, optr, dptr)) { /* found? */ - if (srptr) return NULL; /* ambig? err */ - srptr = rptr; /* save reg */ - *gdptr = dptr; } } /* save unit */ -return srptr; -} - -/* find_reg find register matching input string - - Inputs: - cptr = pointer to input string - optr = pointer to output pointer (can be null) - dptr = pointer to device - Outputs: - result = pointer to register, NULL if error - *optr = pointer to next character in input string -*/ - -REG *find_reg (char *cptr, char **optr, DEVICE *dptr) -{ -char *tptr; -REG *rptr; - -if ((cptr == NULL) || (dptr == NULL) || - (dptr -> registers == NULL)) return NULL; -tptr = cptr; -do { tptr++; } - while (isalnum (*tptr) || (*tptr == '*') || (*tptr == '_')); -for (rptr = dptr -> registers; rptr -> name != NULL; rptr++) { - if (strncmp (cptr, rptr -> name, tptr - cptr) == 0) { - if (optr != NULL) *optr = tptr; - return rptr; } } -return NULL; -} - -/* get_switches get switches from input string - - Inputs: - cptr = pointer to input string - Outputs: - sw = switch bit mask - 0 if no switches, -1 if error -*/ - -int32 get_switches (char *cptr) -{ -int32 sw; - -if (*cptr != '-') return 0; -sw = 0; -for (cptr++; (isspace (*cptr) == 0) && (*cptr != 0); cptr++) { - if (isalpha (*cptr) == 0) return -1; - sw = sw | SWMASK (*cptr); } -return sw; -} - -t_bool match_ext (char *fnam, char *ext) -{ -char *fptr, *eptr; - -if ((fnam == NULL) || (ext == NULL)) return FALSE; -fptr = strrchr (fnam, '.'); -if (fptr == NULL) return FALSE; -for (fptr++, eptr = ext; *fptr; fptr++, eptr++) { - if (toupper (*fptr) != toupper (*eptr)) return FALSE; } -if (*eptr) return FALSE; -return TRUE; -} - -/* Get search specification - - Inputs: - cptr = pointer to input string - dptr = pointer to device - schptr = pointer to search table - Outputs: - return = NULL if error - schptr if valid search specification -*/ - -SCHTAB *get_search (char *cptr, DEVICE *dptr, SCHTAB *schptr) -{ -int c, logop, cmpop; -t_value logval, cmpval; -char *sptr, *tptr; -const char logstr[] = "|&^", cmpstr[] = "=!><"; - -if (*cptr == 0) return NULL; /* check for clause */ -for (logop = cmpop = -1; c = *cptr++; ) { /* loop thru clauses */ - if (sptr = strchr (logstr, c)) { /* check for mask */ - logop = sptr - logstr; - logval = strtotv (cptr, &tptr, dptr -> dradix); - if (cptr == tptr) return NULL; - cptr = tptr; } - else if (sptr = strchr (cmpstr, c)) { /* check for bool */ - cmpop = sptr - cmpstr; - if (*cptr == '=') { - cmpop = cmpop + strlen (cmpstr); - cptr++; } - cmpval = strtotv (cptr, &tptr, dptr -> dradix); - if (cptr == tptr) return NULL; - cptr = tptr; } - else return NULL; } /* end while */ -if (logop >= 0) { - schptr -> logic = logop; - schptr -> mask = logval; } -if (cmpop >= 0) { - schptr -> bool = cmpop; - schptr -> comp = cmpval; } -return schptr; -} - -/* Test value against search specification - - Inputs: - val = value to test - schptr = pointer to search table - Outputs: - return = 1 if value passes search criteria, 0 if not -*/ - -int test_search (t_value val, SCHTAB *schptr) -{ -if (schptr == NULL) return 0; -switch (schptr -> logic) { /* case on logical */ -case SCH_OR: - val = val | schptr -> mask; - break; -case SCH_AND: - val = val & schptr -> mask; - break; -case SCH_XOR: - val = val ^ schptr -> mask; - break; } -switch (schptr -> bool) { /* case on comparison */ -case SCH_E: case SCH_EE: - return (val == schptr -> comp); -case SCH_N: case SCH_NE: - return (val != schptr -> comp); -case SCH_G: - return (val > schptr -> comp); -case SCH_GE: - return (val >= schptr -> comp); -case SCH_L: - return (val < schptr -> comp); -case SCH_LE: - return (val <= schptr -> comp); } -return 0; -} - -/* Radix independent input/output package - - strtotv - general radix input routine - - Inputs: - inptr = string to convert - endptr = pointer to first unconverted character - radix = radix for input - Outputs: - value = converted value - - On an error, the endptr will equal the inptr. -*/ - -t_value strtotv (char *inptr, char **endptr, int radix) -{ -int nodigit; -t_value val; -int c, digit; - -*endptr = inptr; /* assume fails */ -if ((radix < 2) || (radix > 36)) return 0; -while (isspace (*inptr)) inptr++; /* bypass white space */ -val = 0; -nodigit = 1; -for (c = *inptr; isalnum(c); c = *++inptr) { /* loop through char */ - if (islower (c)) c = toupper (c); - if (isdigit (c)) digit = c - (int) '0'; /* digit? */ - else digit = c + 10 - (int) 'A'; /* no, letter */ - if (digit >= radix) return 0; /* valid in radix? */ - val = (val * radix) + digit; /* add to value */ - nodigit = 0; } -if (nodigit) return 0; /* no digits? */ -*endptr = inptr; /* result pointer */ -return val; -} - -/* fprint_val - general radix printing routine - - Inputs: - stream = stream designator - val = value to print - radix = radix to print - width = width to print - format = leading zeroes format - Outputs: - status = error status -*/ - -t_stat fprint_val (FILE *stream, t_value val, int radix, - int width, int format) -{ -#define MAX_WIDTH ((int) (CHAR_BIT * sizeof (t_value))) -t_value owtest, wtest; -int32 d, digit, ndigits; -char dbuf[MAX_WIDTH + 1]; - -for (d = 0; d < MAX_WIDTH; d++) dbuf[d] = (format == PV_RZRO)? '0': ' '; -dbuf[MAX_WIDTH] = 0; -d = MAX_WIDTH; -do { d = d - 1; - digit = (int32) (val % (unsigned) radix); - val = val / (unsigned) radix; - dbuf[d] = (digit <= 9)? '0' + digit: 'A' + (digit - 10); - } while ((d > 0) && (val != 0)); - -if (format != PV_LEFT) { - wtest = owtest = radix; - ndigits = 1; - while ((wtest < width_mask[width]) && (wtest >= owtest)) { - owtest = wtest; - wtest = wtest * radix; - ndigits = ndigits + 1; } - if ((MAX_WIDTH - ndigits) < d) d = MAX_WIDTH - ndigits; } -if (fputs (&dbuf[d], stream) == EOF) return SCPE_IOERR; -return SCPE_OK; -} - -/* Event queue package - - sim_activate add entry to event queue - sim_cancel remove entry from event queue - sim_process_event process entries on event queue - sim_is_active see if entry is on event queue - sim_atime return absolute time for an entry - sim_gtime return global time - sim_qcount return event queue entry count - - Asynchronous events are set up by queueing a unit data structure - to the event queue with a timeout (in simulator units, relative - to the current time). Each simulator 'times' these events by - counting down interval counter sim_interval. When this reaches - zero the simulator calls sim_process_event to process the event - and to see if further events need to be processed, or sim_interval - reset to count the next one. - - The event queue is maintained in clock order; entry timeouts are - RELATIVE to the time in the previous entry. - - sim_process_event - process event - - Inputs: - none - Outputs: - reason reason code returned by any event processor, - or 0 (SCPE_OK) if no exceptions -*/ - -t_stat sim_process_event (void) -{ -UNIT *uptr; -t_stat reason; - -if (stop_cpu) return SCPE_STOP; /* stop CPU? */ -if (sim_clock_queue == NULL) { /* queue empty? */ - UPDATE_SIM_TIME (noqueue_time); /* update sim time */ - sim_interval = noqueue_time = NOQUEUE_WAIT; /* flag queue empty */ - return SCPE_OK; } -UPDATE_SIM_TIME (sim_clock_queue -> time); /* update sim time */ -do { uptr = sim_clock_queue; /* get first */ - sim_clock_queue = uptr -> next; /* remove first */ - uptr -> next = NULL; /* hygiene */ - uptr -> time = 0; - if (sim_clock_queue != NULL) sim_interval = sim_clock_queue -> time; - else sim_interval = noqueue_time = NOQUEUE_WAIT; - if (uptr -> action != NULL) reason = uptr -> action (uptr); - else reason = SCPE_OK; - } while ((reason == SCPE_OK) && (sim_interval == 0)); - -/* Empty queue forces sim_interval != 0 */ - -return reason; -} - -/* sim_activate - activate (queue) event - - Inputs: - uptr = pointer to unit - event_time = relative timeout - Outputs: - reason = result (SCPE_OK if ok) -*/ - -t_stat sim_activate (UNIT *uptr, int32 event_time) -{ -UNIT *cptr, *prvptr; -int32 accum; - -if (event_time < 0) return SCPE_IERR; -if (sim_is_active (uptr)) return SCPE_OK; /* already active? */ -if (sim_clock_queue == NULL) { UPDATE_SIM_TIME (noqueue_time); } -else { UPDATE_SIM_TIME (sim_clock_queue -> time); } /* update sim time */ - -prvptr = NULL; -accum = 0; -for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr -> next) { - if (event_time < (accum + cptr -> time)) break; - accum = accum + cptr -> time; - prvptr = cptr; } -if (prvptr == NULL) { /* insert at head */ - cptr = uptr -> next = sim_clock_queue; - sim_clock_queue = uptr; } -else { cptr = uptr -> next = prvptr -> next; /* insert at prvptr */ - prvptr -> next = uptr; } -uptr -> time = event_time - accum; -if (cptr != NULL) cptr -> time = cptr -> time - uptr -> time; -sim_interval = sim_clock_queue -> time; -return SCPE_OK; -} - -/* sim_cancel - cancel (dequeue) event - - Inputs: - uptr = pointer to unit - Outputs: - reason = result (SCPE_OK if ok) - -*/ - -t_stat sim_cancel (UNIT *uptr) -{ -UNIT *cptr, *nptr; - -if (sim_clock_queue == NULL) return SCPE_OK; -UPDATE_SIM_TIME (sim_clock_queue -> time); /* update sim time */ -nptr = NULL; -if (sim_clock_queue == uptr) nptr = sim_clock_queue = uptr -> next; -else { for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr -> next) { - if (cptr -> next == uptr) { - nptr = cptr -> next = uptr -> next; - break; } } } /* end queue scan */ -if (nptr != NULL) nptr -> time = nptr -> time + uptr -> time; -uptr -> next = NULL; /* hygiene */ -uptr -> time = 0; -if (sim_clock_queue != NULL) sim_interval = sim_clock_queue -> time; -else sim_interval = noqueue_time = NOQUEUE_WAIT; -return SCPE_OK; -} - -/* sim_is_active - test for entry in queue, return activation time - - Inputs: - uptr = pointer to unit - Outputs: - result = absolute activation time + 1, 0 if inactive -*/ - -int32 sim_is_active (UNIT *uptr) -{ -UNIT *cptr; -int32 accum; - -accum = 0; -for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr -> next) { - accum = accum + cptr -> time; - if (cptr == uptr) return accum + 1; } -return 0; -} - -/* sim_gtime - return global time - sim_grtime - return global time with rollover - - Inputs: none - Outputs: - time = global time -*/ - -double sim_gtime (void) -{ -if (sim_clock_queue == NULL) { UPDATE_SIM_TIME (noqueue_time); } -else { UPDATE_SIM_TIME (sim_clock_queue -> time); } -return sim_time; -} - -uint32 sim_grtime (void) -{ -if (sim_clock_queue == NULL) { UPDATE_SIM_TIME (noqueue_time); } -else { UPDATE_SIM_TIME (sim_clock_queue -> time); } -return sim_rtime; -} - -/* sim_qcount - return queue entry count - - Inputs: none - Outputs: - count = number of entries on the queue -*/ - -int32 sim_qcount (void) -{ -int32 cnt; -UNIT *uptr; - -cnt = 0; -for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr -> next) cnt++; -return cnt; -} - -/* Endian independent binary I/O package - - For consistency, all binary data read and written by the simulator - is stored in little endian data order. That is, in a multi-byte - data item, the bytes are written out right to left, low order byte - to high order byte. On a big endian host, data is read and written - from high byte to low byte. Consequently, data written on a little - endian system must be byte reversed to be usable on a big endian - system, and vice versa. - - These routines are analogs of the standard C runtime routines - fread and fwrite. If the host is little endian, or the data items - are size char, then the calls are passed directly to fread or - fwrite. Otherwise, these routines perform the necessary byte swaps - using an intermediate buffer. -*/ - -size_t fxread (void *bptr, size_t size, size_t count, FILE *fptr) -{ -size_t c, j, nelem, nbuf, lcnt, total; -int32 i, k; -unsigned char *sptr, *dptr; - -if (sim_end || (size == sizeof (char))) - return fread (bptr, size, count, fptr); -if ((size == 0) || (count == 0)) return 0; -nelem = FLIP_SIZE / size; /* elements in buffer */ -nbuf = count / nelem; /* number buffers */ -lcnt = count % nelem; /* count in last buf */ -if (lcnt) nbuf = nbuf + 1; -else lcnt = nelem; -total = 0; -dptr = bptr; /* init output ptr */ -for (i = nbuf; i > 0; i--) { - c = fread (sim_flip, size, (i == 1? lcnt: nelem), fptr); - if (c == 0) return total; - total = total + c; - for (j = 0, sptr = sim_flip; j < c; j++) { - for (k = size - 1; k >= 0; k--) *(dptr + k) = *sptr++; - dptr = dptr + size; } } -return total; -} - -size_t fxwrite (void *bptr, size_t size, size_t count, FILE *fptr) -{ -size_t c, j, nelem, nbuf, lcnt, total; -int32 i, k; -unsigned char *sptr, *dptr; - -if (sim_end || (size == sizeof (char))) - return fwrite (bptr, size, count, fptr); -if ((size == 0) || (count == 0)) return 0; -nelem = FLIP_SIZE / size; /* elements in buffer */ -nbuf = count / nelem; /* number buffers */ -lcnt = count % nelem; /* count in last buf */ -if (lcnt) nbuf = nbuf + 1; -else lcnt = nelem; -total = 0; -sptr = bptr; /* init input ptr */ -for (i = nbuf; i > 0; i--) { - c = (i == 1)? lcnt: nelem; - for (j = 0, dptr = sim_flip; j < c; j++) { - for (k = size - 1; k >= 0; k--) *(dptr + k) = *sptr++; - dptr = dptr + size; } - c = fwrite (sim_flip, size, c, fptr); - if (c == 0) return total; - total = total + c; } -return total; -} - -/* OS independent clock calibration package - - sim_rtc_init initialize calibration - sim_rtc_calb calibrate clock -*/ - -static int32 rtc_ticks[SIM_NTIMERS] = { 0 }; /* ticks */ -static uint32 rtc_rtime[SIM_NTIMERS] = { 0 }; /* real time */ -static uint32 rtc_vtime[SIM_NTIMERS] = { 0 }; /* virtual time */ -static uint32 rtc_nxintv[SIM_NTIMERS] = { 0 }; /* next interval */ -static int32 rtc_based[SIM_NTIMERS] = { 0 }; /* base delay */ -static int32 rtc_currd[SIM_NTIMERS] = { 0 }; /* current delay */ -extern t_bool rtc_avail; - -int32 sim_rtcn_init (int32 time, int32 tmr) -{ -if ((tmr < 0) || (tmr > SIM_NTIMERS)) return time; -rtc_rtime[tmr] = sim_os_msec (); -rtc_vtime[tmr] = rtc_rtime[tmr]; -rtc_nxintv[tmr] = 1000; -rtc_ticks[tmr] = 0; -rtc_based[tmr] = time; -rtc_currd[tmr] = time; -return time; -} - -int32 sim_rtcn_calb (int32 ticksper, int32 tmr) -{ -uint32 new_rtime, delta_rtime; -int32 delta_vtime; - -if ((tmr < 0) || (tmr > SIM_NTIMERS)) return 10000; -rtc_ticks[tmr] = rtc_ticks[tmr] + 1; /* count ticks */ -if (rtc_ticks[tmr] < ticksper) return rtc_currd[tmr]; /* 1 sec yet? */ -rtc_ticks[tmr] = 0; /* reset ticks */ -if (!rtc_avail) return rtc_currd[tmr]; /* no timer? */ -new_rtime = sim_os_msec (); /* wall time */ -delta_rtime = new_rtime - rtc_rtime[tmr]; /* elapsed wtime */ -if (delta_rtime == 0) return rtc_currd[tmr]; /* can't calibr */ -rtc_based[tmr] = (int32) (((double) rtc_based[tmr] * (double) rtc_nxintv[tmr]) / - ((double) delta_rtime)); /* new base rate */ -rtc_rtime[tmr] = new_rtime; /* adv wall time */ -rtc_vtime[tmr] = rtc_vtime[tmr] + 1000; /* adv sim time */ -delta_vtime = rtc_vtime[tmr] - rtc_rtime[tmr]; /* gap */ -if (delta_vtime > SIM_TMAX) delta_vtime = SIM_TMAX; /* limit gap */ -else if (delta_vtime < -SIM_TMAX) delta_vtime = -SIM_TMAX; -rtc_nxintv[tmr] = 1000 + delta_vtime; /* next wtime */ -rtc_currd[tmr] = (int32) (((double) rtc_based[tmr] * (double) rtc_nxintv[tmr]) / - 1000.0); /* next delay */ -return rtc_currd[tmr]; -} - -/* Prior interfaces - default to timer 0 */ - -int32 sim_rtc_init (int32 time) -{ -return sim_rtcn_init (time, 0); -} - -int32 sim_rtc_calb (int32 ticksper) -{ -return sim_rtcn_calb (ticksper, 0); -} - -/* Breakpoint package. This module replaces the VM-implemented one - instruction breakpoint capability. - - Breakpoints are stored in table sim_brk_tab, which is ordered by address for - efficient binary searching. A breakpoint consists of a four entry structure: - - addr address of the breakpoint - type types of breakpoints set on the address - a bit mask representing letters A-Z - cnt number of iterations before breakp is taken - action pointer to list of commands to be executed - when break is taken - - sim_brk_summ is a summary of the types of breakpoints that are currently set (it - is the bitwise OR of all the type fields). A simulator need only check for - a breakpoint of type X if bit SWMASK('X') is set in sim_brk_sum. - - The package contains the following public routines: - - sim_brk_init initialize - sim_brk_pchg PC change - sim_brk_set set breakpoint - sim_brk_clr clear breakpoint - sim_brk_clrall clear all breakpoints - sim_brk_show show breakpoint - sim_brk_showall show all breakpoints - sim_brk_test test for breakpoint - sim_brk_npc PC has been changed - - Initialize breakpoint system. If simulator has filled in sim_brk_types, - allocate an initial breakpoint table, otherwise, allocate a minimal table. -*/ - -t_stat sim_brk_init (void) -{ -if (sim_brk_types) sim_brk_lnt = SIM_BRK_INILNT; -else sim_brk_lnt = 1; -sim_brk_tab = calloc (sim_brk_lnt, sizeof (BRKTAB)); -if (sim_brk_tab == NULL) return SCPE_MEM; -sim_brk_ent = sim_brk_ins = 0; -return SCPE_OK; -} - -/* Search for a breakpoint in the sorted breakpoint table */ - -BRKTAB *sim_brk_fnd (t_addr loc) -{ -int32 lo, hi, p; -BRKTAB *bp; - -if (sim_brk_ent == 0) { /* table empty? */ - sim_brk_ins = 0; /* insrt at head */ - return NULL; } /* sch fails */ -lo = 0; /* initial bounds */ -hi = sim_brk_ent - 1; -do { p = (lo + hi) >> 1; /* probe */ - bp = sim_brk_tab + p; /* table addr */ - if (loc == bp -> addr) return bp; /* match? */ - else if (loc < bp -> addr) hi = p - 1; /* go down? p is upper */ - else lo = p + 1; } /* go up? p is lower */ -while (lo <= hi); -if (loc < bp -> addr) sim_brk_ins = p; /* insrt before or */ -else sim_brk_ins = p + 1; /* after last sch */ -return NULL; -} - -/* Insert a breakpoint */ - -BRKTAB *sim_brk_new (t_addr loc) -{ -BRKTAB *bp; - -if (sim_brk_ins < 0) return NULL; -if (sim_brk_ent >= sim_brk_lnt) return NULL; -if (sim_brk_ins != sim_brk_ent) { /* move needed? */ - for (bp = sim_brk_tab + sim_brk_ent; - bp > sim_brk_tab + sim_brk_ins; bp--) - *bp = *(bp - 1); } -bp = sim_brk_tab + sim_brk_ins; -bp -> addr = loc; -bp -> typ = 0; -bp -> cnt = 0; -bp -> act = NULL; -sim_brk_ent = sim_brk_ent + 1; -return bp; -} - -/* Set a breakpoint of type sw */ - -t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt) -{ -BRKTAB *bp; - -if (sw == 0) sw = sim_brk_dflt; -if ((sim_brk_types & sw) == 0) return SCPE_NOFNC; -bp = sim_brk_fnd (loc); -if (!bp) bp = sim_brk_new (loc); -if (!bp) return SCPE_MEM; -bp -> typ = sw; -bp -> cnt = ncnt; -sim_brk_summ = sim_brk_summ | sw; -return SCPE_OK; -} - -/* Clear a breakpoint */ - -t_stat sim_brk_clr (t_addr loc, int32 sw) -{ -BRKTAB *bp = sim_brk_fnd (loc); - -if (!bp) return SCPE_OK; -if (sw == 0) sw = SIM_BRK_ALLTYP; -bp -> typ = bp -> typ & ~sw; -if (bp -> typ) return SCPE_OK; -for ( ; bp < (sim_brk_tab + sim_brk_ent - 1); bp++) - *bp = *(bp + 1); -sim_brk_ent = sim_brk_ent - 1; -sim_brk_summ = 0; -for (bp = sim_brk_tab; bp < (sim_brk_tab + sim_brk_ent); bp++) - sim_brk_summ = sim_brk_summ | bp -> typ; -return SCPE_OK; -} - -/* Clear all breakpoints */ - -t_stat sim_brk_clrall (int32 sw) -{ -BRKTAB *bp; - -if (sw == 0) sw = SIM_BRK_ALLTYP; -if ((sim_brk_summ & ~sw) == 0) sim_brk_ent = sim_brk_summ = 0; -else { for (bp = sim_brk_tab; bp < (sim_brk_tab + sim_brk_ent); bp++) { - if (bp -> typ & sw) sim_brk_clr (bp -> addr, sw); } } -return SCPE_OK; -} - -/* Show a breakpoint */ - -t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw) -{ -BRKTAB *bp = sim_brk_fnd (loc); -DEVICE *dptr; -int32 i, any; - -if (sw == 0) sw = SIM_BRK_ALLTYP; -if (!bp || (!(bp -> typ & sw))) return SCPE_OK; -dptr = sim_devices[0]; -if (dptr == NULL) return SCPE_OK; -fprint_val (st, loc, dptr -> aradix, dptr -> awidth, PV_LEFT); -fprintf (st, ":\t"); -for (i = any = 0; i < 26; i++) { - if ((bp -> typ >> i) & 1) { - if (any) fprintf (st, ", "); - fputc (i + 'A', st); - any = 1; } } -if (bp -> cnt > 0) fprintf (st, " [%d]", bp -> cnt); -fprintf (st, "\n"); -return SCPE_OK; -} - -/* Show all breakpoints */ - -t_stat sim_brk_showall (FILE *st, int32 sw) -{ -BRKTAB *bp; - -if (sw == 0) sw = SIM_BRK_ALLTYP; -for (bp = sim_brk_tab; bp < (sim_brk_tab + sim_brk_ent); bp++) { - if (bp -> typ & sw) sim_brk_show (st, bp -> addr, sw); } -return SCPE_OK; -} - -/* Test for breakpoint */ - -t_bool sim_brk_test (t_addr loc, int32 btyp) -{ -BRKTAB *bp; - -if ((bp = sim_brk_fnd (loc)) && - (btyp & bp -> typ) && - (!sim_brk_pend || (loc != sim_brk_ploc)) && - (--(bp -> cnt) <= 0)) { - bp -> cnt = 0; - sim_brk_ploc = loc; - sim_brk_pend = TRUE; - return TRUE; } -sim_brk_pend = FALSE; -return FALSE; -} - -/* New PC */ - -void sim_brk_npc (void) -{ -sim_brk_pend = FALSE; -return; -} - -/* BLK - added the following routines */ - -/* panic - report fatal internal programming error */ - -void panic (char *msg) -{ - fprintf(stderr, "%s\n", msg); - exit(1); -} - -/* read_cmdline - read command from stdin with allowance for simulated console button input */ - -#ifdef GUI_SUPPORT - -#ifndef MIN -# define MIN(a,b) (((a) <= (b)) ? (a) : (b)) -#endif - -#ifdef WIN32 - - /* win32 - use a separate thread to read command lines so the GUI - * can insert commands as well */ - - #include - - static HANDLE hCmdThread = NULL; - static DWORD iCmdThreadID = 0; - static HANDLE hCmdReadEvent = NULL; - static HANDLE hCmdReadyEvent = NULL; - static BOOL scp_stuffed = FALSE, scp_reading = FALSE; - static char cmdbuffer[256]; - - /* CmdThread - separate thread to read commands from stdin upon request */ - - static DWORD WINAPI CmdThread (LPVOID arg) - { - for (;;) { - WaitForSingleObject(hCmdReadEvent, INFINITE); /* wait for request */ - read_line(cmdbuffer, sizeof(cmdbuffer), stdin); /* read one line */ - scp_stuffed = FALSE; /* say how we got it */ - SetEvent(hCmdReadyEvent); /* notify main thread a line is ready */ - } - return 0; - } - - char *read_cmdline (char *ptr, int size) - { - char *cptr; - - if (hCmdThread == NULL) { /* set up command-reading thread */ - if ((hCmdReadEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) - panic("Can't create command line read event"); - - if ((hCmdReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL) - panic("Can't create command line ready event"); - /* start up the command thread */ - if ((hCmdThread = CreateThread(NULL, 0, CmdThread, NULL, 0, &iCmdThreadID)) == NULL) - panic("Unable to create command line reading thread"); - } - - scp_reading = TRUE; - - SetEvent(hCmdReadEvent); /* let read thread get one line */ - WaitForSingleObject(hCmdReadyEvent, INFINITE); /* wait for read thread or GUI to respond */ - - scp_reading = FALSE; - - strncpy(ptr, cmdbuffer, MIN(size, sizeof(cmdbuffer))); /* copy line to caller's buffer */ - - for (cptr = ptr; isspace(*cptr); cptr++) /* absorb spaces */ - ; - - if (scp_stuffed) { /* stuffed command needs to be echoed */ - printf("%s\n", cptr); - if (sim_log) fprintf(sim_log, "%s\n", cptr); - } - - return cptr; - } - - /* stuff_cmd - force a command into the read_cmdline output buffer. Called asynchronously by GUI */ - - void stuff_cmd (char *cmd) - { - strcpy(cmdbuffer, cmd); /* save the string */ - scp_stuffed = TRUE; /* note where it came from */ - SetEvent(hCmdReadyEvent); /* notify main thread a line is ready */ - } - - /* remark_cmd - print a remark from inside a command processor. This routine takes - * into account the possiblity that the command might have been stuffed, in which - * case the sim> prompt needs to be reprinted. - */ - - void remark_cmd (char *remark) - { - printf("%s\n", remark); - if (sim_log) fprintf(sim_log, "%s\n", remark); - if (scp_reading) { - printf("sim> "); - if (sim_log) fprintf(sim_log, "sim> "); - } - } - -#else /* ifdef WIN32 */ - - /* GUI support is not currently implemented under other operating systems */ - - char *read_cmdline (char *ptr, int size) - { - return read_line(ptr, size, stdin); - } - - void stuff_cmd (char *cmd) - { - printf("Sorry, couldn't stuff \"%s\"\n", cmd); - } - - void remark_cmd (char *remark) - { - printf("%s\n", remark); - if (sim_log) fprintf(sim_log, "%s\n", remark); - } -#endif /* ifdef WIN32 */ - -#else /* ifdef GUI_SUPPORT */ - -/* read_cmdline - w/o GUI support, just read a line from stdin */ - -char *read_cmdline (char *ptr, int size) -{ - return read_line(ptr, size, stdin); -} - -#endif /* ifdef GUI_SUPPORT */ diff --git a/Ibm1130/sim_defs.h b/Ibm1130/sim_defs.h deleted file mode 100644 index 23f95e20..00000000 --- a/Ibm1130/sim_defs.h +++ /dev/null @@ -1,373 +0,0 @@ -/* sim_defs.h: simulator definitions - - Copyright (c) 1993-2002, Robert M Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - 30-Dec-01 RMS Generalized timer package, added circular arrays - 07-Dec-01 RMS Added breakpoint package - 01-Dec-01 RMS Added read-only unit support, extended SET/SHOW features, - improved error messages - 24-Nov-01 RMS Added unit-based registers - 27-Sep-01 RMS Added queue count prototype - 17-Sep-01 RMS Removed multiple console support - 07-Sep-01 RMS Removed conditional externs on function prototypes - 31-Aug-01 RMS Changed int64 to t_int64 for Windoze - 17-Jul-01 RMS Added additional function prototypes - 27-May-01 RMS Added multiple console support - 15-May-01 RMS Increased string buffer size - 25-Feb-01 RMS Revisions for V2.6 - 15-Oct-00 RMS Editorial revisions for V2.5 - 11-Jul-99 RMS Added unsigned int data types - 14-Apr-99 RMS Converted t_addr to unsigned - 04-Oct-98 RMS Additional definitions for V2.4 - - The interface between the simulator control package (SCP) and the - simulator consists of the following routines and data structures - - sim_name simulator name string - sim_devices[] array of pointers to simulated devices - sim_PC pointer to saved PC register descriptor - sim_interval simulator interval to next event - sim_stop_messages[] array of pointers to stop messages - sim_instr() instruction execution routine - sim_load() binary loader routine - sim_emax maximum number of words in an instruction - - In addition, the simulator must supply routines to print and parse - architecture specific formats - - print_sym print symbolic output - parse_sym parse symbolic input -*/ - -#include -#include -#include -#include -#include -#include - -#ifndef TRUE -#define TRUE 1 -#define FALSE 0 -#endif - -/* Length specific integer declarations */ - -#define int8 char -#define int16 short -#define int32 int -typedef int t_stat; /* status */ -typedef int t_bool; /* boolean */ -typedef unsigned int8 uint8; -typedef unsigned int16 uint16; -typedef unsigned int32 uint32, t_addr; /* address */ -#if defined (USE_INT64) && defined (_WIN32) -#define t_int64 __int64 /* for Windows */ -#elif defined (USE_INT64) && defined (VMS) && defined (__ALPHA) -#define t_int64 __int64 /* for AVMS */ -#elif defined (USE_INT64) && defined (__ALPHA) && defined (__unix__) -#define t_int64 long /* for DUNIX */ -#elif defined (USE_INT64) -#define t_int64 long long /* for GCC */ -#endif -#if defined (t_int64) -typedef unsigned t_int64 t_uint64, t_value; /* value */ -typedef t_int64 t_svalue; /* signed value */ -#else -typedef unsigned int32 t_value; -typedef int32 t_svalue; -#endif - -/* System independent definitions */ - -typedef int32 t_mtrlnt; /* magtape rec lnt */ -#define MTRF(x) ((x) & (1u << 31)) /* record error flg */ -#define MTRL(x) ((x) & ((1u << 31) - 1)) /* record length */ -#define FLIP_SIZE (1 << 16) /* flip buf size */ -#if !defined (PATH_MAX) /* usually in limits */ -#define PATH_MAX 512 -#endif -#define CBUFSIZE (128 + PATH_MAX) /* string buf size */ -#define CONS_SIZE 4096 /* console buffer */ - -/* Simulator status codes - - 0 ok - 1 - (SCPE_BASE - 1) simulator specific - SCPE_BASE - n general -*/ - -#define SCPE_OK 0 /* normal return */ -#define SCPE_BASE 32 /* base for messages */ -#define SCPE_NXM (SCPE_BASE + 0) /* nxm */ -#define SCPE_UNATT (SCPE_BASE + 1) /* no file */ -#define SCPE_IOERR (SCPE_BASE + 2) /* I/O error */ -#define SCPE_CSUM (SCPE_BASE + 3) /* loader cksum */ -#define SCPE_FMT (SCPE_BASE + 4) /* loader format */ -#define SCPE_NOATT (SCPE_BASE + 5) /* not attachable */ -#define SCPE_OPENERR (SCPE_BASE + 6) /* open error */ -#define SCPE_MEM (SCPE_BASE + 7) /* alloc error */ -#define SCPE_ARG (SCPE_BASE + 8) /* argument error */ -#define SCPE_STEP (SCPE_BASE + 9) /* step expired */ -#define SCPE_UNK (SCPE_BASE + 10) /* unknown command */ -#define SCPE_RO (SCPE_BASE + 11) /* read only */ -#define SCPE_INCOMP (SCPE_BASE + 12) /* incomplete */ -#define SCPE_STOP (SCPE_BASE + 13) /* sim stopped */ -#define SCPE_EXIT (SCPE_BASE + 14) /* sim exit */ -#define SCPE_TTIERR (SCPE_BASE + 15) /* console tti err */ -#define SCPE_TTOERR (SCPE_BASE + 16) /* console tto err */ -#define SCPE_EOF (SCPE_BASE + 17) /* end of file */ -#define SCPE_REL (SCPE_BASE + 18) /* relocation error */ -#define SCPE_NOPARAM (SCPE_BASE + 19) /* no parameters */ -#define SCPE_ALATT (SCPE_BASE + 20) /* already attached */ -#define SCPE_TIMER (SCPE_BASE + 21) /* hwre timer err */ -#define SCPE_SIGERR (SCPE_BASE + 22) /* signal err */ -#define SCPE_TTYERR (SCPE_BASE + 23) /* tty setup err */ -#define SCPE_SUB (SCPE_BASE + 24) /* subscript err */ -#define SCPE_NOFNC (SCPE_BASE + 25) /* func not imp */ -#define SCPE_UDIS (SCPE_BASE + 26) /* unit disabled */ -#define SCPE_LOGON (SCPE_BASE + 27) /* logging enabled */ -#define SCPE_LOGOFF (SCPE_BASE + 28) /* logging disabled */ -#define SCPE_NORO (SCPE_BASE + 29) /* rd only not ok */ -#define SCPE_INVSW (SCPE_BASE + 30) /* invalid switch */ -#define SCPE_MISVAL (SCPE_BASE + 31) /* missing value */ -#define SCPE_2FARG (SCPE_BASE + 32) /* too few arguments */ -#define SCPE_2MARG (SCPE_BASE + 33) /* too many arguments */ -#define SCPE_NXDEV (SCPE_BASE + 34) /* nx device */ -#define SCPE_NXUN (SCPE_BASE + 35) /* nx unit */ -#define SCPE_NXREG (SCPE_BASE + 36) /* nx register */ -#define SCPE_NXPAR (SCPE_BASE + 37) /* nx parameter */ -#define SCPE_NEST (SCPE_BASE + 38) /* nested DO */ -#define SCPE_IERR (SCPE_BASE + 39) /* internal error */ -#define SCPE_KFLAG 01000 /* tti data flag */ - -/* Print value format codes */ - -#define PV_RZRO 0 /* right, zero fill */ -#define PV_RSPC 1 /* right, space fill */ -#define PV_LEFT 2 /* left justify */ - -/* Default timing parameters */ - -#define KBD_POLL_WAIT 5000 /* keyboard poll */ -#define SERIAL_IN_WAIT 100 /* serial in time */ -#define SERIAL_OUT_WAIT 10 /* serial output */ -#define NOQUEUE_WAIT 10000 /* min check time */ - -/* Convert switch letter to bit mask */ - -#define SWMASK(x) (1u << (((int) (x)) - ((int) 'A'))) - -/* String match */ - -#define MATCH_CMD(ptr,cmd) strncmp ((ptr), (cmd), strlen (ptr)) - -/* Device data structure */ - -struct device { - char *name; /* name */ - struct unit *units; /* units */ - struct reg *registers; /* registers */ - struct mtab *modifiers; /* modifiers */ - int32 numunits; /* #units */ - int32 aradix; /* address radix */ - int32 awidth; /* address width */ - int32 aincr; /* addr increment */ - int32 dradix; /* data radix */ - int32 dwidth; /* data width */ - t_stat (*examine)(); /* examine routine */ - t_stat (*deposit)(); /* deposit routine */ - t_stat (*reset)(); /* reset routine */ - t_stat (*boot)(); /* boot routine */ - t_stat (*attach)(); /* attach routine */ - t_stat (*detach)(); /* detach routine */ -}; - -/* Unit data structure - - Parts of the unit structure are device specific, that is, they are - not referenced by the simulator control package and can be freely - used by device simulators. Fields starting with 'buf', and flags - starting with 'UF', are device specific. The definitions given here - are for a typical sequential device. -*/ - -struct unit { - struct unit *next; /* next active */ - t_stat (*action)(); /* action routine */ - char *filename; /* open file name */ - FILE *fileref; /* file reference */ - void *filebuf; /* memory buffer */ - t_addr hwmark; /* high water mark */ - int32 time; /* time out */ - int32 flags; /* flags */ - t_addr capac; /* capacity */ - t_addr pos; /* file position */ - int32 buf; /* buffer */ - int32 wait; /* wait */ - int32 u3; /* device specific */ - int32 u4; /* device specific */ -}; - -/* Unit flags */ - -#define UNIT_ATTABLE 000001 /* attachable */ -#define UNIT_RO 000002 /* read only */ -#define UNIT_FIX 000004 /* fixed capacity */ -#define UNIT_SEQ 000010 /* sequential */ -#define UNIT_ATT 000020 /* attached */ -#define UNIT_BINK 000040 /* K = power of 2 */ -#define UNIT_BUFABLE 000100 /* bufferable */ -#define UNIT_MUSTBUF 000200 /* must buffer */ -#define UNIT_BUF 000400 /* buffered */ -#define UNIT_ROABLE 001000 /* read only ok */ -#define UNIT_DISABLE 002000 /* disable-able */ -#define UNIT_DIS 004000 /* disabled */ -#define UNIT_V_UF 12 /* device specific */ - /* must be DIS+1!! */ -#define UNIT_V_RSV 31 /* reserved!! */ - -/* Register data structure */ - -struct reg { - char *name; /* name */ - void *loc; /* location */ - int32 radix; /* radix */ - int32 width; /* width */ - int32 offset; /* starting bit */ - int32 depth; /* save depth */ - int32 flags; /* flags */ - int32 qptr; /* circ q ptr */ -}; - -#define REG_FMT 0003 /* see PV_x */ -#define REG_RO 0004 /* read only */ -#define REG_HIDDEN 0010 /* hidden */ -#define REG_NZ 0020 /* must be non-zero */ -#define REG_UNIT 0040 /* in unit struct */ -#define REG_CIRC 0100 /* circular array */ -#define REG_HRO (REG_RO | REG_HIDDEN) /* hidden, read only */ - -/* Command table */ - -struct ctab { - char *name; /* name */ - t_stat (*action)(); /* action routine */ - int32 arg; /* argument */ -}; - -/* Modifier table - only extended entries have disp, reg, or flags */ - -struct mtab { - int32 mask; /* mask or radix */ - int32 match; /* match or max */ - char *pstring; /* print string */ - char *mstring; /* match string */ - t_stat (*valid)(); /* validation routine */ - t_stat (*disp)(); /* display routine */ - void *desc; /* value descriptor */ - /* REG * if MTAB_VAL */ - /* int * if not */ -}; - -#define MTAB_XTD (1u << UNIT_V_RSV) /* ext entry flag */ -#define MTAB_VDV 001 /* valid for dev */ -#define MTAB_VUN 002 /* valid for unit */ -#define MTAB_VAL 004 /* takes a value */ -#define MTAB_NMO 010 /* only if named */ - -/* Search table */ - -struct schtab { - int logic; /* logical operator */ - int bool; /* boolean operator */ - t_value mask; /* mask for logical */ - t_value comp; /* comparison for boolean */ -}; - -/* The following macros define structure contents */ - -#define UDATA(act,fl,cap) NULL,act,NULL,NULL,NULL,0,0,(fl),(cap),0,0 - -#if defined (__STDC__) || defined (_WIN32) -#define ORDATA(nm,loc,wd) #nm, &(loc), 8, (wd), 0, 1 -#define DRDATA(nm,loc,wd) #nm, &(loc), 10, (wd), 0, 1 -#define HRDATA(nm,loc,wd) #nm, &(loc), 16, (wd), 0, 1 -#define FLDATA(nm,loc,pos) #nm, &(loc), 2, 1, (pos), 1 -#define GRDATA(nm,loc,rdx,wd,pos) #nm, &(loc), (rdx), (wd), (pos), 1 -#define BRDATA(nm,loc,rdx,wd,dep) #nm, (loc), (rdx), (wd), 0, (dep) -#define URDATA(nm,loc,rdx,wd,off,dep,fl) \ - #nm, &(loc), (rdx), (wd), (off), (dep), ((fl) | REG_UNIT) -#else -#define ORDATA(nm,loc,wd) "nm", &(loc), 8, (wd), 0, 1 -#define DRDATA(nm,loc,wd) "nm", &(loc), 10, (wd), 0, 1 -#define HRDATA(nm,loc,wd) "nm", &(loc), 16, (wd), 0, 1 -#define FLDATA(nm,loc,pos) "nm", &(loc), 2, 1, (pos), 1 -#define GRDATA(nm,loc,rdx,wd,pos) "nm", &(loc), (rdx), (wd), (pos), 1 -#define BRDATA(nm,loc,rdx,wd,dep) "nm", (loc), (rdx), (wd), 0, (dep) -#define URDATA(nm,loc,rdx,wd,off,dep,fl) \ - "nm", &(loc), (rdx), (wd), (off), (dep), ((fl) | REG_UNIT) -#endif - -/* Typedefs for principal structures */ - -typedef struct device DEVICE; -typedef struct unit UNIT; -typedef struct reg REG; -typedef struct ctab CTAB; -typedef struct mtab MTAB; -typedef struct schtab SCHTAB; - -/* Function prototypes */ - -t_stat sim_process_event (void); -t_stat sim_activate (UNIT *uptr, int32 interval); -t_stat sim_cancel (UNIT *uptr); -int32 sim_is_active (UNIT *uptr); -double sim_gtime (void); -uint32 sim_grtime (void); -int32 sim_qcount (void); -t_stat attach_unit (UNIT *uptr, char *cptr); -t_stat detach_unit (UNIT *uptr); -t_stat reset_all (int start_device); -size_t fxread (void *bptr, size_t size, size_t count, FILE *fptr); -size_t fxwrite (void *bptr, size_t size, size_t count, FILE *fptr); -t_stat get_yn (char *ques, t_stat deflt); -char *get_glyph (char *iptr, char *optr, char mchar); -char *get_glyph_nc (char *iptr, char *optr, char mchar); -t_value get_uint (char *cptr, int radix, t_value max, t_stat *status); -t_value strtotv (char *cptr, char **endptr, int radix); -DEVICE *find_dev_from_unit (UNIT *uptr); -REG *find_reg (char *ptr, char **optr, DEVICE *dptr); -int32 sim_rtc_init (int32 time); -int32 sim_rtc_calb (int32 ticksper); -int32 sim_rtcn_init (int32 time, int32 tmr); -int32 sim_rtcn_calb (int32 time, int32 tmr); -t_stat sim_poll_kbd (void); -t_stat sim_putchar (int32 out); -t_bool sim_brk_test (t_addr bloc, int32 btyp); - -#ifdef GUI_SUPPORT -void update_gui (t_bool force); -#endif diff --git a/Ibm1130/viewdeck.c b/Ibm1130/viewdeck.c new file mode 100644 index 00000000..5d83483f --- /dev/null +++ b/Ibm1130/viewdeck.c @@ -0,0 +1,144 @@ +/* Simple program to display a binary card-image file in ASCII. + * We assume the deck was written with one card per 16-bit word, left-justified, + * and written in PC little-endian order + * + * (C) Copyright 2002, Brian Knittel. + * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN + * RISK basis, there is no warranty of fitness for any purpose, and the rest of the + * usual yada-yada. Please keep this notice and the copyright in any distributions + * or modifications. + * + * This is not a supported product, but I welcome bug reports and fixes. + * Mail to sim@ibm1130.org + */ + +#include +#include + +int hollerith_to_ascii (unsigned short h); +void bail (char *msg); + +int main (int argc, char **argv) +{ + FILE *fd; + char line[82]; + unsigned short buf[80]; + int i, lastnb; + + if (argc != 2) + bail("Usage: viewdeck deckfile"); + + if ((fd = fopen(argv[1], "rb")) == NULL) { + perror(argv[1]); + return 1; + } + + while (fread(buf, sizeof(short), 80, fd) == 80) { + lastnb = -1; + for (i = 0; i < 80; i++) { + line[i] = hollerith_to_ascii(buf[i]); + if (line[i] > ' ') + lastnb = i; + } + line[++lastnb] = '\n'; + line[++lastnb] = '\0'; + fputs(line, stdout); + } + + fclose(fd); + + return 0; +} + +typedef struct { + unsigned short hollerith; + char ascii; +} CPCODE; + +static CPCODE cardcode_029[] = +{ + 0x0000, ' ', + 0x8000, '&', // + in 026 Fortran + 0x4000, '-', + 0x2000, '0', + 0x1000, '1', + 0x0800, '2', + 0x0400, '3', + 0x0200, '4', + 0x0100, '5', + 0x0080, '6', + 0x0040, '7', + 0x0020, '8', + 0x0010, '9', + 0x9000, 'A', + 0x8800, 'B', + 0x8400, 'C', + 0x8200, 'D', + 0x8100, 'E', + 0x8080, 'F', + 0x8040, 'G', + 0x8020, 'H', + 0x8010, 'I', + 0x5000, 'J', + 0x4800, 'K', + 0x4400, 'L', + 0x4200, 'M', + 0x4100, 'N', + 0x4080, 'O', + 0x4040, 'P', + 0x4020, 'Q', + 0x4010, 'R', + 0x3000, '/', + 0x2800, 'S', + 0x2400, 'T', + 0x2200, 'U', + 0x2100, 'V', + 0x2080, 'W', + 0x2040, 'X', + 0x2020, 'Y', + 0x2010, 'Z', + 0x0820, ':', + 0x0420, '#', // = in 026 Fortran + 0x0220, '@', // ' in 026 Fortran + 0x0120, '\'', + 0x00A0, '=', + 0x0060, '"', + 0x8820, 'c', // cent + 0x8420, '.', + 0x8220, '<', // ) in 026 Fortran + 0x8120, '(', + 0x80A0, '+', + 0x8060, '|', + 0x4820, '!', + 0x4420, '$', + 0x4220, '*', + 0x4120, ')', + 0x40A0, ';', + 0x4060, 'n', // not + 0x2820, 'x', // what? + 0x2420, ',', + 0x2220, '%', // ( in 026 Fortran + 0x2120, '_', + 0x20A0, '>', + 0x2060, '>', +}; + +int hollerith_to_ascii (unsigned short h) +{ + int i; + + h &= 0xFFF0; + + for (i = 0; i < sizeof(cardcode_029) / sizeof(CPCODE); i++) + if (cardcode_029[i].hollerith == h) + return cardcode_029[i].ascii; + + return '?'; +} + +void bail (char *msg) +{ + fprintf(stderr, "%s\n", msg); + exit(1); +} + diff --git a/Ibm1130/viewdeck.mak b/Ibm1130/viewdeck.mak new file mode 100644 index 00000000..37da412c --- /dev/null +++ b/Ibm1130/viewdeck.mak @@ -0,0 +1,161 @@ +# Microsoft Visual C++ Generated NMAKE File, Format Version 2.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=Win32 Debug +!MESSAGE No configuration specified. Defaulting to Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "Win32 Release" && "$(CFG)" != "Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "viewdeck.mak" CFG="Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +################################################################################ +# Begin Project +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "WinRel" +# PROP BASE Intermediate_Dir "WinRel" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "WinRel" +# PROP Intermediate_Dir "WinRel" +OUTDIR=.\WinRel +INTDIR=.\WinRel + +ALL : $(OUTDIR)/viewdeck.exe $(OUTDIR)/viewdeck.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /ML /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /ML /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /ML /W3 /GX /YX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"viewdeck.pch" /Fo$(INTDIR)/ /c +CPP_OBJS=.\WinRel/ +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"viewdeck.bsc" +BSC32_SBRS= \ + $(INTDIR)/viewdeck.sbr + +$(OUTDIR)/viewdeck.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib /NOLOGO /SUBSYSTEM:console /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:no\ + /PDB:$(OUTDIR)/"viewdeck.pdb" /MACHINE:I386 /OUT:$(OUTDIR)/"viewdeck.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/viewdeck.obj + +$(OUTDIR)/viewdeck.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "WinDebug" +# PROP BASE Intermediate_Dir "WinDebug" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "WinDebug" +# PROP Intermediate_Dir "WinDebug" +OUTDIR=.\WinDebug +INTDIR=.\WinDebug + +ALL : $(OUTDIR)/viewdeck.exe $(OUTDIR)/viewdeck.bsc + +$(OUTDIR) : + if not exist $(OUTDIR)/nul mkdir $(OUTDIR) + +# ADD BASE CPP /nologo /ML /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +# ADD CPP /nologo /ML /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /FR /c +CPP_PROJ=/nologo /ML /W3 /GX /Zi /YX /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE"\ + /FR$(INTDIR)/ /Fp$(OUTDIR)/"viewdeck.pch" /Fo$(INTDIR)/\ + /Fd$(OUTDIR)/"viewdeck.pdb" /c +CPP_OBJS=.\WinDebug/ +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o$(OUTDIR)/"viewdeck.bsc" +BSC32_SBRS= \ + $(INTDIR)/viewdeck.sbr + +$(OUTDIR)/viewdeck.bsc : $(OUTDIR) $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib /NOLOGO /SUBSYSTEM:console /DEBUG /MACHINE:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib /NOLOGO /SUBSYSTEM:console /INCREMENTAL:yes\ + /PDB:$(OUTDIR)/"viewdeck.pdb" /DEBUG /MACHINE:I386\ + /OUT:$(OUTDIR)/"viewdeck.exe" +DEF_FILE= +LINK32_OBJS= \ + $(INTDIR)/viewdeck.obj + +$(OUTDIR)/viewdeck.exe : $(OUTDIR) $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Group "Source Files" + +################################################################################ +# Begin Source File + +SOURCE=.\viewdeck.c + +$(INTDIR)/viewdeck.obj : $(SOURCE) $(INTDIR) + +# End Source File +# End Group +# End Project +################################################################################ diff --git a/NOVA/eclipse_cpu.c b/NOVA/eclipse_cpu.c index 9a8e3e80..8972e9bd 100644 --- a/NOVA/eclipse_cpu.c +++ b/NOVA/eclipse_cpu.c @@ -316,11 +316,11 @@ #include "nova_defs.h" #define UNIT_V_MICRO (UNIT_V_UF) /* Microeclipse? */ -#define UNIT_MICRO (1 << UNIT_V_MICRO) -#define UNIT_V_MSIZE (UNIT_V_UF+1) /* dummy mask */ -#define UNIT_MSIZE (1 << UNIT_V_MSIZE) #define UNIT_V_17B (UNIT_V_UF) /* 17 bit MAP */ +#define UNIT_V_MSIZE (UNIT_V_UF+1) /* dummy mask */ +#define UNIT_MICRO (1 << UNIT_V_MICRO) #define UNIT_17B (1 << UNIT_V_17B) +#define UNIT_MSIZE (1 << UNIT_V_MSIZE) unsigned int16 M[MAXMEMSIZE] = { 0 }; /* memory */ int32 AC[4] = { 0 }; /* accumulators */ @@ -344,6 +344,8 @@ int32 XCT_mode = 0; /* 1 if XCT mode */ int32 XCT_inst = 0; /* XCT instruction */ int32 PPC = -1; +struct ndev dev_table[64]; /* dispatch table */ + /* Instruction history buffer */ #define HISTMAX 4096 @@ -418,11 +420,12 @@ FILE *Trace; t_stat reason; extern int32 sim_int_char; extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern DEVICE *sim_devices[]; t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); -t_stat cpu_boot (int32 unitno); +t_stat cpu_boot (int32 unitno, DEVICE *dptr); t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat Debug_Dump (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat map_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); @@ -432,59 +435,11 @@ t_stat map_svc (UNIT *uptr); int32 GetMap(int32 addr); int32 PutMap(int32 addr, int32 data); int32 Debug_Entry(int32 PC, int32 inst, int32 inst2, int32 AC0, int32 AC1, int32 AC2, int32 AC3, int32 flags); +t_stat build_devtab (void); -extern int32 ptr (int32 pulse, int32 code, int32 AC); -extern int32 ptp (int32 pulse, int32 code, int32 AC); -extern int32 tti (int32 pulse, int32 code, int32 AC); -extern int32 tto (int32 pulse, int32 code, int32 AC); -extern int32 tti1 (int32 pulse, int32 code, int32 AC); -extern int32 tto1 (int32 pulse, int32 code, int32 AC); -extern int32 clk (int32 pulse, int32 code, int32 AC); -extern int32 plt (int32 pulse, int32 code, int32 AC); -extern int32 lpt (int32 pulse, int32 code, int32 AC); -extern int32 dsk (int32 pulse, int32 code, int32 AC); -extern int32 dkp (int32 pulse, int32 code, int32 AC); -extern int32 mta (int32 pulse, int32 code, int32 AC); -int32 nulldev (int32 pulse, int32 code, int32 AC); extern t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw); -/* IOT dispatch table */ - -struct ndev dev_table[64] = { - { 0, 0, &nulldev }, { 0, 0, &nulldev }, /* 0 - 7 */ - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { INT_TTI, PI_TTI, &tti }, { INT_TTO, PI_TTO, &tto }, /* 10 - 17 */ - { INT_PTR, PI_PTR, &ptr }, { INT_PTP, PI_PTP, &ptp }, - { INT_CLK, PI_CLK, &clk }, { INT_PLT, PI_PLT, &plt }, - { 0, 0, &nulldev }, { INT_LPT, PI_LPT, &lpt }, - { INT_DSK, PI_DSK, &dsk }, { 0, 0, &nulldev }, /* 20 - 27 */ - { INT_MTA, PI_MTA, &mta }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, /* 30 - 37 */ - { 0, 0, &nulldev }, {INT_DKP, PI_DKP, &dkp }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, /* 40 - 47 */ - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { INT_TTI1, PI_TTI1, &tti1 }, { INT_TTO1, PI_TTO1, &tto1 }, /* 50 - 57 */ - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, /* 60 - 67 */ - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, /* 70 - 77 */ - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev } }; - /* CPU data structures cpu_dev CPU device descriptor @@ -513,7 +468,6 @@ REG cpu_reg[] = { { ORDATA (DONE, dev_done, INT_V_ION+1), REG_RO }, { ORDATA (DISABLE, dev_disable, INT_V_ION+1), REG_RO }, { FLDATA (STOP_DEV, stop_dev, 0) }, - { FLDATA (MICRO, cpu_unit.flags, UNIT_V_MICRO), REG_HRO }, { DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT }, { ORDATA (DEBUG, Debug_Flags, 16) }, { DRDATA (MODEL, model, 16) }, @@ -606,6 +560,7 @@ int32 pushrtn(int32 pc); /* Restore register state */ +if (build_devtab () != SCPE_OK) return SCPE_IERR; /* build dispatch */ PC = saved_PC & AMASK; /* load local PC */ C = C & 0200000; mask_out (pimask); /* reset int system */ @@ -2762,8 +2717,7 @@ else { /* IOT */ } break; } } /* end CPU control */ - else if ((dev_table[device].mask == 0) || - (dev_table[device].mask & iot_enb)) { /* normal device */ + else if (dev_table[device].routine) { /* normal device */ iodata = dev_table[device].routine (pulse, code, AC[dstAC]); reason = iodata >> IOT_V_REASON; if (code & 1) AC[dstAC] = iodata & 0177777; @@ -3189,13 +3143,6 @@ int32 unimp(int32 PC) return 0; } -/* Null device */ - -int32 nulldev (int32 pulse, int32 code, int32 AC) -{ -return stop_dev << IOT_V_REASON; -} - /* New priority mask out */ void mask_out (int32 newmask) @@ -3240,6 +3187,8 @@ M[addr] = val & 0177777; return SCPE_OK; } +/* Alter memory size */ + t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { int32 mc = 0; @@ -3325,7 +3274,7 @@ static const int32 boot_rom[] = { 0 /* 0 ;padding */ }; -t_stat cpu_boot (int32 unitno) +t_stat cpu_boot (int32 unitno, DEVICE *dptr) { int32 i; extern int32 saved_PC; @@ -3411,38 +3360,23 @@ int32 Debug_Dump(UNIT *uptr, int32 val, char *cptr, void *desc) return SCPE_OK; } -/* Device enable routine */ +/* Build dispatch table */ -t_stat set_enb (UNIT *uptr, int32 val, char *cptr, void *desc) +t_stat build_devtab (void) { DEVICE *dptr; +DIB *dibp; +int32 i, dn; -if (cptr != NULL) return SCPE_ARG; -if ((uptr == NULL) || (val == 0)) return SCPE_IERR; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) return SCPE_IERR; -iot_enb = iot_enb | val; -if (dptr -> reset) dptr -> reset (dptr); -return SCPE_OK; -} - -/* Device disable routine */ - -t_stat set_dsb (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 i; -DEVICE *dptr; -UNIT *up; - -if (cptr != NULL) return SCPE_ARG; -if ((uptr == NULL) || (val == 0)) return SCPE_IERR; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) return SCPE_IERR; -for (i = 0; i < dptr -> numunits; i++) { /* check units */ - up = (dptr -> units) + i; - if ((up -> flags & UNIT_ATT) || sim_is_active (up)) - return SCPE_NOFNC; } -iot_enb = iot_enb & ~val; -if (dptr -> reset) dptr -> reset (dptr); +for (i = 0; i < 64; i++) { /* clr dev_table */ + dev_table[i].mask = 0; + dev_table[i].pi = 0; + dev_table[i].routine = NULL; } +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ + if (dibp = (DIB *) dptr->ctxt) { /* get DIB */ + dn = dibp->dnum; /* get dev num */ + dev_table[dn].mask = dibp->mask; /* copy entries */ + dev_table[dn].pi = dibp->pi; + dev_table[dn].routine = dibp->routine; } } return SCPE_OK; } diff --git a/NOVA/eclipse_tt.c b/NOVA/eclipse_tt.c index f3448983..4858e6e3 100644 --- a/NOVA/eclipse_tt.c +++ b/NOVA/eclipse_tt.c @@ -8,6 +8,7 @@ tti terminal input tto terminal output + 03-Oct-02 RMS Added DIBs 30-May-02 RMS Widened POS to 32b 28-Jan-02 RMS Cleaned up compiler warnings */ @@ -19,6 +20,8 @@ extern int32 int_req, dev_busy, dev_done, dev_disable; +int32 tti (int32 pulse, int32 code, int32 AC); +int32 tto (int32 pulse, int32 code, int32 AC); t_stat tti_svc (UNIT *uptr); t_stat tto_svc (UNIT *uptr); t_stat tti_reset (DEVICE *dptr); @@ -36,6 +39,8 @@ int32 putseq(char *seq); ttx_mod TTI/TTO modifiers list */ +DIB tti_dib = { DEV_TTI, INT_TTI, PI_TTI, &tti }; + UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT }; REG tti_reg[] = { @@ -46,7 +51,6 @@ REG tti_reg[] = { { FLDATA (INT, int_req, INT_V_TTI) }, { DRDATA (POS, tti_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, - { FLDATA (MODE, tti_unit.flags, UNIT_V_DASHER), REG_HRO }, { NULL } }; MTAB ttx_mod[] = { @@ -58,7 +62,8 @@ DEVICE tti_dev = { "TTI", &tti_unit, tti_reg, ttx_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &tti_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &tti_dib, 0 }; /* TTO data structures @@ -67,6 +72,8 @@ DEVICE tti_dev = { tto_reg TTO register list */ +DIB tto_dib = { DEV_TTO, INT_TTO, PI_TTO, &tto }; + UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT }; REG tto_reg[] = { @@ -77,14 +84,14 @@ REG tto_reg[] = { { FLDATA (INT, int_req, INT_V_TTO) }, { DRDATA (POS, tto_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT }, - { FLDATA (MODE, tto_unit.flags, UNIT_V_DASHER), REG_HRO }, { NULL } }; DEVICE tto_dev = { "TTO", &tto_unit, tto_reg, ttx_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &tto_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &tto_dib, 0 }; diff --git a/NOVA/nova_clk.c b/NOVA/nova_clk.c index a0411417..383f3070 100644 --- a/NOVA/nova_clk.c +++ b/NOVA/nova_clk.c @@ -25,6 +25,7 @@ clk real-time clock + 03-Oct-02 RMS Added DIB 17-Sep-01 RMS Added terminal multiplexor support 17-Mar-01 RMS Moved function prototype 05-Mar-01 RMS Added clock calibration @@ -34,11 +35,14 @@ #include "nova_defs.h" extern int32 int_req, dev_busy, dev_done, dev_disable; + int32 clk_sel = 0; /* selected freq */ int32 clk_time[4] = { 16000, 100000, 10000, 1000 }; /* freq table */ int32 clk_tps[4] = { 60, 10, 100, 1000 }; /* ticks per sec */ int32 clk_adj[4] = { 1, -5, 2, 20 }; /* tmxr adjust */ int32 tmxr_poll = 16000; /* tmxr poll */ + +int32 clk (int32 pulse, int32 code, int32 AC); t_stat clk_svc (UNIT *uptr); t_stat clk_reset (DEVICE *dptr); @@ -49,6 +53,8 @@ t_stat clk_reset (DEVICE *dptr); clk_reg CLK register list */ +DIB clk_dib = { DEV_CLK, INT_CLK, PI_CLK, &clk }; + UNIT clk_unit = { UDATA (&clk_svc, 0, 0) }; REG clk_reg[] = { @@ -67,7 +73,8 @@ DEVICE clk_dev = { "CLK", &clk_unit, clk_reg, NULL, 1, 0, 0, 0, 0, 0, NULL, NULL, &clk_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &clk_dib, 0 }; /* IOT routine */ diff --git a/NOVA/nova_cpu.c b/NOVA/nova_cpu.c index 625543ae..723de635 100644 --- a/NOVA/nova_cpu.c +++ b/NOVA/nova_cpu.c @@ -25,6 +25,7 @@ cpu Nova central processor + 03-Oct-02 RMS Added DIB infrastructure 30-Dec-01 RMS Added old PC queue 07-Dec-01 RMS Revised to use breakpoint package 30-Nov-01 RMS Added extended SET/SHOW support @@ -197,8 +198,7 @@ 4. Adding I/O devices. These modules must be modified: nova_defs.h add interrupt request definition - nova_cpu.c add IOT mask, PI mask, and routine to dev_table - nova_sys.c add pointer to data structures to sim_devices + nova_sys.c add sim_devices entry */ #include "nova_defs.h" @@ -218,17 +218,17 @@ M[x] = (M[x] - 1) & 0177777; \ x = M[x] & AMASK -#define UNIT_V_MDV (UNIT_V_UF) /* MDV present */ +#define UNIT_V_MDV (UNIT_V_UF + 0) /* MDV present */ +#define UNIT_V_STK (UNIT_V_UF + 1) /* stack instr */ +#define UNIT_V_BYT (UNIT_V_UF + 2) /* byte instr */ +#define UNIT_V_MSIZE (UNIT_V_UF + 3) /* dummy mask */ #define UNIT_MDV (1 << UNIT_V_MDV) -#define UNIT_V_STK (UNIT_V_UF+1) /* stack instr */ #define UNIT_STK (1 << UNIT_V_STK) -#define UNIT_V_BYT (UNIT_V_UF+2) /* byte instr */ #define UNIT_BYT (1 << UNIT_V_BYT) +#define UNIT_MSIZE (1 << UNIT_V_MSIZE) #define UNIT_IOPT (UNIT_MDV | UNIT_STK | UNIT_BYT) #define UNIT_NOVA3 (UNIT_MDV | UNIT_STK) #define UNIT_NOVA4 (UNIT_MDV | UNIT_STK | UNIT_BYT) -#define UNIT_V_MSIZE (UNIT_V_UF+3) /* dummy mask */ -#define UNIT_MSIZE (1 << UNIT_V_MSIZE) uint16 M[MAXMEMSIZE] = { 0 }; /* memory */ int32 AC[4] = { 0 }; /* accumulators */ @@ -240,7 +240,6 @@ int32 SR = 0; /* switch register */ int32 dev_done = 0; /* device done flags */ int32 dev_busy = 0; /* device busy flags */ int32 dev_disable = 0; /* int disable flags */ -int32 iot_enb = -1; /* IOT enables */ int32 int_req = 0; /* interrupt requests */ int32 pimask = 0; /* priority int mask */ int32 pwr_low = 0; /* power fail flag */ @@ -249,64 +248,18 @@ int32 stop_dev = 0; /* stop on ill dev */ uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ int32 pcq_p = 0; /* PC queue ptr */ REG *pcq_r = NULL; /* PC queue reg ptr */ +struct ndev dev_table[64]; /* dispatch table */ + extern int32 sim_int_char; extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern DEVICE *sim_devices[]; t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_boot (int32 unitno); -extern int32 ptr (int32 pulse, int32 code, int32 AC); -extern int32 ptp (int32 pulse, int32 code, int32 AC); -extern int32 tti (int32 pulse, int32 code, int32 AC); -extern int32 tto (int32 pulse, int32 code, int32 AC); -extern int32 tti1 (int32 pulse, int32 code, int32 AC); -extern int32 tto1 (int32 pulse, int32 code, int32 AC); -extern int32 clk (int32 pulse, int32 code, int32 AC); -extern int32 plt (int32 pulse, int32 code, int32 AC); -extern int32 lpt (int32 pulse, int32 code, int32 AC); -extern int32 dsk (int32 pulse, int32 code, int32 AC); -extern int32 dkp (int32 pulse, int32 code, int32 AC); -extern int32 mta (int32 pulse, int32 code, int32 AC); -int32 nulldev (int32 pulse, int32 code, int32 AC); -extern t_stat sim_activate (UNIT *uptr, int32 delay); - -/* IOT dispatch table */ - -struct ndev dev_table[64] = { - { 0, 0, &nulldev }, { 0, 0, &nulldev }, /* 0 - 7 */ - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { INT_TTI, PI_TTI, &tti }, { INT_TTO, PI_TTO, &tto }, /* 10 - 17 */ - { INT_PTR, PI_PTR, &ptr }, { INT_PTP, PI_PTP, &ptp }, - { INT_CLK, PI_CLK, &clk }, { INT_PLT, PI_PLT, &plt }, - { 0, 0, &nulldev }, { INT_LPT, PI_LPT, &lpt }, - { INT_DSK, PI_DSK, &dsk }, { 0, 0, &nulldev }, /* 20 - 27 */ - { INT_MTA, PI_MTA, &mta }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, /* 30 - 37 */ - { 0, 0, &nulldev }, {INT_DKP, PI_DKP, &dkp }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, /* 40 - 47 */ - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { INT_TTI1, PI_TTI1, &tti1 }, { INT_TTO1, PI_TTO1, &tto1 }, /* 50 - 57 */ - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, /* 60 - 67 */ - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, /* 70 - 77 */ - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev }, - { 0, 0, &nulldev }, { 0, 0, &nulldev } }; +t_stat cpu_boot (int32 unitno, DEVICE *dptr); +t_stat build_devtab (void); /* CPU data structures @@ -339,14 +292,10 @@ REG cpu_reg[] = { { ORDATA (DONE, dev_done, INT_V_ION+1), REG_RO }, { ORDATA (DISABLE, dev_disable, INT_V_ION+1), REG_RO }, { FLDATA (STOP_DEV, stop_dev, 0) }, - { FLDATA (MDV, cpu_unit.flags, UNIT_V_MDV), REG_HRO }, - { FLDATA (ISTK, cpu_unit.flags, UNIT_V_STK), REG_HRO }, - { FLDATA (IBYT, cpu_unit.flags, UNIT_V_BYT), REG_HRO }, { DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT }, { BRDATA (PCQ, pcq, 8, 16, PCQ_SIZE), REG_RO+REG_CIRC }, { ORDATA (PCQP, pcq_p, 6), REG_HRO }, { ORDATA (WRU, sim_int_char, 8) }, - { ORDATA (IOTENB, iot_enb, 32), REG_HRO }, { NULL } }; MTAB cpu_mod[] = { @@ -380,6 +329,7 @@ extern int32 clk_sel, clk_time[4]; /* Restore register state */ +if (build_devtab () != SCPE_OK) return SCPE_IERR; /* build dispatch */ PC = saved_PC & AMASK; /* load local PC */ C = C & CBIT; mask_out (pimask); /* reset int system */ @@ -789,8 +739,7 @@ else { /* IOT */ int_req = int_req & ~INT_ION; break; } /* end switch pulse */ } /* end CPU control */ - else if ((dev_table[device].mask == 0) || - (dev_table[device].mask & iot_enb)) { /* normal device */ + else if (dev_table[device].routine) { /* normal device */ iodata = dev_table[device].routine (pulse, code, AC[dstAC]); reason = iodata >> IOT_V_REASON; if (code & 1) AC[dstAC] = iodata & 0177777; } @@ -801,17 +750,10 @@ else { /* IOT */ /* Simulation halted */ saved_PC = PC; -pcq_r -> qptr = pcq_p; /* update pc q ptr */ +pcq_r->qptr = pcq_p; /* update pc q ptr */ return reason; } -/* Null device */ - -int32 nulldev (int32 pulse, int32 code, int32 AC) -{ -return stop_dev << IOT_V_REASON; -} - /* New priority mask out */ void mask_out (int32 newmask) @@ -835,7 +777,7 @@ pimask = 0; dev_disable = 0; pwr_low = 0; pcq_r = find_reg ("PCQ", NULL, dptr); -if (pcq_r) pcq_r -> qptr = 0; +if (pcq_r) pcq_r->qptr = 0; else return SCPE_IERR; sim_brk_types = sim_brk_dflt = SWMASK ('E'); return SCPE_OK; @@ -859,6 +801,8 @@ M[addr] = val & DMASK; return SCPE_OK; } +/* Alter memory size */ + t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { int32 mc = 0; @@ -874,6 +818,27 @@ for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; return SCPE_OK; } +/* Build dispatch table */ + +t_stat build_devtab (void) +{ +DEVICE *dptr; +DIB *dibp; +int32 i, dn; + +for (i = 0; i < 64; i++) { /* clr dev_table */ + dev_table[i].mask = 0; + dev_table[i].pi = 0; + dev_table[i].routine = NULL; } +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ + if (dibp = (DIB *) dptr->ctxt) { /* get DIB */ + dn = dibp->dnum; /* get dev num */ + dev_table[dn].mask = dibp->mask; /* copy entries */ + dev_table[dn].pi = dibp->pi; + dev_table[dn].routine = dibp->routine; } } +return SCPE_OK; +} + /* Bootstrap routine for CPU */ #define BOOT_START 00000 @@ -917,7 +882,7 @@ static const int32 boot_rom[] = { 0000000 /* 0 ;padding */ }; -t_stat cpu_boot (int32 unitno) +t_stat cpu_boot (int32 unitno, DEVICE *dptr) { int32 i; extern int32 saved_PC; @@ -927,42 +892,6 @@ saved_PC = BOOT_START; return SCPE_OK; } -/* Device enable routine */ - -t_stat set_enb (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -DEVICE *dptr; - -if (cptr != NULL) return SCPE_ARG; -if ((uptr == NULL) || (val == 0)) return SCPE_IERR; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) return SCPE_IERR; -iot_enb = iot_enb | val; -if (dptr -> reset) dptr -> reset (dptr); -return SCPE_OK; -} - -/* Device disable routine */ - -t_stat set_dsb (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 i; -DEVICE *dptr; -UNIT *up; - -if (cptr != NULL) return SCPE_ARG; -if ((uptr == NULL) || (val == 0)) return SCPE_IERR; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) return SCPE_IERR; -for (i = 0; i < dptr -> numunits; i++) { /* check units */ - up = (dptr -> units) + i; - if ((up -> flags & UNIT_ATT) || sim_is_active (up)) - return SCPE_NOFNC; } -iot_enb = iot_enb & ~val; -if (dptr -> reset) dptr -> reset (dptr); -return SCPE_OK; -} - /* 1-to-1 map for I/O devices */ int32 MapAddr (int32 map, int32 addr) diff --git a/NOVA/nova_defs.h b/NOVA/nova_defs.h index 05cee81b..15db1b2d 100644 --- a/NOVA/nova_defs.h +++ b/NOVA/nova_defs.h @@ -23,6 +23,7 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 03-Oct-02 RMS Added device information structure 22-Dec-00 RMS Added Bruce Ray's second terminal support 10-Dec-00 RMS Added Charles Owen's Eclipse support 08-Dec-00 RMS Added Bruce Ray's plotter support @@ -156,8 +157,24 @@ #define DEV_LOW 010 /* lowest intr dev */ #define DEV_HIGH 051 /* highest intr dev */ #define DEV_MDV 001 /* multiply/divide */ -#define DEV_MAP 003 /* MMPU control */ #define DEV_ECC 002 /* ECC memory control */ +#define DEV_MAP 003 /* MMPU control */ +#define DEV_TTI 010 /* console input */ +#define DEV_TTO 011 /* console output */ +#define DEV_PTR 012 /* paper tape reader */ +#define DEV_PTP 013 /* paper tape punch */ +#define DEV_CLK 014 /* clock */ +#define DEV_PLT 015 /* plotter */ +#define DEV_CDR 016 /* card reader */ +#define DEV_LPT 017 /* line printer */ +#define DEV_DSK 020 /* fixed head disk */ +#define DEV_MTA 022 /* magtape */ +#define DEV_DCM 024 /* data comm mux */ +#define DEV_ADCV 030 /* A/D converter */ +#define DEV_DKP 033 /* disk pack */ +#define DEV_CAS 034 /* cassette */ +#define DEV_TTI1 050 /* second console input */ +#define DEV_TTO1 051 /* second console output */ #define DEV_CPU 077 /* CPU control */ /* I/O structure @@ -168,6 +185,9 @@ mask device mask for busy, done (simulator representation) pi pi disable bit (hardware representation) routine IOT action routine + + dev_table is populated at run time from the device information + blocks in each device. */ struct ndev { @@ -176,6 +196,15 @@ struct ndev { int32 (*routine)(); /* dispatch routine */ }; +struct nova_dib { + int32 dnum; /* device number */ + int32 mask; /* done/busy mask */ + int32 pi; /* assigned pi bit */ + int32 (*routine)(); /* dispatch routine */ + }; + +typedef struct nova_dib DIB; + /* Device flags (simulator representation) Priority (for INTA) runs from low numbers to high diff --git a/NOVA/nova_dkp.c b/NOVA/nova_dkp.c index f6ab8399..ce7bce7a 100644 --- a/NOVA/nova_dkp.c +++ b/NOVA/nova_dkp.c @@ -25,6 +25,7 @@ dkp moving head disk + 08-Oct-02 RMS Added DIB 06-Jan-02 RMS Revised enable/disable support 30-Nov-01 RMS Added read only unit, extended SET/SHOW support 24-Nov-01 RMS Changed FLG, CAPAC to arrays @@ -47,7 +48,6 @@ #define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */ #define UNIT_M_DTYPE 017 #define UNIT_V_AUTO (UNIT_V_UF + 5) /* autosize */ -#define UNIT_W_UF 7 /* saved flag width */ #define UNIT_WLK (1 << UNIT_V_WLK) #define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE) #define UNIT_AUTO (1 << UNIT_V_AUTO) @@ -274,16 +274,20 @@ struct drvtyp drv_tab[] = { extern uint16 M[]; extern UNIT cpu_unit; -extern int32 int_req, dev_busy, dev_done, dev_disable, iot_enb; +extern int32 int_req, dev_busy, dev_done, dev_disable; + int32 dkp_ma = 0; /* memory address */ int32 dkp_ussc = 0; /* unit/sf/sc/cnt */ int32 dkp_fccy = 0; /* flags/cylinder */ int32 dkp_sta = 0; /* status register */ int32 dkp_swait = 100; /* seek latency */ int32 dkp_rwait = 100; /* rotate latency */ + +DEVICE dkp_dev; +int32 dkp (int32 pulse, int32 code, int32 AC); t_stat dkp_svc (UNIT *uptr); t_stat dkp_reset (DEVICE *dptr); -t_stat dkp_boot (int32 unitno); +t_stat dkp_boot (int32 unitno, DEVICE *dptr); t_stat dkp_attach (UNIT *uptr, char *cptr); t_stat dkp_go (void); t_stat dkp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); @@ -296,6 +300,8 @@ t_stat dkp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); dkp_mod DKP modifier list */ +DIB dkp_dib = { DEV_DKP, INT_DKP, PI_DKP, &dkp }; + UNIT dkp_unit[] = { { UDATA (&dkp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ UNIT_ROABLE+(TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) }, @@ -317,11 +323,8 @@ REG dkp_reg[] = { { FLDATA (DISABLE, dev_disable, INT_V_DKP) }, { DRDATA (STIME, dkp_swait, 24), PV_LEFT }, { DRDATA (RTIME, dkp_rwait, 24), PV_LEFT }, - { URDATA (FLG, dkp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, - DKP_NUMDR, REG_HRO) }, { URDATA (CAPAC, dkp_unit[0].capac, 10, 31, 0, DKP_NUMDR, PV_LEFT | REG_HRO) }, - { FLDATA (*DEVENB, iot_enb, INT_V_DKP), REG_HRO }, { NULL } }; MTAB dkp_mod[] = { @@ -419,15 +422,14 @@ MTAB dkp_mod[] = { NULL, "4231", &dkp_set_size }, { (UNIT_AUTO+UNIT_DTYPE), (TYPE_4231 << UNIT_V_DTYPE), NULL, "3330", &dkp_set_size }, - { MTAB_XTD|MTAB_VDV, INT_DKP, NULL, "ENABLED", &set_enb }, - { MTAB_XTD|MTAB_VDV, INT_DKP, NULL, "DISABLED", &set_dsb }, { 0 } }; DEVICE dkp_dev = { "DP", dkp_unit, dkp_reg, dkp_mod, DKP_NUMDR, 8, 30, 1, 8, 16, NULL, NULL, &dkp_reset, - &dkp_boot, &dkp_attach, NULL }; + &dkp_boot, &dkp_attach, NULL, + &dkp_dib, DEV_DISABLE }; /* IOT routine */ @@ -437,13 +439,13 @@ UNIT *uptr; int32 u, rval, dtype; rval = 0; -uptr = dkp_dev.units + GET_UNIT (dkp_ussc); /* select unit */ -dtype = GET_DTYPE (uptr -> flags); /* get drive type */ +uptr = dkp_dev.units + GET_UNIT (dkp_ussc); /* select unit */ +dtype = GET_DTYPE (uptr->flags); /* get drive type */ switch (code) { /* decode IR<5:7> */ case ioDIA: /* DIA */ dkp_sta = dkp_sta & ~STA_DYN; /* clear dynamic */ - if (uptr -> flags & UNIT_ATT) dkp_sta = dkp_sta | STA_DRDY; - if (uptr -> CYL >= drv_tab[dtype].cyl) + if (uptr->flags & UNIT_ATT) dkp_sta = dkp_sta | STA_DRDY; + if (uptr->CYL >= drv_tab[dtype].cyl) dkp_sta = dkp_sta | STA_CYL; /* bad cylinder? */ if (dkp_sta & STA_EFLGS) dkp_sta = dkp_sta | STA_ERR; rval = dkp_sta; @@ -454,7 +456,7 @@ case ioDOA: /* DOA */ dkp_sta = dkp_sta & ~(AC & FCCY_FLAGS); } break; case ioDIB: /* DIB */ - rval = dkp_ma; /* return buf addr */ + rval = dkp_ma; /* return buf addr */ break; case ioDOB: /* DOB */ if ((dev_busy & INT_DKP) == 0) dkp_ma = @@ -510,10 +512,10 @@ int32 newcyl, func, u, dtype; dkp_sta = dkp_sta & ~STA_EFLGS; /* clear errors */ u = GET_UNIT (dkp_ussc); /* get unit number */ uptr = dkp_dev.units + u; /* get unit */ -if (((uptr -> flags & UNIT_ATT) == 0) || sim_is_active (uptr)) { +if (((uptr->flags & UNIT_ATT) == 0) || sim_is_active (uptr)) { dkp_sta = dkp_sta | STA_ERR; /* attached or busy? */ return FALSE; } -dtype = GET_DTYPE (uptr -> flags); /* get drive type */ +dtype = GET_DTYPE (uptr->flags); /* get drive type */ func = GET_CMD (dkp_fccy, dtype); /* get function */ newcyl = GET_CYL (dkp_fccy, dtype); /* get cylinder */ switch (func) { /* decode command */ @@ -524,11 +526,11 @@ case FCCY_RECAL: /* recalibrate */ newcyl = 0; func = FCCY_SEEK; case FCCY_SEEK: /* seek */ - sim_activate (uptr, dkp_swait * abs (newcyl - uptr -> CYL)); + sim_activate (uptr, dkp_swait * abs (newcyl - uptr->CYL)); dkp_sta = dkp_sta | (STA_SEEK0 >> u); /* set seeking */ - uptr -> CYL = newcyl; /* on cylinder */ + uptr->CYL = newcyl; /* on cylinder */ break; } /* end case command */ -uptr -> FUNC = func; /* save command */ +uptr->FUNC = func; /* save command */ return TRUE; /* no error */ } @@ -546,16 +548,17 @@ return TRUE; /* no error */ t_stat dkp_svc (UNIT *uptr) { -int32 sc, sa, xcsa, awc, bda; -int32 sx, dx, pa; -int32 dtype, u, err, newsect, newsurf; +int32 sc, sa, xcsa, bda; +int32 sx, dx, pa, u; +int32 dtype, err, newsect, newsurf; +uint32 awc; t_stat rval; static uint16 tbuf[DKP_NUMWD]; /* transfer buffer */ rval = SCPE_OK; -dtype = GET_DTYPE (uptr -> flags); /* get drive type */ -if (uptr -> FUNC == FCCY_SEEK) { /* seek? */ - if (uptr -> CYL >= drv_tab[dtype].cyl) /* bad cylinder? */ +dtype = GET_DTYPE (uptr->flags); /* get drive type */ +if (uptr->FUNC == FCCY_SEEK) { /* seek? */ + if (uptr->CYL >= drv_tab[dtype].cyl) /* bad cylinder? */ dkp_sta = dkp_sta | STA_ERR | STA_CYL; dev_done = dev_done | INT_DKP; /* set done */ int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); @@ -564,52 +567,52 @@ if (uptr -> FUNC == FCCY_SEEK) { /* seek? */ & ~(STA_SEEK0 >> u); /* clear seeking */ return SCPE_OK; } -if (((uptr -> flags & UNIT_ATT) == 0) || /* not attached? */ - ((uptr -> flags & UNIT_WPRT) && (uptr -> FUNC == FCCY_WRITE))) +if (((uptr->flags & UNIT_ATT) == 0) || /* not attached? */ + ((uptr->flags & UNIT_WPRT) && (uptr->FUNC == FCCY_WRITE))) dkp_sta = dkp_sta | STA_DONE | STA_ERR; /* error */ -else if ((uptr -> CYL >= drv_tab[dtype].cyl) || /* bad cylinder */ +else if ((uptr->CYL >= drv_tab[dtype].cyl) || /* bad cylinder */ (GET_SURF (dkp_ussc, dtype) >= drv_tab[dtype].surf) || /* bad surface */ (GET_SECT (dkp_ussc, dtype) >= drv_tab[dtype].sect)) /* or bad sector? */ dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_UNS; -else if (GET_CYL (dkp_fccy, dtype) != uptr -> CYL) /* address error? */ +else if (GET_CYL (dkp_fccy, dtype) != uptr->CYL) /* address error? */ dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_UNS; else { sc = 16 - GET_COUNT (dkp_ussc); /* get sector count */ - sa = GET_SA (uptr -> CYL, GET_SURF (dkp_ussc, dtype), + sa = GET_SA (uptr->CYL, GET_SURF (dkp_ussc, dtype), GET_SECT (dkp_ussc, dtype), dtype); /* get disk block */ - xcsa = GET_SA (uptr -> CYL + 1, 0, 0, dtype); /* get next cyl addr */ + xcsa = GET_SA (uptr->CYL + 1, 0, 0, dtype); /* get next cyl addr */ if ((sa + sc) > xcsa ) { /* across cylinder? */ sc = xcsa - sa; /* limit transfer */ dkp_sta = dkp_sta | STA_XCY; } /* xcyl error */ bda = sa * DKP_NUMWD * sizeof (short); /* to words, bytes */ - err = fseek (uptr -> fileref, bda, SEEK_SET); /* position drive */ + err = fseek (uptr->fileref, bda, SEEK_SET); /* position drive */ - if (uptr -> FUNC == FCCY_READ) { /* read? */ + if (uptr->FUNC == FCCY_READ) { /* read? */ for (sx = 0; sx < sc; sx++) { /* loop thru sectors */ - awc = fxread (tbuf, sizeof(uint16), DKP_NUMWD, uptr -> fileref); + awc = fxread (tbuf, sizeof(uint16), DKP_NUMWD, uptr->fileref); for ( ; awc < DKP_NUMWD; awc++) tbuf[awc] = 0; - if (err = ferror (uptr -> fileref)) break; + if (err = ferror (uptr->fileref)) break; for (dx = 0; dx < DKP_NUMWD; dx++) { /* loop thru buffer */ pa = MapAddr (0, dkp_ma); if (MEM_ADDR_OK (pa)) M[pa] = tbuf[dx]; dkp_ma = (dkp_ma + 1) & AMASK; } } } - if (uptr -> FUNC == FCCY_WRITE) { /* write? */ + if (uptr->FUNC == FCCY_WRITE) { /* write? */ for (sx = 0; sx < sc; sx++) { /* loop thru sectors */ for (dx = 0; dx < DKP_NUMWD; dx++) { /* loop into buffer */ pa = MapAddr (0, dkp_ma); tbuf[dx] = M[pa]; dkp_ma = (dkp_ma + 1) & AMASK; } - fxwrite (tbuf, sizeof(int16), DKP_NUMWD, uptr -> fileref); - if (err = ferror (uptr -> fileref)) break; } } + fxwrite (tbuf, sizeof(int16), DKP_NUMWD, uptr->fileref); + if (err = ferror (uptr->fileref)) break; } } if (err != 0) { perror ("DKP I/O error"); rval = SCPE_IOERR; } - clearerr (uptr -> fileref); + clearerr (uptr->fileref); sa = sa + sc; /* update sector addr */ newsect = sa % drv_tab[dtype].sect; @@ -640,7 +643,7 @@ dkp_fccy = dkp_ussc = dkp_ma = dkp_sta = 0; /* clear registers */ for (u = 0; u < DKP_NUMDR; u++) { /* loop thru units */ uptr = dkp_dev.units + u; sim_cancel (uptr); /* cancel activity */ - uptr -> CYL = uptr -> FUNC = 0; } + uptr->CYL = uptr->FUNC = 0; } return SCPE_OK; } @@ -651,15 +654,15 @@ t_stat dkp_attach (UNIT *uptr, char *cptr) int32 i, p; t_stat r; -uptr -> capac = drv_tab[GET_DTYPE (uptr -> flags)].size; +uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size; r = attach_unit (uptr, cptr); -if ((r != SCPE_OK) || ((uptr -> flags & UNIT_AUTO) == 0)) return r; -if (fseek (uptr -> fileref, 0, SEEK_END)) return SCPE_OK; -if ((p = ftell (uptr -> fileref)) == 0) return SCPE_OK; +if ((r != SCPE_OK) || ((uptr->flags & UNIT_AUTO) == 0)) return r; +if (fseek (uptr->fileref, 0, SEEK_END)) return SCPE_OK; +if ((p = ftell (uptr->fileref)) == 0) return SCPE_OK; for (i = 0; drv_tab[i].sect != 0; i++) { if (p <= (drv_tab[i].size * (int) sizeof (short))) { - uptr -> flags = (uptr -> flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE); - uptr -> capac = drv_tab[i].size; + uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE); + uptr->capac = drv_tab[i].size; return SCPE_OK; } } return SCPE_OK; } @@ -668,8 +671,8 @@ return SCPE_OK; t_stat dkp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { -if (uptr -> flags & UNIT_ATT) return SCPE_ALATT; -uptr -> capac = drv_tab[GET_DTYPE (val)].size; +if (uptr->flags & UNIT_ATT) return SCPE_ALATT; +uptr->capac = drv_tab[GET_DTYPE (val)].size; return SCPE_OK; } @@ -704,7 +707,7 @@ static const int32 boot_rom[] = { 0174000 /* REDCMD: 174000 */ }; -t_stat dkp_boot (int32 unitno) +t_stat dkp_boot (int32 unitno, DEVICE *dptr) { int32 i, dtype; extern int32 saved_PC; diff --git a/NOVA/nova_doc.txt b/NOVA/nova_doc.txt index 13af4395..40a33e40 100644 --- a/NOVA/nova_doc.txt +++ b/NOVA/nova_doc.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik Subj: Nova Simulator Usage -Date: 15-Jun-2002 +Date: 15-Nov-2002 COPYRIGHT NOTICE @@ -37,11 +37,11 @@ This memorandum documents the Nova simulator. 1. Simulator Files sim/ sim_defs.h + sim_rev.h sim_sock.h sim_tmxr.h scp.c scp_tty.c - sim_rev.c sim_sock.c sim_tmxr.c @@ -76,8 +76,6 @@ DK head-per-track disk controller DP moving head disk controller with four drives MT magnetic tape controller with eight drives -The TTI1/TTO1, PLT, DK, DP, and MT devices can be set DISABLED. - The Nova simulator implements these unique stop conditions: - reference to undefined I/O device, and STOP_DEV is set @@ -89,14 +87,21 @@ The Nova simulator implements these unique stop conditions: The Nova loader supports standard binary format tapes. The DUMP command is not implemented. +Most devices can be disabled or enabled, by the commands: + + SET DISABLED + SET ENABLED + +All devices are enabled by default. + 2.1 CPU The only CPU options are the presence of the optional instructions and the size of main memory. - SET CPU NOVA4 enable Nova4 instructions - SET CPU NOVA3 enable Nova3 instructions SET CPU MDV enable multiply/divide + SET CPU NOVA3 enable Nova3 instructions + SET CPU NOVA4 enable Nova4 instructions SET CPU NONE disable all optional instructions SET CPU 4K set memory size = 4K SET CPU 8K set memory size = 8K @@ -505,8 +510,7 @@ Error handling is as follows: not attached tape not ready - end of file (read or space) end of physical tape - (write) ignored + end of file bad tape OS I/O error report error and stop diff --git a/NOVA/nova_dsk.c b/NOVA/nova_dsk.c index 5eb89ecf..874ca064 100644 --- a/NOVA/nova_dsk.c +++ b/NOVA/nova_dsk.c @@ -23,8 +23,9 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - dsk fixed head disk + dsk fixed head disk + 03-Oct-02 RMS Added DIB 06-Jan-02 RMS Revised enable/disable support 23-Aug-01 RMS Fixed bug in write watermarking 26-Apr-01 RMS Added device enable/disable support @@ -79,16 +80,20 @@ static const int32 sector_map[] = { extern uint16 M[]; extern UNIT cpu_unit; -extern int32 int_req, dev_busy, dev_done, dev_disable, iot_enb; +extern int32 int_req, dev_busy, dev_done, dev_disable; + int32 dsk_stat = 0; /* status register */ int32 dsk_da = 0; /* disk address */ int32 dsk_ma = 0; /* memory address */ int32 dsk_wlk = 0; /* wrt lock switches */ int32 dsk_stopioe = 1; /* stop on error */ int32 dsk_time = 100; /* time per sector */ + +DEVICE dsk_dev; +int32 dsk (int32 pulse, int32 code, int32 AC); t_stat dsk_svc (UNIT *uptr); t_stat dsk_reset (DEVICE *dptr); -t_stat dsk_boot (int32 unitno); +t_stat dsk_boot (int32 unitno, DEVICE *dptr); /* DSK data structures @@ -97,6 +102,8 @@ t_stat dsk_boot (int32 unitno); dsk_reg register list */ +DIB dsk_dib = { DEV_DSK, INT_DSK, PI_DSK, &dsk }; + UNIT dsk_unit = { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DSK_SIZE) }; @@ -112,19 +119,14 @@ REG dsk_reg[] = { { ORDATA (WLK, dsk_wlk, 8) }, { DRDATA (TIME, dsk_time, 24), REG_NZ + PV_LEFT }, { FLDATA (STOP_IOE, dsk_stopioe, 0) }, - { FLDATA (*DEVENB, iot_enb, INT_V_DSK), REG_HRO }, { NULL } }; -MTAB dsk_mod[] = { - { MTAB_XTD|MTAB_VDV, INT_DSK, NULL, "ENABLED", &set_enb }, - { MTAB_XTD|MTAB_VDV, INT_DSK, NULL, "DISABLED", &set_dsb }, - { 0 } }; - DEVICE dsk_dev = { - "DK", &dsk_unit, dsk_reg, dsk_mod, + "DK", &dsk_unit, dsk_reg, NULL, 1, 8, 21, 1, 8, 16, NULL, NULL, &dsk_reset, - &dsk_boot, NULL, NULL }; + &dsk_boot, NULL, NULL, + &dsk_dib, DEV_DISABLE }; /* IOT routine */ @@ -184,23 +186,23 @@ dev_busy = dev_busy & ~INT_DSK; /* clear busy */ dev_done = dev_done | INT_DSK; /* set done */ int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); -if ((uptr -> flags & UNIT_BUF) == 0) { /* not buf? abort */ +if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */ dsk_stat = DSKS_ERR + DSKS_NSD; /* set status */ return IORETURN (dsk_stopioe, SCPE_UNATT); } da = dsk_da * DSK_NUMWD; /* calc disk addr */ -if (uptr -> FUNC == iopS) { /* read? */ +if (uptr->FUNC == iopS) { /* read? */ for (i = 0; i < DSK_NUMWD; i++) { /* copy sector */ pa = MapAddr (0, (dsk_ma + i) & AMASK); /* map address */ if (MEM_ADDR_OK (pa)) M[pa] = - *(((int16 *) uptr -> filebuf) + da + i); } + *(((int16 *) uptr->filebuf) + da + i); } dsk_ma = (dsk_ma + DSK_NUMWD) & AMASK; } -if (uptr -> FUNC == iopP) { /* write? */ +if (uptr->FUNC == iopP) { /* write? */ for (i = 0; i < DSK_NUMWD; i++) { /* copy sector */ pa = MapAddr (0, (dsk_ma + i) & AMASK); /* map address */ - *(((int16 *) uptr -> filebuf) + da + i) = M[pa]; } - if (((t_addr) (da + i)) >= uptr -> hwmark) /* past end? */ - uptr -> hwmark = da + i + 1; /* upd hwmark */ + *(((int16 *) uptr->filebuf) + da + i) = M[pa]; } + if (((t_addr) (da + i)) >= uptr->hwmark) /* past end? */ + uptr->hwmark = da + i + 1; /* upd hwmark */ dsk_ma = (dsk_ma + DSK_NUMWD + 3) & AMASK; } dsk_stat = 0; /* set status */ @@ -234,7 +236,7 @@ static const int32 boot_rom[] = { 000377, /* JMP 377 */ }; -t_stat dsk_boot (int32 unitno) +t_stat dsk_boot (int32 unitno, DEVICE *dptr) { int32 i; extern int32 saved_PC; diff --git a/NOVA/nova_lp.c b/NOVA/nova_lp.c index c2095838..e5c9151d 100644 --- a/NOVA/nova_lp.c +++ b/NOVA/nova_lp.c @@ -31,7 +31,10 @@ #include "nova_defs.h" extern int32 int_req, dev_busy, dev_done, dev_disable; + int32 lpt_stopioe = 0; /* stop on error */ + +int32 lpt (int32 pulse, int32 code, int32 AC); t_stat lpt_svc (UNIT *uptr); t_stat lpt_reset (DEVICE *dptr); @@ -42,6 +45,8 @@ t_stat lpt_reset (DEVICE *dptr); lpt_reg LPT register list */ +DIB lpt_dib = { DEV_LPT, INT_LPT, PI_LPT, &lpt }; + UNIT lpt_unit = { UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; @@ -60,7 +65,8 @@ DEVICE lpt_dev = { "LPT", &lpt_unit, lpt_reg, NULL, 1, 10, 31, 1, 8, 8, NULL, NULL, &lpt_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &lpt_dib, DEV_DISABLE }; /* IOT routine */ diff --git a/NOVA/nova_mta.c b/NOVA/nova_mta.c index 8d61142d..92e955e8 100644 --- a/NOVA/nova_mta.c +++ b/NOVA/nova_mta.c @@ -25,6 +25,10 @@ mta magnetic tape + 30-Oct-02 RMS Fixed BOT handling, added error record handling + 08-Oct-02 RMS Added DIB + 30-Sep-02 RMS Revamped error handling + 28-Aug-02 RMS Added end of medium support 30-May-02 RMS Widened POS to 32b 22-Apr-02 RMS Added maximum record length test 06-Jan-02 RMS Revised enable/disable support @@ -59,10 +63,10 @@ #define MTA_NUMDR 8 /* #drives */ #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_V_PNU (UNIT_V_UF + 1) /* pos not updated */ #define UNIT_WLK (1 << UNIT_V_WLK) -#define UNIT_W_UF 2 /* saved flags width */ +#define UNIT_PNU (1 << UNIT_V_PNU) #define USTAT u3 /* unit status */ -#define UNUM u4 /* unit number */ #define MTA_MAXFR (1 << 16) /* max record lnt */ #define DTSIZE (1 << 14) /* max data xfer */ #define DTMASK (DTSIZE - 1) @@ -93,7 +97,7 @@ #define GET_CMD(x) (((x) >> CU_V_CMD) & CU_M_CMD) #define GET_UNIT(x) (((x) >> CU_V_UNIT) & CU_M_UNIT) -/* Status 1 - stored in mta_sta<31:16> or (*) uptr -> USTAT<31:16> */ +/* Status 1 - stored in mta_sta<31:16> or (*) uptr->USTAT<31:16> */ #define STA_ERR1 (0100000u << 16) /* error */ #define STA_DLT (0040000 << 16) /* data late */ @@ -111,7 +115,7 @@ #define STA_ODD (0000002 << 16) /* odd character */ #define STA_RDY (0000001 << 16) /* *drive ready */ -/* Status 2 - stored in mta_sta<15:0> or (*) uptr -> USTAT<15:0> */ +/* Status 2 - stored in mta_sta<15:0> or (*) uptr->USTAT<15:0> */ #define STA_ERR2 0100000 /* error */ #define STA_RWY 0040000 /* runaway tape */ @@ -141,7 +145,8 @@ extern uint16 M[]; extern UNIT cpu_unit; -extern int32 int_req, dev_busy, dev_done, dev_disable, iot_enb; +extern int32 int_req, dev_busy, dev_done, dev_disable; + int32 mta_ma = 0; /* memory address */ int32 mta_wc = 0; /* word count */ int32 mta_cu = 0; /* command/unit */ @@ -149,14 +154,19 @@ int32 mta_sta = 0; /* status register */ int32 mta_ep = 0; /* enable polling */ int32 mta_cwait = 100; /* command latency */ int32 mta_rwait = 100; /* record latency */ + +DEVICE mta_dev; +int32 mta (int32 pulse, int32 code, int32 AC); t_stat mta_svc (UNIT *uptr); t_stat mta_reset (DEVICE *dptr); -t_stat mta_boot (int32 unitno); +t_stat mta_boot (int32 unitno, DEVICE *dptr); t_stat mta_attach (UNIT *uptr, char *cptr); t_stat mta_detach (UNIT *uptr); int32 mta_updcsta (UNIT *uptr); void mta_upddsta (UNIT *uptr, int32 newsta); t_stat mta_vlock (UNIT *uptr, int32 val, char *cptr, void *desc); +t_bool mta_rdlntf (UNIT *uptr, t_mtrlnt *tbc, int32 *err); +t_bool mta_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err); static const int ctype[32] = { /* c vs r timing */ 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, @@ -170,6 +180,8 @@ static const int ctype[32] = { /* c vs r timing */ mta_mod MTA modifier list */ +DIB mta_dib = { DEV_MTA, INT_MTA, PI_MTA, &mta }; + UNIT mta_unit[] = { { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, @@ -196,23 +208,19 @@ REG mta_reg[] = { { URDATA (UST, mta_unit[0].USTAT, 8, 32, 0, MTA_NUMDR, 0) }, { URDATA (POS, mta_unit[0].pos, 8, 32, 0, MTA_NUMDR, REG_RO | PV_LEFT) }, - { URDATA (FLG, mta_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, - MTA_NUMDR, REG_HRO) }, - { FLDATA (*DEVENB, iot_enb, INT_V_MTA), REG_HRO }, { NULL } }; MTAB mta_mod[] = { { UNIT_WLK, 0, "write enabled", "WRITEENABLED", &mta_vlock }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &mta_vlock }, - { MTAB_XTD|MTAB_VDV, INT_MTA, NULL, "ENABLED", &set_enb }, - { MTAB_XTD|MTAB_VDV, INT_MTA, NULL, "DISABLED", &set_dsb }, { 0 } }; DEVICE mta_dev = { "MT", mta_unit, mta_reg, mta_mod, MTA_NUMDR, 10, 31, 1, 8, 8, NULL, NULL, &mta_reset, - &mta_boot, &mta_attach, &mta_detach }; + &mta_boot, &mta_attach, &mta_detach, + &mta_dib, DEV_DISABLE }; /* IOT routine */ @@ -252,13 +260,13 @@ switch (pulse) { /* decode IR<8:9> */ case iopS: /* start */ c = GET_CMD (mta_cu); /* get command */ if (dev_busy & INT_MTA) break; /* ignore if busy */ - if ((uptr -> USTAT & STA_RDY) == 0) { /* drive not ready? */ + if ((uptr->USTAT & STA_RDY) == 0) { /* drive not ready? */ mta_sta = mta_sta | STA_ILL; /* illegal op */ dev_busy = dev_busy & ~INT_MTA; /* clear busy */ dev_done = dev_done | INT_MTA; /* set done */ int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); } else if ((c == CU_REWIND) || (c == CU_UNLOAD)) { /* rewind, unload? */ - mta_upddsta (uptr, (uptr -> USTAT & /* update status */ + mta_upddsta (uptr, (uptr->USTAT & /* update status */ ~(STA_BOT | STA_EOF | STA_EOT | STA_RDY)) | STA_REW); sim_activate (uptr, mta_rwait); /* start IO */ if (c == CU_UNLOAD) detach_unit (uptr); } @@ -267,7 +275,7 @@ case iopS: /* start */ dev_done = dev_done & ~INT_MTA; /* clear done */ int_req = int_req & ~INT_MTA; /* clear int */ if (ctype[c]) sim_activate (uptr, mta_cwait); - else { mta_upddsta (uptr, uptr -> USTAT & + else { mta_upddsta (uptr, uptr->USTAT & ~(STA_BOT | STA_EOF | STA_EOT | STA_RDY)); sim_activate (uptr, mta_rwait); } } mta_updcsta (uptr); /* update status */ @@ -275,8 +283,8 @@ case iopS: /* start */ case iopC: /* clear */ for (u = 0; u < MTA_NUMDR; u++) { /* loop thru units */ uptr = mta_dev.units + u; /* cancel IO */ - if (sim_is_active (uptr) && !(uptr -> USTAT & STA_REW)) { - mta_upddsta (uptr, uptr -> USTAT | STA_RDY); + if (sim_is_active (uptr) && !(uptr->USTAT & STA_REW)) { + mta_upddsta (uptr, uptr->USTAT | STA_RDY); sim_cancel (uptr); } } dev_busy = dev_busy & ~INT_MTA; /* clear busy */ dev_done = dev_done & ~INT_MTA; /* clear done */ @@ -295,32 +303,32 @@ return rval; t_stat mta_svc (UNIT *uptr) { -int32 c, i, p, u, pa, err; -t_stat rval; -t_mtrlnt cbc, tbc, wc; +int32 c, p, pa, err, pnu, u; +t_mtrlnt i, cbc, tbc, wc; uint16 c1, c2; static uint8 dbuf[2 * DTSIZE]; -static t_mtrlnt bceof = { 0 }; - -rval = SCPE_OK; -u = uptr -> UNUM; /* get unit number */ -if (uptr -> USTAT & STA_REW) { /* rewind? */ - uptr -> pos = 0; /* update position */ - mta_upddsta (uptr, (uptr -> USTAT & ~STA_REW) | STA_BOT | STA_RDY); - if (u == GET_UNIT (mta_cu)) mta_updcsta (uptr); - return rval; } +static t_mtrlnt bceof = { MTR_TMK }; err = 0; +u = uptr - mta_dev.units; /* get unit number */ +pnu = MT_TST_PNU (uptr); /* get pos not upd */ +MT_CLR_PNU (uptr); /* and clear */ +if (uptr->USTAT & STA_REW) { /* rewind? */ + uptr->pos = 0; /* update position */ + mta_upddsta (uptr, (uptr->USTAT & ~STA_REW) | STA_BOT | STA_RDY); + if (u == GET_UNIT (mta_cu)) mta_updcsta (uptr); + return SCPE_OK; } + c = GET_CMD (mta_cu); /* command */ wc = DTSIZE - (mta_wc & DTMASK); /* io wc */ -if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */ +if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ mta_upddsta (uptr, 0); /* unit off line */ mta_sta = mta_sta | STA_ILL; } /* illegal operation */ -else if ((uptr -> flags & UNIT_WPRT) && /* write locked? */ +else if ((uptr->flags & UNIT_WPRT) && /* write locked? */ ((c == CU_WRITE) || (c == CU_WREOF) || (c == CU_ERASE))) { - mta_upddsta (uptr, uptr -> USTAT | STA_WLK | STA_RDY); + mta_upddsta (uptr, uptr->USTAT | STA_WLK | STA_RDY); mta_sta = mta_sta | STA_ILL; } /* illegal operation */ else switch (c) { /* case on command */ @@ -328,35 +336,28 @@ case CU_CMODE: /* controller mode */ mta_ep = mta_cu & CU_EP; break; case CU_DMODE: /* drive mode */ - if (uptr -> pos) mta_sta = mta_sta | STA_ILL; /* must be BOT */ + if (uptr->pos) mta_sta = mta_sta | STA_ILL; /* must be BOT */ else mta_upddsta (uptr, (mta_cu & CU_PE)? /* update drv status */ - uptr -> USTAT | STA_PEM: uptr -> USTAT & ~ STA_PEM); + uptr->USTAT | STA_PEM: uptr->USTAT & ~ STA_PEM); break; /* Unit service, continued */ case CU_READ: /* read */ case CU_READNS: /* read non-stop */ - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); - fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); /* read byte count */ - if ((err = ferror (uptr -> fileref)) || /* error or eof? */ - (feof (uptr -> fileref))) { - mta_upddsta (uptr, uptr -> USTAT | STA_RDY | STA_EOT); - break; } - if (tbc == 0) { /* tape mark? */ - mta_upddsta (uptr, uptr -> USTAT | STA_RDY | STA_EOF); - uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); - break; } - tbc = MTRL (tbc); /* ignore error flag */ + if (mta_rdlntf (uptr, &tbc, & err)) break; /* read rec lnt, err? */ if (tbc > MTA_MAXFR) return SCPE_MTRLNT; /* record too long? */ cbc = wc * 2; /* expected bc */ if (tbc & 1) mta_sta = mta_sta | STA_ODD; /* odd byte count? */ if (tbc > cbc) mta_sta = mta_sta | STA_WCO; /* too big? */ else { cbc = tbc; /* no, use it */ wc = (cbc + 1) / 2; } /* adjust wc */ - i = fxread (dbuf, sizeof (int8), cbc, uptr -> fileref); + i = fxread (dbuf, sizeof (int8), cbc, uptr->fileref); for ( ; i < cbc; i++) dbuf[i] = 0; - err = ferror (uptr -> fileref); + mta_upddsta (uptr, uptr->USTAT | STA_RDY); + if (err = ferror (uptr->fileref)) { /* error? */ + MT_SET_PNU (uptr); /* pos not upd */ + break; } for (i = p = 0; i < wc; i++) { /* copy buf to mem */ c1 = dbuf[p++]; c2 = dbuf[p++]; @@ -364,105 +365,82 @@ case CU_READNS: /* read non-stop */ if (MEM_ADDR_OK (pa)) M[pa] = (c1 << 8) | c2; mta_ma = (mta_ma + 1) & AMASK; } mta_wc = (mta_wc + wc) & DMASK; - uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) + + uptr->pos = uptr->pos + ((tbc + 1) & ~1) + (2 * sizeof (t_mtrlnt)); - mta_upddsta (uptr, uptr -> USTAT | STA_RDY); break; + case CU_WRITE: /* write */ - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); + fseek (uptr->fileref, uptr->pos, SEEK_SET); tbc = wc * 2; /* io byte count */ - fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); + fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr->fileref); for (i = p = 0; i < wc; i++) { /* copy to buffer */ pa = MapAddr (0, mta_ma); /* map address */ dbuf[p++] = (M[pa] >> 8) & 0377; dbuf[p++] = M[pa] & 0377; mta_ma = (mta_ma + 1) & AMASK; } - fxwrite (dbuf, sizeof (int8), tbc, uptr -> fileref); - fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - err = ferror (uptr -> fileref); - mta_wc = 0; - uptr -> pos = uptr -> pos + tbc + (2 * sizeof (t_mtrlnt)); - mta_upddsta (uptr, uptr -> USTAT | STA_RDY); - break; -case CU_WREOF: /* write eof */ - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); - fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr -> fileref); - err = ferror (uptr -> fileref); - uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); - mta_upddsta (uptr, uptr -> USTAT | STA_EOF | STA_RDY); - break; -case CU_ERASE: /* erase */ - mta_upddsta (uptr, uptr -> USTAT | STA_RDY); + fxwrite (dbuf, sizeof (int8), tbc, uptr->fileref); + fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr->fileref); + mta_upddsta (uptr, uptr->USTAT | STA_RDY); + if (err = ferror (uptr->fileref)) MT_SET_PNU (uptr); /* error? */ + else { mta_wc = 0; + uptr->pos = uptr->pos + tbc + (2 * sizeof (t_mtrlnt)); } break; /* Unit service, continued */ +case CU_WREOF: /* write eof */ + fseek (uptr->fileref, uptr->pos, SEEK_SET); + fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr->fileref); + mta_upddsta (uptr, uptr->USTAT | STA_EOF | STA_RDY); + if (err = ferror (uptr->fileref)) MT_SET_PNU (uptr); /* error? */ + else uptr->pos = uptr->pos + sizeof (t_mtrlnt); + break; + +case CU_ERASE: /* erase */ + mta_upddsta (uptr, uptr->USTAT | STA_RDY); + break; + case CU_SPACEF: /* space forward */ do { mta_wc = (mta_wc + 1) & DMASK; /* incr wc */ - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); - fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - if ((err = ferror (uptr -> fileref)) || /* error or eof? */ - (feof (uptr -> fileref))) { - mta_upddsta (uptr, uptr -> USTAT | STA_RDY | STA_EOT); - break; } - if (tbc == 0) { /* zero bc? */ - mta_upddsta (uptr, uptr -> USTAT | STA_RDY | STA_EOF); - uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); - break; } - uptr -> pos = uptr -> pos + ((MTRL (tbc) + 1) & ~1) + + if (mta_rdlntf (uptr, &tbc, &err)) break; /* read rec lnt, err? */ + uptr->pos = uptr->pos + ((tbc + 1) & ~1) + (2 * sizeof (t_mtrlnt)); } while (mta_wc != 0); - mta_upddsta (uptr, uptr -> USTAT | STA_RDY); + mta_upddsta (uptr, uptr->USTAT | STA_RDY); break; + case CU_SPACER: /* space reverse */ - if (uptr -> pos == 0) { /* at BOT? */ - mta_upddsta (uptr, uptr -> USTAT | STA_RDY | STA_BOT); - break; } do { mta_wc = (mta_wc + 1) & DMASK; /* incr wc */ - fseek (uptr -> fileref, uptr -> pos - sizeof (t_mtrlnt), - SEEK_SET); /* bs to reclnt */ - fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - if ((err = ferror (uptr -> fileref)) || /* error or eof? */ - (feof (uptr -> fileref))) { - mta_upddsta (uptr, uptr -> USTAT | STA_RDY | STA_BOT); - uptr -> pos = 0; - break; } - if (tbc == 0) { /* zero bc? */ - mta_upddsta (uptr, uptr -> USTAT | STA_RDY | STA_EOF); - uptr -> pos = uptr -> pos - sizeof (t_mtrlnt); - break; } - uptr -> pos = uptr -> pos - ((MTRL (tbc) + 1) & ~1) - - (2 * sizeof (t_mtrlnt)); - if (uptr -> pos == 0) { /* start of tape? */ - mta_upddsta (uptr, uptr -> USTAT | STA_RDY | STA_BOT); - break; } } + if (pnu) pnu = 0; /* pos not upd? */ + else { if (mta_rdlntr (uptr, &tbc, &err)) break; + uptr->pos = uptr->pos - ((tbc + 1) & ~1) - + (2 * sizeof (t_mtrlnt)); } } while (mta_wc != 0); - mta_upddsta (uptr, uptr -> USTAT | STA_RDY); + mta_upddsta (uptr, uptr->USTAT | STA_RDY); break; + default: /* reserved */ mta_sta = mta_sta | STA_ILL; break; } /* end case */ - -/* Unit service, continued */ -if (err != 0) { /* I/O error */ - mta_sta = mta_sta | STA_DAE; /* flag error */ - perror ("MTA I/O error"); - rval = SCPE_IOERR; - clearerr (uptr -> fileref); } +if (err != 0) mta_sta = mta_sta | STA_DAE; /* I/O error */ mta_updcsta (uptr); /* update status */ dev_busy = dev_busy & ~INT_MTA; /* clear busy */ dev_done = dev_done | INT_MTA; /* set done */ int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); -return rval; +if (err != 0) { + perror ("MTA I/O error"); + clearerr (uptr->fileref); + return SCPE_IOERR; } +return SCPE_OK; } - + /* Update controller status */ int32 mta_updcsta (UNIT *uptr) /* update ctrl */ { mta_sta = (mta_sta & ~(STA_DYN | STA_CLR | STA_ERR1 | STA_ERR2)) | - (uptr -> USTAT & STA_DYN) | STA_SET; + (uptr->USTAT & STA_DYN) | STA_SET; if (mta_sta & STA_EFLGS1) mta_sta = mta_sta | STA_ERR1; if (mta_sta & STA_EFLGS2) mta_sta = mta_sta | STA_ERR2; return mta_sta; @@ -474,17 +452,73 @@ void mta_upddsta (UNIT *uptr, int32 newsta) /* drive status */ { int32 change; -if ((uptr -> flags & UNIT_ATT) == 0) newsta = 0; /* offline? */ -change = (uptr -> USTAT ^ newsta) & STA_MON; /* changes? */ -uptr -> USTAT = newsta & STA_DYN; /* update status */ +if ((uptr->flags & UNIT_ATT) == 0) newsta = 0; /* offline? */ +change = (uptr->USTAT ^ newsta) & STA_MON; /* changes? */ +uptr->USTAT = newsta & STA_DYN; /* update status */ if (change) { /* if (mta_ep) { /* if polling */ -/* u = uptr -> UNUM; /* unit num */ +/* u = uptr - mta_dev.units; /* unit num */ /* mta_sta = (mta_sta & ~STA_UNIT) | (u << STA_V_UNIT); /* set polling interupt... } */ mta_sta = mta_sta | STA_CHG; } /* flag change */ return; } + +/* Read record length forward - return T if error, EOM, or EOF */ + +t_bool mta_rdlntf (UNIT *uptr, t_mtrlnt *tbc, int32 *err) +{ +fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set tape pos */ +fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); /* read rec lnt */ +if (*err = ferror (uptr->fileref)) { /* error? */ + mta_sta = mta_sta | STA_DAE; /* data error */ + mta_upddsta (uptr, uptr->USTAT | STA_RDY); /* ready */ + MT_SET_PNU (uptr); /* pos not upd */ + return TRUE; } +if (feof (uptr->fileref) || (*tbc == MTR_EOM)) { /* eof or eom? */ + mta_sta = mta_sta | STA_BAT; /* bad tape */ + mta_upddsta (uptr, uptr->USTAT | STA_RDY); /* ready */ + MT_SET_PNU (uptr); /* pos not upd */ + return TRUE; } +if (*tbc == MTR_TMK) { /* tape mark? */ + mta_upddsta (uptr, uptr->USTAT | STA_RDY | STA_EOF); + uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* spc over tmk */ + return TRUE; } +if (MTRF (*tbc)) mta_sta = mta_sta | STA_DAE; /* record in error? */ +*tbc = MTRL (*tbc); /* clear error flag */ +return FALSE; +} + +/* Read record length reverse - return T if error, EOM, or EOF */ + +t_bool mta_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err) +{ +if (uptr->pos < sizeof (t_mtrlnt)) { /* at BOT? */ + mta_upddsta (uptr, uptr->USTAT | STA_RDY | STA_BOT); + return TRUE; } +fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt), SEEK_SET); +fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); +if (*err = ferror (uptr->fileref)) { /* error? */ + mta_sta = mta_sta | STA_DAE; /* data error */ + mta_upddsta (uptr, uptr->USTAT | STA_RDY); /* ready */ + return TRUE; } +if (feof (uptr->fileref)) { /* eof? */ + mta_sta = mta_sta | STA_BAT; /* bad tape */ + mta_upddsta (uptr, uptr->USTAT | STA_RDY); /* ready */ + return TRUE; } +if (*tbc == MTR_EOM) { /* eom? */ + mta_sta = mta_sta | STA_BAT; /* bad tape */ + mta_upddsta (uptr, uptr->USTAT | STA_RDY); /* ready */ + uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over eom */ + return TRUE; } +if (*tbc == MTR_TMK) { /* tape mark? */ + mta_upddsta (uptr, uptr->USTAT | STA_RDY | STA_EOF); + uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over tmk */ + return TRUE; } +if (MTRF (*tbc)) mta_sta = mta_sta | STA_DAE; /* record in error? */ +*tbc = MTRL (*tbc); /* clear error flag */ +return FALSE; +} /* Reset routine */ @@ -500,13 +534,13 @@ mta_cu = mta_wc = mta_ma = mta_sta = 0; /* clear registers */ mta_ep = 0; for (u = 0; u < MTA_NUMDR; u++) { /* loop thru units */ uptr = mta_dev.units + u; + MT_CLR_PNU (uptr); /* clear pos flag */ sim_cancel (uptr); /* cancel activity */ - uptr -> UNUM = u; - if (uptr -> flags & UNIT_ATT) uptr -> USTAT = STA_RDY | - (uptr -> USTAT & STA_PEM) | - ((uptr -> flags & UNIT_WPRT)? STA_WLK: 0) | - ((uptr -> pos)? 0: STA_BOT); - else uptr -> USTAT = 0; } + if (uptr->flags & UNIT_ATT) uptr->USTAT = STA_RDY | + (uptr->USTAT & STA_PEM) | + ((uptr->flags & UNIT_WPRT)? STA_WLK: 0) | + ((uptr->pos)? 0: STA_BOT); + else uptr->USTAT = 0; } mta_updcsta (&mta_unit[0]); /* update status */ return SCPE_OK; } @@ -519,8 +553,9 @@ t_stat r; r = attach_unit (uptr, cptr); if (r != SCPE_OK) return r; +MT_CLR_PNU (uptr); if (!sim_is_active (uptr)) mta_upddsta (uptr, STA_RDY | STA_BOT | STA_PEM | - ((uptr -> flags & UNIT_WPRT)? STA_WLK: 0)); + ((uptr->flags & UNIT_WPRT)? STA_WLK: 0)); return r; } @@ -528,6 +563,7 @@ return r; t_stat mta_detach (UNIT* uptr) { +MT_CLR_PNU (uptr); if (!sim_is_active (uptr)) mta_upddsta (uptr, 0); return detach_unit (uptr); } @@ -536,9 +572,9 @@ return detach_unit (uptr); t_stat mta_vlock (UNIT *uptr, int32 val, char *cptr, void *desc) { -if ((uptr -> flags & UNIT_ATT) && val) - mta_upddsta (uptr, uptr -> USTAT | STA_WLK); -else mta_upddsta (uptr, uptr -> USTAT & ~STA_WLK); +if ((uptr->flags & UNIT_ATT) && val) + mta_upddsta (uptr, uptr->USTAT | STA_WLK); +else mta_upddsta (uptr, uptr->USTAT & ~STA_WLK); return SCPE_OK; } @@ -569,7 +605,7 @@ static const int32 boot_rom[] = { 000010 /* REWIND: 10 */ }; -t_stat mta_boot (int32 unitno) +t_stat mta_boot (int32 unitno, DEVICE *dptr) { int32 i; extern int32 saved_PC; diff --git a/NOVA/nova_plt.c b/NOVA/nova_plt.c index 66479f26..3b9e5bb9 100644 --- a/NOVA/nova_plt.c +++ b/NOVA/nova_plt.c @@ -26,6 +26,7 @@ plt plotter + 03-Oct-02 RMS Added DIB 30-May-02 RMS Widened POS to 32b 06-Jan-02 RMS Revised enable/disable support 26-Apr-01 RMS Added device enable/disable support @@ -33,8 +34,12 @@ #include "nova_defs.h" -extern int32 int_req, dev_busy, dev_done, dev_disable, iot_enb; +extern int32 int_req, dev_busy, dev_done, dev_disable; + int32 plt_stopioe = 0; /* stop on error */ + +DEVICE plt_dev; +int32 plt (int32 pulse, int32 code, int32 AC); t_stat plt_svc (UNIT *uptr); t_stat plt_reset (DEVICE *dptr); @@ -45,6 +50,8 @@ t_stat plt_reset (DEVICE *dptr); plt_reg PLT register list */ +DIB plt_dib = { DEV_PLT, INT_PLT, PI_PLT, &plt }; + UNIT plt_unit = { UDATA (&plt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; @@ -57,19 +64,14 @@ REG plt_reg[] = { { DRDATA (POS, plt_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, plt_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, plt_stopioe, 0) }, - { FLDATA (*DEVENB, iot_enb, INT_V_PLT), REG_HRO }, { NULL } }; -MTAB plt_mod[] = { - { MTAB_XTD|MTAB_VDV, INT_PLT, NULL, "ENABLED", &set_enb }, - { MTAB_XTD|MTAB_VDV, INT_PLT, NULL, "DISABLED", &set_dsb }, - { 0 } }; - DEVICE plt_dev = { - "PLT", &plt_unit, plt_reg, plt_mod, + "PLT", &plt_unit, plt_reg, NULL, 1, 10, 31, 1, 8, 8, NULL, NULL, &plt_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &plt_dib, DEV_DISABLE }; /* plotter: IOT routine */ diff --git a/NOVA/nova_pt.c b/NOVA/nova_pt.c index 629b1db1..e7c05ec1 100644 --- a/NOVA/nova_pt.c +++ b/NOVA/nova_pt.c @@ -26,6 +26,7 @@ ptr paper tape reader ptp paper tape punch + 03-Oct-02 RMS Added DIBs 30-May-02 RMS Widened POS to 32b 29-Nov-01 RMS Added read only unit support */ @@ -33,7 +34,11 @@ #include "nova_defs.h" extern int32 int_req, dev_busy, dev_done, dev_disable; + int32 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */ + +int32 ptr (int32 pulse, int32 code, int32 AC); +int32 ptp (int32 pulse, int32 code, int32 AC); t_stat ptr_svc (UNIT *uptr); t_stat ptp_svc (UNIT *uptr); t_stat ptr_reset (DEVICE *dptr); @@ -46,6 +51,8 @@ t_stat ptp_reset (DEVICE *dptr); ptr_reg PTR register list */ +DIB ptr_dib = { DEV_PTR, INT_PTR, PI_PTR, &ptr }; + UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), SERIAL_IN_WAIT }; @@ -65,7 +72,8 @@ DEVICE ptr_dev = { "PTR", &ptr_unit, ptr_reg, NULL, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptr_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &ptr_dib, 0 }; /* PTP data structures @@ -74,6 +82,8 @@ DEVICE ptr_dev = { ptp_reg PTP register list */ +DIB ptp_dib = { DEV_PTP, INT_PTP, PI_PTP, &ptp }; + UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; @@ -92,7 +102,8 @@ DEVICE ptp_dev = { "PTP", &ptp_unit, ptp_reg, NULL, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptp_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &ptp_dib, 0 }; /* Paper tape reader: IOT routine */ diff --git a/NOVA/nova_tt.c b/NOVA/nova_tt.c index c611f335..88cd8cac 100644 --- a/NOVA/nova_tt.c +++ b/NOVA/nova_tt.c @@ -26,6 +26,7 @@ tti terminal input tto terminal output + 03-Oct-02 RMS Added DIBs 30-May-02 RMS Widened POS to 32b 30-Nov-01 RMS Added extended SET/SHOW support 17-Sep-01 RMS Removed multiconsole support @@ -38,6 +39,9 @@ #define UNIT_V_DASHER (UNIT_V_UF + 0) /* Dasher mode */ #define UNIT_DASHER (1 << UNIT_V_DASHER) extern int32 int_req, dev_busy, dev_done, dev_disable; + +int32 tti (int32 pulse, int32 code, int32 AC); +int32 tto (int32 pulse, int32 code, int32 AC); t_stat tti_svc (UNIT *uptr); t_stat tto_svc (UNIT *uptr); t_stat tti_reset (DEVICE *dptr); @@ -52,6 +56,8 @@ t_stat ttx_setmod (UNIT *uptr, int32 val, char *cptr); ttx_mod TTI/TTO modifiers list */ +DIB tti_dib = { DEV_TTI, INT_TTI, PI_TTI, &tti }; + UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT }; REG tti_reg[] = { @@ -62,7 +68,6 @@ REG tti_reg[] = { { FLDATA (INT, int_req, INT_V_TTI) }, { DRDATA (POS, tti_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, - { FLDATA (MODE, tti_unit.flags, UNIT_V_DASHER), REG_HRO }, { NULL } }; MTAB ttx_mod[] = { @@ -74,7 +79,8 @@ DEVICE tti_dev = { "TTI", &tti_unit, tti_reg, ttx_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &tti_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &tti_dib, 0 }; /* TTO data structures @@ -83,6 +89,8 @@ DEVICE tti_dev = { tto_reg TTO register list */ +DIB tto_dib = { DEV_TTO, INT_TTO, PI_TTO, &tto }; + UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT }; REG tto_reg[] = { @@ -93,14 +101,14 @@ REG tto_reg[] = { { FLDATA (INT, int_req, INT_V_TTO) }, { DRDATA (POS, tto_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT }, - { FLDATA (MODE, tto_unit.flags, UNIT_V_DASHER), REG_HRO }, { NULL } }; DEVICE tto_dev = { "TTO", &tto_unit, tto_reg, ttx_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &tto_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &tto_dib, 0 }; /* Terminal input: IOT routine */ diff --git a/NOVA/nova_tt1.c b/NOVA/nova_tt1.c index 8aedfb9f..d45854fc 100644 --- a/NOVA/nova_tt1.c +++ b/NOVA/nova_tt1.c @@ -27,6 +27,8 @@ tti1 second terminal input tto1 second terminal output + 03-Oct-02 RMS Added DIBs + 22-Aug-02 RMS Updated for changes in sim_tmxr 30-May-02 RMS Widened POS to 32b 06-Jan-02 RMS Revised enable/disable support 30-Dec-01 RMS Added show statistics, set disconnect @@ -44,11 +46,14 @@ #define UNIT_V_DASHER (UNIT_V_UF + 0) /* Dasher mode */ #define UNIT_DASHER (1 << UNIT_V_DASHER) -extern int32 int_req, dev_busy, dev_done, dev_disable, iot_enb; +extern int32 int_req, dev_busy, dev_done, dev_disable; extern int32 tmxr_poll; /* calibrated poll */ TMLN tt1_ldsc = { 0 }; /* line descriptors */ -TMXR tt_desc = { 1, 0, &tt1_ldsc }; /* mux descriptor */ +TMXR tt_desc = { 1, 0, 0, &tt1_ldsc }; /* mux descriptor */ +DEVICE tti1_dev, tto1_dev; +int32 tti1 (int32 pulse, int32 code, int32 AC); +int32 tto1 (int32 pulse, int32 code, int32 AC); t_stat tti1_svc (UNIT *uptr); t_stat tto1_svc (UNIT *uptr); t_stat tti1_reset (DEVICE *dptr); @@ -58,7 +63,8 @@ t_stat tti1_attach (UNIT *uptr, char *cptr); t_stat tti1_detach (UNIT *uptr); t_stat tti1_summ (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat tti1_show (FILE *st, UNIT *uptr, int32 val, void *desc); - +void ttx1_enbdis (int32 dis); + /* TTI1 data structures tti1_dev TTI1 device descriptor @@ -67,6 +73,8 @@ t_stat tti1_show (FILE *st, UNIT *uptr, int32 val, void *desc); ttx1_mod TTI1/TTO1 modifiers list */ +DIB tti1_dib = { DEV_TTI1, INT_TTI1, PI_TTI1, &tti1 }; + UNIT tti1_unit = { UDATA (&tti1_svc, UNIT_ATTABLE, 0), KBD_POLL_WAIT }; REG tti1_reg[] = { @@ -77,8 +85,6 @@ REG tti1_reg[] = { { FLDATA (INT, int_req, INT_V_TTI1) }, { DRDATA (POS, tt1_ldsc.rxcnt, 32), PV_LEFT }, { DRDATA (TIME, tti1_unit.wait, 24), REG_NZ + PV_LEFT }, - { FLDATA (MODE, tti1_unit.flags, UNIT_V_DASHER), REG_HRO }, - { FLDATA (*DEVENB, iot_enb, INT_V_TTI1), REG_HRO }, { NULL } }; MTAB tti1_mod[] = { @@ -91,15 +97,14 @@ MTAB tti1_mod[] = { NULL, &tti1_show, NULL }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, NULL, &tti1_show, NULL }, - { MTAB_XTD|MTAB_VDV, INT_TTI1 | INT_TTO1, NULL, "ENABLED", &set_enb }, - { MTAB_XTD|MTAB_VDV, INT_TTI1 | INT_TTO1, NULL, "DISABLED", &set_dsb }, { 0 } }; DEVICE tti1_dev = { "TTI1", &tti1_unit, tti1_reg, tti1_mod, 1, 10, 31, 1, 8, 8, &tmxr_ex, &tmxr_dep, &tti1_reset, - NULL, &tti1_attach, &tti1_detach }; + NULL, &tti1_attach, &tti1_detach, + &tti1_dib, DEV_DISABLE }; /* TTO1 data structures @@ -108,6 +113,8 @@ DEVICE tti1_dev = { tto1_reg TTO1 register list */ +DIB tto1_dib = { DEV_TTO1, INT_TTO1, PI_TTO1, &tto1 }; + UNIT tto1_unit = { UDATA (&tto1_svc, 0, 0), SERIAL_OUT_WAIT }; REG tto1_reg[] = { @@ -118,8 +125,6 @@ REG tto1_reg[] = { { FLDATA (INT, int_req, INT_V_TTO1) }, { DRDATA (POS, tt1_ldsc.txcnt, 32), PV_LEFT }, { DRDATA (TIME, tto1_unit.wait, 24), PV_LEFT }, - { FLDATA (MODE, tto1_unit.flags, UNIT_V_DASHER), REG_HRO }, - { FLDATA (*DEVENB, iot_enb, INT_V_TTO1), REG_HRO }, { NULL } }; MTAB tto1_mod[] = { @@ -131,7 +136,8 @@ DEVICE tto1_dev = { "TTO1", &tto1_unit, tto1_reg, tto1_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &tto1_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &tto1_dib, DEV_DISABLE }; /* Terminal input: IOT routine */ @@ -163,16 +169,16 @@ int32 temp, newln; if (tt1_ldsc.conn) { /* connected? */ tmxr_poll_rx (&tt_desc); /* poll for input */ if (temp = tmxr_getc_ln (&tt1_ldsc)) { /* get char */ - uptr -> buf = temp & 0177; - if ((uptr -> flags & UNIT_DASHER) && - (uptr -> buf == '\r')) - uptr -> buf = '\n'; /* Dasher: cr -> nl */ + uptr->buf = temp & 0177; + if ((uptr->flags & UNIT_DASHER) && + (uptr->buf == '\r')) + uptr->buf = '\n'; /* Dasher: cr->nl */ dev_busy = dev_busy & ~INT_TTI1; /* clear busy */ dev_done = dev_done | INT_TTI1; /* set done */ int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); } - sim_activate (uptr, uptr -> wait); } /* continue poll */ -if (uptr -> flags & UNIT_ATT) { /* attached? */ - newln = tmxr_poll_conn (&tt_desc, uptr); /* poll connect */ + sim_activate (uptr, uptr->wait); } /* continue poll */ +if (uptr->flags & UNIT_ATT) { /* attached? */ + newln = tmxr_poll_conn (&tt_desc); /* poll connect */ if (newln >= 0) { /* got one? */ sim_activate (&tti1_unit, tti1_unit.wait); tt1_ldsc.rcve = 1; } /* rcv enabled */ @@ -184,6 +190,7 @@ return SCPE_OK; t_stat tti1_reset (DEVICE *dptr) { +ttx1_enbdis (dptr->flags & DEV_DIS); /* sync devices */ tti1_unit.buf = 0; dev_busy = dev_busy & ~INT_TTI1; /* clear busy */ dev_done = dev_done & ~INT_TTI1; /* clear done, int */ @@ -243,6 +250,7 @@ return SCPE_OK; t_stat tto1_reset (DEVICE *dptr) { +ttx1_enbdis (dptr->flags & DEV_DIS); /* sync devices */ tto1_unit.buf = 0; dev_busy = dev_busy & ~INT_TTO1; /* clear busy */ dev_done = dev_done & ~INT_TTO1; /* clear done, int */ @@ -299,3 +307,15 @@ if (val) tmxr_fconns (st, &tt1_ldsc, -1); else tmxr_fstats (st, &tt1_ldsc, -1); return SCPE_OK; } + +/* Enable/disable device */ + +void ttx1_enbdis (int32 dis) +{ +if (dis) { + tti1_dev.flags = tto1_dev.flags | DEV_DIS; + tto1_dev.flags = tto1_dev.flags | DEV_DIS; } +else { tti1_dev.flags = tti1_dev.flags & ~DEV_DIS; + tto1_dev.flags = tto1_dev.flags & ~DEV_DIS; } +return; +} diff --git a/PDP1/pdp1_cpu.c b/PDP1/pdp1_cpu.c index 3be08d24..aadb48a2 100644 --- a/PDP1/pdp1_cpu.c +++ b/PDP1/pdp1_cpu.c @@ -25,6 +25,8 @@ cpu PDP-1 central processor + 06-Oct-02 RMS Revised for V2.10 + 20-Aug-02 RMS Added DECtape support 30-Dec-01 RMS Added old PC queue 07-Dec-01 RMS Revised to use breakpoint package 30-Nov-01 RMS Added extended SET/SHOW support @@ -209,8 +211,8 @@ 4. Adding I/O devices. Three modules must be modified: pdp1_defs.h add interrupt request definition - pdp1_cpu.c add IOT dispatches - pdp1_sys.c add pointer to data structures to sim_devices + pdp1_cpu.c add IOT dispatch code + pdp1_sys.c add sim_devices table entry */ #include "pdp1_defs.h" @@ -218,9 +220,9 @@ #define PCQ_SIZE 64 /* must be 2**n */ #define PCQ_MASK (PCQ_SIZE - 1) #define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC -#define UNIT_V_MDV (UNIT_V_UF) /* mul/div */ +#define UNIT_V_MDV (UNIT_V_UF + 0) /* mul/div */ +#define UNIT_V_MSIZE (UNIT_V_UF + 1) /* dummy mask */ #define UNIT_MDV (1 << UNIT_V_MDV) -#define UNIT_V_MSIZE (UNIT_V_UF+1) /* dummy mask */ #define UNIT_MSIZE (1 << UNIT_V_MSIZE) int32 M[MAXMEMSIZE] = { 0 }; /* memory */ @@ -244,6 +246,7 @@ int32 ind_max = 16; /* nested ind limit */ uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ int32 pcq_p = 0; /* PC queue ptr */ REG *pcq_r = NULL; /* PC queue reg ptr */ + extern UNIT *sim_clock_queue; extern int32 sim_int_char; extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ @@ -252,12 +255,13 @@ t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); + extern int32 ptr (int32 inst, int32 dev, int32 IO); extern int32 ptp (int32 inst, int32 dev, int32 IO); extern int32 tti (int32 inst, int32 dev, int32 IO); extern int32 tto (int32 inst, int32 dev, int32 IO); extern int32 lpt (int32 inst, int32 dev, int32 IO); -extern t_stat sim_activate (UNIT *uptr, int32 delay); +extern int32 dt (int32 inst, int32 dev, int32 IO); int32 sc_map[512] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, /* 00000xxxx */ @@ -324,7 +328,6 @@ REG cpu_reg[] = { { FLDATA (STOP_INST, stop_inst, 0) }, { FLDATA (SBS_INIT, sbs_init, SB_V_ON) }, { FLDATA (EXTM_INIT, extm_init, 0) }, - { FLDATA (MDV, cpu_unit.flags, UNIT_V_MDV), REG_HRO }, { DRDATA (XCT_MAX, xct_max, 8), PV_LEFT + REG_NZ }, { DRDATA (IND_MAX, ind_max, 8), PV_LEFT + REG_NZ }, { ORDATA (WRU, sim_int_char, 8) }, @@ -349,7 +352,8 @@ DEVICE cpu_dev = { "CPU", &cpu_unit, cpu_reg, cpu_mod, 1, 8, ASIZE, 1, 8, 18, &cpu_ex, &cpu_dep, &cpu_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + NULL, 0 }; t_stat sim_instr (void) { @@ -691,7 +695,11 @@ case 035: switch (dev) { /* case on dev */ case 000: /* I/O wait */ break; - case 001: case 002: case 030: /* paper tape rdr */ + case 001: + if (IR & 003700) io_data = dt (IR, dev, IO); /* DECtape */ + else io_data = ptr (IR, dev, IO); /* paper tape rdr */ + break; + case 002: case 030: /* paper tape rdr */ io_data = ptr (IR, dev, IO); break; case 003: /* typewriter */ @@ -731,7 +739,7 @@ default: /* undefined */ reason = STOP_RSRV; /* halt */ break; } /* end switch opcode */ } /* end while */ -pcq_r -> qptr = pcq_p; /* update pc q ptr */ +pcq_r->qptr = pcq_p; /* update pc q ptr */ return reason; } @@ -745,7 +753,7 @@ ioh = ioc = 0; OV = 0; PF = 0; pcq_r = find_reg ("PCQ", NULL, dptr); -if (pcq_r) pcq_r -> qptr = 0; +if (pcq_r) pcq_r->qptr = 0; else return SCPE_IERR; sim_brk_types = sim_brk_dflt = SWMASK ('E'); return SCPE_OK; diff --git a/PDP1/pdp1_defs.h b/PDP1/pdp1_defs.h index 18c5b40f..5890abce 100644 --- a/PDP1/pdp1_defs.h +++ b/PDP1/pdp1_defs.h @@ -57,6 +57,7 @@ /* Architectural constants */ +#define DMASK 0777777 /* data mask */ #define DAMASK 007777 /* direct addr */ #define EPCMASK (AMASK & ~DAMASK) /* extended addr */ #define IA 010000 /* indirect flag */ diff --git a/PDP1/pdp1_doc.txt b/PDP1/pdp1_doc.txt index 786d4ce9..f28c0eb2 100644 --- a/PDP1/pdp1_doc.txt +++ b/PDP1/pdp1_doc.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik Subj: PDP-1 Simulator Usage -Date: 15-Jun-02 +Date: 15-Nov-2002 COPYRIGHT NOTICE @@ -37,12 +37,17 @@ This memorandum documents the PDP-1 simulator. 1. Simulator Files sim/ sim_defs.h + sim_rev.h + sim_sock.h + sim_tmxr.h scp.c scp_tty.c - sim_rev.c + sim_sock.c + sim_tmxr.c sim/pdp1/ pdp1_defs.h pdp1_cpu.c + pdp1_dt.c pdp1_lp.c pdp1_stddev.c pdp1_sys.c @@ -58,6 +63,7 @@ CPU PDP-1 CPU with up to 64KW of memory PTR,PTP integral paper tape reader/punch TTI,TTO Flexowriter typewriter input/output LPT Type 62 line printer +DT Type 550 Microtape (DECtape) The PDP-1 simulator implements the following unique stop conditions: @@ -212,6 +218,9 @@ The paper line printer (LPT) writes data to a disk file. The POS register specifies the number of the next data item to be written. Thus, by changing POS, the user can backspace or advance the printer. +The line printer can be disabled and enabled with the SET LPT DISABLED +and SET LPT ENABLED commands, respectively. + The line printer implements these registers: name size comments @@ -235,7 +244,64 @@ Error handling is as follows: OS I/O error x report error and stop -2.3 Symbolic Display and Input +2.3 Type 550/555 Microtape (DECtape) (DT) + +The PDP-1 used the Type 550 Microtape (later renamed DECtape), a programmed +I/O controller. PDP-1 DECtape format had 4 18b words in its block headers +and trailers. + +DECtapes drives are numbered 1-8; in the simulator, drive 8 is unit 0. +DECtape options include the ability to make units write enabled or write +locked. + + SET DTn WRITEENABLED set unit n write enabled + SET DTn LOCKED set unit n write locked + +Units can also be set ONLINE or OFFLINE. + +The DECtape controller can be disabled and enabled with the SET DT DISABLED +and SET DT ENABLED commands, respectively. + +The Type 550 supports PDP-8 format, PDP-11 format, and 18b format DECtape +images. ATTACH tries to determine the tape format from the DECtape image; +the user can force a particular format with switches: + + -r PDP-8 format + -s PDP-11 format + -t 18b format + +The DECtape controller is a data-only simulator; the timing and mark +track, and block header and trailer, are not stored. Thus, the WRITE +TIMING AND MARK TRACK function is not supported; the READ ALL function +always returns the hardware standard block header and trailer; and the +WRITE ALL function dumps non-data words into the bit bucket. + +The DECtape controller implements these registers: + + name size comments + + DTSA 12 status register A + DTSB 12 status register B + DTDB 18 data buffer + DTF 1 DECtape flag + BEF 1 block end flag + ERF 1 error flag + LTIME 31 time between lines + ACTIME 31 time to accelerate to full speed + DCTIME 31 time to decelerate to a full stop + SUBSTATE 2 read/write command substate + POS[0:7] 32 position, in lines, units 0-7 + STATT[0:7] 18 unit state, units 0-7 + +It is critically important to maintain certain timing relationships +among the DECtape parameters, or the DECtape simulator will fail to +operate correctly. + + - LTIME must be at least 6 + - ACTIME must be less than DCTIME, and both need to be at + least 100 times LTIME + +2.4 Symbolic Display and Input The PDP-1 simulator implements symbolic display and input. Display is controlled by command line switches: @@ -295,7 +361,7 @@ Finally, the LAW instruction has the format where immediate is in the range 0 to 07777. -2.4 Character Sets +2.5 Character Sets The PDP-1's console was a Frieden Flexowriter; its character encoding was known as FIODEC. The PDP-1's line printer used a modified Hollerith diff --git a/PDP1/pdp1_dt.c b/PDP1/pdp1_dt.c new file mode 100644 index 00000000..b7eb872d --- /dev/null +++ b/PDP1/pdp1_dt.c @@ -0,0 +1,976 @@ +/* pdp1_dt.c: 18b DECtape simulator + + Copyright (c) 1993-2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + dt Type 550/555 DECtape + + 17-Oct-02 RMS Fixed bug in end of reel logic + 06-Oct-02 RMS Added device disable support + 13-Aug-02 RMS Cloned from pdp18b_dt.c + + 18b DECtapes are represented in memory by fixed length buffer of 32b words. + Three file formats are supported: + + 18b/36b 256 words per block [256 x 18b] + 16b 256 words per block [256 x 16b] + 12b 129 words per block [129 x 12b] + + When a 16b or 12b DECtape file is read in, it is converted to 18b/36b format. + + DECtape motion is measured in 3b lines. Time between lines is 33.33us. + Tape density is nominally 300 lines per inch. The format of a DECtape is + + reverse end zone 36000 lines ~ 10 feet + block 0 + : + block n + forward end zone 36000 lines ~ 10 feet + + A block consists of five 18b header words, a tape-specific number of data + words, and five 18b trailer words. All systems except the PDP-8 use a + standard block length of 256 words; the PDP-8 uses a standard block length + of 86 words (x 18b = 129 words x 12b). [A PDP-1/4/7 DECtape has only four 18b + header words; for consistency, the PDP-1/4/7 uses the same format as the PDP-9/15 + but skips the missing header words.] + + Because a DECtape file only contains data, the simulator cannot support + write timing and mark track and can only do a limited implementation + of read all and write all. Read all assumes that the tape has been + conventionally written forward: + + header word 0 0 + header word 1 block number (for forward reads) + header words 2,3 0 + header word 4 0 + : + trailer word 4 checksum + trailer words 3,2 0 + trailer word 1 block number (for reverse reads) + trailer word 0 0 + + Write all writes only the data words and dumps the interblock words in the + bit bucket. + + The Type 550 controller has a 4b unit select field, for units 1-8; the TC02 + has a 3b unit select field, with unit 8 being represented as 0. The code + assumes that the GETUNIT macro returns a unit number in the range of 0-7, + with 8 represented as 0, and an invalid unit as -1. +*/ + +#include "pdp1_defs.h" + +#define DT_NUMDR 8 /* #drives */ +#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_V_8FMT (UNIT_V_UF + 1) /* 12b format */ +#define UNIT_V_11FMT (UNIT_V_UF + 2) /* 16b format */ +#define UNIT_WLK (1 << UNIT_V_WLK) +#define UNIT_8FMT (1 << UNIT_V_8FMT) +#define UNIT_11FMT (1 << UNIT_V_11FMT) +#define STATE u3 /* unit state */ +#define LASTT u4 /* last time update */ +#define DT_WC 030 /* word count */ +#define DT_CA 031 /* current addr */ +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ + +/* System independent DECtape constants */ + +#define DT_EZLIN 36000 /* end zone length */ +#define DT_HTLIN 30 /* header/trailer lines */ +#define DT_BLKLN 6 /* blk no line in h/t */ +#define DT_CSMLN 24 /* checksum line in h/t */ +#define DT_HTWRD (DT_HTLIN / DT_WSIZE) /* header/trailer words */ +#define DT_BLKWD (DT_BLKLN / DT_WSIZE) /* blk no word in h/t */ +#define DT_CSMWD (DT_CSMLN / DT_WSIZE) /* checksum word in h/t */ + +/* 16b, 18b, 36b DECtape constants */ + +#define D18_WSIZE 6 /* word size in lines */ +#define D18_BSIZE 256 /* block size in 18b */ +#define D18_TSIZE 578 /* tape size */ +#define D18_LPERB (DT_HTLIN + (D18_BSIZE * DT_WSIZE) + DT_HTLIN) +#define D18_FWDEZ (DT_EZLIN + (D18_LPERB * D18_TSIZE)) +#define D18_CAPAC (D18_TSIZE * D18_BSIZE) /* tape capacity */ +#define D11_FILSIZ (D18_CAPAC * sizeof (int16)) + +/* 12b DECtape constants */ + +#define D8_WSIZE 4 /* word size in lines */ +#define D8_BSIZE 86 /* block size in 18b */ +#define D8_TSIZE 1474 /* tape size */ +#define D8_LPERB (DT_HTLIN + (D8_BSIZE * DT_WSIZE) + DT_HTLIN) +#define D8_FWDEZ (DT_EZLIN + (D8_LPERB * D8_TSIZE)) +#define D8_CAPAC (D8_TSIZE * D8_BSIZE) /* tape capacity */ + +#define D8_NBSIZE ((D8_BSIZE * D18_WSIZE) / D8_WSIZE) +#define D8_FILSIZ (D8_NBSIZE * D8_TSIZE * sizeof (int16)) + +/* This controller */ + +#define DT_CAPAC D18_CAPAC /* default */ +#define DT_WSIZE D18_WSIZE + +/* Calculated constants, per unit */ + +#define DTU_BSIZE(u) (((u)->flags & UNIT_8FMT)? D8_BSIZE: D18_BSIZE) +#define DTU_TSIZE(u) (((u)->flags & UNIT_8FMT)? D8_TSIZE: D18_TSIZE) +#define DTU_LPERB(u) (((u)->flags & UNIT_8FMT)? D8_LPERB: D18_LPERB) +#define DTU_FWDEZ(u) (((u)->flags & UNIT_8FMT)? D8_FWDEZ: D18_FWDEZ) +#define DTU_CAPAC(u) (((u)->flags & UNIT_8FMT)? D8_CAPAC: D18_CAPAC) + +#define DT_LIN2BL(p,u) (((p) - DT_EZLIN) / DTU_LPERB (u)) +#define DT_LIN2OF(p,u) (((p) - DT_EZLIN) % DTU_LPERB (u)) +#define DT_LIN2WD(p,u) ((DT_LIN2OF (p,u) - DT_HTLIN) / DT_WSIZE) +#define DT_BLK2LN(p,u) (((p) * DTU_LPERB (u)) + DT_EZLIN) +#define DT_QREZ(u) (((u)->pos) < DT_EZLIN) +#define DT_QFEZ(u) (((u)->pos) >= ((uint32) DTU_FWDEZ (u))) +#define DT_QEZ(u) (DT_QREZ (u) || DT_QFEZ (u)) + +/* Status register A */ + +#define DTA_V_UNIT 12 /* unit select */ +#define DTA_M_UNIT 017 +#define DTA_UNIT (DTA_M_UNIT << DTA_V_UNIT) +#define DTA_V_MOT 4 /* motion */ +#define DTA_M_MOT 03 +#define DTA_V_FNC 0 /* function */ +#define DTA_M_FNC 07 +#define FNC_MOVE 00 /* move */ +#define FNC_SRCH 01 /* search */ +#define FNC_READ 02 /* read */ +#define FNC_WRIT 03 /* write */ +#define FNC_RALL 05 /* read all */ +#define FNC_WALL 06 /* write all */ +#define FNC_WMRK 07 /* write timing */ +#define DTA_STSTP (1u << (DTA_V_MOT + 1)) +#define DTA_FWDRV (1u << DTA_V_MOT) +#define DTA_MODE 0 /* not implemented */ +#define DTA_RW 077 +#define DTA_GETUNIT(x) map_unit[(((x) >> DTA_V_UNIT) & DTA_M_UNIT)] +#define DT_UPDINT if (dtsb & (DTB_DTF | DTB_BEF | DTB_ERF)) \ + sbs = sbs | SB_RQ; + +#define DTA_GETMOT(x) (((x) >> DTA_V_MOT) & DTA_M_MOT) +#define DTA_GETFNC(x) (((x) >> DTA_V_FNC) & DTA_M_FNC) + +/* Status register B */ + +#define DTB_V_DTF 17 /* data flag */ +#define DTB_V_BEF 16 /* block end flag */ +#define DTB_V_ERF 15 /* error flag */ +#define DTB_V_END 14 /* end of tape */ +#define DTB_V_TIM 13 /* timing err */ +#define DTB_V_REV 12 /* reverse */ +#define DTB_V_GO 11 /* go */ +#define DTB_V_MRK 10 /* mark trk err */ +#define DTB_V_SEL 9 /* select err */ +#define DTB_DTF (1u << DTB_V_DTF) +#define DTB_BEF (1u << DTB_V_BEF) +#define DTB_ERF (1u << DTB_V_ERF) +#define DTB_END (1u << DTB_V_END) +#define DTB_TIM (1u << DTB_V_TIM) +#define DTB_REV (1u << DTB_V_REV) +#define DTB_GO (1u << DTB_V_GO) +#define DTB_MRK (1u << DTB_V_MRK) +#define DTB_SEL (1u << DTB_V_SEL) +#define DTB_ALLERR (DTB_END | DTB_TIM | DTB_MRK | DTB_SEL) + +/* DECtape state */ + +#define DTS_V_MOT 3 /* motion */ +#define DTS_M_MOT 07 +#define DTS_STOP 0 /* stopped */ +#define DTS_DECF 2 /* decel, fwd */ +#define DTS_DECR 3 /* decel, rev */ +#define DTS_ACCF 4 /* accel, fwd */ +#define DTS_ACCR 5 /* accel, rev */ +#define DTS_ATSF 6 /* @speed, fwd */ +#define DTS_ATSR 7 /* @speed, rev */ +#define DTS_DIR 01 /* dir mask */ +#define DTS_V_FNC 0 /* function */ +#define DTS_M_FNC 07 +#define DTS_OFR 7 /* "off reel" */ +#define DTS_GETMOT(x) (((x) >> DTS_V_MOT) & DTS_M_MOT) +#define DTS_GETFNC(x) (((x) >> DTS_V_FNC) & DTS_M_FNC) +#define DTS_V_2ND 6 /* next state */ +#define DTS_V_3RD (DTS_V_2ND + DTS_V_2ND) /* next next */ +#define DTS_STA(y,z) (((y) << DTS_V_MOT) | ((z) << DTS_V_FNC)) +#define DTS_SETSTA(y,z) uptr->STATE = DTS_STA (y, z) +#define DTS_SET2ND(y,z) uptr->STATE = (uptr->STATE & 077) | \ + ((DTS_STA (y, z)) << DTS_V_2ND) +#define DTS_SET3RD(y,z) uptr->STATE = (uptr->STATE & 07777) | \ + ((DTS_STA (y, z)) << DTS_V_3RD) +#define DTS_NXTSTA(x) (x >> DTS_V_2ND) + +/* Operation substates */ + +#define DTO_WCO 1 /* wc overflow */ +#define DTO_SOB 2 /* start of block */ + +/* Logging */ + +#define LOG_MS 001 /* move, search */ +#define LOG_RW 002 /* read, write */ +#define LOG_RA 004 /* read all */ +#define LOG_BL 010 /* block # lblk */ + +#define ABS(x) (((x) < 0)? (-(x)): (x)) + +extern int32 M[]; +extern int32 sbs; +extern int32 stop_inst; +extern UNIT cpu_unit; +extern int32 sim_switches; +extern int32 sim_is_running; + +int32 dtsa = 0; /* status A */ +int32 dtsb = 0; /* status B */ +int32 dtdb = 0; /* data buffer */ +int32 dt_ltime = 12; /* interline time */ +int32 dt_actime = 54000; /* accel time */ +int32 dt_dctime = 72000; /* decel time */ +int32 dt_substate = 0; +int32 dt_log = 0; +int32 dt_logblk = 0; +static const int32 map_unit[16] = { /* Type 550 unit map */ + -1, 1, 2, 3, 4, 5, 6, 7, + 0, -1, -1, -1, -1, -1, -1, -1 }; + +t_stat dt_svc (UNIT *uptr); +t_stat dt_reset (DEVICE *dptr); +t_stat dt_attach (UNIT *uptr, char *cptr); +t_stat dt_detach (UNIT *uptr); +void dt_deselect (int32 oldf); +void dt_newsa (int32 newf); +void dt_newfnc (UNIT *uptr, int32 newsta); +t_bool dt_setpos (UNIT *uptr); +void dt_schedez (UNIT *uptr, int32 dir); +void dt_seterr (UNIT *uptr, int32 e); +int32 dt_comobv (int32 val); +int32 dt_csum (UNIT *uptr, int32 blk); +int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos); + +/* DT data structures + + dt_dev DT device descriptor + dt_unit DT unit list + dt_reg DT register list + dt_mod DT modifier list +*/ + +UNIT dt_unit[] = { + { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, DT_CAPAC) } }; + +REG dt_reg[] = { + { ORDATA (DTSA, dtsa, 18) }, + { ORDATA (DTSB, dtsb, 18) }, + { ORDATA (DTDB, dtdb, 18) }, + { FLDATA (DTF, dtsb, DTB_V_DTF) }, + { FLDATA (BEF, dtsb, DTB_V_BEF) }, + { FLDATA (ERF, dtsb, DTB_V_ERF) }, + { DRDATA (LTIME, dt_ltime, 31), REG_NZ }, + { DRDATA (ACTIME, dt_actime, 31), REG_NZ }, + { DRDATA (DCTIME, dt_dctime, 31), REG_NZ }, + { ORDATA (SUBSTATE, dt_substate, 2) }, + { ORDATA (LOG, dt_log, 4), REG_HIDDEN }, + { DRDATA (LBLK, dt_logblk, 12), REG_HIDDEN }, + { URDATA (POS, dt_unit[0].pos, 10, 32, 0, + DT_NUMDR, PV_LEFT | REG_RO) }, + { URDATA (STATT, dt_unit[0].STATE, 8, 18, 0, + DT_NUMDR, REG_RO) }, + { URDATA (LASTT, dt_unit[0].LASTT, 10, 32, 0, + DT_NUMDR, REG_HRO) }, + { NULL } }; + +MTAB dt_mod[] = { + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, + { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, + { UNIT_8FMT + UNIT_11FMT, 0, "18b", NULL, NULL }, + { UNIT_8FMT + UNIT_11FMT, UNIT_8FMT, "12b", NULL, NULL }, + { UNIT_8FMT + UNIT_11FMT, UNIT_11FMT, "16b", NULL, NULL }, + { 0 } }; + +DEVICE dt_dev = { + "DT", dt_unit, dt_reg, dt_mod, + DT_NUMDR, 8, 24, 1, 8, 18, + NULL, NULL, &dt_reset, + NULL, &dt_attach, &dt_detach, + NULL, DEV_DISABLE }; + +int32 dt (int32 IR, int32 dev, int32 IO) +{ +int32 pulse = (IR >> 6) & 037; +int32 fnc, mot, unum; +UNIT *uptr = NULL; + +if (dt_dev.flags & DEV_DIS) /* disabled? */ + return (stop_inst << IOT_V_REASON) | IO; /* stop if requested */ +unum = DTA_GETUNIT (dtsa); /* get unit no */ +if (unum >= 0) uptr = dt_dev.units + unum; /* get unit */ + +if (pulse == 003) { /* MSE */ + if ((dtsa ^ IO) & DTA_UNIT) dt_deselect (dtsa); /* new unit? */ + dtsa = (dtsa & ~DTA_UNIT) | (IO & DTA_UNIT); + dtsb = dtsb & ~(DTB_DTF | DTB_BEF | DTB_ERF | DTB_ALLERR); } +if (pulse == 004) { /* MLC */ + dtsa = (dtsa & ~DTA_RW) | (IO & DTA_RW); /* load dtsa */ + dtsb = dtsb & ~(DTB_DTF | DTB_BEF | DTB_ERF | DTB_ALLERR); + fnc = DTA_GETFNC (dtsa); /* get fnc */ + if ((uptr == NULL) || /* invalid? */ + ((uptr->flags) & UNIT_DIS) || /* disabled? */ + (fnc >= FNC_WMRK) || /* write mark? */ + ((fnc == FNC_WRIT) && (uptr->flags & UNIT_WLK)) || + ((fnc == FNC_WALL) && (uptr->flags & UNIT_WLK))) + dt_seterr (uptr, DTB_SEL); /* select err */ + else dt_newsa (dtsa); } +if (pulse == 005) { /* MRD */ + IO = (IO & ~DMASK) | dtdb; + dtsb = dtsb & ~(DTB_DTF | DTB_BEF); } +if (pulse == 006) { /* MWR */ + dtdb = IO & DMASK; + dtsb = dtsb & ~(DTB_DTF | DTB_BEF); } +if (pulse == 007) { /* MRS */ + dtsb = dtsb & ~(DTB_REV | DTB_GO); /* clr rev, go */ + if (uptr) { /* valid unit? */ + mot = DTS_GETMOT (uptr->STATE); /* get motion */ + if (mot & DTS_DIR) dtsb = dtsb | DTB_REV; /* rev? set */ + if ((mot >= DTS_ACCF) || (uptr->STATE & 0777700)) + dtsb = dtsb | DTB_GO; } /* accel? go */ + IO = (IO & ~DMASK) | dtsb; } +DT_UPDINT; +return IO; +} + +/* Unit deselect */ + +void dt_deselect (int32 oldf) +{ +int32 old_unit, old_mot; +UNIT *uptr; + +old_unit = DTA_GETUNIT (oldf); /* get unit no */ +if (old_unit < 0) return; /* invalid? */ +uptr = dt_dev.units + old_unit; /* get unit */ +old_mot = DTS_GETMOT (uptr->STATE); +if (old_mot >= DTS_ATSF) /* at speed? */ + dt_newfnc (uptr, DTS_STA (old_mot, DTS_OFR)); +else if (old_mot >= DTS_ACCF) /* accelerating? */ + DTS_SET2ND (DTS_ATSF | (old_mot & DTS_DIR), DTS_OFR); +return; +} + +/* Command register change + + 1. If change in motion, stop to start + - schedule acceleration + - set function as next state + 2. If change in motion, start to stop + - if not already decelerating (could be reversing), + schedule deceleration + 3. If change in direction, + - if not decelerating, schedule deceleration + - set accelerating (other dir) as next state + - set function as next next state + 4. If not accelerating or at speed, + - schedule acceleration + - set function as next state + 5. If not yet at speed, + - set function as next state + 6. If at speed, + - set function as current state, schedule function +*/ + +void dt_newsa (int32 newf) +{ +int32 new_unit, prev_mot, new_fnc; +int32 prev_mving, new_mving, prev_dir, new_dir; +UNIT *uptr; + +new_unit = DTA_GETUNIT (newf); /* new unit */ +if (new_unit < 0) return; /* invalid? */ +uptr = dt_dev.units + new_unit; +if ((uptr->flags & UNIT_ATT) == 0) { /* new unit attached? */ + dt_seterr (uptr, DTB_SEL); /* no, error */ + return; } +prev_mot = DTS_GETMOT (uptr->STATE); /* previous motion */ +prev_mving = prev_mot != DTS_STOP; /* previous moving? */ +prev_dir = prev_mot & DTS_DIR; /* previous dir? */ +new_mving = (newf & DTA_STSTP) != 0; /* new moving? */ +new_dir = (newf & DTA_FWDRV) != 0; /* new dir? */ +new_fnc = DTA_GETFNC (newf); /* new function? */ + +if ((prev_mving | new_mving) == 0) return; /* stop to stop */ + +if (new_mving & ~prev_mving) { /* start? */ + if (dt_setpos (uptr)) return; /* update pos */ + sim_cancel (uptr); /* stop current */ + sim_activate (uptr, dt_actime); /* schedule accel */ + DTS_SETSTA (DTS_ACCF | new_dir, 0); /* state = accel */ + DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */ + return; } + +if (prev_mving & ~new_mving) { /* stop? */ + if ((prev_mot & ~DTS_DIR) != DTS_DECF) { /* !already stopping? */ + if (dt_setpos (uptr)) return; /* update pos */ + sim_cancel (uptr); /* stop current */ + sim_activate (uptr, dt_dctime); } /* schedule decel */ + DTS_SETSTA (DTS_DECF | prev_dir, 0); /* state = decel */ + return; } + +if (prev_dir ^ new_dir) { /* dir chg? */ + if ((prev_mot & ~DTS_DIR) != DTS_DECF) { /* !already stopping? */ + if (dt_setpos (uptr)) return; /* update pos */ + sim_cancel (uptr); /* stop current */ + sim_activate (uptr, dt_dctime); } /* schedule decel */ + DTS_SETSTA (DTS_DECF | prev_dir, 0); /* state = decel */ + DTS_SET2ND (DTS_ACCF | new_dir, 0); /* next = accel */ + DTS_SET3RD (DTS_ATSF | new_dir, new_fnc); /* next next = fnc */ + return; } + +if (prev_mot < DTS_ACCF) { /* not accel/at speed? */ + if (dt_setpos (uptr)) return; /* update pos */ + sim_cancel (uptr); /* cancel cur */ + sim_activate (uptr, dt_actime); /* schedule accel */ + DTS_SETSTA (DTS_ACCF | new_dir, 0); /* state = accel */ + DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */ + return; } + +if (prev_mot < DTS_ATSF) { /* not at speed? */ + DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */ + return; } + +dt_newfnc (uptr, DTS_STA (DTS_ATSF | new_dir, new_fnc));/* state = fnc */ +return; +} + +/* Schedule new DECtape function + + This routine is only called if + - the selected unit is attached + - the selected unit is at speed (forward or backward) + + This routine + - updates the selected unit's position + - updates the selected unit's state + - schedules the new operation +*/ + +void dt_newfnc (UNIT *uptr, int32 newsta) +{ +int32 fnc, dir, blk, unum, newpos; +uint32 oldpos; + +oldpos = uptr->pos; /* save old pos */ +if (dt_setpos (uptr)) return; /* update pos */ +uptr->STATE = newsta; /* update state */ +fnc = DTS_GETFNC (uptr->STATE); /* set variables */ +dir = DTS_GETMOT (uptr->STATE) & DTS_DIR; +unum = uptr - dt_dev.units; +if (oldpos == uptr->pos) /* bump pos */ + uptr->pos = uptr->pos + (dir? -1: 1); +blk = DT_LIN2BL (uptr->pos, uptr); + +if (dir? DT_QREZ (uptr): DT_QFEZ (uptr)) { /* wrong ez? */ + dt_seterr (uptr, DTB_END); /* set ez flag, stop */ + return; } +sim_cancel (uptr); /* cancel cur op */ +dt_substate = DTO_SOB; /* substate = block start */ +switch (fnc) { /* case function */ +case DTS_OFR: /* off reel */ + if (dir) newpos = -1000; /* rev? < start */ + else newpos = DTU_FWDEZ (uptr) + DT_EZLIN + 1000; /* fwd? > end */ + break; +case FNC_MOVE: /* move */ + dt_schedez (uptr, dir); /* sched end zone */ + if (dt_log & LOG_MS) printf ("[DT%d: moving %s]\n", unum, (dir? + "backward": "forward")); + return; /* done */ +case FNC_SRCH: /* search */ + if (dir) newpos = DT_BLK2LN ((DT_QFEZ (uptr)? + DTU_TSIZE (uptr): blk), uptr) - DT_BLKLN - DT_WSIZE; + else newpos = DT_BLK2LN ((DT_QREZ (uptr)? + 0: blk + 1), uptr) + DT_BLKLN + (DT_WSIZE - 1); + if (dt_log & LOG_MS) printf ("[DT%d: searching %s]\n", unum, + (dir? "backward": "forward")); + break; +case FNC_WRIT: /* write */ +case FNC_READ: /* read */ +case FNC_RALL: /* read all */ +case FNC_WALL: /* write all */ + if (DT_QEZ (uptr)) { /* in "ok" end zone? */ + if (dir) newpos = DTU_FWDEZ (uptr) - DT_WSIZE; + else newpos = DT_EZLIN + (DT_WSIZE - 1); } + else { newpos = ((uptr->pos) / DT_WSIZE) * DT_WSIZE; + if (!dir) newpos = newpos + (DT_WSIZE - 1); } + if ((dt_log & LOG_RA) || ((dt_log & LOG_BL) && (blk == dt_logblk))) + printf ("[DT%d: read all block %d %s%s\n", + unum, blk, (dir? "backward": "forward"), + ((dtsa & DTA_MODE)? " continuous]": "]")); + break; +default: + dt_seterr (uptr, DTB_SEL); /* bad state */ + return; } +if ((fnc == FNC_WRIT) || (fnc == FNC_WALL)) { /* write function? */ + dtsb = dtsb | DTB_DTF; /* set data flag */ + DT_UPDINT; } +sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime); +return; +} + +/* Update DECtape position + + DECtape motion is modeled as a constant velocity, with linear + acceleration and deceleration. The motion equations are as follows: + + t = time since operation started + tmax = time for operation (accel, decel only) + v = at speed velocity in lines (= 1/dt_ltime) + + Then: + at speed dist = t * v + accel dist = (t^2 * v) / (2 * tmax) + decel dist = (((2 * t * tmax) - t^2) * v) / (2 * tmax) + + This routine uses the relative (integer) time, rather than the absolute + (floating point) time, to allow save and restore of the start times. +*/ + +t_bool dt_setpos (UNIT *uptr) +{ +uint32 new_time, ut, ulin, udelt; +int32 mot = DTS_GETMOT (uptr->STATE); +int32 unum, delta; + +new_time = sim_grtime (); /* current time */ +ut = new_time - uptr->LASTT; /* elapsed time */ +if (ut == 0) return FALSE; /* no time gone? exit */ +uptr->LASTT = new_time; /* update last time */ +switch (mot & ~DTS_DIR) { /* case on motion */ +case DTS_STOP: /* stop */ + delta = 0; + break; +case DTS_DECF: /* slowing */ + ulin = ut / (uint32) dt_ltime; udelt = dt_dctime / dt_ltime; + delta = ((ulin * udelt * 2) - (ulin * ulin)) / (2 * udelt); + break; +case DTS_ACCF: /* accelerating */ + ulin = ut / (uint32) dt_ltime; udelt = dt_actime / dt_ltime; + delta = (ulin * ulin) / (2 * udelt); + break; +case DTS_ATSF: /* at speed */ + delta = ut / (uint32) dt_ltime; + break; } +if (mot & DTS_DIR) uptr->pos = uptr->pos - delta; /* update pos */ +else uptr->pos = uptr->pos + delta; +if (((int32) uptr->pos < 0) || + ((int32) uptr->pos > (DTU_FWDEZ (uptr) + DT_EZLIN))) { + detach_unit (uptr); /* off reel? */ + uptr->STATE = uptr->pos = 0; + unum = uptr - dt_dev.units; + if (unum == DTA_GETUNIT (dtsa)) /* if selected, */ + dt_seterr (uptr, DTB_SEL); /* error */ + return TRUE; } +return FALSE; +} + +/* Unit service + + Unit must be attached, detach cancels operation +*/ + +t_stat dt_svc (UNIT *uptr) +{ +int32 mot = DTS_GETMOT (uptr->STATE); +int32 dir = mot & DTS_DIR; +int32 fnc = DTS_GETFNC (uptr->STATE); +int32 *bptr = uptr->filebuf; +int32 unum = uptr - dt_dev.units; +int32 blk, wrd, ma, relpos; +t_addr ba; + +/* Motion cases + + Decelerating - if next state != stopped, must be accel reverse + Accelerating - next state must be @speed, schedule function + At speed - do functional processing +*/ + +switch (mot) { +case DTS_DECF: case DTS_DECR: /* decelerating */ + if (dt_setpos (uptr)) return SCPE_OK; /* update pos */ + uptr->STATE = DTS_NXTSTA (uptr->STATE); /* advance state */ + if (uptr->STATE) /* not stopped? */ + sim_activate (uptr, dt_actime); /* must be reversing */ + return SCPE_OK; +case DTS_ACCF: case DTS_ACCR: /* accelerating */ + dt_newfnc (uptr, DTS_NXTSTA (uptr->STATE)); /* adv state, sched */ + return SCPE_OK; +case DTS_ATSF: case DTS_ATSR: /* at speed */ + break; /* check function */ +default: /* other */ + dt_seterr (uptr, DTB_SEL); /* state error */ + return SCPE_OK; } + +/* Functional cases + + Move - must be at end zone + Search - transfer block number, schedule next block + Off reel - detach unit (it must be deselected) +*/ + +if (dt_setpos (uptr)) return SCPE_OK; /* update pos */ +if (DT_QEZ (uptr)) { /* in end zone? */ + dt_seterr (uptr, DTB_END); /* end zone error */ + return SCPE_OK; } +blk = DT_LIN2BL (uptr->pos, uptr); /* get block # */ +switch (fnc) { /* at speed, check fnc */ +case FNC_MOVE: /* move */ + dt_seterr (uptr, DTB_END); /* end zone error */ + return SCPE_OK; +case DTS_OFR: /* off reel */ + detach_unit (uptr); /* must be deselected */ + uptr->STATE = uptr->pos = 0; /* no visible action */ + break; + +/* Search */ + +case FNC_SRCH: /* search */ + if (dtsb & DTB_DTF) { /* DTF set? */ + dt_seterr (uptr, DTB_TIM); /* timing error */ + return SCPE_OK; } + sim_activate (uptr, DTU_LPERB (uptr) * dt_ltime);/* sched next block */ + dtdb = blk; /* store block # */ + dtsb = dtsb | DTB_DTF; /* set DTF */ + break; + +/* Read and read all */ + +case FNC_READ: case FNC_RALL: + if (dtsb & DTB_DTF) { /* DTF set? */ + dt_seterr (uptr, DTB_TIM); /* timing error */ + return SCPE_OK; } + sim_activate (uptr, DT_WSIZE * dt_ltime); /* sched next word */ + relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ + if ((relpos >= DT_HTLIN) && /* in data zone? */ + (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { + wrd = DT_LIN2WD (uptr->pos, uptr); + ba = (blk * DTU_BSIZE (uptr)) + wrd; + dtdb = bptr[ba]; /* get tape word */ + dtsb = dtsb | DTB_DTF; } /* set flag */ + else { ma = (2 * DT_HTWRD) + DTU_BSIZE (uptr) - DT_CSMWD - 1; + wrd = relpos / DT_WSIZE; /* hdr start = wd 0 */ + if ((wrd == 0) || /* skip 1st, last */ + (wrd == ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - 1))) break; + if ((fnc == FNC_READ) && /* read, skip if not */ + (wrd != DT_CSMWD) && /* fwd, rev cksum */ + (wrd != ma)) break; + dtdb = dt_gethdr (uptr, blk, relpos); + if (wrd == (dir? DT_CSMWD: ma)) /* at end csum? */ + dtsb = dtsb | DTB_BEF; /* end block */ + else dtsb = dtsb | DTB_DTF; } /* else next word */ + if (dir) dtdb = dt_comobv (dtdb); + break; + +/* Write and write all */ + +case FNC_WRIT: case FNC_WALL: + if (dtsb & DTB_DTF) { /* DTF set? */ + dt_seterr (uptr, DTB_TIM); /* timing error */ + return SCPE_OK; } + sim_activate (uptr, DT_WSIZE * dt_ltime); /* sched next word */ + relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ + if ((relpos >= DT_HTLIN) && /* in data zone? */ + (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { + wrd = DT_LIN2WD (uptr->pos, uptr); + ba = (blk * DTU_BSIZE (uptr)) + wrd; + if (dir) bptr[ba] = dt_comobv (dtdb); /* get data word */ + else bptr[ba] = dtdb; + if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; + if (wrd == (dir? 0: DTU_BSIZE (uptr) - 1)) + dtsb = dtsb | DTB_BEF; /* end block */ + else dtsb = dtsb | DTB_DTF; } /* else next word */ + else { wrd = relpos / DT_WSIZE; /* hdr start = wd 0 */ + if ((wrd == 0) || /* skip 1st, last */ + (wrd == ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - 1))) break; + if ((fnc == FNC_WRIT) && /* wr, skip if !csm */ + (wrd != ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - DT_CSMWD - 1))) + break; + dtsb = dtsb | DTB_DTF; } /* set flag */ + break; + +default: + dt_seterr (uptr, DTB_SEL); /* impossible state */ + break; } +DT_UPDINT; /* update interrupts */ +return SCPE_OK; +} + +/* Utility routines */ + +/* Set error flag */ + +void dt_seterr (UNIT *uptr, int32 e) +{ +int32 mot = DTS_GETMOT (uptr->STATE); + +dtsa = dtsa & ~DTA_STSTP; /* clear go */ +dtsb = dtsb | DTB_ERF | e; /* set error flag */ +if (mot >= DTS_ACCF) { /* ~stopped or stopping? */ + sim_cancel (uptr); /* cancel activity */ + if (dt_setpos (uptr)) return; /* update position */ + sim_activate (uptr, dt_dctime); /* sched decel */ + DTS_SETSTA (DTS_DECF | (mot & DTS_DIR), 0); } /* state = decel */ +DT_UPDINT; +return; +} + +/* Schedule end zone */ + +void dt_schedez (UNIT *uptr, int32 dir) +{ +int32 newpos; + +if (dir) newpos = DT_EZLIN - DT_WSIZE; /* rev? rev ez */ +else newpos = DTU_FWDEZ (uptr) + DT_WSIZE; /* fwd? fwd ez */ +sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime); +return; +} + +/* Complement obverse routine */ + +int32 dt_comobv (int32 dat) +{ +dat = dat ^ 0777777; /* compl obverse */ +dat = ((dat >> 15) & 07) | ((dat >> 9) & 070) | + ((dat >> 3) & 0700) | ((dat & 0700) << 3) | + ((dat & 070) << 9) | ((dat & 07) << 15); +return dat; +} + +/* Checksum routine */ + +int32 dt_csum (UNIT *uptr, int32 blk) +{ +int32 *bptr = uptr->filebuf; +int32 ba = blk * DTU_BSIZE (uptr); +int32 i, csum, wrd; + +csum = 0777777; +for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */ + wrd = bptr[ba + i]; /* get word */ + csum = csum + wrd; /* 1's comp add */ + if (csum > 0777777) csum = (csum + 1) & 0777777; } +return (csum ^ 0777777); /* 1's comp res */ +} + +/* Get header word */ + +int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos) +{ +int32 wrd = relpos / DT_WSIZE; + +if (wrd == DT_BLKWD) return blk; /* fwd blknum */ +if (wrd == DT_CSMWD) return 0777777; /* rev csum */ +if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_CSMWD - 1)) /* fwd csum */ + return (dt_csum (uptr, blk)); +if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_BLKWD - 1)) /* rev blkno */ + return dt_comobv (blk); +return 0; /* all others */ +} + +/* Reset routine */ + +t_stat dt_reset (DEVICE *dptr) +{ +int32 i, prev_mot; +UNIT *uptr; + +for (i = 0; i < DT_NUMDR; i++) { /* stop all drives */ + uptr = dt_dev.units + i; + if (sim_is_running) { /* CAF? */ + prev_mot = DTS_GETMOT (uptr->STATE); /* get motion */ + if ((prev_mot & ~DTS_DIR) > DTS_DECF) { /* accel or spd? */ + if (dt_setpos (uptr)) continue; /* update pos */ + sim_cancel (uptr); + sim_activate (uptr, dt_dctime); /* sched decel */ + DTS_SETSTA (DTS_DECF | (prev_mot & DTS_DIR), 0); + } } + else { sim_cancel (uptr); /* sim reset */ + uptr->STATE = 0; + uptr->LASTT = sim_grtime (); } } +dtsa = dtsb = 0; /* clear status */ +DT_UPDINT; /* reset interrupt */ +return SCPE_OK; +} + +/* IORS routine */ + +int32 dt_iors (void) +{ +#if defined IOS_DTA +return ((dtsb & (DTB_ERF | DTB_DTF))? IOS_DTA: 0); +#else +return 0; +#endif +} + +/* Attach routine + + Determine 12b, 16b, or 18b/36b format + Allocate buffer + If 12b, read 12b format and convert to 18b in buffer + If 16b, read 16b format and convert to 18b in buffer + If 18b/36b, read data into buffer +*/ + +t_stat dt_attach (UNIT *uptr, char *cptr) +{ +uint16 pdp8b[D8_NBSIZE]; +uint16 pdp11b[D18_BSIZE]; +uint32 k, p, *bptr; +t_stat r; +t_addr ba; + +r = attach_unit (uptr, cptr); /* attach */ +if (r != SCPE_OK) return r; /* error? */ +uptr->flags = uptr->flags & ~(UNIT_8FMT | UNIT_11FMT); /* default 18b */ +if (sim_switches & SWMASK ('R')) /* att 12b? */ + uptr->flags = uptr->flags | UNIT_8FMT; +else if (sim_switches & SWMASK ('S')) /* att 16b? */ + uptr->flags = uptr->flags | UNIT_11FMT; +else if (!(sim_switches & SWMASK ('T')) && /* autosize? */ + (fseek (uptr->fileref, 0, SEEK_END) == 0) && + ((p = ftell (uptr->fileref)) != 0)) { + if (p == D8_FILSIZ) uptr->flags = uptr->flags | UNIT_8FMT; + if (p == D11_FILSIZ) uptr->flags = uptr->flags | UNIT_11FMT; } +uptr->capac = DTU_CAPAC (uptr); /* set capacity */ +uptr->filebuf = calloc (uptr->capac, sizeof (int32)); +if (uptr->filebuf == NULL) { /* can't alloc? */ + detach_unit (uptr); + return SCPE_MEM; } +bptr = uptr->filebuf; /* file buffer */ +if (uptr->flags & UNIT_8FMT) printf ("DT: 12b format"); +else if (uptr->flags & UNIT_11FMT) printf ("DT: 16b format"); +else printf ("DT: 18b/36b format"); +printf (", buffering file in memory\n"); +rewind (uptr->fileref); /* start of file */ +if (uptr->flags & UNIT_8FMT) { /* 12b? */ + for (ba = 0; ba < uptr->capac; ) { /* loop thru file */ + k = fxread (pdp8b, sizeof (int16), D8_NBSIZE, uptr->fileref); + if (k == 0) break; + for ( ; k < D8_NBSIZE; k++) pdp8b[k] = 0; + for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop thru blk */ + bptr[ba] = ((uint32) (pdp8b[k] & 07777) << 6) | + ((uint32) (pdp8b[k + 1] >> 6) & 077); + bptr[ba + 1] = ((uint32) (pdp8b[k + 1] & 077) << 12) | + (pdp8b[k + 2] & 07777); + ba = ba + 2; } /* end blk loop */ + } /* end file loop */ + uptr->hwmark = ba; } /* end if */ +else if (uptr->flags & UNIT_11FMT) { /* 16b? */ + for (ba = 0; ba < uptr->capac; ) { /* loop thru file */ + k = fxread (pdp11b, sizeof (int16), D18_BSIZE, uptr->fileref); + if (k == 0) break; + for ( ; k < D18_BSIZE; k++) pdp11b[k] = 0; + for (k = 0; k < D18_BSIZE; k++) + bptr[ba++] = pdp11b[k]; } + uptr->hwmark = ba; } /* end elif */ +else uptr->hwmark = fxread (uptr->filebuf, sizeof (int32), + uptr->capac, uptr->fileref); +uptr->flags = uptr->flags | UNIT_BUF; /* set buf flag */ +uptr->pos = DT_EZLIN; /* beyond leader */ +uptr->LASTT = sim_grtime (); /* last pos update */ +return SCPE_OK; +} + +/* Detach routine + + Cancel in progress operation + If 12b, convert 18b buffer to 12b and write to file + If 16b, convert 18b buffer to 16b and write to file + If 18b/36b, write buffer to file + Deallocate buffer +*/ + +t_stat dt_detach (UNIT* uptr) +{ +uint16 pdp8b[D8_NBSIZE]; +uint16 pdp11b[D18_BSIZE]; +uint32 k, *bptr; +int32 unum = uptr - dt_dev.units; +t_addr ba; + +if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; +if (sim_is_active (uptr)) { + sim_cancel (uptr); + if ((unum == DTA_GETUNIT (dtsa)) && (dtsa & DTA_STSTP)) { + dtsb = dtsb | DTB_ERF | DTB_SEL | DTB_DTF; + DT_UPDINT; } + uptr->STATE = uptr->pos = 0; } +bptr = uptr->filebuf; /* file buffer */ +if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { /* any data? */ + printf ("DT: writing buffer to file\n"); + rewind (uptr->fileref); /* start of file */ + if (uptr->flags & UNIT_8FMT) { /* 12b? */ + for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */ + for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop blk */ + pdp8b[k] = (bptr[ba] >> 6) & 07777; + pdp8b[k + 1] = ((bptr[ba] & 077) << 6) | + ((bptr[ba + 1] >> 12) & 077); + pdp8b[k + 2] = bptr[ba + 1] & 07777; + ba = ba + 2; } /* end loop blk */ + fxwrite (pdp8b, sizeof (int16), D8_NBSIZE, uptr->fileref); + if (ferror (uptr->fileref)) break; } /* end loop file */ + } /* end if 12b */ + else if (uptr->flags & UNIT_11FMT) { /* 16b? */ + for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */ + for (k = 0; k < D18_BSIZE; k++) /* loop blk */ + pdp11b[k] = bptr[ba++] & 0177777; + fxwrite (pdp11b, sizeof (int16), D18_BSIZE, uptr->fileref); + if (ferror (uptr->fileref)) break; } /* end loop file */ + } /* end if 16b */ + else fxwrite (uptr->filebuf, sizeof (int32), /* write file */ + uptr->hwmark, uptr->fileref); + if (ferror (uptr->fileref)) perror ("I/O error"); } /* end if hwmark */ +free (uptr->filebuf); /* release buf */ +uptr->flags = uptr->flags & ~UNIT_BUF; /* clear buf flag */ +uptr->filebuf = NULL; /* clear buf ptr */ +uptr->flags = uptr->flags & ~(UNIT_8FMT | UNIT_11FMT); /* default fmt */ +uptr->capac = DT_CAPAC; /* default size */ +return detach_unit (uptr); +} diff --git a/PDP1/pdp1_lp.c b/PDP1/pdp1_lp.c index 4da02c47..d4e43a84 100644 --- a/PDP1/pdp1_lp.c +++ b/PDP1/pdp1_lp.c @@ -30,12 +30,22 @@ */ #include "pdp1_defs.h" + #define BPTR_MAX 40 /* pointer max */ #define LPT_BSIZE (BPTR_MAX * 3) /* line size */ #define BPTR_MASK 077 /* buf ptr mask */ + extern int32 ioc, sbs, iosta; +extern int32 stop_inst; + int32 lpt_rpls = 0, lpt_iot = 0, lpt_stopioe = 0, bptr = 0; char lpt_buf[LPT_BSIZE + 1] = { 0 }; +static const unsigned char lpt_trans[64] = { + ' ','1','2','3','4','5','6','7','8','9','\'','~','#','V','^','<', + '0','/','S','T','U','V','W','X','Y','Z','"',',','>','^','-','?', + '@','J','K','L','M','N','O','P','Q','R','$','=','-',')','-','(', + '_','A','B','C','D','E','F','G','H','I','*','.','+',']','|','[' }; + t_stat lpt_svc (UNIT *uptr); t_stat lpt_reset (DEVICE *dptr); @@ -66,7 +76,8 @@ DEVICE lpt_dev = { "LPT", &lpt_unit, lpt_reg, NULL, 1, 10, 31, 1, 8, 8, NULL, NULL, &lpt_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + NULL, DEV_DISABLE }; /* Line printer IOT routine */ @@ -74,18 +85,14 @@ int32 lpt (int32 inst, int32 dev, int32 data) { int32 i; -static const unsigned char lpt_trans[64] = { - ' ','1','2','3','4','5','6','7','8','9','\'','~','#','V','^','<', - '0','/','S','T','U','V','W','X','Y','Z','"',',','>','^','-','?', - '@','J','K','L','M','N','O','P','Q','R','$','=','-',')','-','(', - '_','A','B','C','D','E','F','G','H','I','*','.','+',']','|','[' }; - +if (lpt_dev.flags & DEV_DIS) /* disabled? */ + return (stop_inst << IOT_V_REASON) | data; /* stop if requested */ if ((inst & 0700) == 0100) { /* fill buf */ if (bptr < BPTR_MAX) { /* limit test ptr */ i = bptr * 3; /* cvt to chr ptr */ - lpt_buf[i++] = lpt_trans[(data >> 12) & 077]; - lpt_buf[i++] = lpt_trans[(data >> 6) & 077]; - lpt_buf[i++] = lpt_trans[data & 077]; } + lpt_buf[i] = lpt_trans[(data >> 12) & 077]; + lpt_buf[i + 1] = lpt_trans[(data >> 6) & 077]; + lpt_buf[i + 2] = lpt_trans[data & 077]; } bptr = (bptr + 1) & BPTR_MASK; return data; } lpt_rpls = 0; diff --git a/PDP1/pdp1_stddev.c b/PDP1/pdp1_stddev.c index 8201bce7..aa8c5c71 100644 --- a/PDP1/pdp1_stddev.c +++ b/PDP1/pdp1_stddev.c @@ -28,6 +28,7 @@ tti keyboard tto teleprinter + 06-Oct-02 RMS Revised for V2.10 30-May-02 RMS Widened POS to 32b 29-Nov-01 RMS Added read only unit support 07-Sep-01 RMS Moved function prototypes @@ -43,12 +44,15 @@ #define BOTH 0200 /* both cases */ #define CW 0400 /* char waiting */ #define TT_WIDTH 077 + extern int32 sbs, ioc, iosta, PF, IO, PC; extern int32 M[]; + int32 ptr_rpls = 0, ptr_stopioe = 0, ptr_state = 0; int32 ptp_rpls = 0, ptp_stopioe = 0; int32 tti_state = 0; int32 tto_rpls = 0, tto_state = 0; + t_stat ptr_svc (UNIT *uptr); t_stat ptp_svc (UNIT *uptr); t_stat tti_svc (UNIT *uptr); @@ -57,7 +61,7 @@ t_stat ptr_reset (DEVICE *dptr); t_stat ptp_reset (DEVICE *dptr); t_stat tti_reset (DEVICE *dptr); t_stat tto_reset (DEVICE *dptr); -t_stat ptr_boot (int32 unitno); +t_stat ptr_boot (int32 unitno, DEVICE *dptr); /* Character translation tables */ @@ -122,7 +126,8 @@ DEVICE ptr_dev = { "PTR", &ptr_unit, ptr_reg, NULL, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptr_reset, - &ptr_boot, NULL, NULL }; + &ptr_boot, NULL, NULL, + NULL, 0 }; /* PTP data structures @@ -147,7 +152,8 @@ DEVICE ptp_dev = { "PTP", &ptp_unit, ptp_reg, NULL, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptp_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + NULL, 0 }; /* TTI data structures @@ -170,7 +176,8 @@ DEVICE tti_dev = { "TTI", &tti_unit, tti_reg, NULL, 1, 10, 31, 1, 8, 8, NULL, NULL, &tti_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + NULL, 0 }; /* TTO data structures @@ -194,7 +201,8 @@ DEVICE tto_dev = { "TTO", &tto_unit, tto_reg, NULL, 1, 10, 31, 1, 8, 8, NULL, NULL, &tto_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + NULL, 0 }; /* Paper tape reader: IOT routine */ @@ -267,7 +275,7 @@ static const int32 boot_rom[] = { 0607772 /* jmp r */ }; -t_stat ptr_boot (int32 unitno) +t_stat ptr_boot (int32 unitno, DEVICE *dptr) { int32 i; diff --git a/PDP1/pdp1_sys.c b/PDP1/pdp1_sys.c index 1babdf54..0a61f15b 100644 --- a/PDP1/pdp1_sys.c +++ b/PDP1/pdp1_sys.c @@ -23,6 +23,7 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 20-Aug-02 RMS Added DECtape support 17-Sep-01 RMS Removed multiconsole support 13-Jul-01 RMS Fixed RIM loader format 27-May-01 RMS Added multiconsole support @@ -39,7 +40,7 @@ extern DEVICE cpu_dev; extern DEVICE ptr_dev, ptp_dev; extern DEVICE tti_dev, tto_dev; -extern DEVICE lpt_dev; +extern DEVICE lpt_dev, dt_dev; extern UNIT cpu_unit; extern REG cpu_reg[]; extern int32 M[]; @@ -63,9 +64,15 @@ REG *sim_PC = &cpu_reg[0]; int32 sim_emax = 1; -DEVICE *sim_devices[] = { &cpu_dev, - &ptr_dev, &ptp_dev, &tti_dev, &tto_dev, - &lpt_dev, NULL }; +DEVICE *sim_devices[] = { + &cpu_dev, + &ptr_dev, + &ptp_dev, + &tti_dev, + &tto_dev, + &lpt_dev, + &dt_dev, + NULL }; const char *sim_stop_messages[] = { "Unknown error", @@ -108,8 +115,9 @@ for (;;) { if (MEM_ADDR_OK (origin)) M[origin++] = val; } else if ((val & 0770000) == 0600000) { /* JMP? */ PC = val & 007777; - return SCPE_OK; } } -return SCPE_FMT; /* error */ + break; } + } +return SCPE_OK; /* done */ } /* Symbol tables */ @@ -150,6 +158,7 @@ static const char *opcode[] = { "PPA", "PPB", "TYO", "TYI", "LSM", "ESM", "CBS", "LEM", "EEM", "CKS", + "MSE", "MLC", "MRD", "MWR", "MRS", "SKP", "SKP I", "CLO", "SFT", "LAW", "OPR", @@ -201,6 +210,7 @@ static const int32 opc_val[] = { 0720005+I_IOT, 0720006+I_IOT, 0720003+I_IOT, 0720004+I_IOT, 0720054+I_NPN, 0720055+I_NPN, 0720056+I_NPN, 0720074+I_NPN, 0724074+I_NPN, 0720033+I_NPN, + 0720301+I_NPN, 0720401+I_NPN, 0720501+I_NPN, 0720601+I_NPN, 0720701+I_NPN, 0640000+I_NPN, 0650000+I_NPN, 0651600+I_NPN, 0660000+I_NPN, 0700000+I_LAW, 0760000+I_NPN, diff --git a/PDP10/pdp10_cpu.c b/PDP10/pdp10_cpu.c index b203ba4c..ca03ce01 100644 --- a/PDP10/pdp10_cpu.c +++ b/PDP10/pdp10_cpu.c @@ -25,6 +25,8 @@ cpu KS10 central processor + 08-Oct-02 RMS Revised to build dib_tab dynamically + Added SHOW IOSPACE 30-Dec-01 RMS Added old PC queue 25-Dec-01 RMS Cleaned up sim_inst declarations 07-Dec-01 RMS Revised to use new breakpoint package @@ -111,11 +113,10 @@ 3. Arithmetic. The PDP-10 is a 2's complement system. - 4. Adding I/O devices. Three modules must be modified: + 4. Adding I/O devices. These modules must be modified: - pdp10_defs.h add interrupt request definition - pdp10_ksio.c add I/O page linkages - pdp10_sys.c add pointer to data structures to sim_devices + pdp10_defs.h add device address and interrupt definitions + pdp10_sys.c add sim_devices table entry A note on ITS 1-proceed. The simulator follows the implementation on the KS10, keeping 1-proceed as a side flag (its_1pr) rather than @@ -225,6 +226,8 @@ int32 pi_eval (void); int32 test_int (void); void set_ac_display (d10 *acbase); +extern t_stat build_dib_tab (void); +extern t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc); extern d10 Read (a10 ea, int32 prv); /* read, read check */ extern d10 ReadM (a10 ea, int32 prv); /* read, write check */ extern d10 ReadE (a10 ea); /* read, exec */ @@ -361,8 +364,6 @@ REG cpu_reg[] = { { ORDATA (PCQP, pcq_p, 6), REG_HRO }, { DRDATA (INDMAX, ind_max, 8), PV_LEFT + REG_NZ }, { DRDATA (XCTMAX, xct_max, 8), PV_LEFT + REG_NZ }, - { FLDATA (ITS, cpu_unit.flags, UNIT_V_ITS), REG_HRO }, - { FLDATA (T20V41, cpu_unit.flags, UNIT_V_T20V41), REG_HRO }, { ORDATA (WRU, sim_int_char, 8) }, { FLDATA (STOP_ILL, stop_op0, 0) }, { BRDATA (REG, acs, 8, 36, AC_NUM * AC_NBLK) }, @@ -372,6 +373,8 @@ MTAB cpu_mod[] = { { UNIT_ITS+UNIT_T20V41, 0, "Standard microcode", "STANDARD", NULL }, { UNIT_ITS+UNIT_T20V41, UNIT_T20V41, "TOPS-20 V4.1", "TOPS20V41", NULL }, { UNIT_ITS+UNIT_T20V41, UNIT_ITS, "ITS microcode", "ITS", NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "IOSPACE", NULL, + NULL, &show_iospace }, { 0 } }; DEVICE cpu_dev = { @@ -581,9 +584,11 @@ t_stat sim_instr (void) { a10 PC; /* set by setjmp */ int abortval = 0; /* abort value */ +t_stat r; /* Restore register state */ +if ((r = build_dib_tab ()) != SCPE_OK) return r; /* build, chk dib_tab */ pager_PC = PC = saved_PC & AMASK; /* load local PC */ set_dyn_ptrs (); /* set up local ptrs */ pager_tc = FALSE; /* not in trap cycle */ @@ -605,7 +610,7 @@ if ((abortval > 0) || pager_pi) { /* stop or pi err? */ abortval = STOP_PAGINT; /* stop for pi err */ saved_PC = pager_PC & AMASK; /* failing instr PC */ set_ac_display (ac_cur); /* set up AC display */ - pcq_r -> qptr = pcq_p; /* update pc q ptr */ + pcq_r->qptr = pcq_p; /* update pc q ptr */ return abortval; } /* return to SCP */ /* Page fail - checked against KS10 ucode @@ -2044,7 +2049,7 @@ pi_eval (); if (M == NULL) M = calloc (MAXMEMSIZE, sizeof (d10)); if (M == NULL) return SCPE_MEM; pcq_r = find_reg ("PCQ", NULL, dptr); -if (pcq_r) pcq_r -> qptr = 0; +if (pcq_r) pcq_r->qptr = 0; else return SCPE_IERR; sim_brk_types = sim_brk_dflt = SWMASK ('E'); return SCPE_OK; @@ -2087,6 +2092,6 @@ int i; rptr = find_reg ("AC0", NULL, &cpu_dev); if (rptr == NULL) return; -for (i = 0; i < AC_NUM; i++, rptr++) rptr -> loc = (void *) (acbase + i); +for (i = 0; i < AC_NUM; i++, rptr++) rptr->loc = (void *) (acbase + i); return; } diff --git a/PDP10/pdp10_defs.h b/PDP10/pdp10_defs.h index 98b63e16..09bcc653 100644 --- a/PDP10/pdp10_defs.h +++ b/PDP10/pdp10_defs.h @@ -23,6 +23,7 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 29-Sep-02 RMS Added variable vector, RX211 support 22-Apr-02 RMS Removed magtape record length error 20-Jan-02 RMS Added multiboard DZ11 support 23-Oct-01 RMS New IO page address constants @@ -34,6 +35,9 @@ 19-May-01 RMS Added workaround for TOPS-20 V4.1 boot bug */ +#ifndef _PDP10_DEFS_H_ +#define _PDP10_DEFS_H_ 0 + #include "sim_defs.h" /* simulator defns */ /* Digital Equipment Corporation's 36b family had six implementations: @@ -576,19 +580,38 @@ typedef t_int64 d10; /* PDP-10 data (36b) */ /* Device information block */ +#define VEC_DEVMAX 8 /* max device vec */ + struct pdp_dib { - uint32 enb; /* enabled */ uint32 ba; /* base addr */ uint32 lnt; /* length */ t_stat (*rd)(int32 *dat, int32 ad, int32 md); - t_stat (*wr)(int32 dat, int32 ad, int32 md); }; + t_stat (*wr)(int32 dat, int32 ad, int32 md); + int32 vnum; /* vectors: number */ + int32 vloc; /* locator */ + int32 vec; /* value */ + int32 (*ack[VEC_DEVMAX])(void); /* ack routines */ +}; typedef struct pdp_dib DIB; -/* DZ11 parameters */ +/* I/O system parameters */ #define DZ_MUXES 4 /* max # of muxes */ #define DZ_LINES 8 /* lines per mux */ +#define DIB_MAX 100 /* max DIBs */ + +#define DEV_V_UBUS (DEV_V_UF + 0) /* Unibus */ +#define DEV_V_QBUS (DEV_V_UF + 1) /* Qbus */ +#define DEV_V_FLTA (DEV_V_UF + 2) /* float addr */ +#define DEV_UBUS (1u << DEV_V_UBUS) +#define DEV_QBUS (1u << DEV_V_QBUS) +#define DEV_FLTA (1u << DEV_V_FLTA) + +#define UNIBUS TRUE /* 18b only */ + +#define FST 0 /* Unibus 1 */ +#define MAP 1 /* Unibus 3 */ /* I/O page layout */ @@ -614,12 +637,16 @@ typedef struct pdp_dib DIB; #define IOLN_UBCS3 001 #define IOBA_UBMNT3 (IO_UBA3 + 0763101) /* Unibus 3 maint reg */ #define IOLN_UBMNT3 001 +#define IOBA_RY (IO_UBA3 + 0777170) /* RX211 */ +#define IOLN_RY 004 #define IOBA_TU (IO_UBA3 + 0772440) /* RH11/tape */ #define IOLN_TU 034 #define IOBA_LP20 (IO_UBA3 + 0775400) /* LP20 */ #define IOLN_LP20 020 -#define IOBA_PT (IO_UBA3 + 0777550) /* PC11 */ -#define IOLN_PT 010 +#define IOBA_PTR (IO_UBA3 + 017550) /* PC11 reader */ +#define IOLN_PTR 004 +#define IOBA_PTP (IO_UBA3 + 017554) /* PC11 punch */ +#define IOLN_PTP 004 /* Common Unibus CSR flags */ @@ -647,6 +674,7 @@ typedef struct pdp_dib DIB; #define INT_V_TU 7 /* RH11/TM03/TU45 */ #define INT_V_DZRX 16 /* DZ11 */ #define INT_V_DZTX 17 +#define INT_V_RY 18 /* RX211 */ #define INT_V_PTR 24 /* PC11 */ #define INT_V_PTP 25 #define INT_V_LP20 26 /* LPT20 */ @@ -655,6 +683,7 @@ typedef struct pdp_dib DIB; #define INT_TU (1u << INT_V_TU) #define INT_DZRX (1u << INT_V_DZRX) #define INT_DZTX (1u << INT_V_DZTX) +#define INT_RY (1u << INT_V_RY) #define INT_PTR (1u << INT_V_PTR) #define INT_PTP (1u << INT_V_PTP) #define INT_LP20 (1u << INT_V_LP20) @@ -663,6 +692,7 @@ typedef struct pdp_dib DIB; #define IPL_TU 6 #define IPL_DZRX 5 #define IPL_DZTX 5 +#define IPL_RY 5 #define IPL_PTR 4 #define IPL_PTP 4 #define IPL_LP20 4 @@ -675,21 +705,31 @@ typedef struct pdp_dib DIB; #define INT_IPL5 0x000FFF00 #define INT_IPL4 0x3FF00000 +#define VEC_Q 0000 /* vector base */ #define VEC_PTR 0070 /* interrupt vectors */ #define VEC_PTP 0074 #define VEC_TU 0224 #define VEC_RP 0254 +#define VEC_RY 0264 #define VEC_DZRX 0340 #define VEC_DZTX 0344 #define VEC_LP20 0754 +#define IVCL(dv) (INT_V_##dv) #define IREQ(dv) int_req #define SET_INT(dv) IREQ(dv) = IREQ(dv) | (INT_##dv) #define CLR_INT(dv) IREQ(dv) = IREQ(dv) & ~(INT_##dv) /* Function prototypes */ +int32 Map_ReadB (t_addr ba, int32 bc, uint8 *buf, t_bool ub); +int32 Map_ReadW (t_addr ba, int32 bc, uint16 *buf, t_bool ub); +int32 Map_WriteB (t_addr ba, int32 bc, uint8 *buf, t_bool ub); +int32 Map_WriteW (t_addr ba, int32 bc, uint16 *buf, t_bool ub); t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc); -t_bool dev_conflict (uint32 nba, DIB *curr); +t_stat set_vec (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat show_vec (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat auto_config (uint32 rank, uint32 num); + +#endif diff --git a/PDP10/pdp10_doc.txt b/PDP10/pdp10_doc.txt index d5ed0f55..c8c686c0 100644 --- a/PDP10/pdp10_doc.txt +++ b/PDP10/pdp10_doc.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik Subj: PDP-10 Simulator Usage -Date: 15-Jun-2002 +Date: 15-Nov-2002 COPYRIGHT NOTICE @@ -39,13 +39,14 @@ This memorandum documents the PDP-10 simulator. To compile the PDP-10, you must define USE_INT64 as part of the compilation command line. -sim/ sim_defs.h +sim/ dec_dz.h + dec_pt.h + sim_defs.h + sim_rev.h sim_sock.h sim_tmxr.h - dec_dz.h scp.c scp_tty.c - sim_rev.c sim_sock.c sim_tmxr.c @@ -63,6 +64,8 @@ sim/pdp10/ pdp10_defs.h pdp10_tu.c pdp10_xtnd.c +sim/pdp11/ pdp11_ry.c + 2. PDP-10 Features The PDP-10 simulator is configured as follows: @@ -76,14 +79,19 @@ UBA Unibus adapters (translation maps) FE console TIM timer PTR,PTP PC11 paper tape reader/punch +RY RX211/RX02 floppy disk and two drives DZ DZ11 8-line terminal multiplexor (up to 4) LP20 LP20 line printer RP RH11/RP04/RP05/RP06/RP07/RM03/RM05/RM80 controller with eight drives TU RH11/TM02/TU45 controller with eight drives -The PTR/PTP are initially set DISABLED. The DZ11 and LP20 can also be -set DISABLED. +The PTR, PTP, and RX211 are initially set DISABLED. The DZ11 and LP20 can +also be set DISABLED. Some devices support the SET ADDRESS command, which +allows the I/O page address of the device to be changed, and the SET VECTOR +command, which allows the vector of the device to be changed. All devices +support the SHOW ADDRESS and SHOW VECTOR commands, which display the device +address and vector, respectively. The PDP-10 simulator implements several unique stop condition: @@ -112,6 +120,7 @@ microcode SET CPU STANDARD Standard microcode SET CPU TOPS20V41 Standard microcode with TOPS-20 V4.1 bug fix SET CPU ITS ITS compatible microcode + SHOW CPU IOSPACE show I/O space address map CPU registers include the visible state of the processor as well as the control registers for the interrupt system. @@ -234,6 +243,9 @@ The paper tape reader (PTR) reads data from a disk file. The POS register specifies the number of the next data item to be read. Thus, by changing POS, the user can backspace or advance the reader. +The paper tape reader requires an unsupported driver under TOPS-10 +and is not supported under TOPS-20 or ITS. + The paper tape reader implements these registers: name size comments @@ -268,6 +280,9 @@ The paper tape punch (PTP) writes data to a disk file. The POS register specifies the number of the next data item to be written. Thus, by by changing POS, the user can backspace or advance the punch. +The paper tape punch requires an unsupported driver under TOPS-10 +and is not supported under TOPS-20 or ITS. + The paper tape punch implements these registers: name size comments @@ -300,6 +315,13 @@ are supported. The number of lines can be changed with the command The line count must be a multiple of 8, with a maximum of 32. +The DZ11 can support 8-bit input and output of characters. 8-bit +output is incompatible with TOPS-20 and is off by default. The command + + SET DZ 8B + +allows output characters to be 8 bits. + The terminal lines perform input and output through Telnet sessions connected to a user-specified port. The ATTACH command specifies the port to be used: @@ -443,12 +465,11 @@ Error handling is as follows: error processed as - not attached tape not ready + not attached tape not ready; if STOP_IOE, stop - end of file (read or space) end of physical tape - (write) ignored + end of file operation incomplete - OS I/O error report error and stop + OS I/O error parity error; if STOP_IOE, stop 2.11 LP20 DMA Line Printer (LP20) @@ -492,7 +513,57 @@ Error handling is as follows: OS I/O error x report error and stop -2.12 Symbolic Display and Input +2.12 RX211/RX02 Floppy Disk (RY) + +RX211 options include the ability to set units write enabled or write +locked, single or double density, or autosized: + + SET RYn LOCKED set unit n write locked + SET RYn WRITEENABLED set unit n write enabled + SET RYn SINGLE set unit n single density + SET RYn DOUBLE set unit n double density (default) + SET RYn AUTOSIZE set unit n autosized + +The RX211 supports the BOOT command, but only for double density. + +The floppy disk requires an unsupported driver under TOPS-10 and +is not supported under TOPS-20 or ITS. + +The RX211 implements these registers: + + name size comments + + RYCS 16 status + RYBA 16 buffer address + RYWC 8 word count + RYDB 16 data buffer + RYES 12 error status + RYERR 8 error code + RYTA 8 current track + RYSA 8 current sector + STAPTR 4 controller state + INT 1 interrupt pending flag + ERR 1 error flag (CSR<15>) + TR 1 transfer ready flag (CSR<7>) + IE 1 interrupt enable flag (CSR<6>) + DONE 1 device done flag (CSR<5>) + CTIME 24 command completion time + STIME 24 seek time, per track + XTIME 24 transfer ready delay + STOP_IOE 1 stop on I/O error + SBUF[0:255] 8 sector buffer array + +Error handling is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 disk not ready + +RX02 data files are buffered in memory; therefore, end of file and OS +I/O errors cannot occur. + +2.13 Symbolic Display and Input The PDP-10 simulator implements symbolic display and input. Display is controlled by command line switches: diff --git a/PDP10/pdp10_dz.c b/PDP10/pdp10_dz.c index 4859cbd5..12e14d87 100644 --- a/PDP10/pdp10_dz.c +++ b/PDP10/pdp10_dz.c @@ -26,5 +26,8 @@ dz DZ11 terminal multiplexor */ +#define VM_PDP10 0 /* no flt addr */ +#define RANK_DZ 0 /* no autoconfig */ + #include "pdp10_defs.h" #include "dec_dz.h" diff --git a/PDP10/pdp10_ksio.c b/PDP10/pdp10_ksio.c index f363a06b..9200fb3c 100644 --- a/PDP10/pdp10_ksio.c +++ b/PDP10/pdp10_ksio.c @@ -25,6 +25,9 @@ uba Unibus adapters + 10-Oct-02 RMS Revised for dynamic table generation + Added SHOW IOSPACE routine + 29-Sep-02 RMS Added variable vector, central map support 25-Jan-02 RMS Revised for multiple DZ11's 06-Jan-02 RMS Revised enable/disable support 23-Sep-01 RMS New IO page address constants @@ -66,6 +69,7 @@ #include "pdp10_defs.h" #include +#define XBA_MBZ 0400000 /* ba mbz */ #define eaRB (ea & ~1) #define GETBYTE(ea,x) ((((ea) & 1)? (x) >> 8: (x)) & 0377) #define UBNXM_FAIL(pa,op) \ @@ -91,22 +95,25 @@ static const int32 ubabr76[UBANUM] = { INT_UB1 & (INT_IPL7 | INT_IPL6), INT_UB3 & (INT_IPL7 | INT_IPL6) }; static const int32 ubabr54[UBANUM] = { INT_UB1 & (INT_IPL5 | INT_IPL4), INT_UB3 & (INT_IPL5 | INT_IPL4) }; +static const int32 ubashf[4] = { 18, 26, 0, 8 }; +extern d10 *M; /* main memory */ extern d10 *ac_cur; extern d10 pager_word; extern int32 flags, pi_l2bit[8]; extern UNIT cpu_unit; extern FILE *sim_log; extern jmp_buf save_env; +extern DEVICE *sim_devices[]; extern d10 Read (a10 ea); extern void pi_eval (); -extern DIB dz_dib, pt_dib, lp20_dib, rp_dib, tu_dib, tcu_dib; extern int32 rp_inta (void); extern int32 tu_inta (void); extern int32 lp20_inta (void); extern int32 dz_rxinta (void); extern int32 dz_txinta (void); + t_stat ubmap_rd (int32 *data, int32 addr, int32 access); t_stat ubmap_wr (int32 data, int32 addr, int32 access); t_stat ubs_rd (int32 *data, int32 addr, int32 access); @@ -118,7 +125,6 @@ t_stat uba_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat uba_reset (DEVICE *dptr); d10 ReadIO (a10 ea); void WriteIO (a10 ea, d10 val, int32 mode); -t_bool dev_conflict (uint32 nba, DIB *curr); /* Unibus adapter data structures @@ -127,13 +133,13 @@ t_bool dev_conflict (uint32 nba, DIB *curr); uba_reg UBA register list */ -DIB ubmp1_dib = { 1, IOBA_UBMAP1, IOLN_UBMAP1, &ubmap_rd, &ubmap_wr }; -DIB ubmp3_dib = { 1, IOBA_UBMAP3, IOLN_UBMAP3, &ubmap_rd, &ubmap_wr }; -DIB ubcs1_dib = { 1, IOBA_UBCS1, IOLN_UBCS1, &ubs_rd, &ubs_wr }; -DIB ubcs3_dib = { 1, IOBA_UBCS3, IOLN_UBCS3, &ubs_rd, &ubs_wr }; -DIB ubmn1_dib = { 1, IOBA_UBMNT1, IOLN_UBMNT1, &rd_zro, &wr_nop }; -DIB ubmn3_dib = { 1, IOBA_UBMNT3, IOLN_UBMNT3, &rd_zro, &wr_nop }; -DIB msys_dib = { 1, 00100000, 00100001, &rd_zro, &wr_nop }; +DIB ubmp1_dib = { IOBA_UBMAP1, IOLN_UBMAP1, &ubmap_rd, &ubmap_wr, 0 }; +DIB ubmp3_dib = { IOBA_UBMAP3, IOLN_UBMAP3, &ubmap_rd, &ubmap_wr, 0 }; +DIB ubcs1_dib = { IOBA_UBCS1, IOLN_UBCS1, &ubs_rd, &ubs_wr, 0 }; +DIB ubcs3_dib = { IOBA_UBCS3, IOLN_UBCS3, &ubs_rd, &ubs_wr, 0 }; +DIB ubmn1_dib = { IOBA_UBMNT1, IOLN_UBMNT1, &rd_zro, &wr_nop, 0 }; +DIB ubmn3_dib = { IOBA_UBMNT3, IOLN_UBMNT3, &rd_zro, &wr_nop, 0 }; +DIB msys_dib = { 00100000, 1, &rd_zro, &wr_nop, 0 }; UNIT uba_unit[] = { { UDATA (NULL, UNIT_FIX, UMAP_MEMSIZE) }, @@ -149,17 +155,18 @@ DEVICE uba_dev = { "UBA", uba_unit, uba_reg, NULL, UBANUM, 8, UMAP_ASIZE, 1, 8, 32, &uba_ex, &uba_dep, &uba_reset, - NULL, NULL, NULL }; - + NULL, NULL, NULL, + NULL, 0 }; + /* PDP-11 I/O structures */ -DIB *dib_tab[] = { - &rp_dib, - &tu_dib, - &dz_dib, - &lp20_dib, - &pt_dib, - &tcu_dib, +DIB *dib_tab[DIB_MAX]; /* run-time DIBs */ + +int32 (*int_ack[32])(void); /* int ack routines */ + +int32 int_vec[32]; /* int vectors */ + +DIB *std_dib[] = { /* standard DIBs */ &ubmp1_dib, &ubmp3_dib, &ubcs1_dib, @@ -168,22 +175,6 @@ DIB *dib_tab[] = { &ubmn3_dib, &msys_dib, NULL }; - -/* Interrupt request to interrupt action map */ - -int32 (*int_ack[32])() = { /* int ack routines */ - NULL, NULL, NULL, NULL, NULL, NULL, &rp_inta, &tu_inta, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - &dz_rxinta, &dz_txinta, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, &lp20_inta, NULL, NULL, NULL, NULL, NULL }; - -/* Interrupt request to vector map */ - -int32 int_vec[32] = { /* int req to vector */ - 0, 0, 0, 0, 0, 0, VEC_RP, VEC_TU, - 0, 0, 0, 0, 0, 0, 0, 0, - VEC_DZRX, VEC_DZTX, 0, 0, 0, 0, 0, 0, - VEC_PTR, VEC_PTP, VEC_LP20, 0, 0, 0, 0, 0 }; /* IO 710 (DEC) TIOE - test I/O word, skip if zero (ITS) IORDI - read word from Unibus 3 @@ -378,9 +369,9 @@ int32 i, n, val; DIB *dibp; for (i = 0; dibp = dib_tab[i]; i++ ) { - if (dibp -> enb && (pa >= dibp -> ba) && - (pa < (dibp -> ba + dibp -> lnt))) { - dibp -> rd (&val, pa, READ); + if ((pa >= dibp->ba) && + (pa < (dibp->ba + dibp->lnt))) { + dibp->rd (&val, pa, READ); pi_eval (); return ((d10) val); } } UBNXM_FAIL (pa, READ); @@ -393,14 +384,97 @@ int32 i, n; DIB *dibp; for (i = 0; dibp = dib_tab[i]; i++ ) { - if (dibp -> enb && (pa >= dibp -> ba) && - (pa < (dibp -> ba + dibp -> lnt))) { - dibp -> wr ((int32) val, pa, mode); + if ((pa >= dibp->ba) && + (pa < (dibp->ba + dibp->lnt))) { + dibp->wr ((int32) val, pa, mode); pi_eval (); return; } } UBNXM_FAIL (pa, mode); } +/* Mapped read and write routines - used by word-oriented Unibus devices */ + +a10 Map_Addr10 (a10 ba, int32 ub) +{ +a10 pa10; +int32 vpn = PAG_GETVPN (ba >> 2); /* get PDP-10 page number */ + +if ((vpn >= UMAP_MEMSIZE) || (ba & XBA_MBZ) || + ((ubmap[ub][vpn] & UMAP_VLD) == 0)) return -1; /* invalid map? */ +pa10 = (ubmap[ub][vpn] + PAG_GETOFF (ba >> 2)) & PAMASK; +return pa10; +} + +int32 Map_ReadB (t_addr ba, int32 bc, uint8 *buf, t_bool ub) +{ +t_addr lim; +a10 pa10; + +lim = ba + bc; +for ( ; ba < lim; ba++) { /* by bytes */ + pa10 = Map_Addr10 (ba, ub); /* map addr */ + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ + ubcs[ub] = ubcs[ub] | UBCS_TMO; /* UBA times out */ + return (lim - ba); } /* return bc */ + *buf++ = (uint8) ((M[pa10] >> ubashf[ba & 3]) & 0377); + } +return 0; +} + +int32 Map_ReadW (t_addr ba, int32 bc, uint16 *buf, t_bool ub) +{ +t_addr lim; +a10 pa10; + +ba = ba & ~01; /* align start */ +lim = ba + (bc & ~01); +for ( ; ba < lim; ba = ba + 2) { /* by words */ + pa10 = Map_Addr10 (ba, ub); /* map addr */ + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ + ubcs[ub] = ubcs[ub] | UBCS_TMO; /* UBA times out */ + return (lim - ba); } /* return bc */ + *buf++ = (uint16) ((M[pa10] >> ((ba & 2)? 0: 18)) & 0177777); + } +return 0; +} + +int32 Map_WriteB (t_addr ba, int32 bc, uint8 *buf, t_bool ub) +{ +t_addr lim; +a10 pa10; +static d10 mask = 0377; + +lim = ba + bc; +for ( ; ba < lim; ba++) { /* by bytes */ + pa10 = Map_Addr10 (ba, ub); /* map addr */ + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ + ubcs[ub] = ubcs[ub] | UBCS_TMO; /* UBA times out */ + return (lim - ba); } /* return bc */ + M[pa10] = (M[pa10] & ~(mask << ubashf[ba & 3])) | + (((d10) *buf++) << ubashf[ba & 3]); } +return 0; +} + +int32 Map_WriteW (t_addr ba, int32 bc, uint16 *buf, t_bool ub) +{ +t_addr lim; +a10 pa10; +d10 val; + +ba = ba & ~01; /* align start */ +lim = ba + (bc & ~01); +for ( ; ba < lim; ba++) { /* by bytes */ + pa10 = Map_Addr10 (ba, ub); /* map addr */ + if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ + ubcs[ub] = ubcs[ub] | UBCS_TMO; /* UBA times out */ + return (lim - ba); } /* return bc */ + val = *buf++; /* get data */ + if (ba & 2) M[pa10] = (M[pa10] & 0777777600000) | val; + else M[pa10] = (M[pa10] & 0600000777777) | (val << 18); + } +return 0; +} + /* Evaluate Unibus priority interrupts */ int32 pi_ub_eval () @@ -530,24 +604,27 @@ pi_eval (); return SCPE_OK; } -/* Change device number for a device */ +/* Change device address */ t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc) { +DEVICE *dptr; DIB *dibp; uint32 newba; t_stat r; if (cptr == NULL) return SCPE_ARG; -if ((val == 0) || (desc == NULL)) return SCPE_IERR; -dibp = (DIB *) desc; +if ((val == 0) || (uptr == NULL)) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); +if (dptr == NULL) return SCPE_IERR; +dibp = (DIB *) dptr->ctxt; +if (dibp == NULL) return SCPE_IERR; newba = (uint32) get_uint (cptr, 8, PAMASK, &r); /* get new */ -if ((r != SCPE_OK) || (newba == dibp -> ba)) return r; -if ((newba & AMASK) <= IOPAGEBASE) return SCPE_ARG; /* must be > 0 */ +if ((r != SCPE_OK) || (newba == dibp->ba)) return r; +if (GET_IOUBA (newba) != GET_IOUBA (dibp->ba)) return SCPE_ARG; if (newba % ((uint32) val)) return SCPE_ARG; /* check modulus */ -if (GET_IOUBA (newba) != GET_IOUBA (dibp -> ba)) return SCPE_ARG; -if (dev_conflict (newba, dibp)) return SCPE_OK; -dibp -> ba = newba; /* store */ +if (GET_IOUBA (newba) != GET_IOUBA (dibp->ba)) return SCPE_ARG; +dibp->ba = newba; /* store */ return SCPE_OK; } @@ -555,61 +632,163 @@ return SCPE_OK; t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc) { +DEVICE *dptr; DIB *dibp; -if (desc == NULL) return SCPE_IERR; -dibp = (DIB *) desc; -if (dibp -> ba <= IOPAGEBASE) return SCPE_IERR; -fprintf (st, "address=%07o", dibp -> ba); -if (dibp -> lnt > 1) - fprintf (st, "-%07o", dibp -> ba + dibp -> lnt - 1); +if (uptr == NULL) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); +if (dptr == NULL) return SCPE_IERR; +dibp = (DIB *) dptr->ctxt; +if ((dibp == NULL) || (dibp->ba <= IOPAGEBASE)) return SCPE_IERR; +fprintf (st, "address=%07o", dibp->ba); +if (dibp->lnt > 1) + fprintf (st, "-%07o", dibp->ba + dibp->lnt - 1); return SCPE_OK; } -/* Enable or disable a device */ +/* Change device vector */ -t_stat set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc) +t_stat set_vec (UNIT *uptr, int32 arg, char *cptr, void *desc) { -int32 i; DEVICE *dptr; DIB *dibp; -UNIT *up; +uint32 newvec; +t_stat r; -if (cptr != NULL) return SCPE_ARG; -if ((uptr == NULL) || (desc == NULL)) return SCPE_IERR; -dptr = find_dev_from_unit (uptr); /* find device */ +if (cptr == NULL) return SCPE_ARG; +if (uptr == NULL) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); if (dptr == NULL) return SCPE_IERR; -dibp = (DIB *) desc; -if ((val ^ dibp -> enb) == 0) return SCPE_OK; /* enable chg? */ -if (val) { /* enable? */ - if (dev_conflict (dibp -> ba, dibp)) return SCPE_OK; } -else { /* disable */ - for (i = 0; i < dptr -> numunits; i++) { /* check units */ - up = (dptr -> units) + i; - if ((up -> flags & UNIT_ATT) || sim_is_active (up)) - return SCPE_NOFNC; } } -dibp -> enb = val; -if (dptr -> reset) return dptr -> reset (dptr); -else return SCPE_OK; +dibp = (DIB *) dptr->ctxt; +if (dibp == NULL) return SCPE_IERR; +newvec = (uint32) get_uint (cptr, 8, VEC_Q + 01000, &r); +if ((r != SCPE_OK) || (newvec <= VEC_Q) || + ((newvec + (dibp->vnum * 4)) >= (VEC_Q + 01000)) || + (newvec & ((dibp->vnum > 1)? 07: 03))) return SCPE_ARG; +dibp->vec = newvec; +return SCPE_OK; } +/* Show device vector */ + +t_stat show_vec (FILE *st, UNIT *uptr, int32 arg, void *desc) +{ +DEVICE *dptr; +DIB *dibp; +uint32 vec, numvec; + +if (uptr == NULL) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); +if (dptr == NULL) return SCPE_IERR; +dibp = (DIB *) dptr->ctxt; +if (dibp == NULL) return SCPE_IERR; +vec = dibp->vec; +if (arg) numvec = arg; +else numvec = dibp->vnum; +if (vec == 0) fprintf (st, "no vector"); +else { fprintf (st, "vector=%o", vec); + if (numvec > 1) fprintf (st, "-%o", vec + (4 * (numvec - 1))); } +return SCPE_OK; +} + /* Test for conflict in device addresses */ -t_bool dev_conflict (uint32 nba, DIB *curr) +t_bool dev_conflict (DIB *curr) { uint32 i, end; +DEVICE *dptr; DIB *dibp; -end = nba + curr -> lnt - 1; /* get end */ -for (i = 0; dibp = dib_tab[i]; i++) { /* loop thru dev */ - if (!dibp -> enb || (dibp == curr)) continue; /* skip disabled */ - if (((nba >= dibp -> ba) && - (nba < (dibp -> ba + dibp -> lnt))) || - ((end >= dibp -> ba) && - (end < (dibp -> ba + dibp -> lnt)))) { - printf ("Device address conflict at %07o\n", dibp -> ba); +end = curr->ba + curr->lnt - 1; /* get end */ +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ + dibp = (DIB *) dptr->ctxt; /* get DIB */ + if ((dibp == NULL) || (dibp == curr) || + (dptr->flags & DEV_DIS)) continue; + if (((curr->ba >= dibp->ba) && /* overlap start? */ + (curr->ba < (dibp->ba + dibp->lnt))) || + ((end >= dibp->ba) && /* overlap end? */ + (end < (dibp->ba + dibp->lnt)))) { + printf ("Device %s address conflict at %08o\n", dptr->name, dibp->ba); if (sim_log) fprintf (sim_log, - "Device number conflict at %07o\n", dibp -> ba); + "Device %s address conflict at %08o\n", dptr->name, dibp->ba); return TRUE; } } return FALSE; } + +/* Build interrupt tables */ + +void build_int_vec (int32 vloc, int32 ivec, int32 (*iack)(void) ) +{ +if (iack != NULL) int_ack[vloc] = iack; +else int_vec[vloc] = ivec; +return; +} + +/* Build dib_tab from device list */ + +t_bool build_dib_tab (void) +{ +int32 i, j, k; +DEVICE *dptr; +DIB *dibp; + +for (i = 0; i < 32; i++) { /* clear intr tables */ + int_vec[i] = 0; + int_ack[i] = NULL; } +for (i = j = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ + dibp = (DIB *) dptr->ctxt; /* get DIB */ + if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */ + if (dibp->vnum > VEC_DEVMAX) return SCPE_IERR; + for (k = 0; k < dibp->vnum; k++) /* loop thru vec */ + build_int_vec (dibp->vloc + k, /* add vector */ + dibp->vec + (k * 4), dibp->ack[k]); + if (dibp->lnt != 0) { /* I/O addresses? */ + dib_tab[j++] = dibp; /* add DIB to dib_tab */ + if (j >= DIB_MAX) return SCPE_IERR; } /* too many? */ + } /* end if enabled */ + } /* end for */ +for (i = 0; (dibp = std_dib[i]) != NULL; i++) { /* loop thru std */ + dib_tab[j++] = dibp; /* add to dib_tab */ + if (j >= DIB_MAX) return SCPE_IERR; } /* too many? */ +dib_tab[j] = NULL; /* end with NULL */ +for (i = 0; (dibp = dib_tab[i]) != NULL; i++) { /* test built dib_tab */ + if (dev_conflict (dibp)) return SCPE_STOP; } /* for conflicts */ +return SCPE_OK; +} + +/* Show dib_tab */ + +t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +int32 i, j, done = 0; +DEVICE *dptr; +DIB *dibt; + +build_dib_tab (); /* build table */ +while (done == 0) { /* sort ascending */ + done = 1; /* assume done */ + for (i = 0; dib_tab[i + 1] != NULL; i++) { /* check table */ + if (dib_tab[i]->ba > dib_tab[i + 1]->ba) { /* out of order? */ + dibt = dib_tab[i]; /* interchange */ + dib_tab[i] = dib_tab[i + 1]; + dib_tab[i + 1] = dibt; + done = 0; } } /* not done */ + } /* end while */ +for (i = 0; dib_tab[i] != NULL; i++) { /* print table */ + for (j = 0, dptr = NULL; sim_devices[j] != NULL; j++) { + if (((DIB*) sim_devices[j]->ctxt) == dib_tab[i]) { + dptr = sim_devices[j]; + break; } } + fprintf (st, "%07o - %07o\t%s\n", dib_tab[i]->ba, + dib_tab[i]->ba + dib_tab[i]->lnt - 1, + dptr? dptr->name: "CPU"); + } +return SCPE_OK; +} + +/* Stub auto-configure */ + +t_stat auto_config (uint32 rank, uint32 num) +{ +return SCPE_OK; +} diff --git a/PDP10/pdp10_lp20.c b/PDP10/pdp10_lp20.c index 5c709a6c..31dd95c0 100644 --- a/PDP10/pdp10_lp20.c +++ b/PDP10/pdp10_lp20.c @@ -25,6 +25,9 @@ lp20 line printer + 29-Sep-02 RMS Added variable vector support + Modified to use common Unibus routines + New data structures 30-May-02 RMS Widened POS to 32b 06-Jan-02 RMS Added enable/disable support 30-Nov-01 RMS Added extended SET/SHOW support @@ -114,8 +117,6 @@ /* LPBA (765404) */ -#define XBA_MBZ 0400000 /* addr<17> must be 0 */ - /* LPBC (765506) */ #define BC_MASK 0007777 /* <15:12> MBZ */ @@ -134,8 +135,10 @@ extern d10 *M; /* main memory */ extern int32 int_req; +extern int32 int_vec[32]; extern int32 ubcs[UBANUM]; /* UBA csr */ extern int32 ubmap[UBANUM][UMAP_MEMSIZE]; /* UBA map */ + int32 lpcsa = 0; /* control/status A */ int32 lpcsb = 0; /* control/status B */ int32 lpba = 0; /* bus address */ @@ -153,8 +156,10 @@ int32 lp20_stopioe = 0; /* stop on error */ int16 txram[TX_SIZE] = { 0 }; /* translation RAM */ int16 davfu[DV_SIZE] = { 0 }; /* DAVFU */ +DEVICE lp20_dev; t_stat lp20_rd (int32 *data, int32 pa, int32 access); t_stat lp20_wr (int32 data, int32 pa, int32 access); +int32 lp20_inta (void); t_stat lp20_svc (UNIT *uptr); t_stat lp20_reset (DEVICE *dptr); t_stat lp20_attach (UNIT *uptr, char *ptr); @@ -172,7 +177,8 @@ void update_lpcs (int32 flg); lp20_reg LPT register list */ -DIB lp20_dib = { 1, IOBA_LP20, IOLN_LP20, &lp20_rd, &lp20_wr }; +DIB lp20_dib = { IOBA_LP20, IOLN_LP20, &lp20_rd, &lp20_wr, + 1, IVCL (LP20), VEC_LP20, { &lp20_inta } }; UNIT lp20_unit = { UDATA (&lp20_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; @@ -200,23 +206,24 @@ REG lp20_reg[] = { { FLDATA (STOP_IOE, lp20_stopioe, 0) }, { BRDATA (TXRAM, txram, 8, 12, TX_SIZE) }, { BRDATA (DAVFU, davfu, 8, 12, DV_SIZE) }, + { ORDATA (DEVADDR, lp20_dib.ba, 32), REG_HRO }, + { ORDATA (DEVVEC, lp20_dib.vec, 16), REG_HRO }, { NULL } }; MTAB lp20_mod[] = { { UNIT_DUMMY, 0, NULL, "VFUCLEAR", &lp20_clear_vfu }, { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, &lp20_dib }, - { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", - &set_enbdis, NULL, &lp20_dib }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", - &set_enbdis, NULL, &lp20_dib }, + &set_addr, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + &set_vec, &show_vec, NULL }, { 0 } }; DEVICE lp20_dev = { "LP20", &lp20_unit, lp20_reg, lp20_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &lp20_reset, - NULL, &lp20_attach, &lp20_detach }; + NULL, &lp20_attach, &lp20_detach, + &lp20_dib, DEV_DISABLE | DEV_UBUS }; /* Line printer routines @@ -338,11 +345,12 @@ return SCPE_OK; t_stat lp20_svc (UNIT *uptr) { -int32 fnc, i, tbc, vpn, temp, txst, wd10; +int32 fnc, i, tbc, temp, txst; int32 dvld = -2; /* must be even */ int32 err = 0; +uint16 wd10; t_bool cont; -a10 ba, pa10; +a10 ba; static const uint32 txcase[32] = { TX_CHR, TX_RAM, TX_CHR, TX_DVU, TX_RAM, TX_RAM, TX_DVU, TX_DVU, @@ -362,20 +370,10 @@ if ((fnc == FNC_PR) && (dvlnt == 0)) { return SCPE_OK; } for (i = 0, cont = TRUE; (i < tbc) && cont; ba++, i++) { - vpn = PAG_GETVPN (ba >> 2); /* get PDP-10 page number */ - if ((vpn >= UMAP_MEMSIZE) || (ba & XBA_MBZ) || - ((ubmap[1][vpn] & UMAP_VLD) == 0)) { /* invalid map? */ + if (Map_ReadW (ba, 2, &wd10, MAP)) { /* get word, err? */ lpcsb = lpcsb | CSB_MTE; /* set NXM error */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */ update_lpcs (CSA_ERR); /* set done */ break; } - pa10 = (ubmap[1][vpn] + PAG_GETOFF (ba >> 2)) & PAMASK; - if (MEM_ADDR_NXM (pa10)) { /* nxm? */ - lpcsb = lpcsb | CSB_MTE; /* set NXM error */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA times out */ - update_lpcs (CSA_ERR); /* set done */ - break; } - wd10 = (int32) ((M[pa10] >> ((ba & 2)? 0: 18)) & 0177777); lpcbuf = (wd10 >> ((ba & 1)? 8: 0)) & 0377; /* get character */ lpcsum = (lpcsum + lpcbuf) & 0377; /* add into checksum */ switch (fnc) { /* switch on function */ @@ -442,7 +440,7 @@ if (lpbc) update_lpcs (CSA_MBZ); /* intr, but not done */ else update_lpcs (CSA_DONE); /* intr and done */ if ((fnc == FNC_PR) && ferror (lp20_unit.fileref)) { perror ("LP I/O error"); - clearerr (uptr -> fileref); + clearerr (uptr->fileref); return SCPE_IOERR; } return SCPE_OK; } @@ -547,7 +545,7 @@ return; int32 lp20_inta (void) { lp20_irq = 0; /* clear int req */ -return VEC_LP20; +return lp20_dib.vec; } t_stat lp20_reset (DEVICE *dptr) diff --git a/PDP10/pdp10_mdfp.c b/PDP10/pdp10_mdfp.c index a7945268..a822b077 100644 --- a/PDP10/pdp10_mdfp.c +++ b/PDP10/pdp10_mdfp.c @@ -620,18 +620,18 @@ void funpack (d10 h, d10 l, UFP *r, t_bool sgn) { d10 fphi, fplo; -r -> sign = GET_FPSIGN (h); -r -> exp = GET_FPEXP (h); +r->sign = GET_FPSIGN (h); +r->exp = GET_FPEXP (h); fphi = GET_FPHI (h); fplo = GET_FPLO (l); -r -> fhi = (fphi << FP_V_UFHI) | (fplo << FP_V_UFLO); -r -> flo = 0; -if (r -> sign) { - r -> exp = r -> exp ^ FP_M_EXP; - if (sgn) r -> fhi = r -> fhi | FP_UCRY; /* ext sign */ - else { if (r -> fhi) r -> fhi = UNEG (r -> fhi) & FP_UFRAC; - else { r -> exp = r -> exp + 1; - r -> fhi = FP_UNORM; } } } +r->fhi = (fphi << FP_V_UFHI) | (fplo << FP_V_UFLO); +r->flo = 0; +if (r->sign) { + r->exp = r->exp ^ FP_M_EXP; + if (sgn) r->fhi = r->fhi | FP_UCRY; /* ext sign */ + else { if (r->fhi) r->fhi = UNEG (r->fhi) & FP_UFRAC; + else { r->exp = r->exp + 1; + r->fhi = FP_UNORM; } } } return; } @@ -645,20 +645,20 @@ static t_uint64 normmask[6] = { 0x7FFF800000000000, 0x7FFFFFFF80000000, 0x7FFFFFFFFFFFFFFF }; static int32 normtab[7] = { 1, 2, 4, 8, 16, 32, 63 }; -if ((a -> fhi | a -> flo) == 0) { /* if fraction = 0 */ - a -> sign = a -> exp = 0; /* result is 0 */ +if ((a->fhi | a->flo) == 0) { /* if fraction = 0 */ + a->sign = a->exp = 0; /* result is 0 */ return; } -while ((a -> fhi & FP_UNORM) == 0) { /* normalized? */ +while ((a->fhi & FP_UNORM) == 0) { /* normalized? */ for (i = 0; i < 6; i++) { - if (a -> fhi & normmask[i]) break; } - a -> fhi = (a -> fhi << normtab[i]) | (a -> flo >> (64 - normtab[i])); - a -> flo = a -> flo << normtab[i]; - a -> exp = a -> exp - normtab[i]; } + if (a->fhi & normmask[i]) break; } + a->fhi = (a->fhi << normtab[i]) | (a->flo >> (64 - normtab[i])); + a->flo = a->flo << normtab[i]; + a->exp = a->exp - normtab[i]; } if (rnd) { /* rounding? */ - a -> fhi = a -> fhi + rnd; /* add round const */ - if (a -> fhi & FP_UCRY) { /* if carry out, */ - a -> fhi = a -> fhi >> 1; /* renormalize */ - a -> exp = a -> exp + 1; } } + a->fhi = a->fhi + rnd; /* add round const */ + if (a->fhi & FP_UCRY) { /* if carry out, */ + a->fhi = a->fhi >> 1; /* renormalize */ + a->exp = a->exp + 1; } } return; } @@ -668,13 +668,13 @@ d10 fpack (UFP *r, d10 *lo, t_bool fdvneg) { d10 val[2]; -if (r -> exp < 0) SETF (F_AOV | F_FOV | F_FXU | F_T1); -else if (r -> exp > FP_M_EXP) SETF (F_AOV | F_FOV | F_T1); -val[0] = (((((d10) r -> exp) & FP_M_EXP) << FP_V_EXP) | - ((r -> fhi & FP_UFHI) >> FP_V_UFHI)) & DMASK; -if (lo) val[1] = ((r -> fhi & FP_UFLO) >> FP_V_UFLO) & MMASK; +if (r->exp < 0) SETF (F_AOV | F_FOV | F_FXU | F_T1); +else if (r->exp > FP_M_EXP) SETF (F_AOV | F_FOV | F_T1); +val[0] = (((((d10) r->exp) & FP_M_EXP) << FP_V_EXP) | + ((r->fhi & FP_UFHI) >> FP_V_UFHI)) & DMASK; +if (lo) val[1] = ((r->fhi & FP_UFLO) >> FP_V_UFLO) & MMASK; else val[1] = 0; -if (r -> sign) { /* negate? */ +if (r->sign) { /* negate? */ if (fdvneg) { /* fdvr special? */ val[1] = ~val[1] & MMASK; /* 1's comp */ val[0] = ~val[0] & DMASK; } diff --git a/PDP10/pdp10_pag.c b/PDP10/pdp10_pag.c index 77d41637..a4be66d2 100644 --- a/PDP10/pdp10_pag.c +++ b/PDP10/pdp10_pag.c @@ -142,7 +142,8 @@ DEVICE pag_dev = { "PAG", pag_unit, pag_reg, NULL, 2, 8, PTBL_ASIZE, 1, 8, 32, &pag_ex, &pag_dep, &pag_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + NULL, 0 }; /* Memory read and write routines diff --git a/PDP10/pdp10_pt.c b/PDP10/pdp10_pt.c index 0b9017ed..eeb2db22 100644 --- a/PDP10/pdp10_pt.c +++ b/PDP10/pdp10_pt.c @@ -1,4 +1,4 @@ -/* pdp10_pt.c: PDP-10 Unibus paper tape reader/punch simulator +/* pdp10_pt.c: PDP-10 paper tape reader/punch simulator Copyright (c) 1993-2002, Robert M Supnik @@ -26,283 +26,13 @@ ptr paper tape reader ptp paper tape punch - 30-May-02 RMS Widened POS to 32b - 06-Jan-02 RMS Revised enable/disable support - 29-Nov-01 RMS Added read only unit support - 07-Sep-01 RMS Revised disable mechanism + 12-Sep-02 RMS Consolidated source */ +#define VM_PDP10 1 +#define PT_RDX 8 +#define PT_DIS DEV_DIS #include "pdp10_defs.h" - -#define PTRCSR_IMP (CSR_ERR+CSR_BUSY+CSR_DONE+CSR_IE) /* paper tape reader */ -#define PTRCSR_RW (CSR_IE) -#define PTPCSR_IMP (CSR_ERR + CSR_DONE + CSR_IE) /* paper tape punch */ -#define PTPCSR_RW (CSR_IE) - extern int32 int_req; -int32 ptr_csr = 0; /* control/status */ -int32 ptr_stopioe = 0; /* stop on error */ -int32 ptp_csr = 0; /* control/status */ -int32 ptp_stopioe = 0; /* stop on error */ - -t_stat pt_rd (int32 *data, int32 PA, int32 access); -t_stat pt_wr (int32 data, int32 PA, int32 access); -t_stat ptr_svc (UNIT *uptr); -t_stat ptp_svc (UNIT *uptr); -t_stat ptr_reset (DEVICE *dptr); -t_stat ptp_reset (DEVICE *dptr); -t_stat ptr_attach (UNIT *uptr, char *ptr); -t_stat ptr_detach (UNIT *uptr); -t_stat ptp_attach (UNIT *uptr, char *ptr); -t_stat ptp_detach (UNIT *uptr); - -/* PTR data structures - - ptr_dev PTR device descriptor - ptr_unit PTR unit descriptor - ptr_reg PTR register list -*/ - -DIB pt_dib = { 0, IOBA_PT, IOLN_PT, &pt_rd, &pt_wr }; - -UNIT ptr_unit = { - UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), - SERIAL_IN_WAIT }; - -REG ptr_reg[] = { - { ORDATA (CSR, ptr_csr, 16) }, - { ORDATA (BUF, ptr_unit.buf, 8) }, - { FLDATA (INT, int_req, INT_V_PTR) }, - { FLDATA (ERR, ptr_csr, CSR_V_ERR) }, - { FLDATA (BUSY, ptr_csr, CSR_V_BUSY) }, - { FLDATA (DONE, ptr_csr, CSR_V_DONE) }, - { FLDATA (IE, ptr_csr, CSR_V_IE) }, - { DRDATA (POS, ptr_unit.pos, 32), PV_LEFT }, - { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, - { FLDATA (STOP_IOE, ptr_stopioe, 0) }, - { FLDATA (*DEVENB, pt_dib.enb, 0), REG_HRO }, - { NULL } }; - -MTAB ptr_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, - NULL, &show_addr, &pt_dib }, - { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", - &set_enbdis, NULL, &pt_dib }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", - &set_enbdis, NULL, &pt_dib }, - { 0 } }; - -DEVICE ptr_dev = { - "PTR", &ptr_unit, ptr_reg, ptr_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ptr_reset, - NULL, &ptr_attach, &ptr_detach }; - -/* PTP data structures - - ptp_dev PTP device descriptor - ptp_unit PTP unit descriptor - ptp_reg PTP register list -*/ - -UNIT ptp_unit = { - UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; - -REG ptp_reg[] = { - { ORDATA (BUF, ptp_unit.buf, 8) }, - { ORDATA (CSR, ptp_csr, 16) }, - { FLDATA (INT, int_req, INT_V_PTP) }, - { FLDATA (ERR, ptp_csr, CSR_V_ERR) }, - { FLDATA (DONE, ptp_csr, CSR_V_DONE) }, - { FLDATA (IE, ptp_csr, CSR_V_IE) }, - { DRDATA (POS, ptp_unit.pos, 32), PV_LEFT }, - { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, - { FLDATA (STOP_IOE, ptp_stopioe, 0) }, - { FLDATA (*DEVENB, pt_dib.enb, 0), REG_HRO }, - { NULL } }; - -MTAB ptp_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, - NULL, &show_addr, &pt_dib }, - { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", - &set_enbdis, NULL, &pt_dib }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", - &set_enbdis, NULL, &pt_dib }, - { 0 } }; - -DEVICE ptp_dev = { - "PTP", &ptp_unit, ptp_reg, ptp_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ptp_reset, - NULL, &ptp_attach, &ptp_detach }; - -/* Standard I/O dispatch routine, I/O addresses 17777550-17777557 - - 17777550 ptr CSR - 17777552 ptr buffer - 17777554 ptp CSR - 17777556 ptp buffer - - Note: Word access routines filter out odd addresses. Thus, - an odd address implies an (odd) byte access. -*/ - -t_stat pt_rd (int32 *data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 03) { /* decode PA<2:1> */ -case 0: /* ptr csr */ - *data = ptr_csr & PTRCSR_IMP; - return SCPE_OK; -case 1: /* ptr buf */ - ptr_csr = ptr_csr & ~CSR_DONE; - int_req = int_req & ~INT_PTR; - *data = ptr_unit.buf & 0377; - return SCPE_OK; -case 2: /* ptp csr */ - *data = ptp_csr & PTPCSR_IMP; - return SCPE_OK; -case 3: /* ptp buf */ - *data = ptp_unit.buf; - return SCPE_OK; } -return SCPE_NXM; /* can't get here */ -} - -t_stat pt_wr (int32 data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 03) { /* decode PA<2:1> */ -case 0: /* ptr csr */ - if (PA & 1) return SCPE_OK; - if ((data & CSR_IE) == 0) int_req = int_req & ~INT_PTR; - else if (((ptr_csr & CSR_IE) == 0) && (ptr_csr & (CSR_ERR | CSR_DONE))) - int_req = int_req | INT_PTR; - if (data & CSR_GO) { - ptr_csr = (ptr_csr & ~CSR_DONE) | CSR_BUSY; - int_req = int_req & ~INT_PTR; - if (ptr_unit.flags & UNIT_ATT) /* data to read? */ - sim_activate (&ptr_unit, ptr_unit.wait); - else sim_activate (&ptr_unit, 0); } /* error if not */ - ptr_csr = (ptr_csr & ~PTRCSR_RW) | (data & PTRCSR_RW); - return SCPE_OK; -case 1: /* ptr buf */ - return SCPE_OK; -case 2: /* ptp csr */ - if (PA & 1) return SCPE_OK; - if ((data & CSR_IE) == 0) int_req = int_req & ~INT_PTP; - else if (((ptp_csr & CSR_IE) == 0) && (ptp_csr & (CSR_ERR | CSR_DONE))) - int_req = int_req | INT_PTP; - ptp_csr = (ptp_csr & ~PTPCSR_RW) | (data & PTPCSR_RW); - return SCPE_OK; -case 3: /* ptp buf */ - if ((PA & 1) == 0) ptp_unit.buf = data & 0377; - ptp_csr = ptp_csr & ~CSR_DONE; - int_req = int_req & ~INT_PTP; - if (ptp_unit.flags & UNIT_ATT) /* file to write? */ - sim_activate (&ptp_unit, ptp_unit.wait); - else sim_activate (&ptp_unit, 0); /* error if not */ - return SCPE_OK; } /* end switch PA */ -return SCPE_NXM; /* can't get here */ -} - -/* Paper tape reader routines - - ptr_svc process event (character ready) - ptr_reset process reset - ptr_attach process attach - ptr_detach process detach -*/ - -t_stat ptr_svc (UNIT *uptr) -{ -int32 temp; - -ptr_csr = (ptr_csr | CSR_ERR) & ~CSR_BUSY; -if (ptr_csr & CSR_IE) int_req = int_req | INT_PTR; -if ((ptr_unit.flags & UNIT_ATT) == 0) - return IORETURN (ptr_stopioe, SCPE_UNATT); -if ((temp = getc (ptr_unit.fileref)) == EOF) { - if (feof (ptr_unit.fileref)) { - if (ptr_stopioe) printf ("PTR end of file\n"); - else return SCPE_OK; } - else perror ("PTR I/O error"); - clearerr (ptr_unit.fileref); - return SCPE_IOERR; } -ptr_csr = (ptr_csr | CSR_DONE) & ~CSR_ERR; -ptr_unit.buf = temp & 0377; -ptr_unit.pos = ptr_unit.pos + 1; -return SCPE_OK; -} - -t_stat ptr_reset (DEVICE *dptr) -{ -ptr_unit.buf = 0; -ptr_csr = 0; -if ((ptr_unit.flags & UNIT_ATT) == 0) ptr_csr = ptr_csr | CSR_ERR; -int_req = int_req & ~INT_PTR; -sim_cancel (&ptr_unit); -return SCPE_OK; -} - -t_stat ptr_attach (UNIT *uptr, char *cptr) -{ -t_stat reason; - -reason = attach_unit (uptr, cptr); -if ((ptr_unit.flags & UNIT_ATT) == 0) ptr_csr = ptr_csr | CSR_ERR; -else ptr_csr = ptr_csr & ~CSR_ERR; -return reason; -} - -t_stat ptr_detach (UNIT *uptr) -{ -ptr_csr = ptr_csr | CSR_ERR; -return detach_unit (uptr); -} - -/* Paper tape punch routines - - ptp_svc process event (character punched) - ptp_reset process reset - ptp_attach process attach - ptp_detach process detach -*/ - -t_stat ptp_svc (UNIT *uptr) -{ -ptp_csr = ptp_csr | CSR_ERR | CSR_DONE; -if (ptp_csr & CSR_IE) int_req = int_req | INT_PTP; -if ((ptp_unit.flags & UNIT_ATT) == 0) - return IORETURN (ptp_stopioe, SCPE_UNATT); -if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { - perror ("PTP I/O error"); - clearerr (ptp_unit.fileref); - return SCPE_IOERR; } -ptp_csr = ptp_csr & ~CSR_ERR; -ptp_unit.pos = ptp_unit.pos + 1; -return SCPE_OK; -} - -t_stat ptp_reset (DEVICE *dptr) -{ -ptp_unit.buf = 0; -ptp_csr = CSR_DONE; -if ((ptp_unit.flags & UNIT_ATT) == 0) ptp_csr = ptp_csr | CSR_ERR; -int_req = int_req & ~INT_PTP; -sim_cancel (&ptp_unit); /* deactivate unit */ -return SCPE_OK; -} - -t_stat ptp_attach (UNIT *uptr, char *cptr) -{ -t_stat reason; - -reason = attach_unit (uptr, cptr); -if ((ptp_unit.flags & UNIT_ATT) == 0) ptp_csr = ptp_csr | CSR_ERR; -else ptp_csr = ptp_csr & ~CSR_ERR; -return reason; -} - -t_stat ptp_detach (UNIT *uptr) -{ -ptp_csr = ptp_csr | CSR_ERR; -return detach_unit (uptr); -} +extern int32 int_vec[32]; +#include "dec_pt.h" diff --git a/PDP10/pdp10_rp.c b/PDP10/pdp10_rp.c index 2e3d47df..f8e95682 100644 --- a/PDP10/pdp10_rp.c +++ b/PDP10/pdp10_rp.c @@ -25,6 +25,8 @@ rp RH/RP/RM moving head disks + 29-Sep-02 RMS Added variable vector support + New data structures 30-Nov-01 RMS Added read only unit, extended SET/SHOW support support 24-Nov-01 RMS Changed RPER, RPDS, FNC, FLG to arrays 23-Oct-01 RMS Fixed bug in error interrupts @@ -73,11 +75,10 @@ #define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */ #define UNIT_M_DTYPE 7 #define UNIT_V_AUTO (UNIT_V_UF + 4) /* autosize */ +#define UNIT_V_DUMMY (UNIT_V_UF + 5) /* dummy flag */ #define UNIT_WLK (1 << UNIT_V_WLK) #define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE) #define UNIT_AUTO (1 << UNIT_V_AUTO) -#define UNIT_W_UF 6 /* user flags width */ -#define UNIT_V_DUMMY (UNIT_V_UF + UNIT_W_UF) /* dummy flag */ #define UNIT_DUMMY (1 << UNIT_V_DUMMY) #define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE) #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ @@ -313,9 +314,11 @@ struct drvtyp drv_tab[] = { extern d10 *M; /* memory */ extern int32 int_req; +extern int32 int_vec[32]; extern int32 ubmap[UBANUM][UMAP_MEMSIZE]; /* Unibus maps */ extern int32 ubcs[UBANUM]; extern UNIT cpu_unit; + int32 rpcs1 = 0; /* control/status 1 */ int32 rpwc = 0; /* word count */ int32 rpba = 0; /* bus address */ @@ -341,9 +344,10 @@ int reg_in_drive[32] = { t_stat rp_rd (int32 *data, int32 PA, int32 access); t_stat rp_wr (int32 data, int32 PA, int32 access); +int32 rp_inta (void); t_stat rp_svc (UNIT *uptr); t_stat rp_reset (DEVICE *dptr); -t_stat rp_boot (int32 unitno); +t_stat rp_boot (int32 unitno, DEVICE *dptr); t_stat rp_attach (UNIT *uptr, char *cptr); t_stat rp_detach (UNIT *uptr); void update_rpcs (int32 flags, int32 drv); @@ -358,7 +362,8 @@ t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); rp_mod RP modifier list */ -DIB rp_dib = { 1, IOBA_RP, IOLN_RP, &rp_rd, &rp_wr }; +DIB rp_dib = { IOBA_RP, IOLN_RP, &rp_rd, &rp_wr, + 1, IVCL (RP), VEC_RP, { &rp_inta } }; UNIT rp_unit[] = { { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ @@ -402,8 +407,6 @@ REG rp_reg[] = { { DRDATA (STIME, rp_swait, 24), REG_NZ + PV_LEFT }, { DRDATA (RTIME, rp_rwait, 24), REG_NZ + PV_LEFT }, { URDATA (FNC, rp_unit[0].FUNC, 8, 5, 0, RP_NUMDR, REG_HRO) }, - { URDATA (FLG, rp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, - RP_NUMDR, REG_HRO) }, { URDATA (CAPAC, rp_unit[0].capac, 10, 31, 0, RP_NUMDR, PV_LEFT | REG_HRO) }, { FLDATA (STOP_IOE, rp_stopioe, 0) }, @@ -451,14 +454,17 @@ MTAB rp_mod[] = { { (UNIT_AUTO+UNIT_DTYPE), (RP07_DTYPE << UNIT_V_DTYPE), NULL, "RP07", &rp_set_size }, { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, - NULL, &show_addr, &rp_dib }, + NULL, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, + NULL, &show_vec, NULL }, { 0 } }; DEVICE rp_dev = { "RP", rp_unit, rp_reg, rp_mod, RP_NUMDR, 8, 30, 1, 8, 36, NULL, NULL, &rp_reset, - &rp_boot, &rp_attach, &rp_detach }; + &rp_boot, &rp_attach, &rp_detach, + &rp_dib, DEV_UBUS }; /* I/O dispatch routines, I/O addresses 17776700 - 17776776 */ @@ -577,17 +583,17 @@ case 000: /* RPCS1 */ if ((data & CS1_DONE) && (data & CS1_IE)) /* to DONE+IE? */ rpiff = 1; /* set CSTB INTR */ rpcs1 = (rpcs1 & ~CS1_IE) | (data & CS1_IE); - if (uptr -> flags & UNIT_DIS) { /* nx disk? */ + if (uptr->flags & UNIT_DIS) { /* nx disk? */ rpcs2 = rpcs2 | CS2_NED; /* set error flag */ cs1f = CS1_SC; } /* req interrupt */ else if (sim_is_active (uptr)) rper1[drv] = rper1[drv] | ER1_RMR; /* won't write */ else if (data & CS1_GO) { /* start op */ - uptr -> FUNC = GET_FNC (data); /* set func */ - if ((uptr -> FUNC >= FNC_XFER) && /* data xfer and */ + uptr->FUNC = GET_FNC (data); /* set func */ + if ((uptr->FUNC >= FNC_XFER) && /* data xfer and */ ((rpcs1 & CS1_DONE) == 0)) /* ~rdy? PGE */ rpcs2 = rpcs2 | CS2_PGE; - else rp_go (drv, uptr -> FUNC); } } + else rp_go (drv, uptr->FUNC); } } break; case 001: /* RPWC */ if (access == WRITEB) data = (PA & 1)? @@ -669,7 +675,7 @@ int32 dc, dtype, t; UNIT *uptr; uptr = rp_dev.units + drv; /* get unit */ -if (uptr -> flags & UNIT_DIS) { /* nx unit? */ +if (uptr->flags & UNIT_DIS) { /* nx unit? */ rpcs2 = rpcs2 | CS2_NED; /* set error flag */ update_rpcs (CS1_SC, drv); /* request intr */ return; } @@ -678,7 +684,7 @@ if ((fnc != FNC_DCLR) && (rpds[drv] & DS_ERR)) { /* err & ~clear? */ rpds[drv] = rpds[drv] | DS_ATA; /* set attention */ update_rpcs (CS1_SC, drv); /* request intr */ return; } -dtype = GET_DTYPE (uptr -> flags); /* get drive type */ +dtype = GET_DTYPE (uptr->flags); /* get drive type */ rpds[drv] = rpds[drv] & ~DS_ATA; /* clear attention */ dc = rpdc; /* assume seek, sch */ @@ -700,7 +706,7 @@ case FNC_PACK: /* pack acknowledge */ case FNC_OFFSET: /* offset mode */ case FNC_RETURN: - if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */ + if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */ break; } rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */ @@ -712,7 +718,7 @@ case FNC_RECAL: /* recalibrate */ dc = 0; /* seek to 0 */ case FNC_SEEK: /* seek */ case FNC_SEARCH: /* search */ - if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */ + if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */ break; } if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */ @@ -721,10 +727,10 @@ case FNC_SEARCH: /* search */ rper1[drv] = rper1[drv] | ER1_IAE; break; } rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */ - t = abs (dc - uptr -> CYL); /* cyl diff */ + t = abs (dc - uptr->CYL); /* cyl diff */ if (t == 0) t = 1; /* min time */ sim_activate (uptr, rp_swait * t); /* schedule */ - uptr -> CYL = dc; /* save cylinder */ + uptr->CYL = dc; /* save cylinder */ return; case FNC_WRITEH: /* write headers */ @@ -732,7 +738,7 @@ case FNC_WRITE: /* write */ case FNC_WCHK: /* write check */ case FNC_READ: /* read */ case FNC_READH: /* read headers */ - if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */ + if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */ break; } rpcs2 = rpcs2 & ~CS2_ERR; /* clear errors */ @@ -743,8 +749,8 @@ case FNC_READH: /* read headers */ rper1[drv] = rper1[drv] | ER1_IAE; break; } rpds[drv] = rpds[drv] & ~DS_RDY; /* clear drive rdy */ - sim_activate (uptr, rp_rwait + (rp_swait * abs (dc - uptr -> CYL))); - uptr -> CYL = dc; /* save cylinder */ + sim_activate (uptr, rp_rwait + (rp_swait * abs (dc - uptr->CYL))); + uptr->CYL = dc; /* save cylinder */ return; default: /* all others */ @@ -770,11 +776,11 @@ a10 pa10, mpa10; int32 wc10, twc10, awc10, fc10; static d10 dbuf[RP_MAXFR]; -dtype = GET_DTYPE (uptr -> flags); /* get drive type */ +dtype = GET_DTYPE (uptr->flags); /* get drive type */ drv = uptr - rp_dev.units; /* get drv number */ rpds[drv] = (rpds[drv] & ~DS_PIP) | DS_RDY; /* change drive status */ -switch (uptr -> FUNC) { /* case on function */ +switch (uptr->FUNC) { /* case on function */ case FNC_OFFSET: /* offset */ rpds[drv] = rpds[drv] | DS_OF | DS_ATA; /* set offset, attention */ update_rpcs (CS1_SC, drv); @@ -804,7 +810,7 @@ case FNC_SEEK: /* seek */ #define XBA_MBZ 0000003 /* addr<1:0> must be 0 */ case FNC_WRITE: /* write */ - if (uptr -> flags & UNIT_WPRT) { /* write locked? */ + if (uptr->flags & UNIT_WPRT) { /* write locked? */ rper1[drv] = rper1[drv] | ER1_WLE; /* set drive error */ update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */ break; } @@ -819,8 +825,8 @@ case FNC_READH: /* read headers */ if (wc10 > (drv_tab[dtype].size - da)) wc10 = drv_tab[dtype].size - da; } - err = fseek (uptr -> fileref, da * sizeof (d10), SEEK_SET); - if (uptr -> FUNC == FNC_WRITE) { /* write? */ + err = fseek (uptr->fileref, da * sizeof (d10), SEEK_SET); + if (uptr->FUNC == FNC_WRITE) { /* write? */ for (twc10 = 0; twc10 < wc10; twc10++) { pa10 = ba >> 2; vpn = PAG_GETVPN (pa10); /* map addr */ @@ -836,15 +842,15 @@ case FNC_READH: /* read headers */ break; } dbuf[twc10] = M[mpa10]; /* write to disk */ if ((rpcs2 & CS2_UAI) == 0) ba = ba + 4; } - if (fc10 = twc10 & (RP_NUMWD - 1)) { /* fill? */ + if (fc10 = twc10 & (RP_NUMWD - 1)) { /* fill? */ fc10 = RP_NUMWD - fc10; for (i = 0; i < fc10; i++) dbuf[twc10 + i] = 0; } - fxwrite (dbuf, sizeof (d10), twc10 + fc10, uptr -> fileref); - err = ferror (uptr -> fileref); + fxwrite (dbuf, sizeof (d10), twc10 + fc10, uptr->fileref); + err = ferror (uptr->fileref); } /* end if */ else { /* read, wchk */ - awc10 = fxread (dbuf, sizeof (d10), wc10, uptr -> fileref); - err = ferror (uptr -> fileref); + awc10 = fxread (dbuf, sizeof (d10), wc10, uptr->fileref); + err = ferror (uptr->fileref); for ( ; awc10 < wc10; awc10++) dbuf[awc10] = 0; for (twc10 = 0; twc10 < wc10; twc10++) { pa10 = ba >> 2; @@ -859,7 +865,7 @@ case FNC_READH: /* read headers */ rpcs2 = rpcs2 | CS2_NEM; /* set error */ ubcs[0] = ubcs[0] | UBCS_TMO; /* UBA times out */ break; } - if (uptr -> FUNC == FNC_READ) M[mpa10] = dbuf[twc10]; + if (uptr->FUNC == FNC_READ) M[mpa10] = dbuf[twc10]; else if (M[mpa10] != dbuf[twc10]) { rpcs2 = rpcs2 | CS2_WCE; /* set error */ break; } @@ -881,7 +887,7 @@ case FNC_READH: /* read headers */ rper1[drv] = rper1[drv] | ER1_PAR; /* set drive error */ update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */ perror ("RP I/O error"); - clearerr (uptr -> fileref); + clearerr (uptr->fileref); return SCPE_IOERR; } case FNC_WRITEH: /* write headers stub */ update_rpcs (CS1_DONE, drv); /* set done */ @@ -913,7 +919,7 @@ if (rper1[drv] | rper2 | rper3) rpds[drv] = rpds[drv] | DS_ERR | DS_ATA; else rpds[drv] = rpds[drv] & ~DS_ERR; rpcs1 = (rpcs1 & ~(CS1_SC | CS1_MCPE | CS1_MBZ | CS1_DRV)) | CS1_DVA | flag; -rpcs1 = rpcs1 | (uptr -> FUNC << CS1_V_FNC); +rpcs1 = rpcs1 | (uptr->FUNC << CS1_V_FNC); if (sim_is_active (uptr)) rpcs1 = rpcs1 | CS1_GO; if (rpcs2 & CS2_ERR) rpcs1 = rpcs1 | CS1_TRE | CS1_SC; else if (rpcs1 & CS1_TRE) rpcs1 = rpcs1 | CS1_SC; @@ -952,10 +958,10 @@ int_req = int_req & ~INT_RP; /* clear intr req */ for (i = 0; i < RP_NUMDR; i++) { uptr = rp_dev.units + i; sim_cancel (uptr); - uptr -> CYL = uptr -> FUNC = 0; - if (uptr -> flags & UNIT_ATT) rpds[i] = (rpds[i] & DS_VV) | - DS_DPR | DS_RDY | DS_MOL | ((uptr -> flags & UNIT_WPRT)? DS_WRL: 0); - else if (uptr -> flags & UNIT_DIS) rpds[i] = 0; + uptr->CYL = uptr->FUNC = 0; + if (uptr->flags & UNIT_ATT) rpds[i] = (rpds[i] & DS_VV) | + DS_DPR | DS_RDY | DS_MOL | ((uptr->flags & UNIT_WPRT)? DS_WRL: 0); + else if (uptr->flags & UNIT_DIS) rpds[i] = 0; else rpds[i] = DS_DPR; rper1[i] = 0; } return SCPE_OK; @@ -968,22 +974,22 @@ t_stat rp_attach (UNIT *uptr, char *cptr) int drv, i, p; t_stat r; -uptr -> capac = drv_tab[GET_DTYPE (uptr -> flags)].size; +uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size; r = attach_unit (uptr, cptr); if (r != SCPE_OK) return r; drv = uptr - rp_dev.units; /* get drv number */ rpds[drv] = DS_ATA | DS_MOL | DS_RDY | DS_DPR | - ((uptr -> flags & UNIT_WPRT)? DS_WRL: 0); + ((uptr->flags & UNIT_WPRT)? DS_WRL: 0); rper1[drv] = 0; update_rpcs (CS1_SC, drv); -if ((uptr -> flags & UNIT_AUTO) == 0) return SCPE_OK; /* autosize? */ -if (fseek (uptr -> fileref, 0, SEEK_END)) return SCPE_OK; -if ((p = ftell (uptr -> fileref)) == 0) return SCPE_OK; +if ((uptr->flags & UNIT_AUTO) == 0) return SCPE_OK; /* autosize? */ +if (fseek (uptr->fileref, 0, SEEK_END)) return SCPE_OK; +if ((p = ftell (uptr->fileref)) == 0) return SCPE_OK; for (i = 0; drv_tab[i].sect != 0; i++) { if (p <= (drv_tab[i].size * (int) sizeof (d10))) { - uptr -> flags = (uptr -> flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE); - uptr -> capac = drv_tab[i].size; + uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE); + uptr->capac = drv_tab[i].size; return SCPE_OK; } } return SCPE_OK; } @@ -1000,7 +1006,7 @@ rpds[drv] = (rpds[drv] & ~(DS_MOL | DS_RDY | DS_WRL | DS_VV | DS_OF)) | if (sim_is_active (uptr)) { /* unit active? */ sim_cancel (uptr); /* cancel operation */ rper1[drv] = rper1[drv] | ER1_OPI; /* set drive error */ - if (uptr -> FUNC >= FNC_WCHK) /* data transfer? */ + if (uptr->FUNC >= FNC_WCHK) /* data transfer? */ rpcs1 = rpcs1 | CS1_DONE | CS1_TRE; } /* set done, err */ update_rpcs (CS1_SC, drv); /* request intr */ return detach_unit (uptr); @@ -1010,8 +1016,8 @@ return detach_unit (uptr); t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { -if (uptr -> flags & UNIT_ATT) return SCPE_ALATT; -uptr -> capac = drv_tab[GET_DTYPE (val)].size; +if (uptr->flags & UNIT_ATT) return SCPE_ALATT; +uptr->capac = drv_tab[GET_DTYPE (val)].size; return SCPE_OK; } @@ -1114,7 +1120,7 @@ static const d10 boot_rom_its[] = { 0254017000000, /* jrst 0(17) ; return */ }; -t_stat rp_boot (int32 unitno) +t_stat rp_boot (int32 unitno, DEVICE *dptr) { int32 i; extern a10 saved_PC; diff --git a/PDP10/pdp10_sys.c b/PDP10/pdp10_sys.c index 30b8ff19..ba7dde3a 100644 --- a/PDP10/pdp10_sys.c +++ b/PDP10/pdp10_sys.c @@ -23,6 +23,7 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 12-Sep-02 RMS Added RX211 support 22-Apr-02 RMS Removed magtape record length error 17-Sep-01 RMS Removed multiconsole support 25-Aug-01 RMS Enabled DZ11 @@ -41,7 +42,7 @@ extern DEVICE cpu_dev, pag_dev; extern DEVICE tim_dev, fe_dev, uba_dev; extern DEVICE ptr_dev, ptp_dev; extern DEVICE rp_dev, tu_dev; -extern DEVICE dz_dev; +extern DEVICE dz_dev, ry_dev; extern DEVICE lp20_dev; extern UNIT cpu_unit; extern REG cpu_reg[]; @@ -72,6 +73,7 @@ DEVICE *sim_devices[] = { &uba_dev, &ptr_dev, &ptp_dev, + &ry_dev, &lp20_dev, &rp_dev, &tu_dev, diff --git a/PDP10/pdp10_tim.c b/PDP10/pdp10_tim.c index 1c13e7f5..f143c70b 100644 --- a/PDP10/pdp10_tim.c +++ b/PDP10/pdp10_tim.c @@ -25,6 +25,7 @@ tim timer subsystem + 29-Jan-02 RMS New data structures 06-Jan-02 RMS Added enable/disable support 02-Dec-01 RMS Fixed bug in ITS PC sampling (found by Dave Conroy) 31-Aug-01 RMS Changed int64 to t_int64 for Windoze @@ -55,6 +56,7 @@ d10 quant = 0; /* ITS quantum */ int32 diagflg = 0; /* diagnostics? */ int32 tmxr_poll = TIM_DELAY * DZ_MULT; /* term mux poll */ +DEVICE tim_dev; t_stat tcu_rd (int32 *data, int32 PA, int32 access); extern t_stat wr_nop (int32 data, int32 PA, int32 access); t_stat tim_svc (UNIT *uptr); @@ -72,7 +74,7 @@ extern int32 pi_eval (void); tim_reg TIM register list */ -DIB tcu_dib = { 1, IOBA_TCU, IOLN_TCU, &tcu_rd, &wr_nop }; +DIB tcu_dib = { IOBA_TCU, IOLN_TCU, &tcu_rd, &wr_nop, 0 }; UNIT tim_unit = { UDATA (&tim_svc, 0, 0), TIM_DELAY }; @@ -90,18 +92,15 @@ MTAB tim_mod[] = { { UNIT_Y2K, 0, "non Y2K OS", "NOY2K", NULL }, { UNIT_Y2K, UNIT_Y2K, "Y2K OS", "Y2K", NULL }, { MTAB_XTD|MTAB_VDV, 000, "ADDRESS", NULL, - NULL, &show_addr, &tcu_dib }, - { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", - &set_enbdis, NULL, &tcu_dib }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", - &set_enbdis, NULL, &tcu_dib }, + NULL, &show_addr, NULL }, { 0 } }; DEVICE tim_dev = { "TIM", &tim_unit, tim_reg, tim_mod, 1, 0, 0, 0, 0, 0, NULL, NULL, &tim_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &tcu_dib, DEV_DISABLE | DEV_UBUS }; /* Timer instructions */ @@ -179,21 +178,21 @@ struct tm *tptr; curtim = time (NULL); /* get time */ tptr = localtime (&curtim); /* decompose */ if (tptr == NULL) return SCPE_NXM; /* Y2K prob? */ -if ((tptr -> tm_year > 99) && !(tim_unit.flags & UNIT_Y2K)) - tptr -> tm_year = 99; +if ((tptr->tm_year > 99) && !(tim_unit.flags & UNIT_Y2K)) + tptr->tm_year = 99; switch ((PA >> 1) & 03) { /* decode PA<3:1> */ case 0: /* year/month/day */ - *data = (((tptr -> tm_year) & 0177) << 9) | - (((tptr -> tm_mon + 1) & 017) << 5) | - ((tptr -> tm_mday) & 037); + *data = (((tptr->tm_year) & 0177) << 9) | + (((tptr->tm_mon + 1) & 017) << 5) | + ((tptr->tm_mday) & 037); return SCPE_OK; case 1: /* hour/minute */ - *data = (((tptr -> tm_hour) & 037) << 8) | - ((tptr -> tm_min) & 077); + *data = (((tptr->tm_hour) & 037) << 8) | + ((tptr->tm_min) & 077); return SCPE_OK; case 2: /* second */ - *data = (tptr -> tm_sec) & 077; + *data = (tptr->tm_sec) & 077; return SCPE_OK; case 3: /* status */ *data = CSR_DONE; diff --git a/PDP10/pdp10_tu.c b/PDP10/pdp10_tu.c index ff2dce3d..23f5c68d 100644 --- a/PDP10/pdp10_tu.c +++ b/PDP10/pdp10_tu.c @@ -25,6 +25,9 @@ tu RH11/TM03/TU45 magtape + 29-Sep-02 RMS Added variable vector support + New data structures + 28-Aug-02 RMS Added end of medium support 30-May-02 RMS Widened POS to 32b 22-Apr-02 RMS Changed record length error code 06-Jan-02 RMS Revised enable/disable support @@ -73,8 +76,9 @@ #define TU_NUMFM 1 /* #formatters */ #define TU_NUMDR 8 /* #drives */ #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_V_PNU (UNIT_V_UF + 1) /* pos not updated */ #define UNIT_WLK (1 << UNIT_V_WLK) -#define UNIT_W_UF 2 /* saved user flags */ +#define UNIT_PNU (1 << UNIT_V_PNU) #define USTAT u3 /* unit status */ #define UDENS u4 /* unit density */ #define UD_UNK 0 /* unknown */ @@ -181,7 +185,7 @@ #define ER_MCP 0000010 /* Mbus cpar err NI */ #define ER_FER 0000020 /* format sel err */ #define ER_MDP 0000040 /* Mbus dpar err NI */ -#define ER_VPE 0000100 /* vert parity err NI */ +#define ER_VPE 0000100 /* vert parity err */ #define ER_CRC 0000200 /* CRC err NI */ #define ER_NSG 0000400 /* non std gap err NI */ #define ER_FCE 0001000 /* frame count err */ @@ -270,9 +274,11 @@ extern d10 *M; /* memory */ extern int32 int_req; +extern int32 int_vec[32]; extern int32 ubmap[UBANUM][UMAP_MEMSIZE]; /* Unibus map */ extern int32 ubcs[UBANUM]; extern UNIT cpu_unit; + int32 tucs1 = 0; /* control/status 1 */ int32 tuwc = 0; /* word count */ int32 tuba = 0; /* bus address */ @@ -301,14 +307,17 @@ int den_test[8] = { /* valid densities */ t_stat tu_rd (int32 *data, int32 PA, int32 access); t_stat tu_wr (int32 data, int32 PA, int32 access); +int32 tu_inta (void); t_stat tu_svc (UNIT *uptr); t_stat tu_reset (DEVICE *dptr); t_stat tu_attach (UNIT *uptr, char *cptr); t_stat tu_detach (UNIT *uptr); -t_stat tu_boot (int32 unitno); +t_stat tu_boot (int32 unitno, DEVICE *dptr); void tu_go (int32 drv); void update_tucs (int32 flag, int32 drv); t_stat tu_vlock (UNIT *uptr, int32 val, char *cptr, void *desc); +t_bool tu_rdlntf (UNIT *uptr, t_mtrlnt *tbc, int32 *err); +t_bool tu_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err); /* TU data structures @@ -318,7 +327,8 @@ t_stat tu_vlock (UNIT *uptr, int32 val, char *cptr, void *desc); tu_mod TU modifier list */ -DIB tu_dib = { 1, IOBA_TU, IOLN_TU, &tu_rd, &tu_wr }; +DIB tu_dib = { IOBA_TU, IOLN_TU, &tu_rd, &tu_wr, + 1, IVCL (TU), VEC_TU, { &tu_inta } }; UNIT tu_unit[] = { { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, @@ -351,8 +361,6 @@ REG tu_reg[] = { { URDATA (UST, tu_unit[0].USTAT, 8, 17, 0, TU_NUMDR, 0) }, { URDATA (POS, tu_unit[0].pos, 8, 32, 0, TU_NUMDR, PV_LEFT | REG_RO) }, - { URDATA (FLG, tu_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, - TU_NUMDR, REG_HRO) }, { ORDATA (LOG, tu_log, 8), REG_HIDDEN }, { NULL } }; @@ -360,14 +368,17 @@ MTAB tu_mod[] = { { UNIT_WLK, 0, "write enabled", "WRITEENABLED", &tu_vlock }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &tu_vlock }, { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, - NULL, &show_addr, &tu_dib }, + NULL, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, + NULL, &show_vec, NULL }, { 0 } }; DEVICE tu_dev = { "TU", tu_unit, tu_reg, tu_mod, TU_NUMDR, 10, 31, 1, 8, 8, NULL, NULL, &tu_reset, - &tu_boot, &tu_attach, &tu_detach }; + &tu_boot, &tu_attach, &tu_detach, + &tu_dib, DEV_UBUS }; /* I/O dispatch routine, I/O addresses 17772440 - 17772472 */ @@ -560,7 +571,7 @@ case FNC_FCLR: /* drive clear */ tutc = tutc & ~TC_FCS; /* clear fc status */ tufs = tufs & ~(FS_SAT | FS_SSC | FS_ID | FS_TMK | FS_ERR); sim_cancel (uptr); /* reset drive */ - uptr -> USTAT = 0; + uptr->USTAT = 0; case FNC_NOP: tucs1 = tucs1 & ~CS1_GO; /* no operation */ return; @@ -572,19 +583,19 @@ case FNC_RIP: /* read-in preset */ return; case FNC_UNLOAD: /* unload */ - if ((uptr -> flags & UNIT_ATT) == 0) { /* unattached? */ + if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ tuer = tuer | ER_UNS; break; } detach_unit (uptr); - uptr -> USTAT = FS_REW; + uptr->USTAT = FS_REW; sim_activate (uptr, tu_time); tucs1 = tucs1 & ~CS1_GO; return; case FNC_REWIND: - if ((uptr -> flags & UNIT_ATT) == 0) { /* unattached? */ + if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ tuer = tuer | ER_UNS; break; } - uptr -> USTAT = FS_PIP | FS_REW; + uptr->USTAT = FS_PIP | FS_REW; sim_activate (uptr, tu_time); tucs1 = tucs1 & ~CS1_GO; return; @@ -592,13 +603,13 @@ case FNC_REWIND: case FNC_SPACEF: space_test = FS_EOT; case FNC_SPACER: - if ((uptr -> flags & UNIT_ATT) == 0) { /* unattached? */ + if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ tuer = tuer | ER_UNS; break; } if ((tufs & space_test) || ((tutc & TC_FCS) == 0)) { tuer = tuer | ER_NXF; break; } - uptr -> USTAT = FS_PIP; + uptr->USTAT = FS_PIP; goto GO_XFER; case FNC_WCHKR: /* wchk = read */ @@ -615,13 +626,13 @@ case FNC_WRITE: /* write */ break; } case FNC_WREOF: /* write tape mark */ case FNC_ERASE: /* erase */ - if (uptr -> flags & UNIT_WPRT) { /* write locked? */ + if (uptr->flags & UNIT_WPRT) { /* write locked? */ tuer = tuer | ER_NXF; break; } case FNC_WCHKF: /* wchk = read */ case FNC_READF: /* read */ DATA_XFER: - if ((uptr -> flags & UNIT_ATT) == 0) { /* unattached? */ + if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ tuer = tuer | ER_UNS; break; } if (fmt_test[GET_FMT (tutc)] == 0) { /* invalid format? */ @@ -630,11 +641,11 @@ DATA_XFER: if (den_test[den] == 0) { /* invalid density? */ tuer = tuer | ER_NXF; break; } - if (uptr -> UDENS == UD_UNK) uptr -> UDENS = den; /* set dens */ -/* else if (uptr -> UDENS != den) { /* density mismatch? */ + if (uptr->UDENS == UD_UNK) uptr->UDENS = den; /* set dens */ +/* else if (uptr->UDENS != den) { /* density mismatch? */ /* tuer = tuer | ER_NXF; /* break; } */ - uptr -> USTAT = 0; + uptr->USTAT = 0; tucs1 = tucs1 & ~CS1_DONE; /* clear done */ GO_XFER: tucs2 = tucs2 & ~CS2_ERR; /* clear errors */ @@ -662,17 +673,19 @@ return; t_stat tu_svc (UNIT *uptr) { -int32 f, fmt, i, j, k, err, wc10, ba10; +int32 f, fmt, i, j, k, err, wc10, ba10, pnu; int32 ba, fc, wc, drv, mpa10, vpn; d10 val, v[4]; -t_mtrlnt tbc; -static t_mtrlnt bceof = { 0 }; +t_mtrlnt abc, tbc; +static t_mtrlnt bceof = { MTR_TMK }; static uint8 xbuf[XBUFLNT + 4]; -drv = uptr - tu_dev.units; -if (uptr -> USTAT & FS_REW) { /* rewind or unload? */ - uptr -> pos = 0; /* update position */ - uptr -> USTAT = 0; /* clear status */ +drv = uptr - tu_dev.units; /* get drive # */ +pnu = MT_TST_PNU (uptr); /* get pos not upd */ +MT_CLR_PNU (uptr); /* and clear */ +if (uptr->USTAT & FS_REW) { /* rewind or unload? */ + uptr->pos = 0; /* update position */ + uptr->USTAT = 0; /* clear status */ tufs = tufs | FS_ATA | FS_SSC; update_tucs (CS1_SC, drv); /* update status */ return SCPE_OK; } @@ -685,55 +698,42 @@ fc = 0200000 - tufc; /* get frame count */ wc10 = wc >> 1; /* 10 word count */ ba10 = ba >> 2; /* 10 word addr */ err = 0; -uptr -> USTAT = 0; /* clear status */ +uptr->USTAT = 0; /* clear status */ switch (f) { /* case on function */ /* Unit service - non-data transfer commands - set ATA when done */ case FNC_SPACEF: /* space forward */ do { tufc = (tufc + 1) & 0177777; /* incr fc */ - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); - fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - if ((err = ferror (uptr -> fileref)) || /* error or eof? */ - feof (uptr -> fileref)) { - uptr -> USTAT = FS_EOT; - break; } - if (tbc == 0) { /* zero bc? */ - tufs = tufs | FS_TMK; - uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); - break; } - uptr -> pos = uptr -> pos + ((MTRL (tbc) + 1) & ~1) + + if (tu_rdlntf (uptr, &tbc, &err)) break;/* read rec lnt, err? */ + uptr->pos = uptr->pos + ((MTRL (tbc) + 1) & ~1) + (2 * sizeof (t_mtrlnt)); } while (tufc != 0); if (tufc) tuer = tuer | ER_FCE; else tutc = tutc & ~TC_FCS; tufs = tufs | FS_ATA; break; + case FNC_SPACER: /* space reverse */ do { tufc = (tufc + 1) & 0177777; /* incr wc */ - fseek (uptr -> fileref, uptr -> pos - sizeof (t_mtrlnt), - SEEK_SET); - fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - if ((err = ferror (uptr -> fileref)) || /* error or eof? */ - feof (uptr -> fileref)) { - uptr -> pos = 0; - break; } - if (tbc == 0) { /* start of prv file? */ - tufs = tufs | FS_TMK; - uptr -> pos = uptr -> pos - sizeof (t_mtrlnt); - break; } - uptr -> pos = uptr -> pos - ((MTRL (tbc) + 1) & ~1) - - (2 * sizeof (t_mtrlnt)); } - while ((tufc != 0) && (uptr -> pos)); + if (pnu) pnu = 0; /* pos not upd? */ + else { if (tu_rdlntr (uptr, &tbc, &err)) break; + uptr->pos = uptr->pos - ((MTRL (tbc) + 1) & ~1) - + (2 * sizeof (t_mtrlnt)); } } + while (tufc != 0); if (tufc) tuer = tuer | ER_FCE; else tutc = tutc & ~TC_FCS; tufs = tufs | FS_ATA; break; + case FNC_WREOF: - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); - fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr -> fileref); - err = ferror (uptr -> fileref); - uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); /* update position */ + fseek (uptr->fileref, uptr->pos, SEEK_SET); + fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr->fileref); + tufs = tufs | FS_ATA; + if (err = ferror (uptr->fileref)) MT_SET_PNU (uptr); + else uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* update position */ + break; + case FNC_ERASE: tufs = tufs | FS_ATA; break; @@ -754,29 +754,23 @@ case FNC_ERASE: case FNC_READF: /* read */ case FNC_WCHKF: /* wcheck = read */ tufc = 0; /* clear frame count */ - if ((uptr -> UDENS == TC_1600) && (uptr -> pos == 0)) + if ((uptr->UDENS == TC_1600) && (uptr->pos == 0)) tufs = tufs | FS_ID; /* PE BOT? ID burst */ TXFR (ba, wc, 0); /* validate transfer */ - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); - fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - if ((err = ferror (uptr -> fileref)) || /* error or eof? */ - (feof (uptr -> fileref))) { - uptr -> USTAT = FS_EOT; - break; } + if (tu_rdlntf (uptr, &tbc, &err)) break; /* read rec lnt, err? */ + fseek (uptr->fileref, uptr->pos, SEEK_SET); if (MTRF (tbc)) { /* bad record? */ tuer = tuer | ER_CRC; /* set error flag */ - uptr -> pos = uptr -> pos + ((MTRL (tbc) + 1) & ~1) + + uptr->pos = uptr->pos + ((MTRL (tbc) + 1) & ~1) + (2 * sizeof (t_mtrlnt)); break; } - if (tbc == 0) { /* tape mark? */ - tufs = tufs | FS_TMK; - uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); - break; } if (tbc > XBUFLNT) return SCPE_MTRLNT; /* bad rec length? */ - i = fxread (xbuf, sizeof (int8), tbc, uptr -> fileref); - for ( ; i < tbc + 4; i++) xbuf[i] = 0; /* fill/pad with 0's */ - err = ferror (uptr -> fileref); - for (i = j = 0; (i < wc10) && (j < tbc); i++) { + abc = fxread (xbuf, sizeof (int8), tbc, uptr->fileref); + if (err = ferror (uptr->fileref)) { /* error? */ + MT_SET_PNU (uptr); /* pos not upd */ + break; } + for ( ; abc < tbc + 4; abc++) xbuf[abc] = 0; /* fill/pad with 0's */ + for (i = j = 0; (i < wc10) && (j < ((int32) tbc)); i++) { if ((i == 0) || NEWPAGE (ba10 + i, 0)) { /* map new page */ MAPM (ba10 + i, mpa10, 0); } for (k = 0; k < 4; k++) v[k] = xbuf[j++]; @@ -784,15 +778,15 @@ case FNC_WCHKF: /* wcheck = read */ if (fmt == TC_10C) val = val | ((d10) xbuf[j++] & 017); if (f == FNC_READF) M[mpa10] = val; mpa10 = mpa10 + 1; } /* end for */ - uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) + (2 * sizeof (t_mtrlnt)); + uptr->pos = uptr->pos + ((tbc + 1) & ~1) + (2 * sizeof (t_mtrlnt)); tufc = tbc & 0177777; tuwc = (tuwc + (i << 1)) & 0177777; ba = ba + (i << 2); break; - + case FNC_WRITE: /* write */ TXFR (ba, wc, 0); /* validate transfer */ - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); + fseek (uptr->fileref, uptr->pos, SEEK_SET); for (i = j = 0; (i < wc10) && (j < fc); i++) { if ((i == 0) || NEWPAGE (ba10 + i, 0)) { /* map new page */ MAPM (ba10 + i, mpa10, 0); } @@ -804,41 +798,34 @@ case FNC_WRITE: /* write */ if (fmt == TC_10C) xbuf[j++] = (uint8) (val & 017); mpa10 = mpa10 + 1; } /* end for */ if (j < fc) fc = j; /* short record? */ - fxwrite (&fc, sizeof (t_mtrlnt), 1, uptr -> fileref); - fxwrite (xbuf, sizeof (int8), (fc + 1) & ~1, uptr -> fileref); - fxwrite (&fc, sizeof (t_mtrlnt), 1, uptr -> fileref); - err = ferror (uptr -> fileref); - uptr -> pos = uptr -> pos + ((fc + 1) & ~1) + (2 * sizeof (t_mtrlnt)); - tufc = (tufc + fc) & 0177777; - if (tufc == 0) tutc = tutc & ~TC_FCS; - tuwc = (tuwc + (i << 1)) & 0177777; - ba = ba + (i << 2); + fxwrite (&fc, sizeof (t_mtrlnt), 1, uptr->fileref); + fxwrite (xbuf, sizeof (int8), (fc + 1) & ~1, uptr->fileref); + fxwrite (&fc, sizeof (t_mtrlnt), 1, uptr->fileref); + if (err = ferror (uptr->fileref)) MT_SET_PNU (uptr); + else { uptr->pos = uptr->pos + ((fc + 1) & ~1) + + (2 * sizeof (t_mtrlnt)); + tufc = (tufc + fc) & 0177777; + if (tufc == 0) tutc = tutc & ~TC_FCS; + tuwc = (tuwc + (i << 1)) & 0177777; + ba = ba + (i << 2); } break; - + case FNC_READR: /* read reverse */ case FNC_WCHKR: /* wcheck = read */ tufc = 0; /* clear frame count */ TXFR (ba, wc, 1); /* validate xfer rev */ - fseek (uptr -> fileref, uptr -> pos - sizeof (t_mtrlnt), SEEK_SET); - fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - if ((err = ferror (uptr -> fileref)) || /* error or eof? */ - (feof (uptr -> fileref))) { - uptr -> USTAT = FS_EOT; - break; } + if (tu_rdlntr (uptr, &tbc, &err)) break; /* read rec lnt, err? */ if (MTRF (tbc)) { /* bad record? */ tuer = tuer | ER_CRC; /* set error flag */ - uptr -> pos = uptr -> pos - ((MTRL (tbc) + 1) & ~1) - + uptr->pos = uptr->pos - ((MTRL (tbc) + 1) & ~1) - (2 * sizeof (t_mtrlnt)); break; } - if (tbc == 0) { /* tape mark? */ - tufs = tufs | FS_TMK; - uptr -> pos = uptr -> pos - sizeof (t_mtrlnt); - break; } if (tbc > XBUFLNT) return SCPE_MTRLNT; /* bad rec length? */ - fseek (uptr -> fileref, uptr -> pos - sizeof (t_mtrlnt) + fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt) - ((tbc + 1) & ~1), SEEK_SET); - fxread (xbuf + 4, sizeof (int8), tbc, uptr -> fileref); + fxread (xbuf + 4, sizeof (int8), tbc, uptr->fileref); for (i = 0; i < 4; i++) xbuf[i] = 0; + err = ferror (uptr->fileref); /* set err but finish */ for (i = 0, j = tbc + 4; (i < wc10) && (j >= 4); i++) { if ((i == 0) || NEWPAGE (ba10 - i, PAG_M_OFF)) { /* map page */ MAPM (ba10 - i, mpa10, UMAP_RRV); } @@ -847,23 +834,21 @@ case FNC_WCHKR: /* wcheck = read */ val = val | (v[0] << 4) | (v[1] << 12) | (v[2] << 20) | (v[3] << 28); if (f == FNC_READR) M[mpa10] = val; mpa10 = mpa10 - 1; } /* end for */ - uptr -> pos = uptr -> pos - ((tbc + 1) & ~1) - (2 * sizeof (t_mtrlnt)); + uptr->pos = uptr->pos - ((tbc + 1) & ~1) - (2 * sizeof (t_mtrlnt)); tufc = tbc & 0177777; tuwc = (tuwc + (i << 1)) & 0177777; ba = ba - (i << 2); break; } /* end case */ -/* Unit service, continued */ - tucs1 = (tucs1 & ~CS1_UAE) | ((ba >> (16 - CS1_V_UAE)) & CS1_UAE); tuba = ba & 0177777; /* update mem addr */ tucs1 = tucs1 & ~CS1_GO; /* clear go */ if (err != 0) { /* I/O error */ - tuer = tuer | ER_CRC; /* flag error */ + tuer = tuer | ER_VPE; /* flag error */ update_tucs (CS1_DONE | CS1_TRE, drv); /* set done, err */ perror ("TU I/O error"); - clearerr (uptr -> fileref); - return IORETURN (tu_stopioe, SCPE_IOERR); } + clearerr (uptr->fileref); + return (tu_stopioe? SCPE_IOERR: SCPE_OK); } update_tucs (CS1_DONE, drv); return SCPE_OK; } @@ -910,6 +895,52 @@ tucs1 = tucs1 & ~CS1_IE; /* clear int enable */ tuiff = 0; /* clear CSTB INTR */ return VEC_TU; /* acknowledge */ } + +/* Read record length forward - return T if error, EOM, or EOF */ + +t_bool tu_rdlntf (UNIT *uptr, t_mtrlnt *tbc, int32 *err) +{ +fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set tape pos */ +fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); /* read rec lnt */ +if (*err = ferror (uptr->fileref)) { /* error? */ + tuer = tuer | ER_VPE; /* parity error */ + MT_SET_PNU (uptr); /* pos not updated */ + return TRUE; } +if (feof (uptr->fileref) || (*tbc == MTR_EOM)) { /* eof or eom? */ + tuer = tuer | ER_OPI; /* incomplete */ + MT_SET_PNU (uptr); /* pos not updated */ + return TRUE; } +if (*tbc == MTR_TMK) { /* tape mark? */ + tufs = tufs | FS_TMK; + uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* spc over tmk */ + return TRUE; } +return FALSE; +} + +/* Read record length reverse - return T if error, EOM, or EOF */ + +t_bool tu_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err) +{ +if (uptr->pos < sizeof (t_mtrlnt)) return TRUE; +fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt), SEEK_SET); +fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); +if (*err = ferror (uptr->fileref)) { /* error? */ + tuer = tuer | ER_VPE; /* parity error */ + return TRUE; } +if (feof (uptr->fileref)) { /* eof? */ + tuer = tuer | ER_OPI; /* incomplete */ + return TRUE; } +if (*tbc == MTR_EOM) { /* eom? */ + tuer = tuer | ER_OPI; /* incomplete */ + uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over eom */ + return TRUE; } +if (*tbc == MTR_TMK) { /* tape mark? */ + tufs = tufs | FS_TMK; + uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over tmk */ + return TRUE; } +*tbc = MTRL (*tbc); /* ignore error flag */ +return FALSE; +} /* Reset routine */ @@ -927,8 +958,9 @@ tuiff = 0; /* clear CSTB INTR */ int_req = int_req & ~INT_TU; /* clear interrupt */ for (u = 0; u < TU_NUMDR; u++) { /* loop thru units */ uptr = tu_dev.units + u; + MT_CLR_PNU (uptr); /* clear pos flag */ sim_cancel (uptr); /* cancel activity */ - uptr -> USTAT = 0; } + uptr->USTAT = 0; } return SCPE_OK; } @@ -941,8 +973,9 @@ t_stat r; r = attach_unit (uptr, cptr); if (r != SCPE_OK) return r; -uptr -> USTAT = 0; /* clear unit status */ -uptr -> UDENS = UD_UNK; /* unknown density */ +MT_CLR_PNU (uptr); +uptr->USTAT = 0; /* clear unit status */ +uptr->UDENS = UD_UNK; /* unknown density */ tufs = tufs | FS_ATA | FS_SSC; /* set attention */ if ((GET_FMTR (tucs2) == 0) && (GET_DRV (tutc) == drv)) /* selected drive? */ tufs = tufs | FS_SAT; /* set slave attn */ @@ -959,9 +992,10 @@ int32 drv = uptr - tu_dev.units; if (sim_is_active (uptr)) { /* unit active? */ sim_cancel (uptr); /* cancel operation */ tuer = tuer | ER_UNS; /* set formatter error */ - if ((uptr -> USTAT & FS_REW) == 0) /* data transfer? */ + if ((uptr->USTAT & FS_REW) == 0) /* data transfer? */ tucs1 = tucs1 | CS1_DONE | CS1_TRE; } /* set done, err */ -uptr -> USTAT = 0; /* clear status flags */ +MT_CLR_PNU (uptr); +uptr->USTAT = 0; /* clear status flags */ tufs = tufs | FS_ATA | FS_SSC; /* set attention */ update_tucs (CS1_SC, drv); /* update status */ return detach_unit (uptr); @@ -1055,7 +1089,7 @@ static const d10 boot_rom_its[] = { 0254200377052, /* halt */ 0254017000000, /* jrst 0(17) ; return */ }; -t_stat tu_boot (int32 unitno) +t_stat tu_boot (int32 unitno, DEVICE *dptr) { int32 i; extern a10 saved_PC; diff --git a/PDP11/pdp11_cis.c b/PDP11/pdp11_cis.c index 80a4bbf4..96dbbb8c 100644 --- a/PDP11/pdp11_cis.c +++ b/PDP11/pdp11_cis.c @@ -25,6 +25,9 @@ This module simulates the PDP-11 commercial instruction set (CIS). + 17-Oct-02 RMS Fixed compiler warning (found by Hans Pufal) + 08-Oct-02 RMS Fixed macro definitions + The commercial instruction set consists of three instruction formats: +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ register operands @@ -138,11 +141,11 @@ /* Condition code macros */ -#define GET_BIT(ir,n) (((ir) >> n) & 1) +#define GET_BIT(ir,n) (((ir) >> (n)) & 1) #define GET_SIGN_L(ir) GET_BIT((ir), 31) #define GET_SIGN_W(ir) GET_BIT((ir), 15) #define GET_SIGN_B(ir) GET_BIT((ir), 7) -#define GET_Z(ir) (ir == 0) +#define GET_Z(ir) ((ir) == 0) /* Decimal string structure */ @@ -151,8 +154,8 @@ #define MAXDVAL 429496730 /* 2^32 / 10 */ struct dstr { - unsigned int32 sign; - unsigned int32 val[DSTRLNT]; }; + unsigned int32 sign; + unsigned int32 val[DSTRLNT]; }; typedef struct dstr DSTR; @@ -354,9 +357,6 @@ for (i = j = 0; (i < MAXOPN) && opntab[op][i]; i++) { /* parse operands */ break; } /* end case */ } /* end for */ switch (op) { /* case on opcode */ -default: - setTRAP (TRAP_ILL); - return; /* MOVC, MOVTC, MOVCI, MOVTCI @@ -891,7 +891,10 @@ CVTLx: dst.val[i / 8] = dst.val[i / 8] | (digit << ((i % 8) * 4)); } V = C = 0; WriteDstr (A1, &dst, op); /* write result */ - return; } + return; +default: + setTRAP (TRAP_ILL); + break; } return; } /* end cis */ @@ -934,25 +937,25 @@ if (flag & PACKED) { /* packed? */ if ((i == end) && ((lnt & 1) == 0)) c = c & 0xF; if (c >= 0xA0) c = c & 0xF; /* check hi digit */ if ((c & 0xF) >= 0xA) c = c & 0xF0; /* check lo digit */ - src -> val[i / 4] = src -> val[i / 4] | (c << ((i % 4) * 8)); + src->val[i / 4] = src->val[i / 4] | (c << ((i % 4) * 8)); } /* end for */ - if ((t == 0xB) || (t == 0xD)) src -> sign = 1; /* if -, set sign */ - src -> val[0] = src -> val[0] & ~0xF; /* clear sign */ + if ((t == 0xB) || (t == 0xD)) src->sign = 1; /* if -, set sign */ + src->val[0] = src->val[0] & ~0xF; /* clear sign */ } /* end packed */ else { /* numeric */ - if (type >= TS) src -> sign = (ReadB ((((type == TS)? + if (type >= TS) src->sign = (ReadB ((((type == TS)? dscr[1] + lnt: dscr[1] - 1) & 0177777) | dsenable) == '-'); for (i = 1; i <= lnt; i++) { /* loop thru string */ c = ReadB (((dscr[1] + lnt - i) & 0177777) | dsenable); if ((i == 1) && (type == XZ) && ((c & 0xF0) == 0x70)) - src -> sign = 1; /* signed zoned */ + src->sign = 1; /* signed zoned */ else if (((i == 1) && (type == TO)) || ((i == lnt) && (type == LO))) { c = overbin[c & 0177]; /* get sign and digit */ - src -> sign = c >> 7; } /* set sign */ + src->sign = c >> 7; } /* set sign */ c = c & 0xF; /* get digit */ if (c > 9) c = 0; /* range check */ - src -> val[i / 8] = src -> val[i / 8] | (c << ((i % 8) * 4)); + src->val[i / 8] = src->val[i / 8] | (c << ((i % 8) * 4)); } /* end for */ } /* end numeric */ return TestDstr (src); /* clean -0 */ @@ -995,30 +998,30 @@ limit = lnt / 8; /* limit for test */ for (i = 0; i < DSTRLNT; i++) { /* loop thru value */ if (i == limit) mask = masktab[lnt % 8]; /* at limit, get mask */ else if (i > limit) mask = 0xFFFFFFFF; /* beyond, all ovflo */ - if (dst -> val[i] & mask) V = 1; /* test for ovflo */ - if (dst -> val[i] = dst -> val[i] & ~mask) Z = 0; } /* test nz */ -dst -> sign = dst -> sign & ~unsignedtab[type] & ~(Z & ~V); -N = dst -> sign & ~Z; /* N = sign, if ~zero */ + if (dst->val[i] & mask) V = 1; /* test for ovflo */ + if (dst->val[i] = dst->val[i] & ~mask) Z = 0; } /* test nz */ +dst->sign = dst->sign & ~unsignedtab[type] & ~(Z & ~V); +N = dst->sign & ~Z; /* N = sign, if ~zero */ if (flag & PACKED) { /* packed? */ end = lnt / 2; /* end of string */ - if (type == UP) dst -> val[0] = dst -> val[0] | 0xF; - else dst -> val[0] = dst -> val[0] | 0xC | dst -> sign; + if (type == UP) dst->val[0] = dst->val[0] | 0xF; + else dst->val[0] = dst->val[0] | 0xC | dst->sign; for (i = 0; i <= end; i++) { /* store string */ - c = (dst -> val[i / 4] >> ((i % 4) * 8)) & 0xFF; + c = (dst->val[i / 4] >> ((i % 4) * 8)) & 0xFF; WriteB (c, ((dscr[1] + end - i) & 0177777)); } /* end for */ } /* end packed */ else { - if (type >= TS) WriteB (dst -> sign? '-': '+', (((type == TS)? + if (type >= TS) WriteB (dst->sign? '-': '+', (((type == TS)? dscr[1] + lnt: dscr[1] - 1) & 0177777) | dsenable); for (i = 1; i <= lnt; i++) { /* store string */ - c = (dst -> val[i / 8] >> ((i % 8) * 4)) & 0xF; /* get digit */ - if ((i == 1) && (type == XZ) && dst -> sign) + c = (dst->val[i / 8] >> ((i % 8) * 4)) & 0xF; /* get digit */ + if ((i == 1) && (type == XZ) && dst->sign) c = c | 0x70; /* signed zoned */ else if (((i == 1) && (type == TO)) || ((i == lnt) && (type == LO))) - c = binover[dst -> sign][c]; /* get sign and digit */ + c = binover[dst->sign][c]; /* get sign and digit */ else c = c | 0x30; /* default */ WriteB (c, ((dscr[1] + lnt - i) & 0177777)); } /* end for */ @@ -1070,14 +1073,14 @@ int32 i; unsigned int32 sm1, sm2, tm1, tm2, tm3, tm4; for (i = 0; i < DSTRLNT; i++) { /* loop low to high */ - tm1 = s1 -> val[i] ^ (s2 -> val[i] + cy); /* xor operands */ - sm1 = s1 -> val[i] + (s2 -> val[i] + cy); /* sum operands */ + tm1 = s1->val[i] ^ (s2->val[i] + cy); /* xor operands */ + sm1 = s1->val[i] + (s2->val[i] + cy); /* sum operands */ sm2 = sm1 + 0x66666666; /* force carry out */ - cy = ((sm1 < s1 -> val[i]) || (sm2 < sm1)); /* check for overflow */ + cy = ((sm1 < s1->val[i]) || (sm2 < sm1)); /* check for overflow */ tm2 = tm1 ^ sm2; /* get carry flags */ tm3 = (tm2 >> 3) | (cy << 29); /* compute adjustment */ tm4 = 0x22222222 & ~tm3; /* clear where carry */ - ds -> val[i] = sm2 - (3 * tm4); } /* final result */ + ds->val[i] = sm2 - (3 * tm4); } /* final result */ return cy; } @@ -1098,7 +1101,7 @@ void SubDstr (DSTR *s1, DSTR *s2, DSTR *ds) int32 i; DSTR compl; -for (i = 0; i < DSTRLNT; i++) compl.val[i] = 0x99999999 - s1 -> val[i]; +for (i = 0; i < DSTRLNT; i++) compl.val[i] = 0x99999999 - s1->val[i]; AddDstr (&compl, s2, ds, 1); /* s1 + ~s2 + 1 */ return; } @@ -1116,8 +1119,8 @@ int32 CmpDstr (DSTR *s1, DSTR *s2) int32 i; for (i = DSTRMAX; i >=0; i--) { - if (s1 -> val[i] > s2 -> val[i]) return 1; - if (s1 -> val[i] < s2 -> val[i]) return -1; } + if (s1->val[i] > s2->val[i]) return 1; + if (s1->val[i] < s2->val[i]) return -1; } return 0; } @@ -1133,8 +1136,8 @@ int32 TestDstr (DSTR *dsrc) { int32 i; -for (i = DSTRMAX; i >= 0; i--) if (dsrc -> val[i]) return (i + 1); -dsrc -> sign = 0; +for (i = DSTRMAX; i >= 0; i--) if (dsrc->val[i]) return (i + 1); +dsrc->sign = 0; return 0; } @@ -1150,7 +1153,7 @@ int32 LntDstr (DSTR *dsrc, int32 nz) int32 i; for (i = 7; i > 0; i--) { - if ((dsrc -> val[nz - 1] >> (i * 4)) & 0xF) break; } + if ((dsrc->val[nz - 1] >> (i * 4)) & 0xF) break; } return ((nz - 1) * 8) + i; } @@ -1187,8 +1190,8 @@ int32 i; if (sc) { for (i = 0; i < DSTRLNT; i++) { - if ((i + sc) < DSTRLNT) dsrc -> val[i] = dsrc -> val[i + sc]; - else dsrc -> val[i] = 0; } } + if ((i + sc) < DSTRLNT) dsrc->val[i] = dsrc->val[i + sc]; + else dsrc->val[i] = 0; } } return; } @@ -1206,9 +1209,9 @@ int32 i, c; c = 0; if (sc) { for (i = DSTRMAX; i >= 0; i--) { - if (i > (DSTRMAX - sc)) c = c | dsrc -> val[i]; - if ((i - sc) >= 0) dsrc -> val[i] = dsrc -> val[i - sc]; - else dsrc -> val[i] = 0; } } + if (i > (DSTRMAX - sc)) c = c | dsrc->val[i]; + if ((i - sc) >= 0) dsrc->val[i] = dsrc->val[i - sc]; + else dsrc->val[i] = 0; } } return c; } @@ -1227,8 +1230,8 @@ int32 i, s, rs, nc; if (s = sc * 4) { rs = 32 - s; for (i = DSTRMAX; i >= 0; i--) { - nc = dsrc -> val[i]; - dsrc -> val[i] = ((dsrc -> val[i] >> s) | + nc = dsrc->val[i]; + dsrc->val[i] = ((dsrc->val[i] >> s) | (cin << rs)) & 0xFFFFFFFF; cin = nc; } return cin; } @@ -1250,8 +1253,8 @@ int32 i, s, rs, nc; if (s = sc * 4) { rs = 32 - s; for (i = 0; i < DSTRLNT; i++) { - nc = dsrc -> val[i]; - dsrc -> val[i] = ((dsrc -> val[i] << s) | + nc = dsrc->val[i]; + dsrc->val[i] = ((dsrc->val[i] << s) | (cin >> rs)) & 0xFFFFFFFF; cin = nc; } return cin; } diff --git a/PDP11/pdp11_cpu.c b/PDP11/pdp11_cpu.c index c93a47f7..9a37cc5d 100644 --- a/PDP11/pdp11_cpu.c +++ b/PDP11/pdp11_cpu.c @@ -25,6 +25,10 @@ cpu PDP-11 CPU (J-11 microprocessor) + 17-Oct-02 RMS Fixed bug in examine/deposit (found by Hans Pufal) + 08-Oct-02 RMS Revised to build dib_tab dynamically + Added SHOW IOSPACE + 09-Sep-02 RMS Added KW11P support 14-Jul-02 RMS Fixed bug in MMR0 error status load 03-Jun-02 RMS Fixed relocation add overflow, added PS<15:12> = 1111 special case logic to MFPI and removed it from MTPI @@ -184,11 +188,10 @@ Because the PSW can be explicitly written as address 17777776, all instructions must update PSW before executing their last write. - 4. Adding I/O devices. This requires modifications to three modules: + 4. Adding I/O devices. These modules must be modified: - pdp11_defs.h add interrupt request definitions - pdp11_io.c add to dib_tab - pdp11_sys.c add to sim_devices + pdp11_defs.h add device address and interrupt definitions + pdp11_sys.c add to sim_devices table entry */ /* Definitions */ @@ -277,9 +280,10 @@ int32 dsmask[4] = { MMR3_KDS, MMR3_SDS, 0, MMR3_UDS }; /* dspace enables */ extern int32 sim_interval; extern UNIT *sim_clock_queue; -extern UNIT clk_unit; +extern UNIT clk_unit, pclk_unit; extern int32 sim_int_char; extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern DEVICE *sim_devices[]; /* Function declarations */ @@ -287,6 +291,7 @@ t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_set_bus (UNIT *uptr, int32 val, char *cptr, void *desc); int32 GeteaB (int32 spec); int32 GeteaW (int32 spec); int32 relocR (int32 addr); @@ -310,6 +315,8 @@ t_stat MMR3_wr (int32 data, int32 addr, int32 access); t_stat ubm_rd (int32 *data, int32 addr, int32 access); t_stat ubm_wr (int32 data, int32 addr, int32 access); +extern t_stat build_dib_tab (int32 ubm); +extern t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc); extern t_stat iopageR (int32 *data, uint32 addr, int32 access); extern t_stat iopageW (int32 data, uint32 addr, int32 access); extern int32 calc_ints (int32 nipl, int32 trq); @@ -336,12 +343,12 @@ int32 trap_clear[TRAP_V_MAX] = { /* trap clears */ /* Fixed I/O address table entries */ -DIB cpu0_dib = { 1, IOBA_CPU, IOLN_CPU, &CPU_rd, &CPU_wr }; -DIB cpu1_dib = { 1, IOBA_APR, IOLN_APR, &APR_rd, &APR_wr }; -DIB cpu2_dib = { 1, IOBA_APR1, IOLN_APR1, &APR_rd, &APR_wr }; -DIB cpu3_dib = { 1, IOBA_SRMM, IOLN_SRMM, &SR_MMR012_rd, &SR_MMR012_wr }; -DIB cpu4_dib = { 1, IOBA_MMR3, IOLN_MMR3, &MMR3_rd, &MMR3_wr }; -DIB ubm_dib = { 0, IOBA_UBM, IOLN_UBM, &ubm_rd, &ubm_wr }; +DIB cpu0_dib = { IOBA_CPU, IOLN_CPU, &CPU_rd, &CPU_wr, 0 }; +DIB cpu1_dib = { IOBA_APR, IOLN_APR, &APR_rd, &APR_wr, 0 }; +DIB cpu2_dib = { IOBA_APR1, IOLN_APR1, &APR_rd, &APR_wr, 0 }; +DIB cpu3_dib = { IOBA_SRMM, IOLN_SRMM, &SR_MMR012_rd, &SR_MMR012_wr, 0 }; +DIB cpu4_dib = { IOBA_MMR3, IOLN_MMR3, &MMR3_rd, &MMR3_wr, 0 }; +DIB ubm_dib = { IOBA_UBM, IOLN_UBM, &ubm_rd, &ubm_wr, 0 }; /* CPU data structures @@ -395,7 +402,7 @@ REG cpu_reg[] = { { ORDATA (STOP_TRAPS, stop_trap, TRAP_V_MAX) }, { FLDATA (STOP_VECA, stop_vecabort, 0) }, { FLDATA (STOP_SPA, stop_spabort, 0) }, - { ORDATA (DBGLOG, cpu_log, 16), REG_HIDDEN }, + { HRDATA (DBGLOG, cpu_log, 16), REG_HIDDEN }, { ORDATA (FAC0H, FR[0].h, 32) }, { ORDATA (FAC0L, FR[0].l, 32) }, { ORDATA (FAC1H, FR[1].h, 32) }, @@ -512,10 +519,6 @@ REG cpu_reg[] = { { GRDATA (UDPAR7, APRFILE[077], 8, 16, 16) }, { GRDATA (UDPDR7, APRFILE[077], 8, 16, 0) }, { BRDATA (UBMAP, ub_map, 8, 22, UBM_LNT_LW) }, - { FLDATA (18B_ADDR, cpu_unit.flags, UNIT_V_18B), REG_HRO }, - { FLDATA (UB_MAP, cpu_unit.flags, UNIT_V_UBM), REG_HRO }, - { FLDATA (RH11, cpu_unit.flags, UNIT_V_RH11), REG_HRO }, - { FLDATA (CIS, cpu_unit.flags, UNIT_V_CIS), REG_HRO }, { BRDATA (PCQ, pcq, 8, 16, PCQ_SIZE), REG_RO+REG_CIRC }, { ORDATA (PCQP, pcq_p, 6), REG_HRO }, { ORDATA (WRU, sim_int_char, 8) }, @@ -524,9 +527,9 @@ REG cpu_reg[] = { MTAB cpu_mod[] = { { UNIT_MAP, UNIT_18B, "18b addressing", "18B", NULL }, - { UNIT_MAP, UNIT_UBM, "22b Unibus + RH70", "URH70", NULL }, - { UNIT_MAP, UNIT_UBM + UNIT_RH11, "22b Unibus + RH11", "URH11", NULL }, - { UNIT_MAP, 0, "22b addressing", "22B", NULL }, + { UNIT_MAP, UNIT_UBM, "22b Unibus + RH70", "URH70", &cpu_set_bus }, + { UNIT_MAP, UNIT_UBM + UNIT_RH11, "22b Unibus + RH11", "URH11", &cpu_set_bus }, + { UNIT_MAP, 0, "22b addressing", "22B", &cpu_set_bus }, { UNIT_CIS, UNIT_CIS, "CIS", "CIS", NULL }, { UNIT_CIS, 0, "no CIS", "NOCIS", NULL }, { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size}, @@ -548,6 +551,8 @@ MTAB cpu_mod[] = { { UNIT_MSIZE, 2097152, NULL, "2M", &cpu_set_size}, { UNIT_MSIZE, 3145728, NULL, "3M", &cpu_set_size}, { UNIT_MSIZE, 4186112, NULL, "4M", &cpu_set_size}, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "IOSPACE", NULL, + NULL, &show_iospace }, { 0 } }; DEVICE cpu_dev = { @@ -573,8 +578,12 @@ void cis11 (int32 IR); 5. Interrupt system */ -if (cpu_unit.flags & UNIT_UBM) ubm_dib.enb = 1; /* enb/dis map */ -else ubm_dib.enb = 0; +cpu_18b = cpu_unit.flags & UNIT_18B; /* export cnf flgs */ +cpu_ubm = cpu_unit.flags & UNIT_UBM; +cpu_rh11 = cpu_unit.flags & UNIT_RH11; +cpu_bme = (MMR3 & MMR3_BME) && cpu_ubm; +reason = build_dib_tab (cpu_ubm); /* build, chk dib_tab */ +if (reason != SCPE_OK) return reason; cm = (PSW >> PSW_V_CM) & 03; /* call calc_is,ds */ pm = (PSW >> PSW_V_PM) & 03; rs = (PSW >> PSW_V_RS) & 01; @@ -593,14 +602,11 @@ isenable = calc_is (cm); dsenable = calc_ds (cm); CPU_wr (PIRQ, 017777772, WRITE); /* rewrite PIRQ */ -cpu_bme = (MMR3 & MMR3_BME) && (cpu_unit.flags & UNIT_UBM); -cpu_18b = cpu_unit.flags & UNIT_18B; /* export cnf flgs */ -cpu_ubm = cpu_unit.flags & UNIT_UBM; -cpu_rh11 = cpu_unit.flags & UNIT_RH11; trap_req = calc_ints (ipl, trap_req); /* upd int req */ trapea = 0; reason = 0; sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init line clock */ +sim_rtcn_init (pclk_unit.wait, TMR_PCLK); /* init prog clock */ /* Abort handling @@ -1689,7 +1695,7 @@ PSW = (cm << PSW_V_CM) | (pm << PSW_V_PM) | (rs << PSW_V_RS) | for (i = 0; i < 6; i++) REGFILE[i][rs] = R[i]; STACKFILE[cm] = SP; saved_PC = PC & 0177777; -pcq_r -> qptr = pcq_p; /* update pc q ptr */ +pcq_r->qptr = pcq_p; /* update pc q ptr */ return reason; } @@ -1805,7 +1811,6 @@ case 2: /* (R)+ */ if (update_MM) MMR1 = calc_MMR1 ((delta << 3) | reg); return (adr | ds); case 3: /* @(R)+ */ - adr = R[reg]; R[reg] = ((adr = R[reg]) + 2) & 0177777; if (update_MM) MMR1 = calc_MMR1 (020 | reg); adr = ReadW (adr | ds); @@ -2086,7 +2091,7 @@ return pa; sw = switches Outputs: pa = physical address - On aborts, this routine returns -1 + On aborts, this routine returns MAXMEMSIZE */ int32 relocC (int32 va, int32 sw) @@ -2104,8 +2109,8 @@ if (MMR0 & MMR0_MME) { /* if mmgt */ apr = APRFILE[apridx]; /* with va<18:13> */ dbn = va & VA_BN; /* extr block num */ plf = (apr & PDR_PLF) >> 2; /* extr page length */ - if ((apr & PDR_PRD) == 0) return -1; /* not readable? */ - if ((apr & PDR_ED)? dbn < plf: dbn > plf) return -1; + if ((apr & PDR_PRD) == 0) return MAXMEMSIZE; /* not readable? */ + if ((apr & PDR_ED)? dbn < plf: dbn > plf) return MAXMEMSIZE; pa = ((va & VA_DF) + ((apr >> 10) & 017777700)) & PAMASK; if ((MMR3 & MMR3_M22E) == 0) { pa = pa & 0777777; @@ -2171,7 +2176,7 @@ if (pa & 1) return SCPE_OK; MMR3 = data & MMR3_RW; if (cpu_unit.flags & UNIT_18B) MMR3 = MMR3 & ~(MMR3_BME + MMR3_M22E); /* for UNIX V6 */ -cpu_bme = (MMR3 & MMR3_BME) && (cpu_unit.flags & UNIT_UBM); +cpu_bme = (MMR3 & MMR3_BME) && cpu_ubm; dsenable = calc_ds (cm); return SCPE_OK; } @@ -2364,7 +2369,7 @@ wait_state = 0; if (M == NULL) M = calloc (MEMSIZE >> 1, sizeof (unsigned int16)); if (M == NULL) return SCPE_MEM; pcq_r = find_reg ("PCQ", NULL, dptr); -if (pcq_r) pcq_r -> qptr = 0; +if (pcq_r) pcq_r->qptr = 0; else return SCPE_IERR; for (i = 0; i < UBM_LNT_LW; i++) ub_map[i] = 0; sim_brk_types = sim_brk_dflt = SWMASK ('E'); @@ -2382,7 +2387,7 @@ if (vptr == NULL) return SCPE_ARG; if (sw & SWMASK ('V')) { /* -v */ if (addr >= VASIZE) return SCPE_NXM; addr = relocC (addr, sw); /* relocate */ - if (addr < 0) return SCPE_REL; } + if (addr >= MAXMEMSIZE) return SCPE_REL; } if (addr < MEMSIZE) { *vptr = M[addr >> 1] & 0177777; return SCPE_OK; } @@ -2399,7 +2404,7 @@ t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) if (sw & SWMASK ('V')) { /* -v */ if (addr >= VASIZE) return SCPE_NXM; addr = relocC (addr, sw); /* relocate */ - if (addr < 0) return SCPE_REL; } + if (addr >= MAXMEMSIZE) return SCPE_REL; } if (addr < MEMSIZE) { M[addr >> 1] = val & 0177777; return SCPE_OK; } @@ -2413,7 +2418,7 @@ t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { int32 mc = 0; t_addr i, clim; -unsigned int16 *nM = NULL; +unsigned int16 *nM; if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0)) return SCPE_ARG; @@ -2427,4 +2432,26 @@ for (i = 0; i < clim; i = i + 2) nM[i >> 1] = M[i >> 1]; free (M); M = nM; MEMSIZE = val; -return SCPE_OK; } +return cpu_set_bus (uptr, (cpu_unit.flags & UNIT_MAP) | 1, cptr, desc); } + +/* Bus configuration, disable Unibus or Qbus devices */ + +t_stat cpu_set_bus (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +DEVICE *dptr; +uint32 i, target; + +if ((MEMSIZE <= UNIMEMSIZE) || (val & UNIT_18B) || + (!(val & 1) && ((uint32) val == (cpu_unit.flags & UNIT_MAP)))) return SCPE_OK; +if (val & UNIT_MAP) target = DEV_QBUS; /* going to Ubus? */ +else target = DEV_UBUS; /* going to Qbus */ +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { + if ((dptr->flags & DEV_DISABLE) && /* disable-able? */ + !(dptr->flags & DEV_DIS) && /* enabled? */ + ((dptr->flags & (DEV_QBUS|DEV_UBUS)) == target)) { + printf ("Disabling %s\n", dptr->name); + if (sim_log) fprintf (sim_log, "Disabling %s\n", dptr->name); + dptr->flags = dptr->flags | DEV_DIS; } } +return SCPE_OK; +} + diff --git a/PDP11/pdp11_defs.h b/PDP11/pdp11_defs.h index 5df26f95..256a908f 100644 --- a/PDP11/pdp11_defs.h +++ b/PDP11/pdp11_defs.h @@ -26,6 +26,12 @@ The author gratefully acknowledges the help of Max Burnet, Megan Gentry, and John Wilson in resolving questions about the PDP-11 + 11-Nov-02 RMS Changed log definitions to be VAX compatible + 10-Oct-02 RMS Added vector information to DIB + Changed DZ11 vector to Unibus standard + Added DEQNA/DELQA, DEUNA/DELUA support + Added multiple RQDX3, autoconfigure support + 12-Sep-02 RMS Added TMSCP, KW11P,and RX211 support 28-Apr-02 RMS Clarified PDF ACF mnemonics 22-Apr-02 RMS Added HTRAP, BPOK maint register flags, MT_MAXFR 06-Mar-02 RMS Changed system type to KDJ11A @@ -42,6 +48,9 @@ 10-Feb-01 RMS Added DECtape support */ +#ifndef _PDP11_DEFS_H +#define _PDP11_DEFS_H 0 + #include "sim_defs.h" /* simulator defns */ #include @@ -51,6 +60,8 @@ #define VASIZE 0200000 /* 2**16 */ #define VAMASK (VASIZE - 1) /* 2**16 - 1 */ #define INIMEMSIZE 001000000 /* 2**18 */ +#define UNIMEMSIZE 001000000 /* 2**18 */ +#define UNIMASK (UNIMEMSIZE - 1) /* 2**18 - 1 */ #define IOPAGEBASE 017760000 /* 2**22 - 2**13 */ #define MAXMEMSIZE 020000000 /* 2**22 */ #define PAMASK (MAXMEMSIZE - 1) /* 2**22 - 1 */ @@ -275,34 +286,61 @@ typedef struct fpac fpac_t; #define STOP_VECABORT (TRAP_V_MAX + 4) /* abort vector read */ #define STOP_SPABORT (TRAP_V_MAX + 5) /* abort trap push */ #define STOP_RQ (TRAP_V_MAX + 6) /* RQDX3 panic */ +#define STOP_SANITY (TRAP_V_MAX + 7) /* sanity timer exp */ #define IORETURN(f,v) ((f)? (v): SCPE_OK) /* cond error return */ /* Timers */ #define TMR_CLK 0 /* line clock */ -#define TMR_KWP 1 /* KW11P */ +#define TMR_PCLK 1 /* KW11P */ /* IO parameters */ #define DZ_MUXES 4 /* max # of muxes */ #define DZ_LINES 8 /* lines per mux */ #define MT_MAXFR (1 << 16) /* magtape max rec */ +#define AUTO_LNT 34 /* autoconfig ranks */ +#define DIB_MAX 100 /* max DIBs */ + +#define DEV_V_UBUS (DEV_V_UF + 0) /* Unibus */ +#define DEV_V_QBUS (DEV_V_UF + 1) /* Qbus */ +#define DEV_V_FLTA (DEV_V_UF + 2) /* flt addr */ +#define DEV_UBUS (1u << DEV_V_UBUS) +#define DEV_QBUS (1u << DEV_V_QBUS) +#define DEV_FLTA (1u << DEV_V_FLTA) + +#define UNIBUS (cpu_18b || cpu_ubm) /* T if 18b */ + +#define MAP 1 /* mapped */ +#define NOMAP 0 /* not mapped */ /* Device information block */ +#define VEC_DEVMAX 4 /* max device vec */ + struct pdp_dib { - uint32 enb; /* enabled */ uint32 ba; /* base addr */ uint32 lnt; /* length */ t_stat (*rd)(int32 *dat, int32 ad, int32 md); - t_stat (*wr)(int32 dat, int32 ad, int32 md); }; + t_stat (*wr)(int32 dat, int32 ad, int32 md); + int32 vnum; /* vectors: number */ + int32 vloc; /* locator */ + int32 vec; /* value */ + int32 (*ack[VEC_DEVMAX])(void); /* ack routines */ +}; typedef struct pdp_dib DIB; -/* I/O page layout */ +/* I/O page layout - RQB,RQC,RQD float based on number of DZ's */ #define IOBA_DZ (IOPAGEBASE + 000100) /* DZ11 */ #define IOLN_DZ 010 +#define IOBA_RQB (IOPAGEBASE + 000334 + (020 * (DZ_MUXES / 2))) +#define IOLN_RQB 004 +#define IOBA_RQC (IOPAGEBASE + IOBA_RQB + IOLN_RQB) +#define IOLN_RQC 004 +#define IOBA_RQD (IOPAGEBASE + IOBA_RQC + IOLN_RQC) +#define IOLN_RQD 004 #define IOBA_UBM (IOPAGEBASE + 010200) /* Unibus map */ #define IOLN_UBM (UBM_LNT_LW * sizeof (int32)) #define IOBA_RQ (IOPAGEBASE + 012150) /* RQDX3 */ @@ -315,26 +353,42 @@ typedef struct pdp_dib DIB; #define IOLN_TM 014 #define IOBA_TS (IOPAGEBASE + 012520) /* TS11 */ #define IOLN_TS 004 +#define IOBA_PCLK (IOPAGEBASE + 012540) /* KW11P */ +#define IOLN_PCLK 006 #define IOBA_RL (IOPAGEBASE + 014400) /* RL11 */ #define IOLN_RL 012 +#define IOBA_XQ (IOPAGEBASE + 014440) /* DEQNA/DELQA */ +#define IOLN_XQ 020 +#define IOBA_XQB (IOPAGEBASE + 014460) /* 2nd DEQNA/DELQA */ +#define IOLN_XQB 020 +#define IOBA_TQ (IOPAGEBASE + 014500) /* TMSCP */ +#define IOLN_TQ 004 +#define IOBA_XU (IOPAGEBASE + 014510) /* DEUNA/DELUA */ +#define IOLN_XU 010 #define IOBA_RP (IOPAGEBASE + 016700) /* RP/RM */ #define IOLN_RP 054 #define IOBA_RX (IOPAGEBASE + 017170) /* RX11 */ #define IOLN_RX 004 +#define IOBA_RY (IOPAGEBASE + 017170) /* RY11 */ +#define IOLN_RY 004 #define IOBA_TC (IOPAGEBASE + 017340) /* TC11 */ #define IOLN_TC 012 #define IOBA_RK (IOPAGEBASE + 017400) /* RK11 */ #define IOLN_RK 020 -#define IOBA_RK6 (IOPAGEBASE + 017440) /* RK611 */ -#define IOLN_RK6 040 +#define IOBA_HK (IOPAGEBASE + 017440) /* RK611 */ +#define IOLN_HK 040 #define IOBA_LPT (IOPAGEBASE + 017514) /* LP11 */ #define IOLN_LPT 004 #define IOBA_CLK (IOPAGEBASE + 017546) /* KW11L */ #define IOLN_CLK 002 -#define IOBA_PT (IOPAGEBASE + 017550) /* PC11 */ -#define IOLN_PT 010 -#define IOBA_TT (IOPAGEBASE + 017560) /* DL11 */ -#define IOLN_TT 010 +#define IOBA_PTR (IOPAGEBASE + 017550) /* PC11 reader */ +#define IOLN_PTR 004 +#define IOBA_PTP (IOPAGEBASE + 017554) /* PC11 punch */ +#define IOLN_PTP 004 +#define IOBA_TTI (IOPAGEBASE + 017560) /* DL11 rcv */ +#define IOLN_TTI 004 +#define IOBA_TTO (IOPAGEBASE + 017564) /* DL11 xmt */ +#define IOLN_TTO 004 #define IOBA_SRMM (IOPAGEBASE + 017570) /* SR, MMR0-2 */ #define IOLN_SRMM 010 #define IOBA_APR1 (IOPAGEBASE + 017600) /* APRs */ @@ -349,8 +403,9 @@ typedef struct pdp_dib DIB; #define INT_V_PIR7 0 /* BR7 */ #define INT_V_CLK 0 /* BR6 */ -#define INT_V_DTA 1 -#define INT_V_PIR6 2 +#define INT_V_PCLK 1 +#define INT_V_DTA 2 +#define INT_V_PIR6 3 #define INT_V_RK 0 /* BR5 */ #define INT_V_RL 1 @@ -362,7 +417,11 @@ typedef struct pdp_dib DIB; #define INT_V_RQ 7 #define INT_V_DZRX 8 #define INT_V_DZTX 9 -#define INT_V_PIR5 10 +#define INT_V_TQ 10 +#define INT_V_RY 11 +#define INT_V_XQ 12 +#define INT_V_XU 13 +#define INT_V_PIR5 14 #define INT_V_TTI 0 /* BR4 */ #define INT_V_TTO 1 @@ -377,6 +436,7 @@ typedef struct pdp_dib DIB; #define INT_PIR7 (1u << INT_V_PIR7) #define INT_CLK (1u << INT_V_CLK) +#define INT_PCLK (1u << INT_V_PCLK) #define INT_DTA (1u << INT_V_DTA) #define INT_PIR6 (1u << INT_V_PIR6) #define INT_RK (1u << INT_V_RK) @@ -385,10 +445,14 @@ typedef struct pdp_dib DIB; #define INT_TM (1u << INT_V_TM) #define INT_RP (1u << INT_V_RP) #define INT_TS (1u << INT_V_TS) -#define INT_RK6 (1u << INT_V_HK) +#define INT_HK (1u << INT_V_HK) #define INT_RQ (1u << INT_V_RQ) #define INT_DZRX (1u << INT_V_DZRX) #define INT_DZTX (1u << INT_V_DZTX) +#define INT_TQ (1u << INT_V_TQ) +#define INT_RY (1u << INT_V_RY) +#define INT_XQ (1u << INT_V_XQ) +#define INT_XU (1u << INT_V_XU) #define INT_PIR5 (1u << INT_V_PIR5) #define INT_PTR (1u << INT_V_PTR) #define INT_PTP (1u << INT_V_PTP) @@ -401,6 +465,7 @@ typedef struct pdp_dib DIB; #define INT_PIR1 (1u << INT_V_PIR1) #define IPL_CLK 6 /* int pri levels */ +#define IPL_PCLK 6 #define IPL_DTA 6 #define IPL_RK 5 #define IPL_RL 5 @@ -408,10 +473,14 @@ typedef struct pdp_dib DIB; #define IPL_TM 5 #define IPL_RP 5 #define IPL_TS 5 -#define IPL_RK6 5 +#define IPL_HK 5 #define IPL_RQ 5 #define IPL_DZRX 5 #define IPL_DZTX 5 +#define IPL_TQ 5 +#define IPL_RY 5 +#define IPL_XQ 5 +#define IPL_XU 5 #define IPL_PTR 4 #define IPL_PTP 4 #define IPL_TTI 4 @@ -426,6 +495,8 @@ typedef struct pdp_dib DIB; #define IPL_PIR2 2 #define IPL_PIR1 1 +/* Device vectors */ + #define VEC_Q 0000 /* vector base */ #define VEC_PIRQ 0240 #define VEC_TTI 0060 @@ -433,21 +504,36 @@ typedef struct pdp_dib DIB; #define VEC_PTR 0070 #define VEC_PTP 0074 #define VEC_CLK 0100 +#define VEC_PCLK 0104 +#define VEC_XQ 0120 +#define VEC_XU 0120 #define VEC_RQ 0154 #define VEC_RL 0160 #define VEC_LPT 0200 -#define VEC_RK6 0210 +#define VEC_HK 0210 #define VEC_RK 0220 #define VEC_DTA 0214 #define VEC_TM 0224 #define VEC_TS 0224 #define VEC_RP 0254 +#define VEC_TQ 0260 #define VEC_RX 0264 -#define VEC_DZRX 0310 -#define VEC_DZTX 0314 +#define VEC_RY 0264 +#define VEC_DZRX 0300 +#define VEC_DZTX 0304 + +/* Autoconfigure ranks */ + +#define RANK_DZ 8 +#define RANK_RL 14 +#define RANK_RX 18 +#define RANK_XU 25 +#define RANK_RQ 26 +#define RANK_TQ 30 /* Interrupt macros */ +#define IVCL(dv) ((IPL_##dv * 32) + INT_V_##dv) #define IREQ(dv) int_req[IPL_##dv] #define SET_INT(dv) int_req[IPL_##dv] = int_req[IPL_##dv] | (INT_##dv) #define CLR_INT(dv) int_req[IPL_##dv] = int_req[IPL_##dv] & ~(INT_##dv) @@ -463,28 +549,34 @@ typedef struct pdp_dib DIB; /* Logging */ -#define LOG_CPU_I 00000001 -#define LOG_RP 00000010 -#define LOG_TS 00000020 -#define LOG_RQ 00000040 -#define LOG_TC_MS 00000100 -#define LOG_TC_RW 00000200 -#define LOG_TC_RA 00000400 -#define LOG_TC_BL 00001000 +#define LOG_CPU_I 0x0001 +#define LOG_RP 0x0010 +#define LOG_TS 0x0020 +#define LOG_RQ 0x0040 +#define LOG_TQ 0x0080 +#define LOG_XQ0 0x0100 +#define LOG_XQ1 0x0200 +#define LOG_XQ2 0x0400 +#define LOG_XQ3 0x0800 +#define LOG_TC_MS 0x1000 +#define LOG_TC_RW 0x2000 +#define LOG_TC_BL 0x4000 +#define LOG_HK 0x8000 #define DBG_LOG(x) (sim_log && (cpu_log & (x))) /* Function prototypes */ -#define QB 0 /* Q22 native */ -#define UB 1 /* Unibus */ - t_bool Map_Addr (t_addr qa, t_addr *ma); -int32 Map_ReadB (t_addr ba, int32 bc, uint8 *buf, t_bool ub); -int32 Map_ReadW (t_addr ba, int32 bc, uint16 *buf, t_bool ub); -int32 Map_WriteB (t_addr ba, int32 bc, uint8 *buf, t_bool ub); -int32 Map_WriteW (t_addr ba, int32 bc, uint16 *buf, t_bool ub); +int32 Map_ReadB (t_addr ba, int32 bc, uint8 *buf, t_bool map); +int32 Map_ReadW (t_addr ba, int32 bc, uint16 *buf, t_bool map); +int32 Map_WriteB (t_addr ba, int32 bc, uint8 *buf, t_bool map); +int32 Map_WriteW (t_addr ba, int32 bc, uint16 *buf, t_bool map); t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc); -t_bool dev_conflict (uint32 nba, DIB *curr); +t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat set_vec (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat show_vec (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat auto_config (uint32 rank, uint32 num); + +#endif diff --git a/PDP11/pdp11_doc.txt b/PDP11/pdp11_doc.txt index 9257048e..8214fe3d 100644 --- a/PDP11/pdp11_doc.txt +++ b/PDP11/pdp11_doc.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik Subj: PDP-11 Simulator Usage -Date: 15-Jun-2002 +Date: 15-Nov-2002 COPYRIGHT NOTICE @@ -36,34 +36,44 @@ This memorandum documents the PDP-11 simulator. 1. Simulator Files -sim/ sim_defs.h +sim/ dec_dz.h + dec_pt.h + sim_defs.h + sim_ether.h + sim_rev.h sim_sock.h sim_tmxr.h - dec_dz.h - dec_mscp.h - dec_uqssp.h scp.c scp_tty.c - sim_rev.c + sim_ether.c sim_sock.c sim_tmxr.c sim/pdp11/ pdp11_defs.h + pdp11_mscp.h + pdp11_uqssp.h + pdp11_xq.h pdp11_cpu.c pdp11_dz.c pdp11_fp.c + pdp11_hk.c pdp11_io.c pdp11_lp.c + pdp11_pclk.c + pdp11_pt.c pdp11_rk.c pdp11_rl.c pdp11_rp.c pdp11_rq.c + pdp11_tq.c pdp11_rx.c + pdp11_ry.c pdp11_stddev.c pdp11_sys.c pdp11_tc.c pdp11_tm.c pdp11_ts.c + pdp11_xp.c 2. PDP-11 Features @@ -79,27 +89,27 @@ PTR,PTP PC11 paper tape reader/punch TTI,TTO DL11 console terminal LPT LP11 line printer CLK line frequency clock +PCLK KW11P programmable clock DZ DZ11 8-line terminal multiplexor (up to 4) RK RK11/RK05 cartridge disk controller with eight drives +HK RK611/RK06(7) cartridge disk controller with eight drives RL RLV12/RL01(2) cartridge disk controller with four drives RP RM02/03/05/80, RP04/05/06/07 Massbus style controller with eight drives RQ RQDX3 MSCP controller with four drives +RQB second RQDX3 MSCP controller with four drives +RQC third RQDX3 MSCP controller with four drives +RQD fourth RQDX3 MSCP controller with four drives RX RX11/RX01 floppy disk controller with two drives +RY RX211/RX01 floppy disk controller with two drives TC TC11/TU56 DECtape controller with eight drives TM TM11/TU10 magnetic tape controller with eight drives TS TS11/TSV05 magnetic tape controller with one drive +TQ TQK50 TMSCP magnetic tape controller with four drives +XQ DELQA/DEQNA Ethernet controller -The DZ, RK, RL, RP, RQ, RX, TC, TM, and TS devices can be set DISABLED. -With default I/O page addressing, the PDP-11 can support either a TM11 -or a TS11, but not both, since they use the same I/O addresses. The -simulator defaults to the TM11. To change the magtape from TM11 to TS11, - - SET TM DISABLED disable TM11 - SET TS ENABLED enable TS11 - -Most devices support the SET ADDRESS command, which allows the I/O page -address of the device to be changed. +The DZ, RK, HK, RL, RP, RQ, RQB, RQC, RQD, RX, RY, TC, TM, TS, TQ, and XQ +devices can be set DISABLED. RQB, RQC, RQD, RY, and TS are disabled by default. The PDP-11 simulator implements several unique stop conditions: @@ -141,10 +151,39 @@ with RH70-style controllers, 22b Unibus with RH11 style controllers, and SET CPU 2048K (or 2M) set memory size = 2048KB SET CPU 3072K (or 3M) set memory size = 3072KB SET CPU 4096K (or 4M) set memory size = 4096KB + SHOW CPU IOSPACE show I/O space address map If memory size is being reduced, and the memory being truncated contains non-zero data, the simulator asks for confirmation. Data in the truncated -portion of memory is lost. Initial memory size is 256KB. +portion of memory is lost. Initial memory size is 256KB. If memory size +is being increased to more than 256KB, or the bus structue is being changed, +the simulator asks whether it should disable peripherals that can't run +in the current bus structure. + +DMA peripherals function differently, depending on whether the CPU is +configured for 18B, URH11, URH70, or 22B addressing and I/O: + + peripheral 18B URH11 URH70 22B + + RK 18b 18b 18b won't work, disabled + HK 18b 18b 18b SC02/C 22b, works + only with Ultrix-11 + RL 18b 18b 18b 22b RLV12 + RP 18b 18b 22b 22b third party + RQ 18b 18b 18b 22b RQDX3 + RY 18b 18b 18b won't work, disabled + TC 18b 18b 18b won't work, disabled + TM 18b 18b 18b won't work, disabled + TS 18b 18b 18b 22b TSV05 + TQ 18b 18b 18b 22b TQK50 + XQ 18b won't work, 22b DELQA + disabled + XU 18b 18b 18b won't work, disabled + +Non-DMA peripherals work the same in all configurations. Unibus-only +peripherals should be disabled in a Qbus (22B) configuration with more +than 256KB of memory, and Qbus-only peripherals should be disabled in +a Unibus (URH11 or URH70) configuration with more than 256KB of memory. These switches are recognized when examining or depositing in CPU memory: @@ -204,9 +243,53 @@ control registers for the interrupt system. most recent PC change first WRU 8 interrupt character -2.2 Programmed I/O Devices +2.2 I/O Device Addressing -2.2.1 PC11 Paper Tape Reader (PTR) +PDP-11 I/O space is not large enough to allow all possible devices to be +configured simultaneously at fixed addresses. Instead, many devices have +floating addresses; that is, the assigned device address depends on the +presense of other devices in the configuration: + + DZ11 all instances have floating addresses + RL11 first instance has fixed address, rest floating + RX11/RX211 first instance has fixed address, rest floating + DEUNA/DELUA first instance has fixed address, rest floating + MSCP disk first instance has fixed address, rest floating + TMSCP tape first instance has fixed address, rest floating + +To maintain addressing consistency as the configuration changes, the +simulator implements DEC's standard I/O address and vector autoconfiguration +algorithms for devices DZ, RL, RX, RY, XU, RQ, and TQ. This allows the +user to enable or disable devices without needing to manage I/O addresses +and vectors. For example, if RY is enabled while RX is present, RY is +assigned an I/O address in the floating I/O space range; but if RX is +disabled and then RY is enabled, RY is assigned the fixed "first instance" +I/O address for floppy disks. + +Autoconfiguration cannot solve address conflicts between devices with +overlapping fixed address. For example, with default I/O page addressing, +the PDP-11 can support either a TM11 or a TS11, but not both, since they use +the same I/O addresses. + +In addition to autoconfiguration, most devices support the SET ADDRESS +command, which allows the I/O page address of the device to be changed, +and the SET VECTOR command, which allows the vector of the device to be +changed. Explicitly setting the I/O address of a device which normally +uses autoconfiguration DISABLES autoconfiguration for that device. As +a consequence, the user may have to manually configure all other +autoconfigured devices, because the autoconfiguration algorithm no +longer recognizes the explicitly configured device. A device can be +reset to autoconfigure with the SET AUTOCONFIGURE command. + +The current I/O map can be displayed with the SHOW CPU IOSPACE command. +Address that have set by autoconfiguration are marked with an asterisk (*). + +All devices support the SHOW ADDRESS and SHOW VECTOR commands, which display +the device address and vector, respectively. + +2.3 Programmed I/O Devices + +2.3.1 PC11 Paper Tape Reader (PTR) The paper tape reader (PTR) reads data from a disk file. The POS register specifies the number of the next data item to be read. Thus, @@ -239,7 +322,7 @@ Error handling is as follows: OS I/O error x report error and stop -2.2.2 PC11 Paper Tape Punch (PTP) +2.3.2 PC11 Paper Tape Punch (PTP) The paper tape punch (PTP) writes data to a disk file. The POS register specifies the number of the next data item to be written. @@ -268,7 +351,12 @@ Error handling is as follows: OS I/O error x report error and stop -2.2.3 DL11 Terminal Input (TTI) +2.3.3 DL11 Terminal Input (TTI) + +The terminal interfaces (TTI, TTO) can be set to one of two modes: +7B or 8B. In 7B mode, input and output characters are masked to 7 +bits. In 8B mode, characters are not modified. Changing the mode +of either interface changes both. The default mode is 8B. The terminal input (TTI) polls the console keyboard for input. It implements these registers: @@ -284,7 +372,7 @@ implements these registers: POS 32 number of characters input TIME 24 keyboard polling interval -2.2.4 DL11 Terminal Output (TTO) +2.3.4 DL11 Terminal Output (TTO) The terminal output (TTO) writes to the simulator console window. It implements these registers: @@ -300,7 +388,7 @@ implements these registers: POS 32 number of characters input TIME 24 time from I/O initiation to interrupt -2.2.5 LP11 Line Printer (LPT) +2.3.5 LP11 Line Printer (LPT) The line printer (LPT) writes data to a disk file. The POS register specifies the number of the next data item to be written. Thus, @@ -329,7 +417,7 @@ Error handling is as follows: OS I/O error x report error and stop -2.2.6 Line-Time Clock (CLK) +2.3.6 Line-Time Clock (CLK) The line-time clock (CLK) implements these registers: @@ -339,13 +427,37 @@ The line-time clock (CLK) implements these registers: INT 1 interrupt pending flag DONE 1 device done flag (CSR<7>) IE 1 interrupt enable flag (CSR<6>) - TIME 24 clock frequency + TIME 24 clock interval TPS 8 ticks per second (60 or 50) -The line-time clock autocalibrates; the clock interval is adjusted up or -down so that the clock tracks actual elapsed time. +The line-time clock autocalibrates; the clock interval is adjusted up +or down so that the clock tracks actual elapsed time. -2.2.7 DZ11 Terminal Multiplexor (DZ) +2.3.7 Programmable Clock (PCLK) + +The programmable clock (PCLK) implements these registers: + + name size comments + + CSR 16 control/status register + CSB 16 count set buffer + CNT 16 current count + INT 1 interrupt pending flag + OVFL 1 overflow (error) flag (CSR<15>) + DONE 1 device done flag (CSR<7>) + IE 1 interrupt enable flag (CSR<6>) + UPDN 1 up/down count mode (CSR<4>) + MODE 1 single/repeat mode (CSR<3>) + RUN 1 clock run (CSR<0>) + TIME[0..3] 32 clock interval, rates 0..3 + TPS[0..3] 32 ticks per second, rates 0..3 + +The programmable clock autocalibrates; the clock interval is adjusted +up or down so that the clock tracks actual elapsed time. Operation at +the highest clock rate (100Khz) is not recommended. The programmable +clock is disabled by default. + +2.3.8 DZ11 Terminal Multiplexor (DZ) The DZ11 is an 8-line terminal multiplexor. Up to 4 DZ11's (32 lines) are supported. The number of lines can be changed with the command @@ -354,6 +466,13 @@ are supported. The number of lines can be changed with the command The line count must be a multiple of 8, with a maximum of 32. +The DZ11 supports 8-bit input and output of characters. 8-bit output +may be incompatible with certain operating systems. The command + + SET DZ 7B + +forces output characters (only) to be masked to 7 bits. + The terminal lines perform input and output through Telnet sessions connected to a user-specified port. The ATTACH command specifies the port to be used: @@ -394,50 +513,11 @@ The DZ11 implements these registers: The DZ11 does not support save and restore. All open connections are lost when the simulator shuts down or the DZ is detached. -2.3 RK11/RK05 Cartridge Disk (RK) +2.4 Floppy Disk Drives -RK11 options include the ability to make units write enabled or write locked: +2.4.1 RX11/RX01 Floppy Disk (RX) - SET RKn LOCKED set unit n write locked - SET RKn WRITEENABLED set unit n write enabled - -Units can also be set ONLINE or OFFLINE. The RK11 supports the BOOT command. - -The RK11 implements these registers: - - name size comments - - RKCS 16 control/status - RKDA 16 disk address - RKBA 16 memory address - RKWC 16 word count - RKDS 16 drive status - RKER 16 error status - INTQ 9 interrupt queue - DRVN 3 number of last selected drive - INT 1 interrupt pending flag - ERR 1 error flag (CSR<15>) - DONE 1 device done flag (CSR<7>) - IE 1 interrupt enable flag (CSR<6>) - INT 1 interrupt pending flag - STIME 24 seek time, per cylinder - RTIME 24 rotational delay - STOP_IOE 1 stop on I/O error - -Error handling is as follows: - - error STOP_IOE processed as - - not attached 1 report error and stop - 0 disk not ready - - end of file x assume rest of disk is zero - - OS I/O error x report error and stop - -2.4 RX11/RX01 Floppy Disk (RX) - -RX11 options include the ability to make units write enabled or write locked: +RX11 options include the ability to set units write enabled or write locked: SET RXn LOCKED set unit n write locked SET RXn WRITEENABLED set unit n write enabled @@ -477,11 +557,161 @@ Error handling is as follows: RX01 data files are buffered in memory; therefore, end of file and OS I/O errors cannot occur. -2.5 RL11(V12)/RL01,RL02 Cartridge Disk (RL) +2.4.2 RX211/RX02 Floppy Disk (RY) -RL11 options include the ability to set units write enabled or write locked, -to set the drive size to RL01, RL02, or autosize, and to write a DEC standard -044 compliant bad block table on the last track: +RX211 options include the ability to set units write enabled or write +locked, single or double density, or autosized: + + SET RYn LOCKED set unit n write locked + SET RYn WRITEENABLED set unit n write enabled + SET RYn SINGLE set unit n single density + SET RYn DOUBLE set unit n double density (default) + SET RYn AUTOSIZE set unit n autosized + +The RX211 supports the BOOT command. The RX211 will not function +properly in a Qbus (22B) system with more than 256KB of memory. + +The RX211 implements these registers: + + name size comments + + RYCS 16 status + RYBA 16 buffer address + RYWC 8 word count + RYDB 16 data buffer + RYES 12 error status + RYERR 8 error code + RYTA 8 current track + RYSA 8 current sector + STAPTR 4 controller state + INT 1 interrupt pending flag + ERR 1 error flag (CSR<15>) + TR 1 transfer ready flag (CSR<7>) + IE 1 interrupt enable flag (CSR<6>) + DONE 1 device done flag (CSR<5>) + CTIME 24 command completion time + STIME 24 seek time, per track + XTIME 24 transfer ready delay + STOP_IOE 1 stop on I/O error + SBUF[0:255] 8 sector buffer array + +Error handling is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 disk not ready + +RX02 data files are buffered in memory; therefore, end of file and OS +I/O errors cannot occur. + +2.5 Cartridge Disk Drives + +2.5.1 RK11/RK05 Cartridge Disk (RK) + +RK11 options include the ability to make units write enabled or write +locked: + + SET RKn LOCKED set unit n write locked + SET RKn WRITEENABLED set unit n write enabled + +Units can also be set ONLINE or OFFLINE. The RK11 supports the BOOT +command. The RK11 will not function properly in a Qbus (22B) system +with more than 256KB of memory. + +The RK11 implements these registers: + + name size comments + + RKCS 16 control/status + RKDA 16 disk address + RKBA 16 memory address + RKWC 16 word count + RKDS 16 drive status + RKER 16 error status + INTQ 9 interrupt queue + DRVN 3 number of last selected drive + INT 1 interrupt pending flag + ERR 1 error flag (CSR<15>) + DONE 1 device done flag (CSR<7>) + IE 1 interrupt enable flag (CSR<6>) + INT 1 interrupt pending flag + STIME 24 seek time, per cylinder + RTIME 24 rotational delay + STOP_IOE 1 stop on I/O error + +Error handling is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 disk not ready + + end of file x assume rest of disk is zero + + OS I/O error x report error and stop + +2.5.2 RK611/RK06,RK07 Cartridge Disk (RL) + +RK611 options include the ability to set units write enabled or write +locked, to set the drive size to RK06, RK07, or autosize, and to write +a DEC standard 044 compliant bad block table on the last track: + + SET HKn LOCKED set unit n write locked + SET HKn WRITEENABLED set unit n write enabled + SET HKn RK06 set size to RK06 + SET HKn RK07 set size to RK07 + SET HKn AUTOSIZE set size based on file size at attach + SET HKn BADBLOCK write bad block table on last track + +The size options can be used only when a unit is not attached to a file. +The bad block option can be used only when a unit is attached to a file. +Units can be set ONLINE or OFFLINE. The RK611 supports the BOOT command. +The RK611 will not function properly in a Qbus (22B) system with more +than 256KB of memory using standard DEC software. The simulator implements +a third-party extension of addressing capability to 22b; this is only +supported by Ultrix-11. + +The RK611 implements these registers: + + name size comments + + HKCS1 16 control/status 1 + HKWC 16 word count + HKBA 16 bus address + HKDA 16 desired surface, sector + HKCS2 16 control/status 2 + HKDS[0:7] 16 drive status, drives 0-7 + HKER[0:7] 16 drive errors, drives 0-7 + HKDB[0:2] 16 data buffer silo + HKDC 16 desired cylinder + HKOF 8 offset + HKMR 16 maintenance register + HKSPR 16 spare register + INT 1 interrupt pending flag + ERR 1 error flag (CSR<15>) + DONE 1 device done flag (CSR1<7>) + IE 1 interrupt enable flag (CSR1<6>) + STIME 24 seek time, per cylinder + RTIME 24 rotational delay + STOP_IOE 1 stop on I/O error + +Error handling is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 disk not ready + + end of file x assume rest of disk is zero + + OS I/O error x report error and stop + +2.5.3 RL11(V12)/RL01,RL02 Cartridge Disk (RL) + +RL11 options include the ability to set units write enabled or write +locked, to set the drive size to RL01, RL02, or autosize, and to write +a DEC standard 044 compliant bad block table on the last track: SET RLn LOCKED set unit n write locked SET RLn WRITEENABLED set unit n write enabled @@ -490,9 +720,12 @@ to set the drive size to RL01, RL02, or autosize, and to write a DEC standard SET RLn AUTOSIZE set size based on file size at attach SET RLn BADBLOCK write bad block table on last track -The size options can be used only when a unit is not attached to a file. The -bad block option can be used only when a unit is attached to a file. Units -can also be set ONLINE or OFFLINE. The RL11 supports the BOOT command. +The size options can be used only when a unit is not attached to a file. +The bad block option can be used only when a unit is attached to a file. +Units can be set ONLINE or OFFLINE. The RL11 supports the BOOT command. +In an 18B or Unibus system, the RL behaves like an RL11 with 18b +addressing; in a Qbus (22B) system, the RL behaves like the RLV12 with +22b addressing. The RL11 implements these registers: @@ -524,15 +757,16 @@ Error handling is as follows: 2.6 RM02/03/05/80, RP04/05/06/07 Disk Pack Drives (RP) -The RP controller implements a "Massbus style" 22b direct interface for -large disk drives. It is more abstract than other device simulators, with -just enough detail to run operating system drivers. In addition, the RP -controller conflates the details of the RM series controllers with the RP -series controllers, although there were detailed differences. +The RP controller implements a "Massbus style" 22b direct interface +for large disk drives. It is more abstract than other device simulators, +with just enough detail to run operating system drivers. In addition, +the RP controller conflates the details of the RM series controllers +with the RP series controllers, although there were detailed differences. -RP options include the ability to set units write enabled or write locked, -to set the drive type to one of six disk types, or autosize, and to write -a DEC standard 044 compliant bad block table on the last track: +RP options include the ability to set units write enabled or write +locked, to set the drive type to one of six disk types, or autosize, +and to write a DEC standard 044 compliant bad block table on the last +track: SET RPn LOCKED set unit n write locked SET RPn WRITEENABLED set unit n write enabled @@ -547,8 +781,10 @@ a DEC standard 044 compliant bad block table on the last track: The type options can be used only when a unit is not attached to a file. The bad block option can be used only when a unit is attached to a file. -Units can also be set ONLINE or OFFLINE. The RP controller supports the -BOOT command. +Units can be set ONLINE or OFFLINE. The RP controller supports the +BOOT command. In a Unibus system, the RP can implement either 18b +(RH11) addressing or 22b (RH70) addressing. In a Qbus (22B) system, +the RP always implements 22b addressing. The RP controller implements these registers: @@ -562,7 +798,7 @@ The RP controller implements these registers: RPDS[0:7] 16 drive status, drives 0-7 RPER1[0:7] 16 drive errors, drives 0-7 RPOF 16 offset - RPDC 8 desired cylinder + RPDC 16 desired cylinder RPER2 16 error status 2 RPER3 16 error status 3 RPEC1 16 ECC syndrome 1 @@ -591,11 +827,13 @@ Error handling is as follows: OS I/O error x report error and stop -2.7 RQDX3 MSCP Disk Controller (RQ) +2.7 RQDX3 MSCP Disk Controllers (RQ, RQB, RQC, RQD) -The RQ controller simulates the RQDX3 MSCP disk controller. RQ options -include the ability to set units write enabled or write locked, and to -set the drive type to one of eleven disk types: +The simulator implements four MSCP disk controllers, RQ, RQB, RQC, RQD. +Initially, RQB, RQC, and RQD are disabled. Each RQ controller simulates +an RQDX3 MSCP disk controller. RQ options include the ability to set +units write enabled or write locked, and to set the drive type to one +of eleven disk types: SET RQn LOCKED set unit n write locked SET RQn WRITEENABLED set unit n write enabled @@ -613,10 +851,11 @@ set the drive type to one of eleven disk types: SET RQn RRD40 set type to RRD40 (CD ROM) The type options can be used only when a unit is not attached to a file. -Units can also be set ONLINE or OFFLINE. The RQ controller supports the -BOOT command. +Units can also be set ONLINE or OFFLINE. Each RQ controller supports the +BOOT command. In a Unibus system, an RQ supports 18b addressing. In +a Qbus (22B) system, an RQ supports 22b addressing. -The RQ controller implements the following special SHOW commands: +Each RQ controller implements the following special SHOW commands: SHOW RQ RINGS show command and response rings SHOW RQ FREEQ show packet free queue @@ -625,7 +864,7 @@ The RQ controller implements the following special SHOW commands: SHOW RQ ALL show all ring and queue state SHOW RQn UNITQ show unit queues for unit n -The RQ controller implements these registers: +Each RQ controller implements these registers: name size comments @@ -680,14 +919,17 @@ locked. SET DTn LOCKED set unit n write locked SET DTn WRITEENABLED set unit n write enabled -Units can also be set ONLINE or OFFLINE. The TC11 supports the BOOT command. +Units can be set ONLINE or OFFLINE. The TC11 supports the BOOT command. +The TC11 will not function properly in a 22B (Qbus) system with more +than 256KB of memory. -The TC11 supports both PDP-8 format and PDP-9/11/15 format DECtape images. -ATTACH tries to determine the tape format from the DECtape image; the user -can force a particular format with switches: +The TC11 supports supports PDP-8 format, PDP-11 format, and 18b format +DECtape images. ATTACH tries to determine the tape format from the DECtape +image; the user can force a particular format with switches: - -f foreign (PDP-8) format - -n native (PDP-9/11/15) format + -r PDP-8 format + -s PDP-11 format + -t 18b format The DECtape controller is a data-only simulator; the timing and mark track, and block header and trailer, are not stored. Thus, the WRITE @@ -695,7 +937,7 @@ TIMING AND MARK TRACK function is not supported; the READ ALL function always returns the hardware standard block header and trailer; and the WRITE ALL function dumps non-data words into the bit bucket. -The DECtape controller implements these registers: +The TC controller implements these registers: name size comments @@ -723,24 +965,30 @@ operate correctly. - LTIME must be at least 6 - ACTIME must be less than DCTIME, and both need to be at least 100 times LTIME - -2.9 TM11 Magnetic Tape (TM) -TM options include the ability to make units write enabled or write locked. +2.9 Magnetic Tape Controllers + +2.9.1 TM11 Magnetic Tape (TM) + +TM options include the ability to make units write enabled or write +locked. SET TMn LOCKED set unit n write locked SET TMn WRITEENABLED set unit n write enabled -Units can also be set ONLINE or OFFLINE. +Units can be set ONLINE or OFFLINE. The TM11 supports the BOOT command. The bootstrap supports both original and DEC standard boot formats. Originally, a tape bootstrap read and executed the first record on tape. To allow for ANSI labels, the DEC -standard bootstrap skipped the first record and read and executed the second. -The DEC standard is the default; to bootstrap an original format tape, use -the -o switch. +standard bootstrap skipped the first record and read and executed the +second. The DEC standard is the default; to bootstrap an original format +tape, use the -o switch. -The magnetic tape controller implements these registers: +The TM11 will not function properly in a Qbus (22B) system with more +than 256KB of memory + +The TM controller implements these registers: name size comments @@ -761,14 +1009,13 @@ Error handling is as follows: error processed as - not attached tape not ready + not attached tape not ready; if STOP_IOE, stop - end of file (read or space) end of physical tape - (write) ignored + end of file bad tape - OS I/O error report error and stop + OS I/O error parity error; if STOP_IOE, stop -2.10 TS11/TSV05 Magnetic Tape (TS) +2.9.2 TS11/TSV05 Magnetic Tape (TS) The TS actually implements the TSV05, with 22-bit addressing, but will work with TS11 drivers. TS options include the ability to make the unit @@ -778,10 +1025,13 @@ write enabled or write locked. SET TS WRITEENABLED set unit write enabled The TS11 supports the BOOT command. The bootstrap supports only DEC -standard boot formats. To allow for ANSI labels, the DEC standard bootstrap -skipped the first record and read and executed the second. +standard boot formats. To allow for ANSI labels, the DEC standard +bootstrap skipped the first record and read and executed the second. +In a Unibus system, the TS behaves like the TS11 and implements 18b +addresses. In a Qbus (22B) system, the TS behaves like the TSV05 +and implements 22b addresses. -The magnetic tape controller implements these registers: +The TS controller implements these registers: name size comments @@ -817,11 +1067,148 @@ Error handling is as follows: not attached tape not ready - end of file (read or space) end of physical tape - (write) ignored + end of file bad tape OS I/O error fatal tape error +2.9.3 TQK50 TMSCP Disk Controller (TQ) + +The TQ controller simulates the TQK50 TMSCP disk controller. TQ options +include the ability to set units write enabled or write locked: + + SET TQn LOCKED set unit n write locked + SET TQn WRITEENABLED set unit n write enabled + +The TQ controller supports the BOOT command. In a Unibus system, the +TQ supports 18b addressing. In a Qbus (22B) system, the TQ supports +22b addressing. + +The TQ controller implements the following special SHOW commands: + + SHOW TQ RINGS show command and response rings + SHOW TQ FREEQ show packet free queue + SHOW TQ RESPQ show packet response queue + SHOW TQ UNITQ show unit queues + SHOW TQ ALL show all ring and queue state + SHOW TQn UNITQ show unit queues for unit n + +The TQ controller implements these registers: + + name size comments + + SA 16 status/address register + S1DAT 16 step 1 init host data + CQBA 22 command queue base address + CQLNT 8 command queue length + CQIDX 8 command queue index + RQBA 22 request queue base address + RQLNT 8 request queue length + RQIDX 8 request queue index + FREE 5 head of free packet list + RESP 5 head of response packet list + PBSY 5 number of busy packets + CFLGS 16 controller flags + CSTA 4 controller state + PERR 9 port error number + CRED 5 host credits + HAT 17 host available timer + HTMO 17 host timeout value + CPKT[0:3] 5 current packet, units 0-3 + PKTQ[0:3] 5 packet queue, units 0-3 + UFLG[0:3] 16 unit flags, units 0-3 + POS[0:3] 32 tape position, units 0-3 + OBJP[0:3] 32 object position, units 0-3 + INT 1 interrupt request + ITIME 1 response time for initialization steps + (except for step 4) + QTIME 24 response time for 'immediate' packets + XTIME 24 response time for data transfers + PKTS[33*32] 16 packet buffers, 33W each, + 32 entries + +Some DEC operating systems, notably RSX11M/M+, are very sensitive to +the timing parameters. Changing the default values may cause M/M+ to +crash on boot or to hang during operation. + +Error handling is as follows: + + error processed as + + not attached tape not ready + + end of file end of medium + + OS I/O error fatal tape error + +2.10 DELQA/DEQNA Ethernet Controller (XQ) + +XQ simulates the DELQA/DEQNA 10Mbps Ethernet controller. Options allow +control of the MAC address, the controller mode, and the sanity timer. + + SET XQ MAC= ex. 08-00-2B-AA-BB-CC + SHOW XQ MAC + +These commands are used to change or display the MAC address. +is a valid ethernet MAC, delimited by dashes or periods. The controller +defaults to 08-00-2B-AA-BB-CC, which should be sufficient if there is +only one SIMH controller on your LAN. Two cards with the same MAC address +will see each other's packets, resulting in a serious mess. + + SET XQ TYPE={DEQNA|[DELQA]} + SHOW XQ TYPE + +These commands are used to change or display the controller mode. DELQA +mode is better and faster but may not be usable by older or non-DEC OS's. +Also, be aware that DEQNA mode is not supported by many modern OS's. The +DEQNA-LOCK mode of the DELQA card is emulated by setting the the controller +to DEQNA - there is no need for a separate mode. DEQNA-LOCK mode behaves +exactly like a DEQNA, except for the operation of the VAR and MOP processing. + + SET XQ SANITY={ON|[OFF]} + SHOW XQ SANITY + +These commands change or display the INITIALIZATION sanity timer (DEQNA +jumper W3/DELQA switch S4). The INITIALIZATION sanity timer has a default +timeout of 4 minutes, and cannot be turned off, just reset. The normal +sanity timer can be set by operating system software regardless of the +state of this switch. Note that only the DEQNA (or the DELQA in DEQNA- +LOCK mode (=DEQNA)) supports the sanity timer - it is ignored by a DELQA +in Normal mode, which uses switch S4 for a different purpose. + +To access the network, the simulated Ethernet controller must be attached +to a real Ethernet interface: + + ATTACH XQ0 {ethX|} ex. eth0 or /dev/era0 + SHOW XQ ETH + +where X in 'ethX' is the number of the ethernet controller to attach, or +the real device name. The X number is system dependant. If you only have +one ethernet controller, the number will probably be 0. To find out what +your system thinks the ethernet numbers are, use the SHOW XQ ETH command. +The device list can be quite cryptic, depending on the host system, but +is probably better than guessing. If you do not attach the device, the +controller will behave as though the ethernet cable were unplugged. + +XQ has the following registers: + + name size comments + + SA0 16 station address word 0 + SA1 16 station address word 1 + SA2 16 station address word 2 + SA3 16 station address word 3 + SA4 16 station address word 4 + SA5 16 station address word 5 + CSR 16 control status register + VAR 16 vector address register + RBDL 32 receive buffer descriptor list + XBDL 32 trans(X)mit buffer descriptorlList + +One final note: because of it's asynchronous nature, the XQ controller is +not limited to the ~1.5Mbit/sec of the real DEQNA/DELQA controllers, +nor the 10Mbit/sec of a standard Ethernet. Attach it to a Fast Ethernet +(100 Mbit/sec) card, and "Feel the Power!" :-) + 2.11 Symbolic Display and Input The PDP-11 simulator implements symbolic display and input. Display is diff --git a/PDP11/pdp11_dz.c b/PDP11/pdp11_dz.c index 77a1296c..1b62f163 100644 --- a/PDP11/pdp11_dz.c +++ b/PDP11/pdp11_dz.c @@ -25,6 +25,7 @@ dz DZ11 terminal multiplexor + 01-Nov-02 RMS Added 8B support 09-Nov-01 RMS Added VAX support */ @@ -32,11 +33,13 @@ #define VM_VAX 1 #include "vax_defs.h" #define DZ_RDX 16 +#define DZ_8B_DFLT UNIT_8B #else #define VM_PDP11 1 #include "pdp11_defs.h" #define DZ_RDX 8 +#define DZ_8B_DFLT UNIT_8B #endif #include "dec_dz.h" diff --git a/PDP11/pdp11_fp.c b/PDP11/pdp11_fp.c index 3365f9be..3cb29322 100644 --- a/PDP11/pdp11_fp.c +++ b/PDP11/pdp11_fp.c @@ -23,6 +23,7 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 08-Oct-02 RMS Fixed macro definitions 05-Jun-98 RMS Fixed implementation specific shift bugs 20-Apr-98 RMS Fixed bug in MODf integer truncation 17-Apr-98 RMS Fixed bug in STCfi range check @@ -142,20 +143,20 @@ /* Double precision operations on 64b quantities */ #define F_LOAD(qd,ac,ds) ds.h = ac.h; ds.l = (qd)? ac.l: 0 -#define F_LOAD_P(qd,ac,ds) ds -> h = ac.h; ds -> l = (qd)? ac.l: 0 +#define F_LOAD_P(qd,ac,ds) ds->h = ac.h; ds->l = (qd)? ac.l: 0 #define F_LOAD_FRAC(qd,ac,ds) ds.h = (ac.h & FP_FRACH) | FP_HB; \ ds.l = (qd)? ac.l: 0 #define F_STORE(qd,sr,ac) ac.h = sr.h; if ((qd)) ac.l = sr.l -#define F_STORE_P(qd,sr,ac) ac.h = sr -> h; if ((qd)) ac.l = sr -> l -#define F_GET_FRAC_P(sr,ds) ds.l = sr -> l; \ - ds.h = (sr -> h & FP_FRACH) | FP_HB +#define F_STORE_P(qd,sr,ac) ac.h = sr->h; if ((qd)) ac.l = sr->l +#define F_GET_FRAC_P(sr,ds) ds.l = sr->l; \ + ds.h = (sr->h & FP_FRACH) | FP_HB #define F_ADD(s2,s1,ds) ds.l = (s1.l + s2.l) & 0xFFFFFFFF; \ ds.h = (s1.h + s2.h + (ds.l < s2.l)) & 0xFFFFFFFF #define F_SUB(s2,s1,ds) ds.h = (s1.h - s2.h - (s1.l < s2.l)) & 0xFFFFFFFF; \ ds.l = (s1.l - s2.l) & 0xFFFFFFFF #define F_LT(x,y) ((x.h < y.h) || ((x.h == y.h) && (x.l < y.l))) -#define F_LT_AP(x,y) (((x -> h & ~FP_SIGN) < (y -> h & ~FP_SIGN)) || \ - (((x -> h & ~FP_SIGN) == (y -> h & ~FP_SIGN)) && (x -> l < y -> l))) +#define F_LT_AP(x,y) (((x->h & ~FP_SIGN) < (y->h & ~FP_SIGN)) || \ + (((x->h & ~FP_SIGN) == (y->h & ~FP_SIGN)) && (x->l < y->l))) #define F_LSH_V(sr,n,ds) \ ds.h = (((n) >= 32)? (sr.l << ((n) - 32)): \ (sr.h << (n)) | ((sr.l >> (32 - (n))) & and_mask[n])) \ @@ -185,11 +186,11 @@ #define F_LSH_GUARD(ds) F_LSH_K(ds,FP_GUARD,ds) #define F_RSH_GUARD(ds) F_RSH_K(ds,FP_GUARD,ds) -#define GET_BIT(ir,n) (((ir) >> n) & 1) -#define GET_SIGN(ir) GET_BIT((ir), FP_V_SIGN) -#define GET_EXP(ir) (((ir) >> FP_V_EXP) & FP_M_EXP) -#define GET_SIGN_L(ir) GET_BIT((ir), 31) -#define GET_SIGN_W(ir) GET_BIT((ir), 15) +#define GET_BIT(ir,n) (((ir) >> (n)) & 1) +#define GET_SIGN(ir) GET_BIT((ir), FP_V_SIGN) +#define GET_EXP(ir) (((ir) >> FP_V_EXP) & FP_M_EXP) +#define GET_SIGN_L(ir) GET_BIT((ir), 31) +#define GET_SIGN_W(ir) GET_BIT((ir), 15) extern jmp_buf save_env; extern int32 FEC, FEA, FPS; @@ -197,9 +198,7 @@ extern int32 CPUERR, trap_req; extern int32 N, Z, V, C; extern int32 R[8]; extern fpac_t FR[6]; -extern int32 GeteaW (int32 spec); -extern int32 ReadW (int32 addr); -extern void WriteW (int32 data, int32 addr); + fpac_t zero_fac = { 0, 0 }; fpac_t one_fac = { 1, 0 }; fpac_t fround_fac = { (1u << (FP_V_FROUND + 32)), 0 }; @@ -218,6 +217,7 @@ static const uint32 and_mask[33] = { 0, int32 backup_PC; int32 fpnotrap (int32 code); int32 GeteaFP (int32 spec, int32 len); + unsigned int32 ReadI (int32 addr, int32 spec, int32 len); void ReadFP (fpac_t *fac, int32 addr, int32 spec, int32 len); void WriteI (int32 data, int32 addr, int32 spec, int32 len); @@ -230,6 +230,10 @@ int32 modfp11 (fpac_t *src1, fpac_t *src2, fpac_t *frac); void frac_mulfp11 (fpac_t *src1, fpac_t *src2); int32 roundfp11 (fpac_t *src); int32 round_and_pack (fpac_t *fac, int32 exp, fpac_t *frac, int r); + +extern int32 GeteaW (int32 spec); +extern int32 ReadW (int32 addr); +extern void WriteW (int32 data, int32 addr); /* Set up for instruction decode and execution */ @@ -565,16 +569,16 @@ if (spec <= 07) { F_LOAD_P (len == QUAD, FR[spec], fptr); return; } if (spec == 027) { - fptr -> h = (ReadW (VA) << FP_V_F0); - fptr -> l = 0; } + fptr->h = (ReadW (VA) << FP_V_F0); + fptr->l = 0; } else { exta = VA & ~0177777; - fptr -> h = (ReadW (VA) << FP_V_F0) | + fptr->h = (ReadW (VA) << FP_V_F0) | (ReadW (exta | ((VA + 2) & 0177777)) << FP_V_F1); - if (len == QUAD) fptr -> l = + if (len == QUAD) fptr->l = (ReadW (exta | ((VA + 4) & 0177777)) << FP_V_F2) | (ReadW (exta | ((VA + 6) & 0177777)) << FP_V_F3); - else fptr -> l = 0; } -if ((GET_SIGN (fptr -> h) != 0) && (GET_EXP (fptr -> h) == 0) && + else fptr->l = 0; } +if ((GET_SIGN (fptr->h) != 0) && (GET_EXP (fptr->h) == 0) && (fpnotrap (FEC_UNDFV) == 0)) ABORT (TRAP_INT); return; } @@ -614,13 +618,13 @@ int32 exta; if (spec <= 07) { F_STORE_P (len == QUAD, fptr, FR[spec]); return; } -WriteW ((fptr -> h >> FP_V_F0) & 0177777, VA); +WriteW ((fptr->h >> FP_V_F0) & 0177777, VA); if (spec == 027) return; exta = VA & ~0177777; -WriteW ((fptr -> h >> FP_V_F1) & 0177777, exta | ((VA + 2) & 0177777)); +WriteW ((fptr->h >> FP_V_F1) & 0177777, exta | ((VA + 2) & 0177777)); if (len == LONG) return; -WriteW ((fptr -> l >> FP_V_F2) & 0177777, exta | ((VA + 4) & 0177777)); -WriteW ((fptr -> l >> FP_V_F3) & 0177777, exta | ((VA + 6) & 0177777)); +WriteW ((fptr->l >> FP_V_F2) & 0177777, exta | ((VA + 4) & 0177777)); +WriteW ((fptr->l >> FP_V_F3) & 0177777, exta | ((VA + 6) & 0177777)); return; } @@ -642,8 +646,8 @@ if (F_LT_AP (facp, fsrcp)) { /* if !fac! < !fsrc! */ facfrac = *facp; *facp = *fsrcp; /* swap operands */ *fsrcp = facfrac; } -facexp = GET_EXP (facp -> h); /* get exponents */ -fsrcexp = GET_EXP (fsrcp -> h); +facexp = GET_EXP (facp->h); /* get exponents */ +fsrcexp = GET_EXP (fsrcp->h); if (facexp == 0) { /* fac = 0? */ *facp = fsrcexp? *fsrcp: zero_fac; /* result fsrc or 0 */ return 0; } @@ -654,7 +658,7 @@ F_GET_FRAC_P (facp, facfrac); /* get fractions */ F_GET_FRAC_P (fsrcp, fsrcfrac); F_LSH_GUARD (facfrac); /* guard fractions */ F_LSH_GUARD (fsrcfrac); -if (GET_SIGN (facp -> h) != GET_SIGN (fsrcp -> h)) { /* signs different? */ +if (GET_SIGN (facp->h) != GET_SIGN (fsrcp->h)) { /* signs different? */ if (ediff) { F_RSH_V (fsrcfrac, ediff, fsrcfrac); } /* sub, shf fsrc */ F_SUB (fsrcfrac, facfrac, facfrac); /* sub fsrc from fac */ if ((facfrac.h | facfrac.l) == 0) { /* result zero? */ @@ -695,15 +699,15 @@ int32 mulfp11 (fpac_t *facp, fpac_t *fsrcp) int32 facexp, fsrcexp; fpac_t facfrac, fsrcfrac; -facexp = GET_EXP (facp -> h); /* get exponents */ -fsrcexp = GET_EXP (fsrcp -> h); +facexp = GET_EXP (facp->h); /* get exponents */ +fsrcexp = GET_EXP (fsrcp->h); if ((facexp == 0) || (fsrcexp == 0)) { /* test for zero */ *facp = zero_fac; return 0; } F_GET_FRAC_P (facp, facfrac); /* get fractions */ F_GET_FRAC_P (fsrcp, fsrcfrac); facexp = facexp + fsrcexp - FP_BIAS; /* calculate exp */ -facp -> h = facp -> h ^ fsrcp -> h; /* calculate sign */ +facp->h = facp->h ^ fsrcp->h; /* calculate sign */ frac_mulfp11 (&facfrac, &fsrcfrac); /* multiply fracs */ /* Multiplying two numbers in the range [.5,1) produces a result in the @@ -734,8 +738,8 @@ int32 modfp11 (fpac_t *facp, fpac_t *fsrcp, fpac_t *fracp) int32 facexp, fsrcexp; fpac_t facfrac, fsrcfrac, fmask; -facexp = GET_EXP (facp -> h); /* get exponents */ -fsrcexp = GET_EXP (fsrcp -> h); +facexp = GET_EXP (facp->h); /* get exponents */ +fsrcexp = GET_EXP (fsrcp->h); if ((facexp == 0) || (fsrcexp == 0)) { /* test for zero */ *fracp = zero_fac; *facp = zero_fac; @@ -743,7 +747,7 @@ if ((facexp == 0) || (fsrcexp == 0)) { /* test for zero */ F_GET_FRAC_P (facp, facfrac); /* get fractions */ F_GET_FRAC_P (fsrcp, fsrcfrac); facexp = facexp + fsrcexp - FP_BIAS; /* calculate exp */ -fracp -> h = facp -> h = facp -> h ^ fsrcp -> h; /* calculate sign */ +fracp->h = facp->h = facp->h ^ fsrcp->h; /* calculate sign */ frac_mulfp11 (&facfrac, &fsrcfrac); /* multiply fracs */ /* Multiplying two numbers in the range [.5,1) produces a result in the @@ -861,11 +865,11 @@ int32 divfp11 (fpac_t *facp, fpac_t *fsrcp) int32 facexp, fsrcexp, i, count, qd; fpac_t facfrac, fsrcfrac, quo; -fsrcexp = GET_EXP (fsrcp -> h); /* get divisor exp */ +fsrcexp = GET_EXP (fsrcp->h); /* get divisor exp */ if (fsrcexp == 0) { /* divide by zero? */ fpnotrap (FEC_DZRO); ABORT (TRAP_INT); } -facexp = GET_EXP (facp -> h); /* get dividend exp */ +facexp = GET_EXP (facp->h); /* get dividend exp */ if (facexp == 0) { /* test for zero */ *facp = zero_fac; /* result zero */ return 0; } @@ -874,7 +878,7 @@ F_GET_FRAC_P (fsrcp, fsrcfrac); F_LSH_GUARD (facfrac); /* guard fractions */ F_LSH_GUARD (fsrcfrac); facexp = facexp - fsrcexp + FP_BIAS + 1; /* calculate exp */ -facp -> h = facp -> h ^ fsrcp -> h; /* calculate sign */ +facp->h = facp->h ^ fsrcp->h; /* calculate sign */ qd = FPS & FPS_D; count = FP_V_HB + FP_GUARD + (qd? 33: 1); /* count = 56b/24b */ @@ -933,7 +937,7 @@ fpac_t outf; outf = *fptr; /* get argument */ F_ADD (fround_fac, outf, outf); /* round */ -if (GET_SIGN (outf.h ^ fptr -> h)) { /* flipped sign? */ +if (GET_SIGN (outf.h ^ fptr->h)) { /* flipped sign? */ outf.h = (outf.h ^ FP_SIGN) & 0xFFFFFFFF; /* restore sign */ if (fpnotrap (FEC_OVFLO)) *fptr = zero_fac; /* if no int, clear */ else *fptr = outf; /* return rounded */ @@ -966,8 +970,8 @@ if (r && ((FPS & FPS_T) == 0)) { F_RSH_1 (frac); exp = exp + 1; } } F_RSH_GUARD (frac); -facp -> l = frac.l & FP_FRACL; -facp -> h = (facp -> h & FP_SIGN) | ((exp & FP_M_EXP) << FP_V_EXP) | +facp->l = frac.l & FP_FRACL; +facp->h = (facp->h & FP_SIGN) | ((exp & FP_M_EXP) << FP_V_EXP) | (frac.h & FP_FRACH); if (exp > 0377) { if (fpnotrap (FEC_OVFLO)) *facp = zero_fac; diff --git a/PDP11/pdp11_hk.c b/PDP11/pdp11_hk.c new file mode 100644 index 00000000..2f1d8a07 --- /dev/null +++ b/PDP11/pdp11_hk.c @@ -0,0 +1,1141 @@ +/* pdp11_hk.c - RK611/RK06/RK07 disk controller + + Copyright (c) 1993-2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PUHKOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + hk RK611/RK06/RK07 disk + + This is a somewhat abstracted implementation of the RK611, more closely + modelled on third party clones than DEC's own implementation. In particular, + the drive-to-controller serial communications system is simulated only at + a level equal to the Emulex SC21. + + The RK611 functions only in 18b Unibus systems with I/O maps. The Emulex + SC02/C was a Qbus work-alike with a unique extension to 22b addressing. It + was only supported in Ultrix-11 and other third party software. + + This module includes ideas from a previous implementation by Fred Van Kempen. +*/ + +#include "pdp11_defs.h" +#define VM_PDP11 1 +#define HK_RDX 8 +#define HK_WID 16 +extern int32 cpu_18b, cpu_ubm; + +extern uint16 *M; + +#define HK_NUMDR 8 /* #drives */ +#define HK_NUMCY6 411 /* cyl/drive */ +#define HK_NUMCY7 815 /* cyl/drive */ +#define HK_NUMSF 3 /* tracks/cyl */ +#define HK_NUMSC 22 /* sectors/track */ +#define HK_NUMWD 256 /* words/sector */ +#define RK06_SIZE (HK_NUMCY6*HK_NUMSF*HK_NUMSC*HK_NUMWD) +#define RK07_SIZE (HK_NUMCY7*HK_NUMSF*HK_NUMSC*HK_NUMWD) +#define HK_SIZE(x) (((x)->flags & UNIT_DTYPE)? RK07_SIZE: RK06_SIZE) +#define HK_CYL(x) (((x)->flags & UNIT_DTYPE)? HK_NUMCY7: HK_NUMCY6) +#define HK_MAXFR (1 << 16) + +/* Flags in the unit flags word */ + +#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */ +#define UNIT_V_AUTO (UNIT_V_UF + 2) /* autosize */ +#define UNIT_V_DUMMY (UNIT_V_UF + 3) /* dummy flag */ +#define UNIT_WLK (1 << UNIT_V_WLK) +#define UNIT_DTYPE (1 << UNIT_V_DTYPE) +#define UNIT_RK06 (0 << UNIT_V_DTYPE) +#define UNIT_RK07 (1 << UNIT_V_DTYPE) +#define UNIT_AUTO (1 << UNIT_V_AUTO) +#define UNIT_DUMMY (1 << UNIT_V_DUMMY) +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */ + +/* Parameters in the unit descriptor */ + +#define CYL u3 /* current cylinder */ +#define FNC u4 /* function */ + +/* HKCS1 - 177440 - control/status 1 */ + +#define CS1_GO CSR_GO /* go */ +#define CS1_V_FNC 1 /* function pos */ +#define CS1_M_FNC 017 /* function mask */ +#define CS1_FNC (CS1_M_FNC << CS1_V_FNC) +#define FNC_NOP 000 /* no operation */ +#define FNC_PACK 001 /* pack acknowledge */ +#define FNC_DCLR 002 /* drive clear */ +#define FNC_UNLOAD 003 /* unload */ +#define FNC_START 004 /* start */ +#define FNC_RECAL 005 /* recalibrate */ +#define FNC_OFFSET 006 /* offset */ +#define FNC_SEEK 007 /* seek */ +#define FNC_XFER 010 +#define FNC_READ 010 /* read */ +#define FNC_WRITE 011 /* write */ +#define FNC_WRITEH 013 /* write w/ headers */ +#define FNC_READH 012 /* read w/ headers */ +#define FNC_WCHK 014 /* write check */ +#define FNC_2ND 020 /* 2nd state flag */ +#define CS1_SPA 0000040 /* spare */ +#define CS1_IE CSR_IE /* int enable */ +#define CS1_DONE CSR_DONE /* ready */ +#define CS1_V_UAE 8 /* Unibus addr ext */ +#define CS1_M_UAE 03 +#define CS1_UAE (CS1_M_UAE << CS1_V_UAE) +#define CS1_DT 0002000 /* drive type */ +#define CS1_CTO 0004000 /* ctrl timeout NI */ +#define CS1_FMT 0010000 /* 16b/18b NI */ +#define CS1_PAR 0020000 /* par err NI */ +#define CS1_DI 0040000 /* drive intr */ +#define CS1_ERR 0100000 /* error */ +#define CS1_CCLR 0100000 /* ctrl clear */ +#define CS1_RW (CS1_DT|CS1_UAE|CS1_IE|CS1_SPA|CS1_FNC|CS1_GO) +#define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC) +#define GET_UAE(x) (((x) >> CS1_V_UAE) & CS1_M_UAE) +#define PUT_UAE(x,n) (((x) & ~ CS1_UAE) | (((n) << CS1_V_UAE) & CS1_UAE)) + +/* HKWC - 177442 - word count */ + +/* HKBA - 177444 - base address */ + +#define BA_MBZ 0000001 /* must be zero */ + +/* HKDA - 177446 - sector/track */ + +#define DA_V_SC 0 /* sector pos */ +#define DA_M_SC 037 /* sector mask */ +#define DA_V_SF 8 /* track pos */ +#define DA_M_SF 007 /* track mask */ +#define DA_MBZ 0174340 +#define GET_SC(x) (((x) >> DA_V_SC) & DA_M_SC) +#define GET_SF(x) (((x) >> DA_V_SF) & DA_M_SF) + +/* HKCS2 - 177450 - control/status 2 */ + +#define CS2_V_UNIT 0 /* unit pos */ +#define CS2_M_UNIT 07 /* unit mask */ +#define CS2_UNIT (CS2_M_UNIT << CS2_V_UNIT) +#define CS2_RLS 0000010 /* release NI */ +#define CS2_UAI 0000020 /* addr inhibit */ +#define CS2_CLR 0000040 /* controller clear */ +#define CS2_IR 0000100 /* input ready */ +#define CS2_OR 0000200 /* output ready */ +#define CS2_UFE 0000400 /* unit field err NI */ +#define CS2_MDS 0001000 /* multidrive sel NI */ +#define CS2_PGE 0002000 /* program err */ +#define CS2_NEM 0004000 /* nx mem err */ +#define CS2_NED 0010000 /* nx drive err */ +#define CS2_PE 0020000 /* parity err NI */ +#define CS2_WCE 0040000 /* write check err */ +#define CS2_DLT 0100000 /* data late NI */ +#define CS2_MBZ (CS2_CLR) +#define CS2_RW 0000037 +#define CS2_ERR (CS2_UFE | CS2_MDS | CS2_PGE | CS2_NEM | \ + CS2_NED | CS2_PE | CS2_WCE | CS2_DLT ) +#define GET_UNIT(x) (((x) >> CS2_V_UNIT) & CS2_M_UNIT) + +/* HKDS - 177452 - drive status ^ = calculated dynamically */ + +#define DS_DRA 0000001 /* ^drive avail */ +#define DS_OF 0000004 /* ^offset mode */ +#define DS_ACLO 0000010 /* ^AC LO NI */ +#define DS_SPLS 0000020 /* ^speed loss NI */ +#define DS_DOT 0000040 /* ^off track NI */ +#define DS_VV 0000100 /* volume valid */ +#define DS_RDY 0000200 /* ^drive ready */ +#define DS_DT 0000400 /* ^drive type */ +#define DS_WRL 0004000 /* ^write locked */ +#define DS_PIP 0020000 /* pos in progress */ +#define DS_ATA 0040000 /* attention active */ +#define DS_VLD 0100000 /* ^status valid */ +#define DS_MBZ 0013002 + +/* HKER - 177454 - error status */ + +#define ER_ILF 0000001 /* illegal func */ +#define ER_SKI 0000002 /* seek incomp */ +#define ER_NXF 0000004 /* non-exec func */ +#define ER_PAR 0000010 /* parity err */ +#define ER_FER 0000020 /* format err NI */ +#define ER_DTY 0000040 /* drive type err */ +#define ER_ECH 0000100 /* ECC hard err NI */ +#define ER_BSE 0000200 /* bad sector err NI */ +#define ER_HCR 0000400 /* hdr CRC err NI */ +#define ER_AOE 0001000 /* addr ovflo err */ +#define ER_IAE 0002000 /* invalid addr err */ +#define ER_WLE 0004000 /* write lock err */ +#define ER_DTE 0010000 /* drive time err NI */ +#define ER_OPI 0020000 /* op incomplete */ +#define ER_UNS 0040000 /* drive unsafe */ +#define ER_DCK 0100000 /* data check NI */ + +/* HKAS - 177456 - attention summary/offset */ + +#define AS_U0 0000400 /* unit 0 flag */ +#define AS_OF 0000277 /* offset mask */ + +/* HKDC - 177460 - desired cylinder */ + +#define DC_V_CY 0 /* cylinder pos */ +#define DC_M_CY 0001777 /* cylinder mask */ +#define DC_MBZ 0176000 +#define GET_CY(x) (((x) >> DC_V_CY) & DC_M_CY) +#define GET_DA(c,fs) ((((GET_CY (c) * HK_NUMSF) + \ + GET_SF (fs)) * HK_NUMSC) + GET_SC (fs)) + +/* Spare - 177462 - read/write */ + +#define XM_KMASK 0177700 /* Qbus XM key mask */ +#define XM_KEY 0022000 /* Qbus XM "key" */ +#define XM_MMASK 0000077 /* Qbus XM mask */ +#define SC02C (!UNIBUS && ((hkspr & XM_KMASK) == XM_KEY)) + +/* HKDB - 177464 - read/write */ + +/* HKMR - 177466 - maintenance register 1 */ + +#define MR_V_MS 0 /* message select */ +#define MR_M_MS 03 +#define MR_MS (MR_M_MS << MR_V_MS) +#define GET_MS(x) (((x) >> MR_V_MS) & MR_M_MS) +#define MR_PAR 0000020 /* force even parity */ +#define MR_DMD 0000040 /* diagnostic mode */ +#define MR_RW 0001777 + +/* HKEC1 - 177470 - ECC status 1 - always reads as 0 */ +/* HKEC2 - 177472 - ECC status 2 - always reads as 0 */ + +/* HKMR2 - 177474 - maintenance register 2 */ + +#define AX_V_UNIT 0 /* unit #, all msgs */ +#define AX_PAR 0100000 /* parity, all msgs */ + +#define A0_DRA 0000040 /* drive avail */ +#define A0_VV 0000100 /* vol valid */ +#define A0_RDY 0000200 /* drive ready */ +#define A0_DT 0000400 /* drive type */ +#define A0_FMT 0001000 /* format NI */ +#define A0_OF 0002000 /* offset mode */ +#define A0_WRL 0004000 /* write lock */ +#define A0_SPO 0010000 /* spindle on */ +#define A0_PIP 0020000 /* pos in prog */ +#define A0_ATA 0040000 /* attention */ + +#define A1_SRV 0000020 /* servo */ +#define A1_HHM 0000040 /* heads home */ +#define A1_BHM 0000100 /* brushes home */ +#define A1_DOR 0000200 /* door latched */ +#define A1_CAR 0000400 /* cartridge present */ +#define A1_SPD 0001000 /* speed ok */ +#define A1_FWD 0002000 /* seek fwd */ +#define A1_REV 0004000 /* seek rev */ +#define A1_LDH 0010000 /* loading heads NI */ +#define A1_RTZ 0020000 /* return to zero */ +#define A1_UNL 0040000 /* unloading heads */ + +#define A2_V_DIF 4 /* cyl diff */ +#define A2_M_DIF 0777 + +#define A3_V_SNO 3 /* serial # */ + +/* HKMR3 - 177476 - maintenance register 3 */ + +#define B0_IAE 0000040 /* invalid addr */ +#define B0_ACLO 0000100 /* AC LO NI */ +#define B0_FLT 0000200 /* fault */ +#define B0_NXF 0000400 /* non exec fnc */ +#define B0_CDP 0001000 /* msg parity err */ +#define B0_SKI 0002000 /* seek incomp */ +#define B0_WLE 0004000 /* write lock err */ +#define B0_SLO 0010000 /* speed low NI */ +#define B0_OFT 0020000 /* off track NI */ +#define B0_UNS 0040000 /* rw unsafe NI */ + +#define B1_SCE 0000020 /* sector err NI */ +#define B1_NWC 0000040 /* no write curr NI */ +#define B1_NWT 0000100 /* no write trans NI */ +#define B1_HFL 0000200 /* head fault NI */ +#define B1_MHS 0000400 /* multiselect NI */ +#define B1_IDX 0001000 /* index err NI */ +#define B1_TRI 0002000 /* tribit err NI */ +#define B1_SVE 0004000 /* servo err NI */ +#define B1_SKI 0010000 /* seek no mot */ +#define B1_LIM 0020000 /* seek limit NI */ +#define B1_SVU 0040000 /* servo unsafe NI */ + +#define B2_V_CYL 4 /* cylinder */ + +#define B3_V_SEC 4 /* sector */ +#define B3_V_DHA 9 /* decoded head */ + +/* Read header */ + +#define RDH1_V_CYL 0 /* cylinder */ +#define RDH2_V_SEC 0 /* sector */ +#define RDH2_V_DHA 5 /* decoded head */ +#define RDH2_GOOD 0140000 /* good sector flags */ + +extern int32 int_req[IPL_HLVL]; +extern int32 int_vec[IPL_HLVL][32]; +extern int32 cpu_log; +extern FILE *sim_log; + +uint16 *hkxb = NULL; /* xfer buffer */ +int32 hkcs1 = 0; /* control/status 1 */ +int32 hkwc = 0; /* word count */ +int32 hkba = 0; /* bus address */ +int32 hkda = 0; /* track/sector */ +int32 hkcs2 = 0; /* control/status 2 */ +int32 hkds[HK_NUMDR] = { 0 }; /* drive status */ +int32 hker[HK_NUMDR] = { 0 }; /* error status */ +int32 hkof = 0; /* offset */ +int32 hkmr = 0; /* maint registers */ +int32 hkmr2 = 0; +int32 hkmr3 = 0; +int32 hkdc = 0; /* cylinder */ +int32 hkspr = 0; /* spare */ +int32 hk_stopioe = 1; /* stop on error */ +int32 hk_cwait = 5; /* command time */ +int32 hk_swait = 10; /* seek time */ +int32 hk_rwait = 10; /* rotate time */ +int16 hkdb[3] = { 0 }; /* data buffer silo */ +int16 hk_off[HK_NUMDR] = { 0 }; /* saved offset */ +int16 hk_dif[HK_NUMDR] = { 0 }; /* cylinder diff */ +static int reg_in_drive[16] = { + 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +DEVICE hk_dev; +t_stat hk_rd (int32 *data, int32 PA, int32 access); +t_stat hk_wr (int32 data, int32 PA, int32 access); +t_stat hk_svc (UNIT *uptr); +t_stat hk_reset (DEVICE *dptr); +t_stat hk_boot (int32 unitno, DEVICE *dptr); +t_stat hk_attach (UNIT *uptr, char *cptr); +t_stat hk_detach (UNIT *uptr); +int32 hk_rdmr2 (int32 msg); +int32 hk_rdmr3 (int32 msg); +void update_hkcs (int32 flags, int32 drv); +void update_hkds (int32 drv); +void hk_cmderr (int32 err, int32 drv); +void hk_go (int32 drv); +t_stat hk_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat hk_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc); + +extern t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds); + +/* HK data structures + + hk_dev HK device descriptor + hk_unit HK unit list + hk_reg HK register list + hk_mod HK modifier list +*/ + +DIB hk_dib = { IOBA_HK, IOLN_HK, &hk_rd, &hk_wr, + 1, IVCL (HK), VEC_HK, { NULL } }; + +UNIT hk_unit[] = { + { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ + UNIT_ROABLE+UNIT_RK06, RK06_SIZE) }, + { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ + UNIT_ROABLE+UNIT_RK06, RK06_SIZE) }, + { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ + UNIT_ROABLE+UNIT_RK06, RK06_SIZE) }, + { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ + UNIT_ROABLE+UNIT_RK06, RK06_SIZE) }, + { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ + UNIT_ROABLE+UNIT_RK06, RK06_SIZE) }, + { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ + UNIT_ROABLE+UNIT_RK06, RK06_SIZE) }, + { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ + UNIT_ROABLE+UNIT_RK06, RK06_SIZE) }, + { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ + UNIT_ROABLE+UNIT_RK06, RK06_SIZE) } }; + +REG hk_reg[] = { + { GRDATA (HKCS1, hkcs1, HK_RDX, 16, 0) }, + { GRDATA (HKWC, hkwc, HK_RDX, 16, 0) }, + { GRDATA (HKBA, hkba, HK_RDX, 16, 0) }, + { GRDATA (HKDA, hkda, HK_RDX, 16, 0) }, + { GRDATA (HKCS2, hkcs2, HK_RDX, 16, 0) }, + { BRDATA (HKDS, hkds, HK_RDX, 16, HK_NUMDR) }, + { BRDATA (HKER, hker, HK_RDX, 16, HK_NUMDR) }, + { BRDATA (HKDB, hkdb, HK_RDX, 16, 3) }, + { GRDATA (HKDC, hkdc, HK_RDX, 16, 0) }, + { GRDATA (HKOF, hkof, HK_RDX, 8, 0) }, + { GRDATA (HKMR, hkmr, HK_RDX, 16, 0) }, + { GRDATA (HKMR2, hkmr2, HK_RDX, 16, 0), REG_RO }, + { GRDATA (HKMR3, hkmr3, HK_RDX, 16, 0), REG_RO }, + { GRDATA (HKSPR, hkspr, HK_RDX, 16, 0) }, + { FLDATA (INT, IREQ (HK), INT_V_HK) }, + { FLDATA (ERR, hkcs1, CSR_V_ERR) }, + { FLDATA (DONE, hkcs1, CSR_V_DONE) }, + { FLDATA (IE, hkcs1, CSR_V_IE) }, + { DRDATA (STIME, hk_swait, 24), REG_NZ + PV_LEFT }, + { DRDATA (RTIME, hk_rwait, 24), REG_NZ + PV_LEFT }, + { URDATA (FNC, hk_unit[0].FNC, HK_RDX, 5, 0, + HK_NUMDR, REG_HRO) }, + { URDATA (CYL, hk_unit[0].CYL, HK_RDX, 10, 0, + HK_NUMDR, REG_HRO) }, + { BRDATA (OFFSET, hk_off, HK_RDX, 16, HK_NUMDR), REG_HRO }, + { BRDATA (CYLDIF, hk_dif, HK_RDX, 16, HK_NUMDR), REG_HRO }, + { URDATA (CAPAC, hk_unit[0].capac, 10, 32, 0, + HK_NUMDR, PV_LEFT | REG_HRO) }, + { FLDATA (STOP_IOE, hk_stopioe, 0) }, + { GRDATA (DEVADDR, hk_dib.ba, HK_RDX, 32, 0), REG_HRO }, + { GRDATA (DEVVEC, hk_dib.vec, HK_RDX, 16, 0), REG_HRO }, + { NULL } }; + +MTAB hk_mod[] = { + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, + { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, + { UNIT_DUMMY, 0, NULL, "BADBLOCK", &hk_set_bad }, + { (UNIT_DTYPE+UNIT_ATT), UNIT_RK06 + UNIT_ATT, + "RK06", NULL, NULL }, + { (UNIT_DTYPE+UNIT_ATT), UNIT_RK07 + UNIT_ATT, + "RK07", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), UNIT_RK06, + "RK06", NULL, NULL }, + { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), UNIT_RK07, + "RK07", NULL, NULL }, + { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL }, + { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL }, + { (UNIT_AUTO+UNIT_DTYPE), UNIT_RK06, + NULL, "RK06", &hk_set_size }, + { (UNIT_AUTO+UNIT_DTYPE), UNIT_RK07, + NULL, "RK07", &hk_set_size }, + { MTAB_XTD|MTAB_VDV, 0040, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + &set_vec, &show_vec, NULL }, + { 0 } }; + +DEVICE hk_dev = { + "HK", hk_unit, hk_reg, hk_mod, + HK_NUMDR, HK_RDX, 24, 1, HK_RDX, HK_WID, + NULL, NULL, &hk_reset, + &hk_boot, &hk_attach, &hk_detach, + &hk_dib, DEV_DISABLE | DEV_UBUS }; + +/* I/O dispatch routines, I/O addresses 17777440 - 17777476 */ + +t_stat hk_rd (int32 *data, int32 PA, int32 access) +{ +int32 drv, i, j; + +drv = GET_UNIT (hkcs2); /* get current unit */ +j = (PA >> 1) & 017; /* get reg offset */ +if (reg_in_drive[j] && (hk_unit[drv].flags & UNIT_DIS)) { /* nx disk */ + hkcs2 = hkcs2 | CS2_NED; /* set error flag */ + update_hkcs (0, drv); + *data = 0; + return SCPE_OK; } + +update_hkcs (0, drv); /* update status */ +switch (j) { /* decode PA<4:1> */ +case 000: /* HKCS1 */ + *data = hkcs1; + break; +case 001: /* HKWC */ + *data = hkwc; + break; +case 002: /* HKBA */ + *data = hkba = hkba & ~BA_MBZ; + break; +case 003: /* HKDA */ + *data = hkda = hkda & ~DA_MBZ; + break; +case 004: /* HKCS2 */ + *data = hkcs2 = (hkcs2 & ~CS2_MBZ) | CS2_IR | CS2_OR; + break; +case 005: /* HKDS */ + *data = hkds[drv]; + break; +case 006: /* HKER */ + *data = hker[drv]; + break; +case 007: /* HKAS */ + *data = hkof; + for (i = 0; i < HK_NUMDR; i++) + if (hkds[i] & DS_ATA) *data = *data | (AS_U0 << i); + break; +case 010: /* HKDC */ + *data = hkdc = hkdc & ~DC_MBZ; + break; +case 011: /* spare */ + *data = hkspr; + break; +case 012: /* HKDB */ + *data = hkdb[0]; /* top of silo */ + hkdb[0] = hkdb[1]; /* ripple silo */ + hkdb[1] = hkdb[2]; + hkdb[2] = 0; /* just for READH */ + break; +case 013: /* HKMR */ + *data = hkmr; + break; +case 014: /* HKEC1 */ +case 015: /* HKEC2 */ + *data = 0; /* no ECC */ + break; +case 016: /* HKMR2 */ + *data = hkmr2 = hk_rdmr2 (GET_MS (hkmr)); + break; +case 017: /* HKMR3 */ + *data = hkmr3 = hk_rdmr3 (GET_MS (hkmr)); + break; } +return SCPE_OK; +} + +t_stat hk_wr (int32 data, int32 PA, int32 access) +{ +int32 drv, i, j; +UNIT *uptr; + +drv = GET_UNIT (hkcs2); /* get current unit */ +uptr = hk_dev.units + drv; /* get unit */ +j = (PA >> 1) & 017; /* get reg offset */ +if ((hkcs1 & CS1_GO) && /* busy? */ + !(((j == 0) && (data & CS1_CCLR)) || /* not cclr or sclr? */ + ((j == 4) && (data & CS2_CLR)))) { + hkcs2 = hkcs2 | CS2_PGE; /* prog error */ + update_hkcs (0, drv); + return SCPE_OK; } + +switch (j) { /* decode PA<4:1> */ +case 000: /* HKCS1 */ + if (data & CS1_CCLR) { /* controller reset? */ + hkcs1 = CS1_DONE; /* CS1 = done */ + hkcs2 = CS2_IR | CS2_OR; /* CS2 = ready */ + hkmr = hkmr2 = hkmr3 = 0; /* maint = 0 */ + hkda = hkdc = 0; + hkba = hkwc = 0; + hkspr = hkof = 0; + CLR_INT (HK); /* clr int */ + for (i = 0; i < HK_NUMDR; i++) { /* stop data xfr */ + if (sim_is_active (&hk_unit[i]) && + ((uptr->FNC & CS1_M_FNC) >= FNC_XFER)) + sim_cancel (&hk_unit[i]); } + drv = 0; + break; } + if (data & CS1_IE) { /* setting IE? */ + if (data & CS1_DONE) SET_INT (HK); } /* write to DONE+IE? */ + else CLR_INT (HK); /* no, clr intr */ + hkcs1 = (hkcs1 & ~CS1_RW) | (data & CS1_RW); /* merge data */ + if (SC02C) hkspr = (hkspr & ~CS1_M_UAE) | GET_UAE (hkcs1); + if (hkcs1 & CS1_GO) { /* go? */ + if (hkcs1 & CS1_ERR) hkcs1 = hkcs1 & ~CS1_GO; + else hk_go (drv); } + break; +case 001: /* HKWC */ + hkwc = data; + break; +case 002: /* HKBA */ + hkba = data & ~BA_MBZ; + break; +case 003: /* HKDA */ + hkda = data & ~DA_MBZ; + break; +case 004: /* HKCS2 */ + if (data & CS2_CLR) hk_reset (&hk_dev); /* init? */ + else hkcs2 = (hkcs2 & ~CS2_RW) | (data & CS2_RW) | CS2_IR | CS2_OR; + drv = GET_UNIT (hkcs2); + break; +case 007: /* HKAS */ + hkof = data & AS_OF; + break; +case 010: /* HKDC */ + hkdc = data & ~DC_MBZ; + break; +case 011: /* spare */ + hkspr = data; + if (SC02C) hkcs1 = PUT_UAE (hkcs1, hkspr & 03); /* SC02C? upd UAE */ + break; +case 012: /* HKDB */ + hkdb[0] = data; + break; +case 013: /* HKMR */ + hkmr = data & MR_RW; + break; +default: /* all others RO */ + break; } /* end switch */ +update_hkcs (0, drv); /* update status */ +return SCPE_OK; +} + +/* Initiate operation - unit not busy, function set */ + +void hk_go (int32 drv) +{ + +int32 fnc, t; +UNIT *uptr; +static int fnc_nxf[16] = { + 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0 }; +static int fnc_att[16] = { + 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }; +static int fnc_rdy[16] = { + 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 }; +static int fnc_cyl[16] = { + 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0 }; + +fnc = GET_FNC (hkcs1); +if (DBG_LOG (LOG_HK)) fprintf (sim_log, + ">>HK%d: fnc=%o, ds=%o, cyl=%o, da=%o, ba=%o, wc=%o\n", + drv, fnc, hkds[drv], hkdc, hkda, hkba, hkwc); +uptr = hk_dev.units + drv; /* get unit */ +if (fnc != FNC_NOP) hkmr = hkmr & ~MR_MS; /* !nop, clr msg sel */ +if (uptr->flags & UNIT_DIS) { /* nx unit? */ + hkcs2 = hkcs2 | CS2_NED; /* set error flag */ + update_hkcs (CS1_DONE, drv); /* done */ + return; } +if (((hkcs1 & CS1_DT) != 0) != /* dtype mismatch? */ + ((uptr->flags & UNIT_DTYPE) != 0)) { + hk_cmderr (ER_DTY, drv); /* type error */ + return; } +if (fnc_nxf[fnc] && ((hkds[drv] & DS_VV) == 0)) { /* need vol valid? */ + hk_cmderr (ER_NXF, drv); /* non exec func */ + return; } +if (fnc_att[fnc] && ((uptr->flags & UNIT_ATT) == 0)) { /* need attached? */ + hk_cmderr (ER_UNS, drv); /* unsafe */ + return; } +if (fnc_rdy[fnc] && sim_is_active (uptr)) { /* need inactive? */ + hkcs1 = (hkcs1 | CS1_DONE) & ~CS1_GO; /* ignore if busy */ + return; } +if (fnc_cyl[fnc] && /* need valid cyl */ + ((GET_CY (hkdc) >= HK_CYL (uptr)) || /* bad cylinder */ + (GET_SF (hkda) >= HK_NUMSF) || /* bad surface */ + (GET_SC (hkda) >= HK_NUMSC))) { /* or bad sector? */ + hk_cmderr (ER_IAE, drv); /* illegal addr */ + return; } + +hkcs1 = hkcs1 & ~CS1_DONE; /* clear done */ +hkds[drv] = hkds[drv] & ~DS_ATA; /* clear attention */ +uptr->FNC = fnc; /* save function */ +switch (fnc) { /* case on function */ + +/* "Fast functions" finish in less than 15 usec */ + +case FNC_NOP: /* no operation */ +case FNC_DCLR: /* drive clear */ +case FNC_START: /* start spindle */ +case FNC_UNLOAD: /* unload */ +case FNC_PACK: /* pack acknowledge */ + sim_activate (uptr, hk_cwait); /* schedule */ + return; + +/* Positioning functions provide two interrupts - an immediate interrupt + on ctrl done and a second one (if ctrl ready) when the seek is complete */ + +case FNC_OFFSET: /* offset mode */ +case FNC_RECAL: /* recalibrate */ +case FNC_SEEK: /* seek */ + hkds[drv] = hkds[drv] | DS_PIP; /* set positioning */ + sim_activate (uptr, hk_cwait); /* schedule */ + return; + +/* Data transfer functions lock the controller for the duration */ + +case FNC_WRITEH: /* write headers */ +case FNC_WRITE: /* write */ + hk_off[drv] = 0; /* clr offset */ +case FNC_WCHK: /* write check */ +case FNC_READ: /* read */ +case FNC_READH: /* read headers */ + hk_dif[drv] = hkdc - uptr->CYL; /* cyl diff */ + t = abs (hk_dif[drv]); /* |cyl diff| */ + sim_activate (uptr, hk_rwait + (hk_swait * t)); /* Schedule */ + uptr->CYL = hkdc; /* update cyl */ + return; + +default: + hk_cmderr (ER_ILF, drv); /* not supported */ + break; } +return; +} + +/* Service unit timeout + + Complete movement or data transfer command + Unit must exist - can't remove an active unit + Unit must be attached - detach cancels in progress operations +*/ + +t_stat hk_svc (UNIT *uptr) +{ +int32 i, t, dc, drv, fnc, err; +int32 wc, awc, da; +t_addr ba; +uint16 comp; + +drv = uptr - hk_dev.units; /* get drv number */ +fnc = uptr->FNC & CS1_M_FNC; /* get function */ +switch (fnc) { /* case on function */ + +/* Fast commands and other NOPs - start spindle only provides one interrupt + because ATTACH implicitly spins up the drive */ + +case FNC_DCLR: /* drive clear */ + hker[drv] = 0; /* clear errors */ + update_hkcs (CS1_DONE, drv); /* done */ + break; + +case FNC_PACK: /* pack acknowledge */ + hkds[drv] = hkds[drv] | DS_VV; /* set volume valid */ + update_hkcs (CS1_DONE, drv); /* done */ + break; + +case FNC_UNLOAD: /* unload */ + hk_detach (uptr); /* detach unit */ +case FNC_START: /* start spindle */ +case FNC_NOP: /* select */ + update_hkcs (CS1_DONE, drv); /* done */ + break; + +/* Positioning commands provide two interrupts, an immediate controller done + and a delayed drive interrupt */ + +case FNC_OFFSET: /* offset */ + if (uptr->FNC & FNC_2ND) { /* 2nd int? */ + hkds[drv] = (hkds[drv] & ~DS_PIP) | DS_ATA; /* upd sta */ + update_hkcs (CS1_DI, drv); } /* drive intr */ + else { uptr->FNC = uptr->FNC | FNC_2ND; /* second state */ + hk_off[drv] = hkof & AS_OF; /* save offset */ + sim_activate (uptr, hk_swait * 10); /* wait for compl */ + update_hkcs (CS1_DONE, drv); } /* done */ + break; + +case FNC_RECAL: /* recalibrate */ +case FNC_SEEK: /* seek */ + if (uptr->FNC & FNC_2ND) { /* 2nd int? */ + hkds[drv] = (hkds[drv] & ~DS_PIP) | DS_ATA; /* upd sta */ + update_hkcs (CS1_DI, drv); } /* drive intr */ + else { uptr->FNC = uptr->FNC | FNC_2ND; /* second state */ + hk_off[drv] = 0; /* clr offset */ + dc = (fnc == FNC_SEEK)? hkdc: 0; /* get cyl */ + hk_dif[drv] = dc - uptr->CYL; /* cyl diff */ + t = abs (hk_dif[drv]); /* |cyl diff| */ + if (t == 0) t = 1; /* min time */ + uptr->CYL = dc; /* save cyl */ + sim_activate (uptr, hk_swait * t); /* schedule */ + update_hkcs (CS1_DONE, drv); } /* done */ + break; + +/* Data transfer commands only generate one interrupt */ + +case FNC_READH: + hkdb[0] = uptr->CYL << RDH1_V_CYL; /* first word */ + hkdb[1] = (GET_SC (hkda) << RDH2_V_SEC) | /* second word */ + (1 << (GET_SF (hkda) + RDH2_V_DHA)) | RDH2_GOOD; + hkdb[2] = hkdb[0] ^ hkdb[1]; /* checksum */ + update_hkcs (CS1_DONE, drv); /* done */ + break; + +case FNC_WRITE: /* write */ + if (uptr->flags & UNIT_WPRT) { /* write locked? */ + hk_cmderr (ER_WLE, drv); /* command error */ + return SCPE_OK; } +case FNC_WCHK: /* write check */ +case FNC_READ: /* read */ + if (SC02C) ba = ((hkspr & XM_MMASK) << 16) | hkba; /* 22b addr? */ + else ba = (GET_UAE (hkcs1) << 16) | hkba; /* no, 18b addr */ + da = GET_DA (hkdc, hkda) * HK_NUMWD; /* get disk addr */ + wc = 0200000 - hkwc; /* get true wc */ + + if ((da + wc) > HK_SIZE (uptr)) { /* disk overrun? */ + hker[drv] = hker[drv] | ER_AOE; /* set err */ + wc = HK_SIZE (uptr) - da; /* trim xfer */ + if (da >= HK_SIZE (uptr)) { /* none left? */ + update_hkcs (CS1_DONE, drv); /* then done */ + break; } } + + err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET); + if (uptr->FNC == FNC_WRITE) { /* write? */ + if (hkcs2 & CS2_UAI) { /* no addr inc? */ + if (t = Map_ReadW (ba, 2, &comp, MAP)) { /* get 1st wd */ + wc = 0; /* NXM, no xfr */ + hkcs2 = hkcs2 | CS2_NEM; } /* set nxm err */ + for (i = 0; i < wc; i++) hkxb[i] = comp; } + else { /* normal */ + if (t = Map_ReadW (ba, wc << 1, hkxb, MAP)) { /* get buf */ + wc = wc - (t >> 1); /* NXM, adj wc */ + hkcs2 = hkcs2 | CS2_NEM; } /* set nxm err */ + ba = ba + (wc << 1); } /* adv ba */ + awc = (wc + (HK_NUMWD - 1)) & ~(HK_NUMWD - 1); + for (i = wc; i < awc; i++) hkxb[i] = 0; /* fill buf */ + if (wc && !err) { /* write buf */ + fxwrite (hkxb, sizeof (uint16), wc, uptr->fileref); + err = ferror (uptr->fileref); } + } /* end if wr */ + else if (uptr->FNC == FNC_READ) { /* read? */ + i = fxread (hkxb, sizeof (uint16), wc, uptr->fileref); + err = ferror (uptr->fileref); + for ( ; i < wc; i++) hkxb[i] = 0; /* fill buf */ + if (hkcs2 & CS2_UAI) { /* no addr inc? */ + if (t = Map_WriteW (ba, 2, &hkxb[wc - 1], MAP)) { + wc = 0; /* NXM, no xfr */ + hkcs2 = hkcs2 | CS2_NEM; } } /* set nxm err */ + else { /* normal */ + if (t = Map_WriteW (ba, wc << 1, hkxb, MAP)) { /* put buf */ + wc = wc - (t >> 1); /* NXM, adj wc */ + hkcs2 = hkcs2 | CS2_NEM; } /* set nxm err */ + ba = ba + (wc << 1); } /* adv ba */ + } /* end if read */ + else { /* wchk */ + i = fxread (hkxb, sizeof (uint16), wc, uptr->fileref); + err = ferror (uptr->fileref); + for ( ; i < wc; i++) hkxb[i] = 0; /* fill buf */ + awc = wc; + for (wc = 0; wc < awc; wc++) { /* loop thru buf */ + if (Map_ReadW (ba, 2, &comp, MAP)) { /* read word */ + hkcs2 = hkcs2 | CS2_NEM; /* set error */ + break; } + if (comp != hkxb[wc]) { /* compare wd */ + hkcs2 = hkcs2 | CS2_WCE; /* set error */ + break; } + if ((hkcs2 & CS2_UAI) == 0) ba = ba + 2; } + } /* end else wchk */ + + hkwc = (hkwc + wc) & 0177777; /* final word count */ + hkba = (ba & 0177777) & ~BA_MBZ; /* lower 16b */ + hkcs1 = PUT_UAE (hkcs1, ba >> 16); /* upper 2b */ + if (SC02C) /* SC02C? upper 6b */ + hkspr = (hkspr & ~XM_MMASK) | ((ba >> 16) & XM_MMASK); + da = da + wc + (HK_NUMWD - 1); + da = da / HK_NUMWD; + hkda = da % HK_NUMSC; + da = da / HK_NUMSC; + hkda = hkda | ((da % HK_NUMSF) << DA_V_SF); + hkdc = da / HK_NUMSF; + + if (err != 0) { /* error? */ + hk_cmderr (ER_PAR, drv); /* set drive error */ + perror ("HK I/O error"); + clearerr (uptr->fileref); + return SCPE_IOERR; } + +case FNC_WRITEH: /* write headers stub */ + update_hkcs (CS1_DONE, drv); /* set done */ + break; } /* end case func */ +return SCPE_OK; +} + +/* Controller status update + + Check for done transition + Update drive status + Update HKCS1 + Update interrupt request +*/ + +void update_hkcs (int32 flag, int32 drv) +{ +int32 i; + +update_hkds (drv); /* upd drv status */ +if (flag & CS1_DONE) hkcs1 = hkcs1 & ~CS1_GO; /* clear go */ +if (hkcs1 & CS1_IE) { /* intr enable? */ + if (((flag & CS1_DONE) && ((hkcs1 & CS1_DONE) == 0)) || + ((flag & CS1_DI) && (hkcs1 & CS1_DONE))) /* done 0->1 or DI? */ + SET_INT (HK); } +else CLR_INT (HK); +hkcs1 = (hkcs1 & (CS1_DT|CS1_UAE|CS1_DONE|CS1_IE|CS1_SPA|CS1_FNC|CS1_GO)) | flag; +for (i = 0; i < HK_NUMDR; i++) { /* if ATA, set DI */ + if (hkds[i] & DS_ATA) hkcs1 = hkcs1 | CS1_DI; } +if (hker[drv] | (hkcs1 & (CS1_PAR | CS1_CTO)) | /* if err, set ERR */ + (hkcs2 & CS2_ERR)) hkcs1 = hkcs1 | CS1_ERR; +return; +} + +/* Drive status update */ + +void update_hkds (drv) +{ +if (hk_unit[drv].flags & UNIT_DIS) { /* disabled? */ + hkds[drv] = hker[drv] = 0; /* all clear */ + return; } +hkds[drv] = (hkds[drv] & (DS_VV | DS_PIP | DS_ATA)) | DS_VLD | DS_DRA; +if (hk_unit[drv].flags & UNIT_ATT) { /* attached? */ + if (!sim_is_active (&hk_unit[drv])) /* not busy? */ + hkds[drv] = hkds[drv] | DS_RDY; /* set RDY */ + if (hker[drv]) hkds[drv] = hkds[drv] | DS_ATA; /* err? set ATA */ + if (hk_off[drv]) hkds[drv] = hkds[drv] | DS_OF; /* offset? set OF */ + if (hk_unit[drv].flags & UNIT_WPRT) /* write locked? */ + hkds[drv] = hkds[drv] | DS_WRL; } /* set WRL */ +else { hkds[drv] = hkds[drv] & ~(DS_PIP | DS_VV); /* no, clr PIP,VV */ + hker[drv] = 0; } /* no errors */ +if (hk_unit[drv].flags & UNIT_RK07) hkds[drv] = hkds[drv] | DS_DT; +return; +} + +/* Set error and abort command */ + +void hk_cmderr (int32 err, int32 drv) +{ +hker[drv] = hker[drv] | err; /* set error */ +hkds[drv] = hkds[drv] | DS_ATA; /* set attn */ +hkcs1 = hkcs1 & ~CS1_GO; /* clear go */ +update_hkcs (CS1_DONE, drv); /* set done */ +return; +} + +/* Diagnostic registers + + It's unclear whether the drivers actually use these values, but the + Emulex controller bothers to implement them, so we will too */ + +int32 hk_mrpar (int32 v) +{ +int32 bit, wrk; + +wrk = v & 077777; /* par on 15b */ +v = wrk | ((hkmr & MR_PAR)? 0: AX_PAR); /* even/odd */ +while (wrk) { /* while 1's */ + bit = wrk & (-wrk); /* lowest 1 */ + wrk = wrk & ~bit; /* clear */ + v = v ^ AX_PAR; } /* xor parity */ +return v; +} + +int32 hk_rdmr2 (int32 msg) +{ +int32 drv = GET_UNIT (hkcs2); +int32 v = drv << AX_V_UNIT; +UNIT *uptr = hk_dev.units + drv; +int32 fnc = uptr->FNC & CS1_M_FNC; + +switch (msg) { +case 0: /* message A0 */ + v = v | ((hkds[drv] & DS_ATA)? A0_ATA: 0) | + ((hkds[drv] & DS_PIP)? A0_PIP: 0) | + ((uptr->flags & UNIT_WPRT)? A0_WRL: 0) | + ((hk_off[drv])? A0_OF: 0) | + ((uptr->flags & UNIT_RK07)? A0_DT: 0) | + ((hkds[drv] & DS_VV)? A0_VV: 0) | A0_DRA; + if (uptr->flags & UNIT_ATT) v = v | A0_SPO | + (!sim_is_active (uptr)? A0_RDY: 0); + break; +case 1: /* message A1 */ + if (uptr->flags & UNIT_ATT) { + if (sim_is_active (uptr)) { + if (fnc == FNC_UNLOAD) v = v | A1_UNL; + else if (fnc == FNC_RECAL) v = v | A1_RTZ; + else if (fnc == FNC_SEEK) { + if (hk_dif[drv] < 0) v = v | A1_REV; + if (hk_dif[drv] > 0) v = v | A1_FWD; } } + v = v | (A1_SPD|A1_CAR|A1_DOR|A1_HHM|A1_SRV); } + else v = v | A1_HHM; + break; +case 2: /* message A2 */ + if (hkds[drv] & DS_OF) + v = v | ((hk_off[drv] & A2_M_DIF) << A2_V_DIF); + else v = v | ((hk_dif[drv] & A2_M_DIF) << A2_V_DIF); + break; +case 3: /* message A3 */ + v = v | ((012340 + v) << A3_V_SNO); + break; } +return hk_mrpar (v); +} + +int32 hk_rdmr3 (int32 msg) +{ +int32 drv = GET_UNIT (hkcs2); +int32 v = msg & 03; + +switch (msg) { +case 0: /* message B0 */ + v = v | ((hker[drv] & ER_WLE)? (B0_WLE | B0_FLT): 0) | + ((hker[drv] & ER_SKI)? (B0_SKI | B0_FLT): 0) | + ((hker[drv] & ER_NXF)? (B0_NXF | B0_FLT): 0) | + ((hker[drv] & ER_IAE)? (B0_IAE | B0_FLT): 0); + break; +case 1: /* message B1 */ + v = v | ((hker[drv] & ER_SKI)? B1_SKI: 0) | + ((hker[drv] & ER_UNS)? B1_SVE: 0); + break; +case 2: /* message B2 */ + v = v | (hk_unit[drv].CYL << B2_V_CYL); + break; +case 3: /* message B3 */ + v = v | (GET_SC (hkda) << B3_V_SEC) | + (1 << (GET_SF (hkda) + B3_V_DHA)); + break; } +return hk_mrpar (v); +} + +/* Device reset */ + +t_stat hk_reset (DEVICE *dptr) +{ +int32 i; +UNIT *uptr; + +hkcs1 = CS1_DONE; /* set done */ +hkcs2 = CS2_IR | CS2_OR; /* clear state */ +hkmr = hkmr2 = hkmr3 = 0; +hkda = hkdc = 0; +hkba = hkwc = 0; +hkof = hkspr = 0; +CLR_INT (HK); /* clear intr req */ +for (i = 0; i < HK_NUMDR; i++) { /* stop operations */ + uptr = hk_dev.units + i; + sim_cancel (uptr); + if (uptr->flags & UNIT_ATT) hkds[i] = hkds[i] & DS_VV; + else hkds[i] = 0; + uptr->CYL = uptr->FNC = 0; /* clear state */ + hk_dif[i] = 0; + hk_off[i] = 0; + hker[i] = 0; } /* clear errors */ +if (hkxb == NULL) hkxb = calloc (HK_MAXFR, sizeof (unsigned int16)); +if (hkxb == NULL) return SCPE_MEM; +return SCPE_OK; +} + +/* Device attach */ + +t_stat hk_attach (UNIT *uptr, char *cptr) +{ +int drv, p; +t_stat r; + +uptr->capac = HK_SIZE (uptr); +r = attach_unit (uptr, cptr); +if (r != SCPE_OK) return r; +drv = uptr - hk_dev.units; /* get drv number */ +hkds[drv] = DS_ATA | DS_RDY | ((uptr->flags & UNIT_WPRT)? DS_WRL: 0); +hker[drv] = 0; +hk_off[drv] = 0; +hk_dif[drv] = 0; +uptr->CYL = 0; +update_hkcs (CS1_DI, drv); + +if ((uptr->flags & UNIT_AUTO) == 0) return SCPE_OK; /* autosize? */ +if (fseek (uptr->fileref, 0, SEEK_END)) return SCPE_OK; +if ((p = ftell (uptr->fileref)) == 0) { + if (uptr->flags & UNIT_RO) return SCPE_OK; + return pdp11_bad_block (uptr, HK_NUMSC, HK_NUMWD); } +if (p > (RK06_SIZE * sizeof (int16))) { + uptr->flags = uptr->flags | UNIT_RK07; + uptr->capac = RK07_SIZE; } +else { uptr->flags = uptr->flags & ~UNIT_RK07; + uptr->capac = RK06_SIZE; } +return SCPE_OK; +} + +/* Device detach */ + +t_stat hk_detach (UNIT *uptr) +{ +int32 drv; + +drv = uptr - hk_dev.units; /* get drv number */ +hkds[drv] = (hkds[drv] & ~(DS_RDY | DS_WRL | DS_VV | DS_OF)) | DS_ATA; +if (sim_is_active (uptr)) { /* unit active? */ + sim_cancel (uptr); /* cancel operation */ + hker[drv] = hker[drv] | ER_OPI; /* set drive error */ + if ((uptr->FNC & CS1_M_FNC) >= FNC_XFER) /* data transfer? */ + hkcs1 = hkcs1 | CS1_DONE | CS1_ERR; } /* set done, err */ +update_hkcs (CS1_DI, drv); /* request intr */ +return detach_unit (uptr); +} + +/* Set size command validation routine */ + +t_stat hk_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (uptr->flags & UNIT_ATT) return SCPE_ALATT; +uptr->capac = val? RK07_SIZE: RK06_SIZE; +return SCPE_OK; +} + +/* Set bad block routine */ + +t_stat hk_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +return pdp11_bad_block (uptr, HK_NUMSC, HK_NUMWD); +} + +/* Device bootstrap - does not clear CSR when done */ + +#if defined (VM_PDP11) + +#define BOOT_START 02000 /* start */ +#define BOOT_ENTRY (BOOT_START + 002) /* entry */ +#define BOOT_UNIT (BOOT_START + 010) /* unit number */ +#define BOOT_CSR (BOOT_START + 014) /* CSR */ +#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) + +static const uint16 boot_rom[] = { + 0042115, /* "MD" */ + 0012706, BOOT_START, /* mov #boot_start, sp */ + 0012700, 0000000, /* mov #unit, r0 */ + 0012701, 0177440, /* mov #HKCS1, r1 */ + 0012761, 0000040, 0000010, /* mov #CS2_CLR, 10(r1) ; reset */ + 0010061, 0000010, /* mov r0, 10(r1) ; set unit */ + 0016102, 0000012, /* mov 12(r1), r2 ; drv typ */ + 0100375, /* bpl .-4 ; valid? */ + 0042702, 0177377, /* bic #177377, r2 ; clr rest */ + 0006302, /* asl r2 ; move */ + 0006302, /* asl r2 */ + 0012703, 0000003, /* mov #pack+go, r3 */ + 0050203, /* bis r2, r3 ; merge type */ + 0010311, /* mov r3, (r1); ; pack ack */ + 0105711, /* tstb (r1) ; wait */ + 0100376, /* bpl .-2 */ + 0012761, 0177000, 0000002, /* mov #-512.,2(r1) ; set wc */ + 0005061, 0000004, /* clr 4(r1) ; clr ba */ + 0005061, 0000006, /* clr 6(r1) ; clr da */ + 0005061, 0000020, /* clr 20(r1) ; clr cyl */ + 0012703, 0000021, /* mov #read+go, r3 */ + 0050203, /* bis r2, r3 ; merge type */ + 0010311, /* mov r3, (r1); ; read */ + 0105711, /* tstb (r1) ; wait */ + 0100376, /* bpl .-2 */ + 0005002, /* clr R2 */ + 0005003, /* clr R3 */ + 0012704, BOOT_START+020, /* mov #start+020, r4 */ + 0005005, /* clr R5 */ + 0005007 /* clr PC */ +}; + +t_stat hk_boot (int32 unitno, DEVICE *dptr) +{ +int32 i; +extern int32 saved_PC; + +for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i]; +M[BOOT_UNIT >> 1] = unitno & CS2_M_UNIT; +M[BOOT_CSR >> 1] = hk_dib.ba & DMASK; +saved_PC = BOOT_ENTRY; +return SCPE_OK; +} + +#else + +t_stat hk_boot (int32 unitno, DEVICE *dptr) +{ +return SCPE_NOFNC; +} + +#endif diff --git a/PDP11/pdp11_io.c b/PDP11/pdp11_io.c index be31c414..3fc7e8c6 100644 --- a/PDP11/pdp11_io.c +++ b/PDP11/pdp11_io.c @@ -23,6 +23,10 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 08-Oct-02 RMS Trimmed I/O bus addresses + Added support for dynamic tables + Added show I/O space, autoconfigure routines + 12-Sep-02 RMS Added support for TMSCP, KW11P, RX211 26-Jan-02 RMS Revised for multiple DZ's 06-Jan-02 RMS Revised I/O access, enable/disable support 11-Dec-01 RMS Moved interrupt debug code @@ -35,76 +39,36 @@ extern uint16 *M; extern int32 int_req[IPL_HLVL]; extern int32 ub_map[UBM_LNT_LW]; extern UNIT cpu_unit; -extern int32 cpu_bme, cpu_ubm; +extern int32 cpu_bme, cpu_18b, cpu_ubm; extern int32 trap_req, ipl; extern int32 cpu_log; extern FILE *sim_log; +extern DEVICE *sim_devices[]; + int32 calc_ints (int32 nipl, int32 trq); extern DIB cpu0_dib, cpu1_dib, cpu2_dib; extern DIB cpu3_dib, cpu4_dib, ubm_dib; -extern DIB pt_dib, tt_dib, clk_dib; -extern DIB lpt_dib, dz_dib; -extern DIB rk_dib, rl_dib; -extern DIB rp_dib, rq_dib; -extern DIB rx_dib, dt_dib; -extern DIB tm_dib, ts_dib; -extern int32 rk_inta (void); -extern int32 rp_inta (void); -extern int32 rq_inta (void); -extern int32 dz_rxinta (void); -extern int32 dz_txinta (void); -t_bool dev_conflict (uint32 nba, DIB *curr); - /* I/O data structures */ -DIB *dib_tab[] = { +DIB *dib_tab[DIB_MAX]; /* run time DIBs */ + +int32 int_vec[IPL_HLVL][32]; /* int req to vector */ + +int32 (*int_ack[IPL_HLVL][32])(void); /* int ack routines */ + +static DIB *std_dib[] = { /* standard DIBs */ &cpu0_dib, &cpu1_dib, &cpu2_dib, &cpu3_dib, &cpu4_dib, - &ubm_dib, - &pt_dib, - &tt_dib, - &clk_dib, - &lpt_dib, - &dz_dib, - &rk_dib, - &rl_dib, - &rp_dib, - &rq_dib, - &rx_dib, - &dt_dib, - &tm_dib, - &ts_dib, NULL }; -int32 int_vec[IPL_HLVL][32] = { /* int req to vector */ - { 0 }, /* IPL 0 */ - { VEC_PIRQ }, /* IPL 1 */ - { VEC_PIRQ }, /* IPL 2 */ - { VEC_PIRQ }, /* IPL 3 */ - { VEC_TTI, VEC_TTO, VEC_PTR, VEC_PTP, /* IPL 4 */ - VEC_LPT, VEC_PIRQ }, - { VEC_RK, VEC_RL, VEC_RX, VEC_TM, /* IPL 5 */ - VEC_RP, VEC_TS, VEC_RK6, VEC_RQ, - VEC_DZRX, VEC_DZTX, VEC_PIRQ }, - { VEC_CLK, VEC_DTA, VEC_PIRQ }, /* IPL 6 */ - { VEC_PIRQ } }; /* IPL 7 */ - -int32 (*int_ack[IPL_HLVL][32])() = { /* int ack routines */ - { NULL }, /* IPL 0 */ - { NULL }, /* IPL 1 */ - { NULL }, /* IPL 2 */ - { NULL }, /* IPL 3 */ - { NULL }, /* IPL 4 */ - { &rk_inta, NULL, NULL, NULL, /* IPL 5 */ - &rp_inta, NULL, NULL, &rq_inta, - &dz_rxinta, &dz_txinta, NULL }, - { NULL }, /* IPL 6 */ - { NULL } }; /* IPL 7 */ +static int32 pirq_vloc[7] = { + IVCL (PIR7), IVCL (PIR6), IVCL (PIR5), IVCL (PIR4), + IVCL (PIR3), IVCL (PIR2), IVCL (PIR1) }; /* I/O page lookup and linkage routines @@ -124,9 +88,9 @@ DIB *dibp; t_stat stat; for (i = 0; dibp = dib_tab[i]; i++ ) { - if (dibp -> enb && (pa >= dibp -> ba) && - (pa < (dibp -> ba + dibp -> lnt))) { - stat = dibp -> rd (data, pa, access); + if ((pa >= dibp->ba) && + (pa < (dibp->ba + dibp->lnt))) { + stat = dibp->rd (data, pa, access); trap_req = calc_ints (ipl, trap_req); return stat; } } return SCPE_NXM; @@ -139,9 +103,9 @@ DIB *dibp; t_stat stat; for (i = 0; dibp = dib_tab[i]; i++ ) { - if (dibp -> enb && (pa >= dibp -> ba) && - (pa < (dibp -> ba + dibp -> lnt))) { - stat = dibp -> wr (data, pa, access); + if ((pa >= dibp->ba) && + (pa < (dibp->ba + dibp->lnt))) { + stat = dibp->wr (data, pa, access); trap_req = calc_ints (ipl, trap_req); return stat; } } return SCPE_NXM; @@ -217,6 +181,8 @@ return SCPE_NXM; /* Mapped memory access routines for DMA devices */ +#define BUSMASK(m) ((cpu_18b || (cpu_ubm && (m)))? UNIMASK: PAMASK) + /* Map I/O address to memory address */ t_bool Map_Addr (t_addr ba, t_addr *ma) @@ -239,12 +205,13 @@ return TRUE; Map_WriteW - store word buffer into memory */ -int32 Map_ReadB (t_addr ba, int32 bc, uint8 *buf, t_bool ub) +int32 Map_ReadB (t_addr ba, int32 bc, uint8 *buf, t_bool map) { t_addr alim, lim, ma; +ba = ba & BUSMASK (map); /* trim address */ lim = ba + bc; -if (ub && cpu_bme) { /* UB, map on? */ +if (map && cpu_bme) { /* map req & on? */ for ( ; ba < lim; ba++) { /* by bytes */ Map_Addr (ba, &ma); /* map addr */ if (!ADDR_IS_MEM (ma)) return (lim - ba); /* NXM? err */ @@ -261,13 +228,13 @@ else { /* physical */ return (lim - alim); } } -int32 Map_ReadW (t_addr ba, int32 bc, uint16 *buf, t_bool ub) +int32 Map_ReadW (t_addr ba, int32 bc, uint16 *buf, t_bool map) { t_addr alim, lim, ma; -ba = ba & ~01; /* align start */ +ba = (ba & BUSMASK (map)) & ~01; /* trim, align addr */ lim = ba + (bc & ~01); -if (ub && cpu_bme) { /* UB, map on? */ +if (map && cpu_bme) { /* map req & on? */ for (; ba < lim; ba = ba + 2) { /* by words */ Map_Addr (ba, &ma); /* map addr */ if (!ADDR_IS_MEM (ma)) return (lim - ba); /* NXM? err */ @@ -282,12 +249,13 @@ else { /* physical */ return (lim - alim); } } -int32 Map_WriteB (t_addr ba, int32 bc, uint8 *buf, t_bool ub) +int32 Map_WriteB (t_addr ba, int32 bc, uint8 *buf, t_bool map) { t_addr alim, lim, ma; +ba = ba & BUSMASK (map); /* trim address */ lim = ba + bc; -if (ub && cpu_bme) { /* UB, map on? */ +if (map && cpu_bme) { /* map req & on? */ for ( ; ba < lim; ba++) { /* by bytes */ Map_Addr (ba, &ma); /* map addr */ if (!ADDR_IS_MEM (ma)) return (lim - ba); /* NXM? err */ @@ -306,13 +274,13 @@ else { /* physical */ return (lim - alim); } } -int32 Map_WriteW (t_addr ba, int32 bc, uint16 *buf, t_bool ub) +int32 Map_WriteW (t_addr ba, int32 bc, uint16 *buf, t_bool map) { t_addr alim, lim, ma; -ba = ba & ~01; /* align start */ +ba = (ba & BUSMASK (map)) & ~01; /* trim, align addr */ lim = ba + (bc & ~01); -if (ub && cpu_bme) { /* UB, map on? */ +if (map && cpu_bme) { /* map req & on? */ for (; ba < lim; ba = ba + 2) { /* by words */ Map_Addr (ba, &ma); /* map addr */ if (!ADDR_IS_MEM (ma)) return (lim - ba); /* NXM? err */ @@ -327,85 +295,305 @@ else { /* physical */ return (lim - alim); } } -/* Change device number for a device */ +/* Change device address */ t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc) { +DEVICE *dptr; DIB *dibp; uint32 newba; t_stat r; if (cptr == NULL) return SCPE_ARG; -if ((val == 0) || (desc == NULL)) return SCPE_IERR; -dibp = (DIB *) desc; +if ((val == 0) || (uptr == NULL)) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); +if (dptr == NULL) return SCPE_IERR; +dibp = (DIB *) dptr->ctxt; +if (dibp == NULL) return SCPE_IERR; newba = get_uint (cptr, 8, PAMASK, &r); /* get new */ -if ((r != SCPE_OK) || (newba == dibp -> ba)) return r; -if (newba <= IOPAGEBASE) return SCPE_ARG; /* > IO page base? */ -if (newba % ((uint32) val)) return SCPE_ARG; /* check modulus */ -if (dev_conflict (newba, dibp)) return SCPE_OK; -dibp -> ba = newba; /* store */ -return SCPE_OK; +if (r != SCPE_OK) return r; /* error? */ +if ((newba <= IOPAGEBASE) || /* > IO page base? */ + (newba % ((uint32) val))) return SCPE_ARG; /* check modulus */ +dibp->ba = newba; /* store */ +dptr->flags = dptr->flags & ~DEV_FLTA; /* not floating */ +return auto_config (0, 0); /* autoconfigure */ } /* Show device address */ t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc) { +DEVICE *dptr; DIB *dibp; -if (desc == NULL) return SCPE_IERR; -dibp = (DIB *) desc; -if (dibp -> ba <= IOPAGEBASE) return SCPE_IERR; -fprintf (st, "address=%08o", dibp -> ba); -if (dibp -> lnt > 1) - fprintf (st, "-%08o", dibp -> ba + dibp -> lnt - 1); +if (uptr == NULL) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); +if (dptr == NULL) return SCPE_IERR; +dibp = (DIB *) dptr->ctxt; +if ((dibp == NULL) || (dibp->ba <= IOPAGEBASE)) return SCPE_IERR; +fprintf (st, "address=%08o", dibp->ba); +if (dibp->lnt > 1) + fprintf (st, "-%08o", dibp->ba + dibp->lnt - 1); +if (dptr->flags & DEV_FLTA) fprintf (st, "*"); return SCPE_OK; } -/* Enable or disable a device */ +/* Set address floating */ -t_stat set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc) +t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc) { -int32 i; DEVICE *dptr; -DIB *dibp; -UNIT *up; if (cptr != NULL) return SCPE_ARG; -if ((uptr == NULL) || (desc == NULL)) return SCPE_IERR; -dptr = find_dev_from_unit (uptr); /* find device */ +if (uptr == NULL) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); if (dptr == NULL) return SCPE_IERR; -dibp = (DIB *) desc; -if ((val ^ dibp -> enb) == 0) return SCPE_OK; /* enable chg? */ -if (val) { /* enable? */ - if (dev_conflict (dibp -> ba, dibp)) return SCPE_OK; } -else { /* disable */ - for (i = 0; i < dptr -> numunits; i++) { /* check units */ - up = (dptr -> units) + i; - if ((up -> flags & UNIT_ATT) || sim_is_active (up)) - return SCPE_NOFNC; } } -dibp -> enb = val; -if (dptr -> reset) return dptr -> reset (dptr); -else return SCPE_OK; +dptr->flags = dptr->flags | DEV_FLTA; /* floating */ +return auto_config (0, 0); /* autoconfigure */ } +/* Change device vector */ + +t_stat set_vec (UNIT *uptr, int32 arg, char *cptr, void *desc) +{ +DEVICE *dptr; +DIB *dibp; +uint32 newvec; +t_stat r; + +if (cptr == NULL) return SCPE_ARG; +if (uptr == NULL) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); +if (dptr == NULL) return SCPE_IERR; +dibp = (DIB *) dptr->ctxt; +if (dibp == NULL) return SCPE_IERR; +newvec = get_uint (cptr, 8, VEC_Q + 01000, &r); +if ((r != SCPE_OK) || (newvec <= VEC_Q) || + ((newvec + (dibp->vnum * 4)) >= (VEC_Q + 01000)) || + (newvec & ((dibp->vnum > 1)? 07: 03))) return SCPE_ARG; +dibp->vec = newvec; +return SCPE_OK; +} + +/* Show device vector */ + +t_stat show_vec (FILE *st, UNIT *uptr, int32 arg, void *desc) +{ +DEVICE *dptr; +DIB *dibp; +uint32 vec, numvec; + +if (uptr == NULL) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); +if (dptr == NULL) return SCPE_IERR; +dibp = (DIB *) dptr->ctxt; +if (dibp == NULL) return SCPE_IERR; +vec = dibp->vec; +if (arg) numvec = arg; +else numvec = dibp->vnum; +if (vec == 0) fprintf (st, "no vector"); +else { fprintf (st, "vector=%o", vec); + if (numvec > 1) fprintf (st, "-%o", vec + (4 * (numvec - 1))); } +return SCPE_OK; +} + /* Test for conflict in device addresses */ -t_bool dev_conflict (uint32 nba, DIB *curr) +t_bool dev_conflict (DIB *curr) { uint32 i, end; +DEVICE *dptr; DIB *dibp; -end = nba + curr -> lnt - 1; /* get end */ -for (i = 0; dibp = dib_tab[i]; i++) { /* loop thru dev */ - if (!dibp -> enb || (dibp == curr)) continue; /* skip disabled */ - if (((nba >= dibp -> ba) && /* overlap start? */ - (nba < (dibp -> ba + dibp -> lnt))) || - ((end >= dibp -> ba) && /* overlap end? */ - (end < (dibp -> ba + dibp -> lnt)))) { - printf ("Device address conflict at %08o\n", dibp -> ba); +end = curr->ba + curr->lnt - 1; /* get end */ +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ + dibp = (DIB *) dptr->ctxt; /* get DIB */ + if ((dibp == NULL) || (dibp == curr) || + (dptr->flags & DEV_DIS)) continue; + if (((curr->ba >= dibp->ba) && /* overlap start? */ + (curr->ba < (dibp->ba + dibp->lnt))) || + ((end >= dibp->ba) && /* overlap end? */ + (end < (dibp->ba + dibp->lnt)))) { + printf ("Device %s address conflict at %08o\n", dptr->name, dibp->ba); if (sim_log) fprintf (sim_log, - "Device number conflict at %08o\n", dibp -> ba); - return TRUE; } } + "Device %s address conflict at %08o\n", dptr->name, dibp->ba); + return TRUE; } } return FALSE; } + +/* Build interrupt tables */ + +void build_int_vec (int32 vloc, int32 ivec, int32 (*iack)(void) ) +{ +int32 ilvl = vloc / 32; +int32 ibit = vloc % 32; + +if (iack != NULL) int_ack[ilvl][ibit] = iack; +else int_vec[ilvl][ibit] = ivec; +return; +} + +/* Build dib_tab from device list */ + +t_stat build_dib_tab (int32 ubm) +{ +int32 i, j, k; +DEVICE *dptr; +DIB *dibp; + +for (i = 0; i < IPL_HLVL; i++) { /* clear int tables */ + for (j = 0; j < 32; j++) { + int_vec[i][j] = 0; + int_ack[i][j] = NULL; } } +for (i = j = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ + dibp = (DIB *) dptr->ctxt; /* get DIB */ + if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */ + if (dibp->vnum > VEC_DEVMAX) return SCPE_IERR; + for (k = 0; k < dibp->vnum; k++) /* loop thru vec */ + build_int_vec (dibp->vloc + k, /* add vector */ + dibp->vec + (k * 4), dibp->ack[k]); + if (dibp->lnt != 0) { /* I/O addresses? */ + dib_tab[j++] = dibp; /* add DIB to dib_tab */ + if (j >= DIB_MAX) return SCPE_IERR; } /* too many? */ + } /* end if enabled */ + } /* end for */ +for (i = 0; (dibp = std_dib[i]) != NULL; i++) { /* loop thru std */ + dib_tab[j++] = dibp; /* add to dib_tab */ + if (j >= DIB_MAX) return SCPE_IERR; } /* too many? */ +if (ubm) { /* Unibus map? */ + dib_tab[j++] = &ubm_dib; /* add to dib_tab */ + if (j >= DIB_MAX) return SCPE_IERR; } /* too many? */ +dib_tab[j] = NULL; /* end with NULL */ +for (i = 0; i < 7; i++) /* add PIRQ intr */ + build_int_vec (pirq_vloc[i], VEC_PIRQ, NULL); +for (i = 0; (dibp = dib_tab[i]) != NULL; i++) { /* test built dib_tab */ + if (dev_conflict (dibp)) { + return SCPE_STOP; } } /* for conflicts */ +return SCPE_OK; +} + +/* Show dib_tab */ + +t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +int32 i, j, done = 0; +DEVICE *dptr; +DIB *dibt; + +build_dib_tab (cpu_ubm); /* build table */ +while (done == 0) { /* sort ascending */ + done = 1; /* assume done */ + for (i = 0; dib_tab[i + 1] != NULL; i++) { /* check table */ + if (dib_tab[i]->ba > dib_tab[i + 1]->ba) { /* out of order? */ + dibt = dib_tab[i]; /* interchange */ + dib_tab[i] = dib_tab[i + 1]; + dib_tab[i + 1] = dibt; + done = 0; } } /* not done */ + } /* end while */ +for (i = 0; dib_tab[i] != NULL; i++) { /* print table */ + for (j = 0, dptr = NULL; sim_devices[j] != NULL; j++) { + if (((DIB*) sim_devices[j]->ctxt) == dib_tab[i]) { + dptr = sim_devices[j]; + break; } } + fprintf (st, "%08o - %08o%c\t%s\n", dib_tab[i]->ba, + dib_tab[i]->ba + dib_tab[i]->lnt - 1, + (dptr && (dptr->flags & DEV_FLTA))? '*': ' ', + dptr? dptr->name: "CPU"); + } +return SCPE_OK; +} + +/* Autoconfiguration */ + +#define AUTO_DYN 0001 +#define AUTO_VEC 0002 +#define AUTO_MAXC 4 +#define AUTO_CSRBASE 0010 +#define AUTO_VECBASE 0300 + +struct auto_con { + uint32 amod; + uint32 vmod; + uint32 flags; + uint32 num; + uint32 fix; + char *dnam[AUTO_MAXC]; }; + +struct auto_con auto_tab[AUTO_LNT + 1] = { + { 0x7, 0x7 }, /* DJ11 */ + { 0xf, 0x7 }, /* DH11 */ + { 0x7, 0x7 }, /* DQ11 */ + { 0x7, 0x7 }, /* DU11 */ + { 0x7, 0x7 }, /* DUP11 */ + { 0x7, 0x7 }, /* LK11A */ + { 0x7, 0x7 }, /* DMC11 */ + { 0x7, 0x7, AUTO_VEC, DZ_MUXES, 0, { "DZ" } }, + + { 0x7, 0x7 }, /* KMC11 */ + { 0x7, 0x7 }, /* LPP11 */ + { 0x7, 0x7 }, /* VMV21 */ + { 0xf, 0x7 }, /* VMV31 */ + { 0x7, 0x7 }, /* DWR70 */ + { 0x7, 0x3, AUTO_DYN|AUTO_VEC, 0, IOBA_RL, { "RL", "RLB" } }, + { 0xf, 0x7 }, /* LPA11K */ + { 0x7, 0x7 }, /* KW11C */ + + { 0x7, 0 }, /* reserved */ + { 0x7, 0x3, AUTO_DYN|AUTO_VEC, 0, IOBA_RX, { "RX", "RY" } }, + { 0x7, 0x3 }, /* DR11W */ + { 0x7, 0x3 }, /* DR11B */ + { 0x7, 0x7 }, /* DMP11 */ + { 0x7, 0x7 }, /* DPV11 */ + { 0x7, 0x7 }, /* ISB11 */ + { 0xf, 0x7 }, /* DMV11 */ + + { 0x7, 0x3, AUTO_DYN|AUTO_VEC, 0, IOBA_XU, { "XU", "XUB" } }, + { 0x3, 0x3, AUTO_DYN|AUTO_VEC, 0, IOBA_RQ, { "RQ", "RQB", "RQC", "RQD" } }, + { 0x1f, 0x3 }, /* DMF32 */ + { 0xf, 0x7 }, /* KMS11 */ + { 0xf, 0x3 }, /* VS100 */ + { 0x3, 0x3, AUTO_DYN|AUTO_VEC, 0, IOBA_TQ, { "TQ", "TQB" } }, + { 0xf, 0x7 }, /* KMV11 */ + { 0xf, 0x7 }, /* DHU11/DHQ11 */ + + { 0x1f, 0x7 }, /* DMZ32 */ + { 0x1f, 0x7 }, /* CP132 */ + { 0 }, /* padding */ +}; + +t_stat auto_config (uint32 rank, uint32 nctrl) +{ +uint32 csr = IOPAGEBASE + AUTO_CSRBASE; +uint32 vec = VEC_Q + AUTO_VECBASE; +struct auto_con *autp; +DEVICE *dptr; +DIB *dibp; +int32 i, j, k; +extern DEVICE *find_dev (char *ptr); + +if (rank > AUTO_LNT) return SCPE_IERR; /* legal rank? */ +if (rank) auto_tab[rank - 1].num = nctrl; /* update num? */ +for (i = 0, autp = auto_tab; i < AUTO_LNT; i++) { /* loop thru table */ + for (j = k = 0; (j < AUTO_MAXC) && autp->dnam[j]; j++) { + dptr = find_dev (autp->dnam[j]); /* find ctrl */ + if ((dptr == NULL) || (dptr->flags & DEV_DIS) || + !(dptr->flags & DEV_FLTA)) continue; /* enabled, floating? */ + dibp = (DIB *) dptr->ctxt; /* get DIB */ + if ((k++ == 0) && autp->fix) /* 1st & fixed? */ + dibp->ba = autp->fix; /* gets fixed CSR */ + else { /* no, float */ + dibp->ba = csr; /* set CSR */ + csr = (csr + autp->amod + 1) & ~autp->amod; /* next CSR */ + if ((autp->flags & AUTO_DYN) == 0) /* static? */ + csr = csr + ((autp->num - 1) * (autp->amod + 1)); + if (autp->flags & AUTO_VEC) { /* vectors too? */ + dibp->vec = (vec + autp->vmod) & ~autp->vmod; + if (autp->flags & AUTO_DYN) vec = vec + autp->vmod + 1; + else vec = vec + (autp->num * (autp->vmod + 1)); } + } /* end else flt */ + } /* end for j */ + autp++; + csr = (csr + autp->amod + 1) & ~autp->amod; /* gap */ + } /* end for i */ +return SCPE_OK; +} diff --git a/PDP11/pdp11_lp.c b/PDP11/pdp11_lp.c index a688d4b2..e0b62744 100644 --- a/PDP11/pdp11_lp.c +++ b/PDP11/pdp11_lp.c @@ -25,6 +25,8 @@ lpt LP11 line printer + 29-Sep-02 RMS Added vector change/display support + New data structures 30-May-02 RMS Widened POS to 32b 06-Jan-02 RMS Added enable/disable support 09-Nov-01 RMS Added VAX support @@ -47,10 +49,12 @@ #define LPTCSR_RW (CSR_IE) /* read/write */ extern int32 int_req[IPL_HLVL]; +extern int32 int_vec[IPL_HLVL][32]; int32 lpt_csr = 0; /* control/status */ int32 lpt_stopioe = 0; /* stop on error */ +DEVICE lpt_dev; t_stat lpt_rd (int32 *data, int32 PA, int32 access); t_stat lpt_wr (int32 data, int32 PA, int32 access); t_stat lpt_svc (UNIT *uptr); @@ -65,7 +69,8 @@ t_stat lpt_detach (UNIT *uptr); lpt_reg LPT register list */ -DIB lpt_dib = { 1, IOBA_LPT, IOLN_LPT, &lpt_rd, &lpt_wr }; +DIB lpt_dib = { IOBA_LPT, IOLN_LPT, &lpt_rd, &lpt_wr, + 1, IVCL (LPT), VEC_LPT, { NULL } }; UNIT lpt_unit = { UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; @@ -81,23 +86,22 @@ REG lpt_reg[] = { { DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, lpt_stopioe, 0) }, { GRDATA (DEVADDR, lpt_dib.ba, LPT_DRDX, 32, 0), REG_HRO }, - { FLDATA (*DEVENB, lpt_dib.enb, 0), REG_HRO }, + { GRDATA (DEVVEC, lpt_dib.vec, LPT_DRDX, 16, 0), REG_HRO }, { NULL } }; MTAB lpt_mod[] = { { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, &lpt_dib }, - { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", - &set_enbdis, NULL, &lpt_dib }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", - &set_enbdis, NULL, &lpt_dib }, + &set_addr, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + &set_vec, &show_vec, NULL }, { 0 } }; DEVICE lpt_dev = { "LPT", &lpt_unit, lpt_reg, lpt_mod, 1, 10, 31, 1, LPT_DRDX, 8, NULL, NULL, &lpt_reset, - NULL, &lpt_attach, &lpt_detach }; + NULL, &lpt_attach, &lpt_detach, + &lpt_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS }; /* Line printer routines diff --git a/dec_mscp.h b/PDP11/pdp11_mscp.h similarity index 50% rename from dec_mscp.h rename to PDP11/pdp11_mscp.h index 639db107..e8d0401d 100644 --- a/dec_mscp.h +++ b/PDP11/pdp11_mscp.h @@ -1,4 +1,4 @@ -/* dec_mscp.c: DEC MSCP definitions +/* pdp11_mscp.h: DEC MSCP and TMSCP definitions Copyright (c) 2001-2002, Robert M Supnik Derived from work by Stephen F. Shirron @@ -23,51 +23,74 @@ Except as contained in this notice, the name of Robert M Supnik shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + + 20-Sep-02 RMS Merged TMSCP definitions */ +#ifndef _PDP11_MSCP_H_ +#define _PDP11_MSCP_H_ 0 + /* Misc constants */ #define UID_DISK 2 /* disk class */ +#define UID_TAPE 3 /* tape class */ /* Opcodes */ -#define OP_ABO 1 /* abort */ -#define OP_GCS 2 /* get command status */ -#define OP_GUS 3 /* get unit status */ -#define OP_SCC 4 /* set controller char */ -#define OP_AVL 8 /* available */ -#define OP_ONL 9 /* online */ -#define OP_SUC 10 /* set unit char */ -#define OP_DAP 11 /* det acc paths - nop */ -#define OP_ACC 16 /* access */ -#define OP_CCD 17 /* compare - nop */ -#define OP_ERS 18 /* erase */ -#define OP_FLU 19 /* flush - nop */ -#define OP_CMP 32 /* compare */ -#define OP_RD 33 /* read */ -#define OP_WR 34 /* write */ -#define OP_FMT 47 /* format */ -#define OP_AVA 64 /* unit now avail */ -#define OP_END 0x80 /* end flag */ +#define OP_ABO 1 /* b: abort */ +#define OP_GCS 2 /* b: get command status */ +#define OP_GUS 3 /* b: get unit status */ +#define OP_SCC 4 /* b: set controller char */ +#define OP_AVL 8 /* b: available */ +#define OP_ONL 9 /* b: online */ +#define OP_SUC 10 /* b: set unit char */ +#define OP_DAP 11 /* b: det acc paths - nop */ +#define OP_ACC 16 /* b: access */ +#define OP_CCD 17 /* d: compare - nop */ +#define OP_ERS 18 /* b: erase */ +#define OP_FLU 19 /* d: flush - nop */ +#define OP_ERG 22 /* t: erase gap */ +#define OP_CMP 32 /* b: compare */ +#define OP_RD 33 /* b: read */ +#define OP_WR 34 /* b: write */ +#define OP_WTM 36 /* t: write tape mark */ +#define OP_POS 37 /* t: reposition */ +#define OP_FMT 47 /* d: format */ +#define OP_AVA 64 /* b: unit now avail */ +#define OP_END 0x80 /* b: end flag */ /* Modifiers */ -#define MD_EXP 0x8000 /* express NI */ -#define MD_CMP 0x4000 /* compare NI */ -#define MD_CSE 0x2000 /* clr ser err NI */ -#define MD_ERR 0x1000 /* force error NI*/ -#define MD_SEC 0x0200 /* supr err corr NI */ -#define MD_SER 0x0100 /* supr err rec NI */ -#define MD_SHD 0x0010 /* shadow NI */ -#define MD_SWP 0x0004 /* enb set wrp */ -#define MD_IMF 0x0002 /* onl: ign fmte NI */ -#define MD_NXU 0x0001 /* gus: next unit */ -#define MD_RIP 0x0001 /* onl: allow rip NI */ +#define MD_EXP 0x8000 /* d: express NI */ +#define MD_CMP 0x4000 /* b: compare NI */ +#define MD_CSE 0x2000 /* b: clr ser err */ +#define MD_ERR 0x1000 /* d: force error NI*/ +#define MD_CDL 0x1000 /* t: clr data lost NI*/ +#define MD_SCH 0x0800 /* t: supr cache NI */ +#define MD_SEC 0x0200 /* b: supr err corr NI */ +#define MD_SER 0x0100 /* b: supr err rec NI */ +#define MD_DLE 0x0080 /* t: detect LEOT */ +#define MD_IMM 0x0040 /* t: immediate NI */ +#define MD_EXA 0x0020 /* b: excl access NI */ +#define MD_SHD 0x0010 /* d: shadow NI */ +#define MD_UNL 0x0010 /* t avl: unload */ +#define MD_ERW 0x0008 /* t wr: enb rewrite */ +#define MD_REV 0x0008 /* t rd, pos: reverse */ +#define MD_SWP 0x0004 /* b suc: enb set wrp */ +#define MD_OBC 0x0004 /* t: pos: obj count */ +#define MD_IMF 0x0002 /* d onl: ign fmte NI */ +#define MD_RWD 0x0002 /* t pos: rewind */ +#define MD_ACL 0x0002 /* t avl: all class NI */ +#define MD_NXU 0x0001 /* b gus: next unit */ +#define MD_RIP 0x0001 /* d onl: allow rip NI */ /* End flags */ -#define EF_LOG 0x0020 /* error log */ -#define EF_SEX 0x0010 /* serious exc NI */ +#define EF_LOG 0x0020 /* b: error log */ +#define EF_SXC 0x0010 /* b: serious exc */ +#define EF_EOT 0x0008 /* end of tape */ +#define EF_PLS 0x0004 /* pos lost */ +#define EF_DLS 0x0002 /* cached data lost NI */ /* Controller flags */ @@ -80,71 +103,105 @@ /* Unit flags */ -#define UF_RPL 0x8000 /* ctrl bad blk repl */ -#define UF_WPH 0x2000 /* wr prot hwre */ -#define UF_WPS 0x1000 /* wr prot swre */ -#define UF_WPD 0x0100 /* wr prot data NI */ -#define UF_RMV 0x0080 /* removable */ +#define UF_RPL 0x8000 /* d: ctrl bad blk repl */ +#define UF_CAC 0x8000 /* t: cache write back */ +#define UF_WPH 0x2000 /* b: wr prot hwre */ +#define UF_WPS 0x1000 /* b: wr prot swre */ +#define UF_SCH 0x0800 /* t: supr cache NI */ +#define UF_EXA 0x0400 /* b: exclusive NI */ +#define UF_WPD 0x0100 /* b: wr prot data NI */ +#define UF_RMV 0x0080 /* d: removable */ +#define UF_WBN 0x0040 /* t: write back NI */ +#define UF_VSS 0x0020 /* t: supr var speed NI */ +#define UF_VSU 0x0010 /* t: var speed unit NI */ +#define UF_EWR 0x0008 /* t: enh wr recovery NI */ #define UF_CMW 0x0002 /* cmp writes NI */ #define UF_CMR 0x0001 /* cmp reads NI */ -#define UF_MSK (UF_CMR|UF_CMW) /* Error log flags */ -#define LF_SUC 0x0080 /* successful */ -#define LF_CON 0x0040 /* continuing */ -#define LF_BBR 0x0020 /* bad blk repl NI */ -#define LF_RCT 0x0010 /* err in repl NI */ -#define LF_SNR 0x0001 /* seq # reset */ +#define LF_SUC 0x0080 /* b: successful */ +#define LF_CON 0x0040 /* b: continuing */ +#define LF_BBR 0x0020 /* d: bad blk repl NI */ +#define LF_RCT 0x0010 /* d: err in repl NI */ +#define LF_SNR 0x0001 /* b: seq # reset */ /* Error log formats */ -#define FM_CNT 0 /* port lf err */ -#define FM_BAD 1 /* bad host addr */ -#define FM_DSK 2 /* disk xfer */ -#define FM_SDI 3 /* SDI err */ -#define FM_SDE 4 /* sm disk err */ -#define FM_RPL 9 /* bad blk repl */ +#define FM_CNT 0 /* b: port lf err */ +#define FM_BAD 1 /* b: bad host addr */ +#define FM_DSK 2 /* d: disk xfer */ +#define FM_SDI 3 /* d: SDI err */ +#define FM_SDE 4 /* d: sm disk err */ +#define FM_TAP 5 /* t: tape errors */ +#define FM_RPL 9 /* d: bad blk repl */ /* Status codes */ -#define ST_SUC 0 /* successful */ -#define ST_CMD 1 /* invalid cmd */ -#define ST_ABO 2 /* aborted cmd */ -#define ST_OFL 3 /* unit offline */ -#define ST_AVL 4 /* unit avail */ -#define ST_MFE 5 /* media fmt err */ -#define ST_WPR 6 /* write prot err */ -#define ST_CMP 7 /* compare err */ -#define ST_DAT 8 /* data err */ -#define ST_HST 9 /* host acc err */ -#define ST_CNT 10 /* ctrl err */ -#define ST_DRV 11 /* drive err */ -#define ST_BBR 20 /* bad block */ -#define ST_DIA 31 /* diagnostic */ +#define ST_SUC 0 /* b: successful */ +#define ST_CMD 1 /* b: invalid cmd */ +#define ST_ABO 2 /* b: aborted cmd */ +#define ST_OFL 3 /* b: unit offline */ +#define ST_AVL 4 /* b: unit avail */ +#define ST_MFE 5 /* b: media fmt err */ +#define ST_WPR 6 /* b: write prot err */ +#define ST_CMP 7 /* b: compare err */ +#define ST_DAT 8 /* b: data err */ +#define ST_HST 9 /* b: host acc err */ +#define ST_CNT 10 /* b: ctrl err */ +#define ST_DRV 11 /* b: drive err */ +#define ST_FMT 12 /* t: formatter err */ +#define ST_BOT 13 /* t: BOT encountered */ +#define ST_TMK 14 /* t: tape mark */ +#define ST_RDT 16 /* t: record trunc */ +#define ST_POL 17 /* t: pos lost */ +#define ST_SXC 18 /* b: serious exc */ +#define ST_LED 19 /* t: LEOT detect */ +#define ST_BBR 20 /* d: bad block */ +#define ST_DIA 31 /* b: diagnostic */ #define ST_V_SUB 5 /* subcode */ #define ST_V_INV 8 /* invalid op */ /* Status subcodes */ -#define SB_SUC_ON (8 << ST_V_SUB) /* already online */ -#define SB_OFL_NV (1 << ST_V_SUB) /* no volume */ -#define SB_AVL_INU (32 << ST_V_SUB) /* in use */ -#define SB_WPR_SW (128 << ST_V_SUB) /* swre wlk */ -#define SB_WPR_HW (256 << ST_V_SUB) /* hwre wlk */ -#define SB_HST_OA (1 << ST_V_SUB) /* odd addr */ -#define SB_HST_OC (2 << ST_V_SUB) /* odd count */ -#define SB_HST_NXM (3 << ST_V_SUB) /* nx memory */ -#define SB_HST_PTE (5 << ST_V_SUB) /* mapping err */ +#define SB_SUC_IGN (1 << ST_V_SUB) /* t: unload ignored */ +#define SB_SUC_ON (8 << ST_V_SUB) /* b: already online */ +#define SB_SUC_EOT (32 << ST_V_SUB) /* t: EOT encountered */ +#define SB_SUC_RO (128 << ST_V_SUB) /* t: read only */ +#define SB_OFL_NV (1 << ST_V_SUB) /* b: no volume */ +#define SB_OFL_INOP (2 << ST_V_SUB) /* t: inoperative */ +#define SB_AVL_INU (32 << ST_V_SUB) /* b: in use */ +#define SB_WPR_SW (128 << ST_V_SUB) /* b: swre wlk */ +#define SB_WPR_HW (256 << ST_V_SUB) /* b: hwre wlk */ +#define SB_HST_OA (1 << ST_V_SUB) /* b: odd addr */ +#define SB_HST_OC (2 << ST_V_SUB) /* d: odd count */ +#define SB_HST_NXM (3 << ST_V_SUB) /* b: nx memory */ +#define SB_HST_PAR (4 << ST_V_SUB) /* b: parity err */ +#define SB_HST_PTE (5 << ST_V_SUB) /* b: mapping err */ +#define SB_DAT_RDE (7 << ST_V_SUB) /* t: read err */ /* Status invalid command subcodes */ #define I_OPCD (8 << ST_V_INV) /* inv opcode */ +#define I_FLAG (9 << ST_V_INV) /* inv flags */ +#define I_MODF (10 << ST_V_INV) /* inv modifier */ #define I_BCNT (12 << ST_V_INV) /* inv byte cnt */ #define I_LBN (28 << ST_V_INV) /* inv LBN */ #define I_VRSN (12 << ST_V_INV) /* inv version */ #define I_FMTI (28 << ST_V_INV) /* inv format */ +/* Tape format flags */ + +#define TF_9TK 0x0100 /* 9 track */ +#define TF_9TK_NRZ 0x0001 /* 800 bpi */ +#define TF_9TK_PE 0x0002 /* 1600 bpi */ +#define TF_9TK_GRP 0x0004 /* 6250 bpi */ +#define TF_CTP 0x0200 /* TK50 */ +#define TF_CTP_LO 0x0001 /* low density */ +#define TF_CTP_HI 0x0002 /* hi density */ +#define TF_3480 0x0300 /* 3480 */ +#define TF_WOD 0x0400 /* RV80 */ + /* Packet formats - note that all packet lengths must be multiples of 4 bytes */ /* Command packet header */ @@ -160,6 +217,8 @@ #define CMD_OPC_M_OPC 0xFF #define CMD_OPC_V_CAA 8 /* cache NI */ #define CMD_OPC_M_CAA 0xFF +#define CMD_OPC_V_FLG 8 /* flags */ +#define CMD_OPC_M_FLG 0xFF /* Response packet header */ @@ -184,6 +243,28 @@ #define AVL_LNT 12 +/* Erase packet - min size */ + +#define ERS_LNT 12 + +/* Erase gap - min size */ + +#define ERG_LNT 12 + +/* Flush - 10 W of status (8 undefined) */ + +#define FLU_LNT 32 +/* 8 - 15 /* reserved */ +#define FLU_POSL 16 /* position */ +#define FLU_POSH 17 + +/* Write tape mark - 10W of status (8 undefined) */ + +#define WTM_LNT 32 +/* 8 - 15 /* reserved */ +#define WTM_POSL 16 /* position */ +#define WTM_POSH 17 + /* Get command status packet - 2 W parameter, 4 W of status */ #define GCS_LNT 20 @@ -197,9 +278,10 @@ #define FMT_LNT 12 #define FMT_IH 17 /* magic bit */ -/* Get unit status packet - 18 W status */ +/* Get unit status packet - 18 W status (disk), 16W status (tape) */ -#define GUS_LNT 48 +#define GUS_LNT_D 48 +#define GUS_LNT_T 44 #define GUS_MLUN 8 /* mlun */ #define GUS_UFL 9 /* flags */ #define GUS_RSVL 10 /* reserved */ @@ -210,21 +292,32 @@ #define GUS_UIDD 15 #define GUS_MEDL 16 /* media ID */ #define GUS_MEDH 17 +#define GUS_UVER 23 /* unit version */ + +/* Disk specific status */ + #define GUS_SHUN 18 /* shadowing */ #define GUS_SHST 19 #define GUS_TRK 20 /* track */ #define GUS_GRP 21 /* group */ #define GUS_CYL 22 /* cylinder */ -#define GUS_UVER 23 /* unit version */ #define GUS_RCTS 24 /* RCT size */ #define GUS_RBSC 25 /* RBNs, copies */ +/* Tape specific status */ + +#define GUS_FMT 18 /* format */ +#define GUS_SPEED 19 /* speed */ +#define GUS_MENU 20 /* menu */ +#define GUS_CAP 21 /* capacity */ +#define GUS_FVER 22 /* fmtr version */ + #define GUS_UIDD_V_MOD 0 /* unit model */ #define GUS_UIDD_V_CLS 8 /* unit class */ #define GUS_RB_V_RBNS 0 /* RBNs/track */ #define GUS_RB_V_RCTC 8 /* RCT copies */ -/* Unit online - 2 W parameter, 16 W status */ +/* Unit online - 2 W parameter, 16 W status (disk or tape) */ #define ONL_LNT 44 #define ONL_MLUN 8 /* mlun */ @@ -237,6 +330,9 @@ #define ONL_UIDD 15 #define ONL_MEDL 16 /* media ID */ #define ONL_MEDH 17 + +/* Disk specific status */ + #define ONL_SHUN 18 /* shadowing */ #define ONL_SHST 19 #define ONL_SIZL 20 /* size */ @@ -244,6 +340,15 @@ #define ONL_VSNL 22 /* vol ser # */ #define ONL_VSNH 23 +/* Tape specific status */ + +#define ONL_FMT 18 /* format */ +#define ONL_SPD 19 /* speed */ +#define ONL_MAXL 20 /* max rec size */ +#define ONL_MAXH 21 +#define ONL_NREC 22 /* noise rec */ +#define ONL_RSVE 23 /* reserved */ + #define ONL_UIDD_V_MOD 0 /* unit model */ #define ONL_UIDD_V_CLS 8 /* unit class */ @@ -270,7 +375,18 @@ #define SUC_LNT 44 -/* Data transfer packet - 10 W parameters, 10 W status */ +/* Reposition - 4 W parameters, 10 W status */ + +#define POS_LNT 32 +#define POS_RCL 8 /* record cnt */ +#define POS_RCH 9 +#define POS_TMCL 10 /* tape mk cnt */ +#define POS_TMCH 11 +/* reserved 12 - 15 */ +#define POS_POSL 16 /* position */ +#define POS_POSH 17 + +/* Data transfer packet - 10 W parameters (disk), 6W parameters (tape), 10 W status */ #define RW_LNT 32 #define RW_BCL 8 /* byte count */ @@ -281,6 +397,9 @@ #define RW_MAPH 13 /* 14 /* reserved */ /* 15 /* reserved */ + +/* Disk specific parameters */ + #define RW_LBNL 16 /* LBN */ #define RW_LBNH 17 #define RW_WBCL 18 /* working bc */ @@ -290,6 +409,13 @@ #define RW_WBLL 22 /* working lbn */ #define RW_WBLH 23 +/* Tape specific status */ + +#define RW_POSL 16 /* position */ +#define RW_POSH 17 +#define RW_RSZL 18 /* record size */ +#define RW_RSZH 19 + /* Error log packet header */ #define ELP_REFL 2 /* ref # */ @@ -331,13 +457,23 @@ #define DTE_UIDC 16 #define DTE_UIDD 17 #define DTE_UVER 18 +#define DTE_D2 23 +#define DTE_D3 24 +#define DTE_D4 25 + +/* Disk specific status */ + #define DTE_SCYL 19 /* cylinder */ #define DTE_VSNL 20 /* vol ser # */ #define DTE_VSNH 21 #define DTE_D1 22 /* dev params */ -#define DTE_D2 23 -#define DTE_D3 24 -#define DTE_D4 25 + +/* Tape specific status */ + +#define DTE_RETR 19 /* retry */ +#define DTE_POSL 20 /* position */ +#define DTE_POSH 21 +#define DTE_FVER 22 /* formatter ver */ #define DTE_CIDD_V_MOD 0 /* ctrl model */ #define DTE_CIDD_V_CLS 8 /* ctrl class */ @@ -371,3 +507,5 @@ */ #define UNA_LNT 32 + +#endif diff --git a/PDP11/pdp11_pclk.c b/PDP11/pdp11_pclk.c new file mode 100644 index 00000000..6561bf96 --- /dev/null +++ b/PDP11/pdp11_pclk.c @@ -0,0 +1,292 @@ +/* pdp11_pclk.c: KW11P programmable clock simulator + + Copyright (c) 1993-2002, Robert M Supnik + Written by John Dundas, used with his gracious permission + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + pclk KW11P line frequency clock +*/ + +/* KW11-P Programmable Clock + + I/O Page Registers: + + CSR 17 772 540 + CSB 17 772 542 + CNT 17 772 544 + + Vector: 0104 + + Priority: BR6 + + ** Theory of Operation ** + + A real KW11-P is built around the following major components: + - 16-bit up/down counter + - 16-bit count set buffer + - 9-bit control and status register + - clocks: crystal controlled (1) 100 kHz and (2) 10 kHz clocks, + (3) a 50/60 Hz line frequency clock, and (4) an analog signal + input trigger + This software emulator for SIMH implements all of the above with + the exception of the external input trigger, which is arbitrarily + wired to 10Hz. + + Operation of this emulator is rather simplistic as compared to the + actual device. The register read and write routines are responsible + for copying internal state from the simulated device to the operating + program. Clock state variables are altered in the write routine + as well as the desired clock ticking rate. Possible rates are + given in the table below. + + Rate Bit 2 Bit 1 + 100 kHz 0 0 + 10 kHz 0 1 + Line frequency 1 0 + External 1 1 + + I think SIMH would have a hard time actually keeping up with a 100 + kHz ticking rate. I haven't tried this to verify, though. + + The clock service routine (pclk_svc) is responsible for ticking + the clock. The routine does implement up/down, repeat vs. + single-interrupt, and single clocking (maintenance). The routine + updates the internal state according to the options selected and + signals interrupts when appropriate. + + For a complete description of the device, please see DEC-11-HPWB-D + KW11-P Programmable Real-Time Clock Manual. + + ** Notes ** + + 1. The device is disabled by default. + + 2. Use XXDP V2.5 test program ZKWBJ1.BIC; loads at 1000, starts at + 1100? Seems to execute the first few tests correctly then waits + for input from the console. I don't have a description of how this + diagnostic works and thus don't know how to proceed from that point. + + 3. The read and write routines don't do anything with odd address + accesses. The manual says that byte writes don't work. + + 4. RSTS can use this clock in place of the standard KW11-L line + frequency clock. In order to do this, use the DEFAULT response in + the OPTION: dialog. To the Preferred clock prompt answer "P". + Then you have the option of line frequency "L" or some multiple of + 50 between 50 and 1000 to use the programmable portion of the clock. + + 5. This is really a Unibus peripheral and thus doesn't actually make + sense within a J-11 system as there never was a Qbus version of + this to the best of my knowledge. However the OSs I have tried + don't appear to exhibit any dissonance between this option and the + processor/bus emulation. I think the options that would make + somewhat more sense in a Qbus environment the KWV11-C and/or KWV11-S. + I don't know if any of the -11 OSs contained support for using + these as the system clock, though. +*/ + +#include "pdp11_defs.h" + +#define PCLKCSR_RDMASK 0100377 /* readable */ +#define PCLKCSR_WRMASK 0000137 /* writeable */ + +#define UNIT_V_LINE50HZ (UNIT_V_UF + 0) +#define UNIT_LINE50HZ (1 << UNIT_V_LINE50HZ) + +/* CSR - 17772540 */ + +#define CSR_V_FIX 5 /* single tick */ +#define CSR_V_UPDN 4 /* down/up */ +#define CSR_V_MODE 3 /* single/repeat */ +#define CSR_FIX (1u << CSR_V_FIX) +#define CSR_UPDN (1u << CSR_V_UPDN) +#define CSR_MODE (1u << CSR_V_MODE) +#define CSR_V_RATE 1 /* rate */ +#define CSR_M_RATE 03 +#define CSR_GETRATE(x) (((x) >> CSR_V_RATE) & CSR_M_RATE) + +extern int32 int_req[IPL_HLVL]; +extern int32 int_vec[IPL_HLVL][32]; + +uint32 pclk_csr = 0; /* control/status */ +uint32 pclk_csb = 0; /* count set buffer */ +uint32 pclk_ctr = 0; /* counter */ +static uint32 rate[4] = { 100000, 10000, 60, 10 }; /* ticks per second */ +static uint32 xtim[4] = { 10, 100, 16000, 100000 }; /* nominal time delay */ + +DEVICE pclk_dev; +t_stat pclk_rd (int32 *data, int32 PA, int32 access); +t_stat pclk_wr (int32 data, int32 PA, int32 access); +t_stat pclk_svc (UNIT *uptr); +t_stat pclk_reset (DEVICE *dptr); +t_stat pclk_set_line (UNIT *uptr, int32 val, char *cptr, void *desc); +void pclk_tick (void); + +/* PCLK data structures + + pclk_dev PCLK device descriptor + pclk_unit PCLK unit descriptor + pclk_reg PCLK register list +*/ + +DIB pclk_dib = { IOBA_PCLK, IOLN_PCLK, &pclk_rd, &pclk_wr, + 1, IVCL (PCLK), VEC_PCLK, { NULL } }; + +UNIT pclk_unit = { UDATA (&pclk_svc, 0, 0) }; + +REG pclk_reg[] = { + { ORDATA (CSR, pclk_csr, 16) }, + { ORDATA (CSB, pclk_csb, 16) }, + { ORDATA (CNT, pclk_ctr, 16) }, + { FLDATA (INT, IREQ (PCLK), INT_V_PCLK) }, + { FLDATA (OVFL, pclk_csr, CSR_V_ERR) }, + { FLDATA (DONE, pclk_csr, CSR_V_DONE) }, + { FLDATA (IE, pclk_csr, CSR_V_IE) }, + { FLDATA (UPDN, pclk_csr, CSR_V_UPDN) }, + { FLDATA (MODE, pclk_csr, CSR_V_MODE) }, + { FLDATA (RUN, pclk_csr, CSR_V_GO) }, + { BRDATA (TIME, xtim, 10, 32, 4), REG_NZ + PV_LEFT }, + { BRDATA (TPS, rate, 10, 32, 4), REG_NZ + PV_LEFT }, + { DRDATA (CURTIM, pclk_unit.wait, 32), REG_HRO }, + { ORDATA (DEVADDR, pclk_dib.ba, 32), REG_HRO }, + { ORDATA (DEVVEC, pclk_dib.vec, 16), REG_HRO }, + { NULL } }; + +MTAB pclk_mod[] = { + { UNIT_LINE50HZ, UNIT_LINE50HZ, "50 Hz", "50HZ", &pclk_set_line }, + { UNIT_LINE50HZ, 0, "60 Hz", "60HZ", &pclk_set_line }, + { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, + NULL, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + &set_vec, &show_vec, NULL }, + { 0 } }; + +DEVICE pclk_dev = { + "PCLK", &pclk_unit, pclk_reg, pclk_mod, + 1, 0, 0, 0, 0, 0, + NULL, NULL, &pclk_reset, + NULL, NULL, NULL, + &pclk_dib, DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS }; + +/* Clock I/O address routines */ + +t_stat pclk_rd (int32 *data, int32 PA, int32 access) +{ +switch ((PA >> 1) & 03) { +case 00: /* CSR */ + *data = pclk_csr & PCLKCSR_RDMASK; /* return CSR */ + pclk_csr = pclk_csr & ~(CSR_ERR | CSR_DONE); /* clr err, done */ + CLR_INT (PCLK); /* clr intr */ + break; +case 01: /* buffer */ + *data = 0; /* read only */ + break; +case 02: /* counter */ + *data = pclk_ctr & DMASK; /* return counter */ + break; } +return SCPE_OK; +} + +t_stat pclk_wr (int32 data, int32 PA, int32 access) +{ +int32 old_csr = pclk_csr; +int32 rv; + +switch ((PA >> 1) & 03) { +case 00: /* CSR */ + pclk_csr = data & PCLKCSR_WRMASK; /* clear and write */ + CLR_INT (PCLK); /* clr intr */ + rv = CSR_GETRATE (pclk_csr); /* new rate */ + pclk_unit.wait = xtim[rv]; /* new delay */ + if ((pclk_csr & CSR_GO) == 0) { /* stopped? */ + sim_cancel (&pclk_unit); /* cancel */ + if (data & CSR_FIX) pclk_tick (); } /* fix? tick */ + else if (((old_csr & CSR_GO) == 0) || /* run 0 -> 1? */ + (rv != CSR_GETRATE (old_csr))) { /* rate change? */ + sim_cancel (&pclk_unit); /* cancel */ + sim_activate (&pclk_unit, /* start clock */ + sim_rtcn_init (pclk_unit.wait, TMR_PCLK)); + } + break; +case 01: /* buffer */ + pclk_csb = pclk_ctr = data; /* store ctr */ + pclk_csr = pclk_csr & ~(CSR_ERR | CSR_DONE); /* clr err, done */ + CLR_INT (PCLK); /* clr intr */ + break; +case 02: /* counter */ + break; } /* read only */ +return SCPE_OK; +} + +/* Clock tick (automatic or manual) */ + +void pclk_tick (void) +{ +if (pclk_csr & CSR_UPDN) /* up or down? */ + pclk_ctr = (pclk_ctr + 1) & DMASK; /* 1 = up */ +else pclk_ctr = (pclk_ctr - 1) & DMASK; /* 0 = down */ +if (pclk_ctr == 0) { /* reached zero? */ + if (pclk_csr & CSR_DONE) /* done already set? */ + pclk_csr = pclk_csr | CSR_ERR; /* set error */ + else pclk_csr = pclk_csr | CSR_DONE; /* else set done */ + if (pclk_csr & CSR_IE) SET_INT (PCLK); /* if IE, set int */ + if (pclk_csr & CSR_MODE) pclk_ctr = pclk_csb; /* if rpt, reload */ + else { pclk_csb = 0; /* else clr ctr */ + pclk_csr = pclk_csr & ~CSR_GO; } } /* and clr go */ +return; +} + +/* Clock service */ + +t_stat pclk_svc (UNIT *uptr) +{ +int32 rv; + +pclk_tick (); /* tick clock */ +if ((pclk_csr & CSR_GO) == 0) return SCPE_OK; /* done? */ +rv = CSR_GETRATE (pclk_csr); /* get rate */ +sim_activate (&pclk_unit, sim_rtcn_calb (rate[rv], TMR_PCLK)); +return SCPE_OK; +} + +/* Clock reset */ + +t_stat pclk_reset (DEVICE *dptr) +{ +pclk_csr = 0; /* clear reg */ +pclk_csb = 0; +pclk_ctr = 0; +CLR_INT (PCLK); /* clear int */ +sim_cancel (&pclk_unit); /* cancel */ +pclk_unit.wait = xtim[0]; /* reset delay */ +return SCPE_OK; +} + +/* Set line frequency */ + +t_stat pclk_set_line (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (val == UNIT_LINE50HZ) rate[2] = 50; +else rate[2] = 60; +return SCPE_OK; +} diff --git a/sim_vt.h b/PDP11/pdp11_pt.c similarity index 69% rename from sim_vt.h rename to PDP11/pdp11_pt.c index ebe23a75..eb590216 100644 --- a/sim_vt.h +++ b/PDP11/pdp11_pt.c @@ -1,7 +1,6 @@ -/* sim_vt.h: VT2xx compatible Terminalemulator +/* pdp11_pt.c: PDP-11 paper tape reader/punch simulator - Copyright (c) 2002, Robert M Supnik - Written by Fischer Franz and used with his gracious permission + Copyright (c) 1993-2002, Robert M Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -24,11 +23,24 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - 15-Mar-02 FF Original version Fischer Franz + ptr paper tape reader + ptp paper tape punch + + 12-Sep-02 RMS Split off from pdp11_stddev.c */ -int vt_read (void); -void vt_write (char c); -void vt_init (void); -void vt_cmd (void); -void vt_run (void); +#if defined (USE_INT64) /* VAX version */ +#include "vax_defs.h" +#define VM_VAX 1 +#define PT_RDX 16 +#define PT_DIS DEV_DIS +#else +#include "pdp11_defs.h" /* PDP-11 version */ +#define VM_PDP11 1 +#define PT_RDX 8 +#define PT_DIS 0 +#endif + +extern int32 int_req[IPL_HLVL]; +extern int32 int_vec[IPL_HLVL][32]; +#include "dec_pt.h" diff --git a/PDP11/pdp11_rk.c b/PDP11/pdp11_rk.c index 72a9e74c..255f1b24 100644 --- a/PDP11/pdp11_rk.c +++ b/PDP11/pdp11_rk.c @@ -25,6 +25,10 @@ rk RK11/RK05 cartridge disk + 29-Sep-02 RMS Added variable address support to bootstrap + Added vector change/display support + Revised mapping mnemonics + New data structures 26-Jan-02 RMS Revised bootstrap to conform to M9312 06-Jan-02 RMS Revised enable/disable support 30-Nov-01 RMS Added read only unit, extended SET/SHOW support @@ -75,7 +79,6 @@ #define UNIT_V_HWLK (UNIT_V_UF + 0) /* hwre write lock */ #define UNIT_V_SWLK (UNIT_V_UF + 1) /* swre write lock */ -#define UNIT_W_UF 3 /* user flags width */ #define UNIT_HWLK (1u << UNIT_V_HWLK) #define UNIT_SWLK (1u << UNIT_V_SWLK) #define UNIT_WPRT (UNIT_HWLK|UNIT_SWLK|UNIT_RO) /* write prot */ @@ -169,6 +172,8 @@ extern uint16 *M; /* memory */ extern int32 int_req[IPL_HLVL]; +extern int32 int_vec[IPL_HLVL][32]; + uint16 *rkxb = NULL; /* xfer buffer */ int32 rkcs = 0; /* control/status */ int32 rkds = 0; /* drive status */ @@ -182,14 +187,16 @@ int32 rk_stopioe = 1; /* stop on error */ int32 rk_swait = 10; /* seek time */ int32 rk_rwait = 10; /* rotate time */ +DEVICE rk_dev; t_stat rk_rd (int32 *data, int32 PA, int32 access); t_stat rk_wr (int32 data, int32 PA, int32 access); +int32 rk_inta (void); t_stat rk_svc (UNIT *uptr); t_stat rk_reset (DEVICE *dptr); void rk_go (void); void rk_set_done (int32 error); void rk_clr_done (void); -t_stat rk_boot (int32 unitno); +t_stat rk_boot (int32 unitno, DEVICE *dptr); /* RK11 data structures @@ -199,7 +206,8 @@ t_stat rk_boot (int32 unitno); rk_mod RK modifier list */ -DIB rk_dib = { 1, IOBA_RK, IOLN_RK, &rk_rd, &rk_wr }; +DIB rk_dib = { IOBA_RK, IOLN_RK, &rk_rd, &rk_wr, + 1, IVCL (RK), VEC_RK, { &rk_inta } }; UNIT rk_unit[] = { { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ @@ -234,29 +242,26 @@ REG rk_reg[] = { { FLDATA (IE, rkcs, CSR_V_IE) }, { DRDATA (STIME, rk_swait, 24), PV_LEFT }, { DRDATA (RTIME, rk_rwait, 24), PV_LEFT }, - { URDATA (FLG, rk_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, - RK_NUMDR, REG_HRO) }, { FLDATA (STOP_IOE, rk_stopioe, 0) }, { ORDATA (DEVADDR, rk_dib.ba, 32), REG_HRO }, - { FLDATA (*DEVENB, rk_dib.enb, 0), REG_HRO }, + { ORDATA (DEVVEC, rk_dib.vec, 16), REG_HRO }, { NULL } }; MTAB rk_mod[] = { { UNIT_HWLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL }, { MTAB_XTD|MTAB_VDV, 020, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, &rk_dib }, - { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", - &set_enbdis, NULL, &rk_dib }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", - &set_enbdis, NULL, &rk_dib }, + &set_addr, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + &set_vec, &show_vec, NULL }, { 0 } }; DEVICE rk_dev = { "RK", rk_unit, rk_reg, rk_mod, RK_NUMDR, 8, 24, 1, 8, 16, NULL, NULL, &rk_reset, - &rk_boot, NULL, NULL }; + &rk_boot, NULL, NULL, + &rk_dib, DEV_DISABLE | DEV_UBUS }; /* I/O dispatch routine, I/O addresses 17777400 - 17777416 @@ -281,9 +286,9 @@ case 0: /* RKDS: read only */ rkds = (rkds & RKDS_ID) | RKDS_RK05 | RKDS_SC_OK | (rand () % RK_NUMSC); /* random sector */ uptr = rk_dev.units + GET_DRIVE (rkda); /* selected unit */ - if (uptr -> flags & UNIT_ATT) rkds = rkds | RKDS_RDY; /* attached? */ + if (uptr->flags & UNIT_ATT) rkds = rkds | RKDS_RDY; /* attached? */ if (!sim_is_active (uptr)) rkds = rkds | RKDS_RWS; /* idle? */ - if (uptr -> flags & UNIT_WPRT) rkds = rkds | RKDS_WLK; + if (uptr->flags & UNIT_WPRT) rkds = rkds | RKDS_WLK; if (GET_SECT (rkda) == (rkds & RKDS_SC)) rkds = rkds | RKDS_ON_SC; *data = rkds; return SCPE_OK; @@ -323,10 +328,10 @@ case 2: /* RKCS */ (rkcs & 0377) | (data << 8): (rkcs & ~0377) | data; if ((data & CSR_IE) == 0) { /* int disable? */ rkintq = 0; /* clr int queue */ - CLR_INT (RK); } /* clr int request */ + CLR_INT (RK); } /* clr int request */ else if ((rkcs & (CSR_DONE + CSR_IE)) == CSR_DONE) { rkintq = rkintq | RK_CTLI; /* queue ctrl int */ - SET_INT (RK); } /* set int request */ + SET_INT (RK); } /* set int request */ rkcs = (rkcs & ~RKCS_RW) | (data & RKCS_RW); if ((rkcs & CSR_DONE) && (data & CSR_GO)) rk_go (); /* new function? */ return SCPE_OK; @@ -364,7 +369,7 @@ if (func == RKCS_CTLRESET) { /* control reset? */ rkba = 0; rkcs = CSR_DONE; rkintq = 0; /* clr int queue */ - CLR_INT (RK); /* clr int request */ + CLR_INT (RK); /* clr int request */ return; } rker = rker & ~RKER_SOFT; /* clear soft errors */ if (rker == 0) rkcs = rkcs & ~RKCS_ERR; /* redo summary */ @@ -372,24 +377,24 @@ rkcs = rkcs & ~RKCS_SCP; /* clear sch compl*/ rk_clr_done (); /* clear done */ last_drv = GET_DRIVE (rkda); /* get drive no */ uptr = rk_dev.units + last_drv; /* select unit */ -if (uptr -> flags & UNIT_DIS) { /* not present? */ +if (uptr->flags & UNIT_DIS) { /* not present? */ rk_set_done (RKER_NXD); return; } -if (((uptr -> flags & UNIT_ATT) == 0) || sim_is_active (uptr)) { +if (((uptr->flags & UNIT_ATT) == 0) || sim_is_active (uptr)) { rk_set_done (RKER_DRE); /* not att or busy */ return; } if (rkcs & (RKCS_INH + RKCS_FMT)) { /* format? */ rk_set_done (RKER_PGE); return; } -if ((func == RKCS_WRITE) && (uptr -> flags & UNIT_WPRT)) { +if ((func == RKCS_WRITE) && (uptr->flags & UNIT_WPRT)) { rk_set_done (RKER_WLK); /* write and locked? */ return; } if (func == RKCS_WLK) { /* write lock? */ - uptr -> flags = uptr -> flags | UNIT_SWLK; + uptr->flags = uptr->flags | UNIT_SWLK; rk_set_done (0); return; } if (func == RKCS_DRVRESET) { /* drive reset? */ - uptr -> flags = uptr -> flags & ~UNIT_SWLK; + uptr->flags = uptr->flags & ~UNIT_SWLK; cyl = sect = 0; func = RKCS_SEEK; } else { sect = GET_SECT (rkda); @@ -400,13 +405,13 @@ if (sect >= RK_NUMSC) { /* bad sector? */ if (cyl >= RK_NUMCY) { /* bad cyl? */ rk_set_done (RKER_NXC); return; } -i = abs (cyl - uptr -> CYL) * rk_swait; /* seek time */ +i = abs (cyl - uptr->CYL) * rk_swait; /* seek time */ if (func == RKCS_SEEK) { /* seek? */ rk_set_done (0); /* set done */ sim_activate (uptr, MAX (RK_MIN, i)); } /* schedule */ else sim_activate (uptr, i + rk_rwait); -uptr -> FUNC = func; /* save func */ -uptr -> CYL = cyl; /* put on cylinder */ +uptr->FUNC = func; /* save func */ +uptr->CYL = cyl; /* put on cylinder */ return; } @@ -427,7 +432,7 @@ t_addr ma; uint16 comp; drv = uptr - rk_dev.units; /* get drv number */ -if (uptr -> FUNC == RKCS_SEEK) { /* seek */ +if (uptr->FUNC == RKCS_SEEK) { /* seek */ rkcs = rkcs | RKCS_SCP; /* set seek done */ if (rkcs & CSR_IE) { /* ints enabled? */ rkintq = rkintq | RK_SCPI (drv); /* queue request */ @@ -436,42 +441,42 @@ if (uptr -> FUNC == RKCS_SEEK) { /* seek */ CLR_INT (RK); } /* clear interrupt */ return SCPE_OK; } -if ((uptr -> flags & UNIT_ATT) == 0) { /* attached? */ +if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */ rk_set_done (RKER_DRE); return IORETURN (rk_stopioe, SCPE_UNATT); } ma = ((rkcs & RKCS_MEX) << (16 - RKCS_V_MEX)) | rkba; /* get mem addr */ da = GET_DA (rkda) * RK_NUMWD; /* get disk addr */ wc = 0200000 - rkwc; /* get wd cnt */ -err = fseek (uptr -> fileref, da * sizeof (int16), SEEK_SET); +err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET); -if ((uptr -> FUNC == RKCS_READ) && (err == 0)) { /* read? */ - i = fxread (rkxb, sizeof (int16), wc, uptr -> fileref); - err = ferror (uptr -> fileref); +if ((uptr->FUNC == RKCS_READ) && (err == 0)) { /* read? */ + i = fxread (rkxb, sizeof (int16), wc, uptr->fileref); + err = ferror (uptr->fileref); for ( ; i < wc; i++) rkxb[i] = 0; /* fill buf */ - if (t = Map_WriteW (ma, wc << 1, rkxb, UB)) { /* store buf */ + if (t = Map_WriteW (ma, wc << 1, rkxb, MAP)) { /* store buf */ rker = rker | RKER_NXM; /* NXM? set flg */ wc = wc - t; } /* adj wd cnt */ } /* end read */ -if ((uptr -> FUNC == RKCS_WRITE) && (err == 0)) { /* write? */ - if (t = Map_ReadW (ma, wc << 1, rkxb, UB)) { /* get buf */ +if ((uptr->FUNC == RKCS_WRITE) && (err == 0)) { /* write? */ + if (t = Map_ReadW (ma, wc << 1, rkxb, MAP)) { /* get buf */ rker = rker | RKER_NXM; /* NXM? set flg */ wc = wc - t; } /* adj wd cnt */ if (wc) { /* any xfer? */ awc = (wc + (RK_NUMWD - 1)) & ~(RK_NUMWD - 1); /* clr to */ for (i = wc; i < awc; i++) rkxb[i] = 0; /* end of blk */ - fxwrite (rkxb, sizeof (int16), awc, uptr -> fileref); - err = ferror (uptr -> fileref); } + fxwrite (rkxb, sizeof (int16), awc, uptr->fileref); + err = ferror (uptr->fileref); } } /* end write */ -if ((uptr -> FUNC == RKCS_WCHK) && (err == 0)) { /* write check? */ - i = fxread (rkxb, sizeof (int16), wc, uptr -> fileref); - err = ferror (uptr -> fileref); +if ((uptr->FUNC == RKCS_WCHK) && (err == 0)) { /* write check? */ + i = fxread (rkxb, sizeof (int16), wc, uptr->fileref); + err = ferror (uptr->fileref); for ( ; i < wc; i++) rkxb[i] = 0; /* fill buf */ awc = wc; /* save wc */ for (wc = 0; (err == 0) && (wc < awc); wc++) { /* loop thru buf */ - if (Map_ReadW (ma + (wc << 1), 2, &comp, UB)) { /* mem wd */ + if (Map_ReadW (ma + (wc << 1), 2, &comp, MAP)) { /* mem wd */ rker = rker | RKER_NXM; /* NXM? set flg */ break; } if (comp != rkxb[wc]) { /* match to disk? */ @@ -491,7 +496,7 @@ rk_set_done (0); if (err != 0) { /* error? */ perror ("RK I/O error"); - clearerr (uptr -> fileref); + clearerr (uptr->fileref); return SCPE_IOERR; } return SCPE_OK; } @@ -505,25 +510,25 @@ return SCPE_OK; void rk_set_done (int32 error) { - rkcs = rkcs | CSR_DONE; /* set done */ - if (error != 0) { - rker = rker | error; /* update error */ - if (rker) rkcs = rkcs | RKCS_ERR; /* update err flags */ - if (rker & RKER_HARD) rkcs = rkcs | RKCS_HERR; } - if (rkcs & CSR_IE) { /* int enable? */ - rkintq = rkintq | RK_CTLI; /* set ctrl int */ - SET_INT (RK); } /* request int */ - else { rkintq = 0; /* clear queue */ - CLR_INT (RK); } - return; +rkcs = rkcs | CSR_DONE; /* set done */ +if (error != 0) { + rker = rker | error; /* update error */ + if (rker) rkcs = rkcs | RKCS_ERR; /* update err flags */ + if (rker & RKER_HARD) rkcs = rkcs | RKCS_HERR; } +if (rkcs & CSR_IE) { /* int enable? */ + rkintq = rkintq | RK_CTLI; /* set ctrl int */ + SET_INT (RK); } /* request int */ +else { rkintq = 0; /* clear queue */ + CLR_INT (RK); } +return; } void rk_clr_done (void) { - rkcs = rkcs & ~CSR_DONE; /* clear done */ - rkintq = rkintq & ~RK_CTLI; /* clear ctl int */ - CLR_INT (RK); /* clear int req */ - return; +rkcs = rkcs & ~CSR_DONE; /* clear done */ +rkintq = rkintq & ~RK_CTLI; /* clear ctl int */ +CLR_INT (RK); /* clear int req */ +return; } int32 rk_inta (void) @@ -536,7 +541,7 @@ for (i = 0; i <= RK_NUMDR; i++) { /* loop thru intq */ if (rkintq) SET_INT (RK); /* queue next */ rkds = (rkds & ~RKDS_ID) | /* id drive */ (((i == 0)? last_drv: i - 1) << RKDS_V_ID); - return VEC_RK; } } /* return vector */ + return rk_dib.vec; } } /* return vector */ rkintq = 0; /* clear queue */ return 0; /* passive release */ } @@ -555,8 +560,8 @@ CLR_INT (RK); for (i = 0; i < RK_NUMDR; i++) { uptr = rk_dev.units + i; sim_cancel (uptr); - uptr -> CYL = uptr -> FUNC = 0; - uptr -> flags = uptr -> flags & ~UNIT_SWLK; } + uptr->CYL = uptr->FUNC = 0; + uptr->flags = uptr->flags & ~UNIT_SWLK; } if (rkxb == NULL) rkxb = calloc (RK_MAXFR, sizeof (unsigned int16)); if (rkxb == NULL) return SCPE_MEM; return SCPE_OK; @@ -565,13 +570,14 @@ return SCPE_OK; /* Device bootstrap */ #define BOOT_START 02000 /* start */ -#define BOOT_ENTRY 02002 /* entry */ -#define BOOT_UNIT 02010 /* unit number */ -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) +#define BOOT_ENTRY (BOOT_START + 002) /* entry */ +#define BOOT_UNIT (BOOT_START + 010) /* unit number */ +#define BOOT_CSR (BOOT_START + 032) /* CSR */ +#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) -static const int32 boot_rom[] = { +static const uint16 boot_rom[] = { 0042113, /* "KD" */ - 0012706, 0002000, /* MOV #2000, SP */ + 0012706, BOOT_START, /* MOV #boot_start, SP */ 0012700, 0000000, /* MOV #unit, R0 ; unit number */ 0010003, /* MOV R0, R3 */ 0000303, /* SWAB R3 */ @@ -595,13 +601,14 @@ static const int32 boot_rom[] = { 0005007 /* CLR PC */ }; -t_stat rk_boot (int32 unitno) +t_stat rk_boot (int32 unitno, DEVICE *dptr) { int32 i; extern int32 saved_PC; for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i]; M[BOOT_UNIT >> 1] = unitno & RK_M_NUMDR; +M[BOOT_CSR >> 1] = (rk_dib.ba & DMASK) + 012; saved_PC = BOOT_ENTRY; return SCPE_OK; } diff --git a/PDP11/pdp11_rl.c b/PDP11/pdp11_rl.c index 36d4f7ca..0afd3c38 100644 --- a/PDP11/pdp11_rl.c +++ b/PDP11/pdp11_rl.c @@ -1,4 +1,4 @@ - /* pdp11_rl.c: RL11 (RLV12) cartridge disk simulator +/* pdp11_rl.c: RL11 (RLV12) cartridge disk simulator Copyright (c) 1993-2002, Robert M Supnik @@ -25,6 +25,10 @@ rl RL11(RLV12)/RL01/RL02 cartridge disk + 29-Sep-02 RMS Added variable address support to bootstrap + Added vector change/display support + Revised mapping nomenclature + New data structures 26-Jan-02 RMS Revised bootstrap to conform to M9312 06-Jan-02 RMS Revised enable/disable support 30-Nov-01 RMS Added read only, extended SET/SHOW support @@ -65,13 +69,11 @@ #include "vax_defs.h" #define VM_VAX 1 #define RL_RDX 16 -#define RL_18B FALSE /* always 22b */ #else /* PDP11 version */ #include "pdp11_defs.h" #define VM_PDP11 1 #define RL_RDX 8 -#define RL_18B (cpu_18b || cpu_ubm) extern int32 cpu_18b, cpu_ubm; #endif @@ -88,11 +90,10 @@ extern int32 cpu_18b, cpu_ubm; /* Flags in the unit flags word */ -#define UNIT_V_WLK (UNIT_V_UF) /* hwre write lock */ -#define UNIT_V_RL02 (UNIT_V_UF+1) /* RL01 vs RL02 */ -#define UNIT_V_AUTO (UNIT_V_UF+2) /* autosize enable */ -#define UNIT_W_UF 4 /* saved flags width */ -#define UNIT_V_DUMMY (UNIT_V_UF + UNIT_W_UF) /* dummy flag */ +#define UNIT_V_WLK (UNIT_V_UF + 0) /* hwre write lock */ +#define UNIT_V_RL02 (UNIT_V_UF + 1) /* RL01 vs RL02 */ +#define UNIT_V_AUTO (UNIT_V_UF + 2) /* autosize enable */ +#define UNIT_V_DUMMY (UNIT_V_UF + 3) /* dummy flag */ #define UNIT_DUMMY (1 << UNIT_V_DUMMY) #define UNIT_WLK (1u << UNIT_V_WLK) #define UNIT_RL02 (1u << UNIT_V_RL02) @@ -184,7 +185,10 @@ extern int32 cpu_18b, cpu_ubm; #define RLBAE_IMP 0000077 /* implemented */ +extern uint16 *M; extern int32 int_req[IPL_HLVL]; +extern int32 int_vec[IPL_HLVL][32]; + uint16 *rlxb = NULL; /* xfer buffer */ int32 rlcs = 0; /* control/status */ int32 rlba = 0; /* memory address */ @@ -195,12 +199,13 @@ int32 rl_swait = 10; /* seek wait */ int32 rl_rwait = 10; /* rotate wait */ int32 rl_stopioe = 1; /* stop on error */ +DEVICE rl_dev; t_stat rl_rd (int32 *data, int32 PA, int32 access); t_stat rl_wr (int32 data, int32 PA, int32 access); t_stat rl_svc (UNIT *uptr); t_stat rl_reset (DEVICE *dptr); void rl_set_done (int32 error); -t_stat rl_boot (int32 unitno); +t_stat rl_boot (int32 unitno, DEVICE *dptr); t_stat rl_attach (UNIT *uptr, char *cptr); t_stat rl_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc); @@ -214,7 +219,8 @@ extern t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds); rl_mod RL modifier list */ -DIB rl_dib = { 1, IOBA_RL, IOLN_RL, &rl_rd, &rl_wr }; +DIB rl_dib = { IOBA_RL, IOLN_RL, &rl_rd, &rl_wr, + 1, IVCL (RL), VEC_RL, { NULL } }; UNIT rl_unit[] = { { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ @@ -240,13 +246,11 @@ REG rl_reg[] = { { FLDATA (IE, rlcs, CSR_V_IE) }, { DRDATA (STIME, rl_swait, 24), PV_LEFT }, { DRDATA (RTIME, rl_rwait, 24), PV_LEFT }, - { URDATA (FLG, rl_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, - RL_NUMDR, REG_HRO) }, { URDATA (CAPAC, rl_unit[0].capac, 10, 31, 0, RL_NUMDR, PV_LEFT + REG_HRO) }, { FLDATA (STOP_IOE, rl_stopioe, 0) }, { GRDATA (DEVADDR, rl_dib.ba, RL_RDX, 32, 0), REG_HRO }, - { FLDATA (*DEVENB, rl_dib.enb, 0), REG_HRO }, + { GRDATA (DEVVEC, rl_dib.vec, RL_RDX, 16, 0), REG_HRO }, { NULL } }; MTAB rl_mod[] = { @@ -262,18 +266,17 @@ MTAB rl_mod[] = { { (UNIT_AUTO+UNIT_RL02), 0, NULL, "RL01", &rl_set_size }, { (UNIT_AUTO+UNIT_RL02), UNIT_RL02, NULL, "RL02", &rl_set_size }, { MTAB_XTD|MTAB_VDV, 010, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, &rl_dib }, - { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", - &set_enbdis, NULL, &rl_dib }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", - &set_enbdis, NULL, &rl_dib }, + &set_addr, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + &set_vec, &show_vec, NULL }, { 0 } }; DEVICE rl_dev = { "RL", rl_unit, rl_reg, rl_mod, RL_NUMDR, RL_RDX, 24, 1, RL_RDX, 16, NULL, NULL, &rl_reset, - &rl_boot, &rl_attach, NULL }; + &rl_boot, &rl_attach, NULL, + &rl_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS }; /* I/O dispatch routine, I/O addresses 17774400 - 17774407 @@ -309,7 +312,7 @@ case 3: /* RLMP */ rlmp1 = rlmp2; break; case 4: /* RLBAE */ - if (RL_18B) return SCPE_NXM; /* not in RL11 */ + if (UNIBUS) return SCPE_NXM; /* not in RL11 */ *data = rlbae & RLBAE_IMP; break; } /* end switch */ return SCPE_OK; @@ -345,16 +348,16 @@ case 0: /* RLCS */ rl_set_done (0); break; case RLCS_SEEK: /* seek */ - curr = GET_CYL (uptr -> TRK); /* current cylinder */ + curr = GET_CYL (uptr->TRK); /* current cylinder */ offs = GET_CYL (rlda); /* offset */ if (rlda & RLDA_SK_DIR) { /* in or out? */ newc = curr + offs; /* out */ - maxc = (uptr -> flags & UNIT_RL02)? + maxc = (uptr->flags & UNIT_RL02)? RL_NUMCY * 2: RL_NUMCY; if (newc >= maxc) newc = maxc - 1; } else { newc = curr - offs; /* in */ if (newc < 0) newc = 0; } - uptr -> TRK = (newc << RLDA_V_CYL) | /* put on track */ + uptr->TRK = (newc << RLDA_V_CYL) | /* put on track */ ((rlda & RLDA_SK_HD)? RLDA_HD1: RLDA_HD0); sim_activate (uptr, rl_swait * abs (newc - curr)); break; @@ -379,7 +382,7 @@ case 3: /* RLMP */ rlmp = rlmp1 = rlmp2 = data; break; case 4: /* RLBAE */ - if (RL_18B) return SCPE_NXM; /* not in RL11 */ + if (UNIBUS) return SCPE_NXM; /* not in RL11 */ if (PA & 1) return SCPE_OK; rlbae = data & RLBAE_IMP; rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX); @@ -405,23 +408,23 @@ uint16 comp; func = GET_FUNC (rlcs); /* get function */ if (func == RLCS_GSTA) { /* get status */ - if (rlda & RLDA_GS_CLR) uptr -> STAT = uptr -> STAT & ~RLDS_ERR; - rlmp = uptr -> STAT | (uptr -> TRK & RLDS_HD) | - ((uptr -> flags & UNIT_ATT)? RLDS_ATT: RLDS_UNATT); - if (uptr -> flags & UNIT_RL02) rlmp = rlmp | RLDS_RL02; - if (uptr -> flags & UNIT_WPRT) rlmp = rlmp | RLDS_WLK; + if (rlda & RLDA_GS_CLR) uptr->STAT = uptr->STAT & ~RLDS_ERR; + rlmp = uptr->STAT | (uptr->TRK & RLDS_HD) | + ((uptr->flags & UNIT_ATT)? RLDS_ATT: RLDS_UNATT); + if (uptr->flags & UNIT_RL02) rlmp = rlmp | RLDS_RL02; + if (uptr->flags & UNIT_WPRT) rlmp = rlmp | RLDS_WLK; rlmp2 = rlmp1 = rlmp; rl_set_done (0); /* done */ return SCPE_OK; } -if ((uptr -> flags & UNIT_ATT) == 0) { /* attached? */ +if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */ rlcs = rlcs & ~RLCS_DRDY; /* clear drive ready */ - uptr -> STAT = uptr -> STAT | RLDS_SPE; /* spin error */ + uptr->STAT = uptr->STAT | RLDS_SPE; /* spin error */ rl_set_done (RLCS_ERR | RLCS_INCMP); /* flag error */ return IORETURN (rl_stopioe, SCPE_UNATT); } -if ((func == RLCS_WRITE) && (uptr -> flags & UNIT_WPRT)) { - uptr -> STAT = uptr -> STAT | RLDS_WGE; /* write and locked */ +if ((func == RLCS_WRITE) && (uptr->flags & UNIT_WPRT)) { + uptr->STAT = uptr->STAT | RLDS_WGE; /* write and locked */ rl_set_done (RLCS_ERR | RLCS_DRE); return SCPE_OK; } @@ -430,12 +433,12 @@ if (func == RLCS_SEEK) { /* seek? */ return SCPE_OK; } if (func == RLCS_RHDR) { /* read header? */ - rlmp = (uptr -> TRK & RLDA_TRACK) | GET_SECT (rlda); + rlmp = (uptr->TRK & RLDA_TRACK) | GET_SECT (rlda); rlmp1 = rlmp2 = 0; rl_set_done (0); /* done */ return SCPE_OK; } -if (((func != RLCS_RNOHDR) && ((uptr -> TRK & RLDA_CYL) != (rlda & RLDA_CYL))) +if (((func != RLCS_RNOHDR) && ((uptr->TRK & RLDA_CYL) != (rlda & RLDA_CYL))) || (GET_SECT (rlda) >= RL_NUMSC)) { /* bad cyl or sector? */ rl_set_done (RLCS_ERR | RLCS_HDE | RLCS_INCMP); /* wrong cylinder? */ return SCPE_OK; } @@ -446,35 +449,35 @@ wc = 0200000 - rlmp; /* get true wc */ maxwc = (RL_NUMSC - GET_SECT (rlda)) * RL_NUMWD; /* max transfer */ if (wc > maxwc) wc = maxwc; /* track overrun? */ -err = fseek (uptr -> fileref, da * sizeof (int16), SEEK_SET); +err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET); if ((func >= RLCS_READ) && (err == 0)) { /* read (no hdr)? */ - i = fxread (rlxb, sizeof (int16), wc, uptr -> fileref); - err = ferror (uptr -> fileref); + i = fxread (rlxb, sizeof (int16), wc, uptr->fileref); + err = ferror (uptr->fileref); for ( ; i < wc; i++) rlxb[i] = 0; /* fill buffer */ - if (t = Map_WriteW (ma, wc << 1, rlxb, UB)) { /* store buffer */ + if (t = Map_WriteW (ma, wc << 1, rlxb, MAP)) { /* store buffer */ rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */ wc = wc - t; } /* adjust wc */ } /* end read */ if ((func == RLCS_WRITE) && (err == 0)) { /* write? */ - if (t = Map_ReadW (ma, wc << 1, rlxb, UB)) { /* fetch buffer */ + if (t = Map_ReadW (ma, wc << 1, rlxb, MAP)) { /* fetch buffer */ rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */ wc = wc - t; } /* adj xfer lnt */ if (wc) { /* any xfer? */ awc = (wc + (RL_NUMWD - 1)) & ~(RL_NUMWD - 1); /* clr to */ for (i = wc; i < awc; i++) rlxb[i] = 0; /* end of blk */ - fxwrite (rlxb, sizeof (int16), awc, uptr -> fileref); - err = ferror (uptr -> fileref); } + fxwrite (rlxb, sizeof (int16), awc, uptr->fileref); + err = ferror (uptr->fileref); } } /* end write */ if ((func == RLCS_WCHK) && (err == 0)) { /* write check? */ - i = fxread (rlxb, sizeof (int16), wc, uptr -> fileref); - err = ferror (uptr -> fileref); + i = fxread (rlxb, sizeof (int16), wc, uptr->fileref); + err = ferror (uptr->fileref); for ( ; i < wc; i++) rlxb[i] = 0; /* fill buffer */ awc = wc; /* save wc */ for (wc = 0; (err == 0) && (wc < awc); wc++) { /* loop thru buf */ - if (Map_ReadW (ma + (wc << 1), 2, &comp, UB)) { /* mem wd */ + if (Map_ReadW (ma + (wc << 1), 2, &comp, MAP)) { /* mem wd */ rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */ break; } if (comp != rlxb[wc]) /* check to buf */ @@ -493,7 +496,7 @@ rl_set_done (0); if (err != 0) { /* error? */ perror ("RL I/O error"); - clearerr (uptr -> fileref); + clearerr (uptr->fileref); return SCPE_IOERR; } return SCPE_OK; } @@ -524,7 +527,7 @@ CLR_INT (RL); for (i = 0; i < RL_NUMDR; i++) { uptr = rl_dev.units + i; sim_cancel (uptr); - uptr -> STAT = 0; } + uptr->STAT = 0; } if (rlxb == NULL) rlxb = calloc (RL_MAXFR, sizeof (unsigned int16)); if (rlxb == NULL) return SCPE_MEM; return SCPE_OK; @@ -537,20 +540,20 @@ t_stat rl_attach (UNIT *uptr, char *cptr) int32 p; t_stat r; -uptr -> capac = (uptr -> flags & UNIT_RL02)? RL02_SIZE: RL01_SIZE; +uptr->capac = (uptr->flags & UNIT_RL02)? RL02_SIZE: RL01_SIZE; r = attach_unit (uptr, cptr); -if ((r != SCPE_OK) || ((uptr -> flags & UNIT_AUTO) == 0)) return r; -uptr -> TRK = 0; /* cylinder 0 */ -uptr -> STAT = RLDS_VCK; /* new volume */ -if (fseek (uptr -> fileref, 0, SEEK_END)) return SCPE_OK; -if ((p = ftell (uptr -> fileref)) == 0) { - if (uptr -> flags & UNIT_RO) return SCPE_OK; +if ((r != SCPE_OK) || ((uptr->flags & UNIT_AUTO) == 0)) return r; +uptr->TRK = 0; /* cylinder 0 */ +uptr->STAT = RLDS_VCK; /* new volume */ +if (fseek (uptr->fileref, 0, SEEK_END)) return SCPE_OK; +if ((p = ftell (uptr->fileref)) == 0) { + if (uptr->flags & UNIT_RO) return SCPE_OK; return pdp11_bad_block (uptr, RL_NUMSC, RL_NUMWD); } if (p > (RL01_SIZE * sizeof (int16))) { - uptr -> flags = uptr -> flags | UNIT_RL02; - uptr -> capac = RL02_SIZE; } -else { uptr -> flags = uptr -> flags & ~UNIT_RL02; - uptr -> capac = RL01_SIZE; } + uptr->flags = uptr->flags | UNIT_RL02; + uptr->capac = RL02_SIZE; } +else { uptr->flags = uptr->flags & ~UNIT_RL02; + uptr->capac = RL01_SIZE; } return SCPE_OK; } @@ -558,8 +561,8 @@ return SCPE_OK; t_stat rl_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { -if (uptr -> flags & UNIT_ATT) return SCPE_ALATT; -uptr -> capac = (val & UNIT_RL02)? RL02_SIZE: RL01_SIZE; +if (uptr->flags & UNIT_ATT) return SCPE_ALATT; +uptr->capac = (val & UNIT_RL02)? RL02_SIZE: RL01_SIZE; return SCPE_OK; } @@ -575,14 +578,15 @@ return pdp11_bad_block (uptr, RL_NUMSC, RL_NUMWD); #if defined (VM_PDP11) #define BOOT_START 02000 /* start */ -#define BOOT_ENTRY 02002 /* entry */ -#define BOOT_UNIT 02010 /* unit number */ -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) +#define BOOT_ENTRY (BOOT_START + 002) /* entry */ +#define BOOT_UNIT (BOOT_START + 010) /* unit number */ +#define BOOT_CSR (BOOT_START + 020) /* CSR */ +#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) -static const int32 boot_rom[] = { +static const uint16 boot_rom[] = { 0042114, /* "LD" */ - 0012706, 0002000, /* MOV #2000, SP */ - 0012700, 0000000, /* MOV #UNIT, R0 */ + 0012706, BOOT_START, /* MOV #boot_start, SP */ + 0012700, 0000000, /* MOV #unit, R0 */ 0010003, /* MOV R0, R3 */ 0000303, /* SWAB R3 */ 0012701, 0174400, /* MOV #RLCS, R1 ; csr */ @@ -621,21 +625,21 @@ static const int32 boot_rom[] = { 0005007 /* CLR PC */ }; -t_stat rl_boot (int32 unitno) +t_stat rl_boot (int32 unitno, DEVICE *dptr) { int32 i; extern int32 saved_PC; -extern uint16 *M; for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i]; M[BOOT_UNIT >> 1] = unitno & RLCS_M_DRIVE; +M[BOOT_CSR >> 1] = rl_dib.ba & DMASK; saved_PC = BOOT_ENTRY; return SCPE_OK; } #else -t_stat rl_boot (int32 unitno) +t_stat rl_boot (int32 unitno, DEVICE *dptr) { return SCPE_NOFNC; } diff --git a/PDP11/pdp11_rp.c b/PDP11/pdp11_rp.c index ea825195..0d2ee4a8 100644 --- a/PDP11/pdp11_rp.c +++ b/PDP11/pdp11_rp.c @@ -25,6 +25,10 @@ rp RH/RP/RM moving head disks + 29-Sep-02 RMS Added variable address support to bootstrap + Added vector change/display support + Revised mapping mnemonics + New data structures 24-Apr-02 RMS Fixed SHOW RP ADDRESS 26-Jan-02 RMS Revised bootstrap to conform to M9312 06-Jan-02 RMS Revised enable/disable support @@ -75,12 +79,11 @@ The RP/RM functions in four environments: - - PDP-11 Q22 systems - the I/O map is one for one, so it's safe to - go through the I/O map + - PDP-11 Q22 systems - bus map is bypassed - PDP-11 Unibus systems with native 22b controllers - see above - - PDP-11 Unibus 22b systems - the RP/RM behaves as an 18b Unibus - peripheral and must go through the I/O map - - VAX Q22 systems - the Rp/RM must go through the I/O map + - PDP-11 Unibus without native 22b controllers - the RP/RM behaves + as an 18b Unibus peripheral and must go through the I/O map + - VAX Q22 systems - the RP/RM must go through the I/O map To distinguish the two Unibus cases, the PDP-11 version of the RP/RM provides an internal mode flag for RH11 vs RH70 @@ -92,18 +95,17 @@ #define RP_RDX 16 #define RP_WID 32 #define DMASK 0xFFFF -#define RH_18B FALSE /* always 22b */ +#define RH11 0 /* always 22b */ #else /* PDP11 version */ #include "pdp11_defs.h" #define VM_PDP11 1 #define RP_RDX 8 -#define RP_WID 16 /* off by default */ -#define RH_18B (cpu_18b || (cpu_ubm && cpu_rh11)) +#define RP_WID 16 +#define RH (cpu_18b || (cpu_ubm && cpu_rh11)) +#define RH11 (RH) extern uint16 *M; extern int32 cpu_18b, cpu_ubm, cpu_rh11; -extern int32 cpu_log; -extern FILE *sim_log; #endif #include @@ -120,11 +122,10 @@ extern FILE *sim_log; #define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */ #define UNIT_M_DTYPE 7 #define UNIT_V_AUTO (UNIT_V_UF + 4) /* autosize */ +#define UNIT_V_DUMMY (UNIT_V_UF + 5) /* dummy flag */ #define UNIT_WLK (1 << UNIT_V_WLK) #define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE) #define UNIT_AUTO (1 << UNIT_V_AUTO) -#define UNIT_W_UF 6 /* user flags width */ -#define UNIT_V_DUMMY (UNIT_V_UF + UNIT_W_UF) /* dummy flag */ #define UNIT_DUMMY (1 << UNIT_V_DUMMY) #define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE) #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */ @@ -366,6 +367,10 @@ static struct drvtyp drv_tab[] = { { 0 } }; extern int32 int_req[IPL_HLVL]; +extern int32 int_vec[IPL_HLVL][32]; +extern int32 cpu_log; +extern FILE *sim_log; + uint16 *rpxb = NULL; /* xfer buffer */ int32 rpcs1 = 0; /* control/status 1 */ int32 rpwc = 0; /* word count */ @@ -388,15 +393,17 @@ int32 rpiff = 0; /* INTR flip/flop */ int32 rp_stopioe = 1; /* stop on error */ int32 rp_swait = 10; /* seek time */ int32 rp_rwait = 10; /* rotate time */ -int reg_in_drive[32] = { +static int reg_in_drive[32] = { 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +DEVICE rp_dev; t_stat rp_rd (int32 *data, int32 PA, int32 access); t_stat rp_wr (int32 data, int32 PA, int32 access); +int32 rp_inta (void); t_stat rp_svc (UNIT *uptr); t_stat rp_reset (DEVICE *dptr); -t_stat rp_boot (int32 unitno); +t_stat rp_boot (int32 unitno, DEVICE *dptr); t_stat rp_attach (UNIT *uptr, char *cptr); t_stat rp_detach (UNIT *uptr); void update_rpcs (int32 flags, int32 drv); @@ -413,7 +420,8 @@ extern t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds); rp_mod RP modifier list */ -DIB rp_dib = { 1, IOBA_RP, IOLN_RP, &rp_rd, &rp_wr }; +DIB rp_dib = { IOBA_RP, IOLN_RP, &rp_rd, &rp_wr, + 1, IVCL (RP), VEC_RP, { &rp_inta } }; UNIT rp_unit[] = { { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ @@ -460,13 +468,11 @@ REG rp_reg[] = { { DRDATA (RTIME, rp_rwait, 24), REG_NZ + PV_LEFT }, { URDATA (FNC, rp_unit[0].FUNC, RP_RDX, 5, 0, RP_NUMDR, REG_HRO) }, - { URDATA (FLG, rp_unit[0].flags, RP_RDX, UNIT_W_UF, UNIT_V_UF - 1, - RP_NUMDR, REG_HRO) }, { URDATA (CAPAC, rp_unit[0].capac, 10, 31, 0, RP_NUMDR, PV_LEFT | REG_HRO) }, { FLDATA (STOP_IOE, rp_stopioe, 0) }, { GRDATA (DEVADDR, rp_dib.ba, RP_RDX, 32, 0), REG_HRO }, - { FLDATA (*DEVENB, rp_dib.enb, 0), REG_HRO }, + { GRDATA (DEVVEC, rp_dib.vec, RP_RDX, 16, 0), REG_HRO }, { NULL } }; MTAB rp_mod[] = { @@ -512,18 +518,17 @@ MTAB rp_mod[] = { { (UNIT_AUTO+UNIT_DTYPE), (RP07_DTYPE << UNIT_V_DTYPE), NULL, "RP07", &rp_set_size }, { MTAB_XTD|MTAB_VDV, 0100, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, &rp_dib }, - { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", - &set_enbdis, NULL, &rp_dib }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", - &set_enbdis, NULL, &rp_dib }, + &set_addr, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + &set_vec, &show_vec, NULL }, { 0 } }; DEVICE rp_dev = { "RP", rp_unit, rp_reg, rp_mod, RP_NUMDR, RP_RDX, 30, 1, RP_RDX, RP_WID, NULL, NULL, &rp_reset, - &rp_boot, &rp_attach, &rp_detach }; + &rp_boot, &rp_attach, &rp_detach, + &rp_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS }; /* I/O dispatch routines, I/O addresses 17776700 - 17776776 */ @@ -605,11 +610,11 @@ case 023: /* RPEC2 */ *data = rpec2; break; case 024: /* RPBAE */ - if (RH_18B) return SCPE_NXM; /* not in RH11 */ + if (RH11) return SCPE_NXM; /* not in RH11 */ *data = rpbae = rpbae & ~AE_MBZ; break; case 025: /* RPCS3 */ - if (RH_18B) return SCPE_NXM; /* not in RH11 */ + if (RH11) return SCPE_NXM; /* not in RH11 */ *data = rpcs3 = (rpcs3 & ~(CS1_IE | CS3_MBZ)) | (rpcs1 & CS1_IE); break; default: /* all others */ @@ -650,17 +655,17 @@ case 000: /* RPCS1 */ if ((data & CS1_DONE) && (data & CS1_IE)) /* to DONE+IE? */ rpiff = 1; /* set CSTB INTR */ rpcs1 = (rpcs1 & ~CS1_IE) | (data & CS1_IE); - if (uptr -> flags & UNIT_DIS) { /* nx disk? */ + if (uptr->flags & UNIT_DIS) { /* nx disk? */ rpcs2 = rpcs2 | CS2_NED; /* set error flag */ cs1f = CS1_SC; } /* req interrupt */ else if (sim_is_active (uptr)) rper1[drv] = rper1[drv] | ER1_RMR; /* won't write */ else if (data & CS1_GO) { /* start op */ - uptr -> FUNC = GET_FNC (data); /* set func */ - if ((uptr -> FUNC >= FNC_XFER) && /* data xfer and */ - ((rpcs1 & CS1_DONE) == 0)) /* ~rdy? PGE */ + uptr->FUNC = GET_FNC (data); /* set func */ + if ((uptr->FUNC >= FNC_XFER) && /* data xfer and */ + ((rpcs1 & CS1_DONE) == 0)) /* ~rdy? PGE */ rpcs2 = rpcs2 | CS2_PGE; - else rp_go (drv, uptr -> FUNC); } } + else rp_go (drv, uptr->FUNC); } } rpcs3 = (rpcs3 & ~CS1_IE) | (rpcs1 & CS1_IE); rpbae = (rpbae & ~CS1_M_UAE) | ((rpcs1 >> CS1_V_UAE) & CS1_M_UAE); break; @@ -719,13 +724,13 @@ case 016: /* RPDC */ rpdc = data & ~DC_MBZ; break; case 024: /* RPBAE */ - if (RH_18B) return SCPE_NXM; /* not in RH11 */ + if (RH11) return SCPE_NXM; /* not in RH11 */ if ((access == WRITEB) && (PA & 1)) break; rpbae = data & ~AE_MBZ; rpcs1 = (rpcs1 & ~CS1_UAE) | ((rpbae << CS1_V_UAE) & CS1_UAE); break; case 025: /* RPCS3 */ - if (RH_18B) return SCPE_NXM; /* not in RH11 */ + if (RH11) return SCPE_NXM; /* not in RH11 */ if ((access == WRITEB) && (PA & 1)) break; rpcs3 = data & ~CS3_MBZ; rpcs1 = (rpcs1 & ~CS1_IE) | (rpcs3 & CS1_IE); @@ -759,7 +764,7 @@ if (DBG_LOG (LOG_RP)) fprintf (sim_log, ">>RP%d: fnc=%o, ds=%o, cyl=%o, da=%o, ba=%o, wc=%o\n", drv, fnc, rpds[drv], rpdc, rpda, (rpbae << 16) | rpba, rpwc); uptr = rp_dev.units + drv; /* get unit */ -if (uptr -> flags & UNIT_DIS) { /* nx unit? */ +if (uptr->flags & UNIT_DIS) { /* nx unit? */ rpcs2 = rpcs2 | CS2_NED; /* set error flag */ update_rpcs (CS1_SC, drv); /* request intr */ return; } @@ -768,7 +773,7 @@ if ((fnc != FNC_DCLR) && (rpds[drv] & DS_ERR)) { /* err & ~clear? */ rpds[drv] = rpds[drv] | DS_ATA; /* set attention */ update_rpcs (CS1_SC, drv); /* request intr */ return; } -dtype = GET_DTYPE (uptr -> flags); /* get drive type */ +dtype = GET_DTYPE (uptr->flags); /* get drive type */ rpds[drv] = rpds[drv] & ~DS_ATA; /* clear attention */ dc = rpdc; /* assume seek, sch */ @@ -790,7 +795,7 @@ case FNC_PACK: /* pack acknowledge */ case FNC_OFFSET: /* offset mode */ case FNC_RETURN: - if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */ + if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */ break; } rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */ @@ -802,7 +807,7 @@ case FNC_RECAL: /* recalibrate */ dc = 0; /* seek to 0 */ case FNC_SEEK: /* seek */ case FNC_SEARCH: /* search */ - if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */ + if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */ break; } if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */ @@ -811,10 +816,10 @@ case FNC_SEARCH: /* search */ rper1[drv] = rper1[drv] | ER1_IAE; break; } rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */ - t = abs (dc - uptr -> CYL); /* cyl diff */ + t = abs (dc - uptr->CYL); /* cyl diff */ if (t == 0) t = 1; /* min time */ sim_activate (uptr, rp_swait * t); /* schedule */ - uptr -> CYL = dc; /* save cylinder */ + uptr->CYL = dc; /* save cylinder */ return; case FNC_WRITEH: /* write headers */ @@ -822,7 +827,7 @@ case FNC_WRITE: /* write */ case FNC_WCHK: /* write check */ case FNC_READ: /* read */ case FNC_READH: /* read headers */ - if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */ + if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ rper1[drv] = rper1[drv] | ER1_UNS; /* unsafe */ break; } rpcs2 = rpcs2 & ~CS2_ERR; /* clear errors */ @@ -833,8 +838,8 @@ case FNC_READH: /* read headers */ rper1[drv] = rper1[drv] | ER1_IAE; break; } rpds[drv] = rpds[drv] & ~DS_RDY; /* clear drive rdy */ - sim_activate (uptr, rp_rwait + (rp_swait * abs (dc - uptr -> CYL))); - uptr -> CYL = dc; /* save cylinder */ + sim_activate (uptr, rp_rwait + (rp_swait * abs (dc - uptr->CYL))); + uptr->CYL = dc; /* save cylinder */ return; default: /* all others */ @@ -859,13 +864,12 @@ int32 i, t, dtype, drv, err; int32 wc, awc, da; t_addr ba; uint16 comp; -int32 ub = RH_18B; -dtype = GET_DTYPE (uptr -> flags); /* get drive type */ +dtype = GET_DTYPE (uptr->flags); /* get drive type */ drv = uptr - rp_dev.units; /* get drv number */ rpds[drv] = (rpds[drv] & ~DS_PIP) | DS_RDY; /* change drive status */ -switch (uptr -> FUNC) { /* case on function */ +switch (uptr->FUNC) { /* case on function */ case FNC_OFFSET: /* offset */ rpds[drv] = rpds[drv] | DS_OF | DS_ATA; /* set offset, attention */ update_rpcs (CS1_SC, drv); @@ -885,7 +889,7 @@ case FNC_SEEK: /* seek */ break; case FNC_WRITE: /* write */ - if (uptr -> flags & UNIT_WPRT) { /* write locked? */ + if (uptr->flags & UNIT_WPRT) { /* write locked? */ rper1[drv] = rper1[drv] | ER1_WLE; /* set drive error */ update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */ break; } @@ -903,46 +907,46 @@ case FNC_READH: /* read headers */ update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */ break; } } - err = fseek (uptr -> fileref, da * sizeof (int16), SEEK_SET); - if (uptr -> FUNC == FNC_WRITE) { /* write? */ + err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET); + if (uptr->FUNC == FNC_WRITE) { /* write? */ if (rpcs2 & CS2_UAI) { /* no addr inc? */ - if (t = Map_ReadW (ba, 2, &comp, ub)) { /* get 1st wd */ + if (t = Map_ReadW (ba, 2, &comp, RH)) { /* get 1st wd */ wc = 0; /* NXM, no xfr */ rpcs2 = rpcs2 | CS2_NEM; } /* set nxm err */ for (i = 0; i < wc; i++) rpxb[i] = comp; } else { /* normal */ - if (t = Map_ReadW (ba, wc << 1, rpxb, ub)) { /* get buf */ + if (t = Map_ReadW (ba, wc << 1, rpxb, RH)) { /* get buf */ wc = wc - (t >> 1); /* NXM, adj wc */ rpcs2 = rpcs2 | CS2_NEM; } /* set nxm err */ ba = ba + (wc << 1); } /* adv ba */ awc = (wc + (RP_NUMWD - 1)) & ~(RP_NUMWD - 1); for (i = wc; i < awc; i++) rpxb[i] = 0; /* fill buf */ if (wc && !err) { /* write buf */ - fxwrite (rpxb, sizeof (uint16), wc, uptr -> fileref); - err = ferror (uptr -> fileref); } + fxwrite (rpxb, sizeof (uint16), wc, uptr->fileref); + err = ferror (uptr->fileref); } } /* end if wr */ - else if ((uptr -> FUNC == FNC_READ) || /* read? */ - (uptr -> FUNC == FNC_READH)) { - i = fxread (rpxb, sizeof (uint16), wc, uptr -> fileref); - err = ferror (uptr -> fileref); + else if ((uptr->FUNC == FNC_READ) || /* read? */ + (uptr->FUNC == FNC_READH)) { + i = fxread (rpxb, sizeof (uint16), wc, uptr->fileref); + err = ferror (uptr->fileref); for ( ; i < wc; i++) rpxb[i] = 0; /* fill buf */ if (rpcs2 & CS2_UAI) { /* no addr inc? */ - if (t = Map_WriteW (ba, 2, &rpxb[wc - 1], ub)) { + if (t = Map_WriteW (ba, 2, &rpxb[wc - 1], RH)) { wc = 0; /* NXM, no xfr */ rpcs2 = rpcs2 | CS2_NEM; } } /* set nxm err */ else { /* normal */ - if (t = Map_WriteW (ba, wc << 1, rpxb, ub)) { /* put buf */ + if (t = Map_WriteW (ba, wc << 1, rpxb, RH)) { /* put buf */ wc = wc - (t >> 1); /* NXM, adj wc */ rpcs2 = rpcs2 | CS2_NEM; } /* set nxm err */ ba = ba + (wc << 1); } /* adv ba */ } /* end if read */ else { /* wchk */ - i = fxread (rpxb, sizeof (uint16), wc, uptr -> fileref); - err = ferror (uptr -> fileref); + i = fxread (rpxb, sizeof (uint16), wc, uptr->fileref); + err = ferror (uptr->fileref); for ( ; i < wc; i++) rpxb[i] = 0; /* fill buf */ awc = wc; for (wc = 0; wc < awc; wc++) { /* loop thru buf */ - if (Map_ReadW (ba, 2, &comp, ub)) { /* read word */ + if (Map_ReadW (ba, 2, &comp, RH)) { /* read word */ rpcs2 = rpcs2 | CS2_NEM; /* set error */ break; } if (comp != rpxb[wc]) { /* compare wd */ @@ -967,7 +971,7 @@ case FNC_READH: /* read headers */ rper1[drv] = rper1[drv] | ER1_PAR; /* set drive error */ update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */ perror ("RP I/O error"); - clearerr (uptr -> fileref); + clearerr (uptr->fileref); return SCPE_IOERR; } case FNC_WRITEH: /* write headers stub */ update_rpcs (CS1_DONE, drv); /* set done */ @@ -999,7 +1003,7 @@ if (rper1[drv] | rper2 | rper3) rpds[drv] = rpds[drv] | DS_ERR | DS_ATA; else rpds[drv] = rpds[drv] & ~DS_ERR; rpcs1 = (rpcs1 & ~(CS1_SC | CS1_MCPE | CS1_MBZ | CS1_DRV)) | CS1_DVA | flag; -rpcs1 = rpcs1 | (uptr -> FUNC << CS1_V_FNC); +rpcs1 = rpcs1 | (uptr->FUNC << CS1_V_FNC); if (sim_is_active (uptr)) rpcs1 = rpcs1 | CS1_GO; if (rpcs2 & CS2_ERR) rpcs1 = rpcs1 | CS1_TRE | CS1_SC; else if (rpcs1 & CS1_TRE) rpcs1 = rpcs1 | CS1_SC; @@ -1018,7 +1022,7 @@ int32 rp_inta (void) rpcs1 = rpcs1 & ~CS1_IE; /* clear int enable */ rpcs3 = rpcs3 & ~CS1_IE; /* in both registers */ rpiff = 0; /* clear CSTB INTR */ -return VEC_RP; /* acknowledge */ +return rp_dib.vec; /* acknowledge */ } /* Device reset */ @@ -1040,10 +1044,10 @@ CLR_INT (RP); /* clear intr req */ for (i = 0; i < RP_NUMDR; i++) { uptr = rp_dev.units + i; sim_cancel (uptr); - uptr -> CYL = uptr -> FUNC = 0; - if (uptr -> flags & UNIT_ATT) rpds[i] = (rpds[i] & DS_VV) | - DS_DPR | DS_RDY | DS_MOL | ((uptr -> flags & UNIT_WPRT)? DS_WRL: 0); - else if (uptr -> flags & UNIT_DIS) rpds[i] = 0; + uptr->CYL = uptr->FUNC = 0; + if (uptr->flags & UNIT_ATT) rpds[i] = (rpds[i] & DS_VV) | + DS_DPR | DS_RDY | DS_MOL | ((uptr->flags & UNIT_WPRT)? DS_WRL: 0); + else if (uptr->flags & UNIT_DIS) rpds[i] = 0; else rpds[i] = DS_DPR; rper1[i] = 0; } if (rpxb == NULL) rpxb = calloc (RP_MAXFR, sizeof (unsigned int16)); @@ -1058,25 +1062,25 @@ t_stat rp_attach (UNIT *uptr, char *cptr) int drv, i, p; t_stat r; -uptr -> capac = drv_tab[GET_DTYPE (uptr -> flags)].size; +uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size; r = attach_unit (uptr, cptr); if (r != SCPE_OK) return r; drv = uptr - rp_dev.units; /* get drv number */ rpds[drv] = DS_ATA | DS_MOL | DS_RDY | DS_DPR | - ((uptr -> flags & UNIT_WPRT)? DS_WRL: 0); + ((uptr->flags & UNIT_WPRT)? DS_WRL: 0); rper1[drv] = 0; update_rpcs (CS1_SC, drv); -if ((uptr -> flags & UNIT_AUTO) == 0) return SCPE_OK; /* autosize? */ -if (fseek (uptr -> fileref, 0, SEEK_END)) return SCPE_OK; -if ((p = ftell (uptr -> fileref)) == 0) { - if (uptr -> flags & UNIT_RO) return SCPE_OK; +if ((uptr->flags & UNIT_AUTO) == 0) return SCPE_OK; /* autosize? */ +if (fseek (uptr->fileref, 0, SEEK_END)) return SCPE_OK; +if ((p = ftell (uptr->fileref)) == 0) { + if (uptr->flags & UNIT_RO) return SCPE_OK; return pdp11_bad_block (uptr, - drv_tab[GET_DTYPE (uptr -> flags)].sect, RP_NUMWD); } + drv_tab[GET_DTYPE (uptr->flags)].sect, RP_NUMWD); } for (i = 0; drv_tab[i].sect != 0; i++) { if (p <= (drv_tab[i].size * (int) sizeof (int16))) { - uptr -> flags = (uptr -> flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE); - uptr -> capac = drv_tab[i].size; + uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE); + uptr->capac = drv_tab[i].size; return SCPE_OK; } } return SCPE_OK; } @@ -1093,7 +1097,7 @@ rpds[drv] = (rpds[drv] & ~(DS_MOL | DS_RDY | DS_WRL | DS_VV | DS_OF)) | if (sim_is_active (uptr)) { /* unit active? */ sim_cancel (uptr); /* cancel operation */ rper1[drv] = rper1[drv] | ER1_OPI; /* set drive error */ - if (uptr -> FUNC >= FNC_WCHK) /* data transfer? */ + if (uptr->FUNC >= FNC_WCHK) /* data transfer? */ rpcs1 = rpcs1 | CS1_DONE | CS1_TRE; } /* set done, err */ update_rpcs (CS1_SC, drv); /* request intr */ return detach_unit (uptr); @@ -1103,8 +1107,8 @@ return detach_unit (uptr); t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { -if (uptr -> flags & UNIT_ATT) return SCPE_ALATT; -uptr -> capac = drv_tab[GET_DTYPE (val)].size; +if (uptr->flags & UNIT_ATT) return SCPE_ALATT; +uptr->capac = drv_tab[GET_DTYPE (val)].size; return SCPE_OK; } @@ -1112,7 +1116,7 @@ return SCPE_OK; t_stat rp_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc) { -return pdp11_bad_block (uptr, drv_tab[GET_DTYPE (uptr -> flags)].sect, RP_NUMWD); +return pdp11_bad_block (uptr, drv_tab[GET_DTYPE (uptr->flags)].sect, RP_NUMWD); } /* Device bootstrap */ @@ -1120,49 +1124,50 @@ return pdp11_bad_block (uptr, drv_tab[GET_DTYPE (uptr -> flags)].sect, RP_NUMWD) #if defined (VM_PDP11) #define BOOT_START 02000 /* start */ -#define BOOT_ENTRY 02002 -#define BOOT_UNIT 02010 /* unit number */ -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) +#define BOOT_ENTRY (BOOT_START + 002) /* entry */ +#define BOOT_UNIT (BOOT_START + 010) /* unit number */ +#define BOOT_CSR (BOOT_START + 014) /* CSR */ +#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) -static const int32 boot_rom[] = { +static const uint16 boot_rom[] = { 0042102, /* "DB" */ - 0012706, 0002000, /* mov #2000, sp */ + 0012706, BOOT_START, /* mov #boot_start, sp */ 0012700, 0000000, /* mov #unit, r0 */ 0012701, 0176700, /* mov #RPCS1, r1 */ - 0012737, 0000040, 0176710, /* mov #CS2_CLR, RPCS2 */ - 0010037, 0176710, /* mov r0, RPCS2 */ - 0012711, 0000021, /* mov #RIP+GO, (R1) */ - 0012737, 0010000, 0176732, /* mov #FMT16B, RPOF */ -/* 0005037, 0176750, /* clr RPBAE */ - 0005037, 0176704, /* clr RPBA */ - 0005037, 0176734, /* clr RPDC */ - 0005037, 0176706, /* clr RPDA */ - 0012737, 0177000, 0176702, /* mov #-512., RPWC */ - 0012711, 0000071, /* mov #READ+GO, (R1) */ + 0012761, 0000040, 0000010, /* mov #CS2_CLR, 10(r1) ; reset */ + 0010061, 0000010, /* mov r0, 10(r1) ; set unit */ + 0012711, 0000021, /* mov #RIP+GO, (r1) ; pack ack */ + 0012761, 0010000, 0000032, /* mov #FMT16B, 32(r1) ; 16b mode */ + 0012761, 0177000, 0000002, /* mov #-512., 2(r1) ; set wc */ + 0005061, 0000004, /* clr 4(r1) ; clr ba */ + 0005061, 0000006, /* clr 6(r1) ; clr da */ + 0005061, 0000034, /* clr 34(r1) ; clr cyl */ + 0012711, 0000071, /* mov #READ+GO, (r1) ; read */ + 0105711, /* tstb (r1) ; wait */ + 0100376, /* bpl .-2 */ 0005002, /* clr R2 */ 0005003, /* clr R3 */ 0012704, BOOT_START+020, /* mov #start+020, r4 */ 0005005, /* clr R5 */ - 0105711, /* tstb (R1) */ - 0100376, /* bpl .-2 */ - 0105011, /* clrb (R1) */ + 0105011, /* clrb (r1) */ 0005007 /* clr PC */ }; -t_stat rp_boot (int32 unitno) +t_stat rp_boot (int32 unitno, DEVICE *dptr) { int32 i; extern int32 saved_PC; for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i]; M[BOOT_UNIT >> 1] = unitno & CS2_M_UNIT; +M[BOOT_CSR >> 1] = rp_dib.ba & DMASK; saved_PC = BOOT_ENTRY; return SCPE_OK; } #else -t_stat rp_boot (int32 unitno) +t_stat rp_boot (int32 unitno, DEVICE *dptr) { return SCPE_NOFNC; } diff --git a/PDP11/pdp11_rq.c b/PDP11/pdp11_rq.c index c77e1068..d6b7951d 100644 --- a/PDP11/pdp11_rq.c +++ b/PDP11/pdp11_rq.c @@ -26,6 +26,14 @@ rq RQDX3 disk controller + 12-Oct-02 RMS Added multicontroller support + 29-Sep-02 RMS Changed addressing to 18b in Unibus mode + Added variable address support to bootstrap + Added vector display support + Fixed status code in HBE error log + Consolidated MSCP/TMSCP header file + New data structures + 16-Aug-02 RMS Removed unused variables (found by David Hittner) 04-May-02 RMS Fixed bug in polling loop for queued operations 26-Mar-02 RMS Fixed bug, reset routine cleared UF_WPH 09-Mar-02 RMS Adjusted delays for M+ timing bugs @@ -51,10 +59,19 @@ #define RQ_RDX 8 #define RQ_AINC 2 #define RQ_WID 16 +extern int32 cpu_18b, cpu_ubm; #endif -#include "dec_uqssp.h" -#include "dec_mscp.h" +#if !defined (RQ_NUMCT) +#define RQ_NUMCT 4 +#elif (RQ_NUMCT > 4) +Assertion failure: RQ_NUMCT exceeds 4 +#endif + +#include "pdp11_uqssp.h" +#include "pdp11_mscp.h" + +#define UF_MSK (UF_CMR|UF_CMW) /* settable flags */ #define RQ_SH_MAX 24 /* max display wds */ #define RQ_SH_PPL 8 /* wds per line */ @@ -65,7 +82,8 @@ #define RQ_SH_UN 010 /* show unit q's */ #define RQ_CLASS 1 /* RQ class */ -#define RQ_MODEL 19 /* RQ model */ +#define RQ_UQPM 19 /* UQ port model */ +#define RQ_MODEL 19 /* MSCP ctrl model */ #define RQ_HVER 1 /* hardware version */ #define RQ_SVER 3 /* software version */ #define RQ_DHTMO 60 /* def host timeout */ @@ -83,16 +101,16 @@ #define UNIT_WLK (1 << UNIT_V_WLK) #define UNIT_ATP (1 << UNIT_V_ATP) #define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE) -#define UNIT_W_UF 8 /* user flags width */ #define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE) #define cpkt u3 /* current packet */ #define pktq u4 /* packet queue */ #define uf buf /* settable unit flags */ +#define cnum wait /* controller index */ #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */ -#define RQ_RMV(u) ((drv_tab[GET_DTYPE (u -> flags)].flgs & RQDF_RMV)? \ +#define RQ_RMV(u) ((drv_tab[GET_DTYPE (u->flags)].flgs & RQDF_RMV)? \ UF_RMV: 0) -#define RQ_WPH(u) (((drv_tab[GET_DTYPE (u -> flags)].flgs & RQDF_RO) || \ - (u -> flags & UNIT_WPRT))? UF_WPH: 0) +#define RQ_WPH(u) (((drv_tab[GET_DTYPE (u->flags)].flgs & RQDF_RO) || \ + (u->flags & UNIT_WPRT))? UF_WPH: 0) #define CST_S1 0 /* init stage 1 */ #define CST_S1_WR 1 /* stage 1 wrap */ @@ -104,13 +122,11 @@ #define CST_UP 7 /* online */ #define CST_DEAD 8 /* fatal error */ -#define rq_comm rq_rq.ba - #define ERR 0 /* must be SCPE_OK! */ #define OK 1 -#define ER_NXM 0x1000 /* nxm err */ -#define ER_PTE 0x0400 /* pte err */ +#define RQ_TIMER (RQ_NUMDR) +#define RQ_QUEUE (RQ_TIMER + 1) /* Internal packet management. The real RQDX3 manages its packets as true linked lists. However, use of actual addresses in structures won't work @@ -129,13 +145,13 @@ struct rqpkt { int16 link; /* link to next */ uint16 d[RQ_PKT_SIZE_W]; }; /* data */ -/* Packet payload extraction and insertion */ +/* Packet payload extraction and insertion; cp defines controller */ -#define GETP(p,w,f) ((rq_pkt[p].d[w] >> w##_V_##f) & w##_M_##f) -#define GETP32(p,w) (((uint32) rq_pkt[p].d[w]) | \ - (((uint32) rq_pkt[p].d[(w)+1]) << 16)) -#define PUTP32(p,w,x) rq_pkt[p].d[w] = (x) & 0xFFFF; \ - rq_pkt[p].d[(w)+1] = ((x) >> 16) & 0xFFFF +#define GETP(p,w,f) ((cp->pak[p].d[w] >> w##_V_##f) & w##_M_##f) +#define GETP32(p,w) (((uint32) cp->pak[p].d[w]) | \ + (((uint32) cp->pak[p].d[(w)+1]) << 16)) +#define PUTP32(p,w,x) cp->pak[p].d[w] = (x) & 0xFFFF; \ + cp->pak[p].d[(w)+1] = ((x) >> 16) & 0xFFFF /* Disk formats. An RQDX3 consists of the following regions: @@ -424,28 +440,38 @@ extern UNIT cpu_unit; extern FILE *sim_log; uint16 *rqxb = NULL; /* xfer buffer */ -uint32 rq_sa = 0; /* status, addr */ -uint32 rq_saw = 0; /* written data */ -uint32 rq_s1dat = 0; /* S1 data */ -uint32 rq_csta = 0; /* ctrl state */ -uint32 rq_perr = 0; /* last error */ -uint32 rq_cflgs = 0; /* ctrl flags */ -uint32 rq_prgi = 0; /* purge int */ -uint32 rq_pip = 0; /* poll in progress */ -struct uq_ring rq_cq = { SA_COMM_CI }; /* cmd ring */ -struct uq_ring rq_rq = { SA_COMM_RI }; /* rsp ring */ -struct rqpkt rq_pkt[RQ_NPKTS]; /* packet queue */ -int32 rq_freq = 0; /* free list */ -int32 rq_rspq = 0; /* resp list */ -uint32 rq_pbsy = 0; /* #busy pkts */ -uint32 rq_credits = 0; /* credits */ -uint32 rq_hat = 0; /* host timer */ -uint32 rq_htmo = RQ_DHTMO; /* host timeout */ int32 rq_itime = 200; /* init time, except */ int32 rq_itime4 = 10; /* stage 4 */ int32 rq_qtime = 200; /* queue time */ int32 rq_xtime = 500; /* transfer time */ -int32 rq_enb = 1; /* device enable */ + +struct mscp_con { + uint32 cnum; /* ctrl number */ + uint32 ubase; /* unit base */ + uint32 sa; /* status, addr */ + uint32 saw; /* written data */ + uint32 s1dat; /* S1 data */ + uint32 comm; /* comm region */ + uint32 csta; /* ctrl state */ + uint32 perr; /* last error */ + uint32 cflgs; /* ctrl flags */ + uint32 irq; /* intr request */ + uint32 prgi; /* purge int */ + uint32 pip; /* poll in progress */ + int32 freq; /* free list */ + int32 rspq; /* resp list */ + uint32 pbsy; /* #busy pkts */ + uint32 credits; /* credits */ + uint32 hat; /* host timer */ + uint32 htmo; /* host timeout */ + struct uq_ring cq; /* cmd ring */ + struct uq_ring rq; /* rsp ring */ + struct rqpkt pak[RQ_NPKTS]; /* packet queue */ +}; + +#define MSC struct mscp_con /* MSCP ctrl context */ + +DEVICE rq_dev, rqb_dev, rqc_dev,rqd_dev; t_stat rq_rd (int32 *data, int32 PA, int32 access); t_stat rq_wr (int32 data, int32 PA, int32 access); @@ -455,45 +481,50 @@ t_stat rq_quesvc (UNIT *uptr); t_stat rq_reset (DEVICE *dptr); t_stat rq_attach (UNIT *uptr, char *cptr); t_stat rq_detach (UNIT *uptr); -t_stat rq_boot (int32 unitno); +t_stat rq_boot (int32 unitno, DEVICE *dptr); t_stat rq_set_wlk (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat rq_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat rq_show_wlk (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat rq_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat rq_show_unitq (FILE *st, UNIT *uptr, int32 val, void *desc); -t_bool rq_step4 (void); -t_bool rq_mscp (int32 pkt, t_bool q); -t_bool rq_abo (int32 pkt, t_bool q); -t_bool rq_avl (int32 pkt, t_bool q); -t_bool rq_fmt (int32 pkt, t_bool q); -t_bool rq_gcs (int32 pkt, t_bool q); -t_bool rq_gus (int32 pkt, t_bool q); -t_bool rq_onl (int32 pkt, t_bool q); -t_bool rq_rw (int32 pkt, t_bool q); -t_bool rq_scc (int32 pkt, t_bool q); -t_bool rq_suc (int32 pkt, t_bool q); -t_bool rq_plf (uint32 err); -t_bool rq_dte (UNIT *uptr, uint32 err); -t_bool rq_hbe (UNIT *uptr, uint32 err); -t_bool rq_una (UNIT *uptr); -t_bool rq_deqf (int32 *pkt); -int32 rq_deqh (int32 *lh); -void rq_enqh (int32 *lh, int32 pkt); -void rq_enqt (int32 *lh, int32 pkt); -t_bool rq_getpkt (int32 *pkt); -t_bool rq_putpkt (int32 pkt, t_bool qt); -t_bool rq_getdesc (struct uq_ring *ring, uint32 *desc); -t_bool rq_putdesc (struct uq_ring *ring, uint32 desc); -int32 rq_rw_valid (int32 pkt, UNIT *uptr, uint32 cmd); -t_bool rq_rw_end (UNIT *uptr, uint32 flg, uint32 sts); -void rq_putr (int32 pkt, uint32 cmd, uint32 flg, uint32 sts, uint32 lnt, uint32 typ); -void rq_putr_unit (int32 pkt, UNIT *uptr, uint32 lu, t_bool all); -void rq_setf_unit (int32 pkt, UNIT *uptr); -void rq_init_int (void); -void rq_ring_int (struct uq_ring *ring); -t_bool rq_fatal (uint32 err); -UNIT *rq_getucb (uint32 lu); +t_bool rq_step4 (MSC *cp); +t_bool rq_mscp (MSC *cp, int32 pkt, t_bool q); +t_bool rq_abo (MSC *cp, int32 pkt, t_bool q); +t_bool rq_avl (MSC *cp, int32 pkt, t_bool q); +t_bool rq_fmt (MSC *cp, int32 pkt, t_bool q); +t_bool rq_gcs (MSC *cp, int32 pkt, t_bool q); +t_bool rq_gus (MSC *cp, int32 pkt, t_bool q); +t_bool rq_onl (MSC *cp, int32 pkt, t_bool q); +t_bool rq_rw (MSC *cp, int32 pkt, t_bool q); +t_bool rq_scc (MSC *cp, int32 pkt, t_bool q); +t_bool rq_suc (MSC *cp, int32 pkt, t_bool q); +t_bool rq_plf (MSC *cp, uint32 err); +t_bool rq_dte (MSC *cp, UNIT *uptr, uint32 err); +t_bool rq_hbe (MSC *cp, UNIT *uptr); +t_bool rq_una (MSC *cp, int32 un); +t_bool rq_deqf (MSC *cp, int32 *pkt); +int32 rq_deqh (MSC *cp, int32 *lh); +void rq_enqh (MSC *cp, int32 *lh, int32 pkt); +void rq_enqt (MSC *cp, int32 *lh, int32 pkt); +t_bool rq_getpkt (MSC *cp, int32 *pkt); +t_bool rq_putpkt (MSC *cp, int32 pkt, t_bool qt); +t_bool rq_getdesc (MSC *cp, struct uq_ring *ring, uint32 *desc); +t_bool rq_putdesc (MSC *cp, struct uq_ring *ring, uint32 desc); +int32 rq_rw_valid (MSC *cp, int32 pkt, UNIT *uptr, uint32 cmd); +t_bool rq_rw_end (MSC *cp, UNIT *uptr, uint32 flg, uint32 sts); +void rq_putr (MSC *cp, int32 pkt, uint32 cmd, uint32 flg, + uint32 sts, uint32 lnt, uint32 typ); +void rq_putr_unit (MSC *cp, int32 pkt, UNIT *uptr, uint32 lu, t_bool all); +void rq_setf_unit (MSC *cp, int32 pkt, UNIT *uptr); +void rq_init_int (MSC *cp); +void rq_ring_int (MSC *cp, struct uq_ring *ring); +t_bool rq_fatal (MSC *cp, uint32 err); +UNIT *rq_getucb (MSC *cp, uint32 lu); +int32 rq_map_pa (uint32 pa); +void rq_setint (MSC *cp); +void rq_clrint (MSC *cp); +int32 rq_inta (void); /* RQ data structures @@ -503,7 +534,10 @@ UNIT *rq_getucb (uint32 lu); rq_mod RQ modifier list */ -DIB rq_dib = { 1, IOBA_RQ, IOLN_RQ, &rq_rd, &rq_wr }; +MSC rq_ctx = { 0 }; + +DIB rq_dib = { IOBA_RQ, IOLN_RQ, &rq_rd, &rq_wr, + 1, IVCL (RQ), 0, { &rq_inta } }; UNIT rq_unit[] = { { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ @@ -517,59 +551,56 @@ UNIT rq_unit[] = { { UDATA (&rq_tmrsvc, UNIT_DIS, 0) }, { UDATA (&rq_quesvc, UNIT_DIS, 0) } }; -#define RQ_TIMER (RQ_NUMDR) -#define RQ_QUEUE (RQ_TIMER + 1) - REG rq_reg[] = { - { GRDATA (SA, rq_sa, RQ_RDX, 16, 0) }, - { GRDATA (SAW, rq_sa, RQ_RDX, 16, 0) }, - { GRDATA (S1DAT, rq_s1dat, RQ_RDX, 16, 0) }, - { GRDATA (CQBA, rq_cq.ba, RQ_RDX, 22, 0) }, - { GRDATA (CQLNT, rq_cq.lnt, RQ_RDX, 8, 2), REG_NZ }, - { GRDATA (CQIDX, rq_cq.idx, RQ_RDX, 8, 2) }, - { GRDATA (RQBA, rq_rq.ba, RQ_RDX, 22, 0) }, - { GRDATA (RQLNT, rq_rq.lnt, RQ_RDX, 8, 2), REG_NZ }, - { GRDATA (RQIDX, rq_rq.idx, RQ_RDX, 8, 2) }, - { DRDATA (FREE, rq_freq, 5) }, - { DRDATA (RESP, rq_rspq, 5) }, - { DRDATA (PBSY, rq_pbsy, 5) }, - { GRDATA (CFLGS, rq_cflgs, RQ_RDX, 16, 0) }, - { GRDATA (CSTA, rq_csta, RQ_RDX, 4, 0) }, - { GRDATA (PERR, rq_perr, RQ_RDX, 9, 0) }, - { DRDATA (CRED, rq_credits, 5) }, - { DRDATA (HAT, rq_hat, 17) }, - { DRDATA (HTMO, rq_htmo, 17) }, + { GRDATA (SA, rq_ctx.sa, RQ_RDX, 16, 0) }, + { GRDATA (SAW, rq_ctx.saw, RQ_RDX, 16, 0) }, + { GRDATA (S1DAT, rq_ctx.s1dat, RQ_RDX, 16, 0) }, + { GRDATA (COMM, rq_ctx.comm, RQ_RDX, 22, 0) }, + { GRDATA (CQBA, rq_ctx.cq.ba, RQ_RDX, 22, 0) }, + { GRDATA (CQLNT, rq_ctx.cq.lnt, RQ_RDX, 8, 2), REG_NZ }, + { GRDATA (CQIDX, rq_ctx.cq.idx, RQ_RDX, 8, 2) }, + { GRDATA (RQBA, rq_ctx.rq.ba, RQ_RDX, 22, 0) }, + { GRDATA (RQLNT, rq_ctx.rq.lnt, RQ_RDX, 8, 2), REG_NZ }, + { GRDATA (RQIDX, rq_ctx.rq.idx, RQ_RDX, 8, 2) }, + { DRDATA (FREE, rq_ctx.freq, 5) }, + { DRDATA (RESP, rq_ctx.rspq, 5) }, + { DRDATA (PBSY, rq_ctx.pbsy, 5) }, + { GRDATA (CFLGS, rq_ctx.cflgs, RQ_RDX, 16, 0) }, + { GRDATA (CSTA, rq_ctx.csta, RQ_RDX, 4, 0) }, + { GRDATA (PERR, rq_ctx.perr, RQ_RDX, 9, 0) }, + { DRDATA (CRED, rq_ctx.credits, 5) }, + { DRDATA (HAT, rq_ctx.hat, 17) }, + { DRDATA (HTMO, rq_ctx.htmo, 17) }, + { FLDATA (PRGI, rq_ctx.prgi, 0), REG_HIDDEN }, + { FLDATA (PIP, rq_ctx.pip, 0), REG_HIDDEN }, + { FLDATA (INT, rq_ctx.irq, 0) }, + { DRDATA (ITIME, rq_itime, 24), PV_LEFT + REG_NZ }, + { DRDATA (I4TIME, rq_itime4, 24), PV_LEFT + REG_NZ }, + { DRDATA (QTIME, rq_qtime, 24), PV_LEFT + REG_NZ }, + { DRDATA (XTIME, rq_xtime, 24), PV_LEFT + REG_NZ }, + { BRDATA (PKTS, rq_ctx.pak, RQ_RDX, 16, RQ_NPKTS * (RQ_PKT_SIZE_W + 1)) }, { URDATA (CPKT, rq_unit[0].cpkt, 10, 5, 0, RQ_NUMDR, 0) }, { URDATA (PKTQ, rq_unit[0].pktq, 10, 5, 0, RQ_NUMDR, 0) }, { URDATA (UFLG, rq_unit[0].uf, RQ_RDX, 16, 0, RQ_NUMDR, 0) }, - { URDATA (SFLG, rq_unit[0].flags, RQ_RDX, UNIT_W_UF, UNIT_V_UF-1, - RQ_NUMDR, REG_HRO) }, - { FLDATA (PRGI, rq_prgi, 0), REG_HIDDEN }, - { FLDATA (PIP, rq_pip, 0), REG_HIDDEN }, - { FLDATA (INT, IREQ (RQ), INT_V_RQ) }, - { DRDATA (ITIME, rq_itime, 24), PV_LEFT + REG_NZ }, - { DRDATA (QTIME, rq_qtime, 24), PV_LEFT + REG_NZ }, - { DRDATA (XTIME, rq_xtime, 24), PV_LEFT + REG_NZ }, - { BRDATA (PKTS, rq_pkt, RQ_RDX, 16, RQ_NPKTS * (RQ_PKT_SIZE_W + 1)) }, { GRDATA (DEVADDR, rq_dib.ba, RQ_RDX, 32, 0), REG_HRO }, - { FLDATA (*DEVENB, rq_dib.enb, 0), REG_HRO }, + { GRDATA (DEVVEC, rq_dib.vec, RQ_RDX, 16, 0), REG_HRO }, { NULL } }; MTAB rq_mod[] = { { UNIT_WLK, 0, NULL, "WRITEENABLED", &rq_set_wlk }, { UNIT_WLK, UNIT_WLK, NULL, "LOCKED", &rq_set_wlk }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, RQ_SH_RI, "RINGS", NULL, - NULL, &rq_show_ctrl, NULL }, + NULL, &rq_show_ctrl, 0 }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, RQ_SH_FR, "FREEQ", NULL, - NULL, &rq_show_ctrl, NULL }, + NULL, &rq_show_ctrl, 0 }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, RQ_SH_RS, "RESPQ", NULL, - NULL, &rq_show_ctrl, NULL }, + NULL, &rq_show_ctrl, 0 }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, RQ_SH_UN, "UNITQ", NULL, - NULL, &rq_show_ctrl, NULL }, + NULL, &rq_show_ctrl, 0 }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, -1, "ALL", NULL, - NULL, &rq_show_ctrl, NULL }, + NULL, &rq_show_ctrl, 0 }, { MTAB_XTD | MTAB_VUN | MTAB_NMO, 0, "UNITQ", NULL, - NULL, &rq_show_unitq, NULL }, + NULL, &rq_show_unitq, 0 }, { MTAB_XTD | MTAB_VUN, 0, "WRITE", NULL, NULL, &rq_show_wlk, NULL }, { UNIT_DTYPE, (RX50_DTYPE << UNIT_V_DTYPE), "RX50", "RX50", &rq_set_size }, @@ -585,83 +616,314 @@ MTAB rq_mod[] = { { UNIT_DTYPE, (RA92_DTYPE << UNIT_V_DTYPE), "RA92", "RA92", &rq_set_size }, { UNIT_DTYPE, (RRD40_DTYPE << UNIT_V_DTYPE), "RRD40", "RRD40", &rq_set_size }, { UNIT_DTYPE, (RRD40_DTYPE << UNIT_V_DTYPE), NULL, "CDROM", &rq_set_size }, +#if defined (VM_PDP11) { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, &rq_dib }, - { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", - &set_enbdis, NULL, &rq_dib }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", - &set_enbdis, NULL, &rq_dib }, + &set_addr, &show_addr, NULL }, +#else + { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL, + NULL, &show_addr, NULL }, +#endif + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, + NULL, &show_vec, NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE", + &set_addr_flt, NULL, NULL }, { 0 } }; DEVICE rq_dev = { "RQ", rq_unit, rq_reg, rq_mod, RQ_NUMDR + 2, RQ_RDX, 31, RQ_AINC, RQ_RDX, RQ_WID, NULL, NULL, &rq_reset, - &rq_boot, &rq_attach, &rq_detach }; + &rq_boot, &rq_attach, &rq_detach, + &rq_dib, DEV_FLTA | DEV_DISABLE | DEV_UBUS | DEV_QBUS }; + +/* RQB data structures + + rqb_dev RQB device descriptor + rqb_unit RQB unit list + rqb_reg RQB register list + rqb_mod RQB modifier list +*/ + +MSC rqb_ctx = { 1 }; + +DIB rqb_dib = { IOBA_RQB, IOLN_RQB, &rq_rd, &rq_wr, + 1, IVCL (RQ), 0, { &rq_inta } }; + +UNIT rqb_unit[] = { + { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ + (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, + { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ + (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, + { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ + (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, + { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ + (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, + { UDATA (&rq_tmrsvc, UNIT_DIS, 0) }, + { UDATA (&rq_quesvc, UNIT_DIS, 0) } }; + +REG rqb_reg[] = { + { GRDATA (SA, rqb_ctx.sa, RQ_RDX, 16, 0) }, + { GRDATA (SAW, rqb_ctx.saw, RQ_RDX, 16, 0) }, + { GRDATA (S1DAT, rqb_ctx.s1dat, RQ_RDX, 16, 0) }, + { GRDATA (COMM, rqb_ctx.comm, RQ_RDX, 22, 0) }, + { GRDATA (CQBA, rqb_ctx.cq.ba, RQ_RDX, 22, 0) }, + { GRDATA (CQLNT, rqb_ctx.cq.lnt, RQ_RDX, 8, 2), REG_NZ }, + { GRDATA (CQIDX, rqb_ctx.cq.idx, RQ_RDX, 8, 2) }, + { GRDATA (RQBA, rqb_ctx.rq.ba, RQ_RDX, 22, 0) }, + { GRDATA (RQLNT, rqb_ctx.rq.lnt, RQ_RDX, 8, 2), REG_NZ }, + { GRDATA (RQIDX, rqb_ctx.rq.idx, RQ_RDX, 8, 2) }, + { DRDATA (FREE, rqb_ctx.freq, 5) }, + { DRDATA (RESP, rqb_ctx.rspq, 5) }, + { DRDATA (PBSY, rqb_ctx.pbsy, 5) }, + { GRDATA (CFLGS, rqb_ctx.cflgs, RQ_RDX, 16, 0) }, + { GRDATA (CSTA, rqb_ctx.csta, RQ_RDX, 4, 0) }, + { GRDATA (PERR, rqb_ctx.perr, RQ_RDX, 9, 0) }, + { DRDATA (CRED, rqb_ctx.credits, 5) }, + { DRDATA (HAT, rqb_ctx.hat, 17) }, + { DRDATA (HTMO, rqb_ctx.htmo, 17) }, + { FLDATA (PRGI, rqb_ctx.prgi, 0), REG_HIDDEN }, + { FLDATA (PIP, rqb_ctx.pip, 0), REG_HIDDEN }, + { FLDATA (INT, rqb_ctx.irq, 0) }, + { BRDATA (PKTS, rqb_ctx.pak, RQ_RDX, 16, RQ_NPKTS * (RQ_PKT_SIZE_W + 1)) }, + { URDATA (CPKT, rqb_unit[0].cpkt, 10, 5, 0, RQ_NUMDR, 0) }, + { URDATA (PKTQ, rqb_unit[0].pktq, 10, 5, 0, RQ_NUMDR, 0) }, + { URDATA (UFLG, rqb_unit[0].uf, RQ_RDX, 16, 0, RQ_NUMDR, 0) }, + { GRDATA (DEVADDR, rqb_dib.ba, RQ_RDX, 32, 0), REG_HRO }, + { GRDATA (DEVVEC, rqb_dib.vec, RQ_RDX, 16, 0), REG_HRO }, + { NULL } }; + +DEVICE rqb_dev = { + "RQB", rqb_unit, rqb_reg, rq_mod, + RQ_NUMDR + 2, RQ_RDX, 31, RQ_AINC, RQ_RDX, RQ_WID, + NULL, NULL, &rq_reset, + &rq_boot, &rq_attach, &rq_detach, + &rqb_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS }; + +/* RQC data structures + + rqc_dev RQC device descriptor + rqc_unit RQC unit list + rqc_reg RQC register list + rqc_mod RQC modifier list +*/ + +MSC rqc_ctx = { 2 }; + +DIB rqc_dib = { IOBA_RQC, IOLN_RQC, &rq_rd, &rq_wr, + 1, IVCL (RQ), 0, { &rq_inta } }; + +UNIT rqc_unit[] = { + { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ + (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, + { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ + (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, + { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ + (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, + { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ + (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, + { UDATA (&rq_tmrsvc, UNIT_DIS, 0) }, + { UDATA (&rq_quesvc, UNIT_DIS, 0) } }; + +REG rqc_reg[] = { + { GRDATA (SA, rqc_ctx.sa, RQ_RDX, 16, 0) }, + { GRDATA (SAW, rqc_ctx.saw, RQ_RDX, 16, 0) }, + { GRDATA (S1DAT, rqc_ctx.s1dat, RQ_RDX, 16, 0) }, + { GRDATA (COMM, rqc_ctx.comm, RQ_RDX, 22, 0) }, + { GRDATA (CQBA, rqc_ctx.cq.ba, RQ_RDX, 22, 0) }, + { GRDATA (CQLNT, rqc_ctx.cq.lnt, RQ_RDX, 8, 2), REG_NZ }, + { GRDATA (CQIDX, rqc_ctx.cq.idx, RQ_RDX, 8, 2) }, + { GRDATA (RQBA, rqc_ctx.rq.ba, RQ_RDX, 22, 0) }, + { GRDATA (RQLNT, rqc_ctx.rq.lnt, RQ_RDX, 8, 2), REG_NZ }, + { GRDATA (RQIDX, rqc_ctx.rq.idx, RQ_RDX, 8, 2) }, + { DRDATA (FREE, rqc_ctx.freq, 5) }, + { DRDATA (RESP, rqc_ctx.rspq, 5) }, + { DRDATA (PBSY, rqc_ctx.pbsy, 5) }, + { GRDATA (CFLGS, rqc_ctx.cflgs, RQ_RDX, 16, 0) }, + { GRDATA (CSTA, rqc_ctx.csta, RQ_RDX, 4, 0) }, + { GRDATA (PERR, rqc_ctx.perr, RQ_RDX, 9, 0) }, + { DRDATA (CRED, rqc_ctx.credits, 5) }, + { DRDATA (HAT, rqc_ctx.hat, 17) }, + { DRDATA (HTMO, rqc_ctx.htmo, 17) }, + { FLDATA (PRGI, rqc_ctx.prgi, 0), REG_HIDDEN }, + { FLDATA (PIP, rqc_ctx.pip, 0), REG_HIDDEN }, + { FLDATA (INT, rqc_ctx.irq, 0) }, + { BRDATA (PKTS, rqc_ctx.pak, RQ_RDX, 16, RQ_NPKTS * (RQ_PKT_SIZE_W + 1)) }, + { URDATA (CPKT, rqc_unit[0].cpkt, 10, 5, 0, RQ_NUMDR, 0) }, + { URDATA (PKTQ, rqc_unit[0].pktq, 10, 5, 0, RQ_NUMDR, 0) }, + { URDATA (UFLG, rqc_unit[0].uf, RQ_RDX, 16, 0, RQ_NUMDR, 0) }, + { GRDATA (DEVADDR, rqc_dib.ba, RQ_RDX, 32, 0), REG_HRO }, + { GRDATA (DEVVEC, rqc_dib.vec, RQ_RDX, 16, 0), REG_HRO }, + { NULL } }; + +DEVICE rqc_dev = { + "RQC", rqc_unit, rqc_reg, rq_mod, + RQ_NUMDR + 2, RQ_RDX, 31, RQ_AINC, RQ_RDX, RQ_WID, + NULL, NULL, &rq_reset, + &rq_boot, &rq_attach, &rq_detach, + &rqc_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS }; + +/* RQD data structures + + rqd_dev RQ device descriptor + rqd_unit RQ unit list + rqd_reg RQ register list + rqd_mod RQ modifier list +*/ + +MSC rqd_ctx = { 3 }; + +DIB rqd_dib = { IOBA_RQD, IOLN_RQD, &rq_rd, &rq_wr, + 1, IVCL (RQ), 0, { &rq_inta } }; + +UNIT rqd_unit[] = { + { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ + (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, + { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ + (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, + { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ + (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, + { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ + (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, + { UDATA (&rq_tmrsvc, UNIT_DIS, 0) }, + { UDATA (&rq_quesvc, UNIT_DIS, 0) } }; + +REG rqd_reg[] = { + { GRDATA (SA, rqd_ctx.sa, RQ_RDX, 16, 0) }, + { GRDATA (SAW, rqd_ctx.saw, RQ_RDX, 16, 0) }, + { GRDATA (S1DAT, rqd_ctx.s1dat, RQ_RDX, 16, 0) }, + { GRDATA (COMM, rqd_ctx.comm, RQ_RDX, 22, 0) }, + { GRDATA (CQBA, rqd_ctx.cq.ba, RQ_RDX, 22, 0) }, + { GRDATA (CQLNT, rqd_ctx.cq.lnt, RQ_RDX, 8, 2), REG_NZ }, + { GRDATA (CQIDX, rqd_ctx.cq.idx, RQ_RDX, 8, 2) }, + { GRDATA (RQBA, rqd_ctx.rq.ba, RQ_RDX, 22, 0) }, + { GRDATA (RQLNT, rqd_ctx.rq.lnt, RQ_RDX, 8, 2), REG_NZ }, + { GRDATA (RQIDX, rqd_ctx.rq.idx, RQ_RDX, 8, 2) }, + { DRDATA (FREE, rqd_ctx.freq, 5) }, + { DRDATA (RESP, rqd_ctx.rspq, 5) }, + { DRDATA (PBSY, rqd_ctx.pbsy, 5) }, + { GRDATA (CFLGS, rqd_ctx.cflgs, RQ_RDX, 16, 0) }, + { GRDATA (CSTA, rqd_ctx.csta, RQ_RDX, 4, 0) }, + { GRDATA (PERR, rqd_ctx.perr, RQ_RDX, 9, 0) }, + { DRDATA (CRED, rqd_ctx.credits, 5) }, + { DRDATA (HAT, rqd_ctx.hat, 17) }, + { DRDATA (HTMO, rqd_ctx.htmo, 17) }, + { FLDATA (PRGI, rqd_ctx.prgi, 0), REG_HIDDEN }, + { FLDATA (PIP, rqd_ctx.pip, 0), REG_HIDDEN }, + { FLDATA (INT, rqd_ctx.irq, 0) }, + { BRDATA (PKTS, rqd_ctx.pak, RQ_RDX, 16, RQ_NPKTS * (RQ_PKT_SIZE_W + 1)) }, + { URDATA (CPKT, rqd_unit[0].cpkt, 10, 5, 0, RQ_NUMDR, 0) }, + { URDATA (PKTQ, rqd_unit[0].pktq, 10, 5, 0, RQ_NUMDR, 0) }, + { URDATA (UFLG, rqd_unit[0].uf, RQ_RDX, 16, 0, RQ_NUMDR, 0) }, + { GRDATA (DEVADDR, rqd_dib.ba, RQ_RDX, 32, 0), REG_HRO }, + { GRDATA (DEVVEC, rqd_dib.vec, RQ_RDX, 16, 0), REG_HRO }, + { NULL } }; + +DEVICE rqd_dev = { + "RQD", rqd_unit, rqd_reg, rq_mod, + RQ_NUMDR + 2, RQ_RDX, 31, RQ_AINC, RQ_RDX, RQ_WID, + NULL, NULL, &rq_reset, + &rq_boot, &rq_attach, &rq_detach, + &rqd_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS }; + +static DEVICE *rq_devmap[RQ_NUMCT] = { + &rq_dev, &rqb_dev, &rqc_dev, &rqd_dev }; + +static MSC *rq_ctxmap[RQ_NUMCT] = { + &rq_ctx, &rqb_ctx, &rqc_ctx, &rqd_ctx }; /* I/O dispatch routine, I/O addresses 17772150 - 17772152 - 17772150 IP read/write - 17772152 SA read/write + base + 0 IP read/write + base + 2 SA read/write */ t_stat rq_rd (int32 *data, int32 PA, int32 access) { +int32 cidx = rq_map_pa ((uint32) PA); +MSC *cp = rq_ctxmap[cidx]; +DEVICE *dptr = rq_devmap[cidx]; + +if (cidx < 0) return SCPE_IERR; switch ((PA >> 1) & 01) { /* decode PA<1> */ case 0: /* IP */ *data = 0; /* reads zero */ - if (rq_csta == CST_S3_PPB) rq_step4 (); /* waiting for poll? */ - else if (rq_csta == CST_UP) { /* if up */ - rq_pip = 1; /* poll host */ - sim_activate (&rq_unit[RQ_QUEUE], rq_qtime); } + if (cp->csta == CST_S3_PPB) rq_step4 (cp); /* waiting for poll? */ + else if (cp->csta == CST_UP) { /* if up */ + cp->pip = 1; /* poll host */ + sim_activate (dptr->units + RQ_QUEUE, rq_qtime); } break; case 1: /* SA */ - *data = rq_sa; + *data = cp->sa; break; } return SCPE_OK; } t_stat rq_wr (int32 data, int32 PA, int32 access) { +int32 cidx = rq_map_pa ((uint32) PA); +MSC *cp = rq_ctxmap[cidx]; +DEVICE *dptr = rq_devmap[cidx]; + +if (cidx < 0) return SCPE_IERR; switch ((PA >> 1) & 01) { /* decode PA<1> */ case 0: /* IP */ - rq_reset (&rq_dev); /* init device */ - if (DBG_LOG (LOG_RQ)) fprintf (sim_log, ">>RQ: initialization started\n"); + rq_reset (rq_devmap[cidx]); /* init device */ + if (DBG_LOG (LOG_RQ)) fprintf (sim_log, + ">>RQ%c: initialization started\n", 'A' + cp->cnum); break; case 1: /* SA */ - rq_saw = data; - if (rq_csta < CST_S4) /* stages 1-3 */ - sim_activate (&rq_unit[RQ_QUEUE], rq_itime); - else if (rq_csta == CST_S4) /* stage 4 (fast) */ - sim_activate (&rq_unit[RQ_QUEUE], rq_itime4); + cp->saw = data; + if (cp->csta < CST_S4) /* stages 1-3 */ + sim_activate (dptr->units + RQ_QUEUE, rq_itime); + else if (cp->csta == CST_S4) /* stage 4 (fast) */ + sim_activate (dptr->units + RQ_QUEUE, rq_itime4); break; } return SCPE_OK; } +/* Map physical address to device context */ + +int32 rq_map_pa (uint32 pa) +{ +int32 i; +DEVICE *dptr; +DIB *dibp; + +for (i = 0; i < RQ_NUMCT; i++) { /* loop thru ctrls */ + dptr = rq_devmap[i]; /* get device */ + dibp = (DIB *) dptr->ctxt; /* get DIB */ + if ((pa >= dibp->ba) && /* in range? */ + (pa < (dibp->ba + dibp->lnt))) + return i; } /* return ctrl idx */ +return -1; +} + /* Transition to step 4 - init communications region */ -t_bool rq_step4 (void) +t_bool rq_step4 (MSC *cp) { int32 i, lnt; t_addr base; uint16 zero[SA_COMM_MAX >> 1]; -rq_rq.ba = rq_comm; /* set rsp q base */ -rq_rq.lnt = SA_S1H_RQ (rq_s1dat) << 2; /* get resp q len */ -rq_cq.ba = rq_comm + rq_rq.lnt; /* set cmd q base */ -rq_cq.lnt = SA_S1H_CQ (rq_s1dat) << 2; /* get cmd q len */ -rq_cq.idx = rq_rq.idx = 0; /* clear q idx's */ -if (rq_prgi) base = rq_comm + SA_COMM_QQ; -else base = rq_comm + SA_COMM_CI; -lnt = rq_comm + rq_cq.lnt + rq_rq.lnt - base; /* comm lnt */ +cp->rq.ioff = SA_COMM_RI; /* set intr offset */ +cp->rq.ba = cp->comm; /* set rsp q base */ +cp->rq.lnt = SA_S1H_RQ (cp->s1dat) << 2; /* get resp q len */ +cp->cq.ioff = SA_COMM_CI; /* set intr offset */ +cp->cq.ba = cp->comm + cp->rq.lnt; /* set cmd q base */ +cp->cq.lnt = SA_S1H_CQ (cp->s1dat) << 2; /* get cmd q len */ +cp->cq.idx = cp->rq.idx = 0; /* clear q idx's */ +if (cp->prgi) base = cp->comm + SA_COMM_QQ; +else base = cp->comm + SA_COMM_CI; +lnt = cp->comm + cp->cq.lnt + cp->rq.lnt - base; /* comm lnt */ if (lnt > SA_COMM_MAX) lnt = SA_COMM_MAX; /* paranoia */ for (i = 0; i < (lnt >> 1); i++) zero[i] = 0; /* clr buffer */ -if (Map_WriteW (base, lnt, zero, QB)) /* zero comm area */ - return rq_fatal (PE_QWE); /* error? */ -rq_sa = SA_S4 | (RQ_MODEL << SA_S4C_V_MOD) | /* send step 4 */ +if (Map_WriteW (base, lnt, zero, MAP)) /* zero comm area */ + return rq_fatal (cp, PE_QWE); /* error? */ +cp->sa = SA_S4 | (RQ_UQPM << SA_S4C_V_MOD) | /* send step 4 */ (RQ_SVER << SA_S4C_V_VER); -rq_csta = CST_S4; /* set step 4 */ -rq_init_int (); /* poke host */ +cp->csta = CST_S4; /* set step 4 */ +rq_init_int (cp); /* poke host */ return OK; } @@ -681,88 +943,94 @@ t_stat rq_quesvc (UNIT *uptr) { int32 i, cnid; int32 pkt = 0; +UNIT *nuptr; +MSC *cp = rq_ctxmap[uptr->cnum]; +DEVICE *dptr = rq_devmap[uptr->cnum]; +DIB *dibp = (DIB *) dptr->ctxt; -if (rq_csta < CST_UP) { /* still init? */ - switch (rq_csta) { /* controller state? */ +if (cp->csta < CST_UP) { /* still init? */ + switch (cp->csta) { /* controller state? */ case CST_S1: /* need S1 reply */ - if (rq_saw & SA_S1H_VL) { /* valid? */ - if (rq_saw & SA_S1H_WR) { /* wrap? */ - rq_sa = rq_saw; /* echo data */ - rq_csta = CST_S1_WR; } /* endless loop */ + if (cp->saw & SA_S1H_VL) { /* valid? */ + if (cp->saw & SA_S1H_WR) { /* wrap? */ + cp->sa = cp->saw; /* echo data */ + cp->csta = CST_S1_WR; } /* endless loop */ else { - rq_s1dat = rq_saw; /* save data */ - rq_sa = SA_S2 | SA_S2C_PT | SA_S2C_EC (rq_s1dat); - rq_csta = CST_S2; /* now in step 2 */ - rq_init_int (); } /* intr if req */ + cp->s1dat = cp->saw; /* save data */ + dibp->vec = VEC_Q + ((cp->s1dat & SA_S1H_VEC) << 2); + cp->sa = SA_S2 | SA_S2C_PT | SA_S2C_EC (cp->s1dat); + cp->csta = CST_S2; /* now in step 2 */ + rq_init_int (cp); } /* intr if req */ } /* end if valid */ break; case CST_S1_WR: /* wrap mode */ - rq_sa = rq_saw; /* echo data */ + cp->sa = cp->saw; /* echo data */ break; case CST_S2: /* need S2 reply */ - rq_comm = rq_saw & SA_S2H_CLO; /* get low addr */ - rq_prgi = rq_saw & SA_S2H_PI; /* get purge int */ - rq_sa = SA_S3 | SA_S3C_EC (rq_s1dat); - rq_csta = CST_S3; /* now in step 3 */ - rq_init_int (); /* intr if req */ + cp->comm = cp->saw & SA_S2H_CLO; /* get low addr */ + cp->prgi = cp->saw & SA_S2H_PI; /* get purge int */ + cp->sa = SA_S3 | SA_S3C_EC (cp->s1dat); + cp->csta = CST_S3; /* now in step 3 */ + rq_init_int (cp); /* intr if req */ break; case CST_S3: /* need S3 reply */ - rq_comm = ((rq_saw & SA_S3H_CHI) << 16) | rq_comm; - if (rq_saw & SA_S3H_PP) { /* purge/poll test? */ - rq_sa = 0; /* put 0 */ - rq_csta = CST_S3_PPA; } /* wait for 0 write */ - else rq_step4 (); /* send step 4 */ + cp->comm = ((cp->saw & SA_S3H_CHI) << 16) | cp->comm; + if (cp->saw & SA_S3H_PP) { /* purge/poll test? */ + cp->sa = 0; /* put 0 */ + cp->csta = CST_S3_PPA; } /* wait for 0 write */ + else rq_step4 (cp); /* send step 4 */ break; case CST_S3_PPA: /* need purge test */ - if (rq_saw) rq_fatal (PE_PPF); /* data not zero? */ - else rq_csta = CST_S3_PPB; /* wait for poll */ + if (cp->saw) rq_fatal (cp, PE_PPF); /* data not zero? */ + else cp->csta = CST_S3_PPB; /* wait for poll */ break; case CST_S4: /* need S4 reply */ - if (rq_saw & SA_S4H_GO) { /* go set? */ + if (cp->saw & SA_S4H_GO) { /* go set? */ if (DBG_LOG (LOG_RQ)) fprintf (sim_log, - ">>RQ: initialization complete\n"); - rq_csta = CST_UP; /* we're up */ - rq_sa = 0; /* clear SA */ - sim_activate (&rq_unit[RQ_TIMER], tmr_poll * clk_tps); - if ((rq_saw & SA_S4H_LF) && rq_perr) rq_plf (rq_perr); - rq_perr = 0; } + ">>RQ%c: initialization complete\n", 'A' + cp->cnum); + cp->csta = CST_UP; /* we're up */ + cp->sa = 0; /* clear SA */ + sim_activate (dptr->units + RQ_TIMER, tmr_poll * clk_tps); + if ((cp->saw & SA_S4H_LF) && cp->perr) rq_plf (cp, cp->perr); + cp->perr = 0; } break; } /* end switch */ return SCPE_OK; } /* end if */ -if (rq_pip) { /* polling? */ - if (!rq_getpkt (&pkt)) return SCPE_OK; /* get host pkt */ +if (cp->pip) { /* polling? */ + if (!rq_getpkt (cp, &pkt)) return SCPE_OK; /* get host pkt */ if (pkt) { /* got one? */ if (DBG_LOG (LOG_RQ)) { - fprintf (sim_log, ">>RQ: cmd=%04X, mod=%04X, unit=%d, ", - rq_pkt[pkt].d[CMD_OPC], rq_pkt[pkt].d[CMD_MOD], rq_pkt[pkt].d[CMD_UN]); + fprintf (sim_log, ">>RQ%c: cmd=%04X, mod=%04X, unit=%d, ", + 'A' + cp->cnum, cp->pak[pkt].d[CMD_OPC], + cp->pak[pkt].d[CMD_MOD], cp->pak[pkt].d[CMD_UN]); fprintf (sim_log, "bc=%04X%04X, ma=%04X%04X, lbn=%04X%04X\n", - rq_pkt[pkt].d[RW_BCH], rq_pkt[pkt].d[RW_BCL], - rq_pkt[pkt].d[RW_BAH], rq_pkt[pkt].d[RW_BAL], - rq_pkt[pkt].d[RW_LBNH], rq_pkt[pkt].d[RW_LBNL]); } + cp->pak[pkt].d[RW_BCH], cp->pak[pkt].d[RW_BCL], + cp->pak[pkt].d[RW_BAH], cp->pak[pkt].d[RW_BAL], + cp->pak[pkt].d[RW_LBNH], cp->pak[pkt].d[RW_LBNL]); } if (GETP (pkt, UQ_HCTC, TYP) != UQ_TYP_SEQ) /* seq packet? */ - return rq_fatal (PE_PIE); /* no, term thread */ + return rq_fatal (cp, PE_PIE); /* no, term thread */ cnid = GETP (pkt, UQ_HCTC, CID); /* get conn ID */ if (cnid == UQ_CID_MSCP) { /* MSCP packet? */ - if (!rq_mscp (pkt, TRUE)) return SCPE_OK; } /* proc, q non-seq */ + if (!rq_mscp (cp, pkt, TRUE)) return SCPE_OK; } /* proc, q non-seq */ else if (cnid == UQ_CID_DUP) { /* DUP packet? */ - rq_putr (pkt, OP_END, 0, ST_CMD | I_OPCD, RSP_LNT, UQ_TYP_SEQ); - if (!rq_putpkt (pkt, TRUE)) return SCPE_OK; } /* ill cmd */ - else return rq_fatal (PE_ICI); /* no, term thread */ + rq_putr (cp, pkt, OP_END, 0, ST_CMD | I_OPCD, RSP_LNT, UQ_TYP_SEQ); + if (!rq_putpkt (cp, pkt, TRUE)) return SCPE_OK; } /* ill cmd */ + else return rq_fatal (cp, PE_ICI); /* no, term thread */ } /* end if pkt */ - else rq_pip = 0; /* discontinue poll */ + else cp->pip = 0; /* discontinue poll */ } /* end if pip */ -if (!rq_pip) { /* not polling? */ +if (!cp->pip) { /* not polling? */ for (i = 0; i < RQ_NUMDR; i++) { /* chk unit q's */ - UNIT *nuptr = rq_dev.units + i; /* ptr to unit */ - if (nuptr -> cpkt || (nuptr -> pktq == 0)) continue; - pkt = rq_deqh (&nuptr -> pktq); /* get top of q */ - if (!rq_mscp (pkt, FALSE)) return SCPE_OK; } /* process */ + nuptr = dptr->units + i; /* ptr to unit */ + if (nuptr->cpkt || (nuptr->pktq == 0)) continue; + pkt = rq_deqh (cp, &nuptr->pktq); /* get top of q */ + if (!rq_mscp (cp, pkt, FALSE)) return SCPE_OK; } /* process */ } /* end if !pip */ -if (rq_rspq) { /* resp q? */ - pkt = rq_deqh (&rq_rspq); /* get top of q */ - if (!rq_putpkt (pkt, FALSE)) return SCPE_OK; /* send to hst */ +if (cp->rspq) { /* resp q? */ + pkt = rq_deqh (cp, &cp->rspq); /* get top of q */ + if (!rq_putpkt (cp, pkt, FALSE)) return SCPE_OK; /* send to hst */ } /* end if resp q */ -if (pkt) sim_activate (&rq_unit[RQ_QUEUE], rq_qtime); /* more to do? */ +if (pkt) sim_activate (uptr, rq_qtime); /* more to do? */ return SCPE_OK; /* done */ } @@ -772,49 +1040,51 @@ t_stat rq_tmrsvc (UNIT *uptr) { int32 i; UNIT *nuptr; +MSC *cp = rq_ctxmap[uptr->cnum]; +DEVICE *dptr = rq_devmap[uptr->cnum]; sim_activate (uptr, tmr_poll * clk_tps); /* reactivate */ for (i = 0; i < RQ_NUMDR; i++) { /* poll */ - nuptr = rq_dev.units + i; - if ((nuptr -> flags & UNIT_ATP) && /* ATN pending? */ - (nuptr -> flags & UNIT_ATT) && /* still online? */ - (rq_cflgs & CF_ATN)) { /* wanted? */ - if (!rq_una (nuptr)) return SCPE_OK; } - nuptr -> flags = nuptr -> flags & ~UNIT_ATP; } -if ((rq_hat > 0) && (--rq_hat == 0)) /* host timeout? */ - rq_fatal (PE_HAT); /* fatal err */ + nuptr = dptr->units + i; + if ((nuptr->flags & UNIT_ATP) && /* ATN pending? */ + (nuptr->flags & UNIT_ATT) && /* still online? */ + (cp->cflgs & CF_ATN)) { /* wanted? */ + if (!rq_una (cp, i)) return SCPE_OK; } + nuptr->flags = nuptr->flags & ~UNIT_ATP; } +if ((cp->hat > 0) && (--cp->hat == 0)) /* host timeout? */ + rq_fatal (cp, PE_HAT); /* fatal err */ return SCPE_OK; } /* MSCP packet handling */ -t_bool rq_mscp (int32 pkt, t_bool q) +t_bool rq_mscp (MSC *cp, int32 pkt, t_bool q) { uint32 sts, cmd = GETP (pkt, CMD_OPC, OPC); switch (cmd) { case OP_ABO: /* abort */ - return rq_abo (pkt, q); + return rq_abo (cp, pkt, q); case OP_AVL: /* avail */ - return rq_avl (pkt, q); + return rq_avl (cp, pkt, q); case OP_FMT: /* format */ - return rq_fmt (pkt, q); + return rq_fmt (cp, pkt, q); case OP_GCS: /* get cmd status */ - return rq_gcs (pkt, q); + return rq_gcs (cp, pkt, q); case OP_GUS: /* get unit status */ - return rq_gus (pkt, q); + return rq_gus (cp, pkt, q); case OP_ONL: /* online */ - return rq_onl (pkt, q); + return rq_onl (cp, pkt, q); case OP_SCC: /* set ctrl char */ - return rq_scc (pkt, q); + return rq_scc (cp, pkt, q); case OP_SUC: /* set unit char */ - return rq_suc (pkt, q); + return rq_suc (cp, pkt, q); case OP_ACC: /* access */ case OP_CMP: /* compare */ case OP_ERS: /* erase */ case OP_RD: /* read */ case OP_WR: /* write */ - return rq_rw (pkt, q); + return rq_rw (cp, pkt, q); case OP_CCD: /* nops */ case OP_DAP: case OP_FLU: @@ -825,301 +1095,306 @@ default: cmd = OP_END; /* set end op */ sts = ST_CMD | I_OPCD; /* ill op */ break; } -rq_putr (pkt, cmd, 0, sts, RSP_LNT, UQ_TYP_SEQ); -return rq_putpkt (pkt, TRUE); +rq_putr (cp, pkt, cmd, 0, sts, RSP_LNT, UQ_TYP_SEQ); +return rq_putpkt (cp, pkt, TRUE); } /* Abort a command - 1st parameter is ref # of cmd to abort */ -t_bool rq_abo (int32 pkt, t_bool q) +t_bool rq_abo (MSC *cp, int32 pkt, t_bool q) { -uint32 lu = rq_pkt[pkt].d[CMD_UN]; /* unit # */ +uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ uint32 ref = GETP32 (pkt, ABO_REFL); /* cmd ref # */ int32 tpkt, prv; UNIT *uptr; +DEVICE *dptr = rq_devmap[cp->cnum]; tpkt = 0; /* set no mtch */ -if (uptr = rq_getucb (lu)) { /* get unit */ - if (uptr -> cpkt && /* curr pkt? */ - (GETP32 (uptr -> cpkt, CMD_REFL) == ref)) { /* match ref? */ - tpkt = uptr -> cpkt; /* save match */ - uptr -> cpkt = 0; /* gonzo */ - sim_cancel (uptr); /* cancel unit */ - sim_activate (&rq_unit[RQ_QUEUE], rq_qtime); } - else if (uptr -> pktq && /* head of q? */ - (GETP32 (uptr -> pktq, CMD_REFL) == ref)) { /* match ref? */ - tpkt = uptr -> pktq; /* save match */ - uptr -> pktq = rq_pkt[tpkt].link; } /* unlink */ - else if (prv = uptr -> pktq) { /* srch pkt q */ - while (tpkt = rq_pkt[prv].link) { /* walk list */ - if (GETP32 (tpkt, RSP_REFL) == ref) { - rq_pkt[prv].link = rq_pkt[tpkt].link; /* unlink */ - break; } } } +if (uptr = rq_getucb (cp, lu)) { /* get unit */ + if (uptr->cpkt && /* curr pkt? */ + (GETP32 (uptr->cpkt, CMD_REFL) == ref)) { /* match ref? */ + tpkt = uptr->cpkt; /* save match */ + uptr->cpkt = 0; /* gonzo */ + sim_cancel (uptr); /* cancel unit */ + sim_activate (dptr->units + RQ_QUEUE, rq_qtime); } + else if (uptr->pktq && /* head of q? */ + (GETP32 (uptr->pktq, CMD_REFL) == ref)) { /* match ref? */ + tpkt = uptr->pktq; /* save match */ + uptr->pktq = cp->pak[tpkt].link; } /* unlink */ + else if (prv = uptr->pktq) { /* srch pkt q */ + while (tpkt = cp->pak[prv].link) { /* walk list */ + if (GETP32 (tpkt, RSP_REFL) == ref) { /* match? unlink */ + cp->pak[prv].link = cp->pak[tpkt].link; + break; } } } if (tpkt) { /* found target? */ - uint32 tcmd = GETP (tpkt, CMD_OPC, OPC); /* get opcode */ - rq_putr (tpkt, tcmd | OP_END, 0, ST_ABO, RSP_LNT, UQ_TYP_SEQ); - if (!rq_putpkt (tpkt, TRUE)) return ERR; } + uint32 tcmd = GETP (tpkt, CMD_OPC, OPC); /* get opcode */ + rq_putr (cp, tpkt, tcmd | OP_END, 0, ST_ABO, RSP_LNT, UQ_TYP_SEQ); + if (!rq_putpkt (cp, tpkt, TRUE)) return ERR; } } /* end if unit */ -rq_putr (pkt, cmd | OP_END, 0, ST_SUC, ABO_LNT, UQ_TYP_SEQ); -return rq_putpkt (pkt, TRUE); +rq_putr (cp, pkt, cmd | OP_END, 0, ST_SUC, ABO_LNT, UQ_TYP_SEQ); +return rq_putpkt (cp, pkt, TRUE); } /* Unit available - set unit status to available - defer if q'd cmds */ -t_bool rq_avl (int32 pkt, t_bool q) +t_bool rq_avl (MSC *cp, int32 pkt, t_bool q) { -uint32 lu = rq_pkt[pkt].d[CMD_UN]; /* unit # */ +uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ uint32 sts; UNIT *uptr; -if (uptr = rq_getucb (lu)) { /* unit exist? */ - if (q && uptr -> cpkt) { /* need to queue? */ - rq_enqt (&uptr -> pktq, pkt); /* do later */ - return OK; } - uptr -> flags = uptr -> flags & ~UNIT_ONL; /* not online */ - uptr -> uf = 0; /* clr flags */ +if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ + if (q && uptr->cpkt) { /* need to queue? */ + rq_enqt (cp, &uptr->pktq, pkt); /* do later */ + return OK; } + uptr->flags = uptr->flags & ~UNIT_ONL; /* not online */ + uptr->uf = 0; /* clr flags */ sts = ST_SUC; } /* success */ else sts = ST_OFL; /* offline */ -rq_putr (pkt, cmd | OP_END, 0, sts, AVL_LNT, UQ_TYP_SEQ); -return rq_putpkt (pkt, TRUE); +rq_putr (cp, pkt, cmd | OP_END, 0, sts, AVL_LNT, UQ_TYP_SEQ); +return rq_putpkt (cp, pkt, TRUE); } /* Get command status - only interested in active xfr cmd */ -t_bool rq_gcs (int32 pkt, t_bool q) +t_bool rq_gcs (MSC *cp, int32 pkt, t_bool q) { -uint32 lu = rq_pkt[pkt].d[CMD_UN]; /* unit # */ +uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ uint32 ref = GETP32 (pkt, GCS_REFL); /* ref # */ int32 tpkt; UNIT *uptr; -if ((uptr = rq_getucb (lu)) && /* valid lu? */ - (tpkt = uptr -> cpkt) && /* queued pkt? */ +if ((uptr = rq_getucb (cp, lu)) && /* valid lu? */ + (tpkt = uptr->cpkt) && /* queued pkt? */ (GETP32 (tpkt, CMD_REFL) == ref) && /* match ref? */ (GETP (tpkt, CMD_OPC, OPC) >= OP_ACC)) { /* rd/wr cmd? */ - rq_pkt[pkt].d[GCS_STSL] = rq_pkt[tpkt].d[RW_WBCL]; - rq_pkt[pkt].d[GCS_STSH] = rq_pkt[tpkt].d[RW_WBCH]; } -else rq_pkt[pkt].d[GCS_STSL] = rq_pkt[pkt].d[GCS_STSH] = 0; -rq_putr (pkt, cmd | OP_END, 0, ST_SUC, GCS_LNT, UQ_TYP_SEQ); -return rq_putpkt (pkt, TRUE); + cp->pak[pkt].d[GCS_STSL] = cp->pak[tpkt].d[RW_WBCL]; + cp->pak[pkt].d[GCS_STSH] = cp->pak[tpkt].d[RW_WBCH]; } +else { + cp->pak[pkt].d[GCS_STSL] = 0; /* return 0 */ + cp->pak[pkt].d[GCS_STSH] = 0; } +rq_putr (cp, pkt, cmd | OP_END, 0, ST_SUC, GCS_LNT, UQ_TYP_SEQ); +return rq_putpkt (cp, pkt, TRUE); } /* Get unit status */ -t_bool rq_gus (int32 pkt, t_bool q) +t_bool rq_gus (MSC *cp, int32 pkt, t_bool q) { -uint32 lu = rq_pkt[pkt].d[CMD_UN]; /* unit # */ +uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ uint32 dtyp, sts, rbpar; UNIT *uptr; -if (rq_pkt[pkt].d[CMD_MOD] & MD_NXU) { /* next unit? */ - if (lu >= RQ_NUMDR) { /* end of range? */ - lu = 0; /* reset to 0 */ - rq_pkt[pkt].d[RSP_UN] = lu; } } -if (uptr = rq_getucb (lu)) { /* unit exist? */ - if ((uptr -> flags & UNIT_ATT) == 0) /* not attached? */ - sts = ST_OFL | SB_OFL_NV; /* offl no vol */ - else if (uptr -> flags & UNIT_ONL) sts = ST_SUC; /* online */ +if (cp->pak[pkt].d[CMD_MOD] & MD_NXU) { /* next unit? */ + if (lu >= (cp->ubase + RQ_NUMDR)) { /* end of range? */ + lu = 0; /* reset to 0 */ + cp->pak[pkt].d[RSP_UN] = lu; } } +if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ + if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + sts = ST_OFL | SB_OFL_NV; /* offl no vol */ + else if (uptr->flags & UNIT_ONL) sts = ST_SUC; /* online */ else sts = ST_AVL; /* avail */ - rq_putr_unit (pkt, uptr, lu, FALSE); /* fill unit fields */ - dtyp = GET_DTYPE (uptr -> flags); /* get drive type */ + rq_putr_unit (cp, pkt, uptr, lu, FALSE); /* fill unit fields */ + dtyp = GET_DTYPE (uptr->flags); /* get drive type */ if (drv_tab[dtyp].rcts) rbpar = 1; /* ctrl bad blk? */ else rbpar = 0; /* fill geom, bblk */ - rq_pkt[pkt].d[GUS_TRK] = drv_tab[dtyp].sect; - rq_pkt[pkt].d[GUS_GRP] = drv_tab[dtyp].tpg; - rq_pkt[pkt].d[GUS_CYL] = drv_tab[dtyp].gpc; - rq_pkt[pkt].d[GUS_UVER] = 0; - rq_pkt[pkt].d[GUS_RCTS] = drv_tab[dtyp].rcts; - rq_pkt[pkt].d[GUS_RBSC] = - (rbpar << GUS_RB_V_RBNS) | (rbpar << GUS_RB_V_RCTC); } + cp->pak[pkt].d[GUS_TRK] = drv_tab[dtyp].sect; + cp->pak[pkt].d[GUS_GRP] = drv_tab[dtyp].tpg; + cp->pak[pkt].d[GUS_CYL] = drv_tab[dtyp].gpc; + cp->pak[pkt].d[GUS_UVER] = 0; + cp->pak[pkt].d[GUS_RCTS] = drv_tab[dtyp].rcts; + cp->pak[pkt].d[GUS_RBSC] = + (rbpar << GUS_RB_V_RBNS) | (rbpar << GUS_RB_V_RCTC); } else sts = ST_OFL; /* offline */ -rq_pkt[pkt].d[GUS_SHUN] = lu; /* shadowing */ -rq_pkt[pkt].d[GUS_SHST] = 0; -rq_putr (pkt, cmd | OP_END, 0, sts, GUS_LNT, UQ_TYP_SEQ); -return rq_putpkt (pkt, TRUE); +cp->pak[pkt].d[GUS_SHUN] = lu; /* shadowing */ +cp->pak[pkt].d[GUS_SHST] = 0; +rq_putr (cp, pkt, cmd | OP_END, 0, sts, GUS_LNT_D, UQ_TYP_SEQ); +return rq_putpkt (cp, pkt, TRUE); } /* Unit online - defer if q'd commands */ -t_bool rq_onl (int32 pkt, t_bool q) +t_bool rq_onl (MSC *cp, int32 pkt, t_bool q) { -uint32 lu = rq_pkt[pkt].d[CMD_UN]; /* unit # */ +uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ uint32 sts; UNIT *uptr; -if (uptr = rq_getucb (lu)) { /* unit exist? */ - if (q && uptr -> cpkt) { /* need to queue? */ - rq_enqt (&uptr -> pktq, pkt); /* do later */ - return OK; } - if ((uptr -> flags & UNIT_ATT) == 0) /* not attached? */ - sts = ST_OFL | SB_OFL_NV; /* offl no vol */ - else if (uptr -> flags & UNIT_ONL) /* already online? */ - sts = ST_SUC | SB_SUC_ON; - else { sts = ST_SUC; /* mark online */ - uptr -> flags = uptr -> flags | UNIT_ONL; - rq_setf_unit (pkt, uptr); } /* hack flags */ - rq_putr_unit (pkt, uptr, lu, TRUE); } /* set fields */ +if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ + if (q && uptr->cpkt) { /* need to queue? */ + rq_enqt (cp, &uptr->pktq, pkt); /* do later */ + return OK; } + if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + sts = ST_OFL | SB_OFL_NV; /* offl no vol */ + else if (uptr->flags & UNIT_ONL) /* already online? */ + sts = ST_SUC | SB_SUC_ON; + else { /* mark online */ + sts = ST_SUC; + uptr->flags = uptr->flags | UNIT_ONL; + rq_setf_unit (cp, pkt, uptr); } /* hack flags */ + rq_putr_unit (cp, pkt, uptr, lu, TRUE); } /* set fields */ else sts = ST_OFL; /* offline */ -rq_pkt[pkt].d[ONL_SHUN] = lu; /* shadowing */ -rq_pkt[pkt].d[ONL_SHST] = 0; -rq_putr (pkt, cmd | OP_END, 0, sts, ONL_LNT, UQ_TYP_SEQ); -return rq_putpkt (pkt, TRUE); +cp->pak[pkt].d[ONL_SHUN] = lu; /* shadowing */ +cp->pak[pkt].d[ONL_SHST] = 0; +rq_putr (cp, pkt, cmd | OP_END, 0, sts, ONL_LNT, UQ_TYP_SEQ); +return rq_putpkt (cp, pkt, TRUE); } /* Set controller characteristics */ -t_bool rq_scc (int32 pkt, t_bool q) +t_bool rq_scc (MSC *cp, int32 pkt, t_bool q) { int32 sts, cmd; -if (rq_pkt[pkt].d[SCC_MSV]) { /* MSCP ver = 0? */ +if (cp->pak[pkt].d[SCC_MSV]) { /* MSCP ver = 0? */ sts = ST_CMD | I_VRSN; /* no, lose */ cmd = 0; } else { sts = ST_SUC; /* success */ cmd = GETP (pkt, CMD_OPC, OPC); /* get opcode */ - rq_cflgs = (rq_cflgs & CF_RPL) | /* hack ctrl flgs */ - rq_pkt[pkt].d[SCC_CFL]; - if (rq_htmo = rq_pkt[pkt].d[SCC_TMO]) /* set timeout */ - rq_htmo = rq_htmo + 2; /* if nz, round up */ - rq_pkt[pkt].d[SCC_CFL] = rq_cflgs; /* return flags */ - rq_pkt[pkt].d[SCC_TMO] = RQ_DCTMO; /* ctrl timeout */ - rq_pkt[pkt].d[SCC_VER] = (RQ_HVER << SCC_VER_V_HVER) | - (RQ_SVER << SCC_VER_V_SVER); - rq_pkt[pkt].d[SCC_CIDA] = 0; /* ctrl ID */ - rq_pkt[pkt].d[SCC_CIDB] = 0; - rq_pkt[pkt].d[SCC_CIDC] = 0; - rq_pkt[pkt].d[SCC_CIDD] = (RQ_CLASS << SCC_CIDD_V_CLS) | - (RQ_MODEL << SCC_CIDD_V_MOD); - rq_pkt[pkt].d[SCC_MBCL] = 0; /* max bc */ - rq_pkt[pkt].d[SCC_MBCH] = 0; } -rq_putr (pkt, cmd | OP_END, 0, sts, SCC_LNT, UQ_TYP_SEQ); -return rq_putpkt (pkt, TRUE); + cp->cflgs = (cp->cflgs & CF_RPL) | /* hack ctrl flgs */ + cp->pak[pkt].d[SCC_CFL]; + if (cp->htmo = cp->pak[pkt].d[SCC_TMO]) /* set timeout */ + cp->htmo = cp->htmo + 2; /* if nz, round up */ + cp->pak[pkt].d[SCC_CFL] = cp->cflgs; /* return flags */ + cp->pak[pkt].d[SCC_TMO] = RQ_DCTMO; /* ctrl timeout */ + cp->pak[pkt].d[SCC_VER] = (RQ_HVER << SCC_VER_V_HVER) | + (RQ_SVER << SCC_VER_V_SVER); + cp->pak[pkt].d[SCC_CIDA] = 0; /* ctrl ID */ + cp->pak[pkt].d[SCC_CIDB] = 0; + cp->pak[pkt].d[SCC_CIDC] = 0; + cp->pak[pkt].d[SCC_CIDD] = (RQ_CLASS << SCC_CIDD_V_CLS) | + (RQ_MODEL << SCC_CIDD_V_MOD); + cp->pak[pkt].d[SCC_MBCL] = 0; /* max bc */ + cp->pak[pkt].d[SCC_MBCH] = 0; } +rq_putr (cp, pkt, cmd | OP_END, 0, sts, SCC_LNT, UQ_TYP_SEQ); +return rq_putpkt (cp, pkt, TRUE); } /* Set unit characteristics - defer if q'd commands */ -t_bool rq_suc (int32 pkt, t_bool q) +t_bool rq_suc (MSC *cp, int32 pkt, t_bool q) { -uint32 lu = rq_pkt[pkt].d[CMD_UN]; /* unit # */ +uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ uint32 sts; UNIT *uptr; -if (uptr = rq_getucb (lu)) { /* unit exist? */ - if (q && uptr -> cpkt) { /* need to queue? */ - rq_enqt (&uptr -> pktq, pkt); /* do later */ - return OK; } - if ((uptr -> flags & UNIT_ATT) == 0) /* not attached? */ - sts = ST_OFL | SB_OFL_NV; /* offl no vol */ - else { sts = ST_SUC; /* avail or onl */ - rq_setf_unit (pkt, uptr); } /* hack flags */ - rq_putr_unit (pkt, uptr, lu, TRUE); } /* set fields */ +if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ + if (q && uptr->cpkt) { /* need to queue? */ + rq_enqt (cp, &uptr->pktq, pkt); /* do later */ + return OK; } + if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + sts = ST_OFL | SB_OFL_NV; /* offl no vol */ + else { /* avail or onl */ + sts = ST_SUC; + rq_setf_unit (cp, pkt, uptr); } /* hack flags */ + rq_putr_unit (cp, pkt, uptr, lu, TRUE); } /* set fields */ else sts = ST_OFL; /* offline */ -rq_pkt[pkt].d[ONL_SHUN] = lu; /* shadowing */ -rq_pkt[pkt].d[ONL_SHST] = 0; -rq_putr (pkt, cmd | OP_END, 0, sts, SUC_LNT, UQ_TYP_SEQ); -return rq_putpkt (pkt, TRUE); +cp->pak[pkt].d[ONL_SHUN] = lu; /* shadowing */ +cp->pak[pkt].d[ONL_SHST] = 0; +rq_putr (cp, pkt, cmd | OP_END, 0, sts, SUC_LNT, UQ_TYP_SEQ); +return rq_putpkt (cp, pkt, TRUE); } /* Format command - floppies only */ -t_bool rq_fmt (int32 pkt, t_bool q) +t_bool rq_fmt (MSC *cp, int32 pkt, t_bool q) { -uint32 lu = rq_pkt[pkt].d[CMD_UN]; /* unit # */ +uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ uint32 sts; UNIT *uptr; -if (uptr = rq_getucb (lu)) { /* unit exist? */ - if (q && uptr -> cpkt) { /* need to queue? */ - rq_enqt (&uptr -> pktq, pkt); /* do later */ - return OK; } - if (GET_DTYPE (uptr -> flags) != RX33_DTYPE) /* RX33? */ - sts = ST_CMD | I_OPCD; /* no, err */ - else if ((rq_pkt[pkt].d[FMT_IH] & 0100000) == 0) /* magic bit set? */ - sts = ST_CMD | I_FMTI; /* no, err */ - else if ((uptr -> flags & UNIT_ATT) == 0) /* offline? */ - sts = ST_OFL | SB_OFL_NV; /* no vol */ - else if (uptr -> flags & UNIT_ONL) { /* online? */ - uptr -> flags = uptr -> flags & ~UNIT_ONL; - uptr -> uf = 0; /* clear flags */ - sts = ST_AVL | SB_AVL_INU; } /* avail, in use */ +if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ + if (q && uptr->cpkt) { /* need to queue? */ + rq_enqt (cp, &uptr->pktq, pkt); /* do later */ + return OK; } + if (GET_DTYPE (uptr->flags) != RX33_DTYPE) /* RX33? */ + sts = ST_CMD | I_OPCD; /* no, err */ + else if ((cp->pak[pkt].d[FMT_IH] & 0100000) == 0) /* magic bit set? */ + sts = ST_CMD | I_FMTI; /* no, err */ + else if ((uptr->flags & UNIT_ATT) == 0) /* offline? */ + sts = ST_OFL | SB_OFL_NV; /* no vol */ + else if (uptr->flags & UNIT_ONL) { /* online? */ + uptr->flags = uptr->flags & ~UNIT_ONL; + uptr->uf = 0; /* clear flags */ + sts = ST_AVL | SB_AVL_INU; } /* avail, in use */ else if (RQ_WPH (uptr)) /* write prot? */ - sts = ST_WPR | SB_WPR_HW; /* can't fmt */ + sts = ST_WPR | SB_WPR_HW; /* can't fmt */ else sts = ST_SUC; /*** for now ***/ } else sts = ST_OFL; /* offline */ -rq_putr (pkt, cmd | OP_END, 0, sts, FMT_LNT, UQ_TYP_SEQ); -return rq_putpkt (pkt, TRUE); +rq_putr (cp, pkt, cmd | OP_END, 0, sts, FMT_LNT, UQ_TYP_SEQ); +return rq_putpkt (cp, pkt, TRUE); } /* Data transfer commands */ -t_bool rq_rw (int32 pkt, t_bool q) +t_bool rq_rw (MSC *cp, int32 pkt, t_bool q) { -uint32 lu = rq_pkt[pkt].d[CMD_UN]; /* unit # */ +uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ uint32 sts; UNIT *uptr; -if (uptr = rq_getucb (lu)) { /* unit exist? */ - if (q && uptr -> cpkt) { /* need to queue? */ - rq_enqt (&uptr -> pktq, pkt); /* do later */ - return OK; } - sts = rq_rw_valid (pkt, uptr, cmd); /* validity checks */ +if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ + if (q && uptr->cpkt) { /* need to queue? */ + rq_enqt (cp, &uptr->pktq, pkt); /* do later */ + return OK; } + sts = rq_rw_valid (cp, pkt, uptr, cmd); /* validity checks */ if (sts == 0) { /* ok? */ - uptr -> cpkt = pkt; /* op in progress */ - rq_pkt[pkt].d[RW_WBAL] = rq_pkt[pkt].d[RW_BAL]; - rq_pkt[pkt].d[RW_WBAH] = rq_pkt[pkt].d[RW_BAH]; - rq_pkt[pkt].d[RW_WBCL] = rq_pkt[pkt].d[RW_BCL]; - rq_pkt[pkt].d[RW_WBCH] = rq_pkt[pkt].d[RW_BCH]; - rq_pkt[pkt].d[RW_WBLL] = rq_pkt[pkt].d[RW_LBNL]; - rq_pkt[pkt].d[RW_WBLH] = rq_pkt[pkt].d[RW_LBNH]; - sim_activate (uptr, rq_xtime); /* activate */ - return OK; } } /* done */ + uptr->cpkt = pkt; /* op in progress */ + cp->pak[pkt].d[RW_WBAL] = cp->pak[pkt].d[RW_BAL]; + cp->pak[pkt].d[RW_WBAH] = cp->pak[pkt].d[RW_BAH]; + cp->pak[pkt].d[RW_WBCL] = cp->pak[pkt].d[RW_BCL]; + cp->pak[pkt].d[RW_WBCH] = cp->pak[pkt].d[RW_BCH]; + cp->pak[pkt].d[RW_WBLL] = cp->pak[pkt].d[RW_LBNL]; + cp->pak[pkt].d[RW_WBLH] = cp->pak[pkt].d[RW_LBNH]; + sim_activate (uptr, rq_xtime); /* activate */ + return OK; } } /* done */ else sts = ST_OFL; /* offline */ -rq_pkt[pkt].d[RW_BCL] = rq_pkt[pkt].d[RW_BCH] = 0; /* bad packet */ -rq_putr (pkt, cmd | OP_END, 0, sts, RW_LNT, UQ_TYP_SEQ); -return rq_putpkt (pkt, TRUE); +cp->pak[pkt].d[RW_BCL] = cp->pak[pkt].d[RW_BCH] = 0; /* bad packet */ +rq_putr (cp, pkt, cmd | OP_END, 0, sts, RW_LNT, UQ_TYP_SEQ); +return rq_putpkt (cp, pkt, TRUE); } /* Validity checks */ -int32 rq_rw_valid (int32 pkt, UNIT *uptr, uint32 cmd) +int32 rq_rw_valid (MSC *cp, int32 pkt, UNIT *uptr, uint32 cmd) { -uint32 dtyp = GET_DTYPE (uptr -> flags); /* get drive type */ +uint32 dtyp = GET_DTYPE (uptr->flags); /* get drive type */ uint32 lbn = GETP32 (pkt, RW_LBNL); /* get lbn */ uint32 bc = GETP32 (pkt, RW_BCL); /* get byte cnt */ uint32 maxlbn = drv_tab[dtyp].lbn; /* get max lbn */ -if ((uptr -> flags & UNIT_ATT) == 0) /* not attached? */ +if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ return (ST_OFL | SB_OFL_NV); /* offl no vol */ -if ((uptr -> flags & UNIT_ONL) == 0) /* not online? */ +if ((uptr->flags & UNIT_ONL) == 0) /* not online? */ return ST_AVL; /* only avail */ if ((cmd != OP_ACC) && (cmd != OP_ERS) && /* 'real' xfer */ - (rq_pkt[pkt].d[RW_BAL] & 1)) /* odd address? */ + (cp->pak[pkt].d[RW_BAL] & 1)) /* odd address? */ return (ST_HST | SB_HST_OA); /* host buf odd */ if (bc & 1) return (ST_HST | SB_HST_OC); /* odd byte cnt? */ if (bc & 0xF0000000) return (ST_CMD | I_BCNT); /* 'reasonable' bc? */ if (lbn & 0xF0000000) return (ST_CMD | I_LBN); /* 'reasonable' lbn? */ if (lbn >= maxlbn) { /* accessing RCT? */ if (lbn >= (maxlbn + drv_tab[dtyp].rcts)) /* beyond copy 1? */ - return (ST_CMD | I_LBN); /* lbn err */ + return (ST_CMD | I_LBN); /* lbn err */ if (bc != RQ_NUMBY) return (ST_CMD | I_BCNT); }/* bc must be 512 */ else if ((lbn + ((bc + (RQ_NUMBY - 1)) / RQ_NUMBY)) > maxlbn) return (ST_CMD | I_BCNT); /* spiral to RCT */ if ((cmd == OP_WR) || (cmd == OP_ERS)) { /* write op? */ if (lbn >= maxlbn) /* accessing RCT? */ - return (ST_CMD | I_LBN); /* lbn err */ - if (uptr -> uf & UF_WPS) /* swre wlk? */ - return (ST_WPR | SB_WPR_SW); + return (ST_CMD | I_LBN); /* lbn err */ + if (uptr->uf & UF_WPS) /* swre wlk? */ + return (ST_WPR | SB_WPR_SW); if (RQ_WPH (uptr)) /* hwre wlk? */ - return (ST_WPR | SB_WPR_HW); } + return (ST_WPR | SB_WPR_HW); } return 0; /* success! */ } @@ -1127,89 +1402,91 @@ return 0; /* success! */ t_stat rq_svc (UNIT *uptr) { +MSC *cp = rq_ctxmap[uptr->cnum]; + uint32 i, t, err, tbc, abc, wwc; -int32 pkt = uptr -> cpkt; /* get packet */ +int32 pkt = uptr->cpkt; /* get packet */ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* get cmd */ uint32 ba = GETP32 (pkt, RW_WBAL); /* buf addr */ uint32 bc = GETP32 (pkt, RW_WBCL); /* byte count */ uint32 bl = GETP32 (pkt, RW_WBLL); /* block addr */ uint32 da = bl * RQ_NUMBY; /* disk addr */ -if (pkt == 0) return STOP_RQ; /* what??? */ +if ((cp == NULL) || (pkt == 0)) return STOP_RQ; /* what??? */ tbc = (bc > RQ_MAXFR)? RQ_MAXFR: bc; /* trim cnt to max */ -if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */ - rq_rw_end (uptr, 0, ST_OFL | SB_OFL_NV); /* offl no vol */ +if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ + rq_rw_end (cp, uptr, 0, ST_OFL | SB_OFL_NV); /* offl no vol */ return SCPE_OK; } if (bc == 0) { /* no xfer? */ - rq_rw_end (uptr, 0, ST_SUC); /* ok by me... */ + rq_rw_end (cp, uptr, 0, ST_SUC); /* ok by me... */ return SCPE_OK; } if ((cmd == OP_ERS) || (cmd == OP_WR)) { /* write op? */ if (RQ_WPH (uptr)) { - rq_rw_end (uptr, 0, ST_WPR | SB_WPR_HW); - return SCPE_OK; } - if (uptr -> uf & UF_WPS) { - rq_rw_end (uptr, 0, ST_WPR | SB_WPR_SW); - return SCPE_OK; } } + rq_rw_end (cp, uptr, 0, ST_WPR | SB_WPR_HW); + return SCPE_OK; } + if (uptr->uf & UF_WPS) { + rq_rw_end (cp, uptr, 0, ST_WPR | SB_WPR_SW); + return SCPE_OK; } } if (cmd == OP_ERS) { /* erase? */ wwc = ((tbc + (RQ_NUMBY - 1)) & ~(RQ_NUMBY - 1)) >> 1; for (i = 0; i < wwc; i++) rqxb[i] = 0; /* clr buf */ - err = fseek (uptr -> fileref, da, SEEK_SET); /* set pos */ - if (!err) fxwrite (rqxb, sizeof (int16), wwc, uptr -> fileref); - err = ferror (uptr -> fileref); } /* end if erase */ + err = fseek (uptr->fileref, da, SEEK_SET); /* set pos */ + if (!err) fxwrite (rqxb, sizeof (int16), wwc, uptr->fileref); + err = ferror (uptr->fileref); } /* end if erase */ else if (cmd == OP_WR) { /* write? */ - t = Map_ReadW (ba, tbc, rqxb, QB); /* fetch buffer */ + t = Map_ReadW (ba, tbc, rqxb, MAP); /* fetch buffer */ if (abc = tbc - t) { /* any xfer? */ - wwc = ((abc + (RQ_NUMBY - 1)) & ~(RQ_NUMBY - 1)) >> 1; - for (i = (abc >> 1); i < wwc; i++) rqxb[i] = 0; - err = fseek (uptr -> fileref, da, SEEK_SET); - if (!err) fxwrite (rqxb, sizeof (int16), wwc, uptr -> fileref); - err = ferror (uptr -> fileref); } + wwc = ((abc + (RQ_NUMBY - 1)) & ~(RQ_NUMBY - 1)) >> 1; + for (i = (abc >> 1); i < wwc; i++) rqxb[i] = 0; + err = fseek (uptr->fileref, da, SEEK_SET); + if (!err) fxwrite (rqxb, sizeof (int16), wwc, uptr->fileref); + err = ferror (uptr->fileref); } if (t) { /* nxm? */ - PUTP32 (pkt, RW_WBCL, bc - abc); /* adj bc */ - PUTP32 (pkt, RW_WBAL, ba + abc); /* adj ba */ - if (rq_hbe (uptr, ER_NXM)) /* post err log */ - rq_rw_end (uptr, EF_LOG, ST_HST | SB_HST_NXM); - return SCPE_OK; } } /* end else wr */ + PUTP32 (pkt, RW_WBCL, bc - abc); /* adj bc */ + PUTP32 (pkt, RW_WBAL, ba + abc); /* adj ba */ + if (rq_hbe (cp, uptr)) /* post err log */ + rq_rw_end (cp, uptr, EF_LOG, ST_HST | SB_HST_NXM); + return SCPE_OK; } } /* end else wr */ -else { err = fseek (uptr -> fileref, da, SEEK_SET); /* set pos */ +else { err = fseek (uptr->fileref, da, SEEK_SET); /* set pos */ if (!err) { - i = fxread (rqxb, sizeof (int16), tbc >> 1, uptr -> fileref); - for ( ; i < (tbc >> 1); i++) rqxb[i] = 0; /* fill */ - err = ferror (uptr -> fileref); } + i = fxread (rqxb, sizeof (int16), tbc >> 1, uptr->fileref); + for ( ; i < (tbc >> 1); i++) rqxb[i] = 0; /* fill */ + err = ferror (uptr->fileref); } if ((cmd == OP_RD) && !err) { /* read? */ - if (t = Map_WriteW (ba, tbc, rqxb, QB)) { /* store, nxm? */ - PUTP32 (pkt, RW_WBCL, bc - (tbc - t)); /* adj bc */ - PUTP32 (pkt, RW_WBAL, ba + (tbc - t)); /* adj ba */ - if (rq_hbe (uptr, ER_NXM)) /* post err log */ - rq_rw_end (uptr, EF_LOG, ST_HST | SB_HST_NXM); - return SCPE_OK; } - } + if (t = Map_WriteW (ba, tbc, rqxb, MAP)) { /* store, nxm? */ + PUTP32 (pkt, RW_WBCL, bc - (tbc - t)); /* adj bc */ + PUTP32 (pkt, RW_WBAL, ba + (tbc - t)); /* adj ba */ + if (rq_hbe (cp, uptr)) /* post err log */ + rq_rw_end (cp, uptr, EF_LOG, ST_HST | SB_HST_NXM); + return SCPE_OK; } + } else if ((cmd == OP_CMP) && !err) { /* compare? */ - uint8 dby, mby; - for (i = 0; i < tbc; i++) { /* loop */ - if (Map_ReadB (ba + i, 1, &mby, QB)) { /* fetch, nxm? */ - PUTP32 (pkt, RW_WBCL, bc - i); /* adj bc */ - PUTP32 (pkt, RW_WBAL, bc - i); /* adj ba */ - if (rq_hbe (uptr, ER_NXM)) /* post err log */ - rq_rw_end (uptr, EF_LOG, ST_HST | SB_HST_NXM); - return SCPE_OK; } - dby = (rqxb[i >> 1] >> ((i & 1)? 8: 0)) & 0xFF; - if (mby != dby) { /* cmp err? */ - PUTP32 (pkt, RW_WBCL, bc - i); /* adj bc */ - rq_rw_end (uptr, 0, ST_CMP); /* done */ - return SCPE_OK; } /* exit */ - } /* end for */ - } /* end else if */ + uint8 dby, mby; + for (i = 0; i < tbc; i++) { /* loop */ + if (Map_ReadB (ba + i, 1, &mby, MAP)) { /* fetch, nxm? */ + PUTP32 (pkt, RW_WBCL, bc - i); /* adj bc */ + PUTP32 (pkt, RW_WBAL, bc - i); /* adj ba */ + if (rq_hbe (cp, uptr)) /* post err log */ + rq_rw_end (cp, uptr, EF_LOG, ST_HST | SB_HST_NXM); + return SCPE_OK; } + dby = (rqxb[i >> 1] >> ((i & 1)? 8: 0)) & 0xFF; + if (mby != dby) { /* cmp err? */ + PUTP32 (pkt, RW_WBCL, bc - i); /* adj bc */ + rq_rw_end (cp, uptr, 0, ST_CMP); /* done */ + return SCPE_OK; } /* exit */ + } /* end for */ + } /* end else if */ } /* end else read */ if (err != 0) { /* error? */ - if (rq_dte (uptr, ST_DRV)) /* post err log */ - rq_rw_end (uptr, EF_LOG, ST_DRV); /* if ok, report err */ + if (rq_dte (cp, uptr, ST_DRV)) /* post err log */ + rq_rw_end (cp, uptr, EF_LOG, ST_DRV); /* if ok, report err */ perror ("RQ I/O error"); - clearerr (uptr -> fileref); + clearerr (uptr->fileref); return SCPE_IOERR; } ba = ba + tbc; /* incr bus addr */ bc = bc - tbc; /* decr byte cnt */ @@ -1218,44 +1495,48 @@ PUTP32 (pkt, RW_WBAL, ba); /* update pkt */ PUTP32 (pkt, RW_WBCL, bc); PUTP32 (pkt, RW_WBLL, bl); if (bc) sim_activate (uptr, rq_xtime); /* more? resched */ -else rq_rw_end (uptr, 0, ST_SUC); /* done! */ +else rq_rw_end (cp, uptr, 0, ST_SUC); /* done! */ return SCPE_OK; } /* Transfer command complete */ -t_bool rq_rw_end (UNIT *uptr, uint32 flg, uint32 sts) +t_bool rq_rw_end (MSC *cp, UNIT *uptr, uint32 flg, uint32 sts) { -int32 pkt = uptr -> cpkt; /* packet */ +int32 pkt = uptr->cpkt; /* packet */ uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* get cmd */ uint32 bc = GETP32 (pkt, RW_BCL); /* init bc */ uint32 wbc = GETP32 (pkt, RW_WBCL); /* work bc */ +DEVICE *dptr = rq_devmap[uptr->cnum]; -uptr -> cpkt = 0; /* done */ +uptr->cpkt = 0; /* done */ PUTP32 (pkt, RW_BCL, bc - wbc); /* bytes processed */ -rq_pkt[pkt].d[RW_WBAL] = rq_pkt[pkt].d[RW_WBAH] = 0; /* clear temps */ -rq_pkt[pkt].d[RW_WBCL] = rq_pkt[pkt].d[RW_WBCH] = 0; -rq_pkt[pkt].d[RW_WBLL] = rq_pkt[pkt].d[RW_WBLH] = 0; -rq_putr (pkt, cmd | OP_END, flg, sts, RW_LNT, UQ_TYP_SEQ); /* fill pkt */ -if (!rq_putpkt (pkt, TRUE)) return ERR; /* send pkt */ -if (uptr -> pktq) /* more to do? */ - sim_activate (&rq_unit[RQ_QUEUE], rq_qtime); /* activate thread */ +cp->pak[pkt].d[RW_WBAL] = 0; /* clear temps */ +cp->pak[pkt].d[RW_WBAH] = 0; +cp->pak[pkt].d[RW_WBCL] = 0; +cp->pak[pkt].d[RW_WBCH] = 0; +cp->pak[pkt].d[RW_WBLL] = 0; +cp->pak[pkt].d[RW_WBLH] = 0; +rq_putr (cp, pkt, cmd | OP_END, flg, sts, RW_LNT, UQ_TYP_SEQ); /* fill pkt */ +if (!rq_putpkt (cp, pkt, TRUE)) return ERR; /* send pkt */ +if (uptr->pktq) /* more to do? */ + sim_activate (dptr->units + RQ_QUEUE, rq_qtime); /* activate thread */ return OK; } /* Data transfer error log packet */ -t_bool rq_dte (UNIT *uptr, uint32 err) +t_bool rq_dte (MSC *cp, UNIT *uptr, uint32 err) { int32 pkt, tpkt; uint32 lu, dtyp, lbn, ccyl, csurf, csect, t; -if ((rq_cflgs & CF_THS) == 0) return OK; /* logging? */ -if (!rq_deqf (&pkt)) return ERR; /* get log pkt */ -tpkt = uptr -> cpkt; /* rw pkt */ -lu = rq_pkt[tpkt].d[CMD_UN]; /* unit # */ +if ((cp->cflgs & CF_THS) == 0) return OK; /* logging? */ +if (!rq_deqf (cp, &pkt)) return ERR; /* get log pkt */ +tpkt = uptr->cpkt; /* rw pkt */ +lu = cp->pak[tpkt].d[CMD_UN]; /* unit # */ lbn = GETP32 (tpkt, RW_WBLL); /* recent LBN */ -dtyp = GET_DTYPE (uptr -> flags); /* drv type */ +dtyp = GET_DTYPE (uptr->flags); /* drv type */ if (drv_tab[dtyp].flgs & RQDF_SDI) t = 0; /* SDI? ovhd @ end */ else t = (drv_tab[dtyp].xbn + drv_tab[dtyp].dbn) / /* ovhd cylinders */ (drv_tab[dtyp].sect * drv_tab[dtyp].surf); @@ -1264,99 +1545,103 @@ t = lbn % drv_tab[dtyp].cyl; /* trk relative blk */ csurf = t / drv_tab[dtyp].surf; /* curr surf */ csect = t % drv_tab[dtyp].surf; /* curr sect */ -rq_pkt[pkt].d[ELP_REFL] = rq_pkt[tpkt].d[CMD_REFL]; /* copy cmd ref */ -rq_pkt[pkt].d[ELP_REFH] = rq_pkt[tpkt].d[CMD_REFH]; /* copy cmd ref */ -rq_pkt[pkt].d[ELP_UN] = lu; /* copy unit */ -rq_pkt[pkt].d[ELP_SEQ] = 0; /* clr seq # */ -rq_pkt[pkt].d[DTE_CIDA] = 0; /* ctrl ID */ -rq_pkt[pkt].d[DTE_CIDB] = 0; -rq_pkt[pkt].d[DTE_CIDC] = 0; -rq_pkt[pkt].d[DTE_CIDD] = (RQ_CLASS << DTE_CIDD_V_CLS) | +cp->pak[pkt].d[ELP_REFL] = cp->pak[tpkt].d[CMD_REFL]; /* copy cmd ref */ +cp->pak[pkt].d[ELP_REFH] = cp->pak[tpkt].d[CMD_REFH]; +cp->pak[pkt].d[ELP_UN] = lu; /* copy unit */ +cp->pak[pkt].d[ELP_SEQ] = 0; /* clr seq # */ +cp->pak[pkt].d[DTE_CIDA] = 0; /* ctrl ID */ +cp->pak[pkt].d[DTE_CIDB] = 0; +cp->pak[pkt].d[DTE_CIDC] = 0; +cp->pak[pkt].d[DTE_CIDD] = (RQ_CLASS << DTE_CIDD_V_CLS) | (RQ_MODEL << DTE_CIDD_V_MOD); -rq_pkt[pkt].d[DTE_VER] = (RQ_HVER << DTE_VER_V_HVER) | +cp->pak[pkt].d[DTE_VER] = (RQ_HVER << DTE_VER_V_HVER) | (RQ_SVER << DTE_VER_V_SVER); -rq_pkt[pkt].d[DTE_MLUN] = lu; /* MLUN */ -rq_pkt[pkt].d[DTE_UIDA] = lu; /* unit ID */ -rq_pkt[pkt].d[DTE_UIDB] = 0; -rq_pkt[pkt].d[DTE_UIDC] = 0; -rq_pkt[pkt].d[DTE_UIDD] = (UID_DISK << DTE_UIDD_V_CLS) | +cp->pak[pkt].d[DTE_MLUN] = lu; /* MLUN */ +cp->pak[pkt].d[DTE_UIDA] = lu; /* unit ID */ +cp->pak[pkt].d[DTE_UIDB] = 0; +cp->pak[pkt].d[DTE_UIDC] = 0; +cp->pak[pkt].d[DTE_UIDD] = (UID_DISK << DTE_UIDD_V_CLS) | (drv_tab[dtyp].mod << DTE_UIDD_V_MOD); -rq_pkt[pkt].d[DTE_UVER] = 0; /* unit versn */ -rq_pkt[pkt].d[DTE_SCYL] = ccyl; /* cylinder */ -rq_pkt[pkt].d[DTE_VSNL] = 01234 + lu; /* vol ser # */ -rq_pkt[pkt].d[DTE_VSNH] = 0; -rq_pkt[pkt].d[DTE_D1] = 0; -rq_pkt[pkt].d[DTE_D2] = csect << DTE_D2_V_SECT; /* geometry */ -rq_pkt[pkt].d[DTE_D3] = (ccyl << DTE_D3_V_CYL) | +cp->pak[pkt].d[DTE_UVER] = 0; /* unit versn */ +cp->pak[pkt].d[DTE_SCYL] = ccyl; /* cylinder */ +cp->pak[pkt].d[DTE_VSNL] = 01234 + lu; /* vol ser # */ +cp->pak[pkt].d[DTE_VSNH] = 0; +cp->pak[pkt].d[DTE_D1] = 0; +cp->pak[pkt].d[DTE_D2] = csect << DTE_D2_V_SECT; /* geometry */ +cp->pak[pkt].d[DTE_D3] = (ccyl << DTE_D3_V_CYL) | (csurf << DTE_D3_V_SURF); -rq_putr (pkt, FM_SDE, LF_SNR, err, DTE_LNT, UQ_TYP_DAT); -return rq_putpkt (pkt, TRUE); +rq_putr (cp, pkt, FM_SDE, LF_SNR, err, DTE_LNT, UQ_TYP_DAT); +return rq_putpkt (cp, pkt, TRUE); } /* Host bus error log packet */ -t_bool rq_hbe (UNIT *uptr, uint32 err) +t_bool rq_hbe (MSC *cp, UNIT *uptr) { int32 pkt, tpkt; -if ((rq_cflgs & CF_THS) == 0) return OK; /* logging? */ -if (!rq_deqf (&pkt)) return ERR; /* get log pkt */ -tpkt = uptr -> cpkt; /* rw pkt */ -rq_pkt[pkt].d[ELP_REFL] = rq_pkt[tpkt].d[CMD_REFL]; /* copy cmd ref */ -rq_pkt[pkt].d[ELP_REFH] = rq_pkt[tpkt].d[CMD_REFH]; /* copy cmd ref */ -rq_pkt[pkt].d[ELP_UN] = rq_pkt[tpkt].d[CMD_UN]; /* copy unit */ -rq_pkt[pkt].d[ELP_SEQ] = 0; /* clr seq # */ -rq_pkt[pkt].d[HBE_CIDA] = 0; /* ctrl ID */ -rq_pkt[pkt].d[HBE_CIDB] = 0; -rq_pkt[pkt].d[HBE_CIDC] = 0; -rq_pkt[pkt].d[HBE_CIDD] = (RQ_CLASS << DTE_CIDD_V_CLS) | +if ((cp->cflgs & CF_THS) == 0) return OK; /* logging? */ +if (!rq_deqf (cp, &pkt)) return ERR; /* get log pkt */ +tpkt = uptr->cpkt; /* rw pkt */ +cp->pak[pkt].d[ELP_REFL] = cp->pak[tpkt].d[CMD_REFL]; /* copy cmd ref */ +cp->pak[pkt].d[ELP_REFH] = cp->pak[tpkt].d[CMD_REFH]; +cp->pak[pkt].d[ELP_UN] = cp->pak[tpkt].d[CMD_UN]; /* copy unit */ +cp->pak[pkt].d[ELP_SEQ] = 0; /* clr seq # */ +cp->pak[pkt].d[HBE_CIDA] = 0; /* ctrl ID */ +cp->pak[pkt].d[HBE_CIDB] = 0; +cp->pak[pkt].d[HBE_CIDC] = 0; +cp->pak[pkt].d[HBE_CIDD] = (RQ_CLASS << DTE_CIDD_V_CLS) | (RQ_MODEL << DTE_CIDD_V_MOD); -rq_pkt[pkt].d[HBE_VER] = (RQ_HVER << HBE_VER_V_HVER) | /* versions */ +cp->pak[pkt].d[HBE_VER] = (RQ_HVER << HBE_VER_V_HVER) | /* versions */ (RQ_SVER << HBE_VER_V_SVER); -rq_pkt[pkt].d[HBE_RSV] = 0; -rq_pkt[pkt].d[HBE_BADL] = rq_pkt[tpkt].d[RW_WBAL]; /* bad addr */ -rq_pkt[pkt].d[HBE_BADH] = rq_pkt[tpkt].d[RW_WBAH]; -rq_putr (pkt, FM_BAD, LF_SNR, err, HBE_LNT, UQ_TYP_DAT); -return rq_putpkt (pkt, TRUE); +cp->pak[pkt].d[HBE_RSV] = 0; +cp->pak[pkt].d[HBE_BADL] = cp->pak[tpkt].d[RW_WBAL]; /* bad addr */ +cp->pak[pkt].d[HBE_BADH] = cp->pak[tpkt].d[RW_WBAH]; +rq_putr (cp, pkt, FM_BAD, LF_SNR, ST_HST | SB_HST_NXM, HBE_LNT, UQ_TYP_DAT); +return rq_putpkt (cp, pkt, TRUE); } /* Port last failure error log packet */ -t_bool rq_plf (uint32 err) +t_bool rq_plf (MSC *cp, uint32 err) { int32 pkt; -if (!rq_deqf (&pkt)) return ERR; /* get log pkt */ -rq_pkt[pkt].d[ELP_REFL] = rq_pkt[pkt].d[ELP_REFH] = 0; /* ref = 0 */ -rq_pkt[pkt].d[ELP_UN] = rq_pkt[pkt].d[ELP_SEQ] = 0; /* no unit, seq */ -rq_pkt[pkt].d[PLF_CIDA] = 0; /* cntl ID */ -rq_pkt[pkt].d[PLF_CIDB] = 0; -rq_pkt[pkt].d[PLF_CIDC] = 0; -rq_pkt[pkt].d[PLF_CIDD] = (RQ_CLASS << PLF_CIDD_V_CLS) | +if (!rq_deqf (cp, &pkt)) return ERR; /* get log pkt */ +cp->pak[pkt].d[ELP_REFL] = 0; /* ref = 0 */ +cp->pak[pkt].d[ELP_REFH] = 0; +cp->pak[pkt].d[ELP_UN] = 0; /* no unit */ +cp->pak[pkt].d[ELP_SEQ] = 0; /* no seq */ +cp->pak[pkt].d[PLF_CIDA] = 0; /* cntl ID */ +cp->pak[pkt].d[PLF_CIDB] = 0; +cp->pak[pkt].d[PLF_CIDC] = 0; +cp->pak[pkt].d[PLF_CIDD] = (RQ_CLASS << PLF_CIDD_V_CLS) | (RQ_MODEL << PLF_CIDD_V_MOD); -rq_pkt[pkt].d[PLF_VER] = (RQ_SVER << PLF_VER_V_SVER) | +cp->pak[pkt].d[PLF_VER] = (RQ_SVER << PLF_VER_V_SVER) | (RQ_HVER << PLF_VER_V_HVER); -rq_pkt[pkt].d[PLF_ERR] = err; -rq_putr (pkt, FM_CNT, LF_SNR, ST_CNT, PLF_LNT, UQ_TYP_DAT); -rq_pkt[pkt].d[UQ_HCTC] |= (UQ_CID_DIAG << UQ_HCTC_V_CID); -return rq_putpkt (pkt, TRUE); +cp->pak[pkt].d[PLF_ERR] = err; +rq_putr (cp, pkt, FM_CNT, LF_SNR, ST_CNT, PLF_LNT, UQ_TYP_DAT); +cp->pak[pkt].d[UQ_HCTC] |= (UQ_CID_DIAG << UQ_HCTC_V_CID); +return rq_putpkt (cp, pkt, TRUE); } /* Unit now available attention packet */ -int32 rq_una (UNIT *uptr) +int32 rq_una (MSC *cp, int32 un) { int32 pkt; -uint32 lu; +uint32 lu = cp->ubase + un; +UNIT *uptr = rq_getucb (cp, lu); -if (!rq_deqf (&pkt)) return ERR; /* get log pkt */ -lu = uptr - rq_dev.units; /* get unit */ -rq_pkt[pkt].d[RSP_REFL] = rq_pkt[pkt].d[RSP_REFH] = 0; /* ref = 0 */ -rq_pkt[pkt].d[RSP_UN] = lu; -rq_pkt[pkt].d[RSP_RSV] = 0; -rq_putr_unit (pkt, uptr, lu, FALSE); /* fill unit fields */ -rq_putr (pkt, OP_AVA, 0, 0, UNA_LNT, UQ_TYP_SEQ); /* fill std fields */ -return rq_putpkt (pkt, TRUE); +if (uptr == NULL) return OK; /* huh? */ +if (!rq_deqf (cp, &pkt)) return ERR; /* get log pkt */ +cp->pak[pkt].d[RSP_REFL] = 0; /* ref = 0 */ +cp->pak[pkt].d[RSP_REFH] = 0; +cp->pak[pkt].d[RSP_UN] = lu; +cp->pak[pkt].d[RSP_RSV] = 0; +rq_putr_unit (cp, pkt, uptr, lu, FALSE); /* fill unit fields */ +rq_putr (cp, pkt, OP_AVA, 0, 0, UNA_LNT, UQ_TYP_SEQ); /* fill std fields */ +return rq_putpkt (cp, pkt, TRUE); } /* List handling @@ -1367,39 +1652,39 @@ return rq_putpkt (pkt, TRUE); rq_enqt - enqueue at tail of list */ -t_bool rq_deqf (int32 *pkt) +t_bool rq_deqf (MSC *cp, int32 *pkt) { -if (rq_freq == 0) return rq_fatal (PE_NSR); /* no free pkts?? */ -rq_pbsy = rq_pbsy + 1; /* cnt busy pkts */ -*pkt = rq_freq; /* head of list */ -rq_freq = rq_pkt[rq_freq].link; /* next */ +if (cp->freq == 0) return rq_fatal (cp, PE_NSR); /* no free pkts?? */ +cp->pbsy = cp->pbsy + 1; /* cnt busy pkts */ +*pkt = cp->freq; /* head of list */ +cp->freq = cp->pak[cp->freq].link; /* next */ return OK; } -int32 rq_deqh (int32 *lh) +int32 rq_deqh (MSC *cp, int32 *lh) { int32 ptr = *lh; /* head of list */ -if (ptr) *lh = rq_pkt[ptr].link; /* next */ +if (ptr) *lh = cp->pak[ptr].link; /* next */ return ptr; } -void rq_enqh (int32 *lh, int32 pkt) +void rq_enqh (MSC *cp, int32 *lh, int32 pkt) { if (pkt == 0) return; /* any pkt? */ -rq_pkt[pkt].link = *lh; /* link is old lh */ +cp->pak[pkt].link = *lh; /* link is old lh */ *lh = pkt; /* pkt is new lh */ return; } -void rq_enqt (int32 *lh, int32 pkt) +void rq_enqt (MSC *cp, int32 *lh, int32 pkt) { if (pkt == 0) return; /* any pkt? */ -rq_pkt[pkt].link = 0; /* it will be tail */ +cp->pak[pkt].link = 0; /* it will be tail */ if (*lh == 0) *lh = pkt; /* if empty, enqh */ else { uint32 ptr = *lh; /* chase to end */ - while (rq_pkt[ptr].link) ptr = rq_pkt[ptr].link; - rq_pkt[ptr].link = pkt; } /* enq at tail */ + while (cp->pak[ptr].link) ptr = cp->pak[ptr].link; + cp->pak[ptr].link = pkt; } /* enq at tail */ return; } @@ -1407,21 +1692,21 @@ return; /* Get packet from command ring */ -t_bool rq_getpkt (int32 *pkt) +t_bool rq_getpkt (MSC *cp, int32 *pkt) { uint32 desc; t_addr addr; -if (!rq_getdesc (&rq_cq, &desc)) return ERR; /* get cmd desc */ +if (!rq_getdesc (cp, &cp->cq, &desc)) return ERR; /* get cmd desc */ if ((desc & UQ_DESC_OWN) == 0) { /* none */ *pkt = 0; /* pkt = 0 */ return OK; } /* no error */ -if (!rq_deqf (pkt)) return ERR; /* get cmd pkt */ -rq_hat = 0; /* dsbl hst timer */ +if (!rq_deqf (cp, pkt)) return ERR; /* get cmd pkt */ +cp->hat = 0; /* dsbl hst timer */ addr = desc & UQ_ADDR; /* get Q22 addr */ -if (Map_ReadW (addr + UQ_HDR_OFF, RQ_PKT_SIZE, rq_pkt[*pkt].d, QB)) - return rq_fatal (PE_PRE); /* read pkt */ -return rq_putdesc (&rq_cq, desc); /* release desc */ +if (Map_ReadW (addr + UQ_HDR_OFF, RQ_PKT_SIZE, cp->pak[*pkt].d, MAP)) + return rq_fatal (cp, PE_PRE); /* read pkt */ +return rq_putdesc (cp, &cp->cq, desc); /* release desc */ } /* Put packet to response ring - note the clever hack about credits. @@ -1429,47 +1714,48 @@ return rq_putdesc (&rq_cq, desc); /* release desc */ supplies one credit for every response packet sent over. Simple! */ -t_bool rq_putpkt (int32 pkt, t_bool qt) +t_bool rq_putpkt (MSC *cp, int32 pkt, t_bool qt) { uint32 desc, lnt, cr; t_addr addr; +DEVICE *dptr = rq_devmap[cp->cnum]; if (pkt == 0) return OK; /* any packet? */ if (DBG_LOG (LOG_RQ)) fprintf (sim_log, - ">>RQ: rsp=%04X, sts=%04X\n", - rq_pkt[pkt].d[RSP_OPF], rq_pkt[pkt].d[RSP_STS]); -if (!rq_getdesc (&rq_rq, &desc)) return ERR; /* get rsp desc */ + ">>RQ%c: rsp=%04X, sts=%04X\n", 'A' + cp->cnum, + cp->pak[pkt].d[RSP_OPF], cp->pak[pkt].d[RSP_STS]); +if (!rq_getdesc (cp, &cp->rq, &desc)) return ERR; /* get rsp desc */ if ((desc & UQ_DESC_OWN) == 0) { /* not valid? */ - if (qt) rq_enqt (&rq_rspq, pkt); /* normal? q tail */ - else rq_enqh (&rq_rspq, pkt); /* resp q call */ - sim_activate (&rq_unit[RQ_QUEUE], rq_qtime); /* activate q thrd */ + if (qt) rq_enqt (cp, &cp->rspq, pkt); /* normal? q tail */ + else rq_enqh (cp, &cp->rspq, pkt); /* resp q call */ + sim_activate (dptr->units + RQ_QUEUE, rq_qtime); /* activate q thrd */ return OK; } addr = desc & UQ_ADDR; /* get Q22 addr */ -lnt = rq_pkt[pkt].d[UQ_HLNT] - UQ_HDR_OFF; /* size, with hdr */ +lnt = cp->pak[pkt].d[UQ_HLNT] - UQ_HDR_OFF; /* size, with hdr */ if ((GETP (pkt, UQ_HCTC, TYP) == UQ_TYP_SEQ) && /* seq packet? */ (GETP (pkt, CMD_OPC, OPC) & OP_END)) { /* end packet? */ - cr = (rq_credits >= 14)? 14: rq_credits; /* max 14 credits */ - rq_credits = rq_credits - cr; /* decr credits */ - rq_pkt[pkt].d[UQ_HCTC] |= ((cr + 1) << UQ_HCTC_V_CR); } -if (Map_WriteW (addr + UQ_HDR_OFF, lnt, rq_pkt[pkt].d, QB)) - return rq_fatal (PE_PWE); /* write pkt */ -rq_enqh (&rq_freq, pkt); /* pkt is free */ -rq_pbsy = rq_pbsy - 1; /* decr busy cnt */ -if (rq_pbsy == 0) rq_hat = rq_htmo; /* idle? strt hst tmr */ -return rq_putdesc (&rq_rq, desc); /* release desc */ + cr = (cp->credits >= 14)? 14: cp->credits; /* max 14 credits */ + cp->credits = cp->credits - cr; /* decr credits */ + cp->pak[pkt].d[UQ_HCTC] |= ((cr + 1) << UQ_HCTC_V_CR); } +if (Map_WriteW (addr + UQ_HDR_OFF, lnt, cp->pak[pkt].d, MAP)) + return rq_fatal (cp, PE_PWE); /* write pkt */ +rq_enqh (cp, &cp->freq, pkt); /* pkt is free */ +cp->pbsy = cp->pbsy - 1; /* decr busy cnt */ +if (cp->pbsy == 0) cp->hat = cp->htmo; /* idle? strt hst tmr */ +return rq_putdesc (cp, &cp->rq, desc); /* release desc */ } /* Get a descriptor from the host */ -t_bool rq_getdesc (struct uq_ring *ring, uint32 *desc) +t_bool rq_getdesc (MSC *cp, struct uq_ring *ring, uint32 *desc) { -t_addr addr = ring -> ba + ring -> idx; +t_addr addr = ring->ba + ring->idx; uint16 d[2]; -if (Map_ReadW (addr, 4, d, QB)) /* fetch desc */ - return rq_fatal (PE_QRE); /* err? dead */ +if (Map_ReadW (addr, 4, d, MAP)) /* fetch desc */ + return rq_fatal (cp, PE_QRE); /* err? dead */ *desc = ((uint32) d[0]) | (((uint32) d[1]) << 16); -return OK; /* own? ok */ +return OK; } /* Return a descriptor to the host, clearing owner bit @@ -1478,104 +1764,133 @@ return OK; /* own? ok */ Actually, test whether previous ring entry was owned by host. */ -t_bool rq_putdesc (struct uq_ring *ring, uint32 desc) +t_bool rq_putdesc (MSC *cp, struct uq_ring *ring, uint32 desc) { uint32 prvd, newd = (desc & ~UQ_DESC_OWN) | UQ_DESC_F; -t_addr prva, addr = ring -> ba + ring -> idx; +t_addr prva, addr = ring->ba + ring->idx; uint16 d[2]; d[0] = newd & 0xFFFF; /* 32b to 16b */ d[1] = (newd >> 16) & 0xFFFF; -if (Map_WriteW (addr, 4, d, QB)) /* store desc */ - return rq_fatal (PE_QWE); /* err? dead */ +if (Map_WriteW (addr, 4, d, MAP)) /* store desc */ + return rq_fatal (cp, PE_QWE); /* err? dead */ if (desc & UQ_DESC_F) { /* was F set? */ - if (ring -> lnt <= 4) rq_ring_int (ring); /* lnt = 1? intr */ - else { prva = ring -> ba + /* prv desc */ - ((ring -> idx - 4) & (ring -> lnt - 1)); - if (Map_ReadW (prva, 4, d, QB)) /* read prv */ - return rq_fatal (PE_QRE); - prvd = ((uint32) d[0]) | (((uint32) d[1]) << 16); - if (prvd & UQ_DESC_OWN) rq_ring_int (ring); } } -ring -> idx = (ring -> idx + 4) & (ring -> lnt - 1); + if (ring->lnt <= 4) rq_ring_int (cp, ring); /* lnt = 1? intr */ + else { /* prv desc */ + prva = ring->ba + ((ring->idx - 4) & (ring->lnt - 1)); + if (Map_ReadW (prva, 4, d, MAP)) /* read prv */ + return rq_fatal (cp, PE_QRE); + prvd = ((uint32) d[0]) | (((uint32) d[1]) << 16); + if (prvd & UQ_DESC_OWN) rq_ring_int (cp, ring); } } +ring->idx = (ring->idx + 4) & (ring->lnt - 1); return OK; } -/* Get unit descriptor for logical unit - trivial now, - but eventually, hide multiboard complexities here */ +/* Get unit descriptor for logical unit */ -UNIT *rq_getucb (uint32 lu) +UNIT *rq_getucb (MSC *cp, uint32 lu) { +DEVICE *dptr = rq_devmap[cp->cnum]; UNIT *uptr; -if (lu >= RQ_NUMDR) return NULL; -uptr = rq_dev.units + lu; -if (uptr -> flags & UNIT_DIS) return NULL; +if ((lu < cp->ubase) || (lu >= (cp->ubase + RQ_NUMDR))) + return NULL; +uptr = dptr->units + (lu % RQ_NUMDR); +if (uptr->flags & UNIT_DIS) return NULL; return uptr; } /* Hack unit flags */ -void rq_setf_unit (int32 pkt, UNIT *uptr) +void rq_setf_unit (MSC *cp, int32 pkt, UNIT *uptr) { -uptr -> uf = rq_pkt[pkt].d[ONL_UFL] & UF_MSK; /* settable flags */ -if ((rq_pkt[pkt].d[CMD_MOD] & MD_SWP) && /* swre wrp enb? */ - (rq_pkt[pkt].d[ONL_UFL] & UF_WPS)) /* swre wrp on? */ - uptr -> uf = uptr -> uf | UF_WPS; /* simon says... */ +uptr->uf = cp->pak[pkt].d[ONL_UFL] & UF_MSK; /* settable flags */ +if ((cp->pak[pkt].d[CMD_MOD] & MD_SWP) && /* swre wrp enb? */ + (cp->pak[pkt].d[ONL_UFL] & UF_WPS)) /* swre wrp on? */ + uptr->uf = uptr->uf | UF_WPS; /* simon says... */ return; } /* Unit response fields */ -void rq_putr_unit (int32 pkt, UNIT *uptr, uint32 lu, t_bool all) +void rq_putr_unit (MSC *cp, int32 pkt, UNIT *uptr, uint32 lu, t_bool all) { -uint32 dtyp = GET_DTYPE (uptr -> flags); /* get drive type */ +uint32 dtyp = GET_DTYPE (uptr->flags); /* get drive type */ -rq_pkt[pkt].d[ONL_MLUN] = lu; /* unit */ -rq_pkt[pkt].d[ONL_UFL] = uptr -> uf | UF_RPL | RQ_WPH (uptr) | RQ_RMV (uptr); -rq_pkt[pkt].d[ONL_RSVL] = rq_pkt[pkt].d[ONL_RSVH] = 0; /* reserved */ -rq_pkt[pkt].d[ONL_UIDA] = lu; /* UID low */ -rq_pkt[pkt].d[ONL_UIDB] = 0; -rq_pkt[pkt].d[ONL_UIDC] = 0; -rq_pkt[pkt].d[ONL_UIDD] = (UID_DISK << ONL_UIDD_V_CLS) | +cp->pak[pkt].d[ONL_MLUN] = lu; /* unit */ +cp->pak[pkt].d[ONL_UFL] = uptr->uf | UF_RPL | RQ_WPH (uptr) | RQ_RMV (uptr); +cp->pak[pkt].d[ONL_RSVL] = 0; /* reserved */ +cp->pak[pkt].d[ONL_RSVH] = 0; +cp->pak[pkt].d[ONL_UIDA] = lu; /* UID low */ +cp->pak[pkt].d[ONL_UIDB] = 0; +cp->pak[pkt].d[ONL_UIDC] = 0; +cp->pak[pkt].d[ONL_UIDD] = (UID_DISK << ONL_UIDD_V_CLS) | (drv_tab[dtyp].mod << ONL_UIDD_V_MOD); /* UID hi */ PUTP32 (pkt, ONL_MEDL, drv_tab[dtyp].med); /* media type */ if (all) { /* if long form */ PUTP32 (pkt, ONL_SIZL, drv_tab[dtyp].lbn); /* user LBNs */ - rq_pkt[pkt].d[ONL_VSNL] = 01234 + lu; /* vol serial # */ - rq_pkt[pkt].d[ONL_VSNH] = 0; } + cp->pak[pkt].d[ONL_VSNL] = 01234 + lu; /* vol serial # */ + cp->pak[pkt].d[ONL_VSNH] = 0; } return; } /* UQ_HDR and RSP_OP fields */ -void rq_putr (int32 pkt, uint32 cmd, uint32 flg, uint32 sts, uint32 lnt, uint32 typ) +void rq_putr (MSC *cp, int32 pkt, uint32 cmd, uint32 flg, + uint32 sts, uint32 lnt, uint32 typ) { -rq_pkt[pkt].d[RSP_OPF] = (cmd << RSP_OPF_V_OPC) | /* set cmd, flg */ +cp->pak[pkt].d[RSP_OPF] = (cmd << RSP_OPF_V_OPC) | /* set cmd, flg */ (flg << RSP_OPF_V_FLG); -rq_pkt[pkt].d[RSP_STS] = sts; -rq_pkt[pkt].d[UQ_HLNT] = lnt; /* length */ -rq_pkt[pkt].d[UQ_HCTC] = typ << UQ_HCTC_V_TYP; /* type, clr cid, cr */ +cp->pak[pkt].d[RSP_STS] = sts; +cp->pak[pkt].d[UQ_HLNT] = lnt; /* length */ +cp->pak[pkt].d[UQ_HCTC] = (typ << UQ_HCTC_V_TYP) | /* type, cid */ + (UQ_CID_MSCP << UQ_HCTC_V_CID); /* clr credits */ return; } /* Post interrupt during init */ -void rq_init_int (void) +void rq_init_int (MSC *cp) { -if ((rq_s1dat & SA_S1H_IE) && (rq_s1dat & SA_S1H_VEC)) { - SET_INT (RQ); } +if (cp->s1dat & (SA_S1H_IE | SA_S1H_VEC)) rq_setint (cp); return; } /* Post interrupt during putpkt - note that NXMs are ignored! */ -void rq_ring_int (struct uq_ring *ring) +void rq_ring_int (MSC *cp, struct uq_ring *ring) { -t_addr iadr = rq_comm + ring -> ioff; /* addr intr wd */ +t_addr iadr = cp->comm + ring->ioff; /* addr intr wd */ uint16 flag = 1; -Map_WriteW (iadr, 2, &flag, QB); /* write flag */ -if (rq_s1dat & SA_S1H_VEC) SET_INT (RQ); /* if enb, intr */ +Map_WriteW (iadr, 2, &flag, MAP); /* write flag */ +if (cp->s1dat & SA_S1H_VEC) rq_setint (cp); /* if enb, intr */ +return; +} + +/* Set RQ interrupt */ + +void rq_setint (MSC *cp) +{ +cp->irq = 1; /* set ctrl int */ +SET_INT (RQ); /* set master int */ +return; +} + +/* Clear RQ interrupt */ + +void rq_clrint (MSC *cp) +{ +int32 i; +MSC *ncp; + +cp->irq = 0; /* clr ctrl int */ +for (i = 0; i < RQ_NUMCT; i++) { /* loop thru ctrls */ + ncp = rq_ctxmap[i]; /* get context */ + if (ncp->irq) { /* other interrupt? */ + SET_INT (RQ); /* yes, set master */ + return; } } +CLR_INT (RQ); /* no, clr master */ return; } @@ -1583,18 +1898,31 @@ return; int32 rq_inta (void) { -return (VEC_Q + ((rq_s1dat & SA_S1H_VEC) << 2)); /* prog vector */ +int32 i; +MSC *ncp; +DEVICE *dptr; +DIB *dibp; + +for (i = 0; i < RQ_NUMCT; i++) { /* loop thru ctrl */ + ncp = rq_ctxmap[i]; /* get context */ + if (ncp->irq) { /* ctrl int set? */ + dptr = rq_devmap[i]; /* get device */ + dibp = (DIB *) dptr->ctxt; /* get DIB */ + rq_clrint (ncp); /* clear int req */ + return dibp->vec; } } /* return vector */ +return 0; /* no intr req */ } /* Fatal error */ -t_bool rq_fatal (uint32 err) +t_bool rq_fatal (MSC *cp, uint32 err) { -if (DBG_LOG (LOG_RQ)) fprintf (sim_log, ">>RQ: fatal err=%X\n", err); -rq_reset (&rq_dev); /* reset device */ -rq_sa = SA_ER | err; /* SA = dead code */ -rq_csta = CST_DEAD; /* state = dead */ -rq_perr = err; /* save error */ +if (DBG_LOG (LOG_RQ)) + fprintf (sim_log, ">>RQ%c: fatal err=%X\n", 'A' + cp->cnum, err); +rq_reset (rq_devmap[cp->cnum]); /* reset device */ +cp->sa = SA_ER | err; /* SA = dead code */ +cp->csta = CST_DEAD; /* state = dead */ +cp->perr = err; /* save error */ return ERR; } @@ -1602,7 +1930,7 @@ return ERR; t_stat rq_set_wlk (UNIT *uptr, int32 val, char *cptr, void *desc) { -uint32 dtyp = GET_DTYPE (uptr -> flags); /* get drive type */ +uint32 dtyp = GET_DTYPE (uptr->flags); /* get drive type */ if (drv_tab[dtyp].flgs & RQDF_RO) return SCPE_NOFNC; /* not on read only */ return SCPE_OK; @@ -1612,10 +1940,10 @@ return SCPE_OK; t_stat rq_show_wlk (FILE *st, UNIT *uptr, int32 val, void *desc) { -uint32 dtyp = GET_DTYPE (uptr -> flags); /* get drive type */ +uint32 dtyp = GET_DTYPE (uptr->flags); /* get drive type */ if (drv_tab[dtyp].flgs & RQDF_RO) fprintf (st, "read only"); -else if (uptr -> flags & UNIT_WPRT) fprintf (st, "write locked"); +else if (uptr->flags & UNIT_WPRT) fprintf (st, "write locked"); else fprintf (st, "write enabled"); return SCPE_OK; } @@ -1626,8 +1954,8 @@ t_stat rq_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { uint32 dtyp = GET_DTYPE (val); -if (uptr -> flags & UNIT_ATT) return SCPE_ALATT; -uptr -> capac = drv_tab[GET_DTYPE (val)].lbn * RQ_NUMBY; +if (uptr->flags & UNIT_ATT) return SCPE_ALATT; +uptr->capac = drv_tab[dtyp].lbn * RQ_NUMBY; return SCPE_OK; } @@ -1635,13 +1963,14 @@ return SCPE_OK; t_stat rq_attach (UNIT *uptr, char *cptr) { -int32 dtyp = GET_DTYPE (uptr -> flags); +int32 dtyp = GET_DTYPE (uptr->flags); +MSC *cp = rq_ctxmap[uptr->cnum]; t_stat r; -uptr -> capac = drv_tab[dtyp].lbn * RQ_NUMBY; +uptr->capac = drv_tab[dtyp].lbn * RQ_NUMBY; r = attach_unit (uptr, cptr); if (r != SCPE_OK) return r; -if (rq_csta == CST_UP) uptr -> flags = uptr -> flags | UNIT_ATP; +if (cp->csta == CST_UP) uptr->flags = uptr->flags | UNIT_ATP; return SCPE_OK; } @@ -1653,8 +1982,8 @@ t_stat r; r = detach_unit (uptr); /* detach unit */ if (r != SCPE_OK) return r; -uptr -> flags = uptr -> flags & ~(UNIT_ONL | UNIT_ATP); /* clr onl, atn pend */ -uptr -> uf = 0; /* clr unit flgs */ +uptr->flags = uptr->flags & ~(UNIT_ONL | UNIT_ATP); /* clr onl, atn pend */ +uptr->uf = 0; /* clr unit flgs */ return SCPE_OK; } @@ -1662,38 +1991,47 @@ return SCPE_OK; t_stat rq_reset (DEVICE *dptr) { -int32 i, j; +int32 i, j, cidx; +UNIT *uptr; +MSC *cp; +DIB *dibp = (DIB *) dptr->ctxt; -rq_csta = CST_S1; /* init stage 1 */ -rq_s1dat = 0; /* no S1 data */ -rq_sa = SA_S1 | SA_S1C_Q22 | SA_S1C_DI | SA_S1C_MP; /* init SA val */ -rq_cflgs = CF_RPL; /* ctrl flgs off */ -rq_htmo = RQ_DHTMO + 1; /* default timeout */ -rq_hat = rq_htmo; /* default timer */ -rq_cq.ba = rq_cq.lnt = rq_cq.idx = 0; /* clr cmd ring */ -rq_rq.ba = rq_rq.lnt = rq_rq.idx = 0; /* clr rsp ring */ -rq_credits = (RQ_NPKTS / 2) - 1; /* init credits */ -rq_freq = 1; /* init free list */ +for (i = 0, cidx = -1; i < RQ_NUMCT; i++) { /* find ctrl num */ + if (rq_devmap[i] == dptr) cidx = i; } +if (cidx < 0) return SCPE_IERR; /* not found??? */ +cp = rq_ctxmap[cidx]; /* get context */ +cp->cnum = cidx; /* init index */ +cp->ubase = cidx * RQ_NUMDR; /* init unit base */ +cp->csta = CST_S1; /* init stage 1 */ +cp->s1dat = 0; /* no S1 data */ +dibp->vec = 0; /* no vector */ +cp->comm = 0; /* no comm region */ +cp->sa = SA_S1 | SA_S1C_Q22 | SA_S1C_DI | SA_S1C_MP; /* init SA val */ +cp->cflgs = CF_RPL; /* ctrl flgs off */ +cp->htmo = RQ_DHTMO; /* default timeout */ +cp->hat = cp->htmo; /* default timer */ +cp->cq.ba = cp->cq.lnt = cp->cq.idx = 0; /* clr cmd ring */ +cp->rq.ba = cp->rq.lnt = cp->rq.idx = 0; /* clr rsp ring */ +cp->credits = (RQ_NPKTS / 2) - 1; /* init credits */ +cp->freq = 1; /* init free list */ for (i = 0; i < RQ_NPKTS; i++) { /* all pkts free */ - if (i) rq_pkt[i].link = (i + 1) & RQ_M_NPKTS; - else rq_pkt[i].link = 0; - for (j = 0; j < RQ_PKT_SIZE_W; j++) rq_pkt[i].d[j] = 0; } -rq_rspq = 0; /* no q'd rsp pkts */ -rq_pbsy = 0; /* all pkts free */ -rq_pip = 0; /* not polling */ -CLR_INT (RQ); /* clr intr req */ -for (i = 0; i < RQ_NUMDR; i++) { /* init units */ - UNIT *uptr = rq_dev.units + i; - uint32 dtyp = GET_DTYPE (uptr -> flags); /* get drive type */ + if (i) cp->pak[i].link = (i + 1) & RQ_M_NPKTS; + else cp->pak[i].link = 0; + for (j = 0; j < RQ_PKT_SIZE_W; j++) cp->pak[i].d[j] = 0; } +cp->rspq = 0; /* no q'd rsp pkts */ +cp->pbsy = 0; /* all pkts free */ +cp->pip = 0; /* not polling */ +rq_clrint (cp); /* clr intr req */ +for (i = 0; i < (RQ_NUMDR + 2); i++) { /* init units */ + uptr = dptr->units + i; sim_cancel (uptr); /* clr activity */ - uptr -> flags = uptr -> flags & ~UNIT_ONL; /* not online */ - uptr -> uf = 0; /* ctlr unit flags */ - uptr -> cpkt = uptr -> pktq = 0; } /* clr pkt q's */ -sim_cancel (&rq_unit[RQ_TIMER]); /* clr timer thrd */ -sim_cancel (&rq_unit[RQ_QUEUE]); /* clr queue thrd */ + uptr->cnum = cidx; /* set ctrl index */ + uptr->flags = uptr->flags & ~(UNIT_ONL | UNIT_ATP); + uptr->uf = 0; /* clr unit flags */ + uptr->cpkt = uptr->pktq = 0; } /* clr pkt q's */ if (rqxb == NULL) rqxb = calloc (RQ_MAXFR >> 1, sizeof (unsigned int16)); if (rqxb == NULL) return SCPE_MEM; -return SCPE_OK; +return auto_config (0, 0); /* run autoconfig */ } /* Device bootstrap */ @@ -1701,9 +2039,10 @@ return SCPE_OK; #if defined (VM_PDP11) #define BOOT_START 016000 /* start */ -#define BOOT_ENTRY 016002 /* entry */ -#define BOOT_UNIT 016010 /* unit number */ -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) +#define BOOT_ENTRY (BOOT_START + 002) /* entry */ +#define BOOT_UNIT (BOOT_START + 010) /* unit number */ +#define BOOT_CSR (BOOT_START + 014) /* CSR */ +#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) static const uint16 boot_rom[] = { @@ -1771,21 +2110,23 @@ static const uint16 boot_rom[] = { 0000000 }; -t_stat rq_boot (int32 unitno) +t_stat rq_boot (int32 unitno, DEVICE *dptr) { int32 i; extern int32 saved_PC; extern uint16 *M; +DIB *dibp = (DIB *) dptr->ctxt; for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i]; M[BOOT_UNIT >> 1] = unitno & 3; +M[BOOT_CSR >> 1] = dibp->ba & DMASK; saved_PC = BOOT_ENTRY; return SCPE_OK; } #else -t_stat rq_boot (int32 unitno) +t_stat rq_boot (int32 unitno, DEVICE *dptr) { return SCPE_NOFNC; } @@ -1800,13 +2141,13 @@ uint16 d[2]; #if defined (VM_PDP11) fprintf (st, "ring, base = %o, index = %d, length = %d\n", - rp -> ba, rp -> idx >> 2, rp -> lnt >> 2); + rp->ba, rp->idx >> 2, rp->lnt >> 2); #else fprintf (st, "ring, base = %x, index = %d, length = %d\n", - rp -> ba, rp -> idx >> 2, rp -> lnt >> 2); + rp->ba, rp->idx >> 2, rp->lnt >> 2); #endif -for (i = 0; i < (rp -> lnt >> 2); i++) { - if (Map_ReadW (rp -> ba + (i << 2), 4, d, QB)) { +for (i = 0; i < (rp->lnt >> 2); i++) { + if (Map_ReadW (rp->ba + (i << 2), 4, d, MAP)) { fprintf (st, " %3d: non-existent memory\n", i); break; } desc = ((uint32) d[0]) | (((uint32) d[1]) << 16); @@ -1819,7 +2160,7 @@ for (i = 0; i < (rp -> lnt >> 2); i++) { return; } -void rq_show_pkt (FILE *st, int32 pkt) +void rq_show_pkt (FILE *st, MSC *cp, int32 pkt) { int32 i, j; uint32 cr = GETP (pkt, UQ_HCTC, CR); @@ -1832,9 +2173,9 @@ for (i = 0; i < RQ_SH_MAX; i = i + RQ_SH_PPL) { fprintf (st, " %2d:", i); for (j = i; j < (i + RQ_SH_PPL); j++) #if defined (VM_PDP11) - fprintf (st, " %06o", rq_pkt[pkt].d[j]); + fprintf (st, " %06o", cp->pak[pkt].d[j]); #else - fprintf (st, " %04x", rq_pkt[pkt].d[j]); + fprintf (st, " %04x", cp->pak[pkt].d[j]); #endif fprintf (st, "\n"); } @@ -1843,45 +2184,50 @@ return; t_stat rq_show_unitq (FILE *st, UNIT *uptr, int32 val, void *desc) { -int32 pkt, u = uptr - rq_dev.units; +MSC *cp = rq_ctxmap[uptr->cnum]; +DEVICE *dptr = rq_devmap[uptr->cnum]; +int32 pkt, u; -if (rq_csta != CST_UP) { +u = uptr - dptr->units; +if (cp->csta != CST_UP) { fprintf (st, "Controller is not initialized\n"); return SCPE_OK; } -if ((uptr -> flags & UNIT_ONL) == 0) { - if (uptr -> flags & UNIT_ATT) +if ((uptr->flags & UNIT_ONL) == 0) { + if (uptr->flags & UNIT_ATT) fprintf (st, "Unit %d is available\n", u); else fprintf (st, "Unit %d is offline\n", u); return SCPE_OK; } -if (uptr -> cpkt) { +if (uptr->cpkt) { fprintf (st, "Unit %d current ", u); - rq_show_pkt (st, uptr -> cpkt); - if (pkt = uptr -> pktq) { + rq_show_pkt (st, cp, uptr->cpkt); + if (pkt = uptr->pktq) { do { fprintf (st, "Unit %d queued ", u); - rq_show_pkt (st, pkt); } - while (pkt = rq_pkt[pkt].link); } } + rq_show_pkt (st, cp, pkt); } + while (pkt = cp->pak[pkt].link); } } else fprintf (st, "Unit %d queues are empty\n", u); return SCPE_OK; } t_stat rq_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc) { +MSC *cp = rq_ctxmap[uptr->cnum]; +DEVICE *dptr = rq_devmap[uptr->cnum]; int32 i, pkt; -if (rq_csta != CST_UP) { +if (cp->csta != CST_UP) { fprintf (st, "Controller is not initialized\n"); return SCPE_OK; } if (val & RQ_SH_RI) { - if (rq_pip) fprintf (st, "Polling in progress, host timer = %d\n", rq_hat); - else fprintf (st, "Host timer = %d\n", rq_hat); + if (cp->pip) fprintf (st, "Polling in progress, host timer = %d\n", cp->hat); + else fprintf (st, "Host timer = %d\n", cp->hat); fprintf (st, "Command "); - rq_show_ring (st, &rq_cq); + rq_show_ring (st, &cp->cq); fprintf (st, "Response "); - rq_show_ring (st, &rq_rq); + rq_show_ring (st, &cp->rq); } if (val & RQ_SH_FR) { - if (pkt = rq_freq) { - for (i = 0; pkt != 0; i++, pkt = rq_pkt[pkt].link) { + if (pkt = cp->freq) { + for (i = 0; pkt != 0; i++, pkt = cp->pak[pkt].link) { if (i == 0) fprintf (st, "Free queue = %d", pkt); else if ((i % 16) == 0) fprintf (st, ",\n %d", pkt); else fprintf (st, ", %d", pkt); } @@ -1889,15 +2235,15 @@ if (val & RQ_SH_FR) { else fprintf (st, "Free queue is empty\n"); } if (val & RQ_SH_RS) { - if (pkt = rq_rspq) { + if (pkt = cp->rspq) { do { fprintf (st, "Response "); - rq_show_pkt (st, pkt); } - while (pkt = rq_pkt[pkt].link); } + rq_show_pkt (st, cp, pkt); } + while (pkt = cp->pak[pkt].link); } else fprintf (st, "Response queue is empty\n"); } if (val & RQ_SH_UN) { for (i = 0; i < RQ_NUMDR; i++) - rq_show_unitq (st, &rq_unit[i], 0, NULL); + rq_show_unitq (st, dptr->units + i, 0, desc); } return SCPE_OK; } diff --git a/PDP11/pdp11_rx.c b/PDP11/pdp11_rx.c index 6dfae164..1c5b1797 100644 --- a/PDP11/pdp11_rx.c +++ b/PDP11/pdp11_rx.c @@ -25,6 +25,12 @@ rx RX11/RX01 floppy disk + 12-Oct-02 RMS Added autoconfigure support + 08-Oct-02 RMS Added variable address support to bootstrap + Added vector change/display support + Revised state machine based on RX211 + New data structures + Fixed reset of disabled device 26-Jan-02 RMS Revised bootstrap to conform to M9312 06-Jan-02 RMS Revised enable/disable support 30-Nov-01 RMS Added read only unit, extended SET/SHOW support @@ -57,10 +63,11 @@ #define IDLE 0 /* idle state */ #define RWDS 1 /* rw, sect next */ #define RWDT 2 /* rw, track next */ -#define FILL 3 /* fill buffer */ -#define EMPTY 4 /* empty buffer */ -#define CMD_COMPLETE 5 /* set done next */ -#define INIT_COMPLETE 6 /* init compl next */ +#define RWXFR 3 /* rw, transfer */ +#define FILL 4 /* fill buffer */ +#define EMPTY 5 /* empty buffer */ +#define CMD_COMPLETE 6 /* set done next */ +#define INIT_COMPLETE 7 /* init compl next */ #define RXCS_V_FUNC 1 /* function */ #define RXCS_M_FUNC 7 @@ -73,16 +80,21 @@ #define RXCS_ECODE 7 /* read error code */ #define RXCS_V_DRV 4 /* drive select */ #define RXCS_V_DONE 5 /* done */ +#define RXCS_V_IE 6 /* intr enable */ #define RXCS_V_TR 7 /* xfer request */ #define RXCS_V_INIT 14 /* init */ +#define RXCS_V_ERR 15 /* error */ #define RXCS_FUNC (RXCS_M_FUNC << RXCS_V_FUNC) #define RXCS_DRV (1u << RXCS_V_DRV) #define RXCS_DONE (1u << RXCS_V_DONE) +#define RXCS_IE (1u << RXCS_V_IE) #define RXCS_TR (1u << RXCS_V_TR) #define RXCS_INIT (1u << RXCS_V_INIT) -#define RXCS_ROUT (CSR_ERR+RXCS_TR+CSR_IE+RXCS_DONE) +#define RXCS_ERR (1u << RXCS_V_ERR) +#define RXCS_ROUT (RXCS_ERR+RXCS_TR+RXCS_IE+RXCS_DONE) #define RXCS_IMP (RXCS_ROUT+RXCS_DRV+RXCS_FUNC) -#define RXCS_RW (CSR_IE) /* read/write */ +#define RXCS_RW (RXCS_IE) /* read/write */ +#define RXCS_GETFNC(x) (((x) >> RXCS_V_FUNC) & RXCS_M_FUNC) #define RXES_CRC 0001 /* CRC error */ #define RXES_PAR 0002 /* parity error */ @@ -95,6 +107,8 @@ #define CALC_DA(t,s) (((t) * RX_NUMSC) + ((s) - 1)) * RX_NUMBY extern int32 int_req[IPL_HLVL]; +extern int32 int_vec[IPL_HLVL][32]; + int32 rx_csr = 0; /* control/status */ int32 rx_dbr = 0; /* data buffer */ int32 rx_esr = 0; /* error status */ @@ -106,15 +120,17 @@ int32 rx_stopioe = 1; /* stop on error */ int32 rx_cwait = 100; /* command time */ int32 rx_swait = 10; /* seek, per track */ int32 rx_xwait = 1; /* tr set time */ -unsigned int8 rx_buf[RX_NUMBY] = { 0 }; /* sector buffer */ -int32 bptr = 0; /* buffer pointer */ +uint8 rx_buf[RX_NUMBY] = { 0 }; /* sector buffer */ +static int32 bptr = 0; /* buffer pointer */ int32 rx_enb = 1; /* device enable */ +DEVICE rx_dev; t_stat rx_rd (int32 *data, int32 PA, int32 access); t_stat rx_wr (int32 data, int32 PA, int32 access); t_stat rx_svc (UNIT *uptr); t_stat rx_reset (DEVICE *dptr); -t_stat rx_boot (int32 unitno); +t_stat rx_boot (int32 unitno, DEVICE *dptr); +void rx_done (int esr_flags, int new_ecode); /* RX11 data structures @@ -124,7 +140,8 @@ t_stat rx_boot (int32 unitno); rx_mod RX modifier list */ -DIB rx_dib = { 1, IOBA_RX, IOLN_RX, &rx_rd, &rx_wr }; +DIB rx_dib = { IOBA_RX, IOLN_RX, &rx_rd, &rx_wr, + 1, IVCL (RX), VEC_RX, { NULL } }; UNIT rx_unit[] = { { UDATA (&rx_svc, @@ -139,39 +156,39 @@ REG rx_reg[] = { { ORDATA (RXERR, rx_ecode, 8) }, { ORDATA (RXTA, rx_track, 8) }, { ORDATA (RXSA, rx_sector, 8) }, - { ORDATA (STAPTR, rx_state, 3), REG_RO }, - { ORDATA (BUFPTR, bptr, 7) }, + { DRDATA (STAPTR, rx_state, 3), REG_RO }, + { DRDATA (BUFPTR, bptr, 7) }, { FLDATA (INT, IREQ (RX), INT_V_RX) }, - { FLDATA (ERR, rx_csr, CSR_V_ERR) }, + { FLDATA (ERR, rx_csr, RXCS_V_ERR) }, { FLDATA (TR, rx_csr, RXCS_V_TR) }, - { FLDATA (IE, rx_csr, CSR_V_IE) }, + { FLDATA (IE, rx_csr, RXCS_V_IE) }, { FLDATA (DONE, rx_csr, RXCS_V_DONE) }, { DRDATA (CTIME, rx_cwait, 24), PV_LEFT }, { DRDATA (STIME, rx_swait, 24), PV_LEFT }, { DRDATA (XTIME, rx_xwait, 24), PV_LEFT }, - { URDATA (FLG, rx_unit[0].flags, 2, 1, UNIT_V_WLK, RX_NUMDR, REG_HRO) }, { FLDATA (STOP_IOE, rx_stopioe, 0) }, { BRDATA (SBUF, rx_buf, 8, 8, RX_NUMBY) }, { ORDATA (DEVADDR, rx_dib.ba, 32), REG_HRO }, - { FLDATA (*DEVENB, rx_dib.enb, 0), REG_HRO }, + { ORDATA (DEVVEC, rx_dib.vec, 16), REG_HRO }, { NULL } }; MTAB rx_mod[] = { { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, &rx_dib }, - { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", - &set_enbdis, NULL, &rx_dib }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", - &set_enbdis, NULL, &rx_dib }, + &set_addr, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + &set_vec, &show_vec, NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE", + &set_addr_flt, NULL, NULL }, { 0 } }; DEVICE rx_dev = { "RX", rx_unit, rx_reg, rx_mod, RX_NUMDR, 8, 20, 1, 8, 8, NULL, NULL, &rx_reset, - &rx_boot, NULL, NULL }; + &rx_boot, NULL, NULL, + &rx_dib, DEV_FLTA | DEV_DISABLE | DEV_UBUS | DEV_QBUS }; /* I/O dispatch routine, I/O addresses 17777170 - 17777172 @@ -187,7 +204,7 @@ case 0: /* RXCS */ *data = rx_csr & RXCS_ROUT; break; case 1: /* RXDB */ - if (rx_state == EMPTY) { /* empty? */ + if ((rx_state == EMPTY) && (rx_csr & RXCS_TR)) {/* empty? */ sim_activate (&rx_unit[0], rx_xwait); rx_csr = rx_csr & ~RXCS_TR; } /* clear xfer */ *data = rx_dbr; /* return data */ @@ -218,16 +235,17 @@ case 0: /* RXCS */ rx_reset (&rx_dev); /* reset device */ return SCPE_OK; } /* end if init */ if ((data & CSR_GO) && (rx_state == IDLE)) { /* new function? */ - rx_csr = data & (CSR_IE + RXCS_DRV + RXCS_FUNC); + rx_csr = data & (RXCS_IE + RXCS_DRV + RXCS_FUNC); + drv = ((rx_csr & RXCS_DRV)? 1: 0); /* reselect drive */ bptr = 0; /* clear buf pointer */ - switch ((data >> RXCS_V_FUNC) & RXCS_M_FUNC) { + switch (RXCS_GETFNC (data)) { /* case on func */ case RXCS_FILL: rx_state = FILL; /* state = fill */ rx_csr = rx_csr | RXCS_TR; /* xfer is ready */ break; case RXCS_EMPTY: rx_state = EMPTY; /* state = empty */ - sim_activate (&rx_unit[0], rx_xwait); + sim_activate (&rx_unit[drv], rx_xwait); break; case RXCS_READ: case RXCS_WRITE: case RXCS_WRDEL: rx_state = RWDS; /* state = get sector */ @@ -236,12 +254,11 @@ case 0: /* RXCS */ break; default: rx_state = CMD_COMPLETE; /* state = cmd compl */ - drv = (data & RXCS_DRV) > 0; /* get drive number */ sim_activate (&rx_unit[drv], rx_cwait); break; } /* end switch func */ return SCPE_OK; } /* end if GO */ - if ((data & CSR_IE) == 0) CLR_INT (RX); - else if ((rx_csr & (RXCS_DONE + CSR_IE)) == RXCS_DONE) + if ((data & RXCS_IE) == 0) CLR_INT (RX); + else if ((rx_csr & (RXCS_DONE + RXCS_IE)) == RXCS_DONE) SET_INT (RX); rx_csr = (rx_csr & ~RXCS_RW) | (data & RXCS_RW); break; /* end case RXCS */ @@ -255,13 +272,9 @@ case 1: /* RXDB */ if ((PA & 1) || ((rx_state != IDLE) && ((rx_csr & RXCS_TR) == 0))) return SCPE_OK; /* if ~IDLE, need tr */ rx_dbr = data & 0377; /* save data */ - if ((rx_state == FILL) || (rx_state == RWDS)) { /* fill or sector? */ - sim_activate (&rx_unit[0], rx_xwait); /* sched event */ - rx_csr = rx_csr & ~RXCS_TR; } /* clear xfer */ - if (rx_state == RWDT) { /* track? */ - drv = (rx_csr & RXCS_DRV) > 0; /* get drive number */ - sim_activate (&rx_unit[drv], /* sched done */ - rx_swait * abs (rx_track - rx_unit[drv].TRACK)); + if ((rx_state != IDLE) && (rx_state != EMPTY)) { + drv = ((rx_csr & RXCS_DRV)? 1: 0); /* select drive */ + sim_activate (&rx_unit[drv], rx_xwait); /* sched event */ rx_csr = rx_csr & ~RXCS_TR; } /* clear xfer */ break; /* end case RXDB */ } /* end switch PA */ @@ -270,9 +283,10 @@ return SCPE_OK; /* Unit service; the action to be taken depends on the transfer state: - IDLE Should never get here, treat as unknown command - RWDS Just transferred sector, wait for track, set tr - RWDT Just transferred track, do read or write, finish command + IDLE Should never get here + RWDS Save sector, set TR, set RWDT + RWDT Save track, set RWXFR + RWXFR Read/write buffer FILL copy ir to rx_buf[bptr], advance ptr if bptr > max, finish command, else set tr EMPTY if bptr > max, finish command, else @@ -288,93 +302,104 @@ t_stat rx_svc (UNIT *uptr) { int32 i, func; t_addr da; -t_stat rval; -void rx_done (int new_dbr, int new_ecode); -rval = SCPE_OK; /* assume ok */ -func = (rx_csr >> RXCS_V_FUNC) & RXCS_M_FUNC; /* get function */ +func = RXCS_GETFNC (rx_csr); /* get function */ switch (rx_state) { /* case on state */ + case IDLE: /* idle */ - rx_done (rx_esr, 0); /* done */ - break; + return SCPE_IERR; /* done */ + case EMPTY: /* empty buffer */ - if (bptr >= RX_NUMBY) rx_done (rx_esr, 0); /* done all? */ + if (bptr >= RX_NUMBY) rx_done (0, 0); /* done all? */ else { rx_dbr = rx_buf[bptr]; /* get next */ bptr = bptr + 1; rx_csr = rx_csr | RXCS_TR; } /* set xfer */ break; + case FILL: /* fill buffer */ rx_buf[bptr] = rx_dbr; /* write next */ bptr = bptr + 1; if (bptr < RX_NUMBY) rx_csr = rx_csr | RXCS_TR; /* if more, set xfer */ - else rx_done (rx_esr, 0); /* else done */ + else rx_done (0, 0); /* else done */ break; + case RWDS: /* wait for sector */ rx_sector = rx_dbr & RX_M_SECTOR; /* save sector */ rx_csr = rx_csr | RXCS_TR; /* set xfer */ rx_state = RWDT; /* advance state */ - break; + return SCPE_OK; case RWDT: /* wait for track */ rx_track = rx_dbr & RX_M_TRACK; /* save track */ + rx_state = RWXFR; + sim_activate (uptr, /* sched done */ + rx_swait * abs (rx_track - uptr->TRACK)); + return SCPE_OK; +case RWXFR: + if ((uptr->flags & UNIT_BUF) == 0) { /* not buffered? */ + rx_done (0, 0110); /* done, error */ + return IORETURN (rx_stopioe, SCPE_UNATT); } if (rx_track >= RX_NUMTR) { /* bad track? */ - rx_done (rx_esr, 0040); /* done, error */ + rx_done (0, 0040); /* done, error */ break; } - uptr -> TRACK = rx_track; /* now on track */ + uptr->TRACK = rx_track; /* now on track */ if ((rx_sector == 0) || (rx_sector > RX_NUMSC)) { /* bad sect? */ - rx_done (rx_esr, 0070); /* done, error */ - break; } - if ((uptr -> flags & UNIT_BUF) == 0) { /* not buffered? */ - rx_done (rx_esr, 0110); /* done, error */ - rval = SCPE_UNATT; /* return error */ + rx_done (0, 0070); /* done, error */ break; } da = CALC_DA (rx_track, rx_sector); /* get disk address */ if (func == RXCS_WRDEL) rx_esr = rx_esr | RXES_DD; /* del data? */ if (func == RXCS_READ) { /* read? */ for (i = 0; i < RX_NUMBY; i++) - rx_buf[i] = *(((int8 *) uptr -> filebuf) + da + i); } - else { if (uptr -> flags & UNIT_WPRT) { /* write and locked? */ - rx_esr = rx_esr | RXES_WLK; /* flag error */ - rx_done (rx_esr, 0100); /* done, error */ - break; } + rx_buf[i] = *(((int8 *) uptr->filebuf) + da + i); } + else { if (uptr->flags & UNIT_WPRT) { /* write and locked? */ + rx_done (RXES_WLK, 0100); /* done, error */ + break; } for (i = 0; i < RX_NUMBY; i++) /* write */ - *(((int8 *) uptr -> filebuf) + da + i) = rx_buf[i]; + *(((int8 *) uptr->filebuf) + da + i) = rx_buf[i]; da = da + RX_NUMBY; - if (da > uptr -> hwmark) uptr -> hwmark = da; } - rx_done (rx_esr, 0); /* done */ + if (da > uptr->hwmark) uptr->hwmark = da; } + rx_done (0, 0); /* done */ break; + case CMD_COMPLETE: /* command complete */ - if (func == RXCS_ECODE) rx_done (rx_ecode, 0); - else if (uptr -> flags & UNIT_ATT) rx_done (rx_esr | RXES_DRDY, 0); - else rx_done (rx_esr, 0); + if (func == RXCS_ECODE) { /* read ecode? */ + rx_dbr = rx_ecode; /* set dbr */ + rx_done (0, -1); } /* don't update */ + else rx_done (0, 0); break; + case INIT_COMPLETE: /* init complete */ rx_unit[0].TRACK = 1; /* drive 0 to trk 1 */ rx_unit[1].TRACK = 0; /* drive 1 to trk 0 */ if ((rx_unit[0].flags & UNIT_BUF) == 0) { /* not buffered? */ - rx_done (rx_esr | RXES_ID, 0010); /* init done, error */ + rx_done (RXES_ID, 0010); /* init done, error */ break; } da = CALC_DA (1, 1); /* track 1, sector 1 */ for (i = 0; i < RX_NUMBY; i++) /* read sector */ - rx_buf[i] = *(((int8 *) uptr -> filebuf) + da + i); - rx_done (rx_esr | RXES_ID | RXES_DRDY, 0); /* set done */ + rx_buf[i] = *(((int8 *) uptr->filebuf) + da + i); + rx_done (RXES_ID, 0); /* set done */ if ((rx_unit[1].flags & UNIT_ATT) == 0) rx_ecode = 0020; break; } /* end case state */ -return IORETURN (rx_stopioe, rval); +return SCPE_OK; } /* Command complete. Set done and put final value in interface register, request interrupt if needed, return to IDLE state. */ -void rx_done (int32 new_dbr, int32 new_ecode) +void rx_done (int32 esr_flags, int32 new_ecode) { -rx_csr = rx_csr | RXCS_DONE; /* set done */ -if (rx_csr & CSR_IE) SET_INT (RX); /* if ie, intr */ -rx_dbr = new_dbr; /* update RXDB */ -if (new_ecode != 0) { /* test for error */ - rx_ecode = new_ecode; - rx_csr = rx_csr | CSR_ERR; } +int32 drv = (rx_csr & RXCS_DRV)? 1: 0; + rx_state = IDLE; /* now idle */ +rx_csr = rx_csr | RXCS_DONE; /* set done */ +if (rx_csr & RXCS_IE) SET_INT (RX); /* if ie, intr */ +rx_esr = (rx_esr | esr_flags) & ~RXES_DRDY; +if (rx_unit[drv].flags & UNIT_ATT) + rx_esr = rx_esr | RXES_DRDY; +if (new_ecode > 0) rx_csr = rx_csr | RXCS_ERR; /* test for error */ +if (new_ecode < 0) return; /* don't update? */ +rx_ecode = new_ecode; /* update ecode */ +rx_dbr = rx_esr; /* update RXDB */ return; } @@ -386,25 +411,29 @@ t_stat rx_reset (DEVICE *dptr) { rx_csr = rx_dbr = 0; /* clear regs */ rx_esr = rx_ecode = 0; /* clear error */ +rx_track = rx_sector = 0; /* clear addr */ +rx_state = IDLE; /* ctrl idle */ CLR_INT (RX); /* clear int req */ sim_cancel (&rx_unit[1]); /* cancel drive 1 */ -if (rx_unit[0].flags & UNIT_BUF) { /* attached? */ +if (dptr->flags & DEV_DIS) sim_cancel (&rx_unit[0]); /* disabled? */ +else if (rx_unit[0].flags & UNIT_BUF) { /* attached? */ rx_state = INIT_COMPLETE; /* yes, sched init */ sim_activate (&rx_unit[0], rx_swait * abs (1 - rx_unit[0].TRACK)); } -else rx_done (rx_esr | RXES_ID, 0010); /* no, error */ -return SCPE_OK; +else rx_done (0, 0010); /* no, error */ +return auto_config (0, 0); /* run autoconfig */ } /* Device bootstrap */ #define BOOT_START 02000 /* start */ -#define BOOT_ENTRY 02002 /* entry */ -#define BOOT_UNIT 02010 /* unit number */ -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) +#define BOOT_ENTRY (BOOT_START + 002) /* entry */ +#define BOOT_UNIT (BOOT_START + 010) /* unit number */ +#define BOOT_CSR (BOOT_START + 026) /* CSR */ +#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) -static const int32 boot_rom[] = { +static const uint16 boot_rom[] = { 042130, /* "XD" */ - 0012706, 0002000, /* MOV #2000, SP */ + 0012706, BOOT_START, /* MOV #boot_start, SP */ 0012700, 0000000, /* MOV #unit, R0 ; unit number */ 0010003, /* MOV R0, R3 */ 0006303, /* ASL R3 */ @@ -438,7 +467,7 @@ static const int32 boot_rom[] = { 0005007 /* CLR R7 */ }; -t_stat rx_boot (int32 unitno) +t_stat rx_boot (int32 unitno, DEVICE *dptr) { int32 i; extern int32 saved_PC; @@ -446,6 +475,7 @@ extern uint16 *M; for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i]; M[BOOT_UNIT >> 1] = unitno & RX_M_NUMDR; +M[BOOT_CSR >> 1] = rx_dib.ba & DMASK; saved_PC = BOOT_ENTRY; return SCPE_OK; } diff --git a/PDP11/pdp11_ry.c b/PDP11/pdp11_ry.c new file mode 100644 index 00000000..40c6f5a2 --- /dev/null +++ b/PDP11/pdp11_ry.c @@ -0,0 +1,631 @@ +/* pdp11_ry.c: RY11/RX02 floppy disk simulator + + Copyright (c) 1993-2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + ry RY11/RX02 floppy disk + + 12-Oct-02 RMS Added autoconfigure support + + An RX02 diskette consists of 77 tracks, each with 26 sectors of 256B. + Tracks are numbered 0-76, sectors 1-26. +*/ + +#if defined (USE_INT64) /* PDP-10 !! */ +#include "pdp10_defs.h" +#define VM_PDP10 1 +extern int32 int_req; +extern int32 int_vec[32]; +#else +#include "pdp11_defs.h" /* PDP-11 */ +#define VM_PDP11 1 +extern int32 int_req[IPL_HLVL]; +extern int32 int_vec[IPL_HLVL][32]; +#endif + +#define RX_NUMTR 77 /* tracks/disk */ +#define RX_M_TRACK 0377 +#define RX_NUMSC 26 /* sectors/track */ +#define RX_M_SECTOR 0177 +#define RX_NUMBY 128 +#define RX_SIZE (RX_NUMTR * RX_NUMSC * RX_NUMBY) +#define RY_NUMBY 256 /* bytes/sector */ +#define RY_SIZE (RX_NUMTR * RX_NUMSC * RY_NUMBY) +#define RX_NUMDR 2 /* drives/controller */ +#define RX_M_NUMDR 01 +#define UNIT_V_WLK (UNIT_V_UF) /* write locked */ +#define UNIT_V_DEN (UNIT_V_UF + 1) /* double density */ +#define UNIT_V_AUTO (UNIT_V_UF + 2) /* autosize */ +#define UNIT_WLK (1u << UNIT_V_WLK) +#define UNIT_DEN (1u << UNIT_V_DEN) +#define UNIT_AUTO (1u << UNIT_V_AUTO) +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ + +#define IDLE 0 /* idle state */ +#define RWDS 1 /* rw, sect next */ +#define RWDT 2 /* rw, track next */ +#define RWXFR 3 /* rw, transfer */ +#define FEWC 4 /* fill empty, wc next */ +#define FEBA 5 /* fill empty, ba next */ +#define FEXFR 6 /* fill empty, transfer */ +#define SDCNF 7 /* set dens, conf next */ +#define SDXFR 8 /* set dens, transfer */ +#define ESBA 9 /* ext sta, ba next */ +#define ESXFR 10 /* ext sta, transfer */ +#define CMD_COMPLETE 11 /* set done next */ +#define INIT_COMPLETE 12 /* init compl next */ + +#define RYCS_V_FUNC 1 /* function */ +#define RYCS_M_FUNC 7 +#define RYCS_FILL 0 /* fill buffer */ +#define RYCS_EMPTY 1 /* empty buffer */ +#define RYCS_WRITE 2 /* write sector */ +#define RYCS_READ 3 /* read sector */ +#define RYCS_SDEN 4 /* set density */ +#define RYCS_RYES 5 /* read status */ +#define RYCS_WRDEL 6 /* write del data */ +#define RYCS_ESTAT 7 /* read ext status */ +#define RYCS_V_DRV 4 /* drive select */ +#define RYCS_V_DONE 5 /* done */ +#define RYCS_V_IE 6 /* int enable */ +#define RYCS_V_TR 7 /* xfer request */ +#define RYCS_V_DEN 8 /* density select */ +#define RYCS_V_RY 11 /* RX02 flag */ +#define RYCS_V_UAE 12 /* addr ext */ +#define RYCS_M_UAE 03 +#define RYCS_V_INIT 14 /* init */ +#define RYCS_V_ERR 15 /* error */ +#define RYCS_FUNC (RYCS_M_FUNC << RYCS_V_FUNC) +#define RYCS_DRV (1u << RYCS_V_DRV) +#define RYCS_DONE (1u << RYCS_V_DONE) +#define RYCS_IE (1u << RYCS_V_IE) +#define RYCS_TR (1u << RYCS_V_TR) +#define RYCS_DEN (1u << RYCS_V_DEN) +#define RYCS_RY (1u << RYCS_V_RY) +#define RYCS_UAE (RYCS_M_UAE << RYCS_V_UAE) +#define RYCS_INIT (1u << RYCS_V_INIT) +#define RYCS_ERR (1u << RYCS_V_ERR) +#define RYCS_IMP (RYCS_ERR+RYCS_UAE+RYCS_DEN+RYCS_TR+RYCS_IE+\ + RYCS_DONE+RYCS_DRV+RYCS_FUNC) +#define RYCS_RW (RYCS_UAE+RYCS_DEN+RYCS_IE+RYCS_DRV+RYCS_FUNC) +#define RYCS_GETFNC(x) (((x) >> RYCS_V_FUNC) & RYCS_M_FUNC) +#define RYCS_GETUAE(x) (((x) >> RYCS_V_UAE) & RYCS_M_UAE) + +#define RYES_CRC 00001 /* CRC error NI */ +#define RYES_ID 00004 /* init done */ +#define RYES_ACLO 00010 /* ACLO NI */ +#define RYES_DERR 00020 /* density err */ +#define RYES_DDEN 00040 /* drive density */ +#define RYES_DD 00100 /* deleted data */ +#define RYES_DRDY 00200 /* drive ready */ +#define RYES_USEL 00400 /* unit selected */ +#define RYES_WCO 02000 /* wc overflow */ +#define RYES_NXM 04000 /* nxm */ +#define RYES_ERR (RYES_NXM|RYES_WCO|RYES_DERR|RYES_ACLO|RYES_CRC) + +#define TRACK u3 /* current track */ +#define CALC_DA(t,s,b) (((t) * RX_NUMSC) + ((s) - 1)) * b + +int32 ry_csr = 0; /* control/status */ +int32 ry_dbr = 0; /* data buffer */ +int32 ry_esr = 0; /* error status */ +int32 ry_ecode = 0; /* error code */ +int32 ry_track = 0; /* desired track */ +int32 ry_sector = 0; /* desired sector */ +int32 ry_ba = 0; /* bus addr */ +int32 ry_wc = 0; /* word count */ +int32 ry_state = IDLE; /* controller state */ +int32 ry_stopioe = 1; /* stop on error */ +int32 ry_cwait = 100; /* command time */ +int32 ry_swait = 10; /* seek, per track */ +int32 ry_xwait = 1; /* tr set time */ +uint8 rx2xb[RY_NUMBY] = { 0 }; /* sector buffer */ +int32 ry_enb = 0; /* device enable */ + +DEVICE ry_dev; +t_stat ry_rd (int32 *data, int32 PA, int32 access); +t_stat ry_wr (int32 data, int32 PA, int32 access); +t_stat ry_svc (UNIT *uptr); +t_stat ry_reset (DEVICE *dptr); +t_stat ry_boot (int32 unitno, DEVICE *dptr); +void ry_done (int esr_flags, int new_ecode); +t_stat ry_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat ry_attach (UNIT *uptr, char *cptr); + +/* RY11 data structures + + ry_dev RY device descriptor + ry_unit RY unit list + ry_reg RY register list + ry_mod RY modifier list +*/ + +DIB ry_dib = { IOBA_RY, IOLN_RY, &ry_rd, &ry_wr, + 1, IVCL (RY), VEC_RY, { NULL } }; + +UNIT ry_unit[] = { + { UDATA (&ry_svc, UNIT_DEN+ + UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, RY_SIZE) }, + { UDATA (&ry_svc, UNIT_DEN+ + UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, RY_SIZE) } }; + +REG ry_reg[] = { + { ORDATA (RYCS, ry_csr, 16) }, + { ORDATA (RYBA, ry_ba, 16) }, + { ORDATA (RYWC, ry_wc, 8) }, + { ORDATA (RYDB, ry_dbr, 16) }, + { ORDATA (RYES, ry_esr, 12) }, + { ORDATA (RYERR, ry_ecode, 8) }, + { ORDATA (RYTA, ry_track, 8) }, + { ORDATA (RYSA, ry_sector, 8) }, + { DRDATA (STAPTR, ry_state, 4), REG_RO }, + { FLDATA (INT, IREQ (RY), INT_V_RY) }, + { FLDATA (ERR, ry_csr, RYCS_V_ERR) }, + { FLDATA (TR, ry_csr, RYCS_V_TR) }, + { FLDATA (IE, ry_csr, RYCS_V_IE) }, + { FLDATA (DONE, ry_csr, RYCS_V_DONE) }, + { DRDATA (CTIME, ry_cwait, 24), PV_LEFT }, + { DRDATA (STIME, ry_swait, 24), PV_LEFT }, + { DRDATA (XTIME, ry_xwait, 24), PV_LEFT }, + { BRDATA (SBUF, rx2xb, 8, 8, RY_NUMBY) }, + { FLDATA (STOP_IOE, ry_stopioe, 0) }, + { ORDATA (DEVADDR, ry_dib.ba, 32), REG_HRO }, + { ORDATA (DEVVEC, ry_dib.vec, 16), REG_HRO }, + { NULL } }; + +MTAB ry_mod[] = { + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, + { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, + { (UNIT_DEN+UNIT_ATT), UNIT_ATT, "single density", NULL, NULL }, + { (UNIT_DEN+UNIT_ATT), (UNIT_DEN+UNIT_ATT), "double density", NULL, NULL }, + { (UNIT_AUTO+UNIT_DEN+UNIT_ATT), 0, "single density", NULL, NULL }, + { (UNIT_AUTO+UNIT_DEN+UNIT_ATT), UNIT_DEN, "double density", NULL, NULL }, + { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL }, + { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL }, + { (UNIT_AUTO+UNIT_DEN), 0, NULL, "SINGLE", &ry_set_size }, + { (UNIT_AUTO+UNIT_DEN), UNIT_DEN, NULL, "DOUBLE", &ry_set_size }, + { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + &set_vec, &show_vec, NULL }, +#if defined (VM_PDP11) + { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE", + &set_addr_flt, NULL, NULL }, +#endif + { 0 } }; + +DEVICE ry_dev = { + "RY", ry_unit, ry_reg, ry_mod, + RX_NUMDR, 8, 20, 1, 8, 8, + NULL, NULL, &ry_reset, + &ry_boot, &ry_attach, NULL, + &ry_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS }; + +/* I/O dispatch routine, I/O addresses 17777170 - 17777172 + + 17777170 floppy CSR + 17777172 floppy data register +*/ + +t_stat ry_rd (int32 *data, int32 PA, int32 access) +{ +switch ((PA >> 1) & 1) { /* decode PA<1> */ +case 0: /* RYCS */ + ry_csr = (ry_csr & RYCS_IMP) | RYCS_RY; /* clear junk */ + *data = ry_csr; + break; +case 1: /* RYDB */ + *data = ry_dbr; /* return data */ + break; } /* end switch PA */ +return SCPE_OK; +} + +t_stat ry_wr (int32 data, int32 PA, int32 access) +{ +int32 drv; + +switch ((PA >> 1) & 1) { /* decode PA<1> */ + +/* Writing RYCS, three cases: + 1. Writing INIT, reset device + 2. Idle and writing new function + - clear error, done, transfer ready, int req + - save int enable, function, drive + - start new function + 3. Otherwise, write IE and update interrupts +*/ + +case 0: /* RYCS */ + ry_csr = (ry_csr & RYCS_IMP) | RYCS_RY; /* clear junk */ + if (access == WRITEB) data = (PA & 1)? /* write byte? */ + (ry_csr & 0377) | (data << 8): (ry_csr & ~0377) | data; + if (data & RYCS_INIT) { /* initialize? */ + ry_reset (&ry_dev); /* reset device */ + return SCPE_OK; } /* end if init */ + if ((data & CSR_GO) && (ry_state == IDLE)) { /* new function? */ + ry_csr = (data & RYCS_RW) | RYCS_RY; + drv = ((ry_csr & RYCS_DRV)? 1: 0); /* reselect drv */ + switch (RYCS_GETFNC (data)) { + case RYCS_FILL: case RYCS_EMPTY: + ry_state = FEWC; /* state = get wc */ + ry_csr = ry_csr | RYCS_TR; /* xfer is ready */ + break; + case RYCS_SDEN: + ry_state = SDCNF; /* state = get conf */ + ry_csr = ry_csr | RYCS_TR; /* xfer is ready */ + break; + case RYCS_ESTAT: + ry_state = ESBA; /* state = get ba */ + ry_csr = ry_csr | RYCS_TR; /* xfer is ready */ + break; + case RYCS_READ: case RYCS_WRITE: case RYCS_WRDEL: + ry_state = RWDS; /* state = get sector */ + ry_csr = ry_csr | RYCS_TR; /* xfer is ready */ + ry_esr = ry_esr & RYES_ID; /* clear errors */ + ry_ecode = 0; + break; + default: + ry_state = CMD_COMPLETE; /* state = cmd compl */ + sim_activate (&ry_unit[drv], ry_cwait); + break; } /* end switch func */ + return SCPE_OK; } /* end if GO */ + if ((data & RYCS_IE) == 0) CLR_INT (RY); + else if ((ry_csr & (RYCS_DONE + RYCS_IE)) == RYCS_DONE) + SET_INT (RY); + ry_csr = (ry_csr & ~RYCS_RW) | (data & RYCS_RW); + break; /* end case RYCS */ + +/* Accessing RYDB, two cases: + 1. Write idle, write + 2. Write not idle and TR set, state dependent +*/ + +case 1: /* RYDB */ + if ((PA & 1) || ((ry_state != IDLE) && ((ry_csr & RYCS_TR) == 0))) + return SCPE_OK; /* if ~IDLE, need tr */ + ry_dbr = data; /* save data */ + if (ry_state != IDLE) { + drv = ((ry_csr & RYCS_DRV)? 1: 0); /* select drv */ + sim_activate (&ry_unit[drv], ry_xwait); /* sched event */ + ry_csr = ry_csr & ~RYCS_TR; } /* clear xfer */ + break; /* end case RYDB */ + } /* end switch PA */ +return SCPE_OK; +} + +/* Unit service; the action to be taken depends on the transfer state: + + IDLE Should never get here + FEWC Save word count, set TR, set FEBA + FEBA Save bus address, set FEXFR + FEXFR Fill/empty buffer + RWDS Save sector, set TR, set RWDT + RWDT Save track, set RWXFR + RWXFR Read/write buffer + SDCNF Check confirmation, set SDXFR + SDXFR Erase disk + CMD_COMPLETE copy requested data to ir, finish command + INIT_COMPLETE read drive 0, track 1, sector 1 to buffer, finish command +*/ + +t_stat ry_svc (UNIT *uptr) +{ +int32 i, t, func, bps; +static uint8 estat[8]; +t_addr ba, da; + +func = RYCS_GETFNC (ry_csr); /* get function */ +bps = (ry_csr & RYCS_DEN)? RY_NUMBY: RX_NUMBY; /* get sector size */ +ba = (RYCS_GETUAE (ry_csr) << 16) | ry_ba; /* get mem addr */ +switch (ry_state) { /* case on state */ + +case IDLE: /* idle */ + return SCPE_IERR; +case FEWC: /* word count */ + ry_wc = ry_dbr & 0377; /* save WC */ + ry_csr = ry_csr | RYCS_TR; /* set TR */ + ry_state = FEBA; /* next state */ + return SCPE_OK; +case FEBA: /* buffer address */ + ry_ba = ry_dbr; /* save buf addr */ + ry_state = FEXFR; /* next state */ + sim_activate (uptr, ry_cwait); /* schedule xfer */ + return SCPE_OK; +case FEXFR: /* transfer */ + if ((ry_wc << 1) > bps) { /* wc too big? */ + ry_done (RYES_WCO, 0230); /* error */ + break; } + if (func == RYCS_FILL) { /* fill? read */ + for (i = 0; i < RY_NUMBY; i++) rx2xb[i] = 0; + t = Map_ReadB (ba, ry_wc << 1, rx2xb, MAP); } + else t = Map_WriteB (ba, ry_wc << 1, rx2xb, MAP); + ry_wc = t >> 1; /* adjust wc */ + ry_done (t? RYES_NXM: 0, 0); /* done */ + break; + +case RWDS: /* wait for sector */ + ry_sector = ry_dbr & RX_M_SECTOR; /* save sector */ + ry_csr = ry_csr | RYCS_TR; /* set xfer */ + ry_state = RWDT; /* advance state */ + return SCPE_OK; +case RWDT: /* wait for track */ + ry_track = ry_dbr & RX_M_TRACK; /* save track */ + ry_state = RWXFR; /* next state */ + sim_activate (uptr, /* sched xfer */ + ry_swait * abs (ry_track - uptr->TRACK)); + return SCPE_OK; +case RWXFR: /* read/write */ + if ((uptr->flags & UNIT_BUF) == 0) { /* not buffered? */ + ry_done (0, 0110); /* done, error */ + return IORETURN (ry_stopioe, SCPE_UNATT); } + if (ry_track >= RX_NUMTR) { /* bad track? */ + ry_done (0, 0040); /* done, error */ + break; } + uptr->TRACK = ry_track; /* now on track */ + if ((ry_sector == 0) || (ry_sector > RX_NUMSC)) { /* bad sect? */ + ry_done (0, 0070); /* done, error */ + break; } + if (((uptr->flags & UNIT_DEN) != 0) ^ + ((ry_csr & RYCS_DEN) != 0)) { /* densities agree? */ + ry_done (RYES_DERR, 0240); /* no, error */ + break; } + da = CALC_DA (ry_track, ry_sector, bps); /* get disk address */ + if (func == RYCS_WRDEL) ry_esr = ry_esr | RYES_DD; /* del data? */ + if (func == RYCS_READ) { /* read? */ + for (i = 0; i < bps; i++) + rx2xb[i] = *(((int8 *) uptr->filebuf) + da + i); } + else { if (uptr->flags & UNIT_WPRT) { /* write and locked? */ + ry_done (0, 0100); /* done, error */ + break; } + for (i = 0; i < bps; i++) /* write */ + *(((int8 *) uptr->filebuf) + da + i) = rx2xb[i]; + da = da + bps; + if (da > uptr->hwmark) uptr->hwmark = da; } + ry_done (0, 0); /* done */ + break; + +case SDCNF: /* confirm set density */ + if ((ry_dbr & 0377) != 0111) { /* confirmed? */ + ry_done (0, 0250); /* no, error */ + break; } + ry_state = SDXFR; /* next state */ + sim_activate (uptr, ry_cwait * 100); /* schedule operation */ + break; +case SDXFR: /* erase disk */ + for (i = 0; i < (int32) uptr->capac; i++) + *(((int8 *) uptr->filebuf) + i) = 0; + uptr->hwmark = uptr->capac; + if (ry_csr & RYCS_DEN) uptr->flags = uptr->flags | UNIT_DEN; + else uptr->flags = uptr->flags & ~UNIT_DEN; + ry_done (0, 0); + break; + +case ESBA: + ry_ba = ry_dbr; /* save WC */ + ry_state = ESXFR; /* next state */ + sim_activate (uptr, ry_cwait); /* schedule xfer */ + return SCPE_OK; +case ESXFR: + estat[0] = ry_ecode; /* fill 8B status */ + estat[1] = ry_wc; + estat[2] = ry_unit[0].TRACK; + estat[3] = ry_unit[1].TRACK; + estat[4] = ry_track; + estat[5] = ry_sector; + estat[6] = ((ry_csr & RYCS_DRV)? 0200: 0) | + ((ry_unit[1].flags & UNIT_DEN)? 0100: 0) | + ((uptr->flags & UNIT_ATT)? 0040: 0) | + ((ry_unit[0].flags & UNIT_DEN)? 0020: 0) | + ((ry_csr & RYCS_DEN)? 0001: 0); + estat[7] = uptr->TRACK; + t = Map_WriteB (ba, 8, estat, MAP); /* DMA to memory */ + ry_done (t? RYES_NXM: 0, 0); /* done */ + break; + +case CMD_COMPLETE: /* command complete */ + ry_done (0, 0); + break; + +case INIT_COMPLETE: /* init complete */ + ry_unit[0].TRACK = 1; /* drive 0 to trk 1 */ + ry_unit[1].TRACK = 0; /* drive 1 to trk 0 */ + if ((uptr->flags & UNIT_BUF) == 0) { /* not buffered? */ + ry_done (RYES_ID, 0010); /* init done, error */ + break; } + da = CALC_DA (1, 1, bps); /* track 1, sector 1 */ + for (i = 0; i < bps; i++) /* read sector */ + rx2xb[i] = *(((int8 *) uptr->filebuf) + da + i); + ry_done (RYES_ID, 0); /* set done */ + if ((ry_unit[1].flags & UNIT_ATT) == 0) ry_ecode = 0020; + break; } /* end case state */ + +return SCPE_OK; +} + +/* Command complete. Set done and put final value in interface register, + request interrupt if needed, return to IDLE state. +*/ + +void ry_done (int32 esr_flags, int32 new_ecode) +{ +int32 drv = (ry_csr & RYCS_DRV)? 1: 0; + +ry_state = IDLE; /* now idle */ +ry_csr = ry_csr | RYCS_DONE; /* set done */ +if (ry_csr & CSR_IE) SET_INT (RY); /* if ie, intr */ +ry_esr = (ry_esr | esr_flags) & ~(RYES_USEL|RYES_DDEN|RYES_DRDY); +if (drv) ry_esr = ry_esr | RYES_USEL; /* updates RYES */ +if (ry_unit[drv].flags & UNIT_ATT) { + ry_esr = ry_esr | RYES_DRDY; + if (ry_unit[drv].flags & UNIT_DEN) + ry_esr = ry_esr | RYES_DDEN; } +if ((new_ecode > 0) || (ry_esr & RYES_ERR)) /* test for error */ + ry_csr = ry_csr | RYCS_ERR; +ry_ecode = new_ecode; /* update ecode */ +ry_dbr = ry_esr; /* update RYDB */ +return; +} + +/* Device initialization. The RY is one of the few devices that schedules + an I/O transfer as part of its initialization. +*/ + +t_stat ry_reset (DEVICE *dptr) +{ +ry_csr = ry_dbr = 0; /* clear registers */ +ry_esr = ry_ecode = 0; /* clear error */ +ry_ba = ry_wc = 0; /* clear wc, ba */ +ry_track = ry_sector = 0; /* clear trk, sector */ +ry_state = IDLE; /* ctrl idle */ +CLR_INT (RY); /* clear int req */ +sim_cancel (&ry_unit[1]); /* cancel drive 1 */ +if (dptr->flags & UNIT_DIS) sim_cancel (&ry_unit[0]); /* disabled? */ +else if (ry_unit[0].flags & UNIT_BUF) { /* attached? */ + ry_state = INIT_COMPLETE; /* yes, sched init */ + sim_activate (&ry_unit[0], ry_swait * abs (1 - ry_unit[0].TRACK)); } +else ry_done (RYES_ID, 0010); /* no, error */ +return auto_config (0, 0); /* run autoconfig */ +} + +/* Attach routine */ + +t_stat ry_attach (UNIT *uptr, char *cptr) +{ +int32 p; +t_stat r; + +uptr->capac = (uptr->flags & UNIT_DEN)? RY_SIZE: RX_SIZE; +r = attach_unit (uptr, cptr); +if ((r != SCPE_OK) || ((uptr->flags & UNIT_AUTO) == 0)) return r; +if (fseek (uptr->fileref, 0, SEEK_END)) return SCPE_OK; +if ((p = ftell (uptr->fileref)) == 0) return SCPE_OK; +if (p > RX_SIZE) { + uptr->flags = uptr->flags | UNIT_DEN; + uptr->capac = RY_SIZE; } +else { uptr->flags = uptr->flags & ~UNIT_DEN; + uptr->capac = RX_SIZE; } +return SCPE_OK; +} + +/* Set size routine */ + +t_stat ry_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (uptr->flags & UNIT_ATT) return SCPE_ALATT; +uptr->capac = val? RY_SIZE: RX_SIZE; +return SCPE_OK; +} + +/* Device bootstrap */ + +#if defined (VM_PDP11) + +#define BOOT_START 02000 /* start */ +#define BOOT_ENTRY (BOOT_START + 002) /* entry */ +#define BOOT_UNIT (BOOT_START + 010) /* unit number */ +#define BOOT_CSR (BOOT_START + 026) /* CSR */ +#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) + +static const uint16 boot_rom[] = { + 042131, /* "YD" */ + 0012706, BOOT_START, /* MOV #boot_start, SP */ + 0012700, 0000000, /* MOV #unit, R0 ; unit number */ + 0010003, /* MOV R0, R3 */ + 0006303, /* ASL R3 */ + 0006303, /* ASL R3 */ + 0006303, /* ASL R3 */ + 0006303, /* ASL R3 */ + 0012701, 0177170, /* MOV #RYCS, R1 ; csr */ + 0005002, /* CLR R2 ; ba */ + 0005004, /* CLR R4 ; density */ + 0012705, 0000001, /* MOV #1, R5 ; sector */ + 0005104, /* DN: COM R4 ; compl dens */ + 0042704, 0177377, /* BIC #177377, R4 ; clr rest */ + 0032711, 0000040, /* RD: BIT #40, (R1) ; ready? */ + 0001775, /* BEQ .-4 */ + 0012746, 0000007, /* MOV #READ+GO, -(SP) */ + 0050416, /* BIS R4, (SP) ; or density */ + 0012611, /* MOV (SP)+, (R1) ; read & go */ + 0105711, /* TSTB (R1) ; xfr ready? */ + 0100376, /* BPL .-2 */ + 0010561, 0000002, /* MOV R5, 2(R1) ; sector */ + 0105711, /* TSTB (R1) ; xfr ready? */ + 0100376, /* BPL .-2 */ + 0012761, 0000001, 0000002, /* MOV #1, 2(R1) ; track */ + 0032711, 0000040, /* BIT #40, (R1) ; ready? */ + 0001775, /* BEQ .-4 */ + 0005711, /* TST (R1) ; error? */ + 0100003, /* BEQ OK */ + 0005704, /* TST R4 ; single? */ + 0001346, /* BNE DN ; no, try again */ + 0000000, /* HALT ; dead */ + 0012746, 0000003, /* OK: MOV #EMPTY+GO, -(SP); empty & go */ + 0050416, /* BIS R4, (SP) ; or density */ + 0012611, /* MOV (SP)+, (R1) ; read & go */ + 0105711, /* TSTB (R1) ; xfr, done? */ + 0001776, /* BPL .-2 */ + 0012746, 0000100, /* MOV #100, -(SP) ; assume sd */ + 0005704, /* TST R4 ; test dd */ + 0001401, /* BEQ .+4 */ + 0006316, /* ASL (SP) ; dd, double */ + 0011661, 0000002, /* MOV (SP), 2(R1) ; wc */ + 0105711, /* TSTB (R1) ; xfr, done? */ + 0001776, /* BPL .-2 */ + 0010261, 0000002, /* MOV R2, 2(R1) ; ba */ + 0032711, 0000040, /* BIT #40, (R1) ; ready? */ + 0001775, /* BEQ .-4 */ + 0061602, /* ADD (SP), R2 ; cvt wd to byte */ + 0062602, /* ADD (SP)+, R2 ; adv buf addr */ + 0122525, /* CMPB (R5)+, (R5)+ ; sect += 2 */ + 0020527, 0000007, /* CMP R5, #7 ; end? */ + 0101716, /* BLOS RD ; read next */ + 0005002, /* CLR R2 */ + 0005003, /* CLR R3 */ + 0012704, BOOT_START+020, /* MOV #START+20, R4 */ + 0005005, /* CLR R5 */ + 0005007 /* CLR R7 */ +}; + +t_stat ry_boot (int32 unitno, DEVICE *dptr) +{ +int32 i; +extern int32 saved_PC; +extern uint16 *M; + +if ((ry_unit[unitno & RX_M_NUMDR].flags & UNIT_DEN) == 0) + return SCPE_NOFNC; +for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i]; +M[BOOT_UNIT >> 1] = unitno & RX_M_NUMDR; +M[BOOT_CSR >> 1] = ry_dib.ba & DMASK; +saved_PC = BOOT_ENTRY; +return SCPE_OK; +} + +#else + +t_stat ry_boot (int32 unitno, DEVICE *dptr) +{ +return SCPE_NOFNC; +} + +#endif diff --git a/PDP11/pdp11_stddev.c b/PDP11/pdp11_stddev.c index addb18c0..f7bff9e8 100644 --- a/PDP11/pdp11_stddev.c +++ b/PDP11/pdp11_stddev.c @@ -23,10 +23,13 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - ptr,ptp PC11 paper tape reader/punch tti,tto DL11 terminal input/output clk KW11L line frequency clock + 01-Nov-02 RMS Added 7B/8B support to terminal + 29-Sep-02 RMS Added vector display support + Split out paper tape + Split DL11 dibs 30-May-02 RMS Widened POS to 32b 26-Jan-02 RMS Revised for multiple timers 09-Jan-02 RMS Fixed bugs in KW11L (found by John Dundas) @@ -44,10 +47,6 @@ #include "pdp11_defs.h" -#define PTRCSR_IMP (CSR_ERR+CSR_BUSY+CSR_DONE+CSR_IE) /* paper tape reader */ -#define PTRCSR_RW (CSR_IE) -#define PTPCSR_IMP (CSR_ERR + CSR_DONE + CSR_IE) /* paper tape punch */ -#define PTPCSR_RW (CSR_IE) #define TTICSR_IMP (CSR_DONE + CSR_IE) /* terminal input */ #define TTICSR_RW (CSR_IE) #define TTOCSR_IMP (CSR_DONE + CSR_IE) /* terminal output */ @@ -56,11 +55,13 @@ #define CLKCSR_RW (CSR_IE) #define CLK_DELAY 8000 +#define UNIT_V_8B (UNIT_V_UF + 0) /* 8B */ +#define UNIT_8B (1 << UNIT_V_8B) +#define UNIT_KSR (1 << UNIT_V_KSR) + extern int32 int_req[IPL_HLVL]; -int32 ptr_csr = 0; /* control/status */ -int32 ptr_stopioe = 0; /* stop on error */ -int32 ptp_csr = 0; /* control/status */ -int32 ptp_stopioe = 0; /* stop on error */ +extern int32 int_vec[IPL_HLVL][32]; + int32 tti_csr = 0; /* control/status */ int32 tto_csr = 0; /* control/status */ int32 clk_csr = 0; /* control/status */ @@ -68,106 +69,19 @@ int32 clk_tps = 60; /* ticks/second */ int32 tmxr_poll = CLK_DELAY; /* term mux poll */ int32 tmr_poll = CLK_DELAY; /* timer poll */ -t_stat pt_rd (int32 *data, int32 PA, int32 access); -t_stat pt_wr (int32 data, int32 PA, int32 access); -t_stat ptr_svc (UNIT *uptr); -t_stat ptp_svc (UNIT *uptr); -t_stat tt_rd (int32 *data, int32 PA, int32 access); -t_stat tt_wr (int32 data, int32 PA, int32 access); +t_stat tti_rd (int32 *data, int32 PA, int32 access); +t_stat tti_wr (int32 data, int32 PA, int32 access); t_stat tti_svc (UNIT *uptr); +t_stat tti_reset (DEVICE *dptr); +t_stat tto_rd (int32 *data, int32 PA, int32 access); +t_stat tto_wr (int32 data, int32 PA, int32 access); t_stat tto_svc (UNIT *uptr); +t_stat tto_reset (DEVICE *dptr); +t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat clk_rd (int32 *data, int32 PA, int32 access); t_stat clk_wr (int32 data, int32 PA, int32 access); t_stat clk_svc (UNIT *uptr); -t_stat ptr_reset (DEVICE *dptr); -t_stat ptp_reset (DEVICE *dptr); -t_stat tti_reset (DEVICE *dptr); -t_stat tto_reset (DEVICE *dptr); t_stat clk_reset (DEVICE *dptr); -t_stat ptr_attach (UNIT *uptr, char *ptr); -t_stat ptr_detach (UNIT *uptr); -t_stat ptp_attach (UNIT *uptr, char *ptr); -t_stat ptp_detach (UNIT *uptr); - -/* PTR data structures - - ptr_dev PTR device descriptor - ptr_unit PTR unit descriptor - ptr_reg PTR register list -*/ - -DIB pt_dib = { 1, IOBA_PT, IOLN_PT, &pt_rd, &pt_wr }; - -UNIT ptr_unit = { - UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), - SERIAL_IN_WAIT }; - -REG ptr_reg[] = { - { ORDATA (BUF, ptr_unit.buf, 8) }, - { ORDATA (CSR, ptr_csr, 16) }, - { FLDATA (INT, IREQ (PTR), INT_V_PTR) }, - { FLDATA (ERR, ptr_csr, CSR_V_ERR) }, - { FLDATA (BUSY, ptr_csr, CSR_V_BUSY) }, - { FLDATA (DONE, ptr_csr, CSR_V_DONE) }, - { FLDATA (IE, ptr_csr, CSR_V_IE) }, - { DRDATA (POS, ptr_unit.pos, 32), PV_LEFT }, - { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, - { FLDATA (STOP_IOE, ptr_stopioe, 0) }, - { FLDATA (*DEVENB, pt_dib.enb, 0), REG_HRO }, - { NULL } }; - -MTAB ptr_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, - NULL, &show_addr, &pt_dib }, - { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", - &set_enbdis, NULL, &pt_dib }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", - &set_enbdis, NULL, &pt_dib }, - { 0 } }; - -DEVICE ptr_dev = { - "PTR", &ptr_unit, ptr_reg, ptr_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ptr_reset, - NULL, &ptr_attach, &ptr_detach }; - -/* PTP data structures - - ptp_dev PTP device descriptor - ptp_unit PTP unit descriptor - ptp_reg PTP register list -*/ - -UNIT ptp_unit = { - UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; - -REG ptp_reg[] = { - { ORDATA (BUF, ptp_unit.buf, 8) }, - { ORDATA (CSR, ptp_csr, 16) }, - { FLDATA (INT, IREQ (PTP), INT_V_PTP) }, - { FLDATA (ERR, ptp_csr, CSR_V_ERR) }, - { FLDATA (DONE, ptp_csr, CSR_V_DONE) }, - { FLDATA (IE, ptp_csr, CSR_V_IE) }, - { DRDATA (POS, ptp_unit.pos, 32), PV_LEFT }, - { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, - { FLDATA (STOP_IOE, ptp_stopioe, 0) }, - { FLDATA (*DEVENB, pt_dib.enb, 0), REG_HRO }, - { NULL } }; - -MTAB ptp_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, - NULL, &show_addr, &pt_dib }, - { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", - &set_enbdis, NULL, &pt_dib }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", - &set_enbdis, NULL, &pt_dib }, - { 0 } }; - -DEVICE ptp_dev = { - "PTP", &ptp_unit, ptp_reg, ptp_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ptp_reset, - NULL, &ptp_attach, &ptp_detach }; /* TTI data structures @@ -176,9 +90,10 @@ DEVICE ptp_dev = { tti_reg TTI register list */ -DIB tt_dib = { 1, IOBA_TT, IOLN_TT, &tt_rd, &tt_wr }; +DIB tti_dib = { IOBA_TTI, IOLN_TTI, &tti_rd, &tti_wr, + 1, IVCL (TTI), VEC_TTI, { NULL } }; -UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT }; +UNIT tti_unit = { UDATA (&tti_svc, UNIT_8B, 0), KBD_POLL_WAIT }; REG tti_reg[] = { { ORDATA (BUF, tti_unit.buf, 8) }, @@ -192,15 +107,20 @@ REG tti_reg[] = { { NULL } }; MTAB tti_mod[] = { + { UNIT_8B, 0 , "7b" , "7B" , &tty_set_mode }, + { UNIT_8B, UNIT_8B , "8b" , "8B" , &tty_set_mode }, { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, - NULL, &show_addr, &tt_dib }, + NULL, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, + NULL, &show_vec, NULL }, { 0 } }; DEVICE tti_dev = { "TTI", &tti_unit, tti_reg, tti_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &tti_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &tti_dib, DEV_UBUS | DEV_QBUS }; /* TTO data structures @@ -209,7 +129,10 @@ DEVICE tti_dev = { tto_reg TTO register list */ -UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT }; +DIB tto_dib = { IOBA_TTO, IOLN_TTO, &tto_rd, &tto_wr, + 1, IVCL (TTO), VEC_TTO, { NULL } }; + +UNIT tto_unit = { UDATA (&tto_svc, UNIT_8B, 0), SERIAL_OUT_WAIT }; REG tto_reg[] = { { ORDATA (BUF, tto_unit.buf, 8) }, @@ -223,15 +146,20 @@ REG tto_reg[] = { { NULL } }; MTAB tto_mod[] = { + { UNIT_8B, 0 , "7b" , "7B" , &tty_set_mode }, + { UNIT_8B, UNIT_8B , "8b" , "8B" , &tty_set_mode }, { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, - NULL, &show_addr, &tt_dib }, + NULL, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, + NULL, &show_vec, NULL }, { 0 } }; DEVICE tto_dev = { "TTO", &tto_unit, tto_reg, tto_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &tto_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &tto_dib, DEV_UBUS | DEV_QBUS }; /* CLK data structures @@ -240,7 +168,8 @@ DEVICE tto_dev = { clk_reg CLK register list */ -DIB clk_dib = { 1, IOBA_CLK, IOLN_CLK, &clk_rd, &clk_wr }; +DIB clk_dib = { IOBA_CLK, IOLN_CLK, &clk_rd, &clk_wr, + 1, IVCL (CLK), VEC_CLK, { NULL } }; UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 8000 }; @@ -255,170 +184,23 @@ REG clk_reg[] = { MTAB clk_mod[] = { { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, - NULL, &show_addr, &clk_dib }, + NULL, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, + NULL, &show_vec, NULL }, { 0 } }; DEVICE clk_dev = { "CLK", &clk_unit, clk_reg, clk_mod, 1, 0, 0, 0, 0, 0, NULL, NULL, &clk_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &clk_dib, DEV_UBUS | DEV_QBUS }; -/* Paper tape I/O address routines */ +/* Terminal input address routines */ -t_stat pt_rd (int32 *data, int32 PA, int32 access) +t_stat tti_rd (int32 *data, int32 PA, int32 access) { -switch ((PA >> 1) & 03) { /* decode PA<2:1> */ -case 00: /* ptr csr */ - *data = ptr_csr & PTRCSR_IMP; - return SCPE_OK; -case 01: /* ptr buf */ - ptr_csr = ptr_csr & ~CSR_DONE; - CLR_INT (PTR); - *data = ptr_unit.buf & 0377; - return SCPE_OK; -case 02: /* ptp csr */ - *data = ptp_csr & PTPCSR_IMP; - return SCPE_OK; -case 03: /* ptp buf */ - *data = ptp_unit.buf; - return SCPE_OK; } /* end switch PA */ -return SCPE_NXM; -} - -t_stat pt_wr (int32 data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 03) { /* decode PA<2:1> */ -case 00: /* ptr csr */ - if (PA & 1) return SCPE_OK; - if ((data & CSR_IE) == 0) CLR_INT (PTR); - else if (((ptr_csr & CSR_IE) == 0) && (ptr_csr & (CSR_ERR | CSR_DONE))) - SET_INT (PTR); - if (data & CSR_GO) { - ptr_csr = (ptr_csr & ~CSR_DONE) | CSR_BUSY; - CLR_INT (PTR); - if (ptr_unit.flags & UNIT_ATT) /* data to read? */ - sim_activate (&ptr_unit, ptr_unit.wait); - else sim_activate (&ptr_unit, 0); } /* error if not */ - ptr_csr = (ptr_csr & ~PTRCSR_RW) | (data & PTRCSR_RW); - return SCPE_OK; -case 01: /* ptr buf */ - return SCPE_OK; -case 02: /* ptp csr */ - if (PA & 1) return SCPE_OK; - if ((data & CSR_IE) == 0) CLR_INT (PTP); - else if (((ptp_csr & CSR_IE) == 0) && (ptp_csr & (CSR_ERR | CSR_DONE))) - SET_INT (PTP); - ptp_csr = (ptp_csr & ~PTPCSR_RW) | (data & PTPCSR_RW); - return SCPE_OK; -case 03: /* ptp buf */ - if ((PA & 1) == 0) ptp_unit.buf = data & 0377; - ptp_csr = ptp_csr & ~CSR_DONE; - CLR_INT (PTP); - if (ptp_unit.flags & UNIT_ATT) /* file to write? */ - sim_activate (&ptp_unit, ptp_unit.wait); - else sim_activate (&ptp_unit, 0); /* error if not */ - return SCPE_OK; } /* end switch PA */ -return SCPE_NXM; -} - -/* Paper tape reader routines */ - -t_stat ptr_svc (UNIT *uptr) -{ -int32 temp; - -ptr_csr = (ptr_csr | CSR_ERR) & ~CSR_BUSY; -if (ptr_csr & CSR_IE) SET_INT (PTR); -if ((ptr_unit.flags & UNIT_ATT) == 0) - return IORETURN (ptr_stopioe, SCPE_UNATT); -if ((temp = getc (ptr_unit.fileref)) == EOF) { - if (feof (ptr_unit.fileref)) { - if (ptr_stopioe) printf ("PTR end of file\n"); - else return SCPE_OK; } - else perror ("PTR I/O error"); - clearerr (ptr_unit.fileref); - return SCPE_IOERR; } -ptr_csr = (ptr_csr | CSR_DONE) & ~CSR_ERR; -ptr_unit.buf = temp & 0377; -ptr_unit.pos = ptr_unit.pos + 1; -return SCPE_OK; -} - -t_stat ptr_reset (DEVICE *dptr) -{ -ptr_unit.buf = 0; -ptr_csr = 0; -if ((ptr_unit.flags & UNIT_ATT) == 0) ptr_csr = ptr_csr | CSR_ERR; -CLR_INT (PTR); -sim_cancel (&ptr_unit); -return SCPE_OK; -} - -t_stat ptr_attach (UNIT *uptr, char *cptr) -{ -t_stat reason; - -reason = attach_unit (uptr, cptr); -if ((ptr_unit.flags & UNIT_ATT) == 0) ptr_csr = ptr_csr | CSR_ERR; -else ptr_csr = ptr_csr & ~CSR_ERR; -return reason; -} - -t_stat ptr_detach (UNIT *uptr) -{ -ptr_csr = ptr_csr | CSR_ERR; -return detach_unit (uptr); -} - -/* Paper tape punch routines */ - -t_stat ptp_svc (UNIT *uptr) -{ -ptp_csr = ptp_csr | CSR_ERR | CSR_DONE; -if (ptp_csr & CSR_IE) SET_INT (PTP); -if ((ptp_unit.flags & UNIT_ATT) == 0) - return IORETURN (ptp_stopioe, SCPE_UNATT); -if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { - perror ("PTP I/O error"); - clearerr (ptp_unit.fileref); - return SCPE_IOERR; } -ptp_csr = ptp_csr & ~CSR_ERR; -ptp_unit.pos = ptp_unit.pos + 1; -return SCPE_OK; -} - -t_stat ptp_reset (DEVICE *dptr) -{ -ptp_unit.buf = 0; -ptp_csr = CSR_DONE; -if ((ptp_unit.flags & UNIT_ATT) == 0) ptp_csr = ptp_csr | CSR_ERR; -CLR_INT (PTP); -sim_cancel (&ptp_unit); /* deactivate unit */ -return SCPE_OK; -} - -t_stat ptp_attach (UNIT *uptr, char *cptr) -{ -t_stat reason; - -reason = attach_unit (uptr, cptr); -if ((ptp_unit.flags & UNIT_ATT) == 0) ptp_csr = ptp_csr | CSR_ERR; -else ptp_csr = ptp_csr & ~CSR_ERR; -return reason; -} - -t_stat ptp_detach (UNIT *uptr) -{ -ptp_csr = ptp_csr | CSR_ERR; -return detach_unit (uptr); -} - -/* Terminal I/O address routines */ - -t_stat tt_rd (int32 *data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 03) { /* decode PA<2:1> */ +switch ((PA >> 1) & 01) { /* decode PA<1> */ case 00: /* tti csr */ *data = tti_csr & TTICSR_IMP; return SCPE_OK; @@ -426,19 +208,13 @@ case 01: /* tti buf */ tti_csr = tti_csr & ~CSR_DONE; CLR_INT (TTI); *data = tti_unit.buf & 0377; - return SCPE_OK; -case 02: /* tto csr */ - *data = tto_csr & TTOCSR_IMP; - return SCPE_OK; -case 03: /* tto buf */ - *data = tto_unit.buf; return SCPE_OK; } /* end switch PA */ return SCPE_NXM; } -t_stat tt_wr (int32 data, int32 PA, int32 access) +t_stat tti_wr (int32 data, int32 PA, int32 access) { -switch ((PA >> 1) & 03) { /* decode PA<2:1> */ +switch ((PA >> 1) & 01) { /* decode PA<1> */ case 00: /* tti csr */ if (PA & 1) return SCPE_OK; if ((data & CSR_IE) == 0) CLR_INT (TTI); @@ -447,42 +223,27 @@ case 00: /* tti csr */ tti_csr = (tti_csr & ~TTICSR_RW) | (data & TTICSR_RW); return SCPE_OK; case 01: /* tti buf */ - return SCPE_OK; -case 02: /* tto csr */ - if (PA & 1) return SCPE_OK; - if ((data & CSR_IE) == 0) CLR_INT (TTO); - else if ((tto_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) - SET_INT (TTO); - tto_csr = (tto_csr & ~TTOCSR_RW) | (data & TTOCSR_RW); - return SCPE_OK; -case 03: /* tto buf */ - if ((PA & 1) == 0) tto_unit.buf = data & 0377; - tto_csr = tto_csr & ~CSR_DONE; - CLR_INT (TTO); - sim_activate (&tto_unit, tto_unit.wait); return SCPE_OK; } /* end switch PA */ return SCPE_NXM; } - -/* Terminal input routines - tti_svc process event (character ready) - tti_reset process reset -*/ +/* Terminal input service */ t_stat tti_svc (UNIT *uptr) { -int32 temp; +int32 c; sim_activate (&tti_unit, tti_unit.wait); /* continue poll */ -if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */ -tti_unit.buf = temp & 0377; +if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */ +tti_unit.buf = c & ((tti_unit.flags & UNIT_8B)? 0377: 0177); tti_unit.pos = tti_unit.pos + 1; tti_csr = tti_csr | CSR_DONE; if (tti_csr & CSR_IE) SET_INT (TTI); return SCPE_OK; } +/* Terminal input reset */ + t_stat tti_reset (DEVICE *dptr) { tti_unit.buf = 0; @@ -492,23 +253,56 @@ sim_activate (&tti_unit, tti_unit.wait); /* activate unit */ return SCPE_OK; } -/* Terminal output routines +/* Terminal output address routines */ - tto_svc process event (character typed) - tto_reset process reset -*/ +t_stat tto_rd (int32 *data, int32 PA, int32 access) +{ +switch ((PA >> 1) & 01) { /* decode PA<1> */ +case 00: /* tto csr */ + *data = tto_csr & TTOCSR_IMP; + return SCPE_OK; +case 01: /* tto buf */ + *data = tto_unit.buf; + return SCPE_OK; } /* end switch PA */ +return SCPE_NXM; +} + +t_stat tto_wr (int32 data, int32 PA, int32 access) +{ +switch ((PA >> 1) & 01) { /* decode PA<1> */ +case 00: /* tto csr */ + if (PA & 1) return SCPE_OK; + if ((data & CSR_IE) == 0) CLR_INT (TTO); + else if ((tto_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) + SET_INT (TTO); + tto_csr = (tto_csr & ~TTOCSR_RW) | (data & TTOCSR_RW); + return SCPE_OK; +case 01: /* tto buf */ + if ((PA & 1) == 0) tto_unit.buf = data & 0377; + tto_csr = tto_csr & ~CSR_DONE; + CLR_INT (TTO); + sim_activate (&tto_unit, tto_unit.wait); + return SCPE_OK; } /* end switch PA */ +return SCPE_NXM; +} + +/* Terminal output service */ t_stat tto_svc (UNIT *uptr) { -int32 temp; +int32 c; +t_stat r; tto_csr = tto_csr | CSR_DONE; if (tto_csr & CSR_IE) SET_INT (TTO); -if ((temp = sim_putchar (tto_unit.buf & 0177)) != SCPE_OK) return temp; +c = tto_unit.buf & ((tto_unit.flags & UNIT_8B)? 0377: 0177); +if ((r = sim_putchar (c)) != SCPE_OK) return r; tto_unit.pos = tto_unit.pos + 1; return SCPE_OK; } +/* Terminal output reset */ + t_stat tto_reset (DEVICE *dptr) { tto_unit.buf = 0; @@ -517,6 +311,13 @@ CLR_INT (TTO); sim_cancel (&tto_unit); /* deactivate unit */ return SCPE_OK; } + +t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +tti_unit.flags = (tti_unit.flags & ~UNIT_8B) | val; +tto_unit.flags = (tto_unit.flags & ~UNIT_8B) | val; +return SCPE_OK; +} /* Clock I/O address routines */ @@ -531,12 +332,12 @@ t_stat clk_wr (int32 data, int32 PA, int32 access) if (PA & 1) return SCPE_OK; clk_csr = (clk_csr & ~CLKCSR_RW) | (data & CLKCSR_RW); if ((data & CSR_DONE) == 0) clk_csr = clk_csr & ~CSR_DONE; -if (((clk_csr & CSR_IE) == 0) || /* unless IE+DONE */ +if (((clk_csr & CSR_IE) == 0) || /* unless IE+DONE */ ((clk_csr & CSR_DONE) == 0)) CLR_INT (CLK); /* clr intr */ return SCPE_OK; } -/* Clock routines */ +/* Clock service */ t_stat clk_svc (UNIT *uptr) { @@ -551,6 +352,8 @@ tmxr_poll = t; /* set mux poll */ return SCPE_OK; } +/* Clock reset */ + t_stat clk_reset (DEVICE *dptr) { clk_csr = CSR_DONE; /* set done */ diff --git a/PDP11/pdp11_sys.c b/PDP11/pdp11_sys.c index d1fff505..bcad0261 100644 --- a/PDP11/pdp11_sys.c +++ b/PDP11/pdp11_sys.c @@ -23,6 +23,9 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 17-Oct-02 RMS Fixed bugs in branch, SOB address parsing + 09-Oct-02 RMS Added DELQA support + 12-Sep-02 RMS Added TMSCP, KW11P, RX211 support, RAD50 examine 29-Nov-01 RMS Added read only unit support 17-Sep-01 RMS Removed multiconsole support 26-Aug-01 RMS Added DZ11 @@ -47,12 +50,18 @@ extern DEVICE cpu_dev; extern DEVICE ptr_dev, ptp_dev; extern DEVICE tti_dev, tto_dev; -extern DEVICE lpt_dev, clk_dev; +extern DEVICE lpt_dev; +extern DEVICE clk_dev, pclk_dev; extern DEVICE dz_dev; extern DEVICE rk_dev, rl_dev; -extern DEVICE rp_dev, rq_dev; -extern DEVICE rx_dev, dt_dev; +extern DEVICE hk_dev; +extern DEVICE rx_dev, ry_dev; +extern DEVICE rp_dev; +extern DEVICE rq_dev, rqb_dev, rqc_dev, rqd_dev; +extern DEVICE dt_dev; extern DEVICE tm_dev, ts_dev; +extern DEVICE tq_dev; +extern DEVICE xq_dev; extern UNIT cpu_unit; extern REG cpu_reg[]; extern uint16 *M; @@ -76,14 +85,29 @@ int32 sim_emax = 4; DEVICE *sim_devices[] = { &cpu_dev, - &ptr_dev, &ptp_dev, - &tti_dev, &tto_dev, - &lpt_dev, &clk_dev, + &ptr_dev, + &ptp_dev, + &tti_dev, + &tto_dev, + &lpt_dev, + &clk_dev, + &pclk_dev, &dz_dev, - &rk_dev, &rl_dev, - &rp_dev, &rq_dev, - &rx_dev, &dt_dev, - &tm_dev, &ts_dev, + &rk_dev, + &rl_dev, + &hk_dev, + &rx_dev, + &ry_dev, + &rp_dev, + &rq_dev, + &rqb_dev, + &rqc_dev, + &rqd_dev, + &dt_dev, + &tm_dev, + &ts_dev, + &tq_dev, + &xq_dev, NULL }; const char *sim_stop_messages[] = { @@ -108,7 +132,8 @@ const char *sim_stop_messages[] = { "Wait state", "Trap vector fetch abort", "Trap stack push abort", - "RQDX3 consistency error" }; + "RQDX3 consistency error", + "Sanity timer expired" }; /* Binary loader. @@ -210,19 +235,19 @@ int32 i, da; int16 *buf; if ((sec < 2) || (wds < 16)) return SCPE_ARG; -if ((uptr -> flags & UNIT_ATT) == 0) return SCPE_UNATT; -if (uptr -> flags & UNIT_RO) return SCPE_RO; +if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; +if (uptr->flags & UNIT_RO) return SCPE_RO; if (!get_yn ("Create bad block table on last track? [N]", FALSE)) return SCPE_OK; -da = (uptr -> capac - (sec * wds)) * sizeof (int16); -if (fseek (uptr -> fileref, da, SEEK_SET)) return SCPE_IOERR; +da = (uptr->capac - (sec * wds)) * sizeof (int16); +if (fseek (uptr->fileref, da, SEEK_SET)) return SCPE_IOERR; if ((buf = malloc (wds * sizeof (int16))) == NULL) return SCPE_MEM; buf[0] = buf[1] = 012345u; buf[2] = buf[3] = 0; for (i = 4; i < wds; i++) buf[i] = 0177777u; for (i = 0; (i < sec) && (i < 10); i++) - fxwrite (buf, sizeof (int16), wds, uptr -> fileref); + fxwrite (buf, sizeof (int16), wds, uptr->fileref); free (buf); -if (ferror (uptr -> fileref)) return SCPE_IOERR; +if (ferror (uptr->fileref)) return SCPE_IOERR; return SCPE_OK; } @@ -417,6 +442,8 @@ static const char *rname [] = static const char *fname [] = { "F0", "F1", "F2", "F3", "F4", "F5", "?6", "?7" }; + +static const char r50_to_asc[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789"; /* Specifier decode @@ -489,7 +516,7 @@ return ((reg == 07)? pcwd[mode]: rgwd[mode]); t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw) { -int32 cflag, i, j, c1, c2, inst, fac, srcm, srcr, dstm, dstr; +int32 cflag, i, j, c1, c2, c3, inst, fac, srcm, srcr, dstm, dstr; int32 l8b, brdisp, wd1, wd2; extern int32 FPS; @@ -503,6 +530,14 @@ if (sw & SWMASK ('C')) { /* character? */ fprintf (of, (c1 < 040)? "<%03o>": "%c", c1); fprintf (of, (c2 < 040)? "<%03o>": "%c", c2); return SCPE_OK; } +if (sw & SWMASK ('R')) { /* radix 50? */ + if (val[0] > 0174777) return SCPE_ARG; /* max value */ + c3 = val[0] % 050; + c2 = (val[0] / 050) % 050; + c1 = val[0] / (050 * 050); + fprintf (of, "%c%c%c", r50_to_asc[c1], + r50_to_asc[c2], r50_to_asc[c3]); + return SCPE_OK; } if (!(sw & SWMASK ('M'))) return SCPE_ARG; inst = val[0] | ((FPS << (I_V_L - FPS_V_L)) & I_L) | @@ -638,8 +673,9 @@ if (*cptr == '-') { /* -? */ errno = 0; val = strtoul (cptr, &tptr, 8); if (cptr == tptr) { /* no number? */ - if (*pflag != (A_REL + A_NUM)) return cptr; - else return NULL; } + if (*pflag == (A_REL + A_NUM)) return NULL; /* .+, .-? */ + *dptr = 0; + return cptr; } if (errno || (*pflag == A_REL)) return NULL; /* .n? */ *dptr = (minus? -val: val) & 0177777; *pflag = *pflag | A_NUM; @@ -756,7 +792,7 @@ t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) { int32 cflag, d, i, j, reg, spec, n1, n2, disp, pflag; t_stat r; -char gbuf[CBUFSIZE]; +char *tptr, gbuf[CBUFSIZE]; cflag = (uptr == NULL) || (uptr == &cpu_unit); while (isspace (*cptr)) cptr++; /* absorb spaces */ @@ -768,6 +804,7 @@ if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */ if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ val[0] = ((t_value) cptr[1] << 8) + (t_value) cptr[0]; return SCPE_OK; } +if (sw & SWMASK ('R')) return SCPE_ARG; /* radix 50 */ cptr = get_glyph (cptr, gbuf, 0); /* get opcode */ n1 = n2 = pflag = 0; @@ -792,7 +829,8 @@ case I_V_3B: case I_V_6B: case I_V_8B: /* xb literal */ break; case I_V_BR: /* cond br */ cptr = get_glyph (cptr, gbuf, 0); /* get address */ - if ((cptr = get_addr (gbuf, &disp, &pflag)) == NULL) return SCPE_ARG; + tptr = get_addr (gbuf, &disp, &pflag); /* parse */ + if ((tptr == NULL) || (*tptr != 0)) return SCPE_ARG; if ((pflag & A_REL) == 0) { if (cflag) disp = (disp - addr) & 0177777; else return SCPE_ARG; } @@ -804,7 +842,8 @@ case I_V_SOB: /* sob */ if ((reg = get_reg (gbuf, rname, 0)) < 0) return SCPE_ARG; val[0] = val[0] | (reg << 6); cptr = get_glyph (cptr, gbuf, 0); /* get address */ - if ((cptr = get_addr (gbuf, &disp, &pflag)) == NULL) return SCPE_ARG; + tptr = get_addr (gbuf, &disp, &pflag); /* parse */ + if ((tptr == NULL) || (*tptr != 0)) return SCPE_ARG; if ((pflag & A_REL) == 0) { if (cflag) disp = (disp - addr) & 0177777; else return SCPE_ARG; } diff --git a/PDP11/pdp11_tc.c b/PDP11/pdp11_tc.c index 650a2857..365306f6 100644 --- a/PDP11/pdp11_tc.c +++ b/PDP11/pdp11_tc.c @@ -25,6 +25,10 @@ tc TC11/TU56 DECtape + 29-Sep-02 RMS Added variable address support to bootstrap + Added vector change/display support + Added 16b format support + New data structures 30-May-02 RMS Widened POS to 32b 26-Jan-02 RMS Revised bootstrap to conform to M9312 06-Jan-02 RMS Revised enable/disable support @@ -42,11 +46,14 @@ 16-Mar-01 RMS Fixed bug in interrupt after stop 15-Mar-01 RMS Added 129th word to PDP-8 format - PDP-11 DECtapes are represented by fixed length data blocks of 18b words. Two - tape formats are supported: + PDP-11 DECtapes are represented in memory by fixed length buffer of 32b words. + Three file formats are supported: - 16b/18b/36b 256 words per block - 12b 86 words per block [129 x 12b] + 18b/36b 256 words per block [256 x 18b] + 16b 256 words per block [256 x 16b] + 12b 129 words per block [129 x 12b] + + When a 16b or 12b DECtape file is read in, it is converted to 18b/36b format. DECtape motion is measured in 3b lines. Time between lines is 33.33us. Tape density is nominally 300 lines per inch. The format of a DECtape is @@ -86,10 +93,11 @@ #define DT_NUMDR 8 /* #drives */ #define DT_M_NUMDR (DT_NUMDR - 1) #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_WLK 1 << UNIT_V_WLK #define UNIT_V_8FMT (UNIT_V_UF + 1) /* 12b format */ +#define UNIT_V_11FMT (UNIT_V_UF + 2) /* 16b format */ +#define UNIT_WLK (1 << UNIT_V_WLK) #define UNIT_8FMT (1 << UNIT_V_8FMT) -#define UNIT_W_UF 3 /* saved flag width */ +#define UNIT_11FMT (1 << UNIT_V_11FMT) #define STATE u3 /* unit state */ #define LASTT u4 /* last time update */ #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ @@ -112,6 +120,7 @@ #define D18_LPERB (DT_HTLIN + (D18_BSIZE * DT_WSIZE) + DT_HTLIN) #define D18_FWDEZ (DT_EZLIN + (D18_LPERB * D18_TSIZE)) #define D18_CAPAC (D18_TSIZE * D18_BSIZE) /* tape capacity */ +#define D16_FILSIZ (D18_TSIZE * D18_BSIZE * sizeof (int16)) /* 12b DECtape constants */ @@ -132,18 +141,18 @@ /* Calculated constants, per unit */ -#define DTU_BSIZE(u) (((u) -> flags & UNIT_8FMT)? D8_BSIZE: D18_BSIZE) -#define DTU_TSIZE(u) (((u) -> flags & UNIT_8FMT)? D8_TSIZE: D18_TSIZE) -#define DTU_LPERB(u) (((u) -> flags & UNIT_8FMT)? D8_LPERB: D18_LPERB) -#define DTU_FWDEZ(u) (((u) -> flags & UNIT_8FMT)? D8_FWDEZ: D18_FWDEZ) -#define DTU_CAPAC(u) (((u) -> flags & UNIT_8FMT)? D8_CAPAC: D18_CAPAC) +#define DTU_BSIZE(u) (((u)->flags & UNIT_8FMT)? D8_BSIZE: D18_BSIZE) +#define DTU_TSIZE(u) (((u)->flags & UNIT_8FMT)? D8_TSIZE: D18_TSIZE) +#define DTU_LPERB(u) (((u)->flags & UNIT_8FMT)? D8_LPERB: D18_LPERB) +#define DTU_FWDEZ(u) (((u)->flags & UNIT_8FMT)? D8_FWDEZ: D18_FWDEZ) +#define DTU_CAPAC(u) (((u)->flags & UNIT_8FMT)? D8_CAPAC: D18_CAPAC) #define DT_LIN2BL(p,u) (((p) - DT_EZLIN) / DTU_LPERB (u)) #define DT_LIN2OF(p,u) (((p) - DT_EZLIN) % DTU_LPERB (u)) #define DT_LIN2WD(p,u) ((DT_LIN2OF (p,u) - DT_HTLIN) / DT_WSIZE) #define DT_BLK2LN(p,u) (((p) * DTU_LPERB (u)) + DT_EZLIN) -#define DT_QREZ(u) (((u) -> pos) < DT_EZLIN) -#define DT_QFEZ(u) (((u) -> pos) >= ((uint32) DTU_FWDEZ (u))) +#define DT_QREZ(u) (((u)->pos) < DT_EZLIN) +#define DT_QFEZ(u) (((u)->pos) >= ((uint32) DTU_FWDEZ (u))) #define DT_QEZ(u) (DT_QREZ (u) || DT_QFEZ (u)) /* TCST - 177340 - status register */ @@ -224,10 +233,10 @@ #define DTS_V_2ND 6 /* next state */ #define DTS_V_3RD (DTS_V_2ND + DTS_V_2ND) /* next next */ #define DTS_STA(y,z) (((y) << DTS_V_MOT) | ((z) << DTS_V_FNC)) -#define DTS_SETSTA(y,z) uptr -> STATE = DTS_STA (y, z) -#define DTS_SET2ND(y,z) uptr -> STATE = (uptr -> STATE & 077) | \ +#define DTS_SETSTA(y,z) uptr->STATE = DTS_STA (y, z) +#define DTS_SET2ND(y,z) uptr->STATE = (uptr->STATE & 077) | \ ((DTS_STA (y, z)) << DTS_V_2ND) -#define DTS_SET3RD(y,z) uptr -> STATE = (uptr -> STATE & 07777) | \ +#define DTS_SET3RD(y,z) uptr->STATE = (uptr->STATE & 07777) | \ ((DTS_STA (y, z)) << DTS_V_3RD) #define DTS_NXTSTA(x) (x >> DTS_V_2ND) @@ -246,10 +255,12 @@ extern uint16 *M; /* memory */ extern int32 int_req[IPL_HLVL]; +extern int32 int_vec[IPL_HLVL][32]; extern UNIT cpu_unit; extern int32 sim_switches; extern int32 cpu_log; extern FILE *sim_log; + int32 tcst = 0; /* status */ int32 tccm = 0; /* command */ int32 tcwc = 0; /* word count */ @@ -262,6 +273,7 @@ int32 dt_dctime = 72000; /* decel time */ int32 dt_substate = 0; int32 dt_logblk = 0; +DEVICE dt_dev; t_stat dt_rd (int32 *data, int32 PA, int32 access); t_stat dt_wr (int32 data, int32 PA, int32 access); t_stat dt_svc (UNIT *uptr); @@ -269,7 +281,7 @@ t_stat dt_svcdone (UNIT *uptr); t_stat dt_reset (DEVICE *dptr); t_stat dt_attach (UNIT *uptr, char *cptr); t_stat dt_detach (UNIT *uptr); -t_stat dt_boot (int32 unitno); +t_stat dt_boot (int32 unitno, DEVICE *dptr); void dt_deselect (int32 oldf); void dt_newsa (int32 newf); void dt_newfnc (UNIT *uptr, int32 newsta); @@ -290,17 +302,26 @@ extern int32 sim_is_running; dt_mod DT modifier list */ -DIB dt_dib = { 1, IOBA_TC, IOLN_TC, &dt_rd, &dt_wr }; +DIB dt_dib = { IOBA_TC, IOLN_TC, &dt_rd, &dt_wr, + 1, IVCL (DTA), VEC_DTA, { NULL } }; UNIT dt_unit[] = { - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) }, { UDATA (&dt_svcdone, UNIT_DIS, 0) } }; #define DT_TIMER (DT_NUMDR) @@ -327,30 +348,28 @@ REG dt_reg[] = { DT_NUMDR, REG_RO) }, { URDATA (LASTT, dt_unit[0].LASTT, 10, 32, 0, DT_NUMDR, REG_HRO) }, - { URDATA (FLG, dt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, - DT_NUMDR, REG_HRO) }, { ORDATA (DEVADDR, dt_dib.ba, 32), REG_HRO }, - { FLDATA (*DEVENB, dt_dib.enb, 0), REG_HRO }, + { ORDATA (DEVVEC, dt_dib.vec, 16), REG_HRO }, { NULL } }; MTAB dt_mod[] = { { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, - { UNIT_8FMT, 0, "16b/18b", NULL, NULL }, - { UNIT_8FMT, UNIT_8FMT, "12b", NULL, NULL }, + { UNIT_8FMT + UNIT_11FMT, 0, "18b", NULL, NULL }, + { UNIT_8FMT + UNIT_11FMT, UNIT_8FMT, "12b", NULL, NULL }, + { UNIT_8FMT + UNIT_11FMT, UNIT_11FMT, "16b", NULL, NULL }, { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, &dt_dib }, - { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", - &set_enbdis, NULL, &dt_dib }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", - &set_enbdis, NULL, &dt_dib }, + &set_addr, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + &set_vec, &show_vec, NULL }, { 0 } }; DEVICE dt_dev = { "TC", dt_unit, dt_reg, dt_mod, DT_NUMDR + 1, 8, 24, 1, 8, 18, NULL, NULL, &dt_reset, - &dt_boot, &dt_attach, &dt_detach }; + &dt_boot, &dt_attach, &dt_detach, + &dt_dib, DEV_DISABLE | DEV_UBUS }; /* IO dispatch routines, I/O addresses 17777340 - 17777350 */ @@ -419,11 +438,11 @@ case 001: /* TCCM */ dt_stopunit (dt_dev.units + i); /* stop unit */ break; } uptr = dt_dev.units + unum; - if (uptr -> flags & UNIT_DIS) /* disabled? */ + if (uptr->flags & UNIT_DIS) /* disabled? */ dt_seterr (uptr, STA_SEL); /* select err */ if ((fnc == FNC_WMRK) || /* write mark? */ - ((fnc == FNC_WALL) && (uptr -> flags & UNIT_WPRT)) || - ((fnc == FNC_WRIT) && (uptr -> flags & UNIT_WPRT))) + ((fnc == FNC_WALL) && (uptr->flags & UNIT_WPRT)) || + ((fnc == FNC_WRIT) && (uptr->flags & UNIT_WPRT))) dt_seterr (uptr, STA_ILO); /* illegal op */ if (!(tccm & CSR_ERR)) dt_newsa (tccm); } else if ((tccm & CSR_ERR) == 0) { /* clear err? */ @@ -452,7 +471,7 @@ void dt_deselect (int32 oldf) { int32 old_unit = CSR_GETUNIT (oldf); UNIT *uptr = dt_dev.units + old_unit; -int32 old_mot = DTS_GETMOT (uptr -> STATE); +int32 old_mot = DTS_GETMOT (uptr->STATE); if (old_mot >= DTS_ATSF) /* at speed? */ dt_newfnc (uptr, DTS_STA (old_mot, DTS_OFR)); @@ -480,17 +499,16 @@ return; } void dt_newsa (int32 newf) { -int32 new_unit, prev_mot, prev_fnc, new_fnc; +int32 new_unit, prev_mot, new_fnc; int32 prev_dir, new_dir; UNIT *uptr; new_unit = CSR_GETUNIT (newf); /* new, old units */ uptr = dt_dev.units + new_unit; -if ((uptr -> flags & UNIT_ATT) == 0) { /* new unit attached? */ +if ((uptr->flags & UNIT_ATT) == 0) { /* new unit attached? */ dt_seterr (uptr, STA_SEL); /* no, error */ return; } -prev_mot = DTS_GETMOT (uptr -> STATE); /* previous motion */ -prev_fnc = DTS_GETFNC (uptr -> STATE); /* prev function */ +prev_mot = DTS_GETMOT (uptr->STATE); /* previous motion */ prev_dir = prev_mot & DTS_DIR; /* previous dir */ new_fnc = CSR_GETFNC (newf); /* new function */ new_dir = (newf & CSR_DIR) != 0; /* new di? */ @@ -547,15 +565,15 @@ void dt_newfnc (UNIT *uptr, int32 newsta) int32 fnc, dir, blk, unum, relpos, newpos; uint32 oldpos; -oldpos = uptr -> pos; /* save old pos */ +oldpos = uptr->pos; /* save old pos */ if (dt_setpos (uptr)) return; /* update pos */ -uptr -> STATE = newsta; /* update state */ -fnc = DTS_GETFNC (uptr -> STATE); /* set variables */ -dir = DTS_GETMOT (uptr -> STATE) & DTS_DIR; +uptr->STATE = newsta; /* update state */ +fnc = DTS_GETFNC (uptr->STATE); /* set variables */ +dir = DTS_GETMOT (uptr->STATE) & DTS_DIR; unum = uptr - dt_dev.units; -if (oldpos == uptr -> pos) - uptr -> pos = uptr -> pos + (dir? -1: 1); -blk = DT_LIN2BL (uptr -> pos, uptr); +if (oldpos == uptr->pos) + uptr->pos = uptr->pos + (dir? -1: 1); +blk = DT_LIN2BL (uptr->pos, uptr); if (dir? DT_QREZ (uptr): DT_QFEZ (uptr)) { /* wrong ez? */ dt_seterr (uptr, STA_END); /* set ez flag, stop */ @@ -581,7 +599,7 @@ case FNC_READ: /* read */ if (dir) newpos = DTU_FWDEZ (uptr) - DT_HTLIN - DT_WSIZE; else newpos = DT_EZLIN + DT_HTLIN + (DT_WSIZE - 1); break; } - relpos = DT_LIN2OF (uptr -> pos, uptr); /* cur pos in blk */ + relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ if ((relpos >= DT_HTLIN) && /* in data zone? */ (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { dt_seterr (uptr, STA_BLKM); @@ -600,7 +618,7 @@ case FNC_WALL: /* write all */ if (DT_QEZ (uptr)) { /* in "ok" end zone? */ if (dir) newpos = DTU_FWDEZ (uptr) - DT_WSIZE; else newpos = DT_EZLIN + (DT_WSIZE - 1); } - else { relpos = DT_LIN2OF (uptr -> pos, uptr); /* cur pos in blk */ + else { relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ if (dir? (relpos < (DTU_LPERB (uptr) - DT_CSMLN)): /* switch in time? */ (relpos >= DT_CSMLN)) { dt_seterr (uptr, STA_BLKM); @@ -616,7 +634,7 @@ case FNC_WALL: /* write all */ default: dt_seterr (uptr, STA_SEL); /* bad state */ return; } -sim_activate (uptr, ABS (newpos - ((int32) uptr -> pos)) * dt_ltime); +sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime); return; } @@ -641,13 +659,13 @@ return; t_bool dt_setpos (UNIT *uptr) { uint32 new_time, ut, ulin, udelt; -int32 mot = DTS_GETMOT (uptr -> STATE); +int32 mot = DTS_GETMOT (uptr->STATE); int32 unum, delta; new_time = sim_grtime (); /* current time */ -ut = new_time - uptr -> LASTT; /* elapsed time */ +ut = new_time - uptr->LASTT; /* elapsed time */ if (ut == 0) return FALSE; /* no time gone? exit */ -uptr -> LASTT = new_time; /* update last time */ +uptr->LASTT = new_time; /* update last time */ switch (mot & ~DTS_DIR) { /* case on motion */ case DTS_STOP: /* stop */ delta = 0; @@ -663,12 +681,12 @@ case DTS_ACCF: /* accelerating */ case DTS_ATSF: /* at speed */ delta = ut / (uint32) dt_ltime; break; } -if (mot & DTS_DIR) uptr -> pos = uptr -> pos - delta; /* update pos */ -else uptr -> pos = uptr -> pos + delta; -if ((uptr -> pos < 0) || - (uptr -> pos > ((uint32) (DTU_FWDEZ (uptr) + DT_EZLIN)))) { +if (mot & DTS_DIR) uptr->pos = uptr->pos - delta; /* update pos */ +else uptr->pos = uptr->pos + delta; +if (((int32) uptr->pos < 0) || + ((int32) uptr->pos > (DTU_FWDEZ (uptr) + DT_EZLIN))) { detach_unit (uptr); /* off reel? */ - uptr -> STATE = uptr -> pos = 0; + uptr->STATE = uptr->pos = 0; unum = uptr - dt_dev.units; if ((unum == CSR_GETUNIT (tccm)) && (CSR_GETFNC (tccm) != FNC_STOP)) dt_seterr (uptr, STA_SEL); /* error */ @@ -691,11 +709,10 @@ return SCPE_OK; t_stat dt_svc (UNIT *uptr) { -int32 mot = DTS_GETMOT (uptr -> STATE); +int32 mot = DTS_GETMOT (uptr->STATE); int32 dir = mot & DTS_DIR; -int32 fnc = DTS_GETFNC (uptr -> STATE); -int32 *bptr = uptr -> filebuf; -int32 unum = uptr - dt_dev.units; +int32 fnc = DTS_GETFNC (uptr->STATE); +int32 *bptr = uptr->filebuf; int32 blk, wrd, relpos, dat; t_addr ma, mma, ba; @@ -709,12 +726,12 @@ t_addr ma, mma, ba; switch (mot) { case DTS_DECF: case DTS_DECR: /* decelerating */ if (dt_setpos (uptr)) return SCPE_OK; /* update pos */ - uptr -> STATE = DTS_NXTSTA (uptr -> STATE); /* advance state */ - if (uptr -> STATE) /* not stopped? */ + uptr->STATE = DTS_NXTSTA (uptr->STATE); /* advance state */ + if (uptr->STATE) /* not stopped? */ sim_activate (uptr, dt_actime); /* must be reversing */ return SCPE_OK; case DTS_ACCF: case DTS_ACCR: /* accelerating */ - dt_newfnc (uptr, DTS_NXTSTA (uptr -> STATE)); /* adv state, sched */ + dt_newfnc (uptr, DTS_NXTSTA (uptr->STATE)); /* adv state, sched */ return SCPE_OK; case DTS_ATSF: case DTS_ATSR: /* at speed */ break; /* check function */ @@ -732,7 +749,7 @@ if (dt_setpos (uptr)) return SCPE_OK; /* update pos */ if (DT_QEZ (uptr)) { /* in end zone? */ dt_seterr (uptr, STA_END); /* end zone error */ return SCPE_OK; } -blk = DT_LIN2BL (uptr -> pos, uptr); /* get block # */ +blk = DT_LIN2BL (uptr->pos, uptr); /* get block # */ switch (fnc) { /* at speed, check fnc */ case FNC_SRCH: /* search */ @@ -742,7 +759,7 @@ case FNC_SRCH: /* search */ break; case DTS_OFR: /* off reel */ detach_unit (uptr); /* must be deselected */ - uptr -> STATE = uptr -> pos = 0; /* no visible action */ + uptr->STATE = uptr->pos = 0; /* no visible action */ break; /* Read @@ -755,7 +772,7 @@ case DTS_OFR: /* off reel */ */ case FNC_READ: /* read */ - wrd = DT_LIN2WD (uptr -> pos, uptr); /* get word # */ + wrd = DT_LIN2WD (uptr->pos, uptr); /* get word # */ if (!dt_substate) { /* !wc ovf? */ tcwc = tcwc & DMASK; /* incr MA, WC */ tcba = tcba & DMASK; @@ -789,7 +806,7 @@ case FNC_READ: /* read */ */ case FNC_WRIT: /* write */ - wrd = DT_LIN2WD (uptr -> pos, uptr); /* get word # */ + wrd = DT_LIN2WD (uptr->pos, uptr); /* get word # */ if (dt_substate) tcdt = 0; /* wc ovf? fill */ else { ma = (CSR_GETMEX (tccm) << 16) | tcba; /* form 18b addr */ if (!Map_Addr (ma, &mma) || /* map addr */ @@ -802,7 +819,7 @@ case FNC_WRIT: /* write */ if (tcba <= 1) tccm = CSR_INCMEX (tccm); } ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */ bptr[ba] = tcdt; /* write word */ - if (ba >= uptr -> hwmark) uptr -> hwmark = ba + 1; + if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; if (tcwc == 0) dt_substate = 1; if (wrd != (dir? 0: DTU_BSIZE (uptr) - 1)) /* not end blk? */ sim_activate (uptr, DT_WSIZE * dt_ltime); @@ -818,10 +835,10 @@ case FNC_RALL: if (tccm & CSR_DONE) { /* done set? */ dt_seterr (uptr, STA_DATM); /* data miss */ break; } - relpos = DT_LIN2OF (uptr -> pos, uptr); /* cur pos in blk */ + relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ if ((relpos >= DT_HTLIN) && /* in data zone? */ (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { - wrd = DT_LIN2WD (uptr -> pos, uptr); + wrd = DT_LIN2WD (uptr->pos, uptr); ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */ dat = bptr[ba]; } /* get tape word */ else dat = dt_gethdr (uptr, blk, relpos); /* get hdr */ @@ -838,15 +855,15 @@ case FNC_WALL: if (tccm & CSR_DONE) { /* done set? */ dt_seterr (uptr, STA_DATM); /* data miss */ break; } - relpos = DT_LIN2OF (uptr -> pos, uptr); /* cur pos in blk */ + relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ if ((relpos >= DT_HTLIN) && /* in data zone? */ (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { - wrd = DT_LIN2WD (uptr -> pos, uptr); + wrd = DT_LIN2WD (uptr->pos, uptr); dat = (STA_GETXD (tcst) << 16) | tcdt; /* get data word */ if (dir) dat = dt_comobv (dat); /* rev? comp obv */ ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */ bptr[ba] = dat; /* write word */ - if (ba >= uptr -> hwmark) uptr -> hwmark = ba + 1; } + if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; } /* else /* ignore hdr */ sim_activate (uptr, DT_WSIZE * dt_ltime); DT_SETDONE; /* set done */ @@ -863,7 +880,7 @@ return SCPE_OK; void dt_seterr (UNIT *uptr, int32 e) { -int32 mot = DTS_GETMOT (uptr -> STATE); +int32 mot = DTS_GETMOT (uptr->STATE); tcst = tcst | e; /* set error flag */ tccm = tccm | CSR_ERR; @@ -881,7 +898,7 @@ return; void dt_stopunit (UNIT *uptr) { -int32 mot = DTS_GETMOT (uptr -> STATE); +int32 mot = DTS_GETMOT (uptr->STATE); int32 dir = mot & DTS_DIR; if (mot == DTS_STOP) return; /* already stopped? */ @@ -901,7 +918,7 @@ int32 newpos; if (dir) newpos = DT_EZLIN - DT_WSIZE; /* rev? rev ez */ else newpos = DTU_FWDEZ (uptr) + DT_WSIZE; /* fwd? fwd ez */ -sim_activate (uptr, ABS (newpos - ((int32) uptr -> pos)) * dt_ltime); +sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime); return; } @@ -920,7 +937,7 @@ return dat; int32 dt_csum (UNIT *uptr, int32 blk) { -int32 *bptr = uptr -> filebuf; +int32 *bptr = uptr->filebuf; int32 ba = blk * DTU_BSIZE (uptr); int32 i, csum, wrd; @@ -955,7 +972,7 @@ UNIT *uptr; for (i = 0; i < DT_NUMDR; i++) { /* stop all activity */ uptr = dt_dev.units + i; if (sim_is_running) { /* RESET? */ - prev_mot = DTS_GETMOT (uptr -> STATE); /* get motion */ + prev_mot = DTS_GETMOT (uptr->STATE); /* get motion */ if ((prev_mot & ~DTS_DIR) > DTS_DECF) { /* accel or spd? */ if (dt_setpos (uptr)) continue; /* update pos */ sim_cancel (uptr); @@ -963,8 +980,8 @@ for (i = 0; i < DT_NUMDR; i++) { /* stop all activity */ DTS_SETSTA (DTS_DECF | (prev_mot & DTS_DIR), 0); } } else { sim_cancel (uptr); /* sim reset */ - uptr -> STATE = 0; - uptr -> LASTT = sim_grtime (); } } + uptr->STATE = 0; + uptr->LASTT = sim_grtime (); } } tcst = tcwc = tcba = tcdt = 0; /* clear reg */ tccm = CSR_DONE; CLR_INT (DTA); /* clear int req */ @@ -974,13 +991,14 @@ return SCPE_OK; /* Device bootstrap */ #define BOOT_START 02000 /* start */ -#define BOOT_ENTRY 02002 /* entry */ -#define BOOT_UNIT 02010 /* unit number */ -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) +#define BOOT_ENTRY (BOOT_START + 002) /* entry */ +#define BOOT_UNIT (BOOT_START + 010) /* unit number */ +#define BOOT_CSR (BOOT_START + 020) /* CSR */ +#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) -static const int32 boot_rom[] = { +static const uint16 boot_rom[] = { 0042124, /* "TD" */ - 0012706, 0002000, /* MOV #2000, SP */ + 0012706, BOOT_START, /* MOV #boot_start, SP */ 0012700, 0000000, /* MOV #unit, R0 ; unit number */ 0010003, /* MOV R0, R3 */ 0000303, /* SWAB R3 */ @@ -991,7 +1009,7 @@ static const int32 boot_rom[] = { 0032711, 0100200, /* BIT #100200, (R1) ; wait */ 0001775, /* BEQ .-4 */ 0100370, /* BPL RW ; no err, cont */ - 0005737, 0177340, /* TST TCST ; end zone? */ + 0005761, 0177776, /* TST -2(R1) ; end zone? */ 0100036, /* BPL ER ; no, err */ 0012702, 0000003, /* MOV #3, R2 ; rnum+go */ 0050302, /* BIS R3, R2 */ @@ -999,10 +1017,10 @@ static const int32 boot_rom[] = { 0032711, 0100200, /* BIT #100200, (R1) ; wait */ 0001775, /* BEQ .-4 */ 0100426, /* BMI ER ; err, die */ - 0005737, 0177350, /* TST TCDT ; blk 0? */ + 0005761, 0000006, /* TST 6(R1) ; blk 0? */ 0001023, /* BNE ER ; no, die */ - 0012737, 0177000, 0177344, /* MOV #-256.*2, TCWC ; load wc */ - 0005037, 0177346, /* CLR TCBA ; clear ba */ + 0012761, 0177000, 0000002, /* MOV #-256.*2, 2(R1) ; load wc */ + 0005061, 0000004, /* CLR 4(R1) ; clear ba */ 0012702, 0000005, /* MOV #READ+GO, R2 ; read & go */ 0050302, /* BIS R3, R2 */ 0010211, /* MOV R2, (R1) ; load csr */ @@ -1018,7 +1036,7 @@ static const int32 boot_rom[] = { 0000000 /* HALT */ }; -t_stat dt_boot (int32 unitno) +t_stat dt_boot (int32 unitno, DEVICE *dptr) { int32 i; extern int32 saved_PC; @@ -1026,108 +1044,135 @@ extern int32 saved_PC; dt_unit[unitno].pos = DT_EZLIN; for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i]; M[BOOT_UNIT >> 1] = unitno & DT_M_NUMDR; +M[BOOT_CSR >> 1] = (dt_dib.ba & DMASK) + 02; saved_PC = BOOT_ENTRY; return SCPE_OK; } /* Attach routine - Determine native or PDP8 format + Determine 12b, 16b, or 18b/36b format Allocate buffer - If PDP8, read 12b format and convert to 18b in buffer - If native, read data into buffer + If 12b, read 12b format and convert to 18b in buffer + If 16b, read 16b format and convert to 18b in buffer + If 18b/36b, read data into buffer */ t_stat dt_attach (UNIT *uptr, char *cptr) { uint16 pdp8b[D8_NBSIZE]; -int32 k, p, *bptr; +uint16 pdp11b[D18_BSIZE]; +uint32 k, p, *bptr; t_stat r; t_addr ba; -uptr -> flags = uptr -> flags & ~UNIT_8FMT; r = attach_unit (uptr, cptr); /* attach */ if (r != SCPE_OK) return r; /* fail? */ -if (sim_switches & SWMASK ('F')) /* att foreign? */ - uptr -> flags = uptr -> flags | UNIT_8FMT; /* PDP8 = T */ -else if (!(sim_switches & SWMASK ('N'))) { /* autosize? */ - if ((fseek (uptr -> fileref, 0, SEEK_END) == 0) && - (p = ftell (uptr -> fileref)) && - (p == D8_FILSIZ)) uptr -> flags = uptr -> flags | UNIT_8FMT; } -uptr -> capac = DTU_CAPAC (uptr); /* set capacity */ -uptr -> filebuf = calloc (uptr -> capac, sizeof (int32)); -if (uptr -> filebuf == NULL) { /* can't alloc? */ +uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT; /* default 16b */ +if (sim_switches & SWMASK ('R')) /* att 12b? */ + uptr->flags = (uptr->flags | UNIT_8FMT) & ~UNIT_11FMT; +else if (sim_switches & SWMASK ('T')) /* att 18b? */ + uptr->flags = uptr->flags & ~(UNIT_8FMT | UNIT_11FMT); +else if (!(sim_switches & SWMASK ('S')) && /* autosize? */ + (fseek (uptr->fileref, 0, SEEK_END) == 0) && + ((p = ftell (uptr->fileref)) > D16_FILSIZ)) { + if (p <= D8_FILSIZ) + uptr->flags = (uptr->flags | UNIT_8FMT) & ~UNIT_11FMT; + else uptr->flags = uptr->flags & ~(UNIT_8FMT | UNIT_11FMT); } +uptr->capac = DTU_CAPAC (uptr); /* set capacity */ +uptr->filebuf = calloc (uptr->capac, sizeof (int32)); +if (uptr->filebuf == NULL) { /* can't alloc? */ detach_unit (uptr); return SCPE_MEM; } -printf ("TC: buffering file in memory\n"); -rewind (uptr -> fileref); /* start of file */ -if (uptr -> flags & UNIT_8FMT) { /* PDP-8? */ - bptr = uptr -> filebuf; /* file buffer */ - for (ba = 0; ba < uptr -> capac; ) { /* loop thru file */ - k = fxread (pdp8b, sizeof (int16), D8_NBSIZE, uptr -> fileref); - if (k == 0) break; - for ( ; k < D8_NBSIZE; k++) pdp8b[k] = 0; - for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop thru blk */ - bptr[ba] = ((uint32) (pdp8b[k] & 07777) << 6) | - ((uint32) (pdp8b[k + 1] >> 6) & 077); - bptr[ba + 1] = ((pdp8b[k + 1] & 077) << 12) | - ((uint32) (pdp8b[k + 2] & 07777)); - ba = ba + 2; } /* end blk loop */ - } /* end file loop */ - uptr -> hwmark = ba; } /* end if */ -else uptr -> hwmark = fxread (uptr -> filebuf, sizeof (int32), - uptr -> capac, uptr -> fileref); -uptr -> flags = uptr -> flags | UNIT_BUF; /* set buf flag */ -uptr -> pos = DT_EZLIN; /* beyond leader */ -uptr -> LASTT = sim_grtime (); /* last pos update */ +bptr = uptr->filebuf; /* file buffer */ +if (uptr->flags & UNIT_8FMT) printf ("TC: 12b format"); +else if (uptr->flags & UNIT_11FMT) printf ("TC: 16b format"); +else printf ("TC: 18b/36b format"); +printf (", buffering file in memory\n"); +rewind (uptr->fileref); /* start of file */ +if (uptr->flags & UNIT_8FMT) { /* 12b? */ + for (ba = 0; ba < uptr->capac; ) { /* loop thru file */ + k = fxread (pdp8b, sizeof (int16), D8_NBSIZE, uptr->fileref); + if (k == 0) break; + for ( ; k < D8_NBSIZE; k++) pdp8b[k] = 0; + for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop thru blk */ + bptr[ba] = ((uint32) (pdp8b[k] & 07777) << 6) | + ((uint32) (pdp8b[k + 1] >> 6) & 077); + bptr[ba + 1] = ((pdp8b[k + 1] & 077) << 12) | + ((uint32) (pdp8b[k + 2] & 07777)); + ba = ba + 2; } /* end blk loop */ + } /* end file loop */ + uptr->hwmark = ba; } /* end if */ +else if (uptr->flags & UNIT_11FMT) { /* 16b? */ + for (ba = 0; ba < uptr->capac; ) { /* loop thru file */ + k = fxread (pdp11b, sizeof (int16), D18_BSIZE, uptr->fileref); + if (k == 0) break; + for ( ; k < D18_BSIZE; k++) pdp11b[k] = 0; + for (k = 0; k < D18_BSIZE; k++) + bptr[ba++] = pdp11b[k]; } + uptr->hwmark = ba; } /* end elif */ +else uptr->hwmark = fxread (uptr->filebuf, sizeof (int32), + uptr->capac, uptr->fileref); +uptr->flags = uptr->flags | UNIT_BUF; /* set buf flag */ +uptr->pos = DT_EZLIN; /* beyond leader */ +uptr->LASTT = sim_grtime (); /* last pos update */ return SCPE_OK; } /* Detach routine Cancel in progress operation - If PDP8, convert 18b buffer to 12b and write to file - If native, write buffer to file + If 12b, convert 18b buffer to 12b and write to file + If 16b, convert 18b buffer to 16b and write to file + If 18b/36b, write buffer to file Deallocate buffer */ t_stat dt_detach (UNIT* uptr) { uint16 pdp8b[D8_NBSIZE]; -int32 k, *bptr; +uint16 pdp11b[D18_BSIZE]; +uint32 k, *bptr; int32 unum = uptr - dt_dev.units; t_addr ba; -if (!(uptr -> flags & UNIT_ATT)) return SCPE_OK; +if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; if (sim_is_active (uptr)) { /* active? cancel op */ sim_cancel (uptr); if ((unum == CSR_GETUNIT (tccm)) && ((tccm & CSR_DONE) == 0)) { - tcst = tcst | STA_SEL; - tccm = tccm | CSR_ERR | CSR_DONE; - if (tccm & CSR_IE) SET_INT (DTA); } - uptr -> STATE = uptr -> pos = 0; } -if (uptr -> hwmark && ((uptr -> flags & UNIT_RO) == 0)) { /* any data? */ + tcst = tcst | STA_SEL; + tccm = tccm | CSR_ERR | CSR_DONE; + if (tccm & CSR_IE) SET_INT (DTA); } + uptr->STATE = uptr->pos = 0; } +bptr = uptr->filebuf; /* file buffer */ +if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { /* any data? */ printf ("TC: writing buffer to file\n"); - rewind (uptr -> fileref); /* start of file */ - if (uptr -> flags & UNIT_8FMT) { /* PDP8? */ - bptr = uptr -> filebuf; /* file buffer */ - for (ba = 0; ba < uptr -> hwmark; ) { /* loop thru buf */ - for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop blk */ - pdp8b[k] = (bptr[ba] >> 6) & 07777; - pdp8b[k + 1] = ((bptr[ba] & 077) << 6) | - ((bptr[ba + 1] >> 12) & 077); - pdp8b[k + 2] = bptr[ba + 1] & 07777; - ba = ba + 2; } /* end loop blk */ - fxwrite (pdp8b, sizeof (int16), D8_NBSIZE, uptr -> fileref); - if (ferror (uptr -> fileref)) break; } /* end loop file */ - } /* end if PDP8 */ - else fxwrite (uptr -> filebuf, sizeof (int32), /* write file */ - uptr -> hwmark, uptr -> fileref); - if (ferror (uptr -> fileref)) perror ("I/O error"); } /* end if hwmark */ -free (uptr -> filebuf); /* release buf */ -uptr -> flags = uptr -> flags & ~UNIT_BUF; /* clear buf flag */ -uptr -> filebuf = NULL; /* clear buf ptr */ -uptr -> flags = uptr -> flags & ~UNIT_8FMT; /* default fmt */ -uptr -> capac = DT_CAPAC; /* default size */ + rewind (uptr->fileref); /* start of file */ + if (uptr->flags & UNIT_8FMT) { /* 12b? */ + for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */ + for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop blk */ + pdp8b[k] = (bptr[ba] >> 6) & 07777; + pdp8b[k + 1] = ((bptr[ba] & 077) << 6) | + ((bptr[ba + 1] >> 12) & 077); + pdp8b[k + 2] = bptr[ba + 1] & 07777; + ba = ba + 2; } /* end loop blk */ + fxwrite (pdp8b, sizeof (int16), D8_NBSIZE, uptr->fileref); + if (ferror (uptr->fileref)) break; } /* end loop file */ + } /* end if 12b */ + else if (uptr->flags & UNIT_11FMT) { /* 16b? */ + for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */ + for (k = 0; k < D18_BSIZE; k++) /* loop blk */ + pdp11b[k] = bptr[ba++] & DMASK; + fxwrite (pdp11b, sizeof (int16), D18_BSIZE, uptr->fileref); + if (ferror (uptr->fileref)) break; } /* end loop file */ + } /* end if 16b */ + else fxwrite (uptr->filebuf, sizeof (int32), /* write file */ + uptr->hwmark, uptr->fileref); + if (ferror (uptr->fileref)) perror ("I/O error"); } /* end if hwmark */ +free (uptr->filebuf); /* release buf */ +uptr->flags = uptr->flags & ~UNIT_BUF; /* clear buf flag */ +uptr->filebuf = NULL; /* clear buf ptr */ +uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT; /* default fmt */ +uptr->capac = DT_CAPAC; /* default size */ return detach_unit (uptr); } diff --git a/PDP11/pdp11_tm.c b/PDP11/pdp11_tm.c index 38d5318d..58b78192 100644 --- a/PDP11/pdp11_tm.c +++ b/PDP11/pdp11_tm.c @@ -25,6 +25,13 @@ tm TM11/TU10 magtape + 30-Oct-02 RMS Revised BOT handling, added error record handling + 30-Sep-02 RMS Added variable address support to bootstrap + Added vector change/display support + Changed mapping mnemonics + New data structures + Updated error handling + 28-Aug-02 RMS Added end of medium support 30-May-02 RMS Widened POS to 32b 22-Apr-02 RMS Fixed max record length, first block bootstrap (found by Jonathan Engdahl) @@ -68,10 +75,10 @@ #define TM_NUMDR 8 /* #drives */ #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_WLK 1 << UNIT_V_WLK -#define UNIT_W_UF 2 /* saved user flags */ +#define UNIT_V_PNU (UNIT_V_UF + 1) /* pos not updated */ +#define UNIT_WLK (1 << UNIT_V_WLK) +#define UNIT_PNU (1 << UNIT_V_PNU) #define USTAT u3 /* unit status */ -#define UNUM u4 /* unit number */ #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ /* Command - tm_cmd */ @@ -108,7 +115,7 @@ #define GET_UNIT(x) (((x) >> MTC_V_UNIT) & MTC_M_UNIT) #define GET_FNC(x) (((x) >> MTC_V_FNC) & MTC_M_FNC) -/* Status - stored in tm_sta or (*) uptr -> USTAT or (+) calculated */ +/* Status - stored in tm_sta or (*) uptr->USTAT or (+) calculated */ #define STA_ILL 0100000 /* illegal */ #define STA_EOF 0040000 /* *end of file */ @@ -140,6 +147,8 @@ extern uint16 *M; /* memory */ extern int32 int_req[IPL_HLVL]; +extern int32 int_vec[IPL_HLVL][32]; + uint8 *tmxb = NULL; /* xfer buffer */ int32 tm_sta = 0; /* status register */ int32 tm_cmd = 0; /* command register */ @@ -150,16 +159,19 @@ int32 tm_rdl = 0; /* read lines */ int32 tm_time = 10; /* record latency */ int32 tm_stopioe = 1; /* stop on error */ +DEVICE tm_dev; t_stat tm_rd (int32 *data, int32 PA, int32 access); t_stat tm_wr (int32 data, int32 PA, int32 access); t_stat tm_svc (UNIT *uptr); t_stat tm_reset (DEVICE *dptr); t_stat tm_attach (UNIT *uptr, char *cptr); t_stat tm_detach (UNIT *uptr); -t_stat tm_boot (int32 unitno); +t_stat tm_boot (int32 unitno, DEVICE *dptr); void tm_go (UNIT *uptr); int32 tm_updcsta (UNIT *uptr); void tm_set_done (void); +t_bool tm_rdlntf (UNIT *uptr, t_mtrlnt *tbc, int32 *err); +t_bool tm_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err); t_stat tm_vlock (UNIT *uptr, int32 val, char *cptr, void *desc); /* MT data structures @@ -170,7 +182,8 @@ t_stat tm_vlock (UNIT *uptr, int32 val, char *cptr, void *desc); tm_mod MT modifier list */ -DIB tm_dib = { 1, IOBA_TM, IOLN_TM, &tm_rd, &tm_wr }; +DIB tm_dib = { IOBA_TM, IOLN_TM, &tm_rd, &tm_wr, + 1, IVCL (TM), VEC_TM, { NULL } }; UNIT tm_unit[] = { { UDATA (&tm_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, @@ -198,28 +211,25 @@ REG tm_reg[] = { { URDATA (UST, tm_unit[0].USTAT, 8, 16, 0, TM_NUMDR, 0) }, { URDATA (POS, tm_unit[0].pos, 10, 32, 0, TM_NUMDR, PV_LEFT | REG_RO) }, - { URDATA (FLG, tm_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, - TM_NUMDR, REG_HRO) }, { ORDATA (DEVADDR, tm_dib.ba, 32), REG_HRO }, - { FLDATA (*DEVENB, tm_dib.enb, 0), REG_HRO }, + { ORDATA (DEVVEC, tm_dib.vec, 16), REG_HRO }, { NULL } }; MTAB tm_mod[] = { { UNIT_WLK, 0, "write enabled", "WRITEENABLED", &tm_vlock }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &tm_vlock }, { MTAB_XTD|MTAB_VDV, 020, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, &tm_dib }, - { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", - &set_enbdis, NULL, &tm_dib }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", - &set_enbdis, NULL, &tm_dib }, + &set_addr, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + &set_vec, &show_vec, NULL }, { 0 } }; DEVICE tm_dev = { "TM", tm_unit, tm_reg, tm_mod, TM_NUMDR, 10, 31, 1, 8, 8, NULL, NULL, &tm_reset, - &tm_boot, &tm_attach, &tm_detach }; + &tm_boot, &tm_attach, &tm_detach, + &tm_dib, DEV_DISABLE | DEV_UBUS }; /* I/O dispatch routine, I/O addresses 17772520 - 17772532 @@ -313,20 +323,20 @@ void tm_go (UNIT *uptr) int32 f; f = GET_FNC (tm_cmd); /* get function */ -if (((uptr -> flags & UNIT_ATT) == 0) || /* not attached? */ +if (((uptr->flags & UNIT_ATT) == 0) || /* not attached? */ sim_is_active (uptr) || /* busy? */ (((f == MTC_WRITE) || (f == MTC_WREOF) || (f == MTC_WREXT)) && - (uptr -> flags & UNIT_WPRT))) { /* write locked? */ + (uptr->flags & UNIT_WPRT))) { /* write locked? */ tm_sta = tm_sta | STA_ILL; /* illegal */ tm_set_done (); /* set done */ return; } -uptr -> USTAT = uptr -> USTAT & (STA_WLK | STA_ONL); /* clear status */ +uptr->USTAT = uptr->USTAT & (STA_WLK | STA_ONL); /* clear status */ tm_sta = 0; /* clear errors */ if (f == MTC_UNLOAD) { /* unload? */ - uptr -> USTAT = (uptr -> USTAT | STA_REW) & ~STA_ONL; + uptr->USTAT = (uptr->USTAT | STA_REW) & ~STA_ONL; detach_unit (uptr); } /* set offline */ else if (f == MTC_REWIND) /* rewind */ - uptr -> USTAT = uptr -> USTAT | STA_REW; /* rewinding */ + uptr->USTAT = uptr->USTAT | STA_REW; /* rewinding */ /* else /* uncomment this else if rewind/unload don't set done */ tm_cmd = tm_cmd & ~MTC_DONE; /* clear done */ CLR_INT (TM); /* clear int */ @@ -342,25 +352,27 @@ return; t_stat tm_svc (UNIT *uptr) { -int32 f, i, t, err; +int32 f, t, err, pnu, u; t_addr xma; -t_stat rval; -t_mtrlnt tbc, cbc; -static t_mtrlnt bceof = { 0 }; +t_mtrlnt abc, tbc, cbc, ebc; +static t_mtrlnt bceof = { MTR_TMK }; -if (uptr -> USTAT & STA_REW) { /* rewind? */ - uptr -> pos = 0; /* update position */ - if (uptr -> flags & UNIT_ATT) /* still on line? */ - uptr -> USTAT = STA_ONL | STA_BOT | - ((uptr -> flags & UNIT_WPRT)? STA_WLK: 0); - else uptr -> USTAT = 0; - if (uptr -> UNUM == GET_UNIT (tm_cmd)) { /* selected? */ +u = uptr - tm_dev.units; /* get unit number */ +pnu = MT_TST_PNU (uptr); /* get pos not upd */ +MT_CLR_PNU (uptr); /* and clear */ +if (uptr->USTAT & STA_REW) { /* rewind? */ + uptr->pos = 0; /* update position */ + if (uptr->flags & UNIT_ATT) /* still on line? */ + uptr->USTAT = STA_ONL | STA_BOT | + ((uptr->flags & UNIT_WPRT)? STA_WLK: 0); + else uptr->USTAT = 0; + if (u == GET_UNIT (tm_cmd)) { /* selected? */ tm_set_done (); /* set done */ tm_updcsta (uptr); } /* update status */ return SCPE_OK; } -if ((uptr -> flags & UNIT_ATT) == 0) { /* if not attached */ - uptr -> USTAT = 0; /* unit off line */ +if ((uptr->flags & UNIT_ATT) == 0) { /* if not attached */ + uptr->USTAT = 0; /* unit off line */ tm_sta = tm_sta | STA_ILL; /* illegal operation */ tm_set_done (); /* set done */ tm_updcsta (uptr); /* update status */ @@ -368,14 +380,13 @@ if ((uptr -> flags & UNIT_ATT) == 0) { /* if not attached */ f = GET_FNC (tm_cmd); /* get command */ if (((f == MTC_WRITE) || (f == MTC_WREOF) || (f == MTC_WREXT)) && - (uptr -> flags & UNIT_WPRT)) { /* write and locked? */ + (uptr->flags & UNIT_WPRT)) { /* write and locked? */ tm_sta = tm_sta | STA_ILL; /* illegal operation */ tm_set_done (); /* set done */ tm_updcsta (uptr); /* update status */ return SCPE_OK; } err = 0; -rval = SCPE_OK; xma = GET_EMA (tm_cmd) | tm_ca; /* get mem addr */ cbc = 0200000 - tm_bc; /* get bc */ switch (f) { /* case on function */ @@ -383,116 +394,85 @@ switch (f) { /* case on function */ /* Unit service, continued */ case MTC_READ: /* read */ - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); - fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - if ((err = ferror (uptr -> fileref)) || /* error or eof? */ - (feof (uptr -> fileref))) { - uptr -> USTAT = uptr -> USTAT | STA_EOT; - break; } - if (tbc == 0) { /* tape mark? */ - uptr -> USTAT = uptr -> USTAT | STA_EOF; - uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); - break; } - tbc = MTRL (tbc); /* ignore error flag */ + if (tm_rdlntf (uptr, &tbc, &err)) break; /* read rec lnt, err? */ if (tbc > MT_MAXFR) return SCPE_MTRLNT; /* record too long? */ if (tbc > cbc) tm_sta = tm_sta | STA_RLE; /* wrong size? */ if (tbc < cbc) cbc = tbc; /* use smaller */ - i = fxread (tmxb, sizeof (int8), cbc, uptr -> fileref); - err = ferror (uptr -> fileref); - for ( ; i < cbc; i++) tmxb[i] = 0; /* fill with 0's */ - if (t = Map_WriteB (xma, cbc, tmxb, UB)) { /* copy buf to mem */ + abc = fxread (tmxb, sizeof (int8), cbc, uptr->fileref); + if (err = ferror (uptr->fileref)) { /* error? */ + MT_SET_PNU (uptr); /* pos not upd */ + break; } + for ( ; abc < cbc; abc++) tmxb[abc] = 0; /* fill with 0's */ + if (t = Map_WriteB (xma, cbc, tmxb, MAP)) { /* copy buf to mem */ tm_sta = tm_sta | STA_NXM; /* NXM, set err */ cbc = cbc - t; } /* adj byte cnt */ xma = (xma + cbc) & 0777777; /* inc bus addr */ tm_bc = (tm_bc + cbc) & 0177777; /* inc byte cnt */ - uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) + /* upd position */ + uptr->pos = uptr->pos + ((tbc + 1) & ~1) + /* upd position */ (2 * sizeof (t_mtrlnt)); break; + case MTC_WRITE: /* write */ case MTC_WREXT: /* write ext gap */ - if (t = Map_ReadB (xma, cbc, tmxb, UB)) { /* copy mem to buf */ + if (t = Map_ReadB (xma, cbc, tmxb, MAP)) { /* copy mem to buf */ tm_sta = tm_sta | STA_NXM; /* NXM, set err */ cbc = cbc - t; /* adj byte cnt */ if (cbc == 0) break; } /* no xfr? done */ - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); - fxwrite (&cbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - fxwrite (tmxb, sizeof (int8), cbc, uptr -> fileref); - fxwrite (&cbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - err = ferror (uptr -> fileref); - xma = (xma + cbc) & 0777777; /* inc bus addr */ - tm_bc = (tm_bc + cbc) & 0177777; /* inc byte cnt */ - uptr -> pos = uptr -> pos + ((cbc + 1) & ~1) + /* upd position */ - (2 * sizeof (t_mtrlnt)); - break; -case MTC_WREOF: - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); - fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr -> fileref); - err = ferror (uptr -> fileref); - uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); /* update position */ + ebc = (cbc + 1) & ~1; /* force even */ + fseek (uptr->fileref, uptr->pos, SEEK_SET); + fxwrite (&cbc, sizeof (t_mtrlnt), 1, uptr->fileref); + fxwrite (tmxb, sizeof (int8), ebc, uptr->fileref); + fxwrite (&cbc, sizeof (t_mtrlnt), 1, uptr->fileref); + if (err = ferror (uptr->fileref)) MT_SET_PNU (uptr); /* error? */ + else { xma = (xma + cbc) & 0777777; /* inc bus addr */ + tm_bc = (tm_bc + cbc) & 0177777; /* inc byte cnt */ + uptr->pos = uptr->pos + ebc + /* upd pos */ + (2 * sizeof (t_mtrlnt)); } break; /* Unit service, continued */ +case MTC_WREOF: + fseek (uptr->fileref, uptr->pos, SEEK_SET); + fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr->fileref); + if (err = ferror (uptr->fileref)) MT_SET_PNU (uptr); /* error? */ + else uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* update position */ + break; + case MTC_SPACEF: /* space forward */ do { tm_bc = (tm_bc + 1) & 0177777; /* incr wc */ - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); - fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - if ((err = ferror (uptr -> fileref)) || /* error or eof? */ - feof (uptr -> fileref)) { - uptr -> USTAT = uptr -> USTAT | STA_EOT; - break; } - if (tbc == 0) { /* zero bc? */ - uptr -> USTAT = uptr -> USTAT | STA_EOF; - uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); - break; } - uptr -> pos = uptr -> pos + ((MTRL (tbc) + 1) & ~1) + + if (tm_rdlntf (uptr, &tbc, &err)) break;/* read rec lnt, err? */ + uptr->pos = uptr->pos + ((tbc + 1) & ~1) + (2 * sizeof (t_mtrlnt)); } while (tm_bc != 0); break; + case MTC_SPACER: /* space reverse */ - if (uptr -> pos == 0) { /* at BOT? */ - uptr -> USTAT = uptr -> USTAT | STA_BOT; - break; } do { tm_bc = (tm_bc + 1) & 0177777; /* incr wc */ - fseek (uptr -> fileref, uptr -> pos - sizeof (t_mtrlnt), - SEEK_SET); - fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - if ((err = ferror (uptr -> fileref)) || /* error or eof? */ - feof (uptr -> fileref)) { - uptr -> USTAT = uptr -> USTAT | STA_BOT; - uptr -> pos = 0; - break; } - if (tbc == 0) { /* start of prv file? */ - uptr -> USTAT = uptr -> USTAT | STA_EOF; - uptr -> pos = uptr -> pos - sizeof (t_mtrlnt); - break; } - uptr -> pos = uptr -> pos - ((MTRL (tbc) + 1) & ~1) - - (2 * sizeof (t_mtrlnt)); - if (uptr -> pos == 0) { /* start of tape? */ - uptr -> USTAT = uptr -> USTAT | STA_BOT; - break; } } + if (pnu) pnu = 0; /* pos not upd? */ + else { if (tm_rdlntr (uptr, &tbc, &err)) break; + uptr->pos = uptr->pos - ((tbc + 1) & ~1) - + (2 * sizeof (t_mtrlnt)); } } while (tm_bc != 0); break; } /* end case */ - -/* Unit service, continued */ -if (err != 0) { /* I/O error */ - tm_sta = tm_sta | STA_PAR | STA_CRC; /* flag error */ - perror ("MT I/O error"); - rval = SCPE_IOERR; - clearerr (uptr -> fileref); } +if (err != 0) tm_sta = tm_sta | STA_PAR; /* flag error */ tm_cmd = (tm_cmd & ~MTC_EMA) | ((xma >> (16 - MTC_V_EMA)) & MTC_EMA); tm_ca = xma & 0177777; /* update mem addr */ tm_set_done (); /* set done */ tm_updcsta (uptr); /* update status */ -return IORETURN (tm_stopioe, rval); +if (err != 0) { /* I/O error */ + perror ("MT I/O error"); + clearerr (uptr->fileref); + if (tm_stopioe) return SCPE_IOERR; } +return SCPE_OK; } - + /* Update controller status */ int32 tm_updcsta (UNIT *uptr) { -tm_sta = (tm_sta & ~(STA_DYN | STA_CLR)) | (uptr -> USTAT & STA_DYN); +tm_sta = (tm_sta & ~(STA_DYN | STA_CLR)) | (uptr->USTAT & STA_DYN); if (sim_is_active (uptr)) tm_sta = tm_sta & ~STA_TUR; else tm_sta = tm_sta | STA_TUR; if (tm_sta & STA_EFLGS) tm_cmd = tm_cmd | MTC_ERR; @@ -509,6 +489,57 @@ tm_cmd = tm_cmd | MTC_DONE; if (tm_cmd & MTC_IE) SET_INT (TM); return; } + +/* Read record length forward - return T if error, EOM, or EOF */ + +t_bool tm_rdlntf (UNIT *uptr, t_mtrlnt *tbc, int32 *err) +{ +fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set tape pos */ +fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); /* read rec lnt */ +if (*err = ferror (uptr->fileref)) { /* error? */ + tm_sta = tm_sta | STA_PAR; /* parity error */ + MT_SET_PNU (uptr); /* pos not upd */ + return TRUE; } +if (feof (uptr->fileref) || (*tbc == MTR_EOM)) { /* eof or eom? */ + tm_sta = tm_sta | STA_BAD; /* bad tape */ + MT_SET_PNU (uptr); /* pos not upd */ + return TRUE; } +if (*tbc == MTR_TMK) { /* tape mark? */ + uptr->USTAT = uptr->USTAT | STA_EOF; /* end of file */ + uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* spc over tmk */ + return TRUE; } +if (MTRF (*tbc)) tm_sta = tm_sta | STA_PAR; /* record in error? */ +*tbc = MTRL (*tbc); /* clear error flag */ +return FALSE; +} + +/* Read record length reverse - return T if error, EOM, or EOF */ + +t_bool tm_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err) +{ +if (uptr->pos < sizeof (t_mtrlnt)) { /* at BOT? */ + uptr->USTAT = uptr->USTAT | STA_BOT; /* set status */ + return TRUE; } /* error */ +fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt), SEEK_SET); +fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); +if (*err = ferror (uptr->fileref)) { /* error? */ + tm_sta = tm_sta | STA_PAR; /* parity error */ + return TRUE; } +if (feof (uptr->fileref)) { /* eof? */ + tm_sta = tm_sta | STA_BAD; /* bad tape */ + return TRUE; } +if (*tbc == MTR_EOM) { /* eom? */ + tm_sta = tm_sta | STA_BAD; /* bad tape */ + uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over eom */ + return TRUE; } +if (*tbc == MTR_TMK) { /* tape mark? */ + uptr->USTAT = uptr->USTAT | STA_EOF; /* end of file */ + uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over tmk */ + return TRUE; } +if (MTRF (*tbc)) tm_sta = tm_sta | STA_PAR; /* record in error? */ +*tbc = MTRL (*tbc); /* clear error flag */ +return FALSE; +} /* Reset routine */ @@ -522,12 +553,12 @@ tm_bc = tm_ca = tm_db = tm_sta = tm_rdl = 0; CLR_INT (TM); /* clear interrupt */ for (u = 0; u < TM_NUMDR; u++) { /* loop thru units */ uptr = tm_dev.units + u; - uptr -> UNUM = u; /* init drive number */ + MT_CLR_PNU (uptr); /* clear pos flag */ sim_cancel (uptr); /* cancel activity */ - if (uptr -> flags & UNIT_ATT) uptr -> USTAT = STA_ONL | - ((uptr -> pos)? 0: STA_BOT) | - ((uptr -> flags & UNIT_WPRT)? STA_WLK: 0); - else uptr -> USTAT = 0; } + if (uptr->flags & UNIT_ATT) uptr->USTAT = STA_ONL | + ((uptr->pos)? 0: STA_BOT) | + ((uptr->flags & UNIT_WPRT)? STA_WLK: 0); + else uptr->USTAT = 0; } if (tmxb == NULL) tmxb = calloc (MT_MAXFR, sizeof (unsigned int8)); if (tmxb == NULL) return SCPE_MEM; return SCPE_OK; @@ -538,11 +569,13 @@ return SCPE_OK; t_stat tm_attach (UNIT *uptr, char *cptr) { t_stat r; +int32 u = uptr - tm_dev.units; r = attach_unit (uptr, cptr); if (r != SCPE_OK) return r; -uptr -> USTAT = STA_ONL | STA_BOT | ((uptr -> flags & UNIT_WPRT)? STA_WLK: 0); -if (uptr -> UNUM == GET_UNIT (tm_cmd)) tm_updcsta (uptr); +MT_CLR_PNU (uptr); +uptr->USTAT = STA_ONL | STA_BOT | ((uptr->flags & UNIT_WPRT)? STA_WLK: 0); +if (u == GET_UNIT (tm_cmd)) tm_updcsta (uptr); return r; } @@ -550,8 +583,11 @@ return r; t_stat tm_detach (UNIT* uptr) { -if (!sim_is_active (uptr)) uptr -> USTAT = 0; -if (uptr -> UNUM == GET_UNIT (tm_cmd)) tm_updcsta (uptr); +int32 u = uptr - tm_dev.units; + +MT_CLR_PNU (uptr); +if (!sim_is_active (uptr)) uptr->USTAT = 0; +if (u == GET_UNIT (tm_cmd)) tm_updcsta (uptr); return detach_unit (uptr); } @@ -559,11 +595,13 @@ return detach_unit (uptr); t_stat tm_vlock (UNIT *uptr, int32 val, char *cptr, void *desc) { -if ((uptr -> flags & UNIT_ATT) && - (val || (uptr -> flags & UNIT_RO))) - uptr -> USTAT = uptr -> USTAT | STA_WLK; -else uptr -> USTAT = uptr -> USTAT & ~STA_WLK; -if (uptr -> UNUM == GET_UNIT (tm_cmd)) tm_updcsta (uptr); +int32 u = uptr - tm_dev.units; + +if ((uptr->flags & UNIT_ATT) && + (val || (uptr->flags & UNIT_RO))) + uptr->USTAT = uptr->USTAT | STA_WLK; +else uptr->USTAT = uptr->USTAT & ~STA_WLK; +if (u == GET_UNIT (tm_cmd)) tm_updcsta (uptr); return SCPE_OK; } @@ -578,15 +616,16 @@ return SCPE_OK; To boot from the first block, use boot -o (old). */ -#define BOOT_START 040000 +#define BOOT_START 016000 #define BOOT_ENTRY (BOOT_START + 2) #define BOOT_UNIT (BOOT_START + 010) -#define BOOT1_LEN (sizeof (boot1_rom) / sizeof (int32)) -#define BOOT2_LEN (sizeof (boot2_rom) / sizeof (int32)) +#define BOOT_CSR (BOOT_START + 014) +#define BOOT1_LEN (sizeof (boot1_rom) / sizeof (int16)) +#define BOOT2_LEN (sizeof (boot2_rom) / sizeof (int16)) -static const int32 boot1_rom[] = { +static const uint16 boot1_rom[] = { 0046524, /* boot_start: "TM" */ - 0012706, 0040000, /* mov #boot_start, sp */ + 0012706, BOOT_START, /* mov #boot_start, sp */ 0012700, 0000000, /* mov #unit_num, r0 */ 0012701, 0172526, /* mov #172526, r1 ; mtcma */ 0005011, /* clr (r1) */ @@ -604,9 +643,9 @@ static const int32 boot1_rom[] = { 0005007 /* clr r7 */ }; -static const int32 boot2_rom[] = { +static const uint16 boot2_rom[] = { 0046524, /* boot_start: "TM" */ - 0012706, 0040000, /* mov #boot_start, sp */ + 0012706, BOOT_START, /* mov #boot_start, sp */ 0012700, 0000000, /* mov #unit_num, r0 */ 0012701, 0172526, /* mov #172526, r1 ; mtcma */ 0005011, /* clr (r1) */ @@ -630,7 +669,7 @@ static const int32 boot2_rom[] = { 0005007 /* clr r7 */ }; -t_stat tm_boot (int32 unitno) +t_stat tm_boot (int32 unitno, DEVICE *dptr) { int32 i; extern int32 saved_PC; @@ -643,6 +682,7 @@ if (sim_switches & SWMASK ('O')) { else { for (i = 0; i < BOOT2_LEN; i++) M[(BOOT_START >> 1) + i] = boot2_rom[i]; } M[BOOT_UNIT >> 1] = unitno; +M[BOOT_CSR >> 1] = (tm_dib.ba & DMASK) + 06; saved_PC = BOOT_ENTRY; return SCPE_OK; } diff --git a/PDP11/pdp11_tq.c b/PDP11/pdp11_tq.c new file mode 100644 index 00000000..aeb20ba3 --- /dev/null +++ b/PDP11/pdp11_tq.c @@ -0,0 +1,1984 @@ +/* pdp11_tq.c: TQK50 tape controller simulator + + Copyright (c) 2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + tq TQK50 tape controller + + 17-Oct-02 RMS Fixed bug in read reverse (found by Hans Pufal) +*/ + +#if defined (USE_INT64) +#include "vax_defs.h" +#define VM_VAX 1 +#define TQ_RDX 16 + +#else +#include "pdp11_defs.h" +#define VM_PDP11 1 +#define TQ_RDX 8 +extern int32 cpu_18b, cpu_ubm; +#endif + +#include "pdp11_uqssp.h" +#include "pdp11_mscp.h" + +#define UF_MSK (UF_SCH|UF_VSS|UF_CMR|UF_CMW) /* settable flags */ + +#define TQ_SH_MAX 24 /* max display wds */ +#define TQ_SH_PPL 8 /* wds per line */ +#define TQ_SH_DPL 4 /* desc per line */ +#define TQ_SH_RI 001 /* show rings */ +#define TQ_SH_FR 002 /* show free q */ +#define TQ_SH_RS 004 /* show resp q */ +#define TQ_SH_UN 010 /* show unit q's */ + +#define TQ_CLASS 1 /* TQK50 class */ +#define TQ_DHTMO 0 /* def host timeout */ +#define TQ_DCTMO 120 /* def ctrl timeout */ +#define TQ_NUMDR 4 /* # drives */ +#define TQ_MAXFR (1 << 16) /* max xfer */ + +#define UNIT_V_ONL (UNIT_V_UF + 0) /* online */ +#define UNIT_V_WLK (UNIT_V_UF + 1) /* hwre write lock */ +#define UNIT_V_ATP (UNIT_V_UF + 2) /* attn pending */ +#define UNIT_V_SXC (UNIT_V_UF + 3) /* serious exc */ +#define UNIT_V_POL (UNIT_V_UF + 4) /* position lost */ +#define UNIT_V_TMK (UNIT_V_UF + 5) /* tape mark seen */ +#define UNIT_ONL (1 << UNIT_V_ONL) +#define UNIT_WLK (1 << UNIT_V_WLK) +#define UNIT_ATP (1 << UNIT_V_ATP) +#define UNIT_SXC (1 << UNIT_V_SXC) +#define UNIT_POL (1 << UNIT_V_POL) +#define UNIT_TMK (1 << UNIT_V_TMK) +#define cpkt u3 /* current packet */ +#define pktq u4 /* packet queue */ +#define uf buf /* settable unit flags */ +#define objp wait /* object position */ +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */ +#define TQ_WPH(u) ((u->flags & UNIT_WPRT)? UF_WPH: 0) + +#define CST_S1 0 /* init stage 1 */ +#define CST_S1_WR 1 /* stage 1 wrap */ +#define CST_S2 2 /* init stage 2 */ +#define CST_S3 3 /* init stage 3 */ +#define CST_S3_PPA 4 /* stage 3 sa wait */ +#define CST_S3_PPB 5 /* stage 3 ip wait */ +#define CST_S4 6 /* stage 4 */ +#define CST_UP 7 /* online */ +#define CST_DEAD 8 /* fatal error */ + +#define tq_comm tq_rq.ba + +#define ERR 0 /* must be SCPE_OK! */ +#define OK 1 + +#define CMF_IMM 0x10000 /* immediate */ +#define CMF_SEQ 0x20000 /* sequential */ +#define CMF_WR 0x40000 /* write */ +#define CMF_RW 0x80000 /* resp to GCS */ + +/* Internal packet management */ + +#define TQ_NPKTS 32 /* # packets (pwr of 2) */ +#define TQ_M_NPKTS (TQ_NPKTS - 1) /* mask */ +#define TQ_PKT_SIZE_W 32 /* payload size (wds) */ +#define TQ_PKT_SIZE (TQ_PKT_SIZE_W * sizeof (int16)) + +struct tqpkt { + int16 link; /* link to next */ + uint16 d[TQ_PKT_SIZE_W]; }; /* data */ + +/* Packet payload extraction and insertion */ + +#define GETP(p,w,f) ((tq_pkt[p].d[w] >> w##_V_##f) & w##_M_##f) +#define GETP32(p,w) (((uint32) tq_pkt[p].d[w]) | \ + (((uint32) tq_pkt[p].d[(w)+1]) << 16)) +#define PUTP32(p,w,x) tq_pkt[p].d[w] = (x) & 0xFFFF; \ + tq_pkt[p].d[(w)+1] = ((x) >> 16) & 0xFFFF + +/* Controller and device types - TQK50 must be swre rev 5 or later */ + +#define TQ5_TYPE 0 /* TK50 */ +#define TQ5_UQPM 3 /* UQ port ID */ +#define TQ5_CMOD 9 /* ctrl ID */ +#define TQ5_UMOD 3 /* unit ID */ +#define TQ5_MED 0x6D68B032 /* media ID */ +#define TQ5_CREV ((1 << 8) | 5) /* ctrl revs */ +#define TQ5_FREV 0 /* formatter revs */ +#define TQ5_UREV 0 /* unit revs */ +#define TQ5_CAP (94 * (1 << 20)) /* capacity */ +#define TQ5_FMT (TF_CTP|TF_CTP_LO) /* menu */ + +#define TQ7_TYPE 1 /* TK70 */ +#define TQ7_UQPM 14 /* UQ port ID */ +#define TQ7_CMOD 14 /* ctrl ID */ +#define TQ7_UMOD 11 /* unit ID */ +#define TQ7_MED 0x6A68B046 /* media ID */ +#define TQ7_CREV ((1 << 8) | 5) /* ctrl revs */ +#define TQ7_FREV 0 /* formatter revs */ +#define TQ7_UREV 0 /* unit revs */ +#define TQ7_CAP (300 * (1 << 20)) /* capacity */ +#define TQ7_FMT (TF_CTP|TF_CTP_LO) /* menu */ + +#define TQ8_TYPE 2 /* TU81 */ +#define TQ8_UQPM 5 /* UQ port ID */ +#define TQ8_CMOD 5 /* ctrl ID */ +#define TQ8_UMOD 2 /* unit ID */ +#define TQ8_MED 0x6D695051 /* media ID */ +#define TQ8_CREV ((1 << 8) | 5) /* ctrl revs */ +#define TQ8_FREV 0 /* formatter revs */ +#define TQ8_UREV 0 /* unit revs */ +#define TQ8_CAP (180 * (1 << 20)) /* capacity */ +#define TQ8_FMT (TF_9TK|TF_9TK_GRP) /* menu */ + +#define TQ_DRV(d) \ + d##_UQPM, \ + d##_CMOD, d##_MED, d##_FMT, d##_CAP, \ + d##_UMOD, d##_CREV, d##_FREV, d##_UREV + +#define TEST_EOT(u) (uptr->pos > drv_tab[tq_typ].cap) + +struct drvtyp { + uint32 uqpm; /* UQ port model */ + uint32 cmod; /* ctrl model */ + uint32 med; /* MSCP media */ + uint32 fmt; /* flags */ + uint32 cap; /* capacity */ + uint32 umod; /* unit model */ + uint32 cver; + uint32 fver; + uint32 uver; +}; + +static struct drvtyp drv_tab[] = { + { TQ_DRV (TQ5) }, + { TQ_DRV (TQ7) }, + { TQ_DRV (TQ8) } +}; + +/* Data */ + +extern int32 int_req[IPL_HLVL]; +extern int32 tmr_poll, clk_tps; +extern int32 cpu_log; +extern UNIT cpu_unit; +extern FILE *sim_log; + +uint8 *tqxb = NULL; /* xfer buffer */ +uint32 tq_sa = 0; /* status, addr */ +uint32 tq_saw = 0; /* written data */ +uint32 tq_s1dat = 0; /* S1 data */ +uint32 tq_csta = 0; /* ctrl state */ +uint32 tq_perr = 0; /* last error */ +uint32 tq_cflgs = 0; /* ctrl flags */ +uint32 tq_prgi = 0; /* purge int */ +uint32 tq_pip = 0; /* poll in progress */ +struct uq_ring tq_cq = { 0 }; /* cmd ring */ +struct uq_ring tq_rq = { 0 }; /* rsp ring */ +struct tqpkt tq_pkt[TQ_NPKTS]; /* packet queue */ +int32 tq_freq = 0; /* free list */ +int32 tq_rspq = 0; /* resp list */ +uint32 tq_pbsy = 0; /* #busy pkts */ +uint32 tq_credits = 0; /* credits */ +uint32 tq_hat = 0; /* host timer */ +uint32 tq_htmo = TQ_DHTMO; /* host timeout */ +int32 tq_itime = 200; /* init time, except */ +int32 tq_itime4 = 10; /* stage 4 */ +int32 tq_qtime = 200; /* queue time */ +int32 tq_xtime = 500; /* transfer time */ +int32 tq_typ = 0; /* device type */ + +/* Command table - legal modifiers (low 16b) and flags (high 16b) */ + +static uint32 tq_cmf[64] = { + 0, /* 0 */ + CMF_IMM, /* abort */ + CMF_IMM, /* get cmd status */ + CMF_IMM|MD_NXU, /* get unit status */ + CMF_IMM, /* set ctrl char */ + 0, 0, 0, /* 5-7 */ + CMF_SEQ|MD_ACL|MD_CDL|MD_CSE|MD_EXA|MD_UNL, /* available */ + CMF_SEQ|MD_CDL|MD_CSE|MD_SWP|MD_EXA, /* online */ + CMF_SEQ|MD_CDL|MD_CSE|MD_SWP|MD_EXA, /* set unit char */ + CMF_IMM, /* define acc paths */ + 0, 0, 0, 0, /* 12-15 */ + CMF_SEQ|CMF_RW|MD_CDL|MD_CSE|MD_REV| /* access */ + MD_SCH|MD_SEC|MD_SER, + 0, /* 17 */ + CMF_SEQ|CMF_WR|MD_CDL|MD_CSE|MD_IMM, /* erase */ + CMF_SEQ|CMF_WR|MD_CDL|MD_CSE, /* flush */ + 0, 0, /* 20-21 */ + CMF_SEQ|CMF_WR|MD_CDL|MD_CSE|MD_IMM, /* erase gap */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 22-31 */ + CMF_SEQ|CMF_RW|MD_CDL|MD_CSE|MD_REV| /* compare */ + MD_SCH|MD_SEC|MD_SER, + CMF_SEQ|CMF_RW|MD_CDL|MD_CSE|MD_REV|MD_CMP| /* read */ + MD_SCH|MD_SEC|MD_SER, + CMF_SEQ|CMF_RW|CMF_WR|MD_CDL|MD_CSE|MD_IMM| /* write */ + MD_CMP|MD_ERW|MD_SEC|MD_SER, + 0, /* 35 */ + CMF_SEQ|MD_CDL|MD_CSE|MD_IMM, /* wr tape mark */ + CMF_SEQ|MD_CDL|MD_CSE|MD_IMM|MD_OBC| /* reposition */ + MD_REV|MD_RWD|MD_DLE| + MD_SCH|MD_SEC|MD_SER, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 38-47 */ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 }; + +/* Forward references */ + +DEVICE tq_dev; + +t_stat tq_rd (int32 *data, int32 PA, int32 access); +t_stat tq_wr (int32 data, int32 PA, int32 access); +t_stat tq_inta (void); +t_stat tq_svc (UNIT *uptr); +t_stat tq_tmrsvc (UNIT *uptr); +t_stat tq_quesvc (UNIT *uptr); +t_stat tq_reset (DEVICE *dptr); +t_stat tq_attach (UNIT *uptr, char *cptr); +t_stat tq_detach (UNIT *uptr); +t_stat tq_boot (int32 unitno, DEVICE *dptr); +t_stat tq_set_wlk (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat tq_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat tq_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat tq_show_unitq (FILE *st, UNIT *uptr, int32 val, void *desc); + +t_bool tq_step4 (void); +t_bool tq_mscp (int32 pkt, t_bool q); +t_bool tq_abo (int32 pkt); +t_bool tq_avl (int32 pkt); +t_bool tq_erase (int32 pkt); +t_bool tq_flu (int32 pkt); +t_bool tq_gcs (int32 pkt); +t_bool tq_gus (int32 pkt); +t_bool tq_onl (int32 pkt); +t_bool tq_pos (int32 pkt); +t_bool tq_rw (int32 pkt); +t_bool tq_scc (int32 pkt); +t_bool tq_suc (int32 pkt); +t_bool tq_wtm (int32 pkt); +t_bool tq_plf (uint32 err); +t_bool tq_dte (UNIT *uptr, uint32 err); +t_bool tq_hbe (UNIT *uptr, uint32 ba); +t_bool tq_una (UNIT *uptr); +uint32 tq_rdlntf (UNIT *uptr, t_mtrlnt *tbc); +uint32 tq_spacef (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec); +uint32 tq_skipff (UNIT *uptr, uint32 cnt, uint32 *skipped); +uint32 tq_rdbuff (UNIT *uptr, t_mtrlnt *tbc); +uint32 tq_rdlntr (UNIT *uptr, t_mtrlnt *tbc); +uint32 tq_spacer (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec); +uint32 tq_skipfr (UNIT *uptr, uint32 cnt, uint32 *skipped); +uint32 tq_rdbufr (UNIT *uptr, t_mtrlnt *tbc); +t_bool tq_deqf (int32 *pkt); +int32 tq_deqh (int32 *lh); +void tq_enqh (int32 *lh, int32 pkt); +void tq_enqt (int32 *lh, int32 pkt); +t_bool tq_getpkt (int32 *pkt); +t_bool tq_putpkt (int32 pkt, t_bool qt); +t_bool tq_getdesc (struct uq_ring *ring, uint32 *desc); +t_bool tq_putdesc (struct uq_ring *ring, uint32 desc); +int32 tq_mot_valid (UNIT *uptr, uint32 cmd); +t_stat tq_mot_err (UNIT *uptr, uint32 rsiz); +t_bool tq_mot_end (UNIT *uptr, uint32 flg, uint32 sts, uint32 rsiz); +void tq_putr (int32 pkt, uint32 cmd, uint32 flg, uint32 sts, uint32 lnt, uint32 typ); +void tq_putr_unit (int32 pkt, UNIT *uptr, uint32 lu, t_bool all); +void tq_setf_unit (int32 pkt, UNIT *uptr); +uint32 tq_efl (UNIT *uptr); +void tq_init_int (void); +void tq_ring_int (struct uq_ring *ring); +t_bool tq_fatal (uint32 err); +UNIT *tq_getucb (uint32 lu); + +/* TQ data structures + + tq_dev TQ device descriptor + tq_unit TQ unit list + tq_reg TQ register list + tq_mod TQ modifier list +*/ + +DIB tq_dib = { IOBA_TQ, IOLN_TQ, &tq_rd, &tq_wr, + 1, IVCL (TQ), 0, { &tq_inta } }; + +UNIT tq_unit[] = { + { UDATA (&tq_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0), 0 }, + { UDATA (&tq_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0), 0 }, + { UDATA (&tq_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0), 0 }, + { UDATA (&tq_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0), 0 }, + { UDATA (&tq_tmrsvc, UNIT_DIS, 0) }, + { UDATA (&tq_quesvc, UNIT_DIS, 0) } }; + +#define TQ_TIMER (TQ_NUMDR) +#define TQ_QUEUE (TQ_TIMER + 1) + +REG tq_reg[] = { + { GRDATA (SA, tq_sa, TQ_RDX, 16, 0) }, + { GRDATA (SAW, tq_saw, TQ_RDX, 16, 0) }, + { GRDATA (S1DAT, tq_s1dat, TQ_RDX, 16, 0) }, + { GRDATA (CQBA, tq_cq.ba, TQ_RDX, 22, 0) }, + { GRDATA (CQLNT, tq_cq.lnt, TQ_RDX, 8, 2), REG_NZ }, + { GRDATA (CQIDX, tq_cq.idx, TQ_RDX, 8, 2) }, + { GRDATA (TQBA, tq_rq.ba, TQ_RDX, 22, 0) }, + { GRDATA (TQLNT, tq_rq.lnt, TQ_RDX, 8, 2), REG_NZ }, + { GRDATA (TQIDX, tq_rq.idx, TQ_RDX, 8, 2) }, + { DRDATA (FREE, tq_freq, 5) }, + { DRDATA (RESP, tq_rspq, 5) }, + { DRDATA (PBSY, tq_pbsy, 5) }, + { GRDATA (CFLGS, tq_cflgs, TQ_RDX, 16, 0) }, + { GRDATA (CSTA, tq_csta, TQ_RDX, 4, 0) }, + { GRDATA (PERR, tq_perr, TQ_RDX, 9, 0) }, + { DRDATA (CRED, tq_credits, 5) }, + { DRDATA (HAT, tq_hat, 17) }, + { DRDATA (HTMO, tq_htmo, 17) }, + { URDATA (CPKT, tq_unit[0].cpkt, 10, 5, 0, TQ_NUMDR, 0) }, + { URDATA (PKTQ, tq_unit[0].pktq, 10, 5, 0, TQ_NUMDR, 0) }, + { URDATA (UFLG, tq_unit[0].uf, TQ_RDX, 16, 0, TQ_NUMDR, 0) }, + { URDATA (POS, tq_unit[0].pos, 10, 32, 0, TQ_NUMDR, 0) }, + { URDATA (OBJP, tq_unit[0].objp, 10, 32, 0, TQ_NUMDR, 0) }, + { FLDATA (PRGI, tq_prgi, 0), REG_HIDDEN }, + { FLDATA (PIP, tq_pip, 0), REG_HIDDEN }, + { FLDATA (INT, IREQ (TQ), INT_V_TQ) }, + { DRDATA (ITIME, tq_itime, 24), PV_LEFT + REG_NZ }, + { DRDATA (I4TIME, tq_itime4, 24), PV_LEFT + REG_NZ }, + { DRDATA (QTIME, tq_qtime, 24), PV_LEFT + REG_NZ }, + { DRDATA (XTIME, tq_xtime, 24), PV_LEFT + REG_NZ }, + { BRDATA (PKTS, tq_pkt, TQ_RDX, 16, TQ_NPKTS * (TQ_PKT_SIZE_W + 1)) }, + { FLDATA (DEVTYPE, tq_typ, 0), REG_HRO }, + { GRDATA (DEVADDR, tq_dib.ba, TQ_RDX, 32, 0), REG_HRO }, + { GRDATA (DEVVEC, tq_dib.vec, TQ_RDX, 16, 0), REG_HRO }, + { NULL } }; + +MTAB tq_mod[] = { + { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, + { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_RI, "RINGS", NULL, + NULL, &tq_show_ctrl, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_FR, "FREEQ", NULL, + NULL, &tq_show_ctrl, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_RS, "RESPQ", NULL, + NULL, &tq_show_ctrl, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_UN, "UNITQ", NULL, + NULL, &tq_show_ctrl, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, -1, "ALL", NULL, + NULL, &tq_show_ctrl, NULL }, + { MTAB_XTD | MTAB_VUN | MTAB_NMO, 0, "UNITQ", NULL, + NULL, &tq_show_unitq, NULL }, +#if defined (VM_PDP11) + { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, NULL }, +#else + { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL, + NULL, &show_addr, NULL }, +#endif + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, + NULL, &show_vec, NULL }, + { 0 } }; + +DEVICE tq_dev = { + "TQ", tq_unit, tq_reg, tq_mod, + TQ_NUMDR + 2, 10, 31, 1, TQ_RDX, 8, + NULL, NULL, &tq_reset, + &tq_boot, &tq_attach, &tq_detach, + &tq_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS }; + +/* I/O dispatch routine, I/O addresses 17772150 - 17772152 + + 17772150 IP read/write + 17772152 SA read/write +*/ + +t_stat tq_rd (int32 *data, int32 PA, int32 access) +{ +switch ((PA >> 1) & 01) { /* decode PA<1> */ +case 0: /* IP */ + *data = 0; /* reads zero */ + if (tq_csta == CST_S3_PPB) tq_step4 (); /* waiting for poll? */ + else if (tq_csta == CST_UP) { /* if up */ + tq_pip = 1; /* poll host */ + sim_activate (&tq_unit[TQ_QUEUE], tq_qtime); } + break; +case 1: /* SA */ + *data = tq_sa; + break; } +return SCPE_OK; +} + +t_stat tq_wr (int32 data, int32 PA, int32 access) +{ +switch ((PA >> 1) & 01) { /* decode PA<1> */ +case 0: /* IP */ + tq_reset (&tq_dev); /* init device */ + if (DBG_LOG (LOG_TQ)) fprintf (sim_log, ">>TQ: initialization started\n"); + break; +case 1: /* SA */ + tq_saw = data; + if (tq_csta < CST_S4) /* stages 1-3 */ + sim_activate (&tq_unit[TQ_QUEUE], tq_itime); + else if (tq_csta == CST_S4) /* stage 4 (fast) */ + sim_activate (&tq_unit[TQ_QUEUE], tq_itime4); + break; } +return SCPE_OK; +} + +/* Transition to step 4 - init communications region */ + +t_bool tq_step4 (void) +{ +int32 i, lnt; +t_addr base; +uint16 zero[SA_COMM_MAX >> 1]; + +tq_rq.ioff = SA_COMM_RI; /* set intr offset */ +tq_rq.ba = tq_comm; /* set rsp q base */ +tq_rq.lnt = SA_S1H_RQ (tq_s1dat) << 2; /* get resp q len */ +tq_cq.ioff = SA_COMM_CI; /* set intr offset */ +tq_cq.ba = tq_comm + tq_rq.lnt; /* set cmd q base */ +tq_cq.lnt = SA_S1H_CQ (tq_s1dat) << 2; /* get cmd q len */ +tq_cq.idx = tq_rq.idx = 0; /* clear q idx's */ +if (tq_prgi) base = tq_comm + SA_COMM_QQ; +else base = tq_comm + SA_COMM_CI; +lnt = tq_comm + tq_cq.lnt + tq_rq.lnt - base; /* comm lnt */ +if (lnt > SA_COMM_MAX) lnt = SA_COMM_MAX; /* paranoia */ +for (i = 0; i < (lnt >> 1); i++) zero[i] = 0; /* clr buffer */ +if (Map_WriteW (base, lnt, zero, MAP)) /* zero comm area */ + return tq_fatal (PE_QWE); /* error? */ +tq_sa = SA_S4 | (drv_tab[tq_typ].uqpm << SA_S4C_V_MOD) |/* send step 4 */ + ((drv_tab[tq_typ].cver & 0xFF) << SA_S4C_V_VER); +tq_csta = CST_S4; /* set step 4 */ +tq_init_int (); /* poke host */ +return OK; +} + +/* Queue service - invoked when any of the queues (host queue, unit + queues, response queue) require servicing. Also invoked during + initialization to provide some delay to the next step. + + Process at most one item off the host queue + If the host queue is empty, process at most one item off + each unit queue + Process at most one item off the response queue + + If all queues are idle, terminate thread +*/ + +t_stat tq_quesvc (UNIT *uptr) +{ +int32 i, cnid; +int32 pkt = 0; +UNIT *nuptr; + +if (tq_csta < CST_UP) { /* still init? */ + switch (tq_csta) { /* controller state? */ + case CST_S1: /* need S1 reply */ + if (tq_saw & SA_S1H_VL) { /* valid? */ + if (tq_saw & SA_S1H_WR) { /* wrap? */ + tq_sa = tq_saw; /* echo data */ + tq_csta = CST_S1_WR; } /* endless loop */ + else { + tq_s1dat = tq_saw; /* save data */ + tq_dib.vec = VEC_Q + ((tq_s1dat & SA_S1H_VEC) << 2); + tq_sa = SA_S2 | SA_S2C_PT | SA_S2C_EC (tq_s1dat); + tq_csta = CST_S2; /* now in step 2 */ + tq_init_int (); } /* intr if req */ + } /* end if valid */ + break; + case CST_S1_WR: /* wrap mode */ + tq_sa = tq_saw; /* echo data */ + break; + case CST_S2: /* need S2 reply */ + tq_comm = tq_saw & SA_S2H_CLO; /* get low addr */ + tq_prgi = tq_saw & SA_S2H_PI; /* get purge int */ + tq_sa = SA_S3 | SA_S3C_EC (tq_s1dat); + tq_csta = CST_S3; /* now in step 3 */ + tq_init_int (); /* intr if req */ + break; + case CST_S3: /* need S3 reply */ + tq_comm = ((tq_saw & SA_S3H_CHI) << 16) | tq_comm; + if (tq_saw & SA_S3H_PP) { /* purge/poll test? */ + tq_sa = 0; /* put 0 */ + tq_csta = CST_S3_PPA; } /* wait for 0 write */ + else tq_step4 (); /* send step 4 */ + break; + case CST_S3_PPA: /* need purge test */ + if (tq_saw) tq_fatal (PE_PPF); /* data not zero? */ + else tq_csta = CST_S3_PPB; /* wait for poll */ + break; + case CST_S4: /* need S4 reply */ + if (tq_saw & SA_S4H_GO) { /* go set? */ + if (DBG_LOG (LOG_TQ)) fprintf (sim_log, + ">>TQ: initialization complete\n"); + tq_csta = CST_UP; /* we're up */ + tq_sa = 0; /* clear SA */ + sim_activate (&tq_unit[TQ_TIMER], tmr_poll * clk_tps); + if ((tq_saw & SA_S4H_LF) && tq_perr) tq_plf (tq_perr); + tq_perr = 0; } + break; } /* end switch */ + return SCPE_OK; } /* end if */ + +if (tq_pip) { /* polling? */ + if (!tq_getpkt (&pkt)) return SCPE_OK; /* get host pkt */ + if (pkt) { /* got one? */ + if (DBG_LOG (LOG_TQ)) { + UNIT *up = tq_getucb (tq_pkt[pkt].d[CMD_UN]); + fprintf (sim_log, ">>TQ: cmd=%04X, mod=%04X, unit=%d, ", + tq_pkt[pkt].d[CMD_OPC], tq_pkt[pkt].d[CMD_MOD], tq_pkt[pkt].d[CMD_UN]); + fprintf (sim_log, "bc=%04X%04X, ma=%04X%04X", + tq_pkt[pkt].d[RW_BCH], tq_pkt[pkt].d[RW_BCL], + tq_pkt[pkt].d[RW_BAH], tq_pkt[pkt].d[RW_BAL]); + if (up) fprintf (sim_log, ", pos=%d, obj=%d\n", up->pos, up->objp); + else fprintf (sim_log, "\n"); } + if (GETP (pkt, UQ_HCTC, TYP) != UQ_TYP_SEQ) /* seq packet? */ + return tq_fatal (PE_PIE); /* no, term thread */ + cnid = GETP (pkt, UQ_HCTC, CID); /* get conn ID */ + if (cnid == UQ_CID_TMSCP) { /* TMSCP packet? */ + if (!tq_mscp (pkt, TRUE)) return SCPE_OK; } /* proc, q non-seq */ + else if (cnid == UQ_CID_DUP) { /* DUP packet? */ + tq_putr (pkt, OP_END, 0, ST_CMD | I_OPCD, RSP_LNT, UQ_TYP_SEQ); + if (!tq_putpkt (pkt, TRUE)) return SCPE_OK; } /* ill cmd */ + else return tq_fatal (PE_ICI); /* no, term thread */ + } /* end if pkt */ + else tq_pip = 0; /* discontinue poll */ + } /* end if pip */ +if (!tq_pip) { /* not polling? */ + for (i = 0; i < TQ_NUMDR; i++) { /* chk unit q's */ + nuptr = tq_dev.units + i; /* ptr to unit */ + if (nuptr->cpkt || (nuptr->pktq == 0)) continue; + pkt = tq_deqh (&nuptr->pktq); /* get top of q */ + if (!tq_mscp (pkt, FALSE)) return SCPE_OK; } /* process */ + } /* end if !pip */ +if (tq_rspq) { /* resp q? */ + pkt = tq_deqh (&tq_rspq); /* get top of q */ + if (!tq_putpkt (pkt, FALSE)) return SCPE_OK; /* send to hst */ + } /* end if resp q */ +if (pkt) sim_activate (&tq_unit[TQ_QUEUE], tq_qtime); /* more to do? */ +return SCPE_OK; /* done */ +} + +/* Clock service (roughly once per second) */ + +t_stat tq_tmrsvc (UNIT *uptr) +{ +int32 i; +UNIT *nuptr; + +sim_activate (uptr, tmr_poll * clk_tps); /* reactivate */ +for (i = 0; i < TQ_NUMDR; i++) { /* poll */ + nuptr = tq_dev.units + i; + if ((nuptr->flags & UNIT_ATP) && /* ATN pending? */ + (nuptr->flags & UNIT_ATT) && /* still online? */ + (tq_cflgs & CF_ATN)) { /* wanted? */ + if (!tq_una (nuptr)) return SCPE_OK; } + nuptr->flags = nuptr->flags & ~UNIT_ATP; } +if ((tq_hat > 0) && (--tq_hat == 0)) /* host timeout? */ + tq_fatal (PE_HAT); /* fatal err */ +return SCPE_OK; +} + +/* MSCP packet handling */ + +t_bool tq_mscp (int32 pkt, t_bool q) +{ +uint32 sts; +uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* command */ +uint32 flg = GETP (pkt, CMD_OPC, FLG); /* flags */ +uint32 mdf = tq_pkt[pkt].d[CMD_MOD]; /* modifier */ +uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ +UNIT *uptr; + +if ((cmd >= 64) || (tq_cmf[cmd] == 0)) { /* invalid cmd? */ + cmd = OP_END; /* set end op */ + sts = ST_CMD | I_OPCD; } /* ill op */ +else if (flg) { /* flags? */ + cmd = cmd | OP_END; /* set end flag */ + sts = ST_CMD | I_FLAG; } /* ill flags */ +else if (mdf & ~tq_cmf[cmd]) { /* invalid mod? */ + cmd = cmd | OP_END; /* set end flag */ + sts = ST_CMD | I_MODF; } /* ill mods */ +else { /* valid cmd */ + if (uptr = tq_getucb (lu)) { /* valid unit? */ + if (q && uptr->cpkt && (tq_cmf[cmd] & CMF_SEQ)) { + tq_enqt (&uptr->pktq, pkt); /* do later */ + return OK; } +/* if (tq_cmf[cmd] & MD_CDL) /* clr cch lost? */ +/* uptr->flags = uptr->flags & ~UNIT_CDL; */ + if (tq_cmf[cmd] & MD_CSE) /* clr ser exc? */ + uptr->flags = uptr->flags & ~UNIT_SXC; } + switch (cmd) { + case OP_ABO: /* abort */ + return tq_abo (pkt); + case OP_AVL: /* avail */ + return tq_avl (pkt); + case OP_GCS: /* get cmd status */ + return tq_gcs (pkt); + case OP_GUS: /* get unit status */ + return tq_gus (pkt); + case OP_ONL: /* online */ + return tq_onl (pkt); + case OP_SCC: /* set ctrl char */ + return tq_scc (pkt); + case OP_SUC: /* set unit char */ + return tq_suc (pkt); + case OP_ERS: /* erase */ + case OP_ERG: /* erase gap */ + return tq_erase (pkt); + case OP_FLU: /* flush */ + return tq_flu (pkt); + case OP_POS: /* position */ + return tq_pos (pkt); + case OP_WTM: /* write tape mark */ + return tq_wtm (pkt); + case OP_ACC: /* access */ + case OP_CMP: /* compare */ + case OP_RD: /* read */ + case OP_WR: /* write */ + return tq_rw (pkt); + case OP_DAP: + cmd = cmd | OP_END; /* set end flag */ + sts = ST_SUC; /* success */ + break; + default: + cmd = OP_END; /* set end op */ + sts = ST_CMD | I_OPCD; /* ill op */ + break; + } /* end switch */ + } /* end else */ +tq_putr (pkt, cmd, 0, sts, RSP_LNT, UQ_TYP_SEQ); +return tq_putpkt (pkt, TRUE); +} + +/* Abort a command - 1st parameter is ref # of cmd to abort */ + +t_bool tq_abo (int32 pkt) +{ +uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ +uint32 ref = GETP32 (pkt, ABO_REFL); /* cmd ref # */ +int32 tpkt, prv; +UNIT *uptr; + +tpkt = 0; /* set no mtch */ +if (uptr = tq_getucb (lu)) { /* get unit */ + if (uptr->cpkt && /* curr pkt? */ + (GETP32 (uptr->cpkt, CMD_REFL) == ref)) { /* match ref? */ + tpkt = uptr->cpkt; /* save match */ + uptr->cpkt = 0; /* gonzo */ + sim_cancel (uptr); /* cancel unit */ + sim_activate (&tq_unit[TQ_QUEUE], tq_qtime); } + else if (uptr->pktq && /* head of q? */ + (GETP32 (uptr->pktq, CMD_REFL) == ref)) { /* match ref? */ + tpkt = uptr->pktq; /* save match */ + uptr->pktq = tq_pkt[tpkt].link; } /* unlink */ + else if (prv = uptr->pktq) { /* srch pkt q */ + while (tpkt = tq_pkt[prv].link) { /* walk list */ + if (GETP32 (tpkt, RSP_REFL) == ref) { /* match ref? */ + tq_pkt[prv].link = tq_pkt[tpkt].link; /* unlink */ + break; } } } + if (tpkt) { /* found target? */ + uint32 tcmd = GETP (tpkt, CMD_OPC, OPC); /* get opcode */ + tq_putr (tpkt, tcmd | OP_END, 0, ST_ABO, RSP_LNT, UQ_TYP_SEQ); + if (!tq_putpkt (tpkt, TRUE)) return ERR; } + } /* end if unit */ +tq_putr (pkt, OP_ABO | OP_END, 0, ST_SUC, ABO_LNT, UQ_TYP_SEQ); +return tq_putpkt (pkt, TRUE); +} + +/* Unit available - set unit status to available + Deferred if q'd cmds, bypassed if ser exc */ + +t_bool tq_avl (int32 pkt) +{ +uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ +uint32 mdf = tq_pkt[pkt].d[CMD_MOD]; /* modifiers */ +uint32 sts; +UNIT *uptr; + +if (uptr = tq_getucb (lu)) { /* unit exist? */ + if (uptr->flags & UNIT_SXC) sts = ST_SXC; /* ser exc pending? */ + else { + uptr->flags = uptr->flags & ~(UNIT_ONL | UNIT_TMK | UNIT_POL); + uptr->uf = uptr->pos = uptr->objp = 0; /* clr flags, rewind */ + if (uptr->flags & UNIT_ATT) { /* attached? */ + sts = ST_SUC; /* success */ + if (mdf & MD_UNL) tq_detach (uptr); } /* unload? */ + else sts = ST_OFL | SB_OFL_NV; } } /* no, offline */ +else sts = ST_OFL; /* offline */ +tq_putr (pkt, OP_AVL | OP_END, tq_efl (uptr), sts, AVL_LNT, UQ_TYP_SEQ); +return tq_putpkt (pkt, TRUE); +} + +/* Get command status - only interested in active xfr cmd */ + +t_bool tq_gcs (int32 pkt) +{ +uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ +uint32 ref = GETP32 (pkt, GCS_REFL); /* ref # */ +int32 tpkt; +UNIT *uptr; + +if ((uptr = tq_getucb (lu)) && /* valid lu? */ + (tpkt = uptr->cpkt) && /* queued pkt? */ + (GETP32 (tpkt, CMD_REFL) == ref) && /* match ref? */ + (tq_cmf[GETP (tpkt, CMD_OPC, OPC)] & CMF_RW)) { /* rd/wr cmd? */ + tq_pkt[pkt].d[GCS_STSL] = tq_pkt[tpkt].d[RW_BCL]; + tq_pkt[pkt].d[GCS_STSH] = tq_pkt[tpkt].d[RW_BCH]; } +else tq_pkt[pkt].d[GCS_STSL] = tq_pkt[pkt].d[GCS_STSH] = 0; +tq_putr (pkt, OP_GCS | OP_END, 0, ST_SUC, GCS_LNT, UQ_TYP_SEQ); +return tq_putpkt (pkt, TRUE); +} + +/* Get unit status */ + +t_bool tq_gus (int32 pkt) +{ +uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ +uint32 sts; +UNIT *uptr; + +if (tq_pkt[pkt].d[CMD_MOD] & MD_NXU) { /* next unit? */ + if (lu >= TQ_NUMDR) { /* end of range? */ + lu = 0; /* reset to 0 */ + tq_pkt[pkt].d[RSP_UN] = lu; } } +if (uptr = tq_getucb (lu)) { /* unit exist? */ + if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + sts = ST_OFL | SB_OFL_NV; /* offl no vol */ + else if (uptr->flags & UNIT_ONL) sts = ST_SUC; /* online */ + else sts = ST_AVL; /* avail */ + tq_putr_unit (pkt, uptr, lu, FALSE); /* fill unit fields */ + tq_pkt[pkt].d[GUS_MENU] = drv_tab[tq_typ].fmt; /* format menu */ + tq_pkt[pkt].d[GUS_CAP] = 0; /* free capacity */ + tq_pkt[pkt].d[GUS_FVER] = drv_tab[tq_typ].fver; /* formatter version */ + tq_pkt[pkt].d[GUS_UVER] = drv_tab[tq_typ].uver; /* unit version */ + } +else sts = ST_OFL; /* offline */ +tq_putr (pkt, OP_GUS | OP_END, tq_efl (uptr), sts, GUS_LNT_T, UQ_TYP_SEQ); +return tq_putpkt (pkt, TRUE); +} + +/* Unit online - deferred if q'd commands */ + +t_bool tq_onl (int32 pkt) +{ +uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ +uint32 sts; +UNIT *uptr; + +if (uptr = tq_getucb (lu)) { /* unit exist? */ + if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + sts = ST_OFL | SB_OFL_NV; /* offl no vol */ + else if (uptr->flags & UNIT_ONL) /* already online? */ + sts = ST_SUC | SB_SUC_ON; + else { sts = ST_SUC; /* mark online */ + uptr->pos = uptr->objp = 0; /* rewind */ + uptr->flags = (uptr->flags | UNIT_ONL) & + ~(UNIT_TMK | UNIT_POL); /* onl, pos ok */ + tq_setf_unit (pkt, uptr); } /* hack flags */ + tq_putr_unit (pkt, uptr, lu, TRUE); } /* set fields */ +else sts = ST_OFL; /* offline */ +tq_putr (pkt, OP_ONL | OP_END, tq_efl (uptr), sts, ONL_LNT, UQ_TYP_SEQ); +return tq_putpkt (pkt, TRUE); +} + +/* Set controller characteristics */ + +t_bool tq_scc (int32 pkt) +{ +if (tq_pkt[pkt].d[SCC_MSV]) /* MSCP ver = 0? */ + tq_putr (pkt, 0, 0, ST_CMD | I_VRSN, SCC_LNT, UQ_TYP_SEQ); +else { tq_cflgs = (tq_cflgs & CF_RPL) | /* hack ctrl flgs */ + tq_pkt[pkt].d[SCC_CFL]; + if (tq_htmo = tq_pkt[pkt].d[SCC_TMO]) /* set timeout */ + tq_htmo = tq_htmo + 2; /* if nz, round up */ + tq_pkt[pkt].d[SCC_CFL] = tq_cflgs; /* return flags */ + tq_pkt[pkt].d[SCC_TMO] = TQ_DCTMO; /* ctrl timeout */ + tq_pkt[pkt].d[SCC_VER] = drv_tab[tq_typ].cver; /* ctrl version */ + tq_pkt[pkt].d[SCC_CIDA] = 0; /* ctrl ID */ + tq_pkt[pkt].d[SCC_CIDB] = 0; + tq_pkt[pkt].d[SCC_CIDC] = 0; + tq_pkt[pkt].d[SCC_CIDD] = (TQ_CLASS << SCC_CIDD_V_CLS) | + (drv_tab[tq_typ].cmod << SCC_CIDD_V_MOD); + PUTP32 (pkt, SCC_MBCL, TQ_MAXFR); /* max bc */ + tq_putr (pkt, OP_SCC | OP_END, 0, ST_SUC, SCC_LNT, UQ_TYP_SEQ); + } +return tq_putpkt (pkt, TRUE); +} + +/* Set unit characteristics - defer if q'd commands */ + +t_bool tq_suc (int32 pkt) +{ +uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ +uint32 sts; +UNIT *uptr; + +if (uptr = tq_getucb (lu)) { /* unit exist? */ + if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + sts = ST_OFL | SB_OFL_NV; /* offl no vol */ + else { sts = ST_SUC; /* avail or onl */ + tq_setf_unit (pkt, uptr); } /* hack flags */ + tq_putr_unit (pkt, uptr, lu, TRUE); } /* set fields */ +else sts = ST_OFL; /* offline */ +tq_putr (pkt, OP_SUC | OP_END, 0, sts, SUC_LNT, UQ_TYP_SEQ); +return tq_putpkt (pkt, TRUE); +} + +/* Flush - sequential nop - deferred if q'd cmds, bypassed if ser exc */ + +t_bool tq_flu (int32 pkt) +{ +uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ +uint32 sts; +UNIT *uptr; + +if (uptr = tq_getucb (lu)) { /* unit exist? */ + sts = tq_mot_valid (uptr, OP_FLU); } /* validate req */ +else sts = ST_OFL; /* offline */ +tq_putr (pkt, OP_FLU | OP_END, tq_efl (uptr), sts, FLU_LNT, UQ_TYP_SEQ); +return tq_putpkt (pkt, TRUE); +} + +/* Erase, erase gap - deferred if q'd cmds, bypassed if ser exc */ + +t_bool tq_erase (int32 pkt) +{ +uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ +uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ +uint32 sts; +UNIT *uptr; + +if (uptr = tq_getucb (lu)) { /* unit exist? */ + sts = tq_mot_valid (uptr, cmd); /* validity checks */ + if (sts == ST_SUC) { /* ok? */ + uptr->cpkt = pkt; /* op in progress */ + sim_activate (uptr, tq_xtime); /* activate */ + return OK; } } /* done */ +else sts = ST_OFL; /* offline */ +tq_putr (pkt, cmd | OP_END, tq_efl (uptr), sts, ERS_LNT, UQ_TYP_SEQ); +return tq_putpkt (pkt, TRUE); +} + +/* Write tape mark - deferred if q'd cmds, bypassed if ser exc */ + +t_bool tq_wtm (int32 pkt) +{ +uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ +uint32 sts, objp = 0; +UNIT *uptr; + +if (uptr = tq_getucb (lu)) { /* unit exist? */ + objp = uptr->objp; /* position op */ + sts = tq_mot_valid (uptr, OP_WTM); /* validity checks */ + if (sts == ST_SUC) { /* ok? */ + uptr->cpkt = pkt; /* op in progress */ + sim_activate (uptr, tq_xtime); /* activate */ + return OK; } } /* done */ +else sts = ST_OFL; /* offline */ +PUTP32 (pkt, WTM_POSL, objp); /* set obj pos */ +tq_putr (pkt, OP_WTM | OP_END, tq_efl (uptr), sts, WTM_LNT, UQ_TYP_SEQ); +return tq_putpkt (pkt, TRUE); +} + +/* Position - deferred if q'd cmds, bypassed if ser exc */ + +t_bool tq_pos (int32 pkt) +{ +uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ +uint32 sts, objp = 0; +UNIT *uptr; + +if (uptr = tq_getucb (lu)) { /* unit exist? */ + objp = uptr->objp; /* position op */ + sts = tq_mot_valid (uptr, OP_POS); /* validity checks */ + if (sts == ST_SUC) { /* ok? */ + uptr->cpkt = pkt; /* op in progress */ + sim_activate (uptr, tq_xtime); /* activate */ + return OK; } } /* done */ +else sts = ST_OFL; /* offline */ +PUTP32 (pkt, POS_RCL, 0); /* clear #skipped */ +PUTP32 (pkt, POS_TMCL, 0); +PUTP32 (pkt, POS_POSL, objp); /* set obj pos */ +tq_putr (pkt, OP_POS | OP_END, tq_efl (uptr), sts, POS_LNT, UQ_TYP_SEQ); +return tq_putpkt (pkt, TRUE); +} + +/* Data transfer commands - deferred if q'd commands, bypassed if ser exc */ + +t_bool tq_rw (int32 pkt) +{ +uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ +uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ +uint32 bc = GETP32 (pkt, RW_BCL); /* byte count */ +uint32 sts, objp = 0; +UNIT *uptr; + +if (uptr = tq_getucb (lu)) { /* unit exist? */ + objp = uptr->objp; /* position op */ + sts = tq_mot_valid (uptr, cmd); /* validity checks */ + if (sts == ST_SUC) { /* ok? */ + if ((bc == 0) || (bc > TQ_MAXFR)) { /* invalid? */ + uptr->flags = uptr->flags | UNIT_SXC; /* set ser exc */ + sts = ST_CMD | I_BCNT; } + else { + uptr->cpkt = pkt; /* op in progress */ + sim_activate (uptr, tq_xtime); /* activate */ + return OK; } } } /* done */ +else sts = ST_OFL; /* offline */ +PUTP32 (pkt, RW_BCL, 0); /* no bytes processed */ +PUTP32 (pkt, RW_POSL, objp); /* set obj pos */ +PUTP32 (pkt, RW_RSZL, 0); /* clr rec size */ +tq_putr (pkt, cmd | OP_END, tq_efl (uptr), sts, RW_LNT, UQ_TYP_SEQ); +return tq_putpkt (pkt, TRUE); +} + +/* Validity checks */ + +int32 tq_mot_valid (UNIT *uptr, uint32 cmd) +{ +if (uptr->flags & UNIT_SXC) return ST_SXC; /* ser exc pend? */ +if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ + return (ST_OFL | SB_OFL_NV); /* offl no vol */ +if ((uptr->flags & UNIT_ONL) == 0) /* not online? */ + return ST_AVL; /* only avail */ +if (tq_cmf[cmd] & CMF_WR) { /* write op? */ + if (uptr->uf & UF_WPS) { /* swre wlk? */ + uptr->flags = uptr->flags | UNIT_SXC; /* set ser exc */ + return (ST_WPR | SB_WPR_SW); } + if (TQ_WPH (uptr)) { /* hwre wlk? */ + uptr->flags = uptr->flags | UNIT_SXC; /* set ser exc */ + return (ST_WPR | SB_WPR_HW); } } +return ST_SUC; /* success! */ +} + +/* Unit service for motion commands */ + +t_stat tq_svc (UNIT *uptr) +{ +uint32 t, sts, sktmk, skrec; +t_mtrlnt i, ebc, tbc, wbc; +int32 pkt = uptr->cpkt; /* get packet */ +uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* get cmd */ +uint32 mdf = tq_pkt[pkt].d[CMD_MOD]; /* modifier */ +uint32 ba = GETP32 (pkt, RW_BAL); /* buf addr */ +t_mtrlnt bc = GETP32 (pkt, RW_BCL); /* byte count */ +uint32 nrec = GETP32 (pkt, POS_RCL); /* #rec to skip */ +uint32 ntmk = GETP32 (pkt, POS_TMCL); /* #tmk to skp */ +static t_mtrlnt bceof = MTR_TMK; +static t_mtrlnt bceom = MTR_EOM; + +if (pkt == 0) return SCPE_IERR; /* what??? */ +if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ + tq_mot_end (uptr, 0, ST_OFL | SB_OFL_NV, 0); /* offl no vol */ + return SCPE_OK; } + +if (tq_cmf[cmd] & CMF_WR) { /* write op? */ + if (TQ_WPH (uptr)) { /* hwre write prot? */ + uptr->flags = uptr->flags | UNIT_SXC; /* set ser exc */ + tq_mot_end (uptr, 0, ST_WPR | SB_WPR_HW, 0); + return SCPE_OK; } + if (uptr->uf & UF_WPS) { /* swre write prot? */ + uptr->flags = uptr->flags | UNIT_SXC; /* set ser exc */ + tq_mot_end (uptr, 0, ST_WPR | SB_WPR_SW, 0); + return SCPE_OK; } } +sts = ST_SUC; /* assume success */ +tbc = 0; /* assume zero rec */ +switch (cmd) { /* case on command */ + +case OP_RD:case OP_ACC:case OP_CMP: /* read-like op */ + if (mdf & MD_REV) sts = tq_rdbufr (uptr, &tbc); /* read record */ + else sts = tq_rdbuff (uptr, &tbc); + if (sts == ST_DRV) { /* read error? */ + PUTP32 (pkt, RW_BCL, 0); /* no bytes processed */ + return tq_mot_err (uptr, tbc); } /* log, done */ + if ((sts != ST_SUC) || (cmd == OP_ACC)) { /* error or access? */ + PUTP32 (pkt, RW_BCL, 0); /* no bytes processed */ + break; } + if (tbc > bc) { /* tape rec > buf? */ + uptr->flags = uptr->flags | UNIT_SXC; /* serious exc */ + sts = ST_RDT; /* data truncated */ + wbc = bc; } /* set working bc */ + else wbc = tbc; + if (cmd == OP_RD) { /* read? */ + if (t = Map_WriteB (ba, wbc, tqxb, MAP)) { /* store, nxm? */ + PUTP32 (pkt, RW_BCL, wbc - t); /* adj bc */ + if (tq_hbe (uptr, ba + wbc - t)) /* post err log */ + tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, tbc); + return SCPE_OK; } /* end if nxm */ + } /* end if read */ + else { /* compare */ + uint8 mby, dby; + uint32 mba; + for (i = 0; i < wbc; i++) { /* loop */ + if (mdf & MD_REV) { /* reverse? */ + mba = ba + bc - 1 - i; /* mem addr */ + dby = tqxb[tbc - 1 - i]; } /* byte */ + else { + mba = ba + i; + dby = tqxb[i]; } + if (Map_ReadB (mba, 1, &mby, MAP)) { /* fetch, nxm? */ + PUTP32 (pkt, RW_BCL, i); /* adj bc */ + if (tq_hbe (uptr, mba)) /* post err log */ + tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, tbc); + return SCPE_OK; } + if (mby != dby) { /* cmp err? */ + uptr->flags = uptr->flags | UNIT_SXC; /* ser exc */ + PUTP32 (pkt, RW_BCL, i); /* adj bc */ + tq_mot_end (uptr, 0, ST_CMP, tbc); + return SCPE_OK; } /* exit */ + } /* end for */ + } /* end if compare */ + PUTP32 (pkt, RW_BCL, wbc); /* bytes read/cmp'd */ + break; + +case OP_WR: /* write */ + if (t = Map_ReadB (ba, bc, tqxb, MAP)) { /* fetch buf, nxm? */ + PUTP32 (pkt, RW_BCL, 0); /* no bytes xfer'd */ + if (tq_hbe (uptr, ba + bc - t)) /* post err log */ + tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, bc); + return SCPE_OK; } /* end else wr */ + ebc = (bc + 1) & ~1; /* force even */ + fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set pos */ + fxwrite (&bc, sizeof (t_mtrlnt), 1, uptr->fileref); + fxwrite (tqxb, sizeof (uint8), ebc, uptr->fileref); + fxwrite (&bc, sizeof (t_mtrlnt), 1, uptr->fileref); + if (ferror (uptr->fileref)) /* error? */ + return tq_mot_err (uptr, bc); /* log, end */ + uptr->pos = uptr->pos + ebc + (2 * sizeof (t_mtrlnt)); + uptr->objp = uptr->objp + 1; /* upd obj pos */ + if (TEST_EOT (uptr)) /* EOT on write? */ + uptr->flags = uptr->flags | UNIT_SXC; + uptr->flags = uptr->flags & ~UNIT_TMK; /* disable LEOT */ + tbc = bc; /* RW_BC is ok */ + break; + +case OP_WTM: /* write tape mark */ + fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set pos */ + fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr->fileref); + if (ferror (uptr->fileref)) /* error? */ + return tq_mot_err (uptr, 0); /* log, end */ + uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* update pos */ + uptr->objp = uptr->objp + 1; /* incr obj cnt */ +case OP_ERG: /* erase gap */ + if (TEST_EOT (uptr)) /* EOT on write? */ + uptr->flags = uptr->flags | UNIT_SXC; + uptr->flags = uptr->flags & ~UNIT_TMK; /* disable LEOT */ + break; + +case OP_ERS: /* erase */ + fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set pos */ + fxwrite (&bceom, sizeof (t_mtrlnt), 1, uptr->fileref); + if (ferror (uptr->fileref)) /* error? */ + return tq_mot_err (uptr, 0); + uptr->pos = uptr->objp = 0; /* rewind */ + uptr->flags = uptr->flags & ~(UNIT_TMK | UNIT_POL); + break; + +case OP_POS: /* position */ + sktmk = skrec = 0; /* clr skipped */ + if (mdf & MD_RWD) { /* rewind? */ + uptr->pos = uptr->objp = 0; /* clr flags */ + uptr->flags = uptr->flags & ~(UNIT_TMK | UNIT_POL); } + if (mdf & MD_OBC) { /* skip obj? */ + if (mdf & MD_REV) /* reverse? */ + sts = tq_spacer (uptr, nrec, &skrec, FALSE); + else sts = tq_spacef (uptr, nrec, &skrec, FALSE); + } + else { /* skip tmk, rec */ + if (mdf & MD_REV) sts = tq_skipfr (uptr, ntmk, &sktmk); + else sts = tq_skipff (uptr, ntmk, &sktmk); + if (sts == ST_SUC) { /* tmk succeed? */ + if (mdf & MD_REV) /* reverse? */ + sts = tq_spacer (uptr, nrec, &skrec, TRUE); + else sts = tq_spacef (uptr, nrec, &skrec, TRUE); + if (sts == ST_TMK) sktmk = sktmk + 1; } + } + PUTP32 (pkt, POS_RCL, skrec); /* #rec skipped */ + PUTP32 (pkt, POS_TMCL, sktmk); /* #tmk skipped */ + break; + +default: + return SCPE_IERR; } +tq_mot_end (uptr, 0, sts, tbc); /* done */ +return SCPE_OK; +} + +/* Motion command drive error */ + +t_stat tq_mot_err (UNIT *uptr, uint32 rsiz) +{ +uptr->flags = (uptr->flags | UNIT_SXC) & ~UNIT_TMK; /* serious exception */ +if (tq_dte (uptr, ST_DRV)) /* post err log */ + tq_mot_end (uptr, EF_LOG, ST_DRV, rsiz); /* if ok, report err */ +perror ("TQ I/O error"); +clearerr (uptr->fileref); +return SCPE_IOERR; +} + +/* Motion command complete */ + +t_bool tq_mot_end (UNIT *uptr, uint32 flg, uint32 sts, uint32 rsiz) +{ +int32 pkt = uptr->cpkt; /* packet */ +uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* get cmd */ +uint32 lnt = RW_LNT; /* assume rw */ + +if (cmd == OP_ERG) lnt = ERG_LNT; /* set pkt lnt */ +else if (cmd == OP_ERS) lnt = ERS_LNT; +else if (cmd == OP_WTM) lnt = WTM_LNT; +else if (cmd == OP_POS) lnt = POS_LNT; + +uptr->cpkt = 0; /* done */ +if (lnt > ERG_LNT) { /* xfer cmd? */ + PUTP32 (pkt, RW_POSL, uptr->objp); } /* position */ +if (lnt > POS_LNT) { /* read or write? */ + PUTP32 (pkt, RW_RSZL, rsiz); } /* record size */ +tq_putr (pkt, cmd | OP_END, flg | tq_efl (uptr), sts, lnt, UQ_TYP_SEQ); +if (!tq_putpkt (pkt, TRUE)) return ERR; /* send pkt */ +if (uptr->pktq) /* more to do? */ + sim_activate (&tq_unit[TQ_QUEUE], tq_qtime); /* activate thread */ +return OK; +} + +/* Tape motion routines */ + +uint32 tq_rdlntf (UNIT *uptr, t_mtrlnt *tbc) +{ +fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set pos */ +fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); /* read rec lnt */ +if (ferror (uptr->fileref)) { /* error? */ + uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL; /* ser exc, pos lost */ + return ST_DRV; } +if (feof (uptr->fileref) || (*tbc == MTR_EOM)) { /* end of medium? */ + uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL; /* ser exc, pos lost */ + return ST_DAT; } +return 0; +} + +uint32 tq_spacef (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec) +{ +uint32 st; +t_mtrlnt tbc; + +*skipped = 0; +while (*skipped < cnt) { /* loop */ + if (st = tq_rdlntf (uptr, &tbc)) return st; /* read rec lnt */ + uptr->objp = uptr->objp + 1; /* upd obj cnt */ + if (tbc == MTR_TMK) { /* tape mark? */ + int32 pkt = uptr->cpkt; /* get pkt */ + if ((tq_pkt[pkt].d[CMD_MOD] & MD_DLE) && /* LEOT? */ + (uptr->flags & UNIT_TMK)) { + uptr->flags = uptr->flags | UNIT_SXC; /* serious exc */ + return ST_LED; } /* dont upd pos */ + uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* update pos */ + uptr->flags = uptr->flags | UNIT_TMK; /* set TM seen */ + if (qrec) return ST_TMK; } /* rec spc? stop */ + else { + uptr->pos = uptr->pos + ((MTRL (tbc) + 1) & ~1) + + (2 * sizeof (t_mtrlnt)); /* update pos */ + uptr->flags = uptr->flags & ~UNIT_TMK; } /* clr TM seen */ + *skipped = *skipped + 1; } /* # rec skipped */ +return 0; +} + +uint32 tq_skipff (UNIT *uptr, uint32 cnt, uint32 *skipped) +{ +uint32 st, skrec; + +*skipped = 0; +while (*skipped < cnt) { /* loop */ + st = tq_spacef (uptr, 0xFFFFFFFF, &skrec, TRUE); /* rec spc fwd */ + if (st == ST_TMK) *skipped = *skipped + 1; /* count files */ + else if (st != 0) return st; } +return 0; +} + +uint32 tq_rdlntr (UNIT *uptr, t_mtrlnt *tbc) +{ +uptr->flags = uptr->flags & ~UNIT_TMK; /* rev clrs tmk */ +if (uptr->pos < sizeof (t_mtrlnt)) { /* at BOT? */ + uptr->flags = (uptr->flags | UNIT_SXC) & ~UNIT_POL; + return ST_BOT; } +fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt), SEEK_SET); +fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); /* read rec lnt */ +if (ferror (uptr->fileref)) { /* error? */ + uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL; /* ser exc, pos lost */ + return ST_DRV; } +if (feof (uptr->fileref)) { /* end of file? */ + uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL; /* ser exc, pos lost */ + return ST_DAT; } +if (*tbc == MTR_EOM) { /* end of medium? */ + uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL; /* ser exc, pos lost */ + uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over eom */ + return ST_DAT; } +return 0; +} + +uint32 tq_spacer (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec) +{ +uint32 st; +t_mtrlnt tbc; + +*skipped = 0; +while (*skipped < cnt) { /* loop */ + if (st = tq_rdlntr (uptr, &tbc)) return st; /* read rec lnt */ + uptr->objp = uptr->objp - 1; /* upd obj cnt */ + if (tbc == MTR_TMK) { /* tape mark? */ + uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* update pos */ + if (qrec) return ST_TMK; } /* recd spc? stop */ + else uptr->pos = uptr->pos - ((MTRL (tbc) + 1) & ~1) - + (2 * sizeof (t_mtrlnt)); /* update pos */ + *skipped = *skipped + 1; } /* # rec skipped */ +return 0; +} + +uint32 tq_skipfr (UNIT *uptr, uint32 cnt, uint32 *skipped) +{ +uint32 st, skrec; + +*skipped = 0; +while (*skipped < cnt) { /* loopo */ + st = tq_spacer (uptr, 0xFFFFFFFF, &skrec, TRUE); /* rec spc rev */ + if (st == ST_TMK) *skipped = *skipped + 1; /* tape mark? */ + else if (st != 0) return st; } /* error? */ +return 0; +} + +/* Read buffer - can return ST_TMK, ST_FMT, or ST_DRV */ + +uint32 tq_rdbuff (UNIT *uptr, t_mtrlnt *tbc) +{ +t_mtrlnt i; +uint32 st; + +if (st = tq_rdlntf (uptr, tbc)) return st; /* read rec lnt */ +if (*tbc == MTR_TMK) { /* tape mark? */ + uptr->flags = uptr->flags | UNIT_SXC | UNIT_TMK; /* serious exc */ + uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* update pos */ + uptr->objp = uptr->objp + 1; /* update obj cnt */ + return ST_TMK; } +uptr->flags = uptr->flags & ~UNIT_TMK; /* clr tape mark */ +*tbc = MTRL (*tbc); /* ignore err flag */ +if (*tbc > MT_MAXFR) { /* rec out of range? */ + uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL; + return ST_FMT; } +i = fxread (tqxb, sizeof (uint8), *tbc, uptr->fileref); /* read record */ +if (ferror (uptr->fileref)) { /* error? */ + uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL; + return ST_DRV; } +for ( ; i < *tbc; i++) tqxb[i] = 0; /* fill with 0's */ +uptr->pos = uptr->pos + ((*tbc + 1) & ~1) + (2 * sizeof (t_mtrlnt)); +uptr->objp = uptr->objp + 1; /* upd obj cnt */ +return 0; +} + +uint32 tq_rdbufr (UNIT *uptr, t_mtrlnt *tbc) +{ +t_mtrlnt i; +uint32 st; + +if (st = tq_rdlntr (uptr, tbc)) return st; /* read rec lnt */ +if (*tbc == MTR_TMK) { /* tape mark? */ + uptr->flags = uptr->flags | UNIT_SXC; /* serious exc */ + uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* update pos */ + uptr->objp = uptr->objp - 1; /* update obj cnt */ + return ST_TMK; } +*tbc = MTRL (*tbc); /* ignore err flag */ +if (*tbc > MT_MAXFR) { /* rec out of range? */ + uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL; + return ST_FMT; } +fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt) - *tbc, SEEK_SET); +i = fxread (tqxb, sizeof (uint8), *tbc, uptr->fileref); /* read record */ +if (ferror (uptr->fileref)) { /* error? */ + uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL; + return ST_DRV; } +for ( ; i < *tbc; i++) tqxb[i] = 0; /* fill with 0's */ +uptr->pos = uptr->pos - ((*tbc + 1) & ~1) - (2 * sizeof (t_mtrlnt)); +uptr->objp = uptr->objp - 1; /* upd obj cnt */ +return 0; +} + +/* Data transfer error log packet */ + +t_bool tq_dte (UNIT *uptr, uint32 err) +{ +int32 pkt, tpkt; +uint32 lu; + +if ((tq_cflgs & CF_THS) == 0) return OK; /* logging? */ +if (!tq_deqf (&pkt)) return ERR; /* get log pkt */ +tpkt = uptr->cpkt; /* rw pkt */ +lu = tq_pkt[tpkt].d[CMD_UN]; /* unit # */ + +tq_pkt[pkt].d[ELP_REFL] = tq_pkt[tpkt].d[CMD_REFL]; /* copy cmd ref */ +tq_pkt[pkt].d[ELP_REFH] = tq_pkt[tpkt].d[CMD_REFH]; /* copy cmd ref */ +tq_pkt[pkt].d[ELP_UN] = lu; /* copy unit */ +tq_pkt[pkt].d[ELP_SEQ] = 0; /* clr seq # */ +tq_pkt[pkt].d[DTE_CIDA] = 0; /* ctrl ID */ +tq_pkt[pkt].d[DTE_CIDB] = 0; +tq_pkt[pkt].d[DTE_CIDC] = 0; +tq_pkt[pkt].d[DTE_CIDD] = (TQ_CLASS << DTE_CIDD_V_CLS) | + (drv_tab[tq_typ].cmod << DTE_CIDD_V_MOD); +tq_pkt[pkt].d[DTE_VER] = drv_tab[tq_typ].cver; /* ctrl ver */ +tq_pkt[pkt].d[DTE_MLUN] = lu; /* MLUN */ +tq_pkt[pkt].d[DTE_UIDA] = lu; /* unit ID */ +tq_pkt[pkt].d[DTE_UIDB] = 0; +tq_pkt[pkt].d[DTE_UIDC] = 0; +tq_pkt[pkt].d[DTE_UIDD] = (UID_TAPE << DTE_UIDD_V_CLS) | + (drv_tab[tq_typ].umod << DTE_UIDD_V_MOD); +tq_pkt[pkt].d[DTE_UVER] = drv_tab[tq_typ].uver; /* unit ver */ +PUTP32 (pkt, DTE_POSL, uptr->objp); /* position */ +tq_pkt[pkt].d[DTE_FVER] = drv_tab[tq_typ].fver; /* fmtr ver */ +tq_putr (pkt, FM_TAP, LF_SNR, err, DTE_LNT, UQ_TYP_DAT); +return tq_putpkt (pkt, TRUE); +} + +/* Host bus error log packet */ + +t_bool tq_hbe (UNIT *uptr, uint32 ba) +{ +int32 pkt, tpkt; + +if ((tq_cflgs & CF_THS) == 0) return OK; /* logging? */ +if (!tq_deqf (&pkt)) return ERR; /* get log pkt */ +tpkt = uptr->cpkt; /* rw pkt */ +tq_pkt[pkt].d[ELP_REFL] = tq_pkt[tpkt].d[CMD_REFL]; /* copy cmd ref */ +tq_pkt[pkt].d[ELP_REFH] = tq_pkt[tpkt].d[CMD_REFH]; /* copy cmd ref */ +tq_pkt[pkt].d[ELP_UN] = tq_pkt[tpkt].d[CMD_UN]; /* copy unit */ +tq_pkt[pkt].d[ELP_SEQ] = 0; /* clr seq # */ +tq_pkt[pkt].d[HBE_CIDA] = 0; /* ctrl ID */ +tq_pkt[pkt].d[HBE_CIDB] = 0; +tq_pkt[pkt].d[HBE_CIDC] = 0; +tq_pkt[pkt].d[DTE_CIDD] = (TQ_CLASS << DTE_CIDD_V_CLS) | + (drv_tab[tq_typ].cmod << DTE_CIDD_V_MOD); +tq_pkt[pkt].d[HBE_VER] = drv_tab[tq_typ].cver; /* ctrl ver */ +tq_pkt[pkt].d[HBE_RSV] = 0; +PUTP32 (pkt, HBE_BADL, ba); /* bad addr */ +tq_putr (pkt, FM_BAD, LF_SNR, ST_HST | SB_HST_NXM, HBE_LNT, UQ_TYP_DAT); +return tq_putpkt (pkt, TRUE); +} + +/* Port last failure error log packet */ + +t_bool tq_plf (uint32 err) +{ +int32 pkt; + +if (!tq_deqf (&pkt)) return ERR; /* get log pkt */ +tq_pkt[pkt].d[ELP_REFL] = tq_pkt[pkt].d[ELP_REFH] = 0; /* ref = 0 */ +tq_pkt[pkt].d[ELP_UN] = tq_pkt[pkt].d[ELP_SEQ] = 0; /* no unit, seq */ +tq_pkt[pkt].d[PLF_CIDA] = 0; /* cntl ID */ +tq_pkt[pkt].d[PLF_CIDB] = 0; +tq_pkt[pkt].d[PLF_CIDC] = 0; +tq_pkt[pkt].d[PLF_CIDD] = (TQ_CLASS << PLF_CIDD_V_CLS) | + (drv_tab[tq_typ].cmod << PLF_CIDD_V_MOD); +tq_pkt[pkt].d[PLF_VER] = drv_tab[tq_typ].cver; +tq_pkt[pkt].d[PLF_ERR] = err; +tq_putr (pkt, FM_CNT, LF_SNR, ST_CNT, PLF_LNT, UQ_TYP_DAT); +tq_pkt[pkt].d[UQ_HCTC] |= (UQ_CID_DIAG << UQ_HCTC_V_CID); +return tq_putpkt (pkt, TRUE); +} + +/* Unit now available attention packet */ + +int32 tq_una (UNIT *uptr) +{ +int32 pkt; +uint32 lu; + +if (!tq_deqf (&pkt)) return ERR; /* get log pkt */ +lu = uptr - tq_dev.units; /* get unit */ +tq_pkt[pkt].d[RSP_REFL] = tq_pkt[pkt].d[RSP_REFH] = 0; /* ref = 0 */ +tq_pkt[pkt].d[RSP_UN] = lu; +tq_pkt[pkt].d[RSP_RSV] = 0; +tq_putr_unit (pkt, uptr, lu, FALSE); /* fill unit fields */ +tq_putr (pkt, OP_AVA, 0, 0, UNA_LNT, UQ_TYP_SEQ); /* fill std fields */ +return tq_putpkt (pkt, TRUE); +} + +/* List handling + + tq_deqf - dequeue head of free list (fatal err if none) + tq_deqh - dequeue head of list + tq_enqh - enqueue at head of list + tq_enqt - enqueue at tail of list +*/ + +t_bool tq_deqf (int32 *pkt) +{ +if (tq_freq == 0) return tq_fatal (PE_NSR); /* no free pkts?? */ +tq_pbsy = tq_pbsy + 1; /* cnt busy pkts */ +*pkt = tq_freq; /* head of list */ +tq_freq = tq_pkt[tq_freq].link; /* next */ +return OK; +} + +int32 tq_deqh (int32 *lh) +{ +int32 ptr = *lh; /* head of list */ + +if (ptr) *lh = tq_pkt[ptr].link; /* next */ +return ptr; +} + +void tq_enqh (int32 *lh, int32 pkt) +{ +if (pkt == 0) return; /* any pkt? */ +tq_pkt[pkt].link = *lh; /* link is old lh */ +*lh = pkt; /* pkt is new lh */ +return; +} + +void tq_enqt (int32 *lh, int32 pkt) +{ +if (pkt == 0) return; /* any pkt? */ +tq_pkt[pkt].link = 0; /* it will be tail */ +if (*lh == 0) *lh = pkt; /* if empty, enqh */ +else { uint32 ptr = *lh; /* chase to end */ + while (tq_pkt[ptr].link) ptr = tq_pkt[ptr].link; + tq_pkt[ptr].link = pkt; } /* enq at tail */ +return; +} + +/* Packet and descriptor handling */ + +/* Get packet from command ring */ + +t_bool tq_getpkt (int32 *pkt) +{ +uint32 desc; +t_addr addr; + +if (!tq_getdesc (&tq_cq, &desc)) return ERR; /* get cmd desc */ +if ((desc & UQ_DESC_OWN) == 0) { /* none */ + *pkt = 0; /* pkt = 0 */ + return OK; } /* no error */ +if (!tq_deqf (pkt)) return ERR; /* get cmd pkt */ +tq_hat = 0; /* dsbl hst timer */ +addr = desc & UQ_ADDR; /* get Q22 addr */ +if (Map_ReadW (addr + UQ_HDR_OFF, TQ_PKT_SIZE, tq_pkt[*pkt].d, MAP)) + return tq_fatal (PE_PRE); /* read pkt */ +return tq_putdesc (&tq_cq, desc); /* release desc */ +} + +/* Put packet to response ring - note the clever hack about credits. + The controller sends all its credits to the host. Thereafter, it + supplies one credit for every response packet sent over. Simple! +*/ + +t_bool tq_putpkt (int32 pkt, t_bool qt) +{ +uint32 desc, lnt, cr; +t_addr addr; + +if (pkt == 0) return OK; /* any packet? */ +if (DBG_LOG (LOG_TQ)) { + UNIT *up = tq_getucb (tq_pkt[pkt].d[CMD_UN]); + fprintf (sim_log, ">>TQ: rsp=%04X, sts=%04X", + tq_pkt[pkt].d[RSP_OPF], tq_pkt[pkt].d[RSP_STS]); + if (up) fprintf (sim_log, ", pos=%d, obj=%d\n", up->pos, up->objp); + else fprintf (sim_log, "\n"); } +if (!tq_getdesc (&tq_rq, &desc)) return ERR; /* get rsp desc */ +if ((desc & UQ_DESC_OWN) == 0) { /* not valid? */ + if (qt) tq_enqt (&tq_rspq, pkt); /* normal? q tail */ + else tq_enqh (&tq_rspq, pkt); /* resp q call */ + sim_activate (&tq_unit[TQ_QUEUE], tq_qtime); /* activate q thrd */ + return OK; } +addr = desc & UQ_ADDR; /* get Q22 addr */ +lnt = tq_pkt[pkt].d[UQ_HLNT] - UQ_HDR_OFF; /* size, with hdr */ +if ((GETP (pkt, UQ_HCTC, TYP) == UQ_TYP_SEQ) && /* seq packet? */ + (GETP (pkt, CMD_OPC, OPC) & OP_END)) { /* end packet? */ + cr = (tq_credits >= 14)? 14: tq_credits; /* max 14 credits */ + tq_credits = tq_credits - cr; /* decr credits */ + tq_pkt[pkt].d[UQ_HCTC] |= ((cr + 1) << UQ_HCTC_V_CR); } +if (Map_WriteW (addr + UQ_HDR_OFF, lnt, tq_pkt[pkt].d, MAP)) + return tq_fatal (PE_PWE); /* write pkt */ +tq_enqh (&tq_freq, pkt); /* pkt is free */ +tq_pbsy = tq_pbsy - 1; /* decr busy cnt */ +if (tq_pbsy == 0) tq_hat = tq_htmo; /* idle? strt hst tmr */ +return tq_putdesc (&tq_rq, desc); /* release desc */ +} + +/* Get a descriptor from the host */ + +t_bool tq_getdesc (struct uq_ring *ring, uint32 *desc) +{ +t_addr addr = ring->ba + ring->idx; +uint16 d[2]; + +if (Map_ReadW (addr, 4, d, MAP)) /* fetch desc */ + return tq_fatal (PE_QRE); /* err? dead */ +*desc = ((uint32) d[0]) | (((uint32) d[1]) << 16); +return OK; +} + +/* Return a descriptor to the host, clearing owner bit + If rings transitions from "empty" to "not empty" or "full" to + "not full", and interrupt bit was set, interrupt the host. + Actually, test whether previous ring entry was owned by host. +*/ + +t_bool tq_putdesc (struct uq_ring *ring, uint32 desc) +{ +uint32 prvd, newd = (desc & ~UQ_DESC_OWN) | UQ_DESC_F; +t_addr prva, addr = ring->ba + ring->idx; +uint16 d[2]; + +d[0] = newd & 0xFFFF; /* 32b to 16b */ +d[1] = (newd >> 16) & 0xFFFF; +if (Map_WriteW (addr, 4, d, MAP)) /* store desc */ + return tq_fatal (PE_QWE); /* err? dead */ +if (desc & UQ_DESC_F) { /* was F set? */ + if (ring->lnt <= 4) tq_ring_int (ring); /* lnt = 1? intr */ + else { prva = ring->ba + /* prv desc */ + ((ring->idx - 4) & (ring->lnt - 1)); + if (Map_ReadW (prva, 4, d, MAP)) /* read prv */ + return tq_fatal (PE_QRE); + prvd = ((uint32) d[0]) | (((uint32) d[1]) << 16); + if (prvd & UQ_DESC_OWN) tq_ring_int (ring); } } +ring->idx = (ring->idx + 4) & (ring->lnt - 1); +return OK; +} + +/* Get unit descriptor for logical unit - trivial now, + but eventually, hide multiboard complexities here */ + +UNIT *tq_getucb (uint32 lu) +{ +UNIT *uptr; + +if (lu >= TQ_NUMDR) return NULL; +uptr = tq_dev.units + lu; +if (uptr->flags & UNIT_DIS) return NULL; +return uptr; +} + +/* Hack unit flags */ + +void tq_setf_unit (int32 pkt, UNIT *uptr) +{ +uptr->uf = tq_pkt[pkt].d[ONL_UFL] & UF_MSK; /* settable flags */ +if ((tq_pkt[pkt].d[CMD_MOD] & MD_SWP) && /* swre wrp enb? */ + (tq_pkt[pkt].d[ONL_UFL] & UF_WPS)) /* swre wrp on? */ + uptr->uf = uptr->uf | UF_WPS; /* simon says... */ +return; +} + +/* Hack end flags */ + +uint32 tq_efl (UNIT *uptr) +{ +uint32 t = 0; + +if (uptr) { /* any unit? */ + if (uptr->flags & UNIT_POL) t = t | EF_PLS; /* note pos lost */ + if (uptr->flags & UNIT_SXC) t = t | EF_SXC; /* note ser exc */ + if (TEST_EOT (uptr)) t = t | EF_EOT; } /* note EOT */ +return t; +} + +/* Unit response fields */ + +void tq_putr_unit (int32 pkt, UNIT *uptr, uint32 lu, t_bool all) +{ +tq_pkt[pkt].d[ONL_MLUN] = lu; /* multi-unit */ +tq_pkt[pkt].d[ONL_UFL] = uptr->uf | TQ_WPH (uptr); /* unit flags */ +tq_pkt[pkt].d[ONL_RSVL] = tq_pkt[pkt].d[ONL_RSVH] = 0; /* reserved */ +tq_pkt[pkt].d[ONL_UIDA] = lu; /* UID low */ +tq_pkt[pkt].d[ONL_UIDB] = 0; +tq_pkt[pkt].d[ONL_UIDC] = 0; +tq_pkt[pkt].d[ONL_UIDD] = (UID_TAPE << ONL_UIDD_V_CLS) | + (drv_tab[tq_typ].umod << ONL_UIDD_V_MOD); /* UID hi */ +PUTP32 (pkt, ONL_MEDL, drv_tab[tq_typ].med); /* media type */ +if (all) { /* if long form */ + tq_pkt[pkt].d[ONL_FMT] = drv_tab[tq_typ].fmt; /* format */ + tq_pkt[pkt].d[ONL_SPD] = 0; /* speed */ + PUTP32 (pkt, ONL_MAXL, TQ_MAXFR); /* max xfr */ + tq_pkt[pkt].d[ONL_NREC] = 0; /* noise rec */ + tq_pkt[pkt].d[ONL_RSVE] = 0; } /* reserved */ +return; +} + +/* UQ_HDR and RSP_OP fields */ + +void tq_putr (int32 pkt, uint32 cmd, uint32 flg, uint32 sts, uint32 lnt, uint32 typ) +{ +tq_pkt[pkt].d[RSP_OPF] = (cmd << RSP_OPF_V_OPC) | /* set cmd, flg */ + (flg << RSP_OPF_V_FLG); +tq_pkt[pkt].d[RSP_STS] = sts; +tq_pkt[pkt].d[UQ_HLNT] = lnt; /* length */ +tq_pkt[pkt].d[UQ_HCTC] = (typ << UQ_HCTC_V_TYP) | /* type, cid */ + (UQ_CID_TMSCP << UQ_HCTC_V_CID); /* clr credits */ +return; +} + +/* Post interrupt during init */ + +void tq_init_int (void) +{ +if ((tq_s1dat & SA_S1H_IE) && tq_dib.vec) SET_INT (TQ); +return; +} + +/* Post interrupt during putpkt - note that NXMs are ignored! */ + +void tq_ring_int (struct uq_ring *ring) +{ +t_addr iadr = tq_comm + ring->ioff; /* addr intr wd */ +uint16 flag = 1; + +Map_WriteW (iadr, 2, &flag, MAP); /* write flag */ +if (tq_dib.vec) SET_INT (TQ); /* if enb, intr */ +return; +} + +/* Return interrupt vector */ + +int32 tq_inta (void) +{ +return tq_dib.vec; /* prog vector */ +} + +/* Fatal error */ + +t_bool tq_fatal (uint32 err) +{ +if (DBG_LOG (LOG_TQ)) fprintf (sim_log, ">>TQ: fatal err=%X\n", err); +tq_reset (&tq_dev); /* reset device */ +tq_sa = SA_ER | err; /* SA = dead code */ +tq_csta = CST_DEAD; /* state = dead */ +tq_perr = err; /* save error */ +return ERR; +} + +/* Change controller type */ + +t_stat tq_set_type (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +tq_typ = val; +return SCPE_OK; +} + +/* Device attach */ + +t_stat tq_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +r = attach_unit (uptr, cptr); +if (r != SCPE_OK) return r; +if (tq_csta == CST_UP) uptr->flags = (uptr->flags | UNIT_ATP) & + ~(UNIT_SXC | UNIT_POL | UNIT_TMK); +return SCPE_OK; +} + +/* Device detach */ + +t_stat tq_detach (UNIT *uptr) +{ +t_stat r; + +r = detach_unit (uptr); /* detach unit */ +if (r != SCPE_OK) return r; +uptr->flags = uptr->flags & ~(UNIT_ONL | UNIT_ATP | UNIT_SXC | UNIT_POL | UNIT_TMK); +uptr->uf = 0; /* clr unit flgs */ +return SCPE_OK; +} + +/* Device reset */ + +t_stat tq_reset (DEVICE *dptr) +{ +int32 i, j; +UNIT *uptr; + +tq_csta = CST_S1; /* init stage 1 */ +tq_s1dat = 0; /* no S1 data */ +tq_dib.vec = 0; /* no vector */ +tq_sa = SA_S1 | SA_S1C_Q22 | SA_S1C_DI | SA_S1C_MP; /* init SA val */ +tq_cflgs = CF_RPL; /* ctrl flgs off */ +tq_htmo = TQ_DHTMO; /* default timeout */ +tq_hat = tq_htmo; /* default timer */ +tq_cq.ba = tq_cq.lnt = tq_cq.idx = 0; /* clr cmd ring */ +tq_rq.ba = tq_rq.lnt = tq_rq.idx = 0; /* clr rsp ring */ +tq_credits = (TQ_NPKTS / 2) - 1; /* init credits */ +tq_freq = 1; /* init free list */ +for (i = 0; i < TQ_NPKTS; i++) { /* all pkts free */ + if (i) tq_pkt[i].link = (i + 1) & TQ_M_NPKTS; + else tq_pkt[i].link = 0; + for (j = 0; j < TQ_PKT_SIZE_W; j++) tq_pkt[i].d[j] = 0; } +tq_rspq = 0; /* no q'd rsp pkts */ +tq_pbsy = 0; /* all pkts free */ +tq_pip = 0; /* not polling */ +CLR_INT (TQ); /* clr intr req */ +for (i = 0; i < TQ_NUMDR + 2; i++) { /* init units */ + uptr = tq_dev.units + i; + sim_cancel (uptr); /* clr activity */ + uptr->flags = uptr->flags & /* not online */ + ~(UNIT_ONL|UNIT_ATP|UNIT_SXC|UNIT_POL|UNIT_TMK); + uptr->uf = 0; /* clr unit flags */ + uptr->cpkt = uptr->pktq = 0; } /* clr pkt q's */ +if (tqxb == NULL) tqxb = calloc (TQ_MAXFR, sizeof (uint8)); +if (tqxb == NULL) return SCPE_MEM; +return SCPE_OK; +} + +/* Device bootstrap */ + +#if defined (VM_PDP11) + +#define BOOT_START 016000 /* start */ +#define BOOT_ENTRY (BOOT_START + 002) /* entry */ +#define BOOT_UNIT (BOOT_START + 010) /* unit number */ +#define BOOT_CSR (BOOT_START + 014) /* CSR */ +#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) + + +/* Data structure definitions */ + +#define B_CMDINT (BOOT_START - 01000) /* cmd int */ +#define B_RSPINT (B_CMDINT + 002) /* rsp int */ +#define B_RING (B_RSPINT + 002) /* ring base */ +#define B_RSPH (B_RING + 010) /* resp pkt hdr */ +#define B_TKRSP (B_RSPH + 004) /* resp pkt */ +#define B_CMDH (B_TKRSP + 060) /* cmd pkt hdr */ +#define B_TKCMD (B_CMDH + 004) /* cmd pkt */ +#define B_UNIT (B_TKCMD + 004) /* unit # */ + +static const uint16 boot_rom[] = { + + 0046525, /* ST: "UM" */ + + 0012706, 0016000, /* mov #st,sp */ + 0012700, 0000000, /* mov #unitno,r0 */ + 0012701, 0174500, /* mov #174500,r1 ; ip addr */ + 0005021, /* clr (r1)+ ; init */ + 0012704, 0004000, /* mov #4000,r4 ; s1 mask */ + 0005002, /* clr r2 */ + 0005022, /* 10$: clr (r2)+ ; clr up to boot */ + 0020237, BOOT_START - 2, /* cmp r2,#st-2 */ + 0103774, /* blo 10$ */ + 0012705, BOOT_START+0312, /* mov #cmdtbl,r5 ; addr of tbl */ + + /* Four step init process */ + + 0005711, /* 20$: tst (r1) ; err? */ + 0100001, /* bpl 30$ */ + 0000000, /* halt */ + 0030411, /* 30$: bit r4,(r1) ; step set? */ + 0001773, /* beq 20$ ; wait */ + 0012511, /* mov (r5)+,(r1) ; send next */ + 0006304, /* asl r4 ; next mask */ + 0100370, /* bpl 20$ ; s4 done? */ + + /* Set up rings, issue ONLINE, REWIND, READ */ + + 0012737, 0000400, B_CMDH + 2, /* mov #400,cmdh+2 ; VCID = 1 */ + 0012737, 0000044, B_CMDH, /* mov #36.,cmdh ; cmd pkt lnt */ + 0010037, B_UNIT, /* mov r0,unit ; unit # */ + 0012737, 0000011, B_TKCMD + 8, /* mov #11,tkcmd+8. ; online op */ + 0012737, 0020000, B_TKCMD + 10, /* mov #20000,tkcmd+10. ; clr ser ex */ + 0012702, B_RING, /* mov #ring,r2 ; init rings */ + 0012722, B_TKRSP, /* mov #tkrsp,(r2)+ ; rsp pkt addr */ + 0010203, /* mov r2,r3 ; save ring+2 */ + 0010423, /* mov r4,(r3)+ ; set TK own */ + 0012723, B_TKCMD, /* mov #tkcmd,(r3)+ ; cmd pkt addr */ + 0010423, /* mov r4,(r3)+ ; set TK own */ + 0005741, /* tst -(r1) ; start poll */ + 0005712, /* 40$: tst (r2) ; wait for resp */ + 0100776, /* bmi 40$ */ + 0105737, B_TKRSP + 10, /* tstb tkrsp+10. ; check stat */ + 0001401, /* beq 50$ */ + 0000000, /* halt */ + 0012703, B_TKCMD + 8, /* 50$: mov #tkcmd+8.,r3 */ + 0012723, 0000045, /* mov #45,(r3)+ ; reposition */ + 0012723, 0020002, /* mov #20002,(r3)+ ; rew, clr exc */ + 0012723, 0000001, /* mov #1,(r3)+ ; lo rec skp */ + 0005023, /* clr (r3)+ ; hi rec skp */ + 0005023, /* clr (r3)+ ; lo tmk skp */ + 0005023, /* clr (r3)+ ; hi tmk skp */ + 0010412, /* mov r4,(r2) ; TK own rsp */ + 0010437, B_RING + 6, /* mov r4,ring+6 ; TK own cmd */ + 0005711, /* tst (r1) ; start poll */ + 0005712, /* 60$: tst (r2) ; wait for resp */ + 0100776, /* bmi 60$ */ + 0105737, B_TKRSP + 10, /* tstb tkrsp+10. ; check stat */ + 0001401, /* beq 70$ */ + 0000000, /* halt */ + 0012703, B_TKCMD + 8, /* 70$: mov #tkcmd+8.,r3 */ + 0012723, 0000041, /* mov #41,(r3)+ ; read */ + 0012723, 0020000, /* mov #20000,(r3)+ ; clr exc */ + 0012723, 0001000, /* mov #512.,(r3)+ ; bc = 512 */ + 0005023, /* clr (r3)+ ; clr args */ + 0005023, /* clr (r3)+ ; ba = 0 */ + 0010412, /* mov r4,(r2) ; TK own rsp */ + 0010437, B_RING + 6, /* mov r4,ring+6 ; TK own cmd */ + 0005711, /* tst (r1) ; start poll */ + 0005712, /* 80$: tst (r2) ; wait for resp */ + 0100776, /* bmi 80$ */ + 0105737, B_TKRSP + 10, /* tstb tkrsp+10. ; check stat */ + 0001401, /* beq 90$ */ + 0000000, /* halt */ + + /* Boot block read in, jump to 0 - leave controller init'd */ + + 0005003, /* clr r3 */ + 0012704, BOOT_START+020, /* mov #st+020,r4 */ + 0005005, /* clr r5 */ + 0005007, /* clr pc */ + + 0100000, /* cmdtbl: init step 1 */ + B_RING, /* ring base */ + 0000000, /* high ring base */ + 0000001 /* go */ +}; + +t_stat tq_boot (int32 unitno, DEVICE *dptr) +{ +int32 i; +extern int32 saved_PC; +extern uint16 *M; + +for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i]; +M[BOOT_UNIT >> 1] = unitno & 3; +M[BOOT_CSR >> 1] = tq_dib.ba & DMASK; +saved_PC = BOOT_ENTRY; +return SCPE_OK; +} + +#else + +t_stat tq_boot (int32 unitno, DEVICE *dptr) +{ +return SCPE_NOFNC; +} +#endif + +/* Special show commands */ + +void tq_show_ring (FILE *st, struct uq_ring *rp) +{ +uint32 i, desc; +uint16 d[2]; + +#if defined (VM_PDP11) +fprintf (st, "ring, base = %o, index = %d, length = %d\n", + rp->ba, rp->idx >> 2, rp->lnt >> 2); +#else +fprintf (st, "ring, base = %x, index = %d, length = %d\n", + rp->ba, rp->idx >> 2, rp->lnt >> 2); +#endif +for (i = 0; i < (rp->lnt >> 2); i++) { + if (Map_ReadW (rp->ba + (i << 2), 4, d, MAP)) { + fprintf (st, " %3d: non-existent memory\n", i); + break; } + desc = ((uint32) d[0]) | (((uint32) d[1]) << 16); +#if defined (VM_PDP11) + fprintf (st, " %3d: %011o\n", i, desc); +#else + fprintf (st, " %3d: %08x\n", i, desc); +#endif + } +return; +} + +void tq_show_pkt (FILE *st, int32 pkt) +{ +int32 i, j; +uint32 cr = GETP (pkt, UQ_HCTC, CR); +uint32 typ = GETP (pkt, UQ_HCTC, TYP); +uint32 cid = GETP (pkt, UQ_HCTC, CID); + +fprintf (st, "packet %d, credits = %d, type = %d, cid = %d\n", + pkt, cr, typ, cid); +for (i = 0; i < TQ_SH_MAX; i = i + TQ_SH_PPL) { + fprintf (st, " %2d:", i); + for (j = i; j < (i + TQ_SH_PPL); j++) +#if defined (VM_PDP11) + fprintf (st, " %06o", tq_pkt[pkt].d[j]); +#else + fprintf (st, " %04x", tq_pkt[pkt].d[j]); +#endif + fprintf (st, "\n"); + } +return; +} + +t_stat tq_show_unitq (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +int32 pkt, u = uptr - tq_dev.units; + +if (tq_csta != CST_UP) { + fprintf (st, "Controller is not initialized\n"); + return SCPE_OK; } +if ((uptr->flags & UNIT_ONL) == 0) { + if (uptr->flags & UNIT_ATT) + fprintf (st, "Unit %d is available\n", u); + else fprintf (st, "Unit %d is offline\n", u); + return SCPE_OK; } +if (uptr->cpkt) { + fprintf (st, "Unit %d current ", u); + tq_show_pkt (st, uptr->cpkt); + if (pkt = uptr->pktq) { + do { fprintf (st, "Unit %d queued ", u); + tq_show_pkt (st, pkt); } + while (pkt = tq_pkt[pkt].link); } } +else fprintf (st, "Unit %d queues are empty\n", u); +return SCPE_OK; +} + +t_stat tq_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +int32 i, pkt; + +if (tq_csta != CST_UP) { + fprintf (st, "Controller is not initialized\n"); + return SCPE_OK; } +if (val & TQ_SH_RI) { + if (tq_pip) fprintf (st, "Polling in progress, host timer = %d\n", tq_hat); + else fprintf (st, "Host timer = %d\n", tq_hat); + fprintf (st, "Command "); + tq_show_ring (st, &tq_cq); + fprintf (st, "Response "); + tq_show_ring (st, &tq_rq); + } +if (val & TQ_SH_FR) { + if (pkt = tq_freq) { + for (i = 0; pkt != 0; i++, pkt = tq_pkt[pkt].link) { + if (i == 0) fprintf (st, "Free queue = %d", pkt); + else if ((i % 16) == 0) fprintf (st, ",\n %d", pkt); + else fprintf (st, ", %d", pkt); } + fprintf (st, "\n"); } + else fprintf (st, "Free queue is empty\n"); + } +if (val & TQ_SH_RS) { + if (pkt = tq_rspq) { + do { fprintf (st, "Response "); + tq_show_pkt (st, pkt); } + while (pkt = tq_pkt[pkt].link); } + else fprintf (st, "Response queue is empty\n"); + } +if (val & TQ_SH_UN) { + for (i = 0; i < TQ_NUMDR; i++) + tq_show_unitq (st, &tq_unit[i], 0, NULL); + } +return SCPE_OK; +} diff --git a/PDP11/pdp11_ts.c b/PDP11/pdp11_ts.c index 78d1ed5a..58a3ba96 100644 --- a/PDP11/pdp11_ts.c +++ b/PDP11/pdp11_ts.c @@ -25,6 +25,12 @@ ts TS11/TSV05 magtape + 30-Sep-02 RMS Added variable address support to bootstrap + Added vector change/display support + Fixed CTL unload/clean decode + Implemented XS0_MOT in extended status + New data structures, revamped error recovery + 28-Aug-02 RMS Added end of medium support 30-May-02 RMS Widened POS to 32b 22-Apr-02 RMS Added maximum record length protection 04-Apr-02 RMS Fixed bug in residual frame count after space operation @@ -69,8 +75,7 @@ #include "vax_defs.h" #define VM_VAX 1 #define TS_RDX 16 -#define TS_DF_ENB 1 /* on by default */ -#define TS_18B FALSE /* always 22b */ +#define TS_DIS 0 /* on by default */ #define ADDRTEST 0177700 #define DMASK 0xFFFF extern int32 ReadB (t_addr pa); @@ -82,9 +87,8 @@ extern void WriteW (t_addr pa, int32 val); #include "pdp11_defs.h" #define VM_PDP11 1 #define TS_RDX 8 -#define TS_DF_ENB 0 /* off by default */ -#define TS_18B (cpu_18b || cpu_ubm) -#define ADDRTEST (TS_18B? 0177774: 0177700) +#define TS_DIS DEV_DIS /* off by default */ +#define ADDRTEST (UNIBUS? 0177774: 0177700) extern uint16 *M; extern int32 cpu_18b, cpu_ubm; #define ReadB(p) ((M[(p) >> 1] >> (((p) & 1)? 8: 0)) & 0377) @@ -211,7 +215,7 @@ extern int32 cpu_18b, cpu_ubm; #define XS0_NEF 0002000 /* non exec fnc */ #define XS0_ILC 0001000 /* illegal cmd */ #define XS0_ILA 0000400 /* illegal addr */ -#define XS0_MOT 0000200 /* motion */ +#define XS0_MOT 0000200 /* tape has moved */ #define XS0_ONL 0000100 /* online */ #define XS0_IE 0000040 /* int enb */ #define XS0_VCK 0000020 /* volume check */ @@ -219,9 +223,11 @@ extern int32 cpu_18b, cpu_ubm; #define XS0_WLK 0000004 /* write lock */ #define XS0_BOT 0000002 /* BOT */ #define XS0_EOT 0000001 /* EOT */ -#define XS0_ALLERR 0177600 /* all errors */ +#define XS0_ALLCLR 0177600 /* clear at start */ -/* Extended status register 1 - none of these errors are ever set */ +/* Extended status register 1 */ + +#define XS1_UCOR 0000002 /* uncorrectable */ /* Extended status register 2 */ @@ -260,6 +266,8 @@ extern int32 cpu_18b, cpu_ubm; #define MAX(a,b) (((a) >= (b))? (a): (b)) extern int32 int_req[IPL_HLVL]; +extern int32 int_vec[IPL_HLVL][32]; + extern UNIT cpu_unit; extern int32 cpu_log; extern FILE *sim_log; @@ -276,13 +284,14 @@ int32 ts_qatn = 0; /* queued attn */ int32 ts_bcmd = 0; /* boot cmd */ int32 ts_time = 10; /* record latency */ +DEVICE ts_dev; t_stat ts_rd (int32 *data, int32 PA, int32 access); t_stat ts_wr (int32 data, int32 PA, int32 access); t_stat ts_svc (UNIT *uptr); t_stat ts_reset (DEVICE *dptr); t_stat ts_attach (UNIT *uptr, char *cptr); t_stat ts_detach (UNIT *uptr); -t_stat ts_boot (int32 unitno); +t_stat ts_boot (int32 unitno, DEVICE *dptr); int32 ts_updtssr (int32 t); int32 ts_updxs0 (int32 t); void ts_cmpendcmd (int32 s0, int32 s1); @@ -296,7 +305,8 @@ void ts_endcmd (int32 ssf, int32 xs0f, int32 msg); ts_mod TS modifier list */ -DIB ts_dib = { TS_DF_ENB, IOBA_TS, IOLN_TS, &ts_rd, &ts_wr }; +DIB ts_dib = { IOBA_TS, IOLN_TS, &ts_rd, &ts_wr, + 1, IVCL (TS), VEC_TS, { NULL } }; UNIT ts_unit = { UDATA (&ts_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }; @@ -327,27 +337,25 @@ REG ts_reg[] = { { FLDATA (OWNM, ts_ownm, 0) }, { DRDATA (TIME, ts_time, 24), PV_LEFT + REG_NZ }, { DRDATA (POS, ts_unit.pos, 32), PV_LEFT + REG_RO }, - { FLDATA (WLK, ts_unit.flags, UNIT_V_WLK), REG_HRO }, { GRDATA (DEVADDR, ts_dib.ba, TS_RDX, 32, 0), REG_HRO }, - { FLDATA (*DEVENB, ts_dib.enb, 0), REG_HRO }, + { GRDATA (DEVVEC, ts_dib.vec, TS_RDX, 16, 0), REG_HRO }, { NULL } }; MTAB ts_mod[] = { { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, &ts_dib }, - { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", - &set_enbdis, NULL, &ts_dib }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", - &set_enbdis, NULL, &ts_dib }, + &set_addr, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + &set_vec, &show_vec, NULL }, { 0 } }; DEVICE ts_dev = { "TS", &ts_unit, ts_reg, ts_mod, 1, 10, 31, 1, TS_RDX, 8, NULL, NULL, &ts_reset, - &ts_boot, &ts_attach, &ts_detach }; + &ts_boot, &ts_attach, &ts_detach, + &ts_dib, DEV_DISABLE | TS_DIS | DEV_UBUS | DEV_QBUS }; /* I/O dispatch routine, I/O addresses 17772520 - 17772522 @@ -381,7 +389,7 @@ case 0: /* TSDB */ ((data & 03) << 16) | (data & 0177774); tsdbx = 0; /* clr tsdbx */ tssr = ts_updtssr (tssr & TSSR_NBA); /* clr ssr, err */ - msgxs0 = ts_updxs0 (msgxs0 & ~XS0_ALLERR); /* clr err, upd xs0 */ + msgxs0 = ts_updxs0 (msgxs0 & ~XS0_ALLCLR); /* clr, upd xs0 */ msgrfc = msgxs1 = msgxs2 = msgxs3 = msgxs4 = 0; /* clr status */ CLR_INT (TS); /* clr int req */ for (i = 0; i < CMD_PLNT; i++) { /* get cmd pkt */ @@ -395,7 +403,7 @@ case 0: /* TSDB */ break; case 1: /* TSSR */ if (PA & 1) { /* TSDBX */ - if (TS_18B) return SCPE_OK; /* not in TS11 */ + if (UNIBUS) return SCPE_OK; /* not in TS11 */ if (tssr & TSSR_SSR) { /* ready? */ tsdbx = data; /* save */ if (data & TSDBX_BOOT) { @@ -415,10 +423,14 @@ return SCPE_OK; int32 ts_rdlntf (UNIT *uptr, t_mtrlnt *tbc) { -fseek (uptr -> fileref, uptr -> pos, SEEK_SET); /* set pos */ -fxread (tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); /* read rec lnt */ -if (ferror (uptr -> fileref)) return (XTC (XS0_EOT | XS0_RLS, TC2)); -if (feof (uptr -> fileref)) return (XTC (XS0_TMK | XS0_RLS, TC2)); +fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set pos */ +fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); /* read rec lnt */ +if (ferror (uptr->fileref)) { /* error? */ + msgxs1 = msgxs1 | XS1_UCOR; /* uncorrectable */ + return (XTC (XS0_RLS, TC6)); } /* pos lost */ +if (feof (uptr->fileref) || (*tbc == MTR_EOM)) { /* end of medium? */ + msgxs3 = msgxs3 | XS3_OPI; /* incomplete */ + return (XTC (XS0_RLS, TC6)); } /* pos lost */ return 0; } @@ -430,9 +442,11 @@ t_mtrlnt tbc; do { fc = (fc - 1) & DMASK; /* decr wc */ if (upd) msgrfc = fc; if (st = ts_rdlntf (uptr, &tbc)) return st; /* read rec lnt */ - uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); /* update pos */ - if (tbc == 0) return (XTC (XS0_TMK | XS0_RLS, TC2)); - uptr -> pos = uptr -> pos + ((MTRL (tbc) + 1) & ~1) + sizeof (t_mtrlnt); + uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* update pos */ + msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ + if (tbc == MTR_TMK) /* tape mark? */ + return (XTC (XS0_TMK | XS0_RLS, TC2)); + uptr->pos = uptr->pos + ((MTRL (tbc) + 1) & ~1) + sizeof (t_mtrlnt); } while (fc != 0); return 0; @@ -445,13 +459,13 @@ t_mtrlnt prvp; t_bool tmkprv = FALSE; msgrfc = fc; -if ((uptr -> pos == 0) && (wchopt & WCH_ENB)) tmkprv = TRUE; -do { prvp = uptr -> pos; /* save cur pos */ +if ((uptr->pos == 0) && (wchopt & WCH_ENB)) tmkprv = TRUE; +do { prvp = uptr->pos; /* save cur pos */ tc = ts_spacef (uptr, 0, FALSE); /* space fwd */ if (GET_X (tc) & XS0_TMK) { /* tape mark? */ msgrfc = (msgrfc - 1) & DMASK; /* decr count */ if (tmkprv && (wchopt & WCH_ESS) && - (uptr -> pos - prvp == sizeof (t_mtrlnt))) + (uptr->pos - prvp == sizeof (t_mtrlnt))) return (XTC ((msgrfc? XS0_RLS: 0) | XS0_TMK | XS0_LET, TC2)); tmkprv = TRUE; } @@ -464,12 +478,21 @@ return 0; int32 ts_rdlntr (UNIT *uptr, t_mtrlnt *tbc) { msgxs3 = msgxs3 | XS3_REV; /* set rev op */ -fseek (uptr -> fileref, uptr -> pos - sizeof (t_mtrlnt), SEEK_SET); -fxread (tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); -if (ferror (uptr -> fileref) || /* error or eof? */ - feof (uptr -> fileref)) { - msgxs3 = msgxs3 | XS3_OPI; /* fatal err */ - return (XTC (XS0_RLS, TC6)); } +if (uptr->pos < sizeof (t_mtrlnt)) { /* BOT? */ + msgxs3 = msgxs3 | XS3_RIB; /* set status */ + return (XTC (XS0_BOT | XS0_RLS, TC2)); } /* tape alert */ +fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt), SEEK_SET); +fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); +if (ferror (uptr->fileref)) { /* error? */ + msgxs1 = msgxs1 | XS1_UCOR; /* uncorrectable */ + return (XTC (XS0_RLS, TC6)); } /* pos lost */ +if (feof (uptr->fileref)) { /* end of file? */ + msgxs3 = msgxs3 | XS3_OPI; /* incomplete */ + return (XTC (XS0_RLS, TC6)); } /* pos lost */ +if (*tbc == MTR_EOM) { /* eom? */ + msgxs3 = msgxs3 | XS3_OPI; /* incomplete */ + uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over eom */ + return (XTC (XS0_RLS, TC6)); } /* pos lost */ return 0; } @@ -479,18 +502,16 @@ int32 st; t_mtrlnt tbc; if (upd) msgrfc = fc; -do { if (uptr -> pos == 0) break; /* BOT? */ - fc = (fc - 1) & DMASK; /* decr wc */ +do { fc = (fc - 1) & DMASK; /* decr wc */ if (upd) msgrfc = fc; if (st = ts_rdlntr (uptr, &tbc)) return st; /* read rec lnt */ - uptr -> pos = uptr -> pos - sizeof (t_mtrlnt); /* update pos */ - if (tbc == 0) return (XTC (XS0_TMK | XS0_RLS, TC2)); - uptr -> pos = uptr -> pos - ((MTRL (tbc) + 1) & ~1) - sizeof (t_mtrlnt); + uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* update pos */ + msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ + if (tbc == MTR_TMK) /* tape mark? */ + return (XTC (XS0_TMK | XS0_RLS, TC2)); + uptr->pos = uptr->pos - ((MTRL (tbc) + 1) & ~1) - sizeof (t_mtrlnt); } while (fc != 0); -if (uptr -> pos == 0) { - msgxs3 = msgxs3 | XS3_RIB; - return (XTC (XS0_BOT | (fc? XS0_RLS: 0), TC2)); } return 0; } @@ -501,12 +522,12 @@ t_mtrlnt prvp; t_bool tmkprv = FALSE; msgrfc = fc; -do { prvp = uptr -> pos; /* save cur pos */ +do { prvp = uptr->pos; /* save cur pos */ tc = ts_spacer (uptr, 0, FALSE); /* space rev */ if (GET_X (tc) & XS0_TMK) { /* tape mark? */ msgrfc = (msgrfc - 1) & DMASK; /* decr wc */ if (tmkprv && (wchopt & WCH_ESS) && - (prvp - uptr -> pos == sizeof (t_mtrlnt))) + (prvp - uptr->pos == sizeof (t_mtrlnt))) return (XTC ((msgrfc? XS0_RLS: 0) | XS0_TMK | XS0_LET, TC2)); tmkprv = TRUE; } @@ -516,26 +537,32 @@ while (msgrfc != 0); return 0; } -int32 ts_readf (UNIT *uptr, int32 fc) +int32 ts_readf (UNIT *uptr, uint32 fc) { -int32 i, st; -t_mtrlnt tbc, wbc; +int32 st; +t_mtrlnt i, tbc, wbc; t_addr wa, pa; msgrfc = fc; if (st = ts_rdlntf (uptr, &tbc)) return st; /* read rec lnt */ -if (tbc == 0) { /* tape mark? */ - uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); /* update pos */ +if (tbc == MTR_TMK) { /* tape mark? */ + uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* update pos */ + msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ return (XTC (XS0_TMK | XS0_RLS, TC2)); } if (fc == 0) fc = 0200000; /* byte count */ tsba = (cmdadh << 16) | cmdadl; /* buf addr */ tbc = MTRL (tbc); /* ignore err flag */ -if (tbc > MT_MAXFR) return SCPE_MTRLNT; /* record too long? */ +if (tbc > MT_MAXFR) { /* record too long? */ + msgxs1 = msgxs1 | XS1_UCOR; /* uncorrectable */ + return XTC (XS0_RLS, TC6); } /* pos lost */ wbc = (tbc > fc)? fc: tbc; /* cap buf size */ -i = fxread (tsxb, sizeof (uint8), wbc, uptr -> fileref); /* read record */ -if (ferror (uptr -> fileref)) return XTC (XS0_EOT | XS0_RLS, TC2); +i = fxread (tsxb, sizeof (uint8), wbc, uptr->fileref); /* read record */ +if (ferror (uptr->fileref)) { /* error? */ + msgxs1 = msgxs1 | XS1_UCOR; /* uncorrectable */ + return XTC (XS0_RLS, TC6); } /* pos lost */ for ( ; i < wbc; i++) tsxb[i] = 0; /* fill with 0's */ -uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) + (2 * sizeof (t_mtrlnt)); +uptr->pos = uptr->pos + ((tbc + 1) & ~1) + (2 * sizeof (t_mtrlnt)); +msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ for (i = 0; i < wbc; i++) { /* copy buffer */ wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply OPP */ if (Map_Addr (wa, &pa) && ADDR_IS_MEM (pa)) /* map addr, nxm? */ @@ -549,32 +576,33 @@ if (tbc > wbc) return (XTC (XS0_RLL, TC2)); /* rec too big? */ return 0; } -int32 ts_readr (UNIT *uptr, int32 fc) +int32 ts_readr (UNIT *uptr, uint32 fc) { -int32 i, st; -t_mtrlnt tbc, wbc; +int32 st; +t_mtrlnt i, tbc, wbc; t_addr wa, pa; msgrfc = fc; -if (uptr -> pos == 0) { /* BOT? */ - msgxs3 = msgxs3 | XS3_RIB; /* nothing to do */ - return (XTC (XS0_BOT | XS0_RLS, TC2)); } if (st = ts_rdlntr (uptr, &tbc)) return st; /* read rec lnt */ -if (tbc == 0) { /* tape mark? */ - uptr -> pos = uptr -> pos - sizeof (t_mtrlnt); /* update pos */ +if (tbc == MTR_TMK) { /* tape mark? */ + uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* update pos */ + msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ return XTC (XS0_TMK | XS0_RLS, TC2); } if (fc == 0) fc = 0200000; /* byte count */ tsba = (cmdadh << 16) | cmdadl + fc; /* buf addr */ tbc = MTRL (tbc); /* ignore err flag */ -if (tbc > MT_MAXFR) return SCPE_MTRLNT; /* record too long? */ +if (tbc > MT_MAXFR) { /* record too long? */ + msgxs1 = msgxs1 | XS1_UCOR; /* uncorrectable */ + return XTC (XS0_RLS, TC6); } /* pos lost */ wbc = (tbc > fc)? fc: tbc; /* cap buf size */ -fseek (uptr -> fileref, uptr -> pos - sizeof (t_mtrlnt) - wbc, SEEK_SET); -i = fxread (tsxb, sizeof (uint8), wbc, uptr -> fileref); +fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt) - wbc, SEEK_SET); +i = fxread (tsxb, sizeof (uint8), wbc, uptr->fileref); for ( ; i < wbc; i++) tsxb[i] = 0; /* fill with 0's */ -if (ferror (uptr -> fileref)) { /* error? */ - msgxs3 = msgxs3 | XS3_OPI; - return XTC (XS0_RLS, TC6); } -uptr -> pos = uptr -> pos - ((tbc + 1) & ~1) - (2 * sizeof (t_mtrlnt)); +if (ferror (uptr->fileref)) { /* error? */ + msgxs1 = msgxs1 | XS1_UCOR; /* uncorrectable */ + return XTC (XS0_RLS, TC6); } /* pos lost */ +uptr->pos = uptr->pos - ((tbc + 1) & ~1) - (2 * sizeof (t_mtrlnt)); +msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ for (i = wbc; i > 0; i--) { /* copy buffer */ tsba = tsba - 1; wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply OPP */ @@ -590,7 +618,7 @@ return 0; int32 ts_write (UNIT *uptr, int32 fc) { -int32 i; +int32 i, ebc; t_addr wa, pa; msgrfc = fc; @@ -603,26 +631,29 @@ for (i = 0; i < fc; i++) { /* copy mem to buf */ else { tssr = ts_updtssr (tssr | TSSR_NXM); return TC5; } tsba = tsba + 1; } -fseek (uptr -> fileref, uptr -> pos, SEEK_SET); /* position */ -fxwrite (&fc, sizeof (t_mtrlnt), 1, uptr -> fileref); -fxwrite (tsxb, sizeof (uint8), fc, uptr -> fileref); -fxwrite (&fc, sizeof (t_mtrlnt), 1, uptr -> fileref); -uptr -> pos = uptr -> pos + ((fc + 1) & ~1) + (2 * sizeof (t_mtrlnt)); -msgrfc = 0; -if (ferror (uptr -> fileref)) { /* error? */ +ebc = (fc + 1) & ~1; /* force even */ +fseek (uptr->fileref, uptr->pos, SEEK_SET); /* position */ +fxwrite (&fc, sizeof (t_mtrlnt), 1, uptr->fileref); +fxwrite (tsxb, sizeof (uint8), ebc, uptr->fileref); +fxwrite (&fc, sizeof (t_mtrlnt), 1, uptr->fileref); +if (ferror (uptr->fileref)) { /* error? */ msgxs3 = msgxs3 | XS3_OPI; return TC6; } +uptr->pos = uptr->pos + ebc + (2 * sizeof (t_mtrlnt)); /* update pos */ +msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ +msgrfc = 0; return 0; } int32 ts_wtmk (UNIT *uptr) { -t_mtrlnt bceof = 0; +t_mtrlnt bceof = MTR_TMK; -fseek (uptr -> fileref, uptr -> pos, SEEK_SET); /* set pos */ -fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr -> fileref); -uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); /* update position */ -if (ferror (uptr -> fileref)) return TC6; +fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set pos */ +fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr->fileref); +if (ferror (uptr->fileref)) return TC6; +uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* update position */ +msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ return XTC (XS0_TMK, TC0); } @@ -646,8 +677,8 @@ static const int32 fnc_flg[CMD_N_FNC] = { if (ts_bcmd) { /* boot? */ ts_bcmd = 0; /* clear flag */ - uptr -> pos = 0; /* rewind */ - if (uptr -> flags & UNIT_ATT) { /* attached? */ + uptr->pos = 0; /* rewind */ + if (uptr->flags & UNIT_ATT) { /* attached? */ cmdlnt = cmdadh = cmdadl = 0; /* defang rd */ ts_spacef (uptr, 1, FALSE); /* space fwd */ ts_readf (uptr, 512); /* read blk */ @@ -663,6 +694,9 @@ if (!(cmdhdr & CMD_ACK)) { /* no acknowledge? */ return SCPE_OK; } fnc = GET_FNC (cmdhdr); /* get fnc+mode */ mod = GET_MOD (cmdhdr); +if (DBG_LOG (LOG_TS)) + fprintf (sim_log, ">>TS: cmd=%o, mod=%o, buf=%o, lnt=%d, pos=%d\n", + fnc, mod, cmdadl, cmdlnt, ts_unit.pos); if ((fnc != FNC_WCHR) && (tssr & TSSR_NBA)) { /* ~wr chr & nba? */ ts_endcmd (TC3, 0, 0); /* error */ return SCPE_OK; } @@ -677,16 +711,16 @@ if ((cmdhdr & CMD_MBZ) || (mod >= fnc_mod[fnc])) { /* test mbz */ ts_endcmd (TC3, XS0_ILC, MSG_ACK | MSG_MILL | MSG_CFAIL); return SCPE_OK; } if ((fnc_flg[fnc] & FLG_MO) && /* mot+(vck|!att)? */ - ((msgxs0 & XS0_VCK) || !(uptr -> flags & UNIT_ATT))) { + ((msgxs0 & XS0_VCK) || !(uptr->flags & UNIT_ATT))) { ts_endcmd (TC3, XS0_NEF, MSG_ACK | MSG_MNEF | MSG_CFAIL); return SCPE_OK; } if ((fnc_flg[fnc] & FLG_WR) && /* write? */ - (uptr -> flags & UNIT_WPRT)) { /* write lck? */ + (uptr->flags & UNIT_WPRT)) { /* write lck? */ ts_endcmd (TC3, XS0_WLE | XS0_NEF, MSG_ACK | MSG_MNEF | MSG_CFAIL); return SCPE_OK; } if ((((fnc == FNC_READ) && (mod == 1)) || /* read rev */ ((fnc == FNC_POS) && (mod & 1))) && /* space rev */ - (uptr -> pos == 0)) { /* BOT? */ + (uptr->pos == 0)) { /* BOT? */ ts_endcmd (TC3, XS0_NEF, MSG_ACK | MSG_MNEF | MSG_CFAIL); return SCPE_OK; } if ((fnc_flg[fnc] & FLG_AD) && (cmdadh & ADDRTEST)) { /* buf addr > 22b? */ @@ -696,7 +730,8 @@ if ((fnc_flg[fnc] & FLG_AD) && (cmdadh & ADDRTEST)) { /* buf addr > 22b? */ st0 = st1 = 0; switch (fnc) { /* case on func */ case FNC_INIT: /* init */ - uptr -> pos = 0; /* rewind */ + if (uptr->pos) msgxs0 = msgxs0 | XS0_MOT; /* set if tape moves */ + uptr->pos = 0; /* rewind */ case FNC_WSSM: /* write mem */ case FNC_GSTA: /* get status */ ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); /* send end packet */ @@ -725,18 +760,20 @@ case FNC_CTL: /* control */ if (wchopt & WCH_ERI) SET_INT (TS); ts_ownc = 0; ts_ownm = 1; /* keep msg */ break; - case 01: /* clean */ - ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); /* nop */ - break; - case 02: /* rewind and unload */ + case 01: /* rewind and unload */ + if (uptr->pos) msgxs0 = msgxs0 | XS0_MOT; /* if tape moves */ detach_unit (uptr); /* unload */ ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); break; + case 02: /* clean */ + ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); /* nop */ + break; case 03: /* undefined */ ts_endcmd (TC3, XS0_ILC, MSG_ACK | MSG_MILL | MSG_CFAIL); return SCPE_OK; case 04: /* rewind */ - ts_unit.pos = 0; + if (uptr->pos) msgxs0 = msgxs0 | XS0_MOT; /* if tape moves */ + uptr->pos = 0; ts_endcmd (TC0, XS0_BOT, MSG_ACK | MSG_CEND); break; } break; @@ -804,13 +841,11 @@ case FNC_POS: st0 = ts_skipr (uptr, cmdadl); break; case 04: /* rewind */ - ts_unit.pos = 0; + if (uptr->pos) msgxs0 = msgxs0 | XS0_MOT; /* if tape moves */ + uptr->pos = 0; break; } ts_cmpendcmd (st0, 0); break; } -if (DBG_LOG (LOG_TS)) - fprintf (sim_log, ">>TS: cmd=%o, mod=%o, buf=%o, lnt=%d, sta=%o, tc=%o, pos=%d\n", - fnc, mod, cmdadl, cmdlnt, msgxs0, GET_TC (tssr), ts_unit.pos); return SCPE_OK; } @@ -875,6 +910,9 @@ if (msg && !(tssr & TSSR_NBA)) { /* send end pkt */ tssr = ts_updtssr (tssr | tc | TSSR_SSR | (tc? TSSR_SC: 0)); if (cmdhdr & CMD_IE) SET_INT (TS); ts_ownm = 0; ts_ownc = 0; +if (DBG_LOG (LOG_TS)) + fprintf (sim_log, ">>TS: sta=%o, tc=%o, rfc=%d, pos=%d\n", + msgxs0, GET_TC (tssr), msgrfc, ts_unit.pos); return; } @@ -939,10 +977,12 @@ return r; /* Boot */ #if defined (VM_PDP11) -#define BOOT_START 01000 -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) +#define BOOT_START 01000 +#define BOOT_CSR0 (BOOT_START + 006) +#define BOOT_CSR1 (BOOT_START + 012) +#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) -static const int32 boot_rom[] = { +static const uint16 boot_rom[] = { 0012706, 0001000, /* mov #boot_start, sp */ 0012700, 0172520, /* mov #tsba, r0 */ 0012701, 0172522, /* mov #tssr, r1 */ @@ -980,7 +1020,7 @@ static const int32 boot_rom[] = { /* msg: .blk 4 */ }; -t_stat ts_boot (int32 unitno) +t_stat ts_boot (int32 unitno, DEVICE *dptr) { int32 i; extern int32 saved_PC; @@ -988,13 +1028,15 @@ extern int32 saved_PC; ts_unit.pos = 0; for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i]; +M[BOOT_CSR0 >> 1] = ts_dib.ba & DMASK; +M[BOOT_CSR1 >> 1] = (ts_dib.ba & DMASK) + 02; saved_PC = BOOT_START; return SCPE_OK; } #else -t_stat ts_boot (int32 unitno) +t_stat ts_boot (int32 unitno, DEVICE *dptr) { return SCPE_NOFNC; } -#endif \ No newline at end of file +#endif diff --git a/dec_uqssp.h b/PDP11/pdp11_uqssp.h similarity index 92% rename from dec_uqssp.h rename to PDP11/pdp11_uqssp.h index 96b6d08a..4f31eb1c 100644 --- a/dec_uqssp.h +++ b/PDP11/pdp11_uqssp.h @@ -1,4 +1,4 @@ -/* dec_uqssp.h: Unibus/Qbus storage systems port definitions file +/* pdp11_uqssp.h: Unibus/Qbus storage systems port definitions file Copyright (c) 2001-2002, Robert M Supnik Derived from work by Stephen F. Shirron @@ -23,8 +23,13 @@ Except as contained in this notice, the name of Robert M Supnik shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + + 30-Aug-02 RMS Added TMSCP support */ +#ifndef _PDP11_UQSSP_H_ +#define _PDP11_UQSSP_H_ 0 + /* IP register - initialization and polling read - controller polls command queue @@ -129,7 +134,7 @@ /* Command/response rings */ struct uq_ring { - const int32 ioff; /* intr offset */ + int32 ioff; /* intr offset */ t_addr ba; /* base addr */ uint32 lnt; /* size in bytes */ uint32 idx; /* current index */ @@ -156,7 +161,9 @@ struct uq_ring { #define UQ_TYP_DAT 1 /* datagram */ #define UQ_HCTC_V_CID 8 /* conn ID */ #define UQ_HCTC_M_CID 0xFF -#define UQ_CID_MSCP 0 /* standard */ +#define UQ_CID_MSCP 0 /* MSCP */ +#define UQ_CID_TMSCP 1 /* TMSCP */ #define UQ_CID_DUP 2 /* DUP */ #define UQ_CID_DIAG 0xFF /* diagnostic */ +#endif diff --git a/PDP11/pdp11_xq.c b/PDP11/pdp11_xq.c new file mode 100644 index 00000000..7976f9b1 --- /dev/null +++ b/PDP11/pdp11_xq.c @@ -0,0 +1,1376 @@ +/* pdp11_xq.c: DEQNA/DELQA ethernet controller simulator + ------------------------------------------------------------------------------ + + Copyright (c) 2002, David T. Hittner + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + ------------------------------------------------------------------------------ + + This DELQA/DEQNA simulation is based on: + Digital DELQA Users Guide, Part# EK-DELQA-UG-002 + Digital DEQNA Users Guide, Part# EK-DEQNA-UG-001 + + Certain adaptations have been made because this is an emulation: + The default MAC address is 08-00-2B-AA-BB-CC unless set otherwise. + Ethernet transceiver power flag CSR<12> is ON when attached. + External Loopback does not go out to the physical adapter, it is + implemented more like an extended Internal Loopback + Time Domain Reflectometry (TDR) numbers are faked + The 10-second approx. hardware/software reset delay does not exist + Some physical ethernet receive events like Runts, Overruns, etc. are never + reported back, since the packet-level driver never sees them + + Certain advantages are derived from this emulation: + If the real ethernet controller is faster than 10Mbit, the speed is + passed on since there are no minimum response times. + + ------------------------------------------------------------------------------ + + Modification history: + + 31-Oct-02 DTH Cleaned up pointer warnings (found by Federico Schwindt) + Corrected unattached and no network behavior + Added message when SHOW XQ ETH finds no devices + 23-Oct-02 DTH Beta 5 released + 22-Oct-02 DTH Added all_multicast and promiscuous support + 21-Oct-02 DTH Added write buffer max size check (code by Jason Thorpe) + Corrected copyright again + Implemented NXM testing and recovery + 16-Oct-02 DTH Beta 4 released + Added and debugged Sanity Timer code + Corrected copyright + 15-Oct-02 DTH Rollback to known good Beta3 and roll forward; TCP broken + 12-Oct-02 DTH Fixed VAX network bootstrap; setup packets must return non-zero TDR + 11-Oct-02 DTH Added SET/SHOW XQ TYPE and SET/SHOW XQ SANITY commands + 10-Oct-02 DTH Beta 3 released; Integrated with 2.10-0b1 + Fixed off-by-1 bug on xq.setup.macs[7..13] + Added make_checksum + Added rejection of multicast addresses in SET XQ MAC + 08-Oct-02 DTH Beta 2 released; Integrated with 2.10-0p4 + Added variable vector (fixes PDP11) and copyrights + 03-Oct-02 DTH Beta version of xq/sim_ether released for SIMH 2.09-11 + 24-Sep-02 DTH Moved more code to Sim_Ether module, added SHOW ETH command + 23-Sep-02 DTH Added SET/SHOW MAC command + 22-Sep-02 DTH Multinet TCP/IP loaded, tests OK via SET HOST/TELNET + 20-Sep-02 DTH Cleaned up code fragments, fixed non-DECNET MAC use + 19-Sep-02 DTH DECNET finally stays up; successful SET HOST to another node + 15-Sep-02 DTH Added ethernet packet read/write + 13-Sep-02 DTH DECNET starts, but circuit keeps going up & down + 26-Aug-02 DTH DECNET loaded, returns device timeout + 22-Aug-02 DTH VMS 7.2 recognizes device as XQA0 + 18-Aug-02 DTH VAX sees device as XQA0; shows hardcoded MAC correctly + 15-Aug-02 DTH Started XQ simulation + + ------------------------------------------------------------------------------ + + Known Bugs or Unsupported features: + + 1) DEQNA and DEQNA-LOCK modes not implemented fully + 2) Sanity Timer not implemented [done! 16-Oct-02] + 3) MOP functionality not implemented + 4) Multicast support is weak [done! 22-Oct-02] + 5) Promiscuous mode not implemented [done! 22-Oct-02] + 6) Cannot VMScluster node + 7) Cannot bootstrap module on VAX (>>> B XQA0) + 8) PDP11 bootstrap code missing + 9) Automatic ID broadcast every 8-10 minutes + 10) External loopback packet processing + 11) NXM detection/protection [done! 21-Oct-02] + + ------------------------------------------------------------------------------ +*/ + +/* compiler directives to help the Author keep the code clean :-) */ +#if defined (__BORLANDC__) && defined (XQ_DEBUG) +#pragma warn +8070 /* function should return value */ +/* #pragma warn +8071 */ /* conversion may lose significant digits */ +#pragma warn +8075 /* suspicious pointer conversion */ +#pragma warn +8079 /* mixing different char pointers */ +#pragma warn +8080 /* variable declared but not used */ +#endif /* __BORLANDC__ && XQ_DEBUG */ + +#include +#include "pdp11_xq.h" + +extern int32 int_req[IPL_HLVL]; +extern int32 tmr_poll, clk_tps; + +struct xq_device xq = { + 100, /* rtime */ + {0x08, 0x00, 0x2B, 0xAA, 0xBB, 0xCC}, /* mac */ + XQ_T_DELQA, /* type */ + {0} /* sanity */ + }; + + +/* forward declarations */ +t_stat xq_rd(int32* data, int32 PA, int32 access); +t_stat xq_wr(int32 data, int32 PA, int32 access); +t_stat xq_svc(UNIT * uptr); +t_stat xq_sansvc(UNIT * uptr); +t_stat xq_reset (DEVICE * dptr); +t_stat xq_attach (UNIT * uptr, char * cptr); +t_stat xq_detach (UNIT * uptr); +t_stat xq_showmac (FILE* st, UNIT* uptr, int32 val, void* desc); +t_stat xq_setmac (UNIT* uptr, int32 val, char* cptr, void* desc); +t_stat xq_show_type (FILE* st, UNIT* uptr, int32 val, void* desc); +t_stat xq_set_type (UNIT* uptr, int32 val, char* cptr, void* desc); +t_stat xq_show_sanity (FILE* st, UNIT* uptr, int32 val, void* desc); +t_stat xq_set_sanity (UNIT* uptr, int32 val, char* cptr, void* desc); +t_stat xq_showeth (FILE* st, UNIT* uptr, int32 val, void* desc); +t_stat xq_process_xbdl(void); +t_stat xq_dispatch_xbdl(void); +void xq_start_receiver(void); +void xq_sw_reset(void); +int32 xq_inta (void); +t_stat xq_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); +t_stat xq_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); +void xq_start_santmr(void); +void xq_cancel_santmr(void); +void xq_reset_santmr(void); + + +/* SIMH device structures */ +DIB xq_dib = { IOBA_XQ, IOLN_XQ, &xq_rd, &xq_wr, + 1, IVCL (XQ), 0, { &xq_inta } }; + +UNIT xq_unit[] = { + { UDATA (&xq_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, + { UDATA (&xq_sansvc, UNIT_DIS, 0) } /* sanity timer */ +}; + +REG xq_reg[] = { + { GRDATA ( SA0, xq.addr[0], XQ_RDX, 16, 0), REG_RO}, + { GRDATA ( SA1, xq.addr[1], XQ_RDX, 16, 0), REG_RO}, + { GRDATA ( SA2, xq.addr[2], XQ_RDX, 16, 0), REG_RO}, + { GRDATA ( SA3, xq.addr[3], XQ_RDX, 16, 0), REG_RO}, + { GRDATA ( SA4, xq.addr[4], XQ_RDX, 16, 0), REG_RO}, + { GRDATA ( SA5, xq.addr[5], XQ_RDX, 16, 0), REG_RO}, + { GRDATA ( RBDL, xq.rbdl, XQ_RDX, 32, 0) }, + { GRDATA ( XBDL, xq.xbdl, XQ_RDX, 32, 0) }, + { GRDATA ( VAR, xq.var, XQ_RDX, 16, 0) }, + { GRDATA ( CSR, xq.csr, XQ_RDX, 16, 0) }, + { NULL }, +}; + +MTAB xq_mod[] = { +#if defined (VM_PDP11) + { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", + &set_addr, &show_addr, NULL }, +#else + { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL, + NULL, &show_addr, NULL }, +#endif + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, + NULL, &show_vec, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "MAC", "MAC", + &xq_setmac, &xq_showmac, &xq.mac }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "ETH", "ETH", + 0, &xq_showeth, 0 }, + { MTAB_XTD | MTAB_VDV, 0, "TYPE", "TYPE", + &xq_set_type, &xq_show_type, 0 }, + { MTAB_XTD | MTAB_VDV, 0, "SANITY", "SANITY", + &xq_set_sanity, &xq_show_sanity, 0 }, + { 0 }, +}; + +DEVICE xq_dev = { + "XQ", xq_unit, xq_reg, xq_mod, + 2, XQ_RDX, 0, 1, XQ_RDX, 8, + &xq_ex, &xq_dep, &xq_reset, + NULL, &xq_attach, &xq_detach, + &xq_dib, DEV_DISABLE | DEV_QBUS +}; + +#ifdef XQ_DEBUG +const char* const xq_csr_bits[] = { + "RE ", "SR ", "NI ", "BD ", "XL ", "RL ", "IE ", "XI ", + "IL ", "EL ", "SE ", "RR ", "OK ", "CA ", "PE ", "RI" +}; + +/* internal debugging routines */ +void xq_debug_setup(void); +void xq_dump_csr(void); +void xq_dump_var(void); +void xq_csr_changes(uint16 data); +void xq_var_changes(uint16 data); + +/* sanity timer debugging */ +#include +struct timeb start, finish; + +#endif /* XQ_DEBUG */ + +/* +================================================================================ + Queue Management +================================================================================ +*/ + +void xq_clear_queue(struct xq_msg_que* que) +{ + int i; + struct xq_msg_itm* item; + + for (i = 0; i < XQ_QUE_MAX; i++) { + item = &que->item[i]; + item->type = 0; + item->packet.len = 0; + item->status = 0; + } + que->count = que->head = que->tail = que->loss = 0; +} + +void xq_remove_queue(struct xq_msg_que* que) +{ + struct xq_msg_itm* item = &que->item[que->head]; + + if (que->count) { + item->type = 0; + item->packet.len = 0; + item->status = 0; + if (++que->head == XQ_QUE_MAX) + que->head = 0; + que->count--; + } +} + +void xq_insert_queue(struct xq_msg_que* que, int32 type, ETH_PACK packet, int32 status) +{ + struct xq_msg_itm* item; + + /* if queue empty, set pointers to beginning */ + if (!que->count) { + que->head = 0; + que->tail = -1; + } + + /* find new tail of the circular queue */ + if (++que->tail == XQ_QUE_MAX) + que->tail = 0; + if (++que->count > XQ_QUE_MAX) { + que->count = XQ_QUE_MAX; + /* lose oldest packet */ + if (++que->head == XQ_QUE_MAX) + que->head = 0; + que->loss++; + } + + /* set information in (new) tail item */ + item = &que->item[que->tail]; + item->type = type; + item->packet = packet; + item->status = status; +} + +/* +================================================================================ +*/ + + +/* stop simh from reading non-existant unit data stream */ +t_stat xq_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ + return SCPE_NOFNC; +} + +/* stop simh from writing non-existant unit data stream */ +t_stat xq_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ + return SCPE_NOFNC; +} + +t_stat xq_showmac (FILE* st, UNIT* uptr, int32 val, void* desc) +{ + ETH_MAC* mac = (ETH_MAC*) desc; + char buffer[20]; + + if (!desc) return SCPE_IERR; + eth_mac_fmt(mac, buffer); + + fprintf(st, "MAC=%s", buffer); + return SCPE_OK; +} + +void make_checksum(void) +{ + /* checksum calculation routine detailed in vaxboot.zip/xqbtdrivr.mar */ + uint32 checksum = 0; + const uint32 wmask = 0xFFFF; + int i; + + for (i = 0; i < sizeof(ETH_MAC); i += 2) { + checksum <<= 1; + if (checksum > wmask) + checksum -= wmask; + checksum += (xq.mac[i] << 8) | xq.mac[i+1]; + if (checksum > wmask) + checksum -= wmask; + } + if (checksum == wmask) + checksum = 0; + + /* set checksum bytes */ + xq.mac_checksum[0] = checksum & 0xFF; + xq.mac_checksum[1] = checksum >> 8; +} + +t_stat xq_setmac (UNIT* uptr, int32 val, char* cptr, void* desc) +{ + int i, j, len; + short int num; + ETH_MAC newmac = {0,0,0,0,0,0}; + const ETH_MAC zeros = {0,0,0,0,0,0}; + const ETH_MAC ones = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + + if ((!cptr) || (!desc)) return SCPE_IERR; + /* parse new mac and validate */ + len = strlen(cptr); + if (len != 17) return SCPE_ARG; + /* make sure byte separators are OK */ + for (i=2; i */ +#endif + + /* update write status words */ + if (status == 0) { /* success */ + wstatus = Map_WriteW(xq.xbdl_ba + 8, 4, write_success, NOMAP); + } else { /* failure */ + wstatus = Map_WriteW(xq.xbdl_ba + 8, 4, write_failure, NOMAP); + } + if (wstatus) { + xq_nxm_error(); + return; + } + + /* update csr */ + xq.csr |= XQ_CSR_XI; + if (xq.csr & XQ_CSR_IE) + SET_INT(XQ); + + /* reset sanity timer */ + xq_reset_santmr(); + + /* clear write buffer */ + xq.write_buffer.len = 0; + + /* next descriptor (implicit) */ + xq.xbdl_ba += 12; + + /* finish processing xbdl */ + rstatus = xq_process_xbdl(); +} + +/* read registers: */ + +t_stat xq_rd(int32* data, int32 PA, int32 access) +{ + int index = (PA >> 1) & 07; /* word index */ + + switch (index) { + case 0: + case 1: + /* return checksum in external loopback mode */ + if (xq.csr & XQ_CSR_EL) + *data = 0xFF00 | xq.mac_checksum[index]; + else + *data = 0xFF00 | xq.mac[index]; + break; + case 2: + case 3: + case 4: + case 5: + *data = 0xFF00 | xq.mac[index]; + break; + case 6: +#if 0 +#ifdef XQ_DEBUG + xq_dump_var(); +#endif +#endif + *data = xq.var; + break; + case 7: +#ifdef XQ_DEBUG + xq_dump_csr(); +#endif + *data = xq.csr; + break; + } + return SCPE_OK; +} + + +/* dispatch ethernet read request + procedure documented in sec. 3.2.2 */ + +t_stat xq_process_rbdl(void) +{ + int32 rstatus, wstatus; + uint16 b_length, w_length, rbl; + t_addr address; + struct xq_msg_itm* item; + +#ifdef XQ_DEBUG + printf("CSR: Processing read\n"); +#endif + /* process buffer descriptors */ + while(1) { + + /* get receive bdl from memory */ + xq.rbdl_buf[0] = 0xFFFF; + wstatus = Map_WriteW(xq.rbdl_ba, 2, &xq.rbdl_buf[0], NOMAP); + rstatus = Map_ReadW (xq.rbdl_ba + 2, 6, &xq.rbdl_buf[1], NOMAP); + if (rstatus || wstatus) return xq_nxm_error(); + + /* invalid buffer? */ + if (~xq.rbdl_buf[1] & XQ_DSC_V) { + xq.csr |= XQ_CSR_RL; + if (xq.csr & XQ_CSR_IE) + SET_INT(XQ); + return SCPE_OK; + } + + /* explicit chain buffer? */ + if (xq.rbdl_buf[1] & XQ_DSC_C) { + xq.rbdl_ba = ((xq.rbdl_buf[1] & 0x3F) << 16) | xq.rbdl_buf[2]; + continue; + } + + /* stop processing if nothing in read queue */ + if (!xq.ReadQ.count) break; + + /* get status words */ + rstatus = Map_ReadW(xq.rbdl_ba + 8, 4, &xq.rbdl_buf[4], NOMAP); + if (rstatus) return xq_nxm_error(); + + /* get host memory address */ + address = ((xq.rbdl_buf[1] & 0x3F) << 16) | xq.rbdl_buf[2]; + + /* decode buffer length - two's complement (in words) */ + w_length = ~xq.rbdl_buf[3] + 1; + b_length = w_length * 2; + if (xq.rbdl_buf[1] & XQ_DSC_H) b_length -= 1; + if (xq.rbdl_buf[1] & XQ_DSC_L) b_length -= 1; + + item = &xq.ReadQ.item[xq.ReadQ.head]; + rbl = item->packet.len; + + /* make sure entire packet fits in buffer */ + assert(rbl <= b_length); + + /* send data to host */ + wstatus = Map_WriteB(address, item->packet.len, item->packet.msg, NOMAP); + if (wstatus) return xq_nxm_error(); + + /* set receive size into RBL - RBL<10:8> maps into Status1<10:8>, + RBL<7:0> maps into Status2<7:0>, and Status2<15:8> (copy) */ + + xq.rbdl_buf[4] = 0; + switch (item->type) { + case 0: /* setup packet */ + xq.rbdl_buf[4] = 0x2700; /* set esetup and RBL 10:8 */ + break; + case 1: /* loopback packet */ + xq.rbdl_buf[4] = 0x2000; /* loopback flag */ + xq.rbdl_buf[4] |= (rbl & 0x0700); /* high bits of rbl */ + break; + case 2: /* normal packet */ + rbl -= 60; /* keeps max packet size in 11 bits */ + xq.rbdl_buf[4] = (rbl & 0x0700); /* high bits of rbl */ + break; + } + xq.rbdl_buf[5] = ((rbl & 0x00FF) << 8) | (rbl & 0x00FF); + if (xq.ReadQ.loss) { + xq.rbdl_buf[4] |= 0x0001; /* set overflow bit */ + xq.ReadQ.loss = 0; /* reset loss counter */ + } + + /* update read status words*/ + wstatus = Map_WriteW(xq.rbdl_ba + 8, 4, &xq.rbdl_buf[4], NOMAP); + if (wstatus) return xq_nxm_error(); + + /* remove packet from queue */ + xq_remove_queue(&xq.ReadQ); + + /* reset sanity timer */ + xq_reset_santmr(); + + /* mark transmission complete */ + xq.csr |= XQ_CSR_RI; + if (xq.csr & XQ_CSR_IE) + SET_INT(XQ); + + /* set to next bdl (implicit chain) */ + xq.rbdl_ba += 12; + + } /* while */ + + return SCPE_OK; +} + +t_stat xq_process_mop(void) +{ + t_addr address; + uint16 size; + int32 wstatus; + struct xq_meb* meb = (struct xq_meb*) &xq.write_buffer.msg[0200]; + const struct xq_meb* limit = (struct xq_meb*) &xq.write_buffer.msg[0400]; + + if (xq.type == XQ_T_DEQNA) /* DEQNA's don't MOP */ + return SCPE_NOFNC; + + while ((meb->type != 0) && (meb < limit)) { + address = (meb->add_hi << 16) || (meb->add_mi << 8) || meb->add_lo; + size = (meb->siz_hi << 8) || meb->siz_lo; + + /* MOP stuff here - NOT YET FULLY IMPLEMENTED */ + +#ifdef XQ_DEBUG + printf("Processing MEB type: %d\n", meb->type); +#endif + switch (meb->type) { + case 0: /* MOP Termination */ + break; + case 1: /* MOP Read Ethernet Address */ + wstatus = Map_WriteB(address, sizeof(ETH_MAC), (uint8*) &xq.setup.macs[0], NOMAP); + if (wstatus) return xq_nxm_error(); + break; + case 2: /* MOP Reset System ID */ + break; + case 3: /* MOP Read Last MOP Boot */ + break; + case 4: /* MOP Read Boot Password */ + break; + case 5: /* MOP Write Boot Password */ + break; + case 6: /* MOP Read System ID */ + break; + case 7: /* MOP Write System ID */ + break; + case 8: /* MOP Read Counters */ + break; + case 9: /* Mop Read/Clear Counters */ + break; + } /* switch */ + + /* process next meb */ + meb += sizeof(struct xq_meb); + + } /* while */ + return SCPE_OK; +} + +t_stat xq_process_setup(void) +{ + int i,j; + int count = 0; + float secs; + t_stat status; + ETH_MAC zeros = {0, 0, 0, 0, 0, 0}; + ETH_MAC filters[XQ_FILTER_MAX + 1]; + + /* extract filter addresses from setup packet */ + for (i = 0; i < 7; i++) + for (j = 0; j < 6; j++) { + xq.setup.macs[i] [j] = xq.write_buffer.msg[(i + 01) + (j * 8)]; + if (xq.write_buffer.len > 112) + xq.setup.macs[i+7][j] = xq.write_buffer.msg[(i + 0101) + (j * 8)]; + } + + /* process high byte count */ + if (xq.write_buffer.len > 128) { + uint16 len = xq.write_buffer.len; + uint16 led, san; + + if (len & XQ_SETUP_MC) + xq.setup.multicast = 1; + if (len & XQ_SETUP_PM) + xq.setup.promiscuous = 1; + if (led = (len & XQ_SETUP_LD) >> 2) { + switch (led) { + case 1: xq.setup.l1 = 0; break; + case 2: xq.setup.l2 = 0; break; + case 3: xq.setup.l3 = 0; break; + } /* switch */ + } /* if led */ + /* set sanity timer timeout */ + san = (len & XQ_SETUP_ST) >> 4; + switch(san) { + case 0: secs = 0.25; break; /* 1/4 second */ + case 1: secs = 1; break; /* 1 second */ + case 2: secs = 4; break; /* 4 seconds */ + case 3: secs = 16; break; /* 16 seconds */ + case 4: secs = 1 * 60; break; /* 1 minute */ + case 5: secs = 4 * 60; break; /* 4 minutes */ + case 6: secs = 16 * 60; break; /* 16 minutes */ + case 7: secs = 64 * 60; break; /* 64 minutes */ + } + xq.sanity.quarter_secs = (int) (secs * 4); + + /* if sanity timer enabled, start sanity timer */ + if (xq.csr & XQ_CSR_SE || xq.sanity.enabled) + xq_start_santmr(); + else + xq_cancel_santmr(); + } + + /* set ethernet filter */ + /* memcpy (filters[count++], xq.mac, sizeof(ETH_MAC)); */ + for (i = 0; i < XQ_FILTER_MAX; i++) + if (memcmp(zeros, &xq.setup.macs[i], sizeof(ETH_MAC))) + memcpy (filters[count++], xq.setup.macs[i], sizeof(ETH_MAC)); + status = eth_filter (xq.etherface, count, filters, xq.setup.multicast, xq.setup.promiscuous); + + /* process MOP information */ + if (xq.write_buffer.msg[0]) + status = xq_process_mop(); + +#ifdef XQ_DEBUG + xq_debug_setup(); +#endif + return SCPE_OK; +} + +/* + Dispatch Write Operation + + The DELQA manual does not explicitly state whether or not multiple packets + can be written in one transmit operation, so a maximum of 1 packet is assumed. + +*/ +t_stat xq_process_xbdl() +{ + const uint16 implicit_chain_status[2] = {XQ_DSC_L | XQ_DSC_C, 0}; + const uint16 write_success[2] = {0, 1 /*Non-Zero TDR*/}; + + uint16 b_length, w_length; + int32 rstatus, wstatus; + t_addr address; + t_stat status; + +#ifdef XQ_DEBUG + printf("CSR: Processing write\n"); +#endif + /* clear write buffer */ + xq.write_buffer.len = 0; + + /* process buffer descriptors until not valid */ + while (1) { + + /* Get transmit bdl from memory */ + xq.xbdl_buf[0] = 0xFFFF; + wstatus = Map_WriteW(xq.xbdl_ba, 2, &xq.xbdl_buf[0], NOMAP); + rstatus = Map_ReadW (xq.xbdl_ba + 2, 6, &xq.xbdl_buf[1], NOMAP); + if (rstatus || wstatus) return xq_nxm_error(); + + /* invalid buffer? */ + if (~xq.xbdl_buf[1] & XQ_DSC_V) { + xq.csr |= XQ_CSR_XL; + if (xq.csr & XQ_CSR_IE) + SET_INT(XQ); + return SCPE_OK; + } + + /* explicit chain buffer? */ + if (xq.xbdl_buf[1] & XQ_DSC_C) { + xq.xbdl_ba = ((xq.xbdl_buf[1] & 0x3F) << 16) | xq.xbdl_buf[2]; + continue; + } + + /* get status words */ + rstatus = Map_ReadW(xq.xbdl_ba + 8, 4, &xq.xbdl_buf[4], NOMAP); + if (rstatus) return xq_nxm_error(); + + /* get host memory address */ + address = ((xq.xbdl_buf[1] & 0x3F) << 16) | xq.xbdl_buf[2]; + + /* decode buffer length - two's complement (in words) */ + w_length = ~xq.xbdl_buf[3] + 1; + b_length = w_length * 2; + if (xq.xbdl_buf[1] & XQ_DSC_H) b_length -= 1; + if (xq.xbdl_buf[1] & XQ_DSC_L) b_length -= 1; + + /* add to transmit buffer, making sure it's not too big */ + if ((xq.write_buffer.len + b_length) > sizeof(xq.write_buffer.msg)) + b_length = sizeof(xq.write_buffer.msg) - xq.write_buffer.len; + rstatus = Map_ReadB(address, b_length, &xq.write_buffer.msg[xq.write_buffer.len], NOMAP); + if (rstatus) return xq_nxm_error(); + xq.write_buffer.len += b_length; + + /* end of message? */ + if (xq.xbdl_buf[1] & XQ_DSC_E) { + if (((~xq.csr & XQ_CSR_RE) && ((~xq.csr & XQ_CSR_IL) || (xq.csr & XQ_CSR_EL))) || /* loopback */ + (xq.xbdl_buf[1] & XQ_DSC_S)) { /* or setup packet (forces loopback regardless of state) */ + if (xq.xbdl_buf[1] & XQ_DSC_S) { /* setup packet */ + status = xq_process_setup(); + + /* put packet in read buffer */ + xq_insert_queue (&xq.ReadQ, 0, xq.write_buffer, status); + } else { /* loopback */ + /* put packet in read buffer */ + xq_insert_queue (&xq.ReadQ, 1, xq.write_buffer, 0); + } + + /* update write status */ + wstatus = Map_WriteW(xq.xbdl_ba + 8, 4, (uint16*) write_success, NOMAP); + if (wstatus) return xq_nxm_error(); + + /* clear write buffer */ + xq.write_buffer.len = 0; + + /* reset sanity timer */ + xq_reset_santmr(); + + /* mark transmission complete */ + xq.csr |= XQ_CSR_XI; + if (xq.csr & XQ_CSR_IE) + SET_INT(XQ); + + /* now trigger "read" of setup or loopback packet */ + if (~xq.csr & XQ_CSR_RL) + status = xq_process_rbdl(); + + } else { /* not loopback */ + + status = eth_write(xq.etherface, &xq.write_buffer, &xq_write_callback); + if (status != SCPE_OK) /* not implemented or unattached */ + xq_write_callback(1); /* fake failure */ + return SCPE_OK; + + } /* loopback/non-loopback */ + } else { /* not at end-of-message */ + + /* update bdl status words */ + wstatus = Map_WriteW(xq.xbdl_ba + 8, 4, (uint16*) implicit_chain_status, NOMAP); + if(wstatus) return xq_nxm_error(); + } + + /* set to next bdl (implicit chain) */ + xq.xbdl_ba += 12; + + } /* while */ +} + +t_stat xq_dispatch_rbdl(void) +{ + int i; + int32 rstatus, wstatus; + t_stat status; + +#ifdef XQ_DEBUG + printf("CSR: Dispatching read\n"); +#endif + /* mark receive bdl valid */ + xq.csr &= ~XQ_CSR_RL; + + /* init receive bdl buffer */ + for (i=0; i<6; i++) + xq.rbdl_buf[i] = 0; + + /* get address of first receive buffer */ + xq.rbdl_ba = ((xq.rbdl[1] & 0x3F) << 16) | (xq.rbdl[0] & ~01); + + /* get first receive buffer */ + xq.rbdl_buf[0] = 0xFFFF; + wstatus = Map_WriteW(xq.rbdl_ba, 2, &xq.rbdl_buf[0], NOMAP); + rstatus = Map_ReadW (xq.rbdl_ba + 2, 6, &xq.rbdl_buf[1], NOMAP); + if (rstatus || wstatus) return xq_nxm_error(); + + /* is buffer valid? */ + if (~xq.rbdl_buf[1] & XQ_DSC_V) { + xq.csr |= XQ_CSR_RL; + if (xq.csr & XQ_CSR_IE) + SET_INT(XQ); + return SCPE_OK; + } + + /* process any waiting packets in receive queue */ + if (xq.ReadQ.count) + status = xq_process_rbdl(); + + return SCPE_OK; +} + +t_stat xq_dispatch_xbdl() +{ + int i; + t_stat status; +#ifdef XQ_DEBUG + printf("CSR: Dispatching write\n"); +#endif + /* mark transmit bdl valid */ + xq.csr &= ~XQ_CSR_XL; + + /* initialize transmit bdl buffers */ + for (i=0; i<6; i++) + xq.xbdl_buf[i] = 0; + + /* clear transmit buffer */ + xq.write_buffer.len = 0; + + /* get base address of first transmit descriptor */ + xq.xbdl_ba = ((xq.xbdl[1] & 0x3F) << 16) | (xq.xbdl[0] & ~01); + + /* process xbdl */ + status = xq_process_xbdl(); + + return status; +} + +void xq_read_callback(int status) +{ + t_stat rstatus; + + if (xq.csr & XQ_CSR_RE) { /* receiver enabled */ + + /* add packet to read queue */ + xq_insert_queue(&xq.ReadQ, 2, xq.read_buffer, status); + + /* process packet if receive list is valid */ + if (~xq.csr & XQ_CSR_RL) + rstatus = xq_process_rbdl(); + + } +} + +void xq_sw_reset(void) +{ + /* cancel sanity timer */ + xq_cancel_santmr(); + + /* disconnect ethernet reception */ + sim_cancel(&xq_unit[0]); + + /* reset csr bits */ + xq.csr = XQ_CSR_XL | XQ_CSR_RL; + + if (xq.etherface) + xq.csr |= XQ_CSR_OK; + + /* flush read queue */ + xq_clear_queue(&xq.ReadQ); + + /* clear setup info */ + memset (&xq.setup, 0, 6 * XQ_FILTER_MAX); + xq.setup.promiscuous = 0; + +} + +/* write registers: */ + +t_stat xq_wr_var(int32 data) +{ +#ifdef XQ_DEBUG + xq_var_changes(data); +#endif + + switch (xq.type) { + case XQ_T_DEQNA: + xq.var = (data & XQ_VEC_IV); + break; + case XQ_T_DELQA: + xq.var = (xq.var & XQ_VEC_RO) | (data & XQ_VEC_RW); + + /* if switching to DEQNA-LOCK mode clear VAR<14:10> */ + if (~xq.var & XQ_VEC_MS) + xq.var &= ~(XQ_VEC_OS | XQ_VEC_RS | XQ_VEC_ST); + break; + } + + /* set vector of SIMH device */ + if (data & XQ_VEC_IV) + xq_dib.vec = (data & XQ_VEC_IV) + VEC_Q; + else + xq_dib.vec = 0; + + return SCPE_OK; +} + +t_stat xq_wr_csr(int32 data) +{ + uint16 saved_csr = xq.csr; +#ifdef XQ_DEBUG + xq_csr_changes(data); +#endif + + /* reset controller when SR transitions to cleared */ + if (xq.csr & XQ_CSR_SR & ~data) { + xq_sw_reset(); + return SCPE_OK; + } + + /* write the writeable bits */ + xq.csr = (xq.csr & XQ_CSR_RO) | (data & XQ_CSR_RW); + + /* clear write-one-to-clear bits */ + xq.csr &= ~(data & XQ_CSR_W1); + if (data & XQ_CSR_XI) /* clearing XI clears NI too */ + xq.csr &= ~XQ_CSR_NI; + + /* start receiver when RE transitions to set */ + if (~saved_csr & XQ_CSR_RE & data) { + //xq_start_receiver(); + sim_activate(&xq_unit[0], xq.rtime); + } + + return SCPE_OK; +} + +t_stat xq_wr(int32 data, int32 PA, int32 access) +{ + t_stat status; + + switch ((PA >> 1) & 07) { + case 0: /* these should not be written */ + case 1: + break; + case 2: /* receive bdl low bits */ + xq.rbdl[0] = data; + break; + case 3: /* receive bdl high bits */ + xq.rbdl[1] = data; + status = xq_dispatch_rbdl(); /* start receive operation */ + break; + case 4: /* transmit bdl low bits */ + xq.xbdl[0] = data; + break; + case 5: /* transmit bdl high bits */ + xq.xbdl[1] = data; + status = xq_dispatch_xbdl(); /* start transmit operation */ + break; + case 6: /* vector address register */ + status = xq_wr_var(data); + break; + case 7: /* control and status register */ + status = xq_wr_csr(data); + break; + } + return SCPE_OK; +} + + +/* reset device */ +t_stat xq_reset(DEVICE* dptr) +{ + t_stat status; + + /* calculate MAC checksum */ + make_checksum(); + + /* init vector address register */ + switch (xq.type) { + case XQ_T_DEQNA: + xq.var = 0; + break; + case XQ_T_DELQA: + xq.var = XQ_VEC_MS | XQ_VEC_OS; + break; + } + xq_dib.vec = 0; + + /* init control status register */ + xq.csr = XQ_CSR_RL | XQ_CSR_XL; + + /* reset ethernet interface */ + if (xq.etherface) { + status = eth_filter (xq.etherface, 1, &xq.mac, 0, 0); + xq.csr |= XQ_CSR_OK; + } + + /* clear read queue */ + xq_clear_queue(&xq.ReadQ); + + /* start sanity timer if power-on SANITY is set */ + switch (xq.type) { + case XQ_T_DEQNA: + if (xq.sanity.enabled) { + xq.sanity.quarter_secs = 4 * (4 * 60); /* default is 4 minutes */; + xq_start_santmr(); + } + break; + case XQ_T_DELQA: + /* note that the DELQA in NORMAL mode has no power-on SANITY state! */ + break; + }; + + return SCPE_OK; +} + +void xq_start_santmr(void) +{ + /* must be recalculated each time since tmr_poll is a dynamic number */ + const int32 quarter_sec = (clk_tps * tmr_poll) / 4; + +#if 0 +#ifdef XQ_DEBUG + printf("SANITY TIMER: enabled, qsecs: %d, poll:%d\n", xq.sanity.quarter_secs, tmr_poll); +#endif +#endif + if (sim_is_active(&xq_unit[1])) /* cancel timer, just in case */ + sim_cancel(&xq_unit[1]); + xq_reset_santmr(); + sim_activate(&xq_unit[1], quarter_sec); +} + +void xq_cancel_santmr(void) +{ + /* can't cancel hardware switch sanity timer */ + if (sim_is_active(&xq_unit[1]) && !xq.sanity.enabled) { +#if 0 +#ifdef XQ_DEBUG + printf("SANITY TIMER: cancelled, qsecs: %d\n", xq.sanity.quarter_secs); +#endif +#endif + sim_cancel(&xq_unit[1]); + } +} + +void xq_reset_santmr(void) +{ +#if 0 +#ifdef XQ_DEBUG + ftime(&start); + printf("SANITY TIMER: resetting, qsecs: %d\n", xq.sanity.quarter_secs); +#endif +#endif + xq.sanity.countdown = xq.sanity.quarter_secs; +} + +t_stat xq_sansvc(UNIT* uptr) +{ + if (--xq.sanity.countdown) { + /* must be recalculated each time since tmr_poll is a dynamic number */ + const int32 quarter_sec = (clk_tps * tmr_poll) / 4; + + /* haven't hit the end of the countdown timer yet, resubmit */ + sim_activate(&xq_unit[1], quarter_sec); + } else { + /* + If this section is entered, it means that the sanity timer has expired + without being reset, and the controller must reboot the processor. + + The manual says the hardware should force Qbus BDCOK low for + 3.6 microseconds, which will cause the host to reboot. + + Since the SIMH Qbus emulator does not have this functionality, we call + a special STOP_ code, and let the CPU stop dispatch routine decide + what the appropriate cpu-specific behavior should be. + */ +#if 0 +#ifdef XQ_DEBUG + ftime(&finish); + printf("SANITY TIMER: EXPIRED, qsecs: %d, poll: %d, elapsed: %d\n", + xq.sanity.quarter_secs, tmr_poll, finish.time - start.time); +#endif +#endif + return STOP_SANITY; + } + return SCPE_OK; +} + +/* +** service routine - used for ethernet reading loop +*/ +t_stat xq_svc(UNIT* uptr) +{ + t_stat status; + + /* read a packet from the ethernet - processing is via the callback */ + status = eth_read (xq.etherface, &xq.read_buffer, &xq_read_callback); + + /* resubmit if still receive enabled */ + if (xq.csr & XQ_CSR_RE) + sim_activate(&xq_unit[0], xq.rtime); + + return SCPE_OK; +} + + + +/* attach device: */ +t_stat xq_attach(UNIT* uptr, char* cptr) +{ + t_stat status; + char* tptr; + + tptr = malloc(strlen(cptr) + 1); + if (tptr == NULL) return SCPE_MEM; + strcpy(tptr, cptr); + + xq.etherface = malloc(sizeof(ETH_DEV)); + if (!xq.etherface) return SCPE_MEM; + + status = eth_open(xq.etherface, cptr); + if (status != SCPE_OK) { + free(tptr); + free(xq.etherface); + xq.etherface = 0; + return status; + } + uptr->filename = tptr; + uptr->flags |= UNIT_ATT; + + /* turn on transceiver power indicator */ + xq.csr |= XQ_CSR_OK; + + return SCPE_OK; +} + +/* detach device: */ + +t_stat xq_detach(UNIT* uptr) +{ + t_stat status; + + if (uptr->flags & UNIT_ATT) { + status = eth_close (xq.etherface); + free(xq.etherface); + xq.etherface = 0; + free(uptr->filename); + uptr->filename = NULL; + uptr->flags &= ~UNIT_ATT; + } + + /* turn off transceiver power indicator */ + xq.csr &= ~XQ_CSR_OK; + + return SCPE_OK; +} + +int32 xq_inta (void) +{ + return xq_dib.vec; +} + +/*============================================================================== +/ debugging routines +/=============================================================================*/ + +#ifdef XQ_DEBUG +void xq_dump_csr (void) +{ + /* tell user what is changing in register */ + int i; + int mask = 1; + uint16 csr = xq.csr; + char hi[256] = "Set: "; + char lo[256] = "Reset: "; + for (i=0; i<16; i++, mask <<= 1) { + if ((csr & mask)) strcat (hi, xq_csr_bits[i]); + if ((~csr & mask)) strcat (lo, xq_csr_bits[i]); + } + printf ("CSR read: %s %s\n", hi, lo); +} + +void xq_dump_var (void) +{ + /* tell user what is changing in register */ + uint16 var = xq.var; + char hi[256] = "Set: "; + char lo[256] = "Reset: "; + int vec = (var & XQ_VEC_IV) >> 2; + strcat((var & XQ_VEC_MS) ? hi : lo, "MS "); + strcat((var & XQ_VEC_OS) ? hi : lo, "OS "); + strcat((var & XQ_VEC_RS) ? hi : lo, "RS "); + strcat((var & XQ_VEC_S3) ? hi : lo, "S3 "); + strcat((var & XQ_VEC_S2) ? hi : lo, "S2 "); + strcat((var & XQ_VEC_S1) ? hi : lo, "S1 "); + strcat((var & XQ_VEC_RR) ? hi : lo, "RR "); + strcat((var & XQ_VEC_ID) ? hi : lo, "ID "); + printf ("VAR read: %s %s - Vec: %d \n", hi, lo, vec); +} + +void xq_csr_changes (uint16 data) +{ + /* tell user what is changing in register */ + int i; + int mask = 1; + uint16 csr = xq.csr; + char hi[256] = "Setting: "; + char lo[256] = "Resetting: "; + for (i=0; i<16; i++, mask <<= 1) { + if ((csr & mask) && (~data & mask)) strcat (lo, xq_csr_bits[i]); + if ((~csr & mask) && (data & mask)) strcat (hi, xq_csr_bits[i]); + } + /* write-one-to-clear bits*/ + if (data & XQ_CSR_RI) strcat(lo, "RI "); + if (data & XQ_CSR_XI) strcat(lo, "XI "); + printf ("CSR write: %s %s\n", hi, lo); +} + +void xq_var_changes (uint16 data) +{ + /* tell user what is changing in register */ + uint16 vec; + uint16 var = xq.var; + char hi[256] = "Setting: "; + char lo[256] = "Resetting: "; + if (~var & XQ_VEC_MS & data) strcat (hi, "MS "); + if (var & XQ_VEC_MS & ~data) strcat (lo, "MS "); + if (~var & XQ_VEC_OS & data) strcat (hi, "OS "); + if (var & XQ_VEC_OS & ~data) strcat (lo, "OS "); + if (~var & XQ_VEC_RS & data) strcat (hi, "RS "); + if (var & XQ_VEC_RS & ~data) strcat (lo, "RS "); + if (~var & XQ_VEC_ID & data) strcat (hi, "ID "); + if (var & XQ_VEC_ID & ~data) strcat (lo, "ID "); + + if ((var & XQ_VEC_IV) != (data & XQ_VEC_IV)) + vec = (data & XQ_VEC_IV) >> 2; + printf ("VAR write: %s %s - Vec: %d\n", hi, lo, vec); +} + +void xq_debug_setup(void) +{ + int i; + char buffer[20]; + if (xq.write_buffer.msg[0]) + printf ("Setup: MOP info present!\n"); + + for (i = 0; i < XQ_FILTER_MAX; i++) { + eth_mac_fmt(&xq.setup.macs[i], buffer); + printf ("Setup: set addr[%d]: %s\n", i, buffer); + } + + if (xq.write_buffer.len > 128) { + char buffer[20] = {0}; + uint16 len = xq.write_buffer.len; + if (len & XQ_SETUP_MC) strcat(buffer, "MC "); + if (len & XQ_SETUP_PM) strcat(buffer, "PM "); + if (len & XQ_SETUP_LD) strcat(buffer, "LD "); + if (len & XQ_SETUP_ST) strcat(buffer, "ST "); + printf ("Setup: Length [%d] info: %s\n", len, buffer); + } +} +#endif + diff --git a/PDP11/pdp11_xq.h b/PDP11/pdp11_xq.h new file mode 100644 index 00000000..fdc8ad98 --- /dev/null +++ b/PDP11/pdp11_xq.h @@ -0,0 +1,184 @@ +/* pdp11_xq.h: DEQNA/DELQA ethernet controller information + ------------------------------------------------------------------------------ + + Copyright (c) 2002, David T. Hittner + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + ------------------------------------------------------------------------------ + + Modification history: + + 21-Oct-02 DTH Corrected copyright again + 15-Oct-02 DTH Fixed copyright, added sanity timer support + 10-Oct-02 DTH Added more setup fields and bitmasks + 08-Oct-02 DTH Integrated with 2.10-0p4, added variable vector and copyrights + 03-Oct-02 DTH Beta version of xq/sim_ether released for SIMH 2.09-11 + 15-Aug-02 DTH Started XQ simulation + + ------------------------------------------------------------------------------ +*/ + +#ifndef _PDP11_XQ_H +#define _PDP11_XQ_H + +#if defined (USE_INT64) +#include "vax_defs.h" +#define VM_VAX 1 +#define XQ_RDX 16 +#define XQ_WID 32 + +#else +#include "pdp11_defs.h" +#define VM_PDP11 1 +#define XQ_RDX 8 +#define XQ_WID 16 +#endif + + +#include "sim_ether.h" + +/* message queue arrays */ +#define XQ_QUE_MAX 500 +#define XQ_FILTER_MAX 14 + +enum xq_type {XQ_T_DEQNA, XQ_T_DELQA}; + +struct xq_sanity { + int enabled; /* sanity timer enabled ? */ + int quarter_secs; /* sanity timer value in 1/4 seconds */ + int countdown; /* sanity timer countdown in 1/4 seconds */ +}; + +struct xq_msg_itm { + int type; /* receive (0=setup, 1=loopback, 2=normal) */ + ETH_PACK packet; /* packet */ + int32 status; /* message size */ +}; + +struct xq_msg_que { + int count; + int head; + int tail; + struct xq_msg_itm item[XQ_QUE_MAX]; + int loss; +}; + +struct xq_setup { + int promiscuous; /* promiscuous mode enabled */ + int multicast; /* enable all multicast addresses */ + int l1; /* first diagnostic led state */ + int l2; /* second diagnostic led state */ + int l3; /* third diagnostic led state */ + int sanity_timer; /* sanity timer value (encoded) */ + ETH_MAC macs[XQ_FILTER_MAX]; /* MAC addresses to respond to */ +}; + +struct xq_meb { /* MEB block */ + uint8 type; + uint8 add_lo; + uint8 add_mi; + uint8 add_hi; + uint8 siz_lo; + uint8 siz_hi; +}; + +struct xq_device { + /*+ initialized values - DO NOT MOVE */ + int rtime; /* ethernet read timer */ + ETH_MAC mac; /* MAC address */ + enum xq_type type; /* controller type */ + struct xq_sanity sanity; /* sanity timer information */ + /*- initialized values - DO NOT MOVE */ + + /* I/O register storage */ + uint16 addr[6]; + uint16 rbdl[2]; + uint16 xbdl[2]; + uint16 var; + uint16 csr; + + /* buffers, etc. */ + struct xq_setup setup; + uint8 mac_checksum[2]; + uint16 rbdl_buf[6]; + uint16 xbdl_buf[6]; +// ETH_MAC target_address[XQ_MAX_FILTERS]; + t_addr rbdl_ba; + t_addr xbdl_ba; + ETH_DEV* etherface; + int receiving; + ETH_PACK read_buffer; + ETH_PACK write_buffer; + struct xq_msg_que ReadQ; +}; + +#define XQ_CSR_RI 0x8000 /* Receive Interrupt Request (RI) [RO/W1] */ +#define XQ_CSR_PE 0x4000 /* Parity Error in Host Memory (PE) [RO] */ +#define XQ_CSR_CA 0x2000 /* Carrier from Receiver Enabled (CA) [RO] */ +#define XQ_CSR_OK 0x1000 /* Ethernet Transceiver Power (OK) [RO] */ +#define XQ_CSR_RR 0x0800 /* Reserved : Set to Zero (RR) [RO] */ +#define XQ_CSR_SE 0x0400 /* Sanity Timer Enable (SE) [RW] */ +#define XQ_CSR_EL 0x0200 /* External Loopback (EL) [RW] */ +#define XQ_CSR_IL 0x0100 /* Internal Loopback (IL) [RW] */ +#define XQ_CSR_XI 0x0080 /* Transmit Interrupt Request (XI) [RO/W1] */ +#define XQ_CSR_IE 0x0040 /* Interrupt Enable (IE) [RW] */ +#define XQ_CSR_RL 0x0020 /* Receive List Invalid/Empty (RL) [RO] */ +#define XQ_CSR_XL 0x0010 /* Transmit List Invalid/Empty (XL) [RO] */ +#define XQ_CSR_BD 0x0008 /* Boot/Diagnostic ROM Load (BD) [RW] */ +#define XQ_CSR_NI 0x0004 /* NonExistant Memory Timeout (NXM) [RO] */ +#define XQ_CSR_SR 0x0002 /* Software Reset (SR) [RW] */ +#define XQ_CSR_RE 0x0001 /* Receiver Enable (RE) [RW] */ + +/* special access bitmaps */ +#define XQ_CSR_RO 0xF8B4 /* Read-Only bits */ +#define XQ_CSR_RW 0x074B /* Read/Write bits */ +#define XQ_CSR_W1 0x8080 /* Write-one-to-clear bits */ + +#define XQ_VEC_MS 0x8000 /* Mode Select (MO) [RW] */ +#define XQ_VEC_OS 0x4000 /* Option Switch Setting (OS) [RO] */ +#define XQ_VEC_RS 0x2000 /* Request Self-Test (RS) [RW] */ +#define XQ_VEC_S3 0x1000 /* Self-Test Status (S3) [RO] */ +#define XQ_VEC_S2 0x0800 /* Self-Test Status (S2) [RO] */ +#define XQ_VEC_S1 0x0400 /* Self-Test Status (S1) [RO] */ +#define XQ_VEC_ST 0x1C00 /* Self-Test (S1 + S2 + S3) [RO] */ +#define XQ_VEC_IV 0x03FC /* Interrupt Vector (IV) [RW] */ +#define XQ_VEC_RR 0x0002 /* Reserved (RR) [RO] */ +#define XQ_VEC_ID 0x0001 /* Identity Test Bit (ID) [RW] */ + +/* special access bitmaps */ +#define XQ_VEC_RO 0x5C02 /* Read-Only bits */ +#define XQ_VEC_RW 0xA3FD /* Read/Write bits */ + +#define XQ_DSC_V 0x8000 /* Valid bit */ +#define XQ_DSC_C 0x4000 /* Chain bit */ +#define XQ_DSC_E 0x2000 /* End of Message bit [Transmit only] */ +#define XQ_DSC_S 0x1000 /* Setup bit [Transmit only] */ +#define XQ_DSC_L 0x0080 /* Low Byte Termination bit [Transmit only] */ +#define XQ_DSC_H 0x0040 /* High Byte Start bit [Transmit only] */ + +#define XQ_SETUP_MC 0x0001 /* multicast bit */ +#define XQ_SETUP_PM 0x0002 /* promiscuous bit */ +#define XQ_SETUP_LD 0x000C /* led bits */ +#define XQ_SETUP_ST 0x0070 /* sanity timer bits */ + +#endif /* _PDP11_XQ_H */ diff --git a/PDP18B/pdp18b_cpu.c b/PDP18B/pdp18b_cpu.c index a26a2b11..03e582ee 100644 --- a/PDP18B/pdp18b_cpu.c +++ b/PDP18B/pdp18b_cpu.c @@ -25,6 +25,8 @@ cpu PDP-4/7/9/15 central processor + 05-Oct-02 RMS Added DIBs, device number support + 25-Jul-02 RMS Added DECtape support for PDP-4 06-Jan-02 RMS Revised enable/disable support 30-Dec-01 RMS Added old PC queue 30-Nov-01 RMS Added extended SET/SHOW support @@ -242,8 +244,7 @@ 4. Adding I/O devices. Three modules must be modified: pdp18b_defs.h add interrupt request definition - pdp18b_cpu.c add IOT and IORS dispatches - pdp18b_sys.c add pointer to data structures to sim_devices + pdp18b_sys.c add sim_devices table entry */ #include "pdp18b_defs.h" @@ -252,10 +253,10 @@ #define PCQ_MASK (PCQ_SIZE - 1) #define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC #define UNIT_V_NOEAE (UNIT_V_UF) /* EAE absent */ -#define UNIT_NOEAE (1 << UNIT_V_NOEAE) #define UNIT_V_NOAPI (UNIT_V_UF+1) /* API absent */ -#define UNIT_NOAPI (1 << UNIT_V_NOAPI) #define UNIT_V_MSIZE (UNIT_V_UF+2) /* dummy mask */ +#define UNIT_NOEAE (1 << UNIT_V_NOEAE) +#define UNIT_NOAPI (1 << UNIT_V_NOAPI) #define UNIT_MSIZE (1 << UNIT_V_MSIZE) #if defined (PDP4) @@ -309,10 +310,14 @@ int16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ #endif int32 pcq_p = 0; /* PC queue ptr */ REG *pcq_r = NULL; /* PC queue reg ptr */ -int32 dev_enb = -1; /* device enables */ -extern int32 sim_int_char; -extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern int32 sim_int_char; +extern int32 sim_interval; +extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern DEVICE *sim_devices[]; +extern FILE *sim_log; + +t_bool build_dev_tab (void); t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); @@ -320,6 +325,12 @@ t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); int32 upd_iors (void); int32 api_eval (int32 *pend); +extern clk (int32 pulse, int32 AC); + +int32 (*dev_tab[DEV_MAX])(int32 pulse, int32 AC); /* device dispatch */ + +int32 (*dev_iors[DEV_MAX])(void); /* IORS dispatch */ + static const int32 api_ffo[256] = { 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, @@ -412,11 +423,8 @@ REG cpu_reg[] = { { BRDATA (PCQ, pcq, 8, ADDRSIZE, PCQ_SIZE), REG_RO+REG_CIRC }, { ORDATA (PCQP, pcq_p, 6), REG_HRO }, { FLDATA (STOP_INST, stop_inst, 0) }, - { FLDATA (NOEAE, cpu_unit.flags, UNIT_V_NOEAE), REG_HRO }, - { FLDATA (NOAPI, cpu_unit.flags, UNIT_V_NOAPI), REG_HRO }, { DRDATA (XCT_MAX, xct_max, 8), PV_LEFT + REG_NZ }, { ORDATA (WRU, sim_int_char, 8) }, - { ORDATA (DEVENB, dev_enb, 32), REG_HRO }, { NULL } }; MTAB cpu_mod[] = { @@ -457,49 +465,17 @@ DEVICE cpu_dev = { t_stat sim_instr (void) { -extern int32 sim_interval; int32 PC, LAC, MQ; int32 api_int, api_cycle, skp; int32 iot_data, device, pulse; t_stat reason; extern UNIT clk_unit; -extern int32 tti (int32 pulse, int32 AC); -extern int32 tto (int32 pulse, int32 AC); -extern int32 ptr (int32 pulse, int32 AC); -extern int32 ptp (int32 pulse, int32 AC); -extern int32 clk (int32 pulse, int32 AC); -extern int32 lpt65 (int32 pulse, int32 AC); -extern int32 lpt66 (int32 pulse, int32 AC); -#if defined (DRM) -extern int32 drm60 (int32 pulse, int32 AC); -extern int32 drm61 (int32 pulse, int32 AC); -extern int32 drm62 (int32 pulse, int32 AC); -#endif -#if defined (RF) -extern int32 rf70 (int32 pulse, int32 AC); -extern int32 rf72 (int32 pulse, int32 AC); -#endif -#if defined (RP) -extern int32 rp63 (int32 pulse, int32 AC); -extern int32 rp64 (int32 pulse, int32 AC); -#endif -#if defined (MTA) -extern int32 mt (int32 pulse, int32 AC); -#endif -#if defined (DTA) -extern int32 dt75 (int32 pulse, int32 AC); -extern int32 dt76 (int32 pulse, int32 AC); -#endif -#if defined (TTY1) -extern int32 tti1 (int32 pulse, int32 AC); -extern int32 tto1 (int32 pulse, int32 AC); -#endif #define JMS_WORD(t) (((LAC & 01000000) >> 1) | ((memm & 1) << 16) | \ (((t) & 1) << 15) | ((PC) & 077777)) #define INCR_ADDR(x) (((x) & epcmask) | (((x) + 1) & damask)) #define SEXT(x) ((int) (((x) & 0400000)? (x) | ~0777777: (x) & 0777777)) - + /* The following macros implement addressing. They account for autoincrement addressing, extended addressing, and memory protection, if it exists. @@ -615,6 +591,7 @@ epcmask = ADDRMASK & ~damask; /* extended PC mask */ #define epcmask (ADDRMASK & ~damask) /* extended PC mask */ #endif +if (build_dev_tab ()) return SCPE_STOP; /* build, chk tables */ PC = saved_PC & ADDRMASK; /* load local copies */ LAC = saved_LAC & 01777777; MQ = saved_MQ & 0777777; @@ -1300,7 +1277,7 @@ case 034: /* IOT */ pulse = IR & 067; /* pulse = IR<12:17> */ if (IR & 0000010) LAC = LAC & 01000000; /* clear AC? */ iot_data = LAC & 0777777; /* AC unchanged */ - + /* PDP-4 system IOT's */ #if defined (PDP4) @@ -1404,87 +1381,10 @@ case 034: /* IOT */ /* IOT, continued */ - case 1: /* PTR */ - iot_data = ptr (pulse, iot_data); - break; - case 2: /* PTP */ - iot_data = ptp (pulse, iot_data); - break; - case 3: /* TTI */ - if (pulse == 004) iot_data = upd_iors (); - else iot_data = tti (pulse, iot_data); - break; - case 4: /* TTO */ - iot_data = tto (pulse, iot_data); - break; -#if defined (TTY1) - case 040: /* TTO1 */ - if (dev_enb & ENB_TTI1) iot_data = tto1 (pulse, iot_data); - else reason = stop_inst; - break; - case 041: /* TTI1 */ - if (dev_enb & ENB_TTI1) iot_data = tti1 (pulse, iot_data); - else reason = stop_inst; - break; -#endif -#if defined (DRM) - case 060: /* drum */ - if (dev_enb & ENB_DRM) iot_data = drm60 (pulse, iot_data); - else reason = stop_inst; - break; - case 061: - if (dev_enb & ENB_DRM) iot_data = drm61 (pulse, iot_data); - else reason = stop_inst; - break; - case 062: - if (dev_enb & ENB_DRM) iot_data = drm62 (pulse, iot_data); - else reason = stop_inst; - break; -#endif -#if defined (RP) - case 063: /* RP15 */ - if (dev_enb & ENB_RP) iot_data = rp63 (pulse, iot_data); - else reason = stop_inst; - break; - case 064: - if (dev_enb & ENB_RP) iot_data = rp64 (pulse, iot_data); - else reason = stop_inst; - break; -#endif - case 065: /* LPT */ - iot_data = lpt65 (pulse, iot_data); - break; - case 066: - iot_data = lpt66 (pulse, iot_data); - break; -#if defined (RF) - case 070: /* RF09 */ - if (dev_enb & ENB_RF) iot_data = rf70 (pulse, iot_data); - else reason = stop_inst; - break; - case 072: - if (dev_enb & ENB_RF) iot_data = rf72 (pulse, iot_data); - else reason = stop_inst; - break; -#endif -#if defined (MTA) - case 073: /* TC59 */ - if (dev_enb & ENB_MTA) iot_data = mt (pulse, iot_data); - else reason = stop_inst; - break; -#endif -#if defined (DTA) - case 075: /* TC02/TC15 */ - if (dev_enb & ENB_DTA) iot_data = dt75 (pulse, iot_data); - else reason = stop_inst; - break; - case 076: - if (dev_enb & ENB_DTA) iot_data = dt76 (pulse, iot_data); - else reason = stop_inst; - break; -#endif - default: /* unknown device */ - reason = stop_inst; /* stop on flag */ + default: /* devices */ + if (dev_tab[device]) /* defined? */ + iot_data = dev_tab[device] (pulse, iot_data); + else reason = stop_inst; /* stop on flag */ break; } /* end switch device */ LAC = LAC | (iot_data & 0777777); if (iot_data & IOT_SKP) PC = INCR_ADDR (PC); @@ -1504,7 +1404,7 @@ saved_PC = PC & ADDRMASK; /* save copies */ saved_LAC = LAC & 01777777; saved_MQ = MQ & 0777777; iors = upd_iors (); /* get IORS */ -pcq_r -> qptr = pcq_p; /* update pc q ptr */ +pcq_r->qptr = pcq_p; /* update pc q ptr */ return reason; } @@ -1530,35 +1430,12 @@ return 0; int32 upd_iors (void) { -extern int32 std_iors (void); -extern int32 lpt_iors (void); -#if defined (DRM) -extern int32 drm_iors (void); -#endif -#if defined (RF) -extern int32 rf_iors (void); -#endif -#if defined (RP) -extern int32 rp_iors (void); -#endif -#if defined (MTA) -extern int32 mt_iors (void); -#endif +int32 d, p; -return (ion? IOS_ION: 0) | -#if defined (DRM) - drm_iors () | -#endif -#if defined (RP) - rp_iors () | -#endif -#if defined (RF) - rf_iors () | -#endif -#if defined (MTA) - mt_iors () | -#endif - std_iors () | lpt_iors (); +d = (ion? IOS_ION: 0); /* ION */ +for (p = 0; dev_iors[p] != NULL; p++) { /* loop thru table */ + d = d | dev_iors[p](); } /* OR in results */ +return d; } /* Reset routine */ @@ -1576,7 +1453,7 @@ memm = memm_init; nexm = prvn = trap_pending = 0; emir_pending = rest_pending = 0; pcq_r = find_reg ("PCQ", NULL, dptr); -if (pcq_r) pcq_r -> qptr = 0; +if (pcq_r) pcq_r->qptr = 0; else return SCPE_IERR; sim_brk_types = sim_brk_dflt = SWMASK ('E'); return SCPE_OK; @@ -1617,38 +1494,89 @@ for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; return SCPE_OK; } -/* Device enable routine */ +/* Change device number for a device */ -t_stat set_enb (UNIT *uptr, int32 val, char *cptr, void *desc) +t_stat set_devno (UNIT *uptr, int32 val, char *cptr, void *desc) { DEVICE *dptr; +DIB *dibp; +uint32 newdev; +t_stat r; -if (cptr != NULL) return SCPE_ARG; -if ((uptr == NULL) || (val == 0)) return SCPE_IERR; +if (cptr == NULL) return SCPE_ARG; +if (uptr == NULL) return SCPE_IERR; dptr = find_dev_from_unit (uptr); if (dptr == NULL) return SCPE_IERR; -dev_enb = dev_enb | val; -if (dptr -> reset) dptr -> reset (dptr); +dibp = (DIB *) dptr->ctxt; +if (dibp == NULL) return SCPE_IERR; +newdev = get_uint (cptr, 8, DEV_MAX - 1, &r); /* get new */ +if ((r != SCPE_OK) || (newdev == dibp->dev)) return r; +dibp->dev = newdev; /* store */ return SCPE_OK; } -/* Device disable routine */ +/* Show device number for a device */ -t_stat set_dsb (UNIT *uptr, int32 val, char *cptr, void *desc) +t_stat show_devno (FILE *st, UNIT *uptr, int32 val, void *desc) { -int32 i; DEVICE *dptr; -UNIT *up; +DIB *dibp; -if (cptr != NULL) return SCPE_ARG; -if ((uptr == NULL) || (val == 0)) return SCPE_IERR; +if (uptr == NULL) return SCPE_IERR; dptr = find_dev_from_unit (uptr); if (dptr == NULL) return SCPE_IERR; -for (i = 0; i < dptr -> numunits; i++) { /* check units */ - up = (dptr -> units) + i; - if ((up -> flags & UNIT_ATT) || sim_is_active (up)) - return SCPE_NOFNC; } -dev_enb = dev_enb & ~val; -if (dptr -> reset) dptr -> reset (dptr); +dibp = (DIB *) dptr->ctxt; +if (dibp == NULL) return SCPE_IERR; +fprintf (st, "devno=%02o", dibp->dev); +if (dibp-> num > 1) fprintf (st, "-%2o", dibp->dev + dibp->num - 1); return SCPE_OK; } + +/* CPU device handler - should never get here! */ + +int32 bad_dev (int32 pulse, int32 AC) +{ +return (SCPE_IERR << IOT_V_REASON) | AC; /* broken! */ +} + +/* Build device dispatch table */ + +t_bool build_dev_tab (void) +{ +DEVICE *dptr; +DIB *dibp; +uint32 i, j, p; +static const uint8 std_dev[] = +#if defined (PDP4) + { 000 }; +#elif defined (PDP7) + { 000, 033, 077 }; +#else + { 000, 017, 033, 055, 077 }; +#endif + +for (i = 0; i < DEV_MAX; i++) { /* clr tables */ + dev_tab[i] = NULL; + dev_iors[i] = NULL; } +for (i = 0; i < ((uint32) sizeof (std_dev)); i++) /* std entries */ + dev_tab[std_dev[i]] = &bad_dev; +for (i = p = 0; (dptr = sim_devices[i]) != NULL; i++) { /* add devices */ + dibp = (DIB *) dptr->ctxt; /* get DIB */ + if (dibp && !(dptr->flags & DEV_DIS)) { /* enabled? */ + if (dibp->iors) dev_iors[p++] = dibp->iors; /* if IORS, add */ + for (j = 0; j < dibp->num; j++) { /* loop thru disp */ + if (dibp->dsp[j]) { /* any dispatch? */ + if (dev_tab[dibp->dev + j]) { /* already filled? */ + printf ("%s device number conflict at %02o\n", + dptr->name, dibp->dev + j); + if (sim_log) fprintf (sim_log, + "%s device number conflict at %02o\n", + dptr->name, dibp->dev + j); + return TRUE; } + dev_tab[dibp->dev + j] = dibp->dsp[j]; /* fill */ + } /* end if dsp */ + } /* end for j */ + } /* end if enb */ + } /* end for i */ +return FALSE; +} diff --git a/PDP18B/pdp18b_defs.h b/PDP18B/pdp18b_defs.h index d4135060..a2ce2d89 100644 --- a/PDP18B/pdp18b_defs.h +++ b/PDP18B/pdp18b_defs.h @@ -23,6 +23,8 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 05-Oct-02 RMS Added DIB structure + 25-Jul-02 RMS Added PDP-4 DECtape support 10-Feb-02 RMS Added PDP-7 DECtape support 25-Nov-01 RMS Revised interrupt structure 27-May-01 RMS Added second Teletype support @@ -48,6 +50,7 @@ Type 75 paper tape punch integral real time clock Type 62 line printer (Hollerith) + Type 550/555 DECtape PDP7 32K Type 177 EAE Type 649 KSR-33 Teletype Type 148 mem extension Type 444 paper tape reader @@ -91,6 +94,7 @@ #define STOP_IBKPT 3 /* breakpoint */ #define STOP_XCT 4 /* nested XCT's */ #define STOP_API 5 /* invalid API int */ +#define STOP_NONSTD 6 /* non-std dev num */ /* Peripheral configuration */ @@ -98,17 +102,18 @@ #define ADDRSIZE 13 #define KSR28 0 /* Baudot terminal */ #define TYPE62 0 /* Hollerith printer */ +#define TYPE550 0 /* DECtape */ #elif defined (PDP7) #define ADDRSIZE 15 #define TYPE647 0 /* sixbit printer */ -#define DTA 0 /* DECtape */ +#define TYPE550 0 /* DECtape */ #define DRM 0 /* drum */ #elif defined (PDP9) #define ADDRSIZE 15 #define TYPE647 0 /* sixbit printer */ #define RF 0 /* fixed head disk */ #define MTA 0 /* magtape */ -#define DTA 0 /* DECtape */ +#define TC02 0 /* DECtape */ #define TTY1 0 /* second Teletype */ #define BRMASK 0076000 /* bounds mask */ #elif defined (PDP15) @@ -117,7 +122,7 @@ #define RF 0 /* fixed head disk */ #define RP 0 /* disk pack */ #define MTA 0 /* magtape */ -#define DTA 0 /* DECtape */ +#define TC02 0 /* DECtape */ #define TTY1 0 /* second Teletype */ #define BRMASK 0377400 /* bounds mask */ #endif @@ -150,6 +155,35 @@ #define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */ +/* Device information block */ + +#define DEV_MAXBLK 8 /* max dev block */ +#define DEV_MAX 64 /* total devices */ + +struct pdp18b_dib { + uint32 dev; /* base dev number */ + uint32 num; /* number of slots */ + int32 (*iors)(void); /* IORS responder */ + int32 (*dsp[DEV_MAXBLK])(int32 IR, int32 dat); +}; + +typedef struct pdp18b_dib DIB; + +/* Standard device numbers */ + +#define DEV_PTR 001 /* paper tape reader */ +#define DEV_PTP 002 /* paper tape punch */ +#define DEV_TTI 003 /* console input */ +#define DEV_TTO 004 /* console output */ +#define DEV_TTI1 041 /* extra terminals */ +#define DEV_TTO1 040 +#define DEV_DRM 060 /* drum */ +#define DEV_RP 063 /* RP15 */ +#define DEV_LPT 065 /* line printer */ +#define DEV_RF 070 /* RF09 */ +#define DEV_MT 073 /* magtape */ +#define DEV_DTA 075 /* dectape */ + /* Interrupt system The interrupt system can be modelled on either the flag driven system @@ -286,22 +320,6 @@ #define SET_INT(dv) int_hwre[API_##dv] = int_hwre[API_##dv] | INT_##dv #define CLR_INT(dv) int_hwre[API_##dv] = int_hwre[API_##dv] & ~INT_##dv #define TST_INT(dv) (int_hwre[API_##dv] & INT_##dv) - -/* Device enable flags are defined in a single 32b word */ - -#define ENB_V_DTA 0 /* DECtape */ -#define ENB_V_MTA 1 /* magtape */ -#define ENB_V_DRM 2 /* drum */ -#define ENB_V_RF 3 /* fixed head disk */ -#define ENB_V_RP 4 /* disk pack */ -#define ENB_V_TTI1 5 /* 2nd teletype */ - -#define ENB_DTA (1u << ENB_V_DTA) -#define ENB_MTA (1u << ENB_V_MTA) -#define ENB_DRM (1u << ENB_V_DRM) -#define ENB_RF (1u << ENB_V_RF) -#define ENB_RP (1u << ENB_V_RP) -#define ENB_TTI1 (1u << ENB_V_TTI1) /* I/O status flags for the IORS instruction @@ -358,5 +376,5 @@ /* Function prototypes */ -t_stat set_enb (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat set_dsb (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat set_devno (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat show_devno (FILE *st, UNIT *uptr, int32 val, void *desc); diff --git a/PDP18B/pdp18b_doc.txt b/PDP18B/pdp18b_doc.txt index a53640d0..9408f7cb 100644 --- a/PDP18B/pdp18b_doc.txt +++ b/PDP18B/pdp18b_doc.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik Subj: 18b PDP Simulator Usage -Date: 15-Jul-2002 +Date: 15-Nov-2002 COPYRIGHT NOTICE @@ -47,11 +47,11 @@ PDP-15/ PDP15 If no model is specified, the default is the PDP-9. sim/ sim_defs.h + sim_rev.h sim_sock.h sim_tmxr.h scp.c scp_tty.c - sim_rev.c sim_sock.c sim_tmxr.c @@ -80,6 +80,7 @@ PDP-4 CPU PDP-4 CPU with 8KW of memory TTI,TTO KSR28 console terminal (Baudot code) LPT Type 62 line printer (Hollerith code) CLK integral real-time clock + DT Type 550/555 DECtape PDP-7 CPU PDP-7 CPU with 32KW of memory - Type 177 extended arithmetic element (EAE) @@ -121,7 +122,16 @@ PDP-15 CPU PDP-15 CPU with 32KW of memory DT TC15/TU56 DECtape MT TC59/TU10 magnetic tape -The DRM, RF, RP, DT, and MT devices can be set DISABLED. +Most devices can be disabled or enabled, by the commands: + + SET DISABLED + SET ENABLED + +The simulator allows most device numbers to be changed, by the command: + + SET DEV= + +However, devices can only be BOOTed with their default device numbers. The 18b PDP simulators implement several unique stop conditions: @@ -134,7 +144,8 @@ The PDP-4 and PDP-7 loaders support only RIM format tapes. The PDP-9 and PDP-15 support both RIM and BIN format tapes. If the file extension is .RIM, or the -r switch is specified with LOAD, the file is assumed to be RIM format; if the file extension is not .RIM, or if the -b switch is -specified, the file is assumed to be BIN format. +specified, the file is assumed to be BIN format. RIM loading requires +that the loading address be specified on the command line. 2.1 CPU @@ -226,7 +237,7 @@ BOOT PTR copies the RIM loader into memory and starts it running, while BOOT -F PTR copies the funny format binary loader into memory and starts it running. -The PTR ATTACH command recognizes one switch, -a for ASCII mode. In +The PTR ATTACH command recognizes one switch, -A for ASCII mode. In ASCII mode, data returned by the read alphabetic command has the high order bit automatically set to 1. This allows normal text files to be used as input to the paper tape reader. @@ -261,7 +272,7 @@ The paper tape punch (PTP) writes data to a disk file. The POS register specifies the number of the next data item to be written. Thus, by changing POS, the user can backspace or advance the punch. -The PTP ATTACH command recognizes one switch, -a for ASCII mode. In +The PTP ATTACH command recognizes one switch, -A for ASCII mode. In ASCII mode, data is punched with the high order bit clear, and NULL and DEL characters are supressed. This allows punch output to be processed with normal text editing utilities. @@ -289,17 +300,20 @@ Error handling is as follows: 2.2.3 Terminal Input (TTI) -The terminal input (TTI) polls the console keyboard for input. The -input side has one option, UC; when set, it automatically converts lower -case input to upper case. +On the PDP-7, PDP-9, and PDP-15, the terminal interfaces (TTI, TTO) +can be set to one of three modes: KSR, 7B, or 8B. In KSR mode, lower +case input and output characters are automatically converted to upper +case, the high order bit is forced to one on input, and printing of +ALTmode characters is supressed. In 7B mode, input and output characters +are masked to 7 bits. In 8B mode, characters are not modified. Changing +the mode of either interface changes both. The default mode is KSR. -The PDP-9 and PDP-15 operate the console terminal (TTI/TTO), by default, -with local echo. For backward compatibility, on the PDP-9 and PDP-15 -the first terminal input has a second option, FDX; when set, it operates -the terminal input without local echo mode. The second terminal does -not offer local echo. +On the PDP-9 and PDP-15, the console terminal operates, by default, +with local echo. For backward compatibility, the terminal input can +be set to FDX (full duplex), which supresses local echo. -The terminal input implements these registers: +The terminal input (TTI) polls the console keyboard for input. It +implements these registers: name size comments @@ -311,11 +325,8 @@ The terminal input implements these registers: 2.2.4 Terminal Output (TTO) -The terminal output (TTO) writes to the simulator console window. The -terminal output has one option, UC; when set, it suppresses lower case -output (so that ALTMODE is not echoed as }). - -The terminal output implements these registers: +The terminal output (TTO) writes to the simulator console window. It +implements these registers: name size comments @@ -331,7 +342,7 @@ The line printer (LPT) writes data to a disk file. The POS register specifies the number of the next data item to be written. Thus, by changing POS, the user can backspace or advance the printer. -The PDP-4 used a Type 62 printer controller, with these registers: +The PDP-4 uses a Type 62 printer controller, with these registers: name size comments @@ -345,7 +356,7 @@ The PDP-4 used a Type 62 printer controller, with these registers: STOP_IOE 1 stop on I/O error LBUF[0:119] 8 line buffer -The PDP-7 and PDP-7 used a Type 647 printer controller, with these +The PDP-7 and PDP-9 use a Type 647 printer controller, with these registers: name size comments @@ -353,7 +364,7 @@ registers: BUF 8 last data item processed INT 1 interrupt pending flag DONE 1 device done flag - ENABLE 1 interrupt enable (PDP-9 only) + ENABLE 1 interrupt enable (PDP-9 only) ERR 1 error flag BPTR 7 print buffer pointer POS 32 position in the output file @@ -361,14 +372,14 @@ registers: STOP_IOE 1 stop on I/O error LBUF[0:119] 8 line buffer -The PDP-15 used an LP15 printer controller, with these registers: +The PDP-15 uses an LP15 printer controller, with these registers: name size comments STA 18 status register MA 18 DMA memory address INT 1 interrupt pending flag - ENABLE 1 interrupt enable + ENABLE 1 interrupt enable LCNT 8 line counter BPTR 7 print buffer pointer POS 32 position in the output file @@ -393,7 +404,7 @@ The real-time clock (CLK) implements these registers: INT 1 interrupt pending flag DONE 1 device done flag - ENABLE 1 clock enable + ENABLE 1 clock enable TIME 24 clock frequency TPS 8 ticks per second (60 or 50) @@ -417,10 +428,13 @@ for a connection on the specified port. It assumes that the incoming connection is a Telnet connection. The connection remain opens until disconnected by the Telnet client, or by a DETACH TTI1 command. -The second terminal input has one option, UC; when set, it automatically -converts lower case input to upper case. The second terminal output also -has one option, UC; when set, it suppresses lower case output (so that -ALTMODE is not echoed as }). +The second terminal (TTI1,TTO1) can be set to one of three modes: KSR, 7B, +or 8B. In KSR mode, lower case input and output characters are converted +automatically to upper case, the high order bit is forced to one on input, +and printing of ALTmode characters is supressed. In 7B mode, input and +output characters are masked to 7 bits. In 8B mode, characters are not +modified. Changing the mode of either device changes both. The default +mode is KSR. The SHOW TTI1 CONNECTIONS command displays the current connection to TTI1. The SHOW TTI1 STATISTICS command displays statistics for the current connection. @@ -537,10 +551,10 @@ I/O errors cannot occur. 2.6 Type 550/555, TC02/TU55, and TC15/TU56 DECtape (DT) -The PDP-7 used the Type 550 DECtape, a programmed I/O controller. The -PDP-9 used the TC02, and the PDP-15 used the TC15. The TC02 and TC15 were -DMA controllers and programmatically identical. PDP-7 DECtape format had -4 18b words in its block headers and trailers; PDP-9/15 DECtape format +The PDP-4 and PDP-7 use the Type 550 DECtape, a programmed I/O controller. +The PDP-9 uses the TC02, and the PDP-15 uses the TC15. The TC02 and TC15 +are DMA controllers and programmatically identical. PDP-4/7 DECtape format +had 4 18b words in its block headers and trailers; PDP-9/15 DECtape format had 5 18b words. DECtapes drives are numbered 1-8; in the simulator, drive 8 is unit 0. @@ -552,12 +566,14 @@ locked. Units can also be set ONLINE or OFFLINE. -The Type 550, TC02, and TC15 support both PDP-8 format and PDP-9/11/15 -format DECtape images. ATTACH tries to determine the tape format from -the DECtape image; the user can force a particular format with switches: +The Type 550, TC02, and TC15 support supports PDP-8 format, PDP-11 format, +and 18b format DECtape images. ATTACH tries to determine the tape +format from the DECtape image; the user can force a particular format +with switches: - -f foreign (PDP-8) format - -n native (PDP-9/11/15) format + -r PDP-8 format + -s PDP-11 format + -t 18b format The DECtape controller is a data-only simulator; the timing and mark track, and block header and trailer, are not stored. Thus, the WRITE @@ -622,12 +638,11 @@ Error handling is as follows: error processed as - not attached tape not ready + not attached tape not ready; if STOP_IOE, stop - end of file (read or space) end of physical tape - (write) ignored + end of file bad tape - OS I/O error report error and stop + OS I/O error parity error; if STOP_IOE, stop 2.8 Symbolic Display and Input diff --git a/PDP18B/pdp18b_drm.c b/PDP18B/pdp18b_drm.c index 08fcddf3..1c338818 100644 --- a/PDP18B/pdp18b_drm.c +++ b/PDP18B/pdp18b_drm.c @@ -26,6 +26,7 @@ drm (PDP-7) Type 24 serial drum (PDP-9) RM09 serial drum + 05-Feb-02 RMS Added DIB, device number support 03-Feb-02 RMS Fixed bug in reset routine (found by Robert Alan Byer) 06-Jan-02 RMS Revised enable/disable support 25-Nov-01 RMS Revised interrupt structure @@ -57,17 +58,24 @@ ((double) DRM_NUMWDT))) extern int32 M[]; -extern int32 int_hwre[API_HLVL+1], dev_enb; +extern int32 int_hwre[API_HLVL+1]; extern UNIT cpu_unit; + int32 drm_da = 0; /* track address */ int32 drm_ma = 0; /* memory address */ int32 drm_err = 0; /* error flag */ int32 drm_wlk = 0; /* write lock */ int32 drm_time = 10; /* inter-word time */ int32 drm_stopioe = 1; /* stop on error */ + +DEVICE drm_dev; +int32 drm60 (int32 pulse, int32 AC); +int32 drm61 (int32 pulse, int32 AC); +int32 drm62 (int32 pulse, int32 AC); +int32 drm_iors (void); t_stat drm_svc (UNIT *uptr); t_stat drm_reset (DEVICE *dptr); -t_stat drm_boot (int32 unitno); +t_stat drm_boot (int32 unitno, DEVICE *dptr); /* DRM data structures @@ -76,9 +84,11 @@ t_stat drm_boot (int32 unitno); drm_reg DRM register list */ +DIB drm_dib = { DEV_DRM, 3 ,&drm_iors, { &drm60, &drm61, &drm62 } }; + UNIT drm_unit = { UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, - DRM_SIZE) }; + DRM_SIZE) }; REG drm_reg[] = { { ORDATA (DA, drm_da, 9) }, @@ -89,19 +99,19 @@ REG drm_reg[] = { { ORDATA (WLK, drm_wlk, 32) }, { DRDATA (TIME, drm_time, 24), REG_NZ + PV_LEFT }, { FLDATA (STOP_IOE, drm_stopioe, 0) }, - { FLDATA (*DEVENB, dev_enb, ENB_V_DRM), REG_HRO }, + { ORDATA (DEVNO, drm_dib.dev, 6), REG_HRO }, { NULL } }; MTAB drm_mod[] = { - { MTAB_XTD|MTAB_VDV, ENB_DRM, NULL, "ENABLED", &set_enb }, - { MTAB_XTD|MTAB_VDV, ENB_DRM, NULL, "DISABLED", &set_dsb }, + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno }, { 0 } }; DEVICE drm_dev = { "DRM", &drm_unit, drm_reg, drm_mod, 1, 8, 20, 1, 8, 18, NULL, NULL, &drm_reset, - &drm_boot, NULL, NULL }; + &drm_boot, NULL, NULL, + &drm_dib, DEV_DISABLE }; /* IOT routines */ @@ -155,20 +165,20 @@ t_stat drm_svc (UNIT *uptr) int32 i; t_addr da; -if ((uptr -> flags & UNIT_BUF) == 0) { /* not buf? abort */ +if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */ drm_err = 1; /* set error */ SET_INT (DRM); /* set done */ return IORETURN (drm_stopioe, SCPE_UNATT); } da = drm_da * DRM_NUMWDS; /* compute dev addr */ for (i = 0; i < DRM_NUMWDS; i++, da++) { /* do transfer */ - if (uptr -> FUNC == DRM_READ) { + if (uptr->FUNC == DRM_READ) { if (MEM_ADDR_OK (drm_ma)) /* read, check nxm */ - M[drm_ma] = *(((int32 *) uptr -> filebuf) + da); } + M[drm_ma] = *(((int32 *) uptr->filebuf) + da); } else { if ((drm_wlk >> (drm_da >> 4)) & 1) drm_err = 1; - else { *(((int32 *) uptr -> filebuf) + da) = M[drm_ma]; - if (da >= uptr -> hwmark) - uptr -> hwmark = da + 1; } } + else { *(((int32 *) uptr->filebuf) + da) = M[drm_ma]; + if (da >= uptr->hwmark) + uptr->hwmark = da + 1; } } drm_ma = (drm_ma + 1) & ADDRMASK; } /* incr mem addr */ drm_da = (drm_da + 1) & DRM_SMASK; /* incr dev addr */ SET_INT (DRM); /* set done */ @@ -202,15 +212,16 @@ static const int32 boot_rom[] = { 0706006, /* DRLR ; load ma */ 0706106, /* DRSS ; load da, start */ 0706101, /* DRSF ; wait for done */ - 0602003, /* JMP .-1 + 0602003, /* JMP .-1 */ 0600000 /* JMP 0 ; enter boot */ }; -t_stat drm_boot (int32 unitno) +t_stat drm_boot (int32 unitno, DEVICE *dptr) { int32 i; extern int32 saved_PC; +if (drm_dib.dev != DEV_DRM) return STOP_NONSTD; /* non-std addr? */ for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i]; saved_PC = BOOT_START; return SCPE_OK; diff --git a/PDP18B/pdp18b_dt.c b/PDP18B/pdp18b_dt.c index 6a78dd85..809f1073 100644 --- a/PDP18B/pdp18b_dt.c +++ b/PDP18B/pdp18b_dt.c @@ -1,4 +1,4 @@ -/* pdp18b_dt.c: PDP-7/9/15 DECtape simulator +/* pdp18b_dt.c: 18b DECtape simulator Copyright (c) 1993-2002, Robert M Supnik @@ -23,10 +23,15 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - dt (PDP-7) Type 550/555 DECtape + dt (PDP-4, PDP-7) Type 550/555 DECtape (PDP-9) TC02/TU55 DECtape (PDP-15) TC15/TU56 DECtape + 17-Oct-02 RMS Fixed bug in end of reel logic + 05-Oct-02 RMS Added DIB, device number support + 12-Sep-02 RMS Added 16b format support + 13-Aug-02 RMS Corrected Type 550 unit select logic + 25-Jul-02 RMS Added PDP-4 support 30-May-02 RMS Widened POS to 32b 10-Feb-02 RMS Added PDP-7 support 06-Jan-02 RMS Revised enable/disable support @@ -39,11 +44,14 @@ 26-Apr-01 RMS Added device enable/disable support 15-Mar-01 RMS Added 129th word to PDP-8 format - 18b DECtapes are represented by fixed length data blocks of 18b words. Two - tape formats are supported: + 18b DECtapes are represented in memory by fixed length buffer of 32b words. + Three file formats are supported: - 16b/18b/36b 256 words per block - 12b 86 words per block [129 x 12b] + 18b/36b 256 words per block [256 x 18b] + 16b 256 words per block [256 x 16b] + 12b 129 words per block [129 x 12b] + + When a 16b or 12b DECtape file is read in, it is converted to 18b/36b format. DECtape motion is measured in 3b lines. Time between lines is 33.33us. Tape density is nominally 300 lines per inch. The format of a DECtape is @@ -57,9 +65,9 @@ A block consists of five 18b header words, a tape-specific number of data words, and five 18b trailer words. All systems except the PDP-8 use a standard block length of 256 words; the PDP-8 uses a standard block length - of 86 words (x 18b = 129 words x 12b). [A PDP-7 DECtape has only four 18b - header words; for consistency, the PDP-7 uses the same format as the PDP-9 - and PDP-15 but skips the missing header words.] + of 86 words (x 18b = 129 words x 12b). [A PDP-4/7 DECtape has only four 18b + header words; for consistency, the PDP-4/7 uses the same format as the PDP-9/15 + but skips the missing header words.] Because a DECtape file only contains data, the simulator cannot support write timing and mark track and can only do a limited implementation @@ -78,16 +86,22 @@ Write all writes only the data words and dumps the interblock words in the bit bucket. + + The Type 550 controller has a 4b unit select field, for units 1-8; the TC02 + has a 3b unit select field, with unit 8 being represented as 0. The code + assumes that the GETUNIT macro returns a unit number in the range of 0-7, + with 8 represented as 0, and an invalid unit as -1. */ #include "pdp18b_defs.h" #define DT_NUMDR 8 /* #drives */ #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_WLK (1 << UNIT_V_WLK) #define UNIT_V_8FMT (UNIT_V_UF + 1) /* 12b format */ +#define UNIT_V_11FMT (UNIT_V_UF + 2) /* 16b format */ +#define UNIT_WLK (1 << UNIT_V_WLK) #define UNIT_8FMT (1 << UNIT_V_8FMT) -#define UNIT_W_UF 3 /* saved flag width */ +#define UNIT_11FMT (1 << UNIT_V_11FMT) #define STATE u3 /* unit state */ #define LASTT u4 /* last time update */ #define DT_WC 030 /* word count */ @@ -112,6 +126,7 @@ #define D18_LPERB (DT_HTLIN + (D18_BSIZE * DT_WSIZE) + DT_HTLIN) #define D18_FWDEZ (DT_EZLIN + (D18_LPERB * D18_TSIZE)) #define D18_CAPAC (D18_TSIZE * D18_BSIZE) /* tape capacity */ +#define D11_FILSIZ (D18_CAPAC * sizeof (int16)) /* 12b DECtape constants */ @@ -132,23 +147,23 @@ /* Calculated constants, per unit */ -#define DTU_BSIZE(u) (((u) -> flags & UNIT_8FMT)? D8_BSIZE: D18_BSIZE) -#define DTU_TSIZE(u) (((u) -> flags & UNIT_8FMT)? D8_TSIZE: D18_TSIZE) -#define DTU_LPERB(u) (((u) -> flags & UNIT_8FMT)? D8_LPERB: D18_LPERB) -#define DTU_FWDEZ(u) (((u) -> flags & UNIT_8FMT)? D8_FWDEZ: D18_FWDEZ) -#define DTU_CAPAC(u) (((u) -> flags & UNIT_8FMT)? D8_CAPAC: D18_CAPAC) +#define DTU_BSIZE(u) (((u)->flags & UNIT_8FMT)? D8_BSIZE: D18_BSIZE) +#define DTU_TSIZE(u) (((u)->flags & UNIT_8FMT)? D8_TSIZE: D18_TSIZE) +#define DTU_LPERB(u) (((u)->flags & UNIT_8FMT)? D8_LPERB: D18_LPERB) +#define DTU_FWDEZ(u) (((u)->flags & UNIT_8FMT)? D8_FWDEZ: D18_FWDEZ) +#define DTU_CAPAC(u) (((u)->flags & UNIT_8FMT)? D8_CAPAC: D18_CAPAC) #define DT_LIN2BL(p,u) (((p) - DT_EZLIN) / DTU_LPERB (u)) #define DT_LIN2OF(p,u) (((p) - DT_EZLIN) % DTU_LPERB (u)) #define DT_LIN2WD(p,u) ((DT_LIN2OF (p,u) - DT_HTLIN) / DT_WSIZE) #define DT_BLK2LN(p,u) (((p) * DTU_LPERB (u)) + DT_EZLIN) -#define DT_QREZ(u) (((u) -> pos) < DT_EZLIN) -#define DT_QFEZ(u) (((u) -> pos) >= ((uint32) DTU_FWDEZ (u))) +#define DT_QREZ(u) (((u)->pos) < DT_EZLIN) +#define DT_QFEZ(u) (((u)->pos) >= ((uint32) DTU_FWDEZ (u))) #define DT_QEZ(u) (DT_QREZ (u) || DT_QFEZ (u)) /* Status register A */ -#if defined (PDP9) || defined (PDP15) /* TC02/TC15 */ +#if defined (TC02) /* TC02/TC15 */ #define DTA_V_UNIT 15 /* unit select */ #define DTA_M_UNIT 07 #define DTA_UNIT (DTA_M_UNIT << DTA_V_UNIT) @@ -174,13 +189,14 @@ #define DTA_CERF (1u << DTA_V_CERF) #define DTA_CDTF (1u << DTA_V_CDTF) #define DTA_RW (0777700 & ~(DTA_CERF | DTA_CDTF)) +#define DTA_GETUNIT(x) (((x) >> DTA_V_UNIT) & DTA_M_UNIT) #define DT_UPDINT if ((dtsa & DTA_ENB) && (dtsb & (DTB_ERF | DTB_DTF))) \ SET_INT (DTA); \ else CLR_INT (DTA); #else /* Type 550 */ #define DTA_V_UNIT 12 /* unit select */ -#define DTA_M_UNIT 07 +#define DTA_M_UNIT 017 #define DTA_UNIT (DTA_M_UNIT << DTA_V_UNIT) #define DTA_V_MOT 4 /* motion */ #define DTA_M_MOT 03 @@ -197,18 +213,18 @@ #define DTA_FWDRV (1u << DTA_V_MOT) #define DTA_MODE 0 /* not implemented */ #define DTA_RW 077 +#define DTA_GETUNIT(x) map_unit[(((x) >> DTA_V_UNIT) & DTA_M_UNIT)] #define DT_UPDINT if (dtsb & (DTB_DTF | DTB_BEF | DTB_ERF)) \ SET_INT (DTA); \ else CLR_INT (DTA); #endif -#define DTA_GETUNIT(x) (((x) >> DTA_V_UNIT) & DTA_M_UNIT) #define DTA_GETMOT(x) (((x) >> DTA_V_MOT) & DTA_M_MOT) #define DTA_GETFNC(x) (((x) >> DTA_V_FNC) & DTA_M_FNC) /* Status register B */ -#if defined (PDP9) || defined (PDP15) /* TC02/TC15 */ +#if defined (TC02) /* TC02/TC15 */ #define DTB_V_ERF 17 /* error flag */ #define DTB_V_MRK 16 /* mark trk err */ #define DTB_V_END 15 /* end zone err */ @@ -268,10 +284,10 @@ #define DTS_V_2ND 6 /* next state */ #define DTS_V_3RD (DTS_V_2ND + DTS_V_2ND) /* next next */ #define DTS_STA(y,z) (((y) << DTS_V_MOT) | ((z) << DTS_V_FNC)) -#define DTS_SETSTA(y,z) uptr -> STATE = DTS_STA (y, z) -#define DTS_SET2ND(y,z) uptr -> STATE = (uptr -> STATE & 077) | \ +#define DTS_SETSTA(y,z) uptr->STATE = DTS_STA (y, z) +#define DTS_SET2ND(y,z) uptr->STATE = (uptr->STATE & 077) | \ ((DTS_STA (y, z)) << DTS_V_2ND) -#define DTS_SET3RD(y,z) uptr -> STATE = (uptr -> STATE & 07777) | \ +#define DTS_SET3RD(y,z) uptr->STATE = (uptr->STATE & 07777) | \ ((DTS_STA (y, z)) << DTS_V_3RD) #define DTS_NXTSTA(x) (x >> DTS_V_2ND) @@ -293,6 +309,8 @@ extern int32 M[]; extern int32 int_hwre[API_HLVL+1], dev_enb; extern UNIT cpu_unit; extern int32 sim_switches; +extern int32 sim_is_running; + int32 dtsa = 0; /* status A */ int32 dtsb = 0; /* status B */ int32 dtdb = 0; /* data buffer */ @@ -302,6 +320,14 @@ int32 dt_dctime = 72000; /* decel time */ int32 dt_substate = 0; int32 dt_log = 0; int32 dt_logblk = 0; +static const int32 map_unit[16] = { /* Type 550 unit map */ + -1, 1, 2, 3, 4, 5, 6, 7, + 0, -1, -1, -1, -1, -1, -1, -1 }; + +DEVICE dt_dev; +int32 dt75 (int32 pulse, int32 AC); +int32 dt76 (int32 pulse, int32 AC); +int32 dt_iors (void); t_stat dt_svc (UNIT *uptr); t_stat dt_reset (DEVICE *dptr); t_stat dt_attach (UNIT *uptr, char *cptr); @@ -315,7 +341,6 @@ void dt_seterr (UNIT *uptr, int32 e); int32 dt_comobv (int32 val); int32 dt_csum (UNIT *uptr, int32 blk); int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos); -extern int32 sim_is_running; /* DT data structures @@ -325,6 +350,8 @@ extern int32 sim_is_running; dt_mod DT modifier list */ +DIB dt_dib = { DEV_DTA, 2, &dt_iors, { &dt75, &dt76 } }; + UNIT dt_unit[] = { { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ UNIT_ROABLE, DT_CAPAC) }, @@ -356,7 +383,7 @@ REG dt_reg[] = { { FLDATA (BEF, dtsb, DTB_V_BEF) }, #endif { FLDATA (ERF, dtsb, DTB_V_ERF) }, -#if defined (PDP9) || defined (PDP15) +#if defined (TC02) /* TC02/TC15 */ { ORDATA (WC, M[DT_WC], 18) }, { ORDATA (CA, M[DT_CA], 18) }, #endif @@ -372,29 +399,28 @@ REG dt_reg[] = { DT_NUMDR, REG_RO) }, { URDATA (LASTT, dt_unit[0].LASTT, 10, 32, 0, DT_NUMDR, REG_HRO) }, - { URDATA (FLG, dt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, - DT_NUMDR, REG_HRO) }, - { FLDATA (*DEVENB, dev_enb, ENB_V_DTA), REG_HRO }, + { ORDATA (DEVNO, dt_dib.dev, 6), REG_HRO }, { NULL } }; MTAB dt_mod[] = { { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, - { UNIT_8FMT, 0, "16b/18b", NULL, NULL }, - { UNIT_8FMT, UNIT_8FMT, "12b", NULL, NULL }, - { MTAB_XTD|MTAB_VDV, ENB_DTA, NULL, "ENABLED", &set_enb }, - { MTAB_XTD|MTAB_VDV, ENB_DTA, NULL, "DISABLED", &set_dsb }, + { UNIT_8FMT + UNIT_11FMT, 0, "18b", NULL, NULL }, + { UNIT_8FMT + UNIT_11FMT, UNIT_8FMT, "12b", NULL, NULL }, + { UNIT_8FMT + UNIT_11FMT, UNIT_11FMT, "16b", NULL, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno }, { 0 } }; DEVICE dt_dev = { "DT", dt_unit, dt_reg, dt_mod, DT_NUMDR, 8, 24, 1, 8, 18, NULL, NULL, &dt_reset, - NULL, &dt_attach, &dt_detach }; + NULL, &dt_attach, &dt_detach, + &dt_dib, DEV_DISABLE }; /* IOT routines */ -#if defined (PDP9) || defined (PDP15) +#if defined (TC02) /* TC02/TC15 */ int32 dt75 (int32 pulse, int32 AC) { int32 old_dtsa = dtsa, fnc; @@ -410,10 +436,10 @@ if (((pulse & 060) == 040) && (pulse & 05)) { /* select */ if ((old_dtsa ^ dtsa) & DTA_UNIT) dt_deselect (old_dtsa); uptr = dt_dev.units + DTA_GETUNIT (dtsa); /* get unit */ fnc = DTA_GETFNC (dtsa); /* get fnc */ - if (((uptr -> flags) & UNIT_DIS) || /* disabled? */ + if (((uptr->flags) & UNIT_DIS) || /* disabled? */ (fnc >= FNC_WMRK) || /* write mark? */ - ((fnc == FNC_WRIT) && (uptr -> flags & UNIT_WPRT)) || - ((fnc == FNC_WALL) && (uptr -> flags & UNIT_WPRT))) + ((fnc == FNC_WRIT) && (uptr->flags & UNIT_WPRT)) || + ((fnc == FNC_WALL) && (uptr->flags & UNIT_WPRT))) dt_seterr (uptr, DTB_SEL); /* select err */ else dt_newsa (dtsa); /* new func */ DT_UPDINT; @@ -434,11 +460,9 @@ if ((pulse & 01) && (dtsb & DTB_DTF)) /* DTDF */ return AC; } -#else +#else /* Type 550 */ int32 dt75 (int32 pulse, int32 AC) { -int32 old_dtsa = dtsa; - if (((pulse & 041) == 001) && (dtsb & DTB_DTF)) /* MMDF */ AC = AC | IOT_SKP; else if (((pulse & 041) == 041) && (dtsb & DTB_ERF)) /* MMEF */ @@ -455,18 +479,20 @@ return AC; int32 dt76 (int32 pulse, int32 AC) { -int32 fnc, mot; -UNIT *uptr; +int32 fnc, mot, unum; +UNIT *uptr = NULL; -uptr = dt_dev.units + DTA_GETUNIT (dtsa); /* get unit */ +unum = DTA_GETUNIT (dtsa); /* get unit no */ +if (unum >= 0) uptr = dt_dev.units + unum; /* get unit */ if ((pulse & 001) && (dtsb & DTB_BEF)) /* MMBF */ AC = AC | IOT_SKP; if (pulse & 002) { /* MMRS */ dtsb = dtsb & ~(DTB_REV | DTB_GO); /* clr rev, go */ - mot = DTS_GETMOT (uptr -> STATE); /* get motion */ - if (mot & DTS_DIR) dtsb = dtsb | DTB_REV; /* rev? set */ - if ((mot >= DTS_ACCF) || (uptr -> STATE & 0777700)) - dtsb = dtsb | DTB_GO; /* accel? go */ + if (uptr) { /* valid unit? */ + mot = DTS_GETMOT (uptr->STATE); /* get motion */ + if (mot & DTS_DIR) dtsb = dtsb | DTB_REV; /* rev? set */ + if ((mot >= DTS_ACCF) || (uptr->STATE & 0777700)) + dtsb = dtsb | DTB_GO; } /* accel? go */ AC = (AC & ~DMASK) | dtsb; } if ((pulse & 044) == 044) { /* MMSE */ if ((dtsa ^ AC) & DTA_UNIT) dt_deselect (dtsa); /* new unit? */ @@ -476,10 +502,11 @@ else if ((pulse & 044) == 004) { /* MMLC */ dtsa = (dtsa & ~DTA_RW) | (AC & DTA_RW); /* load dtsa */ dtsb = dtsb & ~(DTB_DTF | DTB_BEF | DTB_ERF | DTB_ALLERR); fnc = DTA_GETFNC (dtsa); /* get fnc */ - if (((uptr -> flags) & UNIT_DIS) || /* disabled? */ + if ((uptr == NULL) || /* invalid? */ + ((uptr->flags) & UNIT_DIS) || /* disabled? */ (fnc >= FNC_WMRK) || /* write mark? */ - ((fnc == FNC_WRIT) && (uptr -> flags & UNIT_WLK)) || - ((fnc == FNC_WALL) && (uptr -> flags & UNIT_WLK))) + ((fnc == FNC_WRIT) && (uptr->flags & UNIT_WLK)) || + ((fnc == FNC_WALL) && (uptr->flags & UNIT_WLK))) dt_seterr (uptr, DTB_SEL); /* select err */ else dt_newsa (dtsa); } DT_UPDINT; @@ -491,10 +518,13 @@ return AC; void dt_deselect (int32 oldf) { -int32 old_unit = DTA_GETUNIT (oldf); -UNIT *uptr = dt_dev.units + old_unit; -int32 old_mot = DTS_GETMOT (uptr -> STATE); +int32 old_unit, old_mot; +UNIT *uptr; +old_unit = DTA_GETUNIT (oldf); /* get unit no */ +if (old_unit < 0) return; /* invalid? */ +uptr = dt_dev.units + old_unit; /* get unit */ +old_mot = DTS_GETMOT (uptr->STATE); if (old_mot >= DTS_ATSF) /* at speed? */ dt_newfnc (uptr, DTS_STA (old_mot, DTS_OFR)); else if (old_mot >= DTS_ACCF) /* accelerating? */ @@ -525,19 +555,19 @@ return; void dt_newsa (int32 newf) { -int32 new_unit, prev_mot, prev_fnc, new_fnc; +int32 new_unit, prev_mot, new_fnc; int32 prev_mving, new_mving, prev_dir, new_dir; UNIT *uptr; -new_unit = DTA_GETUNIT (newf); /* new, old units */ +new_unit = DTA_GETUNIT (newf); /* new unit */ +if (new_unit < 0) return; /* invalid? */ uptr = dt_dev.units + new_unit; -if ((uptr -> flags & UNIT_ATT) == 0) { /* new unit attached? */ +if ((uptr->flags & UNIT_ATT) == 0) { /* new unit attached? */ dt_seterr (uptr, DTB_SEL); /* no, error */ return; } -prev_mot = DTS_GETMOT (uptr -> STATE); /* previous motion */ +prev_mot = DTS_GETMOT (uptr->STATE); /* previous motion */ prev_mving = prev_mot != DTS_STOP; /* previous moving? */ prev_dir = prev_mot & DTS_DIR; /* previous dir? */ -prev_fnc = DTS_GETFNC (uptr -> STATE); /* prev function? */ new_mving = (newf & DTA_STSTP) != 0; /* new moving? */ new_dir = (newf & DTA_FWDRV) != 0; /* new dir? */ new_fnc = DTA_GETFNC (newf); /* new function? */ @@ -603,15 +633,15 @@ void dt_newfnc (UNIT *uptr, int32 newsta) int32 fnc, dir, blk, unum, relpos, newpos; uint32 oldpos; -oldpos = uptr -> pos; /* save old pos */ +oldpos = uptr->pos; /* save old pos */ if (dt_setpos (uptr)) return; /* update pos */ -uptr -> STATE = newsta; /* update state */ -fnc = DTS_GETFNC (uptr -> STATE); /* set variables */ -dir = DTS_GETMOT (uptr -> STATE) & DTS_DIR; +uptr->STATE = newsta; /* update state */ +fnc = DTS_GETFNC (uptr->STATE); /* set variables */ +dir = DTS_GETMOT (uptr->STATE) & DTS_DIR; unum = uptr - dt_dev.units; -if (oldpos == uptr -> pos) /* bump pos */ - uptr -> pos = uptr -> pos + (dir? -1: 1); -blk = DT_LIN2BL (uptr -> pos, uptr); +if (oldpos == uptr->pos) /* bump pos */ + uptr->pos = uptr->pos + (dir? -1: 1); +blk = DT_LIN2BL (uptr->pos, uptr); if (dir? DT_QREZ (uptr): DT_QFEZ (uptr)) { /* wrong ez? */ dt_seterr (uptr, DTB_END); /* set ez flag, stop */ @@ -638,12 +668,12 @@ case FNC_SRCH: /* search */ break; case FNC_WRIT: /* write */ case FNC_READ: /* read */ -#if defined (PDP9) || defined (PDP15) +#if defined (TC02) /* TC02/TC15 */ if (DT_QEZ (uptr)) { /* in "ok" end zone? */ if (dir) newpos = DTU_FWDEZ (uptr) - DT_HTLIN - DT_WSIZE; else newpos = DT_EZLIN + DT_HTLIN + (DT_WSIZE - 1); break; } - relpos = DT_LIN2OF (uptr -> pos, uptr); /* cur pos in blk */ + relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ if ((relpos >= DT_HTLIN) && /* in data zone? */ (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { dt_seterr (uptr, DTB_SEL); @@ -659,7 +689,7 @@ case FNC_WALL: /* write all */ if (DT_QEZ (uptr)) { /* in "ok" end zone? */ if (dir) newpos = DTU_FWDEZ (uptr) - DT_WSIZE; else newpos = DT_EZLIN + (DT_WSIZE - 1); } - else { newpos = ((uptr -> pos) / DT_WSIZE) * DT_WSIZE; + else { newpos = ((uptr->pos) / DT_WSIZE) * DT_WSIZE; if (!dir) newpos = newpos + (DT_WSIZE - 1); } if ((dt_log & LOG_RA) || ((dt_log & LOG_BL) && (blk == dt_logblk))) printf ("[DT%d: read all block %d %s%s\n", @@ -669,12 +699,12 @@ case FNC_WALL: /* write all */ default: dt_seterr (uptr, DTB_SEL); /* bad state */ return; } -#if defined (PDP7) +#if defined (TYPE550) /* Type 550 */ if ((fnc == FNC_WRIT) || (fnc == FNC_WALL)) { /* write function? */ dtsb = dtsb | DTB_DTF; /* set data flag */ DT_UPDINT; } #endif -sim_activate (uptr, ABS (newpos - ((int32) uptr -> pos)) * dt_ltime); +sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime); return; } @@ -699,13 +729,13 @@ return; t_bool dt_setpos (UNIT *uptr) { uint32 new_time, ut, ulin, udelt; -int32 mot = DTS_GETMOT (uptr -> STATE); +int32 mot = DTS_GETMOT (uptr->STATE); int32 unum, delta; new_time = sim_grtime (); /* current time */ -ut = new_time - uptr -> LASTT; /* elapsed time */ +ut = new_time - uptr->LASTT; /* elapsed time */ if (ut == 0) return FALSE; /* no time gone? exit */ -uptr -> LASTT = new_time; /* update last time */ +uptr->LASTT = new_time; /* update last time */ switch (mot & ~DTS_DIR) { /* case on motion */ case DTS_STOP: /* stop */ delta = 0; @@ -721,12 +751,12 @@ case DTS_ACCF: /* accelerating */ case DTS_ATSF: /* at speed */ delta = ut / (uint32) dt_ltime; break; } -if (mot & DTS_DIR) uptr -> pos = uptr -> pos - delta; /* update pos */ -else uptr -> pos = uptr -> pos + delta; -if ((uptr -> pos < 0) || - (uptr -> pos > ((uint32) (DTU_FWDEZ (uptr) + DT_EZLIN)))) { +if (mot & DTS_DIR) uptr->pos = uptr->pos - delta; /* update pos */ +else uptr->pos = uptr->pos + delta; +if (((int32) uptr->pos < 0) || + ((int32) uptr->pos > (DTU_FWDEZ (uptr) + DT_EZLIN))) { detach_unit (uptr); /* off reel? */ - uptr -> STATE = uptr -> pos = 0; + uptr->STATE = uptr->pos = 0; unum = uptr - dt_dev.units; if (unum == DTA_GETUNIT (dtsa)) /* if selected, */ dt_seterr (uptr, DTB_SEL); /* error */ @@ -741,10 +771,10 @@ return FALSE; t_stat dt_svc (UNIT *uptr) { -int32 mot = DTS_GETMOT (uptr -> STATE); +int32 mot = DTS_GETMOT (uptr->STATE); int32 dir = mot & DTS_DIR; -int32 fnc = DTS_GETFNC (uptr -> STATE); -int32 *bptr = uptr -> filebuf; +int32 fnc = DTS_GETFNC (uptr->STATE); +int32 *bptr = uptr->filebuf; int32 unum = uptr - dt_dev.units; int32 blk, wrd, ma, relpos; t_addr ba; @@ -759,12 +789,12 @@ t_addr ba; switch (mot) { case DTS_DECF: case DTS_DECR: /* decelerating */ if (dt_setpos (uptr)) return SCPE_OK; /* update pos */ - uptr -> STATE = DTS_NXTSTA (uptr -> STATE); /* advance state */ - if (uptr -> STATE) /* not stopped? */ + uptr->STATE = DTS_NXTSTA (uptr->STATE); /* advance state */ + if (uptr->STATE) /* not stopped? */ sim_activate (uptr, dt_actime); /* must be reversing */ return SCPE_OK; case DTS_ACCF: case DTS_ACCR: /* accelerating */ - dt_newfnc (uptr, DTS_NXTSTA (uptr -> STATE)); /* adv state, sched */ + dt_newfnc (uptr, DTS_NXTSTA (uptr->STATE)); /* adv state, sched */ return SCPE_OK; case DTS_ATSF: case DTS_ATSR: /* at speed */ break; /* check function */ @@ -783,20 +813,20 @@ if (dt_setpos (uptr)) return SCPE_OK; /* update pos */ if (DT_QEZ (uptr)) { /* in end zone? */ dt_seterr (uptr, DTB_END); /* end zone error */ return SCPE_OK; } -blk = DT_LIN2BL (uptr -> pos, uptr); /* get block # */ +blk = DT_LIN2BL (uptr->pos, uptr); /* get block # */ switch (fnc) { /* at speed, check fnc */ case FNC_MOVE: /* move */ dt_seterr (uptr, DTB_END); /* end zone error */ return SCPE_OK; case DTS_OFR: /* off reel */ detach_unit (uptr); /* must be deselected */ - uptr -> STATE = uptr -> pos = 0; /* no visible action */ + uptr->STATE = uptr->pos = 0; /* no visible action */ break; /* TC02/TC15 service */ /* Search */ -#if defined (PDP9) || defined (PDP15) +#if defined (TC02) /* TC02/TC15 */ case FNC_SRCH: /* search */ if (dtsb & DTB_DTF) { /* DTF set? */ dt_seterr (uptr, DTB_TIM); /* timing error */ @@ -823,7 +853,7 @@ case FNC_SRCH: /* search */ */ case FNC_READ: /* read */ - wrd = DT_LIN2WD (uptr -> pos, uptr); /* get word # */ + wrd = DT_LIN2WD (uptr->pos, uptr); /* get word # */ switch (dt_substate) { /* case on substate */ case DTO_SOB: /* start of block */ if (dtsb & DTB_DTF) { /* DTF set? */ @@ -871,7 +901,7 @@ case FNC_READ: /* read */ */ case FNC_WRIT: /* write */ - wrd = DT_LIN2WD (uptr -> pos, uptr); /* get word # */ + wrd = DT_LIN2WD (uptr->pos, uptr); /* get word # */ switch (dt_substate) { /* case on substate */ case DTO_SOB: /* start block */ if (dtsb & DTB_DTF) { /* DTF set? */ @@ -891,7 +921,7 @@ case FNC_WRIT: /* write */ dtdb = dt_substate? 0: M[ma]; /* get word */ if (dir) dtdb = dt_comobv (dtdb); /* rev? comp obv */ bptr[ba] = dtdb; /* write word */ - if (ba >= uptr -> hwmark) uptr -> hwmark = ba + 1; + if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; if (M[DT_WC] == 0) dt_substate = DTO_WCO; if (wrd != (dir? 0: DTU_BSIZE (uptr) - 1)) /* not last? */ sim_activate (uptr, DT_WSIZE * dt_ltime); @@ -917,13 +947,13 @@ case FNC_RALL: if (dtsb & DTB_DTF) { /* DTF set? */ dt_seterr (uptr, DTB_TIM); /* timing error */ return SCPE_OK; } - relpos = DT_LIN2OF (uptr -> pos, uptr); /* cur pos in blk */ + relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ M[DT_WC] = (M[DT_WC] + 1) & DMASK; /* incr WC, CA */ M[DT_CA] = (M[DT_CA] + 1) & DMASK; ma = M[DT_CA] & ADDRMASK; /* mem addr */ if ((relpos >= DT_HTLIN) && /* in data zone? */ (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { - wrd = DT_LIN2WD (uptr -> pos, uptr); + wrd = DT_LIN2WD (uptr->pos, uptr); ba = (blk * DTU_BSIZE (uptr)) + wrd; dtdb = bptr[ba]; } /* get tape word */ else dtdb = dt_gethdr (uptr, blk, relpos); /* get hdr */ @@ -951,7 +981,7 @@ case FNC_WALL: if (dtsb & DTB_DTF) { /* DTF set? */ dt_seterr (uptr, DTB_TIM); /* timing error */ return SCPE_OK; } - relpos = DT_LIN2OF (uptr -> pos, uptr); /* cur pos in blk */ + relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ M[DT_WC] = (M[DT_WC] + 1) & DMASK; /* incr WC, CA */ M[DT_CA] = (M[DT_CA] + 1) & DMASK; ma = M[DT_CA] & ADDRMASK; /* mem addr */ @@ -959,10 +989,10 @@ case FNC_WALL: (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { dtdb = M[ma]; /* get mem word */ if (dir) dtdb = dt_comobv (dtdb); - wrd = DT_LIN2WD (uptr -> pos, uptr); + wrd = DT_LIN2WD (uptr->pos, uptr); ba = (blk * DTU_BSIZE (uptr)) + wrd; bptr[ba] = dtdb; /* write word */ - if (ba >= uptr -> hwmark) uptr -> hwmark = ba + 1; } + if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; } /* /* ignore hdr */ sim_activate (uptr, DT_WSIZE * dt_ltime); if (M[DT_WC] == 0) dt_substate = DTO_WCO; @@ -977,7 +1007,7 @@ case FNC_WALL: /* Type 550 service */ /* Search */ -#else +#else /* Type 550 */ case FNC_SRCH: /* search */ if (dtsb & DTB_DTF) { /* DTF set? */ dt_seterr (uptr, DTB_TIM); /* timing error */ @@ -994,10 +1024,10 @@ case FNC_READ: case FNC_RALL: dt_seterr (uptr, DTB_TIM); /* timing error */ return SCPE_OK; } sim_activate (uptr, DT_WSIZE * dt_ltime); /* sched next word */ - relpos = DT_LIN2OF (uptr -> pos, uptr); /* cur pos in blk */ + relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ if ((relpos >= DT_HTLIN) && /* in data zone? */ (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { - wrd = DT_LIN2WD (uptr -> pos, uptr); + wrd = DT_LIN2WD (uptr->pos, uptr); ba = (blk * DTU_BSIZE (uptr)) + wrd; dtdb = bptr[ba]; /* get tape word */ dtsb = dtsb | DTB_DTF; } /* set flag */ @@ -1022,14 +1052,14 @@ case FNC_WRIT: case FNC_WALL: dt_seterr (uptr, DTB_TIM); /* timing error */ return SCPE_OK; } sim_activate (uptr, DT_WSIZE * dt_ltime); /* sched next word */ - relpos = DT_LIN2OF (uptr -> pos, uptr); /* cur pos in blk */ + relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ if ((relpos >= DT_HTLIN) && /* in data zone? */ (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { - wrd = DT_LIN2WD (uptr -> pos, uptr); + wrd = DT_LIN2WD (uptr->pos, uptr); ba = (blk * DTU_BSIZE (uptr)) + wrd; if (dir) bptr[ba] = dt_comobv (dtdb); /* get data word */ else bptr[ba] = dtdb; - if (ba >= uptr -> hwmark) uptr -> hwmark = ba + 1; + if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; if (wrd == (dir? 0: DTU_BSIZE (uptr) - 1)) dtsb = dtsb | DTB_BEF; /* end block */ else dtsb = dtsb | DTB_DTF; } /* else next word */ @@ -1056,7 +1086,7 @@ return SCPE_OK; void dt_seterr (UNIT *uptr, int32 e) { -int32 mot = DTS_GETMOT (uptr -> STATE); +int32 mot = DTS_GETMOT (uptr->STATE); dtsa = dtsa & ~DTA_STSTP; /* clear go */ dtsb = dtsb | DTB_ERF | e; /* set error flag */ @@ -1077,7 +1107,7 @@ int32 newpos; if (dir) newpos = DT_EZLIN - DT_WSIZE; /* rev? rev ez */ else newpos = DTU_FWDEZ (uptr) + DT_WSIZE; /* fwd? fwd ez */ -sim_activate (uptr, ABS (newpos - ((int32) uptr -> pos)) * dt_ltime); +sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime); return; } @@ -1096,17 +1126,17 @@ return dat; int32 dt_csum (UNIT *uptr, int32 blk) { -int32 *bptr = uptr -> filebuf; +int32 *bptr = uptr->filebuf; int32 ba = blk * DTU_BSIZE (uptr); int32 i, csum, wrd; -#if defined (PDP9) || defined (PDP15) +#if defined (TC02) /* TC02/TC15 */ csum = 077; /* init csum */ for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */ wrd = bptr[ba + i] ^ 0777777; /* get ~word */ csum = csum ^ (wrd >> 12) ^ (wrd >> 6) ^ wrd; } return (csum & 077); -#else +#else /* Type 550 */ csum = 0777777; for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */ wrd = bptr[ba + i]; /* get word */ @@ -1123,14 +1153,14 @@ int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos) int32 wrd = relpos / DT_WSIZE; if (wrd == DT_BLKWD) return blk; /* fwd blknum */ -#if defined (PDP9) || defined (PDP15) +#if defined (TC02) /* TC02/TC15 */ if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_CSMWD - 1)) /* fwd csum */ return (dt_csum (uptr, blk) << 12); #else if (wrd == DT_CSMWD) return 0777777; /* rev csum */ if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_CSMWD - 1)) /* fwd csum */ return (dt_csum (uptr, blk)); -#endif +#endif /* Type 550 */ if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_BLKWD - 1)) /* rev blkno */ return dt_comobv (blk); return 0; /* all others */ @@ -1146,7 +1176,7 @@ UNIT *uptr; for (i = 0; i < DT_NUMDR; i++) { /* stop all drives */ uptr = dt_dev.units + i; if (sim_is_running) { /* CAF? */ - prev_mot = DTS_GETMOT (uptr -> STATE); /* get motion */ + prev_mot = DTS_GETMOT (uptr->STATE); /* get motion */ if ((prev_mot & ~DTS_DIR) > DTS_DECF) { /* accel or spd? */ if (dt_setpos (uptr)) continue; /* update pos */ sim_cancel (uptr); @@ -1154,8 +1184,8 @@ for (i = 0; i < DT_NUMDR; i++) { /* stop all drives */ DTS_SETSTA (DTS_DECF | (prev_mot & DTS_DIR), 0); } } else { sim_cancel (uptr); /* sim reset */ - uptr -> STATE = 0; - uptr -> LASTT = sim_grtime (); } } + uptr->STATE = 0; + uptr->LASTT = sim_grtime (); } } dtsa = dtsb = 0; /* clear status */ DT_UPDINT; /* reset interrupt */ return SCPE_OK; @@ -1174,101 +1204,126 @@ return 0; /* Attach routine - Determine native or PDP8 format + Determine 12b, 16b, or 18b/36b format Allocate buffer - If PDP8, read 12b format and convert to 18b in buffer - If native, read data into buffer + If 12b, read 12b format and convert to 18b in buffer + If 16b, read 16b format and convert to 18b in buffer + If 18b/36b, read data into buffer */ t_stat dt_attach (UNIT *uptr, char *cptr) { uint16 pdp8b[D8_NBSIZE]; -int32 k, p, *bptr; +uint16 pdp11b[D18_BSIZE]; +uint32 k, p, *bptr; t_stat r; t_addr ba; -uptr -> flags = uptr -> flags & ~UNIT_8FMT; r = attach_unit (uptr, cptr); /* attach */ -if (r != SCPE_OK) return r; /* fail? */ -if (sim_switches & SWMASK ('F')) /* att foreign? */ - uptr -> flags = uptr -> flags | UNIT_8FMT; /* PDP8 = T */ -else if (!(sim_switches & SWMASK ('N'))) { /* autosize? */ - if ((fseek (uptr -> fileref, 0, SEEK_END) == 0) && - (p = ftell (uptr -> fileref)) && - (p == D8_FILSIZ)) uptr -> flags = uptr -> flags | UNIT_8FMT; } -uptr -> capac = DTU_CAPAC (uptr); /* set capacity */ -uptr -> filebuf = calloc (uptr -> capac, sizeof (int32)); -if (uptr -> filebuf == NULL) { /* can't alloc? */ +if (r != SCPE_OK) return r; /* error? */ +uptr->flags = uptr->flags & ~(UNIT_8FMT | UNIT_11FMT); /* default 18b */ +if (sim_switches & SWMASK ('R')) /* att 12b? */ + uptr->flags = uptr->flags | UNIT_8FMT; +else if (sim_switches & SWMASK ('S')) /* att 16b? */ + uptr->flags = uptr->flags | UNIT_11FMT; +else if (!(sim_switches & SWMASK ('T')) && /* autosize? */ + (fseek (uptr->fileref, 0, SEEK_END) == 0) && + ((p = ftell (uptr->fileref)) != 0)) { + if (p == D8_FILSIZ) uptr->flags = uptr->flags | UNIT_8FMT; + if (p == D11_FILSIZ) uptr->flags = uptr->flags | UNIT_11FMT; } +uptr->capac = DTU_CAPAC (uptr); /* set capacity */ +uptr->filebuf = calloc (uptr->capac, sizeof (int32)); +if (uptr->filebuf == NULL) { /* can't alloc? */ detach_unit (uptr); return SCPE_MEM; } -printf ("%DT: buffering file in memory\n"); -rewind (uptr -> fileref); /* start of file */ -if (uptr -> flags & UNIT_8FMT) { /* PDP-8? */ - bptr = uptr -> filebuf; /* file buffer */ - for (ba = 0; ba < uptr -> capac; ) { /* loop thru file */ - k = fxread (pdp8b, sizeof (int16), D8_NBSIZE, uptr -> fileref); - if (k == 0) break; - for ( ; k < D8_NBSIZE; k++) pdp8b[k] = 0; - for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop thru blk */ - bptr[ba] = ((uint32) (pdp8b[k] & 07777) << 6) | - ((uint32) (pdp8b[k + 1] >> 6) & 077); - bptr[ba + 1] = ((uint32) (pdp8b[k + 1] & 077) << 12) | - (pdp8b[k + 2] & 07777); - ba = ba + 2; } /* end blk loop */ - } /* end file loop */ - uptr -> hwmark = ba; } /* end if */ -else uptr -> hwmark = fxread (uptr -> filebuf, sizeof (int32), - uptr -> capac, uptr -> fileref); -uptr -> flags = uptr -> flags | UNIT_BUF; /* set buf flag */ -uptr -> pos = DT_EZLIN; /* beyond leader */ -uptr -> LASTT = sim_grtime (); /* last pos update */ +bptr = uptr->filebuf; /* file buffer */ +if (uptr->flags & UNIT_8FMT) printf ("DT: 12b format"); +else if (uptr->flags & UNIT_11FMT) printf ("DT: 16b format"); +else printf ("DT: 18b/36b format"); +printf (", buffering file in memory\n"); +rewind (uptr->fileref); /* start of file */ +if (uptr->flags & UNIT_8FMT) { /* 12b? */ + for (ba = 0; ba < uptr->capac; ) { /* loop thru file */ + k = fxread (pdp8b, sizeof (int16), D8_NBSIZE, uptr->fileref); + if (k == 0) break; + for ( ; k < D8_NBSIZE; k++) pdp8b[k] = 0; + for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop thru blk */ + bptr[ba] = ((uint32) (pdp8b[k] & 07777) << 6) | + ((uint32) (pdp8b[k + 1] >> 6) & 077); + bptr[ba + 1] = ((uint32) (pdp8b[k + 1] & 077) << 12) | + (pdp8b[k + 2] & 07777); + ba = ba + 2; } /* end blk loop */ + } /* end file loop */ + uptr->hwmark = ba; } /* end if */ +else if (uptr->flags & UNIT_11FMT) { /* 16b? */ + for (ba = 0; ba < uptr->capac; ) { /* loop thru file */ + k = fxread (pdp11b, sizeof (int16), D18_BSIZE, uptr->fileref); + if (k == 0) break; + for ( ; k < D18_BSIZE; k++) pdp11b[k] = 0; + for (k = 0; k < D18_BSIZE; k++) + bptr[ba++] = pdp11b[k]; } + uptr->hwmark = ba; } /* end elif */ +else uptr->hwmark = fxread (uptr->filebuf, sizeof (int32), + uptr->capac, uptr->fileref); +uptr->flags = uptr->flags | UNIT_BUF; /* set buf flag */ +uptr->pos = DT_EZLIN; /* beyond leader */ +uptr->LASTT = sim_grtime (); /* last pos update */ return SCPE_OK; } /* Detach routine Cancel in progress operation - If PDP8, convert 18b buffer to 12b and write to file - If native, write buffer to file + If 12b, convert 18b buffer to 12b and write to file + If 16b, convert 18b buffer to 16b and write to file + If 18b/36b, write buffer to file Deallocate buffer */ t_stat dt_detach (UNIT* uptr) { uint16 pdp8b[D8_NBSIZE]; -int32 k, *bptr; +uint16 pdp11b[D18_BSIZE]; +uint32 k, *bptr; int32 unum = uptr - dt_dev.units; t_addr ba; -if (!(uptr -> flags & UNIT_ATT)) return SCPE_OK; +if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; if (sim_is_active (uptr)) { sim_cancel (uptr); if ((unum == DTA_GETUNIT (dtsa)) && (dtsa & DTA_STSTP)) { dtsb = dtsb | DTB_ERF | DTB_SEL | DTB_DTF; DT_UPDINT; } - uptr -> STATE = uptr -> pos = 0; } -if (uptr -> hwmark && ((uptr -> flags & UNIT_RO) == 0)) { /* any data? */ + uptr->STATE = uptr->pos = 0; } +bptr = uptr->filebuf; /* file buffer */ +if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { /* any data? */ printf ("DT: writing buffer to file\n"); - rewind (uptr -> fileref); /* start of file */ - if (uptr -> flags & UNIT_8FMT) { /* PDP8? */ - bptr = uptr -> filebuf; /* file buffer */ - for (ba = 0; ba < uptr -> hwmark; ) { /* loop thru buf */ - for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop blk */ - pdp8b[k] = (bptr[ba] >> 6) & 07777; - pdp8b[k + 1] = ((bptr[ba] & 077) << 6) | - ((bptr[ba + 1] >> 12) & 077); - pdp8b[k + 2] = bptr[ba + 1] & 07777; - ba = ba + 2; } /* end loop blk */ - fxwrite (pdp8b, sizeof (int16), D8_NBSIZE, uptr -> fileref); - if (ferror (uptr -> fileref)) break; } /* end loop file */ - } /* end if PDP8 */ - else fxwrite (uptr -> filebuf, sizeof (int32), /* write file */ - uptr -> hwmark, uptr -> fileref); - if (ferror (uptr -> fileref)) perror ("I/O error"); } /* end if hwmark */ -free (uptr -> filebuf); /* release buf */ -uptr -> flags = uptr -> flags & ~UNIT_BUF; /* clear buf flag */ -uptr -> filebuf = NULL; /* clear buf ptr */ -uptr -> flags = uptr -> flags & ~UNIT_8FMT; /* default fmt */ -uptr -> capac = DT_CAPAC; /* default size */ + rewind (uptr->fileref); /* start of file */ + if (uptr->flags & UNIT_8FMT) { /* 12b? */ + for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */ + for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop blk */ + pdp8b[k] = (bptr[ba] >> 6) & 07777; + pdp8b[k + 1] = ((bptr[ba] & 077) << 6) | + ((bptr[ba + 1] >> 12) & 077); + pdp8b[k + 2] = bptr[ba + 1] & 07777; + ba = ba + 2; } /* end loop blk */ + fxwrite (pdp8b, sizeof (int16), D8_NBSIZE, uptr->fileref); + if (ferror (uptr->fileref)) break; } /* end loop file */ + } /* end if 12b */ + else if (uptr->flags & UNIT_11FMT) { /* 16b? */ + for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */ + for (k = 0; k < D18_BSIZE; k++) /* loop blk */ + pdp11b[k] = bptr[ba++] & 0177777; + fxwrite (pdp11b, sizeof (int16), D18_BSIZE, uptr->fileref); + if (ferror (uptr->fileref)) break; } /* end loop file */ + } /* end if 16b */ + else fxwrite (uptr->filebuf, sizeof (int32), /* write file */ + uptr->hwmark, uptr->fileref); + if (ferror (uptr->fileref)) perror ("I/O error"); } /* end if hwmark */ +free (uptr->filebuf); /* release buf */ +uptr->flags = uptr->flags & ~UNIT_BUF; /* clear buf flag */ +uptr->filebuf = NULL; /* clear buf ptr */ +uptr->flags = uptr->flags & ~(UNIT_8FMT | UNIT_11FMT); /* default fmt */ +uptr->capac = DT_CAPAC; /* default size */ return detach_unit (uptr); } diff --git a/PDP18B/pdp18b_lp.c b/PDP18B/pdp18b_lp.c index 8e14d6d8..15d6f356 100644 --- a/PDP18B/pdp18b_lp.c +++ b/PDP18B/pdp18b_lp.c @@ -27,6 +27,7 @@ (PDP-7,9) Type 647 line printer (PDP-15) LP15 line printer + 05-Oct-02 RMS Added DIB, device number support 30-May-02 RMS Widened POS to 32b 03-Feb-02 RMS Fixed typo (found by Robert Alan Byer) 25-Nov-01 RMS Revised interrupt structure @@ -40,18 +41,32 @@ #include "pdp18b_defs.h" +DEVICE lpt_dev; +int32 lpt65 (int32 pulse, int32 AC); +int32 lpt66 (int32 pulse, int32 AC); +int32 lpt_iors (void); +t_stat lpt_svc (UNIT *uptr); +t_stat lpt_reset (DEVICE *dptr); + +extern int32 int_hwre[API_HLVL+1]; + +DIB lpt_dib = { DEV_LPT, 2, &lpt_iors, { &lpt65, &lpt66 } }; + +UNIT lpt_unit = { + UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; + +MTAB lpt_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno }, + { 0 } }; + #if defined (TYPE62) #define BPTR_MAX 40 /* pointer max */ #define LPT_BSIZE 120 /* line size */ #define BPTR_MASK 077 /* buf ptr max */ -extern int32 int_hwre[API_HLVL+1]; int32 lpt_iot = 0, lpt_stopioe = 0, bptr = 0; char lpt_buf[LPT_BSIZE + 1] = { 0 }; -t_stat lpt_svc (UNIT *uptr); -t_stat lpt_reset (DEVICE *dptr); - /* Type 62 LPT data structures lpt_dev LPT device descriptor @@ -59,9 +74,6 @@ t_stat lpt_reset (DEVICE *dptr); lpt_reg LPT register list */ -UNIT lpt_unit = { - UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; - REG lpt_reg[] = { { ORDATA (BUF, lpt_unit.buf, 8) }, { FLDATA (INT, int_hwre[API_LPT], INT_V_LPT) }, @@ -73,13 +85,15 @@ REG lpt_reg[] = { { DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, lpt_stopioe, 0) }, { BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE) }, + { ORDATA (DEVNO, lpt_dib.dev, 6), REG_HRO }, { NULL } }; DEVICE lpt_dev = { - "LPT", &lpt_unit, lpt_reg, NULL, + "LPT", &lpt_unit, lpt_reg, lpt_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &lpt_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &lpt_dib, DEV_DISABLE }; /* Type 62 line printer: IOT routines */ @@ -97,9 +111,9 @@ if ((pulse & 001) && TST_INT (LPT)) AC = IOT_SKP | AC; /* LPSF */ if ((pulse & 042) == 002) CLR_INT (LPT); /* LPCF */ if (((pulse & 042) == 042) && (bptr < BPTR_MAX)) { /* LPLD */ i = bptr * 3; /* cvt to chr ptr */ - lpt_buf[i++] = lpt_trans[(AC >> 12) & 077]; - lpt_buf[i++] = lpt_trans[(AC >> 6) & 077]; - lpt_buf[i++] = lpt_trans[AC & 077]; + lpt_buf[i] = lpt_trans[(AC >> 12) & 077]; + lpt_buf[i + 1] = lpt_trans[(AC >> 6) & 077]; + lpt_buf[i + 2] = lpt_trans[AC & 077]; bptr = (bptr + 1) & BPTR_MASK; } if (pulse & 004) { /* LPSE */ sim_activate (&lpt_unit, lpt_unit.wait); } /* activate */ @@ -189,13 +203,10 @@ return (TST_INT (LPT)? IOS_LPT: 0) | #elif defined (TYPE647) #define LPT_BSIZE 120 /* line size */ -extern int32 int_hwre[API_HLVL+1]; int32 lpt_done = 0, lpt_ie = 1, lpt_err = 0; int32 lpt_iot = 0, lpt_stopioe = 0, bptr = 0; char lpt_buf[LPT_BSIZE] = { 0 }; -t_stat lpt_svc (UNIT *uptr); -t_stat lpt_reset (DEVICE *dptr); t_stat lpt_attach (UNIT *uptr, char *cptr); t_stat lpt_detach (UNIT *uptr); @@ -206,9 +217,6 @@ t_stat lpt_detach (UNIT *uptr); lpt_reg LPT register list */ -UNIT lpt_unit = { - UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; - REG lpt_reg[] = { { ORDATA (BUF, lpt_unit.buf, 8) }, { FLDATA (INT, int_hwre[API_LPT], INT_V_LPT) }, @@ -223,13 +231,15 @@ REG lpt_reg[] = { { DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, lpt_stopioe, 0) }, { BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE) }, + { ORDATA (DEVNO, lpt_dib.dev, 6), REG_HRO }, { NULL } }; DEVICE lpt_dev = { - "LPT", &lpt_unit, lpt_reg, NULL, + "LPT", &lpt_unit, lpt_reg, lpt_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &lpt_reset, - NULL, &lpt_attach, &lpt_detach }; + NULL, &lpt_attach, &lpt_detach, + &lpt_dib, DEV_DISABLE }; /* Type 647 line printer: IOT routines */ @@ -404,13 +414,10 @@ return detach_unit (uptr); #define STA_CLR 0003777 /* always clear */ extern int32 M[]; -extern int32 int_hwre[API_HLVL+1]; int32 lpt_sta = 0, lpt_ie = 1, lpt_stopioe = 0; int32 mode = 0, lcnt = 0, bptr = 0; char lpt_buf[LPT_BSIZE] = { 0 }; -t_stat lpt_svc (UNIT *uptr); -t_stat lpt_reset (DEVICE *dptr); int32 lpt_updsta (int32 new); /* LP15 LPT data structures @@ -420,9 +427,6 @@ int32 lpt_updsta (int32 new); lpt_reg LPT register list */ -UNIT lpt_unit = { - UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; - REG lpt_reg[] = { { ORDATA (STA, lpt_sta, 18) }, { ORDATA (CA, M[LPT_CA], 18) }, @@ -435,13 +439,15 @@ REG lpt_reg[] = { { DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, lpt_stopioe, 0) }, { BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE) }, + { ORDATA (DEVNO, lpt_dib.dev, 6), REG_HRO }, { NULL } }; DEVICE lpt_dev = { - "LPT", &lpt_unit, lpt_reg, NULL, + "LPT", &lpt_unit, lpt_reg, lpt_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &lpt_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &lpt_dib, DEV_DISABLE }; /* LP15 line printer: IOT routines */ diff --git a/PDP18B/pdp18b_mt.c b/PDP18B/pdp18b_mt.c index be6ff668..66d4daa2 100644 --- a/PDP18B/pdp18b_mt.c +++ b/PDP18B/pdp18b_mt.c @@ -26,6 +26,10 @@ mt (PDP-9) TC59 magtape (PDP-15) TC59D magtape + 30-Oct-02 RMS Revised BOT handling, added error record handling + 05-Oct-02 RMS Added DIB, device number support + Revamped error recovery + 28-Aug-02 RMS Added end of medium support 30-May-02 RMS Widened POS to 32b 22-Apr-02 RMS Added maximum record length test 06-Jan-02 RMS Revised enabled/disable support @@ -57,10 +61,10 @@ #define MT_NUMDR 8 /* #drives */ #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_WLK 1 << UNIT_V_WLK -#define UNIT_W_UF 2 /* saved flag width */ +#define UNIT_V_PNU (UNIT_V_UF + 1) /* pos not updated */ +#define UNIT_WLK (1 << UNIT_V_WLK) +#define UNIT_PNU (1 << UNIT_V_PNU) #define USTAT u3 /* unit status */ -#define UNUM u4 /* unit number */ #define MT_MAXFR (1 << 16) /* max record length */ #define DBSIZE (1 << 12) /* max word count */ #define DBMASK (DBSIZE - 1) @@ -94,7 +98,7 @@ #define GET_TYPE(x) (((x) >> CU_V_TYPE) & CU_M_TYPE) #define PACKED(x) (((x) & CU_DUMP) || (GET_TYPE (x) != TY_9TK)) -/* Status - stored in mt_sta or (*) uptr -> USTAT */ +/* Status - stored in mt_sta or (*) uptr->USTAT */ #define STA_ERR 0400000 /* error */ #define STA_REW 0200000 /* *rewinding */ @@ -117,17 +121,24 @@ /* error flags */ extern int32 M[]; -extern int32 int_hwre[API_HLVL+1], dev_enb; +extern int32 int_hwre[API_HLVL+1]; extern UNIT cpu_unit; + int32 mt_cu = 0; /* command/unit */ int32 mt_sta = 0; /* status register */ int32 mt_time = 10; /* record latency */ int32 mt_stopioe = 1; /* stop on error */ + +DEVICE mt_dev; +int32 mt (int32 pulse, int32 AC); +int32 mt_iors (void); t_stat mt_svc (UNIT *uptr); t_stat mt_reset (DEVICE *dptr); t_stat mt_attach (UNIT *uptr, char *cptr); t_stat mt_detach (UNIT *uptr); int32 mt_updcsta (UNIT *uptr, int32 val); +t_bool mt_rdlntf (UNIT *uptr, t_mtrlnt *tbc, int32 *err); +t_bool mt_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err); UNIT *mt_busy (void); /* MT data structures @@ -138,6 +149,8 @@ UNIT *mt_busy (void); mt_mod MT modifier list */ +DIB mt_dib = { DEV_MT, 1, &mt_iors, { &mt } }; + UNIT mt_unit[] = { { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, @@ -159,23 +172,21 @@ REG mt_reg[] = { { URDATA (UST, mt_unit[0].USTAT, 8, 16, 0, MT_NUMDR, 0) }, { URDATA (POS, mt_unit[0].pos, 10, 32, 0, MT_NUMDR, PV_LEFT | REG_RO) }, - { URDATA (FLG, mt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, - MT_NUMDR, REG_HRO) }, - { FLDATA (*DEVENB, dev_enb, ENB_V_MTA), REG_HRO }, + { ORDATA (DEVNO, mt_dib.dev, 6), REG_HRO }, { NULL } }; MTAB mt_mod[] = { { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, - { MTAB_XTD|MTAB_VDV, ENB_MTA, NULL, "ENABLED", &set_enb }, - { MTAB_XTD|MTAB_VDV, ENB_MTA, NULL, "DISABLED", &set_dsb }, + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno }, { 0 } }; DEVICE mt_dev = { "MT", mt_unit, mt_reg, mt_mod, MT_NUMDR, 10, 31, 1, 8, 8, NULL, NULL, &mt_reset, - NULL, &mt_attach, &mt_detach }; + NULL, &mt_attach, &mt_detach, + &mt_dib, DEV_DISABLE }; /* IOT routine */ @@ -202,12 +213,12 @@ if ((pulse & 064) == 024) /* MTCM, MTLC */ if (pulse == 004) { /* MTGO */ f = GET_CMD (mt_cu); /* get function */ if (mt_busy () || (sim_is_active (uptr)) || - (((f == FN_SPACER) || (f == FN_REWIND)) & (uptr -> pos == 0)) || - (((f == FN_WRITE) || (f == FN_WREOF)) && (uptr -> flags & UNIT_WPRT)) - || ((uptr -> flags & UNIT_ATT) == 0) || (f == FN_NOP)) + (((f == FN_SPACER) || (f == FN_REWIND)) & (uptr->USTAT & STA_BOT)) || + (((f == FN_WRITE) || (f == FN_WREOF)) && (uptr->flags & UNIT_WPRT)) + || ((uptr->flags & UNIT_ATT) == 0) || (f == FN_NOP)) mt_sta = mt_sta | STA_ILL; /* illegal op flag */ - else { if (f == FN_REWIND) uptr -> USTAT = STA_REW; /* rewind? */ - else mt_sta = uptr -> USTAT = 0; /* no, clear status */ + else { if (f == FN_REWIND) uptr->USTAT = STA_REW; /* rewind? */ + else mt_sta = uptr->USTAT = 0; /* no, clear status */ sim_activate (uptr, mt_time); } } /* start io */ mt_updcsta (mt_dev.units + GET_UNIT (mt_cu), 0); /* update status */ return AC; @@ -221,53 +232,44 @@ return AC; t_stat mt_svc (UNIT *uptr) { -int32 c, c1, c2, c3, f, i, p, u, err; +int32 c, c1, c2, c3, f, i, p, u, err, pnu; int32 wc, xma; -t_stat rval; -t_mtrlnt tbc, cbc; +t_mtrlnt abc, tbc, cbc; static uint8 dbuf[(3 * DBSIZE)]; -static t_mtrlnt bceof = { 0 }; +static t_mtrlnt bceof = MTR_TMK; -u = uptr -> UNUM; /* get unit number */ -if (uptr -> USTAT & STA_REW) { /* rewind? */ - uptr -> pos = 0; /* update position */ - if (uptr -> flags & UNIT_ATT) uptr -> USTAT = STA_BOT; - else uptr -> USTAT = 0; +err = 0; +u = uptr - mt_dev.units; /* get unit number */ +f = GET_CMD (mt_cu); /* get command */ +pnu = MT_TST_PNU (uptr); /* get pos not upd */ +MT_CLR_PNU (uptr); /* and clear */ + +if (uptr->USTAT & STA_REW) { /* rewind? */ + uptr->pos = 0; /* update position */ + if (uptr->flags & UNIT_ATT) uptr->USTAT = STA_BOT; + else uptr->USTAT = 0; if (u == GET_UNIT (mt_cu)) mt_updcsta (uptr, STA_DON); return SCPE_OK; } -f = GET_CMD (mt_cu); /* get command */ -if ((uptr -> flags & UNIT_ATT) == 0) { /* if not attached */ +if ((uptr->flags & UNIT_ATT) == 0) { /* if not attached */ mt_updcsta (uptr, STA_ILL); /* illegal operation */ return IORETURN (mt_stopioe, SCPE_UNATT); } if ((f == FN_WRITE) || (f == FN_WREOF)) { /* write? */ - if (uptr -> flags & UNIT_WPRT) { /* write locked? */ + if (uptr->flags & UNIT_WPRT) { /* write locked? */ mt_updcsta (uptr, STA_ILL); /* illegal operation */ return SCPE_OK; } mt_cu = mt_cu & ~CU_ERASE; } /* clear erase flag */ -err = 0; -rval = SCPE_OK; switch (f) { /* case on function */ /* Unit service, continued */ case FN_READ: /* read */ case FN_CMPARE: /* read/compare */ - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); - fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - if ((err = ferror (uptr -> fileref)) || /* error or eof? */ - (feof (uptr -> fileref))) { - uptr -> USTAT = STA_EOT; - mt_updcsta (uptr, STA_RLE); + if (mt_rdlntf (uptr, &tbc, &err)) { /* read rec lnt, err? */ + mt_updcsta (uptr, STA_RLE); /* set RLE flag */ break; } - if (tbc == 0) { /* tape mark? */ - uptr -> USTAT = STA_EOF; - mt_updcsta (uptr, STA_RLE); - uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); - break; } - tbc = MTRL (tbc); /* ignore error flag */ if (tbc > MT_MAXFR) return SCPE_MTRLNT; /* record too long? */ wc = DBSIZE - (M[MT_WC] & DBMASK); /* get word count */ cbc = PACKED (mt_cu)? wc * 3: wc * 2; /* expected bc */ @@ -275,9 +277,11 @@ case FN_CMPARE: /* read/compare */ if (tbc < cbc) { /* record small? */ cbc = tbc; /* use smaller */ wc = PACKED (mt_cu)? ((tbc + 2) / 3): ((tbc + 1) / 2); } - i = fxread (dbuf, sizeof (int8), cbc, uptr -> fileref); - for ( ; i < cbc; i++) dbuf[i] = 0; /* fill with 0's */ - err = ferror (uptr -> fileref); + abc = fxread (dbuf, sizeof (int8), cbc, uptr->fileref); + if (err = ferror (uptr->fileref)) { /* error */ + MT_SET_PNU (uptr); /* pos not upd */ + break; } + for ( ; abc < cbc; abc++) dbuf[abc] = 0; /* fill with 0's */ for (i = p = 0; i < wc; i++) { /* copy buffer */ M[MT_WC] = (M[MT_WC] + 1) & 0777777; /* inc WC, CA */ M[MT_CA] = (M[MT_CA] + 1) & 0777777; @@ -295,14 +299,15 @@ case FN_CMPARE: /* read/compare */ (PACKED (mt_cu)? 0777777: 0177777)))) { mt_updcsta (uptr, STA_CPE); break; } } - uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) + + uptr->pos = uptr->pos + ((tbc + 1) & ~1) + (2 * sizeof (t_mtrlnt)); break; + case FN_WRITE: /* write */ - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); + fseek (uptr->fileref, uptr->pos, SEEK_SET); wc = DBSIZE - (M[MT_WC] & DBMASK); /* get word count */ tbc = PACKED (mt_cu)? wc * 3: wc * 2; - fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); + fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr->fileref); for (i = p = 0; i < wc; i++) { /* copy buf to tape */ M[MT_WC] = (M[MT_WC] + 1) & 0777777; /* inc WC, CA */ M[MT_CA] = (M[MT_CA] + 1) & 0777777; @@ -313,79 +318,52 @@ case FN_WRITE: /* write */ dbuf[p++] = M[xma] & 077; } else { dbuf[p++] = (M[xma] >> 8) & 0377; dbuf[p++] = M[xma] & 0377; } } - fxwrite (dbuf, sizeof (char), (tbc + 1) & ~1, uptr -> fileref); - fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - err = ferror (uptr -> fileref); - uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) + + fxwrite (dbuf, sizeof (char), (tbc + 1) & ~1, uptr->fileref); + fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr->fileref); + if (err = ferror (uptr->fileref)) MT_SET_PNU (uptr); /* error? */ + else uptr->pos = uptr->pos + ((tbc + 1) & ~1) + /* no, upd pos */ (2 * sizeof (t_mtrlnt)); break; /* Unit service, continued */ case FN_WREOF: - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); - fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr -> fileref); - err = ferror (uptr -> fileref); - uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); - uptr -> USTAT = STA_EOF; + fseek (uptr->fileref, uptr->pos, SEEK_SET); + fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr->fileref); + uptr->USTAT = STA_EOF; + if (err = ferror (uptr->fileref)) MT_SET_PNU (uptr); /* error? */ + else uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* no, upd pos */ break; + case FN_SPACEF: /* space forward */ - do { fseek (uptr -> fileref, uptr -> pos, SEEK_SET); - fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); /* read bc */ - if ((err = ferror (uptr -> fileref)) || /* error or eof? */ - feof (uptr -> fileref)) { - uptr -> USTAT = STA_EOT; - break; } - if (tbc == 0) { /* zero bc? */ - uptr -> USTAT = STA_EOF; - uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); - break; } - uptr -> pos = uptr -> pos + ((MTRL (tbc) + 1) & ~1) + + do { if (mt_rdlntf (uptr, &tbc, &err)) break;/* read rec lnt, err? */ + uptr->pos = uptr->pos + ((tbc + 1) & ~1) + (2 * sizeof (t_mtrlnt)); } while ((M[MT_WC] = (M[MT_WC] + 1) & 0777777) != 0); break; + case FN_SPACER: /* space reverse */ - if (uptr -> pos == 0) { /* at BOT? */ - uptr -> USTAT = STA_BOT; - break; } - do { fseek (uptr -> fileref, uptr -> pos - sizeof (t_mtrlnt), - SEEK_SET); - fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - tbc = MTRL (tbc); /* ignore error flag */ - if ((err = ferror (uptr -> fileref)) || /* error or eof? */ - feof (uptr -> fileref)) { - uptr -> USTAT = STA_BOT; - uptr -> pos = 0; - break; } - if (tbc == 0) { /* end of file? */ - uptr -> USTAT = STA_EOF; - uptr -> pos = uptr -> pos - sizeof (t_mtrlnt); - break; } - uptr -> pos = uptr -> pos - ((tbc + 1) & ~1) - - (2 * sizeof (t_mtrlnt)); - if (uptr -> pos == 0) { /* at BOT? */ - uptr -> USTAT = STA_BOT; - break; } } + do { if (pnu) pnu = 0; /* pos not upd? */ + else { if (mt_rdlntf (uptr, &tbc, &err)) break; + uptr->pos = uptr->pos - ((tbc + 1) & ~1) - + (2 * sizeof (t_mtrlnt)); } } while ((M[MT_WC] = (M[MT_WC] + 1) & 0777777) != 0); break; } /* end case */ - -/* Unit service, continued */ -if (err != 0) { /* I/O error */ - mt_updcsta (uptr, STA_PAR); /* flag error */ +mt_updcsta (uptr, STA_DON | (err? STA_PAR: 0)); /* set done */ +if (err != 0) { /* I/O error? */ perror ("MT I/O error"); - rval = SCPE_IOERR; - clearerr (uptr -> fileref); } -mt_updcsta (uptr, STA_DON); /* set done */ -return IORETURN (mt_stopioe, rval); + clearerr (uptr->fileref); + if (mt_stopioe) return SCPE_IOERR; } +return SCPE_OK; } - + /* Update controller status */ -int32 mt_updcsta (UNIT *uptr, int32 new) +int32 mt_updcsta (UNIT *uptr, int32 news) { mt_sta = (mt_sta & ~(STA_DYN | STA_ERR | STA_CLR)) | - (uptr -> USTAT & STA_DYN) | new; + (uptr->USTAT & STA_DYN) | news; if (mt_sta & STA_EFLGS) mt_sta = mt_sta | STA_ERR; /* error flag */ if ((mt_sta & (STA_ERR | STA_DON)) && ((mt_cu & CU_IE) == 0)) SET_INT (MTA); @@ -402,10 +380,61 @@ UNIT *uptr; for (u = 0; u < MT_NUMDR; u++) { /* loop thru units */ uptr = mt_dev.units + u; - if (sim_is_active (uptr) && ((uptr -> USTAT & STA_REW) == 0)) + if (sim_is_active (uptr) && ((uptr->USTAT & STA_REW) == 0)) return uptr; } return NULL; } + +/* Read record length forward - return status flag if err, EOM, or EOF */ + +t_bool mt_rdlntf (UNIT *uptr, t_mtrlnt *tbc, int32 *err) +{ +fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set tape pos */ +fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); /* read rec lnt */ +if (*err = ferror (uptr->fileref)) { /* error? */ + mt_sta = mt_sta | STA_PAR; /* set flag */ + MT_SET_PNU (uptr); /* pos not upd */ + return TRUE; } +if (feof (uptr->fileref) || (*tbc == MTR_EOM)) { /* eof or eom? */ + mt_sta = mt_sta | STA_BAD; /* bad tape */ + MT_SET_PNU (uptr); /* pos not upd */ + return TRUE; } +if (*tbc == MTR_TMK) { /* tape mark? */ + uptr->USTAT = uptr->USTAT | STA_EOF; /* end of file */ + uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* spc over tmk */ + return TRUE; } +if (MTRF (*tbc)) mt_sta = mt_sta | STA_PAR; /* record in error? */ +*tbc = MTRL (*tbc); /* clear error flag */ +return FALSE; +} + +/* Read record length reverse - return status flag if err, EOM, or EOF */ + +int32 mt_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err) +{ +if (uptr->pos < sizeof (t_mtrlnt)) { /* at BOT? */ + uptr->USTAT = STA_BOT; /* set status */ + return TRUE; } /* error */ +fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt), SEEK_SET); +fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); +if (*err = ferror (uptr->fileref)) { /* error? */ + mt_sta = mt_sta | STA_PAR; /* set flag */ + return TRUE; } +if (feof (uptr->fileref)) { /* eof? */ + mt_sta = mt_sta | STA_BAD; /* bad tape */ + return TRUE; } +if (*tbc == MTR_EOM) { /* eom? */ + mt_sta = mt_sta | STA_BAD; /* bad tape */ + uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over eom */ + return TRUE; } +if (*tbc == MTR_TMK) { /* tape mark? */ + uptr->USTAT = uptr->USTAT | STA_EOF; /* end of file */ + uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over tmk */ + return TRUE; } +if (MTRF (*tbc)) mt_sta = mt_sta | STA_PAR; /* record in error? */ +*tbc = MTRL (*tbc); /* clear error flag */ +return FALSE; +} /* Reset routine */ @@ -417,10 +446,10 @@ UNIT *uptr; mt_cu = mt_sta = 0; for (u = 0; u < MT_NUMDR; u++) { /* loop thru units */ uptr = mt_dev.units + u; - uptr -> UNUM = u; /* init drive number */ + MT_CLR_PNU (uptr); /* clr pos not upd */ sim_cancel (uptr); /* cancel activity */ - if (uptr -> flags & UNIT_ATT) uptr -> USTAT = STA_BOT; - else uptr -> USTAT = 0; } + if (uptr->flags & UNIT_ATT) uptr->USTAT = STA_BOT; + else uptr->USTAT = 0; } mt_updcsta (&mt_unit[0], 0); /* update status */ return SCPE_OK; } @@ -440,7 +469,8 @@ t_stat r; r = attach_unit (uptr, cptr); if (r != SCPE_OK) return r; -uptr -> USTAT = STA_BOT; +MT_CLR_PNU (uptr); +uptr->USTAT = STA_BOT; mt_updcsta (mt_dev.units + GET_UNIT (mt_cu), 0); /* update status */ return r; } @@ -449,7 +479,8 @@ return r; t_stat mt_detach (UNIT* uptr) { -if (!sim_is_active (uptr)) uptr -> USTAT = 0; +MT_CLR_PNU (uptr); +if (!sim_is_active (uptr)) uptr->USTAT = 0; mt_updcsta (mt_dev.units + GET_UNIT (mt_cu), 0); /* update status */ return detach_unit (uptr); } diff --git a/PDP18B/pdp18b_rf.c b/PDP18B/pdp18b_rf.c index c85bcb2d..beef0729 100644 --- a/PDP18B/pdp18b_rf.c +++ b/PDP18B/pdp18b_rf.c @@ -26,6 +26,7 @@ rf (PDP-9) RF09/RF09 (PDP-15) RF15/RS09 + 05-Oct-02 RMS Added DIB, dev number support 06-Jan-02 RMS Revised enable/disable support 25-Nov-01 RMS Revised interrupt structure 24-Nov-01 RMS Changed WLK to array @@ -88,8 +89,9 @@ #define RF_BUSY (sim_is_active (&rf_unit)) extern int32 M[]; -extern int32 int_hwre[API_HLVL+1], dev_enb; +extern int32 int_hwre[API_HLVL+1]; extern UNIT cpu_unit; + int32 rf_sta = 0; /* status register */ int32 rf_da = 0; /* disk address */ int32 rf_dbuf = 0; /* data buffer */ @@ -97,6 +99,11 @@ int32 rf_wlk[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; /* write lock */ int32 rf_time = 10; /* inter-word time */ int32 rf_burst = 1; /* burst mode flag */ int32 rf_stopioe = 1; /* stop on error */ + +DEVICE rf_dev; +int32 rf70 (int32 pulse, int32 AC); +int32 rf72 (int32 pulse, int32 AC); +int32 rf_iors (void); t_stat rf_svc (UNIT *uptr); t_stat rf_reset (DEVICE *dptr); int32 rf_updsta (int32 new); @@ -108,6 +115,8 @@ int32 rf_updsta (int32 new); rf_reg RF register list */ +DIB rf_dib = { DEV_RF, 3, &rf_iors, { &rf70, NULL, &rf72 } }; + UNIT rf_unit = { UDATA (&rf_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, RF_SIZE) }; @@ -123,19 +132,19 @@ REG rf_reg[] = { { DRDATA (TIME, rf_time, 24), PV_LEFT + REG_NZ }, { FLDATA (BURST, rf_burst, 0) }, { FLDATA (STOP_IOE, rf_stopioe, 0) }, - { FLDATA (*DEVENB, dev_enb, ENB_V_RF), REG_HRO }, + { ORDATA (DEVNO, rf_dib.dev, 6), REG_HRO }, { NULL } }; MTAB rf_mod[] = { - { MTAB_XTD|MTAB_VDV, ENB_RF, NULL, "ENABLED", &set_enb }, - { MTAB_XTD|MTAB_VDV, ENB_RF, NULL, "DISABLED", &set_dsb }, + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno }, { 0 } }; DEVICE rf_dev = { "RF", &rf_unit, rf_reg, rf_mod, 1, 8, 21, 1, 8, 18, NULL, NULL, &rf_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &rf_dib, DEV_DISABLE }; /* IOT routines */ @@ -203,7 +212,7 @@ t_stat rf_svc (UNIT *uptr) { int32 f, pa, d, t; -if ((uptr -> flags & UNIT_BUF) == 0) { /* not buf? abort */ +if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */ rf_updsta (RFS_NED | RFS_DON); /* set nxd, done */ return IORETURN (rf_stopioe, SCPE_UNATT); } @@ -211,9 +220,9 @@ f = GET_FNC (rf_sta); /* get function */ do { M[RF_WC] = (M[RF_WC] + 1) & 0777777; /* incr word count */ pa = M[RF_CA] = (M[RF_CA] + 1) & ADDRMASK; /* incr mem addr */ if ((f == FN_READ) && MEM_ADDR_OK (pa)) /* read? */ - M[pa] = *(((int32 *) uptr -> filebuf) + rf_da); + M[pa] = *(((int32 *) uptr->filebuf) + rf_da); if ((f == FN_WCHK) && /* write check? */ - (M[pa] != *(((int32 *) uptr -> filebuf) + rf_da))) { + (M[pa] != *(((int32 *) uptr->filebuf) + rf_da))) { rf_updsta (RFS_WCE); /* flag error */ break; } if (f == FN_WRITE) { /* write? */ @@ -222,9 +231,9 @@ do { M[RF_WC] = (M[RF_WC] + 1) & 0777777; /* incr word count */ if ((rf_wlk[d] >> t) & 1) { /* write locked? */ rf_updsta (RFS_WLO); break; } - else { *(((int32 *) uptr -> filebuf) + rf_da) = M[pa]; - if (((t_addr) rf_da) >= uptr -> hwmark) - uptr -> hwmark = rf_da + 1; } } + else { *(((int32 *) uptr->filebuf) + rf_da) = M[pa]; + if (((t_addr) rf_da) >= uptr->hwmark) + uptr->hwmark = rf_da + 1; } } rf_da = rf_da + 1; /* incr disk addr */ if (rf_da > RF_SIZE) { /* disk overflow? */ rf_da = 0; diff --git a/PDP18B/pdp18b_rp.c b/PDP18B/pdp18b_rp.c index 53294718..721d9b64 100644 --- a/PDP18B/pdp18b_rp.c +++ b/PDP18B/pdp18b_rp.c @@ -25,6 +25,7 @@ rp RP15/RP02 disk pack + 05-Oct-02 RMS Added DIB, device number support 06-Jan-02 RMS Revised enable/disable support 29-Nov-01 RMS Added read only unit support 25-Nov-01 RMS Revised interrupt structure @@ -48,7 +49,6 @@ /* Unit specific flags */ #define UNIT_V_WLK (UNIT_V_UF + 0) /* hwre write lock */ -#define UNIT_W_UF 2 /* user flags width */ #define UNIT_WLK (1u << UNIT_V_WLK) #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ @@ -129,8 +129,9 @@ #define MAX(x,y) (((x) > (y))? (x): (y)) extern int32 M[]; -extern int32 int_hwre[API_HLVL+1], dev_enb, nexm; +extern int32 int_hwre[API_HLVL+1], nexm; extern UNIT cpu_unit; + int32 rp_sta = 0; /* status A */ int32 rp_stb = 0; /* status B */ int32 rp_ma = 0; /* memory address */ @@ -140,6 +141,11 @@ int32 rp_busy = 0; /* busy */ int32 rp_stopioe = 1; /* stop on error */ int32 rp_swait = 10; /* seek time */ int32 rp_rwait = 10; /* rotate time */ + +DEVICE rp_dev; +int32 rp63 (int32 pulse, int32 AC); +int32 rp64 (int32 pulse, int32 AC); +int32 rp_iors (void); t_stat rp_svc (UNIT *uptr); void rp_updsta (int32 newa, int32 newb); t_stat rp_reset (DEVICE *dptr); @@ -154,6 +160,8 @@ t_stat rp_detach (UNIT *uptr); rp_mod RP modifier list */ +DIB rp_dib = { DEV_RP, 2, &rp_iors, { &rp63, &rp64 } }; + UNIT rp_unit[] = { { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RP_SIZE) }, @@ -175,23 +183,21 @@ REG rp_reg[] = { { FLDATA (STOP_IOE, rp_stopioe, 0) }, { DRDATA (STIME, rp_swait, 24), PV_LEFT }, { DRDATA (RTIME, rp_rwait, 24), PV_LEFT }, - { URDATA (FLG, rp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, - RP_NUMDR, REG_HRO) }, - { FLDATA (*DEVENB, dev_enb, ENB_V_RP), REG_HRO }, + { ORDATA (DEVNO, rp_dib.dev, 6), REG_HRO }, { NULL } }; MTAB rp_mod[] = { { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, - { MTAB_XTD|MTAB_VDV, ENB_RP, NULL, "ENABLED", &set_enb }, - { MTAB_XTD|MTAB_VDV, ENB_RP, NULL, "DISABLED", &set_dsb }, + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno }, { 0 } }; DEVICE rp_dev = { "RP", rp_unit, rp_reg, rp_mod, RP_NUMDR, 8, 24, 1, 8, 18, NULL, NULL, &rp_reset, - NULL, &rp_attach, &rp_detach }; + NULL, &rp_attach, &rp_detach, + &rp_dib, DEV_DISABLE }; /* IOT routines */ @@ -251,16 +257,16 @@ if (rp_sta & STA_GO) { u = GET_UNIT (rp_sta); /* get unit num */ uptr = rp_dev.units + u; /* select unit */ if (sim_is_active (uptr)) return AC; /* can't if busy */ - f = uptr -> FUNC = GET_FUNC (rp_sta); /* get function */ + f = uptr->FUNC = GET_FUNC (rp_sta); /* get function */ rp_busy = 1; /* set ctrl busy */ rp_sta = rp_sta & ~(STA_HNF | STA_DON); /* clear flags */ rp_stb = rp_stb & ~(STB_FME | STB_WPE | STB_LON | STB_WCE | STB_TME | STB_PGE | STB_EOP | (1 << (STB_V_ATT0 - u))); - if (((uptr -> flags & UNIT_ATT) == 0) || (f == FN_IDLE) || + if (((uptr->flags & UNIT_ATT) == 0) || (f == FN_IDLE) || (f == FN_SEEK) || (f == FN_RECAL)) sim_activate (uptr, RP_MIN); /* short delay */ else { c = GET_CYL (rp_da); - c = abs (c - uptr -> CYL) * rp_swait; /* seek time */ + c = abs (c - uptr->CYL) * rp_swait; /* seek time */ sim_activate (uptr, MAX (RP_MIN, c + rp_rwait)); } } rp_updsta (0, 0); return AC; @@ -286,7 +292,7 @@ int32 f, u, comp, cyl, sect, surf; int32 err, pa, da, wc, awc, i; u = uptr - rp_dev.units; /* get drv number */ -f = uptr -> FUNC; /* get function */ +f = uptr->FUNC; /* get function */ if (f == FN_IDLE) { /* idle? */ rp_busy = 0; /* clear busy */ return SCPE_OK; } @@ -294,9 +300,9 @@ if (f == FN_IDLE) { /* idle? */ if ((f == FN_SEEK) || (f == FN_RECAL)) { /* seek or recal? */ rp_busy = 0; /* not busy */ cyl = (f == FN_SEEK)? GET_CYL (rp_da): 0; /* get cylinder */ - sim_activate (uptr, MAX (RP_MIN, abs (cyl - uptr -> CYL) * rp_swait)); - uptr -> CYL = cyl; /* on cylinder */ - uptr -> FUNC = FN_SEEK | FN_2ND; /* set second state */ + sim_activate (uptr, MAX (RP_MIN, abs (cyl - uptr->CYL) * rp_swait)); + uptr->CYL = cyl; /* on cylinder */ + uptr->FUNC = FN_SEEK | FN_2ND; /* set second state */ rp_updsta (0, 0); /* update status */ return SCPE_OK; } @@ -304,11 +310,11 @@ if (f == (FN_SEEK | FN_2ND)) { /* seek done? */ rp_updsta (0, rp_stb | (1 << (STB_V_ATT0 - u))); /* set attention */ return SCPE_OK; } -if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */ +if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ rp_updsta (STA_DON, STB_SUFU); /* done, unsafe */ return IORETURN (rp_stopioe, SCPE_UNATT); } -if ((f == FN_WRITE) && (uptr -> flags & UNIT_WPRT)) { /* write locked? */ +if ((f == FN_WRITE) && (uptr->flags & UNIT_WPRT)) { /* write locked? */ rp_updsta (STA_DON | STA_WPE, 0); /* error */ return SCPE_OK; } @@ -329,26 +335,26 @@ if ((da + wc) > RP_SIZE) { /* disk overrun? */ rp_updsta (0, STB_EOP); /* error */ wc = RP_SIZE - da; } /* limit xfer */ -err = fseek (uptr -> fileref, da * sizeof (int), SEEK_SET); +err = fseek (uptr->fileref, da * sizeof (int), SEEK_SET); if ((f == FN_READ) && (err == 0)) { /* read? */ - awc = fxread (&M[pa], sizeof (int32), wc, uptr -> fileref); + awc = fxread (&M[pa], sizeof (int32), wc, uptr->fileref); for ( ; awc < wc; awc++) M[pa + awc] = 0; - err = ferror (uptr -> fileref); } + err = ferror (uptr->fileref); } if ((f == FN_WRITE) && (err == 0)) { /* write? */ - fxwrite (&M[pa], sizeof (int32), wc, uptr -> fileref); - err = ferror (uptr -> fileref); + fxwrite (&M[pa], sizeof (int32), wc, uptr->fileref); + err = ferror (uptr->fileref); if ((err == 0) && (i = (wc & (RP_NUMWD - 1)))) { - fxwrite (fill, sizeof (int), i, uptr -> fileref); - err = ferror (uptr -> fileref); } } + fxwrite (fill, sizeof (int), i, uptr->fileref); + err = ferror (uptr->fileref); } } if ((f == FN_WRCHK) && (err == 0)) { /* write check? */ for (i = 0; (err == 0) && (i < wc); i++) { - awc = fxread (&comp, sizeof (int32), 1, uptr -> fileref); + awc = fxread (&comp, sizeof (int32), 1, uptr->fileref); if (awc == 0) comp = 0; if (comp != M[pa + i]) rp_updsta (0, STB_WCE); } - err = ferror (uptr -> fileref); } + err = ferror (uptr->fileref); } rp_wc = (rp_wc + wc) & 0777777; /* final word count */ rp_ma = (rp_ma + wc) & 0777777; /* final mem addr */ @@ -363,7 +369,7 @@ rp_updsta (STA_DON, 0); /* set done */ if (err != 0) { /* error? */ perror ("RP I/O error"); - clearerr (uptr -> fileref); + clearerr (uptr->fileref); return IORETURN (rp_stopioe, SCPE_IOERR); } return SCPE_OK; } @@ -378,13 +384,13 @@ UNIT *uptr; uptr = rp_dev.units + GET_UNIT (rp_sta); rp_sta = (rp_sta & ~(STA_DYN | STA_ERR)) | newa; rp_stb = (rp_stb & ~STB_DYN) | newb; -if (uptr -> flags & UNIT_WPRT) rp_sta = rp_sta | STA_SUWP; -if ((uptr -> flags & UNIT_ATT) == 0) rp_stb = rp_stb | STB_SUFU | STB_SUNR; +if (uptr->flags & UNIT_WPRT) rp_sta = rp_sta | STA_SUWP; +if ((uptr->flags & UNIT_ATT) == 0) rp_stb = rp_stb | STB_SUFU | STB_SUNR; else if (sim_is_active (uptr)) { - f = (uptr -> FUNC) & STA_M_FUNC; + f = (uptr->FUNC) & STA_M_FUNC; if ((f == FN_SEEK) || (f == FN_RECAL)) rp_stb = rp_stb | STB_SUSU | STB_SUNR; } -else if (uptr -> CYL >= RP_NUMCY) rp_sta = rp_sta | STA_SUSI; +else if (uptr->CYL >= RP_NUMCY) rp_sta = rp_sta | STA_SUSI; if ((rp_sta & STA_EFLGS) || (rp_stb & STB_EFLGS)) rp_sta = rp_sta | STA_ERR; if (((rp_sta & (STA_ERR | STA_DON)) && (rp_sta & STA_IED)) || ((rp_stb & STB_ATTN) && (rp_sta & STA_IEA))) SET_INT (RP); @@ -404,7 +410,7 @@ CLR_INT (RP); for (i = 0; i < RP_NUMDR; i++) { uptr = rp_dev.units + i; sim_cancel (uptr); - uptr -> CYL = uptr -> FUNC = 0; } + uptr->CYL = uptr->FUNC = 0; } return SCPE_OK; } diff --git a/PDP18B/pdp18b_stddev.c b/PDP18B/pdp18b_stddev.c index a9ecc1fc..30364897 100644 --- a/PDP18B/pdp18b_stddev.c +++ b/PDP18B/pdp18b_stddev.c @@ -29,6 +29,8 @@ tto teleprinter clk clock + 01-Nov-02 RMS Added 7B/8B support to terminal + 05-Oct-02 RMS Added DIBs, device number support, IORS call 14-Jul-02 RMS Added ASCII reader/punch support (from Hans Pufal) 30-May-02 RMS Widened POS to 32b 29-Nov-01 RMS Added read only unit support @@ -50,9 +52,9 @@ #include "pdp18b_defs.h" #include -#define UNIT_V_RASCII UNIT_V_UF /* reader ASCII */ +#define UNIT_V_RASCII (UNIT_V_UF + 0) /* reader ASCII */ #define UNIT_RASCII (1 << UNIT_V_RASCII) -#define UNIT_V_PASCII UNIT_V_UF /* punch ASCII */ +#define UNIT_V_PASCII (UNIT_V_UF + 0) /* punch ASCII */ #define UNIT_PASCII (1 << UNIT_V_PASCII) extern int32 M[]; @@ -68,6 +70,15 @@ int32 tto_state = 0; int32 clk_tps = 60; /* ticks/second */ int32 tmxr_poll = 16000; /* term mux poll */ +int32 ptr (int32 pulse, int32 AC); +int32 ptp (int32 pulse, int32 AC); +int32 tti (int32 pulse, int32 AC); +int32 tto (int32 pulse, int32 AC); +int32 clk_iors (void); +int32 ptr_iors (void); +int32 ptp_iors (void); +int32 tti_iors (void); +int32 tto_iors (void); t_stat clk_svc (UNIT *uptr); t_stat ptr_svc (UNIT *uptr); t_stat ptp_svc (UNIT *uptr); @@ -82,7 +93,10 @@ t_stat ptr_attach (UNIT *uptr, char *cptr); t_stat ptp_attach (UNIT *uptr, char *cptr); t_stat ptr_detach (UNIT *uptr); t_stat ptp_detach (UNIT *uptr); -t_stat ptr_boot (int32 unitno); +t_stat ptr_boot (int32 unitno, DEVICE *dptr); +t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); + +extern int32 upd_iors (void); /* CLK data structures @@ -91,6 +105,8 @@ t_stat ptr_boot (int32 unitno); clk_reg CLK register list */ +DIB clk_dib = { 0, 0, &clk_iors, { NULL } }; + UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 16000 }; REG clk_reg[] = { @@ -101,11 +117,16 @@ REG clk_reg[] = { { DRDATA (TPS, clk_tps, 8), REG_NZ + PV_LEFT }, { NULL } }; +MTAB clk_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_devno }, + { 0 } }; + DEVICE clk_dev = { - "CLK", &clk_unit, clk_reg, NULL, + "CLK", &clk_unit, clk_reg, clk_mod, 1, 0, 0, 0, 0, 0, NULL, NULL, &clk_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &clk_dib, 0 }; /* PTR data structures @@ -114,6 +135,8 @@ DEVICE clk_dev = { ptr_reg PTR register list */ +DIB ptr_dib = { DEV_PTR, 1, &ptr_iors, { &ptr } }; + UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), SERIAL_IN_WAIT }; @@ -129,14 +152,18 @@ REG ptr_reg[] = { { DRDATA (POS, ptr_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptr_stopioe, 0) }, - { FLDATA (ASCII, ptr_unit.flags, UNIT_V_RASCII), REG_HRO }, { NULL } }; +MTAB ptr_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_devno }, + { 0 } }; + DEVICE ptr_dev = { - "PTR", &ptr_unit, ptr_reg, NULL, + "PTR", &ptr_unit, ptr_reg, ptr_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptr_reset, - &ptr_boot, &ptr_attach, &ptr_detach }; + &ptr_boot, &ptr_attach, &ptr_detach, + &ptr_dib, 0 }; /* PTP data structures @@ -145,6 +172,8 @@ DEVICE ptr_dev = { ptp_reg PTP register list */ +DIB ptp_dib = { DEV_PTP, 1, &ptp_iors, { &ptp } }; + UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; @@ -158,14 +187,18 @@ REG ptp_reg[] = { { DRDATA (POS, ptp_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, ptp_stopioe, 0) }, - { FLDATA (ASCII, ptp_unit.flags, UNIT_V_PASCII), REG_HRO }, { NULL } }; +MTAB ptp_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_devno }, + { 0 } }; + DEVICE ptp_dev = { - "PTP", &ptp_unit, ptp_reg, NULL, + "PTP", &ptp_unit, ptp_reg, ptp_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptp_reset, - NULL, &ptp_attach, &ptp_detach }; + NULL, &ptp_attach, &ptp_detach, + &ptp_dib, 0 }; /* TTI data structures @@ -206,15 +239,19 @@ static const int32 tti_trans[128] = { #endif #define TTI_MASK ((1 << TTI_WIDTH) - 1) -#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */ -#define UNIT_UC (1 << UNIT_V_UC) -#define UNIT_V_HDX (UNIT_V_UF + 1) /* half duplex */ +#define UNIT_V_8B (UNIT_V_UF + 0) /* 8B */ +#define UNIT_V_KSR (UNIT_V_UF + 1) /* KSR33 */ +#define UNIT_V_HDX (UNIT_V_UF + 2) /* half duplex */ +#define UNIT_8B (1 << UNIT_V_8B) +#define UNIT_KSR (1 << UNIT_V_KSR) #define UNIT_HDX (1 << UNIT_V_HDX) +DIB tti_dib = { DEV_TTI, 1, &tti_iors, { &tti } }; + #if defined (PDP4) || defined (PDP7) -UNIT tti_unit = { UDATA (&tti_svc, UNIT_UC, 0), KBD_POLL_WAIT }; +UNIT tti_unit = { UDATA (&tti_svc, UNIT_KSR, 0), KBD_POLL_WAIT }; #else -UNIT tti_unit = { UDATA (&tti_svc, UNIT_UC+UNIT_HDX, 0), KBD_POLL_WAIT }; +UNIT tti_unit = { UDATA (&tti_svc, UNIT_KSR+UNIT_HDX, 0), KBD_POLL_WAIT }; #endif REG tti_reg[] = { @@ -223,9 +260,6 @@ REG tti_reg[] = { { FLDATA (DONE, int_hwre[API_TTI], INT_V_TTI) }, #if defined (KSR28) { ORDATA (TTI_STATE, tti_state, (TTI_WIDTH + 3)), REG_HRO }, -#else - { FLDATA (UC, tti_unit.flags, UNIT_V_UC), REG_HRO }, - { FLDATA (HDX, tti_unit.flags, UNIT_V_HDX), REG_HRO }, #endif { DRDATA (POS, tti_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, @@ -233,18 +267,21 @@ REG tti_reg[] = { MTAB tti_mod[] = { #if !defined (KSR28) - { UNIT_UC, 0, "lower case", "LC", NULL }, - { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, - { UNIT_HDX, 0, "full duplex", "FDX", NULL }, + { UNIT_KSR+UNIT_8B, UNIT_KSR, "KSR", "KSR", &tty_set_mode }, + { UNIT_KSR+UNIT_8B, 0 , "7b" , "7B" , &tty_set_mode }, + { UNIT_KSR+UNIT_8B, UNIT_8B , "8b" , "8B" , &tty_set_mode }, + { UNIT_HDX, 0 , "full duplex", "FDX", NULL }, { UNIT_HDX, UNIT_HDX, "half duplex", "HDX", NULL }, #endif + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_devno }, { 0 } }; DEVICE tti_dev = { "TTI", &tti_unit, tti_reg, tti_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &tti_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &tti_dib, 0 }; /* TTO data structures @@ -274,7 +311,9 @@ static const char tto_trans[64] = { #define TTO_MASK ((1 << TTO_WIDTH) - 1) -UNIT tto_unit = { UDATA (&tto_svc, UNIT_UC, 0), SERIAL_OUT_WAIT }; +DIB tto_dib = { DEV_TTO, 1, &tto_iors, { &tto } }; + +UNIT tto_unit = { UDATA (&tto_svc, UNIT_KSR, 0), SERIAL_OUT_WAIT }; REG tto_reg[] = { { ORDATA (BUF, tto_unit.buf, TTO_WIDTH) }, @@ -289,16 +328,19 @@ REG tto_reg[] = { MTAB tto_mod[] = { #if !defined (KSR28) - { UNIT_UC, 0, "lower case", "LC", NULL }, - { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, + { UNIT_KSR+UNIT_8B, UNIT_KSR, "KSR", "KSR", &tty_set_mode }, + { UNIT_KSR+UNIT_8B, 0 , "7b" , "7B" , &tty_set_mode }, + { UNIT_KSR+UNIT_8B, UNIT_8B , "8b" , "8B" , &tty_set_mode }, #endif + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_devno }, { 0 } }; DEVICE tto_dev = { "TTO", &tto_unit, tto_reg, tto_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &tto_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &tto_dib, 0 }; /* Clock: IOT routine */ @@ -332,6 +374,13 @@ if (clk_state) { /* clock on? */ return SCPE_OK; } +/* IORS service */ + +int32 clk_iors (void) +{ +return (TST_INT (CLK)? IOS_CLK: 0); +} + /* Reset routine */ t_stat clk_reset (DEVICE *dptr) @@ -342,24 +391,6 @@ sim_cancel (&clk_unit); /* stop clock */ tmxr_poll = clk_unit.wait; /* set mux poll */ return SCPE_OK; } - -/* IORS service for all standard devices */ - -int32 std_iors (void) -{ -return ((TST_INT (CLK)? IOS_CLK: 0) | - (TST_INT (PTR)? IOS_PTR: 0) | - (TST_INT (PTP)? IOS_PTP: 0) | - (TST_INT (TTI)? IOS_TTI: 0) | - (TST_INT (TTO)? IOS_TTO: 0) | -#if defined (IOS_PTRERR) - (ptr_err? IOS_PTRERR: 0) | -#endif -#if defined (IOS_PTPERR) - (ptp_err? IOS_PTPERR: 0) | -#endif - (clk_state? IOS_CLKON: 0)); -} /* Paper tape reader: IOT routine */ @@ -423,6 +454,17 @@ ptr_err = (ptr_unit.flags & UNIT_ATT)? 0: 1; sim_cancel (&ptr_unit); /* deactivate unit */ return SCPE_OK; } + +/* IORS service */ + +int32 ptr_iors (void) +{ +return ((TST_INT (PTR)? IOS_PTR: 0) +#if defined (IOS_PTRERR) + | (ptr_err? IOS_PTRERR: 0) +#endif + ); +} /* Attach routine */ @@ -592,11 +634,12 @@ static const int32 boot_rom[] = { 0617771 /* jmp g */ }; -t_stat ptr_boot (int32 unitno) +t_stat ptr_boot (int32 unitno, DEVICE *dptr) { int32 i, mask, wd; extern int32 sim_switches; +if (ptr_dib.dev != DEV_PTR) return STOP_NONSTD; /* non-std addr? */ if (MEMSIZE < 8192) mask = 0767777; /* 4k? */ else mask = 0777777; for (i = 0; i < BOOT_LEN; i++) { @@ -611,7 +654,7 @@ return SCPE_OK; /* PDP-9 and PDP-15 have built-in hardware RIM loaders */ -t_stat ptr_boot (int32 unitno) +t_stat ptr_boot (int32 unitno, DEVICE *dptr) { return SCPE_ARG; } @@ -653,6 +696,17 @@ if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { /* I/O error? */ ptp_unit.pos = ptp_unit.pos + 1; return SCPE_OK; } + +/* IORS service */ + +int32 ptp_iors (void) +{ +return ((TST_INT (PTP)? IOS_PTP: 0) +#if defined (IOS_PTPERR) + | (ptp_err? IOS_PTPERR: 0) +#endif + ); +} /* Reset routine */ @@ -696,6 +750,8 @@ if (pulse & 001) { /* KSF */ if (pulse & 002) { /* KRB */ CLR_INT (TTI); /* clear flag */ AC = AC | tti_unit.buf & TTI_MASK; } /* return buffer */ +if (pulse & 004) { /* IORS */ + AC = AC | upd_iors (); } return AC; } @@ -703,38 +759,52 @@ return AC; t_stat tti_svc (UNIT *uptr) { -int32 temp; +#if defined (KSR28) /* Baudot... */ +int32 c; sim_activate (&tti_unit, tti_unit.wait); /* continue poll */ - -#if defined (KSR28) /* Baudot... */ if (tti_state & TTI_2ND) { /* char waiting? */ tti_unit.buf = tti_state & TTI_MASK; /* return char */ tti_state = tti_state & ~TTI_2ND; } /* not waiting */ -else { if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; - temp = tti_trans[temp & 0177]; /* translate char */ - if (temp == 0) return SCPE_OK; /* untranslatable? */ - if (((temp & TTI_FIGURES) == (tti_state & TTI_FIGURES)) || - (temp & TTI_BOTH)) tti_unit.buf = temp & TTI_MASK; - else { tti_unit.buf = (temp & TTI_FIGURES)? +else { if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; + c = tti_trans[c & 0177]; /* translate char */ + if (c == 0) return SCPE_OK; /* untranslatable? */ + if (((c & TTI_FIGURES) == (tti_state & TTI_FIGURES)) || + (c & TTI_BOTH)) tti_unit.buf = c & TTI_MASK; + else { tti_unit.buf = (c & TTI_FIGURES)? BAUDOT_FIGURES: BAUDOT_LETTERS; - tti_state = temp | TTI_2ND; } } /* set 2nd waiting */ + tti_state = c | TTI_2ND; } } /* set 2nd waiting */ + #else /* ASCII... */ -if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */ -temp = temp & 0177; -if ((tti_unit.flags & UNIT_UC) && islower (temp)) temp = toupper (temp); -if ((tti_unit.flags & UNIT_HDX) && - (!(tto_unit.flags & UNIT_UC) || - ((temp >= 007) && (temp <= 0137)))) { - sim_putchar (temp); +int32 c, out; + +sim_activate (&tti_unit, tti_unit.wait); /* continue poll */ +if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */ +out = c & 0177; /* mask echo to 7b */ +if (tti_unit.flags & UNIT_KSR) { /* KSR? */ + if (islower (out)) out = toupper (out); /* convert to UC */ + c = out | 0200; } /* set TTY bit */ +else c = c & ((tti_unit.flags & UNIT_8B)? 0377: 0177); /* no, 7b/8b */ +if ((tti_unit.flags & UNIT_HDX) && /* half duplex and */ + (!(tto_unit.flags & UNIT_KSR) || /* 7b/8b or */ + ((out >= 007) && (out <= 0137)))) { /* in range? */ + sim_putchar (out); /* echo */ tto_unit.pos = tto_unit.pos + 1; } -tti_unit.buf = temp | 0200; /* got char */ +tti_unit.buf = c; /* got char */ + #endif SET_INT (TTI); /* set flag */ tti_unit.pos = tti_unit.pos + 1; return SCPE_OK; } +/* IORS service */ + +int32 tti_iors (void) +{ +return (TST_INT (TTI)? IOS_TTI: 0); +} + /* Reset routine */ t_stat tti_reset (DEVICE *dptr) @@ -763,7 +833,8 @@ return AC; t_stat tto_svc (UNIT *uptr) { -int32 out, temp; +int32 c; +t_stat r; SET_INT (TTO); /* set flag */ #if defined (KSR28) /* Baudot... */ @@ -773,18 +844,26 @@ if (tto_unit.buf == BAUDOT_FIGURES) { /* set figures? */ if (tto_unit.buf == BAUDOT_LETTERS) { /* set letters? */ tto_state = 0; return SCPE_OK; } -out = tto_trans[tto_unit.buf + tto_state]; /* translate */ +c = tto_trans[tto_unit.buf + tto_state]; /* translate */ #else -out = tto_unit.buf & 0177; /* ASCII... */ +if (tto_unit.flags & UNIT_KSR) { /* KSR? */ + c = tto_unit.buf & 0177; + if (islower (c)) c = toupper (c); + if ((c < 007) || (c > 0137)) return SCPE_OK; } +else c = tto_unit.buf & ((tto_unit.flags & UNIT_8B)? 0377: 0177); #endif -if (!(tto_unit.flags & UNIT_UC) || - ((out >= 007) && (out <= 0137))) { - temp = sim_putchar (out); - if (temp != SCPE_OK) return temp; - tto_unit.pos = tto_unit.pos + 1; } +if ((r = sim_putchar (c)) != SCPE_OK) return r; +tto_unit.pos = tto_unit.pos + 1; return SCPE_OK; } +/* IORS service */ + +int32 tto_iors (void) +{ +return (TST_INT (TTO)? IOS_TTO: 0); +} + /* Reset routine */ t_stat tto_reset (DEVICE *dptr) @@ -795,3 +874,10 @@ CLR_INT (TTO); /* clear flag */ sim_cancel (&tto_unit); /* deactivate unit */ return SCPE_OK; } + +t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +tti_unit.flags = (tti_unit.flags & ~(UNIT_KSR | UNIT_8B)) | val; +tto_unit.flags = (tto_unit.flags & ~(UNIT_KSR | UNIT_8B)) | val; +return SCPE_OK; +} diff --git a/PDP18B/pdp18b_sys.c b/PDP18B/pdp18b_sys.c index 9545ad06..2f386b72 100644 --- a/PDP18B/pdp18b_sys.c +++ b/PDP18B/pdp18b_sys.c @@ -23,6 +23,8 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 05-Oct-02 RMS Added variable device number support + 25-Jul-02 RMS Added PDP-4 DECtape support 10-Feb-02 RMS Added PDP-7 DECtape IOT's 03-Feb-02 RMS Fixed typo (found by Robert Alan Byer) 17-Sep-01 RMS Removed multiconsole support @@ -47,6 +49,7 @@ extern DEVICE tti_dev, tto_dev; extern UNIT tti_unit, tto_unit; extern DEVICE clk_dev; extern DEVICE lpt_dev; +extern DEVICE dt_dev; #if defined (DRM) extern DEVICE drm_dev; #endif @@ -59,9 +62,6 @@ extern DEVICE rp_dev; #if defined (MTA) extern DEVICE mt_dev; #endif -#if defined (DTA) -extern DEVICE dt_dev; -#endif #if defined (TTY1) extern DEVICE tti1_dev, tto1_dev; extern UNIT tti1_unit, tto1_unit; @@ -109,9 +109,7 @@ DEVICE *sim_devices[] = { &cpu_dev, #if defined (RP) &rp_dev, #endif -#if defined (DTA) &dt_dev, -#endif #if defined (MTA) &mt_dev, #endif @@ -126,7 +124,8 @@ const char *sim_stop_messages[] = { "HALT instruction", "Breakpoint", "Nested XCT's", - "Invalid API interrupt" }; + "Invalid API interrupt", + "Non-standard device number" }; /* Binary loader */ @@ -238,7 +237,7 @@ for (;;) { /* block loop */ if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT; if (val & SIGN) { if (val != DMASK) saved_PC = val & 077777; - return SCPE_OK; } + break; } cksum = origin = val; /* save origin */ if ((val = getword (fileref, NULL)) < 0) return SCPE_FMT; cksum = cksum + val; /* add to cksum */ @@ -250,7 +249,7 @@ for (;;) { /* block loop */ cksum = cksum + val; if (MEM_ADDR_OK (origin)) M[origin++] = val; } if ((cksum & DMASK) != 0) return SCPE_CSUM; } -return SCPE_FMT; +return SCPE_OK; } #endif @@ -361,15 +360,13 @@ static const char *opcode[] = { "MTTR", "MTCR", "MTSF", "MTRC", "MTAF", "MTRS", "MTGO", "MTCM", "MTLC", #endif -#if defined (DTA) /* DECtape */ -#if defined (PDP7) /* Type 550 */ +#if defined (TYPE550) /* Type 550 */ "MMDF", "MMEF", "MMRD", "MMWR", "MMBF", "MMRS", "MMLC", "MMSE", -#elif defined (PDP9) || defined (PDP15) /* TC02/TC15 */ +#elif defined (TC02) /* TC02/TC15 */ "DTCA", "DTRA", "DTXA", "DTLA", "DTEF", "DTRB", "DTDF", #endif -#endif #if defined (TTY1) "KSF1", "KRB1", "TSF1", "TCF1", "TLS1", "TCF1!TLS1", @@ -517,15 +514,13 @@ static const int32 opc_val[] = { 0707301+I_NPI, 0707321+I_NPI, 0707341+I_NPI, 0707312+I_NPN, 0707322+I_NPI, 0707352+I_NPN, 0707304+I_NPI, 0707324+I_NPI, 0707326+I_NPI, #endif -#if defined (DTA) -#if defined (PDP7) /* Type 550 */ +#if defined (TYPE550) /* Type 550 */ 0707501+I_NPI, 0707541+I_NPI, 0707512+I_NPN, 0707504+I_NPI, 0707601+I_NPI, 0707612+I_NPN, 0707604+I_NPI, 0707644+I_NPI, -#elif defined (PDP9) || defined (PDP15) /* TC02/TC15 */ +#elif defined (TC02) /* TC02/TC15 */ 0707541+I_NPI, 0707552+I_NPN, 0707544+I_NPI, 0707545+I_NPI, 0707561+I_NPI, 0707572+I_NPN, 0707601+I_NPI, #endif -#endif #if defined (TTY1) 0704101+I_NPI, 0704112+I_NPN, 0704001+I_NPI, 0704002+I_NPI, 0704004+I_NPI, 0704006+I_NPI, @@ -639,7 +634,6 @@ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, int32 cflag, i, j, k, sp, inst, disp, ma; inst = val[0]; -i = val[1]; cflag = (uptr == NULL) || (uptr == &cpu_unit); if (sw & SWMASK ('A')) { /* ASCII? */ if (inst > 0377) return SCPE_ARG; @@ -652,6 +646,7 @@ if (sw & SWMASK ('C')) { /* character? */ return SCPE_OK; } #if defined (PDP15) if (sw & SWMASK ('P')) { /* packed ASCII? */ + i = val[1]; fprintf (of, "%c", FMTASC ((inst >> 11) & 0177)); fprintf (of, "%c", FMTASC ((inst >> 4) & 0177)); fprintf (of, "%c", FMTASC (((inst << 3) | (i >> 15)) & 0177)); diff --git a/PDP18B/pdp18b_tt1.c b/PDP18B/pdp18b_tt1.c index de7c0c23..7544d558 100644 --- a/PDP18B/pdp18b_tt1.c +++ b/PDP18B/pdp18b_tt1.c @@ -26,6 +26,9 @@ tti1 keyboard tto1 teleprinter + 02-Nov-02 RMS Added 7B/8B support + 05-Oct-02 RMS Added DIB, device number support + 22-Aug-02 RMS Updated for changes to sim_tmxr 30-May-02 RMS Widened POS to 32b 06-Jan-02 RMS Added enable/disable support 30-Dec-01 RMS Added show statistics, set disconnect @@ -42,14 +45,19 @@ #include "sim_tmxr.h" #include -#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */ -#define UNIT_UC (1 << UNIT_V_UC) +#define UNIT_V_8B (UNIT_V_UF + 0) /* 8B */ +#define UNIT_V_KSR (UNIT_V_UF + 1) /* KSR33 */ +#define UNIT_8B (1 << UNIT_V_8B) +#define UNIT_KSR (1 << UNIT_V_KSR) extern int32 int_hwre[API_HLVL+1], dev_enb; extern int32 tmxr_poll; /* calibrated poll */ TMLN tt1_ldsc = { 0 }; /* line descriptors */ -TMXR tt_desc = { 1, 0, &tt1_ldsc }; /* mux descriptor */ +TMXR tt_desc = { 1, 0, 0, &tt1_ldsc }; /* mux descriptor */ +DEVICE tti1_dev, tto1_dev; +int32 tti1 (int32 pulse, int32 AC); +int32 tto1 (int32 pulse, int32 AC); t_stat tti1_svc (UNIT *uptr); t_stat tto1_svc (UNIT *uptr); t_stat tti1_reset (DEVICE *dptr); @@ -58,6 +66,8 @@ t_stat tti1_attach (UNIT *uptr, char *cptr); t_stat tti1_detach (UNIT *uptr); t_stat tti1_summ (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat tti1_show (FILE *st, UNIT *uptr, int32 val, void *desc); +void tt1_enbdis (int32 dis); +t_stat tt1_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); /* TTI1 data structures @@ -67,21 +77,23 @@ t_stat tti1_show (FILE *st, UNIT *uptr, int32 val, void *desc); tti1_reg TTI1 register list */ -UNIT tti1_unit = { UDATA (&tti1_svc, UNIT_ATTABLE+UNIT_UC, 0), KBD_POLL_WAIT }; +DIB tti1_dib = { DEV_TTI1, 1, NULL, { &tti1 } }; + +UNIT tti1_unit = { UDATA (&tti1_svc, UNIT_ATTABLE+UNIT_KSR, 0), KBD_POLL_WAIT }; REG tti1_reg[] = { { ORDATA (BUF, tti1_unit.buf, 8) }, { FLDATA (INT, int_hwre[API_TTI1], INT_V_TTI1) }, { FLDATA (DONE, int_hwre[API_TTI1], INT_V_TTI1) }, - { FLDATA (UC, tti1_unit.flags, UNIT_V_UC), REG_HRO }, { DRDATA (POS, tt1_ldsc.rxcnt, 32), PV_LEFT }, { DRDATA (TIME, tti1_unit.wait, 24), REG_NZ + PV_LEFT }, - { FLDATA (*DEVENB, dev_enb, ENB_V_TTI1), REG_HRO }, + { ORDATA (DEVNO, tti1_dib.dev, 6), REG_HRO }, { NULL } }; MTAB tti1_mod[] = { - { UNIT_UC, 0, "lower case", "LC", NULL }, - { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, + { UNIT_KSR+UNIT_8B, UNIT_KSR, "KSR", "KSR", &tt1_set_mode }, + { UNIT_KSR+UNIT_8B, 0 , "7b" , "7B" , &tt1_set_mode }, + { UNIT_KSR+UNIT_8B, UNIT_8B , "8b" , "8B" , &tt1_set_mode }, { UNIT_ATT, UNIT_ATT, "summary", NULL, NULL, &tti1_summ }, { MTAB_XTD | MTAB_VDV, 0, NULL, "DISCONNECT", &tmxr_dscln, NULL, &tt_desc }, @@ -89,15 +101,15 @@ MTAB tti1_mod[] = { NULL, &tti1_show, NULL }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, NULL, &tti1_show, NULL }, - { MTAB_XTD|MTAB_VDV, ENB_TTI1, NULL, "ENABLED", &set_enb }, - { MTAB_XTD|MTAB_VDV, ENB_TTI1, NULL, "DISABLED", &set_dsb }, + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno }, { 0 } }; DEVICE tti1_dev = { "TTI1", &tti1_unit, tti1_reg, tti1_mod, 1, 10, 31, 1, 8, 8, &tmxr_ex, &tmxr_dep, &tti1_reset, - NULL, &tti1_attach, &tti1_detach }; + NULL, &tti1_attach, &tti1_detach, + &tti1_dib, DEV_DISABLE }; /* TTO1 data structures @@ -107,7 +119,9 @@ DEVICE tti1_dev = { tto1_reg TTO1 register list */ -UNIT tto1_unit = { UDATA (&tto1_svc, UNIT_UC, 0), SERIAL_OUT_WAIT }; +DIB tto1_dib = { DEV_TTO1, 1, NULL, { &tto1 } }; + +UNIT tto1_unit = { UDATA (&tto1_svc, UNIT_KSR, 0), SERIAL_OUT_WAIT }; REG tto1_reg[] = { { ORDATA (BUF, tto1_unit.buf, 8) }, @@ -115,19 +129,22 @@ REG tto1_reg[] = { { FLDATA (DONE, int_hwre[API_TTO1], INT_V_TTO1) }, { DRDATA (POS, tt1_ldsc.txcnt, 32), PV_LEFT }, { DRDATA (TIME, tto1_unit.wait, 24), PV_LEFT }, - { FLDATA (*DEVENB, dev_enb, ENB_V_TTI1), REG_HRO }, + { ORDATA (DEVNO, tto1_dib.dev, 6), REG_HRO }, { NULL } }; MTAB tto1_mod[] = { - { UNIT_UC, 0, "lower case", "LC", NULL }, - { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, + { UNIT_KSR+UNIT_8B, UNIT_KSR, "KSR", "KSR", &tt1_set_mode }, + { UNIT_KSR+UNIT_8B, 0 , "7b" , "7B" , &tt1_set_mode }, + { UNIT_KSR+UNIT_8B, UNIT_8B , "8b" , "8B" , &tt1_set_mode }, + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno }, { 0 } }; DEVICE tto1_dev = { "TTO1", &tto1_unit, tto1_reg, tto1_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &tto1_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &tto1_dib, DEV_DISABLE }; /* Terminal input: IOT routine */ @@ -145,22 +162,23 @@ return AC; t_stat tti1_svc (UNIT *uptr) { -int32 temp, newln; +int32 c, newln; if (tt1_ldsc.conn) { /* connected? */ tmxr_poll_rx (&tt_desc); /* poll for input */ - if (temp = tmxr_getc_ln (&tt1_ldsc)) { /* get char */ - temp = temp & 0177; - if ((uptr -> flags & UNIT_UC) && - islower (temp)) temp = toupper (temp); - uptr -> buf = temp | 0200; /* got char */ - SET_INT (TTI1); } /* set flag */ - sim_activate (uptr, uptr -> wait); } /* continue poll */ -if (uptr -> flags & UNIT_ATT) { /* attached? */ - newln = tmxr_poll_conn (&tt_desc, uptr); /* poll connect */ + if (c = tmxr_getc_ln (&tt1_ldsc)) { /* get char */ + if (uptr->flags & UNIT_KSR) { /* KSR? */ + c = c & 0177; + if (islower (c)) c = toupper (c); + uptr->buf = c | 0200; } /* got char */ + else c = c & ((tti1_unit.flags & UNIT_8B)? 0377: 0177); + SET_INT (TTI1); } /* set flag */ + sim_activate (uptr, uptr->wait); } /* continue poll */ +if (uptr->flags & UNIT_ATT) { /* attached? */ + newln = tmxr_poll_conn (&tt_desc); /* poll connect */ if (newln >= 0) { /* got one? */ - sim_activate (&tti1_unit, tti1_unit.wait); - tt1_ldsc.rcve = 1; } /* rcv enabled */ + sim_activate (&tti1_unit, tti1_unit.wait); + tt1_ldsc.rcve = 1; } /* rcv enabled */ sim_activate (uptr, tmxr_poll); } /* sched poll */ return SCPE_OK; } @@ -169,6 +187,7 @@ return SCPE_OK; t_stat tti1_reset (DEVICE *dptr) { +tt1_enbdis (dptr->flags & DEV_DIS); /* sync enables */ tti1_unit.buf = 0; /* clear buffer */ CLR_INT (TTI1); /* clear flag */ if (tt1_ldsc.conn) { /* if conn, */ @@ -197,19 +216,23 @@ return AC; t_stat tto1_svc (UNIT *uptr) { -int32 out; +int32 c; SET_INT (TTO1); /* set flag */ -out = tto1_unit.buf & 0177; +c = tto1_unit.buf & 0177; if (tt1_ldsc.conn) { /* connected? */ if (tt1_ldsc.xmte) { /* tx enabled? */ - if (!(tto1_unit.flags & UNIT_UC) || - ((out >= 007) && (out <= 0137))) - tmxr_putc_ln (&tt1_ldsc, out); /* output char */ - tmxr_poll_tx (&tt_desc); } /* poll xmt */ - else { tmxr_poll_tx (&tt_desc); /* poll xmt */ - sim_activate (&tto1_unit, tmxr_poll); /* wait */ - return SCPE_OK; } } + if (tto1_unit.flags & UNIT_KSR) { /* KSR? */ + c = c & 0177; + if (islower (c)) c = toupper (c); + if ((c < 007) || (c > 0137)) c = 0; } + else c = c & ((tto1_unit.flags & UNIT_8B)? 0377: 0177); + if (c) tmxr_putc_ln (&tt1_ldsc, c); /* output char */ + tmxr_poll_tx (&tt_desc); } /* poll xmt */ + else { + tmxr_poll_tx (&tt_desc); /* poll xmt */ + sim_activate (&tto1_unit, tmxr_poll); /* wait */ + return SCPE_OK; } } return SCPE_OK; } @@ -217,6 +240,7 @@ return SCPE_OK; t_stat tto1_reset (DEVICE *dptr) { +tt1_enbdis (dptr->flags & DEV_DIS); /* sync enables */ tto1_unit.buf = 0; /* clear buffer */ CLR_INT (TTO1); /* clear flag */ sim_cancel (&tto1_unit); /* deactivate unit */ @@ -264,3 +288,22 @@ if (val) tmxr_fconns (st, &tt1_ldsc, -1); else tmxr_fstats (st, &tt1_ldsc, -1); return SCPE_OK; } + +/* Enable/disable device */ + +void tt1_enbdis (int32 dis) +{ +if (dis) { + tti1_dev.flags = tto1_dev.flags | DEV_DIS; + tto1_dev.flags = tto1_dev.flags | DEV_DIS; } +else { tti1_dev.flags = tti1_dev.flags & ~DEV_DIS; + tto1_dev.flags = tto1_dev.flags & ~DEV_DIS; } +return; +} + +t_stat tt1_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +tti1_unit.flags = (tti1_unit.flags & ~(UNIT_KSR | UNIT_8B)) | val; +tto1_unit.flags = (tto1_unit.flags & ~(UNIT_KSR | UNIT_8B)) | val; +return SCPE_OK; +} \ No newline at end of file diff --git a/PDP8/pdp8_clk.c b/PDP8/pdp8_clk.c index 53e79636..7030c739 100644 --- a/PDP8/pdp8_clk.c +++ b/PDP8/pdp8_clk.c @@ -25,6 +25,7 @@ clk real time clock + 04-Oct-02 RMS Added DIB, device number support 30-Dec-01 RMS Removed for generalized timers 05-Sep-01 RMS Added terminal multiplexor support 17-Jul-01 RMS Moved function prototype @@ -36,11 +37,14 @@ #include "pdp8_defs.h" extern int32 int_req, int_enable, dev_done, stop_inst; -t_stat clk_svc (UNIT *uptr); -t_stat clk_reset (DEVICE *dptr); + int32 clk_tps = 60; /* ticks/second */ int32 tmxr_poll = 16000; /* term mux poll */ +int32 clk (int32 IR, int32 AC); +t_stat clk_svc (UNIT *uptr); +t_stat clk_reset (DEVICE *dptr); + /* CLK data structures clk_dev CLK device descriptor @@ -48,6 +52,8 @@ int32 tmxr_poll = 16000; /* term mux poll */ clk_reg CLK register list */ +DIB clk_dib = { DEV_CLK, 1, { &clk } }; + UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 16000 }; REG clk_reg[] = { @@ -58,21 +64,26 @@ REG clk_reg[] = { { DRDATA (TPS, clk_tps, 8), REG_NZ + PV_LEFT }, { NULL } }; +MTAB clk_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev }, + { 0 } }; + DEVICE clk_dev = { - "CLK", &clk_unit, clk_reg, NULL, + "CLK", &clk_unit, clk_reg, clk_mod, 1, 0, 0, 0, 0, 0, NULL, NULL, &clk_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &clk_dib, 0 }; /* IOT routine IOT's 6131-6133 are the PDP-8/E clock - IOT's 6135-6137 the PDP-8/A clock + IOT's 6135-6137 are the PDP-8/A clock */ -int32 clk (int32 pulse, int32 AC) +int32 clk (int32 IR, int32 AC) { -switch (pulse) { /* decode IR<9:11> */ +switch (IR & 07) { /* decode IR<9:11> */ case 1: /* CLEI */ int_enable = int_enable | INT_CLK; /* enable clk ints */ int_req = INT_UPDATE; /* update interrupts */ diff --git a/PDP8/pdp8_cpu.c b/PDP8/pdp8_cpu.c index 3cbddfb2..2c0e147f 100644 --- a/PDP8/pdp8_cpu.c +++ b/PDP8/pdp8_cpu.c @@ -25,6 +25,7 @@ cpu central processor + 04-Oct-02 RMS Revamped device dispatching, added device number support 06-Jan-02 RMS Added device enable/disable routines 30-Dec-01 RMS Added old PC queue 16-Dec-01 RMS Fixed bugs in EAE @@ -172,11 +173,10 @@ Thus, only writes outside the current field (indirect writes) need be checked against actual memory size. - 3. Adding I/O devices. Three modules must be modified: + 3. Adding I/O devices. These modules must be modified: - pdp8_defs.h add interrupt request definition - pdp8_cpu.c add IOT dispatch - pdp8_sys.c add pointer to data structures to sim_devices + pdp8_defs.h add device number and interrupt definitions + pdp8_sys.c add sim_devices table entry */ #include "pdp8_defs.h" @@ -208,41 +208,21 @@ REG *pcq_r = NULL; /* PC queue reg ptr */ int32 dev_done = 0; /* dev done flags */ int32 int_enable = INT_INIT_ENABLE; /* intr enables */ int32 int_req = 0; /* intr requests */ -int32 dev_enb = -1 & ~INT_DF & ~INT_RL; /* device enables */ int32 stop_inst = 0; /* trap on ill inst */ +int32 (*dev_tab[DEV_MAX])(int32 IR, int32 dat); /* device dispatch */ + extern int32 sim_interval; extern int32 sim_int_char; extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern DEVICE *sim_devices[]; +extern FILE *sim_log; extern UNIT clk_unit, ttix_unit; t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -extern int32 tti (int32 pulse, int32 AC); -extern int32 tto (int32 pulse, int32 AC); -extern int32 ptr (int32 pulse, int32 AC); -extern int32 ptp (int32 pulse, int32 AC); -extern int32 clk (int32 pulse, int32 AC); -extern int32 lpt (int32 pulse, int32 AC); -extern int32 ttix (int32 inst, int32 AC); -extern int32 ttox (int32 inst, int32 AC); -extern int32 rk (int32 pulse, int32 AC); -extern int32 rx (int32 pulse, int32 AC); -extern int32 df60 (int32 pulse, int32 AC); -extern int32 df61 (int32 pulse, int32 AC); -extern int32 df62 (int32 pulse, int32 AC); -extern int32 rf60 (int32 pulse, int32 AC); -extern int32 rf61 (int32 pulse, int32 AC); -extern int32 rf62 (int32 pulse, int32 AC); -extern int32 rf64 (int32 pulse, int32 AC); -extern int32 rl60 (int32 pulse, int32 AC); -extern int32 rl61 (int32 pulse, int32 AC); -extern int32 mt70 (int32 pulse, int32 AC); -extern int32 mt71 (int32 pulse, int32 AC); -extern int32 mt72 (int32 pulse, int32 AC); -extern int32 dt76 (int32 pulse, int32 AC); -extern int32 dt77 (int32 pulse, int32 AC); +t_bool build_dev_tab (void); /* CPU data structures @@ -277,12 +257,10 @@ REG cpu_reg[] = { { ORDATA (INT, int_req, INT_V_ION+1), REG_RO }, { ORDATA (DONE, dev_done, INT_V_DIRECT), REG_RO }, { ORDATA (ENABLE, int_enable, INT_V_DIRECT), REG_RO }, - { FLDATA (NOEAE, cpu_unit.flags, UNIT_V_NOEAE), REG_HRO }, { BRDATA (PCQ, pcq, 8, 15, PCQ_SIZE), REG_RO+REG_CIRC }, { ORDATA (PCQP, pcq_p, 6), REG_HRO }, { FLDATA (STOP_INST, stop_inst, 0) }, { ORDATA (WRU, sim_int_char, 8) }, - { ORDATA (DEVENB, dev_enb, 32), REG_HRO }, { NULL } }; MTAB cpu_mod[] = { @@ -302,7 +280,8 @@ DEVICE cpu_dev = { "CPU", &cpu_unit, cpu_reg, cpu_mod, 1, 8, 15, 1, 8, 12, &cpu_ex, &cpu_dep, &cpu_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + NULL, 0 }; t_stat sim_instr (void) { @@ -313,6 +292,7 @@ t_stat reason; /* Restore register state */ +if (build_dev_tab ()) return SCPE_STOP; /* build dev_tab */ PC = saved_PC & 007777; /* load local copies */ IF = saved_PC & 070000; DF = saved_DF & 070000; @@ -940,7 +920,7 @@ case 030:case 031:case 032:case 033: /* IOT */ int_enable = INT_INIT_ENABLE; LAC = 0; break; } /* end switch pulse */ - continue; /* skip rest of IOT */ + break; /* end case 0 */ /* IOT, continued: memory extension */ @@ -993,7 +973,7 @@ case 030:case 031:case 032:case 033: /* IOT */ default: reason = stop_inst; break; } /* end switch pulse */ - continue; /* skip rest of IOT */ + break; /* end case 20-27 */ /* IOT, continued: other special cases */ @@ -1010,90 +990,16 @@ case 030:case 031:case 032:case 033: /* IOT */ default: reason = stop_inst; break; } /* end switch pulse */ - continue; /* skip rest of IOT */ - default: /* unknown device */ - reason = stop_inst; /* stop on flag */ - continue; /* skip rest of IOT */ - -/* IOT, continued: I/O devices */ - - case 1: /* PTR */ - iot_data = ptr (pulse, iot_data); - break; - case 2: /* PTP */ - iot_data = ptp (pulse, iot_data); - break; - case 3: /* TTI */ - iot_data = tti (pulse, iot_data); - break; - case 4: /* TTO */ - iot_data = tto (pulse, iot_data); - break; - case 013: /* CLK */ - iot_data = clk (pulse, iot_data); - break; - case 040: case 042: case 044: case 046: /* KL8JA in */ - if (dev_enb & INT_TTI1) iot_data = ttix (IR, iot_data); - else reason = stop_inst; - break; - case 041: case 043: case 045: case 047: /* KL8JA out */ - if (dev_enb & INT_TTI1) iot_data = ttox (IR, iot_data); - else reason = stop_inst; - break; - case 060: /* DF32/RF08 */ - if (dev_enb & INT_DF) iot_data = df60 (pulse, iot_data); - else if (dev_enb & INT_RF) iot_data = rf60 (pulse, iot_data); - else if (dev_enb & INT_RL) iot_data = rl60 (pulse, iot_data); - else reason = stop_inst; - break; - case 061: - if (dev_enb & INT_DF) iot_data = df61 (pulse, iot_data); - else if (dev_enb & INT_RF) iot_data = rf61 (pulse, iot_data); - else if (dev_enb & INT_RL) iot_data = rl61 (pulse, iot_data); - else reason = stop_inst; - break; - case 062: - if (dev_enb & INT_DF) iot_data = df62 (pulse, iot_data); - else if (dev_enb & INT_RF) iot_data = rf62 (pulse, iot_data); - else reason = stop_inst; - break; - case 064: - if (dev_enb & INT_RF) iot_data = rf64 (pulse, iot_data); - else reason = stop_inst; - break; - case 066: /* LPT */ - iot_data = lpt (pulse, iot_data); - break; - case 070: /* TM8E */ - if (dev_enb & INT_MT) iot_data = mt70 (pulse, iot_data); - else reason = stop_inst; - break; - case 071: - if (dev_enb & INT_MT) iot_data = mt71 (pulse, iot_data); - else reason = stop_inst; - break; - case 072: - if (dev_enb & INT_MT) iot_data = mt72 (pulse, iot_data); - else reason = stop_inst; - break; - case 074: /* RK8E */ - if (dev_enb & INT_RK) iot_data = rk (pulse, iot_data); - else reason = stop_inst; - break; - case 075: /* RX8E */ - if (dev_enb & INT_RX) iot_data = rx (pulse, iot_data); - break; - case 076: /* TC01/TC08 */ - if (dev_enb & INT_DTA) iot_data = dt76 (pulse, iot_data); - else reason = stop_inst; - break; - case 077: - if (dev_enb & INT_DTA) iot_data = dt77 (pulse, iot_data); - else reason = stop_inst; + break; /* end case 10 */ + default: /* I/O device */ + if (dev_tab[device]) { /* dev present? */ + iot_data = dev_tab[device] (IR, iot_data); + LAC = (LAC & 010000) | (iot_data & 07777); + if (iot_data & IOT_SKP) PC = (PC + 1) & 07777; + if (iot_data >= IOT_REASON) + reason = iot_data >> IOT_V_REASON; } + else reason = stop_inst; /* stop on flag */ break; } /* end switch device */ - LAC = (LAC & 010000) | (iot_data & 07777); - if (iot_data & IOT_SKP) PC = (PC + 1) & 07777; - if (iot_data >= IOT_REASON) reason = iot_data >> IOT_V_REASON; break; } /* end switch opcode */ } /* end while */ @@ -1103,7 +1009,7 @@ saved_PC = IF | (PC & 07777); /* save copies */ saved_DF = DF & 070000; saved_LAC = LAC & 017777; saved_MQ = MQ & 07777; -pcq_r -> qptr = pcq_p; /* update pc q ptr */ +pcq_r->qptr = pcq_p; /* update pc q ptr */ return reason; } /* end sim_instr */ @@ -1115,7 +1021,7 @@ int_req = (int_req & ~INT_ION) | INT_NO_CIF_PENDING; saved_DF = IB = saved_PC & 070000; UF = UB = gtf = emode = 0; pcq_r = find_reg ("PCQ", NULL, dptr); -if (pcq_r) pcq_r -> qptr = 0; +if (pcq_r) pcq_r->qptr = 0; else return SCPE_IERR; sim_brk_types = sim_brk_dflt = SWMASK ('E'); return SCPE_OK; @@ -1156,38 +1062,80 @@ for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; return SCPE_OK; } -/* Device enable routine */ +/* Change device number for a device */ -t_stat set_enb (UNIT *uptr, int32 val, char *cptr, void *desc) +t_stat set_dev (UNIT *uptr, int32 val, char *cptr, void *desc) { DEVICE *dptr; +DIB *dibp; +uint32 newdev; +t_stat r; -if (cptr != NULL) return SCPE_ARG; -if ((uptr == NULL) || (val == 0)) return SCPE_IERR; +if (cptr == NULL) return SCPE_ARG; +if (uptr == NULL) return SCPE_IERR; dptr = find_dev_from_unit (uptr); if (dptr == NULL) return SCPE_IERR; -dev_enb = dev_enb | val; -if (dptr -> reset) dptr -> reset (dptr); +dibp = (DIB *) dptr->ctxt; +if (dibp == NULL) return SCPE_IERR; +newdev = get_uint (cptr, 8, DEV_MAX - 1, &r); /* get new */ +if ((r != SCPE_OK) || (newdev == dibp->dev)) return r; +dibp->dev = newdev; /* store */ return SCPE_OK; } -/* Device disable routine */ +/* Show device number for a device */ -t_stat set_dsb (UNIT *uptr, int32 val, char *cptr, void *desc) +t_stat show_dev (FILE *st, UNIT *uptr, int32 val, void *desc) { -int32 i; DEVICE *dptr; -UNIT *up; +DIB *dibp; -if (cptr != NULL) return SCPE_ARG; -if ((uptr == NULL) || (val == 0)) return SCPE_IERR; +if (uptr == NULL) return SCPE_IERR; dptr = find_dev_from_unit (uptr); if (dptr == NULL) return SCPE_IERR; -for (i = 0; i < dptr -> numunits; i++) { /* check units */ - up = (dptr -> units) + i; - if ((up -> flags & UNIT_ATT) || sim_is_active (up)) - return SCPE_NOFNC; } -dev_enb = dev_enb & ~val; -if (dptr -> reset) dptr -> reset (dptr); +dibp = (DIB *) dptr->ctxt; +if (dibp == NULL) return SCPE_IERR; +fprintf (st, "devno=%02o", dibp->dev); +if (dibp-> num > 1) fprintf (st, "-%2o", dibp->dev + dibp->num - 1); return SCPE_OK; } + +/* CPU device handler - should never get here! */ + +int32 bad_dev (int32 IR, int32 AC) +{ +return (SCPE_IERR << IOT_V_REASON) | AC; /* broken! */ +} + +/* Build device dispatch table */ + +t_bool build_dev_tab (void) +{ +DEVICE *dptr; +DIB *dibp; +uint32 i, j; +static const uint8 std_dev[] = + { 000, 010, 020, 021, 022, 023, 024, 025, 026, 027 }; + +for (i = 0; i < DEV_MAX; i++) dev_tab[i] = NULL; /* clr table */ +for (i = 0; i < ((uint32) sizeof (std_dev)); i++) /* std entries */ + dev_tab[std_dev[i]] = &bad_dev; +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* add devices */ + dibp = (DIB *) dptr->ctxt; /* get DIB */ + if (dibp && !(dptr->flags & DEV_DIS)) { /* enabled? */ + for (j = 0; j < dibp->num; j++) { /* loop thru disp */ + if (dibp->dsp[j]) { /* any dispatch? */ + if (dev_tab[dibp->dev + j]) { /* already filled? */ + printf ("%s device number conflict at %02o\n", + dptr->name, dibp->dev + j); + if (sim_log) fprintf (sim_log, + "%s device number conflict at %02o\n", + dptr->name, dibp->dev + j); + return TRUE; } + dev_tab[dibp->dev + j] = dibp->dsp[j]; /* fill */ + } /* end if dsp */ + } /* end for j */ + } /* end if enb */ + } /* end for i */ +return FALSE; +} diff --git a/PDP8/pdp8_defs.h b/PDP8/pdp8_defs.h index 110f888d..88eb99d8 100644 --- a/PDP8/pdp8_defs.h +++ b/PDP8/pdp8_defs.h @@ -23,6 +23,7 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 04-Oct-02 RMS Added variable device number support 20-Jan-02 RMS Fixed bug in TTx interrupt enable initialization 25-Nov-01 RMS Added RL8A support 16-Sep-01 RMS Added multiple KL support @@ -43,6 +44,7 @@ #define STOP_RSRV 1 /* must be 1 */ #define STOP_HALT 2 /* HALT */ #define STOP_IBKPT 3 /* breakpoint */ +#define STOP_NOTSTD 4 /* non-std devno */ /* Memory */ @@ -63,6 +65,36 @@ #define TMR_CLK 0 /* timer 0 = clock */ #define TMR_TTX 1 /* timer 1 = TTx */ + +/* Device information block */ + +#define DEV_MAXBLK 8 /* max dev block */ +#define DEV_MAX 64 /* total devices */ + +struct pdp8_dib { + uint32 dev; /* base dev number */ + uint32 num; /* number of slots */ + int32 (*dsp[DEV_MAXBLK])(int32 IR, int32 dat); +}; + +typedef struct pdp8_dib DIB; + +/* Standard device numbers */ + +#define DEV_PTR 001 /* paper tape reader */ +#define DEV_PTP 002 /* paper tape punch */ +#define DEV_TTI 003 /* console input */ +#define DEV_TTO 004 /* console output */ +#define DEV_CLK 013 /* clock */ +#define DEV_KJ8 040 /* extra terminals */ +#define DEV_DF 060 /* DF32 */ +#define DEV_RF 060 /* RF08 */ +#define DEV_RL 060 /* RL8A */ +#define DEV_LPT 066 /* line printer */ +#define DEV_MT 070 /* TM8E */ +#define DEV_RK 074 /* RK8E */ +#define DEV_RX 075 /* RX8E/RX28 */ +#define DEV_DTA 076 /* TC08 */ /* Interrupt flags @@ -152,5 +184,5 @@ /* Function prototypes */ -t_stat set_enb (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat set_dsb (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat set_dev (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat show_dev (FILE *st, UNIT *uptr, int32 val, void *desc); diff --git a/PDP8/pdp8_df.c b/PDP8/pdp8_df.c index 1a90ac4f..4def4ed9 100644 --- a/PDP8/pdp8_df.c +++ b/PDP8/pdp8_df.c @@ -25,6 +25,7 @@ df DF32 fixed head disk + 04-Oct-02 RMS Added DIBs, device number support 28-Nov-01 RMS Added RL8A support 25-Apr-01 RMS Added device enable/disable support @@ -77,9 +78,9 @@ else df_sta = df_sta & ~DFS_PCA extern uint16 M[]; -extern int32 int_req, dev_enb, stop_inst; +extern int32 int_req, stop_inst; extern UNIT cpu_unit; -extern int32 rf_devenb; + int32 df_sta = 0; /* status register */ int32 df_da = 0; /* disk address */ int32 df_done = 0; /* done flag */ @@ -87,10 +88,15 @@ int32 df_wlk = 0; /* write lock */ int32 df_time = 10; /* inter-word time */ int32 df_burst = 1; /* burst mode flag */ int32 df_stopioe = 1; /* stop on error */ + +DEVICE df_dev; +int32 df60 (int32 IR, int32 AC); +int32 df61 (int32 IR, int32 AC); +int32 df62 (int32 IR, int32 AC); t_stat df_svc (UNIT *uptr); t_stat pcell_svc (UNIT *uptr); t_stat df_reset (DEVICE *dptr); -t_stat df_boot (int32 unitno); +t_stat df_boot (int32 unitno, DEVICE *dptr); /* DF32 data structures @@ -100,6 +106,8 @@ t_stat df_boot (int32 unitno); df_reg RF register list */ +DIB df_dib = { DEV_DF, 3, { &df60, &df61, &df62 } }; + UNIT df_unit = { UDATA (&df_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, DF_SIZE) }; @@ -115,25 +123,27 @@ REG df_reg[] = { { DRDATA (TIME, df_time, 24), REG_NZ + PV_LEFT }, { FLDATA (BURST, df_burst, 0) }, { FLDATA (STOP_IOE, df_stopioe, 0) }, - { FLDATA (*DEVENB, dev_enb, INT_V_DF), REG_HRO }, + { ORDATA (DEVNUM, df_dib.dev, 6), REG_HRO }, { NULL } }; MTAB df_mod[] = { - { MTAB_XTD|MTAB_VDV, INT_DF, NULL, "ENABLED", &set_enb }, - { MTAB_XTD|MTAB_VDV, INT_DF, NULL, "DISABLED", &set_dsb }, + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", + &set_dev, &show_dev, NULL }, { 0 } }; DEVICE df_dev = { "DF", &df_unit, df_reg, df_mod, 1, 8, 17, 1, 8, 12, NULL, NULL, &df_reset, - &df_boot, NULL, NULL }; + &df_boot, NULL, NULL, + &df_dib, DEV_DISABLE }; /* IOT routines */ -int32 df60 (int32 pulse, int32 AC) +int32 df60 (int32 IR, int32 AC) { int32 t; +int32 pulse = IR & 07; UPDATE_PCELL; /* update photocell */ if (pulse & 1) { /* DCMA */ @@ -161,9 +171,10 @@ return AC; AC = AC | old_df_sta */ -int32 df61 (int32 pulse, int32 AC) +int32 df61 (int32 IR, int32 AC) { int32 old_df_sta = df_sta; +int32 pulse = IR & 07; UPDATE_PCELL; /* update photocell */ if (pulse & 1) /* DCEA */ @@ -176,8 +187,10 @@ if (pulse & 4) { return AC; } -int32 df62 (int32 pulse, int32 AC) +int32 df62 (int32 IR, int32 AC) { +int32 pulse = IR & 07; + UPDATE_PCELL; /* update photocell */ if (pulse & 1) { /* DFSE */ if ((df_sta & DFS_ERR) == 0) AC = AC | IOT_SKP; } @@ -200,7 +213,7 @@ int32 pa, t, mex; t_addr da; UPDATE_PCELL; /* update photocell */ -if ((uptr -> flags & UNIT_BUF) == 0) { /* not buf? abort */ +if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */ df_done = 1; int_req = int_req | INT_DF; /* update int req */ return IORETURN (df_stopioe, SCPE_UNATT); } @@ -210,20 +223,20 @@ da = GET_DEX (df_sta) | df_da; /* form disk addr */ do { M[DF_WC] = (M[DF_WC] + 1) & 07777; /* incr word count */ M[DF_MA] = (M[DF_MA] + 1) & 07777; /* incr mem addr */ pa = mex | M[DF_MA]; /* add extension */ - if (uptr -> FUNC == DF_READ) { + if (uptr->FUNC == DF_READ) { if (MEM_ADDR_OK (pa)) /* read, check nxm */ - M[pa] = *(((int16 *) uptr -> filebuf) + da); } + M[pa] = *(((int16 *) uptr->filebuf) + da); } else { t = (da >> 14) & 07; if ((df_wlk >> t) & 1) df_sta = df_sta | DFS_WLS; - else { *(((int16 *) uptr -> filebuf) + da) = M[pa]; - if (da >= uptr -> hwmark) - uptr -> hwmark = da + 1; } } + else { *(((int16 *) uptr->filebuf) + da) = M[pa]; + if (da >= uptr->hwmark) + uptr->hwmark = da + 1; } } da = (da + 1) & 0377777; } /* incr disk addr */ while ((M[DF_WC] != 0) && (df_burst != 0)); /* brk if wc, no brst */ if (M[DF_WC] != 0) /* more to do? */ sim_activate (&df_unit, df_time); /* sched next */ -else { if (uptr -> FUNC != DF_READ) da = (da - 1) & 0377777; +else { if (uptr->FUNC != DF_READ) da = (da - 1) & 0377777; df_done = 1; /* done */ int_req = int_req | INT_DF; } /* update int req */ df_sta = (df_sta & ~DFS_DEX) | ((da >> (12 - DFS_V_DEX)) & DFS_DEX); @@ -235,8 +248,6 @@ return SCPE_OK; t_stat df_reset (DEVICE *dptr) { -if (dev_enb & INT_DF) /* DF? no RF or RL */ - dev_enb = dev_enb & ~(INT_RF | INT_RL); df_sta = df_da = 0; df_done = 1; int_req = int_req & ~INT_DF; /* clear interrupt */ @@ -247,11 +258,11 @@ return SCPE_OK; /* Bootstrap routine */ #define OS8_START 07750 -#define OS8_LEN (sizeof (os8_rom) / sizeof (int32)) +#define OS8_LEN (sizeof (os8_rom) / sizeof (int16)) #define DM4_START 00200 -#define DM4_LEN (sizeof (dm4_rom) / sizeof (int32)) +#define DM4_LEN (sizeof (dm4_rom) / sizeof (int16)) -static const int32 os8_rom[] = { +static const uint16 os8_rom[] = { 07600, /* 7750, CLA CLL ; also word count */ 06603, /* 7751, DMAR ; also address */ 06622, /* 7752, DFSC ; done? */ @@ -259,7 +270,7 @@ static const int32 os8_rom[] = { 05752 /* 7754, JMP @.-2 ; enter boot */ }; -static const int32 dm4_rom[] = { +static const uint16 dm4_rom[] = { 00200, 07600, /* 0200, CLA CLL */ 00201, 06603, /* 0201, DMAR ; read */ 00202, 06622, /* 0202, DFSC ; done? */ @@ -269,7 +280,7 @@ static const int32 dm4_rom[] = { 07751, 07576 /* 7751, 7576 ; address */ }; -t_stat df_boot (int32 unitno) +t_stat df_boot (int32 unitno, DEVICE *dptr) { int32 i; extern int32 sim_switches, saved_PC; diff --git a/PDP8/pdp8_doc.txt b/PDP8/pdp8_doc.txt index be513ca7..aef8c49f 100644 --- a/PDP8/pdp8_doc.txt +++ b/PDP8/pdp8_doc.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik Subj: PDP-8 Simulator Usage -Date: 15-Jun-2002 +Date: 15-Nov-2002 COPYRIGHT NOTICE @@ -37,11 +37,11 @@ This memorandum documents the PDP-8 simulator. 1. Simulator Files sim/ sim_defs.h + sim_rev.h sim_sock.h sim_tmxr.h scp.c scp_tty.c - sim_rev.c sim_sock.c sim_tmxr.c @@ -79,18 +79,34 @@ RK RK8E/RK05 cartridge disk controller with four drives RF RF08/RS08 fixed head disk controller with four platters, or DF DF32/DS32 fixed head disk controller with four platters RL RL8A/RL01 cartridge disk controller with four drives -RX RX8E/RX01 floppy disk controller with two drives +RX RX8E/RX01, RX28/RX02 floppy disk controller with two drives DT TC08/TU56 DECtape controller with eight drives MT TM8E/TU10 magnetic tape controller with eight drives -The RK, RF, DF, RL, RX, DT, MT, and TTIX/TTOX devices can be set DISABLEd. -The PDP-8 can support only one of the set {DF32, RF08, RL8A}, since they -use the same IOT's. The simulator defaults to the RF08. To change the -disk at device addresses 60-61: +Most devices can be disabled or enabled, by the commands: - SET RF DISABLED disable RF08 - SET DF ENABLED, or enable DF32 - SET RL ENABLED enable RL8A + SET DISABLED + SET ENABLED + +The simulator allows most device numbers to be changed, by the command: + + SET DEV= + +The PDP-8 can support only one of the set {DF32, RF08, RL8A} using the +default device numbers, since they all use device numbers 60-61. The +default is the RF08. To change the disk at device numbers 60-61: + + sim> SET RF DISABLED disable RF08 + sim> SET DF ENABLED, or enable DF32 + sim> SET RL ENABLED enable RL8A + +Alternately, the device conflict can be eliminated by changing device +numbers: + + sim> SET RL DEV=50 + sim> SET RL ENA + +However, devices can only be BOOTed with their default device numbers. The PDP-8 simulator implements one unique stop condition: if an undefined instruction (unimplemented IOT or OPR) is decoded, and register STOP_INST @@ -218,11 +234,15 @@ Error handling is as follows: 2.2.3 KL8E Terminal Input (TTI) -The terminal input (TTI) polls the console keyboard for input. The -input side has one option, UC; when set, it automatically converts lower -case input to upper case. This is required by OS/8 and is on by default. +The terminal interfaces (TTI, TTO) can be set to one of three modes: +KSR, 7B, or 8B. In KSR mode, lower case input and output characters +are automatically converted to upper case, and the high order bit is +forced to one on input. In 7B mode, input and output characters are +masked to 7 bits. In 8B mode, characters are not modified. Changing +the mode of either interface changes both. The default mode is KSR. -The terminal input implements these registers: +The terminal input (TTI) polls the console keyboard for input. It +implements these registers: name size comments @@ -235,7 +255,7 @@ The terminal input implements these registers: 2.2.4 KL8E Terminal Output (TTO) -The terminal output (TTO) writes to the simulator console window. It +The terminal output (TTO) writes to the simulator console window. It implements these registers: name size comments @@ -302,9 +322,11 @@ command specifies the port to be used: where port is a decimal number between 1 and 65535 that is not being used for other TCP/IP activities. -The additional terminals have one option, UC; when set, lower case input -characters are automatically converted to upper case. This is required -by TSS/8 and is on by default for all lines. +The additional terminals can be set to one of three modes: UC, 7B, or +8B. In KSR mode, lower case input and output characters are converted +automatically to upper case. In 7B mode, input and output characters +are masked to 7 bits. In 8B mode, characters are not modified. The +default mode is UC. Once TTIX is attached and the simulator is running, the terminals listen for connections on the specified port. They assume that the incoming @@ -419,26 +441,43 @@ Error handling is as follows: OS I/O error x report error and stop -2.4 RX8E/RX01 Floppy Disk (RX) +2.4 RX8E/RX01, RX28/RX02 Floppy Disk (RX) + +The RX can be configured as an RX8E with two RX01 drives, or an RX28 with +two RX02 drives: + + SET RX RX8E set controller to RX8E/RX01 + SET RX RX28 set controller to RX28/RX02 + +The controller is set to the RX8E by default. The RX28 is not backwards- +compatible with the RX8E and will not work with the standard OS/8 V3D floppy +disk driver. RX8E options include the ability to set units write enabled or write locked: SET RXn LOCKED set unit n write locked SET RXn WRITEENABLED set unit n write enabled -The RX8E supports the BOOT command. +RX28 options include, in addition, the ability to set the unit density to +single density, double density, or autosized; autosizing is the default: -The RX8E implements these registers: + SET RXn SINGLE set unit n single density + SET RXn DOUBLE set unit n double density + SET RXn AUTOSIZE set unit n autosize + +The RX8E and RX28 support the BOOT command. + +The RX8E and RX28 implement these registers: name size comments RXCS 12 status RXDB 12 data buffer - RXES 8 error status + RXES 12 error status RXTA 8 current track RXSA 8 current sector - STAPTR 3 controller state - BUFPTR 3 buffer pointer + STAPTR 4 controller state + BUFPTR 8 buffer pointer INT 1 interrupt pending flag DONE 1 device done flag ENABLE 1 interrupt enable flag @@ -448,7 +487,7 @@ The RX8E implements these registers: STIME 24 seek time, per track XTIME 24 transfer ready delay STOP_IOE 1 stop on I/O error - SBUF[0:127] 8 sector buffer array + SBUF[0:255] 8 sector buffer array Error handling is as follows: @@ -457,13 +496,13 @@ Error handling is as follows: not attached 1 report error and stop 0 disk not ready -RX01 data files are buffered in memory; therefore, end of file and OS -I/O errors cannot occur. +RX01 and RX02 data files are buffered in memory; therefore, end of file +and OS I/O errors cannot occur. 2.5 Fixed Head Disks Either the RF08 or the DF32 can be present in a configuration, but -not both. +not both, with default device addressing. 2.5.1 RF08/RS08 Fixed Head Disk (RF) @@ -483,7 +522,7 @@ The RF08 implements these registers: STOP_IOE 1 stop on I/O error The RF08 supports the BOOT command. The default bootstrap is for OS/8. To -bootstrap the 4K Disk Monitor, use the BOOT -D command. +bootstrap the 4K Disk Monitor, use the BOOT -D RF command. The RF08 is a three-cycle data break device. If BURST = 0, word transfers are scheduled individually; if BURST = 1, the entire transfer occurs in @@ -517,7 +556,7 @@ The DF32 implements these registers: STOP_IOE 1 stop on I/O error The DF32 supports the BOOT command. The default bootstrap is for OS/8. To -bootstrap the 4K Disk Monitor, use the BOOT -D command. +bootstrap the 4K Disk Monitor, use the BOOT -D DF command. The DF32 is a three-cycle data break device. If BURST = 0, word transfers are scheduled individually; if BURST = 1, the entire transfer occurs in @@ -544,12 +583,13 @@ locked. Units can also be set ONLINE or OFFLINE. The TC08 supports the BOOT command. -The TC08 supports both PDP-8 format and PDP-9/11/15 format DECtape images. -ATTACH tries to determine the tape format from the DECtape image; the user -can force a particular format with switches: +The TC08 supports supports PDP-8 format, PDP-11 format, and 18b format +DECtape images. ATTACH tries to determine the tape format from the DECtape +image; the user can force a particular format with switches: - -f foreign (PDP-9/11/15) format - -n native (PDP-8) format + -r PDP-8 format + -s PDP-11 format + -t 18b format The DECtape controller is a data-only simulator; the timing and mark track, and block header and trailer, are not stored. Thus, the WRITE @@ -616,12 +656,11 @@ Error handling is as follows: error processed as - not attached tape not ready + not attached tape not ready; if STOP_IOE, stop - end of file (read or space) end of physical tape - (write) ignored + end of file bad tape - OS I/O error report error and stop + OS I/O error parity error; if STOP_IOE, stop 2.8 Symbolic Display and Input diff --git a/PDP8/pdp8_dt.c b/PDP8/pdp8_dt.c index b64370ca..ad499e97 100644 --- a/PDP8/pdp8_dt.c +++ b/PDP8/pdp8_dt.c @@ -25,6 +25,9 @@ dt TC08/TU56 DECtape + 17-Oct-02 RMS Fixed bug in end of reel logic + 04-Oct-02 RMS Added DIB, device number support + 12-Sep-02 RMS Added support for 16b format 30-May-02 RMS Widened POS to 32b 06-Jan-02 RMS Changed enable/disable support 30-Nov-01 RMS Added read only unit, extended SET/SHOW support @@ -37,11 +40,14 @@ 19-Mar-01 RMS Changed bootstrap to support 4k disk monitor 15-Mar-01 RMS Added 129th word to PDP-8 format - PDP-8 DECtapes are represented by fixed length data blocks of 12b words. Two - tape formats are supported: + PDP-8 DECtapes are represented in memory by fixed length buffer of 16b words. + Three file formats are supported: - 12b 129 words per block - 16b/18b/36b 384 words per block + 18b/36b 256 words per block [256 x 18b] + 16b 256 words per block [256 x 16b] + 12b 129 words per block [129 x 12b] + + When a 16b or 18/36bb DECtape file is read in, it is converted to 12b format. DECtape motion is measured in 3b lines. Time between lines is 33.33us. Tape density is nominally 300 lines per inch. The format of a DECtape is @@ -80,10 +86,11 @@ #define DT_NUMDR 8 /* #drives */ #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_WLK (1 << UNIT_V_WLK) #define UNIT_V_8FMT (UNIT_V_UF + 1) /* 12b format */ +#define UNIT_V_11FMT (UNIT_V_UF + 2) /* 16b format */ +#define UNIT_WLK (1 << UNIT_V_WLK) #define UNIT_8FMT (1 << UNIT_V_8FMT) -#define UNIT_W_UF 3 /* saved flag width */ +#define UNIT_11FMT (1 << UNIT_V_11FMT) #define STATE u3 /* unit state */ #define LASTT u4 /* last time update */ #define DT_WC 07754 /* word count */ @@ -108,6 +115,7 @@ #define D18_NBSIZE ((D18_BSIZE * D8_WSIZE) / D18_WSIZE) #define D18_FILSIZ (D18_NBSIZE * D18_TSIZE * sizeof (int32)) +#define D11_FILSIZ (D18_NBSIZE * D18_TSIZE * sizeof (int16)) /* 12b DECtape constants */ @@ -117,6 +125,7 @@ #define D8_LPERB (DT_HTLIN + (D8_BSIZE * DT_WSIZE) + DT_HTLIN) #define D8_FWDEZ (DT_EZLIN + (D8_LPERB * D8_TSIZE)) #define D8_CAPAC (D8_TSIZE * D8_BSIZE) /* tape capacity */ +#define D8_FILSIZ (D8_CAPAC * sizeof (int16)) /* This controller */ @@ -125,18 +134,18 @@ /* Calculated constants, per unit */ -#define DTU_BSIZE(u) (((u) -> flags & UNIT_8FMT)? D8_BSIZE: D18_BSIZE) -#define DTU_TSIZE(u) (((u) -> flags & UNIT_8FMT)? D8_TSIZE: D18_TSIZE) -#define DTU_LPERB(u) (((u) -> flags & UNIT_8FMT)? D8_LPERB: D18_LPERB) -#define DTU_FWDEZ(u) (((u) -> flags & UNIT_8FMT)? D8_FWDEZ: D18_FWDEZ) -#define DTU_CAPAC(u) (((u) -> flags & UNIT_8FMT)? D8_CAPAC: D18_CAPAC) +#define DTU_BSIZE(u) (((u)->flags & UNIT_8FMT)? D8_BSIZE: D18_BSIZE) +#define DTU_TSIZE(u) (((u)->flags & UNIT_8FMT)? D8_TSIZE: D18_TSIZE) +#define DTU_LPERB(u) (((u)->flags & UNIT_8FMT)? D8_LPERB: D18_LPERB) +#define DTU_FWDEZ(u) (((u)->flags & UNIT_8FMT)? D8_FWDEZ: D18_FWDEZ) +#define DTU_CAPAC(u) (((u)->flags & UNIT_8FMT)? D8_CAPAC: D18_CAPAC) #define DT_LIN2BL(p,u) (((p) - DT_EZLIN) / DTU_LPERB (u)) #define DT_LIN2OF(p,u) (((p) - DT_EZLIN) % DTU_LPERB (u)) #define DT_LIN2WD(p,u) ((DT_LIN2OF (p,u) - DT_HTLIN) / DT_WSIZE) #define DT_BLK2LN(p,u) (((p) * DTU_LPERB (u)) + DT_EZLIN) -#define DT_QREZ(u) (((u) -> pos) < DT_EZLIN) -#define DT_QFEZ(u) (((u) -> pos) >= ((uint32) DTU_FWDEZ (u))) +#define DT_QREZ(u) (((u)->pos) < DT_EZLIN) +#define DT_QFEZ(u) (((u)->pos) >= ((uint32) DTU_FWDEZ (u))) #define DT_QEZ(u) (DT_QREZ (u) || DT_QFEZ (u)) /* Status register A */ @@ -214,10 +223,10 @@ #define DTS_V_2ND 6 /* next state */ #define DTS_V_3RD (DTS_V_2ND + DTS_V_2ND) /* next next */ #define DTS_STA(y,z) (((y) << DTS_V_MOT) | ((z) << DTS_V_FNC)) -#define DTS_SETSTA(y,z) uptr -> STATE = DTS_STA (y, z) -#define DTS_SET2ND(y,z) uptr -> STATE = (uptr -> STATE & 077) | \ +#define DTS_SETSTA(y,z) uptr->STATE = DTS_STA (y, z) +#define DTS_SET2ND(y,z) uptr->STATE = (uptr->STATE & 077) | \ ((DTS_STA (y, z)) << DTS_V_2ND) -#define DTS_SET3RD(y,z) uptr -> STATE = (uptr -> STATE & 07777) | \ +#define DTS_SET3RD(y,z) uptr->STATE = (uptr->STATE & 07777) | \ ((DTS_STA (y, z)) << DTS_V_3RD) #define DTS_NXTSTA(x) (x >> DTS_V_2ND) @@ -239,9 +248,10 @@ #define ABS(x) (((x) < 0)? (-(x)): (x)) extern uint16 M[]; -extern int32 int_req, dev_enb; +extern int32 int_req; extern UNIT cpu_unit; extern int32 sim_switches; + int32 dtsa = 0; /* status A */ int32 dtsb = 0; /* status B */ int32 dt_ltime = 12; /* interline time */ @@ -250,11 +260,15 @@ int32 dt_dctime = 72000; /* decel time */ int32 dt_substate = 0; int32 dt_log = 0; /* debug */ int32 dt_logblk = 0; + +DEVICE dt_dev; +int32 dt76 (int32 IR, int32 AC); +int32 dt77 (int32 IR, int32 AC); t_stat dt_svc (UNIT *uptr); t_stat dt_reset (DEVICE *dptr); t_stat dt_attach (UNIT *uptr, char *cptr); t_stat dt_detach (UNIT *uptr); -t_stat dt_boot (int32 unitno); +t_stat dt_boot (int32 unitno, DEVICE *dptr); void dt_deselect (int32 oldf); void dt_newsa (int32 newf); void dt_newfnc (UNIT *uptr, int32 newsta); @@ -274,6 +288,8 @@ extern int32 sim_is_running; dt_mod DT modifier list */ +DIB dt_dib = { DEV_DTA, 2, { &dt76, &dt77 } }; + UNIT dt_unit[] = { { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+ UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) }, @@ -313,30 +329,31 @@ REG dt_reg[] = { DT_NUMDR, REG_RO) }, { URDATA (LASTT, dt_unit[0].LASTT, 10, 32, 0, DT_NUMDR, REG_HRO) }, - { URDATA (FLG, dt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, - DT_NUMDR, REG_HRO) }, - { FLDATA (*DEVENB, dev_enb, INT_V_DTA), REG_HRO }, + { ORDATA (DEVNUM, dt_dib.dev, 6), REG_HRO }, { NULL } }; MTAB dt_mod[] = { { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, - { UNIT_8FMT, 0, "16b/18b", NULL, NULL }, - { UNIT_8FMT, UNIT_8FMT, "12b", NULL, NULL }, - { MTAB_XTD|MTAB_VDV, INT_DTA, NULL, "ENABLED", &set_enb }, - { MTAB_XTD|MTAB_VDV, INT_DTA, NULL, "DISABLED", &set_dsb }, + { UNIT_8FMT + UNIT_11FMT, 0, "18b", NULL, NULL }, + { UNIT_8FMT + UNIT_11FMT, UNIT_8FMT, "12b", NULL, NULL }, + { UNIT_8FMT + UNIT_11FMT, UNIT_11FMT, "16b", NULL, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", + &set_dev, &show_dev, NULL }, { 0 } }; DEVICE dt_dev = { "DT", dt_unit, dt_reg, dt_mod, DT_NUMDR, 8, 24, 1, 8, 12, NULL, NULL, &dt_reset, - &dt_boot, &dt_attach, &dt_detach }; + &dt_boot, &dt_attach, &dt_detach, + &dt_dib, DEV_DISABLE }; /* IOT routines */ -int32 dt76 (int32 pulse, int32 AC) +int32 dt76 (int32 IR, int32 AC) { +int32 pulse = IR & 07; int32 old_dtsa = dtsa, fnc; UNIT *uptr; @@ -351,18 +368,20 @@ if (pulse & 06) { /* select */ if ((old_dtsa ^ dtsa) & DTA_UNIT) dt_deselect (old_dtsa); uptr = dt_dev.units + DTA_GETUNIT (dtsa); /* get unit */ fnc = DTA_GETFNC (dtsa); /* get fnc */ - if (((uptr -> flags) & UNIT_DIS) || /* disabled? */ + if (((uptr->flags) & UNIT_DIS) || /* disabled? */ (fnc >= FNC_WMRK) || /* write mark? */ - ((fnc == FNC_WALL) && (uptr -> flags & UNIT_WPRT)) || - ((fnc == FNC_WRIT) && (uptr -> flags & UNIT_WPRT))) + ((fnc == FNC_WALL) && (uptr->flags & UNIT_WPRT)) || + ((fnc == FNC_WRIT) && (uptr->flags & UNIT_WPRT))) dt_seterr (uptr, DTB_SEL); /* select err */ else dt_newsa (dtsa); DT_UPDINT; } return AC; } -int32 dt77 (int32 pulse, int32 AC) +int32 dt77 (int32 IR, int32 AC) { +int32 pulse = IR & 07; + if ((pulse & 01) && (dtsb & (DTB_ERF |DTB_DTF))) /* DTSF */ AC = IOT_SKP | AC; if (pulse & 02) AC = AC | dtsb; /* DTRB */ @@ -378,7 +397,7 @@ void dt_deselect (int32 oldf) { int32 old_unit = DTA_GETUNIT (oldf); UNIT *uptr = dt_dev.units + old_unit; -int32 old_mot = DTS_GETMOT (uptr -> STATE); +int32 old_mot = DTS_GETMOT (uptr->STATE); if (old_mot >= DTS_ATSF) /* at speed? */ dt_newfnc (uptr, DTS_STA (old_mot, DTS_OFR)); @@ -409,19 +428,18 @@ return; } void dt_newsa (int32 newf) { -int32 new_unit, prev_mot, prev_fnc, new_fnc; +int32 new_unit, prev_mot, new_fnc; int32 prev_mving, new_mving, prev_dir, new_dir; UNIT *uptr; new_unit = DTA_GETUNIT (newf); /* new, old units */ uptr = dt_dev.units + new_unit; -if ((uptr -> flags & UNIT_ATT) == 0) { /* new unit attached? */ +if ((uptr->flags & UNIT_ATT) == 0) { /* new unit attached? */ dt_seterr (uptr, DTB_SEL); /* no, error */ return; } -prev_mot = DTS_GETMOT (uptr -> STATE); /* previous motion */ +prev_mot = DTS_GETMOT (uptr->STATE); /* previous motion */ prev_mving = prev_mot != DTS_STOP; /* previous moving? */ prev_dir = prev_mot & DTS_DIR; /* previous dir? */ -prev_fnc = DTS_GETFNC (uptr -> STATE); /* prev function? */ new_mving = (newf & DTA_STSTP) != 0; /* new moving? */ new_dir = (newf & DTA_FWDRV) != 0; /* new dir? */ new_fnc = DTA_GETFNC (newf); /* new function? */ @@ -487,15 +505,15 @@ void dt_newfnc (UNIT *uptr, int32 newsta) int32 fnc, dir, blk, unum, relpos, newpos; uint32 oldpos; -oldpos = uptr -> pos; /* save old pos */ +oldpos = uptr->pos; /* save old pos */ if (dt_setpos (uptr)) return; /* update pos */ -uptr -> STATE = newsta; /* update state */ -fnc = DTS_GETFNC (uptr -> STATE); /* set variables */ -dir = DTS_GETMOT (uptr -> STATE) & DTS_DIR; +uptr->STATE = newsta; /* update state */ +fnc = DTS_GETFNC (uptr->STATE); /* set variables */ +dir = DTS_GETMOT (uptr->STATE) & DTS_DIR; unum = uptr - dt_dev.units; -if (oldpos == uptr -> pos) /* bump pos */ - uptr -> pos = uptr -> pos + (dir? -1: 1); -blk = DT_LIN2BL (uptr -> pos, uptr); +if (oldpos == uptr->pos) /* bump pos */ + uptr->pos = uptr->pos + (dir? -1: 1); +blk = DT_LIN2BL (uptr->pos, uptr); if (dir? DT_QREZ (uptr): DT_QFEZ (uptr)) { /* wrong ez? */ dt_seterr (uptr, DTB_END); /* set ez flag, stop */ @@ -528,7 +546,7 @@ case FNC_WALL: /* write all */ if (dir) newpos = DTU_FWDEZ (uptr) - DT_HTLIN - DT_WSIZE; else newpos = DT_EZLIN + DT_HTLIN + (DT_WSIZE - 1); break; } - relpos = DT_LIN2OF (uptr -> pos, uptr); /* cur pos in blk */ + relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ if ((relpos >= DT_HTLIN) && /* in data zone? */ (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { dt_seterr (uptr, DTB_SEL); @@ -541,7 +559,7 @@ case FNC_WALL: /* write all */ default: dt_seterr (uptr, DTB_SEL); /* bad state */ return; } -sim_activate (uptr, ABS (newpos - ((int32) uptr -> pos)) * dt_ltime); +sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime); return; } @@ -566,13 +584,13 @@ return; t_bool dt_setpos (UNIT *uptr) { uint32 new_time, ut, ulin, udelt; -int32 mot = DTS_GETMOT (uptr -> STATE); +int32 mot = DTS_GETMOT (uptr->STATE); int32 unum, delta; new_time = sim_grtime (); /* current time */ -ut = new_time - uptr -> LASTT; /* elapsed time */ +ut = new_time - uptr->LASTT; /* elapsed time */ if (ut == 0) return FALSE; /* no time gone? exit */ -uptr -> LASTT = new_time; /* update last time */ +uptr->LASTT = new_time; /* update last time */ switch (mot & ~DTS_DIR) { /* case on motion */ case DTS_STOP: /* stop */ delta = 0; @@ -588,12 +606,12 @@ case DTS_ACCF: /* accelerating */ case DTS_ATSF: /* at speed */ delta = ut / (uint32) dt_ltime; break; } -if (mot & DTS_DIR) uptr -> pos = uptr -> pos - delta; /* update pos */ -else uptr -> pos = uptr -> pos + delta; -if ((uptr -> pos < 0) || - (uptr -> pos > ((uint32) (DTU_FWDEZ (uptr) + DT_EZLIN)))) { +if (mot & DTS_DIR) uptr->pos = uptr->pos - delta; /* update pos */ +else uptr->pos = uptr->pos + delta; +if (((int32) uptr->pos < 0) || + ((int32) uptr->pos > (DTU_FWDEZ (uptr) + DT_EZLIN))) { detach_unit (uptr); /* off reel? */ - uptr -> STATE = uptr -> pos = 0; + uptr->STATE = uptr->pos = 0; unum = uptr - dt_dev.units; if (unum == DTA_GETUNIT (dtsa)) /* if selected, */ dt_seterr (uptr, DTB_SEL); /* error */ @@ -608,10 +626,10 @@ return FALSE; t_stat dt_svc (UNIT *uptr) { -int32 mot = DTS_GETMOT (uptr -> STATE); +int32 mot = DTS_GETMOT (uptr->STATE); int32 dir = mot & DTS_DIR; -int32 fnc = DTS_GETFNC (uptr -> STATE); -int16 *bptr = uptr -> filebuf; +int32 fnc = DTS_GETFNC (uptr->STATE); +int16 *bptr = uptr->filebuf; int32 unum = uptr - dt_dev.units; int32 blk, wrd, ma, relpos, dat; t_addr ba; @@ -626,12 +644,12 @@ t_addr ba; switch (mot) { case DTS_DECF: case DTS_DECR: /* decelerating */ if (dt_setpos (uptr)) return SCPE_OK; /* update pos */ - uptr -> STATE = DTS_NXTSTA (uptr -> STATE); /* advance state */ - if (uptr -> STATE) /* not stopped? */ + uptr->STATE = DTS_NXTSTA (uptr->STATE); /* advance state */ + if (uptr->STATE) /* not stopped? */ sim_activate (uptr, dt_actime); /* must be reversing */ return SCPE_OK; case DTS_ACCF: case DTS_ACCR: /* accelerating */ - dt_newfnc (uptr, DTS_NXTSTA (uptr -> STATE)); /* adv state, sched */ + dt_newfnc (uptr, DTS_NXTSTA (uptr->STATE)); /* adv state, sched */ return SCPE_OK; case DTS_ATSF: case DTS_ATSR: /* at speed */ break; /* check function */ @@ -650,7 +668,7 @@ if (dt_setpos (uptr)) return SCPE_OK; /* update pos */ if (DT_QEZ (uptr)) { /* in end zone? */ dt_seterr (uptr, DTB_END); /* end zone error */ return SCPE_OK; } -blk = DT_LIN2BL (uptr -> pos, uptr); /* get block # */ +blk = DT_LIN2BL (uptr->pos, uptr); /* get block # */ switch (fnc) { /* at speed, check fnc */ case FNC_MOVE: /* move */ dt_seterr (uptr, DTB_END); /* end zone error */ @@ -668,7 +686,7 @@ case FNC_SRCH: /* search */ break; case DTS_OFR: /* off reel */ detach_unit (uptr); /* must be deselected */ - uptr -> STATE = uptr -> pos = 0; /* no visible action */ + uptr->STATE = uptr->pos = 0; /* no visible action */ break; /* Read has four subcases @@ -685,7 +703,7 @@ case DTS_OFR: /* off reel */ */ case FNC_READ: /* read */ - wrd = DT_LIN2WD (uptr -> pos, uptr); /* get word # */ + wrd = DT_LIN2WD (uptr->pos, uptr); /* get word # */ switch (dt_substate) { /* case on substate */ case DTO_SOB: /* start of block */ if (dtsb & DTB_DTF) { /* DTF set? */ @@ -733,7 +751,7 @@ case FNC_READ: /* read */ */ case FNC_WRIT: /* write */ - wrd = DT_LIN2WD (uptr -> pos, uptr); /* get word # */ + wrd = DT_LIN2WD (uptr->pos, uptr); /* get word # */ switch (dt_substate) { /* case on substate */ case DTO_SOB: /* start block */ if (dtsb & DTB_DTF) { /* DTF set? */ @@ -753,7 +771,7 @@ case FNC_WRIT: /* write */ dat = dt_substate? 0: M[ma]; /* get word */ if (dir) dat = dt_comobv (dat); /* rev? comp obv */ bptr[ba] = dat; /* write word */ - if (ba >= uptr -> hwmark) uptr -> hwmark = ba + 1; + if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; if (M[DT_WC] == 0) dt_substate = DTO_WCO; if (wrd != (dir? 0: DTU_BSIZE (uptr) - 1)) /* not last? */ sim_activate (uptr, DT_WSIZE * dt_ltime); @@ -779,13 +797,13 @@ case FNC_RALL: if (dtsb & DTB_DTF) { /* DTF set? */ dt_seterr (uptr, DTB_TIM); /* timing error */ return SCPE_OK; } - relpos = DT_LIN2OF (uptr -> pos, uptr); /* cur pos in blk */ + relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ M[DT_WC] = (M[DT_WC] + 1) & 07777; /* incr WC, CA */ M[DT_CA] = (M[DT_CA] + 1) & 07777; ma = DTB_GETMEX (dtsb) | M[DT_CA]; /* get mem addr */ if ((relpos >= DT_HTLIN) && /* in data zone? */ (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { - wrd = DT_LIN2WD (uptr -> pos, uptr); + wrd = DT_LIN2WD (uptr->pos, uptr); ba = (blk * DTU_BSIZE (uptr)) + wrd; dat = bptr[ba]; /* get tape word */ if (dir) dat = dt_comobv (dat); } /* rev? comp obv */ @@ -813,7 +831,7 @@ case FNC_WALL: if (dtsb & DTB_DTF) { /* DTF set? */ dt_seterr (uptr, DTB_TIM); /* timing error */ return SCPE_OK; } - relpos = DT_LIN2OF (uptr -> pos, uptr); /* cur pos in blk */ + relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ M[DT_WC] = (M[DT_WC] + 1) & 07777; /* incr WC, CA */ M[DT_CA] = (M[DT_CA] + 1) & 07777; ma = DTB_GETMEX (dtsb) | M[DT_CA]; /* get mem addr */ @@ -821,10 +839,10 @@ case FNC_WALL: (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { dat = M[ma]; /* get mem word */ if (dir) dat = dt_comobv (dat); - wrd = DT_LIN2WD (uptr -> pos, uptr); + wrd = DT_LIN2WD (uptr->pos, uptr); ba = (blk * DTU_BSIZE (uptr)) + wrd; bptr[ba] = dat; /* write word */ - if (ba >= uptr -> hwmark) uptr -> hwmark = ba + 1; } + if (ba >= uptr->hwmark) uptr->hwmark = ba + 1; } /* /* ignore hdr */ sim_activate (uptr, DT_WSIZE * dt_ltime); if (M[DT_WC] == 0) dt_substate = DTO_WCO; @@ -907,7 +925,7 @@ return 0; void dt_seterr (UNIT *uptr, int32 e) { -int32 mot = DTS_GETMOT (uptr -> STATE); +int32 mot = DTS_GETMOT (uptr->STATE); dtsa = dtsa & ~DTA_STSTP; /* clear go */ dtsb = dtsb | DTB_ERF | e; /* set error flag */ @@ -928,7 +946,7 @@ int32 newpos; if (dir) newpos = DT_EZLIN - DT_WSIZE; /* rev? rev ez */ else newpos = DTU_FWDEZ (uptr) + DT_WSIZE; /* fwd? fwd ez */ -sim_activate (uptr, ABS (newpos - ((int32) uptr -> pos)) * dt_ltime); +sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime); return; } @@ -946,7 +964,7 @@ return dat; int32 dt_csum (UNIT *uptr, int32 blk) { -int16 *bptr = uptr -> filebuf; +int16 *bptr = uptr->filebuf; int32 ba = blk * DTU_BSIZE (uptr); int32 i, csum, wrd; @@ -967,7 +985,7 @@ UNIT *uptr; for (i = 0; i < DT_NUMDR; i++) { /* stop all activity */ uptr = dt_dev.units + i; if (sim_is_running) { /* CAF? */ - prev_mot = DTS_GETMOT (uptr -> STATE); /* get motion */ + prev_mot = DTS_GETMOT (uptr->STATE); /* get motion */ if ((prev_mot & ~DTS_DIR) > DTS_DECF) { /* accel or spd? */ if (dt_setpos (uptr)) continue; /* update pos */ sim_cancel (uptr); @@ -975,8 +993,8 @@ for (i = 0; i < DT_NUMDR; i++) { /* stop all activity */ DTS_SETSTA (DTS_DECF | (prev_mot & DTS_DIR), 0); } } else { sim_cancel (uptr); /* sim reset */ - uptr -> STATE = 0; - uptr -> LASTT = sim_grtime (); } } + uptr->STATE = 0; + uptr->LASTT = sim_grtime (); } } dtsa = dtsb = 0; /* clear status */ DT_UPDINT; /* reset interrupt */ return SCPE_OK; @@ -990,9 +1008,9 @@ return SCPE_OK; */ #define BOOT_START 0200 -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int)) +#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) -static const int32 boot_rom[] = { +static const uint16 boot_rom[] = { 07600, /* 200, CLA CLL */ 01216, /* TAD MVB ; move back */ 04210, /* JMS DO ; action */ @@ -1014,12 +1032,13 @@ static const int32 boot_rom[] = { 00220 /* RF, 0220 */ }; -t_stat dt_boot (int32 unitno) +t_stat dt_boot (int32 unitno, DEVICE *dptr) { int32 i; extern int32 saved_PC; if (unitno) return SCPE_ARG; /* only unit 0 */ +if (dt_dib.dev != DEV_DTA) return STOP_NOTSTD; /* only std devno */ dt_unit[unitno].pos = DT_EZLIN; for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i]; saved_PC = BOOT_START; @@ -1028,107 +1047,121 @@ return SCPE_OK; /* Attach routine - Determine native or PDP11/15 format + Determine 12b, 16b, or 18b/36b format Allocate buffer - If native, read data into buffer - If PDP9/11/15, convert 18b data to 12b and read into buffer + If 16b or 18b, read 16b or 18b format and convert to 12b in buffer + If 12b, read data into buffer */ t_stat dt_attach (UNIT *uptr, char *cptr) { uint32 pdp18b[D18_NBSIZE]; -int32 k, p; -int16 *bptr; +uint16 pdp11b[D18_NBSIZE], *bptr; +int32 i, k, p; t_stat r; t_addr ba; -uptr -> flags = uptr -> flags | UNIT_8FMT; r = attach_unit (uptr, cptr); /* attach */ if (r != SCPE_OK) return r; /* fail? */ -if (sim_switches & SWMASK ('F')) /* att foreign? */ - uptr -> flags = uptr -> flags & ~UNIT_8FMT; /* PDP8 = F */ -else if (!(sim_switches & SWMASK ('N'))) { /* autosize? */ - if ((fseek (uptr -> fileref, 0, SEEK_END) == 0) && - (p = ftell (uptr -> fileref)) && - (p == D18_FILSIZ)) uptr -> flags = uptr -> flags & ~UNIT_8FMT; } -uptr -> capac = DTU_CAPAC (uptr); /* set capacity */ -uptr -> filebuf = calloc (uptr -> capac, sizeof (int16)); -if (uptr -> filebuf == NULL) { /* can't alloc? */ +uptr->flags = (uptr->flags | UNIT_8FMT) & ~UNIT_11FMT; +if (sim_switches & SWMASK ('T')) /* att 18b? */ + uptr->flags = uptr->flags & ~UNIT_8FMT; +else if (sim_switches & SWMASK ('S')) /* att 16b? */ + uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT; +else if (!(sim_switches & SWMASK ('R')) && /* autosize? */ + (fseek (uptr->fileref, 0, SEEK_END) == 0) && + ((p = ftell (uptr->fileref)) > 0)) { + if (p == D11_FILSIZ) + uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT; + if (p > D8_FILSIZ) uptr->flags = uptr->flags & ~UNIT_8FMT; } +uptr->capac = DTU_CAPAC (uptr); /* set capacity */ +uptr->filebuf = calloc (uptr->capac, sizeof (int16)); +if (uptr->filebuf == NULL) { /* can't alloc? */ detach_unit (uptr); return SCPE_MEM; } -printf ("%DT: buffering file in memory\n"); -rewind (uptr -> fileref); /* start of file */ -bptr = uptr -> filebuf; /* file buffer */ -if (uptr -> flags & UNIT_8FMT) /* PDP8? */ - uptr -> hwmark = fxread (uptr -> filebuf, sizeof (int16), - uptr -> capac, uptr -> fileref); -else { /* PDP9/11/15 */ - for (ba = 0; ba < uptr -> capac; ) { /* loop thru file */ - k = fxread (pdp18b, sizeof (int32), D18_NBSIZE, uptr -> fileref); - if (k == 0) break; - for ( ; k < D18_NBSIZE; k++) pdp18b[k] = 0; - for (k = 0; k < D18_NBSIZE; k = k + 2) { /* loop thru blk */ - bptr[ba] = (pdp18b[k] >> 6) & 07777; - bptr[ba + 1] = ((pdp18b[k] & 077) << 6) | - ((pdp18b[k + 1] >> 12) & 077); - bptr[ba + 2] = pdp18b[k + 1] & 07777; - ba = ba + 3; } /* end blk loop */ - } /* end file loop */ - uptr -> hwmark = ba; } /* end else */ -uptr -> flags = uptr -> flags | UNIT_BUF; /* set buf flag */ -uptr -> pos = DT_EZLIN; /* beyond leader */ -uptr -> LASTT = sim_grtime (); /* last pos update */ +bptr = uptr->filebuf; /* file buffer */ +if (uptr->flags & UNIT_8FMT) printf ("DT: 12b format"); +else if (uptr->flags & UNIT_11FMT) printf ("DT: 16b format"); +else printf ("DT: 18b/36b format"); +printf (", buffering file in memory\n"); +rewind (uptr->fileref); /* start of file */ +if (uptr->flags & UNIT_8FMT) /* 12b? */ + uptr->hwmark = fxread (uptr->filebuf, sizeof (int16), + uptr->capac, uptr->fileref); +else { /* 16b/18b */ + for (ba = 0; ba < uptr->capac; ) { /* loop thru file */ + if (uptr->flags & UNIT_11FMT) { + k = fxread (pdp11b, sizeof (int16), D18_NBSIZE, uptr->fileref); + for (i = 0; i < k; i++) pdp18b[i] = pdp11b[i]; } + else k = fxread (pdp18b, sizeof (int32), D18_NBSIZE, uptr->fileref); + if (k == 0) break; + for ( ; k < D18_NBSIZE; k++) pdp18b[k] = 0; + for (k = 0; k < D18_NBSIZE; k = k + 2) { /* loop thru blk */ + bptr[ba] = (pdp18b[k] >> 6) & 07777; + bptr[ba + 1] = ((pdp18b[k] & 077) << 6) | + ((pdp18b[k + 1] >> 12) & 077); + bptr[ba + 2] = pdp18b[k + 1] & 07777; + ba = ba + 3; } /* end blk loop */ + } /* end file loop */ + uptr->hwmark = ba; } /* end else */ +uptr->flags = uptr->flags | UNIT_BUF; /* set buf flag */ +uptr->pos = DT_EZLIN; /* beyond leader */ +uptr->LASTT = sim_grtime (); /* last pos update */ return SCPE_OK; } /* Detach routine Cancel in progress operation - If native, write buffer to file - If PDP9/11/15, convert 12b buffer to 18b and write to file + If 12b, write buffer to file + If 16b or 18b, convert 12b buffer to 16b or 18b and write to file Deallocate buffer */ t_stat dt_detach (UNIT* uptr) { uint32 pdp18b[D18_NBSIZE]; -int32 k; +uint16 pdp11b[D18_NBSIZE], *bptr; +int32 i, k; int32 unum = uptr - dt_dev.units; -int16 *bptr; t_addr ba; -if (!(uptr -> flags & UNIT_ATT)) return SCPE_OK; +if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; if (sim_is_active (uptr)) { sim_cancel (uptr); if ((unum == DTA_GETUNIT (dtsa)) && (dtsa & DTA_STSTP)) { - dtsb = dtsb | DTB_ERF | DTB_SEL | DTB_DTF; - DT_UPDINT; } - uptr -> STATE = uptr -> pos = 0; } -if (uptr -> hwmark && ((uptr -> flags & UNIT_RO)== 0)) { /* any data? */ + dtsb = dtsb | DTB_ERF | DTB_SEL | DTB_DTF; + DT_UPDINT; } + uptr->STATE = uptr->pos = 0; } +bptr = uptr->filebuf; /* file buffer */ +if (uptr->hwmark && ((uptr->flags & UNIT_RO)== 0)) { /* any data? */ printf ("DT: writing buffer to file\n"); - rewind (uptr -> fileref); /* start of file */ - bptr = uptr -> filebuf; /* file buffer */ - if (uptr -> flags & UNIT_8FMT) /* PDP8? */ - fxwrite (uptr -> filebuf, sizeof (int16), /* write file */ - uptr -> hwmark, uptr -> fileref); - else { /* PDP9/11/15 */ - for (ba = 0; ba < uptr -> hwmark; ) { /* loop thru buf */ - for (k = 0; k < D18_NBSIZE; k = k + 2) { - pdp18b[k] = ((uint32) (bptr[ba] & 07777) << 6) | - ((uint32) (bptr[ba + 1] >> 6) & 077); - pdp18b[k + 1] = ((uint32) (bptr[ba + 1] & 077) << 12) | - ((uint32) (bptr[ba + 2] & 07777)); - ba = ba + 3; } /* end loop blk */ - fxwrite (pdp18b, sizeof (int32), - D18_NBSIZE, uptr -> fileref); + rewind (uptr->fileref); /* start of file */ + if (uptr->flags & UNIT_8FMT) /* PDP8? */ + fxwrite (uptr->filebuf, sizeof (int16), /* write file */ + uptr->hwmark, uptr->fileref); + else { /* 16b/18b */ + for (ba = 0; ba < uptr->hwmark; ) { /* loop thru buf */ + for (k = 0; k < D18_NBSIZE; k = k + 2) { + pdp18b[k] = ((uint32) (bptr[ba] & 07777) << 6) | + ((uint32) (bptr[ba + 1] >> 6) & 077); + pdp18b[k + 1] = ((uint32) (bptr[ba + 1] & 077) << 12) | + ((uint32) (bptr[ba + 2] & 07777)); + ba = ba + 3; } /* end loop blk */ + if (uptr->flags & UNIT_11FMT) { /* 16b? */ + for (i = 0; i < D18_NBSIZE; i++) pdp11b[i] = pdp18b[i]; + fxwrite (pdp11b, sizeof (int16), + D18_NBSIZE, uptr->fileref); } + else fxwrite (pdp18b, sizeof (int32), + D18_NBSIZE, uptr->fileref); } /* end loop buf */ } /* end else */ - if (ferror (uptr -> fileref)) perror ("I/O error"); + if (ferror (uptr->fileref)) perror ("I/O error"); } /* end if hwmark */ -free (uptr -> filebuf); /* release buf */ -uptr -> flags = uptr -> flags & ~UNIT_BUF; /* clear buf flag */ -uptr -> filebuf = NULL; /* clear buf ptr */ -uptr -> flags = uptr -> flags | UNIT_8FMT; /* default fmt */ -uptr -> capac = DT_CAPAC; /* default size */ +free (uptr->filebuf); /* release buf */ +uptr->flags = uptr->flags & ~UNIT_BUF; /* clear buf flag */ +uptr->filebuf = NULL; /* clear buf ptr */ +uptr->flags = (uptr->flags | UNIT_8FMT) & ~UNIT_11FMT; /* default fmt */ +uptr->capac = DT_CAPAC; /* default size */ return detach_unit (uptr); } diff --git a/PDP8/pdp8_lp.c b/PDP8/pdp8_lp.c index 0c4d3920..604d7104 100644 --- a/PDP8/pdp8_lp.c +++ b/PDP8/pdp8_lp.c @@ -25,14 +25,19 @@ lpt LP8E line printer + 04-Oct-02 RMS Added DIB, enable/disable, device number support 30-May-02 RMS Widened POS to 32b */ #include "pdp8_defs.h" extern int32 int_req, int_enable, dev_done, stop_inst; + int32 lpt_err = 0; /* error flag */ int32 lpt_stopioe = 0; /* stop on error */ + +DEVICE lpt_dev; +int32 lpt (int32 IR, int32 AC); t_stat lpt_svc (UNIT *uptr); t_stat lpt_reset (DEVICE *dptr); t_stat lpt_attach (UNIT *uptr, char *cptr); @@ -45,6 +50,8 @@ t_stat lpt_detach (UNIT *uptr); lpt_reg LPT register list */ +DIB lpt_dib = { DEV_LPT, 1, { &lpt } }; + UNIT lpt_unit = { UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; @@ -57,19 +64,26 @@ REG lpt_reg[] = { { DRDATA (POS, lpt_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT }, { FLDATA (STOP_IOE, lpt_stopioe, 0) }, + { ORDATA (DEVNUM, lpt_dib.dev, 6), REG_HRO }, { NULL } }; +MTAB lpt_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", + &set_dev, &show_dev, NULL }, + { 0 } }; + DEVICE lpt_dev = { - "LPT", &lpt_unit, lpt_reg, NULL, + "LPT", &lpt_unit, lpt_reg, lpt_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &lpt_reset, - NULL, &lpt_attach, &lpt_detach }; + NULL, &lpt_attach, &lpt_detach, + &lpt_dib, DEV_DISABLE }; /* IOT routine */ -int32 lpt (int32 pulse, int32 AC) +int32 lpt (int32 IR, int32 AC) { -switch (pulse) { /* decode IR<9:11> */ +switch (IR & 07) { /* decode IR<9:11> */ case 1: /* PSKF */ return (dev_done & INT_LPT)? IOT_SKP + AC: AC; case 2: /* PCLF */ diff --git a/PDP8/pdp8_mt.c b/PDP8/pdp8_mt.c index 23c7f606..8b9dfb5a 100644 --- a/PDP8/pdp8_mt.c +++ b/PDP8/pdp8_mt.c @@ -25,6 +25,10 @@ mt TM8E/TU10 magtape + 30-Oct-02 RMS Revised BOT handling, added error record handling + 04-Oct-02 RMS Added DIBs, device number support + 30-Aug-02 RMS Revamped error handling + 28-Aug-02 RMS Added end of medium support 30-May-02 RMS Widened POS to 32b 22-Apr-02 RMS Added maximum record length test 06-Jan-02 RMS Changed enable/disable support @@ -54,10 +58,10 @@ #define MT_NUMDR 8 /* #drives */ #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_V_PNU (UNIT_V_UF + 1) /* pos not updated */ #define UNIT_WLK (1 << UNIT_V_WLK) -#define UNIT_W_UF 2 /* saved user flags */ +#define UNIT_PNU (1 << UNIT_V_PNU) #define USTAT u3 /* unit status */ -#define UNUM u4 /* unit number */ #define MT_MAXFR (1 << 16) /* max record lnt */ #define DBSIZE (1 << 12) /* max data cmd */ #define DBMASK (SBSIZE - 1) @@ -94,10 +98,10 @@ #define FN_CRC 00200 /* read CRC */ #define FN_GO 00100 /* go */ #define FN_INC 00040 /* incr mode */ -#define FN_RMASK 07740 /* readable bits */ +#define FN_RMASK 07700 /* readable bits */ #define GET_FNC(x) (((x) >> FN_V_FNC) & FN_M_FNC) -/* Status - stored in mt_sta or (*) uptr -> USTAT */ +/* Status - stored in mt_sta or (*) uptr->USTAT */ #define STA_ERR (04000 << 12) /* error */ #define STA_REW (02000 << 12) /* *rewinding */ @@ -111,6 +115,8 @@ #define STA_WLK (00004 << 12) /* *write locked */ #define STA_CPE (00002 << 12) /* compare error */ #define STA_ILL (00001 << 12) /* illegal */ +#define STA_9TK 00040 /* 9 track */ +/* #define STA_BAD 00020 /* bad tape?? */ #define STA_INC 00010 /* increment error */ #define STA_LAT 00004 /* lateral par error */ #define STA_CRC 00002 /* CRC error */ @@ -120,13 +126,15 @@ #define STA_DYN (STA_REW | STA_BOT | STA_REM | STA_EOF | \ STA_EOT | STA_WLK) /* kept in USTAT */ #define STA_EFLGS (STA_BOT | STA_PAR | STA_RLE | STA_DLT | \ - STA_EOT | STA_CPE | STA_ILL | STA_EOF | STA_INC) + STA_EOT | STA_CPE | STA_ILL | STA_EOF | \ + STA_INC ) /* set error */ #define TUR(u) (!sim_is_active (u)) /* tape unit ready */ extern uint16 M[]; -extern int32 int_req, dev_enb, stop_inst; +extern int32 int_req, stop_inst; extern UNIT cpu_unit; + int32 mt_cu = 0; /* command/unit */ int32 mt_fn = 0; /* function */ int32 mt_ca = 0; /* current address */ @@ -136,6 +144,11 @@ int32 mt_db = 0; /* data buffer */ int32 mt_done = 0; /* mag tape flag */ int32 mt_time = 10; /* record latency */ int32 mt_stopioe = 1; /* stop on error */ + +DEVICE mt_dev; +int32 mt70 (int32 IR, int32 AC); +int32 mt71 (int32 IR, int32 AC); +int32 mt72 (int32 IR, int32 AC); t_stat mt_svc (UNIT *uptr); t_stat mt_reset (DEVICE *dptr); t_stat mt_attach (UNIT *uptr, char *cptr); @@ -145,6 +158,8 @@ int32 mt_ixma (int32 xma); t_stat mt_vlock (UNIT *uptr, int32 val, char *cptr, void *desc); UNIT *mt_busy (void); void mt_set_done (void); +t_bool mt_rdlntf (UNIT *uptr, t_mtrlnt *tbc, int32 *err); +t_bool mt_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err); /* MT data structures @@ -154,6 +169,8 @@ void mt_set_done (void); mt_mod MT modifier list */ +DIB mt_dib = { DEV_MT, 3, { &mt70, &mt71, &mt72 } }; + UNIT mt_unit[] = { { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, @@ -179,33 +196,32 @@ REG mt_reg[] = { { URDATA (UST, mt_unit[0].USTAT, 8, 16, 0, MT_NUMDR, 0) }, { URDATA (POS, mt_unit[0].pos, 10, 32, 0, MT_NUMDR, PV_LEFT | REG_RO) }, - { URDATA (FLG, mt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, - MT_NUMDR, REG_HRO) }, - { FLDATA (*DEVENB, dev_enb, INT_V_MT), REG_HRO }, + { FLDATA (DEVNUM, mt_dib.dev, 6), REG_HRO }, { NULL } }; MTAB mt_mod[] = { { UNIT_WLK, 0, "write enabled", "WRITEENABLED", &mt_vlock }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &mt_vlock }, - { MTAB_XTD|MTAB_VDV, INT_MT, NULL, "ENABLED", &set_enb }, - { MTAB_XTD|MTAB_VDV, INT_MT, NULL, "DISABLED", &set_dsb }, + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", + &set_dev, &show_dev, NULL }, { 0 } }; DEVICE mt_dev = { "MT", mt_unit, mt_reg, mt_mod, MT_NUMDR, 10, 31, 1, 8, 8, NULL, NULL, &mt_reset, - NULL, &mt_attach, &mt_detach }; + NULL, &mt_attach, &mt_detach, + &mt_dib, DEV_DISABLE }; /* IOT routines */ -int32 mt70 (int32 pulse, int32 AC) +int32 mt70 (int32 IR, int32 AC) { int32 f; UNIT *uptr; uptr = mt_dev.units + GET_UNIT (mt_cu); /* get unit */ -switch (pulse) { /* decode IR<9:11> */ +switch (IR & 07) { /* decode IR<9:11> */ case 1: /* LWCR */ mt_wc = AC; /* load word count */ return 0; @@ -223,9 +239,6 @@ case 5: /* LCMR */ mt_cu = AC; /* load command reg */ mt_updcsta (mt_dev.units + GET_UNIT (mt_cu)); return 0; - -/* MT70, continued */ - case 6: /* LFGR */ if (mt_busy ()) mt_sta = mt_sta | STA_ILL; /* busy? illegal op */ mt_fn = AC; /* load function */ @@ -233,20 +246,20 @@ case 6: /* LFGR */ mt_updcsta (uptr); /* update status */ return 0; } f = GET_FNC (mt_fn); /* get function */ - if (((uptr -> flags & UNIT_ATT) == 0) || !TUR (uptr) || - (((f == FN_WRITE) || (f == FN_WREOF)) && (uptr -> flags & UNIT_WPRT)) - || (((f == FN_SPACER) || (f == FN_REWIND)) && (uptr -> pos == 0))) { + if (((uptr->flags & UNIT_ATT) == 0) || !TUR (uptr) || + (((f == FN_WRITE) || (f == FN_WREOF)) && (uptr->flags & UNIT_WPRT)) + || (((f == FN_SPACER) || (f == FN_REWIND)) && (uptr->USTAT & STA_BOT))) { mt_sta = mt_sta | STA_ILL; /* illegal op error */ mt_set_done (); /* set done */ mt_updcsta (uptr); /* update status */ return 0; } - uptr -> USTAT = uptr -> USTAT & STA_WLK; /* clear status */ + uptr->USTAT = uptr->USTAT & STA_WLK; /* clear status */ if (f == FN_UNLOAD) { /* unload? */ detach_unit (uptr); /* set offline */ - uptr -> USTAT = STA_REW | STA_REM; /* rewinding, off */ + uptr->USTAT = STA_REW | STA_REM; /* rewinding, off */ mt_set_done (); } /* set done */ else if (f == FN_REWIND) { /* rewind */ - uptr -> USTAT = uptr -> USTAT | STA_REW; /* rewinding */ + uptr->USTAT = uptr->USTAT | STA_REW; /* rewinding */ mt_set_done (); } /* set done */ else mt_done = 0; /* clear done */ mt_updcsta (uptr); /* update status */ @@ -257,18 +270,18 @@ case 7: /* LDBR */ mt_db = AC; /* load buffer */ mt_set_done (); /* set done */ mt_updcsta (uptr); /* update status */ - return 0; } /* end switch */ + return 0; } /* end switch */ return (stop_inst << IOT_V_REASON) + AC; /* ill inst */ } /* IOTs, continued */ -int32 mt71 (int32 pulse, int32 AC) +int32 mt71 (int32 IR, int32 AC) { UNIT *uptr; uptr = mt_dev.units + GET_UNIT (mt_cu); -switch (pulse) { /* decode IR<9:11> */ +switch (IR & 07) { /* decode IR<9:11> */ case 1: /* RWCR */ return mt_wc; /* read word count */ case 2: /* CLT */ @@ -284,16 +297,16 @@ case 6: /* RFSR */ return (((mt_fn & FN_RMASK) | (mt_updcsta (uptr) & ~FN_RMASK)) & 07777); /* read function */ case 7: /* RDBR */ - return mt_db; } /* read data buffer */ -return (stop_inst << IOT_V_REASON) + AC; /* ill inst */ + return mt_db; } /* read data buffer */ +return (stop_inst << IOT_V_REASON) + AC; /* ill inst */ } -int32 mt72 (int32 pulse, int32 AC) +int32 mt72 (int32 IR, int32 AC) { UNIT *uptr; uptr = mt_dev.units + GET_UNIT (mt_cu); /* get unit */ -switch (pulse) { /* decode IR<9:11> */ +switch (IR & 07) { /* decode IR<9:11> */ case 1: /* SKEF */ return (mt_sta & STA_ERR)? IOT_SKP + AC: AC; case 2: /* SKCB */ @@ -308,7 +321,7 @@ case 5: /* CLF */ mt_done = 0; /* clear done */ mt_updcsta (uptr); } /* update status */ return AC; } /* end switch */ -return (stop_inst << IOT_V_REASON) + AC; /* ill inst */ +return (stop_inst << IOT_V_REASON) + AC; /* ill inst */ } /* Unit service @@ -319,40 +332,41 @@ return (stop_inst << IOT_V_REASON) + AC; /* ill inst */ t_stat mt_svc (UNIT *uptr) { -int32 f, i, p, u, err, wc, xma; -t_stat rval; -t_mtrlnt tbc, cbc; +int32 f, i, p, u, err, wc, xma, pnu; +t_mtrlnt abc, tbc, cbc; uint16 c, c1, c2; uint8 dbuf[(2 * DBSIZE)]; -static t_mtrlnt bceof = { 0 }; +static t_mtrlnt bceof = MTR_TMK; -u = uptr -> UNUM; /* get unit number */ -if (uptr -> USTAT & STA_REW) { /* rewind? */ - uptr -> pos = 0; /* update position */ - if (uptr -> flags & UNIT_ATT) /* still on line? */ - uptr -> USTAT = (uptr -> USTAT & STA_WLK) | STA_BOT; - else uptr -> USTAT = STA_REM; +err = 0; +u = uptr - mt_dev.units; /* get unit number */ +f = GET_FNC (mt_fn); /* get command */ +pnu = MT_TST_PNU (uptr); /* get pos not upd */ +MT_CLR_PNU (uptr); /* and clear */ + +if (uptr->USTAT & STA_REW) { /* rewind? */ + uptr->pos = 0; /* update position */ + if (uptr->flags & UNIT_ATT) /* still on line? */ + uptr->USTAT = (uptr->USTAT & STA_WLK) | STA_BOT; + else uptr->USTAT = STA_REM; if (u == GET_UNIT (mt_cu)) { /* selected? */ mt_set_done (); /* set done */ mt_updcsta (uptr); } /* update status */ return SCPE_OK; } -if ((uptr -> flags & UNIT_ATT) == 0) { /* if not attached */ - uptr -> USTAT = STA_REM; /* unit off line */ +if ((uptr->flags & UNIT_ATT) == 0) { /* if not attached */ + uptr->USTAT = STA_REM; /* unit off line */ mt_sta = mt_sta | STA_ILL; /* illegal operation */ mt_set_done (); /* set done */ mt_updcsta (uptr); /* update status */ return IORETURN (mt_stopioe, SCPE_UNATT); } -f = GET_FNC (mt_fn); /* get command */ -if (((f == FN_WRITE) || (f == FN_WREOF)) && (uptr -> flags & UNIT_WPRT)) { +if (((f == FN_WRITE) || (f == FN_WREOF)) && (uptr->flags & UNIT_WPRT)) { mt_sta = mt_sta | STA_ILL; /* illegal operation */ mt_set_done (); /* set done */ mt_updcsta (uptr); /* update status */ return SCPE_OK; } -err = 0; -rval = SCPE_OK; xma = GET_EMA (mt_cu) + mt_ca; /* get mem addr */ wc = 010000 - mt_wc; /* get wc */ switch (f) { /* case on function */ @@ -361,26 +375,21 @@ switch (f) { /* case on function */ case FN_READ: /* read */ case FN_CMPARE: /* read/compare */ - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); - fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - if ((err = ferror (uptr -> fileref)) || /* error or eof? */ - (feof (uptr -> fileref))) { - uptr -> USTAT = uptr -> USTAT | STA_EOT | STA_RLE; + if (mt_rdlntf (uptr, &tbc, &err)) { /* read rec lnt */ + mt_sta = mt_sta | STA_RLE; /* err, eof/eom, tmk */ break; } - if (tbc == 0) { /* tape mark? */ - uptr -> USTAT = uptr -> USTAT | STA_EOF | STA_RLE; - uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); - break; } - tbc = MTRL (tbc); /* ignore error flag */ if (tbc > MT_MAXFR) return SCPE_MTRLNT; /* record too long? */ cbc = (mt_cu & CU_UNPAK)? wc: wc * 2; /* expected bc */ if (tbc != cbc) mt_sta = mt_sta | STA_RLE; /* wrong size? */ if (tbc < cbc) { /* record small? */ cbc = tbc; /* use smaller */ wc = (mt_cu & CU_UNPAK)? cbc: (cbc + 1) / 2; } - i = fxread (dbuf, sizeof (int8), cbc, uptr -> fileref); - for ( ; i < cbc; i++) dbuf[i] = 0; /* fill with 0's */ - err = ferror (uptr -> fileref); + abc = fxread (dbuf, sizeof (uint8), cbc, uptr->fileref); + if (err = ferror (uptr->fileref)) { /* error? */ + mt_sta = mt_sta | STA_RLE; /* set flag */ + MT_SET_PNU (uptr); /* pos not upd */ + break; } + for ( ; abc < cbc; abc++) dbuf[abc] = 0; /* fill with 0's */ for (i = p = 0; i < wc; i++) { /* copy buffer */ xma = mt_ixma (xma); /* increment xma */ if (mt_cu & CU_UNPAK) c = dbuf[p++]; @@ -392,94 +401,70 @@ case FN_CMPARE: /* read/compare */ mt_sta = mt_sta | STA_CPE; break; } } mt_wc = (mt_wc + wc) & 07777; /* update wc */ - uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) + /* update tape pos */ - (2 * sizeof (t_mtrlnt)); + uptr->pos = uptr->pos + ((tbc + 1) & ~1) + /* update tape pos */ + (2 * sizeof (t_mtrlnt)); break; + case FN_WRITE: /* write */ - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); + fseek (uptr->fileref, uptr->pos, SEEK_SET); tbc = (mt_cu & CU_UNPAK)? wc: wc * 2; - fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); + fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr->fileref); for (i = p = 0; i < wc; i++) { /* copy buf to tape */ xma = mt_ixma (xma); /* incr mem addr */ if (mt_cu & CU_UNPAK) dbuf[p++] = M[xma] & 0377; else { dbuf[p++] = (M[xma] >> 6) & 077; dbuf[p++] = M[xma] & 077; } } - fxwrite (dbuf, sizeof (int8), (tbc + 1) & ~1, uptr -> fileref); - fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - err = ferror (uptr -> fileref); - mt_wc = 0; - uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) + /* update tape pos */ - (2 * sizeof (t_mtrlnt)); - break; -case FN_WREOF: - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); - fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr -> fileref); /* write eof */ - err = ferror (uptr -> fileref); - uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); /* update tape pos */ + fxwrite (dbuf, sizeof (int8), (tbc + 1) & ~1, uptr->fileref); + fxwrite (&tbc, sizeof (t_mtrlnt), 1, uptr->fileref); + if (err = ferror (uptr->fileref)) MT_SET_PNU (uptr); /* error? */ + else { mt_wc = 0; + uptr->pos = uptr->pos + ((tbc + 1) & ~1) + /* upd tape pos */ + (2 * sizeof (t_mtrlnt)); } break; /* Unit service, continued */ +case FN_WREOF: + fseek (uptr->fileref, uptr->pos, SEEK_SET); + fxwrite (&bceof, sizeof (t_mtrlnt), 1, uptr->fileref); /* write eof */ + if (err = ferror (uptr->fileref)) MT_SET_PNU (uptr); /* error? */ + else uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* update tape pos */ + break; + case FN_SPACEF: /* space forward */ do { mt_wc = (mt_wc + 1) & 07777; /* incr wc */ - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); - fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - if ((err = ferror (uptr -> fileref)) || /* error or eof? */ - feof (uptr -> fileref)) { - uptr -> USTAT = uptr -> USTAT | STA_EOT; - break; } - if (tbc == 0) { /* zero bc? */ - uptr -> USTAT = uptr -> USTAT | STA_EOF; - uptr -> pos = uptr -> pos + sizeof (t_mtrlnt); - break; } - uptr -> pos = uptr -> pos + ((MTRL (tbc) + 1) & ~1) + + if (mt_rdlntf (uptr, &tbc, &err)) break;/* read rec lnt, err? */ + uptr->pos = uptr->pos + ((tbc + 1) & ~1) + (2 * sizeof (t_mtrlnt)); } while (mt_wc != 0); break; + case FN_SPACER: /* space reverse */ - if (uptr -> pos == 0) { /* at BOT? */ - uptr -> USTAT = uptr -> USTAT | STA_BOT; - break; } do { mt_wc = (mt_wc + 1) & 07777; /* incr wc */ - fseek (uptr -> fileref, uptr -> pos - sizeof (t_mtrlnt), - SEEK_SET); - fxread (&tbc, sizeof (t_mtrlnt), 1, uptr -> fileref); - if ((err = ferror (uptr -> fileref)) || /* error or eof? */ - feof (uptr -> fileref)) { - uptr -> USTAT = uptr -> USTAT | STA_BOT; - uptr -> pos = 0; - break; } - if (tbc == 0) { /* start of prv file? */ - uptr -> USTAT = uptr -> USTAT | STA_EOF; - uptr -> pos = uptr -> pos - sizeof (t_mtrlnt); - break; } - uptr -> pos = uptr -> pos - ((MTRL (tbc) + 1) & ~1) - - (2 * sizeof (t_mtrlnt)); - if (uptr -> pos == 0) { /* at BOT? */ - uptr -> USTAT = uptr -> USTAT | STA_BOT; - break; } } + if (pnu) pnu = 0; /* pos not upd? */ + else { if (mt_rdlntr (uptr, &tbc, &err)) break; + uptr->pos = uptr->pos - ((tbc + 1) & ~1) - + (2 * sizeof (t_mtrlnt)); } } while (mt_wc != 0); break; } /* end case */ - -/* Unit service, continued */ -if (err != 0) { /* I/O error */ - mt_sta = mt_sta | STA_PAR | STA_CRC; /* flag error */ - perror ("MT I/O error"); - rval = SCPE_IOERR; - clearerr (uptr -> fileref); } +if (err != 0) mt_sta = mt_sta | STA_PAR; /* error? set flag */ mt_cu = (mt_cu & ~CU_EMA) | ((xma >> (12 - CU_V_EMA)) & CU_EMA); mt_ca = xma & 07777; /* update mem addr */ mt_set_done (); /* set done */ mt_updcsta (uptr); /* update status */ -return IORETURN (mt_stopioe, rval); +if (err != 0) { /* error? */ + perror ("MT I/O error"); + clearerr (uptr->fileref); + if (mt_stopioe) return SCPE_IOERR; } +return SCPE_OK; } /* Update controller status */ int32 mt_updcsta (UNIT *uptr) { -mt_sta = (mt_sta & ~(STA_DYN | STA_ERR | STA_CLR)) | (uptr -> USTAT & STA_DYN); +mt_sta = (mt_sta & ~(STA_DYN | STA_ERR | STA_CLR)) | (uptr->USTAT & STA_DYN); if (mt_sta & STA_EFLGS) mt_sta = mt_sta | STA_ERR; if (((mt_sta & STA_ERR) && (mt_cu & CU_IEE)) || (mt_done && (mt_cu & CU_IED))) int_req = int_req | INT_MT; @@ -496,7 +481,7 @@ UNIT *uptr; for (u = 0; u < MT_NUMDR; u++) { /* loop thru units */ uptr = mt_dev.units + u; - if (sim_is_active (uptr) && ((uptr -> USTAT & STA_REW) == 0)) + if (sim_is_active (uptr) && ((uptr->USTAT & STA_REW) == 0)) return uptr; } return NULL; } @@ -522,6 +507,52 @@ mt_done = 1; /* set done */ mt_fn = mt_fn & ~(FN_CRC | FN_GO | FN_INC); /* clear func<4:6> */ return; } + +/* Read record length forward - return T if error, EOM, or EOF */ + +t_bool mt_rdlntf (UNIT *uptr, t_mtrlnt *tbc, int32 *err) +{ +fseek (uptr->fileref, uptr->pos, SEEK_SET); /* set tape pos */ +fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); /* read rec lnt */ +if ((*err = ferror (uptr->fileref)) || /* error, */ + feof (uptr->fileref) || (*tbc == MTR_EOM)) { /* eof or eom? */ + mt_sta = mt_sta | STA_PAR; /* parity error */ + MT_SET_PNU (uptr); /* pos not upd */ + return TRUE; } +if (*tbc == MTR_TMK) { /* tape mark? */ + uptr->USTAT = uptr->USTAT | STA_EOF; /* end of file */ + uptr->pos = uptr->pos + sizeof (t_mtrlnt); /* spc over tmk */ + return TRUE; } +if (MTRF (*tbc)) mt_sta = mt_sta | STA_PAR; /* record in error? */ +*tbc = MTRL (*tbc); /* clear error flag */ +return FALSE; +} + +/* Read record length reverse - return T if error, EOM, or EOF */ + +t_bool mt_rdlntr (UNIT *uptr, t_mtrlnt *tbc, int32 *err) +{ +if (uptr->pos < sizeof (t_mtrlnt)) { /* at BOT? */ + uptr->USTAT = uptr->USTAT | STA_BOT; /* set status */ + return TRUE; } /* error */ +fseek (uptr->fileref, uptr->pos - sizeof (t_mtrlnt), SEEK_SET); +fxread (tbc, sizeof (t_mtrlnt), 1, uptr->fileref); +if ((*err = ferror (uptr->fileref)) || /* error? */ + feof (uptr->fileref)) { /* end of file? */ + mt_sta = mt_sta | STA_PAR; /* parity error */ + return TRUE; } +if (*tbc == MTR_EOM) { /* eom? */ + mt_sta = mt_sta | STA_PAR; /* bad tape */ + uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over eom */ + return TRUE; } +if (*tbc == MTR_TMK) { /* tape mark? */ + uptr->USTAT = uptr->USTAT | STA_EOF; /* end of file */ + uptr->pos = uptr->pos - sizeof (t_mtrlnt); /* spc over tmk */ + return TRUE; } +if (MTRF (*tbc)) mt_sta = mt_sta | STA_PAR; /* record in error? */ +*tbc = MTRL (*tbc); /* clear error flag */ +return FALSE; +} /* Reset routine */ @@ -534,12 +565,12 @@ mt_cu = mt_fn = mt_wc = mt_ca = mt_db = mt_sta = mt_done = 0; int_req = int_req & ~INT_MT; /* clear interrupt */ for (u = 0; u < MT_NUMDR; u++) { /* loop thru units */ uptr = mt_dev.units + u; - uptr -> UNUM = u; /* init drive number */ sim_cancel (uptr); /* cancel activity */ - if (uptr -> flags & UNIT_ATT) uptr -> USTAT = - ((uptr -> pos)? 0: STA_BOT) | - ((uptr -> flags & UNIT_WPRT)? STA_WLK: 0); - else uptr -> USTAT = STA_REM; } + MT_CLR_PNU (uptr); /* clear pos flag */ + if (uptr->flags & UNIT_ATT) uptr->USTAT = + ((uptr->pos)? 0: STA_BOT) | + ((uptr->flags & UNIT_WPRT)? STA_WLK: 0); + else uptr->USTAT = STA_REM; } return SCPE_OK; } @@ -548,11 +579,13 @@ return SCPE_OK; t_stat mt_attach (UNIT *uptr, char *cptr) { t_stat r; +int32 u = uptr - mt_dev.units; /* get unit number */ r = attach_unit (uptr, cptr); if (r != SCPE_OK) return r; -uptr -> USTAT = STA_BOT | ((uptr -> flags & UNIT_WPRT)? STA_WLK: 0); -if (uptr -> UNUM == GET_UNIT (mt_cu)) mt_updcsta (uptr); +MT_CLR_PNU (uptr); +uptr->USTAT = STA_BOT | ((uptr->flags & UNIT_WPRT)? STA_WLK: 0); +if (u == GET_UNIT (mt_cu)) mt_updcsta (uptr); return r; } @@ -560,8 +593,11 @@ return r; t_stat mt_detach (UNIT* uptr) { -if (!sim_is_active (uptr)) uptr -> USTAT = STA_REM; -if (uptr -> UNUM == GET_UNIT (mt_cu)) mt_updcsta (uptr); +int32 u = uptr - mt_dev.units; /* get unit number */ + +MT_CLR_PNU (uptr); +if (!sim_is_active (uptr)) uptr->USTAT = STA_REM; +if (u == GET_UNIT (mt_cu)) mt_updcsta (uptr); return detach_unit (uptr); } @@ -569,8 +605,10 @@ return detach_unit (uptr); t_stat mt_vlock (UNIT *uptr, int32 val, char *cptr, void *desc) { -if ((uptr -> flags & UNIT_ATT) && val) uptr -> USTAT = uptr -> USTAT | STA_WLK; -else uptr -> USTAT = uptr -> USTAT & ~STA_WLK; -if (uptr -> UNUM == GET_UNIT (mt_cu)) mt_updcsta (uptr); +int32 u = uptr - mt_dev.units; /* get unit number */ + +if ((uptr->flags & UNIT_ATT) && val) uptr->USTAT = uptr->USTAT | STA_WLK; +else uptr->USTAT = uptr->USTAT & ~STA_WLK; +if (u == GET_UNIT (mt_cu)) mt_updcsta (uptr); return SCPE_OK; } diff --git a/PDP8/pdp8_pt.c b/PDP8/pdp8_pt.c index ea353b8f..018e6183 100644 --- a/PDP8/pdp8_pt.c +++ b/PDP8/pdp8_pt.c @@ -25,6 +25,7 @@ ptr,ptp PC8E paper tape reader/punch + 04-Oct-02 RMS Added DIBs 30-May-02 RMS Widened POS to 32b 30-Nov-01 RMS Added read only unit support 30-Mar-98 RMS Added RIM loader as PTR bootstrap @@ -33,12 +34,16 @@ #include "pdp8_defs.h" extern int32 int_req, int_enable, dev_done, stop_inst; + int32 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */ + +int32 ptr (int32 IR, int32 AC); +int32 ptp (int32 IR, int32 AC); t_stat ptr_svc (UNIT *uptr); t_stat ptp_svc (UNIT *uptr); t_stat ptr_reset (DEVICE *dptr); t_stat ptp_reset (DEVICE *dptr); -t_stat ptr_boot (int32 unitno); +t_stat ptr_boot (int32 unitno, DEVICE *dptr); /* PTR data structures @@ -47,6 +52,8 @@ t_stat ptr_boot (int32 unitno); ptr_reg PTR register list */ +DIB ptr_dib = { DEV_PTR, 1, { &ptr } }; + UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), SERIAL_IN_WAIT }; @@ -61,11 +68,16 @@ REG ptr_reg[] = { { FLDATA (STOP_IOE, ptr_stopioe, 0) }, { NULL } }; +MTAB ptr_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev }, + { 0 } }; + DEVICE ptr_dev = { - "PTR", &ptr_unit, ptr_reg, NULL, + "PTR", &ptr_unit, ptr_reg, ptr_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptr_reset, - &ptr_boot, NULL, NULL }; + &ptr_boot, NULL, NULL, + &ptr_dib, 0 }; /* PTP data structures @@ -74,6 +86,8 @@ DEVICE ptr_dev = { ptp_reg PTP register list */ +DIB ptp_dib = { DEV_PTP, 1, { &ptp } }; + UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; @@ -87,17 +101,22 @@ REG ptp_reg[] = { { FLDATA (STOP_IOE, ptp_stopioe, 0) }, { NULL } }; +MTAB ptp_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev }, + { 0 } }; + DEVICE ptp_dev = { - "PTP", &ptp_unit, ptp_reg, NULL, + "PTP", &ptp_unit, ptp_reg, ptp_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &ptp_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &ptp_dib, 0 }; /* Paper tape reader: IOT routine */ -int32 ptr (int32 pulse, int32 AC) +int32 ptr (int32 IR, int32 AC) { -switch (pulse) { /* decode IR<9:11> */ +switch (IR & 07) { /* decode IR<9:11> */ case 0: /* RPE */ int_enable = int_enable | (INT_PTR+INT_PTP); /* set enable */ int_req = INT_UPDATE; /* update interrupts */ @@ -155,9 +174,9 @@ return SCPE_OK; /* Paper tape punch: IOT routine */ -int32 ptp (int32 pulse, int32 AC) +int32 ptp (int32 IR, int32 AC) { -switch (pulse) { /* decode IR<9:11> */ +switch (IR & 07) { /* decode IR<9:11> */ case 0: /* PCE */ int_enable = int_enable & ~(INT_PTR+INT_PTP); /* clear enables */ int_req = INT_UPDATE; /* update interrupts */ @@ -210,9 +229,9 @@ return SCPE_OK; /* Bootstrap routine */ #define BOOT_START 07756 -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) +#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) -static const int32 boot_rom[] = { +static const uint16 boot_rom[] = { 06014, /* 7756, RFC */ 06011, /* 7757, LOOP, RSF */ 05357, /* JMP .-1 */ @@ -230,15 +249,16 @@ static const int32 boot_rom[] = { 03376, /* 7774, DCA 7776 */ 05357, /* JMP 7757 */ 00000, /* 7776, 0 */ - 05301 /* 7777, JMP 7701 */ + 05301 /* 7777, JMP 7701 */ }; -t_stat ptr_boot (int32 unitno) +t_stat ptr_boot (int32 unitno, DEVICE *dptr) { int32 i; extern int32 saved_PC; extern uint16 M[]; +if (ptr_dib.dev != DEV_PTR) return STOP_NOTSTD; /* only std devno */ for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i]; saved_PC = BOOT_START; return SCPE_OK; diff --git a/PDP8/pdp8_rf.c b/PDP8/pdp8_rf.c index e4cfa1b0..f14a3b07 100644 --- a/PDP8/pdp8_rf.c +++ b/PDP8/pdp8_rf.c @@ -25,7 +25,7 @@ rf RF08 fixed head disk - 06-Nov-02 RMS Changed enable/disable support + 04-Oct-02 RMS Added DIB, device number support 28-Nov-01 RMS Added RL8A support 25-Apr-01 RMS Added device enable/disable support 19-Mar-01 RMS Added disk monitor bootstrap, fixed IOT decoding @@ -89,9 +89,9 @@ else int_req = int_req & ~INT_RF extern uint16 M[]; -extern int32 int_req, dev_enb, stop_inst; +extern int32 int_req, stop_inst; extern UNIT cpu_unit; -extern int32 df_devenb; + int32 rf_sta = 0; /* status register */ int32 rf_da = 0; /* disk address */ int32 rf_done = 0; /* done flag */ @@ -99,10 +99,16 @@ int32 rf_wlk = 0; /* write lock */ int32 rf_time = 10; /* inter-word time */ int32 rf_burst = 1; /* burst mode flag */ int32 rf_stopioe = 1; /* stop on error */ + +DEVICE rf_dev; +int32 rf60 (int32 IR, int32 AC); +int32 rf61 (int32 IR, int32 AC); +int32 rf62 (int32 IR, int32 AC); +int32 rf64 (int32 IR, int32 AC); t_stat rf_svc (UNIT *uptr); t_stat pcell_svc (UNIT *uptr); t_stat rf_reset (DEVICE *dptr); -t_stat rf_boot (int32 unitno); +t_stat rf_boot (int32 unitno, DEVICE *dptr); /* RF08 data structures @@ -112,6 +118,8 @@ t_stat rf_boot (int32 unitno); rf_reg RF register list */ +DIB rf_dib = { DEV_RF, 5, { &rf60, &rf61, &rf62, NULL, &rf64 } }; + UNIT rf_unit = { UDATA (&rf_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, RF_SIZE) }; @@ -129,25 +137,27 @@ REG rf_reg[] = { { DRDATA (TIME, rf_time, 24), REG_NZ + PV_LEFT }, { FLDATA (BURST, rf_burst, 0) }, { FLDATA (STOP_IOE, rf_stopioe, 0) }, - { FLDATA (*DEVENB, dev_enb, INT_V_RF), REG_HRO }, + { ORDATA (DEVNUM, rf_dib.dev, 6), REG_HRO }, { NULL } }; MTAB rf_mod[] = { - { MTAB_XTD|MTAB_VDV, INT_RF, NULL, "ENABLED", &set_enb }, - { MTAB_XTD|MTAB_VDV, INT_RF, NULL, "DISABLED", &set_dsb }, + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", + &set_dev, &show_dev, NULL }, { 0 } }; DEVICE rf_dev = { "RF", &rf_unit, rf_reg, rf_mod, 1, 8, 20, 1, 8, 12, NULL, NULL, &rf_reset, - &rf_boot, NULL, NULL }; + &rf_boot, NULL, NULL, + &rf_dib, DEV_DISABLE | DEV_DIS }; /* IOT routines */ -int32 rf60 (int32 pulse, int32 AC) +int32 rf60 (int32 IR, int32 AC) { int32 t; +int32 pulse = IR & 07; UPDATE_PCELL; /* update photocell */ if (pulse & 1) { /* DCMA */ @@ -165,8 +175,10 @@ if (pulse & 6) { /* DMAR, DMAW */ return AC; } -int32 rf61 (int32 pulse, int32 AC) +int32 rf61 (int32 IR, int32 AC) { +int32 pulse = IR & 07; + UPDATE_PCELL; /* update photocell */ switch (pulse) { /* decode IR<9:11> */ case 1: /* DCIM */ @@ -191,8 +203,10 @@ return AC; /* IOT's, continued */ -int32 rf62 (int32 pulse, int32 AC) +int32 rf62 (int32 IR, int32 AC) { +int32 pulse = IR & 07; + UPDATE_PCELL; /* update photocell */ if (pulse & 1) { /* DFSE */ if (rf_sta & RFS_ERR) AC = AC | IOT_SKP; } @@ -203,8 +217,10 @@ if (pulse & 4) AC = AC | (rf_da & 07777); /* DMAC */ return AC; } -int32 rf64 (int32 pulse, int32 AC) +int32 rf64 (int32 IR, int32 AC) { +int32 pulse = IR & 07; + UPDATE_PCELL; /* update photocell */ switch (pulse) { /* decode IR<9:11> */ case 1: /* DCXA */ @@ -230,7 +246,7 @@ t_stat rf_svc (UNIT *uptr) int32 pa, t, mex; UPDATE_PCELL; /* update photocell */ -if ((uptr -> flags & UNIT_BUF) == 0) { /* not buf? abort */ +if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */ rf_sta = rf_sta | RFS_NXD; rf_done = 1; RF_INT_UPDATE; /* update int req */ @@ -240,14 +256,14 @@ mex = GET_MEX (rf_sta); do { M[RF_WC] = (M[RF_WC] + 1) & 07777; /* incr word count */ M[RF_MA] = (M[RF_MA] + 1) & 07777; /* incr mem addr */ pa = mex | M[RF_MA]; /* add extension */ - if (uptr -> FUNC == RF_READ) { + if (uptr->FUNC == RF_READ) { if (MEM_ADDR_OK (pa)) /* read, check nxm */ - M[pa] = *(((int16 *) uptr -> filebuf) + rf_da); } + M[pa] = *(((int16 *) uptr->filebuf) + rf_da); } else { t = ((rf_da >> 15) & 030) | ((rf_da >> 14) & 07); if ((rf_wlk >> t) & 1) rf_sta = rf_sta | RFS_WLS; - else { *(((int16 *) uptr -> filebuf) + rf_da) = M[pa]; - if (((t_addr) rf_da) >= uptr -> hwmark) - uptr -> hwmark = rf_da + 1; } } + else { *(((int16 *) uptr->filebuf) + rf_da) = M[pa]; + if (((t_addr) rf_da) >= uptr->hwmark) + uptr->hwmark = rf_da + 1; } } rf_da = (rf_da + 1) & 03777777; } /* incr disk addr */ while ((M[RF_WC] != 0) && (rf_burst != 0)); /* brk if wc, no brst */ @@ -273,8 +289,6 @@ return SCPE_OK; t_stat rf_reset (DEVICE *dptr) { -if (dev_enb & INT_RF) /* RF? no DF or RL */ - dev_enb = dev_enb & ~(INT_DF | INT_RL); rf_sta = rf_da = 0; rf_done = 1; int_req = int_req & ~INT_RF; /* clear interrupt */ @@ -286,11 +300,11 @@ return SCPE_OK; /* Bootstrap routine */ #define OS8_START 07750 -#define OS8_LEN (sizeof (os8_rom) / sizeof (int32)) +#define OS8_LEN (sizeof (os8_rom) / sizeof (int16)) #define DM4_START 00200 -#define DM4_LEN (sizeof (dm4_rom) / sizeof (int32)) +#define DM4_LEN (sizeof (dm4_rom) / sizeof (int16)) -static const int32 os8_rom[] = { +static const uint16 os8_rom[] = { 07600, /* 7750, CLA CLL ; also word count */ 06603, /* 7751, DMAR ; also address */ 06622, /* 7752, DFSC ; done? */ @@ -298,7 +312,7 @@ static const int32 os8_rom[] = { 05752 /* 7754, JMP @.-2 ; enter boot */ }; -static const int32 dm4_rom[] = { +static const uint16 dm4_rom[] = { 00200, 07600, /* 0200, CLA CLL */ 00201, 06603, /* 0201, DMAR ; read */ 00202, 06622, /* 0202, DFSC ; done? */ @@ -308,11 +322,12 @@ static const int32 dm4_rom[] = { 07751, 07576 /* 7751, 7576 ; address */ }; -t_stat rf_boot (int32 unitno) +t_stat rf_boot (int32 unitno, DEVICE *dptr) { int32 i; extern int32 sim_switches, saved_PC; +if (rf_dib.dev != DEV_RF) return STOP_NOTSTD; /* only std devno */ if (sim_switches & SWMASK ('D')) { for (i = 0; i < DM4_LEN; i = i + 2) M[dm4_rom[i]] = dm4_rom[i + 1]; diff --git a/PDP8/pdp8_rk.c b/PDP8/pdp8_rk.c index 50c8d8ad..3ca8816f 100644 --- a/PDP8/pdp8_rk.c +++ b/PDP8/pdp8_rk.c @@ -25,6 +25,7 @@ rk RK8E/RK05 cartridge disk + 04-Oct-02 RMS Added DIB, device number support 06-Jan-02 RMS Changed enable/disable support 30-Nov-01 RMS Added read only unit, extended SET/SHOW support 24-Nov-01 RMS Converted FLG to array, made register names consistent @@ -48,7 +49,6 @@ #define UNIT_V_HWLK (UNIT_V_UF + 0) /* hwre write lock */ #define UNIT_V_SWLK (UNIT_V_UF + 1) /* swre write lock */ -#define UNIT_W_UF 3 /* user flags width */ #define UNIT_HWLK (1 << UNIT_V_HWLK) #define UNIT_SWLK (1 << UNIT_V_SWLK) #define UNIT_WPRT (UNIT_HWLK|UNIT_SWLK|UNIT_RO) /* write protect */ @@ -123,8 +123,9 @@ #define MAX(x,y) (((x) > (y))? (x): (y)) extern uint16 M[]; -extern int32 int_req, dev_enb, stop_inst; +extern int32 int_req, stop_inst; extern UNIT cpu_unit; + int32 rk_busy = 0; /* controller busy */ int32 rk_sta = 0; /* status register */ int32 rk_cmd = 0; /* command register */ @@ -132,9 +133,12 @@ int32 rk_da = 0; /* disk address */ int32 rk_ma = 0; /* memory address */ int32 rk_swait = 10, rk_rwait = 10; /* seek, rotate wait */ int32 rk_stopioe = 1; /* stop on error */ + +DEVICE rk_dev; +int32 rk (int32 IR, int32 AC); t_stat rk_svc (UNIT *uptr); t_stat rk_reset (DEVICE *dptr); -t_stat rk_boot (int32 unitno); +t_stat rk_boot (int32 unitno, DEVICE *dptr); void rk_go (int32 function, int32 cylinder); /* RK-8E data structures @@ -145,6 +149,8 @@ void rk_go (int32 function, int32 cylinder); rk_mod RK modifiers list */ +DIB rk_dib = { DEV_RK, 1, { &rk } }; + UNIT rk_unit[] = { { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ UNIT_ROABLE, RK_SIZE) }, @@ -164,33 +170,32 @@ REG rk_reg[] = { { FLDATA (INT, int_req, INT_V_RK) }, { DRDATA (STIME, rk_swait, 24), PV_LEFT }, { DRDATA (RTIME, rk_rwait, 24), PV_LEFT }, - { URDATA (FLG, rk_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, - RK_NUMDR, REG_HRO) }, { FLDATA (STOP_IOE, rk_stopioe, 0) }, - { FLDATA (*DEVENB, dev_enb, INT_V_RK), REG_HRO }, + { ORDATA (DEVNUM, rk_dib.dev, 6), REG_HRO }, { NULL } }; MTAB rk_mod[] = { { UNIT_HWLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL }, - { MTAB_XTD|MTAB_VDV, INT_RK, NULL, "ENABLED", &set_enb }, - { MTAB_XTD|MTAB_VDV, INT_RK, NULL, "DISABLED", &set_dsb }, + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", + &set_dev, &show_dev, NULL }, { 0 } }; DEVICE rk_dev = { "RK", rk_unit, rk_reg, rk_mod, RK_NUMDR, 8, 24, 1, 8, 12, NULL, NULL, &rk_reset, - &rk_boot, NULL, NULL }; + &rk_boot, NULL, NULL, + &rk_dib, DEV_DISABLE }; /* IOT routine */ -int32 rk (int32 pulse, int32 AC) +int32 rk (int32 IR, int32 AC) { int32 i; UNIT *uptr; -switch (pulse) { /* decode IR<9:11> */ +switch (IR & 07) { /* decode IR<9:11> */ case 0: /* unused */ return (stop_inst << IOT_V_REASON) + AC; case 1: /* DSKP */ @@ -225,7 +230,7 @@ case 4: /* DLCA */ case 5: /* DRST */ uptr = rk_dev.units + GET_DRIVE (rk_cmd); /* selected unit */ rk_sta = rk_sta & ~(RKS_HMOV + RKS_NRDY); /* clear dynamic */ - if ((uptr -> flags & UNIT_ATT) == 0) rk_sta = rk_sta | RKS_NRDY; + if ((uptr->flags & UNIT_ATT) == 0) rk_sta = rk_sta | RKS_NRDY; if (sim_is_active (uptr)) rk_sta = rk_sta | RKS_HMOV; return rk_sta; case 6: /* DLDC */ @@ -256,27 +261,27 @@ UNIT *uptr; if (func == RKC_RALL) func = RKC_READ; /* all? use standard */ if (func == RKC_WALL) func = RKC_WRITE; uptr = rk_dev.units + GET_DRIVE (rk_cmd); /* selected unit */ -if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */ +if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ rk_sta = rk_sta | RKS_DONE | RKS_NRDY | RKS_STAT; return; } if (sim_is_active (uptr) || (cyl >= RK_NUMCY)) { /* busy or bad cyl? */ rk_sta = rk_sta | RKS_DONE | RKS_STAT; return; } -if ((func == RKC_WRITE) && (uptr -> flags & UNIT_WPRT)) { +if ((func == RKC_WRITE) && (uptr->flags & UNIT_WPRT)) { rk_sta = rk_sta | RKS_DONE | RKS_WLK; /* write and locked? */ return; } if (func == RKC_WLK) { /* write lock? */ - uptr -> flags = uptr -> flags | UNIT_SWLK; + uptr->flags = uptr->flags | UNIT_SWLK; rk_sta = rk_sta | RKS_DONE; return; } -t = abs (cyl - uptr -> CYL) * rk_swait; /* seek time */ +t = abs (cyl - uptr->CYL) * rk_swait; /* seek time */ if (func == RKC_SEEK) { /* seek? */ sim_activate (uptr, MAX (RK_MIN, t)); /* schedule */ rk_sta = rk_sta | RKS_DONE; } /* set done */ else { sim_activate (uptr, t + rk_rwait); /* schedule */ rk_busy = 1; } /* set busy */ -uptr -> FUNC = func; /* save func */ -uptr -> CYL = cyl; /* put on cylinder */ +uptr->FUNC = func; /* save func */ +uptr->CYL = cyl; /* put on cylinder */ return; } @@ -297,20 +302,20 @@ t_stat rk_svc (UNIT *uptr) int32 err, wc, wc1, awc, swc, pa, da; UNIT *seluptr; -if (uptr -> FUNC == RKC_SEEK) { /* seek? */ +if (uptr->FUNC == RKC_SEEK) { /* seek? */ seluptr = rk_dev.units + GET_DRIVE (rk_cmd); /* see if selected */ if ((uptr == seluptr) && ((rk_cmd & RKC_SKDN) != 0)) { rk_sta = rk_sta | RKS_DONE; RK_INT_UPDATE; } return SCPE_OK; } -if ((uptr -> flags & UNIT_ATT) == 0) { /* not att? abort */ +if ((uptr->flags & UNIT_ATT) == 0) { /* not att? abort */ rk_sta = rk_sta | RKS_DONE | RKS_NRDY | RKS_STAT; rk_busy = 0; RK_INT_UPDATE; return IORETURN (rk_stopioe, SCPE_UNATT); } -if ((uptr -> FUNC == RKC_WRITE) && (uptr -> flags & UNIT_WPRT)) { +if ((uptr->FUNC == RKC_WRITE) && (uptr->flags & UNIT_WPRT)) { rk_sta = rk_sta | RKS_DONE | RKS_WLK; /* write and locked? */ rk_busy = 0; RK_INT_UPDATE; @@ -320,28 +325,28 @@ pa = GET_MEX (rk_cmd) | rk_ma; /* phys address */ da = GET_DA (rk_cmd, rk_da) * RK_NUMWD * sizeof (int16);/* disk address */ swc = wc = (rk_cmd & RKC_HALF)? RK_NUMWD / 2: RK_NUMWD; /* get transfer size */ if ((wc1 = ((rk_ma + wc) - 010000)) > 0) wc = wc - wc1; /* if wrap, limit */ -err = fseek (uptr -> fileref, da, SEEK_SET); /* locate sector */ +err = fseek (uptr->fileref, da, SEEK_SET); /* locate sector */ -if ((uptr -> FUNC == RKC_READ) && (err == 0) && MEM_ADDR_OK (pa)) { /* read? */ - awc = fxread (&M[pa], sizeof (int16), wc, uptr -> fileref); +if ((uptr->FUNC == RKC_READ) && (err == 0) && MEM_ADDR_OK (pa)) { /* read? */ + awc = fxread (&M[pa], sizeof (int16), wc, uptr->fileref); for ( ; awc < wc; awc++) M[pa + awc] = 0; /* fill if eof */ - err = ferror (uptr -> fileref); + err = ferror (uptr->fileref); if ((wc1 > 0) && (err == 0)) { /* field wraparound? */ pa = pa & 070000; /* wrap phys addr */ - awc = fxread (&M[pa], sizeof (int16), wc1, uptr -> fileref); + awc = fxread (&M[pa], sizeof (int16), wc1, uptr->fileref); for ( ; awc < wc1; awc++) M[pa + awc] = 0; /* fill if eof */ - err = ferror (uptr -> fileref); } } + err = ferror (uptr->fileref); } } -if ((uptr -> FUNC == RKC_WRITE) && (err == 0)) { /* write? */ - fxwrite (&M[pa], sizeof (int16), wc, uptr -> fileref); - err = ferror (uptr -> fileref); +if ((uptr->FUNC == RKC_WRITE) && (err == 0)) { /* write? */ + fxwrite (&M[pa], sizeof (int16), wc, uptr->fileref); + err = ferror (uptr->fileref); if ((wc1 > 0) && (err == 0)) { /* field wraparound? */ pa = pa & 070000; /* wrap phys addr */ - fxwrite (&M[pa], sizeof (int16), wc1, uptr -> fileref); - err = ferror (uptr -> fileref); } + fxwrite (&M[pa], sizeof (int16), wc1, uptr->fileref); + err = ferror (uptr->fileref); } if ((rk_cmd & RKC_HALF) && (err == 0)) { /* fill half sector */ - fxwrite (fill, sizeof (int16), RK_NUMWD/2, uptr -> fileref); - err = ferror (uptr -> fileref); } } + fxwrite (fill, sizeof (int16), RK_NUMWD/2, uptr->fileref); + err = ferror (uptr->fileref); } } rk_ma = (rk_ma + swc) & 07777; /* incr mem addr reg */ rk_sta = rk_sta | RKS_DONE; /* set done */ @@ -350,7 +355,7 @@ RK_INT_UPDATE; if (err != 0) { perror ("RK I/O error"); - clearerr (uptr -> fileref); + clearerr (uptr->fileref); return SCPE_IOERR; } return SCPE_OK; } @@ -367,8 +372,8 @@ int_req = int_req & ~INT_RK; /* clear interrupt */ for (i = 0; i < RK_NUMDR; i++) { /* stop all units */ uptr = rk_dev.units + i; sim_cancel (uptr); - uptr -> flags = uptr -> flags & ~UNIT_SWLK; - uptr -> CYL = uptr -> FUNC = 0; } + uptr->flags = uptr->flags & ~UNIT_SWLK; + uptr->CYL = uptr->FUNC = 0; } return SCPE_OK; } @@ -376,9 +381,9 @@ return SCPE_OK; #define BOOT_START 023 #define BOOT_UNIT 032 -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int)) +#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) -static const int32 boot_rom[] = { +static const uint16 boot_rom[] = { 06007, /* 23, CAF */ 06744, /* 24, DLCA ; addr = 0 */ 01032, /* 25, TAD UNIT ; unit no */ @@ -389,11 +394,12 @@ static const int32 boot_rom[] = { 00000 /* UNIT, 0 ; in bits <9:10> */ }; -t_stat rk_boot (int32 unitno) +t_stat rk_boot (int32 unitno, DEVICE *dptr) { int32 i; extern int32 saved_PC; +if (rk_dib.dev != DEV_RK) return STOP_NOTSTD; /* only std devno */ for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i]; M[BOOT_UNIT] = (unitno & RK_M_NUMDR) << 1; saved_PC = BOOT_START; diff --git a/PDP8/pdp8_rl.c b/PDP8/pdp8_rl.c index e0d7f56a..f0aa16fd 100644 --- a/PDP8/pdp8_rl.c +++ b/PDP8/pdp8_rl.c @@ -25,6 +25,7 @@ rl RL8A cartridge disk + 04-Oct-02 RMS Added DIB, device number support 06-Jan-02 RMS Changed enable/disable support 30-Nov-01 RMS Cloned from RL11 @@ -58,11 +59,10 @@ /* Flags in the unit flags word */ -#define UNIT_V_WLK (UNIT_V_UF) /* write lock */ -#define UNIT_V_RL02 (UNIT_V_UF+1) /* RL01 vs RL02 */ -#define UNIT_V_AUTO (UNIT_V_UF+2) /* autosize enable */ -#define UNIT_W_UF 4 /* saved flags width */ -#define UNIT_V_DUMMY (UNIT_V_UF + UNIT_W_UF) /* dummy flag */ +#define UNIT_V_WLK (UNIT_V_UF + 0) /* write lock */ +#define UNIT_V_RL02 (UNIT_V_UF + 1) /* RL01 vs RL02 */ +#define UNIT_V_AUTO (UNIT_V_UF + 2) /* autosize enable */ +#define UNIT_V_DUMMY (UNIT_V_UF + 3) /* dummy flag */ #define UNIT_DUMMY (1u << UNIT_V_DUMMY) #define UNIT_WLK (1u << UNIT_V_WLK) #define UNIT_RL02 (1u << UNIT_V_RL02) @@ -96,7 +96,7 @@ #define RLDS_ERR (RLDS_WDE+RLDS_HCE+RLDS_STO+RLDS_SPE+RLDS_WGE+ \ RLDS_VCK+RLDS_DSE) /* errors bits */ -/* RLCSA, seek = offset/rw = address (also uptr -> TRK) */ +/* RLCSA, seek = offset/rw = address (also uptr->TRK) */ #define RLCSA_DIR 04000 /* direction */ #define RLCSA_HD 02000 /* head select */ @@ -151,8 +151,9 @@ #define RLSI_V_TRK 6 /* track */ extern uint16 M[]; -extern int32 int_req, dev_enb; +extern int32 int_req; extern UNIT cpu_unit; + uint8 *rlxb = NULL; /* xfer buffer */ int32 rlcsa = 0; /* control/status A */ int32 rlcsb = 0; /* control/status B */ @@ -167,10 +168,14 @@ int32 rl_erf = 0; /* error flag */ int32 rl_swait = 10; /* seek wait */ int32 rl_rwait = 10; /* rotate wait */ int32 rl_stopioe = 1; /* stop on error */ + +DEVICE rl_dev; +int32 rl60 (int32 IR, int32 AC); +int32 rl61 (int32 IR, int32 AC); t_stat rl_svc (UNIT *uptr); t_stat rl_reset (DEVICE *dptr); void rl_set_done (int32 error); -t_stat rl_boot (int32 unitno); +t_stat rl_boot (int32 unitno, DEVICE *dptr); t_stat rl_attach (UNIT *uptr, char *cptr); t_stat rl_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc); @@ -183,6 +188,8 @@ t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc); rl_mod RL modifier list */ +DIB rl_dib = { DEV_RL, 2, { &rl60, &rl61 } }; + UNIT rl_unit[] = { { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ UNIT_ROABLE, RL01_SIZE) }, @@ -210,12 +217,10 @@ REG rl_reg[] = { { FLDATA (ERR, rl_erf, 0) }, { DRDATA (STIME, rl_swait, 24), PV_LEFT }, { DRDATA (RTIME, rl_rwait, 24), PV_LEFT }, - { URDATA (FLG, rl_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, - RL_NUMDR, REG_HRO) }, { URDATA (CAPAC, rl_unit[0].capac, 10, 31, 0, RL_NUMDR, PV_LEFT + REG_HRO) }, { FLDATA (STOP_IOE, rl_stopioe, 0) }, - { FLDATA (*DEVENB, dev_enb, INT_V_RL), REG_HRO }, + { ORDATA (DEVNUM, rl_dib.dev, 6), REG_HRO }, { NULL } }; MTAB rl_mod[] = { @@ -230,24 +235,25 @@ MTAB rl_mod[] = { { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL }, { (UNIT_AUTO+UNIT_RL02), 0, NULL, "RL01", &rl_set_size }, { (UNIT_AUTO+UNIT_RL02), UNIT_RL02, NULL, "RL02", &rl_set_size }, - { MTAB_XTD|MTAB_VDV, INT_RL, NULL, "ENABLED", &set_enb }, - { MTAB_XTD|MTAB_VDV, INT_RL, NULL, "DISABLED", &set_dsb }, + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", + &set_dev, &show_dev, NULL }, { 0 } }; DEVICE rl_dev = { "RL", rl_unit, rl_reg, rl_mod, RL_NUMDR, 8, 24, 1, 8, 8, NULL, NULL, &rl_reset, - &rl_boot, &rl_attach, NULL }; + &rl_boot, &rl_attach, NULL, + &rl_dib, DEV_DISABLE | DEV_DIS }; /* IOT 60 routine */ -int32 rl60 (int32 pulse, int32 AC) +int32 rl60 (int32 IR, int32 AC) { int32 curr, offs, newc, maxc; UNIT *uptr; -switch (pulse) { /* case IR<9:11> */ +switch (IR & 07) { /* case IR<9:11> */ case 0: /* RLDC */ rl_reset (&rl_dev); /* reset device */ break; @@ -272,21 +278,21 @@ case 4: /* RLCB */ uptr = rl_dev.units + GET_DRIVE (rlcsb); /* select unit */ switch (GET_FUNC (rlcsb)) { /* case on func */ case RLCSB_CLRD: /* clear drive */ - uptr -> STAT = uptr -> STAT & ~RLDS_ERR; /* clear errors */ + uptr->STAT = uptr->STAT & ~RLDS_ERR; /* clear errors */ case RLCSB_MNT: /* mnt */ rl_set_done (0); break; case RLCSB_SEEK: /* seek */ - curr = GET_CYL (uptr -> TRK); /* current cylinder */ + curr = GET_CYL (uptr->TRK); /* current cylinder */ offs = GET_CYL (rlcsa); /* offset */ if (rlcsa & RLCSA_DIR) { /* in or out? */ newc = curr + offs; /* out */ - maxc = (uptr -> flags & UNIT_RL02)? + maxc = (uptr->flags & UNIT_RL02)? RL_NUMCY * 2: RL_NUMCY; if (newc >= maxc) newc = maxc - 1; } else { newc = curr - offs; /* in */ if (newc < 0) newc = 0; } - uptr -> TRK = newc | (rlcsa & RLCSA_HD); + uptr->TRK = newc | (rlcsa & RLCSA_HD); sim_activate (uptr, rl_swait * abs (newc - curr)); break; default: /* data transfer */ @@ -315,7 +321,7 @@ switch (pulse) { /* case IR<9:11> */ case 0: /* RRER */ uptr = rl_dev.units + GET_DRIVE (rlcsb); /* select unit */ if (!sim_is_active (uptr) && /* update drdy */ - (uptr -> flags & UNIT_ATT)) + (uptr->flags & UNIT_ATT)) rler = rler | RLER_DRDY; else rler = rler & ~RLER_DRDY; dat = rler & RLER_MASK; @@ -367,22 +373,22 @@ t_addr ma; func = GET_FUNC (rlcsb); /* get function */ if (func == RLCSB_GSTA) { /* get status? */ - rlsi = uptr -> STAT | - ((uptr -> TRK & RLCSA_HD)? RLDS_HD: 0) | - ((uptr -> flags & UNIT_ATT)? RLDS_ATT: RLDS_UNATT); - if (uptr -> flags & UNIT_RL02) rlsi = rlsi | RLDS_RL02; - if (uptr -> flags & UNIT_WPRT) rlsi = rlsi | RLDS_WLK; + rlsi = uptr->STAT | + ((uptr->TRK & RLCSA_HD)? RLDS_HD: 0) | + ((uptr->flags & UNIT_ATT)? RLDS_ATT: RLDS_UNATT); + if (uptr->flags & UNIT_RL02) rlsi = rlsi | RLDS_RL02; + if (uptr->flags & UNIT_WPRT) rlsi = rlsi | RLDS_WLK; rlsi2 = rlsi1 = rlsi; rl_set_done (0); /* done */ return SCPE_OK; } -if ((uptr -> flags & UNIT_ATT) == 0) { /* attached? */ - uptr -> STAT = uptr -> STAT | RLDS_SPE; /* spin error */ +if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */ + uptr->STAT = uptr->STAT | RLDS_SPE; /* spin error */ rl_set_done (RLER_INCMP); /* flag error */ return IORETURN (rl_stopioe, SCPE_UNATT); } -if ((func == RLCSB_WRITE) && (uptr -> flags & UNIT_WPRT)) { - uptr -> STAT = uptr -> STAT | RLDS_WGE; /* write and locked */ +if ((func == RLCSB_WRITE) && (uptr->flags & UNIT_WPRT)) { + uptr->STAT = uptr->STAT | RLDS_WGE; /* write and locked */ rl_set_done (RLER_DRE); /* flag error */ return SCPE_OK; } @@ -391,12 +397,12 @@ if (func == RLCSB_SEEK) { /* seek? */ return SCPE_OK; } if (func == RLCSB_RHDR) { /* read header? */ - rlsi = (GET_TRK (uptr -> TRK) << RLSI_V_TRK) | rlsa; + rlsi = (GET_TRK (uptr->TRK) << RLSI_V_TRK) | rlsa; rlsi1 = rlsi2 = 0; rl_set_done (0); /* done */ return SCPE_OK; } -if (((func != RLCSB_RNOHDR) && (GET_CYL (uptr -> TRK) != GET_CYL (rlcsa))) +if (((func != RLCSB_RNOHDR) && (GET_CYL (uptr->TRK) != GET_CYL (rlcsa))) || (rlsa >= RL_NUMSC)) { /* bad cyl or sector? */ rl_set_done (RLER_HDE | RLER_INCMP); /* flag error */ return SCPE_OK; } @@ -413,12 +419,12 @@ else { bc = ((wc * 3) + 1) / 2; /* 12b mode */ bc = RL_NUMBY; /* cap xfer */ wc = (RL_NUMBY * 2) / 3; } } -err = fseek (uptr -> fileref, da, SEEK_SET); +err = fseek (uptr->fileref, da, SEEK_SET); if ((func >= RLCSB_READ) && (err == 0) && /* read (no hdr)? */ MEM_ADDR_OK (ma)) { /* valid bank? */ - i = fxread (rlxb, sizeof (int8), bc, uptr -> fileref); - err = ferror (uptr -> fileref); + i = fxread (rlxb, sizeof (int8), bc, uptr->fileref); + err = ferror (uptr->fileref); for ( ; i < bc; i++) rlxb[i] = 0; /* fill buffer */ for (i = j = 0; i < wc; i++) { /* store buffer */ if (rlcsb & RLCSB_8B) /* 8b mode? */ @@ -448,8 +454,8 @@ if ((func == RLCSB_WRITE) && (err == 0)) { /* write? */ } /* end for */ wbc = (bc + (RL_NUMBY - 1)) & ~(RL_NUMBY - 1); /* clr to */ for (i = bc; i < wbc; i++) rlxb[i] = 0; /* end of blk */ - fxwrite (rlxb, sizeof (int8), wbc, uptr -> fileref); - err = ferror (uptr -> fileref); + fxwrite (rlxb, sizeof (int8), wbc, uptr->fileref); + err = ferror (uptr->fileref); } /* end write */ rlwc = (rlwc + wc) & 07777; /* final word count */ @@ -460,7 +466,7 @@ rl_set_done (0); if (err != 0) { /* error? */ perror ("RL I/O error"); - clearerr (uptr -> fileref); + clearerr (uptr->fileref); return SCPE_IOERR; } return SCPE_OK; } @@ -487,8 +493,6 @@ t_stat rl_reset (DEVICE *dptr) int32 i; UNIT *uptr; -if (dev_enb & INT_RL) /* RL? no DF or RF */ - dev_enb = dev_enb & ~(INT_DF | INT_RF); rlcsa = rlcsb = rlsa = rler = 0; rlma = rlwc = 0; rlsi = rlsi1 = rlsi2 = 0; @@ -499,7 +503,7 @@ int_req = int_req & ~INT_RL; for (i = 0; i < RL_NUMDR; i++) { uptr = rl_dev.units + i; sim_cancel (uptr); - uptr -> STAT = 0; } + uptr->STAT = 0; } if (rlxb == NULL) rlxb = calloc (RL_MAXFR, sizeof (unsigned int8)); if (rlxb == NULL) return SCPE_MEM; return SCPE_OK; @@ -512,21 +516,21 @@ t_stat rl_attach (UNIT *uptr, char *cptr) int32 p; t_stat r; -uptr -> capac = (uptr -> flags & UNIT_RL02)? RL02_SIZE: RL01_SIZE; +uptr->capac = (uptr->flags & UNIT_RL02)? RL02_SIZE: RL01_SIZE; r = attach_unit (uptr, cptr); -if ((r != SCPE_OK) || ((uptr -> flags & UNIT_AUTO) == 0)) return r; -uptr -> TRK = 0; /* cyl 0 */ -uptr -> STAT = RLDS_VCK; /* new volume */ -if (fseek (uptr -> fileref, 0, SEEK_END)) return SCPE_OK; -if ((p = ftell (uptr -> fileref)) == 0) { - if (uptr -> flags & UNIT_RO) return SCPE_OK; +if ((r != SCPE_OK) || ((uptr->flags & UNIT_AUTO) == 0)) return r; +uptr->TRK = 0; /* cyl 0 */ +uptr->STAT = RLDS_VCK; /* new volume */ +if (fseek (uptr->fileref, 0, SEEK_END)) return SCPE_OK; +if ((p = ftell (uptr->fileref)) == 0) { + if (uptr->flags & UNIT_RO) return SCPE_OK; return rl_set_bad (uptr, 0, NULL, NULL); } if (p > (RL01_SIZE * sizeof (int16))) { - uptr -> flags = uptr -> flags | UNIT_RL02; - uptr -> capac = RL02_SIZE; } -else { uptr -> flags = uptr -> flags & ~UNIT_RL02; - uptr -> capac = RL01_SIZE; } + uptr->flags = uptr->flags | UNIT_RL02; + uptr->capac = RL02_SIZE; } +else { uptr->flags = uptr->flags & ~UNIT_RL02; + uptr->capac = RL01_SIZE; } return SCPE_OK; } @@ -534,8 +538,8 @@ return SCPE_OK; t_stat rl_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { -if (uptr -> flags & UNIT_ATT) return SCPE_ALATT; -uptr -> capac = (val & UNIT_RL02)? RL02_SIZE: RL01_SIZE; +if (uptr->flags & UNIT_ATT) return SCPE_ALATT; +uptr->capac = (val & UNIT_RL02)? RL02_SIZE: RL01_SIZE; return SCPE_OK; } @@ -559,14 +563,14 @@ t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc) { int32 i, da = RL_BBMAP * RL_NUMBY; -if ((uptr -> flags & UNIT_ATT) == 0) return SCPE_UNATT; -if (uptr -> flags & UNIT_RO) return SCPE_RO; +if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; +if (uptr->flags & UNIT_RO) return SCPE_RO; if (!get_yn ("Create bad block table? [N]", FALSE)) return SCPE_OK; -if (fseek (uptr -> fileref, da, SEEK_SET)) return SCPE_IOERR; +if (fseek (uptr->fileref, da, SEEK_SET)) return SCPE_IOERR; rlxb[0] = RL_BBID; for (i = 1; i < RL_NUMBY; i++) rlxb[i] = 0; -fxwrite (rlxb, sizeof (int8), RL_NUMBY, uptr -> fileref); -if (ferror (uptr -> fileref)) return SCPE_IOERR; +fxwrite (rlxb, sizeof (int8), RL_NUMBY, uptr->fileref); +if (ferror (uptr->fileref)) return SCPE_IOERR; return SCPE_OK; } @@ -576,7 +580,7 @@ return SCPE_OK; #define BOOT_UNIT 02006 /* unit number */ #define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) -static const int16 boot_rom[] = { +static const uint16 boot_rom[] = { 06600, /* BT, RLDC ; reset */ 07201, /* 02, CLA IAC ; clr drv = 1 */ 04027, /* 03, JMS GO ; do io */ @@ -609,12 +613,13 @@ static const int16 boot_rom[] = { }; -t_stat rl_boot (int32 unitno) +t_stat rl_boot (int32 unitno, DEVICE *dptr) { int32 i; extern int32 saved_PC; if (unitno) return SCPE_ARG; +if (rl_dib.dev != DEV_RL) return STOP_NOTSTD; /* only std devno */ rl_unit[unitno].TRK = 0; for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i]; saved_PC = BOOT_START; diff --git a/PDP8/pdp8_rx.c b/PDP8/pdp8_rx.c index fde74076..239815ff 100644 --- a/PDP8/pdp8_rx.c +++ b/PDP8/pdp8_rx.c @@ -1,4 +1,4 @@ -/* pdp8_rx.c: RX8E/RX01 floppy disk simulator +/* pdp8_rx.c: RX8E/RX01, RX28/RX02 floppy disk simulator Copyright (c) 1993-2002, Robert M Supnik @@ -23,8 +23,11 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - rx RX8E/RX01 floppy disk + rx RX8E/RX01, RX28/RX02 floppy disk + 08-Oct-02 RMS Added DIB, device number support + Fixed reset to work with disabled device + 15-Sep-02 RMS Added RX28/RX02 support 06-Jan-02 RMS Changed enable/disable support 30-Nov-01 RMS Added read only unit, extended SET/SHOW support 24-Nov-01 RMS Converted FLG to array @@ -35,11 +38,13 @@ 15-Aug-96 RMS Fixed bug in LCD An RX01 diskette consists of 77 tracks, each with 26 sectors of 128B. - Tracks are numbered 0-76, sectors 1-26. The RX8E can store data in - 8b mode or 12b mode. In 8b mode, the controller reads or writes - 128 bytes per sector. In 12b mode, the reads or writes 64 12b words - per sector. The 12b words are bit packed into the first 96 bytes - of the sector; the last 32 bytes are zeroed on writes. + An RX02 diskette consists of 77 tracks, each with 26 sectors of 128B + (single density) or 256B (double density). Tracks are numbered 0-76, + sectors 1-26. The RX8E (RX28) can store data in 8b mode or 12b mode. + In 8b mode, the controller reads or writes 128 bytes (128B or 256B) + per sector. In 12b mode, it reads or writes 64 (64 or 128) 12b words + per sector. The 12b words are bit packed into the first 96 (192) bytes + of the sector; the last 32 (64) bytes are zeroed on writes. */ #include "pdp8_defs.h" @@ -49,21 +54,32 @@ #define RX_NUMSC 26 /* sectors/track */ #define RX_M_SECTOR 0177 /* cf Jones!! */ #define RX_NUMBY 128 /* bytes/sector */ +#define RX2_NUMBY 256 #define RX_NUMWD (RX_NUMBY / 2) /* words/sector */ +#define RX2_NUMWD (RX2_NUMBY / 2) #define RX_SIZE (RX_NUMTR * RX_NUMSC * RX_NUMBY) /* bytes/disk */ +#define RX2_SIZE (RX_NUMTR * RX_NUMSC * RX2_NUMBY) #define RX_NUMDR 2 /* drives/controller */ #define RX_M_NUMDR 01 -#define UNIT_V_WLK (UNIT_V_UF) /* write locked */ -#define UNIT_WLK (1 << UNIT_V_UF) +#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ +#define UNIT_V_DEN (UNIT_V_UF + 1) /* double density */ +#define UNIT_V_AUTO (UNIT_V_UF + 2) /* autosize */ +#define UNIT_WLK (1u << UNIT_V_WLK) +#define UNIT_DEN (1u << UNIT_V_DEN) +#define UNIT_AUTO (1u << UNIT_V_AUTO) #define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ #define IDLE 0 /* idle state */ -#define RWDS 1 /* rw, sect next */ -#define RWDT 2 /* rw, track next */ -#define FILL 3 /* fill buffer */ -#define EMPTY 4 /* empty buffer */ -#define CMD_COMPLETE 5 /* set done next */ -#define INIT_COMPLETE 6 /* init compl next */ +#define CMD8 1 /* 8b cmd, ho next */ +#define RWDS 2 /* rw, sect next */ +#define RWDT 3 /* rw, track next */ +#define RWXFR 4 /* rw, transfer */ +#define FILL 5 /* fill buffer */ +#define EMPTY 6 /* empty buffer */ +#define SDCNF 7 /* set dens, conf next */ +#define SDXFR 8 /* set dens, transfer */ +#define CMD_COMPLETE 9 /* set done next */ +#define INIT_COMPLETE 10 /* init compl next */ #define RXCS_V_FUNC 1 /* function */ #define RXCS_M_FUNC 7 @@ -71,25 +87,31 @@ #define RXCS_EMPTY 1 /* empty buffer */ #define RXCS_WRITE 2 /* write sector */ #define RXCS_READ 3 /* read sector */ +#define RXCS_SDEN 4 /* set density (RX28) */ #define RXCS_RXES 5 /* read status */ #define RXCS_WRDEL 6 /* write del data */ #define RXCS_ECODE 7 /* read error code */ #define RXCS_DRV 0020 /* drive */ #define RXCS_MODE 0100 /* mode */ #define RXCS_MAINT 0200 /* maintenance */ +#define RXCS_DEN 0400 /* density (RX28) */ +#define RXCS_GETFNC(x) (((x) >> RXCS_V_FUNC) & RXCS_M_FUNC) -#define RXES_CRC 0001 /* CRC error */ -#define RXES_PAR 0002 /* parity error */ +#define RXES_CRC 0001 /* CRC error NI */ #define RXES_ID 0004 /* init done */ -#define RXES_WLK 0010 /* write protect */ +#define RXES_RX02 0010 /* RX02 (RX28) */ +#define RXES_DERR 0020 /* density err (RX28) */ +#define RXES_DEN 0040 /* density (RX28) */ #define RXES_DD 0100 /* deleted data */ #define RXES_DRDY 0200 /* drive ready */ #define TRACK u3 /* current track */ -#define READ_RXDBR ((rx_csr & RXCS_MODE)? AC | (rx_dbr & 0377): rx_dbr) -#define CALC_DA(t,s) (((t) * RX_NUMSC) + ((s) - 1)) * RX_NUMBY +#define READ_RXDBR ((rx_csr & RXCS_MODE)? AC | (rx_dbr & 0377): rx_dbr) +#define CALC_DA(t,s,b) (((t) * RX_NUMSC) + ((s) - 1)) * b -extern int32 int_req, int_enable, dev_done, dev_enb; +extern int32 int_req, int_enable, dev_done; + +int32 rx_28 = 0; /* controller type */ int32 rx_tr = 0; /* xfer ready flag */ int32 rx_err = 0; /* error flag */ int32 rx_csr = 0; /* control/status */ @@ -102,13 +124,22 @@ int32 rx_state = IDLE; /* controller state */ int32 rx_cwait = 100; /* command time */ int32 rx_swait = 10; /* seek, per track */ int32 rx_xwait = 1; /* tr set time */ -int32 rx_stopioe = 1; /* stop on error */ -uint8 rx_buf[RX_NUMBY] = { 0 }; /* sector buffer */ -int32 bufptr = 0; /* buffer pointer */ +int32 rx_stopioe = 0; /* stop on error */ +uint8 rx_buf[RX2_NUMBY] = { 0 }; /* sector buffer */ +static int32 bptr = 0; /* buffer pointer */ + +DEVICE rx_dev; +int32 rx (int32 IR, int32 AC); t_stat rx_svc (UNIT *uptr); t_stat rx_reset (DEVICE *dptr); -t_stat rx_boot (int32 unitno); - +t_stat rx_boot (int32 unitno, DEVICE *dptr); +t_stat rx_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat rx_attach (UNIT *uptr, char *cptr); +void rx_cmd (void); +void rx_done (int32 esr_flags, int32 new_ecode); +t_stat rx_settype (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat rx_showtype (FILE *st, UNIT *uptr, int32 val, void *desc); + /* RX8E data structures rx_dev RX device descriptor @@ -117,6 +148,8 @@ t_stat rx_boot (int32 unitno); rx_mod RX modifier list */ +DIB rx_dib = { DEV_RX, 1, { &rx } }; + UNIT rx_unit[] = { { UDATA (&rx_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF+ UNIT_ROABLE, RX_SIZE) }, @@ -126,12 +159,12 @@ UNIT rx_unit[] = { REG rx_reg[] = { { ORDATA (RXCS, rx_csr, 12) }, { ORDATA (RXDB, rx_dbr, 12) }, - { ORDATA (RXES, rx_esr, 8) }, + { ORDATA (RXES, rx_esr, 12) }, { ORDATA (RXERR, rx_ecode, 8) }, { ORDATA (RXTA, rx_track, 8) }, { ORDATA (RXSA, rx_sector, 8) }, - { ORDATA (STAPTR, rx_state, 3), REG_RO }, - { ORDATA (BUFPTR, bufptr, 7) }, + { DRDATA (STAPTR, rx_state, 4), REG_RO }, + { DRDATA (BUFPTR, bptr, 8) }, { FLDATA (TR, rx_tr, 0) }, { FLDATA (ERR, rx_err, 0) }, { FLDATA (DONE, dev_done, INT_V_RX) }, @@ -140,81 +173,78 @@ REG rx_reg[] = { { DRDATA (CTIME, rx_cwait, 24), PV_LEFT }, { DRDATA (STIME, rx_swait, 24), PV_LEFT }, { DRDATA (XTIME, rx_xwait, 24), PV_LEFT }, - { URDATA (FLG, rx_unit[0].flags, 2, 1, UNIT_V_WLK, RX_NUMDR, REG_HRO) }, { FLDATA (STOP_IOE, rx_stopioe, 0) }, - { BRDATA (SBUF, rx_buf, 8, 8, RX_NUMBY) }, - { FLDATA (*DEVENB, dev_enb, INT_V_RX), REG_HRO }, + { BRDATA (SBUF, rx_buf, 8, 8, RX2_NUMBY) }, + { FLDATA (RX28, rx_28, 0), REG_HRO }, + { ORDATA (DEVNUM, rx_dib.dev, 6), REG_HRO }, { NULL } }; MTAB rx_mod[] = { { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, - { MTAB_XTD|MTAB_VDV, INT_RX, NULL, "ENABLED", &set_enb }, - { MTAB_XTD|MTAB_VDV, INT_RX, NULL, "DISABLED", &set_dsb }, + { MTAB_XTD | MTAB_VDV, 1, NULL, "RX28", + &rx_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 0, NULL, "RX8E", + &rx_settype, NULL, NULL }, + { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, + NULL, &rx_showtype, NULL }, + { (UNIT_DEN+UNIT_ATT), UNIT_ATT, "single density", NULL, NULL }, + { (UNIT_DEN+UNIT_ATT), (UNIT_DEN+UNIT_ATT), "double density", NULL, NULL }, + { (UNIT_AUTO+UNIT_DEN+UNIT_ATT), 0, "single density", NULL, NULL }, + { (UNIT_AUTO+UNIT_DEN+UNIT_ATT), UNIT_DEN, "double density", NULL, NULL }, + { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL }, + { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL }, + { (UNIT_AUTO+UNIT_DEN), 0, NULL, "SINGLE", &rx_set_size }, + { (UNIT_AUTO+UNIT_DEN), UNIT_DEN, NULL, "DOUBLE", &rx_set_size }, + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", + &set_dev, &show_dev, NULL }, { 0 } }; DEVICE rx_dev = { "RX", rx_unit, rx_reg, rx_mod, RX_NUMDR, 8, 20, 1, 8, 8, NULL, NULL, &rx_reset, - &rx_boot, NULL, NULL }; + &rx_boot, &rx_attach, NULL, + &rx_dib, DEV_DISABLE }; /* IOT routine */ -int32 rx (int32 pulse, int32 AC) +int32 rx (int32 IR, int32 AC) { -int32 drv; +int32 drv = ((rx_csr & RXCS_DRV)? 1: 0); /* get drive number */ -switch (pulse) { /* decode IR<9:11> */ +switch (IR & 07) { /* decode IR<9:11> */ case 0: /* unused */ break; case 1: /* LCD */ if (rx_state != IDLE) return AC; /* ignore if busy */ - rx_dbr = rx_csr = AC; /* save new command */ dev_done = dev_done & ~INT_RX; /* clear done, int */ int_req = int_req & ~INT_RX; rx_tr = rx_err = 0; /* clear flags */ - bufptr = 0; /* clear buf pointer */ - switch ((AC >> RXCS_V_FUNC) & RXCS_M_FUNC) { /* decode command */ - case RXCS_FILL: - rx_state = FILL; /* state = fill */ + bptr = 0; /* clear buf pointer */ + if (rx_28 && (AC & RXCS_MODE)) { /* RX28 8b mode? */ + rx_dbr = rx_csr = AC & 0377; /* save 8b */ rx_tr = 1; /* xfer is ready */ - break; - case RXCS_EMPTY: - rx_state = EMPTY; /* state = empty */ - sim_activate (&rx_unit[0], rx_xwait); /* sched xfer */ - break; - case RXCS_READ: case RXCS_WRITE: case RXCS_WRDEL: - rx_state = RWDS; /* state = get sector */ - rx_tr = 1; /* xfer is ready */ - rx_esr = rx_esr & RXES_ID; /* clear errors */ - break; - default: - rx_state = CMD_COMPLETE; /* state = cmd compl */ - drv = (rx_csr & RXCS_DRV) > 0; /* get drive number */ - sim_activate (&rx_unit[drv], rx_cwait); /* sched done */ - break; } /* end switch func */ + rx_state = CMD8; } /* wait for part 2 */ + else { rx_dbr = rx_csr = AC; /* save new command */ + rx_cmd (); } /* issue command */ return 0; /* clear AC */ case 2: /* XDR */ - switch (rx_state & 07) { /* case on state */ - default: /* default */ - return READ_RXDBR; /* return data reg */ + switch (rx_state & 017) { /* case on state */ case EMPTY: /* emptying buffer */ - sim_activate (&rx_unit[0], rx_xwait); /* sched xfer */ + sim_activate (&rx_unit[drv], rx_xwait); /* sched xfer */ return READ_RXDBR; /* return data reg */ - case RWDS: /* sector */ - rx_sector = AC & RX_M_SECTOR; /* save sector */ - case FILL: /* fill */ - rx_dbr = AC; /* save data */ - sim_activate (&rx_unit[0], rx_xwait); /* sched xfer */ + case CMD8: /* waiting for cmd */ + rx_dbr = AC & 0377; + rx_csr = (rx_csr & 0377) | ((AC & 017) << 8); + rx_cmd (); break; - case RWDT: /* track */ - rx_track = AC & RX_M_TRACK; /* save track */ + case RWDS:case RWDT:case FILL:case SDCNF: /* waiting for data */ rx_dbr = AC; /* save data */ - drv = (rx_csr & RXCS_DRV) > 0; /* get drive number */ - sim_activate (&rx_unit[drv], /* sched done */ - rx_swait * abs (rx_track - rx_unit[drv].TRACK)); - break; } /* end switch state */ + sim_activate (&rx_unit[drv], rx_xwait); /* schedule */ + break; + default: /* default */ + return READ_RXDBR; } /* return data reg */ break; case 3: /* STR */ if (rx_tr != 0) { @@ -242,16 +272,47 @@ case 7: /* INIT */ break; } /* end case pulse */ return AC; } + +void rx_cmd (void) +{ +int32 drv = ((rx_csr & RXCS_DRV)? 1: 0); /* get drive number */ + +switch (RXCS_GETFNC (rx_csr)) { /* decode command */ +case RXCS_FILL: + rx_state = FILL; /* state = fill */ + rx_tr = 1; /* xfer is ready */ + break; +case RXCS_EMPTY: + rx_state = EMPTY; /* state = empty */ + sim_activate (&rx_unit[drv], rx_xwait); /* sched xfer */ + break; +case RXCS_READ: case RXCS_WRITE: case RXCS_WRDEL: + rx_state = RWDS; /* state = get sector */ + rx_tr = 1; /* xfer is ready */ + rx_esr = rx_esr & RXES_ID; /* clear errors */ + break; +case RXCS_SDEN: + if (rx_28) { /* RX28? */ + rx_state = SDCNF; /* state = get conf */ + rx_tr = 1; /* xfer is ready */ + break; } /* else fall thru */ +default: + rx_state = CMD_COMPLETE; /* state = cmd compl */ + sim_activate (&rx_unit[drv], rx_cwait); /* sched done */ + break; } /* end switch func */ +return; +} /* Unit service; the action to be taken depends on the transfer state: - IDLE Should never get here, treat as unknown command - RWDS Just transferred sector, wait for track, set tr - RWDT Just transferred track, do read or write, finish command - FILL copy dbr to rx_buf[bufptr], advance ptr - if bufptr > max, finish command, else set tr - EMPTY if bufptr > max, finish command, else - copy rx_buf[bufptr] to dbr, advance ptr, set tr + IDLE Should never get here + RWDS Save sector, set TR, set RWDT + RWDT Save track, set RWXFR + RWXFR Read/write buffer + FILL copy dbr to rx_buf[bptr], advance ptr + if bptr > max, finish command, else set tr + EMPTY if bptr > max, finish command, else + copy rx_buf[bptr] to dbr, advance ptr, set tr CMD_COMPLETE copy requested data to dbr, finish command INIT_COMPLETE read drive 0, track 1, sector 1 to buffer, finish command @@ -261,158 +322,267 @@ return AC; t_stat rx_svc (UNIT *uptr) { -int32 i, func, byptr; +int32 i, func, byptr, bps, wps; t_addr da; -t_stat rval; -void rx_done (int32 new_dbr, int32 new_ecode); #define PTR12(x) (((x) + (x) + (x)) >> 1) -rval = SCPE_OK; /* assume ok */ -func = (rx_csr >> RXCS_V_FUNC) & RXCS_M_FUNC; /* get function */ +if (rx_28 && (uptr->flags & UNIT_DEN)) + bps = RX2_NUMBY; +else bps = RX_NUMBY; +wps = bps / 2; +func = RXCS_GETFNC (rx_csr); /* get function */ switch (rx_state) { /* case on state */ + case IDLE: /* idle */ - rx_done (rx_esr, 0); /* done */ - break; + return SCPE_IERR; + case EMPTY: /* empty buffer */ if (rx_csr & RXCS_MODE) { /* 8b xfer? */ - if (bufptr >= RX_NUMBY) { /* done? */ - rx_done (rx_esr, 0); /* set done */ - break; } /* and exit */ - rx_dbr = rx_buf[bufptr]; } /* else get data */ - else { byptr = PTR12 (bufptr); /* 12b xfer */ - if (bufptr >= RX_NUMWD) { /* done? */ - rx_done (rx_esr, 0); /* set done */ - break; } /* and exit */ - rx_dbr = (bufptr & 1)? /* get data */ - ((rx_buf[byptr] & 017) << 8) | rx_buf[byptr + 1]: - (rx_buf[byptr] << 4) | ((rx_buf[byptr + 1] >> 4) & 017); } - bufptr = bufptr + 1; + if (bptr >= bps) { /* done? */ + rx_done (0, 0); /* set done */ + break; } /* and exit */ + rx_dbr = rx_buf[bptr]; } /* else get data */ + else { + byptr = PTR12 (bptr); /* 12b xfer */ + if (bptr >= wps) { /* done? */ + rx_done (0, 0); /* set done */ + break; } /* and exit */ + rx_dbr = (bptr & 1)? /* get data */ + ((rx_buf[byptr] & 017) << 8) | rx_buf[byptr + 1]: + (rx_buf[byptr] << 4) | ((rx_buf[byptr + 1] >> 4) & 017); } + bptr = bptr + 1; rx_tr = 1; break; + case FILL: /* fill buffer */ if (rx_csr & RXCS_MODE) { /* 8b xfer? */ - rx_buf[bufptr] = rx_dbr; /* fill buffer */ - bufptr = bufptr + 1; - if (bufptr < RX_NUMBY) rx_tr = 1; /* if more, set xfer */ - else rx_done (rx_esr, 0); } /* else done */ - else { byptr = PTR12 (bufptr); /* 12b xfer */ - if (bufptr & 1) { /* odd or even? */ - rx_buf[byptr] = (rx_buf[byptr] & 0360) | ((rx_dbr >> 8) & 017); - rx_buf[byptr + 1] = rx_dbr & 0377; } - else { - rx_buf[byptr] = (rx_dbr >> 4) & 0377; - rx_buf[byptr + 1] = (rx_dbr & 017) << 4; } - bufptr = bufptr + 1; - if (bufptr < RX_NUMWD) rx_tr = 1; /* if more, set xfer */ - else { for (i = PTR12 (RX_NUMWD); i < RX_NUMBY; i++) - rx_buf[i] = 0; /* else fill sector */ - rx_done (rx_esr, 0); } } /* set done */ + rx_buf[bptr] = rx_dbr; /* fill buffer */ + bptr = bptr + 1; + if (bptr < bps) rx_tr = 1; /* if more, set xfer */ + else rx_done (0, 0); } /* else done */ + else { + byptr = PTR12 (bptr); /* 12b xfer */ + if (bptr & 1) { /* odd or even? */ + rx_buf[byptr] = (rx_buf[byptr] & 0360) | ((rx_dbr >> 8) & 017); + rx_buf[byptr + 1] = rx_dbr & 0377; } + else { + rx_buf[byptr] = (rx_dbr >> 4) & 0377; + rx_buf[byptr + 1] = (rx_dbr & 017) << 4; } + bptr = bptr + 1; + if (bptr < wps) rx_tr = 1; /* if more, set xfer */ + else { + for (i = PTR12 (RX_NUMWD); i < RX_NUMBY; i++) + rx_buf[i] = 0; /* else fill sector */ + rx_done (0, 0); } } /* set done */ break; + case RWDS: /* wait for sector */ + rx_sector = rx_dbr & RX_M_SECTOR; /* save sector */ rx_tr = 1; /* set xfer ready */ rx_state = RWDT; /* advance state */ - break; + return SCPE_OK; case RWDT: /* wait for track */ + rx_track = rx_dbr & RX_M_TRACK; /* save track */ + rx_state = RWXFR; + sim_activate (uptr, /* sched done */ + rx_swait * abs (rx_track - uptr->TRACK)); + return SCPE_OK; +case RWXFR: /* transfer */ + if ((uptr->flags & UNIT_BUF) == 0) { /* not buffered? */ + rx_done (0, 0110); /* done, error */ + return IORETURN (rx_stopioe, SCPE_UNATT); } if (rx_track >= RX_NUMTR) { /* bad track? */ - rx_done (rx_esr, 0040); /* done, error */ - break; } - uptr -> TRACK = rx_track; /* now on track */ + rx_done (0, 0040); /* done, error */ + break; } + uptr->TRACK = rx_track; /* now on track */ if ((rx_sector == 0) || (rx_sector > RX_NUMSC)) { /* bad sect? */ - rx_done (rx_esr, 0070); /* done, error */ + rx_done (0, 0070); /* done, error */ + break; } + if (rx_28 && /* RX28? */ + (((uptr->flags & UNIT_DEN) != 0) ^ + ((rx_csr & RXCS_DEN) != 0))) { /* densities agree? */ + rx_done (RXES_DERR, 0240); /* no, error */ break; } - if ((uptr -> flags & UNIT_BUF) == 0) { /* not buffered? */ - rx_done (rx_esr, 0110); /* done, error */ - rval = SCPE_UNATT; /* return error */ - break; } - da = CALC_DA (rx_track, rx_sector); /* get disk address */ + da = CALC_DA (rx_track, rx_sector, bps); /* get disk address */ if (func == RXCS_WRDEL) rx_esr = rx_esr | RXES_DD; /* del data? */ if (func == RXCS_READ) { /* read? */ - for (i = 0; i < RX_NUMBY; i++) - rx_buf[i] = *(((int8 *) uptr -> filebuf) + da + i); } - else { if (uptr -> flags & UNIT_WPRT) { /* write and locked? */ - rx_esr = rx_esr | RXES_WLK; /* flag error */ - rx_done (rx_esr, 0100); /* done, error */ - break; } - for (i = 0; i < RX_NUMBY; i++) /* write */ - *(((int8 *) uptr -> filebuf) + da + i) = rx_buf[i]; - da = da + RX_NUMBY; - if (da > uptr -> hwmark) uptr -> hwmark = da; } - rx_done (rx_esr, 0); /* done */ + for (i = 0; i < bps; i++) + rx_buf[i] = *(((int8 *) uptr->filebuf) + da + i); } + else { /* write */ + if (uptr->flags & UNIT_WPRT) { /* locked? */ + rx_done (0, 0100); /* done, error */ + break; } + for (i = 0; i < RX_NUMBY; i++) /* write */ + *(((int8 *) uptr->filebuf) + da + i) = rx_buf[i]; + da = da + RX_NUMBY; + if (da > uptr->hwmark) uptr->hwmark = da; } + rx_done (0, 0); /* done */ break; + +case SDCNF: /* confirm set density */ + if ((rx_dbr & 0377) != 0111) { /* confirmed? */ + rx_done (0, 0250); /* no, error */ + break; } + rx_state = SDXFR; /* next state */ + sim_activate (uptr, rx_cwait * 100); /* schedule operation */ + break; +case SDXFR: /* erase disk */ + for (i = 0; i < (int32) uptr->capac; i++) + *(((int8 *) uptr->filebuf) + i) = 0; + uptr->hwmark = uptr->capac; + if (rx_csr & RXCS_DEN) uptr->flags = uptr->flags | UNIT_DEN; + else uptr->flags = uptr->flags & ~UNIT_DEN; + rx_done (0, 0); + break; + case CMD_COMPLETE: /* command complete */ - if (func == RXCS_ECODE) rx_done (rx_ecode, 0); - else if (uptr -> flags & UNIT_ATT) rx_done (rx_esr | RXES_DRDY, 0); - else rx_done (rx_esr, 0); + if (func == RXCS_ECODE) { /* read ecode? */ + rx_dbr = rx_ecode; /* set dbr */ + rx_done (0, -1); } /* don't update */ + else rx_done (0, 0); break; + case INIT_COMPLETE: /* init complete */ rx_unit[0].TRACK = 1; /* drive 0 to trk 1 */ rx_unit[1].TRACK = 0; /* drive 1 to trk 0 */ if ((rx_unit[0].flags & UNIT_BUF) == 0) { /* not buffered? */ - rx_done (rx_esr | RXES_ID, 0010); /* init done, error */ - break; } - da = CALC_DA (1, 1); /* track 1, sector 1 */ - for (i = 0; i < RX_NUMBY; i++) /* read sector */ - rx_buf[i] = *(((int8 *) uptr -> filebuf) + da + i); - rx_done (rx_esr | RXES_ID | RXES_DRDY, 0); /* set done */ + rx_done (RXES_ID, 0010); /* init done, error */ + break; } + da = CALC_DA (1, 1, bps); /* track 1, sector 1 */ + for (i = 0; i < bps; i++) /* read sector */ + rx_buf[i] = *(((int8 *) uptr->filebuf) + da + i); + rx_done (RXES_ID, 0); /* set done */ if ((rx_unit[1].flags & UNIT_ATT) == 0) rx_ecode = 0020; break; } /* end case state */ -return IORETURN (rx_stopioe, rval); +return SCPE_OK; } /* Command complete. Set done and put final value in interface register, return to IDLE state. */ -void rx_done (int32 new_dbr, int32 new_ecode) +void rx_done (int32 esr_flags, int32 new_ecode) { +int32 drv = (rx_csr & RXCS_DRV)? 1: 0; + +rx_state = IDLE; /* now idle */ dev_done = dev_done | INT_RX; /* set done */ int_req = INT_UPDATE; /* update ints */ -rx_dbr = new_dbr; /* update buffer */ -if (new_ecode != 0) { /* test for error */ - rx_ecode = new_ecode; - rx_err = 1; } -rx_state = IDLE; /* now idle */ +rx_esr = (rx_esr | esr_flags) & ~(RXES_DRDY|RXES_RX02|RXES_DEN); +if (rx_28) rx_esr = rx_esr | RXES_RX02; /* update estat */ +if (rx_unit[drv].flags & UNIT_ATT) { /* update drv rdy */ + rx_esr = rx_esr | RXES_DRDY; + if (rx_unit[drv].flags & UNIT_DEN) /* update density */ + rx_esr = rx_esr | RXES_DEN; } +if (new_ecode > 0) rx_err = 1; /* test for error */ +if (new_ecode < 0) return; /* don't update? */ +rx_ecode = new_ecode; /* update ecode */ +rx_dbr = rx_esr; /* update RXDB */ return; } /* Reset routine. The RX is one of the few devices that schedules - an I/O transfer as part of its initialization. -*/ + an I/O transfer as part of its initialization */ t_stat rx_reset (DEVICE *dptr) { +rx_dbr = rx_csr = 0; /* 12b mode, drive 0 */ rx_esr = rx_ecode = 0; /* clear error */ rx_tr = rx_err = 0; /* clear flags */ +rx_track = rx_sector = 0; /* clear address */ +rx_state = IDLE; /* ctrl idle */ dev_done = dev_done & ~INT_RX; /* clear done, int */ int_req = int_req & ~INT_RX; int_enable = int_enable & ~INT_RX; -rx_dbr = rx_csr = 0; /* 12b mode, drive 0 */ sim_cancel (&rx_unit[1]); /* cancel drive 1 */ -if (rx_unit[0].flags & UNIT_BUF) { /* attached? */ +if (dptr->flags & DEV_DIS) sim_cancel (&rx_unit[0]); /* disabled? */ +else if (rx_unit[0].flags & UNIT_BUF) { /* attached? */ rx_state = INIT_COMPLETE; /* yes, sched init */ sim_activate (&rx_unit[0], rx_swait * abs (1 - rx_unit[0].TRACK)); } else rx_done (rx_esr | RXES_ID, 0010); /* no, error */ return SCPE_OK; } + +/* Attach routine */ + +t_stat rx_attach (UNIT *uptr, char *cptr) +{ +int32 p; +t_stat r; + +uptr->capac = (uptr->flags & UNIT_DEN)? RX2_SIZE: RX_SIZE; +r = attach_unit (uptr, cptr); +if ((r != SCPE_OK) || ((uptr->flags & UNIT_AUTO) == 0) || + (rx_28 == 0)) return r; +if (fseek (uptr->fileref, 0, SEEK_END)) return SCPE_OK; +if ((p = ftell (uptr->fileref)) == 0) return SCPE_OK; +if (p > RX_SIZE) { + uptr->flags = uptr->flags | UNIT_DEN; + uptr->capac = RX2_SIZE; } +else { uptr->flags = uptr->flags & ~UNIT_DEN; + uptr->capac = RX_SIZE; } +return SCPE_OK; +} + +/* Set size routine */ + +t_stat rx_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +if (uptr->flags & UNIT_ATT) return SCPE_ALATT; +if ((rx_28 == 0) && val) return SCPE_NOFNC; /* not on RX8E */ +uptr->capac = val? RX2_SIZE: RX_SIZE; +return SCPE_OK; +} + +/* Set controller type */ + +t_stat rx_settype (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +int32 i; + +if ((val < 0) || (val > 1) || (cptr != NULL)) return SCPE_ARG; +if (val == rx_28) return SCPE_OK; +for (i = 0; i < RX_NUMDR; i++) { + if (rx_unit[i].flags & UNIT_ATT) return SCPE_ALATT; } +for (i = 0; i < RX_NUMDR; i++) { + rx_unit[i].flags = rx_unit[i].flags & ~(UNIT_DEN | UNIT_AUTO); + rx_unit[i].capac = RX_SIZE; + if (val) rx_unit[i].flags = rx_unit[i].flags | UNIT_AUTO; } +rx_28 = val; +return SCPE_OK; +} + +/* Show controller type */ + +t_stat rx_showtype (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +if (rx_28) fprintf (st, "RX28"); +else fprintf (st, "RX8E"); +return SCPE_OK; +} /* Bootstrap routine */ -#define BOOT_START 022 -#define BOOT_INST 060 -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int)) +#define BOOT_START 022 +#define BOOT_ENTRY 022 +#define BOOT_INST 060 +#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) +#define BOOT2_START 020 +#define BOOT2_ENTRY 033 +#define BOOT2_LEN (sizeof (boot2_rom) / sizeof (int16)) -static const int32 boot_rom[] = { +static const uint16 boot_rom[] = { 06755, /* 22, SDN */ 05022, /* 23, JMP .-1 */ 07126, /* 24, CLL CML RTL ; read command + */ 01060, /* 25, TAD UNIT ; unit no */ 06751, /* 26, LCD ; load read+unit */ - 07201, /* 27, CLL IAC ; AC = 1 */ - 04053, /* 30, JMS 053 ; load sector */ - 04053, /* 31, JMS 053 ; load track */ + 07201, /* 27, CLA IAC ; AC = 1 */ + 04053, /* 30, JMS LOAD ; load sector */ + 04053, /* 31, JMS LOAD ; load track */ 07104, /* 32, CLL RAL ; AC = 2 */ 06755, /* 33, SDN */ - 05054, /* 34, JMP 54 */ + 05054, /* 34, JMP LOAD+1 */ 06754, /* 35, SER */ 07450, /* 36, SNA ; more to do? */ 07610, /* 37, CLA SKP ; error */ @@ -420,27 +590,69 @@ static const int32 boot_rom[] = { 07402, 07402, /* 41-45, HALT ; error */ 07402, 07402, 07402, 06751, /* 46, LCD ; load empty */ - 04053, /* 47, JMS 53 ; get data */ + 04053, /* 47, JMS LOAD ; get data */ 03002, /* 50, DCA 2 ; store */ 02050, /* 51, ISZ 50 ; incr store */ 05047, /* 52, JMP 47 ; loop until done */ - 00000, /* 53, 0 */ + 00000, /* LOAD, 0 */ 06753, /* 54, STR */ 05033, /* 55, JMP 33 */ 06752, /* 56, XDR */ - 05453, /* 57, JMP I 53 */ + 05453, /* 57, JMP I LOAD */ 07024, /* UNIT, CML RAL ; for unit 1 */ 06030 /* 61, KCC */ }; -t_stat rx_boot (int32 unitno) +static const uint16 boot2_rom[] = { + 01061, /* READ, TAD UNIT ; next unit+den */ + 01046, /* 21, TAD CON360 ; add in 360 */ + 00060, /* 22, AND CON420 ; mask to 420 */ + 03061, /* 23, DCA UNIT ; 400,420,0,20... */ + 07327, /* 24, STL CLA IAC RTL ; AC = 6 = read */ + 01061, /* 25, TAD UNIT ; +unit+den */ + 06751, /* 26, LCD ; load cmd */ + 07201, /* 27, CLA IAC; ; AC = 1 = trksec */ + 04053, /* 30, JMS LOAD ; load trk */ + 04053, /* 31, JMS LOAD ; load sec */ + 07004, /* CN7004, RAL ; AC = 2 = empty */ + 06755, /* START, SDN ; done? */ + 05054, /* 34, JMP LOAD+1 ; check xfr */ + 06754, /* 35, SER ; error? */ + 07450, /* 36, SNA ; AC=0 on start */ + 05020, /* 37, JMP RD ; try next den,un */ + 01061, /* 40, TAD UNIT ; +unit+den */ + 06751, /* 41, LCD ; load cmd */ + 01061, /* 42, TAD UNIT ; set 60 for sec boot */ + 00046, /* 43, AND CON360 ; only density */ + 01032, /* 44, TAD CN7004 ; magic */ + 03060, /* 45, DCA 60 */ + 00360, /* CON360, 360 ; NOP */ + 04053, /* 47, JMS LOAD ; get data */ + 03002, /* 50, DCA 2 ; store */ + 02050, /* 51, ISZ .-1 ; incr store */ + 05047, /* 52, JMP .-3 ; loop until done */ + 00000, /* LOAD, 0 */ + 06753, /* 54, STR ; xfr ready? */ + 05033, /* 55, JMP 33 ; no, chk done */ + 06752, /* 56, XDR ; get word */ + 05453, /* 57, JMP I 53 ; return */ + 00420, /* CON420, 420 ; toggle */ + 00020 /* UNIT, 20 ; unit+density */ +}; + +t_stat rx_boot (int32 unitno, DEVICE *dptr) { int32 i; extern int32 saved_PC; extern uint16 M[]; -for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i]; -M[BOOT_INST] = unitno? 07024: 07004; -saved_PC = BOOT_START; +if (rx_dib.dev != DEV_RX) return STOP_NOTSTD; /* only std devno */ +if (rx_28) { + for (i = 0; i < BOOT2_LEN; i++) M[BOOT2_START + i] = boot2_rom[i]; + saved_PC = BOOT2_ENTRY; } +else { + for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i]; + M[BOOT_INST] = unitno? 07024: 07004; + saved_PC = BOOT_ENTRY; } return SCPE_OK; } diff --git a/PDP8/pdp8_sys.c b/PDP8/pdp8_sys.c index c484a717..d9efba82 100644 --- a/PDP8/pdp8_sys.c +++ b/PDP8/pdp8_sys.c @@ -87,7 +87,8 @@ const char *sim_stop_messages[] = { "Unknown error", "Unimplemented instruction", "HALT instruction", - "Breakpoint" }; + "Breakpoint", + "Non-standard device number" }; /* Binary loader diff --git a/PDP8/pdp8_tt.c b/PDP8/pdp8_tt.c index 26bb6f7a..5c204110 100644 --- a/PDP8/pdp8_tt.c +++ b/PDP8/pdp8_tt.c @@ -25,6 +25,8 @@ tti,tto KL8E terminal input/output + 01-Nov-02 RMS Added 7B/8B support + 04-Oct-02 RMS Added DIBs, device number support 30-May-02 RMS Widened POS to 32b 07-Sep-01 RMS Moved function prototypes */ @@ -32,13 +34,20 @@ #include "pdp8_defs.h" #include -#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */ -#define UNIT_UC (1 << UNIT_V_UC) +#define UNIT_V_8B (UNIT_V_UF + 0) /* 8B */ +#define UNIT_V_KSR (UNIT_V_UF + 1) /* KSR33 */ +#define UNIT_8B (1 << UNIT_V_8B) +#define UNIT_KSR (1 << UNIT_V_KSR) + extern int32 int_req, int_enable, dev_done, stop_inst; + +int32 tti (int32 IR, int32 AC); +int32 tto (int32 IR, int32 AC); t_stat tti_svc (UNIT *uptr); t_stat tto_svc (UNIT *uptr); t_stat tti_reset (DEVICE *dptr); t_stat tto_reset (DEVICE *dptr); +t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); /* TTI data structures @@ -48,7 +57,9 @@ t_stat tto_reset (DEVICE *dptr); tti_mod TTI modifiers list */ -UNIT tti_unit = { UDATA (&tti_svc, UNIT_UC, 0), KBD_POLL_WAIT }; +DIB tti_dib = { DEV_TTI, 1, { &tti } }; + +UNIT tti_unit = { UDATA (&tti_svc, UNIT_KSR, 0), KBD_POLL_WAIT }; REG tti_reg[] = { { ORDATA (BUF, tti_unit.buf, 8) }, @@ -57,19 +68,22 @@ REG tti_reg[] = { { FLDATA (INT, int_req, INT_V_TTI) }, { DRDATA (POS, tti_unit.pos, 32), PV_LEFT }, { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, - { FLDATA (UC, tti_unit.flags, UNIT_V_UC), REG_HRO }, + { FLDATA (UC, tti_unit.flags, UNIT_V_KSR), REG_HRO }, { NULL } }; MTAB tti_mod[] = { - { UNIT_UC, 0, "lower case", "LC", NULL }, - { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, + { UNIT_KSR+UNIT_8B, UNIT_KSR, "KSR", "KSR", &tty_set_mode }, + { UNIT_KSR+UNIT_8B, 0 , "7b" , "7B" , &tty_set_mode }, + { UNIT_KSR+UNIT_8B, UNIT_8B , "8b" , "8B" , &tty_set_mode }, + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev }, { 0 } }; DEVICE tti_dev = { "TTI", &tti_unit, tti_reg, tti_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &tti_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &tti_dib, 0 }; /* TTO data structures @@ -78,7 +92,9 @@ DEVICE tti_dev = { tto_reg TTO register list */ -UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT }; +DIB tto_dib = { DEV_TTO, 1, { &tto } }; + +UNIT tto_unit = { UDATA (&tto_svc, UNIT_KSR, 0), SERIAL_OUT_WAIT }; REG tto_reg[] = { { ORDATA (BUF, tto_unit.buf, 8) }, @@ -89,17 +105,25 @@ REG tto_reg[] = { { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT }, { NULL } }; +MTAB tto_mod[] = { + { UNIT_KSR+UNIT_8B, UNIT_KSR, "KSR", "KSR", &tty_set_mode }, + { UNIT_KSR+UNIT_8B, 0 , "7b" , "7B" , &tty_set_mode }, + { UNIT_KSR+UNIT_8B, UNIT_8B , "8b" , "8B" , &tty_set_mode }, + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", NULL, NULL, &show_dev }, + { 0 } }; + DEVICE tto_dev = { - "TTO", &tto_unit, tto_reg, NULL, + "TTO", &tto_unit, tto_reg, tto_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &tto_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &tto_dib, 0 }; /* Terminal input: IOT routine */ -int32 tti (int32 pulse, int32 AC) +int32 tti (int32 IR, int32 AC) { -switch (pulse) { /* decode IR<9:11> */ +switch (IR & 07) { /* decode IR<9:11> */ case 0: /* KCF */ dev_done = dev_done & ~INT_TTI; /* clear flag */ int_req = int_req & ~INT_TTI; @@ -129,14 +153,15 @@ default: t_stat tti_svc (UNIT *uptr) { -int32 temp; +int32 c; sim_activate (&tti_unit, tti_unit.wait); /* continue poll */ -if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */ -temp = temp & 0177; -if ((tti_unit.flags & UNIT_UC) && islower (temp)) - temp = toupper (temp); -tti_unit.buf = temp | 0200; /* got char */ +if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */ +if (tti_unit.flags & UNIT_KSR) { /* UC only? */ + c = c & 0177; + if (islower (c)) c = toupper (c); + tti_unit.buf = c | 0200; } /* add TTY bit */ +else tti_unit.buf = c & ((tti_unit.flags & UNIT_8B)? 0377: 0177); dev_done = dev_done | INT_TTI; /* set done */ int_req = INT_UPDATE; /* update interrupts */ tti_unit.pos = tti_unit.pos + 1; @@ -157,9 +182,9 @@ return SCPE_OK; /* Terminal output: IOT routine */ -int32 tto (int32 pulse, int32 AC) +int32 tto (int32 IR, int32 AC) { -switch (pulse) { /* decode IR<9:11> */ +switch (IR & 07) { /* decode IR<9:11> */ case 0: /* TLF */ dev_done = dev_done | INT_TTO; /* set flag */ int_req = INT_UPDATE; /* update interrupts */ @@ -187,11 +212,16 @@ default: t_stat tto_svc (UNIT *uptr) { -int32 temp; +int32 c; +t_stat r; dev_done = dev_done | INT_TTO; /* set done */ int_req = INT_UPDATE; /* update interrupts */ -if ((temp = sim_putchar (tto_unit.buf & 0177)) != SCPE_OK) return temp; +if (tto_unit.flags & UNIT_KSR) { /* UC only? */ + c = tto_unit.buf & 0177; + if (islower (c)) c = toupper (c); } +else c = tto_unit.buf & ((tto_unit.flags & UNIT_8B)? 0377: 0177); +if ((r = sim_putchar (c)) != SCPE_OK) return r; tto_unit.pos = tto_unit.pos + 1; return SCPE_OK; } @@ -207,3 +237,10 @@ int_enable = int_enable | INT_TTO; /* set enable */ sim_cancel (&tto_unit); /* deactivate unit */ return SCPE_OK; } + +t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +tti_unit.flags = (tti_unit.flags & ~(UNIT_KSR | UNIT_8B)) | val; +tto_unit.flags = (tto_unit.flags & ~(UNIT_KSR | UNIT_8B)) | val; +return SCPE_OK; +} diff --git a/PDP8/pdp8_ttx.c b/PDP8/pdp8_ttx.c index e22742f9..55f82c54 100644 --- a/PDP8/pdp8_ttx.c +++ b/PDP8/pdp8_ttx.c @@ -25,6 +25,9 @@ ttix,ttox PT08/KL8JA terminal input/output + 02-Nov-02 RMS Added 7B/8B support + 04-Oct-02 RMS Added DIB, device number support + 22-Aug-02 RMS Updated for changes to sim_tmxr.c 06-Jan-02 RMS Added device enable/disable support 30-Dec-01 RMS Complete rebuild 30-Nov-01 RMS Added extended SET/SHOW support @@ -42,18 +45,26 @@ #define TTX_LINES 4 #define TTX_MASK (TTX_LINES - 1) -#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */ + +#define UNIT_V_8B (UNIT_V_UF + 0) /* 8B */ +#define UNIT_V_UC (UNIT_V_UF + 1) /* upper case */ +#define UNIT_8B (1 << UNIT_V_8B) #define UNIT_UC (1 << UNIT_V_UC) + #define TTX_GETLN(x) (((x) >> 4) & TTX_MASK) -extern int32 int_req, int_enable, dev_done, dev_enb, stop_inst; +extern int32 int_req, int_enable, dev_done, stop_inst; + uint8 ttix_buf[TTX_LINES] = { 0 }; /* input buffers */ uint8 ttox_buf[TTX_LINES] = { 0 }; /* output buffers */ int32 ttx_tps = 100; /* polls per second */ TMLN ttx_ldsc[TTX_LINES] = { 0 }; /* line descriptors */ TMXR ttx_desc = { /* mux descriptor */ - TTX_LINES, 0, &ttx_ldsc[0], &ttx_ldsc[1], &ttx_ldsc[2], &ttx_ldsc[3] }; + TTX_LINES, 0, 0, &ttx_ldsc[0], &ttx_ldsc[1], &ttx_ldsc[2], &ttx_ldsc[3] }; +DEVICE ttix_dev, ttox_dev; +int32 ttix (int32 IR, int32 AC); +int32 ttox (int32 IR, int32 AC); t_stat ttix_svc (UNIT *uptr); t_stat ttix_reset (DEVICE *dptr); t_stat ttox_svc (UNIT *uptr); @@ -62,6 +73,7 @@ t_stat ttx_attach (UNIT *uptr, char *cptr); t_stat ttx_detach (UNIT *uptr); t_stat ttx_summ (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat ttx_show (FILE *st, UNIT *uptr, int32 val, void *desc); +void ttx_enbdis (int32 dis); /* TTIx data structures @@ -71,6 +83,9 @@ t_stat ttx_show (FILE *st, UNIT *uptr, int32 val, void *desc); ttix_mod TTIx modifiers list */ +DIB ttix_dib = { DEV_KJ8, 8, + { &ttix, &ttox, &ttix, &ttox, &ttix, &ttox, &ttix, &ttox } }; + UNIT ttix_unit = { UDATA (&ttix_svc, UNIT_ATTABLE, 0), KBD_POLL_WAIT }; REG ttix_reg[] = { @@ -80,7 +95,7 @@ REG ttix_reg[] = { { GRDATA (INT, int_req, 8, TTX_LINES, INT_V_TTI1) }, { DRDATA (TIME, ttix_unit.wait, 24), REG_NZ + PV_LEFT }, { DRDATA (TPS, ttx_tps, 10), REG_NZ + PV_LEFT }, - { FLDATA (*DEVENB, dev_enb, INT_V_TTI1), REG_HRO }, + { ORDATA (DEVNUM, ttix_dib.dev, 6), REG_HRO }, { NULL } }; MTAB ttix_mod[] = { @@ -91,15 +106,16 @@ MTAB ttix_mod[] = { NULL, &ttx_show, NULL }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, NULL, &ttx_show, NULL }, - { MTAB_XTD|MTAB_VDV, INT_TTI1, NULL, "ENABLED", &set_enb }, - { MTAB_XTD|MTAB_VDV, INT_TTI1, NULL, "DISABLED", &set_dsb }, + { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", + &set_dev, &show_dev, NULL }, { 0 } }; DEVICE ttix_dev = { "TTIX", &ttix_unit, ttix_reg, ttix_mod, 1, 10, 31, 1, 8, 8, &tmxr_ex, &tmxr_dep, &ttix_reset, - NULL, &ttx_attach, &ttx_detach }; + NULL, &ttx_attach, &ttx_detach, + &ttix_dib, DEV_DISABLE }; /* TTOx data structures @@ -121,21 +137,20 @@ REG ttox_reg[] = { { GRDATA (INT, int_req, 8, TTX_LINES, INT_V_TTO1) }, { URDATA (TIME, ttox_unit[0].wait, 10, 24, 0, TTX_LINES, PV_LEFT) }, - { URDATA (FLGS, ttox_unit[0].flags, 8, 1, UNIT_V_UC, - TTX_LINES, REG_HRO) }, - { FLDATA (*DEVENB, dev_enb, INT_V_TTI1), REG_HRO }, { NULL } }; MTAB ttox_mod[] = { - { UNIT_UC, 0, "lower case", "LC", NULL }, - { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, + { UNIT_UC+UNIT_8B, UNIT_UC, "UC", "UC", NULL }, + { UNIT_UC+UNIT_8B, 0 , "7b" , "7B" , NULL }, + { UNIT_UC+UNIT_8B, UNIT_8B , "8b" , "8B" , NULL }, { 0 } }; DEVICE ttox_dev = { "TTOX", ttox_unit, ttox_reg, ttox_mod, 4, 10, 31, 1, 8, 8, NULL, NULL, &ttox_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + NULL, DEV_DISABLE }; /* Terminal input: IOT routine */ @@ -179,19 +194,20 @@ t_stat ttix_svc (UNIT *uptr) { int32 ln, c, temp; -if ((uptr -> flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */ +if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */ temp = sim_rtcn_calb (ttx_tps, TMR_TTX); /* calibrate */ sim_activate (uptr, temp); /* continue poll */ -ln = tmxr_poll_conn (&ttx_desc, uptr); /* look for connect */ +ln = tmxr_poll_conn (&ttx_desc); /* look for connect */ if (ln >= 0) { /* got one? */ ttx_ldsc[ln].rcve = 1; } /* rcv enabled */ tmxr_poll_rx (&ttx_desc); /* poll for input */ for (ln = 0; ln < TTX_LINES; ln++) { /* loop thru lines */ if (ttx_ldsc[ln].conn) { /* connected? */ if (temp = tmxr_getc_ln (&ttx_ldsc[ln])) { /* get char */ - c = temp & 0177; - if ((ttox_unit[ln].flags & UNIT_UC) && islower (c)) - c = toupper (c); + if (ttox_unit[ln].flags & UNIT_UC) { /* UC mode? */ + c = temp & 0177; + if (islower (c)) c = toupper (c); } + else c = temp & ((ttox_unit[ln].flags & UNIT_8B)? 0377: 0177); ttix_buf[ln] = c; dev_done = dev_done | (INT_TTI1 << ln); int_req = INT_UPDATE; } } } @@ -204,10 +220,11 @@ t_stat ttix_reset (DEVICE *dptr) { int32 t, ln, itto; +ttx_enbdis (dptr->flags & DEV_DIS); /* sync enables */ if (ttix_unit.flags & UNIT_ATT) { /* if attached, */ if (!sim_is_active (&ttix_unit)) { - t = sim_rtcn_init (ttix_unit.wait, TMR_TTX); - sim_activate (&ttix_unit, t); } } /* activate */ + t = sim_rtcn_init (ttix_unit.wait, TMR_TTX); + sim_activate (&ttix_unit, t); } } /* activate */ else sim_cancel (&ttix_unit); /* else stop */ for (ln = 0; ln < TTX_LINES; ln++) { /* for all lines */ ttix_buf[ln] = 0; /* clear buf, */ @@ -258,17 +275,19 @@ t_stat ttox_svc (UNIT *uptr) { int32 c, ln = uptr - ttox_unit; /* line # */ -if (ttx_desc.ldsc[ln] -> conn) { /* connected? */ - if (ttx_desc.ldsc[ln] -> xmte) { /* tx enabled? */ - TMLN *lp = ttx_desc.ldsc[ln]; /* get line */ +if (ttx_desc.ldsc[ln]->conn) { /* connected? */ + if (ttx_desc.ldsc[ln]->xmte) { /* tx enabled? */ + TMLN *lp = ttx_desc.ldsc[ln]; /* get line */ + if (ttox_unit[ln].flags & UNIT_UC) { /* UC mode? */ c = ttox_buf[ln] & 0177; /* get char */ - if ((ttox_unit[ln].flags & UNIT_UC) && islower (c)) - c = toupper (c); - tmxr_putc_ln (lp, c); /* output char */ - tmxr_poll_tx (&ttx_desc); } /* poll xmt */ - else { tmxr_poll_tx (&ttx_desc); /* poll xmt */ - sim_activate (uptr, ttox_unit[ln].wait); /* wait */ - return SCPE_OK; } } + if (islower (c)) c = toupper (c); } + else c = ttox_buf[ln] & ((ttox_unit[ln].flags & UNIT_8B)? 0377: 0177); + tmxr_putc_ln (lp, c); /* output char */ + tmxr_poll_tx (&ttx_desc); } /* poll xmt */ + else { + tmxr_poll_tx (&ttx_desc); /* poll xmt */ + sim_activate (uptr, ttox_unit[ln].wait); /* wait */ + return SCPE_OK; } } dev_done = dev_done | (INT_TTO1 << ln); /* set done */ int_req = INT_UPDATE; /* update intr */ return SCPE_OK; @@ -280,6 +299,7 @@ t_stat ttox_reset (DEVICE *dptr) { int32 ln, itto; +ttx_enbdis (dptr->flags & DEV_DIS); /* sync enables */ for (ln = 0; ln < TTX_LINES; ln++) { /* for all lines */ ttox_buf[ln] = 0; /* clear buf */ itto = (INT_TTO1 << ln); /* interrupt */ @@ -313,9 +333,9 @@ t_stat r; r = tmxr_detach (&ttx_desc, uptr); /* detach */ for (i = 0; i < TTX_LINES; i++) { /* all lines, */ - ttx_desc.ldsc[i] -> rcve = 0; /* disable rcv */ + ttx_desc.ldsc[i]->rcve = 0; /* disable rcv */ sim_cancel (&ttox_unit[i]); } /* stop poll */ -return SCPE_OK; +return r; } /* Show summary processor */ @@ -345,3 +365,15 @@ if (i < TTX_LINES) { else fprintf (st, "all disconnected\n"); return SCPE_OK; } + +/* Enable/disable device */ + +void ttx_enbdis (int32 dis) +{ +if (dis) { + ttix_dev.flags = ttox_dev.flags | DEV_DIS; + ttox_dev.flags = ttox_dev.flags | DEV_DIS; } +else { ttix_dev.flags = ttix_dev.flags & ~DEV_DIS; + ttox_dev.flags = ttox_dev.flags & ~DEV_DIS; } +return; +} diff --git a/S3/s3_cd.c b/S3/s3_cd.c index d5ed05f2..58db7428 100644 --- a/S3/s3_cd.c +++ b/S3/s3_cd.c @@ -1,7 +1,6 @@ /* s3_cd.c: IBM 1442 card reader/punch - Copyright (c) 2001 Charles E. Owen - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 2001, Charles E. Owen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -20,14 +19,16 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - Except as contained in this notice, the name of Robert M Supnik shall not + Except as contained in this notice, the name of Charles E. Owen shall not be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. + in this Software without prior written authorization from Charles E. Owen. cdr card reader cdp card punch cdp2 card punch stacker 2 + 08-Oct-02 RMS Added impossible function catcher + Normally, cards are represented as ASCII text streams terminated by newlines. This allows cards to be created and edited as normal files. Set the EBCDIC flag on the card unit allows cards to be read or punched in EBCDIC format, @@ -43,7 +44,7 @@ extern char ascii_to_ebcdic[256]; int32 s1sel, s2sel; char rbuf[CBUFSIZE]; /* > CDR_WIDTH */ t_stat cdr_svc (UNIT *uptr); -t_stat cdr_boot (int32 unitno); +t_stat cdr_boot (int32 unitno, DEVICE *dptr); t_stat cdr_attach (UNIT *uptr, char *cptr); t_stat cd_reset (DEVICE *dptr); t_stat read_card (int32 ilnt, int32 mod); @@ -148,7 +149,7 @@ int32 crd (int32 op, int32 m, int32 n, int32 data) case 0: /* SIO 1442 */ /* if (n == 1) return STOP_IBKPT; */ - switch (data) { /* Select atacker */ + switch (data) { /* Select stacker */ case 0x00: break; case 0x01: @@ -256,6 +257,8 @@ int32 crd (int32 op, int32 m, int32 n, int32 data) default: break; } + printf (">>CRD non-existent function %d\n", op); + return SCPE_OK; } /* Card read routine @@ -428,7 +431,7 @@ return attach_unit (uptr, cptr); /* Bootstrap routine */ -t_stat cdr_boot (int32 unitno) +t_stat cdr_boot (int32 unitno, DEVICE *dptr) { cdr_ebcdic = 1; DAR = 0; diff --git a/S3/s3_cpu.c b/S3/s3_cpu.c index d125d9bc..470d4b30 100644 --- a/S3/s3_cpu.c +++ b/S3/s3_cpu.c @@ -21,6 +21,10 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + Except as contained in this notice, the name of Charles E. Owen shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Charles E. Owen. + ------------------------------------------------------------------------------ cpu System/3 (models 10 and 15) central processor @@ -384,7 +388,7 @@ t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_reset (DEVICE *dptr); t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_boot (int32 unitno); +t_stat cpu_boot (int32 unitno, DEVICE *dptr1); extern int32 pkb (int32 op, int32 m, int32 n, int32 data); extern int32 crd (int32 op, int32 m, int32 n, int32 data); extern int32 lpt (int32 op, int32 m, int32 n, int32 data); @@ -567,7 +571,7 @@ if (debug_reg & 0x01) { val[3] = GetMem(PC+3); val[4] = GetMem(PC+4); val[5] = GetMem(PC+5); - fprint_sym(trace, PC, val, &cpu_unit, SWMASK('M')); + fprint_sym(trace, PC, (uint32 *) val, &cpu_unit, SWMASK('M')); fprintf(trace, "\n"); } @@ -1820,7 +1824,7 @@ for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; return SCPE_OK; } -t_stat cpu_boot (int32 unitno) +t_stat cpu_boot (int32 unitno, DEVICE *dptr) { level = 8; IAR[8] = 0; diff --git a/S3/s3_defs.h b/S3/s3_defs.h index aab3b013..bd7a5610 100644 --- a/S3/s3_defs.h +++ b/S3/s3_defs.h @@ -1,7 +1,6 @@ /* ibms3_defs.h: IBM System/3 simulator definitions Copyright (c) 2001, Charles E. Owen - Copyright (c) 1993-2001, Robert M. Supnik Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -20,10 +19,9 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - Except as contained in this notice, the name of Robert M Supnik shall not + Except as contained in this notice, the name of Charles E. Owen shall not be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - + in this Software without prior written authorization from Charles E. Owen. */ #include "sim_defs.h" /* simulator defns */ diff --git a/S3/s3_disk.c b/S3/s3_disk.c index a4d9f795..48192194 100644 --- a/S3/s3_disk.c +++ b/S3/s3_disk.c @@ -1,7 +1,6 @@ /* s3_disk.c: IBM 5444 Disk Drives - Copyright (c) 2001 Charles E. Owen - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 2001, Charles E. Owen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -20,14 +19,16 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - Except as contained in this notice, the name of Robert M Supnik shall not + Except as contained in this notice, the name of Charles E. Owen shall not be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. + in this Software without prior written authorization from Charles E. Owen. r1 Removeable disk 1 f1 Fixed disk 1 r2 Removeable disk 2 f2 Fixed disk 2 + + 08-Oct-02 RMS Added impossible function catcher */ #include "s3_defs.h" @@ -42,19 +43,19 @@ int32 dsk (int32 disk, int32 op, int32 m, int32 n, int32 data); int32 read_sector(UNIT *uptr, char *dbuf, int32 sect); int32 write_sector(UNIT *uptr, char *dbuf, int32 sect); t_stat r1_svc (UNIT *uptr); -t_stat r1_boot (int32 unitno); +t_stat r1_boot (int32 unitno, DEVICE *dptr); t_stat r1_attach (UNIT *uptr, char *cptr); t_stat r1_reset (DEVICE *dptr); t_stat f1_svc (UNIT *uptr); -t_stat f1_boot (int32 unitno); +t_stat f1_boot (int32 unitno, DEVICE *dptr); t_stat f1_attach (UNIT *uptr, char *cptr); t_stat f1_reset (DEVICE *dptr); t_stat r2_svc (UNIT *uptr); -t_stat r2_boot (int32 unitno); +t_stat r2_boot (int32 unitno, DEVICE *dptr); t_stat r2_attach (UNIT *uptr, char *cptr); t_stat r2_reset (DEVICE *dptr); t_stat f2_svc (UNIT *uptr); -t_stat f2_boot (int32 unitno); +t_stat f2_boot (int32 unitno, DEVICE *dptr); t_stat f2_attach (UNIT *uptr, char *cptr); t_stat f2_reset (DEVICE *dptr); extern int32 GetMem(int32 addr); @@ -603,7 +604,9 @@ int32 dsk (int32 disk, int32 op, int32 m, int32 n, int32 data) return ((SCPE_OK << 16) | iodata); default: break; - } + } + printf (">>DSK%d non-existent function %d\n", disk, op); + return SCPE_OK; } /* Disk unit service. If a stacker select is active, copy to the @@ -701,7 +704,7 @@ return attach_unit (uptr, cptr); /* Bootstrap routine */ -t_stat r1_boot (int32 unitno) +t_stat r1_boot (int32 unitno, DEVICE *dptr) { int i; r1_unit.u3 = 0; @@ -711,7 +714,7 @@ for (i = 0; i < 256; i++) { } return SCPE_OK; } -t_stat f1_boot (int32 unitno) +t_stat f1_boot (int32 unitno, DEVICE *dptr) { int i; f1_unit.u3 = 0; @@ -721,7 +724,7 @@ for (i = 0; i < 256; i++) { } return SCPE_OK; } -t_stat r2_boot (int32 unitno) +t_stat r2_boot (int32 unitno, DEVICE *dptr) { int i; r2_unit.u3 = 0; @@ -731,7 +734,7 @@ for (i = 0; i < 256; i++) { } return SCPE_OK; } -t_stat f2_boot (int32 unitno) +t_stat f2_boot (int32 unitno, DEVICE *dptr) { int i; f2_unit.u3 = 0; diff --git a/S3/s3_lp.c b/S3/s3_lp.c index e047fc0f..4ebadb5c 100644 --- a/S3/s3_lp.c +++ b/S3/s3_lp.c @@ -1,7 +1,6 @@ /* s3_lp.c: IBM 1403 line printer simulator - Copyright (c) 2001 Charles E. Owen - Copyright (c) 1993-2001, Robert M. Supnik + Copyright (c) 2001, Charles E. Owen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -20,12 +19,13 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - Except as contained in this notice, the name of Robert M Supnik shall not + Except as contained in this notice, the name of Charles E. Owen shall not be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. + in this Software without prior written authorization from Charles E. Owen. lpt 1403 line printer + 08-Oct-02 RMS Added impossible function catcher */ #include "s3_defs.h" @@ -199,6 +199,8 @@ int32 lpt (int32 op, int32 m, int32 n, int32 data) default: break; } + printf (">>LPT non-existent function %d\n", op); + return SCPE_OK; } @@ -210,7 +212,7 @@ int32 lpt (int32 op, int32 m, int32 n, int32 data) t_stat write_line (int32 ilnt, int32 mod) { -int32 i, t, lc, sup; +int32 i, t, lc; static char lbuf[LPT_WIDTH + 1]; /* + null */ if ((lpt_unit.flags & UNIT_ATT) == 0) @@ -221,13 +223,13 @@ lc = LPDAR; /* clear error */ for (i = 0; i < LPT_WIDTH; i++) { /* convert print buf */ t = M[lc]; lbuf[i] = ebcdic_to_ascii[t & 0xff]; - M[lc] = 0x40; /* HJS MOD */ + M[lc] = 0x40; /* HJS MOD */ lc++; } for (i = LPT_WIDTH - 1; (i >= 0) && (lbuf[i] == ' '); i--) lbuf[i] = 0; fputs (lbuf, lpt_unit.fileref); /* write line */ if (lines) space (lines, lflag); /* cc action? do it */ -else if (sup == 0) space (1, FALSE); /* default? 1 line */ +else if (mod == 0) space (1, FALSE); /* default? 1 line */ else { fputc ('\r', lpt_unit.fileref); /* sup -> overprint */ lpt_unit.pos = ftell (lpt_unit.fileref); } /* update position */ lines = lflag = 0; /* clear cc action */ diff --git a/S3/s3_pkb.c b/S3/s3_pkb.c index 9f4c557e..7f2fa686 100644 --- a/S3/s3_pkb.c +++ b/S3/s3_pkb.c @@ -1,6 +1,6 @@ /* s3_pkb.c: System/3 5471 console terminal simulator - Copyright (c) 2001, Charles E Owen + Copyright (c) 2001, Charles E. Owen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), @@ -19,7 +19,13 @@ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + Except as contained in this notice, the name of Charles E. Owen shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Charles E. Owen. + pkb 5471 printer/keyboard + + 08-Oct-02 RMS Added impossible function catcher */ #include "s3_defs.h" @@ -223,6 +229,8 @@ int32 pkb (int32 op, int32 m, int32 n, int32 data) default: break; } + printf (">>PKB non-existent function %d\n", op); + return SCPE_OK; } /* Unit service */ diff --git a/S3/s3_sys.c b/S3/s3_sys.c index 82b910f1..0d2cc73e 100644 --- a/S3/s3_sys.c +++ b/S3/s3_sys.c @@ -1,15 +1,32 @@ /* ibms3_sys.c: IBM System/3 system interface - (C) Copyright 2001 by Charles E. Owen - Commercial use prohibited + Copyright (c) 2001, Charles E. Owen + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Charles E. Owen shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Charles E. Owen. */ - #include - #include "s3_defs.h" - extern DEVICE cpu_dev; extern DEVICE pkb_dev; extern DEVICE cdr_dev; @@ -26,6 +43,7 @@ extern unsigned char M[]; extern int32 saved_PC, IAR[]; extern char ebcdic_to_ascii[256]; char *parse_addr(char *cptr, char *gbuf, int32 *addr, int32 *addrtype); + int32 printf_sym (FILE *of, char *strg, int32 addr, unsigned int32 *val, UNIT *uptr, int32 sw); diff --git a/VAX/vax_cpu.c b/VAX/vax_cpu.c index b4a6d9df..7c7092bd 100644 --- a/VAX/vax_cpu.c +++ b/VAX/vax_cpu.c @@ -25,6 +25,7 @@ cpu CVAX central processor + 29-Sep-02 RMS Revised to build dib_tab dynamically 14-Jul-02 RMS Added halt to console, infinite loop detection (from Mark Pizzolato) 02-May-02 RMS Fixed bug in indexed autoincrement register logging @@ -125,11 +126,10 @@ 2. Interrupt requests are maintained in the int_req array, one word per interrupt level, one bit per device. - 3. Adding I/O devices. This requires modifications to three modules: + 3. Adding I/O devices. These modules must be modified: - vax_defs.h add interrupt request definitions - vax_mm.c add I/O page linkages - vax_sys.c add to sim_devices + vax_defs.h add device address and interrupt definitions + vax_sys.c add sim_devices table entry */ /* Definitions */ @@ -231,6 +231,7 @@ extern int32 sim_int_char; extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ extern UNIT clk_unit; +extern t_stat build_dib_tab (void); extern UNIT rom_unit, nvr_unit; extern int32 op_ashq (int32 *opnd, int32 *rh, int32 *flg); extern int32 op_emul (int32 mpy, int32 mpc, int32 *rh); @@ -300,8 +301,10 @@ extern int32 get_vector (int32 lvl); extern void set_map_reg (void); extern void rom_wr (int32 pa, int32 val, int32 lnt); extern uint16 drom[NUM_INST][MAX_SPEC + 1]; +extern t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc); + t_stat cpu_reset (DEVICE *dptr); -t_stat cpu_boot (int32 unitno); +t_stat cpu_boot (int32 unitno, DEVICE *dptr); t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); @@ -376,6 +379,8 @@ MTAB cpu_mod[] = { { UNIT_MSIZE, (1u << 26), NULL, "64M", &cpu_set_size }, { UNIT_CONH, 0, "HALT to SIMH", "SIMHALT", NULL }, { UNIT_CONH, UNIT_CONH, "HALT to console", "CONHALT", NULL }, + { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "IOSPACE", NULL, + NULL, &show_iospace }, { MTAB_XTD|MTAB_VDV, 0, NULL, "VIRTUAL", &cpu_show_virt }, { 0 } }; @@ -383,14 +388,17 @@ DEVICE cpu_dev = { "CPU", &cpu_unit, cpu_reg, cpu_mod, 1, 16, 32, 1, 16, 8, &cpu_ex, &cpu_dep, &cpu_reset, - &cpu_boot, NULL, NULL }; + &cpu_boot, NULL, NULL, + NULL, 0 }; t_stat sim_instr (void) { volatile int32 opc, cc; /* used by setjmp */ int32 acc; /* set by setjmp */ int abortval; +t_stat r; +if ((r = build_dib_tab ()) != SCPE_OK) return r; /* build, chk dib_tab */ cc = PSL & CC_MASK; /* split PSL */ PSL = PSL & ~CC_MASK; in_ie = 0; /* not in exc */ @@ -403,7 +411,7 @@ sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init clock */ abortval = setjmp (save_env); /* set abort hdlr */ if (abortval > 0) { /* sim stop? */ PSL = PSL | cc; /* put PSL together */ - pcq_r -> qptr = pcq_p; /* update pc q ptr */ + pcq_r->qptr = pcq_p; /* update pc q ptr */ return abortval; } /* return to SCP */ else if (abortval < 0) { /* mm or rsrv or int */ int32 i, temp, st1, st2, hsir; @@ -2237,7 +2245,7 @@ mapen = 0; if (M == NULL) M = calloc (MEMSIZE >> 2, sizeof (int32)); if (M == NULL) return SCPE_MEM; pcq_r = find_reg ("PCQ", NULL, dptr); -if (pcq_r) pcq_r -> qptr = 0; +if (pcq_r) pcq_r->qptr = 0; else return SCPE_IERR; sim_brk_types = sim_brk_dflt = SWMASK ('E'); return SCPE_OK; @@ -2245,12 +2253,16 @@ return SCPE_OK; /* Bootstrap */ -t_stat cpu_boot (int32 unitno) +t_stat cpu_boot (int32 unitno, DEVICE *dptr) { extern int32 clk_csr; extern t_stat qba_powerup (void); extern t_stat sysd_powerup (void); extern t_stat todr_powerup (void); +extern uint32 *rom; +extern t_stat load_cmd (int32 flag, char *cptr); +extern FILE *sim_log; +t_stat r; qba_powerup (); sysd_powerup (); @@ -2259,6 +2271,13 @@ PC = ROMBASE; PSL = PSL_IS | PSL_IPL1F; conpc = 0; conpsl = PSL_IS | PSL_IPL1F | CON_PWRUP; +if (rom == NULL) return SCPE_IERR; +if (*rom == 0) { /* no boot? */ + printf ("Loading boot code from ka655.bin\n"); + if (sim_log) fprintf (sim_log, + "Loading boot code from ka655.bin\n"); + r = load_cmd (0, "-R ka655.bin"); + if (r != SCPE_OK) return r; } return SCPE_OK; } diff --git a/VAX/vax_cpu1.c b/VAX/vax_cpu1.c index da1ad948..cde3efed 100644 --- a/VAX/vax_cpu1.c +++ b/VAX/vax_cpu1.c @@ -174,7 +174,7 @@ int32 pos = opnd[0]; int32 size = opnd[1]; int32 rn = opnd[2]; uint32 wd = opnd[3]; -int32 ba, wd1; +int32 ba, wd1 = 0; if (size == 0) return 0; /* size 0? field = 0 */ if (size > 32) RSVD_OPND_FAULT; /* size > 32? fault */ diff --git a/VAX/vax_defs.h b/VAX/vax_defs.h index 8e173134..ef5d5206 100644 --- a/VAX/vax_defs.h +++ b/VAX/vax_defs.h @@ -46,6 +46,7 @@ #define STOP_RQ 9 /* fatal RQ err */ #define STOP_LOOP 10 /* infinite loop */ #define STOP_UNKABO 11 /* unknown abort */ +#define STOP_SANITY 12 /* sanity timer exp */ #define ABORT_INTR -1 /* interrupt */ #define ABORT_MCHK (-SCB_MCHK) /* machine check */ #define ABORT_RESIN (-SCB_RESIN) /* rsvd instruction */ @@ -65,9 +66,10 @@ /* Address space */ +#define VAMASK 0xFFFFFFFF /* virt addr mask */ #define PAWIDTH 30 /* phys addr width */ #define PASIZE (1 << PAWIDTH) /* phys addr size */ -#define PAMASK (PASIZE - 1) /* phys mem mask */ +#define PAMASK (PASIZE - 1) /* phys addr mask */ #define IOPAGE (1 << (PAWIDTH - 1)) /* start of I/O page */ /* Architectural constants */ @@ -430,9 +432,10 @@ enum opcodes { #define SXTB(x) (((x) & BSIGN)? ((x) | ~BMASK): ((x) & BMASK)) #define SXTW(x) (((x) & WSIGN)? ((x) | ~WMASK): ((x) & WMASK)) #define SXTBW(x) (((x) & BSIGN)? ((x) | (WMASK - BMASK)): ((x) & BMASK)) +#define SXTL(x) (((x) & LSIGN)? ((x) | ~LMASK): ((x) & LMASK)) #define INTOV if (PSL & PSW_IV) SET_TRAP (TRAP_INTOV) #define V_INTOV cc = cc | CC_V; INTOV -#define NEG(x) (-((int32) (x))) +#define NEG(x) ((~(x) + 1) & LMASK) /* Istream access */ diff --git a/VAX/vax_doc.txt b/VAX/vax_doc.txt index 7d6500b5..6553fb2c 100644 --- a/VAX/vax_doc.txt +++ b/VAX/vax_doc.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik Subj: VAX Simulator Usage -Date: 15-Jun-2002 +Date: 15-Nov-2002 COPYRIGHT NOTICE @@ -39,15 +39,16 @@ This memorandum documents the VAX simulator. To compile the VAX, you must define USE_INT64 as part of the compilation command line. -sim/ sim_defs.h +sim/ dec_dz.h + dec_pt.h + sim_defs.h + sim_ether.h + sim_rev.h sim_sock.h sim_tmxr.h - dec_dz.h - dec_mscp.h - dec_uqssp.h scp.c scp_tty.c - sim_rev.c + sim_ether.c sim_sock.c sim_tmxr.c @@ -61,11 +62,17 @@ sim/vax/ vax_defs.h vax_stddev.c vax_sys.c -sim/pdp11/ pdp11_dz.c +sim/pdp11/ pdp11_mscp.h + pdp11_uqssp.h + pdp11_xq.h + pdp11_dz.c pdp11_lp.c + pdp11_pt.c pdp11_rl.c pdp11_rq.c + pdp11_tq.c pdp11_ts.c + pdp11_xp.c 2. VAX Features @@ -87,11 +94,15 @@ CLK real-time clock DZ DZV11 8-line terminal multiplexor (up to 4) RL RLV12/RL01(2) cartridge disk controller with four drives RQ RQDX3 MSCP controller with four drives +RQB second RQDX3 MSCP controller with four drives +RQC third RQDX3 MSCP controller with four drives +RQD fourth RQDX3 MSCP controller with four drives TS TSV11/TSV05 magnetic tape controller with one drive +TQ TQK50 TMSCP magnetic tape controller with four drives +XQ DELQA/DEQNA Ethernet controller -The PTR, PTP, LPT, DZ, RL, and TS devices can be set DISABLED. In addition, -most devices support the SET ADDRESS command, which allows the I/O page -address of the device to be changed. +The PTR, PTP, LPT, DZ, RL, RQ, RQB, RQC, RQD, TS, TQ, and XQ devices can +be set DISABLED. RQB, RQC, and RQD are disabled by default. The VAX simulator implements several unique stop conditions: @@ -119,10 +130,13 @@ HALT instruction. SET CPU 64M set memory size = 64MB SET CPU SIMHALT kernel HALT returns to simulator SET CPU CONHALT kernel HALT returns to boot ROM console + SHOW CPU IOSPACE show I/O space address map If memory size is being reduced, and the memory being truncated contains non-zero data, the simulator asks for confirmation. Data in the truncated -portion of memory is lost. Initial memory size is 16MB. +portion of memory is lost. Initial memory size is 16MB. If the simulator +is running VMS, the operating system will not recognize memory size changes +until AUTOGEN is run. Memory can be loaded with a binary byte stream using the LOAD command. The LOAD command recognizes one switch: @@ -131,10 +145,12 @@ The LOAD command recognizes one switch: The CPU supports the BOOT command and is the only VAX device to do so. -These switches are recognized when examining or depositing in CPU memory: +These switches are recognized when examining or depositing in CPU memory +(or any other byte oriented device): -b examine/deposit bytes -w examine/deposit words + -l examine/deposit longwords -d data radix is decimal -o data radix is octal -h data radix is hexadecimal @@ -200,10 +216,10 @@ using the LOAD -r command: The NVR consists of a single unit, representing 1KB of battery-backed up memory. When the simulator starts, NVR is cleared to 0, and the SSC -battery-low indicator is set. The NVR can be loaded with a binary byte -stream using the LOAD -n command: - - LOAD -n NVR.BIN -- load NVR image NVR.BIN +battery-low indicator is set. Normally, NVR is saved and restored like +other memory in the system. Alternately, NVR can be attached to a file. +This allows its contents to be saved and restored independently of +other memories, so that NVR state can be preserved across simulator runs. Successfully loading an NVR image clears the SSC battery-low indicator. @@ -253,9 +269,43 @@ The QBA represents the CQBIC Qbus adapter chip. The QBA registers are: IPL15 32 IPL 15 interrupt flags IPL14 32 IPL 14 interrupt flags -2.2 Programmed I/O Devices +2.2 I/O Device Addressing -2.2.1 PC11 Paper Tape Reader (PTR) +Qbus I/O space is not large enough to allow all possible devices to be +configured simultaneously at fixed addresses. Instead, many devices have +floating addresses; that is, the assigned device address depends on the +presense of other devices in the configuration: + + DZ11 all instances have floating addresses + RL11 first instance has fixed address, rest floating + MSCP disk first instance has fixed address, rest floating + TMSCP tape first instance has fixed address, rest floating + +To maintain addressing consistency as the configuration changes, the +simulator implements DEC's standard I/O address and vector autoconfiguration +algorithms for devices DZ, RL, RQ, and TQ. This allows the user to +enable or disable devices without needing to manage I/O addresses +and vectors. + +In addition to autoconfiguration, most devices support the SET ADDRESS +command, which allows the I/O page address of the device to be changed, +and the SET VECTOR command, which allows the vector of the device to be +changed. Explicitly setting the I/O address of a device which normally +uses autoconfiguration DISABLES autoconfiguration for that device. As +a consequence, the user may have to manually configure all other +autoconfigured devices, because the autoconfiguration algorithm no +longer recognizes the explicitly configured device. A device can be +reset to autoconfigure with the SET AUTOCONFIGURE command. + +The current I/O map can be displayed with the SHOW CPU IOSPACE command. +Address that have set by autoconfiguration are marked with an asterisk (*). + +All devices support the SHOW ADDRESS and SHOW VECTOR commands, which display +the device address and vector, respectively. + +2.3 Programmed I/O Devices + +2.3.1 PC11 Paper Tape Reader (PTR) The paper tape reader (PTR) reads data from a disk file. The POS register specifies the number of the next data item to be read. Thus, @@ -288,7 +338,7 @@ Error handling is as follows: OS I/O error x report error and stop -2.2.2 PC11 Paper Tape Punch (PTP) +2.3.2 PC11 Paper Tape Punch (PTP) The paper tape punch (PTP) writes data to a disk file. The POS register specifies the number of the next data item to be written. @@ -317,7 +367,12 @@ Error handling is as follows: OS I/O error x report error and stop -2.2.3 Terminal Input (TTI) +2.3.3 Terminal Input (TTI) + +The terminal interfaces (TTI, TTO) can be set to one of two modes: +7B or 8B. In 7B mode, input and output characters are masked to 7 +bits. In 8B mode, characters are not modified. Changing the mode +of either interface changes both. The default mode is 8B. The terminal input (TTI) polls the console keyboard for input. It implements these registers: @@ -333,7 +388,7 @@ implements these registers: POS 32 number of characters input TIME 24 keyboard polling interval -2.2.4 Terminal Output (TTO) +2.3.4 Terminal Output (TTO) The terminal output (TTO) writes to the simulator console window. It implements these registers: @@ -349,7 +404,7 @@ implements these registers: POS 32 number of characters input TIME 24 time from I/O initiation to interrupt -2.2.5 Line Printer (LPT) +2.3.5 Line Printer (LPT) The line printer (LPT) writes data to a disk file. The POS register specifies the number of the next data item to be written. Thus, @@ -378,7 +433,7 @@ Error handling is as follows: OS I/O error x report error and stop -2.2.6 Real-Time Clock (CLK) +2.3.6 Real-Time Clock (CLK) The clock (CLK) implements these registers: @@ -395,14 +450,21 @@ The clock (CLK) implements these registers: The real-time clock autocalibrates; the clock interval is adjusted up or down so that the clock tracks actual elapsed time. -2.2.7 DZ11 Terminal Multiplexor (DZ) +2.3.7 DZ11 Terminal Multiplexor (DZ) The DZ11 is an 8-line terminal multiplexor. Up to 4 DZ11's (32 lines) are supported. The number of lines can be changed with the command SET DZ LINES=n set line count to n -The line count must be a multiple of 8, with a maximum of 32. +The line count must be a multiple of 4, with a maximum of 16. + +The DZ11 supports 8-bit input and output of characters. 8-bit output +may be incompatible with certain operating systems. The command + + SET DZ 7B + +forces output characters to be masked to 7 bits. The terminal lines perform input and output through Telnet sessions connected to a user-specified port. The ATTACH command specifies @@ -444,7 +506,7 @@ The DZ11 implements these registers: The DZ11 does not support save and restore. All open connections are lost when the simulator shuts down or the DZ is detached. -2.3 RLV12/RL01,RL02 Cartridge Disk (RL) +2.4 RLV12/RL01,RL02 Cartridge Disk (RL) RLV12 options include the ability to set units write enabled or write locked, to set the drive size to RL01, RL02, or autosize, and to write a DEC standard @@ -489,11 +551,13 @@ Error handling is as follows: OS I/O error x report error and stop -2.4 RQDX3 MSCP Disk Controller (RQ) +2.5 RQDX3 MSCP Disk Controllers (RQ, RQB, RQC, RQD) -The RQ controller simulates the RQDX3 MSCP disk controller. RQ options -include the ability to set units write enabled or write locked, and to -set the drive type to one of eleven disk types: +The simulator implements four MSCP disk controllers, RQ, RQB, RQC, RQD. +Initially, RQB, RQC, and RQD are disabled. Each RQ controller simulates +an RQDX3 MSCP disk controller. RQ options include the ability to set +units write enabled or write locked, and to set the drive type to one +of eleven disk types: SET RQn LOCKED set unit n write locked SET RQn WRITEENABLED set unit n write enabled @@ -512,7 +576,7 @@ set the drive type to one of eleven disk types: The type options can be used only when a unit is not attached to a file. Units can also be set ONLINE or OFFLINE. -The RQ controller implements the following special SHOW commands: +Each RQ controller implements the following special SHOW commands: SHOW RQ RINGS show command and response rings SHOW RQ FREEQ show packet free queue @@ -521,7 +585,7 @@ The RQ controller implements the following special SHOW commands: SHOW RQ ALL show all ring and queue state SHOW RQn UNITQ show unit queues for unit n -The RQ controller implements these registers: +Each RQ controller implements these registers: name size comments @@ -563,7 +627,7 @@ Error handling is as follows: OS I/O error report error and stop -2.5 TSV11/TSV05 Magnetic Tape (TS) +2.6 TSV11/TSV05 Magnetic Tape (TS) TS options include the ability to make the unit write enabled or write locked. @@ -611,7 +675,137 @@ Error handling is as follows: OS I/O error fatal tape error -2.6 Symbolic Display and Input +2.7 TQK50 TMSCP Disk Controller (TQ) + +The TQ controller simulates the TQK50 TMSCP disk controller. TQ options +include the ability to set units write enabled or write locked: + + SET TQn LOCKED set unit n write locked + SET TQn WRITEENABLED set unit n write enabled + +The TQ controller implements the following special SHOW commands: + + SHOW TQ RINGS show command and response rings + SHOW TQ FREEQ show packet free queue + SHOW TQ RESPQ show packet response queue + SHOW TQ UNITQ show unit queues + SHOW TQ ALL show all ring and queue state + SHOW TQn UNITQ show unit queues for unit n + +The TQ controller implements these registers: + + name size comments + + SA 16 status/address register + S1DAT 16 step 1 init host data + CQBA 22 command queue base address + CQLNT 8 command queue length + CQIDX 8 command queue index + RQBA 22 request queue base address + RQLNT 8 request queue length + RQIDX 8 request queue index + FREE 5 head of free packet list + RESP 5 head of response packet list + PBSY 5 number of busy packets + CFLGS 16 controller flags + CSTA 4 controller state + PERR 9 port error number + CRED 5 host credits + HAT 17 host available timer + HTMO 17 host timeout value + CPKT[0:3] 5 current packet, units 0-3 + PKTQ[0:3] 5 packet queue, units 0-3 + UFLG[0:3] 16 unit flags, units 0-3 + POS[0:3] 32 tape position, units 0-3 + OBJP[0:3] 32 object position, units 0-3 + INT 1 interrupt request + ITIME 1 response time for initialization steps + (except for step 4) + QTIME 24 response time for 'immediate' packets + XTIME 24 response time for data transfers + PKTS[33*32] 16 packet buffers, 33W each, + 32 entries + +Error handling is as follows: + + error processed as + + not attached tape not ready + + end of file end of medium + + OS I/O error report error and stop + +2.8 DELQA/DEQNA Ethernet Controller (XQ) + +XQ simulates the DELQA/DEQNA 10Mbps Ethernet controller. Options allow +control of the MAC address, the controller mode, and the sanity timer. + + SET XQ MAC= ex. 08-00-2B-AA-BB-CC + SHOW XQ MAC + +These commands are used to change or display the MAC address. +is a valid ethernet MAC, delimited by dashes or periods. The controller +defaults to 08-00-2B-AA-BB-CC, which should be sufficient if there is +only one SIMH controller on your LAN. Two cards with the same MAC address +will see each other's packets, resulting in a serious mess. + + SET XQ TYPE={DEQNA|[DELQA]} + SHOW XQ TYPE + +These commands are used to change or display the controller mode. DELQA +mode is better and faster but may not be usable by older or non-DEC OS's. +Also, be aware that DEQNA mode is not supported by many modern OS's. The +DEQNA-LOCK mode of the DELQA card is emulated by setting the the controller +to DEQNA - there is no need for a separate mode. DEQNA-LOCK mode behaves +exactly like a DEQNA, except for the operation of the VAR and MOP processing. + + SET XQ SANITY={ON|[OFF]} + SHOW XQ SANITY + +These commands change or display the INITIALIZATION sanity timer (DEQNA +jumper W3/DELQA switch S4). The INITIALIZATION sanity timer has a default +timeout of 4 minutes, and cannot be turned off, just reset. The normal +sanity timer can be set by operating system software regardless of the +state of this switch. Note that only the DEQNA (or the DELQA in DEQNA- +LOCK mode (=DEQNA)) supports the sanity timer - it is ignored by a DELQA +in Normal mode, which uses switch S4 for a different purpose. + +To access the network, the simulated Ethernet controller must be attached +to a real Ethernet interface: + + ATTACH XQ0 {ethX|} ex. eth0 or /dev/era0 + SHOW XQ ETH + +where X in 'ethX' is the number of the ethernet controller to attach, or +the real device name. The X number is system dependant. If you only have +one ethernet controller, the number will probably be 0. To find out what +your system thinks the ethernet numbers are, use the SHOW XQ ETH command. +The device list can be quite cryptic, depending on the host system, but +is probably better than guessing. If you do not attach the device, the +controller will behave as though the ethernet cable were unplugged. + +XQ has the following registers: + + name size comments + + SA0 16 station address word 0 + SA1 16 station address word 1 + SA2 16 station address word 2 + SA3 16 station address word 3 + SA4 16 station address word 4 + SA5 16 station address word 5 + CSR 16 control status register + VAR 16 vector address register + RBDL 32 receive buffer descriptor list + XBDL 32 trans(X)mit buffer descriptorlList + +One final note: because of it's asynchronous nature, the XQ controller is +not limited to the ~1.5Mbit/sec of the real DEQNA/DELQA controllers, +nor the 10Mbit/sec of a standard Ethernet. Attach it to a Fast Ethernet +(100 Mbit/sec) card, and "Feel the Power!" :-) + +2.9 Symbolic Display and Input The VAX simulator implements symbolic display and input. Display is controlled by command line switches: diff --git a/VAX/vax_fpa.c b/VAX/vax_fpa.c index d0709a3f..44560dd9 100644 --- a/VAX/vax_fpa.c +++ b/VAX/vax_fpa.c @@ -366,34 +366,34 @@ void vax_fadd (UFP *a, UFP *b, t_int64 mask) int32 ediff; UFP t; -if (a -> exp == 0) { /* s1 = 0? */ +if (a->exp == 0) { /* s1 = 0? */ *a = *b; return; } -if (b -> exp == 0) return; /* s2 = 0? */ -if (a -> exp < b -> exp) { /* s1 < s2? swap */ +if (b->exp == 0) return; /* s2 = 0? */ +if (a->exp < b->exp) { /* s1 < s2? swap */ t = *a; *a = *b; *b = t; } -ediff = a -> exp - b -> exp; /* exp diff */ -if (a -> sign ^ b -> sign) { /* eff sub? */ +ediff = a->exp - b->exp; /* exp diff */ +if (a->sign ^ b->sign) { /* eff sub? */ if (ediff) { /* exp diff? */ - b -> frac = (ediff > 63)? ONES: /* shift b */ - ((-((t_int64) b -> frac) >> ediff) | + b->frac = (ediff > 63)? ONES: /* shift b */ + ((-((t_int64) b->frac) >> ediff) | (ONES << (64 - ediff))); /* preserve sign */ - a -> frac = a -> frac + b -> frac; } /* add frac */ - else { if (a -> frac < b -> frac) { /* same, check magn */ - a -> frac = b -> frac - a -> frac; /* b > a */ - a -> sign = b -> sign; } - else a -> frac = a -> frac - b -> frac; } /* a >= b */ - a -> frac = a -> frac & ~mask; + a->frac = a->frac + b->frac; } /* add frac */ + else { if (a->frac < b->frac) { /* same, check magn */ + a->frac = b->frac - a->frac; /* b > a */ + a->sign = b->sign; } + else a->frac = a->frac - b->frac; } /* a >= b */ + a->frac = a->frac & ~mask; norm (a); } /* normalize */ -else { if (ediff >= 64) b -> frac = 0; - else b -> frac = b -> frac >> ediff; /* add, denorm */ - a -> frac = a -> frac + b -> frac; /* add frac */ - if (a -> frac < b -> frac) { /* chk for carry */ - a -> frac = UF_NM | (a -> frac >> 1); /* shift in carry */ - a -> exp = a -> exp + 1; } /* skip norm */ - a -> frac = a -> frac & ~mask; } +else { if (ediff >= 64) b->frac = 0; + else b->frac = b->frac >> ediff; /* add, denorm */ + a->frac = a->frac + b->frac; /* add frac */ + if (a->frac < b->frac) { /* chk for carry */ + a->frac = UF_NM | (a->frac >> 1); /* shift in carry */ + a->exp = a->exp + 1; } /* skip norm */ + a->frac = a->frac & ~mask; } return; } @@ -419,7 +419,7 @@ UFP a, b; unpackd (opnd[0], opnd[1], &a); unpackd (opnd[2], opnd[3], &b); -vax_fmul (&a, &b, 56, FD_BIAS, 0); /* do multiply */ +vax_fmul (&a, &b, 56, FD_BIAS, 0); /* do multiply */ return rpackfd (&a, rh); /* round and pack */ } @@ -441,17 +441,17 @@ void vax_fmul (UFP *a, UFP *b, int32 prec, int32 bias, t_int64 mask) { t_uint64 ah, bh, al, bl, rhi, rlo, rmid1, rmid2; -if ((a -> exp == 0) || (b -> exp == 0)) { /* zero argument? */ - a -> frac = a -> sign = a -> exp = 0; /* result is zero */ +if ((a->exp == 0) || (b->exp == 0)) { /* zero argument? */ + a->frac = a->sign = a->exp = 0; /* result is zero */ return; } -a -> sign = a -> sign ^ b -> sign; /* sign of result */ -a -> exp = a -> exp + b -> exp - bias; /* add exponents */ -ah = (a -> frac >> 32) & M32; /* split operands */ -bh = (b -> frac >> 32) & M32; /* into 32b chunks */ +a->sign = a->sign ^ b->sign; /* sign of result */ +a->exp = a->exp + b->exp - bias; /* add exponents */ +ah = (a->frac >> 32) & M32; /* split operands */ +bh = (b->frac >> 32) & M32; /* into 32b chunks */ rhi = ah * bh; /* high result */ if (prec > 32) { /* 64b needed? */ - al = a -> frac & M32; - bl = b -> frac & M32; + al = a->frac & M32; + bl = b->frac & M32; rmid1 = ah * bl; rmid2 = al * bh; rlo = al * bl; @@ -460,7 +460,7 @@ if (prec > 32) { /* 64b needed? */ if (rmid1 < rlo) rhi = rhi + 1; /* carry? incr hi */ rmid2 = rmid1 + (rmid2 << 32); /* add mid2 to to */ if (rmid2 < rmid1) rhi = rhi + 1; } /* carry? incr hi */ -a -> frac = rhi & ~mask; /* mask out */ +a->frac = rhi & ~mask; /* mask out */ norm (a); /* normalize */ return; } @@ -508,19 +508,19 @@ void vax_fdiv (UFP *a, UFP *b, int32 prec, int32 bias) int32 i; t_uint64 quo = 0; -if (a -> exp == 0) FLT_DZRO_FAULT; /* divr = 0? */ -if (b -> exp == 0) return; /* divd = 0? */ -b -> sign = b -> sign ^ a -> sign; /* result sign */ -b -> exp = b -> exp - a -> exp + bias + 1; /* unbiased exp */ -a -> frac = a -> frac >> 1; /* allow 1 bit left */ -b -> frac = b -> frac >> 1; -for (i = 0; (i < prec) && b -> frac; i++) { /* divide loop */ +if (a->exp == 0) FLT_DZRO_FAULT; /* divr = 0? */ +if (b->exp == 0) return; /* divd = 0? */ +b->sign = b->sign ^ a->sign; /* result sign */ +b->exp = b->exp - a->exp + bias + 1; /* unbiased exp */ +a->frac = a->frac >> 1; /* allow 1 bit left */ +b->frac = b->frac >> 1; +for (i = 0; (i < prec) && b->frac; i++) { /* divide loop */ quo = quo << 1; /* shift quo */ - if (b -> frac >= a -> frac) { /* div step ok? */ - b -> frac = b -> frac - a -> frac; /* subtract */ + if (b->frac >= a->frac) { /* div step ok? */ + b->frac = b->frac - a->frac; /* subtract */ quo = quo + 1; } /* quo bit = 1 */ - b -> frac = b -> frac << 1; } /* shift divd */ -b -> frac = quo << (UF_V_NM - i + 1); /* shift quo */ + b->frac = b->frac << 1; } /* shift divd */ +b->frac = quo << (UF_V_NM - i + 1); /* shift quo */ norm (b); /* normalize */ return; } @@ -572,13 +572,13 @@ return rpackg (&a, flo); /* return frac */ void vax_fmod (UFP *a, int32 bias, int32 *intgr, int32 *flg) { -if (a -> exp <= bias) *intgr = 0; /* 0 or <1? int = 0 */ -else if (a -> exp <= (bias + 64)) { /* in range? */ - *intgr = (int32) (a -> frac >> (64 - (a -> exp - bias))); - a -> frac = a -> frac << (a -> exp - bias); } +if (a->exp <= bias) *intgr = 0; /* 0 or <1? int = 0 */ +else if (a->exp <= (bias + 64)) { /* in range? */ + *intgr = (int32) (a->frac >> (64 - (a->exp - bias))); + a->frac = a->frac << (a->exp - bias); } else *intgr = 0; /* out of range */ -if (a -> sign) *intgr = -*intgr; /* -? comp int */ -if ((a -> exp >= (bias + 32)) || (((a -> sign) != 0) && (*intgr < 0))) +if (a->sign) *intgr = -*intgr; /* -? comp int */ +if ((a->exp >= (bias + 32)) || (((a->sign) != 0) && (*intgr < 0))) *flg = CC_V; /* test ovflo */ else *flg = 0; norm (a); /* normalize */ @@ -684,40 +684,40 @@ return; void unpackf (int32 hi, UFP *r) { -r -> sign = hi & FPSIGN; /* get sign */ -r -> exp = FD_GETEXP (hi); /* get exponent */ -if (r -> exp == 0) { /* exp = 0? */ - if (r -> sign) RSVD_OPND_FAULT; /* if -, rsvd op */ - r -> frac = 0; /* else 0 */ +r->sign = hi & FPSIGN; /* get sign */ +r->exp = FD_GETEXP (hi); /* get exponent */ +if (r->exp == 0) { /* exp = 0? */ + if (r->sign) RSVD_OPND_FAULT; /* if -, rsvd op */ + r->frac = 0; /* else 0 */ return; } hi = (((hi & FD_FRACW) | FD_HB) << 16) | ((hi >> 16) & 0xFFFF); -r -> frac = ((t_uint64) hi) << (32 + UF_V_FDLO); +r->frac = ((t_uint64) hi) << (32 + UF_V_FDLO); return; } void unpackd (int32 hi, int32 lo, UFP *r) { -r -> sign = hi & FPSIGN; /* get sign */ -r -> exp = FD_GETEXP (hi); /* get exponent */ -if (r -> exp == 0) { /* exp = 0? */ - if (r -> sign) RSVD_OPND_FAULT; /* if -, rsvd op */ - r -> frac = 0; /* else 0 */ +r->sign = hi & FPSIGN; /* get sign */ +r->exp = FD_GETEXP (hi); /* get exponent */ +if (r->exp == 0) { /* exp = 0? */ + if (r->sign) RSVD_OPND_FAULT; /* if -, rsvd op */ + r->frac = 0; /* else 0 */ return; } hi = (hi & FD_FRACL) | FD_HB; /* canonical form */ -r -> frac = UNSCRAM (hi, lo) << UF_V_FDLO; /* guard bits */ +r->frac = UNSCRAM (hi, lo) << UF_V_FDLO; /* guard bits */ return; } void unpackg (int32 hi, int32 lo, UFP *r) { -r -> sign = hi & FPSIGN; /* get sign */ -r -> exp = G_GETEXP (hi); /* get exponent */ -if (r -> exp == 0) { /* exp = 0? */ - if (r -> sign) RSVD_OPND_FAULT; /* if -, rsvd op */ - r -> frac = 0; /* else 0 */ +r->sign = hi & FPSIGN; /* get sign */ +r->exp = G_GETEXP (hi); /* get exponent */ +if (r->exp == 0) { /* exp = 0? */ + if (r->sign) RSVD_OPND_FAULT; /* if -, rsvd op */ + r->frac = 0; /* else 0 */ return; } hi = (hi & G_FRACL) | G_HB; /* canonical form */ -r -> frac = UNSCRAM (hi, lo) << UF_V_GLO; /* guard bits */ +r->frac = UNSCRAM (hi, lo) << UF_V_GLO; /* guard bits */ return; } @@ -729,45 +729,45 @@ static t_uint64 normmask[5] = { 0xffff000000000000, 0xffffffff00000000 }; static int32 normtab[6] = { 1, 2, 4, 8, 16, 32}; -if (r -> frac == 0) { /* if fraction = 0 */ - r -> sign = r -> exp = 0; /* result is 0 */ +if (r->frac == 0) { /* if fraction = 0 */ + r->sign = r->exp = 0; /* result is 0 */ return; } -while ((r -> frac & UF_NM) == 0) { /* normalized? */ +while ((r->frac & UF_NM) == 0) { /* normalized? */ for (i = 0; i < 5; i++) { /* find first 1 */ - if (r -> frac & normmask[i]) break; } - r -> frac = r -> frac << normtab[i]; /* shift frac */ - r -> exp = r -> exp - normtab[i]; } /* decr exp */ + if (r->frac & normmask[i]) break; } + r->frac = r->frac << normtab[i]; /* shift frac */ + r->exp = r->exp - normtab[i]; } /* decr exp */ return; } int32 rpackfd (UFP *r, int32 *rh) { if (rh) *rh = 0; /* assume 0 */ -if (r -> frac == 0) return 0; /* result 0? */ -r -> frac = r -> frac + (rh? UF_DRND: UF_FRND); /* round */ -if ((r -> frac & UF_NM) == 0) { /* carry out? */ - r -> frac = r -> frac >> 1; /* renormalize */ - r -> exp = r -> exp + 1; } -if (r -> exp > (int32) FD_M_EXP) FLT_OVFL_FAULT; /* ovflo? fault */ -if (r -> exp <= 0) { /* underflow? */ +if (r->frac == 0) return 0; /* result 0? */ +r->frac = r->frac + (rh? UF_DRND: UF_FRND); /* round */ +if ((r->frac & UF_NM) == 0) { /* carry out? */ + r->frac = r->frac >> 1; /* renormalize */ + r->exp = r->exp + 1; } +if (r->exp > (int32) FD_M_EXP) FLT_OVFL_FAULT; /* ovflo? fault */ +if (r->exp <= 0) { /* underflow? */ if (PSL & PSW_FU) FLT_UNFL_FAULT; /* fault if fu */ return 0; } /* else 0 */ -if (rh) *rh = UF_GETFDLO (r -> frac); /* get low */ -return r -> sign | (r -> exp << FD_V_EXP) | UF_GETFDHI (r -> frac); +if (rh) *rh = UF_GETFDLO (r->frac); /* get low */ +return r->sign | (r->exp << FD_V_EXP) | UF_GETFDHI (r->frac); } int32 rpackg (UFP *r, int32 *rh) { *rh = 0; /* assume 0 */ -if (r -> frac == 0) return 0; /* result 0? */ -r -> frac = r -> frac + UF_GRND; /* round */ -if ((r -> frac & UF_NM) == 0) { /* carry out? */ - r -> frac = r -> frac >> 1; /* renormalize */ - r -> exp = r -> exp + 1; } -if (r -> exp > (int32) G_M_EXP) FLT_OVFL_FAULT; /* ovflo? fault */ -if (r -> exp <= 0) { /* underflow? */ +if (r->frac == 0) return 0; /* result 0? */ +r->frac = r->frac + UF_GRND; /* round */ +if ((r->frac & UF_NM) == 0) { /* carry out? */ + r->frac = r->frac >> 1; /* renormalize */ + r->exp = r->exp + 1; } +if (r->exp > (int32) G_M_EXP) FLT_OVFL_FAULT; /* ovflo? fault */ +if (r->exp <= 0) { /* underflow? */ if (PSL & PSW_FU) FLT_UNFL_FAULT; /* fault if fu */ return 0; } /* else 0 */ -if (rh) *rh = UF_GETGLO (r -> frac); /* get low */ -return r -> sign | (r -> exp << G_V_EXP) | UF_GETGHI (r -> frac); +if (rh) *rh = UF_GETGLO (r->frac); /* get low */ +return r->sign | (r->exp << G_V_EXP) | UF_GETGHI (r->frac); } diff --git a/VAX/vax_io.c b/VAX/vax_io.c index 2d8fb725..7b56c5ae 100644 --- a/VAX/vax_io.c +++ b/VAX/vax_io.c @@ -24,6 +24,11 @@ in this Software without prior written authorization from Robert M Supnik. qba Qbus adapter + + 12-Oct-02 RMS Added autoconfigure support + Added SHOW IO space routine + 29-Sep-02 RMS Added dynamic table support + 07-Sep-02 RMS Added TMSCP and variable vector support */ #include "vax_defs.h" @@ -86,7 +91,6 @@ int32 cq_mear = 0; /* MEAR */ int32 cq_sear = 0; /* SEAR */ int32 cq_mbr = 0; /* MBR */ int32 cq_ipc = 0; /* IPC */ -static int_dummy = 0; /* keep save/restore working */ extern uint32 *M; extern UNIT cpu_unit; @@ -94,6 +98,7 @@ extern int32 PSL, SISR, trpirq, mem_err; extern int32 p1; extern int32 ssc_bto; extern jmp_buf save_env; +extern DEVICE *sim_devices[]; extern int32 ReadB (t_addr pa); extern int32 ReadW (t_addr pa); @@ -101,10 +106,6 @@ extern int32 ReadL (t_addr pa); extern int32 WriteB (t_addr pa, int32 val); extern int32 WriteW (t_addr pa, int32 val); extern int32 WriteL (t_addr pa, int32 val); -extern DIB pt_dib; -extern DIB lpt_dib, dz_dib; -extern DIB rl_dib, rq_dib; -extern DIB ts_dib; extern FILE *sim_log; t_stat dbl_rd (int32 *data, int32 addr, int32 access); @@ -112,13 +113,7 @@ t_stat dbl_wr (int32 data, int32 addr, int32 access); int32 eval_int (void); void cq_merr (int32 pa); void cq_serr (int32 pa); -t_bool dev_conflict (uint32 nba, DIB *curr); t_stat qba_reset (DEVICE *dptr); -extern int32 rq_inta (void); -extern int32 tmr0_inta (void); -extern int32 tmr1_inta (void); -extern dz_rxinta (void); -extern dz_txinta (void); /* Qbus adapter data structures @@ -127,7 +122,7 @@ extern dz_txinta (void); qba_reg QBA register list */ -DIB qba_dib = { 1, IOBA_DBL, IOLN_DBL, &dbl_rd, &dbl_wr }; +DIB qba_dib = { IOBA_DBL, IOLN_DBL, &dbl_rd, &dbl_wr, 0 }; UNIT qba_unit = { UDATA (NULL, 0, 0) }; @@ -138,7 +133,6 @@ REG qba_reg[] = { { HRDATA (SEAR, cq_sear, 20) }, { HRDATA (MBR, cq_mbr, 29) }, { HRDATA (IPC, cq_ipc, 16) }, - { HRDATA (IPL18, int_dummy, 32), REG_HRO }, { HRDATA (IPL17, int_req[3], 32), REG_RO }, { HRDATA (IPL16, int_req[2], 32), REG_RO }, { HRDATA (IPL15, int_req[1], 32), REG_RO }, @@ -149,48 +143,20 @@ DEVICE qba_dev = { "QBA", &qba_unit, qba_reg, NULL, 1, 0, 0, 0, 0, 0, NULL, NULL, &qba_reset, - NULL, NULL, NULL }; - -struct iolink { /* I/O page linkage */ - int32 low; /* low I/O addr */ - int32 high; /* high I/O addr */ - int32 *enb; /* enable flag */ - t_stat (*read)(); /* read routine */ - t_stat (*write)(); }; /* write routine */ + NULL, NULL, NULL, + &qba_dib, DEV_QBUS }; /* IO page addresses */ -DIB *dib_tab[] = { - &dz_dib, - &rq_dib, - &rl_dib, - &pt_dib, - &lpt_dib, - &ts_dib, - &qba_dib, - NULL }; +DIB *dib_tab[DIB_MAX]; /* DIB table */ /* Interrupt request to interrupt action map */ -int32 (*int_ack[IPL_HLVL][32])() = { /* int ack routines */ - { NULL, NULL, NULL, NULL, /* IPL 14 */ - NULL, NULL, NULL, &tmr0_inta, - &tmr1_inta }, - { &rq_inta, NULL, &dz_rxinta, &dz_txinta, /* IPL 15 */ - NULL, NULL }, - { NULL }, /* IPL 16 */ - { NULL } }; /* IPL 17 */ +int32 (*int_ack[IPL_HLVL][32])(); /* int ack routines */ /* Interrupt request to vector map */ -int32 int_vec[IPL_HLVL][32] = { /* int req to vector */ - { SCB_TTI, SCB_TTO, VEC_PTR, VEC_PTP, /* IPL 14 */ - VEC_LPT, SCB_CSI, SCB_CSO, 0, - 0 }, - { VEC_RQ, VEC_RL, VEC_DZRX, VEC_DZTX, /* IPL 15 */ - VEC_RP, VEC_TS }, - { SCB_INTTIM }, /* IPL 16 */ - { 0 } }; /* IPL 17 */ +int32 int_vec[IPL_HLVL][32]; /* int req to vector */ /* The KA65x handles errors in I/O space as follows @@ -204,9 +170,9 @@ int32 i, val; DIB *dibp; for (i = 0; dibp = dib_tab[i]; i++ ) { - if (dibp -> enb && (pa >= dibp -> ba) && - (pa < (dibp -> ba + dibp -> lnt))) { - dibp -> rd (&val, pa, READ); + if ((pa >= dibp->ba) && + (pa < (dibp->ba + dibp->lnt))) { + dibp->rd (&val, pa, READ); return val; } } cq_merr (pa); MACH_CHECK (MCHK_READ); @@ -219,9 +185,9 @@ int32 i; DIB *dibp; for (i = 0; dibp = dib_tab[i]; i++ ) { - if (dibp -> enb && (pa >= dibp -> ba) && - (pa < (dibp -> ba + dibp -> lnt))) { - dibp -> wr (val, pa, mode); + if ((pa >= dibp->ba) && + (pa < (dibp->ba + dibp->lnt))) { + dibp->wr (val, pa, mode); return; } } cq_merr (pa); mem_err = 1; @@ -292,7 +258,7 @@ for (i = IPL_SMAX; i > ipl; i--) { /* check swre int */ return 0; } -/* Return vector for highest priority hardware interrupt at IPL lvl*/ +/* Return vector for highest priority hardware interrupt at IPL lvl */ int32 get_vector (int32 lvl) { @@ -635,85 +601,296 @@ for (i = ma = 0; i < bc; i = i + 4, buf++) { /* by lw */ return 0; } -/* Change device number for a device */ +/* Change device address */ t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc) { +DEVICE *dptr; DIB *dibp; uint32 newba; t_stat r; if (cptr == NULL) return SCPE_ARG; -if ((val == 0) || (desc == NULL)) return SCPE_IERR; -dibp = (DIB *) desc; +if ((val == 0) || (uptr == NULL)) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); +if (dptr == NULL) return SCPE_IERR; +dibp = (DIB *) dptr->ctxt; +if (dibp == NULL) return SCPE_IERR; newba = (uint32) get_uint (cptr, 16, IOPAGEBASE+IOPAGEMASK, &r); /* get new */ -if ((r != SCPE_OK) || (newba == dibp -> ba)) return r; -if (newba <= IOPAGEBASE) return SCPE_ARG; /* must be > 0 */ -if (newba % ((uint32) val)) return SCPE_ARG; /* check modulus */ -if (dev_conflict (newba, dibp)) return SCPE_OK; -dibp -> ba = newba; /* store */ -return SCPE_OK; +if (r != SCPE_OK) return r; +if ((newba <= IOPAGEBASE) || /* must be > 0 */ + (newba % ((uint32) val))) return SCPE_ARG; /* check modulus */ +dibp->ba = newba; /* store */ +dptr->flags = dptr->flags & ~DEV_FLTA; /* not floating */ +return auto_config (0, 0); /* autoconfigure */ } /* Show device address */ t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc) { +DEVICE *dptr; DIB *dibp; -if (desc == NULL) return SCPE_IERR; -dibp = (DIB *) desc; -if (dibp -> ba <= IOPAGEBASE) return SCPE_IERR; -fprintf (st, "address=%08X", dibp -> ba); -if (dibp -> lnt > 1) - fprintf (st, "-%08X", dibp -> ba + dibp -> lnt - 1); +if (uptr == NULL) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); +if (dptr == NULL) return SCPE_IERR; +dibp = (DIB *) dptr->ctxt; +if ((dibp == NULL) || (dibp->ba <= IOPAGEBASE)) return SCPE_IERR; +fprintf (st, "address=%08X", dibp->ba); +if (dibp->lnt > 1) + fprintf (st, "-%08X", dibp->ba + dibp->lnt - 1); +if (dptr->flags & DEV_FLTA) fprintf (st, "*"); return SCPE_OK; } -/* Enable or disable a device */ +/* Set address floating */ -t_stat set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc) +t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc) { -int32 i; DEVICE *dptr; -DIB *dibp; -UNIT *up; -if (cptr != NULL) return SCPE_ARG; -if ((uptr == NULL) || (desc == NULL)) return SCPE_IERR; -dptr = find_dev_from_unit (uptr); /* find device */ +if (cptr == NULL) return SCPE_ARG; +if ((val == 0) || (uptr == NULL)) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); if (dptr == NULL) return SCPE_IERR; -dibp = (DIB *) desc; -if ((val ^ dibp -> enb) == 0) return SCPE_OK; /* enable chg? */ -if (val) { /* enable? */ - if (dev_conflict (dibp -> ba, dibp)) return SCPE_OK; } -else { /* disable */ - for (i = 0; i < dptr -> numunits; i++) { /* check units */ - up = (dptr -> units) + i; - if ((up -> flags & UNIT_ATT) || sim_is_active (up)) - return SCPE_NOFNC; } } -dibp -> enb = val; -if (dptr -> reset) return dptr -> reset (dptr); -else return SCPE_OK; +dptr->flags = dptr->flags | DEV_FLTA; /* floating */ +return auto_config (0, 0); /* autoconfigure */ } +/* Change device vector */ + +t_stat set_vec (UNIT *uptr, int32 arg, char *cptr, void *desc) +{ +DEVICE *dptr; +DIB *dibp; +uint32 newvec; +t_stat r; + +if (cptr == NULL) return SCPE_ARG; +if (uptr == NULL) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); +if (dptr == NULL) return SCPE_IERR; +dibp = (DIB *) dptr->ctxt; +if (dibp == NULL) return SCPE_IERR; +newvec = (uint32) get_uint (cptr, 16, VEC_Q + 01000, &r); +if ((r != SCPE_OK) || (newvec <= VEC_Q) || + ((newvec + (dibp->vnum * 4)) >= (VEC_Q + 01000)) || + (newvec & ((dibp->vnum > 1)? 07: 03))) return SCPE_ARG; +dibp->vec = newvec; +return SCPE_OK; +} + +/* Show device vector */ + +t_stat show_vec (FILE *st, UNIT *uptr, int32 arg, void *desc) +{ +DEVICE *dptr; +DIB *dibp; +uint32 vec, numvec; + +if (uptr == NULL) return SCPE_IERR; +dptr = find_dev_from_unit (uptr); +if (dptr == NULL) return SCPE_IERR; +dibp = (DIB *) dptr->ctxt; +if (dibp == NULL) return SCPE_IERR; +vec = dibp->vec; +if (arg) numvec = arg; +else numvec = dibp->vnum; +if (vec == 0) fprintf (st, "no vector"); +else { fprintf (st, "vector=%X", vec); + if (numvec > 1) fprintf (st, "-%X", vec + (4 * (numvec - 1))); } +return SCPE_OK; +} + /* Test for conflict in device addresses */ -t_bool dev_conflict (uint32 nba, DIB *curr) +t_bool dev_conflict (DIB *curr) { uint32 i, end; +DEVICE *dptr; DIB *dibp; -end = nba + curr -> lnt - 1; /* get end */ -for (i = 0; dibp = dib_tab[i]; i++) { /* loop thru dev */ - if (!dibp -> enb || (dibp == curr)) continue; /* skip disabled */ - if (((nba >= dibp -> ba) && - (nba < (dibp -> ba + dibp -> lnt))) || - ((end >= dibp -> ba) && - (end < (dibp -> ba + dibp -> lnt)))) { - printf ("Device address conflict at %08X\n", dibp -> ba); +end = curr->ba + curr->lnt - 1; /* get end */ +for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ + dibp = (DIB *) dptr->ctxt; /* get DIB */ + if ((dibp == NULL) || (dibp == curr) || + (dptr->flags & DEV_DIS)) continue; + if (((curr->ba >= dibp->ba) && /* overlap start? */ + (curr->ba < (dibp->ba + dibp->lnt))) || + ((end >= dibp->ba) && /* overlap end? */ + (end < (dibp->ba + dibp->lnt)))) { + printf ("Device %s address conflict at %08X\n", dptr->name, dibp->ba); if (sim_log) fprintf (sim_log, - "Device number conflict at %08X\n", dibp -> ba); + "Device %s address conflict at %08X\n", dptr->name, dibp->ba); return TRUE; } } return FALSE; } + +/* Build interrupt tables */ + +void build_int_vec (int32 vloc, int32 ivec, int32 (*iack)(void) ) +{ +int32 ilvl = vloc / 32; +int32 ibit = vloc % 32; + +if (iack != NULL) int_ack[ilvl][ibit] = iack; +else int_vec[ilvl][ibit] = ivec; +return; +} + +/* Build dib_tab from device list */ + +t_stat build_dib_tab (void) +{ +int32 i, j, k; +DEVICE *dptr; +DIB *dibp; + +for (i = 0; i < IPL_HLVL; i++) { /* clear int tables */ + for (j = 0; j < 32; j++) { + int_vec[i][j] = 0; + int_ack[i][j] = NULL; } } +for (i = j = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ + dibp = (DIB *) dptr->ctxt; /* get DIB */ + if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */ + if (dibp->vnum > VEC_DEVMAX) return SCPE_IERR; + for (k = 0; k < dibp->vnum; k++) /* loop thru vec */ + build_int_vec (dibp->vloc + k, /* add vector */ + dibp->vec + (k * 4), dibp->ack[k]); + if (dibp->lnt != 0) { /* I/O addresses? */ + dib_tab[j++] = dibp; /* add DIB to dib_tab */ + if (j >= DIB_MAX) return SCPE_IERR; } /* too many? */ + } /* end if enabled */ + } /* end for */ +dib_tab[j] = NULL; /* end with NULL */ +for (i = 0; (dibp = dib_tab[i]) != NULL; i++) { /* test built dib_tab */ + if (dev_conflict (dibp)) return SCPE_STOP; } /* for conflicts */ +return FALSE; +} + +/* Show dib_tab */ + +t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +int32 i, j, done = 0; +DEVICE *dptr; +DIB *dibt; + +build_dib_tab (); /* build table */ +while (done == 0) { /* sort ascending */ + done = 1; /* assume done */ + for (i = 0; dib_tab[i + 1] != NULL; i++) { /* check table */ + if (dib_tab[i]->ba > dib_tab[i + 1]->ba) { /* out of order? */ + dibt = dib_tab[i]; /* interchange */ + dib_tab[i] = dib_tab[i + 1]; + dib_tab[i + 1] = dibt; + done = 0; } } /* not done */ + } /* end while */ +for (i = 0; dib_tab[i] != NULL; i++) { /* print table */ + for (j = 0, dptr = NULL; sim_devices[j] != NULL; j++) { + if (((DIB*) sim_devices[j]->ctxt) == dib_tab[i]) { + dptr = sim_devices[j]; + break; } } + fprintf (st, "%08X - %08X%c\t%s\n", dib_tab[i]->ba, + dib_tab[i]->ba + dib_tab[i]->lnt - 1, + (dptr && (dptr->flags & DEV_FLTA))? '*': ' ', + dptr? dptr->name: "CPU"); + } +return SCPE_OK; +} + +/* Autoconfiguration */ + +#define AUTO_DYN 0001 +#define AUTO_VEC 0002 +#define AUTO_MAXC 4 +#define AUTO_CSRBASE 0010 +#define AUTO_VECBASE 0300 + +struct auto_con { + uint32 amod; + uint32 vmod; + uint32 flags; + uint32 num; + uint32 fix; + char *dnam[AUTO_MAXC]; }; + +struct auto_con auto_tab[AUTO_LNT + 1] = { + { 0x7, 0x7 }, /* DJ11 */ + { 0xf, 0x7 }, /* DH11 */ + { 0x7, 0x7 }, /* DQ11 */ + { 0x7, 0x7 }, /* DU11 */ + { 0x7, 0x7 }, /* DUP11 */ + { 0x7, 0x7 }, /* LK11A */ + { 0x7, 0x7 }, /* DMC11 */ + { 0x7, 0x7, AUTO_VEC, DZ_MUXES, 0, { "DZ" } }, + + { 0x7, 0x7 }, /* KMC11 */ + { 0x7, 0x7 }, /* LPP11 */ + { 0x7, 0x7 }, /* VMV21 */ + { 0xf, 0x7 }, /* VMV31 */ + { 0x7, 0x7 }, /* DWR70 */ + { 0x7, 0x3, AUTO_DYN|AUTO_VEC, 0, IOBA_RL, { "RL", "RLB" } }, + { 0xf, 0x7 }, /* LPA11K */ + { 0x7, 0x7 }, /* KW11C */ + + { 0x7, 0 }, /* reserved */ + { 0x7, 0x3 }, /* RX11/RX211 */ + { 0x7, 0x3 }, /* DR11W */ + { 0x7, 0x3 }, /* DR11B */ + { 0x7, 0x7 }, /* DMP11 */ + { 0x7, 0x7 }, /* DPV11 */ + { 0x7, 0x7 }, /* ISB11 */ + { 0xf, 0x7 }, /* DMV11 */ + + { 0x7, 0x3 }, /* DEUNA/DELUA */ + { 0x3, 0x3, AUTO_DYN|AUTO_VEC, 0, IOBA_RQ, { "RQ", "RQB", "RQC", "RQD" } }, + { 0x1f, 0x3 }, /* DMF32 */ + { 0xf, 0x7 }, /* KMS11 */ + { 0xf, 0x3 }, /* VS100 */ + { 0x3, 0x3, AUTO_DYN|AUTO_VEC, 0, IOBA_TQ, { "TQ", "TQB" } }, + { 0xf, 0x7 }, /* KMV11 */ + { 0xf, 0x7 }, /* DHU11/DHQ11 */ + + { 0x1f, 0x7 }, /* DMZ32 */ + { 0x1f, 0x7 }, /* CP132 */ + { 0 }, /* padding */ +}; + +t_stat auto_config (uint32 rank, uint32 nctrl) +{ +uint32 csr = IOPAGEBASE + AUTO_CSRBASE; +uint32 vec = VEC_Q + AUTO_VECBASE; +struct auto_con *autp; +DEVICE *dptr; +DIB *dibp; +int32 i, j, k; +extern DEVICE *find_dev (char *ptr); + +if (rank > AUTO_LNT) return SCPE_IERR; /* legal rank? */ +if (rank) auto_tab[rank - 1].num = nctrl; /* update num? */ +for (i = 0, autp = auto_tab; i < AUTO_LNT; i++) { /* loop thru table */ + for (j = k = 0; (j < AUTO_MAXC) && autp->dnam[j]; j++) { + dptr = find_dev (autp->dnam[j]); /* find ctrl */ + if ((dptr == NULL) || (dptr->flags & DEV_DIS) || + !(dptr->flags & DEV_FLTA)) continue; /* enabled, floating? */ + dibp = (DIB *) dptr->ctxt; /* get DIB */ + if ((k++ == 0) && autp->fix) /* 1st & fixed? */ + dibp->ba = autp->fix; /* gets fixed CSR */ + else { /* no, float */ + dibp->ba = csr; /* set CSR */ + csr = (csr + autp->amod + 1) & ~autp->amod; /* next CSR */ + if ((autp->flags & AUTO_DYN) == 0) /* static? */ + csr = csr + ((autp->num - 1) * (autp->amod + 1)); + if (autp->flags & AUTO_VEC) { /* vectors too? */ + dibp->vec = (vec + autp->vmod) & ~autp->vmod; + if (autp->flags & AUTO_DYN) vec = vec + autp->vmod + 1; + else vec = vec + (autp->num * (autp->vmod + 1)); } + } /* end else flt */ + } /* end for j */ + autp++; + csr = (csr + autp->amod + 1) & ~autp->amod; /* gap */ + } /* end for i */ +return SCPE_OK; +} diff --git a/VAX/vax_stddev.c b/VAX/vax_stddev.c index e4c976d1..e009835c 100644 --- a/VAX/vax_stddev.c +++ b/VAX/vax_stddev.c @@ -23,12 +23,12 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. - ptr paper tape reader - ptp paper tape punch tti terminal input tto terminal output - clk line frequency clock + clk 100Hz and TODR clock + 01-Nov-02 RMS Added 7B/8B capability to terminal + 12-Sep-02 RMS Removed paper tape, added variable vector support 30-May-02 RMS Widened POS to 32b 30-Apr-02 RMS Automatically set TODR to VMS-correct value during boot */ @@ -36,10 +36,6 @@ #include "vax_defs.h" #include -#define PTRCSR_IMP (CSR_ERR+CSR_BUSY+CSR_DONE+CSR_IE) /* paper tape reader */ -#define PTRCSR_RW (CSR_IE) -#define PTPCSR_IMP (CSR_ERR + CSR_DONE + CSR_IE) /* paper tape punch */ -#define PTPCSR_RW (CSR_IE) #define TTICSR_IMP (CSR_DONE + CSR_IE) /* terminal input */ #define TTICSR_RW (CSR_IE) #define TTOCSR_IMP (CSR_DONE + CSR_IE) /* terminal output */ @@ -49,11 +45,11 @@ #define CLK_DELAY 5000 /* 100 Hz */ #define TMXR_MULT 2 /* 50 Hz */ +#define UNIT_V_8B (UNIT_V_UF + 0) /* 8B mode */ +#define UNIT_8B (1 << UNIT_V_8B) + extern int32 int_req[IPL_HLVL]; -int32 ptr_csr = 0; /* control/status */ -int32 ptr_stopioe = 0; /* stop on error */ -int32 ptp_csr = 0; /* control/status */ -int32 ptp_stopioe = 0; /* stop on error */ + int32 tti_csr = 0; /* control/status */ int32 tto_csr = 0; /* control/status */ int32 clk_csr = 0; /* control/status */ @@ -63,100 +59,12 @@ int32 todr_blow = 1; /* TODR battery low */ int32 tmxr_poll = CLK_DELAY * TMXR_MULT; /* term mux poll */ int32 tmr_poll = CLK_DELAY; /* pgm timer poll */ -t_stat pt_rd (int32 *data, int32 PA, int32 access); -t_stat pt_wr (int32 data, int32 PA, int32 access); -t_stat ptr_svc (UNIT *uptr); -t_stat ptp_svc (UNIT *uptr); t_stat tti_svc (UNIT *uptr); t_stat tto_svc (UNIT *uptr); t_stat clk_svc (UNIT *uptr); -t_stat ptr_reset (DEVICE *dptr); -t_stat ptp_reset (DEVICE *dptr); t_stat tti_reset (DEVICE *dptr); t_stat tto_reset (DEVICE *dptr); t_stat clk_reset (DEVICE *dptr); -t_stat ptr_attach (UNIT *uptr, char *ptr); -t_stat ptr_detach (UNIT *uptr); -t_stat ptp_attach (UNIT *uptr, char *ptr); -t_stat ptp_detach (UNIT *uptr); - -/* PTR data structures - - ptr_dev PTR device descriptor - ptr_unit PTR unit descriptor - ptr_reg PTR register list -*/ - -DIB pt_dib = { 1, IOBA_PT, IOLN_PT, &pt_rd, &pt_wr }; - -UNIT ptr_unit = { - UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), - SERIAL_IN_WAIT }; - -REG ptr_reg[] = { - { HRDATA (BUF, ptr_unit.buf, 8) }, - { HRDATA (CSR, ptr_csr, 16) }, - { FLDATA (INT, int_req[IPL_PTR], INT_V_PTR) }, - { FLDATA (ERR, ptr_csr, CSR_V_ERR) }, - { FLDATA (BUSY, ptr_csr, CSR_V_BUSY) }, - { FLDATA (DONE, ptr_csr, CSR_V_DONE) }, - { FLDATA (IE, ptr_csr, CSR_V_IE) }, - { DRDATA (POS, ptr_unit.pos, 32), PV_LEFT }, - { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, - { FLDATA (STOP_IOE, ptr_stopioe, 0) }, - { NULL } }; - -MTAB ptr_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, - NULL, &show_addr, &pt_dib }, - { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", - &set_enbdis, NULL, &pt_dib }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", - &set_enbdis, NULL, &pt_dib }, - { 0 } }; - -DEVICE ptr_dev = { - "PTR", &ptr_unit, ptr_reg, ptr_mod, - 1, 10, 31, 1, 16, 8, - NULL, NULL, &ptr_reset, - NULL, &ptr_attach, &ptr_detach }; - -/* PTP data structures - - ptp_dev PTP device descriptor - ptp_unit PTP unit descriptor - ptp_reg PTP register list -*/ - -UNIT ptp_unit = { - UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; - -REG ptp_reg[] = { - { HRDATA (BUF, ptp_unit.buf, 8) }, - { HRDATA (CSR, ptp_csr, 16) }, - { FLDATA (INT, int_req[IPL_PTP], INT_V_PTP) }, - { FLDATA (ERR, ptp_csr, CSR_V_ERR) }, - { FLDATA (DONE, ptp_csr, CSR_V_DONE) }, - { FLDATA (IE, ptp_csr, CSR_V_IE) }, - { DRDATA (POS, ptp_unit.pos, 32), PV_LEFT }, - { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, - { FLDATA (STOP_IOE, ptp_stopioe, 0) }, - { NULL } }; - -MTAB ptp_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, - NULL, &show_addr, &pt_dib }, - { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", - &set_enbdis, NULL, &pt_dib }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", - &set_enbdis, NULL, &pt_dib }, - { 0 } }; - -DEVICE ptp_dev = { - "PTP", &ptp_unit, ptp_reg, ptp_mod, - 1, 10, 31, 1, 16, 8, - NULL, NULL, &ptp_reset, - NULL, &ptp_attach, &ptp_detach }; /* TTI data structures @@ -165,7 +73,9 @@ DEVICE ptp_dev = { tti_reg TTI register list */ -UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT }; +DIB tti_dib = { 0, 0, NULL, NULL, 1, IVCL (TTI), SCB_TTI, { NULL } }; + +UNIT tti_unit = { UDATA (&tti_svc, UNIT_8B, 0), KBD_POLL_WAIT }; REG tti_reg[] = { { HRDATA (BUF, tti_unit.buf, 8) }, @@ -177,11 +87,18 @@ REG tti_reg[] = { { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, { NULL } }; +MTAB tti_mod[] = { + { UNIT_8B, UNIT_8B, "8b", "8B", NULL }, + { UNIT_8B, 0 , "7b", "7B", NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, NULL, &show_vec }, + { 0 } }; + DEVICE tti_dev = { - "TTI", &tti_unit, tti_reg, NULL, + "TTI", &tti_unit, tti_reg, tti_mod, 1, 10, 31, 1, 16, 8, NULL, NULL, &tti_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &tti_dib, 0 }; /* TTO data structures @@ -190,7 +107,9 @@ DEVICE tti_dev = { tto_reg TTO register list */ -UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT }; +DIB tto_dib = { 0, 0, NULL, NULL, 1, IVCL (TTO), SCB_TTO, { NULL } }; + +UNIT tto_unit = { UDATA (&tto_svc, UNIT_8B, 0), SERIAL_OUT_WAIT }; REG tto_reg[] = { { HRDATA (BUF, tto_unit.buf, 8) }, @@ -202,11 +121,18 @@ REG tto_reg[] = { { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT }, { NULL } }; +MTAB tto_mod[] = { + { UNIT_8B, UNIT_8B, "8b", "8B", NULL }, + { UNIT_8B, 0 , "7b", "7B", NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, NULL, &show_vec }, + { 0 } }; + DEVICE tto_dev = { - "TTO", &tto_unit, tto_reg, NULL, + "TTO", &tto_unit, tto_reg, tto_mod, 1, 10, 31, 1, 16, 8, NULL, NULL, &tto_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &tto_dib, 0 }; /* CLK data structures @@ -215,6 +141,8 @@ DEVICE tto_dev = { clk_reg CLK register list */ +DIB clk_dib = { 0, 0, NULL, NULL, 1, IVCL (CLK), SCB_INTTIM, { NULL } }; + UNIT clk_unit = { UDATA (&clk_svc, 0, 0), CLK_DELAY }; REG clk_reg[] = { @@ -227,78 +155,16 @@ REG clk_reg[] = { { DRDATA (TPS, clk_tps, 8), REG_NZ + PV_LEFT }, { NULL } }; +MTAB clk_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, NULL, &show_vec }, + { 0 } }; + DEVICE clk_dev = { - "CLK", &clk_unit, clk_reg, NULL, + "CLK", &clk_unit, clk_reg, clk_mod, 1, 0, 0, 0, 0, 0, NULL, NULL, &clk_reset, - NULL, NULL, NULL }; - -/* Paper tape I/O dispatch routine, I/O addresses 17777550-17777577 - - 17777550 ptr CSR - 17777552 ptr buffer - 17777554 ptp CSR - 17777556 ptp buffer - - Note: Word access routines filter out odd addresses. Thus, - an odd address implies an (odd) byte access. -*/ - -t_stat pt_rd (int32 *data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 03) { /* decode PA<2:1> */ -case 00: /* ptr csr */ - *data = ptr_csr & PTRCSR_IMP; - break; -case 01: /* ptr buf */ - ptr_csr = ptr_csr & ~CSR_DONE; - CLR_INT (PTR); - *data = ptr_unit.buf & 0377; - break; -case 02: /* ptp csr */ - *data = ptp_csr & PTPCSR_IMP; - break; -case 03: /* ptp buf */ - *data = ptp_unit.buf; - break; } -return SCPE_OK; -} - -t_stat pt_wr (int32 data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 03) { /* decode PA<2:1> */ -case 00: /* ptr csr */ - if (PA & 1) return SCPE_OK; - if ((data & CSR_IE) == 0) CLR_INT (PTR); - else if (((ptr_csr & CSR_IE) == 0) && (ptr_csr & (CSR_ERR | CSR_DONE))) - SET_INT (PTR); - if (data & CSR_GO) { - ptr_csr = (ptr_csr & ~CSR_DONE) | CSR_BUSY; - CLR_INT (PTR); - if (ptr_unit.flags & UNIT_ATT) /* data to read? */ - sim_activate (&ptr_unit, ptr_unit.wait); - else sim_activate (&ptr_unit, 0); } /* error if not */ - ptr_csr = (ptr_csr & ~PTRCSR_RW) | (data & PTRCSR_RW); - break; -case 01: /* ptr buf */ - break; -case 02: /* ptp csr */ - if (PA & 1) return SCPE_OK; - if ((data & CSR_IE) == 0) CLR_INT (PTP); - else if (((ptp_csr & CSR_IE) == 0) && (ptp_csr & (CSR_ERR | CSR_DONE))) - SET_INT (PTP); - ptp_csr = (ptp_csr & ~PTPCSR_RW) | (data & PTPCSR_RW); - break; -case 03: /* ptp buf */ - if ((PA & 1) == 0) ptp_unit.buf = data & 0377; - ptp_csr = ptp_csr & ~CSR_DONE; - CLR_INT (PTP); - if (ptp_unit.flags & UNIT_ATT) /* file to write? */ - sim_activate (&ptp_unit, ptp_unit.wait); - else sim_activate (&ptp_unit, 0); /* error if not */ - break; } /* end switch PA */ -return SCPE_OK; -} + NULL, NULL, NULL, + &clk_dib, 0 }; /* Clock and terminal MxPR routines @@ -378,110 +244,6 @@ sim_activate (&tto_unit, tto_unit.wait); return; } -/* Paper tape reader routines - - ptr_svc process event (character ready) - ptr_reset process reset - ptr_attach process attach - ptr_detach process detach -*/ - -t_stat ptr_svc (UNIT *uptr) -{ -int32 temp; - -ptr_csr = (ptr_csr | CSR_ERR) & ~CSR_BUSY; -if (ptr_csr & CSR_IE) SET_INT (PTR); -if ((ptr_unit.flags & UNIT_ATT) == 0) - return IORETURN (ptr_stopioe, SCPE_UNATT); -if ((temp = getc (ptr_unit.fileref)) == EOF) { - if (feof (ptr_unit.fileref)) { - if (ptr_stopioe) printf ("PTR end of file\n"); - else return SCPE_OK; } - else perror ("PTR I/O error"); - clearerr (ptr_unit.fileref); - return SCPE_IOERR; } -ptr_csr = (ptr_csr | CSR_DONE) & ~CSR_ERR; -ptr_unit.buf = temp & 0377; -ptr_unit.pos = ptr_unit.pos + 1; -return SCPE_OK; -} - -t_stat ptr_reset (DEVICE *dptr) -{ -ptr_unit.buf = 0; -ptr_csr = 0; -if ((ptr_unit.flags & UNIT_ATT) == 0) ptr_csr = ptr_csr | CSR_ERR; -CLR_INT (PTR); -sim_cancel (&ptr_unit); -return SCPE_OK; -} - -t_stat ptr_attach (UNIT *uptr, char *cptr) -{ -t_stat reason; - -reason = attach_unit (uptr, cptr); -if ((ptr_unit.flags & UNIT_ATT) == 0) ptr_csr = ptr_csr | CSR_ERR; -else ptr_csr = ptr_csr & ~CSR_ERR; -return reason; -} - -t_stat ptr_detach (UNIT *uptr) -{ -ptr_csr = ptr_csr | CSR_ERR; -return detach_unit (uptr); -} - -/* Paper tape punch routines - - ptp_svc process event (character punched) - ptp_reset process reset - ptp_attach process attach - ptp_detach process detach -*/ - -t_stat ptp_svc (UNIT *uptr) -{ -ptp_csr = ptp_csr | CSR_ERR | CSR_DONE; -if (ptp_csr & CSR_IE) SET_INT (PTP); -if ((ptp_unit.flags & UNIT_ATT) == 0) - return IORETURN (ptp_stopioe, SCPE_UNATT); -if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { - perror ("PTP I/O error"); - clearerr (ptp_unit.fileref); - return SCPE_IOERR; } -ptp_csr = ptp_csr & ~CSR_ERR; -ptp_unit.pos = ptp_unit.pos + 1; -return SCPE_OK; -} - -t_stat ptp_reset (DEVICE *dptr) -{ -ptp_unit.buf = 0; -ptp_csr = CSR_DONE; -if ((ptp_unit.flags & UNIT_ATT) == 0) ptp_csr = ptp_csr | CSR_ERR; -CLR_INT (PTP); -sim_cancel (&ptp_unit); /* deactivate unit */ -return SCPE_OK; -} - -t_stat ptp_attach (UNIT *uptr, char *cptr) -{ -t_stat reason; - -reason = attach_unit (uptr, cptr); -if ((ptp_unit.flags & UNIT_ATT) == 0) ptp_csr = ptp_csr | CSR_ERR; -else ptp_csr = ptp_csr & ~CSR_ERR; -return reason; -} - -t_stat ptp_detach (UNIT *uptr) -{ -ptp_csr = ptp_csr | CSR_ERR; -return detach_unit (uptr); -} - /* Terminal input routines tti_svc process event (character ready) @@ -490,11 +252,11 @@ return detach_unit (uptr); t_stat tti_svc (UNIT *uptr) { -int32 temp; +int32 c; sim_activate (&tti_unit, tti_unit.wait); /* continue poll */ -if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */ -tti_unit.buf = temp & 0377; +if ((c = sim_poll_kbd ()) < SCPE_KFLAG) return c; /* no char or error? */ +tti_unit.buf = c & ((tti_unit.flags & UNIT_8B)? 0377: 0177); tti_unit.pos = tti_unit.pos + 1; tti_csr = tti_csr | CSR_DONE; if (tti_csr & CSR_IE) SET_INT (TTI); @@ -518,11 +280,13 @@ return SCPE_OK; t_stat tto_svc (UNIT *uptr) { -int32 temp; +int32 c; +t_stat r; tto_csr = tto_csr | CSR_DONE; if (tto_csr & CSR_IE) SET_INT (TTO); -if ((temp = sim_putchar (tto_unit.buf & 0177)) != SCPE_OK) return temp; +c = tto_unit.buf & ((tto_unit.flags & UNIT_8B)? 0377: 0177); +if ((r = sim_putchar (c)) != SCPE_OK) return r; tto_unit.pos = tto_unit.pos + 1; return SCPE_OK; } @@ -579,10 +343,10 @@ curr = time (NULL); /* get curr time */ if (curr == (time_t) -1) return SCPE_NOFNC; /* error? */ ctm = localtime (&curr); /* decompose */ if (ctm == NULL) return SCPE_NOFNC; /* error? */ -base = (((((ctm -> tm_yday * 24) + /* sec since 1-Jan */ - ctm -> tm_hour) * 60) + - ctm -> tm_min) * 60) + - ctm -> tm_sec; +base = (((((ctm->tm_yday * 24) + /* sec since 1-Jan */ + ctm->tm_hour) * 60) + + ctm->tm_min) * 60) + + ctm->tm_sec; todr_reg = (base * 100) + 0x10000000; /* cvt to VAX form */ todr_blow = 0; return SCPE_OK; diff --git a/VAX/vax_sys.c b/VAX/vax_sys.c index 443811fa..d97ae530 100644 --- a/VAX/vax_sys.c +++ b/VAX/vax_sys.c @@ -23,6 +23,10 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 12-Oct-02 RMS Added multiple RQ controller support + 10-Oct-02 RMS Added DELQA support + 21-Sep-02 RMS Extended symbolic ex/mod to all byte devices + 06-Sep-02 RMS Added TMSCP support 14-Jul-02 RMS Added infinite loop message */ @@ -36,17 +40,16 @@ extern DEVICE ptr_dev, ptp_dev; extern DEVICE tti_dev, tto_dev; extern DEVICE csi_dev, cso_dev; extern DEVICE lpt_dev, clk_dev; -extern DEVICE rq_dev, rl_dev; -extern DEVICE ts_dev; -extern DEVICE dz_dev; +extern DEVICE rq_dev, rqb_dev, rqc_dev, rqd_dev; +extern DEVICE rl_dev; +extern DEVICE ts_dev, tq_dev; +extern DEVICE dz_dev, xq_dev; extern UNIT cpu_unit; extern REG cpu_reg[]; extern uint32 *M; extern int32 saved_PC; extern int32 sim_switches; -extern t_stat fprint_val (FILE *stream, t_value val, int radix, - int width, int format); extern void WriteB (int32 pa, int32 val); extern void rom_wr (int32 pa, int32 val, int32 lnt); t_stat fprint_sym_m (FILE *of, t_addr addr, t_value *val); @@ -91,10 +94,15 @@ DEVICE *sim_devices[] = { &ptr_dev, &ptp_dev, &lpt_dev, - &rq_dev, - &rl_dev, - &ts_dev, &dz_dev, + &rl_dev, + &rq_dev, + &rqb_dev, + &rqc_dev, + &rqd_dev, + &ts_dev, + &tq_dev, + &xq_dev, NULL }; const char *sim_stop_messages[] = { @@ -109,7 +117,8 @@ const char *sim_stop_messages[] = { "Unknown error", "Fatal RQDX3 error", "Infinite loop", - "Unknown abort code" }; + "Unknown abort code", + "Sanity timer expired" }; /* Binary loader @@ -178,18 +187,18 @@ int32 i, da; int32 *buf; if ((sec < 2) || (wds < 16)) return SCPE_ARG; -if ((uptr -> flags & UNIT_ATT) == 0) return SCPE_UNATT; +if ((uptr->flags & UNIT_ATT) == 0) return SCPE_UNATT; if (!get_yn ("Overwrite last track? [N]", FALSE)) return SCPE_OK; -da = (uptr -> capac - (sec * wds)) * sizeof (int16); -if (fseek (uptr -> fileref, da, SEEK_SET)) return SCPE_IOERR; +da = (uptr->capac - (sec * wds)) * sizeof (int16); +if (fseek (uptr->fileref, da, SEEK_SET)) return SCPE_IOERR; if ((buf = malloc (wds * sizeof (int32))) == NULL) return SCPE_MEM; buf[0] = 0x12345678; buf[1] = 0; for (i = 2; i < wds; i++) buf[i] = 0xFFFFFFFF; for (i = 0; (i < sec) && (i < 10); i++) - fxwrite (buf, sizeof (int32), wds, uptr -> fileref); + fxwrite (buf, sizeof (int32), wds, uptr->fileref); free (buf); -if (ferror (uptr -> fileref)) return SCPE_IOERR; +if (ferror (uptr->fileref)) return SCPE_IOERR; return SCPE_OK; } @@ -817,25 +826,30 @@ t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, { int32 c, k, num, vp, lnt, rdx; t_stat r; +DEVICE *dptr; -if (uptr && uptr != &cpu_unit) return SCPE_ARG; /* only for CPU */ -vp = 0; /* init ptr */ +if (uptr == NULL) uptr = &cpu_unit; /* anon = CPU */ +dptr = find_dev_from_unit (uptr); /* find dev */ +if (dptr == NULL) return SCPE_IERR; +if (dptr->dwidth != 8) return SCPE_ARG; /* byte dev only */ if (sw & SWMASK ('B')) lnt = 1; /* get length */ else if (sw & SWMASK ('W')) lnt = 2; -else lnt = 4; +else if (sw & SWMASK ('L')) lnt = 4; +else lnt = (uptr == &cpu_unit)? 4: 1; if (sw & SWMASK ('D')) rdx = 10; /* get radix */ else if (sw & SWMASK ('O')) rdx = 8; else if (sw & SWMASK ('H')) rdx = 16; -else rdx = cpu_dev.dradix; +else rdx = dptr->dradix; +vp = 0; /* init ptr */ if ((sw & SWMASK ('A')) || (sw & SWMASK ('C'))) { /* char format? */ if (sw & SWMASK ('C')) lnt = sim_emax; /* -c -> string */ - if ((val[0] & 0177) == 0) return SCPE_ARG; + if ((val[0] & 0x7F) == 0) return SCPE_ARG; while (vp < lnt) { /* print string */ - if ((c = (int32) val[vp++] & 0177) == 0) break; - fprintf (of, (c < 040)? "<%03o>": "%c", c); } + if ((c = (int32) val[vp++] & 0x7F) == 0) break; + fprintf (of, (c < 0x20)? "<%02X>": "%c", c); } return -(vp - 1); } /* return # chars */ -if (sw & SWMASK ('M')) { /* inst format? */ +if (sw & SWMASK ('M') && (uptr == &cpu_unit)) { /* inst format? */ r = fprint_sym_m (of, addr, val); /* decode inst */ if (r <= 0) return r; } @@ -985,27 +999,32 @@ t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) { int32 k, rdx, lnt, num, vp; t_stat r; +DEVICE *dptr; static const uint32 maxv[5] = { 0, 0xFF, 0xFFFF, 0, 0xFFFFFFFF }; -if (uptr != &cpu_unit) return SCPE_ARG; /* only for CPU */ -vp = 0; /* init ptr */ -if (sw & SWMASK ('B')) lnt = 1; /* set length */ +if (uptr == NULL) uptr = &cpu_unit; /* anon = CPU */ +dptr = find_dev_from_unit (uptr); /* find dev */ +if (dptr == NULL) return SCPE_IERR; +if (dptr->dwidth != 8) return SCPE_ARG; /* byte dev only */ +if (sw & SWMASK ('B')) lnt = 1; /* get length */ else if (sw & SWMASK ('W')) lnt = 2; -else lnt = 4; -if (sw & SWMASK ('D')) rdx = 10; /* set radix */ +else if (sw & SWMASK ('L')) lnt = 4; +else lnt = (uptr == &cpu_unit)? 4: 1; +if (sw & SWMASK ('D')) rdx = 10; /* get radix */ else if (sw & SWMASK ('O')) rdx = 8; else if (sw & SWMASK ('H')) rdx = 16; -else rdx = cpu_dev.dradix; +else rdx = dptr->dradix; +vp = 0; if ((sw & SWMASK ('A')) || (sw & SWMASK ('C'))) { /* char format? */ if (sw & SWMASK ('C')) lnt = sim_emax; /* -c -> string */ if (*cptr == 0) return SCPE_ARG; - while (vp < lnt) { /* get chars */ - if (*cptr == 0) break; + while ((vp < lnt) && *cptr) { /* get chars */ val[vp++] = *cptr++; } return -(vp - 1); } /* return # chars */ -r = parse_sym_m (cptr, addr, val); /* try to parse inst */ -if (r <= 0) return r; +if (uptr == &cpu_unit) { /* cpu only */ + r = parse_sym_m (cptr, addr, val); /* try to parse inst */ + if (r <= 0) return r; } num = (int32) get_uint (cptr, rdx, maxv[lnt], &r); /* get number */ if (r != SCPE_OK) return r; diff --git a/VAX/vax_sysdev.c b/VAX/vax_sysdev.c index 6ab803ae..63438c0a 100644 --- a/VAX/vax_sysdev.c +++ b/VAX/vax_sysdev.c @@ -33,6 +33,8 @@ cso console storage output sysd system devices (SSC miscellany) + 19-Aug-02 RMS Removed unused variables (found by David Hittner) + Allowed NVR to be attached to file 30-May-02 RMS Widened POS to 32b 28-Feb-02 RMS Fixed bug, missing end of table (found by Lars Brinkhoff) */ @@ -183,6 +185,8 @@ t_stat rom_reset (DEVICE *dptr); t_stat nvr_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); t_stat nvr_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat nvr_reset (DEVICE *dptr); +t_stat nvr_attach (UNIT *uptr, char *cptr); +t_stat nvr_detach (UNIT *uptr); t_stat csi_reset (DEVICE *dptr); t_stat cso_reset (DEVICE *dptr); t_stat cso_svc (UNIT *uptr); @@ -210,6 +214,8 @@ int32 tmr_tir_rd (int32 tmr, t_bool interp); void tmr_csr_wr (int32 tmr, int32 val); void tmr_sched (int32 tmr); void tmr_incr (int32 tmr, uint32 inc); +int32 tmr0_inta (void); +int32 tmr1_inta (void); int32 parity (int32 val, int32 odd); extern int32 cqmap_rd (int32 pa); @@ -248,7 +254,8 @@ DEVICE rom_dev = { "ROM", &rom_unit, rom_reg, NULL, 1, 16, ROMAWIDTH, 4, 16, 32, &rom_ex, &rom_dep, &rom_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + NULL, 0 }; /* NVR data structures @@ -267,7 +274,8 @@ DEVICE nvr_dev = { "NVR", &nvr_unit, nvr_reg, NULL, 1, 16, NVRAWIDTH, 4, 16, 32, &nvr_ex, &nvr_dep, &nvr_reset, - NULL, NULL, NULL }; + NULL, &nvr_attach, &nvr_detach, + NULL, 0 }; /* CSI data structures @@ -276,6 +284,8 @@ DEVICE nvr_dev = { csi_reg CSI register list */ +DIB csi_dib = { 0, 0, NULL, NULL, 1, IVCL (CSI), SCB_CSI, { NULL } }; + UNIT csi_unit = { UDATA (NULL, 0, 0), KBD_POLL_WAIT }; REG csi_reg[] = { @@ -288,11 +298,16 @@ REG csi_reg[] = { { DRDATA (TIME, csi_unit.wait, 24), REG_NZ + PV_LEFT }, { NULL } }; +MTAB csi_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, NULL, &show_vec }, + { 0 } }; + DEVICE csi_dev = { - "CSI", &csi_unit, csi_reg, NULL, + "CSI", &csi_unit, csi_reg, csi_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &csi_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &csi_dib, 0 }; /* CSO data structures @@ -301,6 +316,8 @@ DEVICE csi_dev = { cso_reg CSO register list */ +DIB cso_dib = { 0, 0, NULL, NULL, 1, IVCL (CSO), SCB_CSO, { NULL } }; + UNIT cso_unit = { UDATA (&cso_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; REG cso_reg[] = { @@ -313,11 +330,16 @@ REG cso_reg[] = { { DRDATA (TIME, cso_unit.wait, 24), PV_LEFT }, { NULL } }; +MTAB cso_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, NULL, &show_vec }, + { 0 } }; + DEVICE cso_dev = { - "CSO", &cso_unit, cso_reg, NULL, + "CSO", &cso_unit, cso_reg, cso_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &cso_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &cso_dib, 0 }; /* SYSD data structures @@ -326,6 +348,9 @@ DEVICE cso_dev = { sysd_reg SYSD register list */ +DIB sysd_dib[] = { 0, 0, NULL, NULL, + 2, IVCL (TMR0), 0, { &tmr0_inta, &tmr1_inta } }; + UNIT sysd_unit[] = { { UDATA (&tmr_svc, 0, 0) }, { UDATA (&tmr_svc, 0, 0) } }; @@ -361,7 +386,8 @@ DEVICE sysd_dev = { "SYSD", sysd_unit, sysd_reg, NULL, 2, 16, 16, 1, 16, 8, NULL, NULL, &sysd_reset, - NULL, NULL, NULL }; + NULL, NULL, NULL, + &sysd_dib, 0 }; /* ROM: read only memory - stored in a buffered file Register space access routines see ROM twice @@ -462,10 +488,38 @@ t_stat nvr_reset (DEVICE *dptr) { if (nvr == NULL) { nvr = calloc (NVRSIZE >> 2, sizeof (int32)); + nvr_unit.filebuf = nvr; ssc_cnf = ssc_cnf | SSCCNF_BLO; } if (nvr == NULL) return SCPE_MEM; return SCPE_OK; } + +/* NVR attach */ + +t_stat nvr_attach (UNIT *uptr, char *cptr) +{ +t_stat r; + +uptr->flags = uptr->flags | (UNIT_ATTABLE | UNIT_BUFABLE); +r = attach_unit (uptr, cptr); +if (r != SCPE_OK) + uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE); +else { uptr->hwmark = uptr->capac; + ssc_cnf = ssc_cnf & ~SSCCNF_BLO; } +return r; +} + +/* NVR detach */ + +t_stat nvr_detach (UNIT *uptr) +{ +t_stat r; + +r = detach_unit (uptr); +if ((uptr->flags & UNIT_ATT) == 0) + uptr->flags = uptr->flags & ~(UNIT_ATTABLE | UNIT_BUFABLE); +return r; +} /* CSI: console storage input */ @@ -485,7 +539,7 @@ void csrs_wr (int32 data) { if ((data & CSR_IE) == 0) CLR_INT (CSI); else if ((csi_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) - SET_INT (CSI); + SET_INT (CSI); csi_csr = (csi_csr & ~CSICSR_RW) | (data & CSICSR_RW); return; } @@ -682,9 +736,9 @@ int32 ReadReg (int32 pa, int32 lnt) { struct reglink *p; -for (p = ®table[0]; p -> low != 0; p++) { - if ((pa >= p -> low) && (pa < p -> high) && p -> read) - return p -> read (pa); } +for (p = ®table[0]; p->low != 0; p++) { + if ((pa >= p->low) && (pa < p->high) && p->read) + return p->read (pa); } ssc_bto = ssc_bto | SSCBTO_BTO | SSCBTO_RWT; MACH_CHECK (MCHK_READ); return 0; @@ -704,9 +758,9 @@ void WriteReg (int32 pa, int32 val, int32 lnt) { struct reglink *p; -for (p = ®table[0]; p -> low != 0; p++) { - if ((pa >= p -> low) && (pa < p -> high) && p -> write) { - p -> write (pa, val, lnt); +for (p = ®table[0]; p->low != 0; p++) { + if ((pa >= p->low) && (pa < p->high) && p->write) { + p->write (pa, val, lnt); return; } } ssc_bto = ssc_bto | SSCBTO_BTO | SSCBTO_RWT; MACH_CHECK (MCHK_WRITE); @@ -795,8 +849,6 @@ return; int32 cdg_rd (int32 pa) { int32 t, row = CDG_GETROW (pa); -int32 tag = CDG_GETTAG (pa); -int32 tidx = row >> 1; t = cdg_dat[row]; ka_cacr = ka_cacr & ~CACR_DRO; /* clear diag */ diff --git a/VAX/vaxmod_defs.h b/VAX/vaxmod_defs.h index 9df63227..ccc82566 100644 --- a/VAX/vaxmod_defs.h +++ b/VAX/vaxmod_defs.h @@ -23,6 +23,10 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 11-Nov-02 RMS Added log bits for XQ + 10-Oct-02 RMS Added DEQNA/DELQA, multiple RQ, autoconfigure support + 29-Sep-02 RMS Revamped bus support macros + 06-Sep-02 RMS Added TMSCP support 14-Jul-02 RMS Added additional console halt codes 28-Apr-02 RMS Fixed DZV vector base and number of lines @@ -185,47 +189,76 @@ #define CSR_BUSY (1u << CSR_V_BUSY) #define CSR_ERR (1u << CSR_V_ERR) -/* IO parameters */ - -#define DZ_MUXES 4 /* max # of muxes */ -#define DZ_LINES 4 /* (DZV) lines per mux */ -#define MT_MAXFR (1 << 16) /* magtape max rec */ - /* Timers */ #define TMR_CLK 0 /* 100Hz clock */ /* I/O system definitions */ +#define DZ_MUXES 4 /* max # of muxes */ +#define DZ_LINES 4 /* (DZV) lines per mux */ +#define MT_MAXFR (1 << 16) /* magtape max rec */ +#define AUTO_LNT 34 /* autoconfig ranks */ +#define DIB_MAX 100 /* max DIBs */ + +#define DEV_V_UBUS (DEV_V_UF + 0) /* Unibus */ +#define DEV_V_QBUS (DEV_V_UF + 1) /* Qbus */ +#define DEV_V_FLTA (DEV_V_UF + 2) /* flt addr */ +#define DEV_UBUS (1u << DEV_V_UBUS) +#define DEV_QBUS (1u << DEV_V_QBUS) +#define DEV_FLTA (1u << DEV_V_FLTA) + +#define UNIBUS FALSE /* 22b only */ + /* Device information block */ +#define VEC_DEVMAX 4 /* max device vec */ + struct pdp_dib { - uint32 enb; /* enabled */ uint32 ba; /* base addr */ uint32 lnt; /* length */ t_stat (*rd)(int32 *dat, int32 ad, int32 md); - t_stat (*wr)(int32 dat, int32 ad, int32 md); }; + t_stat (*wr)(int32 dat, int32 ad, int32 md); + int32 vnum; /* vectors: number */ + int32 vloc; /* locator */ + int32 vec; /* value */ + int32 (*ack[VEC_DEVMAX])(void); /* ack routines */ +}; typedef struct pdp_dib DIB; -/* I/O page layout */ +/* I/O page layout - RQB,RQC,RQD float based on number of DZ's */ #define IOBA_DZ (IOPAGEBASE + 000100) /* DZ11 */ #define IOLN_DZ 010 +#define IOBA_RQB (IOPAGEBASE + 000334 + (020 * (DZ_MUXES / 2))) +#define IOLN_RQB 004 +#define IOBA_RQC (IOPAGEBASE + IOBA_RQB + IOLN_RQB) +#define IOLN_RQC 004 +#define IOBA_RQD (IOPAGEBASE + IOBA_RQC + IOLN_RQC) +#define IOLN_RQD 004 #define IOBA_RQ (IOPAGEBASE + 012150) /* RQDX3 */ #define IOLN_RQ 004 #define IOBA_TS (IOPAGEBASE + 012520) /* TS11 */ #define IOLN_TS 004 #define IOBA_RL (IOPAGEBASE + 014400) /* RL11 */ #define IOLN_RL 012 +#define IOBA_XQ (IOPAGEBASE + 014440) /* DEQNA/DELQA */ +#define IOLN_XQ 020 +#define IOBA_XQB (IOPAGEBASE + 014460) /* 2nd DEQNA/DELQA */ +#define IOLN_XQB 020 +#define IOBA_TQ (IOPAGEBASE + 014500) /* TMSCP */ +#define IOLN_TQ 004 #define IOBA_RP (IOPAGEBASE + 016700) /* RP/RM */ #define IOLN_RP 054 #define IOBA_DBL (IOPAGEBASE + 017500) /* doorbell */ #define IOLN_DBL 002 #define IOBA_LPT (IOPAGEBASE + 017514) /* LP11 */ #define IOLN_LPT 004 -#define IOBA_PT (IOPAGEBASE + 017550) /* PC11 */ -#define IOLN_PT 010 +#define IOBA_PTR (IOPAGEBASE + 017550) /* PC11 reader */ +#define IOLN_PTR 004 +#define IOBA_PTP (IOPAGEBASE + 017554) /* PC11 punch */ +#define IOLN_PTP 004 /* The KA65x maintains 4 separate hardware IPL levels, IPL 17 to IPL 14 Within each IPL, priority is right to left @@ -245,6 +278,8 @@ typedef struct pdp_dib DIB; #define INT_V_DZTX 3 #define INT_V_RP 4 /* RP,RM drives */ #define INT_V_TS 5 /* TS11/TSV05 */ +#define INT_V_TQ 6 /* TMSCP */ +#define INT_V_XQ 7 /* DEQNA/DELQA */ /* IPL 14 */ @@ -265,6 +300,8 @@ typedef struct pdp_dib DIB; #define INT_DZTX (1u << INT_V_DZTX) #define INT_RP (1u << INT_V_RP) #define INT_TS (1u << INT_V_TS) +#define INT_TQ (1u << INT_V_TQ) +#define INT_XQ (1u << INT_V_XQ) #define INT_TTI (1u << INT_V_TTI) #define INT_TTO (1u << INT_V_TTO) #define INT_PTR (1u << INT_V_PTR) @@ -282,6 +319,8 @@ typedef struct pdp_dib DIB; #define IPL_DZTX (0x15 - IPL_HMIN) #define IPL_RP (0x15 - IPL_HMIN) #define IPL_TS (0x15 - IPL_HMIN) +#define IPL_TQ (0x15 - IPL_HMIN) +#define IPL_XQ (0x15 - IPL_HMIN) #define IPL_TTI (0x14 - IPL_HMIN) #define IPL_TTO (0x14 - IPL_HMIN) #define IPL_PTR (0x14 - IPL_HMIN) @@ -297,17 +336,31 @@ typedef struct pdp_dib DIB; #define IPL_HLVL (IPL_HMAX - IPL_HMIN + 1) /* # hardware levels */ #define IPL_SMAX 0xF /* highest swre level */ +/* Device vectors */ + #define VEC_Q 0x200 /* Qbus vector offset */ -#define VEC_PTR (VEC_Q + 0070) /* Qbus vectors */ +#define VEC_PTR (VEC_Q + 0070) #define VEC_PTP (VEC_Q + 0074) +#define VEC_XQ (VEC_Q + 0120) #define VEC_RQ (VEC_Q + 0154) #define VEC_RL (VEC_Q + 0160) #define VEC_LPT (VEC_Q + 0200) #define VEC_TS (VEC_Q + 0224) #define VEC_RP (VEC_Q + 0254) +#define VEC_TQ (VEC_Q + 0260) #define VEC_DZRX (VEC_Q + 0300) #define VEC_DZTX (VEC_Q + 0304) +/* Autoconfigure ranks */ + +#define RANK_DZ 8 +#define RANK_RL 14 +#define RANK_RQ 26 +#define RANK_TQ 30 + +/* Interrupt macros */ + +#define IVCL(dv) ((IPL_##dv * 32) + INT_V_##dv) #define IREQ(dv) int_req[IPL_##dv] #define SET_INT(dv) int_req[IPL_##dv] = int_req[IPL_##dv] | (INT_##dv) #define CLR_INT(dv) int_req[IPL_##dv] = int_req[IPL_##dv] & ~(INT_##dv) @@ -315,13 +368,18 @@ typedef struct pdp_dib DIB; /* Logging */ -#define LOG_CPU_I 0x001 /* intexc */ -#define LOG_CPU_R 0x002 /* REI */ -#define LOG_CPU_P 0x004 /* context */ -#define LOG_CPU_A 0x008 -#define LOG_RP 0x010 -#define LOG_TS 0x020 -#define LOG_RQ 0x040 +#define LOG_CPU_I 0x0001 /* intexc */ +#define LOG_CPU_R 0x0002 /* REI */ +#define LOG_CPU_P 0x0004 /* context */ +#define LOG_CPU_A 0x0008 +#define LOG_RP 0x0010 +#define LOG_TS 0x0020 +#define LOG_RQ 0x0040 +#define LOG_TQ 0x0080 +#define LOG_XQ0 0x0100 +#define LOG_XQ1 0x0200 +#define LOG_XQ2 0x0400 +#define LOG_XQ3 0x0800 #define DBG_LOG(x) (sim_log && (cpu_log & (x))) @@ -335,17 +393,15 @@ int32 map_writeB (t_addr ba, int32 bc, uint8 *buf); int32 map_writeW (t_addr ba, int32 bc, uint16 *buf); int32 map_writeL (t_addr ba, int32 bc, uint32 *buf); -/* Macros for PDP-11 compatibility */ - -#define QB 0 /* Q22 native */ -#define UB 1 /* Unibus */ - #define Map_Addr(a,b) map_addr (a, b) #define Map_ReadB(a,b,c,d) map_readB (a, b, c) #define Map_ReadW(a,b,c,d) map_readW (a, b, c) #define Map_WriteB(a,b,c,d) map_writeB (a, b, c) #define Map_WriteW(a,b,c,d) map_writeW (a, b, c) + t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc); -t_bool dev_conflict (uint32 nba, DIB *curr); +t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat set_vec (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat show_vec (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat auto_config (uint32 rank, uint32 num); diff --git a/build_mingw.bat b/build_mingw.bat index c5789784..873e73bd 100644 --- a/build_mingw.bat +++ b/build_mingw.bat @@ -1,3 +1,4 @@ +rem 22-Aug-02 rms Telnet console support rem 18-May-02 rms VT emulation support rem rem Compile all of SIMH using MINGW gcc environment @@ -11,7 +12,7 @@ path c:\mingw\bin;%path% rem rem PDP-1 rem -gcc -O0 -o .\bin\pdp1 -I. -I.\pdp1 scp*.c sim_vt.c .\pdp1\pdp1*.c +gcc -O0 -o .\bin\pdp1 -I. -I.\pdp1 scp*.c sim*.c .\pdp1\pdp1*.c -lwsock32 rem rem PDP-11 rem @@ -23,14 +24,14 @@ gcc -O0 -o .\bin\pdp8 -I. -I.\pdp8 scp*.c sim*.c .\pdp8\pdp8*.c -lm -lwsock32 rem rem PDP-4, PDP-7, PDP-9, PDP-15 rem -gcc -O0 -DPDP4 -o .\bin\pdp4 -I. -I./pdp18b scp*.c sim*.c .\pdp18b\pdp18b*.c -lm -lwsock32 -gcc -O0 -DPDP7 -o .\bin\pdp7 -I. -I./pdp18b scp*.c sim*.c .\pdp18b\pdp18b*.c -lm -lwsock32 -gcc -O0 -DPDP9 -o .\bin\pdp9 -I. -I./pdp18b scp*.c sim*.c .\pdp18b\pdp18b*.c -lm -lwsock32 -gcc -O0 -DPDP15 -o .\bin\pdp15 -I. -I./pdp18b scp*.c sim*.c .\pdp18b\pdp18b*.c -lm -lwsock32 +gcc -O0 -DPDP4 -o .\bin\pdp4 -I. -I.\pdp18b scp*.c sim*.c .\pdp18b\pdp18b*.c -lm -lwsock32 +gcc -O0 -DPDP7 -o .\bin\pdp7 -I. -I.\pdp18b scp*.c sim*.c .\pdp18b\pdp18b*.c -lm -lwsock32 +gcc -O0 -DPDP9 -o .\bin\pdp9 -I. -I.\pdp18b scp*.c sim*.c .\pdp18b\pdp18b*.c -lm -lwsock32 +gcc -O0 -DPDP15 -o .\bin\pdp15 -I. -I.\pdp18b scp*.c sim*.c .\pdp18b\pdp18b*.c -lm -lwsock32 rem rem PDP-10 rem -gcc -O0 -DUSE_INT64 -o .\bin\pdp10 -I. -I.\bin\pdp10 scp*.c sim*.c .\pdp10\pdp10*.c -lm -lwsock32 +gcc -O0 -DUSE_INT64 -o .\bin\pdp10 -I.\pdp11 -I. -I.\pdp10 scp*.c sim*.c .\pdp10\pdp10*.c .\pdp11\pdp11_ry.c -lm -lwsock32 rem rem Nova, Eclipse rem @@ -39,7 +40,7 @@ gcc -O0 -DECLIPSE -o .\bin\eclipse -I. -I.\nova scp*.c sim*.c .\nova\eclipse_cpu rem rem Altair rem -gcc -O0 -o .\bin\altair -I. -I.\altair scp*.c sim_vt.c .\altair\altair*.c +gcc -O0 -o .\bin\altair -I. -I.\altair scp*.c sim*.c .\altair\altair*.c -lwsock32 rem rem AltairZ80 rem @@ -47,7 +48,7 @@ gcc -O0 -o .\bin\altairz80 -I. -I.\altairz80 scp*.c sim*.c .\altairz80\altair*.c rem rem H316 rem -gcc -O0 -o .\bin\h316 -I. -I.\h316 scp*.c sim_vt.c .\h316\h316*.c +gcc -O0 -o .\bin\h316 -I. -I.\h316 scp*.c sim*.c .\h316\h316*.c -lwsock32 rem rem HP2100 rem @@ -55,23 +56,27 @@ gcc -O0 -o .\bin\hp2100 -I. -I.\hp2100 scp*.c sim*.c .\hp2100\hp2100*.c -lwsock3 rem rem IBM 1401 rem -gcc -O0 -o .\bin\i1401 -I. -I.\i1401 scp*.c sim_vt.c .\i1401\i1401*.c +gcc -O0 -o .\bin\i1401 -I. -I.\i1401 scp*.c sim*.c .\i1401\i1401*.c -lwsock32 +rem +rem IBM 1620 +rem +gcc -O0 -o .\bin\i1620 -I. -I.\i1620 scp*.c sim*.c .\i1620\i1620*.c -lwsock32 rem rem IBM System 3 rem -gcc -O0 -o .\bin\s3 -I. -I.\s3 scp*.c sim_vt.c .\s3\s3*.c +gcc -O0 -o .\bin\s3 -I. -I.\s3 scp*.c sim*.c .\s3\s3*.c -lwsock32 rem rem IBM 1130 rem -gcc -O0 -o .\bin\ibm1130 -I. -I.\ibm1130 scp*.c sim_vt.c .\ibm1130\ibm1130*.c +gcc -O0 -o .\bin\ibm1130 -I. -I.\ibm1130 scp*.c sim*.c .\ibm1130\ibm1130*.c -lwsock32 rem rem VAX rem -gcc -O0 -DUSE_INT64 -o .\bin\vax -I. -I.\vax -I.\pdp11 scp*.c sim*.c .\pdp11\pdp11_rl.c .\pdp11\pdp11_rq.c .\pdp11\pdp11_dz.c .\pdp11\pdp11_lp.c .\pdp11\pdp11_ts.c .\vax\vax*.c -lm -lwsock32 +gcc -O0 -DUSE_INT64 -o .\bin\vax -I. -I.\vax -I.\pdp11 scp*.c sim*.c .\pdp11\pdp11_pt.c .\pdp11\pdp11_rl.c .\pdp11\pdp11_rq.c .\pdp11\pdp11_dz.c .\pdp11\pdp11_lp.c .\pdp11\pdp11_ts.c .\pdp11\pdp11_tq.c .\pdp11\pdp11_xq.c .\vax\vax*.c -lm -lwsock32 rem rem GRI rem -gcc -O0 -o .\bin\gri -I. -I.\gri scp*.c sim_vt.c .\gri\gri*.c +gcc -O0 -o .\bin\gri -I. -I.\gri scp*.c sim*.c .\gri\gri*.c -lwsock32 rem rem Placeholders for future simulators rem diff --git a/build_mingw_ether.bat b/build_mingw_ether.bat new file mode 100644 index 00000000..ee7a9f57 --- /dev/null +++ b/build_mingw_ether.bat @@ -0,0 +1,86 @@ +rem 12-Nov-02 rms Ethernet support +rem 22-Aug-02 rms Telnet console support +rem 18-May-02 rms VT emulation support +rem +rem Compile all of SIMH using MINGW gcc environment +rem Individual simulator sources are in .\simulator_name +rem Individual simulator executables are to .\bin +rem +rem If needed, define the path for the MINGW bin directory. +rem (this should already be set if MINGW was installed correctly) +rem +path c:\mingw\bin;%path% +rem +rem PDP-1 +rem +gcc -O0 -o .\bin\pdp1 -I. -I.\pdp1 scp*.c sim*.c .\pdp1\pdp1*.c -lwsock32 +rem +rem PDP-11 +rem +gcc -O0 -DUSE_NETWORK -o .\bin\pdp11 -I. -I.\pdp11 scp*.c sim*.c .\pdp11\pdp11*.c -lm -lwsock32 -lwpcap -lpacket +rem +rem PDP-8 +rem +gcc -O0 -o .\bin\pdp8 -I. -I.\pdp8 scp*.c sim*.c .\pdp8\pdp8*.c -lm -lwsock32 +rem +rem PDP-4, PDP-7, PDP-9, PDP-15 +rem +gcc -O0 -DPDP4 -o .\bin\pdp4 -I. -I.\pdp18b scp*.c sim*.c .\pdp18b\pdp18b*.c -lm -lwsock32 +gcc -O0 -DPDP7 -o .\bin\pdp7 -I. -I.\pdp18b scp*.c sim*.c .\pdp18b\pdp18b*.c -lm -lwsock32 +gcc -O0 -DPDP9 -o .\bin\pdp9 -I. -I.\pdp18b scp*.c sim*.c .\pdp18b\pdp18b*.c -lm -lwsock32 +gcc -O0 -DPDP15 -o .\bin\pdp15 -I. -I.\pdp18b scp*.c sim*.c .\pdp18b\pdp18b*.c -lm -lwsock32 +rem +rem PDP-10 +rem +gcc -O0 -DUSE_INT64 -o .\bin\pdp10 -I.\pdp11 -I. -I.\pdp10 scp*.c sim*.c .\pdp10\pdp10*.c .\pdp11\pdp11_ry.c -lm -lwsock32 +rem +rem Nova, Eclipse +rem +gcc -O0 -o .\bin\nova -I. -I.\nova scp*.c sim*.c .\nova\nova*.c -lm -lwsock32 +gcc -O0 -DECLIPSE -o .\bin\eclipse -I. -I.\nova scp*.c sim*.c .\nova\eclipse_cpu.c .\nova\nova_clk.c .\nova\nova_dkp.c .\nova\nova_dsk.c .\nova\nova_lp.c .\nova\nova_mta.c .\nova\nova_plt.c .\nova\nova_pt.c .\nova\nova_sys.c .\nova\nova_tt.c .\nova\nova_tt1.c -lm -lwsock32 +rem +rem Altair +rem +gcc -O0 -o .\bin\altair -I. -I.\altair scp*.c sim*.c .\altair\altair*.c -lwsock32 +rem +rem AltairZ80 +rem +gcc -O0 -o .\bin\altairz80 -I. -I.\altairz80 scp*.c sim*.c .\altairz80\altair*.c -lwsock32 +rem +rem H316 +rem +gcc -O0 -o .\bin\h316 -I. -I.\h316 scp*.c sim*.c .\h316\h316*.c -lwsock32 +rem +rem HP2100 +rem +gcc -O0 -o .\bin\hp2100 -I. -I.\hp2100 scp*.c sim*.c .\hp2100\hp2100*.c -lwsock32 +rem +rem IBM 1401 +rem +gcc -O0 -o .\bin\i1401 -I. -I.\i1401 scp*.c sim*.c .\i1401\i1401*.c -lwsock32 +rem +rem IBM 1620 +rem +gcc -O0 -o .\bin\i1620 -I. -I.\i1620 scp*.c sim*.c .\i1620\i1620*.c -lwsock32 +rem +rem IBM System 3 +rem +gcc -O0 -o .\bin\s3 -I. -I.\s3 scp*.c sim*.c .\s3\s3*.c -lwsock32 +rem +rem IBM 1130 +rem +gcc -O0 -o .\bin\ibm1130 -I. -I.\ibm1130 scp*.c sim*.c .\ibm1130\ibm1130*.c -lwsock32 +rem +rem VAX +rem +gcc -O0 -DUSE_INT64 -DUSE_NETWORK -o .\bin\vax -I. -I.\vax -I.\pdp11 scp*.c sim*.c .\pdp11\pdp11_pt.c .\pdp11\pdp11_rl.c .\pdp11\pdp11_rq.c .\pdp11\pdp11_dz.c .\pdp11\pdp11_lp.c .\pdp11\pdp11_ts.c .\pdp11\pdp11_tq.c .\pdp11\pdp11_xq.c .\vax\vax*.c -lm -lwsock32 -lwpcap -lpacket +rem +rem GRI +rem +gcc -O0 -o .\bin\gri -I. -I.\gri scp*.c sim*.c .\gri\gri*.c -lwsock32 +rem +rem Placeholders for future simulators +rem +rem gcc -O0 -o .\bin\sds -I. -I.\sds scp*.c sim*.c .\sds\sds*.c -lm -lwsock32 +rem gcc -O0 -o .\bin\id16 -I. -I.\interdata scp*.c sim*.c .\interdata\id16*.c .\interdata\id_*.c -lwsock32 +rem gcc -O0 -o .\bin\id32 -I. -I.\interdata scp*.c sim*.c .\interdata\id32*.c .\interdata\id_*.c -lwsock32 diff --git a/build_vms.com b/build_vms.com deleted file mode 100644 index af8dec06..00000000 --- a/build_vms.com +++ /dev/null @@ -1,1112 +0,0 @@ -$! -$! BUILD_VMS.COM -$! Written By: Robert Alan Byer -$! byer@mail.ourservers.net -$! -$! -$! This script is used to compile and thar various simualtors in the SIMH -$! package for OpenVMS using DEC C v6.0-001. -$! -$! The script accepts the following parameters. -$! -$! P1 ALL Just Build "Everything". -$! ALTAIR Just Build The MITS Altair. -$! ALTAIRZ80 Just Build The MITS Altair Z80. -$! ECLIPSE Just Build The Data General Eclipse. -$! H316 Just Build The Honewell 316/516. -$! HP2100 Just Build The Hewlett-Packard HP-2100. -$! I1401 Just Build The IBM 1401. -$! IBM1130 Just Build The IBM 1130. -$! INTERDATA Just Build The Interdata 4. -$! NOVA Just Build The Data General Nova. -$! PDP1 Just Build The DEC PDP-1. -$! PDP8 Just Build The DEC PDP-8. -$! PDP10 Just Build The DEC PDP-10. -$! PDP11 Just Build The DEC PDP-11. -$! PDP18B Just Build The DEC PDP-4, PDP-7, PDP-9 And PDP-15. -$! S3 Just Build The IBM System 3. -$! SDS Just Build The SDS System. -$! VAX Just Build The DEC VAX. -$! -$! P2 DEBUG Link With Debugger Information. -$! NODEBUG Link Withoug Debugger Information. -$! -$! -$! The defaults are "ALL" and "NODEBUG". -$! -$! -$! Define The Simualtors We Have That We Can Build. -$! -$ SIMH_SIMS = "ALTAIR,ALTAIRZ80,ECLIPSE,H316,HP2100,I1401,IBM1130," + - - "INTERDATA,NOVA,PDP1,PDP8,PDP10,PDP11,PDP18B,S3,SDS,VAX" -$! -$! Check To Make Sure We Have Valid Command Line Parameters. -$! -$ GOSUB CHECK_OPTIONS -$! -$! Check To See If We Are On An AXP Machine. -$! -$ IF (F$GETSYI("CPU").LT.128) -$ THEN -$! -$! We Are On A VAX Machine So Tell The User. -$! -$ WRITE SYS$OUTPUT "Compiling On A VAX Machine." -$! -$! Define The Machine Type. -$! -$ MACHINE_TYPE = "VAX" -$! -$! Else, We Are On An AXP Machine. -$! -$ ELSE -$! -$! We Are On A AXP Machine So Tell The User. -$! -$ WRITE SYS$OUTPUT "Compiling On A AXP Machine." -$! -$! Define The Machine Type. -$! -$ MACHINE_TYPE = "AXP" -$! -$! End Of The Machine Check. -$! -$ ENDIF -$! -$! Define The Compile Command. -$! -$ CC = "CC/PREFIX=ALL/''OPTIMIZE'/''DEBUGGER'" + - - "/NEST=PRIMARY/NAME=(AS_IS,SHORTENED)" -$! -$! Define The SIMH Library Name. -$! -$ SIMHLIB_NAME = "SYS$DISK:[.LIB]SIMH-''MACHINE_TYPE'.OLB" -$! -$! Check To See What We Are To Do. -$! -$ IF (BUILDALL.NES."TRUE") -$ THEN -$! -$! Define The Name Of The Module We Are To Compile. -$! -$ SIMH_MOD_NAME = P1 -$! -$! Check To See If We Are Going To Build The PDP18B Simulators. -$! -$ IF (SIMH_MOD_NAME.EQS."PDP18B") -$ THEN -$! -$! Use The Special Build For PDP18B. -$! -$ GOSUB BUILD_PDP18B_MOD -$! -$! Else... -$! -$ ELSE -$! -$! Build Just What The User Wants Us To Build. -$! -$ GOSUB BUILD_SIMHLIB_MOD -$! -$! That's All, Time To EXIT. -$! -$ EXIT -$! -$! Time To Exit The PDP18B Check. -$! -$ ENDIF -$! -$! Time To End The BUILDALL Check. -$! -$ ENDIF -$! -$! Build The SIMH Library. -$! -$ GOSUB BUILD_SIMHLIB -$! -$! Define A Counter And Set It To "0". -$! -$ SIMH_MOD_COUNTER = 0 -$! -$! Top Of The Loop. -$! -$ NEXT_SIMH_MOD_NAME: -$! -$! O.K, Extract The File Module From The File List. -$! -$ SIMH_MOD_NAME = F$ELEMENT(SIMH_MOD_COUNTER,",",SIMH_SIMS) -$! -$! Check To See If We Are At The End Of The Simulator List. -$! -$ IF (SIMH_MOD_NAME.EQS.",") THEN GOTO SIMH_MOD_DONE -$! -$! Increment The Counter. -$! -$ SIMH_MOD_COUNTER = SIMH_MOD_COUNTER + 1 -$! -$! Check To See If We Are On VAX. -$! -$ IF (MACHINE_TYPE.EQS."VAX") -$ THEN -$! -$! Check To See If We Are Build The PDP10 or VAX Simulator. -$! -$ IF (SIMH_MOD_NAME.EQS."PDP10").OR.(SIMH_MOD_NAME.EQS."VAX") -$ THEN -$! -$! Tell The User We Can't Build PDP10 Or VAX On The VAX -$! Platform. -$! -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT "Due to the use of INT64, the ''SIMH_MOD_NAME' simulator will not be built for the ''MACHINE_TYPE'" -$ WRITE SYS$OUTPUT "platform." -$ WRITE SYS$OUTPUT "" -$! -$! Skip And Go To The Next Simulator. -$! -$ GOTO NEXT_SIMH_MOD_NAME -$! -$! Time To End The PDP10 And VAX Check. -$! -$ ENDIF -$! -$! Time To End The VAX Check. -$! -$ ENDIF -$! -$! Check To See If We Are Going To Build The PDP18B Simulators. -$! -$ IF (SIMH_MOD_NAME.EQS."PDP18B") -$ THEN -$! -$! Use The Special Build For PDP18B. -$! -$ GOSUB BUILD_PDP18B_MOD -$! -$! Else... -$! -$ ELSE -$! -$! Build The Module. -$! -$ GOSUB BUILD_SIMHLIB_MOD -$! -$! Time To End The PDP18D Check. -$! -$ ENDIF -$! -$! Go Back And Get Another Module Name. -$! -$ GOTO NEXT_SIMH_MOD_NAME -$! -$! End Of The Module List. -$! -$ SIMH_MOD_DONE: -$! -$! All Done Building Modules, Time To EXIT. -$! -$ EXIT -$! -$! Build The SYS$DISK:[.LIB]SIMH-xxx.OLB Library. -$! -$ BUILD_SIMHLIB: -$! -$! Define The C INCLUDES We Are To Use. -$! -$ SIMHLIB_INCLUDES = "INCLUDE=(SYS$DISK:[])" -$! -$! Check To See If We Have A SYS$DISK:[.LIB] Dierctory To Put The -$! Library In. -$! -$ IF (F$SEARCH("SYS$DISK:[]LIB.DIR").EQS."") -$ THEN -$! -$! A SYS$DISK:[.LIB] Directory Dosen't Exist So Tell The User We -$! Are Going To Create One. -$! -$ WRITE SYS$OUTPUT "Creating SYS$DISK:[.LIB]" -$! -$! Create The Directory. -$! -$ CREATE/DIRECTORY SYS$DISK:[.LIB] -$! -$! Time To End The SYS$DISK:[.LIB] Directory Check. -$! -$ ENDIF -$! -$! Check To See If We Already Have A SYS$DISK:[.LIB]SIMH-xxx.OLB Library... -$! -$ IF (F$SEARCH(SIMHLIB_NAME).EQS."") -$ THEN -$! -$! Guess Not, Create The Library. -$! -$ LIBRARY/CREATE/OBJECT 'SIMHLIB_NAME' -$! -$! End The Library Check. -$! -$ ENDIF -$! -$! Tell The User What We Are Doing. -$! -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT "Compling The ''SIMHLIB_NAME' Library." -$! -$! Tell The User What Compile Command We Are Going To Use. -$! -$ WRITE SYS$OUTPUT "Using Compile Command: ",CC,"/",SIMHLIB_INCLUDES -$ WRITE SYS$OUTPUT "" -$! -$! Top Of The File Loop. -$! -$ NEXT_SIMHLIB_FILE: -$! -$! Define The List Of Files We Are Going To Compile. -$! -$ SIMHLIB_FILES = F$ELEMENT(0,";",F$ELEMENT(1,"]",F$SEARCH("SYS$DISK:[]*.C",1))) -$! -$! Extract The File Name From The File List. -$! -$ SIMHLIB_FILE_NAME = F$ELEMENT(0,".",SIMHLIB_FILES) -$! -$! Check To See If We Are At The End Of The File List. -$! -$ IF (SIMHLIB_FILE_NAME.EQS."]") THEN GOTO SIMHLIB_FILE_DONE -$! -$! Check To See If We We Are At The SCP.C File. -$! -$ IF (SIMHLIB_FILE_NAME.EQS."SCP") -$ THEN -$! -$! Since We Are At The SCP.C File, Go Back And -$! Get Another One As We Don't Want Add This To The Library. -$! -$ GOTO NEXT_SIMHLIB_FILE -$! -$! Time To End The SCP.C Check. -$! -$ ENDIF -$! -$! Create The Source File Name. -$! -$ SIMHLIB_SOURCE_FILE = "SYS$DISK:[]" + SIMHLIB_FILE_NAME + ".C" -$! -$! Create The Object File Name. -$! -$ SIMHLIB_OBJECT_FILE = "SYS$DISK:[]" + SIMHLIB_FILE_NAME + ".OBJ" -$! -$! Tell The User What We Are Compiling. -$! -$ WRITE SYS$OUTPUT " ",SIMHLIB_SOURCE_FILE -$! -$! Compile The File. -$! -$ CC/'SIMHLIB_INCLUDES'/OBJECT='SIMHLIB_OBJECT_FILE' 'SIMHLIB_SOURCE_FILE' -$! -$! Add It To The Library. -$! -$ LIBRARY/REPLACE/OBJECT 'SIMHLIB_NAME' 'SIMHLIB_OBJECT_FILE' -$! -$! Delete The Object File. -$! -$ DELETE/NOCONFIRM/NOLOG 'SIMHLIB_OBJECT_FILE';* -$! -$! Go Back And Do It Again. -$! -$ GOTO NEXT_SIMHLIB_FILE -$! -$! All Done Compiling. -$! -$ SIMHLIB_FILE_DONE: -$! -$! That's It, Time To Return From Where We Came From. -$! -$ RETURN -$! -$! Build The Libraries And Simulators.. -$! -$ BUILD_SIMHLIB_MOD: -$! -$! Check To See If We Are Going To Build The VAX Simulator. -$! -$ IF (SIMH_MOD_NAME.EQS."VAX") -$ THEN -$! -$! Define The C INCLUDES For The VAX Simulator. -$! -$ SIMHLIB_MOD_INCLUDES = "/INCLUDE=(SYS$DISK:[]," + - - "SYS$DISK:[.''SIMH_MOD_NAME']," + - - "SYS$DISK:[.PDP11])" -$! -$! Else... -$! -$ ELSE -$! -$! Define The Standard C INCLUDES We Are To Use. -$! -$ SIMHLIB_MOD_INCLUDES = "/INCLUDE=(SYS$DISK:[]," + - - "SYS$DISK:[.''SIMH_MOD_NAME'])" -$! -$! Time To End The VAX Check. -$! -$ ENDIF -$! -$! Check To See If We Are Going To Build The Eclipse Simulator. -$! -$ IF (SIMH_MOD_NAME.EQS."ECLIPSE") -$ THEN -$! -$! Define The Module Directory For The Eclipse Simulator. -$! -$ SIMHLIB_MOD_DIR = "SYS$DISK:[.NOVA]" -$! -$! Else... -$! -$ ELSE -$! -$! Define The Module Directory. -$! -$ SIMHLIB_MOD_DIR = "SYS$DISK:[.''SIMH_MOD_NAME']" -$! -$! Time To End The Ecplise Simulator Check. -$! -$ ENDIF -$! -$! Check To See If We Are Going To Build The Eclipse Simulator. -$! -$ IF (SIMH_MOD_NAME.EQS."ECLIPSE") -$ THEN -$! -$! Set The Compiler DEFINES For The Eclipse Simulator. -$! -$ SIMHLIB_MOD_DEFINE = "/DEFINE=(""ECLIPSE=1"")" -$! -$! Else... -$! -$ ELSE -$! -$! Check To See If We Are Going To Build The PDP10 Or VAX Simulator. -$! -$ IF (SIMH_MOD_NAME.EQS."PDP10").OR.(SIMH_MOD_NAME.EQS."VAX") -$ THEN -$! -$! Set The Compiler DEFINES For The PDP10 Simulator. -$! -$ SIMHLIB_MOD_DEFINE = "/DEFINE=(""USE_INT64=1"")" -$! -$! Else... -$! -$ ELSE -$! -$! Set The Compiler Defines For Everything Else. -$! -$ SIMHLIB_MOD_DEFINE = "" -$! -$! Time To End The PDP10 And VAX Simulator Check. -$! -$ ENDIF -$! -$! Time To End The Eclipse Simulator Check. -$! -$ ENDIF -$! -$! Check To See If There Are Any Files In The Module Directory. -$! -$ IF (F$SEARCH("''SIMHLIB_MOD_DIR'*.C").EQS."") -$ THEN -$! -$! There Are No Files To Compile In The Module Directory So -$! RETURN From Where We Came From And Get Another Module Name. -$! -$ RETURN -$! -$! Time To End The File Check. -$! -$ ENDIF -$! -$! Check To See If We Have A SYS$DISK:[.LIB] Dierctory To Put The -$! Library In. -$! -$ IF (F$SEARCH("SYS$DISK:[]LIB.DIR").EQS."") -$ THEN -$! -$! A SYS$DISK:[.LIB] Directory Dosen't Exist So Tell The User We -$! Are Going To Create One. -$! -$ WRITE SYS$OUTPUT "Creating SYS$DISK:[.LIB]" -$! -$! Create The Directory. -$! -$ CREATE/DIRECTORY SYS$DISK:[.LIB] -$! -$! Time To End The SYS$DISK:[.LIB] Directory Check. -$! -$ ENDIF -$! -$! Create The Module Library Name. -$! -$ SIMHLIB_MOD_LIB_NAME = "SYS$DISK:[.LIB]''SIMH_MOD_NAME'-''MACHINE_TYPE'" + - - ".OLB" -$! -$! Check To See If We Already Have A Library... -$! -$ IF (F$SEARCH("''SIMHLIB_MOD_LIB_NAME'").EQS."") -$ THEN -$! -$! Guess Not, Create The Library. -$! -$ LIBRARY/CREATE/OBJECT 'SIMHLIB_MOD_LIB_NAME' -$! -$! End The Library Check. -$! -$ ENDIF -$! -$! Tell The User What We Are Doing. -$! -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT "Compling The ''SIMHLIB_MOD_LIB_NAME' Library." -$! -$! Tell The User What Compile Command We Are Going To Use. -$! -$ WRITE SYS$OUTPUT "Using Compile Command: ",CC,"''SIMHLIB_MOD_INCLUDES'", - - SIMHLIB_MOD_DEFINE -$ WRITE SYS$OUTPUT "" -$! -$! Top Of The File Loop. -$! -$ NEXT_SIMHLIB_MOD_FILE: -$! -$! Check To See If We Are Going To Build Nova. -$! -$ IF (SIMH_MOD_NAME.EQS."NOVA") -$ THEN -$! -$! Since Nova And Eclipse Share The Same Directory We Only Want The -$! Nova Files When We Build Nova. -$! -$ SIMHLIB_MOD_FILES = F$ELEMENT(0,";",F$ELEMENT(1,"]", - - F$SEARCH("''SIMHLIB_MOD_DIR'''SIMH_MOD_NAME'*.C",1))) -$! -$! Else... -$! -$ ELSE -$! -$! Define The List Of Files We Are Going To Compile. -$! -$ SIMHLIB_MOD_FILES = F$ELEMENT(0,";",F$ELEMENT(1,"]", - - F$SEARCH("''SIMHLIB_MOD_DIR'*.C",1))) -$! -$! Time To End The Nova Simulator Check. -$! -$ ENDIF -$! -$! Extract The File Name From The File List. -$! -$ SIMHLIB_MOD_FILE_NAME = F$ELEMENT(0,".",SIMHLIB_MOD_FILES) -$! -$! Check To See If We Are At The End Of The File List. -$! -$ IF (SIMHLIB_MOD_FILE_NAME.EQS."]") THEN GOTO SIMHLIB_MOD_FILE_DONE -$! -$! Check To See If We Building Eclipse. -$! -$ IF (SIMH_MOD_NAME.EQS."ECLIPSE") -$ THEN -$! -$! Check To See If We We Are At The NOVA_CPU.C Or NOVA_TT.C File. -$! -$ IF (SIMHLIB_MOD_FILE_NAME.EQS."NOVA_CPU").OR. - - (SIMHLIB_MOD_FILE_NAME.EQS."NOVA_TT") -$ THEN -$! -$! Since We Building The Eclipse And Are At The Either The NOVA_CPU.C Or -$! NOVA_TT.C File, Go Back And Get Another File As We Don't Want Add -$! These To The Eclipse Library. -$! -$ GOTO NEXT_SIMHLIB_MOD_FILE -$! -$! Time To End The NOVA_CPU.C Check. -$! -$ ENDIF -$! -$! Time To End The Eclipse Check. -$! -$ ENDIF -$! -$! Check To See If We Building IBM 1130 -$! -$ IF (SIMH_MOD_NAME.EQS."IBM1130") -$ THEN -$! -$! Check To See If We We Are At The SYS$DISK:[.IBM1130]SCP.C File. -$! -$ IF (SIMHLIB_MOD_FILE_NAME.EQS."SCP") -$ THEN -$! -$! Since We Are Building The IBM 1130 Without The GUI Front Panel -$! Interface (For Now), Go Back And Get Another File As We Don't -$! Want To Add This To The IBM 1130 Library. -$! -$ GOTO NEXT_SIMHLIB_MOD_FILE -$! -$! Time To End The SYS$DISK:[.IBM1130]SCP.C Check. -$! -$ ENDIF -$! -$! Time To End The IBM 1130 Check. -$! -$ ENDIF -$! -$! Create The Source File Name. -$! -$ SIMHLIB_MOD_SOURCE_FILE = "''SIMHLIB_MOD_DIR'''SIMHLIB_MOD_FILE_NAME'.C" -$! -$! Create The Object File Name. -$! -$ SIMHLIB_MOD_OBJECT_FILE = "''SIMHLIB_MOD_DIR'''SIMHLIB_MOD_FILE_NAME'.OBJ" -$! -$! Tell The User What We Are Compiling. -$! -$ WRITE SYS$OUTPUT " ",SIMHLIB_MOD_SOURCE_FILE -$! -$! Compile The File. -$! -$ CC 'SIMHLIB_MOD_INCLUDES''SIMHLIB_MOD_DEFINE'/OBJECT='SIMHLIB_MOD_OBJECT_FILE' - - 'SIMHLIB_MOD_SOURCE_FILE' -$! -$! Add It To The Library. -$! -$ LIBRARY/REPLACE/OBJECT 'SIMHLIB_MOD_LIB_NAME' 'SIMHLIB_MOD_OBJECT_FILE' -$! -$! Delete The Object File. -$! -$ DELETE/NOCONFIRM/NOLOG 'SIMHLIB_MOD_OBJECT_FILE';* -$! -$! Go Back And Do It Again. -$! -$ GOTO NEXT_SIMHLIB_MOD_FILE -$! -$! All Done Compiling. -$! -$ SIMHLIB_MOD_FILE_DONE: -$! -$! Check To See If We Are Building The VAX Simulator. -$! -$ IF (SIMH_MOD_NAME.EQS."VAX") -$ THEN -$! -$! Define The PDP11 Files We Need To Include In The SYS$DISK:[.LIB]VAX-xxx.OLB -$! Library. -$! -$ SIMH_PDP11_LIST = "PDP11_RL,PDP11_RQ,PDP11_TS,PDP11_DZ,PDP11_LP" -$! -$! Define A Counter And Set It To "0". -$! -$ SIMH_PDP11_COUNTER = 0 -$! -$! Top Of The Loop. -$! -$ NEXT_SIMH_PDP11_NAME: -$! -$! O.K, Extract The PDP11 File From The File List. -$! -$ SIMH_PDP11_FILE_NAME = F$ELEMENT(SIMH_PDP11_COUNTER,",",SIMH_PDP11_LIST) -$! -$! Check To See If We Are At The End Of The PDP11 List. -$! -$ IF (SIMH_PDP11_FILE_NAME.EQS.",") THEN GOTO SIMH_PDP11_FILE_DONE -$! -$! Increment The Counter. -$! -$ SIMH_PDP11_COUNTER = SIMH_PDP11_COUNTER + 1 -$! -$! Create The Source File Name. -$! -$ SIMH_PDP11_SOURCE_FILE = "SYS$DISK:[.PDP11]''SIMH_PDP11_FILE_NAME'.C" -$! -$! Create The Object File Name. -$! -$ SIMH_PDP11_OBJECT_FILE = "SYS$DISK:[.PDP11]''SIMH_PDP11_FILE_NAME'.OBJ" -$! -$! Tell The User What We Are Compiling. -$! -$ WRITE SYS$OUTPUT " ",SIMH_PDP11_SOURCE_FILE -$! -$! Compile The File. -$! -$ CC 'SIMHLIB_MOD_INCLUDES''SIMHLIB_MOD_DEFINE' - - /OBJECT='SIMH_PDP11_OBJECT_FILE' 'SIMH_PDP11_SOURCE_FILE' -$! -$! Add It To The Library. -$! -$ LIBRARY/REPLACE/OBJECT 'SIMHLIB_MOD_LIB_NAME' 'SIMH_PDP11_OBJECT_FILE' -$! -$! Delete The Object File. -$! -$ DELETE/NOCONFIRM/NOLOG 'SIMH_PDP11_OBJECT_FILE';* -$! -$! Go Back And Do It Again. -$! -$ GOTO NEXT_SIMH_PDP11_NAME -$! -$! All Done Compiling. -$! -$ SIMH_PDP11_FILE_DONE: -$! -$! Time To End The VAX Check. -$! -$ ENDIF -$! -$! Display A Blank Line. -$! -$ WRITE SYS$OUTPUT "" -$! -$! Check To See If We Have The SYS$DISK:[.LIB]SIMH-xxx.OLB Library. -$! -$ IF (F$SEARCH("SYS$DISK:[.LIB]SIMH-''MACHINE_TYPE'.OLB").EQS."") -$ THEN -$! -$! Guess Not, So Build The SYS$DISK:[.LIB]SIMH-xxx.OLB Library. -$! -$ GOSUB BUILD_SIMHLIB -$! -$! End The SYS$DISK:[.LIB]SIMH-xxx.OLB Library Check. -$! -$ ENDIF -$! -$! Check To See If We Have A SYS$DISK:[.BIN] Dierctory To Put The -$! Executable In. -$! -$ IF (F$SEARCH("SYS$DISK:[]BIN.DIR").EQS."") -$ THEN -$! -$! A SYS$DISK:[.BIN] Directory Dosen't Exist So Tell The User We -$! Are Going To Create One. -$! -$ WRITE SYS$OUTPUT "Creating SYS$DISK:[.BIN]" -$! -$! Create The Directory. -$! -$ CREATE/DIRECTORY SYS$DISK:[.BIN] -$! -$! Time To End The SYS$DISK:[.BIN] Directory Check. -$! -$ ENDIF -$! -$! Tell The User What We Building. -$! -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT "Building SYS$DISK:[.BIN]''SIMH_MOD_NAME'-''MACHINE_TYPE'.EXE" -$! -$! Compile The SYS$DISK:[]SCP.C File. -$! -$ CC 'SIMHLIB_MOD_INCLUDES''SIMHLIB_MOD_DEFINE' - - /OBJECT=SYS$DISK:[]SCP-'MACHINE_TYPE'.OBJ SYS$DISK:[]SCP.C -$! -$! Link The Simulator. -$! -$ LINK/'DEBUGGER'/'TRACEBACK' - - /EXE=SYS$DISK:[.BIN]'SIMH_MOD_NAME'-'MACHINE_TYPE'.EXE - - SYS$DISK:[]SCP-'MACHINE_TYPE'.OBJ,'SIMHLIB_MOD_LIB_NAME'/LIBRARY, - - 'SIMHLIB_NAME'/LIBRARY -$! -$! Delete The SYS$DISK:[]SCP-xxx.OBJ File. -$! -$ DELETE/NOCONFIRM/NOLOG SYS$DISK:[]SCP*.OBJ*;* -$! -$! Time To Return From Where We Came From. -$! -$ RETURN -$! -$! Build The PDP18B Systems. -$! -$ BUILD_PDP18B_MOD: -$! -$! Define The PDP18B System We Are To Build. -$! -$ SIMH_PDP18B_MODS = "PDP4,PDP7,PDP9,PDP15" -$! -$! Define The Compiler INCLUDES. -$! -$ SIMH_PDP18B_INCLUDE = "/INCLUDE=(SYS$DISK:[],SYS$DISK:[.PDP18B])" -$! -$! Define A Counter And Set It To "0". -$! -$ SIMH_PDP18B_COUNTER = 0 -$! -$! Top Of The Loop. -$! -$ NEXT_SIMH_PDP18B_NAME: -$! -$! O.K, Extract The File Module From The File List. -$! -$ SIMH_PDP18B_NAME = F$ELEMENT(SIMH_PDP18B_COUNTER,",",SIMH_PDP18B_MODS) -$! -$! Check To See If We Are At The End Of The PDP18B List. -$! -$ IF (SIMH_PDP18B_NAME.EQS.",") THEN GOTO SIMH_PDP18B_DONE -$! -$! Increment The Counter. -$! -$ SIMH_PDP18B_COUNTER = SIMH_PDP18B_COUNTER + 1 -$! -$! Define The Compiler DEFINES. -$! -$ SIMH_PDP18B_DEFINE = "/DEFINE=(""''SIMH_PDP18B_NAME'=1"")" -$! -$! Check To See If We Have A SYS$DISK:[.LIB] Dierctory To Put The -$! Library In. -$! -$ IF (F$SEARCH("SYS$DISK:[]LIB.DIR").EQS."") -$ THEN -$! -$! A SYS$DISK:[.LIB] Directory Dosen't Exist So Tell The User We -$! Are Going To Create One. -$! -$ WRITE SYS$OUTPUT "Creating SYS$DISK:[.LIB]" -$! -$! Create The Directory. -$! -$ CREATE/DIRECTORY SYS$DISK:[.LIB] -$! -$! Time To End The SYS$DISK:[.LIB] Directory Check. -$! -$ ENDIF -$! -$! Create The Module Library Name. -$! -$ SIMH_PDP18B_LIB_NAME = "SYS$DISK:[.LIB]''SIMH_PDP18B_NAME'-" + - - "''MACHINE_TYPE'.OLB" -$! -$! Check To See If We Already Have A Library... -$! -$ IF (F$SEARCH(SIMH_PDP18B_LIB_NAME).EQS."") -$ THEN -$! -$! Guess Not, Create The Library. -$! -$ LIBRARY/CREATE/OBJECT 'SIMH_PDP18B_LIB_NAME' -$! -$! End The Library Check. -$! -$ ENDIF -$! -$! Tell The User What We Are Doing. -$! -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT "Compling The ''SIMH_PDP18B_LIB_NAME' Library." -$! -$! Tell The User What Compile Command We Are Going To Use. -$! -$ WRITE SYS$OUTPUT "Using Compile Command: ",CC,SIMH_PDP18B_DEFINE, - - SIMH_PDP18B_INCLUDE -$ WRITE SYS$OUTPUT "" -$! -$! Top Of The File Loop. -$! -$ NEXT_SIMH_PDP18B_FILE: -$! -$! Define The List Of Files We Are Going To Compile. -$! -$ SIMH_PDP18B_FILES = F$ELEMENT(0,";",F$ELEMENT(1,"]",- - F$SEARCH("SYS$DISK:[.PDP18B]*.C",1))) -$! -$! Extract The File Name From The File List. -$! -$ SIMH_PDP18B_FILE_NAME = F$ELEMENT(0,".",SIMH_PDP18B_FILES) -$! -$! Check To See If We Are At The End Of The File List. -$! -$ IF (SIMH_PDP18B_FILE_NAME.EQS."]") THEN GOTO SIMH_PDP18B_FILE_DONE - -$! -$! Create The Source File Name. -$! -$ SIMH_PDP18B_SOURCE_FILE = "SYS$DISK:[.PDP18B]" + SIMH_PDP18B_FILE_NAME + ".C" -$! -$! Create The Object File Name. -$! -$ SIMH_PDP18B_OBJECT_FILE = "SYS$DISK:[.PDP18B]" + SIMH_PDP18B_FILE_NAME + - - ".OBJ" -$! -$! Tell The User What We Are Compiling. -$! -$ WRITE SYS$OUTPUT " ",SIMH_PDP18B_SOURCE_FILE -$! -$! Compile The File. -$! -$ CC 'SIMH_PDP18B_DEFINE''SIMH_PDP18B_INCLUDE' - - /OBJECT='SIMH_PDP18B_OBJECT_FILE' 'SIMH_PDP18B_SOURCE_FILE' -$! -$! Add It To The Library. -$! -$ LIBRARY/REPLACE/OBJECT 'SIMH_PDP18B_LIB_NAME' 'SIMH_PDP18B_OBJECT_FILE' -$! -$! Delete The Object File. -$! -$ DELETE/NOCONFIRM/NOLOG 'SIMH_PDP18B_OBJECT_FILE';* -$! -$! Go Back And Do It Again. -$! -$ GOTO NEXT_SIMH_PDP18B_FILE -$! -$! All Done Compiling. -$! -$ SIMH_PDP18B_FILE_DONE: -$! -$! Display A Blank Line. -$! -$ WRITE SYS$OUTPUT "" -$! -$! Check To See If We Have The SYS$DISK:[.LIB]SIMH-xxx.OLB Library. -$! -$ IF (F$SEARCH("SYS$DISK:[.LIB]SIMH-''MACHINE_TYPE'.OLB").EQS."") -$ THEN -$! -$! Guess Not, So Build The SYS$DISK:[.LIB]SIMH-xxx.OLB Library. -$! -$ GOSUB BUILD_SIMHLIB -$! -$! End The SYS$DISK:[.LIB]SIMH-xxx.OLB Library Check. -$! -$ ENDIF -$! -$! Check To See If We Have A SYS$DISK:[.BIN] Dierctory To Put The -$! Executable In. -$! -$ IF (F$SEARCH("SYS$DISK:[]BIN.DIR").EQS."") -$ THEN -$! -$! A SYS$DISK:[.BIN] Directory Dosen't Exist So Tell The User We -$! Are Going To Create One. -$! -$ WRITE SYS$OUTPUT "Creating SYS$DISK:[.BIN]" -$! -$! Create The Directory. -$! -$ CREATE/DIRECTORY SYS$DISK:[.BIN] -$! -$! Time To End The SYS$DISK:[.BIN] Directory Check. -$! -$ ENDIF -$! -$! Tell The User What We Building. -$! -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT "Building SYS$DISK:[.BIN]''SIMH_PDP18B_NAME'-''MACHINE_TYPE'.EXE" -$! -$! Compile The SYS$DISK:[]SCP.C File. -$! -$ CC 'SIMH_PDP18_MOD_INCLUDES''SIMH_PDP18B_MOD_DEFINE' - - /OBJECT=SYS$DISK:[]SCP-'MACHINE_TYPE'.OBJ SYS$DISK:[]SCP.C -$! -$! Link The Simulator. -$! -$ LINK/'DEBUGGER'/'TRACEBACK' - - /EXE=SYS$DISK:[.BIN]'SIMH_PDP18B_NAME'-'MACHINE_TYPE'.EXE - - SYS$DISK:[]SCP-'MACHINE_TYPE'.OBJ,'SIMH_PDP18B_LIB_NAME'/LIBRARY, - - 'SIMHLIB_NAME'/LIBRARY -$! -$! Delete The SYS$DISK:[]SCP-xxx.OBJ File. -$! -$ DELETE/NOCONFIRM/NOLOG SYS$DISK:[]SCP*.OBJ*;* -$! -$! Go Back And Do The Next PDP18B Module. -$! -$ GOTO NEXT_SIMH_PDP18B_NAME -$! -$! End Of The PDP18B Module List. -$! -$ SIMH_PDP18B_DONE: -$! -$! All Done, Time To Return From Where We Came From. -$! -$ RETURN -$! -$! Check The User's Options. -$! -$ CHECK_OPTIONS: -$! -$! Define A Counter And Set It To "0". -$! -$ SIMH_SIMS_COUNTER = 0 -$! -$! Check To See If We Are To "Just Build Everything." -$! -$ IF (P1.EQS."").OR.(P1.EQS."ALL") -$ THEN -$! -$! P1 Is Blank Or "ALL", So Just Build Everything. -$! -$ BUILDALL = "TRUE" -$! -$! Else -$! -$ ELSE -$! -$! Top Of The Loop. -$! -$ NEXT_SIMH_SIMS: -$! -$! O.K, Extract The File Name From The File List. -$! -$ SIMH_SIMS_NAME = F$ELEMENT(SIMH_SIMS_COUNTER,",",SIMH_SIMS) -$! -$! Check To See If We Are At The End Of The Simulator List. -$! -$ IF (SIMH_SIMS_NAME.EQS.",") THEN GOTO SIMH_SIMS_ERROR -$! -$! Increment The Counter. -$! -$ SIMH_SIMS_COUNTER = SIMH_SIMS_COUNTER + 1 -$! -$! Check To See If P1 Has A Valid Argument. -$! -$ IF (P1.EQS.SIMH_SIMS_NAME) -$ THEN -$! -$! A Valid Argument. -$! -$ BUILDALL = P1 -$! -$! Exit This Routine. -$! -$ GOTO SIMH_CHECK_OPT_DONE -$! -$! Else... -$! -$ ELSE -$! -$! Go Back And Check Agianst The Next Sim In The List. -$! -$ GOTO NEXT_SIMH_SIMS -$! -$! Time To End The Valid Argument Check. -$! -$ ENDIF -$! -$! We Don't Know What The User Entered, So Tell Them. -$! -$ SIMH_SIMS_ERROR: -$! -$! Tell The User We Don't Know What They Want. -$! -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT "The Option ",P1," Is Invalid. The Valid Options Are:" -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT " ALL : Just Build "Everything". -$ WRITE SYS$OUTPUT " ALTAIR : Just Build The MITS Altair." -$ WRITE SYS$OUTPUT " ALTAIRZ80 : Just Build The MITS Altair Z80." -$ WRITE SYS$OUTPUT " ECLIPSE : Just Build The Data General Eclipse." -$ WRITE SYS$OUTPUT " H316 : Just Build The Honewell 316/516." -$ WRITE SYS$OUTPUT " HP2100 : Just Build The Hewlett-Packard HP-3100." -$ WRITE SYS$OUTPUT " I1401 : Just Build The IBM 1401." -$ WRITE SYS$OUTPUT " IBM1130 : Just Build The IBM 1130." -$ WRITE SYS$OUTPUT " INTERDATA : Just Build The Interdata 4." -$ WRITE SYS$OUTPUT " NOVA : Just Build The Data General Nova." -$ WRITE SYS$OUTPUT " PDP1 : Just Build The DEC PDP-1." -$ WRITE SYS$OUTPUT " PDP8 : Just Build The DEC PDP-8." -$ WRITE SYS$OUTPUT " PDP10 : Just Build The DEC PDP-10." -$ WRITE SYS$OUTPUT " PDP11 : Just Build The DEC PDP-11." -$ WRITE SYS$OUTPUT " PDP18B : Just Build The DEC PDP-4, PDP-7, PDP-9 And PDP-15." -$ WRITE SYS$OUTPUT " S3 : Just Build The IBM System 3" -$ WRITE SYS$OUTPUT " SDS : Just Build The SDS System" -$ WRITE SYS$OUTPUT " VAX : Just Build The DEC VAX." -$ WRITE SYS$OUTPUT "" -$! -$! Time To Exit. -$! -$ EXIT -$! -$! Time To End The BUILDALL Check. -$! -$ ENDIF -$ SIMH_CHECK_OPT_DONE: -$! -$! Check To See If We Are To Link Without Debugger Information. -$! -$ IF ((P2.EQS."").OR.(P2.EQS."NODEBUG")) -$ THEN -$! -$! P2 Is Either Blank Or "NODEBUG" So Link Without Debugger Information. -$! -$ DEBUGGER = "NODEBUG" -$! -$! Check To See If We Are On An AXP Machine. -$! -$ IF (F$GETSYI("CPU").LT.128) -$ THEN -$! -$! We Are On A VAX Machine So Use The VAX Optimizations. - -$ OPTIMIZE = "OPTIMIZE" -$! -$! Else... -$! -$ ELSE -$! -$! We Are On A AXP Machine So Use The AXP Optimizations. -$! -$ OPTIMIZE = "OPTIMIZE=(INTRINSICS,INLINE=AUTOMATIC,LEVEL=5,UNROLL=0,TUNE=HOST)/ARCH=HOST" -$! -$! Time To End The Machine Check. -$! -$ ENDIF -$! -$! Set The Link TRACEBACK Option. -$! -$ TRACEBACK = "NOTRACEBACK" -$! -$! Tell The User What They Selected. -$! -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT "Runtime Debugger Won't Be Included At Link." -$! -$! Else... -$! -$ ELSE -$! -$! Check To See If We Are To Link With Debugger Information. -$! -$ IF (P2.EQS."DEBUG") -$ THEN -$! -$! Compile With Debugger Information. -$! -$ DEBUGGER = "DEBUG" -$ OPTIMIZE = "NOOPTIMIZE" -$ TRACEBACK = "TRACEBACK" -$! -$! Tell The User What They Selected. -$! -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT "Runtime Debugger Will Be Included At Link." -$! -$! Else... -$! -$ ELSE -$! -$! Tell The User Entered An Invalid Option.. -$! -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT "The Option ",P2," Is Invalid. The Valid Options Are:" -$ WRITE SYS$OUTPUT "" -$ WRITE SYS$OUTPUT " DEBUG : Link With The Debugger Information." -$ WRITE SYS$OUTPUT " NODEBUG : Link Without The Debugger Information." -$ WRITE SYS$OUTPUT "" -$! -$! Time To EXIT. -$! -$ EXIT -$! -$! Time To End The Valid P2 Check. -$! -$ ENDIF -$! -$! Time To End The P2 Check. -$! -$ ENDIF -$! -$! Time To Return To Where We Were. -$! -$ RETURN diff --git a/dec_dz.h b/dec_dz.h index f78efe0e..dce6482b 100644 --- a/dec_dz.h +++ b/dec_dz.h @@ -28,6 +28,12 @@ dz DZ11 terminal multiplexor + 31-Oct-02 RMS Added 8b support + 12-Oct-02 RMS Added autoconfigure support + 29-Sep-02 RMS Fixed bug in set number of lines routine + Added variable vector support + New data structures + 22-Apr-02 RMS Updated for changes in sim_tmxr 28-Apr-02 RMS Fixed interrupt acknowledge, fixed SHOW DZ ADDRESS 14-Jan-02 RMS Added multiboard support 30-Dec-01 RMS Added show statistics, set disconnect @@ -62,6 +68,12 @@ #if !defined (DZ_LINES) #define DZ_LINES 8 #endif +#if !defined (DZ_8B_DFLT) +#define DZ_8B_DFLT 0 +#endif + +#define UNIT_V_8B (UNIT_V_UF + 0) /* 8b output */ +#define UNIT_8B (1 << UNIT_V_8B) #define DZ_MNOMASK (DZ_MUXES - 1) /* mask for mux no */ #define DZ_LNOMASK (DZ_LINES - 1) /* mask for lineno */ @@ -136,10 +148,13 @@ uint32 dz_txi = 0; /* xmt interrupts */ int32 dz_mctl = 0; /* modem ctrl enabled */ int32 dz_auto = 0; /* autodiscon enabled */ TMLN dz_ldsc[DZ_MUXES * DZ_LINES] = { 0 }; /* line descriptors */ -TMXR dz_desc = { DZ_MUXES * DZ_LINES, 0, NULL }; /* mux descriptor */ +TMXR dz_desc = { DZ_MUXES * DZ_LINES, 0, 0, NULL }; /* mux descriptor */ +DEVICE dz_dev; t_stat dz_rd (int32 *data, int32 PA, int32 access); t_stat dz_wr (int32 data, int32 PA, int32 access); +int32 dz_rxinta (void); +int32 dz_txinta (void); t_stat dz_svc (UNIT *uptr); t_stat dz_reset (DEVICE *dptr); t_stat dz_attach (UNIT *uptr, char *cptr); @@ -154,6 +169,7 @@ void dz_clr_txint (int32 dz); void dz_set_txint (int32 dz); t_stat dz_summ (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat dz_show (FILE *st, UNIT *uptr, int32 val, void *desc); +t_stat dz_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc); t_stat dz_setnl (UNIT *uptr, int32 val, char *cptr, void *desc); /* DZ data structures @@ -163,9 +179,10 @@ t_stat dz_setnl (UNIT *uptr, int32 val, char *cptr, void *desc); dz_reg DZ register list */ -DIB dz_dib = { 1, IOBA_DZ, IOLN_DZ * DZ_MUXES, &dz_rd, &dz_wr }; +DIB dz_dib = { IOBA_DZ, IOLN_DZ * DZ_MUXES, &dz_rd, &dz_wr, + 2, IVCL (DZRX), VEC_DZRX, { &dz_rxinta, &dz_txinta } }; -UNIT dz_unit = { UDATA (&dz_svc, UNIT_ATTABLE, 0) }; +UNIT dz_unit = { UDATA (&dz_svc, UNIT_ATTABLE + DZ_8B_DFLT, 0) }; REG dz_nlreg = { DRDATA (NLINES, dz_desc.lines, 6), PV_LEFT }; @@ -182,23 +199,27 @@ REG dz_reg[] = { { FLDATA (MDMCTL, dz_mctl, 0) }, { FLDATA (AUTODS, dz_auto, 0) }, { GRDATA (DEVADDR, dz_dib.ba, DZ_RDX, 32, 0), REG_HRO }, - { FLDATA (*DEVENB, dz_dib.enb, 0), REG_HRO }, + { GRDATA (DEVVEC, dz_dib.vec, DZ_RDX, 16, 0), REG_HRO }, { NULL } }; MTAB dz_mod[] = { - { UNIT_ATT, UNIT_ATT, "connections", NULL, NULL, &dz_summ }, + { UNIT_8B, 0, "7b", "7B", NULL }, + { UNIT_8B, UNIT_8B, "8b", "8B", NULL }, { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", &tmxr_dscln, NULL, &dz_desc }, + { UNIT_ATT, UNIT_ATT, "connections", NULL, NULL, &dz_summ }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, NULL, &dz_show, NULL }, { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, NULL, &dz_show, NULL }, { MTAB_XTD|MTAB_VDV, 010, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, &dz_dib }, - { MTAB_XTD|MTAB_VDV, 1, NULL, "ENABLED", - &set_enbdis, NULL, &dz_dib }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", - &set_enbdis, NULL, &dz_dib }, + &set_addr, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", + &set_vec, &dz_show_vec, NULL }, +#if !defined (VM_PDP10) + { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE", + &set_addr_flt, NULL, NULL }, +#endif { MTAB_XTD | MTAB_VDV | MTAB_VAL, 0, "lines", "LINES", &dz_setnl, NULL, &dz_nlreg }, { 0 } }; @@ -207,7 +228,8 @@ DEVICE dz_dev = { "DZ", &dz_unit, dz_reg, dz_mod, 1, DZ_RDX, 8, 1, DZ_RDX, 8, &tmxr_ex, &tmxr_dep, &dz_reset, - NULL, &dz_attach, &dz_detach }; + NULL, &dz_attach, &dz_detach, + &dz_dib, DEV_FLTA | DEV_DISABLE | DEV_UBUS | DEV_QBUS }; /* IO dispatch routines, I/O addresses 177601x0 - 177601x7 */ @@ -267,8 +289,8 @@ case 01: /* LPR */ dz_lpr[dz] = data; line = (dz * DZ_LINES) + LPR_GETLN (data); /* get line num */ lp = &dz_ldsc[line]; /* get line desc */ - if (dz_lpr[dz] & LPR_RCVE) lp -> rcve = 1; /* rcv enb? on */ - else lp -> rcve = 0; /* else line off */ + if (dz_lpr[dz] & LPR_RCVE) lp->rcve = 1; /* rcv enb? on */ + else lp->rcve = 0; /* else line off */ tmxr_poll_rx (&dz_desc); /* poll input */ dz_update_rcvi (); /* update rx intr */ break; @@ -286,8 +308,8 @@ case 02: /* TCR */ for (i = 0; i < DZ_LINES; i++) { /* drop hangups */ line = (dz * DZ_LINES) + i; /* get line num */ lp = &dz_ldsc[line]; /* get line desc */ - if (lp -> conn && (drop & (1 << i))) { - tmxr_msg (lp -> conn, "\r\nLine hangup\r\n"); + if (lp->conn && (drop & (1 << i))) { + tmxr_msg (lp->conn, "\r\nLine hangup\r\n"); tmxr_reset_ln (lp); /* reset line, cdet */ dz_msr[dz] &= ~(1 << (i + MSR_V_CD)); } /* end if drop */ @@ -306,7 +328,8 @@ case 03: /* TDR */ if (dz_csr[dz] & CSR_MSE) { /* enabled? */ line = (dz * DZ_LINES) + CSR_GETTL (dz_csr[dz]); lp = &dz_ldsc[line]; /* get line desc */ - tmxr_putc_ln (lp, dz_tdr[dz] & 0177); /* store char */ + tmxr_putc_ln (lp, dz_tdr[dz] & /* store char */ + ((dz_unit.flags & UNIT_8B)? 0377: 0177)); tmxr_poll_tx (&dz_desc); /* poll output */ dz_update_xmti (); } /* update int */ break; } @@ -331,7 +354,7 @@ int32 dz, t, newln; for (dz = t = 0; dz < DZ_MUXES; dz++) /* check enabled */ t = t | (dz_csr[dz] & CSR_MSE); if (t) { /* any enabled? */ - newln = tmxr_poll_conn (&dz_desc, uptr); /* poll connect */ + newln = tmxr_poll_conn (&dz_desc); /* poll connect */ if ((newln >= 0) && dz_mctl) { /* got a live one? */ dz = newln / DZ_LINES; /* get mux num */ if (dz_tcr[dz] & (1 << (newln + TCR_V_DTR))) /* DTR set? */ @@ -372,7 +395,7 @@ for (dz = 0; dz < DZ_MUXES; dz++) { /* loop thru muxes */ line = (dz * DZ_LINES) + i; /* get line num */ lp = &dz_ldsc[line]; /* get line desc */ scnt[dz] = scnt[dz] + tmxr_rqln (lp); /* sum buffers */ - if (dz_mctl && !lp -> conn) /* if disconn */ + if (dz_mctl && !lp->conn) /* if disconn */ dz_msr[dz] &= ~(1 << (i + MSR_V_CD)); /* reset car det */ } } @@ -440,7 +463,7 @@ int32 dz; for (dz = 0; dz < DZ_MUXES; dz++) { /* find 1st mux */ if (dz_rxi & (1 << dz)) { dz_clr_rxint (dz); /* clear intr */ - return (VEC_DZRX + (dz * 010)); } } /* return vector */ + return (dz_dib.vec + (dz * 010)); } } /* return vector */ return 0; } @@ -466,7 +489,7 @@ int32 dz; for (dz = 0; dz < DZ_MUXES; dz++) { /* find 1st mux */ if (dz_txi & (1 << dz)) { dz_clr_txint (dz); /* clear intr */ - return (VEC_DZTX + (dz * 010)); } } /* return vector */ + return (dz_dib.vec + 4 + (dz * 010)); } } /* return vector */ return 0; } @@ -494,7 +517,7 @@ return SCPE_OK; t_stat dz_reset (DEVICE *dptr) { -int32 i; +int32 i, ndev; for (i = 0; i < (DZ_MUXES * DZ_LINES); i++) /* init mux desc */ dz_desc.ldsc[i] = &dz_ldsc[i]; @@ -503,7 +526,8 @@ dz_rxi = dz_txi = 0; /* clr master int */ CLR_INT (DZRX); CLR_INT (DZTX); sim_cancel (&dz_unit); /* stop poll */ -return SCPE_OK; +ndev = ((dptr->flags & DEV_DIS)? 0: (dz_desc.lines / DZ_LINES)); +return auto_config (RANK_DZ, ndev); /* auto config */ } /* Attach */ @@ -568,7 +592,7 @@ return SCPE_OK; t_stat dz_setnl (UNIT *uptr, int32 val, char *cptr, void *desc) { -int32 newln, i, t; +int32 newln, i, t, ndev; t_stat r; if (cptr == NULL) return SCPE_ARG; @@ -585,14 +609,16 @@ if (newln < dz_desc.lines) { tmxr_reset_ln (&dz_ldsc[i]); } /* reset line */ if ((i % DZ_LINES) == (DZ_LINES - 1)) dz_clear (i / DZ_LINES, TRUE); } /* reset mux */ - dz_dib.lnt = newln; - } -else { - dz_dib.lnt = newln; /* set length */ - if (dev_conflict (dz_dib.ba, &dz_dib)) { /* chk addr conflict */ - dz_dib.lnt = dz_desc.lines; - return SCPE_OK; } } +dz_dib.lnt = (newln / DZ_LINES) * IOLN_DZ; /* set length */ dz_desc.lines = newln; -return SCPE_OK; +ndev = ((dz_dev.flags & DEV_DIS)? 0: (dz_desc.lines / DZ_LINES)); +return auto_config (RANK_DZ, ndev); /* auto config */ +} + +/* SHOW VECTOR processor */ + +t_stat dz_show_vec (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +return show_vec (st, uptr, ((dz_desc.lines * 2) / DZ_LINES), desc); } diff --git a/dec_pt.h b/dec_pt.h new file mode 100644 index 00000000..f73fbfe5 --- /dev/null +++ b/dec_pt.h @@ -0,0 +1,303 @@ +/* dec_pt.h: PC11 paper tape reader/punch simulator + + Copyright (c) 1993-2002, Robert M Supnik + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of Robert M Supnik shall not + be used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from Robert M Supnik. + + ptr paper tape reader + ptp paper tape punch + + 29-Sep-02 RMS Split off from pdp11_stddev.c +*/ + +#define PTRCSR_IMP (CSR_ERR+CSR_BUSY+CSR_DONE+CSR_IE) /* paper tape reader */ +#define PTRCSR_RW (CSR_IE) +#define PTPCSR_IMP (CSR_ERR + CSR_DONE + CSR_IE) /* paper tape punch */ +#define PTPCSR_RW (CSR_IE) + +int32 ptr_csr = 0; /* control/status */ +int32 ptr_stopioe = 0; /* stop on error */ +int32 ptp_csr = 0; /* control/status */ +int32 ptp_stopioe = 0; /* stop on error */ + +DEVICE ptr_dev, ptp_dev; +t_stat ptr_rd (int32 *data, int32 PA, int32 access); +t_stat ptr_wr (int32 data, int32 PA, int32 access); +t_stat ptr_svc (UNIT *uptr); +t_stat ptr_reset (DEVICE *dptr); +t_stat ptr_attach (UNIT *uptr, char *ptr); +t_stat ptr_detach (UNIT *uptr); +t_stat ptp_rd (int32 *data, int32 PA, int32 access); +t_stat ptp_wr (int32 data, int32 PA, int32 access); +t_stat ptp_svc (UNIT *uptr); +t_stat ptp_reset (DEVICE *dptr); +t_stat ptp_attach (UNIT *uptr, char *ptr); +t_stat ptp_detach (UNIT *uptr); + +/* PTR data structures + + ptr_dev PTR device descriptor + ptr_unit PTR unit descriptor + ptr_reg PTR register list +*/ + +DIB ptr_dib = { IOBA_PTR, IOLN_PTR, &ptr_rd, &ptr_wr, + 1, IVCL (PTR), VEC_PTR, { NULL } }; + +UNIT ptr_unit = { + UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), + SERIAL_IN_WAIT }; + +REG ptr_reg[] = { + { GRDATA (BUF, ptr_unit.buf, PT_RDX, 8, 0) }, + { GRDATA (CSR, ptr_csr, PT_RDX, 16, 0) }, + { FLDATA (INT, int_req, INT_V_PTR) }, + { FLDATA (ERR, ptr_csr, CSR_V_ERR) }, + { FLDATA (BUSY, ptr_csr, CSR_V_BUSY) }, + { FLDATA (DONE, ptr_csr, CSR_V_DONE) }, + { FLDATA (IE, ptr_csr, CSR_V_IE) }, + { DRDATA (POS, ptr_unit.pos, 32), PV_LEFT }, + { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, + { FLDATA (STOP_IOE, ptr_stopioe, 0) }, + { FLDATA (DEVDIS, ptr_dev.flags, DEV_V_DIS), REG_HRO }, + { NULL } }; + +MTAB ptr_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, + NULL, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, + NULL, &show_vec, NULL }, + { 0 } }; + +DEVICE ptr_dev = { + "PTR", &ptr_unit, ptr_reg, ptr_mod, + 1, 10, 31, 1, PT_RDX, 8, + NULL, NULL, &ptr_reset, + NULL, &ptr_attach, &ptr_detach, + &ptr_dib, DEV_DISABLE | PT_DIS | DEV_UBUS | DEV_QBUS }; + +/* PTP data structures + + ptp_dev PTP device descriptor + ptp_unit PTP unit descriptor + ptp_reg PTP register list +*/ + +DIB ptp_dib = { IOBA_PTP, IOLN_PTP, &ptp_rd, &ptp_wr, + 1, IVCL (PTP), VEC_PTP, { NULL } }; + +UNIT ptp_unit = { + UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; + +REG ptp_reg[] = { + { GRDATA (BUF, ptp_unit.buf, PT_RDX, 8, 0) }, + { GRDATA (CSR, ptp_csr, PT_RDX, 16, 0) }, + { FLDATA (INT, int_req, INT_V_PTP) }, + { FLDATA (ERR, ptp_csr, CSR_V_ERR) }, + { FLDATA (DONE, ptp_csr, CSR_V_DONE) }, + { FLDATA (IE, ptp_csr, CSR_V_IE) }, + { DRDATA (POS, ptp_unit.pos, 32), PV_LEFT }, + { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, + { FLDATA (STOP_IOE, ptp_stopioe, 0) }, + { NULL } }; + +MTAB ptp_mod[] = { + { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, + NULL, &show_addr, NULL }, + { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, + NULL, &show_vec, NULL }, + { 0 } }; + +DEVICE ptp_dev = { + "PTP", &ptp_unit, ptp_reg, ptp_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ptp_reset, + NULL, &ptp_attach, &ptp_detach, + &ptp_dib, DEV_DISABLE | PT_DIS | DEV_UBUS | DEV_QBUS }; + +/* Paper tape reader I/O address routines */ + +t_stat ptr_rd (int32 *data, int32 PA, int32 access) +{ +switch ((PA >> 1) & 01) { /* decode PA<1> */ +case 0: /* ptr csr */ + *data = ptr_csr & PTRCSR_IMP; + return SCPE_OK; +case 1: /* ptr buf */ + ptr_csr = ptr_csr & ~CSR_DONE; + CLR_INT (PTR); + *data = ptr_unit.buf & 0377; + return SCPE_OK; } +return SCPE_NXM; /* can't get here */ +} + +t_stat ptr_wr (int32 data, int32 PA, int32 access) +{ +switch ((PA >> 1) & 01) { /* decode PA<1> */ +case 0: /* ptr csr */ + if (PA & 1) return SCPE_OK; + if ((data & CSR_IE) == 0) CLR_INT (PTR); + else if (((ptr_csr & CSR_IE) == 0) && (ptr_csr & (CSR_ERR | CSR_DONE))) + SET_INT (PTR); + if (data & CSR_GO) { + ptr_csr = (ptr_csr & ~CSR_DONE) | CSR_BUSY; + CLR_INT (PTR); + if (ptr_unit.flags & UNIT_ATT) /* data to read? */ + sim_activate (&ptr_unit, ptr_unit.wait); + else sim_activate (&ptr_unit, 0); } /* error if not */ + ptr_csr = (ptr_csr & ~PTRCSR_RW) | (data & PTRCSR_RW); + return SCPE_OK; +case 1: /* ptr buf */ + return SCPE_OK; } /* end switch PA */ +return SCPE_NXM; /* can't get here */ +} + +/* Paper tape reader service */ + +t_stat ptr_svc (UNIT *uptr) +{ +int32 temp; + +ptr_csr = (ptr_csr | CSR_ERR) & ~CSR_BUSY; +if (ptr_csr & CSR_IE) SET_INT (PTR); +if ((ptr_unit.flags & UNIT_ATT) == 0) + return IORETURN (ptr_stopioe, SCPE_UNATT); +if ((temp = getc (ptr_unit.fileref)) == EOF) { + if (feof (ptr_unit.fileref)) { + if (ptr_stopioe) printf ("PTR end of file\n"); + else return SCPE_OK; } + else perror ("PTR I/O error"); + clearerr (ptr_unit.fileref); + return SCPE_IOERR; } +ptr_csr = (ptr_csr | CSR_DONE) & ~CSR_ERR; +ptr_unit.buf = temp & 0377; +ptr_unit.pos = ptr_unit.pos + 1; +return SCPE_OK; +} + +/* Paper tape reader support routines */ + +t_stat ptr_reset (DEVICE *dptr) +{ +ptr_unit.buf = 0; +ptr_csr = 0; +if ((ptr_unit.flags & UNIT_ATT) == 0) ptr_csr = ptr_csr | CSR_ERR; +CLR_INT (PTR); +sim_cancel (&ptr_unit); +return SCPE_OK; +} + +t_stat ptr_attach (UNIT *uptr, char *cptr) +{ +t_stat reason; + +reason = attach_unit (uptr, cptr); +if ((ptr_unit.flags & UNIT_ATT) == 0) ptr_csr = ptr_csr | CSR_ERR; +else ptr_csr = ptr_csr & ~CSR_ERR; +return reason; +} + +t_stat ptr_detach (UNIT *uptr) +{ +ptr_csr = ptr_csr | CSR_ERR; +return detach_unit (uptr); +} + +/* Paper tape punch I/O address routines */ + +t_stat ptp_rd (int32 *data, int32 PA, int32 access) +{ +switch ((PA >> 1) & 01) { /* decode PA<1> */ +case 0: /* ptp csr */ + *data = ptp_csr & PTPCSR_IMP; + return SCPE_OK; +case 1: /* ptp buf */ + *data = ptp_unit.buf; + return SCPE_OK; } +return SCPE_NXM; /* can't get here */ +} + +t_stat ptp_wr (int32 data, int32 PA, int32 access) +{ +switch ((PA >> 1) & 01) { /* decode PA<1> */ +case 0: /* ptp csr */ + if (PA & 1) return SCPE_OK; + if ((data & CSR_IE) == 0) CLR_INT (PTP); + else if (((ptp_csr & CSR_IE) == 0) && (ptp_csr & (CSR_ERR | CSR_DONE))) + SET_INT (PTP); + ptp_csr = (ptp_csr & ~PTPCSR_RW) | (data & PTPCSR_RW); + return SCPE_OK; +case 1: /* ptp buf */ + if ((PA & 1) == 0) ptp_unit.buf = data & 0377; + ptp_csr = ptp_csr & ~CSR_DONE; + CLR_INT (PTP); + if (ptp_unit.flags & UNIT_ATT) /* file to write? */ + sim_activate (&ptp_unit, ptp_unit.wait); + else sim_activate (&ptp_unit, 0); /* error if not */ + return SCPE_OK; } /* end switch PA */ +return SCPE_NXM; /* can't get here */ +} + +/* Paper tape punch service */ + +t_stat ptp_svc (UNIT *uptr) +{ +ptp_csr = ptp_csr | CSR_ERR | CSR_DONE; +if (ptp_csr & CSR_IE) SET_INT (PTP); +if ((ptp_unit.flags & UNIT_ATT) == 0) + return IORETURN (ptp_stopioe, SCPE_UNATT); +if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { + perror ("PTP I/O error"); + clearerr (ptp_unit.fileref); + return SCPE_IOERR; } +ptp_csr = ptp_csr & ~CSR_ERR; +ptp_unit.pos = ptp_unit.pos + 1; +return SCPE_OK; +} + +/* Paper tape punch support routines */ + +t_stat ptp_reset (DEVICE *dptr) +{ +ptp_unit.buf = 0; +ptp_csr = CSR_DONE; +if ((ptp_unit.flags & UNIT_ATT) == 0) ptp_csr = ptp_csr | CSR_ERR; +CLR_INT (PTP); +sim_cancel (&ptp_unit); /* deactivate unit */ +return SCPE_OK; +} + +t_stat ptp_attach (UNIT *uptr, char *cptr) +{ +t_stat reason; + +reason = attach_unit (uptr, cptr); +if ((ptp_unit.flags & UNIT_ATT) == 0) ptp_csr = ptp_csr | CSR_ERR; +else ptp_csr = ptp_csr & ~CSR_ERR; +return reason; +} + +t_stat ptp_detach (UNIT *uptr) +{ +ptp_csr = ptp_csr | CSR_ERR; +return detach_unit (uptr); +} diff --git a/descrip.mms b/descrip.mms new file mode 100644 index 00000000..cd76486d --- /dev/null +++ b/descrip.mms @@ -0,0 +1,1000 @@ +# +# DESCRIP.MMS +# Written By: Robert Alan Byer +# byer@mail.ourservers.net +# +# This MMS/MMK build script is used to compile the various simulators in +# the SIMH package for OpenVMS using DEC C v6.0-001. +# +# Note: On VAX, the PDP-10 and VAX simulator will not be built due to the +# fact that INT64 is required for those simulators. +# +# +# This build script will accept the following build options. +# +# ALL Just Build "Everything". +# ALTAIR Just Build The MITS Altair. +# ALTAIRZ80 Just Build The MITS Altair Z80. +# ECLIPSE Just Build The Data General Eclipse. +# GRI Just Build The GRI Corporation GRI-909. +# H316 Just Build The Honewell 316/516. +# HP2100 Just Build The Hewlett-Packard HP-2100. +# I1401 Just Build The IBM 1401. +# IBM1130 Just Build The IBM 1130. +# ID16 Just Build The Interdata 16-bit CPU. +# ID32 Just Build The Interdata 32-bit CPU. +# NOVA Just Build The Data General Nova. +# PDP1 Just Build The DEC PDP-1. +# PDP4 Just Build The DEC PDP-4. +# PDP7 Just Build The DEC PDP-7. +# PDP8 Just Build The DEC PDP-8. +# PDP9 Just Build The DEC PDP-9. +# PDP10 Just Build The DEC PDP-10. +# PDP11 Just Build The DEC PDP-11. +# PDP15 Just Build The DEC PDP-15. +# S3 Just Build The IBM System 3. +# SDS Just Build The SDS 940. +# VAX Just Build The DEC VAX. +# +# To build with debugging enabled (which will also enable traceback +# information) use.. +# +# MMK/FORCE/MACRO=(DEBUG=1) +# + +# +# Define The BIN Directory Where The Executables Will Go. +# +BIN_DIR = SYS$DISK:[.BIN] + +# +# Define Our Library Directory. +# +LIB_DIR = SYS$DISK:[.LIB] + +# +# Let's See If We Are Going To Build With DEBUG Enabled. +# +.IFDEF DEBUG +CC_DEBUG = /DEBUG +LINK_DEBUG = /DEBUG/TRACEBACK +CC_OPTIMIZE = /NOOPTIMIZE +.ELSE +CC_DEBUG = /NODEBUG +LINK_DEBUG = /NODEBUG/NOTRACEBACK +.IFDEF __ALPHA__ +CC_OPTIMIZE = /OPTIMIZE=(LEVEL=5,TUNE=HOST)/ARCH=HOST +CC_FLAGS = /PREFIX=ALL +ARCH = AXP +.ELSE +CC_OPTIMIZE = /OPTIMIZE +ARCH = VAX +.ENDIF +.ENDIF + +# +# Define Our Compiler Flags. +# +CC_FLAGS = $(CC_FLAGS)$(CC_OPTIMIZE)/NEST=PRIMARY/NAME=(AS_IS,SHORTENED) + +# +# Define The Compile Command. +# +CC = CC $(CC_FLAGS) + +# +# First, Let's Check To Make Sure We Have A SYS$DISK:[.BIN] And +# SYS$DISK:[.LIB] Directory. +# +.FIRST + @ IF (F$SEARCH("SYS$DISK:[]BIN.DIR").EQS."") THEN CREATE/DIRECTORY $(BIN_DIR) + @ IF (F$SEARCH("SYS$DISK:[]LIB.DIR").EQS."") THEN CREATE/DIRECTORY $(LIB_DIR) + +# +# Core SIMH File Definitions. +# +SIMH_DIR = SYS$DISK:[] +SIMH_LIB = $(LIB_DIR)SIMH-$(ARCH).OLB +SIMH_SOURCE = $(SIMH_DIR)SCP_TTY.C,$(SIMH_DIR)SIM_SOCK.C,\ + $(SIMH_DIR)SIM_TMXR.C,$(SIMH_DIR)SIM_ETHER.C +SIMH_OBJS = $(SIMH_DIR)SCP_TTY.OBJ,$(SIMH_DIR)SIM_SOCK.OBJ,\ + $(SIMH_DIR)SIM_TMXR.OBJ,$(SIMH_DIR)SIM_ETHER.OBJ + +# +# MITS Altair Simulator Definitions. +# +ALTAIR_DIR = SYS$DISK:[.ALTAIR] +ALTAIR_LIB = $(LIB_DIR)ALTAIR-$(ARCH).OLB +ALTAIR_SOURCE = $(ALTAIR_DIR)ALTAIR_SIO.C,$(ALTAIR_DIR)ALTAIR_CPU.C,\ + $(ALTAIR_DIR)ALTAIR_DSK.C,$(ALTAIR_DIR)ALTAIR_SYS.C +ALTAIR_OBJS = $(ALTAIR_DIR)ALTAIR_SIO.OBJ,$(ALTAIR_DIR)ALTAIR_CPU.OBJ,\ + $(ALTAIR_DIR)ALTAIR_DSK.OBJ,$(ALTAIR_DIR)ALTAIR_SYS.OBJ +ALTAIR_OPTIONS = /INCLUDE=($(SIMH_DIR),$(ALTAIR_DIR)) + +# +# MITS Altair Z80 Simulator Definitions. +# +ALTAIRZ80_DIR = SYS$DISK:[.ALTAIRZ80] +ALTAIRZ80_LIB = $(LIB_DIR)ALTAIRZ80-$(ARCH).OLB +ALTAIRZ80_SOURCE = $(ALTAIRZ80_DIR)ALTAIRZ80_CPU.C,\ + $(ALTAIRZ80_DIR)ALTAIRZ80_DSK.C,\ + $(ALTAIRZ80_DIR)ALTAIRZ80_SIO.C,\ + $(ALTAIRZ80_DIR)ALTAIRZ80_SYS.C,\ + $(ALTAIRZ80_DIR)ALTAIRZ80_HDSK.C +ALTAIRZ80_OBJS = $(ALTAIRZ80_DIR)ALTAIRZ80_CPU.OBJ,\ + $(ALTAIRZ80_DIR)ALTAIRZ80_DSK.OBJ,\ + $(ALTAIRZ80_DIR)ALTAIRZ80_SIO.OBJ,\ + $(ALTAIRZ80_DIR)ALTAIRZ80_SYS.OBJ,\ + $(ALTAIRZ80_DIR)ALTAIRZ80_HDSK.OBJ +ALTAIRZ80_OPTIONS = /INCLUDE=($(SIMH_DIR),$(ALTAIRZ80_DIR)) + +# +# Data General Nova Simulator Definitions. +# +NOVA_DIR = SYS$DISK:[.NOVA] +NOVA_LIB = $(LIB_DIR)NOVA-$(ARCH).OLB +NOVA_SOURCE = $(NOVA_DIR)NOVA_SYS.C,$(NOVA_DIR)NOVA_CPU.C,\ + $(NOVA_DIR)NOVA_DKP.C,$(NOVA_DIR)NOVA_DSK.C,\ + $(NOVA_DIR)NOVA_LP.C,$(NOVA_DIR)NOVA_MTA.C,\ + $(NOVA_DIR)NOVA_PLT.C,$(NOVA_DIR)NOVA_PT.C,\ + $(NOVA_DIR)NOVA_CLK.C,$(NOVA_DIR)NOVA_TT.C,\ + $(NOVA_DIR)NOVA_TT1.C +NOVA_OBJS = $(NOVA_DIR)NOVA_SYS.OBJ,$(NOVA_DIR)NOVA_CPU.OBJ,\ + $(NOVA_DIR)NOVA_DKP.OBJ,$(NOVA_DIR)NOVA_DSK.OBJ,\ + $(NOVA_DIR)NOVA_LP.OBJ,$(NOVA_DIR)NOVA_MTA.OBJ,\ + $(NOVA_DIR)NOVA_PLT.OBJ,$(NOVA_DIR)NOVA_PT.OBJ,\ + $(NOVA_DIR)NOVA_CLK.OBJ,$(NOVA_DIR)NOVA_TT.OBJ,\ + $(NOVA_DIR)NOVA_TT1.OBJ +NOVA_OPTIONS = /INCLUDE=($(SIMH_DIR),$(NOVA_DIR)) + +# +# Data General Eclipse Simulator Definitions. +# +ECLIPSE_LIB = $(LIB_DIR)ECLIPSE-$(ARCH).OLB +ECLIPSE_SOURCE = $(NOVA_DIR)ECLIPSE_CPU.C,$(NOVA_DIR)ECLIPSE_TT.C,\ + $(NOVA_DIR)NOVA_SYS.C,$(NOVA_DIR)NOVA_DKP.C,\ + $(NOVA_DIR)NOVA_DSK.C,$(NOVA_DIR)NOVA_LP.C,\ + $(NOVA_DIR)NOVA_MTA.C,$(NOVA_DIR)NOVA_PLT.C,\ + $(NOVA_DIR)NOVA_PT.C,$(NOVA_DIR)NOVA_CLK.C,\ + $(NOVA_DIR)NOVA_TT1.C +ECLIPSE_OBJS = $(NOVA_DIR)ECLIPSE_CPU.OBJ,$(NOVA_DIR)ECLIPSE_TT.OBJ,\ + $(NOVA_DIR)NOVA_SYS.OBJ,$(NOVA_DIR)NOVA_DKP.OBJ,\ + $(NOVA_DIR)NOVA_DSK.OBJ,$(NOVA_DIR)NOVA_LP.OBJ,\ + $(NOVA_DIR)NOVA_MTA.OBJ,$(NOVA_DIR)NOVA_PLT.OBJ,\ + $(NOVA_DIR)NOVA_PT.OBJ,$(NOVA_DIR)NOVA_CLK.OBJ,\ + $(NOVA_DIR)NOVA_TT1.OBJ +ECLIPSE_OPTIONS = /INCLUDE=($(SIMH_DIR),$(NOVA_DIR))/DEFINE=("ECLIPSE=1") + +# +# GRI Corporation GRI-909 Simulator Definitions. +# +GRI_DIR = SYS$DISK:[.GRI] +GRI_LIB = $(LIB_DIR)GRI-$(ARCH).OLB +GRI_SOURCE = $(GRI_DIR)GRI_CPU.C,$(GRI_DIR)GRI_STDDEV.C,$(GRI_DIR)GRI_SYS.C +GRI_OBJS = $(GRI_DIR)GRI_CPU.OBJ,$(GRI_DIR)GRI_STDDEV.OBJ,\ + $(GRI_DIR)GRI_SYS.OBJ +GRI_OPTIONS = /INCLUDE=($(SIMH_DIR),$(GRI_DIR)) + +# +# Honeywell 316/516 Simulator Definitions. +# +H316_DIR = SYS$DISK:[.H316] +H316_LIB = $(LIB_DIR)H316-$(ARCH).OLB +H316_SOURCE = $(H316_DIR)H316_STDDEV.C,$(H316_DIR)H316_LP.C,\ + $(H316_DIR)H316_CPU.C,$(H316_DIR)H316_SYS.C +H316_OBJS = $(H316_DIR)H316_STDDEV.OBJ,$(H316_DIR)H316_LP.OBJ,\ + $(H316_DIR)H316_CPU.OBJ,$(H316_DIR)H316_SYS.OBJ +H316_OPTIONS = /INCLUDE=($(SIMH_DIR),$(H316_DIR)) + +# +# Hewlett-Packard HP-2100 Simulator Definitions. +# +HP2100_DIR = SYS$DISK:[.HP2100] +HP2100_LIB = $(LIB_DIR)HP2100-$(ARCH).OLB +HP2100_SOURCE = $(HP2100_DIR)HP2100_STDDEV.C,$(HP2100_DIR)HP2100_DP.C,\ + $(HP2100_DIR)HP2100_DQ.C,$(HP2100_DIR)HP2100_DR.C,\ + $(HP2100_DIR)HP2100_LPS.C,$(HP2100_DIR)HP2100_MS.C,\ + $(HP2100_DIR)HP2100_MT.C,$(HP2100_DIR)HP2100_MUX.C,\ + $(HP2100_DIR)HP2100_CPU.C,$(HP2100_DIR)HP2100_FP.C,\ + $(HP2100_DIR)HP2100_SYS.C,$(HP2100_DIR)HP2100_LPT.C +HP2100_OBJS = $(HP2100_DIR)HP2100_STDDEV.OBJ,$(HP2100_DIR)HP2100_DP.OBJ,\ + $(HP2100_DIR)HP2100_DQ.OBJ,$(HP2100_DIR)HP2100_DR.OBJ,\ + $(HP2100_DIR)HP2100_LPS.OBJ,$(HP2100_DIR)HP2100_MS.OBJ,\ + $(HP2100_DIR)HP2100_MT.OBJ,$(HP2100_DIR)HP2100_MUX.OBJ,\ + $(HP2100_DIR)HP2100_CPU.OBJ,$(HP2100_DIR)HP2100_FP.OBJ,\ + $(HP2100_DIR)HP2100_SYS.OBJ,$(HP2100_DIR)HP2100_LPT.OBJ +HP2100_OPTIONS = /INCLUDE=($(SIMH_DIR),$(HP2100_DIR)) + +# +# Interdata 16-bit CPU. +# +ID16_DIR = SYS$DISK:[.INTERDATA] +ID16_LIB = $(LIB_DIR)ID16-$(ARCH).OLB +ID16_SOURCE = $(ID16_DIR)ID16_CPU.C,$(ID16_DIR)ID16_SYS.C,$(ID16_DIR)ID_DP.C,\ + $(ID16_DIR)ID_FD.C,$(ID16_DIR)ID_FP.C,$(ID16_DIR)ID_IDC.C,\ + $(ID16_DIR)ID_IO.C,$(ID16_DIR)ID_LP.C,$(ID16_DIR)ID_MT.C,\ + $(ID16_DIR)ID_PAS.C,$(ID16_DIR)ID_PT.C,$(ID16_DIR)ID_TT.C,\ + $(ID16_DIR)ID_UVC.C +ID16_OBJS = $(ID16_DIR)ID16_CPU.OBJ,$(ID16_DIR)ID16_SYS.OBJ,$(ID16_DIR)ID_DP.OBJ,\ + $(ID16_DIR)ID_FD.OBJ,$(ID16_DIR)ID_FP.OBJ,$(ID16_DIR)ID_IDC.OBJ,\ + $(ID16_DIR)ID_IO.OBJ,$(ID16_DIR)ID_LP.OBJ,$(ID16_DIR)ID_MT.OBJ,\ + $(ID16_DIR)ID_PAS.OBJ,$(ID16_DIR)ID_PT.OBJ,$(ID16_DIR)ID_TT.OBJ,\ + $(ID16_DIR)ID_UVC.OBJ +ID16_OPTIONS = /INCLUDE=($(SIMH_DIR),$(ID16_DIR)) + +# +# Interdata 32-bit CPU. +# +ID32_DIR = SYS$DISK:[.INTERDATA] +ID32_LIB = $(LIB_DIR)ID32-$(ARCH).OLB +ID32_SOURCE = $(ID32_DIR)ID32_CPU.C,$(ID32_DIR)ID32_SYS.C,$(ID32_DIR)ID_DP.C,\ + $(ID32_DIR)ID_FD.C,$(ID32_DIR)ID_FP.C,$(ID32_DIR)ID_IDC.C,\ + $(ID32_DIR)ID_IO.C,$(ID32_DIR)ID_LP.C,$(ID32_DIR)ID_MT.C,\ + $(ID32_DIR)ID_PAS.C,$(ID32_DIR)ID_PT.C,$(ID32_DIR)ID_TT.C,\ + $(ID32_DIR)ID_UVC.C +ID32_OBJS = $(ID32_DIR)ID32_CPU.OBJ,$(ID32_DIR)ID32_SYS.OBJ,\ + $(ID32_DIR)ID_DP.OBJ,$(ID32_DIR)ID_FD.OBJ,\ + $(ID32_DIR)ID_FP.OBJ,$(ID32_DIR)ID_IDC.OBJ,\ + $(ID32_DIR)ID_IO.OBJ,$(ID32_DIR)ID_LP.OBJ,$(ID32_DIR)ID_MT.OBJ,\ + $(ID32_DIR)ID_PAS.OBJ,$(ID32_DIR)ID_PT.OBJ,$(ID32_DIR)ID_TT.OBJ,\ + $(ID32_DIR)ID_UVC.OBJ +ID32_OPTIONS = /INCLUDE=($(SIMH_DIR),$(ID32_DIR)) + +# +# IBM 1130 Simulator Definitions. +# +IBM1130_DIR = SYS$DISK:[.IBM1130] +IBM1130_LIB = $(LIB_DIR)IBM1130-$(ARCH).OLB +IBM1130_SOURCE = $(IBM1130_DIR)IBM1130_CPU.C,$(IBM1130_DIR)IBM1130_CR.C,\ + $(IBM1130_DIR)IBM1130_DISK.C,$(IBM1130_DIR)IBM1130_STDDEV.C,\ + $(IBM1130_DIR)IBM1130_SYS.C,$(IBM1130_DIR)IBM1130_GDU.C,\ + $(IBM1130_DIR)IBM1130_GUI.C,$(IBM1130_DIR)IBM1130_PRT.C +IBM1130_OBJS = $(IBM1130_DIR)IBM1130_CPU.OBJ,$(IBM1130_DIR)IBM1130_CR.OBJ,\ + $(IBM1130_DIR)IBM1130_DISK.OBJ,$(IBM1130_DIR)IBM1130_STDDEV.OBJ,\ + $(IBM1130_DIR)IBM1130_SYS.OBJ,$(IBM1130_DIR)IBM1130_GDU.OBJ,\ + $(IBM1130_DIR)IBM1130_GUI.OBJ,$(IBM1130_DIR)IBM1130_PRT.OBJ +IBM1130_OPTIONS = /INCLUDE=($(SIMH_DIR),$(IBM1130_DIR)) + +# +# IBM 1401 Simulator Definitions. +# +I1401_DIR = SYS$DISK:[.I1401] +I1401_LIB = $(LIB_DIR)I1401-$(ARCH).OLB +I1401_SOURCE = $(I1401_DIR)I1401_LP.C,$(I1401_DIR)I1401_CPU.C,\ + $(I1401_DIR)I1401_IQ.C,$(I1401_DIR)I1401_CD.C,\ + $(I1401_DIR)I1401_MT.C,$(I1401_DIR)I1401_DP.C,\ + $(I1401_DIR)I1401_SYS.C +I1401_OBJS = $(I1401_DIR)I1401_LP.OBJ,$(I1401_DIR)I1401_CPU.OBJ,\ + $(I1401_DIR)I1401_IQ.OBJ,$(I1401_DIR)I1401_CD.OBJ,\ + $(I1401_DIR)I1401_MT.OBJ,$(I1401_DIR)I1401_DP.OBJ,\ + $(I1401_DIR)I1401_SYS.OBJ +I1401_OPTIONS = /INCLUDE=($(SIMH_DIR),$(I1401_DIR)) + + +# +# IBM 1620 Simulators Definitions. +# +I1620_DIR = SYS$DISK:[.I1620] +I1620_LIB = $(LIB_DIR)I1620-$(ARCH).OLB +I1620_SOURCE = $(I1620_DIR)I1620_CD.C,$(I1620_DIR)I1620_DP.C,\ + $(I1620_DIR)I1620_PT.C,$(I1620_DIR)I1620_TTY.C,\ + $(I1620_DIR)I1620_CPU.C,$(I1620_DIR)I1620_LP.C,\ + $(I1620_DIR)I1620_FP.C,$(I1620_DIR)I1620_SYS.C +I1620_OBJS = $(I1620_DIR)I1620_CD.OBJ,$(I1620_DIR)I1620_DP.OBJ,\ + $(I1620_DIR)I1620_PT.OBJ,$(I1620_DIR)I1620_TTY.OBJ,\ + $(I1620_DIR)I1620_CPU.OBJ,$(I1620_DIR)I1620_LP.OBJ,\ + $(I1620_DIR)I1620_FP.OBJ,$(I1620_DIR)I1620_SYS.OBJ +I1620_OPTIONS = /INCLUDE=($(SIMH_DIR),$(I1620_DIR)) + +# +# PDP-1 Simulator Definitions. +# +PDP1_DIR = SYS$DISK:[.PDP1] +PDP1_LIB = $(LIB_DIR)PDP1-$(ARCH).OLB +PDP1_SOURCE = $(PDP1_DIR)PDP1_LP.C,$(PDP1_DIR)PDP1_CPU.C,\ + $(PDP1_DIR)PDP1_STDDEV.C,$(PDP1_DIR)PDP1_SYS.C,\ + $(PDP1_DIR)PDP1_DT.C +PDP1_OBJS = $(PDP1_DIR)PDP1_LP.OBJ,$(PDP1_DIR)PDP1_CPU.OBJ,\ + $(PDP1_DIR)PDP1_STDDEV.OBJ,$(PDP1_DIR)PDP1_SYS.OBJ,\ + $(PDP1_DIR)PDP1_DT.OBJ +PDP1_OPTIONS = /INCLUDE=($(SIMH_DIR),$(PDP1_DIR)) + +# +# Digital Equipment PDP-8 Simulator Definitions. +# +PDP8_DIR = SYS$DISK:[.PDP8] +PDP8_LIB = $(LIB_DIR)PDP8-$(ARCH).OLB +PDP8_SOURCE = $(PDP8_DIR)PDP8_CPU.C,$(PDP8_DIR)PDP8_CLK.C,\ + $(PDP8_DIR)PDP8_DF.C,$(PDP8_DIR)PDP8_DT.C,\ + $(PDP8_DIR)PDP8_LP.C,$(PDP8_DIR)PDP8_MT.C,\ + $(PDP8_DIR)PDP8_PT.C,$(PDP8_DIR)PDP8_RF.C,\ + $(PDP8_DIR)PDP8_RK.C,$(PDP8_DIR)PDP8_RX.C,\ + $(PDP8_DIR)PDP8_SYS.C,$(PDP8_DIR)PDP8_TT.C,\ + $(PDP8_DIR)PDP8_TTX.C,$(PDP8_DIR)PDP8_RL.C +PDP8_OBJS = $(PDP8_DIR)PDP8_CPU.OBJ,$(PDP8_DIR)PDP8_CLK.OBJ,\ + $(PDP8_DIR)PDP8_DF.OBJ,$(PDP8_DIR)PDP8_DT.OBJ,\ + $(PDP8_DIR)PDP8_LP.OBJ,$(PDP8_DIR)PDP8_MT.OBJ,\ + $(PDP8_DIR)PDP8_PT.OBJ,$(PDP8_DIR)PDP8_RF.OBJ,\ + $(PDP8_DIR)PDP8_RK.OBJ,$(PDP8_DIR)PDP8_RX.OBJ,\ + $(PDP8_DIR)PDP8_SYS.OBJ,$(PDP8_DIR)PDP8_TT.OBJ,\ + $(PDP8_DIR)PDP8_TTX.OBJ,$(PDP8_DIR)PDP8_RL.OBJ +PDP8_OPTIONS = /INCLUDE=($(SIMH_DIR),$(PDP8_DIR)) + +# +# Digital Equipment PDP-4, PDP-7, PDP-9 And PDP-15 Simulator Definitions. +# +PDP18B_DIR = SYS$DISK:[.PDP18B] +PDP4_LIB = $(LIB_DIR)PDP4-$(ARCH).OLB +PDP7_LIB = $(LIB_DIR)PDP7-$(ARCH).OLB +PDP9_LIB = $(LIB_DIR)PDP9-$(ARCH).OLB +PDP15_LIB = $(LIB_DIR)PDP15-$(ARCH).OLB +PDP18B_SOURCE = $(PDP18B_DIR)PDP18B_DT.C,$(PDP18B_DIR)PDP18B_DRM.C,\ + $(PDP18B_DIR)PDP18B_CPU.C,$(PDP18B_DIR)PDP18B_LP.C,\ + $(PDP18B_DIR)PDP18B_MT.C,$(PDP18B_DIR)PDP18B_RF.C,\ + $(PDP18B_DIR)PDP18B_RP.C,$(PDP18B_DIR)PDP18B_STDDEV.C,\ + $(PDP18B_DIR)PDP18B_SYS.C,$(PDP18B_DIR)PDP18B_TT1.C +PDP18B_OBJS = $(PDP18B_DIR)PDP18B_DT.OBJ,$(PDP18B_DIR)PDP18B_DRM.OBJ,\ + $(PDP18B_DIR)PDP18B_CPU.OBJ,$(PDP18B_DIR)PDP18B_LP.OBJ,\ + $(PDP18B_DIR)PDP18B_MT.OBJ,$(PDP18B_DIR)PDP18B_RF.OBJ,\ + $(PDP18B_DIR)PDP18B_RP.OBJ,$(PDP18B_DIR)PDP18B_STDDEV.OBJ,\ + $(PDP18B_DIR)PDP18B_SYS.OBJ,$(PDP18B_DIR)PDP18B_TT1.OBJ +PDP4_OPTIONS = /INCLUDE=($(SIMH_DIR),$(PDP18B_DIR))/DEFINE=("PDP4=1") +PDP7_OPTIONS = /INCLUDE=($(SIMH_DIR),$(PDP18B_DIR))/DEFINE=("PDP7=1") +PDP9_OPTIONS = /INCLUDE=($(SIMH_DIR),$(PDP18B_DIR))/DEFINE=("PDP9=1") +PDP15_OPTIONS = /INCLUDE=($(SIMH_DIR),$(PDP18B_DIR))/DEFINE=("PDP15=1") + +# +# Digital Equipment PDP-11 Simulator Definitions. +# +PDP11_DIR = SYS$DISK:[.PDP11] +PDP11_LIB = $(LIB_DIR)PDP11-$(ARCH).OLB +PDP11_SOURCE = $(PDP11_DIR)PDP11_FP.C,$(PDP11_DIR)PDP11_CPU.C,\ + $(PDP11_DIR)PDP11_DZ.C,$(PDP11_DIR)PDP11_CIS.C,\ + $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_RK.C,\ + $(PDP11_DIR)PDP11_RL.C,$(PDP11_DIR)PDP11_RP.C,\ + $(PDP11_DIR)PDP11_RX.C,$(PDP11_DIR)PDP11_STDDEV.C,\ + $(PDP11_DIR)PDP11_SYS.C,$(PDP11_DIR)PDP11_TC.C,\ + $(PDP11_DIR)PDP11_TM.C,$(PDP11_DIR)PDP11_TS.C,\ + $(PDP11_DIR)PDP11_IO.C,$(PDP11_DIR)PDP11_RQ.C,\ + $(PDP11_DIR)PDP11_TQ.C,$(PDP11_DIR)PDP11_PCLK.C,\ + $(PDP11_DIR)PDP11_RY.C,$(PDP11_DIR)PDP11_PT.C,\ + $(PDP11_DIR)PDP11_HK.C,$(PDP11_DIR)PDP11_XQ.C +PDP11_OBJS = $(PDP11_DIR)PDP11_FP.OBJ,$(PDP11_DIR)PDP11_CPU.OBJ,\ + $(PDP11_DIR)PDP11_DZ.OBJ,$(PDP11_DIR)PDP11_CIS.OBJ,\ + $(PDP11_DIR)PDP11_LP.OBJ,$(PDP11_DIR)PDP11_RK.OBJ,\ + $(PDP11_DIR)PDP11_RL.OBJ,$(PDP11_DIR)PDP11_RP.OBJ,\ + $(PDP11_DIR)PDP11_RX.OBJ,$(PDP11_DIR)PDP11_STDDEV.OBJ,\ + $(PDP11_DIR)PDP11_SYS.OBJ,$(PDP11_DIR)PDP11_TC.OBJ,\ + $(PDP11_DIR)PDP11_TM.OBJ,$(PDP11_DIR)PDP11_TS.OBJ,\ + $(PDP11_DIR)PDP11_IO.OBJ,$(PDP11_DIR)PDP11_RQ.OBJ,\ + $(PDP11_DIR)PDP11_TQ.OBJ,$(PDP11_DIR)PDP11_PCLK.OBJ,\ + $(PDP11_DIR)PDP11_RY.OBJ,$(PDP11_DIR)PDP11_PT.OBJ,\ + $(PDP11_DIR)PDP11_HK.OBJ,$(PDP11_DIR)PDP11_XQ.OBJ +PDP11_OPTIONS = /INCLUDE=($(SIMH_DIR),$(PDP11_DIR))/DEFINE=("USE_NETWORK=1") + +# +# Digital Equipment PDP-10 Simulator Definitions. +# +PDP10_DIR = SYS$DISK:[.PDP10] +PDP10_LIB = $(LIB_DIR)PDP10-$(ARCH).OLB +PDP10_SOURCE = $(PDP10_DIR)PDP10_FE.C,$(PDP10_DIR)PDP10_DZ.C,\ + $(PDP10_DIR)PDP10_CPU.C,$(PDP10_DIR)PDP10_KSIO.C,\ + $(PDP10_DIR)PDP10_LP20.C,$(PDP10_DIR)PDP10_MDFP.C,\ + $(PDP10_DIR)PDP10_PAG.C,$(PDP10_DIR)PDP10_PT.C,\ + $(PDP10_DIR)PDP10_RP.C,$(PDP10_DIR)PDP10_SYS.C,\ + $(PDP10_DIR)PDP10_TIM.C,$(PDP10_DIR)PDP10_TU.C,\ + $(PDP10_DIR)PDP10_XTND.C,$(PDP10_DIR)PDP10_PT.C,\ + $(PDP11_DIR)PDP11_RY.C +PDP10_OBJS = $(PDP10_DIR)PDP10_FE.OBJ,$(PDP10_DIR)PDP10_DZ.OBJ,\ + $(PDP10_DIR)PDP10_CPU.OBJ,$(PDP10_DIR)PDP10_KSIO.OBJ,\ + $(PDP10_DIR)PDP10_LP20.OBJ,$(PDP10_DIR)PDP10_MDFP.OBJ,\ + $(PDP10_DIR)PDP10_PAG.OBJ,$(PDP10_DIR)PDP10_PT.OBJ,\ + $(PDP10_DIR)PDP10_RP.OBJ,$(PDP10_DIR)PDP10_SYS.OBJ,\ + $(PDP10_DIR)PDP10_TIM.OBJ,$(PDP10_DIR)PDP10_TU.OBJ,\ + $(PDP10_DIR)PDP10_XTND.OBJ,$(PDP10_DIR)PDP10_PT.OBJ,\ + $(PDP10_DIR)PDP11_RY.OBJ +PDP10_OPTIONS = /INCLUDE=($(SIMH_DIR),$(PDP10_DIR),$(PDP11_DIR))/DEFINE=("USE_INT64=1") + +# +# IBM System 3 Simulator Definitions. +# +S3_DIR = SYS$DISK:[.S3] +S3_LIB = $(LIB_DIR)S3-$(ARCH).OLB +S3_SOURCE = $(S3_DIR)S3_CD.C,$(S3_DIR)S3_CPU.C,$(S3_DIR)S3_DISK.C,\ + $(S3_DIR)S3_LP.C,$(S3_DIR)S3_PKB.C,$(S3_DIR)S3_SYS.C +S3_OBJS = $(S3_DIR)S3_CD.OBJ,$(S3_DIR)S3_CPU.OBJ,$(S3_DIR)S3_DISK.OBJ,\ + $(S3_DIR)S3_LP.OBJ,$(S3_DIR)S3_PKB.OBJ,$(S3_DIR)S3_SYS.OBJ +S3_OPTIONS = /INCLUDE=($(SIMH_DIR),$(S3_DIR)) + +# +# SDS 940 +# +SDS_DIR = SYS$DISK:[.SDS] +SDS_LIB = $(LIB_DIR)SDS-$(ARCH).OLB +SDS_SOURCE = $(SDS_DIR)SDS_CPU.C,$(SDS_DIR)SDS_DRM.C,$(SDS_DIR)SDS_DSK.C,\ + $(SDS_DIR)SDS_IO.C,$(SDS_DIR)SDS_LP.C,$(SDS_DIR)SDS_MT.C,\ + $(SDS_DIR)SDS_MUX.C,$(SDS_DIR)SDS_RAD.C,$(SDS_DIR)SDS_STDDEV.C,\ + $(SDS_DIR)SDS_SYS.C +SDS_OBJS = $(SDS_DIR)SDS_CPU.OBJ,$(SDS_DIR)SDS_DRM.OBJ,$(SDS_DIR)SDS_DSK.OBJ,\ + $(SDS_DIR)SDS_IO.OBJ,$(SDS_DIR)SDS_LP.OBJ,$(SDS_DIR)SDS_MT.OBJ,\ + $(SDS_DIR)SDS_MUX.OBJ,$(SDS_DIR)SDS_RAD.OBJ,$(SDS_DIR)SDS_STDDEV.OBJ,\ + $(SDS_DIR)SDS_SYS.OBJ +SDS_OPTIONS = /INCLUDE=($(SIMH_DIR),$(SDS_DIR)) + +# +# Digital Equipment VAX Simulator Definitions. +# +VAX_DIR = SYS$DISK:[.VAX] +VAX_LIB = $(LIB_DIR)VAX-$(ARCH).OLB +VAX_SOURCE = $(VAX_DIR)VAX_CPU1.C,$(VAX_DIR)VAX_CPU.C,\ + $(VAX_DIR)VAX_FPA.C,$(VAX_DIR)VAX_IO.C,\ + $(VAX_DIR)VAX_MMU.C,$(VAX_DIR)VAX_STDDEV.C,\ + $(VAX_DIR)VAX_SYS.C,$(VAX_DIR)VAX_SYSDEV.C,\ + $(PDP11_DIR)PDP11_RL.C,$(PDP11_DIR)PDP11_RQ.C,\ + $(PDP11_DIR)PDP11_TS.C,$(PDP11_DIR)PDP11_DZ.C,\ + $(PDP11_DIR)PDP11_LP.C,$(PDP11_DIR)PDP11_TQ.C,\ + $(PDP11_DIR)PDP11_PT.C,$(PDP11_DIR)PDP11_XQ.C +VAX_OBJS = $(VAX_DIR)VAX_CPU1.OBJ,$(VAX_DIR)VAX_CPU.OBJ,\ + $(VAX_DIR)VAX_FPA.OBJ,$(VAX_DIR)VAX_IO.OBJ,\ + $(VAX_DIR)VAX_MMU.OBJ,$(VAX_DIR)VAX_STDDEV.OBJ,\ + $(VAX_DIR)VAX_SYS.OBJ,$(VAX_DIR)VAX_SYSDEV.OBJ,\ + $(VAX_DIR)PDP11_RL.OBJ,$(VAX_DIR)PDP11_RQ.OBJ,\ + $(VAX_DIR)PDP11_TS.OBJ,$(VAX_DIR)PDP11_DZ.OBJ,\ + $(VAX_DIR)PDP11_LP.OBJ,$(VAX_DIR)PDP11_TQ.OBJ,\ + $(VAX_DIR)PDP11_PT.OBJ,$(VAX_DIR)PDP11_XQ.OBJ +VAX_OPTIONS = /INCLUDE=($(SIMH_DIR),$(VAX_DIR),$(PDP11_DIR))/DEFINE=("USE_INT64=1","USE_NETWORK=1") + +# +# If On Alpha, Build Everything. +# +.IFDEF __ALPHA__ +ALL : ALTAIR ALTAIRZ80 ECLIPSE GRI H316 HP2100 I1401 I1620 IBM1130 ID16 ID32 \ + NOVA PDP1 PDP4 PDP7 PDP8 PDP9 PDP10 PDP11 PDP15 S3 SDS VAX +.ELSE +# +# Else We Are On VAX And Build Everything EXCEPT PDP-10 And VAX Since VAX +# Dosen't Have INT64 +# +ALL : ALTAIR ALTAIRZ80 ECLIPSE GRI H316 HP2100 I1401 I1620 IBM1130 ID16 ID32 \ + NOVA PDP1 PDP4 PDP7 PDP8 PDP9 PDP11 PDP15 S3 SDS +.ENDIF + +# +# Build The Libraries. +# +$(LIB_DIR)SIMH-$(ARCH).OLB : $(SIMH_SOURCE) + $! + $! Building The $(SIMH_LIB) Library. + $! + $ $(CC)/OBJECT=$(SIMH_DIR) $(SIMH_SOURCE) + $ IF (F$SEARCH("$(SIMH_LIB)").EQS."") THEN - + LIBRARY/CREATE $(SIMH_LIB) + $ LIBRARY/REPLACE $(SIMH_LIB) $(SIMH_OBJS) + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* + +$(LIB_DIR)ALTAIR-$(ARCH).OLB : $(ALTAIR_SOURCE) + $! + $! Building The $(ALTAIR_LIB) Library. + $! + $ $(CC)$(ALTAIR_OPTIONS)/OBJECT=$(ALTAIR_DIR) - + $(ALTAIR_SOURCE) + $ IF (F$SEARCH("$(ALTAIR_LIB)").EQS."") THEN - + LIBRARY/CREATE $(ALTAIR_LIB) + $ LIBRARY/REPLACE $(ALTAIR_LIB) - + $(ALTAIR_OBJS) + $ DELETE/NOLOG/NOCONFIRM $(ALTAIR_DIR)*.OBJ;* + +$(LIB_DIR)ALTAIRZ80-$(ARCH).OLB : $(ALTAIRZ80_SOURCE) + $! + $! Building The $(ALTAIRZ80_LIB) Library. + $! + $ $(CC)$(ALTAIRZ80_OPTIONS) - + /OBJECT=$(ALTAIRZ80_DIR) - + $(ALTAIRZ80_SOURCE) + $ IF (F$SEARCH("$(ALTAIRZ80_LIB)").EQS."") - + THEN LIBRARY/CREATE $(ALTAIRZ80_LIB) + $ LIBRARY/REPLACE $(ALTAIRZ80_LIB) - + $(ALTAIRZ80_OBJS) + $ DELETE/NOLOG/NOCONFIRM - + $(ALTAIRZ80_DIR)*.OBJ;* + +$(LIB_DIR)ECLIPSE-$(ARCH).OLB : $(ECLIPSE_SOURCE) + $! + $! Building The $(ECLIPSE_LIB) Library. + $! + $ $(CC)$(ECLIPSE_OPTIONS)/OBJECT=$(NOVA_DIR) - + $(ECLIPSE_SOURCE) + $ IF (F$SEARCH("$(ECLIPSE_LIB)").EQS."") THEN - + LIBRARY/CREATE $(ECLIPSE_LIB) + $ LIBRARY/REPLACE $(ECLIPSE_LIB) - + $(ECLIPSE_OBJS) + $ DELETE/NOLOG/NOCONFIRM $(NOVA_DIR)*.OBJ;* + +$(LIB_DIR)GRI-$(ARCH).OLB : $(GRI_SOURCE) + $! + $! Building The $(GRI_LIB) Library. + $! + $ $(CC)$(GRI_OPTIONS)/OBJECT=$(GRI_DIR) - + $(GRI_SOURCE) + $ IF (F$SEARCH("$(GRI_LIB)").EQS."") THEN - + LIBRARY/CREATE $(GRI_LIB) + $ LIBRARY/REPLACE $(GRI_LIB) $(GRI_OBJS) + $ DELETE/NOLOG/NOCONFIRM $(GRI_DIR)*.OBJ;* + +$(LIB_DIR)H316-$(ARCH).OLB : $(H316_SOURCE) + $! + $! Building The $(H316_LIB) Library. + $! + $ $(CC)$(H316_OPTIONS)/OBJECT=$(H316_DIR) - + $(H316_SOURCE) + $ IF (F$SEARCH("$(H316_LIB)").EQS."") THEN - + LIBRARY/CREATE $(H316_LIB) + $ LIBRARY/REPLACE $(H316_LIB) $(H316_OBJS) + $ DELETE/NOLOG/NOCONFIRM $(H316_DIR)*.OBJ;* + +$(LIB_DIR)HP2100-$(ARCH).OLB : $(HP2100_SOURCE) + $! + $! Building The $(HP2100_LIB) Library. + $! + $ $(CC)$(HP2100_OPTIONS)/OBJECT=$(HP2100_DIR) - + $(HP2100_SOURCE) + $ IF (F$SEARCH("$(HP2100_LIB)").EQS."") THEN - + LIBRARY/CREATE $(HP2100_LIB) + $ LIBRARY/REPLACE $(HP2100_LIB) $(HP2100_OBJS) + $ DELETE/NOLOG/NOCONFIRM $(HP2100_DIR)*.OBJ;* + +$(LIB_DIR)I1401-$(ARCH).OLB : $(I1401_SOURCE) + $! + $! Building The $(I1401_LIB) Library. + $! + $ $(CC)$(I1401_OPTIONS)/OBJECT=$(I1401_DIR) - + $(I1401_SOURCE) + $ IF (F$SEARCH("$(I1401_LIB)").EQS."") THEN - + LIBRARY/CREATE $(I1401_LIB) + $ LIBRARY/REPLACE $(I1401_LIB) $(I1401_OBJS) + $ DELETE/NOLOG/NOCONFIRM $(I1401_DIR)*.OBJ;* + +$(LIB_DIR)I1620-$(ARCH).OLB : $(I1620_SOURCE) + $! + $! Building The $(I1620_LIB) Library. + $! + $ $(CC)$(I1620_OPTIONS)/OBJECT=$(I1620_DIR) - + $(I1620_SOURCE) + $ IF (F$SEARCH("$(I1620_LIB)").EQS."") THEN - + LIBRARY/CREATE $(I1620_LIB) + $ LIBRARY/REPLACE $(I1620_LIB) $(I1620_OBJS) + $ DELETE/NOLOG/NOCONFIRM $(I1620_DIR)*.OBJ;* + +$(LIB_DIR)IBM1130-$(ARCH).OLB : $(IBM1130_SOURCE) + $! + $! Building The $(IBM1130_LIB) Library. + $! + $ $(CC)$(IBM1130_OPTIONS) - + /OBJECT=$(IBM1130_DIR) - + $(IBM1130_SOURCE) + $ IF (F$SEARCH("$(IBM1130_LIB)").EQS."") THEN - + LIBRARY/CREATE $(IBM1130_LIB) + $ LIBRARY/REPLACE $(IBM1130_LIB) $(IBM1130_OBJS) + $ DELETE/NOLOG/NOCONFIRM $(IBM1130_DIR)*.OBJ;* + +$(LIB_DIR)ID16-$(ARCH).OLB : $(ID16_SOURCE) + $! + $! Building The $(ID16_LIB) Library. + $! + $ $(CC)$(ID16_OPTIONS)/OBJECT=$(ID16_DIR) - + $(ID16_SOURCE) + $ IF (F$SEARCH("$(ID16_LIB)").EQS."") THEN - + LIBRARY/CREATE $(ID16_LIB) + $ LIBRARY/REPLACE $(ID16_LIB) $(ID16_OBJS) + $ DELETE/NOLOG/NOCONFIRM $(ID16_DIR)*.OBJ;* + +$(LIB_DIR)ID32-$(ARCH).OLB : $(ID32_SOURCE) + $! + $! Building The $(ID32_LIB) Library. + $! + $ $(CC)$(ID32_OPTIONS)/OBJECT=$(ID32_DIR) - + $(ID32_SOURCE) + $ IF (F$SEARCH("$(ID32_LIB)").EQS."") THEN - + LIBRARY/CREATE $(ID32_LIB) + $ LIBRARY/REPLACE $(ID32_LIB) $(ID32_OBJS) + $ DELETE/NOLOG/NOCONFIRM $(ID32_DIR)*.OBJ;* + +$(LIB_DIR)NOVA-$(ARCH).OLB : $(NOVA_SOURCE) + $! + $! Building The $(NOVA_LIB) Library. + $! + $ $(CC)$(NOVA_OPTIONS)/OBJECT=$(NOVA_DIR) - + $(NOVA_SOURCE) + $ IF (F$SEARCH("$(NOVA_LIB)").EQS."") THEN - + LIBRARY/CREATE $(NOVA_LIB) + $ LIBRARY/REPLACE $(NOVA_LIB) $(NOVA_OBJS) + $ DELETE/NOLOG/NOCONFIRM $(NOVA_DIR)*.OBJ;* + +$(LIB_DIR)PDP1-$(ARCH).OLB : $(PDP1_SOURCE) + $! + $! Building The $(PDP1_LIB) Library. + $! + $ $(CC)$(PDP1_OPTIONS)/OBJECT=$(PDP1_DIR) - + $(PDP1_SOURCE) + $ IF (F$SEARCH("$(PDP1_LIB)").EQS."") THEN - + LIBRARY/CREATE $(PDP1_LIB) + $ LIBRARY/REPLACE $(PDP1_LIB) $(PDP1_OBJS) + $ DELETE/NOLOG/NOCONFIRM $(PDP1_DIR)*.OBJ;* + +$(LIB_DIR)PDP4-$(ARCH).OLB : $(PDP18B_SOURCE) + $! + $! Building The $(PDP4_LIB) Library. + $! + $ $(CC)$(PDP4_OPTIONS)/OBJECT=$(PDP18B_DIR) - + $(PDP18B_SOURCE) + $ IF (F$SEARCH("$(PDP4_LIB)").EQS."") THEN - + LIBRARY/CREATE $(PDP4_LIB) + $ LIBRARY/REPLACE $(PDP4_LIB) $(PDP18B_OBJS) + $ DELETE/NOLOG/NOCONFIRM $(PDP18B_DIR)*.OBJ;* + +$(LIB_DIR)PDP7-$(ARCH).OLB : $(PDP18B_SOURCE) + $! + $! Building The $(PDP7_LIB) Library. + $! + $ $(CC)$(PDP7_OPTIONS)/OBJECT=$(PDP18B_DIR) - + $(PDP18B_SOURCE) + $ IF (F$SEARCH("$(PDP7_LIB)").EQS."") THEN - + LIBRARY/CREATE $(PDP7_LIB) + $ LIBRARY/REPLACE $(PDP7_LIB) $(PDP18B_OBJS) + $ DELETE/NOLOG/NOCONFIRM $(PDP18B_DIR)*.OBJ;* + +$(LIB_DIR)PDP8-$(ARCH).OLB : $(PDP8_SOURCE) + $! + $! Building The $(PDP8_LIB) Library. + $! + $ $(CC)$(PDP8_OPTIONS)/OBJECT=$(PDP8_DIR) - + $(PDP8_SOURCE) + $ IF (F$SEARCH("$(PDP8_LIB)").EQS."") THEN - + LIBRARY/CREATE $(PDP8_LIB) + $ LIBRARY/REPLACE $(PDP8_LIB) $(PDP8_OBJS) + $ DELETE/NOLOG/NOCONFIRM $(PDP8_DIR)*.OBJ;* + +$(LIB_DIR)PDP9-$(ARCH).OLB : $(PDP18B_SOURCE) + $! + $! Building The $(PDP9_LIB) Library. + $! + $ $(CC)$(PDP9_OPTIONS)/OBJECT=$(PDP18B_DIR) - + $(PDP18B_SOURCE) + $ IF (F$SEARCH("$(PDP9_LIB)").EQS."") THEN - + LIBRARY/CREATE $(PDP9_LIB) + $ LIBRARY/REPLACE $(PDP9_LIB) $(PDP18B_OBJS) + $ DELETE/NOLOG/NOCONFIRM $(PDP18B_DIR)*.OBJ;* + +# +# If On Alpha, Build The PDP-10 Library. +# +.IFDEF __ALPHA__ +$(LIB_DIR)PDP10-$(ARCH).OLB : $(PDP10_SOURCE) + $! + $! Building The $(PDP10_LIB) Library. + $! + $ $(CC)$(PDP10_OPTIONS)/OBJECT=$(PDP10_DIR) - + $(PDP10_SOURCE) + $ IF (F$SEARCH("$(PDP10_LIB)").EQS."") THEN - + LIBRARY/CREATE $(PDP10_LIB) + $ LIBRARY/REPLACE $(PDP10_LIB) $(PDP10_OBJS) + DELETE/NOLOG/NOCONFIRM $(PDP10_DIR)*.OBJ;* +.ELSE +# +# We Are On VAX And Due To The Use of INT64 We Can't Build It. +# +$(LIB_DIR)PDP10-$(ARCH).OLB : + $! + $! Due To The Use Of INT64 We Can't Build The + $! $(LIB_DIR)PDP10-$(ARCH).OLB Library On VAX. + $! +.ENDIF + +$(LIB_DIR)PDP11-$(ARCH).OLB : $(PDP11_SOURCE) + $! + $! Building The $(PDP11_LIB) Library. + $! + $(CC)$(PDP11_OPTIONS)/OBJECT=$(PDP11_DIR) - + $(PDP11_SOURCE) + $ IF (F$SEARCH("$(PDP11_LIB)").EQS."") THEN - + LIBRARY/CREATE $(PDP11_LIB) + $ LIBRARY/REPLACE $(PDP11_LIB) $(PDP11_OBJS) + $ DELETE/NOLOG/NOCONFIRM $(PDP11_DIR)*.OBJ;* + +$(LIB_DIR)PDP15-$(ARCH).OLB : $(PDP18B_SOURCE) + $! + $! Building The $(PDP15_LIB) Library. + $! + $ $(CC)$(PDP15_OPTIONS)/OBJECT=$(PDP18B_DIR) - + $(PDP18B_SOURCE) + $ IF (F$SEARCH("$(PDP15_LIB)").EQS."") THEN - + LIBRARY/CREATE $(PDP15_LIB) + $ LIBRARY/REPLACE $(PDP15_LIB) $(PDP18B_OBJS) + $ DELETE/NOLOG/NOCONFIRM $(PDP18B_DIR)*.OBJ;* + +$(LIB_DIR)S3-$(ARCH).OLB : $(S3_SOURCE) + $! + $! Building The $(S3_LIB) Library. + $! + $ $(CC)$(S3_OPTIONS)/OBJECT=$(S3_DIR) $(S3_SOURCE) + $ IF (F$SEARCH("$(S3_LIB)").EQS."") THEN - + LIBRARY/CREATE $(S3_LIB) + $ LIBRARY/REPLACE $(S3_LIB) $(S3_OBJS) + $ DELETE/NOLOG/NOCONFIRM $(S3_DIR)*.OBJ;* + +$(LIB_DIR)SDS-$(ARCH).OLB : $(SDS_SOURCE) + $! + $! Building The $(SDS_LIB) Library. + $! + $ $(CC)$(SDS_OPTIONS)/OBJECT=$(SDS_DIR) - + $(SDS_SOURCE) + $ IF (F$SEARCH("$(SDS_LIB)").EQS."") THEN - + LIBRARY/CREATE $(SDS_LIB) + $ LIBRARY/REPLACE $(SDS_LIB) $(SDS_OBJS) + $ DELETE/NOLOG/NOCONFIRM $(SDS_DIR)*.OBJ;* + +# +# If On Alpha, Build The VAX Library. +# +.IFDEF __ALPHA__ +$(LIB_DIR)VAX-$(ARCH).OLB : $(VAX_SOURCE) + $! + $! Building The $(VAX_LIB) Library. + $! + $ $(CC)$(VAX_OPTIONS)/OBJECT=$(VAX_DIR) - + $(VAX_SOURCE) + $ IF (F$SEARCH("$(VAX_LIB)").EQS."") THEN - + LIBRARY/CREATE $(VAX_LIB) + $ LIBRARY/REPLACE $(VAX_LIB) $(VAX_OBJS) + $ DELETE/NOLOG/NOCONFIRM $(VAX_DIR)*.OBJ;* +.ELSE +# +# We Are On VAX And Due To The Use of INT64 We Can't Build It. +# +$(LIB_DIR)VAX-$(ARCH).OLB : + $! + $! Due To The Use Of INT64 We Can't Build The + $! $(LIB_DIR)VAX-$(ARCH).OLB Library On VAX. + $! +.ENDIF + +# +# Individual Simulator Builds. +# +ALTAIR : $(SIMH_LIB) $(ALTAIR_LIB) + $! + $! Building The $(BIN_DIR)ALTAIR-$(ARCH).EXE Simulator. + $! + $ $(CC)$(ALTAIR_OPTIONS)/OBJECT=$(SIMH_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)ALTAIR-$(ARCH).EXE - + SCP.OBJ,$(ALTAIR_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* + +ALTAIRZ80 : $(SIMH_LIB) $(ALTAIRZ80_LIB) + $! + $! Building The $(BIN_DIR)ALTAIRZ80-$(ARCH).EXE Simulator. + $! + $ $(CC)$(ALTAIRZ80_OPTIONS)/OBJECT=$(SIMH_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)ALTAIRZ80-$(ARCH).EXE - + SCP.OBJ,$(ALTAIRZ80_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* + +ECLIPSE : $(SIMH_LIB) $(ECLIPSE_LIB) + $! + $! Building The $(BIN_DIR)ECLPISE-$(ARCH).EXE Simulator. + $! + $ $(CC)$(ECLIPSE_OPTIONS)/OBJECT=$(SIMH_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)ECLIPSE-$(ARCH).EXE - + SCP.OBJ,$(ECLIPSE_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* + +GRI : $(SIMH_LIB) $(GRI_LIB) + $! + $! Building The $(BIN_DIR)GRI-$(ARCH).EXE Simulator. + $! + $ $(CC)$(GRI_OPTIONS)/OBJECT=$(SIMH_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)GRI-$(ARCH).EXE - + SCP.OBJ,$(GRI_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* + +H316 : $(SIMH_LIB) $(H316_LIB) + $! + $! Building The $(BIN_DIR)H316-$(ARCH).EXE Simulator. + $! + $ $(CC)$(H316_OPTIONS)/OBJECT=$(SIMH_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)H316-$(ARCH).EXE - + SCP.OBJ,$(H316_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* + +HP2100 : $(SIMH_LIB) $(HP2100_LIB) + $! + $! Building The $(BIN_DIR)HP2100-$(ARCH).EXE Simulator. + $! + $ $(CC)$(HP2100_OPTIONS)/OBJECT=$(SIMH_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)HP2100-$(ARCH).EXE - + SCP.OBJ,$(HP2100_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* + +I1401 : $(SIMH_LIB) $(I1401_LIB) + $! + $! Building The $(BIN_DIR)I1401-$(ARCH).EXE Simulator. + $! + $ $(CC)$(I1401_OPTIONS)/OBJECT=$(SIMH_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)I1401-$(ARCH).EXE - + SCP.OBJ,$(I1401_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* + +I1620 : $(SIMH_LIB) $(I1620_LIB) + $! + $! Building The $(BIN_DIR)I1620-$(ARCH).EXE Simulator. + $! + $ $(CC)$(I1620_OPTIONS)/OBJECT=$(SIMH_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)I1620-$(ARCH).EXE - + SCP.OBJ,$(I1620_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* + +IBM1130 : $(SIMH_LIB) $(IBM1130_LIB) + $! + $! Building The $(BIN_DIR)IBM1130-$(ARCH).EXE Simulator. + $! + $ $(CC)$(IBM1130_OPTIONS)/OBJECT=$(SIMH_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)IBM1130-$(ARCH).EXE - + SCP.OBJ,$(IBM1130_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* + +ID16 : $(SIMH_LIB) $(ID16_LIB) + $! + $! Building The $(BIN_DIR)ID16-$(ARCH).EXE Simulator. + $! + $ $(CC)$(ID16_OPTIONS)/OBJECT=$(SIMH_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)ID16-$(ARCH).EXE - + SCP.OBJ,$(ID16_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* + +ID32 : $(SIMH_LIB) $(ID32_LIB) + $! + $! Building The $(BIN_DIR)ID32-$(ARCH).EXE Simulator. + $! + $ $(CC)$(ID32_OPTIONS)/OBJECT=$(SIMH_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)ID32-$(ARCH).EXE - + SCP.OBJ,$(ID32_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* + +NOVA : $(SIMH_LIB) $(NOVA_LIB) + $! + $! Building The $(BIN_DIR)NOVA-$(ARCH).EXE Simulator. + $! + $ $(CC)$(NOVA_OPTIONS)/OBJECT=$(SIMH_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)NOVA-$(ARCH).EXE - + SCP.OBJ,$(NOVA_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* + +PDP1 : $(SIMH_LIB) $(PDP1_LIB) + $! + $! Building The $(BIN_DIR)PDP1-$(ARCH).EXE Simulator. + $! + $ $(CC)$(PDP1_OPTIONS)/OBJECT=$(SIMH_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)PDP1-$(ARCH).EXE - + SCP.OBJ,$(PDP1_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* + +PDP4 : $(SIMH_LIB) $(PDP4_LIB) + $! + $! Building The $(BIN_DIR)PDP4-$(ARCH).EXE Simulator. + $! + $ $(CC)$(PDP4_OPTIONS)/OBJECT=$(SIMH_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)PDP4-$(ARCH).EXE - + SCP.OBJ,$(PDP4_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* + +PDP7 : $(SIMH_LIB) $(PDP7_LIB) + $! + $! Building The $(BIN_DIR)PDP7-$(ARCH).EXE Simulator. + $! + $ $(CC)$(PDP7_OPTIONS)/OBJECT=$(SIMH_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)PDP7-$(ARCH).EXE - + SCP.OBJ,$(PDP7_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* + +PDP8 : $(SIMH_LIB) $(PDP8_LIB) + $! + $! Building The $(BIN_DIR)PDP8-$(ARCH).EXE Simulator. + $! + $ $(CC)$(PDP8_OPTIONS)/OBJECT=$(SIMH_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)PDP8-$(ARCH).EXE - + SCP.OBJ,$(PDP8_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* + +PDP9 : $(SIMH_LIB) $(PDP9_LIB) + $! + $! Building The $(BIN_DIR)PDP9-$(ARCH).EXE Simulator. + $! + $ $(CC)$(PDP9_OPTIONS)/OBJECT=$(SIMH_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)PDP9-$(ARCH).EXE - + SCP.OBJ,$(PDP9_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* + +# +# If On Alpha, Build The PDP-10 Simulator. +# +.IFDEF __ALPHA__ +PDP10 : $(SIMH_LIB) $(PDP10_LIB) + $! + $! Building The $(BIN_DIR)PDP10-$(ARCH).EXE Simulator. + $! + $ $(CC)$(PDP10_OPTIONS)/OBJECT=$(SIMH_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)PDP10-$(ARCH).EXE - + SCP.OBJ,$(PDP10_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* +.ELSE +# +# Else We Are On VAX And Tell The User We Can't Build On VAX +# Due To The Use Of INT64. +# +PDP10 : + $! + $! Sorry, Can't Build $(BIN_DIR)PDP10-$(ARCH).EXE Simulator + $! Because It Requires The Use Of INT64. + $! +.ENDIF + +PDP11 : $(SIMH_LIB) $(PDP11_LIB) + $! + $! Building The $(BIN_DIR)PDP11-$(ARCH).EXE Simulator. + $! + $ $(CC)$(PDP11_OPTIONS)/OBJECT=$(SIMH_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)PDP11-$(ARCH).EXE - + SCP.OBJ,$(PDP11_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* + +PDP15 : $(SIMH_LIB) $(PDP15_LIB) + $! + $! Building The $(BIN_DIR)PDP15-$(ARCH).EXE Simulator. + $! + $ $(CC)$(PDP15_OPTIONS)/OBJECT=$(SIMH_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)PDP15-$(ARCH).EXE - + SCP.OBJ,$(PDP15_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* + +S3 : $(SIMH_LIB) $(S3_LIB) + $! + $! Building The $(BIN_DIR)S3-$(ARCH).EXE Simulator. + $! + $ $(CC)$(S3_OPTIONS)/OBJECT=$(SIMH_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)S3-$(ARCH).EXE - + SCP.OBJ,$(S3_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* + +SDS : $(SIMH_LIB) $(SDS_LIB) + $! + $! Building The $(BIN_DIR)SDS-$(ARCH).EXE Simulator. + $! + $ $(CC)$(SDS_OPTIONS)/OBJECT=$(SIMH_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)SDS-$(ARCH).EXE - + SCP.OBJ,$(SDS_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* + +# +# If On Alpha, Build The VAX Simulator. +# +.IFDEF __ALPHA__ +VAX : $(SIMH_LIB) $(VAX_LIB) + $! + $! Building The $(BIN_DIR)VAX-$(ARCH).EXE Simulator. + $! + $ $(CC)$(VAX_OPTIONS)/OBJECT=$(SIMH_DIR) SCP.C + $ LINK $(LINK_DEBUG)/EXE=$(BIN_DIR)VAX-$(ARCH).EXE - + SCP.OBJ,$(VAX_LIB)/LIBRARY,$(SIMH_LIB)/LIBRARY + $ DELETE/NOLOG/NOCONFIRM $(SIMH_DIR)*.OBJ;* +.ELSE +# +# Else We Are On VAX And Tell The User We Can't Build On VAX +# Due To The Use Of INT64. +# +VAX : + $! + $! Sorry, Can't Build $(BIN_DIR)VAX-$(ARCH).EXE Simulator + $! Because It Requires The Use Of INT64. + $! +.ENDIF + diff --git a/makefile b/makefile index 915ac20b..bfeeb013 100644 --- a/makefile +++ b/makefile @@ -3,7 +3,7 @@ # Note: -O2 is sometimes broken in GCC when setjump/longjump is being # used. Try -O2 only with released simulators. # -CC = gcc -O0 -lm -I . +CC = gcc -O2 -lm -I . #CC = gcc -O2 -g -lm -I . @@ -12,7 +12,7 @@ CC = gcc -O0 -lm -I . # Common Libraries # BIN = BIN/ -SIM = scp.c scp_tty.c sim_sock.c sim_tmxr.c +SIM = scp.c scp_tty.c sim_sock.c sim_tmxr.c sim_ether.c @@ -21,7 +21,7 @@ SIM = scp.c scp_tty.c sim_sock.c sim_tmxr.c # PDP1D = PDP1/ PDP1 = ${PDP1D}pdp1_lp.c ${PDP1D}pdp1_cpu.c ${PDP1D}pdp1_stddev.c \ - ${PDP1D}pdp1_sys.c + ${PDP1D}pdp1_sys.c ${PDP1D}pdp1_dt.c PDP1_OPT = -I ${PDP1D} @@ -60,18 +60,31 @@ PDP11 = ${PDP11D}pdp11_fp.c ${PDP11D}pdp11_cpu.c ${PDP11D}pdp11_dz.c \ ${PDP11D}pdp11_rl.c ${PDP11D}pdp11_rp.c ${PDP11D}pdp11_rx.c \ ${PDP11D}pdp11_stddev.c ${PDP11D}pdp11_sys.c ${PDP11D}pdp11_tc.c \ ${PDP11D}pdp11_tm.c ${PDP11D}pdp11_ts.c ${PDP11D}pdp11_io.c \ - ${PDP11D}pdp11_rq.c + ${PDP11D}pdp11_rq.c ${PDP11D}pdp11_tq.c ${PDP11D}pdp11_pclk.c \ + ${PDP11D}pdp11_ry.c ${PDP11D}pdp11_pt.c ${PDP11D}pdp11_hk.c \ + ${PDP11D}pdp11_xq.c PDP11_OPT = -I ${PDP11D} +VAXD = VAX/ +VAX = ${VAXD}vax_cpu1.c ${VAXD}vax_cpu.c ${VAXD}vax_fpa.c ${VAXD}vax_io.c \ + ${VAXD}vax_mmu.c ${VAXD}vax_stddev.c ${VAXD}vax_sys.c \ + ${VAXD}vax_sysdev.c \ + ${PDP11D}pdp11_rl.c ${PDP11D}pdp11_rq.c ${PDP11D}pdp11_ts.c \ + ${PDP11D}pdp11_dz.c ${PDP11D}pdp11_lp.c ${PDP11D}pdp11_tq.c \ + ${PDP11D}pdp11_pt.c ${PDP11D}pdp11_xq.c +VAX_OPT = -I ${VAXD} -I ${PDP11D} -DUSE_INT64 + + + PDP10D = PDP10/ PDP10 = ${PDP10D}pdp10_fe.c ${PDP10D}pdp10_dz.c ${PDP10D}pdp10_cpu.c \ ${PDP10D}pdp10_ksio.c ${PDP10D}pdp10_lp20.c ${PDP10D}pdp10_mdfp.c \ - ${PDP10D}pdp10_pag.c ${PDP10D}pdp10_pt.c ${PDP10D}pdp10_rp.c \ - ${PDP10D}pdp10_sys.c ${PDP10D}pdp10_tim.c ${PDP10D}pdp10_tu.c \ - ${PDP10D}pdp10_xtnd.c -PDP10_OPT = -DUSE_INT64 -I ${PDP10D} + ${PDP10D}pdp10_pag.c ${PDP10D}pdp10_rp.c ${PDP10D}pdp10_sys.c \ + ${PDP10D}pdp10_tim.c ${PDP10D}pdp10_tu.c ${PDP10D}pdp10_xtnd.c \ + ${PDP10D}pdp10_pt.c ${PDP11D}pdp11_ry.c +PDP10_OPT = -DUSE_INT64 -I ${PDP10D} -I ${PDP11D} -I ${VAXD} @@ -94,9 +107,9 @@ H316_OPT = -I ${H316D} HP2100D = HP2100/ HP2100 = ${HP2100D}hp2100_stddev.c ${HP2100D}hp2100_dp.c ${HP2100D}hp2100_dq.c \ - ${HP2100D}hp2100_dr.c ${HP2100D}hp2100_lp.c ${HP2100D}hp2100_ms.c \ + ${HP2100D}hp2100_dr.c ${HP2100D}hp2100_lps.c ${HP2100D}hp2100_ms.c \ ${HP2100D}hp2100_mt.c ${HP2100D}hp2100_mux.c ${HP2100D}hp2100_cpu.c \ - ${HP2100D}hp2100_fp.c ${HP2100D}hp2100_sys.c + ${HP2100D}hp2100_fp.c ${HP2100D}hp2100_sys.c ${HP2100D}hp2100_lpt.c HP2100_OPT = -I ${HP2100D} @@ -109,13 +122,38 @@ I1401_OPT = -I ${I1401D} -VAXD = VAX/ -VAX = ${VAXD}vax_cpu1.c ${VAXD}vax_cpu.c ${VAXD}vax_fpa.c ${VAXD}vax_io.c \ - ${VAXD}vax_mmu.c ${VAXD}vax_stddev.c ${VAXD}vax_sys.c \ - ${VAXD}vax_sysdev.c \ - ${PDP11D}pdp11_rl.c ${PDP11D}pdp11_rq.c ${PDP11D}pdp11_ts.c \ - ${PDP11D}pdp11_dz.c ${PDP11D}pdp11_lp.c -VAX_OPT = -I ${VAXD} -I ${PDP11D} -DUSE_INT64 +I1620D = I1620/ +I1620 = ${I1620D}i1620_cd.c ${I1620D}i1620_dp.c ${I1620D}i1620_pt.c \ + ${I1620D}i1620_tty.c ${I1620D}i1620_cpu.c ${I1620D}i1620_lp.c \ + ${I1620D}i1620_fp.c ${I1620D}i1620_sys.c +I1620_OPT = -I ${I1620D} + + + +IBM1130D = Ibm1130/ +IBM1130 = ${IBM1130D}ibm1130_cpu.c ${IBM1130D}ibm1130_cr.c \ + ${IBM1130D}ibm1130_disk.c ${IBM1130D}ibm1130_stddev.c \ + ${IBM1130D}ibm1130_sys.c ${IBM1130D}ibm1130_gdu.c \ + ${IBM1130D}ibm1130_gui.c ${IBM1130D}ibm1130_prt.c +IBM1130_OPT = -I ${IBM1130D} + + + +ID16D = Interdata/ +ID16 = ${ID16D}id16_cpu.c ${ID16D}id16_sys.c ${ID16D}id_dp.c \ + ${ID16D}id_fd.c ${ID16D}id_fp.c ${ID16D}id_idc.c ${ID16D}id_io.c \ + ${ID16D}id_lp.c ${ID16D}id_mt.c ${ID16D}id_pas.c ${ID16D}id_pt.c \ + ${ID16D}id_tt.c ${ID16D}id_uvc.c +ID16_OPT = -I ${ID16D} + + + +ID32D = Interdata/ +ID32 = ${ID32D}id32_cpu.c ${ID32D}id32_sys.c ${ID32D}id_dp.c \ + ${ID32D}id_fd.c ${ID32D}id_fp.c ${ID32D}id_idc.c ${ID32D}id_io.c \ + ${ID32D}id_lp.c ${ID32D}id_mt.c ${ID32D}id_pas.c ${ID32D}id_pt.c \ + ${ID32D}id_tt.c ${ID32D}id_uvc.c +ID32_OPT = -I ${ID32D} @@ -135,7 +173,8 @@ ALTAIR_OPT = -I ${ALTAIRD} ALTAIRZ80D = AltairZ80/ ALTAIRZ80 = ${ALTAIRZ80D}altairz80_cpu.c ${ALTAIRZ80D}altairz80_dsk.c \ - ${ALTAIRZ80D}altairz80_sio.c ${ALTAIRZ80D}altairz80_sys.c + ${ALTAIRZ80D}altairz80_sio.c ${ALTAIRZ80D}altairz80_sys.c \ + ${ALTAIRZ80D}altairz80_hdsk.c ALTAIRZ80_OPT = -I ${ALTAIRZ80D} @@ -145,13 +184,23 @@ GRI = ${GRID}gri_cpu.c ${GRID}gri_stddev.c ${GRID}gri_sys.c GRI_OPT = -I ${GRID} + +SDSD = SDS/ +SDS = ${SDSD}sds_cpu.c ${SDSD}sds_drm.c ${SDSD}sds_dsk.c ${SDSD}sds_io.c \ + ${SDSD}sds_lp.c ${SDSD}sds_mt.c ${SDSD}sds_mux.c ${SDSD}sds_rad.c \ + ${SDSD}sds_stddev.c ${SDSD}sds_sys.c +SDS_OPT = -I ${SDSD} + + + # # Build everything # all : ${BIN}pdp1 ${BIN}pdp4 ${BIN}pdp7 ${BIN}pdp8 ${BIN}pdp9 ${BIN}pdp15 \ ${BIN}pdp11 ${BIN}pdp10 ${BIN}vax ${BIN}nova ${BIN}eclipse ${BIN}h316 \ - ${BIN}hp2100 ${BIN}i1401 ${BIN}s3 ${BIN}altair \ - ${BIN}altairz80 ${BIN}gri + ${BIN}hp2100 ${BIN}i1401 ${BIN}i1620 ${BIN}s3 ${BIN}altair \ + ${BIN}altairz80 ${BIN}gri ${BIN}i1620 ${BIN}ibm1130 \ + ${BIN}id16 ${BIN}id32 ${BIN}sds @@ -228,6 +277,14 @@ ${BIN}i1401 : ${I1401} ${SIM} +${BIN}i1620 : ${I1620} ${SIM} + ${CC} ${I1620} ${SIM} ${I1620_OPT} -o $@ + + +${BIN}ibm1130 : ${IBM1130} + ${CC} ${IBM1130} ${SIM} ${IBM1130_OPT} -o $@ + + ${BIN}s3 : ${S3} ${SIM} ${CC} ${S3} ${SIM} ${S3_OPT} -o $@ @@ -236,9 +293,21 @@ ${BIN}altair : ${ALTAIR} ${SIM} ${CC} ${ALTAIR} ${SIM} ${ALTAIR_OPT} -o $@ -${BIN}altairz80 : ${ALTAIRZ80} ${SIM} +${BIN}altairz80 : ${ALTAIRZ80} ${SIM} ${ALTAIRZ80D}altairZ80_defs.h ${CC} ${ALTAIRZ80_OPT} ${ALTAIRZ80} ${SIM} -o $@ - +${ALTAIRZ80D}altairZ80_defs.h : ${ALTAIRZ80D}altairz80_defs.h + cp ${ALTAIRZ80D}altairz80_defs.h ${ALTAIRZ80D}altairZ80_defs.h ${BIN}gri : ${GRI} ${SIM} ${CC} ${GRI} ${SIM} ${GRI_OPT} -o $@ + +${BIN}id16 : ${ID16} ${SIM} + ${CC} ${ID16} ${SIM} ${ID16_OPT} -o $@ + +${BIN}id32 : ${ID32} ${SIM} + ${CC} ${ID32} ${SIM} ${ID32_OPT} -o $@ + +${BIN}sds : ${SDS} ${SIM} + ${CC} ${SDS} ${SIM} ${SDS_OPT} -o $@ + + diff --git a/makefile_ether b/makefile_ether new file mode 100644 index 00000000..62634608 --- /dev/null +++ b/makefile_ether @@ -0,0 +1,313 @@ +# CC Command +# +# Note: -O2 is sometimes broken in GCC when setjump/longjump is being +# used. Try -O2 only with released simulators. +# +CC = gcc -O2 -lm -I . +#CC = gcc -O2 -g -lm -I . + + + +# +# Common Libraries +# +BIN = BIN/ +SIM = scp.c scp_tty.c sim_sock.c sim_tmxr.c sim_ether.c + + + +# +# Emulator source files and compile time options +# +PDP1D = PDP1/ +PDP1 = ${PDP1D}pdp1_lp.c ${PDP1D}pdp1_cpu.c ${PDP1D}pdp1_stddev.c \ + ${PDP1D}pdp1_sys.c ${PDP1D}pdp1_dt.c +PDP1_OPT = -I ${PDP1D} + + +NOVAD = NOVA/ +NOVA = ${NOVAD}nova_sys.c ${NOVAD}nova_cpu.c ${NOVAD}nova_dkp.c \ + ${NOVAD}nova_dsk.c ${NOVAD}nova_lp.c ${NOVAD}nova_mta.c \ + ${NOVAD}nova_plt.c ${NOVAD}nova_pt.c ${NOVAD}nova_clk.c \ + ${NOVAD}nova_tt.c ${NOVAD}nova_tt1.c +NOVA_OPT = -I ${NOVAD} + + + +ECLIPSE = ${NOVAD}eclipse_cpu.c ${NOVAD}eclipse_tt.c ${NOVAD}nova_sys.c \ + ${NOVAD}nova_dkp.c ${NOVAD}nova_dsk.c ${NOVAD}nova_lp.c \ + ${NOVAD}nova_mta.c ${NOVAD}nova_plt.c ${NOVAD}nova_pt.c \ + ${NOVAD}nova_clk.c ${NOVAD}nova_tt1.c +ECLIPSE_OPT = -I ${NOVAD} -DECLIPSE + + + +PDP18BD = PDP18B/ +PDP18B = ${PDP18BD}pdp18b_dt.c ${PDP18BD}pdp18b_drm.c ${PDP18BD}pdp18b_cpu.c \ + ${PDP18BD}pdp18b_lp.c ${PDP18BD}pdp18b_mt.c ${PDP18BD}pdp18b_rf.c \ + ${PDP18BD}pdp18b_rp.c ${PDP18BD}pdp18b_stddev.c ${PDP18BD}pdp18b_sys.c \ + ${PDP18BD}pdp18b_tt1.c +PDP4_OPT = -DPDP4 -I ${PDP18BD} +PDP7_OPT = -DPDP7 -I ${PDP18BD} +PDP9_OPT = -DPDP9 -I ${PDP18BD} +PDP15_OPT = -DPDP15 -I ${PDP18BD} + + + +PDP11D = PDP11/ +PDP11 = ${PDP11D}pdp11_fp.c ${PDP11D}pdp11_cpu.c ${PDP11D}pdp11_dz.c \ + ${PDP11D}pdp11_cis.c ${PDP11D}pdp11_lp.c ${PDP11D}pdp11_rk.c \ + ${PDP11D}pdp11_rl.c ${PDP11D}pdp11_rp.c ${PDP11D}pdp11_rx.c \ + ${PDP11D}pdp11_stddev.c ${PDP11D}pdp11_sys.c ${PDP11D}pdp11_tc.c \ + ${PDP11D}pdp11_tm.c ${PDP11D}pdp11_ts.c ${PDP11D}pdp11_io.c \ + ${PDP11D}pdp11_rq.c ${PDP11D}pdp11_tq.c ${PDP11D}pdp11_pclk.c \ + ${PDP11D}pdp11_ry.c ${PDP11D}pdp11_pt.c ${PDP11D}pdp11_hk.c \ + ${PDP11D}pdp11_xq.c +PDP11_OPT = -I ${PDP11D} -DUSE_NETWORK -lpcap + + + +VAXD = VAX/ +VAX = ${VAXD}vax_cpu1.c ${VAXD}vax_cpu.c ${VAXD}vax_fpa.c ${VAXD}vax_io.c \ + ${VAXD}vax_mmu.c ${VAXD}vax_stddev.c ${VAXD}vax_sys.c \ + ${VAXD}vax_sysdev.c \ + ${PDP11D}pdp11_rl.c ${PDP11D}pdp11_rq.c ${PDP11D}pdp11_ts.c \ + ${PDP11D}pdp11_dz.c ${PDP11D}pdp11_lp.c ${PDP11D}pdp11_tq.c \ + ${PDP11D}pdp11_pt.c ${PDP11D}pdp11_xq.c +VAX_OPT = -I ${VAXD} -I ${PDP11D} -DUSE_INT64 -DUSE_NETWORK -lpcap + + + +PDP10D = PDP10/ +PDP10 = ${PDP10D}pdp10_fe.c ${PDP10D}pdp10_dz.c ${PDP10D}pdp10_cpu.c \ + ${PDP10D}pdp10_ksio.c ${PDP10D}pdp10_lp20.c ${PDP10D}pdp10_mdfp.c \ + ${PDP10D}pdp10_pag.c ${PDP10D}pdp10_rp.c ${PDP10D}pdp10_sys.c \ + ${PDP10D}pdp10_tim.c ${PDP10D}pdp10_tu.c ${PDP10D}pdp10_xtnd.c \ + ${PDP10D}pdp10_pt.c ${PDP11D}pdp11_ry.c +PDP10_OPT = -DUSE_INT64 -I ${PDP10D} -I ${PDP11D} -I ${VAXD} + + + +PDP8D = PDP8/ +PDP8 = ${PDP8D}pdp8_cpu.c ${PDP8D}pdp8_clk.c ${PDP8D}pdp8_df.c \ + ${PDP8D}pdp8_dt.c ${PDP8D}pdp8_lp.c ${PDP8D}pdp8_mt.c \ + ${PDP8D}pdp8_pt.c ${PDP8D}pdp8_rf.c ${PDP8D}pdp8_rk.c \ + ${PDP8D}pdp8_rx.c ${PDP8D}pdp8_sys.c ${PDP8D}pdp8_tt.c \ + ${PDP8D}pdp8_ttx.c ${PDP8D}pdp8_rl.c +PDP8_OPT = -I ${PDP8D} + + + +H316D = H316/ +H316 = ${H316D}h316_stddev.c ${H316D}h316_lp.c ${H316D}h316_cpu.c \ + ${H316D}h316_sys.c +H316_OPT = -I ${H316D} + + + +HP2100D = HP2100/ +HP2100 = ${HP2100D}hp2100_stddev.c ${HP2100D}hp2100_dp.c ${HP2100D}hp2100_dq.c \ + ${HP2100D}hp2100_dr.c ${HP2100D}hp2100_lps.c ${HP2100D}hp2100_ms.c \ + ${HP2100D}hp2100_mt.c ${HP2100D}hp2100_mux.c ${HP2100D}hp2100_cpu.c \ + ${HP2100D}hp2100_fp.c ${HP2100D}hp2100_sys.c ${HP2100D}hp2100_lpt.c +HP2100_OPT = -I ${HP2100D} + + + +I1401D = I1401/ +I1401 = ${I1401D}i1401_lp.c ${I1401D}i1401_cpu.c ${I1401D}i1401_iq.c \ + ${I1401D}i1401_cd.c ${I1401D}i1401_mt.c ${I1401D}i1401_dp.c \ + ${I1401D}i1401_sys.c +I1401_OPT = -I ${I1401D} + + + +I1620D = I1620/ +I1620 = ${I1620D}i1620_cd.c ${I1620D}i1620_dp.c ${I1620D}i1620_pt.c \ + ${I1620D}i1620_tty.c ${I1620D}i1620_cpu.c ${I1620D}i1620_lp.c \ + ${I1620D}i1620_fp.c ${I1620D}i1620_sys.c +I1620_OPT = -I ${I1620D} + + + +IBM1130D = Ibm1130/ +IBM1130 = ${IBM1130D}ibm1130_cpu.c ${IBM1130D}ibm1130_cr.c \ + ${IBM1130D}ibm1130_disk.c ${IBM1130D}ibm1130_stddev.c \ + ${IBM1130D}ibm1130_sys.c ${IBM1130D}ibm1130_gdu.c \ + ${IBM1130D}ibm1130_gui.c ${IBM1130D}ibm1130_prt.c +IBM1130_OPT = -I ${IBM1130D} + + + +ID16D = Interdata/ +ID16 = ${ID16D}id16_cpu.c ${ID16D}id16_sys.c ${ID16D}id_dp.c \ + ${ID16D}id_fd.c ${ID16D}id_fp.c ${ID16D}id_idc.c ${ID16D}id_io.c \ + ${ID16D}id_lp.c ${ID16D}id_mt.c ${ID16D}id_pas.c ${ID16D}id_pt.c \ + ${ID16D}id_tt.c ${ID16D}id_uvc.c +ID16_OPT = -I ${ID16D} + + + +ID32D = Interdata/ +ID32 = ${ID32D}id32_cpu.c ${ID32D}id32_sys.c ${ID32D}id_dp.c \ + ${ID32D}id_fd.c ${ID32D}id_fp.c ${ID32D}id_idc.c ${ID32D}id_io.c \ + ${ID32D}id_lp.c ${ID32D}id_mt.c ${ID32D}id_pas.c ${ID32D}id_pt.c \ + ${ID32D}id_tt.c ${ID32D}id_uvc.c +ID32_OPT = -I ${ID32D} + + + +S3D = S3/ +S3 = ${S3D}s3_cd.c ${S3D}s3_cpu.c ${S3D}s3_disk.c ${S3D}s3_lp.c \ + ${S3D}s3_pkb.c ${S3D}s3_sys.c +S3_OPT = -I ${S3D} + + + +ALTAIRD = ALTAIR/ +ALTAIR = ${ALTAIRD}altair_sio.c ${ALTAIRD}altair_cpu.c ${ALTAIRD}altair_dsk.c \ + ${ALTAIRD}altair_sys.c +ALTAIR_OPT = -I ${ALTAIRD} + + + +ALTAIRZ80D = AltairZ80/ +ALTAIRZ80 = ${ALTAIRZ80D}altairz80_cpu.c ${ALTAIRZ80D}altairz80_dsk.c \ + ${ALTAIRZ80D}altairz80_sio.c ${ALTAIRZ80D}altairz80_sys.c \ + ${ALTAIRZ80D}altairz80_hdsk.c +ALTAIRZ80_OPT = -I ${ALTAIRZ80D} + + + +GRID = GRI/ +GRI = ${GRID}gri_cpu.c ${GRID}gri_stddev.c ${GRID}gri_sys.c +GRI_OPT = -I ${GRID} + + + +SDSD = SDS/ +SDS = ${SDSD}sds_cpu.c ${SDSD}sds_drm.c ${SDSD}sds_dsk.c ${SDSD}sds_io.c \ + ${SDSD}sds_lp.c ${SDSD}sds_mt.c ${SDSD}sds_mux.c ${SDSD}sds_rad.c \ + ${SDSD}sds_stddev.c ${SDSD}sds_sys.c +SDS_OPT = -I ${SDSD} + + + +# +# Build everything +# +all : ${BIN}pdp1 ${BIN}pdp4 ${BIN}pdp7 ${BIN}pdp8 ${BIN}pdp9 ${BIN}pdp15 \ + ${BIN}pdp11 ${BIN}pdp10 ${BIN}vax ${BIN}nova ${BIN}eclipse ${BIN}h316 \ + ${BIN}hp2100 ${BIN}i1401 ${BIN}i1620 ${BIN}s3 ${BIN}altair \ + ${BIN}altairz80 ${BIN}gri ${BIN}i1620 ${BIN}ibm1130 \ + ${BIN}id16 ${BIN}id32 ${BIN}sds + + + +# +# Individual builds +# +${BIN}pdp1 : ${PDP1} ${SIM} + ${CC} ${PDP1} ${SIM} ${PDP1_OPT} -o $@ + + + +${BIN}pdp4 : ${PDP18B} ${SIM} + ${CC} ${PDP18B} ${SIM} ${PDP4_OPT} -o $@ + + + +${BIN}pdp7 : ${PDP18B} ${SIM} + ${CC} ${PDP18B} ${SIM} ${PDP7_OPT} -o $@ + + + +${BIN}pdp8 : ${PDP8} ${SIM} + ${CC} ${PDP8} ${SIM} ${PDP8_OPT} -o $@ + + + +${BIN}pdp9 : ${PDP18B} ${SIM} + ${CC} ${PDP18B} ${SIM} ${PDP9_OPT} -o $@ + + + +${BIN}pdp15 : ${PDP18B} ${SIM} + ${CC} ${PDP18B} ${SIM} ${PDP15_OPT} -o $@ + + + +${BIN}pdp10 : ${PDP10} ${SIM} + ${CC} ${PDP10} ${SIM} ${PDP10_OPT} -o $@ + + + +${BIN}pdp11 : ${PDP11} ${SIM} + ${CC} ${PDP11} ${SIM} ${PDP11_OPT} -o $@ + + + +${BIN}vax : ${VAX} ${SIM} + ${CC} ${VAX} ${SIM} ${VAX_OPT} -o $@ + + + +${BIN}nova : ${NOVA} ${SIM} + ${CC} ${NOVA} ${SIM} ${NOVA_OPT} -o $@ + + + +${BIN}eclipse : ${ECLIPSE} ${SIM} + ${CC} ${ECLIPSE} ${SIM} ${ECLIPSE_OPT} -o $@ + + + +${BIN}h316 : ${H316} ${SIM} + ${CC} ${H316} ${SIM} ${H316_OPT} -o $@ + + + +${BIN}hp2100 : ${HP2100} ${SIM} + ${CC} ${HP2100} ${SIM} ${HP2100_OPT} -o $@ + + + +${BIN}i1401 : ${I1401} ${SIM} + ${CC} ${I1401} ${SIM} ${I1401_OPT} -o $@ + + + +${BIN}i1620 : ${I1620} ${SIM} + ${CC} ${I1620} ${SIM} ${I1620_OPT} -o $@ + + +${BIN}ibm1130 : ${IBM1130} + ${CC} ${IBM1130} ${SIM} ${IBM1130_OPT} -o $@ + + +${BIN}s3 : ${S3} ${SIM} + ${CC} ${S3} ${SIM} ${S3_OPT} -o $@ + + +${BIN}altair : ${ALTAIR} ${SIM} + ${CC} ${ALTAIR} ${SIM} ${ALTAIR_OPT} -o $@ + + +${BIN}altairz80 : ${ALTAIRZ80} ${SIM} ${ALTAIRZ80D}altairZ80_defs.h + ${CC} ${ALTAIRZ80_OPT} ${ALTAIRZ80} ${SIM} -o $@ +${ALTAIRZ80D}altairZ80_defs.h : ${ALTAIRZ80D}altairz80_defs.h + cp ${ALTAIRZ80D}altairz80_defs.h ${ALTAIRZ80D}altairZ80_defs.h + +${BIN}gri : ${GRI} ${SIM} + ${CC} ${GRI} ${SIM} ${GRI_OPT} -o $@ + +${BIN}id16 : ${ID16} ${SIM} + ${CC} ${ID16} ${SIM} ${ID16_OPT} -o $@ + +${BIN}id32 : ${ID32} ${SIM} + ${CC} ${ID32} ${SIM} ${ID32_OPT} -o $@ + +${BIN}sds : ${SDS} ${SIM} + ${CC} ${SDS} ${SIM} ${SDS_OPT} -o $@ + + diff --git a/scp.c b/scp.c index d3ecbda1..021ffbbd 100644 --- a/scp.c +++ b/scp.c @@ -23,6 +23,16 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 16-Nov-02 RMS Fixed bug in register name match algorithm + 13-Oct-02 RMS Fixed Borland compiler warnings (found by Hans Pufal) + 05-Oct-02 RMS Fixed bugs in set_logon, ssh_break (found by David Hittner) + Added support for fixed buffer devices + Added support for Telnet console, removed VT support + Added help + Added VMS file optimizations (from Robert Alan Byer) + Added quiet mode, DO with parameters, GUI interface, + extensible commands (from Brian Knittel) + Added device enable/disable commands 14-Jul-02 RMS Fixed exit bug in do, added -v switch (from Brian Knittel) 17-May-02 RMS Fixed bug in fxread/fxwrite error usage (found by Norm Lastovic) @@ -80,9 +90,13 @@ 22-May-95 RMS Added symbolic input 13-Apr-95 RMS Added symbolic printouts */ + +/* Macros and data structures */ #include "sim_defs.h" #include "sim_rev.h" +#include "sim_sock.h" +#include "sim_tmxr.h" #include #include @@ -119,66 +133,10 @@ sim_rtime = sim_rtime + ((uint32) (x - sim_interval)); \ x = sim_interval -struct brktab { - t_addr addr; - int32 typ; - int32 cnt; - char *act; -}; - -typedef struct brktab BRKTAB; - -extern char sim_name[]; -extern DEVICE *sim_devices[]; -extern REG *sim_PC; -extern char *sim_stop_messages[]; -extern t_stat sim_instr (void); -extern t_stat sim_load (FILE *ptr, char *cptr, char *fnam, int flag); -extern int32 sim_emax; -extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, - UNIT *uptr, int32 sw); -extern t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, - int32 sw); -extern t_stat ttinit (void); -extern t_stat ttrunstate (void); -extern t_stat ttcmdstate (void); -extern t_stat ttclose (void); -extern t_stat sim_putchar (int32 out); -extern uint32 sim_os_msec (void); -extern int32 sim_vt; -UNIT *sim_clock_queue = NULL; -int32 sim_interval = 0; -int32 sim_switches = 0; -int32 sim_is_running = 0; -uint32 sim_brk_summ = 0; -uint32 sim_brk_types = 0; -uint32 sim_brk_dflt = 0; -BRKTAB *sim_brk_tab = NULL; -int32 sim_brk_ent = 0; -int32 sim_brk_lnt = 0; -int32 sim_brk_ins = 0; -t_bool sim_brk_pend = FALSE; -t_addr sim_brk_ploc = 0; -static double sim_time; -static uint32 sim_rtime; -static int32 noqueue_time; -volatile int32 stop_cpu = 0; -t_value *sim_eval = NULL; -int32 sim_end = 1; /* 1 = little */ -FILE *sim_log = NULL; /* log file */ -unsigned char sim_flip[FLIP_SIZE]; - -t_stat sim_brk_init (void); -t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt); -t_stat sim_brk_clr (t_addr loc, int32 sw); -t_stat sim_brk_clrall (int32 sw); -t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw); -t_stat sim_brk_showall (FILE *st, int32 sw); -void sim_brk_npc (void); #define print_val(a,b,c,d) fprint_val (stdout, (a), (b), (c), (d)) -#define SZ_D(dp) (size_map[((dp) -> dwidth + CHAR_BIT - 1) / CHAR_BIT]) +#define SZ_D(dp) (size_map[((dp)->dwidth + CHAR_BIT - 1) / CHAR_BIT]) #define SZ_R(rp) \ - (size_map[((rp) -> width + (rp) -> offset + CHAR_BIT - 1) / CHAR_BIT]) + (size_map[((rp)->width + (rp)->offset + CHAR_BIT - 1) / CHAR_BIT]) #if defined (t_int64) #define SZ_LOAD(sz,v,mb,j) \ if (sz == sizeof (uint8)) v = *(((uint8 *) mb) + j); \ @@ -213,51 +171,160 @@ void sim_brk_npc (void); else if (sim_switches & SWMASK ('H')) val = 16; \ else val = dft; -CTAB *find_ctab (CTAB *tab, char *gbuf); -t_stat set_vt (int32 flag, char *cptr); +struct brktab { + t_addr addr; + int32 typ; + int32 cnt; + char *act; +}; + +typedef struct brktab BRKTAB; + +#if defined(VMS) +#define FOPEN(file_spec, mode) fopen (file_spec, mode, "ALQ=32", "DEQ=4096", \ + "MBF=6", "MBC=128", "FOP=cbt,tef,sqo", "ROP=rah,wbh") +#else +#define FOPEN(file_spec, mode) fopen (file_spec, mode) +#endif + +/* VM interface */ + +extern char sim_name[]; +extern DEVICE *sim_devices[]; +extern REG *sim_PC; +extern char *sim_stop_messages[]; +extern t_stat sim_instr (void); +extern t_stat sim_load (FILE *ptr, char *cptr, char *fnam, int32 flag); +extern int32 sim_emax; +extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, + UNIT *uptr, int32 sw); +extern t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, + int32 sw); + +/* The per-simulator init routine is a weak global that defaults to NULL + The other per-simulator pointers can be overrriden by the init routine */ + +void (*sim_vm_init) (void); +char* (*sim_vm_read) (char *ptr, int32 size, FILE *stream) = NULL; +void (*sim_vm_post) (t_bool from_scp) = NULL; +CTAB *sim_vm_cmd = NULL; + +/* External routines */ + +extern t_stat ttinit (void); +extern t_stat ttrunstate (void); +extern t_stat ttcmdstate (void); +extern t_stat ttclose (void); +extern t_stat sim_os_poll_kbd (void); +extern t_stat sim_os_putchar (int32 out); +extern uint32 sim_os_msec (void); +extern int sim_os_sleep (unsigned int sec); + +/* Prototypes */ + +t_stat sim_brk_init (void); +t_stat sim_brk_set (t_addr loc, int32 sw, int32 ncnt); +t_stat sim_brk_clr (t_addr loc, int32 sw); +t_stat sim_brk_clrall (int32 sw); +t_stat sim_brk_show (FILE *st, t_addr loc, int32 sw); +t_stat sim_brk_showall (FILE *st, int32 sw); +void sim_brk_npc (void); +t_stat set_telnet (int32 flg, char *cptr); +t_stat set_notelnet (int32 flg, char *cptr); t_stat set_logon (int32 flag, char *cptr); t_stat set_logoff (int32 flag, char *cptr); -t_stat set_radix (DEVICE *dptr, UNIT *uptr, int flag); +t_stat set_radix (DEVICE *dptr, UNIT *uptr, int32 flag); +t_stat set_devenbdis (DEVICE *dptr, UNIT *uptr, int32 flag); t_stat set_onoff (DEVICE *dptr, UNIT *uptr, int32 flag); t_stat ssh_break (FILE *st, char *cptr, int32 flg); -t_stat show_config (FILE *st, int32 flag); -t_stat show_queue (FILE *st, int32 flag); -t_stat show_time (FILE *st, int32 flag); -t_stat show_mod_names (FILE *st, int32 flag); -t_stat show_log (FILE *st, int32 flag); -t_stat show_vt (FILE *st, int32 flag); +t_stat show_config (FILE *st, int32 flag, char *cptr); +t_stat show_queue (FILE *st, int32 flag, char *cptr); +t_stat show_time (FILE *st, int32 flag, char *cptr); +t_stat show_mod_names (FILE *st, int32 flag, char *cptr); +t_stat show_log (FILE *st, int32 flag, char *cptr); +t_stat show_telnet (FILE *st, int32 flag, char *cptr); +t_stat show_version (FILE *st, int32 flag, char *cptr); +t_stat show_break (FILE *st, int32 flag, char *cptr); t_stat show_device (FILE *st, DEVICE *dptr, int32 flag); t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag); t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flg); t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr, int32 flag); +t_stat sim_check_console (int32 sec); int32 get_switches (char *cptr); -t_value get_rval (REG *rptr, int idx); -void put_rval (REG *rptr, int idx, t_value val); +t_value get_rval (REG *rptr, int32 idx); +void put_rval (REG *rptr, int32 idx, t_value val); t_stat get_aval (t_addr addr, DEVICE *dptr, UNIT *uptr); -t_value strtotv (char *inptr, char **endptr, int radix); -t_stat fprint_val (FILE *stream, t_value val, int rdx, int wid, int fmt); +t_value strtotv (char *inptr, char **endptr, int32 radix); void fprint_stopped (FILE *stream, t_stat r); -char *read_line (char *ptr, int size, FILE *stream); +char *read_line (char *ptr, int32 size, FILE *stream); +CTAB *find_ctab (CTAB *tab, char *gbuf); +CTAB *find_cmd (char *gbuf); DEVICE *find_dev (char *ptr); DEVICE *find_unit (char *ptr, UNIT **uptr); REG *find_reg_glob (char *ptr, char **optr, DEVICE **gdptr); +t_bool restore_skip_val (FILE *rfile); t_bool qdisable (DEVICE *dptr); t_stat attach_err (UNIT *uptr, t_stat stat); t_stat detach_all (int32 start_device, t_bool shutdown); -t_stat ex_reg (FILE *ofile, t_value val, int flag, REG *rptr, t_addr idx); -t_stat dep_reg (int flag, char *cptr, REG *rptr, t_addr idx); -t_stat ex_addr (FILE *ofile, int flag, t_addr addr, DEVICE *dptr, UNIT *uptr); -t_stat dep_addr (int flag, char *cptr, t_addr addr, DEVICE *dptr, - UNIT *uptr, int dfltinc); -char *get_range (char *cptr, t_addr *lo, t_addr *hi, int rdx, +t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, t_addr idx); +t_stat dep_reg (int32 flag, char *cptr, REG *rptr, t_addr idx); +t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr); +t_stat dep_addr (int32 flag, char *cptr, t_addr addr, DEVICE *dptr, + UNIT *uptr, int32 dfltinc); +char *get_range (char *cptr, t_addr *lo, t_addr *hi, int32 rdx, t_addr max, char term); SCHTAB *get_search (char *cptr, DEVICE *dptr, SCHTAB *schptr); -int test_search (t_value val, SCHTAB *schptr); +int32 test_search (t_value val, SCHTAB *schptr); t_stat step_svc (UNIT *ptr); -t_stat show_version (FILE *st, int flag); +t_stat reset_cmd (int32 flag, char *ptr); +t_stat exdep_cmd (int32 flag, char *ptr); +t_stat load_cmd (int32 flag, char *ptr); +t_stat run_cmd (int32 flag, char *ptr); +t_stat attach_cmd (int32 flag, char *ptr); +t_stat detach_cmd (int32 flag, char *ptr); +t_stat save_cmd (int32 flag, char *ptr); +t_stat restore_cmd (int32 flag, char *ptr); +t_stat exit_cmd (int32 flag, char *ptr); +t_stat set_cmd (int32 flag, char *ptr); +t_stat show_cmd (int32 flag, char *ptr); +t_stat brk_cmd (int32 flag, char *ptr); +t_stat do_cmd (int32 flag, char *ptr); +t_stat help_cmd (int32 flag, char *ptr); + +/* Global data */ + +UNIT *sim_clock_queue = NULL; +int32 sim_interval = 0; +int32 sim_switches = 0; +int32 sim_is_running = 0; +uint32 sim_brk_summ = 0; +uint32 sim_brk_types = 0; +uint32 sim_brk_dflt = 0; +BRKTAB *sim_brk_tab = NULL; +int32 sim_brk_ent = 0; +int32 sim_brk_lnt = 0; +int32 sim_brk_ins = 0; +t_bool sim_brk_pend = FALSE; +t_addr sim_brk_ploc = 0; +int32 sim_quiet = 0; +static double sim_time; +static uint32 sim_rtime; +static int32 noqueue_time; +volatile int32 stop_cpu = 0; +t_value *sim_eval = NULL; +int32 sim_end = 1; /* 1 = little */ +FILE *sim_log = NULL; /* log file */ +unsigned char sim_flip[FLIP_SIZE]; + +TMLN sim_con_ldsc = { 0 }; /* console line descr */ +TMXR sim_con_tmxr = { 1, 0, 0, &sim_con_ldsc }; /* console line mux */ UNIT step_unit = { UDATA (&step_svc, 0, 0) }; -const char save_vercur[] = "V2.6"; + +/* Tables and strings */ + +const char save_vercur[] = "V2.10"; +const char save_ver26[] = "V2.6"; const char save_ver25[] = "V2.5"; const char *scp_error_messages[] = { "Address space exceeded", @@ -298,7 +365,9 @@ const char *scp_error_messages[] = { "Non-existent parameter", "Nested DO commands", "Internal error", - "Invalid magtape record length" + "Invalid magtape record length", + "Console Telnet connection lost", + "Console Telnet connection timed out" }; const size_t size_map[] = { sizeof (int8), @@ -330,49 +399,77 @@ const t_value width_mask[] = { 0, 0x7FFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF #endif }; - -t_stat reset_cmd (int flag, char *ptr); -t_stat exdep_cmd (int flag, char *ptr); -t_stat load_cmd (int flag, char *ptr); -t_stat run_cmd (int flag, char *ptr); -t_stat attach_cmd (int flag, char *ptr); -t_stat detach_cmd (int flag, char *ptr); -t_stat save_cmd (int flag, char *ptr); -t_stat restore_cmd (int flag, char *ptr); -t_stat exit_cmd (int flag, char *ptr); -t_stat set_cmd (int flag, char *ptr); -t_stat show_cmd (int flag, char *ptr); -t_stat brk_cmd (int flag, char *ptr); -t_stat do_cmd (int flag, char *ptr); -t_stat help_cmd (int flag, char *ptr); static CTAB cmd_table[] = { - { "RESET", &reset_cmd, 0 }, - { "EXAMINE", &exdep_cmd, EX_E }, - { "IEXAMINE", &exdep_cmd, EX_E+EX_I }, - { "DEPOSIT", &exdep_cmd, EX_D }, - { "IDEPOSIT", &exdep_cmd, EX_D+EX_I }, - { "RUN", &run_cmd, RU_RUN }, - { "GO", &run_cmd, RU_GO }, - { "STEP", &run_cmd, RU_STEP }, - { "CONT", &run_cmd, RU_CONT }, - { "BOOT", &run_cmd, RU_BOOT }, - { "ATTACH", &attach_cmd, 0 }, - { "DETACH", &detach_cmd, 0 }, - { "SAVE", &save_cmd, 0 }, - { "RESTORE", &restore_cmd, 0 }, - { "GET", &restore_cmd, 0 }, - { "LOAD", &load_cmd, 0 }, - { "DUMP", &load_cmd, 1 }, - { "EXIT", &exit_cmd, 0 }, - { "QUIT", &exit_cmd, 0 }, - { "BYE", &exit_cmd, 0 }, - { "SET", &set_cmd, 0 }, - { "SHOW", &show_cmd, 0 }, - { "BREAK", &brk_cmd, SSH_ST }, - { "NOBREAK", &brk_cmd, SSH_CL }, - { "DO", &do_cmd, 0 }, - { "HELP", &help_cmd, 0 }, + { "RESET", &reset_cmd, 0, + "r{eset} {ALL|} reset simulator\n" }, + { "EXAMINE", &exdep_cmd, EX_E, + "e{xamine} examine memory or registers\n" }, + { "IEXAMINE", &exdep_cmd, EX_E+EX_I, + "ie{xamine} interactive examine memory or registers\n" }, + { "DEPOSIT", &exdep_cmd, EX_D, + "d{eposit} deposit in memory or registers\n" }, + { "IDEPOSIT", &exdep_cmd, EX_D+EX_I, + "id{eposit} interactive deposit in memory or registers\n" }, + { "RUN", &run_cmd, RU_RUN, + "ru{n} {new PC} reset and start simulation\n" }, + { "GO", &run_cmd, RU_GO, + "go {new PC} start simulation\n" }, + { "STEP", &run_cmd, RU_STEP, + "s{tep} {n} simulate n instructions\n" }, + { "CONT", &run_cmd, RU_CONT, + "c{ont} continue simulation\n" }, + { "BOOT", &run_cmd, RU_BOOT, + "b{oot} bootstrap unit\n" }, + { "BREAK", &brk_cmd, SSH_ST, + "br{eak} set breakpoints\n" }, + { "NOBREAK", &brk_cmd, SSH_CL, + "nobr{eak} clear breakpoints\n" }, + { "ATTACH", &attach_cmd, 0, + "at{tach} attach file to simulated unit\n" }, + { "DETACH", &detach_cmd, 0, + "det{ach} detach file from simulated unit\n" }, + { "SAVE", &save_cmd, 0, + "sa{ve} save simulator to file\n" }, + { "RESTORE", &restore_cmd, 0, + "rest{ore}|ge{t} restore simulator from file\n" }, + { "GET", &restore_cmd, 0, NULL }, + { "LOAD", &load_cmd, 0, + "l{oad} {} load binary file\n" }, + { "DUMP", &load_cmd, 1, + "du(mp) {} dump binary file\n" }, + { "EXIT", &exit_cmd, 0, + "exi{t}|q{uit}|by{e} exit from simulation\n" }, + { "QUIT", &exit_cmd, 0, NULL }, + { "BYE", &exit_cmd, 0, NULL }, + { "SET", &set_cmd, 0, + "set log enable logging to file\n" + "set nolog disable logging\n" + "set telnet enable Telnet port for console\n" + "set notelnet disable Telnet for console\n" + "set OCT|DEC|HEX set device display radix\n" + "set ENABLED enable device\n" + "set DISABLED disable device\n" + "set ONLINE enable unit\n" + "set OFFLINE disable unit\n" + "set | set device/unit parameter\n" + }, + { "SHOW", &show_cmd, 0, + "sh{ow} br{eak} show breakpoints on address list\n" + "sh{ow} c{onfiguration} show configuration\n" + "sh{ow} d{evices} show devices\n" + "sh{ow} l{og} show log\n" + "sh{ow} m{odifiers} show modifiers\n" + "sh{ow} q{ueue} show event queue\n" + "sh{ow} te{lnet} show console Telnet status\n" + "sh{ow} ti{me} show simulated time\n" + "sh{ow} ve{rsion} show simulator version\n" + "sh{ow} | show device parameters\n" }, + { "DO", &do_cmd, 0, + "do {arg,arg...} process command file\n" }, + { "HELP", &help_cmd, 0, + "h{elp} type this message\n" + "h{elp} type help for command\n" }, { NULL, NULL, 0 } }; /* Main command loop */ @@ -380,20 +477,36 @@ static CTAB cmd_table[] = { int main (int argc, char *argv[]) { char cbuf[CBUFSIZE], gbuf[CBUFSIZE], *cptr; -int32 i; +int32 i, sw; +t_bool lookswitch; t_stat stat; +CTAB *cmdp; union {int32 i; char c[sizeof (int32)]; } end_test; #if defined (__MWERKS__) && defined (macintosh) -argc = ccommand(&argv); +argc = ccommand (&argv); #endif -if ((stat = ttinit ()) != SCPE_OK) { - printf ("Fatal terminal initialization error\n%s\n", - scp_error_messages[stat - SCPE_BASE]); - return 0; } -printf ("\n"); -show_version (stdout, 0); +*cbuf = 0; /* init arg buffer */ +sim_switches = 0; /* init switches */ +lookswitch = TRUE; +for (i = 1; i < argc; i++) { /* loop thru args */ + if (argv[i] == NULL) continue; /* paranoia */ + if ((*argv[i] == '-') && lookswitch) { /* switch? */ + if ((sw = get_switches (argv[i])) < 0) { + printf ("Invalid switch %s\n", argv[i]); + return 0; } + sim_switches = sim_switches | sw; } + else { if ((strlen (argv[i]) + strlen (cbuf) + 1) >= CBUFSIZE) { + printf ("Argument string too long\n"); + return 0; } + if (*cbuf) strcat (cbuf, " "); /* concat args */ + strcat (cbuf, argv[i]); + lookswitch = FALSE; } /* no more switches */ + } /* end for */ +sim_quiet = sim_switches & SWMASK ('Q'); /* -q means quiet */ + +if (sim_vm_init != NULL) (*sim_vm_init)(); /* call once only */ end_test.i = 1; /* test endian-ness */ sim_end = end_test.c[0]; stop_cpu = 0; @@ -404,6 +517,11 @@ sim_clock_queue = NULL; sim_is_running = 0; sim_log = NULL; if (sim_emax <= 0) sim_emax = 1; + +if ((stat = ttinit ()) != SCPE_OK) { + printf ("Fatal terminal initialization error\n%s\n", + scp_error_messages[stat - SCPE_BASE]); + return 0; } if ((sim_eval = calloc (sim_emax, sizeof (t_value))) == NULL) { printf ("Unable to allocate examine buffer\n"); return 0; }; @@ -415,38 +533,56 @@ if ((stat = sim_brk_init ()) != SCPE_OK) { printf ("Fatal breakpoint table initialization error\n%s\n", scp_error_messages[stat - SCPE_BASE]); return 0; } +if (!sim_quiet) { + printf ("\n"); + show_version (stdout, 0, NULL); } -if ((argc > 1) && argv[1]) { /* cmd file arg? */ - stat = do_cmd (0, argv[1]); /* proc cmd file */ - if (stat == SCPE_OPENERR) fprintf (stderr, /* error? */ - "Can't open file %s\n", argv[1]); } +if (*cbuf) { /* cmd file arg? */ + stat = do_cmd (1, cbuf); /* proc cmd file */ + if (stat == SCPE_OPENERR) /* error? */ + fprintf (stderr, "Can't open file %s\n", cbuf); } +else stat = SCPE_OK; -do { printf ("sim> "); /* prompt */ - cptr = read_line (cbuf, CBUFSIZE, stdin); /* read command line */ - stat = SCPE_UNK; +while (stat != SCPE_EXIT) { /* in case exit */ + printf ("sim> "); /* prompt */ + if (sim_vm_read != NULL) /* sim routine? */ + cptr = (*sim_vm_read) (cbuf, CBUFSIZE, stdin); + else cptr = read_line (cbuf, CBUFSIZE, stdin); /* read command line */ if (cptr == NULL) continue; /* ignore EOF */ if (*cptr == 0) continue; /* ignore blank */ if (sim_log) fprintf (sim_log, "sim> %s\n", cbuf); /* log cmd */ cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */ - for (i = 0; cmd_table[i].name != NULL; i++) { - if (MATCH_CMD (gbuf, cmd_table[i].name) == 0) { - stat = cmd_table[i].action (cmd_table[i].arg, cptr); - break; } } + if (cmdp = find_cmd (gbuf)) /* lookup command */ + stat = cmdp->action (cmdp->arg, cptr); /* if found, exec */ + else stat = SCPE_UNK; if (stat >= SCPE_BASE) { /* error? */ printf ("%s\n", scp_error_messages[stat - SCPE_BASE]); if (sim_log) fprintf (sim_log, "%s\n", scp_error_messages[stat - SCPE_BASE]); } -} while (stat != SCPE_EXIT); + if (sim_vm_post != NULL) (*sim_vm_post) (TRUE); + } /* end while */ detach_all (0, TRUE); /* close files */ set_logoff (0, NULL); /* close log */ +set_notelnet (0, NULL); /* close Telnet */ ttclose (); /* close console */ return 0; } + +/* Find command routine */ + +CTAB *find_cmd (char *gbuf) +{ +CTAB *cmdp = NULL; + +if (sim_vm_cmd) cmdp = find_ctab (sim_vm_cmd, gbuf); /* try ext commands */ +if (cmdp == NULL) cmdp = find_ctab (cmd_table, gbuf); /* try regular cmds */ +return cmdp; +} /* Exit command */ -t_stat exit_cmd (int flag, char *cptr) +t_stat exit_cmd (int32 flag, char *cptr) { return SCPE_EXIT; } @@ -455,90 +591,115 @@ return SCPE_EXIT; void fprint_help (FILE *st) { -fprintf (st, "r{eset} {ALL|} reset simulator\n"); -fprintf (st, "e{xamine} examine memory or registers\n"); -fprintf (st, "ie{xamine} interactive examine memory or registers\n"); -fprintf (st, "d{eposit} deposit in memory or registers\n"); -fprintf (st, "id{eposit} interactive deposit in memory or registers\n"); -fprintf (st, "l{oad} {} load binary file\n"); -fprintf (st, "du(mp) {} dump binary file\n"); -fprintf (st, "ru{n} {new PC} reset and start simulation\n"); -fprintf (st, "go {new PC} start simulation\n"); -fprintf (st, "c{ont} continue simulation\n"); -fprintf (st, "s{tep} {n} simulate n instructions\n"); -fprintf (st, "b{oot} bootstrap unit\n"); -fprintf (st, "br{eak} set breakpoints\n"); -fprintf (st, "nobr{eak} clear breakpoints\n"); -fprintf (st, "at{tach} attach file to simulated unit\n"); -fprintf (st, "det{ach} detach file from simulated unit\n"); -fprintf (st, "sa{ve} save simulator to file\n"); -fprintf (st, "rest{ore}|ge{t} restore simulator from file\n"); -fprintf (st, "exi{t}|q{uit}|by{e} exit from simulation\n"); -fprintf (st, "set log enable logging to file\n"); -fprintf (st, "set nolog disable logging\n"); -fprintf (st, "set vt enable VT emulation (Windows only)\n"); -fprintf (st, "set novt disable VT emulation (Windows only)\n"); -fprintf (st, "set | set device/unit parameter\n"); -fprintf (st, "sh{ow} c{onfiguration} show configuration\n"); -fprintf (st, "sh{ow} d{evices} show devices\n"); -fprintf (st, "sh{ow} l{og} show log\n"); -fprintf (st, "sh{ow} m{odifiers} show modifiers\n"); -fprintf (st, "sh{ow} q{ueue} show event queue\n"); -fprintf (st, "sh{ow} t{ime} show simulated time\n"); -fprintf (st, "sh{ow} ve{rsion} show simulator version\n"); -fprintf (st, "sh{ow} vt show VT emulation\n"); -fprintf (st, "sh{ow} | show device parameters\n"); -fprintf (st, "do process command file\n"); -fprintf (st, "h{elp} type this message\n"); +CTAB *cmdp; + +for (cmdp = cmd_table; cmdp && (cmdp->name != NULL); cmdp++) { + if (cmdp->help) fprintf (st, cmdp->help); } +for (cmdp = sim_vm_cmd; cmdp && (cmdp->name != NULL); cmdp++) { + if (cmdp->help) fprintf (st, cmdp->help); } return; } -t_stat help_cmd (int flag, char *cptr) +t_stat help_cmd (int32 flag, char *cptr) { -fprint_help (stdout); -if (sim_log) fprint_help (sim_log); +char gbuf[CBUFSIZE]; +CTAB *cmdp; + +if (*cptr) { + cptr = get_glyph (cptr, gbuf, 0); + if (*cptr) return SCPE_2MARG; + if (cmdp = find_cmd (gbuf)) { + printf (cmdp->help); + if (sim_log) fprintf (sim_log, cmdp->help); } + else return SCPE_ARG; } +else { fprint_help (stdout); + if (sim_log) fprint_help (sim_log); } return SCPE_OK; } /* Do command */ +/* Substitute_args - replace %n tokens in 'instr' with the do command's arguments + + Calling sequence + instr = input string + tmpbuf = temp buffer + maxstr = min (len (instr), len (tmpbuf)) + nargs = number of arguments + do_arg[10] = arguments +*/ + +void sub_args (char *instr, char *tmpbuf, int32 maxstr, int32 nargs, char *do_arg[]) +{ +char *ip, *op, *ap, *oend = tmpbuf + maxstr - 2; + +for (ip = instr, op = tmpbuf; *ip && (op < oend); ) { + if ((*ip == '\\') && (ip[1] == '%')) { /* \% = literal % */ + ip++; /* skip \ */ + if (*ip) *op++ = *ip++; } /* copy next */ + else if ((*ip == '%') && /* %n = sub */ + ((ip[1] >= '1') && (ip[1] <= ('0'+ nargs - 1)))) { + ap = do_arg[ip[1] - '0']; + ip = ip + 2; + while (*ap && (op < oend)) *op++ = *ap++; }/* copy the argument */ + else *op++ = *ip++; } /* literal character */ +*op = 0; /* term buffer */ +strcpy (instr, tmpbuf); +return; +} + t_stat do_cmd (int flag, char *fcptr) { -char *cptr, cbuf[CBUFSIZE], gbuf[CBUFSIZE]; +char *cptr, cbuf[CBUFSIZE], gbuf[CBUFSIZE], *c, quote, *do_arg[10]; FILE *fpin; -int32 i, echo; +CTAB *cmdp; +int32 echo, nargs; t_stat stat = SCPE_OK; -GET_SWITCHES (fcptr, gbuf); /* get switches */ -echo = sim_switches & SWMASK ('V'); /* set echo flag */ -if ((fpin = fopen (fcptr, "r")) != NULL) { /* cmd file open? */ - do { - cptr = read_line (cbuf, CBUFSIZE, fpin); /* get cmd line */ +if (flag == 0) { GET_SWITCHES (fcptr, gbuf); } /* get switches */ +echo = sim_switches & SWMASK ('V'); /* -v means echo */ + +c = fcptr; +for (nargs = 0; nargs < 10; ) { /* extract arguments */ + while (*c && (*c <= ' ')) c++; /* skip blanks */ + if (! *c) break; /* all done */ + do_arg[nargs++] = c; /* save start */ + while (*c && (*c > ' ')) { + if (*c == '\'' || *c == '"') { /* quoted string */ + for (quote = *c++; *c; ) + if (*c++ == quote) break; } + else c++; } + if (*c) *c++ = 0; /* term arg at spc */ + } /* end for */ +if (nargs <= 0) return SCPE_2FARG; /* need at least 1 */ +if ((fpin = FOPEN (do_arg[0], "r")) == NULL) /* cmd file failed to open? */ + return SCPE_OPENERR; + +do { cptr = read_line (cbuf, CBUFSIZE, fpin); /* get cmd line */ + sub_args (cbuf, gbuf, CBUFSIZE, nargs, do_arg); if (cptr == NULL) break; /* exit on eof */ if (*cptr == 0) continue; /* ignore blank */ - if (echo) printf ("do> %s\n", cptr); /* echo cmd? */ + if (echo) printf("do> %s\n", cptr); /* echo if -v */ if (sim_log) fprintf (sim_log, "do> %s\n", cptr); cptr = get_glyph (cptr, gbuf, 0); /* get command glyph */ if (strcmp (gbuf, "do") == 0) { /* don't recurse */ fclose (fpin); return SCPE_NEST; } - for (i = 0; cmd_table[i].name != NULL; i++) { /* find cmd */ - if (MATCH_CMD (gbuf, cmd_table[i].name) == 0) { - stat = cmd_table[i].action (cmd_table[i].arg, cptr); - break; } } + if (cmdp = find_cmd (gbuf)) /* lookup command */ + stat = cmdp->action (cmdp->arg, cptr); /* if found, exec */ + else stat = SCPE_UNK; if (stat >= SCPE_BASE) /* error? */ - printf ("%s\n", scp_error_messages[stat - SCPE_BASE]); - } - while (stat != SCPE_EXIT); - fclose (fpin); /* close file */ - return ((stat == SCPE_EXIT)? SCPE_EXIT: SCPE_OK); - } /* end if cmd file */ -return SCPE_OPENERR; + printf ("%s\n", scp_error_messages[stat - SCPE_BASE]); + if (sim_vm_post != NULL) (*sim_vm_post) (TRUE); +} while (stat != SCPE_EXIT); + +fclose (fpin); /* close file */ +return (stat == SCPE_EXIT)? SCPE_EXIT: SCPE_OK; } /* Set command */ -t_stat set_cmd (int flag, char *cptr) +t_stat set_cmd (int32 flag, char *cptr) { int32 lvl; t_stat r; @@ -548,15 +709,18 @@ UNIT *uptr; MTAB *mptr; CTAB *ctbr, *glbr; static CTAB set_glob_tab[] = { - { "VT", &set_vt, 1 }, - { "NOVT", &set_vt, 0 }, + { "TELNET", &set_telnet, 0 }, + { "NOTELNET", &set_notelnet, 0 }, { "LOG", &set_logon, 0 }, { "NOLOG", &set_logoff, 0 }, + { "BREAK", &brk_cmd, SSH_ST }, { NULL, NULL, 0 } }; static CTAB set_dev_tab[] = { { "OCTAL", &set_radix, 8 }, { "DECIMAL", &set_radix, 10 }, { "HEX", &set_radix, 16 }, + { "ENABLED", &set_devenbdis, 1 }, + { "DISABLED", &set_devenbdis, 0 }, { NULL, NULL, 0 } }; static CTAB set_unit_tab[] = { { "ONLINE", &set_onoff, 1 }, @@ -566,58 +730,60 @@ static CTAB set_unit_tab[] = { GET_SWITCHES (cptr, gbuf); /* get switches */ if (*cptr == 0) return SCPE_2FARG; /* must be more */ cptr = get_glyph (cptr, gbuf, 0); /* get glob/dev/unit */ -if (glbr = find_ctab (set_glob_tab, gbuf)) /* global? */ - return glbr -> action (glbr -> arg, cptr); /* do the rest */ -if (*cptr == 0) return SCPE_2FARG; /* must be more */ if (dptr = find_dev (gbuf)) { /* device match? */ - uptr = dptr -> units; /* first unit */ + uptr = dptr->units; /* first unit */ ctbr = set_dev_tab; /* global table */ lvl = MTAB_VDV; } /* device match */ else if (dptr = find_unit (gbuf, &uptr)) { /* unit match? */ if (uptr == NULL) return SCPE_NXUN; /* invalid unit */ ctbr = set_unit_tab; /* global table */ lvl = MTAB_VUN; } /* unit match */ +else if (glbr = find_ctab (set_glob_tab, gbuf)) /* global? */ + return glbr->action (glbr->arg, cptr); /* do the rest */ else return SCPE_NXDEV; /* no match */ -if (dptr -> modifiers == NULL) return SCPE_NOPARAM; /* any modifiers? */ +if (*cptr == 0) return SCPE_2FARG; /* must be more */ while (*cptr != 0) { /* do all mods */ cptr = get_glyph (cptr, gbuf, ','); /* get modifier */ if (cvptr = strchr (gbuf, '=')) *cvptr++ = 0; /* = value? */ - if (glbr = find_ctab (ctbr, gbuf)) /* global match? */ - return glbr -> action (dptr, uptr, glbr -> arg); - for (mptr = dptr -> modifiers; mptr -> mask != 0; mptr++) { - if ((mptr -> mstring) && /* match string */ - (MATCH_CMD (gbuf, mptr -> mstring) == 0)) { /* matches option? */ - if (mptr -> mask & MTAB_XTD) { /* extended? */ - if ((lvl & mptr -> mask) == 0) return SCPE_ARG; - if ((lvl & MTAB_VUN) && (uptr -> flags & UNIT_DIS)) + for (mptr = dptr->modifiers; mptr && (mptr->mask != 0); mptr++) { + if ((mptr->mstring) && /* match string */ + (MATCH_CMD (gbuf, mptr->mstring) == 0)) { /* matches option? */ + if (mptr->mask & MTAB_XTD) { /* extended? */ + if ((lvl & mptr->mask) == 0) return SCPE_ARG; + if ((lvl & MTAB_VUN) && (uptr->flags & UNIT_DIS)) return SCPE_UDIS; /* unit disabled? */ - if (mptr -> valid) { /* validation rtn? */ - r = mptr -> valid (uptr, mptr -> match, cvptr, mptr -> desc); + if (mptr->valid) { /* validation rtn? */ + r = mptr->valid (uptr, mptr->match, cvptr, mptr->desc); if (r != SCPE_OK) return r; } - else if (!mptr -> desc) break; /* value desc? */ - else if (mptr -> mask & MTAB_VAL) { /* take a value? */ + else if (!mptr->desc) break; /* value desc? */ + else if (mptr->mask & MTAB_VAL) { /* take a value? */ if (!cvptr) return SCPE_MISVAL; /* none? error */ - r = dep_reg (0, cvptr, (REG *) mptr -> desc, 0); + r = dep_reg (0, cvptr, (REG *) mptr->desc, 0); if (r != SCPE_OK) return r; } else if (cvptr) return SCPE_ARG; /* = value? */ - else *((int32 *) mptr -> desc) = mptr -> match; + else *((int32 *) mptr->desc) = mptr->match; } /* end if xtd */ else { /* old style */ if (cvptr) return SCPE_ARG; /* = value? */ - if (uptr -> flags & UNIT_DIS) /* disabled? */ + if (uptr->flags & UNIT_DIS) /* disabled? */ return SCPE_UDIS; - if ((mptr -> valid) && ((r = mptr -> valid - (uptr, mptr -> match, cvptr, mptr -> desc)) + if ((mptr->valid) && ((r = mptr->valid + (uptr, mptr->match, cvptr, mptr->desc)) != SCPE_OK)) return r; /* invalid? */ - uptr -> flags = (uptr -> flags & ~(mptr -> mask)) | - (mptr -> match & mptr -> mask); /* set new value */ + uptr->flags = (uptr->flags & ~(mptr->mask)) | + (mptr->match & mptr->mask); /* set new value */ } /* end else xtd */ break; /* terminate for */ } /* end if match */ } /* end for */ - if (mptr -> mask == 0) return SCPE_NXPAR; /* any match? */ + if (!mptr || (mptr->mask == 0)) { /* no match? */ + if (glbr = find_ctab (ctbr, gbuf)) { /* global match? */ + r = glbr->action (dptr, uptr, glbr->arg); /* do global */ + if (r != SCPE_OK) return r; } + else if (!dptr->modifiers) return SCPE_NOPARAM; /* no modifiers? */ + else return SCPE_NXPAR; } /* end if no mat */ } /* end while */ return SCPE_OK; /* done all */ } @@ -626,75 +792,87 @@ return SCPE_OK; /* done all */ CTAB *find_ctab (CTAB *tab, char *gbuf) { -for (; tab -> name != NULL; tab++) { - if (MATCH_CMD (gbuf, tab -> name) == 0) return tab; } +for (; tab->name != NULL; tab++) { + if (MATCH_CMD (gbuf, tab->name) == 0) return tab; } return NULL; } -/* VT on/off routine */ - -t_stat set_vt (int32 val, char *cptr) -{ -if (sim_vt < 0) return SCPE_NOFNC; /* not possible */ -if (*cptr) return SCPE_2MARG; /* no more args */ -sim_vt = val; -return SCPE_OK; -} - /* Log on routine */ -t_stat set_logon (int flag, char *cptr) +t_stat set_logon (int32 flag, char *cptr) { char gbuf[CBUFSIZE]; -if (*cptr == 0) SCPE_2FARG; /* need arg */ +if (*cptr == 0) return SCPE_2FARG; /* need arg */ cptr = get_glyph_nc (cptr, gbuf, 0); /* get file name */ if (*cptr != 0) return SCPE_2MARG; /* now eol? */ set_logoff (0, NULL); /* close cur log */ -sim_log = fopen (gbuf, "a"); /* open log */ +sim_log = FOPEN (gbuf, "a"); /* open log */ if (sim_log == NULL) return SCPE_OPENERR; /* error? */ -printf ("Logging to file \"%s\"\n", gbuf); /* start of log */ -fprintf (sim_log, "Logging to file \"%s\"\n", gbuf); +if (!sim_quiet) printf ("Logging to file \"%s\"\n", gbuf); +fprintf (sim_log, "Logging to file \"%s\"\n", gbuf); /* start of log */ return SCPE_OK; } /* Log off routine */ -t_stat set_logoff (int flag, char *cptr) +t_stat set_logoff (int32 flag, char *cptr) { if (cptr && (*cptr != 0)) return SCPE_2MARG; /* now eol? */ if (sim_log == NULL) return SCPE_OK; /* no log? */ -printf ("Log file closed\n"); +if (!sim_quiet) printf ("Log file closed\n"); fprintf (sim_log, "Log file closed\n"); /* close log */ fclose (sim_log); sim_log = NULL; return SCPE_OK; } -/* Set radix routine */ +/* Set controller data radix routine */ t_stat set_radix (DEVICE *dptr, UNIT *uptr, int32 flag) { -dptr -> dradix = flag & 017; +dptr->dradix = flag & 037; return SCPE_OK; } -/* Set online/offline routine */ +/* Set controller enabled/disabled routine */ + +t_stat set_devenbdis (DEVICE *dptr, UNIT *uptr, int32 flag) +{ +UNIT *up; +int32 i; + +if ((dptr->flags & DEV_DISABLE) == 0) return SCPE_NOFNC;/* allowed? */ +if (flag) { /* enable? */ + if ((dptr->flags & DEV_DIS) == 0) return SCPE_OK; /* already enb? ok */ + dptr->flags = dptr->flags & ~DEV_DIS; } /* no, enable */ +else { /* disable */ + if (dptr->flags & DEV_DIS) return SCPE_OK; /* already dsb? ok */ + for (i = 0; i < dptr->numunits; i++) { /* check units */ + up = (dptr->units) + i; /* att or active? */ + if ((up->flags & UNIT_ATT) || sim_is_active (up)) + return SCPE_NOFNC; } /* can't do it */ + dptr->flags = dptr->flags | DEV_DIS; } /* disable */ +if (dptr->reset) return dptr->reset (dptr); /* reset device */ +else return SCPE_OK; +} + +/* Set unit online/offline routine */ t_stat set_onoff (DEVICE *dptr, UNIT *uptr, int32 flag) { -if (!(uptr -> flags & UNIT_DISABLE)) return SCPE_NOFNC; /* allowed? */ -if (flag) uptr -> flags = uptr -> flags & ~UNIT_DIS; /* onl? enable */ +if (!(uptr->flags & UNIT_DISABLE)) return SCPE_NOFNC; /* allowed? */ +if (flag) uptr->flags = uptr->flags & ~UNIT_DIS; /* onl? enable */ else { /* offline? */ - if ((uptr -> flags & UNIT_ATT) || sim_is_active (uptr)) + if ((uptr->flags & UNIT_ATT) || sim_is_active (uptr)) return SCPE_NOFNC; /* more tests */ - uptr -> flags = uptr -> flags | UNIT_DIS; } /* disable */ + uptr->flags = uptr->flags | UNIT_DIS; } /* disable */ return SCPE_OK; } /* Show command */ -t_stat show_cmd (int flag, char *cptr) +t_stat show_cmd (int32 flag, char *cptr) { int32 i, lvl; t_stat r; @@ -711,7 +889,8 @@ static CTAB show_table[] = { { "MODIFIERS", &show_mod_names, 0 }, { "VERSION", &show_version, 0 }, { "LOG", &show_log, 0 }, - { "VT", &show_vt, 0 }, + { "TELNET", &show_telnet, 0 }, + { "BREAK", &show_break, 0 }, { NULL, NULL, 0 } }; GET_SWITCHES (cptr, gbuf); /* test for switches */ @@ -719,21 +898,16 @@ if (*cptr == 0) return SCPE_2FARG; /* must be more */ cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ for (i = 0; show_table[i].name != NULL; i++) { /* find command */ if (MATCH_CMD (gbuf, show_table[i].name) == 0) { - if (*cptr != 0) return SCPE_2MARG; /* now eol? */ - r = show_table[i].action (stdout, show_table[i].arg); - if (sim_log) show_table[i].action (sim_log, show_table[i].arg); + r = show_table[i].action (stdout, show_table[i].arg, cptr); + if (sim_log) show_table[i].action (sim_log, show_table[i].arg, cptr); return r; } } -if (MATCH_CMD (gbuf, "BREAK") == 0) { /* SHOW BREAK? */ - r = ssh_break (stdout, cptr, 1); - if (sim_log) ssh_break (sim_log, cptr, SSH_SH); - return r; } if (dptr = find_dev (gbuf)) { /* device match? */ - uptr = dptr -> units; /* first unit */ + uptr = dptr->units; /* first unit */ lvl = MTAB_VDV; } /* device match */ else if (dptr = find_unit (gbuf, &uptr)) { /* unit match? */ if (uptr == NULL) return SCPE_NXUN; /* invalid unit */ - if (uptr -> flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ + if (uptr->flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ lvl = MTAB_VUN; } /* unit match */ else return SCPE_NXDEV; /* no match */ @@ -746,103 +920,108 @@ if (*cptr == 0) { /* now eol? */ r = show_unit (stdout, dptr, uptr, -1); if (sim_log) show_unit (sim_log, dptr, uptr, -1); return r; } } -if (dptr -> modifiers == NULL) return SCPE_NOPARAM; /* any modifiers? */ +if (dptr->modifiers == NULL) return SCPE_NOPARAM; /* any modifiers? */ while (*cptr != 0) { /* do all mods */ cptr = get_glyph (cptr, gbuf, ','); /* get modifier */ - for (mptr = dptr -> modifiers; mptr -> mask != 0; mptr++) { - if (((mptr -> mask & MTAB_XTD)? /* right level? */ - (mptr -> mask & lvl): (MTAB_VUN & lvl)) && - ((mptr -> disp && mptr -> pstring && /* named disp? */ - (MATCH_CMD (gbuf, mptr -> pstring) == 0)) || - ((mptr -> mask & MTAB_VAL) && /* named value? */ - mptr -> mstring && - (MATCH_CMD (gbuf, mptr -> mstring) == 0)))) { + for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) { + if (((mptr->mask & MTAB_XTD)? /* right level? */ + (mptr->mask & lvl): (MTAB_VUN & lvl)) && + ((mptr->disp && mptr->pstring && /* named disp? */ + (MATCH_CMD (gbuf, mptr->pstring) == 0)) || + ((mptr->mask & MTAB_VAL) && /* named value? */ + mptr->mstring && + (MATCH_CMD (gbuf, mptr->mstring) == 0)))) { show_one_mod (stdout, dptr, uptr, mptr, 1); if (sim_log) show_one_mod (sim_log, dptr, uptr, mptr, 1); break; } /* end if */ } /* end for */ - if (mptr -> mask == 0) return SCPE_ARG; /* any match? */ + if (mptr->mask == 0) return SCPE_ARG; /* any match? */ } /* end while */ return SCPE_OK; } -/* Show processors */ +/* Show device and unit */ t_stat show_device (FILE *st, DEVICE *dptr, int32 flag) { int32 j, ucnt; UNIT *uptr; -fprintf (st, "%s", dptr -> name); /* print dev name */ +fprintf (st, "%s", dptr->name); /* print dev name */ if (qdisable (dptr)) { /* disabled? */ fprintf (st, ", disabled\n"); return SCPE_OK; } -for (j = ucnt = 0; j < dptr -> numunits; j++) { /* count units */ - uptr = (dptr -> units) + j; - if (!(uptr -> flags & UNIT_DIS)) ucnt++; } -show_all_mods (st, dptr, dptr -> units, MTAB_VDV); /* show dev mods */ -if (dptr -> numunits == 0) fprintf (st, "\n"); +for (j = ucnt = 0; j < dptr->numunits; j++) { /* count units */ + uptr = (dptr->units) + j; + if (!(uptr->flags & UNIT_DIS)) ucnt++; } +show_all_mods (st, dptr, dptr->units, MTAB_VDV); /* show dev mods */ +if (dptr->numunits == 0) fprintf (st, "\n"); else { if (ucnt == 0) fprintf (st, ", all units disabled\n"); else if (ucnt > 1) fprintf (st, ", %d units\n", ucnt); else if (flag) fprintf (st, "\n"); } if (flag) return SCPE_OK; /* dev only? */ -for (j = 0; j < dptr -> numunits; j++) { /* loop thru units */ - uptr = (dptr -> units) + j; - if ((uptr -> flags & UNIT_DIS) == 0) +for (j = 0; j < dptr->numunits; j++) { /* loop thru units */ + uptr = (dptr->units) + j; + if ((uptr->flags & UNIT_DIS) == 0) show_unit (st, dptr, uptr, ucnt); } return SCPE_OK; } t_stat show_unit (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag) { -t_addr kval = (uptr -> flags & UNIT_BINK)? 1024: 1000; -int32 u = uptr - dptr -> units; +t_addr kval = (uptr->flags & UNIT_BINK)? 1024: 1000; +int32 u = uptr - dptr->units; -if (flag > 1) fprintf (st, " %s%d", dptr -> name, u); -else if (flag < 0) fprintf (st, "%s%d", dptr -> name, u); -if (uptr -> flags & UNIT_FIX) { - if (uptr -> capac < kval) - fprintf (st, ", %d%s", uptr -> capac, - ((dptr -> dwidth / dptr -> aincr) > 8)? "W": "B"); - else fprintf (st, ", %dK%s", uptr -> capac / kval, - ((dptr -> dwidth / dptr -> aincr) > 8)? "W": "B"); } -if (uptr -> flags & UNIT_ATT) { - fprintf (st, ", attached to %s", uptr -> filename); - if (uptr -> flags & UNIT_RO) fprintf (st, ", read only"); } -else if (uptr -> flags & UNIT_ATTABLE) +if (flag > 1) fprintf (st, " %s%d", dptr->name, u); +else if (flag < 0) fprintf (st, "%s%d", dptr->name, u); +if (uptr->flags & UNIT_FIX) { + if (uptr->capac < kval) + fprintf (st, ", %d%s", uptr->capac, + ((dptr->dwidth / dptr->aincr) > 8)? "W": "B"); + else fprintf (st, ", %dK%s", uptr->capac / kval, + ((dptr->dwidth / dptr->aincr) > 8)? "W": "B"); } +if (uptr->flags & UNIT_ATT) { + fprintf (st, ", attached to %s", uptr->filename); + if (uptr->flags & UNIT_RO) fprintf (st, ", read only"); } +else if (uptr->flags & UNIT_ATTABLE) fprintf (st, ", not attached"); show_all_mods (st, dptr, uptr, MTAB_VUN); /* show unit mods */ fprintf (st, "\n"); return SCPE_OK; } -t_stat show_version (FILE *st, int32 flag) +/* Show processors */ + +t_stat show_version (FILE *st, int32 flag, char *cptr) { int32 vmaj = SIM_MAJOR, vmin = SIM_MINOR, vpat = SIM_PATCH; +if (cptr && (*cptr != 0)) return SCPE_2MARG; fprintf (st, "%s simulator V%d.%d-%d\n", sim_name, vmaj, vmin, vpat); return SCPE_OK; } -t_stat show_config (FILE *st, int32 flag) +t_stat show_config (FILE *st, int32 flag, char *cptr) { int32 i; DEVICE *dptr; +if (cptr && (*cptr != 0)) return SCPE_2MARG; fprintf (st, "%s simulator configuration\n\n", sim_name); for (i = 0; (dptr = sim_devices[i]) != NULL; i++) show_device (st, dptr, flag); return SCPE_OK; } -t_stat show_queue (FILE *st, int32 flag) +t_stat show_queue (FILE *st, int32 flag, char *cptr) { DEVICE *dptr; UNIT *uptr; int32 accum; +if (cptr && (*cptr != 0)) return SCPE_2MARG; if (sim_clock_queue == NULL) { fprintf (st, "%s event queue empty, time = %-16.0f\n", sim_name, sim_time); @@ -850,53 +1029,66 @@ if (sim_clock_queue == NULL) { fprintf (st, "%s event queue status, time = %-16.0f\n", sim_name, sim_time); accum = 0; -for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr -> next) { +for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr->next) { if (uptr == &step_unit) fprintf (st, " Step timer"); else if ((dptr = find_dev_from_unit (uptr)) != NULL) { - fprintf (st, " %s", dptr -> name); - if (dptr -> numunits > 1) fprintf (st, " unit %d", - uptr - dptr -> units); } + fprintf (st, " %s", dptr->name); + if (dptr->numunits > 1) fprintf (st, " unit %d", + uptr - dptr->units); } else fprintf (st, " Unknown"); - fprintf (st, " at %d\n", accum + uptr -> time); - accum = accum + uptr -> time; } + fprintf (st, " at %d\n", accum + uptr->time); + accum = accum + uptr->time; } return SCPE_OK; } -t_stat show_time (FILE *st, int32 flag) +t_stat show_time (FILE *st, int32 flag, char *cptr) { +if (cptr && (*cptr != 0)) return SCPE_2MARG; fprintf (st, "Time: %-16.0f\n", sim_time); return SCPE_OK; } -t_stat show_log (FILE *st, int32 flag) +t_stat show_log (FILE *st, int32 flag, char *cptr) { +if (cptr && (*cptr != 0)) return SCPE_2MARG; if (sim_log) fprintf (st, "Logging enabled\n"); else fprintf (st, "Logging disabled\n"); return SCPE_OK; } -t_stat show_vt (FILE *st, int32 flag) +t_stat show_break (FILE *st, int32 flag, char *cptr) { -if (sim_vt < 0) fprintf (st, "VT emulation not available\n"); -else if (sim_vt) fprintf (st, "VT emulation enabled\n"); -else fprintf (st, "VT emulation disabled\n"); -return SCPE_OK; -} +t_stat r; -t_stat show_mod_names (FILE *st, int32 flag) +if (cptr && (*cptr != 0)) { /* more? */ + r = ssh_break (stdout, cptr, 1); + if (sim_log) ssh_break (sim_log, cptr, SSH_SH); } +else { r = sim_brk_showall (stdout, sim_switches); + if (sim_log) sim_brk_showall (sim_log,sim_switches); } +return r; +} + +/* Show modifiers */ + +t_stat show_mod_names (FILE *st, int32 flag, char *cptr) { -int i, any; +int32 i, any, enb; DEVICE *dptr; MTAB *mptr; +if (cptr && (*cptr != 0)) return SCPE_2MARG; /* now eol? */ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { - if (dptr -> modifiers) { - any = 0; - for (mptr = dptr -> modifiers; mptr -> mask != 0; mptr++) { - if (mptr -> mstring) { - if (any++) fprintf (st, ", %s", mptr -> mstring); - else fprintf (st, "%s\t%s", dptr -> name, mptr -> mstring); } } - if (any) fprintf (st, "\n"); } } + any = enb = 0; + if (dptr->modifiers) { + for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) { + if (mptr->mstring) { + if (strcmp (mptr->mstring, "ENABLED") == 0) enb = 1; + if (any++) fprintf (st, ", %s", mptr->mstring); + else fprintf (st, "%s\t%s", dptr->name, mptr->mstring); } } } + if (!enb && (dptr->flags & DEV_DISABLE)) { + if (any++) fprintf (st, ", ENABLED, DISABLED"); + else fprintf (st, "%s\tENABLED, DISABLED", dptr->name); } + if (any) fprintf (st, "\n"); } return SCPE_OK; } @@ -904,11 +1096,11 @@ t_stat show_all_mods (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag) { MTAB *mptr; -if (dptr -> modifiers == NULL) return SCPE_OK; -for (mptr = dptr -> modifiers; mptr -> mask != 0; mptr++) { - if (mptr -> pstring && ((mptr -> mask & MTAB_XTD)? - ((mptr -> mask & flag) && !(mptr -> mask & MTAB_NMO)): - ((MTAB_VUN & flag) && ((uptr -> flags & mptr -> mask) == mptr -> match)))) { +if (dptr->modifiers == NULL) return SCPE_OK; +for (mptr = dptr->modifiers; mptr->mask != 0; mptr++) { + if (mptr->pstring && ((mptr->mask & MTAB_XTD)? + ((mptr->mask & flag) && !(mptr->mask & MTAB_NMO)): + ((MTAB_VUN & flag) && ((uptr->flags & mptr->mask) == mptr->match)))) { fputs (", ", st); show_one_mod (st, dptr, uptr, mptr, 0); } } return SCPE_OK; @@ -918,27 +1110,26 @@ t_stat show_one_mod (FILE *st, DEVICE *dptr, UNIT *uptr, MTAB *mptr, int32 flag) { t_value val; -if (mptr -> disp) mptr -> disp (st, uptr, mptr -> match, mptr -> desc); -else if ((mptr -> mask & MTAB_XTD) && (mptr -> mask & MTAB_VAL)) { - REG *rptr = (REG *) mptr -> desc; - fprintf (st, "%s=", mptr -> pstring); +if (mptr->disp) mptr->disp (st, uptr, mptr->match, mptr->desc); +else if ((mptr->mask & MTAB_XTD) && (mptr->mask & MTAB_VAL)) { + REG *rptr = (REG *) mptr->desc; + fprintf (st, "%s=", mptr->pstring); val = get_rval (rptr, 0); - fprint_val (st, val, rptr -> radix, rptr -> width, - rptr -> flags & REG_FMT); } -else fputs (mptr -> pstring, st); -if (flag && !((mptr -> mask & MTAB_XTD) && - (mptr -> mask & MTAB_NMO))) fputc ('\n', st); + fprint_val (st, val, rptr->radix, rptr->width, + rptr->flags & REG_FMT); } +else fputs (mptr->pstring, st); +if (flag && !((mptr->mask & MTAB_XTD) && + (mptr->mask & MTAB_NMO))) fputc ('\n', st); return SCPE_OK; } /* Breakpoint commands */ -t_stat brk_cmd (int flg, char *cptr) +t_stat brk_cmd (int32 flg, char *cptr) { char gbuf[CBUFSIZE]; GET_SWITCHES (cptr, gbuf); /* test for switches */ -if (*cptr == 0) return SCPE_2FARG; /* must be more */ return ssh_break (NULL, cptr, flg); /* call common code */ } @@ -946,9 +1137,9 @@ t_stat ssh_break (FILE *st, char *cptr, int32 flg) { char gbuf[CBUFSIZE], *tptr, *t1ptr; DEVICE *dptr = sim_devices[0]; -UNIT *uptr = dptr -> units; +UNIT *uptr = dptr->units; t_stat r; -t_addr lo, hi, max = uptr -> capac - dptr -> aincr; +t_addr lo, hi, max = uptr->capac - dptr->aincr; int32 cnt; if (*cptr == 0) return SCPE_2FARG; @@ -956,7 +1147,7 @@ if (sim_brk_types == 0) return SCPE_NOFNC; if ((dptr == NULL) || (uptr == NULL)) return SCPE_IERR; while (*cptr) { cptr = get_glyph (cptr, gbuf, ','); - tptr = get_range (gbuf, &lo, &hi, dptr -> aradix, max, 0); + tptr = get_range (gbuf, &lo, &hi, dptr->aradix, max, 0); if (tptr == NULL) return SCPE_ARG; if (*tptr == '[') { errno = 0; @@ -971,11 +1162,12 @@ while (*cptr) { else if (flg == SSH_SH) sim_brk_showall (st, sim_switches); else return SCPE_ARG; } else { - for ( ; lo <= hi; lo = lo + dptr -> aincr) { + for ( ; lo <= hi; lo = lo + dptr->aincr) { if (flg == SSH_ST) r = sim_brk_set (lo, sim_switches, cnt); else if (flg == SSH_CL) r = sim_brk_clr (lo, sim_switches); else if (flg == SSH_SH) r = sim_brk_show (st, lo, sim_switches); else return SCPE_ARG; + if (r != SCPE_OK) return r; } } } @@ -989,7 +1181,7 @@ return SCPE_OK; re[set] device reset specific device */ -t_stat reset_cmd (int flag, char *cptr) +t_stat reset_cmd (int32 flag, char *cptr) { char gbuf[CBUFSIZE]; DEVICE *dptr; @@ -1001,7 +1193,7 @@ if (*cptr != 0) return SCPE_2MARG; /* now eol? */ if (strcmp (gbuf, "ALL") == 0) return (reset_all (0)); dptr = find_dev (gbuf); /* locate device */ if (dptr == NULL) return SCPE_NXDEV; /* found it? */ -if (dptr -> reset != NULL) return dptr -> reset (dptr); +if (dptr->reset != NULL) return dptr->reset (dptr); else return SCPE_OK; } @@ -1013,7 +1205,7 @@ else return SCPE_OK; status = error status */ -t_stat reset_all (int start) +t_stat reset_all (int32 start) { DEVICE *dptr; int32 i; @@ -1023,8 +1215,8 @@ if (start < 0) return SCPE_IERR; for (i = 0; i < start; i++) { if (sim_devices[i] == NULL) return SCPE_IERR; } for (i = start; (dptr = sim_devices[i]) != NULL; i++) { - if (dptr -> reset != NULL) { - reason = dptr -> reset (dptr); + if (dptr->reset != NULL) { + reason = dptr->reset (dptr); if (reason != SCPE_OK) return reason; } } return SCPE_OK; } @@ -1035,7 +1227,7 @@ return SCPE_OK; du[mp] filename {arg} dump to specified file */ -t_stat load_cmd (int flag, char *cptr) +t_stat load_cmd (int32 flag, char *cptr) { char gbuf[CBUFSIZE]; FILE *loadfile; @@ -1044,7 +1236,7 @@ t_stat reason; GET_SWITCHES (cptr, gbuf); /* test for switches */ if (*cptr == 0) return SCPE_2FARG; /* must be more */ cptr = get_glyph_nc (cptr, gbuf, 0); /* get file name */ -loadfile = fopen (gbuf, flag? "wb": "rb"); /* open for wr/rd */ +loadfile = FOPEN (gbuf, flag? "wb": "rb"); /* open for wr/rd */ if (loadfile == NULL) return SCPE_OPENERR; reason = sim_load (loadfile, cptr, gbuf, flag); /* load or dump */ fclose (loadfile); @@ -1056,7 +1248,7 @@ return reason; at[tach] unit file attach specified unit to file */ -t_stat attach_cmd (int flag, char *cptr) +t_stat attach_cmd (int32 flag, char *cptr) { char gbuf[CBUFSIZE]; DEVICE *dptr; @@ -1065,11 +1257,11 @@ UNIT *uptr; GET_SWITCHES (cptr, gbuf); /* test for switches */ if (*cptr == 0) return SCPE_2FARG; /* must be more */ cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ -if (*cptr == 0) return SCPE_2MARG; /* now eol? */ +if (*cptr == 0) return SCPE_2FARG; /* now eol? */ dptr = find_unit (gbuf, &uptr); /* locate unit */ if (dptr == NULL) return SCPE_NXDEV; /* found dev? */ if (uptr == NULL) return SCPE_NXUN; /* valid unit? */ -if (dptr -> attach != NULL) return dptr -> attach (uptr, cptr); +if (dptr->attach != NULL) return dptr->attach (uptr, cptr); return attach_unit (uptr, cptr); } @@ -1078,60 +1270,62 @@ t_stat attach_unit (UNIT *uptr, char *cptr) DEVICE *dptr; t_stat reason; -if (uptr -> flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ -if (!(uptr -> flags & UNIT_ATTABLE)) return SCPE_NOATT; /* not attachable? */ +if (uptr->flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ +if (!(uptr->flags & UNIT_ATTABLE)) return SCPE_NOATT; /* not attachable? */ if ((dptr = find_dev_from_unit (uptr)) == NULL) return SCPE_NOATT; -if (uptr -> flags & UNIT_ATT) { /* already attached? */ +if (uptr->flags & UNIT_ATT) { /* already attached? */ reason = detach_unit (uptr); if (reason != SCPE_OK) return reason; } -uptr -> filename = calloc (CBUFSIZE, sizeof (char)); -if (uptr -> filename == NULL) return SCPE_MEM; -strncpy (uptr -> filename, cptr, CBUFSIZE); +uptr->filename = calloc (CBUFSIZE, sizeof (char)); +if (uptr->filename == NULL) return SCPE_MEM; +strncpy (uptr->filename, cptr, CBUFSIZE); if (sim_switches & SWMASK ('R')) { /* read only? */ - if ((uptr -> flags & UNIT_ROABLE) == 0) /* allowed? */ + if ((uptr->flags & UNIT_ROABLE) == 0) /* allowed? */ return attach_err (uptr, SCPE_NORO); /* no, error */ - uptr -> fileref = fopen (cptr, "rb"); /* open rd only */ - if (uptr -> fileref == NULL) /* open fail? */ + uptr->fileref = FOPEN (cptr, "rb"); /* open rd only */ + if (uptr->fileref == NULL) /* open fail? */ return attach_err (uptr, SCPE_OPENERR); /* yes, error */ - uptr -> flags = uptr -> flags | UNIT_RO; /* set rd only */ - printf ("%s: unit is read only\n", dptr -> name); } + uptr->flags = uptr->flags | UNIT_RO; /* set rd only */ + if (!sim_quiet) printf ("%s: unit is read only\n", dptr->name); } else { /* normal */ - uptr -> fileref = fopen (cptr, "rb+"); /* open r/w */ - if (uptr -> fileref == NULL) { /* open fail? */ + uptr->fileref = FOPEN (cptr, "rb+"); /* open r/w */ + if (uptr->fileref == NULL) { /* open fail? */ if (errno == EROFS) { /* read only? */ - if ((uptr -> flags & UNIT_ROABLE) == 0) /* allowed? */ + if ((uptr->flags & UNIT_ROABLE) == 0) /* allowed? */ return attach_err (uptr, SCPE_NORO); /* no error */ - uptr -> fileref = fopen (cptr, "rb"); /* open rd only */ - if (uptr -> fileref == NULL) /* open fail? */ + uptr->fileref = FOPEN (cptr, "rb"); /* open rd only */ + if (uptr->fileref == NULL) /* open fail? */ return attach_err (uptr, SCPE_OPENERR); /* yes, error */ - uptr -> flags = uptr -> flags | UNIT_RO; /* set rd only */ - printf ("%s: unit is read only\n", dptr -> name); } + uptr->flags = uptr->flags | UNIT_RO; /* set rd only */ + if (!sim_quiet) printf ("%s: unit is read only\n", dptr->name); } else { /* doesn't exist */ if (sim_switches & SWMASK ('E')) /* must exist? */ return attach_err (uptr, SCPE_OPENERR); /* yes, error */ - uptr -> fileref = fopen (cptr, "wb+"); /* open new file */ - if (uptr -> fileref == NULL) /* open fail? */ + uptr->fileref = FOPEN (cptr, "wb+"); /* open new file */ + if (uptr->fileref == NULL) /* open fail? */ return attach_err (uptr, SCPE_OPENERR); /* yes, error */ - printf ("%s: creating new file\n", dptr -> name); } + if (!sim_quiet) printf ("%s: creating new file\n", dptr->name); } } /* end if null */ } /* end else */ -if (uptr -> flags & UNIT_BUFABLE) { /* buffer? */ - if ((uptr -> filebuf = calloc (uptr -> capac, SZ_D (dptr))) != NULL) { - printf ("%s: buffering file in memory\n", dptr -> name); - uptr -> hwmark = fxread (uptr -> filebuf, SZ_D (dptr), - uptr -> capac, uptr -> fileref); - uptr -> flags = uptr -> flags | UNIT_BUF; } - else if (uptr -> flags & UNIT_MUSTBUF) /* must buf? */ - return attach_err (uptr, SCPE_MEM); } -uptr -> flags = uptr -> flags | UNIT_ATT; -uptr -> pos = 0; +if (uptr->flags & UNIT_BUFABLE) { /* buffer? */ + int32 cap = uptr->capac / dptr->aincr; /* effective size */ + if (uptr->flags & UNIT_MUSTBUF) /* dyn alloc? */ + uptr->filebuf = calloc (cap, SZ_D (dptr)); /* allocate */ + if (uptr->filebuf == NULL) /* no buffer? */ + return attach_err (uptr, SCPE_MEM); /* error */ + if (!sim_quiet) printf ("%s: buffering file in memory\n", dptr->name); + uptr->hwmark = fxread (uptr->filebuf, SZ_D (dptr), /* read file */ + cap, uptr->fileref); + uptr->flags = uptr->flags | UNIT_BUF; } /* set buffered */ +uptr->flags = uptr->flags | UNIT_ATT; +uptr->pos = 0; return SCPE_OK; } t_stat attach_err (UNIT *uptr, t_stat stat) { -free (uptr -> filename); -uptr -> filename = NULL; +free (uptr->filename); +uptr->filename = NULL; return stat; } @@ -1141,7 +1335,7 @@ return stat; det[ach] unit detach specified unit */ -t_stat detach_cmd (int flag, char *cptr) +t_stat detach_cmd (int32 flag, char *cptr) { char gbuf[CBUFSIZE]; DEVICE *dptr; @@ -1155,8 +1349,8 @@ if (strcmp (gbuf, "ALL") == 0) return (detach_all (0, FALSE)); dptr = find_unit (gbuf, &uptr); /* locate unit */ if (dptr == NULL) return SCPE_NXDEV; /* found dev? */ if (uptr == NULL) return SCPE_NXUN; /* valid unit? */ -if (!(uptr -> flags & UNIT_ATTABLE)) return SCPE_NOATT; -if (dptr -> detach != NULL) return dptr -> detach (uptr); +if (!(uptr->flags & UNIT_ATTABLE)) return SCPE_NOATT; +if (dptr->detach != NULL) return dptr->detach (uptr); return detach_unit (uptr); } @@ -1178,10 +1372,10 @@ UNIT *uptr; if ((start < 0) || (start > 1)) return SCPE_IERR; for (i = start; (dptr = sim_devices[i]) != NULL; i++) { - for (j = 0; j < dptr -> numunits; j++) { - uptr = (dptr -> units) + j; - if ((uptr -> flags & UNIT_ATTABLE) || shutdown) { - if (dptr -> detach != NULL) reason = dptr -> detach (uptr); + for (j = 0; j < dptr->numunits; j++) { + uptr = (dptr->units) + j; + if ((uptr->flags & UNIT_ATTABLE) || shutdown) { + if (dptr->detach != NULL) reason = dptr->detach (uptr); else reason = detach_unit (uptr); if (reason != SCPE_OK) return reason; } } } return SCPE_OK; @@ -1192,21 +1386,23 @@ t_stat detach_unit (UNIT *uptr) DEVICE *dptr; if (uptr == NULL) return SCPE_IERR; -if (!(uptr -> flags & UNIT_ATT)) return SCPE_OK; +if (!(uptr->flags & UNIT_ATT)) return SCPE_OK; if ((dptr = find_dev_from_unit (uptr)) == NULL) return SCPE_OK; -if (uptr -> flags & UNIT_BUF) { - if (uptr -> hwmark && ((uptr -> flags & UNIT_RO) == 0)) { - printf ("%s: writing buffer to file\n", dptr -> name); - rewind (uptr -> fileref); - fxwrite (uptr -> filebuf, SZ_D (dptr), uptr -> hwmark, uptr -> fileref); - if (ferror (uptr -> fileref)) perror ("I/O error"); } - free (uptr -> filebuf); - uptr -> flags = uptr -> flags & ~UNIT_BUF; - uptr -> filebuf = NULL; } -uptr -> flags = uptr -> flags & ~(UNIT_ATT | UNIT_RO); -free (uptr -> filename); -uptr -> filename = NULL; -return (fclose (uptr -> fileref) == EOF)? SCPE_IOERR: SCPE_OK; +if (uptr->flags & UNIT_BUF) { + int32 cap = (uptr->hwmark + dptr->aincr - 1) / dptr->aincr; + if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { + if (!sim_quiet) printf ("%s: writing buffer to file\n", dptr->name); + rewind (uptr->fileref); + fxwrite (uptr->filebuf, SZ_D (dptr), cap, uptr->fileref); + if (ferror (uptr->fileref)) perror ("I/O error"); } + if (uptr->flags & UNIT_MUSTBUF) { /* dyn alloc? */ + free (uptr->filebuf); /* free buf */ + uptr->filebuf = NULL; } + uptr->flags = uptr->flags & ~UNIT_BUF; } +uptr->flags = uptr->flags & ~(UNIT_ATT | UNIT_RO); +free (uptr->filename); +uptr->filename = NULL; +return (fclose (uptr->fileref) == EOF)? SCPE_IOERR: SCPE_OK; } /* Save command @@ -1214,7 +1410,7 @@ return (fclose (uptr -> fileref) == EOF)? SCPE_IOERR: SCPE_OK; sa[ve] filename save state to specified file */ -t_stat save_cmd (int flag, char *cptr) +t_stat save_cmd (int32 flag, char *cptr) { char gbuf[CBUFSIZE]; void *mbuf; @@ -1233,64 +1429,69 @@ REG *rptr; GET_SWITCHES (cptr, gbuf); /* test for switches */ if (*cptr == 0) return SCPE_2FARG; /* must be more */ -if ((sfile = fopen (cptr, "wb")) == NULL) return SCPE_OPENERR; -fputs (save_vercur, sfile); /* save format version */ +if ((sfile = FOPEN (cptr, "wb")) == NULL) return SCPE_OPENERR; +fputs (save_vercur, sfile); /* [V2.5] save format */ fputc ('\n', sfile); fputs (sim_name, sfile); /* sim name */ fputc ('\n', sfile); WRITE_I (sim_time); /* sim time */ -WRITE_I (sim_rtime); /* sim relative time */ +WRITE_I (sim_rtime); /* [V2.6] sim rel time */ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru devices */ - fputs (dptr -> name, sfile); /* device name */ + fputs (dptr->name, sfile); /* device name */ fputc ('\n', sfile); - for (j = 0; j < dptr -> numunits; j++) { - uptr = (dptr -> units) + j; - t = sim_is_active (uptr); - WRITE_I (j); /* unit number */ - WRITE_I (t); /* activation time */ - WRITE_I (uptr -> u3); /* unit specific */ - WRITE_I (uptr -> u4); - if (uptr -> flags & UNIT_ATT) fputs (uptr -> filename, sfile); - fputc ('\n', sfile); - if (((uptr -> flags & (UNIT_FIX + UNIT_ATTABLE)) == UNIT_FIX) && - (dptr -> examine != NULL) && - ((high = uptr -> capac) != 0)) { /* memory-like unit? */ - WRITE_I (high); /* write size */ - sz = SZ_D (dptr); - if ((mbuf = calloc (SRBSIZ, sz)) == NULL) { - fclose (sfile); - return SCPE_MEM; } - for (k = 0; k < high; ) { - zeroflg = TRUE; - for (l = 0; (l < SRBSIZ) && (k < high); - l++, k = k + (dptr -> aincr)) { - r = dptr -> examine (&val, k, uptr, 0); - if (r != SCPE_OK) return r; - if (val) zeroflg = FALSE; - SZ_STORE (sz, val, mbuf, l); - } /* end for l */ - if (zeroflg) { /* all zero's? */ - l = -l; /* invert block count */ - WRITE_I (l); } /* write only count */ - else { - WRITE_I (l); /* block count */ - fxwrite (mbuf, l, sz, sfile); } - } /* end for k */ - free (mbuf); /* dealloc buffer */ - } /* end if mem */ - else { high = 0; - WRITE_I (high); } /* no memory */ - } /* end unit loop */ - j = -1; /* write marker */ - WRITE_I (j); - for (rptr = dptr -> registers; /* loop thru regs */ - (rptr != NULL) && (rptr -> name != NULL); rptr++) { - fputs (rptr -> name, sfile); /* name */ - fputc ('\n', sfile); - for (j = 0; j < rptr -> depth; j++) { /* loop thru values */ - val = get_rval (rptr, j); /* get value */ - WRITE_I (val); } } /* store */ + WRITE_I (dptr->flags); /* [V2.10] flags */ + for (j = 0; j < dptr->numunits; j++) { + uptr = (dptr->units) + j; + t = sim_is_active (uptr); + WRITE_I (j); /* unit number */ + WRITE_I (t); /* activation time */ + WRITE_I (uptr->u3); /* unit specific */ + WRITE_I (uptr->u4); + WRITE_I (uptr->flags); /* [V2.10] flags */ + if (uptr->flags & UNIT_ATT) fputs (uptr->filename, sfile); + fputc ('\n', sfile); + if (((uptr->flags & (UNIT_FIX + UNIT_ATTABLE)) == UNIT_FIX) && + (dptr->examine != NULL) && + ((high = uptr->capac) != 0)) { /* memory-like unit? */ + WRITE_I (high); /* [V2.5] write size */ + sz = SZ_D (dptr); + if ((mbuf = calloc (SRBSIZ, sz)) == NULL) { + fclose (sfile); + return SCPE_MEM; } + for (k = 0; k < high; ) { /* loop thru mem */ + zeroflg = TRUE; + for (l = 0; (l < SRBSIZ) && (k < high); l++, + k = k + (dptr->aincr)) { /* check for 0 block */ + r = dptr->examine (&val, k, uptr, 0); + if (r != SCPE_OK) return r; + if (val) zeroflg = FALSE; + SZ_STORE (sz, val, mbuf, l); + } /* end for l */ + if (zeroflg) { /* all zero's? */ + l = -l; /* invert block count */ + WRITE_I (l); } /* write only count */ + else { + WRITE_I (l); /* block count */ + fxwrite (mbuf, l, sz, sfile); } + } /* end for k */ + free (mbuf); /* dealloc buffer */ + } /* end if mem */ + else { /* no memory */ + high = 0; /* write 0 */ + WRITE_I (high); + } /* end else mem */ + } /* end unit loop */ + j = -1; /* end units */ + WRITE_I (j); /* write marker */ + for (rptr = dptr->registers; (rptr != NULL) && /* loop thru regs */ + (rptr->name != NULL); rptr++) { + fputs (rptr->name, sfile); /* name */ + fputc ('\n', sfile); + WRITE_I (rptr->depth); /* [V2.10] depth */ + for (j = 0; j < rptr->depth; j++) { /* loop thru values */ + val = get_rval (rptr, j); /* get value */ + WRITE_I (val); } } /* store */ fputc ('\n', sfile); } /* end registers */ fputc ('\n', sfile); /* end devices */ r = (ferror (sfile))? SCPE_IOERR: SCPE_OK; /* error during save? */ @@ -1303,17 +1504,17 @@ return r; re[store] filename restore state from specified file */ -t_stat restore_cmd (int flag, char *cptr) +t_stat restore_cmd (int32 flag, char *cptr) { char buf[CBUFSIZE]; void *mbuf; FILE *rfile; -int32 i, j, blkcnt, limit, unitno, time; +int32 i, j, blkcnt, limit, unitno, time, flg, depth; t_addr k, high; -t_value val, mask, vzro = 0; +t_value val, mask; t_stat r; size_t sz; -t_bool v26 = FALSE, v25 = FALSE; +t_bool v210 = FALSE, v26 = FALSE; DEVICE *dptr; UNIT *uptr; REG *rptr; @@ -1325,106 +1526,145 @@ REG *rptr; GET_SWITCHES (cptr, buf); /* test for switches */ if (*cptr == 0) return SCPE_2FARG; /* must be more */ -if ((rfile = fopen (cptr, "rb")) == NULL) return SCPE_OPENERR; -READ_S (buf); /* save ver or sim name */ -if (strcmp (buf, save_vercur) == 0) { /* version 2.6? */ - v26 = v25 = TRUE; /* set flag */ - READ_S (buf); } /* read name */ -else if (strcmp (buf, save_ver25) == 0) { /* version 2.5? */ - v25 = TRUE; /* set flag */ - READ_S (buf); } /* read name */ +if ((rfile = FOPEN (cptr, "rb")) == NULL) return SCPE_OPENERR; +READ_S (buf); /* [V2.5+] read version */ +if (strcmp (buf, save_vercur) == 0) v210 = v26 = TRUE; /* version 2.10? */ +else if (strcmp (buf, save_ver26) == 0) v26 = TRUE; /* version 2.6? */ +else if (strcmp (buf, save_ver25) != 0) { /* version 2.5? */ + printf ("Invalid file version: %s\n", buf); /* no, unknown */ + fclose (rfile); + return SCPE_INCOMP; } +READ_S (buf); /* read sim name */ if (strcmp (buf, sim_name)) { /* name match? */ printf ("Wrong system type: %s\n", buf); fclose (rfile); return SCPE_INCOMP; } READ_I (sim_time); /* sim time */ -if (v26) { READ_I (sim_rtime); } /* sim relative time */ +if (v26) { READ_I (sim_rtime); } /* [V2.6+] sim rel time */ for ( ;; ) { /* device loop */ READ_S (buf); /* read device name */ if (buf[0] == 0) break; /* last? */ if ((dptr = find_dev (buf)) == NULL) { /* locate device */ - printf ("Invalid device name: %s\n", buf); + printf ("Invalid device name: %s\n", buf); + fclose (rfile); + return SCPE_INCOMP; } + if (v210) { /* [V2.10+] */ + READ_I (flg); /* cont flags */ + dptr->flags = (dptr->flags & ~DEV_RFLAGS) | /* restore */ + (flg & DEV_RFLAGS); } + for ( ;; ) { /* unit loop */ + READ_I (unitno); /* unit number */ + if (unitno < 0) break; /* end units? */ + if (unitno >= dptr->numunits) { /* too big? */ + printf ("Invalid unit number: %s%d\n", dptr->name, unitno); fclose (rfile); return SCPE_INCOMP; } - for ( ;; ) { /* unit loop */ - READ_I (unitno); /* unit number */ - if (unitno < 0) break; - if (unitno >= dptr -> numunits) { - printf ("Invalid unit number %s%d\n", dptr -> name, - unitno); + READ_I (time); /* event time */ + uptr = (dptr->units) + unitno; + sim_cancel (uptr); + if (time > 0) sim_activate (uptr, time - 1); + READ_I (uptr->u3); /* device specific */ + READ_I (uptr->u4); + if (v210) { /* [V2.10+] */ + READ_I (flg); /* unit flags */ + uptr->flags = (uptr->flags & ~UNIT_RFLAGS) | + (flg & UNIT_RFLAGS); } /* restore */ + READ_S (buf); /* attached file */ + if (buf[0] != 0) { /* any file? */ + uptr->flags = uptr->flags & ~UNIT_DIS; + if (v210 && (flg & UNIT_RO)) /* saved flgs & RO? */ + sim_switches = SWMASK ('R'); /* RO attach */ + else sim_switches = 0; /* no, normal att */ + if (dptr->attach != NULL) r = dptr->attach (uptr, buf); + else r = attach_unit (uptr, buf); + if (r != SCPE_OK) return r; } + READ_I (high); /* memory capacity */ + if (high > 0) { /* [V2.5+] any memory? */ + if (((uptr->flags & (UNIT_FIX + UNIT_ATTABLE)) != UNIT_FIX) || + (high > uptr->capac) || (dptr->deposit == NULL)) { + printf ("Invalid memory bound: %s%d = %u\n", + dptr->name, unitno, high); + fclose (rfile); + return SCPE_INCOMP; } + sz = SZ_D (dptr); /* allocate buffer */ + if ((mbuf = calloc (SRBSIZ, sz)) == NULL) { + fclose (rfile); + return SCPE_MEM; } + for (k = 0; k < high; ) { /* loop thru mem */ + READ_I (blkcnt); /* block count */ + if (blkcnt < 0) limit = -blkcnt; /* compressed? */ + else limit = fxread (mbuf, sz, blkcnt, rfile); + if (limit <= 0) { /* invalid or err? */ fclose (rfile); - return SCPE_INCOMP; } - READ_I (time); /* event time */ - uptr = (dptr -> units) + unitno; - sim_cancel (uptr); - if (time > 0) sim_activate (uptr, time - 1); - READ_I (uptr -> u3); /* device specific */ - READ_I (uptr -> u4); - READ_S (buf); /* attached file */ - if (buf[0] != 0) { - uptr -> flags = uptr -> flags & ~UNIT_DIS; - if (dptr -> attach != NULL) r = dptr -> attach (uptr, buf); - else r = attach_unit (uptr, buf); - if (r != SCPE_OK) return r; } - READ_I (high); /* memory capacity */ - if (high > 0) { /* any memory? */ - if (((uptr -> flags & (UNIT_FIX + UNIT_ATTABLE)) != UNIT_FIX) || - (high > uptr -> capac) || (dptr -> deposit == NULL)) { - printf ("Invalid memory bound: %u\n", high); - fclose (rfile); - return SCPE_INCOMP; } - if (v25) { - sz = SZ_D (dptr); - if ((mbuf = calloc (SRBSIZ, sz)) == NULL) { - fclose (rfile); - return SCPE_MEM; } - for (k = 0; k < high; ) { - READ_I (blkcnt); - if (blkcnt < 0) limit = -blkcnt; - else limit = fxread (mbuf, sz, blkcnt, rfile); - if (limit <= 0) { - fclose (rfile); - return SCPE_IOERR; } - for (j = 0; j < limit; j++, k = k + (dptr -> aincr)) { - if (blkcnt < 0) val = 0; - else SZ_LOAD (sz, val, mbuf, j); - r = dptr -> deposit (val, k, uptr, 0); - if (r != SCPE_OK) return r; - } /* end for j */ - } /* end for k */ - free (mbuf); /* dealloc buffer */ - } /* end if v25 */ - else { for (k = 0; k < high; k = k + (dptr -> aincr)) { - READ_I (val); - if (((t_svalue) val) < 0) { - for (j = (int32) val + 1; j < 0; j++) { - r = dptr -> deposit (vzro, k, uptr, 0); - if (r != SCPE_OK) return r; - k = k + (dptr -> aincr); } - val = 0; } - r = dptr -> deposit (val, k, uptr, 0); - if (r != SCPE_OK) return r; } - } /* end else v25 */ - } /* end if high */ - } /* end unit loop */ + return SCPE_IOERR; } + for (j = 0; j < limit; j++, k = k + (dptr->aincr)) { + if (blkcnt < 0) val = 0; /* compressed? */ + else SZ_LOAD (sz, val, mbuf, j);/* saved value */ + r = dptr->deposit (val, k, uptr, 0); + if (r != SCPE_OK) return r; + } /* end for j */ + } /* end for k */ + free (mbuf); /* dealloc buffer */ + } /* end if high */ + } /* end unit loop */ for ( ;; ) { /* register loop */ - READ_S (buf); /* read reg name */ - if (buf[0] == 0) break; /* last? */ - if ((rptr = find_reg (buf, NULL, dptr)) == NULL) { - printf ("Invalid register name: %s\n", buf); - READ_I (val); /* assume depth=1 */ - continue; } /* and pray! */ - mask = width_mask[rptr -> width]; - for (i = 0; i < rptr -> depth; i++) { /* loop thru values */ - READ_I (val); /* read value */ - if (val > mask) - printf ("Invalid register value: %s\n", buf); - else put_rval (rptr, i, val); } } + READ_S (buf); /* read reg name */ + if (buf[0] == 0) break; /* last? */ + if (v210) { READ_I (depth); } /* [V2.10+] depth */ + if ((rptr = find_reg (buf, NULL, dptr)) == NULL) { + printf ("Invalid register name: %s %s\n", dptr->name, buf); + if (v210) { /* [V2.10]+ */ + for (i = 0; i < depth; i++) { /* skip values */ + READ_I (val); } } + else { + READ_I (val); /* must be one val */ + if (!restore_skip_val (rfile)) /* grope for next reg */ + return SCPE_INCOMP; } /* err or eof? */ + continue; } /* pray! */ + if (v210 && (depth != rptr->depth)) /* [V2.10+] mismatch? */ + printf ("Register depth mismatch: %s %s, file = %d, sim = %d\n", + dptr->name, buf, depth, rptr->depth); + else depth = rptr->depth; /* depth validated */ + mask = width_mask[rptr->width]; /* get mask */ + for (i = 0; i < depth; i++) { /* loop thru values */ + READ_I (val); /* read value */ + if (val > mask) /* value ok? */ + printf ("Invalid register value: %s %s\n", dptr->name, buf); + else if (i < rptr->depth) /* in range? */ + put_rval (rptr, i, val); } } } /* end device loop */ fclose (rfile); return SCPE_OK; } + +/* Restore skip values (pre V2.10) + + To find the next register name, sift through bytes looking for valid + upper case ASCII characters terminated by \n */ + +t_bool restore_skip_val (FILE *rfile) +{ +t_bool instr = FALSE; +char c; +int32 ic, pos; + +if ((ic = fgetc (rfile)) == EOF) return FALSE; /* one char */ +fseek (rfile, ftell (rfile) - 1, SEEK_SET); /* back up over */ +if ((ic & 0377) == '\n') return TRUE; /* immediate nl? */ +while ((ic = fgetc (rfile)) != EOF) { /* get char */ + c = ic & 0377; /* cut to 8b */ + if (isalnum (c) || (c == '*') || (c == '_')) { /* valid reg char? */ + if (!instr) pos = ftell (rfile) - 1; /* new? save pos */ + instr = TRUE; } + else { /* not ASCII */ + if ((c == '\n') && instr) { /* nl & in string? */ + fseek (rfile, pos, SEEK_SET); /* rewind file */ + return TRUE; } + instr = FALSE; } /* not in string */ + } /* end while */ +return FALSE; /* error */ +} /* Run, go, cont, step commands @@ -1435,7 +1675,7 @@ return SCPE_OK; b[oot] device bootstrap from device and start simulation */ -t_stat run_cmd (int flag, char *cptr) +t_stat run_cmd (int32 flag, char *cptr) { char gbuf[CBUFSIZE]; int32 i, j, step, unitno; @@ -1462,12 +1702,12 @@ if (flag == RU_BOOT) { /* boot */ dptr = find_unit (gbuf, &uptr); /* locate unit */ if (dptr == NULL) return SCPE_NXDEV; /* found dev? */ if (uptr == NULL) return SCPE_NXUN; /* valid unit? */ - if (dptr -> boot == NULL) return SCPE_NOFNC; /* can it boot? */ - if (uptr -> flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ - if ((uptr -> flags & UNIT_ATTABLE) && - !(uptr -> flags & UNIT_ATT)) return SCPE_UNATT; - unitno = uptr - dptr -> units; /* recover unit# */ - if ((r = dptr -> boot (unitno)) != SCPE_OK) return r; } + if (dptr->boot == NULL) return SCPE_NOFNC; /* can it boot? */ + if (uptr->flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ + if ((uptr->flags & UNIT_ATTABLE) && + !(uptr->flags & UNIT_ATT)) return SCPE_UNATT; + unitno = uptr - dptr->units; /* recover unit# */ + if ((r = dptr->boot (unitno, dptr)) != SCPE_OK) return r; } if (*cptr != 0) return SCPE_2MARG; /* now eol? */ @@ -1478,17 +1718,20 @@ if ((flag == RU_RUN) || (flag == RU_BOOT)) { /* run or boot */ sim_clock_queue = NULL; if ((r = reset_all (0)) != SCPE_OK) return r; } for (i = 1; (dptr = sim_devices[i]) != NULL; i++) { - for (j = 0; j < dptr -> numunits; j++) { - uptr = (dptr -> units) + j; - if ((uptr -> flags & (UNIT_ATT + UNIT_SEQ)) == + for (j = 0; j < dptr->numunits; j++) { + uptr = (dptr->units) + j; + if ((uptr->flags & (UNIT_ATT + UNIT_SEQ)) == (UNIT_ATT + UNIT_SEQ)) - fseek (uptr -> fileref, uptr -> pos, SEEK_SET); } } + fseek (uptr->fileref, uptr->pos, SEEK_SET); } } stop_cpu = 0; -if ((int) signal (SIGINT, int_handler) == -1) { /* set WRU */ +if (signal (SIGINT, int_handler) == SIG_ERR) { /* set WRU */ return SCPE_SIGERR; } -if (ttrunstate () != SCPE_OK) { /* set console */ +if (ttrunstate () != SCPE_OK) { /* set console mode */ ttcmdstate (); return SCPE_TTYERR; } +if ((r = sim_check_console (30)) != SCPE_OK) { /* check console, error? */ + ttcmdstate (); + return r; } if (step) sim_activate (&step_unit, step); /* set step timer */ sim_is_running = 1; /* flag running */ r = sim_instr(); @@ -1498,7 +1741,7 @@ ttcmdstate (); /* restore console */ signal (SIGINT, SIG_DFL); /* cancel WRU */ sim_cancel (&step_unit); /* cancel step timer */ if (sim_clock_queue != NULL) { /* update sim time */ - UPDATE_SIM_TIME (sim_clock_queue -> time); } + UPDATE_SIM_TIME (sim_clock_queue->time); } else { UPDATE_SIM_TIME (noqueue_time); } #if defined (VMS) printf ("\n"); @@ -1519,21 +1762,21 @@ t_value pcval; DEVICE *dptr; if (v >= SCPE_BASE) fprintf (stream, "\n%s, %s: ", - scp_error_messages[v - SCPE_BASE], sim_PC -> name); -else fprintf (stream, "\n%s, %s: ", sim_stop_messages[v], sim_PC -> name); + scp_error_messages[v - SCPE_BASE], sim_PC->name); +else fprintf (stream, "\n%s, %s: ", sim_stop_messages[v], sim_PC->name); pcval = get_rval (sim_PC, 0); -fprint_val (stream, pcval, sim_PC -> radix, sim_PC -> width, - sim_PC -> flags & REG_FMT); -if (((dptr = sim_devices[0]) != NULL) && (dptr -> examine != NULL)) { +fprint_val (stream, pcval, sim_PC->radix, sim_PC->width, + sim_PC->flags & REG_FMT); +if (((dptr = sim_devices[0]) != NULL) && (dptr->examine != NULL)) { for (i = 0; i < sim_emax; i++) sim_eval[i] = 0; - for (i = 0, k = (t_addr) pcval; i < sim_emax; i++, k = k + dptr -> aincr) { - if (r = dptr -> examine (&sim_eval[i], k, dptr -> units, - SWMASK ('V')) != SCPE_OK) break; } + for (i = 0, k = (t_addr) pcval; i < sim_emax; i++, k = k + dptr->aincr) { + if ((r = dptr->examine (&sim_eval[i], k, dptr->units, + SWMASK ('V'))) != SCPE_OK) break; } if ((r == SCPE_OK) || (i > 0)) { fprintf (stream, " ("); if (fprint_sym (stream, (t_addr) pcval, sim_eval, NULL, SWMASK('M')) > 0) - fprint_val (stream, sim_eval[0], dptr -> dradix, - dptr -> dwidth, PV_RZRO); + fprint_val (stream, sim_eval[0], dptr->dradix, + dptr->dwidth, PV_RZRO); fprintf (stream, ")"); } } fprintf (stream, "\n"); return; @@ -1580,7 +1823,7 @@ return; STATE all registers */ -t_stat exdep_cmd (int flag, char *cptr) +t_stat exdep_cmd (int32 flag, char *cptr) { char gbuf[CBUFSIZE], *gptr, *tptr; int32 t; @@ -1592,9 +1835,9 @@ UNIT *uptr, *tuptr; REG *lowr, *highr; SCHTAB stab, *schptr; FILE *ofile; -t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int flag, char *ptr, +t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, char *ptr, t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr); -t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int flag, char *ptr, +t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, char *ptr, REG *lowr, REG *highr, t_addr lows, t_addr highs); ofile = NULL; /* no output file */ @@ -1605,7 +1848,7 @@ stab.logic = SCH_OR; /* default search params */ stab.bool = SCH_GE; stab.mask = stab.comp = 0; dptr = sim_devices[0]; /* default device, unit */ -uptr = dptr -> units; +uptr = dptr->units; for (;;) { /* loop through modifiers */ if (*cptr == 0) return SCPE_2FARG; /* must be more */ if (*cptr == '@') { /* output file spec? */ @@ -1614,7 +1857,7 @@ for (;;) { /* loop through modifiers */ fclose (ofile); /* one per customer */ return SCPE_ARG; } cptr = get_glyph_nc (cptr + 1, gbuf, 0); - ofile = fopen (gbuf, "a"); /* open for append */ + ofile = FOPEN (gbuf, "a"); /* open for append */ if (ofile == NULL) return SCPE_OPENERR; exd2f = TRUE; continue; } /* look for more */ @@ -1639,8 +1882,8 @@ for (gptr = gbuf, reason = SCPE_OK; if (strncmp (gptr, "STATE", strlen ("STATE")) == 0) { tptr = gptr + strlen ("STATE"); if (*tptr && (*tptr++ != ',')) return SCPE_ARG; - if ((lowr = dptr -> registers) == NULL) return SCPE_NXREG; - for (highr = lowr; highr -> name != NULL; highr++) ; + if ((lowr = dptr->registers) == NULL) return SCPE_NXREG; + for (highr = lowr; highr->name != NULL; highr++) ; sim_switches = sim_switches | SWHIDE; reason = exdep_reg_loop (ofile, schptr, flag, cptr, lowr, --highr, 0, 0); @@ -1654,18 +1897,18 @@ for (gptr = gbuf, reason = SCPE_OK; if (highr == NULL) return SCPE_NXREG; } else { highr = lowr; if (*tptr == '[') { - if (lowr -> depth <= 1) return SCPE_ARG; + if (lowr->depth <= 1) return SCPE_ARG; tptr = get_range (tptr + 1, &low, &high, - 10, lowr -> depth - 1, ']'); + 10, lowr->depth - 1, ']'); if (tptr == NULL) return SCPE_ARG; } } if (*tptr && (*tptr++ != ',')) return SCPE_ARG; reason = exdep_reg_loop (ofile, schptr, flag, cptr, lowr, highr, low, high); continue; } - tptr = get_range (gptr, &low, &high, dptr -> aradix, - (((uptr -> capac == 0) || (flag == EX_E))? 0: - uptr -> capac - dptr -> aincr), 0); + tptr = get_range (gptr, &low, &high, dptr->aradix, + (((uptr->capac == 0) || (flag == EX_E))? 0: + uptr->capac - dptr->aincr), 0); if (tptr == NULL) return SCPE_ARG; if (*tptr && (*tptr++ != ',')) return SCPE_ARG; reason = exdep_addr_loop (ofile, schptr, flag, cptr, low, high, @@ -1681,7 +1924,7 @@ return reason; exdep_addr_loop examine/deposit range of addresses */ -t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int flag, char *cptr, +t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int32 flag, char *cptr, REG *lowr, REG *highr, t_addr lows, t_addr highs) { t_stat reason; @@ -1693,9 +1936,9 @@ if ((lowr == NULL) || (highr == NULL)) return SCPE_IERR; if (lowr > highr) return SCPE_ARG; for (rptr = lowr; rptr <= highr; rptr++) { if ((sim_switches & SWHIDE) && - (rptr -> flags & REG_HIDDEN)) continue; + (rptr->flags & REG_HIDDEN)) continue; for (idx = lows; idx <= highs; idx++) { - if (idx >= (t_addr) rptr -> depth) return SCPE_SUB; + if (idx >= (t_addr) rptr->depth) return SCPE_SUB; val = get_rval (rptr, idx); if (schptr && !test_search (val, schptr)) continue; if (flag != EX_D) { @@ -1709,17 +1952,16 @@ for (rptr = lowr; rptr <= highr; rptr++) { return SCPE_OK; } -t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int flag, char *cptr, +t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int32 flag, char *cptr, t_addr low, t_addr high, DEVICE *dptr, UNIT *uptr) { t_addr i, mask; t_stat reason; -if (uptr -> flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ -reason = 0; -mask = (t_addr) width_mask[dptr -> awidth]; +if (uptr->flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ +mask = (t_addr) width_mask[dptr->awidth]; if ((low > mask) || (high > mask) || (low > high)) return SCPE_ARG; -for (i = low; i <= high; i = i + (dptr -> aincr)) { +for (i = low; i <= high; i = i + (dptr->aincr)) { reason = get_aval (i, dptr, uptr); /* get data */ if (reason != SCPE_OK) return reason; /* return if error */ if (schptr && !test_search (sim_eval[0], schptr)) continue; @@ -1731,7 +1973,7 @@ for (i = low; i <= high; i = i + (dptr -> aincr)) { if (flag != EX_E) { reason = dep_addr (flag, cptr, i, dptr, uptr, reason); if (reason > SCPE_OK) return reason; } - if (reason < SCPE_OK) i = i - (reason * dptr -> aincr); } + if (reason < SCPE_OK) i = i - (reason * dptr->aincr); } return SCPE_OK; } @@ -1747,16 +1989,16 @@ return SCPE_OK; return = error status */ -t_stat ex_reg (FILE *ofile, t_value val, int flag, REG *rptr, t_addr idx) +t_stat ex_reg (FILE *ofile, t_value val, int32 flag, REG *rptr, t_addr idx) { int32 rdx; if (rptr == NULL) return SCPE_IERR; -if (rptr -> depth > 1) fprintf (ofile, "%s[%d]: ", rptr -> name, idx); -else fprintf (ofile, "%s: ", rptr -> name); +if (rptr->depth > 1) fprintf (ofile, "%s[%d]: ", rptr->name, idx); +else fprintf (ofile, "%s: ", rptr->name); if (!(flag & EX_E)) return SCPE_OK; -GET_RADIX (rdx, rptr -> radix); -fprint_val (ofile, val, rdx, rptr -> width, rptr -> flags & REG_FMT); +GET_RADIX (rdx, rptr->radix); +fprint_val (ofile, val, rdx, rptr->width, rptr->flags & REG_FMT); if (flag & EX_I) fprintf (ofile, " "); else fprintf (ofile, "\n"); return SCPE_OK; @@ -1771,31 +2013,31 @@ return SCPE_OK; return = register value */ -t_value get_rval (REG *rptr, int idx) +t_value get_rval (REG *rptr, int32 idx) { size_t sz; t_value val; UNIT *uptr; sz = SZ_R (rptr); -if ((rptr -> depth > 1) && (rptr -> flags & REG_CIRC)) { - idx = idx + rptr -> qptr; - if (idx >= rptr -> depth) idx = idx - rptr -> depth; } -if ((rptr -> depth > 1) && (rptr -> flags & REG_UNIT)) { - uptr = ((UNIT *) rptr -> loc) + idx; +if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) { + idx = idx + rptr->qptr; + if (idx >= rptr->depth) idx = idx - rptr->depth; } +if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) { + uptr = ((UNIT *) rptr->loc) + idx; val = *((uint32 *) uptr); } -else if ((rptr -> depth > 1) && (sz == sizeof (uint8))) - val = *(((uint8 *) rptr -> loc) + idx); -else if ((rptr -> depth > 1) && (sz == sizeof (uint16))) - val = *(((uint16 *) rptr -> loc) + idx); +else if ((rptr->depth > 1) && (sz == sizeof (uint8))) + val = *(((uint8 *) rptr->loc) + idx); +else if ((rptr->depth > 1) && (sz == sizeof (uint16))) + val = *(((uint16 *) rptr->loc) + idx); #if !defined (t_int64) -else val = *(((uint32 *) rptr -> loc) + idx); +else val = *(((uint32 *) rptr->loc) + idx); #else else if (sz <= sizeof (uint32)) - val = *(((uint32 *) rptr -> loc) + idx); -else val = *(((t_uint64 *) rptr -> loc) + idx); + val = *(((uint32 *) rptr->loc) + idx); +else val = *(((t_uint64 *) rptr->loc) + idx); #endif -val = (val >> rptr -> offset) & width_mask[rptr -> width]; +val = (val >> rptr->offset) & width_mask[rptr->width]; return val; } @@ -1810,7 +2052,7 @@ return val; return = error status */ -t_stat dep_reg (int flag, char *cptr, REG *rptr, t_addr idx) +t_stat dep_reg (int32 flag, char *cptr, REG *rptr, t_addr idx) { t_stat r; t_value val, mask; @@ -1818,17 +2060,17 @@ int32 rdx; char gbuf[CBUFSIZE]; if ((cptr == NULL) || (rptr == NULL)) return SCPE_IERR; -if (rptr -> flags & REG_RO) return SCPE_RO; +if (rptr->flags & REG_RO) return SCPE_RO; if (flag & EX_I) { cptr = read_line (gbuf, CBUFSIZE, stdin); if (sim_log) fprintf (sim_log, (cptr? "%s\n": "\n"), cptr); if (cptr == NULL) return 1; /* force exit */ if (*cptr == 0) return SCPE_OK; } /* success */ -mask = width_mask[rptr -> width]; -GET_RADIX (rdx, rptr -> radix); +mask = width_mask[rptr->width]; +GET_RADIX (rdx, rptr->radix); val = get_uint (cptr, rdx, mask, &r); if (r != SCPE_OK) return SCPE_ARG; -if ((rptr -> flags & REG_NZ) && (val == 0)) return SCPE_ARG; +if ((rptr->flags & REG_NZ) && (val == 0)) return SCPE_ARG; put_rval (rptr, idx, val); return SCPE_OK; } @@ -1844,32 +2086,32 @@ return SCPE_OK; none */ -void put_rval (REG *rptr, int idx, t_value val) +void put_rval (REG *rptr, int32 idx, t_value val) { size_t sz; t_value mask; UNIT *uptr; #define PUT_RVAL(sz,rp,id,v,m) \ - *(((sz *) rp -> loc) + id) = \ - (*(((sz *) rp -> loc) + id) & \ - ~((m) << (rp) -> offset)) | ((v) << (rp) -> offset) + *(((sz *) rp->loc) + id) = \ + (*(((sz *) rp->loc) + id) & \ + ~((m) << (rp)->offset)) | ((v) << (rp)->offset) if (rptr == sim_PC) sim_brk_npc (); sz = SZ_R (rptr); -mask = width_mask[rptr -> width]; -if ((rptr -> depth > 1) && (rptr -> flags & REG_CIRC)) { - idx = idx + rptr -> qptr; - if (idx >= rptr -> depth) idx = idx - rptr -> depth; } -if ((rptr -> depth > 1) && (rptr -> flags & REG_UNIT)) { - uptr = ((UNIT *) rptr -> loc) + idx; +mask = width_mask[rptr->width]; +if ((rptr->depth > 1) && (rptr->flags & REG_CIRC)) { + idx = idx + rptr->qptr; + if (idx >= rptr->depth) idx = idx - rptr->depth; } +if ((rptr->depth > 1) && (rptr->flags & REG_UNIT)) { + uptr = ((UNIT *) rptr->loc) + idx; *((uint32 *) uptr) = (*((uint32 *) uptr) & - ~(((uint32) mask) << rptr -> offset)) | - (((uint32) val) << rptr -> offset); } -else if ((rptr -> depth > 1) && (sz == sizeof (uint8))) + ~(((uint32) mask) << rptr->offset)) | + (((uint32) val) << rptr->offset); } +else if ((rptr->depth > 1) && (sz == sizeof (uint8))) PUT_RVAL (uint8, rptr, idx, (uint32) val, (uint32) mask); -else if ((rptr -> depth > 1) && (sz == sizeof (uint16))) +else if ((rptr->depth > 1) && (sz == sizeof (uint16))) PUT_RVAL (uint16, rptr, idx, (uint32) val, (uint32) mask); #if !defined (t_int64) else PUT_RVAL (uint32, rptr, idx, val, mask); @@ -1894,18 +2136,18 @@ return; if < 0, number of extra words retired */ -t_stat ex_addr (FILE *ofile, int flag, t_addr addr, DEVICE *dptr, UNIT *uptr) +t_stat ex_addr (FILE *ofile, int32 flag, t_addr addr, DEVICE *dptr, UNIT *uptr) { t_stat reason; int32 rdx; -fprint_val (ofile, addr, dptr -> aradix, dptr -> awidth, PV_LEFT); +fprint_val (ofile, addr, dptr->aradix, dptr->awidth, PV_LEFT); fprintf (ofile, ": "); if (!(flag & EX_E)) return SCPE_OK; -GET_RADIX (rdx, dptr -> dradix); +GET_RADIX (rdx, dptr->dradix); if ((reason = fprint_sym (ofile, addr, sim_eval, uptr, sim_switches)) > 0) - reason = fprint_val (ofile, sim_eval[0], rdx, dptr -> dwidth, PV_RZRO); + reason = fprint_val (ofile, sim_eval[0], rdx, dptr->dwidth, PV_RZRO); if (flag & EX_I) fprintf (ofile, " "); else fprintf (ofile, "\n"); return reason; @@ -1931,28 +2173,28 @@ size_t sz; t_stat reason = SCPE_OK; if ((dptr == NULL) || (uptr == NULL)) return SCPE_IERR; -mask = width_mask[dptr -> dwidth]; +mask = width_mask[dptr->dwidth]; for (i = 0; i < sim_emax; i++) sim_eval[i] = 0; -for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr -> aincr) { - if (dptr -> examine != NULL) { - reason = dptr -> examine (&sim_eval[i], j, uptr, sim_switches); +for (i = 0, j = addr; i < sim_emax; i++, j = j + dptr->aincr) { + if (dptr->examine != NULL) { + reason = dptr->examine (&sim_eval[i], j, uptr, sim_switches); if (reason != SCPE_OK) break; } - else { if (!(uptr -> flags & UNIT_ATT)) return SCPE_UNATT; - if ((uptr -> flags & UNIT_FIX) && (j >= uptr -> capac)) { + else { if (!(uptr->flags & UNIT_ATT)) return SCPE_UNATT; + if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac)) { reason = SCPE_NXM; break; } sz = SZ_D (dptr); - loc = j / dptr -> aincr; - if (uptr -> flags & UNIT_BUF) { - SZ_LOAD (sz, sim_eval[i], uptr -> filebuf, loc); } - else { fseek (uptr -> fileref, sz * loc, SEEK_SET); - fxread (&sim_eval[i], sz, 1, uptr -> fileref); - if ((feof (uptr -> fileref)) && - !(uptr -> flags & UNIT_FIX)) { + loc = j / dptr->aincr; + if (uptr->flags & UNIT_BUF) { + SZ_LOAD (sz, sim_eval[i], uptr->filebuf, loc); } + else { fseek (uptr->fileref, sz * loc, SEEK_SET); + fxread (&sim_eval[i], sz, 1, uptr->fileref); + if ((feof (uptr->fileref)) && + !(uptr->flags & UNIT_FIX)) { reason = SCPE_EOF; break; } - else if (ferror (uptr -> fileref)) { - clearerr (uptr -> fileref); + else if (ferror (uptr->fileref)) { + clearerr (uptr->fileref); reason = SCPE_IOERR; break; } } } sim_eval[i] = sim_eval[i] & mask; } @@ -1974,8 +2216,8 @@ return SCPE_OK; if < 0, number of extra words retired */ -t_stat dep_addr (int flag, char *cptr, t_addr addr, DEVICE *dptr, - UNIT *uptr, int dfltinc) +t_stat dep_addr (int32 flag, char *cptr, t_addr addr, DEVICE *dptr, + UNIT *uptr, int32 dfltinc) { int32 i, count, rdx; t_addr j, loc; @@ -1990,32 +2232,32 @@ if (flag & EX_I) { if (sim_log) fprintf (sim_log, (cptr? "%s\n": "\n"), cptr); if (cptr == NULL) return 1; /* force exit */ if (*cptr == 0) return dfltinc; } /* success */ -if (uptr -> flags & UNIT_RO) return SCPE_RO; /* read only? */ -mask = width_mask[dptr -> dwidth]; +if (uptr->flags & UNIT_RO) return SCPE_RO; /* read only? */ +mask = width_mask[dptr->dwidth]; -GET_RADIX (rdx, dptr -> dradix); +GET_RADIX (rdx, dptr->dradix); if ((reason = parse_sym (cptr, addr, uptr, sim_eval, sim_switches)) > 0) { sim_eval[0] = get_uint (cptr, rdx, mask, &reason); if (reason != SCPE_OK) return reason; } count = 1 - reason; -for (i = 0, j = addr; i < count; i++, j = j + dptr -> aincr) { +for (i = 0, j = addr; i < count; i++, j = j + dptr->aincr) { sim_eval[i] = sim_eval[i] & mask; - if (dptr -> deposit != NULL) { - r = dptr -> deposit (sim_eval[i], j, uptr, sim_switches); + if (dptr->deposit != NULL) { + r = dptr->deposit (sim_eval[i], j, uptr, sim_switches); if (r != SCPE_OK) return r; } - else { if (!(uptr -> flags & UNIT_ATT)) return SCPE_UNATT; - if ((uptr -> flags & UNIT_FIX) && (j >= uptr -> capac)) + else { if (!(uptr->flags & UNIT_ATT)) return SCPE_UNATT; + if ((uptr->flags & UNIT_FIX) && (j >= uptr->capac)) return SCPE_NXM; sz = SZ_D (dptr); - loc = j / dptr -> aincr; - if (uptr -> flags & UNIT_BUF) { - SZ_STORE (sz, sim_eval[i], uptr -> filebuf, loc); - if (loc >= uptr -> hwmark) uptr -> hwmark = loc + 1; } - else { fseek (uptr -> fileref, sz * loc, SEEK_SET); - fxwrite (sim_eval, sz, 1, uptr -> fileref); - if (ferror (uptr -> fileref)) { - clearerr (uptr -> fileref); + loc = j / dptr->aincr; + if (uptr->flags & UNIT_BUF) { + SZ_STORE (sz, sim_eval[i], uptr->filebuf, loc); + if (loc >= uptr->hwmark) uptr->hwmark = loc + 1; } + else { fseek (uptr->fileref, sz * loc, SEEK_SET); + fxwrite (sim_eval, sz, 1, uptr->fileref); + if (ferror (uptr->fileref)) { + clearerr (uptr->fileref); return SCPE_IOERR; } } } } return reason; } @@ -2033,7 +2275,7 @@ return reason; NULL if EOF */ -char *read_line (char *cptr, int size, FILE *stream) +char *read_line (char *cptr, int32 size, FILE *stream) { char *tptr; @@ -2041,8 +2283,8 @@ cptr = fgets (cptr, size, stream); /* get cmd line */ if (cptr == NULL) { clearerr (stream); /* clear error */ return NULL; } /* ignore EOF */ -for (tptr = cptr; tptr < (cptr + size); tptr++) /* remove cr */ - if (*tptr == '\n') *tptr = 0; +for (tptr = cptr; tptr < (cptr + size); tptr++) /* remove cr or nl */ + if ((*tptr == '\n') || (*tptr == '\r')) *tptr = 0; while (isspace (*cptr)) cptr++; /* absorb spaces */ if (*cptr == ';') *cptr = 0; /* ignore comment */ return cptr; @@ -2114,7 +2356,7 @@ return FALSE; val = value */ -t_value get_uint (char *cptr, int radix, t_value max, t_stat *status) +t_value get_uint (char *cptr, int32 radix, t_value max, t_stat *status) { t_value val; char *tptr; @@ -2139,7 +2381,7 @@ return val; NULL if error */ -char *get_range (char *cptr, t_addr *lo, t_addr *hi, int rdx, +char *get_range (char *cptr, t_addr *lo, t_addr *hi, int32 rdx, t_addr max, char term) { char *tptr; @@ -2178,7 +2420,7 @@ int32 i; DEVICE *dptr; for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { - if (strcmp (cptr, dptr -> name) == 0) return dptr; } + if (strcmp (cptr, dptr->name) == 0) return dptr; } return NULL; } @@ -2194,26 +2436,27 @@ return NULL; DEVICE *find_unit (char *cptr, UNIT **uptr) { -int32 i, lenn, u; +int32 i, u; +char *tptr; t_stat r; DEVICE *dptr; if (uptr == NULL) return NULL; /* arg error? */ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* exact match? */ - if (strcmp (cptr, dptr -> name) == 0) { + if (strcmp (cptr, dptr->name) == 0) { if (qdisable (dptr)) return NULL; /* disabled? */ - *uptr = dptr -> units; /* unit 0 */ + *uptr = dptr->units; /* unit 0 */ return dptr; } } for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* base + unit#? */ - lenn = strlen (dptr -> name); - if ((dptr -> numunits == 0) || /* no units? */ - (strncmp (cptr, dptr -> name, lenn) != 0)) continue; + if ((dptr->numunits == 0) || /* no units? */ + (strncmp (cptr, dptr->name, strlen (dptr->name)) != 0)) continue; + tptr = cptr + strlen (dptr->name); /* skip devname */ + if (!isdigit (*tptr)) continue; /* number next? */ if (qdisable (dptr)) return NULL; /* disabled? */ - cptr = cptr + lenn; /* skip devname */ - u = (int32) get_uint (cptr, 10, dptr -> numunits - 1, &r); + u = (int32) get_uint (tptr, 10, dptr->numunits - 1, &r); if (r != SCPE_OK) *uptr = NULL; /* error? */ - else *uptr = dptr -> units + u; + else *uptr = dptr->units + u; return dptr; } return NULL; } @@ -2233,8 +2476,8 @@ int32 i, j; if (uptr == NULL) return NULL; for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { - for (j = 0; j < dptr -> numunits; j++) { - if (uptr == (dptr -> units + j)) return dptr; } } + for (j = 0; j < dptr->numunits; j++) { + if (uptr == (dptr->units + j)) return dptr; } } return NULL; } @@ -2242,11 +2485,7 @@ return NULL; t_bool qdisable (DEVICE *dptr) { -REG *rptr; - -rptr = find_reg ("*DEVENB", NULL, dptr); /* locate enable */ -if (rptr == NULL) return FALSE; /* found it? */ -return (get_rval (rptr, 0)? FALSE: TRUE); /* return flag */ +return (dptr->flags & DEV_DIS? TRUE: FALSE); } /* find_reg_glob find globally unique register @@ -2290,14 +2529,17 @@ REG *find_reg (char *cptr, char **optr, DEVICE *dptr) { char *tptr; REG *rptr; +uint32 slnt; if ((cptr == NULL) || (dptr == NULL) || - (dptr -> registers == NULL)) return NULL; + (dptr->registers == NULL)) return NULL; tptr = cptr; do { tptr++; } while (isalnum (*tptr) || (*tptr == '*') || (*tptr == '_')); -for (rptr = dptr -> registers; rptr -> name != NULL; rptr++) { - if (strncmp (cptr, rptr -> name, tptr - cptr) == 0) { +slnt = tptr - cptr; +for (rptr = dptr->registers; rptr->name != NULL; rptr++) { + if ((slnt == strlen (rptr->name)) && + (strncmp (cptr, rptr->name, slnt) == 0)) { if (optr != NULL) *optr = tptr; return rptr; } } return NULL; @@ -2350,7 +2592,7 @@ return TRUE; SCHTAB *get_search (char *cptr, DEVICE *dptr, SCHTAB *schptr) { -int c, logop, cmpop; +int32 c, logop, cmpop; t_value logval, cmpval; char *sptr, *tptr; const char logstr[] = "|&^", cmpstr[] = "=!><"; @@ -2359,24 +2601,24 @@ if (*cptr == 0) return NULL; /* check for clause */ for (logop = cmpop = -1; c = *cptr++; ) { /* loop thru clauses */ if (sptr = strchr (logstr, c)) { /* check for mask */ logop = sptr - logstr; - logval = strtotv (cptr, &tptr, dptr -> dradix); + logval = strtotv (cptr, &tptr, dptr->dradix); if (cptr == tptr) return NULL; cptr = tptr; } - else if (sptr = strchr (cmpstr, c)) { /* check for bool */ + else if (sptr = strchr (cmpstr, c)) { /* check for bool */ cmpop = sptr - cmpstr; if (*cptr == '=') { cmpop = cmpop + strlen (cmpstr); cptr++; } - cmpval = strtotv (cptr, &tptr, dptr -> dradix); + cmpval = strtotv (cptr, &tptr, dptr->dradix); if (cptr == tptr) return NULL; cptr = tptr; } else return NULL; } /* end while */ if (logop >= 0) { - schptr -> logic = logop; - schptr -> mask = logval; } + schptr->logic = logop; + schptr->mask = logval; } if (cmpop >= 0) { - schptr -> bool = cmpop; - schptr -> comp = cmpval; } + schptr->bool = cmpop; + schptr->comp = cmpval; } return schptr; } @@ -2389,32 +2631,32 @@ return schptr; return = 1 if value passes search criteria, 0 if not */ -int test_search (t_value val, SCHTAB *schptr) +int32 test_search (t_value val, SCHTAB *schptr) { if (schptr == NULL) return 0; -switch (schptr -> logic) { /* case on logical */ +switch (schptr->logic) { /* case on logical */ case SCH_OR: - val = val | schptr -> mask; + val = val | schptr->mask; break; case SCH_AND: - val = val & schptr -> mask; + val = val & schptr->mask; break; case SCH_XOR: - val = val ^ schptr -> mask; + val = val ^ schptr->mask; break; } -switch (schptr -> bool) { /* case on comparison */ +switch (schptr->bool) { /* case on comparison */ case SCH_E: case SCH_EE: - return (val == schptr -> comp); + return (val == schptr->comp); case SCH_N: case SCH_NE: - return (val != schptr -> comp); + return (val != schptr->comp); case SCH_G: - return (val > schptr -> comp); + return (val > schptr->comp); case SCH_GE: - return (val >= schptr -> comp); + return (val >= schptr->comp); case SCH_L: - return (val < schptr -> comp); + return (val < schptr->comp); case SCH_LE: - return (val <= schptr -> comp); } + return (val <= schptr->comp); } return 0; } @@ -2432,11 +2674,11 @@ return 0; On an error, the endptr will equal the inptr. */ -t_value strtotv (char *inptr, char **endptr, int radix) +t_value strtotv (char *inptr, char **endptr, int32 radix) { -int nodigit; +int32 nodigit; t_value val; -int c, digit; +int32 c, digit; *endptr = inptr; /* assume fails */ if ((radix < 2) || (radix > 36)) return 0; @@ -2467,8 +2709,8 @@ return val; status = error status */ -t_stat fprint_val (FILE *stream, t_value val, int radix, - int width, int format) +t_stat fprint_val (FILE *stream, t_value val, int32 radix, + int32 width, int32 format) { #define MAX_WIDTH ((int) (CHAR_BIT * sizeof (t_value))) t_value owtest, wtest; @@ -2536,14 +2778,14 @@ if (sim_clock_queue == NULL) { /* queue empty? */ UPDATE_SIM_TIME (noqueue_time); /* update sim time */ sim_interval = noqueue_time = NOQUEUE_WAIT; /* flag queue empty */ return SCPE_OK; } -UPDATE_SIM_TIME (sim_clock_queue -> time); /* update sim time */ +UPDATE_SIM_TIME (sim_clock_queue->time); /* update sim time */ do { uptr = sim_clock_queue; /* get first */ - sim_clock_queue = uptr -> next; /* remove first */ - uptr -> next = NULL; /* hygiene */ - uptr -> time = 0; - if (sim_clock_queue != NULL) sim_interval = sim_clock_queue -> time; + sim_clock_queue = uptr->next; /* remove first */ + uptr->next = NULL; /* hygiene */ + uptr->time = 0; + if (sim_clock_queue != NULL) sim_interval = sim_clock_queue->time; else sim_interval = noqueue_time = NOQUEUE_WAIT; - if (uptr -> action != NULL) reason = uptr -> action (uptr); + if (uptr->action != NULL) reason = uptr->action (uptr); else reason = SCPE_OK; } while ((reason == SCPE_OK) && (sim_interval == 0)); @@ -2569,22 +2811,22 @@ int32 accum; if (event_time < 0) return SCPE_IERR; if (sim_is_active (uptr)) return SCPE_OK; /* already active? */ if (sim_clock_queue == NULL) { UPDATE_SIM_TIME (noqueue_time); } -else { UPDATE_SIM_TIME (sim_clock_queue -> time); } /* update sim time */ +else { UPDATE_SIM_TIME (sim_clock_queue->time); } /* update sim time */ prvptr = NULL; accum = 0; -for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr -> next) { - if (event_time < (accum + cptr -> time)) break; - accum = accum + cptr -> time; +for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr->next) { + if (event_time < (accum + cptr->time)) break; + accum = accum + cptr->time; prvptr = cptr; } if (prvptr == NULL) { /* insert at head */ - cptr = uptr -> next = sim_clock_queue; + cptr = uptr->next = sim_clock_queue; sim_clock_queue = uptr; } -else { cptr = uptr -> next = prvptr -> next; /* insert at prvptr */ - prvptr -> next = uptr; } -uptr -> time = event_time - accum; -if (cptr != NULL) cptr -> time = cptr -> time - uptr -> time; -sim_interval = sim_clock_queue -> time; +else { cptr = uptr->next = prvptr->next; /* insert at prvptr */ + prvptr->next = uptr; } +uptr->time = event_time - accum; +if (cptr != NULL) cptr->time = cptr->time - uptr->time; +sim_interval = sim_clock_queue->time; return SCPE_OK; } @@ -2602,17 +2844,17 @@ t_stat sim_cancel (UNIT *uptr) UNIT *cptr, *nptr; if (sim_clock_queue == NULL) return SCPE_OK; -UPDATE_SIM_TIME (sim_clock_queue -> time); /* update sim time */ +UPDATE_SIM_TIME (sim_clock_queue->time); /* update sim time */ nptr = NULL; -if (sim_clock_queue == uptr) nptr = sim_clock_queue = uptr -> next; -else { for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr -> next) { - if (cptr -> next == uptr) { - nptr = cptr -> next = uptr -> next; +if (sim_clock_queue == uptr) nptr = sim_clock_queue = uptr->next; +else { for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr->next) { + if (cptr->next == uptr) { + nptr = cptr->next = uptr->next; break; } } } /* end queue scan */ -if (nptr != NULL) nptr -> time = nptr -> time + uptr -> time; -uptr -> next = NULL; /* hygiene */ -uptr -> time = 0; -if (sim_clock_queue != NULL) sim_interval = sim_clock_queue -> time; +if (nptr != NULL) nptr->time = nptr->time + uptr->time; +uptr->next = NULL; /* hygiene */ +uptr->time = 0; +if (sim_clock_queue != NULL) sim_interval = sim_clock_queue->time; else sim_interval = noqueue_time = NOQUEUE_WAIT; return SCPE_OK; } @@ -2631,8 +2873,8 @@ UNIT *cptr; int32 accum; accum = 0; -for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr -> next) { - accum = accum + cptr -> time; +for (cptr = sim_clock_queue; cptr != NULL; cptr = cptr->next) { + accum = accum + cptr->time; if (cptr == uptr) return accum + 1; } return 0; } @@ -2648,14 +2890,14 @@ return 0; double sim_gtime (void) { if (sim_clock_queue == NULL) { UPDATE_SIM_TIME (noqueue_time); } -else { UPDATE_SIM_TIME (sim_clock_queue -> time); } +else { UPDATE_SIM_TIME (sim_clock_queue->time); } return sim_time; } uint32 sim_grtime (void) { if (sim_clock_queue == NULL) { UPDATE_SIM_TIME (noqueue_time); } -else { UPDATE_SIM_TIME (sim_clock_queue -> time); } +else { UPDATE_SIM_TIME (sim_clock_queue->time); } return sim_rtime; } @@ -2672,7 +2914,7 @@ int32 cnt; UNIT *uptr; cnt = 0; -for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr -> next) cnt++; +for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr->next) cnt++; return cnt; } @@ -2864,19 +3106,19 @@ BRKTAB *sim_brk_fnd (t_addr loc) int32 lo, hi, p; BRKTAB *bp; -if (sim_brk_ent == 0) { /* table empty? */ - sim_brk_ins = 0; /* insrt at head */ - return NULL; } /* sch fails */ -lo = 0; /* initial bounds */ +if (sim_brk_ent == 0) { /* table empty? */ + sim_brk_ins = 0; /* insrt at head */ + return NULL; } /* sch fails */ +lo = 0; /* initial bounds */ hi = sim_brk_ent - 1; -do { p = (lo + hi) >> 1; /* probe */ - bp = sim_brk_tab + p; /* table addr */ - if (loc == bp -> addr) return bp; /* match? */ - else if (loc < bp -> addr) hi = p - 1; /* go down? p is upper */ - else lo = p + 1; } /* go up? p is lower */ +do { p = (lo + hi) >> 1; /* probe */ + bp = sim_brk_tab + p; /* table addr */ + if (loc == bp->addr) return bp; /* match? */ + else if (loc < bp->addr) hi = p - 1; /* go down? p is upper */ + else lo = p + 1; } /* go up? p is lower */ while (lo <= hi); -if (loc < bp -> addr) sim_brk_ins = p; /* insrt before or */ -else sim_brk_ins = p + 1; /* after last sch */ +if (loc < bp->addr) sim_brk_ins = p; /* insrt before or */ +else sim_brk_ins = p + 1; /* after last sch */ return NULL; } @@ -2888,15 +3130,15 @@ BRKTAB *bp; if (sim_brk_ins < 0) return NULL; if (sim_brk_ent >= sim_brk_lnt) return NULL; -if (sim_brk_ins != sim_brk_ent) { /* move needed? */ +if (sim_brk_ins != sim_brk_ent) { /* move needed? */ for (bp = sim_brk_tab + sim_brk_ent; bp > sim_brk_tab + sim_brk_ins; bp--) *bp = *(bp - 1); } bp = sim_brk_tab + sim_brk_ins; -bp -> addr = loc; -bp -> typ = 0; -bp -> cnt = 0; -bp -> act = NULL; +bp->addr = loc; +bp->typ = 0; +bp->cnt = 0; +bp->act = NULL; sim_brk_ent = sim_brk_ent + 1; return bp; } @@ -2912,8 +3154,8 @@ if ((sim_brk_types & sw) == 0) return SCPE_NOFNC; bp = sim_brk_fnd (loc); if (!bp) bp = sim_brk_new (loc); if (!bp) return SCPE_MEM; -bp -> typ = sw; -bp -> cnt = ncnt; +bp->typ = sw; +bp->cnt = ncnt; sim_brk_summ = sim_brk_summ | sw; return SCPE_OK; } @@ -2926,14 +3168,14 @@ BRKTAB *bp = sim_brk_fnd (loc); if (!bp) return SCPE_OK; if (sw == 0) sw = SIM_BRK_ALLTYP; -bp -> typ = bp -> typ & ~sw; -if (bp -> typ) return SCPE_OK; +bp->typ = bp->typ & ~sw; +if (bp->typ) return SCPE_OK; for ( ; bp < (sim_brk_tab + sim_brk_ent - 1); bp++) *bp = *(bp + 1); sim_brk_ent = sim_brk_ent - 1; sim_brk_summ = 0; for (bp = sim_brk_tab; bp < (sim_brk_tab + sim_brk_ent); bp++) - sim_brk_summ = sim_brk_summ | bp -> typ; + sim_brk_summ = sim_brk_summ | bp->typ; return SCPE_OK; } @@ -2946,7 +3188,7 @@ BRKTAB *bp; if (sw == 0) sw = SIM_BRK_ALLTYP; if ((sim_brk_summ & ~sw) == 0) sim_brk_ent = sim_brk_summ = 0; else { for (bp = sim_brk_tab; bp < (sim_brk_tab + sim_brk_ent); bp++) { - if (bp -> typ & sw) sim_brk_clr (bp -> addr, sw); } } + if (bp->typ & sw) sim_brk_clr (bp->addr, sw); } } return SCPE_OK; } @@ -2959,17 +3201,17 @@ DEVICE *dptr; int32 i, any; if (sw == 0) sw = SIM_BRK_ALLTYP; -if (!bp || (!(bp -> typ & sw))) return SCPE_OK; +if (!bp || (!(bp->typ & sw))) return SCPE_OK; dptr = sim_devices[0]; if (dptr == NULL) return SCPE_OK; -fprint_val (st, loc, dptr -> aradix, dptr -> awidth, PV_LEFT); +fprint_val (st, loc, dptr->aradix, dptr->awidth, PV_LEFT); fprintf (st, ":\t"); for (i = any = 0; i < 26; i++) { - if ((bp -> typ >> i) & 1) { + if ((bp->typ >> i) & 1) { if (any) fprintf (st, ", "); fputc (i + 'A', st); any = 1; } } -if (bp -> cnt > 0) fprintf (st, " [%d]", bp -> cnt); +if (bp->cnt > 0) fprintf (st, " [%d]", bp->cnt); fprintf (st, "\n"); return SCPE_OK; } @@ -2982,7 +3224,7 @@ BRKTAB *bp; if (sw == 0) sw = SIM_BRK_ALLTYP; for (bp = sim_brk_tab; bp < (sim_brk_tab + sim_brk_ent); bp++) { - if (bp -> typ & sw) sim_brk_show (st, bp -> addr, sw); } + if (bp->typ & sw) sim_brk_show (st, bp->addr, sw); } return SCPE_OK; } @@ -2993,10 +3235,10 @@ t_bool sim_brk_test (t_addr loc, int32 btyp) BRKTAB *bp; if ((bp = sim_brk_fnd (loc)) && - (btyp & bp -> typ) && + (btyp & bp->typ) && (!sim_brk_pend || (loc != sim_brk_ploc)) && - (--(bp -> cnt) <= 0)) { - bp -> cnt = 0; + (--(bp->cnt) <= 0)) { + bp->cnt = 0; sim_brk_ploc = loc; sim_brk_pend = TRUE; return TRUE; } @@ -3011,3 +3253,100 @@ void sim_brk_npc (void) sim_brk_pend = FALSE; return; } + +/* Telnet console package. + + The console terminal can be attached to the controlling window + or to a Telnet connection. If attached to a Telnet connection, + the console is described by internal terminal multiplexor + sim_con_tmxr and internal terminal line description sim_con_ldsc. +*/ + +/* Set console to Telnet port */ + +t_stat set_telnet (int32 flg, char *cptr) +{ +if (*cptr == 0) return SCPE_2FARG; /* too few arguments? */ +if (sim_con_tmxr.master) return SCPE_ALATT; /* already open? */ +return tmxr_open_master (&sim_con_tmxr, cptr); /* open master socket */ +} + +/* Close console Telnet port */ + +t_stat set_notelnet (int32 flag, char *cptr) +{ +if (cptr && (*cptr != 0)) return SCPE_2MARG; /* too many arguments? */ +if (sim_con_tmxr.master == 0) return SCPE_OK; /* ignore if already closed */ +return tmxr_close_master (&sim_con_tmxr); /* close master socket */ +} + +/* Show console Telnet status */ + +t_stat show_telnet (FILE *st, int32 flag, char *cptr) +{ +if (cptr && (*cptr != 0)) return SCPE_2MARG; +if (sim_con_tmxr.master == 0) + fprintf (st, "Connected to console window\n"); +else if (sim_con_ldsc.conn == 0) + fprintf (st, "Listening on port %d\n", sim_con_tmxr.port); +else { fprintf (st, "Listening on port %d, connected to socket %d\n", + sim_con_tmxr.port, sim_con_ldsc.conn); + tmxr_fconns (st, &sim_con_ldsc, -1); + tmxr_fstats (st, &sim_con_ldsc, -1); } +return SCPE_OK; +} + +/* Check connection before executing */ + +t_stat sim_check_console (int32 sec) +{ +int32 c, i; + +if (sim_con_tmxr.master == 0) return SCPE_OK; /* not Telnet? done */ +if (sim_con_ldsc.conn) { /* connected? */ + tmxr_poll_rx (&sim_con_tmxr); /* poll (check disconn) */ + if (sim_con_ldsc.conn) return SCPE_OK; } /* still connected? */ +for (i = 0; i < sec; i++) { /* loop */ + if (tmxr_poll_conn (&sim_con_tmxr) >= 0) { /* poll connect */ + sim_con_ldsc.rcve = 1; /* rcv enabled */ + if (i) { /* if delayed */ + printf ("Running\n"); /* print transition */ + fflush (stdout); } + return SCPE_OK; } /* ready to proceed */ + c = sim_os_poll_kbd (); /* check for stop char */ + if ((c == SCPE_STOP) || stop_cpu) return SCPE_STOP; + if ((i % 10) == 0) { /* Status every 10 sec */ + printf ("Waiting for console Telnet connnection\n"); + fflush (stdout); } + sim_os_sleep (1); /* wait 1 second */ + } +return SCPE_TTMO; /* timed out */ +} + +/* Poll for character */ + +t_stat sim_poll_kbd (void) +{ +int32 c; + +c = sim_os_poll_kbd (); /* get character */ +if ((c == SCPE_STOP) || (sim_con_tmxr.master == 0)) /* ^E or not Telnet? */ + return c; /* in-window */ +if (sim_con_ldsc.conn == 0) return SCPE_LOST; /* no Telnet conn? */ +tmxr_poll_rx (&sim_con_tmxr); /* poll for input */ +if (c = tmxr_getc_ln (&sim_con_ldsc)) /* any char? */ + return (c & 0377) | SCPE_KFLAG; +return SCPE_OK; +} + +/* Output character */ + +t_stat sim_putchar (int32 c) +{ +if (sim_con_tmxr.master == 0) /* not Telnet? */ + return sim_os_putchar (c); /* in-window version */ +if (sim_con_ldsc.conn == 0) return SCPE_LOST; /* no Telnet conn? */ +tmxr_putc_ln (&sim_con_ldsc, c); /* output char */ +tmxr_poll_tx (&sim_con_tmxr); /* poll xmt */ +return SCPE_OK; +} diff --git a/scp_tty.c b/scp_tty.c index 741b386a..14b3c1f3 100644 --- a/scp_tty.c +++ b/scp_tty.c @@ -23,6 +23,9 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 24-Sep-02 RMS Removed VT support, added Telnet console support + Added CGI support (from Brian Knittel) + Added MacOS sleep (from Peter Schorn) 14-Jul-02 RMS Added Windows priority control from Mark Pizzolato 20-May-02 RMS Added Windows VT support from Fischer Franz 01-Feb-02 RMS Added VAX fix from Robert Alan Byer @@ -44,12 +47,13 @@ ttrunstate - called to put terminal into run state ttcmdstate - called to return terminal to command state ttclose - called once before the simulator exits - sim_poll_kbd - poll for keyboard input - sim_putchar - output character to terminal + sim_os_poll_kbd - poll for keyboard input + sim_os_putchar - output character to terminal This module implements the following routines to support clock calibration: sim_os_msec - return elapsed time in msec + sim_os_sleep - sleep specified number of seconds Versions are included for VMS, Windows, OS/2, Macintosh, BSD UNIX, and POSIX UNIX. The POSIX UNIX version works with LINUX. @@ -75,6 +79,7 @@ extern FILE *sim_log; #include #include #include +#include #define EFN 0 unsigned int32 tty_chan = 0; typedef struct { @@ -89,7 +94,6 @@ typedef struct { unsigned int32 dev_status; } IOSB; SENSE_BUF cmd_mode = { 0 }; SENSE_BUF run_mode = { 0 }; -int32 sim_vt = -1; t_stat ttinit (void) { @@ -135,7 +139,7 @@ t_stat ttclose (void) return ttcmdstate (); } -t_stat sim_poll_kbd (void) +t_stat sim_os_poll_kbd (void) { unsigned int status, term[2]; unsigned char buf[4]; @@ -156,7 +160,7 @@ if (buf[0] == sim_int_char) return SCPE_STOP; return (buf[0] | SCPE_KFLAG); } -t_stat sim_putchar (int32 out) +t_stat sim_os_putchar (int32 out) { unsigned int status; char c; @@ -196,6 +200,11 @@ for (i = 0; i < 64; i++) { /* 64b quo */ return quo; } +int sim_os_sleep (unsigned int sec) +{ +return sleep (sec); +} + #endif /* Win32 routines */ @@ -205,9 +214,7 @@ return quo; #include #include #include -#include "sim_vt.h" static volatile int sim_win_ctlc = 0; -int32 sim_vt = 0; void win_handler (int sig) { @@ -217,22 +224,18 @@ return; t_stat ttinit (void) { -vt_init (); return SCPE_OK; } t_stat ttrunstate (void) { -sim_win_ctlc = 0; -if (sim_vt > 0) vt_run (); -if ((int) signal (SIGINT, win_handler) == -1) return SCPE_SIGERR; +if (signal (SIGINT, win_handler) == SIG_ERR) return SCPE_SIGERR; SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_BELOW_NORMAL); return SCPE_OK; } t_stat ttcmdstate (void) { -if (sim_vt > 0) vt_cmd (); SetThreadPriority (GetCurrentThread(), THREAD_PRIORITY_NORMAL); return SCPE_OK; } @@ -242,7 +245,7 @@ t_stat ttclose (void) return SCPE_OK; } -t_stat sim_poll_kbd (void) +t_stat sim_os_poll_kbd (void) { int c; @@ -250,21 +253,18 @@ if (sim_win_ctlc) { sim_win_ctlc = 0; signal (SIGINT, win_handler); return 003 | SCPE_KFLAG; } -if (sim_vt > 0) { - c = vt_read (); - if (c == -1) return SCPE_OK; } -else { if (!kbhit ()) return SCPE_OK; - c = _getch (); } +if (!kbhit ()) return SCPE_OK; +c = _getch (); if ((c & 0177) == '\b') c = 0177; if ((c & 0177) == sim_int_char) return SCPE_STOP; return c | SCPE_KFLAG; } -t_stat sim_putchar (int32 c) +t_stat sim_os_putchar (int32 c) { -if (sim_vt > 0) vt_write ((char) c); -else if (c != 0177) _putch (c); -if (sim_log) fputc (c, sim_log); +if (c != 0177) { + _putch (c); + if (sim_log) fputc (c, sim_log); } return SCPE_OK; } @@ -275,6 +275,12 @@ uint32 sim_os_msec () return GetTickCount (); } +int sim_os_sleep (unsigned int sec) +{ +Sleep (sec * 1000); +return 0; +} + #endif /* OS/2 routines, from Bruce Ray */ @@ -282,7 +288,6 @@ return GetTickCount (); #if defined (__OS2__) #define __TTYROUTINES 0 #include -int32 sim_vt = -1; t_stat ttinit (void) { @@ -304,7 +309,7 @@ t_stat ttclose (void) return SCPE_OK; } -t_stat sim_poll_kbd (void) +t_stat sim_os_poll_kbd (void) { int c; @@ -315,7 +320,7 @@ if ((c & 0177) == sim_int_char) return SCPE_STOP; return c | SCPE_KFLAG; } -t_stat sim_putchar (int32 c) +t_stat sim_os_putchar (int32 c) { if (c != 0177) { putch (c); @@ -345,11 +350,27 @@ return 0; #include #include #include +#include #include #include #include -int32 sim_vt = -1; +/* function prototypes */ +Boolean SIOUXIsAppWindow(WindowPtr window); +void SIOUXDoMenuChoice(long menuValue); +void SIOUXUpdateMenuItems(void); +void SIOUXUpdateScrollbar(void); +int ps_kbhit(void); +int ps_getch(void); +t_stat ttinit (void); +t_stat ttrunstate (void); +t_stat ttcmdstate (void); +t_stat ttclose (void); +uint32 sim_os_msec (void); +t_stat sim_os_poll_kbd (void); +t_stat sim_os_putchar (int32 c); +int sim_os_sleep (unsigned int sec); + extern char sim_name[]; extern pSIOUXWin SIOUXTextWindow; static CursHandle iBeamCursorH = NULL; /* contains the iBeamCursor */ @@ -362,21 +383,21 @@ static void updateCursor(void) { Point localMouse; GetPort(&savePort); SetPort(window); -#if !TARGET_API_MAC_CARBON - localMouse = LMGetMouseLocation(); -#else +#if TARGET_API_MAC_CARBON GetGlobalMouse(&localMouse); +#else + localMouse = LMGetMouseLocation(); #endif GlobalToLocal(&localMouse); if (PtInRect(localMouse, &(*SIOUXTextWindow->edit)->viewRect) && iBeamCursorH) { SetCursor(*iBeamCursorH); - } + } else { SetCursor(&qd.arrow); } TEIdle(SIOUXTextWindow->edit); SetPort(savePort); - } + } else { SetCursor(&qd.arrow); TEIdle(SIOUXTextWindow->edit); @@ -406,11 +427,11 @@ int ps_kbhit(void) { } return false; } - return true; + return true; } else { - return false; - } + return false; + } } int ps_getch(void) { @@ -477,7 +498,7 @@ t_stat ttclose (void) return SCPE_OK; } -t_stat sim_poll_kbd (void) +t_stat sim_os_poll_kbd (void) { int c; @@ -488,7 +509,7 @@ if ((c & 0177) == sim_int_char) return SCPE_STOP; return c | SCPE_KFLAG; } -t_stat sim_putchar (int32 c) +t_stat sim_os_putchar (int32 c) { if (c != 0177) { putchar (c); @@ -504,13 +525,18 @@ uint32 sim_os_msec (void) unsigned long long micros; UnsignedWide macMicros; unsigned long millis; - + Microseconds (&macMicros); micros = *((unsigned long long *) &macMicros); millis = micros / 1000LL; return (uint32) millis; } +int sim_os_sleep (unsigned int sec) +{ +return sleep (sec); +} + #endif /* BSD UNIX routines */ @@ -520,8 +546,8 @@ return (uint32) millis; #include #include #include +#include -int32 sim_vt = -1; struct sgttyb cmdtty,runtty; /* V6/V7 stty data */ struct tchars cmdtchars,runtchars; /* V7 editing */ struct ltchars cmdltchars,runltchars; /* 4.2 BSD editing */ @@ -575,7 +601,7 @@ t_stat ttclose (void) return ttcmdstate (); } -t_stat sim_poll_kbd (void) +t_stat sim_os_poll_kbd (void) { int status; unsigned char buf[1]; @@ -585,7 +611,7 @@ if (status != 1) return SCPE_OK; else return (buf[0] | SCPE_KFLAG); } -t_stat sim_putchar (int32 out) +t_stat sim_os_putchar (int32 out) { char c; @@ -608,6 +634,11 @@ msec = (((uint32) cur.tv_sec) * 1000) + (((uint32) cur.tv_usec) / 1000); return msec; } +int sim_os_sleep (unsigned int sec) +{ +return sleep (sec); +} + #endif /* POSIX UNIX routines, from Leendert Van Doorn */ @@ -615,12 +646,13 @@ return msec; #if !defined (__TTYROUTINES) #include #include +#include -int32 sim_vt = -1; struct termios cmdtty, runtty; t_stat ttinit (void) { +if (!isatty (fileno (stdin))) return SCPE_OK; /* skip if !tty */ if (tcgetattr (0, &cmdtty) < 0) return SCPE_TTIERR; /* get old flags */ runtty = cmdtty; runtty.c_lflag = runtty.c_lflag & ~(ECHO | ICANON); /* no echo or edit */ @@ -660,6 +692,7 @@ return SCPE_OK; t_stat ttrunstate (void) { +if (!isatty (fileno (stdin))) return SCPE_OK; /* skip if !tty */ runtty.c_cc[VINTR] = sim_int_char; /* in case changed */ if (tcsetattr (0, TCSAFLUSH, &runtty) < 0) return SCPE_TTIERR; return SCPE_OK; @@ -667,6 +700,7 @@ return SCPE_OK; t_stat ttcmdstate (void) { +if (!isatty (fileno (stdin))) return SCPE_OK; /* skip if !tty */ if (tcsetattr (0, TCSAFLUSH, &cmdtty) < 0) return SCPE_TTIERR; return SCPE_OK; } @@ -676,7 +710,7 @@ t_stat ttclose (void) return ttcmdstate (); } -t_stat sim_poll_kbd (void) +t_stat sim_os_poll_kbd (void) { int status; unsigned char buf[1]; @@ -686,7 +720,7 @@ if (status != 1) return SCPE_OK; else return (buf[0] | SCPE_KFLAG); } -t_stat sim_putchar (int32 out) +t_stat sim_os_putchar (int32 out) { char c; @@ -708,4 +742,9 @@ msec = (((uint32) cur.tv_sec) * 1000) + (((uint32) cur.tv_usec) / 1000); return msec; } +int sim_os_sleep (unsigned int sec) +{ +return sleep (sec); +} + #endif diff --git a/sim_defs.h b/sim_defs.h index be0ea3bb..58a8efb2 100644 --- a/sim_defs.h +++ b/sim_defs.h @@ -23,6 +23,13 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 08-Oct-02 RMS Increased simulator error code space + Added Telnet errors, + Added end of medium support + Added help messages to CTAB + Added flag and context fields to DEVICE + Added restore flag masks + Revised 64b definitions 02-May-02 RMS Removed log status codes 22-Apr-02 RMS Added magtape record length error 30-Dec-01 RMS Generalized timer package, added circular arrays @@ -62,6 +69,9 @@ parse_sym parse symbolic input */ +#ifndef _SIM_DEFS_H_ +#define _SIM_DEFS_H_ 0 + #include #include #include @@ -84,34 +94,40 @@ typedef int t_bool; /* boolean */ typedef unsigned int8 uint8; typedef unsigned int16 uint16; typedef unsigned int32 uint32, t_addr; /* address */ -#if defined (USE_INT64) && defined (_WIN32) -#define t_int64 __int64 /* for Windows */ -#elif defined (USE_INT64) && defined (VMS) && defined (__ALPHA) -#define t_int64 __int64 /* for AVMS */ -#elif defined (USE_INT64) && defined (__ALPHA) && defined (__unix__) -#define t_int64 long /* for DUNIX */ -#elif defined (USE_INT64) -#define t_int64 long long /* for GCC */ -#endif -#if defined (t_int64) +#if defined (USE_INT64) /* 64b */ +#if defined (WIN32) /* Windows */ +#define t_int64 __int64 +#elif defined (__ALPHA) && defined (VMS) /* Alpha VMS */ +#define t_int64 __int64 +#elif defined (__ALPHA) && defined (__unix__) /* Alpha UNIX */ +#define t_int64 long +#else /* default GCC */ +#define t_int64 long long +#endif /* end OS's */ typedef unsigned t_int64 t_uint64, t_value; /* value */ typedef t_int64 t_svalue; /* signed value */ -#else +#else /* 32b */ typedef unsigned int32 t_value; typedef int32 t_svalue; -#endif +#endif /* end else 64b */ /* System independent definitions */ -typedef int32 t_mtrlnt; /* magtape rec lnt */ -#define MTRF(x) ((x) & (1u << 31)) /* record error flg */ -#define MTRL(x) ((x) & ((1u << 31) - 1)) /* record length */ +typedef uint32 t_mtrlnt; /* magtape rec lnt */ +#define MTR_TMK 0x00000000 /* tape mark */ +#define MTR_EOM 0xFFFFFFFF /* end of medium */ +#define MTR_ERF 0x80000000 /* error flag */ +#define MTRF(x) ((x) & MTR_ERF) /* record error flg */ +#define MTRL(x) ((x) & ~MTR_ERF) /* record length */ +#define MT_SET_PNU(u) (u)->flags = (u)->flags | UNIT_PNU +#define MT_CLR_PNU(u) (u)->flags = (u)->flags & ~UNIT_PNU +#define MT_TST_PNU(u) ((u)->flags & UNIT_PNU) + #define FLIP_SIZE (1 << 16) /* flip buf size */ #if !defined (PATH_MAX) /* usually in limits */ #define PATH_MAX 512 #endif #define CBUFSIZE (128 + PATH_MAX) /* string buf size */ -#define CONS_SIZE 4096 /* console buffer */ /* Simulator status codes @@ -121,7 +137,7 @@ typedef int32 t_mtrlnt; /* magtape rec lnt */ */ #define SCPE_OK 0 /* normal return */ -#define SCPE_BASE 32 /* base for messages */ +#define SCPE_BASE 64 /* base for messages */ #define SCPE_NXM (SCPE_BASE + 0) /* nxm */ #define SCPE_UNATT (SCPE_BASE + 1) /* no file */ #define SCPE_IOERR (SCPE_BASE + 2) /* I/O error */ @@ -161,6 +177,8 @@ typedef int32 t_mtrlnt; /* magtape rec lnt */ #define SCPE_NEST (SCPE_BASE + 36) /* nested DO */ #define SCPE_IERR (SCPE_BASE + 37) /* internal error */ #define SCPE_MTRLNT (SCPE_BASE + 38) /* tape rec lnt error */ +#define SCPE_LOST (SCPE_BASE + 39) /* Telnet conn lost */ +#define SCPE_TTMO (SCPE_BASE + 40) /* Telnet conn timeout */ #define SCPE_KFLAG 01000 /* tti data flag */ /* Print value format codes */ @@ -203,8 +221,23 @@ struct device { t_stat (*boot)(); /* boot routine */ t_stat (*attach)(); /* attach routine */ t_stat (*detach)(); /* detach routine */ + void *ctxt; /* context */ + int32 flags; /* flags */ }; +/* Device flags */ + +#define DEV_V_DIS 0 /* dev enabled */ +#define DEV_V_DISABLE 1 /* dev disable-able */ +#define DEV_V_UF 12 /* user flags */ +#define DEV_V_RSV 31 /* reserved */ + +#define DEV_DIS (1 << DEV_V_DIS) +#define DEV_DISABLE (1 << DEV_V_DISABLE) + +#define DEV_UFMASK (((1u << DEV_V_RSV) - 1) & ~((1u << DEV_V_UF) - 1)) +#define DEV_RFLAGS (DEV_UFMASK|DEV_DIS) /* restored flags */ + /* Unit data structure Parts of the unit structure are device specific, that is, they are @@ -233,6 +266,9 @@ struct unit { /* Unit flags */ +#define UNIT_V_UF 12 /* device specific */ +#define UNIT_V_RSV 31 /* reserved!! */ + #define UNIT_ATTABLE 000001 /* attachable */ #define UNIT_RO 000002 /* read only */ #define UNIT_FIX 000004 /* fixed capacity */ @@ -245,9 +281,9 @@ struct unit { #define UNIT_ROABLE 001000 /* read only ok */ #define UNIT_DISABLE 002000 /* disable-able */ #define UNIT_DIS 004000 /* disabled */ -#define UNIT_V_UF 12 /* device specific */ - /* must be DIS+1!! */ -#define UNIT_V_RSV 31 /* reserved!! */ + +#define UNIT_UFMASK (((1u << UNIT_V_RSV) - 1) & ~((1u << UNIT_V_UF) - 1)) +#define UNIT_RFLAGS (UNIT_UFMASK|UNIT_DIS) /* restored flags */ /* Register data structure */ @@ -276,6 +312,7 @@ struct ctab { char *name; /* name */ t_stat (*action)(); /* action routine */ int32 arg; /* argument */ + char *help; /* help string */ }; /* Modifier table - only extended entries have disp, reg, or flags */ @@ -301,8 +338,8 @@ struct mtab { /* Search table */ struct schtab { - int logic; /* logical operator */ - int bool; /* boolean operator */ + int32 logic; /* logical operator */ + int32 bool; /* boolean operator */ t_value mask; /* mask for logical */ t_value comp; /* comparison for boolean */ }; @@ -359,6 +396,7 @@ char *get_glyph (char *iptr, char *optr, char mchar); char *get_glyph_nc (char *iptr, char *optr, char mchar); t_value get_uint (char *cptr, int radix, t_value max, t_stat *status); t_value strtotv (char *cptr, char **endptr, int radix); +t_stat fprint_val (FILE *stream, t_value val, int32 rdx, int32 wid, int32 fmt); DEVICE *find_dev_from_unit (UNIT *uptr); REG *find_reg (char *ptr, char **optr, DEVICE *dptr); int32 sim_rtc_init (int32 time); @@ -368,3 +406,5 @@ int32 sim_rtcn_calb (int32 time, int32 tmr); t_stat sim_poll_kbd (void); t_stat sim_putchar (int32 out); t_bool sim_brk_test (t_addr bloc, int32 btyp); + +#endif diff --git a/sim_ether.c b/sim_ether.c new file mode 100644 index 00000000..1005cb43 --- /dev/null +++ b/sim_ether.c @@ -0,0 +1,493 @@ +/* sim_ether.c: OS-dependent network routines + ------------------------------------------------------------------------------ + + Copyright (c) 2002, David T. Hittner + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + ------------------------------------------------------------------------------ + + Modification history: + + 31-Oct-02 DTH Added USE_NETWORK conditional + Reworked not attached test + Added OpenBSD support (from Federico Schwindt) + Added ethX detection simplification (from Megan Gentry) + Removed sections of temporary code + Added parameter validation + 23-Oct-02 DTH Beta 5 released + 22-Oct-02 DTH Added all_multicast and promiscuous support + Fixed not attached behavior + 21-Oct-02 DTH Added NetBSD support (from Jason Thorpe) + Patched buffer size to make sure entire packet is read in + Made 'ethX' check characters passed as well as length + Corrected copyright again + 16-Oct-02 DTH Beta 4 released + Corrected copyright + 09-Oct-02 DTH Beta 3 released + Added pdp11 write acceleration (from Patrick Caulfield) + 08-Oct-02 DTH Beta 2 released + Integrated with 2.10-0p4 + Added variable vector and copyrights + 04-Oct-02 DTH Added linux support (from Patrick Caulfield) + 03-Oct-02 DTH Beta version of xq/sim_ether released for SIMH 2.09-11 + 24-Sep-02 DTH Finished eth_devices, eth_getname + 18-Sep-02 DTH Callbacks implemented + 13-Sep-02 DTH Basic packet read/write written + 20-Aug-02 DTH Created Sim_Ether for O/S independant ethernet implementation + + ------------------------------------------------------------------------------ + + Work left to do: + 1) Add Asynchronous Packet Writing to WIN32 platform + 2) Addition of other host Operating Systems + 3) Addition of BPF packet filtering for efficiency + + ------------------------------------------------------------------------------ +*/ + + +#include "sim_ether.h" + +/*============================================================================*/ +/* OS-independant ethernet routines */ +/*============================================================================*/ + +void eth_mac_fmt(ETH_MAC* mac, char* buff) +{ + uint8* m = (uint8*) mac; + sprintf(buff, "%02X-%02X-%02X-%02X-%02X-%02X", m[0], m[1], m[2], m[3], m[4], m[5]); + return; +} + +void eth_packet_trace(ETH_PACK* packet, char* msg) +{ + unsigned char src[20]; + unsigned char dst[20]; + unsigned short* proto = (unsigned short*) &packet->msg[12]; + eth_mac_fmt((ETH_MAC*)&packet->msg[0], dst); + eth_mac_fmt((ETH_MAC*)&packet->msg[6], src); + printf("%s: dst: %s src: %s protocol: %d len: %d\n", + msg, dst, src, *proto, packet->len); +} + +char* eth_getname(int number, char* name) +{ +#define ETH_SUPPORTED_DEVICES 10 + ETH_LIST list[ETH_SUPPORTED_DEVICES]; + int count = eth_devices(ETH_SUPPORTED_DEVICES, list); + + if (count < number) return 0; + strcpy(name, list[number].name); + return name; +} + +void eth_zero(ETH_DEV* dev) +{ + /* set all members to NULL OR 0 */ + memset(dev, 0, sizeof(ETH_DEV)); +} + +/*============================================================================*/ +/* Non-implemented versions */ +/*============================================================================*/ + +#if !defined (WIN32) && !defined(linux) && !defined(__NetBSD__) && \ + !defined (__OpenBSD__) || !defined (USE_NETWORK) +t_stat eth_open (ETH_DEV* dev, char* name) + {return SCPE_NOFNC;} +t_stat eth_close (ETH_DEV* dev) + {return SCPE_NOFNC;} +t_stat eth_write (ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine) + {return SCPE_NOFNC;} +t_stat eth_read (ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine) + {return SCPE_NOFNC;} +t_stat eth_filter (ETH_DEV* dev, int addr_count, ETH_MAC* addresses, + ETH_BOOL all_multicast, ETH_BOOL promiscuous) + {return SCPE_NOFNC;} +int eth_devices (int max, ETH_LIST* dev) + {return 0;} +#else /* endif unimplemented */ + +/*============================================================================*/ +/* WIN32, Linux, NetBSD, and OpenBSD routines */ +/* Uses WinPCAP and libpcap packages */ +/*============================================================================*/ + +#include +#include +#ifdef WIN32 +#include +#endif /* WIN32 */ +#if defined (__NetBSD__) || defined (__OpenBSD__) +#include +#include +#endif /* __NetBSD__ || __OpenBSD__*/ +#if defined (linux) || defined(__NetBSD__) || defined (__OpenBSD__) +#include +#endif /* linux || __NetBSD__ || __OpenBSD__ */ + +t_stat eth_open(ETH_DEV* dev, char* name) +{ + const int bufsz = (BUFSIZ < ETH_MAX_PACKET) ? ETH_MAX_PACKET : BUFSIZ; + char errbuf[PCAP_ERRBUF_SIZE]; + char temp[1024]; + char* savname = name; + int i, num; + + /* initialize device */ + eth_zero(dev); + + /* translate name of type "ethX" to real device name */ + if ((strlen(name) == 4) + && (tolower(name[0]) == 'e') + && (tolower(name[1]) == 't') + && (tolower(name[2]) == 'h') + && isdigit(name[3]) + ) { + num = atoi(&name[3]); + savname = eth_getname(num, temp); + } + + /* attempt to connect device */ + dev->handle = (void*) pcap_open_live(savname, bufsz, ETH_PROMISC, -1, errbuf); + + if (!dev->handle) { /* can't open device */ +#ifdef _DEBUG + printf("pcap_open_live: %s\n", errbuf); +#endif + return SCPE_OPENERR; + } + + /* save name of device */ + dev->name = malloc(strlen(savname)+1); + strcpy(dev->name, savname); + +#if defined (__NetBSD__) || defined(__OpenBSD__) + /* tell the kernel that the header is fully-formed when it gets it. + this is required in order to fake the src address. */ + i = 1; + ioctl(pcap_fileno(dev->handle), BIOCSHDRCMPLT, &i); +#endif /* __NetBSD__ || __OpenBSD__ */ + +#if defined(linux) || defined(__NetBSD__) || defined (__OpenBSD__) + /* set file non-blocking */ + fcntl(pcap_fileno(dev->handle), F_SETFL, fcntl(pcap_fileno(dev->handle), F_GETFL, 0) | O_NONBLOCK); +#endif /* linux || __NetBSD__ || __OpenBSD__ */ + + return SCPE_OK; +} + +t_stat eth_close(ETH_DEV* dev) +{ + /* make sure device exists */ + if (!dev) return SCPE_UNATT; + + /* close the device */ + pcap_close(dev->handle); + + /* clean up the mess */ + free(dev->name); + eth_zero(dev); + + return SCPE_OK; +} + +t_stat eth_write(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine) +{ + int status = 1; /* default to failure */ + + /* make sure device exists */ + if (!dev) return SCPE_UNATT; + + /* make sure packet exists */ + if (!packet) return SCPE_ARG; + + /* make sure packet is acceptable length */ + if ((packet->len >= ETH_MIN_PACKET) && (packet->len <= ETH_MAX_PACKET)) { + /* dispatch write request (synchronous; no need to save write info to dev) */ +#ifdef _DEBUG + eth_packet_trace (packet, "writing"); +#endif + status = pcap_sendpacket((pcap_t*)dev->handle, (u_char*)packet->msg, packet->len); + } /* if packet->len */ + + /* call optional write callback function */ + if (routine) + (routine)(status); + + return SCPE_OK; +} + +void eth_callback(u_char* info, const struct pcap_pkthdr* header, const u_char* data) +{ + ETH_DEV* dev = (ETH_DEV*) info; + + /*+ temporary packet filter - should be done by BPF filter */ + int to_me = 0; + int from_me = 0; + int i; + for (i = 0; i < ETH_FILTER_MAX; i++) { + if (memcmp(data, dev->filter_address[i], 6) == 0) to_me = 1; + if (memcmp(&data[6], dev->filter_address[i], 6) == 0) from_me = 1; + } /* for */ + + /* all multicast mode? */ + if (dev->all_multicast && (data[0] & 0x01)) to_me = 1; + + /* promiscuous mode? */ + if (dev->promiscuous) to_me = 1; + + if (to_me && !from_me) { + + /*- temporary packet filter - should be done by driver filter */ + + + /* set data in passed read packet */ + dev->read_packet->len = header->len; + memcpy(dev->read_packet->msg, data, header->len); + +#ifdef _DEBUG + eth_packet_trace (dev->read_packet, "reading"); +#endif + + /* call optional read callback function */ + if (dev->read_callback) + (dev->read_callback)(0); + + + /*+ temporary packet filter - should be done by driver filter */ + } /* if use */ + /*- temporary packet filter - should be done by driver filter */ + +} + +t_stat eth_read(ETH_DEV* dev, ETH_PACK* packet, ETH_PCALLBACK routine) +{ + int status; + + /* make sure device exists */ + if (!dev) return SCPE_UNATT; + + /* make sure packet exists */ + if (!packet) return SCPE_ARG; + + /* set read packet */ + dev->read_packet = packet; + + /* set optional callback routine */ + dev->read_callback = routine; + + /* dispatch read request */ + status = pcap_dispatch((pcap_t*)dev->handle, 1, ð_callback, (u_char*)dev); + + return SCPE_OK; +} + +t_stat eth_filter(ETH_DEV* dev, int addr_count, ETH_MAC* addresses, + ETH_BOOL all_multicast, ETH_BOOL promiscuous) +{ + int i; + + /* make sure device exists */ + if (!dev) return SCPE_UNATT; + + /* should be implemented as a BPF filter, but for now.. */ + + /* filter count OK? */ + if ((addr_count < 0) || (addr_count > ETH_FILTER_MAX)) + return SCPE_ARG; + else + if (!addresses) return SCPE_ARG; + + /* clear filter array */ + memset(dev->filter_address, 0, sizeof(ETH_MAC) * ETH_FILTER_MAX); + + /* set new filter addresses */ + for (i = 0; i < addr_count; i++) + memcpy(dev->filter_address[i], addresses[i], sizeof(ETH_MAC)); + + /* set all_multicast and promiscuous flags */ + dev->all_multicast = all_multicast; + dev->promiscuous = promiscuous; + + return SCPE_OK; +} + +int eth_devices(int max, ETH_LIST* list) +{ + int i, index, len; + uint8 buffer[2048]; + uint8 buffer2[2048]; + uint8* cptr = buffer2; + int size = sizeof(buffer); + unsigned long ret; + + /* get names of devices from packet driver */ + ret = PacketGetAdapterNames(buffer, &size); + + /* device names in ascii or unicode format? */ + if ((buffer[1] == 0) && (buffer[3] == 0)) { /* unicode.. */ + int i = 0; + int cptr_inc = 2; + /* want to use buffer for scanning, so copy to buffer2 */ + memcpy (buffer2, buffer, sizeof(buffer)); + /* convert unicode to ascii (assuming every other byte is zero) */ + while (cptr < (buffer2 + sizeof(buffer2))) { + buffer[i] = *cptr; + if ((buffer[i] == 0) && (buffer[i-1] == 0)) { /* end of unicode devices */ + /* descriptions are in ascii, so change increment */ + cptr_inc = 1; + } + cptr += cptr_inc; + i++; + } + } + + /* scan ascii string and load list*/ + index = 0; + cptr = buffer; + /* extract device names and numbers */ + while (len = strlen(cptr)) { + list[index].num = index; + strcpy(list[index].name, cptr); + cptr += len + 1; + index++; + } + cptr += 2; + /* extract device descriptions */ + for (i=0; i < index; i++) { + len = strlen(cptr); + strcpy(list[i].desc, cptr); + cptr += len + 1; + } + return index; /* count of devices */ +} + +#endif /* (WIN32 || linux || __NetBSD__ || __OpenBSD__) && USE_NETWORK */ + +/*============================================================================*/ +/* linux-specific code */ +/*============================================================================*/ + +#if defined (linux) && defined (USE_NETWORK) +#include +#include +#include /* for the glibc version number */ +#if (__GLIBC__ >= 2 && __GLIBC_MINOR >= 1) || __GLIBC__ >= 3 +#include +#include /* the L2 protocols */ +#else /*__GLIBC__*/ +#include +#include +#include +#include +#include /* The L2 protocols */ +#endif /*__GLIBC__*/ + +int pcap_sendpacket(pcap_t* handle, u_char* msg, int len) +{ + return (send(pcap_fileno(handle), msg, len, 0) == len)?0:-1; +} + +int PacketGetAdapterNames(char* buffer, int* size) +{ + struct ifreq ifr; + int iindex = 1; + int sock = socket(PF_PACKET, SOCK_RAW, 0); + int ptr = 0; + + ifr.ifr_ifindex = iindex; + + while (ioctl(sock, SIOCGIFNAME, &ifr) == 0) { + /* Only use ethernet interfaces */ + ioctl(sock, SIOCGIFHWADDR, &ifr); + if (ifr.ifr_hwaddr.sa_family == ARPHRD_ETHER) { + strcpy(buffer+ptr, ifr.ifr_name); + ptr += strlen(buffer)+1; + } + ifr.ifr_ifindex = ++iindex; + } + + close(sock); + + buffer[ptr++] = '\0'; + buffer[ptr++] = '\0'; + *size = ptr; +} + +#endif /* linux && USE_NETWORK */ + +/*============================================================================*/ +/* NetBSD/OpenBSD-specific code */ +/*============================================================================*/ + +#if (defined (__NetBSD__) || defined(__OpenBSD__)) && defined (USE_NETWORK) +#include +#include +#include +#include +#include +#include + +int pcap_sendpacket(pcap_t* handle, u_char* msg, int len) +{ + return (write(pcap_fileno(handle), msg, len) == len)?0:-1; +} + +int PacketGetAdapterNames(char* buffer, int* size) +{ + const struct sockaddr_dl *sdl; + struct ifaddrs *ifap, *ifa; + char *p; + int ptr = 0; + + if (getifaddrs(&ifap) != 0) { + *size = 0; + return (0); + } + + p = NULL; + for (ifa = ifap; ifa; ifa = ifa->ifa_next) { + if (ifa->ifa_addr->sa_family != AF_LINK) + continue; + if (p && strcmp(p, ifa->ifa_name) == 0) + continue; + sdl = (const struct sockaddr_dl *) ifa->ifa_addr; + if (sdl->sdl_type != IFT_ETHER) + continue; + + strcpy(buffer+ptr, ifa->ifa_name); + ptr += strlen(ifa->ifa_name)+1; + } + + freeifaddrs(ifap); + + buffer[ptr++] = '\0'; + buffer[ptr++] = '\0'; + *size = ptr; + + return (ptr); +} + +#endif /* (__NetBSD__ || __OpenBSD__) && USE_NETWORK */ + diff --git a/sim_ether.h b/sim_ether.h new file mode 100644 index 00000000..46aa2ba2 --- /dev/null +++ b/sim_ether.h @@ -0,0 +1,105 @@ +/* sim_ether.h: OS-dependent network information + ------------------------------------------------------------------------------ + + Copyright (c) 2002, David T. Hittner + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in + all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + Except as contained in this notice, the name of the author shall not be + used in advertising or otherwise to promote the sale, use or other dealings + in this Software without prior written authorization from the author. + + ------------------------------------------------------------------------------ + + Modification history: + + 22-Oct-02 DTH Added all_multicast and promiscuous support + 21-Oct-02 DTH Corrected copyright again + 16-Oct-02 DTH Fixed copyright + 08-Oct-02 DTH Integrated with 2.10-0p4, added variable vector and copyrights + 03-Oct-02 DTH Beta version of xq/sim_ether released for SIMH 2.09-11 + 15-Aug-02 DTH Started XQ simulation + + ------------------------------------------------------------------------------ +*/ + +#ifndef _SIM_ETHER_H +#define _SIM_ETHER_H + +#include "sim_defs.h" + +/* structure declarations */ + +#define ETH_PROMISC 1 /* promiscuous mode = true */ +#define ETH_TIMEOUT -1 /* read timeout in milliseconds (immediate) */ +#define ETH_FILTER_MAX 20 /* maximum address filters */ +#define ETH_BPF_INS_MAX 500 /* maximum bpf instructions */ +#define ETH_DEV_NAME_MAX 256 /* maximum device name size */ +#define ETH_DEV_DESC_MAX 256 /* maximum device description size */ +#define ETH_MIN_PACKET 60 /* minimum ethernet packet size */ +#define ETH_MAX_PACKET 1514 /* maximum ethernet packet size */ + +struct eth_packet { + uint8 msg[1518]; + int len; +}; + +struct eth_list { + int num; + uint8 name[ETH_DEV_NAME_MAX]; + uint8 desc[ETH_DEV_DESC_MAX]; +}; + +typedef int ETH_BOOL; +typedef unsigned char ETH_MAC[6]; +typedef struct eth_packet ETH_PACK; +typedef void (*ETH_PCALLBACK)(int status); +typedef struct eth_list ETH_LIST; + +struct eth_device { + uint8* name; /* name of ethernet device */ + void* handle; /* handle of implementation-specific device */ + ETH_PCALLBACK read_callback; /* read callback function */ + ETH_PCALLBACK write_callback; /* write callback function */ + ETH_PACK* read_packet; /* read packet */ + ETH_PACK* write_packet; /* write packet */ + ETH_MAC filter_address[ETH_FILTER_MAX]; /* filtering addresses */ + ETH_BOOL promiscuous; /* promiscuous mode flag */ + ETH_BOOL all_multicast; /* receive all multicast messages */ +}; + +typedef struct eth_device ETH_DEV; + +/* prototype declarations*/ + +t_stat eth_open (ETH_DEV* dev, char* name); /* open ethernet interface */ +t_stat eth_close (ETH_DEV* dev); /* close ethernet interface */ +t_stat eth_write (ETH_DEV* dev, ETH_PACK* packet,/* write sychronous packet; */ + ETH_PCALLBACK routine); /* callback when done */ +t_stat eth_read (ETH_DEV* dev, ETH_PACK* packet,/* read single packet; */ + ETH_PCALLBACK routine); /* callback when done*/ +t_stat eth_filter (ETH_DEV* dev, int addr_count, /* set filter on incoming packets */ + ETH_MAC* addresses, + ETH_BOOL all_multicast, + ETH_BOOL promiscuous); +int eth_devices (int max, ETH_LIST* dev); /* get ethernet devices on host */ + +void eth_mac_fmt (ETH_MAC* add, char* buffer); /* format ethernet mac address */ +void eth_packet_trace (ETH_PACK* packet, char* msg); /* trace ethernet packet */ + +#endif /* _SIM_ETHER_H */ diff --git a/sim_rev.h b/sim_rev.h index d801afe5..9127c05b 100644 --- a/sim_rev.h +++ b/sim_rev.h @@ -25,42 +25,170 @@ */ #define SIM_MAJOR 2 -#define SIM_MINOR 9 -#define SIM_PATCH 11 +#define SIM_MINOR 10 +#define SIM_PATCH 0 -/* V2.9 revision history +/* V2.10 revision history patch date module(s) and fix(es) + 0 15-Nov-02 SCP and libraries + scp.c: + -- added Telnet console support + -- removed VT emulation support + -- added support for statically buffered devices + -- added HELP + -- fixed bugs in set_logon, ssh_break (found by David Hittner) + -- added VMS file optimization (from Robert Alan Byer) + -- added quiet mode, DO with parameters, GUI interface, + extensible commands (from Brian Knittel) + -- added DEVICE context and flags + -- added central device enable/disable support + -- modified SAVE/GET to save and restore flags + -- modified boot routine calling sequence + scp_tty.c: + -- removed VT emulation support + -- added sim_os_sleep, renamed sim_poll_kbd, sim_putchar + sim_tmxr.c: + -- modified for Telnet console support + -- fixed bug in binary (8b) support + sim_sock.c: modified for Telnet console support + sim_ether.c: new library for Ethernet (from David Hittner) + + all magtapes: + -- added support for end of medium + -- cleaned up BOT handling + + all DECtapes: added support for RT11 image file format + + most terminals and multiplexors: + -- added support for 7b vs 8b character processing + + PDP-1 + pdp1_cpu.c, pdp1_sys.c, pdp1_dt.c: added PDP-1 DECtape support + + PDP-8 + pdp8_cpu.c, all peripherals: + -- added variable device number support + -- added new device enabled/disable support + pdp8_rx.c: added RX28/RX02 support + + PDP-11 + pdp11_defs.h, pdp11_io.c, pdp11_sys.c, all peripherals: + -- added variable vector support + -- added new device enable/disable support + -- added autoconfiguration support + all bootstraps: modified to support variable addresses + dec_mscp.h, pdp11_tq.c: added TK50 support + pdp11_rq.c: + -- added multicontroller support + -- fixed bug in HBE error log packet + -- fixed bug in ATP processing + pdp11_ry.c: added RX211/RX02 support + pdp11_hk.c: added RK611/RK06/RK07 support + pdp11_tq.c: added TMSCP support + pdp11_xq.c: added DEQNA/DELQA support (from David Hittner) + pdp11_pclk.c: added KW11P support + pdp11_ts.c: + -- fixed bug in CTL decoding + -- fixed bug in extended status XS0_MOT + pdp11_stddev.c: removed paper tape to its own module + + PDP-18b + pdp18b_cpu.c, all peripherals: + -- added variable device number support + -- added new device enabled/disabled support + + VAX + dec_dz.h: fixed bug in number of boards calculation + vax_moddefs.h, vax_io.c, vax_sys.c, all peripherals: + -- added variable vector support + -- added new device enable/disable support + -- added autoconfiguration support + vax_sys.c: + -- generalized examine/deposit + -- added TMSCP, multiple RQDX3, DEQNA/DELQA support + vax_stddev.c: removed paper tape, now uses PDP-11 version + vax_sysdev.c: + -- allowed NVR to be attached to file + -- removed unused variables (found by David Hittner) + + PDP-10 + pdp10_defs.h, pdp10_ksio.c, all peripherals: + -- added variable vector support + -- added new device enable/disable support + pdp10_defs.h, pdp10_ksio.c: added support for standard PDP-11 + peripherals, added RX211 support + pdp10_pt.c: rewritten to reference common implementation + + Nova, Eclipse: + nova_cpu.c, eclipse_cpu.c, all peripherals: + -- added new device enable/disable support + + HP2100 + hp2100_cpu: + -- fixed bugs in the EAU, 21MX, DMS, and IOP instructions + -- fixed bugs in the memory protect and DMS functions + -- created new options to enable/disable EAU, MPR, DMS + -- added new device enable/disable support + hp2100_fp.c: + -- recoded to conform to 21MX microcode algorithms + hp2100_stddev.c: + -- fixed bugs in TTY reset, OTA, time base generator + -- revised BOOT support to conform to RBL loader + -- added clock calibration + hp2100_dp.c: + -- changed default to 13210A + -- added BOOT support + hp2100_dq.c: + -- finished incomplete functions, fixed head switching + -- added BOOT support + hp2100_ms.c: + -- fixed bugs found by diagnostics + -- added 13183 support + -- added BOOT support + hp2100_mt.c: + -- fixed bugs found by diagnostics + -- disabled by default + hp2100_lpt.c: implemented 12845A controller + hp2100_lps.c: + -- renamed 12653A controller + -- added diagnostic mode for MPR, DCPC diagnostics + -- disabled by default + + IBM 1620: first release + +/* V2.9 revision history + 11 20-Jul-02 i1401_mt.c: on read, end of record stores group mark - without word mark (found by Van Snyder) + without word mark (found by Van Snyder) i1401_dp.c: reworked address generation and checking vax_cpu.c: added infinite loop detection and halt to - boot ROM option (from Mark Pizzolato) + boot ROM option (from Mark Pizzolato) vax_fpa.c: changed function names to prevent conflict - with C math library + with C math library pdp11_cpu.c: fixed bug in MMR0 update logic (from - John Dundas) + John Dundas) pdp18b_stddev.c: added "ASCII mode" for reader and - punch (from Hans Pufal) + punch (from Hans Pufal) gri_*.c: added GRI-909 simulator scp.c: added DO echo, DO exit (from Brian Knittel) scp_tty.c: added Windows priority hacking (from - Mark Pizzolato) + Mark Pizzolato) 10 15-Jun-02 scp.c: fixed error checking on calls to fxread/fxwrite - (found by Norm Lastovic) + (found by Norm Lastovic) scp_tty.c, sim_vt.h, sim_vt.c: added VTxxx emulation - support for Windows (from Fischer Franz) + support for Windows (from Fischer Franz) sim_sock.c: added OS/2 support (from Holger Veit) @@ -97,10 +225,10 @@ patch date module(s) and fix(es) vax_cpu1.c: fixed exception flows to clear trap request 7 30-Apr-02 scp.c: fixed bug in clock calibration when (real) clock - jumps forward due too far (found by Jonathan Engdahl) + jumps forward due too far (found by Jonathan Engdahl) pdp11_cpu.c: fixed bugs, added features (from John Dundas - and Wolfgang Helbig) + and Wolfgang Helbig) -- added HTRAP and BPOK to maintenance register -- added trap on kernel HALT if MAINT set -- fixed red zone trap, clear odd address and nxm traps @@ -122,7 +250,7 @@ patch date module(s) and fix(es) -- fixed SHOW ADDRESS command all magtape routines: added test for badly formed - record length (suggested by Jonathan Engdahl) + record length (suggested by Jonathan Engdahl) 6 18-Apr-02 vax_cpu.c: fixed CASEL condition codes @@ -143,17 +271,17 @@ patch date module(s) and fix(es) pdp11_rq.c: adjusted delays for M+ timing bugs hp2100_cpu.c, pdp10_cpu.c, pdp11_cpu.c: tweaked abort - code for ANSI setjmp/longjmp compliance + code for ANSI setjmp/longjmp compliance hp2100_cpu.c, hp2100_fp.c, hp2100_stddev.c, hp2100_sys.c: - revised to allocate memory dynamically + revised to allocate memory dynamically 2 01-Mar-02 pdp11_cpu.c: -- fixed bugs in CPU registers -- fixed double operand evaluation order for M+ pdp11_rq.c: added delays to initialization for - RSX11M+ prior to V4.5 + RSX11M+ prior to V4.5 1 20-Feb-02 scp.c: fixed bug in clock calibration when (real) time runs backwards @@ -163,7 +291,7 @@ patch date module(s) and fix(es) pdp11_ts.c: fixed bug in message header logic pdp18b_defs.h, pdp18b_dt.c, pdp18b_sys.c: added - PDP-7 DECtape support + PDP-7 DECtape support hp2100_cpu.c: -- added floating point and DMS @@ -206,7 +334,7 @@ patch date module(s) and fix(es) pdp11_rp.c: fixed bug in 18b mode boot pdp11 bootable I/O devices: fixed register setup at boot - exit (found by Doug Carman) + exit (found by Doug Carman) hp2100_cpu.c: -- fixed DMA register tables (found by Bill McDermith) @@ -216,13 +344,13 @@ patch date module(s) and fix(es) hp2100_mt.c: fixed bug on write of last character hp2100_dq,dr,ms,mux.c: added new disk, magtape, and terminal - multiplexor controllers + multiplexor controllers i1401_cd.c, i1401_mt.c: new zero footprint bootstraps - (from Van Snyder) + (from Van Snyder) i1401_sys.c: fixed symbolic display of H, NOP with no trailing - word mark (found by Van Snyder) + word mark (found by Van Snyder) most CPUs: -- replaced OLDPC with PC queue @@ -257,10 +385,10 @@ patch date module(s) and fix(es) 0 30-Nov-01 Reorganized simh source and documentation tree scp: Added DO command, universal registers, extended - SET/SHOW logic + SET/SHOW logic pdp11: overhauled PDP-11 for DMA map support, shared - sources with VAX, dynamic buffer allocation + sources with VAX, dynamic buffer allocation 18b pdp: overhauled interrupt structure @@ -273,56 +401,56 @@ patch date module(s) and fix(es) patch date module(s) and fix(es) 15 23-Oct-01 pdp11_rp.c, pdp10_rp.c, pdp10_tu.c: fixed bugs - error interrupt handling + error interrupt handling pdp10_defs.h, pdp10_ksio.c, pdp10_fe.c, pdp10_fe.c, pdp10_rp.c, pdp10_tu.c: reworked I/O page interface - to use symbolic base addresses and lengths + to use symbolic base addresses and lengths 14 20-Oct-01 dec_dz.h, sim_tmxr_h, sim_tmxr.c: fixed bug in Telnet - state handling (found by Thord Nilson), removed - tmxr_getchar, added tmxr_rqln and tmxr_tqln + state handling (found by Thord Nilson), removed + tmxr_getchar, added tmxr_rqln and tmxr_tqln 13 18-Oct-01 pdp11_tm.c: added stub diagnostic register clock - for RSTS/E (found by Thord Nilson) + for RSTS/E (found by Thord Nilson) 12 15-Oct-01 pdp11_defs.h, pdp11_cpu.c, pdp11_tc.c, pdp11_ts.c, - pdp11_rp.c: added operations logging + pdp11_rp.c: added operations logging 11 8-Oct-01 scp.c: added sim_rev.h include and version print pdp11_cpu.c: fixed bug in interrupt acknowledge, - multiple outstanding interrupts caused the lowest - rather than the highest to be acknowledged + multiple outstanding interrupts caused the lowest + rather than the highest to be acknowledged 10 7-Oct-01 pdp11_stddev.c: added monitor bits (CSR<7>) for full - KW11L compatibility, needed for RSTS/E autoconfiguration + KW11L compatibility, needed for RSTS/E autoconfiguration 9 6-Oct-01 pdp11_rp.c, pdp10_rp.c, pdp10_tu.c: rewrote interrupt - logic from RH11/RH70 schematics, to mimic hardware quirks + logic from RH11/RH70 schematics, to mimic hardware quirks dec_dz.c: fixed bug in carrier detect logic, carrier - detect was being cleared on next modem poll + detect was being cleared on next modem poll 8 4-Oct-01 pdp11_rp.c, pdp10_rp.c, pdp10_tu.c: undid edit of - 28-Sep-01; real problem was level-sensitive nature of - CS1_SC, but CS1_SC can only trigger an interrupt if - DONE is set + 28-Sep-01; real problem was level-sensitive nature of + CS1_SC, but CS1_SC can only trigger an interrupt if + DONE is set 7 2-Oct-01 pdp11_rp.c, pdp10_rp.c: CS1_SC is evaluated as a level- - sensitive, rather than an edge-sensitive, input to - interrupt request + sensitive, rather than an edge-sensitive, input to + interrupt request 6 30-Sep-01 pdp11_rp.c, pdp10_rp.c: separated out CS1<5:0> to per- - drive registers + drive registers pdp10_tu.c: based on above, cleaned up handling of - non-existent formatters, fixed non-data transfer commands - clearing DONE + non-existent formatters, fixed non-data transfer + commands clearing DONE 5 28-Sep-01 pdp11_rp.c, pdp10_rp.c, pdp10_tu.c: controller should - interrupt if ATA or SC sets when IE is set, was - interrupting only if DON = 1 as well + interrupt if ATA or SC sets when IE is set, was + interrupting only if DON = 1 as well 4 27-Sep-01 pdp11_ts.c: -- NXM errors should return TC4 or TC5; were returning TC3 @@ -332,7 +460,7 @@ patch date module(s) and fix(es) pdp11_tc.c: stop, stop all do cause an interrupt dec_dz.h: scanner should find a ready output line, even - if there are no connections; needed for RSTS/E autoconfigure + if there are no connections; needed for RSTS/E autoconfigure scp.c: -- added routine sim_qcount for 1130 @@ -343,7 +471,7 @@ patch date module(s) and fix(es) 3 20-Sep-01 pdp11_ts.c: boot code binary was incorrect 2 19-Sep-01 pdp18b_cpu.c: EAE should interpret initial count of 00 - as 100 + as 100 scp.c: modified Macintosh support diff --git a/sim_sock.c b/sim_sock.c index cb08324a..fc91f942 100644 --- a/sim_sock.c +++ b/sim_sock.c @@ -23,6 +23,8 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 08-Oct-02 RMS Revised for .NET compatibility + 22-Aug-02 RMS Changed calling sequence for sim_accept_conn 22-May-02 RMS Added OS2 EMX support from Holger Veit 06-Feb-02 RMS Added VMS support from Robert Alan Byer 16-Sep-01 RMS Added Macintosh support from Peter Schorn @@ -53,7 +55,7 @@ SOCKET sim_master_sock (int32 port) return INVALID_SOCKET; } -SOCKET sim_accept_conn (SOCKET master, UNIT *uptr) +SOCKET sim_accept_conn (SOCKET master, uint32 *ipaddr) { return INVALID_SOCKET; } @@ -88,12 +90,12 @@ SOCKET newsock; struct sockaddr_in name; int32 sta; -#if defined (_WIN32) +#if defined (WIN32) WORD wVersionRequested; WSADATA wsaData; -wVersionRequested = MAKEWORD(1, 1); +wVersionRequested = MAKEWORD (1, 1); -sta = WSAStartup(wVersionRequested, &wsaData); /* start Winsock */ +sta = WSAStartup (wVersionRequested, &wsaData); /* start Winsock */ if (sta != 0) { printf ("Winsock: startup error %d\n", sta); return sta; } @@ -127,12 +129,12 @@ if (sta == SOCKET_ERROR) { /* listen error? */ return newsock; /* got it! */ } -SOCKET sim_accept_conn (SOCKET master, UNIT *uptr, uint32 *ipaddr) +SOCKET sim_accept_conn (SOCKET master, uint32 *ipaddr) { int32 sta; #if defined (macintosh) socklen_t size; -#elif defined (__EMX__) +#elif defined (WIN32) || defined (__EMX__) int size; #else size_t size; @@ -140,8 +142,7 @@ size_t size; SOCKET newsock; struct sockaddr_in clientname; -if ((uptr -> flags & UNIT_ATT) == 0) /* not attached? */ - return INVALID_SOCKET; +if (master == 0) return INVALID_SOCKET; /* not attached? */ size = sizeof (clientname); newsock = accept (master, (struct sockaddr *) &clientname, &size); if (newsock == INVALID_SOCKET) { /* error? */ @@ -178,7 +179,7 @@ return send (sock, msg, nbytes, 0); void sim_close_sock (SOCKET sock, t_bool master) { -#if defined (_WIN32) +#if defined (WIN32) closesocket (sock); if (master) WSACleanup (); #else @@ -187,21 +188,23 @@ close (sock); return; } -#if defined (_WIN32) +#if defined (WIN32) /* Windows */ SOCKET sim_setnonblock (SOCKET sock) { unsigned long non_block = 1; return ioctlsocket (sock, FIONBIO, &non_block); /* set nonblocking */ } -#elif defined (VMS) + +#elif defined (VMS) /* VMS */ SOCKET sim_setnonblock (SOCKET sock) { int non_block = 1; return ioctl (sock, FIONBIO, &non_block); /* set nonblocking */ } -#else + +#else /* Mac, Unix, OS/2 */ int32 sim_setnonblock (SOCKET sock) { int32 fl, sta; @@ -210,12 +213,13 @@ fl = fcntl (sock, F_GETFL,0); /* get flags */ if (fl == -1) return SOCKET_ERROR; sta = fcntl (sock, F_SETFL, fl | O_NONBLOCK); /* set nonblock */ if (sta == -1) return SOCKET_ERROR; -#if !defined (macintosh) && !defined (__EMX__) +#if !defined (macintosh) && !defined (__EMX__) /* Unix only */ sta = fcntl (sock, F_SETOWN, getpid()); /* set ownership */ if (sta == -1) return SOCKET_ERROR; #endif return 0; } -#endif /* endif !Win32 */ -#endif /* endif Win32/UNIX/Mac/VMS */ +#endif /* endif !Win32 && !VMS */ + +#endif /* end else !implemented */ diff --git a/sim_sock.h b/sim_sock.h index 94218b74..1e8d74d0 100644 --- a/sim_sock.h +++ b/sim_sock.h @@ -1,4 +1,4 @@ -/* scp_sock.h: OS-dependent socket routines header file +/* sim_sock.h: OS-dependent socket routines header file Copyright (c) 2001, Robert M Supnik @@ -23,16 +23,26 @@ be used in advertising or otherwise to promote the sale, use or other dealings in this Software without prior written authorization from Robert M Supnik. + 08-Oct-02 RMS Revised for .NET compatibility + 20-Aug-02 RMS Changed calling sequence for sim_accept_conn 30-Apr-02 RMS Changed VMS stropts include to ioctl 06-Feb-02 RMS Added VMS support from Robert Alan Byer 16-Sep-01 RMS Added Macintosh support from Peter Schorn */ +#ifndef _SIM_SOCK_H_ +#define _SIM_SOCK_H_ 0 + #if defined (WIN32) /* Windows */ #undef INT_PTR /* hack, hack */ #include -#elif !defined (__OS2__) /* other supported */ -#define WSAGetLastError() errno + +#elif !defined (__OS2__) || defined (__EMX__) /* VMS, Mac, Unix, OS/2 EMX */ +#define WSAGetLastError() errno /* Windows macros */ +#define SOCKET int32 +#define WSAEWOULDBLOCK EWOULDBLOCK +#define INVALID_SOCKET -1 +#define SOCKET_ERROR -1 #include /* for fcntl, getpid */ #include /* for sockets */ #include @@ -40,28 +50,16 @@ #include /* for sockaddr_in */ #include #endif + #if defined (VMS) /* VMS unique */ #include /* for ioctl */ #endif -/* Code uses Windows-specific defs that are undefined for most systems */ - -#if !defined (SOCKET) -#define SOCKET int32 -#endif -#if !defined (WSAEWOULDBLOCK) -#define WSAEWOULDBLOCK EWOULDBLOCK -#endif -#if !defined (INVALID_SOCKET) -#define INVALID_SOCKET -1 -#endif -#if !defined (SOCKET_ERROR) -#define SOCKET_ERROR -1 -#endif - SOCKET sim_master_sock (int32 port); -SOCKET sim_accept_conn (SOCKET master, UNIT *uptr, uint32 *ipaddr); +SOCKET sim_accept_conn (SOCKET master, uint32 *ipaddr); int32 sim_read_sock (SOCKET sock, char *buf, int32 nbytes); int32 sim_write_sock (SOCKET sock, char *msg, int32 nbytes); void sim_close_sock (SOCKET sock, t_bool master); SOCKET sim_setnonblock (SOCKET sock); + +#endif diff --git a/sim_tmxr.c b/sim_tmxr.c index 771a67c9..d5148030 100644 --- a/sim_tmxr.c +++ b/sim_tmxr.c @@ -26,6 +26,8 @@ Based on the original DZ11 simulator by Thord Nilson, as updated by Arthur Krewat. + 31-Oct-02 RMS Fixed bug in 8b (binary) support + 22-Aug-02 RMS Added tmxr_open_master, tmxr_close_master 30-Dec-01 RMS Added tmxr_fstats, tmxr_dscln, renamed tmxr_fstatus 03-Dec-01 RMS Changed tmxr_fconns for extended SET/SHOW 20-Oct-01 RMS Fixed bugs in read logic (found by Thord Nilson). @@ -73,7 +75,7 @@ extern uint32 sim_os_msec (void); line number activated, -1 if none */ -int32 tmxr_poll_conn (TMXR *mp, UNIT *uptr) +int32 tmxr_poll_conn (TMXR *mp) { SOCKET newsock; TMLN *lp; @@ -86,26 +88,26 @@ static char mantra[] = { TN_IAC, TN_WILL, TN_BIN, TN_IAC, TN_DO, TN_BIN }; -newsock = sim_accept_conn (mp -> master, uptr, &ipaddr);/* poll connect */ +newsock = sim_accept_conn (mp->master, &ipaddr); /* poll connect */ if (newsock != INVALID_SOCKET) { /* got a live one? */ - for (i = 0; i < mp -> lines; i++) { /* find avail line */ - lp = mp -> ldsc[i]; /* ptr to ln desc */ - if (lp -> conn == 0) break; } /* available? */ - if (i >= mp -> lines) { /* all busy? */ - tmxr_msg (newsock, "All connections busy... please try later\r\n"); + for (i = 0; i < mp->lines; i++) { /* find avail line */ + lp = mp->ldsc[i]; /* ptr to ln desc */ + if (lp->conn == 0) break; } /* available? */ + if (i >= mp->lines) { /* all busy? */ + tmxr_msg (newsock, "All connections busy\r\n"); sim_close_sock (newsock, 0); } - else { lp = mp -> ldsc[i]; /* get line desc */ - lp -> conn = newsock; /* record connection */ - lp -> ipad = ipaddr; /* ip address */ - lp -> cnms = sim_os_msec (); /* time of conn */ - lp -> rxbpr = lp -> rxbpi = 0; /* init buf pointers */ - lp -> txbpr = lp -> txbpi = 0; - lp -> rxcnt = lp -> txcnt = 0; /* init counters */ - lp -> tsta = 0; /* init telnet state */ - lp -> xmte = 1; /* enable transmit */ - lp -> dstb = 0; /* default bin mode */ + else { lp = mp->ldsc[i]; /* get line desc */ + lp->conn = newsock; /* record connection */ + lp->ipad = ipaddr; /* ip address */ + lp->cnms = sim_os_msec (); /* time of conn */ + lp->rxbpr = lp->rxbpi = 0; /* init buf pointers */ + lp->txbpr = lp->txbpi = 0; + lp->rxcnt = lp->txcnt = 0; /* init counters */ + lp->tsta = 0; /* init telnet state */ + lp->xmte = 1; /* enable transmit */ + lp->dstb = 0; /* default bin mode */ sim_write_sock (newsock, mantra, 15); - tmxr_msg (newsock, "\n\r\nWelcome to the "); + tmxr_msg (newsock, "\n\r\nConnected to the "); tmxr_msg (newsock, sim_name); tmxr_msg (newsock, " simulator\r\n\n"); return i; } @@ -117,12 +119,12 @@ return -1; void tmxr_reset_ln (TMLN *lp) { -sim_close_sock (lp -> conn, 0); /* reset conn */ -lp -> conn = lp -> tsta = 0; /* reset state */ -lp -> rxbpr = lp -> rxbpi = 0; -lp -> txbpr = lp -> txbpi = 0; -lp -> xmte = 1; -lp -> dstb = 0; +sim_close_sock (lp->conn, 0); /* reset conn */ +lp->conn = lp->tsta = 0; /* reset state */ +lp->rxbpr = lp->rxbpi = 0; +lp->txbpr = lp->txbpi = 0; +lp->xmte = 1; +lp->dstb = 0; return; } @@ -139,15 +141,15 @@ int32 tmxr_getc_ln (TMLN *lp) int32 j, val = 0; uint32 tmp; -if (lp -> conn && lp -> rcve) { /* conn & enb? */ - j = lp -> rxbpi - lp -> rxbpr; /* # input chrs */ +if (lp->conn && lp->rcve) { /* conn & enb? */ + j = lp->rxbpi - lp->rxbpr; /* # input chrs */ if (j) { /* any? */ - tmp = lp -> rxb[lp -> rxbpr]; /* get char */ - lp -> rxbpr = lp -> rxbpr + 1; /* adv pointer */ + tmp = lp->rxb[lp->rxbpr]; /* get char */ + lp->rxbpr = lp->rxbpr + 1; /* adv pointer */ val = TMXR_VALID | (tmp & 0377); } /* valid + chr */ } /* end if conn */ -if (lp -> rxbpi == lp -> rxbpr) /* empty? zero ptrs */ - lp -> rxbpi = lp -> rxbpr = 0; +if (lp->rxbpi == lp->rxbpr) /* empty? zero ptrs */ + lp->rxbpi = lp->rxbpr = 0; return val; } @@ -163,62 +165,65 @@ void tmxr_poll_rx (TMXR *mp) int32 i, nbytes, j; TMLN *lp; -for (i = 0; i < mp -> lines; i++) { /* loop thru lines */ - lp = mp -> ldsc[i]; /* get line desc */ - if (!lp -> conn || !lp -> rcve) continue; /* skip if !conn */ +for (i = 0; i < mp->lines; i++) { /* loop thru lines */ + lp = mp->ldsc[i]; /* get line desc */ + if (!lp->conn || !lp->rcve) continue; /* skip if !conn */ nbytes = 0; - if (lp -> rxbpi == 0) /* need input? */ - nbytes = sim_read_sock (lp -> conn, /* yes, read */ - &(lp -> rxb[lp -> rxbpi]), /* leave spc for */ + if (lp->rxbpi == 0) /* need input? */ + nbytes = sim_read_sock (lp->conn, /* yes, read */ + &(lp->rxb[lp->rxbpi]), /* leave spc for */ TMXR_MAXBUF - TMXR_GUARD); /* Telnet cruft */ - else if (lp -> tsta) /* in Telnet seq? */ - nbytes = sim_read_sock (lp -> conn, /* yes, read to end */ - &(lp -> rxb[lp -> rxbpi]), - TMXR_MAXBUF - lp -> rxbpi); + else if (lp->tsta) /* in Telnet seq? */ + nbytes = sim_read_sock (lp->conn, /* yes, read to end */ + &(lp->rxb[lp->rxbpi]), + TMXR_MAXBUF - lp->rxbpi); if (nbytes < 0) tmxr_reset_ln (lp); /* closed? reset ln */ else if (nbytes > 0) { /* if data rcvd */ - j = lp -> rxbpi; /* start of data */ - lp -> rxbpi = lp -> rxbpi + nbytes; /* adv pointers */ - lp -> rxcnt = lp -> rxcnt + nbytes; + j = lp->rxbpi; /* start of data */ + lp->rxbpi = lp->rxbpi + nbytes; /* adv pointers */ + lp->rxcnt = lp->rxcnt + nbytes; /* Examine new data, remove TELNET cruft before making input available */ - for (; j < lp -> rxbpi; ) { /* loop thru char */ - char tmp = lp -> rxb[j]; /* get char */ - switch (lp -> tsta) { /* case tlnt state */ + for (; j < lp->rxbpi; ) { /* loop thru char */ + char tmp = lp->rxb[j]; /* get char */ + switch (lp->tsta) { /* case tlnt state */ case TNS_NORM: /* normal */ if (tmp == TN_IAC) { /* IAC? */ - lp -> tsta = TNS_IAC; /* change state */ + lp->tsta = TNS_IAC; /* change state */ tmxr_rmvrc (lp, j); /* remove char */ break; } - if ((tmp == TN_CR) && lp -> dstb) /* CR, no bin */ - lp -> tsta = TNS_SKIP; /* skip next */ + if ((tmp == TN_CR) && lp->dstb) /* CR, no bin */ + lp->tsta = TNS_SKIP; /* skip next */ j = j + 1; /* advance j */ break; case TNS_IAC: /* IAC prev */ + if ((tmp == TN_IAC) & !lp->dstb) { /* IAC + IAC, bin? */ + lp->tsta = TNS_NORM; /* treat as normal */ + break; } /* keep IAC */ if (tmp == TN_WILL) /* IAC + WILL? */ - lp -> tsta = TNS_WILL; + lp->tsta = TNS_WILL; else if (tmp == TN_WONT) /* IAC + WONT? */ - lp -> tsta = TNS_WONT; - else lp -> tsta = TNS_SKIP; /* IAC + other */ + lp->tsta = TNS_WONT; + else lp->tsta = TNS_SKIP; /* IAC + other */ tmxr_rmvrc (lp, j); /* remove char */ break; case TNS_WILL: case TNS_WONT: /* IAC+WILL/WONT prev */ if (tmp == TN_BIN) { /* BIN? */ - if (lp -> tsta == TNS_WILL) lp -> dstb = 0; - else lp -> dstb = 1; } + if (lp->tsta == TNS_WILL) lp->dstb = 0; + else lp->dstb = 1; } case TNS_SKIP: default: /* skip char */ - lp -> tsta = TNS_NORM; /* next normal */ + lp->tsta = TNS_NORM; /* next normal */ tmxr_rmvrc (lp, j); /* remove char */ break; } /* end case state */ } /* end for char */ } /* end else nbytes */ } /* end for lines */ -for (i = 0; i < mp -> lines; i++) { /* loop thru lines */ - lp = mp -> ldsc[i]; /* get line desc */ - if (lp -> rxbpi == lp -> rxbpr) /* if buf empty, */ - lp -> rxbpi = lp -> rxbpr = 0; /* reset pointers */ +for (i = 0; i < mp->lines; i++) { /* loop thru lines */ + lp = mp->ldsc[i]; /* get line desc */ + if (lp->rxbpi == lp->rxbpr) /* if buf empty, */ + lp->rxbpi = lp->rxbpr = 0; /* reset pointers */ } /* end for */ return; } @@ -227,15 +232,15 @@ return; int32 tmxr_rqln (TMLN *lp) { -return (lp -> rxbpi - lp -> rxbpr); +return (lp->rxbpi - lp->rxbpr); } /* Remove character p from line l input buffer */ void tmxr_rmvrc (TMLN *lp, int32 p) { -for ( ; p < lp -> rxbpi; p++) lp -> rxb[p] = lp -> rxb[p + 1]; -lp -> rxbpi = lp -> rxbpi - 1; +for ( ; p < lp->rxbpi; p++) lp->rxb[p] = lp->rxb[p + 1]; +lp->rxbpi = lp->rxbpi - 1; return; } @@ -250,13 +255,13 @@ return; void tmxr_putc_ln (TMLN *lp, int32 chr) { -if (lp -> conn == 0) return; /* no conn? done */ -if (lp -> txbpi < TMXR_MAXBUF) { /* room for char? */ - lp -> txb[lp -> txbpi] = (char) chr; /* buffer char */ - lp -> txbpi = lp -> txbpi + 1; /* adv pointer */ - if (lp -> txbpi > (TMXR_MAXBUF - TMXR_GUARD)) /* near full? */ - lp -> xmte = 0; } /* disable line */ -else lp -> xmte = 0; /* disable line */ +if (lp->conn == 0) return; /* no conn? done */ +if (lp->txbpi < TMXR_MAXBUF) { /* room for char? */ + lp->txb[lp->txbpi] = (char) chr; /* buffer char */ + lp->txbpi = lp->txbpi + 1; /* adv pointer */ + if (lp->txbpi > (TMXR_MAXBUF - TMXR_GUARD)) /* near full? */ + lp->xmte = 0; } /* disable line */ +else lp->xmte = 0; /* disable line */ return; } @@ -273,21 +278,21 @@ void tmxr_poll_tx (TMXR *mp) int32 i, nbytes, sbytes; TMLN *lp; -for (i = 0; i < mp -> lines; i++) { /* loop thru lines */ - lp = mp -> ldsc[i]; /* get line desc */ - if (lp -> conn == 0) continue; /* skip if !conn */ - nbytes = lp -> txbpi - lp -> txbpr; /* avail bytes */ +for (i = 0; i < mp->lines; i++) { /* loop thru lines */ + lp = mp->ldsc[i]; /* get line desc */ + if (lp->conn == 0) continue; /* skip if !conn */ + nbytes = lp->txbpi - lp->txbpr; /* avail bytes */ if (nbytes) { /* >0? write */ - sbytes = sim_write_sock (lp -> conn, - &(lp -> txb[lp -> txbpr]), nbytes); + sbytes = sim_write_sock (lp->conn, + &(lp->txb[lp->txbpr]), nbytes); if (sbytes != SOCKET_ERROR) { /* update ptrs */ - lp -> txbpr = lp -> txbpr + sbytes; - lp -> txcnt = lp -> txcnt + sbytes; + lp->txbpr = lp->txbpr + sbytes; + lp->txcnt = lp->txcnt + sbytes; nbytes = nbytes - sbytes; } } if (nbytes == 0) { /* buf empty? */ - lp -> xmte = 1; /* enable this line */ - lp -> txbpr = lp -> txbpi = 0; } + lp->xmte = 1; /* enable this line */ + lp->txbpr = lp->txbpi = 0; } } /* end for */ return; } @@ -296,68 +301,86 @@ return; int32 tmxr_tqln (TMLN *lp) { -return (lp -> txbpi - lp -> txbpr); +return (lp->txbpi - lp->txbpr); } -/* Attach */ +/* Open master socket */ -t_stat tmxr_attach (TMXR *mp, UNIT *uptr, char *cptr) +t_stat tmxr_open_master (TMXR *mp, char *cptr) { -char* tptr; int32 i, port; SOCKET sock; TMLN *lp; t_stat r; -extern int32 sim_switches; port = (int32) get_uint (cptr, 10, 65535, &r); /* get port */ if ((r != SCPE_OK) || (port == 0)) return SCPE_ARG; -tptr = malloc (strlen (cptr) + 1); /* get string buf */ -if (tptr == NULL) return SCPE_MEM; /* no more mem? */ - sock = sim_master_sock (port); /* make master socket */ -if (sock == INVALID_SOCKET) { /* open error */ - free (tptr); /* release buf */ - return SCPE_OPENERR; } -printf ("Listening on socket %d\n", sock); -if (sim_log) fprintf (sim_log, "Listening on socket %d\n", sock); -mp -> master = sock; /* save master socket */ -strcpy (tptr, cptr); /* copy port */ -uptr -> filename = tptr; /* save */ -uptr -> flags = uptr -> flags | UNIT_ATT; /* no more errors */ - -for (i = 0; i < mp -> lines; i++) { /* initialize lines */ - lp = mp -> ldsc[i]; - lp -> conn = lp -> tsta = 0; - lp -> rxbpi = lp -> rxbpr = 0; - lp -> txbpi = lp -> txbpr = 0; - lp -> rxcnt = lp -> txcnt = 0; - lp -> xmte = 1; - lp -> dstb = 0; } +if (sock == INVALID_SOCKET) return SCPE_OPENERR; /* open error */ +printf ("Listening on port %d (socket %d)\n", port, sock); +if (sim_log) fprintf (sim_log, + "Listening on port %d (socket %d)\n", port, sock); +mp->port = port; /* save port */ +mp->master = sock; /* save master socket */ +for (i = 0; i < mp->lines; i++) { /* initialize lines */ + lp = mp->ldsc[i]; + lp->conn = lp->tsta = 0; + lp->rxbpi = lp->rxbpr = 0; + lp->txbpi = lp->txbpr = 0; + lp->rxcnt = lp->txcnt = 0; + lp->xmte = 1; + lp->dstb = 0; } return SCPE_OK; } -/* Detach */ +/* Attach unit to master socket */ -t_stat tmxr_detach (TMXR *mp, UNIT *uptr) +t_stat tmxr_attach (TMXR *mp, UNIT *uptr, char *cptr) +{ +char* tptr; +t_stat r; + +tptr = malloc (strlen (cptr) + 1); /* get string buf */ +if (tptr == NULL) return SCPE_MEM; /* no more mem? */ +r = tmxr_open_master (mp, cptr); /* open master socket */ +if (r != SCPE_OK) { /* error? */ + free (tptr); /* release buf */ + return SCPE_OPENERR; } +strcpy (tptr, cptr); /* copy port */ +uptr->filename = tptr; /* save */ +uptr->flags = uptr->flags | UNIT_ATT; /* no more errors */ +return SCPE_OK; +} + +/* Close master socket */ + +t_stat tmxr_close_master (TMXR *mp) { int32 i; TMLN *lp; -if ((uptr -> flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */ -for (i = 0; i < mp -> lines; i++) { /* loop thru conn */ - lp = mp -> ldsc[i]; - if (lp -> conn) { - tmxr_msg (lp -> conn, "\r\n"); - tmxr_msg (lp -> conn, sim_name); - tmxr_msg (lp -> conn, " simulator shutting down\r\n\n"); +for (i = 0; i < mp->lines; i++) { /* loop thru conn */ + lp = mp->ldsc[i]; + if (lp->conn) { + tmxr_msg (lp->conn, "\r\nDisconnected from the "); + tmxr_msg (lp->conn, sim_name); + tmxr_msg (lp->conn, " simulator\r\n\n"); tmxr_reset_ln (lp); } /* end if conn */ } /* end for */ -sim_close_sock (mp -> master, 1); /* close master socket */ -mp -> master = 0; -free (uptr -> filename); /* free port string */ -uptr -> filename = NULL; -uptr -> flags = uptr -> flags & ~UNIT_ATT; /* not attached */ +sim_close_sock (mp->master, 1); /* close master socket */ +mp->master = 0; +return SCPE_OK; +} + +/* Detach unit from master socket */ + +t_stat tmxr_detach (TMXR *mp, UNIT *uptr) +{ +if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */ +tmxr_close_master (mp); /* close master socket */ +free (uptr->filename); /* free port string */ +uptr->filename = NULL; +uptr->flags = uptr->flags & ~UNIT_ATT; /* not attached */ return SCPE_OK; } @@ -386,15 +409,15 @@ return; void tmxr_fconns (FILE *st, TMLN *lp, int32 ln) { if (ln >= 0) fprintf (st, "line %d: ", ln); -if (lp -> conn) { +if (lp->conn) { int32 o1, o2, o3, o4, hr, mn, sc; uint32 ctime; - o1 = (lp -> ipad >> 24) & 0xFF; - o2 = (lp -> ipad >> 16) & 0xFF; - o3 = (lp -> ipad >> 8) & 0xFF; - o4 = (lp -> ipad) & 0xFF; - ctime = (sim_os_msec () - lp -> cnms) / 1000; + o1 = (lp->ipad >> 24) & 0xFF; + o2 = (lp->ipad >> 16) & 0xFF; + o3 = (lp->ipad >> 8) & 0xFF; + o4 = (lp->ipad) & 0xFF; + ctime = (sim_os_msec () - lp->cnms) / 1000; hr = ctime / 3600; mn = (ctime / 60) % 60; sc = ctime % 3600; @@ -412,13 +435,13 @@ static const char *enab = "on"; static const char *dsab = "off"; if (ln >= 0) fprintf (st, "line %d: ", ln); -if (lp -> conn) { +if (lp->conn) { fprintf (st, "input (%s) queued/total = %d/%d, ", - (lp -> rcve? enab: dsab), - lp -> rxbpi - lp -> rxbpr, lp -> rxcnt); + (lp->rcve? enab: dsab), + lp->rxbpi - lp->rxbpr, lp->rxcnt); fprintf (st, "output (%s) queued/total = %d/%d\n", - (lp -> xmte? enab: dsab), - lp -> txbpi - lp -> txbpr, lp -> txcnt); } + (lp->xmte? enab: dsab), + lp->txbpi - lp->txbpr, lp->txcnt); } else fprintf (st, "line disconnected\n"); return; } @@ -434,12 +457,12 @@ t_stat r; if ((mp == NULL) || (val && (cptr == NULL))) return SCPE_ARG; if (cptr) { - ln = (int32) get_uint (cptr, 10, mp -> lines - 1, &r); + ln = (int32) get_uint (cptr, 10, mp->lines - 1, &r); if (r != SCPE_OK) return SCPE_ARG; } else ln = 0; -lp = mp -> ldsc[ln]; -if (lp -> conn) { - tmxr_msg (lp -> conn, "\r\nOperator disconnected line\r\n\n"); +lp = mp->ldsc[ln]; +if (lp->conn) { + tmxr_msg (lp->conn, "\r\nOperator disconnected line\r\n\n"); tmxr_reset_ln (lp); } return SCPE_OK; } diff --git a/sim_tmxr.h b/sim_tmxr.h index 20bd6185..4eb9bb8b 100644 --- a/sim_tmxr.h +++ b/sim_tmxr.h @@ -26,11 +26,15 @@ Based on the original DZ11 simulator by Thord Nilson, as updated by Arthur Krewat. + 20-Aug-02 RMS Added tmxr_open_master, tmxr_close_master, tmxr.port 30-Dec-01 RMS Renamed tmxr_fstatus, added tmxr_fstats 20-Oct-01 RMS Removed tmxr_getchar, formalized buffer guard, added tmxr_rqln, tmxr_tqln */ +#ifndef _SIM_TMXR_H_ +#define _SIM_TMXR_H_ 0 + #define TMXR_V_VALID 15 #define TMXR_VALID (1 << TMXR_V_VALID) #define TMXR_MAXBUF 128 /* buffer size */ @@ -59,18 +63,21 @@ typedef struct tmln TMLN; struct tmxr { int32 lines; /* # lines */ + int32 port; /* listening port */ SOCKET master; /* master socket */ TMLN *ldsc[TMXR_MAXLIN]; /* line descriptors */ }; typedef struct tmxr TMXR; -int32 tmxr_poll_conn (TMXR *mp, UNIT *uptr); +int32 tmxr_poll_conn (TMXR *mp); void tmxr_reset_ln (TMLN *lp); int32 tmxr_getc_ln (TMLN *lp); void tmxr_poll_rx (TMXR *mp); void tmxr_putc_ln (TMLN *lp, int32 chr); void tmxr_poll_tx (TMXR *mp); +t_stat tmxr_open_master (TMXR *mp, char *cptr); +t_stat tmxr_close_master (TMXR *mp); t_stat tmxr_attach (TMXR *mp, UNIT *uptr, char *cptr); t_stat tmxr_detach (TMXR *mp, UNIT *uptr); t_stat tmxr_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); @@ -82,3 +89,5 @@ t_stat tmxr_dscln (UNIT *uptr, int32 val, char *cptr, void *desc); int32 tmxr_rqln (TMLN *lp); int32 tmxr_tqln (TMLN *lp); +#endif + diff --git a/sim_vt.c b/sim_vt.c deleted file mode 100644 index 4534e995..00000000 --- a/sim_vt.c +++ /dev/null @@ -1,508 +0,0 @@ -/* sim_vt.c: VT2xx compatible terminal emulator - - Copyright (c) 2002, Robert M Supnik - Written by Fischer Franz and used with his gracious permission - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not - be used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - 13-Apr-02 FF Added Hold-Screen on Pause-Key - Corrected scrolling - Added additional Esc-sequences Erase-Insert-Delete-Char - Corrected decoding - (ESC [ H, ESC [ x H, ESC [ ; y H , ESC [ x ; y H - are all valid sequences) - 15-Mar-02 FF Original version Fischer Franz -*/ - -#include -#include "sim_defs.h" - -#define HOLD 0x1 -#define INSERT 0x2 -#define SCRMAX 64 - -static HANDLE kbdHdl; -static HANDLE scrHdl; -static INPUT_RECORD inBuf; -static DWORD act, mode; -static CONSOLE_SCREEN_BUFFER_INFO screen; -static COORD margin; -static WORD attrib; - -static char *kbd_ptr; -static char *scr_ptr; -static char scr_buf[SCRMAX]; -static uint8 scr_mode; - -struct keyEntry { - uint8 asciiCode; - uint8 scanCode; - char *escSeq; -}; -typedef struct keyEntry KEY; - -typedef void (*scr_func) (); -struct scrEntry { - char last; - scr_func interpret; -}; -typedef struct scrEntry SCR; - -static KEY keyTab[] = { - {0 ,0x3B,"[31~"}, /* F1, mapped to F17 on VT320 */ - {0 ,0x3C,"[32~"}, /* F2, mapped to F18 on VT320 */ - {0 ,0x3D,"[33~"}, /* F3, mapped to F19 on VT320 */ - {0 ,0x3E,"[34~"}, /* F4, mapped to F20 on VT320 */ - {0 ,0x3F,"[17~"}, /* F5, mapped to F6 on VT320 */ - {0 ,0x40,"[18~"}, /* F6, mapped to F7 on VT320 */ - {0 ,0x41,"[19~"}, /* F7, mapped to F8 on VT320 */ - {0 ,0x42,"[20~"}, /* F8, mapped to F9 on VT320 */ - {0 ,0x43,"[23~"}, /* F9, mapped to F11 on VT320 */ - {0 ,0x44,"[24~"}, /* F10,mapped to F12 on VT320 */ - {0 ,0x57,"[25~"}, /* F11,mapped to F13 on VT320 */ - {0 ,0x58,"[26~"}, /* F12,mapped to F14 on VT320 */ - - {0xE0,0x52,"[2~"}, /* INS,mapped to INSERT on VT320 */ - {0xE0,0x53,"[3~"}, /* DEL,mapped to REMOVE in VT320 */ - {0xE0,0x47,"[1~"}, /* HOME, mapped to FIND on VT320 */ - {0xE0,0x4F,"[4~"}, /* END,mapped to SELECT on VT320 */ - {0xE0,0x49,"[5~"}, /* PAGE UP, mapped to PREV on VT320 */ - {0xE0,0x51,"[6~"}, /* PAGE DOWN, mapped to NEXT on VT320 */ - - {0xE0,0x48,"[A"},/* UP */ - {0xE0,0x50,"[B"},/* DOWN */ - {0xE0,0x4D,"[C"},/* RIGHT */ - {0xE0,0x4B,"[D"},/* LEFT */ - - {0xE0,0x45,"OP"},/* NUM, mapped to PF1 on VT320 */ - {0xE0,0x35,"OQ"},/* / , mapped to PF2 on VT320 */ - {'*' ,0x37,"OR"},/* * , mapped to PF3 on VT320 */ - {'-', 0x4A,"OS"},/* / , mapped to PF4 on VT320 */ - - /* The following Keys send Application Keypad-Mode sequences */ - {0 ,0x52,"Op"}, /* KP0 */ - {'0',0x52,"Op"}, /* KP0 */ - {0 ,0x4F,"Oq"}, /* KP1 */ - {'1',0x4F,"Oq"}, /* KP1 */ - {0 ,0x50,"Or"}, /* KP2 */ - {'2',0x50,"Or"}, /* KP2 */ - {0 ,0x51,"Os"}, /* KP3 */ - {'3',0x51,"Os"}, /* KP3 */ - {0 ,0x4B,"Ot"}, /* KP4 */ - {'4',0x4B,"Ot"}, /* KP4 */ - {0 ,0x4C,"Ou"}, /* KP5 */ - {'5',0x4C,"Ou"}, /* KP5 */ - {0 ,0x4D,"Ov"}, /* KP6 */ - {'6',0x4D,"Ov"}, /* KP6 */ - {0 ,0x47,"Ow"}, /* KP7 */ - {'7',0x47,"Ow"}, /* KP7 */ - {0 ,0x48,"Ox"}, /* KP8 */ - {'8',0x48,"Ox"}, /* KP8 */ - {0 ,0x49,"Oy"}, /* KP9 */ - {'9',0x49,"Oy"}, /* KP9 */ - {0 ,0x53,"On"}, /* PERIOD */ - {'.',0x53,"On"}, /* PERIOD */ - {0xE0,0x1C,"OM"}, /* ENTER */ - {'+',0x4E,"Ol"}, /* COMMA */ - {0} /* End of List */ -}; - -int vt_read() { - DWORD cnt = 0; - uint8 sCode, aCode; - KEY *key; - - if (kbd_ptr && *kbd_ptr) { - return (*kbd_ptr++ & 0177); - } - - GetNumberOfConsoleInputEvents(kbdHdl, &cnt); - if (!cnt) return -1; - - ReadConsoleInput(kbdHdl, &inBuf, 1, &act); - - if (inBuf.EventType != KEY_EVENT) return -1; - if (!inBuf.Event.KeyEvent.bKeyDown) return -1; - if (inBuf.Event.KeyEvent.dwControlKeyState & ENHANCED_KEY) inBuf.Event.KeyEvent.uChar.AsciiChar = (uint8)0xE0; - - sCode = (uint8)inBuf.Event.KeyEvent.wVirtualScanCode; - aCode = inBuf.Event.KeyEvent.uChar.AsciiChar; - - if (scr_mode & HOLD) { - scr_mode &= ~HOLD; - return 0x11; - } - if (sCode < 0x37 && aCode != 0 && aCode != 0xE0) return aCode; - if (sCode == 0x45 && aCode == 0) { - scr_mode |= HOLD; - return 0x13; - } - - for (key = keyTab; key->scanCode; key++) { - if (key->asciiCode != aCode || key->scanCode != sCode) continue; - kbd_ptr = key->escSeq; - return 0x1b; - } - - if (aCode != 0 && aCode != 0xE0) return aCode; - return -1; -} - -static void scr_nop () {}; - -static void scr_scroll_up(int from, int to, int lines) { - SMALL_RECT src; - COORD dst; - CHAR_INFO fill; - - dst.X=0; dst.Y=from; - src.Top=from+lines; src.Left=0; src.Bottom=to; src.Right=screen.dwSize.X; - fill.Char.AsciiChar = ' '; - fill.Attributes = attrib; - ScrollConsoleScreenBuffer(scrHdl,&src,0,dst,&fill); -}; -static void scr_scroll_down(int from, int to, int lines) { - SMALL_RECT src; - COORD dst; - CHAR_INFO fill; - - dst.X=0; dst.Y=from+lines; - src.Top=from; src.Left=0; src.Bottom=to-lines; src.Right=screen.dwSize.X; - fill.Char.AsciiChar = ' '; - fill.Attributes = attrib; - ScrollConsoleScreenBuffer(scrHdl,&src,0,dst,&fill); -}; -static void scr_insert_char() { - int nr = atoi(&scr_buf[1]); - SMALL_RECT src; - COORD dst; - CHAR_INFO fill; - - if (!nr) nr = 1; - src.Top=screen.dwCursorPosition.Y; src.Left=screen.dwCursorPosition.X-nr; - src.Bottom=src.Top; src.Right=screen.dwSize.X; - dst.X=src.Left+nr; dst.Y=src.Top; - fill.Char.AsciiChar = ' '; - fill.Attributes = attrib; - ScrollConsoleScreenBuffer(scrHdl,&src,0,dst,&fill); -}; -static void scr_pos_up() { - int nr = atoi(&scr_buf[1]); - if (!nr) nr = 1; - if (screen.dwCursorPosition.Y > nr) screen.dwCursorPosition.Y -= nr; - else screen.dwCursorPosition.Y = 0; - SetConsoleCursorPosition(scrHdl,screen.dwCursorPosition); -}; -static void scr_pos_down() { - int nr = atoi(&scr_buf[1]); - if (!nr) nr = 1; - screen.dwCursorPosition.Y += nr; - if (screen.dwCursorPosition.Y >= margin.Y) screen.dwCursorPosition.Y = margin.Y-1; - SetConsoleCursorPosition(scrHdl,screen.dwCursorPosition); -}; -static void scr_pos_right() { - int nr = atoi(&scr_buf[1]); - if (!nr) nr = 1; - screen.dwCursorPosition.X += nr; - if (screen.dwCursorPosition.X >= screen.dwSize.X) screen.dwCursorPosition.X = screen.dwSize.X-1; - SetConsoleCursorPosition(scrHdl,screen.dwCursorPosition); -}; -static void scr_pos_left() { - int nr = atoi(&scr_buf[1]); - if (!nr) nr = 1; - if (screen.dwCursorPosition.X > nr) screen.dwCursorPosition.X -= nr; - else screen.dwCursorPosition.X = 0; - SetConsoleCursorPosition(scrHdl,screen.dwCursorPosition); -}; -static void scr_pos_cursor() { - int x, y; - if (scr_buf[0] == 'H') return; - x = 1; y = 1; - if (!sscanf(scr_buf,"[%d;%d",&y,&x)) sscanf(scr_buf,"[;%d",&x); - screen.dwCursorPosition.X = x-1; - screen.dwCursorPosition.Y = y-1; - SetConsoleCursorPosition(scrHdl,screen.dwCursorPosition); -}; -static void scr_prev_line() { - scr_scroll_down(margin.X,margin.Y,1); -}; -static void scr_next_line() { - scr_scroll_up(margin.X,margin.Y,1); -}; -static void scr_erase_display() { - int nr = atoi(&scr_buf[1]); - COORD pos; - int len; - - if (nr == 0) { - pos = screen.dwCursorPosition; - len = (screen.dwSize.Y-screen.dwCursorPosition.Y-1)*screen.dwSize.X + - (screen.dwSize.X-screen.dwCursorPosition.X); - } else if (nr == 1) { - pos.X = 0; pos.Y = 0; - len = (screen.dwCursorPosition.Y-1)*screen.dwSize.X + screen.dwCursorPosition.X; - } else if (nr == 2) { - pos.X = 0; pos.Y = 0; - len = screen.dwSize.X*screen.dwSize.Y; - } else { - return; - } - - FillConsoleOutputAttribute(scrHdl,screen.wAttributes,len,pos,&act); - FillConsoleOutputCharacter(scrHdl,' ',len,pos,&act); -}; -static void scr_erase_line() { - int nr = atoi(&scr_buf[1]); - COORD pos; - int len; - - if (nr == 0) { - pos = screen.dwCursorPosition; - len = screen.dwSize.X-screen.dwCursorPosition.X; - } else if (nr == 1) { - pos.X = 0; pos.Y = screen.dwCursorPosition.Y; - len = screen.dwCursorPosition.X; - } else if (nr == 2) { - pos.X = 0; pos.Y = screen.dwCursorPosition.Y; - len = screen.dwSize.X; - } else { - return; - } - - FillConsoleOutputAttribute(scrHdl,screen.wAttributes,len,pos,&act); - FillConsoleOutputCharacter(scrHdl,' ',len,pos,&act); -}; -static void scr_delete_line() { - if (scr_buf[0] == 'M') { - scr_prev_line(); - } else { - int nr = atoi(&scr_buf[1]); - if (!nr) nr = 1; - scr_scroll_up(screen.dwCursorPosition.Y,margin.Y,nr); - } -}; -static void scr_insert_line() { - int nr = atoi(&scr_buf[1]); - if (!nr) nr = 1; - scr_scroll_down(screen.dwCursorPosition.Y,margin.Y,nr); -}; -static void scr_delete_char() { - int nr = atoi(&scr_buf[1]); - SMALL_RECT src; - COORD dst; - CHAR_INFO fill; - - if (!nr) nr = 1; - dst = screen.dwCursorPosition; - src.Top=dst.Y; src.Left=dst.X+nr; src.Bottom=dst.Y; src.Right=screen.dwSize.X; - fill.Char.AsciiChar = ' '; - fill.Attributes = attrib; - ScrollConsoleScreenBuffer(scrHdl,&src,0,dst,&fill); -}; -static void scr_erase_char() { - int nr = atoi(&scr_buf[1]); - COORD pos; - - if (!nr) nr = 1; - pos = screen.dwCursorPosition; - - FillConsoleOutputAttribute(scrHdl,screen.wAttributes,nr,pos,&act); - FillConsoleOutputCharacter(scrHdl,' ',nr,pos,&act); -}; -static void scr_request() { - kbd_ptr = "\033[?6c"; -}; -static void scr_set() { - int nr = atoi(&scr_buf[1]); - if (nr == 4) scr_mode |= INSERT; -}; -static void scr_reset() { - int nr = atoi(&scr_buf[1]); - if (nr == 4) scr_mode &= ~INSERT; -}; -static void scr_attrib() { - int nr = atoi(&scr_buf[1]); - switch (nr) { - case 0: - attrib = screen.wAttributes; - break; - case 1: - attrib = screen.wAttributes | 0x80; - break; - case 7: - attrib = ((screen.wAttributes & 0xf) << 4) | ((screen.wAttributes & 0x7) >> 4); - break; - } -}; -static void scr_report() {}; -static void scr_margin() { - int top, bot; - top = 1; bot = screen.dwSize.Y+1; - if (!sscanf(scr_buf,"[%d;%d",&top,&bot)) sscanf(scr_buf,"[;%d",&bot); - margin.X = top-1; - if (bot != 24) margin.Y = bot-1; - else margin.Y = screen.dwSize.Y; - - screen.dwCursorPosition.X = 0; - screen.dwCursorPosition.Y = 0; - SetConsoleCursorPosition(scrHdl,screen.dwCursorPosition); -}; - -static SCR scrTab[] = { - {'@', scr_insert_char}, - {'A', scr_pos_up}, - {'B', scr_pos_down}, - {'C', scr_pos_right}, - {'D', scr_pos_left}, - {'E', scr_next_line}, - {'H', scr_pos_cursor}, - {'I', scr_prev_line}, - {'J', scr_erase_display}, - {'K', scr_erase_line}, - {'L', scr_insert_line}, - {'M', scr_delete_line}, - {'P', scr_delete_char}, - {'X', scr_erase_char}, - {'Z', scr_request}, - - {'c', scr_request},/* Device attribute request */ - {'f', scr_pos_cursor}, - {'h', scr_set}, /* Set mode */ - {'l', scr_reset}, /* Reset mode */ - {'m', scr_attrib}, /* Display attributes */ - {'n', scr_report}, /* Device report */ - {'r', scr_margin}, - {'=', scr_nop}, /* Set applikation keypad mode */ - {'>', scr_nop}, /* Set numeric keypad mode */ - {0} -}; - -static void scr_char(char c) { - - if (c == 0x8) { /* BS */ - if (screen.dwCursorPosition.X > 0) screen.dwCursorPosition.X--; - } else if (c == 0xa) { /* LF */ - if (screen.dwCursorPosition.Y < margin.Y-1) screen.dwCursorPosition.Y++; - else scr_scroll_up(margin.X,margin.Y,1); - } else if (c == 0xd) { /* CR */ - screen.dwCursorPosition.X = 0; - } else if (c == 0x9) { /* Tab */ - screen.dwCursorPosition.X = (screen.dwCursorPosition.X + 8) & ~7; - if (screen.dwCursorPosition.X >= screen.dwSize.X) screen.dwCursorPosition.X = screen.dwSize.X-1; - } else if (c < ' ') { - return; - } else if (!(scr_mode & INSERT)) { - WriteConsoleOutputCharacter(scrHdl,&c,1,screen.dwCursorPosition,&act); - WriteConsoleOutputAttribute(scrHdl,&attrib,1,screen.dwCursorPosition,&act); - - if (screen.dwCursorPosition.X < screen.dwSize.X) screen.dwCursorPosition.X++; - else if (screen.dwCursorPosition.Y < margin.Y-1) { - screen.dwCursorPosition.X = 0; - screen.dwCursorPosition.Y++; - } else { - scr_scroll_up(margin.X,margin.Y,1); - screen.dwCursorPosition.X = 0; - } - } else { - SMALL_RECT src; - COORD dst; - CHAR_INFO fill; - - src.Top=screen.dwCursorPosition.Y; src.Left=screen.dwCursorPosition.X; - src.Bottom=src.Top; src.Right=screen.dwSize.X; - dst.X=src.Left+1; dst.Y=src.Top; - fill.Char.AsciiChar = ' '; - fill.Attributes = attrib; - ScrollConsoleScreenBuffer(scrHdl,&src,0,dst,&fill); - WriteConsoleOutputCharacter(scrHdl,&c,1,screen.dwCursorPosition,&act); - - if (screen.dwCursorPosition.X < screen.dwSize.X) screen.dwCursorPosition.X++; - else if (screen.dwCursorPosition.Y < margin.Y-1) { - screen.dwCursorPosition.X = 0; - screen.dwCursorPosition.Y++; - } else { - scr_scroll_up(margin.X,margin.Y,1); - screen.dwCursorPosition.X = 0; - } - } - - SetConsoleCursorPosition(scrHdl,screen.dwCursorPosition); -} - -static void check_esc (char c) { - SCR *scr; - - *scr_ptr = c; - if ((scr_ptr - scr_buf) < SCRMAX) scr_ptr++; - for (scr = scrTab; scr->last; scr++) { - if (scr->last != c) continue; - - *scr_ptr = 0; - scr->interpret(); - scr_ptr = 0; - return; - } -} - -void vt_write(char c) { - - if (c != 0x1b && !scr_ptr) { - scr_char(c); - } else if (c == 0x1b) { - scr_ptr = scr_buf; - } else if (c < ' ') { - scr_ptr = 0; - scr_char(c); - } else if (scr_ptr == scr_buf) { - check_esc(c); - } else if (c >= '@') { - check_esc(c); - scr_ptr = 0; - } else { - *scr_ptr = c; - if ((scr_ptr - scr_buf) < SCRMAX) scr_ptr++; - } -} - -void vt_init() { - kbdHdl = GetStdHandle(STD_INPUT_HANDLE); - scrHdl = GetStdHandle(STD_OUTPUT_HANDLE); - - GetConsoleMode(kbdHdl, &mode); - GetConsoleScreenBufferInfo(scrHdl, &screen); - margin.X = 0; margin.Y = screen.dwSize.Y; - attrib = screen.wAttributes; - scr_mode = 0; -} - -void vt_cmd() { - SetConsoleMode(kbdHdl, mode); -} - -void vt_run() { - kbd_ptr = 0; - SetConsoleMode(kbdHdl, 0); - GetConsoleScreenBufferInfo(scrHdl, &screen); - margin.X = 0; margin.Y = screen.dwSize.Y; - attrib = screen.wAttributes; - scr_mode = 0; -} \ No newline at end of file diff --git a/simh_doc.txt b/simh_doc.txt index 18c4aa55..5b904eca 100644 --- a/simh_doc.txt +++ b/simh_doc.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik -Subj: Simulator Usage, V2.11 -Date: 15-Jul-2002 +Subj: Simulator Usage, V2.10 +Date: 15-Nov-2002 COPYRIGHT NOTICE @@ -45,28 +45,22 @@ documented in separate, machine-specific memoranda. 1. Compiling And Running A Simulator The simulators have been tested on VAX VMS, Alpha VMS, Alpha UNIX, -Intel FreeBSD, Intel LINUX, Windows 9x/Me/NT/2000 (Visual C++ and -MINGW gcc), Macintosh 9 and X (CodeWarrior), and OS/2. Porting to -other environments will require changes to the operating system -dependent code in scp_tty.c and scp_sock.c. +NetBSD, FreeBSD, OpenBSD, Linux, Solaris, Windows 9x/Me/NT/2000, MacOS +9 and X, and OS/2. Porting to other environments will require changes +to the operating system dependent code in scp_tty.c, scp_sock.c, and +sim_ether.c. -The simulator sources are provided in a zip archive. The sources -originate on a Windows system and have cr-lf at the end of every line. -For use on UNIX or Mac, the sources must be converted to UNIX and MAC -text conventions. This can usually be done with the UNZIP utility -(e.g., unzip -a on UNIX). - -The simulator sources are organized hierarchically. Source files for -the simulator libraries are in the top level directory; source files -for each simulator are in individual subdirectories. Note that the -include files in the top level directory are referenced from the -subdirectories, without path identifiers. Your build tool needs -to search the top level directory for include files not found in the -simulator-specific directory, or you will have to copy all files -from the subdirectories into the master directory. File manifests +The simulator sources are provided in a zip archive and are organized +hierarchically. Source files for the simulator libraries are in the +top level directory; source files for each simulator are in individual +subdirectories. Note that the include files in the top level directory +are referenced from the subdirectories, without path identifiers. Your +build tool needs to search the top level directory for include files not +found in the simulator-specific directory, or you will have to copy all +files from the subdirectories into the master directory. File manifests for each simulator are given in that simulator's documentation. -Compilation notes: +The simulators recognize or require a few compile-time #defines: - The 18b simulators require that the model name be defined as part of the compilation command line (i.e., PDP4 for the PDP-4, PDP7 @@ -79,6 +73,40 @@ Compilation notes: default is GNU C (long long). If your compiler uses a different convention, you will have to modify sim_defs.h. +- The PDP-11 and VAX simulators optionally support Ethernet. To + include Ethernet emulation, USE_NETWORK must be defined as part + of the compilation command line. At present, Ethernet support is + available only on Windows, Linux, NetBSD, and OpenBSD. + +To start the simulator, simply type its name. (On version of VMS +prior to 6.2, the simulators must then be defined as foreign commands +in order to be be started by name.) The simulator recognizes one +switch, -Q; if specified, certain informational messages are suppressed. +The simulator interprets the arguments on the command line, if any, +as the file name and arguments for a DO command. If a startup file +is specified, it should contain a series of non-interactive simulator +commands, one per line. These command can be used to set up standard +parameters, for example, disk sizes: + + % pdp10 { {arg,arg,...}}(cr) + +The simulator types out its name and version, executes the commands +in the startup file, if any, and then prompts for input with + + sim> + +1.1 Compiling Under UNIX/Linux + +The sources originate on a Windows system and have cr-lf at the end of +every line. For use on UNIX or Mac, the sources must be converted to +UNIX text conventions. This can be done with the UNIX UNZIP utility +(unzip -a). + +The supplied makefile will compile the simulators for UNIX systems +which support the POSIX TERMIOS. The VAX and PDP-11 will be compiled +without Ethernet support; use makefile_ether to compile with Ethernet +support. Notes for hand compilation: + - The default UNIX terminal handling model is the POSIX TERMIOS interface, which is supported by Linux, Mac OS/X, and Alpha UNIX. If your UNIX only supports the BSD terminal interface, BSDTTY @@ -88,18 +116,8 @@ Compilation notes: math library. If your UNIX does not link the math library automatically, you must add -lm to the compilation command line. -- Simulators supporting multiple terminals require a sockets library. - Under UNIX, this library is linked in automatically. Under Visual - C++, wsock32.lib must be added to the library search list. Under - OS/2, socket support requires the EMX compiler. - Examples: -- PDP-8 under VMS: - - $ cc pdp8_*.c,scp.c,scp_tty.c,sim_*.c ! PDP-8 - $ link/exec=pdp8 pdp8_*.obj,scp.obj,scp_tty.obj,sim_*.obj - - PDP-11 under TERMIOS UNIX: % cc pdp11_*.c scp*.c sim_*.c -lm -o pdp11 @@ -112,35 +130,99 @@ Examples: % cc -DUSE_INT64 -DBSDTTY pdp10_*.c scp*.c sim_*.c -lm -o pdp10 -A batch file for compiling under the Windows MINGW environment, and -a Make file for UNIX, are included in the distribution. +1.2 Compiling Under Windows -To start the simulator, simply type its name. (On version of VMS -prior to 6.2, the simulators must then be defined as foreign commands -in order to be be started by name.) The simulator takes one optional -argument, a startup command file. If specified, this file should -contain a series of non-interactive simulator commands, one per line. -These command can be used to set up standard parameters, for example, -disk sizes: +1.2.1 Compiling PDP-11 and VAX with Ethernet Support - % pdp10 (cr) or +The Windows-specific Ethernet code uses the WinPCAP 3.0 package. +This package for windows simulates the libpcap package that is freely +available for Unix systems. Note that WinPCAP DOES NOT SUPPORT dual +CPU environments. -The simulator types out its name and version, executes the commands -in the startup file, if any, and then prompts for input with +WinPCAP must be installed prior to building the PDP-11 and VAX +simulators with Ethernet support. - sim> +- Download V3.0 from http://winpcap.polito.it. +- Install the package as directed. +- Copy the required .h files (bittypes.h, devioctl.h, ip6_misc.h, + packet32.h, pcap.h, pcap-stdinc.h) from the WinPCAP 3.0 developer's + kit to the top level simulation directory. +- Get the required .lib files (packet.lib, wpcap.lib) from the WinPCAP + 3.0 developer's kit. If you're using Borland C++, use COFF2OMF to + convert the .lib files into a format that can be used by the compiler. + Then move the libraries to the top level simulation directory. +- Add -DUSE_NETWORK to the compilation command lines for the PDP-11 + and VAX. + +1.2.2 Compiling Under MinGW + +MinGW (Minimum GCC for Windows) is a free C compiler available from +http://www.mingw.org. The distribution includes a batch file +(build_mingw.bat) that will build all the simulators from source. +By default, the PDP-11 and VAX are built without Ethernet support. To +enable Ethernet support, install WinPCAP as described in the previous +section, and then use the alternative batch file (build_mingw_ether.bat). + +1.2.3 Compiling Under Visual C++ + +Each simulator must be organized as a separate Visual C++ project. +Starting from an empty console application, + +- Add all the files from the simulator file manifest to the project. +- Open the Project->Settings dialog box. +- On the C/C++ tab, Category: General, add any required preprocessor + definitions (for example, USE_INT64). +- On the C/C++ tab, Category: Preprocessor, add the top level + simulation directory to the Additional Include Directories. For + the VAX and PDP-10, you must also add the PDP-11 directory. +- On the Link tab, add wsock32.lib at the end of the list of + Object/Module Libraries. +- If you are building the PDP-11 and VAX with Ethernet support, you + must also add the WinPCAP libraries (packet.lib, wpcap.lib) to the + list of Object/Module libraries. + +If you are using Visual C++ .NET, you must turn off /Wp (warn about +potential 64b incompatibilities); otherwise, the compilations will +generate a lot of spurious conversion warnings. + +1.2.4 Compiling Under Borland C++ + +The Borland C++ compiler generates lots of spurious warnings about +missing function prototypes and conversions. All of these warnings +can be safely ignored. + +1.3 Compiling Under OpenVMS + +Compiling on OpenVMS requires DEC C. The simulators that require +64b (PDP-10 and VAX) will not compile on OpenVMS/VAX. The SIMH +distribution includes an MMS command file descrip.mms that will +build all the simulators from source. An example of hand compilation: + +- PDP-8 under VMS: + + $ cc scp*.c,sim_*.c,[.pdp8]pdp8*.c + $ link/exec=pdp8 scp*.obj,sim_*.obj,[.pdp8]pdp8*.obj + +1.4 Compiling Under MacOS + +The simulators have been tested on both MacOS 9 (with Codewarrior) +and MacOS/X (with Apple's tools). + +1.5 Compiling Under OS/2 + +Socket support requires the EMX compiler. 2. Simulator Conventions -A simulator consists of a series of devices, the first of which is always -the CPU. A device consists of named registers and one or more numbered -units. Registers correspond to device state, units to device address -spaces. Thus, the CPU device might have registers like PC, ION, etc, -and a unit corresponding to main memory; a disk device might have -registers like BUSY, DONE, etc, and units corresponding to individual +A simulator consists of a series of devices, the first of which is +always the CPU. A device consists of named registers and one or more +numbered units. Registers correspond to device state, units to device +address spaces. Thus, the CPU device might have registers like PC, +ION, etc, and a unit corresponding to main memory; a disk device might +have registers like BUSY, DONE, etc, and units corresponding to individual disk drives. Except for main memory, device address spaces are simulated -as unstructured binary disk files in the host file system. The SHOW CONFIG -command displays the simulator configuration. +as unstructured binary disk files in the host file system. The SHOW +CONFIG command displays the simulator configuration. A simulator keeps time in terms of arbitrary units, usually one time unit per instruction executed. Simulated events (such as completion of I/O) @@ -152,8 +234,8 @@ displays the simulator event queue. 3. Commands -Simulator commands consist of a command verb, optional switches, and optional -arguments. Switches take the form: +Simulator commands consist of a command verb, optional switches, and +optional arguments. Switches take the form: -{...} @@ -161,7 +243,8 @@ Multiple switches may be specified separately or together: -abcd or -a -b -c -d are treated identically. Verbs, switches, and other input (except for file names) are case insensitive. -Any command beginning with semicolon (;) is considered a comment and ignored. +Any command beginning with semicolon (;) is considered a comment and +ignored. 3.1 Loading and Saving Programs @@ -211,24 +294,26 @@ does not clear main memory or affect I/O connections. 3.4 Connecting and Disconnecting Devices -Except for main memory, simulated unit address spaces are simulated as -unstructured binary disk files in the host file system. Before using a -simulated unit the user must specify the file to be accessed by that -unit. The ATTACH (abbreviation AT) command associates a unit and a file: +Except for main memory, simulated unit address spaces are simulated +as unstructured binary disk files in the host file system. Before +using a simulated unit, the user must specify the file to be accessed +by that unit. The ATTACH (abbreviation AT) command associates a unit +and a file: sim> ATTACH (cr) -If the file does not exist, and the -e switch was not specified, a new -file is created, and an appropriate message is printed. If the -e switch -was specified, a new file is not created, and an error message is printed. +If the file does not exist, and the -e switch was not specified, a +new file is created, and an appropriate message is printed. If the +-e switch was specified, a new file is not created, and an error +message is printed. -If the -r switch is specified, or the file is write protected, ATTACH tries -to open the file read only. If the file does not exist, or the unit -does not support read only operation, an error occurs. Input-only -devices, such as paper-tape readers, and devices with write lock switches, -such as disks and tapes, support read only operation; other devices do -not. If a file is ATTACHed read only, its contents can be examined but -not modified. +If the -r switch is specified, or the file is write protected, ATTACH +tries to open the file read only. If the file does not exist, or the +unit does not support read only operation, an error occurs. Input- +only devices, such as paper-tape readers, and devices with write lock +switches, such as disks and tapes, support read only operation; other +devices do not. If a file is ATTACHed read only, its contents can be +examined but not modified. For Telnet-based terminal emulators, the ATTACH command associates the master unit with a TCP/IP port: @@ -238,11 +323,11 @@ master unit with a TCP/IP port: The port is a decimal number between 1 and 65535 and should not used by standard TCP/IP protocols. -The DETACH (abbreviation DET) command breaks the association between a -unit and a file, or between a unit and a port: +The DETACH (abbreviation DET) command breaks the association between +a unit and a file, or between a unit and a port: - sim> DETACH ALL(cr) -- detach all units - sim> DETACH (cr) -- detach specified unit + sim> DETACH ALL(cr) -- detach all units + sim> DETACH (cr) -- detach specified unit The EXIT command performs an automatic DETACH ALL. @@ -322,7 +407,8 @@ Switches can be used to control the format of display information: -d display as decimal -h display as hexidecimal -The simulators typically accept symbolic input (see simulator sections). +The simulators typically accept symbolic input (see documentation with +each simulator). Examples: @@ -347,16 +433,16 @@ The RUN command (abbreviated RU) resets all devices, deposits its argument (if given) in the PC, and starts execution. If no argument is given, execution starts at the current PC. -The GO command does NOT reset devices, deposits its argument (if given) in -the PC, and starts execution. If no argument is given, execution starts at -the current PC. +The GO command does NOT reset devices, deposits its argument (if given) +in the PC, and starts execution. If no argument is given, execution +starts at the current PC. The CONT command (abbreviated CO) does NOT reset devices and resumes execution at the current PC. -The STEP command (abbreviated S) resumes execution at the current PC for -the number of instructions given by its argument. If no argument is -supplied, one instruction is executed. +The STEP command (abbreviated S) resumes execution at the current PC +for the number of instructions given by its argument. If no argument +is supplied, one instruction is executed. The BOOT command (abbreviated BO) bootstraps the device and unit given by its argument. If no unit is supplied, unit 0 is bootstrapped. The @@ -405,18 +491,18 @@ A breakpoint is set by the BREAK command: sim> BREAK {-types} {[count]},{addr range...} -If no type is specified, the simulator-specific default breakpoint type -(usually E for execution) is used. As with EXAMINE and DEPOSIT, an address -range may be a single address, a range of addresses low-high, or a relative -range of address/length. Examples of BREAK: +If no type is specified, the simulator-specific default breakpoint +type (usually E for execution) is used. As with EXAMINE and DEPOSIT, +an address range may be a single address, a range of addresses low-high, +or a relative range of address/length. Examples of BREAK: - sim> break -e 200 -- set E break at 200 - sim> break 2000/2[2] -- set E breaks at 2000,2001 - with count = 2 + sim> break -e 200 -- set E break at 200 + sim> break 2000/2[2] -- set E breaks at 2000,2001 + with count = 2 Currently set breakpoints can be displayed with the SHOW BREAK command: - sim> SHOW {-types} BREAK ALL|{,...} + sim> SHOW {-types} BREAK {ALL|{,...}} Locations with breakpoints of the specified type are displayed. @@ -445,35 +531,37 @@ All devices recognize the following parameters: 3.9 Displaying Parameters and Status -The SHOW CONFIGURATION command shows the simulator configuration and the -status of all simulated devices and units. +The SHOW CONFIGURATION command shows the simulator configuration and +the status of all simulated devices and units. -The SHOW DEVICES command shows the configuration of all simulated devices. - -The SHOW MODIFIERS command shows the modifiers available on all simulated +The SHOW DEVICES command shows the configuration of all simulated devices. -The SHOW QUEUE command shows the state of the simulator event queue. Times -are in "simulation units", typically one unit per instruction execution, -relative to the current simulation time. +The SHOW MODIFIERS command shows the modifiers available on all +simulated devices. + +The SHOW QUEUE command shows the state of the simulator event queue. +Times are in "simulation units", typically one unit per instruction +execution, relative to the current simulation time. The SHOW TIME command shows the number of time units elapsed since the last RUN command. -The SHOW command shows the status of the named simulated device. -SHOW shows the value of the named parameter, if it -display a result. +The SHOW command shows the status of the named simulated +device. SHOW shows the value of the named +parameter, if it can display a value. The SHOW command shows the status of the named simulated unit. -SHOW shows the value of the named parameter, if it can -display a result. +SHOW shows the value of the named parameter, if +it can display a value. 3.10 Altering the Simulated Configuration -In most simulators, the SET DISABLED command removes the specified -device from the configuration. A DISABLED device is invisible to running -programs. The device can still be RESET but it cannot be ATTAChed, DETACHed, -or BOOTed. SET ENABLED restores a disabled device to a configuration. +In most simulators, the SET DISABLED command removes the +specified device from the configuration. A DISABLED device is +invisible to running programs. The device can still be RESET but +it cannot be ATTAChed, DETACHed, or BOOTed. SET ENABLED +restores a disabled device to a configuration. Most multi-unit devices allow units to be placed online or offline: @@ -482,25 +570,26 @@ Most multi-unit devices allow units to be placed online or offline: When a unit is offline, it will not be displayed by SHOW DEVICE. -If the host is VMS or UNIX, VT100 terminal emulation for the console window -is built in to the Xterm program. For Windows, VT100 emulation foir the -console window can be enabled or disabled explicitly: +The console terminal normally runs in the controlling window. +Optionally, the console terminal can be connected to a Telnet port. +This allows systems to emulate a VT100 using the built-in terminal +emulation of the Telnet client. - sim> SET VT -- enable VT emulation - sim> SET NOVT -- disable VT emulation - -VT100 emulation is not presently available on Mac or OS/2 hosts. + sim> SET TELNET -- listen for console + Telnet connection on port + sim> SET NOTELNET -- disable console Telnet + sim> SHOW TELNET -- show console Telnet status 3.11 Logging Console Output -Output to the console can be logged simultaneously to a file. Logging is -enabled by the LOG command: +Output to the console can be logged simultaneously to a file. Logging +is enabled by the LOG command: - sim> SET LOG -- log console output to file + sim> SET LOG -- log console output to file Logging is disabled by the NOLOG command: - sim> SET NOLOG -- disable logging + sim> SET NOLOG -- disable logging SHOW LOG displays whether logging is enabled or disabled. @@ -508,12 +597,27 @@ SHOW LOG displays whether logging is enabled or disabled. The simulator can execute command files with the DO command: - sim> DO -- execute commands in file + sim> DO {arguments...} -- execute commands in file -If the switch -V is specified, the commands in the file are echoed before -they are executed. +The DO command allows command files to contain substitutable arguments. +The string %n is recognized as meaning argument n from the DO command +line. The character \ has the usual UNIX meaning of an escape character; +the next character is interpreted literally, even if it is % or \. +Arguments with spaces can be enclosed in matching single or double +quotation marks. -3.13 Exiting The Simulator +If the switch -V is specified, the commands in the file are echoed +before they are executed. + +3.13 Getting Help + +The HELP command prints out information about a command or about all +commands: + + sim> HELP -- print all HELP messages + sim> HELP -- print HELP for command + +3.14 Exiting The Simulator EXIT (synonyms QUIT and BYE) returns control to the operating system. @@ -524,26 +628,33 @@ simulator automatically performs any required byte swapping. 1. Hard Disks -Hard disks are represented as unstructured binary files of 16b data items for -the 12b and 16b simulators, of 32b data items for the 18b and 32b simulators, -and 64b for the 36b simulators. +Hard disks are represented as unstructured binary files of 16b data +items for the 12b and 16b simulators, of 32b data items for the 18b, +24b, and 32b simulators, and 64b for the 36b simulators. 2. Floppy Disks -PDP-8 and PDP-11 floppy disks are represented as unstructured binary files -of 8b data items. They are nearly identical to the floppy disk images for -Doug Jones' PDP-8 simulator but lack the initial 256 byte header. A utility -for converting between the two formats is easily written. +PDP-8 and PDP-11 floppy disks are represented as unstructured binary +files of 8b data items. They are nearly identical to the floppy disk +images for Doug Jones' PDP-8 simulator but lack the initial 256 byte +header. A utility for converting between the two formats is easily +written. 3. Magnetic Tapes Magnetic tapes are represented as unstructured binary files of 8b data items. Each record consists of a 32b record header, in little endian -format, followed by n 8b bytes of data, followed by a repeat of the 32b -record header. The high order bit of the record header is used as an -error flag; the remaining 31b are the byte count of the record. If -the byte count is odd, the record is padded to even length; the pad -byte is undefined. +format. If the record header is not a special header, it is followed +by n 8b bytes of data, followed by a repeat of the 32b record header. +A 1 in the high order bit of the record header indicates an error in +the record. If the byte count is odd, the record is padded to even +length; the pad byte is undefined. + +Special record headers occur only once and have no data. The currently +defined special headers are: + + 0x00000000 file mark (not repeated) + 0xFFFFFFFF end of medium (not repeated) Magnetic tapes are endian independent and consistent across simulator families. A magtape produced by the Nova simulator will appear to @@ -551,19 +662,21 @@ have its 16b words byte swapped if read by the PDP-11 simulator. 4. Line Printers -Line printer output is represented by an ASCII file of lines separated by -the newline character. Overprinting is represented by a line ending in -return rather than newline. +Line printer output is represented by an ASCII file of lines separated +by the newline character. Overprinting is represented by a line ending +in return rather than newline. 5. DECtapes -DECtapes are structured as fixed length blocks. PDP-9/11/15 DECtapes +DECtapes are structured as fixed length blocks. PDP-1/4/7/9/15 DECtapes use 578 blocks of 256 32b words. Each 32b word contains 18b (6 lines) -of data. PDP-8 DECtapes use 1474 blocks of 129 16b words. Each 16b -word contains 12b (4 lines) of data. Note that PDP-8 OS/8 does not use -the 129th word of each block, and OS/8 DECtape dumps contain only 128 -words per block. A utility, DTOS8CVT.C, is provided to convert OS/8 -DECtape dumps to simulator format. +of data. PDP-11 DECtapes use 578 blocks of 256 16b words. Each 16b word +contains 6 lines of data, with 2b omitted. This is compatible with native +PDP-11 DECtape dump facilities, and with John Wilson's PUTR Program. PDP-8 +DECtapes use 1474 blocks of 129 16b words. Each 16b word contains 12b +(4 lines) of data. PDP-8 OS/8 does not use the 129th word of each block, +and OS/8 DECtape dumps contain only 128 words per block. A utility, +DTOS8CVT.C, is provided to convert OS/8 DECtape dumps to simulator format. A known problem in DECtape format is that when a block is recorded in one direction and read in the other, the bits in a word are scrambled @@ -593,7 +706,7 @@ The debug status of each simulated CPU and device is as follows: device CPU y y y y y FPU - y - - - -CIS - h - - - +EIS/CIS - h - - - console y y y y y paper tape y y y h y card reader - - - - - @@ -603,42 +716,42 @@ extra terminal y y y - y hard disk y y y - h fixed disk y - h - h floppy disk y y y - - -DECtape y y - - y +DECtape y y - h y mag tape h y y - h system 1401 2100 PDP-10 H316 VAX device CPU y y y h y -FPU - - y - y -CIS - - y - - +FPU - d y - y +EIS/CIS - d y - - console h y y h y -paper tape - h h h y +paper tape - d h h y card reader y - - - - -line printer y h y h y -clock - h y h y +line printer y d y h y +clock - d y h y extra terminal - h y - y hard disk - h y - y fixed disk - h - - - -floppy disk - - - - - +floppy disk - - h - - DECtape - - - - - -mag tape y h y - y +mag tape y d y - y - system GRI-909 + system GRI-909 1620 device -CPU h -FPU - -CIS - -console h -paper tape h -card reader - -line printer - -clock h -extra terminal - -hard disk - -fixed disk - -floppy disk - -DECtape - -mag tape - +CPU h h +FPU - - +CIS - - +console h h +paper tape h h +card reader - h +line printer - h +clock h - +extra terminal - - +hard disk - h +fixed disk - - +floppy disk - - +DECtape - - +mag tape - - legend: y = runs operating system or sample program d = runs diagnostics @@ -646,11 +759,35 @@ legend: y = runs operating system or sample program n = untested - = not applicable -Revision History (covering Rev 1.1 to 2.9) +Revision History (covering Rev 2.0 to present) Starting with Rev 2.7, detailed revision histories can be found in file sim_rev.c. +Rev 2.10, Nov, 02 + Added Telnet console capability, removed VT emulation + Added DO with substitutable arguments + Added quiet mode + Added device enable/disable support + Added optional simulator for input, output, commands + Added PDP-11 KW11P programmable clock + Added PDP-11 RK611/RK06/RK07 disk + Added PDP-11/VAX TMSCP tape + Added PDP-11/VAX DELQA Ethernet support (from David Hittner) + Added PDP-11/PDP-10 RX211/RX02 floppy disk + Added PDP-11/VAX autoconfiguration support + Added PDP-10/PDP-11/VAX variable vector support + Added PDP-1 DECtape + Added PDP-8 RX28 support + Added HP2100 12845A line printer + Added HP2100 13183 magtape support + Added HP2100 boot ROM support + Added IBM 1620 + Added 16b DECtape file format support + Added support for statically buffered devices + Added magtape end of medium support + Added 7B/8B support to terminals and multiplexors + Rev 2.9, Jan, 02 Added circular register arrays Replaced ENABLE/DISABLE with SET ENABLED/DISABLED @@ -948,6 +1085,7 @@ Ken Harrenstein KLH PDP-10 simulator Bill Haygood PDP-8 information, simulator, and software Wolfgang Helbig DZ11 implementation Mark Hittinger PDP-10 debugging +Dave Hittner SCP debugging, Ethernet emulation Sellam Ismail GRI-909 documentation Jay Jaeger IBM 1401 information Doug Jones PDP-8 information, simulator, and software @@ -964,6 +1102,7 @@ Bill McDermith HP 2100 debugging, 12565A simulator Scott McGregor PDP-11 UNIX legal permissions Jeff Moffatt HP 2100 information, documentation, and software Alec Muffett Solaris port testing +Terry Newton HP 21MX debugging Thord Nilson DZ11 implementation Charles Owen Nova moving head disk debugging, Altair simulator, Eclipse simulator, IBM System 3 simulator, diff --git a/simh_swre.txt b/simh_swre.txt index 89e8461d..b5fa8774 100644 --- a/simh_swre.txt +++ b/simh_swre.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik Subj: Sample Software Packages -Date: 15-Apr-2002 +Date: 15-Nov-2002 This memorandum documents the sample software packages available to run with the SIMH simulators. Many of these packages are available under @@ -241,9 +241,9 @@ RT-11 is contained in a single RK05 disk image. To boot and run RT-11: sim> att rk0 rtv4_rk.dsk sim> boot rk0 -For RL, RM, and RP series disks, RT-11 expects to find a manufacturer's bad -block table in the last track of the disk. Therefore, INITialization of a -new (all zero's) disk fails, because there is no valid bad block table. To +For RL, HK, RM, and RP series disks, RT-11 expects to find a manufacturer's +bad block table in the last track of the disk. Therefore, INITialization of +a new (all zero's) disk fails, because there is no valid bad block table. To create a minimal bad block table, use the SET BADBLOCK command. 2.2.2 RT-11 V5.3 @@ -322,9 +322,10 @@ To load and run SIM8: 6.1 FOCAL FOCAL15 is an interactive program for technical computations. It can -execute both immediate commands and stored programs (like BASIC). FOCAL15 -is provided as a binary loader format paper-tape image. My thanks to Al -Kossow, who provided the binary image. To load and run FOCAL15: +execute both immediate commands and stored programs (like BASIC). +FOCAL15 is provided as a binary loader format paper-tape image. My +thanks to Al Kossow, who provided the binary image. To load and run +FOCAL15: sim> load focal15.bin sim> run @@ -334,9 +335,9 @@ Kossow, who provided the binary image. To load and run FOCAL15: 6.2 Advanced Software System/Keyboard Monitor -The Advanced Software System Keyboard Monitor is the simplest mass storage -monitor for the PDP-15. It offers single-user program development and -execution capabilities. To load and run ADSS/KM-15: +The Advanced Software System Keyboard Monitor is the simplest mass +storage monitor for the PDP-15. It offers single-user program +development and execution capabilities. To load and run ADSS/KM-15: - On the PDP-9 (only), initialize extend mode to on: @@ -386,9 +387,9 @@ execution capabilities. To load and run ADSS/KM-15: 6.3 Advanced Software System/Foreground Background -Note: your environment must have a functioning second Teletype; that is, you cannot -at present run Foreground/Background if your host system does not support the SIMH -sockets library. +Note: your environment must have a functioning second Teletype; that is, +you cannot at present run Foreground/Background if your host system +does not support the SIMH sockets library. - Load the paper-tape bootstrap into upper memory: