From 701f0fe0280852dc1922d6d99b45ff5f1cee1f71 Mon Sep 17 00:00:00 2001 From: Bob Supnik Date: Wed, 26 Dec 2001 09:38:00 -0800 Subject: [PATCH] Notes For V2.8 1. New Features 1.1 Directory and documentation - Only common files (SCP and libraries) are in the top level directory. Individual simulator files are in their individual directories. - simh_doc.txt has been split up. simh_doc.txt now documents only SCP. The individual simulators are documented in separate text files in their own directories. - mingw_build.bat is a batch file for the MINGW/gcc environment that will build all the simulators, assuming the root directory structure is at c:\sim. - Makefile is a UNIX make file for the gcc environment that will build all the simulators, assuming the root directory is at c:\sim. 1.2 SCP - DO executes the SCP commands in the specified file. - Replicated registers in unit structures can now be declared as arrays for examine, modify, save, and restore. Most replicated unit registers (for example, mag tape position registers) have been changed to arrays. - The ADD/REMOVE commands have been replaced by SET unit ONLINE and SET unit OFFLINE, respectively. - Register names that are unique within an entire simulator do not have to be prefaced with the device name. - The ATTACH command can attach files read only, either under user option (-r), or because the attached file is ready only. - The SET/SHOW capabilities have been extended. New forms include: SET param{=value}{ param ...} SET param{=value}{ param ...} SHOW {param param ...} SHOW {param param ...} - Multiple breakpoints have been implemented. Breakpoints are set/cleared/displayed by: BREAK addr_list{[count]} NOBREAK addr_list SHOW BREAK addr_list 1.3 PDP-11 simulator - Unibus map implemented, with 22b RP controller (URH70) or 18b RP controller (URH11) (in debug). - All DMA peripherals rewritten to use map. - Many peripherals modified for source sharing with VAX. - RQDX3 implemented. - Bugs fixed in RK11 and RL11 write check. 1.4 PDP-10 simulator - ITS 1-proceed implemented. - Bugs fixed in ITS PC sampling and LPMR 1.5 18b PDP simulator - Interrupts split out to multiple levels to allow easier expansion. 1.5 IBM System 3 Simulator - Written by Charles (Dutch) Owen. 1.6 VAX Simulator (in debug) - Simulates MicroVAX 3800 (KA655) with 16MB-64MB memory, RQDX3, RLV12, TSV11, DZV11, LPV11, PCV11. - CDROM capability has been added to the RQDX3, to allow testing with VMS hobbyist images. 1.7 SDS 940 Simulator (not tested) - Simulates SDS 940, 16K-64K memory, fixed and moving head disk, magtape, line printer, console. 1.8 Altair Z80 - Revised from Charles (Dutch) Owen's original by Peter Schorn. - MITS 8080 with full Z80 simulation. - 4K and 8K BASIC packages, Prolog package. 1.9 Interdata The I4 simulator has been withdrawn for major rework. Look for a complete 16b/32b Interdata simulator sometime next year. 2. Release Notes 2.1 SCP SCP now allows replicated registers in unit structures to be modelled as arrays. All replicated register declarations have been replaced by register array declarations. As a result, save files from prior revisions will generate errors after restoring main memory. 2.2 PDP-11 The Unibus map code is in debug. The map was implemented primarily to allow source sharing with the VAX, which requires a DMA map. DMA devices work correctly with the Unibus map disabled. The RQDX3 simulator has run a complete RSTS/E SYSGEN, with multiple drives, and booted the completed system from scratch. 2.3 VAX The VAX simulator will run the boot code up to the >>> prompt. It can successfully process a SHOW DEVICE command. It runs the HCORE instruction diagnostic. It can boot the hobbyist CD through SYSBOOT and through the date/time dialog and restore the hobbyist CD, using standalone backup. On the boot of the restored disk, it gets to the date/time dialog, and then crashes. 2.4 SDS 940 The SDS 940 is untested, awaiting real code. 2.5 GCC Optimization At -O2 and above, GCC does not correctly compile the simulators which use setjmp-longjmp (PDP-11, PDP-10, VAX). A working hypothesis is that optimized state maintained in registers is being used in the setjmp processing routine. On the PDP-11 and PDP-10, all of this state has been either made global, or volatile, to encourage GCC to keep the state up to date in memory. The VAX is still vulnerable. 3. Work list 3.1 SCP - Better ENABLE/DISABLE. 3.2 PDP-11 RQDX3 Software mapped mode, RCT read simulation, VMS debug. --- 0readme28.txt | 144 + altair.txt => ALTAIR/altair.txt | 0 altair_cpu.c => ALTAIR/altair_cpu.c | 39 +- altair_defs.h => ALTAIR/altair_defs.h | 0 altair_dsk.c => ALTAIR/altair_dsk.c | 0 altair_sio.c => ALTAIR/altair_sio.c | 0 altair_sys.c => ALTAIR/altair_sys.c | 0 AltairZ80/altairZ80.txt | 375 ++ AltairZ80/altairZ80_cpu.c | 3372 ++++++++++++++ AltairZ80/altairZ80_defs.h | 30 + AltairZ80/altairZ80_dsk.c | 408 ++ AltairZ80/altairZ80_sio.c | 434 ++ AltairZ80/altairZ80_sys.c | 687 +++ h316_cpu.c => H316/h316_cpu.c | 51 +- h316_defs.h => H316/h316_defs.h | 0 H316/h316_doc.txt | 303 ++ h316_lp.c => H316/h316_lp.c | 0 h316_stddev.c => H316/h316_stddev.c | 14 +- h316_sys.c => H316/h316_sys.c | 0 hp2100_cpu.c => HP2100/hp2100_cpu.c | 83 +- hp2100_defs.h => HP2100/hp2100_defs.h | 7 +- HP2100/hp2100_doc.txt | 471 ++ hp2100_dp.c => HP2100/hp2100_dp.c | 10 +- hp2100_lp.c => HP2100/hp2100_lp.c | 4 +- hp2100_mt.c => HP2100/hp2100_mt.c | 21 +- hp2100_stddev.c => HP2100/hp2100_stddev.c | 31 +- hp2100_sys.c => HP2100/hp2100_sys.c | 0 i1401_cd.c => I1401/i1401_cd.c | 3 +- i1401_cpu.c => I1401/i1401_cpu.c | 34 +- i1401_defs.h => I1401/i1401_defs.h | 0 I1401/i1401_doc.txt | 428 ++ i1401_iq.c => I1401/i1401_iq.c | 2 + i1401_lp.c => I1401/i1401_lp.c | 2 +- i1401_mt.c => I1401/i1401_mt.c | 30 +- i1401_sys.c => I1401/i1401_sys.c | 0 eclipse.txt => NOVA/eclipse.txt | 6 +- eclipse_cpu.c => NOVA/eclipse_cpu.c | 42 +- eclipse_tt.c => NOVA/eclipse_tt.c | 0 nova_clk.c => NOVA/nova_clk.c | 0 nova_cpu.c => NOVA/nova_cpu.c | 39 +- nova_defs.h => NOVA/nova_defs.h | 0 nova_dkp.c => NOVA/nova_dkp.c | 35 +- NOVA/nova_doc.txt | 565 +++ nova_dsk.c => NOVA/nova_dsk.c | 0 nova_lp.c => NOVA/nova_lp.c | 0 nova_mta.c => NOVA/nova_mta.c | 68 +- nova_plt.c => NOVA/nova_plt.c | 0 nova_pt.c => NOVA/nova_pt.c | 5 +- nova_sys.c => NOVA/nova_sys.c | 0 nova_tt.c => NOVA/nova_tt.c | 9 +- nova_tt1.c => NOVA/nova_tt1.c | 17 +- pdp1_cpu.c => PDP1/pdp1_cpu.c | 41 +- pdp1_defs.h => PDP1/pdp1_defs.h | 0 PDP1/pdp1_doc.txt | 409 ++ pdp1_lp.c => PDP1/pdp1_lp.c | 0 pdp1_stddev.c => PDP1/pdp1_stddev.c | 4 +- pdp1_sys.c => PDP1/pdp1_sys.c | 0 pdp10_cpu.c => PDP10/pdp10_cpu.c | 372 +- pdp10_defs.h => PDP10/pdp10_defs.h | 7 +- PDP10/pdp10_doc.txt | 526 +++ pdp10_dz.c => PDP10/pdp10_dz.c | 0 pdp10_fe.c => PDP10/pdp10_fe.c | 9 +- pdp10_ksio.c => PDP10/pdp10_ksio.c | 0 pdp10_lp20.c => PDP10/pdp10_lp20.c | 6 +- pdp10_mdfp.c => PDP10/pdp10_mdfp.c | 0 pdp10_pag.c => PDP10/pdp10_pag.c | 2 + pdp10_pt.c => PDP10/pdp10_pt.c | 4 +- pdp10_rp.c => PDP10/pdp10_rp.c | 80 +- pdp10_sys.c => PDP10/pdp10_sys.c | 0 pdp10_tim.c => PDP10/pdp10_tim.c | 5 +- pdp10_tu.c => PDP10/pdp10_tu.c | 64 +- pdp10_xtnd.c => PDP10/pdp10_xtnd.c | 0 pdp11_cis.c => PDP11/pdp11_cis.c | 0 pdp11_cpu.c => PDP11/pdp11_cpu.c | 328 +- pdp11_defs.h => PDP11/pdp11_defs.h | 124 +- PDP11/pdp11_doc.txt | 868 ++++ pdp11_dz.c => PDP11/pdp11_dz.c | 12 + pdp11_fp.c => PDP11/pdp11_fp.c | 0 PDP11/pdp11_io.c | 361 ++ pdp11_lp.c => PDP11/pdp11_lp.c | 16 +- pdp11_rk.c => PDP11/pdp11_rk.c | 134 +- pdp11_rl.c => PDP11/pdp11_rl.c | 229 +- pdp11_rp.c => PDP11/pdp11_rp.c | 260 +- PDP11/pdp11_rq.c | 1849 ++++++++ pdp11_rx.c => PDP11/pdp11_rx.c | 8 +- pdp11_stddev.c => PDP11/pdp11_stddev.c | 8 +- pdp11_sys.c => PDP11/pdp11_sys.c | 17 +- pdp11_tc.c => PDP11/pdp11_tc.c | 72 +- pdp11_tm.c => PDP11/pdp11_tm.c | 109 +- pdp11_ts.c => PDP11/pdp11_ts.c | 163 +- pdp18b_cpu.c => PDP18B/pdp18b_cpu.c | 113 +- pdp18b_defs.h => PDP18B/pdp18b_defs.h | 113 +- PDP18B/pdp18b_doc.txt | 782 ++++ pdp18b_drm.c => PDP18B/pdp18b_drm.c | 21 +- pdp18b_dt.c => PDP18B/pdp18b_dt.c | 90 +- pdp18b_lp.c => PDP18B/pdp18b_lp.c | 60 +- pdp18b_mt.c => PDP18B/pdp18b_mt.c | 69 +- pdp18b_rf.c => PDP18B/pdp18b_rf.c | 19 +- pdp18b_rp.c => PDP18B/pdp18b_rp.c | 46 +- pdp18b_stddev.c => PDP18B/pdp18b_stddev.c | 87 +- pdp18b_sys.c => PDP18B/pdp18b_sys.c | 0 pdp18b_tt1.c => PDP18B/pdp18b_tt1.c | 47 +- pdp8_clk.c => PDP8/pdp8_clk.c | 0 pdp8_cpu.c => PDP8/pdp8_cpu.c | 55 +- pdp8_defs.h => PDP8/pdp8_defs.h | 9 +- pdp8_df.c => PDP8/pdp8_df.c | 4 +- PDP8/pdp8_doc.txt | 676 +++ pdp8_dt.c => PDP8/pdp8_dt.c | 81 +- pdp8_lp.c => PDP8/pdp8_lp.c | 0 pdp8_mt.c => PDP8/pdp8_mt.c | 68 +- pdp8_pt.c => PDP8/pdp8_pt.c | 4 +- pdp8_rf.c => PDP8/pdp8_rf.c | 4 +- pdp8_rk.c => PDP8/pdp8_rk.c | 48 +- PDP8/pdp8_rl.c | 619 +++ pdp8_rx.c => PDP8/pdp8_rx.c | 16 +- pdp8_sys.c => PDP8/pdp8_sys.c | 17 +- pdp8_tt.c => PDP8/pdp8_tt.c | 0 pdp8_ttx.c => PDP8/pdp8_ttx.c | 11 +- S3/haltguide.txt | 950 ++++ S3/readme_s3.txt | 78 + S3/s3_cd.c | 434 ++ S3/s3_cpu.c | 1825 ++++++++ S3/s3_defs.h | 97 + S3/s3_disk.c | 779 ++++ S3/s3_lp.c | 349 ++ S3/s3_pkb.c | 302 ++ S3/s3_sys.c | 925 ++++ S3/system3.txt | 472 ++ dec_dz.h | 29 +- dec_mscp.h | 373 ++ dec_uqssp.h | 162 + id4_cpu.c | 770 ---- id4_defs.h | 146 - id4_fp.c | 277 -- id4_stddev.c | 407 -- id4_sys.c | 322 -- makefile | 247 ++ mingw_build.bat | 41 + scp.c | 1070 +++-- sim_defs.h | 65 +- sim_rev.h | 48 +- sim_tmxr.c | 8 +- simh.doc | 974 ----- simh_doc.txt | 4865 +-------------------- simh_swre.txt | 67 +- 145 files changed, 23190 insertions(+), 9807 deletions(-) create mode 100644 0readme28.txt rename altair.txt => ALTAIR/altair.txt (100%) rename altair_cpu.c => ALTAIR/altair_cpu.c (93%) rename altair_defs.h => ALTAIR/altair_defs.h (100%) rename altair_dsk.c => ALTAIR/altair_dsk.c (100%) rename altair_sio.c => ALTAIR/altair_sio.c (100%) rename altair_sys.c => ALTAIR/altair_sys.c (100%) create mode 100644 AltairZ80/altairZ80.txt create mode 100644 AltairZ80/altairZ80_cpu.c create mode 100644 AltairZ80/altairZ80_defs.h create mode 100644 AltairZ80/altairZ80_dsk.c create mode 100644 AltairZ80/altairZ80_sio.c create mode 100644 AltairZ80/altairZ80_sys.c rename h316_cpu.c => H316/h316_cpu.c (94%) rename h316_defs.h => H316/h316_defs.h (100%) create mode 100644 H316/h316_doc.txt rename h316_lp.c => H316/h316_lp.c (100%) rename h316_stddev.c => H316/h316_stddev.c (93%) rename h316_sys.c => H316/h316_sys.c (100%) rename hp2100_cpu.c => HP2100/hp2100_cpu.c (93%) rename hp2100_defs.h => HP2100/hp2100_defs.h (92%) create mode 100644 HP2100/hp2100_doc.txt rename hp2100_dp.c => HP2100/hp2100_dp.c (96%) rename hp2100_lp.c => HP2100/hp2100_lp.c (94%) rename hp2100_mt.c => HP2100/hp2100_mt.c (92%) rename hp2100_stddev.c => HP2100/hp2100_stddev.c (92%) rename hp2100_sys.c => HP2100/hp2100_sys.c (100%) rename i1401_cd.c => I1401/i1401_cd.c (95%) rename i1401_cpu.c => I1401/i1401_cpu.c (94%) rename i1401_defs.h => I1401/i1401_defs.h (100%) create mode 100644 I1401/i1401_doc.txt rename i1401_iq.c => I1401/i1401_iq.c (96%) rename i1401_lp.c => I1401/i1401_lp.c (96%) rename i1401_mt.c => I1401/i1401_mt.c (88%) rename i1401_sys.c => I1401/i1401_sys.c (100%) rename eclipse.txt => NOVA/eclipse.txt (78%) rename eclipse_cpu.c => NOVA/eclipse_cpu.c (96%) rename eclipse_tt.c => NOVA/eclipse_tt.c (100%) rename nova_clk.c => NOVA/nova_clk.c (100%) rename nova_cpu.c => NOVA/nova_cpu.c (94%) rename nova_defs.h => NOVA/nova_defs.h (100%) rename nova_dkp.c => NOVA/nova_dkp.c (93%) create mode 100644 NOVA/nova_doc.txt rename nova_dsk.c => NOVA/nova_dsk.c (100%) rename nova_lp.c => NOVA/nova_lp.c (100%) rename nova_mta.c => NOVA/nova_mta.c (87%) rename nova_plt.c => NOVA/nova_plt.c (100%) rename nova_pt.c => NOVA/nova_pt.c (94%) rename nova_sys.c => NOVA/nova_sys.c (100%) rename nova_tt.c => NOVA/nova_tt.c (92%) rename nova_tt1.c => NOVA/nova_tt1.c (90%) rename pdp1_cpu.c => PDP1/pdp1_cpu.c (93%) rename pdp1_defs.h => PDP1/pdp1_defs.h (100%) create mode 100644 PDP1/pdp1_doc.txt rename pdp1_lp.c => PDP1/pdp1_lp.c (100%) rename pdp1_stddev.c => PDP1/pdp1_stddev.c (95%) rename pdp1_sys.c => PDP1/pdp1_sys.c (100%) rename pdp10_cpu.c => PDP10/pdp10_cpu.c (93%) rename pdp10_defs.h => PDP10/pdp10_defs.h (96%) create mode 100644 PDP10/pdp10_doc.txt rename pdp10_dz.c => PDP10/pdp10_dz.c (100%) rename pdp10_fe.c => PDP10/pdp10_fe.c (91%) rename pdp10_ksio.c => PDP10/pdp10_ksio.c (100%) rename pdp10_lp20.c => PDP10/pdp10_lp20.c (96%) rename pdp10_mdfp.c => PDP10/pdp10_mdfp.c (100%) rename pdp10_pag.c => PDP10/pdp10_pag.c (96%) rename pdp10_pt.c => PDP10/pdp10_pt.c (95%) rename pdp10_rp.c => PDP10/pdp10_rp.c (91%) rename pdp10_sys.c => PDP10/pdp10_sys.c (100%) rename pdp10_tim.c => PDP10/pdp10_tim.c (94%) rename pdp10_tu.c => PDP10/pdp10_tu.c (91%) rename pdp10_xtnd.c => PDP10/pdp10_xtnd.c (100%) rename pdp11_cis.c => PDP11/pdp11_cis.c (100%) rename pdp11_cpu.c => PDP11/pdp11_cpu.c (86%) rename pdp11_defs.h => PDP11/pdp11_defs.h (71%) create mode 100644 PDP11/pdp11_doc.txt rename pdp11_dz.c => PDP11/pdp11_dz.c (87%) rename pdp11_fp.c => PDP11/pdp11_fp.c (100%) create mode 100644 PDP11/pdp11_io.c rename pdp11_lp.c => PDP11/pdp11_lp.c (90%) rename pdp11_rk.c => PDP11/pdp11_rk.c (82%) rename pdp11_rl.c => PDP11/pdp11_rl.c (72%) rename pdp11_rp.c => PDP11/pdp11_rp.c (82%) create mode 100644 PDP11/pdp11_rq.c rename pdp11_rx.c => PDP11/pdp11_rx.c (95%) rename pdp11_stddev.c => PDP11/pdp11_stddev.c (94%) rename pdp11_sys.c => PDP11/pdp11_sys.c (95%) rename pdp11_tc.c => PDP11/pdp11_tc.c (91%) rename pdp11_tm.c => PDP11/pdp11_tm.c (84%) rename pdp11_ts.c => PDP11/pdp11_ts.c (84%) rename pdp18b_cpu.c => PDP18B/pdp18b_cpu.c (92%) rename pdp18b_defs.h => PDP18B/pdp18b_defs.h (84%) create mode 100644 PDP18B/pdp18b_doc.txt rename pdp18b_drm.c => PDP18B/pdp18b_drm.c (89%) rename pdp18b_dt.c => PDP18B/pdp18b_dt.c (90%) rename pdp18b_lp.c => PDP18B/pdp18b_lp.c (88%) rename pdp18b_mt.c => PDP18B/pdp18b_mt.c (84%) rename pdp18b_rf.c => PDP18B/pdp18b_rf.c (92%) rename pdp18b_rp.c => PDP18B/pdp18b_rp.c (90%) rename pdp18b_stddev.c => PDP18B/pdp18b_stddev.c (88%) rename pdp18b_sys.c => PDP18B/pdp18b_sys.c (100%) rename pdp18b_tt1.c => PDP18B/pdp18b_tt1.c (81%) rename pdp8_clk.c => PDP8/pdp8_clk.c (100%) rename pdp8_cpu.c => PDP8/pdp8_cpu.c (92%) rename pdp8_defs.h => PDP8/pdp8_defs.h (93%) rename pdp8_df.c => PDP8/pdp8_df.c (95%) create mode 100644 PDP8/pdp8_doc.txt rename pdp8_dt.c => PDP8/pdp8_dt.c (90%) rename pdp8_lp.c => PDP8/pdp8_lp.c (100%) rename pdp8_mt.c => PDP8/pdp8_mt.c (87%) rename pdp8_pt.c => PDP8/pdp8_pt.c (95%) rename pdp8_rf.c => PDP8/pdp8_rf.c (95%) rename pdp8_rk.c => PDP8/pdp8_rk.c (88%) create mode 100644 PDP8/pdp8_rl.c rename pdp8_rx.c => PDP8/pdp8_rx.c (94%) rename pdp8_sys.c => PDP8/pdp8_sys.c (94%) rename pdp8_tt.c => PDP8/pdp8_tt.c (100%) rename pdp8_ttx.c => PDP8/pdp8_ttx.c (94%) create mode 100644 S3/haltguide.txt create mode 100644 S3/readme_s3.txt create mode 100644 S3/s3_cd.c create mode 100644 S3/s3_cpu.c create mode 100644 S3/s3_defs.h create mode 100644 S3/s3_disk.c create mode 100644 S3/s3_lp.c create mode 100644 S3/s3_pkb.c create mode 100644 S3/s3_sys.c create mode 100644 S3/system3.txt create mode 100644 dec_mscp.h create mode 100644 dec_uqssp.h delete mode 100644 id4_cpu.c delete mode 100644 id4_defs.h delete mode 100644 id4_fp.c delete mode 100644 id4_stddev.c delete mode 100644 id4_sys.c create mode 100644 makefile create mode 100644 mingw_build.bat delete mode 100644 simh.doc diff --git a/0readme28.txt b/0readme28.txt new file mode 100644 index 00000000..ea8ddaea --- /dev/null +++ b/0readme28.txt @@ -0,0 +1,144 @@ +Notes For V2.8 + +1. New Features + +1.1 Directory and documentation + +- Only common files (SCP and libraries) are in the top level + directory. Individual simulator files are in their individual + directories. +- simh_doc.txt has been split up. simh_doc.txt now documents + only SCP. The individual simulators are documented in separate + text files in their own directories. +- mingw_build.bat is a batch file for the MINGW/gcc environment + that will build all the simulators, assuming the root directory + structure is at c:\sim. +- Makefile is a UNIX make file for the gcc environment that will + build all the simulators, assuming the root directory is at + c:\sim. + +1.2 SCP + +- DO executes the SCP commands in the specified file. +- Replicated registers in unit structures can now be declared as + arrays for examine, modify, save, and restore. Most replicated + unit registers (for example, mag tape position registers) have + been changed to arrays. +- The ADD/REMOVE commands have been replaced by SET unit ONLINE + and SET unit OFFLINE, respectively. +- Register names that are unique within an entire simulator do + not have to be prefaced with the device name. +- The ATTACH command can attach files read only, either under + user option (-r), or because the attached file is ready only. +- The SET/SHOW capabilities have been extended. New forms include: + + SET param{=value}{ param ...} + SET param{=value}{ param ...} + SHOW {param param ...} + SHOW {param param ...} + +- Multiple breakpoints have been implemented. Breakpoints are + set/cleared/displayed by: + + BREAK addr_list{[count]} + NOBREAK addr_list + SHOW BREAK addr_list + +1.3 PDP-11 simulator + +- Unibus map implemented, with 22b RP controller (URH70) or 18b + RP controller (URH11) (in debug). +- All DMA peripherals rewritten to use map. +- Many peripherals modified for source sharing with VAX. +- RQDX3 implemented. +- Bugs fixed in RK11 and RL11 write check. + +1.4 PDP-10 simulator + +- ITS 1-proceed implemented. +- Bugs fixed in ITS PC sampling and LPMR + +1.5 18b PDP simulator + +- Interrupts split out to multiple levels to allow easier + expansion. + +1.5 IBM System 3 Simulator + +- Written by Charles (Dutch) Owen. + +1.6 VAX Simulator (in debug) + +- Simulates MicroVAX 3800 (KA655) with 16MB-64MB memory, RQDX3, + RLV12, TSV11, DZV11, LPV11, PCV11. +- CDROM capability has been added to the RQDX3, to allow testing + with VMS hobbyist images. + +1.7 SDS 940 Simulator (not tested) + +- Simulates SDS 940, 16K-64K memory, fixed and moving head + disk, magtape, line printer, console. + +1.8 Altair Z80 + +- Revised from Charles (Dutch) Owen's original by Peter Schorn. +- MITS 8080 with full Z80 simulation. +- 4K and 8K BASIC packages, Prolog package. + +1.9 Interdata + +The I4 simulator has been withdrawn for major rework. Look for +a complete 16b/32b Interdata simulator sometime next year. + +2. Release Notes + +2.1 SCP + +SCP now allows replicated registers in unit structures to be +modelled as arrays. All replicated register declarations have +been replaced by register array declarations. As a result, +save files from prior revisions will generate errors after +restoring main memory. + +2.2 PDP-11 + +The Unibus map code is in debug. The map was implemented primarily +to allow source sharing with the VAX, which requires a DMA map. +DMA devices work correctly with the Unibus map disabled. + +The RQDX3 simulator has run a complete RSTS/E SYSGEN, with multiple +drives, and booted the completed system from scratch. + +2.3 VAX + +The VAX simulator will run the boot code up to the >>> prompt. It +can successfully process a SHOW DEVICE command. It runs the HCORE +instruction diagnostic. It can boot the hobbyist CD through SYSBOOT +and through the date/time dialog and restore the hobbyist CD, using +standalone backup. On the boot of the restored disk, it gets to the +date/time dialog, and then crashes. + +2.4 SDS 940 + +The SDS 940 is untested, awaiting real code. + +2.5 GCC Optimization + +At -O2 and above, GCC does not correctly compile the simulators which +use setjmp-longjmp (PDP-11, PDP-10, VAX). A working hypothesis is +that optimized state maintained in registers is being used in the +setjmp processing routine. On the PDP-11 and PDP-10, all of this +state has been either made global, or volatile, to encourage GCC to +keep the state up to date in memory. The VAX is still vulnerable. + +3. Work list + +3.1 SCP + +- Better ENABLE/DISABLE. + +3.2 PDP-11 RQDX3 + +Software mapped mode, RCT read simulation, VMS debug. + + diff --git a/altair.txt b/ALTAIR/altair.txt similarity index 100% rename from altair.txt rename to ALTAIR/altair.txt diff --git a/altair_cpu.c b/ALTAIR/altair_cpu.c similarity index 93% rename from altair_cpu.c rename to ALTAIR/altair_cpu.c index 049dbe14..53502b0b 100644 --- a/altair_cpu.c +++ b/ALTAIR/altair_cpu.c @@ -58,8 +58,6 @@ #include "altair_defs.h" -#define ILL_ADR_FLAG 0200000 -#define save_ibkpt (cpu_unit.u3) #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 */ @@ -82,20 +80,19 @@ int32 saved_PC = 0; /* program counter */ int32 SR = 0; /* switch register */ int32 INTE = 0; /* Interrupt Enable */ int32 int_req = 0; /* Interrupt request */ -int32 ibkpt_addr = ILL_ADR_FLAG | ADDRMASK; /* breakpoint addr */ int32 chip = 0; /* 0 = 8080 chip, 1 = z80 chip */ int32 PCX; /* External view of PC */ extern int32 sim_int_char; +extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ /* function prototypes */ 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_svc (UNIT *uptr); -t_stat cpu_set_size (UNIT *uptr, int32 value); +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); void setarith(int32 reg); void setlogical(int32 reg); void setinc(int32 reg); @@ -234,7 +231,7 @@ int32 bootrom[256] = { cpu_mod CPU modifiers list */ -UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK, +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) }; REG cpu_reg[] = { @@ -249,11 +246,10 @@ REG cpu_reg[] = { { FLDATA (AC, AC, 16) }, { FLDATA (S, S, 16) }, { FLDATA (P, P, 16) }, - { FLDATA (INTE, INTE, 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 (BREAK, ibkpt_addr, 17) }, { ORDATA (WRU, sim_int_char, 8) }, { NULL } }; @@ -303,10 +299,8 @@ int32 sim_instr (void) } /* end interrupt */ - if (PC == ibkpt_addr) { /* breakpoint? */ - save_ibkpt = ibkpt_addr; /* save address */ - ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */ - sim_activate (&cpu_unit, 1); /* sched re-enable */ + if (sim_brk_summ && + sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ reason = STOP_IBKPT; /* stop simulation */ break; } @@ -1125,7 +1119,8 @@ C = 0; Z = 0; saved_PC = 0; int_req = 0; -return cpu_svc (&cpu_unit); +sim_brk_types = sim_brk_dflt = SWMASK ('E'); +return SCPE_OK; } /* Memory examine */ @@ -1146,27 +1141,17 @@ t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) return SCPE_OK; } -/* Breakpoint service */ - -t_stat cpu_svc (UNIT *uptr) -{ - if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt) - ibkpt_addr = save_ibkpt; - save_ibkpt = -1; - return SCPE_OK; -} - -t_stat cpu_set_size (UNIT *uptr, int32 value) +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { int32 mc = 0; t_addr i; -if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 07777) != 0)) +if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0)) return SCPE_ARG; -for (i = value; i < MEMSIZE; i++) mc = mc | M[i]; +for (i = val; i < MEMSIZE; i++) mc = mc | M[i]; if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) return SCPE_OK; -MEMSIZE = value; +MEMSIZE = val; for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; return SCPE_OK; } diff --git a/altair_defs.h b/ALTAIR/altair_defs.h similarity index 100% rename from altair_defs.h rename to ALTAIR/altair_defs.h diff --git a/altair_dsk.c b/ALTAIR/altair_dsk.c similarity index 100% rename from altair_dsk.c rename to ALTAIR/altair_dsk.c diff --git a/altair_sio.c b/ALTAIR/altair_sio.c similarity index 100% rename from altair_sio.c rename to ALTAIR/altair_sio.c diff --git a/altair_sys.c b/ALTAIR/altair_sys.c similarity index 100% rename from altair_sys.c rename to ALTAIR/altair_sys.c diff --git a/AltairZ80/altairZ80.txt b/AltairZ80/altairZ80.txt new file mode 100644 index 00000000..90e43ab3 --- /dev/null +++ b/AltairZ80/altairZ80.txt @@ -0,0 +1,375 @@ +Altair 8800 Simulator +===================== + +1. Background. + + The MITS (Micro Instrumentation and Telemetry Systems) Altair 8800 +was announced on the January 1975 cover of Popular Electronics, which +boasted you could buy and build this powerful computer kit for only $397. +The kit consisted at that time of only the parts to build a case, power +supply, card cage (18 slots), CPU card, and memory card with 256 *bytes* of +memory. Still, thousands were ordered within the first few months after the +announcement, starting the personal computer revolution as we know it today. + + Many laugh at the small size of the that first kit, noting there +were no peripherals and the 256 byte memory size. But the computer was an +open system, and by 1977 MITS and many other small startups had added many +expansion cards to make the Altair quite a respectable little computer. The +"Altair Bus" that made this possible was soon called the S-100 Bus, later +adopted as an industry standard, and eventually became the IEE-696 Bus. + +2. Hardware + + We are simulating a fairly "loaded" Altair 8800 from about 1977, +with the following configuration: + + device simulates + name(s) + + CPU Altair 8800 with Intel 8080 CPU board, 62KB + of RAM, 2K of EPROM with start boot ROM. + SIO MITS 88-2SIO Dual Serial Interface Board. Port 1 + is assumed to be connected to a serial "glass + TTY" that is your terminal running the Simulator. + PTR Paper Tape Reader attached to port 2 of the 2SIO board. + PTP Paper Tape Punch attached to port 2 of the + 2SIO board. This also doubles as a printer port. + DSK MITS 88-DISK Floppy Disk controller with up + to eight drives. + +2.1 CPU + + We have 2 CPU options that were not present on the original +machine but are useful in the simulator. We also allow you to select +memory sizes, but be aware that some sample software requires the full +64K (i.e. CP/M) and the MITS Disk Basic and Altair DOS require about +a minimum of 24K. + + SET CPU 8080 Simulates the 8080 CPU (normal) + SET CPU Z80 Simulates the Z80 CPU. Note that some software (e.g. most + original Altair software such as 4K Basic) requires an 8080 CPU and + will not or not properly run on a Z80. This is mainly due to the use + of the parity flag on the 8080 which has not always the same + semantics on the Z80. + SET CPU ITRAP Causes the simulator to halt if an invalid opcode + is detected (depending on the chosen CPU). + SET CPU NOITRAP Does not stop on an invalid Opcode. This is + how the real 8080 works. + SET CPU 4K + SET CPU 8K + SET CPU 12K + SET CPU 16K + ...... + SET CPU 64K All these set various CPU memory configurations. + The 2K EPROM at the high end of memory is always + present and will always boot. + +The BOOT EPROM card starts at address FF00. Jumping to this address +will always boot drive 0 of the floppy controller. 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 +is alot nicer, it will halt but send you back to the simulator command line. + +CPU Registers include the following: + + name size comments + + PC 16 The Program Counter + AF 16 The accumulator and the flag register + F = S Z - AC - P/V N C + S = Sign flag. + Z = Zero Flag. + AC = Auxillary Carry flag. + P/V = Parity flag on 8080 + Parity / Overflow flag on Z80 + - = not used (undefined) + N = Internal sign flag + C = Carry flag. + BC 16 The BC register pair. Register B is the high 8 bits, + C is the lower 8 bits + DE 16 The DE register pair. Register D is the high 8 bits, + E is the lower 8 bits. + HL 16 The HL register pair. Register H is the high 8 bits, + L is the lower 8 bits. + AF1 16 The alternate AF register (only on Z80) + BC1 16 The alternate BC register (only on Z80) + DE1 16 The alternate DE register (only on Z80) + HL1 16 The alternate HL register (only on Z80) + IX 16 The IX index register (only on Z80) + IY 16 The IY index register (only on Z80) + IFF 8 Interrupt flag (only on Z80, no effect) + INT 8 Interrupt register (only on Z80, no effect) + + SR 16 The front panel switches (use D SR 8 for 4k Basic). + WRU 8 The interrupt character. This starts as 5 + (ctrl-E) but some Altair software uses this + keystroke so best to change this to something + exotic such as 035 (which is Ctl-]). + + +2.2 The Serial I/O Card (2SIO) + + This simple programmed I/O device provides 2 serial ports to the +outside world, which could be hardware jumpered to support RS-232 plugs or a +TTY current loop interface. The standard I/O addresses assigned by MITS +was 10-11 (hex) for the first port, and 12-13 (hex) for the second. +We follow this standard in the Simulator. + + The simulator directs I/O to/from the first port to the screen. The +second port reads from an attachable "tape reader" file on input, and writes +to an attachable "punch file" on output. These files are considered a +simple stream of 8-bit bytes. + + The SIO can be configured in SIMH with the following commands: + + SET SIO TTY Bit 8 is set to zero on console output + SET SIO ANSI Bit 8 is not touched on console output + + SET SIO ALL Console input support lower- and upper case + SET SIO UPPER Console input is transformed to upper case characters only + (This feature is useful for most Altair software) + + SET SIO BS Map the delete character to backspace + SET SIO DEL Map the backspace character to delete + + You can also attach the SIO to a port: + + ATTACH SIO 23 Console IO goes via a Telnet connection on port 23 + DETACH SIO Console IO goes via the regular SIMH console + +2.3 The 88-DISK controller. + + The MITS 88-DISK is a simple programmed I/O interface to the MITS +8-inch floppy drive, which was basically a Pertec FD-400 with a power +supply and buffer board builtin. The controller supports neither interrupts +nor DMA, so floppy access required the sustained attention of the CPU. +The standard I/O addresses were 8, 9, and 0A (hex), and we follow the +standard. Details on controlling this hardware are in the altair_dsk.c +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). + + 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) +have been defined with the following meaning: + + 1 Trace all IN and OUT instructions on the disk ports 8 and 9 + 2 Trace all read and writes to full sectors on the disk + 4 Print a message whenever an unnecessary step-in or step out of the + disk head occurs (often an indication of an infinite loop) + 8 Print a message whenever the disk head appears to be waiting for a + sector which does not show up (often an indication of an infinite + loop) + +For example the command "D TRACE 10" will trace options 2+8 from above. + + +3. Sample Software + + Running an Altair in 1977 you would be running either MITS Disk +Extended BASIC, or the brand new and sexy CP/M Operating System from Digital +Research. Or possibly, you ordered Altair DOS back when it was promised in +1975, and are still waiting for it to be delivered in early 1977. + + We have samples of all three for you to check out. We can't go into +the details of how they work, but we'll give you a few hints. + + +3.1 CP/M Version 2.2 + + This version is my own port of the standard CP/M to the Altair. +There were some "official" versions but I don't have them. None were +endorsed or sold by MITS to my knowledge, however. + To boot CP/M: + + sim> attach dsk altcpm.dsk + sim> go ff00 + 62K CP/M VERSION 2.2 (ALTAIR 8800) + A>DIR + + CP/M feels like DOS, sort of. DIR will work. I have included all +the standard CP/M utilities, plus a few common public-domain ones. I also +include the sources to the customized BIOS and some other small programs. +TYPE will print an ASCII file. DUMP will dump a binary one. LS is a better +DIR than DIR. ASM will assemble .ASM files to Hex, LOAD will "load" them to +binary format (.COM). ED is a simple editor, #A command will bring the +source file to the buffer, T command will "type" lines, L will move lines, +E exits the editor. 20L20T will move down 20 lines, and type 20. Very +DECish. DDT is the debugger, SUBMIT is a batch-type command processor. +A sample batch file that will assemble and write out the bootable CP/M +image (on drive A) is "SYSGEN.SUB". To run it, type "SUBMIT SYSGEN". + + In order to efficiently transfer files into the CP/M environment use the +included program READ . If you have a file named foo.ext in +the current directory (i.e. the directory where SIMH is), executing +READ FOO.EXT under CP/M will transfer the file onto the CP/M disk. READ will +only run with Z80 CPU so remember to "SET CPU Z80". + +The disk "altcpm.dsk" contains the following files: +Name Ext Size Comment +ABOOT62 ASM 1K Moves CP/M image from MOVCPM location to real location + in memory +ASM COM 8K Standard CP/M assembler +CALC PRO 3K Prolog sample file "Calculator" +CBIOS ASM 8K BIOS for the Altair (used for sysgen) +COPY COM 1K ALTAIR diskette backup program +CPM62 COM 9K CP/M binary (used for sysgen) +DDT COM 5K Dynamic Debugging Tool (Standard CP/M) +DDTZ COM 10K Dynamic Debugging Tool for Z80 +DUMP ASM 5K Assembler source for DUMP utility +DUMP COM 1K Dumps the contents of a file in hex (Standard CP/M) +ED COM 7K Line oriented editor (Standard CP/M) +FAMILY PRO 2K Prolog sample file "Family relations" +FORMAT COM 2K Formats a disk +INTEGER PRO 1K Prolog sample file "Integer arithmetic" +KNAKE PRO 2K Prolog sample file "Logic puzzle" +LOAD COM 2K Loads a hex file and produces an executable + (Standard CP/M) +LS COM 3K Directory utility +MOVCPM COM 12K Regenerates the CP/M system for a particular + memory size (Standard CP/M) +PINST COM 4K Terminal installer for PROLOGZ.COM +PIP COM 8K Peripheral Interchange Program for copying files + (Standard CP/M) +PROLOGZ COM 17K Prolog development environment +PROLOGZ TXT 40K PROLOGZ documentation in German +PTD ASM 2K Writes Altair-format memory image to disk + (used for sysgen) +QUEEN PRO 2K Prolog sample file "N Queens problem" +READ COM 2K Reads a file from the SIMH filesystem to CP/M +README TXT 3K This file +STAT COM 6K Provides information about drives, disks and + files (Standard CP/M) +SUBMIT COM 2K Submits a file of commands for batch processing + (Standard CP/M) +SURVEY COM 2K Provides information about memory and IO ports +SYSCOPY COM 2K Copies the reserved tracks between disks +SYSGEN SUB 2K Submit file for generating the CP/M system +XSUB COM 2K Addition to SUBMIT such that all input is read + from the submit file (Standard CP/M) + +3.2 MITS Disk Extended BASIC Version 4.1 + + This was the commonly used software for serious users of the Altair +computer. It is a powerful (but slow) BASIC with some extended commands to +allow it to access and manage the disk. There was no operating system it +ran under. To boot: + + sim> set cpu 8080 ;Z80 will not work + sim> attach dsk mbasic.dsk + sim> set sio upper + sim> go ff00 + + MEMORY SIZE? [return] + LINEPRINTER? C [return] + HIGHEST DISK NUMBER? 0 [return] (3 here = 4 drive system) + NUMBER OF FILES? 3 [return] + NUMBER OF RANDOM FILES? 2 [return] + + 44041 BYTES FREE + ALTAIR BASIC REV. 4.1 + [DISK EXTENDED VERSION] + COPYRIGHT 1977 BY MITS INC. + OK + MOUNT 0 + OK + FILES + + +3.3 Altair DOS Version 1.0 + + This was long promised but not delivered until it was almost +irrelevant. A short attempted tour will reveal it to be a dog, far inferior +to CP/M. To boot: + + sim> attach dsk altdos.dsk + sim> set sio upper + sim> go ff00 + + MEMORY SIZE? [return] + INTERRUPTS? N [return] + HIGHEST DISK NUMBER? 0 [return] (3 here = 4 drive system) + HOW MANY DISK FILES? 3 [return] + HOW MANY RANDOM FILES? 2 [return] + + 056449 BYTES AVAILABLE + DOS MONITOR VER 1.0 + COPYRIGHT 1977 BY MITS INC + .MNT 0 + + .DIR 0 + +3.4 Altair 4k Basic + In order to run the famous 4k Basic, use the following commands (the trick +is to get the Switch Register right). + + sim> set cpu 8080 ;note 4k Basic will not run on a Z80 CPU + sim> set sio upper ;4k Basic does not like lower case letters as input + sim> set sio ansi ;4k Basic produces 8-bit output, strip to seven bits + sim> d sr 8 ;good setting for the Switch Register + sim> load 4kbas.bin ;load it + sim> go ;and go + MEMORY SIZE? [return] + TERMINAL WIDTH? [return] + WANT SIN? [Y] + + 61911 BYTES FREE + + BASIC VERSION 3.2 + [4K VERSION] + + OK + +3.5 Altair 8k Basic + Running 8k Basic follows the procedure for 4k Basic. + + sim> set cpu 8080 ;note 8k Basic will not run on a Z80 CPU + sim> set sio upper ;8k Basic does not like lower case letters as input + sim> set sio ansi ;8k Basic produces 8-bit output, strip to seven bits + sim> d sr 8 ;good setting for the Switch Register + sim> load 8kbas.bin ;load it + sim> go ;and go + MEMORY SIZE? [A] + + WRITTEN FOR ROYALTIES BY MICRO-SOFT + + MEMORY SIZE? [return] + TERMINAL WIDTH? [return] + WANT SIN-COS-TAN-ATN? [Y] + + 58756 BYTES FREE + ALTAIR BASIC REV. 4.0 + [EIGHT-K VERSION] + COPYRIGHT 1976 BY MITS INC. + OK + +4. Brief summary of all major changes to the original Altair simulator +- Full support for Z80. CP/M software requiring a Z80 CPU now runs + properly. DDTZ and PROLOGZ are included for demonstration purposes. +- Full assembler and dis-assembler support for Z80 and 8080 mnemonics. + Depending on the current setting of the CPU, the appropriate mnemonics + are used. +- The BOOT ROM was changed to fully load the software from disk. The + original code basically loaded a copy of itself from the disk and + executed it. +- ROM and memory size settings are now fully honored. This means that you + cannot write into the ROM or outside the defined RAM (e.g. when the RAM size + was truncated with the SET CPU commands). This feature allows programs which + check for the size of available RAM to run properly (e.g. 4k Basic). +- The console can also be used via Telnet. This is useful when a terminal is + needed which supports cursor control such as a VT100. PROLOGZ for example + has a built-in screen editor which works under Telnet. +- Simplified file exchange for CP/M. Using the READ program under CP/M one + can easily import files into CP/M from the regular file system. Note that PIP + does not work properly on non-text files on PTR. +- The last character read from PTR is always Control-Z (the EOF character for + CP/M). This makes sure that PIP (Peripheral Interchange Program on CP/M) will + terminate properly. +- Fixed a bug in the BIOS warm boot routine which caused CP/M to crash. +- Modified the BIOS for CP/M to support 8 disks. +- Changed from octal to hex which is more concise. diff --git a/AltairZ80/altairZ80_cpu.c b/AltairZ80/altairZ80_cpu.c new file mode 100644 index 00000000..ad8b1f59 --- /dev/null +++ b/AltairZ80/altairZ80_cpu.c @@ -0,0 +1,3372 @@ +/* altairz80_cpu.c: MITS Altair CPU (8080 and Z80) + Written by Peter Schorn, 2001 + 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) +*/ + +#include +#include "altairZ80_defs.h" + +/*-------------------------------- definitions for memory space --------*/ + +uint8 M[MAXMEMSIZE]; /* RAM which is present */ + +/* two sets of accumulator / flags */ +uint16 af[2]; +int af_sel; + +/* two sets of 16-bit registers */ +struct ddregs { + uint16 bc; + uint16 de; + uint16 hl; +} regs[2]; +int regs_sel; + +uint16 ir; +uint16 ix; +uint16 iy; +uint16 sp; +uint16 pc; +uint16 IFF; + +#define FLAG_C 1 +#define FLAG_N 2 +#define FLAG_P 4 +#define FLAG_H 16 +#define FLAG_Z 64 +#define FLAG_S 128 + +#define SETFLAG(f,c) AF = (c) ? AF | FLAG_ ## f : AF & ~FLAG_ ## f +#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 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 +*/ +#define SetPV ((cpu_unit.flags & UNIT_CHIP) ? (((cbits >> 6) ^ (cbits >> 5)) & 4) : (parity(sum))) +#define SetPV2(x) ((cpu_unit.flags & UNIT_CHIP) ? (((temp == (x)) << 2)) : (parity(temp))) + +/* checkCPU must be invoked whenever a Z80 only instruction is executed */ +#define checkCPU if ((cpu_unit.flags & UNIT_CHIP) == 0) { Bad8080OpOccured = 1; break; } + +static const uint8 partab[256] = { + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 0,4,4,0,4,0,0,4,4,0,0,4,0,4,4,0, + 4,0,0,4,0,4,4,0,0,4,4,0,4,0,0,4, +}; + +#define parity(x) partab[(x)&0xff] + +#define POP(x) do { \ + register uint32 y = RAM_pp(SP); \ + x = y + (RAM_pp(SP) << 8); \ +} while (0) + +#define JPC(cond) PC = cond ? GetWORD(PC) : PC+2 + +#define CALLC(cond) { \ + if (cond) { \ + register uint32 adrr = GetWORD(PC); \ + PUSH(PC+2); \ + PC = adrr; \ + } \ + else \ + PC += 2; \ +} + +int32 saved_PC = 0; /* program counter */ +int32 SR = 0; /* switch register */ +int32 PCX; /* External view of PC */ + +extern int32 sim_int_char; +extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ + +/* function prototypes */ + +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_svc (UNIT *uptr); +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +void clear_memory(int32 starting); + +extern int32 sio0s(int32 io, int32 data); +extern int32 sio0d(int32 io, int32 data); +extern int32 sio1s(int32 io, int32 data); +extern int32 sio1d(int32 io, int32 data); +extern int32 dsk10(int32 io, int32 data); +extern int32 dsk11(int32 io, int32 data); +extern int32 dsk12(int32 io, int32 data); +extern int32 nulldev(int32 io, int32 data); +extern int32 simh_dev(int32 io, int32 data); +extern int32 markTimeSP; + +/* This is the I/O configuration table. There are 255 possible + device addresses, if a device is plugged to a port it's routine + address is here, 'nulldev' means no device is available +*/ +struct idev { + int32 (*routine)(); +}; +struct idev dev_table[256] = { +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 00 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 04 */ +{&dsk10}, {&dsk11}, {&dsk12}, {&nulldev}, /* 08 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 0C */ +{&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /* 10 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 14 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 18 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 1C */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 20 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 24 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 28 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 2C */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 30 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 34 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 38 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 3C */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 40 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 44 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 48 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 4C */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 50 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 54 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 58 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 5C */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 60 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 64 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 68 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 6C */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 70 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 74 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 78 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 7C */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 80 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 84 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 88 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 8C */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 90 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 94 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 98 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 9C */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* A0 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* A4 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* A8 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* AC */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* B0 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* B4 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* B8 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* BC */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* C0 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* C4 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* C8 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* CC */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D0 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D4 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D8 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* DC */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* D0 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* E4 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* E8 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* EC */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F0 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F4 */ +{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* F8 */ +{&nulldev}, {&nulldev}, {&simh_dev}, {&nulldev} }; /* FC */ + +/* Altair MITS modified BOOT EPROM, fits in upper 256 byte of memory */ + +int32 bootrom[bootrom_size] = { + 0x21, 0x00, 0x5c, 0x11, 0x13, 0xff, 0x0e, 0xb9, /* ff00-ff07 */ + 0x1a, 0x77, 0x13, 0x23, 0x0d, 0xc2, 0x08, 0xff, /* ff08-ff0f */ + 0xc3, 0x00, 0x5c, 0x31, 0xa6, 0x5d, 0xaf, 0xd3, /* ff10-ff17 */ + 0x08, 0x3e, 0x04, 0xd3, 0x09, 0xc3, 0x18, 0x5c, /* ff18-ff1f */ + 0xdb, 0x08, 0xe6, 0x02, 0xc2, 0x0d, 0x5c, 0x3e, /* ff20-ff27 */ + 0x02, 0xd3, 0x09, 0xdb, 0x08, 0xe6, 0x40, 0xc2, /* ff28-ff2f */ + 0x0d, 0x5c, 0x11, 0x00, 0x00, 0x06, 0x08, 0xc3, /* ff30-ff37 */ + 0x29, 0x5c, 0x06, 0x00, 0x3e, 0x10, 0xf5, 0xd5, /* ff38-ff3f */ + 0xc5, 0xd5, 0x11, 0x86, 0x80, 0x21, 0xb9, 0x5c, /* ff40-ff47 */ + 0xdb, 0x09, 0x1f, 0xda, 0x35, 0x5c, 0xe6, 0x1f, /* ff48-ff4f */ + 0xb8, 0xc2, 0x35, 0x5c, 0xdb, 0x08, 0xb7, 0xfa, /* ff50-ff57 */ + 0x41, 0x5c, 0xdb, 0x0a, 0x77, 0x23, 0x1d, 0xca, /* ff58-ff5f */ + 0x57, 0x5c, 0x1d, 0xdb, 0x0a, 0x77, 0x23, 0xc2, /* ff60-ff67 */ + 0x41, 0x5c, 0xe1, 0x11, 0xbc, 0x5c, 0x01, 0x80, /* ff68-ff6f */ + 0x00, 0x1a, 0x77, 0xbe, 0x80, 0x47, 0x13, 0x23, /* ff70-ff77 */ + 0x0d, 0xc2, 0x5e, 0x5c, 0x1a, 0xfe, 0xff, 0xc2, /* ff78-ff7f */ + 0x72, 0x5c, 0x13, 0x1a, 0xb8, 0xc1, 0xeb, 0xc2, /* ff80-ff87 */ + 0xac, 0x5c, 0xf1, 0xf1, 0x2a, 0xba, 0x5c, 0xd5, /* ff88-ff8f */ + 0x11, 0x00, 0x5c, 0xcd, 0xb3, 0x5c, 0xd1, 0xcd, /* ff90-ff97 */ + 0xb3, 0x5c, 0xd2, 0xa5, 0x5c, 0x04, 0x04, 0x78, /* ff98-ff9f */ + 0xfe, 0x20, 0xda, 0x29, 0x5c, 0x06, 0x01, 0xca, /* ffa0-ffa7 */ + 0x29, 0x5c, 0xdb, 0x08, 0xe6, 0x02, 0xc2, 0x97, /* ffa8-ffaf */ + 0x5c, 0x3e, 0x01, 0xd3, 0x09, 0xc3, 0x27, 0x5c, /* ffb0-ffb7 */ + 0x3e, 0x80, 0xd3, 0x08, 0xc3, 0x00, 0x00, 0xd1, /* ffb8-ffbf */ + 0xf1, 0x3d, 0xc2, 0x2b, 0x5c, 0x76, 0x7a, 0xbc, /* ffc0-ffc7 */ + 0xc0, 0x7b, 0xbd, 0xc9, 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 */ +}; + +/* CPU data structures + cpu_dev CPU device descriptor + cpu_unit CPU unit descriptor + cpu_reg CPU register list + cpu_mod CPU modifiers list +*/ + +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) }; + +int32 AF_S; +int32 BC_S; +int32 DE_S; +int32 HL_S; +int32 IX_S; +int32 IY_S; +int32 SP_S; +int32 AF1_S; +int32 BC1_S; +int32 DE1_S; +int32 HL1_S; +int32 IFF_S; +int32 INT_S; + +REG cpu_reg[] = { + { HRDATA (PC, saved_PC, 16) }, + { HRDATA (AF, AF_S, 16) }, + { HRDATA (BC, BC_S, 16) }, + { HRDATA (DE, DE_S, 16) }, + { HRDATA (HL, HL_S, 16) }, + { HRDATA (IX, IX_S, 16) }, + { HRDATA (IY, IY_S, 16) }, + { HRDATA (SP, SP_S, 16) }, + { HRDATA (AF1, AF1_S, 16) }, + { HRDATA (BC1, BC1_S, 16) }, + { HRDATA (DE1, DE1_S, 16) }, + { HRDATA (HL1, HL1_S, 16) }, + { FLDATA (IFF, IFF_S, 8) }, + { FLDATA (INT, INT_S, 8) }, + { FLDATA (Z80, cpu_unit.flags, UNIT_V_CHIP), REG_HRO }, + { FLDATA (OPSTOP, cpu_unit.flags, UNIT_V_OPSTOP), REG_HRO }, + { HRDATA (SR, SR, 8) }, + { HRDATA (WRU, sim_int_char, 8) }, + { DRDATA (MARK, markTimeSP, 3), REG_RO }, + { 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_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 }, + { 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 }; + +void out(uint32 Port, uint8 Value) { + dev_table[Port].routine(1, Value); +} + +int in(uint32 Port) { + return Port == 0xFF ? SR & 0xFF : dev_table[Port].routine(0, 0); +} + +inline uint8 GetBYTE(register uint16 a) { + return a < MEMSIZE ? M[a] : 0xff; +} + +#define RAM_mm(a) GetBYTE(a--) +#define RAM_pp(a) GetBYTE(a++) + +inline void PutBYTE(register uint16 Addr, register uint8 Value) { + if ((Addr < MEMSIZE) && (Addr < bootrom_origin)) { + M[Addr] = Value; + } +/* + else { + printf("R/O M[%x]:=%x\n", Addr, Value); + } +*/ +} + +#define PutBYTE_pp(a,v) PutBYTE(a++, v) +#define PutBYTE_mm(a,v) PutBYTE(a--, v) +#define mm_PutBYTE(a,v) PutBYTE(--a, v) + +inline uint16 GetWORD(register uint16 a) {return (GetBYTE(a) | (GetBYTE((a)+1) << 8));} +inline void PutWORD(register uint16 a, register uint16 v) { + PutBYTE(a, (uint8)(v)); + PutBYTE(a+1, v>>8); +} + +#define PUSH(x) do { \ + mm_PutBYTE(SP, (x) >> 8); \ + mm_PutBYTE(SP, x); \ +} while (0) + +int32 sim_instr (void) { + extern int32 sim_interval; + int32 reason = 0; + register uint32 AF; + register uint32 BC; + register uint32 DE; + register uint32 HL; + register uint32 PC; + register uint32 SP; + register uint32 IX; + register uint32 IY; + register uint32 temp, acu, sum, cbits; + register uint32 op, adr; + int32 BadZ80OpOccured = 0; + int32 Bad8080OpOccured = 0; + + pc = saved_PC & ADDRMASK; /* load local PC */ + af[af_sel] = AF_S; + regs[regs_sel].bc = BC_S; + regs[regs_sel].de = DE_S; + regs[regs_sel].hl = HL_S; + ix = IX_S; + iy = IY_S; + sp = SP_S; + af[1-af_sel] = AF1_S; + regs[1-regs_sel].bc = BC1_S; + regs[1-regs_sel].de = DE1_S; + regs[1-regs_sel].hl = HL1_S; + IFF = IFF_S; + ir = INT_S; + + AF = af[af_sel]; + BC = regs[regs_sel].bc; + DE = regs[regs_sel].de; + HL = regs[regs_sel].hl; + PC = pc; + SP = sp; + IX = ix; + IY = iy; + + /* Main instruction fetch/decode loop */ + while (reason == 0) { /* loop until halted */ + 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; + } + + PCX = PC; + sim_interval--; + switch(RAM_pp(PC)) { + case 0x00: /* NOP */ + break; + case 0x01: /* LD BC,nnnn */ + BC = GetWORD(PC); + PC += 2; + break; + case 0x02: /* LD (BC),A */ + PutBYTE(BC, hreg(AF)); + break; + case 0x03: /* INC BC */ + ++BC; + break; + case 0x04: /* INC B */ + BC += 0x100; + temp = hreg(BC); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0) << 4) | + SetPV2(0x80); + break; + case 0x05: /* DEC B */ + BC -= 0x100; + temp = hreg(BC); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0xf) << 4) | + SetPV2(0x7f) | 2; + break; + case 0x06: /* LD B,nn */ + Sethreg(BC, RAM_pp(PC)); + break; + case 0x07: /* RLCA */ + AF = ((AF >> 7) & 0x0128) | ((AF << 1) & ~0x1ff) | + (AF & 0xc4) | ((AF >> 15) & 1); + break; + case 0x08: /* EX AF,AF' */ + checkCPU + af[af_sel] = AF; + af_sel = 1 - af_sel; + AF = af[af_sel]; + break; + case 0x09: /* ADD HL,BC */ + HL &= 0xffff; + BC &= 0xffff; + sum = HL + BC; + cbits = (HL ^ BC ^ sum) >> 8; + HL = sum; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0x0A: /* LD A,(BC) */ + Sethreg(AF, GetBYTE(BC)); + break; + case 0x0B: /* DEC BC */ + --BC; + break; + case 0x0C: /* INC C */ + temp = lreg(BC)+1; + Setlreg(BC, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0) << 4) | + SetPV2(0x80); + break; + case 0x0D: /* DEC C */ + temp = lreg(BC)-1; + Setlreg(BC, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0xf) << 4) | + SetPV2(0x7f) | 2; + break; + case 0x0E: /* LD C,nn */ + Setlreg(BC, RAM_pp(PC)); + break; + case 0x0F: /* RRCA */ + temp = hreg(AF); + sum = temp >> 1; + AF = ((temp & 1) << 15) | (sum << 8) | + (sum & 0x28) | (AF & 0xc4) | (temp & 1); + break; + case 0x10: /* DJNZ dd */ + checkCPU + PC += ((BC -= 0x100) & 0xff00) ? (signed char) GetBYTE(PC) + 1 : 1; + break; + case 0x11: /* LD DE,nnnn */ + DE = GetWORD(PC); + PC += 2; + break; + case 0x12: /* LD (DE),A */ + PutBYTE(DE, hreg(AF)); + break; + case 0x13: /* INC DE */ + ++DE; + break; + case 0x14: /* INC D */ + DE += 0x100; + temp = hreg(DE); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0) << 4) | + SetPV2(0x80); + break; + case 0x15: /* DEC D */ + DE -= 0x100; + temp = hreg(DE); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0xf) << 4) | + SetPV2(0x7f) | 2; + break; + case 0x16: /* LD D,nn */ + Sethreg(DE, RAM_pp(PC)); + break; + case 0x17: /* RLA */ + AF = ((AF << 8) & 0x0100) | ((AF >> 7) & 0x28) | ((AF << 1) & ~0x01ff) | + (AF & 0xc4) | ((AF >> 15) & 1); + break; + case 0x18: /* JR dd */ + checkCPU + PC += (1) ? (signed char) GetBYTE(PC) + 1 : 1; + break; + case 0x19: /* ADD HL,DE */ + HL &= 0xffff; + DE &= 0xffff; + sum = HL + DE; + cbits = (HL ^ DE ^ sum) >> 8; + HL = sum; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0x1A: /* LD A,(DE) */ + Sethreg(AF, GetBYTE(DE)); + break; + case 0x1B: /* DEC DE */ + --DE; + break; + case 0x1C: /* INC E */ + temp = lreg(DE)+1; + Setlreg(DE, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0) << 4) | + SetPV2(0x80); + break; + case 0x1D: /* DEC E */ + temp = lreg(DE)-1; + Setlreg(DE, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0xf) << 4) | + SetPV2(0x7f) | 2; + break; + case 0x1E: /* LD E,nn */ + Setlreg(DE, RAM_pp(PC)); + break; + case 0x1F: /* RRA */ + temp = hreg(AF); + sum = temp >> 1; + AF = ((AF & 1) << 15) | (sum << 8) | + (sum & 0x28) | (AF & 0xc4) | (temp & 1); + break; + case 0x20: /* JR NZ,dd */ + checkCPU + PC += (!TSTFLAG(Z)) ? (signed char) GetBYTE(PC) + 1 : 1; + break; + case 0x21: /* LD HL,nnnn */ + HL = GetWORD(PC); + PC += 2; + break; + case 0x22: /* LD (nnnn),HL */ + temp = GetWORD(PC); + PutWORD(temp, HL); + PC += 2; + break; + case 0x23: /* INC HL */ + ++HL; + break; + case 0x24: /* INC H */ + HL += 0x100; + temp = hreg(HL); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0) << 4) | + SetPV2(0x80); + break; + case 0x25: /* DEC H */ + HL -= 0x100; + temp = hreg(HL); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0xf) << 4) | + SetPV2(0x7f) | 2; + break; + case 0x26: /* LD H,nn */ + Sethreg(HL, RAM_pp(PC)); + break; + case 0x27: /* DAA */ + acu = hreg(AF); + temp = ldig(acu); + cbits = TSTFLAG(C); + if (TSTFLAG(N)) { /* last operation was a subtract */ + int hd = cbits || acu > 0x99; + if (TSTFLAG(H) || (temp > 9)) { /* adjust low digit */ + if (temp > 5) + SETFLAG(H, 0); + acu -= 6; + acu &= 0xff; + } + if (hd) /* adjust high digit */ + acu -= 0x160; + } + else { /* last operation was an add */ + if (TSTFLAG(H) || (temp > 9)) { /* adjust low digit */ + SETFLAG(H, (temp > 9)); + acu += 6; + } + if (cbits || ((acu & 0x1f0) > 0x90)) /* adjust high digit */ + acu += 0x60; + } + cbits |= (acu >> 8) & 1; + acu &= 0xff; + AF = (acu << 8) | (acu & 0xa8) | ((acu == 0) << 6) | + (AF & 0x12) | partab[acu] | cbits; + break; + case 0x28: /* JR Z,dd */ + checkCPU + PC += (TSTFLAG(Z)) ? (signed char) GetBYTE(PC) + 1 : 1; + break; + case 0x29: /* ADD HL,HL */ + HL &= 0xffff; + sum = HL + HL; + cbits = (HL ^ HL ^ sum) >> 8; + HL = sum; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0x2A: /* LD HL,(nnnn) */ + temp = GetWORD(PC); + HL = GetWORD(temp); + PC += 2; + break; + case 0x2B: /* DEC HL */ + --HL; + break; + case 0x2C: /* INC L */ + temp = lreg(HL)+1; + Setlreg(HL, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0) << 4) | + SetPV2(0x80); + break; + case 0x2D: /* DEC L */ + temp = lreg(HL)-1; + Setlreg(HL, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0xf) << 4) | + SetPV2(0x7f) | 2; + break; + case 0x2E: /* LD L,nn */ + Setlreg(HL, RAM_pp(PC)); + break; + case 0x2F: /* CPL */ + AF = (~AF & ~0xff) | (AF & 0xc5) | ((~AF >> 8) & 0x28) | 0x12; + break; + case 0x30: /* JR NC,dd */ + checkCPU + PC += (!TSTFLAG(C)) ? (signed char) GetBYTE(PC) + 1 : 1; + break; + case 0x31: /* LD SP,nnnn */ + SP = GetWORD(PC); + PC += 2; + break; + case 0x32: /* LD (nnnn),A */ + temp = GetWORD(PC); + PutBYTE(temp, hreg(AF)); + PC += 2; + break; + case 0x33: /* INC SP */ + ++SP; + break; + case 0x34: /* INC (HL) */ + temp = GetBYTE(HL)+1; + PutBYTE(HL, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0) << 4) | + SetPV2(0x80); + break; + case 0x35: /* DEC (HL) */ + temp = GetBYTE(HL)-1; + PutBYTE(HL, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0xf) << 4) | + SetPV2(0x7f) | 2; + break; + case 0x36: /* LD (HL),nn */ + PutBYTE(HL, RAM_pp(PC)); + break; + case 0x37: /* SCF */ + AF = (AF&~0x3b)|((AF>>8)&0x28)|1; + break; + case 0x38: /* JR C,dd */ + checkCPU + PC += (TSTFLAG(C)) ? (signed char) GetBYTE(PC) + 1 : 1; + break; + case 0x39: /* ADD HL,SP */ + HL &= 0xffff; + SP &= 0xffff; + sum = HL + SP; + cbits = (HL ^ SP ^ sum) >> 8; + HL = sum; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0x3A: /* LD A,(nnnn) */ + temp = GetWORD(PC); + Sethreg(AF, GetBYTE(temp)); + PC += 2; + break; + case 0x3B: /* DEC SP */ + --SP; + break; + case 0x3C: /* INC A */ + AF += 0x100; + temp = hreg(AF); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0) << 4) | + SetPV2(0x80); + break; + case 0x3D: /* DEC A */ + AF -= 0x100; + temp = hreg(AF); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0xf) << 4) | + SetPV2(0x7f) | 2; + break; + case 0x3E: /* LD A,nn */ + Sethreg(AF, RAM_pp(PC)); + break; + case 0x3F: /* CCF */ + AF = (AF&~0x3b)|((AF>>8)&0x28)|((AF&1)<<4)|(~AF&1); + break; + case 0x40: /* LD B,B */ + /* nop */ + break; + case 0x41: /* LD B,C */ + BC = (BC & 255) | ((BC & 255) << 8); + break; + case 0x42: /* LD B,D */ + BC = (BC & 255) | (DE & ~255); + break; + case 0x43: /* LD B,E */ + BC = (BC & 255) | ((DE & 255) << 8); + break; + case 0x44: /* LD B,H */ + BC = (BC & 255) | (HL & ~255); + break; + case 0x45: /* LD B,L */ + BC = (BC & 255) | ((HL & 255) << 8); + break; + case 0x46: /* LD B,(HL) */ + Sethreg(BC, GetBYTE(HL)); + break; + case 0x47: /* LD B,A */ + BC = (BC & 255) | (AF & ~255); + break; + case 0x48: /* LD C,B */ + BC = (BC & ~255) | ((BC >> 8) & 255); + break; + case 0x49: /* LD C,C */ + /* nop */ + break; + case 0x4A: /* LD C,D */ + BC = (BC & ~255) | ((DE >> 8) & 255); + break; + case 0x4B: /* LD C,E */ + BC = (BC & ~255) | (DE & 255); + break; + case 0x4C: /* LD C,H */ + BC = (BC & ~255) | ((HL >> 8) & 255); + break; + case 0x4D: /* LD C,L */ + BC = (BC & ~255) | (HL & 255); + break; + case 0x4E: /* LD C,(HL) */ + Setlreg(BC, GetBYTE(HL)); + break; + case 0x4F: /* LD C,A */ + BC = (BC & ~255) | ((AF >> 8) & 255); + break; + case 0x50: /* LD D,B */ + DE = (DE & 255) | (BC & ~255); + break; + case 0x51: /* LD D,C */ + DE = (DE & 255) | ((BC & 255) << 8); + break; + case 0x52: /* LD D,D */ + /* nop */ + break; + case 0x53: /* LD D,E */ + DE = (DE & 255) | ((DE & 255) << 8); + break; + case 0x54: /* LD D,H */ + DE = (DE & 255) | (HL & ~255); + break; + case 0x55: /* LD D,L */ + DE = (DE & 255) | ((HL & 255) << 8); + break; + case 0x56: /* LD D,(HL) */ + Sethreg(DE, GetBYTE(HL)); + break; + case 0x57: /* LD D,A */ + DE = (DE & 255) | (AF & ~255); + break; + case 0x58: /* LD E,B */ + DE = (DE & ~255) | ((BC >> 8) & 255); + break; + case 0x59: /* LD E,C */ + DE = (DE & ~255) | (BC & 255); + break; + case 0x5A: /* LD E,D */ + DE = (DE & ~255) | ((DE >> 8) & 255); + break; + case 0x5B: /* LD E,E */ + /* nop */ + break; + case 0x5C: /* LD E,H */ + DE = (DE & ~255) | ((HL >> 8) & 255); + break; + case 0x5D: /* LD E,L */ + DE = (DE & ~255) | (HL & 255); + break; + case 0x5E: /* LD E,(HL) */ + Setlreg(DE, GetBYTE(HL)); + break; + case 0x5F: /* LD E,A */ + DE = (DE & ~255) | ((AF >> 8) & 255); + break; + case 0x60: /* LD H,B */ + HL = (HL & 255) | (BC & ~255); + break; + case 0x61: /* LD H,C */ + HL = (HL & 255) | ((BC & 255) << 8); + break; + case 0x62: /* LD H,D */ + HL = (HL & 255) | (DE & ~255); + break; + case 0x63: /* LD H,E */ + HL = (HL & 255) | ((DE & 255) << 8); + break; + case 0x64: /* LD H,H */ + /* nop */ + break; + case 0x65: /* LD H,L */ + HL = (HL & 255) | ((HL & 255) << 8); + break; + case 0x66: /* LD H,(HL) */ + Sethreg(HL, GetBYTE(HL)); + break; + case 0x67: /* LD H,A */ + HL = (HL & 255) | (AF & ~255); + break; + case 0x68: /* LD L,B */ + HL = (HL & ~255) | ((BC >> 8) & 255); + break; + case 0x69: /* LD L,C */ + HL = (HL & ~255) | (BC & 255); + break; + case 0x6A: /* LD L,D */ + HL = (HL & ~255) | ((DE >> 8) & 255); + break; + case 0x6B: /* LD L,E */ + HL = (HL & ~255) | (DE & 255); + break; + case 0x6C: /* LD L,H */ + HL = (HL & ~255) | ((HL >> 8) & 255); + break; + case 0x6D: /* LD L,L */ + /* nop */ + break; + case 0x6E: /* LD L,(HL) */ + Setlreg(HL, GetBYTE(HL)); + break; + case 0x6F: /* LD L,A */ + HL = (HL & ~255) | ((AF >> 8) & 255); + break; + case 0x70: /* LD (HL),B */ + PutBYTE(HL, hreg(BC)); + break; + case 0x71: /* LD (HL),C */ + PutBYTE(HL, lreg(BC)); + break; + case 0x72: /* LD (HL),D */ + PutBYTE(HL, hreg(DE)); + break; + case 0x73: /* LD (HL),E */ + PutBYTE(HL, lreg(DE)); + break; + case 0x74: /* LD (HL),H */ + PutBYTE(HL, hreg(HL)); + break; + case 0x75: /* LD (HL),L */ + PutBYTE(HL, lreg(HL)); + break; + case 0x76: /* HALT */ + reason = STOP_HALT; + PC--; + continue; + case 0x77: /* LD (HL),A */ + PutBYTE(HL, hreg(AF)); + break; + case 0x78: /* LD A,B */ + AF = (AF & 255) | (BC & ~255); + break; + case 0x79: /* LD A,C */ + AF = (AF & 255) | ((BC & 255) << 8); + break; + case 0x7A: /* LD A,D */ + AF = (AF & 255) | (DE & ~255); + break; + case 0x7B: /* LD A,E */ + AF = (AF & 255) | ((DE & 255) << 8); + break; + case 0x7C: /* LD A,H */ + AF = (AF & 255) | (HL & ~255); + break; + case 0x7D: /* LD A,L */ + AF = (AF & 255) | ((HL & 255) << 8); + break; + case 0x7E: /* LD A,(HL) */ + Sethreg(AF, GetBYTE(HL)); + break; + case 0x7F: /* LD A,A */ + /* nop */ + break; + case 0x80: /* ADD A,B */ + temp = hreg(BC); + acu = hreg(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | + ((cbits >> 8) & 1); + break; + case 0x81: /* ADD A,C */ + temp = lreg(BC); + acu = hreg(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | + ((cbits >> 8) & 1); + break; + case 0x82: /* ADD A,D */ + temp = hreg(DE); + acu = hreg(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | + ((cbits >> 8) & 1); + break; + case 0x83: /* ADD A,E */ + temp = lreg(DE); + acu = hreg(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | + ((cbits >> 8) & 1); + break; + case 0x84: /* ADD A,H */ + temp = hreg(HL); + acu = hreg(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | + ((cbits >> 8) & 1); + break; + case 0x85: /* ADD A,L */ + temp = lreg(HL); + acu = hreg(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | + ((cbits >> 8) & 1); + break; + case 0x86: /* ADD A,(HL) */ + temp = GetBYTE(HL); + acu = hreg(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | + ((cbits >> 8) & 1); + break; + case 0x87: /* ADD A,A */ + temp = hreg(AF); + acu = hreg(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | + ((cbits >> 8) & 1); + break; + case 0x88: /* ADC A,B */ + temp = hreg(BC); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | + ((cbits >> 8) & 1); + break; + case 0x89: /* ADC A,C */ + temp = lreg(BC); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | + ((cbits >> 8) & 1); + break; + case 0x8A: /* ADC A,D */ + temp = hreg(DE); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | + ((cbits >> 8) & 1); + break; + case 0x8B: /* ADC A,E */ + temp = lreg(DE); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | + ((cbits >> 8) & 1); + break; + case 0x8C: /* ADC A,H */ + temp = hreg(HL); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | + ((cbits >> 8) & 1); + break; + case 0x8D: /* ADC A,L */ + temp = lreg(HL); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | + ((cbits >> 8) & 1); + break; + case 0x8E: /* ADC A,(HL) */ + temp = GetBYTE(HL); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | + ((cbits >> 8) & 1); + break; + case 0x8F: /* ADC A,A */ + temp = hreg(AF); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | + ((cbits >> 8) & 1); + break; + case 0x90: /* SUB B */ + temp = hreg(BC); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | 2 | + ((cbits >> 8) & 1); + break; + case 0x91: /* SUB C */ + temp = lreg(BC); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | 2 | + ((cbits >> 8) & 1); + break; + case 0x92: /* SUB D */ + temp = hreg(DE); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | 2 | + ((cbits >> 8) & 1); + break; + case 0x93: /* SUB E */ + temp = lreg(DE); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | 2 | + ((cbits >> 8) & 1); + break; + case 0x94: /* SUB H */ + temp = hreg(HL); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | 2 | + ((cbits >> 8) & 1); + break; + case 0x95: /* SUB L */ + temp = lreg(HL); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | 2 | + ((cbits >> 8) & 1); + break; + case 0x96: /* SUB (HL) */ + temp = GetBYTE(HL); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | 2 | + ((cbits >> 8) & 1); + break; + case 0x97: /* SUB A */ + temp = hreg(AF); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | 2 | + ((cbits >> 8) & 1); + break; + case 0x98: /* SBC A,B */ + temp = hreg(BC); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | 2 | + ((cbits >> 8) & 1); + break; + case 0x99: /* SBC A,C */ + temp = lreg(BC); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | 2 | + ((cbits >> 8) & 1); + break; + case 0x9A: /* SBC A,D */ + temp = hreg(DE); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | 2 | + ((cbits >> 8) & 1); + break; + case 0x9B: /* SBC A,E */ + temp = lreg(DE); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | 2 | + ((cbits >> 8) & 1); + break; + case 0x9C: /* SBC A,H */ + temp = hreg(HL); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | 2 | + ((cbits >> 8) & 1); + break; + case 0x9D: /* SBC A,L */ + temp = lreg(HL); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | 2 | + ((cbits >> 8) & 1); + break; + case 0x9E: /* SBC A,(HL) */ + temp = GetBYTE(HL); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | 2 | + ((cbits >> 8) & 1); + break; + case 0x9F: /* SBC A,A */ + temp = hreg(AF); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | 2 | + ((cbits >> 8) & 1); + break; + case 0xA0: /* AND B */ + sum = ((AF & (BC)) >> 8) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | + ((sum == 0) << 6) | 0x10 | partab[sum]; + break; + case 0xA1: /* AND C */ + sum = ((AF >> 8) & BC) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | 0x10 | + ((sum == 0) << 6) | partab[sum]; + break; + case 0xA2: /* AND D */ + sum = ((AF & (DE)) >> 8) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | + ((sum == 0) << 6) | 0x10 | partab[sum]; + break; + case 0xA3: /* AND E */ + sum = ((AF >> 8) & DE) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | 0x10 | + ((sum == 0) << 6) | partab[sum]; + break; + case 0xA4: /* AND H */ + sum = ((AF & (HL)) >> 8) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | + ((sum == 0) << 6) | 0x10 | partab[sum]; + break; + case 0xA5: /* AND L */ + sum = ((AF >> 8) & HL) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | 0x10 | + ((sum == 0) << 6) | partab[sum]; + break; + case 0xA6: /* AND (HL) */ + sum = ((AF >> 8) & GetBYTE(HL)) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | 0x10 | + ((sum == 0) << 6) | partab[sum]; + break; + case 0xA7: /* AND A */ + sum = ((AF & (AF)) >> 8) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | + ((sum == 0) << 6) | 0x10 | partab[sum]; + break; + case 0xA8: /* XOR B */ + sum = ((AF ^ (BC)) >> 8) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xA9: /* XOR C */ + sum = ((AF >> 8) ^ BC) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xAA: /* XOR D */ + sum = ((AF ^ (DE)) >> 8) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xAB: /* XOR E */ + sum = ((AF >> 8) ^ DE) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xAC: /* XOR H */ + sum = ((AF ^ (HL)) >> 8) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xAD: /* XOR L */ + sum = ((AF >> 8) ^ HL) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xAE: /* XOR (HL) */ + sum = ((AF >> 8) ^ GetBYTE(HL)) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xAF: /* XOR A */ + sum = ((AF ^ (AF)) >> 8) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xB0: /* OR B */ + sum = ((AF | (BC)) >> 8) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xB1: /* OR C */ + sum = ((AF >> 8) | BC) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xB2: /* OR D */ + sum = ((AF | (DE)) >> 8) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xB3: /* OR E */ + sum = ((AF >> 8) | DE) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xB4: /* OR H */ + sum = ((AF | (HL)) >> 8) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xB5: /* OR L */ + sum = ((AF >> 8) | HL) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xB6: /* OR (HL) */ + sum = ((AF >> 8) | GetBYTE(HL)) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xB7: /* OR A */ + sum = ((AF | (AF)) >> 8) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xB8: /* CP B */ + temp = hreg(BC); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | (sum & 0x80) | + (((sum & 0xff) == 0) << 6) | (temp & 0x28) | + (SetPV) | 2 | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0xB9: /* CP C */ + temp = lreg(BC); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | (sum & 0x80) | + (((sum & 0xff) == 0) << 6) | (temp & 0x28) | + (SetPV) | 2 | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0xBA: /* CP D */ + temp = hreg(DE); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | (sum & 0x80) | + (((sum & 0xff) == 0) << 6) | (temp & 0x28) | + (SetPV) | 2 | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0xBB: /* CP E */ + temp = lreg(DE); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | (sum & 0x80) | + (((sum & 0xff) == 0) << 6) | (temp & 0x28) | + (SetPV) | 2 | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0xBC: /* CP H */ + temp = hreg(HL); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | (sum & 0x80) | + (((sum & 0xff) == 0) << 6) | (temp & 0x28) | + (SetPV) | 2 | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0xBD: /* CP L */ + temp = lreg(HL); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | (sum & 0x80) | + (((sum & 0xff) == 0) << 6) | (temp & 0x28) | + (SetPV) | 2 | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0xBE: /* CP (HL) */ + temp = GetBYTE(HL); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | (sum & 0x80) | + (((sum & 0xff) == 0) << 6) | (temp & 0x28) | + (SetPV) | 2 | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0xBF: /* CP A */ + temp = hreg(AF); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | (sum & 0x80) | + (((sum & 0xff) == 0) << 6) | (temp & 0x28) | + (SetPV) | 2 | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0xC0: /* RET NZ */ + if (!TSTFLAG(Z)) POP(PC); + break; + case 0xC1: /* POP BC */ + POP(BC); + break; + case 0xC2: /* JP NZ,nnnn */ + JPC(!TSTFLAG(Z)); + break; + case 0xC3: /* JP nnnn */ + JPC(1); + break; + case 0xC4: /* CALL NZ,nnnn */ + CALLC(!TSTFLAG(Z)); + break; + case 0xC5: /* PUSH BC */ + PUSH(BC); + break; + case 0xC6: /* ADD A,nn */ + temp = RAM_pp(PC); + acu = hreg(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | + ((cbits >> 8) & 1); + break; + case 0xC7: /* RST 0 */ + PUSH(PC); PC = 0; + break; + case 0xC8: /* RET Z */ + if (TSTFLAG(Z)) POP(PC); + break; + case 0xC9: /* RET */ + POP(PC); + break; + case 0xCA: /* JP Z,nnnn */ + JPC(TSTFLAG(Z)); + break; + case 0xCB: /* CB prefix */ + checkCPU + adr = HL; + switch ((op = GetBYTE(PC)) & 7) { + case 0: ++PC; acu = hreg(BC); break; + case 1: ++PC; acu = lreg(BC); break; + case 2: ++PC; acu = hreg(DE); break; + case 3: ++PC; acu = lreg(DE); break; + case 4: ++PC; acu = hreg(HL); break; + case 5: ++PC; acu = lreg(HL); break; + case 6: ++PC; acu = GetBYTE(adr); break; + case 7: ++PC; acu = hreg(AF); break; + } + switch (op & 0xc0) { + case 0x00: /* shift/rotate */ + switch (op & 0x38) { + case 0x00: /* RLC */ + temp = (acu << 1) | (acu >> 7); + cbits = temp & 1; + goto cbshflg1; + case 0x08: /* RRC */ + temp = (acu >> 1) | (acu << 7); + cbits = temp & 0x80; + goto cbshflg1; + case 0x10: /* RL */ + temp = (acu << 1) | TSTFLAG(C); + cbits = acu & 0x80; + goto cbshflg1; + case 0x18: /* RR */ + temp = (acu >> 1) | (TSTFLAG(C) << 7); + cbits = acu & 1; + goto cbshflg1; + case 0x20: /* SLA */ + temp = acu << 1; + cbits = acu & 0x80; + goto cbshflg1; + case 0x28: /* SRA */ + temp = (acu >> 1) | (acu & 0x80); + cbits = acu & 1; + goto cbshflg1; + case 0x30: /* SLIA */ + temp = (acu << 1) | 1; + cbits = acu & 0x80; + goto cbshflg1; + case 0x38: /* SRL */ + temp = acu >> 1; + cbits = acu & 1; + cbshflg1: + AF = (AF & ~0xff) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + parity(temp) | !!cbits; + } + break; + case 0x40: /* BIT */ + if (acu & (1 << ((op >> 3) & 7))) + AF = (AF & ~0xfe) | 0x10 | + (((op & 0x38) == 0x38) << 7); + else + AF = (AF & ~0xfe) | 0x54; + if ((op&7) != 6) + AF |= (acu & 0x28); + temp = acu; + break; + case 0x80: /* RES */ + temp = acu & ~(1 << ((op >> 3) & 7)); + break; + case 0xc0: /* SET */ + temp = acu | (1 << ((op >> 3) & 7)); + break; + } + switch (op & 7) { + case 0: Sethreg(BC, temp); break; + case 1: Setlreg(BC, temp); break; + case 2: Sethreg(DE, temp); break; + case 3: Setlreg(DE, temp); break; + case 4: Sethreg(HL, temp); break; + case 5: Setlreg(HL, temp); break; + case 6: PutBYTE(adr, temp); break; + case 7: Sethreg(AF, temp); break; + } + break; + case 0xCC: /* CALL Z,nnnn */ + CALLC(TSTFLAG(Z)); + break; + case 0xCD: /* CALL nnnn */ + CALLC(1); + break; + case 0xCE: /* ADC A,nn */ + temp = RAM_pp(PC); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | + ((cbits >> 8) & 1); + break; + case 0xCF: /* RST 8 */ + PUSH(PC); PC = 8; + break; + case 0xD0: /* RET NC */ + if (!TSTFLAG(C)) POP(PC); + break; + case 0xD1: /* POP DE */ + POP(DE); + break; + case 0xD2: /* JP NC,nnnn */ + JPC(!TSTFLAG(C)); + break; + case 0xD3: /* OUT (nn),A */ + out(RAM_pp(PC), hreg(AF)); + break; + case 0xD4: /* CALL NC,nnnn */ + CALLC(!TSTFLAG(C)); + break; + case 0xD5: /* PUSH DE */ + PUSH(DE); + break; + case 0xD6: /* SUB nn */ + temp = RAM_pp(PC); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | 2 | + ((cbits >> 8) & 1); + break; + case 0xD7: /* RST 10H */ + PUSH(PC); PC = 0x10; + break; + case 0xD8: /* RET C */ + if (TSTFLAG(C)) POP(PC); + break; + case 0xD9: /* EXX */ + checkCPU + regs[regs_sel].bc = BC; + regs[regs_sel].de = DE; + regs[regs_sel].hl = HL; + regs_sel = 1 - regs_sel; + BC = regs[regs_sel].bc; + DE = regs[regs_sel].de; + HL = regs[regs_sel].hl; + break; + case 0xDA: /* JP C,nnnn */ + JPC(TSTFLAG(C)); + break; + case 0xDB: /* IN A,(nn) */ + Sethreg(AF, in(RAM_pp(PC))); + break; + case 0xDC: /* CALL C,nnnn */ + CALLC(TSTFLAG(C)); + break; + case 0xDD: /* DD prefix */ + checkCPU + switch (op = RAM_pp(PC)) { + case 0x09: /* ADD IX,BC */ + IX &= 0xffff; + BC &= 0xffff; + sum = IX + BC; + cbits = (IX ^ BC ^ sum) >> 8; + IX = sum; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0x19: /* ADD IX,DE */ + IX &= 0xffff; + DE &= 0xffff; + sum = IX + DE; + cbits = (IX ^ DE ^ sum) >> 8; + IX = sum; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0x21: /* LD IX,nnnn */ + IX = GetWORD(PC); + PC += 2; + break; + case 0x22: /* LD (nnnn),IX */ + temp = GetWORD(PC); + PutWORD(temp, IX); + PC += 2; + break; + case 0x23: /* INC IX */ + ++IX; + break; + case 0x24: /* INC IXH */ + IX += 0x100; + temp = hreg(IX); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0) << 4) | + ((temp == 0x80) << 2); + break; + case 0x25: /* DEC IXH */ + IX -= 0x100; + temp = hreg(IX); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0xf) << 4) | + ((temp == 0x7f) << 2) | 2; + break; + case 0x26: /* LD IXH,nn */ + Sethreg(IX, RAM_pp(PC)); + break; + case 0x29: /* ADD IX,IX */ + IX &= 0xffff; + sum = IX + IX; + cbits = (IX ^ IX ^ sum) >> 8; + IX = sum; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0x2A: /* LD IX,(nnnn) */ + temp = GetWORD(PC); + IX = GetWORD(temp); + PC += 2; + break; + case 0x2B: /* DEC IX */ + --IX; + break; + case 0x2C: /* INC IXL */ + temp = lreg(IX)+1; + Setlreg(IX, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0) << 4) | + ((temp == 0x80) << 2); + break; + case 0x2D: /* DEC IXL */ + temp = lreg(IX)-1; + Setlreg(IX, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0xf) << 4) | + ((temp == 0x7f) << 2) | 2; + break; + case 0x2E: /* LD IXL,nn */ + Setlreg(IX, RAM_pp(PC)); + break; + case 0x34: /* INC (IX+dd) */ + adr = IX + (signed char) RAM_pp(PC); + temp = GetBYTE(adr)+1; + PutBYTE(adr, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0) << 4) | + ((temp == 0x80) << 2); + break; + case 0x35: /* DEC (IX+dd) */ + adr = IX + (signed char) RAM_pp(PC); + temp = GetBYTE(adr)-1; + PutBYTE(adr, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0xf) << 4) | + ((temp == 0x7f) << 2) | 2; + break; + case 0x36: /* LD (IX+dd),nn */ + adr = IX + (signed char) RAM_pp(PC); + PutBYTE(adr, RAM_pp(PC)); + break; + case 0x39: /* ADD IX,SP */ + IX &= 0xffff; + SP &= 0xffff; + sum = IX + SP; + cbits = (IX ^ SP ^ sum) >> 8; + IX = sum; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0x44: /* LD B,IXH */ + Sethreg(BC, hreg(IX)); + break; + case 0x45: /* LD B,IXL */ + Sethreg(BC, lreg(IX)); + break; + case 0x46: /* LD B,(IX+dd) */ + adr = IX + (signed char) RAM_pp(PC); + Sethreg(BC, GetBYTE(adr)); + break; + case 0x4C: /* LD C,IXH */ + Setlreg(BC, hreg(IX)); + break; + case 0x4D: /* LD C,IXL */ + Setlreg(BC, lreg(IX)); + break; + case 0x4E: /* LD C,(IX+dd) */ + adr = IX + (signed char) RAM_pp(PC); + Setlreg(BC, GetBYTE(adr)); + break; + case 0x54: /* LD D,IXH */ + Sethreg(DE, hreg(IX)); + break; + case 0x55: /* LD D,IXL */ + Sethreg(DE, lreg(IX)); + break; + case 0x56: /* LD D,(IX+dd) */ + adr = IX + (signed char) RAM_pp(PC); + Sethreg(DE, GetBYTE(adr)); + break; + case 0x5C: /* LD E,H */ + Setlreg(DE, hreg(IX)); + break; + case 0x5D: /* LD E,L */ + Setlreg(DE, lreg(IX)); + break; + case 0x5E: /* LD E,(IX+dd) */ + adr = IX + (signed char) RAM_pp(PC); + Setlreg(DE, GetBYTE(adr)); + break; + case 0x60: /* LD IXH,B */ + Sethreg(IX, hreg(BC)); + break; + case 0x61: /* LD IXH,C */ + Sethreg(IX, lreg(BC)); + break; + case 0x62: /* LD IXH,D */ + Sethreg(IX, hreg(DE)); + break; + case 0x63: /* LD IXH,E */ + Sethreg(IX, lreg(DE)); + break; + case 0x64: /* LD IXH,IXH */ + /* nop */ + break; + case 0x65: /* LD IXH,IXL */ + Sethreg(IX, lreg(IX)); + break; + case 0x66: /* LD H,(IX+dd) */ + adr = IX + (signed char) RAM_pp(PC); + Sethreg(HL, GetBYTE(adr)); + break; + case 0x67: /* LD IXH,A */ + Sethreg(IX, hreg(AF)); + break; + case 0x68: /* LD IXL,B */ + Setlreg(IX, hreg(BC)); + break; + case 0x69: /* LD IXL,C */ + Setlreg(IX, lreg(BC)); + break; + case 0x6A: /* LD IXL,D */ + Setlreg(IX, hreg(DE)); + break; + case 0x6B: /* LD IXL,E */ + Setlreg(IX, lreg(DE)); + break; + case 0x6C: /* LD IXL,IXH */ + Setlreg(IX, hreg(IX)); + break; + case 0x6D: /* LD IXL,IXL */ + /* nop */ + break; + case 0x6E: /* LD L,(IX+dd) */ + adr = IX + (signed char) RAM_pp(PC); + Setlreg(HL, GetBYTE(adr)); + break; + case 0x6F: /* LD IXL,A */ + Setlreg(IX, hreg(AF)); + break; + case 0x70: /* LD (IX+dd),B */ + adr = IX + (signed char) RAM_pp(PC); + PutBYTE(adr, hreg(BC)); + break; + case 0x71: /* LD (IX+dd),C */ + adr = IX + (signed char) RAM_pp(PC); + PutBYTE(adr, lreg(BC)); + break; + case 0x72: /* LD (IX+dd),D */ + adr = IX + (signed char) RAM_pp(PC); + PutBYTE(adr, hreg(DE)); + break; + case 0x73: /* LD (IX+dd),E */ + adr = IX + (signed char) RAM_pp(PC); + PutBYTE(adr, lreg(DE)); + break; + case 0x74: /* LD (IX+dd),H */ + adr = IX + (signed char) RAM_pp(PC); + PutBYTE(adr, hreg(HL)); + break; + case 0x75: /* LD (IX+dd),L */ + adr = IX + (signed char) RAM_pp(PC); + PutBYTE(adr, lreg(HL)); + break; + case 0x77: /* LD (IX+dd),A */ + adr = IX + (signed char) RAM_pp(PC); + PutBYTE(adr, hreg(AF)); + break; + case 0x7C: /* LD A,IXH */ + Sethreg(AF, hreg(IX)); + break; + case 0x7D: /* LD A,IXL */ + Sethreg(AF, lreg(IX)); + break; + case 0x7E: /* LD A,(IX+dd) */ + adr = IX + (signed char) RAM_pp(PC); + Sethreg(AF, GetBYTE(adr)); + break; + case 0x84: /* ADD A,IXH */ + temp = hreg(IX); + acu = hreg(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | + ((cbits >> 8) & 1); + break; + case 0x85: /* ADD A,IXL */ + temp = lreg(IX); + acu = hreg(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | + ((cbits >> 8) & 1); + break; + case 0x86: /* ADD A,(IX+dd) */ + adr = IX + (signed char) RAM_pp(PC); + temp = GetBYTE(adr); + acu = hreg(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | + ((cbits >> 8) & 1); + break; + case 0x8C: /* ADC A,IXH */ + temp = hreg(IX); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | + ((cbits >> 8) & 1); + break; + case 0x8D: /* ADC A,IXL */ + temp = lreg(IX); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | + ((cbits >> 8) & 1); + break; + case 0x8E: /* ADC A,(IX+dd) */ + adr = IX + (signed char) RAM_pp(PC); + temp = GetBYTE(adr); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | + ((cbits >> 8) & 1); + break; + case 0x94: /* SUB IXH */ + temp = hreg(IX); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | + ((cbits >> 8) & 1); + break; + case 0x95: /* SUB IXL */ + temp = lreg(IX); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | + ((cbits >> 8) & 1); + break; + case 0x96: /* SUB (IX+dd) */ + adr = IX + (signed char) RAM_pp(PC); + temp = GetBYTE(adr); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | + ((cbits >> 8) & 1); + break; + case 0x9C: /* SBC A,IXH */ + temp = hreg(IX); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | + ((cbits >> 8) & 1); + break; + case 0x9D: /* SBC A,IXL */ + temp = lreg(IX); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | + ((cbits >> 8) & 1); + break; + case 0x9E: /* SBC A,(IX+dd) */ + adr = IX + (signed char) RAM_pp(PC); + temp = GetBYTE(adr); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | + ((cbits >> 8) & 1); + break; + case 0xA4: /* AND IXH */ + sum = ((AF & (IX)) >> 8) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | + ((sum == 0) << 6) | 0x10 | partab[sum]; + break; + case 0xA5: /* AND IXL */ + sum = ((AF >> 8) & IX) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | 0x10 | + ((sum == 0) << 6) | partab[sum]; + break; + case 0xA6: /* AND (IX+dd) */ + adr = IX + (signed char) RAM_pp(PC); + sum = ((AF >> 8) & GetBYTE(adr)) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | 0x10 | + ((sum == 0) << 6) | partab[sum]; + break; + case 0xAC: /* XOR IXH */ + sum = ((AF ^ (IX)) >> 8) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xAD: /* XOR IXL */ + sum = ((AF >> 8) ^ IX) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xAE: /* XOR (IX+dd) */ + adr = IX + (signed char) RAM_pp(PC); + sum = ((AF >> 8) ^ GetBYTE(adr)) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xB4: /* OR IXH */ + sum = ((AF | (IX)) >> 8) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xB5: /* OR IXL */ + sum = ((AF >> 8) | IX) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xB6: /* OR (IX+dd) */ + adr = IX + (signed char) RAM_pp(PC); + sum = ((AF >> 8) | GetBYTE(adr)) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xBC: /* CP IXH */ + temp = hreg(IX); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | (sum & 0x80) | + (((sum & 0xff) == 0) << 6) | (temp & 0x28) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0xBD: /* CP IXL */ + temp = lreg(IX); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | (sum & 0x80) | + (((sum & 0xff) == 0) << 6) | (temp & 0x28) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0xBE: /* CP (IX+dd) */ + adr = IX + (signed char) RAM_pp(PC); + temp = GetBYTE(adr); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | (sum & 0x80) | + (((sum & 0xff) == 0) << 6) | (temp & 0x28) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0xCB: /* CB prefix */ + adr = IX + (signed char) RAM_pp(PC); + adr = adr; + switch ((op = GetBYTE(PC)) & 7) { + case 0: ++PC; acu = hreg(BC); break; + case 1: ++PC; acu = lreg(BC); break; + case 2: ++PC; acu = hreg(DE); break; + case 3: ++PC; acu = lreg(DE); break; + case 4: ++PC; acu = hreg(HL); break; + case 5: ++PC; acu = lreg(HL); break; + case 6: ++PC; acu = GetBYTE(adr); break; + case 7: ++PC; acu = hreg(AF); break; + } + switch (op & 0xc0) { + case 0x00: /* shift/rotate */ + switch (op & 0x38) { + case 0x00: /* RLC */ + temp = (acu << 1) | (acu >> 7); + cbits = temp & 1; + goto cbshflg2; + case 0x08: /* RRC */ + temp = (acu >> 1) | (acu << 7); + cbits = temp & 0x80; + goto cbshflg2; + case 0x10: /* RL */ + temp = (acu << 1) | TSTFLAG(C); + cbits = acu & 0x80; + goto cbshflg2; + case 0x18: /* RR */ + temp = (acu >> 1) | (TSTFLAG(C) << 7); + cbits = acu & 1; + goto cbshflg2; + case 0x20: /* SLA */ + temp = acu << 1; + cbits = acu & 0x80; + goto cbshflg2; + case 0x28: /* SRA */ + temp = (acu >> 1) | (acu & 0x80); + cbits = acu & 1; + goto cbshflg2; + case 0x30: /* SLIA */ + temp = (acu << 1) | 1; + cbits = acu & 0x80; + goto cbshflg2; + case 0x38: /* SRL */ + temp = acu >> 1; + cbits = acu & 1; + cbshflg2: + AF = (AF & ~0xff) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + parity(temp) | !!cbits; + } + break; + case 0x40: /* BIT */ + if (acu & (1 << ((op >> 3) & 7))) + AF = (AF & ~0xfe) | 0x10 | + (((op & 0x38) == 0x38) << 7); + else + AF = (AF & ~0xfe) | 0x54; + if ((op&7) != 6) + AF |= (acu & 0x28); + temp = acu; + break; + case 0x80: /* RES */ + temp = acu & ~(1 << ((op >> 3) & 7)); + break; + case 0xc0: /* SET */ + temp = acu | (1 << ((op >> 3) & 7)); + break; + } + switch (op & 7) { + case 0: Sethreg(BC, temp); break; + case 1: Setlreg(BC, temp); break; + case 2: Sethreg(DE, temp); break; + case 3: Setlreg(DE, temp); break; + case 4: Sethreg(HL, temp); break; + case 5: Setlreg(HL, temp); break; + case 6: PutBYTE(adr, temp); break; + case 7: Sethreg(AF, temp); break; + } + break; + case 0xE1: /* POP IX */ + POP(IX); + break; + case 0xE3: /* EX (SP),IX */ + temp = IX; POP(IX); PUSH(temp); + break; + case 0xE5: /* PUSH IX */ + PUSH(IX); + break; + case 0xE9: /* JP (IX) */ + PC = IX; + break; + case 0xF9: /* LD SP,IX */ + SP = IX; + break; + default: /* ignore DD */ + BadZ80OpOccured = 1; + PC--; + } + break; + case 0xDE: /* SBC A,nn */ + temp = RAM_pp(PC); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (SetPV) | 2 | + ((cbits >> 8) & 1); + break; + case 0xDF: /* RST 18H */ + PUSH(PC); PC = 0x18; + break; + case 0xE0: /* RET PO */ + if (!TSTFLAG(P)) POP(PC); + break; + case 0xE1: /* POP HL */ + POP(HL); + break; + case 0xE2: /* JP PO,nnnn */ + JPC(!TSTFLAG(P)); + break; + case 0xE3: /* EX (SP),HL */ + temp = HL; POP(HL); PUSH(temp); + break; + case 0xE4: /* CALL PO,nnnn */ + CALLC(!TSTFLAG(P)); + break; + case 0xE5: /* PUSH HL */ + PUSH(HL); + break; + case 0xE6: /* AND nn */ + sum = ((AF >> 8) & RAM_pp(PC)) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | 0x10 | + ((sum == 0) << 6) | partab[sum]; + break; + case 0xE7: /* RST 20H */ + PUSH(PC); PC = 0x20; + break; + case 0xE8: /* RET PE */ + if (TSTFLAG(P)) POP(PC); + break; + case 0xE9: /* JP (HL) */ + PC = HL; + break; + case 0xEA: /* JP PE,nnnn */ + JPC(TSTFLAG(P)); + break; + case 0xEB: /* EX DE,HL */ + temp = HL; HL = DE; DE = temp; + break; + case 0xEC: /* CALL PE,nnnn */ + CALLC(TSTFLAG(P)); + break; + case 0xED: /* ED prefix */ + checkCPU + switch (op = RAM_pp(PC)) { + case 0x40: /* IN B,(C) */ + temp = in(lreg(BC)); + Sethreg(BC, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + parity(temp); + break; + case 0x41: /* OUT (C),B */ + out(lreg(BC), hreg(BC)); + break; + case 0x42: /* SBC HL,BC */ + HL &= 0xffff; + BC &= 0xffff; + sum = HL - BC - TSTFLAG(C); + cbits = (HL ^ BC ^ sum) >> 8; + HL = sum; + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | + (((sum & 0xffff) == 0) << 6) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | + (cbits & 0x10) | 2 | ((cbits >> 8) & 1); + break; + case 0x43: /* LD (nnnn),BC */ + temp = GetWORD(PC); + PutWORD(temp, BC); + PC += 2; + break; + case 0x44: /* NEG */ + temp = hreg(AF); + AF = (-(AF & 0xff00) & 0xff00); + AF |= ((AF >> 8) & 0xa8) | (((AF & 0xff00) == 0) << 6) | + (((temp & 0x0f) != 0) << 4) | + ((temp == 0x80) << 2) | + 2 | (temp != 0); + break; + case 0x45: /* RETN */ + IFF |= IFF >> 1; + POP(PC); + break; + case 0x46: /* IM 0 */ + /* interrupt mode 0 */ + break; + case 0x47: /* LD I,A */ + ir = (ir & 255) | (AF & ~255); + break; + case 0x48: /* IN C,(C) */ + temp = in(lreg(BC)); + Setlreg(BC, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + parity(temp); + break; + case 0x49: /* OUT (C),C */ + out(lreg(BC), lreg(BC)); + break; + case 0x4A: /* ADC HL,BC */ + HL &= 0xffff; + BC &= 0xffff; + sum = HL + BC + TSTFLAG(C); + cbits = (HL ^ BC ^ sum) >> 8; + HL = sum; + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | + (((sum & 0xffff) == 0) << 6) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0x4B: /* LD BC,(nnnn) */ + temp = GetWORD(PC); + BC = GetWORD(temp); + PC += 2; + break; + case 0x4D: /* RETI */ + IFF |= IFF >> 1; + POP(PC); + break; + case 0x4F: /* LD R,A */ + ir = (ir & ~255) | ((AF >> 8) & 255); + break; + case 0x50: /* IN D,(C) */ + temp = in(lreg(BC)); + Sethreg(DE, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + parity(temp); + break; + case 0x51: /* OUT (C),D */ + out(lreg(BC), hreg(DE)); + break; + case 0x52: /* SBC HL,DE */ + HL &= 0xffff; + DE &= 0xffff; + sum = HL - DE - TSTFLAG(C); + cbits = (HL ^ DE ^ sum) >> 8; + HL = sum; + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | + (((sum & 0xffff) == 0) << 6) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | + (cbits & 0x10) | 2 | ((cbits >> 8) & 1); + break; + case 0x53: /* LD (nnnn),DE */ + temp = GetWORD(PC); + PutWORD(temp, DE); + PC += 2; + break; + case 0x56: /* IM 1 */ + /* interrupt mode 1 */ + break; + case 0x57: /* LD A,I */ + AF = (AF & 0x29) | (ir & ~255) | ((ir >> 8) & 0x80) | (((ir & ~255) == 0) << 6) | ((IFF & 2) << 1); + break; + case 0x58: /* IN E,(C) */ + temp = in(lreg(BC)); + Setlreg(DE, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + parity(temp); + break; + case 0x59: /* OUT (C),E */ + out(lreg(BC), lreg(DE)); + break; + case 0x5A: /* ADC HL,DE */ + HL &= 0xffff; + DE &= 0xffff; + sum = HL + DE + TSTFLAG(C); + cbits = (HL ^ DE ^ sum) >> 8; + HL = sum; + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | + (((sum & 0xffff) == 0) << 6) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0x5B: /* LD DE,(nnnn) */ + temp = GetWORD(PC); + DE = GetWORD(temp); + PC += 2; + break; + case 0x5E: /* IM 2 */ + /* interrupt mode 2 */ + break; + case 0x5F: /* LD A,R */ + AF = (AF & 0x29) | ((ir & 255) << 8) | (ir & 0x80) | (((ir & 255) == 0) << 6) | ((IFF & 2) << 1); + break; + case 0x60: /* IN H,(C) */ + temp = in(lreg(BC)); + Sethreg(HL, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + parity(temp); + break; + case 0x61: /* OUT (C),H */ + out(lreg(BC), hreg(HL)); + break; + case 0x62: /* SBC HL,HL */ + HL &= 0xffff; + sum = HL - HL - TSTFLAG(C); + cbits = (HL ^ HL ^ sum) >> 8; + HL = sum; + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | + (((sum & 0xffff) == 0) << 6) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | + (cbits & 0x10) | 2 | ((cbits >> 8) & 1); + break; + case 0x63: /* LD (nnnn),HL */ + temp = GetWORD(PC); + PutWORD(temp, HL); + PC += 2; + break; + case 0x67: /* RRD */ + temp = GetBYTE(HL); + acu = hreg(AF); + PutBYTE(HL, hdig(temp) | (ldig(acu) << 4)); + acu = (acu & 0xf0) | ldig(temp); + AF = (acu << 8) | (acu & 0xa8) | (((acu & 0xff) == 0) << 6) | + partab[acu] | (AF & 1); + break; + case 0x68: /* IN L,(C) */ + temp = in(lreg(BC)); + Setlreg(HL, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + parity(temp); + break; + case 0x69: /* OUT (C),L */ + out(lreg(BC), lreg(HL)); + break; + case 0x6A: /* ADC HL,HL */ + HL &= 0xffff; + sum = HL + HL + TSTFLAG(C); + cbits = (HL ^ HL ^ sum) >> 8; + HL = sum; + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | + (((sum & 0xffff) == 0) << 6) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0x6B: /* LD HL,(nnnn) */ + temp = GetWORD(PC); + HL = GetWORD(temp); + PC += 2; + break; + case 0x6F: /* RLD */ + temp = GetBYTE(HL); + acu = hreg(AF); + PutBYTE(HL, (ldig(temp) << 4) | ldig(acu)); + acu = (acu & 0xf0) | hdig(temp); + AF = (acu << 8) | (acu & 0xa8) | (((acu & 0xff) == 0) << 6) | + partab[acu] | (AF & 1); + break; + case 0x70: /* IN (C) */ + temp = in(lreg(BC)); + Setlreg(temp, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + parity(temp); + break; + case 0x71: /* OUT (C),0 */ + out(lreg(BC), 0); + break; + case 0x72: /* SBC HL,SP */ + HL &= 0xffff; + SP &= 0xffff; + sum = HL - SP - TSTFLAG(C); + cbits = (HL ^ SP ^ sum) >> 8; + HL = sum; + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | + (((sum & 0xffff) == 0) << 6) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | + (cbits & 0x10) | 2 | ((cbits >> 8) & 1); + break; + case 0x73: /* LD (nnnn),SP */ + temp = GetWORD(PC); + PutWORD(temp, SP); + PC += 2; + break; + case 0x78: /* IN A,(C) */ + temp = in(lreg(BC)); + Sethreg(AF, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + parity(temp); + break; + case 0x79: /* OUT (C),A */ + out(lreg(BC), hreg(AF)); + break; + case 0x7A: /* ADC HL,SP */ + HL &= 0xffff; + SP &= 0xffff; + sum = HL + SP + TSTFLAG(C); + cbits = (HL ^ SP ^ sum) >> 8; + HL = sum; + AF = (AF & ~0xff) | ((sum >> 8) & 0xa8) | + (((sum & 0xffff) == 0) << 6) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0x7B: /* LD SP,(nnnn) */ + temp = GetWORD(PC); + SP = GetWORD(temp); + PC += 2; + break; + case 0xA0: /* LDI */ + acu = RAM_pp(HL); + PutBYTE_pp(DE, acu); + acu += hreg(AF); + AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4) | + (((--BC & 0xffff) != 0) << 2); + break; + case 0xA1: /* CPI */ + acu = hreg(AF); + temp = RAM_pp(HL); + 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 >> 4) & 1)) & 8) | + ((--BC & 0xffff) != 0) << 2 | 2; + if ((sum & 15) == 8 && (cbits & 16) != 0) + AF &= ~8; + break; + case 0xA2: /* INI */ + PutBYTE(HL, in(lreg(BC))); ++HL; + SETFLAG(N, 1); + SETFLAG(P, (--BC & 0xffff) != 0); + break; + case 0xA3: /* OUTI */ + out(lreg(BC), GetBYTE(HL)); ++HL; + SETFLAG(N, 1); + Sethreg(BC, lreg(BC) - 1); + SETFLAG(Z, lreg(BC) == 0); + break; + case 0xA8: /* LDD */ + acu = RAM_mm(HL); + PutBYTE_mm(DE, acu); + acu += hreg(AF); + AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4) | + (((--BC & 0xffff) != 0) << 2); + break; + case 0xA9: /* CPD */ + acu = hreg(AF); + temp = RAM_mm(HL); + 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 >> 4) & 1)) & 8) | + ((--BC & 0xffff) != 0) << 2 | 2; + if ((sum & 15) == 8 && (cbits & 16) != 0) + AF &= ~8; + break; + case 0xAA: /* IND */ + PutBYTE(HL, in(lreg(BC))); --HL; + SETFLAG(N, 1); + Sethreg(BC, lreg(BC) - 1); + SETFLAG(Z, lreg(BC) == 0); + break; + case 0xAB: /* OUTD */ + out(lreg(BC), GetBYTE(HL)); --HL; + SETFLAG(N, 1); + Sethreg(BC, lreg(BC) - 1); + SETFLAG(Z, lreg(BC) == 0); + break; + case 0xB0: /* LDIR */ + acu = hreg(AF); + BC &= 0xffff; + do { + acu = RAM_pp(HL); + PutBYTE_pp(DE, acu); + } while (--BC); + acu += hreg(AF); + AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4); + break; + case 0xB1: /* CPIR */ + acu = hreg(AF); + BC &= 0xffff; + do { + temp = RAM_pp(HL); + op = --BC != 0; + sum = acu - temp; + } while (op && sum != 0); + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | + (((sum - ((cbits&16)>>4))&2) << 4) | + (cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) | + op << 2 | 2; + if ((sum & 15) == 8 && (cbits & 16) != 0) + AF &= ~8; + break; + case 0xB2: /* INIR */ + temp = hreg(BC); + do { + PutBYTE(HL, in(lreg(BC))); ++HL; + } while (--temp); + Sethreg(BC, 0); + SETFLAG(N, 1); + SETFLAG(Z, 1); + break; + case 0xB3: /* OTIR */ + temp = hreg(BC); + do { + out(lreg(BC), GetBYTE(HL)); ++HL; + } while (--temp); + Sethreg(BC, 0); + SETFLAG(N, 1); + SETFLAG(Z, 1); + break; + case 0xB8: /* LDDR */ + BC &= 0xffff; + do { + acu = RAM_mm(HL); + PutBYTE_mm(DE, acu); + } while (--BC); + acu += hreg(AF); + AF = (AF & ~0x3e) | (acu & 8) | ((acu & 2) << 4); + break; + case 0xB9: /* CPDR */ + acu = hreg(AF); + BC &= 0xffff; + do { + temp = RAM_mm(HL); + op = --BC != 0; + sum = acu - temp; + } while (op && sum != 0); + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xfe) | (sum & 0x80) | (!(sum & 0xff) << 6) | + (((sum - ((cbits&16)>>4))&2) << 4) | + (cbits & 16) | ((sum - ((cbits >> 4) & 1)) & 8) | + op << 2 | 2; + if ((sum & 15) == 8 && (cbits & 16) != 0) + AF &= ~8; + break; + case 0xBA: /* INDR */ + temp = hreg(BC); + do { + PutBYTE(HL, in(lreg(BC))); --HL; + } while (--temp); + Sethreg(BC, 0); + SETFLAG(N, 1); + SETFLAG(Z, 1); + break; + case 0xBB: /* OTDR */ + temp = hreg(BC); + do { + out(lreg(BC), GetBYTE(HL)); --HL; + } while (--temp); + Sethreg(BC, 0); + SETFLAG(N, 1); + SETFLAG(Z, 1); + break; + default: /* ignore ED and following byte */ + BadZ80OpOccured = 1; + } + break; + case 0xEE: /* XOR nn */ + sum = ((AF >> 8) ^ RAM_pp(PC)) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xEF: /* RST 28H */ + PUSH(PC); PC = 0x28; + break; + case 0xF0: /* RET P */ + if (!TSTFLAG(S)) POP(PC); + break; + case 0xF1: /* POP AF */ + POP(AF); + break; + case 0xF2: /* JP P,nnnn */ + JPC(!TSTFLAG(S)); + break; + case 0xF3: /* DI */ + IFF = 0; + break; + case 0xF4: /* CALL P,nnnn */ + CALLC(!TSTFLAG(S)); + break; + case 0xF5: /* PUSH AF */ + PUSH(AF); + break; + case 0xF6: /* OR nn */ + sum = ((AF >> 8) | RAM_pp(PC)) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xF7: /* RST 30H */ + PUSH(PC); PC = 0x30; + break; + case 0xF8: /* RET M */ + if (TSTFLAG(S)) POP(PC); + break; + case 0xF9: /* LD SP,HL */ + SP = HL; + break; + case 0xFA: /* JP M,nnnn */ + JPC(TSTFLAG(S)); + break; + case 0xFB: /* EI */ + IFF = 3; + break; + case 0xFC: /* CALL M,nnnn */ + CALLC(TSTFLAG(S)); + break; + case 0xFD: /* FD prefix */ + checkCPU + switch (op = RAM_pp(PC)) { + case 0x09: /* ADD IY,BC */ + IY &= 0xffff; + BC &= 0xffff; + sum = IY + BC; + cbits = (IY ^ BC ^ sum) >> 8; + IY = sum; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0x19: /* ADD IY,DE */ + IY &= 0xffff; + DE &= 0xffff; + sum = IY + DE; + cbits = (IY ^ DE ^ sum) >> 8; + IY = sum; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0x21: /* LD IY,nnnn */ + IY = GetWORD(PC); + PC += 2; + break; + case 0x22: /* LD (nnnn),IY */ + temp = GetWORD(PC); + PutWORD(temp, IY); + PC += 2; + break; + case 0x23: /* INC IY */ + ++IY; + break; + case 0x24: /* INC IYH */ + IY += 0x100; + temp = hreg(IY); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0) << 4) | + ((temp == 0x80) << 2); + break; + case 0x25: /* DEC IYH */ + IY -= 0x100; + temp = hreg(IY); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0xf) << 4) | + ((temp == 0x7f) << 2) | 2; + break; + case 0x26: /* LD IYH,nn */ + Sethreg(IY, RAM_pp(PC)); + break; + case 0x29: /* ADD IY,IY */ + IY &= 0xffff; + sum = IY + IY; + cbits = (IY ^ IY ^ sum) >> 8; + IY = sum; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0x2A: /* LD IY,(nnnn) */ + temp = GetWORD(PC); + IY = GetWORD(temp); + PC += 2; + break; + case 0x2B: /* DEC IY */ + --IY; + break; + case 0x2C: /* INC IYL */ + temp = lreg(IY)+1; + Setlreg(IY, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0) << 4) | + ((temp == 0x80) << 2); + break; + case 0x2D: /* DEC IYL */ + temp = lreg(IY)-1; + Setlreg(IY, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0xf) << 4) | + ((temp == 0x7f) << 2) | 2; + break; + case 0x2E: /* LD IYL,nn */ + Setlreg(IY, RAM_pp(PC)); + break; + case 0x34: /* INC (IY+dd) */ + adr = IY + (signed char) RAM_pp(PC); + temp = GetBYTE(adr)+1; + PutBYTE(adr, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0) << 4) | + ((temp == 0x80) << 2); + break; + case 0x35: /* DEC (IY+dd) */ + adr = IY + (signed char) RAM_pp(PC); + temp = GetBYTE(adr)-1; + PutBYTE(adr, temp); + AF = (AF & ~0xfe) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + (((temp & 0xf) == 0xf) << 4) | + ((temp == 0x7f) << 2) | 2; + break; + case 0x36: /* LD (IY+dd),nn */ + adr = IY + (signed char) RAM_pp(PC); + PutBYTE(adr, RAM_pp(PC)); + break; + case 0x39: /* ADD IY,SP */ + IY &= 0xffff; + SP &= 0xffff; + sum = IY + SP; + cbits = (IY ^ SP ^ sum) >> 8; + IY = sum; + AF = (AF & ~0x3b) | ((sum >> 8) & 0x28) | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0x44: /* LD B,IYH */ + Sethreg(BC, hreg(IY)); + break; + case 0x45: /* LD B,IYL */ + Sethreg(BC, lreg(IY)); + break; + case 0x46: /* LD B,(IY+dd) */ + adr = IY + (signed char) RAM_pp(PC); + Sethreg(BC, GetBYTE(adr)); + break; + case 0x4C: /* LD C,IYH */ + Setlreg(BC, hreg(IY)); + break; + case 0x4D: /* LD C,IYL */ + Setlreg(BC, lreg(IY)); + break; + case 0x4E: /* LD C,(IY+dd) */ + adr = IY + (signed char) RAM_pp(PC); + Setlreg(BC, GetBYTE(adr)); + break; + case 0x54: /* LD D,IYH */ + Sethreg(DE, hreg(IY)); + break; + case 0x55: /* LD D,IYL */ + Sethreg(DE, lreg(IY)); + break; + case 0x56: /* LD D,(IY+dd) */ + adr = IY + (signed char) RAM_pp(PC); + Sethreg(DE, GetBYTE(adr)); + break; + case 0x5C: /* LD E,H */ + Setlreg(DE, hreg(IY)); + break; + case 0x5D: /* LD E,L */ + Setlreg(DE, lreg(IY)); + break; + case 0x5E: /* LD E,(IY+dd) */ + adr = IY + (signed char) RAM_pp(PC); + Setlreg(DE, GetBYTE(adr)); + break; + case 0x60: /* LD IYH,B */ + Sethreg(IY, hreg(BC)); + break; + case 0x61: /* LD IYH,C */ + Sethreg(IY, lreg(BC)); + break; + case 0x62: /* LD IYH,D */ + Sethreg(IY, hreg(DE)); + break; + case 0x63: /* LD IYH,E */ + Sethreg(IY, lreg(DE)); + break; + case 0x64: /* LD IYH,IYH */ + /* nop */ + break; + case 0x65: /* LD IYH,IYL */ + Sethreg(IY, lreg(IY)); + break; + case 0x66: /* LD H,(IY+dd) */ + adr = IY + (signed char) RAM_pp(PC); + Sethreg(HL, GetBYTE(adr)); + break; + case 0x67: /* LD IYH,A */ + Sethreg(IY, hreg(AF)); + break; + case 0x68: /* LD IYL,B */ + Setlreg(IY, hreg(BC)); + break; + case 0x69: /* LD IYL,C */ + Setlreg(IY, lreg(BC)); + break; + case 0x6A: /* LD IYL,D */ + Setlreg(IY, hreg(DE)); + break; + case 0x6B: /* LD IYL,E */ + Setlreg(IY, lreg(DE)); + break; + case 0x6C: /* LD IYL,IYH */ + Setlreg(IY, hreg(IY)); + break; + case 0x6D: /* LD IYL,IYL */ + /* nop */ + break; + case 0x6E: /* LD L,(IY+dd) */ + adr = IY + (signed char) RAM_pp(PC); + Setlreg(HL, GetBYTE(adr)); + break; + case 0x6F: /* LD IYL,A */ + Setlreg(IY, hreg(AF)); + break; + case 0x70: /* LD (IY+dd),B */ + adr = IY + (signed char) RAM_pp(PC); + PutBYTE(adr, hreg(BC)); + break; + case 0x71: /* LD (IY+dd),C */ + adr = IY + (signed char) RAM_pp(PC); + PutBYTE(adr, lreg(BC)); + break; + case 0x72: /* LD (IY+dd),D */ + adr = IY + (signed char) RAM_pp(PC); + PutBYTE(adr, hreg(DE)); + break; + case 0x73: /* LD (IY+dd),E */ + adr = IY + (signed char) RAM_pp(PC); + PutBYTE(adr, lreg(DE)); + break; + case 0x74: /* LD (IY+dd),H */ + adr = IY + (signed char) RAM_pp(PC); + PutBYTE(adr, hreg(HL)); + break; + case 0x75: /* LD (IY+dd),L */ + adr = IY + (signed char) RAM_pp(PC); + PutBYTE(adr, lreg(HL)); + break; + case 0x77: /* LD (IY+dd),A */ + adr = IY + (signed char) RAM_pp(PC); + PutBYTE(adr, hreg(AF)); + break; + case 0x7C: /* LD A,IYH */ + Sethreg(AF, hreg(IY)); + break; + case 0x7D: /* LD A,IYL */ + Sethreg(AF, lreg(IY)); + break; + case 0x7E: /* LD A,(IY+dd) */ + adr = IY + (signed char) RAM_pp(PC); + Sethreg(AF, GetBYTE(adr)); + break; + case 0x84: /* ADD A,IYH */ + temp = hreg(IY); + acu = hreg(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | + ((cbits >> 8) & 1); + break; + case 0x85: /* ADD A,IYL */ + temp = lreg(IY); + acu = hreg(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | + ((cbits >> 8) & 1); + break; + case 0x86: /* ADD A,(IY+dd) */ + adr = IY + (signed char) RAM_pp(PC); + temp = GetBYTE(adr); + acu = hreg(AF); + sum = acu + temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | + ((cbits >> 8) & 1); + break; + case 0x8C: /* ADC A,IYH */ + temp = hreg(IY); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | + ((cbits >> 8) & 1); + break; + case 0x8D: /* ADC A,IYL */ + temp = lreg(IY); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | + ((cbits >> 8) & 1); + break; + case 0x8E: /* ADC A,(IY+dd) */ + adr = IY + (signed char) RAM_pp(PC); + temp = GetBYTE(adr); + acu = hreg(AF); + sum = acu + temp + TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | + ((cbits >> 8) & 1); + break; + case 0x94: /* SUB IYH */ + temp = hreg(IY); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | + ((cbits >> 8) & 1); + break; + case 0x95: /* SUB IYL */ + temp = lreg(IY); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | + ((cbits >> 8) & 1); + break; + case 0x96: /* SUB (IY+dd) */ + adr = IY + (signed char) RAM_pp(PC); + temp = GetBYTE(adr); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | + ((cbits >> 8) & 1); + break; + case 0x9C: /* SBC A,IYH */ + temp = hreg(IY); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | + ((cbits >> 8) & 1); + break; + case 0x9D: /* SBC A,IYL */ + temp = lreg(IY); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | + ((cbits >> 8) & 1); + break; + case 0x9E: /* SBC A,(IY+dd) */ + adr = IY + (signed char) RAM_pp(PC); + temp = GetBYTE(adr); + acu = hreg(AF); + sum = acu - temp - TSTFLAG(C); + cbits = acu ^ temp ^ sum; + AF = ((sum & 0xff) << 8) | (sum & 0xa8) | + (((sum & 0xff) == 0) << 6) | (cbits & 0x10) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | + ((cbits >> 8) & 1); + break; + case 0xA4: /* AND IYH */ + sum = ((AF & (IY)) >> 8) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | + ((sum == 0) << 6) | 0x10 | partab[sum]; + break; + case 0xA5: /* AND IYL */ + sum = ((AF >> 8) & IY) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | 0x10 | + ((sum == 0) << 6) | partab[sum]; + break; + case 0xA6: /* AND (IY+dd) */ + adr = IY + (signed char) RAM_pp(PC); + sum = ((AF >> 8) & GetBYTE(adr)) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | 0x10 | + ((sum == 0) << 6) | partab[sum]; + break; + case 0xAC: /* XOR IYH */ + sum = ((AF ^ (IY)) >> 8) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xAD: /* XOR IYL */ + sum = ((AF >> 8) ^ IY) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xAE: /* XOR (IY+dd) */ + adr = IY + (signed char) RAM_pp(PC); + sum = ((AF >> 8) ^ GetBYTE(adr)) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xB4: /* OR IYH */ + sum = ((AF | (IY)) >> 8) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xB5: /* OR IYL */ + sum = ((AF >> 8) | IY) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xB6: /* OR (IY+dd) */ + adr = IY + (signed char) RAM_pp(PC); + sum = ((AF >> 8) | GetBYTE(adr)) & 0xff; + AF = (sum << 8) | (sum & 0xa8) | ((sum == 0) << 6) | partab[sum]; + break; + case 0xBC: /* CP IYH */ + temp = hreg(IY); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | (sum & 0x80) | + (((sum & 0xff) == 0) << 6) | (temp & 0x28) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0xBD: /* CP IYL */ + temp = lreg(IY); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | (sum & 0x80) | + (((sum & 0xff) == 0) << 6) | (temp & 0x28) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0xBE: /* CP (IY+dd) */ + adr = IY + (signed char) RAM_pp(PC); + temp = GetBYTE(adr); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | (sum & 0x80) | + (((sum & 0xff) == 0) << 6) | (temp & 0x28) | + (((cbits >> 6) ^ (cbits >> 5)) & 4) | 2 | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0xCB: /* CB prefix */ + adr = IY + (signed char) RAM_pp(PC); + adr = adr; + switch ((op = GetBYTE(PC)) & 7) { + case 0: ++PC; acu = hreg(BC); break; + case 1: ++PC; acu = lreg(BC); break; + case 2: ++PC; acu = hreg(DE); break; + case 3: ++PC; acu = lreg(DE); break; + case 4: ++PC; acu = hreg(HL); break; + case 5: ++PC; acu = lreg(HL); break; + case 6: ++PC; acu = GetBYTE(adr); break; + case 7: ++PC; acu = hreg(AF); break; + } + switch (op & 0xc0) { + case 0x00: /* shift/rotate */ + switch (op & 0x38) { + case 0x00: /* RLC */ + temp = (acu << 1) | (acu >> 7); + cbits = temp & 1; + goto cbshflg3; + case 0x08: /* RRC */ + temp = (acu >> 1) | (acu << 7); + cbits = temp & 0x80; + goto cbshflg3; + case 0x10: /* RL */ + temp = (acu << 1) | TSTFLAG(C); + cbits = acu & 0x80; + goto cbshflg3; + case 0x18: /* RR */ + temp = (acu >> 1) | (TSTFLAG(C) << 7); + cbits = acu & 1; + goto cbshflg3; + case 0x20: /* SLA */ + temp = acu << 1; + cbits = acu & 0x80; + goto cbshflg3; + case 0x28: /* SRA */ + temp = (acu >> 1) | (acu & 0x80); + cbits = acu & 1; + goto cbshflg3; + case 0x30: /* SLIA */ + temp = (acu << 1) | 1; + cbits = acu & 0x80; + goto cbshflg3; + case 0x38: /* SRL */ + temp = acu >> 1; + cbits = acu & 1; + cbshflg3: + AF = (AF & ~0xff) | (temp & 0xa8) | + (((temp & 0xff) == 0) << 6) | + parity(temp) | !!cbits; + } + break; + case 0x40: /* BIT */ + if (acu & (1 << ((op >> 3) & 7))) + AF = (AF & ~0xfe) | 0x10 | + (((op & 0x38) == 0x38) << 7); + else + AF = (AF & ~0xfe) | 0x54; + if ((op&7) != 6) + AF |= (acu & 0x28); + temp = acu; + break; + case 0x80: /* RES */ + temp = acu & ~(1 << ((op >> 3) & 7)); + break; + case 0xc0: /* SET */ + temp = acu | (1 << ((op >> 3) & 7)); + break; + } + switch (op & 7) { + case 0: Sethreg(BC, temp); break; + case 1: Setlreg(BC, temp); break; + case 2: Sethreg(DE, temp); break; + case 3: Setlreg(DE, temp); break; + case 4: Sethreg(HL, temp); break; + case 5: Setlreg(HL, temp); break; + case 6: PutBYTE(adr, temp); break; + case 7: Sethreg(AF, temp); break; + } + break; + case 0xE1: /* POP IY */ + POP(IY); + break; + case 0xE3: /* EX (SP),IY */ + temp = IY; POP(IY); PUSH(temp); + break; + case 0xE5: /* PUSH IY */ + PUSH(IY); + break; + case 0xE9: /* JP (IY) */ + PC = IY; + break; + case 0xF9: /* LD SP,IY */ + SP = IY; + break; + default: /* ignore FD */ + BadZ80OpOccured = 1; + PC--; + } + break; + case 0xFE: /* CP nn */ + temp = RAM_pp(PC); + AF = (AF & ~0x28) | (temp & 0x28); + acu = hreg(AF); + sum = acu - temp; + cbits = acu ^ temp ^ sum; + AF = (AF & ~0xff) | (sum & 0x80) | + (((sum & 0xff) == 0) << 6) | (temp & 0x28) | + (SetPV) | 2 | + (cbits & 0x10) | ((cbits >> 8) & 1); + break; + case 0xFF: /* RST 38H */ + PUSH(PC); PC = 0x38; + } + if ((BadZ80OpOccured || Bad8080OpOccured) && (cpu_unit.flags & UNIT_OPSTOP)) { + reason = STOP_OPCODE; + } + } + pc = PC; + af[af_sel] = AF; + regs[regs_sel].bc = BC; + regs[regs_sel].de = DE; + regs[regs_sel].hl = HL; + ix = IX; + iy = IY; + sp = SP; + + /* Simulation halted */ + saved_PC = (reason == STOP_OPCODE) ? PCX : pc; + AF_S = af[af_sel]; + BC_S = regs[regs_sel].bc; + DE_S = regs[regs_sel].de; + HL_S = regs[regs_sel].hl; + IX_S = ix; + IY_S = iy; + SP_S = sp; + AF1_S = af[1-af_sel]; + BC1_S = regs[1-regs_sel].bc; + DE1_S = regs[1-regs_sel].de; + HL1_S = regs[1-regs_sel].hl; + IFF_S = IFF; + INT_S = ir; + return reason; +} + +void clear_memory(int32 starting) { + int32 i; + for (i = starting; i < MAXMEMSIZE; i++) { + M[i] = 0; + } + for (i = 0; i < bootrom_size; i++) { + M[i + bootrom_origin] = bootrom[i] & 0xFF; + } +} + +/* Reset routine */ + +t_stat cpu_reset (DEVICE *dptr) + +{ + af[0] = af[1] = 0; + af_sel = 0; + regs[0].bc = regs[0].de = regs[0].hl = 0; + regs_sel = 0; + regs[1].bc = regs[1].de = regs[1].hl = 0; + ir = ix = iy = sp = pc = IFF = 0; + saved_PC = 0; + clear_memory(0); + markTimeSP = 0; + sim_brk_types = sim_brk_dflt = SWMASK ('E'); + return SCPE_OK; +} + +/* Memory examine */ + +t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) +{ + if ((addr >= MEMSIZE) && (addr < bootrom_origin)) { + return SCPE_NXM; + } + if (vptr != NULL) { + *vptr = M[addr] & 0xff; + } + return SCPE_OK; +} + +/* Memory deposit */ + +t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) +{ + if ((addr >= MEMSIZE) || (addr >= bootrom_origin)) { + return SCPE_NXM; + } + M[addr] = val & 0xff; + return SCPE_OK; +} + +t_stat cpu_set_size (UNIT *uptr, int32 value, char *cptr, void *desc) +{ + int32 mc = 0; + t_addr i; + int32 limit; + + if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 0xFFF) != 0)) { + return SCPE_ARG; + } + limit = (bootrom_origin < MEMSIZE) ? bootrom_origin : MEMSIZE; + for (i = value; i < limit; i++) { + mc |= M[i]; + } + if (mc && (!get_yn ("Really truncate memory [N]?", FALSE))) { + return SCPE_OK; + } + MEMSIZE = value; + clear_memory(value); + return SCPE_OK; +} diff --git a/AltairZ80/altairZ80_defs.h b/AltairZ80/altairZ80_defs.h new file mode 100644 index 00000000..93776ccd --- /dev/null +++ b/AltairZ80/altairZ80_defs.h @@ -0,0 +1,30 @@ +/* altairZ80_defs.h: MITS Altair simulator definitions + Written by Peter Schorn, 2001 + Based on work by Charles E Owen ((c) 1997, Commercial use prohibited) +*/ + +#include "sim_defs.h" /* simulator definitions */ + +/* Memory */ +#define MAXMEMSIZE 65536 /* max memory size */ +#define KB 1024 /* kilo byte */ +#define MEMSIZE (cpu_unit.capac) /* actual memory size */ +#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */ +#define bootrom_size 256 /* size of boot rom */ +#define bootrom_origin 0xFF00 /* start address of boot rom */ + +#define BACKSPACE_CHAR 0x08 /* backspace character */ +#define DELETE_CHAR 0x7f /* delete character */ +#define CONTROLZ_CHAR 26 /* control Z character */ + +/* Simulator stop codes */ +#define STOP_HALT 2 /* HALT */ +#define STOP_IBKPT 3 /* breakpoint */ +#define STOP_OPCODE 4 + +#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) diff --git a/AltairZ80/altairZ80_dsk.c b/AltairZ80/altairZ80_dsk.c new file mode 100644 index 00000000..873766a2 --- /dev/null +++ b/AltairZ80/altairZ80_dsk.c @@ -0,0 +1,408 @@ +/* altairZ80_dsk.c: MITS Altair 88-DISK Simulator + Written by Charles E Owen ((c) 1997, Commercial use prohibited) + Minor modifications by Peter Schorn, 2001 + + 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 + each. + + The controller is interfaced to the CPU by use of 3 I/O addreses, + standardly, these are device numbers 10, 11, and 12 (octal). + + Address Mode Function + ------- ---- -------- + + 10 Out Selects and enables Controller and Drive + 10 In Indicates status of Drive and Controller + 11 Out Controls Disk Function + 11 In Indicates current sector position of disk + 12 Out Write data + 12 In Read data + + Drive Select Out (Device 10 OUT): + + +---+---+---+---+---+---+---+---+ + | C | X | X | X | Device | + +---+---+---+---+---+---+---+---+ + + C = If this bit is 1, the disk controller selected by 'device' is + cleared. If the bit is zero, 'device' is selected as the + device being controlled by subsequent I/O operations. + X = not used + Device = value zero thru 15, selects drive to be controlled. + + Drive Status In (Device 10 IN): + + +---+---+---+---+---+---+---+---+ + | R | Z | I | X | X | H | M | W | + +---+---+---+---+---+---+---+---+ + + W - When 0, write circuit ready to write another byte. + 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) + Z - When 0, indicates head is on track 0 + R - When 0, indicates that read circuit has new byte to read + + Drive Control (Device 11 OUT): + + +---+---+---+---+---+---+---+---+ + | W | C | D | E | U | H | O | I | + +---+---+---+---+---+---+---+---+ + + I - When 1, steps head IN one track + O - When 1, steps head OUT one track + H - When 1, loads head to drive surface + U - When 1, unloads head + E - Enables interrupts (ignored this simulator) + D - Disables interrupts (ignored this simulator) + C - When 1 lowers head current (ignored this simulator) + W - When 1, starts Write Enable sequence: W bit on device 10 + (see above) will go 1 and data will be read from port 12 + until 137 bytes have been read by the controller from + that port. The W bit will go off then, and the sector data + will be written to disk. Before you do this, you must have + stepped the track to the desired number, and waited until + the right sector number is presented on device 11 IN, then + set this bit. + + Sector Position (Device 11 IN): + + As the sectors pass by the read head, they are counted and the + number of the current one is available in this register. + + +---+---+---+---+---+---+---+---+ + | X | X | Sector Number | T | + +---+---+---+---+---+---+---+---+ + + X = Not used + Sector number = binary of the sector number currently under the + head, 0-31. + T = Sector True, is a 1 when the sector is positioned to read or + write. + +*/ + +#include +#include "altairZ80_defs.h" + +#define UNIT_V_ENABLE (UNIT_V_UF + 0) /* Write Enable */ +#define UNIT_ENABLE (1 << UNIT_V_ENABLE) +#define DSK_SECTSIZE 137 /* size of sector */ +#define DSK_SECT 32 /* sectors per track */ +#define 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 TRACE_IN_OUT 1 +#define TRACE_READ_WRITE 2 +#define TRACE_SECTOR_STUCK 4 +#define TRACE_TRACK_STUCK 8 + +t_stat dsk_svc (UNIT *uptr); +t_stat dsk_reset (DEVICE *dptr); +void writebuf(); + +extern int32 PCX; +extern FILE *sim_log; + +/* Global data on status */ + +int32 cur_disk = 8; /* Currently selected drive */ +int32 cur_track[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0xff}; +int32 cur_sect[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0xff}; +int32 cur_byte[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0xff}; +int32 cur_flags[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; +int32 trace_flag = 0; +int32 in9_count = 0; +int32 in9_message = FALSE; + +char dskbuf[DSK_SECTSIZE]; /* Data Buffer */ +int32 dirty = 0; /* 1 when buffer has unwritten data in it */ +UNIT *dptr; /* fileref to write dirty buffer to */ + +/* 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) } }; + +REG dsk_reg[] = { + { DRDATA (DISK, cur_disk, 4) }, + { ORDATA (TRACE, trace_flag, 8) }, + { DRDATA (IN9, in9_count, 4), REG_RO }, + { NULL } }; + +DEVICE dsk_dev = { + "DSK", dsk_unit, dsk_reg, NULL, + 8, 10, 31, 1, 8, 8, + NULL, NULL, &dsk_reset, + NULL, NULL, NULL }; + +/* Service routines to handle simlulator functions */ + +/* service routine - actually gets char & places in buffer */ + +t_stat dsk_svc (UNIT *uptr) +{ + return SCPE_OK; +} + +/* Reset routine */ + +t_stat dsk_reset (DEVICE *dptr) +{ + cur_disk = 0; + trace_flag = 0; + in9_count = 0; + in9_message = FALSE; + return SCPE_OK; +} + +/* I/O instruction handlers, called from the CPU module when an + IN or OUT instruction is issued. + + Each function is passed an 'io' flag, where 0 means a read from + the port, and 1 means a write to the port. On input, the actual + input is passed as the return value, on output, 'data' is written + to the device. +*/ + +/* Disk Controller Status/Select */ + +/* IMPORTANT: The status flags read by port 8 IN instruction are + INVERTED, that is, 0 is true and 1 is false. To handle this, the + simulator keeps it's own status flags as 0=false, 1=true; and + returns the COMPLEMENT of the status flags when read. This makes + setting/testing of the flag bits more logical, yet meets the + simulation requirement that they are reversed in hardware. +*/ + +int32 dsk10(int32 io, int32 data) +{ + in9_count = 0; + if (io == 0) { /* IN: return flags */ + return ((~cur_flags[cur_disk]) & 0xFF); /* Return the COMPLEMENT! */ + } + + /* OUT: Controller set/reset/enable/disable */ + if (dirty == 1) + writebuf(); + if (trace_flag & TRACE_IN_OUT) { + printf("\n[%x] OUT 08: %x", PCX, data); + if (sim_log) { + fprintf(sim_log, "\n[%x] OUT 08: %x", PCX, data); + } + } + cur_disk = data & 0x0F; + if ((((dsk_dev.units + cur_disk) -> flags) & UNIT_ATT) == 0) { /* nothing attached? */ + cur_disk = 8; + } + else { + cur_sect[cur_disk] = 0xff; /* reset internal counters */ + cur_byte[cur_disk] = 0xff; + cur_flags[cur_disk] = data & 0x80 ? 0 /* Disable drive */ : + (cur_track[cur_disk] == 0 ? 0x5A /* Enable: head move true, track 0 if there */ : + 0x1A); /* Enable: head move true */ + } + return (0); /* ignored since OUT */ +} + +/* Disk Drive Status/Functions */ + +int32 dsk11(int32 io, int32 data) +{ + if (io == 0) { /* Read sector position */ + in9_count++; + if ((trace_flag & TRACE_SECTOR_STUCK) && (in9_count > 2*DSK_SECT) && (!in9_message)) { + in9_message = TRUE; + printf("\n[%x] Looping on sector find %d.\n", PCX, cur_disk); + if (sim_log) { + fprintf(sim_log, "\n[%x] Looping on sector find %d.\n", PCX, cur_disk); + } + } + if (trace_flag & TRACE_IN_OUT) { + printf("\n[%x] IN 09", PCX); + if (sim_log) { + fprintf(sim_log, "\n[%x] IN 09", PCX); + } + } + if (dirty == 1) + writebuf(); + if (cur_flags[cur_disk] & 0x04) { /* head loaded? */ + cur_sect[cur_disk]++; + if (cur_sect[cur_disk] >= DSK_SECT) + cur_sect[cur_disk] = 0; + cur_byte[cur_disk] = 0xff; + return (((cur_sect[cur_disk] << 1) & 0x3E) /* return 'sector true' bit = 0 (true) */ + | 0xC0); /* set on 'unused' bits */ + } else { + return (0); /* head not loaded - return 0 */ + } + } + + in9_count = 0; + /* Drive functions */ + + if (cur_disk > 7) + return (0); /* no drive selected - can do nothing */ + + if (trace_flag & TRACE_IN_OUT) { + printf("\n[%x] OUT 09: %x", PCX, data); + if (sim_log) { + fprintf(sim_log, "\n[%x] OUT 09: %x", PCX, data); + } + } + if (data & 0x01) { /* Step head in */ + if (trace_flag & TRACE_TRACK_STUCK) { + if (cur_track[cur_disk] == (TRACKS-1)) { + printf("\n[%x] Unnecessary step in for disk %d", PCX, cur_disk); + if (sim_log) { + fprintf(sim_log, "\n[%x] Unnecessary step in for disk %d", PCX, cur_disk); + } + } + } + cur_track[cur_disk]++; + if (cur_track[cur_disk] > (TRACKS-1) ) + cur_track[cur_disk] = (TRACKS-1); + if (dirty == 1) + writebuf(); + cur_sect[cur_disk] = 0xff; + cur_byte[cur_disk] = 0xff; + } + + if (data & 0x02) { /* Step head out */ + if (trace_flag & TRACE_TRACK_STUCK) { + if (cur_track[cur_disk] == 0) { + printf("\n[%x] Unnecessary step out for disk %d", PCX, cur_disk); + if (sim_log) { + fprintf(sim_log, "\n[%x] Unnecessary step out for disk %d", PCX, cur_disk); + } + } + } + cur_track[cur_disk]--; + if (cur_track[cur_disk] < 0) { + cur_track[cur_disk] = 0; + cur_flags[cur_disk] |= 0x40; /* track 0 if there */ + } + if (dirty == 1) + writebuf(); + cur_sect[cur_disk] = 0xff; + cur_byte[cur_disk] = 0xff; + } + + if (dirty == 1) + writebuf(); + + if (data & 0x04) { /* Head load */ + cur_flags[cur_disk] |= 0x04; /* turn on head loaded bit */ + cur_flags[cur_disk] |= 0x80; /* turn on 'read data available */ + } + + if (data & 0x08) { /* Head Unload */ + cur_flags[cur_disk] &= 0xFB; /* off on 'head loaded' */ + cur_flags[cur_disk] &= 0x7F; /* off on 'read data avail */ + cur_sect[cur_disk] = 0xff; + cur_byte[cur_disk] = 0xff; + } + + /* Interrupts & head current are ignored */ + + if (data & 0x80) { /* write sequence start */ + cur_byte[cur_disk] = 0; + cur_flags[cur_disk] |= 0x01; /* enter new write data on */ + } + return (0); /* ignored since OUT */ +} + +/* Disk Data In/Out*/ + +inline int32 dskseek(UNIT *xptr) { + return fseek(xptr -> fileref, DSK_TRACSIZE * cur_track[cur_disk] + + DSK_SECTSIZE * cur_sect[cur_disk], SEEK_SET); +} + +int32 dsk12(int32 io, int32 data) +{ + static int32 i; + UNIT *uptr; + + in9_count = 0; + uptr = dsk_dev.units + cur_disk; + if (io == 0) { + if (cur_byte[cur_disk] >= DSK_SECTSIZE) { + /* physically read the sector */ + if (trace_flag & TRACE_READ_WRITE) { + printf("\n[%x] IN 0A (READ) D%d T%d S%d", PCX, cur_disk, cur_track[cur_disk], cur_sect[cur_disk]); + if (sim_log) { + fprintf(sim_log, "\n[%x] IN 0A (READ) D%d T%d S%d", PCX, cur_disk, cur_track[cur_disk], + cur_sect[cur_disk]); + } + } + for (i = 0; i < DSK_SECTSIZE; i++) { + dskbuf[i] = 0; + } + dskseek(uptr); + fread(dskbuf, DSK_SECTSIZE, 1, uptr -> fileref); + cur_byte[cur_disk] = 0; + } + return (dskbuf[cur_byte[cur_disk]++] & 0xFF); + } + else { + if (cur_byte[cur_disk] >= DSK_SECTSIZE) { + writebuf(); + } + else { + dirty = 1; + dptr = uptr; + dskbuf[cur_byte[cur_disk]++] = data & 0xFF; + } + return (0); /* ignored since OUT */ + } +} + +void writebuf() +{ + int32 i, rtn; + + i = cur_byte[cur_disk]; /* null-fill rest of sector if any */ + while (i < DSK_SECTSIZE) { + dskbuf[i++] = 0; + } + if (trace_flag & TRACE_READ_WRITE) { + printf("\n[%x] OUT 0A (WRITE) D%d T%d S%d", PCX, cur_disk, + cur_track[cur_disk], cur_sect[cur_disk]); + if (sim_log) { + fprintf (sim_log, "\n[%x] OUT 0A (WRITE) D%d T%d S%d", PCX, cur_disk, + cur_track[cur_disk], cur_sect[cur_disk]); + } + } + if (dskseek(dptr)) { + printf("\n[%x] fseek failed D%d T%d S%d", PCX, cur_disk, + cur_track[cur_disk], cur_sect[cur_disk]); + if (sim_log) { + fprintf(sim_log, "\n[%x] fseek failed D%d T%d S%d", PCX, cur_disk, + cur_track[cur_disk], cur_sect[cur_disk]); + } + } + rtn = fwrite(dskbuf, DSK_SECTSIZE, 1, dptr -> fileref); + if (rtn != 1) { + printf("\n[%x] fwrite failed T%d S%d Return=%d", PCX, cur_track[cur_disk], + cur_sect[cur_disk], rtn); + if (sim_log) { + fprintf(sim_log, "\n[%x] fwrite failed T%d S%d Return=%d", PCX, cur_track[cur_disk], + cur_sect[cur_disk], rtn); + } + } + cur_flags[cur_disk] &= 0xFE; /* ENWD off */ + cur_byte[cur_disk] = 0xff; + dirty = 0; +} diff --git a/AltairZ80/altairZ80_sio.c b/AltairZ80/altairZ80_sio.c new file mode 100644 index 00000000..0b4f7937 --- /dev/null +++ b/AltairZ80/altairZ80_sio.c @@ -0,0 +1,434 @@ +/* altairZ80_sio: MITS Altair serial I/O card + Written by Peter Schorn, 2001 + Based on work by Charles E Owen ((c) 1997, Commercial use prohibited) + + 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, + RS232, or TTY interface. Available baud rates were jumper + selectable for each port from 110 to 9600. + + All I/O is via programmed I/O. Each each has a status port + and a data port. A write to the status port can select + some options for the device (0x03 will reset the port). + A read of the status port gets the port status: + + +---+---+---+---+---+---+---+---+ + | X X X X X X O I | + +---+---+---+---+---+---+---+---+ + + I - A 1 in this bit position means a character has been received + on the data port and is ready to be read. + O - A 1 in this bit means the port is ready to receive a character + on the data port and transmit it out over the serial line. + + A read to the data port gets the buffered character, a write + to the data port writes the character to the device. +*/ + +#include +#include + +#include "altairZ80_defs.h" +#include "sim_sock.h" +#include "sim_tmxr.h" + +#define UNIT_V_ANSI (UNIT_V_UF + 0) /* ANSI mode, strip bit 8 on output */ +#define UNIT_ANSI (1 << UNIT_V_ANSI) +#define UNIT_V_UPPER (UNIT_V_UF + 1) /* uppper case mode */ +#define UNIT_UPPER (1 << UNIT_V_UPPER) +#define UNIT_V_BS (UNIT_V_UF + 2) /* map delete to backspace */ +#define UNIT_BS (1 << UNIT_V_BS) +#define Terminals 1 /* lines per mux */ + +TMLN TerminalLines[Terminals] = { { 0 } }; /* we only need one line */ +TMXR altairTMXR = {Terminals, 0, &TerminalLines[0] }; /* mux descriptor */ + +t_stat sio_svc (UNIT *uptr); +t_stat sio_reset (DEVICE *dptr); +t_stat sio_attach (UNIT *uptr, char *cptr); +t_stat sio_detach (UNIT *uptr); +t_stat ptr_svc (UNIT *uptr); +t_stat ptr_reset (DEVICE *dptr); +t_stat ptp_svc (UNIT *uptr); +t_stat ptp_reset (DEVICE *dptr); +int32 nulldev(int32 io, int32 data); +int32 simh_dev(int32 io, int32 data); +int32 sio0d(int32 io, int32 data); +int32 sio0s(int32 io, int32 data); +int32 sio1d(int32 io, int32 data); +int32 sio1s(int32 io, int32 data); +void attachCPM(); + +extern t_stat sim_activate (UNIT *uptr, int32 interval); +extern t_stat sim_cancel (UNIT *uptr); +extern t_stat sim_poll_kbd (void); +extern t_stat sim_putchar (int32 out); +extern t_stat attach_unit (UNIT *uptr, char *cptr); +extern t_bool rtc_avail; +extern FILE *sim_log; +extern int32 sim_switches; +extern uint32 sim_os_msec (void); +extern uint8 M[MAXMEMSIZE]; + +/* 2SIO Standard I/O Data Structures */ + +UNIT sio_unit = { UDATA (&sio_svc, UNIT_ATTABLE, 0), + KBD_POLL_WAIT }; + +REG sio_reg[] = { + { HRDATA (DATA, sio_unit.buf, 8) }, + { HRDATA (STAT, sio_unit.u3, 8) }, + { NULL } }; + +MTAB sio_mod[] = { + { UNIT_ANSI, 0, "TTY", "TTY", NULL }, /* keep bit 8 as is for output */ + { UNIT_ANSI, UNIT_ANSI, "ANSI", "ANSI", NULL }, /* set bit 8 to 0 before output */ + { UNIT_UPPER, 0, "ALL", "ALL", NULL }, /* do not change case of input characters */ + { UNIT_UPPER, UNIT_UPPER, "UPPER", "UPPER", NULL }, /* change input characters to upper case */ + { UNIT_BS, 0, "BS", "BS", NULL }, /* map delete to backspace */ + { UNIT_BS, UNIT_BS, "DEL", "DEL", NULL }, /* map backspace to delete */ + { 0 } }; + +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 }; + +UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ + UNIT_ATTABLE + UNIT_ROABLE, 0), + KBD_POLL_WAIT }; + +REG ptr_reg[] = { + { HRDATA (DATA, ptr_unit.buf, 8) }, + { HRDATA (STAT, ptr_unit.u3, 8) }, + { DRDATA (POS, ptr_unit.pos, 31) }, + { NULL } }; + +DEVICE ptr_dev = { + "PTR", &ptr_unit, ptr_reg, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ptr_reset, + NULL, NULL, NULL }; + +UNIT ptp_unit = { UDATA (&ptp_svc, UNIT_SEQ + UNIT_ATTABLE, 0), + KBD_POLL_WAIT }; + +REG ptp_reg[] = { + { HRDATA (DATA, ptp_unit.buf, 8) }, + { HRDATA (STAT, ptp_unit.u3, 8) }, + { DRDATA (POS, ptp_unit.pos, 31) }, + { NULL } }; + +DEVICE ptp_dev = { + "PTP", &ptp_unit, ptp_reg, NULL, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &ptp_reset, + NULL, NULL, NULL }; + +t_stat sio_attach (UNIT *uptr, char *cptr) +{ +return tmxr_attach (&altairTMXR, uptr, cptr); /* attach mux */ +} + +/* Detach */ + +t_stat sio_detach (UNIT *uptr) +{ +sio_unit.u3 = 0x02; /* Status */ +sio_unit.buf = 0; /* Data */ +return tmxr_detach (&altairTMXR, uptr); +} + +/* Service routines to handle simulator functions */ + +/* service routine - actually gets char & places in buffer */ + +t_stat sio_svc (UNIT *uptr) +{ + int32 temp; + + sim_activate (&sio_unit, sio_unit.wait); /* continue poll */ + + if (sio_unit.flags & UNIT_ATT) { + if (sim_poll_kbd () == SCPE_STOP) { /* listen for ^E */ + return SCPE_STOP; + } + temp = tmxr_poll_conn(&altairTMXR, &sio_unit); /* poll connection */ + if (temp >= 0) { + altairTMXR.ldsc[temp] -> rcve = 1; /* enable receive */ + } + tmxr_poll_rx(&altairTMXR); /* poll input */ + tmxr_poll_tx(&altairTMXR); /* poll output */ + } + else { + if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) { + return temp; /* no char or error? */ + } + sio_unit.buf = temp & 0xff; /* Save char */ + sio_unit.u3 |= 0x01; /* Set status */ + } + return SCPE_OK; +} + + +t_stat ptr_svc (UNIT *uptr) +{ + return SCPE_OK; +} + +t_stat ptp_svc (UNIT *uptr) +{ + return SCPE_OK; +} + + +/* Reset routine */ + +t_stat sio_reset (DEVICE *dptr) +{ + if (sio_unit.flags & UNIT_ATT) { + if (altairTMXR.ldsc[0]->conn > 0) { + tmxr_reset_ln(altairTMXR.ldsc[0]); + } + sio_unit.u3 = 0; /* Status */ + } + else { + sio_unit.u3 = 0x02; /* Status */ + } + sio_unit.buf = 0; /* Data */ + sim_activate (&sio_unit, sio_unit.wait); /* activate unit */ + return SCPE_OK; +} + + +t_stat ptr_reset (DEVICE *dptr) +{ + ptr_unit.buf = 0; + ptr_unit.u3 = 0; + ptr_unit.pos = 0; + if (ptr_unit.flags & UNIT_ATT) { /* attached? */ + rewind(ptr_dev.units -> fileref); + } + sim_cancel (&ptp_unit); /* deactivate unit */ + return SCPE_OK; +} + +t_stat ptp_reset (DEVICE *dptr) +{ + ptp_unit.buf = 0; + ptp_unit.u3 = 0x02; + sim_cancel (&ptp_unit); /* deactivate unit */ + return SCPE_OK; +} + +/* I/O instruction handlers, called from the CPU module when an + IN or OUT instruction is issued. + + Each function is passed an 'io' flag, where 0 means a read from + the port, and 1 means a write to the port. On input, the actual + input is passed as the return value, on output, 'data' is written + to the device. +*/ + +int32 sio0s(int32 io, int32 data) +{ + if (io == 0) { /* IN */ + if (sio_unit.flags & UNIT_ATT) { + sio_unit.u3 = (((tmxr_rqln(altairTMXR.ldsc[0]) > 0 ? 0x01 : 0) | /* read possible if character available */ + (altairTMXR.ldsc[0]->conn == 0 ? 0 : 0x02))); /* write possible if connected */ + } + return (sio_unit.u3); + } + else { /* OUT */ + if (sio_unit.flags & UNIT_ATT) { + if (data == 0x03) { /* reset port! */ + sio_unit.u3 = 0; + sio_unit.buf = 0; + } + } + else { + if (data == 0x03) { /* reset port! */ + sio_unit.u3 = 0x02; + sio_unit.buf = 0; + } + } + return (0); /* ignored since OUT */ + } +} + +int32 sio0d(int32 io, int32 data) +{ + if (io == 0) { /* IN */ + if (sio_unit.flags & UNIT_ATT) { + sio_unit.buf = tmxr_getc_ln(altairTMXR.ldsc[0]) & 0xff; + } + sio_unit.u3 = sio_unit.u3 & 0xFE; + if (sio_unit.flags & UNIT_BS) { + if (sio_unit.buf == BACKSPACE_CHAR) { + sio_unit.buf = DELETE_CHAR; + } + } + else { + if (sio_unit.buf == DELETE_CHAR) { + sio_unit.buf = BACKSPACE_CHAR; + } + } + return ((sio_unit.flags & UNIT_UPPER) ? toupper(sio_unit.buf) : sio_unit.buf); + } + else { /* OUT */ + if (sio_unit.flags & UNIT_ANSI) { + data &= 0x7f; + } + if (sio_unit.flags & UNIT_ATT) { + tmxr_putc_ln(altairTMXR.ldsc[0], data); + } + else { + sim_putchar(data); + } + return (0); /* ignored since OUT */ + } +} + +/* Port 2 controls the PTR/PTP devices */ + +int32 sio1s(int32 io, int32 data) +{ + if (io == 0) { + /* reset I bit iff PTR unit not attached or no more data available. */ + /* O bit is always set since write always possible. */ + return ((ptr_unit.flags & UNIT_ATT) == 0) || (ptr_unit.u3 != 0) ? 0x02 : 0x03; + } + else { /* OUT */ + if (data == 0x03) { + ptr_unit.u3 = 0; + ptr_unit.buf = 0; + ptr_unit.pos = 0; + ptp_unit.u3 = 0; + ptp_unit.buf = 0; + ptp_unit.pos = 0; + } + return (0); /* ignored since OUT */ + } +} + +int32 sio1d(int32 io, int32 data) +{ + int32 temp; + if (io == 0) { /* IN */ + if (((ptr_unit.flags & UNIT_ATT) == 0) || (ptr_unit.u3 != 0)) + return (0); /* not attached or no more data available */ + if ((temp = getc(ptr_dev.units -> fileref)) == EOF) { /* end of file? */ + ptr_unit.u3 = 0x01; + return (CONTROLZ_CHAR); /* control Z denotes end of text file in CP/M */ + } + ptr_unit.pos++; + return (temp & 0xFF); + } + else { /* OUT */ + putc(data, ptp_dev.units -> fileref); + ptp_unit.pos++; + return (0); /* ignored since OUT */ + } +} + +int32 nulldev(int32 io, int32 data) +{ + return (io == 0 ? 0xff : 0); +} + +#define splimit 10 +#define printTimeCmd 0 +#define markTimeCmd 1 +#define showTimeCmd 2 +#define resetPtrCmd 3 +#define attachCmd 4 +#define detachCmd 5 +#define resetCmd 6 +#define cpmCommandLineLength 128 +uint32 markTime[splimit]; +int32 markTimeSP = 0; +char version[] = "SIMH001"; +int32 versionPos = 0; + +/* The CP/M commandline is used as the name of a file and PTR is attached to it */ +void attachCPM() { + char cpmCommandLine[cpmCommandLineLength]; + uint32 i, len = (M[0x80] & 0x7f) - 1; /* 0x80 contains length of commandline, discard first char */ + for (i = 0; i < len; i++) { + cpmCommandLine[i] = (char)M[0x82+i]; /* the first char, typically ' ', is discarded */ + } + cpmCommandLine[i] = 0; /* make C string */ + sim_switches = SWMASK ('R'); + attach_unit(&ptr_unit, cpmCommandLine); +} + +/* port 0xfe is a device for communication SIMH <--> Altair machine */ +int32 simh_dev(int32 io, int32 data) { + uint32 delta; + int32 result; + if (io == 0) { /* IN */ + result = version[versionPos++]; + if (result == 0) { + versionPos = 0; + } + return (result); + } + else { /* OUT */ + switch(data) { + case printTimeCmd: /* print time */ + if (rtc_avail) { + printf("Current time in milliseconds = %d.\n", sim_os_msec ()); + if (sim_log) { + fprintf(sim_log, "Current time in milliseconds = %d.\n", sim_os_msec ()); + } + } + break; + case markTimeCmd: /* mark time */ + if (rtc_avail) { + if (markTimeSP < splimit) { + markTime[markTimeSP++] = sim_os_msec (); + } + else { + printf("Mark stack overflow.\n"); + if (sim_log) { + fprintf(sim_log, "Mark stack overflow.\n"); + } + } + } + break; + case showTimeCmd: /* show time difference */ + if (rtc_avail) { + if (markTimeSP > 0) { + delta = sim_os_msec () - markTime[--markTimeSP]; + printf("Delta to mark in milliseconds = %d.\n", delta); + if (sim_log) { + fprintf(sim_log, "Delta to mark in milliseconds = %d.\n", delta); + } + } + else { + printf("Missing mark.\n"); + if (sim_log) { + fprintf(sim_log, "Missing mark.\n"); + } + } + } + break; + case resetPtrCmd: /* reset ptr device */ + ptr_reset(NULL); + break; + case attachCmd: /* attach ptr to the file with name at beginning of CP/M command line */ + attachCPM(); + break; + case detachCmd: /* detach ptr */ + detach_unit(&ptr_unit); + break; + case resetCmd: + versionPos = 0; + break; + default:; + } + return 0; /* ignored, since OUT */ + } +} + diff --git a/AltairZ80/altairZ80_sys.c b/AltairZ80/altairZ80_sys.c new file mode 100644 index 00000000..83afb8f9 --- /dev/null +++ b/AltairZ80/altairZ80_sys.c @@ -0,0 +1,687 @@ +/* altairz80_sys.c: MITS Altair system interface + Written by Peter Schorn, 2001 + Based on work by Charles E Owen ((c) 1997 - Commercial use prohibited) + Disassembler from Marat Fayzullin ((c) 1995, 1996, 1997 - Commercial use prohibited) +*/ + +#include +#include "altairZ80_defs.h" + +extern DEVICE cpu_dev; +extern DEVICE dsk_dev; +extern UNIT cpu_unit; +extern REG cpu_reg[]; +extern DEVICE sio_dev; +extern DEVICE ptr_dev; +extern DEVICE ptp_dev; +extern uint8 M[]; +extern int32 saved_PC; + +int32 sim_load (FILE *fileref, char *cptr, char *fnam, int32 flag); +int32 fprint_sym (FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw); +int32 checkbase(char ch, char *numString); +int32 numok(char ch, char **numString, int32 minvalue, int32 maxvalue, int32 requireSign, int32 *result); +int32 match(char *pattern, char *input, char *xy, int32 *number, int32 *star, int32 *at, int32 *hat); +int32 parse_X80(char *cptr, int32 addr, uint32 *val, char *Mnemonics[]); +int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw); +int32 DAsm(char *S, uint32 *val, int32 useZ80Mnemonics); + +/* SCP data structures + sim_name simulator name string + sim_PC pointer to saved PC register descriptor + sim_emax number of words needed for examine + sim_devices array of pointers to simulated devices + sim_stop_messages array of pointers to stop messages + sim_load binary loader +*/ + +char sim_name[] = "Altair 8800 (Z80)"; +REG *sim_PC = &cpu_reg[0]; +int32 sim_emax = 4; +DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &ptr_dev, &ptp_dev, &dsk_dev, NULL }; + +const char *sim_stop_messages[] = { + "Unknown error", + "Unknown I/O Instruction", + "HALT instruction", + "Breakpoint", + "Invalid Opcode" }; + +static char *Mnemonics8080[] = { +/*0/8 1/9 2/A 3/B 4/C 5/D 6/E 7/F */ + "NOP", "LXI B,#h", "STAX B", "INX B", "INR B", "DCR B", "MVI B,*h", "RLC", /* 00-07 */ + "DB 09h", "DAD B", "LDAX B", "DCX B", "INR C", "DCR C", "MVI C,*h", "RRC", /* 08-0f */ + "DB 10h", "LXI D,#h", "STAX D", "INX D", "INR D", "DCR D", "MVI D,*h", "RAL", /* 10-17 */ + "DB 18h", "DAD D", "LDAX D", "DCX D", "INR E", "DCR E", "MVI E,*h", "RAR", /* 18-1f */ + "DB 20h", "LXI H,#h", "SHLD #h", "INX H", "INR H", "DCR H", "MVI H,*h", "DAA", /* 20-27 */ + "DB 28h", "DAD H", "LHLD #h", "DCX H", "INR L", "DCR L", "MVI L,*h", "CMA", /* 28-2f */ + "DB 30h", "LXI SP,#h", "STA #h", "INX SP", "INR M", "DCR M", "MVI M,*h", "STC", /* 30-37 */ + "DB 38h", "DAD SP", "LDA #h", "DCX SP", "INR A", "DCR A", "MVI A,*h", "CMC", /* 38-3f */ + "MOV B,B", "MOV B,C", "MOV B,D", "MOV B,E", "MOV B,H", "MOV B,L", "MOV B,M", "MOV B,A", /* 40-47 */ + "MOV C,B", "MOV C,C", "MOV C,D", "MOV C,E", "MOV C,H", "MOV C,L", "MOV C,M", "MOV C,A", /* 48-4f */ + "MOV D,B", "MOV D,C", "MOV D,D", "MOV D,E", "MOV D,H", "MOV D,L", "MOV D,M", "MOV D,A", /* 50-57 */ + "MOV E,B", "MOV E,C", "MOV E,D", "MOV E,E", "MOV E,H", "MOV E,L", "MOV E,M", "MOV E,A", /* 58-5f */ + "MOV H,B", "MOV H,C", "MOV H,D", "MOV H,E", "MOV H,H", "MOV H,L", "MOV H,M", "MOV H,A", /* 60-67 */ + "MOV L,B", "MOV L,C", "MOV L,D", "MOV L,E", "MOV L,H", "MOV L,L", "MOV L,M", "MOV L,A", /* 68-6f */ + "MOV M,B", "MOV M,C", "MOV M,D", "MOV M,E", "MOV M,H", "MOV M,L", "HLT", "MOV M,A", /* 70-77 */ + "MOV A,B", "MOV A,C", "MOV A,D", "MOV A,E", "MOV A,H", "MOV A,L", "MOV A,M", "MOV A,A", /* 78-7f */ + "ADD B", "ADD C", "ADD D", "ADD E", "ADD H", "ADD L", "ADD M", "ADD A", /* 80-87 */ + "ADC B", "ADC C", "ADC D", "ADC E", "ADC H", "ADC L", "ADC M", "ADC A", /* 88-8f */ + "SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB M", "SUB A", /* 90-97 */ + "SBB B", "SBB C", "SBB D", "SBB E", "SBB H", "SBB L", "SBB M", "SBB A", /* 98-9f */ + "ANA B", "ANA C", "ANA D", "ANA E", "ANA H", "ANA L", "ANA M", "ANA A", /* a0-a7 */ + "XRA B", "XRA C", "XRA D", "XRA E", "XRA H", "XRA L", "XRA M", "XRA A", /* a8-af */ + "ORA B", "ORA C", "ORA D", "ORA E", "ORA H", "ORA L", "ORA M", "ORA A", /* b0-b7 */ + "CMP B", "CMP C", "CMP D", "CMP E", "CMP H", "CMP L", "CMP M", "CMP A", /* b8-bf */ + "RNZ", "POP B", "JNZ #h", "JMP #h", "CNZ #h", "PUSH B", "ADI *h", "RST 0", /* c0-c7 */ + "RZ", "RET", "JZ #h", "DB CBh", "CZ #h", "CALL #h", "ACI *h", "RST 1", /* c8-cf */ + "RNC", "POP D", "JNC #h", "OUT *h", "CNC #h", "PUSH D", "SUI *h", "RST 2", /* d0-d7 */ + "RC", "DB D9h", "JC #h", "IN *h", "CC #h", "DB DDh", "SBI *h", "RST 3", /* d8-df */ + "RPO", "POP H", "JPO #h", "XTHL", "CPO #h", "PUSH H", "ANI *h", "RST 4", /* e0-e7 */ + "RPE", "PCHL", "JPE #h", "XCHG", "CPE #h", "DB EDh", "XRI *h", "RST 5", /* e8-ef */ + "RP", "POP PSW", "JP #h", "DI", "CP #h", "PUSH PSW", "ORI *h", "RST 6", /* f0-f7 */ + "RM", "SPHL", "JM #h", "EI", "CM #h", "DB FDh", "CPI *h", "RST 7" /* f8-ff */ + }; + +static char *MnemonicsZ80[256] = +{ + "NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA", + "EX AF,AF'", "ADD HL,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA", + "DJNZ @h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA", + "JR @h", "ADD HL,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA", + "JR NZ,@h", "LD HL,#h", "LD (#h),HL", "INC HL", "INC H", "DEC H", "LD H,*h", "DAA", + "JR Z,@h", "ADD HL,HL", "LD HL,(#h)", "DEC HL", "INC L", "DEC L", "LD L,*h", "CPL", + "JR NC,@h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (HL)", "DEC (HL)", "LD (HL),*h", "SCF", + "JR C,@h", "ADD HL,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF", + "LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,H", "LD B,L", "LD B,(HL)", "LD B,A", + "LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,H", "LD C,L", "LD C,(HL)", "LD C,A", + "LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,H", "LD D,L", "LD D,(HL)", "LD D,A", + "LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,H", "LD E,L", "LD E,(HL)", "LD E,A", + "LD H,B", "LD H,C", "LD H,D", "LD H,E", "LD H,H", "LD H,L", "LD H,(HL)", "LD H,A", + "LD L,B", "LD L,C", "LD L,D", "LD L,E", "LD L,H", "LD L,L", "LD L,(HL)", "LD L,A", + "LD (HL),B", "LD (HL),C", "LD (HL),D", "LD (HL),E", "LD (HL),H", "LD (HL),L", "HALT", "LD (HL),A", + "LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,H", "LD A,L", "LD A,(HL)", "LD A,A", + "ADD B", "ADD C", "ADD D", "ADD E", "ADD H", "ADD L", "ADD (HL)", "ADD A", + "ADC B", "ADC C", "ADC D", "ADC E", "ADC H", "ADC L", "ADC (HL)", "ADC A", + "SUB B", "SUB C", "SUB D", "SUB E", "SUB H", "SUB L", "SUB (HL)", "SUB A", + "SBC B", "SBC C", "SBC D", "SBC E", "SBC H", "SBC L", "SBC (HL)", "SBC A", + "AND B", "AND C", "AND D", "AND E", "AND H", "AND L", "AND (HL)", "AND A", + "XOR B", "XOR C", "XOR D", "XOR E", "XOR H", "XOR L", "XOR (HL)", "XOR A", + "OR B", "OR C", "OR D", "OR E", "OR H", "OR L", "OR (HL)", "OR A", + "CP B", "CP C", "CP D", "CP E", "CP H", "CP L", "CP (HL)", "CP A", + "RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD *h", "RST 00h", + "RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC *h", "RST 08h", + "RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h", + "RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC *h", "RST 18h", + "RET PO", "POP HL", "JP PO,#h", "EX HL,(SP)", "CALL PO,#h", "PUSH HL", "AND *h", "RST 20h", + "RET PE", "LD PC,HL", "JP PE,#h", "EX DE,HL", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h", + "RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h", + "RET M", "LD SP,HL", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h" +}; + +static char *MnemonicsCB[256] = +{ + "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (HL)", "RLC A", + "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (HL)", "RRC A", + "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (HL)", "RL A", + "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (HL)", "RR A", + "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (HL)", "SLA A", + "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (HL)", "SRA A", + "SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (HL)", "SLL A", + "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (HL)", "SRL A", + "BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(HL)", "BIT 0,A", + "BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(HL)", "BIT 1,A", + "BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(HL)", "BIT 2,A", + "BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(HL)", "BIT 3,A", + "BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(HL)", "BIT 4,A", + "BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(HL)", "BIT 5,A", + "BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(HL)", "BIT 6,A", + "BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(HL)", "BIT 7,A", + "RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(HL)", "RES 0,A", + "RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(HL)", "RES 1,A", + "RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(HL)", "RES 2,A", + "RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(HL)", "RES 3,A", + "RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(HL)", "RES 4,A", + "RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(HL)", "RES 5,A", + "RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(HL)", "RES 6,A", + "RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(HL)", "RES 7,A", + "SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(HL)", "SET 0,A", + "SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(HL)", "SET 1,A", + "SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(HL)", "SET 2,A", + "SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(HL)", "SET 3,A", + "SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(HL)", "SET 4,A", + "SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(HL)", "SET 5,A", + "SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(HL)", "SET 6,A", + "SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(HL)", "SET 7,A" +}; + +static char *MnemonicsED[256] = +{ + "DB EDh,00h", "DB EDh,01h", "DB EDh,02h", "DB EDh,03h", "DB EDh,04h", "DB EDh,05h", "DB EDh,06h", "DB EDh,07h", + "DB EDh,08h", "DB EDh,09h", "DB EDh,0Ah", "DB EDh,0Bh", "DB EDh,0Ch", "DB EDh,0Dh", "DB EDh,0Eh", "DB EDh,0Fh", + "DB EDh,10h", "DB EDh,11h", "DB EDh,12h", "DB EDh,13h", "DB EDh,14h", "DB EDh,15h", "DB EDh,16h", "DB EDh,17h", + "DB EDh,18h", "DB EDh,19h", "DB EDh,1Ah", "DB EDh,1Bh", "DB EDh,1Ch", "DB EDh,1Dh", "DB EDh,1Eh", "DB EDh,1Fh", + "DB EDh,20h", "DB EDh,21h", "DB EDh,22h", "DB EDh,23h", "DB EDh,24h", "DB EDh,25h", "DB EDh,26h", "DB EDh,27h", + "DB EDh,28h", "DB EDh,29h", "DB EDh,2Ah", "DB EDh,2Bh", "DB EDh,2Ch", "DB EDh,2Dh", "DB EDh,2Eh", "DB EDh,2Fh", + "DB EDh,30h", "DB EDh,31h", "DB EDh,32h", "DB EDh,33h", "DB EDh,34h", "DB EDh,35h", "DB EDh,36h", "DB EDh,37h", + "DB EDh,38h", "DB EDh,39h", "DB EDh,3Ah", "DB EDh,3Bh", "DB EDh,3Ch", "DB EDh,3Dh", "DB EDh,3Eh", "DB EDh,3Fh", + "IN B,(C)", "OUT (C),B", "SBC HL,BC", "LD (#h),BC", "NEG", "RETN", "IM 0", "LD I,A", + "IN C,(C)", "OUT (C),C", "ADC HL,BC", "LD BC,(#h)", "DB EDh,4Ch", "RETI", "DB EDh,4Eh", "LD R,A", + "IN D,(C)", "OUT (C),D", "SBC HL,DE", "LD (#h),DE", "DB EDh,54h", "DB EDh,55h", "IM 1", "LD A,I", + "IN E,(C)", "OUT (C),E", "ADC HL,DE", "LD DE,(#h)", "DB EDh,5Ch", "DB EDh,5Dh", "IM 2", "LD A,R", + "IN H,(C)", "OUT (C),H", "SBC HL,HL", "LD (#h),HL", "DB EDh,64h", "DB EDh,65h", "DB EDh,66h", "RRD", + "IN L,(C)", "OUT (C),L", "ADC HL,HL", "LD HL,(#h)", "DB EDh,6Ch", "DB EDh,6Dh", "DB EDh,6Eh", "RLD", + "IN F,(C)", "DB EDh,71h", "SBC HL,SP", "LD (#h),SP", "DB EDh,74h", "DB EDh,75h", "DB EDh,76h", "DB EDh,77h", + "IN A,(C)", "OUT (C),A", "ADC HL,SP", "LD SP,(#h)", "DB EDh,7Ch", "DB EDh,7Dh", "DB EDh,7Eh", "DB EDh,7Fh", + "DB EDh,80h", "DB EDh,81h", "DB EDh,82h", "DB EDh,83h", "DB EDh,84h", "DB EDh,85h", "DB EDh,86h", "DB EDh,87h", + "DB EDh,88h", "DB EDh,89h", "DB EDh,8Ah", "DB EDh,8Bh", "DB EDh,8Ch", "DB EDh,8Dh", "DB EDh,8Eh", "DB EDh,8Fh", + "DB EDh,90h", "DB EDh,91h", "DB EDh,92h", "DB EDh,93h", "DB EDh,94h", "DB EDh,95h", "DB EDh,96h", "DB EDh,97h", + "DB EDh,98h", "DB EDh,99h", "DB EDh,9Ah", "DB EDh,9Bh", "DB EDh,9Ch", "DB EDh,9Dh", "DB EDh,9Eh", "DB EDh,9Fh", + "LDI", "CPI", "INI", "OUTI", "DB EDh,A4h", "DB EDh,A5h", "DB EDh,A6h", "DB EDh,A7h", + "LDD", "CPD", "IND", "OUTD", "DB EDh,ACh", "DB EDh,ADh", "DB EDh,AEh", "DB EDh,AFh", + "LDIR", "CPIR", "INIR", "OTIR", "DB EDh,B4h", "DB EDh,B5h", "DB EDh,B6h", "DB EDh,B7h", + "LDDR", "CPDR", "INDR", "OTDR", "DB EDh,BCh", "DB EDh,BDh", "DB EDh,BEh", "DB EDh,BFh", + "DB EDh,C0h", "DB EDh,C1h", "DB EDh,C2h", "DB EDh,C3h", "DB EDh,C4h", "DB EDh,C5h", "DB EDh,C6h", "DB EDh,C7h", + "DB EDh,C8h", "DB EDh,C9h", "DB EDh,CAh", "DB EDh,CBh", "DB EDh,CCh", "DB EDh,CDh", "DB EDh,CEh", "DB EDh,CFh", + "DB EDh,D0h", "DB EDh,D1h", "DB EDh,D2h", "DB EDh,D3h", "DB EDh,D4h", "DB EDh,D5h", "DB EDh,D6h", "DB EDh,D7h", + "DB EDh,D8h", "DB EDh,D9h", "DB EDh,DAh", "DB EDh,DBh", "DB EDh,DCh", "DB EDh,DDh", "DB EDh,DEh", "DB EDh,DFh", + "DB EDh,E0h", "DB EDh,E1h", "DB EDh,E2h", "DB EDh,E3h", "DB EDh,E4h", "DB EDh,E5h", "DB EDh,E6h", "DB EDh,E7h", + "DB EDh,E8h", "DB EDh,E9h", "DB EDh,EAh", "DB EDh,EBh", "DB EDh,ECh", "DB EDh,EDh", "DB EDh,EEh", "DB EDh,EFh", + "DB EDh,F0h", "DB EDh,F1h", "DB EDh,F2h", "DB EDh,F3h", "DB EDh,F4h", "DB EDh,F5h", "DB EDh,F6h", "DB EDh,F7h", + "DB EDh,F8h", "DB EDh,F9h", "DB EDh,FAh", "DB EDh,FBh", "DB EDh,FCh", "DB EDh,FDh", "DB EDh,FEh", "DB EDh,FFh" +}; + +static char *MnemonicsXX[256] = +{ + "NOP", "LD BC,#h", "LD (BC),A", "INC BC", "INC B", "DEC B", "LD B,*h", "RLCA", + "EX AF,AF'", "ADD I%,BC", "LD A,(BC)", "DEC BC", "INC C", "DEC C", "LD C,*h", "RRCA", + "DJNZ @h", "LD DE,#h", "LD (DE),A", "INC DE", "INC D", "DEC D", "LD D,*h", "RLA", + "JR @h", "ADD I%,DE", "LD A,(DE)", "DEC DE", "INC E", "DEC E", "LD E,*h", "RRA", + "JR NZ,@h", "LD I%,#h", "LD (#h),I%", "INC I%", "INC I%h", "DEC I%h", "LD I%h,*h", "DAA", + "JR Z,@h", "ADD I%,I%", "LD I%,(#h)", "DEC I%", "INC I%l", "DEC I%l", "LD I%l,*h", "CPL", + "JR NC,@h", "LD SP,#h", "LD (#h),A", "INC SP", "INC (I%+^h)", "DEC (I%+^h)", "LD (I%+^h),*h", "SCF", + "JR C,@h", "ADD I%,SP", "LD A,(#h)", "DEC SP", "INC A", "DEC A", "LD A,*h", "CCF", + "LD B,B", "LD B,C", "LD B,D", "LD B,E", "LD B,I%h", "LD B,I%l", "LD B,(I%+^h)", "LD B,A", + "LD C,B", "LD C,C", "LD C,D", "LD C,E", "LD C,I%h", "LD C,I%l", "LD C,(I%+^h)", "LD C,A", + "LD D,B", "LD D,C", "LD D,D", "LD D,E", "LD D,I%h", "LD D,I%l", "LD D,(I%+^h)", "LD D,A", + "LD E,B", "LD E,C", "LD E,D", "LD E,E", "LD E,I%h", "LD E,I%l", "LD E,(I%+^h)", "LD E,A", + "LD I%h,B", "LD I%h,C", "LD I%h,D", "LD I%h,E", "LD I%h,I%h", "LD I%h,I%l", "LD H,(I%+^h)", "LD I%h,A", + "LD I%l,B", "LD I%l,C", "LD I%l,D", "LD I%l,E", "LD I%l,I%h", "LD I%l,I%l", "LD L,(I%+^h)", "LD I%l,A", + "LD (I%+^h),B", "LD (I%+^h),C", "LD (I%+^h),D", "LD (I%+^h),E", "LD (I%+^h),H", "LD (I%+^h),L", "HALT", "LD (I%+^h),A", + "LD A,B", "LD A,C", "LD A,D", "LD A,E", "LD A,I%h", "LD A,I%l", "LD A,(I%+^h)", "LD A,A", + "ADD B", "ADD C", "ADD D", "ADD E", "ADD I%h", "ADD I%l", "ADD (I%+^h)", "ADD A", + "ADC B", "ADC C", "ADC D", "ADC E", "ADC I%h", "ADC I%l", "ADC (I%+^h)", "ADC,A", + "SUB B", "SUB C", "SUB D", "SUB E", "SUB I%h", "SUB I%l", "SUB (I%+^h)", "SUB A", + "SBC B", "SBC C", "SBC D", "SBC E", "SBC I%h", "SBC I%l", "SBC (I%+^h)", "SBC A", + "AND B", "AND C", "AND D", "AND E", "AND I%h", "AND I%l", "AND (I%+^h)", "AND A", + "XOR B", "XOR C", "XOR D", "XOR E", "XOR I%h", "XOR I%l", "XOR (I%+^h)", "XOR A", + "OR B", "OR C", "OR D", "OR E", "OR I%h", "OR I%l", "OR (I%+^h)", "OR A", + "CP B", "CP C", "CP D", "CP E", "CP I%h", "CP I%l", "CP (I%+^h)", "CP A", + "RET NZ", "POP BC", "JP NZ,#h", "JP #h", "CALL NZ,#h", "PUSH BC", "ADD *h", "RST 00h", + "RET Z", "RET", "JP Z,#h", "PFX_CB", "CALL Z,#h", "CALL #h", "ADC *h", "RST 08h", + "RET NC", "POP DE", "JP NC,#h", "OUT (*h),A", "CALL NC,#h", "PUSH DE", "SUB *h", "RST 10h", + "RET C", "EXX", "JP C,#h", "IN A,(*h)", "CALL C,#h", "PFX_DD", "SBC *h", "RST 18h", + "RET PO", "POP I%", "JP PO,#h", "EX I%,(SP)", "CALL PO,#h", "PUSH I%", "AND *h", "RST 20h", + "RET PE", "LD PC,I%", "JP PE,#h", "EX DE,I%", "CALL PE,#h", "PFX_ED", "XOR *h", "RST 28h", + "RET P", "POP AF", "JP P,#h", "DI", "CALL P,#h", "PUSH AF", "OR *h", "RST 30h", + "RET M", "LD SP,I%", "JP M,#h", "EI", "CALL M,#h", "PFX_FD", "CP *h", "RST 38h" +}; + +static char *MnemonicsXCB[256] = +{ + "RLC B", "RLC C", "RLC D", "RLC E", "RLC H", "RLC L", "RLC (I%@h)", "RLC A", + "RRC B", "RRC C", "RRC D", "RRC E", "RRC H", "RRC L", "RRC (I%@h)", "RRC A", + "RL B", "RL C", "RL D", "RL E", "RL H", "RL L", "RL (I%@h)", "RL A", + "RR B", "RR C", "RR D", "RR E", "RR H", "RR L", "RR (I%@h)", "RR A", + "SLA B", "SLA C", "SLA D", "SLA E", "SLA H", "SLA L", "SLA (I%@h)", "SLA A", + "SRA B", "SRA C", "SRA D", "SRA E", "SRA H", "SRA L", "SRA (I%@h)", "SRA A", + "SLL B", "SLL C", "SLL D", "SLL E", "SLL H", "SLL L", "SLL (I%@h)", "SLL A", + "SRL B", "SRL C", "SRL D", "SRL E", "SRL H", "SRL L", "SRL (I%@h)", "SRL A", + "BIT 0,B", "BIT 0,C", "BIT 0,D", "BIT 0,E", "BIT 0,H", "BIT 0,L", "BIT 0,(I%@h)", "BIT 0,A", + "BIT 1,B", "BIT 1,C", "BIT 1,D", "BIT 1,E", "BIT 1,H", "BIT 1,L", "BIT 1,(I%@h)", "BIT 1,A", + "BIT 2,B", "BIT 2,C", "BIT 2,D", "BIT 2,E", "BIT 2,H", "BIT 2,L", "BIT 2,(I%@h)", "BIT 2,A", + "BIT 3,B", "BIT 3,C", "BIT 3,D", "BIT 3,E", "BIT 3,H", "BIT 3,L", "BIT 3,(I%@h)", "BIT 3,A", + "BIT 4,B", "BIT 4,C", "BIT 4,D", "BIT 4,E", "BIT 4,H", "BIT 4,L", "BIT 4,(I%@h)", "BIT 4,A", + "BIT 5,B", "BIT 5,C", "BIT 5,D", "BIT 5,E", "BIT 5,H", "BIT 5,L", "BIT 5,(I%@h)", "BIT 5,A", + "BIT 6,B", "BIT 6,C", "BIT 6,D", "BIT 6,E", "BIT 6,H", "BIT 6,L", "BIT 6,(I%@h)", "BIT 6,A", + "BIT 7,B", "BIT 7,C", "BIT 7,D", "BIT 7,E", "BIT 7,H", "BIT 7,L", "BIT 7,(I%@h)", "BIT 7,A", + "RES 0,B", "RES 0,C", "RES 0,D", "RES 0,E", "RES 0,H", "RES 0,L", "RES 0,(I%@h)", "RES 0,A", + "RES 1,B", "RES 1,C", "RES 1,D", "RES 1,E", "RES 1,H", "RES 1,L", "RES 1,(I%@h)", "RES 1,A", + "RES 2,B", "RES 2,C", "RES 2,D", "RES 2,E", "RES 2,H", "RES 2,L", "RES 2,(I%@h)", "RES 2,A", + "RES 3,B", "RES 3,C", "RES 3,D", "RES 3,E", "RES 3,H", "RES 3,L", "RES 3,(I%@h)", "RES 3,A", + "RES 4,B", "RES 4,C", "RES 4,D", "RES 4,E", "RES 4,H", "RES 4,L", "RES 4,(I%@h)", "RES 4,A", + "RES 5,B", "RES 5,C", "RES 5,D", "RES 5,E", "RES 5,H", "RES 5,L", "RES 5,(I%@h)", "RES 5,A", + "RES 6,B", "RES 6,C", "RES 6,D", "RES 6,E", "RES 6,H", "RES 6,L", "RES 6,(I%@h)", "RES 6,A", + "RES 7,B", "RES 7,C", "RES 7,D", "RES 7,E", "RES 7,H", "RES 7,L", "RES 7,(I%@h)", "RES 7,A", + "SET 0,B", "SET 0,C", "SET 0,D", "SET 0,E", "SET 0,H", "SET 0,L", "SET 0,(I%@h)", "SET 0,A", + "SET 1,B", "SET 1,C", "SET 1,D", "SET 1,E", "SET 1,H", "SET 1,L", "SET 1,(I%@h)", "SET 1,A", + "SET 2,B", "SET 2,C", "SET 2,D", "SET 2,E", "SET 2,H", "SET 2,L", "SET 2,(I%@h)", "SET 2,A", + "SET 3,B", "SET 3,C", "SET 3,D", "SET 3,E", "SET 3,H", "SET 3,L", "SET 3,(I%@h)", "SET 3,A", + "SET 4,B", "SET 4,C", "SET 4,D", "SET 4,E", "SET 4,H", "SET 4,L", "SET 4,(I%@h)", "SET 4,A", + "SET 5,B", "SET 5,C", "SET 5,D", "SET 5,E", "SET 5,H", "SET 5,L", "SET 5,(I%@h)", "SET 5,A", + "SET 6,B", "SET 6,C", "SET 6,D", "SET 6,E", "SET 6,H", "SET 6,L", "SET 6,(I%@h)", "SET 6,A", + "SET 7,B", "SET 7,C", "SET 7,D", "SET 7,E", "SET 7,H", "SET 7,L", "SET 7,(I%@h)", "SET 7,A" +}; + +/* Symbolic disassembler + + Inputs: + *val = instructions to disassemble + useZ80Mnemonics = > 0 iff Z80 mnemonics are to be used + Outputs: + *S = output text + + DAsm is Copyright (C) Marat Fayzullin 1995,1996,1997 + You are not allowed to distribute this software + commercially. + +*/ + +int32 DAsm(char *S, uint32 *val, int32 useZ80Mnemonics) +{ + char R[128], H[10], C= '\0', *T, *P; + uint8 J = 0, Offset; + uint16 B = 0; + + if (useZ80Mnemonics) { + switch(val[B]) { + case 0xCB: + B++; + T = MnemonicsCB[val[B++]]; + break; + case 0xED: + B++; + T = MnemonicsED[val[B++]]; + break; + case 0xDD: + case 0xFD: + C = (val[B] == 0xDD) ? 'X' : 'Y'; + B++; + if (val[B] == 0xCB) { + B++; + Offset = val[B++]; + J = 1; + T = MnemonicsXCB[val[B++]]; + } + else { + T = MnemonicsXX[val[B++]]; + } + break; + default: + T = MnemonicsZ80[val[B++]]; + } + } + else { + T = Mnemonics8080[val[B++]]; + } + + if (P = strchr(T, '^')) + { + strncpy(R, T, P - T); + R[P - T] = '\0'; + sprintf(H, "%02X", val[B++]); + strcat(R, H); + strcat(R, P + 1); + } + else { + strcpy(R, T); + } + if (P = strchr(R, '%')) { + *P = C; + if (P = strchr(P + 1, '%')) *P = C; + } + + if(P = strchr(R, '*')) { + strncpy(S, R, P - R); + S[P - R] = '\0'; + sprintf(H, "%02X", val[B++]); + strcat(S, H); + strcat(S, P + 1); + } + else if (P = strchr(R, '@')) { + strncpy(S, R, P - R); + S[P - R] = '\0'; + if(!J) { + Offset = val[B++]; + } + strcat(S, Offset & 0x80 ? "-" : "+"); + J = Offset & 0x80 ? 256 - Offset : Offset; + sprintf(H, "%02X", J); + strcat(S, H); + strcat(S, P + 1); + } + else if (P = strchr(R, '#')) { + strncpy(S, R, P - R); + S[P - R] = '\0'; + sprintf(H, "%04X", val[B] + 256*val[B + 1]); + strcat(S, H); + strcat(S, P + 1); + B += 2; + } + else { + strcpy(S, R); + } + return(B); +} + +/* Symbolic output + + Inputs: + *of = output stream + addr = current PC + *val = pointer to values + *uptr = pointer to unit + sw = switches + Outputs: + status = error code +*/ + +int32 fprint_sym (FILE *of, int32 addr, uint32 *val, UNIT *uptr, int32 sw) +{ + char disasm[128]; + int32 ch = val[0] & 0x7f; + if (sw & (SWMASK ('A') | SWMASK ('C'))) { + fprintf(of, ((0x20 <= ch) && (ch < 0x7f)) ? "'%c'" : "%02x", ch); + return SCPE_OK; + } + if (!(sw & SWMASK ('M'))) { + return SCPE_ARG; + } + ch = DAsm(disasm, val, cpu_unit.flags & UNIT_CHIP); + fprintf(of, "%s", disasm); + return (1-ch); /* need to return additional bytes */ +} + +/* numString checks determines the base of the number (ch, *numString) + and returns FALSE if the number is bad */ +int32 checkbase(char ch, char *numString) { + int32 decimal = (ch <= '9'); + if (toupper(ch) == 'H') { + return FALSE; + } + while (isxdigit(ch = *numString++)) { + if (ch > '9') { + decimal = FALSE; + } + } + return toupper(ch) == 'H' ? 16 : (decimal ? 10 : FALSE); +} + +int32 numok(char ch, char **numString, int32 minvalue, int32 maxvalue, int32 requireSign, int32 *result) { + int32 sign = 1, value = 0, base; + if (requireSign) { + if (ch == '+') { + ch = *(*numString)++; + } + else if (ch == '-') { + sign = -1; + ch = *(*numString)++; + } + else { + return FALSE; + } + } + if (!(base = checkbase(ch, *numString))) { + return FALSE; + } + while (isxdigit(ch)) { + value = base * value + ((ch <= '9') ? (ch - '0') : (toupper(ch) - 'A' + 10)); + ch = *(*numString)++; + } + if (toupper(ch) != 'H') { + (*numString)--; + } + *result = value*sign; + return (minvalue <= value) && (value <= maxvalue); +} + +int32 match(char *pattern, char *input, char *xy, int32 *number, int32 *star, + int32 *at, int32 *hat) { + char pat = *pattern++; + char inp = *input++; + while ((pat) && (inp)) { + switch(pat) { + case ',': + if (inp == ' ') { + inp = *input++; + continue; + } + case ' ': + if (inp != pat) { + return FALSE; + } + pat = *pattern++; + inp = *input++; + while (inp == ' ') { + inp = *input++; + } + continue; + break; + case '%': + inp = toupper(inp); + if ((inp == 'X') || (inp == 'Y')) { + *xy = inp; + } + else { + return FALSE; + } + break; + case '#': + if (numok(inp, &input, 0, 65535, FALSE, number)) { + pattern++; /* skip h */ + } + else { + return FALSE; + } + break; + case '*': + if (numok(inp, &input, 0, 255, FALSE, star)) { + pattern++; /* skip h */ + } + else { + return FALSE; + } + break; + case '@': + if (numok(inp, &input, -128, 65535, TRUE, at)) { + pattern++; /* skip h */ + } + else { + return FALSE; + } + break; + case '^': + if (numok(inp, &input, 0, 255, FALSE, hat)) { + pattern++; /* skip h */ + } + else { + return FALSE; + } + break; + default: + if (toupper(pat) != toupper(inp)) { + return FALSE; + } + } + pat = *pattern++; + inp = *input++; + } + while (inp == ' ') { + inp = *input++; + } + return (pat == 0) && (inp == 0); +} + +inline int32 checkXY(char xy) { + if (xy == 'X') { + return 0xDD; + } + else if (xy == 'Y') { + return 0xFD; + } + else { + printf("X or Y expected.\n"); + return FALSE; + } +} + +int32 parse_X80(char *cptr, int32 addr, uint32 *val, char *Mnemonics[]) { + char xy; + int32 op, number, star, at, hat; + for (op = 0; op < 256; op++) { + number = star = at = -129; + if (match(Mnemonics[op], cptr, &xy, &number, &star, &at, &hat)) { + val[0] = op; + if (number >= 0) { + val[1] = (0xff) & number; + val[2] = (0xff) & (number >> 8); + return (-2); /* two additional bytes returned */ + } + else if (star >= 0) { + val[1] = (0xff) & star; + return (-1); /* one additional byte returned */ + } + else if (at > -129) { + if (at > 127) { /* assume absolute address is meant */ + at -= addr + 2; /* translate to relative address */ + } + if ((-128 <= at) && (at < 127)) { + val[1] = (int8)(at); + return (-1); + } + else { + return SCPE_ARG; + } + } + else { + return SCPE_OK; + } + } + } + if (Mnemonics == Mnemonics8080) { + return SCPE_ARG; + } + + for (op = 0; op < 256; op++) { + if (match(MnemonicsCB[op], cptr, &xy, &number, &star, &at, &hat)) { + val[0] = 0xCB; + val[1] = op; + return (-1); /* one additional byte returned */ + } + } + + for (op = 0; op < 256; op++) { + number = -1; + if (match(MnemonicsED[op], cptr, &xy, &number, &star, &at, &hat)) { + val[0] = 0xED; + val[1] = op; + if (number >= 0) { + val[2] = (0xff) & number; + val[3] = (0xff) & (number >> 8); + return (-3); /* three additional bytes returned */ + } + else { + return (-1); /* one additional byte returned */ + } + } + } + + for (op = 0; op < 256; op++) { + number = star = hat = -1; + xy = ' '; + if (match(MnemonicsXX[op], cptr, &xy, &number, &star, &at, &hat)) { + if (!(val[0] = checkXY(xy))) { + return SCPE_ARG; + } + val[1] = op; + if (number >= 0) { + val[2] = (0xff) & number; + val[3] = (0xff) & (number >> 8); + return (-3); /* three additional bytes returned */ + } + else if ((star >= 0) && (hat >= 0)) { + val[2] = (0xff) & hat; + val[3] = (0xff) & star; + return (-3); /* three additional bytes returned */ + } + else if (star >= 0) { + val[2] = (0xff) & star; + return (-2); /* two additional bytes returned */ + } + else if (hat >= 0) { + val[2] = (0xff) & hat; + return (-2); /* two additional bytes returned */ + } + else { + return (-1); /* one additional byte returned */ + } + } + } + + for (op = 0; op < 256; op++) { + at = -129; + xy = ' '; + if (match(MnemonicsXCB[op], cptr, &xy, &number, &star, &at, &hat)) { + if (!(val[0] = checkXY(xy))) { + return SCPE_ARG; + } + val[1] = 0xCB; + if (at > -129) { + val[2] = (int8) (at); + } + else { + printf("Offset expected.\n"); + return SCPE_ARG; + } + val[3] = op; + return (-3); /* three additional bytes returned */ + } + } + return SCPE_ARG; +} + + +/* Symbolic input + + Inputs: + *cptr = pointer to input string + addr = current PC + *uptr = pointer to unit + *val = pointer to output values + sw = switches + Outputs: + status = error status +*/ +int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw) +{ + while (isspace (*cptr)) cptr++; /* absorb spaces */ + if ((sw & (SWMASK ('A') | SWMASK ('C'))) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ + if (cptr[0] == 0) { + return SCPE_ARG; /* must have 1 char */ + } + 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); +} + + +/* 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. +*/ + +int32 sim_load (FILE *fileref, char *cptr, char *fnam, int32 flag) +{ + int32 i, addr = 0, cnt = 0; + + if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; + addr = saved_PC; + while ((i = getc (fileref)) != EOF) { + M[addr++] = i; + cnt++; + } /* end while */ + printf ("%d Bytes loaded.\n", cnt); + return (SCPE_OK); +} diff --git a/h316_cpu.c b/H316/h316_cpu.c similarity index 94% rename from h316_cpu.c rename to H316/h316_cpu.c index 2001c2a6..0f4fc778 100644 --- a/h316_cpu.c +++ b/H316/h316_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. + cpu H316/H516 CPU + + 03-Nov-01 RMS Fixed NOHSA modifier + 30-Nov-01 RMS Added extended SET/SHOW support + The register state for the Honeywell 316/516 CPU is: AR<1:16> A register @@ -184,8 +189,6 @@ #include "h316_defs.h" -#define ILL_ADR_FLAG 0100000 -#define save_ibkpt (cpu_unit.u3) #define UNIT_V_MSIZE (UNIT_V_UF) /* dummy mask */ #define UNIT_MSIZE (1 << UNIT_V_MSIZE) #define m7 0001000 /* for generics */ @@ -216,21 +219,20 @@ int32 dev_enable = 0; /* dev enable */ int32 ind_max = 8; /* iadr nest limit */ int32 stop_inst = 1; /* stop on ill inst */ int32 stop_dev = 2; /* stop on ill dev */ -int32 ibkpt_addr = ILL_ADR_FLAG | X_AMASK; /* breakpoint addr */ int32 old_PC = 0; /* previous PC */ int32 dlog = 0; /* debug log */ int32 turnoff = 0; - extern int32 sim_int_char; +extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ extern FILE *sim_log; + extern t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, UNIT *uptr, int32 sw); 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_svc (UNIT *uptr); -t_stat cpu_set_noext (UNIT *uptr, int32 value); -t_stat cpu_set_size (UNIT *uptr, int32 value); +t_stat cpu_set_noext (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); /* CPU data structures @@ -240,7 +242,7 @@ t_stat cpu_set_size (UNIT *uptr, int32 value); cpu_mod CPU modifiers list */ -UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK + UNIT_EXT, +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK + UNIT_EXT, MAXMEMSIZE) }; REG cpu_reg[] = { @@ -268,7 +270,6 @@ REG cpu_reg[] = { { FLDATA (STOP_DEV, stop_dev, 1) }, { DRDATA (INDMAX, ind_max, 8), REG_NZ + PV_LEFT }, { ORDATA (OLDP, old_PC, 15), REG_RO }, - { ORDATA (BREAK, ibkpt_addr, 16) }, { ORDATA (WRU, sim_int_char, 8) }, { FLDATA (DLOG, dlog, 0) }, { FLDATA (HEXT, cpu_unit.flags, UNIT_V_EXT), REG_HRO }, @@ -278,7 +279,7 @@ REG cpu_reg[] = { MTAB cpu_mod[] = { { UNIT_EXT, 0, "no extend", "NOEXTEND", &cpu_set_noext }, { UNIT_EXT, UNIT_EXT, "extend", "EXTEND", NULL }, - { UNIT_HSA, 0, "no HSA", "HSA", NULL }, + { UNIT_HSA, 0, "no HSA", "NOHSA", NULL }, { UNIT_HSA, UNIT_HSA, "HSA", "HSA", NULL }, { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size }, { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size }, @@ -362,10 +363,8 @@ if ((dev_ready & (INT_PENDING | dev_enable)) > INT_PENDING) { /* int req? */ if (dlog && sim_log) fprintf (sim_log, "Interrupt\n"); MB = 0120000 | M_INT; } /* inst = JST* 63 */ -else { if (PC == ibkpt_addr) { /* breakpoint? */ - save_ibkpt = ibkpt_addr; /* save address */ - ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */ - sim_activate (&cpu_unit, 1); /* sched re-enable */ +else { if (sim_brk_summ && + sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ reason = STOP_IBKPT; /* stop simulation */ break; } Y = PC; /* set mem addr */ @@ -986,7 +985,8 @@ dp = 0; ext = pme = extoff_pending = 0; dev_ready = dev_ready & ~INT_PENDING; dev_enable = 0; -return cpu_svc (&cpu_unit); +sim_brk_types = sim_brk_dflt = SWMASK ('E'); +return SCPE_OK; } /* Memory examine */ @@ -1012,35 +1012,26 @@ else M[addr] = val & DMASK; return SCPE_OK; } -/* Breakpoint service */ - -t_stat cpu_svc (UNIT *uptr) -{ -if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt) ibkpt_addr = save_ibkpt; -save_ibkpt = -1; -return SCPE_OK; -} - /* Option processors */ -t_stat cpu_set_noext (UNIT *uptr, int32 value) +t_stat cpu_set_noext (UNIT *uptr, int32 val, char *cptr, void *desc) { if (MEMSIZE > (NX_AMASK + 1)) return SCPE_ARG; return SCPE_OK; } -t_stat cpu_set_size (UNIT *uptr, int32 value) +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { int32 mc = 0; t_addr i; -if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 07777) != 0) || - (((cpu_unit.flags & UNIT_EXT) == 0) && (value > (NX_AMASK + 1)))) +if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0) || + (((cpu_unit.flags & UNIT_EXT) == 0) && (val > (NX_AMASK + 1)))) return SCPE_ARG; -for (i = value; i < MEMSIZE; i++) mc = mc | M[i]; +for (i = val; i < MEMSIZE; i++) mc = mc | M[i]; if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) return SCPE_OK; -MEMSIZE = value; +MEMSIZE = val; for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; return SCPE_OK; } diff --git a/h316_defs.h b/H316/h316_defs.h similarity index 100% rename from h316_defs.h rename to H316/h316_defs.h diff --git a/H316/h316_doc.txt b/H316/h316_doc.txt new file mode 100644 index 00000000..32d36018 --- /dev/null +++ b/H316/h316_doc.txt @@ -0,0 +1,303 @@ +To: Users +From: Bob Supnik +Subj: H316 Simulator Usage +Date: 1-Dec-2001 + + COPYRIGHT NOTICE + +The following copyright notice applies to both the SIMH source and binary: + + Original code published in 1993-2001, written by Robert M Supnik + 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. + +This memorandum documents Honeywell 316/516 simulator. + + +1. Simulator Files + +The H316 requires the following files: + +sim/ sim_defs.h + scp.c + scp_tty.c + sim_rev.c + +sim/h316/ h316_defs.h + h316_cpu.c + h316_lp.c + h316_stddev.c + h316_cpu.c + +2. H316/H516 Features + +The Honeywell 316/516 simulator is configured as follows: + +device simulates +name(s) + +CPU H316/H516 CPU with 16/32KW memory +PTR 316/516-50 paper tape reader +PTP 316/516-52 paper tape punch +TTY 316/516-33 console terminal +CLK 316/516-12 real time clock +LPT 316/516 line printer + +The H316/H516 simulator implements several unique stop conditions: + + - decode of an undefined instruction, and STOP_INST is et + - reference to an undefined I/O device, and STOP_DEV is set + - more than INDMAX indirect references are detected during + memory reference address decoding + +The H316/H516 loader is not implemented. + +2.1 CPU + +CPU options include choice of instruction set and memory size. + + SET CPU HSA high speed arithmetic instructions + SET CPU NOHSA no high speed arithmetic instructions + SET CPU 4K set memory size = 4K + SET CPU 8K set memory size = 8K + SET CPU 12K set memory size = 12K + SET CPU 16K set memory size = 16K + SET CPU 24K set memory size = 24K + SET CPU 32K set memory size = 32K + +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. + +CPU registers include the visible state of the processor as well as the +control registers for the interrupt system. + + name size comments + + P 15 program counter + A 16 A register + B 16 B register + X 16 index register + SC 16 shift count + C 1 carry flag + EXT 1 extend flag + PME 1 previous mode extend flag + EXT_OFF 1 extend off pending flag + DP 1 double precision flag + SS1..4 1 sense switches 1..4 + ION 1 interrupts enabled + INODEF 1 interrupts not deferred + INTREQ 16 interrupt requests + DEVRDY 16 device ready flags (read only) + DEVENB 16 device interrupt enable flags (read only) + STOP_INST 1 stop on undefined instruction + STOP_DEV 1 stop on undefined device + INDMAX 1 indirect address limit + OLDP 15 PC prior to last JMP, JSB, or interrupt + WRU 8 interrupt character + +2.2 Programmed I/O Devices + +2.2.1 316/516-50 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 copies the +absolute binary loader into memory and starts it running. + +The paper tape reader implements these registers: + + name size comments + + BUF 8 last data item processed + INTREQ 1 device interrupt request + READY 1 device ready + ENABLE 1 device interrupts enabled + POS 31 position in the input or output file + TIME 24 time from I/O initiation to interrupt + 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 out of tape + + end of file 1 report error and stop + 0 out of tape or paper + + OS I/O error x report error and stop + +2.2.2 316/516-52 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. +Thus, by changing POS, the user can backspace or advance the punch. + +The paper tape punch implements these registers: + + name size comments + + BUF 8 last data item processed + INTREQ 1 device interrupt request + READY 1 device ready + ENABLE 1 device interrupts enabled + POWER 1 device powered up + POS 31 position in the input or output file + TIME 24 time from I/O initiation to interrupt + PWRTIME 24 time from I/O request to power up + 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 out of tape + + OS I/O error x report error and stop + +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 terminal these registers: + + name size comments + + BUF 8 last data item processed + MODE 1 read/write mode + INTREQ 1 device interrupt request + READY 1 device ready + ENABLE 1 device interrupts enabled + KPOS 31 number of characters input + KTIME 24 keyboard polling interval + TPOS 31 number of characters output + TTIME 24 time from I/O initiation to interrupt + +2.2.4 316/516-12 Real Time Clock (CLK) + +The real time clock (CLK) implements these registers: + + name size comments + + INTREQ 1 device interrupt request + READY 1 device ready + ENABLE 1 device interrupts enabled + TIME 24 clock interval + +2.2.5 316/5116 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, +by changing POS, the user can backspace or advance the printer. + +The line printer implements these registers: + + name size comments + + WDPOS 6 word position in current scan + DRPOS 6 drum position + CRPOS 1 carriage position + XFER 1 transfer ready flag + PRDN 1 print done flag + INTREQ 1 device interrupt request + ENABLE 1 device interrupt enable + SVCST 2 service state + SVCCH 2 service channel + BUF 8 buffer + POS 31 number of characters output + XTIME 24 delay between transfers + ETIME 24 delay at end of scan + PTIME 24 delay for shuttle/line advance + 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 out of paper + + OS I/O error x report error and stop + +2.3 Symbolic Display and Input + +The H316/H516 simulator implements symbolic display and input. Display is +controlled by command line switches: + + -a display as ASCII character + -c display as two character string + -m display instruction mnemonics + +Input parsing is controlled by the first character typed in or by command +line switches: + + ' or -a ASCII character + " or -c two character sixbit string + alphabetic instruction mnemonic + numeric octal number + +Instruction input uses standard H316/H516 assembler syntax. There are six +instruction classes: memory reference, I/O, control, shift, skip, and +operate. + +Memory reference instructions have the format + + memref{*} {C/Z} address{,1} + +where * signifies indirect, C a current sector reference, Z a sector zero +reference, and 1 indexed. The address is an octal number in the range 0 - +077777; if C or Z is specified, the address is a page offset in the range +0 - 0777. Normally, C is not needed; the simulator figures out from the +address what mode to use. However, when referencing memory outside the CPU +(eg, disks), there is no valid PC, and C must be used to specify current +sector addressing. + +I/O instructions have the format + + io pulse+device + +The pulse+device is an octal number in the range 0 - 01777. + +Control and operate instructions consist of a single opcode + + opcode + +Shift instructions have the format + + shift n + +where n is an octal number in the range 0-77. + +Skip instructions have the format + + sub-op sub-op sub-op... + +The simulator checks that the combination of sub-opcodes is legal. diff --git a/h316_lp.c b/H316/h316_lp.c similarity index 100% rename from h316_lp.c rename to H316/h316_lp.c diff --git a/h316_stddev.c b/H316/h316_stddev.c similarity index 93% rename from h316_stddev.c rename to H316/h316_stddev.c index 514eda6d..2dd27cc7 100644 --- a/h316_stddev.c +++ b/H316/h316_stddev.c @@ -28,6 +28,8 @@ tty 316/516-33 teleprinter clk/options 316/516-12 real time clocks/internal options + 03-Nov-01 RMS Implemented upper case for console output + 29-Nov-01 RMS Added read only unit support 07-Sep-01 RMS Moved function prototypes */ @@ -66,7 +68,8 @@ t_stat clk_reset (DEVICE *dptr); */ UNIT ptr_unit = { - UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_IN_WAIT }; + UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), + SERIAL_IN_WAIT }; REG ptr_reg[] = { { ORDATA (BUF, ptr_unit.buf, 8) }, @@ -125,7 +128,7 @@ DEVICE ptp_dev = { UNIT tty_unit[] = { { UDATA (&tti_svc, UNIT_UC, 0), KBD_POLL_WAIT }, - { UDATA (&tto_svc, UNIT_UC, 0), SERIAL_OUT_WAIT } }; + { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT } }; REG tty_reg[] = { { ORDATA (BUF, tty_buf, 8) }, @@ -397,10 +400,13 @@ return SCPE_OK; t_stat tto_svc (UNIT *uptr) { -int32 temp; +int32 ch, temp; SET_READY (INT_TTY); /* set done flag */ -if ((temp = sim_putchar (tty_buf & 0177)) != SCPE_OK) return temp; +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 */ tty_unit[TTO].pos = tty_unit[TTO].pos + 1; return SCPE_OK; } diff --git a/h316_sys.c b/H316/h316_sys.c similarity index 100% rename from h316_sys.c rename to H316/h316_sys.c diff --git a/hp2100_cpu.c b/HP2100/hp2100_cpu.c similarity index 93% rename from hp2100_cpu.c rename to HP2100/hp2100_cpu.c index 2cdea58c..1536e738 100644 --- a/hp2100_cpu.c +++ b/HP2100/hp2100_cpu.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. + 07-Dec-01 RMS Revised to use breakpoint package + 03-Dec-01 RMS Added extended SET/SHOW support 10-Aug-01 RMS Removed register in declarations 26-Nov-00 RMS Fixed bug in dual device number routine 21-Nov-00 RMS Fixed bug in reset routine @@ -238,8 +240,6 @@ #include "hp2100_defs.h" -#define ILL_ADR_FLAG 0100000 -#define save_ibkpt (cpu_unit.u3) #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 */ @@ -269,10 +269,10 @@ int32 maddr = 0; /* mem prot err addr */ int32 ind_max = 16; /* iadr nest limit */ int32 stop_inst = 1; /* stop on ill inst */ int32 stop_dev = 2; /* stop on ill dev */ -int32 ibkpt_addr = ILL_ADR_FLAG | AMASK; /* breakpoint addr */ int32 old_PC = 0; /* previous PC */ - extern int32 sim_int_char; +extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ + int32 shift (int32 inval, int32 flag, int32 oper); int32 calc_dma (void); int32 calc_int (void); @@ -282,8 +282,7 @@ 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_svc (UNIT *uptr); -t_stat cpu_set_size (UNIT *uptr, int32 value); +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); /* CPU data structures @@ -293,7 +292,7 @@ t_stat cpu_set_size (UNIT *uptr, int32 value); cpu_mod CPU modifiers list */ -UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK, +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) }; REG cpu_reg[] = { @@ -317,7 +316,6 @@ REG cpu_reg[] = { { FLDATA (STOP_DEV, stop_dev, 1) }, { DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT }, { ORDATA (OLDP, old_PC, 15), REG_RO }, - { ORDATA (BREAK, ibkpt_addr, 16) }, { 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 }, @@ -531,10 +529,8 @@ if (intrq && ((intrq <= PRO) || !ion_defer)) { /* interrupt request? */ intrq = 0; /* clear request */ clrCTL (PRO); } /* protection off */ -else { if (PC == ibkpt_addr) { /* breakpoint? */ - save_ibkpt = ibkpt_addr; /* save address */ - ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */ - sim_activate (&cpu_unit, 1); /* sched re-enable */ +else { if (sim_brk_summ && + sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ reason = STOP_IBKPT; /* stop simulation */ break; } err_PC = PC; /* save PC for error */ @@ -1343,7 +1339,8 @@ clrFLG (PRO); clrFBF (PRO); mfence = 0; maddr = 0; -return cpu_svc (&cpu_unit); +sim_brk_types = sim_brk_dflt = SWMASK ('E'); +return SCPE_OK; } t_stat dma0_reset (DEVICE *tptr) @@ -1391,45 +1388,29 @@ else M[addr] = val & DMASK; return SCPE_OK; } -/* Breakpoint service */ - -t_stat cpu_svc (UNIT *uptr) -{ -if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt) ibkpt_addr = save_ibkpt; -save_ibkpt = -1; -return SCPE_OK; -} - -t_stat cpu_set_size (UNIT *uptr, int32 value) +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { int32 mc = 0; t_addr i; -if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 07777) != 0)) +if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0)) return SCPE_ARG; -for (i = value; i < MEMSIZE; i++) mc = mc | M[i]; +for (i = val; i < MEMSIZE; i++) mc = mc | M[i]; if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) return SCPE_OK; -MEMSIZE = value; +MEMSIZE = val; for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; return SCPE_OK; } -/* Set device number */ +/* Set/show device number */ -extern char *read_line (char *ptr, int size, FILE *stream); -extern t_value get_uint (char *cptr, int radix, t_value max, t_stat *status); - -t_stat hp_setdev (UNIT *uptr, int32 ord) +t_stat hp_setdev (UNIT *uptr, int32 ord, char *cptr, void *desc) { -char cbuf[CBUFSIZE], *cptr; -int32 i, olddev, newdev; +int32 i, newdev; t_stat r; -olddev = infotab[ord].devno; -printf ("Device number: %-o ", olddev); -cptr = read_line (cbuf, CBUFSIZE, stdin); -if ((cptr == NULL) || (*cptr == 0)) return SCPE_OK; +if (cptr == NULL) return SCPE_ARG; newdev = get_uint (cptr, 8, DEVMASK, &r); if (r != SCPE_OK) return r; if (newdev < VARDEV) return SCPE_ARG; @@ -1440,23 +1421,35 @@ infotab[ord].devno = newdev; return SCPE_OK; } -/* Set device number for data/control pair */ - -t_stat hp_setdev2 (UNIT *uptr, int32 ord) +t_stat hp_showdev (FILE *st, UNIT *uptr, int32 ord, void *desc) { -int32 i, olddev; +fprintf (st, "devno=%o", infotab[ord].devno); +return SCPE_OK; +} + +/* Set/show device number for data/control pair */ + +t_stat hp_setdev2 (UNIT *uptr, int32 ord, char *cptr, void *desc) +{ +int32 i, olddev, newdev; t_stat r; olddev = infotab[ord].devno; -if ((r = hp_setdev (uptr, ord)) != SCPE_OK) return r; -if (infotab[ord].devno == DEVMASK) { +if ((r = hp_setdev (uptr, ord, cptr, NULL)) != SCPE_OK) return r; +newdev = infotab[ord].devno + 1; +if (newdev > DEVMASK) { infotab[ord].devno = olddev; return SCPE_ARG; } for (i = 0; infotab[i].devno != 0; i++) { - if ((i != (ord + 1)) && - ((infotab[ord].devno + 1) == infotab[i].devno)) { + if ((i != (ord + 1)) && (newdev == infotab[i].devno)) { infotab[ord].devno = olddev; return SCPE_ARG; } } infotab[ord + 1].devno = infotab[ord].devno + 1; return SCPE_OK; } + +t_stat hp_showdev2 (FILE *st, UNIT *uptr, int32 ord, void *desc) +{ +fprintf (st, "devno=%o/%o", infotab[ord].devno, infotab[ord + 1].devno); +return SCPE_OK; +} diff --git a/hp2100_defs.h b/HP2100/hp2100_defs.h similarity index 92% rename from hp2100_defs.h rename to HP2100/hp2100_defs.h index 21fa7b8f..7c6472c7 100644 --- a/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. + 30-Nov-01 RMS Added extended SET/SHOW support 15-Oct-00 RMS Added dynamic device numbers 14-Apr-99 RMS Changed t_addr to unsigned @@ -178,5 +179,7 @@ struct hpdev { /* Function prototypes */ -t_bool hp_setdev (UNIT *uptr, int32 val); -t_bool hp_setdev2 (UNIT *uptr, int32 val); +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 hp_setdev2 (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat hp_showdev2 (FILE *st, UNIT *uptr, int32 val, void *desc); diff --git a/HP2100/hp2100_doc.txt b/HP2100/hp2100_doc.txt new file mode 100644 index 00000000..c120b6b5 --- /dev/null +++ b/HP2100/hp2100_doc.txt @@ -0,0 +1,471 @@ +To: Users +From: Bob Supnik +Subj: HP2100 Simulator Usage +Date: 1-Dec-01 + + COPYRIGHT NOTICE + +The following copyright notice applies to both the SIMH source and binary: + + Original code published in 1993-2001, written by Robert M Supnik + 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. + +This memorandum documents the HP 2100 simulator. + + +1. Simulator Files + +sim/ sim_defs.h + scp.c + scp_tty.c + sim_rev.c + +sim/hp2100/ hp2100_defs.h + hp2100_cpu.c + hp2100_dp.c + hp2100_lp.c + hp2100_mt.c + hp2100_stddev.c + hp2100_sys.c + +2. HP2100 Features + +The HP2100 simulator is configured as follows: + +device simulates +name(s) + +CPU 2116, 2100, or 21MX CPU with 32KW memory +DMA0, DMA1 dual channel DMA controller +PTR,PTP 12597A paper tape reader/punch +TTY 12631C buffered teleprinter +LPT 12653A line printer +CLK 12539A/B/C time base generator +DP 12557A cartridge disk controller with four drives +MT 12559C magnetic tape controller with one drives + +The HP2100 simulator implements several unique stop conditions: + + - decode of an undefined instruction, and STOP_INST is et + - reference to an undefined I/O device, and STOP_DEV is set + - more than INDMAX indirect references are detected during + memory reference address decoding + +The HP2100 loader supports standard absolute binary format. The DUMP +command is not implemented. + +2.1 CPU + +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 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 + +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. + +CPU registers include the visible state of the processor as well as the +control registers for the interrupt system. + + name 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 + OLDP 15 PC prior to last JMP, JSB, or interrupt + WRU 8 interrupt character + +2.2 DMA Controllers + +The HP2100 includes two DMA channel controllers (DMA0 and DMA1). Each +DMA channel has the following visible state: + + name size comments + + CMD 1 channel enabled + 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 + +2.3 Variable Device Assignments + +On the HP2100, I/O device take their device numbers from the backplane +slot they are plugged into. Thus, device number assignments vary +considerably from system to system, and software package to software +package. The HP2100 simulator supports dynamic device number assignment. +The current device device is shown with the command SHOW DEVNO: + + sim> SHOW PTR DEV + device=10 + +The user can change the device number with the SET DEVNO= +command: + + sim> SET PTR DEV=30 + sim> SHOW PTR DEV + device=30 + +The new device number must be in the range 010..077 (octal) and must +not be currently assigned to another device. For devices with two +device numbers, only the lower numbered device number can be changed; +the higher is automatically set to the lower + 1. + +2.4 Programmed I/O Devices + +2.4.1 12597A-002 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 copies the +absolute binary loader into memory and starts it running. + +The paper tape reader implements these registers: + + name size comments + + BUF 8 last data item processed + CMD 1 reader enable + CTL 1 device/interrupt enable + FLG 1 device ready + FBF 1 device ready buffer + POS 31 position in the input file + TIME 24 time from I/O initiation to interrupt + STOP_IOE 1 stop on I/O error + DEVNO 6 current device number (read only) + +Error handling is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 out of tape + + end of file 1 report error and stop + 0 out of tape or paper + + OS I/O error x report error and stop + +2.4.2 12597A-005 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. +Thus, by changing POS, the user can backspace or advance the punch. + +The paper tape punch implements these registers: + + name size comments + + BUF 8 last data item processed + CMD 1 punch enable + CTL 1 device/interrupt enable + FLG 1 device ready + FBF 1 device ready buffer + POS 31 position in the output file + TIME 24 time from I/O initiation to interrupt + STOP_IOE 1 stop on I/O error + DEVNO 6 current device number (read only) + +Error handling is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 out of tape + + OS I/O error x report error and stop + +2.4.3 12631C Buffered Teleprinter (TTY) + +The console teleprinter 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. + +The terminal implements these registers: + + name size comments + + BUF 8 last data item processed + MODE 16 mode + CTL 1 device/interrupt enable + FLG 1 device ready + FBF 1 device ready buffer + KPOS 31 number of characters input + KTIME 24 keyboard polling interval + TPOS 31 number of characters printed + TTIME 24 time from I/O initiation to interrupt + PPOS 31 position in the punch output file + STOP_IOE 1 punch stop on I/O error + DEVNO 6 current device number (read only) + +Error handling for the punch is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 out of tape + + OS I/O error x report error and stop + +2.4.4 12653A 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, +by changing POS, the user can backspace or advance the printer. + +The line printer implements these registers: + + name size comments + + BUF 8 last data item processed + CMD 1 printer enable + CTL 1 device/interrupt enable + FLG 1 device ready + FBF 1 device ready buffer + POS 31 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 + DEVNO 6 current device number (read only) + +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 + +2.4.5 12539A/B/C Time Base Generator (CLK) + +The time base generator (CLK) implements these registers: + + name size comments + + SEL 3 time base select + CTL 1 device/interrupt enable + FLG 1 device ready + FBF 1 device ready buffer + ERR 1 error flag + TIME[0:7] 31 clock intervals, select = 0..7 + DEVNO 6 current device number (read only) + +2.5 12557A Cartridge Disk (DP) + +The 12557A cartridge disk 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 REMOVEd or ADDed to the configuration. + +The data channel implements these registers: + + name size comments + + IBUF 16 input buffer + OBUF 16 output buffer + BPTR 7 sector buffer pointer + CMD 1 channel enable + CTL 1 interrupt enable + FLG 1 channel ready + FBF 1 channel ready buffer + DEVNO 6 current device number (read only) + +The device controller implements these registers: + + name size comments + + 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 + STIME 24 seek delay time, per cylinder + XTIME 24 interword transfer time + STA[0:3] 16 drive status, drives 0-3 + DEVNO 6 current device number (read only) + +Error handling is as follows: + + error processed as + + not attached disk not ready + + end of file assume rest of disk is zero + + OS I/O error report error and stop + +2.6 12559C Magnetic Tape (MT) + +Magnetic tape options include the ability to make the unit write enabled +or write locked. + + SET MT LOCKED set unit write locked + SET MT ENABLED 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 data channel implements these registers: + + name size comments + + FLG 1 channel ready + BPTR 16 buffer pointer (reads and writes) + BMAX 16 buffer size (writes) + DEVNO 6 current device number (read only) + +The device controller implements these registers: + + name size comments + + FNC 8 current function + STA 9 tape status + BUF 8 buffer + BUSY 3 busy (unit #, + 1, of active unit) + CTL 1 interrupt enabled + FLG 1 controller ready + FBF 1 controller ready buffer + DTF 1 data transfer flop + FSVC 1 first service flop + POS 31 magtape position + CTIME 24 command delay time + XTIME 24 interword transfer delay time + STOP_IOE 1 stop on I/O error + DEVNO 6 current device number (read only) + +Error handling is as follows: + + error processed as + + not attached tape not ready + + end of file (read or space) end of physical tape + (write) ignored + + OS I/O error report error and stop + +2.7 Symbolic Display and Input + +The HP2100 simulator implements symbolic display and input. Display is +controlled by command line switches: + + -a display as ASCII character + -c display as two character string + -m display instruction mnemonics + +Input parsing is controlled by the first character typed in or by command +line switches: + + ' or -a ASCII character + " or -c two character sixbit string + alphabetic instruction mnemonic + numeric octal number + +Instruction input uses standard HP2100 assembler syntax. There are seven +instruction classes: memory reference, I/O, shift, alter skip, extended +shift, extended memory reference, extended two address reference. + +Memory reference instructions have the format + + memref {C/Z} address{,I} + +where I signifies indirect, C a current page reference, and Z a zero page +reference. The address is an octal number in the range 0 - 077777; if C or +Z is specified, the address is a page offset in the range 0 - 01777. Normally, +C is not needed; the simulator figures out from the address what mode to use. +However, when referencing memory outside the CPU (eg, disks), there is no +valid PC, and C must be used to specify current page addressing. + +IOT instructions have the format + + io device{,C} + +where C signifies that the device flag is to be cleared. The device is an +octal number in the range 0 - 77. + +Shift and alter/skip instructions have the format + + sub-op sub-op sub-op... + +The simulator checks that the combination of sub-opcodes is legal. + +Extended shift instructions have the format + + extshift count + +where count is an octal number in the range 1 - 020. + +Extended memory reference instructions have the format + + extmemref address{,I} + +where I signifies indirect addressing. The address is an octal number in +the range 0 - 077777. + +Extended two address instructions have the format + + ext2addr addr1{,I},addr2{,I} + +where I signifies indirect addressing. Both address 1 and address 2 are +octal numbers in the range 0 - 077777. diff --git a/hp2100_dp.c b/HP2100/hp2100_dp.c similarity index 96% rename from hp2100_dp.c rename to HP2100/hp2100_dp.c index 577364df..59c926ca 100644 --- a/hp2100_dp.c +++ b/HP2100/hp2100_dp.c @@ -25,6 +25,8 @@ dp 12557A cartridge disk system + 03-Dec-01 RMS Changed DEVNO to use extended SET/SHOW + 24-Nov-01 RMS Changed STA to be an array 07-Sep-01 RMS Moved function prototypes 29-Nov-00 RMS Made variable names unique 21-Nov-00 RMS Fixed flag, buffer power up state @@ -182,10 +184,7 @@ REG dpc_reg[] = { { DRDATA (CTIME, dpc_ctime, 24), PV_LEFT }, { DRDATA (STIME, dpc_stime, 24), PV_LEFT }, { DRDATA (XTIME, dpc_xtime, 24), REG_NZ + PV_LEFT }, - { ORDATA (STA0, dpc_sta[0], 16) }, - { ORDATA (STA1, dpc_sta[1], 16) }, - { ORDATA (STA2, dpc_sta[2], 16) }, - { ORDATA (STA3, dpc_sta[3], 16) }, + { BRDATA (STA, dpc_sta, 8, 16, DP_NUMDRV) }, { GRDATA (UFLG0, dpc_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), REG_HRO }, { GRDATA (UFLG1, dpc_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), @@ -200,7 +199,8 @@ REG dpc_reg[] = { MTAB dpc_mod[] = { /* { UNIT_WLK, 0, "write enabled", "ENABLED", &dpc_vlock }, */ /* { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &dpc_vlock }, */ - { UNIT_DEVNO, inDPD, NULL, "DEVNO", &hp_setdev2 }, + { MTAB_XTD | MTAB_VDV, inDPD, "DEVNO", "DEVNO", + &hp_setdev2, &hp_showdev2, NULL }, { 0 } }; DEVICE dpc_dev = { diff --git a/hp2100_lp.c b/HP2100/hp2100_lp.c similarity index 94% rename from hp2100_lp.c rename to HP2100/hp2100_lp.c index beffe6bb..e50a2871 100644 --- a/hp2100_lp.c +++ b/HP2100/hp2100_lp.c @@ -25,6 +25,7 @@ lpt 12653A line printer + 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 @@ -68,7 +69,8 @@ REG lpt_reg[] = { { NULL } }; MTAB lpt_mod[] = { - { UNIT_DEVNO, inLPT, NULL, "DEVNO", &hp_setdev }, + { MTAB_XTD | MTAB_VDV, inLPT, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, NULL }, { 0 } }; DEVICE lpt_dev = { diff --git a/hp2100_mt.c b/HP2100/hp2100_mt.c similarity index 92% rename from hp2100_mt.c rename to HP2100/hp2100_mt.c index 2ed0775a..b4d32454 100644 --- a/hp2100_mt.c +++ b/HP2100/hp2100_mt.c @@ -25,6 +25,7 @@ mt 12559A nine track magnetic tape + 03-Dec-01 RMS Added read only unit, extended SET/SHOW support 07-Sep-01 RMS Moved function prototypes 30-Nov-00 RMS Made variable names unique 04-Oct-98 RMS V2.4 magtape format @@ -54,6 +55,7 @@ #define DB_V_SIZE 16 /* max data buf */ #define DBSIZE (1 << DB_V_SIZE) /* max data cmd */ #define DBMASK (DBSIZE - 1) +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ /* Command - mtc_fnc */ @@ -97,7 +99,7 @@ static const int32 mtc_cmd[] = { t_stat mtc_svc (UNIT *uptr); t_stat mtc_reset (DEVICE *dptr); -t_stat mtc_vlock (UNIT *uptr, int32 val); +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_stat mtd_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); @@ -136,7 +138,7 @@ DEVICE mtd_dev = { mtc_mod MTC modifier list */ -UNIT mtc_unit = { UDATA (&mtc_svc, UNIT_ATTABLE, 0) }; +UNIT mtc_unit = { UDATA (&mtc_svc, UNIT_ATTABLE + UNIT_ROABLE, 0) }; REG mtc_reg[] = { { ORDATA (FNC, mtc_fnc, 8) }, @@ -159,7 +161,8 @@ REG mtc_reg[] = { MTAB mtc_mod[] = { { UNIT_WLK, 0, "write enabled", "ENABLED", &mtc_vlock }, { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", &mtc_vlock }, - { UNIT_DEVNO, inMTD, NULL, "DEVNO", &hp_setdev2 }, + { MTAB_XTD | MTAB_VDV, inMTD, "DEVNO", "DEVNO", + &hp_setdev2, &hp_showdev2, NULL }, { 0 } }; DEVICE mtc_dev = { @@ -236,7 +239,7 @@ case ioOTX: /* output */ ((mtc_unit.flags & UNIT_ATT) == 0) || ((mtc_sta & STA_BOT) && ((dat == FNC_BSR) || (dat == FNC_REW) || (dat == FNC_RWS))) || - ((mtc_unit.flags & UNIT_WLK) && + ((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 */ @@ -254,7 +257,7 @@ case ioMIX: /* merge */ 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_WLK) mtc_sta = mtc_sta | STA_WLK; } + if (mtc_unit.flags & UNIT_WPRT) mtc_sta = mtc_sta | STA_WLK; } else mtc_sta = STA_BUSY | STA_LOCAL; dat = dat | mtc_sta; break; @@ -419,7 +422,7 @@ infotab[inMTC].flg = infotab[inMTD].flg = 0; /* clear flg */ infotab[inMTC].fbf = infotab[inMTD].fbf = 0; /* clear fbf */ sim_cancel (&mtc_unit); /* cancel activity */ if (mtc_unit.flags & UNIT_ATT) mtc_sta = ((mtc_unit.pos)? 0: STA_BOT) | - ((mtc_unit.flags & UNIT_WLK)? STA_WLK: 0); + ((mtc_unit.flags & UNIT_WPRT)? STA_WLK: 0); else mtc_sta = STA_LOCAL | STA_BUSY; return SCPE_OK; } @@ -432,7 +435,7 @@ 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_WLK)? STA_WLK: 0); +mtc_sta = STA_BOT | ((uptr -> flags & UNIT_WPRT)? STA_WLK: 0); return r; } @@ -446,9 +449,9 @@ return detach_unit (uptr); /* detach unit */ /* Write lock/enable routine */ -t_stat mtc_vlock (UNIT *uptr, int32 val) +t_stat mtc_vlock (UNIT *uptr, int32 val, char *cptr, void *desc) { -if (uptr -> flags & UNIT_ATT) return SCPE_ARG; +if (val && (uptr -> flags & UNIT_ATT)) return SCPE_ARG; return SCPE_OK; } diff --git a/hp2100_stddev.c b/HP2100/hp2100_stddev.c similarity index 92% rename from hp2100_stddev.c rename to HP2100/hp2100_stddev.c index 629ac797..ebeb8bfa 100644 --- a/hp2100_stddev.c +++ b/HP2100/hp2100_stddev.c @@ -28,6 +28,9 @@ tty 12531C buffered teleprinter interface clk 12539A/B/C time base generator + 03-Nov-01 RMS Changed DEVNO to use extended SET/SHOW + 29-Nov-01 RMS Added read only unit support + 24-Nov-01 RMS Changed TIME to an array 07-Sep-01 RMS Moved function prototypes 21-Nov-00 RMS Fixed flag, buffer power up state Added status input for ptp, tty @@ -82,7 +85,8 @@ t_stat clk_reset (DEVICE *dptr); */ UNIT ptr_unit = { - UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_IN_WAIT }; + UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), + SERIAL_IN_WAIT }; REG ptr_reg[] = { { ORDATA (BUF, ptr_unit.buf, 8) }, @@ -97,7 +101,8 @@ REG ptr_reg[] = { { NULL } }; MTAB ptr_mod[] = { - { UNIT_DEVNO, inPTR, NULL, "DEVNO", &hp_setdev }, + { MTAB_XTD | MTAB_VDV, inPTR, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, NULL }, { 0 } }; DEVICE ptr_dev = { @@ -130,7 +135,8 @@ REG ptp_reg[] = { { NULL } }; MTAB ptp_mod[] = { - { UNIT_DEVNO, inPTP, NULL, "DEVNO", &hp_setdev }, + { MTAB_XTD | MTAB_VDV, inPTP, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, NULL }, { 0 } }; DEVICE ptp_dev = { @@ -153,7 +159,7 @@ DEVICE ptp_dev = { UNIT tty_unit[] = { { UDATA (&tti_svc, UNIT_UC, 0), KBD_POLL_WAIT }, - { UDATA (&tto_svc, UNIT_UC, 0), SERIAL_OUT_WAIT }, + { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT }, { UDATA (&tto_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT } }; REG tty_reg[] = { @@ -176,7 +182,8 @@ REG tty_reg[] = { MTAB tty_mod[] = { { UNIT_UC, 0, "lower case", "LC", NULL }, { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, - { UNIT_DEVNO, inTTY, NULL, "DEVNO", &hp_setdev }, + { MTAB_XTD | MTAB_VDV, inTTY, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, NULL }, { 0 } }; DEVICE tty_dev = { @@ -203,19 +210,13 @@ REG clk_reg[] = { { FLDATA (FLG, infotab[inCLK].flg, 0) }, { FLDATA (FBF, infotab[inCLK].fbf, 0) }, { FLDATA (ERR, clk_error, CLK_V_ERROR) }, - { DRDATA (TIME0, clk_delay[0], 31), PV_LEFT }, - { DRDATA (TIME1, clk_delay[1], 31), PV_LEFT }, - { DRDATA (TIME2, clk_delay[2], 31), PV_LEFT }, - { DRDATA (TIME3, clk_delay[3], 31), PV_LEFT }, - { DRDATA (TIME4, clk_delay[4], 31), PV_LEFT }, - { DRDATA (TIME5, clk_delay[5], 31), PV_LEFT }, - { DRDATA (TIME6, clk_delay[6], 31), PV_LEFT }, - { DRDATA (TIME7, clk_delay[7], 31), PV_LEFT }, + { BRDATA (TIME, clk_delay, 8, 31, 8) }, { ORDATA (DEVNO, infotab[inCLK].devno, 6), REG_RO }, { NULL } }; MTAB clk_mod[] = { - { UNIT_DEVNO, inCLK, NULL, "DEVNO", &hp_setdev }, + { MTAB_XTD | MTAB_VDV, inCLK, "DEVNO", "DEVNO", + &hp_setdev, &hp_showdev, NULL }, { 0 } }; DEVICE clk_dev = { @@ -447,6 +448,8 @@ t_stat tto_out (int32 ch) t_stat ret = SCPE_OK; if (tty_mode & TM_PRI) { /* printing? */ + if ((tty_unit[TTI].flags & UNIT_UC) && islower (ch)) /* upper case? */ + ch = toupper (ch); ret = sim_putchar (ch & 0177); /* output char */ tty_unit[TTO].pos = tty_unit[TTO].pos + 1; } if (tty_mode & TM_PUN) { /* punching? */ diff --git a/hp2100_sys.c b/HP2100/hp2100_sys.c similarity index 100% rename from hp2100_sys.c rename to HP2100/hp2100_sys.c diff --git a/i1401_cd.c b/I1401/i1401_cd.c similarity index 95% rename from i1401_cd.c rename to I1401/i1401_cd.c index 3b5f7aaa..2f9fa7b7 100644 --- a/i1401_cd.c +++ b/I1401/i1401_cd.c @@ -35,6 +35,7 @@ Cards are represented as ASCII text streams terminated by newlines. This allows cards to be created and edited as normal files. + 29-Nov-01 RMS Added read only unit support 13-Apr-01 RMS Revised for register arrays */ @@ -60,7 +61,7 @@ t_stat cd_reset (DEVICE *dptr); */ UNIT cdr_unit = { - UDATA (&cdr_svc, UNIT_SEQ+UNIT_ATTABLE, 0), 100 }; + UDATA (&cdr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), 100 }; REG cdr_reg[] = { { FLDATA (LAST, ind[IN_LST], 0) }, diff --git a/i1401_cpu.c b/I1401/i1401_cpu.c similarity index 94% rename from i1401_cpu.c rename to I1401/i1401_cpu.c index 0522cf5b..67790d4c 100644 --- a/i1401_cpu.c +++ b/I1401/i1401_cpu.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. + 30-Nov-01 RMS Added extended SET/SHOW support 10-Aug-01 RMS Removed register in declarations 07-Dec-00 RMS Fixed bugs found by Charles Owen -- 4,7 char NOPs are legal @@ -105,8 +106,6 @@ #include "i1401_defs.h" -#define ILL_ADR_FLAG 100000 /* invalid addr flag */ -#define save_ibkpt (cpu_unit.u3) /* saved bkpt addr */ #define MM(x) x = x - 1; \ if (x < 0) { \ x = BA + MAXMEMSIZE - 1; \ @@ -135,14 +134,13 @@ int32 ind[64] = { 0 }; /* indicators */ int32 ssa = 1; /* sense switch A */ int32 prchk = 0; /* process check stop */ int32 iochk = 0; /* I/O check stop */ -int32 ibkpt_addr = ILL_ADR_FLAG + MAXMEMSIZE; /* breakpoint addr */ extern int32 sim_int_char; +extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ 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_svc (UNIT *uptr); -t_stat cpu_set_size (UNIT *uptr, int32 value); +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); int32 store_addr_h (int32 addr); int32 store_addr_t (int32 addr); int32 store_addr_u (int32 addr); @@ -167,7 +165,7 @@ extern t_stat sim_activate (UNIT *uptr, int32 delay); cpu_mod CPU modifier list */ -UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BCD + STDOPT, +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BCD + STDOPT, MAXMEMSIZE) }; REG cpu_reg[] = { @@ -191,7 +189,6 @@ REG cpu_reg[] = { { FLDATA (IOCHK, iochk, 0) }, { FLDATA (PRCHK, prchk, 0) }, { DRDATA (OLDIS, oldIS, 14), REG_RO + PV_LEFT }, - { DRDATA (BREAK, ibkpt_addr, 17), PV_LEFT }, { ORDATA (WRU, sim_int_char, 8) }, { NULL } }; @@ -420,10 +417,7 @@ saved_IS = IS; /* commit prev instr */ if (sim_interval <= 0) { /* check clock queue */ if (reason = sim_process_event ()) break; } -if (IS == ibkpt_addr) { /* breakpoint? */ - save_ibkpt = ibkpt_addr; /* save ibkpt */ - ibkpt_addr = ibkpt_addr + ILL_ADR_FLAG; /* disable */ - sim_activate (&cpu_unit, 1); /* sched re-enable */ +if (sim_brk_summ && sim_brk_test (IS, SWMASK ('E'))) { /* breakpoint? */ reason = STOP_IBKPT; /* stop simulation */ break; } @@ -1061,15 +1055,7 @@ for (i = 0; i < 64; i++) ind[i] = 0; ind[IN_UNC] = 1; AS = 0; as_err = 1; BS = 0; bs_err = 1; -return cpu_svc (&cpu_unit); -} - -/* Breakpoint service */ - -t_stat cpu_svc (UNIT *uptr) -{ -if ((ibkpt_addr - ILL_ADR_FLAG) == save_ibkpt) ibkpt_addr = save_ibkpt; -save_ibkpt = -1; +sim_brk_types = sim_brk_dflt = SWMASK ('E'); return SCPE_OK; } @@ -1093,17 +1079,17 @@ return SCPE_OK; /* Memory size change */ -t_stat cpu_set_size (UNIT *uptr, int32 value) +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { int32 mc = 0; t_addr i; -if ((value <= 0) || (value > MAXMEMSIZE) || ((value % 1000) != 0)) +if ((val <= 0) || (val > MAXMEMSIZE) || ((val % 1000) != 0)) return SCPE_ARG; -for (i = value; i < MEMSIZE; i++) mc = mc | M[i]; +for (i = val; i < MEMSIZE; i++) mc = mc | M[i]; if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) return SCPE_OK; -MEMSIZE = value; +MEMSIZE = val; for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; if (MEMSIZE > 4000) cpu_unit.flags = cpu_unit.flags | MA; else cpu_unit.flags = cpu_unit.flags & ~MA; diff --git a/i1401_defs.h b/I1401/i1401_defs.h similarity index 100% rename from i1401_defs.h rename to I1401/i1401_defs.h diff --git a/I1401/i1401_doc.txt b/I1401/i1401_doc.txt new file mode 100644 index 00000000..be770b95 --- /dev/null +++ b/I1401/i1401_doc.txt @@ -0,0 +1,428 @@ +To: Users +From: Bob Supnik +Subj: IBM 1401 Simulator Usage +Date: 1-Dec-01 + + COPYRIGHT NOTICE + +The following copyright notice applies to both the SIMH source and binary: + + Original code published in 1993-2001, written by Robert M Supnik + 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. + +This memorandum documents the IBM 1401 simulator. + + +1. Simulator Files + +sim/ sim_defs.h + scp.c + scp_tty.c + sim_rev.c + +sim/i1401/ i1401_defs.h + i1401_cpu.c + i1401_iq.c + i1401_lp.c + i1401_mt.c + i1401_sys.c + +2. IBM 1401 Features + +The IBM 1401 simulator is configured as follows: + +device simulates +name(s) + +CPU IBM 1401 CPU with 16K of memory +CDR,CDP IBM 1402 card reader/punch +LPT IBM 1403 line printer +INQ IBM 1407 inquiry terminal +MT IBM 729 7-track magnetic tape controller with six drives + +The IBM 1401 simulator implements many unique stop conditions. On almost +any kind of error the simulator stops: + + unimplemented opcode + reference to non-existent memory + reference to non-existent device + no word mark under opcode + invalid A address + invalid B address + invalid instruction length + invalid modifier character + invalid branch address + invalid magtape unit number + invalid magtape record length + write to locked magtape drive + skip to unpunched carriage control tape channel + card reader hopper empty + address register wrap-around + single character A field in MCE + single character B field in MCE + hanging $ in MCE with EPE enabled + I/O check with I/O stop switch set + +The LOAD and DUMP commands are not implemented. + +2.1 CPU + +The CPU options include a number of special features and the size of main +memory. Note that the Modify Address special feature is always included +when memory size is greater than 4K. + + SET CPU XSA enable advanced programming special feature + SET CPU NOXSA disable advanced programming + SET CPU HLE enable high/low/equal special feature + SET CPU NOHLE disable high/low/equal + SET CPU BBE enable branch on bit equal special feature + SET CPU NOBBE disable branch on bit equal + SET CPU MR enable move record special feature + SET CPU NOMR disable move record + SET CPU EPE enable extended print edit special feature + SET CPU NOEPE disable extended print edit + SET CPU 4K set memory size = 4K + SET CPU 8K set memory size = 8K + SET CPU 12K set memory size = 12K + SET CPU 16K set memory size = 16K + +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 7 bit BCD characters, as follows: + + 6 5 4 3 2 1 0 + + word B bit A bit 8 4 2 1 + mark <-- zone --> <-------- digit --------> + +In BCD, the decimal digits 0-9 are (octal) values 012, 001, 002, 003, 004, +005, 006, 007, 010, 011, respectively. Signs are encoded in the zone bits, +with 00, 01, and 11 being positive, and 10 being negative. + +CPU registers include the visible state of the processor. The 1401 has no +interrupt system. + + name size comments + + IS 14 instruction storage address register (PC) + AS 14 A storage address register + BS 14 B storage address register + ASERR 1 AS invalid flag + BSERR 1 BS invalid flag + SSA 1 sense switch A + SSB 1 sense switch B + SSC 1 sense switch C + SSD 1 sense switch D + SSE 1 sense switch E + SSF 1 sense switch F + SSG 1 sense switch G + EQU 1 equal compare indicator + UNEQ 1 unequal compare indicator + HIGH 1 high compare indicator + LOW 1 low compare indicator + OVF 1 overflow indicator + IOCHK 1 I/O check switch + PRCHK 1 process check switch + OLDIS 1 IS prior to last branch + WRU 8 interrupt character + +2.2 1402 Card Reader/Punch (CDR, CDP, STKR) + +The IBM 1402 card/reader punch is simulated as three independent devices: +the card reader (CDR), the card punch (CDP), and the reader and punch +stackers (STKR). STRK units 0, 1, 2, and 4 correspond to the reader +normal stacker, reader stacker 1, shared stacker 2/8, and punch stacker +4, respectively. + +The card reader supports the BOOT command. BOOT CDR reads a card image +into locations 1-80, sets a word mark under location 1, clears storage, +and then transfers control to location 1. + +The card reader reads data from disk files, while the punch and stackers +write data to disk files. Cards are simulated as ASCII text lines with +terminating newlines; column binary is not supported. 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 reader/punch registers are: + + device name size comments + + CDR LAST 1 last card indicator + ERR 1 error indicator + S1 1 stacker 1 select flag + S2 1 stacker 2 select flag + POS 31 position + TIME 24 delay window for stacker select + BUF[0:79] 8 reader buffer + + CDP ERR 1 error indicator + S4 1 stacker 4 select flag + S8 1 stacker 8 select flag + + STKR POS0 31 position, normal reader stack + POS1 31 position, reader stacker 1 + POS2 31 position, shared stacker 2/8 + POS4 31 position, punch stacker 4 + +Error handling is as follows: + + device error processed as + + reader end of file if SSA set, set LAST indicator + on next Read, report error and stop + + reader,punch not attached report error and stop + OS I/O error print error message + if IOCHK set, report error and stop + otherwise, set ERR indicator + + stacker not attached ignored + OS I/O error print error message + if IOCHK set, report error and stop + +2.3 1403 Line Printer (LPT) + +The IBM 1403 line printer (LPT) writes its data, converted to ASCII, to +a disk file. The line printer supports three different print character +sets or "chains": + + SET LPT PCF full 64 character chain + SET LPT PCA 48 character business chain + SET LPT PCH 48 character FORTRAN chain + +In addition, 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 + + LINES 8 number of newlines after next print + LFLAG 1 carriage control flag (1 = skip, 0 = space) + CCTP 8 carriage control tape pointer + CCTL 8 carriage control tape length (read only) + ERR 1 error indicator + POS 31 position + CCT[0:131] 32 carriage control tape array + +Error handling is as follows: + + error processed as + + not attached report error and stop + + OS I/O error print error message + if IOCHK set, report error and stop + otherwise, set ERR indicator + +2.4 1407 Inquiry Terminal (INQ) + +The IBM 1407 inquiry terminal (INQ) is a half-duplex console. It polls +the console keyboard periodically for inquiry requests. The inquiry +terminal registers are: + + name size comments + + INQC 7 inquiry request character (initially ESC) + INR 1 inquiry request indicator + INC 1 inquiry cleared indicator + TIME 24 polling interval + +When the 1401 CPU requests input from the keyboard, the message [Enter] +is printed out, followed by a new line. The CPU hangs waiting for input +until either the return/enter key is pressed, or the inquiry request +character is typed in. The latter cancels the type-in and sets INC. + +The inquiry terminal has no errors. + +2.5 729 Magnetic Tape (MT) + +The magnetic tape controller supports six drives, numbered 1 through 6. +Magnetic tape options include the ability to make units write enabled or +or write locked. + + SET MTn LOCKED set unit n write locked + SET MTn ENABLED set unit n write enabled + +Units can also be REMOVEd or ADDed to the configuration. The magnetic +tape simulator supports the BOOT command. BOOT MT reads the first +record off tape, starting at location 1, and then branches to it. + +The magnetic tape controller implements these registers: + + name size comments + + END 1 end of file indicator + ERR 1 error indicator + PAR 1 parity error indicator + POS1..6 31 position, drives 1..6 + +Error handling is as follows: + + error processed as + + not attached report error and stop + + end of file (read or space) end of physical tape + (write) ignored + + OS I/O error print error message + if IOCHK set, report error and stop + otherwise, set ERR indicator + +2.6 Symbolic Display and Input + +The IBM 1401 simulator implements symbolic display and input. Display is +controlled by command line switches: + + -c display as single character + (BCD for CPU and MT, ASCII for others) + -s display as wordmark terminated BCD string + (CPU only) + -m display instruction mnemonics + (CPU only) + +In a CPU character display, word marks are denoted by ~. + +Input parsing is controlled by the first character typed in or by command +line switches: + + ' or " or -c or -s characters (BCD for CPU and MT, ASCII + for others) + alphabetic instruction mnemonic + numeric octal number + +Instruction input is free format, with spaces separating fields. There +are six instruction formats: 1, 2, 4, 5, 7, and 8 characters: + + 1 character opcode + 2 character opcode 'modifier + 4 character opcode address + 5 character opcode address 'modifier + 7 character opcode address address + 8 character opcode address address 'modifier + +Addresses are always decimal, except for special I/O addresses in the A +field, which may be specified as %xy, where x denotes the device and y +the unit number. + +For the CPU, string input may encompass multiple characters. A word mark +is denoted by ~ and must precede the character to be marked. All other +devices can only accept single character input, without word marks. + +2.7 Character Sets + +The IBM 1401 used a 6b character code called BCD (binary coded decimal). +Some of the characters have no equivalent in ASCII and require different +representations: + +BCD ASCII IBM 1401 print +code representation character chains + +00 space +01 1 +02 2 +03 3 +04 4 +05 5 +06 6 +07 7 +10 8 +11 9 +12 0 +13 # = in H chain +14 @ ' in H chain +15 : blank in A, H chains +16 > blank in A, H chains +17 ( tape mark blank in A, H chains +20 ^ alternate blank blank in A, H chains +21 / +22 S +23 T +24 U +25 V +26 W +27 X +30 Y +31 Z +32 ' record mark +33 , +34 % ( in H chain +35 = word mark blank in A, H chains +36 \ blank in A, H chains +37 + blank in A, H chains +40 - +41 J +42 K +43 L +44 M +45 N +46 O +47 P +50 Q +51 R +52 ! +53 $ +54 * +55 ] blank in A, H chains +56 ; blank in A, H chains +57 _ delta blank in A, H chains +60 & +61 A +62 B +63 C +64 D +65 E +66 F +67 G +70 H +71 I +72 ? +73 . +74 ) lozenge +75 [ blank in A, H chains +76 < blank in A, H chains +77 " group mark blank in A, H chains diff --git a/i1401_iq.c b/I1401/i1401_iq.c similarity index 96% rename from i1401_iq.c rename to I1401/i1401_iq.c index 105f4e76..3ee61262 100644 --- a/i1401_iq.c +++ b/I1401/i1401_iq.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. + inq 1407 inquiry terminal + 07-Sep-01 RMS Moved function prototypes 14-Apr-99 RMS Changed t_addr to unsigned */ diff --git a/i1401_lp.c b/I1401/i1401_lp.c similarity index 96% rename from i1401_lp.c rename to I1401/i1401_lp.c index b1ea1a06..16bfbc66 100644 --- a/i1401_lp.c +++ b/I1401/i1401_lp.c @@ -23,7 +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. - lpt 1403 line printer + lpt 1403 line printer 13-Apr-01 RMS Revised for register arrays */ diff --git a/i1401_mt.c b/I1401/i1401_mt.c similarity index 88% rename from i1401_mt.c rename to I1401/i1401_mt.c index 586ff436..adf9fa8e 100644 --- a/i1401_mt.c +++ b/I1401/i1401_mt.c @@ -1,4 +1,4 @@ -/* IBM 1401 magnetic tape simulator +/* i1401_mt.c: IBM 1401 magnetic tape simulator Copyright (c) 1993-2001, Robert M. Supnik @@ -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. + mt 7-track magtape + + 29-Nov-01 RMS Added read only unit support 18-Apr-01 RMS Changed to rewind tape before boot 07-Dec-00 RMS Widened display width from 6 to 8 bits to see record lnt CEO Added tape bootstrap @@ -50,6 +53,7 @@ #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ #define UNIT_WLK (1 << UNIT_V_WLK) #define UNIT_W_UF 2 /* #save flags */ +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ extern uint8 M[]; /* memory */ extern int32 ind[64]; @@ -70,12 +74,18 @@ UNIT *get_unit (int32 unit); UNIT mt_unit[] = { { UDATA (NULL, UNIT_DIS, 0) }, /* doesn't exist */ - { UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE + UNIT_BCD, 0) }, - { UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE + UNIT_BCD, 0) }, - { UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE + UNIT_BCD, 0) }, - { UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE + UNIT_BCD, 0) }, - { UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE + UNIT_BCD, 0) }, - { UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE + UNIT_BCD, 0) } }; + { UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE + + UNIT_ROABLE + UNIT_BCD, 0) }, + { UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE + + UNIT_ROABLE + UNIT_BCD, 0) }, + { UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE + + UNIT_ROABLE + UNIT_BCD, 0) }, + { UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE + + UNIT_ROABLE + UNIT_BCD, 0) }, + { UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE + + UNIT_ROABLE + UNIT_BCD, 0) }, + { UDATA (NULL, UNIT_DISABLE + UNIT_ATTABLE + + UNIT_ROABLE + UNIT_BCD, 0) } }; REG mt_reg[] = { { FLDATA (END, ind[IN_END], 0) }, @@ -145,10 +155,10 @@ case BCD_B: /* backspace */ (2 * sizeof (t_mtrlnt)); break; /* end case */ case BCD_E: /* erase = nop */ - if (uptr -> flags & UNIT_WLK) return STOP_MTL; + if (uptr -> flags & UNIT_WPRT) return STOP_MTL; return SCPE_OK; case BCD_M: /* write tapemark */ - if (uptr -> flags & UNIT_WLK) return STOP_MTL; + 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); @@ -223,7 +233,7 @@ case BCD_R: /* read */ break; case BCD_W: - if (uptr -> flags & UNIT_WLK) 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); ) { diff --git a/i1401_sys.c b/I1401/i1401_sys.c similarity index 100% rename from i1401_sys.c rename to I1401/i1401_sys.c diff --git a/eclipse.txt b/NOVA/eclipse.txt similarity index 78% rename from eclipse.txt rename to NOVA/eclipse.txt index c00d270a..4cc9cf08 100644 --- a/eclipse.txt +++ b/NOVA/eclipse.txt @@ -2,9 +2,9 @@ Charles Owen's Eclipse Modules 1. Eclipse CPU simulator -The Eclipse CPU simulator can be used with the V2.5a Nova definitions and peripheral -modules to produce an Eclipse simulator that will run Eclipse mapped RDOS V7.5. The -compilation procedure is the same as for the Nova simulator, except: +The Eclipse CPU simulator can be used with the Nova definitions and peripheral +modules to produce an Eclipse simulator that will run Eclipse mapped RDOS V7.5. +The compilation procedure is the same as for the Nova simulator, except: - the symbol ECLIPSE must be defined - the module eclipse_cpu.c must be substituted for nova_cpu.c diff --git a/eclipse_cpu.c b/NOVA/eclipse_cpu.c similarity index 96% rename from eclipse_cpu.c rename to NOVA/eclipse_cpu.c index c176b554..25ff4f68 100644 --- a/eclipse_cpu.c +++ b/NOVA/eclipse_cpu.c @@ -28,6 +28,7 @@ cpu Eclipse central processor + 30-Nov-01 RMS Added extended SET/SHOW support 01-Jun-01 RMS Added second terminal, plotter support 26-Apr-01 RMS Added device enable/disable support @@ -313,8 +314,6 @@ #include "nova_defs.h" -#define ILL_ADR_FLAG 0100000 -#define save_ibkpt (cpu_unit.u3) #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 */ @@ -336,7 +335,6 @@ int32 pimask = 0; /* priority int mask */ int32 pwr_low = 0; /* power fail flag */ int32 ind_max = 15; /* iadr nest limit */ int32 stop_dev = 0; /* stop on ill dev */ -int32 ibkpt_addr = ILL_ADR_FLAG | AMASK; /* ibreakpoint addr */ int32 old_PC = 0; /* previous PC */ int32 model = 130; /* Model of Eclipse */ int32 speed = 0; /* Delay for each instruction */ @@ -417,15 +415,15 @@ int32 Tron = 0; /* For trace files */ FILE *Trace; t_stat reason; - extern int32 sim_int_char; +extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ + 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_svc (UNIT *uptr); t_stat cpu_boot (int32 unitno); -t_stat cpu_set_size (UNIT *uptr, int32 value); -t_stat Debug_Dump (UNIT *uptr, int32 value); +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); t_stat map_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); t_stat map_reset (DEVICE *dptr); @@ -494,7 +492,7 @@ struct ndev dev_table[64] = { cpu_mod CPU modifiers list */ -UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK, +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) }; REG cpu_reg[] = { @@ -517,7 +515,6 @@ REG cpu_reg[] = { { FLDATA (MICRO, cpu_unit.flags, UNIT_V_MICRO), REG_HRO }, { DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT }, { ORDATA (DEBUG, Debug_Flags, 16) }, - { ORDATA (BREAK, ibkpt_addr, 16) }, { DRDATA (MODEL, model, 16) }, { DRDATA (SPEED, speed, 16) }, { ORDATA (WRU, sim_int_char, 8) }, @@ -714,10 +711,7 @@ if (Inhibit != 0) { /* Handle 1-instruction inhibit sequence */ Inhibit = 0; } -if (PC == ibkpt_addr) { /* breakpoint? */ - save_ibkpt = ibkpt_addr; /* save address */ - ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */ - sim_activate (&cpu_unit, 1); /* sched re-enable */ +if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ reason = STOP_IBKPT; /* stop simulation */ break; } @@ -3223,7 +3217,8 @@ int_req = int_req & ~INT_ION; pimask = 0; dev_disable = 0; pwr_low = 0; -return cpu_svc (&cpu_unit); +sim_brk_types = sim_brk_dflt = SWMASK ('E'); +return SCPE_OK; } /* Memory examine */ @@ -3244,26 +3239,17 @@ M[addr] = val & 0177777; return SCPE_OK; } -/* Breakpoint service */ - -t_stat cpu_svc (UNIT *uptr) -{ -if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt) ibkpt_addr = save_ibkpt; -save_ibkpt = -1; -return SCPE_OK; -} - -t_stat cpu_set_size (UNIT *uptr, int32 value) +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { int32 mc = 0; t_addr i; -if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 07777) != 0)) +if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0)) return SCPE_ARG; -for (i = value; i < MEMSIZE; i++) mc = mc | M[i]; +for (i = val; i < MEMSIZE; i++) mc = mc | M[i]; if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) return SCPE_OK; -MEMSIZE = value; +MEMSIZE = val; for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; return SCPE_OK; } @@ -3366,7 +3352,7 @@ int32 Debug_Entry(int32 PC, int32 inst, int32 inst2, int32 AC0, int32 AC1, int32 return 0; } -int32 Debug_Dump(UNIT *uptr, int32 value) +int32 Debug_Dump(UNIT *uptr, int32 val, char *cptr, void *desc) { char debmap[4], debion[4]; t_value simeval[20]; diff --git a/eclipse_tt.c b/NOVA/eclipse_tt.c similarity index 100% rename from eclipse_tt.c rename to NOVA/eclipse_tt.c diff --git a/nova_clk.c b/NOVA/nova_clk.c similarity index 100% rename from nova_clk.c rename to NOVA/nova_clk.c diff --git a/nova_cpu.c b/NOVA/nova_cpu.c similarity index 94% rename from nova_cpu.c rename to NOVA/nova_cpu.c index 76154d01..44973c9c 100644 --- a/nova_cpu.c +++ b/NOVA/nova_cpu.c @@ -25,6 +25,8 @@ cpu Nova central processor + 07-Dec-01 RMS Revised to use breakpoint package + 30-Nov-01 RMS Added extended SET/SHOW support 10-Aug-01 RMS Removed register in declarations 17-Jul-01 RMS Moved function prototype 26-Apr-01 RMS Added device enable/disable support @@ -211,8 +213,6 @@ M[x] = (M[x] - 1) & 0177777; \ x = M[x] & AMASK -#define ILL_ADR_FLAG A_IND -#define save_ibkpt (cpu_unit.u3) #define UNIT_V_MDV (UNIT_V_UF) /* MDV present */ #define UNIT_MDV (1 << UNIT_V_MDV) #define UNIT_V_STK (UNIT_V_UF+1) /* stack instr */ @@ -241,15 +241,14 @@ int32 pimask = 0; /* priority int mask */ int32 pwr_low = 0; /* power fail flag */ int32 ind_max = 16; /* iadr nest limit */ int32 stop_dev = 0; /* stop on ill dev */ -int32 ibkpt_addr = ILL_ADR_FLAG | AMASK; /* ibreakpoint addr */ int32 old_PC = 0; /* previous PC */ - extern int32 sim_int_char; +extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ + 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_svc (UNIT *uptr); -t_stat cpu_set_size (UNIT *uptr, int32 value); +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); @@ -310,7 +309,7 @@ struct ndev dev_table[64] = { cpu_mod CPU modifiers list */ -UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK + UNIT_MDV, +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK + UNIT_MDV, MAXMEMSIZE) }; REG cpu_reg[] = { @@ -338,7 +337,6 @@ REG cpu_reg[] = { { FLDATA (IBYT, cpu_unit.flags, UNIT_V_BYT), REG_HRO }, { DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT }, { ORDATA (OLDPC, old_PC, 15), REG_RO }, - { ORDATA (BREAK, ibkpt_addr, 16) }, { ORDATA (WRU, sim_int_char, 8) }, { ORDATA (IOTENB, iot_enb, 32), REG_HRO }, { NULL } }; @@ -401,10 +399,7 @@ if (int_req > INT_PENDING) { /* interrupt? */ break; } PC = MA; } /* end interrupt */ -if (PC == ibkpt_addr) { /* breakpoint? */ - save_ibkpt = ibkpt_addr; /* save address */ - ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */ - sim_activate (&cpu_unit, 1); /* sched re-enable */ +if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ reason = STOP_IBKPT; /* stop simulation */ break; } @@ -828,7 +823,8 @@ int_req = int_req & ~(INT_ION | INT_STK); pimask = 0; dev_disable = 0; pwr_low = 0; -return cpu_svc (&cpu_unit); +sim_brk_types = sim_brk_dflt = SWMASK ('E'); +return SCPE_OK; } /* Memory examine */ @@ -849,26 +845,17 @@ M[addr] = val & DMASK; return SCPE_OK; } -/* Breakpoint service */ - -t_stat cpu_svc (UNIT *uptr) -{ -if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt) ibkpt_addr = save_ibkpt; -save_ibkpt = -1; -return SCPE_OK; -} - -t_stat cpu_set_size (UNIT *uptr, int32 value) +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { int32 mc = 0; t_addr i; -if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 07777) != 0)) +if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0)) return SCPE_ARG; -for (i = value; i < MEMSIZE; i++) mc = mc | M[i]; +for (i = val; i < MEMSIZE; i++) mc = mc | M[i]; if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) return SCPE_OK; -MEMSIZE = value; +MEMSIZE = val; for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; return SCPE_OK; } diff --git a/nova_defs.h b/NOVA/nova_defs.h similarity index 100% rename from nova_defs.h rename to NOVA/nova_defs.h diff --git a/nova_dkp.c b/NOVA/nova_dkp.c similarity index 93% rename from nova_dkp.c rename to NOVA/nova_dkp.c index 070bd0a4..ec21fec5 100644 --- a/nova_dkp.c +++ b/NOVA/nova_dkp.c @@ -25,6 +25,8 @@ dkp moving head disk + 30-Nov-01 RMS Added read only unit, extended SET/SHOW support + 24-Nov-01 RMS Changed FLG, CAPAC to arrays 26-Apr-01 RMS Added device enable/disable support 12-Dec-00 RMS Added Eclipse support from Charles Owen 15-Oct-00 RMS Editorial changes @@ -51,6 +53,7 @@ #define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE) #define FUNC u3 /* function */ #define CYL u4 /* on cylinder */ +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ /* Unit, surface, sector, count register @@ -282,7 +285,7 @@ t_stat dkp_reset (DEVICE *dptr); t_stat dkp_boot (int32 unitno); t_stat dkp_attach (UNIT *uptr, char *cptr); t_stat dkp_go (void); -t_stat dkp_set_size (UNIT *uptr, int32 value); +t_stat dkp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); #if defined (ECLIPSE) extern int32 MapAddr (int32 map, int32 addr); #else @@ -299,13 +302,13 @@ extern int32 MapAddr (int32 map, int32 addr); UNIT dkp_unit[] = { { UDATA (&dkp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - (TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) }, + UNIT_ROABLE+(TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) }, { UDATA (&dkp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - (TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) }, + UNIT_ROABLE+(TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) }, { UDATA (&dkp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - (TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) }, + UNIT_ROABLE+(TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) }, { UDATA (&dkp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - (TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) } }; + UNIT_ROABLE+(TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) } }; REG dkp_reg[] = { { ORDATA (FCCY, dkp_fccy, 16) }, @@ -318,18 +321,10 @@ REG dkp_reg[] = { { FLDATA (DISABLE, dev_disable, INT_V_DKP) }, { DRDATA (STIME, dkp_swait, 24), PV_LEFT }, { DRDATA (RTIME, dkp_rwait, 24), PV_LEFT }, - { GRDATA (FLG0, dkp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG1, dkp_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG2, dkp_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG3, dkp_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { DRDATA (CAPAC0, dkp_unit[0].capac, 32), PV_LEFT + REG_HRO }, - { DRDATA (CAPAC1, dkp_unit[1].capac, 32), PV_LEFT + REG_HRO }, - { DRDATA (CAPAC2, dkp_unit[2].capac, 32), PV_LEFT + REG_HRO }, - { DRDATA (CAPAC3, dkp_unit[3].capac, 32), PV_LEFT + REG_HRO }, + { 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 } }; @@ -572,7 +567,7 @@ if (uptr -> FUNC == FCCY_SEEK) { /* seek? */ return SCPE_OK; } if (((uptr -> flags & UNIT_ATT) == 0) || /* not attached? */ - ((uptr -> flags & UNIT_WLK) && (uptr -> FUNC == FCCY_WRITE))) + ((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 */ @@ -673,10 +668,10 @@ return SCPE_OK; /* Set size command validation routine */ -t_stat dkp_set_size (UNIT *uptr, int32 value) +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 (value)].size; +uptr -> capac = drv_tab[GET_DTYPE (val)].size; return SCPE_OK; } diff --git a/NOVA/nova_doc.txt b/NOVA/nova_doc.txt new file mode 100644 index 00000000..27eb5912 --- /dev/null +++ b/NOVA/nova_doc.txt @@ -0,0 +1,565 @@ +To: Users +From: Bob Supnik +Subj: Nova Simulator Usage +Date: 1-Dec-01 + + COPYRIGHT NOTICE + +The following copyright notice applies to both the SIMH source and binary: + + Original code published in 1993-2001, written by Robert M Supnik + 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. + +This memorandum documents the Nova simulator. + + +1. Simulator Files + +sim/ sim_defs.h + sim_sock.h + sim_tmxr.h + scp.c + scp_tty.c + sim_rev.c + sim_sock.c + sim_tmxr.c + +sim/nova/ nova_defs.h + nova_cpu.c + nova_clk.c + nova_dkp.c + nova_dsk.c + nova_lp.c + nova_mta.c + nova_plt.c + nova_sys.c + nova_tt.c + nova_tt1.c + +2. Nova Features + +The Nova simulator is configured as follows: + +device simulates +name(s) + +CPU Nova CPU with 32KW of memory +- hardware multiply/divide +PTR,PTP paper tape reader/punch +TTI,TTO console terminal +TTI1,TTO1 second terminal +LPT line printer +PLT plotter +CLK real-time clock +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 DISABLEd. + +The Nova simulator implements these unique stop conditions: + + - reference to undefined I/O device, and STOP_DEV is set + - more than INDMAX indirect addresses are detected during + an interrupt + - more than INDMAX indirect addresses are detected during + memory reference address decoding + +The Nova loader supports standard binary format tapes. The DUMP command +is not implemented. + +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 NONE disable all optional instructions + SET CPU 4K set memory size = 4K + SET CPU 8K set memory size = 8K + SET CPU 12K set memory size = 12K + SET CPU 16K set memory size = 16K + SET CPU 20K set memory size = 20K + SET CPU 24K set memory size = 24K + SET CPU 28K set memory size = 28K + SET CPU 32K set memory size = 32K + +(MDV = unsigned multiply/divide instructions) +(Nova 3 = unsigned multiply/divide, stack, trap instructions) +(Nova 4 = unsigned and signed multiply/divide, stack, byte, trap instructions) + +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. + +CPU registers include the visible state of the processor as well as the +control registers for the interrupt system. + + name size comments + + PC 15 program counter + AC0..AC3 16 accumulators 0..3 + C 1 carry + SR 16 front panel switches + PI 16 priority interrupt mask + ION 1 interrupt enable + ION_DELAY 1 interrupt enable delay for ION + PWR 1 power fail interrupt + INT 15 interrupt pending flags + BUSY 15 device busy flags + DONE 15 device done flags + DISABLE 15 device interrupt disable flags + STOP_DEV 1 stop on undefined IOT + INDMAX 15 maximum number of nested indirects + OLDPC 15 PC prior to last JMP, JMS, or interrupt + WRU 8 interrupt character + +2.2 Programmed I/O Devices + +2.2.1 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 implements these registers: + + name size comments + + BUF 8 last data item processed + BUSY 1 device busy flag + DONE 1 device done flag + DISABLE 1 interrupt disable flag + INT 1 interrupt pending flag + POS 31 position in the input file + TIME 24 time from I/O initiation to interrupt + 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 out of tape or paper + + end of file 1 report error and stop + 0 out of tape or paper + + OS I/O error x report error and stop + +2.2.2 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. +Thus, by changing POS, the user can backspace or advance the punch. + +The paper tape punch implements these registers: + + name size comments + + BUF 8 last data item processed + BUSY 1 device busy flag + DONE 1 device done flag + DISABLE 1 interrupt disable flag + INT 1 interrupt pending flag + POS 31 position in the output file + TIME 24 time from I/O initiation to interrupt + 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 out of tape or paper + + OS I/O error x report error and stop + +2.2.3 Terminal Input (TTI) + +The terminal input polls the console keyboard for input. Terminal +input options include the ability to set ANSI mode or limited Dasher +compatibility mode: + + SET TTI ANSI normal mode + SET TTI DASHER Dasher mode + +Setting either TTI or TTO changes both devices. In Dasher mode, carriage +return is changed to newline on input, and ^X is changed to backspace. + +The terminal input implements these registers: + + name size comments + + BUF 8 last data item processed + BUSY 1 device busy flag + DONE 1 device done flag + DISABLE 1 interrupt disable flag + INT 1 interrupt pending flag + POS 31 number of characters input + TIME 24 keyboard polling interval + +2.2.4 Terminal Output (TTO) + +The terminal output writes to the simulator console window. Terminal +output options include the the ability to set ANSI mode or limited +Dasher compatibility mode: + + SET TTO ANSI normal mode + SET TTO DASHER Dasher mode + +Setting either TTI or TTO changes both devices. In Dasher mode, carriage +return is changed to newline on input, and ^X is changed to backspace. + +The terminal output implements these registers: + + name size comments + + BUF 8 last data item processed + BUSY 1 device busy flag + DONE 1 device done flag + DISABLE 1 interrupt disable flag + INT 1 interrupt pending flag + POS 31 number of characters output + TIME 24 time from I/O initiation to interrupt + +2.2.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, +by changing POS, the user can backspace or advance the printer. + +The line printer implements these registers: + + name size comments + + BUF 8 last data item processed + BUSY 1 device busy flag + DONE 1 device done flag + DISABLE 1 interrupt disable flag + INT 1 interrupt pending flag + POS 31 position in the output file + TIME 24 time from I/O initiation to interrupt + 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 out of paper + + OS I/O error x report error and stop + +2.2.6 Real-Time Clock (CLK) + +The real-time clock (CLK) implements these registers: + + name size comments + + SELECT 2 selected clock interval + BUSY 1 device busy flag + DONE 1 device done flag + DISABLE 1 interrupt disable flag + INT 1 interrupt pending flag + TIME0 24 clock frequency, select = 0 + TIME1 24 clock frequency, select = 1 + TIME2 24 clock frequency, select = 2 + TIME3 24 clock frequency, select = 3 + +The real-time clock autocalibrates; the clock interval is adjusted up or +down so that the clock tracks actual elapsed time. + +2.2.7 Plotter (PTP) + +The plotter (PLT) 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 plotter. + +The plotter implements these registers: + + name size comments + + BUF 8 last data item processed + BUSY 1 device busy flag + DONE 1 device done flag + DISABLE 1 interrupt disable flag + INT 1 interrupt pending flag + POS 31 position in the output file + TIME 24 time from I/O initiation to interrupt + 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 out of tape or paper + + OS I/O error x report error and stop + +2.2.8 Second Terminal (TTI1, TTO1) + +The second terminal consists of two independent devices, TTI1 and TTO1. +The additional terminal performs input and output through a Telnet session +connecting into a user-specified port. The ATTACH command specifies the +port to be used: + + ATTACH TTI1 (cr) -- set up listening port + +where port is a decimal number between 1 and 65535 that is not being used +for other TCP/IP activities. + +Once TTI1 is attached and the simulator is running, the terminal listens +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 has two options, recognized on both devices, for +setting limited Dasher-compatibility mode or ANSI mode: + + SET TTI1 ANSI normal mode + SET TTI1 DASHER Dasher mode + SET TTO1 ANSI normal mode + SET TTO1 DASHER Dasher mode + +Setting either TTI1 or TTO1 changes both devices. In Dasher mode, carriage +return is changed to newline on input, and ^X is changed to backspace. + +The SHOW TTI1 LINESTATUS command displays the current connection to the +second terminal. + +The second terminal input implements these registers: + + name size comments + + BUF 8 last data item processed + BUSY 1 device busy flag + DONE 1 device done flag + DISABLE 1 interrupt disable flag + INT 1 interrupt pending flag + POS 31 number of characters input + TIME 24 keyboard polling interval + +The second terminal output implements these registers: + + name size comments + + BUF 8 last data item processed + BUSY 1 device busy flag + DONE 1 device done flag + DISABLE 1 interrupt disable flag + INT 1 interrupt pending flag + POS 31 number of characters output + TIME 24 time from I/O initiation to interrupt + +2.3 Fixed Head Disk (DK) + +The fixed head disk controller implements these registers: + + name size comments + + STAT 16 status + DA 16 disk address + MA 16 memory address + BUSY 1 device busy flag + DONE 1 device done flag + DISABLE 1 device disable flag + INT 1 interrupt pending flag + WLK 8 write lock switches + TIME 24 rotational delay, per sector + STOP_IOE 1 stop on I/O error + +The fixed head disk controller supports the BOOT command. + +Error handling is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 disk not ready + +Fixed head disk data files are buffered in memory; therefore, end of file +and OS I/O errors cannot occur. + +2.4 Moving Head Disk (DP) + +Moving head disk options include the ability to make units write enabled or +write locked, and to select the type of drive: + + SET DPn LOCKED set unit n write locked + SET DPn ENABLED set unit n write enabled + SET DPn FLOPPY set unit n to floppy disk + SET DPn D31 set unit n to Diablo 31 + SET DPn D44 set unit n to Diablo 44 + SET DPn C111 set unit n to Century 111 + SET DPn C114 set unit n to Century 114 + SET DPn 6225 set unit n to 6225 + SET DPn 6099 set unit n to 6099 + SET DPn 6227 set unit n to 6227 + SET DPn 6070 set unit n to 6070 + SET DPn 6103 set unit n to 6103 + SET DPn 4231 set unit n to 4231 + +Units can also be REMOVEd or ADDed to the configuration. The moving head +disk controller supports the BOOT command. + +All drives have 256 16b words per sector. The other disk parameters are: + + drive cylinders surfaces sectors size (MW) DG models + + floppy 77 1 8 .158 6038 + D31 203 2 12 1.247 4047, 4237, 4238 + D44 408 4 12 5.014 4234, 6045 + C111 203 10 6 3.118 4048 + C114 203 20 12 12.472 4057, 2314 + 6225 20 2 245 2.508 + 6099 32 4 192 6.291 + 6227 20 6 245 7.526 + 6070 24 4 408 10.027 + 6103 32 8 192 12.583 + 4231 23 19 411 45.979 + +The moving head disk controller implements these registers: + + name size comments + + FCCY 16 flags, command, cylinder + USSC 16 unit, surface, sector, count + STAT 16 status + MA 16 memory address + BUSY 1 device busy flag + DONE 1 device done flag + DISABLE 1 interrupt disable flag + INT 1 interrupt pending flag + STIME 24 seek time, per cylinder + RTIME 24 rotational delay + +Error handling is as follows: + + error processed as + + not attached disk not ready + + end of file assume rest of disk is zero + + OS I/O error report error and stop + +2.5 Magnetic Tape (MT) + +Magnetic tape options include the ability to make units write enabled or +or write locked. + + SET MTn LOCKED set unit n write locked + SET MTn ENABLED set unit n write enabled + +Units can also be REMOVEd or ADDed to the configuration. The magnetic +tape controller supports the BOOT command. + +The magnetic tape controller implements these registers: + + name size comments + + CU 16 command, unit + MA 16 memory address + WC 16 word count + STA1 16 status word 1 + STA2 16 status word 2 + EP 1 extended polling mode (not supported) + BUSY 1 device busy flag + DONE 1 device done flag + DISABLE 1 interrupt disable flag + INT 1 interrupt pending flag + STOP_IOE 1 stop on I/O error + CTIME 24 controller delay + RTIME 24 record delay + UST[0:7] 32 unit status, units 0-7 + POS[0:7] 31 position, units 0-7 + +Error handling is as follows: + + error processed as + + not attached tape not ready + + end of file (read or space) end of physical tape + (write) ignored + + OS I/O error report error and stop + +2.6 Symbolic Display and Input + +The Nova simulator implements symbolic display and input. Display is +controlled by command line switches: + + -a display as ASCII character + -c display as two character ASCII string + -m display instruction mnemonics + +Input parsing is controlled by the first character typed in or by command +line switches: + + ' or -a ASCII character + " or -c two character ASCII string + alphabetic instruction mnemonic + numeric octal number + +Instruction input uses standard Nova assembler syntax. There are three +instruction classes: memory reference, IOT, and operate. + +Memory reference instructions have the format + + memref {ac,}{@}address{,index} + +LDA and STA require an initial register; ISZ, DSZ, JSR, and JMP do not. +The syntax for addresses and indices is as follows: + +syntax mode displacement comments + +0 <= n < 0400 0 n +{+/-}n >= 0400 1 {+/-}n - PC must be in range [-200, 177] + invalid on disk +.+/-n 1 {+/-}n must be in range [-200, 177] +{+/-}n,2 2 {+/-}n must be in range [-200, 177] +{+/-}n,3 3 {+/-}n must be in range [-200, 177] + +IOT instructions have one of four formats + + syntax example + + iot HALT + iot reg INTA + iot device SKPDN + iot reg,device DOAS + +Devices may be specified as mnemonics or as numbers in the range 0 - 077. + +Operate instructions have the format + + opcode{#} reg,reg{,skip} + +In all Nova instructions, blanks may be substituted for commas as field +delimiters. diff --git a/nova_dsk.c b/NOVA/nova_dsk.c similarity index 100% rename from nova_dsk.c rename to NOVA/nova_dsk.c diff --git a/nova_lp.c b/NOVA/nova_lp.c similarity index 100% rename from nova_lp.c rename to NOVA/nova_lp.c diff --git a/nova_mta.c b/NOVA/nova_mta.c similarity index 87% rename from nova_mta.c rename to NOVA/nova_mta.c index 934d2f82..63b6271f 100644 --- a/nova_mta.c +++ b/NOVA/nova_mta.c @@ -25,6 +25,8 @@ mta magnetic tape + 30-Nov-01 RMS Added read only unit, extended SET/SHOW support + 24-Nov-01 RMS Changed POS, USTAT, FLG to an array 26-Apr-01 RMS Added device enable/disable support 18-Apr-01 RMS Changed to rewind tape before boot 10-Dec-00 RMS Added Eclipse support from Charles Owen @@ -54,12 +56,13 @@ #define MTA_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 flags width */ -#define UNIT_WLK 1 << UNIT_V_WLK #define USTAT u3 /* unit status */ #define UNUM u4 /* unit number */ #define DTSIZE (1 << 14) /* max data xfer */ #define DTMASK (DTSIZE - 1) +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ /* Command/unit */ @@ -149,7 +152,7 @@ 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); +t_stat mta_vlock (UNIT *uptr, int32 val, char *cptr, void *desc); #if defined (ECLIPSE) extern int32 MapAddr (int32 map, int32 addr); #else @@ -169,14 +172,14 @@ static const int ctype[32] = { /* c vs r timing */ */ UNIT mta_unit[] = { - { UDATA (&mta_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&mta_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&mta_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&mta_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&mta_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&mta_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&mta_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&mta_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) } }; + { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) } }; REG mta_reg[] = { { ORDATA (CU, mta_cu, 16) }, @@ -191,38 +194,11 @@ REG mta_reg[] = { { FLDATA (INT, int_req, INT_V_MTA) }, { DRDATA (CTIME, mta_cwait, 24), PV_LEFT }, { DRDATA (RTIME, mta_rwait, 24), PV_LEFT }, - { ORDATA (UST0, mta_unit[0].USTAT, 32) }, - { ORDATA (UST1, mta_unit[1].USTAT, 32) }, - { ORDATA (UST2, mta_unit[2].USTAT, 32) }, - { ORDATA (UST3, mta_unit[3].USTAT, 32) }, - { ORDATA (UST4, mta_unit[4].USTAT, 32) }, - { ORDATA (UST5, mta_unit[5].USTAT, 32) }, - { ORDATA (UST6, mta_unit[6].USTAT, 32) }, - { ORDATA (UST7, mta_unit[7].USTAT, 32) }, - { DRDATA (POS0, mta_unit[0].pos, 31), REG_RO + PV_LEFT }, - { DRDATA (POS1, mta_unit[1].pos, 31), REG_RO + PV_LEFT }, - { DRDATA (POS2, mta_unit[2].pos, 31), REG_RO + PV_LEFT }, - { DRDATA (POS3, mta_unit[3].pos, 31), REG_RO + PV_LEFT }, - { DRDATA (POS4, mta_unit[4].pos, 31), REG_RO + PV_LEFT }, - { DRDATA (POS5, mta_unit[5].pos, 31), REG_RO + PV_LEFT }, - { DRDATA (POS6, mta_unit[6].pos, 31), REG_RO + PV_LEFT }, - { DRDATA (POS7, mta_unit[7].pos, 31), REG_RO + PV_LEFT }, - { GRDATA (FLG0, mta_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG1, mta_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG2, mta_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG3, mta_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG4, mta_unit[4].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG5, mta_unit[5].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG6, mta_unit[6].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG7, mta_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, + { URDATA (UST, mta_unit[0].USTAT, 8, 32, 0, MTA_NUMDR, 0) }, + { URDATA (POS, mta_unit[0].pos, 8, 31, 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 } }; @@ -341,7 +317,7 @@ 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_WLK) && /* 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_sta = mta_sta | STA_ILL; } /* illegal operation */ @@ -526,7 +502,7 @@ for (u = 0; u < MTA_NUMDR; u++) { /* loop thru units */ uptr -> UNUM = u; if (uptr -> flags & UNIT_ATT) uptr -> USTAT = STA_RDY | (uptr -> USTAT & STA_PEM) | - ((uptr -> flags & UNIT_WLK)? STA_WLK: 0) | + ((uptr -> flags & UNIT_WPRT)? STA_WLK: 0) | ((uptr -> pos)? 0: STA_BOT); else uptr -> USTAT = 0; } mta_updcsta (&mta_unit[0]); /* update status */ @@ -542,7 +518,7 @@ t_stat r; r = attach_unit (uptr, cptr); if (r != SCPE_OK) return r; if (!sim_is_active (uptr)) mta_upddsta (uptr, STA_RDY | STA_BOT | STA_PEM | - ((uptr -> flags & UNIT_WLK)? STA_WLK: 0)); + ((uptr -> flags & UNIT_WPRT)? STA_WLK: 0)); return r; } @@ -556,7 +532,7 @@ return detach_unit (uptr); /* Write lock/unlock validate routine */ -t_stat mta_vlock (UNIT *uptr, int32 val) +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); diff --git a/nova_plt.c b/NOVA/nova_plt.c similarity index 100% rename from nova_plt.c rename to NOVA/nova_plt.c diff --git a/nova_pt.c b/NOVA/nova_pt.c similarity index 94% rename from nova_pt.c rename to NOVA/nova_pt.c index e7a6de60..922233b7 100644 --- a/nova_pt.c +++ b/NOVA/nova_pt.c @@ -25,6 +25,8 @@ ptr paper tape reader ptp paper tape punch + + 29-Nov-01 RMS Added read only unit support */ #include "nova_defs.h" @@ -44,7 +46,8 @@ t_stat ptp_reset (DEVICE *dptr); */ UNIT ptr_unit = { - UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_IN_WAIT }; + UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), + SERIAL_IN_WAIT }; REG ptr_reg[] = { { ORDATA (BUF, ptr_unit.buf, 8) }, diff --git a/nova_sys.c b/NOVA/nova_sys.c similarity index 100% rename from nova_sys.c rename to NOVA/nova_sys.c diff --git a/nova_tt.c b/NOVA/nova_tt.c similarity index 92% rename from nova_tt.c rename to NOVA/nova_tt.c index 1c60a52e..7cc75741 100644 --- a/nova_tt.c +++ b/NOVA/nova_tt.c @@ -26,6 +26,7 @@ tti terminal input tto terminal output + 30-Nov-01 RMS Added extended SET/SHOW support 17-Sep-01 RMS Removed multiconsole support 07-Sep-01 RMS Moved function prototypes 31-May-01 RMS Added multiconsole support @@ -40,7 +41,7 @@ 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 ttx_setmod (UNIT *uptr, int32 value); +t_stat ttx_setmod (UNIT *uptr, int32 val, char *cptr); /* TTI data structures @@ -200,9 +201,9 @@ sim_cancel (&tto_unit); /* deactivate unit */ return SCPE_OK; } -t_stat ttx_setmod (UNIT *uptr, int32 value) +t_stat ttx_setmod (UNIT *uptr, int32 val, char *cptr) { -tti_unit.flags = (tti_unit.flags & ~UNIT_DASHER) | value; -tto_unit.flags = (tto_unit.flags & ~UNIT_DASHER) | value; +tti_unit.flags = (tti_unit.flags & ~UNIT_DASHER) | val; +tto_unit.flags = (tto_unit.flags & ~UNIT_DASHER) | val; return SCPE_OK; } diff --git a/nova_tt1.c b/NOVA/nova_tt1.c similarity index 90% rename from nova_tt1.c rename to NOVA/nova_tt1.c index b367e01a..6d70840e 100644 --- a/nova_tt1.c +++ b/NOVA/nova_tt1.c @@ -27,6 +27,7 @@ tti1 second terminal input tto1 second terminal output + 30-Nov-01 RMS Added extended SET/SHOW support 17-Sep-01 RMS Changed to use terminal multiplexor library 07-Sep-01 RMS Moved function prototypes 31-May-01 RMS Added multiconsole support @@ -49,10 +50,10 @@ t_stat tti1_svc (UNIT *uptr); t_stat tto1_svc (UNIT *uptr); t_stat tti1_reset (DEVICE *dptr); t_stat tto1_reset (DEVICE *dptr); -t_stat ttx1_setmod (UNIT *uptr, int32 value); +t_stat ttx1_setmod (UNIT *uptr, int32 val, char *cptr); t_stat tti1_attach (UNIT *uptr, char *cptr); t_stat tti1_detach (UNIT *uptr); -t_stat tti1_status (UNIT *uptr, FILE *st); +t_stat tti1_status (FILE *st, UNIT *uptr, int32 val, void *desc); /* TTI1 data structures @@ -77,9 +78,11 @@ REG tti1_reg[] = { { NULL } }; MTAB ttx1_mod[] = { - { UNIT_ATT, UNIT_ATT, "line status:", NULL, &tti1_status }, { UNIT_DASHER, 0, "ANSI", "ANSI", &ttx1_setmod }, { UNIT_DASHER, UNIT_DASHER, "Dasher", "DASHER", &ttx1_setmod }, + { UNIT_ATT, UNIT_ATT, "line status", NULL, NULL, &tti1_status }, + { MTAB_XTD | MTAB_VDV | MTAB_VUN | MTAB_NMO, 0, "LINE", NULL, + NULL, &tti1_status, NULL }, { 0 } }; DEVICE tti1_dev = { @@ -233,10 +236,10 @@ sim_cancel (&tto1_unit); /* deactivate unit */ return SCPE_OK; } -t_stat ttx1_setmod (UNIT *uptr, int32 value) +t_stat ttx1_setmod (UNIT *uptr, int32 val, char *cptr) { -tti1_unit.flags = (tti1_unit.flags & ~UNIT_DASHER) | value; -tto1_unit.flags = (tto1_unit.flags & ~UNIT_DASHER) | value; +tti1_unit.flags = (tti1_unit.flags & ~UNIT_DASHER) | val; +tto1_unit.flags = (tto1_unit.flags & ~UNIT_DASHER) | val; return SCPE_OK; } @@ -266,7 +269,7 @@ return r; /* Status routine */ -t_stat tti1_status (UNIT *uptr, FILE *st) +t_stat tti1_status (FILE *st, UNIT *uptr, int32 val, void *desc) { tmxr_fstatus (st, &tt1_ldsc, -1); return SCPE_OK; diff --git a/pdp1_cpu.c b/PDP1/pdp1_cpu.c similarity index 93% rename from pdp1_cpu.c rename to PDP1/pdp1_cpu.c index 26cec4a5..355a7620 100644 --- a/pdp1_cpu.c +++ b/PDP1/pdp1_cpu.c @@ -25,6 +25,8 @@ cpu PDP-1 central processor + 07-Dec-01 RMS Revised to use breakpoint package + 30-Nov-01 RMS Added extended SET/SHOW support 16-Dec-00 RMS Fixed bug in XCT address calculation 14-Apr-99 RMS Changed t_addr to unsigned @@ -212,8 +214,6 @@ #include "pdp1_defs.h" -#define ILL_ADR_FLAG (1 << ASIZE) -#define save_ibkpt (cpu_unit.u3) #define UNIT_V_MDV (UNIT_V_UF) /* mul/div */ #define UNIT_MDV (1 << UNIT_V_MDV) #define UNIT_V_MSIZE (UNIT_V_UF+1) /* dummy mask */ @@ -238,15 +238,14 @@ int32 stop_inst = 0; /* stop on rsrv inst */ int32 xct_max = 16; /* nested XCT limit */ int32 ind_max = 16; /* nested ind limit */ int32 old_PC = 0; /* old PC */ -int32 ibkpt_addr = ILL_ADR_FLAG | AMASK; /* breakpoint addr */ +extern UNIT *sim_clock_queue; +extern int32 sim_int_char; +extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ 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_svc (UNIT *uptr); -t_stat cpu_set_size (UNIT *uptr, int32 value); -extern int32 sim_int_char; -extern UNIT *sim_clock_queue; +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); @@ -297,7 +296,7 @@ int32 sc_map[512] = { cpu_mod CPU modifier list */ -UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) }; +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) }; REG cpu_reg[] = { { ORDATA (PC, PC, ASIZE) }, @@ -321,7 +320,6 @@ REG cpu_reg[] = { { 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 (BREAK, ibkpt_addr, ASIZE + 1) }, { ORDATA (WRU, sim_int_char, 8) }, { NULL } }; @@ -379,10 +377,7 @@ if (sbs == (SB_ON | SB_RQ)) { /* interrupt? */ extm = 0; /* extend off */ OV = 0; } /* clear overflow */ -if (PC == ibkpt_addr) { /* breakpoint? */ - save_ibkpt = ibkpt_addr; /* save ibkpt */ - ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */ - sim_activate (&cpu_unit, 1); /* sched re-enable */ +if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ reason = STOP_IBKPT; /* stop simulation */ break; } @@ -741,7 +736,8 @@ extm = extm_init; ioh = ioc = 0; OV = 0; PF = 0; -return cpu_svc (&cpu_unit); +sim_brk_types = sim_brk_dflt = SWMASK ('E'); +return SCPE_OK; } /* Memory examine */ @@ -762,28 +758,19 @@ M[addr] = val & 0777777; return SCPE_OK; } -/* Service breakpoint */ - -t_stat cpu_svc (UNIT *uptr) -{ -if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt) ibkpt_addr = save_ibkpt; -save_ibkpt = -1; -return SCPE_OK; -} - /* Change memory size */ -t_stat cpu_set_size (UNIT *uptr, int32 value) +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { int32 mc = 0; t_addr i; -if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 07777) != 0)) +if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0)) return SCPE_ARG; -for (i = value; i < MEMSIZE; i++) mc = mc | M[i]; +for (i = val; i < MEMSIZE; i++) mc = mc | M[i]; if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) return SCPE_OK; -MEMSIZE = value; +MEMSIZE = val; for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; return SCPE_OK; } diff --git a/pdp1_defs.h b/PDP1/pdp1_defs.h similarity index 100% rename from pdp1_defs.h rename to PDP1/pdp1_defs.h diff --git a/PDP1/pdp1_doc.txt b/PDP1/pdp1_doc.txt new file mode 100644 index 00000000..fdca74e6 --- /dev/null +++ b/PDP1/pdp1_doc.txt @@ -0,0 +1,409 @@ +To: Users +From: Bob Supnik +Subj: PDP-1 Simulator Usage +Date: 1-Dec-01 + + COPYRIGHT NOTICE + +The following copyright notice applies to both the SIMH source and binary: + + Original code published in 1993-2001, written by Robert M Supnik + 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. + +This memorandum documents the PDP-1 simulator. + + +1. Simulator Files + +sim/ sim_defs.h + scp.c + scp_tty.c + sim_rev.c + +sim/pdp1/ pdp1_defs.h + pdp1_cpu.c + pdp1_lp.c + pdp1_stddev.c + pdp1_sys.c + +2. PDP-1 Features + +The PDP-1 is configured as follows: + +device simulates +name(s) + +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 + +The PDP-1 simulator implements the following unique stop conditions: + + - an unimplemented instruction is decoded, and register + STOP_INST is set + - more than INDMAX indirect addresses are detected during + memory reference address decoding + - more than XCTMAX nested executes are detected during + instruction execution + - wait state entered, and no I/O operations outstanding + (ie, no interrupt can ever occur) + +The PDP-1 loader supports RIM format tapes. The DUMP command is not +implemented. + +2.1 CPU + +The only CPU options are the presence of hardware multiply/divide and the +size of main memory. + + SET CPU MDV enable multiply/divide + SET CPU NOMDV disable multiply/divide + SET CPU 4K set memory size = 4K + SET CPU 8K set memory size = 8K + SET CPU 12K set memory size = 12K + SET CPU 16K set memory size = 16K + SET CPU 20K set memory size = 20K + SET CPU 24K set memory size = 24K + SET CPU 28K set memory size = 28K + SET CPU 32K set memory size = 32K + SET CPU 48K set memory size = 48K + SET CPU 64K set memory size = 64K + +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 64K. + +CPU registers include the visible state of the processor as well as the +control registers for the interrupt system. + + name size comments + + PC 16 program counter + AC 18 accumulator + IO 18 IO register + OV 1 overflow flag + PF 6 program flags<1:6> + SS 6 sense switches<1:6> + TW 18 test word (front panel switches) + EXTM 1 extend mode + IOSTA 18 IO status register + SBON 1 sequence break enable + SBRQ 1 sequence break request + SBIP 1 sequence break in progress + IOH 1 I/O halt in progress + IOC 1 I/O continue + OLDPC 16 PC prior to last transfer + STOP_INST 1 stop on undefined instruction + SBS_INIT 1 initial state of sequence break enable + EXTM_INIT 1 initial state of extend mode + WRU 8 interrupt character + +2.2 Programmed I/O Devices + +2.2.1 Paper Tape Reader (PTR) + +The paper tape reader (PTR) 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 PTR copies the +RIM loader into memory and starts it running. + +The paper tape reader implements these registers: + + name size comments + + BUF 8 last data item processed + DONE 1 device done flag + RPLS 1 return restart pulse flag + POS 31 position in the input file + TIME 24 time from I/O initiation to interrupt + 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 out of tape + + end of file 1 report error and stop + 0 out of tape + + OS I/O error x report error and stop + +2.2.2 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. +Thus, by changing POS, the user can backspace or advance the punch. + +The paper tape punch implements these registers: + + name size comments + + BUF 8 last data item processed + DONE 1 device done flag + RPLS 1 return restart pulse flag + POS 31 position in the output file + TIME 24 time from I/O initiation to interrupt + 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 out of tape + + OS I/O error x report error and stop + +2.2.3 Terminal Input (TTI) + +The terminal input (TTI) polls the console keyboard for input. It +implements these registers: + + name size comments + + BUF 8 last data item processed + DONE 1 device done flag + POS 31 number of characters input + TIME 24 keyboard polling interval + +2.2.4 Terminal Output (TTO) + +The terminal output (TTO) writes to the simulator console window. +It implements these registers: + + name size comments + + BUF 8 last data item processed + DONE 1 device done flag + RPLS 1 return restart pulse flag + POS 31 number of characters output + TIME 24 time from I/O initiation to interrupt + +2.2.5 Type 62 Line Printer (LPT) + +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 implements these registers: + + name size comments + + BUF 8 last data item processed + PNT 1 printing done flag + SPC 1 spacing done flag + RPLS 1 return restart pulse flag + BPTR 6 print buffer pointer + POS 31 position in the output file + TIME 24 time from I/O initiation to interrupt + STOP_IOE 1 stop on I/O error + LBUF[0:119] 8 line buffer + +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 + +2.3 Symbolic Display and Input + +The PDP-1 simulator implements symbolic display and input. Display is +controlled by command line switches: + + -a display as ASCII character + -c display as FIODEC character string + -m display instruction mnemonics + +Input parsing is controlled by the first character typed in or by command +line switches: + + ' or -a ASCII character + " or -c three character FIODEC string + alphabetic instruction mnemonic + numeric octal number + +Instruction input uses modified PDP-1 assembler syntax. There are six +instruction classes: memory reference, shift, skip, operate, IOT, and +LAW. + +Memory reference instructions have the format + + memref {I} address + +where I signifies indirect reference. The address is an octal number in +the range 0 - 0177777. + +Shift instructions have the format + + shift shift_count + +The shift count is an octal number in the range 0-9. + +Skip instructions consist of single mnemonics, eg, SZA, SZS4. Skip +instructions may be or'd together + + skip skip skip... + +The sense of a skip can be inverted by including the mnemonic I. + +Operate instructions consist of single mnemonics, eg, CLA, CLI. Operate +instructions may be or'd together + + opr opr opr... + +IOT instructions consist of single mnemonics, eg, TYI, TYO. IOT +instructions may include an octal numeric modifier or the modifier I: + + iot modifier + +The simulator does not check the legality of skip, operate, or IOT +combinations. + +Finally, the LAW instruction has the format + + LAW {I} immediate + +where immediate is in the range 0 to 07777. + +2.4 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 +character set. The following table provides equivalences between ASCII +characters and the PDP-1's I/O devices. In the console table, UC stands +for upper case. + + PDP-1 PDP-1 +ASCII console line printer + +000 - 007 none none +bs 075 none +tab 036 none +012 - 014 none none +cr 077 none +016 - 037 none none +space 000 000 +! {OR} UC+005 none +" UC+001 none +# {IMPLIES} UC+004 none +$ none none +% none none +& {AND} UC+006 none +' UC+002 none +( 057 057 +) 055 055 +* {TIMES} UC+073 072 ++ UC+054 074 +, 033 033 +- 054 054 +. 073 073 +/ 021 021 +0 020 020 +1 001 001 +2 002 002 +3 003 003 +4 004 004 +5 005 005 +6 006 006 +7 007 007 +8 010 010 +9 011 011 +: none none +; none none +< UC+007 034 += UC+033 053 +> UC+010 034 +? UC+021 037 +@ {MID DOT} 040 {MID DOT} 040 +A UC+061 061 +B UC+062 062 +C UC+063 063 +D UC+064 064 +E UC+065 065 +F UC+066 066 +G UC+067 067 +H UC+070 070 +I UC+071 071 +J UC+041 041 +K UC+042 042 +L UC+043 043 +M UC+044 044 +N UC+045 045 +O UC+046 046 +P UC+047 047 +Q UC+050 050 +R UC+051 051 +S UC+022 022 +T UC+023 023 +U UC+024 024 +V UC+025 025 +W UC+026 026 +X UC+027 027 +Y UC+030 030 +Z UC+031 031 +[ UC+057 none +\ {OVERLINE} 056 {OVERLINE} 056 +] UC+055 none +^ {UP ARROW} UC+011 {UP ARROW} 035 +_ UC+040 UC+040 +` {RT ARROW} UC+020 036 +a 061 none +b 062 none +c 063 none +d 064 none +e 065 none +f 066 none +g 067 none +h 070 none +i 071 none +j 041 none +k 042 none +l 043 none +m 044 none +n 045 none +o 046 none +p 047 none +q 050 none +r 051 none +s 022 none +t 023 none +u 024 none +v 025 none +w 026 none +x 027 none +y 030 none +z 031 none +{ none none +| UC+056 076 +} none none +~ UC+003 013 +del 075 none diff --git a/pdp1_lp.c b/PDP1/pdp1_lp.c similarity index 100% rename from pdp1_lp.c rename to PDP1/pdp1_lp.c diff --git a/pdp1_stddev.c b/PDP1/pdp1_stddev.c similarity index 95% rename from pdp1_stddev.c rename to PDP1/pdp1_stddev.c index 7c19dbfa..21c0830e 100644 --- a/pdp1_stddev.c +++ b/PDP1/pdp1_stddev.c @@ -28,6 +28,7 @@ tti keyboard tto teleprinter + 29-Nov-01 RMS Added read only unit support 07-Sep-01 RMS Moved function prototypes 10-Jun-01 RMS Fixed comment 30-Oct-00 RMS Standardized device naming @@ -103,7 +104,8 @@ int32 ascii_to_fiodec[128] = { */ UNIT ptr_unit = { - UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_IN_WAIT }; + UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), + SERIAL_IN_WAIT }; REG ptr_reg[] = { { ORDATA (BUF, ptr_unit.buf, 18) }, diff --git a/pdp1_sys.c b/PDP1/pdp1_sys.c similarity index 100% rename from pdp1_sys.c rename to PDP1/pdp1_sys.c diff --git a/pdp10_cpu.c b/PDP10/pdp10_cpu.c similarity index 93% rename from pdp10_cpu.c rename to PDP10/pdp10_cpu.c index f3bba9f5..7611d85b 100644 --- a/pdp10_cpu.c +++ b/PDP10/pdp10_cpu.c @@ -25,6 +25,9 @@ cpu KS10 central processor + 25-Dec-01 RMS Cleaned up sim_inst declarations + 07-Dec-01 RMS Revised to use new breakpoint package + 21-Nov-01 RMS Implemented ITS 1-proceed hack 31-Aug-01 RMS Changed int64 to t_int64 for Windoze 10-Aug-01 RMS Removed register in declarations 17-Jul-01 RMS Moved function prototype @@ -112,13 +115,19 @@ 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 + + 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 + as flags<8>. This simplifies the flag saving instructions, which + don't have to clear flags<8> before saving it. Instead, the page + fail and interrupt code must restore flags<8> from its_1pr. Unlike + the KS10, the simulator will not lose the 1-proceed trap if the + 1-proceeded instructions clears 1-proceed. */ #include "pdp10_defs.h" #include -#define ILL_ADR_FLAG (1 << VASIZE) -#define save_ibkpt (cpu_unit.u3) #define UNIT_V_MSIZE (UNIT_V_T20V41 + 1) /* dummy mask */ #define UNIT_MSIZE (1 << UNIT_V_MSIZE) @@ -126,9 +135,12 @@ d10 *M = NULL; /* memory */ d10 acs[AC_NBLK * AC_NUM] = { 0 }; /* AC blocks */ d10 *ac_cur, *ac_prv; /* AC cur, prv (dyn) */ a10 epta, upta; /* proc tbl addr (dyn) */ -d10 last_inst = 0; /* most recent inst */ a10 saved_PC = 0; /* scp: saved PC */ +d10 pager_word = 0; /* pager: error word */ a10 pager_PC = 0; /* pager: saved PC */ +int32 pager_flags = 0; /* pager: trap flags */ +t_bool pager_pi = FALSE; /* pager: in pi seq */ +t_bool pager_tc = FALSE; /* pager: trap cycle */ d10 ebr = 0; /* exec base reg */ d10 ubr = 0; /* user base reg */ d10 hsb = 0; /* halt status block */ @@ -152,22 +164,60 @@ int32 apr_flg = 0; /* apr flags */ int32 apr_lvl = 0; /* apr level */ int32 qintr = 0; /* interrupt pending */ int32 flags = 0; /* flags */ +int32 its_1pr = 0; /* ITS 1-proceed */ int32 stop_op0 = 0; /* stop on 0 */ -d10 pager_word = 0; /* pager error word */ int32 rlog = 0; /* extend fixup log */ int32 ind_max = 32; /* nested ind limit */ int32 xct_max = 32; /* nested XCT limit */ -int32 astop_cpu = 0; /* address stop */ a10 old_PC = 0; /* old PC */ -a10 ibkpt_addr = ILL_ADR_FLAG | AMASK; /* breakpoint addr */ jmp_buf save_env; +extern int32 sim_int_char; +extern int32 sim_interval; +extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ +extern UNIT tim_unit; + +/* Forward and external declarations */ + 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_svc (UNIT *uptr); -extern int32 sim_int_char; -extern int32 sim_interval; +d10 adjsp (d10 val, a10 ea); +void ibp (a10 ea, int32 pflgs); +d10 ldb (a10 ea, int32 pflgs); +void dpb (d10 val, a10 ea, int32 pflgs); +void adjbp (int32 ac, a10 ea, int32 pflgs); +d10 add (d10 val, d10 mb); +d10 sub (d10 val, d10 mb); +void dadd (int32 ac, d10 *rs); +void dsub (int32 ac, d10 *rs); +int32 jffo (d10 val); +d10 lsh (d10 val, a10 ea); +d10 rot (d10 val, a10 ea); +d10 ash (d10 val, a10 ea); +void lshc (int32 ac, a10 ea); +void rotc (int32 ac, a10 ea); +void ashc (int32 ac, a10 ea); +void circ (int32 ac, a10 ea); +void blt (int32 ac, a10 ea, int32 pflgs); +void bltu (int32 ac, a10 ea, int32 pflgs, int dir); +a10 calc_ea (d10 inst, int32 prv); +a10 calc_ioea (d10 inst, int32 prv); +d10 calc_jrstfea (d10 inst, int32 pflgs); +void pi_dismiss (void); +void set_newflags (d10 fl, t_bool jrst); +extern t_bool aprid (a10 ea, int32 prv); +t_bool wrpi (a10 ea, int32 prv); +t_bool rdpi (a10 ea, int32 prv); +t_bool czpi (a10 ea, int32 prv); +t_bool copi (a10 ea, int32 prv); +t_bool wrapr (a10 ea, int32 prv); +t_bool rdapr (a10 ea, int32 prv); +t_bool czapr (a10 ea, int32 prv); +t_bool coapr (a10 ea, int32 prv); +int32 pi_eval (void); +int32 test_int (void); +void set_ac_display (d10 *acbase); extern d10 Read (a10 ea, int32 prv); /* read, read check */ extern d10 ReadM (a10 ea, int32 prv); /* read, write check */ @@ -180,9 +230,69 @@ extern t_bool AccViol (a10 ea, int32 prv, int32 mode); /* access check */ extern void set_dyn_ptrs (void); extern a10 conmap (a10 ea, int32 mode, int32 sw); extern void fe_intr (); -int32 pi_eval (void); -int32 test_int (void); -void set_ac_display (d10 *acbase); +extern void dfad (int32 ac, d10 *rs, int32 inv); +extern void dfmp (int32 ac, d10 *rs); +extern void dfdv (int32 ac, d10 *rs); +extern void dmul (int32 ac, d10 *rs); +extern void ddiv (int32 ac, d10 *rs); +extern void fix (int32 ac, d10 mb, t_bool rnd); +extern d10 fad (d10 val, d10 mb, t_bool rnd, int32 inv); +extern d10 fmp (d10 val, d10 mb, t_bool rnd); +extern t_bool fdv (d10 val, d10 mb, d10 *rs, t_bool rnd); +extern d10 fsc (d10 val, a10 ea); +extern d10 fltr (d10 mb); +extern int xtend (int32 ac, a10 ea, int32 pflgs); +extern void xtcln (int32 rlog); +extern d10 map (a10 ea, int32 prv); +extern d10 imul (d10 val, d10 mb); +extern t_bool idiv (d10 val, d10 mb, d10 *rs); +extern void mul (d10 val, d10 mb, d10 *rs); +extern t_bool divi (int32 ac, d10 mb, d10 *rs); +extern t_bool io710 (int32 ac, a10 ea); +extern t_bool io711 (int32 ac, a10 ea); +extern d10 io712 (a10 ea); +extern void io713 (d10 val, a10 ea); +extern void io714 (d10 val, a10 ea); +extern void io715 (d10 val, a10 ea); +extern t_bool io720 (int32 ac, a10 ea); +extern t_bool io721 (int32 ac, a10 ea); +extern d10 io722 (a10 ea); +extern void io723 (d10 val, a10 ea); +extern void io724 (d10 val, a10 ea); +extern void io725 (d10 val, a10 ea); +extern t_bool clrcsh (a10 ea, int32 prv); +extern t_bool clrpt (a10 ea, int32 prv); +extern t_bool wrubr (a10 ea, int32 prv); +extern t_bool wrebr (a10 ea, int32 prv); +extern t_bool wrhsb (a10 ea, int32 prv); +extern t_bool wrspb (a10 ea, int32 prv); +extern t_bool wrcsb (a10 ea, int32 prv); +extern t_bool wrpur (a10 ea, int32 prv); +extern t_bool wrcstm (a10 ea, int32 prv); +extern t_bool ldbr1 (a10 ea, int32 prv); +extern t_bool ldbr2 (a10 ea, int32 prv); +extern t_bool ldbr3 (a10 ea, int32 prv); +extern t_bool ldbr4 (a10 ea, int32 prv); +extern t_bool rdubr (a10 ea, int32 prv); +extern t_bool rdebr (a10 ea, int32 prv); +extern t_bool rdhsb (a10 ea, int32 prv); +extern t_bool rdspb (a10 ea, int32 prv); +extern t_bool rdcsb (a10 ea, int32 prv); +extern t_bool rdpur (a10 ea, int32 prv); +extern t_bool rdcstm (a10 ea, int32 prv); +extern t_bool sdbr1 (a10 ea, int32 prv); +extern t_bool sdbr2 (a10 ea, int32 prv); +extern t_bool sdbr3 (a10 ea, int32 prv); +extern t_bool sdbr4 (a10 ea, int32 prv); +extern t_bool rdtim (a10 ea, int32 prv); +extern t_bool rdint (a10 ea, int32 prv); +extern t_bool wrtim (a10 ea, int32 prv); +extern t_bool wrint (a10 ea, int32 prv); +extern t_bool rdpcst (a10 ea, int32 prv); +extern t_bool wrpcst (a10 ea, int32 prv); +extern t_bool spm (a10 ea, int32 prv); +extern t_bool lpmr (a10 ea, int32 prv); +extern int32 pi_ub_vec (int32 lvl, int32 *uba); /* CPU data structures @@ -192,7 +302,7 @@ void set_ac_display (d10 *acbase); cpu_mod CPU modifier list */ -UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX, MAXMEMSIZE) }; +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX, MAXMEMSIZE) }; REG cpu_reg[] = { { ORDATA (PC, saved_PC, VASIZE) }, @@ -213,7 +323,6 @@ REG cpu_reg[] = { { ORDATA (AC15, acs[15], 36) }, { ORDATA (AC16, acs[16], 36) }, { ORDATA (AC17, acs[17], 36) }, - { ORDATA (IR, last_inst, 36), REG_RO }, { ORDATA (PFW, pager_word, 36) }, { ORDATA (EBR, ebr, EBR_N_EBR) }, { FLDATA (PGON, ebr, EBR_V_PGON) }, @@ -241,12 +350,12 @@ REG cpu_reg[] = { { ORDATA (APRFLG, apr_flg, 8) }, { ORDATA (APRLVL, apr_lvl, 3) }, { ORDATA (RLOG, rlog, 10) }, + { FLDATA (F1PR, its_1pr, 0) }, { ORDATA (OLDPC, old_PC, VASIZE), REG_RO }, { 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 (BREAK, ibkpt_addr, VASIZE + 1) }, { ORDATA (WRU, sim_int_char, 8) }, { FLDATA (STOP_ILL, stop_op0, 0) }, { BRDATA (REG, acs, 8, 36, AC_NUM * AC_NBLK) }, @@ -294,12 +403,32 @@ const d10 bytemask[64] = { 0, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES }; -/* JRST classes */ +static t_bool (*io700d[16])() = { + &aprid, NULL, NULL, NULL, &wrapr, &rdapr, &czapr, &coapr, + NULL, NULL, NULL, NULL, &wrpi, &rdpi, &czpi, &copi }; +static t_bool (*io701d[16])() = { + NULL, &rdubr, &clrpt, &wrubr, &wrebr, &rdebr, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; +static t_bool (*io702d[16])() = { + &rdspb, &rdcsb, &rdpur, &rdcstm, &rdtim, &rdint, &rdhsb, NULL, + &wrspb, &wrcsb, &wrpur, &wrcstm, &wrtim, &wrint, &wrhsb, NULL }; +#define io700i io700d +static t_bool (*io701i[16])() = { + &clrcsh, &rdubr, &clrpt, &wrubr, &wrebr, &rdebr, NULL, NULL, + NULL, &rdpcst, NULL, &wrpcst, NULL, NULL, NULL, NULL }; +static t_bool (*io702i[16])() = { + &sdbr1, &sdbr2, &sdbr3, &sdbr4, &rdtim, &rdint, &rdhsb, &spm, + &ldbr1, &ldbr2, &ldbr3, &ldbr4, &wrtim, &wrint, &wrhsb, &lpmr }; + +/* JRST classes and validation table */ #define JRST_U 1 /* ok anywhere */ #define JRST_E 2 /* ok exec mode */ #define JRST_UIO 3 /* ok user I/O mode */ - + +static t_stat jrst_tab[16] = { + JRST_U, JRST_U, JRST_U, 0, JRST_E, JRST_U, JRST_E, JRST_E, + JRST_UIO, 0, JRST_UIO, 0, JRST_E, JRST_U, 0, 0 }; /* Address operations */ @@ -443,148 +572,19 @@ const d10 bytemask[64] = { 0, t_stat sim_instr (void) { - -/* External and forward declarations */ - -extern void dfad (int32 ac, d10 *rs, int32 inv); -extern void dfmp (int32 ac, d10 *rs); -extern void dfdv (int32 ac, d10 *rs); -extern void dmul (int32 ac, d10 *rs); -extern void ddiv (int32 ac, d10 *rs); -extern void fix (int32 ac, d10 mb, t_bool rnd); -extern d10 fad (d10 val, d10 mb, t_bool rnd, int32 inv); -extern d10 fmp (d10 val, d10 mb, t_bool rnd); -extern t_bool fdv (d10 val, d10 mb, d10 *rs, t_bool rnd); -extern d10 fsc (d10 val, a10 ea); -extern d10 fltr (d10 mb); -extern int xtend (int32 ac, a10 ea, int32 pflgs); -extern void xtcln (int32 rlog); -extern d10 map (a10 ea, int32 prv); -extern d10 imul (d10 val, d10 mb); -extern t_bool idiv (d10 val, d10 mb, d10 *rs); -extern void mul (d10 val, d10 mb, d10 *rs); -extern t_bool divi (int32 ac, d10 mb, d10 *rs); -extern t_bool io710 (int32 ac, a10 ea); -extern t_bool io711 (int32 ac, a10 ea); -extern d10 io712 (a10 ea); -extern void io713 (d10 val, a10 ea); -extern void io714 (d10 val, a10 ea); -extern void io715 (d10 val, a10 ea); -extern t_bool io720 (int32 ac, a10 ea); -extern t_bool io721 (int32 ac, a10 ea); -extern d10 io722 (a10 ea); -extern void io723 (d10 val, a10 ea); -extern void io724 (d10 val, a10 ea); -extern void io725 (d10 val, a10 ea); - -extern t_bool clrcsh (a10 ea, int32 prv); -extern t_bool clrpt (a10 ea, int32 prv); -extern t_bool wrubr (a10 ea, int32 prv); -extern t_bool wrebr (a10 ea, int32 prv); -extern t_bool wrhsb (a10 ea, int32 prv); -extern t_bool wrspb (a10 ea, int32 prv); -extern t_bool wrcsb (a10 ea, int32 prv); -extern t_bool wrpur (a10 ea, int32 prv); -extern t_bool wrcstm (a10 ea, int32 prv); -extern t_bool ldbr1 (a10 ea, int32 prv); -extern t_bool ldbr2 (a10 ea, int32 prv); -extern t_bool ldbr3 (a10 ea, int32 prv); -extern t_bool ldbr4 (a10 ea, int32 prv); -extern t_bool rdubr (a10 ea, int32 prv); -extern t_bool rdebr (a10 ea, int32 prv); -extern t_bool rdhsb (a10 ea, int32 prv); -extern t_bool rdspb (a10 ea, int32 prv); -extern t_bool rdcsb (a10 ea, int32 prv); -extern t_bool rdpur (a10 ea, int32 prv); -extern t_bool rdcstm (a10 ea, int32 prv); -extern t_bool sdbr1 (a10 ea, int32 prv); -extern t_bool sdbr2 (a10 ea, int32 prv); -extern t_bool sdbr3 (a10 ea, int32 prv); -extern t_bool sdbr4 (a10 ea, int32 prv); -extern t_bool rdtim (a10 ea, int32 prv); -extern t_bool rdint (a10 ea, int32 prv); -extern t_bool wrtim (a10 ea, int32 prv); -extern t_bool wrint (a10 ea, int32 prv); -extern t_bool rdpcst (a10 ea, int32 prv); -extern t_bool wrpcst (a10 ea, int32 prv); -extern t_bool spm (a10 ea, int32 prv); -extern t_bool lpmr (a10 ea, int32 prv); - -extern int32 pi_ub_vec (int32 lvl, int32 *uba); -extern UNIT tim_unit; - -d10 adjsp (d10 val, a10 ea); -void ibp (a10 ea, int32 pflgs); -d10 ldb (a10 ea, int32 pflgs); -void dpb (d10 val, a10 ea, int32 pflgs); -void adjbp (int32 ac, a10 ea, int32 pflgs); -d10 add (d10 val, d10 mb); -d10 sub (d10 val, d10 mb); -void dadd (int32 ac, d10 *rs); -void dsub (int32 ac, d10 *rs); -int32 jffo (d10 val); -d10 lsh (d10 val, a10 ea); -d10 rot (d10 val, a10 ea); -d10 ash (d10 val, a10 ea); -void lshc (int32 ac, a10 ea); -void rotc (int32 ac, a10 ea); -void ashc (int32 ac, a10 ea); -void circ (int32 ac, a10 ea); -void blt (int32 ac, a10 ea, int32 pflgs); -void bltu (int32 ac, a10 ea, int32 pflgs, int dir); -a10 calc_ea (d10 inst, int32 prv); -a10 calc_ioea (d10 inst, int32 prv); -d10 calc_jrstfea (d10 inst, int32 pflgs); -void pi_dismiss (void); -void set_newflags (d10 fl, t_bool jrst); -extern t_bool aprid (a10 ea, int32 prv); -t_bool wrpi (a10 ea, int32 prv); -t_bool rdpi (a10 ea, int32 prv); -t_bool czpi (a10 ea, int32 prv); -t_bool copi (a10 ea, int32 prv); -t_bool wrapr (a10 ea, int32 prv); -t_bool rdapr (a10 ea, int32 prv); -t_bool czapr (a10 ea, int32 prv); -t_bool coapr (a10 ea, int32 prv); - -static t_bool (*io700d[16])() = { - &aprid, NULL, NULL, NULL, &wrapr, &rdapr, &czapr, &coapr, - NULL, NULL, NULL, NULL, &wrpi, &rdpi, &czpi, &copi }; -static t_bool (*io701d[16])() = { - NULL, &rdubr, &clrpt, &wrubr, &wrebr, &rdebr, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }; -static t_bool (*io702d[16])() = { - &rdspb, &rdcsb, &rdpur, &rdcstm, &rdtim, &rdint, &rdhsb, NULL, - &wrspb, &wrcsb, &wrpur, &wrcstm, &wrtim, &wrint, &wrhsb, NULL }; -#define io700i io700d -static t_bool (*io701i[16])() = { - &clrcsh, &rdubr, &clrpt, &wrubr, &wrebr, &rdebr, NULL, NULL, - NULL, &rdpcst, NULL, &wrpcst, NULL, NULL, NULL, NULL }; -static t_bool (*io702i[16])() = { - &sdbr1, &sdbr2, &sdbr3, &sdbr4, &rdtim, &rdint, &rdhsb, &spm, - &ldbr1, &ldbr2, &ldbr3, &ldbr4, &wrtim, &wrint, &wrhsb, &lpmr }; -static t_stat jrst_tab[16] = { - JRST_U, JRST_U, JRST_U, 0, JRST_E, JRST_U, JRST_E, JRST_E, - JRST_UIO, 0, JRST_UIO, 0, JRST_E, JRST_U, 0, 0 }; - -d10 inst; a10 PC; -int32 pflgs; -int32 pager_flags = 0; /* pager: trap flags */ -t_bool pager_pi = FALSE; /* pager: in pi seq */ int abortval = 0; /* abort value */ -t_bool (*fptr)(); /* Restore register state */ pager_PC = PC = saved_PC & AMASK; /* load local PC */ set_dyn_ptrs (); /* set up local ptrs */ -pflgs = 0; /* not trap or PXCT */ +pager_tc = FALSE; /* not in trap cycle */ pager_pi = FALSE; /* not in pi sequence */ rlog = 0; /* not in extend */ pi_eval (); /* eval pi system */ -astop_cpu = 0; /* no addr stop */ sim_rtc_init (tim_unit.wait); /* init calibration */ +if (!ITS) its_1pr = 0; /* ~ITS, clr 1-proc */ /* Abort handling @@ -597,28 +597,32 @@ if ((abortval > 0) || pager_pi) { /* stop or pi err? */ if (pager_pi && (abortval == PAGE_FAIL)) abortval = STOP_PAGINT; /* stop for pi err */ saved_PC = pager_PC & AMASK; /* failing instr PC */ - last_inst = inst; /* last instr decoded */ set_ac_display (ac_cur); /* set up AC display */ return abortval; } /* return to SCP */ -/* Page fail - checked against KS10 ucode */ +/* Page fail - checked against KS10 ucode + All state variables MUST be declared global for GCC optimization to work +*/ else if (abortval == PAGE_FAIL) { /* page fail */ d10 mb; if (rlog) xtcln (rlog); /* clean up extend */ rlog = 0; /* clear log */ - if (pflgs & TRAP_CYCLE) flags = pager_flags; /* trap? get flags */ - if (!T20 || ITS) { /* TOPS-10 or ITS */ - a10 ea; - if (ITS) ea = epta + EPT_ITS_PAG + (pi_m2lvl[pi_act] * 3); + if (pager_tc) flags = pager_flags; /* trap? get flags */ + if (T20) { /* TOPS-20 */ + WriteP (upta + UPT_T20_PFL, pager_word);/* write page fail wd */ + WriteP (upta + UPT_T20_OFL, XWD (flags, 0)); + WriteP (upta + UPT_T20_OPC, pager_PC); + mb = ReadP (upta + UPT_T20_NPC); } + else { a10 ea; /* TOPS-10 or ITS */ + if (ITS) { /* ITS? */ + ea = epta + EPT_ITS_PAG + (pi_m2lvl[pi_act] * 3); + if (its_1pr) flags = flags | F_1PR; /* store 1-proc */ + its_1pr = 0; } /* clear 1-proc */ else ea = upta + UPT_T10_PAG; WriteP (ea, pager_word); /* write page fail wd */ WriteP (ADDA (ea, 1), XWD (flags, pager_PC)); mb = ReadP (ADDA (ea, 2)); } - else { WriteP (upta + UPT_T20_PFL, pager_word);/* write page fail wd */ - WriteP (upta + UPT_T20_OFL, XWD (flags, 0)); - WriteP (upta + UPT_T20_OPC, pager_PC); - mb = ReadP (upta + UPT_T20_NPC); } JUMP (mb); /* set new PC */ set_newflags (mb, FALSE); /* set new flags */ pi_eval (); } /* eval pi system */ @@ -627,14 +631,15 @@ else PC = pager_PC; /* intr, restore PC */ /* Main instruction fetch/decode loop: check clock queue, intr, trap, bkpt */ for ( ;; ) { /* loop until ABORT */ -int32 op, ac, i, st, xr, xct_cnt; +int32 op, ac, i, st, xr, xct_cnt, its_2pr, pflgs; a10 ea; -d10 mb, indrct, rs[2]; +d10 inst, mb, indrct, rs[2]; +t_bool (*fptr)(); pager_PC = PC; /* update pager PC */ -pflgs = 0; /* not in PXCT or trap */ +pager_tc = FALSE; /* not in trap cycle */ +pflgs = 0; /* not in PXCT */ xct_cnt = 0; /* count XCT's */ -if (astop_cpu) ABORT (STOP_ASTOP); /* address stop? */ if (sim_interval <= 0) { /* check clock queue */ if (i = sim_process_event ()) ABORT (i); /* error? stop sim */ pi_eval (); } /* eval pi system */ @@ -657,6 +662,9 @@ if (qintr) { else inst = ReadP (epta + EPT_PIIT + (2 * qintr)); op = GET_OP (inst); /* get opcode */ ac = GET_AC (inst); /* get ac */ + if (its_1pr && ITS) { /* 1-proc set? */ + flags = flags | F_1PR; /* store 1-proc */ + its_1pr = 0; } /* clear 1-proc */ if (op == OP_JSR) { /* JSR? */ ea = calc_ea (inst, MM_CUR); /* calc ea, cur mode */ WriteE (ea, FLPC); /* save flags+PC, exec */ @@ -688,7 +696,7 @@ if (qintr) { if (TSTF (F_T1 | F_T2) && PAGING) { Read (pager_PC = PC, MM_CUR); /* test fetch */ - pflgs = TRAP_CYCLE; /* in a trap sequence */ + pager_tc = TRUE; /* in a trap sequence */ pager_flags = flags; /* save flags */ ea = (TSTF (F_USR)? upta + UPT_TRBASE: epta + EPT_TRBASE) + GET_TRAPS (flags); @@ -697,10 +705,8 @@ if (TSTF (F_T1 | F_T2) && PAGING) { /* Test for instruction breakpoint */ -else { if (PC == ibkpt_addr) { /* breakpoint? */ - save_ibkpt = ibkpt_addr; /* save bkpt */ - ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */ - sim_activate (&cpu_unit, 1); /* sched re-enable */ +else { if (sim_brk_summ && + sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ ABORT (STOP_IBKPT); } /* stop simulation */ /* Ready (at last) to get an instruction */ @@ -709,6 +715,8 @@ else { if (PC == ibkpt_addr) { /* breakpoint? */ INCPC; sim_interval = sim_interval - 1; } +its_2pr = its_1pr; /* save 1-proc flag */ + /* Execute instruction. XCT and PXCT also return here. */ XCT: @@ -1240,7 +1248,8 @@ case 0725: IOA; io725 (AC(ac), ea); break; /* BCIOB, IOWRBQ */ */ default: -MUUO: if (T20) { /* TOPS20? */ +MUUO: its_2pr = 0; /* clear trap */ + if (T20) { /* TOPS20? */ int32 tf = (op << (INST_V_OP - 18)) | (ac << (INST_V_AC - 18)); WriteP (upta + UPT_MUUO, XWD ( /* store flags,,op+ac */ flags & ~(F_T2 | F_T1), tf)); /* traps clear */ @@ -1252,7 +1261,7 @@ MUUO: if (T20) { /* TOPS20? */ flags & ~(F_T2 | F_T1), PC)); /* traps clear */ WriteP (upta + UPT_T10_CTX, UBRWORD); } /* store context */ ea = upta + (TSTF (F_USR)? UPT_UNPC: UPT_ENPC) + - (pflgs & TRAP_CYCLE? UPT_NPCT: 0); /* calculate vector */ + (pager_tc? UPT_NPCT: 0); /* calculate vector */ mb = ReadP (ea); /* new flags, PC */ JUMP (mb); /* set new PC */ if (TSTF (F_USR)) mb = mb | XWD (F_UIO, 0); /* set PCU */ @@ -1325,6 +1334,15 @@ case 0254: /* JRST */ JUMP (Read (ea, MM_OPND)); /* jump to M[ea] */ break; } /* end case subop */ break; } /* end case op */ + +if (its_2pr) { /* 1-proc trap? */ + its_1pr = its_2pr = 0; /* clear trap */ + if (ITS) { /* better be ITS */ + WriteP (upta + UPT_1PO, FLPC); /* wr old flgs, PC */ + mb = ReadP (upta + UPT_1PN); /* rd new flgs, PC */ + JUMP (mb); /* set PC */ + set_newflags (mb, TRUE); } /* set new flags */ + } /* end if 2-proc */ } /* end for */ /* Should never get here */ @@ -1905,6 +1923,9 @@ int32 fl = (int32) LRZ (newf); if (jrst && TSTF (F_USR)) { /* if in user now */ fl = fl | F_USR; /* can't clear user */ if (!TSTF (F_UIO)) fl = fl & ~F_UIO; } /* if !UIO, can't set */ +if (ITS && (fl & F_1PR)) { /* ITS 1-proceed? */ + its_1pr = 1; /* set flag */ + fl = fl & ~F_1PR; } /* vanish bit */ flags = fl & F_MASK; /* set new flags */ set_dyn_ptrs (); /* set new ptrs */ return; @@ -2002,6 +2023,7 @@ return; t_stat cpu_reset (DEVICE *dptr) { flags = 0; /* clear flags */ +its_1pr = 0; /* clear 1-proceed */ ebr = ubr = 0; /* clear paging */ pi_enb = pi_act = pi_prq = 0; /* clear PI */ apr_enb = apr_flg = apr_lvl = 0; /* clear APR */ @@ -2013,7 +2035,8 @@ set_ac_display (ac_cur); pi_eval (); if (M == NULL) M = calloc (MAXMEMSIZE, sizeof (d10)); if (M == NULL) return SCPE_MEM; -return cpu_svc (&cpu_unit); +sim_brk_types = sim_brk_dflt = SWMASK ('E'); +return SCPE_OK; } /* Memory examine */ @@ -2043,15 +2066,6 @@ else { if (sw & SWMASK ('V')) { return SCPE_OK; } -/* Service breakpoint */ - -t_stat cpu_svc (UNIT *uptr) -{ -if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt) ibkpt_addr = save_ibkpt; -save_ibkpt = -1; -return SCPE_OK; -} - /* Set current AC pointers for SCP */ void set_ac_display (d10 *acbase) diff --git a/pdp10_defs.h b/PDP10/pdp10_defs.h similarity index 96% rename from pdp10_defs.h rename to PDP10/pdp10_defs.h index b0b0f3cb..767d356f 100644 --- a/pdp10_defs.h +++ b/PDP10/pdp10_defs.h @@ -379,11 +379,10 @@ typedef t_int64 d10; /* PDP-10 data (36b) */ There are only two real contexts for selecting the AC block and the memory map: current and previous. However, PXCT allows the choice of current versus previous to be made selectively for - various parts of an instruction. The PXCT flags (and the trap - in progress flag) are kept in a dynamic CPU variable. + various parts of an instruction. The PXCT flags are kept in a + dynamic CPU variable. */ -#define TRAP_CYCLE 040 /* trap in progress */ #define EA_PXCT 010 /* eff addr calc */ #define OPND_PXCT 004 /* operand, bdst */ #define EABP_PXCT 002 /* bp eff addr calc */ @@ -420,6 +419,8 @@ typedef t_int64 d10; /* PDP-10 data (36b) */ #define UPT_T20_UEA 0426 /* T20: address */ #define UPT_T20_CTX 0427 /* T20: context */ #define UPT_ENPC 0430 /* MUUO new PC, exec */ +#define UPT_1PO 0432 /* ITS 1-proc: old PC */ +#define UPT_1PN 0433 /* ITS 1-proc: new PC */ #define UPT_UNPC 0434 /* MUUO new PC, user */ #define UPT_NPCT 1 /* PC offset if trap */ #define UPT_T10_PAG 0500 /* T10: page fail blk */ diff --git a/PDP10/pdp10_doc.txt b/PDP10/pdp10_doc.txt new file mode 100644 index 00000000..1c9cf60c --- /dev/null +++ b/PDP10/pdp10_doc.txt @@ -0,0 +1,526 @@ +To: Users +From: Bob Supnik +Subj: PDP-10 Simulator Usage +Date: 1-Dec-01 + + COPYRIGHT NOTICE + +The following copyright notice applies to both the SIMH source and binary: + + Original code published in 1993-2001, written by Robert M Supnik + 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. + +This memorandum documents the PDP-10 simulator. + + +1. Simulator Files + +To compile the PDP-10, you must define USE_INT64 as part of the compilation +command line. + +sim/ sim_defs.h + sim_sock.h + sim_tmxr.h + dec_dz.h + scp.c + scp_tty.c + sim_rev.c + sim_sock.c + sim_tmxr.c + +sim/pdp10/ pdp10_defs.h + pdp10_cpu.c + pdp10_dz.c + pdp10_fe.c + pdp10_ksio.c + pdp10_lp20.c + pdp10_mdfp.c + pdp10_pag.c + pdp10_pt.c + pdp10_rp.c + pdp10_sys.c + pdp10_tu.c + pdp10_xtnd.c + +2. PDP-10 Features + +The PDP-10 simulator is configured as follows: + +device simulates +name(s) + +CPU KS10 CPU with 1MW of memory +PAG paging unit (translation maps) +UBA Unibus adapters (translation maps) +FE console +TIM timer +PTR,PTP PC11 paper tape reader/punch +DZ DZ11 8-line terminal multiplexor +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 DISABLEd. The DZ11 can also be DISABLEd. + +The PDP-10 simulator implements several unique stop condition: + + - illegal instruction (000) in kernel mode + - indirect addressing nesting exceeds limit + - execute chaining exceeds limit + - page fail or other error in interrupt sequence + - illegal instruction in interrupt sequence + - invalid vector pointer in interrupt sequence + - invalid Unibus adapter number + - non-existent exec or user page table address + +The PDP-10 loader supports RIM10B format paper tapes, SAV binary files, and +EXE binary files. LOAD switches -r, -s, -e specify RIM10, SAV, EXE format, +respectively. If no switch is specified, the LOAD command checks the file +extension; .RIM, .SAV, .EXE specify RIM10, SAV, EXE format, respectively. +If no switch specified, and no extension matches, the LOAD command checks +the file format to try to determine the file type. + +2.1 CPU + +The CPU options allow the user to specify standard microcode, standard +microcode with a bug fix for a boostrap problem in TOPS-20 V4.1, or ITS +microcode + + SET CPU STANDARD Standard microcode + SET CPU TOPS20V41 Standard microcode with TOPS-20 V4.1 bug fix + SET CPU ITS ITS compatible microcode + +CPU registers include the visible state of the processor as well as the +control registers for the interrupt system. + + name size comments + + PC 18 program counter + FLAGS 18 processor flags (<13:17> unused) + AC0..AC17 36 accumulators + IR 36 instruction register + EBR 18 executive base register + PGON 1 paging enabled flag + T20P 1 TOPS-20 paging + UBR 18 user base register + CURAC 3 current AC block + PRVAC 3 previous AC block + SPT 36 shared pointer table + CST 36 core status table + PUR 36 process update register + CSTM 36 CST mask + HSB 18 halt status block address + DBR1 18 descriptor base register 1 (ITS) + DBR2 18 descriptor base register 2 (ITS) + DBR3 18 descriptor base register 3 (ITS) + DBR4 18 descriptor base register 4 (ITS) + PIENB 7 PI levels enabled + PIACT 7 PI levels active + PIPRQ 7 PI levels with program requests + PIIOQ 7 PI levels with IO requests + PIAPR 7 PI levels with APR requests + APRENB 8 APR flags enabled + APRFLG 8 APR flags active + APRLVL 3 PI level for APR interrupt + IND_MAX 8 indirect address nesting limit + XCT_MAX 8 execute chaining limit + OLDPC 18 PC prior to last transfer instruction + WRU 8 interrupt character + REG[0:127] 36 fast memory blocks + +2.2 Pager + +The pager contains the page maps for executive and user mode. The +executive page map is the memory space for unit 0, the user page map the +memory space for unit 1. A page map entry is 32 bits wide and has the +following format: + + bit content + --- ------- + 31 page is writeable + 30 entry is valid + 29:19 mbz + 18:9 physical page base address + 8:0 mbz + +The pager has no registers. + +2.3 Unibus Adapters + +The Unibus adapters link the system I/O devices to the CPU. Unibus +adapter 1 (UBA1) is unit 0, and Unibus adapter 3 is unit 1. The +adapter's Unibus map is the memory space of the corresponding unit. + +The Unibus Adapter has the following registers: + + name size comments + + INTREQ 32 interrupt requests + UB1CS 16 Unibus adapter 1 control/status + UB3CS 16 Unibus adapter 3 control/status + +2.4 Front End (FE) + +The front end is the system console. The keyboard input is unit 0, +the console output is unit 1. It supports two options: + + SET FE STOP halts the PDP-10 operating system + SET FE CTLC simulates typing ^C (for Windoze) + +The front end has the following registers: + + name size comments + + IBUF 8 input buffer + ICOUNT 31 count of input characters + ITIME 24 keyboard polling interval + OBUF 8 output buffer + OCOUNT 31 count of output characters + OTIME 24 console output response time + +2.5 Timer (TIM) + +The timer (TIM) implements the system timer, the interval timer, and +the time of day clock used to get the date and time at system startup. +Because most PDP-10 software is not Y2K compliant, the timer implements +one option + + SET TIM NOY2K software not Y2K compliant, limit time + of day clock to 1999 (default) + SET TIM Y2K software is Y2K compliant + +The timer has the following registers: + + name size comments + + TIMBASE 59 time base (double precision) + TTG 36 time to go (remaining time) for interval + PERIOD 36 reset value for interval + QUANT 36 quantum timer (ITS only) + TIME 24 tick delay + DIAG 1 use fixed tick delay instead of autocalibration + +Unless the DIAG flag is set, the timer autocalibrates; the tick delay +is adjusted up or down so that the time base tracks actual elapsed time. +This may cause time-dependent diagnostics to report errors. + +2.6 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, +by changing POS, the user can backspace or advance the reader. + +The paper tape reader implements these registers: + + name size comments + + BUF 8 last data item processed + CSR 16 control/status register + INT 1 interrupt pending flag + ERR 1 error flag (CSR<15>) + BUSY 1 busy flag (CSR<11>) + DONE 1 device done flag (CSR<7>) + IE 1 interrupt enable flag (CSR<6>) + POS 31 position in the input file + TIME 24 time from I/O initiation to interrupt + 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 out of tape + + end of file 1 report error and stop + 0 out of tape + + OS I/O error x report error and stop + + +2.7 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. +Thus, by by changing POS, the user can backspace or advance the punch. + +The paper tape punch implements these registers: + + name size comments + + BUF 8 last data item processed + CSR 16 control/status register + 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>) + POS 31 position in the input or output file + TIME 24 time from I/O initiation to interrupt + 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 out of tape + + OS I/O error x report error and stop + +2.8 DZ11 Terminal Multiplexor (DZ) + +The DZ11 is an 8-line terminal multiplexor. 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: + + ATTACH {-am} DZ (cr) -- set up listening port + +where port is a decimal number between 1 and 65535 that is not being used +for other TCP/IP activities. The optional switch -m turns on the DZ11's +modem controls; the optional switch -a turns on active disconnects +(disconnect session if computer clears Data Terminal Ready). + +Once the DZ is attached and the simulator is running, the DZ will listen +for connections on the specified port. It assumes that the incoming +connections are Telnet connections. The connection remains open until +disconnected either by the simulated program or by the Telnet client. + +The SHOW DZ LINESTATUS command displays the current connections to the DZ. + +The DZ11 implements these registers: + + name size comments + + CSR 16 control/status register + RBUF 16 receive buffer + LPR 16 line parameter register + TCR 16 transmission control register + MSR 16 modem status register + TDR 16 transmit data register + SAENB 1 silo alarm enabled + MDMTCL 1 modem control enabled + AUTODS 1 autodisconnect enabled + RPOS0..7 32 count of characters received + TPOS0..7 32 count of characters transmitted + +The DZ11 does not support save and restore. All open connections are +lost when the simulator shuts down or the DZ is detached. + +2.9 RH11 Adapter, RM02/03/05/80, RP04/05/06/07 drives (RP) + +The RP controller implements the Massbus 18b (RH11) 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: + + SET RPn LOCKED set unit n write locked + SET RPn ENABLED set unit n write enabled + SET RPn RM03 set type to RM03 + SET RPn RM05 set type to RM05 + SET RPn RM80 set type to RM80 + SET RPn RP04 set type to RP04 + SET RPn RP06 set type to RP06 + SET RPn RP07 set type to RP07 + SET RPn AUTOSIZE set type based on file size at attach + +The type options can be used only when a unit is not attached to a file. +Note that TOPS-10 V7.03 only supported the RP06 and RM03; V7.04 added +support for the RP07. Units can be REMOVEd or ADDed to the configuration. + +The RP controller implements these registers: + + name size comments + + RPCS1 16 control/status 1 + RPWC 16 word count + RPBA 16 bus address + RPDA 16 desired surface, sector + RPCS2 16 control/status 2 + 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 + RPER2 16 error status 2 + RPER3 16 error status 3 + RPEC1 16 ECC syndrome 1 + RPEC2 16 ECC syndrome 2 + RPMR 16 maintenance register + RPDB 16 data buffer + IFF 1 transfer complete interrupt request flop + INT 1 interrupt pending flag + SC 1 special condition (CSR1<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.10 RH11 Adapter, TM02 Formatter, TU45 Magnetic Tape (TU) + +The magnetic tape simulator simulates an RH11 Massbus adapter with one +TM02 formatter and up to eight TU45 drives. Magnetic tape options include +the ability to make units write enabled or locked. + + SET TUn LOCKED set unit n write locked + SET TUn ENABLED set unit n write enabled + +Units can also be REMOVEd or ADDed to the configuration. + +The magnetic tape controller implements these registers: + + name size comments + + MTCS1 16 control/status 1 + MTBA 16 memory address + MTWC 16 word count + MTFC 16 frame count + MTCS2 16 control/status 2 + MTFS 16 formatter status + MTER 16 error status + MTCC 16 check character + MTDB 16 data buffer + MTMR 16 maintenance register + MTTC 16 tape control register + INT 1 interrupt pending flag + DONE 1 device done flag + IE 1 interrupt enable flag + STOP_IOE 1 stop on I/O error + TIME 24 delay + UST[0:7] 16 unit status, units 0-7 + POS[0:7] 31 position, units 0-7 + +Error handling is as follows: + + error processed as + + not attached tape not ready + + end of file (read or space) end of physical tape + (write) ignored + + OS I/O error report error and stop + +2.11 LP20 DMA Line Printer (LP20) + +The LP20 is a DMA-based line printer controller. There is one +line printer option to clear the vertical forms unit (VFU). + + SET LP20 VFUCLEAR clear the vertical forms unit + +The LP20 implements these registers: + + name size comments + + LPCSA 16 control/status register A + LPCSB 16 control/status register B + LPBA 16 bus address register + LPBC 12 byte count register + LPPAGC 12 page count register + LPRDAT 12 RAM data register + LPCBUF 8 character buffer register + LPCOLC 8 column counter register + LPPDAT 8 printer data register + LPCSUM 8 checksum register + DVPTR 7 vertical forms unit pointer + DVLNT 7 vertical forms unit length + INT 1 interrupt request + ERR 1 error flag + DONE 1 done flag + IE 1 interrupt enable flag + POS 31 position in output file + TIME 24 response time + STOP_IOE 1 stop on I/O error + TXRAM[0:255] 12 translation RAM + DAVFU[0:142] 12 vertical forms unit array + +Error handling is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 out of paper + + OS I/O error x report error and stop + +2.12 Symbolic Display and Input + +The PDP-10 simulator implements symbolic display and input. Display is +controlled by command line switches: + + -a display as ASCII character + -c display as (sixbit) character string + -p display as packed (seven bit) string + -m display instruction mnemonics + -v interpret address as virtual + -e force executive mode + -u force user mode + +Input parsing is controlled by the first character typed in or by command +line switches: + + ' or -a ASCII character + " or -c sixbit string + # or -p packed seven bit string + alphabetic instruction mnemonic + numeric octal number + +Instruction input uses standard PDP-10 assembler syntax. There are three +instruction classes: memory reference, memory reference with AC, and I/O. + +Memory reference instructions have the format + + memref {@}address{(index)} + +memory reference with AC instructions have the format + + memac ac,{@}address{(index)} + +and I/O instructions have the format + + io device,{@}address{(index)} + +where @ signifies indirect. The address is a signed octal number in the +range 0 - 0777777. The ac and index are unsigned octal numbers in the +range 0-17. The device is either a recognized device mnemonic (APR, PI, +TIM) or an octal number in the range 0 - 0177. + +The simulator recognizes the standard MACRO alternate mnemonics (CLEAR +for SETZ, OR for IORI), the individual definitions for JRST and JFCL +variants, and the extended instruction mnemonics. diff --git a/pdp10_dz.c b/PDP10/pdp10_dz.c similarity index 100% rename from pdp10_dz.c rename to PDP10/pdp10_dz.c diff --git a/pdp10_fe.c b/PDP10/pdp10_fe.c similarity index 91% rename from pdp10_fe.c rename to PDP10/pdp10_fe.c index 859a77f2..9ba9cc30 100644 --- a/pdp10_fe.c +++ b/PDP10/pdp10_fe.c @@ -25,6 +25,7 @@ fe KS10 console front end + 30-Nov-01 RMS Added extended SET/SHOW support 23-Oct-01 RMS New IO page address constants 07-Sep-01 RMS Moved function prototypes */ @@ -37,8 +38,8 @@ extern int32 apr_flg; t_stat fei_svc (UNIT *uptr); t_stat feo_svc (UNIT *uptr); t_stat fe_reset (DEVICE *dptr); -t_stat fe_stop_os (UNIT *uptr, int32 val); -t_stat fe_ctrl_c (UNIT *uptr, int32 val); +t_stat fe_stop_os (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat fe_ctrl_c (UNIT *uptr, int32 val, char *cptr, void *desc); /* FE data structures @@ -146,7 +147,7 @@ return SCPE_OK; /* Stop operating system */ -t_stat fe_stop_os (UNIT *uptr, int32 val) +t_stat fe_stop_os (UNIT *uptr, int32 val, char *cptr, void *desc) { M[FE_SWITCH] = IOBA_RP; /* tell OS to stop */ return SCPE_OK; @@ -154,7 +155,7 @@ return SCPE_OK; /* Enter control-C for Windoze */ -t_stat fe_ctrl_c (UNIT *uptr, int32 val) +t_stat fe_ctrl_c (UNIT *uptr, int32 val, char *cptr, void *desc) { fei_unit.buf = 003; /* control-C */ M[FE_CTYIN] = fei_unit.buf | FE_CVALID; /* put char in mem */ diff --git a/pdp10_ksio.c b/PDP10/pdp10_ksio.c similarity index 100% rename from pdp10_ksio.c rename to PDP10/pdp10_ksio.c diff --git a/pdp10_lp20.c b/PDP10/pdp10_lp20.c similarity index 96% rename from pdp10_lp20.c rename to PDP10/pdp10_lp20.c index 41be1783..3d2eced3 100644 --- a/pdp10_lp20.c +++ b/PDP10/pdp10_lp20.c @@ -24,6 +24,8 @@ in this Software without prior written authorization from Robert M Supnik. lp20 line printer + + 30-Nov-01 RMS Added extended SET/SHOW support */ #include "pdp10_defs.h" @@ -152,7 +154,7 @@ t_stat lp20_svc (UNIT *uptr); t_stat lp20_reset (DEVICE *dptr); t_stat lp20_attach (UNIT *uptr, char *ptr); t_stat lp20_detach (UNIT *uptr); -t_stat lp20_clear_vfu (UNIT *uptr, int32 arg); +t_stat lp20_clear_vfu (UNIT *uptr, int32 val, char *cptr, void *desc); t_bool lp20_print (int32 c); t_bool lp20_adv (int32 c, t_bool advdvu); t_bool lp20_davfu (int32 c); @@ -570,7 +572,7 @@ update_lpcs (CSA_MBZ); return reason; } -t_stat lp20_clear_vfu (UNIT *uptr, int32 arg) +t_stat lp20_clear_vfu (UNIT *uptr, int32 val, char *cptr, void *desc) { int i; diff --git a/pdp10_mdfp.c b/PDP10/pdp10_mdfp.c similarity index 100% rename from pdp10_mdfp.c rename to PDP10/pdp10_mdfp.c diff --git a/pdp10_pag.c b/PDP10/pdp10_pag.c similarity index 96% rename from pdp10_pag.c rename to PDP10/pdp10_pag.c index dfac99d4..924b7d3b 100644 --- a/pdp10_pag.c +++ b/PDP10/pdp10_pag.c @@ -25,6 +25,7 @@ pag KS10 pager + 02-Dec-01 RMS Fixed bug in ITS LPMR (found by Dave Conroy) 21-Aug-01 RMS Fixed bug in ITS paging (found by Miriam Lennox) Removed register from declarations 19-May-01 RMS Added workaround for TOPS-20 V4.1 boot bug @@ -754,6 +755,7 @@ val = Read (ADDA (ea, 2), prv); dbr1 = (a10) (Read (ea, prv) & AMASK); dbr2 = (a10) (Read (ADDA (ea, 1), prv) & AMASK); quant = val; +pag_reset (&pag_dev); return FALSE; } diff --git a/pdp10_pt.c b/PDP10/pdp10_pt.c similarity index 95% rename from pdp10_pt.c rename to PDP10/pdp10_pt.c index 0183b6b4..224b3b51 100644 --- a/pdp10_pt.c +++ b/PDP10/pdp10_pt.c @@ -26,6 +26,7 @@ ptr paper tape reader ptp paper tape punch + 29-Nov-01 RMS Added read only unit support 07-Sep-01 RMS Revised disable mechanism */ @@ -59,7 +60,8 @@ t_stat ptp_detach (UNIT *uptr); */ UNIT ptr_unit = { - UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_IN_WAIT }; + UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), + SERIAL_IN_WAIT }; REG ptr_reg[] = { { ORDATA (CSR, ptr_csr, 16) }, diff --git a/pdp10_rp.c b/PDP10/pdp10_rp.c similarity index 91% rename from pdp10_rp.c rename to PDP10/pdp10_rp.c index 41e7eed2..b471acfd 100644 --- a/pdp10_rp.c +++ b/PDP10/pdp10_rp.c @@ -25,6 +25,8 @@ rp RH/RP/RM moving head disks + 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 New IO page address constants 05-Oct-01 RMS Rewrote interrupt handling from schematics @@ -75,9 +77,10 @@ #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_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 */ /* Parameters in the unit descriptor */ @@ -338,7 +341,7 @@ int reg_in_drive[32] = { void update_rpcs (int32 flags, int32 drv); void rp_go (int32 drv, int32 fnc); -t_stat rp_set_size (UNIT *uptr, int32 value); +t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat rp_svc (UNIT *uptr); t_stat rp_reset (DEVICE *dptr); t_stat rp_boot (int32 unitno); @@ -355,21 +358,21 @@ t_stat rp_detach (UNIT *uptr); UNIT rp_unit[] = { { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - (RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, + UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - (RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, + UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - (RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, + UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - (RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, + UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - (RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, + UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - (RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, + UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - (RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, + UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - (RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) } }; + UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) } }; REG rp_reg[] = { { ORDATA (RPCS1, rpcs1, 16) }, @@ -377,6 +380,8 @@ REG rp_reg[] = { { ORDATA (RPBA, rpba, 16) }, { ORDATA (RPDA, rpda, 16) }, { ORDATA (RPCS2, rpcs2, 16) }, + { BRDATA (RPDS, rpds, 8, 16, RP_NUMDR) }, + { BRDATA (RPER1, rper1, 8, 16, RP_NUMDR) }, { ORDATA (RPOF, rpof, 16) }, { ORDATA (RPDC, rpdc, 16) }, { ORDATA (RPER2, rper2, 16) }, @@ -392,46 +397,11 @@ REG rp_reg[] = { { FLDATA (IE, rpcs1, CSR_V_IE) }, { DRDATA (STIME, rp_swait, 24), REG_NZ + PV_LEFT }, { DRDATA (RTIME, rp_rwait, 24), REG_NZ + PV_LEFT }, - { ORDATA (RPDS0, rpds[0], 16) }, - { ORDATA (RPDS1, rpds[1], 16) }, - { ORDATA (RPDS2, rpds[2], 16) }, - { ORDATA (RPDS3, rpds[3], 16) }, - { ORDATA (RPDS4, rpds[4], 16) }, - { ORDATA (RPDS5, rpds[5], 16) }, - { ORDATA (RPDS6, rpds[6], 16) }, - { ORDATA (RPDS7, rpds[7], 16) }, - { ORDATA (RPDE0, rper1[0], 16) }, - { ORDATA (RPDE1, rper1[1], 16) }, - { ORDATA (RPDE2, rper1[2], 16) }, - { ORDATA (RPDE3, rper1[3], 16) }, - { ORDATA (RPDE4, rper1[4], 16) }, - { ORDATA (RPDE5, rper1[5], 16) }, - { ORDATA (RPDE6, rper1[6], 16) }, - { ORDATA (RPDE7, rper1[7], 16) }, - { ORDATA (RPFN0, rp_unit[0].FUNC, 5), REG_HRO }, - { ORDATA (RPFN1, rp_unit[1].FUNC, 5), REG_HRO }, - { ORDATA (RPFN2, rp_unit[2].FUNC, 5), REG_HRO }, - { ORDATA (RPFN3, rp_unit[3].FUNC, 5), REG_HRO }, - { ORDATA (RPFN4, rp_unit[4].FUNC, 5), REG_HRO }, - { ORDATA (RPFN5, rp_unit[5].FUNC, 5), REG_HRO }, - { ORDATA (RPFN6, rp_unit[6].FUNC, 5), REG_HRO }, - { ORDATA (RPFN7, rp_unit[7].FUNC, 5), REG_HRO }, - { GRDATA (FLG0, rp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG1, rp_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG2, rp_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG3, rp_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG4, rp_unit[4].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG5, rp_unit[5].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG6, rp_unit[6].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG7, rp_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, + { 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) }, { NULL } }; @@ -828,7 +798,7 @@ case FNC_SEEK: /* seek */ #define XBA_MBZ 0000003 /* addr<1:0> must be 0 */ case FNC_WRITE: /* write */ - if (uptr -> flags & UNIT_WLK) { /* 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; } @@ -978,7 +948,7 @@ for (i = 0; i < RP_NUMDR; 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_WLK)? DS_WRL: 0); + 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; } @@ -997,7 +967,7 @@ 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_WLK)? DS_WRL: 0); + ((uptr -> flags & UNIT_WPRT)? DS_WRL: 0); rper1[drv] = 0; update_rpcs (CS1_SC, drv); @@ -1032,10 +1002,10 @@ return detach_unit (uptr); /* Set size command validation routine */ -t_stat rp_set_size (UNIT *uptr, int32 value) +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 (value)].size; +uptr -> capac = drv_tab[GET_DTYPE (val)].size; return SCPE_OK; } diff --git a/pdp10_sys.c b/PDP10/pdp10_sys.c similarity index 100% rename from pdp10_sys.c rename to PDP10/pdp10_sys.c diff --git a/pdp10_tim.c b/PDP10/pdp10_tim.c similarity index 94% rename from pdp10_tim.c rename to PDP10/pdp10_tim.c index 6d23f21f..5ac77977 100644 --- a/pdp10_tim.c +++ b/PDP10/pdp10_tim.c @@ -25,6 +25,7 @@ tim timer subsystem + 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 17-Jul-01 RMS Moved function prototype 04-Jul-01 RMS Added DZ11 support @@ -142,8 +143,8 @@ if (ttg <= 0) { /* timeout? */ if (ITS) { /* ITS? */ if (pi_act == 0) quant = (quant + TIM_HWRE) & DMASK; if (TSTS (pcst)) { /* PC sampling? */ - pcst = AOB (pcst); /* add 1,,1 */ - WriteP ((a10) pcst & AMASK, pager_PC); } + WriteP ((a10) pcst & AMASK, pager_PC); /* store sample */ + pcst = AOB (pcst); } /* add 1,,1 */ } /* end ITS */ return SCPE_OK; } diff --git a/pdp10_tu.c b/PDP10/pdp10_tu.c similarity index 91% rename from pdp10_tu.c rename to PDP10/pdp10_tu.c index b2b9b2e6..f5a6987a 100644 --- a/pdp10_tu.c +++ b/PDP10/pdp10_tu.c @@ -25,6 +25,8 @@ tu RH11/TM03/TU45 magtape + 30-Nov-01 RMS Added read only unit, extended SET/SHOW support + 24-Nov-01 RMS Changed POS, FLG, UST to arrays 23-Oct-01 RMS Fixed bug in error interrupts New IO page address constants 05-Oct-01 RMS Rewrote interrupt handling from schematics @@ -74,6 +76,7 @@ #define UDENS u4 /* unit density */ #define UD_UNK 0 /* unknown */ #define XBUFLNT (1 << 16) /* max data buf */ +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ /* MTCS1 - 172440 - control/status 1 */ @@ -300,7 +303,7 @@ t_stat tu_detach (UNIT *uptr); t_stat tu_boot (int32 unitno); void tu_go (int32 drv); void update_tucs (int32 flag, int32 drv); -t_stat tu_vlock (UNIT *uptr, int32 val); +t_stat tu_vlock (UNIT *uptr, int32 val, char *cptr, void *desc); /* TU data structures @@ -311,14 +314,14 @@ t_stat tu_vlock (UNIT *uptr, int32 val); */ UNIT tu_unit[] = { - { UDATA (&tu_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&tu_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&tu_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&tu_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&tu_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&tu_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&tu_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&tu_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) } }; + { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) } }; REG tu_reg[] = { { ORDATA (MTCS1, tucs1, 16) }, @@ -338,38 +341,11 @@ REG tu_reg[] = { { FLDATA (IE, tucs1, CSR_V_IE) }, { FLDATA (STOP_IOE, tu_stopioe, 0) }, { DRDATA (TIME, tu_time, 24), PV_LEFT }, - { ORDATA (UST0, tu_unit[0].USTAT, 17) }, - { ORDATA (UST1, tu_unit[1].USTAT, 17) }, - { ORDATA (UST2, tu_unit[2].USTAT, 17) }, - { ORDATA (UST3, tu_unit[3].USTAT, 17) }, - { ORDATA (UST4, tu_unit[4].USTAT, 17) }, - { ORDATA (UST5, tu_unit[5].USTAT, 17) }, - { ORDATA (UST6, tu_unit[6].USTAT, 17) }, - { ORDATA (UST7, tu_unit[7].USTAT, 17) }, - { DRDATA (POS0, tu_unit[0].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS1, tu_unit[1].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS2, tu_unit[2].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS3, tu_unit[3].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS4, tu_unit[4].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS5, tu_unit[5].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS6, tu_unit[6].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS7, tu_unit[7].pos, 31), PV_LEFT + REG_RO }, - { GRDATA (FLG0, tu_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG1, tu_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG2, tu_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG3, tu_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG4, tu_unit[4].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG5, tu_unit[5].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG6, tu_unit[6].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG7, tu_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, + { URDATA (UST, tu_unit[0].USTAT, 8, 17, 0, TU_NUMDR, 0) }, + { URDATA (POS, tu_unit[0].pos, 8, 31, 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 } }; @@ -630,7 +606,7 @@ case FNC_WRITE: /* write */ break; } case FNC_WREOF: /* write tape mark */ case FNC_ERASE: /* erase */ - if (uptr -> flags & UNIT_WLK) { /* write locked? */ + if (uptr -> flags & UNIT_WPRT) { /* write locked? */ tuer = tuer | ER_NXF; break; } case FNC_WCHKF: /* wchk = read */ @@ -902,7 +878,7 @@ if (GET_FMTR (tucs2) == 0) { /* formatter present? */ if (tu_unit[drv].flags & UNIT_ATT) { tufs = tufs | FS_MOL | tu_unit[drv].USTAT; if (tu_unit[drv].UDENS == TC_1600) tufs = tufs | FS_PE; - if (tu_unit[drv].flags & UNIT_WLK) tufs = tufs | FS_WRL; + if (tu_unit[drv].flags & UNIT_WPRT) tufs = tufs | FS_WRL; if ((tu_unit[drv].pos == 0) && !act) tufs = tufs | FS_BOT; } if (tuer) tufs = tufs | FS_ERR; } else tufs = 0; @@ -984,7 +960,7 @@ return detach_unit (uptr); /* Write lock/enable routine */ -t_stat tu_vlock (UNIT *uptr, int32 val) +t_stat tu_vlock (UNIT *uptr, int32 val, char *cptr, void *desc) { if (sim_is_active (uptr)) return SCPE_ARG; return SCPE_OK; diff --git a/pdp10_xtnd.c b/PDP10/pdp10_xtnd.c similarity index 100% rename from pdp10_xtnd.c rename to PDP10/pdp10_xtnd.c diff --git a/pdp11_cis.c b/PDP11/pdp11_cis.c similarity index 100% rename from pdp11_cis.c rename to PDP11/pdp11_cis.c diff --git a/pdp11_cpu.c b/PDP11/pdp11_cpu.c similarity index 86% rename from pdp11_cpu.c rename to PDP11/pdp11_cpu.c index cb5f76a4..d8acf5d3 100644 --- a/pdp11_cpu.c +++ b/PDP11/pdp11_cpu.c @@ -25,6 +25,11 @@ cpu PDP-11 CPU (J-11 microprocessor) + 25-Dec-01 RMS Cleaned up sim_inst declarations + 11-Dec-01 RMS Moved interrupt debug code + 07-Dec-01 RMS Revised to use new breakpoint package + 08-Nov-01 RMS Moved I/O to external module + 26-Oct-01 RMS Revised to use symbolic definitions for IO page 15-Oct-01 RMS Added debug logging 08-Oct-01 RMS Fixed bug in revised interrupt logic 07-Sep-01 RMS Revised device disable and interrupt mechanisms @@ -168,39 +173,41 @@ 4. Adding I/O devices. This requires modifications to three modules: pdp11_defs.h add interrupt request definitions - pdp11_cpu.c add I/O page linkages + pdp11_io.c add I/O page linkages pdp11_sys.c add to sim_devices */ /* Definitions */ #include "pdp11_defs.h" -#include -#define calc_is(md) ((md) << VA_V_MODE) -#define calc_ds(md) (calc_is((md)) | ((MMR3 & dsmask[(md)])? VA_DS: 0)) -#define calc_MMR1(val) (MMR1 = MMR1? ((val) << 8) | MMR1: (val)) -#define GET_SIGN_W(v) ((v) >> 15) -#define GET_SIGN_B(v) ((v) >> 7) -#define GET_Z(v) ((v) == 0) -#define JMP_PC(x) old_PC = PC; PC = (x) -#define BRANCH_F(x) old_PC = PC; PC = (PC + (((x) + (x)) & 0377)) & 0177777 -#define BRANCH_B(x) old_PC = PC; PC = (PC + (((x) + (x)) | 0177400)) & 0177777 -#define ILL_ADR_FLAG 0200000 -#define save_ibkpt (cpu_unit.u3) /* will be SAVEd */ -#define last_pa (cpu_unit.u4) /* and RESTOREd */ +#define calc_is(md) ((md) << VA_V_MODE) +#define calc_ds(md) (calc_is((md)) | ((MMR3 & dsmask[(md)])? VA_DS: 0)) +#define calc_MMR1(val) (MMR1 = MMR1? ((val) << 8) | MMR1: (val)) +#define GET_SIGN_W(v) ((v) >> 15) +#define GET_SIGN_B(v) ((v) >> 7) +#define GET_Z(v) ((v) == 0) +#define JMP_PC(x) old_PC = PC; PC = (x) +#define BRANCH_F(x) old_PC = PC; PC = (PC + (((x) + (x)) & 0377)) & 0177777 +#define BRANCH_B(x) old_PC = PC; PC = (PC + (((x) + (x)) | 0177400)) & 0177777 +#define last_pa (cpu_unit.u4) /* auto save/rest */ #define UNIT_V_18B (UNIT_V_UF) /* force 18b addr */ +#define UNIT_V_UBM (UNIT_V_UF + 1) /* bus map present */ +#define UNIT_V_RH11 (UNIT_V_UF + 2) /* RH11 Massbus */ +#define UNIT_V_CIS (UNIT_V_UF + 3) /* CIS present */ +#define UNIT_V_MSIZE (UNIT_V_UF + 4) /* dummy */ #define UNIT_18B (1u << UNIT_V_18B) -#define UNIT_V_CIS (UNIT_V_UF + 1) /* CIS present */ +#define UNIT_UBM (1u << UNIT_V_UBM) +#define UNIT_RH11 (1u << UNIT_V_RH11) #define UNIT_CIS (1u << UNIT_V_CIS) -#define UNIT_V_MSIZE (UNIT_V_UF + 2) /* dummy */ #define UNIT_MSIZE (1u << UNIT_V_MSIZE) +#define UNIT_MAP (UNIT_18B | UNIT_UBM | UNIT_RH11) /* Global state */ extern FILE *sim_log; -uint16 *M = NULL; /* address of memory */ +uint16 *M = NULL; /* memory */ int32 REGFILE[6][2] = { 0 }; /* R0-R5, two sets */ int32 STACKFILE[4] = { 0 }; /* SP, four modes */ int32 saved_PC = 0; /* program counter */ @@ -227,34 +234,36 @@ int32 MMR0 = 0; /* MMR0 - status */ int32 MMR1 = 0; /* MMR1 - R+/-R */ int32 MMR2 = 0; /* MMR2 - saved PC */ int32 MMR3 = 0; /* MMR3 - 22b status */ +int32 ub_map[UBM_LNT_LW] = { 0 }; /* Unibus map array */ +int32 cpu_bme = 0; /* bus map enable */ +int32 cpu_18b = 0; /* 18b CPU config'd */ +int32 cpu_ubm = 0; /* bus map config'd */ +int32 cpu_rh11 = 0; /* RH11 config'd */ int32 isenable = 0, dsenable = 0; /* i, d space flags */ int32 CPUERR = 0; /* CPU error reg */ int32 MEMERR = 0; /* memory error reg */ int32 CCR = 0; /* cache control reg */ int32 HITMISS = 0; /* hit/miss reg */ -int32 MAINT = (0 << 9) + (0 << 8) + (4 << 4); /* maint bit<9> = Q/U */ - /* <8> = hwre FP */ - /* <6:4> = sys type */ +int32 MAINT = MAINT_Q | MAINT_NOFPA | MAINT_KDJ; /* maint reg */ int32 stop_trap = 1; /* stop on trap */ int32 stop_vecabort = 1; /* stop on vec abort */ int32 stop_spabort = 1; /* stop on SP abort */ int32 wait_enable = 0; /* wait state enable */ -int32 pdp11_log = 0; /* logging */ -int32 ibkpt_addr = ILL_ADR_FLAG | VAMASK; /* breakpoint addr */ +int32 cpu_log = 0; /* logging */ int32 old_PC = 0; /* previous PC */ int32 dev_enb = (-1) & ~INT_TS; /* dev enables */ jmp_buf save_env; /* abort handler */ int32 dsmask[4] = { MMR3_KDS, MMR3_SDS, 0, MMR3_UDS }; /* dspace enables */ extern int32 sim_int_char; +extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ /* Function declarations */ 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_svc (UNIT *uptr); -t_stat cpu_set_size (UNIT *uptr, int32 value); +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); int32 GeteaB (int32 spec); int32 GeteaW (int32 spec); int32 relocR (int32 addr); @@ -267,103 +276,14 @@ void WriteW (int32 data, int32 addr); void WriteB (int32 data, int32 addr); void PWriteW (int32 data, int32 addr); void PWriteB (int32 data, int32 addr); -t_stat iopageR (int32 *data, int32 addr, int32 access); -t_stat iopageW (int32 data, int32 addr, int32 access); -int32 calc_ints (int32 nipl, int32 trq); - -t_stat CPU_rd (int32 *data, int32 addr, int32 access); t_stat CPU_wr (int32 data, int32 addr, int32 access); -t_stat APR_rd (int32 *data, int32 addr, int32 access); -t_stat APR_wr (int32 data, int32 addr, int32 access); -t_stat SR_MMR012_rd (int32 *data, int32 addr, int32 access); -t_stat SR_MMR012_wr (int32 data, int32 addr, int32 access); -t_stat MMR3_rd (int32 *data, int32 addr, int32 access); -t_stat MMR3_wr (int32 data, int32 addr, int32 access); -extern t_stat std_rd (int32 *data, int32 addr, int32 access); -extern t_stat std_wr (int32 data, int32 addr, int32 access); -extern t_stat lpt_rd (int32 *data, int32 addr, int32 access); -extern t_stat lpt_wr (int32 data, int32 addr, int32 access); -extern t_stat dz_rd (int32 *data, int32 addr, int32 access); -extern t_stat dz_wr (int32 data, int32 addr, int32 access); -extern t_stat rk_rd (int32 *data, int32 addr, int32 access); -extern t_stat rk_wr (int32 data, int32 addr, int32 access); -extern int32 rk_inta (void); -extern int32 rk_enb; -/* extern t_stat hk_rd (int32 *data, int32 addr, int32 access); -extern t_stat hk_wr (int32 data, int32 addr, int32 access); -extern int32 hk_inta (void); -extern int32 hk_enb; */ -extern t_stat rl_rd (int32 *data, int32 addr, int32 access); -extern t_stat rl_wr (int32 data, int32 addr, int32 access); -extern int32 rl_enb; -extern t_stat rp_rd (int32 *data, int32 addr, int32 access); -extern t_stat rp_wr (int32 data, int32 addr, int32 access); -extern int32 rp_inta (void); -extern int32 rp_enb; -extern t_stat rx_rd (int32 *data, int32 addr, int32 access); -extern t_stat rx_wr (int32 data, int32 addr, int32 access); -extern int32 rx_enb; -extern t_stat dt_rd (int32 *data, int32 addr, int32 access); -extern t_stat dt_wr (int32 data, int32 addr, int32 access); -extern int32 dt_enb; -extern t_stat tm_rd (int32 *data, int32 addr, int32 access); -extern t_stat tm_wr (int32 data, int32 addr, int32 access); -extern int32 tm_enb; -extern t_stat ts_rd (int32 *data, int32 addr, int32 access); -extern t_stat ts_wr (int32 data, int32 addr, int32 access); -extern int32 ts_enb; - -/* Auxiliary data structures */ -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 */ +extern t_stat iopageR (int32 *data, int32 addr, int32 access); +extern t_stat iopageW (int32 data, int32 addr, int32 access); +extern int32 calc_ints (int32 nipl, int32 trq); +extern int32 get_vector (int32 nipl); -struct iolink iotable[] = { - { 017777740, 017777777, NULL, &CPU_rd, &CPU_wr }, - { 017777546, 017777567, NULL, &std_rd, &std_wr }, - { 017777514, 017777517, NULL, &lpt_rd, &lpt_wr }, - { 017760100, 017760107, NULL, &dz_rd, &dz_wr }, - { 017777400, 017777417, &rk_enb, &rk_rd, &rk_wr }, -/* { 017777440, 017777477, &hk_enb, &hk_rd, &hk_wr }, */ - { 017774400, 017774411, &rl_enb, &rl_rd, &rl_wr }, - { 017776700, 017776753, &rp_enb, &rp_rd, &rp_wr }, - { 017777170, 017777173, &rx_enb, &rx_rd, &rx_wr }, - { 017777340, 017777351, &dt_enb, &dt_rd, &dt_wr }, - { 017772520, 017772533, &tm_enb, &tm_rd, &tm_wr }, - { 017772520, 017772523, &ts_enb, &ts_rd, &ts_wr }, - { 017777600, 017777677, NULL, &APR_rd, &APR_wr }, - { 017772200, 017772377, NULL, &APR_rd, &APR_wr }, - { 017777570, 017777577, NULL, &SR_MMR012_rd, &SR_MMR012_wr }, - { 017772516, 017772517, NULL, &MMR3_rd, &MMR3_wr }, - { 0, 0, NULL, NULL, 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_HK, 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, NULL }, - { NULL }, /* IPL 6 */ - { NULL } }; /* IPL 7 */ +/* Trap data structures */ int32 trap_vec[TRAP_V_MAX] = { /* trap req to vector */ VEC_RED, VEC_ODD, VEC_MME, VEC_NXM, @@ -390,7 +310,7 @@ int32 trap_clear[TRAP_V_MAX] = { /* trap clears */ cpu_mod CPU modifier list */ -UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK, INIMEMSIZE) }; +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, INIMEMSIZE) }; REG cpu_reg[] = { { ORDATA (PC, saved_PC, 16) }, @@ -434,7 +354,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, pdp11_log, 16), REG_HIDDEN }, + { ORDATA (DBGLOG, cpu_log, 16), REG_HIDDEN }, { ORDATA (FAC0H, FR[0].h, 32) }, { ORDATA (FAC0L, FR[0].l, 32) }, { ORDATA (FAC1H, FR[1].h, 32) }, @@ -550,19 +470,23 @@ REG cpu_reg[] = { { GRDATA (UDPDR6, APRFILE[076], 8, 16, 0) }, { 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 }, { ORDATA (OLDPC, old_PC, 16), REG_RO }, - { ORDATA (BREAK, ibkpt_addr, 17) }, { ORDATA (WRU, sim_int_char, 8) }, { ORDATA (DEVENB, dev_enb, 32), REG_HRO }, { NULL} }; MTAB cpu_mod[] = { - { UNIT_18B, UNIT_18B, "18b addressing", "18B", NULL }, - { UNIT_18B, 0, NULL, "22B", NULL }, + { 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_CIS, UNIT_CIS, "CIS", "CIS", NULL }, - { UNIT_CIS, 0, "No CIS", "NOCIS", NULL }, + { UNIT_CIS, 0, "no CIS", "NOCIS", NULL }, { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size}, { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size}, { UNIT_MSIZE, 49152, NULL, "48K", &cpu_set_size}, @@ -595,11 +519,8 @@ t_stat sim_instr (void) extern int32 sim_interval; extern UNIT *sim_clock_queue; extern UNIT clk_unit; -int32 IR, srcspec, srcreg, dstspec, dstreg; -int32 src, src2, dst; -int32 i, j, t, sign, oldrs, trapnum; -int32 abortval; -volatile int32 trapea; +int abortval, i; +volatile int32 trapea; /* needed at longjmp */ t_stat reason; void fp11 (int32 IR); void cis11 (int32 IR); @@ -631,7 +552,11 @@ isenable = calc_is (cm); dsenable = calc_ds (cm); CPU_wr (PIRQ, 017777772, WRITE); /* rewrite PIRQ */ -trap_req = calc_ints (ipl, trap_req); +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_rtc_init (clk_unit.wait); /* init clock */ @@ -668,41 +593,37 @@ if (abortval != 0) { */ while (reason == 0) { -if (sim_interval <= 0) { /* check clock queue */ - reason = sim_process_event (); - trap_req = calc_ints (ipl, trap_req); - continue; } + +int32 IR, srcspec, srcreg, dstspec, dstreg; +int32 src, src2, dst; +int32 i, t, sign, oldrs, trapnum; + +if (sim_interval <= 0) { /* intv cnt expired? */ + reason = sim_process_event (); /* process events */ + trap_req = calc_ints (ipl, trap_req); /* recalc int req */ + continue; + } /* end if sim_interval */ + if (trap_req) { /* check traps, ints */ trapea = 0; /* assume srch fails */ if (t = trap_req & TRAP_ALL) { /* if a trap */ - for (trapnum = 0; trapnum < TRAP_V_MAX; trapnum++) { - if ((t >> trapnum) & 1) { - trapea = trap_vec[trapnum]; + for (trapnum = 0; trapnum < TRAP_V_MAX; trapnum++) { + if ((t >> trapnum) & 1) { /* trap set? */ + trapea = trap_vec[trapnum]; /* get vec, clr */ trap_req = trap_req & ~trap_clear[trapnum]; - if ((stop_trap >> trapnum) & 1) - reason = trapnum + 1; - break; } /* end if t & 1 */ - } /* end for */ - } /* end if */ - else { - for (i = IPL_HLVL - 1; (trapea == 0) && (i > ipl); i--) { - t = int_req[i]; /* get level */ - for (j = 0; t && (j < 32); j++) { /* srch level */ - if ((t >> j) & 1) { /* irq found? */ - int_req[i] = int_req[i] & ~(1u << j); - if (int_ack[i][j]) trapea = int_ack[i][j](); - else trapea = int_vec[i][j]; - trapnum = TRAP_V_MAX; - if (DBG_LOG (LOG_CPU_I)) fprintf (sim_log, - ">>CPU, lvl=%d, flag=%d, vec=%o\n", - i, j, trapea); - break; } /* end if t & 1 */ - } /* end for j */ - } /* end for i */ - } /* end else */ + if ((stop_trap >> trapnum) & 1) /* stop on trap? */ + reason = trapnum + 1; + break; + } /* end if t & 1 */ + } /* end for */ + } /* end if t */ + else { trapea = get_vector (ipl); /* get int vector */ + trapnum = TRAP_V_MAX; /* defang stk trap */ + } /* end else t*/ if (trapea == 0) { /* nothing to do? */ trap_req = calc_ints (ipl, 0); /* recalculate */ - continue; } /* back to fetch */ + continue; /* back to fetch */ + } /* end if trapea */ /* Process a trap or interrupt @@ -761,10 +682,7 @@ if (wait_state) { /* wait state? */ else reason = STOP_WAIT; continue; } -if (PC == ibkpt_addr) { /* breakpoint? */ - save_ibkpt = ibkpt_addr; /* save bkpt */ - ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */ - sim_activate (&cpu_unit, 1); /* sched re-enable */ +if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ reason = STOP_IBKPT; /* stop simulation */ continue; } @@ -2090,56 +2008,6 @@ else { pa = va & 0177777; /* mmgt off */ return pa; } -/* I/O page lookup and linkage routines - - Inputs: - *data = pointer to data to read, if READ - data = data to store, if WRITE or WRITEB - pa = address - access = READ, WRITE, or WRITEB - Outputs: - status = SCPE_OK or SCPE_NXM -*/ - -t_stat iopageR (int32 *data, int32 pa, int32 access) -{ -t_stat stat; -struct iolink *p; - -for (p = &iotable[0]; p -> low != 0; p++ ) { - if ((pa >= p -> low) && (pa <= p -> high) && - ((p -> enb == NULL) || *p -> enb)) { - stat = p -> read (data, pa, access); - trap_req = calc_ints (ipl, trap_req); - return stat; } } -return SCPE_NXM; -} - -t_stat iopageW (int32 data, int32 pa, int32 access) -{ -t_stat stat; -struct iolink *p; - -for (p = &iotable[0]; p -> low != 0; p++ ) { - if ((pa >= p -> low) && (pa <= p -> high) && - ((p -> enb == NULL) || *p -> enb)) { - stat = p -> write (data, pa, access); - trap_req = calc_ints (ipl, trap_req); - return stat; } } -return SCPE_NXM; -} - -/* Calculate interrupt outstanding */ - -int32 calc_ints (int32 nipl, int32 trq) -{ -int32 i; - -for (i = IPL_HLVL - 1; i > nipl; i--) { - if (int_req[i]) return (trq | TRAP_INT); } -return (trq & ~TRAP_INT); -} - /* I/O page routines for CPU registers Switch register and memory management registers @@ -2196,6 +2064,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); dsenable = calc_ds (cm); return SCPE_OK; } @@ -2269,8 +2138,9 @@ case 2: /* MEMERR */ case 3: /* CCR */ *data = CCR; return SCPE_OK; -case 4: /* MAint */ - *data = MAINT; +case 4: /* MAINT */ + if (cpu_ubm) *data = MAINT | MAINT_U; + else *data = MAINT | MAINT_Q; return SCPE_OK; case 5: /* Hit/miss */ *data = HITMISS; @@ -2378,14 +2248,19 @@ return SCPE_NXM; /* unimplemented */ t_stat cpu_reset (DEVICE *dptr) { +int32 i; + PIRQ = MMR0 = MMR1 = MMR2 = MMR3 = 0; +cpu_bme = 0; DR = CPUERR = MEMERR = CCR = HITMISS = 0; PSW = 000340; trap_req = 0; wait_state = 0; if (M == NULL) M = calloc (MEMSIZE >> 1, sizeof (unsigned int16)); if (M == NULL) return SCPE_MEM; -return cpu_svc (&cpu_unit); +for (i = 0; i < UBM_LNT_LW; i++) ub_map[i] = 0; +sim_brk_types = sim_brk_dflt = SWMASK ('E'); +return SCPE_OK; } /* Memory examine */ @@ -2423,34 +2298,25 @@ if (addr < MEMSIZE) { if (addr < IOPAGEBASE) return SCPE_NXM; return iopageW ((int32) val, addr, WRITEC); } - -/* Breakpoint service */ - -t_stat cpu_svc (UNIT *uptr) -{ -if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt) ibkpt_addr = save_ibkpt; -save_ibkpt = -1; -return SCPE_OK; -} /* Memory allocation */ -t_stat cpu_set_size (UNIT *uptr, int32 value) +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { int32 mc = 0; t_addr i, clim; unsigned int16 *nM = NULL; -if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 07777) != 0)) +if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0)) return SCPE_ARG; -for (i = value; i < MEMSIZE; i = i + 2) mc = mc | M[i >> 1]; +for (i = val; i < MEMSIZE; i = i + 2) mc = mc | M[i >> 1]; if ((mc != 0) && !get_yn ("Really truncate memory [N]?", FALSE)) return SCPE_OK; -nM = calloc (value >> 1, sizeof (unsigned int16)); +nM = calloc (val >> 1, sizeof (unsigned int16)); if (nM == NULL) return SCPE_MEM; -clim = (((t_addr) value) < MEMSIZE)? value: MEMSIZE; +clim = (((t_addr) val) < MEMSIZE)? val: MEMSIZE; for (i = 0; i < clim; i = i + 2) nM[i >> 1] = M[i >> 1]; free (M); M = nM; -MEMSIZE = value; +MEMSIZE = val; return SCPE_OK; } diff --git a/pdp11_defs.h b/PDP11/pdp11_defs.h similarity index 71% rename from pdp11_defs.h rename to PDP11/pdp11_defs.h index 4e1a0464..bbf43606 100644 --- a/pdp11_defs.h +++ b/PDP11/pdp11_defs.h @@ -26,6 +26,9 @@ The author gratefully acknowledges the help of Max Burnet, Megan Gentry, and John Wilson in resolving questions about the PDP-11 + 09-Nov-01 RMS Added bus map support + 07-Nov-01 RMS Added RQDX3 support + 26-Oct-01 RMS Added symbolic definitions for IO page 19-Oct-01 RMS Added DZ definitions 15-Oct-01 RMS Added logging capabilities 07-Sep-01 RMS Revised for multilevel interrupts @@ -46,6 +49,7 @@ #define INIMEMSIZE 001000000 /* 2**18 */ #define IOPAGEBASE 017760000 /* 2**22 - 2**13 */ #define MAXMEMSIZE 020000000 /* 2**22 */ +#define PAMASK (MAXMEMSIZE - 1) /* 2**22 - 1 */ #define MEMSIZE (cpu_unit.capac) #define ADDR_IS_MEM(x) (((t_addr) (x)) < MEMSIZE) #define DMASK 0177777 @@ -146,6 +150,16 @@ #define VA_V_MODE 17 /* offset to mode */ #define VA_DS (1u << VA_V_DS) /* data space flag */ +/* Unibus map (if present) */ + +#define UBM_LNT_LW 32 /* size in LW */ +#define UBM_V_PN 13 /* page number */ +#define UBM_M_PN 037 +#define UBM_V_OFF 0 /* offset */ +#define UBM_M_OFF 017777 +#define UBM_GETPN(x) (((x) >> UBM_V_PN) & UBM_M_PN) +#define UBM_GETOFF(x) ((x) & UBM_M_OFF) + /* CPUERR */ #define CPUE_RED 0004 /* red stack */ @@ -156,6 +170,17 @@ #define CPUE_HALT 0200 /* HALT not kernel */ #define CPUE_IMP 0374 /* implemented bits */ +/* Maintenance register */ + +#define MAINT_V_UQ 9 /* Q/U flag */ +#define MAINT_Q (0 << MAINT_V_UQ) /* Qbus */ +#define MAINT_U (1 << MAINT_V_UQ) +#define MAINT_V_FPA 8 /* FPA flag */ +#define MAINT_NOFPA (0 << MAINT_V_FPA) +#define MAINT_FPA (1 << MAINT_V_FPA) +#define MAINT_V_TYP 4 /* system type */ +#define MAINT_KDJ (4 << MAINT_V_TYP) + /* Floating point accumulators */ struct fpac { @@ -233,11 +258,12 @@ typedef struct fpac fpac_t; /* Simulator stop codes; codes 1:TRAP_V_MAX correspond to traps 0:TRAPMAX-1 */ -#define STOP_HALT TRAP_V_MAX + 1 /* HALT instruction */ -#define STOP_IBKPT TRAP_V_MAX + 2 /* instruction bkpt */ -#define STOP_WAIT TRAP_V_MAX + 3 /* wait, no events */ -#define STOP_VECABORT TRAP_V_MAX + 4 /* abort vector read */ -#define STOP_SPABORT TRAP_V_MAX + 5 /* abort trap push */ +#define STOP_HALT (TRAP_V_MAX + 1) /* HALT instruction */ +#define STOP_IBKPT (TRAP_V_MAX + 2) /* instruction bkpt */ +#define STOP_WAIT (TRAP_V_MAX + 3) /* wait, no events */ +#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 IORETURN(f,v) ((f)? (v): SCPE_OK) /* cond error return */ /* DZ11 parameters */ @@ -245,6 +271,45 @@ typedef struct fpac fpac_t; #define DZ_MUXES 1 /* # of muxes */ #define DZ_LINES 8 /* lines per mux */ +/* I/O page layout */ + +#define IOBA_DZ (IOPAGEBASE + 000100) /* DZ11 */ +#define IOLN_DZ (010 * DZ_MUXES) +#define IOBA_UBM (IOPAGEBASE + 010200) /* Unibus map */ +#define IOLN_UBM (UBM_LNT_LW * sizeof (int32)) +#define IOBA_RQ (IOPAGEBASE + 012150) /* RQDX3 */ +#define IOLN_RQ 004 +#define IOBA_APR (IOPAGEBASE + 012200) /* APRs */ +#define IOLN_APR 0200 +#define IOBA_MMR3 (IOPAGEBASE + 012516) /* MMR3 */ +#define IOLN_MMR3 002 +#define IOBA_TM (IOPAGEBASE + 012520) /* TM11 */ +#define IOLN_TM 014 +#define IOBA_TS (IOPAGEBASE + 012520) /* TS11 */ +#define IOLN_TS 004 +#define IOBA_RL (IOPAGEBASE + 014400) /* RL11 */ +#define IOLN_RL 012 +#define IOBA_RP (IOPAGEBASE + 016700) /* RP/RM */ +#define IOLN_RP 054 +#define IOBA_RX (IOPAGEBASE + 017170) /* RX11 */ +#define IOLN_RX 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_LPT (IOPAGEBASE + 017514) /* LP11 */ +#define IOLN_LPT 004 +#define IOBA_STD (IOPAGEBASE + 017546) /* KW11L, DL11, PC11 */ +#define IOLN_STD 022 +#define IOBA_SRMM (IOPAGEBASE + 017570) /* SR, MMR0-2 */ +#define IOLN_SRMM 010 +#define IOBA_APR1 (IOPAGEBASE + 017600) /* APRs */ +#define IOLN_APR1 0100 +#define IOBA_CPU (IOPAGEBASE + 017740) /* CPU reg */ +#define IOLN_CPU 040 + /* Interrupt assignments; within each level, priority is right to left */ #define IPL_HLVL 8 /* # int levels */ @@ -262,9 +327,10 @@ typedef struct fpac fpac_t; #define INT_V_RP 4 #define INT_V_TS 5 #define INT_V_HK 6 -#define INT_V_DZRX 7 -#define INT_V_DZTX 8 -#define INT_V_PIR5 9 +#define INT_V_RQ 7 +#define INT_V_DZRX 8 +#define INT_V_DZTX 9 +#define INT_V_PIR5 10 #define INT_V_TTI 0 /* BR4 */ #define INT_V_TTO 1 @@ -287,7 +353,8 @@ typedef struct fpac fpac_t; #define INT_TM (1u << INT_V_TM) #define INT_RP (1u << INT_V_RP) #define INT_TS (1u << INT_V_TS) -#define INT_HK (1u << INT_V_HK) +#define INT_RK6 (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_PIR5 (1u << INT_V_PIR5) @@ -309,7 +376,8 @@ typedef struct fpac fpac_t; #define IPL_TM 5 #define IPL_RP 5 #define IPL_TS 5 -#define IPL_HK 5 +#define IPL_RK6 5 +#define IPL_RQ 5 #define IPL_DZRX 5 #define IPL_DZTX 5 #define IPL_PTR 4 @@ -326,16 +394,18 @@ typedef struct fpac fpac_t; #define IPL_PIR2 2 #define IPL_PIR1 1 -#define VEC_PIRQ 0240 /* interrupt vectors */ +#define VEC_Q 0000 /* vector base */ +#define VEC_PIRQ 0240 #define VEC_TTI 0060 #define VEC_TTO 0064 #define VEC_PTR 0070 #define VEC_PTP 0074 #define VEC_CLK 0100 -#define VEC_LPT 0200 -#define VEC_HK 0210 -#define VEC_RK 0220 +#define VEC_RQ 0154 #define VEC_RL 0160 +#define VEC_LPT 0200 +#define VEC_RK6 0210 +#define VEC_RK 0220 #define VEC_DTA 0214 #define VEC_TM 0224 #define VEC_TS 0224 @@ -347,15 +417,15 @@ typedef struct fpac fpac_t; /* Interrupt macros */ #define IREQ(dv) int_req[IPL_##dv] -#define SET_INT(dv) IREQ(dv) = IREQ(dv) | (INT_##dv) -#define CLR_INT(dv) IREQ(dv) = IREQ(dv) & ~(INT_##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) /* CPU and FPU macros */ -#define update_MM ((MMR0 & (MMR0_FREEZE + MMR0_MME)) == MMR0_MME) -#define setTRAP(name) trap_req = trap_req | (name) -#define setCPUERR(name) CPUERR = CPUERR | (name) -#define ABORT(val) longjmp (save_env, (val)) +#define update_MM ((MMR0 & (MMR0_FREEZE + MMR0_MME)) == MMR0_MME) +#define setTRAP(name) trap_req = trap_req | (name) +#define setCPUERR(name) CPUERR = CPUERR | (name) +#define ABORT(val) longjmp (save_env, (val)) #define SP R[6] #define PC R[7] @@ -364,9 +434,21 @@ typedef struct fpac fpac_t; #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 DBG_LOG(x) (sim_log && (pdp11_log & (x))) +#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); diff --git a/PDP11/pdp11_doc.txt b/PDP11/pdp11_doc.txt new file mode 100644 index 00000000..f1fa1c93 --- /dev/null +++ b/PDP11/pdp11_doc.txt @@ -0,0 +1,868 @@ +To: Users +From: Bob Supnik +Subj: PDP-11 Simulator Usage +Date: 1-Dec-01 + + COPYRIGHT NOTICE + +The following copyright notice applies to both the SIMH source and binary: + + Original code published in 1993-2001, written by Robert M Supnik + 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. + +This memorandum documents the PDP-11 simulator. + + +1. Simulator Files + +sim/ sim_defs.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_sock.c + sim_tmxr.c + +sim/pdp11/ pdp11_defs.h + pdp11_cpu.c + pdp11_dz.c + pdp11_fp.c + pdp11_io.c + pdp11_lp.c + pdp11_rk.c + pdp11_rl.c + pdp11_rp.c + pdp11_rq.c + pdp11_rx.c + pdp11_stddev.c + pdp11_sys.c + pdp11_tc.c + pdp11_tm.c + pdp11_ts.c + +2. PDP-11 Features + +The PDP-11 simulator is configured as follows: + +device simulates +name(s) + +CPU J-11 CPU with 256KB of memory +- FP11 floating point unit (FPA) +- CIS11 commercial instruction set (CIS, off by default) +PTR,PTP PC11 paper tape reader/punch +TTI,TTO DL11 console terminal +LPT LP11 line printer +CLK line frequency clock +DZ DZ11 8-line terminal multiplexor +RK RK11/RK05 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 +RX RX11/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 + +The DZ, RK, RL, RP, RQ, RX, TC, TM, and TS devices can be DISABLEd. 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, + + ENABLE TM11 enable TM11 and disable TS11 + ENABLE TS11 enable TS11 and disable TM11 + +The PDP-11 simulator implements several unique stop conditions: + + - abort during exception vector fetch, and register STOP_VEC is set + - abort during exception stack push, and register STOP_SPA is set + - trap condition 'n' occurs, and register STOP_TRAP is set + - wait state entered, and no I/O operations outstanding + (ie, no interrupt can ever occur) + +The PDP-11 loader supports standard binary format tapes. The DUMP command +is not implemented. + +2.1 CPU + +The CPU options include CPU mapping configuration (18b Unibus, 22b Unibus +with RH70-style controllers, 22b Unibus with RH11 style controllers, and +22b Qbus), the CIS instruction set, and the size of main memory. + + SET CPU 18B 18b addressing, no I/O map + SET CPU URH11 22b addresssing, Unibus I/O map, + 18b mapped RH11 controller + SET CPU URH70 22b addressing, Unibus I/O map, + 22b unmapped RH70 controller + SET CPU 22B 22b addressing, no I/O map (Qbus) + SET CPU NOCIS disable CIS instructions (default) + SET CPU CIS enable CIS instructions + SET CPU 16K set memory size = 16KB + SET CPU 32K set memory size = 32KB + SET CPU 48K set memory size = 48KB + SET CPU 64K set memory size = 64KB + SET CPU 96K set memory size = 96KB + SET CPU 128K set memory size = 128KB + SET CPU 192K set memory size = 192KB + SET CPU 256K set memory size = 256KB + SET CPU 384K set memory size = 384KB + SET CPU 512K set memory size = 512KB + SET CPU 768K set memory size = 768KB + SET CPU 1024K (or 1M) set memory size = 1024KB + 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 + +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. + +These switches are recognized when examining or depositing in CPU memory: + + -v interpret address as virtual + -d if mem mgt enabled, force data space + -k if mem mgt enabled, force kernel mode + -s if mem mgt enabled, force supervisor mode + -u if mem mgt enabled, force user mode + -p if mem mgt enabled, force previous mode + +CPU registers include the visible state of the processor as well as the +control registers for the interrupt system. + + name size comments + + PC 16 program counter + R0..R5 16 R0..R5, first register set + R10..R15 16 R0..R5, second register set + KSP 16 kernel stack pointer + SSP 16 supervisor stack pointer + USP 16 user stack pointer + PSW 16 processor status word + CM 2 current mode, PSW<15:14> + PM 2 previous mode, PSW<13:12> + RS 2 register set, PSW<11> + IPL 3 interrupt priority level, PSW<7:5> + T 1 trace bit, PSW<4> + N 1 negative flag, PSW<3> + Z 1 zero flag, PSW<2> + V 1 overflow flag, PSW<1> + C 1 carry flag, PSW<0> + SR 16 front panel switches + DR 16 front panel display + MEMERR 16 memory error register + CCR 16 cache control register + MAINT 16 maintenance register + HITMISS 16 hit/miss register + CPUERR 16 CPU error register + PIRQ 16 programmed interrupt requests + FAC0H..FAC5H 32 FAC0..FAC5, high 32 bits + FAC0L..FAC5L 32 FAC0..FAC5, low 32 bits + FPS 16 floating point status + FEA 16 floating exception address + FEC 4 floating exception code + MMR0..3 16 memory management registers 0..3 + {K/S/U}{I/D}{PAR/PDR}{0..7} + 16 memory management registers + UBMAP[0:63] 16 Unibus map registers + INT 32 interrupt pending flags + TRAP 18 trap pending flags + WAIT 0 wait state flag + WAIT_ENABLE 0 wait state enable flag + STOP_TRAPS 18 stop on trap flags + STOP_VECA 1 stop on read abort in trap or interrupt + STOP_SPA 1 stop on stack push abort in trap or interrupt + OLDPC 16 PC prior to last JMP, JMS, or interrupt + WRU 8 interrupt character + +2.2 Programmed I/O Devices + +2.2.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, +by changing POS, the user can backspace or advance the reader. + +The paper tape reader implements these registers: + + name size comments + + BUF 8 last data item processed + CSR 16 control/status register + INT 1 interrupt pending flag + ERR 1 error flag (CSR<15>) + BUSY 1 busy flag (CSR<11>) + DONE 1 device done flag (CSR<7>) + IE 1 interrupt enable flag (CSR<6>) + POS 31 position in the input file + TIME 24 time from I/O initiation to interrupt + 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 out of tape + + end of file 1 report error and stop + 0 out of tape + + OS I/O error x report error and stop + +2.2.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. +Thus, by by changing POS, the user can backspace or advance the punch. + +The paper tape punch implements these registers: + + name size comments + + BUF 8 last data item processed + CSR 16 control/status register + 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>) + POS 31 position in the output file + TIME 24 time from I/O initiation to interrupt + 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 out of tape + + OS I/O error x report error and stop + +2.2.3 DL11 Terminal Input (TTI) + +The terminal input (TTI) polls the console keyboard for input. It +implements these registers: + + name size comments + + BUF 8 last data item processed + CSR 16 control/status register + 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>) + POS 31 number of characters input + TIME 24 keyboard polling interval + +2.2.4 DL11 Terminal Output (TTO) + +The terminal output (TTO) writes to the simulator console window. It +implements these registers: + + name size comments + + BUF 8 last data item processed + CSR 16 control/status register + 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>) + POS 31 number of characters input + TIME 24 time from I/O initiation to interrupt + +2.2.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, +by changing POS, the user can backspace or advance the printer. + +The line printer implements these registers: + + name size comments + + BUF 8 last data item processed + CSR 16 control/status register + 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>) + POS 31 position in the output file + TIME 24 time from I/O initiation to interrupt + 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 out of paper + + OS I/O error x report error and stop + +2.2.6 Line-Time Clock (CLK) + +The clock (CLK) implements these registers: + + name size comments + + CSR 16 control/status register + INT 1 interrupt pending flag + DONE 1 device done flag (CSR<7>) + IE 1 interrupt enable flag (CSR<6>) + TIME 24 clock frequency + TPS 8 ticks per second (60 or 50) + +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) + +The DZ11 is an 8-line terminal multiplexor. 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: + + ATTACH {-am} DZ (cr) -- set up listening port + +where port is a decimal number between 1 and 65535 that is not being used +for other TCP/IP activities. The optional switch -m turns on the DZ11's +modem controls; the optional switch -a turns on active disconnects +(disconnect session if computer clears Data Terminal Ready). + +Once the DZ is attached and the simulator is running, the DZ will listen +for connections on the specified port. It assumes that the incoming +connections are Telnet connections. The connection remains open until +disconnected either by the simulated program or by the Telnet client. + +The SHOW DZ LINESTATUS command displays the current connections to the DZ. + +The DZ11 implements these registers: + + name size comments + + CSR 16 control/status register + RBUF 16 receive buffer + LPR 16 line parameter register + TCR 16 transmission control register + MSR 16 modem status register + TDR 16 transmit data register + SAENB 1 silo alarm enabled + MDMTCL 1 modem control enabled + AUTODS 1 autodisconnect enabled + RPOS0..7 32 count of characters received + TPOS0..7 32 count of characters transmitted + +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) + +RK11 options include the ability to make units write enabled or write locked: + + SET RKn LOCKED set unit n write locked + SET RKn ENABLED set unit n write enabled + +Units can also be REMOVEd or ADDed to the configuration. 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: + + SET RXn LOCKED set unit n write locked + SET RXn ENABLED set unit n write enabled + +The RX11 supports the BOOT command. + +The RX11 implements these registers: + + name size comments + + RXCS 12 status + RXDB 8 data buffer + RXES 8 error status + RXERR 8 error code + RXTA 8 current track + RXSA 8 current sector + STAPTR 3 controller state + BUFPTR 3 buffer pointer + 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:127] 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 + +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) + +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 ENABLED set unit n write enabled + SET RLn RL01 set size to RL01 + SET RLn RL02 set size to RL02 + 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 REMOVEd or ADDed to the configuration. The RL11 supports the +BOOT command. + +The RL11 implements these registers: + + name size comments + + RLCS 16 control/status + RLDA 16 disk address + RLBA 16 memory address + RLBAE 6 memory address extension (RLV12) + RLMP..RLMP2 16 multipurpose register queue + 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>) + 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.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. + +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 ENABLED set unit n write enabled + SET RPn RM03 set type to RM03 + SET RPn RM05 set type to RM05 + SET RPn RM80 set type to RM80 + SET RPn RP04 set type to RP04 + SET RPn RP06 set type to RP06 + SET RPn RP07 set type to RP07 + SET RPn AUTOSIZE set type based on file size at attach + SET RPn BADBLOCK write bad block table on 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 REMOVEd or ADDed to the configuration. The RP controller supports +the BOOT command. + +The RP controller implements these registers: + + name size comments + + RPCS1 16 control/status 1 + RPWC 16 word count + RPBA 16 bus address + RPDA 16 desired surface, sector + RPCS2 16 control/status 2 + 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 + RPER2 16 error status 2 + RPER3 16 error status 3 + RPEC1 16 ECC syndrome 1 + RPEC2 16 ECC syndrome 2 + RPMR 16 maintenance register + RPDB 16 data buffer + RPBAE 6 bus address extension + RPCS3 16 control/status 3 + IFF 1 transfer complete interrupt request flop + INT 1 interrupt pending flag + SC 1 special condition (CSR1<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.7 RQDX3 MSCP Disk Controller (RQ) + +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: + + SET RQn LOCKED set unit n write locked + SET RQn ENABLED set unit n write enabled + SET RQn RX50 set type to RX50 + SET RQn RX33 set type to RX33 + SET RQn RD51 set type to RD51 + SET RQn RD52 set type to RD52 + SET RQn RD53 set type to RD53 + SET RQn RD54 set type to RD54 + SET RQn RD31 set type to RD31 + SET RQn RA82 set type to RA82 + SET RQn RA72 set type to RA72 + SET RQn RA90 set type to RA90 + SET RQn RA92 set type to RA92 + +The type options can be used only when a unit is not attached to a file. +Units can also be REMOVEd or ADDed to the configuration. The RQ controller +supports the BOOT command. + +The RQ controller implements the following special SHOW commands: + + SHOW RQ RINGS show command and response rings + SHOW RQ FREEQ show packet free queue + SHOW RQ RESPQ show packet response queue + SHOW RQ UNITQ show unit queues + SHOW RQ ALL show all ring and queue state + SHOW RQn UNITQ show unit queues for unit n + +The RQ 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 16 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 + INT 1 interrupt request + 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 disk not ready + + end of file assume rest of disk is zero + + OS I/O error report error and stop + +2.8 TC11/TU56 DECtape (DT) + +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 LOCKED set unit n write locked + SET DTn ENABLED set unit n write enabled + +Units can also be REMOVEd or ADDed to the configuration. The TC11 supports +the BOOT command. + +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: + + -f foreign (PDP-8) format + -n native (PDP-9/11/15) 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 + + TCST 16 status register + TCCM 16 command register + TCWC 16 word count register + TCBA 16 bus address register + TCDT 16 data register + INT 1 interrupt pending flag + ERR 1 error flag + DONE 1 done flag + IE 1 interrupt enable flag + CTIME 31 time to complete transport stop + 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] 31 position, in lines, units 0-7 + STATT[0-7] 31 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.9 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 ENABLED set unit n write enabled + +Units can also be REMOVEd or ADDed to the configuration. + +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. + +The magnetic tape controller implements these registers: + + name size comments + + MTS 16 status + MTC 16 command + MTCMA 16 memory address + MTBRC 16 byte/record count + INT 1 interrupt pending flag + ERR 1 error flag + DONE 1 device done flag + IE 1 interrupt enable flag + STOP_IOE 1 stop on I/O error + TIME 24 delay + UST[0:7] 16 unit status, units 0-7 + POS[0:7] 31 position, units 0-7 + +Error handling is as follows: + + error processed as + + not attached tape not ready + + end of file (read or space) end of physical tape + (write) ignored + + OS I/O error report error and stop + +2.10 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 +write enabled or write locked. + + SET TS LOCKED set unit write locked + SET TS ENABLED 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. + +The magnetic tape controller implements these registers: + + name size comments + + TSSR 16 status register + TSBA 16 bus address register + TSDBX 16 data buffer extension register + CHDR 16 command packet header + CADL 16 command packet low address or count + CADH 16 command packet high address + CLNT 16 command packet length + MHDR 16 message packet header + MRFC 16 message packet residual frame count + MXS0 16 message packet extended status 0 + MXS1 16 message packet extended status 1 + MXS2 16 message packet extended status 2 + MXS3 16 message packet extended status 3 + MXS4 16 message packet extended status 4 + WADL 16 write char packet low address + WADH 16 write char packet high address + WLNT 16 write char packet length + WOPT 16 write char packet options + WXOPT 16 write char packet extended options + ATTN 1 attention message pending + BOOT 1 boot request pending + OWNC 1 if set, tape owns command buffer + OWNM 1 if set, tape owns message buffer + TIME 24 delay + POS 31 position + +Error handling is as follows: + + error processed as + + not attached tape not ready + + end of file (read or space) end of physical tape + (write) ignored + + OS I/O error fatal tape error + +2.11 Symbolic Display and Input + +The PDP-11 simulator implements symbolic display and input. Display is +controlled by command line switches: + + -a display as ASCII character + -c display as two character ASCII string + -m display instruction mnemonics + +Input parsing is controlled by the first character typed in or by command +line switches: + + ' or -a ASCII character + " or -c two character ASCII string + alphabetic instruction mnemonic + numeric octal number + +Instruction input uses standard PDP-11 assembler syntax. There are sixteen +instruction classes: + +class operands examples comments + +no operands none HALT, RESET +3b literal literal, 0 - 7 SPL +6b literal literal, 0 - 077 MARK +8b literal literal, 0 - 0377 EMT, TRAP +register register RTS +sop specifier SWAB, CLR, ASL +reg-sop register, specifier JSR, XOR, MUL +fop flt specifier ABSf, NEGf +ac-fop flt reg, flt specifier LDf, MULf +ac-sop flt reg, specifier LDEXP, STEXP +ac-moded sop flt reg, specifier LDCif, STCfi +dop specifier, specifier MOV, ADD, BIC +cond branch address BR, BCC, BNE +sob register, address SOB +cc clear cc clear instructions CLC, CLV, CLZ, CLN combinable +cc set cc set instructions SEC, SEV, SEZ, SEN combinable + +For floating point opcodes, F and D variants, and I and L variants, may be +specified regardless of the state of FPS. + +The syntax for specifiers is as follows: + +syntax specifier displacement comments + +Rn 0n - +Fn 0n - only in flt reg classes +(Rn) 1n - +@(Rn) 7n 0 equivalent to @0(Rn) +(Rn)+ 2n - +@(Rn)+ 3n - +-(Rn) 4n - +@-(Rn) 5n - +{+/-}d(Rn) 6n {+/-}d +@{+/-}d(Rn) 7n {+/-}d +#n 27 n +@#n 37 n +.+/-n 67 +/-n - 4 +@.+/-n 77 +/-n - 4 +{+/-}n 67 {+/-}n - PC - 4 if on disk, 37 and n +@{+/-}n 77 {+/-}n - PC - 4 if on disk, invalid diff --git a/pdp11_dz.c b/PDP11/pdp11_dz.c similarity index 87% rename from pdp11_dz.c rename to PDP11/pdp11_dz.c index 0c7b449c..47620948 100644 --- a/pdp11_dz.c +++ b/PDP11/pdp11_dz.c @@ -24,7 +24,19 @@ in this Software without prior written authorization from Robert M Supnik. dz DZ11 terminal multiplexor + + 09-Nov-01 RMS Added VAX support */ +#if defined (USE_INT64) +#define VM_VAX 1 +#include "vax_defs.h" +#define DZ_RDX 16 + +#else +#define VM_PDP11 1 #include "pdp11_defs.h" +#define DZ_RDX 8 +#endif + #include "dec_dz.h" diff --git a/pdp11_fp.c b/PDP11/pdp11_fp.c similarity index 100% rename from pdp11_fp.c rename to PDP11/pdp11_fp.c diff --git a/PDP11/pdp11_io.c b/PDP11/pdp11_io.c new file mode 100644 index 00000000..da5e9ff6 --- /dev/null +++ b/PDP11/pdp11_io.c @@ -0,0 +1,361 @@ +/* pdp11_io.c: PDP-11 I/O simulator + + 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. + + 11-Dec-01 RMS Moved interrupt debug code + 08-Nov-01 RMS Cloned from cpu sources +*/ + +#include "pdp11_defs.h" + +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 trap_req, ipl; +extern int32 cpu_log; +extern FILE *sim_log; +int32 calc_ints (int32 nipl, int32 trq); + +extern t_stat CPU_rd (int32 *data, int32 addr, int32 access); +extern t_stat CPU_wr (int32 data, int32 addr, int32 access); +extern t_stat APR_rd (int32 *data, int32 addr, int32 access); +extern t_stat APR_wr (int32 data, int32 addr, int32 access); +extern t_stat SR_MMR012_rd (int32 *data, int32 addr, int32 access); +extern t_stat SR_MMR012_wr (int32 data, int32 addr, int32 access); +extern t_stat MMR3_rd (int32 *data, int32 addr, int32 access); +extern t_stat MMR3_wr (int32 data, int32 addr, int32 access); +extern t_stat ubm_rd (int32 *data, int32 addr, int32 access); +extern t_stat ubm_wr (int32 data, int32 addr, int32 access); +extern t_stat std_rd (int32 *data, int32 addr, int32 access); +extern t_stat std_wr (int32 data, int32 addr, int32 access); +extern t_stat lpt_rd (int32 *data, int32 addr, int32 access); +extern t_stat lpt_wr (int32 data, int32 addr, int32 access); +extern t_stat dz_rd (int32 *data, int32 addr, int32 access); +extern t_stat dz_wr (int32 data, int32 addr, int32 access); +extern t_stat rk_rd (int32 *data, int32 addr, int32 access); +extern t_stat rk_wr (int32 data, int32 addr, int32 access); +extern int32 rk_inta (void); +extern int32 rk_enb; +/* extern t_stat rk6_rd (int32 *data, int32 addr, int32 access); +extern t_stat rk6_wr (int32 data, int32 addr, int32 access); +extern int32 rk6_inta (void); +extern int32 rk6_enb; */ +extern t_stat rl_rd (int32 *data, int32 addr, int32 access); +extern t_stat rl_wr (int32 data, int32 addr, int32 access); +extern int32 rl_enb; +extern t_stat rp_rd (int32 *data, int32 addr, int32 access); +extern t_stat rp_wr (int32 data, int32 addr, int32 access); +extern int32 rp_inta (void); +extern int32 rp_enb; +extern t_stat rq_rd (int32 *data, int32 addr, int32 access); +extern t_stat rq_wr (int32 data, int32 addr, int32 access); +extern int32 rq_inta (void); +extern int32 rq_enb; +extern t_stat rx_rd (int32 *data, int32 addr, int32 access); +extern t_stat rx_wr (int32 data, int32 addr, int32 access); +extern int32 rx_enb; +extern t_stat dt_rd (int32 *data, int32 addr, int32 access); +extern t_stat dt_wr (int32 data, int32 addr, int32 access); +extern int32 dt_enb; +extern t_stat tm_rd (int32 *data, int32 addr, int32 access); +extern t_stat tm_wr (int32 data, int32 addr, int32 access); +extern int32 tm_enb; +extern t_stat ts_rd (int32 *data, int32 addr, int32 access); +extern t_stat ts_wr (int32 data, int32 addr, int32 access); +extern int32 ts_enb; + +/* I/O data structures */ + +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 */ + +struct iolink iotable[] = { + { IOBA_CPU, IOBA_CPU+IOLN_CPU, NULL, &CPU_rd, &CPU_wr }, + { IOBA_STD, IOBA_STD+IOLN_STD, NULL, &std_rd, &std_wr }, + { IOBA_LPT, IOBA_LPT+IOLN_LPT, NULL, &lpt_rd, &lpt_wr }, + { IOBA_DZ, IOBA_DZ +IOLN_DZ, NULL, &dz_rd, &dz_wr }, + { IOBA_RK, IOBA_RK +IOLN_RK, &rk_enb, &rk_rd, &rk_wr }, + { IOBA_RL, IOBA_RL +IOLN_RL, &rl_enb, &rl_rd, &rl_wr }, + { IOBA_RP, IOBA_RP +IOLN_RP, &rp_enb, &rp_rd, &rp_wr }, + { IOBA_RQ, IOBA_RQ +IOLN_RQ, &rq_enb, &rq_rd, &rq_wr }, + { IOBA_RX, IOBA_RX +IOLN_RX, &rx_enb, &rx_rd, &rx_wr }, + { IOBA_TC, IOBA_TC +IOLN_TC, &dt_enb, &dt_rd, &dt_wr }, + { IOBA_TM, IOBA_TM +IOLN_TM, &tm_enb, &tm_rd, &tm_wr }, + { IOBA_TS, IOBA_TS +IOLN_TS, &ts_enb, &ts_rd, &ts_wr }, +/* { IOBA_RK6, IOBA_RK6+IOLN_RK6, &rk6_enb, &rk6_rd, &rk6_wr }, */ + { IOBA_APR, IOBA_APR+IOLN_APR, NULL, &APR_rd, &APR_wr }, + { IOBA_APR1, IOBA_APR1+IOLN_APR1, NULL, &APR_rd, &APR_wr }, + { IOBA_SRMM, IOBA_SRMM+IOLN_SRMM, NULL, &SR_MMR012_rd, &SR_MMR012_wr }, + { IOBA_MMR3, IOBA_MMR3+IOLN_MMR3, NULL, &MMR3_rd, &MMR3_wr }, + { IOBA_UBM, IOBA_UBM+IOLN_UBM, NULL, &ubm_rd, &ubm_wr }, + { 0, 0, NULL, NULL, 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 }, + { NULL }, /* IPL 6 */ + { NULL } }; /* IPL 7 */ + +/* I/O page lookup and linkage routines + + Inputs: + *data = pointer to data to read, if READ + data = data to store, if WRITE or WRITEB + pa = address + access = READ, WRITE, or WRITEB + Outputs: + status = SCPE_OK or SCPE_NXM +*/ + +t_stat iopageR (int32 *data, int32 pa, int32 access) +{ +t_stat stat; +struct iolink *p; + +for (p = &iotable[0]; p -> low != 0; p++ ) { + if ((pa >= p -> low) && (pa < p -> high) && + ((p -> enb == NULL) || *p -> enb)) { + stat = p -> read (data, pa, access); + trap_req = calc_ints (ipl, trap_req); + return stat; } } +return SCPE_NXM; +} + +t_stat iopageW (int32 data, int32 pa, int32 access) +{ +t_stat stat; +struct iolink *p; + +for (p = &iotable[0]; p -> low != 0; p++ ) { + if ((pa >= p -> low) && (pa < p -> high) && + ((p -> enb == NULL) || *p -> enb)) { + stat = p -> write (data, pa, access); + trap_req = calc_ints (ipl, trap_req); + return stat; } } +return SCPE_NXM; +} + +/* Calculate interrupt outstanding */ + +int32 calc_ints (int32 nipl, int32 trq) +{ +int32 i; + +for (i = IPL_HLVL - 1; i > nipl; i--) { + if (int_req[i]) return (trq | TRAP_INT); } +return (trq & ~TRAP_INT); +} + +/* Find vector for highest priority interrupt */ + +int32 get_vector (int32 nipl) +{ +int32 i, j, t, vec; + +for (i = IPL_HLVL - 1; i > nipl; i--) { /* loop thru lvls */ + t = int_req[i]; /* get level */ + for (j = 0; t && (j < 32); j++) { /* srch level */ + if ((t >> j) & 1) { /* irq found? */ + int_req[i] = int_req[i] & ~(1u << j); /* clr irq */ + if (int_ack[i][j]) vec = int_ack[i][j](); + else vec = int_vec[i][j]; + if (DBG_LOG (LOG_CPU_I)) fprintf (sim_log, + ">>INT: lvl=%d, flag=%d, vec=%o\n", i, j, vec); + return vec; /* return vector */ + } /* end if t */ + } /* end for j */ + } /* end for i */ +return 0; +} + +/* Read and write Unibus map registers + + In any even/odd pair + even = low 16b, bit <0> clear + odd = high 6b + + The Unibus map is stored as an array of longwords +*/ + +t_stat ubm_rd (int32 *data, int32 addr, int32 access) +{ +if (cpu_ubm) { + int32 pg = (addr >> 2) & UBM_M_PN; + *data = (addr & 2)? ((ub_map[pg] >> 16) & 077): + (ub_map[pg] & 0177776); + return SCPE_OK; } +return SCPE_NXM; +} + +t_stat ubm_wr (int32 data, int32 addr, int32 access) +{ +if (cpu_ubm) { + int32 sc, pg = (addr >> 2) & UBM_M_PN; + if (access == WRITEB) { + sc = (addr & 3) << 3; + ub_map[pg] = (ub_map[pg] & ~(0377 << sc)) | + ((data & 0377) << sc); } + else { sc = (addr & 2) << 3; + ub_map[pg] = (ub_map[pg] & ~(0177777 << sc)) | + ((data & 0177777) << sc); } + ub_map[pg] = ub_map[pg] & 017777776; + return SCPE_OK; } +return SCPE_NXM; +} + +/* Mapped memory access routines for DMA devices */ + +/* Map I/O address to memory address */ + +t_bool Map_Addr (t_addr ba, t_addr *ma) +{ +if (cpu_bme) { /* bus map on? */ + int32 pg = UBM_GETPN (ba); /* map entry */ + int32 off = UBM_GETOFF (ba); /* offset */ + if (pg != UBM_M_PN) /* last page? */ + *ma = (ub_map[pg] + off) & PAMASK; /* no, use map */ + else *ma = (IOPAGEBASE + off) & PAMASK; } /* yes, use fixed */ +else *ma = ba; /* else physical */ +return TRUE; +} + +/* I/O buffer routines, aligned access + + Map_ReadB - fetch byte buffer from memory + Map_ReadW - fetch word buffer from memory + Map_WriteB - store byte buffer into memory + Map_WriteW - store word buffer into memory +*/ + +int32 Map_ReadB (t_addr ba, int32 bc, uint8 *buf, t_bool ub) +{ +t_addr alim, lim, ma; + +lim = ba + bc; +if (ub && cpu_bme) { /* UB, map on? */ + for ( ; ba < lim; ba++) { /* by bytes */ + Map_Addr (ba, &ma); /* map addr */ + if (!ADDR_IS_MEM (ma)) return (lim - ba); /* NXM? err */ + if (ma & 1) *buf++ = (M[ma >> 1] >> 8) & 0377; /* get byte */ + else *buf++ = M[ma >> 1] & 0377; } + return 0; } +else { /* physical */ + if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */ + else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */ + else return bc; /* no, err */ + for ( ; ba < alim; ba++) { /* by bytes */ + if (ba & 1) *buf++ = (M[ba >> 1] >> 8) & 0377; /* get byte */ + else *buf++ = M[ba >> 1] & 0377; } + return (lim - alim); } +} + +int32 Map_ReadW (t_addr ba, int32 bc, uint16 *buf, t_bool ub) +{ +t_addr alim, lim, ma; + +ba = ba & ~01; /* align start */ +lim = ba + (bc & ~01); +if (ub && cpu_bme) { /* UB, map 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 */ + *buf++ = M[ma >> 1]; } + return 0; } +else { /* physical */ + if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */ + else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */ + else return bc; /* no, err */ + for ( ; ba < alim; ba = ba + 2) { /* by words */ + *buf++ = M[ba >> 1]; } + return (lim - alim); } +} + +int32 Map_WriteB (t_addr ba, int32 bc, uint8 *buf, t_bool ub) +{ +t_addr alim, lim, ma; + +lim = ba + bc; +if (ub && cpu_bme) { /* UB, map on? */ + for ( ; ba < lim; ba++) { /* by bytes */ + Map_Addr (ba, &ma); /* map addr */ + if (!ADDR_IS_MEM (ma)) return (lim - ba); /* NXM? err */ + if (ma & 1) M[ma >> 1] = (M[ma >> 1] & 0377) | + ((uint16) *buf++ << 8); + else M[ma >> 1] = (M[ma >> 1] & ~0377) | *buf++; } + return 0; } +else { /* physical */ + if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */ + else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */ + else return bc; /* no, err */ + for ( ; ba < alim; ba++) { /* by bytes */ + if (ba & 1) M[ba >> 1] = (M[ba >> 1] & 0377) | + ((uint16) *buf++ << 8); + else M[ba >> 1] = (M[ba >> 1] & ~0377) | *buf++; } + return (lim - alim); } +} + +int32 Map_WriteW (t_addr ba, int32 bc, uint16 *buf, t_bool ub) +{ +t_addr alim, lim, ma; + +ba = ba & ~01; /* align start */ +lim = ba + (bc & ~01); +if (ub && cpu_bme) { /* UB, map 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 */ + M[ma >> 1] = *buf++; } /* store word */ + return 0; } +else { /* physical */ + if (ADDR_IS_MEM (lim)) alim = lim; /* end ok? */ + else if (ADDR_IS_MEM (ba)) alim = MEMSIZE; /* no, strt ok? */ + else return bc; /* no, err */ + for ( ; ba < alim; ba = ba + 2) { /* by words */ + M[ba >> 1] = *buf++; } + return (lim - alim); } +} diff --git a/pdp11_lp.c b/PDP11/pdp11_lp.c similarity index 90% rename from pdp11_lp.c rename to PDP11/pdp11_lp.c index c11899ff..fec48890 100644 --- a/pdp11_lp.c +++ b/PDP11/pdp11_lp.c @@ -25,11 +25,21 @@ lpt LP11 line printer + 09-Nov-01 RMS Added VAX support 07-Sep-01 RMS Revised interrupt mechanism 30-Oct-00 RMS Standardized register naming */ +#if defined (USE_INT64) +#define VM_VAX 1 +#include "vax_defs.h" +#define LPT_DRDX 16 + +#else +#define VM_PDP11 1 #include "pdp11_defs.h" +#define LPT_DRDX 8 +#endif #define LPTCSR_IMP (CSR_ERR + CSR_DONE + CSR_IE) /* implemented */ #define LPTCSR_RW (CSR_IE) /* read/write */ @@ -53,8 +63,8 @@ UNIT lpt_unit = { UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT }; REG lpt_reg[] = { - { ORDATA (BUF, lpt_unit.buf, 8) }, - { ORDATA (CSR, lpt_csr, 16) }, + { GRDATA (BUF, lpt_unit.buf, LPT_DRDX, 8, 0) }, + { GRDATA (CSR, lpt_csr, LPT_DRDX, 16, 0) }, { FLDATA (INT, IREQ (LPT), INT_V_LPT) }, { FLDATA (ERR, lpt_csr, CSR_V_ERR) }, { FLDATA (DONE, lpt_csr, CSR_V_DONE) }, @@ -66,7 +76,7 @@ REG lpt_reg[] = { DEVICE lpt_dev = { "LPT", &lpt_unit, lpt_reg, NULL, - 1, 10, 31, 1, 8, 8, + 1, 10, 31, 1, LPT_DRDX, 8, NULL, NULL, &lpt_reset, NULL, &lpt_attach, &lpt_detach }; diff --git a/pdp11_rk.c b/PDP11/pdp11_rk.c similarity index 82% rename from pdp11_rk.c rename to PDP11/pdp11_rk.c index 865041cd..fb940df0 100644 --- a/pdp11_rk.c +++ b/PDP11/pdp11_rk.c @@ -25,6 +25,9 @@ rk RK11/RK05 cartridge disk + 30-Nov-01 RMS Added read only unit, extended SET/SHOW support + 24-Nov-01 RMS Converted FLG to array + 09-Nov-01 RMS Added bus map support 07-Sep-01 RMS Revised device disable and interrupt mechanisms 26-Apr-01 RMS Added device enable/disable support 25-Mar-01 RMS Fixed block fill calculation @@ -62,9 +65,9 @@ #define RK_NUMDR 8 /* drives/controller */ #define RK_M_NUMDR 07 #define RK_SIZE (RK_NUMCY * RK_NUMSF * RK_NUMSC * RK_NUMWD) /* words/drive */ -#define RK_MAXMEM ((int32) (MEMSIZE / sizeof (int16))) /* words/memory */ #define RK_CTLI 1 /* controller int */ #define RK_SCPI(x) (2u << (x)) /* drive int */ +#define RK_MAXFR (1 << 16) /* max transfer */ /* Flags in the unit flags word */ @@ -73,6 +76,7 @@ #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 */ /* Parameters in the unit descriptor */ @@ -163,7 +167,7 @@ extern uint16 *M; /* memory */ extern int32 int_req[IPL_HLVL]; -extern UNIT cpu_unit; +uint16 *rkxb = NULL; /* xfer buffer */ int32 rkcs = 0; /* control/status */ int32 rkds = 0; /* drive status */ int32 rkba = 0; /* memory address */ @@ -192,14 +196,22 @@ t_stat rk_boot (int32 unitno); */ UNIT rk_unit[] = { - { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) }, - { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) }, - { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) }, - { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) }, - { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) }, - { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) }, - { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) }, - { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) } }; + { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, RK_SIZE) }, + { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, RK_SIZE) }, + { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, RK_SIZE) }, + { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, RK_SIZE) }, + { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, RK_SIZE) }, + { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, RK_SIZE) }, + { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, RK_SIZE) }, + { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, RK_SIZE) } }; REG rk_reg[] = { { ORDATA (RKCS, rkcs, 16) }, @@ -216,32 +228,15 @@ REG rk_reg[] = { { FLDATA (IE, rkcs, CSR_V_IE) }, { DRDATA (STIME, rk_swait, 24), PV_LEFT }, { DRDATA (RTIME, rk_rwait, 24), PV_LEFT }, - { GRDATA (FLG0, rk_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG1, rk_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG2, rk_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG3, rk_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG4, rk_unit[4].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG5, rk_unit[5].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG6, rk_unit[6].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG7, rk_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, + { 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, rk_enb, 0), REG_HRO }, { NULL } }; MTAB rk_mod[] = { - { (UNIT_HWLK+UNIT_SWLK), 0, "write enabled", "ENABLED", NULL }, - { (UNIT_HWLK+UNIT_SWLK), UNIT_HWLK, "write locked", "LOCKED", NULL }, - { (UNIT_HWLK+UNIT_SWLK), UNIT_SWLK, "write locked", NULL, NULL }, - { (UNIT_HWLK+UNIT_SWLK), (UNIT_HWLK+UNIT_SWLK), "write locked", - NULL, NULL }, + { UNIT_HWLK, 0, "write enabled", "ENABLED", NULL }, + { UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL }, { 0 } }; DEVICE rk_dev = { @@ -275,7 +270,7 @@ case 0: /* RKDS: read only */ uptr = rk_dev.units + GET_DRIVE (rkda); /* selected unit */ if (uptr -> flags & UNIT_ATT) rkds = rkds | RKDS_RDY; /* attached? */ if (!sim_is_active (uptr)) rkds = rkds | RKDS_RWS; /* idle? */ - if (uptr -> flags & (UNIT_HWLK + UNIT_SWLK)) 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; @@ -373,7 +368,7 @@ if (((uptr -> flags & UNIT_ATT) == 0) || sim_is_active (uptr)) { if (rkcs & (RKCS_INH + RKCS_FMT)) { /* format? */ rk_set_done (RKER_PGE); return; } -if ((func == RKCS_WRITE) && (uptr -> flags & (UNIT_HWLK + UNIT_SWLK))) { +if ((func == RKCS_WRITE) && (uptr -> flags & UNIT_WPRT)) { rk_set_done (RKER_WLK); /* write and locked? */ return; } if (func == RKCS_WLK) { /* write lock? */ @@ -413,9 +408,10 @@ return; t_stat rk_svc (UNIT *uptr) { -int32 comp, drv, err, awc, twc, wc; -int32 pa, da, remc, track, sect; -static uint16 fill[RK_NUMWD] = { 0 }; +int32 i, drv, err, awc, wc, t; +int32 da, track, sect; +t_addr ma; +uint16 comp; drv = uptr - rk_dev.units; /* get drv number */ if (uptr -> FUNC == RKCS_SEEK) { /* seek */ @@ -424,54 +420,56 @@ if (uptr -> FUNC == RKCS_SEEK) { /* seek */ rkintq = rkintq | RK_SCPI (drv); /* queue request */ if (rkcs & CSR_DONE) SET_INT (RK); } else { rkintq = 0; /* clear queue */ - CLR_INT (RK); } /* clear interrupt */ + CLR_INT (RK); } /* clear interrupt */ return SCPE_OK; } if ((uptr -> flags & UNIT_ATT) == 0) { /* attached? */ rk_set_done (RKER_DRE); return IORETURN (rk_stopioe, SCPE_UNATT); } -pa = (((rkcs & RKCS_MEX) << (16 - RKCS_V_MEX)) | rkba) >> 1; +ma = ((rkcs & RKCS_MEX) << (16 - RKCS_V_MEX)) | rkba; /* get mem addr */ da = GET_DA (rkda) * RK_NUMWD; /* get disk addr */ -twc = 0200000 - rkwc; /* get true wc */ -if ((pa + twc) > RK_MAXMEM) { /* mem overrun? */ - rker = rker | RKER_NXM; - wc = (RK_MAXMEM - pa); } -else wc = twc; -if (wc < 0) { /* abort transfer? */ - rk_set_done (0); - return SCPE_OK; } -if ((da + twc) > RK_SIZE) { /* disk overrun? */ - rker = rker | RKER_OVR; - if (wc > (RK_SIZE - da)) wc = RK_SIZE - da; } +wc = 0200000 - rkwc; /* get wd cnt */ err = fseek (uptr -> fileref, da * sizeof (int16), SEEK_SET); if ((uptr -> FUNC == RKCS_READ) && (err == 0)) { /* read? */ - awc = fxread (&M[pa], sizeof (int16), wc, uptr -> fileref); - for ( ; awc < wc; awc++) M[pa + awc] = 0; - err = ferror (uptr -> fileref); } + 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 */ + rker = rker | RKER_NXM; /* NXM? set flg */ + wc = wc - t; } /* adj wd cnt */ + } /* end read */ if ((uptr -> FUNC == RKCS_WRITE) && (err == 0)) { /* write? */ - fxwrite (&M[pa], sizeof (int16), wc, uptr -> fileref); - err = ferror (uptr -> fileref); - if ((err == 0) && (remc = (wc & (RK_NUMWD - 1)))) { - fxwrite (fill, sizeof (int16), RK_NUMWD - remc, uptr -> fileref); - err = ferror (uptr -> fileref); } } + if (t = Map_ReadW (ma, wc << 1, rkxb, UB)) { /* 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); } + } /* end write */ if ((uptr -> FUNC == RKCS_WCHK) && (err == 0)) { /* write check? */ - twc = wc; /* xfer length */ - for (wc = 0; (err == 0) && (wc < twc); wc++) { - awc = fxread (&comp, sizeof (int16), 1, uptr -> fileref); - if (awc == 0) comp = 0; - if (comp != M[pa + wc]) { - rker = rker | RKER_WCE; + 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 */ + rker = rker | RKER_NXM; /* NXM? set flg */ + break; } + if (comp != rkxb[wc]) { /* match to disk? */ + rker = rker | RKER_WCE; /* no, err */ if (rkcs & RKCS_SSE) break; } } - err = ferror (uptr -> fileref); } + } /* end wcheck */ rkwc = (rkwc + wc) & 0177777; /* final word count */ -pa = (pa + wc) << 1; /* final byte addr */ -rkba = pa & RKBA_IMP; /* lower 16b */ -rkcs = (rkcs & ~RKCS_MEX) | ((pa >> (16 - RKCS_V_MEX)) & RKCS_MEX); +ma = ma + (wc << 1); /* final byte addr */ +rkba = ma & RKBA_IMP; /* lower 16b */ +rkcs = (rkcs & ~RKCS_MEX) | ((ma >> (16 - RKCS_V_MEX)) & RKCS_MEX); da = da + wc + (RK_NUMWD - 1); track = (da / RK_NUMWD) / RK_NUMSC; sect = (da / RK_NUMWD) % RK_NUMSC; @@ -546,6 +544,8 @@ for (i = 0; i < RK_NUMDR; i++) { sim_cancel (uptr); 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; } diff --git a/pdp11_rl.c b/PDP11/pdp11_rl.c similarity index 72% rename from pdp11_rl.c rename to PDP11/pdp11_rl.c index d82048a4..07cbc29e 100644 --- a/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-2001, Robert M Supnik @@ -25,6 +25,11 @@ rl RL11(RLV12)/RL01/RL02 cartridge disk + 30-Nov-01 MRS Added read only, extended SET/SHOW support + 26-Nov-01 RMS Fixed per-drive error handling + 24-Nov-01 RMS Converted FLG, CAPAC to arrays + 19-Nov-01 RMS Fixed signed/unsigned mismatch in write check + 09-Nov-01 RMS Added bus map, VAX support 07-Sep-01 RMS Revised device disable and interrupt mechanisms 20-Aug-01 RMS Added bad block option in attach 17-Jul-01 RMS Fixed warning from VC++ 6.0 @@ -42,11 +47,31 @@ The most complicated part of the RL11 controller is the way it does seeks. Seeking is relative to the current disk address; this requires - keeping accurate track of the current cylinder. The RL01 will not + keeping accurate track of the current cylinder. The RL11 will not switch heads or cross cylinders during transfers. + + The RL11 functions in three 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 Unibus 22b systems - the RL11 behaves as an 18b Unibus + peripheral and must go through the I/O map + - VAX Q22 systems - the RL11 must go through the I/O map */ +#if defined (USE_INT64) /* VAX version */ +#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 /* Constants */ @@ -55,46 +80,47 @@ #define RL_NUMSF 2 /* surfaces/cylinder */ #define RL_NUMCY 256 /* cylinders/drive */ #define RL_NUMDR 4 /* drives/controller */ +#define RL_MAXFR (1 << 16) /* max transfer */ #define RL01_SIZE (RL_NUMCY * RL_NUMSF * RL_NUMSC * RL_NUMWD) /* words/drive */ #define RL02_SIZE (RL01_SIZE * 2) /* words/drive */ -#define RL_MAXMEM ((int) (MEMSIZE / sizeof (int16))) /* words/memory */ /* Flags in the unit flags word */ -#define UNIT_V_HWLK (UNIT_V_UF) /* hwre write lock */ +#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_DUMMY (1 << UNIT_V_DUMMY) -#define UNIT_HWLK (1u << UNIT_V_HWLK) +#define UNIT_WLK (1u << UNIT_V_WLK) #define UNIT_RL02 (1u << UNIT_V_RL02) #define UNIT_AUTO (1u << UNIT_V_AUTO) +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protected */ /* Parameters in the unit descriptor */ #define TRK u3 /* current track */ #define STAT u4 /* status */ -/* RLDS */ +/* RLDS, NI = not implemented, * = kept in STAT, ^ = kept in TRK */ #define RLDS_LOAD 0 /* no cartridge */ #define RLDS_LOCK 5 /* lock on */ -#define RLDS_BHO 0000010 /* brushes home */ -#define RLDS_HDO 0000020 /* heads out */ -#define RLDS_CVO 0000040 /* cover open */ -#define RLDS_HD 0000100 /* head select */ -#define RLDS_DSE 0000400 /* drive select err */ +#define RLDS_BHO 0000010 /* brushes home NI */ +#define RLDS_HDO 0000020 /* heads out NI */ +#define RLDS_CVO 0000040 /* cover open NI */ +#define RLDS_HD 0000100 /* head select ^ */ #define RLDS_RL02 0000200 /* RL02 */ -#define RLDS_VCK 0001000 /* volume check */ -#define RLDS_WGE 0002000 /* write gate err */ -#define RLDS_SPE 0004000 /* spin err */ -#define RLDS_STO 0010000 /* seek time out */ -#define RLDS_WLK 0020000 /* write locked */ -#define RLDS_HCE 0040000 /* head current err */ -#define RLDS_WDE 0100000 /* write data err */ -#define RLDS_ATT (RLDS_HDO+RLDS_BHO+RLDS_LOCK) /* attached status */ -#define RLDS_UNATT (RLDS_CVO+RLDS_LOAD) /* unattached status */ +#define RLDS_DSE 0000400 /* drv sel err NI */ +#define RLDS_VCK 0001000 /* vol check * */ +#define RLDS_WGE 0002000 /* wr gate err * */ +#define RLDS_SPE 0004000 /* spin err * */ +#define RLDS_STO 0010000 /* seek time out NI */ +#define RLDS_WLK 0020000 /* wr locked */ +#define RLDS_HCE 0040000 /* hd curr err NI */ +#define RLDS_WDE 0100000 /* wr data err NI */ +#define RLDS_ATT (RLDS_HDO+RLDS_BHO+RLDS_LOCK) /* att status */ +#define RLDS_UNATT (RLDS_CVO+RLDS_LOAD) /* unatt status */ #define RLDS_ERR (RLDS_WDE+RLDS_HCE+RLDS_STO+RLDS_SPE+RLDS_WGE+ \ RLDS_VCK+RLDS_DSE) /* errors bits */ @@ -156,9 +182,8 @@ #define RLBAE_IMP 0000077 /* implemented */ -extern uint16 *M; /* memory */ extern int32 int_req[IPL_HLVL]; -extern UNIT cpu_unit; +uint16 *rlxb = NULL; /* xfer buffer */ int32 rlcs = 0; /* control/status */ int32 rlba = 0; /* memory address */ int32 rlbae = 0; /* mem addr extension */ @@ -173,8 +198,8 @@ t_stat rl_reset (DEVICE *dptr); void rl_set_done (int32 error); t_stat rl_boot (int32 unitno); t_stat rl_attach (UNIT *uptr, char *cptr); -t_stat rl_set_size (UNIT *uptr, int32 value); -t_stat rl_set_bad (UNIT *uptr, int32 value); +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); extern t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds); /* RL11 data structures @@ -186,48 +211,40 @@ extern t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds); */ UNIT rl_unit[] = { - { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO, - RL01_SIZE) }, - { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO, - RL01_SIZE) }, - { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO, - RL01_SIZE) }, - { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO, - RL01_SIZE) } }; + { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) }, + { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) }, + { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) }, + { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE+UNIT_AUTO, RL01_SIZE) } }; REG rl_reg[] = { - { ORDATA (RLCS, rlcs, 16) }, - { ORDATA (RLDA, rlda, 16) }, - { ORDATA (RLBA, rlba, 16) }, - { ORDATA (RLBAE, rlbae, 6) }, - { ORDATA (RLMP, rlmp, 16) }, - { ORDATA (RLMP1, rlmp1, 16) }, - { ORDATA (RLMP2, rlmp2, 16) }, + { GRDATA (RLCS, rlcs, RL_RDX, 16, 0) }, + { GRDATA (RLDA, rlda, RL_RDX, 16, 0) }, + { GRDATA (RLBA, rlba, RL_RDX, 16, 0) }, + { GRDATA (RLBAE, rlbae, RL_RDX, 6, 0) }, + { GRDATA (RLMP, rlmp, RL_RDX, 16, 0) }, + { GRDATA (RLMP1, rlmp1, RL_RDX, 16, 0) }, + { GRDATA (RLMP2, rlmp2, RL_RDX, 16, 0) }, { FLDATA (INT, IREQ (RL), INT_V_RL) }, { FLDATA (ERR, rlcs, CSR_V_ERR) }, { FLDATA (DONE, rlcs, CSR_V_DONE) }, { FLDATA (IE, rlcs, CSR_V_IE) }, { DRDATA (STIME, rl_swait, 24), PV_LEFT }, { DRDATA (RTIME, rl_rwait, 24), PV_LEFT }, - { GRDATA (FLG0, rl_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG1, rl_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG2, rl_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG3, rl_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { DRDATA (CAPAC0, rl_unit[0].capac, 32), PV_LEFT + REG_HRO }, - { DRDATA (CAPAC1, rl_unit[1].capac, 32), PV_LEFT + REG_HRO }, - { DRDATA (CAPAC2, rl_unit[2].capac, 32), PV_LEFT + REG_HRO }, - { DRDATA (CAPAC3, rl_unit[3].capac, 32), PV_LEFT + REG_HRO }, + { 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, rl_enb, 0), REG_HRO }, { NULL } }; MTAB rl_mod[] = { - { UNIT_HWLK, 0, "write enabled", "ENABLED", NULL }, - { UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL }, + { UNIT_WLK, 0, "write enabled", "ENABLED", NULL }, + { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, { UNIT_DUMMY, 0, NULL, "BADBLOCK", &rl_set_bad }, { (UNIT_RL02+UNIT_ATT), UNIT_ATT, "RL01", NULL, NULL }, { (UNIT_RL02+UNIT_ATT), (UNIT_RL02+UNIT_ATT), "RL02", NULL, NULL }, @@ -241,7 +258,7 @@ MTAB rl_mod[] = { DEVICE rl_dev = { "RL", rl_unit, rl_reg, rl_mod, - RL_NUMDR, 8, 24, 1, 8, 16, + RL_NUMDR, RL_RDX, 24, 1, RL_RDX, 16, NULL, NULL, &rl_reset, &rl_boot, &rl_attach, NULL }; @@ -279,6 +296,7 @@ case 3: /* RLMP */ rlmp1 = rlmp2; break; case 4: /* RLBAE */ + if (RL_18B) return SCPE_NXM; /* not in RL11 */ *data = rlbae & RLBAE_IMP; break; } /* end switch */ return SCPE_OK; @@ -348,6 +366,7 @@ case 3: /* RLMP */ rlmp = rlmp1 = rlmp2 = data; break; case 4: /* RLBAE */ + if (RL_18B) 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); @@ -366,27 +385,29 @@ return SCPE_OK; t_stat rl_svc (UNIT *uptr) { -int32 comp, err, awc, wc, maxwc; -int32 func, pa, da, remc; -static uint16 fill[RL_NUMWD] = { 0 }; +int32 err, wc, maxwc, t; +int32 i, func, da, awc; +t_addr ma; +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 (rlda & RLDA_GS_CLR) rlmp = rlmp & ~RLDS_ERR; if (uptr -> flags & UNIT_RL02) rlmp = rlmp | RLDS_RL02; - if (uptr -> flags & UNIT_HWLK) rlmp = rlmp | RLDS_WLK; - uptr -> STAT = rlmp2 = rlmp1 = rlmp; + 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? */ rlcs = rlcs & ~RLCS_DRDY; /* clear drive ready */ + 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_HWLK)) { +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; } @@ -397,7 +418,7 @@ if (func == RLCS_SEEK) { /* seek? */ if (func == RLCS_RHDR) { /* read header? */ rlmp = (uptr -> TRK & RLDA_TRACK) | GET_SECT (rlda); - rlmp1 = 0; + rlmp1 = rlmp2 = 0; rl_set_done (0); /* done */ return SCPE_OK; } @@ -406,45 +427,53 @@ if (((func != RLCS_RNOHDR) && ((uptr -> TRK & RLDA_CYL) != (rlda & RLDA_CYL))) rl_set_done (RLCS_ERR | RLCS_HDE | RLCS_INCMP); /* wrong cylinder? */ return SCPE_OK; } -pa = ((rlbae << 16) | rlba) >> 1; /* form phys addr */ +ma = (rlbae << 16) | rlba; /* get mem addr */ da = GET_DA (rlda) * RL_NUMWD; /* get disk addr */ wc = 0200000 - rlmp; /* get true wc */ maxwc = (RL_NUMSC - GET_SECT (rlda)) * RL_NUMWD; /* max transfer */ if (wc > maxwc) wc = maxwc; /* track overrun? */ -if ((pa + wc) > RL_MAXMEM) { /* mem overrun? */ - rlcs = rlcs | RLCS_ERR | RLCS_NXM; - wc = (RL_MAXMEM - pa); } -if (wc < 0) { /* abort transfer? */ - rl_set_done (RLCS_INCMP); - return SCPE_OK; } - err = fseek (uptr -> fileref, da * sizeof (int16), SEEK_SET); + if ((func >= RLCS_READ) && (err == 0)) { /* read (no hdr)? */ - awc = fxread (&M[pa], sizeof (int16), wc, uptr -> fileref); - for ( ; awc < wc; awc++) M[pa + awc] = 0; - 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 */ + rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */ + wc = wc - t; } /* adjust wc */ + } /* end read */ if ((func == RLCS_WRITE) && (err == 0)) { /* write? */ - fxwrite (&M[pa], sizeof (int16), wc, uptr -> fileref); - err = ferror (uptr -> fileref); - if ((err == 0) && (remc = (wc & (RL_NUMWD - 1)))) { - fxwrite (fill, sizeof (int16), RL_NUMWD - remc, uptr -> fileref); - err = ferror (uptr -> fileref); } } + if (t = Map_ReadW (ma, wc << 1, rlxb, UB)) { /* 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); } + } /* end write */ if ((func == RLCS_WCHK) && (err == 0)) { /* write check? */ - remc = wc; /* xfer length */ - for (wc = 0; (err == 0) && (wc < remc); wc++) { - awc = fxread (&comp, sizeof (int16), 1, uptr -> fileref); - if (awc == 0) comp = 0; - if (comp != M[pa + wc]) rlcs = rlcs | RLCS_ERR | RLCS_CRC; } - 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 */ + rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */ + break; } + if (comp != rlxb[wc]) /* check to buf */ + rlcs = rlcs | RLCS_ERR | RLCS_CRC; + } /* end for */ + } /* end wcheck */ rlmp = (rlmp + wc) & 0177777; /* final word count */ if (rlmp != 0) rlcs = rlcs | RLCS_ERR | RLCS_INCMP; /* completed? */ -pa = (pa + wc) << 1; /* final byte addr */ -rlbae = (pa >> 16) & RLBAE_IMP; /* upper 6b */ -rlba = pa & RLBA_IMP; /* lower 16b */ +ma = ma + (wc << 1); /* final byte addr */ +rlbae = (ma >> 16) & RLBAE_IMP; /* upper 6b */ +rlba = ma & RLBA_IMP; /* lower 16b */ rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX); rlda = rlda + ((wc + (RL_NUMWD - 1)) / RL_NUMWD); rl_set_done (0); @@ -483,6 +512,8 @@ for (i = 0; i < RL_NUMDR; i++) { uptr = rl_dev.units + i; sim_cancel (uptr); uptr -> STAT = 0; } +if (rlxb == NULL) rlxb = calloc (RL_MAXFR, sizeof (unsigned int16)); +if (rlxb == NULL) return SCPE_MEM; return SCPE_OK; } @@ -496,9 +527,12 @@ t_stat r; 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) - return pdp11_bad_block (uptr, RL_NUMSC, RL_NUMWD); +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; } @@ -509,22 +543,24 @@ return SCPE_OK; /* Set size routine */ -t_stat rl_set_size (UNIT *uptr, int32 value) +t_stat rl_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { if (uptr -> flags & UNIT_ATT) return SCPE_ALATT; -uptr -> capac = (value & UNIT_RL02)? RL02_SIZE: RL01_SIZE; +uptr -> capac = (val & UNIT_RL02)? RL02_SIZE: RL01_SIZE; return SCPE_OK; } /* Set bad block routine */ -t_stat rl_set_bad (UNIT *uptr, int32 value) +t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc) { return pdp11_bad_block (uptr, RL_NUMSC, RL_NUMWD); } /* Device bootstrap */ +#if defined (VM_PDP11) + #define BOOT_START 02000 /* start */ #define BOOT_UNIT 02006 /* unit number */ #define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) @@ -574,9 +610,18 @@ t_stat rl_boot (int32 unitno) { 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; saved_PC = BOOT_START; return SCPE_OK; } + +#else + +t_stat rl_boot (int32 unitno) +{ +return SCPE_NOFNC; +} +#endif diff --git a/pdp11_rp.c b/PDP11/pdp11_rp.c similarity index 82% rename from pdp11_rp.c rename to PDP11/pdp11_rp.c index 32988437..207b9fcf 100644 --- a/pdp11_rp.c +++ b/PDP11/pdp11_rp.c @@ -25,6 +25,9 @@ rp RH/RP/RM moving head disks + 30-Nov-01 RMS Added read only unit, extended SET/SHOW support + 24-Nov-01 RMS Changed RPDS, RPER, FLG, CAPAC, RPFN to arrays + 09-Nov-01 RMS Added bus map, VAX support 23-Oct-01 RMS Fixed bug in error interrupts 15-Oct-01 RMS Added debug logging 05-Oct-01 RMS Rewrote interrupt handling from schematics @@ -66,14 +69,45 @@ level sensitive. - The DONE interrupt, once set, is not disabled if IE is cleared, but the SC interrupt is. + + 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 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 + + To distinguish the two Unibus cases, the PDP-11 version of the RP/RM + provides an internal mode flag for RH11 vs RH70 */ +#if defined (USE_INT64) /* VAX version */ +#include "vax_defs.h" +#define VM_VAX 1 +#define RP_RDX 16 +#define RP_WID 32 +#define DMASK 0xFFFF +#define RH_18B FALSE /* 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)) +extern uint16 *M; +extern int32 cpu_18b, cpu_ubm, cpu_rh11; +extern int32 cpu_log; +extern FILE *sim_log; +#endif + #include #define RP_NUMDR 8 /* #drives */ #define RP_NUMWD 256 /* words/sector */ -#define RP_MAXFR 65536 /* max transfer */ +#define RP_MAXFR (1 << 16) /* max transfer */ #define GET_SECTOR(x,d) ((int) fmod (sim_gtime() / ((double) (x)), \ ((double) drv_tab[d].sect))) @@ -90,6 +124,7 @@ #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 */ /* Parameters in the unit descriptor */ @@ -318,7 +353,7 @@ struct drvtyp { int devtype; /* device type */ }; -struct drvtyp drv_tab[] = { +static struct drvtyp drv_tab[] = { { RM03_SECT, RM03_SURF, RM03_CYL, RM03_SIZE, RM03_DEV }, { RP04_SECT, RP04_SURF, RP04_CYL, RP04_SIZE, RP04_DEV }, { RM80_SECT, RM80_SURF, RM80_CYL, RM80_SIZE, RM80_DEV }, @@ -327,11 +362,8 @@ struct drvtyp drv_tab[] = { { RP07_SECT, RP07_SURF, RP07_CYL, RP07_SIZE, RP07_DEV }, { 0 } }; -extern uint16 *M; /* memory */ extern int32 int_req[IPL_HLVL]; -extern UNIT cpu_unit; -extern int32 pdp11_log; -extern FILE *sim_log; +uint16 *rpxb = NULL; /* xfer buffer */ int32 rpcs1 = 0; /* control/status 1 */ int32 rpwc = 0; /* word count */ int32 rpba = 0; /* bus address */ @@ -360,8 +392,8 @@ int reg_in_drive[32] = { void update_rpcs (int32 flags, int32 drv); void rp_go (int32 drv, int32 fnc); -t_stat rp_set_size (UNIT *uptr, int32 value); -t_stat rp_set_bad (UNIT *uptr, int32 value); +t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); +t_stat rp_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc); t_stat rp_svc (UNIT *uptr); t_stat rp_reset (DEVICE *dptr); t_stat rp_boot (int32 unitno); @@ -379,38 +411,40 @@ extern t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds); UNIT rp_unit[] = { { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - (RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) }, + UNIT_ROABLE+(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - (RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) }, + UNIT_ROABLE+(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - (RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) }, + UNIT_ROABLE+(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - (RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) }, + UNIT_ROABLE+(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - (RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) }, + UNIT_ROABLE+(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - (RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) }, + UNIT_ROABLE+(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - (RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) }, + UNIT_ROABLE+(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) }, { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - (RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) } }; + UNIT_ROABLE+(RM03_DTYPE << UNIT_V_DTYPE), RM03_SIZE) } }; REG rp_reg[] = { - { ORDATA (RPCS1, rpcs1, 16) }, - { ORDATA (RPWC, rpwc, 16) }, - { ORDATA (RPBA, rpba, 16) }, - { ORDATA (RPDA, rpda, 16) }, - { ORDATA (RPCS2, rpcs2, 16) }, - { ORDATA (RPOF, rpof, 16) }, - { ORDATA (RPDC, rpdc, 16) }, - { ORDATA (RPER2, rper2, 16) }, - { ORDATA (RPER3, rper3, 16) }, - { ORDATA (RPEC1, rpec1, 16) }, - { ORDATA (RPEC2, rpec2, 16) }, - { ORDATA (RPMR, rpmr, 16) }, - { ORDATA (RPDB, rpdb, 16) }, - { ORDATA (RPBAE, rpbae, 6) }, - { ORDATA (RPCS3, rpcs3, 16) }, + { GRDATA (RPCS1, rpcs1, RP_RDX, 16, 0) }, + { GRDATA (RPWC, rpwc, RP_RDX, 16, 0) }, + { GRDATA (RPBA, rpba, RP_RDX, 16, 0) }, + { GRDATA (RPDA, rpda, RP_RDX, 16, 0) }, + { GRDATA (RPCS2, rpcs2, RP_RDX, 16, 0) }, + { BRDATA (RPDS, rpds, RP_RDX, 16, RP_NUMDR) }, + { BRDATA (RPER1, rper1, RP_RDX, 16, RP_NUMDR) }, + { GRDATA (RPOF, rpof, RP_RDX, 16, 0) }, + { GRDATA (RPDC, rpdc, RP_RDX, 16, 0) }, + { GRDATA (RPER2, rper2, RP_RDX, 16, 0) }, + { GRDATA (RPER3, rper3, RP_RDX, 16, 0) }, + { GRDATA (RPEC1, rpec1, RP_RDX, 16, 0) }, + { GRDATA (RPEC2, rpec2, RP_RDX, 16, 0) }, + { GRDATA (RPMR, rpmr, RP_RDX, 16, 0) }, + { GRDATA (RPDB, rpdb, RP_RDX, 16, 0) }, + { GRDATA (RPBAE, rpbae, RP_RDX, 6, 0) }, + { GRDATA (RPCS3, rpcs3, RP_RDX, 16, 0) }, { FLDATA (IFF, rpiff, 0) }, { FLDATA (INT, IREQ (RP), INT_V_RP) }, { FLDATA (SC, rpcs1, CSR_V_ERR) }, @@ -418,46 +452,12 @@ REG rp_reg[] = { { FLDATA (IE, rpcs1, CSR_V_IE) }, { DRDATA (STIME, rp_swait, 24), REG_NZ + PV_LEFT }, { DRDATA (RTIME, rp_rwait, 24), REG_NZ + PV_LEFT }, - { ORDATA (RPDS0, rpds[0], 16) }, - { ORDATA (RPDS1, rpds[1], 16) }, - { ORDATA (RPDS2, rpds[2], 16) }, - { ORDATA (RPDS3, rpds[3], 16) }, - { ORDATA (RPDS4, rpds[4], 16) }, - { ORDATA (RPDS5, rpds[5], 16) }, - { ORDATA (RPDS6, rpds[6], 16) }, - { ORDATA (RPDS7, rpds[7], 16) }, - { ORDATA (RPDE0, rper1[0], 16) }, - { ORDATA (RPDE1, rper1[1], 16) }, - { ORDATA (RPDE2, rper1[2], 16) }, - { ORDATA (RPDE3, rper1[3], 16) }, - { ORDATA (RPDE4, rper1[4], 16) }, - { ORDATA (RPDE5, rper1[5], 16) }, - { ORDATA (RPDE6, rper1[6], 16) }, - { ORDATA (RPDE7, rper1[7], 16) }, - { ORDATA (RPFN0, rp_unit[0].FUNC, 5), REG_HRO }, - { ORDATA (RPFN1, rp_unit[1].FUNC, 5), REG_HRO }, - { ORDATA (RPFN2, rp_unit[2].FUNC, 5), REG_HRO }, - { ORDATA (RPFN3, rp_unit[3].FUNC, 5), REG_HRO }, - { ORDATA (RPFN4, rp_unit[4].FUNC, 5), REG_HRO }, - { ORDATA (RPFN5, rp_unit[5].FUNC, 5), REG_HRO }, - { ORDATA (RPFN6, rp_unit[6].FUNC, 5), REG_HRO }, - { ORDATA (RPFN7, rp_unit[7].FUNC, 5), REG_HRO }, - { GRDATA (FLG0, rp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG1, rp_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG2, rp_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG3, rp_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG4, rp_unit[4].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG5, rp_unit[5].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG6, rp_unit[6].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG7, rp_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, + { 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) }, { FLDATA (*DEVENB, rp_enb, 0), REG_HRO }, { NULL } }; @@ -508,7 +508,7 @@ MTAB rp_mod[] = { DEVICE rp_dev = { "RP", rp_unit, rp_reg, rp_mod, - RP_NUMDR, 8, 30, 1, 8, 16, + RP_NUMDR, RP_RDX, 30, 1, RP_RDX, RP_WID, NULL, NULL, &rp_reset, &rp_boot, &rp_attach, &rp_detach }; @@ -592,9 +592,11 @@ case 023: /* RPEC2 */ *data = rpec2; break; case 024: /* RPBAE */ + if (RH_18B) return SCPE_NXM; /* not in RH11 */ *data = rpbae = rpbae & ~AE_MBZ; break; case 025: /* RPCS3 */ + if (RH_18B) return SCPE_NXM; /* not in RH11 */ *data = rpcs3 = (rpcs3 & ~(CS1_IE | CS3_MBZ)) | (rpcs1 & CS1_IE); break; default: /* all others */ @@ -704,11 +706,13 @@ case 016: /* RPDC */ rpdc = data & ~DC_MBZ; break; case 024: /* RPBAE */ + if (RH_18B) 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 ((access == WRITEB) && (PA & 1)) break; rpcs3 = data & ~CS3_MBZ; rpcs1 = (rpcs1 & ~CS1_IE) | (rpcs3 & CS1_IE); @@ -838,9 +842,11 @@ return; t_stat rp_svc (UNIT *uptr) { -int32 i, dtype, drv, err; -int32 ba, wc, awc, twc, da, fc; -static uint16 dbuf[RP_MAXFR]; +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 */ drv = uptr - rp_dev.units; /* get drv number */ @@ -866,7 +872,7 @@ case FNC_SEEK: /* seek */ break; case FNC_WRITE: /* write */ - if (uptr -> flags & UNIT_WLK) { /* 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; } @@ -878,44 +884,65 @@ case FNC_READH: /* read headers */ wc = 0200000 - rpwc; /* get true wc */ if ((da + wc) > drv_tab[dtype].size) { /* disk overrun? */ - rper1[drv] = rper1[drv] | ER1_AOE; - if (wc > (drv_tab[dtype].size - da)) - wc = drv_tab[dtype].size - da; } + rper1[drv] = rper1[drv] | ER1_AOE; /* set err */ + wc = drv_tab[dtype].size - da; /* trim xfer */ + if (da >= drv_tab[dtype].size) { /* none left? */ + 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? */ - for (twc = 0; twc < wc; twc++) { - if (!ADDR_IS_MEM (ba)) { /* nx memory? */ + if (rpcs2 & CS2_UAI) { /* no addr inc? */ + if (t = Map_ReadW (ba, 2, &comp, ub)) { /* 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 */ + 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); } + } /* 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); + 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)) { + 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 */ + 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); + 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 */ rpcs2 = rpcs2 | CS2_NEM; /* set error */ break; } - dbuf[twc] = M[ba >> 1]; /* write to disk */ - if ((rpcs2 & CS2_UAI) == 0) ba = ba + 2; } - if (fc = twc & (RP_NUMWD - 1)) { /* fill? */ - fc = RP_NUMWD - fc; - for (i = 0; i < fc; i++) dbuf[twc + i] = 0; } - fxwrite (dbuf, sizeof (uint16), twc + fc, uptr -> fileref); - err = ferror (uptr -> fileref); - } /* end if */ - else { /* read, wchk */ - awc = fxread (dbuf, sizeof (uint16), wc, uptr -> fileref); - err = ferror (uptr -> fileref); - for ( ; awc < wc; awc++) dbuf[awc] = 0; - for (twc = 0; twc < wc; twc++) { - if (!ADDR_IS_MEM (ba)) { /* nx memory? */ - rpcs2 = rpcs2 | CS2_NEM; /* set error */ - break; } - if (uptr -> FUNC == FNC_READ) M[ba >> 1] = dbuf[twc]; - else if (M[ba >> 1] != dbuf[twc]) { + if (comp != rpxb[wc]) { /* compare wd */ rpcs2 = rpcs2 | CS2_WCE; /* set error */ break; } if ((rpcs2 & CS2_UAI) == 0) ba = ba + 2; } - } /* end else */ + } /* end else wchk */ - rpwc = (rpwc + twc) & 0177777; /* final word count */ + rpwc = (rpwc + wc) & 0177777; /* final word count */ rpba = (ba & 0177777) & ~BA_MBZ; /* lower 16b */ rpbae = (ba >> 16) & ~AE_MBZ; /* upper 6b */ rpcs1 = (rpcs1 & ~ CS1_UAE) | ((rpbae << CS1_V_UAE) & CS1_UAE); - da = da + twc + (RP_NUMWD - 1); + da = da + wc + (RP_NUMWD - 1); if (da >= drv_tab[dtype].size) rpds[drv] = rpds[drv] | DS_LST; da = da / RP_NUMWD; rpda = da % drv_tab[dtype].sect; @@ -1002,10 +1029,12 @@ for (i = 0; i < RP_NUMDR; 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_WLK)? DS_WRL: 0); + 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)); +if (rpxb == NULL) return SCPE_MEM; return SCPE_OK; } @@ -1021,14 +1050,16 @@ 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_WLK)? 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 pdp11_bad_block (uptr, drv_tab[GET_DTYPE (uptr -> flags)].sect, RP_NUMWD); +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); } 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); @@ -1057,22 +1088,24 @@ return detach_unit (uptr); /* Set size command validation routine */ -t_stat rp_set_size (UNIT *uptr, int32 value) +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 (value)].size; +uptr -> capac = drv_tab[GET_DTYPE (val)].size; return SCPE_OK; } /* Set bad block routine */ -t_stat rp_set_bad (UNIT *uptr, int32 value) +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); } /* Device bootstrap */ +#if defined (VM_PDP11) + #define BOOT_START 02000 /* start */ #define BOOT_UNIT 02006 /* unit number */ #define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) @@ -1111,3 +1144,12 @@ M[BOOT_UNIT >> 1] = unitno & CS2_M_UNIT; saved_PC = BOOT_START; return SCPE_OK; } + +#else + +t_stat rp_boot (int32 unitno) +{ +return SCPE_NOFNC; +} + +#endif diff --git a/PDP11/pdp11_rq.c b/PDP11/pdp11_rq.c new file mode 100644 index 00000000..f8d8e342 --- /dev/null +++ b/PDP11/pdp11_rq.c @@ -0,0 +1,1849 @@ +/* vax_rq.c: RQDX3 disk controller simulator + + Copyright (c) 2001, Robert M Supnik + Derived from work by Stephen F. Shirron + + 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. + + rq RQDX3 disk controller + + 19-Dec-01 RMS Added bigger drives + 17-Dec-01 RMS Added queue process +*/ + +#if defined (USE_INT64) +#include "vax_defs.h" +#define VM_VAX 1 +#define RQ_RDX 16 +#define RQ_AINC 4 +#define RQ_WID 32 + +#else +#include "pdp11_defs.h" +#define VM_PDP11 1 +#define RQ_RDX 8 +#define RQ_AINC 2 +#define RQ_WID 16 +#endif + +#include "dec_uqssp.h" +#include "dec_mscp.h" + +#define RQ_SH_MAX 24 /* max display wds */ +#define RQ_SH_PPL 8 /* wds per line */ +#define RQ_SH_DPL 4 /* desc per line */ +#define RQ_SH_RI 001 /* show rings */ +#define RQ_SH_FR 002 /* show free q */ +#define RQ_SH_RS 004 /* show resp q */ +#define RQ_SH_UN 010 /* show unit q's */ + +#define RQ_CLASS 1 /* RQ class */ +#define RQ_MODEL 19 /* RQ model */ +#define RQ_HVER 1 /* hardware version */ +#define RQ_SVER 3 /* software version */ +#define RQ_DHTMO 60 /* def host timeout */ +#define RQ_DCTMO 120 /* def ctrl timeout */ +#define RQ_NUMDR 4 /* # drives */ +#define RQ_NUMBY 512 /* bytes per block */ +#define RQ_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_DTYPE (UNIT_V_UF + 3) /* drive type */ +#define UNIT_M_DTYPE 0xF +#define UNIT_ONL (1 << UNIT_V_ONL) +#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 /* unit flags */ +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */ + +#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 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 */ + +/* Internal packet management. The real RQDX3 manages its packets as true + linked lists. However, use of actual addresses in structures won't work + with save/restore. Accordingly, the packets are an arrayed structure, + and links are actually subscripts. To minimize complexity, packet[0] + is not used (0 = end of list), and the number of packets must be a power + of two. +*/ + +#define RQ_NPKTS 32 /* # packets (pwr of 2) */ +#define RQ_M_NPKTS (RQ_NPKTS - 1) /* mask */ +#define RQ_PKT_SIZE_W 32 /* payload size (wds) */ +#define RQ_PKT_SIZE (RQ_PKT_SIZE_W * sizeof (int16)) + +struct rqpkt { + int16 link; /* link to next */ + uint16 d[RQ_PKT_SIZE_W]; }; /* data */ + +/* Packet payload extraction and insertion */ + +#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 + +/* Disk formats. An RQDX3 consists of the following regions: + + XBNs Extended blocks - contain information about disk format, + also holds track being reformatted during bad block repl. + Size = sectors/track + 1, replicated 3 times. + DBNs Diagnostic blocks - used by diagnostics. Sized to pad + out the XBNs to a cylinder boundary. + LBNs Logical blocks - contain user information. + RCT Replacement control table - first block contains status, + second contains data from block being replaced, remaining + contain information about replaced bad blocks. + Size = RBNs/128 + 3, replicated 4-8 times. + RBNs Replacement blocks - used to replace bad blocks. + + The simulator does not need to perform bad block replacement; the + information below is for simulating RCT reads, if required. + + Note that an RA drive has a different order: LBNs, RCT, XBN, DBN; + the RBNs are spare blocks at the end of every track. +*/ + +#define RCT_OVHD 2 /* #ovhd blks */ +#define RCT_ENTB 128 /* entries/blk */ +#define RCT_END 0x80000000 /* marks RCT end */ + +/* The RQDX3 supports multiple disk drive types: + + type sec surf cyl tpg gpc RCT LBNs + + RX50 10 1 80 5 16 - 800 + RX33 15 2 80 2 1 - 2400 + RD51 18 4 306 4 1 36*4 21600 + RD31 17 4 615 4 1 3*8 41560 + RD52 17 8 512 8 1 4*8 60480 + RD53 17 7 1024 7 1 5*8 138672 + RD54 17 15 1225 15 1 7*8 311200 + + The simulator also supports larger drives that only existed + on SDI controllers. XBN, DBN, RCTS and RCTC are not known + for the SDI drives and are not used by the simulator: + + RA82 57 15 1435 15 1 ?*8 1216665 + RA72 51 20 1921? 20 1 ?*8 1953300 + RA90 69 13 2656 13 1 ?*8 2376153 + RA92 73 13 3101 13 1 ?*8 2940951 + + Each drive can be a different type. The drive field in the + unit flags specified the drive type and thus, indirectly, + the drive size. DISKS MUST BE DECLARED IN ASCENDING SIZE. +*/ + +#define RQDF_RMV 01 /* removable */ +#define RQDF_RO 02 /* read only */ +#define RQDF_SDI 04 /* SDI drive */ + +#define RX50_DTYPE 0 +#define RX50_SECT 10 +#define RX50_SURF 1 +#define RX50_CYL 80 +#define RX50_TPG 5 +#define RX50_GPC 16 +#define RX50_XBN 0 +#define RX50_DBN 0 +#define RX50_LBN 800 +#define RX50_RCTS 0 +#define RX50_RCTC 0 +#define RX50_RBN 0 +#define RX50_MOD 7 +#define RX50_MED 0x25658032 +#define RX50_FLGS RQDF_RMV + +#define RX33_DTYPE 1 +#define RX33_SECT 15 +#define RX33_SURF 2 +#define RX33_CYL 80 +#define RX33_TPG 2 +#define RX33_GPC 1 +#define RX33_XBN 0 +#define RX33_DBN 0 +#define RX33_LBN 2400 +#define RX33_RCTS 0 +#define RX33_RCTC 0 +#define RX33_RBN 0 +#define RX33_MOD 10 +#define RX33_MED 0x25658021 +#define RX33_FLGS RQDF_RMV + +#define RD51_DTYPE 2 +#define RD51_SECT 18 +#define RD51_SURF 4 +#define RD51_CYL 306 +#define RD51_TPG 4 +#define RD51_GPC 1 +#define RD51_XBN 57 +#define RD51_DBN 87 +#define RD51_LBN 21600 +#define RD51_RCTS 36 +#define RD51_RCTC 4 +#define RD51_RBN 144 +#define RD51_MOD 6 +#define RD51_MED 0x25644033 +#define RD51_FLGS 0 + +#define RD31_DTYPE 3 +#define RD31_SECT 17 +#define RD31_SURF 4 +#define RD31_CYL 615 /* last unused */ +#define RD31_TPG RD31_SURF +#define RD31_GPC 1 +#define RD31_XBN 54 +#define RD31_DBN 14 +#define RD31_LBN 41560 +#define RD31_RCTS 3 +#define RD31_RCTC 8 +#define RD31_RBN 100 +#define RD31_MOD 12 +#define RD31_MED 0x2564401F +#define RD31_FLGS 0 + +#define RD52_DTYPE 4 /* Quantum params */ +#define RD52_SECT 17 +#define RD52_SURF 8 +#define RD52_CYL 512 +#define RD52_TPG RD52_SURF +#define RD52_GPC 1 +#define RD52_XBN 54 +#define RD52_DBN 82 +#define RD52_LBN 60480 +#define RD52_RCTS 4 +#define RD52_RCTC 8 +#define RD52_RBN 168 +#define RD52_MOD 8 +#define RD52_MED 0x25644034 +#define RD52_FLGS 0 + +#define RD53_DTYPE 5 +#define RD53_SECT 17 +#define RD53_SURF 8 +#define RD53_CYL 1024 /* last unused */ +#define RD53_TPG RD53_SURF +#define RD53_GPC 1 +#define RD53_XBN 54 +#define RD53_DBN 82 +#define RD53_LBN 138672 +#define RD53_RCTS 5 +#define RD53_RCTC 8 +#define RD53_RBN 280 +#define RD53_MOD 9 +#define RD53_MED 0x25644035 +#define RD53_FLGS 0 + +#define RD54_DTYPE 6 +#define RD54_SECT 17 +#define RD54_SURF 15 +#define RD54_CYL 1225 /* last unused */ +#define RD54_TPG RD54_SURF +#define RD54_GPC 1 +#define RD54_XBN 54 +#define RD54_DBN 201 +#define RD54_LBN 311200 +#define RD54_RCTS 7 +#define RD54_RCTC 8 +#define RD54_RBN 609 +#define RD54_MOD 13 +#define RD54_MED 0x25644036 +#define RD54_FLGS 0 + +#define RA82_DTYPE 7 /* SDI drive */ +#define RA82_SECT 57 /* +1 spare/track */ +#define RA82_SURF 15 +#define RA82_CYL 1435 /* 0-1422 user */ +#define RA82_TPG RA82_SURF +#define RA82_GPC 1 +#define RA82_XBN 3420 /* cyl 1427-1430 */ +#define RA82_DBN 3420 /* cyl 1431-1434 */ +#define RA82_LBN 1216665 /* 57*15*1423 */ +#define RA82_RCTS 400 /* cyl 1423-1426 */ +#define RA82_RCTC 8 +#define RA82_RBN 21345 /* 1 *15*1423 */ +#define RA82_MOD 11 +#define RA82_MED 0x25641052 +#define RA82_FLGS RQDF_SDI + +#define RRD40_DTYPE 8 +#define RRD40_SECT 128 +#define RRD40_SURF 1 +#define RRD40_CYL 10400 +#define RRD40_TPG RRD40_SURF +#define RRD40_GPC 1 +#define RRD40_XBN 0 +#define RRD40_DBN 0 +#define RRD40_LBN 1331200 +#define RRD40_RCTS 0 +#define RRD40_RCTC 0 +#define RRD40_RBN 0 +#define RRD40_MOD 26 +#define RRD40_MED 0x25652228 +#define RRD40_FLGS (RQDF_RMV | RQDF_RO) + +#define RA72_DTYPE 9 /* SDI drive */ +#define RA72_SECT 51 /* +1 spare/trk */ +#define RA72_SURF 20 +#define RA72_CYL 1921 /* 0-1914 user */ +#define RA72_TPG RA72_SURF +#define RA72_GPC 1 +#define RA72_XBN 2040 /* cyl 1917-1918? */ +#define RA72_DBN 2040 /* cyl 1920-1921? */ +#define RA72_LBN 1953300 /* 51*20*1915 */ +#define RA72_RCTS 400 /* cyl 1915-1916? */ +#define RA72_RCTC 5 /* ? */ +#define RA72_RBN 38300 /* 1 *20*1915 */ +#define RA72_MOD 37 +#define RA72_MED 0x25641048 +#define RA72_FLGS RQDF_SDI + +#define RA90_DTYPE 10 /* SDI drive */ +#define RA90_SECT 69 /* +1 spare/trk */ +#define RA90_SURF 13 +#define RA90_CYL 2656 /* 0-2648 user */ +#define RA90_TPG RA90_SURF +#define RA90_GPC 1 +#define RA90_XBN 1794 /* cyl 2651-2652? */ +#define RA90_DBN 1794 /* cyl 2653-2654? */ +#define RA90_LBN 2376153 /* 69*13*2649 */ +#define RA90_RCTS 400 /* cyl 2649-2650? */ +#define RA90_RCTC 6 /* ? */ +#define RA90_RBN 34437 /* 1 *13*2649 */ +#define RA90_MOD 19 +#define RA90_MED 0x2564105A +#define RA90_FLGS RQDF_SDI + +#define RA92_DTYPE 11 /* SDI drive */ +#define RA92_SECT 73 /* +1 spare/trk */ +#define RA92_SURF 13 +#define RA92_CYL 3101 /* 0-3098 user */ +#define RA92_TPG RA92_SURF +#define RA92_GPC 1 +#define RA92_XBN 174 /* cyl 3100? */ +#define RA92_DBN 775 +#define RA92_LBN 2940951 /* 73*13*3099 */ +#define RA92_RCTS 316 /* cyl 3099? */ +#define RA92_RCTC 3 /* ? */ +#define RA92_RBN 40287 /* 1 *13*3099 */ +#define RA92_MOD 29 +#define RA92_MED 0x2564105C +#define RA92_FLGS RQDF_SDI + +struct drvtyp { + int32 sect; /* sectors */ + int32 surf; /* surfaces */ + int32 cyl; /* cylinders */ + int32 tpg; /* trk/grp */ + int32 gpc; /* grp/cyl */ + int32 xbn; /* XBN size */ + int32 dbn; /* DBN size */ + int32 lbn; /* LBN size */ + int32 rcts; /* RCT size */ + int32 rctc; /* RCT copies */ + int32 rbn; /* RBNs */ + int32 mod; /* MSCP model */ + int32 med; /* MSCP media */ + int32 flgs; /* flags */ +}; + +#define RQ_DRV(d) \ + d##_SECT, d##_SURF, d##_CYL, d##_TPG, \ + d##_GPC, d##_XBN, d##_DBN, d##_LBN, \ + d##_RCTS, d##_RCTC, d##_RBN, d##_MOD, \ + d##_MED, d##_FLGS +#define RQ_SIZE(d) (d##_LBN * RQ_NUMBY) + +static struct drvtyp drv_tab[] = { + { RQ_DRV (RX50) }, { RQ_DRV (RX33) }, + { RQ_DRV (RD51) }, { RQ_DRV (RD31) }, + { RQ_DRV (RD52) }, { RQ_DRV (RD53) }, + { RQ_DRV (RD54) }, { RQ_DRV (RA82) }, + { RQ_DRV (RRD40) }, { RQ_DRV (RA72) }, + { RQ_DRV (RA90) }, { RQ_DRV (RA92) }, + { 0 } }; + +extern int32 int_req[IPL_HLVL]; +extern int32 tmr_poll, clk_tps; +extern UNIT cpu_unit; +uint16 *rqxb = NULL; /* xfer buffer */ +uint32 rq_sa = 0; /* status, addr */ +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_qtime = 100; /* queue time */ +int32 rq_xtime = 500; /* transfer time */ +int32 rq_enb = 1; /* device enable */ + +t_stat rq_svc (UNIT *uptr); +t_stat rq_tmrsvc (UNIT *uptr); +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_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); + +/* RQ data structures + + rq_dev RQ device descriptor + rq_unit RQ unit list + rq_reg RQ register list + rq_mod RQ modifier list +*/ + +UNIT rq_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+ + (RX50_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RX50)) }, + { 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 (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) }, + { GRDATA (FREE, rq_freq, RQ_RDX, 5, 0) }, + { GRDATA (RESP, rq_rspq, RQ_RDX, 5, 0) }, + { GRDATA (PBSY, rq_pbsy, RQ_RDX, 5, 0) }, + { GRDATA (CFLGS, rq_cflgs, RQ_RDX, 16, 0) }, + { GRDATA (CSTA, rq_csta, RQ_RDX, 4, 0) }, + { GRDATA (PERR, rq_perr, RQ_RDX, 9, 0) }, + { GRDATA (CRED, rq_credits, RQ_RDX, 5, 0) }, + { GRDATA (HAT, rq_hat, RQ_RDX, 16, 0) }, + { GRDATA (HTMO, rq_htmo, RQ_RDX, 17, 0) }, + { URDATA (CPKT, rq_unit[0].cpkt, RQ_RDX, 5, 0, RQ_NUMDR, 0) }, + { URDATA (PKTQ, rq_unit[0].pktq, RQ_RDX, 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 (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)) }, + { FLDATA (*DEVENB, rq_enb, 0), REG_HRO }, + { NULL } }; + +MTAB rq_mod[] = { + { UNIT_WLK, 0, NULL, "ENABLED", &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 }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, RQ_SH_FR, "FREEQ", NULL, + NULL, &rq_show_ctrl, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, RQ_SH_RS, "RESPQ", NULL, + NULL, &rq_show_ctrl, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, RQ_SH_UN, "UNITQ", NULL, + NULL, &rq_show_ctrl, NULL }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, -1, "ALL", NULL, + NULL, &rq_show_ctrl, NULL }, + { MTAB_XTD | MTAB_VUN | MTAB_NMO, 0, "UNITQ", NULL, + NULL, &rq_show_unitq, NULL }, + { MTAB_XTD | MTAB_VUN, 0, "WRITE", NULL, + NULL, &rq_show_wlk, NULL }, + { UNIT_DTYPE, (RX50_DTYPE << UNIT_V_DTYPE), "RX50", "RX50", &rq_set_size }, + { UNIT_DTYPE, (RX33_DTYPE << UNIT_V_DTYPE), "RX33", "RX33", &rq_set_size }, + { UNIT_DTYPE, (RD31_DTYPE << UNIT_V_DTYPE), "RD31", "RD31", &rq_set_size }, + { UNIT_DTYPE, (RD51_DTYPE << UNIT_V_DTYPE), "RD51", "RD51", &rq_set_size }, + { UNIT_DTYPE, (RD52_DTYPE << UNIT_V_DTYPE), "RD52", "RD52", &rq_set_size }, + { UNIT_DTYPE, (RD53_DTYPE << UNIT_V_DTYPE), "RD53", "RD53", &rq_set_size }, + { UNIT_DTYPE, (RD54_DTYPE << UNIT_V_DTYPE), "RD54", "RD54", &rq_set_size }, + { UNIT_DTYPE, (RA82_DTYPE << UNIT_V_DTYPE), "RA82", "RA82", &rq_set_size }, + { UNIT_DTYPE, (RA72_DTYPE << UNIT_V_DTYPE), "RA72", "RA72", &rq_set_size }, + { UNIT_DTYPE, (RA90_DTYPE << UNIT_V_DTYPE), "RA90", "RA90", &rq_set_size }, + { 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 }, + { 0 } }; + +DEVICE rq_dev = { + "RQ", rq_unit, rq_reg, rq_mod, + RQ_NUMDR + 1, RQ_RDX, 31, RQ_AINC, RQ_RDX, RQ_WID, + NULL, NULL, &rq_reset, + &rq_boot, &rq_attach, &rq_detach }; + +/* I/O dispatch routine, I/O addresses 17772150 - 17772152 + + 17772150 IP read/write + 17772152 SA read/write +*/ + +t_stat rq_rd (int32 *data, int32 PA, int32 access) +{ +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); } + break; +case 1: /* SA */ + *data = rq_sa; + break; } +return SCPE_OK; +} + +t_stat rq_wr (int32 data, int32 PA, int32 access) +{ +switch ((PA >> 1) & 01) { /* decode PA<1> */ +case 0: /* IP */ + rq_reset (&rq_dev); /* init device */ + break; +case 1: /* SA */ + switch (rq_csta) { /* controller state? */ + case CST_S1: /* need S1 reply */ + if (data & SA_S1H_VL) { /* valid? */ + if (data & SA_S1H_WR) { /* wrap? */ + rq_sa = data; /* echo data */ + rq_csta = CST_S1_WR; } /* endless loop */ + else { rq_s1dat = data; /* 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 */ + } + break; + case CST_S1_WR: /* wrap mode */ + rq_sa = data; /* echo data */ + break; + case CST_S2: /* need S2 reply */ + rq_comm = data & SA_S2H_CLO; /* get low addr */ + rq_prgi = data & 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 */ + break; + case CST_S3: /* need S3 reply */ + rq_comm = ((data & SA_S3H_CHI) << 16) | rq_comm; + if (data & 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 */ + break; + case CST_S3_PPA: /* need purge test */ + if (data) rq_fatal (PE_PPF); /* data not zero? */ + else rq_csta = CST_S3_PPB; /* wait for poll */ + break; + case CST_S4: /* need S4 reply */ + if (data & SA_S4H_GO) { /* go set? */ + rq_csta = CST_UP; /* we're up */ + rq_sa = 0; /* clear SA */ + sim_activate (&rq_unit[RQ_TIMER], tmr_poll * clk_tps); + if ((data & SA_S4H_LF) && rq_perr) rq_plf (rq_perr); + rq_perr = 0; } + break; } + break; } +return SCPE_OK; +} + +/* Transition to step 4 - init communications region */ + +t_bool rq_step4 (void) +{ +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 */ +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 */ + (RQ_SVER << SA_S4C_V_VER); +rq_csta = CST_S4; /* set step 4 */ +rq_init_int (); /* poke host */ +return OK; +} + +/* Queue service - invoked when any of the queues (host queue, unit + queues, response queue) require servicing + + 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 rq_quesvc (UNIT *uptr) +{ +int32 i, cnid; +int32 pkt = 0; + +if (rq_pip) { /* polling? */ + if (!rq_getpkt (&pkt)) return SCPE_OK; /* get host pkt */ + if (pkt) { /* got one? */ + if (GETP (pkt, UQ_HCTC, TYP) != UQ_TYP_SEQ) /* seq packet? */ + return rq_fatal (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 */ + 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 */ + } /* end if pkt */ + else rq_pip = 0; /* discontinue poll */ + } /* end if pip */ +if (!rq_pip) { /* not polling? */ + for (i = 0; i < RQ_NUMDR; i++) { /* chk unit q's */ + if (uptr -> cpkt || (uptr -> pktq == 0)) continue; + pkt = rq_deqh (&uptr -> pktq); /* get top of q */ + if (!rq_mscp (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 */ + } /* end if resp q */ +if (pkt) sim_activate (&rq_unit[RQ_QUEUE], rq_qtime); /* more to do? */ +return SCPE_OK; /* done */ +} + +/* Clock service (roughly once per second) */ + +t_stat rq_tmrsvc (UNIT *uptr) +{ +int32 i; +UNIT *nuptr; + +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 */ +return SCPE_OK; +} + +/* MSCP packet handling */ + +t_bool rq_mscp (int32 pkt, t_bool q) +{ +uint32 sts, cmd = GETP (pkt, CMD_OPC, OPC); + +switch (cmd) { +case OP_ABO: /* abort */ + return rq_abo (pkt, q); +case OP_AVL: /* avail */ + return rq_avl (pkt, q); +case OP_FMT: /* format */ + return rq_fmt (pkt, q); +case OP_GCS: /* get cmd status */ + return rq_gcs (pkt, q); +case OP_GUS: /* get unit status */ + return rq_gus (pkt, q); +case OP_ONL: /* online */ + return rq_onl (pkt, q); +case OP_SCC: /* set ctrl char */ + return rq_scc (pkt, q); +case OP_SUC: /* set unit char */ + return rq_suc (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); +case OP_CCD: /* nops */ +case OP_DAP: +case OP_FLU: + 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; } +rq_putr (pkt, cmd, 0, sts, RSP_LNT, UQ_TYP_SEQ); +return rq_putpkt (pkt, TRUE); +} + +/* Abort a command - 1st parameter is ref # of cmd to abort */ + +t_bool rq_abo (int32 pkt, t_bool q) +{ +uint32 lu = rq_pkt[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; + +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 */ + 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 (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; } + } /* end if unit */ +rq_putr (pkt, cmd | OP_END, 0, ST_SUC, ABO_LNT, UQ_TYP_SEQ); +return rq_putpkt (pkt, TRUE); +} + +/* Unit available - set unit status to available - defer if q'd cmds */ + +t_bool rq_avl (int32 pkt, t_bool q) +{ +uint32 lu = rq_pkt[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 = uptr -> uf & (UF_WPH | UF_RPL | UF_RMV); + 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); +} + +/* Get command status - only interested in active xfr cmd */ + +t_bool rq_gcs (int32 pkt, t_bool q) +{ +uint32 lu = rq_pkt[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? */ + (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); +} + +/* Get unit status */ + +t_bool rq_gus (int32 pkt, t_bool q) +{ +uint32 lu = rq_pkt[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 */ + else sts = ST_AVL; /* avail */ + rq_putr_unit (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); } +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); +} + +/* Unit online - defer if q'd commands */ + +t_bool rq_onl (int32 pkt, t_bool q) +{ +uint32 lu = rq_pkt[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 */ +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); +} + +/* Set controller characteristics */ + +t_bool rq_scc (int32 pkt, t_bool q) +{ +int32 sts, cmd, tmo; + +if (rq_pkt[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 (tmo = rq_pkt[pkt].d[SCC_TMO]) /* valid timeout? */ + rq_htmo = tmo + 2; /* set new val */ + 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); +} + +/* Set unit characteristics - defer if q'd commands */ + +t_bool rq_suc (int32 pkt, t_bool q) +{ +uint32 lu = rq_pkt[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 */ +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); +} + +/* Format command - floppies only */ + +t_bool rq_fmt (int32 pkt, t_bool q) +{ +uint32 lu = rq_pkt[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 = uptr -> uf & (UF_WPH | UF_RPL | UF_RMV); + sts = ST_AVL | SB_AVL_INU; } /* avail, in use */ + else if (uptr -> uf & UF_WPH) /* write prot? */ + 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); +} + +/* Data transfer commands */ + +t_bool rq_rw (int32 pkt, t_bool q) +{ +uint32 lu = rq_pkt[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 (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 */ +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); +} + +/* Validity checks */ + +int32 rq_rw_valid (int32 pkt, UNIT *uptr, uint32 cmd) +{ +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? */ + return (ST_OFL | SB_OFL_NV); /* offl no vol */ +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? */ + 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 */ + 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); + if (uptr -> uf & UF_WPH) /* hwre wlk? */ + return (ST_WPR | SB_WPR_HW); } +return 0; /* success! */ +} + +/* Unit service for data transfer commands */ + +t_stat rq_svc (UNIT *uptr) +{ +uint32 i, t, err, tbc, abc, wwc; +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??? */ +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 */ + return SCPE_OK; } +if (bc == 0) { /* no xfer? */ + rq_rw_end (uptr, 0, ST_SUC); /* ok by me... */ + return SCPE_OK; } + +if (cmd == OP_ERS) { /* erase? */ + if (uptr -> uf & (UF_WPH | UF_WPS)) rq_rw_end (uptr, 0, + ST_WPR | ((uptr -> uf & UF_WPH)? SB_WPR_HW: SB_WPR_SW)); + 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 */ +else if (cmd == OP_WR) { /* write? */ + if (uptr -> uf & (UF_WPH | UF_WPS)) rq_rw_end (uptr, 0, + ST_WPR | ((uptr -> uf & UF_WPH)? SB_WPR_HW: SB_WPR_SW)); + t = Map_ReadW (ba, tbc, rqxb, QB); /* 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); } + 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 */ +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); } + 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; } + } + 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 */ + } /* 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 */ + perror ("RQ I/O error"); + clearerr (uptr -> fileref); + return SCPE_IOERR; } +ba = ba + tbc; /* incr bus addr */ +bc = bc - tbc; /* decr byte cnt */ +bl = bl + ((tbc + (RQ_NUMBY - 1)) / RQ_NUMBY); /* incr blk # */ +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! */ +return SCPE_OK; +} + +/* Transfer command complete */ + +t_bool rq_rw_end (UNIT *uptr, uint32 flg, uint32 sts) +{ +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 */ + +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 */ +return OK; +} + +/* Data transfer error log packet */ + +t_bool rq_dte (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 # */ +lbn = GETP32 (tpkt, RW_WBLL); /* recent LBN */ +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); +ccyl = t + (lbn / drv_tab[dtyp].cyl); /* curr real cyl */ +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) | + (RQ_MODEL << DTE_CIDD_V_MOD); +rq_pkt[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) | + (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) | + (csurf << DTE_D3_V_SURF); +rq_putr (pkt, FM_SDE, LF_SNR, err, DTE_LNT, UQ_TYP_DAT); +return rq_putpkt (pkt, TRUE); +} + +/* Host bus error log packet */ + +t_bool rq_hbe (UNIT *uptr, uint32 err) +{ +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) | + (RQ_MODEL << DTE_CIDD_V_MOD); +rq_pkt[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); +} + +/* Port last failure error log packet */ + +t_bool rq_plf (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) | + (RQ_MODEL << PLF_CIDD_V_MOD); +rq_pkt[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); +} + +/* Unit now available attention packet */ + +int32 rq_una (UNIT *uptr) +{ +int32 pkt; +uint32 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); +} + +/* List handling + + rq_deqf - dequeue head of free list (fatal err if none) + rq_deqh - dequeue head of list + rq_enqh - enqueue at head of list + rq_enqt - enqueue at tail of list +*/ + +t_bool rq_deqf (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 */ +return OK; +} + +int32 rq_deqh (int32 *lh) +{ +int32 ptr = *lh; /* head of list */ + +if (ptr) *lh = rq_pkt[ptr].link; /* next */ +return ptr; +} + +void rq_enqh (int32 *lh, int32 pkt) +{ +if (pkt == 0) return; /* any pkt? */ +rq_pkt[pkt].link = *lh; /* link is old lh */ +*lh = pkt; /* pkt is new lh */ +return; +} + +void rq_enqt (int32 *lh, int32 pkt) +{ +if (pkt == 0) return; /* any pkt? */ +rq_pkt[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 */ +return; +} + +/* Packet and descriptor handling */ + +/* Get packet from command ring */ + +t_bool rq_getpkt (int32 *pkt) +{ +uint32 desc; +t_addr addr; + +if (!rq_getdesc (&rq_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 */ +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 */ +} + +/* 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 rq_putpkt (int32 pkt, t_bool qt) +{ +uint32 desc, lnt, cr; +t_addr addr; + +if (pkt == 0) return OK; /* any packet? */ +if (!rq_getdesc (&rq_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 */ + return OK; } +addr = desc & UQ_ADDR; /* get Q22 addr */ +lnt = rq_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 = (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 */ +} + +/* Get a descriptor from the host */ + +t_bool rq_getdesc (struct uq_ring *ring, uint32 *desc) +{ +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 */ +*desc = ((uint32) d[0]) | (((uint32) d[1]) << 16); +return OK; /* own? 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 rq_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, QB)) /* store desc */ + return rq_fatal (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); +return OK; +} + +/* Get unit descriptor for logical unit - trivial now, + but eventually, hide multiboard complexities here */ + +UNIT *rq_getucb (uint32 lu) +{ +UNIT *uptr; + +if (lu >= RQ_NUMDR) return NULL; +uptr = rq_dev.units + lu; +if (uptr -> flags & UNIT_DIS) return NULL; +return uptr; +} + +/* Hack unit flags */ + +void rq_setf_unit (int32 pkt, UNIT *uptr) +{ +uptr -> uf = (uptr -> uf & (UF_WPH | UF_RPL | UF_RMV)) | + (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... */ +return; +} + +/* Unit response fields */ + +void rq_putr_unit (int32 pkt, UNIT *uptr, uint32 lu, t_bool all) +{ +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; /* flags */ +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) | + (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; } +return; +} + +/* UQ_HDR and RSP_OP fields */ + +void rq_putr (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 */ + (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 */ +return; +} + +/* Post interrupt during init */ + +void rq_init_int (void) +{ +if ((rq_s1dat & SA_S1H_IE) && (rq_s1dat & SA_S1H_VEC)) { + SET_INT (RQ); } +return; +} + +/* Post interrupt during putpkt - note that NXMs are ignored! */ + +void rq_ring_int (struct uq_ring *ring) +{ +t_addr iadr = rq_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 */ +return; +} + +/* Return interrupt vector */ + +int32 rq_inta (void) +{ +return (VEC_Q + ((rq_s1dat & SA_S1H_VEC) << 2)); /* prog vector */ +} + +/* Fatal error */ + +t_bool rq_fatal (uint32 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 */ +return ERR; +} + +/* Set/clear hardware write lock */ + +t_stat rq_set_wlk (UNIT *uptr, int32 val, char *cptr, void *desc) +{ +uint32 dtyp = GET_DTYPE (uptr -> flags); /* get drive type */ + +if (drv_tab[dtyp].flgs & RQDF_RO) return SCPE_NOFNC; /* not on read only */ +if (val || (uptr -> flags & UNIT_RO)) + uptr -> uf = uptr -> uf | UF_WPH; /* copy to uf */ +else uptr -> uf = uptr -> uf & ~UF_WPH; +return SCPE_OK; +} + +/* Show write lock status */ + +t_stat rq_show_wlk (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +uint32 dtyp = GET_DTYPE (uptr -> flags); /* get drive type */ + +if (drv_tab[dtyp].flgs & RQDF_RO) fprintf (st, "read only"); +else if (uptr -> uf & UF_WPH) fprintf (st, "write locked"); +else fprintf (st, "write enabled"); +return SCPE_OK; +} + +/* Change unit size */ + +t_stat rq_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)].lbn * RQ_NUMBY; +if (drv_tab[GET_DTYPE (val)].flgs & RQDF_RMV) + uptr -> uf = uptr -> uf | UF_RMV; +else uptr -> uf = uptr -> uf & ~UF_RMV; +if (val == RRD40_DTYPE) uptr -> uf = uptr -> uf | UF_WPH; +return SCPE_OK; +} + +/* Device attach */ + +t_stat rq_attach (UNIT *uptr, char *cptr) +{ +int32 dtyp = GET_DTYPE (uptr -> flags); +t_stat r; + +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 ((drv_tab[dtyp].flgs & RQDF_RO) || (uptr -> flags & UNIT_RO)) + uptr -> uf = uptr -> uf | UF_WPH; +return SCPE_OK; +} + +/* Device detach */ + +t_stat rq_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); /* clr onl, atn pend */ +uptr -> uf = uptr -> uf & (UF_WPH | UF_RPL | UF_RMV); /* clr unit flgs */ +return SCPE_OK; +} + +/* Device reset */ + +t_stat rq_reset (DEVICE *dptr) +{ +int32 i, j; + +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; 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; + sim_cancel (uptr); /* clr activity */ + uptr -> flags = uptr -> flags & ~UNIT_ONL; /* not online */ + if (drv_tab[GET_DTYPE (uptr -> flags)].flgs & RQDF_RMV) + uptr -> uf = UF_RPL | UF_RMV; /* init flags */ + else uptr -> uf = UF_RPL; + 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 */ +if (rqxb == NULL) rqxb = calloc (RQ_MAXFR >> 1, sizeof (unsigned int16)); +if (rqxb == NULL) return SCPE_MEM; +return SCPE_OK; +} + +/* Device bootstrap */ + +#if defined (VM_PDP11) + +#define BOOT_START 016000 /* start */ +#define BOOT_UNIT 016006 /* unit number */ +#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) + +static const uint16 boot_rom[] = { + + /* Four step init process */ + + 0012706, 0016000, /* st: mov #st,sp */ + 0012700, 0000000, /* mov #unit,r0 */ + 0012701, 0172150, /* mov #172150, r1 ; ip addr */ + 0012704, 0016160, /* mov #it, r4 */ + 0012705, 0004000, /* mov #4000,r5 ; s1 mask */ + 0010102, /* mov r1,r2 */ + 0005022, /* clr (r2)+ ; init */ + 0005712, /* 10$: tst (r2) ; err? */ + 0100001, /* bpl 20$ */ + 0000000, /* halt */ + 0030512, /* 20$: bit r5,(r2) ; step set? */ + 0001773, /* beq 10$ ; wait */ + 0012412, /* mov (r4)+,(r2) ; send next */ + 0006305, /* asl r5 ; next mask */ + 0100370, /* bpl 10$ ; s4 done? */ + + /* Send ONL, READ commands */ + + 0105714, /* 30$: tstb (r4) ; end tbl? */ + 0001434, /* beq done ; 0 = yes */ + 0012702, 0007000, /* mov #rpkt-4,r2 ; clr pkts */ + 0005022, /* 40$: clr (r2)+ */ + 0020227, 0007204, /* cmp r2,#comm */ + 0103774, /* blo 40$ */ + 0112437, 0007100, /* movb (r4)+,cpkt-4 ; set lnt */ + 0110037, 0007110, /* movb r0,cpkt+4 ; set unit */ + 0112437, 0007114, /* movb (r4)+,cpkt+10 ; set op */ + 0112437, 0007121, /* movb (r4)+,cpkt+15 ; set param */ + 0012722, 0007004, /* mov #rpkt,(r2)+ ; rq desc */ + 0010522, /* mov r5,(r2)+ ; rq own */ + 0012722, 0007104, /* mov #ckpt,(r2)+ ; cq desc */ + 0010512, /* mov r5,(r2) ; cq own */ + 0024242, /* cmp -(r2),-(r2) ; back up */ + 0005711, /* tst (r1) ; wake ctrl */ + 0005712, /* 50$: tst (r2) ; rq own clr? */ + 0100776, /* bmi 50$ ; wait */ + 0005737, 0007016, /* tst rpkt+12 ; stat ok? */ + 0001743, /* beq 30$ ; next cmd */ + 0000000, /* halt */ + + /* Boot block read in, jump to 0 */ + + 0005002, /* done: clr r2 */ + 0005003, /* clr r3 */ + 0012705, 0052504, /* mov #"DU,r5 */ + 0010704, /* mov pc,r4 */ + 0005007, /* clr pc */ + + /* Data */ + + 0100000, /* it: no ints, ring sz = 1 */ + 0007204, /* .word comm */ + 0000000, /* .word 0 */ + 0000001, /* .word 1 */ + 0004420, /* .byte 20,11 */ + 0020000, /* .byte 0,40 */ + 0001041, /* .byte 41,2 */ + 0000000 +}; + +t_stat rq_boot (int32 unitno) +{ +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; +saved_PC = BOOT_START; +return SCPE_OK; +} + +#else + +t_stat rq_boot (int32 unitno) +{ +return SCPE_NOFNC; +} +#endif + +/* Special show commands */ + +void rq_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", + rp -> ba, rp -> idx >> 2, rp -> lnt >> 2); +#else +fprintf (st, "ring, base = %x, index = %d, length = %d", + rp -> ba, rp -> idx >> 2, rp -> lnt >> 2); +#endif +for (i = 0; i < rp -> lnt >> 2; i = i++) { + if ((i % RQ_SH_DPL) == 0) fprintf (st, "\n"); + if (Map_ReadW (rp -> ba + (i << 2), 4, d, QB)) { + fprintf (st, " %3d: non-existent memory", i); + break; } + desc = ((uint32) d[0]) | (((uint32) d[1]) << 16); +#if defined (VM_PDP11) + fprintf (st, " %3d: %011o", i, desc); +#else + fprintf (st, " %3d: %08x", i, desc); +#endif + } +return; +} + +void rq_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", + pkt, cr, typ, cid); +for (i = 0; i < RQ_SH_MAX; i = i + RQ_SH_PPL) { + fprintf (st, "\n %2d:", i); + for (j = i; (j < (i + RQ_SH_PPL)); j++) +#if defined (VM_PDP11) + fprintf (st, " %06o", rq_pkt[pkt].d[j]); +#else + fprintf (st, " %04x", rq_pkt[pkt].d[j]); +#endif + } +return; +} + +t_stat rq_show_unitq (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +int32 pkt, u = uptr - rq_dev.units; + +if (rq_csta != CST_UP) { + fprintf (st, "Controller is not initialized"); + return SCPE_OK; } +if ((uptr -> flags & UNIT_ONL) == 0) { + if (uptr -> flags & UNIT_ATT) + fprintf (st, "Unit %d is available", u); + else fprintf (st, "Unit %d is offline", u); + return SCPE_OK; } +if (uptr -> cpkt) { + fprintf (st, "Unit %d current ", u); + rq_show_pkt (st, uptr -> cpkt); + if (pkt = uptr -> pktq) { + do { fprintf (st, "\nUnit %d queued ", u); + rq_show_pkt (st, pkt); } + while (pkt = rq_pkt[pkt].link); } } +else fprintf (st, "Unit %d queues are empty", u); +return SCPE_OK; +} + +t_stat rq_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc) +{ +int32 i, pkt; + +if (rq_csta != CST_UP) { + fprintf (st, "Controller is not initialized"); + return SCPE_OK; } +if (val & RQ_SH_RI) { + if (rq_pip) fprintf (st, "Polling in progress\n"); + fprintf (st, "Command "); + rq_show_ring (st, &rq_cq); + fprintf (st, "\nResponse "); + rq_show_ring (st, &rq_rq); + } +if (val & RQ_SH_FR) { + if (val & RQ_SH_RI) fprintf (st, "\n"); + if (pkt = rq_freq) { + for (i = 0; pkt != 0; i++, pkt = rq_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); } } + else fprintf (st, "Free queue is empty"); + } +if (val & RQ_SH_RS) { + if (val & (RQ_SH_RI | RQ_SH_FR)) fprintf (st, "\n"); + if (pkt = rq_rspq) { + do { fprintf (st, "Response "); + rq_show_pkt (st, pkt); } + while (pkt = rq_pkt[pkt].link); } + else fprintf (st, "Response queue is empty"); + } +if (val & RQ_SH_UN) { + for (i = 0; i < RQ_NUMDR; i++) { + if ((val & (RQ_SH_RI | RQ_SH_FR | RQ_SH_RS)) || i) + fprintf (st, "\n"); + rq_show_unitq (st, &rq_unit[i], 0, NULL); } + } +return SCPE_OK; +} diff --git a/pdp11_rx.c b/PDP11/pdp11_rx.c similarity index 95% rename from pdp11_rx.c rename to PDP11/pdp11_rx.c index 99642ce2..16b10a0e 100644 --- a/pdp11_rx.c +++ b/PDP11/pdp11_rx.c @@ -25,6 +25,8 @@ rx RX11/RX01 floppy disk + 30-Nov-01 RMS Added read only unit, extended SET/SHOW support + 24-Nov-01 RMS Converted FLG to array 07-Sep-01 RMS Revised device disable and interrupt mechanisms 17-Jul-01 RMS Fixed warning from VC++ 6.0 26-Apr-01 RMS Added device enable/disable support @@ -48,6 +50,7 @@ #define RX_M_NUMDR 01 #define UNIT_V_WLK (UNIT_V_UF) /* write locked */ #define UNIT_WLK (1u << UNIT_V_UF) +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ #define IDLE 0 /* idle state */ #define RWDS 1 /* rw, sect next */ @@ -139,8 +142,7 @@ REG rx_reg[] = { { DRDATA (CTIME, rx_cwait, 24), PV_LEFT }, { DRDATA (STIME, rx_swait, 24), PV_LEFT }, { DRDATA (XTIME, rx_xwait, 24), PV_LEFT }, - { FLDATA (FLG0, rx_unit[0].flags, UNIT_V_WLK), REG_HRO }, - { FLDATA (FLG1, rx_unit[1].flags, UNIT_V_WLK), REG_HRO }, + { 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, rx_enb, 0), REG_HRO }, @@ -316,7 +318,7 @@ case RWDT: /* wait for track */ 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_WLK) { /* write and locked? */ + 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; } diff --git a/pdp11_stddev.c b/PDP11/pdp11_stddev.c similarity index 94% rename from pdp11_stddev.c rename to PDP11/pdp11_stddev.c index 3fea03a4..0ef8a245 100644 --- a/pdp11_stddev.c +++ b/PDP11/pdp11_stddev.c @@ -27,6 +27,8 @@ tti,tto DL11 terminal input/output clk KW11L line frequency clock + 29-Nov-01 RMS Added read only unit support + 09-Nov-01 RMS Added RQDX3 support 07-Oct-01 RMS Upgraded clock to full KW11L for RSTS/E autoconfigure 07-Sep-01 RMS Moved function prototypes, revised interrupt mechanism 17-Jul-01 RMS Moved function prototype @@ -60,6 +62,7 @@ int32 tto_csr = 0; /* control/status */ int32 clk_csr = 0; /* control/status */ int32 clk_tps = 60; /* ticks/second */ int32 tmxr_poll = CLK_DELAY; /* term mux poll */ +int32 tmr_poll = CLK_DELAY; /* timer poll */ t_stat ptr_svc (UNIT *uptr); t_stat ptp_svc (UNIT *uptr); @@ -84,7 +87,8 @@ t_stat ptp_detach (UNIT *uptr); */ UNIT ptr_unit = { - UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_IN_WAIT }; + UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), + SERIAL_IN_WAIT }; REG ptr_reg[] = { { ORDATA (BUF, ptr_unit.buf, 8) }, @@ -500,6 +504,7 @@ clk_csr = clk_csr | CSR_DONE; /* set done */ if (clk_csr & CSR_IE) SET_INT (CLK); t = sim_rtc_calb (clk_tps); /* calibrate clock */ sim_activate (&clk_unit, t); /* reactivate unit */ +tmr_poll = t; /* set timer poll */ tmxr_poll = t; /* set mux poll */ return SCPE_OK; } @@ -509,6 +514,7 @@ t_stat clk_reset (DEVICE *dptr) clk_csr = 0; CLR_INT (CLK); sim_activate (&clk_unit, clk_unit.wait); /* activate unit */ +tmr_poll = clk_unit.wait; /* set timer poll */ tmxr_poll = clk_unit.wait; /* set mux poll */ return SCPE_OK; } diff --git a/pdp11_sys.c b/PDP11/pdp11_sys.c similarity index 95% rename from pdp11_sys.c rename to PDP11/pdp11_sys.c index 0df7e8dc..7496d880 100644 --- a/pdp11_sys.c +++ b/PDP11/pdp11_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. + 29-Nov-01 RMS Added read only unit support 17-Sep-01 RMS Removed multiconsole support 26-Aug-01 RMS Added DZ11 20-Aug-01 RMS Updated bad block inquiry @@ -48,10 +49,10 @@ extern DEVICE ptr_dev, ptp_dev; extern DEVICE tti_dev, tto_dev; extern DEVICE lpt_dev, clk_dev; extern DEVICE dz_dev; -extern DEVICE rk_dev, rx_dev; -extern DEVICE rl_dev, rp_dev; -extern DEVICE dt_dev, tm_dev; -extern DEVICE ts_dev; +extern DEVICE rk_dev, rl_dev; +extern DEVICE rp_dev, rq_dev; +extern DEVICE rx_dev, dt_dev; +extern DEVICE tm_dev, ts_dev; /* extern DEVICE hk_dev; */ extern UNIT cpu_unit; extern REG cpu_reg[]; @@ -80,8 +81,8 @@ DEVICE *sim_devices[] = { &tti_dev, &tto_dev, &lpt_dev, &clk_dev, &dz_dev, - &rk_dev, /* &hk_dev, */ - &rl_dev, &rp_dev, + &rk_dev, &rl_dev, + &rp_dev, &rq_dev, &rx_dev, &dt_dev, &tm_dev, &ts_dev, NULL }; @@ -107,7 +108,8 @@ const char *sim_stop_messages[] = { "Breakpoint", "Wait state", "Trap vector fetch abort", - "Trap stack push abort" }; + "Trap stack push abort", + "RQDX3 consistency error" }; /* Binary loader. @@ -210,6 +212,7 @@ 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 (!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; diff --git a/pdp11_tc.c b/PDP11/pdp11_tc.c similarity index 91% rename from pdp11_tc.c rename to PDP11/pdp11_tc.c index f48a6fed..7b4413cd 100644 --- a/pdp11_tc.c +++ b/PDP11/pdp11_tc.c @@ -25,6 +25,9 @@ tc TC11/TU56 DECtape + 30-Nov-01 RMS Added read only unit, extended SET/SHOW support + 24-Nov-01 RMS Converted POS, STATT, LASTT to arrays + 09-Nov-01 RMS Added bus map support 15-Sep-01 RMS Integrated debug logging 27-Sep-01 RMS Fixed interrupt after stop for RSTS/E 07-Sep-01 RMS Revised device disable and interrupt mechanisms @@ -86,6 +89,7 @@ #define UNIT_W_UF 3 /* saved flag width */ #define STATE u3 /* unit state */ #define LASTT u4 /* last time update */ +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ /* System independent DECtape constants */ @@ -241,7 +245,7 @@ extern uint16 *M; /* memory */ extern int32 int_req[IPL_HLVL]; extern UNIT cpu_unit; extern int32 sim_switches; -extern int32 pdp11_log; +extern int32 cpu_log; extern FILE *sim_log; int32 tcst = 0; /* status */ int32 tccm = 0; /* command */ @@ -311,46 +315,14 @@ REG dt_reg[] = { { DRDATA (DCTIME, dt_dctime, 31), REG_NZ }, { ORDATA (SUBSTATE, dt_substate, 1) }, { DRDATA (LBLK, dt_logblk, 12), REG_HIDDEN }, - { DRDATA (POS0, dt_unit[0].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS1, dt_unit[1].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS2, dt_unit[2].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS3, dt_unit[3].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS4, dt_unit[4].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS5, dt_unit[5].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS6, dt_unit[6].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS7, dt_unit[7].pos, 31), PV_LEFT + REG_RO }, - { ORDATA (STATT0, dt_unit[0].STATE, 18), REG_RO }, - { ORDATA (STATT1, dt_unit[1].STATE, 18), REG_RO }, - { ORDATA (STATT2, dt_unit[2].STATE, 18), REG_RO }, - { ORDATA (STATT3, dt_unit[3].STATE, 18), REG_RO }, - { ORDATA (STATT4, dt_unit[4].STATE, 18), REG_RO }, - { ORDATA (STATT5, dt_unit[5].STATE, 18), REG_RO }, - { ORDATA (STATT6, dt_unit[6].STATE, 18), REG_RO }, - { ORDATA (STATT7, dt_unit[7].STATE, 18), REG_RO }, - { DRDATA (LASTT0, dt_unit[0].LASTT, 32), REG_HRO }, - { DRDATA (LASTT1, dt_unit[1].LASTT, 32), REG_HRO }, - { DRDATA (LASTT2, dt_unit[2].LASTT, 32), REG_HRO }, - { DRDATA (LASTT3, dt_unit[3].LASTT, 32), REG_HRO }, - { DRDATA (LASTT4, dt_unit[4].LASTT, 32), REG_HRO }, - { DRDATA (LASTT5, dt_unit[5].LASTT, 32), REG_HRO }, - { DRDATA (LASTT6, dt_unit[6].LASTT, 32), REG_HRO }, - { DRDATA (LASTT7, dt_unit[7].LASTT, 32), REG_HRO }, - { GRDATA (FLG0, dt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG1, dt_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG2, dt_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG3, dt_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG4, dt_unit[4].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG5, dt_unit[5].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG6, dt_unit[6].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG7, dt_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, + { URDATA (POS, dt_unit[0].pos, 10, 31, 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) }, + { URDATA (FLG, dt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, + DT_NUMDR, REG_HRO) }, { FLDATA (*DEVENB, dt_enb, 0), REG_HRO }, { NULL } }; @@ -437,8 +409,8 @@ case 001: /* TCCM */ 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_WLK)) || - ((fnc == FNC_WRIT) && (uptr -> flags & UNIT_WLK))) + ((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? */ @@ -712,7 +684,7 @@ int32 fnc = DTS_GETFNC (uptr -> STATE); int32 *bptr = uptr -> filebuf; int32 unum = uptr - dt_dev.units; int32 blk, wrd, relpos, dat; -t_addr ma, ba; +t_addr ma, mma, ba; /* Motion cases @@ -775,11 +747,12 @@ case FNC_READ: /* read */ tcwc = tcwc & DMASK; /* incr MA, WC */ tcba = tcba & DMASK; ma = (CSR_GETMEX (tccm) << 16) | tcba; /* form 18b addr */ - if (ma >= MEMSIZE) { /* nx mem? */ + if (!Map_Addr (ma, &mma) || /* map addr */ + !ADDR_IS_MEM (mma)) { /* nx mem? */ dt_seterr (uptr, STA_NXM); break; } ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */ - M[ma >> 1] = tcdt = bptr[ba] & DMASK; /* read word */ + M[mma >> 1] = tcdt = bptr[ba] & DMASK; /* read word */ tcwc = (tcwc + 1) & DMASK; /* incr MA, WC */ tcba = (tcba + 2) & DMASK; if (tcba <= 1) tccm = CSR_INCMEX (tccm); @@ -806,10 +779,11 @@ case FNC_WRIT: /* write */ 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 (ma >= MEMSIZE) { /* nx mem? */ + if (!Map_Addr (ma, &mma) || /* map addr */ + !ADDR_IS_MEM (mma)) { /* nx mem? */ dt_seterr (uptr, STA_NXM); break; } - else tcdt = M[ma >> 1]; /* get word */ + else tcdt = M[mma >> 1]; /* get word */ tcwc = (tcwc + 1) & DMASK; /* incr MA, WC */ tcba = (tcba + 2) & DMASK; if (tcba <= 1) tccm = CSR_INCMEX (tccm); } @@ -1117,7 +1091,7 @@ if (sim_is_active (uptr)) { /* active? cancel op */ tccm = tccm | CSR_ERR | CSR_DONE; if (tccm & CSR_IE) SET_INT (DTA); } uptr -> STATE = uptr -> pos = 0; } -if (uptr -> hwmark) { /* any data? */ +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? */ diff --git a/pdp11_tm.c b/PDP11/pdp11_tm.c similarity index 84% rename from pdp11_tm.c rename to PDP11/pdp11_tm.c index c400e5da..3fbfb842 100644 --- a/pdp11_tm.c +++ b/PDP11/pdp11_tm.c @@ -25,6 +25,9 @@ tm TM11/TU10 magtape + 30-Nov-01 RMS Added read only unit, extended SET/SHOW support + 24-Nov-01 RMS Converted UST, POS, FLG to arrays + 09-Nov-01 RMS Added bus map support 18-Oct-01 RMS Added stub diagnostic register (found by Thord Nilson) 07-Sep-01 RMS Revised device disable and interrupt mechanisms 26-Apr-01 RMS Added device enable/disable support @@ -64,8 +67,8 @@ #define UNIT_W_UF 2 /* saved user flags */ #define USTAT u3 /* unit status */ #define UNUM u4 /* unit number */ -#define DBSIZE (1 << 16) /* max data buf */ -#define DBMASK (SBSIZE - 1) +#define TM_MAXFR (1 << 16) /* max transfer */ +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ /* Command - tm_cmd */ @@ -133,7 +136,7 @@ extern uint16 *M; /* memory */ extern int32 int_req[IPL_HLVL]; -extern UNIT cpu_unit; +uint8 *tmxb = NULL; /* xfer buffer */ int32 tm_sta = 0; /* status register */ int32 tm_cmd = 0; /* command register */ int32 tm_ca = 0; /* current address */ @@ -152,7 +155,7 @@ t_stat tm_boot (int32 unitno); void tm_go (UNIT *uptr); int32 tm_updcsta (UNIT *uptr); void tm_set_done (void); -t_stat tm_vlock (UNIT *uptr, int32 val); +t_stat tm_vlock (UNIT *uptr, int32 val, char *cptr, void *desc); /* MT data structures @@ -185,38 +188,11 @@ REG tm_reg[] = { { FLDATA (IE, tm_cmd, CSR_V_IE) }, { FLDATA (STOP_IOE, tm_stopioe, 0) }, { DRDATA (TIME, tm_time, 24), PV_LEFT }, - { ORDATA (UST0, tm_unit[0].USTAT, 16) }, - { ORDATA (UST1, tm_unit[1].USTAT, 16) }, - { ORDATA (UST2, tm_unit[2].USTAT, 16) }, - { ORDATA (UST3, tm_unit[3].USTAT, 16) }, - { ORDATA (UST4, tm_unit[4].USTAT, 16) }, - { ORDATA (UST5, tm_unit[5].USTAT, 16) }, - { ORDATA (UST6, tm_unit[6].USTAT, 16) }, - { ORDATA (UST7, tm_unit[7].USTAT, 16) }, - { DRDATA (POS0, tm_unit[0].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS1, tm_unit[1].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS2, tm_unit[2].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS3, tm_unit[3].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS4, tm_unit[4].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS5, tm_unit[5].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS6, tm_unit[6].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS7, tm_unit[7].pos, 31), PV_LEFT + REG_RO }, - { GRDATA (FLG0, tm_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG1, tm_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG2, tm_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG3, tm_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG4, tm_unit[4].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG5, tm_unit[5].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG6, tm_unit[6].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG7, tm_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, + { URDATA (UST, tm_unit[0].USTAT, 8, 16, 0, TM_NUMDR, 0) }, + { URDATA (POS, tm_unit[0].pos, 10, 31, 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) }, { FLDATA (*DEVENB, tm_enb, 0), REG_HRO }, { NULL } }; @@ -326,7 +302,7 @@ f = GET_FNC (tm_cmd); /* get function */ 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_WLK))) { /* write locked? */ + (uptr -> flags & UNIT_WPRT))) { /* write locked? */ tm_sta = tm_sta | STA_ILL; /* illegal */ tm_set_done (); /* set done */ return; } @@ -352,19 +328,17 @@ return; t_stat tm_svc (UNIT *uptr) { -int32 f, i, p, err; +int32 f, i, t, err; t_addr xma; t_stat rval; t_mtrlnt tbc, cbc; -uint16 c; -static uint8 dbuf[DBSIZE]; static t_mtrlnt bceof = { 0 }; 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_WLK)? STA_WLK: 0); + ((uptr -> flags & UNIT_WPRT)? STA_WLK: 0); else uptr -> USTAT = 0; if (uptr -> UNUM == GET_UNIT (tm_cmd)) { /* selected? */ tm_set_done (); /* set done */ @@ -380,7 +354,7 @@ 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_WLK)) { /* 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 */ @@ -408,38 +382,31 @@ case MTC_READ: /* read */ tbc = MTRL (tbc); /* ignore error flag */ if (tbc > cbc) tm_sta = tm_sta | STA_RLE; /* wrong size? */ if (tbc < cbc) cbc = tbc; /* use smaller */ - i = fxread (dbuf, sizeof (int8), cbc, uptr -> fileref); - for ( ; i < tbc; i++) dbuf[i] = 0; /* fill with 0's */ + i = fxread (tmxb, sizeof (int8), cbc, uptr -> fileref); err = ferror (uptr -> fileref); - for (i = 0; i < cbc; i++) { /* copy buffer */ - if (xma >= MEMSIZE) { /* nx memory? */ - tm_sta = tm_sta | STA_NXM; - break; } - p = xma >> 1; /* word address */ - c = dbuf[i]; /* character */ - if (i & 1) M[p] = (M[p] & 0377) | (c << 8); - else M[p] = (M[p] & 0177400) | c; - xma = (xma + 1) & 0777777; - tm_bc = (tm_bc + 1) & 0177777; } - uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) + + for ( ; i < cbc; i++) tmxb[i] = 0; /* fill with 0's */ + if (t = Map_WriteB (xma, cbc, tmxb, UB)) { /* 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 */ (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 */ + 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); - for (i = 0; i < cbc; i++) { /* copy buf to tape */ - if (xma >= MEMSIZE) { /* nx memory? */ - tm_sta = tm_sta | STA_NXM; - break; } - if (i & 1) dbuf[i] = (M[xma >> 1] >> 8) & 0377; - else dbuf[i] = M[xma >> 1] & 0377; - xma = (xma + 1) & 0777777; - tm_bc = (tm_bc + 1) & 0177777; } - fxwrite (dbuf, sizeof (int8), cbc, uptr -> fileref); + fxwrite (tmxb, sizeof (int8), cbc, uptr -> fileref); fxwrite (&cbc, sizeof (t_mtrlnt), 1, uptr -> fileref); err = ferror (uptr -> fileref); - uptr -> pos = uptr -> pos + ((cbc + 1) & ~1) + + 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: @@ -546,8 +513,10 @@ for (u = 0; u < TM_NUMDR; u++) { /* loop thru units */ sim_cancel (uptr); /* cancel activity */ if (uptr -> flags & UNIT_ATT) uptr -> USTAT = STA_ONL | ((uptr -> pos)? 0: STA_BOT) | - ((uptr -> flags & UNIT_WLK)? STA_WLK: 0); + ((uptr -> flags & UNIT_WPRT)? STA_WLK: 0); else uptr -> USTAT = 0; } +if (tmxb == NULL) tmxb = calloc (TM_MAXFR, sizeof (unsigned int8)); +if (tmxb == NULL) return SCPE_MEM; return SCPE_OK; } @@ -559,7 +528,7 @@ t_stat r; r = attach_unit (uptr, cptr); if (r != SCPE_OK) return r; -uptr -> USTAT = STA_ONL | STA_BOT | ((uptr -> flags & UNIT_WLK)? STA_WLK: 0); +uptr -> USTAT = STA_ONL | STA_BOT | ((uptr -> flags & UNIT_WPRT)? STA_WLK: 0); if (uptr -> UNUM == GET_UNIT (tm_cmd)) tm_updcsta (uptr); return r; } @@ -575,9 +544,11 @@ return detach_unit (uptr); /* Write lock/enable routine */ -t_stat tm_vlock (UNIT *uptr, int32 val) +t_stat tm_vlock (UNIT *uptr, int32 val, char *cptr, void *desc) { -if ((uptr -> flags & UNIT_ATT) && val) uptr -> USTAT = uptr -> USTAT | STA_WLK; +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); return SCPE_OK; diff --git a/pdp11_ts.c b/PDP11/pdp11_ts.c similarity index 84% rename from pdp11_ts.c rename to PDP11/pdp11_ts.c index bbe9ffb1..ff03b4c7 100644 --- a/pdp11_ts.c +++ b/PDP11/pdp11_ts.c @@ -25,6 +25,8 @@ ts TS11/TSV05 magtape + 30-Nov-01 RMS Added read only unit, extended SET/SHOW support + 09-Nov-01 RMS Added bus map, VAX support 15-Oct-01 RMS Integrated debug logging across simulator 27-Sep-01 RMS Implemented extended characteristics and status Fixed bug in write characteristics status return @@ -47,14 +49,51 @@ If the byte count is odd, the record is padded with an extra byte of junk. File marks are represented by a single record length of 0. End of tape is two consecutive end of file marks. + + The TS11 functions in three 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 Unibus 22b systems - the TS11 behaves as an 18b Unibus + peripheral and must go through the I/O map + - VAX Q22 systems - the TS11 must go through the I/O map */ +#if defined (USE_INT64) /* VAX version */ +#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 ADDRTEST 0177700 +#define DMASK 0xFFFF +extern int32 ReadB (t_addr pa); +extern void WriteB (t_addr pa, int32 val); +extern int32 ReadW (t_addr pa); +extern void WriteW (t_addr pa, int32 val); + +#else /* PDP11 version */ #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) +extern uint16 *M; +extern int32 cpu_18b, cpu_ubm; +#define ReadB(p) ((M[(p) >> 1] >> (((p) & 1)? 8: 0)) & 0377) +#define WriteB(p,v) M[(p) >> 1] = ((p) & 1)? \ + ((M[(p) >> 1] & 0377) | ((v) << 8)): \ + ((M[(p) >> 1] & ~0377) | (v)) +#define ReadW(p) M[(p) >> 1] +#define WriteW(p,v) M[(p) >> 1] = (v) +#endif #define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ #define UNIT_WLK (1 << UNIT_V_WLK) -#define DBSIZE (1 << 16) /* data buffer */ - +#define TS_MAXFR (1 << 16) /* max xfer */ +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ + /* TSBA/TSDB - 17772520: base address/data buffer register read: most recent memory address @@ -212,16 +251,11 @@ #define WCHX_HDS 0000040 /* high density */ #define MAX(a,b) (((a) >= (b))? (a): (b)) -#define READ_BYTE(p) ((M[(p) >> 1] >> (((p) & 1)? 8: 0)) & 0377) -#define WRITE_BYTE(d,p) M[(p) >> 1] = (p & 1)? \ - ((M[(p) >> 1] & 0377) | ((d) << 8)): \ - ((M[(p) >> 1] & ~0377) | (d)) -extern uint16 *M; /* memory */ extern int32 int_req[IPL_HLVL]; extern UNIT cpu_unit; extern FILE *sim_log; -extern int32 pdp11_log; +uint8 *tsxb = NULL; /* xfer buffer */ int32 tssr = 0; /* status register */ int32 tsba = 0; /* mem addr */ int32 tsdbx = 0; /* data buf ext */ @@ -233,8 +267,7 @@ int32 ts_ownm = 0; /* tape owns msg */ int32 ts_qatn = 0; /* queued attn */ int32 ts_bcmd = 0; /* boot cmd */ int32 ts_time = 10; /* record latency */ -int32 ts_enb = 0; /* device enable */ -static uint8 dbuf[DBSIZE]; +int32 ts_enb = TS_DF_ENB; /* device enable */ t_stat ts_svc (UNIT *uptr); t_stat ts_reset (DEVICE *dptr); @@ -257,25 +290,25 @@ void ts_endcmd (int32 ssf, int32 xs0f, int32 msg); UNIT ts_unit = { UDATA (&ts_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }; REG ts_reg[] = { - { ORDATA (TSSR, tssr, 16) }, - { ORDATA (TSBA, tsba, 22) }, - { ORDATA (TSDBX, tsdbx, 8) }, - { ORDATA (CHDR, cmdhdr, 16) }, - { ORDATA (CADL, cmdadl, 16) }, - { ORDATA (CADH, cmdadh, 16) }, - { ORDATA (CLNT, cmdlnt, 16) }, - { ORDATA (MHDR, msghdr, 16) }, - { ORDATA (MRFC, msgrfc, 16) }, - { ORDATA (MXS0, msgxs0, 16) }, - { ORDATA (MXS1, msgxs1, 16) }, - { ORDATA (MXS2, msgxs2, 16) }, - { ORDATA (MXS3, msgxs3, 16) }, - { ORDATA (MSX4, msgxs4, 16) }, - { ORDATA (WADL, wchadl, 16) }, - { ORDATA (WADH, wchadh, 16) }, - { ORDATA (WLNT, wchlnt, 16) }, - { ORDATA (WOPT, wchopt, 16) }, - { ORDATA (WXOPT, wchxopt, 16) }, + { GRDATA (TSSR, tssr, TS_RDX, 16, 0) }, + { GRDATA (TSBA, tsba, TS_RDX, 22, 0) }, + { GRDATA (TSDBX, tsdbx, TS_RDX, 8, 0) }, + { GRDATA (CHDR, cmdhdr, TS_RDX, 16, 0) }, + { GRDATA (CADL, cmdadl, TS_RDX, 16, 0) }, + { GRDATA (CADH, cmdadh, TS_RDX, 16, 0) }, + { GRDATA (CLNT, cmdlnt, TS_RDX, 16, 0) }, + { GRDATA (MHDR, msghdr, TS_RDX, 16, 0) }, + { GRDATA (MRFC, msgrfc, TS_RDX, 16, 0) }, + { GRDATA (MXS0, msgxs0, TS_RDX, 16, 0) }, + { GRDATA (MXS1, msgxs1, TS_RDX, 16, 0) }, + { GRDATA (MXS2, msgxs2, TS_RDX, 16, 0) }, + { GRDATA (MXS3, msgxs3, TS_RDX, 16, 0) }, + { GRDATA (MSX4, msgxs4, TS_RDX, 16, 0) }, + { GRDATA (WADL, wchadl, TS_RDX, 16, 0) }, + { GRDATA (WADH, wchadh, TS_RDX, 16, 0) }, + { GRDATA (WLNT, wchlnt, TS_RDX, 16, 0) }, + { GRDATA (WOPT, wchopt, TS_RDX, 16, 0) }, + { GRDATA (WXOPT, wchxopt, TS_RDX, 16, 0) }, { FLDATA (INT, IREQ (TS), INT_V_TS) }, { FLDATA (ATTN, ts_qatn, 0) }, { FLDATA (BOOT, ts_bcmd, 0) }, @@ -294,7 +327,7 @@ MTAB ts_mod[] = { DEVICE ts_dev = { "TS", &ts_unit, ts_reg, ts_mod, - 1, 10, 31, 1, 8, 8, + 1, 10, 31, 1, TS_RDX, 8, NULL, NULL, &ts_reset, &ts_boot, &ts_attach, &ts_detach }; @@ -319,6 +352,7 @@ return SCPE_OK; t_stat ts_wr (int32 data, int32 PA, int32 access) { int32 i; +t_addr pa; switch ((PA >> 1) & 01) { /* decode PA<1> */ case 0: /* TSDB */ @@ -333,7 +367,8 @@ case 0: /* TSDB */ msgrfc = msgxs1 = msgxs2 = msgxs3 = msgxs4 = 0; /* clr status */ CLR_INT (TS); /* clr int req */ for (i = 0; i < CMD_PLNT; i++) { /* get cmd pkt */ - if (ADDR_IS_MEM (tsba)) tscmdp[i] = M[(tsba >> 1)]; + if (Map_Addr (tsba, &pa) && ADDR_IS_MEM (pa)) + tscmdp[i] = ReadW (pa); else { ts_endcmd (TSSR_NXM + TC5, 0, MSG_ACK|MSG_MNEF|MSG_CFAIL); return SCPE_OK; } tsba = tsba + 2; } /* incr tsba */ @@ -342,6 +377,7 @@ case 0: /* TSDB */ break; case 1: /* TSSR */ if (PA & 1) { /* TSDBX */ + if (TS_18B) return SCPE_OK; /* not in TS11 */ if (tssr & TSSR_SSR) { /* ready? */ tsdbx = data; /* save */ if (data & TSDBX_BOOT) { @@ -463,7 +499,7 @@ int32 ts_readf (UNIT *uptr, int32 fc) { int32 i, st; t_mtrlnt tbc, wbc; -t_addr wa; +t_addr wa, pa; msgrfc = fc; if (st = ts_rdlntf (uptr, &tbc)) return st; /* read rec lnt */ @@ -473,15 +509,16 @@ if (tbc == 0) { /* tape mark? */ if (fc == 0) fc = 0200000; /* byte count */ tsba = (cmdadh << 16) | cmdadl; /* buf addr */ tbc = MTRL (tbc); /* ignore err flag */ -wbc = (tbc > DBSIZE)? DBSIZE: tbc; /* cap rec size */ +wbc = (tbc > TS_MAXFR)? TS_MAXFR: tbc; /* cap rec size */ wbc = (wbc > fc)? fc: wbc; /* cap buf size */ -i = fxread (dbuf, sizeof (uint8), wbc, uptr -> fileref); /* read record */ +i = fxread (tsxb, sizeof (uint8), wbc, uptr -> fileref); /* read record */ if (ferror (uptr -> fileref)) return XTC (XS0_EOT | XS0_RLS, TC2); -for ( ; i < wbc; i++) dbuf[i] = 0; /* fill with 0's */ +for ( ; i < wbc; i++) tsxb[i] = 0; /* fill with 0's */ uptr -> pos = uptr -> pos + ((tbc + 1) & ~1) + (2 * sizeof (t_mtrlnt)); for (i = 0; i < wbc; i++) { /* copy buffer */ wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply OPP */ - if (ADDR_IS_MEM (wa)) WRITE_BYTE (dbuf[i], wa); /* nxm? */ + if (Map_Addr (wa, &pa) && ADDR_IS_MEM (pa)) /* map addr, nxm? */ + WriteB (pa, tsxb[i]); /* no, store */ else { tssr = ts_updtssr (tssr | TSSR_NXM); /* set error */ return (XTC (XS0_RLS, TC4)); } tsba = tsba + 1; @@ -495,7 +532,7 @@ int32 ts_readr (UNIT *uptr, int32 fc) { int32 i, st; t_mtrlnt tbc, wbc; -t_addr wa; +t_addr wa, pa; msgrfc = fc; if (uptr -> pos == 0) { /* BOT? */ @@ -508,19 +545,20 @@ if (tbc == 0) { /* tape mark? */ if (fc == 0) fc = 0200000; /* byte count */ tsba = (cmdadh << 16) | cmdadl + fc; /* buf addr */ tbc = MTRL (tbc); /* ignore err flag */ -wbc = (tbc > DBSIZE)? DBSIZE: tbc; /* cap rec size */ +wbc = (tbc > TS_MAXFR)? TS_MAXFR: tbc; /* cap rec size */ wbc = (wbc > fc)? fc: wbc; /* cap buf size */ fseek (uptr -> fileref, uptr -> pos - sizeof (t_mtrlnt) - wbc, SEEK_SET); -i = fxread (dbuf, sizeof (uint8), wbc, uptr -> fileref); -for ( ; i < wbc; i++) dbuf[i] = 0; /* fill with 0's */ +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)); for (i = wbc; i > 0; i--) { /* copy buffer */ tsba = tsba - 1; - wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; - if (ADDR_IS_MEM (wa)) WRITE_BYTE (dbuf[i - 1], wa); + wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply OPP */ + if (Map_Addr (wa, &pa) && ADDR_IS_MEM (pa)) /* map addr, nxm? */ + WriteB (pa, tsxb[i - 1]); /* no, store */ else { tssr = ts_updtssr (tssr | TSSR_NXM); return (XTC (XS0_RLS, TC4)); } msgrfc = (msgrfc - 1) & DMASK; } @@ -532,20 +570,21 @@ return 0; int32 ts_write (UNIT *uptr, int32 fc) { int32 i; -t_addr wa; +t_addr wa, pa; msgrfc = fc; if (fc == 0) fc = 0200000; /* byte count */ tsba = (cmdadh << 16) | cmdadl; /* buf addr */ for (i = 0; i < fc; i++) { /* copy mem to buf */ - wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply opp */ - if (ADDR_IS_MEM (wa)) dbuf[i] = READ_BYTE (wa); /* nxm? */ + wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply OPP */ + if (Map_Addr (wa, &pa) && ADDR_IS_MEM (pa)) /* map addr, nxm? */ + tsxb[i] = ReadB (pa); /* no, store */ 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 (dbuf, sizeof (uint8), fc, 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; @@ -571,6 +610,8 @@ return XTC (XS0_TMK, TC0); t_stat ts_svc (UNIT *uptr) { int32 i, fnc, mod, st0, st1; +t_addr pa; + static const int32 fnc_mod[CMD_N_FNC] = { /* max mod+1 0 ill */ 0, 4, 0, 0, 1, 2, 1, 0, /* 00 - 07 */ 5, 3, 5, 1, 0, 0, 0, 1, /* 10 - 17 */ @@ -619,7 +660,7 @@ if ((fnc_flg[fnc] & FLG_MO) && /* mot+(vck|!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_WLK)) { /* 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 */ @@ -627,7 +668,7 @@ if ((((fnc == FNC_READ) && (mod == 1)) || /* read rev */ (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 & 0177700)) { /* buf addr > 22b? */ +if ((fnc_flg[fnc] & FLG_AD) && (cmdadh & ADDRTEST)) { /* buf addr > 22b? */ ts_endcmd (TC3, XS0_ILA, MSG_ACK | MSG_MILL | MSG_CFAIL); return SCPE_OK; } @@ -640,12 +681,13 @@ case FNC_GSTA: /* get status */ ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); /* send end packet */ return SCPE_OK; case FNC_WCHR: /* write char */ - if ((cmdadh & 0177700) || (cmdadl & 1) || (cmdlnt < 6)) { + if ((cmdadh & ADDRTEST) || (cmdadl & 1) || (cmdlnt < 6)) { ts_endcmd (TSSR_NBA | TC3, XS0_ILA, 0); break; } tsba = (cmdadh << 16) | cmdadl; for (i = 0; (i < WCH_PLNT) && (i < (cmdlnt / 2)); i++) { - if (ADDR_IS_MEM (tsba)) tswchp[i] = M[tsba >> 1]; + if (Map_Addr (tsba, &pa) && ADDR_IS_MEM (pa)) + tswchp[i] = ReadW (pa); else { ts_endcmd (TSSR_NBA | TSSR_NXM | TC5, 0, 0); return SCPE_OK; } tsba = tsba + 2; } @@ -745,9 +787,6 @@ case FNC_POS: break; } ts_cmpendcmd (st0, 0); break; } -if (DBG_LOG (LOG_TS)) - fprintf (sim_log, ">>TS: cmd=%o, mod=%o, buf=%o, lnt=%o, sta = %o, tc=%o, pos=%d\n", - fnc, mod, cmdadl, cmdlnt, msgxs0, (tssr & TSSR_TC) >> 1, ts_unit.pos); return SCPE_OK; } @@ -766,7 +805,7 @@ int32 ts_updxs0 (int32 t) t = (t & ~(XS0_ONL | XS0_WLK | XS0_BOT | XS0_IE)) | XS0_PET; if (ts_unit.flags & UNIT_ATT) { t = t | XS0_ONL; - if (ts_unit.flags & UNIT_WLK) t = t | XS0_WLK; + if (ts_unit.flags & UNIT_WPRT) t = t | XS0_WLK; if (ts_unit.pos == 0) t = (t | XS0_BOT) & ~XS0_EOT; } else t = t & ~XS0_EOT; if (cmdhdr & CMD_IE) t = t | XS0_IE; @@ -792,6 +831,7 @@ return; void ts_endcmd (int32 tc, int32 xs0, int32 msg) { int32 i; +t_addr pa; msgxs0 = ts_updxs0 (msgxs0 | xs0); /* update XS0 */ if (wchxopt & WCHX_HDS) msgxs4 = msgxs4 | XS4_HDS; /* update XS4 */ @@ -800,7 +840,8 @@ if (msg && !(tssr & TSSR_NBA)) { /* send end pkt */ msglnt = wchlnt - 4; /* exclude hdr, bc */ tsba = (wchadh << 16) | wchadl; for (i = 0; (i < MSG_PLNT) && (i < (wchlnt / 2)); i++) { - if (ADDR_IS_MEM (tsba)) M[tsba >> 1] = tsmsgp[i]; + if (Map_Addr (tsba, &pa) && ADDR_IS_MEM (pa)) + WriteW (pa, tsmsgp[i]); else { tssr = tssr | TSSR_NXM; tc = (tc & ~TSSR_TC) | TC4; break; } @@ -816,9 +857,11 @@ return; t_stat ts_reset (DEVICE *dptr) { int32 i; +#if defined (VM_PDP11) extern int32 tm_enb; if (ts_enb) tm_enb = 0; /* TM or TS */ +#endif ts_unit.pos = 0; tsba = tsdbx = 0; ts_ownc = ts_ownm = 0; @@ -830,6 +873,8 @@ for (i = 0; i < WCH_PLNT; i++) tswchp[i] = 0; for (i = 0; i < MSG_PLNT; i++) tsmsgp[i] = 0; msgxs0 = ts_updxs0 (XS0_VCK); CLR_INT (TS); +if (tsxb == NULL) tsxb = calloc (TS_MAXFR, sizeof (unsigned int8)); +if (tsxb == NULL) return SCPE_MEM; return SCPE_OK; } @@ -871,6 +916,7 @@ return r; /* Boot */ +#if defined (VM_PDP11) #define BOOT_START 01000 #define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) @@ -923,3 +969,10 @@ for (i = 0; i < BOOT_LEN; i++) saved_PC = BOOT_START; return SCPE_OK; } +#else + +t_stat ts_boot (int32 unitno) +{ +return SCPE_NOFNC; +} +#endif \ No newline at end of file diff --git a/pdp18b_cpu.c b/PDP18B/pdp18b_cpu.c similarity index 92% rename from pdp18b_cpu.c rename to PDP18B/pdp18b_cpu.c index 01dedddf..02ade4c9 100644 --- a/pdp18b_cpu.c +++ b/PDP18B/pdp18b_cpu.c @@ -25,6 +25,8 @@ cpu PDP-4/7/9/15 central processor + 30-Nov-01 RMS Added extended SET/SHOW support + 25-Nov-01 RMS Revised interrupt structure 19-Sep-01 RMS Fixed bug in EAE (found by Dave Conroy) 17-Sep-01 RMS Fixed typo in conditional 10-Aug-01 RMS Removed register from declarations @@ -224,9 +226,9 @@ nested XCT's I/O error in I/O simulator - 2. Interrupts. Interrupt requests are maintained in the int_req - register. If interrupts are on and not deferred, and at least - one interrupt request is set, a program interrupt occurs. + 2. Interrupts. Interrupt requests are maintained in the int_hwre + array. int_hwre[0:3] corresponds to API levels 0-3; int_hwre[4] + holds PI requests. 3. Arithmetic. The 18b PDP's implements both 1's and 2's complement arithmetic for signed numbers. In 1's complement arithmetic, a @@ -244,8 +246,6 @@ #include "pdp18b_defs.h" -#define ILL_ADR_FLAG (1 << ADDRSIZE) -#define save_ibkpt (cpu_unit.u3) #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 */ @@ -271,7 +271,8 @@ int32 saved_PC = 0; /* PC */ int32 iors = 0; /* IORS */ int32 ion = 0; /* int on */ int32 ion_defer = 0; /* int defer */ -int32 int_req = 0; /* int requests */ +int32 int_pend = 0; /* int pending */ +int32 int_hwre[API_HLVL+1] = { 0 }; /* int requests */ int32 api_enb = 0; /* API enable */ int32 api_req = 0; /* API requests */ int32 api_act = 0; /* API active */ @@ -297,16 +298,16 @@ int32 LR = 0; /* limit register */ int32 stop_inst = 0; /* stop on rsrv inst */ int32 xct_max = 16; /* nested XCT limit */ int32 old_PC = 0; /* old PC */ -int32 ibkpt_addr = ILL_ADR_FLAG | ADDRMASK; /* breakpoint addr */ int32 dev_enb = -1; /* device enables */ extern int32 sim_int_char; +extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ + 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_svc (UNIT *uptr); -t_stat cpu_set_size (UNIT *uptr, int32 value); +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); int32 upd_iors (void); -int32 api_eval (void); +int32 api_eval (int32 *pend); static const int32 api_ffo[256] = { 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, @@ -326,11 +327,11 @@ static const int32 api_ffo[256] = { 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 }; -static const int32 api_vec[32] = { - 0, 0, 0, 0, 0, 0, 0, 0, - 0, ACH_TTO1, ACH_TTI1, ACH_CLK, 0, 0, 0, 0, - 0, ACH_LPT, ACH_LPT, ACH_PTR, 0, 0, 0, ACH_RP, - ACH_RF, ACH_DRM, ACH_MTA, ACH_DTA, 0, 0, ACH_PWRFL, 0 }; +static const int32 api_vec[API_HLVL][32] = { + { ACH_PWRFL }, /* API 0 */ + { ACH_DTA, ACH_MTA, ACH_DRM, ACH_RF, ACH_RP }, /* API 1 */ + { ACH_PTR, ACH_LPT, ACH_LPT }, /* API 2 */ + { ACH_CLK, ACH_TTI1, ACH_TTO1 } }; /* API 3 */ /* CPU data structures @@ -340,7 +341,7 @@ static const int32 api_vec[32] = { cpu_mod CPU modifier list */ -UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK + EAE_DFLT + API_DFLT, +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK + EAE_DFLT + API_DFLT, MAXMEMSIZE) }; REG cpu_reg[] = { @@ -354,13 +355,14 @@ REG cpu_reg[] = { #endif { ORDATA (SR, SR, 18) }, { ORDATA (IORS, iors, 18), REG_RO }, - { ORDATA (INT, int_req, 32), REG_RO }, + { BRDATA (INT, int_hwre, 8, 32, API_HLVL+1), REG_RO }, { FLDATA (ION, ion, 0) }, { ORDATA (ION_DELAY, ion_defer, 2) }, #if defined (PDP7) { FLDATA (TRAPM, usmd, 0) }, { FLDATA (TRAPP, trap_pending, 0) }, { FLDATA (EXTM, memm, 0) }, + { FLDATA (EXTM_INIT, memm_init, 0) }, { FLDATA (EMIRP, emir_pending, 0) }, #endif #if defined (PDP9) @@ -377,7 +379,7 @@ REG cpu_reg[] = { { FLDATA (EXTM_INIT, memm_init, 0) }, { FLDATA (EMIRP, emir_pending, 0) }, { FLDATA (RESTP, rest_pending, 0) }, - { FLDATA (PWRFL, int_req, INT_V_PWRFL) }, + { FLDATA (PWRFL, int_hwre[API_PWRFL], INT_V_PWRFL) }, #endif #if defined (PDP15) { FLDATA (APIENB, api_enb, 0) }, @@ -386,22 +388,21 @@ REG cpu_reg[] = { { ORDATA (XR, XR, 18) }, { ORDATA (LR, LR, 18) }, { ORDATA (BR, BR, ADDRSIZE) }, + { FLDATA (USMD, usmd, 0) }, + { FLDATA (USMDBUF, usmdbuf, 0) }, { FLDATA (NEXM, nexm, 0) }, { FLDATA (PRVN, prvn, 0) }, { FLDATA (TRAPP, trap_pending, 0) }, - { FLDATA (USMD, usmd, 0) }, - { FLDATA (USMDBUF, usmdbuf, 0) }, { FLDATA (BANKM, memm, 0) }, { FLDATA (BANKM_INIT, memm_init, 0) }, - { FLDATA (RESP, rest_pending, 0) }, - { FLDATA (PWRFL, int_req, INT_V_PWRFL) }, + { FLDATA (RESTP, rest_pending, 0) }, + { FLDATA (PWRFL, int_hwre[API_PWRFL], INT_V_PWRFL) }, #endif { ORDATA (OLDPC, old_PC, ADDRSIZE), REG_RO }, { 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 (BREAK, ibkpt_addr, ADDRSIZE + 1) }, { ORDATA (WRU, sim_int_char, 8) }, { ORDATA (DEVENB, dev_enb, 32), REG_HRO }, { NULL } }; @@ -608,7 +609,7 @@ MQ = saved_MQ & 0777777; reason = 0; sim_rtc_init (clk_unit.wait); /* init calibration */ if (cpu_unit.flags & UNIT_NOAPI) api_enb = api_req = api_act = 0; -api_int = api_eval (); /* eval API */ +api_int = api_eval (&int_pend); /* eval API */ api_cycle = 0; /* not API cycle */ /* Main instruction fetch/decode loop: check trap and interrupt */ @@ -619,7 +620,7 @@ int32 link_init, fill; if (sim_interval <= 0) { /* check clock queue */ if (reason = sim_process_event ()) break; - api_int = api_eval (); } /* eval API */ + api_int = api_eval (&int_pend); } /* eval API */ /* Protection traps work like interrupts, with these quirks: @@ -653,18 +654,18 @@ if (trap_pending) { /* trap pending? */ if (api_int && !ion_defer) { /* API intr? */ int32 i, lvl = api_int - 1; /* get req level */ api_act = api_act | (0200 >> lvl); /* set level active */ - if (lvl >= 4) { /* software req? */ - MA = ACH_SWRE + lvl - 4; /* vec = 40:43 */ + if (lvl >= API_HLVL) { /* software req? */ + MA = ACH_SWRE + lvl - API_HLVL; /* vec = 40:43 */ api_req = api_req & ~(0200 >> lvl); } /* remove request */ else { MA = 0; /* assume fails */ - for (i = 31; i >= 0; i--) { /* loop hi to lo */ - if ((int_req >> i) & 1) { /* int req set? */ - MA = api_vec[i]; /* get vector */ - break; } } } /* and stop */ + for (i = 0; i < 32; i++) { /* loop hi to lo */ + if ((int_hwre[lvl] >> i) & 1) { /* int req set? */ + MA = api_vec[lvl][i]; /* get vector */ + break; } } } /* and stop */ if (MA == 0) { /* bad channel? */ reason = STOP_API; /* API error */ break; } - api_int = api_eval (); /* no API int */ + api_int = api_eval (&int_pend); /* no API int */ api_cycle = 1; /* in API cycle */ emir_pending = rest_pending = 0; /* emir, restore off */ xct_count = 0; @@ -672,9 +673,9 @@ if (api_int && !ion_defer) { /* API intr? */ /* Standard program interrupt */ -if (!(api_enb && api_act) && ion && !ion_defer && int_req) { +if (!(api_enb && api_act) && ion && !ion_defer && int_pend) { #else -if (ion && !ion_defer && int_req) { /* interrupt? */ +if (ion && !ion_defer && int_pend) { /* interrupt? */ #endif old_PC = PC; /* save old PC */ M[0] = JMS_WORD (usmd); /* save state */ @@ -688,10 +689,7 @@ if (ion && !ion_defer && int_req) { /* interrupt? */ /* Breakpoint */ -if (PC == ibkpt_addr) { /* breakpoint? */ - save_ibkpt = ibkpt_addr; /* save ibkpt */ - ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */ - sim_activate (&cpu_unit, 1); /* sched re-enable */ +if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ reason = STOP_IBKPT; /* stop simulation */ break; } @@ -862,7 +860,7 @@ case 001: case 000: /* CAL */ usmd = 0; /* clear user mode */ if ((cpu_unit.flags & UNIT_NOAPI) == 0) { /* if API, act lvl 4 */ api_act = api_act | 010; - api_int = api_eval (); } + api_int = api_eval (&int_pend); } #endif if (IR & 0020000) { INDIRECT; } /* indirect? */ CHECK_ADDR_W (MA); @@ -1345,7 +1343,7 @@ case 034: /* IOT */ else if (pulse == 044) nexm = 0; break; case 032: /* power fail */ - if ((pulse == 001) && (int_req & INT_PWRFL)) + if ((pulse == 001) && (TST_INT (PWRFL))) PC = INCR_ADDR (PC); break; case 033: /* CPU control */ @@ -1477,7 +1475,7 @@ case 034: /* IOT */ LAC = LAC | (iot_data & 0777777); if (iot_data & IOT_SKP) PC = INCR_ADDR (PC); if (iot_data >= IOT_REASON) reason = iot_data >> IOT_V_REASON; - api_int = api_eval (); /* eval API */ + api_int = api_eval (&int_pend); /* eval API */ break; /* end case IOT */ } /* end switch opcode */ if (api_cycle) { /* API cycle? */ @@ -1497,16 +1495,17 @@ return reason; /* Evaluate API */ -int32 api_eval (void) +int32 api_eval (int32 *pend) { int32 i, hi; -static const uint32 api_mask[4] = { - API_L0, API_L1, API_L2, API_L3 }; +for (i = *pend = 0; i < API_HLVL+1; i++) { /* any intr? */ + if (int_hwre[i]) *pend = 1; } if (api_enb == 0) return 0; /* off? no req */ api_req = api_req & ~0360; /* clr req<0:3> */ -for (i = 0; i < 4; i++) { - if (int_req & api_mask[i]) api_req = api_req | (0200 >> i); } +for (i = 0; i < API_HLVL; i++) { /* loop thru levels */ + if (int_hwre[i]) /* req on level? */ + api_req = api_req | (0200 >> i); } /* set api req */ hi = api_ffo[api_req & 0377]; /* find hi req */ if (hi < api_ffo[api_act & 0377]) return (hi + 1); return 0; @@ -1554,14 +1553,15 @@ t_stat cpu_reset (DEVICE *dptr) SC = 0; eae_ac_sign = 0; ion = ion_defer = 0; -int_req = int_req & ~INT_PWRFL; +CLR_INT (PWRFL); api_enb = api_req = api_act = 0; BR = 0; usmd = usmdbuf = 0; memm = memm_init; nexm = prvn = trap_pending = 0; emir_pending = rest_pending = 0; -return cpu_svc (&cpu_unit); +sim_brk_types = sim_brk_dflt = SWMASK ('E'); +return SCPE_OK; } /* Memory examine */ @@ -1582,28 +1582,19 @@ M[addr] = val & 0777777; return SCPE_OK; } -/* Service breakpoint */ - -t_stat cpu_svc (UNIT *uptr) -{ -if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt) ibkpt_addr = save_ibkpt; -save_ibkpt = -1; -return SCPE_OK; -} - /* Change memory size */ -t_stat cpu_set_size (UNIT *uptr, int32 value) +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { int32 mc = 0; t_addr i; -if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 07777) != 0)) +if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0)) return SCPE_ARG; -for (i = value; i < MEMSIZE; i++) mc = mc | M[i]; +for (i = val; i < MEMSIZE; i++) mc = mc | M[i]; if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) return SCPE_OK; -MEMSIZE = value; +MEMSIZE = val; for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; return SCPE_OK; } diff --git a/pdp18b_defs.h b/PDP18B/pdp18b_defs.h similarity index 84% rename from pdp18b_defs.h rename to PDP18B/pdp18b_defs.h index 0eaf9408..d7e73f1e 100644 --- a/pdp18b_defs.h +++ b/PDP18B/pdp18b_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. + 25-Nov-01 RMS Revised interrupt structure 27-May-01 RMS Added second Teletype support 21-Jan-01 RMS Added DECtape support 14-Apr-99 RMS Changed t_addr to unsigned @@ -187,65 +188,101 @@ 35 LT15 TTI 3 PDP-15 only 36 - 37 - - - Interrupt system, priority is left to right. - - <30:28> = priority 0 - <27:20> = priority 1 - <19:12> = priority 2 - <11:8> = priority 3 - <7:0> = PI only */ -#define API_L0 0xF0000000 -#define API_L1 0x0FF00000 -#define API_L2 0x000FF000 -#define API_L3 0x00000F00 +#define API_HLVL 4 /* hwre levels */ +#define ACH_SWRE 040 /* swre int vec */ -#define INT_V_PWRFL 30 /* powerfail */ -#define INT_V_DTA 27 /* DECtape */ -#define INT_V_MTA 26 /* magtape */ -#define INT_V_DRM 25 /* drum */ -#define INT_V_RF 24 /* fixed head disk */ -#define INT_V_RP 23 /* disk pack */ -#define INT_V_PTR 19 /* paper tape reader */ -#define INT_V_LPT 18 /* line printer */ -#define INT_V_LPTSPC 17 /* line printer spc */ -#define INT_V_CLK 11 /* clock */ -#define INT_V_TTI1 10 /* LT15 keyboard */ -#define INT_V_TTO1 9 /* LT15 output */ -#define INT_V_TTI 7 /* console keyboard */ -#define INT_V_TTO 6 /* console output */ -#define INT_V_PTP 5 /* paper tape punch */ +/* API level 0 */ + +#define INT_V_PWRFL 0 /* powerfail */ #define INT_PWRFL (1 << INT_V_PWRFL) + +#define API_PWRFL 0 + +#define ACH_PWRFL 052 + +/*API level 1 */ + +#define INT_V_DTA 0 /* DECtape */ +#define INT_V_MTA 1 /* magtape */ +#define INT_V_DRM 2 /* drum */ +#define INT_V_RF 3 /* fixed head disk */ +#define INT_V_RP 4 /* disk pack */ + #define INT_DTA (1 << INT_V_DTA) #define INT_MTA (1 << INT_V_MTA) #define INT_DRM (1 << INT_V_DRM) #define INT_RF (1 << INT_V_RF) #define INT_RP (1 << INT_V_RP) -#define INT_PTR (1 << INT_V_PTR) -#define INT_LPT (1 << INT_V_LPT) -#define INT_LPTSPC (1 << INT_V_LPTSPC) -#define INT_CLK (1 << INT_V_CLK) -#define INT_TTI1 (1 << INT_V_TTI1) -#define INT_TTO1 (1 << INT_V_TTO1) -#define INT_TTI (1 << INT_V_TTI) -#define INT_TTO (1 << INT_V_TTO) -#define INT_PTP (1 << INT_V_PTP) -#define ACH_SWRE 040 /* API channels */ -#define ACH_PWRFL 052 +#define API_DTA 1 +#define API_MTA 1 +#define API_DRM 1 +#define API_RF 1 +#define API_RP 1 + #define ACH_DTA 044 #define ACH_MTA 045 #define ACH_DRM 046 #define ACH_RF 063 #define ACH_RP 064 + +/* API level 2 */ + +#define INT_V_PTR 0 /* paper tape reader */ +#define INT_V_LPT 1 /* line printer */ +#define INT_V_LPTSPC 2 /* line printer spc */ + +#define INT_PTR (1 << INT_V_PTR) +#define INT_LPT (1 << INT_V_LPT) +#define INT_LPTSPC (1 << INT_V_LPTSPC) + +#define API_PTR 2 +#define API_LPT 2 +#define API_LPTSPC 2 + #define ACH_PTR 050 #define ACH_LPT 056 + +/* API level 3 */ + +#define INT_V_CLK 0 /* clock */ +#define INT_V_TTI1 1 /* LT15 keyboard */ +#define INT_V_TTO1 2 /* LT15 output */ + +#define INT_CLK (1 << INT_V_CLK) +#define INT_TTI1 (1 << INT_V_TTI1) +#define INT_TTO1 (1 << INT_V_TTO1) + +#define API_CLK 3 +#define API_TTI1 3 +#define API_TTO1 3 + #define ACH_CLK 051 #define ACH_TTI1 075 #define ACH_TTO1 074 + +/* PI level */ + +#define INT_V_TTI 0 /* console keyboard */ +#define INT_V_TTO 1 /* console output */ +#define INT_V_PTP 2 /* paper tape punch */ + +#define INT_TTI (1 << INT_V_TTI) +#define INT_TTO (1 << INT_V_TTO) +#define INT_PTP (1 << INT_V_PTP) + +#define API_TTI 4 /* PI level */ +#define API_TTO 4 +#define API_PTP 4 + +/* Interrupt macros */ + +#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) /* I/O status flags for the IORS instruction diff --git a/PDP18B/pdp18b_doc.txt b/PDP18B/pdp18b_doc.txt new file mode 100644 index 00000000..dd06f063 --- /dev/null +++ b/PDP18B/pdp18b_doc.txt @@ -0,0 +1,782 @@ +To: Users +From: Bob Supnik +Subj: 18b PDP Simulator Usage +Date: 1-Dec-01 + + COPYRIGHT NOTICE + +The following copyright notice applies to both the SIMH source and binary: + + Original code published in 1993-2001, written by Robert M Supnik + 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. + +This memorandum documents the PDP-4, PDP-7, PDP-9, and PDP-15 simulators. + + +1. Simulator Files + +To compile a particular model in the 18b family, you must include the appropriate +switch in the compilation command line: + +PDP-4/ PDP4 +PDP-7/ PDP7 +PDP-9/ PDP9 +PDP-15/ PDP15 + +If no model is specified, the default is the PDP-9. + +sim/ sim_defs.h + sim_sock.h + sim_tmxr.h + scp.c + scp_tty.c + sim_rev.c + sim_sock.c + sim_tmxr.c + +sim/pdp18b/ pdp18b_defs.h + pdp18b_cpu.c + pdp18b_drm.c + pdp18b_dt.c + pdp18b_lp.c + pdp18b_mt.c + pdp18b_rf.c + pdp18b_rp.c + pdp18b_stddev.c + pdp18b_sys.c + pdp18b_tt1.c + +2. 18b PDP Features + +The other four 18b PDP's (PDP-4, PDP-7, PDP-9, PDP-15) are very similar +and are configured as follows: + +system device simulates + name(s) + +PDP-4 CPU PDP-4 CPU with 8KW of memory + PTR,PTP integral paper tape/Type 75 punch + TTI,TTO KSR28 console terminal (Baudot code) + LPT Type 62 line printer (Hollerith code) + CLK integral real-time clock + +PDP-7 CPU PDP-7 CPU with 32KW of memory + - Type 177 extended arithmetic element (EAE) + - Type 148 memory extension + PTR,PTP Type 444 paper tape reader/Type 75 punch + TTI,TTO KSR 33 console terminal + LPT Type 647 line printer + CLK integral real-time clock + DRM Type 24 serial drum + +PDP-9 CPU PDP-9 CPU with 32KW of memory + - KE09A extended arithmetic element (EAE) + - KF09A automatic priority interrupt (API) + - KG09B memory extension + - KP09A power detection + - KX09A memory protection + PTR,PTP PC09A paper tape reader/punch + TTI,TTO KSR 33 console terminal + TTI1,TTO1 LT09A second console terminal + LPT Type 647E line printer + CLK integral real-time clock + RF RF09/RS09 fixed-head disk + DT TC02/TU55 DECtape + MT TC59/TU10 magnetic tape + +PDP-15 CPU PDP-15 CPU with 32KW of memory + - KE15 extended arithmetic element (EAE) + - KA15 automatic priority interrupt (API) + - KF15 power detection + - KM15 memory protection + PTR,PTP PC15 paper tape reader/punch + TTI,TTO KSR 35 console terminal + TTI1,TTO1 LT15 second console terminal + LPT LP15 line printer + CLK integral real-time clock + RP RP15/RP02 disk pack + RF RF15/RS09 fixed-head disk + DT TC15/TU56 DECtape + MT TC59/TU10 magnetic tape + +The DRM, RF, RP, DT, and MT devices can be DISABLEd. + +The 18b PDP simulators implement several unique stop conditions: + + - an unimplemented instruction is decoded, and register + STOP_INST is set + - more than XCTMAX nested executes are detected during + instruction execution + +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. + +2.1 CPU + +The CPU options are the presence of the EAE, the presense of the API (for +the PDP-9 and PDP-15), and the size of main memory. + + SET CPU EAE enable EAE + SET CPU NOEAE disable EAE + SET CPU API enable API + SET CPU NOAPI disable API + SET CPU 4K set memory size = 4K + SET CPU 8K set memory size = 8K + SET CPU 12K set memory size = 12K + SET CPU 16K set memory size = 16K + SET CPU 20K set memory size = 20K + SET CPU 24K set memory size = 24K + SET CPU 28K set memory size = 28K + SET CPU 32K set memory size = 32K + SET CPU 48K set memory size = 48K + SET CPU 64K set memory size = 64K + SET CPU 80K set memory size = 80K + SET CPU 96K set memory size = 96K + SET CPU 112K set memory size = 112K + SET CPU 128K set memory size = 128K + +Memory sizes greater than 8K are only available on the PDP-7, PDP-9, and +PDP-15; memory sizes greater than 32KW are only available on the PDP-15. +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 8K for the PDP-4, 32K +for the PDP-7 and PDP-9, and 128K for the PDP-15. + +CPU registers include the visible state of the processor as well as the +control registers for the interrupt system. + + system name size comments + + all PC addr program counter + all AC 18 accumulator + all L 1 link + 7,9,15 MQ 18 multiplier-quotient + 7,9,15 SC 6 shift counter + 7,9,15 EAE_AC_SIGN 1 EAE AC sign + all SR 18 front panel switches + all INT[0:4] 32 interrupt requests, + 0:3 = API levels 0-3 + 4 = PI level + all IORS 18 IORS register + all ION 1 interrupt enable + all ION_DELAY 2 interrupt enable delay + 9,15 APIENB 1 API enable + 9,15 APIREQ 8 API requesting levels + 9,15 APIACT 8 API active levels + 9,15 BR addr memory protection bounds + 15 XR 18 index register + 15 LR 18 limit register + 15 BR 17 memory protection bounds + 9,15 USMD 1 user mode + 9,15 USMDBUF 1 user mode buffer + 9,15 NEXM 1 non-existent memory violation + 9,15 PRVN 1 privilege violation + 7,9 EXTM 1 extend mode + 7,9 EXTM_INIT 1 extend mode value after reset + 15 BANKM 1 bank mode + 15 BANKM_INIT 1 bank mode value after reset + 7 TRAPM 1 trap mode + 7,9,15 TRAPP 1 trap pending + 7,9 EMIRP 1 EMIR instruction pending + 9,15 RESTP 1 DBR or RES instruction pending + 9,15 PWRFL 1 power fail flag + all OLDPC addr PC prior to last transfer + all STOP_INST 1 stop on undefined instruction + all WRU 8 interrupt character + +"addr" signifies the address width of the system (13b for the PDP-4, 15b for +the PDP-7 and PDP-9, 17b for the PDP-15). + +2.2 Programmed I/O Devices + +2.2.1 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. + +On the PDP-4 and PDP-7, the paper tape reader supports the BOOT command. +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 paper tape reader implements these registers: + + name size comments + + BUF 8 last data item processed + INT 1 interrupt pending flag + DONE 1 device done flag + ERR 1 error flag (PDP-9, PDP-15 only) + POS 31 position in the input file + TIME 24 time from I/O initiation to interrupt + 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 out of tape + + end of file 1 report error and stop + 0 out of tape + + OS I/O error x report error and stop + +2.2.2 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. +Thus, by changing POS, the user can backspace or advance the punch. + +The paper tape punch implements these registers: + + name size comments + + BUF 8 last data item processed + INT 1 interrupt pending flag + DONE 1 device done flag + ERR 1 error flag (PDP-9, PDP-15 only) + POS 31 position in the output file + TIME 24 time from I/O initiation to interrupt + 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 out of tape or paper + + OS I/O error x report error and stop + +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. + +The PDP-9 and PDP-15 operate the console terminal (TTI/TTO), by default, +as half duplex. 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 in full-duplex mode. The second terminal is always +full duplex. + +The terminal input implements these registers: + + name size comments + + BUF 8 last data item processed + INT 1 interrupt pending flag + DONE 1 device done flag + POS 31 number of characters input + TIME 24 keyboard polling interval + +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: + + name size comments + + BUF 8 last data item processed + INT 1 interrupt pending flag + DONE 1 device done flag + POS 31 number of chararacters output + TIME 24 time from I/O initiation to interrupt + +2.2.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, +by changing POS, the user can backspace or advance the printer. + +The PDP-4 used a Type 62 printer controller, with these registers: + + name size comments + + BUF 8 last data item processed + INT 1 interrupt pending flag + DONE 1 device done flag + SPC 1 spacing done flag + BPTR 6 print buffer pointer + POS 31 position in the output file + TIME 24 time from I/O initiation to interrupt + 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 +registers: + + name size comments + + BUF 8 last data item processed + INT 1 interrupt pending flag + DONE 1 device done flag + ENABLE 1 interrupt enable (PDP-9 only) + ERR 1 error flag + BPTR 7 print buffer pointer + POS 31 position in the output file + TIME 24 time from I/O initiation to interrupt + 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: + + name size comments + + STA 18 status register + MA 18 DMA memory address + INT 1 interrupt pending flag + ENABLE 1 interrupt enable + LCNT 8 line counter + BPTR 7 print buffer pointer + POS 31 position in the output file + TIME 24 time from I/O initiation to interrupt + STOP_IOE 1 stop on I/O error + LBUF[0:131] 8 line buffer + +For all three models, 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 + +2.2.6 Real-Time Clock (CLK) + +The real-time clock (CLK) implements these registers: + + name size comments + + INT 1 interrupt pending flag + DONE 1 device done flag + ENABLE 1 clock enable + TIME 24 clock frequency + TPS 8 ticks per second (60 or 50) + +The real-time clock autocalibrates; the clock interval is adjusted up or +down so that the clock tracks actual elapsed time. + +2.2.7 Second Terminal (TTI1, TTO1) + +The second terminal consists of two independent devices, TTI1 and TTO1. +The second terminal performs input and output through a Telnet session +connected to a user-specified port. The ATTACH command specifies the +port to be used: + + ATTACH TTI1 (cr) -- set up listening port + +where port is a decimal number between 1 and 65535 that is not being used +for other TCP/IP activities. + +Once TTI1 is attached and the simulator is running, the terminal listens +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 SHOW TTI1 LINESTATUS command displays the current connection to the +second terminal. + +The second terminal input implements these registers: + + name size comments + + BUF 8 last data item processed + INT 1 interrupt pending flag + DONE 1 device done flag + POS 31 number of characters input + TIME 24 keyboard polling interval + +The second terminal output implements these registers: + + name size comments + + BUF 8 last data item processed + INT 1 interrupt pending flag + DONE 1 device done flag + POS 31 number of chararacters output + TIME 24 time from I/O initiation to interrupt + +2.3 RP15/RP02 Disk Pack (RP) + +RP15 options include the ability to make units write enabled or write locked: + + SET RPn LOCKED set unit n write locked + SET RPn ENABLED set unit n write enabled + +Units can also be REMOVEd or ADDed to the configuration. + +The RP15 implements these registers: + + name size comments + + STA 18 status A + STB 18 status B + DA 18 disk address + MA 18 current memory address + WC 18 word count + INT 1 interrupt pending flag + BUSY 1 control busy 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 Type 24 Serial Drum (DRM) + +The serial drum (DRM) implements these registers: + + name size comments + + DA 9 drum address (sector number) + MA 15 current memory address + INT 1 interrupt pending flag + DONE 1 device done flag + ERR 1 error flag + WLK 32 write lock switches + TIME 24 rotational latency, per word + 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 + +Drum data files are buffered in memory; therefore, end of file and OS +I/O errors cannot occur. + +2.5 RF09/RF15/RS09 Fixed Head Disk (RF) + +The RF09/RF15 implements these registers: + + name size comments + + STA 18 status + DA 21 current disk address + MA 18 memory address (in memory) + WC 18 word count (in memory) + BUF 18 data buffer (diagnostic only) + INT 1 interrupt pending flag + WLK[0:7] 16 write lock switches for disks 0-7 + TIME 24 rotational delay, per word + BURST 1 burst flag + STOP_IOE 1 stop on I/O error + +The RF09/RF15 is a three-cycle data break device. If BURST = 0, word +transfers are scheduled individually; if BURST = 1, the entire transfer +occurs in a single data break. + +Error handling is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 disk not ready + +RF15/RF09 data files are buffered in memory; therefore, end of file and OS +I/O errors cannot occur. + +2.6 TC02/TU55 and TC15/TU56 DECtape (DT) + +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 LOCKED set unit n write locked + SET DTn ENABLED set unit n write enabled + +Units can also be REMOVEd or ADDed to the configuration. + +The TC02/TC15 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: + + -f foreign (PDP-8) format + -n native (PDP-9/11/15) 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 + INT 1 interrupt pending flag + ENB 1 interrupt enable flag + DTF 1 DECtape flag + ERF 1 error flag + CA 18 current address (memory location 30) + WC 18 word count (memory location 31) + 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] 31 position, in lines, units 0-7 + STATT[0:7] 31 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.7 TC59/TU10 Magnetic Tape (MT) + +Magnetic tape options include the ability to make units write enabled or +or write locked. + + SET MTn LOCKED set unit n write locked + SET MTn ENABLED set unit n write enabled + +Units can also be REMOVEd or ADDed to the configuration. + +The magnetic tape controller implements these registers: + + name size comments + + CMD 18 command + STA 18 main status + MA 18 memory address (in memory) + WC 18 word count (in memory) + INT 1 interrupt pending flag + STOP_IOE 1 stop on I/O error + TIME 24 record delay + UST[0:7] 24 unit status, units 0-7 + POS[0:7] 31 position, units 0-7 + +Error handling is as follows: + + error processed as + + not attached tape not ready + + end of file (read or space) end of physical tape + (write) ignored + + OS I/O error report error and stop + +2.8 Symbolic Display and Input + +The 18b PDP simulators implement symbolic display and input. Display is +controlled by command line switches: + + -a display as ASCII character + -c display as (sixbit) character string + -m display instruction mnemonics + +The PDP-15 also recognizes an additional switch: + + -p display as packed ASCII (five 7b ASCII + characters in two 18b words) + +Input parsing is controlled by the first character typed in or by command +line switches: + + ' or -a ASCII character + " or -c three character sixbit string + alphabetic instruction mnemonic + numeric octal number + +The PDP-15 also recognizes an additional input mode: + + # or -p five character packed ASCII string in + two 18b words + +Instruction input uses standard 18b PDP assembler syntax. There are six +instruction classes: memory reference, EAE, index (PDP-15 only), IOT, +operate, and LAW. + +Memory reference instructions have the format + + memref {I/@} address{,X} + +where I (PDP-4, PDP-7, PDP-9) /@ (PDP-15) signifies indirect reference, +and X signifies indexing (PDP-15 in page mode only). The address is an +octal number in the range 0 - 017777 (PDP-4, PDP-7, PDP-9, and PDP-15 in +bank mode) or 0 - 07777 (PDP-15 in page mode). + +IOT instructions consist of single mnemonics, eg, KRB, TLS. IOT instructions +may be or'd together + + iot iot iot... + +IOT's may also include the number 10, signifying clear the accumulator + + iot 10 + +The simulator does not check the legality of IOT combinations. IOT's for +which there is no opcode may be specified as IOT n, where n is an octal +number in the range 0 - 07777. + +EAE instructions have the format + + eae {+/- shift count} + +EAE instructions may be or'd together + + eae eae eae... + +The simulator does not check the legality of EAE combinations. EAE's for +which there is no opcode may be specified as EAE n, where n is an octal +number in the range 0 - 037777. + +Index instructions (PDP-15 only) have the format + + index {immediate} + +The immediate, if allowed, must be in the range of -0400 to +0377. + +Operate instructions have the format + + opr opr opr... + +The simulator does not check the legality of the proposed combination. The +operands for MUY and DVI must be deposited explicitly. + +Finally, the LAW instruction has the format + + LAW immediate + +where immediate is in the range of 0 to 017777. + +2.9 Character Sets + +The PDP-4's console was an ASR-28 Teletype; its character encoding was +Baudot. The PDP-4's line printer used a modified Hollerith character +set. The PDP-7's and PDP-9's consoles were KSR-33 Teletypes; their +character sets were basically ASCII. The PDP-7's and PDP-9's line +printers used sixbit encoding (ASCII codes 040 - 0137 masked to six +bits). The PDP-15's I/O devices were all ASCII. The following table +provides equivalences between ASCII characters and the PDP-4's I/O devices. +In the console table, FG stands for figures (upper case). + + PDP-4 PDP-4 +ASCII console line printer + +000 - 006 none none +bell FG+024 none +010 - 011 none none +lf 010 none +013 - 014 none none +cr 002 none +016 - 037 none none +space 004 000 +! FG+026 none +" FG+021 none +# FG+005 none +$ FG+062 none +% none none +& FG+013 none +' FG+032 none +( FG+036 057 +) FG+011 055 +* none 072 ++ none 074 +, FG+006 033 +- FG+030 054 +. FG+007 073 +/ FG+027 021 +0 FG+015 020 +1 FG+035 001 +2 FG+031 002 +3 FG+020 003 +4 FG+012 004 +5 FG+001 005 +6 FG+025 006 +7 FG+034 007 +8 FG+014 010 +9 FG+003 011 +: FG+016 none +; FG+017 none +< none 034 += none 053 +> none 034 +? FG+023 037 +@ none {MID DOT} 040 +A 030 061 +B 023 062 +C 016 063 +D 022 064 +E 020 065 +F 026 066 +G 013 067 +H 005 070 +I 014 071 +J 032 041 +K 036 042 +L 011 043 +M 007 044 +N 006 045 +O 003 046 +P 015 047 +Q 035 050 +R 012 051 +S 024 022 +T 001 023 +U 034 024 +V 017 025 +W 031 026 +X 027 027 +Y 025 030 +Z 021 031 +[ none none +\ none {OVERLINE} 056 +] none none +^ none {UP ARROW} 035 +_ none UC+040 +0140 - 0177 none none diff --git a/pdp18b_drm.c b/PDP18B/pdp18b_drm.c similarity index 89% rename from pdp18b_drm.c rename to PDP18B/pdp18b_drm.c index 29730f15..8e0ced38 100644 --- a/pdp18b_drm.c +++ b/PDP18B/pdp18b_drm.c @@ -26,6 +26,7 @@ drm (PDP-7) Type 24 serial drum (PDP-9) RM09 serial drum + 25-Nov-01 RMS Revised interrupt structure 10-Jun-01 RMS Cleaned up IOT decoding to reflect hardware 26-Apr-01 RMS Added device enable/disable support 14-Apr-99 RMS Changed t_addr to unsigned @@ -54,7 +55,7 @@ ((double) DRM_NUMWDT))) extern int32 M[]; -extern int32 int_req, dev_enb; +extern int32 int_hwre[API_HLVL+1], dev_enb; extern UNIT cpu_unit; int32 drm_da = 0; /* track address */ int32 drm_ma = 0; /* memory address */ @@ -80,8 +81,8 @@ UNIT drm_unit = REG drm_reg[] = { { ORDATA (DA, drm_da, 9) }, { ORDATA (MA, drm_ma, 15) }, - { FLDATA (INT, int_req, INT_V_DRM) }, - { FLDATA (DONE, int_req, INT_V_DRM) }, + { FLDATA (INT, int_hwre[API_DRM], INT_V_DRM) }, + { FLDATA (DONE, int_hwre[API_DRM], INT_V_DRM) }, { FLDATA (ERR, drm_err, 0) }, { ORDATA (WLK, drm_wlk, 32) }, { DRDATA (TIME, drm_time, 24), REG_NZ + PV_LEFT }, @@ -110,9 +111,9 @@ int32 drm61 (int32 pulse, int32 AC) int32 t; if (pulse & 001) { /* DRSF */ - if (int_req & INT_DRM) AC = AC | IOT_SKP; } + if (TST_INT (DRM)) AC = AC | IOT_SKP; } if (pulse & 002) { /* DRCF */ - int_req = int_req & ~INT_DRM; /* clear done */ + CLR_INT (DRM); /* clear done */ drm_err = 0; } /* clear error */ if (pulse & 004) { /* DRSS */ drm_da = AC & DRM_SMASK; /* load sector # */ @@ -129,7 +130,7 @@ int32 t; if (pulse & 001) { /* DRSN */ if (drm_err == 0) AC = AC | IOT_SKP; } if (pulse & 004) { /* DRCS */ - int_req = int_req & ~INT_DRM; /* clear done */ + CLR_INT (DRM); /* clear done */ drm_err = 0; /* clear error */ t = ((drm_da % DRM_NUMSC) * DRM_NUMWDS) - GET_POS (drm_time); if (t < 0) t = t + DRM_NUMWDT; /* wrap around? */ @@ -149,7 +150,7 @@ t_addr da; if ((uptr -> flags & UNIT_BUF) == 0) { /* not buf? abort */ drm_err = 1; /* set error */ - int_req = int_req | INT_DRM; /* set done */ + SET_INT (DRM); /* set done */ return IORETURN (drm_stopioe, SCPE_UNATT); } da = drm_da * DRM_NUMWDS; /* compute dev addr */ @@ -163,7 +164,7 @@ for (i = 0; i < DRM_NUMWDS; i++, da++) { /* do transfer */ uptr -> hwmark = da + 1; } } drm_ma = (drm_ma + 1) & ADDRMASK; } /* incr mem addr */ drm_da = (drm_da + 1) & DRM_SMASK; /* incr dev addr */ -int_req = int_req | INT_DRM; /* set done */ +SET_INT (DRM); /* set done */ return SCPE_OK; } @@ -172,7 +173,7 @@ return SCPE_OK; t_stat drm_reset (DEVICE *dptr) { drm_ma = drm_ma = drm_err = 0; -int_req = int_req & ~INT_DRM; +CLR_INT (DRM); /* clear done */ sim_cancel (&drm_unit); return SCPE_OK; } @@ -181,7 +182,7 @@ return SCPE_OK; int32 drm_iors (void) { -return ((int_req & INT_DRM)? IOS_DRM: 0); +return (TST_INT (DRM)? IOS_DRM: 0); } /* Bootstrap routine */ diff --git a/pdp18b_dt.c b/PDP18B/pdp18b_dt.c similarity index 90% rename from pdp18b_dt.c rename to PDP18B/pdp18b_dt.c index db0e96ff..ed95478d 100644 --- a/pdp18b_dt.c +++ b/PDP18B/pdp18b_dt.c @@ -26,6 +26,9 @@ dt (PDP-9) TC02/TU55 DECtape (PDP-15) TC15/TU56 DECtape + 29-Nov-01 RMS Added read only unit support + 25-Nov-01 RMS Revised interrupt structure + Changed POS, STATT, LASTT, FLG to arrays 29-Aug-01 RMS Added casts to PDP-8 unpack routine 17-Jul-01 RMS Moved function prototype 11-May-01 RMS Fixed bug in reset @@ -83,6 +86,7 @@ #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 */ @@ -227,12 +231,12 @@ #define LOG_BL 010 /* block # lblk */ #define DT_UPDINT if ((dtsa & DTA_ENB) && (dtsb & (DTB_ERF | DTB_DTF))) \ - int_req = int_req | INT_DTA; \ - else int_req = int_req & ~INT_DTA; + SET_INT (DTA); \ + else CLR_INT (DTA); #define ABS(x) (((x) < 0)? (-(x)): (x)) extern int32 M[]; -extern int32 int_req, dev_enb; +extern int32 int_hwre[API_HLVL+1], dev_enb; extern UNIT cpu_unit; extern int32 sim_switches; int32 dtsa = 0; /* status A */ @@ -267,19 +271,27 @@ extern int32 sim_is_running; */ 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, 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[] = { { GRDATA (DTSA, dtsa, 8, 12, 6) }, { GRDATA (DTSB, dtsb, 8, 12, 6) }, - { FLDATA (INT, int_req, INT_V_DTA) }, + { FLDATA (INT, int_hwre[API_DTA], INT_V_DTA) }, { FLDATA (ENB, dtsa, DTA_V_ENB) }, { FLDATA (DTF, dtsb, DTB_V_DTF) }, { FLDATA (ERF, dtsb, DTB_V_ERF) }, @@ -291,46 +303,14 @@ REG dt_reg[] = { { ORDATA (SUBSTATE, dt_substate, 2) }, { ORDATA (LOG, dt_log, 4), REG_HIDDEN }, { DRDATA (LBLK, dt_logblk, 12), REG_HIDDEN }, - { DRDATA (POS0, dt_unit[0].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS1, dt_unit[1].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS2, dt_unit[2].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS3, dt_unit[3].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS4, dt_unit[4].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS5, dt_unit[5].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS6, dt_unit[6].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS7, dt_unit[7].pos, 31), PV_LEFT + REG_RO }, - { ORDATA (STATE0, dt_unit[0].STATE, 18), REG_RO }, - { ORDATA (STATE1, dt_unit[1].STATE, 18), REG_RO }, - { ORDATA (STATE2, dt_unit[2].STATE, 18), REG_RO }, - { ORDATA (STATE3, dt_unit[3].STATE, 18), REG_RO }, - { ORDATA (STATE4, dt_unit[4].STATE, 18), REG_RO }, - { ORDATA (STATE5, dt_unit[5].STATE, 18), REG_RO }, - { ORDATA (STATE6, dt_unit[6].STATE, 18), REG_RO }, - { ORDATA (STATE7, dt_unit[7].STATE, 18), REG_RO }, - { DRDATA (LASTT0, dt_unit[0].LASTT, 32), REG_HRO }, - { DRDATA (LASTT1, dt_unit[1].LASTT, 32), REG_HRO }, - { DRDATA (LASTT2, dt_unit[2].LASTT, 32), REG_HRO }, - { DRDATA (LASTT3, dt_unit[3].LASTT, 32), REG_HRO }, - { DRDATA (LASTT4, dt_unit[4].LASTT, 32), REG_HRO }, - { DRDATA (LASTT5, dt_unit[5].LASTT, 32), REG_HRO }, - { DRDATA (LASTT6, dt_unit[6].LASTT, 32), REG_HRO }, - { DRDATA (LASTT7, dt_unit[7].LASTT, 32), REG_HRO }, - { GRDATA (FLG0, dt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG1, dt_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG2, dt_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG3, dt_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG4, dt_unit[4].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG5, dt_unit[5].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG6, dt_unit[6].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG7, dt_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, + { URDATA (POS, dt_unit[0].pos, 10, 31, 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) }, + { 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 }, { NULL } }; @@ -366,8 +346,8 @@ if (((pulse & 060) == 040) && (pulse & 05)) { /* select */ fnc = DTA_GETFNC (dtsa); /* get fnc */ if (((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_WPRT)) || + ((fnc == FNC_WALL) && (uptr -> flags & UNIT_WPRT))) dt_seterr (uptr, DTB_SEL); /* select err */ else dt_newsa (dtsa); /* new func */ DT_UPDINT; @@ -1046,7 +1026,7 @@ if (sim_is_active (uptr)) { dtsb = dtsb | DTB_ERF | DTB_SEL | DTB_DTF; DT_UPDINT; } uptr -> STATE = uptr -> pos = 0; } -if (uptr -> hwmark) { /* any data? */ +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? */ diff --git a/pdp18b_lp.c b/PDP18B/pdp18b_lp.c similarity index 88% rename from pdp18b_lp.c rename to PDP18B/pdp18b_lp.c index 4ed9f950..90652f5d 100644 --- a/pdp18b_lp.c +++ b/PDP18B/pdp18b_lp.c @@ -27,6 +27,7 @@ (PDP-7,9) Type 647 line printer (PDP-15) LP15 line printer + 25-Nov-01 RMS Revised interrupt structure 19-Sep-01 RMS Fixed bug in 647 13-Feb-01 RMS Revised for register arrays 15-Feb-01 RMS Fixed 3 cycle data break sequence @@ -42,7 +43,7 @@ #define BPTR_MAX 40 /* pointer max */ #define LPT_BSIZE 120 /* line size */ #define BPTR_MASK 077 /* buf ptr max */ -extern int32 int_req; +extern int32 int_hwre[API_HLVL+1]; int32 lpt_iot = 0, lpt_stopioe = 0, bptr = 0; char lpt_buf[LPT_BSIZE + 1] = { 0 }; @@ -61,9 +62,9 @@ UNIT lpt_unit = { REG lpt_reg[] = { { ORDATA (BUF, lpt_unit.buf, 8) }, - { FLDATA (INT, int_req, INT_V_LPT) }, - { FLDATA (DONE, int_req, INT_V_LPT) }, - { FLDATA (SPC, int_req, INT_V_LPTSPC) }, + { FLDATA (INT, int_hwre[API_LPT], INT_V_LPT) }, + { FLDATA (DONE, int_hwre[API_LPT], INT_V_LPT) }, + { FLDATA (SPC, int_hwre[API_LPTSPC], INT_V_LPTSPC) }, { DRDATA (BPTR, bptr, 6) }, { ORDATA (STATE, lpt_iot, 6), REG_HRO }, { DRDATA (POS, lpt_unit.pos, 31), PV_LEFT }, @@ -90,8 +91,8 @@ static const char lpt_trans[64] = { 'o','J','K','L','M','N','O','P','Q','R','$','=','-',')','-','(', '_','A','B','C','D','E','F','G','H','I','*','.','+',']','|','[' }; -if (pulse == 001) return (int_req & INT_LPT)? IOT_SKP + AC: AC; /* LPSF */ -if (pulse == 002) int_req = int_req & ~INT_LPT; /* LPCF */ +if (pulse == 001) return (TST_INT (LPT))? IOT_SKP + AC: AC; /* LPSF */ +if (pulse == 002) CLR_INT (LPT); /* LPCF */ else if (pulse == 042) { /* LPLD */ if (bptr < BPTR_MAX) { /* limit test ptr */ i = bptr * 3; /* cvt to chr ptr */ @@ -100,17 +101,17 @@ else if (pulse == 042) { /* LPLD */ lpt_buf[i++] = lpt_trans[AC & 077]; } bptr = (bptr + 1) & BPTR_MASK; } else if (pulse == 006) { /* LPSE */ - int_req = int_req & ~INT_LPT; /* clear flag */ + CLR_INT (LPT); /* clear flag */ sim_activate (&lpt_unit, lpt_unit.wait); } /* activate */ return AC; } int32 lpt66 (int32 pulse, int32 AC) { -if (pulse == 001) return (int_req & INT_LPTSPC)? IOT_SKP + AC: AC; /* LSSF */ -if (pulse & 002) int_req = int_req & ~INT_LPTSPC; /* LSCF */ +if (pulse == 001) return (TST_INT (LPTSPC))? IOT_SKP + AC: AC; /* LSSF */ +if (pulse & 002) CLR_INT (LPTSPC); /* LSCF */ if (pulse & 004) { /* LSPR */ - int_req = int_req & ~INT_LPTSPC; /* clear flag */ + CLR_INT (LPTSPC); /* clear flag */ lpt_iot = 020 | (AC & 07); /* space, no print */ sim_activate (&lpt_unit, lpt_unit.wait); } /* activate */ return AC; @@ -137,7 +138,7 @@ static const char *lpt_cc[] = { "\f" }; if (lpt_iot & 020) { /* space? */ - int_req = int_req | INT_LPTSPC; /* set flag */ + SET_INT (LPTSPC); /* set flag */ if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */ return IORETURN (lpt_stopioe, SCPE_UNATT); fputs (lpt_cc[lpt_iot & 07], lpt_unit.fileref); /* print cctl */ @@ -146,7 +147,7 @@ if (lpt_iot & 020) { /* space? */ clearerr (lpt_unit.fileref); return SCPE_IOERR; } lpt_iot = 0; } /* clear state */ -else { int_req = int_req | INT_LPT; /* print */ +else { SET_INT (LPT); /* print */ if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */ return IORETURN (lpt_stopioe, SCPE_UNATT); if (lpt_iot & 010) fputc ('\r', lpt_unit.fileref); @@ -168,7 +169,8 @@ t_stat lpt_reset (DEVICE *dptr) { int32 i; -int_req = int_req & ~(INT_LPT + INT_LPTSPC); /* clear flag, space */ +CLR_INT (LPT); /* clear intrs */ +CLR_INT (LPTSPC); sim_cancel (&lpt_unit); /* deactivate unit */ bptr = 0; /* clear buffer ptr */ for (i = 0; i <= LPT_BSIZE; i++) lpt_buf[i] = 0; /* clear buffer */ @@ -180,14 +182,14 @@ return SCPE_OK; int32 lpt_iors (void) { -return ((int_req & INT_LPT)? IOS_LPT: 0) | - ((int_req & INT_LPTSPC)? IOS_LPT1: 0); +return (TST_INT (LPT)? IOS_LPT: 0) | + (TST_INT (LPTSPC)? IOS_LPT1: 0); } #elif defined (TYPE647) #define LPT_BSIZE 120 /* line size */ -extern int32 int_req; +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 }; @@ -209,7 +211,7 @@ UNIT lpt_unit = { REG lpt_reg[] = { { ORDATA (BUF, lpt_unit.buf, 8) }, - { FLDATA (INT, int_req, INT_V_LPT) }, + { FLDATA (INT, int_hwre[API_LPT], INT_V_LPT) }, { FLDATA (DONE, lpt_done, 0) }, #if defined (PDP9) { FLDATA (ENABLE, lpt_ie, 0) }, @@ -238,16 +240,16 @@ int32 i; if (pulse == 001) return (lpt_done? IOT_SKP + AC: AC); /* LPSF */ if (pulse & 002) { /* pulse 02 */ lpt_done = 0; /* clear done */ - int_req = int_req & ~INT_LPT; } /* clear int req */ + CLR_INT (LPT); } /* clear int req */ if (pulse == 002) { /* LPCB */ for (i = 0; i < LPT_BSIZE; i++) lpt_buf[i] = 0; bptr = 0; /* reset buf ptr */ lpt_done = 1; /* set done */ - if (lpt_ie) int_req = int_req | INT_LPT; } /* set int */ + if (lpt_ie) SET_INT (LPT); } /* set int */ #if defined (PDP9) if (pulse == 004) { /* LPDI */ lpt_ie = 0; /* clear int enable */ - int_req = int_req & ~INT_LPT; } /* clear int req */ + CLR_INT (LPT); } /* clear int req */ #endif if ((pulse == 046) && (bptr < LPT_BSIZE)) { /* LPB3 */ lpt_buf[bptr] = lpt_buf[bptr] | ((AC >> 12) & 077); @@ -260,7 +262,7 @@ if ((pulse == 046) || (pulse == 026) || (pulse == 066)) { lpt_buf[bptr] = lpt_buf[bptr] | (AC & 077); bptr = bptr + 1; } lpt_done = 1; /* set done */ - if (lpt_ie) int_req = int_req | INT_LPT; } /* set int */ + if (lpt_ie) SET_INT (LPT); } /* set int */ return AC; } @@ -269,14 +271,14 @@ int32 lpt66 (int32 pulse, int32 AC) if (pulse == 001) return (lpt_err? IOT_SKP + AC: AC); /* LPSE */ if (pulse & 002) { /* LPCF */ lpt_done = 0; /* clear done, int */ - int_req = int_req & ~INT_LPT; } + CLR_INT (LPT); } if (((pulse & 060) < 060) && (pulse & 004)) { /* LPLS, LPPB, LPPS */ lpt_iot = (pulse & 060) | (AC & 07); /* save parameters */ sim_activate (&lpt_unit, lpt_unit.wait); } /* activate */ #if defined (PDP9) if (pulse == 064) { /* LPEI */ lpt_ie = 1; /* set int enable */ - if (lpt_done) int_req = int_req | INT_LPT; } + if (lpt_done) SET_INT (LPT); } #endif return AC; } @@ -303,7 +305,7 @@ static const char *lpt_cc[] = { "\f" }; lpt_done = 1; -if (lpt_ie) int_req = int_req | INT_LPT; /* set flag */ +if (lpt_ie) SET_INT (LPT); /* set flag */ if ((lpt_unit.flags & UNIT_ATT) == 0) { /* not attached? */ lpt_err = 1; /* set error */ return IORETURN (lpt_stopioe, SCPE_UNATT); } @@ -338,7 +340,7 @@ int32 i; lpt_done = 0; /* clear done */ lpt_err = (lpt_unit.flags & UNIT_ATT)? 0: 1; /* compute error */ lpt_ie = 1; /* set enable */ -int_req = int_req & ~INT_LPT; /* clear int */ +CLR_INT (LPT); /* clear int */ sim_cancel (&lpt_unit); /* deactivate unit */ bptr = 0; /* clear buffer ptr */ lpt_iot = 0; /* clear state */ @@ -391,7 +393,7 @@ return detach_unit (uptr); #define STA_CLR 0003777 /* always clear */ extern int32 M[]; -extern int32 int_req; +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 }; @@ -413,7 +415,7 @@ UNIT lpt_unit = { REG lpt_reg[] = { { ORDATA (STA, lpt_sta, 18) }, { ORDATA (CA, M[LPT_CA], 18) }, - { FLDATA (INT, int_req, INT_V_LPT) }, + { FLDATA (INT, int_hwre[API_LPT], INT_V_LPT) }, { FLDATA (ENABLE, lpt_ie, 0) }, { DRDATA (LCNT, lcnt, 9) }, { DRDATA (BPTR, bptr, 8) }, @@ -523,8 +525,8 @@ int32 lpt_updsta (int32 new) lpt_sta = (lpt_sta | new) & ~(STA_CLR | STA_ERR | STA_BUSY); if (lpt_sta & STA_EFLGS) lpt_sta = lpt_sta | STA_ERR; /* update errors */ if (sim_is_active (&lpt_unit)) lpt_sta = lpt_sta | STA_BUSY; -if (lpt_ie && (lpt_sta & STA_DON)) int_req = int_req | INT_LPT; -else int_req = int_req & ~INT_LPT; /* update int */ +if (lpt_ie && (lpt_sta & STA_DON)) SET_INT (LPT); +else CLR_INT (LPT); /* update int */ return lpt_sta; } diff --git a/pdp18b_mt.c b/PDP18B/pdp18b_mt.c similarity index 84% rename from pdp18b_mt.c rename to PDP18B/pdp18b_mt.c index 326cd1c4..d9b222a9 100644 --- a/pdp18b_mt.c +++ b/PDP18B/pdp18b_mt.c @@ -26,6 +26,9 @@ mt (PDP-9) TC59 magtape (PDP-15) TC59D magtape + 29-Nov-01 RMS Added read only unit support + 25-Nov-01 RMS Revised interrupt structure + Changed UST, POS, FLG to arrays 26-Apr-01 RMS Added device enable/disable support 15-Feb-01 RMS Fixed 3-cycle data break sequence 04-Oct-98 RMS V2.4 magtape format @@ -59,6 +62,7 @@ #define DBMASK (DBSIZE - 1) #define MT_WC 032 /* word count */ #define MT_CA 033 /* current addr */ +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ /* Command/unit - mt_cu */ @@ -109,7 +113,7 @@ /* error flags */ extern int32 M[]; -extern int32 int_req, dev_enb; +extern int32 int_hwre[API_HLVL+1], dev_enb; extern UNIT cpu_unit; int32 mt_cu = 0; /* command/unit */ int32 mt_sta = 0; /* status register */ @@ -131,55 +135,28 @@ UNIT *mt_busy (void); */ UNIT mt_unit[] = { - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) } }; + { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) } }; REG mt_reg[] = { { ORDATA (STA, mt_sta, 18) }, { ORDATA (CMD, mt_cu, 18) }, { ORDATA (WC, M[MT_WC], 18) }, { ORDATA (CA, M[MT_CA], 18) }, - { FLDATA (INT, int_req, INT_V_MTA) }, + { FLDATA (INT, int_hwre[API_MTA], INT_V_MTA) }, { FLDATA (STOP_IOE, mt_stopioe, 0) }, { DRDATA (TIME, mt_time, 24), PV_LEFT }, - { ORDATA (UST0, mt_unit[0].USTAT, 18) }, - { ORDATA (UST1, mt_unit[1].USTAT, 18) }, - { ORDATA (UST2, mt_unit[2].USTAT, 18) }, - { ORDATA (UST3, mt_unit[3].USTAT, 18) }, - { ORDATA (UST4, mt_unit[4].USTAT, 18) }, - { ORDATA (UST5, mt_unit[5].USTAT, 18) }, - { ORDATA (UST6, mt_unit[6].USTAT, 18) }, - { ORDATA (UST7, mt_unit[7].USTAT, 18) }, - { DRDATA (POS0, mt_unit[0].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS1, mt_unit[1].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS2, mt_unit[2].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS3, mt_unit[3].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS4, mt_unit[4].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS5, mt_unit[5].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS6, mt_unit[6].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS7, mt_unit[7].pos, 31), PV_LEFT + REG_RO }, - { GRDATA (FLG0, mt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { 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 }, - { GRDATA (FLG7, mt_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, + { URDATA (UST, mt_unit[0].USTAT, 8, 16, 0, MT_NUMDR, 0) }, + { URDATA (POS, mt_unit[0].pos, 10, 31, 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_MTA), REG_HRO }, { NULL } }; @@ -220,7 +197,7 @@ 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_WLK)) + (((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? */ @@ -259,7 +236,7 @@ if ((uptr -> flags & UNIT_ATT) == 0) { /* if not attached */ return IORETURN (mt_stopioe, SCPE_UNATT); } if ((f == FN_WRITE) || (f == FN_WREOF)) { /* write? */ - if (uptr -> flags & UNIT_WLK) { /* 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 */ @@ -404,8 +381,8 @@ mt_sta = (mt_sta & ~(STA_DYN | STA_ERR | STA_CLR)) | (uptr -> USTAT & STA_DYN) | new; 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)) - int_req = int_req | INT_MTA; -else int_req = int_req & ~INT_MTA; /* int request */ + SET_INT (MTA); +else CLR_INT (MTA); /* int request */ return mt_sta; } diff --git a/pdp18b_rf.c b/PDP18B/pdp18b_rf.c similarity index 92% rename from pdp18b_rf.c rename to PDP18B/pdp18b_rf.c index 4626f70f..370ead61 100644 --- a/pdp18b_rf.c +++ b/PDP18B/pdp18b_rf.c @@ -26,6 +26,8 @@ rf (PDP-9) RF09/RF09 (PDP-15) RF15/RS09 + 25-Nov-01 RMS Revised interrupt structure + 24-Nov-01 RMS Changed WLK to array 26-Apr-01 RMS Added device enable/disable support 15-Feb-01 RMS Fixed 3 cycle data break sequencing 30-Nov-99 RMS Added non-zero requirement to rf_time @@ -85,7 +87,7 @@ #define RF_BUSY (sim_is_active (&rf_unit)) extern int32 M[]; -extern int32 int_req, dev_enb; +extern int32 int_hwre[API_HLVL+1], dev_enb; extern UNIT cpu_unit; int32 rf_sta = 0; /* status register */ int32 rf_da = 0; /* disk address */ @@ -115,15 +117,8 @@ REG rf_reg[] = { { ORDATA (WC, M[RF_WC], 18) }, { ORDATA (CA, M[RF_CA], 18) }, { ORDATA (BUF, rf_dbuf, 18) }, - { FLDATA (INT, int_req, INT_V_RF) }, - { ORDATA (WLK0, rf_wlk[0], 16) }, - { ORDATA (WLK1, rf_wlk[1], 16) }, - { ORDATA (WLK2, rf_wlk[2], 16) }, - { ORDATA (WLK3, rf_wlk[3], 16) }, - { ORDATA (WLK4, rf_wlk[4], 16) }, - { ORDATA (WLK5, rf_wlk[5], 16) }, - { ORDATA (WLK6, rf_wlk[6], 16) }, - { ORDATA (WLK7, rf_wlk[7], 16) }, + { FLDATA (INT, int_hwre[API_RF], INT_V_RF) }, + { BRDATA (WLK, rf_wlk, 8, 16, RF_NUMDK) }, { DRDATA (TIME, rf_time, 24), PV_LEFT + REG_NZ }, { FLDATA (BURST, rf_burst, 0) }, { FLDATA (STOP_IOE, rf_stopioe, 0) }, @@ -244,8 +239,8 @@ int32 rf_updsta (int32 new) rf_sta = (rf_sta | new) & ~(RFS_ERR | RFS_CLR); if (rf_sta & RFS_EFLGS) rf_sta = rf_sta | RFS_ERR; if ((rf_sta & (RFS_ERR | RFS_DON)) && (rf_sta & RFS_IE)) - int_req = int_req | INT_RF; -else int_req = int_req & ~INT_RF; + SET_INT (RF); +else CLR_INT (RF); return rf_sta; } diff --git a/pdp18b_rp.c b/PDP18B/pdp18b_rp.c similarity index 90% rename from pdp18b_rp.c rename to PDP18B/pdp18b_rp.c index 68e8958e..ffbff7bf 100644 --- a/pdp18b_rp.c +++ b/PDP18B/pdp18b_rp.c @@ -25,6 +25,9 @@ rp RP15/RP02 disk pack + 29-Nov-01 RMS Added read only unit support + 25-Nov-01 RMS Revised interrupt structure + Changed FLG to array 26-Apr-01 RMS Added device enable/disable support 14-Apr-99 RMS Changed t_addr to unsigned 29-Jun-96 RMS Added unit enable/disable support @@ -43,9 +46,10 @@ /* Unit specific flags */ -#define UNIT_V_HWLK (UNIT_V_UF + 0) /* hwre write lock */ +#define UNIT_V_WLK (UNIT_V_UF + 0) /* hwre write lock */ #define UNIT_W_UF 2 /* user flags width */ -#define UNIT_HWLK (1u << UNIT_V_HWLK) +#define UNIT_WLK (1u << UNIT_V_WLK) +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ /* Parameters in the unit descriptor */ @@ -124,7 +128,7 @@ #define MAX(x,y) (((x) > (y))? (x): (y)) extern int32 M[]; -extern int32 int_req, dev_enb, nexm; +extern int32 int_hwre[API_HLVL+1], dev_enb, nexm; extern UNIT cpu_unit; int32 rp_sta = 0; /* status A */ int32 rp_stb = 0; /* status B */ @@ -165,33 +169,19 @@ REG rp_reg[] = { { ORDATA (DA, rp_da, 18) }, { ORDATA (MA, rp_ma, 18) }, { ORDATA (WC, rp_wc, 18) }, - { FLDATA (INT, int_req, INT_V_RP) }, + { FLDATA (INT, int_hwre[API_RP], INT_V_RP) }, { FLDATA (BUSY, rp_busy, 0) }, { FLDATA (STOP_IOE, rp_stopioe, 0) }, { DRDATA (STIME, rp_swait, 24), PV_LEFT }, { DRDATA (RTIME, rp_rwait, 24), PV_LEFT }, - { GRDATA (FLG0, rp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG1, rp_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG2, rp_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG3, rp_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG4, rp_unit[4].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG5, rp_unit[5].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG6, rp_unit[6].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG7, rp_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, + { URDATA (FLG, rp_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1, + RP_NUMDR, REG_HRO) }, { FLDATA (*DEVENB, dev_enb, INT_V_RP), REG_HRO }, { NULL } }; MTAB rp_mod[] = { - { UNIT_HWLK, 0, "write enabled", "ENABLED", NULL }, - { UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL }, + { UNIT_WLK, 0, "write enabled", "ENABLED", NULL }, + { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, { 0 } }; DEVICE rp_dev = { @@ -315,6 +305,10 @@ 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? */ + rp_updsta (STA_DON | STA_WPE, 0); /* error */ + return SCPE_OK; } + if (GET_SECT (rp_da) >= RP_NUMSC) rp_updsta (STA_NXS, 0); if (GET_SURF (rp_da) >= RP_NUMSF) rp_updsta (STA_NXF, 0); if (GET_CYL (rp_da) >= RP_NUMCY) rp_updsta (STA_NXC, 0); @@ -381,7 +375,7 @@ 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_HWLK) rp_sta = rp_sta | STA_SUWP; +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; @@ -390,8 +384,8 @@ else if (sim_is_active (uptr)) { 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))) int_req = int_req | INT_RP; -else int_req = int_req & ~INT_RP; + ((rp_stb & STB_ATTN) && (rp_sta & STA_IEA))) SET_INT (RP); +else CLR_INT (RP); return; } @@ -403,7 +397,7 @@ int32 i; UNIT *uptr; rp_sta = rp_stb = rp_da = rp_wc = rp_ma = rp_busy = 0; -int_req = int_req & ~INT_RP; +CLR_INT (RP); for (i = 0; i < RP_NUMDR; i++) { uptr = rp_dev.units + i; sim_cancel (uptr); diff --git a/pdp18b_stddev.c b/PDP18B/pdp18b_stddev.c similarity index 88% rename from pdp18b_stddev.c rename to PDP18B/pdp18b_stddev.c index 908b75da..8d0cf67c 100644 --- a/pdp18b_stddev.c +++ b/PDP18B/pdp18b_stddev.c @@ -29,6 +29,8 @@ tto teleprinter clk clock + 29-Nov-01 RMS Added read only unit support + 25-Nov-01 RMS Revised interrupt structure 17-Sep-01 RMS Removed multiconsole support 07-Sep-01 RMS Added terminal multiplexor support 17-Jul-01 RMS Moved function prototype @@ -47,7 +49,7 @@ #include extern int32 M[]; -extern int32 int_req, saved_PC; +extern int32 int_hwre[API_HLVL+1], saved_PC; extern UNIT cpu_unit; int32 clk_state = 0; int32 ptr_err = 0, ptr_stopioe = 0, ptr_state = 0; @@ -83,8 +85,8 @@ t_stat ptr_boot (int32 unitno); UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 16000 }; REG clk_reg[] = { - { FLDATA (INT, int_req, INT_V_CLK) }, - { FLDATA (DONE, int_req, INT_V_CLK) }, + { FLDATA (INT, int_hwre[API_CLK], INT_V_CLK) }, + { FLDATA (DONE, int_hwre[API_CLK], INT_V_CLK) }, { FLDATA (ENABLE, clk_state, 0) }, { DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT }, { DRDATA (TPS, clk_tps, 8), REG_NZ + PV_LEFT }, @@ -104,12 +106,13 @@ DEVICE clk_dev = { */ UNIT ptr_unit = { - UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_IN_WAIT }; + UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), + SERIAL_IN_WAIT }; REG ptr_reg[] = { { ORDATA (BUF, ptr_unit.buf, 18) }, - { FLDATA (INT, int_req, INT_V_PTR) }, - { FLDATA (DONE, int_req, INT_V_PTR) }, + { FLDATA (INT, int_hwre[API_PTR], INT_V_PTR) }, + { FLDATA (DONE, int_hwre[API_PTR], INT_V_PTR) }, #if defined (IOS_PTRERR) { FLDATA (ERR, ptr_err, 0) }, #endif @@ -137,8 +140,8 @@ UNIT ptp_unit = { REG ptp_reg[] = { { ORDATA (BUF, ptp_unit.buf, 8) }, - { FLDATA (INT, int_req, INT_V_PTP) }, - { FLDATA (DONE, int_req, INT_V_PTP) }, + { FLDATA (INT, int_hwre[API_PTP], INT_V_PTP) }, + { FLDATA (DONE, int_hwre[API_PTP], INT_V_PTP) }, #if defined (IOS_PTPERR) { FLDATA (ERR, ptp_err, 0) }, #endif @@ -205,8 +208,8 @@ UNIT tti_unit = { UDATA (&tti_svc, UNIT_UC+UNIT_HDX, 0), KBD_POLL_WAIT }; REG tti_reg[] = { { ORDATA (BUF, tti_unit.buf, TTI_WIDTH) }, - { FLDATA (INT, int_req, INT_V_TTI) }, - { FLDATA (DONE, int_req, INT_V_TTI) }, + { FLDATA (INT, int_hwre[API_TTI], INT_V_TTI) }, + { FLDATA (DONE, int_hwre[API_TTI], INT_V_TTI) }, #if defined (KSR28) { ORDATA (TTI_STATE, tti_state, (TTI_WIDTH + 3)), REG_HRO }, #else @@ -264,8 +267,8 @@ UNIT tto_unit = { UDATA (&tto_svc, UNIT_UC, 0), SERIAL_OUT_WAIT }; REG tto_reg[] = { { ORDATA (BUF, tto_unit.buf, TTO_WIDTH) }, - { FLDATA (INT, int_req, INT_V_TTO) }, - { FLDATA (DONE, int_req, INT_V_TTO) }, + { FLDATA (INT, int_hwre[API_TTO], INT_V_TTO) }, + { FLDATA (DONE, int_hwre[API_TTO], INT_V_TTO) }, #if defined (KSR28) { FLDATA (TTO_STATE, tto_state, 0), REG_HRO }, #endif @@ -291,10 +294,10 @@ DEVICE tto_dev = { int32 clk (int32 pulse, int32 AC) { if (pulse & 001) { /* CLSF */ - if (int_req & INT_CLK) AC = AC | IOT_SKP; } + if (TST_INT (CLK)) AC = AC | IOT_SKP; } if (pulse & 004) { /* CLON/CLOF */ if (pulse & 040) { /* CLON */ - int_req = int_req & ~INT_CLK; /* clear flag */ + CLR_INT (CLK); /* clear flag */ clk_state = 1; /* clock on */ if (!sim_is_active (&clk_unit)) /* already on? */ sim_activate (&clk_unit, /* start, calibr */ @@ -311,7 +314,7 @@ int32 t; if (clk_state) { /* clock on? */ M[7] = (M[7] + 1) & 0777777; /* incr counter */ - if (M[7] == 0) int_req = int_req | INT_CLK; /* ovrflo? set flag */ + if (M[7] == 0) SET_INT (CLK); /* ovrflo? set flag */ t = sim_rtc_calb (clk_tps); /* calibrate clock */ sim_activate (&clk_unit, t); /* reactivate unit */ tmxr_poll = t; } /* set mux poll */ @@ -322,7 +325,7 @@ return SCPE_OK; t_stat clk_reset (DEVICE *dptr) { -int_req = int_req & ~INT_CLK; /* clear flag */ +CLR_INT (CLK); /* clear flag */ clk_state = 0; /* clock off */ sim_cancel (&clk_unit); /* stop clock */ tmxr_poll = clk_unit.wait; /* set mux poll */ @@ -333,18 +336,18 @@ return SCPE_OK; int32 std_iors (void) { -return ((int_req & INT_CLK)? IOS_CLK: 0) | - ((int_req & INT_PTR)? IOS_PTR: 0) | - ((int_req & INT_PTP)? IOS_PTP: 0) | - ((int_req & INT_TTI)? IOS_TTI: 0) | - ((int_req & INT_TTO)? IOS_TTO: 0) | +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); + (clk_state? IOS_CLKON: 0)); } /* Paper tape reader: IOT routine */ @@ -352,13 +355,13 @@ return ((int_req & INT_CLK)? IOS_CLK: 0) | int32 ptr (int32 pulse, int32 AC) { if (pulse & 001) { /* RSF */ - if (int_req & INT_PTR) AC = AC | IOT_SKP; } + if (TST_INT (PTR)) AC = AC | IOT_SKP; } if (pulse & 002) { /* RRB, RCF */ - int_req = int_req & ~INT_PTR; /* clear done */ + CLR_INT (PTR); /* clear done */ AC = AC | ptr_unit.buf; } /* return buffer */ if (pulse & 004) { /* RSA, RSB */ ptr_state = (pulse & 040)? 18: 0; /* set mode */ - int_req = int_req & ~INT_PTR; /* clear done */ + CLR_INT (PTR); /* clear done */ ptr_unit.buf = 0; /* clear buffer */ sim_activate (&ptr_unit, ptr_unit.wait); } return AC; @@ -372,13 +375,13 @@ int32 temp; if ((ptr_unit.flags & UNIT_ATT) == 0) { /* attached? */ #if defined (IOS_PTRERR) - int_req = int_req | INT_PTR; /* if err, set int */ + SET_INT (PTR); /* if err, set int */ ptr_err = 1; #endif return IORETURN (ptr_stopioe, SCPE_UNATT); } if ((temp = getc (ptr_unit.fileref)) == EOF) { /* end of file? */ #if defined (IOS_PTRERR) - int_req = int_req | INT_PTR; /* if err, set done */ + SET_INT (PTR); /* if err, set done */ ptr_err = 1; #endif if (feof (ptr_unit.fileref)) { @@ -391,7 +394,7 @@ if (ptr_state == 0) ptr_unit.buf = temp & 0377; /* alpha */ else if (temp & 0200) { /* binary */ ptr_state = ptr_state - 6; ptr_unit.buf = ptr_unit.buf | ((temp & 077) << ptr_state); } -if (ptr_state == 0) int_req = int_req | INT_PTR; /* if done, set flag */ +if (ptr_state == 0) SET_INT (PTR); /* if done, set flag */ else sim_activate (&ptr_unit, ptr_unit.wait); /* else restart */ ptr_unit.pos = ptr_unit.pos + 1; return SCPE_OK; @@ -403,7 +406,7 @@ t_stat ptr_reset (DEVICE *dptr) { ptr_state = 0; /* clear state */ ptr_unit.buf = 0; -int_req = int_req & ~INT_PTR; /* clear flag */ +CLR_INT (PTR); /* clear flag */ ptr_err = (ptr_unit.flags & UNIT_ATT)? 0: 1; sim_cancel (&ptr_unit); /* deactivate unit */ return SCPE_OK; @@ -605,10 +608,10 @@ return SCPE_ARG; int32 ptp (int32 pulse, int32 AC) { if (pulse & 001) { /* PSF */ - if (int_req & INT_PTP) AC = AC | IOT_SKP; } -if (pulse & 002) int_req = int_req & ~INT_PTP; /* PCF */ + if (TST_INT (PTP)) AC = AC | IOT_SKP; } +if (pulse & 002) CLR_INT (PTP); /* PCF */ if (pulse & 004) { /* PSA, PSB, PLS */ - int_req = int_req & ~INT_PTP; /* clear flag */ + CLR_INT (PTP); /* clear flag */ ptp_unit.buf = (pulse & 040)? /* load punch buf */ (AC & 077) | 0200: AC & 0377; /* bin or alpha */ sim_activate (&ptp_unit, ptp_unit.wait); } /* activate unit */ @@ -619,7 +622,7 @@ return AC; t_stat ptp_svc (UNIT *uptr) { -int_req = int_req | INT_PTP; /* set done flag */ +SET_INT (PTP); /* set done flag */ if ((ptp_unit.flags & UNIT_ATT) == 0) { /* not attached? */ ptp_err = 1; /* set error */ return IORETURN (ptp_stopioe, SCPE_UNATT); } @@ -637,7 +640,7 @@ return SCPE_OK; t_stat ptp_reset (DEVICE *dptr) { ptp_unit.buf = 0; -int_req = int_req & ~INT_PTP; /* clear flag */ +CLR_INT (PTP); /* clear flag */ ptp_err = (ptp_unit.flags & UNIT_ATT)? 0: 1; sim_cancel (&ptp_unit); /* deactivate unit */ return SCPE_OK; @@ -667,9 +670,9 @@ return detach_unit (uptr); int32 tti (int32 pulse, int32 AC) { if (pulse & 001) { /* KSF */ - if (int_req & INT_TTI) AC = AC | IOT_SKP; } + if (TST_INT (TTI)) AC = AC | IOT_SKP; } if (pulse & 002) { /* KRB */ - int_req = int_req & ~INT_TTI; /* clear flag */ + CLR_INT (TTI); /* clear flag */ AC = AC | tti_unit.buf & TTI_MASK; } /* return buffer */ return AC; } @@ -705,7 +708,7 @@ if ((tti_unit.flags & UNIT_HDX) && tto_unit.pos = tto_unit.pos + 1; } tti_unit.buf = temp | 0200; /* got char */ #endif -int_req = int_req | INT_TTI; /* set flag */ +SET_INT (TTI); /* set flag */ tti_unit.pos = tti_unit.pos + 1; return SCPE_OK; } @@ -716,7 +719,7 @@ t_stat tti_reset (DEVICE *dptr) { tti_unit.buf = 0; /* clear buffer */ tti_state = 0; /* clear state */ -int_req = int_req & ~INT_TTI; /* clear flag */ +CLR_INT (TTI); /* clear flag */ sim_activate (&tti_unit, tti_unit.wait); /* activate unit */ return SCPE_OK; } @@ -726,8 +729,8 @@ return SCPE_OK; int32 tto (int32 pulse, int32 AC) { if (pulse & 001) { /* TSF */ - if (int_req & INT_TTO) AC = AC | IOT_SKP; } -if (pulse & 002) int_req = int_req & ~INT_TTO; /* clear flag */ + if (TST_INT (TTO)) AC = AC | IOT_SKP; } +if (pulse & 002) CLR_INT (TTO); /* clear flag */ if (pulse & 004) { /* load buffer */ sim_activate (&tto_unit, tto_unit.wait); /* activate unit */ tto_unit.buf = AC & TTO_MASK; } /* load buffer */ @@ -740,7 +743,7 @@ t_stat tto_svc (UNIT *uptr) { int32 out, temp; -int_req = int_req | INT_TTO; /* set flag */ +SET_INT (TTO); /* set flag */ #if defined (KSR28) /* Baudot... */ if (tto_unit.buf == BAUDOT_FIGURES) { /* set figures? */ tto_state = TTO_FIGURES; @@ -766,7 +769,7 @@ t_stat tto_reset (DEVICE *dptr) { tto_unit.buf = 0; /* clear buffer */ tto_state = 0; /* clear state */ -int_req = int_req & ~INT_TTO; /* clear flag */ +CLR_INT (TTO); /* clear flag */ sim_cancel (&tto_unit); /* deactivate unit */ return SCPE_OK; } diff --git a/pdp18b_sys.c b/PDP18B/pdp18b_sys.c similarity index 100% rename from pdp18b_sys.c rename to PDP18B/pdp18b_sys.c diff --git a/pdp18b_tt1.c b/PDP18B/pdp18b_tt1.c similarity index 81% rename from pdp18b_tt1.c rename to PDP18B/pdp18b_tt1.c index ba8625ba..b558b01e 100644 --- a/pdp18b_tt1.c +++ b/PDP18B/pdp18b_tt1.c @@ -26,6 +26,8 @@ tti1 keyboard tto1 teleprinter + 30-Nov-01 RMS Added extended SET/SHOW support + 25-Nov-01 RMS Revised interrupt structure 19-Sep-01 RMS Fixed typo 17-Sep-01 RMS Changed to use terminal multiplexor library 07-Sep-01 RMS Moved function prototypes @@ -40,7 +42,7 @@ #define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */ #define UNIT_UC (1 << UNIT_V_UC) -extern int32 int_req, saved_PC; +extern int32 int_hwre[API_HLVL+1]; extern int32 tmxr_poll; /* calibrated poll */ TMLN tt1_ldsc = { 0 }; /* line descriptors */ TMXR tt_desc = { 1, 0, &tt1_ldsc }; /* mux descriptor */ @@ -51,7 +53,7 @@ t_stat tti1_reset (DEVICE *dptr); t_stat tto1_reset (DEVICE *dptr); t_stat tti1_attach (UNIT *uptr, char *cptr); t_stat tti1_detach (UNIT *uptr); -t_stat tti1_status (UNIT *uptr, FILE *st); +t_stat tti1_status (FILE *st, UNIT *uptr, int32 val, void *desc); /* TTI1 data structures @@ -65,21 +67,23 @@ UNIT tti1_unit = { UDATA (&tti1_svc, UNIT_ATTABLE+UNIT_UC, 0), KBD_POLL_WAIT }; REG tti1_reg[] = { { ORDATA (BUF, tti1_unit.buf, 8) }, - { FLDATA (INT, int_req, INT_V_TTI1) }, - { FLDATA (DONE, int_req, INT_V_TTI1) }, + { 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, 31), PV_LEFT }, { DRDATA (TIME, tti1_unit.wait, 24), REG_NZ + PV_LEFT }, { NULL } }; -MTAB ttx1_mod[] = { - { UNIT_ATT, UNIT_ATT, "line status:", NULL, &tti1_status }, +MTAB tti1_mod[] = { { UNIT_UC, 0, "lower case", "LC", NULL }, { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, + { UNIT_ATT, UNIT_ATT, "line status", NULL, NULL, &tti1_status }, + { MTAB_XTD | MTAB_VDV | MTAB_VUN | MTAB_NMO, 0, "LINE", NULL, + NULL, &tti1_status, NULL }, { 0 } }; DEVICE tti1_dev = { - "TTI1", &tti1_unit, tti1_reg, ttx1_mod, + "TTI1", &tti1_unit, tti1_reg, tti1_mod, 1, 10, 31, 1, 8, 8, &tmxr_ex, &tmxr_dep, &tti1_reset, NULL, &tti1_attach, &tti1_detach }; @@ -96,14 +100,19 @@ UNIT tto1_unit = { UDATA (&tto1_svc, UNIT_UC, 0), SERIAL_OUT_WAIT }; REG tto1_reg[] = { { ORDATA (BUF, tto1_unit.buf, 8) }, - { FLDATA (INT, int_req, INT_V_TTO1) }, - { FLDATA (DONE, int_req, INT_V_TTO1) }, + { FLDATA (INT, int_hwre[API_TTO1], INT_V_TTO1) }, + { FLDATA (DONE, int_hwre[API_TTO1], INT_V_TTO1) }, { DRDATA (POS, tt1_ldsc.txcnt, 31), PV_LEFT }, { DRDATA (TIME, tto1_unit.wait, 24), PV_LEFT }, { NULL } }; +MTAB tto1_mod[] = { + { UNIT_UC, 0, "lower case", "LC", NULL }, + { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, + { 0 } }; + DEVICE tto1_dev = { - "TTO1", &tto1_unit, tto1_reg, ttx1_mod, + "TTO1", &tto1_unit, tto1_reg, tto1_mod, 1, 10, 31, 1, 8, 8, NULL, NULL, &tto1_reset, NULL, NULL, NULL }; @@ -113,9 +122,9 @@ DEVICE tto1_dev = { int32 tti1 (int32 pulse, int32 AC) { if (pulse & 001) { /* KSF1 */ - if (int_req & INT_TTI1) AC = AC | IOT_SKP; } + if (TST_INT (TTI1)) AC = AC | IOT_SKP; } if (pulse & 002) { /* KRB1 */ - int_req = int_req & ~INT_TTI1; /* clear flag */ + CLR_INT (TTI1); /* clear flag */ AC= AC | tti1_unit.buf; } /* return buffer */ return AC; } @@ -133,7 +142,7 @@ if (tt1_ldsc.conn) { /* connected? */ if ((uptr -> flags & UNIT_UC) && islower (temp)) temp = toupper (temp); uptr -> buf = temp | 0200; /* got char */ - int_req = int_req | INT_TTI1; } /* set flag */ + 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 */ @@ -149,7 +158,7 @@ return SCPE_OK; t_stat tti1_reset (DEVICE *dptr) { tti1_unit.buf = 0; /* clear buffer */ -int_req = int_req & ~INT_TTI1; /* clear flag */ +CLR_INT (TTI1); /* clear flag */ if (tt1_ldsc.conn) { /* if conn, */ sim_activate (&tti1_unit, tti1_unit.wait); /* activate, */ tt1_ldsc.rcve = 1; } /* enable */ @@ -164,8 +173,8 @@ return SCPE_OK; int32 tto1 (int32 pulse, int32 AC) { if (pulse & 001) { /* TSF */ - if (int_req & INT_TTO1) AC = AC | IOT_SKP; } -if (pulse & 002) int_req = int_req & ~INT_TTO1; /* clear flag */ + if (TST_INT (TTO1)) AC = AC | IOT_SKP; } +if (pulse & 002) CLR_INT (TTO1); /* clear flag */ if (pulse & 004) { /* load buffer */ sim_activate (&tto1_unit, tto1_unit.wait); /* activate unit */ tto1_unit.buf = AC & 0377; } /* load buffer */ @@ -178,7 +187,7 @@ t_stat tto1_svc (UNIT *uptr) { int32 out; -int_req = int_req | INT_TTO1; /* set flag */ +SET_INT (TTO1); /* set flag */ out = tto1_unit.buf & 0177; if (tt1_ldsc.conn) { /* connected? */ if (tt1_ldsc.xmte) { /* tx enabled? */ @@ -197,7 +206,7 @@ return SCPE_OK; t_stat tto1_reset (DEVICE *dptr) { tto1_unit.buf = 0; /* clear buffer */ -int_req = int_req & ~INT_TTO1; /* clear flag */ +CLR_INT (TTO1); /* clear flag */ sim_cancel (&tto1_unit); /* deactivate unit */ return SCPE_OK; } @@ -228,7 +237,7 @@ return r; /* Status routine */ -t_stat tti1_status (UNIT *uptr, FILE *st) +t_stat tti1_status (FILE *st, UNIT *uptr, int32 val, void *desc) { tmxr_fstatus (st, &tt1_ldsc, -1); return SCPE_OK; diff --git a/pdp8_clk.c b/PDP8/pdp8_clk.c similarity index 100% rename from pdp8_clk.c rename to PDP8/pdp8_clk.c diff --git a/pdp8_cpu.c b/PDP8/pdp8_cpu.c similarity index 92% rename from pdp8_cpu.c rename to PDP8/pdp8_cpu.c index e029e4b6..d9e78fec 100644 --- a/pdp8_cpu.c +++ b/PDP8/pdp8_cpu.c @@ -25,6 +25,9 @@ cpu central processor + 16-Dec-01 RMS Fixed bugs in EAE + 07-Dec-01 RMS Revised to use new breakpoint package + 30-Nov-01 RMS Added RL8A, extended SET/SHOW support 16-Sep-01 RMS Fixed bug in reset routine, added KL8A support 10-Aug-01 RMS Removed register from declarations 17-Jul-01 RMS Moved function prototype @@ -176,8 +179,6 @@ #include "pdp8_defs.h" -#define ILL_ADR_FLAG 0100000 /* invalid addr flag */ -#define save_ibkpt (cpu_unit.u3) /* saved bkpt addr */ #define UNIT_V_NOEAE (UNIT_V_UF) /* EAE absent */ #define UNIT_NOEAE (1 << UNIT_V_NOEAE) #define UNIT_V_MSIZE (UNIT_V_UF+1) /* dummy mask */ @@ -200,16 +201,15 @@ int32 old_PC = 0; /* old PC */ 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; /* device enables */ -int32 ibkpt_addr = ILL_ADR_FLAG | ADDRMASK; /* breakpoint addr */ +int32 dev_enb = -1 & ~INT_DF & ~INT_RL; /* device enables */ int32 stop_inst = 0; /* trap on ill inst */ extern int32 sim_int_char; +extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ 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_svc (UNIT *uptr); -t_stat cpu_set_size (UNIT *uptr, int32 value); +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); /* CPU data structures @@ -219,7 +219,7 @@ t_stat cpu_set_size (UNIT *uptr, int32 value); cpu_mod CPU modifier list */ -UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) }; +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) }; REG cpu_reg[] = { { ORDATA (PC, saved_PC, 15) }, @@ -247,7 +247,6 @@ REG cpu_reg[] = { { FLDATA (NOEAE, cpu_unit.flags, UNIT_V_NOEAE), REG_HRO }, { ORDATA (OLDPC, old_PC, 15), REG_RO }, { FLDATA (STOP_INST, stop_inst, 0) }, - { ORDATA (BREAK, ibkpt_addr, 16) }, { ORDATA (WRU, sim_int_char, 8) }, { ORDATA (DEVENB, dev_enb, 32), REG_HRO }, { NULL } }; @@ -296,6 +295,8 @@ 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); @@ -327,10 +328,7 @@ if (int_req > INT_PENDING) { /* interrupt? */ PC = 1; } /* fetch next from 1 */ MA = IF | PC; /* form PC */ -if (MA == ((t_addr) ibkpt_addr)) { /* breakpoint? */ - save_ibkpt = ibkpt_addr; /* save ibkpt */ - ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */ - sim_activate (&cpu_unit, 1); /* sched re-enable */ +if (sim_brk_summ && sim_brk_test (MA, SWMASK ('E'))) { /* breakpoint? */ reason = STOP_IBKPT; /* stop simulation */ break; } @@ -745,6 +743,7 @@ case 036:case 037: /* OPR, groups 2, 3 */ /* EAE continued */ + if (emode == 0) gtf = 0; /* mode A? clr gtf */ switch ((IR >> 1) & 027) { /* decode IR<6,8:10> */ case 020: /* mode A, B: SCA */ LAC = LAC | SC; @@ -832,7 +831,8 @@ case 036:case 037: /* OPR, groups 2, 3 */ LAC = LAC | SC; /* mode A: SCA then */ case 5: /* SHL */ SC = (M[IF | PC] & 037) + (emode ^ 1); /* shift+1 if mode A */ - temp = ((LAC << 12) | MQ) << SC; /* preserve link */ + if (SC > 25) temp = 0; /* >25? result = 0 */ + else temp = ((LAC << 12) | MQ) << SC; /* <=25? shift LAC:MQ */ LAC = (temp >> 12) & 017777; MQ = temp & 07777; PC = (PC + 1) & 07777; @@ -851,10 +851,10 @@ case 036:case 037: /* OPR, groups 2, 3 */ case 6: /* ASR */ SC = (M[IF | PC] & 037) + (emode ^ 1); /* shift+1 if mode A */ temp = ((LAC & 07777) << 12) | MQ; /* sext from AC0 */ + if (LAC & 04000) temp = temp | ~037777777; if (emode && (SC != 0)) gtf = (temp >> (SC - 1)) & 1; - temp = temp >> SC; - if (LAC & 04000) temp = temp | ((SC > 24)? -1: - (-1 << (24 - SC))); + if (SC > 25) temp = (LAC & 04000)? -1: 0; + else temp = temp >> SC; LAC = (temp >> 12) & 017777; MQ = temp & 07777; PC = (PC + 1) & 07777; @@ -871,7 +871,8 @@ case 036:case 037: /* OPR, groups 2, 3 */ SC = (M[IF | PC] & 037) + (emode ^ 1); /* shift+1 if mode A */ temp = ((LAC & 07777) << 12) | MQ; /* clear link */ if (emode && (SC != 0)) gtf = (temp >> (SC - 1)) & 1; - temp = temp >> SC; + if (SC > 24) temp = 0; /* >24? result = 0 */ + else temp = temp >> SC; /* <=24? shift AC:MQ */ LAC = (temp >> 12) & 07777; MQ = temp & 07777; PC = (PC + 1) & 07777; @@ -1030,11 +1031,13 @@ case 030:case 031:case 032:case 033: /* IOT */ 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: @@ -1098,15 +1101,7 @@ t_stat cpu_reset (DEVICE *dptr) int_req = (int_req & ~INT_ION) | INT_NO_CIF_PENDING; saved_DF = IB = saved_PC & 070000; UF = UB = gtf = emode = 0; -return cpu_svc (&cpu_unit); -} - -/* Breakpoint service */ - -t_stat cpu_svc (UNIT *uptr) -{ -if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt) ibkpt_addr = save_ibkpt; -save_ibkpt = -1; +sim_brk_types = sim_brk_dflt = SWMASK ('E'); return SCPE_OK; } @@ -1130,17 +1125,17 @@ return SCPE_OK; /* Memory size change */ -t_stat cpu_set_size (UNIT *uptr, int32 value) +t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) { int32 mc = 0; t_addr i; -if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 07777) != 0)) +if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0)) return SCPE_ARG; -for (i = value; i < MEMSIZE; i++) mc = mc | M[i]; +for (i = val; i < MEMSIZE; i++) mc = mc | M[i]; if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) return SCPE_OK; -MEMSIZE = value; +MEMSIZE = val; for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; return SCPE_OK; } diff --git a/pdp8_defs.h b/PDP8/pdp8_defs.h similarity index 93% rename from pdp8_defs.h rename to PDP8/pdp8_defs.h index 25acc4df..3fd82513 100644 --- a/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. + 25-Nov-01 RMS Added RL8A support 16-Sep-01 RMS Added multiple KL support 18-Mar-01 RMS Added DF32 support 15-Feb-01 RMS Added DECtape support @@ -101,9 +102,10 @@ #define INT_V_DF (INT_V_DIRECT+3) /* DF32 */ #define INT_V_MT (INT_V_DIRECT+4) /* TM8E */ #define INT_V_DTA (INT_V_DIRECT+5) /* TC08 */ -#define INT_V_PWR (INT_V_DIRECT+6) /* power int */ -#define INT_V_UF (INT_V_DIRECT+7) /* user int */ -#define INT_V_OVHD (INT_V_DIRECT+8) /* overhead start */ +#define INT_V_RL (INT_V_DIRECT+6) /* RL8A */ +#define INT_V_PWR (INT_V_DIRECT+7) /* power int */ +#define INT_V_UF (INT_V_DIRECT+8) /* user int */ +#define INT_V_OVHD (INT_V_DIRECT+9) /* overhead start */ #define INT_V_NO_ION_PENDING (INT_V_OVHD+0) /* ion pending */ #define INT_V_NO_CIF_PENDING (INT_V_OVHD+1) /* cif pending */ #define INT_V_ION (INT_V_OVHD+2) /* interrupts on */ @@ -128,6 +130,7 @@ #define INT_DF (1 << INT_V_DF) #define INT_MT (1 << INT_V_MT) #define INT_DTA (1 << INT_V_DTA) +#define INT_RL (1 << INT_V_RL) #define INT_PWR (1 << INT_V_PWR) #define INT_UF (1 << INT_V_UF) #define INT_NO_ION_PENDING (1 << INT_V_NO_ION_PENDING) diff --git a/pdp8_df.c b/PDP8/pdp8_df.c similarity index 95% rename from pdp8_df.c rename to PDP8/pdp8_df.c index d6421fa0..41209aad 100644 --- a/pdp8_df.c +++ b/PDP8/pdp8_df.c @@ -25,6 +25,7 @@ df DF32 fixed head disk + 28-Nov-01 RMS Added RL8A support 25-Apr-01 RMS Added device enable/disable support The DF32 is a head-per-track disk. It uses the three cycle data break @@ -229,7 +230,8 @@ return SCPE_OK; t_stat df_reset (DEVICE *dptr) { -if (dev_enb & INT_DF) dev_enb = dev_enb & ~INT_RF; /* either DF or RF */ +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 */ diff --git a/PDP8/pdp8_doc.txt b/PDP8/pdp8_doc.txt new file mode 100644 index 00000000..149d7831 --- /dev/null +++ b/PDP8/pdp8_doc.txt @@ -0,0 +1,676 @@ +To: Users +From: Bob Supnik +Subj: PDP-8 Simulator Usage +Date: 1-Dec-01 + + COPYRIGHT NOTICE + +The following copyright notice applies to both the SIMH source and binary: + + Original code published in 1993-2001, written by Robert M Supnik + 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. + +This memorandum documents the PDP-8 simulator. + + +1. Simulator Files + +sim/ sim_defs.h + sim_sock.h + sim_tmxr.h + scp.c + scp_tty.c + sim_rev.c + sim_sock.c + sim_tmxr.c + +sim/pdp8/ pdp8_defs.h + pdp8_cpu.c + pdp8_df.c + pdp8_dt.c + pdp8_lp.c + pdp8_mt.c + pdp8_pt.c + pdp8_rf.c + pdp8_rk.c + pdp8_rl.c + pdp8_rx.c + pdp8_sys.c + pdp8_tt.c + pdp8_ttx.c + +2. PDP-8 Features + +The PDP-8 simulator is configured as follows: + +device simulates +name(s) + +CPU PDP-8/E CPU with 32KW of memory +- KE8E extended arithmetic element (EAE) +- KM8E memory management and timeshare control +PTR,PTP PC8E paper tape reader/punch +TTI,TTO KL8E console terminal +TTI1-4,TTO1-4 KL8JA additional terminals +LPT LE8E line printer +CLK DK8E line frequency clock (also PDP-8/A compatible) +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 +DT TC08/TU56 DECtape controller with eight drives +MT TM8E/TU10 magnetic tape controller with eight drives + +The RK, RF, DF, RL, RX, DT, and MT devices can be 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: + + ENABLE DF enable DF32, disable RF08 and RL8A + ENABLE RF enable RF08, disable DF32 and RL8A + ENABLE RL enable RL8A, disable DF32 and RF08 + +The PDP-8 simulator implements one unique stop condition: if an undefined +instruction (unimplemented IOT or OPR) is decoded, and register STOP_INST +is set, the simulator halts. + +The PDP-8 loader supports both RIM format 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. + +2.1 CPU + +The only CPU options are the presence of the EAE and the size of main +memory; the memory extension and time-share control is always included, +even if memory size is 4K. + + SET CPU EAE enable EAE + SET CPU NOEAE disable EAE + SET CPU 4K set memory size = 4K + SET CPU 8K set memory size = 8K + SET CPU 12K set memory size = 12K + SET CPU 16K set memory size = 16K + SET CPU 20K set memory size = 20K + SET CPU 24K set memory size = 24K + SET CPU 28K set memory size = 28K + SET CPU 32K set memory size = 32K + +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. + +CPU registers include the visible state of the processor as well as the +control registers for the interrupt system. + + name size comments + + PC 15 program counter, including IF as high 3 bits + AC 12 accumulator + MQ 12 multiplier-quotient + L 1 link + SR 12 front panel switches + IF 3 instruction field + DF 3 data field + IB 3 instruction field buffer + SF 7 save field + UF 1 user mode flag + UB 1 user mode buffer + SC 5 EAE shift counter + GTF 1 EAE greater than flag + EMODE 1 EAE mode (0 = A, 1 = B) + ION 1 interrupt enable + ION_DELAY 1 interrupt enable delay for ION + CIF_DELAY 1 interrupt enable delay for CIF + PWR_INT 1 power fail interrupt + UF_INT 1 user mode violation interrupt + INT 15 interrupt pending flags + DONE 15 device done flags + ENABLE 15 device interrupt enable flags + OLDPC 15 PC prior to last JMP, JMS, or interrupt + STOP_INST 1 stop on undefined instruction + WRU 8 interrupt character + +2.2 Programmed I/O Devices + +2.2.1 PC8E 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 copies the +RIM loader into memory and starts it running. + +The paper tape reader implements these registers: + + name size comments + + BUF 8 last data item processed + DONE 1 device done flag + ENABLE 1 interrupt enable flag + INT 1 interrupt pending flag + POS 31 position in the input file + TIME 24 time from I/O initiation to interrupt + 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 out of tape + + end of file 1 report error and stop + 0 out of tape + + OS I/O error x report error and stop + +2.2.2 PC8E 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 + + BUF 8 last data item processed + DONE 1 device done flag + ENABLE 1 interrupt enable flag + INT 1 interrupt pending flag + POS 31 position in the output file + TIME 24 time from I/O initiation to interrupt + 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 out of tape + + OS I/O error x report error and stop + +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 input implements these registers: + + name size comments + + BUF 8 last data item processed + DONE 1 device done flag + ENABLE 1 interrupt enable flag + INT 1 interrupt pending flag + POS 31 number of characters input + TIME 24 keyboard polling interval + +2.2.4 KL8E Terminal Output (TTO) + +The terminal output (TTO) writes to the simulator console window. It +implements these registers: + + name size comments + + BUF 8 last data item processed + DONE 1 device done flag + ENABLE 1 interrupt enable flag + INT 1 interrupt pending flag + POS 31 number of characters output + TIME 24 time from I/O initiation to interrupt + +2.2.5 LE8E 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 read or written. Thus, +by changing POS, the user can backspace or advance the printer. + +The line printer implements these registers: + + name size comments + + BUF 8 last data item processed + ERR 1 error status flag + DONE 1 device done flag + ENABLE 1 interrupt enable flag + INT 1 interrupt pending flag + POS 31 position in the output file + TIME 24 time from I/O initiation to interrupt + +Error handling is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 set error flag + + OS I/O error x report error and stop + +2.2.6 DK8E Line-Frequency Clock (CLK) + +The real-time clock (CLK) implements these registers: + + name size comments + + DONE 1 device done flag + ENABLE 1 interrupt enable flag + INT 1 interrupt pending flag + TIME 24 clock interval + TPS 8 ticks per second (60 or 50) + +The real-time clock autocalibrates; the clock interval is adjusted up or +down so that the clock tracks actual elapsed time. + +2.2.7 KL8JA Additional Terminals (TTI1-4, TTO1-4) + +Each additional terminal consists of two independent devices, TTIn and +TTOn. The entire set is modelled as a terminal multiplexor, with TTI1 +as the master unit. The additional terminals perform input and output +through Telnet sessions connected to a user-specified port. The ATTACH +command specifies the port to be used: + + ATTACH TTI1 (cr) -- set up listening port + +where port is a decimal number between 1 and 65535 that is not being used +for other TCP/IP activities. + +Once TTI1 is attached and the simulator is running, the terminals listen +for connections on the specified port. They assume that the incoming +connections are Telnet connections. The connections remain open until +disconnected either by the Telnet client, or by a DETACH TTI1 command. + +The SHOW TTI1 LINESTATUS command displays the current connections to the +additional terminals. + +The input devices (TTI1-4) implement these registers: + + name size comments + + BUF 8 last data item processed + DONE 1 device done flag + ENABLE 1 interrupt enable flag + INT 1 interrupt pending flag + POS 31 number of characters input + TIME 24 keyboard polling interval + +The output devices (TTO1-4) implement these registers: + + name size comments + + BUF 8 last data item processed + DONE 1 device done flag + ENABLE 1 interrupt enable flag + INT 1 interrupt pending flag + POS 31 number of characters output + TIME 24 time from I/O initiation to interrupt + +The additional terminals do not support save and restore. All open +connections are lost when the simulator shuts down or TTI1 is detached. + +2.3 Moving Head Disks + +2.3.1 RK8E Cartridge Disk (RK) + +RK8E options include the ability to make units write enabled or write locked: + + SET RKn LOCKED set unit n write locked + SET RKn ENABLED set unit n write enabled + +Units can also be REMOVEd or ADDed to the configuration. The RK8E supports +the BOOT command. + +The RK8E implements these registers: + + name size comments + + RKSTA 12 status + RKCMD 12 disk command + RKDA 12 disk address + RKMA 12 current memory address + BUSY 1 control busy flag + 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.3.2 RL8A Cartridge Disk (RL) + +RL8A options include the ability to make units write enabled or write locked: + + SET RKn LOCKED set unit n write locked + SET RKn ENABLED set unit n write enabled + +Units can also be REMOVEd or ADDed to the configuration. The RK8E supports +the BOOT command. + +The RL8A implements these registers: + + name size comments + + RLCSA 12 control/status A + RLCSB 12 control/status B + RLMA 12 memory address + RLWC 12 word count + RLSA 6 sector address + RLER 12 error flags + RLSI 16 silo top word + RLSI1 16 silo second word + RLSI2 16 silo third word + RLSIL 1 silo read left/right flag + INT 1 interrupt request + DONE 1 done flag + ERR 1 composite error flag + STIME 1 seek time, per cylinder + RTIME 1 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 RX8E/RX01 Floppy Disk (RX) + +RX8E options include the ability to set units write enabled or write locked: + + SET RXn LOCKED set unit n write locked + SET RXn ENABLED set unit n write enabled + +The RX8E supports the BOOT command. + +The RX8E implements these registers: + + name size comments + + RXCS 12 status + RXDB 12 data buffer + RXES 8 error status + RXTA 8 current track + RXSA 8 current sector + STAPTR 3 controller state + BUFPTR 3 buffer pointer + INT 1 interrupt pending flag + DONE 1 device done flag + ENABLE 1 interrupt enable flag + TR 1 transfer ready flag + ERR 1 error flag + 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:127] 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 + +RX01 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. + +2.5.1 RF08/RS08 Fixed Head Disk (RF) + +The RF08 implements these registers: + + name size comments + + STA 12 status + DA 20 current disk address + MA 12 memory address (in memory) + WC 12 word count (in memory) + WLK 32 write lock switches + INT 1 interrupt pending flag + DONE 1 device done flag + TIME 24 rotational delay, per word + BURST 1 burst flag + 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. + +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 +a single data break. + +Error handling is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 disk not ready + +RF08 data files are buffered in memory; therefore, end of file and OS +I/O errors cannot occur. + +2.5.2 DF32/DS32 Fixed Head Disk (RF) + +The DF32 implements these registers: + + name size comments + + STA 12 status, disk and memory address extension + DA 12 low order disk address + MA 12 memory address (in memory) + WC 12 word count (in memory) + WLK 16 write lock switches + INT 1 interrupt pending flag + DONE 1 device done flag + TIME 24 rotational delay, per word + BURST 1 burst flag + 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. + +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 +a single data break. + +Error handling is as follows: + + error STOP_IOE processed as + + not attached 1 report error and stop + 0 disk not ready + +DF32 data files are buffered in memory; therefore, end of file and OS +I/O errors cannot occur. + +2.6 TC08/TU56 DECtape (DT) + +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 LOCKED set unit n write locked + SET DTn ENABLED set unit n write enabled + +Units can also be REMOVEd or ADDed to the configuration. 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: + + -f foreign (PDP-9/11/15) format + -n native (PDP-8) 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 + INT 1 interrupt pending flag + ENB 1 interrupt enable flag + DTF 1 DECtape flag + ERF 1 error flag + CA 12 current address (memory location 7754) + WC 12 word count (memory location 7755) + 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] 31 position, in lines, units 0-7 + STATT[0:7] 31 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.7 TM8E Magnetic Tape (MT) + +Magnetic tape options include the ability to make units write enabled or +or write locked. + + SET MTn LOCKED set unit n write locked + SET MTn ENABLED set unit n write enabled + +Units can also be REMOVEd or ADDed to the configuration. + +The magnetic tape controller implements these registers: + + name size comments + + CMD 12 command + FNC 12 function + CA 12 memory address + WC 12 word count + DB 12 data buffer + STA 12 main status + STA2 6 secondary status + DONE 1 device done flag + INT 1 interrupt pending flag + STOP_IOE 1 stop on I/O error + TIME 24 record delay + UST[0:7] 24 unit status, units 0-7 + POS[0:7] 31 position, units 0-7 + +Error handling is as follows: + + error processed as + + not attached tape not ready + + end of file (read or space) end of physical tape + (write) ignored + + OS I/O error report error and stop + +2.8 Symbolic Display and Input + +The PDP-8 simulator implements symbolic display and input. Display is +controlled by command line switches: + + -a display as ASCII character + -c display as (sixbit) character string + -t display as (TSS/8 sixbit) character string + -m display instruction mnemonics + +Input parsing is controlled by the first character typed in or by command +line switches: + + ' or -a ASCII character + " or -c two character sixbit string + # or -t two character TSS/8 sixbit string + alphabetic instruction mnemonic + numeric octal number + +Instruction input uses standard PDP-8 assembler syntax. There are four +instruction classes: memory reference, IOT, field change, and operate. + +Memory reference instructions have the format + + memref {I} {C/Z} address + +where I signifies indirect, C a current page reference, and Z a zero page +reference. The address is an octal number in the range 0 - 07777; if C or +Z is specified, the address is a page offset in the range 0 - 177. Normally, +C is not needed; the simulator figures out from the address what mode to use. +However, when referencing memory outside the CPU (eg, disks), there is no +valid PC, and C must be used to specify current page addressing. + +IOT instructions consist of single mnemonics, eg, KRB, TLS. IOT instructions +may be or'd together + + iot iot iot... + +The simulator does not check the legality of the proposed combination. IOT's +for which there is no opcode may be specified as IOT n, where n is an octal +number in the range 0 - 0777. + +Field change instructions (CIF, CDF) have the format + + fldchg field + +where field is an octal number in the range 0 - 7. Field change instructions +may be or'd together. + +Operate instructions have the format + + opr opr opr... + +The simulator does not check the legality of the proposed combination. EAE +mode A and B mnemonics may be specified regardless of the EAE mode. The +operands for MUY and DVI must be deposited explicitly. diff --git a/pdp8_dt.c b/PDP8/pdp8_dt.c similarity index 90% rename from pdp8_dt.c rename to PDP8/pdp8_dt.c index c92822b5..4fc23a0c 100644 --- a/pdp8_dt.c +++ b/PDP8/pdp8_dt.c @@ -25,6 +25,8 @@ dt TC08/TU56 DECtape + 30-Nov-01 RMS Added read only unit, extended SET/SHOW support + 24-Nov-01 RMS Changed POS, STATT, LASTT, FLG to arrays 29-Aug-01 RMS Added casts to PDP-18b packup routine 17-Jul-01 RMS Moved function prototype 11-May-01 RMS Fixed bug in reset @@ -84,6 +86,7 @@ #define LASTT u4 /* last time update */ #define DT_WC 07754 /* word count */ #define DT_CA 07755 /* current addr */ +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ /* System independent DECtape constants */ @@ -270,14 +273,22 @@ extern int32 sim_is_running; */ UNIT dt_unit[] = { - { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DT_CAPAC) } }; + { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+ + UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+ + UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+ + UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+ + UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+ + UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+ + UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+ + UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) }, + { UDATA (&dt_svc, UNIT_8FMT+UNIT_FIX+UNIT_ATTABLE+ + UNIT_DISABLE+UNIT_ROABLE, DT_CAPAC) } }; REG dt_reg[] = { { ORDATA (DTSA, dtsa, 12) }, @@ -294,46 +305,14 @@ REG dt_reg[] = { { ORDATA (SUBSTATE, dt_substate, 2) }, { ORDATA (LOG, dt_log, 4), REG_HIDDEN }, { DRDATA (LBLK, dt_logblk, 12), REG_HIDDEN }, - { DRDATA (POS0, dt_unit[0].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS1, dt_unit[1].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS2, dt_unit[2].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS3, dt_unit[3].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS4, dt_unit[4].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS5, dt_unit[5].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS6, dt_unit[6].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS7, dt_unit[7].pos, 31), PV_LEFT + REG_RO }, - { ORDATA (STATT0, dt_unit[0].STATE, 18), REG_RO }, - { ORDATA (STATT1, dt_unit[1].STATE, 18), REG_RO }, - { ORDATA (STATT2, dt_unit[2].STATE, 18), REG_RO }, - { ORDATA (STATT3, dt_unit[3].STATE, 18), REG_RO }, - { ORDATA (STATT4, dt_unit[4].STATE, 18), REG_RO }, - { ORDATA (STATT5, dt_unit[5].STATE, 18), REG_RO }, - { ORDATA (STATT6, dt_unit[6].STATE, 18), REG_RO }, - { ORDATA (STATT7, dt_unit[7].STATE, 18), REG_RO }, - { DRDATA (LASTT0, dt_unit[0].LASTT, 32), REG_HRO }, - { DRDATA (LASTT1, dt_unit[1].LASTT, 32), REG_HRO }, - { DRDATA (LASTT2, dt_unit[2].LASTT, 32), REG_HRO }, - { DRDATA (LASTT3, dt_unit[3].LASTT, 32), REG_HRO }, - { DRDATA (LASTT4, dt_unit[4].LASTT, 32), REG_HRO }, - { DRDATA (LASTT5, dt_unit[5].LASTT, 32), REG_HRO }, - { DRDATA (LASTT6, dt_unit[6].LASTT, 32), REG_HRO }, - { DRDATA (LASTT7, dt_unit[7].LASTT, 32), REG_HRO }, - { GRDATA (FLG0, dt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG1, dt_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG2, dt_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG3, dt_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG4, dt_unit[4].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG5, dt_unit[5].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG6, dt_unit[6].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG7, dt_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, + { URDATA (POS, dt_unit[0].pos, 10, 31, 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) }, + { 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 }, { NULL } }; @@ -370,8 +349,8 @@ if (pulse & 06) { /* select */ fnc = DTA_GETFNC (dtsa); /* get fnc */ if (((uptr -> flags) & UNIT_DIS) || /* disabled? */ (fnc >= FNC_WMRK) || /* write mark? */ - ((fnc == FNC_WALL) && (uptr -> flags & UNIT_WLK)) || - ((fnc == FNC_WRIT) && (uptr -> flags & UNIT_WLK))) + ((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; } @@ -1121,7 +1100,7 @@ if (sim_is_active (uptr)) { dtsb = dtsb | DTB_ERF | DTB_SEL | DTB_DTF; DT_UPDINT; } uptr -> STATE = uptr -> pos = 0; } -if (uptr -> hwmark) { /* any data? */ +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 */ diff --git a/pdp8_lp.c b/PDP8/pdp8_lp.c similarity index 100% rename from pdp8_lp.c rename to PDP8/pdp8_lp.c diff --git a/pdp8_mt.c b/PDP8/pdp8_mt.c similarity index 87% rename from pdp8_mt.c rename to PDP8/pdp8_mt.c index 31cc9ce5..16847c57 100644 --- a/pdp8_mt.c +++ b/PDP8/pdp8_mt.c @@ -25,6 +25,8 @@ mt TM8E/TU10 magtape + 30-Nov-01 RMS Added read only unit, extended SET/SHOW support + 24-Nov-01 RMS Changed UST, POS, FLG to arrays 25-Apr-01 RMS Added device enable/disable support 04-Oct-98 RMS V2.4 magtape format 22-Jan-97 RMS V2.3 magtape format @@ -55,6 +57,7 @@ #define UNUM u4 /* unit number */ #define DBSIZE (1 << 12) /* max data cmd */ #define DBMASK (SBSIZE - 1) +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ /* Command/unit - mt_cu */ @@ -135,7 +138,7 @@ t_stat mt_attach (UNIT *uptr, char *cptr); t_stat mt_detach (UNIT *uptr); int32 mt_updcsta (UNIT *uptr); int32 mt_ixma (int32 xma); -t_stat mt_vlock (UNIT *uptr, int32 val); +t_stat mt_vlock (UNIT *uptr, int32 val, char *cptr, void *desc); UNIT *mt_busy (void); void mt_set_done (void); @@ -148,14 +151,14 @@ void mt_set_done (void); */ UNIT mt_unit[] = { - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_DISABLE, 0) } }; + { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, + { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) } }; REG mt_reg[] = { { ORDATA (CMD, mt_cu, 12) }, @@ -169,38 +172,11 @@ REG mt_reg[] = { { FLDATA (INT, int_req, INT_V_MT) }, { FLDATA (STOP_IOE, mt_stopioe, 0) }, { DRDATA (TIME, mt_time, 24), PV_LEFT }, - { ORDATA (UST0, mt_unit[0].USTAT, 24) }, - { ORDATA (UST1, mt_unit[1].USTAT, 24) }, - { ORDATA (UST2, mt_unit[2].USTAT, 24) }, - { ORDATA (UST3, mt_unit[3].USTAT, 24) }, - { ORDATA (UST4, mt_unit[4].USTAT, 24) }, - { ORDATA (UST5, mt_unit[5].USTAT, 24) }, - { ORDATA (UST6, mt_unit[6].USTAT, 24) }, - { ORDATA (UST7, mt_unit[7].USTAT, 24) }, - { DRDATA (POS0, mt_unit[0].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS1, mt_unit[1].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS2, mt_unit[2].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS3, mt_unit[3].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS4, mt_unit[4].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS5, mt_unit[5].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS6, mt_unit[6].pos, 31), PV_LEFT + REG_RO }, - { DRDATA (POS7, mt_unit[7].pos, 31), PV_LEFT + REG_RO }, - { GRDATA (FLG0, mt_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { 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 }, - { GRDATA (FLG7, mt_unit[7].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, + { URDATA (UST, mt_unit[0].USTAT, 8, 16, 0, MT_NUMDR, 0) }, + { URDATA (POS, mt_unit[0].pos, 10, 31, 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 }, { NULL } }; @@ -252,7 +228,7 @@ case 6: /* LFGR */ 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_WLK)) + (((f == FN_WRITE) || (f == FN_WREOF)) && (uptr -> flags & UNIT_WPRT)) || (((f == FN_SPACER) || (f == FN_REWIND)) && (uptr -> pos == 0))) { mt_sta = mt_sta | STA_ILL; /* illegal op error */ mt_set_done (); /* set done */ @@ -363,7 +339,7 @@ if ((uptr -> flags & UNIT_ATT) == 0) { /* if not attached */ return IORETURN (mt_stopioe, SCPE_UNATT); } f = GET_FNC (mt_fn); /* get command */ -if (((f == FN_WRITE) || (f == FN_WREOF)) && (uptr -> flags & UNIT_WLK)) { +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 */ @@ -555,7 +531,7 @@ for (u = 0; u < MT_NUMDR; u++) { /* loop thru units */ sim_cancel (uptr); /* cancel activity */ if (uptr -> flags & UNIT_ATT) uptr -> USTAT = ((uptr -> pos)? 0: STA_BOT) | - ((uptr -> flags & UNIT_WLK)? STA_WLK: 0); + ((uptr -> flags & UNIT_WPRT)? STA_WLK: 0); else uptr -> USTAT = STA_REM; } return SCPE_OK; } @@ -568,7 +544,7 @@ t_stat r; r = attach_unit (uptr, cptr); if (r != SCPE_OK) return r; -uptr -> USTAT = STA_BOT | ((uptr -> flags & UNIT_WLK)? STA_WLK: 0); +uptr -> USTAT = STA_BOT | ((uptr -> flags & UNIT_WPRT)? STA_WLK: 0); if (uptr -> UNUM == GET_UNIT (mt_cu)) mt_updcsta (uptr); return r; } @@ -584,7 +560,7 @@ return detach_unit (uptr); /* Write lock/enable routine */ -t_stat mt_vlock (UNIT *uptr, int32 val) +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; diff --git a/pdp8_pt.c b/PDP8/pdp8_pt.c similarity index 95% rename from pdp8_pt.c rename to PDP8/pdp8_pt.c index 2fded04f..40e9e535 100644 --- a/pdp8_pt.c +++ b/PDP8/pdp8_pt.c @@ -25,6 +25,7 @@ ptr,ptp PC8E paper tape reader/punch + 30-Nov-01 RMS Added read only unit support 30-Mar-98 RMS Added RIM loader as PTR bootstrap */ @@ -46,7 +47,8 @@ t_stat ptr_boot (int32 unitno); */ UNIT ptr_unit = { - UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_IN_WAIT }; + UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), + SERIAL_IN_WAIT }; REG ptr_reg[] = { { ORDATA (BUF, ptr_unit.buf, 8) }, diff --git a/pdp8_rf.c b/PDP8/pdp8_rf.c similarity index 95% rename from pdp8_rf.c rename to PDP8/pdp8_rf.c index 5bb8a3ac..b7ef7228 100644 --- a/pdp8_rf.c +++ b/PDP8/pdp8_rf.c @@ -25,6 +25,7 @@ rf RF08 fixed head disk + 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 15-Feb-01 RMS Fixed 3 cycle data break sequence @@ -266,7 +267,8 @@ return SCPE_OK; t_stat rf_reset (DEVICE *dptr) { -if (dev_enb & INT_RF) dev_enb = dev_enb & ~INT_DF; /* either DF or RF */ +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 */ diff --git a/pdp8_rk.c b/PDP8/pdp8_rk.c similarity index 88% rename from pdp8_rk.c rename to PDP8/pdp8_rk.c index 05d835dc..5bf740f2 100644 --- a/pdp8_rk.c +++ b/PDP8/pdp8_rk.c @@ -25,6 +25,8 @@ rk RK8E/RK05 cartridge disk + 30-Nov-01 RMS Added read only unit, extended SET/SHOW support + 24-Nov-01 RMS Converted FLG to array, made register names consistent 25-Apr-01 RMS Added device enable/disable support 29-Jun-96 RMS Added unit enable/disable support */ @@ -48,6 +50,7 @@ #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 */ /* Parameters in the unit descriptor */ @@ -142,38 +145,33 @@ void rk_go (int32 function, int32 cylinder); */ UNIT rk_unit[] = { - { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) }, - { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) }, - { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) }, - { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, RK_SIZE) } }; + { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, RK_SIZE) }, + { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, RK_SIZE) }, + { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, RK_SIZE) }, + { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ + UNIT_ROABLE, RK_SIZE) } }; REG rk_reg[] = { - { ORDATA (STA, rk_sta, 12) }, - { ORDATA (CMD, rk_cmd, 12) }, - { ORDATA (DA, rk_da, 12) }, - { ORDATA (MA, rk_ma, 12) }, + { ORDATA (RKSTA, rk_sta, 12) }, + { ORDATA (RKCMD, rk_cmd, 12) }, + { ORDATA (RKDA, rk_da, 12) }, + { ORDATA (RKMA, rk_ma, 12) }, { FLDATA (BUSY, rk_busy, 0) }, { FLDATA (INT, int_req, INT_V_RK) }, { DRDATA (STIME, rk_swait, 24), PV_LEFT }, { DRDATA (RTIME, rk_rwait, 24), PV_LEFT }, - { GRDATA (FLG0, rk_unit[0].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG1, rk_unit[1].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG2, rk_unit[2].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, - { GRDATA (FLG3, rk_unit[3].flags, 8, UNIT_W_UF, UNIT_V_UF - 1), - REG_HRO }, + { 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 }, { NULL } }; MTAB rk_mod[] = { - { (UNIT_HWLK+UNIT_SWLK), 0, "write enabled", "ENABLED", NULL }, - { (UNIT_HWLK+UNIT_SWLK), UNIT_HWLK, "write locked", "LOCKED", NULL }, - { (UNIT_HWLK+UNIT_SWLK), UNIT_SWLK, "write locked", NULL, NULL }, - { (UNIT_HWLK+UNIT_SWLK), (UNIT_HWLK+UNIT_SWLK), "write locked", - NULL, NULL }, + { UNIT_HWLK, 0, "write enabled", "ENABLED", NULL }, + { UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL }, { 0 } }; DEVICE rk_dev = { @@ -261,7 +259,7 @@ if ((uptr -> flags & UNIT_ATT) == 0) { /* not attached? */ 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_HWLK + UNIT_SWLK))) { +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? */ @@ -309,6 +307,12 @@ if ((uptr -> flags & UNIT_ATT) == 0) { /* not att? abort */ RK_INT_UPDATE; return IORETURN (rk_stopioe, SCPE_UNATT); } +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; + return SCPE_OK; } + 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 */ diff --git a/PDP8/pdp8_rl.c b/PDP8/pdp8_rl.c new file mode 100644 index 00000000..2ca40dac --- /dev/null +++ b/PDP8/pdp8_rl.c @@ -0,0 +1,619 @@ + /* pdp8_rl.c: RL8A cartridge disk simulator + + 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. + + rl RL8A cartridge disk + + 30-Nov-01 RMS Cloned from RL11 + + The RL8A is a four drive cartridge disk subsystem. An RL01 drive + consists of 256 cylinders, each with 2 surfaces containing 40 sectors + of 256 bytes. An RL02 drive has 512 cylinders. + + The RL8A controller has several serious complications. + - Seeking is relative to the current disk address; this requires + keeping accurate track of the current cylinder. + - The RL8A will not switch heads or cross cylinders during transfers. + - The RL8A operates in 8b and 12b mode, like the RX8E; in 12b mode, it + packs 2 12b words into 3 bytes, creating a 170 "word" sector with + one wasted byte. Multi-sector transfers in 12b mode don't work. +*/ + +#include "pdp8_defs.h" + +/* Constants */ + +#define RL_NUMBY 256 /* 8b bytes/sector */ +#define RL_NUMSC 40 /* sectors/surface */ +#define RL_NUMSF 2 /* surfaces/cylinder */ +#define RL_NUMCY 256 /* cylinders/drive */ +#define RL_NUMDR 4 /* drives/controller */ +#define RL_MAXFR (1 << 12) /* max transfer */ +#define RL01_SIZE (RL_NUMCY*RL_NUMSF*RL_NUMSC*RL_NUMBY) /* words/drive */ +#define RL02_SIZE (RL01_SIZE * 2) /* words/drive */ +#define RL_BBMAP 014 /* sector for bblk map */ +#define RL_BBID 0123 /* ID for bblk map */ + +/* 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_DUMMY (1u << UNIT_V_DUMMY) +#define UNIT_WLK (1u << UNIT_V_WLK) +#define UNIT_RL02 (1u << UNIT_V_RL02) +#define UNIT_AUTO (1u << UNIT_V_AUTO) +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ + +/* Parameters in the unit descriptor */ + +#define TRK u3 /* current cylinder */ +#define STAT u4 /* status */ + +/* RLDS, NI = not implemented, * = kept in STAT, ^ = kept in TRK */ + +#define RLDS_LOAD 0 /* no cartridge */ +#define RLDS_LOCK 5 /* lock on */ +#define RLDS_BHO 0000010 /* brushes home NI */ +#define RLDS_HDO 0000020 /* heads out NI */ +#define RLDS_CVO 0000040 /* cover open NI */ +#define RLDS_HD 0000100 /* head select ^ */ +#define RLDS_RL02 0000200 /* RL02 */ +#define RLDS_DSE 0000400 /* drv sel err NI */ +#define RLDS_VCK 0001000 /* vol check * */ +#define RLDS_WGE 0002000 /* wr gate err * */ +#define RLDS_SPE 0004000 /* spin err * */ +#define RLDS_STO 0010000 /* seek time out NI */ +#define RLDS_WLK 0020000 /* wr locked */ +#define RLDS_HCE 0040000 /* hd curr err NI */ +#define RLDS_WDE 0100000 /* wr data err NI */ +#define RLDS_ATT (RLDS_HDO+RLDS_BHO+RLDS_LOCK) /* att status */ +#define RLDS_UNATT (RLDS_CVO+RLDS_LOAD) /* unatt status */ +#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) */ + +#define RLCSA_DIR 04000 /* direction */ +#define RLCSA_HD 02000 /* head select */ +#define RLCSA_CYL 00777 /* cyl offset */ +#define GET_CYL(x) ((x) & RLCSA_CYL) +#define GET_TRK(x) ((((x) & RLCSA_CYL) * RL_NUMSF) + \ + (((x) & RLCSA_HD)? 1: 0)) +#define GET_DA(x) ((GET_TRK(x) * RL_NUMSC) + rlsa) + +/* RLCSB, function/unit select */ + +#define RLCSB_V_FUNC 0 /* function */ +#define RLCSB_M_FUNC 07 +#define RLCSB_MNT 0 +#define RLCSB_CLRD 1 +#define RLCSB_GSTA 2 +#define RLCSB_SEEK 3 +#define RLCSB_RHDR 4 +#define RLCSB_WRITE 5 +#define RLCSB_READ 6 +#define RLCSB_RNOHDR 7 +#define RLCSB_V_MEX 3 /* memory extension */ +#define RLCSB_M_MEX 07 +#define RLCSB_V_DRIVE 6 /* drive */ +#define RLCSB_M_DRIVE 03 +#define RLCSB_V_IE 8 /* int enable */ +#define RLCSB_IE (1u << RLCSB_V_IE) +#define RLCSB_8B 01000 /* 12b/8b */ +#define RCLS_MNT 02000 /* maint NI */ +#define RLCSB_RW 0001777 /* read/write */ +#define GET_FUNC(x) (((x) >> RLCSB_V_FUNC) & RLCSB_M_FUNC) +#define GET_MEX(x) (((x) >> RLCSB_V_MEX) & RLCSB_M_MEX) +#define GET_DRIVE(x) (((x) >> RLCSB_V_DRIVE) & RLCSB_M_DRIVE) + +/* RLSA, disk sector */ + +#define RLSA_V_SECT 6 /* sector */ +#define RLSA_M_SECT 077 +#define GET_SECT(x) (((x) >> RLSA_V_SECT) & RLSA_M_SECT) + +/* RLER, error register */ + +#define RLER_DRDY 00001 /* drive ready */ +#define RLER_DRE 00002 /* drive error */ +#define RLER_HDE 01000 /* header error */ +#define RLER_INCMP 02000 /* incomplete */ +#define RLER_ICRC 04000 /* CRC error */ +#define RLER_MASK 07003 + +/* RLSI, silo register, used only in read header */ + +#define RLSI_V_TRK 6 /* track */ + +extern uint16 M[]; +extern int32 int_req, dev_enb; +extern UNIT cpu_unit; +uint8 *rlxb = NULL; /* xfer buffer */ +int32 rlcsa = 0; /* control/status A */ +int32 rlcsb = 0; /* control/status B */ +int32 rlma = 0; /* memory address */ +int32 rlwc = 0; /* word count */ +int32 rlsa = 0; /* sector address */ +int32 rler = 0; /* error register */ +int32 rlsi = 0, rlsi1 = 0, rlsi2 = 0; /* silo queue */ +int32 rl_lft = 0; /* silo left/right */ +int32 rl_done = 0; /* done flag */ +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 */ +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_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); + +/* RL8A data structures + + rl_dev RL device descriptor + rl_unit RL unit list + rl_reg RL register list + rl_mod RL modifier list +*/ + +UNIT rl_unit[] = { + { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ + UNIT_ROABLE, RL01_SIZE) }, + { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ + UNIT_ROABLE, RL01_SIZE) }, + { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ + UNIT_ROABLE, RL01_SIZE) }, + { UDATA (&rl_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ + UNIT_ROABLE, RL01_SIZE) } }; + +REG rl_reg[] = { + { ORDATA (RLCSA, rlcsa, 12) }, + { ORDATA (RLCSB, rlcsb, 12) }, + { ORDATA (RLMA, rlma, 12) }, + { ORDATA (RLWC, rlwc, 12) }, + { ORDATA (RLSA, rlsa, 6) }, + { ORDATA (RLER, rler, 12) }, + { ORDATA (RLSI, rlsi, 16) }, + { ORDATA (RLSI1, rlsi1, 16) }, + { ORDATA (RLSI2, rlsi2, 16) }, + { FLDATA (RLSIL, rl_lft, 0) }, + { FLDATA (INT, int_req, INT_V_RL) }, + { FLDATA (DONE, rl_done, INT_V_RL) }, + { FLDATA (IE, rlcsb, RLCSB_V_IE) }, + { 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 }, + { NULL } }; + +MTAB rl_mod[] = { + { UNIT_WLK, 0, "write enabled", "ENABLED", NULL }, + { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, + { UNIT_DUMMY, 0, NULL, "BADBLOCK", &rl_set_bad }, + { (UNIT_RL02+UNIT_ATT), UNIT_ATT, "RL01", NULL, NULL }, + { (UNIT_RL02+UNIT_ATT), (UNIT_RL02+UNIT_ATT), "RL02", NULL, NULL }, + { (UNIT_AUTO+UNIT_RL02+UNIT_ATT), 0, "RL01", NULL, NULL }, + { (UNIT_AUTO+UNIT_RL02+UNIT_ATT), UNIT_RL02, "RL02", NULL, NULL }, + { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL }, + { 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 }, + { 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 }; + +/* IOT 60 routine */ + +int32 rl60 (int32 pulse, int32 AC) +{ +int32 curr, offs, newc, maxc; +UNIT *uptr; + +switch (pulse) { /* case IR<9:11> */ +case 0: /* RLDC */ + rl_reset (&rl_dev); /* reset device */ + break; +case 1: /* RLSD */ + if (rl_done) AC = IOT_SKP; /* skip if done */ + else AC = 0; + rl_done = 0; /* clear done */ + int_req = int_req & ~INT_RL; /* clear intr */ + return AC; +case 2: /* RLMA */ + rlma = AC; + break; +case 3: /* RLCA */ + rlcsa = AC; + break; +case 4: /* RLCB */ + rlcsb = AC; + rl_done = 0; /* clear done */ + rler = rl_erf = 0; /* clear errors */ + int_req = int_req & ~INT_RL; /* clear intr */ + rl_lft = 0; /* clear silo ptr */ + 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 */ + case RLCSB_MNT: /* mnt */ + rl_set_done (0); + break; + case RLCSB_SEEK: /* seek */ + 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)? + 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); + sim_activate (uptr, rl_swait * abs (newc - curr)); + break; + default: /* data transfer */ + sim_activate (uptr, rl_swait); /* activate unit */ + break; } /* end switch func */ + break; +case 5: /* RLSA */ + rlsa = GET_SECT (AC); + break; +case 6: /* spare */ + return 0; +case 7: /* RLWC */ + rlwc = AC; + break; } /* end switch pulse */ +return 0; /* clear AC */ +} + +/* IOT 61 routine */ + +int32 rl61 (int32 pulse, int32 AC) +{ +int32 dat; +UNIT *uptr; + +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)) + rler = rler | RLER_DRDY; + else rler = rler & ~RLER_DRDY; + dat = rler & RLER_MASK; + break; +case 1: /* RRWC */ + dat = rlwc; + break; +case 2: /* RRCA */ + dat = rlcsa; + break; +case 3: /* RRCB */ + dat = rlcsb; + break; +case 4: /* RRSA */ + dat = (rlsa << RLSA_V_SECT) & 07777; + break; +case 5: /* RRSI */ + if (rl_lft) { /* silo left? */ + dat = (rlsi >> 8) & 0377; /* get left 8b */ + rlsi = rlsi1; /* ripple */ + rlsi1 = rlsi2; } + else dat = rlsi & 0377; /* get right 8b */ + rl_lft = rl_lft ^ 1; /* change side */ + break; +case 6: /* spare */ + return AC; +case 7: /* RLSE */ + if (rl_erf) dat = IOT_SKP | AC; /* skip if err */ + else dat = AC; + rl_erf = 0; + break; } /* end switch pulse */ +return dat; +} + +/* Service unit timeout + + If seek in progress, complete seek command + Else complete data transfer command + + The unit control block contains the function and cylinder for + the current command. +*/ + +t_stat rl_svc (UNIT *uptr) +{ +int32 err, wc, maxc; +int32 i, j, func, da, bc, wbc; +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; + 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 */ + 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 */ + rl_set_done (RLER_DRE); /* flag error */ + return SCPE_OK; } + +if (func == RLCSB_SEEK) { /* seek? */ + rl_set_done (0); /* done */ + return SCPE_OK; } + +if (func == RLCSB_RHDR) { /* read header? */ + 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))) + || (rlsa >= RL_NUMSC)) { /* bad cyl or sector? */ + rl_set_done (RLER_HDE | RLER_INCMP); /* flag error */ + return SCPE_OK; } + +ma = (GET_MEX (rlcsb) << 12) | rlma; /* get mem addr */ +da = GET_DA (rlcsa) * RL_NUMBY; /* get disk addr */ +wc = 010000 - rlwc; /* get true wc */ +if (rlcsb & RLCSB_8B) { /* 8b mode? */ + bc = wc; /* bytes to xfr */ + maxc = (RL_NUMSC - rlsa) * RL_NUMBY; /* max transfer */ + if (bc > maxc) wc = bc = maxc; } /* trk ovrun? limit */ +else { bc = ((wc * 3) + 1) / 2; /* 12b mode */ + if (bc > RL_NUMBY) { /* > 1 sector */ + bc = RL_NUMBY; /* cap xfer */ + wc = (RL_NUMBY * 2) / 3; } } + +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); + for ( ; i < bc; i++) rlxb[i] = 0; /* fill buffer */ + for (i = j = 0; i < wc; i++) { /* store buffer */ + if (rlcsb & RLCSB_8B) /* 8b mode? */ + M[ma] = rlxb[i] & 0377; /* store */ + else if (i & 1) { /* odd wd 12b? */ + M[ma] = ((rlxb[j + 1] >> 4) & 017) | + (((uint16) rlxb[j + 2]) << 4); + j = j + 3; } + else M[ma] = rlxb[j] | /* even wd 12b */ + ((((uint16) rlxb[j + 1]) & 017) << 8); + ma = (ma & 070000) + ((ma + 1) & 07777); + } /* end for */ + } /* end if wr */ + +if ((func == RLCSB_WRITE) && (err == 0)) { /* write? */ + for (i = j = 0; i < wc; i++) { /* fetch buffer */ + if (rlcsb & RLCSB_8B) /* 8b mode? */ + rlxb[i] = M[ma] & 0377; /* fetch */ + else if (i & 1) { /* odd wd 12b? */ + rlxb[j + 1] = rlxb[j + 1] | ((M[ma] & 017) << 4); + rlxb[j + 2] = ((M[ma] >> 4) & 0377); + j = j + 3; } + else { /* even wd 12b */ + rlxb[j] = M[ma] & 0377; + rlxb[j + 1] = (M[ma] >> 8) & 017; } + ma = (ma & 070000) + ((ma + 1) & 07777); + } /* 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); + } /* end write */ + +rlwc = (rlwc + wc) & 07777; /* final word count */ +if (rlwc != 0) rler = rler | RLER_INCMP; /* completed? */ +rlma = (rlma + wc) & 07777; /* final word addr */ +rlsa = rlsa + ((bc + (RL_NUMBY - 1)) / RL_NUMBY); +rl_set_done (0); + +if (err != 0) { /* error? */ + perror ("RL I/O error"); + clearerr (uptr -> fileref); + return SCPE_IOERR; } +return SCPE_OK; +} + +/* Set done and possibly errors */ + +void rl_set_done (int32 status) +{ +rl_done = 1; +rler = rler | status; +if (rler) rl_erf = 1; +if (rlcsb & RLCSB_IE) int_req = int_req | INT_RL; +else int_req = int_req & ~INT_RL; +return; +} + +/* Device reset + + Note that the RL8A does NOT recalibrate its drives on RESET +*/ + +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; +rl_lft = 0; +rl_done = 0; +rl_erf = 0; +int_req = int_req & ~INT_RL; +for (i = 0; i < RL_NUMDR; i++) { + uptr = rl_dev.units + i; + sim_cancel (uptr); + uptr -> STAT = 0; } +if (rlxb == NULL) rlxb = calloc (RL_MAXFR, sizeof (unsigned int8)); +if (rlxb == NULL) return SCPE_MEM; +return SCPE_OK; +} + +/* Attach routine */ + +t_stat rl_attach (UNIT *uptr, char *cptr) +{ +int32 p; +t_stat r; + +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; + 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; } +return SCPE_OK; +} + +/* Set size routine */ + +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; +return SCPE_OK; +} + +/* Factory bad block table creation routine + + This routine writes the OS/8 specific bad block map in track 0, sector 014 (RL_BBMAP): + + words 0 magic number = 0123 (RL_BBID) + words 1-n block numbers + : + words n+1 end of table = 0 + + Inputs: + uptr = pointer to unit + val = ignored + Outputs: + sta = status code +*/ + +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 (!get_yn ("Create bad block table? [N]", FALSE)) return SCPE_OK; +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; +return SCPE_OK; +} + +/* Bootstrap */ + +#define BOOT_START 1 /* start */ +#define BOOT_UNIT 02006 /* unit number */ +#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) + +static const int16 boot_rom[] = { + 06600, /* BT, RLDC ; reset */ + 07201, /* 02, CLA IAC ; clr drv = 1 */ + 04027, /* 03, JMS GO ; do io */ + 01004, /* 04, TAD 4 ; rd hdr fnc */ + 04027, /* 05, JMS GO ; do io */ + 06615, /* 06, RRSI ; rd hdr lo */ + 07002, /* 07, BSW ; swap */ + 07012, /* 10, RTR ; lo cyl to L */ + 06615, /* 11, RRSI ; rd hdr hi */ + 00025, /* 12, AND 25 ; mask = 377 */ + 07004, /* 13, RTL ; get cyl */ + 06603, /* 14, RLCA ; set addr */ + 07325, /* 15, CLA STL IAC RAL ; seek = 3 */ + 04027, /* 16, JMS GO ; do io */ + 07332, /* 17, CLA STL RTR ; dir in = 2000 */ + 06605, /* 20, RLSA ; sector */ + 01026, /* 21, TAD (-200) ; one sector */ + 06607, /* 22, RLWC ; word cnt */ + 07327, /* 23, CLA STL IAC RTL ; read = 6*/ + 04027, /* 24, JMS GO ; do io */ + 00377, /* 25, JMP 377 ; start */ + 07600, /* 26, -200 ; word cnt */ + 00000, /* GO, 0 ; subr */ + 06604, /* 30, RLCB ; load fnc */ + 06601, /* 31, RLSD ; wait */ + 05031, /* 32, JMP .-1 ; */ + 06617, /* 33, RLSE ; error? */ + 05427, /* 34, JMP I GO ; no, ok */ + 05001 /* 35, JMP BT ; restart */ +}; + + +t_stat rl_boot (int32 unitno) +{ +int32 i; +extern int32 saved_PC; + +if (unitno) return SCPE_ARG; +rl_unit[unitno].TRK = 0; +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_rx.c b/PDP8/pdp8_rx.c similarity index 94% rename from pdp8_rx.c rename to PDP8/pdp8_rx.c index 04b80d2d..20ecdccf 100644 --- a/pdp8_rx.c +++ b/PDP8/pdp8_rx.c @@ -25,6 +25,8 @@ rx RX8E/RX01 floppy disk + 30-Nov-01 RMS Added read only unit, extended SET/SHOW support + 24-Nov-01 RMS Converted FLG to array 17-Jul-01 RMS Fixed warning from VC++ 6 26-Apr-01 RMS Added device enable/disable support 13-Apr-01 RMS Revised for register arrays @@ -52,6 +54,7 @@ #define RX_M_NUMDR 01 #define UNIT_V_WLK (UNIT_V_UF) /* write locked */ #define UNIT_WLK (1 << UNIT_V_UF) +#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ #define IDLE 0 /* idle state */ #define RWDS 1 /* rw, sect next */ @@ -114,10 +117,10 @@ t_stat rx_boot (int32 unitno); */ UNIT rx_unit[] = { - { UDATA (&rx_svc, - UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, RX_SIZE) }, - { UDATA (&rx_svc, - UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, RX_SIZE) } }; + { UDATA (&rx_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF+ + UNIT_ROABLE, RX_SIZE) }, + { UDATA (&rx_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF+ + UNIT_ROABLE, RX_SIZE) } }; REG rx_reg[] = { { ORDATA (RXCS, rx_csr, 12) }, @@ -136,8 +139,7 @@ REG rx_reg[] = { { DRDATA (CTIME, rx_cwait, 24), PV_LEFT }, { DRDATA (STIME, rx_swait, 24), PV_LEFT }, { DRDATA (XTIME, rx_xwait, 24), PV_LEFT }, - { FLDATA (FLG0, rx_unit[0].flags, UNIT_V_WLK), REG_HRO }, - { FLDATA (FLG1, rx_unit[1].flags, UNIT_V_WLK), REG_HRO }, + { 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 }, @@ -324,7 +326,7 @@ case RWDT: /* wait for track */ 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_WLK) { /* write and locked? */ + 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; } diff --git a/pdp8_sys.c b/PDP8/pdp8_sys.c similarity index 94% rename from pdp8_sys.c rename to PDP8/pdp8_sys.c index ed4297da..bc33e52d 100644 --- a/pdp8_sys.c +++ b/PDP8/pdp8_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. + 26-Nov-01 RMS Added RL8A support 17-Sep-01 RMS Removed multiconsole support 16-Sep-01 RMS Added TSS/8 packed char support, added KL8A support 27-May-01 RMS Added multiconsole support @@ -43,7 +44,8 @@ extern UNIT cpu_unit; extern DEVICE ptr_dev, ptp_dev; extern DEVICE tti_dev, tto_dev; extern DEVICE clk_dev, lpt_dev; -extern DEVICE rk_dev, rx_dev; +extern DEVICE rk_dev, rl_dev; +extern DEVICE rx_dev; extern DEVICE df_dev, rf_dev; extern DEVICE dt_dev, mt_dev; extern DEVICE tti1_dev, tto1_dev; @@ -80,7 +82,8 @@ DEVICE *sim_devices[] = { &tti3_dev, &tto3_dev, &tti4_dev, &tto4_dev, &clk_dev, &lpt_dev, - &rk_dev, &rx_dev, + &rk_dev, &rl_dev, + &rx_dev, &df_dev, &rf_dev, &dt_dev, &mt_dev, NULL }; @@ -226,6 +229,11 @@ static const char *opcode[] = { "SER", "SDN", "INTR", "INIT", "DTRA", "DTCA", "DTXA", "DTLA", "DTSF", "DTRB", "DTLB", + "RLDC", "RLSD", "RLMA", "RLCA", + "RLCB", "RLSA", "RLWC", + "RRER", "RRWC", "RRCA", "RRCB", + "RRSA", "RRSI", "RLSE", + "CDF", "CIF", "CIF CDF", "AND", "TAD", "ISZ", "DCA", "JMS", "JMP", "IOT", "NOP", "NOP2", "NOP3", "SWAB", "SWBA", @@ -278,6 +286,11 @@ static const int32 opc_val[] = { 06754+I_NPN, 06755+I_NPN, 06756+I_NPN, 06757+I_NPN, 06761+I_NPN, 06762+I_NPN, 06764+I_NPN, 06766+I_NPN, 06771+I_NPN, 06772+I_NPN, 06774+I_NPN, + 06600+I_NPN, 06601+I_NPN, 06602+I_NPN, 06603+I_NPN, + 06604+I_NPN, 06605+I_NPN, 06607+I_NPN, + 06610+I_NPN, 06611+I_NPN, 06612+I_NPN, 06613+I_NPN, + 06614+I_NPN, 06615+I_NPN, 06617+I_NPN, + 06201+I_FLD, 06202+I_FLD, 06203+I_FLD, 00000+I_MRF, 01000+I_MRF, 02000+I_MRF, 03000+I_MRF, 04000+I_MRF, 05000+I_MRF, 06000+I_IOT, diff --git a/pdp8_tt.c b/PDP8/pdp8_tt.c similarity index 100% rename from pdp8_tt.c rename to PDP8/pdp8_tt.c diff --git a/pdp8_ttx.c b/PDP8/pdp8_ttx.c similarity index 94% rename from pdp8_ttx.c rename to PDP8/pdp8_ttx.c index 91a692ab..ba5bf5f4 100644 --- a/pdp8_ttx.c +++ b/PDP8/pdp8_ttx.c @@ -25,6 +25,8 @@ ttix,ttox PT08/KL8JA terminal input/output + 30-Nov-01 RMS Added extended SET/SHOW support + This module implements four individual serial interfaces similar in function to the console. These interfaces are mapped to Telnet based connections as though they were the four lines of a terminal multiplexor. The connection @@ -58,7 +60,7 @@ t_stat ttox_svc (UNIT *uptr); t_stat ttox_reset (DEVICE *dptr); t_stat ttx_attach (UNIT *uptr, char *cptr); t_stat ttx_detach (UNIT *uptr); -t_stat ttx_status (UNIT *uptr, FILE *st); +t_stat ttx_status (FILE *st, UNIT *uptr, int32 val, void *desc); /* TTIx data structures @@ -71,7 +73,9 @@ t_stat ttx_status (UNIT *uptr, FILE *st); MTAB ttix_mod[] = { { UNIT_UC, 0, "lower case", "LC", NULL }, { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, - { UNIT_ATT, UNIT_ATT, "line status:", NULL, &ttx_status }, + { UNIT_ATT, UNIT_ATT, "line status", NULL, NULL, &ttx_status }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "LINESTATUS", NULL, + NULL, &ttx_status, NULL }, { 0 } }; UNIT ttix_unit[] = { @@ -409,10 +413,11 @@ return SCPE_OK; /* Status */ -t_stat ttx_status (UNIT *uptr, FILE *st) +t_stat ttx_status (FILE *st, UNIT *uptr, int32 val, void *desc) { int32 i; +fprintf (st, "line status:"); for (i = 0; (i < TTX_LINES) && (ttx_desc.ldsc[i] -> conn == 0); i++) ; if (i < TTX_LINES) { for (i = 0; i < TTX_LINES; i++) { diff --git a/S3/haltguide.txt b/S3/haltguide.txt new file mode 100644 index 00000000..24e90f86 --- /dev/null +++ b/S3/haltguide.txt @@ -0,0 +1,950 @@ + IBM System/3 Model 8/10 SCP + + ********** + Halt Guide + ********** + +This following list is my own reformatting and rewording of the +official IBM Halt Guide for the Model 8/10 SCP. + +The halts are those displayed on the message display unit. The +list is in alphabetical order for easy reference. + +When the system halts, the two 7-segment displays will display the +halt as listed here, and the system console (or printer if the log +device is the printer) will print the "SCP Message" below. To +respond to the halt, deposit one of the valid response numbers +(0 thru 3) into the SR, and then use the C command to continue. + +Unless otherwise stated, a response of 0 means to continue and accept +the error, 1 means to retry the operation or re-read the statement in +error, 2 means to cancel the job and retain added records (if any) and +3 means to end the job and discard any added records in files. + +This is a listing of those halts likely to be encountered using SCP on +the simuator, it is not the complete list of all possible halts. + +Halt SCP Message Description +---- ----------- ----------- + +00 Invalid response to another halt. Deposit a valid + value (0 thru 3) in SR. + +0A A 5448 Disk Unit not ready. + +0C 5448 Disk Equipment Check + +0E Permanent disk error during logging. + +0F ID0FXX 23 Invalid cylinder number on disk operation. + XX = Disk Drive. + +0H ID0HXX 23 Invalid sector number on disk operation + XX = Disk Drive. + +0Y IK0Y0X 123 3741 Error. X: 1=not ready 2=wrong mode + 3=parity error 5=record length error + +0 ID0 XX 23 Disk Data Check + XX = Disk Drive. + +0- ID0-XX Invalid disk operation code: Start cancels job. + XX = Disk Drive. + +10 3 No input file allocate, user error. + +11 0 23 Square root of a negative field + +12 0 23 Divide Overflow + +13 0 23 Divide by zero + +14 0 23 Varible index zero of out of range + +15 0 23 Sequenced table is out of sequence + +16 0 23 (RPG) OBject tables expected. /* Read. + +17 0 23 (RPG) Object table exceeds specified length + +18 0 23 (RPG) Terminal errors in source program. + +19 0 3 (RPG) Warning errors in source program. 0=continue. + +1A 3 (RPG) Out of core memory + +1C 23 Unidentified halt has been issued. Probable system + error. + +1E 0 3 (RPG) Demand file at end of file. + +1F 23 (RPG) End of file or end of extent. If during RPG + compilation, expand $SOURCE or $WORK. + +1H 0 23 Duplicate keys found during build of indexed file. + 0=skip this record and continue. + +1J 0 23 Out of sequence keys during build of indexed file. + 0=skip this record and continue. + +1L 0 23 Key changed during record update. User error. + 0=continue, do not update record. + +1P 01 Forms in printer need positioning. + +1U 123 No record found on direct or indexed file. + +1Y 0 23 (RPG) Invalid numeric data to DSPLY statement. + +1 0 3 Object program ready to punch tables. + +20 1 3 Disk Sort: Invalid header and no // SOURCE + +21 01 3 Disk Sort: Name on // SOURCE not found + +22 0 2 Disk Sort: Warning errors found. + +23 3 Disk Sort: Unrecoverable error. + +25 3 Disk Sort: Terminal errors in sort statements. + +27 0 Disk Sort: In debug mode, finished pass. + +2C 0 3 Disk Sort: No Input Records selected. + +2E 3 Disk Sort: Workfile too small. + +2F 23 Disk Sort: Output file too small. + +2L DT2LY2 3 Tape Record too large to process. + DT2LY7 3 No FILE statement for tape file open. + DT2LY9 3 No enough storage for tape operation + DT2LTC 3 Invalid tape header length + DT2LYF 123 Incorrect block length read from tape + +2P Permanent tape error. + +2U 12 Tape unit is write protected. + +2Y 3 Invalid device specification in object. + +2- 0 3 First statement was not a Tape Sort header. + +30 EG30 3 Space not available on R1 or F1. + UB30A1 0 3 Active files exist on output disk + UB30AF 0 3 Active files exist on 5448 disk + UB30H1 0 3 Wrong capacity or uninitialized pack + UB30NS 3 No 5448 disk for $PCOPY + UB30TP 0 3 Pack change required. + UC30AF 3 Active or system files on target + UC30BD 3 Volume label cannot be read + UC30SP 3 Not enough space for work file + UP30AF 3 Active or system files on target + +31 UI31AF 0 3 Active or system files on target + 0=proceed to next unit to initialize + UI30WP 01 3 Wrong pack, name does not match. + +32 UB32Bx 01 3 5444 pack is not a $PCOPY backup pack. + UB32NP 01 3 Unit specified is not a $PCOPY pack. + UC32BD 3 FROM pack is a TO pack from an interrupted + COPYPACK run. + UC32BP 3 Output pack is a $PCOPY output pack. + Must be initialized or reset by a RESET + statement to be used. + UC32DS 3 Packs FROM and TO are different sizes. + +33 UI33PU 0 3 Pack defective, cannot be initialized. + +34 Ux34 1 3 Keyword in a utility control statement is invalid. + +35 UC35xx 1 3 Error in $COPY or $KCOPY control statement. + +36 UI36CE 0 3 CE track defective on unit F1. + +37 UC37xx 0 3 Pack change required. xx: FP=mount on R1, + IP=pack on COPYIN, OP=pack on COPYO. + +38 UA38XX 0 3 Wrong pack mounted. + UB38DA 01 3 Dates do not match. + UB38DM 01 3 2nd 5444 pack not from same backup set as 1st. + UB38IP 01 3 PACKIN keyword pack not same as pack mounted. + UB38OP 01 3 PACKO keyword not same as pack mounted. + +3A UC3Axx 3 Key out of sequence (DP), invalid high key (HK), + out of space to copy file (XE), or disk I/O error. + +3C UC3CCS 3 COPYFILE out of core. + UC3CNF 3 Module not found, name is logged as R XXXXXX. + +3E UC3EOX 0 3 COPYFILE output not as big as size of input. + +3F UC3Fxx 1 3 Error in COPYFILE statement. + +3J UC3Fxx 3 Invalid specification for Copy/Dump. + +3P UC3Pxx 1 3 Error in COPYPACK, RESET, or LABELS statement. + +3Y UI3YIS 0 3 Requested secondary init when primary required. + +3 UI3 xx 1 3 Error in VOL statement. + +40 DD40 3 File has been referenced as an output or add file + and the file is already allocated. + +4A DD4A 3 File had already been opened and is re-opened. + +4C DD4C 3 Multivolumne file spec error. + +4E DD4E 3 FILE indicates a multivolule file being built, + but program compiled for single volume. + +4F DD4F 3 Print buffers not aligned in program. + +4H DD4H 0 3 Unordered load specified for ISAM. Ordered load + must be specified on RPG file specs. + +4J DD4J 3 All file specs have been checked and there were + errors. + +4L DD4L 3 Referenced file already allocated. + +4P DD4P 3 Prgram/FILE statement mismatch. + +4U DD4U 3 File referenced as update, already allocated. + +4Y DD4Y 3 File has an incorrect device specification. + +4 DD4 3 No FILE specification for referenced file. + +4' DD4' 3 Attempting reference to a file in 2 levels, one or + both using RETAIN-S. + +50 UA50ID 2 Bad track which can't be reassigned. + +51 UR51 12 Can't use Alternate Track program in procedure. + +52 ML52 12 EOJ for Card List program. + +53 IU53 1 3 Number of VOL statements does not agree with number + of units on UIN statement. + +54 EO54 3 End-of-file. + +55 UF55xx 1 3 Error in SCRATCH or REMOVE statement. + +56 UA56TS 0 3 ASSIGN track is over disk capacity. + UA56XX 0 3 Unit specified is uninitialized. + +57 UF57WP 01 3 File delete program. Wrong pack is mounted. + 0: Mount correct pack and continue. 1: + correct statement and retry. + +5A UA5Axx 012 Alternate track assignment error. + +5C MR5Cxx 1 3 Invalid reformat specs. + +5F UF5Fxx 1 3 Error in DISPLAY statement. + +5H UA5HEU 0123 Primary track is still defective. + +5L UF5LAF 0 3 PRogram try to delete files that are being used by + another program. + UF5LNF 0 3 File not found. + UF5LTM 23 Too many files specified. Max is 40. + +5U UI5Uxx 1 3 Error in UIN statement. + +5Y UR5Yxx 1 3 Error in REBUILD statment. + +5 UA5 xx 1 3 Error in ALT statement. + +5- 3 Tape Sort error occurred. + +5' UF5'N1 0 3 Pack cannot be used. Not inited. + UF5'NU 0 3 Pack was used as TO pack on a COPYPACK job + that required early termination. Can only + be used for another COPYPACK job. + +60 LM60SY 0 3 Cannot remove or change library size on pack + from which $MAINT was loaded. + +61 LM61EP 0 3 Trying to copy a system to a library that is + 1) not empty, 2) not allocated with large enough + SWA, or 3) not allocated with enough space. + LM61NS 0 3 System does not exist on FROM pack. + +62 LM62CS 01 3 Check Sum error. + LM62DR Can't determine if REMOVE is data or control. + LM62EF FROM, TO, or AFTER statement does not exist or + is out of sequence. + LM62ND NO data records following INSERT or REPLACE. + LM62SQ Records are out of sequence. + LM62TP Incorrect type record. + +63 LM63DE 0 3 Directory entry error. Name can't be found or + attributes don't match, or attempt to remove + dir entry with MODIFY. + +64 LM64DS 0 3 Syntax error in ALLOCATE. + +65 LM65UN 0 3 Pack not properly initialized. + +66 LA66xx 3 Error with LOAD * function. + +67 EL67NL 0 3 Library does not exist. + +68 EL68DF 0 3 No room in library or directory. + +69 XX69HE 3 Disk I/O Error while using library. + +6A LM6Axx 1 3 $MAINT has detected a syntax error on a control + statement. xx gives a hint of what might be wrong. + AL: SOURCE or OBJECT missing or invalid + AZ: SYSTEM missing or invalid + D2: FROM, TO, or WORK is R2 or F2, not available + DK: Duplicate keyword + DS: Invalid DIRSIZE + FL: Invalid or missing FILE keyword + FM: Invalid or missing FROM keyword + IK: Invalid keyword + IN: Invalid INCR keyword + IS: first 3 columns must be // blank + IV: Invalid statement identifier + LB: Invalid LIBRARY keyword + LS: Invalid LIST keyword + NK: No keywords + NM: Invalid NAME keyword + NU: Invalid NEWNAME keyword + OM: Invalid OMIT keyword + RL: Invalid RECL keyword + RS: Invalid RESER keyword + RT: Invalid RETAIN keyword + SF: INvalid SEQFLD keyword + SQ: Invalid FROM, TO, or AFTER in MODIFY mode + XC: Invalid record. + XD: Duplicate keyword + XF: $$SYFG could not be found. + XL: LIBRARY keyword missing + XM: NAME keyword missing + XN: NAME parameter is invalid + XP: Library does not exist on this pack + XS: Syntax error + XT: Invalid library type + XV: INvalid operation + +6C LM6CSP 0 3 Not enough space on pack. + LM6CSW 0 3 Space not available for work file. + +6E LM6EOF 0 3 Overflow in seq field during RESER. + LM6EDP 0 3 Entry with same name already exists in library. + +6H EL6HDT 0 3 Trying to replace perm with temp entry. + LM6HDP 0 3 NEWNAME is already in library. + +6J LM6JCC 0 3 Control statements are missing. + +6L UA6L 3 Log device is required for this program. + +6Y LM6YNN 1 3 No NEWNAME when copying to same library. + +6 LM6 BC 3 Invalid character in source record. + LM6 CM 0 3 Invalid object deck. + LM6 ND 0 3 No data between COPY and CEND. + +6- LM6-BC 01 Entry containing a blank card being placed in + library. 0: accept, 1: skip and read next card. + +6' LM6'CE 1 3 // CEND expected but not found. 1: Retry, + provide CEND. NOTE: For option 3, if a module + was being replaced, it may have been deleted but + new module not loaded. + +70 CR70 3 Too many overrides for procedure. Max is 25. + +71 CR71 0 3 OCL Syntax Error. + +73 CR73 0 // PARTITION given in invalid location. + +74 CR74 3 /& between LOAD and RUN or CALL and RUN. + +75 CR75 23 Extraneous statement. + +76 CR76 0 3 // Missing from OCL statement. + +77 CR77 23 Invalid OCL statement identifier. + +78 CR78 0 3 Unknown OCL keyword. + +79 CR79 23 Continuation expected but not received. + +7A CR7A 3 A second LOAD or CALL found before run, or a + CALL in procedure overrides. + +7C CR7C 0 3 // COMPILE found between jobs. + +7E CR7E 0 3 // DATE found between jobs. 0: Ignore and continue. + +7F CR7F 0 3 // FILE found between jobs. Must go between + // LOAD or // CALL and // RUN statements. + +7H CR7H 0 3 // SWITCH found between jobs. + +7J CR7J 23 // READER found between LOAD or CALL and RUN. + +7L CI7Lxx 23 Error when reading a tape file. + +7P New print chain expected. Load it and press START. + +7U CR7U 3 RUN statement not preceeded by LOAD or CALL. + +7Y CI7Yxx 23 Error outputing a tape file. + +7 CR7 3 Too many utility control statements, max is 25. + +7- CR7- 0 // PARTITION was read but system does not support + Dual Programming. + +7' Error during tape processing. + +80 CR80 0 // DATE card has not been entered. + +81 CR81 23 Error in LOAD statement. + +83 CR83 23 Error in LOAD * statement. + +84 CR84 23 Error in CALL statement + +85 CR85 23 Second SWITCH statement found. + +86 CR86 23 Invalid paramter in switch statement. + +88 CR88 1 3 Procedure not found. + +89 CR89 01 // DATE has already been given. + 0 - accept the new date as the date. + 1 - leave the old date as the current date. + +8A CR8A01 0 Invalid date specified. + CR8A02 0 DATE parameter missing. + +8C CR8C 23 Second DATE found. + +8E CR8E01 23 Date specified incorrectly. + +8F CR8Fxx 23 Invalid BSCA statement. + +8H CR8H 3 More than 9 levels of procedures have been called. + +8J CR8J 0 Invalid // READER parameter. + +8L CR8L 0 Desired system input device being used by other + program. + +8P CR8P 0 Output device not defined. + +8U CU8UIP 23 Invalid HIKEY in FILE statement: non-numeric. + CR8UKL Parameter length mismatch. + CR8ULO Key greater than 29. + CR8UPL HIKEY-P greater than 15. + CR8USQ HIKEY parameters not in sequence. + +8Y CR8Y 0 Not logging can be done. Log turned off by + other program level. + +8- CR8- 0 3 Logging requested but cannot be done. + +90 CR90 0 // PAUSE statement read. Check printer or console + for instructions and continue. PAUSE was outside + LOAD and RUN. + +91 CR90 0 // PAUSE statement read. Check printer or console + for instructions and continue. PAUSE was inside + LOAD and RUN. + +92 CR92 23 COMPILE already recieved for this job. + +93 CR93 23 Error in COMPILE statement. + +94 CR94 23 Error in COMPILE statement. + +95 CR95 23 Error in COMPILE statement. + +96 CR96 0 23 System error. An OCL error was found, but the system + cannot resolve the error. + +97 CR97 0 Error in LOG statement. + +98 CR98 23 Error in LOG statement. + +99 CR99 0 23 Error in LOG statement. + +9A CR9A 23 Indicated action on last OCL statement read will + be ignored due to previous errors detected. + +9C CR9Cxx 123 Incorrect tape volume online. + +9E CR9E 0 Logging device being used by other program level. + +9F CR9F 0 23 Logging device in use by other program. + +9H CR9H 23 Log device in use. + +9J CR9J 0 Error in FORMS statement. + +9L CR9L 0 23 Error in FORMS statement. + +9P CR9P 23 Error in FORMS statement. + +9U CR9U 0 3 Other program has gotten a // IMAGE or other + program level is using the printer. + +9Y CR9Y 0 23 Logging device not sysgenned or CCP has it. + +9 CR9 0 23 Same as 9Y. + +9- CR9- 0 3 Other program level received a // FORMS or + other level using the printer. + +9' CR9' 0 Same as 9Y. + +A0 CRa0xx 23 Syntax error in FILE statement. + +A1 CRA1xx 23 Keyword error in FILE statement. + +A2 CRA2xx 23 Parameter error on FILE statement. + xx gives parameter: + 01 NAME, 02 UNIT, 03 PACK, 04 LABEL, + 05 RETAIN, 06 DATE, 07 RECORDS, 08 TRACKS, + 09 LOCATION, AS ASCII, BL BLKL, CV CONVERT, + DF DEFER, DN DENSITY, EN END, PT PARITY, + RC RECL, RF RECFM, RL REEL, SP SPLIT, + TN TRANSLATE. + +A3 CRA3xx 23 Missing Parameter on FILE statement, xx = + NN: NAME, NP: PACK, NU: UNIT, OP: no + parameters. + +A4 CRA4xx 23 Invalid parameter combination in FILE statement: + AS: ASCII-YES and RECFM-D/DB on 7-track tape + AV: ASCII-YES and RECFB-V/VB + AY: RECFM-D/DB without ASCII-YES + CT: CONVERT-ON and TRANSLATE + DI: UNIT says tape but disk parameters given + DN: DENSITY-800 not supported. + FS: RECFM is fexed and block or rec len less than 18 + IL: Incorrected RECL or BLKL for RECFM + IP: SPLIT or LOCATION used with RECORDS / TRACKS. + IR: LABEL, DATE or RETAIN wirh REEL-NL or REEL-NS + NS: Not all units are 7-track + PC: CONVERT-ON and PARITY-EVEN + RC: CONVERT-ON not given with RECFM-V/VB for 7-track + SD: DENSITY-1600 invalid for 7-track + SL: LOCATION missing or invalid for SPLIT. + SM: SPLIT invalid for multivolume files. + ST: 7-track paras with 9-track unit + SU: SPlit can't be used with 5444 + TL: TRACKS/LOCATION invalid with unit + TP: UNIT is disk but tape paras given + TR: TRACKS and RECORDS both given + +A6 CRA6xx 23 Error in FILE statement for multivolumne files. + +A7 CRA7xx 23 Error in IMAGE statement. + +A8 CRA8xx 0 Error in IMAGE statements o disk. + +A9 CRA9xx 0 23 Same as A8. + +AA CRAAxx 23 Same as A8. + +AC CRAC 0 Invalid hex character in chain image. + +AE CRAE 0 23 Same as AC. + +AF CRAF 23 Same as AC. + +AH CRAH 0 Error in IMAGE statement. + +AJ CRAJ 0 23 Same as AH + +AL CRALxx 0 Error in PARTITION statement. + +AP CRMN 0 3 Either reocvery option has has been selected during + a job, or OCL errors have occurred for this job. + 0: Continue iwth next job, or no data cards in + reader for this job, otherwise, 3 to cancel. + +AU CRAUxx 23 Error in PARTITION statement. + +A CRA 23 Total number of volumes for a FILE statement + exceeds 40 (!). + +A- CRA-xx 0 23 Error in PARTITION statement. + +A' CRA' 3 No space remaining is System work area. Too many + FILE statements are in this job. + +C1-C9 IFC1 123 1442 Check, various causes. + +CL UDCLxx 1 3 5445 Data Interchange Utility error + +E7 DKE7 0 3 Incorrect record length for attached 3741 + +E8 UTE8xx 1 3 Error in Tape Init VOL statement. + +E9 UTE9xy 0 3 Error during Tape Init Processing. + +F8 DDF8 3 RPG--LIne counter specs omitted and skip past + page size for printer. + +F9 CIF9xy 23 Tape drive not available, x = drive #. + +FA CIFA 3 Program requesting Data Recorder, unsupported. + +FC CIFC 3 Program requesting CRT, unsupported. + +FE DDFE 0 3 Program requesting line line on printer that + exceeds sysgen value. + +FF RPQ routine error. Press start to continue. + +FH CIFH 123 BSCA line not supported. + +FJ CIFJ01 123 1442 not supported but requested + CIFJ02 123 3741 not supported but requested + +FL CIFL 123 Printer/keyboard not supported or unavailable. + +FP CIFP 123 Printer not supported or allocated to other level + +FU CIFU 123 MFCU not supported or allocated to other level + +FY CIFY 23 Device is not supported or in use. + +F CIF 23 Conflict with a resource being used by other level. + +H0-H9 0 23 RPG Programmed halt indicator is on. + +HA CIHA 3 Out of space on $SOURCE during compile. + +HC CIHC 3 Program given on LOAD statement not found. + +HE Hardware error. Simulator has messed up. + +HF CIHF 0 3 // COMPILE read but not required. + +HJ CIHJ01 1 3 Program not found on removable unit, 1: + mount new unit and retry. + CIHJ02 3 Program not found, but removable unit in use. + +HL CIHL 3 Inquiry request made but program is wrong type. + +HP CIHP 3 Insufficient main storage for program. + LMHP 3 $MAINT function out of storage. NOTE: After the + cancel, IPL from the system pack or the pack will + be unusable. + +HU CIHUxx 3 Source program not found on disk. IF a 1 option + is present, you can mount a new removeable pack. + +HY CCHYNN 0 A checkpoint is received and accepted. + +H CCH NN 0 23 A restart has been requested. + +H' CIH' 3 An uninitialized pack has been referenced. + +J0-J9 123 Record with specified match field out of sequence. + This is an RPG error, the 2nd digit indicates which + RPG file statement the error applies to in the + source program. 0=greater than statement 9, + otherwise indicates the file statement number. + +JA CIJA 3 Trying to laod a program that requires or allows + inquiry while another inquiry program is running + in the other level. + +JC CIJCxx 3 Program cannot be run for this reason (xx): + 01: Must be dedicated and other level active + 02: Program in other level must be dedicated + 03: $$RSTR cannot run in level 2 + 04: CHeckpointed program not allowed in level 2 + 05: Program can't run while checkpoint active + +JE CIJE 0 3 Level 1 partition too small. + +JF CIJF 3 Attempt to start inquiry program but keyboard + in use. + +JH CIJF 3 Attempt to start program which allows interrupts in + level 2. + +JJ CIJJ 3 No object library on pack requested for load. + +JL CIJL 3 Not enough storage for program. DPF only. + +JP System input device in use by other level. + +JU 0123 Cancel request made from interrupt key. 0: ignore + 1: continue, request ignored + +JY CIJYRD 0 2 Inquiry request made and accepted. + +J- 3 Attempt to run a CCP program, but CCP not running. + +J' 01 3 Inquiry request is completed, interrupted program + can now resume. + +L0-L9 123 RPG. Unidentified record, 2nd digit gives file + statement number in source program 1-9, 0 means + greater than 9. Can also occur if record is out + of sequence. + +LA CILA 23 Too little storage for number of files in program. + +LC CILC 23 Too little storage for requested allocation. + +LE CILE 23 No FILE or an incorrect FILE for a file requested + by current program. + +LH CILH 23 No space given for an output file on FILE statement. + +LJ CILJ 23 Attempt to output to existing permanent file. + +LL CILL 0 23 Attempt to output over an existing temporary file. + +LP CILP 23 File already exists. + +LU CILU 123 Pack name requested but wrong pack mounted. 1: + retry after mounting correct pack. + +LY CILYxx 23 Attempt to allocate space that isn't available. + xx=02 means space not available in split cylinder + area. + +L LML CP 01 3 $MAINT detected attempt to modify a program on + a pack with an active checkpoint. + +L- CIL- 3 Attempt to add a split cylinder to a split cyl + file while other level is fiddling with a split + cylinder file. + +L' CIl' 23 Trying to allocate a split cylinder file before + allocating the first split cylinder file in a group. + +P1-P8 Printer hardware errors, should not occur in sim. + +PC IPPC 0 23 Unprintable character. + +PH CIPH 23 LOCATION plus TRACKS goes past end of pack. + +PJ CIPJxx 1 A Pack is to be remounted, pack name printed before + half code, xx= unit. + +PU CIPU 3 Duplicate file names in the FILE statements. + +PY CIPY01 3 ISAM file requires at least 2 tracks. + CIPY02 3 ISAM file can't be split cylinder. + +P' CIP'xx 23 Too many scratch or work files. + +U0-U9 0123 RPG. Unidentified record in file, 2nd digit of + halt is file statement in RPG source, 0= greater + than 9. + +UA CIUA 3 Attempt to create a multivolume file in + invalid. + +UC CIUC 3 The printed actived file cannot be found in the + list of scratch files. + +UE CIUExx 1 3 PACK parameter does not match pack name on unit. + xx = Unit referenced. + 1 = Mount another pack and continue. + +UF CIUF 3 Disk file referenced by name and date not found. + +UH CIUH 3 Attempt to create multivolume file failed, + because name alreayd exists. + +UJ CIUJ 3 A LOCATION was specified for an existing disk file + and the file exists but not at that location. + +UL CIUL 3 File on // FILE statement not found, and no size + in TRACKS or RECORDS was given. + +UP CIUP 3 Permanent file referenced with RETAIN-S + +UU CIUU 3 Disk Pack not available. + +UY CIUY 3 File is a System/3 BASIC file which must be unique. + +U CIU 3 Existing file: TRACKS/RECORDS or LOCATION mismatch. + +U- General CCP halt. Press start to see subhalt. + Refer to CCP manual for more info. + +U' CIU' 23 VTOC is full, or more than 2 multivolume files per + pack, or more than 2 ISAM files using HIKEY + parameter. + +YH CRYH 0 3 Cards are being punched, but card read from + reader was not blank. This means you are trying to + punch with a file attached to the CDR device. + Unattach the file and take the zero option. + + 0 (blank 0) FILE WRITE switch in off position. + + 1 (blank 1) Permanent DIsk I/O Error + + 2 RC 211 3 COBOL. Out of room on $WORK. + RC 212 3 Out of room on $SOURCE. + RC 213 3 Out of room on $WORKX. + RC 214 3 Subprogram name table greater than 20. + RC 219 0 3 C or E level diagnostics during compile. + RC 2A1 23 Subscript invalid + RC 2A2 23 Negative exponent or 0 degrees in program + RC 2F1 23 MFCU File not open or opened improperly + RC 2F2 23 1442 File not open or opened improperly + RC 2F3 23 1403/5203 File not open or opened improperly + RC 2F4 23 5444 Disk File not open or opened improperly + RC 2F5 23 5444 File not open or opened improperly + RC 2F7 23 5444 File not open or opened improperly + RC 2F8 23 Tape File not open or opened improperly + RC 2H1 23 OPEN attempted after CLOSE WITH LOCK + RC 2H2 23 Error during ACCEPT + RC 2H3 23 $$STOP not found + RC 2H4 23 CHeckpoint could not be taken. + RC 2H5 23 $$STIC not found for ACCEPT + RC 2H6 23 Parameter mismatch CALL and USING + RC 2H7 23 ACCEPT after /& read + RC 2H8 23 OPEN for a file already OPEN + RC 2 0 3 Too little core for compile + RC 2 1 3 PROCEDURE or DATA division not found. + RC 2 3 3 Program has more than 65535 statements (!) + RC 2 4 3 Source name on COMPILE statement not found + + 3 R 3XX 0 3 COBOL Stop literal. XX is user-specified. + 0 continues program 3 cancels. + + 4 VF 4NF 3 Program not found. Program library and + not printed before halt message. + + 6 RF 6XX 0 23 FORTRAN stop statement. + + 7 RF 701 23 Source member on COMPILE not found + RF 702 23 Object program too large for core. + + 8 CS 8 1 3 System input device allocated to other level. + + 9 CS 9 1 3 System input device has an error. This usually + means the card hopper is empty (i.e. EOF on the + file attached to the reader but SCP wants more + input). + + A DC A 123 Number of characters entered from keyboard + incorrect. + + C DD C 0 23 Unprintable character for printer/keyboard. + + E DC E 123 Hardware error, PKB + + F DC F 0 23 End of forms, PKB + + L DD L 0 3 Records with duplicate keys have been loaded + into ISAM file. Each dup key is logged followed + by blank P halt. 0: continue. Index will + contain duplicate keys. 3: cancel, file is + not usable, reload it. + + P DD P 0 3 Duplicate key encountered. The key is printed + on the log. 0: continue, halt will recur for + any other duplicates, then blank L appears. + + U DD U 3 Disk I/O error while sorting ISAM index. + + Y DD Y 3 System error during file termination. + +-0 DD-0XX 3 ISAM multivolume file being used and high key + not found for current columme, or does not agree + with HIKEY spec. XX=unit number. + +-1 DD-1XX 123 Halt -P occurred and option 0 taken. But, the + pack mounted is not a part of volume set. + +-2 DD-2XX 123 Multivolume load sequence error. + +-3 DD-3XX 123 Multivolume load sequence error. + +-4 DD-4XX 0123 Warning that one or more volumes are about to be + bypassed. + +-5 DD-5XX 123 Multivolume file not found. 1: mount correct pack. + +-6 DD-6XX 0 23 Warning. ENd of volume and HIKEY not found. + +-7 DD-7XX 1 3 -A halt and option 1 taken. But the pack referenced + does not match pack name. + +-8 DD-8XX 3 Multivolume file referenced but file isn't + multivolume. + +-9 DD-9XX 3 Add to a multivolumen file, but last pack not + mounted. + +-A DD-AXX 1 3 Add to existing multivolume filebut no room. + +-C DD-CXX 3 Multivolume file error. Probably out of sequence + volume mounts. + +-E DD-EXX 123 Next volume cannot be processed, because the + location is not available or space is not available + or there are scratch files on the pack. + +-F DD-Fxx 123 Finished a volume, next cannot be processed, mount + the correct pack or cancel. + +-H DD-Hxx 3 HIKEY length does not match file. + +-J DD-Jxx 01 3 First volume referenced is not volumme 1. 0: + continue with this volume, 1: mount another pack. + +-L DD-Lxx 3 Output to multivolume, but file isn't multivolume + or referenced volume isn't first one of set. + +-P DD-PXX 0123 Mount next volume. XX=unit number. 0: continue + bypassing volumes, 1: mount next volume. + +-U DD-UXX 1 3 Halt -J just occurred and 0 or 1 taken. But the + pack name is incorrect or the file isn't found. + +- DD- 123 Multivolume key error. Key too low or high for + volume. + +-' DD-' 123 Sequential add to multivolume file, but HIKEY + record missing on previous volume. + +'0 GM'0DE 3 SYSGEN. I/O Error on reader. + GM'0EX 3 SYSGEN. End of extent on MACOUT or $SOURCE. + GM'0IC 1 3 SYSGEN. Option dependent on a preceding option, the + preceding one was omitted or invalid. + GM'0ID 1 3 SYSGEN invalid delimiter. + GM'0IK 1 3 SYSGEN invalid keyword. + GM'0IR 1 3 SYSGEN invalid option. + GM'0IS 1 3 SYSGEN sequence error. + GM'0NF 1 3 SYSGEN entry in cols 8-12 not found. + GM'0NS 3 SYSGEN Requested source program not found. + GM'0EM 1 3 SYSGEN. END statement not found. + GM'0NP 3 SYSGEN. Module $SGXP2, $SGXP3, $SGXP4, $SGXP5, or + $SGXP6 missing for sysgen, or $MPXP2, $MPXP3 or + $MPXP4 missing for macro processor. + +'1 GG'1 3 System Generation Errors. + +'2 0 3 Error during macro processor run. + +'3 3 Invalid 5445 disk label record. + +'4 GG'4EX 3 Out of room on Sysgen, or disk error. + +----------------------- End of haltguide.txt --------------------------- diff --git a/S3/readme_s3.txt b/S3/readme_s3.txt new file mode 100644 index 00000000..37afdd9c --- /dev/null +++ b/S3/readme_s3.txt @@ -0,0 +1,78 @@ + Welcome to the IBM System/3 Model 10 SIMH simulator. + --------------------------------------------------- + + To compile under linux: + + cc s3*.c scp*.c sim_rev.c -o s3 + + This code can be compiled and run as a console application using + Microsoft Visual C++. + + + + To IPL the provided SCP distribution disk: + + ./s3 + sim> at r1 m10scp.dsk + sim> at f1 f1f1f1.dsk + sim> at lpt print.txt + sim> d sr 5471 + sim> boot r1 + + + // DATE 06/14/01 + // NOHALT + // LOAD $MAINT,R1 + // RUN + // COPY FROM-R1,LIBRARY-ALL,NAME-DIR,TO-PRINT + // END + + + (A printout of the libraries and directories on the SCP DTR + disk will be in the file print.txt) + + + The text file "system3.txt" gives details on the simulators + implementation of System/3 hardware. + + A write up on the use of the SCP and the OCL job control language is + in the text file "userguide.txt". This includes examples of using the + utility programs, and a tutorial guiding you thru a sysgen. + + A nearly complete listing of all possible SCP halts is in the + document "haltguide.txt". + + IMPORTANT NOTES: + + 1) How to correct typing errors when using the System/3 console: + If you make an error, press ESC, which will cancel the current + line being typed and print a quote in position 1. Then you + can use CTRL/R to retype characters up until the error, then + type correctly. Or simply retype the line. BACKSPACE DOES NOT + WORK with the SCP. + + 2) While the simulator allows disk images to be independently + attached to any disk unit, on the real hardware R1 and F1 were on + a single spindle, and R2 and F2 likewise. It is not possible using + SCP to attach R1 without attaching a disk image to F1 also, because + SCP will always look at F1 even when IPLed off R1. + + The OS distributed with the simulator is version 16 of the Model + 10 SCP. This is sysgenned with support only for R1 and F1. If you + do a sysgen to support R2 amd F2 also, you must have images attached + to all 4 disks when you IPL, because SCP looks at all drives when + it starts up, and you will get an "Unattached Unit" error if you + fail to have one attached. + + 3) The 1442 card reader had in reality one card input hopper + and two stackers. This means the same path is used for reading and + punching cards. When punching cards, SCP does a read operation + and inspects the card read for blanks, and if it is not blank, + issues a YH halt. SCP will not punch data onto non-blank cards. + This feature causes problems in the simulator, and as a result + if you punch cards from SCP, YOU MUST not have any file attached + to the CDR device. Leaving this device unattached presents an + infinite supply of blank cards to SCP for punching. + + + -- End of README_S3.txt -- diff --git a/S3/s3_cd.c b/S3/s3_cd.c new file mode 100644 index 00000000..c3ed759a --- /dev/null +++ b/S3/s3_cd.c @@ -0,0 +1,434 @@ +/* s3_cd.c: IBM 1442 card reader/punch + + 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"), + 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 card reader + cdp card punch + cdp2 card punch stacker 2 + + 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, + suitable for binary data. + +*/ + +#include "s3_defs.h" +#include + +extern uint8 M[]; +extern char ebcdic_to_ascii[256]; +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_attach (UNIT *uptr, char *cptr); +t_stat cd_reset (DEVICE *dptr); + +int32 DAR; /* Data address register */ +int32 LCR; /* Length Count Register */ +int32 lastcard = 0; /* Last card switch */ +int32 carderr = 0; /* Error switch */ +int32 pcherror = 0; /* Punch error */ +int32 notready = 0; /* Not ready error */ +int32 cdr_ebcdic = 0; /* EBCDIC mode on reader */ +int32 cdp_ebcdic = 0; /* EBCDIC mode on punch */ + +/* Card reader data structures + + cdr_dev CDR descriptor + cdr_unit CDR unit descriptor + cdr_reg CDR register list +*/ + +UNIT cdr_unit = { + UDATA (&cdr_svc, UNIT_SEQ+UNIT_ATTABLE, 0), 100 }; + +REG cdr_reg[] = { + { FLDATA (LAST, lastcard, 0) }, + { FLDATA (ERR, carderr, 0) }, + { FLDATA (NOTRDY, notready, 0) }, + { HRDATA (DAR, DAR, 16) }, + { HRDATA (LCR, LCR, 16) }, + { FLDATA (EBCDIC, cdr_ebcdic, 0) }, + { FLDATA (S2, s2sel, 0) }, + { DRDATA (POS, cdr_unit.pos, 31), PV_LEFT }, + { DRDATA (TIME, cdr_unit.wait, 24), PV_LEFT }, + { BRDATA (BUF, rbuf, 8, 8, CDR_WIDTH) }, + { NULL } }; + +DEVICE cdr_dev = { + "CDR", &cdr_unit, cdr_reg, NULL, + 1, 10, 31, 1, 8, 7, + NULL, NULL, &cd_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[] = { + { FLDATA (ERR, pcherror, 0) }, + { FLDATA (EBCDIC, cdp_ebcdic, 0) }, + { FLDATA (S2, s2sel, 0) }, + { FLDATA (NOTRDY, notready, 0) }, + { HRDATA (DAR, DAR, 16) }, + { HRDATA (LCR, LCR, 16) }, + { DRDATA (POS, cdp_unit.pos, 31), PV_LEFT }, + { NULL } }; + +DEVICE cdp_dev = { + "CDP", &cdp_unit, cdp_reg, NULL, + 1, 10, 31, 1, 8, 7, + NULL, NULL, &cd_reset, + NULL, NULL, NULL }; + +/* Stacker data structures + + stack_dev STACK device descriptor + stack_unit STACK unit descriptors + stack_reg STACK register list +*/ + +UNIT stack_unit[] = { + { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) } }; + +REG stack_reg[] = { + { DRDATA (POS0, stack_unit[0].pos, 31), PV_LEFT }, + { NULL } }; + +DEVICE stack_dev = { + "CDP2", stack_unit, stack_reg, NULL, + 1, 10, 31, 1, 8, 7, + NULL, NULL, &cd_reset, + NULL, NULL, NULL }; + + +/* -------------------------------------------------------------------- */ + +/* 1442: master routine */ + +int32 crd (int32 op, int32 m, int32 n, int32 data) +{ + int32 iodata; + switch (op) { + case 0: /* SIO 1442 */ + /* if (n == 1) + return STOP_IBKPT; */ + switch (data) { /* Select atacker */ + case 0x00: + break; + case 0x01: + s2sel = 1; + break; + default: + break; + } + switch (n) { + case 0x00: /* Feed */ + iodata = SCPE_OK; + break; + case 0x01: /* Read only */ + if (cdr_ebcdic) + iodata = read_card(0, 1); + else + iodata = read_card(0, 0); + break; + case 0x02: /* Punch and feed */ + iodata = punch_card(0, 0); + break; + case 0x03: /* Read Col Binary */ + iodata = read_card(0, 1); + break; + case 0x04: /* Punch no feed */ + iodata = punch_card(0, 1); + break; + default: + return STOP_INVDEV; + } + return iodata; + case 1: /* LIO 1442 */ + switch (n) { + case 0x00: /* Load LCR */ + LCR = data & 0xffff; + break; + case 0x04: + DAR = data & 0xffff; + break; + default: + return STOP_INVDEV; + } + return SCPE_OK; + case 2: /* TIO 1442 */ + iodata = 0; + switch (n) { + case 0x00: /* Error */ + if (carderr || pcherror || notready) + iodata = 1; + if ((cdr_unit.flags & UNIT_ATT) == 0) + iodata = 1; /* attached? */ + break; + case 0x02: /* Busy */ + if (sim_is_active (&cdr_unit)) + iodata = 1; + break; + default: + return (STOP_INVDEV << 16); + } + return ((SCPE_OK << 16) | iodata); + case 3: /* SNS 1442 */ + iodata = 0; + switch (n) { + case 0x01: + break; + case 0x02: + break; + case 0x03: + if (carderr) + iodata |= 0x80; + if (lastcard) + iodata |= 0x40; + if (pcherror) + iodata |= 0x20; + if ((cdr_unit.flags & UNIT_ATT) == 0) + iodata |= 0x08; + if (notready) + iodata |= 0x08; + break; + case 0x04: + iodata = DAR; + break; + default: + return (STOP_INVDEV << 16); + } + iodata |= ((SCPE_OK << 16) & 0xffff0000); + return (iodata); + case 4: /* APL 1442 */ + iodata = 0; + switch (n) { + case 0x00: /* Error */ + if (carderr || pcherror || notready) + iodata = 1; + if ((cdr_unit.flags & UNIT_ATT) == 0) + iodata = 1; /* attached? */ + break; + case 0x02: /* Busy */ + if (sim_is_active (&cdr_unit)) + iodata = 1; + break; + default: + return (STOP_INVDEV << 16); + } + return ((SCPE_OK << 16) | iodata); + default: + break; + } +} + +/* Card read routine + mod 0 = ASCII read + mod 1 = EBCDIC read +*/ + +t_stat read_card (int32 ilnt, int32 mod) +{ +int32 i, cnt; +t_stat r; + +if (sim_is_active (&cdr_unit)) { /* busy? */ + sim_cancel (&cdr_unit); /* cancel */ + if (r = cdr_svc (&cdr_unit)) return r; /* process */ +} + +if (((cdp_unit.flags & UNIT_ATT) != 0 || + (stack_unit[0].flags & UNIT_ATT) != 0) && /* Punch is attached and */ + (cdr_unit.flags & UNIT_ATT) == 0) { /* reader is not --- */ + for (i = 0; i < 80; i++) { /* Assume blank cards in hopper */ + PutMem(DAR, 0x40); + DAR++; + } + sim_activate (&cdr_unit, cdr_unit.wait); /* activate */ + return SCPE_OK; +} + +if ((cdr_unit.flags & UNIT_ATT) == 0) return SCPE_UNATT; /* attached? */ + +lastcard = carderr = notready = s1sel = s2sel = 0; /* default stacker */ + +for (i = 0; i < CBUFSIZE; i++) rbuf[i] = 0x20; /* clear buffer */ +if (mod) { + for (i = 0; i < 80; i++) { + rbuf[i] = fgetc(cdr_unit.fileref); /* Read EBCDIC */ + } +} else { + fgets (rbuf, CBUFSIZE, cdr_unit.fileref); /* read Ascii */ +} +if (feof (cdr_unit.fileref)) { /* eof? */ + notready = 1; + return STOP_NOCD; +} +if (ferror (cdr_unit.fileref)) { /* error? */ + perror ("Card reader I/O error"); + clearerr (cdr_unit.fileref); + carderr = 1; + return SCPE_OK; } +cdr_unit.pos = ftell (cdr_unit.fileref); /* update position */ +i = getc (cdr_unit.fileref); /* see if more */ +if (feof (cdr_unit.fileref)) lastcard = 1; /* eof? set flag */ +fseek (cdr_unit.fileref, cdr_unit.pos, SEEK_SET); +for (i = 0; i < 80; i++) { + if (mod == 0) { /* If ASCII mode... */ + if (rbuf[i] == '\n' || /* remove ASCII CR/LF */ + rbuf[i] == '\r' || + rbuf[i] == 0x00) + rbuf[i] = ' '; + rbuf[i] = ascii_to_ebcdic[rbuf[i]]; /* convert to EBCDIC */ + } + PutMem(DAR, rbuf[i]); /* Copy to main memory */ + DAR++; +} +sim_activate (&cdr_unit, cdr_unit.wait); /* activate */ +return SCPE_OK; +} + +/* Card reader service. If a stacker select is active, copy to the + selected stacker. Otherwise, copy to the normal stacker. If the + unit is unattached, simply exit. +*/ + +t_stat cdr_svc (UNIT *uptr) +{ +int32 i; + +if (s2sel) uptr = &stack_unit[0]; /* stacker 1? */ +else uptr = &stack_unit[0]; /* then default */ +if ((uptr -> flags & UNIT_ATT) == 0) return SCPE_OK; /* attached? */ +for (i = 0; i < CDR_WIDTH; i++) rbuf[i] = ebcdic_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? */ + perror ("Card stacker I/O error"); + clearerr (uptr -> fileref); +} +uptr -> pos = ftell (uptr -> fileref); /* update position */ +return SCPE_OK; +} + +/* Card punch routine + + mod: not used +*/ + +t_stat punch_card (int32 ilnt, int32 mod) +{ +int32 i, colcount; +static char pbuf[CDP_WIDTH + 1]; /* + null */ +UNIT *uptr; + +if (s2sel) uptr = &stack_unit[0]; /* stack 2? */ +else uptr = &cdp_unit; /* normal output */ +if ((uptr -> flags & UNIT_ATT) == 0) { /* Attached? */ + notready = 1; + return SCPE_OK; +} +pcherror = s1sel = notready = 0; /* clear flags */ + +colcount = 128 - LCR; +for (i = 0; i < colcount; i++) { /* Fetch data */ + if (cdp_ebcdic) + pbuf[i] = GetMem(DAR) & 0xff; + else + pbuf[i] = ebcdic_to_ascii[GetMem(DAR)]; + DAR++; +} +for (i = CDP_WIDTH - 1; (i >= 0) && (pbuf[i] == ' '); i--) pbuf[i] = 0; +pbuf[CDP_WIDTH] = 0; /* trailing null */ +if (!cdp_ebcdic) { + fputs (pbuf, uptr -> fileref); /* output card */ + fputc ('\n', uptr -> fileref); /* plus new line */ +} else { + for (i = 0; i < 80; i++) { + fputc(pbuf[i], uptr -> fileref); + } +} +if (ferror (uptr -> fileref)) { /* error? */ + perror ("Card punch I/O error"); + clearerr (uptr -> fileref); + pcherror = 1; +} +uptr -> pos = ftell (uptr -> fileref); /* update position */ +return SCPE_OK; +} + +/* Select stack routine + + Modifiers have been checked by the caller + Modifiers are 1, 2, for the respective stack +*/ + +t_stat select_stack (int32 ilnt, int32 mod) +{ +if (mod == 1) s1sel = 1; +else if (mod == 2) s2sel = 1; +return SCPE_OK; +} + +/* Card reader/punch reset */ + +t_stat cd_reset (DEVICE *dptr) +{ +lastcard = carderr = notready = pcherror = 0; /* clear indicators */ +s1sel = s2sel = 0; /* clear stacker sel */ +sim_cancel (&cdr_unit); /* clear reader event */ +return SCPE_OK; +} + +/* Card reader attach */ + +t_stat cdr_attach (UNIT *uptr, char *cptr) +{ +carderr = lastcard = notready = 0; /* clear last card */ +return attach_unit (uptr, cptr); +} + +/* Bootstrap routine */ + +t_stat cdr_boot (int32 unitno) +{ +cdr_ebcdic = 1; +DAR = 0; +LCR = 80; +read_card(0, 1); +return SCPE_OK; +} diff --git a/S3/s3_cpu.c b/S3/s3_cpu.c new file mode 100644 index 00000000..b0f1859c --- /dev/null +++ b/S3/s3_cpu.c @@ -0,0 +1,1825 @@ +/* s3_cpu.c: IBM System/3 CPU simulator + + Copyright (c) 2001, Charles E. Owen + HPL & SLC instruction code Copyright (c) 2001 by Henk Stegeman + Decimal Arithmetic Copyright (c) 2000 by Roger Bowler + + 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. + + ------------------------------------------------------------------------------ + + cpu System/3 (models 10 and 15) central processor + + The IBM System/3 was a popular small-business computing system introduced + in 1969 as an entry-level system for businesses that could not afford + the lowest rungs of the System/360. Its architecture is inspired by and + in some ways similar to the 360, but to save cost the instruction set is + much smaller and the I/O channel system greatly simplified. There is no + compatibilty between the two systems. + + The original System/3 had two models, 6 and 10, and these came in two + configurations: card system and disk system. The unique feature of + the /3 was the use of 96-column cards, although traditional 80-column + cards were supprted also via attachment of a 1442 reader/punch. + System/3 is a batch-oriented system, controlled by an operating + system known as SCP (System Control Program), with it's own job control + language known as OCL (simpler and more logical than the JCL used on + the mainframes). Original models did not support multiprogramming + or any form of interactivity. (There was a hardware dual-program + facility available on the model 10 at the high end). + + The line grew throughout the 1970s, overlapping the low end of the 360 + line with the introduction of the model 15. The 15 (and later larger + variations of the model 12) broke the 64K limit designed in the original + models by adding a simple address translation unit to support up to 512K + bytes. The model 15 added a system of storage protection and allowed + multiprogramming in up to 3 partitions. Communications were added to + allow support of multiple 3270 terminals and the models 12 and 15 broke + the batch orientation and facilitated interactive use via the CCP + (communications control program). The System/3 was effectively replaced + by the much easier to manage and use System/34 and System/36 at the + low and middle of the range, and by System/370 or System/38 at the + high end. + + This simulator implements the model 10 and model 15. Models 4, 6, + 8, and 12 are not supported (these were technical variations on the + design which offered no functionality not present on either 10 or 15). + + The System/3 is a byte-oriented machine with a data path of 8 bits + in all models, and an address width of 16 bits. + + The register state for the System/3 CPU is: + + BAR <0:15> Operand 1 address register + AAR <0:15> Operand 2 address register + XR1 <0:15> Index Register 1 + XR2 <0:15> Index Register 2 + PSR <0:15> Condition Register + IAR [0:9]<0:15> Instruction Address Register (p1, p2, plus 1 for each interrupt) + ARR [0:9]<0:15> Address Recall Register (p1, p2, plus 1 for each interrupt) + (The P2 IAR & ARR are used for the Dual Program feature) + + Instruction formats follow the same basic pattern: a 1-byte opcode, a + 1-byte "Q byte", and one or two addresses following in a format defined + by the first 4 bits of the opcode: + + Op Code Q Byte Address(es) + + 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 + +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--... + | A 1 | A 2 | operation | | (defined by operation)| | Format based on A1, A2 + +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--+--+ +--+--+--+--+--+--+--... + + { --- } <---------------- Bits 00 = Operand 2 specified by 2-byte direct addr + Bits 01 = Operand 2 is 1-byte displacement + XR1 + Bits 10 = Operand 2 is 1-byte displacement + XR2 + Bits 11 = Operand 2 is not used + + { --- } <---------------------- Bits 00 = Operand 1 specified by 2-byte direct addr + Bits 01 = Operand 1 is 1-byte displacement + XR1 + Bits 10 = Operand 1 is 1-byte displacement + XR2 + Bits 11 = Operand 1 is not used + + Instructions come in 3 basic formats, of varying lengths which are determined + by the top 4 bits of opcode defined above. Minimum instruction length is 3 bytes, + maximum is 6. + + 1) Command Format (Bits 0-3 are 1111): + + +------------+ +------------+ +------------+ + | Opcode | | Q-byte | | R-byte + + +------------+ +------------+ +------------+ + + (The meaning of Q-byte and R-byte defined by the operation) + + + 2) One Address Instructions (either bits 0-1 or bits 2-3 are 01): + + + Direct Addressing Format: + + +------------+ +------------+ +-----------+----------+ + | Opcode | | Q-byte | | MSB + LSB + + +------------+ +------------+ +-----------+----------+ + + Base-Displacement Format: + + +------------+ +------------+ +------------+ + | Opcode | | Q-byte | |displacement+ + +------------+ +------------+ +------------+ + + Opcodes are 0011xxxx or 1100xxxx. + + Q-byte can be: 1) An immediate operand + 2) A mask + 3) A branch condition + 4) A data selection + + 2) Two Address Instructions (neither bits 0-1 nor bits 2-3 are both 11): + + Operand 1 Address Direct (opcodes 0001 or 0010): + + +------------+ +------------+ +----------+----------+ +------------+ + | Opcode | | Q-byte | | MSB + LSB + |displacement| + +------------+ +------------+ +----------+----------+ +------------+ + + Operand 2 Address Direct (opcodes 0100 or 1000): + + +------------+ +------------+ +------------+ +----------+----------+ + | Opcode | | Q-byte | |displacement| | MSB + LSB + + +------------+ +------------+ +------------+ +----------+----------+ + + Both Addresses Direct (opcode 0000): + + +------------+ +------------+ +----------+----------+ +-----------+----------+ + | Opcode | | Q-byte | | MSB + LSB + + MSB + LSB + + +------------+ +------------+ +----------+----------+ +-----------+----------+ + + Both Addresses Displacement (opcodes 0101, 0110, 1001, or 1010): + + +------------+ +------------+ +------------+ +------------+ + | Opcode | | Q-byte | |displacement| |displacement| + +------------+ +------------+ +------------+ +------------+ + + +Assembler Mnemonic Format +------------------------- + + The assembler format contains the same elements as the machine language operation, +but not always in the same format. The operation code frequently specifies both +the opcode and the Q byte, and the top nybble of the opcode is determined by +the format of the addresses. + + Addresses take two forms: the direct address in hex, or a relative address +specified thusly: (byte,XRx) where 'byte' is a 1-byte offset, and XRx is +either XR1 or XR2 for the two index registers. Use these formats when +'address' is indicated below: + + When 'reg' is mentioned, a mnemonic may be used for the register, thusly: + IAR Instruction Address Register for the current program level + ARR Address Recall Register for the current program level + P1IAR IAR for Program Level 1 + P2IAR IAR for Program Level 2 + PSR Program Status Register + 0x01 - Equal + 0x02 - Low + 0x04 - High + 0x08 - Decimal overflow + 0x10 - Test false + 0x20 - Binary overflow + 0x40 - Not used + 0x80 - Not used + XR1 Index Register 1 + XR2 Index Register 2 + IARx IAR for the interrupt level x (x = 0 thru 7) + + All other operands mentioned below are single-byte hex, except for the +length (len) operand of the two-address instructions, which is a decimal length +in the range 1-256. + + No-address formats: + ------------------ + + HPL hex,hex Halt Program Level, the operands are the Q and R bytes + + + One-address formats: + ------------------- + + A reg,address Add to register + CLI address,byte Compare Logical Immediate + MVI address,byte Move Immediate + TBF address,mask Test Bits Off + TBN address,mask Test Bits On + SBF address,mask Set Bits Off + SBN address,mask Set Bits On + ST reg,address Store Register + L reg,address Load Register + LA reg,address Load Address + JC address,cond Jump on Condition + BC address,cond Branch on Condition + + These operations do not specify a qbyte, it is implicit in the opcode: + + B address Unconditional branch to address + BE address Branch Equal + BNE address Branch Not Equal + BH address Branch High + BNH address Branch Not High + BL address Branch Low + BNL address Branch Not Low + BT address Branch True + BF address Branch False + BP address Branch Plus + BM address Branch Minus + BNP address Branch Not Plus + BNM address Branch Not Minus + BZ address Branch Zero + BNZ address Branch Not Zero + BOZ address Branch Overflow Zoned + BOL address Branch Overflow Logical + BNOZ address Branch No Overflow Zoned + BNOL address Branch No Overflow Logical + NOPB address No - never jump + + (substitute J for B above for a set of Jumps -- 1-byte operand (not 2), + always jumps forward up to 255 bytes. In this case, 'address' cannot be + less than the current address, nor greater than the current address + 255) + + Two-address formats (first address is destination, len is decimal 1-256): + ------------------- + + MVC address,address,len Move Characters + CLC address,address,len Compare Logical Characters + ALC address,address,len Add Logical Characters + SLC address,address,len Subtract Logical Characters + ED address,address,len Edit + ITC address,address,len Insert and Test Characters + AZ address,address,len Add Zoned Decimal + SZ address,address,len Subtract Zoned Decimal + + MNN address,address Move Numeric to Numeric + MNZ address,address Move Numeric to Zone + MZZ address,address Move Zone to Zone + MZN address,address Move Zone to Numeric + + I/O Format + ---------- + + In the I/O format, there are always 3 fields: + + da - Device Address 0-15 (decimal) + m - Modifier 0-1 + n - Function 0-7 + + The meaning of these is entirely defined by the device addressed. + + There may be an optional control byte, or an optional address (based on +the type of instruction). + + SNS da,m,n,address Sense I/O + LIO da,m,n,address Load I/O + TIO da,m,n,address Test I/O + + SIO da,m,n,cc Start I/O -- cc is a control byte + + APL da,m,n Advance Program Level + + + + --------------------------------------------- + Here is a handy opcode cross-reference table: + --------------------------------------------- + + | x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF +---+------------------------------------------------------------------ +0x | - - - - ZAZ - AZ SZ MVX - ED ITC MVC CLC ALC SLC +1x | - - - - ZAZ - AZ SZ MVX - ED ITC MVC CLC ALC SLC +2x | - - - - ZAZ - AZ SZ MVX - ED ITC MVC CLC ALC SLC +3x | SNS LIO - - ST L A - TBN TBF SBN SBF MVI CLI - - + | +4x | - - - - ZAZ - AZ SZ MVX - ED ITC MVC CLC ALC SLC +5x | - - - - ZAZ - AZ SZ MVX - ED ITC MVC CLC ALC SLC +6x | - - - - ZAZ - AZ SZ MVX - ED ITC MVC CLC ALC SLC +7x | SNS LIO - - ST L A - TBN TBF SBN SBF MVI CLI - - + | +8x | - - - - ZAZ - AZ SZ MVX - ED ITC MVC CLC ALC SLC +9x | - - - - ZAZ - AZ SZ MVX - ED ITC MVC CLC ALC SLC +Ax | - - - - ZAZ - AZ SZ MVX - ED ITC MVC CLC ALC SLC +Bx | SNS LIO - - ST L A - TBN TBF SBN SBF MVI CLI - - + | +Cx | BC TIO LA - - - - - - - - - - - - - +Dx | BC TIO LA - - - - - - - - - - - - - +Ex | BC TIO LA - - - - - - - - - - - - - +Fx | HPL APL JC SIO - - - - - - - - - - - - + +*/ + +/* This routine is the instruction decode routine for System/3. + 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 + program check caused by invalid opcode or qbyte or address or I/O spec + unknown I/O device and STOP_DEV flag set + I/O error in I/O simulator + + 2. Interrupts. + + There are 8 levels of interrupt, each with it's own IAR (program + counter). When an interrupt occurs, execution begins at the + location in the IAR for that level interrupt. The program + must save and restore state. Each device is assigned both a + level and a priority in hardware. Interrupts are reset via + an SIO instruction, when this happens, the program level + IAR resumes control. + + Interrupts are maintained in the global variable int_req, + which is zero if no interrupts are pending, otherwise, the + lower 16 bits represent devices, rightmost bit being device + 0. Each device requesting an interrupt sets its bit on. + + + 3. Non-existent memory. On the System/3, any reference to non-existent + memory (read or write) causes a program check and machine stop. + + 4. Adding I/O devices. These modules must be modified: + + ibms3_defs.h add interrupt request definition + ibms3_cpu.c add IOT mask, PI mask, and routine to dev_table + ibms3_sys.c add pointer to data structures to sim_devices +*/ + +#include "s3_defs.h" + +#define UNIT_V_M15 (UNIT_V_UF) /* Model 15 extensions */ +#define UNIT_M15 (1 << UNIT_V_M15) +#define UNIT_V_DPF (UNIT_V_UF+1) /* Dual Programming */ +#define UNIT_DPF (1 << UNIT_V_DPF) +#define UNIT_V_MSIZE (UNIT_V_UF+3) /* dummy mask */ +#define UNIT_MSIZE (1 << UNIT_V_MSIZE) + +uint8 M[MAXMEMSIZE] = { 0 }; /* memory */ +int32 AAR = 0; /* Operand 1 addr reg */ +int32 BAR = 0; /* Operand 2 addr reg */ +int32 XR1 = 0; /* Index register 1 */ +int32 XR2 = 0; /* Index register 2 */ +int32 PSR = 0; /* Condition Register */ +int32 IAR[10] = { 0 }; /* IAR 0-7 = int level 8=P1 9=P2 */ +int32 ARR[10] = { 0 }; /* ARR 0-7 = int level 8=P1 9=P2 */ +int32 dev_disable = 0; /* interrupt disable mask */ +int32 int_req = 0; /* Interrupt request device bitmap */ +int32 level = 8; /* Current Execution Level*/ +int32 stop_dev = 0; /* stop on ill dev */ +int32 SR = 0; /* Switch Register */ +int32 saved_PC; /* Saved (old) PC) */ +int32 debug_reg = 0; /* set for debug/trace */ +int32 debug_flag = 0; /* 1 when trace.log open */ +FILE *trace; +extern int32 sim_int_char; +extern int32 sim_brk_types, sim_brk_dflt, sim_brk_summ; /* breakpoint info */ + +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 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); +extern int32 dsk1 (int32 op, int32 m, int32 n, int32 data); +extern int32 dsk2 (int32 op, int32 m, int32 n, int32 data); +extern int32 cpu (int32 op, int32 m, int32 n, int32 data); +extern t_stat sim_activate (UNIT *uptr, int32 delay); +int32 nulldev (int32 opcode, int32 m, int32 n, int32 data); +int add_zoned (int32 addr1, int32 len1, int32 addr2, int32 len2); +int32 subtract_zoned (int32 addr1, int32 len1, int32 addr2, int32 len2); +static void store_decimal (int32 addr, int32 len, uint8 *dec, int sign); +static void load_decimal (int32 addr, int32 len, uint8 *result, int32 *count, int32 *sign); +static void add_decimal (uint8 *dec1, uint8 *dec2, uint8 *result, int32 *count); +static void subtract_decimal (uint8 *dec1, uint8 *dec2, uint8 *result, int *count, int *sign); + +/* IOT dispatch table */ + +/* System/3 supports only 16 unique device addresses! */ + +struct ndev dev_table[16] = { + { 0, 0, &cpu }, /* Device 0: CPU control */ + { 1, 0, &pkb }, /* Device 1: 5471 console printer/keyboard */ + { 0, 0, &nulldev }, + { 0, 0, &nulldev }, + { 0, 0, &nulldev }, + { 0, 0, &crd }, /* Device 5: 1442 card reader/punch */ + { 0, 0, &nulldev }, /* Device 6: 3410 Tape drives 1 & 2 */ + { 0, 0, &nulldev }, /* Device 7: 3410 Tape drives 3 & 4 */ + { 0, 0, &nulldev }, + { 0, 0, &nulldev }, + { 0, 0, &dsk1 }, /* Device 10: 5444 Disk Drive 1 */ + { 0, 0, &dsk2 }, /* Device 11: 5444 Disk Drive 2 */ + { 0, 0, &nulldev }, /* Device 12: 5448 Disk Drive 1 */ + { 0, 0, &nulldev }, /* DEvice 13: 5448 Disk Drive 2 */ + { 0, 0, &lpt }, /* Device 14: 1403/5203 Printer */ + { 0, 0, &nulldev } /* Device 15: 5424 MFCU */ +}; + +/* Priority assigned to interrupt levels */ + +int32 priority[8] = {8, 7, 5, 4, 3, 6, 2, 1}; + + +/* CPU data structures + + cpu_dev CPU device descriptor + cpu_unit CPU unit descriptor + cpu_reg CPU register list + cpu_mod CPU modifiers list +*/ + +UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) }; + +REG cpu_reg[] = { + { HRDATA (IAR, saved_PC, 16), REG_RO }, + { HRDATA (IAR-P1, IAR[8], 16) }, + { HRDATA (IAR-P2, IAR[9], 16) }, + { HRDATA (ARR-P1, ARR[8], 16) }, + { HRDATA (ARR-P2, ARR[9], 16) }, + { HRDATA (AAR, AAR, 16) }, + { HRDATA (BAR, BAR, 16) }, + { HRDATA (XR1, XR1, 16) }, + { HRDATA (XR2, XR2, 16) }, + { HRDATA (PSR, PSR, 16) }, + { HRDATA (SR, SR, 16) }, + { HRDATA (INT, int_req, 16), REG_RO }, + { HRDATA (LEVEL, level, 16) }, + { HRDATA (IAR0, IAR[0], 16) }, + { HRDATA (IAR1, IAR[1], 16) }, + { HRDATA (IAR2, IAR[2], 16) }, + { HRDATA (IAR3, IAR[3], 16) }, + { HRDATA (IAR4, IAR[4], 16) }, + { HRDATA (IAR5, IAR[5], 16) }, + { HRDATA (IAR6, IAR[6], 16) }, + { HRDATA (IAR7, IAR[7], 16) }, + { HRDATA (ARR0, ARR[0], 16) }, + { HRDATA (ARR1, ARR[1], 16) }, + { HRDATA (ARR2, ARR[2], 16) }, + { HRDATA (ARR3, ARR[3], 16) }, + { HRDATA (ARR4, ARR[4], 16) }, + { HRDATA (ARR5, ARR[5], 16) }, + { HRDATA (ARR6, ARR[6], 16) }, + { HRDATA (ARR7, ARR[7], 16) }, + { HRDATA (DISABLE, dev_disable, 16), REG_RO }, + { FLDATA (STOP_DEV, stop_dev, 0) }, + { HRDATA (WRU, sim_int_char, 8) }, + { HRDATA (DEBUG, debug_reg, 16) }, + { NULL } }; + +MTAB cpu_mod[] = { + { UNIT_M15, UNIT_M15, "M15", "M15", NULL }, + { UNIT_M15, 0, "M10", "M10", NULL }, + { UNIT_DPF, UNIT_DPF, "DPF", "DPF", NULL }, + { UNIT_DPF, 0, "NODPF", "NODPF", NULL }, + { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size }, + { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size }, + { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size }, + { UNIT_MSIZE, 49152, NULL, "48K", &cpu_set_size }, + { UNIT_MSIZE, 65535, 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 }; + +t_stat sim_instr (void) +{ +extern int32 sim_interval; +register int32 PC, IR; +int32 i, j, carry, zero, gt, f, op1, op2; +int32 opcode = 0, qbyte = 0, rbyte = 0; +int32 opaddr, addr1, addr2, dlen1, dlen2, r; +int32 int_savelevel = 8, intpri, intlev, intdev, intmask; +int32 devno, devm, devn; +char display[3][9]; +char resp[2]; +char trstr[256]; +int32 val [32]; +register t_stat reason; + +/* Restore register state */ + +PC = IAR[level]; /* load local PC */ +reason = 0; + +/* Main instruction fetch/decode loop */ + +while (reason == 0) { /* loop until halted */ +if (sim_interval <= 0) { /* check clock queue */ + if (reason = sim_process_event ()) break; } + + +if (int_req) { /* interrupt? */ + intpri = 16; + for (i = 0; i < 16; i++) { /* Get highest priority device */ + if ((int_req >> i) & 0x01) { + intlev = dev_table[i].level; + if (priority[intlev] < intpri) { + intdev = i; + intpri = priority[intlev]; + } + } + } + intmask = 1 << intdev; /* mask is interrupting dev bit */ + int_req = ~int_req & intmask; /* Turn off int_req for device */ + int_savelevel = level; /* save current level for reset */ + level = dev_table[intdev].level; /* get int level from device */ + PC = IAR[level]; /* Use int level IAR for new PC */ +} /* end interrupt */ + +if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ + reason = STOP_IBKPT; /* stop simulation */ + break; +} + +/* Machine Instruction Execution Here */ + +if ((debug_reg == 0) && debug_flag == 1) { + fclose(trace); + debug_flag = 0; +} +if (debug_reg) { + if (!debug_flag) { + trace = fopen("trace.log", "w"); + debug_flag = 1; + } +} + +if (debug_reg & 0x01) { + fprintf(trace, "ARR=%04X XR1=%04X XR2=%04X IAR=%04X ", ARR[level], XR1, XR2, PC); + val[0] = GetMem(PC); + val[1] = GetMem(PC+1); + val[2] = GetMem(PC+2); + val[3] = GetMem(PC+3); + val[4] = GetMem(PC+4); + val[5] = GetMem(PC+5); + fprint_sym(trace, PC, val, &cpu_unit, SWMASK('M')); + fprintf(trace, "\n"); +} + +saved_PC = PC; +opaddr = GetMem(PC) & 0xf0; /* fetch addressing mode */ +opcode = GetMem(PC) & 0x0f; /* fetch opcode */ +PC = (PC + 1) & AMASK; +sim_interval = sim_interval - 1; + +qbyte = GetMem(PC) & 0xff; /* fetch qbyte */ +PC = (PC + 1) & AMASK; + +if (opaddr == 0xf0) { /* Is it command format? */ + rbyte = GetMem(PC) & 0xff; + PC = (PC + 1) & AMASK; + switch (opcode) { + case 0x00: /* HPL: Halt Program Level */ + for (i = 0; i < 3; i++) { + for (j = 0; j < 9; j++) { + display[i][j] = ' '; + } + } + /* First line */ + if (qbyte & 0x04) display[0][2] = '_' ; + if (rbyte & 0x04) display[0][6] = '_' ; + /* Second line */ + if (qbyte & 0x08) display[1][1] = '|' ; + if (rbyte & 0x08) display[1][5] = '|' ; + if (qbyte & 0x10) display[1][2] = '_' ; + if (rbyte & 0x10) display[1][6] = '_' ; + if (qbyte & 0x02) display[1][3] = '|' ; + if (rbyte & 0x02) display[1][7] = '|' ; + /* Third line */ + if (qbyte & 0x20) display[2][1] = '|' ; + if (rbyte & 0x20) display[2][5] = '|' ; + if (qbyte & 0x40) display[2][2] = '_' ; + if (rbyte & 0x40) display[2][6] = '_' ; + if (qbyte & 0x01) display[2][3] = '|' ; + if (rbyte & 0x01) display[2][7] = '|' ; + /* Print display segment array */ + printf("\n\r"); + for (i = 0; i < 3; i++) { + for (j = 0; j < 9; j++) { + printf ("%c", display[i][j]); + } + printf ("\n\r"); + } + reason = STOP_HALT; + break; + case 0x01: /* APL: Advance Program Level */ + devno = (qbyte >> 4) & 0x0f; + devm = (qbyte >> 3) & 0x01; + devn = qbyte & 0x07; + op1 = dev_table[devno].routine(4, devm, devn, rbyte); + if (op1 & 0x01) { + if (cpu_unit.flags & UNIT_DPF) { /* Dual Programming? */ + if (level == 8) /* Yes: switch program levels */ + level = 9; + else + level = 8; + PC = IAR[level]; + } else { /* No: Loop on this inst */ + PC = PC - 3; + } + } + reason = (op1 >> 16) & 0xffff; + break; + case 0x02: /* JC: Jump on Condition */ + if (condition(qbyte) == 1) { + PC = (PC + rbyte) & AMASK; + } + break; + case 0x03: /* SIO: Start I/O */ + devno = (qbyte >> 4) & 0x0f; + devm = (qbyte >> 3) & 0x01; + devn = qbyte & 0x07; + reason = dev_table[devno].routine(0, devm, devn, rbyte); + if (reason == RESET_INTERRUPT) { + reason = SCPE_OK; + IAR[level] = PC; + level = int_savelevel; + PC = IAR[level]; + } + break; + default: + reason = STOP_INVOP; + break; + } /* switch (opcode) */ + IAR[level] = PC; + continue; +} +/* Not command format: fetch the addresses */ + +addr1 = (opaddr >> 6) & 3; +addr2 = (opaddr >> 4) & 3; + +switch (addr1) { + case 0: + BAR = GetMem(PC) << 8; + PC = (PC + 1) & AMASK; + BAR |=GetMem(PC); + PC = (PC + 1) & AMASK; + break; + case 1: + BAR = GetMem(PC); + BAR = (BAR + XR1) & AMASK; + PC = (PC + 1) & AMASK; + break; + case 2: + BAR = GetMem(PC); + BAR = (BAR + XR2) & AMASK; + PC = (PC + 1) & AMASK; + break; + case 3: + break; + default: + break; +} /* switch (addr1) */ + +switch (addr2) { + case 0: + AAR = GetMem(PC) << 8; + PC = (PC + 1) & AMASK; + AAR |= GetMem(PC); + PC = (PC + 1) & AMASK; + break; + case 1: + AAR = GetMem(PC); + AAR = (AAR + XR1) & AMASK; + PC = (PC + 1) & AMASK; + break; + case 2: + AAR = GetMem(PC); + AAR = (AAR + XR2) & AMASK; + PC = (PC + 1) & AMASK; + break; + case 3: + break; + default: + break; +} /* switch (addr1) */ + +switch (opaddr) { + case 0x00: + case 0x10: + case 0x20: + case 0x40: + case 0x50: + case 0x60: + case 0x80: + case 0x90: + case 0xa0: + switch (opcode) { + case 4: /* ZAZ: Zero and Add Zoned */ + dlen2 = qbyte & 0x0f; + dlen1 = (qbyte >> 4) & 0xf; + dlen1 += dlen2; + op1 = BAR; + for (i = 0; i < (dlen1+1); i++) { + PutMem(op1, 0xf0); + op1--; + } + r = add_zoned(BAR, dlen1+1, AAR, dlen2+1); + PSR &= 0xF8; /* HJS mod */ + switch (r) { + case 0: + PSR |= 0x01; + break; + case 1: + PSR |= 0x02; + break; + case 2: + PSR |= 0x04; + break; + default: + break; + } + break; + case 6: /* AZ: Add Zoned */ + dlen2 = qbyte & 0x0f; + dlen1 = (qbyte >> 4) & 0xf; + dlen1 += dlen2; + r = add_zoned(BAR, dlen1+1, AAR, dlen2+1); + PSR &= 0xF0; + switch (r) { + case 0: + PSR |= 0x01; + break; + case 1: + PSR |= 0x02; + break; + case 2: + PSR |= 0x04; + break; + case 3: + PSR |= 0x08; + break; + default: + break; + } + break; + case 7: /* SZ: Subtract Zoned */ + dlen2 = qbyte & 0x0f; + dlen1 = (qbyte >> 4) & 0xf; + dlen1 += dlen2; + r = subtract_zoned(BAR, dlen1+1, AAR, dlen2+1); + PSR &= 0xF0; + switch (r) { + case 0: + PSR |= 0x01; + break; + case 1: + PSR |= 0x02; + break; + case 2: + PSR |= 0x04; + break; + case 3: + PSR |= 0x08; + break; + default: + break; + } + break; + case 8: /* MVX: Move Hex */ + op1 = GetMem(BAR); + op2 = GetMem(AAR); + switch (qbyte) { + case 0: /* Zone to zone */ + op1 = (op1 & 0x0F) | (op2 & 0xF0); + break; + case 1: /* Numeric to zone */ + op1 = (op1 & 0x0F) | (op2 << 4); + break; + case 2: /* Zone to numeric */ + op1 = (op1 & 0xF0) | (op2 >> 4); + break; + case 3: /* Numeric to numeric */ + op1 = (op1 & 0xF0) | (op2 & 0x0F); + break; + default: + reason = STOP_INVQ; + break; + } + PutMem(BAR, op1); + break; + case 0xa: /* ED: Edit */ + zero = 1; + PSR &= 0xF8; + IR = GetMem(AAR); + if ((IR & 0xf0) != 0xF0) + PSR |= 0x02; + else + PSR |= 0x04; + while (qbyte > -1) { + op2 = GetMem(AAR); + op1 = GetMem(BAR); + if (op1 == 0x20) { + op2 |= 0xf0; + PutMem(BAR, op2); + AAR--; + if (op2 != 0xF0) zero = 0; + } + BAR--; + qbyte--; + } + if (zero) + PSR |= 0x01; + break; + case 0xb: /* ITC: Insert and Test Chars */ + op2 = GetMem(AAR); + while (qbyte > -1) { + op1 = GetMem(BAR); + if (op1 >= 0xF1 && op1 <= 0xF9) + break; + PutMem(BAR, op2); + BAR++; + qbyte--; + } + ARR[level] = BAR; + break; + case 0xc: /* MVC: Move Characters */ + while (qbyte > -1) { + PutMem(BAR, GetMem(AAR)); + BAR--; + AAR--; + qbyte--; + } + break; + case 0xd: /* CLC: Compare Characters */ + PSR &= 0xF8; + i = BAR = BAR - qbyte; + j = AAR = AAR - qbyte; + while (qbyte > -1) { + if (GetMem(i) > GetMem(j)) { + PSR |= 0x04; + break; + } + if (GetMem(i) < GetMem(j)) { + PSR |= 0x02; + break; + } + i++; + j++; + qbyte--; + } + if (qbyte == -1) + PSR |= 0x01; + break; + case 0xe: /* ALC: Add Logical Characters */ + carry = 0; + zero = 1; + while (qbyte > -1) { + IR = GetMem(BAR) + GetMem(AAR) + carry; + if (IR & 0x100) + carry = 1; + else + carry = 0; + if ((IR & 0xFF) != 0) zero = 0; /* HJS mod */ + PutMem(BAR,(IR & 0xFF)); + BAR--; + AAR--; + qbyte--; + } + PSR &= 0xD8; + if (zero) + PSR |= 0x01; /* Equal */ + if (!zero && !carry) + PSR |= 0x02; /* Low */ + if (!zero && carry) + PSR |= 0x04; /* High */ + if (carry) + PSR |= 0x20; /* Overflow */ + break; + case 0xf: /* SLC: Subtract Logical Characters */ + carry = 1; + zero = 1; + while (qbyte > -1) { + IR = GetMem(BAR) + (0xFF - GetMem(AAR)) + carry; + if (IR & 0x100) + carry = 1; + else + carry = 0; + if ((IR & 0xFF) != 0) zero = 0; /* HJS mod */ + PutMem(BAR,(IR & 0xFF)); + BAR--; + AAR--; + qbyte--; + } + PSR &= 0xF8; + if (zero) + PSR |= 0x01; /* Equal */ + if (!zero && !carry) + PSR |= 0x02; /* Low */ + if (!zero && carry) + PSR |= 0x04; /* High */ + break; + default: + reason = STOP_INVOP; + break; + } + IAR[level] = PC; + continue; + break; + case 0x30: + case 0x70: + case 0xb0: + switch (opcode) { + case 0: /* SNS: Sense I/O */ + devno = (qbyte >> 4) & 0x0f; + devm = (qbyte >> 3) & 0x01; + devn = qbyte & 0x07; + i = dev_table[devno].routine(3, devm, devn, rbyte); + PutMem(BAR, i & 0xff); + BAR--; + PutMem(BAR, (i >> 8) & 0xff); + reason = (i >> 16) & 0xffff; + break; + case 1: /* LIO: Load I/O */ + devno = (qbyte >> 4) & 0x0f; + devm = (qbyte >> 3) & 0x01; + devn = qbyte & 0x07; + op1 = GetMem(BAR); + BAR--; + op1 |= (GetMem(BAR) << 8) & 0xff00; + reason = dev_table[devno].routine(1, devm, devn, op1); + break; + case 4: /* ST: Store Register */ + switch (qbyte) { + case 0x01: + PutMem(BAR, XR1 & 0xff); + BAR--; + PutMem(BAR, (XR1 >> 8) & 0xff); + break; + case 0x02: + PutMem(BAR, XR2 & 0xff); + BAR--; + PutMem(BAR, (XR2 >> 8) & 0xff); + break; + case 0x04: + PutMem(BAR, PSR & 0xFF); + BAR--; + PutMem(BAR, 0); /* LCRR, not imp. */ + break; + case 0x08: + PutMem(BAR, ARR[level] & 0xff); + BAR--; + PutMem(BAR, (ARR[level] >> 8) & 0xff); + break; + case 0x10: + PutMem(BAR, IAR[level] & 0xff); + BAR--; + PutMem(BAR, (IAR[level] >> 8) & 0xff); + break; + case 0x20: + PutMem(BAR, IAR[8] & 0xff); + BAR--; + PutMem(BAR, (IAR[8] >> 8) & 0xff); + break; + case 0x40: + PutMem(BAR, IAR[9] & 0xff); + BAR--; + PutMem(BAR, (IAR[9] >> 8) & 0xff); + break; + case 0x80: + PutMem(BAR, IAR[0] & 0xff); + BAR--; + PutMem(BAR, (IAR[0] >> 8) & 0xff); + break; + case 0x81: + PutMem(BAR, IAR[7] & 0xff); + BAR--; + PutMem(BAR, (IAR[7] >> 8) & 0xff); + break; + case 0x82: + PutMem(BAR, IAR[6] & 0xff); + BAR--; + PutMem(BAR, (IAR[6] >> 8) & 0xff); + break; + case 0x84: + PutMem(BAR, IAR[5] & 0xff); + BAR--; + PutMem(BAR, (IAR[5] >> 8) & 0xff); + break; + case 0x88: + PutMem(BAR, IAR[4] & 0xff); + BAR--; + PutMem(BAR, (IAR[4] >> 8) & 0xff); + break; + case 0x90: + PutMem(BAR, IAR[3] & 0xff); + BAR--; + PutMem(BAR, (IAR[3] >> 8) & 0xff); + break; + case 0xA0: + PutMem(BAR, IAR[2] & 0xff); + BAR--; + PutMem(BAR, (IAR[2] >> 8) & 0xff); + break; + case 0xC0: + PutMem(BAR, IAR[1] & 0xff); + BAR--; + PutMem(BAR, (IAR[1] >> 8) & 0xff); + break; + default: + reason = STOP_INVQ; + break; + } + break; + case 5: /* L: Load Register */ + switch (qbyte) { + case 0x01: + XR1 = GetMem(BAR) & 0xff; + BAR--; + XR1 |= (GetMem(BAR) << 8) & 0xff00; + break; + case 0x02: + XR2 = GetMem(BAR) & 0xff; + BAR--; + XR2 |= (GetMem(BAR) << 8) & 0xff00; + break; + case 0x04: + PSR = GetMem(BAR) & 0xff; + BAR--; + break; + case 0x08: + ARR[level] = GetMem(BAR) & 0xff; + BAR--; + ARR[level] |= (GetMem(BAR) << 8) & 0xff00; + break; + case 0x10: + IAR[level] = GetMem(BAR) & 0xff; + BAR--; + IAR[level] |= (GetMem(BAR) << 8) & 0xff00; + PC = IAR[level]; + break; + case 0x20: + IAR[8] = GetMem(BAR) & 0xff; + BAR--; + IAR[8] |= (GetMem(BAR) << 8) & 0xff00; + break; + case 0x40: + IAR[9] = GetMem(BAR) & 0xff; + BAR--; + IAR[9] |= (GetMem(BAR) << 8) & 0xff00; + break; + case 0x80: + IAR[0] = GetMem(BAR) & 0xff; + BAR--; + IAR[0] |= (GetMem(BAR) << 8) & 0xff00; + break; + case 0x81: + IAR[7] = GetMem(BAR) & 0xff; + BAR--; + IAR[7] |= (GetMem(BAR) << 8) & 0xff00; + break; + case 0x82: + IAR[6] = GetMem(BAR) & 0xff; + BAR--; + IAR[6] |= (GetMem(BAR) << 8) & 0xff00; + break; + case 0x84: + IAR[5] = GetMem(BAR) & 0xff; + BAR--; + IAR[5] |= (GetMem(BAR) << 8) & 0xff00; + break; + case 0x88: + IAR[4] = GetMem(BAR) & 0xff; + BAR--; + IAR[4] |= (GetMem(BAR) << 8) & 0xff00; + break; + case 0x90: + IAR[3] = GetMem(BAR) & 0xff; + BAR--; + IAR[3] |= (GetMem(BAR) << 8) & 0xff00; + break; + case 0xA0: + IAR[2] = GetMem(BAR) & 0xff; + BAR--; + IAR[2] |= (GetMem(BAR) << 8) & 0xff00; + break; + case 0xC0: + IAR[1] = GetMem(BAR) & 0xff; + BAR--; + IAR[1] |= (GetMem(BAR) << 8) & 0xff00; + break; + default: + reason = STOP_INVQ; + break; + } + break; + case 6: /* A: Add to Register */ + IR = GetMem(BAR) & 0x00ff; + BAR--; + IR |= (GetMem(BAR) << 8) & 0xff00; + switch (qbyte) { + case 0x01: + IR += XR1; + XR1 = IR & AMASK; + break; + case 0x02: + IR += XR2; + XR2 = IR & AMASK; + break; + case 0x04: + IR += PSR; + PSR = IR & AMASK; + break; + case 0x08: + IR += ARR[level]; + ARR[level] = IR & AMASK; + break; + case 0x10: + IR += IAR[level]; + IAR[level] = IR & AMASK; + break; + case 0x20: + IR += IAR[8]; + IAR[8] = IR & AMASK; + break; + case 0x40: + IR += IAR[9]; + IAR[9] = IR & AMASK; + break; + case 0x80: + IR += IAR[0]; + IAR[0] = IR & AMASK; + break; + case 0x81: + IR += IAR[7]; + IAR[7] = IR & AMASK; + break; + case 0x82: + IR += IAR[6]; + IAR[6] = IR & AMASK; + break; + case 0x84: + IR += IAR[5]; + IAR[5] = IR & AMASK; + break; + case 0x88: + IR += IAR[4]; + IAR[4] = IR & AMASK; + break; + case 0x90: + IR += IAR[3]; + IAR[3] = IR & AMASK; + break; + case 0xA0: + IR += IAR[2]; + IAR[2] = IR & AMASK; + break; + case 0xC0: + IR += IAR[1]; + IAR[1] = IR & AMASK; + break; + default: + reason = STOP_INVQ; + break; + } + PSR &= 0xD8; + if ((IR & 0xffff) == 0) + PSR |= 0x01; /* Zero */ + if ((IR & 0xffff) != 0 && !(IR & 0x10000)) + PSR |= 0x02; /* Low */ + if ((IR & 0xffff) != 0 && (IR & 0x10000)) + PSR |= 0x04; /* High */ + if ((IR & 0x10000)) + PSR |= 0x20; /* Bin overflow */ + break; + case 8: /* TBN: Test Bits On */ + IR = GetMem(BAR); + PSR &= 0xFF; + if ((IR & qbyte) != qbyte) + PSR |= 0x10; + break; + case 9: /* TBF: Test Bits Off */ + IR = GetMem(BAR); + PSR &= 0xFF; + if ((IR & qbyte)) + PSR |= 0x10; + break; + case 0xa: /* SBN: Set Bits On */ + IR = GetMem(BAR); + IR |= qbyte; + PutMem(BAR, IR); + break; + case 0xb: /* SBF: Set Bits Off */ + IR = GetMem(BAR); + IR &= ~qbyte; + PutMem(BAR, IR); + break; + case 0xc: /* MVI: Move Immediate */ + PutMem(BAR, qbyte); + break; + case 0xd: /* CLI: Compare Immediate */ + PSR = compare(GetMem(BAR), qbyte, PSR); + break; + default: + reason = STOP_INVOP; + break; + } + IAR[level] = PC; + continue; + break; + case 0xc0: + case 0xd0: + case 0xe0: + switch (opcode) { + case 0: /* BC: Branch on Condition */ + ARR[level] = AAR & AMASK; + if (condition(qbyte) == 1) { + IR = ARR[level]; + ARR[level] = PC & AMASK; + PC = IR; + } + break; + case 1: /* TIO: Test I/O */ + devno = (qbyte >> 4) & 0x0f; + devm = (qbyte >> 3) & 0x01; + devn = qbyte & 0x07; + op1 = dev_table[devno].routine(2, devm, devn, rbyte); + if (op1 & 0x01) { + ARR[level] = AAR & AMASK; + IR = ARR[level]; + ARR[level] = PC & AMASK; + PC = IR; + } + reason = (op1 >> 16) & 0xffff; + break; + case 2: /* LA: Load Address */ + switch (qbyte) { + case 1: + XR1 = AAR; + break; + case 2: + XR2 = AAR; + break; + default: + reason = STOP_INVQ; + break; + } + break; + default: + reason = STOP_INVOP; + break; + } /* switch (opcode) */ + IAR[level] = PC; + continue; + + default: + reason = STOP_INVOP; + break; +} /* switch (opaddr) */ + +} /* end while (reason == 0) */ + +/* Simulation halted */ + +saved_PC = PC; +return reason; +} + +/* On models 4-12, these memory functions could be inline, but + on a model 15 with ATU address mapping must be performed so + they are in functions here for future expansion. +*/ + +/* Fetch a byte from memory */ + +int32 GetMem(int32 addr) +{ + return M[addr] & 0xff; +} + +/* Place a byte in memory */ + +int32 PutMem(int32 addr, int32 data) +{ + M[addr] = data & 0xff; + return 0; +} + +/* Check the condition register against the qbyte and return 1 if true */ + +int32 condition(int32 qbyte) +{ + int32 r = 0, t, q; + t = (qbyte & 0xf0) >> 4; + q = qbyte & 0x0f; + if (qbyte & 0x80) { /* True if any condition tested = 1*/ + if (((qbyte & 0x3f) & PSR) != 0) r = 1; + } else { /* True if all conditions tested = 0 */ + if (((qbyte & 0x3f) & PSR) == 0) r = 1; + } + /* these bits reset by a test */ + if (qbyte & 0x10) + PSR &= 0xEF; /* Reset test false if used */ + if (qbyte & 0x08) + PSR &= 0xF7; /* Reset decimal overflow if tested */ + if (qbyte == 0x00) + r = 1; /* unconditional branch */ + if (qbyte == 0x80) + r = 0; /* force no branch */ + if (t >=0 && t < 8 && (q == 7 || q == 0xf)) + r = 0; /* no-op */ + if (t > 7 && t < 0x10 && (q == 7 || q == 0xf)) + r = 1; /* Force branch */ +return (r); +} +/* Given operand 1 and operand 2, compares the two and returns + the System/3 condition register bits appropriately, given the + condition register initial state in parameter 3 +*/ + +int32 compare(int32 byte1, int32 byte2, int32 cond) +{ + int32 r; + + r = cond & 0xF8; /* mask off all but unaffected bits 2,3,4 */ + if (byte1 == byte2) + r |= 0x01; /* set equal bit */ + if (byte1 < byte2) + r |= 0x02; /* set less-than bit */ + if (byte1 > byte2) + r |= 0x04; /* set greater than bit */ + return r; +} + +/*-------------------------------------------------------------------*/ +/* Add two zoned decimal operands */ +/* */ +/* Input: */ +/* addr1 Logical address of packed decimal storage operand 1 */ +/* len1 Length minus one of storage operand 1 (range 0-15) */ +/* addr2 Logical address of packed decimal storage operand 2 */ +/* len2 Length minus one of storage operand 2 (range 0-15) */ +/* Output: */ +/* The return value is the condition code: */ +/* 0=result zero, 1=result -ve, 2=result +ve, 3=overflow */ +/* */ +/* A program check may be generated if either logical address */ +/* causes an addressing, translation, or fetch protection */ +/* exception, or if either operand causes a data exception */ +/* because of invalid decimal digits or sign, or if the */ +/* first operand is store protected. Depending on the PSW */ +/* program mask, decimal overflow may cause a program check. */ +/*-------------------------------------------------------------------*/ +int32 add_zoned (int32 addr1, int32 len1, int32 addr2, int32 len2) +{ +int cc; /* Condition code */ +uint8 dec1[MAX_DECIMAL_DIGITS]; /* Work area for operand 1 */ +uint8 dec2[MAX_DECIMAL_DIGITS]; /* Work area for operand 2 */ +uint8 dec3[MAX_DECIMAL_DIGITS]; /* Work area for result */ +int count1, count2, count3; /* Significant digit counters*/ +int sign1, sign2, sign3; /* Sign of operands & result */ + + /* Load operands into work areas */ + load_decimal (addr1, len1, dec1, &count1, &sign1); + load_decimal (addr2, len2, dec2, &count2, &sign2); + + /* Add or subtract operand values */ + if (count2 == 0) + { + /* If second operand is zero then result is first operand */ + memcpy (dec3, dec1, MAX_DECIMAL_DIGITS); + count3 = count1; + sign3 = sign1; + } + else if (count1 == 0) + { + /* If first operand is zero then result is second operand */ + memcpy (dec3, dec2, MAX_DECIMAL_DIGITS); + count3 = count2; + sign3 = sign2; + } + else if (sign1 == sign2) + { + /* If signs are equal then add operands */ + add_decimal (dec1, dec2, dec3, &count3); + sign3 = sign1; + } + else + { + /* If signs are opposite then subtract operands */ + subtract_decimal (dec1, dec2, dec3, &count3, &sign3); + if (sign1 < 0) sign3 = -sign3; + } + + /* Set condition code */ + cc = (count3 == 0) ? 0 : (sign3 < 1) ? 1 : 2; + + /* Overflow if result exceeds first operand length */ + if (count3 > len1) + cc = 3; + + /* Set positive sign if result is zero */ + if (count3 == 0) + sign3 = 1; + + /* Store result into first operand location */ + store_decimal (addr1, len1, dec3, sign3); + + /* Return condition code */ + return cc; + +} /* end function add_packed */ + +/*-------------------------------------------------------------------*/ +/* Subtract two zoned decimal operands */ +/* */ +/* Input: */ +/* addr1 Logical address of packed decimal storage operand 1 */ +/* len1 Length minus one of storage operand 1 (range 0-15) */ +/* addr2 Logical address of packed decimal storage operand 2 */ +/* len2 Length minus one of storage operand 2 (range 0-15) */ +/* Output: */ +/* The return value is the condition code: */ +/* 0=result zero, 1=result -ve, 2=result +ve, 3=overflow */ +/* */ +/* A program check may be generated if either logical address */ +/* causes an addressing, translation, or fetch protection */ +/* exception, or if either operand causes a data exception */ +/* because of invalid decimal digits or sign, or if the */ +/* first operand is store protected. Depending on the PSW */ +/* program mask, decimal overflow may cause a program check. */ +/*-------------------------------------------------------------------*/ +int32 subtract_zoned (int32 addr1, int32 len1, int32 addr2, int32 len2) +{ +int cc; /* Condition code */ +uint8 dec1[MAX_DECIMAL_DIGITS]; /* Work area for operand 1 */ +uint8 dec2[MAX_DECIMAL_DIGITS]; /* Work area for operand 2 */ +uint8 dec3[MAX_DECIMAL_DIGITS]; /* Work area for result */ +int count1, count2, count3; /* Significant digit counters*/ +int sign1, sign2, sign3; /* Sign of operands & result */ + + /* Load operands into work areas */ + load_decimal (addr1, len1, dec1, &count1, &sign1); + load_decimal (addr2, len2, dec2, &count2, &sign2); + + /* Add or subtract operand values */ + if (count2 == 0) + { + /* If second operand is zero then result is first operand */ + memcpy (dec3, dec1, MAX_DECIMAL_DIGITS); + count3 = count1; + sign3 = sign1; + } + else if (count1 == 0) + { + /* If first operand is zero then result is -second operand */ + memcpy (dec3, dec2, MAX_DECIMAL_DIGITS); + count3 = count2; + sign3 = -sign2; + } + else if (sign1 != sign2) + { + /* If signs are opposite then add operands */ + add_decimal (dec1, dec2, dec3, &count3); + sign3 = sign1; + } + else + { + /* If signs are equal then subtract operands */ + subtract_decimal (dec1, dec2, dec3, &count3, &sign3); + if (sign1 < 0) sign3 = -sign3; + } + + /* Set condition code */ + cc = (count3 == 0) ? 0 : (sign3 < 1) ? 1 : 2; + + /* Overflow if result exceeds first operand length */ + if (count3 > len1) + cc = 3; + + /* Set positive sign if result is zero */ + if (count3 == 0) + sign3 = 1; + + /* Store result into first operand location */ + store_decimal (addr1, len1, dec3, sign3); + + /* Return condition code */ + return cc; + +} /* end function subtract_packed */ + + +/*-------------------------------------------------------------------*/ +/* Add two decimal byte strings as unsigned decimal numbers */ +/* */ +/* Input: */ +/* dec1 A 31-byte area containing the decimal digits of */ +/* the first operand. Each byte contains one decimal */ +/* digit in the low-order 4 bits of the byte. */ +/* dec2 A 31-byte area containing the decimal digits of */ +/* the second operand. Each byte contains one decimal */ +/* digit in the low-order 4 bits of the byte. */ +/* Output: */ +/* result Points to a 31-byte area to contain the result */ +/* digits. One decimal digit is placed in the low-order */ +/* 4 bits of each byte. */ +/* count Points to an integer to receive the number of */ +/* digits in the result excluding leading zeroes. */ +/* This field is set to zero if the result is all zero, */ +/* or to MAX_DECIMAL_DIGITS+1 if overflow occurred. */ +/*-------------------------------------------------------------------*/ +static void add_decimal (uint8 *dec1, uint8 *dec2, uint8 *result, int32 *count) +{ +int d; /* Decimal digit */ +int i; /* Array subscript */ +int n = 0; /* Significant digit counter */ +int carry = 0; /* Carry indicator */ + + /* Add digits from right to left */ + for (i = MAX_DECIMAL_DIGITS - 1; i >= 0; i--) + { + /* Add digits from first and second operands */ + d = dec1[i] + dec2[i] + carry; + + /* Check for carry into next digit */ + if (d > 9) { + d -= 10; + carry = 1; + } else { + carry = 0; + } + + /* Check for significant digit */ + if (d != 0) + n = MAX_DECIMAL_DIGITS - i; + + /* Store digit in result */ + result[i] = d; + + } /* end for */ + + /* Check for carry out of leftmost digit */ + if (carry) + n = MAX_DECIMAL_DIGITS + 1; + + /* Return significant digit counter */ + *count = n; + +} /* end function add_decimal */ + +/*-------------------------------------------------------------------*/ +/* Subtract two decimal byte strings as unsigned decimal numbers */ +/* */ +/* Input: */ +/* dec1 A 31-byte area containing the decimal digits of */ +/* the first operand. Each byte contains one decimal */ +/* digit in the low-order 4 bits of the byte. */ +/* dec2 A 31-byte area containing the decimal digits of */ +/* the second operand. Each byte contains one decimal */ +/* digit in the low-order 4 bits of the byte. */ +/* Output: */ +/* result Points to a 31-byte area to contain the result */ +/* digits. One decimal digit is placed in the low-order */ +/* 4 bits of each byte. */ +/* count Points to an integer to receive the number of */ +/* digits in the result excluding leading zeroes. */ +/* This field is set to zero if the result is all zero. */ +/* sign -1 if the result is negative (operand2 > operand1) */ +/* +1 if the result is positive (operand2 <= operand1) */ +/*-------------------------------------------------------------------*/ +static void subtract_decimal (uint8 *dec1, uint8 *dec2, uint8 *result, int *count, int *sign) +{ +int d; /* Decimal digit */ +int i; /* Array subscript */ +int n = 0; /* Significant digit counter */ +int borrow = 0; /* Borrow indicator */ +int rc; /* Return code */ +uint8 *higher; /* -> Higher value operand */ +uint8 *lower; /* -> Lower value operand */ + + /* Compare digits to find which operand has higher numeric value */ + rc = memcmp (dec1, dec2, MAX_DECIMAL_DIGITS); + + /* Return positive zero result if both operands are equal */ + if (rc == 0) { + memset (result, 0, MAX_DECIMAL_DIGITS); + *count = 0; + *sign = +1; + return; + } + + /* Point to higher and lower value operands and set sign */ + if (rc > 0) { + higher = dec1; + lower = dec2; + *sign = +1; + } else { + lower = dec1; + higher = dec2; + *sign = -1; + } + + /* Subtract digits from right to left */ + for (i = MAX_DECIMAL_DIGITS - 1; i >= 0; i--) + { + /* Subtract lower operand digit from higher operand digit */ + d = higher[i] - lower[i] - borrow; + + /* Check for borrow from next digit */ + if (d < 0) { + d += 10; + borrow = 1; + } else { + borrow = 0; + } + + /* Check for significant digit */ + if (d != 0) + n = MAX_DECIMAL_DIGITS - i; + + /* Store digit in result */ + result[i] = d; + + } /* end for */ + + /* Return significant digit counter */ + *count = n; + +} /* end function subtract_decimal */ + +/*-------------------------------------------------------------------*/ +/* Load a zoned decimal storage operand into a decimal byte string */ +/* */ +/* Input: */ +/* addr Logical address of zoned decimal storage operand */ +/* len Length minus one of storage operand (range 0-15) */ +/* Output: */ +/* result Points to a 31-byte area into which the decimal */ +/* digits are loaded. One decimal digit is loaded */ +/* into the low-order 4 bits of each byte, and the */ +/* result is padded to the left with high-order zeroes */ +/* if the storage operand contains less than 31 digits. */ +/* count Points to an integer to receive the number of */ +/* digits in the result excluding leading zeroes. */ +/* This field is set to zero if the result is all zero. */ +/* sign Points to an integer which will be set to -1 if a */ +/* negative sign was loaded from the operand, or +1 if */ +/* a positive sign was loaded from the operand. */ +/* */ +/* A program check may be generated if the logical address */ +/* causes an addressing, translation, or fetch protection */ +/* exception, or if the operand causes a data exception */ +/* because of invalid decimal digits or sign. */ +/*-------------------------------------------------------------------*/ +static void load_decimal (int32 addr, int32 len, uint8 *result, int32 *count, int32 *sign) +{ +int h; /* Hexadecimal digit */ +int i, j; /* Array subscripts */ +int n; /* Significant digit counter */ +int s; + + if ((GetMem(addr) & 0xf0) == 0xD0) + *sign = -1; + else + *sign = 1; + j = len; + for (i = MAX_DECIMAL_DIGITS; i > -1; i--) { + if (j) { + h = GetMem(addr) & 0x0f; + addr--; + j--; + } else { + h = 0; + } + result [i-1] = h; + if (h > 0) n = i; + } + *count = 32 - n; + +} /* end function load_decimal */ + +/*-------------------------------------------------------------------*/ +/* Store decimal byte string into packed decimal storage operand */ +/* */ +/* Input: */ +/* addr Logical address of packed decimal storage operand */ +/* len Length minus one of storage operand (range 0-15) */ +/* dec A 31-byte area containing the decimal digits to be */ +/* stored. Each byte contains one decimal digit in */ +/* the low-order 4 bits of the byte. */ +/* sign -1 if a negative sign is to be stored, or +1 if a */ +/* positive sign is to be stored. */ +/* */ +/* A program check may be generated if the logical address */ +/* causes an addressing, translation, or protection exception. */ +/*-------------------------------------------------------------------*/ +static void store_decimal (int32 addr, int32 len, uint8 *dec, int sign) +{ +int i, j, a; /* Array subscripts */ + + j = len; + a = addr; + for (i = MAX_DECIMAL_DIGITS; i > -1; i--) { + if (j) { + PutMem(a, (dec[i-1] | 0xf0)); + a--; + j--; + } else { + break; + } + } + if (sign == -1) { + PutMem(addr, (GetMem(addr) & 0x0f)); + PutMem(addr, (GetMem(addr) | 0xf0)); + } + +} /* end function store_decimal */ + +/* CPU Device Control */ + +int32 cpu (int32 op, int32 m, int32 n, int32 data) +{ + int32 iodata = 0; + + switch (op) { + case 0x00: /* Start IO */ + return SCPE_OK; + case 0x01: /* LIO */ + return SCPE_OK; + case 0x02: /* TIO */ + break; + case 0x03: /* SNS */ + /* SNS CPU gets the data switches */ + iodata = SR; + break; + case 0x04: /* APL */ + break; + default: + break; + } + return ((SCPE_OK << 16) | iodata); +} + + + +/* Null device */ + +int32 nulldev (int32 opcode, int32 m, int32 n, int32 data) +{ +if (opcode == 1) + return SCPE_OK; /* Ok to LIO unconfigured devices? */ +return STOP_INVDEV; +} + +/* Reset routine */ + +t_stat cpu_reset (DEVICE *dptr) +{ +int_req = 0; +level = 8; +sim_brk_types = sim_brk_dflt = SWMASK ('E'); +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] & 0xff; +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 & 0xff; +return SCPE_OK; +} + +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 & 07777) != 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; +} + +t_stat cpu_boot (int32 unitno) +{ +level = 8; +IAR[8] = 0; +return SCPE_OK; +} diff --git a/S3/s3_defs.h b/S3/s3_defs.h new file mode 100644 index 00000000..aab3b013 --- /dev/null +++ b/S3/s3_defs.h @@ -0,0 +1,97 @@ +/* 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"), + 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 "sim_defs.h" /* simulator defns */ + +/* Simulator stop codes */ + +#define STOP_RSRV 1 /* must be 1 */ +#define STOP_HALT 2 /* HALT */ +#define STOP_IBKPT 3 /* breakpoint */ +#define STOP_INVOP 4 /* program check - invalid op */ +#define STOP_INVQ 5 /* Prog check - invalid Q */ +#define STOP_INVADDR 6 /* Prog check - invalid addr */ +#define STOP_INVDEV 7 /* Prog check - invalid dev cmd */ +#define STOP_NOCD 8 /* ATTN card reader */ +#define RESET_INTERRUPT 77 /* special return from SIO */ + +/* Memory */ + +#define MAXMEMSIZE 65536 /* max memory size */ +#define AMASK (MAXMEMSIZE - 1) /* logical addr mask */ +#define PAMASK (MAXMEMSIZE - 1) /* physical addr mask */ +#define MEMSIZE (cpu_unit.capac) /* actual memory size */ + +#define MAX_DECIMAL_DIGITS 31 /* max size of a decimal number */ +#define CDR_WIDTH 80 /* Max card size */ +#define CDP_WIDTH 80 /* Punch width */ +#define LPT_WIDTH 132 +#define CCT_LNT 132 + +#define DSK_SECTSIZE 256 /* Sector length */ +#define DSK_CYLSIZE 256*48 /* Cylinder length */ + +/* I/O structure + + The I/O structure is tied together by dev_table, indexed by + the device number. Each entry in dev_table consists of + + level Interrupt level for device (0-7) + priority Priority for device (1-8) + routine IOT action routine +*/ + +struct ndev { + int32 level; /* interrupt level */ + int32 pri; /* Device priority */ + int32 (*routine)(); /* dispatch routine */ +}; + +/* Structure to define operation codes */ + +struct opdef { + char op[6]; /* Mnemonic for op */ + int32 opmask; /* Bits set on in opcode */ + int32 q; /* Qbyte */ + int32 form; /* Forms are: + 0 - 1-byte hex operand + 1 - 1-byte register addr, A-Addr + 2 - A-addr,B-addr,Qbyte + 3 - A-addr,Qbyte + 4 - da,m,n + 5 - da,m,n,cc + 6 - da,m,n,A-addr + 7 - 1-address implict Q + 8 - 2-address implict Q */ + int32 group; /* Group Code: + 0 - Command Format (0xFx) + 1 - 1-address A (0xx) + 2 - 2-address (0x<0,1,2,4,5,6,8,9,A>x) + 3 - 1-address B (0x<3,7,B>x) */ +}; + \ No newline at end of file diff --git a/S3/s3_disk.c b/S3/s3_disk.c new file mode 100644 index 00000000..573734fa --- /dev/null +++ b/S3/s3_disk.c @@ -0,0 +1,779 @@ +/* s3_disk.c: IBM 5444 Disk Drives + + 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"), + 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. + + r1 Removeable disk 1 + f1 Fixed disk 1 + r2 Removeable disk 2 + f2 Fixed disk 2 +*/ + +#include "s3_defs.h" +#include + +extern uint8 M[]; +extern int32 IAR[], level; +extern FILE *trace; +extern int32 debug_reg; +char dbuf[DSK_SECTSIZE]; /* Disk buffer */ +t_stat r1_svc (UNIT *uptr); +t_stat r1_boot (int32 unitno); +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_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_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_attach (UNIT *uptr, char *cptr); +t_stat f2_reset (DEVICE *dptr); + +char opstr[5][5] = { "SIO", "LIO", "TIO", "SNS", "APL" }; + +int32 DDAR[2]; /* Data address register */ +int32 DCAR[2]; /* Disk Control Address Register */ +int32 diskerr[2] = { 0, 0 }; /* Error status */ +int32 notrdy[2] = { 0, 0 }; /* Not ready error */ +int32 seekbusy[2] = { 0, 0 }; /* Drive busy flags */ +int32 seekhead[2] = { 0, 0 }; /* Disk head 0,1 */ +int32 found[2] = { 0, 0 }; /* Scan found bit */ +int32 RIDsect[2] = { 0, 0 }; /* for Read ID */ + +/* Disk data structures + + xy_dev CDR descriptor + xy_unit CDR unit descriptor + xy_reg CDR register list + + x = F or R + y = 1 or 2 +*/ + +UNIT r1_unit = { + UDATA (&r1_svc, UNIT_FIX+UNIT_ATTABLE, 0), 100 }; + +REG r1_reg[] = { + { FLDATA (NOTRDY, notrdy[0], 0) }, + { FLDATA (SEEK, seekbusy[0], 0) }, + { HRDATA (DAR, DDAR[0], 16) }, + { HRDATA (CAR, DCAR[0], 16) }, + { HRDATA (ERR, diskerr[0], 16) }, + { DRDATA (CYL, r1_unit.u3, 8) }, + { DRDATA (HEAD, seekhead[0], 8) }, + { DRDATA (POS, r1_unit.pos, 31), PV_LEFT }, + { DRDATA (TIME, r1_unit.wait, 24), PV_LEFT }, + { BRDATA (BUF, dbuf, 8, 8, 256) }, + { NULL } }; + +DEVICE r1_dev = { + "R1", &r1_unit, r1_reg, NULL, + 1, 10, 31, 1, 8, 7, + NULL, NULL, &r1_reset, + &r1_boot, &r1_attach, NULL }; + +UNIT f1_unit = { + UDATA (&f1_svc, UNIT_FIX+UNIT_ATTABLE, 0), 100 }; + +REG f1_reg[] = { + { FLDATA (NOTRDY, notrdy[0], 0) }, + { FLDATA (SEEK, seekbusy[0], 0) }, + { HRDATA (DAR, DDAR[0], 16) }, + { HRDATA (CAR, DCAR[0], 16) }, + { HRDATA (ERR, diskerr[0], 16) }, + { DRDATA (CYL, f1_unit.u3, 8) }, + { DRDATA (HEAD, seekhead[0], 8) }, + { DRDATA (POS, f1_unit.pos, 31), PV_LEFT }, + { DRDATA (TIME, f1_unit.wait, 24), PV_LEFT }, + { BRDATA (BUF, dbuf, 8, 8, 256) }, + { NULL } }; + +DEVICE f1_dev = { + "F1", &f1_unit, f1_reg, NULL, + 1, 10, 31, 1, 8, 7, + NULL, NULL, &f1_reset, + &f1_boot, &f1_attach, NULL }; + +UNIT r2_unit = { + UDATA (&r2_svc, UNIT_FIX+UNIT_ATTABLE, 0), 100 }; + +REG r2_reg[] = { + { FLDATA (NOTRDY, notrdy[1], 0) }, + { FLDATA (SEEK, seekbusy[1], 0) }, + { HRDATA (DAR, DDAR[1], 16) }, + { HRDATA (CAR, DCAR[1], 16) }, + { HRDATA (ERR, diskerr[1], 16) }, + { DRDATA (CYL, r2_unit.u3, 8) }, + { DRDATA (HEAD, seekhead[1], 8) }, + { DRDATA (POS, r2_unit.pos, 31), PV_LEFT }, + { DRDATA (TIME, r2_unit.wait, 24), PV_LEFT }, + { BRDATA (BUF, dbuf, 8, 8, 256) }, + { NULL } }; + +DEVICE r2_dev = { + "R2", &r2_unit, r2_reg, NULL, + 1, 10, 31, 1, 8, 7, + NULL, NULL, &r2_reset, + &r2_boot, &r2_attach, NULL }; + +UNIT f2_unit = { + UDATA (&f2_svc, UNIT_FIX+UNIT_ATTABLE, 0), 100 }; + +REG f2_reg[] = { + { FLDATA (NOTRDY, notrdy[1], 0) }, + { FLDATA (SEEK, seekbusy[1], 0) }, + { HRDATA (DAR, DDAR[1], 16) }, + { HRDATA (CAR, DCAR[1], 16) }, + { HRDATA (ERR, diskerr[1], 16) }, + { DRDATA (CYL, f2_unit.u3, 8) }, + { DRDATA (HEAD, seekhead[1], 8) }, + { DRDATA (POS, f2_unit.pos, 31), PV_LEFT }, + { DRDATA (TIME, f2_unit.wait, 24), PV_LEFT }, + { BRDATA (BUF, dbuf, 8, 8, 256) }, + { NULL } }; + +DEVICE f2_dev = { + "F2", &f2_unit, f2_reg, NULL, + 1, 10, 31, 1, 8, 7, + NULL, NULL, &f2_reset, + &f2_boot, &f2_attach, NULL }; + + +/* -------------------------------------------------------------------- */ + +/* 5444: master routines */ + +int32 dsk1 (int32 op, int32 m, int32 n, int32 data) +{ + int32 r; + + r = dsk(0, op, m, n, data); + return (r); +} + +int32 dsk2 (int32 op, int32 m, int32 n, int32 data) +{ + int32 r; + + r = dsk(1, op, m, n, data); + return (r); +} + +/* 5444: operational routine */ + +int32 dsk (int32 disk, int32 op, int32 m, int32 n, int32 data) +{ + int32 iodata, i, j, u, sect, nsects, addr, r, c, res; + int32 F, C, S, N, usave; + UNIT *uptr; + + u = m; + if (disk == 1) u += 2; + F = GetMem(DCAR[disk]+0); /* Flag bits */ + C = GetMem(DCAR[disk]+1); /* Cylinder */ + S = GetMem(DCAR[disk]+2); /* Sector */ + N = GetMem(DCAR[disk]+3); /* Number of sectors */ + switch (u) { + case 0: + uptr = r1_dev.units; + break; + case 1: + uptr = f1_dev.units; + break; + case 2: + uptr = r2_dev.units; + break; + case 3: + uptr = f2_dev.units; + break; + default: + break; + } + if (debug_reg & 0x02) + fprintf(trace, "==> %04X %s %01X,%d,%04X DAR=%04X CAR=%04X C=%02X, S=%02X, N=%02X\n", + IAR[level], + opstr[op], + m, n, data, + DDAR[disk], + DCAR[disk], + C, S, N); + + switch (op) { + + /* SIO 5444 */ + case 0: + if ((uptr->flags & UNIT_ATT) == 0) + return SCPE_UNATT; + diskerr[disk] = 0; /* SIO resets errors */ + found[disk] = 0; /* ... and found bit */ + iodata = 0; + switch (n) { + case 0x00: /* Seek */ + if (S & 0x80) + seekhead[disk] = 1; + else + seekhead[disk] = 0; + if (S & 1) { + uptr -> u3 += N; + } else { + uptr -> u3 -= N; + } + if (uptr -> u3 < 0) + uptr -> u3 = 0; + if (uptr -> u3 > 203) { + uptr -> u3 = 0; + diskerr[disk] |= 0x0100; + if (debug_reg & 0x02) + fprintf(trace, "==> Seek Past End of Disk\n"); + } + + /*sim_activate(uptr, uptr -> wait);*/ + sim_activate(uptr, 1); + + /* Seek arms are the same for both disks on a drive: + update the other arm */ + + usave = uptr -> u3; + if (u == 0) uptr = f1_dev.units; + if (u == 1) uptr = r1_dev.units; + if (u == 2) uptr = f2_dev.units; + if (u == 3) uptr = r2_dev.units; + uptr -> u3 = usave; + + seekbusy[disk] = 1; + iodata = SCPE_OK; + break; + + case 0x01: /* Read */ + switch (data) { + case 0: /* Read data */ + sect = (S >> 2) & 0x3F; + nsects = N + 1; + addr = DDAR[disk]; + + for (i = 0; i < nsects; i++) { + r = read_sector(uptr, dbuf, sect); + if (r != 1 || uptr->u3 != C) { + diskerr[disk] |= 0x0800; + break; + } + for (j = 0; j < DSK_SECTSIZE; j++) { + PutMem(addr, dbuf[j]); + addr++; + } + + if ((sect == 55) ) { /* HJS MODS */ + S = sect; + N = nsects - i - 2; + if (N > -1) diskerr[disk] |= 0x0020; /* end of cyl. */ + DDAR[disk] = addr & 0xFFFF; /* HJS mod */ + PutMem(DCAR[disk]+2, S << 2); + PutMem(DCAR[disk]+3, N); + sim_activate(uptr, 1); + iodata = SCPE_OK; + break; + } + + sect++; + S = sect - 1; + N = nsects - i - 2; + if (sect == 24) + sect = 32; + } + DDAR[disk] = addr & 0xFFFF; /* HJS mod */ + PutMem(DCAR[disk]+2, S << 2); + PutMem(DCAR[disk]+3, N); + /*sim_activate(uptr, uptr -> wait);*/ + sim_activate(uptr, 1); + iodata = SCPE_OK; + break; + case 1: /* Read ID */ + if (uptr -> u3 > 0 && uptr -> u3 < 4) + PutMem(DCAR[disk], 1); + else + PutMem(DCAR[disk], 0); + PutMem(DCAR[disk]+1, uptr -> u3); + PutMem(DCAR[disk]+2, RIDsect[disk]); + RIDsect[disk]++; + if (RIDsect[disk] > 23) + RIDsect[disk] = 32; + if (RIDsect[disk] > 55) + RIDsect[disk] = 0; + break; + case 2: /* Read Diagnostic */ + iodata = STOP_INVDEV; + break; + case 3: /* Verify */ + sect = (S >> 2) & 0x3F; + nsects = N + 1; + addr = DDAR[disk]; + for (i = 0; i < nsects; i++) { + r = read_sector(uptr, dbuf, sect); + if (r != 1 || uptr->u3 != C) { + diskerr[disk] |= 0x0800; + break; + } + if ((sect == 55) ) { /* HJS MODS */ + S = sect; + N = nsects - i - 2; + if (N > -1) diskerr[disk] |= 0x0020; /* end of cyl. */ + DDAR[disk] = addr & 0xFFFF; + PutMem(DCAR[disk]+2, S << 2); + PutMem(DCAR[disk]+3, N); + sim_activate(uptr, 1); + iodata = SCPE_OK; + break; + } + sect++; + S = sect - 1; + N = nsects - i - 2; + if (sect == 24) + sect = 32; + } + DDAR[disk] = addr & 0xFFFF; + PutMem(DCAR[disk]+2, S << 2); + PutMem(DCAR[disk]+3, N); + /*sim_activate(uptr, uptr -> wait);*/ + sim_activate(uptr, 1); + break; + default: + return STOP_INVDEV; + } + break; + case 0x02: /* Write */ + switch (data) { + case 0: /* Write Data */ + sect = (S >> 2) & 0x3F; + nsects = N + 1; + addr = DDAR[disk]; + for (i = 0; i < nsects; i++) { + for (j = 0; j < DSK_SECTSIZE; j++) { + dbuf[j] = GetMem(addr); + addr++; + } + r = write_sector(uptr, dbuf, sect); + if (r != 1 || uptr->u3 != C) { + diskerr[disk] |= 0x0400; + break; + } + if ((sect == 55) ) { /* HJS MODS */ + S = sect; + N = nsects - i - 2; + if (N > -1) diskerr[disk] |= 0x0020; /* end of cyl. */ + DDAR[disk] = addr & 0xFFFF; + PutMem(DCAR[disk]+2, S << 2); + PutMem(DCAR[disk]+3, N); + sim_activate(uptr, 1); + iodata = SCPE_OK; + break; + } + sect++; + S = sect - 1; + N = nsects - i - 2; + if (sect == 24) + sect = 32; + } + DDAR[disk] = addr & 0xFFFF; /* HJS mod */ + PutMem(DCAR[disk]+2, S << 2); + PutMem(DCAR[disk]+3, N); + /*sim_activate(uptr, uptr -> wait);*/ + sim_activate(uptr, 1); + break; + case 1: /* Write identifier */ + if (seekhead[disk] == 0) + S = 0; + else + S = 0x80; + N = 23; + + sect = (S >> 2) & 0x3F; + nsects = N + 1; + addr = DDAR[disk]; + for (i = 0; i < nsects; i++) { + for (j = 0; j < DSK_SECTSIZE; j++) { + dbuf[j] = GetMem(addr); + } + r = write_sector(uptr, dbuf, sect); + if (r != 1) { + diskerr[disk] |= 0x0400; + break; + } + if ((sect == 55) ) { + S = sect; + N = nsects - i - 2; + if (N > 0) diskerr[disk] |= 0x0020; + DDAR[disk] = addr & 0xFFFF; + PutMem(DCAR[disk]+2, S << 2); + PutMem(DCAR[disk]+3, N); + sim_activate(uptr, 1); + iodata = SCPE_OK; + break; + } + sect++; + S = sect - 1; + N = nsects - i - 2; + if (sect == 24) + sect = 32; + } + DDAR[disk] = addr & 0xFFFF; + PutMem(DCAR[disk]+2, S << 2); + PutMem(DCAR[disk]+3, N); + /*sim_activate(uptr, uptr -> wait);*/ + sim_activate(uptr, 1); + break; + default: + return STOP_INVDEV; + } + break; + case 0x03: /* Scan */ + sect = (S >> 2) & 0x3F; + nsects = N + 1; + addr = DDAR[disk]; + for (i = 0; i < nsects; i++) { + r = read_sector(uptr, dbuf, sect); + if (r != 1 || uptr->u3 != C) { + diskerr[disk] |= 0x0800; + break; + } + res = 0; + for (j = 0; j < DSK_SECTSIZE; j++) { + c = GetMem(addr); + if (j != 0xff) { + if (dbuf[i] < c) + res = 1; + if (dbuf[i] > c) + res = 3; + } + addr++; + } + if (res == 0) + found[disk] = 1; + if (res == data) + break; + if ((sect == 55) ) { /* HJS MODS */ + S = sect; + N = nsects - i - 2; + if (N > -1) diskerr[disk] |= 0x0020; /* end of cyl. */ + DDAR[disk] = addr & 0xFFFF; + PutMem(DCAR[disk]+2, S << 2); + PutMem(DCAR[disk]+3, N); + sim_activate(uptr, 1); + iodata = SCPE_OK; + break; + } + sect++; + S = sect - 1; + N = nsects - i - 2; + if (sect == 24) + sect = 32; + } + PutMem(DCAR[disk]+2, S << 2); + PutMem(DCAR[disk]+3, N); + /*sim_activate(uptr, uptr -> wait);*/ + sim_activate(uptr, 1); + break; + default: + return STOP_INVDEV; + } + return iodata; + + /* LIO 5444 */ + case 1: + if ((uptr->flags & UNIT_ATT) == 0) + return SCPE_UNATT; + switch (n) { + case 0x04: /* Data Addr */ + DDAR[disk] = data; + break; + case 0x06: /* Control Addr */ + DCAR[disk] = data; + break; + default: + return STOP_INVDEV; + } + return SCPE_OK; + case 2: /* TIO 5444 */ + if ((uptr->flags & UNIT_ATT) == 0) + return SCPE_UNATT << 16; + iodata = 0; + switch (n) { + case 0x00: /* Error */ + if (diskerr[disk] || notrdy[disk]) + iodata = 1; + if ((uptr -> flags & UNIT_ATT) == 0) + iodata = 1; + break; + case 0x02: /* Busy */ + if (sim_is_active (uptr)) + iodata = 1; + break; + case 0x04: + if (found[disk]) + iodata = 1; + break; + default: + return (STOP_INVDEV << 16); + } + return ((SCPE_OK << 16) | iodata); + + /* SNS 5444 */ + case 3: + if ((uptr->flags & UNIT_ATT) == 0) + return SCPE_UNATT << 16; + iodata = 0; + switch (n) { + case 0x01: + break; + case 0x02: + iodata = diskerr[disk]; + if (notrdy[disk]) + iodata |= 0x4000; + if ((uptr -> flags & UNIT_ATT) == 0) + iodata |= 0x4000; + if (seekbusy[disk]) + iodata |= 0x0010; + if (uptr -> u3 == 0) + iodata |= 0x0040; + break; + case 0x03: + iodata = 0; + break; + case 0x04: + iodata = DDAR[disk]; + break; + case 0x06: + iodata = DCAR[disk]; + break; + default: + return (STOP_INVDEV << 16); + } + iodata |= ((SCPE_OK << 16) & 0xffff0000); + return (iodata); + + /* APL 5444 */ + case 4: + if ((uptr->flags & UNIT_ATT) == 0) + return SCPE_UNATT << 16; + iodata = 0; + switch (n) { + case 0x00: /* Error */ + if (diskerr[disk] || notrdy[disk]) + iodata = 1; + if ((uptr -> flags & UNIT_ATT) == 0) + iodata = 1; + break; + case 0x02: /* Busy */ + if (sim_is_active (uptr)) + iodata = 1; + break; + default: + return (STOP_INVDEV << 16); + } + return ((SCPE_OK << 16) | iodata); + default: + break; + } +} + +/* Disk unit service. If a stacker select is active, copy to the + selected stacker. Otherwise, copy to the normal stacker. If the + unit is unattached, simply exit. +*/ + +t_stat r1_svc (UNIT *uptr) +{ +seekbusy[0] = 0; +return SCPE_OK; +} +t_stat f1_svc (UNIT *uptr) +{ +seekbusy[0] = 0; +return SCPE_OK; +} +t_stat r2_svc (UNIT *uptr) +{ +seekbusy[1] = 0; +return SCPE_OK; +} +t_stat f2_svc (UNIT *uptr) +{ +seekbusy[1] = 0; +return SCPE_OK; +} + + +/* Disk reset */ + +t_stat r1_reset (DEVICE *dptr) +{ +diskerr[0] = notrdy[0] = seekbusy[0] = 0; /* clear indicators */ +found[0] = 0; +sim_cancel (&r1_unit); /* clear event */ +r1_unit.u3 = 0; /* cylinder 0 */ +return SCPE_OK; +} +t_stat f1_reset (DEVICE *dptr) +{ +diskerr[0] = notrdy[0] = seekbusy[0] = 0; /* clear indicators */ +found[0] = 0; +sim_cancel (&f1_unit); /* clear event */ +f1_unit.u3 = 0; /* cylinder 0 */ +return SCPE_OK; +} +t_stat r2_reset (DEVICE *dptr) +{ +diskerr[1] = notrdy[1] = seekbusy[1] = 0; /* clear indicators */ +found[1] = 0; +sim_cancel (&r2_unit); /* clear event */ +r2_unit.u3 = 0; /* cylinder 0 */ +return SCPE_OK; +} +t_stat f2_reset (DEVICE *dptr) +{ +diskerr[1] = notrdy[1] = seekbusy[1] = 0; /* clear indicators */ +found[1] = 0; +sim_cancel (&f2_unit); /* clear event */ +f2_unit.u3 = 0; /* cylinder 0 */ +return SCPE_OK; +} + +/* Disk unit attach */ + +t_stat r1_attach (UNIT *uptr, char *cptr) +{ +diskerr[0] = notrdy[0] = seekbusy[0] = 0; /* clear status */ +found[0] = 0; +uptr -> u3 = 0; /* cylinder 0 */ +return attach_unit (uptr, cptr); +} +t_stat f1_attach (UNIT *uptr, char *cptr) +{ +diskerr[0] = notrdy[0] = seekbusy[0] = 0; /* clear status */ +found[0] = 0; +uptr -> u3 = 0; /* cylinder 0 */ +return attach_unit (uptr, cptr); +} +t_stat r2_attach (UNIT *uptr, char *cptr) +{ +diskerr[1] = notrdy[1] = seekbusy[1] = 0; /* clear status */ +found[1] = 0; +uptr -> u3 = 0; /* cylinder 0 */ +return attach_unit (uptr, cptr); +} +t_stat f2_attach (UNIT *uptr, char *cptr) +{ +diskerr[1] = notrdy[1] = seekbusy[1] = 0; /* clear status */ +found[1] = 0; +uptr -> u3 = 0; /* cylinder 0 */ +return attach_unit (uptr, cptr); +} + +/* Bootstrap routine */ + +t_stat r1_boot (int32 unitno) +{ +int i; +r1_unit.u3 = 0; +read_sector(r1_dev.units, dbuf, 0); +for (i = 0; i < 256; i++) { + M[i] = dbuf[i]; +} +return SCPE_OK; +} +t_stat f1_boot (int32 unitno) +{ +int i; +f1_unit.u3 = 0; +read_sector(f1_dev.units, dbuf, 0); +for (i = 0; i < 256; i++) { + M[i] = dbuf[i]; +} +return SCPE_OK; +} +t_stat r2_boot (int32 unitno) +{ +int i; +r2_unit.u3 = 0; +read_sector(r2_dev.units, dbuf, 0); +for (i = 0; i < 256; i++) { + M[i] = dbuf[i]; +} +return SCPE_OK; +} +t_stat f2_boot (int32 unitno) +{ +int i; +f2_unit.u3 = 0; +read_sector(f2_dev.units, dbuf, 0); +for (i = 0; i < 256; i++) { + M[i] = dbuf[i]; +} +return SCPE_OK; +} + + +/* Raw Disk Data In/Out */ + +int32 read_sector(UNIT *uptr, char *dbuf, int32 sect) +{ + static int32 rtn, realsect; + static long pos; + + /* calculate real sector no */ + if (sect > 23) + realsect = sect - 8; + else + realsect = sect; + /* physically read the sector */ + pos = DSK_CYLSIZE * uptr -> u3; + pos += DSK_SECTSIZE * realsect; + rtn = fseek(uptr -> fileref, pos, 0); + rtn = fread(dbuf, DSK_SECTSIZE, 1, uptr -> fileref); + return (rtn); +} + +int32 write_sector(UNIT *uptr, char *dbuf, int32 sect) +{ + static int32 rtn, realsect; + static long pos; + + /* calculate real sector no */ + if (sect > 23) + realsect = sect - 8; + else + realsect = sect; + if (uptr -> u3 == 0 && realsect == 32) + rtn = 0; + /* physically write the sector */ + pos = DSK_CYLSIZE * uptr -> u3; + pos += DSK_SECTSIZE * realsect; + rtn = fseek(uptr -> fileref, pos, 0); + rtn = fwrite(dbuf, DSK_SECTSIZE, 1, uptr -> fileref); + return (rtn); +} diff --git a/S3/s3_lp.c b/S3/s3_lp.c new file mode 100644 index 00000000..859b5015 --- /dev/null +++ b/S3/s3_lp.c @@ -0,0 +1,349 @@ +/* s3_lp.c: IBM 1403 line printer simulator + + 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"), + 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 1403 line printer + +*/ + +#include "s3_defs.h" + +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); +extern unsigned char ebcdic_to_ascii[256]; + +#define UNIT_V_PCHAIN (UNIT_V_UF + 0) +#define UNIT_M_PCHAIN 03 +#define M_UCS 00 /* Universal */ +#define M_PCF 00 /* full */ +#define M_PCA 01 /* business */ +#define M_PCH 02 /* Fortran */ +#define UNIT_PCHAIN (UNIT_M_PCHAIN << UNIT_V_PCHAIN) +#define UCS (M_UCS << UNIT_V_PCHAIN) +#define PCF (M_PCF << UNIT_V_PCHAIN) +#define PCA (M_PCA << UNIT_V_PCHAIN) +#define PCH (M_PCH << UNIT_V_PCHAIN) +#define GET_PCHAIN(x) (((x) >> UNIT_V_PCHAIN) & UNIT_M_PCHAIN) +#define CHP(ch,val) ((val) & (1 << (ch))) + +int32 LPDAR; /* Data Address */ +int32 LPFLR; /* Forms Length */ +int32 LPIAR; /* Image address */ +int32 linectr; /* current line # */ +int32 lpterror = 0; +int32 CC9 = 0; +int32 CC12 = 0; + +/* LPT data structures + + lpt_dev LPT device descriptor + lpt_unit LPT unit descriptor + lpt_reg LPT register list +*/ + +UNIT lpt_unit = { + UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) }; + +REG lpt_reg[] = { + { FLDATA (ERR, lpterror, 0) }, + { HRDATA (LPDAR, LPDAR, 16) }, + { HRDATA (LPFLR, LPFLR, 8) }, + { HRDATA (LPIAR, LPIAR, 16) }, + { DRDATA (LINECT, linectr, 8) }, + { DRDATA (POS, lpt_unit.pos, 31), PV_LEFT }, + { BRDATA (CCT, cct, 8, 32, CCT_LNT) }, + { 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[] = { + { UNIT_PCHAIN, UCS, "UCS", "UCS", NULL }, + { UNIT_PCHAIN, PCA, "A chain", "PCA", NULL }, + { UNIT_PCHAIN, PCH, "H chain", "PCH", NULL }, + { 0 } }; + +DEVICE lpt_dev = { + "LPT", &lpt_unit, lpt_reg, lpt_mod, + 1, 10, 31, 1, 8, 7, + NULL, NULL, &lpt_reset, + NULL, NULL, NULL }; + + +/* -------------------------------------------------------------------- */ + +/* Printer: master routine */ + +int32 lpt (int32 op, int32 m, int32 n, int32 data) +{ + int32 iodata, c, ec, ac; + switch (op) { + case 0: /* SIO 1403 */ + iodata = 0; + printf("\0"); + switch (n) { + case 0x00: /* Spacing only */ + if (data > 0 && data < 4) + iodata = carriage_control(2, data); + break; + case 0x02: /* Print & space */ + iodata = write_line(0, 0); + if (data > 3) data = 0; + if (iodata == SCPE_OK) + iodata = carriage_control(2, data); + break; + case 0x04: /* Skip only */ + iodata = carriage_control(4, data); + break; + case 0x06: /* Print and skip */ + iodata = write_line(0, 0); + if (iodata == SCPE_OK) + iodata = carriage_control(4, data); + break; + default: + return STOP_INVDEV; + } + return iodata; + case 1: /* LIO 1403 */ + switch (n) { + case 0x00: /* LPFLR */ + LPFLR = (data >> 8) & 0xff; + break; + case 0x04: + LPIAR = data & 0xffff; + break; + case 0x06: + LPDAR = data & 0xffff; + break; + default: + return STOP_INVDEV; + } + return SCPE_OK; + case 2: /* TIO 1403 */ + iodata = 0; + switch (n) { + case 0x00: /* Not ready/check */ + if (lpterror) + iodata = 1; + if ((lpt_unit.flags & UNIT_ATT) == 0) + iodata = 1; + break; + case 0x02: /* Buffer Busy */ + iodata = 0; + break; + case 0x04: /* Carriage Busy */ + iodata = 0; + break; + case 0x06: /* Printer busy */ + iodata = 0; + break; + default: + return (STOP_INVDEV << 16); + } + return ((SCPE_OK << 16) | iodata); + case 3: /* SNS 1403 */ + switch (n) { + case 0x00: /* Line count */ + iodata = (linectr << 8); + break; + case 0x02: /* Timing data */ + iodata = 0; + break; + case 0x03: /* Check data */ + iodata = 0; + break; + case 0x04: /* LPIAR */ + iodata = LPIAR; + break; + case 0x06: /* LPDAR */ + iodata = LPDAR; + break; + default: + return (STOP_INVDEV << 16); + } + return ((SCPE_OK << 16) | iodata); + case 4: /* APL 1403 */ + iodata = 0; + return ((SCPE_OK << 16) | iodata); + default: + break; + } +} + + +/* Print routine + + Modifiers have been checked by the caller + S = suppress automatic newline +*/ + +t_stat write_line (int32 ilnt, int32 mod) +{ +int32 i, t, lc, sup; +char *pch; +static char lbuf[LPT_WIDTH + 1]; /* + null */ + +if ((lpt_unit.flags & UNIT_ATT) == 0) + return SCPE_UNATT; + +lpterror = 0; +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 */ + 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 { fputc ('\r', lpt_unit.fileref); /* sup -> overprint */ + lpt_unit.pos = ftell (lpt_unit.fileref); } /* update position */ +lines = lflag = 0; /* clear cc action */ +if (ferror (lpt_unit.fileref)) { /* error? */ + perror ("Line printer I/O error"); + clearerr (lpt_unit.fileref); + lpterror = 1; } +return SCPE_OK; +} + +/* Carriage control routine + + Parameters: + action = 00, skip to channel now + = 01, space lines after + = 02, space lines now + = 03, skip to channel after + = 04, skip to line number + mod = number of lines or channel number or line number +*/ + +t_stat carriage_control (int32 action, int32 mod) +{ +int32 i; + +if ((lpt_unit.flags & UNIT_ATT) == 0) + return SCPE_UNATT; + +switch (action) { +case 0: /* to channel now */ + if ((mod == 0) || (mod > 12) || CHP (mod, cct[cctptr])) return SCPE_OK; + for (i = 1; i < cctlnt + 1; i++) { /* sweep thru cct */ + if (CHP (mod, cct[(cctptr + i) % cctlnt])) + return space (i, TRUE); } + return STOP_INVDEV; /* runaway channel */ +case 1: /* space after */ + if (mod <= 3) { + lines = mod; /* save # lines */ + lflag = FALSE; /* flag spacing */ + CC9 = CC12 = 0; } + return SCPE_OK; +case 2: /* space now */ + if (mod <= 3) return space (mod, FALSE); + return SCPE_OK; +case 3: /* to channel after */ + if ((mod == 0) || (mod > 12)) return SCPE_OK; /* check channel */ + CC9 = CC12 = 0; + for (i = 1; i < cctlnt + 1; i++) { /* sweep thru cct */ + if (CHP (mod, cct[(cctptr + i) % cctlnt])) { + lines = i; /* save # lines */ + lflag = TRUE; /* flag skipping */ + return SCPE_OK; } + return STOP_INVDEV; +case 4: /* To line # */ + if (mod < 2) { + fputs ("\n\f", lpt_unit.fileref); /* nl, ff */ + linectr = 1; + } else { + if (mod <= linectr) { + fputs ("\n\f", lpt_unit.fileref); + linectr = 1; + } + while (1) { + if (linectr == mod) + break; + space(1, 0); + } + } + return SCPE_OK; } +} +return SCPE_OK; +} + +/* Space routine - space or skip n lines + + Inputs: + count = number of lines to space or skip + sflag = skip (TRUE) or space (FALSE) +*/ + +t_stat space (int32 count, int32 sflag) +{ +int32 i; + +if ((lpt_unit.flags & UNIT_ATT) == 0) return SCPE_UNATT; +cctptr = (cctptr + count) % cctlnt; /* adv cct, mod lnt */ +if (sflag && CHP (0, cct[cctptr])) { /* skip, top of form? */ + fputs ("\n\f", lpt_unit.fileref); /* nl, ff */ + linectr = 1; +} +else { for (i = 0; i < count; i++) fputc ('\n', lpt_unit.fileref); } +lpt_unit.pos = ftell (lpt_unit.fileref); /* update position */ +CC9 = CHP (9, cct[cctptr]) != 0; /* set indicators */ +CC12 = CHP (12, cct[cctptr]) != 0; +linectr += count; +if (linectr > LPFLR) + linectr -= LPFLR; +return SCPE_OK; +} + +/* Reset routine */ + +t_stat lpt_reset (DEVICE *dptr) +{ +cctptr = 0; /* clear cct ptr */ +lines = linectr = lflag = 0; /* no cc action */ +lpterror = 0; +return SCPE_OK; +} + +/* Attach routine */ + +t_stat lpt_attach (UNIT *uptr, char *cptr) +{ +cctptr = 0; /* clear cct ptr */ +lines = 0; /* no cc action */ +lpterror = 0; +linectr = 0; +return attach_unit (uptr, cptr); +} diff --git a/S3/s3_pkb.c b/S3/s3_pkb.c new file mode 100644 index 00000000..2dc156ea --- /dev/null +++ b/S3/s3_pkb.c @@ -0,0 +1,302 @@ +/* s3_pkb.c: System/3 5471 console terminal simulator + + 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. + + pkb 5471 printer/keyboard +*/ + +#include "s3_defs.h" + +extern int32 int_req, dev_busy, dev_done, dev_disable; +t_stat pkb_svc (UNIT *uptr); +t_stat pkb_reset (DEVICE *dptr); +extern t_stat sim_poll_kbd (void); +extern t_stat sim_putchar (int32 out); +extern int32 IAR[], level; +extern int32 debug_reg; + +/* 5471 data structures + + pkb_dev TTI device descriptor + pkb_unit TTI unit descriptor + pkb_reg TTI register list + pkb_mod TTI/TTO modifiers list +*/ + +/* Flag bits : (kept in pkb_unit.u3) */ + +#define PRT_INTREQ 0x800 /* Printer interrupt pending */ +#define KBD_INTREQ 0x400 /* Request key interrupt pending */ +#define KBD_INTEND 0x200 /* End or cancel key interrupt pending */ +#define KBD_INTKEY 0x100 /* Return or other key interrupt pending */ +#define KBD_REQLIGHT 0x20 /* Request Pending Indicator (light on/off) */ +#define KBD_PROLIGHT 0x10 /* Proceed indicator (light on/off) */ +#define KBD_REQINT 0x04 /* Req key interrupts enabled */ +#define KBD_KEYINT 0x02 /* Other key interrupts enabled */ +#define PRT_PRTINT 0x01 /* Printer interrupts enabled */ + +/* Keys mapped to 5471 functions */ + +int32 key_req = 0x01; /* Request key: ^A */ +int32 key_rtn = 0x12; /* Return key: ^R */ +int32 key_can = 0x1B; /* Cancel key: ESC */ +int32 key_end = 0x0d; /* End key - CR */ + +UNIT pkb_unit = { UDATA (&pkb_svc, 0, 0), KBD_POLL_WAIT }; + +REG pkb_reg[] = { + { HRDATA (FLAG, pkb_unit.u3, 16) }, + { HRDATA (IBUF, pkb_unit.buf, 8) }, + { HRDATA (OBUF, pkb_unit.u4, 8) }, + { HRDATA (REQKEY, key_req, 8) }, + { HRDATA (RTNKEY, key_rtn, 8) }, + { HRDATA (CANKEY, key_can, 8) }, + { HRDATA (ENDKEY, key_end, 8) }, + { DRDATA (POS, pkb_unit.pos, 31), PV_LEFT }, + { DRDATA (TIME, pkb_unit.wait, 24), REG_NZ + PV_LEFT }, + { NULL } }; + +MTAB pkb_mod[] = { + { 0 } }; + +DEVICE pkb_dev = { + "PKB", &pkb_unit, pkb_reg, pkb_mod, + 1, 10, 31, 1, 8, 8, + NULL, NULL, &pkb_reset, + NULL, NULL, NULL }; + + +/*-------------------------------------------------------------------*/ +/* EBCDIC to ASCII translate table */ +/*-------------------------------------------------------------------*/ +unsigned char ebcdic_to_ascii[] = { +"\x00\x01\x02\x03\xA6\x09\xA7\x7F\xA9\xB0\xB1\x0B\x0C\x0D\x0E\x0F" +"\x10\x11\x12\x13\xB2\xB4\x08\xB7\x18\x19\x1A\xB8\xBA\x1D\xBB\x1F" +"\xBD\xC0\x1C\xC1\xC2\x0A\x17\x1B\xC3\xC4\xC5\xC6\xC7\x05\x06\x07" +"\xC8\xC9\x16\xCB\xCC\x1E\xCD\x04\xCE\xD0\xD1\xD2\x14\x15\xD3\xFC" +"\x20\xD4\x83\x84\x85\xA0\xD5\x86\x87\xA4\xD6\x2E\x3C\x28\x2B\xD7" +"\x26\x82\x88\x89\x8A\xA1\x8C\x8B\x8D\xD8\x21\x24\x2A\x29\x3B\x5E" +"\x2D\x2F\xD9\x8E\xDB\xDC\xDD\x8F\x80\xA5\x7C\x2C\x25\x5F\x3E\x3F" +"\xDE\x90\xDF\xE0\xE2\xE3\xE4\xE5\xE6\x60\x3A\x23\x40\x27\x3D\x22" +"\xE7\x61\x62\x63\x64\x65\x66\x67\x68\x69\xAE\xAF\xE8\xE9\xEA\xEC" +"\xF0\x6A\x6B\x6C\x6D\x6E\x6F\x70\x71\x72\xF1\xF2\x91\xF3\x92\xF4" +"\xF5\x7E\x73\x74\x75\x76\x77\x78\x79\x7A\xAD\xA8\xF6\x5B\xF7\xF8" +"\x9B\x9C\x9D\x9E\x9F\xB5\xB6\xAC\xAB\xB9\xAA\xB3\xBC\x5D\xBE\xBF" +"\x7B\x41\x42\x43\x44\x45\x46\x47\x48\x49\xCA\x93\x94\x95\xA2\xCF" +"\x7D\x4A\x4B\x4C\x4D\x4E\x4F\x50\x51\x52\xDA\x96\x81\x97\xA3\x98" +"\x5C\xE1\x53\x54\x55\x56\x57\x58\x59\x5A\xFD\xEB\x99\xED\xEE\xEF" +"\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\xFE\xFB\x9A\xF9\xFA\xFF" +}; + +/*-------------------------------------------------------------------*/ +/* ASCII to EBCDIC translate table */ +/*-------------------------------------------------------------------*/ +unsigned char ascii_to_ebcdic[] = { +"\x00\x01\x02\x03\x37\x2D\x2E\x2F\x16\x05\x25\x0B\x0C\x0D\x0E\x0F" +"\x10\x11\x12\x13\x3C\x3D\x32\x26\x18\x19\x1A\x27\x22\x1D\x35\x1F" +"\x40\x5A\x7F\x7B\x5B\x6C\x50\x7D\x4D\x5D\x5C\x4E\x6B\x60\x4B\x61" +"\xF0\xF1\xF2\xF3\xF4\xF5\xF6\xF7\xF8\xF9\x7A\x5E\x4C\x7E\x6E\x6F" +"\x7C\xC1\xC2\xC3\xC4\xC5\xC6\xC7\xC8\xC9\xD1\xD2\xD3\xD4\xD5\xD6" +"\xD7\xD8\xD9\xE2\xE3\xE4\xE5\xE6\xE7\xE8\xE9\xAD\xE0\xBD\x5F\x6D" +"\x79\x81\x82\x83\x84\x85\x86\x87\x88\x89\x91\x92\x93\x94\x95\x96" +"\x97\x98\x99\xA2\xA3\xA4\xA5\xA6\xA7\xA8\xA9\xC0\x6A\xD0\xA1\x07" +"\x68\xDC\x51\x42\x43\x44\x47\x48\x52\x53\x54\x57\x56\x58\x63\x67" +"\x71\x9C\x9E\xCB\xCC\xCD\xDB\xDD\xDF\xEC\xFC\xB0\xB1\xB2\xB3\xB4" +"\x45\x55\xCE\xDE\x49\x69\x04\x06\xAB\x08\xBA\xB8\xB7\xAA\x8A\x8B" +"\x09\x0A\x14\xBB\x15\xB5\xB6\x17\x1B\xB9\x1C\x1E\xBC\x20\xBE\xBF" +"\x21\x23\x24\x28\x29\x2A\x2B\x2C\x30\x31\xCA\x33\x34\x36\x38\xCF" +"\x39\x3A\x3B\x3E\x41\x46\x4A\x4F\x59\x62\xDA\x64\x65\x66\x70\x72" +"\x73\xE1\x74\x75\x76\x77\x78\x80\x8C\x8D\x8E\xEB\x8F\xED\xEE\xEF" +"\x90\x9A\x9B\x9D\x9F\xA0\xAC\xAE\xAF\xFD\xFE\xFB\x3F\xEA\xFA\xFF" +}; + +/* -------------------------------------------------------------------- */ + +/* Console Input: master routine */ + +int32 pkb (int32 op, int32 m, int32 n, int32 data) +{ + int32 iodata= 0, c, ec, ac; + switch (op) { + case 0: /* SIO 5471 */ + if (n != 0) + return STOP_INVDEV; + /*printf("%04X SIO %d,%d,%02X\n\r", IAR[level]-4, m, n, data);*/ + if (m == 0) { /* Keyboard */ + pkb_unit.u3 &= 0xFC1; + pkb_unit.u3 |= data; + if (data & 0x01) { + pkb_unit.u3 &= ~KBD_INTREQ; + pkb_unit.u3 &= ~KBD_INTKEY; + pkb_unit.u3 &= ~KBD_INTEND; + return RESET_INTERRUPT; + } + } else { /* Printer */ + if (data & 0x80) { /* start print bit */ + if (debug_reg & 0x80) + return STOP_IBKPT; + ec = pkb_unit.u4 & 0xff; + ac = ebcdic_to_ascii[ec]; + sim_putchar(ac); + pkb_unit.u3 |= PRT_INTREQ; + } + if (data & 0x40) { /* Carr. Return */ + sim_putchar('\n'); + sim_putchar('\r'); + pkb_unit.u3 |= PRT_INTREQ; + } + pkb_unit.u3 &= 0xFFe; + if (data & 0x04) /* Print interrupt flag */ + pkb_unit.u3 |= PRT_PRTINT; + if (data & 0x01) { /* Reset Interrupt */ + if (level < 8) { + if (!(data & 0x80)) + pkb_unit.u3 &= ~PRT_INTREQ; + return RESET_INTERRUPT; + } + } + } + return SCPE_OK; + case 1: /* LIO 5471 */ + if (n != 0) + return STOP_INVDEV; + if (m != 1) + return STOP_INVDEV; + pkb_unit.u4 = (data >> 8) & 0xff; + return SCPE_OK; + break; + case 2: /* TIO 5471 */ + return STOP_INVDEV; + case 3: /* SNS 5471 */ + if (n != 1 && n != 3) + return (STOP_INVDEV << 16); + if (m == 0) { /* Keyboard data */ + if (n == 1) { /* Sense bytes 0 & 1 */ + iodata = (pkb_unit.buf << 8) & 0xff00; + if (pkb_unit.u3 & KBD_INTREQ) + iodata |= 0x80; + if (pkb_unit.u3 & KBD_INTEND) + iodata |= 0x40; + if (pkb_unit.u3 & KBD_INTKEY) + iodata |= 0x08; + if (pkb_unit.buf == 0x12) /* Return key */ + iodata |= 0x04; + if (pkb_unit.buf == 0x03) /* Cancel key */ + iodata |= 0x20; + if (pkb_unit.buf == 0x0d) /* End key */ + iodata |= 0x10; + iodata |= ((SCPE_OK << 16) & 0xffff0000); + } else { /* Sense bytes 2 & 3 */ + iodata = 0; /* Manual says CE use only */ + } + } else { /* Printer Data */ + if (n == 1) { /* Sense bytes 0 & 1 */ + iodata = 0; + if (pkb_unit.u3 & PRT_INTREQ) + iodata |= 0x80; + } else { + iodata = 0; /* CE use only */ + } + } + iodata |= ((SCPE_OK << 16) & 0xffff0000); + return (iodata); + case 4: /* APL 5471 */ + return STOP_INVDEV; + default: + break; + } +} + +/* Unit service */ + +t_stat pkb_svc (UNIT *uptr) +{ +int32 temp, ac, ec; + +sim_activate (&pkb_unit, pkb_unit.wait); /* continue poll */ + +if (pkb_unit.u3 & PRT_INTREQ) { /* Printer Interrupt */ + int_req |= 2; + return SCPE_OK; +} + +/* Keyboard : handle input */ + +if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */ + +ac = temp & 0x7f; /* placed type ASCII char in ac */ +if (pkb_unit.u3 & KBD_REQINT) { + if (ac == key_req) { /* Request Key */ + pkb_unit.u3 |= KBD_INTREQ; + int_req |= 2; + return SCPE_OK; + } +} +if (islower(ac)) + ac = toupper(ac); +ec = ascii_to_ebcdic[ac]; /* Translate */ +pkb_unit.buf = ec; /* put in buf */ +pkb_unit.pos = pkb_unit.pos + 1; +if (ac == key_end) { /* End key */ + if (pkb_unit.u3 & KBD_KEYINT) { + pkb_unit.u3 |= KBD_INTEND; + pkb_unit.buf = 0x0d; + int_req |= 2; + } + return SCPE_OK; +} +if (ac == key_can) { /* Cancel key */ + if (pkb_unit.u3 & KBD_KEYINT) { + pkb_unit.u3 |= KBD_INTEND; + pkb_unit.buf = 0x03; + int_req |= 2; + } + return SCPE_OK; +} +if (ac == key_rtn) { /* Return key */ + if (pkb_unit.u3 & KBD_KEYINT) { + pkb_unit.u3 |= KBD_INTKEY; + pkb_unit.buf = 0x12; + int_req |= 2; + } + return SCPE_OK; +} +if (pkb_unit.u3 & KBD_KEYINT) { /* Key interupts enabled ? */ + int_req |= 2; /* Device 1 Interrupt! */ + pkb_unit.u3 |= KBD_INTKEY; /* Set pending flag */ +} +return SCPE_OK; +} + +/* Reset routine */ + +t_stat pkb_reset (DEVICE *dptr) +{ +pkb_unit.buf = 0; +int_req = int_req & ~0x02; /* reset interrupt */ +sim_activate (&pkb_unit, pkb_unit.wait); /* activate unit */ +return SCPE_OK; +} + +t_stat pkb_setmod (UNIT *uptr, int32 value) +{ +return SCPE_OK; +} + diff --git a/S3/s3_sys.c b/S3/s3_sys.c new file mode 100644 index 00000000..fdbb277e --- /dev/null +++ b/S3/s3_sys.c @@ -0,0 +1,925 @@ +/* ibms3_sys.c: IBM System/3 system interface + + (C) Copyright 2001 by Charles E. Owen + Commercial use prohibited +*/ + + +#include + +#include "s3_defs.h" + + +extern DEVICE cpu_dev; +extern DEVICE pkb_dev; +extern DEVICE cdr_dev; +extern DEVICE cdp_dev; +extern DEVICE stack_dev; +extern DEVICE lpt_dev; +extern DEVICE r1_dev; +extern DEVICE f1_dev; +extern DEVICE r2_dev; +extern DEVICE f2_dev; +extern UNIT cpu_unit; +extern REG cpu_reg[]; +extern unsigned char M[]; +extern int32 saved_PC, IAR[]; +extern char ebcdic_to_ascii[256]; +extern char *get_glyph (char *cptr, char *gbuf, char term); +extern unsigned int32 get_uint (char *cptr, int32 radix, unsigned int32 max, + int32 *status); +char *parse_addr(char *cptr, char *gbuf, int32 *addr, int32 *addrtype); + +/* SCP data structures + + sim_name simulator name string + sim_PC pointer to saved PC register descriptor + sim_emax number of words needed for examine + sim_devices array of pointers to simulated devices + sim_stop_messages array of pointers to stop messages + sim_load binary loader +*/ + +char sim_name[] = "System/3"; + +REG *sim_PC = &cpu_reg[0]; + +int32 sim_emax = 6; + +DEVICE *sim_devices[] = { &cpu_dev, + &pkb_dev, + &cdr_dev, + &cdp_dev, + &stack_dev, + &lpt_dev, + &r1_dev, + &f1_dev, + &r2_dev, + &f2_dev, + NULL }; + +const char *sim_stop_messages[] = { + "Unknown error", + "Unknown I/O Instruction", + "HALT instruction", + "Breakpoint", + "Invalid Opcode", + "Invalid Qbyte", + "Invalid Address", + "Invalid Device Command", + "ATTN Card Reader" +}; + +/* This is the opcode master defintion table. Each possible opcode mnemonic + is defined here, with enough information to translate to and from + symbolic to binary machine code. + First field is the opcode's mnemonic + Second field is the hex of the right nybble of the binary opcode + Third field is the Q code for those with implicit Q codes + Fourth field is the symbolic format of the operands: + 0 - (Q-byte),(R-byte) + 1 - (Q-byte),(Address) + 2 - (Address),(Address),(Qbyte) + 3 - (Address),(Qbyte) + 4 - (device),(modifier),(function) -- these 3 make up qbyte + 5 - (device),(modifier),(function),(control) + 6 - (device),(modifier),(function),(Address) + 7 - (displacement) -- Q byte is implicit in opcode + 8 - (address) -- Qbyte is implicit in opcode + 9 - (Address),(Address) -- Qbyte is implicit in opcode + Fifth Field is the group number: + 0 - Command Group (left op nybble is F) + 1 - One Address Operations A (Left Nybble C, D, or E) + 2 - Two Address Operations (Left Nybble 0,1,2,4,5,6,8,9, or A) + 3 - One Address Operations B (left Nybble 3, 7, or B) + + There is duplication in this table -- IBM defines different opcodes + that resolve to the same binary machine instruction -- e.g. JE and + JZ. On input this is no problem, on output, define the one you + want to appear first, the second will never appear on output. +*/ + +int32 nopcode = 75; +struct opdef opcode[75] = { + "HPL", 0x00,0,0,0, /* Halt Program Level */ + "A", 0x06,0,1,3, /* Add to Register: A R,AADD */ + "ST", 0x04,0,1,3, /* Store Register */ + "L", 0x05,0,1,3, /* Load Register */ + "LA", 0x02,0,1,1, /* Load Address */ + "ZAZ", 0x04,0,2,2, /* Zero and Add Zoned */ + "AZ", 0x06,0,2,2, /* Add Zoned Decimal */ + "SZ", 0x07,0,2,2, /* Subtract Zoned Decimal */ + "ALC", 0x0E,0,2,2, /* Add Logical: ALC BADD,AADD,LEN */ + "SLC", 0x0F,0,2,2, /* Sub Logical: SLC BADD,AADD,LEN */ + "MVC", 0x0C,0,2,2, /* Move Chars MVX BADD,AADD,LEN */ + "ED", 0x0A,0,2,2, /* Edit: ED BADD,AADD,LEN */ + "ITC", 0x0B,0,2,2, /* Insert Chars: ITC BADD,AADD,LEN */ + "CLC", 0x0D,0,2,2, /* Compare Logical: CLC BADD,AADD,LEN */ + "MVI", 0x0C,0,3,3, /* Move Immediate */ + "SBN", 0x0A,0,3,3, /* Set Bits On */ + "SBF", 0x0B,0,3,3, /* Set Bits Off */ + "CLI", 0x0D,0,3,3, /* Compare Immediate */ + "TBN", 0x08,0,3,3, /* Test Bits On */ + "TBF", 0x09,0,3,3, /* Test Bits Off */ + "APL", 0x01,0,4,0, /* Advance Program Level */ + "SIO", 0x03,0,5,0, /* Start I/O */ + "SNS", 0x00,0,6,3, /* Sense I/O */ + "LIO", 0x01,0,6,3, /* Load I/O */ + "TIO", 0x01,0,6,1, /* Test I/O */ + "J", 0x02,0,7,0, /* Jump Unconditional */ + "J", 0x02,0x87,7,0, /* Alternate J */ + "JH", 0x02,132,7,0, /* Jump if High */ + "JL", 0x02,130,7,0, /* Jump if Low */ + "JE", 0x02,129,7,0, /* Jump if Equal */ + "JNH", 0x02,4,7,0, /* Jump if Not High */ + "JNL", 0x02,2,7,0, /* Jump if Not Low */ + "JNE", 0x02,1,7,0, /* Jump if Not Equal */ + "JOZ", 0x02,136,7,0, /* Jump if Overflow Zoned */ + "JOL", 0x02,160,7,0, /* Jump if Overflow Logical */ + "JNOZ", 0x02,8,7,0, /* Jump if No Overflow Zoned */ + "JNOL", 0x02,32,7,0, /* Jump if No Overflow Logical */ + "JT", 0x02,16,7,0, /* Jump if True */ + "JF", 0x02,144,7,0, /* Jump if False */ + "JP", 0x02,132,7,0, /* Jump if Plus */ + "JM", 0x02,130,7,0, /* Jump if Minus */ + "JZ", 0x02,129,7,0, /* Jump if Zero */ + "JNP", 0x02,4,7,0, /* Jump if Not Plus */ + "JNM", 0x02,2,7,0, /* Jump if Not Minus */ + "JNZ", 0x02,1,7,0, /* Jump if Not Zero */ + "NOPJ", 0x02,0x80,7,0, /* Never Jump - NOP */ + "B", 0x00,0x00,8,1, /* Branch Unconditional */ + "B", 0x00,0x87,8,1, /* Alternate B */ + "BH", 0x00,0x84,8,1, /* Branch if High */ + "BL", 0x00,0x82,8,1, /* Branch if Low */ + "BE", 0x00,0x81,8,1, /* Branch if Equal */ + "BNH", 0x00,0x04,8,1, /* Branch if Not High */ + "BNL", 0x00,0x02,8,1, /* Branch if Not Low */ + "BNE", 0x00,0x01,8,1, /* Branch if Not Equal */ + "BOZ", 0x00,0x88,8,1, /* Branch if Overflow Zoned */ + "BOL", 0x00,0xA0,8,1, /* Branch if Overflow Logical */ + "BNOZ", 0x00,0x08,8,1, /* Branch if No Overflow Zoned */ + "BNOL", 0x00,0x20,8,1, /* Branch if No Overflow Logical */ + "BT", 0x00,0x10,8,1, /* Branch if True */ + "BF", 0x00,0x90,8,1, /* Branch if False */ + "BP", 0x00,0x84,8,1, /* Branch if Plus */ + "BM", 0x00,0x82,8,1, /* Branch if Minus */ + "BZ", 0x00,0x81,8,1, /* Branch if Zero */ + "BNP", 0x00,0x04,8,1, /* Branch if Not Plus */ + "BNM", 0x00,0x02,8,1, /* Branch if Not Minus */ + "BNZ", 0x00,0x01,8,1, /* Branch if Not Zero */ + "NOPB", 0x00,0x80,8,1, /* Never Branch - NOP */ + "MZZ", 0x08,0,9,2, /* Move Zone to Zone */ + "MNZ", 0x08,1,9,2, /* Move Numeric to Zone */ + "MZN", 0x08,2,9,2, /* Move Zone to Numeric */ + "MNN", 0x08,3,9,2, /* Move Numeric to Numeric */ + "MVX", 0x08,0,2,2, /* Move Hex: MVX BADD,AADD,CODE */ + "JC", 0x02,0,3,0, /* Jump on Specified Condition bits */ + "BC", 0x00,0,3,1, /* Branch on Specified Condition */ + "***", 0x00,0,0,0 +}; + +int32 regcode[15] = { 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, + 0x80, 0xC0, 0xA0, 0x90, 0x88, 0x84, 0x82, 0x81 }; + +char regname[15][8] = { "(P2IAR)", + "(P1IAR)", + "(IAR)", + "(ARR)", + "(PSR)", + "(XR2)", + "(XR1)", + "(IAR0)", + "(IAR1)", + "(IAR2)", + "(IAR3)", + "(IAR4)", + "(IAR5)", + "(IAR6)", + "(IAR7)" }; + +/* This is the binary loader. The input file is considered to be + a string of literal bytes with no special format. The + load starts at the current value of the P1IAR. +*/ + +int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag) +{ +int32 i, addr = 0, cnt = 0; + +if ((*cptr != 0) || (flag != 0)) return SCPE_ARG; +addr = IAR[8]; +while ((i = getc (fileref)) != EOF) { + M[addr] = i & 0xff; + addr++; + cnt++; + } /* end while */ +printf ("%d Bytes loaded.\n", cnt); +return (SCPE_OK); +} + +/* Symbolic output + + Inputs: + *of = output stream + addr = current PC + *val = pointer to values + *uptr = pointer to unit + sw = switches + Outputs: + status = error code +*/ + +int32 fprint_sym (FILE *of, int32 addr, unsigned int32 *val, + UNIT *uptr, int32 sw) +{ + int32 r; + char strg[256]; + + strcpy(strg, ""); + r = printf_sym(of, strg, addr, val, uptr, sw); + if (sw & SWMASK ('A')) + strcpy(strg, ""); + else + fprintf(of, "%s", strg); + return (r); +} + +int32 printf_sym (FILE *of, char *strg, int32 addr, unsigned int32 *val, + UNIT *uptr, int32 sw) +{ +int32 cflag, c1, c2, group, len1, len2, inst, adr, aaddr, baddr; +int32 oplen, groupno, i, j, vpos, qbyte, da, m, n; +char bld[128], bldaddr[32], boperand[32], aoperand[32], regoperand[32]; +int32 blk[16], blt[16]; +int32 blkadd; + +cflag = (uptr == NULL) || (uptr == &cpu_unit); +c1 = val[0] & 0xff; +if (sw & SWMASK ('A')) { + for (i = 0; i < 16; i++) { + blkadd = addr + (i*16); + for (j = 0; j < 16; j++) { + blk[j] = M[blkadd+j] & 0xff; + c2 = ebcdic_to_ascii[blk[j]]; + if (c2 < 040 || c2 > 0177 || blk[j] == 07) { + blt[j] = '.'; + } else { + blt[j] = c2; + } + } + if (i == 0) { + fprintf(of, "%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X [%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c]\n ", + blk[0], blk[1], blk[2], blk[3], blk[4], blk[5], blk[6], blk[7], + blk[8], blk[9], blk[10], blk[11], blk[12], blk[13], blk[14], blk[15], + blt[0], blt[1], blt[2], blt[3], blt[4], blt[5], blt[6], blt[7], + blt[8], blt[9], blt[10], blt[11], blt[12], blt[13], blt[14], blt[15]); + } else { + fprintf(of, "%X\t%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X [%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c]\n ", + blkadd, blk[0], blk[1], blk[2], blk[3], blk[4], blk[5], blk[6], blk[7], + blk[8], blk[9], blk[10], blk[11], blk[12], blk[13], blk[14], blk[15], + blt[0], blt[1], blt[2], blt[3], blt[4], blt[5], blt[6], blt[7], + blt[8], blt[9], blt[10], blt[11], blt[12], blt[13], blt[14], blt[15]); + } + } + return SCPE_OK; } +if (sw & SWMASK ('C')) { + c2 = ebcdic_to_ascii[c1]; + if (c2 < 040 || c2 > 0177) { + sprintf(strg, "<%02X>", c1 & 0xff); + } else { + sprintf (strg, "%c", c2 & 0xff); + } + return SCPE_OK; } +if (!(sw & SWMASK ('M'))) return SCPE_ARG; + +inst = val[0] & 0x0f; +len1 = (val[0] >> 6) & 3; +len2 = (val[0] >> 4) & 3; +group = (val[0] >> 4) & 0x0f; +qbyte = val[1]; + +/* Get total length of instruction */ + +if (group == 0x0f) { + oplen = 3; +} else { + oplen = 2; + if (len1 == 0) oplen += 2; + if (len1 == 1 || len1 == 2) oplen++; + if (len2 == 0) oplen += 2; + if (len2 == 1 || len2 == 2) oplen++; +} + +/* Find which group it belongs to */ + +switch (group) { + case 0x0f: + groupno = 0; + break; + case 0x0c: + case 0x0d: + case 0x0e: + groupno = 1; + break; + case 0x03: + case 0x07: + case 0x0b: + groupno = 3; + break; + default: + groupno = 2; + break; +} + +/* find the table entry */ + +for (i = 0; i < nopcode; i++) { + if (opcode[i].form < 7) { /* Explicit Q */ + if (opcode[i].group == groupno && + opcode[i].opmask == inst) break; + } else { /* Implicit Q */ + if (opcode[i].group == groupno && + opcode[i].opmask == inst && + opcode[i].q == qbyte) break; + } +} + +/* print the opcode */ + +if (i >= nopcode) { + sprintf(strg, "%02X", val[0]); + oplen = 1; +} else { + sprintf(bld, "%s ", opcode[i].op); + + /* Extract the addresses into aaddr and baddr */ + + strcpy(aoperand, "ERROR"); + strcpy(boperand, "ERROR"); + vpos = 2; + aaddr = baddr = 0; + switch (len1) { + case 0: + baddr = ((val[vpos] << 8) & 0xff00) | (val[vpos + 1] & 0x00ff); + sprintf(boperand, "%04X", baddr); + vpos = 4; + break; + case 1: + baddr = val[vpos] & 255; + sprintf(boperand, "(%02X,XR1)", baddr); + vpos = 3; + break; + case 2: + baddr = val[vpos] & 255; + sprintf(boperand, "(%02X,XR2)", baddr); + vpos = 3; + break; + default: + baddr = 0; + break; + } + switch (len2) { + case 0: + aaddr = ((val[vpos] << 8) & 0xff00) | (val[vpos + 1] & 0x00ff); + if (group == 0x0C || group == 0x0D || group == 0x0E) + sprintf(boperand, "%04X", aaddr); + else + sprintf(aoperand, "%04X", aaddr); + break; + case 1: + aaddr = val[vpos] & 255; + if (group == 0x0C || group == 0x0D || group == 0x0E) + sprintf(boperand, "(%02X,XR1)", aaddr); + else + sprintf(aoperand, "(%02X,XR1)", aaddr); + break; + case 2: + aaddr = val[vpos] & 255; + if (group == 0x0C || group == 0x0D || group == 0x0E) + sprintf(boperand, "(%02X,XR2)", aaddr); + else + sprintf(aoperand, "(%02X,XR2)", aaddr); + break; + default: + aaddr = 0; + break; + } + + /* Display the operands in the correct format */ + + da = (qbyte >> 4) & 0x0f; + m = (qbyte >> 3) & 0x01; + n = (qbyte) & 0x07; + + switch (opcode[i].form) { + case 0: + sprintf(bldaddr, "%02X,%02X", qbyte, val[2]); + break; + case 1: + if (inst == 2 || inst == 4 || inst == 5 || inst == 6) { + for (i = 0; i < 16; i++) { + if (regcode[i] == qbyte) + break; + } + if (i < 16) { + sprintf(bldaddr, "%s,%s", regname[i], boperand); + } else { + sprintf(bldaddr, "%02X,%s", qbyte, boperand); + } + } else { + sprintf(bldaddr, "%02X,%s", qbyte, boperand); + } + break; + case 2: + if (inst > 9 || inst == 4 || inst == 6 || inst == 7) + qbyte++; /* special +1 for length display */ + sprintf(bldaddr, "%s,%s,%d", boperand, aoperand, qbyte); + break; + case 3: + if (strcmp(opcode[i].op, "JC") == 0) { + sprintf(bldaddr, "%04X,%02X", addr+oplen+val[2], qbyte); + } else { + sprintf(bldaddr, "%s,%02X", boperand, qbyte); + } + break; + case 4: + sprintf(bldaddr, "%d,%d,%d", da, m, n); + break; + case 5: + sprintf(bldaddr, "%d,%d,%d,%02X", da, m, n, val[2]); + break; + case 6: + sprintf(bldaddr, "%d,%d,%d,%s", da, m, n, boperand); + break; + case 7: + sprintf(bldaddr, "%04X", addr+oplen+val[2]); + break; + case 8: + sprintf(bldaddr, "%s", boperand); + break; + default: + sprintf(bldaddr, "%s,%s", boperand, aoperand); + break; + } + sprintf(strg, "%s%s", bld, bldaddr); +} + +return -(oplen - 1); +} + +/* Symbolic input + + Inputs: + *cptr = pointer to input string + addr = current PC + *uptr = pointer to unit + *val = pointer to output values + sw = switches + Outputs: + status = error status +*/ + +int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, unsigned int32 *val, int32 sw) +{ +int32 cflag, i = 0, j, k, r, oplen, addtyp, saveaddr, vptr; +char gbuf[CBUFSIZE]; + +cflag = (uptr == NULL) || (uptr == &cpu_unit); +while (isspace (*cptr)) cptr++; /* absorb spaces */ +if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ + if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ + val[0] = (unsigned int) cptr[0]; + return SCPE_OK; } +if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */ + if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ + val[0] = ((unsigned int) cptr[0] << 8) + (unsigned int) cptr[1]; + return SCPE_OK; } + +/* An instruction: get opcode (all characters until null, comma, left paren, + or numeric (including spaces). +*/ + +while (1) { + if (*cptr == ',' || *cptr == '\0' || *cptr == '(' || + isdigit(*cptr)) + break; + gbuf[i] = toupper(*cptr); + cptr++; + i++; +} + +/* kill trailing spaces if any */ +gbuf[i] = '\0'; +for (j = i - 1; gbuf[j] == ' '; j--) { + gbuf[j] = '\0'; +} + +/* find opcode in table */ +for (j = 0; j < nopcode; j++) { + if (strcmp(gbuf, opcode[j].op) == 0) + break; +} +if (j >= nopcode) /* not found */ + return SCPE_ARG; + +oplen = 2; /* start with op & q */ + +val[0] = opcode[j].opmask; /* store opcode right nybble */ + +switch (opcode[j].form) { /* Get operands based on operand format */ + case 0: /* Single Byte Operand */ + if (*cptr == ',') cptr++; + cptr = get_glyph(cptr, gbuf, ','); /* Get Q Byte */ + sscanf(gbuf, "%x", &r); + val[1] = r; + if (*cptr == ',') cptr++; + cptr = get_glyph(cptr, gbuf, 0); /* Get R Byte */ + sscanf(gbuf, "%x", &r); + val[2] = r; + oplen = 3; + val[0] = 0xf0 | opcode[j].opmask; + break; + case 1: + if (*cptr == ',') cptr++; + cptr = get_glyph(cptr, gbuf, ','); + if (opcode[j].opmask == 2 || + opcode[j].opmask == 4 || + opcode[j].opmask == 5 || + opcode[j].opmask == 6) { + if (isdigit(gbuf[0])) { + sscanf(gbuf, "%x", &r); + } else { + for (i = 0; i < 16; i++) { + if (strcmp(gbuf, regname[i]) == 0) + break; + } + if (i < 16) { + r = regcode[i]; + } else { + return SCPE_ARG; + } + } + } else { + sscanf(gbuf, "%x", &r); + } + if (r > 255) return SCPE_ARG; + val[1] = r; + if (*cptr == ',') cptr++; + cptr = parse_addr(cptr, gbuf, &addr, &addtyp); + switch(addtyp) { + case 0: + val[2] = (addr >> 8) & 0x00ff; + val[3] = addr & 0xff; + oplen = 4; + if (opcode[j].group == 1) + val[0] = 0xC0 | opcode[j].opmask; + else + val[0] = 0x30 | opcode[j].opmask; + break; + case 1: + val[2] = addr & 0xff; + oplen = 3; + if (opcode[j].group == 1) + val[0] = 0xD0 | opcode[j].opmask; + else + val[0] = 0x70 | opcode[j].opmask; + break; + case 2: + val[2] = addr & 0xff; + oplen = 3; + if (opcode[j].group == 1) + val[0] = 0xE0 | opcode[j].opmask; + else + val[0] = 0xB0 | opcode[j].opmask; + break; + default: + return SCPE_ARG; + break; + } + break; + case 2: + oplen = 2; + cptr = parse_addr(cptr, gbuf, &addr, &addtyp); + switch(addtyp) { + case 0: + val[2] = (addr >> 8) & 0xff; + val[3] = addr & 0xff; + oplen += 2; + vptr = 4; + val[0] = 0x00 | opcode[j].opmask; + break; + case 1: + val[2] = addr & 0xff; + oplen += 1; + vptr = 3; + val[0] = 0x40 | opcode[j].opmask; + break; + case 2: + val[2] = addr & 0xff; + oplen += 1; + vptr = 3; + val[0] = 0x80 | opcode[j].opmask; + break; + default: + return SCPE_ARG; + break; + } + if (*cptr == ',') cptr++; + cptr = parse_addr(cptr, gbuf, &addr, &addtyp); + switch(addtyp) { + case 0: + val[vptr] = (addr >> 8) & 0xff; + val[vptr+1] = addr & 0xff; + oplen += 2; + break; + case 1: + val[vptr] = addr & 0xff; + oplen += 1; + val[0] = 0x10 | val[0]; + break; + case 2: + val[vptr] = addr & 0xff; + oplen += 1; + val[0] = 0x20 | val[0]; + break; + default: + return SCPE_ARG; + break; + } + if (*cptr == ',') cptr++; + cptr = get_glyph(cptr, gbuf, 0); + sscanf(gbuf, "%d", &r); + if (opcode[j].opmask > 9 || + opcode[j].opmask == 4 || + opcode[j].opmask == 6 || + opcode[j].opmask == 7) r--; /* special: length -1 */ + val[1] = r; + if (*cptr == ',') cptr++; + break; + case 3: + saveaddr = addr; + if (*cptr == ',') cptr++; + cptr = parse_addr(cptr, gbuf, &addr, &addtyp); + switch(addtyp) { + case 0: + if (opcode[j].group == 0) { /* Group 0 form 3 is JC with explicit Q */ + if (*cptr == ',') cptr++; + cptr = get_glyph(cptr, gbuf, 0); + sscanf(gbuf, "%x", &r); + if ((addr - (saveaddr+3)) > 255 || (addr - (saveaddr+3)) < 1) + return SCPE_ARG; + val[2] = addr - (saveaddr+3); + val[1] = r; + val[0] = 0xf0 | opcode[j].opmask; + oplen = 3; + + } else { + val[2] = (addr >> 8) & 0x00ff; + val[3] = addr & 0xff; + oplen = 4; + if (opcode[j].group == 1) + val[0] = 0xC0 | opcode[j].opmask; + else + val[0] = 0x30 | opcode[j].opmask; + } + break; + case 1: + val[2] = addr & 0xff; + oplen = 3; + if (opcode[j].group == 1) + val[0] = 0xD0 | opcode[j].opmask; + else + val[0] = 0x70 | opcode[j].opmask; + break; + case 2: + val[2] = addr & 0xff; + oplen = 3; + if (opcode[j].group == 1) + val[0] = 0xE0 | opcode[j].opmask; + else + val[0] = 0xB0 | opcode[j].opmask; + break; + default: + return SCPE_ARG; + break; + } + if (*cptr == ',') cptr++; + cptr = get_glyph(cptr, gbuf, 0); + sscanf(gbuf, "%x", &r); + if (r > 255) return SCPE_ARG; + val[1] = r; + break; + case 4: + if (*cptr == ',') cptr++; + cptr = get_glyph(cptr, gbuf, ','); + sscanf(gbuf, "%d", &r); + if (r > 15) return SCPE_ARG; + val[1] = (r << 4) & 0xf0; + val[0] = 0xf0 | opcode[j].opmask; + if (*cptr == ',') cptr++; + cptr = get_glyph(cptr, gbuf, ','); + sscanf(gbuf, "%d", &r); + if (r > 1) return SCPE_ARG; + val[1] |= (r << 3) & 0x08; + if (*cptr == ',') cptr++; + cptr = get_glyph(cptr, gbuf, 0); + sscanf(gbuf, "%d", &r); + if (r > 7) return SCPE_ARG; + val[1] |= r & 0x07; + val[2] = 0; + oplen = 3; + break; + case 5: + if (*cptr == ',') cptr++; + cptr = get_glyph(cptr, gbuf, ','); + sscanf(gbuf, "%d", &r); + if (r > 15) return SCPE_ARG; + val[1] = (r << 4) & 0xf0; + val[0] = 0xf0 | opcode[j].opmask; + if (*cptr == ',') cptr++; + cptr = get_glyph(cptr, gbuf, ','); + sscanf(gbuf, "%d", &r); + if (r > 1) return SCPE_ARG; + val[1] |= (r << 3) & 0x08; + if (*cptr == ',') cptr++; + cptr = get_glyph(cptr, gbuf, ','); + sscanf(gbuf, "%d", &r); + if (r > 7) return SCPE_ARG; + val[1] |= r & 0x07; + if (*cptr == ',') cptr++; + cptr = get_glyph(cptr, gbuf, 0); + sscanf(gbuf, "%x", &r); + if (r > 255) return SCPE_ARG; + val[2] = r; + oplen = 3; + break; + case 6: + if (*cptr == ',') cptr++; + cptr = get_glyph(cptr, gbuf, ','); + sscanf(gbuf, "%d", &r); + if (r > 15) return SCPE_ARG; + val[1] = (r << 4) & 0xf0; + if (*cptr == ',') cptr++; + cptr = get_glyph(cptr, gbuf, ','); + sscanf(gbuf, "%d", &r); + if (r > 1) return SCPE_ARG; + val[1] |= (r << 3) & 0x08; + if (*cptr == ',') cptr++; + cptr = get_glyph(cptr, gbuf, ','); + sscanf(gbuf, "%d", &r); + if (r > 7) return SCPE_ARG; + val[1] |= r & 0x07; + if (*cptr == ',') cptr++; + cptr = parse_addr(cptr, gbuf, &addr, &addtyp); + switch(addtyp) { + case 0: + val[2] = (addr >> 8) & 0x00ff; + val[3] = addr & 0xff; + oplen = 4; + if (opcode[j].group == 1) + val[0] = 0xC0 | opcode[j].opmask; + else + val[0] = 0x30 | opcode[j].opmask; + break; + case 1: + val[2] = addr & 0xff; + oplen = 3; + if (opcode[j].group == 1) + val[0] = 0xD0 | opcode[j].opmask; + else + val[0] = 0x70 | opcode[j].opmask; + break; + case 2: + val[2] = addr & 0xff; + oplen = 3; + if (opcode[j].group == 1) + val[0] = 0xE0 | opcode[j].opmask; + else + val[0] = 0xB0 | opcode[j].opmask; + break; + default: + return SCPE_ARG; + break; + } + break; + case 7: + if (*cptr == ',') cptr++; + cptr = get_glyph(cptr, gbuf, 0); + sscanf(gbuf, "%x", &r); + if ((r - (addr+3)) > 255 || (r - (addr+3)) < 1) return SCPE_ARG; + val[2] = r - (addr+3); + val[1] = opcode[j].q; + val[0] = 0xf0 | opcode[j].opmask; + oplen = 3; + break; + + case 8: + if (*cptr == ',') cptr++; + cptr = parse_addr(cptr, gbuf, &addr, &addtyp); + switch(addtyp) { + case 0: + val[2] = (addr >> 8) & 0x00ff; + val[3] = addr & 0xff; + oplen = 4; + val[0] = 0xC0 | opcode[j].opmask; + break; + case 1: + val[2] = addr & 0xff; + oplen = 3; + val[0] = 0xD0 | opcode[j].opmask; + break; + case 2: + val[2] = addr & 0xff; + oplen = 3; + val[0] = 0xE0 | opcode[j].opmask; + break; + default: + return SCPE_ARG; + break; + } + val[1] = opcode[j].q; + break; + case 9: + oplen = 2; + val[0] = 0; + cptr = parse_addr(cptr, gbuf, &addr, &addtyp); + switch(addtyp) { + case 0: + val[2] = (addr >> 8) & 0xff; + val[3] = addr & 0xff; + oplen += 2; + vptr = 4; + val[0] = 0x00 | opcode[j].opmask; + break; + case 1: + val[2] = addr & 0xff; + oplen += 1; + vptr = 3; + val[0] = 0x40 | opcode[j].opmask; + break; + case 2: + val[2] = addr & 0xff; + oplen += 1; + vptr = 3; + val[0] = 0x80 | opcode[j].opmask; + break; + default: + return SCPE_ARG; + break; + } + if (*cptr == ',') cptr++; + cptr = parse_addr(cptr, gbuf, &addr, &addtyp); + switch(addtyp) { + case 0: + val[vptr] = (addr >> 8) & 0xff; + val[vptr+1] = addr & 0xff; + oplen += 2; + break; + case 1: + val[vptr] = addr & 0xff; + oplen += 1; + val[0] = 0x10 | val[0]; + break; + case 2: + val[vptr] = addr & 0xff; + oplen += 1; + val[0] = 0x20 | val[0]; + break; + default: + return SCPE_ARG; + break; + } + val[1] = opcode[j].q; + break; + default: + break; +} + + +return (-(oplen-1)); +} + +char *parse_addr(char *cptr, char *gbuf, int32 *addr, int32 *addrtype) +{ +int32 nybble = 0; +char temp[32]; + +cptr = get_glyph(cptr, gbuf, ','); +if (gbuf[0] == '(') { /* XR relative */ + strcpy(temp, gbuf+1); + sscanf(temp, "%x", addr); + if (*cptr == ',') cptr++; + cptr = get_glyph(cptr, gbuf, ','); + nybble = -1; + if (strcmp(gbuf, "XR1)") == 0) + nybble = 1; + if (strcmp(gbuf, "XR2)") == 0) + nybble = 2; +} else { /* Direct */ + sscanf(gbuf, "%x", addr); + nybble = 0; +} +*addrtype = nybble; +return cptr; +} + diff --git a/S3/system3.txt b/S3/system3.txt new file mode 100644 index 00000000..e01a97df --- /dev/null +++ b/S3/system3.txt @@ -0,0 +1,472 @@ + The IBM System/3 simulator is configured as follows: + + CPU 5410 (Model 10) CPU with 64KB of memory. + PKB 5471 Printer/Keyboard console. + CDR 1442 Card Reader + CDP 1442 Card Punch + CDP2 1442 2nd stacker + LPT 1403 Line Printer + R1 5444 Top Drive (removeable) + F1 5444 Top Drive (fixed) + R2 5444 Bottom Drive (removeable) + F2 5444 Bottom Drive (fixed + + The only CPU options are to set Model 15 mode (not implemented), DPF +(Dual Programming Facility, not implemented), and the memory size 8K, 16K, +32K, 48K, or 64K. + + CPU registers are the standard System/3 set: + + name size Description + + IAR-P1 16 Instruction Address Register for Program Level 1 + ARR-P2 16 Address Recall Register for Program Level 1 + IAR-P2 16 IAR for Program Level 2 (not implemented) + ARR-P2 16 ARR for Program Level 2 (not implemented) + AAR 16 A-Address Register + BAR 16 B-Address Register + PSR 16 Program Status Register + XR1 16 Index Register 1 + XR2 16 Index Register 2 + IAR<0:7> 16 IAR for interrupt level 0 thru 7 + ARR<0:7> 16 ARR for interrupt level 0 thru 7 + + Plus these simulator registers: + + IAR 16 Value of last IAR used. + LEVEL 8 Current operating level (8=P1, 9=P2, + 0 thru 7 = Interrupt level) + SR 16 Front Panel switches + INT 16 Interrupt Request Flags + WRU 8 Simulator Interrupt Character + BREAK 17 Breakpoint Address + DEBUG 16 Debugging bits: + 0x01: Write all instructions executed to + file trace.log. + 0x02: Write details of all Disk I/O + requests to trace.log. + 0x80: Breakpoint on first character + written to 5471 printer. + +1 5471 Printer/Keyboard + + This is the operator console. It has the following registers: + + FLAG 5471 Flag Bytes + IBUF: Input character from keyboard + OBUF: Output character to printer + POS: Number of characters printed + TIME: Delay for device operation + REQKEY: ASCII value of key mapped to 5471 REQUEST key + RTNKEY: ASCII value of key mapped to 5471 RETURN key + ENDKEY: ASCII value of key mapped to 5471 END key + CANKEY: ASCII value of key mapped to 5471 CANCEL key + + +2 1442 Card Reader. This reader reads 80-column cards; the input + is usually an ASCII file which is translated to EBCDIC when read, + but optionally can be a binary file in EBCDIC format (such as an + object program). + + LAST Last card switch + ERR Card Reader Error + NOTRDY 1442 reader not ready (not attached or past EOF) + DAR Data Address Register (shared with punch) + LCR Length Count Register (shared with punch) + EBCDIC EBCDIC mode flag: if 1, input is 80-col EBCDIC binary. + (IPL from 1442 automatically sets this to 1). + S2 Stacker 2 is selected when this is 1 + POS Number of cards read + TIME Device Delay + + The real hardware 1442 had only 1 hopper for cards, whether + these were used for blank cards for punching, or cards to be + read. Cards could be read without a feed cycle, then + punched. When punching cards, the SCP does a read of a card, + makes sure it is blank, and then punches it. To simulate + this without requiring that a stack of blank lines be attached + to the card reader device, a special feature of the simulator + is this: if no file is attached to the cdr device, but a file + is attached to the cdp or the cdp2 devices, any read from the + reader will return a blank card -- i.e. when punching, an + unattached cdr device is assumed to be loaded with an unlimited + supply of blank cards. + + +3 1442 Card Punch. Normally cards are written to the attached + disk file as ASCII with newline/cr delimiters. But an optional + flag allows writing as 80-column binary EBCDIC. + + ERR Card Punch Error + EBCDIC When this is 1, output will be 80-col EBCDIC. + S2 When this is 1, output is placed in stacker 2 + NOTRDY 1442 punch not ready (not attached) + DAR Data Address Register (shared with reader) + LCR Length Count Register (shared with reader) + POS Number of cards punched + TIME Device Delay + +4 1442 Stacker 2. When cards are to be punched in stacker 2, + attach a disk file to this device (cdp2) to hold that output. + Note: When SCP punches cards, the default is to punch in + stacker 2. + + POS0 Number of cards punched. + +5 1403 Printer. This is a 132-column output device, emulating + the famous IBM 1403, models 2, 6, and N1. Output is always + translated to ASCII with newline/CR delimiters. Page advance + is output as a form feed. + + ERR 1403 error flags + LPDAR Data Address Register + LPFLR Forms Length Register + LPIAR Image Address Register + LINECT Current Line on form + POS Number of lines printed + +6 5444 Disk Drives (R1, R2, F1, F2) + + The 5444 came as a set of two drives, each with two disks. The + top disk in a drive was removable, the bottom fixed. The first + drive consists of disks R1 and F1, the second drive R2 and F2. + Each disk holds 2,467,600 bytes of user data, plus 3 alternate + tracks and a CE track. Flagging of alternate tracks is not + supported in this version of the simulator. + + NOTRDY Drive not ready (not attached) + SEEK Drive is busy with a seek operation + DAR Data Address Register + CAR Control Address Register + ERR Error Flags (16 bits) + CYL Current Cylinder (0 thru 203) + HEAD Current head (0 or 1) + POS Current position in attached disk file + TIME Device Delay + +7 Symbolic Display and Input + + The System/3 Simulator supports symbolic display and input. + Display is controlled by command line switches: + + (none) display as hex EBCDIC + -c display bytes as characters + -m display instruction mnemonics. + -a display a 256-byte block of memory in both hex and ASCII. + + The symbolic format contains the same elements as the machine + language operation, but not always in the same order. The + operation code frequently specifies both the opcode and the Q byte, + and the top nybble of the opcode is determined by the format of the + addresses. + + Addresses take two forms: the direct address in hex, or a relative + address specified thusly: (byte,XRx) where 'byte' is a 1-byte + offset, and XRx is either XR1 or XR2 for the two index registers. + Use these formats when 'address' is indicated below: + + When 'reg' is mentioned, a mnemonic may be used for the register, + thusly: + + IAR Instruction Address Register for the current program level + ARR Address Recall Register for the current program level + P1IAR IAR for Program Level 1 + P2IAR IAR for Program Level 2 + PSR Program Status Register + XR1 Index Register 1 + XR2 Index Register 2 + IARx IAR for the interrupt level x (x = 0 thru 7) + + All other operands mentioned below are single-byte hex, except for + the length (len) operand of the two-address instructions, which is a + decimal length in the range 1-256. + + In operations where there is a source and a destination, the + destination is always operand 1, the source is operand 2. + + No-address formats: + ------------------ + + HPL hex,hex Halt Program Level, the operands are the + Q and R bytes. + + + One-address formats: + ------------------- + + A reg,address Add to register + CLI address,byte Compare Logical Immediate + MVI address,byte Move Immediate + TBF address,mask Test Bits Off + TBN address,mask Test Bits On + SBF address,mask Set Bits Off + SBN address,mask Set Bits On + ST reg,address Store Register + L reg,address Load Register + LA reg,address Load Address (reg can only be XR1 or XR2) + JC address,cond Jump on Condition + BC address,cond Branch on Condition + + These operations do not specify a qbyte, it is implicit in the + opcode: + + B address Unconditional branch to address + BE address Branch Equal + BNE address Branch Not Equal + BH address Branch High + BNH address Branch Not High + BL address Branch Low + BNL address Branch Not Low + BT address Branch True + BF address Branch False + BP address Branch Plus + BM address Branch Minus + BNP address Branch Not Plus + BNM address Branch Not Minus + BZ address Branch Zero + BNZ address Branch Not Zero + BOZ address Branch Overflow Zoned + BOL address Branch Overflow Logical + BNOZ address Branch No Overflow Zoned + BNOL address Branch No Overflow Logical + NOPB address No - never branch + + (substitute J for B above for a set of Jumps -- 1-byte operand (not + 2), always jumps forward up to 255 bytes from the address following + the Jump instruction. In this case, 'address' cannot be less than + the current address, nor greater than the current address + 255) + + Two-address formats (first address is destination, len is decimal 1-256): + ------------------- + + MVC address,address,len Move Characters + CLC address,address,len Compare Logical Characters + ALC address,address,len Add Logical Characters + SLC address,address,len Subtract Logical Characters + ED address,address,len Edit + ITC address,address,len Insert and Test Characters + AZ address,address,len Add Zoned Decimal + SZ address,address,len Subtract Zoned Decimal + + MNN address,address Move Numeric to Numeric + MNZ address,address Move Numeric to Zone + MZZ address,address Move Zone to Zone + MZN address,address Move Zone to Numeric + + I/O Format + ---------- + + In the I/O format, there are always 3 fields: + + da - Device Address 0-15 (decimal) + m - Modifier 0-1 + n - Function 0-7 + + The meaning of these is entirely defined by the device addressed. + + There may be an optional control byte, or an optional address (based + on the type of instruction). + + SNS da,m,n,address Sense I/O + LIO da,m,n,address Load I/O + TIO da,m,n,address Test I/O + + SIO da,m,n,cc Start I/O -- cc is a control byte + + APL da,m,n Advance Program Level + + +8 Device Programming. + + Note: On a model 15, interrupts are used for all devices. On + other models, interrupts are only used for the printer/keyboard. + + This is a summary of the DA, M, N, and CC codes for all supported + devices: + + 5471 Printer Keyboard + --------------------- + + The PKB has 2 visible indicators: Proceed and Request + Pending. It has a normal keyboard and 4 special keys: + Request, Return, End, and Cancel. + + SIO 1,0,0,XX Start Keyboard Operation, bit masks for XX are: + X'20': Request Pending Indicator On + X'10': Proceed Indicator On + X'04': Request Key Interrupts Enable (1) Disable (0) + X'02': Other Key Interrupts Enable (1) Disable (0) + X'01': Reset request key and other key interrupts + + SIO 1,1,0,XX Start Printer Operation, bit masks for XX are: + X'80': Start Printing + X'40': Start Carrier Return + X'04': Printer Interrupt Enable(1) or Disable (0) + X'01': Reset Printer Interrupt + + LIO 1,1,0,addr Load Printer Output Character + addr is address of low-order (highest numbered) + byte of two-byte field, and high-order byte + (that is, addr - 1) is loaded into output + register to print. Printing is done one character + at a time. + + SNS 1,0,1,addr Sense Status Bytes 0 and 1: + Byte 0 (leftmost) is the character typed in + in EBCDIC. + Byte 1 is status: + X'80': Request key interrupt pending + X'40': End or Cancel key interrupt pending + X'20': Cancel key pressed + X'10': End Key Pressed + X'08': Return or data key interrupt pending + X'04': Return key pressed + + SNS 1,0,3,addr Sense Status Bytes 2 and 3: returns 0000 in + this sim. + + 1442 Reader/Punch + ----------------- + + SIO 5,0,0,XX Feed Card without reading/punching + XX is stacker select for all functions: 0 = stacker + 1 (normal), 1 = stacker 2. + + SIO 5,0,1,XX Read Card + SIO 5,0,2,XX Punch and Feed + SIO 5,0,3,XX Read Column Binary + SIO 5,0,4,XX Punch with no feed + + TIO 5,0,0,addr Branch to addr if not ready or busy + TIO 5,0,2,addr Branch to addr if busy + TIO 5,0,5,addr (mod 15 only) branch if interrupt pending + + APL 5,0,0 Loop (or switch prog levels) if not ready/busy + APL 5,0,2 Loop (or switch) if busy + APL 5,0,5 Loop (or switch) if interrupt pending (mod 15 only) + + LIO 5,0,0,addr Load 2-byte field to Length Count Register + LIO 5,0,4,addr Load 2-byte field to Data Address Register + (DAR is incremented by a read/punch operation and must + be reset every card) + + SNS 5,0,1,addr Sense CE indicators (0000 returned in this sim) + SNS 5,0,2,addr Sense CE indicators (0000 returned in this sim) + SNS 5,0,3,addr Sense Status Indicators: (only simulated bits shown) + X'8000': Read Check + X'4000': Last Card + X'2000': Punch Check + X'1000': Data Overrun + X'0800': Not Ready + + + 1403 Printer + ------------ + + SIO 14,0,0,XX Line space XX lines (0-3 valid in XX) + SIO 14,0,2,XX Print a line space (0-3 valid in XX) + SIO 14,0,4,XX Skip Only (line number 1-112 in XX) + + SIO 14,0,6,XX Print and Skip (line number 0-112 in XX) + + TIO 14,0,0,addr Branch to addr if not ready + TIO 14,0,2,addr Branch to addr if buffer busy + TIO 14,0,3,addr Branch to addr if interrupt pending (mod 15 only) + TIO 14,0,4,addr Branch if carriage busy + TIO 14,0,6,addr Branch if printer busy + + APL 14,0,0 Loop (or switch prog levels) if not ready/check + APL 14,0,2 Loop (or switch) if buffer busy + APL 14,0,3 Loop (or switch) if interrupt pending (mod 15 only) + APL 14,0,4 Loop (or switch) if carriage busy + APL 14,0,6 Loop (or switch) if printer busy + + LIO 14,0,0,addr Load 1 byte to Forms Length Reg at addr-1 + LIO 14,0,4,addr Load 2 bytes to Chain Image Address Register + LIO 14,0,6,addr Load 2 bytes to Data Address Register + + SNS 14,0,0,addr Sense Character Count + SNS 14,0,4,addr Sense LPIAR (Image Address Register) + SNS 14,0,6,addr Sense LPDAR (data addres register) + + + 5444 Disk Drives + ---------------- + + Each drive has two disks (upper and lower), each disk + has two surfaces (upper and lower), each surface has + 24 256-byte sectors, sectors are number 0 thru 23 on + upper surface, 32 thru 55 on lower. + + d = drive, 0 is R1/F1, 1 is R2/F2 + s = surface, 0 = upper (removable), 1 = lower (fixed) + + The Control register points to the leftmost byte of a 4-byte + control field in memory with these bytes: + + F - Flag byte (not supported in this sim) + C - Cylinder Address (0-203) + S - Sector Number (0-23, or 32-55) in top 6 bits + N - Number of sectors minus 1 + + These have meaning for all operations except seek, seek uses + the fields differently. + + SIO 1d,s,0,XX Seek, XX not used, control field is used: + + F - not used + C - not used + S - high bit is head to be used 0-upper 1-lower + low bit is direction to move 0-back 1-forward + N - number of cylinders to move + + SIO 1d,s,1,XX Read, values of XX are as follows: + X'00': Read Data + X'01': Read Identifier (updates control field, no + data is read) + X'02': Read Data Diagnostic + X'03': Verify (does not read, but checks) + + SIO 1d,s,2,XX Write, values of XX are as follows: + X'00': Write Data + X'01': Write Identifier (24 sectors with byte at + data address register) + + SIO 1d,s,3,XX Scan. All 256 bytes in memory at data + address register are compared to disk + sectors on current track, except those + bytes of X'FF' are not compared. Values of + XX are: + + X'00': Scan Equal + X'01': Scan Low or Equal + X'02': Scan High or Equal + + LIO 1d,0,4,addr Load Data Address Register + LIO 1d,0,6,addr Load Disk Control Address Register + + TIO 1d,0,0,addr Branch if not ready/unit check + TIO 1d,0,2,addr Branch if busy + TIO 1d,0,4,addr Branch if Scan Found + + APL 1d,0,0 Loop if not ready/unit check + APL 1d,0,2 Loop if busy + APL 1d,0,4 Loop if scan found + + SNS 1d,0,2,addr Sense Status Bytes 0 and 1: (simulated + bits only are shown, otehrs are 0): + X'1000': equipment check + X'0800': data check + X'0400': No record found + X'0100': Seek Check (past cyl 203) + X'0080': Scan equal Hit + X'0040': Cylinder 0 + X'0020': End of Cylinder + X'0010': Seek Busy + SNS 1d,0,3,addr Sense bytes 2 and 3 (0000 in this sim) + SNS 1d,0,4,addr Sense Data Address Register + SNS 1d,0,6,addr Sense Control Address Register + + + + diff --git a/dec_dz.h b/dec_dz.h index c6875548..8d0473f8 100644 --- a/dec_dz.h +++ b/dec_dz.h @@ -28,6 +28,8 @@ dz DZ11 terminal multiplexor + 03-Dec-01 RMS Modified for extended SET/SHOW + 09-Nov-01 RMS Added VAX support 20-Oct-01 RMS Moved getchar from sim_tmxr, changed interrupt logic to use tmxr_rqln 06-Oct-01 RMS Fixed bug in carrier detect logic @@ -47,6 +49,10 @@ #include "sim_sock.h" #include "sim_tmxr.h" +#if !defined (DZ_RDX) +#define DZ_RDX 8 +#endif + #define DZ_LNOMASK (DZ_LINES - 1) /* mask for lineno */ #define DZ_LMASK ((1 << DZ_LINES) - 1) /* mask of lines */ #define DZ_SILO_ALM 16 /* silo alarm level */ @@ -132,7 +138,7 @@ t_stat dz_clear (t_bool flag); int32 dz_getchar (TMXR *mp); void dz_update_rcvi (void); void dz_update_xmti (void); -t_stat dz_status (UNIT *uptr, FILE *st); +t_stat dz_status (FILE *st, UNIT *uptr, void *desc); /* DZ data structures @@ -144,12 +150,12 @@ t_stat dz_status (UNIT *uptr, FILE *st); UNIT dz_unit = { UDATA (&dz_svc, UNIT_ATTABLE, 0) }; REG dz_reg[] = { - { ORDATA (CSR, dz_csr, 16) }, - { ORDATA (RBUF, dz_rbuf, 16) }, - { ORDATA (LPR, dz_lpr, 16) }, - { ORDATA (TCR, dz_tcr, 16) }, - { ORDATA (MSR, dz_msr, 16) }, - { ORDATA (TDR, dz_tdr, 16) }, + { GRDATA (CSR, dz_csr, DZ_RDX, 16, 0) }, + { GRDATA (RBUF, dz_rbuf, DZ_RDX, 16, 0) }, + { GRDATA (LPR, dz_lpr, DZ_RDX, 16, 0) }, + { GRDATA (TCR, dz_tcr, DZ_RDX, 16, 0) }, + { GRDATA (MSR, dz_msr, DZ_RDX, 16, 0) }, + { GRDATA (TDR, dz_tdr, DZ_RDX, 16, 0) }, { FLDATA (SAENB, dz_sa_enb, 0) }, { FLDATA (MDMCTL, dz_mctl, 0) }, { FLDATA (AUTODS, dz_auto, 0) }, @@ -173,12 +179,14 @@ REG dz_reg[] = { { NULL } }; MTAB dz_mod[] = { - { UNIT_ATT, UNIT_ATT, "line status:", NULL, &dz_status }, + { UNIT_ATT, UNIT_ATT, "line status", NULL, NULL, &dz_status }, + { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "LINESTATUS", NULL, + NULL, &dz_status, NULL }, { 0 } }; DEVICE dz_dev = { "DZ", &dz_unit, dz_reg, dz_mod, - 1, 8, 13, 1, 8, 8, + 1, DZ_RDX, 13, 1, DZ_RDX, 8, &tmxr_ex, &tmxr_dep, &dz_reset, NULL, &dz_attach, &dz_detach }; @@ -424,10 +432,11 @@ return tmxr_detach (&dz_desc, uptr); /* Status */ -t_stat dz_status (UNIT *uptr, FILE *st) +t_stat dz_status (FILE *st, UNIT *uptr, void *desc) { int32 i; +fprintf (st, "line status:"); for (i = 0; (i < DZ_LINES) && (dz_desc.ldsc[i] -> conn == 0); i++) ; if (i < DZ_LINES) { for (i = 0; i < DZ_LINES; i++) { diff --git a/dec_mscp.h b/dec_mscp.h new file mode 100644 index 00000000..59f0d4d7 --- /dev/null +++ b/dec_mscp.h @@ -0,0 +1,373 @@ +/* dec_mscp.c: DEC MSCP definitions + + Copyright (c) 2001, Robert M Supnik + Derived from work by Stephen F. Shirron + + 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. +*/ + +/* Misc constants */ + +#define UID_DISK 2 /* disk 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 */ + +/* 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 */ + +/* End flags */ + +#define EF_LOG 0x0020 /* error log */ +#define EF_SEX 0x0010 /* serious exc NI */ + +/* Controller flags */ + +#define CF_RPL 0x8000 /* ctrl bad blk repl */ +#define CF_ATN 0x0080 /* enb attention */ +#define CF_MSC 0x0040 /* enb misc msgs */ +#define CF_OTH 0x0020 /* enb othr host msgs */ +#define CF_THS 0x0010 /* enb this host msgs */ +#define CF_MSK (CF_ATN|CF_MSC|CF_OTH|CF_THS) + +/* 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_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 */ + +/* 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 */ + +/* 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_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 */ + +/* Status invalid command subcodes */ + +#define I_OPCD (8 << ST_V_INV) /* inv opcode */ +#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 */ + +/* Packet formats - note that all packet lengths must be multiples of 4 bytes */ + +/* Command packet header */ + +#define CMD_REFL 2 /* ref # */ +#define CMD_REFH 3 +#define CMD_UN 4 /* unit # */ +/* 5 /* reserved */ +#define CMD_OPC 6 /* opcode */ +#define CMD_MOD 7 /* modifier */ + +#define CMD_OPC_V_OPC 0 /* opcode */ +#define CMD_OPC_M_OPC 0xFF +#define CMD_OPC_V_CAA 8 /* cache NI */ +#define CMD_OPC_M_CAA 0xFF + +/* Response packet header */ + +#define RSP_LNT 12 +#define RSP_REFL 2 /* ref # */ +#define RSP_REFH 3 +#define RSP_UN 4 /* unit # */ +#define RSP_RSV 5 /* reserved */ +#define RSP_OPF 6 /* opcd,flg */ +#define RSP_STS 7 /* modifiers */ + +#define RSP_OPF_V_OPC 0 /* opcode */ +#define RSP_OPF_V_FLG 8 /* flags */ + +/* Abort packet - 2 W parameter, 2 W status */ + +#define ABO_LNT 16 +#define ABO_REFL 8 /* ref # */ +#define ABO_REFH 9 + +/* Avail packet - min size */ + +#define AVL_LNT 12 + +/* Get command status packet - 2 W parameter, 4 W of status */ + +#define GCS_LNT 20 +#define GCS_REFL 8 /* ref # */ +#define GCS_REFH 9 +#define GCS_STSL 10 /* status */ +#define GCS_STSH 11 + +/* Format packet - 8 W parameters, none returned */ + +#define FMT_LNT 12 +#define FMT_IH 17 /* magic bit */ + +/* Get unit status packet - 18 W status */ + +#define GUS_LNT 48 +#define GUS_MLUN 8 /* mlun */ +#define GUS_UFL 9 /* flags */ +#define GUS_RSVL 10 /* reserved */ +#define GUS_RSVH 11 +#define GUS_UIDA 12 /* unit ID */ +#define GUS_UIDB 13 +#define GUS_UIDC 14 +#define GUS_UIDD 15 +#define GUS_MEDL 16 /* media ID */ +#define GUS_MEDH 17 +#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 */ + +#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 */ + +#define ONL_LNT 44 +#define ONL_MLUN 8 /* mlun */ +#define ONL_UFL 9 /* flags */ +#define ONL_RSVL 10 /* reserved */ +#define ONL_RSVH 11 +#define ONL_UIDA 12 /* unit ID */ +#define ONL_UIDB 13 +#define ONL_UIDC 14 +#define ONL_UIDD 15 +#define ONL_MEDL 16 /* media ID */ +#define ONL_MEDH 17 +#define ONL_SHUN 18 /* shadowing */ +#define ONL_SHST 19 +#define ONL_SIZL 20 /* size */ +#define ONL_SIZH 21 +#define ONL_VSNL 22 /* vol ser # */ +#define ONL_VSNH 23 + +#define ONL_UIDD_V_MOD 0 /* unit model */ +#define ONL_UIDD_V_CLS 8 /* unit class */ + +/* Set controller characteristics packet - 8 W parameters, 10 W status */ + +#define SCC_LNT 32 +#define SCC_MSV 8 /* MSCP version */ +#define SCC_CFL 9 /* flags */ +#define SCC_TMO 10 /* timeout */ +#define SCC_VER 11 /* ctrl version */ +#define SCC_CIDA 12 /* ctrl ID */ +#define SCC_CIDB 13 +#define SCC_CIDC 14 +#define SCC_CIDD 15 +#define SCC_MBCL 16 /* max byte count */ +#define SCC_MBCH 17 + +#define SCC_VER_V_SVER 0 /* swre vrsn */ +#define SCC_VER_V_HVER 8 /* hwre vrsn */ +#define SCC_CIDD_V_MOD 0 /* ctrl model */ +#define SCC_CIDD_V_CLS 8 /* ctrl class */ + +/* Set unit characteristics - 2 W parameter, 16 W status - same as ONL */ + +#define SUC_LNT 44 + +/* Data transfer packet - 10 W parameters, 10 W status */ + +#define RW_LNT 32 +#define RW_BCL 8 /* byte count */ +#define RW_BCH 9 +#define RW_BAL 10 /* buff desc */ +#define RW_BAH 11 +#define RW_MAPL 12 /* map table */ +#define RW_MAPH 13 +/* 14 /* reserved */ +/* 15 /* reserved */ +#define RW_LBNL 16 /* LBN */ +#define RW_LBNH 17 +#define RW_WBCL 18 /* working bc */ +#define RW_WBCH 19 +#define RW_WBAL 20 /* working ba */ +#define RW_WBAH 21 +#define RW_WBLL 22 /* working lbn */ +#define RW_WBLH 23 + +/* Error log packet header */ + +#define ELP_REFL 2 /* ref # */ +#define ELP_REFH 3 +#define ELP_UN 4 /* unit */ +#define ELP_SEQ 5 +#define ELP_FF 6 /* fmt,flg */ +#define ELP_EVT 7 /* event */ + +#define ELP_EV_V_FMT 0 /* format */ +#define ELP_EV_V_FLG 8 /* flag */ + +/* Port last failure error log packet - 6 W status */ + +#define PLF_LNT 24 /* length */ +#define PLF_CIDA 8 /* ctrl ID */ +#define PLF_CIDB 9 +#define PLF_CIDC 10 +#define PLF_CIDD 11 +#define PLF_VER 12 /* ctrl version */ +#define PLF_ERR 13 /* err */ + +#define PLF_CIDD_V_MOD 0 /* ctrl model */ +#define PLF_CIDD_V_CLS 8 /* ctrl class */ +#define PLF_VER_V_SVER 0 /* swre ver */ +#define PLF_VER_V_HVER 8 /* hwre ver */ + +/* Disk transfer error log packet - 18 W status */ + +#define DTE_LNT 48 +#define DTE_CIDA 8 /* ctrl ID */ +#define DTE_CIDB 9 +#define DTE_CIDC 10 +#define DTE_CIDD 11 +#define DTE_VER 12 /* version */ +#define DTE_MLUN 13 /* mlun */ +#define DTE_UIDA 14 /* unit ID */ +#define DTE_UIDB 15 +#define DTE_UIDC 16 +#define DTE_UIDD 17 +#define DTE_UVER 18 +#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 + +#define DTE_CIDD_V_MOD 0 /* ctrl model */ +#define DTE_CIDD_V_CLS 8 /* ctrl class */ +#define DTE_VER_V_SVER 0 /* ctrl swre ver */ +#define DTE_VER_V_HVER 8 /* ctrl hwre ver */ +#define DTE_UIDD_V_MOD 0 /* unit model */ +#define DTE_UIDD_V_CLS 8 /* unit class */ +#define DTE_D2_V_SECT 8 +#define DTE_D3_V_SURF 0 +#define DTE_D3_V_CYL 8 + +/* Host bus error log packet - 8 W status */ + +#define HBE_LNT 28 +#define HBE_CIDA 8 /* ctrl ID */ +#define HBE_CIDB 9 +#define HBE_CIDC 10 +#define HBE_CIDD 11 +#define HBE_VER 12 /* ctrl version */ +#define HBE_RSV 13 /* reserved */ +#define HBE_BADL 14 /* bad address */ +#define HBE_BADH 15 + +#define HBE_CIDD_V_MOD 0 /* ctrl model */ +#define HBE_CIDD_V_CLS 8 /* ctrl class */ +#define HBE_VER_V_SVER 0 /* ctrl swre ver */ +#define HBE_VER_V_HVER 8 /* ctrl hwre ver */ + +/* Unit now available attention message - 10 W status, same as + first 10 W of status from get unit status +*/ + +#define UNA_LNT 32 diff --git a/dec_uqssp.h b/dec_uqssp.h new file mode 100644 index 00000000..0ea2801e --- /dev/null +++ b/dec_uqssp.h @@ -0,0 +1,162 @@ +/* dec_uqssp.h: Unibus/Qbus storage systems port definitions file + + Copyright (c) 2001, Robert M Supnik + Derived from work by Stephen F. Shirron + + 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. +*/ + +/* IP register - initialization and polling + + read - controller polls command queue + write - controller re-initializes +*/ + +/* SA register - status, address, and purge + + read - data and error information + write - host startup information, purge complete +*/ + +#define SA_ER 0x8000 /* error */ +#define SA_S4 0x4000 /* init step 4 */ +#define SA_S3 0x2000 /* init step 3 */ +#define SA_S2 0x1000 /* init step 2 */ +#define SA_S1 0x0800 /* init step 1 */ + +/* Init step 1, controller to host */ + +#define SA_S1C_NV 0x0400 /* fixed vec NI */ +#define SA_S1C_Q22 0x0200 /* Q22 device */ +#define SA_S1C_DI 0x0100 /* ext diags */ +#define SA_S1C_OD 0x0080 /* odd addrs NI */ +#define SA_S1C_MP 0x0040 /* mapping */ +#define SA_S1C_SM 0x0020 /* spec fncs NI */ +#define SA_S1C_CN 0x0010 /* node name NI */ + +/* Init step 1, host to controller */ + +#define SA_S1H_VL 0x8000 /* valid */ +#define SA_S1H_WR 0x4000 /* wrap mode */ +#define SA_S1H_V_CQ 11 /* cmd q len */ +#define SA_S1H_M_CQ 0x7 +#define SA_S1H_V_RQ 8 /* resp q len */ +#define SA_S1H_M_RQ 0x7 +#define SA_S1H_IE 0x0080 /* int enb */ +#define SA_S1H_VEC 0x007F /* vector */ +#define SA_S1H_CQ(x) (1 << (((x) >> SA_S1H_V_CQ) & SA_S1H_M_CQ)) +#define SA_S1H_RQ(x) (1 << (((x) >> SA_S1H_V_RQ) & SA_S1H_M_RQ)) + +/* Init step 2, controller to host */ + +#define SA_S2C_PT 0x0000 /* port type */ +#define SA_S2C_V_EC 8 /* info to echo */ +#define SA_S2C_M_EC 0xFF +#define SA_S2C_EC(x) (((x) >> SA_S2C_V_EC) & SA_S2C_M_EC) + +/* Init step 2, host to controller */ + +#define SA_S2H_CLO 0xFFFE /* comm addr lo */ +#define SA_S2H_PI 0x0001 /* adp prg int */ + +/* Init step 3, controller to host */ + +#define SA_S3C_V_EC 0 /* info to echo */ +#define SA_S3C_M_EC 0xFF +#define SA_S3C_EC(x) (((x) >> SA_S3C_V_EC) & SA_S3C_M_EC) + +/* Init step 3, host to controller */ + +#define SA_S3H_PP 0x8000 /* purge, poll test */ +#define SA_S3H_CHI 0x7FFF /* comm addr hi */ + +/* Init step 4, controller to host */ + +#define SA_S4C_V_MOD 4 /* adapter # */ +#define SA_S4C_V_VER 0 /* version # */ + +/* Init step 4, host to controller */ + +#define SA_S4H_CS 0x0400 /* host scrpad NI */ +#define SA_S4H_NN 0x0200 /* snd node name NI */ +#define SA_S4H_SF 0x0100 /* spec fnc NI */ +#define SA_S4H_LF 0x0002 /* send last fail */ +#define SA_S4H_GO 0x0001 /* go */ + +/* Fatal error codes (generic through 32) */ + +#define PE_PRE 1 /* packet read err */ +#define PE_PWE 2 /* packet write err */ +#define PE_QRE 6 /* queue read err */ +#define PE_QWE 7 /* queue write err */ +#define PE_HAT 9 /* host access tmo */ +#define PE_ICI 14 /* inv conn ident */ +#define PE_PIE 20 /* prot incompat */ +#define PE_PPF 21 /* prg/poll err */ +#define PE_MRE 22 /* map reg rd err */ +#define PE_T11 475 /* T11 err NI */ +#define PE_SND 476 /* SND err NI */ +#define PE_RCV 477 /* RCV err NI */ +#define PE_NSR 478 /* no such rsrc */ + +/* Comm region offsets */ + +#define SA_COMM_QQ -8 /* unused */ +#define SA_COMM_PI -6 /* purge int */ +#define SA_COMM_CI -4 /* cmd int */ +#define SA_COMM_RI -2 /* resp int */ +#define SA_COMM_MAX ((4 << SA_S1H_M_CQ) + (4 << SA_S1H_M_RQ) - SA_COMM_QQ) + +/* Command/response rings */ + +struct uq_ring { + const int32 ioff; /* intr offset */ + t_addr ba; /* base addr */ + uint32 lnt; /* size in bytes */ + uint32 idx; /* current index */ + }; + +/* Ring descriptor entry */ + +#define UQ_DESC_OWN 0x80000000 /* ownership */ +#define UQ_DESC_F 0x40000000 /* flag */ +#define UQ_ADDR 0x003FFFFE /* addr, word aligned */ + +/* Packet header */ + +#define UQ_HDR_OFF -4 /* offset */ + +#define UQ_HLNT 0 /* length */ +#define UQ_HCTC 1 /* credits, type, CID */ + +#define UQ_HCTC_V_CR 0 /* credits */ +#define UQ_HCTC_M_CR 0xF +#define UQ_HCTC_V_TYP 4 /* type */ +#define UQ_HCTC_M_TYP 0xF +#define UQ_TYP_SEQ 0 /* sequential */ +#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_DUP 2 /* DUP */ +#define UQ_CID_DIAG 0xFF /* diagnostic */ + diff --git a/id4_cpu.c b/id4_cpu.c deleted file mode 100644 index 0aabf92a..00000000 --- a/id4_cpu.c +++ /dev/null @@ -1,770 +0,0 @@ -/* id4_cpu.c: Interdata 4 CPU simulator - - 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. - - 10-Aug-01 RMS Removed register in declarations - 07-Oct-00 RMS Overhauled I/O subsystem - 14-Apr-99 RMS Changed t_addr to unsigned - - The register state for the Interdata 4 CPU is: - - R[0:F]<0:15> general registers - F[0:7]<0:31> floating point registers - PSW<0:31> processor status word, including - STAT<0:11> status flags - CC<0:3> condition codes - PC<0:15> program counter - int_req[8]<0:31> interrupt requests - int_enb[8]<0:31> interrupt enables - - The Interdata 4 has three instruction formats: register to register, - register to memory, and register to storage. The formats are: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | op | R1 | R2 | register-register - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | op | R1 | RX | register-memory - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | address | - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | op | R1 | RX | register-storage - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | address | - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - For register-memory and register-storage instructions, an effective - address is calculated as follows: - - effective addr = address + RX (if RX > 0) - - Register-memory instructions can access an address space of 65K bytes. -*/ - -/* This routine is the instruction decode routine for the Interdata 4. - 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 - wait state and no I/O outstanding - invalid instruction - I/O error in I/O simulator - - 2. Interrupts. Each device has an interrupt request flag and an - interrupt enabled flag. To facilitate evaluation, all interrupt - requests are kept in int_req, and all enables in int_enb. If - external interrupts are enabled in the PSW, and an external request - is pending, an interrupt occurs. - - 3. Non-existent memory. On the Interdata 4, reads to non-existent - memory return zero, and writes are ignored. In the simulator, the - largest possible memory is instantiated and initialized to zero. - Thus, only writes need be checked against actual memory size. - - 4. Adding I/O devices. These modules must be modified: - - id4_defs.h add a definition for the device mnemonic - id4_cpu.c add dispatch routine to table dev_tab - id4_sys.c add pointer to data structures to sim_devices -*/ - -#include "id4_defs.h" - -#define ILL_ADR_FLAG (MAXMEMSIZE) -#define save_ibkpt (cpu_unit.u3) -#define UNIT_V_MSIZE (UNIT_V_UF) /* dummy mask */ -#define UNIT_MSIZE (1 << UNIT_V_MSIZE) -#define SIGN_EXT(x) (((x) & SIGN)? (x) | ~MAGMASK: (x)) -#define CC_GL(x) if ((x) & SIGN) CC = CC_L; \ - else if (x) CC = CC_G; \ - else CC = 0 -#define CC_GL_C(x) if ((x) & SIGN) CC = CC_L; \ - else if (x) CC = CC_G; \ - else CC = 0 -/* else CC = CC & (CC_G | CC_L) */ -#define BUILD_PSW ((PSW & ~CC_MASK) | CC) -#define PSW_SWAP(o,n) WriteW ((o), BUILD_PSW); \ - WriteW ((o) + 2, PC); \ - PSW = ReadW (n); \ - PC = ReadW ((n) + 2); \ - CC = PSW & CC_MASK - -uint16 M[MAXMEMSIZE >> 1] = { 0 }; /* memory */ -int32 R[16] = { 0 }; /* general registers */ -uint32 F[8] = { 0 }; /* fp registers */ -int32 PSW = 0; /* processor status word */ -int32 saved_PC = 0; /* program counter */ -int32 SR = 0; /* switch register */ -int32 DR = 0; /* display register */ -int32 drmod = 0; /* mode */ -int32 srpos = 0; /* switch register pos */ -int32 drpos = 0; /* display register pos */ -int32 int_req[INTSZ] = { 0 }; /* interrupt requests */ -int32 int_enb[INTSZ] = { 0 }; /* interrupt enables */ -t_bool qanyin = FALSE; /* interrupt outstanding */ -int32 stop_inst = 0; /* stop on ill inst */ -int32 ibkpt_addr = ILL_ADR_FLAG | AMASK; /* breakpoint addr */ -int32 old_PC = 0; /* previous PC */ - -extern int32 sim_int_char; -extern UNIT *sim_clock_queue; -t_bool int_eval (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); -t_stat cpu_svc (UNIT *uptr); -t_stat cpu_set_size (UNIT *uptr, int32 value); -extern int32 le (int32 op, int32 r1, int32 r2, int32 ea); -extern int32 ce (int32 op, int32 r1, int32 r2, int32 ea); -extern int32 ase (int32 op, int32 r1, int32 r2, int32 ea); -extern int32 me (int32 op, int32 r1, int32 r2, int32 ea); -extern int32 de (int32 op, int32 r1, int32 r2, int32 ea); -extern int32 display (int32 op, int32 datout); -extern int32 tt (int32 op, int32 datout); -extern int32 pt (int32 op, int32 datout); - -int32 (*dev_tab[DEVNO])(int32 op, int32 datout) = { - NULL, &display, &tt, &pt, NULL, NULL, NULL, NULL }; - -/* CPU data structures - - cpu_dev CPU device descriptor - cpu_unit CPU unit descriptor - cpu_reg CPU register list - cpu_mod CPU modifiers list -*/ - -UNIT cpu_unit = { UDATA (&cpu_svc, UNIT_FIX + UNIT_BINK, - MAXMEMSIZE) }; - -REG cpu_reg[] = { - { HRDATA (PC, saved_PC, 16) }, - { HRDATA (R0, R[0], 16) }, - { HRDATA (R1, R[1], 16) }, - { HRDATA (R2, R[2], 16) }, - { HRDATA (R3, R[3], 16) }, - { HRDATA (R4, R[4], 16) }, - { HRDATA (R5, R[5], 16) }, - { HRDATA (R6, R[6], 16) }, - { HRDATA (R7, R[7], 16) }, - { HRDATA (R8, R[8], 16) }, - { HRDATA (R9, R[9], 16) }, - { HRDATA (RA, R[10], 16) }, - { HRDATA (RB, R[11], 16) }, - { HRDATA (RC, R[12], 16) }, - { HRDATA (RD, R[13], 16) }, - { HRDATA (RE, R[14], 16) }, - { HRDATA (RF, R[15], 16) }, - { HRDATA (F0, F[0], 32) }, - { HRDATA (F2, F[1], 32) }, - { HRDATA (F4, F[2], 32) }, - { HRDATA (F6, F[3], 32) }, - { HRDATA (F8, F[4], 32) }, - { HRDATA (FA, F[5], 32) }, - { HRDATA (FC, F[6], 32) }, - { HRDATA (FE, F[7], 32) }, - { HRDATA (PSW, PSW, 16) }, - { HRDATA (CC, PSW, 4) }, - { HRDATA (SR, SR, 16) }, - { HRDATA (DR, DR, 16) }, - { GRDATA (DR1, DR, 16, 16, 16) }, - { FLDATA (DRMOD, drmod, 0) }, - { FLDATA (SRPOS, srpos, 0) }, - { HRDATA (DRPOS, drpos, 2) }, - { HRDATA (IRQ0, int_req[0], 32) }, - { HRDATA (IRQ1, int_req[1], 32) }, - { HRDATA (IRQ2, int_req[2], 32) }, - { HRDATA (IRQ3, int_req[3], 32) }, - { HRDATA (IRQ4, int_req[4], 32) }, - { HRDATA (IRQ5, int_req[5], 32) }, - { HRDATA (IRQ6, int_req[6], 32) }, - { HRDATA (IRQ7, int_req[7], 32) }, - { HRDATA (IEN0, int_enb[0], 32) }, - { HRDATA (IEN1, int_enb[1], 32) }, - { HRDATA (IEN2, int_enb[2], 32) }, - { HRDATA (IEN3, int_enb[3], 32) }, - { HRDATA (IEN4, int_enb[4], 32) }, - { HRDATA (IEN5, int_enb[5], 32) }, - { HRDATA (IEN6, int_enb[6], 32) }, - { HRDATA (IEN7, int_enb[7], 32) }, - { FLDATA (STOP_INST, stop_inst, 0) }, - { HRDATA (OLDPC, old_PC, 16), REG_RO }, - { HRDATA (BREAK, ibkpt_addr, 17) }, - { ORDATA (WRU, sim_int_char, 8) }, - { NULL } }; - -MTAB cpu_mod[] = { - { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size }, - { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size }, - { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size }, - { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size }, - { UNIT_MSIZE, 49152, NULL, "48K", &cpu_set_size}, - { UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size}, - { 0 } }; - -DEVICE cpu_dev = { - "CPU", &cpu_unit, cpu_reg, cpu_mod, - 1, 16, 16, 2, 16, 16, - &cpu_ex, &cpu_dep, &cpu_reset, - NULL, NULL, NULL }; - -t_stat sim_instr (void) -{ -extern int32 sim_interval; -int32 dev, i, j, r, t; -int32 PC, OP, R1, R2, EA, CC; -int32 inc, lim; -t_stat reason; - -/* Restore register state */ - -PC = saved_PC & AMASK; -CC = PSW & CC_MASK; /* isolate cond codes */ -qanyin = int_eval (); /* eval interrupts */ -reason = 0; - -/* Main instruction fetch/decode loop */ - -while (reason == 0) { /* loop until halted */ -if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) break; - qanyin = int_eval (); } - -if ((PSW & PSW_EXI) && qanyin) { /* interrupt? */ - PSW_SWAP (EXOPSW, EXNPSW); /* swap PSW */ - continue; } - -if (PSW & PSW_WAIT) { /* wait state? */ - if (sim_clock_queue != NULL) sim_interval = 0; /* force check */ - else reason = STOP_WAIT; - continue; } - -if (PC == ibkpt_addr) { /* breakpoint? */ - save_ibkpt = ibkpt_addr; /* save address */ - ibkpt_addr = ibkpt_addr | ILL_ADR_FLAG; /* disable */ - sim_activate (&cpu_unit, 1); /* sched re-enable */ - reason = STOP_IBKPT; /* stop simulation */ - break; } - -sim_interval = sim_interval - 1; -t = ReadW (PC); /* fetch instr */ -PC = (PC + 2) & AMASK; /* increment PC */ -OP = (t >> 8) & 0xFF; /* isolate op, R1, R2 */ -R1 = (t >> 4) & 0xF; -R2 = t & 0xF; -if (OP & OP_4B) { /* RX or RS? */ - EA = ReadW (PC); /* fetch address */ - PC = (PC + 2) & AMASK; /* increment PC */ - if (R2) EA = (EA + R[R2]) & AMASK; /* index calculation */ - } -else EA = R[R2]; /* RR? "EA" = reg content */ -switch (OP) { /* case on opcode */ - -/* Load/store instructions */ - -case 0x48: /* LH */ - EA = ReadW (EA); /* fetch operand */ -case 0x08: /* LHR */ -case 0xC8: /* LHI */ - R[R1] = EA; /* load operand */ - CC_GL (R[R1]); /* set G,L */ - break; - -case 0x40: /* STH */ - WriteW (EA, R[R1]); /* store register */ - break; - -case 0xD1: /* LM */ - for ( ; R1 <= 0xF; R1++) { /* loop thru reg */ - R[R1] = ReadW (EA); /* load register */ - EA = (EA + 2) & AMASK; } /* incr mem addr */ - break; - -case 0xD0: /* STM */ - for ( ; R1 <= 0xF; R1++) { /* loop thru reg */ - WriteW (EA, R[R1]); /* store register */ - EA = (EA + 2) & AMASK; } /* incr mem addr */ - break; - -case 0x93: /* LDBR */ - R[R1] = R[R2] & 0xFF; /* load byte */ - break; -case 0xD3: /* LDB */ - R[R1] = ReadB (EA); /* load byte */ - break; - -case 0x92: /* STBR */ - R[R2] = (R[R2] & ~0xFF) | (R[R1] & 0xFF); /* store byte */ - break; -case 0xD2: /* STB */ - WriteB (EA, R[R1] & 0xFF); /* store byte */ - break; - -/* Control instructions */ - -case 0x01: /* BALR */ -case 0x41: /* BAL */ - old_PC = R[R1] = PC; /* save cur PC */ - PC = EA; /* branch */ - break; - -case 0x02: /* BTCR */ -case 0x42: /* BTC */ - if (CC & R1) { /* test CC's */ - old_PC = PC; /* branch if true */ - PC = EA; } - break; - -case 0x03: /* BFCR */ -case 0x43: /* BFC */ - if ((CC & R1) == 0) { /* test CC's */ - old_PC = PC; /* branch if false */ - PC = EA; } - break; - -case 0xC0: /* BXH */ - inc = R[(R1 + 1) & 0xF]; /* inc = R1 + 1 */ - lim = R[(R1 + 2) & 0xF]; /* lim = R1 + 2 */ - R[R1] = (R[R1] + inc) & DMASK; /* or -? */ - if (R[R1] > lim) { /* if R1 > lim */ - old_PC = PC; /* branch */ - PC = EA; } - break; - -case 0xC1: /* BXLE */ - inc = R[(R1 + 1) & 0xF]; /* inc = R1 + 1 */ - lim = R[(R1 + 2) & 0xF]; /* lim = R1 + 2 */ - R[R1] = (R[R1] + inc) & DMASK; /* R1 = R1 + inc */ - if (R[R1] <= lim) { /* if R1 <= lim */ - old_PC = PC; /* branch */ - PC = EA; } - break; - -case 0xC2: /* LPSW */ - old_PC = PC; /* effective branch */ - PSW = ReadW (EA); /* read PSW/CC */ - CC = PSW & CC_MASK; /* separate CC */ - PC = ReadW ((EA + 2) & AMASK); /* read PC */ - break; - -/* Logical and shift instructions */ - -case 0x44: /* NH */ - EA = ReadW (EA); /* fetch operand */ -case 0x04: /* NHR */ -case 0xC4: /* NHI */ - R[R1] = R[R1] & EA; /* result */ - CC_GL (R[R1]); /* set G,L */ - break; - -case 0x46: /* OH */ - EA = ReadW (EA); /* fetch operand */ -case 0x06: /* OHR */ -case 0xC6: /* OHI */ - R[R1] = R[R1] | EA; /* result */ - CC_GL (R[R1]); /* set G,L */ - break; - -case 0x47: /* XH */ - EA = ReadW (EA); /* fetch operand */ -case 0x07: /* XHR */ -case 0xC7: /* XHI */ - R[R1] = R[R1] ^ EA; /* result */ - CC_GL (R[R1]); /* set G,L */ - break; - -case 0xCC: /* SRHL */ - t = EA & 0xF; /* shift count */ - r = R[R1] >> t; /* result */ - CC_GL (r); /* set G,L */ - if (t && ((R[R1] >> (t - 1)) & 1)) CC = CC | CC_C; - R[R1] = r; /* store result */ - break; - -case 0xCD: /* SLHL */ - t = EA & 0xF; /* shift count */ - r = R[R1] << t; /* result */ - R[R1] = r & DMASK; /* store masked result */ - CC_GL (R[R1]); /* set G,L */ - if (t && (r & 0x10000)) CC = CC_C; /* set C if shft out */ - break; - -case 0xCE: /* SRHA */ - t = EA & 0xF; /* shift count */ - r = (SIGN_EXT (R[R1]) >> t) & DMASK; /* result */ - CC_GL (r); /* set G,L */ - if (t && ((R[R1] >> (t - 1)) & 1)) CC = CC | CC_C; - R[R1] = r; /* store result */ - break; - -case 0xCF: /* SLHA */ - t = EA & 0xF; /* shift count */ - r = R[R1] << t; /* raw result */ - R[R1] = (R[R1] & SIGN) | (r & MAGMASK); /* arith result */ - CC_GL (R[R1]); /* set G,L */ - if (t && (r & SIGN)) CC = CC | CC_C; /* set C if shft out */ - break; - -/* Arithmetic instructions */ - -case 0x45: /* CLH */ - EA = ReadW (EA); /* fetch operand */ -case 0x05: /* CLHR */ -case 0xC5: /* CLHI */ - r = (R[R1] - EA) & DMASK; /* result */ - CC_GL (r); /* set G,L */ - if (R[R1] < EA) CC = CC | CC_C; /* set C if borrow */ - if (((R[R1] ^ EA) & (~R[R1] ^ r)) & SIGN) CC = CC | CC_V; - break; - -case 0x4A: /* AH */ - EA = ReadW (EA); /* fetch operand */ -case 0x0A: /* AHR */ -case 0xCA: /* AHI */ - r = (R[R1] + EA) & DMASK; /* result */ - CC_GL (r); /* set G,L */ - if (r < EA) CC = CC | CC_C; /* set C if carry */ - if (((~R[R1] ^ EA) & (R[R1] ^ r)) & SIGN) CC = CC | CC_V; - R[R1] = r; - break; - -case 0x4B: /* SH */ - EA = ReadW (EA); /* fetch operand */ -case 0x0B: /* SHR */ -case 0xCB: /* SHI */ - r = (R[R1] - EA) & DMASK; /* result */ - CC_GL (r); /* set G,L */ - if (R[R1] < EA) CC = CC | CC_C; /* set C if borrow */ - if (((R[R1] ^ EA) & (~R[R1] ^ r)) & SIGN) CC = CC | CC_V; - R[R1] = r; - break; - -case 0x4C: /* MH */ - EA = ReadW (EA); /* fetch operand */ -case 0x0C: /* MHR */ - r = SIGN_EXT (R[R1 | 1]) * SIGN_EXT (EA); /* multiply */ - R[R1] = (r >> 16) & DMASK; /* high result */ - R[R1 | 1] = r & DMASK; /* low result */ - break; - -case 0x4D: /* DH */ - EA = ReadW (EA); /* fetch operand */ -case 0x0D: /* DHR */ - r = (SIGN_EXT (R[R1]) << 16) | R[R1 | 1]; /* form 32b divd */ - if (EA) { /* if divisor != 0 */ - t = r / SIGN_EXT (EA); /* quotient */ - r = r % SIGN_EXT (EA); } /* remainder */ - if (EA && ((t < 0x8000) || (t >= -0x8000))) { /* if quo fits */ - R[R1] = r; /* store remainder */ - R[R1 | 1] = t; } /* store quotient */ - else if (PSW & PSW_DFI) { /* div fault enabled? */ - PSW_SWAP (IDOPSW, IDNPSW); } /* swap PSW */ - break; - -case 0x4E: /* ACH */ - EA = ReadW (EA); /* fetch operand */ -case 0x0E: /* ACHR */ - t = R[R1] + EA + ((CC & CC_C) != 0); /* raw result */ - r = t & 0xFFFF; /* masked result */ - CC_GL_C (r); /* set G,L */ - if (t > DMASK) CC = CC | CC_C; /* set C if carry */ - if (((~R[R1] ^ EA) & (R[R1] ^ r)) & SIGN) CC = CC | CC_V; - R[R1] = r; /* store result */ - break; - -case 0x4F: /* SCH */ - EA = ReadW (EA); /* fetch operand */ -case 0x0F: /* SCHR */ - t = R[R1] - EA - ((CC & CC_C) != 0); /* raw result */ - r = t & 0xFFFF; /* masked result */ - CC_GL_C (r); /* set G,L */ - if (t < 0) CC = CC | CC_C; /* set C if borrow */ - if (((R[R1] ^ EA) & (~R[R1] ^ t)) & 0x8000) CC = CC | CC_V; - R[R1] = r; /* store result */ - break; - -/* Floating point instructions */ - -case 0x68: /* LE */ -case 0x28: /* LER */ - CC = le (OP, R1, R2, EA); - break; - -case 0x69: /* CE */ -case 0x29: /* CER */ - CC = ce (OP, R1, R2, EA); - break; - -case 0x6A: /* AE */ -case 0x6B: /* SE */ -case 0x2A: /* AER */ -case 0x2B: /* SER */ - CC = ase (OP, R1, R2, EA); - break; - -case 0x6C: /* ME */ -case 0x2C: /* MER */ - CC = me (OP, R1, R2, EA); - break; - -case 0x6D: /* DE */ -case 0x2D: /* DER */ - t = de (OP, R1, R2, EA); /* perform divide */ - if (t >= 0) CC = t; /* if ok, set CC */ - else if (PSW & PSW_FDI) { /* else fault */ - PSW_SWAP (FDOPSW, FDNPSW); } /* swap PSW */ - break; - -case 0x60: /* STE */ - WriteW ((F[R1 >> 1] >> 16) & DMASK, EA); - WriteW (F[R1 >> 1] & DMASK, ((EA + 2) & AMASK)); - break; - -/* I/O instructions */ - -case 0xDE: /* OC */ - EA = ReadW (EA); /* fetch operand */ -case 0x9E: /* OCR */ - dev = R[R1] & DEV_MAX; - if (dev_tab[dev]) { - dev_tab[dev] (IO_ADR, EA); /* select */ - t = dev_tab[dev] (IO_OC, EA); /* send command */ - qanyin = int_eval (); /* re-eval intr */ - if (t & IOT_EXM) CC = CC_V; /* set V if err */ - else CC = 0; - reason = t >> IOT_V_REASON; } - else CC = CC_V; - break; - -case 0xDA: /* WD */ - EA = ReadW (EA); /* fetch operand */ -case 0x9A: /* WDR */ - dev = R[R1] & DEV_MAX; - if (dev_tab[dev]) { - dev_tab[dev] (IO_ADR, EA); /* select */ - t = dev_tab[dev] (IO_WD, EA); /* send data */ - qanyin = int_eval (); /* re-eval intr */ - if (t & IOT_EXM) CC = CC_V; /* set V if err */ - else CC = 0; - reason = t >> IOT_V_REASON; } - else CC = CC_V; - break; - -case 0xD6: /* WB */ -case 0x96: /* WBR */ - dev = R[R1] & DEV_MAX; - if (OP & OP_4B) { - EA = ReadW (EA); /* start */ - lim = ReadW ((EA + 2) & 0xFFFF); } /* end */ - else lim = R[(R2 + 1) & 0xF]; - if (dev_tab[dev]) { - dev_tab[dev] (IO_ADR, EA); /* select */ - for ( ; EA <= lim; EA = ((EA + 1) & 0xFFFF)) { - t = dev_tab[dev] (IO_WD, ReadB (EA)); - if (reason = t >> IOT_V_REASON) break; - t = dev_tab[dev] (IO_SS, 0); - if (CC = t & 0xF) break; } - qanyin = int_eval (); } /* re-eval intr */ - else CC = CC_V; - break; - -case 0xDB: /* RD */ -case 0x9B: /* RDR */ - dev = R[R1] & DEV_MAX; - if (dev_tab[dev]) { - dev_tab[dev] (IO_ADR, EA); /* select */ - t = dev_tab[dev] (IO_RD, 0); /* get data */ - qanyin = int_eval (); /* re-eval intr */ - if (OP & OP_4B) { /* RX or RR? */ - WriteB (EA, t & 0xFF); } - else R[R2] = t & 0xFF; - if (t & IOT_EXM) CC = CC_V; /* set V if err */ - else CC = 0; - reason = t >> IOT_V_REASON; } - else CC = CC_V; - break; - -case 0xD7: /* RB */ -case 0x97: /* RBR */ - dev = R[R1] & DEV_MAX; - if (OP & OP_4B) { - EA = ReadW (EA); /* start */ - lim = ReadW ((EA + 2) & 0xFFFF); } /* end */ - else lim = R[(R2 + 1) & 0xF]; - if (dev_tab[dev]) { - dev_tab[dev] (IO_ADR, EA); /* select */ - for ( ; EA <= lim; EA = ((EA + 1) & 0xFFFF)) { - t = dev_tab[dev] (IO_RD, 0); - WriteB (EA, t & 0xFF); - if (reason = t >> IOT_V_REASON) break; - t = dev_tab[dev] (IO_SS, 0); - if (CC = t & 0xF) break; } - qanyin = int_eval (); } /* re-eval intr */ - else CC = CC_V; - break; - -case 0xDF: /* AI */ -case 0x9F: /* AIR */ - for (i = t = 0; i < INTSZ; i++) { /* loop thru array */ - uint32 temp; - if (temp = int_req[i] & int_enb[i]) { /* loop thru word */ - for (j = 0; j < 32; j++) { - if (temp & INT_V(j)) break; - t = t + 1; } } - else t = t + 32; } - R[R1] = t & DEV_MAX; - CLR_INT (t & DEV_MAX); /* clear int req */ - /* fall through */ -case 0xDD: /* SS */ -case 0x9D: /* SSR */ - dev = R[R1] & DEV_MAX; - if (dev_tab[dev]) { - dev_tab[dev] (IO_ADR, EA); /* select */ - t = dev_tab[dev] (IO_SS, 0); /* get status */ - qanyin = int_eval (); /* re-eval intr */ - if (OP & OP_4B) { /* RR or RX? */ - WriteB (EA, t & 0xFF); } - else R[R2] = t & 0xFF; - CC = t & 0xF; - reason = t >> IOT_V_REASON; } - else CC = CC_V; - break; - -default: /* undefined */ - PC = (PC - ((OP & OP_4B)? 4: 2)) & AMASK; - if (reason = stop_inst) break; /* stop on undef? */ - PSW_SWAP (ILOPSW, ILNPSW); /* swap PSW */ - break; } /* end switch */ - } /* end while */ - -/* Simulation halted */ - -PSW = BUILD_PSW; -saved_PC = PC & AMASK; -return reason; -} - -/* Evaluate interrupt */ - -t_bool int_eval (void) -{ -int i; - -for (i = 0; i < INTSZ; i++) - if (int_req[i] & int_enb[i]) return TRUE; -return FALSE; -} - -/* Display register device */ - -int32 display (int32 op, int32 dat) -{ -int t; - -switch (op) { -case IO_ADR: /* select */ - drpos = srpos = 0; /* clear counters */ - break; -case IO_OC: /* command */ - op = op & 0xC0; - if (op == 0x40) drmod = 1; /* x40 = inc */ - else if (op == 0x80) drmod = 0; /* x80 = norm */ - else if (op == 0xC0) drmod = drmod ^ 1; /* xC0 = flip */ - break; -case IO_WD: /* write */ - DR = (DR & ~(0xFF << (drpos * 8))) | (dat << (drpos * 8)); - if (drmod) drpos = (drpos + 1) & 0x3; - break; -case IO_RD: /* read */ - t = (SR >> (srpos * 8)) & 0xFF; - srpos = srpos ^ 1; - return t; -case IO_SS: /* status */ - return 0x80; } -return 0; -} - -/* Reset routine */ - -t_stat cpu_reset (DEVICE *dptr) -{ -PSW = 0; -DR = 0; -drmod = 0; -return cpu_svc (&cpu_unit); -} - -/* 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 = ReadW (addr); -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; -WriteW (addr, val); -return SCPE_OK; -} - -/* Breakpoint service */ - -t_stat cpu_svc (UNIT *uptr) -{ -if ((ibkpt_addr & ~ILL_ADR_FLAG) == save_ibkpt) ibkpt_addr = save_ibkpt; -save_ibkpt = -1; -return SCPE_OK; -} - -t_stat cpu_set_size (UNIT *uptr, int32 value) -{ -int32 mc = 0; -t_addr i; - -if ((value <= 0) || (value > MAXMEMSIZE) || ((value & 0xFFF) != 0)) - return SCPE_ARG; -for (i = value; i < MEMSIZE; i++) mc = mc | M[i]; -if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) - return SCPE_OK; -MEMSIZE = value; -for (i = MEMSIZE; i < MAXMEMSIZE; i++) M[i] = 0; -return SCPE_OK; -} diff --git a/id4_defs.h b/id4_defs.h deleted file mode 100644 index 76b3bc39..00000000 --- a/id4_defs.h +++ /dev/null @@ -1,146 +0,0 @@ -/* id4_defs.h: Interdata 4 simulator definitions - - 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. - - 07-Oct-00 RMS Overhauled I/O subsystem - 14-Apr-99 RMS Changed t_addr to unsigned - - The author gratefully acknowledges the help of Carl Friend, who provided - key documents about the Interdata 4. Questions answered to date: - - 1. Do device interrupt enables mask interrupt requests or prevent - interrupt requests? A: Mask interrupt requests. - 2. Does SLHA set C from shift out of bit <0> or bit <1>? A: From <1>. - 3. What is the limit on device numbers? A: 256. How big must the - interrupt request and enable arrays be? A: 8 x 32b. - 4. Does BXH subtract or add the second argument? - 5. Do BXH and BXLE do a logical or arithmetic compare? A: Logical. - 6. Do ACH and SCH produce normal GL codes, or do they take into account - prior GL codes? -*/ - -#include "sim_defs.h" /* simulator defns */ - -/* Simulator stop codes */ - -#define STOP_RSRV 1 /* must be 1 */ -#define STOP_HALT 2 /* HALT */ -#define STOP_IBKPT 3 /* breakpoint */ -#define STOP_WAIT 4 /* wait */ - -/* Memory */ - -#define MAXMEMSIZE 65536 /* max memory size */ -#define MEMSIZE (cpu_unit.capac) /* actual memory size */ -#define AMASK (MAXMEMSIZE - 1) /* address mask */ -#define MEM_ADDR_OK(x) (((t_addr) (x)) < MEMSIZE) -#define ReadW(x) M[(x) >> 1] -#define WriteW(x,d) if (MEM_ADDR_OK (x)) M[(x) >> 1] = d -#define ReadB(x) ((M[(x) >> 1] >> (((x) & 1)? 0: 8)) & 0xFF) -#define WriteB(x,d) if (MEM_ADDR_OK (x)) M[(x) >> 1] = \ - (((x) & 1)? ((M[(x) >> 1] & ~0xFF) | (d)): \ - ((M[(x) >> 1] & 0xFF) | ((d) << 8))) - -/* Architectural constants */ - -#define SIGN 0x8000 /* sign bit */ -#define DMASK 0xFFFF /* data mask */ -#define MAGMASK 0x7FFF /* magnitude mask */ - -#define OP_4B 0x40 /* 2 byte vs 4 byte */ - -#define CC_C 0x8 /* carry */ -#define CC_V 0x4 /* overflow */ -#define CC_G 0x2 /* greater than */ -#define CC_L 0x1 /* less than */ -#define CC_MASK (CC_C | CC_V | CC_G | CC_L) - -#define PSW_WAIT 0x8000 /* wait */ -#define PSW_EXI 0x4000 /* ext intr enable */ -#define PSW_MCI 0x2000 /* machine check enable */ -#define PSW_DFI 0x1000 /* divide fault enable */ -#define PSW_FDI 0x0400 /* flt divide fault enable */ - -#define FDOPSW 0x28 /* flt div fault old PSW */ -#define FDNPSW 0x2C /* flt div fault new PSW */ -#define ILOPSW 0x30 /* illegal op old PSW */ -#define ILNPSW 0x34 /* illegal op new PSW */ -#define MCOPSW 0x38 /* machine check old PSW */ -#define MCNPSW 0x3C /* machine check new PSW */ -#define EXOPSW 0x40 /* external intr old PSW */ -#define EXNPSW 0x44 /* external intr new PSW */ -#define IDOPSW 0x48 /* int div fault old PSW */ -#define IDNPSW 0x4C /* int div fault new PSW */ - -/* I/O operations */ - -#define IO_ADR 0x0 /* address select */ -#define IO_RD 0x1 /* read */ -#define IO_WD 0x2 /* write */ -#define IO_OC 0x3 /* output command */ -#define IO_SS 0x5 /* sense status */ - -/* Device return codes: data byte is <7:0> */ - -#define IOT_V_EXM 8 /* set V flag */ -#define IOT_EXM (1u << IOT_V_EXM) -#define IOT_V_REASON 9 /* set reason */ - -/* Device command byte */ - -#define CMD_V_INT 6 /* interrupt control */ -#define CMD_M_INT 0x3 -#define CMD_IENB 1 /* enable */ -#define CMD_IDIS 2 /* disable */ -#define CMD_ICOM 3 /* complement */ -#define CMD_GETINT(x) (((x) >> CMD_V_INT) & CMD_M_INT) - -/* Device status byte */ - -#define STA_BSY 0x8 /* busy */ -#define STA_EX 0x4 /* examine status */ -#define STA_EOM 0x2 /* end of medium */ -#define STA_DU 0x1 /* device unavailable */ - -/* Device numbers */ - -#define DEV_LOW 0x01 /* lowest intr dev */ -#define DEV_MAX 0xFF /* highest intr dev */ -#define DEVNO (DEV_MAX + 1) /* number of devices */ -#define INTSZ ((DEVNO + 31) / 32) /* number of interrupt words */ -#define DS 0x01 /* display and switches */ -#define TT 0x02 /* teletype */ -#define PT 0x03 /* paper tape */ -#define CD 0x04 /* card reader */ - -/* I/O macros */ - -#define INT_V(d) (1u << ((d) & 0x1F)) -#define SET_INT(d) int_req[(d)/32] = int_req[(d)/32] | INT_V (d) -#define CLR_INT(d) int_req[(d)/32] = int_req[(d)/32] & ~INT_V (d) -#define SET_ENB(d) int_enb[(d)/32] = int_enb[(d)/32] | INT_V (d) -#define COM_ENB(d) int_enb[(d)/32] = int_enb[(d)/32] ^ INT_V (d) -#define CLR_ENB(d) int_enb[(d)/32] = int_enb[(d)/32] & ~INT_V (d) - -#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */ diff --git a/id4_fp.c b/id4_fp.c deleted file mode 100644 index 20f36bf4..00000000 --- a/id4_fp.c +++ /dev/null @@ -1,277 +0,0 @@ -/* id4_fp.c: Interdata 4 floating point instructions - - 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. - - The Interdata 4 uses IBM 360 single precision floating point format: - - 0 7 8 15 23 31 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |S| exponent | fraction | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - where S = 0 for plus, 1 for minus - exponent = 16**n, in excess 64 code - fraction = .hhhhhh, seen as 6 hexadecimal digits - - Numbers could be normalized or unnormalized but are always normalized - when loaded. - - The Interdata 4 has 8 floating point registers, F0, F2, ... , FE. - In floating point instructions, the low order bit of the register - specification is ignored. - - On floating point overflow, the exponent and fraction are set to 1's. - On floating point underflow, the exponent and fraction are set to 0's. -*/ - -#include "id4_defs.h" - -struct ufp { /* unpacked fp */ - int32 sign; /* sign */ - int32 exp; /* unbiased exp */ - unsigned int32 frh; /* fr high */ - unsigned int32 frl; }; /* fr low */ - -#define FP_V_SIGN 31 /* sign */ -#define FP_M_SIGN 0x1 -#define FP_GETSIGN(x) (((x) >> FP_V_SIGN) & FP_M_SIGN) -#define FP_V_EXP 24 /* exponent */ -#define FP_M_EXP 0x7F -#define FP_GETEXP(x) (((x) >> FP_V_EXP) & FP_M_EXP) -#define FP_V_FRH 0 /* fraction */ -#define FP_M_FRH 0xFFFFFF -#define FP_GETFRH(x) (((x) >> FP_V_FRH) & FP_M_FRH) - -#define FP_BIAS 0x40 /* exp bias */ -#define FP_CARRY (1 << FP_V_EXP ) /* carry out */ -#define FP_NORM (0xF << (FP_V_EXP - 4)) /* normalized */ -#define FP_ROUND 0x80000000 -#define FP_DMASK 0xFFFFFFFF - -/* Variable and constant shifts; for constants, 0 < k < 32 */ - -#define FP_SHFR_V(v,s) if ((s) < 32) { \ - v.frl = ((v.frl >> (s)) | \ - (v.frh << (32 - (s)))) & FP_DMASK; \ - v.frh = (v.frh >> (s)) & FP_DMASK; } \ - else { v.frl = v.frh >> ((s) - 32); \ - v.frh = 0; } -#define FP_SHFR_K(v,s) v.frl = ((v.frl >> (s)) | \ - (v.frh << (32 - (s)))) & FP_DMASK; \ - v.frh = (v.frh >> (s)) & FP_DMASK - -extern int32 R[16]; -extern uint32 F[8]; -extern uint16 M[]; -void ReadFP2 (struct ufp *fop, int32 op, int32 r2, int32 ea); -void UnpackFP (struct ufp *fop, unsigned int32 val); -void NormFP (struct ufp *fop); -int32 StoreFP (struct ufp *fop, int32 r1); - -/* Floating point load */ - -int32 le (op, r1, r2, ea) -{ -struct ufp fop2; - -ReadFP2 (&fop2, op, r2, ea); /* get op, normalize */ -return StoreFP (&fop2, r1); /* store, chk unflo */ -} - -/* Floating point compare */ - -int32 ce (op, r1, r2, ea) -{ -struct ufp fop1, fop2; - -ReadFP2 (&fop2, op, r2, ea); /* get op2, normalize */ -UnpackFP (&fop1, F[r1 >> 1]); /* get op1 */ -if (fop1.sign ^ fop2.sign) /* signs differ? */ - return (fop2.sign? CC_G: CC_L); -if (fop1.exp != fop2.exp) /* exps differ? */ - return (((fop1.exp > fop2.exp) ^ fop1.sign)? CC_G: CC_L); -if (fop1.frh != fop2.frh) /* fracs differ? */ - return (((fop1.frh > fop2.frh) ^ fop1.sign)? CC_G: CC_L); -return 0; -} - -/* Floating point add/subtract */ - -int32 ase (op, r1, r2, ea) -{ -struct ufp fop1, fop2, t; -int32 ediff; - -ReadFP2 (&fop2, op, r2, ea); /* get op2, normalize */ -UnpackFP (&fop1, F[r1 >> 1]); /* get op1 */ -if (op & 1) fop2.sign = fop2.sign ^ 1; /* if sub, inv sign2 */ -if (fop1.frh == 0) fop1 = fop2; /* if op1 = 0, res = op2 */ -else if (fop2.frh != 0) { /* if op2 = 0, no add */ - if ((fop1.exp < fop2.exp) || ((fop1.exp == fop2.exp) && - (fop1.frh < fop2.frh))) { /* |op1| < |op2|? */ - t = fop2; /* swap operands */ - fop2 = fop1; - fop1 = t; } - if (ediff = fop1.exp - fop2.exp) { /* exp differ? */ - if (ediff > 14) fop2.frh = 0; /* limit shift */ - else { FP_SHFR_V (fop2, ediff * 4); } } - if (fop1.sign ^ fop2.sign) { /* eff subtract */ - fop1.frl = 0 - fop2.frl; /* sub fractions */ - fop1.frh = fop1.frh - fop2.frh - (fop1.frl != 0); - NormFP (&fop1); } /* normalize result */ - else { fop1.frl = fop2.frl; /* add fractions */ - fop1.frh = fop1.frh + fop2.frh; - if (fop1.frh & FP_CARRY) { /* carry out? */ - FP_SHFR_K (fop1, 4); /* renormalize */ - fop1.exp = fop1.exp + 1; } } /* incr exp */ - } /* end if fop2 */ -return StoreFP (&fop1, r1); /* store result */ -} - -/* Floating point multiply - - Note that the 24b * 24b multiply yields 2 extra hex digits of 0, - which are accounted for by biasing the normalize count - */ - -int32 me (op, r1, r2, ea) -{ -struct ufp fop1, fop2; -unsigned int32 hi1, hi2, mid, lo1, lo2; - -ReadFP2 (&fop2, op, r2, ea); /* get op2, norm */ -UnpackFP (&fop1, F[r1 >> 1]); /* get op1 */ -if (fop1.frh && fop2.frh) { /* if both != 0 */ - fop1.sign = fop1.sign ^ fop2.sign; /* sign = diff */ - fop1.exp = fop1.exp + fop2.exp - FP_BIAS + 2; /* exp = sum */ - hi1 = (fop1.frh >> 16) & 0xFF; /* 24b * 24b */ - hi2 = (fop2.frh >> 16) & 0xFF; /* yields 48b */ - lo1 = fop1.frh & 0xFFFF; /* 32b */ - lo2 = fop2.frh & 0xFFFF; /* 16b */ - fop1.frl = lo1 * lo2; /* 25b */ - mid = (hi1 * lo2) + (lo1 * hi2); - fop1.frh = hi1 * hi2; - fop1.frl = fop1.frl + ((mid << 16) & FP_DMASK); - fop1.frh = fop1.frh + (mid >> 8) + (fop1.frl < ((mid << 16) & FP_DMASK)); - NormFP (&fop1); /* normalize */ - return StoreFP (&fop1, r1); } /* store result */ -else F[r1 >> 0] = 0; /* result = 0 */ -return 0; -} - -/* Floating point divide */ - -int32 de (op, r1, r2, ea) -{ -struct ufp fop1, fop2; -int32 i; -unsigned int32 divd; - -ReadFP2 (&fop2, op, r2, ea); /* get op2, norm */ -UnpackFP (&fop1, F[r1 >> 1]); /* get op1 */ -if (fop2.frh == 0) return -1; /* div by zero? */ -if (fop1.frh) { /* dvd != 0? */ - fop1.sign = fop1.sign ^ fop2.sign; /* sign = diff */ - fop1.exp = fop1.exp - fop2.exp + FP_BIAS; /* exp = diff */ - if (fop1.frh >= fop2.frh) divd = fop1.frh; /* 1st sub ok? */ - else { divd = fop1.frh << 4; /* ensure success */ - fop1.exp = fop1.exp - 1; } - for (i = fop1.frh = 0; i < 6; i++) { /* 6 hex digits */ - fop1.frh = fop1.frh << 4; /* shift quotient */ - while (divd >= fop2.frh) { /* while sub works */ - divd = divd - fop2.frh; /* decrement */ - fop1.frh = fop1.frh + 1; } /* add quo bit */ - divd = divd << 4; } /* shift divd */ - if (divd >= (fop2.frh << 3)) fop1.frl = FP_ROUND; - /* don't need to normalize */ - } /* end if fop1.frh */ -return StoreFP (&fop1, r1); /* store result */ -} - -/* Utility routines */ - -/* Unpack floating point number */ - -void UnpackFP (struct ufp *fop, unsigned int32 val) -{ -fop -> frl = 0; /* low frac zero */ -if (fop -> frh = FP_GETFRH (val)) { /* any fraction? */ - fop -> sign = FP_GETSIGN (val); /* get sign */ - fop -> exp = FP_GETEXP (val); /* get exp */ - NormFP (fop); } /* normalize */ -else fop -> sign = fop -> exp = 0; /* clean zero */ -return; -} - -/* Read memory operand */ - -void ReadFP2 (struct ufp *fop, int32 op, int32 r2, int32 ea) -{ -unsigned int32 t; - -if (op & OP_4B) /* RX? */ - t = (ReadW (ea) << 16) | ReadW ((ea + 2) & AMASK); -else t = F[r2 >> 1]; /* RR */ -UnpackFP (fop, t); /* unpack op */ -return; -} - -/* Normalize unpacked floating point number */ - -void NormFP (struct ufp *fop) -{ -if (fop -> frh || fop -> frl) { /* any fraction? */ - while ((fop -> frh & FP_NORM) == 0) { /* until norm */ - fop -> frh = (fop -> frh << 4) | ((fop -> frl >> 28) & 0xF); - fop -> frl = fop -> frl << 4; - fop -> exp = fop -> exp - 1; } } -else fop -> sign = fop -> exp = 0; /* clean 0 */ -return; -} - -/* Round fp number, store, generate condition codes */ - -int32 StoreFP (struct ufp *fop, int32 r1) -{ -if (fop -> frl & FP_ROUND) { /* round bit set? */ - fop -> frh = fop -> frh + 1; /* add 1 to frac */ - if (fop -> frh & FP_CARRY) { /* carry out? */ - fop -> frh = fop -> frh >> 4; /* renormalize */ - fop -> exp = fop -> exp + 1; } } /* incr exp */ -if (fop -> frh == 0) { /* result 0? */ - F[r1 >> 1] = 0; /* store clean 0 */ - return 0; } -if (fop -> exp <= 0) { /* underflow? */ - F[r1 >> 1] = 0; /* store clean 0 */ - return CC_V; } -if (fop -> exp > FP_M_EXP) { /* overflow? */ - F[r1 >> 1] = (fop -> sign)? 0xFFFFFFFF: 0x3FFFFFFF; - return (CC_V | ((fop -> sign)? CC_L: CC_G)); } -F[r1 >> 1] = ((fop -> sign & FP_M_SIGN) << FP_V_SIGN) | /* pack result */ - ((fop -> exp & FP_M_EXP) << FP_V_EXP) | - ((fop -> frh & FP_M_FRH) << FP_V_FRH); -if (fop -> sign) return CC_L; /* generate cc's */ -if (F[r1 >> 1]) return CC_G; -return 0; -} diff --git a/id4_stddev.c b/id4_stddev.c deleted file mode 100644 index 73e053e7..00000000 --- a/id4_stddev.c +++ /dev/null @@ -1,407 +0,0 @@ -/* id4_stddev.c: Interdata 4 standard devices - - 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. - - pt paper tape reader and punch - tt console - cdr card reader -*/ - -#include "id4_defs.h" -#include -#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */ -#define UNIT_UC (1 << UNIT_V_UC) - -extern uint16 M[]; -extern int32 int_req[INTSZ], int_enb[INTSZ]; -int32 pt_run = 0, pt_slew = 0; /* ptr modes */ -int pt_rw = 0, pt_busy = 0; /* pt state */ -int32 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */ -int32 tt_hdpx = 0; /* tt mode */ -int32 tt_rw = 0, tt_busy = 0; /* tt state */ -t_stat ptr_svc (UNIT *uptr); -t_stat ptp_svc (UNIT *uptr); -t_stat pt_boot (int32 unitno); -t_stat pt_reset (DEVICE *dptr); -t_stat tti_svc (UNIT *uptr); -t_stat tto_svc (UNIT *uptr); -t_stat tt_reset (DEVICE *dptr); -extern t_stat sim_poll_kbd (void); -extern t_stat sim_putchar (int32 out); - -/* Device definitions */ - -#define PTR 0 -#define PTP 1 -#define PT_STA_OVFL 0x80 /* overflow */ -#define PT_STA_NMTN 0x10 /* no motion */ - -#define PT_V_RUN 4 /* run/stop */ -#define PT_M_RUN 0x3 -#define PT_RUN 1 -#define PT_STOP 2 -#define PT_CRS 3 -#define PT_GETRUN(x) (((x) >> PT_V_RUN) & PT_M_RUN) - -#define PT_V_SLEW 2 /* slew/step */ -#define PT_M_SLEW 0x3 -#define PT_SLEW 1 -#define PT_STEP 2 -#define PT_CSLEW 3 -#define PT_GETSLEW(x) (((x) >> PT_V_SLEW) & PT_M_SLEW) - -#define PT_V_RW 0 /* read/write */ -#define PT_M_RW 0x3 -#define PT_RD 1 -#define PT_WD 2 -#define PT_CRW 3 -#define PT_GETRW(x) (((x) >> PT_V_RW) & PT_M_RW) - -#define TTI 0 -#define TTO 1 -#define TT_V_DPX 4 /* half/full duplex */ -#define TT_M_DPX 0x3 -#define TT_FDPX 1 -#define TT_HDPX 2 -#define TT_CDPX 3 -#define TT_GETDPX(x) (((x) >> TT_V_DPX) & TT_M_DPX) - -#define TT_V_RW 2 /* read/write */ -#define TT_M_RW 0x3 -#define TT_RD 1 -#define TT_WD 2 -#define TT_CRW 3 -#define TT_GETRW(x) (((x) >> TT_V_RW) & TT_M_RW) - -/* PT data structures - - pt_dev PT device descriptor - pt_unit PT unit descriptors - pt_reg PT register list -*/ - -UNIT pt_unit[] = { - { UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_IN_WAIT }, - { UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT } -}; - -REG pt_reg[] = { - { HRDATA (RBUF, pt_unit[PTR].buf, 8) }, - { DRDATA (RPOS, pt_unit[PTR].pos, 31), PV_LEFT }, - { DRDATA (RTIME, pt_unit[PTR].wait, 24), PV_LEFT }, - { FLDATA (RSTOP_IOE, ptr_stopioe, 0) }, - { HRDATA (PBUF, pt_unit[PTP].buf, 8) }, - { DRDATA (PPOS, pt_unit[PTP].pos, 31), PV_LEFT }, - { DRDATA (PTIME, pt_unit[PTP].wait, 24), PV_LEFT }, - { FLDATA (PSTOP_IOE, ptp_stopioe, 0) }, - { FLDATA (IREQ, int_req[PT/32], PT & 0x1F) }, - { FLDATA (IENB, int_enb[PT/32], PT & 0x1F) }, - { FLDATA (RUN, pt_run, 0) }, - { FLDATA (SLEW, pt_slew, 0) }, - { FLDATA (BUSY, pt_busy, 0) }, - { FLDATA (RW, pt_rw, 0) }, - { NULL } }; - -DEVICE pt_dev = { - "PT", pt_unit, pt_reg, NULL, - 2, 10, 31, 1, 8, 8, - NULL, NULL, &pt_reset, - &pt_boot, NULL, NULL }; - -/* TT data structures - - tt_dev TT device descriptor - tt_unit TT unit descriptors - tt_reg TT register list - tt_mod TT modifiers list -*/ - -UNIT tt_unit[] = { - { UDATA (&tti_svc, UNIT_UC, 0), KBD_POLL_WAIT }, - { UDATA (&tto_svc, UNIT_UC, 0), SERIAL_OUT_WAIT } -}; - -REG tt_reg[] = { - { HRDATA (KBUF, tt_unit[TTI].buf, 8) }, - { DRDATA (KPOS, tt_unit[TTI].pos, 31), PV_LEFT }, - { DRDATA (KTIME, tt_unit[TTI].wait, 24), REG_NZ + PV_LEFT }, - { HRDATA (TBUF, tt_unit[TTO].buf, 8) }, - { DRDATA (TPOS, tt_unit[TTO].pos, 31), PV_LEFT }, - { DRDATA (TTIME, tt_unit[TTO].wait, 24), REG_NZ + PV_LEFT }, - { FLDATA (IREQ, int_req[TT/32], TT & 0x1F) }, - { FLDATA (IENB, int_enb[TT/32], TT & 0x1F) }, - { FLDATA (HDPX, tt_hdpx, 0) }, - { FLDATA (BUSY, tt_busy, 0) }, - { FLDATA (RW, tt_rw, 0) }, - { FLDATA (UC, tt_unit[TTI].flags, UNIT_V_UC), REG_HRO }, - { NULL } }; - -MTAB tt_mod[] = { - { UNIT_UC, 0, "lower case", "LC", NULL }, - { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, - { 0 } }; - -DEVICE tt_dev = { - "TT", tt_unit, tt_reg, tt_mod, - 2, 10, 31, 1, 8, 8, - NULL, NULL, tt_reset, - NULL, NULL, NULL }; - -/* Paper tape: IO routine */ - -int32 pt (int32 op, int32 dat) -{ -int32 t; - -switch (op) { /* case IO op */ -case IO_ADR: /* select */ - break; -case IO_OC: /* command */ - t = CMD_GETINT (dat); /* get enable */ - if (t == CMD_IENB) SET_ENB (PT); /* process */ - else if (t == CMD_IDIS) CLR_ENB (PT); - else if (t == CMD_ICOM) COM_ENB (PT); - t = PT_GETRUN (dat); /* run/stop */ - if (t == PT_RUN) pt_run = 1; /* process */ - else if (t == PT_STOP) pt_run = 0; - else if (t == PT_CRS) pt_run = pt_run ^ 1; - t = PT_GETSLEW (dat); /* slew/step */ - if (t == PT_SLEW) pt_slew = 1; /* process */ - else if (t == PT_STEP) pt_slew = 0; - else if (t == PT_CSLEW) pt_slew = pt_slew ^ 1; - t = PT_GETRW (dat); /* read/write */ - if (t == PT_RD) pt_rw = 0; /* process */ - else if (t == PT_WD) pt_rw = 1; - else if (t == PT_CRW) pt_rw = pt_rw ^ 1; - if ((pt_rw == 0) && pt_run) /* read + run? */ - sim_activate (&pt_unit[PTR], pt_unit[PTR].wait); - if (sim_is_active (&pt_unit[pt_rw? PTP: PTR])) pt_busy = 1; - else { if (pt_busy) SET_INT (PT); - pt_busy = 0; } - break; -case IO_RD: /* read */ - if (pt_run && !pt_slew) - sim_activate (&pt_unit[PTR], pt_unit[PTR].wait); - if (pt_rw == 0) pt_busy = 1; - return (pt_unit[PTR].buf & 0xFF); -case IO_WD: /* write */ - pt_unit[PTP].buf = dat & 0xFF; - sim_activate (&pt_unit[PTP], pt_unit[PTP].wait); - if (pt_rw) pt_busy = 1; - break; -case IO_SS: /* status */ - t = pt_busy? STA_BSY: 0; - if ((pt_unit[PTR].flags & UNIT_ATT) == 0) t = t | STA_DU; - if (!sim_is_active (&pt_unit[PTR])) t = t | PT_STA_NMTN | STA_EX; - return t; } -return 0; -} - -/* Unit service */ - -t_stat ptr_svc (UNIT *uptr) -{ -int32 temp; - -if ((pt_unit[PTR].flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (ptr_stopioe, SCPE_UNATT); -if (pt_rw == 0) { /* read mode? */ - if (pt_busy) SET_INT (PT); /* if busy, intr */ - pt_busy = 0; } /* not busy */ -if (pt_slew) sim_activate (&pt_unit[PTR], pt_unit[PTR].wait); /* slew? */ -if ((temp = getc (pt_unit[PTR].fileref)) == EOF) { - if (feof (pt_unit[PTR].fileref)) { - if (ptr_stopioe) printf ("PTR end of file\n"); - else return SCPE_OK; } - else perror ("PTR I/O error"); - clearerr (pt_unit[PTR].fileref); - return SCPE_IOERR; } -pt_unit[PTR].buf = temp & 0xFF; -pt_unit[PTR].pos = pt_unit[PTR].pos + 1; -return SCPE_OK; -} - -t_stat ptp_svc (UNIT *uptr) -{ -if ((pt_unit[PTP].flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (ptp_stopioe, SCPE_UNATT); -if (pt_rw) { /* write mode? */ - if (pt_busy) SET_INT (PT); /* if busy, intr */ - pt_busy = 0; } /* not busy */ -if (putc (pt_unit[PTP].buf, pt_unit[PTP].fileref) == EOF) { - perror ("PTP I/O error"); - clearerr (pt_unit[PTP].fileref); - return SCPE_IOERR; } -pt_unit[PTP].pos = pt_unit[PTP].pos + 1; -return SCPE_OK; -} - -/* Bootstrap routine */ - -#define BOOT_START 0x3E -#define BOOT_LEN (sizeof (boot_rom) / sizeof (unsigned int16)) - -static const unsigned int16 boot_rom[] = { - 0xC820, /* START: LHI 2,80 */ - 0x0080, - 0xC830, /* LHI 3,1 */ - 0x0001, - 0xC840, /* LHI 4,CF */ - 0x00CF, - 0xD3A0, /* LB A,78 */ - 0x0078, - 0xDEA0, /* OC A,79 */ - 0x0079, - 0x9DAE, /* LOOP: SSR A,E */ - 0x42F0, /* BTC F,LOOP */ - 0x0052, - 0x9BAE, /* RDR A,E */ - 0x08EE, /* LHR E,E */ - 0x4330, /* BZ LOOP */ - 0x0052, - 0x4300, /* BR STORE */ - 0x006C, - 0x9DAE, /* LOOP1: SSR A,E */ - 0x42F0, /* BTC F,LOOP1 */ - 0x0064, - 0x9BAE, /* RDR A,E */ - 0xD2E2, /* STORE: STB E,0(2) */ - 0x0000, - 0xC120, /* BXLE 2,LOOP1 */ - 0x0064, - 0x4300, /* BR 80 */ - 0x0080, - 0x0395, /* HS PAPER TAPE INPUT */ - 0x039A, /* HS PAPER TAPE OUTPUT */ - 0x0420, /* CARD INPUT TO ASSEMBLER */ - 0x0298 /* TELEPRINTER OUTPUT FOR ASSEMBLER */ -}; - -t_stat pt_boot (int32 unitno) -{ -int32 i; -extern int32 saved_PC; - -for (i = 0; i < BOOT_LEN; i++) M[(BOOT_START >> 1) + i] = boot_rom[i]; -saved_PC = BOOT_START; -return SCPE_OK; -} - -/* Reset routine */ - -t_stat pt_reset (DEVICE *dptr) -{ -sim_cancel (&pt_unit[PTR]); /* deactivate units */ -sim_cancel (&pt_unit[PTP]); -pt_busy = pt_run = pt_slew = pt_rw = 0; -return SCPE_OK; -} - -/* Terminal: IO routine */ - -int32 tt (int32 op, int32 dat) -{ -int32 t, old_tt_rw; - -switch (op) { /* case IO op */ -case IO_ADR: /* select */ - break; -case IO_OC: /* command */ - t = CMD_GETINT (dat); /* get enable */ - if (t == CMD_IENB) SET_ENB (TT); /* process */ - else if (t == CMD_IDIS) CLR_ENB (TT); - else if (t == CMD_ICOM) COM_ENB (TT); - t = TT_GETDPX (dat); /* get duplex */ - if (t == TT_FDPX) tt_hdpx = 0; /* process */ - else if (t == TT_HDPX) tt_hdpx = 1; - else if (t == TT_CDPX) tt_hdpx = tt_hdpx ^ 1; - t = TT_GETRW (dat); /* read/write */ - old_tt_rw = tt_rw; - if (t == TT_RD) tt_rw = 0; /* process */ - else if (t == TT_WD) tt_rw = 1; - else if (t == TT_CRW) tt_rw = tt_rw ^ 1; - if (tt_rw == 0) { /* read? */ - if (old_tt_rw != 0) tt_busy = 1; } /* chg? set busy */ - else { if (sim_is_active (&tt_unit[TTO])) tt_busy = 1; - else { if (tt_busy) SET_INT (TT); - tt_busy = 0; } } - break; -case IO_RD: /* read */ - if (tt_rw == 0) tt_busy = 1; - return (tt_unit[TTI].buf & 0xFF); -case IO_WD: /* write */ - tt_unit[TTO].buf = dat & 0xFF; - sim_activate (&tt_unit[TTO], tt_unit[TTO].wait); - if (pt_rw) tt_busy = 1; - break; -case IO_SS: /* status */ - t = tt_busy? STA_BSY: 0; - return t; } -return 0; -} - -/* Unit service routines */ - -t_stat tti_svc (UNIT *uptr) -{ -int32 temp; - -sim_activate (&tt_unit[TTI], tt_unit[TTI].wait); /* continue poll */ -if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */ -if (tt_rw == 0) { /* read mode? */ - if (tt_busy) SET_INT (TT); /* if busy, intr */ - tt_busy = 0; } /* not busy */ -temp = temp & 0x7F; -if ((tt_unit[TTI].flags & UNIT_UC) && islower (temp)) - temp = toupper (temp); -tt_unit[TTI].buf = temp | 0x80; /* got char */ -tt_unit[TTI].pos = tt_unit[TTI].pos + 1; -if (tt_hdpx) { /* half duplex? */ - sim_putchar (temp); /* write char */ - tt_unit[TTO].pos = tt_unit[TTO].pos + 1; } -return SCPE_OK; -} - -t_stat tto_svc (UNIT *uptr) -{ -int32 temp; - -if (tt_rw) { /* write mode? */ - if (tt_busy) SET_INT (TT); /* if was busy, intr */ - tt_busy = 0; } /* not busy */ -if ((temp = sim_putchar (tt_unit[TTO].buf & 0177)) != SCPE_OK) return temp; -tt_unit[TTO].pos = tt_unit[TTO].pos + 1; -return SCPE_OK; -} - -/* Reset routine */ - -t_stat tt_reset (DEVICE *dptr) -{ -sim_activate (&tt_unit[TTI], tt_unit[TTI].wait); /* activate input */ -sim_cancel (&tt_unit[TTO]); /* cancel output */ -tt_hdpx = tt_rw = 0; -tt_busy = 1; /* no kbd input yet */ -return SCPE_OK; -} diff --git a/id4_sys.c b/id4_sys.c deleted file mode 100644 index 7ebaf25a..00000000 --- a/id4_sys.c +++ /dev/null @@ -1,322 +0,0 @@ -/* id4_sys.c: Interdata 4 simulator interface - - 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. - - 17-Sep-01 RMS Removed multiconsole support - 17-Jul-01 RMS Fixed warning from VC++ 6.0 - 27-May-01 RMS Added multiconsole support - 14-Mar-01 RMS Revised load/dump interface (again) - 30-Oct-00 RMS Added support for examine to file - 27-Oct-98 RMS V2.4 load interface -*/ - -#include "id4_defs.h" -#include - -extern DEVICE cpu_dev; -extern DEVICE pt_dev, tt_dev; -extern UNIT cpu_unit; -extern REG cpu_reg[]; -extern uint16 *M; -extern int32 saved_PC; - -/* SCP data structures and interface routines - - sim_name simulator name string - sim_PC pointer to saved PC register descriptor - sim_emax number of words for examine - sim_devices array of pointers to simulated devices - sim_stop_messages array of pointers to stop messages - sim_load binary loader -*/ - -char sim_name[] = "Interdata 4"; - -REG *sim_PC = &cpu_reg[0]; - -int32 sim_emax = 2; - -DEVICE *sim_devices[] = { &cpu_dev, - &pt_dev, &tt_dev, - NULL }; - -const char *sim_stop_messages[] = { - "Unknown error", - "Reserved instruction", - "HALT instruction", - "Breakpoint", - "Wait state" }; - -/* Binary loader. - - To be specified -*/ - -t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) -{ -return SCPE_FMT; /* unexpected eof */ -} - -/* Symbol tables */ - -#define I_V_FL 16 /* class bits */ -#define I_M_FL 07 /* class mask */ -#define I_V_MR 0 /* mask-register */ -#define I_V_RR 1 /* register-register */ -#define I_V_R 2 /* register */ -#define I_V_MX 3 /* mask-memory */ -#define I_V_RX 4 /* register-memory */ -#define I_V_X 5 /* memory */ -#define I_V_FF 6 /* float reg-reg */ -#define I_V_FX 7 /* float reg-mem */ -#define I_MR (I_V_MR << I_V_FL) -#define I_RR (I_V_RR << I_V_FL) -#define I_R (I_V_R << I_V_FL) -#define I_MX (I_V_MX << I_V_FL) -#define I_RX (I_V_RX << I_V_FL) -#define I_X (I_V_X << I_V_FL) -#define I_FF (I_V_FF << I_V_FL) -#define I_FX (I_V_FX << I_V_FL) - -static const int32 masks[] = -{ 0xFFF0, 0xFF00, 0xFFF0, 0xFF00, - 0xFF00, 0xFFF0, 0xFF00, 0xFF00 }; - -static const char *opcode[] = { -"BZ", "BNZ", "BE", "BNE", -"BP", "BNP", "BL", "BNL", -"BM", "BNM", "BO", "BC", -"B", "BR", - "BALR","BTCR","BFCR", -"NHR", "CLHR","OHR", "XHR", -"LHR", "AHR", "SHR", -"MHR", "DHR", "ACHR","SCHR", -"LER", "CER", "AER", "SER", -"MER", "DER", - "BAL", "BTC", "BFC", -"NH", "CLH", "OH", "XH", -"LH", "AH", "SH", -"MH", "DH", "ACH", "SCH", -"STE", -"LE", "CE", "AE", "SE", -"ME", "DE", - "STBR","LBR", - "WBR", "RBR", - "WDR", "RDR", - "SSR", "OCR", "AIR", -"BXH", "BXLE","LPSW", -"NHI", "CLHI","OHI", "XHI", -"LHI", "AHI", "SHI", -"SRHL","SLHL","SRHA","SLHA", -"STM", "LM", "STB", "LB", - "AL", "WB", "RB", - "WD", "RD", - "SS", "OC", "AI", -NULL }; - -static const int32 opc_val[] = { -0x4330+I_X, 0x4230+I_X, 0x4330+I_X, 0x4230+I_X, -0x4220+I_X, 0x4320+I_X, 0x4280+I_X, 0x4380+I_X, -0x4210+I_X, 0x4310+I_X, 0x4240+I_X, 0x4280+I_X, -0x4300+I_X, 0x0300+I_R, - 0x0100+I_RR, 0x0200+I_MR, 0x0300+I_MR, -0x0400+I_RR, 0x0500+I_RR, 0x0600+I_RR, 0x0700+I_RR, -0x0800+I_RR, 0x0A00+I_RR, 0x0B00+I_RR, -0x0C00+I_RR, 0x0D00+I_RR, 0x0E00+I_RR, 0x0F00+I_RR, -0x2800+I_FF, 0x2900+I_FF, 0x2A00+I_FF, 0x2B00+I_FF, -0x2C00+I_FF, 0x2D00+I_FF, - 0x4100+I_RX, 0x4200+I_MX, 0x4300+I_MX, -0x4400+I_RX, 0x4500+I_RX, 0x4600+I_RX, 0x4700+I_RX, -0x4800+I_RX, 0x4A00+I_RX, 0x4B00+I_RX, -0x4C00+I_RX, 0x4D00+I_RX, 0x4E00+I_RX, 0x4F00+I_RX, -0x6000+I_FX, -0x6800+I_FX, 0x6900+I_FX, 0x6A00+I_FX, 0x6B00+I_FX, -0x6C00+I_FX, 0x6D00+I_FX, - 0x9200+I_RR, 0x9300+I_RR, - 0x9600+I_RR, 0x9700+I_RR, - 0x9A00+I_RR, 0x9B00+I_RR, - 0x9D00+I_RR, 0x9E00+I_RR, 0x9F00+I_RR, -0xC000+I_RX, 0xC100+I_RX, 0xC200+I_RX, -0xC400+I_RX, 0xC500+I_RX, 0xC600+I_RX, 0xC700+I_RX, -0xC800+I_RX, 0xCA00+I_RX, 0xCB00+I_RX, -0xCC00+I_RX, 0xCD00+I_RX, 0xCE00+I_RX, 0xCF00+I_RX, -0xD000+I_RX, 0xD100+I_RX, 0xD200+I_RX, 0xD300+I_RX, - 0xD500+I_RX, 0xD600+I_RX, 0xD700+I_RX, - 0xDA00+I_RX, 0xDB00+I_RX, - 0xDD00+I_RX, 0xDE00+I_RX, 0xDF00+I_RX, --1 }; - -/* Symbolic decode - - Inputs: - *of = output stream - addr = current PC - *val = values to decode - *uptr = pointer to unit - sw = switches - Outputs: - return = if >= 0, error code - if < 0, number of extra words retired -*/ - -t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, - UNIT *uptr, int32 sw) -{ -int32 i, j, c1, c2, inst, r1, r2; - -c1 = (val[0] >> 8) & 0x3F; /* big endian */ -c2 = val[0] & 0177; -if (sw & SWMASK ('A')) { /* ASCII? */ - fprintf (of, (c2 < 0x20)? "<%02X>": "%c", c2); - return SCPE_OK; } -if (sw & SWMASK ('C')) { /* character? */ - fprintf (of, (c1 < 0x20)? "<%02X>": "%c", c1); - fprintf (of, (c2 < 0x20)? "<%02X>": "%c", c2); - return SCPE_OK; } -if (!(sw & SWMASK ('M'))) return SCPE_ARG; - -inst = val[0]; -for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ - j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */ - if ((opc_val[i] & 0xFFFF) == (inst & masks[j])) { /* match? */ - r1 = (val[0] >> 4) & 0xF; - r2 = val[0] & 0xF; - switch (j) { /* case on class */ - case I_V_MR: /* mask-register */ - fprintf (of, "%s %-X,R%-X", opcode[i], r1, r2); - return SCPE_OK; - case I_V_RR: /* register-register */ - case I_V_FF: /* floating-floating */ - fprintf (of, "%s R%-X,R%-X", opcode[i], r1, r2); - return SCPE_OK; - case I_V_R: /* register */ - fprintf (of, "%s R%-X", opcode[i], r2); - return SCPE_OK; - case I_V_MX: /* mask-memory */ - fprintf (of, "%s %-X,%-X", opcode[i], r1, val[1]); - break; - case I_V_RX: /* register-memory */ - case I_V_FX: /* floating-memory */ - fprintf (of, "%s R%-X,%-X", opcode[i], r1, val[1]); - break; - case I_V_X: /* memory */ - fprintf (of, "%s %-X", opcode[i], val[1]); - break; } /* end case */ - if (r2) fprintf (of, "(R%-X)", r2); - return -1; } /* end if */ - } /* end for */ -return SCPE_ARG; /* no match */ -} - -/* Register number - - Inputs: - *cptr = pointer to input string - mchar = match character - regflt = false for integer, true for floating - Outputs: - rnum = output register number, -1 if error -*/ - -int32 get_reg (char *cptr, char mchar, t_bool regflt) -{ -int32 reg = -1; - -if ((*cptr == 'R') || (*cptr == 'r')) cptr++; -if (*(cptr + 1) != mchar) return reg; -if ((*cptr >= '0') && (*cptr <= '9')) reg = *cptr - '0'; -else if ((*cptr >= 'a') && (*cptr <= 'f')) reg = (*cptr - 'a') + 10; -else if ((*cptr >= 'A') && (*cptr <= 'F')) reg = (*cptr - 'A') + 10; -if (regflt && (reg & 1)) return -1; -return reg; -} - -/* 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, j, r1, r2; -t_bool regflt; -char *tptr, gbuf[CBUFSIZE]; - -regflt = FALSE; /* assume int reg */ -while (isspace (*cptr)) cptr++; /* absorb spaces */ -if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ - if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ - val[0] = (t_value) cptr[0]; - return SCPE_OK; } -if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */ - if (cptr[0] == 0) return SCPE_ARG; /* must have 1 char */ - val[0] = ((t_value) cptr[0] << 8) + (t_value) cptr[1]; - return SCPE_OK; } - -cptr = get_glyph (cptr, gbuf, 0); /* get opcode */ -for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ; -if (opcode[i] == NULL) return SCPE_ARG; -val[0] = opc_val[i] & 0xFFFF; /* get value */ -j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */ -switch (j) { /* case on class */ - -case I_V_FF: /* float-float */ - regflt = TRUE; /* fall thru */ -case I_V_MR: case I_V_RR: /* mask/reg-register */ - cptr = get_glyph (cptr, gbuf, ','); /* get register 1 */ - if ((r1 = get_reg (gbuf, 0, regflt)) < 0) return SCPE_ARG; - val[0] = val[0] | (r1 << 4); /* fall thru for reg 2 */ - -case I_V_R: /* register */ - cptr = get_glyph (cptr, gbuf, 0); /* get r2 */ - if ((r2 = get_reg (gbuf, 0, regflt)) < 0) return SCPE_ARG; - val[0] = val[0] | r2; - if (*cptr != 0) return SCPE_ARG; - break; - -case I_V_FX: /* float-memory */ - regflt = TRUE; /* fall thru */ -case I_V_MX: case I_V_RX: /* mask/reg-memory */ - cptr = get_glyph (cptr, gbuf, ','); /* get register 1 */ - if ((r1 = get_reg (gbuf, 0, regflt)) < 0) return SCPE_ARG; - val[0] = val[0] | (r1 << 4); /* fall thru for memory */ - -case I_V_X: /* memory */ - val[1] = strtoul (cptr, &tptr, 16); - if (cptr == tptr) return SCPE_ARG; - if (*tptr == 0) return -1; - if ((*tptr != '(') || (*(tptr + 4) != 0)) return SCPE_ARG; - if ((r2 = get_reg (tptr + 1, ')', FALSE)) < 0) return SCPE_ARG; - val[0] = val[0] | r2; - return -1; } /* end case */ -return SCPE_OK; -} diff --git a/makefile b/makefile new file mode 100644 index 00000000..4d1a5f85 --- /dev/null +++ b/makefile @@ -0,0 +1,247 @@ +# CC Command +# +CC = gcc -O2 -lm -I . +#CC = gcc -O0 -g -lm -I . + + + +# +# Common Libraries +# +BIN = BIN/ +SIM = scp.c scp_tty.c sim_sock.c sim_tmxr.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 +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 +PDP11_OPT = -I ${PDP11D} + + + +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} + + + +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_lp.c \ + ${HP2100D}hp2100_mt.c ${HP2100D}hp2100_cpu.c ${HP2100D}hp2100_sys.c +HP2100_OPT = -I ${HP2100D} + + + +ID4D = ID4/ +ID4 = ${ID4D}id4_fp.c ${ID4D}id4_cpu.c ${ID4D}id4_stddev.c ${ID4D}id4_sys.c +ID4_OPT = -I ${ID4D} + + + +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_sys.c +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 + + + +SDSD = SDS/ +SDS = ${SDSD}sds_stddev.c ${SDSD}sds_fhd.c ${SDSD}sds_io.c ${SDSD}sds_lp.c \ + ${SDSD}sds_mt.c ${SDSD}sds_rad.c ${SDSD}sds_cpu.c ${SDSD}sds_sys.c +SDS_OPT = -I ${SDSD} + + + +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} + + +# +# 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}id4 ${BIN}i1401 ${BIN}sds ${BIN}s3 ${BIN}altair + + + +# +# Make sure subdirectory exists +# +${BIN} : simh_doc.txt + -mkdir ${BIN} + -touch ${BIN} + + +# +# Individual builds +# +${BIN}pdp1 : ${PDP1} ${SIM} ${BIN} + ${CC} ${PDP1} ${SIM} ${PDP1_OPT} -o $@ + + + +${BIN}pdp4 : ${PDP18B} ${SIM} ${BIN} + ${CC} ${PDP18B} ${SIM} ${PDP4_OPT} -o $@ + + + +${BIN}pdp7 : ${PDP18B} ${SIM} ${BIN} + ${CC} ${PDP18B} ${SIM} ${PDP7_OPT} -o $@ + + + +${BIN}pdp8 : ${PDP8} ${SIM} ${BIN} + ${CC} ${PDP8} ${SIM} ${PDP8_OPT} -o $@ + + + +${BIN}pdp9 : ${PDP18B} ${SIM} ${BIN} + ${CC} ${PDP18B} ${SIM} ${PDP9_OPT} -o $@ + + + +${BIN}pdp15 : ${PDP18B} ${SIM} ${BIN} + ${CC} ${PDP18B} ${SIM} ${PDP15_OPT} -o $@ + + + +${BIN}pdp10 : ${PDP10} ${SIM} ${BIN} + ${CC} ${PDP10} ${SIM} ${PDP10_OPT} -o $@ + + + +${BIN}pdp11 : ${PDP11} ${SIM} ${BIN} + ${CC} ${PDP11} ${SIM} ${PDP11_OPT} -o $@ + + + +${BIN}vax : ${VAX} ${SIM} ${BIN} + ${CC} ${VAX} ${SIM} ${VAX_OPT} -o $@ + + + +${BIN}nova : ${NOVA} ${SIM} ${BIN} + ${CC} ${NOVA} ${SIM} ${NOVA_OPT} -o $@ + + + +${BIN}eclipse : ${ECLIPSE} ${SIM} ${BIN} + ${CC} ${ECLIPSE} ${SIM} ${ECLIPSE_OPT} -o $@ + + + +${BIN}h316 : ${H316} ${SIM} ${BIN} + ${CC} ${H316} ${SIM} ${H316_OPT} -o $@ + + + +${BIN}hp2100 : ${HP2100} ${SIM} ${BIN} + ${CC} ${HP2100} ${SIM} ${HP2100_OPT} -o $@ + + + +${BIN}id4 : ${ID4} ${SIM} ${BIN} + ${CC} ${ID4} ${SIM} ${ID4_OPT} -o $@ + + + +${BIN}i1401 : ${I1401} ${SIM} ${BIN} + ${CC} ${I1401} ${SIM} ${I1401_OPT} -o $@ + + + +${BIN}sds : ${SDS} ${SIM} ${BIN} + ${CC} ${SDS} ${SIM} ${SDS_OPT} -o $@ + + + +${BIN}s3 : ${S3} ${SIM} ${BIN} + ${CC} ${S3} ${SIM} ${S3_OPT} -o $@ + + +${BIN}altair : ${ALTAIR} ${SIM} ${BIN} + ${CC} ${ALTAIR} ${SIM} ${ALTAIR_OPT} -o $@ diff --git a/mingw_build.bat b/mingw_build.bat new file mode 100644 index 00000000..6921a1a3 --- /dev/null +++ b/mingw_build.bat @@ -0,0 +1,41 @@ +rem Compile all of SIMH using MINGW gcc environment +rem Master sources are in c:\sim +rem Individual simulator sources are in c:\sim\simulator_name +rem Mingw system is in C:\Mingw\bin +rem +path c:\mingw\bin;%path +cd c:\sim\pdp1 +gcc -o ..\bin\pdp1 -I.. ..\scp*.c pdp1*.c +cd c:\sim\pdp11 +gcc -o ..\bin\pdp11 -I.. ..\scp*.c ..\sim*.c pdp11*.c -lm -lwsock32 +cd c:\sim\pdp8 +gcc -o ..\bin\pdp8 -I.. ..\scp*.c ..\sim*.c pdp8*.c -lm -lwsock32 +cd c:\sim\pdp18b +gcc -DPDP4 -o ..\bin\pdp4 -I.. ..\scp*.c ..\sim*.c pdp18b*.c -lm -lwsock32 +gcc -DPDP7 -o ..\bin\pdp7 -I.. ..\scp*.c ..\sim*.c pdp18b*.c -lm -lwsock32 +gcc -DPDP9 -o ..\bin\pdp9 -I.. ..\scp*.c ..\sim*.c pdp18b*.c -lm -lwsock32 +gcc -DPDP15 -o ..\bin\pdp15 -I.. ..\scp*.c ..\sim*.c pdp18b*.c -lm -lwsock32 +cd c:\sim\pdp10 +gcc -DUSE_INT64 -o ..\bin\pdp10 -I.. ..\scp*.c ..\sim*.c pdp10*.c -lm -lwsock32 +cd c:\sim\vax +gcc -DUSE_INT64 -o ..\bin\vax -I.. -I. ..\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*.c -lm -lwsock32 +cd c:\sim\nova +gcc -o ..\bin\nova -I.. ..\scp*.c ..\sim*.c nova*.c -lm -lwsock32 +cd c:\sim\altair +gcc -o ..\bin\altair -I.. ..\scp*.c altair*.c +cd c:\sim\h316 +gcc -o ..\bin\h316 -I.. ..\scp*.c h316*.c +cd c:\sim\hp2100 +gcc -o ..\bin\hp2100 -I.. ..\scp*.c hp2100*.c +cd c:\sim\i1401 +gcc -o ..\bin\i1401 -I.. ..\scp*.c i1401*.c +cd c:\sim\id4 +gcc -o ..\bin\id4 -I.. ..\scp*.c id4*.c +cd c:\sim\s3 +gcc -o ..\bin\s3 -I.. ..\scp*.c s3*.c +cd c:\sim\sds +gcc -o ..\bin\sds -I.. ..\scp*.c sds*.c -lm +cd .. + + + diff --git a/scp.c b/scp.c index ffd9715c..fd14607f 100644 --- a/scp.c +++ b/scp.c @@ -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. + 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 @@ -67,31 +74,46 @@ #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 SWHIDE (1u << 26) /* enable hiding */ -#define SRBSIZ 1024 /* save/restore buffer */ -#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 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 +#define SIM_BRK_ALLTYP 0xFFFFFFFF #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; @@ -113,6 +135,15 @@ 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; @@ -122,6 +153,13 @@ 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) \ @@ -152,7 +190,7 @@ unsigned char sim_flip[FLIP_SIZE]; while (*cp == '-') { \ int32 lsw; \ cp = get_glyph (cp, gb, 0); \ - if ((lsw = get_switches (gb)) <= 0) return SCPE_ARG; \ + 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; \ @@ -160,6 +198,12 @@ unsigned char sim_flip[FLIP_SIZE]; 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_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); @@ -169,10 +213,12 @@ 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, int32 *iptr); +DEVICE *find_unit (char *ptr, UNIT **uptr); DEVICE *find_dev_from_unit (UNIT *uptr); REG *find_reg (char *ptr, char **optr, DEVICE *dptr); +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); @@ -218,7 +264,18 @@ const char *scp_error_messages[] = { "Command not allowed", "Unit disabled", "Logging enabled", - "Logging disabled" + "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), @@ -251,12 +308,6 @@ const t_value width_mask[] = { 0, #endif }; -int main (int argc, char *argv[]) -{ -char cbuf[CBUFSIZE], gbuf[CBUFSIZE], *cptr; -int32 i, stat; -FILE *fpin; -union {int32 i; char c[sizeof (int32)]; } end_test; t_stat reset_cmd (int flag, char *ptr); t_stat exdep_cmd (int flag, char *ptr); t_stat load_cmd (int flag, char *ptr); @@ -268,12 +319,12 @@ 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 add_cmd (int flag, char *ptr); -t_stat remove_cmd (int flag, char *ptr); t_stat enable_cmd (int flag, char *ptr); t_stat disable_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[] = { @@ -301,15 +352,23 @@ static CTAB cmd_table[] = { { "SHOW", &show_cmd, 0 }, { "ENABLE", &enable_cmd, 0 }, { "DISABLE", &disable_cmd, 0 }, - { "ADD", &add_cmd, 0 }, - { "REMOVE", &remove_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 @@ -337,21 +396,15 @@ 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] != NULL)) { /* cmd line arg? */ - if ((fpin = fopen (argv[1], "r")) != NULL) { /* cmd file open? */ - do { cptr = read_line (cbuf, CBUFSIZE, fpin); - if (cptr == NULL) break; /* exit on eof */ - if (*cptr == 0) continue; /* ignore blank */ - 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) - printf ("%s\n", scp_error_messages[stat - SCPE_BASE]); - } while (stat != SCPE_EXIT); } /* end if cmd file */ - else printf ("Can't open file \"%s\"\n", argv[1]); } /* end if cmd arg */ +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 */ cptr = read_line (cbuf, CBUFSIZE, stdin); /* read command line */ @@ -398,14 +451,16 @@ 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 device\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 unit parameter\n"); -fprintf (st, "show show device parameters\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"); @@ -414,10 +469,9 @@ fprintf (st, "sh{ow} t{ime} show simulated time\n"); fprintf (st, "sh{ow} v{ersion} show simulator version\n"); fprintf (st, "en{able} enable device\n"); fprintf (st, "di{sable} disable device\n"); -fprintf (st, "ad{d} add unit to configuration\n"); -fprintf (st, "rem{ove} remove unit from configuration\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; } @@ -429,105 +483,230 @@ 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; } + 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]); + } 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 i, unitno; +int32 lvl; t_stat r; -char gbuf[CBUFSIZE]; +char gbuf[CBUFSIZE], *cvptr; DEVICE *dptr; UNIT *uptr; MTAB *mptr; -t_stat set_radix (DEVICE *dptr, int flag); -static CTAB set_table[] = { +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); /* test for switches */ -cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ -dptr = find_unit (gbuf, &unitno); /* find dev+unit */ -if ((dptr == NULL) || (dptr -> units == NULL) || - (*cptr == 0)) return SCPE_ARG; /* argument? */ -cptr = get_glyph (cptr, gbuf, 0); /* get glyph */ -uptr = dptr -> units + unitno; -if (uptr -> flags & UNIT_DIS) return SCPE_UDIS; /* disabled? */ -for (i = 0; set_table[i].name != NULL; i++) { /* check globals */ - if (MATCH_CMD (gbuf, set_table[i].name) == 0) { - if (*cptr != 0) return SCPE_ARG; /* now eol? */ - return set_table[i].action (dptr, set_table[i].arg); } } +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? */ -for (mptr = dptr -> modifiers; mptr -> mask != 0; mptr++) { - if ((mptr -> mstring != NULL) && - (MATCH_CMD (gbuf, mptr -> mstring) == 0)) { - if (*cptr != 0) return SCPE_ARG; /* now eol? */ - if ((mptr -> valid != NULL) && - ((r = mptr -> valid (uptr, mptr -> match)) != SCPE_OK)) - return r; /* invalid? */ + +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 */ - return SCPE_OK; } } -return SCPE_ARG; /* no match */ + (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, int flag) +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; +int32 i, lvl; t_stat r; char gbuf[CBUFSIZE]; DEVICE *dptr; +UNIT *uptr; +MTAB *mptr; -t_stat show_config (FILE *st, int flag); -t_stat show_queue (FILE *st, int flag); -t_stat show_time (FILE *st, int flag); -t_stat show_modifiers (FILE *st, int flag); -t_stat show_device (FILE *st, DEVICE *dptr, int 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); static CTAB show_table[] = { { "CONFIGURATION", &show_config, 0 }, { "DEVICES", &show_config, 1 }, { "QUEUE", &show_queue, 0 }, { "TIME", &show_time, 0 }, - { "MODIFIERS", &show_modifiers, 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 */ -if (*cptr != 0) return SCPE_ARG; /* now eol? */ for (i = 0; show_table[i].name != NULL; i++) { /* find command */ - if (MATCH_CMD (gbuf, show_table[i].name) == 0) { - 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; } } -dptr = find_dev (gbuf); /* locate device */ -if (dptr == NULL) return SCPE_ARG; /* not found? */ -r = show_device (stdout, dptr, 0); -if (sim_log) show_device (sim_log, dptr, 0); -return r; -} + 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_XTV) == MTAB_XTV) && /* 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 */ + } /* end while */ +return SCPE_OK; +} + /* Show processors */ -t_stat show_device (FILE *st, DEVICE *dptr, int flag) +t_stat show_device (FILE *st, DEVICE *dptr, int32 flag) { int32 j, ucnt; -t_addr kval; UNIT *uptr; -MTAB *mptr; fprintf (st, "%s", dptr -> name); /* print dev name */ if (qdisable (dptr)) { /* disabled? */ @@ -536,38 +715,43 @@ if (qdisable (dptr)) { /* disabled? */ 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++) { +for (j = 0; j < dptr -> numunits; j++) { /* loop thru units */ uptr = (dptr -> units) + j; - kval = (uptr -> flags & UNIT_BINK)? 1024: 1000; - if (uptr -> flags & UNIT_DIS) continue; - if (ucnt > 1) fprintf (st, " unit %d", j); - if (uptr -> flags & UNIT_FIX) { - if (uptr -> capac < kval) + 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, + 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); - else if (uptr -> flags & UNIT_ATTABLE) - fprintf (st, ", not attached"); - if (dptr -> modifiers != NULL) { - for (mptr = dptr -> modifiers; mptr -> mask != 0; mptr++) { - if ((mptr -> pstring != NULL) && - ((uptr -> flags & mptr -> mask) == mptr -> match)) { - fprintf (st, ", %s", mptr -> pstring); - if ((mptr -> mstring == NULL) && mptr -> valid) - mptr -> valid (uptr, st); } } } - fprintf (st, "\n"); } +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, int flag) +t_stat show_version (FILE *st, int32 flag) { int32 vmaj = SIM_MAJOR, vmin = SIM_MINOR, vpat = SIM_PATCH; @@ -575,7 +759,7 @@ fprintf (st, "%s simulator V%d.%d-%d\n", sim_name, vmaj, vmin, vpat); return SCPE_OK; } -t_stat show_config (FILE *st, int flag) +t_stat show_config (FILE *st, int32 flag) { int32 i; DEVICE *dptr; @@ -586,7 +770,7 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) return SCPE_OK; } -t_stat show_queue (FILE *st, int flag) +t_stat show_queue (FILE *st, int32 flag) { DEVICE *dptr; UNIT *uptr; @@ -611,25 +795,107 @@ for (uptr = sim_clock_queue; uptr != NULL; uptr = uptr -> next) { return SCPE_OK; } -t_stat show_time (FILE *st, int flag) +t_stat show_time (FILE *st, int32 flag) { fprintf (st, "Time: %-16.0f\n", sim_time); return SCPE_OK; } -t_stat show_modifiers (FILE *st, int flag) +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++) { - any = 0; - for (mptr = dptr -> modifiers; mptr && (mptr -> mask != 0); mptr++) { - if (mptr -> mstring) { - if (any++) fprintf (st, ", %s", mptr -> mstring); - else fprintf (st, "%s %s", dptr -> name, mptr -> mstring); } } - if (any) fprintf (st, "\n"); } + 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_XTV) == MTAB_XTV) { + 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) 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; } @@ -646,9 +912,11 @@ DEVICE *dptr; REG *rptr; 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 */ dptr = find_dev (gbuf); /* locate device */ -if ((dptr == NULL) || (*cptr != 0)) return SCPE_ARG; /* found it? */ +if (dptr == NULL) return SCPE_NXDEV; /* found it? */ +if (*cptr != 0) return SCPE_2MARG; /* now eol? */ rptr = find_reg ("*DEVENB", NULL, dptr); /* locate enable */ if (rptr == NULL) return SCPE_NOFNC; /* found it? */ put_rval (rptr, 0, 1); /* enable */ @@ -665,9 +933,11 @@ UNIT *uptr; REG *rptr; 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 */ dptr = find_dev (gbuf); /* locate device */ -if ((dptr == NULL) || (*cptr != 0)) return SCPE_ARG; /* found it? */ +if (dptr == NULL) return SCPE_NXDEV; /* found it? */ +if (*cptr != 0) return SCPE_2MARG; /* now eol? */ rptr = find_reg ("*DEVENB", NULL, dptr); /* locate enable */ if (rptr == NULL) return SCPE_NOFNC; /* found it? */ for (i = 0; i < dptr -> numunits; i++) { /* check units */ @@ -690,50 +960,6 @@ if (rptr == NULL) return FALSE; /* found it? */ return (get_rval (rptr, 0)? FALSE: TRUE); /* return flag */ } -/* Add and remove commands and routines - - ad[d] add unit to configuration - rem[ove] remove unit from configuration -*/ - -t_stat add_cmd (int flag, char *cptr) -{ -int32 unitno; -char gbuf[CBUFSIZE]; -DEVICE *dptr; -UNIT *uptr; - -GET_SWITCHES (cptr, gbuf); /* test for switches */ -cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ -dptr = find_unit (gbuf, &unitno); /* locate dev+unit# */ -if ((dptr == NULL) || (dptr -> units == NULL) || - (*cptr != 0)) return SCPE_ARG; /* found it? */ -uptr = dptr -> units + unitno; /* locate unit */ -if (!(uptr -> flags & UNIT_DISABLE)) return SCPE_NOFNC; /* allowed? */ -uptr -> flags = uptr -> flags & ~UNIT_DIS; /* enable it */ -return SCPE_OK; -} - -t_stat remove_cmd (int flag, char *cptr) -{ -int32 unitno; -char gbuf[CBUFSIZE]; -DEVICE *dptr; -UNIT *uptr; - -GET_SWITCHES (cptr, gbuf); /* test for switches */ -cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ -dptr = find_unit (gbuf, &unitno); /* locate dev+unit# */ -if ((dptr == NULL) || (dptr -> units == NULL) || - (*cptr != 0)) return SCPE_ARG; /* found it? */ -uptr = dptr -> units + unitno; /* locate unit */ -if (!(uptr -> flags & UNIT_DISABLE) || /* allowed? */ - (uptr -> flags & UNIT_ATT) || sim_is_active (uptr)) - return SCPE_NOFNC; -uptr -> flags = uptr -> flags | UNIT_DIS; /* disable it */ -return SCPE_OK; -} - /* Logging commands log filename open log file @@ -747,7 +973,7 @@ 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_ARG; /* end of line? */ +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? */ @@ -762,7 +988,7 @@ char gbuf[CBUFSIZE]; if (cptr) { GET_SWITCHES (cptr, gbuf); /* test for switches */ - if (*cptr != 0) return SCPE_ARG; } /* end of line? */ + 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 */ @@ -786,10 +1012,10 @@ 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_ARG; /* now (cr)? */ +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_ARG; /* found it? */ +if (dptr == NULL) return SCPE_NXDEV; /* found it? */ if (dptr -> reset != NULL) return dptr -> reset (dptr); else return SCPE_OK; } @@ -808,9 +1034,9 @@ DEVICE *dptr; int32 i; t_stat reason; -if (start < 0) return SCPE_ARG; +if (start < 0) return SCPE_IERR; for (i = 0; i < start; i++) { - if (sim_devices[i] == NULL) return SCPE_ARG; } + 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); @@ -831,7 +1057,7 @@ FILE *loadfile; t_stat reason; GET_SWITCHES (cptr, gbuf); /* test for switches */ -if (*cptr == 0) return SCPE_ARG; /* must be more */ +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; @@ -848,17 +1074,16 @@ return reason; t_stat attach_cmd (int flag, char *cptr) { char gbuf[CBUFSIZE]; -int32 unitno; DEVICE *dptr; UNIT *uptr; GET_SWITCHES (cptr, gbuf); /* test for switches */ -if (*cptr == 0) return SCPE_ARG; +if (*cptr == 0) return SCPE_2FARG; /* must be more */ cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ -if (*cptr == 0) return SCPE_ARG; -dptr = find_unit (gbuf, &unitno); /* locate dev+unit# */ -if ((dptr == NULL) || (dptr -> units == NULL)) return SCPE_ARG; -uptr = (dptr -> units) + unitno; +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); } @@ -868,31 +1093,59 @@ t_stat attach_unit (UNIT *uptr, char *cptr) DEVICE *dptr; t_stat reason; -if (uptr -> flags & UNIT_DIS) return SCPE_ARG; /* disabled? */ +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; } + 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 -> fileref = fopen (cptr, "rb+"); -if (uptr -> fileref == NULL) { - uptr -> fileref = fopen (cptr, "wb+"); - if (uptr -> fileref == NULL) return SCPE_OPENERR; - printf ("%s: creating new file\n", dptr -> name); } -if (uptr -> flags & UNIT_BUFABLE) { - 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) return SCPE_MEM; } +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 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 */ + uptr -> fileref = fopen (cptr, "wb+"); /* open new file */ + if (uptr -> fileref == NULL) /* open fail? */ + return 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) return 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 @@ -903,18 +1156,17 @@ return SCPE_OK; t_stat detach_cmd (int flag, char *cptr) { char gbuf[CBUFSIZE]; -int32 unitno; DEVICE *dptr; UNIT *uptr; GET_SWITCHES (cptr, gbuf); /* test for switches */ -if (*cptr == 0) return SCPE_ARG; +if (*cptr == 0) return SCPE_2FARG; /* must be more */ cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ -if (*cptr != 0) return SCPE_ARG; +if (*cptr != 0) return SCPE_2MARG; /* now eol? */ if (strcmp (gbuf, "ALL") == 0) return (detach_all (0, FALSE)); -dptr = find_unit (gbuf, &unitno); /* locate dev+unit# */ -if ((dptr == NULL) || (dptr -> units == NULL)) return SCPE_ARG; -uptr = (dptr -> units) + unitno; +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); @@ -936,14 +1188,14 @@ t_stat reason; DEVICE *dptr; UNIT *uptr; -if ((start < 0) || (start > 1)) return SCPE_ARG; +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; } } } + 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; } @@ -951,19 +1203,19 @@ t_stat detach_unit (UNIT *uptr) { DEVICE *dptr; -if (uptr == NULL) return SCPE_ARG; +if (uptr == NULL) return SCPE_IERR; if (!(uptr -> flags & UNIT_ATT)) return SCPE_OK; -uptr -> flags = uptr -> flags & ~UNIT_ATT; if ((dptr = find_dev_from_unit (uptr)) == NULL) return SCPE_OK; if (uptr -> flags & UNIT_BUF) { - if (uptr -> hwmark) { - 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; } + 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; @@ -992,7 +1244,7 @@ REG *rptr; #define WRITE_I(xx) fxwrite (&(xx), sizeof (xx), 1, sfile) GET_SWITCHES (cptr, gbuf); /* test for switches */ -if (*cptr == 0) return SCPE_ARG; +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); @@ -1084,7 +1336,7 @@ REG *rptr; { fclose (rfile); return SCPE_IOERR; } GET_SWITCHES (cptr, buf); /* test for switches */ -if (*cptr == 0) return SCPE_ARG; +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? */ @@ -1217,18 +1469,19 @@ if (flag == RU_STEP) { /* step */ if ((r != SCPE_OK) || (step == 0)) return SCPE_ARG; } } if (flag == RU_BOOT) { /* boot */ - if (*cptr == 0) return SCPE_ARG; + if (*cptr == 0) return SCPE_2FARG; /* must be more */ cptr = get_glyph (cptr, gbuf, 0); /* get next glyph */ - dptr = find_unit (gbuf, &unitno); /* locate dev+unit# */ - if ((dptr == NULL) || (dptr -> units == NULL) || - (dptr -> boot == NULL)) return SCPE_ARG; - uptr = dptr -> units + unitno; - if (uptr -> flags & UNIT_DIS) return SCPE_ARG; /* disabled? */ + 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_ARG; +if (*cptr != 0) return SCPE_2MARG; /* now eol? */ if ((flag == RU_RUN) || (flag == RU_BOOT)) { /* run or boot */ sim_interval = 0; /* reset queue */ @@ -1284,16 +1537,16 @@ 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, ")"); } } + 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; } @@ -1342,12 +1595,12 @@ return; t_stat exdep_cmd (int flag, char *cptr) { char gbuf[CBUFSIZE], *gptr, *tptr; -int32 unitno, t; +int32 t; t_bool exd2f; t_addr low, high; t_stat reason; DEVICE *dptr, *tdptr; -UNIT *uptr; +UNIT *uptr, *tuptr; REG *lowr, *highr; SCHTAB stab, *schptr; FILE *ofile; @@ -1356,7 +1609,6 @@ t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int flag, char *ptr, t_stat exdep_reg_loop (FILE *ofile, SCHTAB *schptr, int flag, char *ptr, REG *lowr, REG *highr, t_addr lows, t_addr highs); -if (*cptr == 0) return SCPE_ARG; /* err if no args */ ofile = NULL; /* no output file */ exd2f = FALSE; sim_switches = 0; /* no switches */ @@ -1365,9 +1617,9 @@ stab.logic = SCH_OR; /* default search params */ stab.bool = SCH_GE; stab.mask = stab.comp = 0; dptr = sim_devices[0]; /* default device, unit */ -unitno = 0; +uptr = dptr -> units; for (;;) { /* loop through modifiers */ - if (*cptr == 0) return SCPE_ARG; /* error if no arguments */ + 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? */ @@ -1380,36 +1632,38 @@ for (;;) { /* loop through modifiers */ continue; } /* look for more */ cptr = get_glyph (cptr, gbuf, 0); if ((t = get_switches (gbuf)) != 0) { /* try for switches */ - if (t < 0) return SCPE_ARG; /* err if bad switch */ + 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, &t)) != NULL) { /* try for unit */ + else if (((tdptr = find_unit (gbuf, &tuptr)) != NULL) && + (tuptr != NULL)) { /* try for unit */ dptr = tdptr; /* set as default */ - unitno = t; } + 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 (dptr -> units == NULL) return SCPE_ARG; /* got a unit? */ if (ofile == NULL) ofile = stdout; /* no file? stdout */ -uptr = (dptr -> units) + unitno; 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_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, dptr)) { + 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, dptr); - if (highr == NULL) return SCPE_ARG; } + 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; @@ -1447,11 +1701,11 @@ t_addr idx; t_value val; REG *rptr; -if ((lowr == NULL) || (highr == NULL)) return SCPE_ARG; +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) || (rptr -> depth > 1))) continue; + (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); @@ -1473,7 +1727,7 @@ t_stat exdep_addr_loop (FILE *ofile, SCHTAB *schptr, int flag, char *cptr, t_addr i, mask; t_stat reason; -if (uptr -> flags & UNIT_DIS) return SCPE_ARG; /* disabled? */ +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; @@ -1509,7 +1763,7 @@ t_stat ex_reg (FILE *ofile, t_value val, int flag, REG *rptr, t_addr idx) { int32 rdx; -if (rptr == NULL) return SCPE_ARG; +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; @@ -1533,9 +1787,13 @@ t_value get_rval (REG *rptr, int idx) { size_t sz; t_value val; +UNIT *uptr; sz = SZ_R (rptr); -if ((rptr -> depth > 1) && (sz == sizeof (uint8))) +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); @@ -1568,7 +1826,7 @@ t_value val, mask; int32 rdx; char gbuf[CBUFSIZE]; -if ((cptr == NULL) || (rptr == NULL)) return SCPE_ARG; +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); @@ -1588,7 +1846,7 @@ return SCPE_OK; Inputs: rptr = pointer to register descriptor - idx = index (RESTORE reg buffers only) + idx = index val = new value mask = mask Outputs: @@ -1599,15 +1857,23 @@ void put_rval (REG *rptr, int idx, t_value val) { size_t sz; t_value mask; +UNIT *uptr; -#define PUT_RVAL(sz,rp,id,val,msk) \ +#define PUT_RVAL(sz,rp,id,v,m) \ *(((sz *) rp -> loc) + id) = \ (*(((sz *) rp -> loc) + id) & \ - ~((msk) << (rp) -> offset)) | ((val) << (rp) -> offset) + ~((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) && (sz == sizeof (uint8))) +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); @@ -1670,7 +1936,7 @@ t_addr j, loc; t_stat reason; size_t sz; -if ((dptr == NULL) || (uptr == NULL)) return SCPE_ARG; +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) { @@ -1724,12 +1990,13 @@ t_value mask; size_t sz; char gbuf[CBUFSIZE]; -if (dptr == NULL) return SCPE_ARG; +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); @@ -1882,18 +2149,20 @@ 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 = 0; +*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 == ':')) { /* more to do? */ + if ((*tptr == '-') || (*tptr == ':') || (*tptr == '/')) { + if (*tptr == '/') hb = *lo; /* relative? */ cptr = tptr + 1; errno = 0; - *hi = strtoul (cptr, &tptr, rdx); /* get high */ + *hi = hb + strtoul (cptr, &tptr, rdx); /* get high */ if (errno || (cptr == tptr)) return NULL; if (*lo > *hi) return NULL; } else *hi = *lo; } @@ -1923,34 +2192,34 @@ return NULL; Inputs: cptr = pointer to input string - iptr = pointer to unit number + uptr = pointer to unit pointer Outputs: - result = pointer to device - *iptr = unit number + result = pointer to device (null if no dev) + *iptr = pointer to unit (null if nx unit) */ -DEVICE *find_unit (char *cptr, int32 *iptr) +DEVICE *find_unit (char *cptr, UNIT **uptr) { -int32 i, lenn; +int32 i, lenn, u; t_stat r; DEVICE *dptr; -if (iptr == NULL) return NULL; /* arg error? */ -*iptr = 0; /* assume no unit */ +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; - cptr = cptr + lenn; /* skip devname */ - if (*cptr) { /* unit #? */ - *iptr = (int32) get_uint (cptr, 10, dptr -> numunits - 1, &r); - if (r != SCPE_OK) return NULL; } 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; } @@ -1975,6 +2244,32 @@ for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { return NULL; } +/* 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: @@ -2266,7 +2561,7 @@ t_stat sim_activate (UNIT *uptr, int32 event_time) UNIT *cptr, *prvptr; int32 accum; -if (event_time < 0) return SCPE_ARG; +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 */ @@ -2496,4 +2791,201 @@ rtc_currdelay = (int32) (((double) rtc_basedelay * (double) rtc_nextintv) / 1000.0); /* next delay */ return rtc_currdelay; } + +/* 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; +} diff --git a/sim_defs.h b/sim_defs.h index 42d58546..4f17e784 100644 --- a/sim_defs.h +++ b/sim_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. + 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 @@ -144,6 +148,17 @@ typedef int32 t_mtrlnt; /* magtape rec lnt */ #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 + 40) /* nested DO */ +#define SCPE_IERR (SCPE_BASE + 41) /* internal error */ #define SCPE_KFLAG 01000 /* tti data flag */ /* Print value format codes */ @@ -174,12 +189,12 @@ struct device { struct unit *units; /* units */ struct reg *registers; /* registers */ struct mtab *modifiers; /* modifiers */ - int numunits; /* #units */ - int aradix; /* address radix */ - int awidth; /* address width */ - int aincr; /* addr increment */ - int dradix; /* data radix */ - int dwidth; /* data width */ + 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 */ @@ -225,19 +240,22 @@ struct unit { #define UNIT_BUFABLE 000100 /* bufferable */ #define UNIT_MUSTBUF 000200 /* must buffer */ #define UNIT_BUF 000400 /* buffered */ -#define UNIT_DISABLE 001000 /* disable-able */ -#define UNIT_DIS 002000 /* disabled */ +#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 */ - int radix; /* radix */ - int width; /* width */ - int offset; /* starting bit */ - int depth; /* save depth */ + int32 radix; /* radix */ + int32 width; /* width */ + int32 offset; /* starting bit */ + int32 depth; /* save depth */ int32 flags; /* flags */ }; @@ -245,17 +263,18 @@ struct reg { #define REG_RO 004 /* read only */ #define REG_HIDDEN 010 /* hidden */ #define REG_NZ 020 /* must be non-zero */ -#define REG_HRO (REG_RO + REG_HIDDEN) /* hidden, read only */ +#define REG_UNIT 040 /* in unit struct */ +#define REG_HRO (REG_RO | REG_HIDDEN) /* hidden, read only */ /* Command table */ struct ctab { char *name; /* name */ t_stat (*action)(); /* action routine */ - int arg; /* argument */ + int32 arg; /* argument */ }; -/* Modifier table */ +/* Modifier table - only extended entries have disp, reg, or flags */ struct mtab { int32 mask; /* mask or radix */ @@ -263,8 +282,19 @@ struct mtab { 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 */ +#define MTAB_XTV (MTAB_XTD | MTAB_XTD) /* ext with value */ + /* Search table */ struct schtab { @@ -285,6 +315,8 @@ struct schtab { #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 @@ -292,6 +324,8 @@ struct schtab { #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 */ @@ -326,3 +360,4 @@ int32 sim_rtc_init (int32 time); int32 sim_rtc_calb (int32 ticksper); t_stat sim_poll_kbd (void); t_stat sim_putchar (int32 out); +t_bool sim_brk_test (t_addr bloc, int32 btyp); diff --git a/sim_rev.h b/sim_rev.h index 61757a7b..bc327ec8 100644 --- a/sim_rev.h +++ b/sim_rev.h @@ -25,10 +25,52 @@ */ #define SIM_MAJOR 2 -#define SIM_MINOR 7 -#define SIM_PATCH 15 +#define SIM_MINOR 8 +#define SIM_PATCH 5 -/* SIMH detailed revision list, starting with V2.7 +/* V2.8 revision history + +patch date module(s) and fix(es) + +5 25-Dec-01 scp.c: fixed bug in DO command (found by John Dundas) + + pdp10_cpu.c: + -- moved trap-in-progress to separate variable + -- cleaned up declarations + -- cleaned up volatile state for GNU C longjmp + + pdp11_cpu.c: cleaned up declarations + + pdp11_rq.c: added RA-class disks + +4 17-Dec-01 pdp11_rq.c: added delayed processing of packets + +3 16-Dec-01 pdp8_cpu.c: + -- mode A EAE instructions didn't clear GTF + -- ASR shift count > 24 mis-set GTF + -- effective shift count == 32 didn't work + +2 07-Dec-01 scp.c: added breakpoint package + + all CPU's: revised to use new breakpoint package + +1 05-Dec-01 scp.c: fixed bug in universal register name logic + +0 30-Nov-01 Reorganized simh source and documentation tree + + scp: Added DO command, universal registers, extended + SET/SHOW logic + + pdp11: overhauled PDP-11 for DMA map support, shared + sources with VAX, dynamic buffer allocation + + 18b pdp: overhauled interrupt structure + + pdp8: added RL8A + + pdp10: fixed two ITS-related bugs (found by Dave Conroy) + + V2.7 revision history patch date module(s) and fix(es) diff --git a/sim_tmxr.c b/sim_tmxr.c index accfa3ab..74b963ff 100644 --- a/sim_tmxr.c +++ b/sim_tmxr.c @@ -26,6 +26,7 @@ Based on the original DZ11 simulator by Thord Nilson, as updated by Arthur Krewat. + 03-Dec-01 RMS Changed tmxr_status for extended SET/SHOW 20-Oct-01 RMS Fixed bugs in read logic (found by Thord Nilson). added tmxr_rqln, tmxr_tqln */ @@ -383,7 +384,8 @@ return; void tmxr_fstatus (FILE *st, TMLN *lp, int32 ln) { -if (ln >= 0) fprintf (st, "\n line %d", ln); +if (ln >= 0) fprintf (st, "\n line %d: ", ln); +else fprintf (st, "line status: "); if (lp -> conn) { int32 o1, o2, o3, o4, hr, mn, sc; uint32 ctime; @@ -396,8 +398,8 @@ if (lp -> conn) { hr = ctime / 3600; mn = (ctime / 60) % 60; sc = ctime % 3600; - fprintf (st, ": IP address %d.%d.%d.%d", o1, o2, o3, o4); + fprintf (st, "IP address %d.%d.%d.%d", o1, o2, o3, o4); if (ctime) fprintf (st, ", connected %02d:%02d:%02d", hr, mn, sc); } -else fprintf (st, ": disconnected"); +else fprintf (st, "disconnected"); return; } diff --git a/simh.doc b/simh.doc deleted file mode 100644 index 9a868050..00000000 --- a/simh.doc +++ /dev/null @@ -1,974 +0,0 @@ -{\rtf1\ansi\ansicpg1252\uc1 \deff0\deflang1033\deflangfe1033{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fswiss\fcharset0\fprq2{\*\panose 020b0604020202020204}Arial;} -{\f2\fmodern\fcharset0\fprq1{\*\panose 02070309020205020404}Courier New;}{\f3\froman\fcharset2\fprq2{\*\panose 05050102010706020507}Symbol;}{\f4\froman\fcharset0\fprq2{\*\panose 00000000000000000000}Times;} -{\f5\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}Helvetica;}{\f6\fmodern\fcharset0\fprq1{\*\panose 00000000000000000000}Courier;}{\f7\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}Geneva;} -{\f8\froman\fcharset0\fprq2{\*\panose 00000000000000000000}Tms Rmn;}{\f9\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}Helv;}{\f10\froman\fcharset0\fprq2{\*\panose 00000000000000000000}MS Serif;} -{\f11\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}MS Sans Serif;}{\f12\froman\fcharset0\fprq2{\*\panose 00000000000000000000}New York;}{\f13\fswiss\fcharset0\fprq2{\*\panose 00000000000000000000}System;} -{\f14\fnil\fcharset2\fprq2{\*\panose 05000000000000000000}Wingdings;}{\f15\fswiss\fcharset0\fprq2{\*\panose 020b0604030504040204}Tahoma;}{\f16\froman\fcharset177\fprq2{\*\panose 00000000000000000000}Times New Roman (Hebrew);} -{\f17\froman\fcharset178\fprq2{\*\panose 00000000000000000000}Times New Roman (Arabic);}{\f18\fswiss\fcharset177\fprq2{\*\panose 00000000000000000000}Arial (Hebrew);}{\f19\fswiss\fcharset178\fprq2{\*\panose 00000000000000000000}Arial (Arabic);} -{\f20\fmodern\fcharset177\fprq1{\*\panose 00000000000000000000}Courier New (Hebrew);}{\f21\fmodern\fcharset178\fprq1{\*\panose 00000000000000000000}Courier New (Arabic);}{\f22\fswiss\fcharset177\fprq2{\*\panose 00000000000000000000}Tahoma (Hebrew);} -{\f23\fswiss\fcharset178\fprq2{\*\panose 00000000000000000000}Tahoma (Arabic);}{\f24\froman\fcharset238\fprq2 Times New Roman CE;}{\f25\froman\fcharset204\fprq2 Times New Roman Cyr;}{\f27\froman\fcharset161\fprq2 Times New Roman Greek;} -{\f28\froman\fcharset162\fprq2 Times New Roman Tur;}{\f29\froman\fcharset186\fprq2 Times New Roman Baltic;}{\f30\fswiss\fcharset238\fprq2 Arial CE;}{\f31\fswiss\fcharset204\fprq2 Arial Cyr;}{\f33\fswiss\fcharset161\fprq2 Arial Greek;} -{\f34\fswiss\fcharset162\fprq2 Arial Tur;}{\f35\fswiss\fcharset186\fprq2 Arial Baltic;}{\f36\fmodern\fcharset238\fprq1 Courier New CE;}{\f37\fmodern\fcharset204\fprq1 Courier New Cyr;}{\f39\fmodern\fcharset161\fprq1 Courier New Greek;} -{\f40\fmodern\fcharset162\fprq1 Courier New Tur;}{\f41\fmodern\fcharset186\fprq1 Courier New Baltic;}{\f114\fswiss\fcharset238\fprq2 Tahoma CE;}{\f115\fswiss\fcharset204\fprq2 Tahoma Cyr;}{\f117\fswiss\fcharset161\fprq2 Tahoma Greek;} -{\f118\fswiss\fcharset162\fprq2 Tahoma Tur;}{\f119\fswiss\fcharset186\fprq2 Tahoma Baltic;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0; -\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\stylesheet{\widctlpar\adjustright -\fs20\cgrid \snext0 Normal;}{\s1\fi-360\li360\sb240\sa60\keepn\widctlpar\jclisttab\tx360\ls1\outlinelevel0\adjustright \b\f1\fs28\kerning28\cgrid \sbasedon0 \snext0 heading 1;}{\s2\fi-390\li390\sb240\sa60\keepn\widctlpar -\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid \sbasedon0 \snext0 heading 2;}{\s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid \sbasedon0 \snext0 heading 3;}{\*\cs10 \additive -Default Paragraph Font;}{\*\cs15 \additive \b \sbasedon10 Strong;}{\s16\widctlpar\adjustright \b\f1\fs20\cgrid \sbasedon0 \snext16 Body Text;}{\s17\li720\widctlpar\adjustright \f1\fs20\cgrid \sbasedon0 \snext17 Body Text 2;}{ -\s18\sb120\widctlpar\adjustright \b\i\cgrid \sbasedon0 \snext0 \sautoupd toc 1;}{\s19\li200\sb120\widctlpar\adjustright \b\fs22\cgrid \sbasedon0 \snext0 \sautoupd toc 2;}{\s20\li400\widctlpar\adjustright \fs20\cgrid \sbasedon0 \snext0 \sautoupd toc 3;}{ -\s21\li600\widctlpar\adjustright \fs20\cgrid \sbasedon0 \snext0 \sautoupd toc 4;}{\s22\li800\widctlpar\adjustright \fs20\cgrid \sbasedon0 \snext0 \sautoupd toc 5;}{\s23\li1000\widctlpar\adjustright \fs20\cgrid \sbasedon0 \snext0 \sautoupd toc 6;}{ -\s24\li1200\widctlpar\adjustright \fs20\cgrid \sbasedon0 \snext0 \sautoupd toc 7;}{\s25\li1400\widctlpar\adjustright \fs20\cgrid \sbasedon0 \snext0 \sautoupd toc 8;}{\s26\li1600\widctlpar\adjustright \fs20\cgrid \sbasedon0 \snext0 \sautoupd toc 9;}{ -\s27\widctlpar\adjustright \cbpat9 \f15\fs20\cgrid \sbasedon0 \snext27 Document Map;}}{\*\listtable{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext -\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid22442644}{\list\listtemplateid1593215596{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext -\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1440\jclisttab\tx1440 }{\listlevel -\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li2160\jclisttab\tx2160 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0 -{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880\jclisttab\tx2880 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600 } -{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li4320\jclisttab\tx4320 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360 -\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5040\jclisttab\tx5040 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760 -\jclisttab\tx5760 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li6480\jclisttab\tx6480 }{\listname ;}\listid56512481}{\list\listtemplateid-332364684 -{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'02\'00.;}{\levelnumbers\'01;}\fbias0 \s1\fi-360\li360\jclisttab\tx360 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0 -\levelindent0{\leveltext\'03\'00.\'01;}{\levelnumbers\'01\'03;}\fbias0 \s2\fi-390\li390\jclisttab\tx390 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'05\'00.\'01.\'02;}{\levelnumbers -\'01\'03\'05;}\fbias0 \s3\fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'07\'00.\'01.\'02.\'03;}{\levelnumbers\'01\'03\'05\'07;}\fbias0 \fi-1080\li1080 -\jclisttab\tx1080 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'09\'00.\'01.\'02.\'03.\'04;}{\levelnumbers\'01\'03\'05\'07\'09;}\fbias0 \fi-1080\li1080\jclisttab\tx1080 }{\listlevel\levelnfc0 -\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'0b\'00.\'01.\'02.\'03.\'04.\'05;}{\levelnumbers\'01\'03\'05\'07\'09\'0b;}\fbias0 \fi-1440\li1440\jclisttab\tx1440 }{\listlevel\levelnfc0\leveljc0\levelfollow0 -\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'0d\'00.\'01.\'02.\'03.\'04.\'05.\'06;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d;}\fbias0 \fi-1440\li1440\jclisttab\tx1440 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal -\levelspace0\levelindent0{\leveltext\'0f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f;}\fbias0 \fi-1800\li1800\jclisttab\tx1800 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0 -\levelindent0{\leveltext\'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\fbias0 \fi-1800\li1800\jclisttab\tx1800 }{\listname ;}\listid155609463}{\list\listtemplateid1706078190\listsimple{\listlevel -\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid602111040}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23 -\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid621424954}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0 -\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid717362522}{\list\listtemplateid67698689\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0 -\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li360\jclisttab\tx360 }{\listname ;}\listid1064328194}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1 -\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname ;}\listid1080104542}{\list\listtemplateid-5054418{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat2\levelspace0\levelindent0 -{\leveltext\'01\'00;}{\levelnumbers\'01;}\fbias0 \fi-435\li435\jclisttab\tx435 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'03\'00.\'01;}{\levelnumbers\'01\'03;}\fbias0 \fi-435\li435\jclisttab\tx435 } -{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat2\levelspace0\levelindent0{\leveltext\'05\'00.\'01.\'02;}{\levelnumbers\'01\'03\'05;}\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0 -\levelindent0{\leveltext\'07\'00.\'01.\'02.\'03;}{\levelnumbers\'01\'03\'05\'07;}\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext -\'09\'00.\'01.\'02.\'03.\'04;}{\levelnumbers\'01\'03\'05\'07\'09;}\fbias0 \fi-1080\li1080\jclisttab\tx1080 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0b\'00.\'01.\'02.\'03.\'04.\'05;}{\levelnumbers -\'01\'03\'05\'07\'09\'0b;}\fbias0 \fi-1080\li1080\jclisttab\tx1080 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0d\'00.\'01.\'02.\'03.\'04.\'05.\'06;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d;}\fbias0 -\fi-1440\li1440\jclisttab\tx1440 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'0f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f;}\fbias0 \fi-1440\li1440 -\jclisttab\tx1440 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\fbias0 \fi-1800\li1800\jclisttab\tx1800 -}{\listname ;}\listid1262834005}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname -;}\listid1272592440}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname -;}\listid1339387548}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname -;}\listid1409111490}{\list\listtemplateid1666980492{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listlevel\levelnfc23\leveljc0 -\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1440\jclisttab\tx1440 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext -\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li2160\jclisttab\tx2160 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880\jclisttab\tx2880 } -{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0 -{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li4320\jclisttab\tx4320 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5040 -\jclisttab\tx5040 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760\jclisttab\tx5760 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360 -\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li6480\jclisttab\tx6480 }{\listname ;}\listid1484007768}{\list\listtemplateid230209238{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat3\levelspace0\levelindent0{\leveltext -\'02\'00.;}{\levelnumbers\'01;}\fbias0 \fi-360\li360\jclisttab\tx360 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'03\'00.\'01;}{\levelnumbers\'01\'03;}\fbias0 \fi-360\li360\jclisttab\tx360 } -{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext\'05\'00.\'01.\'02;}{\levelnumbers\'01\'03\'05;}\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1 -\levellegal\levelspace0\levelindent0{\leveltext\'07\'00.\'01.\'02.\'03;}{\levelnumbers\'01\'03\'05\'07;}\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext -\'09\'00.\'01.\'02.\'03.\'04;}{\levelnumbers\'01\'03\'05\'07\'09;}\fbias0 \fi-720\li720\jclisttab\tx720 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext -\'0b\'00.\'01.\'02.\'03.\'04.\'05;}{\levelnumbers\'01\'03\'05\'07\'09\'0b;}\fbias0 \fi-1080\li1080\jclisttab\tx1080 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext -\'0d\'00.\'01.\'02.\'03.\'04.\'05.\'06;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d;}\fbias0 \fi-1080\li1080\jclisttab\tx1080 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext -\'0f\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f;}\fbias0 \fi-1440\li1440\jclisttab\tx1440 }{\listlevel\levelnfc0\leveljc0\levelfollow0\levelstartat1\levellegal\levelspace0\levelindent0{\leveltext -\'11\'00.\'01.\'02.\'03.\'04.\'05.\'06.\'07.\'08;}{\levelnumbers\'01\'03\'05\'07\'09\'0b\'0d\'0f\'11;}\fbias0 \fi-1440\li1440\jclisttab\tx1440 }{\listname ;}\listid1502426668}{\list\listtemplateid355235766{\listlevel\levelnfc23\leveljc0\levelfollow0 -\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li360\jclisttab\tx360 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 -\fi-360\li1080\jclisttab\tx1080 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li1800\jclisttab\tx1800 }{\listlevel\levelnfc23\leveljc0\levelfollow0 -\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2520\jclisttab\tx2520 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;} -\f2\fbias0 \fi-360\li3240\jclisttab\tx3240 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li3960\jclisttab\tx3960 }{\listlevel\levelnfc23\leveljc0 -\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li4680\jclisttab\tx4680 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext -\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5400\jclisttab\tx5400 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li6120\jclisttab\tx6120 }{\listname -;}\listid1523011899}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname -;}\listid1645162521}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname -;}\listid2006126440}{\list\listtemplateid1706078190\listsimple{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace0\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li720\jclisttab\tx720 }{\listname -;}\listid2076124660}{\list\listtemplateid1666980492{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li720\jclisttab\tx720 }{\listlevel\levelnfc23\leveljc0 -\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li1440\jclisttab\tx1440 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext -\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li2160\jclisttab\tx2160 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li2880\jclisttab\tx2880 } -{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li3600\jclisttab\tx3600 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0 -{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li4320\jclisttab\tx4320 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01\u-3913 ?;}{\levelnumbers;}\f3\fbias0 \fi-360\li5040 -\jclisttab\tx5040 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360\levelindent0{\leveltext\'01o;}{\levelnumbers;}\f2\fbias0 \fi-360\li5760\jclisttab\tx5760 }{\listlevel\levelnfc23\leveljc0\levelfollow0\levelstartat1\levelspace360 -\levelindent0{\leveltext\'01\u-3929 ?;}{\levelnumbers;}\f14\fbias0 \fi-360\li6480\jclisttab\tx6480 }{\listname ;}\listid2112620548}}{\*\listoverridetable{\listoverride\listid155609463\listoverridecount0\ls1}{\listoverride\listid1409111490 -\listoverridecount0\ls2}{\listoverride\listid1272592440\listoverridecount0\ls3}{\listoverride\listid2076124660\listoverridecount0\ls4}{\listoverride\listid717362522\listoverridecount0\ls5}{\listoverride\listid1339387548\listoverridecount0\ls6} -{\listoverride\listid621424954\listoverridecount0\ls7}{\listoverride\listid1080104542\listoverridecount0\ls8}{\listoverride\listid1262834005\listoverridecount0\ls9}{\listoverride\listid2006126440\listoverridecount0\ls10}{\listoverride\listid602111040 -\listoverridecount0\ls11}{\listoverride\listid22442644\listoverridecount0\ls12}{\listoverride\listid1502426668\listoverridecount0\ls13}{\listoverride\listid1645162521\listoverridecount0\ls14}{\listoverride\listid1064328194\listoverridecount0\ls15} -{\listoverride\listid2112620548\listoverridecount0\ls16}{\listoverride\listid1484007768\listoverridecount0\ls17}{\listoverride\listid1523011899\listoverridecount0\ls18}{\listoverride\listid56512481\listoverridecount0\ls19}}{\info -{\title Writing a Simulator for the SIMH System}{\author Bob Supnik}{\operator Bob Supnik}{\creatim\yr1997\mo8\dy30\hr19}{\revtim\yr2001\mo10\dy20\hr10\min58}{\version29}{\edmins519}{\nofpages19}{\nofwords6533}{\nofchars-32766} -{\*\company Digital Equipment Corporation}{\nofcharsws0}{\vern113}}\widowctrl\ftnbj\aenddoc\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\hyphcaps0\formshade\viewkind4\viewscale100\pgbrdrhead\pgbrdrfoot \fet0\sectd -\linex0\endnhere\sectdefaultcl {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl4 -\pnlcltr\pnstart1\pnindent720\pnhang{\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (} -{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}\pard\plain \widctlpar\outlinelevel0\adjustright \fs20\cgrid {\f1 -Writing a Simulator for the SIMH System -\par }\pard \widctlpar\adjustright {\f1 Revised 20-Oct-01 for V2.7-14 -\par -\par }\pard\plain \s18\sb120\widctlpar\tx400\tqr\tldot\tx8630\adjustright \b\i\cgrid {\field\fldedit{\*\fldinst {\f1 TOC \\o }}{\fldrslt {\lang1024 1.\tab Overview\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228037 \\h }{\fs20\lang1024 {\*\datafield -08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003500320036003200320038003000330037000000000000001e006f}}}{\fldrslt {\lang1024 1}}}{\lang1024 -\par 2.\tab Data Types\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228038 \\h }{\fs20\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300033003800000000016f00000000}}}{\fldrslt { -\lang1024 2}}}{\lang1024 -\par 3.\tab VM Organization\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228039 \\h }{\fs20\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300033003900000000010000001e00}} -}{\fldrslt {\lang1024 2}}}{\lang1024 -\par }\pard\plain \s19\li200\sb120\widctlpar\tx800\tqr\tldot\tx8630\adjustright \b\fs22\cgrid {\lang1024 3.1\tab CPU Organization\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228040 \\h }{\fs20\lang1024 {\*\datafield -08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300034003000000000020100000004}}}{\fldrslt {\lang1024 3}}}{\lang1024 -\par }\pard\plain \s20\li400\widctlpar\tx1200\tqr\tldot\tx8630\adjustright \fs20\cgrid {\lang1024 3.1.1\tab Time Base\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228041 \\h }{\lang1024 {\*\datafield -08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300034003100000000001e0000001e}}}{\fldrslt {\lang1024 4}}}{\lang1024 -\par 3.1.2\tab Memory Organization\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228042 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300034003200000000000000006f00}} -}{\fldrslt {\lang1024 4}}}{\lang1024 -\par 3.1.3\tab Interrupt Organization\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228043 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f00630035003200360032003200380030003400330000000001fe00000000}} -}{\fldrslt {\lang1024 4}}}{\lang1024 -\par 3.1.4\tab I/O Dispatching\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228044 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300034003400000000000000eb0280}}}{\fldrslt -{\lang1024 5}}}{\lang1024 -\par 3.1.5\tab Instruction Execution\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228045 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003500320036003200320038003000340035000000000080000201ff}} -}{\fldrslt {\lang1024 5}}}{\lang1024 -\par }\pard\plain \s19\li200\sb120\widctlpar\tx800\tqr\tldot\tx8630\adjustright \b\fs22\cgrid {\lang1024 3.2\tab Peripheral Device Organization\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228046 \\h }{\fs20\lang1024 {\*\datafield -08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300034003600000000640100006401}}}{\fldrslt {\lang1024 6}}}{\lang1024 -\par }\pard\plain \s20\li400\widctlpar\tx1200\tqr\tldot\tx8630\adjustright \fs20\cgrid {\lang1024 3.2.1\tab Device Timing\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228047 \\h }{\lang1024 {\*\datafield -08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f00630035003200360032003200380030003400370000000000000001fe00}}}{\fldrslt {\lang1024 7}}}{\lang1024 -\par 3.2.2\tab Clock Calibration\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228048 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f0063003500320036003200320038003000340038000000000000008002e2}} -}{\fldrslt {\lang1024 8}}}{\lang1024 -\par 3.2.3\tab Data I/O\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228049 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300034003900000000000000000000}}}{\fldrslt { -\lang1024 9}}}{\lang1024 -\par }\pard\plain \s18\sb120\widctlpar\tx400\tqr\tldot\tx8630\adjustright \b\i\cgrid {\lang1024 4.\tab Data Structures\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228050 \\h }{\fs20\lang1024 {\*\datafield -08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300035003000000000000000000000}}}{\fldrslt {\lang1024 10}}}{\lang1024 -\par }\pard\plain \s19\li200\sb120\widctlpar\tx800\tqr\tldot\tx8630\adjustright \b\fs22\cgrid {\lang1024 4.1\tab device Structure\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228051 \\h }{\fs20\lang1024 {\*\datafield -08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300035003100000000000000000000}}}{\fldrslt {\lang1024 10}}}{\lang1024 -\par }\pard\plain \s20\li400\widctlpar\tx1200\tqr\tldot\tx8630\adjustright \fs20\cgrid {\lang1024 4.1.1\tab Examine and Deposit Routines\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228052 \\h }{\lang1024 {\*\datafield -08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300035003200000000000000000000}}}{\fldrslt {\lang1024 11}}}{\lang1024 -\par 4.1.2\tab Reset Routine\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228053 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300035003300000000000000000000}}}{\fldrslt { -\lang1024 11}}}{\lang1024 -\par 4.1.3\tab Boot Routine\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228054 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300035003400000000000000000000}}}{\fldrslt { -\lang1024 11}}}{\lang1024 -\par 4.1.4\tab Attach and Detach Routines\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228055 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300035003500000000000000000000}} -}{\fldrslt {\lang1024 11}}}{\lang1024 -\par }\pard\plain \s19\li200\sb120\widctlpar\tx800\tqr\tldot\tx8630\adjustright \b\fs22\cgrid {\lang1024 4.2\tab unit Structure\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228056 \\h }{\fs20\lang1024 {\*\datafield -08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300035003600000000000000000000}}}{\fldrslt {\lang1024 12}}}{\lang1024 -\par }\pard\plain \s20\li400\widctlpar\tx1200\tqr\tldot\tx8630\adjustright \fs20\cgrid {\lang1024 4.2.1\tab Unit Flags\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228057 \\h }{\lang1024 {\*\datafield -08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300035003700000000000000000000}}}{\fldrslt {\lang1024 13}}}{\lang1024 -\par 4.2.2\tab Service Routine\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228058 \\h }{\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300035003800000000000000000000}}}{\fldrslt -{\lang1024 13}}}{\lang1024 -\par }\pard\plain \s19\li200\sb120\widctlpar\tx800\tqr\tldot\tx8630\adjustright \b\fs22\cgrid {\lang1024 4.3\tab reg Structure\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228059 \\h }{\fs20\lang1024 {\*\datafield -08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300035003900000000000000000000}}}{\fldrslt {\lang1024 13}}}{\lang1024 -\par }\pard\plain \s20\li400\widctlpar\tx1200\tqr\tldot\tx8630\adjustright \fs20\cgrid {\lang1024 4.3.1\tab Register Flags\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228060 \\h }{\lang1024 {\*\datafield -08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300036003000000000000000000000}}}{\fldrslt {\lang1024 14}}}{\lang1024 -\par }\pard\plain \s19\li200\sb120\widctlpar\tx800\tqr\tldot\tx8630\adjustright \b\fs22\cgrid {\lang1024 4.4\tab mtab Structure\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228061 \\h }{\fs20\lang1024 {\*\datafield -08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300036003100000000000000000000}}}{\fldrslt {\lang1024 15}}}{\lang1024 -\par }\pard\plain \s20\li400\widctlpar\tx1200\tqr\tldot\tx8630\adjustright \fs20\cgrid {\lang1024 4.4.1\tab Validation/Display Routine\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228062 \\h }{\lang1024 {\*\datafield -08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300036003200000000000000000000}}}{\fldrslt {\lang1024 15}}}{\lang1024 -\par }\pard\plain \s19\li200\sb120\widctlpar\tx800\tqr\tldot\tx8630\adjustright \b\fs22\cgrid {\lang1024 4.5\tab Other Data Structures\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228063 \\h }{\fs20\lang1024 {\*\datafield -08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300036003300000000000000000000}}}{\fldrslt {\lang1024 15}}}{\lang1024 -\par }\pard\plain \s18\sb120\widctlpar\tx400\tqr\tldot\tx8630\adjustright \b\i\cgrid {\lang1024 5.\tab VM Provided Routines\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228064 \\h }{\fs20\lang1024 {\*\datafield -08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300036003400000000000000000000}}}{\fldrslt {\lang1024 16}}}{\lang1024 -\par }\pard\plain \s19\li200\sb120\widctlpar\tx800\tqr\tldot\tx8630\adjustright \b\fs22\cgrid {\lang1024 5.1\tab Instruction Execution\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228065 \\h }{\fs20\lang1024 {\*\datafield -08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300036003500000000000000000000}}}{\fldrslt {\lang1024 16}}}{\lang1024 -\par 5.2\tab Binary Load and Dump\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228066 \\h }{\fs20\lang1024 {\*\datafield 08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300036003600000000000000000000}} -}{\fldrslt {\lang1024 16}}}{\lang1024 -\par 5.3\tab Symbolic Examination and Deposit\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228067 \\h }{\fs20\lang1024 {\*\datafield -08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300036003700000000000000000000}}}{\fldrslt {\lang1024 16}}}{\lang1024 -\par 5.4\tab Multi-Terminal Support (Telnet)\tab }{\field{\*\fldinst {\lang1024 PAGEREF _Toc526228068 \\h }{\fs20\lang1024 {\*\datafield -08d0c9ea79f9bace118c8200aa004ba90b02000000080000000e0000005f0054006f006300350032003600320032003800300036003800000000000000000000}}}{\fldrslt {\lang1024 17}}}{\lang1024 -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid }}\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par {\*\bkmkstart _Toc526228037}{\listtext\pard\plain\s1 \b\f1\fs28\kerning28\cgrid \hich\af1\dbch\af0\loch\f1 1.\tab}}\pard\plain \s1\fi-360\li360\sb240\sa60\keepn\widctlpar\jclisttab\tx360\ls1\outlinelevel0\adjustright \b\f1\fs28\kerning28\cgrid {Overview -{\*\bkmkend _Toc526228037} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par SIMH (history simulators) is a set of portab -le programs, written in C, which simulate various historically interesting computers. This document describes how to design, write, and check out a new simulator for SIMH. It is not an introduction to either the philosophy or external operation of SIMH, - -and the reader should be familiar with both of those topics before proceeding. Nor is it a guide to the internal design or operation of SIMH, except insofar as those areas interact with simulator design. Instead, this manual presents and explains the fo -r -m, meaning, and operation of the interfaces between simulators and the SIMH simulator control package. It also offers some suggestions for utilizing the services SIMH offers and explains the constraints that all simulators operating within SIMH will expe -rience. -\par -\par Some terminology: Each simulator consists of a standard }{\i\f1 simulator control package}{\f1 (SCP), which provides a control framework and utility routines for a simulator; and a unique }{\i\f1 virtual machine}{\f1 - (VM), which implements the simulated processor and selected peripherals. A VM consists of multiple }{\i\f1 devices}{\f1 , such as the CPU, paper tape reader, disk controller, etc. Each controller consists of a named state space (called }{\i\f1 -registers}{\f1 ) and one or more }{\i\f1 units}{\f1 . Each unit consists of a numbered state space (called a }{\i\f1 data set}{\f1 ). }{\i\f1 }{\f1 The }{\i\f1 host computer}{\f1 is the system on which SIMH runs; the }{\i\f1 target computer}{\f1 - is the system being simulated. -\par -\par SIMH is unabashedly based on the MIMIC simulation system, designed in the late 1960\rquote s by Len Fehskens, Mike McCarthy, and Bob Supnik. This document is based on MIMIC\rquote s published interface specification, \ldblquote -How to Write a Virtual Machine for the MIMIC Simulation System\rdblquote , by Len Fehskens and Bob Supnik. -\par -\par {\*\bkmkstart _Toc526228038}{\listtext\pard\plain\s1 \b\f1\fs28\kerning28\cgrid \hich\af1\dbch\af0\loch\f1 2.\tab}}\pard\plain \s1\fi-360\li360\sb240\sa60\keepn\widctlpar\jclisttab\tx360\ls1\outlinelevel0\adjustright \b\f1\fs28\kerning28\cgrid {Data Types -{\*\bkmkend _Toc526228038} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par SIMH is written in C. The host system must support (at least) 32-bit data types (64-bit data types for the PDP-10 and other large-word target systems). To cope with the vagaries of C data types, SIMH defines some unambiguous data types for its inter -faces: -\par -\par \tab SIMH data type\tab \tab \tab interpretation in typical 32-bit C -\par -\par \tab int8, uint8\tab \tab \tab char, unsigned char -\par \tab int16, uint16\tab \tab \tab short, unsigned short -\par \tab int32, uint32\tab \tab \tab int, unsigned int -\par \tab t_int64, t_uint64\tab \tab \tab long long, _int64 (system specific) -\par \tab t_addr\tab \tab \tab \tab simulated address, int32 -\par \tab t_value\tab \tab \tab \tab simulated value, unsigned int32 or int64 -\par \tab t_svalue\tab \tab \tab simulated signed value, int32 or int64 -\par \tab t_mtrec\tab \tab \tab \tab mag tape record length, int32 -\par \tab t_stat\tab \tab \tab \tab status code, int -\par \tab t_bool\tab \tab \tab \tab true/false value, int -\par -\par [The inconsistency in naming t_int64 and t_uint64 is due to VC++, which uses int64 as a structure name member in the master Windows definitions file.] -\par -\par }\pard \widctlpar\outlinelevel0\adjustright {\f1 In addition, SIMH defines structures for each of its major data elements -\par }\pard \widctlpar\adjustright {\f1 -\par \tab }{\b\f1 DEVICE}{\f1 \tab \tab \tab device definition structure -\par \tab }{\b\f1 UNIT}{\f1 \tab \tab \tab \tab unit definition structure -\par \tab }{\b\f1 REG}{\f1 \tab \tab \tab \tab register definition structure -\par \tab }{\b\f1 MTAB}{\f1 \tab \tab \tab \tab modifier definition structure -\par -\par {\*\bkmkstart _Toc526228039}{\listtext\pard\plain\s1 \b\f1\fs28\kerning28\cgrid \hich\af1\dbch\af0\loch\f1 3.\tab}}\pard\plain \s1\fi-360\li360\sb240\sa60\keepn\widctlpar\jclisttab\tx360\ls1\outlinelevel0\adjustright \b\f1\fs28\kerning28\cgrid { -VM Organization{\*\bkmkend _Toc526228039} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par A virtual machine (VM) is a collection of devices bound together through their internal logic. Each device is named and corresponds more or less to a hunk of hardware on the real machine; for example: -\par -\par \tab VM device\tab \tab \tab Real machine hardware -\par -\par \tab CPU\tab \tab \tab \tab central processor and main memory -\par \tab PTR\tab \tab \tab \tab paper tape reader controller and paper tape reader -\par \tab TTI\tab \tab \tab \tab console keyboard -\par \tab TTO\tab \tab \tab \tab console output -\par \tab DKP\tab \tab \tab \tab disk pack controller and drives -\par -\par There may be more than one device per physical hardware entity, as for the console; but for each user-accessible device there -must be at least one. One of these devices will have the pre-eminent responsibility for directing simulated operations. Normally, this is the CPU, but it could be a higher-level entity, such as a bus master. -\par -\par The VM actually runs as a subroutine of the simulator control package (SCP). It provides a master routine for running simulated programs and other routines and data structures to implement SCP\rquote -s command and control functions. The interfaces between a VM and SCP are relatively few: -\par -\par \tab Interface\tab \tab \tab Function -\par -\par \tab char }{\b\f1 sim_name[]}{\f1 \tab \tab simulator name string -\par \tab REG *}{\b\f1 sim_pc}{\f1 \tab \tab \tab pointer to simulated program counter -\par \tab int32 }{\b\f1 sim_emax}{\f1 \tab \tab maximum number of words in an instruction -\par \tab DEVICE *}{\b\f1 sim_devices[]}{\f1 \tab table of pointers to simulated devices, NULL terminated -\par \tab UNIT }{\b\f1 *sim_consoles[]}{\f1 \tab \tab table of pointers to simulated consoles -\par \tab char *}{\b\f1 sim_stop_messages[]}{\f1 \tab table of pointers to error messages -\par \tab t_stat }{\b\f1 sim_load}{\f1 (\'85)\tab \tab binary loader subroutine -\par \tab t_stat }{\b\f1 sim_inst}{\f1 (void)\tab \tab instruction execution subroutine -\par \tab t_stat }{\b\f1 parse_sym}{\f1 (\'85)\tab \tab symbolic instruction parse subroutine (optional) -\par \tab t_stat }{\b\f1 fprint_sym}{\f1 (\'85)\tab \tab symbolic instruction print subroutine (optional) -\par -\par There is no required organization for VM code. The following convention has been used so far. Let name be the }{\i\f1 name}{\f1 of the real system (i1401 for the IBM 1401; pdp1 for the PDP-1; pdp18b for the other 18-bit PDP\rquote -s; pdp8 for the PDP-8; pdp11 for the PDP-11; nova for Nova; hp2100 for the HP 21XX; id4 for the Interdata 4; pdp10 for the PDP-10): -\par -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls2\adjustright {\i\f1 name}{\f1 -.h contains definitions for the particular simulator -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls2\adjustright {\i\f1 name}{\f1 -_sys.c contains all the SCP interfaces except the instruction simulator -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls2\adjustright {\i\f1 name}{\f1 -_cpu.c contains the instruction simulator and CPU data structures -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls2\adjustright {\i\f1 name}{\f1 -_stddev.c contains the peripherals which were standard with the real system. -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls2\adjustright {\i\f1 name}{\f1 _lp.c contains th -e line printer. -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls2\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls2\adjustright {\i\f1 name}{\f1 -_mt.c contains the mag tape controller and drives, etc. -\par }\pard \fi1440\widctlpar\adjustright {\f1 -\par }\pard \widctlpar\adjustright {\f1 The SIMH standard definitions are in sim_defs.h, the simulator control package in scp.c, and the operating-system dependent terminal routines in scp_tty.c. Additional librarie -s include sim_tmxr.c (header file sim_tmxr.h) for terminal multiplexors, and sim_sock.c (header file sim_sock.h) for network processing. -\par {\*\bkmkstart _Toc526228040}{\listtext\pard\plain\s2 \b\i\f1\cgrid \hich\af1\dbch\af0\loch\f1 3.1\tab}}\pard\plain \s2\fi-390\li390\sb240\sa60\keepn\widctlpar\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid {CPU Organization -{\*\bkmkend _Toc526228040} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par Most CPU\rquote s perform at least the following functions: -\par -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls3\adjustright {\f1 Time keeping -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls3\adjustright {\f1 Instruction fetching -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls3\adjustright {\f1 Address decoding -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls3\adjustright {\f1 Execution of non-I/O instructions - -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls3\adjustright {\f1 I/O command processing -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls3\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls3\adjustright {\f1 Interrupt processing -\par }\pard \widctlpar\adjustright {\f1 -\par Instruction execution is actually the least complicated part of the design; memory and I/O organization should be tackled first. -\par {\*\bkmkstart _Toc526228041}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 3.1.1\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Time Base{\*\bkmkend _Toc526228041} - -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par In order to simulate asynchronous events, such as I/O completion, the VM must define and keep a time base. This can be accurate (for example, nanoseconds of execution) or arbitrary (for example, number of ins -tructions executed), but it must be consistently used throughout the VM. All existing VM\rquote s count time in instructions. -\par -\par The CPU is responsible for counting down the event counter }{\b\f1 sim_interval}{\f1 and calling the asynchronous event controller }{\b\f1 sim_process_event}{\f1 . The record keeping for timing is done by SCP. -\par {\*\bkmkstart _Toc526228042}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 3.1.2\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Memory Organization -{\*\bkmkend _Toc526228042} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par The criterion for memory layout is very simple: use the SIMH data type that is as large as (or if necessary, larger than), the word length of the real mac -hine. Note that the criterion is word length, not addressability: the PDP-11 has byte addressable memory, but it is a 16-bit machine, and its memory is defined as uint16 M[]. It may seem tempting to define memory as a union of int8 and int16 data types, - but this would make the resulting VM endian-dependent. Instead, the VM should be based on the underlying word size of the real machine, and byte manipulation should be done explicitly. Examples: -\par -\par \tab Simulator\tab \tab memory size\tab \tab memory declaration -\par -\par \tab IBM 1401\tab \tab 6-bit\tab \tab \tab uint8 -\par \tab PDP-8\tab \tab \tab 12-bit\tab \tab \tab uint16 -\par \tab PDP-11, Nova\tab \tab 16-bit\tab \tab \tab uint16 -\par \tab PDP-1\tab \tab \tab 18-bit\tab \tab \tab uint32 -\par \tab PDP-10\tab \tab \tab 36-bit\tab \tab \tab uint64 -\par {\*\bkmkstart _Toc526228043}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 3.1.3\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Interrupt Organization -{\*\bkmkend _Toc526228043} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par The design of the VM\rquote s interrupt structure is a complex interaction between efficiency and fidelity to the hardware. If the VM\rquote -s interrupt structure is too abstract, interrupt driven software may not run. On the other hand, if it follows the hardware too literally, it may si -gnificantly reduce simulation speed. One rule I can offer is to minimize the fetch-phase cost of interrupts, even if this complicates the (much less frequent) evaluation of the interrupt system following an I/O operation or asynchronous event. Another i -s not to over-generalize; even if the real hardware could support 64 or 256 interrupting devices, the simulators will be running much smaller configurations. I\rquote -ll start with a simple interrupt structure and then offer suggestions for generalization. -\par -\par In th -e simplest structure, interrupt requests correspond to device flags and are kept in an interrupt request variable, with one flag per bit. The fetch-phase evaluation of interrupts consists of two steps: are interrupts enabled, and is there an interrupt ou -tstanding? If all the interrupt requests are kept as single-bit flags in a variable, the fetch-phase test is very fast: -\par -\par \tab if (int_enable && int_requests) \{ \'85process interrupt\'85 \} -\par -\par Indeed, the interrupt enable flag can be made the highest bit in the interrupt request variable, and the two tests combined: -\par -\par \tab if (int_requests > INT_ENABLE) \{ \'85process interrupt\'85 \} -\par -\par Setting or clearing device flags directly sets or clears the appropriate interrupt request flag: -\par -\par \tab set: \tab int_requests = int_requests | DEVICE_FLAG; -\par \tab clear:\tab int_requests = int_requests & ~DEVICE_FLAG; -\par -\par At a slightly higher complexity, interrupt requests do not correspond directly to device flags but are based on masking the device flags with an enable (or disable) mask. There are now three parallel vari -ables: interrupt requests, device flags, and interrupt enable mask. The fetch-phase test does not change; however, the evaluation of whether an interrupt is pending now requires an extra step: -\par -\par \tab enable:\tab int_requests = device_flags & int_enables; -\par \tab disable:\tab int_requests = device_flags & ~int_disables; -\par -\par If required for interrupt processing, the highest priority interrupting device can be determined by scanning the interrupt request variable from high priority to low until a set bit is found. The bit position - can then be back-mapped through a table to determine the address or interrupt vector of the interrupting device. -\par -\par At yet higher complexity, the interrupt system may be too complex or too large to evaluate during the fetch-phase. In this case, an interrup -t pending flag is created, and it is evaluated by subroutine call whenever a change could occur (start of execution, I/O instruction issued, device time out occurs). This makes fetch-phase evaluation simple and isolates interrupt evaluation to a common s -ubroutine. -\par {\*\bkmkstart _Toc526228044}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 3.1.4\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {I/O Dispatching -{\*\bkmkend _Toc526228044} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par I/O dispatching consists of four steps: -\par -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls14\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls14\adjustright {\f1 -Identify the I/O command and analyze for the device address. -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls14\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls14\adjustright {\f1 Locate the selected device. - -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls14\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls14\adjustright {\f1 -Break down the I/O command into standard fields. -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls14\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls14\adjustright {\f1 Call the device processor. -\par }\pard \widctlpar\adjustright {\f1 -\par Analyzing an I/O command is usually easy. Most systems have one or more explicit I/O instructions containing an I/O command and a device address. Memory mapped I/O is more complicated; the identification of a reference to I/O -space becomes part of memory addressing. This usually requires centralizing memory reads and writes into subroutines, rather than as inline code. -\par -\par Once an I/O command has been analyzed, the CPU must locate the device subroutine. The simplest way is a lar -ge switch statement with hardwired subroutine calls. Slightly more modular is to call through a dispatch table, with NULL entries representing non-existent devices. Before calling the device routine, the CPU usually breaks down the I/O command into stan -dard fields. This simplifies writing the peripheral simulator. -\par {\*\bkmkstart _Toc526228045}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 3.1.5\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Instruction Execution -{\*\bkmkend _Toc526228045} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par Instruction execution is the responsibility of VM subroutine }{\b\f1 sim_instr}{\f1 . It is called from SCP as a result of a RUN, GO, CONT, or BOOT command. It begins executing instructions at the current PC (}{\b\f1 sim_PC}{\f1 - points to its register description block) and continues until halted by an error or an external event. -\par -\par When called, the CPU needs to account for any state changes that the user made. For e -xample, it may need to re-evaluate whether an interrupt is pending, or restore frequently used state to local register variables for efficiency. The actual instruction fetch and execute cycle is usually structured as a loop controlled by an error variabl -e, e.g., -\par -\par \tab reason = 0; -\par \tab do \{ \'85 \} while (reason == 0);\tab or\tab while (reason == 0) \{ \'85 \} -\par -\par Within this loop, the usual order of events is: -\par -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls4\adjustright {\f1 If the event timer }{\b\f1 -sim_interval}{\f1 has reached zero, process any timed events. This is done by SCP subroutine }{\b\f1 sim_process_event}{\f1 . Because this is the polling mechanism for user-generated processor halts (^E), errors must be recognized immediately: -\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 -\par }\pard \li1440\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 if (sim_interval <= 0) \{ -\par }\pard \fi720\li1440\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 if (reason = sim_process_event ()) break; \} -\par }\pard \fi2160\widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls4\adjustright {\f1 -Check for outstanding interrupts and process if required. -\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls4\adjustright {\f1 -Check for other processor-unique events, such as wait-state outstanding or traps outstanding. -\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls4\adjustright {\f1 -Check for an instruction breakpoint. SCP has no breakpoint facility, but it is customary to implement a single instruction breakpoint to help with processor code. All the existing CPU\rquote s use the same mechanism, see the sources for details. -\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls4\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls4\adjustright {\f1 Fetch the n -ext instruction, increment the PC, optionally decode the address, and dispatch (via a switch statement) for execution. -\par }\pard \widctlpar\adjustright {\f1 -\par A few guidelines for implementation: -\par -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls5\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls5\adjustright {\f1 -In general, code should reflect the hardware being simulated. This is usually simplest and easiest to debug. -\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls5\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls5\adjustright {\f1 -The VM should provide some debugging aids. The existing CPU\rquote s all provide an instruction breakpoint, an OLDPC register, and error stops on invalid instructions or operations. -\par {\*\bkmkstart _Toc526228046}{\listtext\pard\plain\s2 \b\i\f1\cgrid \hich\af1\dbch\af0\loch\f1 3.2\tab}}\pard\plain \s2\fi-390\li390\sb240\sa60\keepn\widctlpar\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid { -Peripheral Device Organization{\*\bkmkend _Toc526228046} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par The basic elements of a VM are devices, each corresponding roughly to a real chunk of hardware. A device consists of register-based state and one or more units. Thus, a multi-drive disk subsystem is a single device (representing the hardware of the real - controller) and one or more units (each representing a single disk drive). Sometimes the device and its unit are the same entity as, for example, in the case of a paper tape reader. However, a single physical device, such as the console, may be broken -up for convenience into separate input and output devices. -\par -\par In general, units correspond to individual sources of input or output (one tape transport, one A-to-D channel). Units are the basic medium for both device timing and device I/O. Except for the co -nsole, all I/O devices are simulated as host-resident files. SCP allows the user to make an explicit association between a host-resident file and a simulated hardware entity. -\par -\par Both devices and units have state. Devices operate on }{\i\f1 registers}{\f1 , which contain information about the state of the device, and indirectly, about the state of the units. Units operate on }{\i\f1 data sets}{\f1 -, which may be thought of as individual instances of input or output, such as a disk pack or a punched paper tape. In a typical multi-unit - device, all units are the same, and the device performs similar operations on all of them, depending on which one has been selected by the program being simulated. -\par -\par (Note: SIMH, like MIMIC, restricts registers to devices. This requires replicated registers, for example, disk drive current state, to have unique names in the device name space.) -\par -\par For each structural level, SIMH defines, and the VM must supply, a corresponding data structure. }{\b\f1 device}{\f1 structures correspond to devices, }{\b\f1 reg}{\f1 structures to registers, and }{\b\f1 unit}{\f1 - structures to units. These structures are described in detail in section 4. -\par -\par The primary functions of a peripheral are: -\par -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls6\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls6\adjustright {\f1 command decoding and execution - -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls6\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls6\adjustright {\f1 device timing -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls6\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls6\adjustright {\f1 data transmission. -\par }\pard \widctlpar\adjustright {\f1 -\par Command decoding is fairly obvious. At least one section of the peripheral code module will be devoted to processing directives issued by the CPU. Typically, the command decoder will be responsible for register and flag manipulation, and for issuing or -canceling I/O requests. The former is easy, but the later requires a thorough understanding of device timing. -\par {\*\bkmkstart _Toc526228047}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 3.2.1\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Device Timing -{\*\bkmkend _Toc526228047} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par The principal problem in I/O device simulation is imitating asynchronous operations in a sequential - simulation environment. Fortunately, the timing characteristics of most I/O devices do not vary with external circumstances. The distinction between devices whose timing is externally generated (e.g., console keyboard) and those whose timing is externa -l -ly generated (disk, paper tape reader) is crucial. With an externally timed device, there is no way to know when an in-progress operation will begin or end; with an internally timed device, given the time when an operation starts, the end time can be cal -culated. -\par -\par For an internally timed device, the elapsed time between the start and conclusion of an operation is called the wait time. Some typical internally timed devices and their wait times include: -\par -\par \tab PTR (300 char/sec)\tab \tab 3.3 msec -\par \tab PTP (50 char/sec)\tab \tab 20 msec -\par \tab CLK (line frequency)\tab \tab 16.6 msec -\par \tab TTO (30 char/sec)\tab \tab 33 msec -\par -\par Mass storage devices, such as disks and tapes, do not have a fixed response time, but a start-to-finish time can be calculated based on current versus desired position, state of motion, etc. -\par -\par For an externally timed device, there is no portable mechanism by which a VM can be notified of an external event. Because the only important externally timed device is the console keyboard, all current VM\rquote -s poll for keyboard input, thus converting the externally timed keyboard to a pseudo-internally timed device. -\par -\par SCP provides the supporting routines for device timing. SCP maintains a list of devices (called }{\i\f1 active devices}{\f1 ) which are in the process of timing out. It also provides routines for querying or manipulating this list (called the }{\i\f1 -active queue}{\f1 ). Lastly, it provides a routine for checking for timed-out units and executing a VM-specified action when a time-out occurs. -\par -\par Device timing is done with the UNIT structure, described in section 3. To se -t up a timed operation, the peripheral calculates a waiting period for a unit and places that unit on the active queue. The CPU counts down the waiting period. When the waiting period has expired, }{\b\f1 sim_process_event}{\f1 - removes the unit from the active queue and calls a device subroutine. A device may also cancel an outstanding timed operation and query the state of the queue. The timing subroutines are: -\par -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls7\adjustright {\f1 t_stat }{\b\f1 sim_activate}{\f1 - (UNIT *uptr, int32 wait). This routine places the specified unit on the active q -ueue with the specified waiting period. A waiting period of 0 is legal; negative waits cause an error. If the unit is already active, the active queue is not changed, and no error occurs. -\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls7\adjustright {\f1 t_stat }{\b\f1 sim_cancel}{\f1 - (UNIT *uptr). This routine removes the specified unit from the active queue. If the unit is not on the queue, no error occurs. -\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls7\adjustright {\f1 int32 }{\b\f1 sim_is_active}{\f1 - (UNIT *uptr). This routine tests whether a unit is in the active queue. If it is, the routine returns the time (+1) remaining; if it is not, the routine returns 0. -\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls7\adjustright {\f1 double }{\b\f1 sim_gtime}{\f1 - (void). This routine returns the time elapsed since the last RUN or BOOT command. -\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls7\adjustright {\f1 uint32 }{\b\f1 sim_grtime}{\f1 - (void). This routine returns the low-order 32b of the time elapsed since the last RUN or BOOT command. -\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls7\adjustright {\f1 int32 }{\b\f1 sim_qcount}{\f1 - (void). This routine returns the number of entries on the clock queue. -\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls7\adjustright {\f1 t_stat }{\b\f1 sim_process_event}{ -\f1 (void). This routine removes all timed out units from the active queue and calls the appropriate device subroutine to service the time-out. -\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls7\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls7\adjustright {\f1 int32 }{\b\f1 sim_interval}{\f1 -. This variable counts down the first outstanding timed event. If there are no timed events outstanding, SCP counts down a \ldblquote null interval\rdblquote of 10,000 time units. -\par {\*\bkmkstart _Toc526228048}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 3.2.2\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Clock Calibration -{\*\bkmkend _Toc526228048} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par The timing mechanism described in the previous section is approximate. Devices, such as real-time clocks, which track wall time will be inaccurate. SCP provides routines to synchronize a simulated real-time clock to wall time. -\par -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360{\*\pn \pnlvlblt\ilvl0\ls15\pnrnot0\pnf3\pnstart1\pnindent360\pnhang{\pntxtb \'b7}}\ls15\adjustright {\f1 int32 }{\b\f1 sim_rtc_init}{\f1 - (int32 clock_interval). This routine initializes the clock calibration mechanism. The argument is returned as the result. -\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li360\widctlpar\jclisttab\tx360{\*\pn \pnlvlblt\ilvl0\ls15\pnrnot0\pnf3\pnstart1\pnindent360\pnhang{\pntxtb \'b7}}\ls15\adjustright {\f1 int32 }{\b\f1 sim_rtc_calb}{\f1 - (int32 tickspersecond). This routine calibrates the real-time clock. The argument is the number of clock ticks expected per second. -\par }\pard \widctlpar\adjustright {\f1 -\par The simulator calls }{\b\f1 sim_rtc_init}{\f1 in the prolog of }{\b\f1 sim_instr}{\f1 , before instruction execution starts, and whenever the real-time clock is started. The simulator calls }{\b\f1 sim_rtc_calb}{\f1 - to calculate the actual interval delay when the real-time clock is serviced: -\par -\par \tab /* clock start */ -\par -\par \tab if (!sim_is_active (&clk_unit)) sim_activate (&clk_unit, sim_rtc_init (clk_delay)); -\par \tab etc. -\par -\par \tab /* clock service */ -\par -\par \tab sim_activate (&clk_unit, sim_rtc_calb (clk_ticks_per_second); -\par {\*\bkmkstart _Toc526228049}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 3.2.3\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Data I/O{\*\bkmkend _Toc526228049} - -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par For most devices, timing is half the battle (for clocks it is the entire war); the other half is I/O. Except for the console, all I/O devices are simulated as files on the host file system in little-endian format. SCP provides facilities for associating - files with units (ATTACH command) and for reading and writing data from and to devices in a endian- and size-independent way. -\par -\par For most devices, the VM designer does not have to be concerned about the formatting of simulated device files. I/O occurs in 1, 2, or 4 byte quantities; SCP automatically chooses the correct data size and corrects for byte ordering. Specific issues: - -\par -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls8\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls8\adjustright {\f1 -Line printers should write data as 7-bit ASCII, with newlines replacing carriage-return/line-feed sequences. -\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls8\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls8\adjustright {\f1 Disks should be - viewed as linear data sets, from sector 0 of surface 0 of cylinder 0 to the last sector on the disk. This allows easy transcription of real disks to files usable by the simulator. -\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls8\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls8\adjustright {\f1 -Magtapes, by convention, use a record based format. Each record consi -sts of a leading 32-bit record length, the record data (padded with a byte of 0 if the record length is odd), and a trailing 32-bit record length. File marks are recorded as one record length of 0. -\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls8\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls8\adjustright {\f1 -Cards have 12 bits of data per column, but the data is most conveniently viewed as (ASCII) characters. Existing card reader simulators do not support binary operation. -\par }\pard \widctlpar\adjustright {\f1 -\par Data I/O varies between fixed and variable capacity devices, and between buffered and non-buffered devices. A fixed capacity device differ -s from a variable capacity device in that the file attached to the former has a maximum size, while the file attached to the latter may expand indefinitely. A buffered device differs from a non-buffered device in that the former buffers its data set in h -ost memory, while the latter maintains it as a file. Most variable capacity devices (such as the paper tape reader and punch) are sequential; all buffered devices are fixed capacity. -\par -\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.2.3.1\tab}}\pard \fi-1080\li1080\widctlpar\jclisttab\tx1080\ls1\ilvl3\adjustright {\f1 Reading and Writing Data -\par }\pard \widctlpar\adjustright {\f1 -\par The ATTACH command creates an association between a host file and an I/O unit. For non-buffered devices, ATTACH stores the file pointer for the host file in the }{\b\f1 fileref}{\f1 - field of the UNIT structure. For buffered devices, ATTACH reads the entire host file into an allocated buffer pointed to by the }{\b\f1 filebuf }{\f1 field of the UNIT structure. -\par -\par For non-buffered devices, I/O is done with standard C subroutines plus the SCP routines }{\b\f1 fxread}{\f1 and }{\b\f1 fxwrite}{\f1 . }{\b\f1 fxread}{\f1 and }{\b\f1 fxwrite}{\f1 - are identical in calling sequence and function to fread and fwrite, respectively, but - will correct for endian dependencies. For buffered devices, I/O is done by copying data to or from the allocated buffer. The device code must maintain the number (+1) of the highest address modified in the }{\b\f1 hwmark}{\f1 - field of the UNIT structure. For both the non-buffered and buffered cases, the device must perform all address calculations and positioning operations. -\par -\par The DETACH command breaks the association between a host file and an I/O unit. For buffered devices, DETACH writes the allocated buffer back to the host file. -\par -\par {\listtext\pard\plain\f1\fs20\cgrid \hich\af1\dbch\af0\loch\f1 3.2.3.2\tab}}\pard \fi-1080\li1080\widctlpar\jclisttab\tx1080\ls1\ilvl3\adjustright {\f1 Console I/O -\par }\pard \widctlpar\adjustright {\f1 -\par }\pard \widctlpar\outlinelevel0\adjustright {\f1 SCP provides two routines for console I/O. -\par }\pard \widctlpar\adjustright {\f1 -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls10\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls10\adjustright {\f1 t_stat }{\b\f1 sim_poll_char }{ -\f1 (void). This routine polls for keyboard input. If there is a character, it returns SCPE_KFLAG + the character. If the user typed the interrupt character (^E), it returns SCPE_STOP. If there is no input, it returns SCPE_OK. -\par }\pard \widctlpar{\*\pn \pnlvlcont\ilvl0\ls0\pnrnot0\pndec }\adjustright {\f1 -\par {\pntext\pard\plain\f3\fs20\cgrid \loch\af3\dbch\af0\hich\f3 \'b7\tab}}\pard \fi-360\li720\widctlpar\jclisttab\tx720{\*\pn \pnlvlblt\ilvl0\ls10\pnrnot0\pnf3\pnstart1\pnindent720\pnhang{\pntxtb \'b7}}\ls10\adjustright {\f1 t_stat }{\b\f1 sim_putchar}{\f1 - (int32 char). This routine types the specified ASCII character on the console. There are no errors. -\par }\pard \widctlpar\adjustright {\f1 -\par {\*\bkmkstart _Toc526228050}{\listtext\pard\plain\s1 \b\f1\fs28\kerning28\cgrid \hich\af1\dbch\af0\loch\f1 4.\tab}}\pard\plain \s1\fi-360\li360\sb240\sa60\keepn\widctlpar\jclisttab\tx360\ls1\outlinelevel0\adjustright \b\f1\fs28\kerning28\cgrid { -Data Structures{\*\bkmkend _Toc526228050} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par The devices, units, and registers which make up a VM are formally described through a set of data structures which interface the VM to the control portions of SCP. The devices themselves are pointed to by the device list array }{\b\f1 sim_devices[]}{\f1 -. Within a device, both units and registers are allocated contiguously as arrays of structures. In addition, many devices allow the user to set or clear options via a modifications table. -\par {\*\bkmkstart _Toc526228051}{\listtext\pard\plain\s2 \b\i\f1\cgrid \hich\af1\dbch\af0\loch\f1 4.1\tab}}\pard\plain \s2\fi-390\li390\sb240\sa60\keepn\widctlpar\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid {device Structure -{\*\bkmkend _Toc526228051} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par Devices are defined by the }{\b\f1 device}{\f1 structure (typedef }{\b\f1 DEVICE}{\f1 ): -\par -\par }\pard \li720\widctlpar\adjustright {\f1 struct device \{ -\par \tab char\tab \tab *name;\tab \tab \tab \tab /* name */ -\par \tab struct unit \tab *units;\tab \tab \tab \tab /* units */ -\par \tab struct reg\tab *registers;\tab \tab \tab /* registers */ -\par \tab struct mtab\tab *modifiers;\tab \tab \tab /* modifiers */ -\par \tab int\tab \tab numunits;\tab \tab \tab /* #units */ -\par \tab int\tab \tab aradix;\tab \tab \tab \tab /* address radix */ -\par \tab int\tab \tab awidth;\tab \tab \tab \tab /* address width */ -\par \tab int\tab \tab aincr;\tab \tab \tab \tab /* addr increment */ -\par \tab int\tab \tab dradix;\tab \tab \tab \tab /* data radix */ -\par \tab int\tab \tab dwidth;\tab \tab \tab \tab /* data width */ -\par \tab t_stat\tab \tab (*examine)();\tab \tab \tab /* examine routine */ -\par \tab t_stat\tab \tab (*deposit)();\tab \tab \tab /* deposit routine */ -\par \tab t_stat\tab \tab (*reset)();\tab \tab \tab /* reset routine */ -\par \tab t_stat\tab \tab (*boot)();\tab \tab \tab /* boot routine */ -\par \tab t_stat\tab \tab (*attach)();\tab \tab \tab /* attach routine */ -\par \tab t_stat\tab \tab (*detach)();\tab \tab \tab /* detach routine */ -\par \}; -\par }\pard \widctlpar\adjustright {\f1 -\par The fields are the following: -\par -\par }\pard \li720\widctlpar\adjustright {\b\f1 name}{\f1 \tab \tab device name, string of all capital alphanumeric characters. -\par }{\b\f1 units}{\f1 \tab \tab pointer to array of }{\b\f1 unit}{\f1 structures, or NULL if none. -\par }{\b\f1 registers}{\f1 \tab pointer to array of }{\b\f1 reg}{\f1 structures, or NULL if none. -\par }{\b\f1 modifiers}{\f1 \tab pointer to array of }{\b\f1 mtab}{\f1 structures, or NULL if none. -\par }{\b\f1 numunits}{\f1 \tab number of units in this device. -\par }{\b\f1 aradix}{\f1 \tab \tab radix for input and display of device addresses, 2 to 16 inclusive. -\par }{\b\f1 awidth}{\f1 \tab \tab width in bits of a device address, 1 to 31 inclusive. -\par }\pard \fi-1440\li2160\widctlpar\adjustright {\b\f1 aincr}{\f1 \tab increment between device addresses, normally 1; however, byte addressed devices with 16-bit words specify 2, with 32-bit words 4. -\par }\pard \li720\widctlpar\adjustright {\b\f1 dradix}{\f1 \tab \tab radix for input and display of device data, 2 to 16 inclusive. -\par }{\b\f1 dwidth}{\f1 \tab \tab width in bits of device data, 1 to 32 inclusive. -\par }{\b\f1 examine}{\f1 \tab address of special device data read routine, or NULL if none is required. -\par }{\b\f1 deposit}{\f1 \tab \tab address of special device data write routine, or NULL if none is required. -\par }{\b\f1 reset}{\f1 \tab \tab address of device reset routine, or NULL if none is required. -\par }{\b\f1 boot}{\f1 \tab \tab address of device bootstrap routine, or NULL if none is required. -\par }{\b\f1 attach}{\f1 \tab \tab address of special device attach routine, or NULL if none is required. -\par }{\b\f1 detach}{\f1 \tab \tab address of special device detach routine, or NULL if none is required. -\par {\*\bkmkstart _Toc526228052}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 4.1.1\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Examine and Deposit Routines -{\*\bkmkend _Toc526228052} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par For devices which maintain their data sets as host files, SCP implements the examine and deposit data functions. However, devices which maintain their data sets as private state (typically just the C -PU) must supply special examine and deposit routines. The calling sequences are: -\par -\par }\pard \li720\widctlpar\adjustright {\f1 t_stat }{\i\f1 examine_routine}{\f1 (t_val *eval_array, t_addr addr, UNIT *uptr, int32 switches) \endash Copy }{\b\f1 sim_emax}{\f1 consecutive addresses for unit }{\i\f1 uptr}{\f1 , starting at }{\i\f1 addr}{ -\f1 , into }{\i\f1 eval_array}{\f1 . The }{\i\f1 switch}{\f1 variable has bit set if the n\rquote th letter was specified as a switch to the examine command. -\par -\par t_stat }{\i\f1 deposit_routine}{\f1 (t_val value, t_addr addr, UNIT *uptr, int32 switches) \endash Store the specified }{\i\f1 value}{\f1 in the specified }{\i\f1 addr}{\f1 for unit }{\i\f1 uptr}{\f1 . The }{\i\f1 switch}{\f1 - variable is the same as for the examine routine. -\par {\*\bkmkstart _Toc526228053}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 4.1.2\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Reset Routine -{\*\bkmkend _Toc526228053} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par The reset routine implements the device reset function for the RESET, RUN, and BOOT commands. Its calling sequence is: -\par -\par \tab t_stat }{\i\f1 reset_routine}{\f1 (DEVICE *dptr) \endash Reset the specified device to its initial state. -\par -\par }\pard \widctlpar\outlinelevel0\adjustright {\f1 A typical reset routine clears all device flags and cancels any outstanding timing operations. -\par {\*\bkmkstart _Toc526228054}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 4.1.3\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Boot Routine -{\*\bkmkend _Toc526228054} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par If a device responds to a BOOT command, the boot routine implements the bootstrapping function. Its calling sequence is: -\par -\par \tab t_stat }{\i\f1 boot_routine}{\f1 (int32 unit_number) \endash Bootstrap the specified unit. -\par -\par A typical bootstrap routine copies a bootstrap loader into main memory and sets the PC to the starting address of the loader. SCP then starts simulation at the specified address. -\par {\*\bkmkstart _Toc526228055}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 4.1.4\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Attach and Detach Routines -{\*\bkmkend _Toc526228055} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par Normally, the ATTACH and DETACH commands are handled by SCP. However, devices which need to pre- or post-process these commands must supply special attach and detach routines. The calling sequences are: -\par -\par }\pard \li720\widctlpar\adjustright {\f1 t_stat }{\i\f1 attach_routine }{\f1 (UNIT *uptr, char *file) \endash Attach the specified }{\i\f1 file}{\f1 to the unit }{\i\f1 uptr}{\f1 . -\par -\par t_stat }{\i\f1 detach_routine}{\f1 (UNIT *uptr) \endash Detach unit }{\i\f1 uptr}{\f1 . -\par }\pard \widctlpar\adjustright {\f1 -\par In practice, these routines always invoke the standard SCP routines, }{\b\f1 attach_unit}{\f1 and }{\b\f1 detach_unit}{\f1 , respectively. For example, here are special attach and detach routines to update line printer error state: -\par -\par }\pard \li720\widctlpar\adjustright {\f1 t_stat lpt_attach (UNIT *uptr, char *cptr) \{ -\par }\pard \fi720\li720\widctlpar\adjustright {\f1 t_stat r; -\par if ((r = attach_unit (uptr, cptr)) != SCPE_OK) return r; -\par lpt_error = 0; -\par return SCPE_OK; -\par }\pard \li720\widctlpar\adjustright {\f1 \} -\par -\par t_stat lpt_detach (UNIT *uptr) \{ -\par \tab lpt_error = 1; -\par \tab return detach_unit (uptr); -\par \} -\par }\pard \widctlpar\adjustright {\f1 -\par SCP executes a DETACH ALL command as part of simulator exit. Normally, DETACH ALL only calls a unit\rquote s detach routine if the unit\rquote -s UNIT_ATTABLE flag is set. During simulator exit, the detach routine is called unconditionally. This allows the detach routine of a non-attachable unit to function as a simulator-specific cleanup routine for the unit, device, or entire simulator. - -\par {\*\bkmkstart _Toc526228056}{\listtext\pard\plain\s2 \b\i\f1\cgrid \hich\af1\dbch\af0\loch\f1 4.2\tab}}\pard\plain \s2\fi-390\li390\sb240\sa60\keepn\widctlpar\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid {unit Structure -{\*\bkmkend _Toc526228056} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\b\f1 -\par }{\f1 Units are allocated as contiguous array. Each unit is defined with a }{\b\f1 unit}{\f1 structure (typedef }{\b\f1 UNIT}{\f1 ): -\par -\par }\pard \li720\widctlpar\adjustright {\f1 struct unit \{ -\par \tab struct unit\tab *next;\tab \tab \tab \tab /* next active */ -\par \tab t_stat\tab \tab (*action)();\tab \tab \tab /* action routine */ -\par \tab char\tab \tab *filename;\tab \tab \tab /* open file name */ -\par \tab FILE\tab \tab *fileref;\tab \tab \tab \tab /* file reference */ -\par \tab void\tab \tab *filebuf;\tab \tab \tab \tab /* memory buffer */ -\par \tab t_addr\tab \tab hwmark;\tab \tab \tab /* high water mark */ -\par \tab int32\tab \tab time;\tab \tab \tab \tab /* time out */ -\par \tab int32\tab \tab flags;\tab \tab \tab \tab /* flags */ -\par \tab t_addr\tab \tab capac;\tab \tab \tab \tab /* capacity */ -\par \tab t_addr\tab \tab pos;\tab \tab \tab \tab /* file position */ -\par \tab int32\tab \tab buf;\tab \tab \tab \tab /* buffer */ -\par \tab int32\tab \tab wait;\tab \tab \tab \tab /* wait */ -\par \tab int32\tab \tab u3;\tab \tab \tab \tab /* device specific */ -\par \tab int32\tab \tab u4;\tab \tab \tab \tab /* device specific */ -\par \}; -\par }\pard \widctlpar\adjustright {\f1 -\par The fields are the following: -\par -\par }\pard \li720\widctlpar\adjustright {\b\f1 next}{\f1 \tab \tab pointer to next unit in active queue, NULL if none. -\par }{\b\f1 action}{\f1 \tab \tab address of unit time-out service routine. -\par }{\b\f1 filename}{\f1 \tab pointer to name of attached file, NULL if none. -\par }{\b\f1 fileref}{\f1 \tab \tab pointer to FILE structure of attached file, NULL if none. -\par }{\b\f1 hwmark}{\f1 \tab buffered devices only; highest modified address, + 1. -\par }{\b\f1 time}{\f1 \tab \tab increment until time-out beyond previous unit in active queue. -\par }{\b\f1 flags}{\f1 \tab \tab unit flags. -\par }{\b\f1 capac}{\f1 \tab \tab unit capacity, 0 if variable. -\par }{\b\f1 pos}{\f1 \tab \tab sequential devices only; next device address to be read or written. -\par }{\b\f1 buf}{\f1 \tab \tab by convention, the unit buffer, but can be used for other purposes. -\par }{\b\f1 wait}{\f1 \tab \tab by convention, the unit wait time, but can be used for other purposes. -\par }{\b\f1 u3}{\f1 \tab \tab user-defined. -\par }{\b\f1 u4}{\f1 \tab \tab user-defined. -\par }\pard \widctlpar\adjustright {\b\f1 -\par buf, wait, u3, u4}{\f1 are all saved and restored by the SAVE and RESTORE commands and thus can be used for unit state which must be preserved. -\par -\par }\pard \widctlpar\outlinelevel0\adjustright {\f1 Macro }{\b\f1 UDATA}{\f1 is available to fill in the common fields of a UNIT. It is invoked by -\par }\pard \widctlpar\adjustright {\f1 -\par \tab UDATA\tab \tab (action_routine, flags, capacity) -\par -\par }\pard \widctlpar\outlinelevel0\adjustright {\f1 Fields after }{\b\f1 buf}{\f1 can be filled in manually, e.g, -\par }\pard \widctlpar\adjustright {\f1 -\par }\pard \widctlpar\outlinelevel0\adjustright {\f1 \tab UNIT lpt_unit = \{ UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE, 0), 500 \}; -\par }\pard \widctlpar\adjustright {\f1 -\par defines the line printer as a sequential unit with a wait time of 500. -\par {\*\bkmkstart _Toc526228057}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 4.2.1\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Unit Flags{\*\bkmkend _Toc526228057 -} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par The }{\b\f1 flags }{\f1 field contains indicators of current unit status. SIMH defines 11 flags: -\par -\par }\pard \li720\widctlpar\adjustright {\f1 flag name\tab \tab meaning if set -\par -\par UNIT_DISABLE\tab \tab the unit responds to ENABLE and DISABLE. -\par UNIT_DIS\tab \tab the unit is currently disabled. -\par UNIT_ATTABLE\tab the unit responds to ATTACH and DETACH. -\par UNIT_ATT\tab \tab the unit is currently attached to a file. -\par UNIT_BUFABLE\tab the unit can buffer its data set in memory. -\par UNIT_MUSTBUF\tab the unit must buffer its data set in memory. -\par UNIT_BUF\tab \tab the unit is currently buffering its data set in memory. -\par UNIT_RO\tab \tab the unit is read only. -\par UNIT_SEQ\tab \tab the unit is sequential. -\par UNIX_FIX\tab \tab the unit is fixed capacity. -\par UNIT_BINK\tab \tab the unit measures \ldblquote K\rdblquote as 1024, rather than 1000. -\par }\pard \widctlpar\adjustright {\f1 -\par Starting at bit position UNIT_V_UF, the remaining flags are device-specific. Device-specific flags are set and cleared with the SET and CLEAR commands, which reference the MTAB array (see be -low). Device-specific flags and UNIT_DIS are not automatically saved and restored; the device must supply a register covering these bits. -\par {\*\bkmkstart _Toc526228058}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 4.2.2\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Service Routine -{\*\bkmkend _Toc526228058} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par This routine is called by }{\b\f1 sim_process_event}{\f1 when a unit times out. Its calling sequence is: -\par -\par }\pard \fi720\widctlpar\adjustright {\f1 t_stat }{\i\f1 service_routine}{\f1 (UNIT *uptr) -\par }\pard \widctlpar\adjustright {\f1 -\par }\pard \widctlpar\outlinelevel0\adjustright {\f1 The status returned by the service routine is passed by }{\b\f1 sim_process_event}{\f1 back to the CPU. -\par {\*\bkmkstart _Toc526228059}{\listtext\pard\plain\s2 \b\i\f1\cgrid \hich\af1\dbch\af0\loch\f1 4.3\tab}}\pard\plain \s2\fi-390\li390\sb240\sa60\keepn\widctlpar\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid {reg Structure -{\*\bkmkend _Toc526228059} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\b\f1 -\par }{\f1 Registers are allocated as contiguous array, with a NULL register at the end. Each register is defined with a }{\b\f1 reg}{\f1 structure (typedef }{\b\f1 REG}{\f1 ): -\par -\par }\pard \li720\widctlpar\adjustright {\f1 struct reg \{ -\par \tab char\tab \tab *name;\tab \tab \tab \tab /* name */ -\par \tab void\tab \tab *loc;\tab \tab \tab \tab /* location */ -\par \tab int\tab \tab radix;\tab \tab \tab \tab /* radix */ -\par \tab int\tab \tab width;\tab \tab \tab \tab /* width */ -\par \tab int\tab \tab offset;\tab \tab \tab \tab /* starting bit */ -\par \tab int\tab \tab depth;\tab \tab \tab \tab /* save depth */ -\par \tab int32\tab \tab flags;\tab \tab \tab \tab /* flags */ -\par \}; -\par }\pard \widctlpar\adjustright {\f1 -\par The fields are the following: -\par -\par }\pard \li720\widctlpar\adjustright {\b\f1 name}{\f1 \tab \tab device name, string of all capital alphanumeric characters. -\par }{\b\f1 loc}{\f1 \tab \tab pointer to location of the register value. -\par }{\b\f1 radix}{\f1 \tab \tab radix for input and display of data, 2 to 16 inclusive. -\par }{\b\f1 width}{\f1 \tab \tab width in bits of data, 1 to 32 inclusive. -\par }{\b\f1 width\tab }{\f1 \tab bit offset (from right end of data). -\par }{\b\f1 depth\tab }{\f1 \tab size of data array (normally 1). -\par }{\b\f1 flags}{\f1 \tab \tab flags and formatting information. -\par }\pard \widctlpar\adjustright {\f1 -\par The }{\b\f1 depth}{\f1 field is only used with special \ldblquote arrayed registers\rdblquote -, like the data buffer in the PDP floppy disk controller. Arrayed registers cannot be examined or deposited, but all the values in the array will be saved and restored by SAVE and RESTORE. -\par -\par Macros }{\b\f1 ORDATA}{\f1 , }{\b\f1 DRDATA}{\f1 , and }{\b\f1 HRDATA}{\f1 define right-justified octal, decimal, and hexidecimal registers, respectively. They are invoked by: -\par -\par \tab xRDATA\tab (name, location, width) -\par -\par Macro }{\b\f1 FLDATA}{\f1 defines a one-bit binary flag at an arbitrary offset in a 32-bit word. It is invoked by: -\par -\par \tab FLDATA\tab (name, location, bit_position) -\par -\par Macro }{\b\f1 GRDATA}{\f1 defines a register with arbitrary location and radix. It is invoked by: -\par -\par \tab GRDATA\tab (name, location, radix, width, bit_position) -\par -\par Finally }{\b\f1 BRDATA}{\f1 defines an arrayed register. It is invoked by: -\par -\par \tab BRDATA\tab (name, location, radix, width, depth) -\par -\par }\pard \widctlpar\outlinelevel0\adjustright {\f1 The }{\b\f1 flag}{\f1 field can be filled in manually, e.g., -\par }\pard \widctlpar\adjustright {\f1 -\par }\pard \widctlpar\outlinelevel0\adjustright {\f1 \tab REG lpt_reg = \{ -\par }\pard \widctlpar\adjustright {\f1 \tab \tab \{ DRDATA\tab (POS, lpt_unit.pos, 31), PV_LFT \}, \'85 \} -\par {\*\bkmkstart _Toc526228060}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 4.3.1\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Register Flags -{\*\bkmkend _Toc526228060} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par }\pard \widctlpar\outlinelevel0\adjustright {\f1 The }{\b\f1 flags }{\f1 field contains indicators that control register examination and deposit. -\par }\pard \widctlpar\adjustright {\f1 -\par }\pard \li720\widctlpar\adjustright {\f1 flag name\tab \tab meaning if specified -\par -\par PV_RZRO\tab \tab print register right justified with leading zeroes. -\par PV_RSPC\tab \tab print register right justified with leading spaces. -\par PV_LEFT\tab \tab print register left justified. -\par REG_RO\tab \tab register is read only. -\par REG_HIDDEN\tab \tab register is hidden (will not appear in EXAMINE STATE). -\par REG_HRO\tab \tab register is read only and hidden. -\par REG_NZ\tab \tab new register values must be non-zero. -\par {\*\bkmkstart _Toc526228061}{\listtext\pard\plain\s2 \b\i\f1\cgrid \hich\af1\dbch\af0\loch\f1 4.4\tab}}\pard\plain \s2\fi-390\li390\sb240\sa60\keepn\widctlpar\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid {mtab Structure -{\*\bkmkend _Toc526228061} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\b\f1 -\par }{\f1 Device-specific SHOW and SET commands are processed using the modifications array, which is allocated as contiguous array, with a NULL at the end. Each possible modification is defined with a }{\b\f1 mtab}{\f1 structure (synonym }{\b\f1 MTAB}{\f1 -), which has the following fields: -\par -\par }\pard \li720\widctlpar\adjustright {\f1 struct mtab \{ -\par \tab int32\tab \tab mask;\tab \tab \tab \tab /* mask */ -\par \tab int32\tab \tab match;\tab \tab \tab \tab /* match */ -\par \tab char\tab \tab *pstring;\tab \tab \tab /* print string */ -\par \tab char\tab \tab *mstring;\tab \tab \tab /* match string */ -\par \tab t_stat\tab \tab (*valid)();\tab \tab \tab /* validation routine */ -\par \}; -\par }\pard \widctlpar\adjustright {\f1 -\par The fields are the following: -\par -\par }\pard \li720\widctlpar\adjustright {\b\f1 mask}{\f1 \tab \tab bit mask for testing the unit.}{\b\f1 flags}{\f1 field -\par }\pard \fi-1440\li2160\widctlpar\adjustright {\b\f1 match}{\f1 \tab (SHOW) if the masked bits equal this value, }{\b\f1 pstring}{\f1 is printed -\par }{\b\f1 \tab }{\f1 (SET) if }{\b\f1 mstring}{\f1 is matched, the masked bits are set to this value -\par }{\b\f1 pstring}{\f1 \tab pointer to character string printed on a match (SHOW), or NULL -\par }{\b\f1 mstring}{\f1 \tab pointer to character string to be matched (SET), or NULL -\par }{\b\f1 valid}{\f1 \tab address of validation/display routine, or NULL if none required -\par {\*\bkmkstart _Toc526228062}{\listtext\pard\plain\s3 \f1\cgrid \hich\af1\dbch\af0\loch\f1 4.4.1\tab}}\pard\plain \s3\fi-720\li720\sb240\sa60\keepn\widctlpar\jclisttab\tx720\ls1\ilvl2\outlinelevel2\adjustright \f1\cgrid {Validation/Display Routine -{\*\bkmkend _Toc526228062} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par The validation/display routine can be used to validate input during SET processing, or to display device-specific output during SHOW processing, but not both. If }{\b\f1 mstring}{\f1 is not NULL, then the routine is a validation routine. If }{\b\f1 -mstring}{\f1 is NULL, and }{\b\f1 pstring}{\f1 is not NULL, then the routine is a display routine. -\par -\par The validation routine is called during SET processing to make sure that the proposed modification is valid. It can make other state changes required by the modification or initiate additional dialogs needed by the modifier. Its calling sequence is: - -\par -\par }\pard \li720\widctlpar\adjustright {\f1 t_stat }{\i\f1 validation_routine}{\f1 (UNIT *uptr, int32 value) \endash test that }{\i\f1 uptr}{\f1 .}{\b\f1 flags}{\f1 can be set to }{\i\f1 value}{\f1 . -\par }\pard \widctlpar\adjustright {\f1 -\par The display routine is called during SHOW processing to display device- or unit-specific state. Its calling sequence is: -\par -\par }\pard \li720\widctlpar\adjustright {\f1 t_stat }{\i\f1 display_routine}{\f1 (UNIT *uptr, FILE *st) \endash output device- or unit-specific state for }{\i\f1 uptr}{\f1 to stream }{\i\f1 st}{\f1 . -\par }\pard \widctlpar\adjustright {\f1 -\par When the display routine is called, SHOW has output the }{\b\f1 pstring}{\f1 argument but has not appended a newline. SHOW will append a final newline after the display routine returns. -\par {\*\bkmkstart _Toc526228063}{\listtext\pard\plain\s2 \b\i\f1\cgrid \hich\af1\dbch\af0\loch\f1 4.5\tab}}\pard\plain \s2\fi-390\li390\sb240\sa60\keepn\widctlpar\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid {Other Data Structures -{\*\bkmkend _Toc526228063} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par char }{\b\f1 sim_name[]}{\f1 is a character array containing the VM name. -\par -\par int32 }{\b\f1 sim_emax}{\f1 contains the maximum number of words needed to hold the largest instruction or data item in the VM. Examine and deposit will process up to }{\b\f1 sim_emax}{\f1 words. -\par -\par DEVICE *}{\b\f1 sim_devices[]}{\f1 is an array of pointers to all the devices in the VM. It is terminated by a NULL. By convention, the CPU is always the first device in the array. -\par -\par UNIT }{\b\f1 *sim_consoles[]}{\f1 is an array of pointers to the units of simulate -d consoles, alternating input and output. (If a console has only an input unit, the output slot should also point to the input unit.) This structure is only used for multi-console support. If the VM has only one console, the pointer should be NULL. - -\par -\par REG *}{\b\f1 sim_PC}{\f1 points to the }{\b\f1 reg}{\f1 structure for the program counter. By convention, the PC is always the first register in the CPU\rquote s register array. -\par -\par char *}{\b\f1 sim_stop_messages[]}{\f1 is an array of pointers to character strings, corresponding to error status returns greater than zero. If }{\b\f1 sim_instr}{\f1 returns status code n > 0, then }{\b\f1 sim_stop_message[n]}{\f1 is printed by SCP. - -\par -\par {\*\bkmkstart _Toc526228064}{\listtext\pard\plain\s1 \b\f1\fs28\kerning28\cgrid \hich\af1\dbch\af0\loch\f1 5.\tab}}\pard\plain \s1\fi-360\li360\sb240\sa60\keepn\widctlpar\jclisttab\tx360\ls1\outlinelevel0\adjustright \b\f1\fs28\kerning28\cgrid { -VM Provided Routines{\*\bkmkend _Toc526228064} -\par {\*\bkmkstart _Toc526228065}{\listtext\pard\plain\s2 \b\i\f1\cgrid \hich\af1\dbch\af0\loch\f1 5.1\tab}}\pard\plain \s2\fi-390\li390\sb240\sa60\keepn\widctlpar\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid {Instruction Execution -{\*\bkmkend _Toc526228065} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par Instruction execution is performed by routine }{\b\f1 sim_instr}{\f1 . Its calling sequence is: -\par -\par t_stat }{\b\f1 sim_instr}{\f1 (void) \endash Execute from current PC until error or halt. -\par {\*\bkmkstart _Toc526228066}{\listtext\pard\plain\s2 \b\i\f1\cgrid \hich\af1\dbch\af0\loch\f1 5.2\tab}}\pard\plain \s2\fi-390\li390\sb240\sa60\keepn\widctlpar\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid {Binary Load and Dump -{\*\bkmkend _Toc526228066} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par If the VM responds to the LOAD (or DUMP) command, the loader (dumper) is implemented by routine }{\b\f1 sim_load}{\f1 . Its calling sequence is: -\par -\par }\pard \li720\widctlpar\adjustright {\f1 t_stat }{\b\f1 sim_load}{\f1 (FILE *fptr, char *buf, char *fnam, t_bool flag) - If }{\i\f1 flag}{\f1 = 0, load data from binary file }{\i\f1 fptr}{\f1 . If }{\i\f1 flag}{\f1 = 1, dump data to binary file }{ -\i\f1 fptr}{\f1 . For either command, }{\i\f1 buf}{\f1 contains any VM-specific arguments, and }{\i\f1 fnam}{\f1 contains the file name. -\par }\pard \widctlpar\adjustright {\f1 -\par If LOAD or DUMP is not implemented, }{\b\f1 sim_load}{\f1 should simply return SCPE_ARG. The LOAD and DUMP commands open and close the specified file for }{\b\f1 sim_load}{\f1 . -\par {\*\bkmkstart _Toc526228067}{\listtext\pard\plain\s2 \b\i\f1\cgrid \hich\af1\dbch\af0\loch\f1 5.3\tab}}\pard\plain \s2\fi-390\li390\sb240\sa60\keepn\widctlpar\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid { -Symbolic Examination and Deposit{\*\bkmkend _Toc526228067} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par If the VM provides symbolic examination and deposit of data, it must provide two routines, }{\b\f1 fprint_sym}{\f1 for output and }{\b\f1 parse_sym}{\f1 for input. Their calling sequences are: -\par -\par }\pard \li720\widctlpar\adjustright {\f1 t_stat }{\b\f1 fprint_sym}{\f1 (FILE *ofile, t_addr addr, t_value *val, UNIT *uptr, int32 switch) \endash Based on the }{\i\f1 switch}{\f1 variable, symbolically output to stream }{\i\f1 ofile}{\f1 - the data in array }{\i\f1 val}{\f1 at the specified }{\i\f1 addr}{\f1 in unit }{\i\f1 uptr}{\f1 . -\par -\par t_stat }{\b\f1 parse_sym}{\f1 (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 switch) \endash Based on the }{\i\f1 switch}{\f1 variable, parse character string }{\i\f1 cptr}{\f1 for a symbolic value }{\i\f1 val}{\f1 at the specified }{ -\i\f1 addr}{\f1 in unit }{\i\f1 uptr}{\f1 . -\par }\pard \widctlpar\adjustright {\f1 -\par If symbolic processing is not implemented, or the output value or input string cannot be parsed, these routines should return SCPE_ARG. If the processing -was successful and consumed more than a single word, then these routines should return extra number of words (not bytes) consumed as a }{\b\f1 negative}{\f1 - number. If the processing was successful and consumed a single word, then these routines should return SCPE_OK. For example, PDP-11 }{\b\f1 parse_sym}{\f1 would respond as follows to various inputs: -\par -\par \tab input\tab \tab \tab \tab return value -\par -\par \tab XYZGH\tab \tab \tab \tab SCPE_ARG -\par \tab MOV R0,R1\tab \tab \tab SCPE_OK -\par \tab MOV #4,R5\tab \tab \tab -1 -\par \tab MOV 1234,5670\tab \tab -2 -\par -\par The interpretation of switch values is arbitrary, but the following are used by existing VM\rquote s: -\par -\par \tab switch\tab \tab \tab \tab interpretation -\par -\par \tab -a\tab \tab \tab \tab single character -\par \tab -c\tab \tab \tab \tab character string -\par \tab -m\tab \tab \tab \tab instruction mnemonic -\par -\par In addition, on input, a leading \lquote (apostrophe) is interpreted to mean a single character, and a leading \ldblquote (double quote) is interpreted to mean a character string. -\par {\*\bkmkstart _Toc526228068}{\listtext\pard\plain\s2 \b\i\f1\cgrid \hich\af1\dbch\af0\loch\f1 5.4\tab}}\pard\plain \s2\fi-390\li390\sb240\sa60\keepn\widctlpar\jclisttab\tx390\ls1\ilvl1\outlinelevel1\adjustright \b\i\f1\cgrid { -Multi-Terminal Support (Telnet){\*\bkmkend _Toc526228068} -\par }\pard\plain \widctlpar\adjustright \fs20\cgrid {\f1 -\par SIMH supports the use of multiple terminals. All terminals except the console are accessed via Telnet. SIMH provides two supporting -libraries for implementing multiple terminals: sim_tmxr.c (and its header file, sim_tmxr.h), which provide OS-independent support routines for terminal multiplexors; and sim_sock.c (and its header file, sim_sock.h), which provide OS-dependent socket routi -nes. Sim_sock.c is presently implemented only under Windows and UNIX. -\par -\par Two basic data structures define the multiple terminals. Individual lines are defined by the }{\b\f1 tmln}{\f1 structure (typedef }{\b\f1 TMLN}{\f1 ): -\par -\par }\pard \li720\widctlpar\adjustright {\f1 struct tmln \{ -\par \tab SOCKET\tab conn;\tab \tab \tab \tab /* line conn */ -\par \tab uint32\tab \tab ipad;\tab \tab \tab \tab /* IP address */ -\par \tab uint32\tab \tab cnms;\tab \tab \tab \tab /* connect time ms */ -\par \tab int32\tab \tab tsta;\tab \tab \tab \tab /* Telnet state */ -\par \tab int32\tab \tab rcve;\tab \tab \tab \tab /* rcv enable */ -\par \tab int32\tab \tab xmte;\tab \tab \tab \tab /* xmt enable */ -\par \tab int32\tab \tab dstb;\tab \tab \tab \tab /* disable Tlnt bin */ -\par \tab int32\tab \tab rxbpr;\tab \tab \tab \tab /* rcv buf remove */ -\par \tab int32\tab \tab rxbpi;\tab \tab \tab \tab /* rcv buf insert */ -\par \tab int32\tab \tab rxcnt;\tab \tab \tab \tab /* rcv count */ -\par \tab int32\tab \tab txbpr;\tab \tab \tab \tab /* xmt buf remove */ -\par \tab int32\tab \tab txbpi;\tab \tab \tab \tab /* xmt buf insert */ -\par \tab int32\tab \tab txcnt;\tab \tab \tab \tab /* xmt count */ -\par \tab uint8\tab \tab rxb[TMXR_MAXBUF];\tab \tab /* rcv buffer */ -\par \tab uint8\tab \tab txb[TMXR_MAXBUF];\tab \tab /* xmt buffer */ -\par \tab \}; -\par }\pard \widctlpar\adjustright {\f1 -\par The fields are the following: -\par -\par \tab }{\b\f1 conn}{\f1 \tab \tab connection socket (0 = disconnected) -\par \tab }{\b\f1 tsta}{\f1 \tab \tab Telnet state -\par \tab }{\b\f1 rcve}{\f1 \tab \tab receive enable flag (0 = disabled) -\par \tab }{\b\f1 xmte}{\f1 \tab \tab transmit flow control flag (0 = transmit disabled) -\par \tab }{\b\f1 dstb}{\f1 \tab \tab Telnet bin mode disabled -\par \tab }{\b\f1 rxbp}{\f1 r\tab \tab receive buffer remove pointer -\par \tab }{\b\f1 rxbpi}{\f1 \tab \tab receive buffer insert pointer -\par \tab }{\b\f1 rxcnt}{\f1 \tab \tab receive count -\par \tab }{\b\f1 txbpr}{\f1 \tab \tab transmit buffer remove pointer -\par \tab }{\b\f1 txbpi}{\f1 \tab \tab transmit buffer insert pointer -\par \tab }{\b\f1 txcnt}{\f1 \tab \tab transmit count -\par }\pard \fi720\widctlpar\adjustright {\b\f1 rxb}{\f1 \tab \tab receive buffer -\par }\pard \widctlpar\adjustright {\f1 \tab }{\b\f1 txb}{\f1 \tab \tab transmit buffer -\par -\par The overall set of extra terminals is defined by the }{\b\f1 tmxr}{\f1 structure (typedef }{\b\f1 TMXR}{\f1 ): -\par -\par }\pard \li720\widctlpar\adjustright {\f1 struct tmxr \{ -\par \tab int32\tab \tab lines;\tab \tab \tab \tab /* # lines */ -\par \tab SOCKET\tab master;\tab \tab \tab \tab /* master socket */ -\par \tab TMLN\tab \tab *ldsc[TMXR_MAXLIN];\tab \tab /* line descriptors */ -\par \tab \}; -\par }\pard \widctlpar\adjustright {\f1 -\par The fields are the following: -\par -\par \tab }{\b\f1 lines}{\f1 \tab \tab number of lines (constant) -\par \tab }{\b\f1 master}{\f1 \tab \tab master listening socket (specified by ATTACH command) -\par \tab }{\b\f1 ldsc}{\f1 \tab \tab array of line descriptors -\par -\par Library sim_tmxr.c provides the following routines to support Telnet-based terminals: -\par -\par }\pard \li720\widctlpar\adjustright {\f1 int32 }{\b\f1 tmxr_poll_conn}{\f1 (TMXR *mp, UNIT *uptr) \endash poll for a new connection to the terminals described by }{\i\f1 mp }{\f1 and unit }{\i\f1 uptr}{\f1 -. If there is a new connection, the routine resets all the line descriptor state (including receive enable) and returns the line number (index to line descriptor) for the new connection. If there isn\rquote t a new connection, the routine returns -\endash 1. -\par -\par void }{\b\f1 tmxr_reset_ln}{\f1 (TMLN *lp) \endash reset the line described by }{\i\f1 lp}{\f1 . The connection is closed and all line descriptor state is reset. -\par -\par int32 }{\b\f1 tmxr_getc_ln}{\f1 (TMLN *lp) \endash return the next available character from the line described by }{\i\f1 lp}{\f1 . If a character is available, the return variable is: -\par -\par \tab (1 << TMXR_V_VALID) | character -\par -\par If no character is available, the return variable is 0. -\par -\par void }{\b\f1 tmxr_poll_rx}{\f1 (TMXR *mp) \endash poll for input available on the terminals described by }{\i\f1 mp}{\f1 . -\par -\par void }{\b\f1 tmxr_rqln}{\f1 (TMLN *lp) \endash return the number of characters in the receive queue of the line described by }{\i\f1 lp}{\f1 . -\par -\par }\pard\plain \s17\li720\widctlpar\adjustright \f1\fs20\cgrid {void }{\b tmxr_putc_ln}{ (TMLN *lp, int32 chr) \endash output character }{\i chr }{to the line described by }{\i lp}{. -\par }\pard\plain \li720\widctlpar\adjustright \fs20\cgrid {\f1 -\par }\pard\plain \s17\li720\widctlpar\adjustright \f1\fs20\cgrid {void }{\b tmxr_poll_tx}{ (TMXR *mp) \endash poll for output complete on the terminals described by }{\i mp}{. -\par }\pard\plain \li720\widctlpar\adjustright \fs20\cgrid {\f1 -\par }{\f1 void }{\b\f1 tmxr_}{\b\f1 t}{\b\f1 qln}{\f1 (TMLN *lp) \endash return the number of characters in the }{\f1 transmit}{\f1 queue of the line described by }{\i\f1 lp}{\f1 . -\par -\par }{\f1 t_stat }{\b\f1 tmxr_attach}{\f1 (TMXR *mp, UNIT *uptr, char *cptr) \endash attach the port contained in character string }{\i\f1 cptr}{\f1 to the terminals described by }{\i\f1 mp}{\f1 and unit }{\i\f1 uptr}{\f1 . -\par -\par }\pard\plain \s17\li720\widctlpar\adjustright \f1\fs20\cgrid {t_stat }{\b tmxr_detach}{ (TMXR *mp, UNIT *uptr) \endash detach all connections for the terminals described by }{\i mp}{ and unit }{\i uptr}{. -\par }\pard\plain \li720\widctlpar\adjustright \fs20\cgrid {\f1 -\par t_stat }{\b\f1 tmxr_ex}{\f1 (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) \endash stub examine routine, needed because the extra terminals are marked as attached; always returns an error. -\par -\par t_stat }{\b\f1 tmxr_dep}{\f1 (t_value val, t_addr addr, UNIT *uptr, int32 sw) \endash stub deposit routine, needed because the extra terminals are marked as detached; always returns an error. -\par }\pard \li360\widctlpar\adjustright {\f1 -\par }\pard \fi360\li360\widctlpar\adjustright {\f1 void }{\b\f1 tmxr_msg}{\f1 (SOCKET sock, char *msg) \endash output character string }{\i\f1 msg}{\f1 to socket }{\i\f1 sock}{\f1 . -\par }\pard \widctlpar\adjustright {\f1 -\par }\pard \widctlpar\outlinelevel0\adjustright {\f1 The OS-dependent socket routines should not need to be accessed by the terminal simulators. -\par }\pard \widctlpar\adjustright {\f1 -\par }} \ No newline at end of file diff --git a/simh_doc.txt b/simh_doc.txt index ceefdd8b..38e2197c 100644 --- a/simh_doc.txt +++ b/simh_doc.txt @@ -1,7 +1,7 @@ To: Users From: Bob Supnik -Subj: Simulator Usage, V2.7 -Date: 30-Sep-01 +Subj: Simulator Usage, V2.8 +Date: 10-Dec-01 COPYRIGHT NOTICE @@ -31,125 +31,92 @@ 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 the PDP-8, PDP-11, PDP-1, other 18b PDP, Nova, -IBM 1401, HP 2100, Interdata 4, and PDP-10 simulators. These simulators are -freeware; refer to the license terms above for conditions of use. Support is -not available. The best way to fix problems or add features is to read and +This memorandum documents SIMH simulators. These simulators are freeware; +refer to the license terms above for conditions of use. Support is not +available. The best way to fix problems or add features is to read and modify the sources yourself. Alternately, you can send Internet mail to bsupnik@us.inter.net, but a response is not guaranteed. -The simulators use a common command interface. The memorandum first -describes the common features of the command interface and then provides -information on each of the individual simulators. +The simulators use a common command interface. This memorandum describes +the features of the command interface. The details of each simulator are +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++ environment), -Macintosh 9 and X (CodeWarrior environment), and OS/2. Porting to other -environments will require changes to the operating system dependent code -in scp_tty.c and scp_sock.c. +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. -To compile the simulators on VMS, use these commands (note that separate -compilations are required for each of the 18b PDP's): +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 +for each simulator are given in that simulator's documentation. + +Compilation notes: + +- 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 + for the PDP-7, PDP9 for the PDP-9, PDP15 for the PDP-15). + +- The PDP-10 and VAX simulators use 64b integer variables, requiring + that USE_INT64 be defined as part of the compilation command line. + Since 64b integer declarations vary, sim_defs.h has conditional + declarations for Windows (_int64) and Digital UNIX (long). The + default is GNU C (long long). If your compiler uses a different + convention, you will have to modify sim_defs.h. + +- 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 + must be defined as part of the compilation command line. + +- The PDP-8, PDP-11, 18b PDP, PDP-10, and Nova simulators use the + 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. + +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 - $ cc pdp11_*.c,scp.c,scp_tty.c,sim_*.c ! PDP-11 - $ link/exec=pdp11 pdp11_*.obj,scp.obj,scp_tty.obj,sim_*.obj +- PDP-11 under TERMIOS UNIX: - $ cc nova_*.c,scp.c,scp_tty.c,sim_*.c ! Nova - $ link/exec=nova nova_*.obj,scp.obj,scp_tty.obj,sim_*.obj - - $ cc pdp1_*.c,scp.c,scp_tty.c ! PDP-1 - $ link/exec=pdp1 pdp1_*.obj,scp.obj,scp_tty.obj - - $ cc/define=PDP{4,7,9,15} pdp18b_*.c,scp.c,scp_tty.c,sim_*.c - $ link/exec=pdp{4,7,9,15} pdp18b_*.obj,scp.obj,scp_tty.obj,sim_*.obj - - $ cc i1401_*.c,scp.c,scp_tty.c ! IBM 1401 - $ link/exec=i1401 i1401_*.obj,scp.obj,scp_tty.obj - - $ cc hp2100_*.c,scp.c,scp_tty.c ! HP 2100 - $ link/exec=hp2100 hp2100_*.obj,scp.obj,scp_tty.obj - - $ cc id4_*.c,scp.c,scp_tty.c ! Interdata 4 - $ link/exec=id4 id4_*.obj,scp.obj,scp_tty.obj - - $ cc h316_*.c,scp.c,scp_tty.c ! Honeywell 316 - $ link/exec=h316 h316_*.obj,scp.obj,scp_tty.obj - -On version of VMS prior to 6.2, the simulators must then be defined as -foreign commands so that they can be started by name. - -To compile the simulators on Alpha UNIX or any UNIX variant which supports -the POSIX compliant TERMIOS interface (including Linux and Mac OS X), use -the following commands (note that separate compilations are required for -each of the 18b PDP's): - - % cc pdp8_*.c scp*.c sim_*.c -lm -o pdp8 % cc pdp11_*.c scp*.c sim_*.c -lm -o pdp11 - % cc nova_*.c scp*.c sim_*.c -lm -o nova - % cc pdp1_*.c scp*.c -o pdp1 - % cc -DPDP{4,7,9,15} pdp18b_*.c scp*.c sim_*.c -lm -o pdp{4,7,9,15} - % cc i1401_*.c scp*.c -o i1401 - % cc hp2100_*.c scp*.c -o hp2100 - % cc id4_*.c scp*.c -o id4 - % cc h316_*.c scp*.c -o h316 -These commands should work with most UNIX variants. If your UNIX only -supports the old BSD terminal interface, add -DBSDTTY to each command. -If your UNIX automatically includes the math library, omit -lm from -the command line. +- PDP-9 under TERMIOS UNIX: -The PDP-10 simulator requires 64b support in the simulator and in the -simulator control package (SCP). To turn on 64b support, add the symbol -USE_INT64 to the command line: + % cc -DPDP9 pdp18b_*.c scp*.c sim_*.c -lm -o pdp9 - % cc -DUSE_INT64 pdp10_*.c scp*.c sim_*.c -lm -o pdp10 +- PDP-10 under BSD terminal UNIX: -Since 64b integer declarations vary, sim_defs.h has conditional -declarations for Windows (_int64) and Digital UNIX (long). The default -is GNU C (long long). If your compiler uses a different convention, -you will have to edit sim_defs.h and modify the conditionals. + % cc -DUSE_INT64 -DBSDTTY pdp10_*.c scp*.c sim_*.c -lm -o pdp10 -To compile the simulators on Windows 9x/ME/NT/2000 and Visual C++, -each simulator must be set up as a separate project. Under the VC++ -file menu, select New, select Project Workspace, select Console -Application, and type in the name of the simulator. In the project -files view, select Add Files To Project and add in the required files: +A batch file for compiling under the Windows MINGW environment, and +a Make file for UNIX, are included in the distribution. - - all simulators: sim_defs.h, sim_rev.h, scp.c, scp_tty - - all simulators: simulator specific files (e.g., all - files beginning with nova_* for the Nova) - - PDP-10, PDP-11: dec_dz.h - - PDP-8, PDP-10, PDP-11, PDP-18b, Nova: sim_sock.h, - sim_sock.c, sim_txmr.h, sim_txmr.c +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: -If the project requires 64b support, add the switch -DUSE_INT64 to -the C/C++ tab of the Configuration dialog. If the project includes -Telnet-based terminals, add the appropriate Winsock library to the -library search list (Wsock32.dll for VC++ V4.) The simulator should -then build properly. - -To start the simulator, simply type its 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. - - % pdp8 (cr) or - % pdp11 (cr) or - % nova (cr) or - % pdp1 (cr) or - % pdp{4,7,9,15} (cr) or - % i1401 (cr) or - % hp2100 (cr) or - % id4 (cr) or - % h316 (cr) or - % pdp10 (cr) + % pdp10 (cr) or The simulator types out its name and version, executes the commands in the startup file, if any, and then prompts for input with @@ -247,6 +214,14 @@ unit. The ATTACH (abbreviation AT) command associates a unit and a file: If the file does not exist, it is created, and an appropriate message is printed. +If the -r switch is given, 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: @@ -389,10 +364,8 @@ These simulator-detected conditions stop simulation: - HALT instruction. If a HALT instruction is decoded, simulation stops. - - Breakpoint. The IBKPT register provides a single virtual - address breakpoint. If the PC matches the contents of the - IBKPT register, simulation stops. The breakpoint is - automatically disabled for the next instruction execution. + - Breakpoint. The simulator may support breakpoints (see + below). - I/O error. If an I/O error occurs during simulation of an I/O operation, and the device stop-on-I/O-error flag is set, @@ -407,11 +380,47 @@ Typing the interrupt character stops simulation. The interrupt character is defined by the WRU (where are you) register and is initially set to 005 (^E). +3.7.3 Breakpoints + +A simulator may offer breakpoint capability. A simulator may define +breakpoints of different types, identified by letter (for example, E +for execution, R for read, W for write, etc). At the moment, most +simulators support only E (execution) breakpoints. + +Associated with a breakpoint is a count. Each time the breakpoint +is sprung, the associated count is decremented. If the count is less +than or equal to 0, the breakpoint occurs; otherwise, it is deferred. + +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 low/length. Examples of SET BREAK + + 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|{,...} + +Locations with breakpoints of the specified type are displayed. + +Finally, breakpoints can be cleared by the NOBREAK command. + 3.8 Setting Device Parameters The SET command (abbreviated SE) changes the status of a device parameter: - sim> SET + sim> SET {= SET {=} Most parameters are simulator and device specific. Disk drives, for example, can usually be set write ENABLED or write LOCKED; if a device @@ -424,6 +433,13 @@ All devices recognize the following parameters: DEC sets the data radix = 10 HEX sets the data radix = 16 +Most multi-unit devices allow units to be placed online or offline: + + sim> SET ONLINE + sim> SET OFFLINE + +When a unit is offline, it will not be displayed by SHOW DEVICE. + 3.9 Displaying Parameters and Status The SHOW CONFIGURATION command shows the simulator configuration and the @@ -434,8 +450,6 @@ The SHOW DEVICES command shows the configuration of all simulated devices. The SHOW MODIFIERS command shows the modifiers available on all simulated devices. -The SHOW command shows the status of the named simulated device. - 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. @@ -443,6 +457,14 @@ 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 unit. +SHOW shows the value of the named parameter, if it can +display a result. + 3.10 Altering the Simulated Configuration For most mass storage, the DISABLE command removes the specified @@ -450,11 +472,6 @@ 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. ENABLE restores a disabled device to a configuration. -In devices with multiple units, the REMOVE command removes the -specified unit from the configuration. Once removed, a unit cannot be -manipulated in any way until it is added back to the configuration. -ADD adds back a unit that had been removed from the configuration. - 3.11 Logging Console Output Output to the console can be logged simultaneously to a file. Logging is @@ -468,4582 +485,16 @@ Logging is disabled by the NOLOG command: LOG with no argument displays whether logging is enabled or disabled. -3.12 Exiting The Simulator +3.12 Executing Command Files + +The simulator can execute command files with the DO command: + + sim> DO -- execute commands in file + +3.13 Exiting The Simulator EXIT (synonyms QUIT and BYE) returns control to the operating system. -4. PDP-8 Features - -The PDP-8 simulator is configured as follows: - -device simulates -name(s) - -CPU PDP-8/E CPU with 32KW of memory -- KE8E extended arithmetic element (EAE) -- KM8E memory management and timeshare control -PTR,PTP PC8E paper tape reader/punch -TTI,TTO KL8E console terminal -TTI1-4,TTO1-4 KL8JA additional terminals -LPT LE8E line printer -CLK DK8E line frequency clock (also PDP-8/A compatible) -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 -RX RX8E/RX01 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, RX, DT, and MT devices can be DISABLEd. The PDP-8 can -support either a DF32 or an RF08, but not both, since they use the same -IOT's. The simulator defaults to the RF08. To change the fixed head disk, - - ENABLE DF32 enable DF32, disable RF08 - ENABLE RF08 enable RF08, disable DF32 - -The PDP-8 simulator implements one unique stop condition: if an undefined -instruction (unimplemented IOT or OPR) is decoded, and register STOP_INST -is set, the simulator halts. - -The PDP-8 loader supports both RIM format 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. - -4.1 CPU - -The only CPU options are the presence of the EAE and the size of main -memory; the memory extension and time-share control is always included, -even if memory size is 4K. - - SET CPU EAE enable EAE - SET CPU NOEAE disable EAE - SET CPU 4K set memory size = 4K - SET CPU 8K set memory size = 8K - SET CPU 12K set memory size = 12K - SET CPU 16K set memory size = 16K - SET CPU 20K set memory size = 20K - SET CPU 24K set memory size = 24K - SET CPU 28K set memory size = 28K - SET CPU 32K set memory size = 32K - -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. - -CPU registers include the visible state of the processor as well as the -control registers for the interrupt system. - - name size comments - - PC 15 program counter, including IF as high 3 bits - AC 12 accumulator - MQ 12 multiplier-quotient - L 1 link - SR 12 front panel switches - IF 3 instruction field - DF 3 data field - IB 3 instruction field buffer - SF 7 save field - UF 1 user mode flag - UB 1 user mode buffer - SC 5 EAE shift counter - GTF 1 EAE greater than flag - EMODE 1 EAE mode (0 = A, 1 = B) - ION 1 interrupt enable - ION_DELAY 1 interrupt enable delay for ION - CIF_DELAY 1 interrupt enable delay for CIF - PWR_INT 1 power fail interrupt - UF_INT 1 user mode violation interrupt - INT 15 interrupt pending flags - DONE 15 device done flags - ENABLE 15 device interrupt enable flags - OLDPC 15 PC prior to last JMP, JMS, or interrupt - STOP_INST 1 stop on undefined instruction - BREAK 16 breakpoint address (177777 to disable) - WRU 8 interrupt character - -4.2 Programmed I/O Devices - -4.2.1 PC8E 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 copies the -RIM loader into memory and starts it running. - -The paper tape reader implements these registers: - - name size comments - - BUF 8 last data item processed - DONE 1 device done flag - ENABLE 1 interrupt enable flag - INT 1 interrupt pending flag - POS 31 position in the input file - TIME 24 time from I/O initiation to interrupt - 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 out of tape - - end of file 1 report error and stop - 0 out of tape - - OS I/O error x report error and stop - -4.2.2 PC8E 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 - - BUF 8 last data item processed - DONE 1 device done flag - ENABLE 1 interrupt enable flag - INT 1 interrupt pending flag - POS 31 position in the output file - TIME 24 time from I/O initiation to interrupt - 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 out of tape - - OS I/O error x report error and stop - -4.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 input implements these registers: - - name size comments - - BUF 8 last data item processed - DONE 1 device done flag - ENABLE 1 interrupt enable flag - INT 1 interrupt pending flag - POS 31 number of characters input - TIME 24 keyboard polling interval - -4.2.4 KL8E Terminal Output (TTO) - -The terminal output (TTO) writes to the simulator console window. It -implements these registers: - - name size comments - - BUF 8 last data item processed - DONE 1 device done flag - ENABLE 1 interrupt enable flag - INT 1 interrupt pending flag - POS 31 number of characters output - TIME 24 time from I/O initiation to interrupt - -4.2.5 LE8E 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 read or written. Thus, -by changing POS, the user can backspace or advance the printer. - -The line printer implements these registers: - - name size comments - - BUF 8 last data item processed - ERR 1 error status flag - DONE 1 device done flag - ENABLE 1 interrupt enable flag - INT 1 interrupt pending flag - POS 31 position in the output file - TIME 24 time from I/O initiation to interrupt - -Error handling is as follows: - - error STOP_IOE processed as - - not attached 1 report error and stop - 0 set error flag - - OS I/O error x report error and stop - -4.2.6 DK8E Line-Frequency Clock (CLK) - -The real-time clock (CLK) implements these registers: - - name size comments - - DONE 1 device done flag - ENABLE 1 interrupt enable flag - INT 1 interrupt pending flag - TIME 24 clock interval - TPS 8 ticks per second (60 or 50) - -The real-time clock autocalibrates; the clock interval is adjusted up or -down so that the clock tracks actual elapsed time. - -4.2.7 KL8JA Additional Terminals (TTI1-4, TTO1-4) - -Each additional terminal consists of two independent devices, TTIn and -TTOn. The entire set is modelled as a terminal multiplexor, with TTI1 -as the master unit. The additional terminals perform input and output -through Telnet sessions connected to a user-specified port. The ATTACH -command specifies the port to be used: - - ATTACH TTI1 (cr) -- set up listening port - -where port is a decimal number between 1 and 65535 that is not being used -for other TCP/IP activities. - -Once TTI1 is attached and the simulator is running, the terminals listen -for connections on the specified port. They assume that the incoming -connections are Telnet connections. The connections remain open until -disconnected either by the Telnet client, or by a DETACH TTI1 command. - -The SHOW TTI1 command displays the current connections to the additional -terminals. - -The input devices (TTI1-4) implement these registers: - - name size comments - - BUF 8 last data item processed - DONE 1 device done flag - ENABLE 1 interrupt enable flag - INT 1 interrupt pending flag - POS 31 number of characters input - TIME 24 keyboard polling interval - -The output devices (TTO1-4) implement these registers: - - name size comments - - BUF 8 last data item processed - DONE 1 device done flag - ENABLE 1 interrupt enable flag - INT 1 interrupt pending flag - POS 31 number of characters output - TIME 24 time from I/O initiation to interrupt - -The additional terminals do not support save and restore. All open -connections are lost when the simulator shuts down or TTI1 is detached. - -4.3 RK8E Cartridge Disk (RK) - -RK8E options include the ability to make units write enabled or write locked: - - SET RKn LOCKED set unit n write locked - SET RKn ENABLED set unit n write enabled - -Units can also be REMOVEd or ADDed to the configuration. The RK8E supports -the BOOT command. - -The RK8E implements these registers: - - name size comments - - STA 12 status - DA 12 disk address - MA 12 current memory address - CMD 12 disk command - BUSY 1 control busy flag - 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 - -4.4 RX8E/RX01 Floppy Disk (RX) - -RX8E options include the ability to set units write enabled or write locked: - - SET RXn LOCKED set unit n write locked - SET RXn ENABLED set unit n write enabled - -The RX8E supports the BOOT command. - -The RX8E implements these registers: - - name size comments - - RXCS 12 status - RXDB 12 data buffer - RXES 8 error status - RXTA 8 current track - RXSA 8 current sector - STAPTR 3 controller state - BUFPTR 3 buffer pointer - INT 1 interrupt pending flag - DONE 1 device done flag - ENABLE 1 interrupt enable flag - TR 1 transfer ready flag - ERR 1 error flag - 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:127] 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 - -RX01 data files are buffered in memory; therefore, end of file and OS -I/O errors cannot occur. - -4.5 Fixed Head Disks - -Either the RF08 or the DF32 can be present in a configuration, but -not both. - -4.5.1 RF08/RS08 Fixed Head Disk (RF) - -The RF08 implements these registers: - - name size comments - - STA 12 status - DA 20 current disk address - MA 12 memory address (in memory) - WC 12 word count (in memory) - WLK 32 write lock switches - INT 1 interrupt pending flag - DONE 1 device done flag - TIME 24 rotational delay, per word - BURST 1 burst flag - 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. - -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 -a single data break. - -Error handling is as follows: - - error STOP_IOE processed as - - not attached 1 report error and stop - 0 disk not ready - -RF08 data files are buffered in memory; therefore, end of file and OS -I/O errors cannot occur. - -4.5.2 DF32/DS32 Fixed Head Disk (RF) - -The DF32 implements these registers: - - name size comments - - STA 12 status, disk and memory address extension - DA 12 low order disk address - MA 12 memory address (in memory) - WC 12 word count (in memory) - WLK 16 write lock switches - INT 1 interrupt pending flag - DONE 1 device done flag - TIME 24 rotational delay, per word - BURST 1 burst flag - 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. - -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 -a single data break. - -Error handling is as follows: - - error STOP_IOE processed as - - not attached 1 report error and stop - 0 disk not ready - -DF32 data files are buffered in memory; therefore, end of file and OS -I/O errors cannot occur. - -4.6 TC08/TU56 DECtape (DT) - -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 LOCKED set unit n write locked - SET DTn ENABLED set unit n write enabled - -Units can also be REMOVEd or ADDed to the configuration. 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: - - -f foreign (PDP-9/11/15) format - -n native (PDP-8) 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 - INT 1 interrupt pending flag - ENB 1 interrupt enable flag - DTF 1 DECtape flag - ERF 1 error flag - CA 12 current address (memory location 7754) - WC 12 word count (memory location 7755) - 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 - POS0..7 31 position, in lines, units 0..7 - STATE0..7 31 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 - -4.7 TM8E Magnetic Tape (MT) - -Magnetic tape options include the ability to make units write enabled or -or write locked. - - SET MTn LOCKED set unit n write locked - SET MTn ENABLED set unit n write enabled - -Units can also be REMOVEd or ADDed to the configuration. - -The magnetic tape controller implements these registers: - - name size comments - - CMD 12 command - FNC 12 function - CA 12 memory address - WC 12 word count - DB 12 data buffer - STA 12 main status - STA2 6 secondary status - DONE 1 device done flag - INT 1 interrupt pending flag - STOP_IOE 1 stop on I/O error - TIME 24 record delay - UST0..7 24 unit status, units 0..n - POS0..7 31 position, units 0..n - -Error handling is as follows: - - error processed as - - not attached tape not ready - - end of file (read or space) end of physical tape - (write) ignored - - OS I/O error report error and stop - -4.8 Symbolic Display and Input - -The PDP-8 simulator implements symbolic display and input. Display is -controlled by command line switches: - - -a display as ASCII character - -c display as (sixbit) character string - -t display as (TSS/8 sixbit) character string - -m display instruction mnemonics - -Input parsing is controlled by the first character typed in or by command -line switches: - - ' or -a ASCII character - " or -c two character sixbit string - # or -t two character TSS/8 sixbit string - alphabetic instruction mnemonic - numeric octal number - -Instruction input uses standard PDP-8 assembler syntax. There are four -instruction classes: memory reference, IOT, field change, and operate. - -Memory reference instructions have the format - - memref {I} {C/Z} address - -where I signifies indirect, C a current page reference, and Z a zero page -reference. The address is an octal number in the range 0 - 07777; if C or -Z is specified, the address is a page offset in the range 0 - 177. Normally, -C is not needed; the simulator figures out from the address what mode to use. -However, when referencing memory outside the CPU (eg, disks), there is no -valid PC, and C must be used to specify current page addressing. - -IOT instructions consist of single mnemonics, eg, KRB, TLS. IOT instructions -may be or'd together - - iot iot iot... - -The simulator does not check the legality of the proposed combination. IOT's -for which there is no opcode may be specified as IOT n, where n is an octal -number in the range 0 - 0777. - -Field change instructions (CIF, CDF) have the format - - fldchg field - -where field is an octal number in the range 0 - 7. Field change instructions -may be or'd together. - -Operate instructions have the format - - opr opr opr... - -The simulator does not check the legality of the proposed combination. EAE -mode A and B mnemonics may be specified regardless of the EAE mode. The -operands for MUY and DVI must be deposited explicitly. - -5. PDP-11 Features - -The PDP-11 simulator is configured as follows: - -device simulates -name(s) - -CPU J-11 CPU with 256KB of memory -- FP11 floating point unit (FPA) -- CIS11 commercial instruction set (CIS, off by default) -PTR,PTP PC11 paper tape reader/punch -TTI,TTO DL11 console terminal -LPT LP11 line printer -CLK line frequency clock -DZ DZ11 8-line terminal multiplexor -RK RK11/RK05 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 -RX RX11/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 - -The DZ, RK, RL, RP, RX, TC, TM, and TS devices can be DISABLEd. 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, - - ENABLE TM11 enable TM11 and disable TS11 - ENABLE TS11 enable TS11 and disable TM11 - -The PDP-11 simulator implements several unique stop conditions: - - - abort during exception vector fetch, and register STOP_VEC is set - - abort during exception stack push, and register STOP_SPA is set - - trap condition 'n' occurs, and register STOP_TRAP is set - - wait state entered, and no I/O operations outstanding - (ie, no interrupt can ever occur) - -The PDP-11 loader supports standard binary format tapes. The DUMP command -is not implemented. - -5.1 CPU - -The only CPU options are disabling of 22b addressing, the CIS instruction -set, and the size of main memory. - - SET CPU 18B disable 22b addressing - SET CPU 22B enable 22b addressing (default) - SET CPU NOCIS disable CIS instructions (default) - SET CPU CIS enable CIS instructions - SET CPU 16K set memory size = 16KB - SET CPU 32K set memory size = 32KB - SET CPU 48K set memory size = 48KB - SET CPU 64K set memory size = 64KB - SET CPU 96K set memory size = 96KB - SET CPU 128K set memory size = 128KB - SET CPU 192K set memory size = 192KB - SET CPU 256K set memory size = 256KB - SET CPU 384K set memory size = 384KB - SET CPU 512K set memory size = 512KB - SET CPU 768K set memory size = 768KB - SET CPU 1024K (or 1M) set memory size = 1024KB - 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 - -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. - -These switches are recognized when examining or depositing in CPU memory: - - -v interpret address as virtual - -d if mem mgt enabled, force data space - -k if mem mgt enabled, force kernel mode - -s if mem mgt enabled, force supervisor mode - -u if mem mgt enabled, force user mode - -p if mem mgt enabled, force previous mode - -CPU registers include the visible state of the processor as well as the -control registers for the interrupt system. - - name size comments - - PC 16 program counter - R0..R5 16 R0..R5, first register set - R10..R15 16 R0..R5, second register set - KSP 16 kernel stack pointer - SSP 16 supervisor stack pointer - USP 16 user stack pointer - PSW 16 processor status word - CM 2 current mode, PSW<15:14> - PM 2 previous mode, PSW<13:12> - RS 2 register set, PSW<11> - IPL 3 interrupt priority level, PSW<7:5> - T 1 trace bit, PSW<4> - N 1 negative flag, PSW<3> - Z 1 zero flag, PSW<2> - V 1 overflow flag, PSW<1> - C 1 carry flag, PSW<0> - SR 16 front panel switches - DR 16 front panel display - MEMERR 16 memory error register - CCR 16 cache control register - MAINT 16 maintenance register - HITMISS 16 hit/miss register - CPUERR 16 CPU error register - PIRQ 16 programmed interrupt requests - FAC0H..FAC5H 32 FAC0..FAC5, high 32 bits - FAC0L..FAC5L 32 FAC0..FAC5, low 32 bits - FPS 16 floating point status - FEA 16 floating exception address - FEC 4 floating exception code - MMR0..3 16 memory management registers 0..3 - {K/S/U}{I/D}{PAR/PDR}{0..7} - 16 memory management registers - INT 32 interrupt pending flags - TRAP 18 trap pending flags - WAIT 0 wait state flag - WAIT_ENABLE 0 wait state enable flag - STOP_TRAPS 18 stop on trap flags - STOP_VECA 1 stop on read abort in trap or interrupt - STOP_SPA 1 stop on stack push abort in trap or interrupt - OLDPC 16 PC prior to last JMP, JMS, or interrupt - BREAK 16 breakpoint address (1 to disable) - WRU 8 interrupt character - -5.2 Programmed I/O Devices - -5.2.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, -by changing POS, the user can backspace or advance the reader. - -The paper tape reader implements these registers: - - name size comments - - BUF 8 last data item processed - CSR 16 control/status register - INT 1 interrupt pending flag - ERR 1 error flag (CSR<15>) - BUSY 1 busy flag (CSR<11>) - DONE 1 device done flag (CSR<7>) - IE 1 interrupt enable flag (CSR<6>) - POS 31 position in the input file - TIME 24 time from I/O initiation to interrupt - 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 out of tape - - end of file 1 report error and stop - 0 out of tape - - OS I/O error x report error and stop - -5.2.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. -Thus, by by changing POS, the user can backspace or advance the punch. - -The paper tape punch implements these registers: - - name size comments - - BUF 8 last data item processed - CSR 16 control/status register - 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>) - POS 31 position in the output file - TIME 24 time from I/O initiation to interrupt - 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 out of tape - - OS I/O error x report error and stop - -5.2.3 KL11 Terminal Input (TTI) - -The terminal input (TTI) polls the console keyboard for input. It -implements these registers: - - name size comments - - BUF 8 last data item processed - CSR 16 control/status register - 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>) - POS 31 number of characters input - TIME 24 keyboard polling interval - -5.2.4 KL11 Terminal Output (TTO) - -The terminal output (TTO) writes to the simulator console window. It -implements these registers: - - name size comments - - BUF 8 last data item processed - CSR 16 control/status register - 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>) - POS 31 number of characters input - TIME 24 time from I/O initiation to interrupt - -5.2.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, -by changing POS, the user can backspace or advance the printer. - -The line printer implements these registers: - - name size comments - - BUF 8 last data item processed - CSR 16 control/status register - 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>) - POS 31 position in the output file - TIME 24 time from I/O initiation to interrupt - 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 out of paper - - OS I/O error x report error and stop - -5.2.6 Line-Time Clock (CLK) - -The clock (CLK) implements these registers: - - name size comments - - CSR 16 control/status register - INT 1 interrupt pending flag - DONE 1 device done flag (CSR<7>) - IE 1 interrupt enable flag (CSR<6>) - TIME 24 clock frequency - TPS 8 ticks per second (60 or 50) - -The real-time clock autocalibrates; the clock interval is adjusted up or -down so that the clock tracks actual elapsed time. - -5.2.7 DZ11 Terminal Multiplexor (DZ) - -The DZ11 is an 8-line terminal multiplexor. 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: - - ATTACH {-am} DZ (cr) -- set up listening port - -where port is a decimal number between 1 and 65535 that is not being used -for other TCP/IP activities. The optional switch -m turns on the DZ11's -modem controls; the optional switch -a turns on active disconnects -(disconnect session if computer clears Data Terminal Ready). - -Once the DZ is attached and the simulator is running, the DZ will listen -for connections on the specified port. It assumes that the incoming -connections are Telnet connections. The connection remains open until -disconnected either by the simulated program or by the Telnet client. - -The SHOW DZ command displays the current connections to the DZ. - -The DZ11 implements these registers: - - name size comments - - CSR 16 control/status register - RBUF 16 receive buffer - LPR 16 line parameter register - TCR 16 transmission control register - MSR 16 modem status register - TDR 16 transmit data register - SAENB 1 silo alarm enabled - MDMTCL 1 modem control enabled - AUTODS 1 autodisconnect enabled - RPOS0..7 32 count of characters received - TPOS0..7 32 count of characters transmitted - -The DZ11 does not support save and restore. All open connections are -lost when the simulator shuts down or the DZ is detached. - -5.3 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 ENABLED set unit n write enabled - -Units can also be REMOVEd or ADDed to the configuration. 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 - -5.4 RX11/RX01 Floppy Disk (RX) - -RX11 options include the ability to make units write enabled or write locked: - - SET RXn LOCKED set unit n write locked - SET RXn ENABLED set unit n write enabled - -The RX11 supports the BOOT command. - -The RX11 implements these registers: - - name size comments - - RXCS 12 status - RXDB 8 data buffer - RXES 8 error status - RXERR 8 error code - RXTA 8 current track - RXSA 8 current sector - STAPTR 3 controller state - BUFPTR 3 buffer pointer - 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:127] 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 - -RX01 data files are buffered in memory; therefore, end of file and OS -I/O errors cannot occur. - -5.5 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 ENABLED set unit n write enabled - SET RLn RL01 set size to RL01 - SET RLn RL02 set size to RL02 - 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 REMOVEd or ADDed to the configuration. The RL11 supports the -BOOT command. - -The RL11 implements these registers: - - name size comments - - RLCS 16 control/status - RLDA 16 disk address - RLBA 16 memory address - RLBAE 6 memory address extension (RLV12) - RLMP..RLMP2 16 multipurpose register queue - 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>) - 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 - -5.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. - -RP options include the ability to set units write enabled or write locked, -to set the drive size to one of seven 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 ENABLED set unit n write enabled - SET RPn RM03 set size to RM03 - SET RPn RM05 set size to RM05 - SET RPn RM80 set size to RM80 - SET RPn RP04 set size to RP04 - SET RPn RP06 set size to RP06 - SET RPn RP07 set size to RP07 - SET RPn AUTOSIZE set size based on file size at attach - SET RPn 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 REMOVEd or ADDed to the configuration. The RP controller supports -the BOOT command. - -The RP controller implements these registers: - - name size comments - - RPCS1 16 control/status 1 - RPWC 16 word count - RPBA 16 bus address - RPDA 16 desired surface, sector - RPCS2 16 control/status 2 - RPOF 16 offset - RPDC 8 desired cylinder - RPER2 16 error status 2 - RPER3 16 error status 3 - RPEC1 16 ECC syndrome 1 - RPEC2 16 ECC syndrome 2 - RPMR 16 maintenance register - RPDB 16 data buffer - RPBAE 6 bus address extension - RPCS3 16 control/status 3 - RPIFF 1 transfer complete interrupt request flop - INT 1 interrupt pending flag - SC 1 special condition (CSR1<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 - RPDS0..7 16 drive status, drives 0-7 - RPDE0..7 16 drive error, drives 0-7 - 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 - -5.7 TC11/TU56 DECtape (DT) - -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 LOCKED set unit n write locked - SET DTn ENABLED set unit n write enabled - -Units can also be REMOVEd or ADDed to the configuration. The TC11 supports -the BOOT command. - -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: - - -f foreign (PDP-8) format - -n native (PDP-9/11/15) 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 - - TCST 16 status register - TCCM 16 command register - TCWC 16 word count register - TCBA 16 bus address register - TCDT 16 data register - INT 1 interrupt pending flag - ERR 1 error flag - DONE 1 done flag - IE 1 interrupt enable flag - CTIME 31 time to complete transport stop - 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 - POS0..7 31 position, in lines, units 0..7 - STATE0..7 31 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 - -5.8 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 ENABLED set unit n write enabled - -Units can also be REMOVEd or ADDed to the configuration. - -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. - -The magnetic tape controller implements these registers: - - name size comments - - MTS 16 status - MTC 16 command - MTCMA 16 memory address - MTBRC 16 byte/record count - INT 1 interrupt pending flag - ERR 1 error flag - DONE 1 device done flag - IE 1 interrupt enable flag - STOP_IOE 1 stop on I/O error - TIME 24 delay - UST0..7 16 unit status, units 0..n - POS0..7 31 position, units 0..n - -Error handling is as follows: - - error processed as - - not attached tape not ready - - end of file (read or space) end of physical tape - (write) ignored - - OS I/O error report error and stop - -5.8 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 -write enabled or write locked. - - SET TS LOCKED set unit write locked - SET TS ENABLED 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. - -The magnetic tape controller implements these registers: - - name size comments - - TSSR 16 status register - TSBA 16 bus address register - TSDBX 16 data buffer extension register - CHDR 16 command packet header - CADL 16 command packet low address or count - CADH 16 command packet high address - CLNT 16 command packet length - MHDR 16 message packet header - MRFC 16 message packet residual frame count - MXS0 16 message packet extended status 0 - MXS1 16 message packet extended status 1 - MXS2 16 message packet extended status 2 - MXS3 16 message packet extended status 3 - MXS4 16 message packet extended status 4 - WADL 16 write char packet low address - WADH 16 write char packet high address - WLNT 16 write char packet length - WOPT 16 write char packet options - WXOPT 16 write char packet extended options - ATTN 1 attention message pending - BOOT 1 boot request pending - OWNC 1 if set, tape owns command buffer - OWNM 1 if set, tape owns message buffer - TIME 24 delay - POS 31 position - -Error handling is as follows: - - error processed as - - not attached tape not ready - - end of file (read or space) end of physical tape - (write) ignored - - OS I/O error fatal tape error - -5.10 Symbolic Display and Input - -The PDP-11 simulator implements symbolic display and input. Display is -controlled by command line switches: - - -a display as ASCII character - -c display as two character ASCII string - -m display instruction mnemonics - -Input parsing is controlled by the first character typed in or by command -line switches: - - ' or -a ASCII character - " or -c two character ASCII string - alphabetic instruction mnemonic - numeric octal number - -Instruction input uses standard PDP-11 assembler syntax. There are sixteen -instruction classes: - -class operands examples comments - -no operands none HALT, RESET -3b literal literal, 0 - 7 SPL -6b literal literal, 0 - 077 MARK -8b literal literal, 0 - 0377 EMT, TRAP -register register RTS -sop specifier SWAB, CLR, ASL -reg-sop register, specifier JSR, XOR, MUL -fop flt specifier ABSf, NEGf -ac-fop flt reg, flt specifier LDf, MULf -ac-sop flt reg, specifier LDEXP, STEXP -ac-moded sop flt reg, specifier LDCif, STCfi -dop specifier, specifier MOV, ADD, BIC -cond branch address BR, BCC, BNE -sob register, address SOB -cc clear cc clear instructions CLC, CLV, CLZ, CLN combinable -cc set cc set instructions SEC, SEV, SEZ, SEN combinable - -For floating point opcodes, F and D variants, and I and L variants, may be -specified regardless of the state of FPS. - -The syntax for specifiers is as follows: - -syntax specifier displacement comments - -Rn 0n - -Fn 0n - only in flt reg classes -(Rn) 1n - -@(Rn) 7n 0 equivalent to @0(Rn) -(Rn)+ 2n - -@(Rn)+ 3n - --(Rn) 4n - -@-(Rn) 5n - -{+/-}d(Rn) 6n {+/-}d -@{+/-}d(Rn) 7n {+/-}d -#n 27 n -@#n 37 n -.+/-n 67 +/-n - 4 -@.+/-n 77 +/-n - 4 -{+/-}n 67 {+/-}n - PC - 4 if on disk, 37 and n -@{+/-}n 77 {+/-}n - PC - 4 if on disk, invalid - -6. Nova Features - -The Nova simulator is configured as follows: - -device simulates -name(s) - -CPU Nova CPU with 32KW of memory -- hardware multiply/divide -PTR,PTP paper tape reader/punch -TTI,TTO console terminal -TTI1,TTO1 second terminal -LPT line printer -PLT plotter -CLK real-time clock -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 DISABLEd. - -The Nova simulator implements these unique stop conditions: - - - reference to undefined I/O device, and STOP_DEV is set - - more than INDMAX indirect addresses are detected during - an interrupt - - more than INDMAX indirect addresses are detected during - memory reference address decoding - -The Nova loader supports standard binary format tapes. The DUMP command -is not implemented. - -6.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 NONE disable all optional instructions - SET CPU 4K set memory size = 4K - SET CPU 8K set memory size = 8K - SET CPU 12K set memory size = 12K - SET CPU 16K set memory size = 16K - SET CPU 20K set memory size = 20K - SET CPU 24K set memory size = 24K - SET CPU 28K set memory size = 28K - SET CPU 32K set memory size = 32K - -(MDV = unsigned multiply/divide instructions) -(Nova 3 = unsigned multiply/divide, stack, trap instructions) -(Nova 4 = unsigned and signed multiply/divide, stack, byte, trap instructions) - -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. - -CPU registers include the visible state of the processor as well as the -control registers for the interrupt system. - - name size comments - - PC 15 program counter - AC0..AC3 16 accumulators 0..3 - C 1 carry - SR 16 front panel switches - PI 16 priority interrupt mask - ION 1 interrupt enable - ION_DELAY 1 interrupt enable delay for ION - PWR 1 power fail interrupt - INT 15 interrupt pending flags - BUSY 15 device busy flags - DONE 15 device done flags - DISABLE 15 device interrupt disable flags - STOP_DEV 1 stop on undefined IOT - INDMAX 15 maximum number of nested indirects - OLDPC 15 PC prior to last JMP, JMS, or interrupt - BREAK 16 breakpoint address (177777 to disable) - WRU 8 interrupt character - -6.2 Programmed I/O Devices - -6.2.1 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 implements these registers: - - name size comments - - BUF 8 last data item processed - BUSY 1 device busy flag - DONE 1 device done flag - DISABLE 1 interrupt disable flag - INT 1 interrupt pending flag - POS 31 position in the input file - TIME 24 time from I/O initiation to interrupt - 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 out of tape or paper - - end of file 1 report error and stop - 0 out of tape or paper - - OS I/O error x report error and stop - -6.2.2 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. -Thus, by changing POS, the user can backspace or advance the punch. - -The paper tape punch implements these registers: - - name size comments - - BUF 8 last data item processed - BUSY 1 device busy flag - DONE 1 device done flag - DISABLE 1 interrupt disable flag - INT 1 interrupt pending flag - POS 31 position in the output file - TIME 24 time from I/O initiation to interrupt - 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 out of tape or paper - - OS I/O error x report error and stop - -6.2.3 Terminal Input (TTI) - -The terminal input polls the console keyboard for input. Terminal -input options include the ability to set ANSI mode or limited Dasher -compatibility mode: - - SET TTI ANSI normal mode - SET TTI DASHER Dasher mode - -Setting either TTI or TTO changes both devices. In Dasher mode, carriage -return is changed to newline on input, and ^X is changed to backspace. - -The terminal input implements these registers: - - name size comments - - BUF 8 last data item processed - BUSY 1 device busy flag - DONE 1 device done flag - DISABLE 1 interrupt disable flag - INT 1 interrupt pending flag - POS 31 number of characters input - TIME 24 keyboard polling interval - -6.2.4 Terminal Output (TTO) - -The terminal output writes to the simulator console window. Terminal -output options include the the ability to set ANSI mode or limited -Dasher compatibility mode: - - SET TTO ANSI normal mode - SET TTO DASHER Dasher mode - -Setting either TTI or TTO changes both devices. In Dasher mode, carriage -return is changed to newline on input, and ^X is changed to backspace. - -The terminal output implements these registers: - - name size comments - - BUF 8 last data item processed - BUSY 1 device busy flag - DONE 1 device done flag - DISABLE 1 interrupt disable flag - INT 1 interrupt pending flag - POS 31 number of characters output - TIME 24 time from I/O initiation to interrupt - -6.2.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, -by changing POS, the user can backspace or advance the printer. - -The line printer implements these registers: - - name size comments - - BUF 8 last data item processed - BUSY 1 device busy flag - DONE 1 device done flag - DISABLE 1 interrupt disable flag - INT 1 interrupt pending flag - POS 31 position in the output file - TIME 24 time from I/O initiation to interrupt - 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 out of paper - - OS I/O error x report error and stop - -6.2.6 Real-Time Clock (CLK) - -The real-time clock (CLK) implements these registers: - - name size comments - - SELECT 2 selected clock interval - BUSY 1 device busy flag - DONE 1 device done flag - DISABLE 1 interrupt disable flag - INT 1 interrupt pending flag - TIME0 24 clock frequency, select = 0 - TIME1 24 clock frequency, select = 1 - TIME2 24 clock frequency, select = 2 - TIME3 24 clock frequency, select = 3 - -The real-time clock autocalibrates; the clock interval is adjusted up or -down so that the clock tracks actual elapsed time. - -6.2.7 Plotter (PTP) - -The plotter (PLT) 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 plotter. - -The plotter implements these registers: - - name size comments - - BUF 8 last data item processed - BUSY 1 device busy flag - DONE 1 device done flag - DISABLE 1 interrupt disable flag - INT 1 interrupt pending flag - POS 31 position in the output file - TIME 24 time from I/O initiation to interrupt - 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 out of tape or paper - - OS I/O error x report error and stop - -6.2.8 Second Terminal (TTI1, TTO1) - -The second terminal consists of two independent devices, TTI1 and TTO1. -The additional terminal performs input and output through a Telnet session -connecting into a user-specified port. The ATTACH command specifies the -port to be used: - - ATTACH TTI1 (cr) -- set up listening port - -where port is a decimal number between 1 and 65535 that is not being used -for other TCP/IP activities. - -Once TTI1 is attached and the simulator is running, the terminal listens -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 has two options, recognized on both devices, for -setting limited Dasher-compatibility mode or ANSI mode: - - SET TTI1 ANSI normal mode - SET TTI1 DASHER Dasher mode - SET TTO1 ANSI normal mode - SET TTO1 DASHER Dasher mode - -Setting either TTI1 or TTO1 changes both devices. In Dasher mode, carriage -return is changed to newline on input, and ^X is changed to backspace. - -The SHOW TTI1 command displays the current connection to the second -terminal. - -The second terminal input implements these registers: - - name size comments - - BUF 8 last data item processed - BUSY 1 device busy flag - DONE 1 device done flag - DISABLE 1 interrupt disable flag - INT 1 interrupt pending flag - POS 31 number of characters input - TIME 24 keyboard polling interval - -The second terminal output implements these registers: - - name size comments - - BUF 8 last data item processed - BUSY 1 device busy flag - DONE 1 device done flag - DISABLE 1 interrupt disable flag - INT 1 interrupt pending flag - POS 31 number of characters output - TIME 24 time from I/O initiation to interrupt - -6.3 Fixed Head Disk (DK) - -The fixed head disk controller implements these registers: - - name size comments - - STAT 16 status - DA 16 disk address - MA 16 memory address - BUSY 1 device busy flag - DONE 1 device done flag - DISABLE 1 device disable flag - INT 1 interrupt pending flag - WLK 8 write lock switches - TIME 24 rotational delay, per sector - STOP_IOE 1 stop on I/O error - -The fixed head disk controller supports the BOOT command. - -Error handling is as follows: - - error STOP_IOE processed as - - not attached 1 report error and stop - 0 disk not ready - -Fixed head disk data files are buffered in memory; therefore, end of file -and OS I/O errors cannot occur. - -6.4 Moving Head Disk (DP) - -Moving head disk options include the ability to make units write enabled or -write locked, and to select the type of drive: - - SET DPn LOCKED set unit n write locked - SET DPn ENABLED set unit n write enabled - SET DPn FLOPPY set unit n to floppy disk - SET DPn D31 set unit n to Diablo 31 - SET DPn D44 set unit n to Diablo 44 - SET DPn C111 set unit n to Century 111 - SET DPn C114 set unit n to Century 114 - SET DPn 6225 set unit n to 6225 - SET DPn 6099 set unit n to 6099 - SET DPn 6227 set unit n to 6227 - SET DPn 6070 set unit n to 6070 - SET DPn 6103 set unit n to 6103 - SET DPn 4231 set unit n to 4231 - -Units can also be REMOVEd or ADDed to the configuration. The moving head -disk controller supports the BOOT command. - -All drives have 256 16b words per sector. The other disk parameters are: - - drive cylinders surfaces sectors size (MW) DG models - - floppy 77 1 8 .158 6038 - D31 203 2 12 1.247 4047, 4237, 4238 - D44 408 4 12 5.014 4234, 6045 - C111 203 10 6 3.118 4048 - C114 203 20 12 12.472 4057, 2314 - 6225 20 2 245 2.508 - 6099 32 4 192 6.291 - 6227 20 6 245 7.526 - 6070 24 4 408 10.027 - 6103 32 8 192 12.583 - 4231 23 19 411 45.979 - -The moving head disk controller implements these registers: - - name size comments - - FCCY 16 flags, command, cylinder - USSC 16 unit, surface, sector, count - STAT 16 status - MA 16 memory address - BUSY 1 device busy flag - DONE 1 device done flag - DISABLE 1 interrupt disable flag - INT 1 interrupt pending flag - STIME 24 seek time, per cylinder - RTIME 24 rotational delay - -Error handling is as follows: - - error processed as - - not attached disk not ready - - end of file assume rest of disk is zero - - OS I/O error report error and stop - -6.5 Magnetic Tape (MT) - -Magnetic tape options include the ability to make units write enabled or -or write locked. - - SET MTn LOCKED set unit n write locked - SET MTn ENABLED set unit n write enabled - -Units can also be REMOVEd or ADDed to the configuration. The magnetic -tape controller supports the BOOT command. - -The magnetic tape controller implements these registers: - - name size comments - - CU 16 command, unit - MA 16 memory address - WC 16 word count - STA1 16 status word 1 - STA2 16 status word 2 - EP 1 extended polling mode (not supported) - BUSY 1 device busy flag - DONE 1 device done flag - DISABLE 1 interrupt disable flag - INT 1 interrupt pending flag - STOP_IOE 1 stop on I/O error - CTIME 24 controller delay - RTIME 24 record delay - UST0..7 32 unit status, units 0..n - POS0..7 31 position, units 0..n - -Error handling is as follows: - - error processed as - - not attached tape not ready - - end of file (read or space) end of physical tape - (write) ignored - - OS I/O error report error and stop - -6.6 Symbolic Display and Input - -The Nova simulator implements symbolic display and input. Display is -controlled by command line switches: - - -a display as ASCII character - -c display as two character ASCII string - -m display instruction mnemonics - -Input parsing is controlled by the first character typed in or by command -line switches: - - ' or -a ASCII character - " or -c two character ASCII string - alphabetic instruction mnemonic - numeric octal number - -Instruction input uses standard Nova assembler syntax. There are three -instruction classes: memory reference, IOT, and operate. - -Memory reference instructions have the format - - memref {ac,}{@}address{,index} - -LDA and STA require an initial register; ISZ, DSZ, JSR, and JMP do not. -The syntax for addresses and indices is as follows: - -syntax mode displacement comments - -0 <= n < 0400 0 n -{+/-}n >= 0400 1 {+/-}n - PC must be in range [-200, 177] - invalid on disk -.+/-n 1 {+/-}n must be in range [-200, 177] -{+/-}n,2 2 {+/-}n must be in range [-200, 177] -{+/-}n,3 3 {+/-}n must be in range [-200, 177] - -IOT instructions have one of four formats - - syntax example - - iot HALT - iot reg INTA - iot device SKPDN - iot reg,device DOAS - -Devices may be specified as mnemonics or as numbers in the range 0 - 077. - -Operate instructions have the format - - opcode{#} reg,reg{,skip} - -In all Nova instructions, blanks may be substituted for commas as field -delimiters. - -7. PDP-1 Features - -The PDP-1 is configured as follows: - -device simulates -name(s) - -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 - -The PDP-1 simulator implements the following unique stop conditions: - - - an unimplemented instruction is decoded, and register - STOP_INST is set - - more than INDMAX indirect addresses are detected during - memory reference address decoding - - more than XCTMAX nested executes are detected during - instruction execution - - wait state entered, and no I/O operations outstanding - (ie, no interrupt can ever occur) - -The PDP-1 loader supports RIM format tapes. The DUMP command is not -implemented. - -7.1 CPU - -The only CPU options are the presence of hardware multiply/divide and the -size of main memory. - - SET CPU MDV enable multiply/divide - SET CPU NOMDV disable multiply/divide - SET CPU 4K set memory size = 4K - SET CPU 8K set memory size = 8K - SET CPU 12K set memory size = 12K - SET CPU 16K set memory size = 16K - SET CPU 20K set memory size = 20K - SET CPU 24K set memory size = 24K - SET CPU 28K set memory size = 28K - SET CPU 32K set memory size = 32K - SET CPU 48K set memory size = 48K - SET CPU 64K set memory size = 64K - -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 64K. - -CPU registers include the visible state of the processor as well as the -control registers for the interrupt system. - - name size comments - - PC 16 program counter - AC 18 accumulator - IO 18 IO register - OV 1 overflow flag - PF 6 program flags<1:6> - SS 6 sense switches<1:6> - TW 18 test word (front panel switches) - EXTM 1 extend mode - IOSTA 18 IO status register - SBON 1 sequence break enable - SBRQ 1 sequence break request - SBIP 1 sequence break in progress - IOH 1 I/O halt in progress - IOC 1 I/O continue - OLDPC 16 PC prior to last transfer - STOP_INST 1 stop on undefined instruction - SBS_INIT 1 initial state of sequence break enable - EXTM_INIT 1 initial state of extend mode - BREAK 17 breakpoint address (377777 to disable) - WRU 8 interrupt character - -7.2 Programmed I/O Devices - -7.2.1 Paper Tape Reader (PTR) - -The paper tape reader (PTR) 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 PTR copies the -RIM loader into memory and starts it running. - -The paper tape reader implements these registers: - - name size comments - - BUF 8 last data item processed - DONE 1 device done flag - RPLS 1 return restart pulse flag - POS 31 position in the input file - TIME 24 time from I/O initiation to interrupt - 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 out of tape - - end of file 1 report error and stop - 0 out of tape - - OS I/O error x report error and stop - -7.2.2 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. -Thus, by changing POS, the user can backspace or advance the punch. - -The paper tape punch implements these registers: - - name size comments - - BUF 8 last data item processed - DONE 1 device done flag - RPLS 1 return restart pulse flag - POS 31 position in the output file - TIME 24 time from I/O initiation to interrupt - 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 out of tape - - OS I/O error x report error and stop - -7.2.3 Terminal Input (TTI) - -The terminal input (TTI) polls the console keyboard for input. It -implements these registers: - - name size comments - - BUF 8 last data item processed - DONE 1 device done flag - POS 31 number of characters input - TIME 24 keyboard polling interval - -7.2.4 Terminal Output (TTO) - -The terminal output (TTO) writes to the simulator console window. -It implements these registers: - - name size comments - - BUF 8 last data item processed - DONE 1 device done flag - RPLS 1 return restart pulse flag - POS 31 number of characters output - TIME 24 time from I/O initiation to interrupt - -7.2.5 Type 62 Line Printer (LPT) - -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 implements these registers: - - name size comments - - BUF 8 last data item processed - PNT 1 printing done flag - SPC 1 spacing done flag - RPLS 1 return restart pulse flag - BPTR 6 print buffer pointer - POS 31 position in the output file - TIME 24 time from I/O initiation to interrupt - STOP_IOE 1 stop on I/O error - LBUF[0:119] 8 line buffer - -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 - -7.3 Symbolic Display and Input - -The PDP-1 simulator implements symbolic display and input. Display is -controlled by command line switches: - - -a display as ASCII character - -c display as FIODEC character string - -m display instruction mnemonics - -Input parsing is controlled by the first character typed in or by command -line switches: - - ' or -a ASCII character - " or -c three character FIODEC string - alphabetic instruction mnemonic - numeric octal number - -Instruction input uses modified PDP-1 assembler syntax. There are six -instruction classes: memory reference, shift, skip, operate, IOT, and -LAW. - -Memory reference instructions have the format - - memref {I} address - -where I signifies indirect reference. The address is an octal number in -the range 0 - 0177777. - -Shift instructions have the format - - shift shift_count - -The shift count is an octal number in the range 0-9. - -Skip instructions consist of single mnemonics, eg, SZA, SZS4. Skip -instructions may be or'd together - - skip skip skip... - -The sense of a skip can be inverted by including the mnemonic I. - -Operate instructions consist of single mnemonics, eg, CLA, CLI. Operate -instructions may be or'd together - - opr opr opr... - -IOT instructions consist of single mnemonics, eg, TYI, TYO. IOT -instructions may include an octal numeric modifier or the modifier I: - - iot modifier - -The simulator does not check the legality of skip, operate, or IOT -combinations. - -Finally, the LAW instruction has the format - - LAW {I} immediate - -where immediate is in the range 0 to 07777. - -7.4 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 -character set. The following table provides equivalences between ASCII -characters and the PDP-1's I/O devices. In the console table, UC stands -for upper case. - - PDP-1 PDP-1 -ASCII console line printer - -000 - 007 none none -bs 075 none -tab 036 none -012 - 014 none none -cr 077 none -016 - 037 none none -space 000 000 -! {OR} UC+005 none -" UC+001 none -# {IMPLIES} UC+004 none -$ none none -% none none -& {AND} UC+006 none -' UC+002 none -( 057 057 -) 055 055 -* {TIMES} UC+073 072 -+ UC+054 074 -, 033 033 -- 054 054 -. 073 073 -/ 021 021 -0 020 020 -1 001 001 -2 002 002 -3 003 003 -4 004 004 -5 005 005 -6 006 006 -7 007 007 -8 010 010 -9 011 011 -: none none -; none none -< UC+007 034 -= UC+033 053 -> UC+010 034 -? UC+021 037 -@ {MID DOT} 040 {MID DOT} 040 -A UC+061 061 -B UC+062 062 -C UC+063 063 -D UC+064 064 -E UC+065 065 -F UC+066 066 -G UC+067 067 -H UC+070 070 -I UC+071 071 -J UC+041 041 -K UC+042 042 -L UC+043 043 -M UC+044 044 -N UC+045 045 -O UC+046 046 -P UC+047 047 -Q UC+050 050 -R UC+051 051 -S UC+022 022 -T UC+023 023 -U UC+024 024 -V UC+025 025 -W UC+026 026 -X UC+027 027 -Y UC+030 030 -Z UC+031 031 -[ UC+057 none -\ {OVERLINE} 056 {OVERLINE} 056 -] UC+055 none -^ {UP ARROW} UC+011 {UP ARROW} 035 -_ UC+040 UC+040 -` {RT ARROW} UC+020 036 -a 061 none -b 062 none -c 063 none -d 064 none -e 065 none -f 066 none -g 067 none -h 070 none -i 071 none -j 041 none -k 042 none -l 043 none -m 044 none -n 045 none -o 046 none -p 047 none -q 050 none -r 051 none -s 022 none -t 023 none -u 024 none -v 025 none -w 026 none -x 027 none -y 030 none -z 031 none -{ none none -| UC+056 076 -} none none -~ UC+003 013 -del 075 none - -8. 18b PDP Features - -The other four 18b PDP's (PDP-4, PDP-7, PDP-9, PDP-15) are very similar -and are configured as follows: - -system device simulates - name(s) - -PDP-4 CPU PDP-4 CPU with 8KW of memory - PTR,PTP integral paper tape/Type 75 punch - TTI,TTO KSR28 console terminal (Baudot code) - LPT Type 62 line printer (Hollerith code) - CLK integral real-time clock - -PDP-7 CPU PDP-7 CPU with 32KW of memory - - Type 177 extended arithmetic element (EAE) - - Type 148 memory extension - PTR,PTP Type 444 paper tape reader/Type 75 punch - TTI,TTO KSR 33 console terminal - LPT Type 647 line printer - CLK integral real-time clock - DRM Type 24 serial drum - -PDP-9 CPU PDP-9 CPU with 32KW of memory - - KE09A extended arithmetic element (EAE) - - KF09A automatic priority interrupt (API) - - KG09B memory extension - - KP09A power detection - - KX09A memory protection - PTR,PTP PC09A paper tape reader/punch - TTI,TTO KSR 33 console terminal - TTI1,TTO1 LT09A second console terminal - LPT Type 647E line printer - CLK integral real-time clock - RF RF09/RS09 fixed-head disk - DT TC02/TU55 DECtape - MT TC59/TU10 magnetic tape - -PDP-15 CPU PDP-15 CPU with 32KW of memory - - KE15 extended arithmetic element (EAE) - - KA15 automatic priority interrupt (API) - - KF15 power detection - - KM15 memory protection - PTR,PTP PC15 paper tape reader/punch - TTI,TTO KSR 35 console terminal - TTI1,TTO1 LT15 second console terminal - LPT LP15 line printer - CLK integral real-time clock - RP RP15/RP02 disk pack - RF RF15/RS09 fixed-head disk - DT TC15/TU56 DECtape - MT TC59/TU10 magnetic tape - -The DRM, RF, RP, DT, and MT devices can be DISABLEd. - -The 18b PDP simulators implement several unique stop conditions: - - - an unimplemented instruction is decoded, and register - STOP_INST is set - - more than XCTMAX nested executes are detected during - instruction execution - -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. - -8.1 CPU - -The CPU options are the presence of the EAE, the presense of the API (for -the PDP-9 and PDP-15), and the size of main memory. - - SET CPU EAE enable EAE - SET CPU NOEAE disable EAE - SET CPU API enable API - SET CPU NOAPI disable API - SET CPU 4K set memory size = 4K - SET CPU 8K set memory size = 8K - SET CPU 12K set memory size = 12K - SET CPU 16K set memory size = 16K - SET CPU 20K set memory size = 20K - SET CPU 24K set memory size = 24K - SET CPU 28K set memory size = 28K - SET CPU 32K set memory size = 32K - SET CPU 48K set memory size = 48K - SET CPU 64K set memory size = 64K - SET CPU 80K set memory size = 80K - SET CPU 96K set memory size = 96K - SET CPU 112K set memory size = 112K - SET CPU 128K set memory size = 128K - -Memory sizes greater than 8K are only available on the PDP-7, PDP-9, and -PDP-15; memory sizes greater than 32KW are only available on the PDP-15. -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 8K for the PDP-4, 32K -for the PDP-7 and PDP-9, and 128K for the PDP-15. - -CPU registers include the visible state of the processor as well as the -control registers for the interrupt system. - - system name size comments - - all PC addr program counter - 7,9 PC 15 program counter - 15 PC 17 program counter - all AC 18 accumulator - 7,9,15 MQ 18 multiplier-quotient - 7,9,15 SC 6 shift counter - 7,9,15 EAE_AC_SIGN 1 EAE AC sign - all L 1 link - 7,9 EXTM 1 extend mode - 9 EXTM_INIT 1 extend mode value after reset - 15 BANKM 1 bank mode - 15 BANKM_INIT 1 bank mode value after reset - 7 TRAPM 1 trap mode - 9,15 USMD 1 user mode - 9,15 USMDBUF 1 user mode buffer - 9,15 BR addr memory protection bounds - 7,9,15 TRAPP 1 trap pending - 9,15 NEXM 1 non-existent memory violation - 9,15 PRVN 1 privilege violation - 7,9 EMIRP 1 EMIR instruction pending - 9,15 RESTP 1 DBR or RES instruction pending - 15 XR 18 index register - 15 LR 18 limit register - all SR 18 front panel switches - all INT 32 interrupt requests - all IORS 18 IORS register - all ION 1 interrupt enable - all ION_DELAY 2 interrupt enable delay - all OLDPC addr PC prior to last transfer - all STOP_INST 1 stop on undefined instruction - all BREAK 18 breakpoint address (777777 to disable) - all WRU 8 interrupt character - -"addr" signifies the address width of the system (13b for the PDP-4, 15b for -the PDP-7 and PDP-9, 17b for the PDP-15). - -8.2 Programmed I/O Devices - -8.2.1 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. - -On the PDP-4 and PDP-7, the paper tape reader supports the BOOT command. -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 paper tape reader implements these registers: - - name size comments - - BUF 8 last data item processed - INT 1 interrupt pending flag - DONE 1 device done flag - ERR 1 error flag (PDP-9, PDP-15 only) - POS 31 position in the input file - TIME 24 time from I/O initiation to interrupt - 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 out of tape - - end of file 1 report error and stop - 0 out of tape - - OS I/O error x report error and stop - -8.2.2 Paper Tape Punch (PTP) - -The ppaper 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 paper tape punch implements these registers: - - name size comments - - BUF 8 last data item processed - INT 1 interrupt pending flag - DONE 1 device done flag - ERR 1 error flag (PDP-9, PDP-15 only) - POS 31 position in the output file - TIME 24 time from I/O initiation to interrupt - 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 out of tape or paper - - OS I/O error x report error and stop - -8.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. - -The PDP-9 and PDP-15 operate the console terminal (TTI/TTO), by default, -as half duplex. 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 in full-duplex mode. The second terminal is always -full duplex. - -The terminal input implements these registers: - - name size comments - - BUF 8 last data item processed - INT 1 interrupt pending flag - DONE 1 device done flag - POS 31 number of characters input - TIME 24 keyboard polling interval - -8.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: - - name size comments - - BUF 8 last data item processed - INT 1 interrupt pending flag - DONE 1 device done flag - POS 31 number of chararacters output - TIME 24 time from I/O initiation to interrupt - -8.2.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, -by changing POS, the user can backspace or advance the printer. - -The PDP-4 used a Type 62 printer controller, with these registers: - - name size comments - - BUF 8 last data item processed - INT 1 interrupt pending flag - DONE 1 device done flag - SPC 1 spacing done flag - BPTR 6 print buffer pointer - POS 31 position in the output file - TIME 24 time from I/O initiation to interrupt - 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 -registers: - - name size comments - - BUF 8 last data item processed - INT 1 interrupt pending flag - DONE 1 device done flag - ENABLE 1 interrupt enable (PDP-9 only) - ERR 1 error flag - BPTR 7 print buffer pointer - POS 31 position in the output file - TIME 24 time from I/O initiation to interrupt - 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: - - name size comments - - STA 18 status register - MA 18 DMA memory address - INT 1 interrupt pending flag - ENABLE 1 interrupt enable - LCNT 8 line counter - BPTR 7 print buffer pointer - POS 31 position in the output file - TIME 24 time from I/O initiation to interrupt - STOP_IOE 1 stop on I/O error - LBUF[0:131] 8 line buffer - -For all three models, 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 - -8.2.6 Real-Time Clock (CLK) - -The real-time clock (CLK) implements these registers: - - name size comments - - INT 1 interrupt pending flag - DONE 1 device done flag - ENABLE 1 clock enable - TIME 24 clock frequency - TPS 8 ticks per second (60 or 50) - -The real-time clock autocalibrates; the clock interval is adjusted up or -down so that the clock tracks actual elapsed time. - -8.2.7 Second Terminal (TTI1, TTO1) - -The second terminal consists of two independent devices, TTI1 and TTO1. -The second terminal performs input and output through a Telnet session -connected to a user-specified port. The ATTACH command specifies the -port to be used: - - ATTACH TTI1 (cr) -- set up listening port - -where port is a decimal number between 1 and 65535 that is not being used -for other TCP/IP activities. - -Once TTI1 is attached and the simulator is running, the terminal listens -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 SHOW TTI1 command displays the current connection to the second -terminal. - -The second terminal input implements these registers: - - name size comments - - BUF 8 last data item processed - INT 1 interrupt pending flag - DONE 1 device done flag - POS 31 number of characters input - TIME 24 keyboard polling interval - -The second terminal output implements these registers: - - name size comments - - BUF 8 last data item processed - INT 1 interrupt pending flag - DONE 1 device done flag - POS 31 number of chararacters output - TIME 24 time from I/O initiation to interrupt - -8.3 RP15/RP02 Disk Pack (RP) - -RP15 options include the ability to make units write enabled or write locked: - - SET RPn LOCKED set unit n write locked - SET RPn ENABLED set unit n write enabled - -Units can also be REMOVEd or ADDed to the configuration. - -The RP15 implements these registers: - - name size comments - - STA 18 status A - STB 18 status B - DA 18 disk address - MA 18 current memory address - WC 18 word count - INT 1 interrupt pending flag - BUSY 1 control busy 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 - -8.4 Type 24 Serial Drum (DRM) - -The serial drum (DRM) implements these registers: - - name size comments - - DA 9 drum address (sector number) - MA 15 current memory address - INT 1 interrupt pending flag - DONE 1 device done flag - ERR 1 error flag - WLK 32 write lock switches - TIME 24 rotational latency, per word - 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 - -Drum data files are buffered in memory; therefore, end of file and OS -I/O errors cannot occur. - -8.5 RF09/RF15/RS09 Fixed Head Disk (RF) - -The RF09/RF15 implements these registers: - - name size comments - - STA 18 status - DA 21 current disk address - MA 18 memory address (in memory) - WC 18 word count (in memory) - BUF 18 data buffer (diagnostic only) - INT 1 interrupt pending flag - WLK0..7 16 write lock switches for disks 0..7 - TIME 24 rotational delay, per word - BURST 1 burst flag - STOP_IOE 1 stop on I/O error - -The RF09/RF15 is a three-cycle data break device. If BURST = 0, word -transfers are scheduled individually; if BURST = 1, the entire transfer -occurs in a single data break. - -Error handling is as follows: - - error STOP_IOE processed as - - not attached 1 report error and stop - 0 disk not ready - -RF15/RF09 data files are buffered in memory; therefore, end of file and OS -I/O errors cannot occur. - -8.6 TC02/TU55 and TC15/TU56 DECtape (DT) - -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 LOCKED set unit n write locked - SET DTn ENABLED set unit n write enabled - -Units can also be REMOVEd or ADDed to the configuration. - -The TC02/TC15 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: - - -f foreign (PDP-8) format - -n native (PDP-9/11/15) 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 - INT 1 interrupt pending flag - ENB 1 interrupt enable flag - DTF 1 DECtape flag - ERF 1 error flag - CA 18 current address (memory location 30) - WC 18 word count (memory location 31) - 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 - POS0..7 31 position, in lines, units 0..7 - STATE0..7 31 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 - -8.7 TC59/TU10 Magnetic Tape (MT) - -Magnetic tape options include the ability to make units write enabled or -or write locked. - - SET MTn LOCKED set unit n write locked - SET MTn ENABLED set unit n write enabled - -Units can also be REMOVEd or ADDed to the configuration. - -The magnetic tape controller implements these registers: - - name size comments - - CMD 18 command - STA 18 main status - MA 18 memory address (in memory) - WC 18 word count (in memory) - INT 1 interrupt pending flag - STOP_IOE 1 stop on I/O error - TIME 24 record delay - UST0..7 24 unit status, units 0..n - POS0..7 31 position, units 0..n - -Error handling is as follows: - - error processed as - - not attached tape not ready - - end of file (read or space) end of physical tape - (write) ignored - - OS I/O error report error and stop - -8.8 Symbolic Display and Input - -The 18b PDP simulators implement symbolic display and input. Display is -controlled by command line switches: - - -a display as ASCII character - -c display as (sixbit) character string - -m display instruction mnemonics - -The PDP-15 also recognizes an additional switch: - - -p display as packed ASCII (five 7b ASCII - characters in two 18b words) - -Input parsing is controlled by the first character typed in or by command -line switches: - - ' or -a ASCII character - " or -c three character sixbit string - alphabetic instruction mnemonic - numeric octal number - -The PDP-15 also recognizes an additional input mode: - - # or -p five character packed ASCII string in - two 18b words - -Instruction input uses standard 18b PDP assembler syntax. There are six -instruction classes: memory reference, EAE, index (PDP-15 only), IOT, -operate, and LAW. - -Memory reference instructions have the format - - memref {I/@} address{,X} - -where I (PDP-4, PDP-7, PDP-9) /@ (PDP-15) signifies indirect reference, -and X signifies indexing (PDP-15 in page mode only). The address is an -octal number in the range 0 - 017777 (PDP-4, PDP-7, PDP-9, and PDP-15 in -bank mode) or 0 - 07777 (PDP-15 in page mode). - -IOT instructions consist of single mnemonics, eg, KRB, TLS. IOT instructions -may be or'd together - - iot iot iot... - -IOT's may also include the number 10, signifying clear the accumulator - - iot 10 - -The simulator does not check the legality of IOT combinations. IOT's for -which there is no opcode may be specified as IOT n, where n is an octal -number in the range 0 - 07777. - -EAE instructions have the format - - eae {+/- shift count} - -EAE instructions may be or'd together - - eae eae eae... - -The simulator does not check the legality of EAE combinations. EAE's for -which there is no opcode may be specified as EAE n, where n is an octal -number in the range 0 - 037777. - -Index instructions (PDP-15 only) have the format - - index {immediate} - -The immediate, if allowed, must be in the range of -0400 to +0377. - -Operate instructions have the format - - opr opr opr... - -The simulator does not check the legality of the proposed combination. The -operands for MUY and DVI must be deposited explicitly. - -Finally, the LAW instruction has the format - - LAW immediate - -where immediate is in the range of 0 to 017777. - -8.8 Character Sets - -The PDP-4's console was an ASR-28 Teletype; its character encoding was -Baudot. The PDP-4's line printer used a modified Hollerith character -set. The PDP-7's and PDP-9's consoles were KSR-33 Teletypes; their -character sets were basically ASCII. The PDP-7's and PDP-9's line -printers used sixbit encoding (ASCII codes 040 - 0137 masked to six -bits). The PDP-15's I/O devices were all ASCII. The following table -provides equivalences between ASCII characters and the PDP-4's I/O devices. -In the console table, FG stands for figures (upper case). - - PDP-4 PDP-4 -ASCII console line printer - -000 - 006 none none -bell FG+024 none -010 - 011 none none -lf 010 none -013 - 014 none none -cr 002 none -016 - 037 none none -space 004 000 -! FG+026 none -" FG+021 none -# FG+005 none -$ FG+062 none -% none none -& FG+013 none -' FG+032 none -( FG+036 057 -) FG+011 055 -* none 072 -+ none 074 -, FG+006 033 -- FG+030 054 -. FG+007 073 -/ FG+027 021 -0 FG+015 020 -1 FG+035 001 -2 FG+031 002 -3 FG+020 003 -4 FG+012 004 -5 FG+001 005 -6 FG+025 006 -7 FG+034 007 -8 FG+014 010 -9 FG+003 011 -: FG+016 none -; FG+017 none -< none 034 -= none 053 -> none 034 -? FG+023 037 -@ none {MID DOT} 040 -A 030 061 -B 023 062 -C 016 063 -D 022 064 -E 020 065 -F 026 066 -G 013 067 -H 005 070 -I 014 071 -J 032 041 -K 036 042 -L 011 043 -M 007 044 -N 006 045 -O 003 046 -P 015 047 -Q 035 050 -R 012 051 -S 024 022 -T 001 023 -U 034 024 -V 017 025 -W 031 026 -X 027 027 -Y 025 030 -Z 021 031 -[ none none -\ none {OVERLINE} 056 -] none none -^ none {UP ARROW} 035 -_ none UC+040 -0140 - 0177 none none - -9. IBM 1401 Features - -The IBM 1401 simulator is configured as follows: - -device simulates -name(s) - -CPU IBM 1401 CPU with 16K of memory -CDR,CDP IBM 1402 card reader/punch -LPT IBM 1403 line printer -INQ IBM 1407 inquiry terminal -MT IBM 729 7-track magnetic tape controller with six drives - -The IBM 1401 simulator implements many unique stop conditions. On almost -any kind of error the simulator stops: - - unimplemented opcode - reference to non-existent memory - reference to non-existent device - no word mark under opcode - invalid A address - invalid B address - invalid instruction length - invalid modifier character - invalid branch address - invalid magtape unit number - invalid magtape record length - write to locked magtape drive - skip to unpunched carriage control tape channel - card reader hopper empty - address register wrap-around - single character A field in MCE - single character B field in MCE - hanging $ in MCE with EPE enabled - I/O check with I/O stop switch set - -The LOAD and DUMP commands are not implemented. - -9.1 CPU - -The CPU options include a number of special features and the size of main -memory. Note that the Modify Address special feature is always included -when memory size is greater than 4K. - - SET CPU XSA enable advanced programming special feature - SET CPU NOXSA disable advanced programming - SET CPU HLE enable high/low/equal special feature - SET CPU NOHLE disable high/low/equal - SET CPU BBE enable branch on bit equal special feature - SET CPU NOBBE disable branch on bit equal - SET CPU MR enable move record special feature - SET CPU NOMR disable move record - SET CPU EPE enable extended print edit special feature - SET CPU NOEPE disable extended print edit - SET CPU 4K set memory size = 4K - SET CPU 8K set memory size = 8K - SET CPU 12K set memory size = 12K - SET CPU 16K set memory size = 16K - -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 7 bit BCD characters, as follows: - - 6 5 4 3 2 1 0 - - word B bit A bit 8 4 2 1 - mark <-- zone --> <-------- digit --------> - -In BCD, the decimal digits 0-9 are (octal) values 012, 001, 002, 003, 004, -005, 006, 007, 010, 011, respectively. Signs are encoded in the zone bits, -with 00, 01, and 11 being positive, and 10 being negative. - -CPU registers include the visible state of the processor. The 1401 has no -interrupt system. - - name size comments - - IS 14 instruction storage address register (PC) - AS 14 A storage address register - BS 14 B storage address register - ASERR 1 AS invalid flag - BSERR 1 BS invalid flag - SSA 1 sense switch A - SSB 1 sense switch B - SSC 1 sense switch C - SSD 1 sense switch D - SSE 1 sense switch E - SSF 1 sense switch F - SSG 1 sense switch G - EQU 1 equal compare indicator - UNEQ 1 unequal compare indicator - HIGH 1 high compare indicator - LOW 1 low compare indicator - OVF 1 overflow indicator - IOCHK 1 I/O check switch - PRCHK 1 process check switch - OLDIS 1 IS prior to last branch - BREAK 17 breakpoint address (1000000 to disable) - WRU 8 interrupt character - -9.2 1402 Card Reader/Punch (CDR, CDP, STKR) - -The IBM 1402 card/reader punch is simulated as three independent devices: -the card reader (CDR), the card punch (CDP), and the reader and punch -stackers (STKR). STRK units 0, 1, 2, and 4 correspond to the reader -normal stacker, reader stacker 1, shared stacker 2/8, and punch stacker -4, respectively. - -The card reader supports the BOOT command. BOOT CDR reads a card image -into locations 1-80, sets a word mark under location 1, clears storage, -and then transfers control to location 1. - -The card reader reads data from disk files, while the punch and stackers -write data to disk files. Cards are simulated as ASCII text lines with -terminating newlines; column binary is not supported. 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 reader/punch registers are: - - device name size comments - - CDR LAST 1 last card indicator - ERR 1 error indicator - S1 1 stacker 1 select flag - S2 1 stacker 2 select flag - POS 31 position - TIME 24 delay window for stacker select - BUF[0:79] 8 reader buffer - - CDP ERR 1 error indicator - S4 1 stacker 4 select flag - S8 1 stacker 8 select flag - - STKR POS0 31 position, normal reader stack - POS1 31 position, reader stacker 1 - POS2 31 position, shared stacker 2/8 - POS4 31 position, punch stacker 4 - -Error handling is as follows: - - device error processed as - - reader end of file if SSA set, set LAST indicator - on next Read, report error and stop - - reader,punch not attached report error and stop - OS I/O error print error message - if IOCHK set, report error and stop - otherwise, set ERR indicator - - stacker not attached ignored - OS I/O error print error message - if IOCHK set, report error and stop - -9.3 1403 Line Printer (LPT) - -The IBM 1403 line printer (LPT) writes its data, converted to ASCII, to -a disk file. The line printer supports three different print character -sets or "chains": - - SET LPT PCF full 64 character chain - SET LPT PCA 48 character business chain - SET LPT PCH 48 character FORTRAN chain - -In addition, 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 - - LINES 8 number of newlines after next print - LFLAG 1 carriage control flag (1 = skip, 0 = space) - CCTP 8 carriage control tape pointer - CCTL 8 carriage control tape length (read only) - ERR 1 error indicator - POS 31 position - CCT[0:131] 32 carriage control tape array - -Error handling is as follows: - - error processed as - - not attached report error and stop - - OS I/O error print error message - if IOCHK set, report error and stop - otherwise, set ERR indicator - -9.4 1407 Inquiry Terminal (INQ) - -The IBM 1407 inquiry terminal (INQ) is a half-duplex console. It polls -the console keyboard periodically for inquiry requests. The inquiry -terminal registers are: - - name size comments - - INQC 7 inquiry request character (initially ESC) - INR 1 inquiry request indicator - INC 1 inquiry cleared indicator - TIME 24 polling interval - -When the 1401 CPU requests input from the keyboard, the message [Enter] -is printed out, followed by a new line. The CPU hangs waiting for input -until either the return/enter key is pressed, or the inquiry request -character is typed in. The latter cancels the type-in and sets INC. - -The inquiry terminal has no errors. - -9.5 729 Magnetic Tape (MT) - -The magnetic tape controller supports six drives, numbered 1 through 6. -Magnetic tape options include the ability to make units write enabled or -or write locked. - - SET MTn LOCKED set unit n write locked - SET MTn ENABLED set unit n write enabled - -Units can also be REMOVEd or ADDed to the configuration. The magnetic -tape simulator supports the BOOT command. BOOT MT reads the first -record off tape, starting at location 1, and then branches to it. - -The magnetic tape controller implements these registers: - - name size comments - - END 1 end of file indicator - ERR 1 error indicator - PAR 1 parity error indicator - POS1..6 31 position, drives 1..6 - -Error handling is as follows: - - error processed as - - not attached report error and stop - - end of file (read or space) end of physical tape - (write) ignored - - OS I/O error print error message - if IOCHK set, report error and stop - otherwise, set ERR indicator - -9.6 Symbolic Display and Input - -The IBM 1401 simulator implements symbolic display and input. Display is -controlled by command line switches: - - -c display as single character - (BCD for CPU and MT, ASCII for others) - -s display as wordmark terminated BCD string - (CPU only) - -m display instruction mnemonics - (CPU only) - -In a CPU character display, word marks are denoted by ~. - -Input parsing is controlled by the first character typed in or by command -line switches: - - ' or " or -c or -s characters (BCD for CPU and MT, ASCII - for others) - alphabetic instruction mnemonic - numeric octal number - -Instruction input is free format, with spaces separating fields. There -are six instruction formats: 1, 2, 4, 5, 7, and 8 characters: - - 1 character opcode - 2 character opcode 'modifier - 4 character opcode address - 5 character opcode address 'modifier - 7 character opcode address address - 8 character opcode address address 'modifier - -Addresses are always decimal, except for special I/O addresses in the A -field, which may be specified as %xy, where x denotes the device and y -the unit number. - -For the CPU, string input may encompass multiple characters. A word mark -is denoted by ~ and must precede the character to be marked. All other -devices can only accept single character input, without word marks. - -9.7 Character Sets - -The IBM 1401 used a 6b character code called BCD (binary coded decimal). -Some of the characters have no equivalent in ASCII and require different -representations: - -BCD ASCII IBM 1401 print -code representation character chains - -00 space -01 1 -02 2 -03 3 -04 4 -05 5 -06 6 -07 7 -10 8 -11 9 -12 0 -13 # = in H chain -14 @ ' in H chain -15 : blank in A, H chains -16 > blank in A, H chains -17 ( tape mark blank in A, H chains -20 ^ alternate blank blank in A, H chains -21 / -22 S -23 T -24 U -25 V -26 W -27 X -30 Y -31 Z -32 ' record mark -33 , -34 % ( in H chain -35 = word mark blank in A, H chains -36 \ blank in A, H chains -37 + blank in A, H chains -40 - -41 J -42 K -43 L -44 M -45 N -46 O -47 P -50 Q -51 R -52 ! -53 $ -54 * -55 ] blank in A, H chains -56 ; blank in A, H chains -57 _ delta blank in A, H chains -60 & -61 A -62 B -63 C -64 D -65 E -66 F -67 G -70 H -71 I -72 ? -73 . -74 ) lozenge -75 [ blank in A, H chains -76 < blank in A, H chains -77 " group mark blank in A, H chains - -10. HP2100 Features - -The HP2100 simulator is configured as follows: - -device simulates -name(s) - -CPU 2116, 2100, or 21MX CPU with 32KW memory -DMA0, DMA1 dual channel DMA controller -PTR,PTP 12597A paper tape reader/punch -TTY 12631C buffered teleprinter -LPT 12653A line printer -CLK 12539A/B/C time base generator -DP 12557A cartridge disk controller with four drives -MT 12559C magnetic tape controller with one drives - -The HP2100 simulator implements several unique stop conditions: - - - decode of an undefined instruction, and STOP_INST is et - - reference to an undefined I/O device, and STOP_DEV is set - - more than INDMAX indirect references are detected during - memory reference address decoding - -The HP2100 loader supports standard absolute binary format. The DUMP -command is not implemented. - -10.1 CPU - -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 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 - -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. - -CPU registers include the visible state of the processor as well as the -control registers for the interrupt system. - - name 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 - OLDP 15 PC prior to last JMP, JSB, or interrupt - BREAK 16 breakpoint address (177777 to disable) - WRU 8 interrupt character - -10.2 DMA Controllers - -The HP2100 includes two DMA channel controllers (DMA0 and DMA1). Each -DMA channel has the following visible state: - - name size comments - - CMD 1 channel enabled - 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 - -10.3 Variable Device Assignments - -On the HP2100, I/O device take their device numbers from the backplane -slot they are plugged into. Thus, device number assignments vary -considerably from system to system, and software package to software -package. The HP2100 simulator supports dynamic device reassignment -with the command: - - SET DEVNO - -This initiates a dialog that displays the current device number and -allows the user to assign a new one: - - Device number: old (cr) - -The new device number must be in the range 010..077 (octal) and must -not be currently assigned to another device. For devices with two -device numbers, only the lower numbered device number can be changed; -the higher is automatically set to the lower + 1. - -10.4 Programmed I/O Devices - -10.4.1 12597A-002 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 copies the -absolute binary loader into memory and starts it running. - -The paper tape reader implements these registers: - - name size comments - - BUF 8 last data item processed - CMD 1 reader enable - CTL 1 device/interrupt enable - FLG 1 device ready - FBF 1 device ready buffer - POS 31 position in the input file - TIME 24 time from I/O initiation to interrupt - STOP_IOE 1 stop on I/O error - DEVNO 6 current device number (read only) - -Error handling is as follows: - - error STOP_IOE processed as - - not attached 1 report error and stop - 0 out of tape - - end of file 1 report error and stop - 0 out of tape or paper - - OS I/O error x report error and stop - -10.4.2 12597A-005 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. -Thus, by changing POS, the user can backspace or advance the punch. - -The paper tape punch implements these registers: - - name size comments - - BUF 8 last data item processed - CMD 1 punch enable - CTL 1 device/interrupt enable - FLG 1 device ready - FBF 1 device ready buffer - POS 31 position in the output file - TIME 24 time from I/O initiation to interrupt - STOP_IOE 1 stop on I/O error - DEVNO 6 current device number (read only) - -Error handling is as follows: - - error STOP_IOE processed as - - not attached 1 report error and stop - 0 out of tape - - OS I/O error x report error and stop - -10.4.3 12631C Buffered Teleprinter (TTY) - -The console teleprinter 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. - -The terminal implements these registers: - - name size comments - - BUF 8 last data item processed - MODE 16 mode - CTL 1 device/interrupt enable - FLG 1 device ready - FBF 1 device ready buffer - KPOS 31 number of characters input - KTIME 24 keyboard polling interval - TPOS 31 number of characters printed - TTIME 24 time from I/O initiation to interrupt - PPOS 31 position in the punch output file - STOP_IOE 1 punch stop on I/O error - DEVNO 6 current device number (read only) - -Error handling for the punch is as follows: - - error STOP_IOE processed as - - not attached 1 report error and stop - 0 out of tape - - OS I/O error x report error and stop - -10.4.4 12653A 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, -by changing POS, the user can backspace or advance the printer. - -The line printer implements these registers: - - name size comments - - BUF 8 last data item processed - CMD 1 printer enable - CTL 1 device/interrupt enable - FLG 1 device ready - FBF 1 device ready buffer - POS 31 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 - DEVNO 6 current device number (read only) - -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 - -10.4.5 12539A/B/C Time Base Generator (CLK) - -The time base generator (CLK) implements these registers: - - name size comments - - SEL 3 time base select - CTL 1 device/interrupt enable - FLG 1 device ready - FBF 1 device ready buffer - ERR 1 error flag - TIME0..TIME7 31 clock intervals, select = 0..7 - DEVNO 6 current device number (read only) - -10.5 12557A Cartridge Disk (DP) - -The 12557A cartridge disk 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 REMOVEd or ADDed to the configuration. - -The data channel implements these registers: - - name size comments - - IBUF 16 input buffer - OBUF 16 output buffer - BPTR 7 sector buffer pointer - CMD 1 channel enable - CTL 1 interrupt enable - FLG 1 channel ready - FBF 1 channel ready buffer - DEVNO 6 current device number (read only) - -The device controller implements these registers: - - name size comments - - 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 - STIME 24 seek delay time, per cylinder - XTIME 24 interword transfer time - STA0 16 drive 0 status - STA1 16 drive 1 status - STA2 16 drive 2 status - STA3 16 drive 3 status - DEVNO 6 current device number (read only) - -Error handling is as follows: - - error processed as - - not attached disk not ready - - end of file assume rest of disk is zero - - OS I/O error report error and stop - -10.6 12559C Magnetic Tape (MT) - -Magnetic tape options include the ability to make the unit write enabled -or write locked. - - SET MT LOCKED set unit write locked - SET MT ENABLED 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 data channel implements these registers: - - name size comments - - FLG 1 channel ready - BPTR 16 buffer pointer (reads and writes) - BMAX 16 buffer size (writes) - DEVNO 6 current device number (read only) - -The device controller implements these registers: - - name size comments - - FNC 8 current function - STA 9 tape status - BUF 8 buffer - BUSY 3 busy (unit #, + 1, of active unit) - CTL 1 interrupt enabled - FLG 1 controller ready - FBF 1 controller ready buffer - DTF 1 data transfer flop - FSVC 1 first service flop - POS 31 magtape position - CTIME 24 command delay time - XTIME 24 interword transfer delay time - STOP_IOE 1 stop on I/O error - DEVNO 6 current device number (read only) - -Error handling is as follows: - - error processed as - - not attached tape not ready - - end of file (read or space) end of physical tape - (write) ignored - - OS I/O error report error and stop - -10.7 Symbolic Display and Input - -The HP2100 simulator implements symbolic display and input. Display is -controlled by command line switches: - - -a display as ASCII character - -c display as two character string - -m display instruction mnemonics - -Input parsing is controlled by the first character typed in or by command -line switches: - - ' or -a ASCII character - " or -c two character sixbit string - alphabetic instruction mnemonic - numeric octal number - -Instruction input uses standard HP2100 assembler syntax. There are seven -instruction classes: memory reference, I/O, shift, alter skip, extended -shift, extended memory reference, extended two address reference. - -Memory reference instructions have the format - - memref {C/Z} address{,I} - -where I signifies indirect, C a current page reference, and Z a zero page -reference. The address is an octal number in the range 0 - 077777; if C or -Z is specified, the address is a page offset in the range 0 - 01777. Normally, -C is not needed; the simulator figures out from the address what mode to use. -However, when referencing memory outside the CPU (eg, disks), there is no -valid PC, and C must be used to specify current page addressing. - -IOT instructions have the format - - io device{,C} - -where C signifies that the device flag is to be cleared. The device is an -octal number in the range 0 - 77. - -Shift and alter/skip instructions have the format - - sub-op sub-op sub-op... - -The simulator checks that the combination of sub-opcodes is legal. - -Extended shift instructions have the format - - extshift count - -where count is an octal number in the range 1 - 020. - -Extended memory reference instructions have the format - - extmemref address{,I} - -where I signifies indirect addressing. The address is an octal number in -the range 0 - 077777. - -Extended two address instructions have the format - - ext2addr addr1{,I},addr2{,I} - -where I signifies indirect addressing. Both address 1 and address 2 are -octal numbers in the range 0 - 077777. - -11. Interdata 4 Features - -The Interdata 4 simulator is not fully debugged. Lack of documentation -and software makes checkout very difficult. The simulator is included in -the hopes that a fellow enthusiast may be able to provide software or -additional documentation to facilitate further debug. - -The Interdata 4 simulator is configured as follows: - -device simulates -name(s) - -CPU Interdata 4 CPU with 64KB memory -PT paper tape reader/punch -TT console terminal - -The Interdata 4 simulator implements one unique stop condition: - - - decode of an undefined instruction, and STOP_INST is set - -The LOAD and DUMP command are not implemented. - -11.1 CPU - -The only CPU options are memory size: - - SET CPU 8K set memory size = 8KB - SET CPU 16K set memory size = 16KB - SET CPU 24K set memory size = 24KB - SET CPU 32K set memory size = 32KB - SET CPU 48K set memory size = 48KB - SET CPU 64K set memory size = 64KB - -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 64KB. - -CPU registers include the visible state of the processor as well as the -control registers for the interrupt system. - - name size comments - - PC 16 program counter - R0..RF 16 general registers - F0, F2..FE 32 floating point registers - PSW 16 processor status word - CC 4 condition codes, PSW<12:15> - SR 16 switch register - DR 16 display register low 16 bits - DR1 16 display register high 16 bits - DRMOD 1 display mode - DRPOS 2 display pointer position - SRPOS 1 switch pointer position - IRQ0..IRQ7 32 interrupt requests - IEN0..IEN7 32 interrupt enables - STOP_INST 1 stop on undefined instruction - OLDPC 16 PC prior to last branch or interrupt - BREAK 17 breakpoint address (377777 to disable) - WRU 8 interrupt character - -11.2 Paper Tape Reader/Punch (PT) - -The paper tape reader and punch (PT units 0 and 1) read data from or -write data to disk files. The RPOS and PPOS registers specify the -number of the next data item to be read and written, respectively. -Thus, by changing RPOS or PPOS, the user can backspace or advance -these devices. - -The paper tape reader supports the BOOT command. BOOT PTR copies the -so-called '50 loader' into memory and starts it running. - -The paper tape controller implements these registers: - - name size comments - - RBUF 8 reader buffer - RPOS 31 reader position in the input file - RTIME 24 time from reader start to interrupt - RSTOP_IOE 1 reader stop on I/O error - PBUF 8 punch buffer - PPOS 31 punch position in the output file - PTIME 24 time from punch start to interrupt - PSTOP_IOE 1 punch stop on I/O error - IREQ 1 paper tape interrupt request - IENB 1 paper tape interrupt enable - RUN 1 paper tape running - SLEW 1 paper tape reader slew mode - BUSY 1 paper tape busy - RW 1 paper tape read/write mode - -Error handling is as follows: - - type error STOP_IOE processed as - - in,out not attached 1 report error and stop - 0 out of tape - - in end of file 1 report error and stop - 0 out of tape - - in,out OS I/O error x report error and stop - -11.3 Teletype (TT) - -The teletype keyboard reads from the console keyboard; the teletype -printer writes to the simulator console window. The keyboard has -one option, UC; when set, it automatically converts lower case -input to upper case. This is on by default. - - name size comments - - KBUF 8 keyboard buffer - KPOS 31 number of characters output - KTIME 24 keyboard polling interval - TBUF 8 output buffer - TPOS 31 number of characters output - TTIME 24 time from output start to interrupt - IREQ 1 teletype interrupt request - IENB 1 teletype interrupt enable - HDPX 1 teletype half-duplex - BUSY 1 teletype busy - RW 1 teletype read/write mode - -11.4 Symbolic Display and Input - -The Interdata 4 simulator implements symbolic display and input. Display is -controlled by command line switches: - - -a display as ASCII character - -c display as two character string - -m display instruction mnemonics - -Input parsing is controlled by the first character typed in or by command -line switches: - - ' or -a ASCII character - " or -c two character sixbit string - alphabetic instruction mnemonic - numeric octal number - -Instruction input uses standard Interdata 4 assembler syntax. There are -four instruction classes: register, memory, register-register, register- -memory. - -Register instructions have the format - - rop regnum - -where the register number is a hex digit, optionally preceded by R, -between 0 and F. - -Memory instructions have the format - - mop address{(index)} - -where address is a hex number between 0 and 0xFFFF, and the index register -is a hex digit, optinally preceded by R, between 0 and F. - -Register-register instructions have the format - - rrop regnum,regnum - -where the register numbers are hex digits, optionally preceded by R, -between 1 and F. - -Register-memory instructions have the format - - rmop regnum,address{(index)} - -where the register number is a hex digit, optionally preceded by R, -between 0 and F, the address is a hex number between 0 and 0xFFFF, and -the index register is a hex digit, optionally preceded by R, between -1 and F. - -12. PDP-10 Features - -The PDP-10 simulator is configured as follows: - -device simulates -name(s) - -CPU KS10 CPU with 1MW of memory -PAG paging unit (translation maps) -UBA Unibus adapters (translation maps) -FE console -TIM timer -PTR,PTP PC11 paper tape reader/punch -DZ DZ11 8-line terminal multiplexor -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 DISABLEd. The DZ11 can also be DISABLEd. - -The PDP-10 simulator implements several unique stop condition: - - - illegal instruction (000) in kernel mode - - indirect addressing nesting exceeds limit - - execute chaining exceeds limit - - page fail or other error in interrupt sequence - - illegal instruction in interrupt sequence - - invalid vector pointer in interrupt sequence - - invalid Unibus adapter number - - non-existent exec or user page table address - -The PDP-10 loader supports RIM10B format paper tapes, SAV binary files, and -EXE binary files. LOAD switches -r, -s, -e specify RIM10, SAV, EXE format, -respectively. If no switch is specified, the LOAD command checks the file -extension; .RIM, .SAV, .EXE specify RIM10, SAV, EXE format, respectively. -If no switch specified, and no extension matches, the LOAD command checks -the file format to try to determine the file type. - -12.1 CPU - -The CPU options allow the user to specify standard microcode, standard -microcode with a bug fix for a boostrap problem in TOPS-20 V4.1, or ITS -microcode - - SET CPU STANDARD Standard microcode - SET CPU TOPS20V41 Standard microcode with TOPS-20 V4.1 bug fix - SET CPU ITS ITS compatible microcode - -CPU registers include the visible state of the processor as well as the -control registers for the interrupt system. - - name size comments - - PC 18 program counter - FLAGS 18 processor flags (<13:17> unused) - AC0..AC17 36 accumulators - IR 36 instruction register - EBR 18 executive base register - PGON 1 paging enabled flag - T20P 1 TOPS-20 paging - UBR 18 user base register - CURAC 3 current AC block - PRVAC 3 previous AC block - SPT 36 shared pointer table - CST 36 core status table - PUR 36 process update register - CSTM 36 CST mask - HSB 18 halt status block address - DBR1 18 descriptor base register 1 (ITS) - DBR2 18 descriptor base register 2 (ITS) - DBR3 18 descriptor base register 3 (ITS) - DBR4 18 descriptor base register 4 (ITS) - PIENB 7 PI levels enabled - PIACT 7 PI levels active - PIPRQ 7 PI levels with program requests - PIIOQ 7 PI levels with IO requests - PIAPR 7 PI levels with APR requests - APRENB 8 APR flags enabled - APRFLG 8 APR flags active - APRLVL 3 PI level for APR interrupt - IND_MAX 8 indirect address nesting limit - XCT_MAX 8 execute chaining limit - OLDPC 18 PC prior to last transfer instruction - BREAK 19 breakpoint address (1777777 to disable) - WRU 8 interrupt character - REG[0:127] 36 fast memory blocks - -12.2 Pager - -The pager contains the page maps for executive and user mode. The -executive page map is the memory space for unit 0, the user page map the -memory space for unit 1. A page map entry is 32 bits wide and has the -following format: - - bit content - --- ------- - 31 page is writeable - 30 entry is valid - 29:19 mbz - 18:9 physical page base address - 8:0 mbz - -The pager has no registers. - -12.3 Unibus Adapters - -The Unibus adapters link the system I/O devices to the CPU. Unibus -adapter 1 (UBA1) is unit 0, and Unibus adapter 3 is unit 1. The -adapter's Unibus map is the memory space of the corresponding unit. - -The Unibus Adapter has the following registers: - - name size comments - - INTREQ 32 interrupt requests - UB1CS 16 Unibus adapter 1 control/status - UB3CS 16 Unibus adapter 3 control/status - -12.4 Front End (FE) - -The front end is the system console. The keyboard input is unit 0, -the console output is unit 1. It supports two options: - - SET FE STOP halts the PDP-10 operating system - SET FE CTLC simulates typing ^C (for Windoze) - -The front end has the following registers: - - name size comments - - IBUF 8 input buffer - ICOUNT 31 count of input characters - ITIME 24 keyboard polling interval - OBUF 8 output buffer - OCOUNT 31 count of output characters - OTIME 24 console output response time - -12.5 Timer (TIM) - -The timer (TIM) implements the system timer, the interval timer, and -the time of day clock used to get the date and time at system startup. -Because most PDP-10 software is not Y2K compliant, the timer implements -one option - - SET TIM NOY2K software not Y2K compliant, limit time of - day clock to 1999 (default) - SET TIM Y2K software is Y2K compliant - -The timer has the following registers: - - name size comments - - TIMBASE 59 time base (double precision) - TTG 36 time to go (remaining time) for interval - PERIOD 36 reset value for interval - QUANT 36 quantum timer (ITS only) - TIME 24 tick delay - DIAG 1 use fixed tick delay instead of autocalibration - -Unless the DIAG flag is set, the timer autocalibrates; the tick delay -is adjusted up or down so that the time base tracks actual elapsed time. -This may cause time-dependent diagnostics to report errors. - -12.6 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, -by changing POS, the user can backspace or advance the reader. - -The paper tape reader implements these registers: - - name size comments - - BUF 8 last data item processed - CSR 16 control/status register - INT 1 interrupt pending flag - ERR 1 error flag (CSR<15>) - BUSY 1 busy flag (CSR<11>) - DONE 1 device done flag (CSR<7>) - IE 1 interrupt enable flag (CSR<6>) - POS 31 position in the input file - TIME 24 time from I/O initiation to interrupt - 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 out of tape - - end of file 1 report error and stop - 0 out of tape - - OS I/O error x report error and stop - - -12.7 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. -Thus, by by changing POS, the user can backspace or advance the punch. - -The paper tape punch implements these registers: - - name size comments - - BUF 8 last data item processed - CSR 16 control/status register - 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>) - POS 31 position in the input or output file - TIME 24 time from I/O initiation to interrupt - 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 out of tape - - OS I/O error x report error and stop - -12.8 DZ11 Terminal Multiplexor (DZ) - -The DZ11 is an 8-line terminal multiplexor. 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: - - ATTACH {-am} DZ (cr) -- set up listening port - -where port is a decimal number between 1 and 65535 that is not being used -for other TCP/IP activities. The optional switch -m turns on the DZ11's -modem controls; the optional switch -a turns on active disconnects -(disconnect session if computer clears Data Terminal Ready). - - - ATTACH {-m} DZ (cr) -- set up listening port - -where port is a decimal number between 1 and 65535 that is not being used -for other TCP/IP activities. The optional switch -m turns on the DZ11's -modem controls; the optional switch -a turns on active disconnects -(disconnect session if computer clears Data Terminal Ready). - -Once the DZ is attached and the simulator is running, the DZ will listen -for connections on the specified port. It assumes that the incoming -connections are Telnet connections. The connection remains open until -disconnected either by the simulated program or by the Telnet client. - -The SHOW DZ command displays the current connections to the DZ. - -The DZ11 implements these registers: - - name size comments - - CSR 16 control/status register - RBUF 16 receive buffer - LPR 16 line parameter register - TCR 16 transmission control register - MSR 16 modem status register - TDR 16 transmit data register - SAENB 1 silo alarm enabled - MDMTCL 1 modem control enabled - AUTODS 1 autodisconnect enabled - RPOS0..7 32 count of characters received - TPOS0..7 32 count of characters transmitted - -The DZ11 does not support save and restore. All open connections are -lost when the simulator shuts down or the DZ is detached. - -12.9 RH11 Adapter, RM02/03/05/80, RP04/05/06/07 drives (RP) - -The RP controller implements the Massbus 18b (RH11) 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 size to one of seven disk types, or autosize: - - SET RPn LOCKED set unit n write locked - SET RPn ENABLED set unit n write enabled - SET RPn RM03 set size to RM03 - SET RPn RM05 set size to RM05 - SET RPn RM80 set size to RM80 - SET RPn RP04 set size to RP04 - SET RPn RP06 set size to RP06 - SET RPn RP07 set size to RP07 - SET RPn AUTOSIZE set size based on file size at attach - -The size options can be used only when a unit is not attached to a file. -Note that TOPS-10 V7.03 only supported the RP06 and RM03; V7.04 added -support for the RP07. Units can be REMOVEd or ADDed to the configuration. - -The RP controller implements these registers: - - name size comments - - RPCS1 16 control/status 1 - RPWC 16 word count - RPBA 16 bus address - RPDA 16 desired surface, sector - RPCS2 16 control/status 2 - RPOF 16 offset - RPDC 8 desired cylinder - RPER2 16 error status 2 - RPER3 16 error status 3 - RPEC1 16 ECC syndrome 1 - RPEC2 16 ECC syndrome 2 - RPMR 16 maintenance register - RPDB 16 data buffer - RPIFF 1 transfer complete interrupt request flop - INT 1 interrupt pending flag - SC 1 special condition (CSR1<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 - RPDS0..7 16 drive status, drives 0-7 - RPDE0..7 16 drive error, drives 0-7 - 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 - -12.10 RH11 Adapter, TM02 Formatter, TU45 Magnetic Tape (TU) - -The magnetic tape simulator simulates an RH11 Massbus adapter with one -TM02 formatter and up to eight TU45 drives. Magnetic tape options include -the ability to make units write enabled or locked. - - SET TUn LOCKED set unit n write locked - SET TUn ENABLED set unit n write enabled - -Units can also be REMOVEd or ADDed to the configuration. - -The magnetic tape controller implements these registers: - - name size comments - - MTCS1 16 control/status 1 - MTBA 16 memory address - MTWC 16 word count - MTFC 16 frame count - MTCS2 16 control/status 2 - MTFS 16 formatter status - MTER 16 error status - MTCC 16 check character - MTDB 16 data buffer - MTMR 16 maintenance register - MTTC 16 tape control register - INT 1 interrupt pending flag - DONE 1 device done flag - IE 1 interrupt enable flag - STOP_IOE 1 stop on I/O error - TIME 24 delay - UST0..7 16 unit status, units 0..n - POS0..7 31 position, units 0..n - -Error handling is as follows: - - error processed as - - not attached tape not ready - - end of file (read or space) end of physical tape - (write) ignored - - OS I/O error report error and stop - -12.11 LP20 DMA Line Printer (LP20) - -The LP20 is a DMA-based line printer controller. There is one -line printer option to clear the vertical forms unit (VFU). - - SET LP20 VFUCLEAR clear the vertical forms unit - -The LP20 implements these registers: - - name size comments - - LPCSA 16 control/status register A - LPCSB 16 control/status register B - LPBA 16 bus address register - LPBC 12 byte count register - LPPAGC 12 page count register - LPRDAT 12 RAM data register - LPCBUF 8 character buffer register - LPCOLC 8 column counter register - LPPDAT 8 printer data register - LPCSUM 8 checksum register - DVPTR 7 vertical forms unit pointer - DVLNT 7 vertical forms unit length - INT 1 interrupt request - ERR 1 error flag - DONE 1 done flag - IE 1 interrupt enable flag - POS 31 position in output file - TIME 24 response time - STOP_IOE 1 stop on I/O error - TXRAM[0:255] 12 translation RAM - DAVFU[0:142] 12 vertical forms unit array - -Error handling is as follows: - - error STOP_IOE processed as - - not attached 1 report error and stop - 0 out of paper - - OS I/O error x report error and stop - -12.12 Symbolic Display and Input - -The PDP-10 simulator implements symbolic display and input. Display is -controlled by command line switches: - - -a display as ASCII character - -c display as (sixbit) character string - -p display as packed (seven bit) string - -m display instruction mnemonics - -v interpret address as virtual - -e force executive mode - -u force user mode - -Input parsing is controlled by the first character typed in or by command -line switches: - - ' or -a ASCII character - " or -c sixbit string - # or -p packed seven bit string - alphabetic instruction mnemonic - numeric octal number - -Instruction input uses standard PDP-10 assembler syntax. There are three -instruction classes: memory reference, memory reference with AC, and I/O. - -Memory reference instructions have the format - - memref {@}address{(index)} - -memory reference with AC instructions have the format - - memac ac,{@}address{(index)} - -and I/O instructions have the format - - io device,{@}address{(index)} - -where @ signifies indirect. The address is a signed octal number in the -range 0 - 0777777. The ac and index are unsigned octal numbers in the -range 0-17. The device is either a recognized device mnemonic (APR, PI, -TIM) or an octal number in the range 0 - 0177. - -The simulator recognizes the standard MACRO alternate mnemonics (CLEAR -for SETZ, OR for IORI), the individual definitions for JRST and JFCL -variants, and the extended instruction mnemonics. - -13. H316/H516 Features - -The Honeywell 316/516 simulator is configured as follows: - -device simulates -name(s) - -CPU H316/H516 CPU with 16/32KW memory -PTR 316/516-50 paper tape reader -PTP 316/516-52 paper tape punch -TTY 316/516-33 console terminal -CLK 316/516-12 real time clock -LPT 316/516 line printer - -The H316/H516 simulator implements several unique stop conditions: - - - decode of an undefined instruction, and STOP_INST is et - - reference to an undefined I/O device, and STOP_DEV is set - - more than INDMAX indirect references are detected during - memory reference address decoding - -The H316/H516 loader is not implemented. - -13.1 CPU - -CPU options include choice of instruction set and memory size. - - SET CPU HSA high speed arithmetic instructions - SET CPU NOHSA no high speed arithmetic instructions - SET CPU 4K set memory size = 4K - SET CPU 8K set memory size = 8K - SET CPU 12K set memory size = 12K - SET CPU 16K set memory size = 16K - SET CPU 24K set memory size = 24K - SET CPU 32K set memory size = 32K - -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. - -CPU registers include the visible state of the processor as well as the -control registers for the interrupt system. - - name size comments - - P 15 program counter - A 16 A register - B 16 B register - X 16 index register - SC 16 shift count - C 1 carry flag - EXT 1 extend flag - PME 1 previous mode extend flag - EXT_OFF 1 extend off pending flag - DP 1 double precision flag - SS1..4 1 sense switches 1..4 - ION 1 interrupts enabled - INODEF 1 interrupts not deferred - INTREQ 16 interrupt requests - DEVRDY 16 device ready flags (read only) - DEVENB 16 device interrupt enable flags (read only) - STOP_INST 1 stop on undefined instruction - STOP_DEV 1 stop on undefined device - INDMAX 1 indirect address limit - OLDP 15 PC prior to last JMP, JSB, or interrupt - BREAK 16 breakpoint address (177777 to disable) - WRU 8 interrupt character - -13.2 Programmed I/O Devices - -13.2.1 316/516-50 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 copies the -absolute binary loader into memory and starts it running. - -The paper tape reader implements these registers: - - name size comments - - BUF 8 last data item processed - INTREQ 1 device interrupt request - READY 1 device ready - ENABLE 1 device interrupts enabled - POS 31 position in the input or output file - TIME 24 time from I/O initiation to interrupt - 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 out of tape - - end of file 1 report error and stop - 0 out of tape or paper - - OS I/O error x report error and stop - -13.2.2 316/516-52 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. -Thus, by changing POS, the user can backspace or advance the punch. - -The paper tape punch implements these registers: - - name size comments - - BUF 8 last data item processed - INTREQ 1 device interrupt request - READY 1 device ready - ENABLE 1 device interrupts enabled - POWER 1 device powered up - POS 31 position in the input or output file - TIME 24 time from I/O initiation to interrupt - PWRTIME 24 time from I/O request to power up - 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 out of tape - - OS I/O error x report error and stop - -13.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 terminal these registers: - - name size comments - - BUF 8 last data item processed - MODE 1 read/write mode - INTREQ 1 device interrupt request - READY 1 device ready - ENABLE 1 device interrupts enabled - KPOS 31 number of characters input - KTIME 24 keyboard polling interval - TPOS 31 number of characters output - TTIME 24 time from I/O initiation to interrupt - -13.2.4 316/516-12 Real Time Clock (CLK) - -The real time clock (CLK) implements these registers: - - name size comments - - INTREQ 1 device interrupt request - READY 1 device ready - ENABLE 1 device interrupts enabled - TIME 24 clock interval - -13.2.5 316/5116 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, -by changing POS, the user can backspace or advance the printer. - -The line printer implements these registers: - - name size comments - - WDPOS 6 word position in current scan - DRPOS 6 drum position - CRPOS 1 carriage position - XFER 1 transfer ready flag - PRDN 1 print done flag - INTREQ 1 device interrupt request - ENABLE 1 device interrupt enable - SVCST 2 service state - SVCCH 2 service channel - BUF 8 buffer - POS 31 number of characters output - XTIME 24 delay between transfers - ETIME 24 delay at end of scan - PTIME 24 delay for shuttle/line advance - 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 out of paper - - OS I/O error x report error and stop - -13.3 Symbolic Display and Input - -The H316/H516 simulator implements symbolic display and input. Display is -controlled by command line switches: - - -a display as ASCII character - -c display as two character string - -m display instruction mnemonics - -Input parsing is controlled by the first character typed in or by command -line switches: - - ' or -a ASCII character - " or -c two character sixbit string - alphabetic instruction mnemonic - numeric octal number - -Instruction input uses standard H316/H516 assembler syntax. There are six -instruction classes: memory reference, I/O, control, shift, skip, and -operate. - -Memory reference instructions have the format - - memref{*} {C/Z} address{,1} - -where * signifies indirect, C a current sector reference, Z a sector zero -reference, and 1 indexed. The address is an octal number in the range 0 - -077777; if C or Z is specified, the address is a page offset in the range -0 - 0777. Normally, C is not needed; the simulator figures out from the -address what mode to use. However, when referencing memory outside the CPU -(eg, disks), there is no valid PC, and C must be used to specify current -sector addressing. - -I/O instructions have the format - - io pulse+device - -The pulse+device is an octal number in the range 0 - 01777. - -Control and operate instructions consist of a single opcode - - opcode - -Shift instructions have the format - - shift n - -where n is an octal number in the range 0-77. - -Skip instructions have the format - - sub-op sub-op sub-op... - -The simulator checks that the combination of sub-opcodes is legal. - Appendix 1: File Representations All file representations are little endian. On big endian hosts, the @@ -5154,7 +605,27 @@ legend: y = runs operating system or sample program n = untested - = not applicable -Revision History (since Rev 1.1) +Revision History (covering Rev 1.1 to 2.7) + +Starting with Rev 2.7, detailed revision histories can be found +in file sim_rev.c. + +Rev 2.8, Dec, 01 + Added DO command + Added general breakpoint facility + Added extended SET/SHOW capability + Replaced ADD/REMOVE with SET ONLINE/OFFLINE + Added global register name recognition + Added unit-based register arrays + Added VAX simulator + Added SDS940 simulator + Added Charles Owen's System 3 simulator + Added PDP-11 I/O bus map + Added PDP-11/VAX RQDX3 + Added PDP-8 RL8A + Revised 18b PDP interrupt structure + Revised directory and documentation structure + Added support for MINGW environment Rev 2.7, Sep, 01 Added DZ11 (from Thord Nilson and Art Krewat) @@ -5395,13 +866,14 @@ would like to acknowledge the help of the following people, all of whom donated their time and talent to this "computer archaeology" project: Bill Ackerman PDP-1 consulting +Alan Bawden ITS consulting Winfried Bergmann Linux port testing Phil Budne Solaris port testing Max Burnet PDP information, documentation, and software James Carpenter LINUX port testing Chip Charlot PDP-11 RT-11, RSTS/E, RSX-11M legal permissions Louis Chrétien Macintosh porting -Dave Conroy HP 21xx documentation +Dave Conroy HP 21xx documentation, PDP-10, PDP-18b debugging L Peter Deutsch PDP-1 LISP software Ethan Dicks PDP-11 2.9 BSD debugging Carl Friend Nova and Interdata documentation, and RDOS software @@ -5413,14 +885,15 @@ Gordon Greene PDP-1 LISP machine readable source Lynne Grettum PDP-11 RT-11, RSTS/E, RSX-11M legal permissions Franc Grootjen PDP-11 2.11 BSD debugging Doug Gwyn Portability debugging -Kevin Handy TS11/TSV05 documentation -Ken Harrenstein PDP-10 simulator +Kevin Handy TS11/TSV05 documentation, make file +Ken Harrenstein KLH PDP-10 simulator Bill Haygood PDP-8 information, simulator, and software -Wolfgang Helbig DZ11 simulator implementation +Wolfgang Helbig DZ11 implementation Mark Hittinger PDP-10 debugging Jay Jaeger IBM 1401 information Doug Jones PDP-8 information, simulator, and software -Al Kossow HP 21xx, Varian 620, TI 990, DEC documentation and software +Al Kossow HP 21xx, Varian 620, TI 990, Interdata, DEC + documentation and software Arthur Krewat DZ11 update for the PDP-10 Mirian Crzig Lennox ITS and DZ11 debugging Don Lewine Nova documentation and legal permissions @@ -5432,23 +905,25 @@ Jeff Moffatt HP 2100 information, documentation, and software Alec Muffett Solaris port testing Thord Nilson DZ11 implementation Charles Owen Nova moving head disk debugging, Altair simulator, + Eclipse simulator, IBM System 3 simulator, IBM 1401 diagnostics, debugging, and magtape boot +Sergio Pedraja MINGW environment debugging Derek Peschel PDP-10 debugging Paul Pierce IBM 1401 diagnostics, media recovery -Hans Pufal PDP-10 debugging +Hans Pufal PDP-10 debugging, PDP-15 bootstrap Bruce Ray Software, documentation, bug fixes, and new devices - for the Nova -Craig St Clair PDP documentation + for the Nova, OS/2 porting +Craig St Clair DEC documentation Richard Schedler Public repository maintenance Peter Schorn Macintosh porting Stephen Schultz PDP-11 2.11 BSD debugging Olaf Seibert NetBSD port testing Brian & Barry Silverman PDP-1 simulator and software Tim Shoppa Nova documentation, RDOS software, PDP-10 and PDP-11 - software archive + software archive, hosting for SIMH site Michael Somos PDP-1 debugging Hans-Michael Stahl OS/2 port testing, TERMIOS implementation -Tim Stark PDP-10 simulator +Tim Stark TS10 PDP-10 simulator Larry Stewart Initial suggestion for the project Bill Strecker Permission to revert copyrights Chris Suddick PDP-11 floating point debugging diff --git a/simh_swre.txt b/simh_swre.txt index d3cb2342..8d322072 100644 --- a/simh_swre.txt +++ b/simh_swre.txt @@ -256,9 +256,9 @@ RT-11 is contained in a single RL02 disk image. To boot and run RT-11: sim> boot rl0 This is a full RT-11 distribution kit. It expects the user to copy the -distribution pack and generate a new system. This requires mounting -blank packs on RL1. When a blank pack is attached to the simulator, -a bad block table must be created with the SET BADBLOCK command. +distribution pack and generate a new system. This requires mounting a +blank pack on RL1. When a blank pack is attached to the simulator, a +bad block table must be created with the SET BADBLOCK command. 3. Nova RDOS @@ -307,7 +307,7 @@ To load and run SIM8: sim> run AC/ 0000 -6. PDP-15 +6. PDP-9/PDP-15 6.1 FOCAL @@ -328,6 +328,10 @@ 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: + + sim> d extm_init 1 + - Load the paper-tape bootstrap into upper memory: sim> load dec-15u.rim 77637 @@ -372,9 +376,6 @@ execution capabilities. To load and run ADSS/KM-15: 6.3 Advanced Software System/Foreground Background -Foreground/Background System ----------------------------- - Note: your environment must have a functioning second Teletype; that is, you cannot at present run Foreground/Background if your host system is VMS or OS/2. @@ -589,58 +590,8 @@ To load and run BASIC: RUN 1.41421 -9. PDP-9/PDP-15 Advanced Software System/Keyboard Monitor -The Advanced Software System was a family of operating systems for the -PDP-9 and PDP-15, ranging from a paper-tape basic system, through the -DECtape or disk based Keyboard Monitor, through the Foreground/Background -Monitor, to DOS-15. To run ADSS/KM from simulated DECtape: - -- On the PDP-9 (only), initialize extend mode to on: - - sim> d extm_init 1 - -- Load the paper-tape bootstrap into upper memory: - - sim> load dec-15u.rim 77637 - -- Verify that the bootstrap loaded correctly: - - sim> ex pc - PC: 077646 - -- Mount the Advanced Software System DECtape image on DECtape unit 0: - - sim> attach dt adss15_32k.dtp - -- Run the bootstrap: - - sim> run - -- The DECtape will boot and print out - - KMS9-15 V5B000 - $ - - and is now ready for commands. Recognized commands include: - - D list system device directory - I list available commands - R list device assignments - SCOM list systems communication region - -- To run Focal, assign unused DAT slot 10 and then load Focal - - $A LPA0 10 - $GLOAD - LOADER V5B000 - >_FOCAL - FOCAL V9A - *TYPE 2+2,! - 4.0000 - * - -10. PDP-10 TOPS-10 7.03, TOPS-20 V4.1 +9. PDP-10 TOPS-10 7.03, TOPS-20 V4.1 TOPS-10 was the primary time-shared operating system for the PDP-10. TOPS-20 was a popular alternative derived from the BBN TENEX system.