From 2288fa348f63f84031cea9172ebbdb28666c5372 Mon Sep 17 00:00:00 2001 From: "J. David Bryan" Date: Wed, 19 Feb 2020 16:58:36 -0800 Subject: [PATCH] SCP: HP Only SCP and additional 3.11 JDB SCP Extensions --- 0readme_310.txt | 91 - 0readme_311.txt | 69 - 0readme_ethernet.txt | 660 -- ALTAIR/altair.txt | 211 - ALTAIR/altair_cpu.c | 1187 --- ALTAIR/altair_defs.h | 42 - ALTAIR/altair_dsk.c | 371 - ALTAIR/altair_sio.c | 262 - ALTAIR/altair_sys.c | 313 - GRI/gri_cpu.c | 1106 --- GRI/gri_defs.h | 256 - GRI/gri_stddev.c | 426 -- GRI/gri_sys.c | 700 -- H316/h316_cpu.c | 1803 ----- H316/h316_defs.h | 227 - H316/h316_dp.c | 1093 --- H316/h316_fhd.c | 485 -- H316/h316_hi.c | 324 - H316/h316_imp.c | 192 - H316/h316_imp.h | 199 - H316/h316_lp.c | 357 - H316/h316_mi.c | 766 -- H316/h316_mt.c | 617 -- H316/h316_rtc.c | 384 - H316/h316_stddev.c | 965 --- H316/h316_sys.c | 454 -- H316/h316_udp.c | 468 -- I1401/i1401_cd.c | 586 -- I1401/i1401_cpu.c | 1968 ----- I1401/i1401_dat.h | 145 - I1401/i1401_defs.h | 304 - I1401/i1401_dp.c | 644 -- I1401/i1401_iq.c | 199 - I1401/i1401_lp.c | 287 - I1401/i1401_mt.c | 482 -- I1401/i1401_sys.c | 449 -- I1620/i1620_cd.c | 546 -- I1620/i1620_cpu.c | 2427 ------ I1620/i1620_defs.h | 249 - I1620/i1620_dp.c | 528 -- I1620/i1620_error_matrix.txt | 29 - I1620/i1620_fp.c | 452 -- I1620/i1620_lp.c | 401 - I1620/i1620_pt.c | 520 -- I1620/i1620_sys.c | 608 -- I1620/i1620_tty.c | 528 -- I7094/i7094_binloader.c | 217 - I7094/i7094_bug_history.txt | 70 - I7094/i7094_cd.c | 512 -- I7094/i7094_clk.c | 137 - I7094/i7094_com.c | 1213 --- I7094/i7094_cpu.c | 2476 ------ I7094/i7094_cpu1.c | 947 --- I7094/i7094_dat.h | 152 - I7094/i7094_defs.h | 485 -- I7094/i7094_drm.c | 334 - I7094/i7094_dsk.c | 1224 --- I7094/i7094_io.c | 1899 ----- I7094/i7094_lp.c | 378 - I7094/i7094_mt.c | 865 --- I7094/i7094_sys.c | 776 -- Interdata/id16_cpu.c | 2037 ----- Interdata/id16_dboot.c | 358 - Interdata/id16_sys.c | 643 -- Interdata/id32_cpu.c | 2425 ------ Interdata/id32_dboot.c | 322 - Interdata/id32_sys.c | 780 -- Interdata/id_defs.h | 489 -- Interdata/id_diag.txt | 911 --- Interdata/id_dp.c | 629 -- Interdata/id_fd.c | 530 -- Interdata/id_fp.c | 546 -- Interdata/id_idc.c | 805 -- Interdata/id_io.c | 660 -- Interdata/id_lp.c | 333 - Interdata/id_mt.c | 545 -- Interdata/id_pas.c | 577 -- Interdata/id_pt.c | 377 - Interdata/id_tt.c | 295 - Interdata/id_ttp.c | 293 - Interdata/id_uvc.c | 396 - LGP/lgp_cpu.c | 763 -- LGP/lgp_defs.h | 141 - LGP/lgp_stddev.c | 684 -- LGP/lgp_sys.c | 398 - Makefile.mak | 78 + NOVA/eclipse.txt | 24 - NOVA/eclipse_cpu.c | 6783 ----------------- NOVA/eclipse_tt.c | 428 -- NOVA/nova_clk.c | 185 - NOVA/nova_cpu.c | 1520 ---- NOVA/nova_defs.h | 329 - NOVA/nova_dkp.c | 1095 --- NOVA/nova_dsk.c | 339 - NOVA/nova_lp.c | 155 - NOVA/nova_mta.c | 648 -- NOVA/nova_plt.c | 161 - NOVA/nova_pt.c | 299 - NOVA/nova_qty.c | 1074 --- NOVA/nova_sys.c | 1188 --- NOVA/nova_tt.c | 274 - NOVA/nova_tt1.c | 337 - PDP1/pdp1_clk.c | 127 - PDP1/pdp1_cpu.c | 1719 ----- PDP1/pdp1_dcs.c | 415 - PDP1/pdp1_defs.h | 199 - PDP1/pdp1_diag.txt | 53 - PDP1/pdp1_drm.c | 372 - PDP1/pdp1_dt.c | 1127 --- PDP1/pdp1_lp.c | 214 - PDP1/pdp1_stddev.c | 707 -- PDP1/pdp1_sys.c | 671 -- PDP10/pdp10_bug_history.txt | 28 - PDP10/pdp10_cpu.c | 2544 ------- PDP10/pdp10_defs.h | 809 -- PDP10/pdp10_fe.c | 316 - PDP10/pdp10_ksio.c | 1972 ----- PDP10/pdp10_lp20.c | 1234 --- PDP10/pdp10_mdfp.c | 815 -- PDP10/pdp10_pag.c | 903 --- PDP10/pdp10_rp.c | 1381 ---- PDP10/pdp10_sys.c | 960 --- PDP10/pdp10_tim.c | 456 -- PDP10/pdp10_tu.c | 1398 ---- PDP10/pdp10_xtnd.c | 758 -- PDP11/pdp11_cis.c | 1640 ---- PDP11/pdp11_cpu.c | 3197 -------- PDP11/pdp11_cpumod.c | 1255 ---- PDP11/pdp11_cpumod.h | 302 - PDP11/pdp11_cr.c | 1801 ----- PDP11/pdp11_cr_dat.h | 682 -- PDP11/pdp11_dc.c | 617 -- PDP11/pdp11_defs.h | 927 --- PDP11/pdp11_dl.c | 576 -- PDP11/pdp11_dz.c | 712 -- PDP11/pdp11_fp.c | 1349 ---- PDP11/pdp11_hk.c | 1382 ---- PDP11/pdp11_io.c | 383 - PDP11/pdp11_io_lib.c | 549 -- PDP11/pdp11_io_lib.h | 44 - PDP11/pdp11_ke.c | 347 - PDP11/pdp11_kg.c | 482 -- PDP11/pdp11_lp.c | 198 - PDP11/pdp11_mscp.h | 518 -- PDP11/pdp11_pclk.c | 317 - PDP11/pdp11_pt.c | 367 - PDP11/pdp11_rc.c | 582 -- PDP11/pdp11_rf.c | 504 -- PDP11/pdp11_rh.c | 910 --- PDP11/pdp11_rk.c | 791 -- PDP11/pdp11_rl.c | 1207 --- PDP11/pdp11_rp.c | 1107 --- PDP11/pdp11_rq.c | 2646 ------- PDP11/pdp11_rs.c | 694 -- PDP11/pdp11_rx.c | 535 -- PDP11/pdp11_ry.c | 702 -- PDP11/pdp11_stddev.c | 510 -- PDP11/pdp11_sys.c | 1110 --- PDP11/pdp11_ta.c | 665 -- PDP11/pdp11_tc.c | 1381 ---- PDP11/pdp11_tm.c | 728 -- PDP11/pdp11_tq.c | 2326 ------ PDP11/pdp11_ts.c | 1171 --- PDP11/pdp11_tu.c | 1059 --- PDP11/pdp11_uc15.c | 545 -- PDP11/pdp11_uqssp.h | 169 - PDP11/pdp11_vh.c | 1459 ---- PDP11/pdp11_xq.c | 2853 ------- PDP11/pdp11_xq.h | 406 - PDP11/pdp11_xq_bootrom.h | 312 - PDP11/pdp11_xu.c | 1706 ----- PDP11/pdp11_xu.h | 309 - PDP11/txt2cbn.c | 49 - PDP18B/pdp18b_cpu.c | 2416 ------ PDP18B/pdp18b_defs.h | 568 -- PDP18B/pdp18b_diag.txt | 110 - PDP18B/pdp18b_dr15.c | 339 - PDP18B/pdp18b_drm.c | 261 - PDP18B/pdp18b_dt.c | 1556 ---- PDP18B/pdp18b_fpp.c | 909 --- PDP18B/pdp18b_g2tty.c | 603 -- PDP18B/pdp18b_lp.c | 892 --- PDP18B/pdp18b_mt.c | 535 -- PDP18B/pdp18b_rb.c | 305 - PDP18B/pdp18b_rf.c | 376 - PDP18B/pdp18b_rp.c | 560 -- PDP18B/pdp18b_stddev.c | 1188 --- PDP18B/pdp18b_sys.c | 1333 ---- PDP18B/pdp18b_tt1.c | 466 -- PDP18B/uc15_defs.h | 59 - PDP8/pdp8_clk.c | 200 - PDP8/pdp8_cpu.c | 1612 ---- PDP8/pdp8_ct.c | 730 -- PDP8/pdp8_defs.h | 259 - PDP8/pdp8_df.c | 383 - PDP8/pdp8_dt.c | 1334 ---- PDP8/pdp8_fpp.c | 1514 ---- PDP8/pdp8_lp.c | 189 - PDP8/pdp8_mt.c | 662 -- PDP8/pdp8_pt.c | 292 - PDP8/pdp8_rf.c | 449 -- PDP8/pdp8_rk.c | 464 -- PDP8/pdp8_rl.c | 704 -- PDP8/pdp8_rx.c | 755 -- PDP8/pdp8_sys.c | 1015 --- PDP8/pdp8_td.c | 943 --- PDP8/pdp8_tsc.c | 159 - PDP8/pdp8_tt.c | 278 - PDP8/pdp8_ttx.c | 505 -- S3/haltguide.txt | 950 --- S3/readme_s3.txt | 78 - S3/s3_cd.c | 448 -- S3/s3_cpu.c | 1830 ----- S3/s3_defs.h | 94 - S3/s3_disk.c | 792 -- S3/s3_lp.c | 364 - S3/s3_pkb.c | 313 - S3/s3_sys.c | 949 --- S3/system3.txt | 472 -- SDS/sds_cpu.c | 1783 ----- SDS/sds_defs.h | 426 -- SDS/sds_diag.txt | 113 - SDS/sds_drm.c | 306 - SDS/sds_dsk.c | 392 - SDS/sds_io.c | 1013 --- SDS/sds_lp.c | 331 - SDS/sds_mt.c | 514 -- SDS/sds_mux.c | 562 -- SDS/sds_rad.c | 343 - SDS/sds_stddev.c | 613 -- SDS/sds_sys.c | 793 -- VAX/ka655_patch.com | 509 -- VAX/ka655x.bin | Bin 131072 -> 0 bytes VAX/vax780_bug_history.txt | 75 - VAX/vax780_defs.h | 474 -- VAX/vax780_fload.c | 256 - VAX/vax780_mba.c | 809 -- VAX/vax780_mem.c | 278 - VAX/vax780_sbi.c | 800 -- VAX/vax780_stddev.c | 983 --- VAX/vax780_syslist.c | 142 - VAX/vax780_uba.c | 984 --- VAX/vax_cis.c | 1712 ----- VAX/vax_cmode.c | 1329 ---- VAX/vax_cpu.c | 3456 --------- VAX/vax_cpu1.c | 1658 ---- VAX/vax_defs.h | 729 -- VAX/vax_fpa.c | 1600 ---- VAX/vax_io.c | 943 --- VAX/vax_mmu.c | 664 -- VAX/vax_octa.c | 1264 ---- VAX/vax_stddev.c | 429 -- VAX/vax_sys.c | 1457 ---- VAX/vax_syscm.c | 691 -- VAX/vax_sysdev.c | 1642 ---- VAX/vax_syslist.c | 135 - VAX/vaxmod_defs.h | 498 -- Visual Studio Projects/0ReadMe_Projects.txt | 56 - Visual Studio Projects/ALTAIR.vcproj | 295 - Visual Studio Projects/ECLIPSE.vcproj | 322 - Visual Studio Projects/GRI.vcproj | 290 - Visual Studio Projects/H316.vcproj | 306 - Visual Studio Projects/I1401.vcproj | 310 - Visual Studio Projects/I1620.vcproj | 310 - Visual Studio Projects/I7094.vcproj | 330 - Visual Studio Projects/ID16.vcproj | 338 - Visual Studio Projects/ID32.vcproj | 338 - Visual Studio Projects/NOVA.vcproj | 326 - Visual Studio Projects/PDP1.vcproj | 310 - Visual Studio Projects/PDP10.vcproj | 340 - Visual Studio Projects/PDP11.vcproj | 488 -- Visual Studio Projects/PDP15.vcproj | 338 - Visual Studio Projects/PDP4.vcproj | 326 - Visual Studio Projects/PDP7.vcproj | 330 - Visual Studio Projects/PDP8.vcproj | 350 - Visual Studio Projects/PDP9.vcproj | 330 - Visual Studio Projects/S3.vcproj | 302 - Visual Studio Projects/SDS.vcproj | 318 - Visual Studio Projects/Simh.sln | 170 - Visual Studio Projects/UC15.vcproj | 350 - Visual Studio Projects/VAX.vcproj | 441 -- Visual Studio Projects/VAX780.vcproj | 463 -- Visual Studio Projects/alpha.vcproj | 325 - Visual Studio Projects/lgp.vcproj | 290 - Visual Studio Projects/sigma.vcproj | 351 - alpha/alpha_500au_syslist.c | 49 - alpha/alpha_cpu.c | 1870 ----- alpha/alpha_defs.h | 455 -- alpha/alpha_ev5_cons.c | 143 - alpha/alpha_ev5_defs.h | 428 -- alpha/alpha_ev5_pal.c | 961 --- alpha/alpha_ev5_tlb.c | 566 -- alpha/alpha_fpi.c | 776 -- alpha/alpha_fpv.c | 457 -- alpha/alpha_io.c | 214 - alpha/alpha_mmu.c | 308 - alpha/alpha_sys.c | 816 -- alpha/alpha_sys_defs.h | 43 - alpha/old_pal/alpha_pal_defs.h | 208 - alpha/old_pal/alpha_pal_unix.c | 702 -- alpha/old_pal/alpha_pal_vms.c | 1780 ----- descrip.mms | 1330 ---- doc/gri_doc.doc | Bin 54784 -> 0 bytes doc/h316_doc.doc | Bin 73216 -> 0 bytes doc/i1401_doc.doc | Bin 67584 -> 0 bytes doc/i1620_doc.doc | Bin 166400 -> 0 bytes doc/i7094_doc.doc | Bin 89600 -> 0 bytes doc/id_doc.doc | Bin 116224 -> 0 bytes doc/lgp_doc.doc | Bin 58880 -> 0 bytes doc/nova_doc.doc | Bin 86528 -> 0 bytes doc/pdp10_doc.doc | Bin 87040 -> 0 bytes doc/pdp11_doc.doc | Bin 209408 -> 0 bytes doc/pdp18b_doc.doc | Bin 112128 -> 0 bytes doc/pdp1_doc.doc | Bin 78336 -> 0 bytes doc/pdp8_doc.doc | Bin 104448 -> 0 bytes doc/sds_doc.doc | Bin 74240 -> 0 bytes doc/sigma_doc.doc | Bin 80384 -> 0 bytes doc/simh_doc.doc | Bin 213504 -> 0 bytes doc/simh_doc.pdf | 7476 +++++++++++++++++++ doc/simh_faq.doc | Bin 127488 -> 0 bytes doc/simh_supplement.pdf | Bin 0 -> 446294 bytes doc/simh_swre.doc | Bin 101376 -> 0 bytes doc/vax780_doc.doc | Bin 125440 -> 0 bytes doc/vax_doc.doc | Bin 124416 -> 0 bytes makefile | 476 +- scp.c | 10 +- scp.h | 2 + sigma/Design Notes on the Sigma 7.doc | Bin 29184 -> 0 bytes sigma/sigma_bugs.txt | 149 - sigma/sigma_cis.c | 995 --- sigma/sigma_coc.c | 619 -- sigma/sigma_cpu.c | 2846 ------- sigma/sigma_defs.h | 479 -- sigma/sigma_disks.txt | 193 - sigma/sigma_dk.c | 470 -- sigma/sigma_dp.c | 1334 ---- sigma/sigma_fp.c | 421 -- sigma/sigma_io.c | 1476 ---- sigma/sigma_io_defs.h | 276 - sigma/sigma_lp.c | 545 -- sigma/sigma_map.c | 593 -- sigma/sigma_mt.c | 649 -- sigma/sigma_pt.c | 299 - sigma/sigma_rad.c | 532 -- sigma/sigma_rtc.c | 270 - sigma/sigma_sys.c | 617 -- sigma/sigma_tt.c | 333 - sim_ether.c | 4021 ---------- sim_ether.h | 388 - sim_extension.c | 5648 ++++++++++++++ sim_extension.h | 109 + sim_rev.h | 1 + sim_rs232.h | 69 + sim_serial.c | 1016 +++ sim_serial.h | 101 + sim_tmxr.c | 28 +- sim_tmxr.h | 10 +- 357 files changed, 14601 insertions(+), 231096 deletions(-) delete mode 100644 0readme_310.txt delete mode 100644 0readme_311.txt delete mode 100644 0readme_ethernet.txt delete mode 100644 ALTAIR/altair.txt delete mode 100644 ALTAIR/altair_cpu.c delete mode 100644 ALTAIR/altair_defs.h delete mode 100644 ALTAIR/altair_dsk.c delete mode 100644 ALTAIR/altair_sio.c delete mode 100644 ALTAIR/altair_sys.c delete mode 100644 GRI/gri_cpu.c delete mode 100644 GRI/gri_defs.h delete mode 100644 GRI/gri_stddev.c delete mode 100644 GRI/gri_sys.c delete mode 100644 H316/h316_cpu.c delete mode 100644 H316/h316_defs.h delete mode 100644 H316/h316_dp.c delete mode 100644 H316/h316_fhd.c delete mode 100644 H316/h316_hi.c delete mode 100644 H316/h316_imp.c delete mode 100644 H316/h316_imp.h delete mode 100644 H316/h316_lp.c delete mode 100644 H316/h316_mi.c delete mode 100644 H316/h316_mt.c delete mode 100644 H316/h316_rtc.c delete mode 100644 H316/h316_stddev.c delete mode 100644 H316/h316_sys.c delete mode 100644 H316/h316_udp.c delete mode 100644 I1401/i1401_cd.c delete mode 100644 I1401/i1401_cpu.c delete mode 100644 I1401/i1401_dat.h delete mode 100644 I1401/i1401_defs.h delete mode 100644 I1401/i1401_dp.c delete mode 100644 I1401/i1401_iq.c delete mode 100644 I1401/i1401_lp.c delete mode 100644 I1401/i1401_mt.c delete mode 100644 I1401/i1401_sys.c delete mode 100644 I1620/i1620_cd.c delete mode 100644 I1620/i1620_cpu.c delete mode 100644 I1620/i1620_defs.h delete mode 100644 I1620/i1620_dp.c delete mode 100644 I1620/i1620_error_matrix.txt delete mode 100644 I1620/i1620_fp.c delete mode 100644 I1620/i1620_lp.c delete mode 100644 I1620/i1620_pt.c delete mode 100644 I1620/i1620_sys.c delete mode 100644 I1620/i1620_tty.c delete mode 100644 I7094/i7094_binloader.c delete mode 100644 I7094/i7094_bug_history.txt delete mode 100644 I7094/i7094_cd.c delete mode 100644 I7094/i7094_clk.c delete mode 100644 I7094/i7094_com.c delete mode 100644 I7094/i7094_cpu.c delete mode 100644 I7094/i7094_cpu1.c delete mode 100644 I7094/i7094_dat.h delete mode 100644 I7094/i7094_defs.h delete mode 100644 I7094/i7094_drm.c delete mode 100644 I7094/i7094_dsk.c delete mode 100644 I7094/i7094_io.c delete mode 100644 I7094/i7094_lp.c delete mode 100644 I7094/i7094_mt.c delete mode 100644 I7094/i7094_sys.c delete mode 100644 Interdata/id16_cpu.c delete mode 100644 Interdata/id16_dboot.c delete mode 100644 Interdata/id16_sys.c delete mode 100644 Interdata/id32_cpu.c delete mode 100644 Interdata/id32_dboot.c delete mode 100644 Interdata/id32_sys.c delete mode 100644 Interdata/id_defs.h delete mode 100644 Interdata/id_diag.txt delete mode 100644 Interdata/id_dp.c delete mode 100644 Interdata/id_fd.c delete mode 100644 Interdata/id_fp.c delete mode 100644 Interdata/id_idc.c delete mode 100644 Interdata/id_io.c delete mode 100644 Interdata/id_lp.c delete mode 100644 Interdata/id_mt.c delete mode 100644 Interdata/id_pas.c delete mode 100644 Interdata/id_pt.c delete mode 100644 Interdata/id_tt.c delete mode 100644 Interdata/id_ttp.c delete mode 100644 Interdata/id_uvc.c delete mode 100644 LGP/lgp_cpu.c delete mode 100644 LGP/lgp_defs.h delete mode 100644 LGP/lgp_stddev.c delete mode 100644 LGP/lgp_sys.c create mode 100644 Makefile.mak delete mode 100644 NOVA/eclipse.txt delete mode 100644 NOVA/eclipse_cpu.c delete mode 100644 NOVA/eclipse_tt.c delete mode 100644 NOVA/nova_clk.c delete mode 100644 NOVA/nova_cpu.c delete mode 100644 NOVA/nova_defs.h delete mode 100644 NOVA/nova_dkp.c delete mode 100644 NOVA/nova_dsk.c delete mode 100644 NOVA/nova_lp.c delete mode 100644 NOVA/nova_mta.c delete mode 100644 NOVA/nova_plt.c delete mode 100644 NOVA/nova_pt.c delete mode 100644 NOVA/nova_qty.c delete mode 100644 NOVA/nova_sys.c delete mode 100644 NOVA/nova_tt.c delete mode 100644 NOVA/nova_tt1.c delete mode 100644 PDP1/pdp1_clk.c delete mode 100644 PDP1/pdp1_cpu.c delete mode 100644 PDP1/pdp1_dcs.c delete mode 100644 PDP1/pdp1_defs.h delete mode 100644 PDP1/pdp1_diag.txt delete mode 100644 PDP1/pdp1_drm.c delete mode 100644 PDP1/pdp1_dt.c delete mode 100644 PDP1/pdp1_lp.c delete mode 100644 PDP1/pdp1_stddev.c delete mode 100644 PDP1/pdp1_sys.c delete mode 100644 PDP10/pdp10_bug_history.txt delete mode 100644 PDP10/pdp10_cpu.c delete mode 100644 PDP10/pdp10_defs.h delete mode 100644 PDP10/pdp10_fe.c delete mode 100644 PDP10/pdp10_ksio.c delete mode 100644 PDP10/pdp10_lp20.c delete mode 100644 PDP10/pdp10_mdfp.c delete mode 100644 PDP10/pdp10_pag.c delete mode 100644 PDP10/pdp10_rp.c delete mode 100644 PDP10/pdp10_sys.c delete mode 100644 PDP10/pdp10_tim.c delete mode 100644 PDP10/pdp10_tu.c delete mode 100644 PDP10/pdp10_xtnd.c delete mode 100644 PDP11/pdp11_cis.c delete mode 100644 PDP11/pdp11_cpu.c delete mode 100644 PDP11/pdp11_cpumod.c delete mode 100644 PDP11/pdp11_cpumod.h delete mode 100644 PDP11/pdp11_cr.c delete mode 100644 PDP11/pdp11_cr_dat.h delete mode 100644 PDP11/pdp11_dc.c delete mode 100644 PDP11/pdp11_defs.h delete mode 100644 PDP11/pdp11_dl.c delete mode 100644 PDP11/pdp11_dz.c delete mode 100644 PDP11/pdp11_fp.c delete mode 100644 PDP11/pdp11_hk.c delete mode 100644 PDP11/pdp11_io.c delete mode 100644 PDP11/pdp11_io_lib.c delete mode 100644 PDP11/pdp11_io_lib.h delete mode 100644 PDP11/pdp11_ke.c delete mode 100644 PDP11/pdp11_kg.c delete mode 100644 PDP11/pdp11_lp.c delete mode 100644 PDP11/pdp11_mscp.h delete mode 100644 PDP11/pdp11_pclk.c delete mode 100644 PDP11/pdp11_pt.c delete mode 100644 PDP11/pdp11_rc.c delete mode 100644 PDP11/pdp11_rf.c delete mode 100644 PDP11/pdp11_rh.c delete mode 100644 PDP11/pdp11_rk.c delete mode 100644 PDP11/pdp11_rl.c delete mode 100644 PDP11/pdp11_rp.c delete mode 100644 PDP11/pdp11_rq.c delete mode 100644 PDP11/pdp11_rs.c delete mode 100644 PDP11/pdp11_rx.c delete mode 100644 PDP11/pdp11_ry.c delete mode 100644 PDP11/pdp11_stddev.c delete mode 100644 PDP11/pdp11_sys.c delete mode 100644 PDP11/pdp11_ta.c delete mode 100644 PDP11/pdp11_tc.c delete mode 100644 PDP11/pdp11_tm.c delete mode 100644 PDP11/pdp11_tq.c delete mode 100644 PDP11/pdp11_ts.c delete mode 100644 PDP11/pdp11_tu.c delete mode 100644 PDP11/pdp11_uc15.c delete mode 100644 PDP11/pdp11_uqssp.h delete mode 100644 PDP11/pdp11_vh.c delete mode 100644 PDP11/pdp11_xq.c delete mode 100644 PDP11/pdp11_xq.h delete mode 100644 PDP11/pdp11_xq_bootrom.h delete mode 100644 PDP11/pdp11_xu.c delete mode 100644 PDP11/pdp11_xu.h delete mode 100644 PDP11/txt2cbn.c delete mode 100644 PDP18B/pdp18b_cpu.c delete mode 100644 PDP18B/pdp18b_defs.h delete mode 100644 PDP18B/pdp18b_diag.txt delete mode 100644 PDP18B/pdp18b_dr15.c delete mode 100644 PDP18B/pdp18b_drm.c delete mode 100644 PDP18B/pdp18b_dt.c delete mode 100644 PDP18B/pdp18b_fpp.c delete mode 100644 PDP18B/pdp18b_g2tty.c delete mode 100644 PDP18B/pdp18b_lp.c delete mode 100644 PDP18B/pdp18b_mt.c delete mode 100644 PDP18B/pdp18b_rb.c delete mode 100644 PDP18B/pdp18b_rf.c delete mode 100644 PDP18B/pdp18b_rp.c delete mode 100644 PDP18B/pdp18b_stddev.c delete mode 100644 PDP18B/pdp18b_sys.c delete mode 100644 PDP18B/pdp18b_tt1.c delete mode 100644 PDP18B/uc15_defs.h delete mode 100644 PDP8/pdp8_clk.c delete mode 100644 PDP8/pdp8_cpu.c delete mode 100644 PDP8/pdp8_ct.c delete mode 100644 PDP8/pdp8_defs.h delete mode 100644 PDP8/pdp8_df.c delete mode 100644 PDP8/pdp8_dt.c delete mode 100644 PDP8/pdp8_fpp.c delete mode 100644 PDP8/pdp8_lp.c delete mode 100644 PDP8/pdp8_mt.c delete mode 100644 PDP8/pdp8_pt.c delete mode 100644 PDP8/pdp8_rf.c delete mode 100644 PDP8/pdp8_rk.c delete mode 100644 PDP8/pdp8_rl.c delete mode 100644 PDP8/pdp8_rx.c delete mode 100644 PDP8/pdp8_sys.c delete mode 100644 PDP8/pdp8_td.c delete mode 100644 PDP8/pdp8_tsc.c delete mode 100644 PDP8/pdp8_tt.c delete mode 100644 PDP8/pdp8_ttx.c delete mode 100644 S3/haltguide.txt delete mode 100644 S3/readme_s3.txt delete mode 100644 S3/s3_cd.c delete mode 100644 S3/s3_cpu.c delete mode 100644 S3/s3_defs.h delete mode 100644 S3/s3_disk.c delete mode 100644 S3/s3_lp.c delete mode 100644 S3/s3_pkb.c delete mode 100644 S3/s3_sys.c delete mode 100644 S3/system3.txt delete mode 100644 SDS/sds_cpu.c delete mode 100644 SDS/sds_defs.h delete mode 100644 SDS/sds_diag.txt delete mode 100644 SDS/sds_drm.c delete mode 100644 SDS/sds_dsk.c delete mode 100644 SDS/sds_io.c delete mode 100644 SDS/sds_lp.c delete mode 100644 SDS/sds_mt.c delete mode 100644 SDS/sds_mux.c delete mode 100644 SDS/sds_rad.c delete mode 100644 SDS/sds_stddev.c delete mode 100644 SDS/sds_sys.c delete mode 100644 VAX/ka655_patch.com delete mode 100644 VAX/ka655x.bin delete mode 100644 VAX/vax780_bug_history.txt delete mode 100644 VAX/vax780_defs.h delete mode 100644 VAX/vax780_fload.c delete mode 100644 VAX/vax780_mba.c delete mode 100644 VAX/vax780_mem.c delete mode 100644 VAX/vax780_sbi.c delete mode 100644 VAX/vax780_stddev.c delete mode 100644 VAX/vax780_syslist.c delete mode 100644 VAX/vax780_uba.c delete mode 100644 VAX/vax_cis.c delete mode 100644 VAX/vax_cmode.c delete mode 100644 VAX/vax_cpu.c delete mode 100644 VAX/vax_cpu1.c delete mode 100644 VAX/vax_defs.h delete mode 100644 VAX/vax_fpa.c delete mode 100644 VAX/vax_io.c delete mode 100644 VAX/vax_mmu.c delete mode 100644 VAX/vax_octa.c delete mode 100644 VAX/vax_stddev.c delete mode 100644 VAX/vax_sys.c delete mode 100644 VAX/vax_syscm.c delete mode 100644 VAX/vax_sysdev.c delete mode 100644 VAX/vax_syslist.c delete mode 100644 VAX/vaxmod_defs.h delete mode 100644 Visual Studio Projects/0ReadMe_Projects.txt delete mode 100644 Visual Studio Projects/ALTAIR.vcproj delete mode 100644 Visual Studio Projects/ECLIPSE.vcproj delete mode 100644 Visual Studio Projects/GRI.vcproj delete mode 100644 Visual Studio Projects/H316.vcproj delete mode 100644 Visual Studio Projects/I1401.vcproj delete mode 100644 Visual Studio Projects/I1620.vcproj delete mode 100644 Visual Studio Projects/I7094.vcproj delete mode 100644 Visual Studio Projects/ID16.vcproj delete mode 100644 Visual Studio Projects/ID32.vcproj delete mode 100644 Visual Studio Projects/NOVA.vcproj delete mode 100644 Visual Studio Projects/PDP1.vcproj delete mode 100644 Visual Studio Projects/PDP10.vcproj delete mode 100644 Visual Studio Projects/PDP11.vcproj delete mode 100644 Visual Studio Projects/PDP15.vcproj delete mode 100644 Visual Studio Projects/PDP4.vcproj delete mode 100644 Visual Studio Projects/PDP7.vcproj delete mode 100644 Visual Studio Projects/PDP8.vcproj delete mode 100644 Visual Studio Projects/PDP9.vcproj delete mode 100644 Visual Studio Projects/S3.vcproj delete mode 100644 Visual Studio Projects/SDS.vcproj delete mode 100644 Visual Studio Projects/Simh.sln delete mode 100644 Visual Studio Projects/UC15.vcproj delete mode 100644 Visual Studio Projects/VAX.vcproj delete mode 100644 Visual Studio Projects/VAX780.vcproj delete mode 100644 Visual Studio Projects/alpha.vcproj delete mode 100644 Visual Studio Projects/lgp.vcproj delete mode 100644 Visual Studio Projects/sigma.vcproj delete mode 100644 alpha/alpha_500au_syslist.c delete mode 100644 alpha/alpha_cpu.c delete mode 100644 alpha/alpha_defs.h delete mode 100644 alpha/alpha_ev5_cons.c delete mode 100644 alpha/alpha_ev5_defs.h delete mode 100644 alpha/alpha_ev5_pal.c delete mode 100644 alpha/alpha_ev5_tlb.c delete mode 100644 alpha/alpha_fpi.c delete mode 100644 alpha/alpha_fpv.c delete mode 100644 alpha/alpha_io.c delete mode 100644 alpha/alpha_mmu.c delete mode 100644 alpha/alpha_sys.c delete mode 100644 alpha/alpha_sys_defs.h delete mode 100644 alpha/old_pal/alpha_pal_defs.h delete mode 100644 alpha/old_pal/alpha_pal_unix.c delete mode 100644 alpha/old_pal/alpha_pal_vms.c delete mode 100644 descrip.mms delete mode 100644 doc/gri_doc.doc delete mode 100644 doc/h316_doc.doc delete mode 100644 doc/i1401_doc.doc delete mode 100644 doc/i1620_doc.doc delete mode 100644 doc/i7094_doc.doc delete mode 100644 doc/id_doc.doc delete mode 100644 doc/lgp_doc.doc delete mode 100644 doc/nova_doc.doc delete mode 100644 doc/pdp10_doc.doc delete mode 100644 doc/pdp11_doc.doc delete mode 100644 doc/pdp18b_doc.doc delete mode 100644 doc/pdp1_doc.doc delete mode 100644 doc/pdp8_doc.doc delete mode 100644 doc/sds_doc.doc delete mode 100644 doc/sigma_doc.doc delete mode 100644 doc/simh_doc.doc create mode 100644 doc/simh_doc.pdf delete mode 100644 doc/simh_faq.doc create mode 100644 doc/simh_supplement.pdf delete mode 100644 doc/simh_swre.doc delete mode 100644 doc/vax780_doc.doc delete mode 100644 doc/vax_doc.doc delete mode 100644 sigma/Design Notes on the Sigma 7.doc delete mode 100644 sigma/sigma_bugs.txt delete mode 100644 sigma/sigma_cis.c delete mode 100644 sigma/sigma_coc.c delete mode 100644 sigma/sigma_cpu.c delete mode 100644 sigma/sigma_defs.h delete mode 100644 sigma/sigma_disks.txt delete mode 100644 sigma/sigma_dk.c delete mode 100644 sigma/sigma_dp.c delete mode 100644 sigma/sigma_fp.c delete mode 100644 sigma/sigma_io.c delete mode 100644 sigma/sigma_io_defs.h delete mode 100644 sigma/sigma_lp.c delete mode 100644 sigma/sigma_map.c delete mode 100644 sigma/sigma_mt.c delete mode 100644 sigma/sigma_pt.c delete mode 100644 sigma/sigma_rad.c delete mode 100644 sigma/sigma_rtc.c delete mode 100644 sigma/sigma_sys.c delete mode 100644 sigma/sigma_tt.c delete mode 100644 sim_ether.c delete mode 100644 sim_ether.h create mode 100644 sim_extension.c create mode 100644 sim_extension.h create mode 100644 sim_rs232.h create mode 100644 sim_serial.c create mode 100644 sim_serial.h diff --git a/0readme_310.txt b/0readme_310.txt deleted file mode 100644 index db3672f7..00000000 --- a/0readme_310.txt +++ /dev/null @@ -1,91 +0,0 @@ -Notes For V3.10 - -3.10 is mostly an attempt to get aligned with the current head of the -GitHub 4.0 sources. While the core libraries and SCP have diverged too -far for real forward and backward compatibility, enough 4.0 workalikes -have been added to allow much closer convergence of the two streams. - -3.10 will provide the basis for my future simulation work. - - -1. New Features - -1.1 SCP and libraries - -- -n added in ATTACH, meaning "force empty file". - -1.2 1401 - -- Option to read cards from the console terminal window. -- Option to print line printer output in the console terminal window. - -1.3 1620 - -- Tab stop support added to console terminal. -- Deferred IO added for console terminal and paper-tape reader/punch. - -1.4 PDP-8 - -- LOAD command now supports multi-segment binary tapes. - -1.5 PDP11 - -- Added RS03/RS04 Massbus fixed head disk support. - -1.6 PDP10 - -- LOAD command now supports ITS RIM format. - -1.7 PDP15 - -- Added DR15/UC15 support for PDP15/76. - -1.8 UC15 - -- New simulator, variant on standard PDP11, for PDP15/76 configuration. - -1.7 HP3000 - -- New simulator (from Dave Bryan). - -1.8 HP2100 - -- Complete overhaul; essentially a new simulator (from Dave Bryan). - -1.9 AltairZ80, IBM 1130, SWTP 6800 - -- Removed. These sources have moved on to the 4.0 base. The versions - I had were too far removed from current source to be useful. - -1.10 Sigma - -- New simulator (moved out of beta). - - -2. Bugs Fixed - -Please see the revision history on http://simh.trailing-edge.com or -in the source module sim_rev.h. - - -3. Status Report - -The main branch of SimH is maintained in a public repository - - https://github.com/simh/simh - -under the general editorship of Mark Pizzolato. The 3.10 branch provides -a simpler environment for debugging, for my taste. - -Because of divergences between 3.X and 4.0, certain features in 4.0 -cannot work in 3.X and are not present: - -PDP11/VAX/PDP10 - DUP11 and DMC11 synchronous network interfaces - -PDP10 - front-end keep-alive timer - -H316 - IMP network interface - -In addition, the PDP11 DZ, VH, XQ, and XU implementations are significantly -"down rev" compared to 4.0, due to differences in supporting libraries. - diff --git a/0readme_311.txt b/0readme_311.txt deleted file mode 100644 index b021c826..00000000 --- a/0readme_311.txt +++ /dev/null @@ -1,69 +0,0 @@ -Notes For V3.11 - -3.X aka "SimH Classic" is my original code base, with mutually-agreed -extensions by Dave Bryan. It emphasizes continuity and upward compatibility -of APIs and data structures so that the simulators can remain largely -untouched by improvements and extensions in the core libraries. - -The current release is 3.11. 3.11 will provide the basis for my future -simulation work and for Dave Bryan's HP simulators. - - -1. New Features - -1.1 SCP and libraries - -- -n added in ATTACH, meaning "force empty file". - -1.2 1401 - -- Option to read cards from the console terminal window. -- Option to print line printer output in the console terminal window. - -1.3 1620 - -- Tab stop support added to console terminal. -- Deferred IO added for console terminal and paper-tape reader/punch. - -1.4 PDP-8 - -- LOAD command now supports multi-segment binary tapes. - -1.5 PDP11 - -- Added RS03/RS04 Massbus fixed head disk support. - -1.6 PDP10 - -- LOAD command now supports ITS RIM format. - -1.7 PDP15 - -- Added DR15/UC15 support for PDP15/76. - -1.8 UC15 - -- New simulator, variant on standard PDP11, for PDP15/76 configuration. - -1.7 HP3000 - -- New release (from Dave Bryan). - -1.8 HP2100 - -- New release (from Dave Bryan). - -1.9 AltairZ80, IBM 1130, SWTP 6800 - -- Removed. - -1.10 Sigma - -- New simulator (moved out of beta). - - -2. Bugs Fixed - -Please see the revision history in the source module sim_rev.h. - - diff --git a/0readme_ethernet.txt b/0readme_ethernet.txt deleted file mode 100644 index 841079e2..00000000 --- a/0readme_ethernet.txt +++ /dev/null @@ -1,660 +0,0 @@ -This file contains information about the SIMH Ethernet package. - -------------------------------------------------------------------------------- - -The XQ emulator is a host-independent software emulation of Digital's -DELQA-T (M7516-YM), DELQA (M7516) and DEQNA (M7504) Q-bus Ethernet cards -for the SIMH emulator. - -The XU emulator is a host-independent software emulation of Digital's DEUNA -(M7792/M7793) and DELUA (M7521) Unibus Ethernet cards for the SIMH emulator. - -The XQ and XU simulators use the Sim_Ether module to execute host-specific -packet reads and writes, since all operating systems talk to real Ethernet -cards/controllers differently. See the comments at the top of sim_ether.c -for the list of currently supported host platforms. - -The Sim_Ether module sets the selected Ethernet card into -promiscuous mode to gather all packets, then filters out the packets that it -doesn't want. In Windows, packets having the same source MAC address as the -controller are ignored for WinPCAP compatibility (see Windows notes below). - -If your Ethernet card is plugged into a switch, the promiscuous mode setting -should not cause much of a problem, since the switch will still filter out -most of the undesirable traffic. You will only see "excessive" traffic if you -are on a direct or hub(repeater) segment. - -On Windows using the WinPcap interface, the simulated computer can "talk" to -the host computer on the same interface. On other platforms with libpcap -(*nix), the simulated computer can not "talk" to the host computer via the -selected interface, since simulator transmitted packets are not received -by the host's network stack. The workaround for this is to use a second NIC -in the host and connect them both into the same network; then the host and -the simulator can communicate over the physical LAN. - -Integrated Universal TUN/TAP support provides another solution for the above -dual-NIC problem for systems that support Universal TUN/TAP. Since the TUN/TAP -interface is a pseudo network interface, the host can create a TAP device for -the simulator and then bridge or route packets between the TAP device and the -real network interface. Note that the TAP device and any bridging or routing -must be established before running the simulator; SIMH does not create, -bridge, or route TAP devices for you. - -Integrated Universal TUN/TAP support can be used for host<->simulator network -traffic (on the platforms where it is available) by using the SIMH command: -"attach xq tap:tapN" (i.e. attach xq tap:tap0). Platforms that this has been -tested on include: Linux, FreeBSD, OpenBSD, NetBSD and OSX. Each of these -platforms has some way to create a tap pseudo device (and possibly then to -bridge it with a physical network interface). - -The following steps were performed to get a working SIMH vax simulator -sharing a physical NIC and allowing Host<->SIMH vax communications: - -Linux (Ubuntu 10.04): - apt-get install make - apt-get install libpcap-dev - apt-get install bridge-utils - apt-get install uml-utilities - - - #!/bin/sh - HOSTIP=`/sbin/ifconfig eth0 | grep "inet addr" | gawk -- '{ print $2 }' | gawk -F : -- '{ print $2 }'` - HOSTNETMASK=`/sbin/ifconfig eth0 | grep "inet addr" | gawk -- '{ print $4 }' | gawk -F : -- '{ print $2 }'` - HOSTBCASTADDR=`/sbin/ifconfig eth0 | grep "inet addr" | gawk -- '{ print $3 }' | gawk -F : -- '{ print $2 }'` - HOSTDEFAULTGATEWAY=`/sbin/route -n | grep ^0.0.0.0 | gawk -- '{ print $2 }'` - # - /usr/sbin/tunctl -t tap0 [-u someuser] - /sbin/ifconfig tap0 up - # - # Now convert eth0 to a bridge and bridge it with the TAP interface - /usr/sbin/brctl addbr br0 - /usr/sbin/brctl addif br0 eth0 - /usr/sbin/brctl setfd br0 0 - /sbin/ifconfig eth0 0.0.0.0 - /sbin/ifconfig br0 $HOSTIP netmask $HOSTNETMASK broadcast $HOSTBCASTADDR up - # set the default route to the br0 interface - /sbin/route add -net 0.0.0.0/0 gw $HOSTDEFAULTGATEWAY - # bridge in the tap device - /usr/sbin/brctl addif br0 tap0 - /sbin/ifconfig tap0 0.0.0.0 - - # Run simulator and "attach xq tap:tap0" - -OpenBSD (OpenBSD 4.6) - - /sbin/ifconfig tun0 create - /sbin/ifconfig tun0 link0 - /sbin/ifconfig tun0 up - - /sbin/ifconfig bridge0 create - /sbin/brconfig bridge0 fwddelay 4 - /sbin/brconfig bridge0 add em0 add tun0 # Change em0 to reflect your physical NIC name - /sbin/brconfig bridge0 up - - # Run simulator and "attach xq tap:tun0" - -FreeBSD (FreeBSD 8.0) - - /sbin/ifconfig tap0 create - /sbin/ifconfig tap0 up - - /sbin/ifconfig bridge0 create - /sbin/ifconfig bridge0 addm em0 addm tap0 # Change em0 to reflect your physical NIC name - /sbin/ifconfig bridge0 up - - # Run simulator and "attach xq tap:tap0" - # Note: it seems that on FreeBSD you may have to - # "/sbin/ifconfig tap0 up" and "/sbin/ifconfig bridge0 up" prior to each - # time simh "attach"es the tap:tap0 device - -NetBSD (NetBSD 5.0.2) - - /sbin/ifconfig tap0 create - /sbin/ifconfig tap0 up - - /sbin/ifconfig bridge0 create - /sbin/brconfig bridge0 fwddelay 1 - /sbin/brconfig bridge0 add wm0 add tap0 # Change wm0 to reflect your physical NIC name - /sbin/brconfig bridge0 up - - # Run simulator and "attach xq tap:tap0" - -OSX (Snow Leopard) - OSX Does NOT have native support for tun/tap interfaces. It also does not have native - support for bridging. - - Mattias Nissler has created tun/tap functionality available at http://tuntaposx,sourceforge.net/ - - We'll punt on bridging for the sake of this example and move on to use a basic tap - based internal network so a host and guest can communicate directly. - - Download the install package from: - http://sourceforge.net/projects/tuntaposx/files/tuntap/20111101/tuntap_20111101.tar.gz - - Expand the tarball to a directory. - Invoke the package installer tuntap_20111101.pkg - Click through the various prompts accepting things and eventually installing the package. - - # Build and Run simulator and: - sim> attach xq tap:tap0 - sim> ! ifconfig tap0 192.168.6.1 netmask 255.255.255.0 - - Simulated system uses IP address 192.168.6.2 and host uses 192.168.6.1 - and things work. - You must run as root for this to work. - -------------------------------------------------------------------------------- -An alternative to direct pcap and tun/tap networking on *nix environments is -VDE (Virtual Distributed Ethernet). - -Note 1: Using vde based networking is likely more flexible, but it isn't - nearly as efficient. Host OS overhead will always be higher when - vde networking is used as compared to native pcap and/or tun/tap - networking. -Note 2: Root access will likely be needed to configure or start the vde - environment prior to starting a simulator which may use it. -Note 3: Simulators running using VDE networking can run without root - privilege. - -Linux (Ubuntu 10.04): - apt-get install make - apt-get install libvdeplug-dev - apt-get install vde2 - - vde_switch -s /tmp/switch1 -tap tap0 -m 666 - ifconfig tap0 192.168.6.1 netmask 255.255.255.0 up - - # Build and Run simulator and: - sim> attach xq vde:/tmp/switch1 #simulator uses IP address 192.168.6.2 - -------------------------------------------------------------------------------- - -Windows notes: - 1. The Windows-specific code uses the WinPCAP 4.x package from - http://www.winpcap.org. This package for windows simulates the libpcap - package that is freely available for un*x systems. - - 2. You must *install* the WinPCAP runtime package. - - 3. The first time the WinPCAP driver is used, it will be dynamically loaded, - and the user must be an Administrator on the machine to do so. If you need - to run as an unprivileged user, you must set the "npf" driver to autostart. - Current WinPcap installers provide an option to configure this at - installation time, so if that choice is made, then there is no need for - administrator privileged to run simulators with network support. - - -Building on Windows: - You should be able to build with any of the free compiler environments - available on the Windows platform. If you want to use the Visual C++ - Express 2008 or 2010 interactive development environments, read the file - ".\Visual Studio Projects\0ReadMe_Projects.txt" for details about the - required dependencies. Alternatively, you can build simh with networking - support using the MinGW GCC compiler environment or the cygwin environment. - Each of these Visual C++, MinGW and cygwin build environments require - WinPcap and Posix packages being available. These should be located in a - directory structure parallel to the current simulator source directory. - - For Example, the directory structure should look like: - - .../simh/simhv38-2-rc1/VAX/vax_cpu.c - .../simh/simhv38-2-rc1/scp.c - .../simh/simhv38-2-rc1/Visual Studio Projects/simh.sln - .../simh/simhv38-2-rc1/Visual Studio Projects/VAX.vcproj - .../simh/simhv38-2-rc1/BIN/Nt/Win32-Release/vax.exe - .../simh/windows-build/pthreads/pthread.h - .../simh/windows-build/winpcap/WpdPack/Include/pcap.h - - The contents of the windows-build directory can be downloaded from: - - https://github.com/downloads/markpizz/simh/windows-build.zip - - - There are Windows batch files provided to initiate compiles using the MinGW - compiler tool chain. These batch files are located in the same directory - as this file and are called: build_mingw.bat, build_mingw_ether.bat, and - build_mingw_noasync.bat. These batch files each presume that the MinGW - toolchain is either in the current path or, if not that it is located at - C:\MinGW\bin. These batch files merely invoke the MinGW make (GNU make) - passing some specific arguments along with the optional arguments the batch - file is invoked with. - - The current windows network built binaries will run on any system without - regard to whether or not WinPcap is installed, and will provide - Network functionality when WinPcap is available. - -------------------------------------------------------------------------------- - -Linux, {Free|Net|Open}BSD, OS/X, and Un*x notes: - ------ WARNING ----- WARNING ----- WARNING ----- WARNING ----- WARNING ----- - -Sim_Ether has been reworked to be more universal; because of this, you will -need to get a version of libpcap that is 0.9 or greater. All current Linux -distributions provide a libpcap-dev package which has the needed version -of libpcap and the required components to build applications using it. -If you are running an older Linux OS, you can download and build the required -library from www.tcpdump.org - see the comments at the top of Sim_ether.c -for details. - ------ WARNING ----- WARNING ----- WARNING ----- WARNING ----- WARNING ----- - - 1. For all platforms, you must run SIMH(scp) with sufficient privilege to - allow the Ethernet card can be set into promiscuous mode and to write - packets through the driver. - a) For Windows systems this means having administrator privileges to - start the "npf" driver. The current WinPcap installer offers an - option to autostart the "npf" driver when the system boots. - Starting the "npf" driver at boot time means that simulators do - not need to run with administrator privileges. - b) For more recent Linux systems, The concepts leveraging "Filesystem - Capabilities" can be used to specifically grant the simh binary - the needed privileges to access the network. The article at: - http://packetlife.net/blog/2010/mar/19/sniffing-wireshark-non-root-user/ - describes how to do this for wireshark. The exact same capabilities - are needed by SIMH for network support. Use that article as a guide. - c) For Unix/Unix-like systems which use bpf devices (NetBSD, - OpenBSD, FreeBSD and OS/X) it is possible to set permissions on - the bpf devices to allow read and write access to users other - than root (For example: chmod 666 /dev/bpf*). Doing this, has - its own security issues. - d) For other platforms this will likely mean running as root. - Additional alternative methods for avoiding the 'run as root' requirement - will be welcomed. - - 2. If you want to use TAP devices, and any surrounding system network/bridge - setup must be done before running SIMH. However, once that is done - (possibly at system boot time), using the TAP devices can be done without - root privileges. - -Building on Linux, {Free|Net|Open}BSD, OS/X, Solaris, other *nix: - - 1. Get/make/install the libpcap-dev package for your operating system. Sources: - All : http://www.tcpdump.org/ - Older versions of libpcap can be found, for various systems, at: - Linux : search for your variant on http://rpmfind.net - OS/X : Apple Developer's site? - - NOTE: The repositories for older versions of these platforms - don't contain a version of libpcap greater than 0.8.1. - However, most(all) recent releases of *nix environments - ship with sufficiently recent versions of libpcap either - automatically installed or available for installation as - part of the distribution. - The OS provided libpcap-dev components will be prefereable - to a package built from www.tcpdump.org sources. This is - due to the fact that various OS supplied packages will - depend on the OS supplied libpcap. The improper build or - install of the www.tcpdump.org source package can conflict - with the OS provided one and break the OS provided - applications (i.e. tcpdump and/or wireshark) as well as - not working correctly for use by simh. - - 2. If you install the vendor supplied libpcap-dev package then the simh - makefile will automatically use the vendor supplied library without any - additional arguments. If you have downloaded and built libpcap from - www.tcpdump.org, then the existing makefile will detect that this is - the case and try to use that. - - 3. The makefile defaults to building simulators with network support which - dynamically load the libpcap library. This means that the same simulator - binaries will run on any system whether or not libpcap is installed. If - you want to force direct libpcap linking during a build you do so by - typing 'make USE_NETWORK=1' - - 4. Build it! - -------------------------------------------------------------------------------- - -OpenVMS Alpha and OpenVMS Integrety (IA64) notes: - 1. Ethernet support will only work on Alpha VMS 7.3-1 or later, which is - when required VCI promiscuous mode support was added. Hobbyists can - get the required version of VMS from the OpenVMS Alpha Hobbyist Kit 3.0. - - Running a simulator built with Ethernet support on a version of VMS prior - to 7.3-1 will behave as if there is no Ethernet support built in due to - the inability of the software to set the PCAPVCM into promiscuous mode. - - An example display of fully functional Ethernet support: - sim> SHOW XQ ETH - ETH devices: - 0 we0 (VMS Device: _EWA0:) - 1 we1 (VMS Device: _EWB0:) - - An example display when the simulator was built without Ethernet support - or is not running the required version of VMS: - sim> SHOW XQ ETH - ETH devices: - no network devices are available - - 2. You must place the PCAPVCM.EXE execlet in SYS$LOADABLE_IMAGES before - running a simulator with Ethernet support. Note: This is done by the - build commands in descrip.mms. - - 3. You must have CMKRNL privilege to SHOW or ATTACH an Ethernet device; - alternatively, you can INSTALL the simulator with CMKRNL privilege. - - 4. If you use a second adapter to communicate to the host, SOME protocol - that creates an I/O structure (SCS, DECNET, TCP) must be running on the - adapter prior trying to connect with SIMH, or the host may crash. - The execlet is not written to create an I/O structure for the device. - -Building on OpenVMS Alpha and OpenVMS Integrety (IA64): - The current descrip.mms file will build simulators capable of using - Ethernet support with them automatically. These currently are: VAX, - VAX780, and PDP11. The descrip.mms driven builds will also build the - pcap library and build and install the VCI execlet. - - 1. Fetch the VMS-PCAP zip file from: - http://simh.trailing-edge.com/sources/vms-pcap.zip - 2. Unzip it into the base of the SIMH distribution directory. - 3. Build the simulator(s) with MMS or MMK: - $ MMx {VAX,PDP11,PDP10, etc...} - -------------------------------------------------------------------------------- - -VAX simulator support: - -An OpenVMS VAX v7.2 system with DECNET Phase IV, MultiNet 4.4a, and LAT 5.3 has -been successfully run. Other testers have reported success booting NetBSD and -OpenVMS VAX 5.5-2 also. - - -PDP11 simulator support: - -An RT-11 v5.3 system with a freeware TCP/IP stack has been successfully run. -Other testers have reported that RSX with DECNET and the NetBSD operating -systems also work. RSTS/E v10.1 has preliminary support - RSTS/E boots and -enables the XH (XQ) device - DECNET and LAT software have not been tested. - -The XU module has been tested by a third party for basic packet functionality -under a modified RSX11M environment. I am unable to test it in-house until -someone can arrange to send me a disk image containing a stock RSTS/E or -RSX11M+ system image that also contains DECNET, LAT, and/or TCP/IP software. - -------------------------------------------------------------------------------- - -How to debug problems with the Ethernet subsystems: - -PLEASE read the host-specific notes in sim_ether.c! - -While running SCP, the following commands can be used to enable debug messages: - - sim> SET DEBUG STDERR - sim> SET XQ DEBUG=TRACE;CSR;VAR;WARN;SETUP;SANITY;REG;PACKET;DATA;ETH - sim> SET XU DEBUG=ETH;TRACE;REG;WARN;PACKET;DATA - -Documentation of the functionality of these debug modifiers can be found in -pdp11_xq.h and pdp11_xu.h. Inline debugging has replaced the previous #ifdef -style of debugging, which required recompilation before debugging. - -------------------------------------------------------------------------------- - -Things planned for future releases: - 1. Full MOP implementation - -------------------------------------------------------------------------------- - -Things which I need help with: - 1. Information about Remote MOP processing - 2. VAX/PDP-11 hardware diagnostics image files and docs, to test XQ thoroughly. - 3. Feedback on operation with other VAX/PDP-11 OS's. - -------------------------------------------------------------------------------- - -Please send all patches, questions, feedback, clarifications, and help to: - david DOT hittner AT ngc DOT com - -Thanks, and Enjoy!! -Dave - - -=============================================================================== - Change Log -=============================================================================== - - 01-Mar-12 AGN Added support for building using Cygwin on Windows - 01-Mar-12 MP Made host NIC address detection more robust on *nix platforms - and mad it work when compiling under Cygwin - 29-Feb-12 MP Fixed MAC Address Conflict detection support - 28-Feb-12 MP Fixed overrun bug in eth_devices which caused SEGFAULTs - 28-Feb-12 MP Fixed internal loopback processing to only respond to loopback - packets addressed to the physical MAC or appropriate Multicast - or Broadcast addresses. - 17-Nov-11 MP Added dynamic loading of libpcap on *nix platforms - 30-Oct-11 MP Added support for vde (Virtual Distributed Ethernet) networking - 29-Oct-11 MP Added support for integrated Tap networking interfaces on OSX - 17-Aug-11 RMS Fix from Sergey Oboguev relating to XU and XQ Auto Config and - vector assignments - 12-Aug-11 MP Cleaned up payload length determination - Fixed race condition detecting reflections when threaded - reading and writing is enabled - 07-Jul-11 MB VMS Pcap (from Mike Burke) - - Fixed Alpha issues - - Added OpenVMS Integrety support - 20-Apr-11 MP Fixed save/restore behavior - 12-Jan-11 DTH Added SHOW XU FILTERS modifier - 11-Jan-11 DTH Corrected DEUNA/DELUA SELFTEST command, enabling use by - VMS 3.7, VMS 4.7, and Ultrix 1.1 - 09-Jan-11 MP Fixed missing crc data when USE_READER_THREAD is defined and - crc's are needed (only the pdp11_xu) - 16-Dec-10 MP added priority boost for read and write threads when - USE_READER_THREAD does I/O in separate threads. This helps - throughput since it allows these I/O bound threads to preempt - the main thread (which is executing simulated instructions). - 09-Dec-10 MP allowed more flexible parsing of MAC address strings - 09-Dec-10 MP Added support to determine if network address conflicts exist - 07-Dec-10 MP Reworked DECnet self detection to the more general approach - of loopback self when any Physical Address is being set. - 06-Dec-10 MP Added loopback processing support to pdp11_xu.c - 06-Dec-10 MP Fixed loopback processing to correctly handle forward packets. - 04-Dec-10 MP Changed eth_write to do nonblocking writes when - USE_READER_THREAD is defined. - 30-Nov-10 MP Fixed the fact that no broadcast packets were received by the DEUNA - 29-Nov-10 MP Fixed interrupt dispatch issue which caused delivered packets - (in and out) to sometimes not interrupt the CPU after processing. - 17-Jun-10 MP Fixed bug in the AUTODIN II hash filtering. - 14-Jun-10 MP Added support for integrated Tap networking interfaces on BSD - platforms. - 13-Jun-10 MP Added support for integrated Tap networking interfaces on Linux - platforms. - 31-May-10 MP Added support for more TOE (TCP Offload Engine) features for IPv4 - network traffic from the host and/or from hosts on the LAN. These - new TOE features are: LSO (Large Send Offload) and Jumbo packet - fragmentation support. These features allow a simulated network - device to support traffic when a host leverages a NIC's Large - Send Offload capabilities to fragment and/or segment outgoing - network traffic. Additionally a simulated network device can - reasonably exist on a LAN which is configured to use Jumbo frames. - 21-May-10 MP Added functionality to fix up IP header checksums to accommodate - packets from a host with a NIC which has TOE (TCP Offload Engine) - enabled which is expected to implement the checksum computations - in hardware. Since we catch packets before they arrive at the - NIC the expected checksum insertions haven't been performed yet. - This processing is only done for packets sent from the host to - the guest we're supporting. In general this will be a relatively - small number of packets so it is done for all IP frame packets - coming from the host to the guest. In order to make the - determination of packets specifically arriving from the host we - need to know the hardware MAC address of the host NIC. Currently - determining a NIC's MAC address is relatively easy on Windows. - The non-windows code works on linux and may work on other *nix - platforms either as is or with slight modifications. The code, - as implemented, only messes with this activity if the host - interface MAC address can be determined. - 20-May-10 MP Added general support to deal with receiving packets smaller - than ETH_MIN_PACKET in length. These come from packets - looped back by some bridging mechanism and need to be padded - to the minimum frame size. A real NIC won't pass us any - packets like that. This fix belongs here since this layer - is responsible for interfacing to the physical layer - devices, AND it belongs here to get CRC processing right. - 15-Aug-08 MP Fixed transmitted packets to have the correct source MAC address. - Fixed incorrect address filter setting calling eth_filter(). - 07-Mar-08 MP Fixed the SCP visible SA registers to always display the - ROM MAC address, even after it is changed by SET XQ MAC=. - 07-Mar-08 MP Added changes so that the Console DELQA diagnostic (>>>TEST 82) - will succeed. - 03-Mar-08 MP Added DELQA-T (aka DELQA Plus) device emulation support. - 06-Feb-08 MP Added dropped frame statistics to record when the receiver discards - received packets due to the receiver being disabled, or due to the - XQ device's packet receive queue being full. - Fixed bug in receive processing when we're not polling. This could - cause receive processing to never be activated again if we don't - read all available packets via eth_read each time we get the - opportunity. - 31-Jan-08 MP Added the ability to Coalesce received packet interrupts. This - is enabled by SET XQ POLL=DELAY=nnn where nnn is a number of - microseconds to delay the triggering of an interrupt when a packet - is received. - 29-Jan-08 MP Added SET XQ POLL=DISABLE (aka SET XQ POLL=0) to operate without - polling for packet read completion. - 29-Jan-08 MP Changed the sanity and id timer mechanisms to use a separate timer - unit so that transmit and receive activities can be dealt with - by the normal xq_svc routine. - Dynamically determine the timer polling rate based on the - calibrated tmr_poll and clk_tps values of the simulator. - 25-Jan-08 MP Enabled the SET XQ POLL to be meaningful if the simulator currently - doesn't support idling. - 25-Jan-08 MP Changed xq_debug_setup to use sim_debug instead of printf so that - all debug output goes to the same place. - 25-Jan-08 MP Restored the call to xq_svc after all successful calls to eth_write - to allow receive processing to happen before the next event - service time. This must have been inadvertently commented out - while other things were being tested. - 23-Jan-08 MP Added debugging support to display packet headers and packet data - 18-Jun-07 RMS Added UNIT_IDLE flag - 29-Oct-06 RMS Synced poll and clock - 27-Jan-06 RMS Fixed unaligned accesses in XQB (found by Doug Carman) - 07-Jan-06 RMS Fixed unaligned access bugs (found by Doug Carman) - 07-Sep-05 DTH Removed unused variable - 16-Aug-05 RMS Fixed C++ declaration and cast problems - - 05-Mar-08 MP Added optional multicast filtering support for doing - LANCE style AUTODIN II based hashed filtering. - 07-Feb-08 MP Added eth_show_dev to display Ethernet state - Changed the return value from eth_read to return whether - or not a packet was read. No existing callers used or - checked constant return value that previously was being - supplied. - 29-Jan-08 MP Added eth_set_async to provide a mechanism (when - USE_READER_THREAD is enabled) to allow packet reception - to dynamically update the simulator event queue and - potentially avoid polling for I/O. This provides a minimal - overhead (no polling) maximal responsiveness for network - activities. - 29-Jan-08 MP Properly sequenced activities in eth_close to avoid a race - condition when USE_READER_THREAD is enabled. - 25-Jan-08 MP Changed the following when USE_READER_THREAD is enabled: - - Fixed bug when the simulated device doesn't need crc - in packet data which is read. - - Added call to pcap_setmintocopy to minimize packet - delivery latencies. - - Added ethq_destroy and used it to avoid a memory leak in - eth_close. - - Properly cleaned up pthread mutexes in eth_close. - Migrated to using sim_os_ms_sleep for a delay instead of - a call to select(). - Fixed the bpf filter used when no traffic is to be matched. - Reworked eth_add_packet_crc32 implementation to avoid an - extra buffer copy while reading packets. - Fixed up #ifdef's relating to USE_SHARED so that setting - USE_SHARED or USE_NETWORK will build a working network - environment. - 23-Jan-08 MP Reworked eth_packet_trace and eth_packet_trace_ex to allow - only output Ethernet header+crc and provide a mechanism for - the simulated device to display full packet data debugging. - 17-May-07 DTH Fixed non-Ethernet device removal loop (from Naoki Hamada) - 15-May-07 DTH Added dynamic loading of wpcap.dll; - Corrected exceed max index bug in ethX lookup - 04-May-07 DTH Corrected failure to look up Ethernet device names in - the registry on Windows XP x64 - 10-Jul-06 RMS Fixed linux conditionalization (from Chaskiel Grundman) - 02-Jun-06 JDB Fixed compiler warning for incompatible sscanf parameter - 15-Dec-05 DTH Patched eth_host_devices [remove non-Ethernet devices] - (from Mark Pizzolato and Galen Tackett, 08-Jun-05) - Patched eth_open [tun fix](from Antal Ritter, 06-Oct-05) - 30-Nov-05 DTH Added option to regenerate CRC on received packets; some - Ethernet devices need to pass it on to the simulation, and by - the time libpcap/winpcap gets the packet, the host OS network - layer has already stripped CRC out of the packet - 01-Dec-04 DTH Added Windows user-defined adapter names (from Timothe Litt) - - - -19-Mar-04 Release: - 1. Genericized Sim_Ether code, reduced #ifdefs (David Hittner) - 2. Further refinement of sim_ether, qualified more platforms (Mark Pizzolato) - 3. Added XU module (David Hittner) - 4. Corrected XQ interrupt signaling for PDP11s (David Hittner) - 5. Added inline debugging support (David Hittner) - -------------------------------------------------------------------------------- - -26-Nov-03 Release: - 1. Added VMS support to Sim_Ether; created pcap-vms port (Anders Ahgren) - 2. Added DECNET duplicate detection for Windows (Mark Pizzolato) - 3. Added BPF filtering to increase efficiency (Mark Pizzolato) - 4. Corrected XQ Runt processing (Mark Pizzolato) - 5. Corrected XQ Software Reset (Mark Pizzolato) - 6. Corrected XQ Multicast/Promiscuous mode setting/resetting (Mark Pizzolato) - 7. Added Universal TUN/TAP support (Mark Pizzolato) - 8. Added FreeBSD support (Edward Brocklesby) - 9. Corrected interrupts on XQB device (David Hittner) - -------------------------------------------------------------------------------- - -05-Jun-03 Release: - 1. Added SET/SHOW XQ STATS (David Hittner) - 2. Added SHOW XQ FILTERS (David Hittner) - 3. Added ability to split rcv packets into multiple buffers (David Hittner) - 4. Added explicit runt & giant packet processing (David Hittner) - -------------------------------------------------------------------------------- - -30-May-03 Release: - 1. Corrected bug in xq_setmac introduced in v3.0 (multiple people) - 2. Made XQ rcv buffer allocation dynamic to reduce scp size (David Hittner) - 3. Optimized some structs, removed legacy variables (Mark Pizzolato) - 4. Changed #ifdef WIN32 to _WIN32 for consistency (Mark Pizzolato) - -------------------------------------------------------------------------------- - -06-May-03 Release: - 1. Added second XQ controller (David Hittner) - 2. Added SIMH v3.0 compatibility (David Hittner) - 3. Removed SET ADDRESS functionality (David Hittner) - -------------------------------------------------------------------------------- - -10-Apr-03 Release: - 1. Added preliminary support for RSTS/E (David Hittner) - 2. Added PDP-11 bootrom load via CSR flags (David Hittner) - 3. Support for SPARC linux (Mark Pizzolato) - -------------------------------------------------------------------------------- - -11-Mar-03 Release: - 1. Added support for RT-11 TCP/IP - 2. Corrected interrupts (thanks to Tom Evans and Bob Supnik) - 3. Moved change log to the bottom of the readme file, cleaned up document - -------------------------------------------------------------------------------- - -16-Jan-03 Release: - 1. Added VMScluster support (thanks to Mark Pizzolato) - 2. Verified VAX remote boot functionality (>>>B XQA0) - 3. Added major performance enhancements (thanks to Mark Pizzolato again) - 4. Changed _DEBUG tracers to XQ_DEBUG and ETH_DEBUG - 5. Added local packet processing - 6. Added system id broadcast - -------------------------------------------------------------------------------- - -08-Nov-02 Release: - 1. Added USE_NETWORK conditional to Sim_Ether - 2. Fixed behavior of SHOW XQ ETH if no devices exist - 3. Added OpenBSD support to Sim_Ether (courtesy of Federico Schwindt) - 4. Added ethX detection simplification (from Megan Gentry) - -=============================================================================== diff --git a/ALTAIR/altair.txt b/ALTAIR/altair.txt deleted file mode 100644 index 13f0c361..00000000 --- a/ALTAIR/altair.txt +++ /dev/null @@ -1,211 +0,0 @@ -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. - 2SIO 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 later Z80 CPU [At the present time - this is not fully implemented and is not to be - trusted with real Z80 software] - SET CPU ITRAP Causes the simulator to halt if an invalid 8080 - Opcode is detected. - 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 177400. 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 - A 8 The accumulator - 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. D is the top 8 bits, E is - the bottom. - HL 16 The HL register pair. H is top, L is bottom. - C 1 Carry flag. - Z 1 Zero Flag. - AC 1 Auxillary Carry flag. - P 1 Parity flag. - S 1 Sign flag. - SR 16 The front panel switches. - BREAK 16 Breakpoint address (377777 to disable). - WRU 8 The interrupt character. This starts as 005 - (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 20-21 (octal) for the first port, and 22-23 (octal) 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. - -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 10, 11, and 12 (octal), and we follow the -standard. Details on controlling this hardware are in the altair_dsk.c -source file. - - -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 dsk0 altcpm.dsk - sim> go 177400 - 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". - - -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> attach dsk0 mbasic.dsk - sim> go 177400 - - 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] - - 44297 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 dsk0 altdos.dsk - sim> go 177400 - - MEMORY SIZE? 64 [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] - - 056769 BYTES AVAILABLE - DOS MONITOR VER 1.0 - COPYRIGHT 1977 BY MITS INC - .mnt 0 - - .dir 0 - - - - - diff --git a/ALTAIR/altair_cpu.c b/ALTAIR/altair_cpu.c deleted file mode 100644 index 8c79acd8..00000000 --- a/ALTAIR/altair_cpu.c +++ /dev/null @@ -1,1187 +0,0 @@ -/* altair_cpu.c: MITS Altair Intel 8080 CPU simulator - - Copyright (c) 1997-2012, Charles E. Owen - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Charles E. Owen shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Charles E. Owen. - - cpu 8080 CPU - - 02-Feb-15 RSB Fixed initialization of "uninstalled" memory - 19-Mar-12 RMS Fixed data type for breakpoint variables - 08-Oct-02 RMS Tied off spurious compiler warnings - - The register state for the 8080 CPU is: - - A<0:7> Accumulator - BC<0:15> BC Register Pair - DE<0:15> DE Register Pair - HL<0:15> HL Register Pair - C carry flag - Z zero flag - S Sign bit - AC Aux carry - P Parity bit - PC<0:15> program counter - SP<0:15> Stack Pointer - - The 8080 is an 8-bit CPU, which uses 16-bit registers to address - up to 64KB of memory. - - The 78 basic instructions come in 1, 2, and 3-byte flavors. - - This routine is the instruction decode routine for the 8080. - 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 - I/O error in I/O simulator - Invalid OP code (if ITRAP is set on CPU) - - 2. Interrupts. - There are 8 possible levels of interrupt, and in effect they - do a hardware CALL instruction to one of 8 possible low - memory addresses. - - 3. Non-existent memory. On the 8080, reads to non-existent memory - return 0377, and writes are ignored. In the simulator, the - largest possible memory is instantiated and initialized to 0377. - Thus, only writes need be checked against actual memory size. - - 4. Adding I/O devices. These modules must be modified: - - altair_cpu.c add I/O service routines to dev_table - altair_sys.c add pointer to data structures in sim_devices -*/ - - -#include - -#include "altair_defs.h" - -#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) - -unsigned char M[MAXMEMSIZE]; /* memory */ -int32 A = 0; /* accumulator */ -int32 BC = 0; /* BC register pair */ -int32 DE = 0; /* DE register pair */ -int32 HL = 0; /* HL register pair */ -int32 SP = 0; /* Stack pointer */ -int32 C = 0; /* carry flag */ -int32 Z = 0; /* Zero flag */ -int32 AC = 0; /* Aux carry */ -int32 S = 0; /* sign flag */ -int32 P = 0; /* parity flag */ -int32 saved_PC = 0; /* program counter */ -int32 SR = 0; /* switch register */ -int32 INTE = 0; /* Interrupt Enable */ -int32 int_req = 0; /* Interrupt request */ -int32 chip = 0; /* 0 = 8080 chip, 1 = z80 chip */ - -int32 PCX; /* External view of PC */ - -/* 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_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -void setarith(int32 reg); -void setlogical(int32 reg); -void setinc(int32 reg); -int32 getreg(int32 reg); -void putreg(int32 reg, int32 val); -int32 getpair(int32 reg); -int32 getpush(int32 reg); -void putpush(int32 reg, int32 data); -void putpair(int32 reg, int32 val); -void parity(int32 reg); -int32 cond(int32 con); - -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); -int32 nulldev(int32 io, int32 data); - -/* 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)(int32, int32); -}; -struct idev dev_table[256] = { -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 000 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 004 */ -{&dsk10}, {&dsk11}, {&dsk12}, {&nulldev}, /* 010 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 014 */ -{&sio0s}, {&sio0d}, {&sio1s}, {&sio1d}, /* 020 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 024 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 030 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 034 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 040 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 044 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 050 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 054 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 060 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 064 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 070 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 074 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 100 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 104 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 110 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 114 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 120 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 124 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 130 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 134 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 140 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 144 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 150 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 154 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 160 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 164 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 170 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 174 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 200 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 204 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 210 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 214 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 220 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 224 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 230 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 234 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 240 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 244 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 250 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 254 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 260 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 264 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 270 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 274 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 300 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 304 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 310 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 314 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 320 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 324 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 330 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 334 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 340 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 344 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 350 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 354 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 360 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 364 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev}, /* 370 */ -{&nulldev}, {&nulldev}, {&nulldev}, {&nulldev} /* 374 */ -}; - -/* Altair MITS standard BOOT EPROM, fits in upper 256K of memory */ - -int32 bootrom[256] = { - 0041, 0000, 0114, 0021, 0030, 0377, 0016, 0346, - 0032, 0167, 0023, 0043, 0015, 0302, 0010, 0377, - 0303, 0000, 0114, 0000, 0000, 0000, 0000, 0000, - 0363, 0061, 0142, 0115, 0257, 0323, 0010, 0076, /* 46000 */ - 0004, 0323, 0011, 0303, 0031, 0114, 0333, 0010, /* 46010 */ - 0346, 0002, 0302, 0016, 0114, 0076, 0002, 0323, /* 46020 */ - 0011, 0333, 0010, 0346, 0100, 0302, 0016, 0114, - 0021, 0000, 0000, 0006, 0000, 0333, 0010, 0346, - 0004, 0302, 0045, 0114, 0076, 0020, 0365, 0325, - 0305, 0325, 0021, 0206, 0200, 0041, 0324, 0114, - 0333, 0011, 0037, 0332, 0070, 0114, 0346, 0037, - 0270, 0302, 0070, 0114, 0333, 0010, 0267, 0372, - 0104, 0114, 0333, 0012, 0167, 0043, 0035, 0312, - 0132, 0114, 0035, 0333, 0012, 0167, 0043, 0302, - 0104, 0114, 0341, 0021, 0327, 0114, 0001, 0200, - 0000, 0032, 0167, 0276, 0302, 0301, 0114, 0200, - 0107, 0023, 0043, 0015, 0302, 0141, 0114, 0032, - 0376, 0377, 0302, 0170, 0114, 0023, 0032, 0270, - 0301, 0353, 0302, 0265, 0114, 0361, 0361, 0052, - 0325, 0114, 0325, 0021, 0000, 0377, 0315, 0316, - 0114, 0321, 0332, 0276, 0114, 0315, 0316, 0114, - 0322, 0256, 0114, 0004, 0004, 0170, 0376, 0040, - 0332, 0054, 0114, 0006, 0001, 0312, 0054, 0114, - 0333, 0010, 0346, 0002, 0302, 0240, 0114, 0076, - 0001, 0323, 0011, 0303, 0043, 0114, 0076, 0200, - 0323, 0010, 0303, 0000, 0000, 0321, 0361, 0075, - 0302, 0056, 0114, 0076, 0103, 0001, 0076, 0117, - 0001, 0076, 0115, 0107, 0076, 0200, 0323, 0010, - 0170, 0323, 0001, 0303, 0311, 0114, 0172, 0274, - 0300, 0173, 0275, 0311, 0204, 0000, 0114, 0044, - 0026, 0126, 0026, 0000, 0000, 0000, 0000, 0000 -}; - -/* 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[] = { - { ORDATA (PC, saved_PC, 16) }, - { ORDATA (A, A, 8) }, - { ORDATA (BC, BC, 16) }, - { ORDATA (DE, DE, 16) }, - { ORDATA (HL, HL, 16) }, - { ORDATA (SP, SP, 16) }, - { FLDATA (C, C, 16) }, - { FLDATA (Z, Z, 16) }, - { FLDATA (AC, AC, 16) }, - { FLDATA (S, S, 16) }, - { FLDATA (P, P, 16) }, - { FLDATA (INTE, INTE, 16) }, - { ORDATA (SR, SR, 16) }, - { ORDATA (WRU, sim_int_char, 8) }, - { NULL } -}; - -MTAB cpu_mod[] = { - { UNIT_CHIP, UNIT_CHIP, "Z80", "Z80", NULL }, - { UNIT_CHIP, 0, "8080", "8080", NULL }, - { UNIT_OPSTOP, UNIT_OPSTOP, "ITRAP", "ITRAP", NULL }, - { UNIT_OPSTOP, 0, "NOITRAP", "NOITRAP", NULL }, - { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size }, - { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size }, - { UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size }, - { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size }, - { UNIT_MSIZE, 20480, NULL, "20K", &cpu_set_size }, - { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size }, - { UNIT_MSIZE, 28672, NULL, "28K", &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, 8, 16, 1, 8, 8, - &cpu_ex, &cpu_dep, &cpu_reset, - NULL, NULL, NULL -}; - -t_stat sim_instr (void) -{ - int32 PC, IR, OP, DAR, reason, hi, lo, carry, i; - - PC = saved_PC & ADDRMASK; /* load local PC */ - C = C & 0200000; - 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 > 0) { /* interrupt? */ - - /* 8080 interrupts not implemented yet. None were used, - on a standard Altair 8800. All I/O is programmed. */ - - } /* end interrupt */ - - if (sim_brk_summ && - sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; - } - - if (PC == 0177400) { /* BOOT PROM address */ - for (i = 0; i < 250; i++) { - M[i + 0177400] = bootrom[i] & 0xFF; - } - } - - PCX = PC; - - IR = OP = M[PC]; /* fetch instruction */ - - PC = (PC + 1) & ADDRMASK; /* increment PC */ - - sim_interval--; - - if (OP == 0166) { /* HLT Instruction*/ - reason = STOP_HALT; - PC--; - continue; - } - - /* Handle below all operations which refer to registers or - register pairs. After that, a large switch statement - takes care of all other opcodes */ - - if ((OP & 0xC0) == 0x40) { /* MOV */ - DAR = getreg(OP & 0x07); - putreg((OP >> 3) & 0x07, DAR); - continue; - } - if ((OP & 0xC7) == 0x06) { /* MVI */ - putreg((OP >> 3) & 0x07, M[PC]); - PC++; - continue; - } - if ((OP & 0xCF) == 0x01) { /* LXI */ - DAR = M[PC] & 0x00ff; - PC++; - DAR = DAR | ((M[PC] <<8) & 0xFF00); - putpair((OP >> 4) & 0x03, DAR); - PC++; - continue; - } - if ((OP & 0xEF) == 0x0A) { /* LDAX */ - DAR = getpair((OP >> 4) & 0x03); - putreg(7, M[DAR]); - continue; - } - if ((OP & 0xEF) == 0x02) { /* STAX */ - DAR = getpair((OP >> 4) & 0x03); - M[DAR] = getreg(7); - continue; - } - - if ((OP & 0xF8) == 0xB8) { /* CMP */ - DAR = A & 0xFF; - DAR -= getreg(OP & 0x07); - setarith(DAR); - continue; - } - if ((OP & 0xC7) == 0xC2) { /* JMP */ - if (cond((OP >> 3) & 0x07) == 1) { - lo = M[PC]; - PC++; - hi = M[PC]; - PC++; - PC = (hi << 8) + lo; - } else { - PC += 2; - } - continue; - } - if ((OP & 0xC7) == 0xC4) { /* CALL */ - if (cond((OP >> 3) & 0x07) == 1) { - lo = M[PC]; - PC++; - hi = M[PC]; - PC++; - SP--; - M[SP] = (PC >> 8) & 0xff; - SP--; - M[SP] = PC & 0xff; - PC = (hi << 8) + lo; - } else { - PC += 2; - } - continue; - } - if ((OP & 0xC7) == 0xC0) { /* RET */ - if (cond((OP >> 3) & 0x07) == 1) { - PC = M[SP]; - SP++; - PC |= (M[SP] << 8) & 0xff00; - SP++; - } - continue; - } - if ((OP & 0xC7) == 0xC7) { /* RST */ - SP--; - M[SP] = (PC >> 8) & 0xff; - SP--; - M[SP] = PC & 0xff; - PC = OP & 0x38; - continue; - } - - if ((OP & 0xCF) == 0xC5) { /* PUSH */ - DAR = getpush((OP >> 4) & 0x03); - SP--; - M[SP] = (DAR >> 8) & 0xff; - SP--; - M[SP] = DAR & 0xff; - continue; - } - if ((OP & 0xCF) == 0xC1) { /*POP */ - DAR = M[SP]; - SP++; - DAR |= M[SP] << 8; - SP++; - putpush((OP >> 4) & 0x03, DAR); - continue; - } - if ((OP & 0xF8) == 0x80) { /* ADD */ - A += getreg(OP & 0x07); - setarith(A); - A = A & 0xFF; - continue; - } - if ((OP & 0xF8) == 0x88) { /* ADC */ - carry = 0; - if (C) carry = 1; - A += getreg(OP & 0x07); - A += carry; - setarith(A); - A = A & 0xFF; - continue; - } - if ((OP & 0xF8) == 0x90) { /* SUB */ - A -= getreg(OP & 0x07); - setarith(A); - A = A & 0xFF; - continue; - } - if ((OP & 0xF8) == 0x98) { /* SBB */ - carry = 0; - if (C) carry = 1; - A -= (getreg(OP & 0x07)) + carry ; - setarith(A); - A = A & 0xFF; - continue; - } - if ((OP & 0xC7) == 0x04) { /* INR */ - DAR = getreg((OP >> 3) & 0x07); - DAR++; - setinc(DAR); - DAR = DAR & 0xFF; - putreg((OP >> 3) & 0x07, DAR); - continue; - } - if ((OP & 0xC7) == 0x05) { /* DCR */ - DAR = getreg((OP >> 3) & 0x07); - DAR--; - setinc(DAR); - DAR = DAR & 0xFF; - putreg((OP >> 3) & 0x07, DAR); - continue; - } - if ((OP & 0xCF) == 0x03) { /* INX */ - DAR = getpair((OP >> 4) & 0x03); - DAR++; - DAR = DAR & 0xFFFF; - putpair((OP >> 4) & 0x03, DAR); - continue; - } - if ((OP & 0xCF) == 0x0B) { /* DCX */ - DAR = getpair((OP >> 4) & 0x03); - DAR--; - DAR = DAR & 0xFFFF; - putpair((OP >> 4) & 0x03, DAR); - continue; - } - if ((OP & 0xCF) == 0x09) { /* DAD */ - HL += getpair((OP >> 4) & 0x03); - C = 0; - if (HL & 0x10000) - C = 0200000; - HL = HL & 0xFFFF; - continue; - } - if ((OP & 0xF8) == 0xA0) { /* ANA */ - A &= getreg(OP & 0x07); - C = 0; - setlogical(A); - A &= 0xFF; - continue; - } - if ((OP & 0xF8) == 0xA8) { /* XRA */ - A ^= getreg(OP & 0x07); - C = 0; - setlogical(A); - A &= 0xFF; - continue; - } - if ((OP & 0xF8) == 0xB0) { /* ORA */ - A |= getreg(OP & 0x07); - C = 0; - setlogical(A); - A &= 0xFF; - continue; - } - - - - /* The Big Instruction Decode Switch */ - - switch (IR) { - - /* Logical instructions */ - - case 0376: { /* CPI */ - DAR = A & 0xFF; - DAR -= M[PC]; - PC++; - setarith(DAR); - break; - } - case 0346: { /* ANI */ - A &= M[PC]; - PC++; - C = AC = 0; - setlogical(A); - A &= 0xFF; - break; - } - case 0356: { /* XRI */ - A ^= M[PC]; - PC++; - C = AC = 0; - setlogical(A); - A &= 0xFF; - break; - } - case 0366: { /* ORI */ - A |= M[PC]; - PC++; - C = AC = 0; - setlogical(A); - A &= 0xFF; - break; - } - - /* Jump instructions */ - - case 0303: { /* JMP */ - lo = M[PC]; - PC++; - hi = M[PC]; - PC++; - PC = (hi << 8) + lo; - break; - } - case 0351: { /* PCHL */ - PC = HL; - break; - } - case 0315: { /* CALL */ - lo = M[PC]; - PC++; - hi = M[PC]; - PC++; - SP--; - M[SP] = (PC >> 8) & 0xff; - SP--; - M[SP] = PC & 0xff; - PC = (hi << 8) + lo; - break; - } - case 0311: { /* RET */ - PC = M[SP]; - SP++; - PC |= (M[SP] << 8) & 0xff00; - SP++; - break; - } - - /* Data Transfer Group */ - - case 062: { /* STA */ - lo = M[PC]; - PC++; - hi = M[PC]; - PC++; - DAR = (hi << 8) + lo; - M[DAR] = A; - break; - } - case 072: { /* LDA */ - lo = M[PC]; - PC++; - hi = M[PC]; - PC++; - DAR = (hi << 8) + lo; - A = M[DAR]; - break; - } - case 042: { /* SHLD */ - lo = M[PC]; - PC++; - hi = M[PC]; - PC++; - DAR = (hi << 8) + lo; - M[DAR] = HL; - DAR++; - M[DAR] = (HL >>8) & 0x00ff; - break; - } - case 052: { /* LHLD */ - lo = M[PC]; - PC++; - hi = M[PC]; - PC++; - DAR = (hi << 8) + lo; - HL = M[DAR]; - DAR++; - HL = HL | (M[DAR] <<8); - break; - } - case 0353: { /* XCHG */ - DAR = HL; - HL = DE; - DE = DAR; - break; - } - - /* Arithmetic Group */ - - case 0306: { /* ADI */ - A += M[PC]; - PC++; - setarith(A); - A = A & 0xFF; - break; - } - case 0316: { /* ACI */ - carry = 0; - if (C) carry = 1; - A += M[PC]; - A += carry; - PC++; - setarith(A); - A = A & 0xFF; - break; - } - case 0326: { /* SUI */ - A -= M[PC]; - PC++; - setarith(A); - A = A & 0xFF; - break; - } - case 0336: { /* SBI */ - carry = 0; - if (C) carry = 1; - A -= (M[PC] + carry); - PC++; - setarith(A); - A = A & 0xFF; - break; - } - case 047: { /* DAA */ - DAR = A & 0x0F; - if (DAR > 9 || AC > 0) { - DAR += 6; - A &= 0xF0; - A |= DAR & 0x0F; - if (DAR & 0x10) - AC = 0200000; - else - AC = 0; - } - DAR = (A >> 4) & 0x0F; - if (DAR > 9 || AC > 0) { - DAR += 6; - if (AC) DAR++; - A &= 0x0F; - A |= (DAR << 4); - } - if ((DAR << 4) & 0x100) - C = 0200000; - else - C = 0; - if (A & 0x80) { - S = 0200000; - } else { - S = 0; - } - if ((A & 0xff) == 0) - Z = 0200000; - else - Z = 0; - parity(A); - A = A & 0xFF; - break; - } - case 07: { /* RLC */ - C = 0; - C = (A << 9) & 0200000; - A = (A << 1) & 0xFF; - if (C) - A |= 0x01; - break; - } - case 017: { /* RRC */ - C = 0; - if ((A & 0x01) == 1) - C |= 0200000; - A = (A >> 1) & 0xFF; - if (C) - A |= 0x80; - break; - } - case 027: { /* RAL */ - DAR = C; - C = 0; - C = (A << 9) & 0200000; - A = (A << 1) & 0xFF; - if (DAR) - A |= 1; - else - A &= 0xFE; - break; - } - case 037: { /* RAR */ - DAR = C; - C = 0; - if ((A & 0x01) == 1) - C |= 0200000; - A = (A >> 1) & 0xFF; - if (DAR) - A |= 0x80; - else - A &= 0x7F; - break; - } - case 057: { /* CMA */ - A = ~ A; - A &= 0xFF; - break; - } - case 077: { /* CMC */ - C = ~ C; - C &= 0200000; - break; - } - case 067: { /* STC */ - C = 0200000; - break; - } - - /* Stack, I/O & Machine Control Group */ - - case 0: { /* NOP */ - break; - } - case 0343: { /* XTHL */ - lo = M[SP]; - hi = M[SP + 1]; - M[SP] = HL & 0xFF; - M[SP + 1] = (HL >> 8) & 0xFF; - HL = (hi << 8) + lo; - break; - } - case 0371: { /* SPHL */ - SP = HL; - break; - } - case 0373: { /* EI */ - INTE = 0200000; - break; - } - case 0363: { /* DI */ - INTE = 0; - break; - } - case 0333: { /* IN */ - DAR = M[PC] & 0xFF; - PC++; - if (DAR == 0xFF) { - A = (SR >> 8) & 0xFF; - } else { - A = dev_table[DAR].routine(0, 0); - } - break; - } - case 0323: { /* OUT */ - DAR = M[PC] & 0xFF; - PC++; - dev_table[DAR].routine(1, A); - break; - } - - default: { - if (cpu_unit.flags & UNIT_OPSTOP) { - reason = STOP_OPCODE; - PC--; - } - break; - } - } -} - -/* Simulation halted */ - -saved_PC = PC; -return reason; -} - -/* Test an 8080 flag condition and return 1 if true, 0 if false */ -int32 cond(int32 con) -{ - switch (con) { - case 0: - if (Z == 0) return (1); - break; - case 1: - if (Z != 0) return (1); - break; - case 2: - if (C == 0) return (1); - break; - case 3: - if (C != 0) return (1); - break; - case 4: - if (P == 0) return (1); - break; - case 5: - if (P != 0) return (1); - break; - case 6: - if (S == 0) return (1); - break; - case 7: - if (S != 0) return (1); - break; - default: - break; - } - return (0); -} - -/* Set the arry, ign, ero and

arity flags following - an arithmetic operation on 'reg'. -*/ - -void setarith(int32 reg) -{ - int32 bc = 0; - - if (reg & 0x100) - C = 0200000; - else - C = 0; - if (reg & 0x80) { - bc++; - S = 0200000; - } else { - S = 0; - } - if ((reg & 0xff) == 0) - Z = 0200000; - else - Z = 0; - AC = 0; - if (cpu_unit.flags & UNIT_CHIP) { - P = 0; /* parity is zero for *all* arith ops on Z80 */ - } else { - parity(reg); - } -} - -/* Set the arry, ign, ero amd

arity flags following - a logical (bitwise) operation on 'reg'. -*/ - -void setlogical(int32 reg) -{ - C = 0; - if (reg & 0x80) { - S = 0200000; - } else { - S = 0; - } - if ((reg & 0xff) == 0) - Z = 0200000; - else - Z = 0; - AC = 0; - parity(reg); -} - -/* Set the Parity (P) flag based on parity of 'reg', i.e., number - of bits on even: P=0200000, else P=0 -*/ - -void parity(int32 reg) -{ - int32 bc = 0; - - if (reg & 0x01) bc++; - if (reg & 0x02) bc++; - if (reg & 0x04) bc++; - if (reg & 0x08) bc++; - if (reg & 0x10) bc++; - if (reg & 0x20) bc++; - if (reg & 0x40) bc++; - if (reg & 0x80) bc++; - P = ~(bc << 16); - P &= 0200000; -} - -/* Set the ign, ero amd

arity flags following - an INR/DCR operation on 'reg'. -*/ - -void setinc(int32 reg) -{ - int32 bc = 0; - - if (reg & 0x80) { - bc++; - S = 0200000; - } else { - S = 0; - } - if ((reg & 0xff) == 0) - Z = 0200000; - else - Z = 0; - if (cpu_unit.flags & UNIT_CHIP) { - P = 0; /* parity is zero for *all* arith ops on Z80 */ - } else { - parity(reg); - } -} - -/* Get an 8080 register and return it */ -int32 getreg(int32 reg) -{ - switch (reg) { - case 0: - return ((BC >>8) & 0x00ff); - case 1: - return (BC & 0x00FF); - case 2: - return ((DE >>8) & 0x00ff); - case 3: - return (DE & 0x00ff); - case 4: - return ((HL >>8) & 0x00ff); - case 5: - return (HL & 0x00ff); - case 6: - return (M[HL]); - case 7: - return (A); - default: - break; - } - return 0; -} - -/* Put a value into an 8080 register from memory */ -void putreg(int32 reg, int32 val) -{ - switch (reg) { - case 0: - BC = BC & 0x00FF; - BC = BC | (val <<8); - break; - case 1: - BC = BC & 0xFF00; - BC = BC | val; - break; - case 2: - DE = DE & 0x00FF; - DE = DE | (val <<8); - break; - case 3: - DE = DE & 0xFF00; - DE = DE | val; - break; - case 4: - HL = HL & 0x00FF; - HL = HL | (val <<8); - break; - case 5: - HL = HL & 0xFF00; - HL = HL | val; - break; - case 6: - M[HL] = val & 0xff; - break; - case 7: - A = val & 0xff; - default: - break; - } -} - -/* Return the value of a selected register pair */ -int32 getpair(int32 reg) -{ - switch (reg) { - case 0: - return (BC); - case 1: - return (DE); - case 2: - return (HL); - case 3: - return (SP); - default: - break; - } - return 0; -} - -/* Return the value of a selected register pair, in PUSH - format where 3 means A& flags, not SP */ -int32 getpush(int32 reg) -{ - int32 stat; - - switch (reg) { - case 0: - return (BC); - case 1: - return (DE); - case 2: - return (HL); - case 3: - stat = A << 8; - if (S) stat |= 0x80; - if (Z) stat |= 0x40; - if (AC) stat |= 0x10; - if (P) stat |= 0x04; - stat |= 0x02; - if (C) stat |= 0x01; - return (stat); - default: - break; - } - return 0; -} - - -/* Place data into the indicated register pair, in PUSH - format where 3 means A& flags, not SP */ -void putpush(int32 reg, int32 data) -{ - switch (reg) { - case 0: - BC = data; - break; - case 1: - DE = data; - break; - case 2: - HL = data; - break; - case 3: - A = (data >> 8) & 0xff; - S = Z = AC = P = C = 0; - if (data & 0x80) S = 0200000; - if (data & 0x40) Z = 0200000; - if (data & 0x10) AC = 0200000; - if (data & 0x04) P = 0200000; - if (data & 0x01) C = 0200000; - break; - default: - break; - } -} - - -/* Put a value into an 8080 register pair */ -void putpair(int32 reg, int32 val) -{ - switch (reg) { - case 0: - BC = val; - break; - case 1: - DE = val; - break; - case 2: - HL = val; - break; - case 3: - SP = val; - break; - default: - break; - } -} - - -/* Reset routine */ - -t_stat cpu_reset (DEVICE *dptr) -{ -C = 0; -Z = 0; -saved_PC = 0; -int_req = 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) return SCPE_NXM; -if (vptr != NULL) *vptr = M[addr] & 0377; -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 & 0377; - return SCPE_OK; -} - -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 mc = 0; -uint32 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] = 0377; -return SCPE_OK; -} - -int32 nulldev(int32 flag, int32 data) -{ - if (flag == 0) - return (0377); - return 0; -} - diff --git a/ALTAIR/altair_defs.h b/ALTAIR/altair_defs.h deleted file mode 100644 index b911f755..00000000 --- a/ALTAIR/altair_defs.h +++ /dev/null @@ -1,42 +0,0 @@ -/* altair_defs.h: MITS Altair simulator definitions - - Copyright (c) 1997-2005, Charles E. Owen - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Charles E. Owen shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Charles E. Owen. -*/ - -#include "sim_defs.h" /* simulator defns */ - -/* Memory */ - -#define MAXMEMSIZE 65536 /* max memory size */ -#define MEMSIZE (cpu_unit.capac) /* actual memory size */ -#define ADDRMASK (MAXMEMSIZE - 1) /* address mask */ -#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) - -/* Simulator stop codes */ - -#define STOP_RSRV 1 /* must be 1 */ -#define STOP_HALT 2 /* HALT */ -#define STOP_IBKPT 3 /* breakpoint */ -#define STOP_OPCODE 4 - diff --git a/ALTAIR/altair_dsk.c b/ALTAIR/altair_dsk.c deleted file mode 100644 index d13d77e5..00000000 --- a/ALTAIR/altair_dsk.c +++ /dev/null @@ -1,371 +0,0 @@ -/* altair_dsk.c: MITS Altair 88-DISK Simulator - - Copyright (c) 1997-2017, Charles E. Owen - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Charles E. Owen shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Charles E. Owen. - - The 88_DISK is a 8-inch floppy controller which can control up - to 16 daisy-chained Pertec FD-400 hard-sectored floppy drives. - Each diskette has physically 77 tracks of 32 137-byte sectors - 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 out 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. - - 12-Mar-17 MP Extend data buffer to avoid overrun (COVERITY) -*/ - -#include - -#include "altair_defs.h" - -#define UNIT_V_ENABLE (UNIT_V_UF + 0) /* Write Enable */ -#define UNIT_ENABLE (1 << UNIT_V_ENABLE) - -#define DSK_SECTSIZE 137 -#define DSK_SECT 32 -#define DSK_TRACSIZE 4384 -#define DSK_SURF 1 -#define DSK_CYL 77 -#define DSK_SIZE (DSK_SECT * DSK_SURF * DSK_CYL * DSK_SECTSIZE) - -t_stat dsk_svc (UNIT *uptr); -t_stat dsk_reset (DEVICE *dptr); -void writebuf(); - -extern int32 PCX; - -/* Global data on status */ - -int32 cur_disk = 8; /* Currently selected drive */ -int32 cur_track[9] = {0, 0, 0, 0, 0, 0, 0, 0, 377}; -int32 cur_sect[9] = {0, 0, 0, 0, 0, 0, 0, 0, 377}; -int32 cur_byte[9] = {0, 0, 0, 0, 0, 0, 0, 0, 377}; -int32 cur_flags[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; - -char dskbuf[138]; /* Data Buffer */ -int32 dirty = 0; /* 1 when buffer has unwritten data in it */ -UNIT *dptr; /* fileref to write dirty buffer to */ - -int32 dsk_rwait = 100; /* rotate latency */ - - -/* 88DSK Standard I/O Data Structures */ - -UNIT dsk_unit[] = { - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE, DSK_SIZE) } -}; - -REG dsk_reg[] = { - { ORDATA (DISK, cur_disk, 4) }, - { 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; -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) -{ - - 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(); - - /*printf("\n[%o] OUT 10: %x", PCX, data);*/ - cur_disk = data & 0x0F; - if (data & 0x80) { - cur_flags[cur_disk] = 0; /* Disable drive */ - cur_sect[cur_disk] = 0377; - cur_byte[cur_disk] = 0377; - return (0); - } - cur_flags[cur_disk] = 0x1A; /* Enable: head move true */ - cur_sect[cur_disk] = 0377; /* reset internal counters */ - cur_byte[cur_disk] = 0377; - if (cur_track[cur_disk] == 0) - cur_flags[cur_disk] |= 0x40; /* track 0 if there */ - return (0); -} - -/* Disk Drive Status/Functions */ - -int32 dsk11(int32 io, int32 data) -{ - int32 stat; - - if (io == 0) { /* Read sector position */ - /*printf("\n[%o] IN 11", PCX);*/ - if (dirty == 1) - writebuf(); - if (cur_flags[cur_disk] & 0x04) { /* head loaded? */ - cur_sect[cur_disk]++; - if (cur_sect[cur_disk] > 31) - cur_sect[cur_disk] = 0; - cur_byte[cur_disk] = 0377; - stat = cur_sect[cur_disk] << 1; - stat &= 0x3E; /* return 'sector true' bit = 0 (true) */ - stat |= 0xC0; /* set on 'unused' bits */ - return (stat); - } else { - return (0); /* head not loaded - return 0 */ - } - } - - /* Drive functions */ - - if (cur_disk > 7) - return (0); /* no drive selected - can do nothin */ - - /*printf("\n[%o] OUT 11: %x", PCX, data);*/ - if (data & 0x01) { /* Step head in */ - cur_track[cur_disk]++; - if (cur_track[cur_disk] > 76 ) - cur_track[cur_disk] = 76; - if (dirty == 1) - writebuf(); - cur_sect[cur_disk] = 0377; - cur_byte[cur_disk] = 0377; - } - - if (data & 0x02) { /* Step head out */ - 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] = 0377; - cur_byte[cur_disk] = 0377; - } - - 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] = 0377; - cur_byte[cur_disk] = 0377; - } - - /* 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; -} - -/* Disk Data In/Out*/ - -int32 dsk12(int32 io, int32 data) -{ - static int32 rtn, i; - static long pos; - UNIT *uptr; - - uptr = dsk_dev.units + cur_disk; - if (io == 0) { - if ((i = cur_byte[cur_disk]) < 138) { /* just get from buffer */ - cur_byte[cur_disk]++; - return (dskbuf[i] & 0xFF); - } - /* physically read the sector */ - /*printf("\n[%o] IN 12 (READ) T%d S%d", PCX, cur_track[cur_disk], - cur_sect[cur_disk]);*/ - pos = DSK_TRACSIZE * cur_track[cur_disk]; - pos += DSK_SECTSIZE * cur_sect[cur_disk]; - if ((uptr == NULL) || (uptr->fileref == NULL)) - return 0; - rtn = fseek(uptr -> fileref, pos, 0); - rtn = fread(dskbuf, 137, 1, uptr -> fileref); - cur_byte[cur_disk] = 1; - return (dskbuf[0] & 0xFF); - } else { - if (cur_byte[cur_disk] > 136) { - i = cur_byte[cur_disk]; - dskbuf[i] = data & 0xFF; - writebuf(); - return (0); - } - i = cur_byte[cur_disk]; - dirty = 1; - dptr = uptr; - dskbuf[i] = data & 0xFF; - cur_byte[cur_disk]++; - return (0); - } -} - -void writebuf() -{ - long pos; - int32 rtn, i; - - i = cur_byte[cur_disk]; /* null-fill rest of sector if any */ - while (i < 138) { - dskbuf[i] = 0; - i++; - } - /*printf("\n[%o] OUT 12 (WRITE) T%d S%d", PCX, cur_track[cur_disk], - cur_sect[cur_disk]); i = getch(); */ - pos = DSK_TRACSIZE * cur_track[cur_disk]; /* calc file pos */ - pos += DSK_SECTSIZE * cur_sect[cur_disk]; - rtn = fseek(dptr -> fileref, pos, 0); - rtn = fwrite(dskbuf, 137, 1, dptr -> fileref); - cur_flags[cur_disk] &= 0xFE; /* ENWD off */ - cur_byte[cur_disk] = 0377; - dirty = 0; - return; -} diff --git a/ALTAIR/altair_sio.c b/ALTAIR/altair_sio.c deleted file mode 100644 index a60927de..00000000 --- a/ALTAIR/altair_sio.c +++ /dev/null @@ -1,262 +0,0 @@ -/* altair_sio: MITS Altair serial I/O card - - Copyright (c) 1997-2005, Charles E. Owen - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Charles E. Owen shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Charles E. Owen. - - These functions support a simulated MITS 2SIO interface card. - The card had two physical I/O ports which could be connected - to any serial I/O device that would connect to a current loop, - 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 "altair_defs.h" - -#define UNIT_V_ANSI (UNIT_V_UF + 0) /* ANSI mode */ -#define UNIT_ANSI (1 << UNIT_V_ANSI) - -t_stat sio_svc (UNIT *uptr); -t_stat sio_reset (DEVICE *dptr); -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 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */ - -/* 2SIO Standard I/O Data Structures */ - -UNIT sio_unit = { UDATA (&sio_svc, 0, 0), KBD_POLL_WAIT }; - -REG sio_reg[] = { - { ORDATA (DATA, sio_unit.buf, 8) }, - { ORDATA (STAT, sio_unit.u3, 8) }, - { NULL } -}; - -MTAB sio_mod[] = { - { UNIT_ANSI, 0, "TTY", "TTY", NULL }, - { UNIT_ANSI, UNIT_ANSI, "ANSI", "ANSI", NULL }, - { 0 } -}; - -DEVICE sio_dev = { - "2SIO", &sio_unit, sio_reg, sio_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &sio_reset, - NULL, NULL, NULL -}; - -UNIT ptr_unit = { UDATA (&ptr_svc, UNIT_SEQ + UNIT_ATTABLE, 0), KBD_POLL_WAIT }; - -REG ptr_reg[] = { - { ORDATA (DATA, ptr_unit.buf, 8) }, - { ORDATA (STAT, ptr_unit.u3, 8) }, - { ORDATA (POS, ptr_unit.pos, T_ADDR_W) }, - { 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[] = { - { ORDATA (DATA, ptp_unit.buf, 8) }, - { ORDATA (STAT, ptp_unit.u3, 8) }, - { ORDATA (POS, ptp_unit.pos, T_ADDR_W) }, - { NULL } -}; - -DEVICE ptp_dev = { - "PTP", &ptp_unit, ptp_reg, NULL, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ptp_reset, - NULL, NULL, NULL -}; - -/* 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 ((temp = sim_poll_kbd ()) < SCPE_KFLAG) - return temp; /* no char or error? */ - sio_unit.buf = temp & 0377; /* Save char */ - sio_unit.u3 |= 0x01; /* Set status */ - - /* Do any special character handling here */ - - sio_unit.pos++; - 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) -{ - sio_unit.buf = 0; /* Data */ - sio_unit.u3 = 0x02; /* Status */ - 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 = 0x02; - sim_cancel (&ptr_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) { - return (sio_unit.u3); - } else { - if (data == 0x03) { /* reset port! */ - sio_unit.u3 = 0x02; - sio_unit.buf = 0; - sio_unit.pos = 0; - } - return (0); - } -} - -int32 sio0d(int32 io, int32 data) -{ - if (io == 0) { - sio_unit.u3 = sio_unit.u3 & 0xFE; - return (sio_unit.buf); - } else { - sim_putchar(data); - } - return 0; -} - -/* Port 2 controls the PTR/PTP devices */ - -int32 sio1s(int32 io, int32 data) -{ - if (io == 0) { - if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */ - return 0x02; - if (ptr_unit.u3 != 0) /* No more data? */ - return 0x02; - return (0x03); /* ready to read/write */ - } else { - 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); - } -} - -int32 sio1d(int32 io, int32 data) -{ - int32 temp; - UNIT *uptr; - - if (io == 0) { - if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */ - return 0; - if (ptr_unit.u3 != 0) - return 0; - uptr = ptr_dev.units; - if ((temp = getc(uptr -> fileref)) == EOF) { /* end of file? */ - ptr_unit.u3 = 0x01; - return 0; - } - ptr_unit.pos++; - return (temp & 0xFF); - } else { - uptr = ptp_dev.units; - putc(data, uptr -> fileref); - ptp_unit.pos++; - } - return 0; -} - diff --git a/ALTAIR/altair_sys.c b/ALTAIR/altair_sys.c deleted file mode 100644 index c6e82e75..00000000 --- a/ALTAIR/altair_sys.c +++ /dev/null @@ -1,313 +0,0 @@ -/* altair_sys.c: MITS Altair system interface - - Copyright (c) 1997-2005, Charles E. Owen - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Charles E. Owen shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Charles E. Owen. -*/ - -#include -#include "altair_defs.h" - -extern DEVICE cpu_dev; -extern DEVICE dsk_dev; -extern UNIT cpu_unit; -extern REG cpu_reg[]; -extern DEVICE sio_dev; -extern DEVICE ptr_dev; -extern DEVICE ptp_dev; -extern DEVICE lpt_dev; -extern unsigned char M[]; -extern int32 saved_PC; - -/* 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"; - -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 const char *opcode[] = { -"NOP", "LXI B", "STAX B", "INX B", /* 000-003 */ -"INR B", "DCR B", "MVI B", "RLC", /* 004-007 */ -"???", "DAD B", "LDAX B", "DCX B", /* 010-013 */ -"INR C", "DCR C", "MVI C", "RRC", /* 014-017 */ -"???", "LXI D", "STAX D", "INX D", /* 020-023 */ -"INR D", "DCR D", "MVI D", "RAL", /* 024-027 */ -"???", "DAD D", "LDAX D", "DCX D", /* 030-033 */ -"INR E", "DCR E", "MVI E", "RAR", /* 034-037 */ -"???", "LXI H", "SHLD", "INX H", /* 040-043 */ -"INR H", "DCR H", "MVI H", "DAA", /* 044-047 */ -"???", "DAD H", "LHLD", "DCX H", /* 050-053 */ -"INR L", "DCR L", "MVI L", "CMA", /* 054-057 */ -"???", "LXI SP", "STA", "INX SP", /* 060-063 */ -"INR M", "DCR M", "MVI M", "STC", /* 064-067 */ -"???", "DAD SP", "LDA", "DCX SP", /* 070-073 */ -"INR A", "DCR A", "MVI A", "CMC", /* 074-077 */ -"MOV B,B", "MOV B,C", "MOV B,D", "MOV B,E", /* 100-103 */ -"MOV B,H", "MOV B,L", "MOV B,M", "MOV B,A", /* 104-107 */ -"MOV C,B", "MOV C,C", "MOV C,D", "MOV C,E", /* 110-113 */ -"MOV C,H", "MOV C,L", "MOV C,M", "MOV C,A", /* 114-117 */ -"MOV D,B", "MOV D,C", "MOV D,D", "MOV D,E", /* 120-123 */ -"MOV D,H", "MOV D,L", "MOV D,M", "MOV D,A", /* 124-127 */ -"MOV E,B", "MOV E,C", "MOV E,D", "MOV E,E", /* 130-133 */ -"MOV E,H", "MOV E,L", "MOV E,M", "MOV E,A", /* 134-137 */ -"MOV H,B", "MOV H,C", "MOV H,D", "MOV H,E", /* 140-143 */ -"MOV H,H", "MOV H,L", "MOV H,M", "MOV H,A", /* 144-147 */ -"MOV L,B", "MOV L,C", "MOV L,D", "MOV L,E", /* 150-153 */ -"MOV L,H", "MOV L,L", "MOV L,M", "MOV L,A", /* 154-157 */ -"MOV M,B", "MOV M,C", "MOV M,D", "MOV M,E", /* 160-163 */ -"MOV M,H", "MOV M,L", "HLT", "MOV M,A", /* 164-167 */ -"MOV A,B", "MOV A,C", "MOV A,D", "MOV A,E", /* 170-173 */ -"MOV A,H", "MOV A,L", "MOV A,M", "MOV A,A", /* 174-177 */ -"ADD B", "ADD C", "ADD D", "ADD E", /* 200-203 */ -"ADD H", "ADD L", "ADD M", "ADD A", /* 204-207 */ -"ADC B", "ADC C", "ADC D", "ADC E", /* 210-213 */ -"ADC H", "ADC L", "ADC M", "ADC A", /* 214-217 */ -"SUB B", "SUB C", "SUB D", "SUB E", /* 220-223 */ -"SUB H", "SUB L", "SUB M", "SUB A", /* 224-227 */ -"SBB B", "SBB C", "SBB D", "SBB E", /* 230-233 */ -"SBB H", "SBB L", "SBB M", "SBB A", /* 234-237 */ -"ANA B", "ANA C", "ANA D", "ANA E", /* 240-243 */ -"ANA H", "ANA L", "ANA M", "ANA A", /* 244-247 */ -"XRA B", "XRA C", "XRA D", "XRA E", /* 250-253 */ -"XRA H", "XRA L", "XRA M", "XRA A", /* 254-257 */ -"ORA B", "ORA C", "ORA D", "ORA E", /* 260-263 */ -"ORA H", "ORA L", "ORA M", "ORA A", /* 264-267 */ -"CMP B", "CMP C", "CMP D", "CMP E", /* 270-273 */ -"CMP H", "CMP L", "CMP M", "CMP A", /* 274-277 */ -"RNZ", "POP B", "JNZ", "JMP", /* 300-303 */ -"CNZ", "PUSH B", "ADI", "RST 0", /* 304-307 */ -"RZ", "RET", "JZ", "???", /* 310-313 */ -"CZ", "CALL", "ACI", "RST 1", /* 314-317 */ -"RNC", "POP D", "JNC", "OUT", /* 320-323 */ -"CNC", "PUSH D", "SUI", "RST 2", /* 324-327 */ -"RC", "???", "JC", "IN", /* 330-333 */ -"CC", "???", "SBI", "RST 3", /* 334-337 */ -"RPO", "POP H", "JPO", "XTHL", /* 340-343 */ -"CPO", "PUSH H", "ANI", "RST 4", /* 344-347 */ -"RPE", "PCHL", "JPE", "XCHG", /* 350-353 */ -"CPE", "???", "XRI", "RST 5", /* 354-357 */ -"RP", "POP PSW", "JP", "DI", /* 360-363 */ -"CP", "PUSH PSW", "ORI", "RST 6", /* 364-367 */ -"RM", "SPHL", "JM", "EI", /* 370-373 */ -"CM", "???", "CPI", "RST 7", /* 374-377 */ - }; - -int32 oplen[256] = { -1,3,1,1,1,1,2,1,0,1,1,1,1,1,2,1,0,3,1,1,1,1,2,1,0,1,1,1,1,1,2,1, -0,3,3,1,1,1,2,1,0,1,3,1,1,1,2,1,0,3,3,1,1,1,2,1,0,1,3,1,1,1,2,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, -1,1,3,3,3,1,2,1,1,1,3,0,3,3,2,1,1,1,3,2,3,1,2,1,1,0,3,2,3,0,2,1, -1,1,3,1,3,1,2,1,1,1,3,1,3,0,2,1,1,1,3,1,3,1,2,1,1,1,3,1,3,0,2,1 }; - -/* 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. -*/ - -t_stat 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 = saved_PC; -while ((i = getc (fileref)) != EOF) { - M[addr] = i; - addr++; - cnt++; -} /* end while */ -sim_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 -*/ - -t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, - UNIT *uptr, int32 sw) -{ -int32 cflag, c1, c2, inst, adr; - -cflag = (uptr == NULL) || (uptr == &cpu_unit); -c1 = (val[0] >> 8) & 0177; -c2 = val[0] & 0177; -if (sw & SWMASK ('A')) { - fprintf (of, (c2 < 040)? "<%03o>": "%c", c2); - return SCPE_OK; -} -if (sw & SWMASK ('C')) { - fprintf (of, (c1 < 040)? "<%03o>": "%c", c1); - fprintf (of, (c2 < 040)? "<%03o>": "%c", c2); - return SCPE_OK; -} -if (!(sw & SWMASK ('M'))) return SCPE_ARG; -inst = val[0]; -fprintf (of, "%s", opcode[inst]); -if (oplen[inst] == 2) { - if (strchr(opcode[inst], ' ') != NULL) - fprintf (of, ","); - else fprintf (of, " "); - fprintf (of, "%o", val[1]); -} -if (oplen[inst] == 3) { - adr = val[1] & 0xFF; - adr |= (val[2] << 8) & 0xff00; - if (strchr(opcode[inst], ' ') != NULL) - fprintf (of, ","); - else fprintf (of, " "); - fprintf (of, "%o", adr); -} -return -(oplen[inst] - 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 -*/ - -t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) -{ -int32 cflag, i = 0, j, r; -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] = (uint32) 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] = ((uint32) cptr[0] << 8) + (uint32) cptr[1]; - return SCPE_OK; -} - -/* An instruction: get opcode (all characters until null, comma, - or numeric (including spaces). -*/ - -while (1) { - if (*cptr == ',' || *cptr == '\0' || - isdigit(*cptr)) - break; - gbuf[i] = toupper(*cptr); - cptr++; - i++; -} - -/* Allow for RST which has numeric as part of opcode */ - -if (toupper(gbuf[0]) == 'R' && - toupper(gbuf[1]) == 'S' && - toupper(gbuf[2]) == 'T') { - gbuf[i] = toupper(*cptr); - cptr++; - i++; -} - -/* Allow for 'MOV' which is only opcode that has comma in it. */ - -if (toupper(gbuf[0]) == 'M' && - toupper(gbuf[1]) == 'O' && - toupper(gbuf[2]) == 'V') { - gbuf[i] = toupper(*cptr); - cptr++; - i++; - 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 < 256; j++) { - if (strcmp(gbuf, opcode[j]) == 0) - break; -} -if (j > 255) /* not found */ - return SCPE_ARG; - -val[0] = j; /* store opcode */ -if (oplen[j] < 2) /* if 1-byter we are done */ - return SCPE_OK; -if (*cptr == ',') cptr++; -cptr = get_glyph(cptr, gbuf, 0); /* get address */ -sscanf(gbuf, "%o", &r); -if (oplen[j] == 2) { - val[1] = r & 0xFF; - return (-1); -} -val[1] = r & 0xFF; -val[2] = (r >> 8) & 0xFF; -return (-2); -} diff --git a/GRI/gri_cpu.c b/GRI/gri_cpu.c deleted file mode 100644 index 64f69739..00000000 --- a/GRI/gri_cpu.c +++ /dev/null @@ -1,1106 +0,0 @@ -/* gri_cpu.c: GRI-909 CPU simulator - - Copyright (c) 2001-2015, 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. - - cpu GRI-909/GRI-99 CPU - - 14-Jan-08 RMS Added GRI-99 support - 28-Apr-07 RMS Removed clock initialization - 22-Sep-05 RMS Fixed declarations (Sterling Garwood) - 18-Jul-04 RMS Fixed missing ao_update calls in AX, AY write - 17-Jul-04 RMS Revised MSR, EAO based on additional documentation - 14-Mar-03 RMS Fixed bug in SC queue tracking - - The system state for the GRI-909/GRI-99 is: - - AX<15:0> arithmetic input - AY<15:0> arithmetic input - BSW<15:0> byte swapper - BPK<15:0> byte packer - GR[0:5]<15:0> extended general registers - MSR<15:0> machine status register - TRP<15:0> trap register (subroutine return) - SC<14:0> sequence counter - XR<15:0> index register (GRI-99 only) - - The GRI-909 has, nominally, just one instruction format: move. - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | source | op | destination | move - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - <6:9> operation - - xx1x complement - 01xx add 1 - 10xx rotate left 1 - 11xx rotate right 1 - - In fact, certain of the source and destination operators have side - effects, yielding four additional instruction formats: function out, - skip on function, memory reference, and conditional jump. - - The function out format is: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 0 0 0 0 1 0| pulse | destination | function out - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - The skip on function format is: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | source | skip |rv| 0 0 0 0 1 0| skip function - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - The memory reference format is (src and/or dst = 006): - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | source | op | mode| destination | memory ref - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | address or immediate | - +-----------------------------------------------+ - - <6:9> operation - - xx0x direct, ea = M[SC+1] - xx1x immediate, ea = SC+1 - xxx1 indirect, M[ea] = M[ea]+1, then ea = M[ea] - 01xx add 1 - 10xx rotate left 1 - 11xx rotate right 1 - - The conditional jump format is (src != 006): - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | source | cond|rv|df| 0 0 0 0 1 1| cond jump - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | jump address | - +-----------------------------------------------+ - - <6:9> operation - - xxx0 direct, ea = M[SC+1] - xxx1 indirect, ea = M[SC+1], M[ea] = M[ea]+1, - then ea = M[ea] - xx1x reverse conditional sense - x1xx jump if src == 0 - 1xxx jump if src < 0 - - This routine is the instruction decode routine for the GRI-909. - 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 - unknown source or destination and STOP_OPR flag set - I/O error in I/O simulator - - 2. Interrupts. The interrupt structure is kept in two parallel variables: - - dev_done device done flags - ISR interrupt status register (enables) - - In addition, there is a master interrupt enable, and a one cycle - interrupt defer, both kept in dev_done. - - 3. Non-existent memory. On the GRI-909, 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: - - gri_defs.h add interrupt request definition - gri_cpu.c add dev_tab table entry - gri_sys.c add sim_devices table entry -*/ - -#include "gri_defs.h" - -#define SCQ_SIZE 64 /* must be 2**n */ -#define SCQ_MASK (SCQ_SIZE - 1) -#define SCQ_ENTRY scq[scq_p = (scq_p - 1) & SCQ_MASK] = SC -#define UNIT_V_AO (UNIT_V_UF + 0) /* AO */ -#define UNIT_AO (1u << UNIT_V_AO) -#define UNIT_V_EAO (UNIT_V_UF + 1) /* EAO */ -#define UNIT_EAO (1u << UNIT_V_EAO) -#define UNIT_V_GPR (UNIT_V_UF + 2) /* GPR */ -#define UNIT_GPR (1u << UNIT_V_GPR) -#define UNIT_V_BSWPK (UNIT_V_UF + 3) /* BSW-BPK */ -#define UNIT_BSWPK (1u << UNIT_V_BSWPK) -#define UNIT_V_GRI99 (UNIT_V_UF + 4) /* GRI-99 */ -#define UNIT_GRI99 (1u << UNIT_V_GRI99) -#define UNIT_V_MSIZE (UNIT_V_UF + 5) /* dummy mask */ -#define UNIT_MSIZE (1u << UNIT_V_MSIZE) - -#define IDX_ADD(x) ((((cpu_unit.flags & UNIT_GRI99) && ((x) & INDEX))? ((x) + XR): (x)) & AMASK) - -uint16 M[MAXMEMSIZE] = { 0 }; /* memory */ -uint32 SC; /* sequence cntr */ -uint32 AX, AY, AO; /* arithmetic unit */ -uint32 IR; /* instr reg */ -uint32 MA; /* memory addr */ -uint32 TRP; /* subr return */ -uint32 MSR; /* machine status */ -uint32 ISR; /* interrupt status */ -uint32 BSW, BPK; /* byte swap, pack */ -uint32 GR[6]; /* extended general regs */ -uint32 SWR; /* switch reg */ -uint32 DR; /* display register */ -uint32 XR; /* index register */ -uint32 thwh = 0; /* thumbwheel */ -uint32 dev_done = 0; /* device flags */ -uint32 bkp = 0; /* bkpt pending */ -uint32 stop_opr = 1; /* stop ill operator */ -int16 scq[SCQ_SIZE] = { 0 }; /* PC queue */ -int32 scq_p = 0; /* PC queue ptr */ -REG *scq_r = NULL; /* PC queue reg ptr */ - -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 bus_op (uint32 src, uint32 op, uint32 dst); - -/* Dispatch tables for source, dest, function out, skip on function */ - -uint32 no_rd (uint32 src); -t_stat no_wr (uint32 dst, uint32 val); -t_stat no_fo (uint32 op); -uint32 no_sf (uint32 op); -uint32 zero_rd (uint32 src); -t_stat zero_wr (uint32 dst, uint32 val); -t_stat zero_fo (uint32 op); -uint32 zero_sf (uint32 op); -uint32 ir_rd (uint32 op); -t_stat ir_fo (uint32 op); -uint32 trp_rd (uint32 src); -t_stat trp_wr (uint32 dst, uint32 val); -uint32 atrp_rd (uint32 src); -t_stat atrp_wr (uint32 dst, uint32 val); -uint32 isr_rd (uint32 src); -t_stat isr_wr (uint32 dst, uint32 val); -t_stat isr_fo (uint32 op); -uint32 isr_sf (uint32 op); -uint32 ma_rd (uint32 src); -uint32 mem_rd (uint32 src); -t_stat mem_wr (uint32 dst, uint32 val); -uint32 sc_rd (uint32 src); -t_stat sc_wr (uint32 dst, uint32 val); -uint32 swr_rd (uint32 src); -uint32 ax_rd (uint32 src); -t_stat ax_wr (uint32 dst, uint32 val); -uint32 ay_rd (uint32 src); -t_stat ay_wr (uint32 dst, uint32 val); -uint32 ao_rd (uint32 src); -t_stat ao_fo (uint32 op); -uint32 ao_sf (uint32 op); -uint32 ao_update (void); -t_stat eao_fo (uint32 op); -uint32 msr_rd (uint32 src); -t_stat msr_wr (uint32 dst, uint32 val); -uint32 bsw_rd (uint32 src); -t_stat bsw_wr (uint32 dst, uint32 val); -uint32 bpk_rd (uint32 src); -t_stat bpk_wr (uint32 dst, uint32 val); -uint32 gr_rd (uint32 src); -t_stat gr_wr (uint32 dst, uint32 val); -uint32 xr_rd (uint32 src); -t_stat xr_wr (uint32 dst, uint32 val); - -extern t_stat rtc_fo (uint32 op); -extern uint32 rtc_sf (uint32 op); -extern uint32 hsrp_rd (uint32 src); -extern t_stat hsrp_wr (uint32 dst, uint32 val); -extern t_stat hsrp_fo (uint32 op); -extern uint32 hsrp_sf (uint32 op); -extern uint32 tty_rd (uint32 src); -extern t_stat tty_wr (uint32 dst, uint32 val); -extern t_stat tty_fo (uint32 op); -extern uint32 tty_sf (uint32 op); - -struct gdev dev_tab[64] = { - { &zero_rd, &zero_wr, &zero_fo, &zero_sf }, /* 00: zero */ - { &ir_rd, &zero_wr, &ir_fo, &zero_sf }, /* ir */ - { &no_rd, &no_wr, &no_fo, &no_sf }, /* fo/sf */ - { &trp_rd, &trp_wr, &zero_fo, &zero_sf }, /* trp */ - { &isr_rd, &isr_wr, &isr_fo, &isr_sf }, /* isr */ - { &ma_rd, &no_wr, &no_fo, &no_sf }, /* ma */ - { &mem_rd, &mem_wr, &zero_fo, &zero_sf }, /* memory */ - { &sc_rd, &sc_wr, &zero_fo, &zero_sf }, /* sc */ - { &swr_rd, &no_wr, &no_fo, &no_sf }, /* swr */ - { &ax_rd, &ax_wr, &zero_fo, &zero_sf }, /* ax */ - { &ay_rd, &ay_wr, &zero_fo, &zero_sf }, /* ay */ - { &ao_rd, &zero_wr, &ao_fo, &ao_sf }, /* ao */ - { &zero_rd, &zero_wr, &eao_fo, &zero_sf }, /* eao */ - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &msr_rd, &msr_wr, &zero_fo, &zero_sf }, /* msr */ - { &no_rd, &no_wr, &no_fo, &no_sf }, /* 20 */ - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &xr_rd, &xr_wr, &no_fo, &no_sf }, /* xr */ - { &atrp_rd, &atrp_wr, &no_fo, &no_sf }, - { &bsw_rd, &bsw_wr, &no_fo, &no_sf }, /* bsw */ - { &bpk_rd, &bpk_wr, &no_fo, &no_sf }, /* bpk */ - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* 30: gr1 */ - { &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* gr2 */ - { &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* gr3 */ - { &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* gr4 */ - { &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* gr5 */ - { &gr_rd, &gr_wr, &zero_fo, &zero_sf }, /* gr6 */ - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, /* 40 */ - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, /* 50 */ - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, /* 60 */ - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, /* 70 */ - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &no_rd, &no_wr, &no_fo, &no_sf }, - { &zero_rd, &zero_wr, &rtc_fo, &rtc_sf }, /* rtc */ - { &hsrp_rd, &hsrp_wr, &hsrp_fo, &hsrp_sf }, /* hsrp */ - { &tty_rd, &tty_wr, &tty_fo, &tty_sf } /* tty */ - }; - -static const int32 vec_map[16] = { - VEC_TTO, VEC_TTI, VEC_HSP, VEC_HSR, - -1, -1, -1, -1, - -1, -1, -1, VEC_RTC, - -1, -1, -1, -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+UNIT_AO+UNIT_EAO+UNIT_GPR, MAXMEMSIZE) }; - -REG cpu_reg[] = { - { ORDATA (SC, SC, 15) }, - { ORDATA (AX, AX, 16) }, - { ORDATA (AY, AY, 16) }, - { ORDATA (AO, AO, 16), REG_RO }, - { ORDATA (TRP, TRP, 16) }, - { ORDATA (MSR, MSR, 16) }, - { ORDATA (ISR, ISR, 16) }, - { ORDATA (BSW, BSW, 16) }, - { ORDATA (BPK, BPK, 16) }, - { ORDATA (GR1, GR[0], 16) }, - { ORDATA (GR2, GR[1], 16) }, - { ORDATA (GR3, GR[2], 16) }, - { ORDATA (GR4, GR[3], 16) }, - { ORDATA (GR5, GR[4], 16) }, - { ORDATA (GR6, GR[5], 16) }, - { ORDATA (XR, XR, 16) }, - { FLDATA (BOV, MSR, MSR_V_BOV) }, - { FLDATA (L, MSR, MSR_V_L) }, - { GRDATA (FOA, MSR, 8, 2, MSR_V_FOA) }, - { FLDATA (SOV, MSR, MSR_V_SOV) }, - { FLDATA (AOV, MSR, MSR_V_AOV) }, - { ORDATA (IR, IR, 16), REG_RO }, - { ORDATA (MA, MA, 16), REG_RO }, - { ORDATA (SWR, SWR, 16) }, - { ORDATA (DR, DR, 16) }, - { ORDATA (THW, thwh, 6) }, - { ORDATA (IREQ, dev_done, INT_V_NODEF) }, - { FLDATA (ION, dev_done, INT_V_ON) }, - { FLDATA (INODEF, dev_done, INT_V_NODEF) }, - { FLDATA (BKP, bkp, 0) }, - { BRDATA (SCQ, scq, 8, 15, SCQ_SIZE), REG_RO + REG_CIRC }, - { ORDATA (SCQP, scq_p, 6), REG_HRO }, - { FLDATA (STOP_OPR, stop_opr, 0) }, - { ORDATA (WRU, sim_int_char, 8) }, - { NULL } - }; - -MTAB cpu_mod[] = { - { UNIT_GRI99, UNIT_GRI99, "GRI99", "GRI99", NULL }, - { UNIT_GRI99, 0, "GRI909", "GRI909", NULL }, - { UNIT_AO, UNIT_AO, "AO", "AO", NULL }, - { UNIT_AO, 0, "no AO", "NOAO", NULL }, - { UNIT_EAO, UNIT_EAO, "EAO", "EAO", NULL }, - { UNIT_EAO, 0, "no EAO", "NOEAO", NULL }, - { UNIT_GPR, UNIT_GPR, "GPR", "GPR", NULL }, - { UNIT_GPR, 0, "no GPR", "NOGPR", NULL }, - { UNIT_BSWPK, UNIT_BSWPK, "BSW-BPK", "BSW-BPK", NULL }, - { UNIT_BSWPK, 0, "no BSW-BPK", "NOBSW-BPK", NULL }, - { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size }, - { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size }, - { UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size }, - { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size }, - { UNIT_MSIZE, 20480, NULL, "20K", &cpu_set_size }, - { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size }, - { UNIT_MSIZE, 28672, NULL, "28K", &cpu_set_size }, - { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size }, - { 0 } - }; - -DEVICE cpu_dev = { - "CPU", &cpu_unit, cpu_reg, cpu_mod, - 1, 8, 15, 1, 8, 16, - &cpu_ex, &cpu_dep, &cpu_reset, - NULL, NULL, NULL - }; - -t_stat sim_instr (void) -{ -uint32 src, dst, op, t, jmp; -t_stat reason; - -/* Restore register state */ - -SC = SC & AMASK; /* load local PC */ -reason = 0; -ao_update (); /* update AO */ - -/* 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 (bkp) { /* breakpoint? */ - bkp = 0; /* clear request */ - dev_done = dev_done & ~INT_ON; /* int off */ - M[VEC_BKP] = SC; /* save SC */ - SC = VEC_BKP + 1; /* new SC */ - } - - else if ((dev_done & (INT_PENDING | ISR)) > (INT_PENDING)) { /* intr? */ - int32 i, vec; - t = dev_done & ISR; /* find hi pri */ - for (i = 15; i >= 0; i--) { - if ((t >> i) & 1) - break; - } - if ((i < 0) || ((vec = vec_map[i]) < 0)) { /* undefined? */ - reason = STOP_ILLINT; /* stop */ - break; - } - dev_done = dev_done & ~INT_ON; /* int off */ - M[vec] = SC; /* save SC */ - SC = vec + 1; /* new SC */ - continue; - } - - if (sim_brk_summ && sim_brk_test (SC, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; - } - - MA = SC; /* set mem addr */ - IR = M[MA]; /* fetch instr */ - dev_done = dev_done | INT_NODEF; /* clr ion defer */ - sim_interval = sim_interval - 1; - -/* Decode instruction types */ - - src = I_GETSRC (IR); /* src unit */ - dst = I_GETDST (IR); /* dst unit */ - op = I_GETOP (IR); /* bus op */ - - if (src == U_FSK) { /* func out? */ - reason = dev_tab[dst].FO (op); /* send function */ - SC = (SC + 1) & AMASK; /* incr SC */ - } - - else if (dst == U_FSK) { /* skip func? */ - t = dev_tab[src].SF (op & ~1); /* issue SF */ - reason = t >> SF_V_REASON; - if ((t ^ op) & 1) /* skip? */ - SC = SC + 2; - SC = (SC + 1) & AMASK; /* incr SC */ - } - - else if ((src != U_MEM) && (dst == U_TRP)) { /* cond jump */ - t = dev_tab[src].Src (src); /* get source */ - switch (op >> 1) { /* case on jump */ - - case 00: /* never */ - jmp = 0; - break; - - case 01: /* always */ - jmp = 1; - break; - - case 02: /* src == 0 */ - jmp = (t == 0); - break; - - case 03: /* src != 0 */ - jmp = (t != 0); - break; - - case 04: /* src < 0 */ - jmp = (t >= SIGN); - break; - - case 05: /* src >= 0 */ - jmp = (t < SIGN); - break; - - case 06: /* src <= 0 */ - jmp = (t == 0) || (t & SIGN); - break; - - case 07: /* src > 0 */ - jmp = (t != 0) && !(t & SIGN); - break; - } - - if (jmp) { /* jump taken? */ - SCQ_ENTRY; /* save SC */ - SC = (SC + 1) & AMASK; /* incr SC once */ - MA = M[SC]; /* get jump addr */ - MA = IDX_ADD (MA); /* index? */ - if (op & TRP_DEF) { /* defer? */ - t = (M[MA] + 1) & DMASK; /* autoinc */ - if (MEM_ADDR_OK (MA)) - M[MA] = t; - MA = IDX_ADD (t); /* index? */ - } - TRP = SC; /* save SC */ - SC = MA; /* load new SC */ - } - else SC = (SC + 2) & AMASK; /* incr SC twice */ - } - - else if ((src != U_MEM) && (dst != U_MEM)) { /* reg-reg? */ - reason = bus_op (src, op, dst); /* xmt and modify */ - SC = (SC + 1) & AMASK; /* incr SC */ - } - -/* Memory reference. The second SC increment occurs after the first - execution cycle. For direct, defer, and immediate defer, this is - after the first memory read and before the bus transfer; but for - immediate, it is after the bus transfer. -*/ - - else { /* memory reference */ - SC = (SC + 1) & AMASK; /* incr SC */ - switch (op & MEM_MOD) { /* case on addr mode */ - - case MEM_DIR: /* direct */ - MA = M[SC]; /* get address */ - MA = IDX_ADD (MA); /* index? */ - SC = (SC + 1) & AMASK; /* incr SC again */ - reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */ - break; - - case MEM_DEF: /* defer */ - MA = M[SC]; /* get ind addr */ - MA = IDX_ADD (MA); /* index? */ - SC = (SC + 1) & AMASK; /* incr SC again */ - t = (M[MA] + 1) & DMASK; /* autoinc */ - if (MEM_ADDR_OK (MA)) - M[MA] = t; - MA = IDX_ADD (t); /* index? */ - reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */ - break; - - case MEM_IMM: /* immediate */ - MA = SC; /* eff addr */ - reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */ - SC = (SC + 1) & AMASK; /* incr SC again */ - break; - - case MEM_IDF: /* immediate defer */ - MA = SC; /* get ind addr */ - t = (M[MA] + 1) & DMASK; /* autoinc */ - if (MEM_ADDR_OK (MA)) - M[MA] = t; - MA = IDX_ADD (t); /* index? */ - SC = (SC + 1) & AMASK; /* incr SC again */ - reason = bus_op (src, op & BUS_FNC, dst); /* xmt and modify */ - break; - } /* end switch */ - } /* end mem ref */ - } /* end while */ - -/* Simulation halted */ - -ao_update (); /* update AO */ -scq_r->qptr = scq_p; /* update sc q ptr */ -return reason; -} - -/* Bus operations */ - -t_stat bus_op (uint32 src, uint32 op, uint32 dst) -{ -uint32 t, old_t; - -t = dev_tab[src].Src (src); /* get src */ -if (op & BUS_COM) /* complement? */ - t = t ^ DMASK; -switch (op & BUS_FNC) { /* case op */ - - case BUS_P1: /* plus 1 */ - t = t + 1; /* do add */ - if (t & CBIT) /* set cry out */ - MSR = MSR | MSR_BOV; - else MSR = MSR & ~MSR_BOV; - break; - - case BUS_L1: /* left 1 */ - t = (t << 1) | ((MSR & MSR_L)? 1: 0); /* rotate */ - if (t & CBIT) /* set link out */ - MSR = MSR | MSR_L; - else MSR = MSR & ~MSR_L; - break; - - case BUS_R1: /* right 1 */ - old_t = t; - t = (t >> 1) | ((MSR & MSR_L)? SIGN: 0); /* rotate */ - if (old_t & 1) /* set link out */ - MSR = MSR | MSR_L; - else MSR = MSR & ~MSR_L; - break; - } /* end case op */ - -if (dst == thwh) /* display dst? */ - DR = t & DMASK; -return dev_tab[dst].Dst (dst, t & DMASK); /* store dst */ -} - -/* Non-existent device */ - -uint32 no_rd (uint32 src) -{ -return 0; -} - -t_stat no_wr (uint32 dst, uint32 dat) -{ -return stop_opr; -} - -t_stat no_fo (uint32 fnc) -{ -return stop_opr; -} - -uint32 no_sf (uint32 fnc) -{ -return (stop_opr << SF_V_REASON); -} - -/* Zero device */ - -uint32 zero_rd (uint32 src) -{ -return 0; -} - -t_stat zero_wr (uint32 dst, uint32 val) -{ -return SCPE_OK; -} - -t_stat zero_fo (uint32 op) -{ -switch (op & 3) { /* FOM link */ - - case 1: /* CLL */ - MSR = MSR & ~MSR_L; - break; - - case 2: /* STL */ - MSR = MSR | MSR_L; - break; - - case 3: /* CML */ - MSR = MSR ^ MSR_L; - break; - } - -if (op & 4) /* HALT */ - return STOP_HALT; -return SCPE_OK; -} - -uint32 zero_sf (uint32 op) -{ -if ((op & 010) || /* power always ok */ - ((op & 4) && (MSR & MSR_L)) || /* link set? */ - ((op & 2) && (MSR & MSR_BOV))) /* BOV set? */ - return 1; -return 0; -} - -/* Instruction register (01) */ - -uint32 ir_rd (uint32 src) -{ -return IR; -} - -t_stat ir_fo (uint32 op) -{ -if (op & 2) - bkp = 1; -return SCPE_OK; -} - -/* Trap register (03) */ - -uint32 trp_rd (uint32 src) -{ -return TRP; -} - -t_stat trp_wr (uint32 dst, uint32 val) -{ -TRP = val; -return SCPE_OK; -} - -/* Interrupt status register (04) */ - -uint32 isr_rd (uint32 src) -{ -return ISR; -} - -t_stat isr_wr (uint32 dst, uint32 dat) -{ -ISR = dat; -return SCPE_OK; -} - -t_stat isr_fo (uint32 op) -{ -if (op & ISR_ON) - dev_done = (dev_done | INT_ON) & ~INT_NODEF; -if (op & ISR_OFF) - dev_done = dev_done & ~INT_ON; -return SCPE_OK; -} - -uint32 isr_sf (uint32 op) -{ -return 0; -} - -/* Memory address (05) */ - -uint32 ma_rd (uint32 src) -{ -return MA; -} - -/* Memory (06) */ - -uint32 mem_rd (uint32 src) -{ -return M[MA]; -} - -t_stat mem_wr (uint32 dst, uint32 dat) -{ - -if (MEM_ADDR_OK (MA)) - M[MA] = dat; -return SCPE_OK; -} - -/* Sequence counter (07) */ - -uint32 sc_rd (uint32 src) -{ -return SC; -} - -t_stat sc_wr (uint32 dst, uint32 dat) -{ -SCQ_ENTRY; -SC = IDX_ADD (dat); -return SCPE_OK; -} - -/* Switch register (10) */ - -uint32 swr_rd (uint32 src) -{ -return SWR; -} - -/* Machine status register (17) */ - -uint32 msr_rd (uint32 src) -{ -return MSR & MSR_RW; -} - -t_stat msr_wr (uint32 src, uint32 dat) -{ -MSR = dat & MSR_RW; /* new MSR */ -ao_update (); /* update SOV,AOV */ -return SCPE_OK; -} - -/* Arithmetic operator (11:13) */ - -uint32 ao_update (void) -{ -uint32 af = MSR_GET_FOA (MSR); - -switch (af) { - - case AO_ADD: - AO = (AX + AY) & DMASK; /* add */ - break; - - case AO_AND: - AO = AX & AY; /* and */ - break; - - case AO_XOR: /* xor */ - AO = AX ^ AY; - break; - - case AO_IOR: - AO = AX | AY; /* or */ - break; - } - -if ((AX + AY) & CBIT) /* always calc AOV */ - MSR = MSR | MSR_AOV; -else MSR = MSR & ~MSR_AOV; -if (SIGN & ((AX ^ (AX + AY)) & (~AX ^ AY))) /* always calc SOV */ - MSR = MSR | MSR_SOV; -else MSR = MSR & ~MSR_SOV; -return AO; -} - -uint32 ax_rd (uint32 src) -{ -if (cpu_unit.flags & UNIT_AO) - return AX; -else return 0; -} - -t_stat ax_wr (uint32 dst, uint32 dat) -{ -if (cpu_unit.flags & UNIT_AO) { - AX = dat; - ao_update (); - return SCPE_OK; - } -return stop_opr; -} - -uint32 ay_rd (uint32 src) -{ -if (cpu_unit.flags & UNIT_AO) - return AY; -else return 0; -} - -t_stat ay_wr (uint32 dst, uint32 dat) -{ -if (cpu_unit.flags & UNIT_AO) { - AY = dat; - ao_update (); - return SCPE_OK; - } -return stop_opr; -} - -uint32 ao_rd (uint32 src) -{ -if (cpu_unit.flags & UNIT_AO) - return ao_update (); -else return 0; -} - -t_stat ao_fo (uint32 op) -{ -if (cpu_unit.flags & UNIT_AO) { - uint32 t = OP_GET_FOA (op); /* get func */ - MSR = MSR_PUT_FOA (MSR, t); /* store in MSR */ - ao_update (); /* update AOV */ - return SCPE_OK; - } -return stop_opr; -} - -uint32 ao_sf (uint32 op) -{ -if (!(cpu_unit.flags & UNIT_AO)) /* not installed? */ - return (stop_opr << SF_V_REASON); -if (((op & 2) && (MSR & MSR_AOV)) || /* arith carry? */ - ((op & 4) && (MSR & MSR_SOV))) /* arith overflow? */ - return 1; -return 0; -} - -/* Extended arithmetic operator (14) */ - -t_stat eao_fo (uint32 op) -{ -uint32 t; - -if (!(cpu_unit.flags & UNIT_EAO)) /* EAO installed? */ - return stop_opr; -switch (op) { - - case EAO_MUL: /* mul? */ - t = AX * AY; /* AX * AY */ - AX = (t >> 16) & DMASK; /* to AX'GR1 */ - GR[0] = t & DMASK; - break; - - case EAO_DIV: /* div? */ - if (AY && (AX < AY)) { - t = (AX << 16) | GR[0]; /* AX'GR1 / AY */ - GR[0] = t / AY; /* quo to GR1 */ - AX = t % AY; /* rem to AX */ - MSR = MSR & ~MSR_L; /* clear link */ - } - else MSR = MSR | MSR_L; /* set link */ - break; - - case EAO_ARS: /* arith right? */ - t = 0; /* shift limiter */ - if (AX & SIGN) /* L = sign */ - MSR = MSR | MSR_L; - else MSR = MSR & ~MSR_L; - do { /* shift one bit */ - AY = ((AY >> 1) | (AX << 15)) & DMASK; - AX = (AX & SIGN) | (AX >> 1); - GR[0] = (GR[0] + 1) & DMASK; - } - while (GR[0] && (++t < 32)); /* until cnt or limit */ - break; - - case EAO_NORM: /* norm? */ - if ((AX | AY) != 0) { /* can normalize? */ - while ((AX & SIGN) != ((AX << 1) & SIGN)) { /* until AX15 != AX14 */ - AX = ((AX << 1) | (AY >> 15)) & DMASK; - AY = (AY << 1) & DMASK; - GR[0] = (GR[0] + 1) & DMASK; - } - } - break; - } - -// MSR = MSR_PUT_FOA (MSR, AO_ADD); /* AO fnc is add */ -ao_update (); -return SCPE_OK; -} - -/* Index register (GRI-99) (22) */ - -uint32 xr_rd (uint32 src) -{ -if (cpu_unit.flags & UNIT_GRI99) - return XR; -else return 0; -} - -t_stat xr_wr (uint32 dst, uint32 val) -{ -if (cpu_unit.flags & UNIT_GRI99) { - XR = val; - return SCPE_OK; - } -return stop_opr; -} - -/* Alternate trap (GRI-99) (23) */ - -uint32 atrp_rd (uint32 src) -{ -if (cpu_unit.flags & UNIT_GRI99) - return TRP; -else return 0; -} - -t_stat atrp_wr (uint32 dst, uint32 val) -{ -if (cpu_unit.flags & UNIT_GRI99) { - TRP = val; - return SCPE_OK; - } -return stop_opr; -} - -/* Byte swapper (24) */ - -uint32 bsw_rd (uint32 src) -{ -if (cpu_unit.flags & UNIT_BSWPK) - return BSW; -else return 0; -} - -t_stat bsw_wr (uint32 dst, uint32 val) -{ -if (cpu_unit.flags & UNIT_BSWPK) { - BSW = ((val >> 8) & 0377) | ((val & 0377) << 8); - return SCPE_OK; - } -return stop_opr; -} - -/* Byte packer (25) */ - -uint32 bpk_rd (uint32 src) -{ -if (cpu_unit.flags & UNIT_BSWPK) - return BPK; -else return 0; -} - -t_stat bpk_wr (uint32 dst, uint32 val) -{ -if (cpu_unit.flags & UNIT_BSWPK) { - BPK = ((BPK & 0377) << 8) | (val & 0377); - return SCPE_OK; - } -return stop_opr; -} - -/* General registers (30:35) */ - -uint32 gr_rd (uint32 src) -{ -if (cpu_unit.flags & UNIT_GPR) - return GR[src - U_GR]; -else return 0; -} - -t_stat gr_wr (uint32 dst, uint32 dat) -{ -if (cpu_unit.flags & UNIT_GPR) { - GR[dst - U_GR] = dat; - return SCPE_OK; - } -return stop_opr; -} - -/* Reset routine */ - -t_stat cpu_reset (DEVICE *dptr) -{ -int32 i; - -AX = AY = AO = 0; -XR = 0; -TRP = 0; -ISR = 0; -MSR = 0; -MA = IR = 0; -BSW = BPK = 0; -for (i = 0; i < 6; i++) - GR[i] = 0; -dev_done = dev_done & ~INT_PENDING; -scq_r = find_reg ("SCQ", NULL, dptr); -if (scq_r) - scq_r->qptr = 0; -else return SCPE_IERR; -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] & DMASK; -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 & DMASK; -return SCPE_OK; -} - -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 mc = 0; -uint32 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; -} diff --git a/GRI/gri_defs.h b/GRI/gri_defs.h deleted file mode 100644 index 82e8fb7e..00000000 --- a/GRI/gri_defs.h +++ /dev/null @@ -1,256 +0,0 @@ -/* gri_defs.h: GRI-909 simulator definitions - - Copyright (c) 2001-2015, 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. - - 22-May-10 RMS Added check for 64b definitions - 12-Jan-08 RMS Added GRI-99 support - 25-Apr-03 RMS Revised for extended file support - 19-Sep-02 RMS Fixed declarations in gdev structure - - There are several discrepancies between the original GRI-909 Reference - Manual of 1969 and the only surviving code sample, the MIT Crystal Growing - System of 1972. These discrepancies were clarified by later documentation: - - 1. Ref Manual documents two GR's at codes 26-27; MITCS documents six GR's - at 30-35. Answer: 6 GR's, 26-27 were used for character compares. - 2. Ref Manual documents only unsigned overflow (carry) for arithmetic - operator; MITCS uses both unsigned overflow (AOV) and signed overflow - (SOV). Answer: signed and unsigned. - 3. Ref Manual documents a ROM-subroutine multiply operator and mentions - but does not document a "fast multiply"; MITCS uses an extended - arithmetic operator with multiply, divide, and shift. Answer: EAO - is a package of ROM subroutines with just four functions: multiply, - divide, arithmetic right shift, and normalize. - 4. Is SOV testable even if the FOA is not ADD? Answer: AOV and SOV are - calculated regardless of the function. - 5. How does the EAO handle divide overflow? Answer: set link. -*/ - -#ifndef GRI_DEFS_H_ -#define GRI_DEFS_H_ 0 - -#include "sim_defs.h" /* simulator defns */ - -#if defined(USE_INT64) || defined(USE_ADDR64) -#error "GRI does not support 64b values!" -#endif - -/* Simulator stop codes */ - -#define STOP_DEV 1 /* must be 1 */ -#define STOP_HALT 2 /* HALT */ -#define STOP_IBKPT 3 /* breakpoint */ -#define STOP_ILLINT 4 /* illegal intr */ - -/* Memory */ - -#define MAXMEMSIZE 32768 /* max memory size */ -#define AMASK 077777 /* logical addr mask */ -#define MEMSIZE (cpu_unit.capac) /* actual memory size */ -#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) - -/* Architectural constants */ - -#define SIGN 0100000 /* sign */ -#define INDEX 0100000 /* indexed (GRI-99) */ -#define DMASK 0177777 /* data mask */ -#define CBIT (DMASK + 1) /* carry bit */ - -/* Instruction format */ - -#define I_M_SRC 077 /* source */ -#define I_V_SRC 10 -#define I_GETSRC(x) (((x) >> I_V_SRC) & I_M_SRC) -#define I_M_OP 017 /* operator */ -#define I_V_OP 6 -#define I_GETOP(x) (((x) >> I_V_OP) & I_M_OP) -#define I_M_DST 077 /* destination */ -#define I_V_DST 0 -#define I_GETDST(x) (((x) >> I_V_DST) & I_M_DST) -#define SF_V_REASON 1 /* SF reason */ - -/* IO return */ - -#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */ - -/* Operators */ - -#define U_ZERO 000 /* zero */ -#define U_IR 001 /* instruction reg */ -#define U_FSK 002 /* func out/skip */ -#define U_TRP 003 /* trap */ -#define U_ISR 004 /* intr status */ -#define U_MA 005 /* mem addr */ -#define U_MEM 006 /* mem data */ -#define U_SC 007 /* seq counter */ -#define U_SWR 010 /* switch register */ -#define U_AX 011 /* arith in 1 */ -#define U_AY 012 /* arith in 2 */ -#define U_AO 013 /* arith out */ -#define U_EAO 014 /* ext arith */ -#define U_MSR 017 /* machine status */ -#define U_XR 022 /* GRI-99: idx reg */ -#define U_GTRP 023 /* GRI-99: alt trap */ -#define U_BSW 024 /* byte swap */ -#define U_BPK 025 /* byte pack */ -#define U_BCP1 026 /* byte compare 1 */ -#define U_BCP2 027 /* byte compare 2 */ -#define U_GR 030 /* hex general regs */ -#define U_CDR 055 /* card reader */ -#define U_CADR 057 -#define U_DWC 066 /* disk */ -#define U_DCA 067 -#define U_DISK 070 -#define U_LPR 071 /* line printer */ -#define U_CAS 074 /* casette */ -#define U_RTC 075 /* clock */ -#define U_HS 076 /* paper tape */ -#define U_TTY 077 /* console */ - -struct gdev { - uint32 (*Src)(uint32); /* source */ - t_stat (*Dst)(uint32, uint32); /* dest */ - t_stat (*FO)(uint32); /* func out */ - uint32 (*SF)(uint32); /* skip func */ -}; - -/* Trap (jump) */ - -#define TRP_DIR 00 /* direct */ -#define TRP_DEF 01 /* defer */ - -/* Interrupt status */ - -#define ISR_OFF 01 /* int off */ -#define ISR_ON 02 /* int on */ - -/* Bus modifiers */ - -#define BUS_COM 002 /* complement */ -#define BUS_FNC 014 /* function mask */ -#define BUS_P1 004 /* + 1 */ -#define BUS_L1 010 /* rotate left */ -#define BUS_R1 014 /* rotate right */ - -/* Memory address modes */ - -#define MEM_MOD 03 -#define MEM_DIR 00 /* direct */ -#define MEM_DEF 01 /* defer */ -#define MEM_IMM 02 /* immediate */ -#define MEM_IDF 03 /* immediate defer */ - -/* Arithmetic unit */ - -#define FO_V_FOA 8 /* arith func */ -#define FO_M_FOA 03 -#define OP_GET_FOA(x) (((x) >> (FO_V_FOA - I_V_OP)) & FO_M_FOA) -#define AO_ADD 00 /* add */ -#define AO_AND 01 /* and */ -#define AO_XOR 02 /* xor */ -#define AO_IOR 03 /* or */ -#define EAO_MUL 01 /* multiply */ -#define EAO_DIV 02 /* divide */ -#define EAO_ARS 03 /* arith rshft */ -#define EAO_NORM 04 /* normalize */ - -/* Machine status */ - -#define MSR_V_BOV 15 /* bus carry */ -#define MSR_V_L 14 /* bus link */ -#define MSR_V_FOA 8 /* arith func */ -#define MSR_M_FOA 03 -#define MSR_V_SOV 1 /* arith ovflo */ -#define MSR_V_AOV 0 /* arith carry */ -#define MSR_BOV (1u << MSR_V_BOV) -#define MSR_L (1u << MSR_V_L) -#define MSR_FOA (MSR_M_FOA << MSR_V_FOA) -#define MSR_SOV (1u << MSR_V_SOV) -#define MSR_AOV (1u << MSR_V_AOV) -#define MSR_GET_FOA(x) (((x) >> MSR_V_FOA) & MSR_M_FOA) -#define MSR_PUT_FOA(x,n) (((x) & ~(MSR_M_FOA << MSR_V_FOA)) | \ - (((n) & MSR_M_FOA) << MSR_V_FOA)) -#define MSR_RW (MSR_BOV|MSR_L|MSR_FOA|MSR_SOV|MSR_AOV) - -/* Real time clock */ - -#define RTC_OFF 001 /* off */ -#define RTC_ON 002 /* clock on */ -#define RTC_OV 010 /* clock flag */ -#define RTC_CTR 0103 /* counter */ - -/* Terminal */ - -#define TTY_ORDY 002 /* output flag */ -#define TTY_IRDY 010 /* input flag */ - -/* Paper tape */ - -#define PT_STRT 001 /* start reader */ -#define PT_ORDY 002 /* output flag */ -#define PT_IRDY 010 /* input flag */ - -/* Interrupt masks (ISR) */ - -#define INT_V_TTO 0 /* console out */ -#define INT_V_TTI 1 /* console in */ -#define INT_V_HSP 2 /* paper tape punch */ -#define INT_V_HSR 3 /* paper tape reader */ -#define INT_V_LPR 5 /* line printer */ -#define INT_V_CDR 7 /* card reader */ -#define INT_V_CASW 9 /* casette */ -#define INT_V_CASR 10 -#define INT_V_RTC 11 /* clock */ -#define INT_V_DISK 14 /* disk */ -#define INT_V_NODEF 16 /* nodefer */ -#define INT_V_ON 17 /* enable */ -#define INT_TTO (1u << INT_V_TTO) -#define INT_TTI (1u << INT_V_TTI) -#define INT_HSP (1u << INT_V_HSP) -#define INT_HSR (1u << INT_V_HSR) -#define INT_LPR (1u << INT_V_LPR) -#define INT_CDR (1u << INT_V_CDR) -#define INT_CASW (1u << INT_V_CAS1) -#define INT_CASR (1u << INT_V_CAS2) -#define INT_RTC (1u << INT_V_RTC) -#define INT_DISK (1u << INT_V_DISK) -#define INT_NODEF (1u << INT_V_NODEF) -#define INT_ON (1u << INT_V_ON) -#define INT_PENDING (INT_ON | INT_NODEF) - -/* Vectors */ - -#define VEC_BKP 0000 /* breakpoint */ -#define VEC_TTO 0011 /* console out */ -#define VEC_TTI 0014 /* console in */ -#define VEC_HSP 0017 /* paper tape punch */ -#define VEC_HSR 0022 /* paper tape reader */ -#define VEC_LPR 0033 /* line printer */ -#define VEC_CDR 0033 /* card reader */ -#define VEC_CASW 0044 /* casette */ -#define VEC_CASR 0047 -#define VEC_DISK 0055 /* disk */ -#define VEC_RTC 0100 /* clock */ - -#endif diff --git a/GRI/gri_stddev.c b/GRI/gri_stddev.c deleted file mode 100644 index 3636c8ce..00000000 --- a/GRI/gri_stddev.c +++ /dev/null @@ -1,426 +0,0 @@ -/* gri_stddev.c: GRI-909 standard devices - - Copyright (c) 2001-2016, 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. - - tti S42-001 terminal input - tto S42-002 terminal output - hsr S42-004 high speed reader - hsp S42-006 high speed punch - rtc real time clock - - 05-May-16 RMS Fixed calling sequence inconsistencies (Mark Pizzolato) - 28-Mar-15 RMS Revised to use sim_printf - 31-May-08 RMS Fixed declarations (Peter Schorn) - 30-Sep-06 RMS Fixed handling of non-printable characters in KSR mode - 22-Nov-05 RMS Revised for new terminal processing routines - 29-Dec-03 RMS Added support for console backpressure - 25-Apr-03 RMS Revised for extended file support - 22-Dec-02 RMS Added break support - 01-Nov-02 RMS Added 7b/8B support to terminal -*/ - -#include "gri_defs.h" -#include - -uint32 hsr_stopioe = 1, hsp_stopioe = 1; - -extern uint16 M[]; -extern uint32 dev_done, ISR; - -t_stat tti_svc (UNIT *uhsr); -t_stat tto_svc (UNIT *uhsr); -t_stat tti_reset (DEVICE *dhsr); -t_stat tto_reset (DEVICE *dhsr); -t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat hsr_svc (UNIT *uhsr); -t_stat hsp_svc (UNIT *uhsr); -t_stat hsr_reset (DEVICE *dhsr); -t_stat hsp_reset (DEVICE *dhsr); -t_stat rtc_svc (UNIT *uhsr); -t_stat rtc_reset (DEVICE *dhsr); -int32 rtc_tps = 1000; - -/* TTI data structures - - tti_dev TTI device descriptor - tti_unit TTI unit descriptor - tti_reg TTI register list - tti_mod TTI modifiers list -*/ - -UNIT tti_unit = { UDATA (&tti_svc, TT_MODE_KSR, 0), KBD_POLL_WAIT }; - -REG tti_reg[] = { - { ORDATA (BUF, tti_unit.buf, 8) }, - { FLDATA (IRDY, dev_done, INT_V_TTI) }, - { FLDATA (IENB, ISR, INT_V_TTI) }, - { DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, - { NULL } - }; - -MTAB tti_mod[] = { - { TT_MODE, TT_MODE_KSR, "KSR", "KSR", &tty_set_mode }, - { TT_MODE, TT_MODE_7B, "7b", "7B", &tty_set_mode }, - { TT_MODE, TT_MODE_8B, "8b", "8B", &tty_set_mode }, - { TT_MODE, TT_MODE_7P, "7b", NULL, NULL }, - { 0 } - }; - -DEVICE tti_dev = { - "TTI", &tti_unit, tti_reg, tti_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &tti_reset, - NULL, NULL, NULL - }; - -/* TTO data structures - - tto_dev TTO device descriptor - tto_unit TTO unit descriptor - tto_reg TTO register list -*/ - -UNIT tto_unit = { UDATA (&tto_svc, TT_MODE_KSR, 0), SERIAL_OUT_WAIT }; - -REG tto_reg[] = { - { ORDATA (BUF, tto_unit.buf, 8) }, - { FLDATA (ORDY, dev_done, INT_V_TTO) }, - { FLDATA (IENB, ISR, INT_V_TTO) }, - { DRDATA (POS, tto_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT }, - { NULL } - }; - -MTAB tto_mod[] = { - { TT_MODE, TT_MODE_KSR, "KSR", "KSR", &tty_set_mode }, - { TT_MODE, TT_MODE_7B, "7b", "7B", &tty_set_mode }, - { TT_MODE, TT_MODE_8B, "8b", "8B", &tty_set_mode }, - { TT_MODE, TT_MODE_7P, "7p", "7P", &tty_set_mode }, - { 0 } - }; - -DEVICE tto_dev = { - "TTO", &tto_unit, tto_reg, tto_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &tto_reset, - NULL, NULL, NULL - }; - -/* HSR data structures - - hsr_dev HSR device descriptor - hsr_unit HSR unit descriptor - hsr_reg HSR register list - hsr_mod HSR modifiers list -*/ - -UNIT hsr_unit = { - UDATA (&hsr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), SERIAL_IN_WAIT - }; - -REG hsr_reg[] = { - { ORDATA (BUF, hsr_unit.buf, 8) }, - { FLDATA (IRDY, dev_done, INT_V_HSR) }, - { FLDATA (IENB, ISR, INT_V_HSR) }, - { DRDATA (POS, hsr_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, hsr_unit.wait, 24), REG_NZ + PV_LEFT }, - { FLDATA (STOP_IOE, hsr_stopioe, 0) }, - { NULL } - }; - -DEVICE hsr_dev = { - "HSR", &hsr_unit, hsr_reg, NULL, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &hsr_reset, - NULL, NULL, NULL - }; - -/* HSP data structures - - hsp_dev HSP device descriptor - hsp_unit HSP unit descriptor - hsp_reg HSP register list -*/ - -UNIT hsp_unit = { - UDATA (&hsp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT - }; - -REG hsp_reg[] = { - { ORDATA (BUF, hsp_unit.buf, 8) }, - { FLDATA (ORDY, dev_done, INT_V_HSP) }, - { FLDATA (IENB, ISR, INT_V_HSP) }, - { DRDATA (POS, hsp_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, hsp_unit.wait, 24), PV_LEFT }, - { FLDATA (STOP_IOE, hsp_stopioe, 0) }, - { NULL } - }; - -DEVICE hsp_dev = { - "HSP", &hsp_unit, hsp_reg, NULL, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &hsp_reset, - NULL, NULL, NULL - }; - -/* RTC data structures - - rtc_dev RTC device descriptor - rtc_unit RTC unit descriptor - rtc_reg RTC register list -*/ - -UNIT rtc_unit = { UDATA (&rtc_svc, 0, 0), 16000 }; - -REG rtc_reg[] = { - { FLDATA (RDY, dev_done, INT_V_RTC) }, - { FLDATA (IENB, ISR, INT_V_RTC) }, - { DRDATA (TIME, rtc_unit.wait, 24), REG_NZ + PV_LEFT }, - { DRDATA (TPS, rtc_tps, 8), REG_NZ + PV_LEFT + REG_HIDDEN }, - { NULL } - }; - -DEVICE rtc_dev = { - "RTC", &rtc_unit, rtc_reg, NULL, - 1, 0, 0, 0, 0, 0, - NULL, NULL, &rtc_reset, - NULL, NULL, NULL - }; - -/* Console terminal function processors */ - -uint32 tty_rd (uint32 src) -{ -return tti_unit.buf; /* return data */ -} - -t_stat tty_wr (uint32 dst, uint32 val) -{ -tto_unit.buf = val & 0377; /* save char */ -dev_done = dev_done & ~INT_TTO; /* clear ready */ -sim_activate (&tto_unit, tto_unit.wait); /* activate unit */ -return SCPE_OK; -} - -t_stat tty_fo (uint32 op) -{ -if (op & TTY_IRDY) - dev_done = dev_done & ~INT_TTI; -if (op & TTY_ORDY) - dev_done = dev_done & ~INT_TTO; -return SCPE_OK; -} - -uint32 tty_sf (uint32 op) -{ -if (((op & TTY_IRDY) && (dev_done & INT_TTI)) || - ((op & TTY_ORDY) && (dev_done & INT_TTO))) - return 1; -return 0; -} - -/* Service routines */ - -t_stat tti_svc (UNIT *uptr) -{ -int32 c; - -sim_activate (uptr, uptr->wait); /* continue poll */ -if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */ - return c; -if (c & SCPE_BREAK) /* break? */ - uptr->buf = 0; -else uptr->buf = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags) | TTUF_KSR); -dev_done = dev_done | INT_TTI; /* set ready */ -uptr->pos = uptr->pos + 1; -return SCPE_OK; -} - -t_stat tto_svc (UNIT *uptr) -{ -int32 c; -t_stat r; - -c = sim_tt_outcvt (uptr->buf, TT_GET_MODE (uptr->flags) | TTUF_KSR); -if (c >= 0) { - if ((r = sim_putchar_s (c)) != SCPE_OK) { /* output; error? */ - sim_activate (uptr, uptr->wait); /* try again */ - return ((r == SCPE_STALL)? SCPE_OK: r); /* !stall? report */ - } - } -dev_done = dev_done | INT_TTO; /* set ready */ -uptr->pos = uptr->pos + 1; -return SCPE_OK; -} - -/* Reset routines */ - -t_stat tti_reset (DEVICE *dptr) -{ -tti_unit.buf = 0; /* clear buffer */ -dev_done = dev_done & ~INT_TTI; /* clear ready */ -sim_activate (&tti_unit, tti_unit.wait); /* activate unit */ -return SCPE_OK; -} - -t_stat tto_reset (DEVICE *dptr) -{ -tto_unit.buf = 0; /* clear buffer */ -dev_done = dev_done | INT_TTO; /* set ready */ -sim_cancel (&tto_unit); /* deactivate unit */ -return SCPE_OK; -} - -t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -tti_unit.flags = (tti_unit.flags & ~TT_MODE) | val; -tto_unit.flags = (tto_unit.flags & ~TT_MODE) | val; -return SCPE_OK; -} - -/* High speed paper tape function processors */ - -uint32 hsrp_rd (uint32 src) -{ -return hsr_unit.buf; /* return data */ -} - -t_stat hsrp_wr (uint32 dst, uint32 val) -{ -hsp_unit.buf = val & 0377; /* save char */ -dev_done = dev_done & ~INT_HSP; /* clear ready */ -sim_activate (&hsp_unit, hsp_unit.wait); /* activate unit */ -return SCPE_OK; -} - -t_stat hsrp_fo (uint32 op) -{ -if (op & PT_IRDY) - dev_done = dev_done & ~INT_HSR; -if (op & PT_ORDY) - dev_done = dev_done & ~INT_HSP; -if (op & PT_STRT) - sim_activate (&hsr_unit, hsr_unit.wait); -return SCPE_OK; -} - -uint32 hsrp_sf (uint32 op) -{ -if (((op & PT_IRDY) && (dev_done & INT_HSR)) || - ((op & PT_ORDY) && (dev_done & INT_HSP))) - return 1; -return 0; -} - -t_stat hsr_svc (UNIT *uptr) -{ -int32 temp; - -if ((hsr_unit.flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (hsr_stopioe, SCPE_UNATT); -if ((temp = getc (hsr_unit.fileref)) == EOF) { /* read char */ - if (feof (hsr_unit.fileref)) { /* err or eof? */ - if (hsr_stopioe) - sim_printf ("HSR end of file\n"); - else return SCPE_OK; - } - else perror ("HSR I/O error"); - clearerr (hsr_unit.fileref); - return SCPE_IOERR; - } -dev_done = dev_done | INT_HSR; /* set ready */ -hsr_unit.buf = temp & 0377; /* save char */ -hsr_unit.pos = hsr_unit.pos + 1; -return SCPE_OK; -} - -t_stat hsp_svc (UNIT *uptr) -{ -dev_done = dev_done | INT_HSP; /* set ready */ -if ((hsp_unit.flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (hsp_stopioe, SCPE_UNATT); -if (putc (hsp_unit.buf, hsp_unit.fileref) == EOF) { /* write char */ - perror ("HSP I/O error"); /* error? */ - clearerr (hsp_unit.fileref); - return SCPE_IOERR; - } -hsp_unit.pos = hsp_unit.pos + 1; -return SCPE_OK; -} - -/* Reset routines */ - -t_stat hsr_reset (DEVICE *dptr) -{ -hsr_unit.buf = 0; /* clear buffer */ -dev_done = dev_done & ~INT_HSR; /* clear ready */ -sim_cancel (&hsr_unit); /* deactivate unit */ -return SCPE_OK; -} - -t_stat hsp_reset (DEVICE *dptr) -{ -hsp_unit.buf = 0; /* clear buffer */ -dev_done = dev_done | INT_HSP; /* set ready */ -sim_cancel (&hsp_unit); /* deactivate unit */ -return SCPE_OK; -} - -/* Clock function processors */ - -t_stat rtc_fo (uint32 op) -{ -if (op & RTC_OFF) /* clock off? */ - sim_cancel (&rtc_unit); -if ((op & RTC_ON) && !sim_is_active (&rtc_unit)) /* clock on? */ - sim_activate (&rtc_unit, sim_rtc_init (rtc_unit.wait)); -if (op & RTC_OV) /* clr ovflo? */ - dev_done = dev_done & ~INT_RTC; -return SCPE_OK; -} - -uint32 rtc_sf (uint32 op) -{ -if ((op & RTC_OV) && (dev_done & INT_RTC)) - return 1; -return 0; -} - -t_stat rtc_svc (UNIT *uptr) -{ -M[RTC_CTR] = (M[RTC_CTR] + 1) & DMASK; /* incr counter */ -if (M[RTC_CTR] == 0) /* ovflo? set ready */ - dev_done = dev_done | INT_RTC; -sim_activate (&rtc_unit, sim_rtc_calb (rtc_tps)); /* reactivate */ -return SCPE_OK; -} - -t_stat rtc_reset (DEVICE *dptr) -{ -sim_register_clock_unit (&rtc_unit); /* declare clock unit */ -dev_done = dev_done & ~INT_RTC; /* clear ready */ -sim_cancel (&rtc_unit); /* stop clock */ -return SCPE_OK; -} diff --git a/GRI/gri_sys.c b/GRI/gri_sys.c deleted file mode 100644 index efda01eb..00000000 --- a/GRI/gri_sys.c +++ /dev/null @@ -1,700 +0,0 @@ -/* gri_sys.c: GRI-909 simulator interface - - Copyright (c) 2001-2017, 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. - - 13-Mar-17 RMS Annotated fall through in switch - 14-Jan-08 RMS Added GRI-99 support - 18-Oct-02 RMS Fixed bug in symbolic decode (Hans Pufal) -*/ - -#include "gri_defs.h" -#include - -extern DEVICE cpu_dev; -extern UNIT cpu_unit; -extern DEVICE tti_dev, tto_dev; -extern DEVICE hsr_dev, hsp_dev; -extern DEVICE rtc_dev; -extern REG cpu_reg[]; -extern uint16 M[]; - -void fprint_addr (FILE *of, uint32 val, uint32 mod, uint32 dst); - -/* SCP data structures and interface routines - - sim_name simulator name string - sim_PC pointer to saved PC register descriptor - sim_emax maximum number of words for examine/deposit - sim_devices array of pointers to simulated devices - sim_stop_messages array of pointers to stop messages - sim_load binary loader -*/ - -char sim_name[] = "GRI-909"; - -REG *sim_PC = &cpu_reg[0]; - -int32 sim_emax = 2; - -DEVICE *sim_devices[] = { - &cpu_dev, - &tti_dev, - &tto_dev, - &hsr_dev, - &hsp_dev, - &rtc_dev, - NULL - }; - -const char *sim_stop_messages[] = { - "Unknown error", - "Unimplemented unit", - "HALT instruction", - "Breakpoint", - "Invalid interrupt request" - }; - -/* Binary loader - - Bootstrap loader format consists of blocks separated by zeroes. Each - word in the block has three frames: a control frame (ignored) and two - data frames. The user must specify the load address. Switch -c means - continue and load all blocks until end of tape. -*/ - -t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) -{ -int32 c; -uint32 org; -t_stat r; -char gbuf[CBUFSIZE]; - -if (*cptr != 0) { /* more input? */ - cptr = get_glyph (cptr, gbuf, 0); /* get origin */ - org = get_uint (gbuf, 8, AMASK, &r); - if (r != SCPE_OK) - return r; - if (*cptr != 0) /* no more */ - return SCPE_ARG; - } -else org = 0200; /* default 200 */ - -for (;;) { /* until EOF */ - while ((c = getc (fileref)) == 0) ; /* skip starting 0's */ - if (c == EOF) /* EOF? done */ - break; - for ( ; c != 0; ) { /* loop until ctl = 0 */ - /* ign ctrl frame */ - if ((c = getc (fileref)) == EOF) /* get high byte */ - return SCPE_FMT; /* EOF is error */ - if (!MEM_ADDR_OK (org)) - return SCPE_NXM; - M[org] = ((c & 0377) << 8); /* store high */ - if ((c = getc (fileref)) == EOF) /* get low byte */ - return SCPE_FMT; /* EOF is error */ - M[org] = M[org] | (c & 0377); /* store low */ - org = org + 1; /* incr origin */ - if ((c = getc (fileref)) == EOF) /* get ctrl frame */ - return SCPE_OK; /* EOF is ok */ - } /* end block for */ - if (!(sim_switches & SWMASK ('C'))) - return SCPE_OK; - } /* end tape for */ -return SCPE_OK; -} - -/* Symbol tables */ - -#define F_V_FL 16 /* class flag */ -#define F_M_FL 017 -#define F_V_FO 000 /* function out */ -#define F_V_FOI 001 /* FO, impl reg */ -#define F_V_SF 002 /* skip function */ -#define F_V_SFI 003 /* SF, impl reg */ -#define F_V_RR 004 /* reg reg */ -#define F_V_ZR 005 /* zero reg */ -#define F_V_RS 006 /* reg self */ -#define F_V_JC 010 /* jump cond */ -#define F_V_JU 011 /* jump uncond */ -#define F_V_RM 012 /* reg mem */ -#define F_V_ZM 013 /* zero mem */ -#define F_V_MR 014 /* mem reg */ -#define F_V_MS 015 /* mem self */ -#define F_2WD 010 /* 2 words */ - -#define F_FO (F_V_FO << F_V_FL) -#define F_FOI (F_V_FOI << F_V_FL) -#define F_SF (F_V_SF << F_V_FL) -#define F_SFI (F_V_SFI << F_V_FL) -#define F_RR (F_V_RR << F_V_FL) -#define F_ZR (F_V_ZR << F_V_FL) -#define F_RS (F_V_RS << F_V_FL) -#define F_JC (F_V_JC << F_V_FL) -#define F_JU (F_V_JU << F_V_FL) -#define F_RM (F_V_RM << F_V_FL) -#define F_ZM (F_V_ZM << F_V_FL) -#define F_MR (F_V_MR << F_V_FL) -#define F_MS (F_V_MS << F_V_FL) - -struct fnc_op { - uint32 inst; /* instr prot */ - uint32 imask; /* instr mask */ - uint32 oper; /* operator */ - uint32 omask; /* oper mask */ - }; - -static const int32 masks[] = { - 0176000, 0176077, 0000077, 0176077, - 0000300, 0176300, 0000300, 0177777, - 0000077, 0177777, 0000377, 0176377, - 0176300, 0176377 - }; - -/* Instruction mnemonics - - Order is critical, as some instructions are more precise versions of - others. For example, JU must precede JC, otherwise, JU will be decoded - as JC 0,ETZ,dst. There are some ambiguities, eg, what is 02-xxxx-06? - Priority is as follows: - - FO (02-xxxx-rr) - SF (rr-xxxx-02) - MR (06-xxxx-rr) - RM (rr-xxxx-06) - JC (rr-xxxx-03) - RR -*/ - -static const char *opcode[] = { - "FOM", "FOA", "FOI", "FO", /* FOx before FO */ - "SFM", "SFA", "SFI", "SF", /* SFx before SF */ - "ZM", "ZMD", "ZMI", "ZMID", /* ZM before RM */ - "MS", "MSD", "MSI", "MSID", - "RM", "RMD", "RMI", "RMID", - "MR", "MRD", "MRI", "MRID", - "JO", "JOD", "JN", "JND", /* JU before JC */ - "JU", "JUD", "JC", "JCD", - "ZR", "ZRC", "RR", "RRC", /* ZR before RR */ - "RS", "RSC", - NULL - }; - -static const uint32 opc_val[] = { - 0004000+F_FOI, 0004013+F_FOI, 0004004+F_FOI, 0004000+F_FO, - 0000002+F_SFI, 0026002+F_SFI, 0010002+F_SFI, 0000002+F_SF, - 0000006+F_ZM, 0000106+F_ZM, 0000206+F_ZM, 0000306+F_ZM, - 0014006+F_MS, 0014106+F_MS, 0014206+F_MS, 0014306+F_MS, - 0000006+F_RM, 0000106+F_RM, 0000206+F_RM, 0000306+F_RM, - 0014000+F_MR, 0014100+F_MR, 0014200+F_MR, 0014300+F_MR, - 0037003+F_JU, 0037103+F_JU, 0037203+F_JU, 0037303+F_JU, - 0000403+F_JU, 0000503+F_JU, 0000003+F_JC, 0000103+F_JC, - 0000000+F_ZR, 0000200+F_ZR, 0000000+F_RR, 0000200+F_RR, - 0000000+F_RS, 0000200+F_RS - }; - -/* Unit mnemonics. All 64 units are decoded, most just to octal integers */ - -static const char *unsrc[64] = { - "0", "IR", "2", "TRP", "ISR", "MA", "MB", "SC", /* 00 - 07 */ - "SWR", "AX", "AY", "AO", "14", "15", "16", "MSR", /* 10 - 17 */ - "20", "21", "XR", "ATRP", "BSW", "BPK", "BCPA", "BCPB",/* 20 - 27 */ - "GR1", "GR2", "GR3", "GR4", "GR5", "GR6", "36", "37", /* 30 - 37 */ - "40", "41", "42", "43", "44", "45", "46", "47", - "50", "51", "52", "53", "54", "CDR", "56", "CADR", - "60", "61", "62", "63", "64", "65", "DWC", "DCA", - "DISK", "LPR", "72", "73", "CAS", "RTC", "HSR", "TTI" /* 70 - 77 */ - }; - -static const char *undst[64] = { - "0", "IR", "2", "TRP", "ISR", "5", "MB", "SC", /* 00 - 07 */ - "SWR", "AX", "AY", "13", "EAO", "15", "16", "MSR", /* 10 - 17 */ - "20", "21", "XR", "ATRP", "BSW", "BPK", "BCPA", "BCPB",/* 20 - 27 */ - "GR1", "GR2", "GR3", "GR4", "GR5", "GR6", "36", "37", /* 30 - 37 */ - "40", "41", "42", "43", "44", "45", "46", "47", - "50", "51", "52", "53", "54", "CDR", "56", "CADR", - "60", "61", "62", "63", "64", "65", "DWC", "DCA", - "DISK", "LPR", "72", "73", "CAS", "RTC", "HSP", "TTO" /* 70 - 77 */ - }; - -/* Operators */ - -static const char *opname[4] = { - NULL, "P1", "L1", "R1" - }; - -/* Conditions */ - -static const char *cdname[8] = { - "NEVER", "ALWAYS", "ETZ", "NEZ", "LTZ", "GEZ", "LEZ", "GTZ" - }; - -/* Function out/sense function */ - -static const char *fname[] = { - "NOT", /* any SF */ - "POK", "LNK", "BOV", /* SFM */ - "SOV", "AOV", /* SFA */ - "IRDY", "ORDY", /* any SF */ - "CLL", "STL", "CML", "HLT", /* FOM */ - "ICF", "ICO", /* FOI */ - "ADD", "AND", "XOR", "OR", /* FOA */ - "INP", "IRDY", "ORDY", "STRT", /* any FO */ - NULL - }; - -static const struct fnc_op fop[] = { - { 0000002, 0000077, 001, 001 }, /* NOT */ - { 0000002, 0176077, 010, 010 }, /* POK */ - { 0000002, 0176077, 004, 004 }, /* LNK */ - { 0000002, 0176077, 002, 002 }, /* BOV */ - { 0026002, 0176077, 004, 004 }, /* SOV */ - { 0026002, 0176077, 002, 002 }, /* AOV */ - { 0000002, 0000077, 010, 010 }, /* IRDY */ - { 0000002, 0000077, 002, 002 }, /* ORDY */ - { 0004000, 0176077, 001, 003 }, /* CLL */ - { 0004000, 0176077, 002, 003 }, /* STL */ - { 0004000, 0176077, 003, 003 }, /* CML */ - { 0004000, 0176077, 004, 004 }, /* HLT */ - { 0004004, 0176077, 001, 001 }, /* ICF */ - { 0004004, 0176077, 002, 002 }, /* ICO */ - { 0004013, 0176077, 000, 014 }, /* ADD */ - { 0004013, 0176077, 004, 014 }, /* AND */ - { 0004013, 0176077, 010, 014 }, /* XOR */ - { 0004013, 0176077, 014, 014 }, /* OR */ - { 0004000, 0176000, 011, 011 }, /* INP */ - { 0004000, 0176000, 010, 010 }, /* IRDY */ - { 0004000, 0176000, 002, 002 }, /* ORDY */ - { 0004000, 0176000, 001, 001 } /* STRT */ - }; - -/* Print opcode field for FO, SF */ - -void fprint_op (FILE *of, uint32 inst, uint32 op) -{ -int32 i, nfirst; - -for (i = nfirst = 0; fname[i] != NULL; i++) { - if (((inst & fop[i].imask) == fop[i].inst) && - ((op & fop[i].omask) == fop[i].oper)) { - op = op & ~fop[i].omask; - if (nfirst) - fputc (' ', of); - nfirst = 1; - fprintf (of, "%s", fname[i]); - } - } -if (op) - fprintf (of, " %o", op); -return; -} - -/* Print address field with potential indexing */ - -void fprint_addr (FILE *of, uint32 val, uint32 mode, uint32 dst) -{ -if ((val & INDEX) && - ((dst == U_SC) || (mode != MEM_IMM))) - fprintf (of, "#%o", val & AMASK); -else fprintf (of, "%o", val); -return; -} - -/* Symbolic decode - - Inputs: - *of = output stream - addr = current PC - *val = pointer to data - *uptr = pointer to unit - sw = switches - Outputs: - return = status code -*/ - -#define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x) - -t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, - UNIT *uptr, int32 sw) -{ -int32 i, j; -uint32 inst, src, dst, op, bop; - -inst = val[0]; -if (sw & SWMASK ('A')) { /* ASCII? */ - if (inst > 0377) - return SCPE_ARG; - fprintf (of, FMTASC (inst & 0177)); - return SCPE_OK; - } -if (sw & SWMASK ('C')) { /* characters? */ - fprintf (of, FMTASC ((inst >> 8) & 0177)); - fprintf (of, FMTASC (inst & 0177)); - return SCPE_OK; - } -if (!(sw & SWMASK ('M'))) - return SCPE_ARG; - -/* Instruction decode */ - -inst = val[0]; -src = I_GETSRC (inst); /* get fields */ -op = I_GETOP (inst); -dst = I_GETDST (inst); -bop = op >> 2; /* bus op */ -for (i = 0; opcode[i] != NULL; i++) { /* loop thru ops */ - j = (opc_val[i] >> F_V_FL) & F_M_FL; /* get class */ - if ((opc_val[i] & DMASK) == (inst & masks[j])) { /* match? */ - - switch (j) { /* case on class */ - - case F_V_FO: /* func out */ - fprintf (of, "%s ", opcode[i]); - fprint_op (of, inst, op); - fprintf (of, ",%s", undst[dst]); - break; - - case F_V_FOI: /* func out impl */ - fprintf (of, "%s ", opcode[i]); - fprint_op (of, inst, op); - break; - - case F_V_SF: /* skip func */ - fprintf (of, "%s %s,", opcode[i], unsrc[src]); - fprint_op (of, inst, op); - break; - - case F_V_SFI: /* skip func impl */ - fprintf (of, "%s ", opcode[i]); - fprint_op (of, inst, op); - break; - - case F_V_RR: /* reg reg */ - if (strcmp (unsrc[src], undst[dst]) == 0) { - if (bop) - fprintf (of, "%s %s,%s", opcode[i + 2], - unsrc[src], opname[bop]); - else fprintf (of, "%s %s", opcode[i + 2], unsrc[src]); - } - else { - if (bop) - fprintf (of, "%s %s,%s,%s", opcode[i], - unsrc[src], opname[bop], undst[dst]); - else fprintf (of, "%s %s,%s", opcode[i], - unsrc[src], undst[dst]); - } - break; - - case F_V_ZR: /* zero reg */ - if (bop) - fprintf (of, "%s %s,%s", opcode[i], - opname[bop], undst[dst]); - else fprintf (of, "%s %s", opcode[i], undst[dst]); - break; - - case F_V_JC: /* jump cond */ - fprintf (of, "%s %s,%s,", - opcode[i], unsrc[src], cdname[op >> 1]); - fprint_addr (of, val[1], 0, U_SC); - break; - - case F_V_JU: /* jump uncond */ - fprintf (of, "%s ", opcode[i]); - fprint_addr (of, val[1], 0, U_SC); - break; - - case F_V_RM: /* reg mem */ - if (bop) - fprintf (of, "%s %s,%s,", - opcode[i], unsrc[src], opname[bop]); - else fprintf (of, "%s %s,", opcode[i], unsrc[src]); - fprint_addr (of, val[1], op & MEM_MOD, dst); - break; - - case F_V_ZM: /* zero mem */ - if (bop) - fprintf (of, "%s %s,", opcode[i], opname[bop]); - else fprintf (of, "%s ", opcode[i]); - fprint_addr (of, val[1], op & MEM_MOD, dst); - break; - - case F_V_MR: /* mem reg */ - fprintf (of, "%s ", opcode[i]); - fprint_addr (of, val[1], op & MEM_MOD, dst); - if (bop) - fprintf (of, ",%s,%s", opname[bop], undst[dst]); - else fprintf (of, ",%s", undst[dst]); - break; - - case F_V_MS: /* mem self */ - fprintf (of, "%s ", opcode[i]); - fprint_addr (of, val[1], op & MEM_MOD, dst); - if (bop) - fprintf (of, ",%s", opname[bop]); - break; - } /* end case */ - - return (j >= F_2WD)? -1: SCPE_OK; - } /* end if */ - } /* end for */ -return SCPE_ARG; -} - -/* Field parse routines - - get_fnc get function field - get_ma get memory address - get_sd get source or dest - get_op get optional bus operator -*/ - -char *get_fnc (char *cptr, t_value *val) -{ -char gbuf[CBUFSIZE]; -int32 i; -t_value d; -t_stat r; -uint32 inst = val[0]; -uint32 fncv = 0, fncm = 0; - -while (*cptr) { - cptr = get_glyph (cptr, gbuf, 0); /* get glyph */ - d = get_uint (gbuf, 8, 017, &r); /* octal? */ - if (r == SCPE_OK) { /* ok? */ - if (d & fncm) /* already filled? */ - return NULL; - fncv = fncv | d; /* save */ - fncm = fncm | d; /* field filled */ - } - else { /* symbol? */ - for (i = 0; fname[i] != NULL; i++) { /* search table */ - if ((strcmp (gbuf, fname[i]) == 0) && /* match for inst? */ - ((inst & fop[i].imask) == fop[i].inst)) { - if (fop[i].oper & fncm) /* already filled? */ - return NULL; - fncm = fncm | fop[i].omask; - fncv = fncv | fop[i].oper; - break; - } - } - if (fname[i] == NULL) - return NULL; - } /* end else */ - } /* end while */ -val[0] = val[0] | (fncv << I_V_OP); /* store fnc */ -return cptr; -} - -char *get_ma (char *cptr, t_value *val, char term) -{ -char gbuf[CBUFSIZE]; -t_value d; -t_stat r; - -cptr = get_glyph (cptr, gbuf, term); /* get glyph */ -if (gbuf[0] == '#') /* indexed? */ - d = get_uint (gbuf + 1, 8, AMASK, &r) | INDEX; /* [0, 77777] */ -else d = get_uint (gbuf, 8, DMASK, &r); /* [0,177777] */ -if (r != SCPE_OK) - return NULL; -val[1] = d; /* second wd */ -return cptr; -} - -char *get_sd (char *cptr, t_value *val, char term, t_bool src) -{ -char gbuf[CBUFSIZE]; -int32 d; -t_stat r; - -cptr = get_glyph (cptr, gbuf, term); /* get glyph */ -for (d = 0; d < 64; d++) { /* symbol match? */ - if ((strcmp (gbuf, unsrc[d]) == 0) || - (strcmp (gbuf, undst[d]) == 0)) - break; - } -if (d >= 64) { /* no, [0,63]? */ - d = get_uint (gbuf, 8, 077, &r); - if (r != SCPE_OK) - return NULL; - } -val[0] = val[0] | (d << (src? I_V_SRC: I_V_DST)); /* or to inst */ -return cptr; -} - -char *get_op (char *cptr, t_value *val, char term) -{ -char gbuf[CBUFSIZE], *tptr; -int32 i; - -tptr = get_glyph (cptr, gbuf, term); /* get glyph */ -for (i = 1; i < 4; i++) { /* symbol match? */ - if (strcmp (gbuf, opname[i]) == 0) { - val[0] = val[0] | (i << (I_V_OP + 2)); /* or to inst */ - return tptr; - } - } -return cptr; /* original ptr */ -} - -/* 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 -*/ - -t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) -{ -int32 i, j, k; -char *tptr, gbuf[CBUFSIZE]; - -while (isspace (*cptr)) cptr++; /* absorb spaces */ -if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ - if (cptr[0] == 0) /* must have 1 char */ - return SCPE_ARG; - val[0] = (t_value) cptr[0] & 0177; - return SCPE_OK; - } -if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* char string? */ - if (cptr[0] == 0) /* must have 1 char */ - return SCPE_ARG; - val[0] = (((t_value) cptr[0] & 0177) << 8) | ((t_value) cptr[1] & 0177); - return SCPE_OK; - } - -/* Instruction parse */ - -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] & DMASK; /* get value */ -j = (opc_val[i] >> F_V_FL) & F_M_FL; /* get class */ - -switch (j) { /* case on class */ - - case F_V_FO: /* func out */ - tptr = strchr (cptr, ','); /* find dst */ - if (!tptr) /* none? */ - return SCPE_ARG; - *tptr = 0; /* split fields */ - cptr = get_fnc (cptr, val); /* fo # */ - if (!cptr) - return SCPE_ARG; - cptr = get_sd (tptr + 1, val, 0, FALSE); /* dst */ - break; - - case F_V_FOI: /* func out impl */ - cptr = get_fnc (cptr, val); /* fo # */ - break; - - case F_V_SF: /* skip func */ - cptr = get_sd (cptr, val, ',', TRUE); /* src */ - if (!cptr) - return SCPE_ARG; - /* fall through */ - case F_V_SFI: /* skip func impl */ - cptr = get_fnc (cptr, val); /* fo # */ - break; - - case F_V_RR: /* reg-reg */ - cptr = get_sd (cptr, val, ',', TRUE); /* src */ - if (!cptr) - return SCPE_ARG; - cptr = get_op (cptr, val, ','); /* op */ - if (!cptr) - return SCPE_ARG; - cptr = get_sd (cptr, val, 0, FALSE); /* dst */ - break; - - case F_V_ZR: /* zero-reg */ - cptr = get_op (cptr, val, ','); /* op */ - if (!cptr) - return SCPE_ARG; - cptr = get_sd (cptr, val, 0, FALSE); /* dst */ - break; - - case F_V_RS: /* reg self */ - cptr = get_sd (cptr, val, ',', TRUE); /* src */ - if (!cptr) - return SCPE_ARG; - val[0] = val[0] | I_GETSRC (val[0]); /* duplicate */ - cptr = get_op (cptr, val, 0); /* op */ - break; - - case F_V_JC: /* jump cond */ - cptr = get_sd (cptr, val, ',', TRUE); /* src */ - if (!cptr) - return SCPE_ARG; - cptr = get_glyph (cptr, gbuf, ','); /* cond */ - for (k = 0; k < 8; k++) { /* symbol? */ - if (strcmp (gbuf, cdname[k]) == 0) - break; - } - if (k >= 8) - return SCPE_ARG; - val[0] = val[0] | (k << (I_V_OP + 1)); /* or to inst */ - - case F_V_JU: /* jump uncond */ - cptr = get_ma (cptr, val, 0); /* addr */ - break; - - case F_V_RM: /* reg mem */ - cptr = get_sd (cptr, val, ',', TRUE); /* src */ - if (!cptr) - return SCPE_ARG; - case F_V_ZM: /* zero mem */ - cptr = get_op (cptr, val, ','); /* op */ - if (!cptr) - return SCPE_ARG; - cptr = get_ma (cptr, val, 0); /* addr */ - break; - - case F_V_MR: /* mem reg */ - cptr = get_ma (cptr, val, ','); /* addr */ - if (!cptr) - return SCPE_ARG; - cptr = get_op (cptr, val, ','); /* op */ - if (!cptr) - return SCPE_ARG; - cptr = get_sd (cptr, val, 0, FALSE); /* dst */ - break; - - case F_V_MS: /* mem self */ - cptr = get_ma (cptr, val, ','); /* addr */ - if (!cptr) - return SCPE_ARG; - cptr = get_op (cptr, val, 0); /* op */ - break; - } /* end case */ - -if (!cptr || (*cptr != 0)) /* junk at end? */ - return SCPE_ARG; -return (j >= F_2WD)? -1: SCPE_OK; -} diff --git a/H316/h316_cpu.c b/H316/h316_cpu.c deleted file mode 100644 index c3d440fc..00000000 --- a/H316/h316_cpu.c +++ /dev/null @@ -1,1803 +0,0 @@ -/* h316_cpu.c: Honeywell 316/516 CPU simulator - - Copyright (c) 1999-2017, 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. - - cpu H316/H516 CPU - - 07-Sep-17 RMS Fixed sim_eval declaration in history routine (COVERITY) - 21-May-13 RLA Add IMP/TIP support - Move SMK/OTK instructions here (from CLK) - Make SET CPU DMA work as documented - Implement extended interrupts - Add "interrupt taken" flag to CPU HISTORY - Add "break on write" breakpoints - 19-Nov-11 RMS Fixed XR behavior (Adrian Wise) - 19-Nov-11 RMS Fixed bugs in double precision, normalization, SC (Adrian Wise) - 10-Jan-10 RMS Fixed bugs in LDX, STX introduced in 3.8-1 (Theo Engel) - 28-Apr-07 RMS Removed clock initialization - 03-Apr-06 RMS Fixed bugs in LLL, LRL (Theo Engel) - 22-Sep-05 RMS Fixed declarations (Sterling Garwood) - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 15-Feb-05 RMS Added start button interrupt - 01-Dec-04 RMS Fixed bug in DIV - 06-Nov-04 RMS Added =n to SHOW HISTORY - 04-Jan-04 RMS Removed unnecessary compare - 31-Dec-03 RMS Fixed bug in cpu_set_hist - 24-Oct-03 RMS Added DMA/DMC support, instruction history - 30-Dec-01 RMS Added old PC queue - 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 - BR<1:16> B register - XR<1:16> X register - PC<1:16> P register (program counter) - Y<1:16> memory address register - MB<1:16> memory data register - C overflow flag - EXT extend mode flag - DP double precision mode flag - SC<1:6> shift count - SR[1:4]<0> sense switches 1-4 - - The Honeywell 316/516 has six instruction formats: memory reference, - I/O, control, shift, skip, and operate. - - The memory reference format is: - - 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - |in|xr| op |sc| offset | memory reference - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - <13:10> mnemonic action - - 0000 (other) see control, shift, skip, operate instructions - 0001 JMP P = MA - 0010 LDA A = M[MA] - 0011 ANA A = A & M[MA] - 0100 STA M[MA] = A - 0101 ERA A = A ^ M[MA] - 0110 ADD A = A + M[MA] - 0111 SUB A = A - M[MA] - 1000 JST M[MA] = P, P = MA + 1 - 1001 CAS skip if A == M[MA], double skip if A < M[MA] - 1010 IRS M[MA] = M[MA] + 1, skip if M[MA] == 0 - 1011 IMA A <=> M[MA] - 1100 (I/O) see I/O instructions - 1101 LDX/STX X = M[MA] (xr = 1), M[MA] = x (xr = 0) - 1110 MPY multiply - 1111 DIV divide - - In non-extend mode, memory reference instructions can access an address - space of 16K words. Multiple levels of indirection are supported, and - each indirect word supplies its own indirect and index bits. - - <1,2,7> mode action - - 0,0,0 sector zero direct MA = IR<8:0> - 0,0,1 current direct MA = P<13:9>'IR<8:0> - 0,1,0 sector zero indexed MA = IR<8:0> + X - 0,1,1 current direct MA = P<13:9>'IR<8:0> + X - 1,0,0 sector zero indirect MA = M[IR<8:0>] - 1,0,1 current indirect MA = M[P<13:9>'IR<8:0>] - 1,1,0 sector zero indirect indexed MA = M[IR<8:0> + X] - 1,1,1 current indirect indexed MA = M[MA = P<13:9>'IR<8:0> + X] - - In extend mode, memory reference instructions can access an address - space of 32K words. Multiple levels of indirection are supported, but - only post-indexing, based on the original instruction word index flag, - is allowed. - - The control format is: - - 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 0 0 0 0 0 0| opcode | control - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - The shift format is: - - 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 0 1 0 0 0 0|dr|sz|type | shift count | shift - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | | \-+-/ - | | | - | | +--------------------- type - | +------------------------- long/A only - +---------------------------- right/left - - The skip format is: - - 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 1 0 0 0 0 0|rv|po|pe|ev|ze|s1|s2|s3|s4|cz| skip - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | | | | | | | | | | - | | | | | | | | | +- skip if C = 0 - | | | | | | | | +---- skip if ssw 4 = 0 - | | | | | | | +------- skip if ssw 3 = 0 - | | | | | | +---------- skip if ssw 2 = 0 - | | | | | +------------- skip if ssw 1 = 0 - | | | | +---------------- skip if A == 0 - | | | +------------------- skip if A<0> == 0 - | | +---------------------- skip if mem par err - | +------------------------- skip if A<15> = 0 - +---------------------------- reverse skip sense - - The operate format is: - - 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 1 1 0 0 0 0| opcode | operate - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - The I/O format is: - - 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | op | 1 1 0 0| function | device | I/O transfer - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - The IO transfer instruction controls the specified device. - Depending on the opcode, the instruction may set or clear - the device flag, start or stop I/O, or read or write data. - - This routine is the instruction decode routine for the Honeywell - 316/516. 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 - infinite indirection loop - unimplemented instruction and stop_inst flag set - unknown I/O device and stop_dev flag set - I/O error in I/O simulator - - 2. Interrupts. Interrupts are maintained by parallel variables: - - dev_int[2] device interrupt flags - dev_enb[2] device interrupt enable flags - - Note that these are actually arrays of two 16 bit words each. The first - word of each vector contains the bits for the standard interrupt devices, - and the second word is the bits for the extended interrupts 1..17. The - IMP uses these extended interrupts, however this was a standard H316 option - and is in no way IMP specific. Actually the H316 supported up to 48 extra - interrupts, but it seems like overkill to implement them all. - - In addition, dev_int[0] contains the interrupt enable and interrupt no - defer flags. If interrupt enable and interrupt no defer are set, and - at least one interrupt request is pending, then an interrupt occurs. - The order of flags in these variables corresponds to the order - in the SMK instruction. - - 3. Non-existent memory. On the H316/516, 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: - - h316_defs.h add interrupt request definition - h316_cpu.c add device dispatch table entry - h316_sys.c add sim_devices table entry - - Notes on the behavior of XR: - - - XR is "shadowed" by memory location 0 as seen by the program currently - executing. Thus, in extend mode, this is always absolute location 0. - However, if extend mode is off, this is location 0, if the program is - executing in the lower bank, or location 040000, if the program is - executing in the upper bank. Writing XR writes the shadowed memory - location, and vice versa. - - However, the front panel console always equates XR to absolute location - 0, regardless of extend mode. There is no direct examine or deposit - to XR; the user must examine or deposit location 0. -*/ - -#include "h316_defs.h" -#ifdef VM_IMPTIP -#include "h316_imp.h" -#endif - -#define PCQ_SIZE 64 /* must be 2**n */ -#define PCQ_MASK (PCQ_SIZE - 1) -#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC -#define PCQ_TOP pcq[pcq_p] -#define m7 0001000 /* for generics */ -#define m8 0000400 -#define m9 0000200 -#define m10 0000100 -#define m11 0000040 -#define m12 0000020 -#define m13 0000010 -#define m14 0000004 -#define m15 0000002 -#define m16 0000001 - -#define HIST_PC 0x40000000 -#define HIST_C 0x20000000 -#define HIST_EA 0x10000000 -#define HIST_MIN 64 -#define HIST_MAX 65536 - -typedef struct { - int32 pc; - int32 ir; - int32 ar; - int32 br; - int32 xr; - int32 ea; - int32 opnd; - t_bool iack; // [RLA] TRUE if an interrupt occurred - } InstHistory; - -uint16 M[MAXMEMSIZE] = { 0 }; /* memory */ -int32 saved_AR = 0; /* A register */ -int32 saved_BR = 0; /* B register */ -int32 saved_XR = 0; /* X register */ -int32 XR = 0; /* live copy - must be global */ -int32 PC = 0; /* P register */ -int32 C = 0; /* C register */ -int32 ext = 0; /* extend mode */ -int32 pme = 0; /* prev mode extend */ -int32 extoff_pending = 0; /* extend off pending */ -int32 dp = 0; /* double mode */ -int32 sc = 0; /* shift count */ -int32 ss[4]; /* sense switches */ -int32 dev_int = 0; /* dev ready */ -int32 dev_enb = 0; /* dev enable */ -uint32 ext_ints = 0; // [RLA] 16 if extended interrupts enabled -uint16 dev_ext_int = 0; // [RLA] extended interrupt request bitmap -uint16 dev_ext_enb = 0; // [RLA] extended interrupt enable bitmap -int32 ind_max = 8; /* iadr nest limit */ -int32 stop_inst = 1; /* stop on ill inst */ -int32 stop_dev = 2; /* stop on ill dev */ -uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ -int32 pcq_p = 0; /* PC queue ptr */ -REG *pcq_r = NULL; /* PC queue reg ptr */ -uint32 dma_nch = DMA_MAX; /* number of chan */ -uint32 dma_ad[DMA_MAX] = { 0 }; /* DMA addresses */ -uint32 dma_wc[DMA_MAX] = { 0 }; /* DMA word count */ -uint32 dma_eor[DMA_MAX] = { 0 }; /* DMA end of range */ -uint32 chan_req = 0; /* channel requests */ -uint32 chan_map[DMA_MAX + DMC_MAX] = { 0 }; /* chan->dev map */ -int32 (*iotab[DEV_MAX])(int32 inst, int32 fnc, int32 dat, int32 dev) = { NULL }; -int32 hst_p = 0; /* history pointer */ -int32 hst_lnt = 0; /* history length */ -InstHistory *hst = NULL; /* instruction history */ - -t_bool devtab_init (void); -int32 dmaio (int32 inst, int32 fnc, int32 dat, int32 dev); -int32 undio (int32 inst, int32 fnc, int32 dat, int32 dev); -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_noext (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat cpu_show_dma (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat cpu_set_nchan (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_show_nchan (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat cpu_set_interrupts (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_show_interrupts (FILE *st, UNIT *uptr, int32 val, void *desc); -int32 sim_ota_2024 (int32 inst, int32 fnc, int32 dat, int32 dev); -int32 cpu_interrupt (int32 vec); -int32 cpu_ext_interrupt (void); - -/* CPU data structures - - cpu_dev CPU device descriptor - cpu_unit CPU unit descriptor - cpu_reg CPU register list - cpu_mod CPU modifiers list -*/ - -DIB cpu_dib = { DMA, 1, IOBUS, IOBUS, INT_V_NONE, INT_V_NONE, &dmaio, 0 }; - -UNIT cpu_unit = { - UDATA (NULL, UNIT_FIX+UNIT_BINK+UNIT_EXT+UNIT_HSA+UNIT_DMC, MAXMEMSIZE) - }; - -REG cpu_reg[] = { - { ORDATA (P, PC, 15) }, - { ORDATA (A, saved_AR, 16) }, - { ORDATA (B, saved_BR, 16) }, - { ORDATA (X, saved_XR, 16) }, - { ORDATA (SC, sc, 16) }, - { FLDATA (C, C, 0) }, - { FLDATA (EXT, ext, 0) }, - { FLDATA (PME, pme, 0) }, - { FLDATA (EXT_OFF, extoff_pending, 0) }, - { FLDATA (DP, dp, 0) }, - { FLDATA (SS1, ss[0], 0) }, - { FLDATA (SS2, ss[1], 0) }, - { FLDATA (SS3, ss[2], 0) }, - { FLDATA (SS4, ss[3], 0) }, - { FLDATA (ION, dev_int, INT_V_ON) }, - { FLDATA (INODEF, dev_int, INT_V_NODEF) }, - { FLDATA (START, dev_int, INT_V_START) }, - { ORDATA (DEVINT, dev_int, 16), REG_RO }, - { ORDATA (DEVENB, dev_enb, 16), REG_RO }, - { ORDATA (EXTINT, dev_ext_int, 16), REG_RO }, - { ORDATA (EXTENB, dev_ext_enb, 16), REG_RO }, - { ORDATA (CHREQ, chan_req, DMA_MAX + DMC_MAX) }, - { BRDATA (DMAAD, dma_ad, 8, 16, DMA_MAX) }, - { BRDATA (DMAWC, dma_wc, 8, 16, DMA_MAX) }, - { BRDATA (DMAEOR, dma_eor, 8, 1, DMA_MAX) }, - { ORDATA (DMANCH, dma_nch, 3), REG_HRO }, - { FLDATA (MPERDY, dev_int, INT_V_MPE) }, - { FLDATA (MPEENB, dev_enb, INT_V_MPE) }, - { FLDATA (STOP_INST, stop_inst, 0) }, - { FLDATA (STOP_DEV, stop_dev, 1) }, - { DRDATA (INDMAX, ind_max, 8), REG_NZ + PV_LEFT }, - { BRDATA (PCQ, pcq, 8, 15, PCQ_SIZE), REG_RO + REG_CIRC }, - { ORDATA (PCQP, pcq_p, 6), REG_HRO }, - { ORDATA (WRU, sim_int_char, 8) }, - { NULL } - }; - -MTAB cpu_mod[] = { - { UNIT_EXT, 0, "no extend", "NOEXTEND", &cpu_set_noext }, - { UNIT_EXT, UNIT_EXT, "extend", "EXTEND", 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 }, - { UNIT_MSIZE, 12288, NULL, "12K", &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 }, - { MTAB_XTD | MTAB_VDV, 0, "channels", "CHANNELS", - &cpu_set_nchan, &cpu_show_nchan, NULL }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "DMA", // [RLA] this is the way it's - &cpu_set_nchan, NULL, NULL }, // [RLA] documented to work! - { UNIT_DMC, 0, "no DMC", "NODMC", NULL }, - { UNIT_DMC, UNIT_DMC, "DMC", "DMC", NULL }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", - &cpu_set_hist, &cpu_show_hist }, - { MTAB_XTD | MTAB_VDV, 0, "extended interrupts", "EXTINT", - &cpu_set_interrupts, &cpu_show_interrupts, NULL }, - { 0 } - }; - -DEVICE cpu_dev = { - "CPU", &cpu_unit, cpu_reg, cpu_mod, - 1, 8, 15, 1, 8, 16, - &cpu_ex, &cpu_dep, &cpu_reset, - NULL, NULL, NULL, - &cpu_dib, 0 - }; - -t_stat sim_instr (void) -{ -int32 AR, BR, MB, Y, t1, t2, t3, skip, dev; -uint32 ut; -t_bool iack; // [RLA] TRUE if an interrupt was taken this cycle -t_stat reason; -t_stat Ea (int32 inst, int32 *addr); -t_stat Write (int32 addr, int32 val); // [RLA] Write() can now cause a break -int32 Add16 (int32 val1, int32 val2); -int32 Add31 (int32 val1, int32 val2); -int32 Operate (int32 MB, int32 AR); - -#define Read(ad) M[(ad)] -#define GETDBL_S(h,l) (((h) << 15) | ((l) & MMASK)) -#define GETDBL_U(h,l) (((h) << 16) | (l)) -#define PUTDBL_S(x) AR = ((x) >> 15) & DMASK; \ - BR = (BR & SIGN) | ((x) & MMASK) -#define PUTDBL_U(x) AR = ((x) >> 16) & DMASK; \ - BR = (x) & DMASK -#define PUTDBL_Z(x) AR = ((x) >> 15) & DMASK; \ - BR = (x) & MMASK -#define SEXT(x) (((x) & SIGN)? ((x) | ~DMASK): ((x) & DMASK)) -#define NEWA(c,n) (ext? (((c) & ~X_AMASK) | ((n) & X_AMASK)): \ - (((c) & ~NX_AMASK) | ((n) & NX_AMASK))) - -/* Restore register state */ - -if (devtab_init ()) /* init tables */ - return SCPE_STOP; -AR = saved_AR & DMASK; /* restore reg */ -BR = saved_BR & DMASK; -XR = saved_XR & DMASK; -PC = PC & ((cpu_unit.flags & UNIT_EXT)? X_AMASK: NX_AMASK); /* mask 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; - } - -/* Channel breaks (DMA and DMC) */ - -if (chan_req) { /* channel request? */ - int32 i, t, ch, dev, st, end, ad, dmcad; - t_stat r; - for (i = 0, ch = chan_req; ch != 0; i++, ch = ch >> 1) { - if (ch & 1) { /* req on chan i? */ - dev = chan_map[i]; /* get dev for chan */ - if (iotab[dev] == &undio) - return SCPE_IERR; - chan_req = chan_req & ~(1 << i); /* clear req */ - if (Q_DMA (i)) /* DMA? */ - st = dma_ad[i]; - else { /* DMC */ - dmcad = DMC_BASE + ((i - DMC_V_DMC1) << 1); - st = Read (dmcad); /* DMC ctrl word */ - } - ad = st & X_AMASK; /* get curr addr */ - if (st & DMA_IN) { /* input? */ - t = iotab[dev] (ioINA, 0, 0, dev); /* input word */ - if ((t & IOT_SKIP) == 0) - return STOP_DMAER; - if ((r = t >> IOT_V_REASON) != 0) - return r; - // [RLA] Note that we intentionally ignore address breaks here! - Write (ad, t & DMASK); /* write to mem */ - } - else { /* no, output */ - t = iotab[dev] (ioOTA, 0, Read (ad), dev); /* output word */ - if ((t & IOT_SKIP) == 0) - return STOP_DMAER; - if ((r = (t >> IOT_V_REASON))) - return r; - } - if (Q_DMA (i)) { /* DMA? */ - dma_ad[i] = (dma_ad[i] & DMA_IN) | ((ad + 1) & X_AMASK); - dma_wc[i] = (dma_wc[i] + 1) & 077777; /* update wc */ - if (dma_wc[i] == 0) { /* done? */ - dma_eor[i] = 1; /* set end of range */ - t = iotab[dev] (ioEND, 0, 0, dev); /* send end range */ - if ((r = t >> IOT_V_REASON) != 0) - return r; - } - } - else { /* DMC */ - st = (st & DMA_IN) | ((ad + 1) & X_AMASK); - // [RLA] Note that we intentionally ignore address breaks here! - Write (dmcad, st); /* update start */ - end = Read (dmcad + 1); /* get end */ - if (((ad ^ end) & X_AMASK) == 0) { /* start == end? */ - t = iotab[dev] (ioEND, 0, 0, dev); /* send end range */ - if ((r = t >> IOT_V_REASON) != 0) - return r; - } /* end if end range */ - } /* end else DMC */ - } /* end if chan i */ - } /* end for */ - } /* end if chan_req */ - - -/* Interrupts */ - -//[RLA] Todo - add WDT interrupts ???? - -iack = FALSE; -if ((dev_int & (INT_PEND|INT_NMI|dev_enb)) > INT_PEND) { // [RLA] check for standard interrupt - MB = cpu_interrupt(M_INT); - iack = TRUE; - } -else if (((dev_ext_int & dev_ext_enb) != 0) // [RLA] check for extended interrupt - && ((dev_int & INT_PEND) == INT_PEND)) { - MB = cpu_ext_interrupt (); - iack = TRUE; - } - -/* Instruction fetch */ - -else { - if (sim_brk_summ && - sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; - } - Y = PC; /* set mem addr */ - MB = Read (Y); /* fetch instr */ - PC = NEWA (Y, Y + 1); /* incr PC */ - dev_int = dev_int | INT_NODEF; - } - -dev_int = dev_int & ~INT_START; /* clr start button int */ -sim_interval = sim_interval - 1; -if (hst_lnt) { /* instr hist? */ - hst_p = (hst_p + 1); /* next entry */ - if (hst_p >= hst_lnt) - hst_p = 0; - hst[hst_p].pc = Y | HIST_PC | (C? HIST_C: 0); /* fill slots */ - hst[hst_p].ir = MB; - hst[hst_p].ar = AR; - hst[hst_p].br = BR; - hst[hst_p].xr = XR; - hst[hst_p].iack = iack; // [RLA] record if interrupt taken - } - -/* Memory reference instructions */ - -switch (I_GETOP (MB)) { /* case on <1:6> */ - - case 001: case 021: case 041: case 061: /* JMP */ - if ((reason = Ea (MB, &Y))) /* eff addr */ - break; - PCQ_ENTRY; /* save PC */ - PC = NEWA (PC, Y); /* set new PC */ - if (extoff_pending) /* cond ext off */ - ext = extoff_pending = 0; - break; - - case 002: case 022: case 042: case 062: /* LDA */ - if ((reason = Ea (MB, &Y))) /* eff addr */ - break; - if (dp) { /* double prec? */ - AR = Read (Y & ~1); /* get doubleword */ - BR = Read (Y | 1); - sc = 0; - } - else AR = Read (Y); /* no, get word */ - break; - - case 003: case 023: case 043: case 063: /* ANA */ - if ((reason = Ea (MB, &Y))) /* eff addr */ - break; - AR = AR & Read (Y); - break; - - case 004: case 024: case 044: case 064: /* STA */ - if ((reason = Ea (MB, &Y))) /* eff addr */ - break; - if ((reason = Write(Y, AR))) - break; /* [RLA] store A */ - if (dp) { /* double prec? */ - if ((reason = Write(Y | 1, BR))) - break; /* [RLA] store B */ - sc = 0; - } - break; - - case 005: case 025: case 045: case 065: /* ERA */ - if ((reason = Ea (MB, &Y))) /* eff addr */ - break; - AR = AR ^ Read (Y); - break; - - case 006: case 026: case 046: case 066: /* ADD */ - if ((reason = Ea (MB, &Y))) /* eff addr */ - break; - if (dp) { /* double prec? */ - t1 = GETDBL_S (AR, BR); /* get A'B */ - t2 = GETDBL_S (Read (Y & ~1), Read (Y | 1)); - t1 = Add31 (t1, t2); /* 31b add */ - PUTDBL_Z (t1); - sc = 0; - } - else AR = Add16 (AR, Read (Y)); /* no, 16b add */ - break; - - case 007: case 027: case 047: case 067: /* SUB */ - if ((reason = Ea (MB, &Y))) /* eff addr */ - break; - if (dp) { /* double prec? */ - t1 = GETDBL_S (AR, BR); /* get A'B */ - t2 = GETDBL_S (Read (Y & ~1), Read (Y | 1)); - t1 = Add31 (t1, -t2); /* 31b sub */ - PUTDBL_Z (t1); - sc = 0; - } - else AR = Add16 (AR, (-Read (Y)) & DMASK); /* no, 16b sub */ - break; - - case 010: case 030: case 050: case 070: /* JST */ - if ((reason = Ea (MB, &Y))) /* eff addr */ - break; - MB = NEWA (Read (Y), PC); /* merge old PC */ - if ((reason = Write(Y, MB))) - break; // [RLA] - PCQ_ENTRY; - PC = NEWA (PC, Y + 1); /* set new PC */ - break; - - case 011: case 031: case 051: case 071: /* CAS */ - if ((reason = Ea (MB, &Y))) /* eff addr */ - break; - MB = Read (Y); - if (AR == MB) - PC = NEWA (PC, PC + 1); - else if (SEXT (AR) < SEXT (MB)) - PC = NEWA (PC, PC + 2); - break; - - case 012: case 032: case 052: case 072: /* IRS */ - if ((reason = Ea (MB, &Y))) /* eff addr */ - break; - MB = (Read (Y) + 1) & DMASK; /* incr, rewrite */ - if ((reason = Write(Y, MB))) - break; // [RLA] - if (MB == 0) /* skip if zero */ - PC = NEWA (PC, PC + 1); - break; - - case 013: case 033: case 053: case 073: /* IMA */ - if ((reason = Ea (MB, &Y))) /* eff addr */ - break; - MB = Read (Y); - if ((reason = Write(Y, AR))) - break; /* [RLA] A to mem */ - AR = MB; /* mem to A */ - break; - - case 015: case 055: /* STX */ - if ((reason = Ea (MB & ~IDX, &Y))) /* eff addr */ - break; - if ((reason = Write(Y, XR))) - break; /* [RLA] store XR */ - break; - - case 035: case 075: /* LDX */ - if ((reason = Ea (MB & ~IDX, &Y))) /* eff addr */ - break; - XR = Read (Y); /* load XR */ - M[M_XR] = XR; /* update mem too */ - break; - - case 016: case 036: case 056: case 076: /* MPY */ - if (cpu_unit.flags & UNIT_HSA) { /* installed? */ - if ((reason = Ea (MB, &Y))) /* eff addr */ - break; - t1 = SEXT (AR) * SEXT (Read (Y)); - PUTDBL_Z (t1); - sc = 0; - } - else reason = stop_inst; - break; - - case 017: case 037: case 057: case 077: /* DIV */ - if (cpu_unit.flags & UNIT_HSA) { /* installed? */ - if ((reason = Ea (MB, &Y))) /* eff addr */ - break; - t2 = SEXT (Read (Y)); /* divr */ - if (t2) { /* divr != 0? */ - t1 = GETDBL_S (SEXT (AR), BR); /* get A'B signed */ - BR = (t1 % t2) & DMASK; /* remainder */ - t1 = t1 / t2; /* quotient */ - AR = t1 & DMASK; - if ((t1 > MMASK) || (t1 < (-SIGN))) - C = 1; - else C = 0; - sc = 0; - } - else C = 1; - } - else reason = stop_inst; - break; - -/* I/O instructions */ - - case 014: /* OCP */ - dev = MB & DEVMASK; - t2 = iotab[dev] (ioOCP, I_GETFNC (MB), AR, dev); - reason = t2 >> IOT_V_REASON; - break; - - case 034: /* SKS */ - dev = MB & DEVMASK; - t2 = iotab[dev] (ioSKS, I_GETFNC (MB), AR, dev); - reason = t2 >> IOT_V_REASON; - if (t2 & IOT_SKIP) /* skip? */ - PC = NEWA (PC, PC + 1); - break; - - case 054: /* INA */ - dev = MB & DEVMASK; - if (MB & INCLRA) - AR = 0; - t2 = iotab[dev] (ioINA, I_GETFNC (MB & ~INCLRA), AR, dev); - reason = t2 >> IOT_V_REASON; - if (t2 & IOT_SKIP) /* skip? */ - PC = NEWA (PC, PC + 1); - AR = t2 & DMASK; /* data */ - break; - - case 074: /* OTA */ - dev = MB & DEVMASK; - // [RLA] OTA w/devices 20 or 24 are SMK or OTK! - if ((dev == 020) || (dev == 024)) - t2 = sim_ota_2024(ioOTA, I_GETFNC (MB), AR, dev); - else - t2 = iotab[dev] (ioOTA, I_GETFNC (MB), AR, dev); - reason = t2 >> IOT_V_REASON; - if (t2 & IOT_SKIP) /* skip? */ - PC = NEWA (PC, PC + 1); - break; - -/* Control */ - - case 000: - if ((MB & 1) == 0) { /* HLT */ - if ((reason = sim_process_event ()) != SCPE_OK) - break; - reason = STOP_HALT; - break; - } - if (MB & m14) { /* SGL, DBL */ - if (cpu_unit.flags & UNIT_HSA) - dp = (MB & m15)? 1: 0; - else reason = stop_inst; - } - if (MB & m13) { /* DXA, EXA */ - if (!(cpu_unit.flags & UNIT_EXT)) - reason = stop_inst; - else if (MB & m15) { /* EXA */ - ext = 1; - extoff_pending = 0; /* DXA */ - } - else extoff_pending = 1; - } - if (MB & m12) /* RMP */ - CLR_INT (INT_MPE); - if (MB & m11) { /* SCA, INK */ - if (MB & m15) /* INK */ - AR = (C << 15) | (dp << 14) | (pme << 13) | (sc & 077); - else if (cpu_unit.flags & UNIT_HSA) /* SCA */ - AR = sc & 077; - else reason = stop_inst; - } - else if (MB & m10) { /* NRM */ - if (cpu_unit.flags & UNIT_HSA) { - for (sc = 0; - (sc < 32) && ((AR & SIGN) == ((AR << 1) & SIGN)); - sc++) { - AR = (AR & SIGN) | ((AR << 1) & MMASK) | - ((BR >> 14) & 1); - BR = (BR & SIGN) | ((BR << 1) & MMASK); - } - sc = sc & 037; - } - else reason = stop_inst; - } - else if (MB & m9) { /* IAB */ - sc = BR; - BR = AR; - AR = sc; - } - if (MB & m8) /* ENB */ - dev_int = (dev_int | INT_ON) & ~INT_NODEF; - if (MB & m7) /* INH */ - dev_int = dev_int & ~INT_ON; - break; - -/* Shift - - Shifts are microcoded as follows: - - op<7> = right/left - op<8> = long/short - op<9> = shift/rotate (rotate bits "or" into new position) - op<10> = logical/arithmetic - - If !op<7> && op<10> (right arithmetic), A<1> propagates rightward - If op<7> && op<10> (left arithmetic), C is set if A<1> changes state - If !op<8> && op<10> (long arithmetic), B<1> is skipped - - This microcoding "explains" how the 4 undefined opcodes actually work - 003 = long arith rotate right, skip B<1>, propagate A<1>, - bits rotated out "or" into A<1> - 007 = short arith rotate right, propagate A<1>, - bits rotated out "or" into A<1> - 013 = long arith rotate left, skip B<1>, C = overflow - 017 = short arith rotate left, C = overflow -*/ - - case 020: - C = 0; /* clear C */ - sc = 0; /* clear sc */ - if ((t1 = (-MB) & SHFMASK) == 0) /* shift count */ - break; - switch (I_GETFNC (MB)) { /* case shift fnc */ - - case 000: /* LRL */ - if (t1 > 32) /* >32? all 0 */ - ut = 0; - else { - ut = GETDBL_U (AR, BR); /* get A'B */ - C = (ut >> (t1 - 1)) & 1; /* C = last out */ - if (t1 == 32) /* =32? all 0 */ - ut = 0; - else ut = ut >> t1; /* log right */ - } - PUTDBL_U (ut); /* store A,B */ - break; - - case 001: /* LRS */ - if (t1 > 31) /* limit to 31 */ - t1 = 31; - t2 = GETDBL_S (SEXT (AR), BR); /* get A'B signed */ - C = (t2 >> (t1 - 1)) & 1; /* C = last out */ - t2 = t2 >> t1; /* arith right */ - PUTDBL_S (t2); /* store A,B */ - break; - - case 002: /* LRR */ - t2 = t1 % 32; /* mod 32 */ - ut = GETDBL_U (AR, BR); /* get A'B */ - ut = (ut >> t2) | (ut << (32 - t2)); /* rot right */ - C = (ut >> 31) & 1; /* C = A<1> */ - PUTDBL_U (ut); /* store A,B */ - break; - - case 003: /* "long right arot" */ - if ((reason = stop_inst)) /* stop on undef? */ - break; - for (t2 = 0; t2 < t1; t2++) { /* bit by bit */ - C = BR & 1; /* C = last out */ - BR = (BR & SIGN) | ((AR & 1) << 14) | - ((BR & MMASK) >> 1); - AR = ((AR & SIGN) | (C << 15)) | (AR >> 1); - } - break; - - case 004: /* LGR */ - if (t1 > 16) /* > 16? all 0 */ - AR = 0; - else { - C = (AR >> (t1 - 1)) & 1; /* C = last out */ - AR = (AR >> t1) & DMASK; /* log right */ - } - break; - - case 005: /* ARS */ - if (t1 > 16) /* limit to 16 */ - t1 = 16; - C = ((SEXT (AR)) >> (t1 - 1)) & 1; /* C = last out */ - AR = ((SEXT (AR)) >> t1) & DMASK; /* arith right */ - break; - - case 006: /* ARR */ - t2 = t1 % 16; /* mod 16 */ - AR = ((AR >> t2) | (AR << (16 - t2))) & DMASK; - C = (AR >> 15) & 1; /* C = A<1> */ - break; - - case 007: /* "short right arot" */ - if ((reason = stop_inst)) /* stop on undef? */ - break; - for (t2 = 0; t2 < t1; t2++) { /* bit by bit */ - C = AR & 1; /* C = last out */ - AR = ((AR & SIGN) | (C << 15)) | (AR >> 1); - } - break; - - case 010: /* LLL */ - if (t1 > 32) /* > 32? all 0 */ - ut = 0; - else { - ut = GETDBL_U (AR, BR); /* get A'B */ - C = (ut >> (32 - t1)) & 1; /* C = last out */ - if (t1 == 32) /* =32? all 0 */ - ut = 0; - else ut = ut << t1; /* log left */ - } - PUTDBL_U (ut); /* store A,B */ - break; - - case 011: /* LLS */ - if (t1 > 31) /* limit to 31 */ - t1 = 31; - t2 = GETDBL_S (SEXT (AR), BR); /* get A'B */ - t3 = t2 << t1; /* "arith" left */ - PUTDBL_S (t3); /* store A'B */ - if ((t2 >> (31 - t1)) != ((AR & SIGN)? -1: 0)) /* shf out = sgn? */ - C = 1; - break; - - case 012: /* LLR */ - t2 = t1 % 32; /* mod 32 */ - ut = GETDBL_U (AR, BR); /* get A'B */ - ut = (ut << t2) | (ut >> (32 - t2)); /* rot left */ - C = ut & 1; /* C = B<16> */ - PUTDBL_U (ut); /* store A,B */ - break; - - case 013: /* "long left arot" */ - if ((reason = stop_inst)) /* stop on undef? */ - break; - for (t2 = 0; t2 < t1; t2++) { /* bit by bit */ - AR = (AR << 1) | ((BR >> 14) & 1); - BR = (BR & SIGN) | ((BR << 1) & MMASK) | - ((AR >> 16) & 1); - if ((AR & SIGN) != ((AR >> 1) & SIGN)) C = 1; - AR = AR & DMASK; - } - break; - - case 014: /* LGL */ - if (t1 > 16) /* > 16? all 0 */ - AR = 0; - else { - C = (AR >> (16 - t1)) & 1; /* C = last out */ - AR = (AR << t1) & DMASK; /* log left */ - } - break; - - case 015: /* ALS */ - if (t1 > 16) /* limit to 16 */ - t1 = 16; - t2 = SEXT (AR); /* save AR */ - AR = (AR << t1) & DMASK; /* "arith" left */ - if ((t2 >> (16 - t1)) != /* shf out + sgn */ - ((AR & SIGN)? -1: 0)) C = 1; - break; - - case 016: /* ALR */ - t2 = t1 % 16; /* mod 16 */ - AR = ((AR << t2) | (AR >> (16 - t2))) & DMASK; - C = AR & 1; /* C = A<16> */ - break; - - case 017: /* "short left arot" */ - if ((reason = stop_inst)) /* stop on undef? */ - break; - for (t2 = 0; t2 < t1; t2++) { /* bit by bit */ - if ((AR & SIGN) != ((AR << 1) & SIGN)) C = 1; - AR = ((AR << 1) | (AR >> 15)) & DMASK; - } - break; /* end case fnc */ - } - break; - -/* Skip */ - - case 040: - skip = 0; - if (((MB & 000001) && C) || /* SSC */ - ((MB & 000002) && ss[3]) || /* SS4 */ - ((MB & 000004) && ss[2]) || /* SS3 */ - ((MB & 000010) && ss[1]) || /* SS2 */ - ((MB & 000020) && ss[0]) || /* SS1 */ - ((MB & 000040) && AR) || /* SNZ */ - ((MB & 000100) && (AR & 1)) || /* SLN */ - ((MB & 000200) && (TST_INTREQ (INT_MPE))) || /* SPS */ - ((MB & 000400) && (AR & SIGN))) /* SMI */ - skip = 1; - if ((MB & 001000) == 0) /* reverse? */ - skip = skip ^ 1; - PC = NEWA (PC, PC + skip); - break; - -/* Operate */ - - case 060: - if (MB == 0140024) /* CHS */ - AR = AR ^ SIGN; - else if (MB == 0140040) /* CRA */ - AR = 0; - else if (MB == 0140100) /* SSP */ - AR = AR & ~SIGN; - else if (MB == 0140200) /* RCB */ - C = 0; - else if (MB == 0140320) { /* CSA */ - C = (AR & SIGN) >> 15; - AR = AR & ~SIGN; - } - else if (MB == 0140401) /* CMA */ - AR = AR ^ DMASK; - else if (MB == 0140407) { /* TCA */ - AR = (-AR) & DMASK; - sc = 0; - } - else if (MB == 0140500) /* SSM */ - AR = AR | SIGN; - else if (MB == 0140600) /* SCB */ - C = 1; - else if (MB == 0141044) /* CAR */ - AR = AR & 0177400; - else if (MB == 0141050) /* CAL */ - AR = AR & 0377; - else if (MB == 0141140) /* ICL */ - AR = AR >> 8; - else if (MB == 0141206) /* AOA */ - AR = Add16 (AR, 1); - else if (MB == 0141216) /* ACA */ - AR = Add16 (AR, C); - else if (MB == 0141240) /* ICR */ - AR = (AR << 8) & DMASK; - else if (MB == 0141340) /* ICA */ - AR = ((AR << 8) | (AR >> 8)) & DMASK; - else if ((reason = stop_inst)) - break; - else AR = Operate (MB, AR); /* undefined */ - break; - } /* end case op */ - } /* end while */ - -saved_AR = AR & DMASK; -saved_BR = BR & DMASK; -saved_XR = XR & DMASK; -pcq_r->qptr = pcq_p; /* update pc q ptr */ -return reason; -} - -/* Effective address - - The effective address calculation consists of three phases: - - base address calculation: 0/pagenumber'displacement - - (extend): indirect address resolution - (non-extend): pre-indexing - - (extend): post-indexing - (non-extend): indirect address/post-indexing resolution - - In extend mode, address calculations are carried out to 16b - and masked to 15b at exit. In non-extend mode, address bits - <1:2> are preserved by the NEWA macro; address bit <1> is - masked at exit. -*/ - -t_stat Ea (int32 IR, int32 *addr) -{ -int32 i; -int32 Y = IR & (IA | DISP); /* ind + disp */ - -if (IR & SC) Y = ((PC - 1) & PAGENO) | Y; /* cur sec? + pageno */ -if (ext) { /* extend mode? */ - for (i = 0; (i < ind_max) && (Y & IA); i++) { /* resolve ind addr */ - Y = Read (Y & X_AMASK); /* get ind addr */ - } - if (IR & IDX) Y = Y + XR; /* post-index */ - } /* end if ext */ -else { /* non-extend */ - Y = NEWA (PC, Y + ((IR & IDX)? XR: 0)); /* pre-index */ - for (i = 0; (i < ind_max) && (IR & IA); i++) { /* resolve ind addr */ - IR = Read (Y & X_AMASK); /* get ind addr */ - Y = NEWA (Y, IR + ((IR & IDX)? XR: 0)); /* post-index */ - } - } /* end else */ -*addr = Y = Y & X_AMASK; /* return addr */ -if (hst_lnt) { /* history? */ - hst[hst_p].pc = hst[hst_p].pc | HIST_EA; - hst[hst_p].ea = Y; - hst[hst_p].opnd = Read (Y); - } -if (i >= ind_max) - return STOP_IND; /* too many ind? */ -return SCPE_OK; -} - -/* Write memory */ - -t_stat Write (int32 addr, int32 val) -{ -// [RLA] Write() now checks for address breaks ... -if (((addr == 0) || (addr >= 020)) && MEM_ADDR_OK (addr)) - M[addr] = val; -if (addr == M_XR) /* write XR loc? */ - XR = val; - // [RLA] Implement "break on memory write" ... - if (sim_brk_summ && sim_brk_test (addr, SWMASK ('W'))) - return STOP_IBKPT; - else - return SCPE_OK; -} - -/* Add */ - -int32 Add16 (int32 v1, int32 v2) -{ -int32 r = v1 + v2; - -if (((v1 ^ ~v2) & (v1 ^ r)) & SIGN) - C = 1; -else C = 0; -return (r & DMASK); -} - -int32 Add31 (int32 v1, int32 v2) -{ -int32 r = v1 + v2; - -if (((v1 ^ ~v2) & (v1 ^ r)) & DP_SIGN) - C = 1; -else C = 0; -return r; -} - -// [RLA] Standard (fixed vector) interrupt action ... - -int32 cpu_interrupt (int32 vec) -{ -pme = ext; /* save extend */ -if (cpu_unit.flags & UNIT_EXT) - ext = 1; /* ext opt? extend on */ -dev_int = dev_int & ~INT_ON; /* intr off */ -return 0120000 | vec; /* inst = JST* vector */ -} - -// [RLA] Extended (priority) interrupt action ... -int32 cpu_ext_interrupt (void) { - // Unlike the standard interrupts, which have a fixed vector shared by all - // devices, the extended interrupts have a unique vector for every device. - // Moreover, extended interrupts are prioritized so that the lowest numbered - // interrupts have priority. That means we have to actually scan the bitmap - // of active interrupts to figure out which one to take. - // - // One uncomfortable thing about the external interrupts is that it appears - // that they were edge triggered - once an interrupt on a given level was - // granted, that interrupt wouldn't occur again until another edge occurred on - // the same request. I'm "uncomfortable" with this because it's different from - // the way the standard interrupt works - that's completely level sensitive. - // Still, this Honeywell document - // - // http://bitsavers.informatik.uni-stuttgart.de/pdf/honeywell/series16/h316/70130072167D_316_Interfacing_Apr73.pdf - // - // (read Chapter 4, Priority Interrupts, the very first paragraph) at least - // seems to imply edge triggering. And the IMP firmware is written as if they - // are edge triggered - there are many cases (modem output, task, RTC) where - // the IMP code does nothing to clear the interrupt request flag. So we're - // going with edge triggered version for now... - int32 i; uint16 m, irq; - irq = dev_ext_int & dev_ext_enb; - for (i = 1, m = SIGN; m != 0; ++i, m >>= 1) { - if ((irq & m) != 0) { - // Extended interrupts are edge triggered (see above) - when this - // interrupt is granted, clear the request ... - CLR_EXT_INT(m); - return cpu_interrupt(M_INT+i); - } - } - // If we get here, it means that we were called with no interrupt bits set. - // That really should never happen, so just HALT ... - return(0); -} - -/* Unimplemented I/O device */ - -int32 undio (int32 op, int32 fnc, int32 val, int32 dev) -{ -return ((stop_dev << IOT_V_REASON) | val); -} - -/* [RLA] Special I/O devices */ - -int32 sim_ota_2024 (int32 inst, int32 fnc, int32 dat, int32 dev) -{ - // OTA instructions with a device code of 20 or 24 are really SMK - // (Set interrupt Mask) instructions. OTA 20 sets the standard H316 - // interrupt mask, and OTA 120, OTA 220 and OTA 320 set the extended - // interrupt mask (of which only one, OTA 120, is used by the IMP). - // - // Further, OTA 1020 is the OTK instruction which sets special CPU - // flags (single or double precision HSA, extended addressing mode, - // the carry flag, etc). - // - // This routine implements these special OTKs as part of the CPU. - // That allows us to implement the extra interrupt masks needed by the - // IMP, and it also allows the CLK device to be disabled without losing - // the SMK or OTK instructions. The clock was an option on the original - // H316 and is not required to be present, and the IMP in particular - // needs it to be disabled. - - // Although OTA 24 is reserved nothing we currently simulate uses it! - - if (dev == 024) - return IOBADFNC (dat); - - // Device code 20... - switch (fnc) { - case 000: // SMK 020 - set standard interrupt mask - dev_enb = dat; - break; - case 001: // SMK 120 - set extended interrupt mask #1 - if (ext_ints < 16) - return IOBADFNC(dat); - dev_ext_enb = dat; - break; - case 002: // SMK 220 - set extended interrupt mask #2 - case 003: // SMK 320 - set extended interrupt mask #3 - return IOBADFNC(dat); - case 010: // OTK - output keys - C = (dat >> 15) & 1; /* set C */ - if (cpu_unit.flags & UNIT_HSA) /* HSA included? */ - dp = (dat >> 14) & 1; /* set dp */ - if (cpu_unit.flags & UNIT_EXT) { /* ext opt? */ - if (dat & 020000) { /* ext set? */ - ext = 1; /* yes, set */ - extoff_pending = 0; - } - else extoff_pending = 1; /* no, clr later */ - } - sc = dat & 037; /* set sc */ - break; - default: - return IOBADFNC (dat); - } - return dat; -} - -/* DMA control */ - -int32 dmaio (int32 inst, int32 fnc, int32 dat, int32 dev) -{ -int32 ch = (fnc - 1) & 03; - -switch (inst) { /* case on opcode */ - - case ioOCP: /* OCP */ - if ((fnc >= 001) && (fnc <= 004)) { /* load addr ctr */ - dma_ad[ch] = dat; - dma_wc[ch] = 0; - dma_eor[ch] = 0; - } - else if ((fnc >= 011) && (fnc <= 014)) /* load range ctr */ - dma_wc[ch] = (dma_wc[ch] | dat) & 077777; - else return IOBADFNC (dat); /* undefined */ - break; - - case ioINA: /* INA */ - if ((fnc >= 011) && (fnc <= 014)) { - if (dma_eor[ch]) /* end range? nop */ - return dat; - return IOSKIP (0100000 | dma_wc[ch]); /* return range */ - } - else return IOBADFNC (dat); - } - -return dat; -} - -/* Undefined operate instruction. This code is reached when the - opcode does not correspond to a standard operate instruction. - It simulates the behavior of the actual logic. - - An operate instruction executes in 4 or 6 phases. A 'normal' - instruction takes 4 phases: - - t1 t1 - t2/tlate t2/t2 extended into t3 - t3/tlate t3 - t4 t4 - - A '1.5 cycle' instruction takes 6 phases: - - t1 t1 - t2/tlate t2/t2 extended into t3 - t3/tlate t3 - t2/tlate 'special' t2/t2 extended into t3 - t3/tlate t3 - t4 t4 - - The key signals, by phase, are the following - - tlate EASTL enable A to sum leg 1 (else 0) - (((m12+m16)x!azzzz)+(m9+m11+azzzz) - EASBM enable 0 to sum leg 2 (else 177777) - (m9+m11+azzzz) - JAMKN jam carry network to 0 = force XOR - ((m12+m16)x!azzzz) - EIKI7 force carry into adder - ((m15x(C+!m13))x!JAMKN) - - t3 CLDTR set D to 177777 (always) - ESDTS enable adder sum to D (always) - SETAZ enable repeat cycle = set azzzz - (m8xm15) - - if azzzz { - t2 CLATR clear A register (due to azzzz) - EDAHS enable D high to A high register (due to azzzz) - EDALS enable D low to A low register (due to azzzz) - - tlate, t3 as above - } - - t4 CLATR clear A register - (m11+m15+m16) - CLA1R clear A1 register - (m10+m14) - EDAHS enable D high to A high register - ((m11xm14)+m15+m16) - EDALS enable D low to A low register - ((m11xm13)+m15+m16) - ETAHS enable D transposed to A high register - (m9xm11) - ETALS enable D transposed to A low register - (m10xm11) - EDA1R enable D1 to A1 register - ((m8xm10)+m14) - CBITL clear C, conditionally set C from adder output - (m9x!m11) - CBITG conditionally set C if D1 - (m10xm12xD1) - CBITE unconditionally set C - (m8xm9) -*/ - -int32 Operate (int32 MB, int32 AR) -{ -int32 D, jamkn, eiki7, easbm, eastl, setaz; -int32 clatr, cla1r, edahs, edals, etahs, etals, eda1r; -int32 cbitl, cbitg, cbite; -int32 aleg, bleg, ARx; - -/* Phase tlate */ - -ARx = AR; /* default */ -jamkn = (MB & (m12+m16)) != 0; /* m12+m16 */ -easbm = (MB & (m9+m11)) != 0; /* m9+m11 */ -eastl = jamkn || easbm; /* m9+m11+m12+m16 */ -setaz = (MB & (m8+m15)) == (m8+m15); /* m8xm15*/ -eiki7 = (MB & m15) && (C || !(MB & m13)); /* cin */ -aleg = eastl? AR: 0; /* a input */ -bleg = easbm? 0: DMASK; /* b input */ -if (jamkn) /* jammin? xor */ - D = aleg ^ bleg; -else D = (aleg + bleg + eiki7) & DMASK; /* else add */ - -/* Possible repeat at end of tlate - special t2, repeat tlate */ - -if (setaz) { - ARx = D; /* forced: t2 */ - aleg = ARx; /* forced: tlate */ - bleg = 0; /* forced */ - jamkn = 0; /* forced */ - D = (aleg + bleg + eiki7) & DMASK; /* forced add */ - sc = 0; /* ends repeat */ - } - -/* Phase t4 */ - -clatr = (MB & (m11+m15+m16)) != 0; /* m11+m15+m16 */ -cla1r = (MB & (m10+m14)) != 0; /* m10+m14 */ -edahs = ((MB & (m11+m14)) == (m11+m14)) || /* (m11xm14)+m15+m16 */ - (MB & (m15+m16)); -edals = ((MB & (m11+m13)) == (m11+m13)) || /* (m11xm13)+m15+m16 */ - (MB & (m15+m16)); -etahs = (MB & (m9+m11)) == (m9+m11); /* m9xm11 */ -etals = (MB & (m10+m11)) == (m10+m11); /* m10xm11 */ -eda1r = ((MB & (m8+m10)) == (m8+m10)) || (MB & m14); /* (m8xm10)+m14 */ -cbitl = (MB & (m9+m11)) == m9; /* m9x!m11 */ -cbite = (MB & (m8+m9)) == (m8+m9); /* m8xm9 */ -cbitg = (MB & (m10+m12)) == (m10+m12); /* m10xm12 */ - -if (clatr) /* clear A */ - ARx = 0; -if (cla1r) /* clear A1 */ - ARx = ARx & ~SIGN; -if (edahs) /* D hi to A hi */ - ARx = ARx | (D & 0177400); -if (edals) /* D lo to A lo */ - ARx = ARx | (D & 0000377); -if (etahs) /* D lo to A hi */ - ARx = ARx | ((D << 8) & 0177400); -if (etals) /* D hi to A lo */ - ARx = ARx | ((D >> 8) & 0000377); -if (eda1r) /* D1 to A1 */ - ARx = ARx | (D & SIGN); -if (cbitl) { /* ovflo to C */ - -/* Overflow calculation. Cases: - - aleg bleg cin overflow - - 0 x x can't overflow - A 0 0 can't overflow - A -1 1 can't overflow - A 0 1 overflow if 77777->100000 - A -1 0 overflow if 100000->77777 -*/ - - if (!jamkn && - ((bleg && !eiki7 && (D == 0077777)) || - (!bleg && eiki7 && (D == 0100000)))) - C = 1; - else C = 0; - } -if (cbite || (cbitg && (D & SIGN))) /* C = 1 */ - C = 1; -return ARx; -} - -/* Reset routines */ - -t_stat cpu_reset (DEVICE *dptr) -{ -int32 i; - -saved_AR = saved_BR = saved_XR = 0; -C = 0; -dp = 0; -ext = pme = extoff_pending = 0; -dev_int = dev_int & ~(INT_PEND|INT_NMI); -dev_ext_int = dev_enb = dev_ext_enb = 0; -for (i = 0; i < DMA_MAX; i++) - dma_ad[i] = dma_wc[i] = dma_eor[i] = 0; -chan_req = 0; -pcq_r = find_reg ("PCQ", NULL, dptr); -if (pcq_r) - pcq_r->qptr = 0; -else return SCPE_IERR; -// [RLA] We now have two break types - "E" (break on execution) and also "W" -// [RLA] (break on write)... -sim_brk_types = SWMASK('W') | SWMASK('E'); -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] & DMASK; -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; -if (addr == 0) - saved_XR = val & DMASK; -M[addr] = val & DMASK; -return SCPE_OK; -} - -/* Option processors */ - -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 val, char *cptr, void *desc) -{ -int32 mc = 0; -uint32 i; - -if ((val <= 0) || (val > MAXMEMSIZE) || ((val & 07777) != 0) || - (((cpu_unit.flags & UNIT_EXT) == 0) && (val > (NX_AMASK + 1)))) - 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; -} - -/* [RLA] Set/Show number of interrupts supported */ - -t_stat cpu_set_interrupts (UNIT *uptr, int32 val, char *cptr, void *desc) -{ - uint32 newint; t_stat ret; - if (cptr == NULL) return SCPE_ARG; - newint = get_uint (cptr, 10, 49, &ret); - if (ret != SCPE_OK) return ret; - if ((newint != 0) && (newint != 16)) return SCPE_ARG; - ext_ints = newint; - return SCPE_OK; -} - -t_stat cpu_show_interrupts (FILE *st, UNIT *uptr, int32 val, void *desc) -{ - if (ext_ints == 0) - fprintf(st,"standard interrupts"); - else - fprintf(st,"extended interrupts = %d", ext_ints); - return SCPE_OK; -} - -t_stat cpu_set_nchan (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -uint32 i, newmax; -t_stat r; - -if (cptr == NULL) - return SCPE_ARG; -newmax = get_uint (cptr, 10, DMA_MAX, &r); /* get new max */ -if ((r != SCPE_OK) || (newmax == dma_nch)) /* err or no chg? */ - return r; -dma_nch = newmax; /* set new max */ -for (i = newmax; i < DMA_MAX; i++) { /* reset chan */ - dma_ad[i] = dma_wc[i] = dma_eor[i] = 0; - chan_req = chan_req & ~(1 << i); - } -return SCPE_OK; -} - -/* Show DMA channels */ - -t_stat cpu_show_nchan (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -if (dma_nch) - fprintf (st, "DMA channels = %d", dma_nch); -else fprintf (st, "no DMA"); -return SCPE_OK; -} - -/* Show channel state */ - -t_stat cpu_show_dma (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -if ((val < 0) || (val >= DMA_MAX)) - return SCPE_IERR; -fputs ((dma_ad[val] & DMA_IN)? "Input": "Output", st); -fprintf (st, ", addr = %06o, count = %06o, ", dma_ad[val] & X_AMASK, dma_wc[val]); -fprintf (st, "end of range %s\n", (dma_eor[val]? "set": "clear")); -return SCPE_OK; -} - -/* Set I/O device to IOBUS / DMA channel / DMC channel */ - -t_stat io_set_iobus (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -DEVICE *dptr; -DIB *dibp; - -if (val || cptr || (uptr == NULL)) - return SCPE_IERR; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if (dibp == NULL) - return SCPE_IERR; -dibp->chan = 0; -return SCPE_OK; -} - -t_stat io_set_dma (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -DEVICE *dptr; -DIB *dibp; -uint32 newc; -t_stat r; - -if ((cptr == NULL) || (uptr == NULL)) - return SCPE_IERR; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if (dibp == NULL) - return SCPE_IERR; -if (dma_nch == 0) - return SCPE_NOFNC; -newc = get_uint (cptr, 10, DMA_MAX, &r); /* get new */ -if ((r != SCPE_OK) || (newc == 0) || (newc > dma_nch)) - return SCPE_ARG; -dibp->chan = (newc - DMA_MIN) + DMA_V_DMA1 + 1; /* store */ -return SCPE_OK; -} - -t_stat io_set_dmc (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -DEVICE *dptr; -DIB *dibp; -uint32 newc; -t_stat r; - -if ((cptr == NULL) || (uptr == NULL)) - return SCPE_IERR; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if (dibp == NULL) - return SCPE_IERR; -if (!(cpu_unit.flags & UNIT_DMC)) - return SCPE_NOFNC; -newc = get_uint (cptr, 10, DMC_MAX, &r); /* get new */ -if ((r != SCPE_OK) || (newc == 0)) - return SCPE_ARG; -dibp->chan = (newc - DMC_MIN) + DMC_V_DMC1 + 1; /* store */ -return SCPE_OK; -} - -/* Show channel configuration */ - -t_stat io_show_chan (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -DEVICE *dptr; -DIB *dibp; - -if (uptr == NULL) - return SCPE_IERR; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if (dibp == NULL) - return SCPE_IERR; -if (dibp->chan == 0) - fprintf (st, "IO bus"); -else if (dibp->chan < (DMC_V_DMC1 + 1)) - fprintf (st, "DMA channel %d", dibp->chan); -else fprintf (st, "DMC channel %d", dibp->chan - DMC_V_DMC1); -return SCPE_OK; -} - -/* Set up I/O dispatch and channel maps */ -// [RLA] Check for DMC conflicts (on both DMC channels!) ... - -t_bool set_chanmap (DEVICE *dptr, DIB *dibp, uint32 dno, uint32 chan) -{ - if ((chan < DMC_V_DMC1) && (chan >= dma_nch)) { - sim_printf ("%s configured for DMA channel %d\n", sim_dname (dptr), chan + 1); - return TRUE; - } - if ((chan >= DMC_V_DMC1) && !(cpu_unit.flags & UNIT_DMC)) { - sim_printf ("%s configured for DMC, option disabled\n", sim_dname (dptr)); - return TRUE; - } - if (chan_map[chan]) { /* channel conflict? */ - sim_printf ("%s DMA/DMC channel conflict, devno = %02o\n", sim_dname (dptr), dno); - return TRUE; - } - chan_map[chan] = dno; /* channel back map */ - return FALSE; -} - -t_bool devtab_init (void) -{ -DEVICE *dptr; -DIB *dibp; -uint32 i, j, dno; - -for (i = 0; i < DEV_MAX; i++) - iotab[i] = NULL; -for (i = 0; i < (DMA_MAX + DMC_MAX); i++) - chan_map[i] = 0; -for (i = 0; (dptr = sim_devices[i]); i++) { /* loop thru devices */ - dibp = (DIB *) dptr->ctxt; /* get DIB */ - if ((dibp == NULL) || (dptr->flags & DEV_DIS)) /* exist, enabled? */ - continue; - dno = dibp->dev; /* device number */ - for (j = 0; j < dibp->num; j++) { /* repeat for slots */ - if (iotab[dno + j]) { /* conflict? */ - sim_printf ("%s device number conflict, devno = %02o\n", - sim_dname (dptr), dno + j); - return TRUE; - } - iotab[dno + j] = dibp->io; /* set I/O routine */ - } /* end for */ - // [RLA] set up the channel map - if (dibp->chan != 0) - if (set_chanmap(dptr, dibp, dno, dibp->chan-1)) - return TRUE; - if (dibp->chan2 != 0) - if (set_chanmap(dptr, dibp, dno, dibp->chan2-1)) - return TRUE; - // [RLA] If the device uses extended interrupts, check that they're enabled. - if ((dibp->inum != INT_V_NONE) && (dibp->inum >= INT_V_EXTD) && (ext_ints == 0)) { - sim_printf ("%s uses extended interrupts but that option is disabled\n", sim_dname (dptr)); - return TRUE; - } - } /* end for */ -for (i = 0; i < DEV_MAX; i++) { /* fill in blanks */ - if (iotab[i] == NULL) - iotab[i] = &undio; - } -return FALSE; -} - -/* Set history */ - -t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 i, lnt; -t_stat r; - -if (cptr == NULL) { - for (i = 0; i < hst_lnt; i++) - hst[i].pc = 0; - hst_p = 0; - return SCPE_OK; - } -lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r); -if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) - return SCPE_ARG; -hst_p = 0; -if (hst_lnt) { - free (hst); - hst_lnt = 0; - hst = NULL; - } -if (lnt) { - hst = (InstHistory *) calloc (lnt, sizeof (InstHistory)); - if (hst == NULL) - return SCPE_MEM; - hst_lnt = lnt; - } -return SCPE_OK; -} - -/* Show history */ - -t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -int32 cr, k, di, op, lnt; -char *cptr = (char *) desc; -extern t_value *sim_eval; -t_stat r; -InstHistory *h; -static uint8 has_opnd[16] = { - 0, 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 - }; - -if (hst_lnt == 0) /* enabled? */ - return SCPE_NOFNC; -if (cptr) { - lnt = (int32) get_uint (cptr, 10, hst_lnt, &r); - if ((r != SCPE_OK) || (lnt == 0)) - return SCPE_ARG; - } -else lnt = hst_lnt; -di = hst_p - lnt; /* work forward */ -if (di < 0) - di = di + hst_lnt; -fprintf (st, " PC C A B X ea IR\n"); -fprintf (st, "----- - ------ ------ ------ ----- -----------\n\n"); -for (k = 0; k < lnt; k++) { /* print specified */ - h = &hst[(++di) % hst_lnt]; /* entry pointer */ - if (h->pc & HIST_PC) { /* instruction? */ - cr = (h->pc & HIST_C)? 1: 0; /* carry */ - fprintf (st, "%05o %o %06o %06o %06o ", - h->pc & X_AMASK, cr, h->ar, h->br, h->xr); - if (h->pc & HIST_EA) - fprintf (st, "%05o ", h->ea); - else fprintf (st, " "); - sim_eval[0] = h->ir; - if ((fprint_sym (st, h->pc & X_AMASK, sim_eval, - &cpu_unit, SWMASK ('M'))) > 0) - fprintf (st, "(undefined) %06o", h->ir); - op = I_GETOP (h->ir) & 017; /* base op */ - if (has_opnd[op]) - fprintf (st, " [%06o]", h->opnd); - if (h->iack) // [RLA] - fprintf(st, " INTERRUPT"); // [RLA] - fputc ('\n', st); /* end line */ - } /* end else instruction */ - } /* end for */ -return SCPE_OK; -} diff --git a/H316/h316_defs.h b/H316/h316_defs.h deleted file mode 100644 index dc7a8ba6..00000000 --- a/H316/h316_defs.h +++ /dev/null @@ -1,227 +0,0 @@ -/* h316_defs.h: Honeywell 316/516 simulator definitions - - Copyright (c) 1999-2015, 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. - - 31-May-13 RLA DIB - add second channel, interrupt and user parameter - 19-Nov-11 RMS Removed XR macro, added XR_LOC macro (from Adrian Wise) - 22-May-10 RMS Added check for 64b definitions - 15-Feb-05 RMS Added start button interrupt - 01-Dec-04 RMS Added double precision constants - 24-Oct-03 RMS Added DMA/DMC support - 25-Apr-03 RMS Revised for extended file support -*/ - -#ifndef H316_DEFS_H_ -#define H316_DEFS_H_ 0 - -#include "sim_defs.h" /* simulator defns */ - -#if defined(USE_INT64) || defined(USE_ADDR64) -#error "H316 does not support 64b values!" -#endif - -/* Simulator stop codes */ - -#define STOP_RSRV 1 /* must be 1 */ -#define STOP_IODV 2 /* must be 2 */ -#define STOP_HALT 3 /* HALT */ -#define STOP_IBKPT 4 /* breakpoint */ -#define STOP_IND 5 /* indirect loop */ -#define STOP_DMAER 6 /* DMA error */ -#define STOP_MTWRP 7 /* MT write protected */ -#define STOP_DPOVR 8 /* DP write overrun */ -#define STOP_DPFMT 9 /* DP invalid format */ - -/* Memory */ - -#define MAXMEMSIZE 32768 /* max memory size */ -#define MEMSIZE (cpu_unit.capac) /* actual memory size */ -#define X_AMASK (MAXMEMSIZE - 1) /* ext address mask */ -#define NX_AMASK ((MAXMEMSIZE / 2) - 1) /* nx address mask */ -#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) - -/* Architectural constants */ - -#define SIGN 0100000 /* sign */ -#define DP_SIGN 010000000000 -#define DMASK 0177777 /* data mask */ -#define MMASK (DMASK & ~SIGN) /* magnitude mask */ -#define M_CLK 061 /* clock location */ -#define M_RSTINT 062 /* restrict int */ -#define M_INT 063 /* int location */ -#define M_XR (ext? 0: (PC & 040000)) /* XR location */ - -/* CPU options */ - -#define UNIT_V_MSIZE (UNIT_V_UF + 0) /* dummy mask */ -#define UNIT_V_EXT (UNIT_V_UF + 1) /* extended mem */ -#define UNIT_V_HSA (UNIT_V_UF + 2) /* high speed arith */ -#define UNIT_V_DMC (UNIT_V_UF + 3) /* DMC */ -#define UNIT_MSIZE (1u << UNIT_V_MSIZE) -#define UNIT_EXT (1u << UNIT_V_EXT) -#define UNIT_HSA (1u << UNIT_V_HSA) -#define UNIT_DMC (1u << UNIT_V_DMC) - -/* Instruction format */ - -#define I_M_OP 077 /* opcode */ -#define I_V_OP 10 -#define I_GETOP(x) (((x) >> I_V_OP) & I_M_OP) -#define I_M_FNC 017 /* function */ -#define I_V_FNC 6 -#define I_GETFNC(x) (((x) >> I_V_FNC) & I_M_FNC) -#define IA 0100000 /* indirect address */ -#define IDX 0040000 /* indexed */ -#define SC 0001000 /* sector */ -#define DISP 0000777 /* page displacement */ -#define PAGENO 0077000 /* page number */ -#define INCLRA (010 << I_V_FNC) /* INA clear A */ -#define DEVMASK 0000077 /* device mask */ -#define SHFMASK 0000077 /* shift mask */ - -/* I/O opcodes */ - -#define ioOCP 0 /* output control */ -#define ioSKS 1 /* skip if set */ -#define ioINA 2 /* input to A */ -#define ioOTA 3 /* output from A */ -#define ioEND 4 /* channel end */ - -/* Device information block */ - -struct h316_dib { - uint32 dev; /* device number */ - uint32 num; /* number of slots */ - uint32 chan; /* dma/dmc channel */ - uint32 chan2; /* alternate DMA/DMD channel */ - uint32 inum; /* interrupt number */ - uint32 inum2; /* alternate interrupt */ - int32 (*io) (int32 inst, int32 fnc, int32 dat, int32 dev); - uint32 u3; /* "user" parameter #1 */ -}; -typedef struct h316_dib DIB; - -/* DMA/DMC channel numbers */ - -#define IOBUS 0 /* IO bus */ -#define DMA_MIN 1 /* 4 DMA channels */ -#define DMA_MAX 4 -#define DMC_MIN 1 /* 16 DMC channels */ -#define DMC_MAX 16 - -#define DMA1 (DMA_MIN) -#define DMC1 (DMA_MAX+DMC_MIN) - -/* DMA/DMC bit assignments in channel request word */ - -#define DMA_V_DMA1 0 /* DMA channels */ -#define DMC_V_DMC1 4 /* DMC channels */ -#define SET_CH_REQ(x) chan_req = chan_req | (1 << (x)) -#define Q_DMA(x) (((x) >= 0) && ((x) < DMC_V_DMC1)) - -/* DMA/DMC definitions */ - -#define DMA_IN 0100000 /* input flag */ -#define DMC_BASE 020 /* DMC memory base */ - -/* I/O device codes */ - -#define PTR 001 /* paper tape reader */ -#define PTP 002 /* paper tape punch */ -#define LPT 003 /* line printer */ -#define TTY 004 /* console */ -#define CDR 005 /* card reader */ -#define MT 010 /* mag tape data */ -#define CLK_KEYS 020 /* clock/keys (CPU) */ -#define FHD 022 /* fixed head disk */ -#define DMA 024 /* DMA control */ -#define DP 025 /* moving head disk */ -#define DEV_MAX 64 - -/* Interrupt flags, definitions correspond to SMK bits */ - -#define INT_V_CLK 0 /* clock */ -#define INT_V_MPE 1 /* parity error */ -#define INT_V_LPT 2 /* line printer */ -#define INT_V_CDR 4 /* card reader */ -#define INT_V_TTY 5 /* teletype */ -#define INT_V_PTP 6 /* paper tape punch */ -#define INT_V_PTR 7 /* paper tape reader */ -#define INT_V_FHD 8 /* fixed head disk */ -#define INT_V_DP 12 /* moving head disk */ -#define INT_V_MT 15 /* mag tape */ -#define INT_V_START 16 /* start button */ -#define INT_V_NODEF 17 /* int not deferred */ -#define INT_V_ON 18 /* int on */ -#define INT_V_EXTD 16 /* first extended interrupt */ -#define INT_V_NONE 0xffffffff /* no interrupt used */ - -/* I/O macros */ - -#define IOT_V_REASON 17 -#define IOT_V_SKIP 16 -#define IOT_SKIP (1u << IOT_V_SKIP) -#define IORETURN(f,v) (((f)? (v): SCPE_OK) << IOT_V_REASON) -#define IOBADFNC(x) (((stop_inst) << IOT_V_REASON) | (x)) -#define IOSKIP(x) (IOT_SKIP | (x)) - -#define INT_CLK (1u << INT_V_CLK) -#define INT_MPE (1u << INT_V_MPE) -#define INT_LPT (1u << INT_V_LPT) -#define INT_CDR (1u << INT_V_CDR) -#define INT_TTY (1u << INT_V_TTY) -#define INT_PTP (1u << INT_V_PTP) -#define INT_PTR (1u << INT_V_PTR) -#define INT_FHD (1u << INT_V_FHD) -#define INT_DP (1u << INT_V_DP) -#define INT_MT (1u << INT_V_MT) -#define INT_START (1u << INT_V_START) -#define INT_NODEF (1u << INT_V_NODEF) -#define INT_ON (1u << INT_V_ON) -#define INT_NMI (INT_START) -#define INT_PEND (INT_ON | INT_NODEF) - -// [RLA] These macros now all affect the standard interrupts. We'll leave -// [RLA] them alone for backward compatibility with the existing code. -#define SET_INT(x) dev_int = dev_int | (x) -#define CLR_INT(x) dev_int = dev_int & ~(x) -#define TST_INT(x) ((dev_int & (x)) != 0) -#define CLR_ENB(x) dev_enb = dev_enb & ~(x) -#define TST_INTREQ(x) ((dev_int & dev_enb & (x)) != 0) - -// [RLA] These macros are functionally identical, but affect extended interrupts. -#define SET_EXT_INT(x) dev_ext_int = dev_ext_int | (x) -#define CLR_EXT_INT(x) dev_ext_int = dev_ext_int & ~(x) -#define TST_EXT_INT(x) ((dev_ext_int & (x)) != 0) -#define CLR_EXT_ENB(x) dev_ext_enb = dev_ext_enb & ~(x) -#define TST_EXT_INTREQ(x) ((dev_ext_int & dev_ext_enb & (x)) != 0) - -/* Prototypes */ - -t_stat io_set_iobus (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat io_set_dma (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat io_set_dmc (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat io_show_chan (FILE *st, UNIT *uptr, int32 val, void *desc); - -#endif diff --git a/H316/h316_dp.c b/H316/h316_dp.c deleted file mode 100644 index 3ad0b8e1..00000000 --- a/H316/h316_dp.c +++ /dev/null @@ -1,1093 +0,0 @@ -/* h316_dp.c: Honeywell 4623, 4651, 4720 disk simulator - - Copyright (c) 2003-2017, Robert M. Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - dp 4623 disk subsystem - 4651 disk subsystem - 4720 disk subsystem - - 13-Mar-17 RMS Annotated intentional fall through in switch - 03-Jul-13 RLA compatibility changes for extended interrupts - 19-Mar-12 RMS Fixed declaration of chan_req (Mark Pizzolato) - 04-Sep-05 RMS Fixed missing return (Peter Schorn) - 15-Jul-05 RMS Fixed bug in attach routine - 01-Dec-04 RMS Fixed bug in skip on !seeking - - The Honeywell disks have the unique characteristic of supporting variable - formatting, on a per track basis. To accomodate this, each track is - simulated as 2048 words, divided into records. (2048 words accomodates - the largest record of 1891 + 8 overhead words.) A record is structured - as follows: - - word 0 record length n (0 = end of track) - word 1 record address (16b, uninterpreted by the simulator) - word 2 record extension (0 to 4 words of permitted 'overwrite') - word 3 first data word - : - word 3+n-1 last data word - word 3+n checksum word - word 4+n first extension word - : - word 7+n fourth extension word - word 8+n start of next record - - Formatting is done in two ways. The SET DPn FORMAT=k command formats - unit n with k records per track, each record having the maximum allowable - record size and a standard record address; or with k words per record. - Alternately, the simulator allows programmatic formating. When a track - is formated, the program supplies record parameters as follows: - - word 0 record address - words 1-n data words - word n+1 gap size in bits - - To make this work, the simulator tracks the consumption of bits in the - track, against the track capacity in bits. Bit consumption is: - - 16.5 * 16 for overhead (including address and checksum) - n * 16 for data - 'gap' for gap, which must be at least 5% of the record length -*/ - -#include "h316_defs.h" -#include - -#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_WLK (1 << UNIT_V_WLK) -#define FNC u3 /* saved function */ -#define CYL u4 /* actual cylinder */ -#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */ -#define DP_TRKLEN 2048 /* track length, words */ -#define DP_NUMDRV 8 /* max # drives */ -#define DP_NUMTYP 3 /* # controller types */ - -/* Record format */ - -#define REC_LNT 0 /* length (unextended) */ -#define REC_ADDR 1 /* address */ -#define REC_EXT 2 /* extension (0-4) */ -#define REC_DATA 3 /* start of data */ -#define REC_OVHD 8 /* overhead words */ -#define REC_MAXEXT 4 /* maximum extension */ -#define REC_OVHD_WRDS 16.5 /* 16.5 words */ -#define REC_OVHD_BITS ((16 * 16) + 8) - -/* Status word, ^ = dynamic */ - -#define STA_BUSY 0100000 /* busy */ -#define STA_RDY 0040000 /* ready */ -#define STA_ADRER 0020000 /* address error */ -#define STA_FMTER 0010000 /* format error */ -#define STA_HNLER 0004000 /* heads not loaded (NI) */ -#define STA_OFLER 0002000 /* offline */ -#define STA_SEKER 0001000 /* seek error */ -#define STA_MBZ 0000700 -#define STA_WPRER 0000040 /* write prot error */ -#define STA_UNSER 0000020 /* unsafe */ -#define STA_CSMER 0000010 /* checksum error */ -#define STA_DTRER 0000004 /* transfer rate error */ -#define STA_ANYER 0000002 /* any error^ */ -#define STA_EOR 0000001 /* end of record */ -#define STA_ALLERR (STA_ADRER|STA_FMTER|STA_HNLER|STA_OFLER|STA_SEKER|\ - STA_WPRER|STA_UNSER|STA_DTRER) - -/* Functions */ - -#define FNC_SK0 0000 /* recalibrate */ -#define FNC_SEEK 0001 /* seek */ -#define FNC_RCA 0002 /* read current */ -#define FNC_UNL 0004 /* unload */ -#define FNC_FMT 0005 /* format */ -#define FNC_RW 0006 /* read/write */ -#define FNC_STOP 0010 /* stop format */ -#define FNC_RDS 0011 /* read status */ -#define FNC_DMA 0013 /* DMA/DMC */ -#define FNC_AKI 0014 /* acknowledge intr */ -#define FNC_IOBUS 0017 /* IO bus */ -#define FNC_2ND 0020 /* second state */ -#define FNC_3RD 0040 /* third state */ -#define FNC_4TH 0060 /* fourth state */ -#define FNC_5TH 0100 /* fifth state */ - -/* Command word 1 */ - -#define CW1_RW 0100000 /* read/write */ -#define CW1_DIR 0000400 /* seek direction */ -#define CW1_V_UNIT 11 /* unit select */ -#define CW1_V_HEAD 6 /* head select */ -#define CW1_V_OFFS 0 /* seek offset */ -#define CW1_GETUNIT(x) (((x) >> CW1_V_UNIT) & dp_tab[dp_ctype].umsk) -#define CW1_GETHEAD(x) (((x) >> CW1_V_HEAD) & dp_tab[dp_ctype].hmsk) -#define CW1_GETOFFS(x) (((x) >> CW1_V_OFFS) & dp_tab[dp_ctype].cmsk) - -/* OTA states */ - -#define OTA_NOP 0 /* normal */ -#define OTA_CW1 1 /* expecting CW1 */ -#define OTA_CW2 2 /* expecting CW2 */ - -/* Transfer state */ - -#define XIP_UMSK 007 /* unit mask */ -#define XIP_SCHED 010 /* scheduled */ -#define XIP_WRT 020 /* write */ -#define XIP_FMT 040 /* format */ - -/* The H316/516 disk emulator supports three disk controllers: - - controller units cylinders surfaces data words per track - - 4651 4 203 2 1908.25 - 4623 8 203 10 1816.5 - 4720 8 203 20 1908.25 - - Disk types may not be intermixed on the same controller. -*/ - -#define TYPE_4651 0 -#define UNIT_4651 4 -#define CYL_4651 203 -#define SURF_4651 2 -#define WRDS_4651 1908.25 -#define UMSK_4651 0003 -#define HMSK_4651 0001 -#define CMSK_4651 0377 -#define CAP_4651 (CYL_4651*SURF_4651*DP_TRKLEN) - -#define TYPE_4623 1 -#define UNIT_4623 8 -#define CYL_4623 203 -#define SURF_4623 10 -#define WRDS_4623 1816.5 -#define UMSK_4623 0007 -#define HMSK_4623 0017 -#define CMSK_4623 0377 -#define CAP_4623 (CYL_4623*SURF_4623*DP_TRKLEN) - -#define TYPE_4720 2 -#define UNIT_4720 8 -#define CYL_4720 203 -#define SURF_4720 20 -#define WRDS_4720 1908.25 -#define UMSK_4720 0007 -#define HMSK_4720 0037 -#define CMSK_4720 0377 -#define CAP_4720 (CYL_4720*SURF_4720*DP_TRKLEN) - -struct drvtyp { - char *name; - uint32 numu; - uint32 cyl; - uint32 surf; - uint32 cap; - uint32 umsk; - uint32 hmsk; - uint32 cmsk; - float wrds; - }; - -#define DP_DRV(d) \ - #d, \ - UNIT_##d, CYL_##d, SURF_##d, CAP_##d, \ - UMSK_##d, HMSK_##d, CMSK_##d, WRDS_##d - -static struct drvtyp dp_tab[] = { - { DP_DRV (4651) }, - { DP_DRV (4623) }, - { DP_DRV (4720) } - }; - -extern int32 dev_int, dev_enb; -extern uint32 chan_req; -extern int32 stop_inst; -extern uint32 dma_ad[DMA_MAX]; - -uint32 dp_cw1 = 0; /* cmd word 1 */ -uint32 dp_cw2 = 0; /* cmd word 2 */ -uint32 dp_fnc = 0; /* saved function */ -uint32 dp_buf = 0; /* buffer */ -uint32 dp_otas = 0; /* state */ -uint32 dp_sta = 0; /* status */ -uint32 dp_defint = 0; /* deferred seek int */ -uint32 dp_ctype = TYPE_4651; /* controller type */ -uint32 dp_dma = 0; /* DMA/DMC */ -uint32 dp_eor = 0; /* end of range */ -uint32 dp_xip = 0; /* transfer in prog */ -uint32 dp_csum = 0; /* parity checksum */ -uint32 dp_rptr = 0; /* start of record */ -uint32 dp_wptr = 0; /* word ptr in record */ -uint32 dp_bctr = 0; /* format bit cntr */ -uint32 dp_gap = 0; /* format gap size */ -uint32 dp_stopioe = 1; /* stop on error */ -int32 dp_stime = 1000; /* seek per cylinder */ -int32 dp_xtime = 10; /* xfer per word */ -int32 dp_btime = 30; /* busy time */ -uint16 dpxb[DP_TRKLEN]; /* track buffer */ - -int32 dpio (int32 inst, int32 fnc, int32 dat, int32 dev); -t_stat dp_svc (UNIT *uptr); -t_stat dp_reset (DEVICE *dptr); -t_stat dp_attach (UNIT *uptr, char *cptr); -t_stat dp_settype (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat dp_go (uint32 dma); -t_stat dp_go1 (uint32 dat); -t_stat dp_go2 (uint32 dat); -t_stat dp_rdtrk (UNIT *uptr, uint16 *buf, uint32 cyl, uint32 hd); -t_stat dp_wrtrk (UNIT *uptr, uint16 *buf, uint32 cyl, uint32 hd); -t_bool dp_findrec (uint32 addr); -t_stat dp_wrwd (UNIT *uptr, uint32 dat); -t_stat dp_wrdone (UNIT *uptr, uint32 flg); -t_stat dp_done (uint32 req, uint32 f); -t_stat dp_setformat (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat dp_showformat (FILE *st, UNIT *uptr, int32 val, void *desc); - -/* DP data structures - - dp_dev DP device descriptor - dp_unit DP unit list - dp_reg DP register list - dp_mod DP modifier list -*/ - -DIB dp_dib = { DP, 1, DMC1, IOBUS, INT_V_DP, INT_V_NONE, &dpio, 0 }; - -UNIT dp_unit[] = { - { UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, CAP_4651) }, - { UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, CAP_4651) }, - { UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, CAP_4651) }, - { UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, CAP_4651) }, - { UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, CAP_4651) }, - { UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, CAP_4651) }, - { UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, CAP_4651) }, - { UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, CAP_4651) } - }; - -REG dp_reg[] = { - { ORDATA (STA, dp_sta, 16) }, - { ORDATA (BUF, dp_buf, 16) }, - { ORDATA (FNC, dp_fnc, 4) }, - { ORDATA (CW1, dp_cw1, 16) }, - { ORDATA (CW2, dp_cw2, 16) }, - { ORDATA (CSUM, dp_csum, 16) }, - { FLDATA (BUSY, dp_sta, 15) }, - { FLDATA (RDY, dp_sta, 14) }, - { FLDATA (EOR, dp_eor, 0) }, - { FLDATA (DEFINT, dp_defint, 0) }, - { FLDATA (INTREQ, dev_int, INT_V_DP) }, - { FLDATA (ENABLE, dev_enb, INT_V_DP) }, - { BRDATA (TBUF, dpxb, 8, 16, DP_TRKLEN) }, - { ORDATA (RPTR, dp_rptr, 11), REG_RO }, - { ORDATA (WPTR, dp_wptr, 11), REG_RO }, - { ORDATA (BCTR, dp_bctr, 15), REG_RO }, - { ORDATA (GAP, dp_gap, 16), REG_RO }, - { DRDATA (STIME, dp_stime, 24), REG_NZ + PV_LEFT }, - { DRDATA (XTIME, dp_xtime, 24), REG_NZ + PV_LEFT }, - { DRDATA (BTIME, dp_btime, 24), REG_NZ + PV_LEFT }, - { FLDATA (CTYPE, dp_ctype, 0), REG_HRO }, - { URDATA (UCYL, dp_unit[0].CYL, 10, 8, 0, - DP_NUMDRV, PV_LEFT | REG_HRO) }, - { URDATA (UFNC, dp_unit[0].FNC, 8, 7, 0, - DP_NUMDRV, REG_HRO) }, - { URDATA (CAPAC, dp_unit[0].capac, 10, T_ADDR_W, 0, - DP_NUMDRV, PV_LEFT | REG_HRO) }, - { ORDATA (OTAS, dp_otas, 2), REG_HRO }, - { ORDATA (XIP, dp_xip, 6), REG_HRO }, - { ORDATA (CHAN, dp_dib.chan, 5), REG_HRO }, - { FLDATA (STOP_IOE, dp_stopioe, 0) }, - { NULL } - }; - -MTAB dp_mod[] = { - { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, - { MTAB_XTD | MTAB_VDV, TYPE_4623, NULL, "4623", - &dp_settype, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, TYPE_4651, NULL, "4651", - &dp_settype, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, TYPE_4720, NULL, "4720", - &dp_settype, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, - NULL, &dp_showtype, NULL }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DMC", - &io_set_dmc, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DMA", - &io_set_dma, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "CHANNEL", NULL, - NULL, &io_show_chan, NULL }, - { MTAB_XTD|MTAB_VUN|MTAB_NMO, 0, "FORMAT", "FORMAT", - &dp_setformat, &dp_showformat, NULL }, - { 0 } - }; - -DEVICE dp_dev = { - "DP", dp_unit, dp_reg, dp_mod, - DP_NUMDRV, 8, 24, 1, 8, 16, - NULL, NULL, &dp_reset, - NULL, &dp_attach, NULL, - &dp_dib, DEV_DISABLE - }; - -/* IOT routines */ - -int32 dpio (int32 inst, int32 fnc, int32 dat, int32 dev) -{ -int32 ch = dp_dib.chan - 1; /* DMA/DMC chan */ -int32 u; -UNIT *uptr; - -switch (inst) { /* case on opcode */ - - case ioOCP: /* OCP */ - switch (fnc) { /* case on function */ - - case FNC_SK0: case FNC_SEEK: case FNC_RCA: /* data transfer */ - case FNC_UNL: case FNC_FMT: case FNC_RW: - dp_go (fnc); /* if !busy, start */ - break; - - case FNC_STOP: /* stop transfer */ - if (dp_xip) { /* transfer in prog? */ - uptr = dp_dev.units + (dp_xip & XIP_UMSK); /* get unit */ - sim_cancel (uptr); /* stop operation */ - if (dp_xip & (XIP_WRT|XIP_FMT)) /* write or format? */ - dp_wrdone (uptr, /* write track */ - ((dp_xip & XIP_FMT) && /* check fmt state */ - (uptr->FNC != (FNC_FMT|FNC_2ND)))? - STA_DTRER: 0); - else dp_done (1, dp_csum? STA_CSMER: 0);/* no, just clr busy */ - dp_xip = 0; /* clear flag */ - } - dp_otas = OTA_NOP; /* clear state */ - dp_sta = dp_sta & ~STA_BUSY; /* clear busy */ - break; - - case FNC_RDS: /* read status */ - if (dp_sta & STA_BUSY) /* ignore if busy */ - return dat; - dp_sta = (dp_sta | STA_RDY) & ~(STA_MBZ | STA_ANYER); - if (dp_sta & STA_ALLERR) dp_sta = dp_sta | STA_ANYER; - dp_buf = dp_sta; - if (dp_dma && Q_DMA (ch)) /* DMA? set chan req */ - SET_CH_REQ (ch); - break; - - case FNC_DMA: /* set DMA/DMC */ - dp_dma = 1; - break; - - case FNC_IOBUS: /* set IO bus */ - dp_dma = 0; - break; - - case FNC_AKI: /* ack intr */ - CLR_INT (INT_DP); - break; - - default: /* undefined */ - return IOBADFNC (dat); - } - break; - - case ioINA: /* INA */ - if (fnc) /* fnc 0 only */ - return IOBADFNC (dat); - if (dp_sta & STA_RDY) { /* ready? */ - dp_sta = dp_sta & ~STA_RDY; /* clear ready */ - return IOSKIP (dat | dp_buf); /* ret buf, skip */ - } - break; - - case ioOTA: /* OTA */ - if (fnc) /* fnc 0 only */ - return IOBADFNC (dat); - if (dp_sta & STA_RDY) { /* ready? */ - dp_sta = dp_sta & ~STA_RDY; /* clear ready */ - dp_buf = dat; /* store buf */ - if (dp_otas == OTA_CW1) /* expecting CW1? */ - dp_go1 (dat); - else if (dp_otas == OTA_CW2) /* expecting CW2? */ - dp_go2 (dat); - return IOSKIP (dat); - } - break; - - case ioSKS: /* SKS */ - u = 7; /* assume unit 7 */ - switch (fnc) { - - case 000: /* ready */ - if (dp_sta & STA_RDY) - return IOSKIP (dat); - break; - - case 001: /* !interrupting */ - if (!TST_INTREQ (INT_DP)) - return IOSKIP (dat); - break; - - case 002: /* operational */ - if (!(dp_sta & (STA_BUSY | STA_ALLERR))) - return IOSKIP (dat); - break; - - case 003: /* !error */ - if (!(dp_sta & STA_ALLERR)) - return IOSKIP (dat); - break; - - case 004: /* !busy */ - if (!(dp_sta & STA_BUSY)) - return IOSKIP (dat); - break; - - case 011: case 012: case 013: /* !not seeking 0-6 */ - case 014: case 015: case 016: case 017: - u = fnc - 011; /* set u, fall through */ - case 007: /* !not seeking 7 */ - if (!sim_is_active (&dp_unit[u]) || /* quiescent? */ - (dp_unit[u].FNC != (FNC_SEEK | FNC_2ND))) - return IOSKIP (dat); /* seeking sets late */ - break; - } - break; - - case ioEND: /* end of range */ - dp_eor = 1; /* transfer done */ - break; - } - -return dat; -} - -/* Start new operation - recal, seek, read address, format, read/write */ - -t_stat dp_go (uint32 fnc) -{ -int32 ch = dp_dib.chan - 1; /* DMA/DMC chan */ - -if (dp_sta & STA_BUSY) /* ignore if busy */ - return SCPE_OK; -dp_fnc = fnc; /* save function */ -dp_xip = 0; /* transfer not started */ -dp_eor = 0; /* not end of range */ -dp_csum = 0; /* init checksum */ -dp_otas = OTA_CW1; /* expect CW1 */ -dp_sta = (dp_sta | STA_BUSY | STA_RDY) & ~(STA_ALLERR | STA_EOR); -if (dp_dma && Q_DMA (ch)) { /* DMA and DMA channel? */ - SET_CH_REQ (ch); /* set channel request */ - dma_ad[ch] = dma_ad[ch] & ~DMA_IN; /* force output */ - } -return SCPE_OK; -} - -/* Process command word 1 - recal, seek, read address, format, read/write */ - -t_stat dp_go1 (uint32 dat) -{ -int32 ch = dp_dib.chan - 1; /* DMA/DMC chan */ -uint32 u = CW1_GETUNIT (dat); -UNIT *uptr = dp_dev.units + u; - -dp_cw1 = dat; /* store CW1 */ -dp_otas = OTA_NOP; /* assume no CW2 */ -uptr->FNC = dp_fnc; -if (sim_is_active (uptr)) /* still seeking? */ - return dp_done (1, STA_UNSER); /* unsafe */ -if (!(uptr->flags & UNIT_ATT)) /* not attached? */ - return dp_done (1, STA_OFLER); /* offline */ - -switch (dp_fnc) { /* case on function */ - - case FNC_SEEK: /* seek */ - case FNC_SK0: /* recalibrate */ - case FNC_UNL: /* unload */ - sim_activate (uptr, dp_btime); /* quick timeout */ - break; - - case FNC_FMT: /* format */ - if (uptr->flags & UNIT_WPRT) /* write protect? */ - return dp_done (1, STA_WPRER); /* stop now */ - case FNC_RCA: /* read current addr */ - dp_xip = u | XIP_SCHED; /* operation started */ - sim_activate (uptr, dp_xtime * 10); /* rotation timeout */ - break; - - case FNC_RW: /* read/write */ - dp_otas = OTA_CW2; /* expect CW2 */ - dp_sta = dp_sta | STA_RDY; /* set ready */ - if (dp_dma && Q_DMA (ch)) /* DMA? set chan request */ - SET_CH_REQ (ch); - break; - } - -return SCPE_OK; -} - -/* Process command word 2 - read/write only */ - -t_stat dp_go2 (uint32 dat) -{ -uint32 u = CW1_GETUNIT (dp_cw1); -UNIT *uptr = dp_dev.units + u; - -dp_cw2 = dat; /* store CW2 */ -dp_otas = OTA_NOP; /* normal state */ -sim_activate (uptr, dp_xtime * 10); /* rotation timeout */ -dp_xip = u | XIP_SCHED; /* operation started */ -return SCPE_OK; -} - -/* Unit service */ - -t_stat dp_svc (UNIT *uptr) -{ -int32 dcyl = 0; /* assume recalibrate */ -int32 ch = dp_dib.chan - 1; /* DMA/DMC chan */ -uint32 h = CW1_GETHEAD (dp_cw1); /* head */ -int32 st; -uint32 i, offs, lnt, ming, tpos; -t_stat r; - -if (!(uptr->flags & UNIT_ATT)) { /* not attached? */ - dp_done (1, STA_OFLER); /* offline */ - return IORETURN (dp_stopioe, SCPE_UNATT); - } - -switch (uptr->FNC) { /* case on function */ - - case FNC_SEEK: /* seek, need cyl */ - offs = CW1_GETOFFS (dp_cw1); /* get offset */ - if (dp_cw1 & CW1_DIR) /* get desired cyl */ - dcyl = uptr->CYL - offs; - else dcyl = uptr->CYL + offs; - if ((offs == 0) || - (dcyl < 0) || - (dcyl >= (int32) dp_tab[dp_ctype].cyl)) - return dp_done (1, STA_SEKER); /* bad seek? */ - - case FNC_SK0: /* recalibrate */ - dp_sta = dp_sta & ~STA_BUSY; /* clear busy */ - uptr->FNC = FNC_SEEK | FNC_2ND; /* next state */ - st = (abs (dcyl - uptr->CYL)) * dp_stime; /* schedule seek */ - if (st == 0) - st = dp_stime; - uptr->CYL = dcyl; /* put on cylinder */ - sim_activate (uptr, st); - return SCPE_OK; - - case FNC_SEEK | FNC_2ND: /* seek, 2nd state */ - if (dp_sta & STA_BUSY) /* busy? queue intr */ - dp_defint = 1; - else SET_INT (INT_DP); /* no, req intr */ - return SCPE_OK; - - case FNC_UNL: /* unload */ - detach_unit (uptr); /* detach unit */ - return dp_done (0, 0); /* clear busy, no intr */ - - case FNC_RCA: /* read current addr */ - if (h >= dp_tab[dp_ctype].surf) /* invalid head? */ - return dp_done (1, STA_ADRER); /* error */ - if ((r = dp_rdtrk (uptr, dpxb, uptr->CYL, h))) /* get track; error? */ - return r; - dp_rptr = 0; /* init rec ptr */ - if (dpxb[dp_rptr + REC_LNT] == 0) /* unformated? */ - return dp_done (1, STA_ADRER); /* error */ - tpos = (uint32) (fmod (sim_gtime () / (double) dp_xtime, DP_TRKLEN)); - do { /* scan down track */ - dp_buf = dpxb[dp_rptr + REC_ADDR]; /* get rec addr */ - dp_rptr = dp_rptr + dpxb[dp_rptr + REC_LNT] + REC_OVHD; - } while ((dp_rptr < tpos) && (dpxb[dp_rptr + REC_LNT] != 0)); - if (dp_dma) { /* DMA/DMC? */ - if (Q_DMA (ch)) /* DMA? */ - dma_ad[ch] = dma_ad[ch] | DMA_IN; /* force input */ - SET_CH_REQ (ch); /* request chan */ - } - return dp_done (1, STA_RDY); /* clr busy, set rdy */ - -/* Formating takes place in five states: - - init - clear track buffer, start at first record - address - store address word - data - store data word(s) until end of range - pause - wait for gap word or stop command - gap - validate gap word, advance to next record - - Note that formating is stopped externally by an OCP command; the - track buffer is flushed at that point. If the stop does not occur - in the proper state (gap word received), a format error occurs. -*/ - - case FNC_FMT: /* format */ - for (i = 0; i < DP_TRKLEN; i++) /* clear track */ - dpxb[i] = 0; - dp_xip = dp_xip | XIP_FMT; /* format in progress */ - dp_rptr = 0; /* init record ptr */ - dp_gap = 0; /* no gap before first */ - dp_bctr = (uint32) (16.0 * dp_tab[dp_ctype].wrds); /* init bit cntr */ - uptr->FNC = uptr->FNC | FNC_2ND; /* address state */ - break; /* set up next word */ - - case FNC_FMT | FNC_2ND: /* format, address word */ - dp_wptr = 0; /* clear word ptr */ - if (dp_bctr < (dp_gap + REC_OVHD_BITS + 16)) /* room for gap, record? */ - return dp_wrdone (uptr, STA_FMTER); /* no, format error */ - dp_bctr = dp_bctr - dp_gap - REC_OVHD_BITS; /* charge for gap, ovhd */ - dpxb[dp_rptr + REC_ADDR] = dp_buf; /* store address */ - uptr->FNC = FNC_FMT | FNC_3RD; /* data state */ - if (dp_eor) { /* record done? */ - dp_eor = 0; /* clear for restart */ - if (dp_dma) /* DMA/DMC? intr */ - SET_INT (INT_DP); - } - break; /* set up next word */ - - case FNC_FMT | FNC_3RD: /* format, data word */ - if (dp_sta & STA_RDY) /* timing failure? */ - return dp_wrdone (uptr, STA_DTRER); /* write trk, err */ - else { /* no, have word */ - if (dp_bctr < 16) /* room for it? */ - return dp_wrdone (uptr, STA_FMTER); /* no, error */ - dp_bctr = dp_bctr - 16; /* charge for word */ - dp_csum = dp_csum ^ dp_buf; /* update checksum */ - dpxb[dp_rptr + REC_DATA + dp_wptr] = dp_buf;/* store word */ - dpxb[dp_rptr + REC_LNT]++; /* incr rec lnt */ - dp_wptr++; /* incr word ptr */ - } - if (dp_eor) { /* record done? */ - dp_eor = 0; /* clear for restart */ - if (dp_dma) /* DMA/DMC? intr */ - SET_INT (INT_DP); - dpxb[dp_rptr + REC_DATA + dp_wptr] = dp_csum; /* store checksum */ - uptr->FNC = uptr->FNC | FNC_4TH; /* pause state */ - sim_activate (uptr, 5 * dp_xtime); /* schedule pause */ - return SCPE_OK; /* don't request word */ - } - break; /* set up next word */ - - case FNC_FMT | FNC_4TH: /* format, pause */ - uptr->FNC = FNC_FMT | FNC_5TH; /* gap state */ - break; /* request word */ - - case FNC_FMT | FNC_5TH: /* format, gap word */ - ming = ((16 * dp_wptr) + REC_OVHD_BITS) / 20; /* min 5% gap */ - if (dp_buf < ming) /* too small? */ - return dp_wrdone (uptr, STA_FMTER); /* yes, format error */ - dp_rptr = dp_rptr + dp_wptr + REC_OVHD; /* next record */ - uptr->FNC = FNC_FMT | FNC_2ND; /* address state */ - if (dp_eor) { /* record done? */ - dp_eor = 0; /* clear for restart */ - if (dp_dma) SET_INT (INT_DP); /* DMA/DMC? intr */ - } - dp_gap = dp_buf; /* save gap */ - dp_csum = 0; /* clear checksum */ - break; /* set up next word */ - -/* Read and write take place in two states: - - init - read track into buffer, find record, validate parameters - data - (read) fetch data from buffer, stop on end of range - - (write) write data into buffer, flush on end of range -*/ - - case FNC_RW: /* read/write */ - if (h >= dp_tab[dp_ctype].surf) /* invalid head? */ - return dp_done (1, STA_ADRER); /* error */ - if ((r = dp_rdtrk (uptr, dpxb, uptr->CYL, h))) /* get track; error? */ - return r; - if (!dp_findrec (dp_cw2)) /* find rec; error? */ - return dp_done (1, STA_ADRER); /* address error */ - if ((dpxb[dp_rptr + REC_LNT] >= (DP_TRKLEN - dp_rptr - REC_OVHD)) || - (dpxb[dp_rptr + REC_EXT] >= REC_MAXEXT)) { /* bad lnt or ext? */ - dp_done (1, STA_UNSER); /* stop simulation */ - return STOP_DPFMT; /* bad format */ - } - uptr->FNC = uptr->FNC | FNC_2ND; /* next state */ - if (dp_cw1 & CW1_RW) { /* write? */ - if (uptr->flags & UNIT_WPRT) /* write protect? */ - return dp_done (1, STA_WPRER); /* error */ - dp_xip = dp_xip | XIP_WRT; /* write in progress */ - dp_sta = dp_sta | STA_RDY; /* set ready */ - if (dp_dma) /* if DMA/DMC, req chan */ - SET_CH_REQ (ch); - } - else if (Q_DMA (ch)) /* read; DMA? */ - dma_ad[ch] = dma_ad[ch] | DMA_IN; /* force input */ - sim_activate (uptr, dp_xtime); /* schedule word */ - dp_wptr = 0; /* init word pointer */ - return SCPE_OK; - - case FNC_RW | FNC_2ND: /* read/write, word */ - if (dp_cw1 & CW1_RW) { /* write? */ - if (dp_sta & STA_RDY) /* timing failure? */ - return dp_wrdone (uptr, STA_DTRER); /* yes, error */ - if ((r = dp_wrwd (uptr, dp_buf))) /* wr word, error? */ - return r; - if (dp_eor) { /* transfer done? */ - dpxb[dp_rptr + REC_DATA + dp_wptr] = dp_csum; - return dp_wrdone (uptr, 0); /* clear busy, intr req */ - } - } - else { /* read? */ - lnt = dpxb[dp_rptr + REC_LNT] + dpxb[dp_rptr + REC_EXT]; - dp_buf = dpxb[dp_rptr + REC_DATA + dp_wptr];/* current word */ - dp_csum = dp_csum ^ dp_buf; /* xor to csum */ - if ((dp_wptr > lnt) || dp_eor) /* transfer done? */ - return dp_done (1, - (dp_csum? STA_CSMER: 0) | ((dp_wptr >= lnt)? STA_EOR: 0)); - if (dp_sta & STA_RDY) /* data buf full? */ - return dp_done (1, STA_DTRER); /* no, underrun */ - dp_wptr++; /* next word */ - } - break; - - default: - return SCPE_IERR; - } /* end case */ - -dp_sta = dp_sta | STA_RDY; /* set ready */ -if (dp_dma) /* if DMA/DMC, req chan */ - SET_CH_REQ (ch); -sim_activate (uptr, dp_xtime); /* schedule word */ -return SCPE_OK; -} - -/* Read track */ - -t_stat dp_rdtrk (UNIT *uptr, uint16 *buf, uint32 c, uint32 h) -{ -uint32 da = ((c * dp_tab[dp_ctype].surf) + h) * DP_TRKLEN; -int32 l; - -fseek (uptr->fileref, da * sizeof (uint16), SEEK_SET); -l = fxread (buf, sizeof (uint16), DP_TRKLEN, uptr->fileref); -for ( ; l < DP_TRKLEN; l++) - buf[l] = 0; -if (ferror (uptr->fileref)) { - perror ("DP I/O error"); - clearerr (uptr->fileref); - dp_done (1, STA_UNSER); - return SCPE_IOERR; - } -return SCPE_OK; -} - -/* Write track */ - -t_stat dp_wrtrk (UNIT *uptr, uint16 *buf, uint32 c, uint32 h) -{ -uint32 da = ((c * dp_tab[dp_ctype].surf) + h) * DP_TRKLEN; - -fseek (uptr->fileref, da * sizeof (uint16), SEEK_SET); -fxwrite (buf, sizeof (uint16), DP_TRKLEN, uptr->fileref); -if (ferror (uptr->fileref)) { - perror ("DP I/O error"); - clearerr (uptr->fileref); - dp_done (1, STA_UNSER); - return SCPE_IOERR; - } -return SCPE_OK; -} - -/* Find record; true if found, false if not found */ - -t_bool dp_findrec (uint32 addr) -{ -dp_rptr = 0; - -do { - if (dpxb[dp_rptr + REC_LNT] == 0) - return FALSE; - if (dpxb[dp_rptr + REC_LNT] >= DP_TRKLEN) - return TRUE; - if (dpxb[dp_rptr + REC_ADDR] == addr) - return TRUE; - dp_rptr = dp_rptr + dpxb[dp_rptr + REC_LNT] + REC_OVHD; - } while (dp_rptr < DP_TRKLEN); -return FALSE; -} - -/* Write next word to track buffer; return TRUE if ok, FALSE if next record trashed */ - -t_stat dp_wrwd (UNIT *uptr, uint32 dat) -{ -uint32 lnt = dpxb[dp_rptr + REC_LNT]; -t_stat r; - -dp_csum = dp_csum ^ dat; -if (dp_wptr < lnt) { - dpxb[dp_rptr + REC_DATA + dp_wptr++] = dat; - return SCPE_OK; - } -if (dp_wptr < (lnt + REC_MAXEXT)) { - dpxb[dp_rptr + REC_EXT]++; - dpxb[dp_rptr + REC_DATA + dp_wptr++] = dat; - return SCPE_OK; - } -dpxb[dp_rptr + REC_DATA + dp_wptr] = dp_csum; /* write csum */ -dpxb[dp_rptr + lnt + REC_OVHD] = 0; /* zap rest of track */ -if ((r = dp_wrdone (uptr, STA_UNSER))) /* dump track */ - return r; -return STOP_DPOVR; -} - -/* Write done, dump track, clear busy */ - -t_stat dp_wrdone (UNIT *uptr, uint32 flg) -{ -dp_done (1, flg); -return dp_wrtrk (uptr, dpxb, uptr->CYL, CW1_GETHEAD (dp_cw1)); -} - -/* Clear busy, set errors, request interrupt if required */ - -t_stat dp_done (uint32 req, uint32 flg) -{ -dp_xip = 0; /* clear xfr in prog */ -dp_sta = (dp_sta | flg) & ~(STA_BUSY | STA_MBZ); /* clear busy */ -if (req || dp_defint) /* if req, set intr */ - SET_INT (INT_DP); -dp_defint = 0; /* clr def intr */ -return SCPE_OK; -} - -/* Reset routine */ - -t_stat dp_reset (DEVICE *dptr) -{ -int32 i; - -dp_fnc = 0; -dp_cw1 = 0; -dp_cw2 = 0; -dp_sta = 0; -dp_buf = 0; -dp_xip = 0; -dp_eor = 0; -dp_dma = 0; -dp_csum = 0; -dp_rptr = 0; -dp_wptr = 0; -dp_bctr = 0; -dp_gap = 0; -dp_defint = 0; -for (i = 0; i < DP_NUMDRV; i++) { /* loop thru drives */ - sim_cancel (&dp_unit[i]); /* cancel activity */ - dp_unit[i].FNC = 0; /* clear function */ - dp_unit[i].CYL = 0; - } -CLR_INT (INT_DP); /* clear int, enb */ -CLR_ENB (INT_DP); -return SCPE_OK; -} - -/* Attach routine, test formating */ - -t_stat dp_attach (UNIT *uptr, char *cptr) -{ -t_stat r; -r = attach_unit (uptr, cptr); -if (r != SCPE_OK) - return r; -return dp_showformat (stdout, uptr, 0, NULL); -} - -/* Set controller type */ - -t_stat dp_settype (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 i; - -if ((val < 0) || (val >= DP_NUMTYP) || (cptr != NULL)) - return SCPE_ARG; -for (i = 0; i < DP_NUMDRV; i++) { - if (dp_unit[i].flags & UNIT_ATT) return SCPE_ALATT; - } -for (i = 0; i < DP_NUMDRV; i++) - dp_unit[i].capac = dp_tab[val].cap; -dp_ctype = val; -return SCPE_OK; -} - -/* Show controller type */ - -t_stat dp_showtype (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -if (dp_ctype >= DP_NUMTYP) - return SCPE_IERR; -fprintf (st, "%s", dp_tab[dp_ctype].name); -return SCPE_OK; -} - -/* Set drive format - - There is no standard format for record addresses. This routine - provides two schemes: - - -S sequential addressing (starting from 0) - default geometric addressing (8b: cylinder, 5b: head, 3b: sector) - - This routine also supports formatting by record count or word count: - - -R argument is records per track - default argument is words per record - - The relationship between words per record (W), bits per track (B), - and records per track (R), is as follows: - - W = (B / (R + ((R - 1) / 20))) - 16.5 - - where (R - 1) / 20 is the "5% gap" and 16.5 is the overhead, in words, - per record. -*/ - -t_stat dp_setformat (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -uint32 h, c, cntr, rptr; -int32 i, nr, nw, inp; -uint16 tbuf[DP_TRKLEN]; -float finp; -t_stat r; - -if (uptr == NULL) - return SCPE_IERR; -if (cptr == NULL) - return SCPE_ARG; -if (!(uptr->flags & UNIT_ATT)) - return SCPE_UNATT; -inp = (int32) get_uint (cptr, 10, 2048, &r); -if (r != SCPE_OK) - return r; -if (inp == 0) - return SCPE_ARG; -finp = (float) inp; -if (sim_switches & SWMASK ('R')) { /* format records? */ - nr = inp; - nw = (int32) ((dp_tab[dp_ctype].wrds / (finp + ((finp - 1.0) / 20.0))) - REC_OVHD_WRDS); - if (nw <= 0) - return SCPE_ARG; - } -else { - nw = inp; /* format words */ - nr = (int32) ((((20.0 * dp_tab[dp_ctype].wrds) / (finp + REC_OVHD_WRDS)) + 1.0) / 21.0); - if (nr <= 0) - return SCPE_ARG; - } -sim_printf ("Proposed format: records/track = %d, record size = %d\n", nr, nw); -if (!get_yn ("Formatting will destroy all data on this disk; proceed? [N]", FALSE)) - return SCPE_OK; -for (c = cntr = 0; c < dp_tab[dp_ctype].cyl; c++) { - for (h = 0; h < dp_tab[dp_ctype].surf; h++) { - for (i = 0; i < DP_TRKLEN; i++) - tbuf[i] = 0; - rptr = 0; - for (i = 0; i < nr; i++) { - tbuf[rptr + REC_LNT] = nw & DMASK; - if (sim_switches & SWMASK ('S')) - tbuf[rptr + REC_ADDR] = cntr++; - else tbuf[rptr + REC_ADDR] = (c << 8) + (h << 3) + i; - rptr = rptr + nw + REC_OVHD; - } - if ((r = dp_wrtrk (uptr, tbuf, c, h))) - return r; - } - } -sim_printf ("Formatting complete\n"); -return SCPE_OK; -} - -/* Show format */ - -t_stat dp_showformat (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -uint32 c, h, rptr, rlnt, sec; -uint32 minrec = DP_TRKLEN; -uint32 maxrec = 0; -uint32 minsec = DP_TRKLEN; -uint32 maxsec = 0; -uint16 tbuf[DP_TRKLEN]; -t_stat r; - -if (uptr == NULL) - return SCPE_IERR; -if ((uptr->flags & UNIT_ATT) == 0) - return SCPE_UNATT; -for (c = 0; c < dp_tab[dp_ctype].cyl; c++) { - for (h = 0; h < dp_tab[dp_ctype].surf; h++) { - if ((r = dp_rdtrk (uptr, tbuf, c, h))) - return r; - rptr = 0; - rlnt = tbuf[rptr + REC_LNT]; - if (rlnt == 0) { - if (c || h) - fprintf (st, "Unformatted track, cyl = %d, head = %d\n", c, h); - else fprintf (st, "Disk is unformatted\n"); - return SCPE_OK; - } - for (sec = 0; rlnt != 0; sec++) { - if ((rptr + rlnt + REC_OVHD) >= DP_TRKLEN) { - fprintf (st, "Invalid record length %d, cyl = %d, head = %d, sect = %d\n", - rlnt, c, h, sec); - return SCPE_OK; - } - if (tbuf[rptr + REC_EXT] >= REC_MAXEXT) { - fprintf (st, "Invalid record extension %d, cyl = %d, head = %d, sect = %d\n", - tbuf[rptr + REC_EXT], c, h, sec); - return SCPE_OK; - } - if (rlnt > maxrec) - maxrec = rlnt; - if (rlnt < minrec) - minrec = rlnt; - rptr = rptr + rlnt + REC_OVHD; - rlnt = tbuf[rptr + REC_LNT]; - } - if (sec > maxsec) - maxsec = sec; - if (sec < minsec) - minsec = sec; - } - } -if ((minrec == maxrec) && (minsec == maxsec)) - fprintf (st, "Valid fixed format, records/track = %d, record size = %d\n", - minsec, minrec); -else if (minrec == maxrec) - fprintf (st, "Valid variable format, records/track = %d-%d, record size = %d\n", - minsec, maxsec, minrec); -else if (minsec == maxsec) - fprintf (st, "Valid variable format, records/track = %d, record sizes = %d-%d\n", - minsec, minrec, maxrec); -else fprintf (st, "Valid variable format, records/track = %d-%d, record sizes = %d-%d\n", - minsec, maxsec, minrec, maxrec); -return SCPE_OK; -} diff --git a/H316/h316_fhd.c b/H316/h316_fhd.c deleted file mode 100644 index e711adab..00000000 --- a/H316/h316_fhd.c +++ /dev/null @@ -1,485 +0,0 @@ -/* h316_fhd.c: H316/516 fixed head simulator - - Copyright (c) 2003-2015, 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. - - fhd 516-4400 fixed head disk - - 03-Sep-13 RMS Added explicit void * cast - 03-Jul-13 RLA compatibility changes for extended interrupts - 19-Mar-12 RMS Fixed declaration of chan_req (Mark Pizzolato) - 15-May-06 RMS Fixed bug in autosize attach (David Gesswein) - 04-Jan-04 RMS Changed sim_fsize calling sequence - - These head-per-track devices are buffered in memory, to minimize overhead. -*/ - -#include "h316_defs.h" -#include - -/* Constants */ - -#define FH_NUMWD 1536 /* words/track */ -#define FH_NUMTK 64 /* tracks/surface */ -#define FH_WDPSF (FH_NUMWD * FH_NUMTK) /* words/surface */ -#define FH_NUMSF 16 /* surfaces/ctlr */ -#define UNIT_V_AUTO (UNIT_V_UF + 0) /* autosize */ -#define UNIT_V_SF (UNIT_V_UF + 1) /* #surfaces - 1 */ -#define UNIT_M_SF 017 -#define UNIT_AUTO (1 << UNIT_V_AUTO) -#define UNIT_SF (UNIT_M_SF << UNIT_V_SF) -#define UNIT_GETSF(x) ((((x) >> UNIT_V_SF) & UNIT_M_SF) + 1) - -/* Command word 1 */ - -#define CW1_RW 0100000 /* read vs write */ -#define CW1_V_SF 10 /* surface */ -#define CW1_M_SF 017 -#define CW1_GETSF(x) (((x) >> CW1_V_SF) & CW1_M_SF) -#define CW1_V_TK 4 /* track */ -#define CW1_M_TK 077 -#define CW1_GETTK(x) (((x) >> CW1_V_TK) & CW1_M_TK) - -/* Command word 2 */ - -#define CW2_V_CA 0 /* character addr */ -#define CW2_M_CA 07777 -#define CW2_GETCA(x) (((x) >> CW2_V_CA) & CW2_M_CA) - -#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \ - ((double) FH_NUMWD))) - -/* OTA states */ - -#define OTA_NOP 0 /* normal */ -#define OTA_CW1 1 /* expecting CW1 */ -#define OTA_CW2 2 /* expecting CW2 */ - -extern int32 dev_int, dev_enb; -extern uint32 chan_req; -extern int32 stop_inst; -extern uint32 dma_ad[DMA_MAX]; - -uint32 fhd_cw1 = 0; /* cmd word 1 */ -uint32 fhd_cw2 = 0; /* cmd word 2 */ -uint32 fhd_buf = 0; /* buffer */ -uint32 fhd_otas = 0; /* state */ -uint32 fhd_busy = 0; /* busy */ -uint32 fhd_rdy = 0; /* word ready */ -uint32 fhd_dte = 0; /* data err */ -uint32 fhd_ace = 0; /* access error */ -uint32 fhd_dma = 0; /* DMA/DMC */ -uint32 fhd_eor = 0; /* end of range */ -uint32 fhd_csum = 0; /* parity checksum */ -uint32 fhd_stopioe = 1; /* stop on error */ -int32 fhd_time = 10; /* time per word */ - -int32 fhdio (int32 inst, int32 fnc, int32 dat, int32 dev); -t_stat fhd_svc (UNIT *uptr); -t_stat fhd_reset (DEVICE *dptr); -t_stat fhd_attach (UNIT *uptr, char *cptr); -t_stat fhd_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -void fhd_go (uint32 dma); -void fhd_go1 (uint32 dat); -void fhd_go2 (uint32 dat); -t_bool fhd_getc (UNIT *uptr, uint32 *ch); -t_bool fhd_putc (UNIT *uptr, uint32 ch); -t_bool fhd_bad_wa (uint32 wa); -uint32 fhd_csword (uint32 cs, uint32 ch); - -/* FHD data structures - - fhd_dev device descriptor - fhd_unit unit descriptor - fhd_mod unit modifiers - fhd_reg register list -*/ - -DIB fhd_dib = { FHD, 1, IOBUS, IOBUS, INT_V_FHD, INT_V_NONE, &fhdio, 0 }; - -UNIT fhd_unit = { - UDATA (&fhd_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, - FH_WDPSF) - }; - -REG fhd_reg[] = { - { ORDATA (CW1, fhd_cw1, 16) }, - { ORDATA (CW2, fhd_cw2, 16) }, - { ORDATA (BUF, fhd_buf, 16) }, - { FLDATA (BUSY, fhd_busy, 0) }, - { FLDATA (RDY, fhd_rdy, 0) }, - { FLDATA (DTE, fhd_dte, 0) }, - { FLDATA (ACE, fhd_ace, 0) }, - { FLDATA (EOR, fhd_eor, 0) }, - { FLDATA (DMA, fhd_dma, 0) }, - { FLDATA (CSUM, fhd_csum, 7) }, - { FLDATA (INTREQ, dev_int, INT_V_MT) }, - { FLDATA (ENABLE, dev_enb, INT_V_MT) }, - { DRDATA (TIME, fhd_time, 31), REG_NZ + PV_LEFT }, - { ORDATA (OTAS, fhd_otas, 2), REG_HRO }, - { ORDATA (CHAN, fhd_dib.chan, 5), REG_HRO }, - { FLDATA (STOP_IOE, fhd_stopioe, 0) }, - { NULL } - }; - -MTAB fhd_mod[] = { - { UNIT_SF, (0 << UNIT_V_SF), NULL, "1S", &fhd_set_size }, - { UNIT_SF, (1 << UNIT_V_SF), NULL, "2S", &fhd_set_size }, - { UNIT_SF, (2 << UNIT_V_SF), NULL, "3S", &fhd_set_size }, - { UNIT_SF, (3 << UNIT_V_SF), NULL, "4S", &fhd_set_size }, - { UNIT_SF, (4 << UNIT_V_SF), NULL, "5S", &fhd_set_size }, - { UNIT_SF, (5 << UNIT_V_SF), NULL, "6S", &fhd_set_size }, - { UNIT_SF, (6 << UNIT_V_SF), NULL, "7S", &fhd_set_size }, - { UNIT_SF, (7 << UNIT_V_SF), NULL, "8S", &fhd_set_size }, - { UNIT_SF, (8 << UNIT_V_SF), NULL, "9S", &fhd_set_size }, - { UNIT_SF, (9 << UNIT_V_SF), NULL, "10S", &fhd_set_size }, - { UNIT_SF, (10 << UNIT_V_SF), NULL, "11S", &fhd_set_size }, - { UNIT_SF, (11 << UNIT_V_SF), NULL, "12S", &fhd_set_size }, - { UNIT_SF, (12 << UNIT_V_SF), NULL, "13S", &fhd_set_size }, - { UNIT_SF, (13 << UNIT_V_SF), NULL, "14S", &fhd_set_size }, - { UNIT_SF, (14 << UNIT_V_SF), NULL, "15S", &fhd_set_size }, - { UNIT_SF, (15 << UNIT_V_SF), NULL, "16S", &fhd_set_size }, - { UNIT_AUTO, UNIT_AUTO, "autosize", "AUTOSIZE", NULL }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "IOBUS", - &io_set_iobus, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DMC", - &io_set_dmc, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DMA", - &io_set_dma, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "CHANNEL", NULL, - NULL, &io_show_chan, NULL }, - { 0 } - }; - -DEVICE fhd_dev = { - "FHD", &fhd_unit, fhd_reg, fhd_mod, - 1, 8, 22, 1, 8, 16, - NULL, NULL, &fhd_reset, - NULL, &fhd_attach, NULL, - &fhd_dib, DEV_DISABLE - }; - -/* IO routines */ - -int32 fhdio (int32 inst, int32 fnc, int32 dat, int32 dev) -{ -switch (inst) { /* case on opcode */ - - case ioOCP: /* control */ - if (fnc == 04) { /* terminate output? */ - fhd_eor = 1; /* stop */ - CLR_INT (INT_FHD); /* clear int req */ - } - else if (fnc == 003) /* start, DMA */ - fhd_go (1); - else if (fnc == 007) /* start, IO bus */ - fhd_go (0); - else return IOBADFNC (dat); - break; - - case ioOTA: /* output */ - if (fnc) /* only fnc 0 */ - return IOBADFNC (dat); - if (fhd_rdy) { /* ready? */ - fhd_buf = dat; /* store data */ - if (fhd_otas == OTA_CW1) /* expecting CW1? */ - fhd_go1 (dat); - else if (fhd_otas == OTA_CW2) /* expecting CW2? */ - fhd_go2 (dat); - else fhd_rdy = 0; /* normal, clr ready */ - return IOSKIP (dat); - } - break; - - case ioINA: /* input */ - if (fnc) /* only fnc 0 */ - return IOBADFNC (dat); - if (fhd_rdy) { /* ready? */ - fhd_rdy = 0; /* clear ready */ - return IOSKIP (dat | fhd_buf); /* return data */ - } - break; - - case ioSKS: /* sense */ - if (((fnc == 000) && fhd_rdy) || /* 0 = skip if ready */ - ((fnc == 001) && !fhd_busy) || /* 1 = skip if !busy */ - ((fnc == 002) && !fhd_dte) || /* 2 = skip if !data err */ - ((fnc == 003) && !fhd_ace) || /* 3 = skip if !access err */ - ((fnc == 004) && !TST_INTREQ (INT_FHD))) /* 4 = skip if !interrupt */ - return IOSKIP (dat); - break; - - case ioEND: - fhd_eor = 1; - break; - } - -return dat; -} - -/* Start new operation */ - -void fhd_go (uint32 dma) -{ -int32 ch = fhd_dib.chan - 1; /* DMA/DMC chan */ - -if (fhd_busy) /* ignore if busy */ - return; -fhd_busy = 1; /* ctlr is busy */ -fhd_eor = 0; /* transfer not done */ -fhd_csum = 0; /* init checksum */ -fhd_dte = 0; /* clear errors */ -fhd_ace = 0; -if (ch >= 0) /* DMA allowed? */ - fhd_dma = dma; -else fhd_dma = 0; /* no, force IO bus */ -fhd_otas = OTA_CW1; /* expect CW1 */ -fhd_rdy = 1; /* set ready */ -if (fhd_dma && Q_DMA (ch)) { /* DMA and DMA channel? */ - SET_CH_REQ (ch); /* set channel request */ - dma_ad[ch] = dma_ad[ch] & ~DMA_IN; /* force output */ - } -return; -} - -/* Process command word 1 */ - -void fhd_go1 (uint32 dat) -{ -int32 ch = fhd_dib.chan - 1; /* DMA/DMC chan */ - -fhd_cw1 = dat; /* store CW1 */ -fhd_otas = OTA_CW2; /* expect CW2 */ -fhd_rdy = 1; /* set ready */ -if (fhd_dma && Q_DMA (ch)) /* DMA? set chan request */ - SET_CH_REQ (ch); -return; -} - -/* Process command word 2 - initiate seek */ - -void fhd_go2 (uint32 dat) -{ -int32 ch = fhd_dib.chan - 1; /* DMA/DMC chan */ -uint32 sf = CW1_GETSF (fhd_cw1); /* surface */ -int32 t, wa; - -fhd_cw2 = dat; /* store CW2 */ -fhd_otas = OTA_NOP; /* next state */ -wa = CW2_GETCA (fhd_cw2) >> 1; /* word addr */ -if ((wa >= FH_NUMWD) || /* if bad char addr */ - ((fhd_unit.flags & UNIT_ATT) == 0) || /* or unattached */ - (sf >= UNIT_GETSF (fhd_unit.flags))) { /* or bad surface */ - fhd_ace = 1; /* access error */ - fhd_busy = 0; /* abort operation */ - SET_INT (INT_FHD); - return; - } -if (fhd_cw1 & CW1_RW) { /* write? */ - fhd_rdy = 1; /* set ready */ - if (fhd_dma) /* if DMA/DMC, req chan */ - SET_CH_REQ (ch); - } -else { - fhd_rdy = 0; /* read, clear ready */ - if (fhd_dma && (ch < DMC_V_DMC1)) /* read and DMA chan? */ - dma_ad[ch] = dma_ad[ch] | DMA_IN; /* force input */ - } -t = wa - GET_POS (fhd_time); /* delta to new loc */ -if (t < 0) /* wrap around? */ - t = t + FH_NUMWD; -sim_activate (&fhd_unit, t * fhd_time); /* schedule op */ -return; -} - -/* Unit service */ - -t_stat fhd_svc (UNIT *uptr) -{ -int32 ch = fhd_dib.chan - 1; /* DMA/DMC chan (-1 if IO bus) */ -uint32 c1, c2; - -if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ - fhd_ace = 1; /* access error */ - fhd_busy = 0; /* abort operation */ - SET_INT (INT_FHD); - return IORETURN (fhd_stopioe, SCPE_UNATT); - } - -if (fhd_eor || fhd_rdy) { /* done or ready set? */ - if (fhd_rdy) /* if ready set, data err */ - fhd_dte = 1; - if (fhd_cw1 & CW1_RW) { /* write? */ - if (!fhd_rdy) { /* buffer full? */ - fhd_putc (uptr, fhd_buf >> 8); /* store last word */ - fhd_putc (uptr, fhd_buf); - } - fhd_putc (uptr, fhd_csum); /* store csum */ - } - else { /* read */ - fhd_getc (uptr, &c1); /* get csum */ - if (fhd_csum) /* if csum != 0, err */ - fhd_dte = 1; - } - fhd_busy = 0; /* operation complete */ - SET_INT (INT_FHD); - return SCPE_OK; - } - -if (fhd_cw1 & CW1_RW) { /* write? */ - if (fhd_putc (uptr, fhd_buf >> 8)) - return SCPE_OK; - if (fhd_putc (uptr, fhd_buf)) - return SCPE_OK; - } -else { /* read */ - if (fhd_getc (uptr, &c1)) - return SCPE_OK; - if (fhd_getc (uptr, &c2)) - return SCPE_OK; - fhd_buf = (c1 << 8) | c2; - } -sim_activate (uptr, fhd_time); /* next word */ -fhd_rdy = 1; /* set ready */ -if (fhd_dma) /* if DMA/DMC, req chan */ - SET_CH_REQ (ch); -return SCPE_OK; -} - -/* Read character from disk */ - -t_bool fhd_getc (UNIT *uptr, uint32 *ch) -{ -uint32 sf = CW1_GETSF (fhd_cw1); /* surface */ -uint32 tk = CW1_GETTK (fhd_cw1); /* track */ -uint32 ca = CW2_GETCA (fhd_cw2); /* char addr */ -uint32 wa = ca >> 1; /* word addr */ -uint32 ba = (((sf * FH_NUMTK) + tk) * FH_NUMWD) + wa; /* buffer offset */ -uint16 *fbuf = (uint16 *) uptr->filebuf; /* buffer base */ -uint32 wd; - -if (fhd_bad_wa (wa)) /* addr bad? */ - return TRUE; -fhd_cw2 = fhd_cw2 + 1; /* incr char addr */ -if (ca & 1) /* select char */ - wd = fbuf[ba] & 0377; -else wd = (fbuf[ba] >> 8) & 0377; -fhd_csum = fhd_csword (fhd_csum, wd); /* put in csum */ -*ch = wd; /* return */ -return FALSE; -} - -/* Write character to disk */ - -t_bool fhd_putc (UNIT *uptr, uint32 ch) -{ -uint32 sf = CW1_GETSF (fhd_cw1); /* surface */ -uint32 tk = CW1_GETTK (fhd_cw1); /* track */ -uint32 ca = CW2_GETCA (fhd_cw2); /* char addr */ -uint32 wa = ca >> 1; /* word addr */ -uint32 ba = (((sf * FH_NUMTK) + tk) * FH_NUMWD) + wa; /* buffer offset */ -uint16 *fbuf = uptr->filebuf; /* buffer base */ - -ch = ch & 0377; /* mask char */ -if (fhd_bad_wa (wa)) /* addr bad? */ - return TRUE; -fhd_cw2 = fhd_cw2 + 1; /* incr char addr */ -if (ca & 1) /* odd? low char */ - fbuf[ba] = (fbuf[ba] & ~0377) | ch; -else fbuf[ba] = (fbuf[ba] & 0377) | (ch << 8); /* even, hi char */ -fhd_csum = fhd_csword (fhd_csum, ch); /* put in csum */ -if (ba >= uptr->hwmark) /* update hwmark */ - uptr->hwmark = ba + 1; -return FALSE; -} - -/* Check word address */ - -t_bool fhd_bad_wa (uint32 wa) -{ -if (wa >= FH_NUMWD) { /* bad address? */ - fhd_ace = 1; /* access error */ - fhd_busy = 0; /* abort operation */ - SET_INT (INT_FHD); - return TRUE; - } -return FALSE; -} - -/* Add character to checksum (parity) */ - -uint32 fhd_csword (uint32 cs, uint32 ch) -{ -while (ch) { /* count bits */ - ch = ch & ~(ch & (-(int32) ch)); - cs = cs ^ 0200; /* invert cs for each 1 */ - } -return cs; -} - -/* Reset routine */ - -t_stat fhd_reset (DEVICE *dptr) -{ -fhd_busy = 0; /* reset state */ -fhd_rdy = 0; -fhd_ace = 0; -fhd_dte = 0; -fhd_eor = 0; -fhd_otas = OTA_NOP; -fhd_cw1 = fhd_cw2 = fhd_buf = 0; -CLR_INT (INT_FHD); /* clear int, enb */ -CLR_ENB (INT_FHD); -sim_cancel (&fhd_unit); /* cancel operation */ -return SCPE_OK; -} - -/* Attach routine */ - -t_stat fhd_attach (UNIT *uptr, char *cptr) -{ -uint32 sz, sf; -uint32 ds_bytes = FH_WDPSF * sizeof (int16); - -if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize_name (cptr))) { - sf = (sz + ds_bytes - 1) / ds_bytes; - if (sf >= FH_NUMSF) - sf = FH_NUMSF - 1; - uptr->flags = (uptr->flags & ~UNIT_SF) | - (sf << UNIT_V_SF); - } -uptr->capac = UNIT_GETSF (uptr->flags) * FH_WDPSF; -return attach_unit (uptr, cptr); -} - -/* Set size routine */ - -t_stat fhd_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (val < 0) - return SCPE_IERR; -if (uptr->flags & UNIT_ATT) - return SCPE_ALATT; -uptr->capac = UNIT_GETSF (val) * FH_WDPSF; -return SCPE_OK; -} diff --git a/H316/h316_hi.c b/H316/h316_hi.c deleted file mode 100644 index 6ef81e56..00000000 --- a/H316/h316_hi.c +++ /dev/null @@ -1,324 +0,0 @@ -/* h316_hi.c- BBN ARPAnet IMP Host Interface - Based on the SIMH simulator package written by Robert M Supnik. - - Copyright (c) 2013 Robert Armstrong, bob@jfcl.com. - - 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 ARMSTRONG 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 Armstrong 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 Armstrong. - - hi host interface - - 21-May-13 RLA New file - - The host interface is one of the BBN engineered devices unique to the - ARPAnet IMP. This is the famous "1822" card which connected each IMP to a - host computer - a DECSYSTEM-10, an SDS Sigma 7, an IBM 360/90, a CDC6600, - or any one of many other ARPAnet hosts. The idea is to simulate this - interface by using a TCP/UDP connection to another simh instance emulating - the host machine and running the ARPAnet host software. - - Presently the details of the host interface card are not well known, and - this implementation is simply a place holder. It's enough to allow the IMP - software to run, but not actually to communicate with a host. The IMP simply - believes that all the attached hosts are down at the moment. - - Host interface state is maintained in a set of position and state variables: - - Host state is maintained in the following variables - - - TBA TBA - - TODO - - IMPLEMENT THIS MODULE!!! -*/ -#ifdef VM_IMPTIP -#include "h316_defs.h" // H316 emulator definitions -#include "h316_imp.h" // ARPAnet IMP/TIP definitions - -// Externals from other parts of simh ... -extern uint16 dev_ext_int, dev_ext_enb; // current IRQ and IEN bit vectors -extern int32 PC; // current PC (for debug messages) -extern int32 stop_inst; // needed by IOBADFNC() -extern uint16 M[]; // main memory (for DMC access) - -// Forward declarations ... -int32 hi_io (uint16 line, int32 inst, int32 fnc, int32 dat, int32 dev); -int32 hi1_io (int32 inst, int32 fnc, int32 dat, int32 dev); -int32 hi2_io (int32 inst, int32 fnc, int32 dat, int32 dev); -int32 hi3_io (int32 inst, int32 fnc, int32 dat, int32 dev); -int32 hi4_io (int32 inst, int32 fnc, int32 dat, int32 dev); -t_stat hi_service (UNIT *uptr); -t_stat hi_reset (DEVICE *dptr); -t_stat hi_attach (UNIT *uptr, char *cptr); -t_stat hi_detach (UNIT *uptr); - - - -//////////////////////////////////////////////////////////////////////////////// -////////////////////// D A T A S T R U C T U R E S ////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -// Host interface data blocks ... -// The HIDB is our own internal data structure for each host. It keeps data -// about the TCP/IP connection, buffers, etc. -#define HI_HIDB(N) {0, 0, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE} -HIDB hi1_db = HI_HIDB(1), hi2_db = HI_HIDB(2); -HIDB hi3_db = HI_HIDB(3), hi4_db = HI_HIDB(4); - -// Host Device Information Blocks ... -// The DIB is the structure simh uses to keep track of the device IO address -// and IO service routine. It can also hold the DMC channel, but we don't use -// that because it's unit specific. -#define HI_DIB(N) {HI##N, 1, HI##N##_RX_DMC, HI##N##_TX_DMC, \ - INT_V_HI##N##RX, INT_V_HI##N##TX, &hi##N##_io, N} -DIB hi1_dib = HI_DIB(1), hi2_dib = HI_DIB(2); -DIB hi3_dib = HI_DIB(3), hi4_dib = HI_DIB(4); - -// Host Device Unit data ... -// simh uses the unit data block primarily to schedule device service events. -// The UNIT data also contains four "user" fields which devices can reuse for -// any purpose and we take advantage of that to store the line number. -#define hline u3 // our host line number is stored in user data 3 -#define HI_UNIT(N) {UDATA (&hi_service, UNIT_ATTABLE, 0), HI_POLL_DELAY, N, 0, 0, 0} -UNIT hi1_unit = HI_UNIT(1), hi2_unit = HI_UNIT(2); -UNIT hi3_unit = HI_UNIT(3), hi4_unit = HI_UNIT(4); - -// Host Device Registers ... -// These are the simh device "registers" - they c can be viewed with the -// "EXAMINE HIxn STATE" command and modified by "DEPOSIT HIxn ..." -#define HI_REG(N) { \ - { DRDATA (POLL, hi##N##_unit.wait, 24), REG_NZ + PV_LEFT }, \ - { FLDATA (RXIRQ, dev_ext_int, INT_V_HI##N##RX-INT_V_EXTD) }, \ - { FLDATA (RXIEN, dev_ext_enb, INT_V_HI##N##RX-INT_V_EXTD) }, \ - { DRDATA (RXTOT, hi##N##_db.rxtotal,32), REG_RO + PV_LEFT }, \ - { FLDATA (TXIRQ, dev_ext_int, INT_V_HI##N##TX-INT_V_EXTD) }, \ - { FLDATA (TXIEN, dev_ext_enb, INT_V_HI##N##TX-INT_V_EXTD) }, \ - { DRDATA (TXTOT, hi##N##_db.txtotal,32), REG_RO + PV_LEFT }, \ - { FLDATA (LLOOP, hi##N##_db.lloop, 0), PV_RZRO }, \ - { FLDATA (ERROR, hi##N##_db.error, 0), PV_RZRO }, \ - { FLDATA (READY, hi##N##_db.ready, 0), PV_RZRO }, \ - { FLDATA (FULL, hi##N##_db.full , 0), PV_RZRO }, \ - { NULL } \ -} -REG hi1_reg[] = HI_REG(1), hi2_reg[] = HI_REG(2); -REG hi3_reg[] = HI_REG(3), hi4_reg[] = HI_REG(4); - -// Host Device Modifiers ... -// These are the modifiers simh uses for the "SET MIxn" and "SHOW MIx" commands. -#define HI_MOD(N) { \ - { 0 } \ -} -MTAB hi1_mod[] = HI_MOD(1), hi2_mod[] = HI_MOD(2); -MTAB hi3_mod[] = HI_MOD(3), hi4_mod[] = HI_MOD(4); - -// Debug modifiers for "SET HIn DEBUG = xxx" ... -DEBTAB hi_debug[] = { - {"WARN", IMP_DBG_WARN}, // print warnings that would otherwise be suppressed - {"UDP", IMP_DBG_UDP}, // print all UDP messages sent and received - {"IO", IMP_DBG_IOT}, // print all program I/O instructions - {0} -}; - -// Host Device data ... -// This is the primary simh structure that defines each device - it gives the -// plain text name, the addresses of the unit, register and modifier tables, and -// the addresses of all action routines (e.g. attach, reset, etc). -#define HI_DEV(HI,N,F) { \ - #HI, &hi##N##_unit, hi##N##_reg, hi##N##_mod, \ - 1, 10, 31, 1, 8, 8, \ - NULL, NULL, &hi_reset, NULL, &hi_attach, &hi_detach, \ - &hi##N##_dib, DEV_DISABLE|DEV_DEBUG|(F), 0, hi_debug, NULL, NULL \ -} -DEVICE hi1_dev = HI_DEV(HI1,1,DEV_DIS), hi2_dev = HI_DEV(HI2,2,DEV_DIS); -DEVICE hi3_dev = HI_DEV(HI3,3,DEV_DIS), hi4_dev = HI_DEV(HI4,4,DEV_DIS); - -// Host Tables ... -// These tables make it easy to locate the data associated with any host. -DEVICE *const hi_devices[HI_NUM] = {&hi1_dev, &hi2_dev, &hi3_dev, &hi4_dev }; -UNIT *const hi_units [HI_NUM] = {&hi1_unit, &hi2_unit, &hi3_unit, &hi4_unit}; -DIB *const hi_dibs [HI_NUM] = {&hi1_dib, &hi2_dib, &hi3_dib, &hi4_dib }; -HIDB *const hi_hidbs [HI_NUM] = {&hi1_db, &hi2_db, &hi3_db, &hi4_db }; - - - -//////////////////////////////////////////////////////////////////////////////// -////////////////// L O W L E V E L F U N C T I O N S /////////////////// -//////////////////////////////////////////////////////////////////////////////// - -// Find a pointer to the DEVICE, UNIT, DIB or HIDB given the host number ... -#define PDEVICE(h) hi_devices[(h)-1] -#define PUNIT(h) hi_units[(h)-1] -#define PDIB(h) hi_dibs[(h)-1] -#define PHIDB(h) hi_hidbs[(h)-1] - -// These macros set and clear the interrupt request and enable flags ... -#define SET_RX_IRQ(h) SET_EXT_INT((1u << (PDIB(h)->rxint - INT_V_EXTD))) -#define SET_TX_IRQ(h) SET_EXT_INT((1u << (PDIB(h)->txint - INT_V_EXTD))) -#define CLR_RX_IRQ(h) CLR_EXT_INT((1u << (PDIB(h)->rxint - INT_V_EXTD))) -#define CLR_TX_IRQ(h) CLR_EXT_INT((1u << (PDIB(h)->txint - INT_V_EXTD))) -#define CLR_RX_IEN(h) CLR_EXT_ENB((1u << (PDIB(h)->rxint - INT_V_EXTD))) -#define CLR_TX_IEN(h) CLR_EXT_ENB((1u << (PDIB(h)->txint - INT_V_EXTD))) - -// TRUE if the host has the specified debugging output enabled ... -#define ISHDBG(l,f) ((PDEVICE(l)->dctrl & (f)) != 0) - -// Reset receiver (clear flags AND initialize all data) ... -void hi_reset_rx (uint16 host) -{ - PHIDB(host)->lloop = PHIDB(host)->error = PHIDB(host)->enabled = FALSE; - PHIDB(host)->ready = PHIDB(host)->eom = FALSE; - PHIDB(host)->rxtotal = 0; - CLR_RX_IRQ(host); CLR_RX_IEN(host); -} - -// Reset transmitter (clear flags AND initialize all data) ... -void hi_reset_tx (uint16 host) -{ - PHIDB(host)->lloop = PHIDB(host)->enabled = PHIDB(host)->full = FALSE; - PHIDB(host)->txtotal = 0; - CLR_TX_IRQ(host); CLR_TX_IEN(host); -} - - - -//////////////////////////////////////////////////////////////////////////////// -//////////// I / O I N S T R U C T I O N E M U L A T I O N ///////////// -//////////////////////////////////////////////////////////////////////////////// - -// Host specific I/O routines ... -int32 hi1_io(int32 inst, int32 fnc, int32 dat, int32 dev) {return hi_io(1, inst, fnc, dat, dev);} -int32 hi2_io(int32 inst, int32 fnc, int32 dat, int32 dev) {return hi_io(2, inst, fnc, dat, dev);} -int32 hi3_io(int32 inst, int32 fnc, int32 dat, int32 dev) {return hi_io(3, inst, fnc, dat, dev);} -int32 hi4_io(int32 inst, int32 fnc, int32 dat, int32 dev) {return hi_io(4, inst, fnc, dat, dev);} - -// Common I/O simulation routine ... -int32 hi_io (uint16 host, int32 inst, int32 fnc, int32 dat, int32 dev) -{ - // This routine is invoked by the CPU module whenever the code executes any - // I/O instruction (OCP, SKS, INA or OTA) with one of our modem's device - // address. - - // OCP (output control pulse) initiates various modem operations ... - if (inst == ioOCP) { - switch (fnc) { - case 000: - // HnROUT - start regular host output ... - sim_debug(IMP_DBG_IOT, PDEVICE(host), "start regular output (PC=%06o)\n", PC-1); - return dat; - case 001: - // HnIN - start host input ... - sim_debug(IMP_DBG_IOT, PDEVICE(host), "start input (PC=%06o)\n", PC-1); - return dat; - case 002: - // HnFOUT - start final host output ... - sim_debug(IMP_DBG_IOT, PDEVICE(host), "start final output (PC=%06o)\n", PC-1); - return dat; - case 003: - // HnXP - cross patch ... - sim_debug(IMP_DBG_IOT, PDEVICE(host), "enable cross patch (PC=%06o)\n", PC-1); - return dat; - case 004: - // HnUNXP - un-cross patch ... - sim_debug(IMP_DBG_IOT, PDEVICE(host), "disable cross patch (PC=%06o)\n", PC-1); - return dat; - case 005: - // HnENAB - enable ... - sim_debug(IMP_DBG_IOT, PDEVICE(host), "enable host (PC=%06o)\n", PC-1); - return dat; - } - - // SKS (skip) tests various modem conditions ... - } else if (inst == ioSKS) { - switch (fnc) { - case 000: - // HnERR - skip on host error ... - sim_debug(IMP_DBG_IOT, PDEVICE(host), "skip on error (PC=%06o %s)\n", PC-1, "NOSKIP"); - return dat; - case 001: - // HnRDY - skip on host ready ... - sim_debug(IMP_DBG_IOT, PDEVICE(host), "skip on ready (PC=%06o %s)\n", PC-1, "NOSKIP"); - return dat; - case 002: - // HnEOM - skip on end of message ... - sim_debug(IMP_DBG_IOT, PDEVICE(host), "skip on end of message (PC=%06o %s)\n", PC-1, "NOSKIP"); - return dat; - case 005: - // HnFULL - skip on host buffer full ... - sim_debug(IMP_DBG_IOT, PDEVICE(host), "skip on buffer full (PC=%06o %s)\n", PC-1, "NOSKIP"); - return dat; - } - } - - // Anything else is an error... - sim_debug(IMP_DBG_WARN, PDEVICE(host), "UNIMPLEMENTED I/O (PC=%06o, instruction=%o, function=%02o)\n", PC-1, inst, fnc); - return IOBADFNC(dat); -} - - - - -//////////////////////////////////////////////////////////////////////////////// -/////////////////// H O S T E V E N T S E R V I C E //////////////////// -//////////////////////////////////////////////////////////////////////////////// - -// Unit service ... -t_stat hi_service (UNIT *uptr) -{ - return SCPE_OK; -} - - - -//////////////////////////////////////////////////////////////////////////////// -/////////////// D E V I C E A C T I O N C O M M A N D S //////////////// -//////////////////////////////////////////////////////////////////////////////// - -// Reset routine ... -t_stat hi_reset (DEVICE *dptr) -{ - // simh calls this routine for the RESET command ... - UNIT *uptr = dptr->units; - uint16 host= uptr->hline; - hi_reset_rx(host); hi_reset_tx(host); - return SCPE_OK; -} - -// Attach (connect) ... -t_stat hi_attach (UNIT *uptr, char *cptr) -{ - // simh calls this routine for (what else?) the ATTACH command. - uint16 host = uptr->hline; - fprintf(stderr,"HI%d - host interface not yet implemented\n", host); - return SCPE_IERR; -} - -// Detach (connect) ... -t_stat hi_detach (UNIT *uptr) -{ - // simh calls this routine for (you guessed it!) the DETACH command. - uint16 host = uptr->hline; - fprintf(stderr,"HI%d - host interface not yet implemented\n", host); - return SCPE_IERR; -} - - -#endif // #ifdef VM_IMPTIP from the very top diff --git a/H316/h316_imp.c b/H316/h316_imp.c deleted file mode 100644 index a99c43a1..00000000 --- a/H316/h316_imp.c +++ /dev/null @@ -1,192 +0,0 @@ -/* h316_imp.c- BBN ARPAnet IMP/TIP Specific Hardware - Based on the SIMH simulator package written by Robert M Supnik. - - Copyright (c) 2013 Robert Armstrong, bob@jfcl.com. - - 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 ARMSTRONG 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 Armstrong 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 Armstrong. - - tks task switch device - mlc multiline controller (aka TIP) - - 21-May-13 RLA New file - - OVERVIEW - - This module implements the IMP pseudo device - this hack takes care of two - custom devices in the IMP hardware - device 041, which implements task - switching and the RDIMPN instruction, and device 42, which implements the - AMIMLC ("am I a multiline controller") instruction. This module also contains - a few miscellaneous routines which are used by the IMP support in general. - - IMP state is maintained in a set of state variables: - - MLC always zero (TIP flag) - IEN task interrupt enabled - IRQ task interrupt pending - - TODO -*/ -#ifdef VM_IMPTIP -#include "h316_defs.h" // H316 emulator definitions -#include "h316_imp.h" // ARPAnet IMP/TIP definitions - -// Locals ... -uint16 imp_station = IMP_STATION; // IMP number (or address) -uint16 imp_ismlc = 0; // 1 for MLC (not yet implemented!) - -// Externals from other parts of simh ... -extern uint16 dev_ext_int, dev_ext_enb; // current IRQ and IEN bit vectors -extern int32 PC; // current PC (for debug messages) -extern int32 stop_inst; // needed by IOBADFNC() - -// Forward declarations ... -int32 imp_io (int32 inst, int32 fnc, int32 dat, int32 dev); -t_stat imp_service (UNIT *uptr); -t_stat imp_reset (DEVICE *dptr); -t_stat imp_show_station (FILE *st, UNIT *uptr, int32 val, void *dp); -t_stat io_show_int (FILE *st, UNIT *uptr, int32 val, void *dp); -t_stat imp_set_station (UNIT *uptr, int32 val, char *cptr, void *dp); -t_stat io_set_int (UNIT *uptr, int32 val, char *cptr, void *dp); - - - -//////////////////////////////////////////////////////////////////////////////// -////////////////////// D A T A S T R U C T U R E S ////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -// IMP device information block ... -DIB imp_dib = { IMP, 2, IOBUS, IOBUS, INT_V_TASK, INT_V_NONE, &imp_io, 0 }; - -// IMP unit data (we have only one!) ... -UNIT imp_unit = { UDATA (&imp_service, 0, 0) }; - -// IMP device registers (for "EXAMINE IMP STATE") ... -REG imp_reg[] = { - { FLDATA (MLC, imp_ismlc, 0), REG_RO }, - { FLDATA (IEN, dev_ext_enb, INT_V_TASK-INT_V_EXTD) }, - { FLDATA (IRQ, dev_ext_int, INT_V_TASK-INT_V_EXTD) }, - { NULL } -}; - -// IMP device modifiers (for "SET/SHOW IMP xxx") ... -MTAB imp_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "NUM", "NUM", &imp_set_station, &imp_show_station, NULL }, - { 0 } -}; - -// IMP debugging flags (for "SET IMP DEBUG=xxx") ... -DEBTAB imp_debug[] = { - {"WARN", IMP_DBG_WARN}, - {"IO", IMP_DBG_IOT}, - {0} -}; - -// And finally tie it all together ... -DEVICE imp_dev = { - "IMP", &imp_unit, imp_reg, imp_mod, - 1, 0, 0, 0, 0, 0, - NULL, NULL, &imp_reset, NULL, NULL, NULL, - &imp_dib, DEV_DIS|DEV_DISABLE|DEV_DEBUG, 0, imp_debug, NULL, NULL -}; - - - -//////////////////////////////////////////////////////////////////////////////// -////////// I M P I / O A N D S E R V I C E R O U T I N E S ////////// -//////////////////////////////////////////////////////////////////////////////// - -// Set and clear the TASK IRQ and IEN ... -#define SET_TASK_IRQ() SET_EXT_INT((1u << (imp_dib.inum - INT_V_EXTD))) -#define CLR_TASK_IRQ() CLR_EXT_INT((1u << (imp_dib.inum - INT_V_EXTD))) -#define CLR_TASK_IEN() CLR_EXT_ENB((1u << (imp_dib.inum - INT_V_EXTD))) - -// IMP I/O routine ... -int32 imp_io (int32 inst, int32 fnc, int32 dat, int32 dev) -{ - if (dev == IMP) { - if ((inst == ioOCP) && (fnc == 000)) { - // TASK - just set the task interrupt request bit ... - sim_debug(IMP_DBG_IOT, &imp_dev, "request task interrupt (PC=%06o)\n", PC-1); - SET_TASK_IRQ(); return dat; - } else if ((inst == ioINA) && ((fnc == 010) || (fnc == 000))) { - // RDIMPN - return the IMP address and always skip ... - sim_debug(IMP_DBG_IOT, &imp_dev, "read address (PC=%06o)\n", PC-1); - return IOSKIP(imp_station); - } - } else if (dev == IMP+1) { - if ((inst == ioSKS) && (fnc == 000)) { - // AMIMLC - skip if this machine is an MLC ... - sim_debug(IMP_DBG_IOT, &imp_dev, "skip on MLC (PC=%06o %s)\n", PC-1, imp_ismlc ? "SKIP" : "NOSKIP"); - if (imp_ismlc != 0) return IOSKIP(dat); else return dat; - } - } - - // Anything else is an error... - sim_debug(IMP_DBG_WARN, &imp_dev, "UNIMPLEMENTED I/O (PC=%06o, instruction=%o, function=%02o)\n", PC-1, inst, fnc); - return IOBADFNC(dat); -} - -// Unit service ... -t_stat imp_service (UNIT *uptr) -{ - return SCPE_OK; -} - - - -//////////////////////////////////////////////////////////////////////////////// -/////////////// D E V I C E A C T I O N C O M M A N D S //////////////// -//////////////////////////////////////////////////////////////////////////////// - -// Reset routine ... -t_stat imp_reset (DEVICE *dptr) -{ - // The simh RESET command clears both the interrupt request and enable... - CLR_TASK_IRQ(); CLR_TASK_IEN(); - return SCPE_OK; -} - - - -//////////////////////////////////////////////////////////////////////////////// -///////// D E V I C E S E T A N D S H O W C O M M A N D S ////////// -//////////////////////////////////////////////////////////////////////////////// - -// Show the station number ... -t_stat imp_show_station (FILE *st, UNIT *uptr, int32 val, void *desc) -{ - fprintf(st,"station=%d", imp_station); - return SCPE_OK; -} - -// Set the station number ... -t_stat imp_set_station (UNIT *uptr, int32 val, char *cptr, void *dp) -{ - uint32 newnum; t_stat sts; - if (cptr == NULL) return SCPE_ARG; - newnum = get_uint (cptr, 10, 9999, &sts); - if (newnum == 0) return SCPE_ARG; - imp_station = newnum; - return SCPE_OK; -} - -#endif // #ifdef VM_IMPTIP from the very top diff --git a/H316/h316_imp.h b/H316/h316_imp.h deleted file mode 100644 index 78e37a66..00000000 --- a/H316/h316_imp.h +++ /dev/null @@ -1,199 +0,0 @@ -/* h316_imp.h- BBN ARPAnet IMP/TIP Definitions - - Copyright (c) 2013, Robert Armstrong, bob@jfcl.com - - 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 ARMSTRONG 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 Armstrong 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 Armstrong. - - 21-May-13 RLA New file. -*/ -#ifdef VM_IMPTIP -#ifndef H316_IMP_H_ -#define H316_IMP_H_ 0 -#include "sim_defs.h" - -// Common modem and host parameters ... -#define MI_NUM 5 // number of modem interfaces -#define HI_NUM 4 // number of host interfaces -#define MI_MAX_MSG 256 // longest possible modem message (words!) -#define HI_MAX_MSG 256 // longest possible host message (words!) -#define MI_RXPOLL 100 // RX polling delay for UDP messages -#define MI_TXBPS 56000UL // default TX speed (bits per second) -#define HI_POLL_DELAY 1000 // polling delay for messages - -// Modem interface, line #1 ... -#define MI1 071 // IO address for modem interface #1 -#define MI1_RX_DMC (DMC1-1+ 1) // DMC channel for modem 1 receive -#define MI1_TX_DMC (DMC1-1+ 6) // DMC channel for modem 1 transmit -#define INT_V_MI1RX (INT_V_EXTD+15) // modem 1 receive interrupt -#define INT_V_MI1TX (INT_V_EXTD+10) // modem 1 transmit interrupt - -// Modem interface, line #2 ... -#define MI2 072 // IO address for modem interface #2 -#define MI2_RX_DMC (DMC1-1+ 2) // DMC channel for modem 2 receive -#define MI2_TX_DMC (DMC1-1+ 7) // DMC channel for modem 2 transmit -#define INT_V_MI2RX (INT_V_EXTD+14) // modem 2 receive interrupt -#define INT_V_MI2TX (INT_V_EXTD+ 9) // modem 2 transmit interrupt - -// Modem interface, line #3 ... -#define MI3 073 // IO address for modem interface #3 -#define MI3_RX_DMC (DMC1-1+ 3) // DMC channel for modem 3 receive -#define MI3_TX_DMC (DMC1-1+ 8) // DMC channel for modem 3 transmit -#define INT_V_MI3RX (INT_V_EXTD+13) // modem 3 receive interrupt -#define INT_V_MI3TX (INT_V_EXTD+ 8) // modem 3 transmit interrupt - -// Modem interface, line #4 ... -#define MI4 074 // IO address for modem interface #4 -#define MI4_RX_DMC (DMC1-1+ 4) // DMC channel for modem 4 receive -#define MI4_TX_DMC (DMC1-1+ 9) // DMC channel for modem 4 transmit -#define INT_V_MI4RX (INT_V_EXTD+12) // modem 4 receive interrupt -#define INT_V_MI4TX (INT_V_EXTD+ 7) // modem 4 transmit interrupt - -// Modem interface, line #5 ... -#define MI5 075 // IO address for modem interface #5 -#define MI5_RX_DMC (DMC1-1+ 5) // DMC channel for modem 5 receive -#define MI5_TX_DMC (DMC1-1+10) // DMC channel for modem 5 transmit -#define INT_V_MI5RX (INT_V_EXTD+11) // modem 5 receive interrupt -#define INT_V_MI5TX (INT_V_EXTD+ 6) // modem 5 transmit interrupt - -// Host interface, line #1 ... -#define HI1 070 // device address for host interface #1 -#define HI1_RX_DMC (DMC1+13-1) // DMC channel for host 1 receive -#define HI1_TX_DMC (DMC1+11-1) // DMC channel for host 1 transmit -#define INT_V_HI1RX (INT_V_EXTD+ 3) // host 1 receive interrupt -#define INT_V_HI1TX (INT_V_EXTD+ 5) // host 1 transmit interrupt - -// Host interface, line #2 ... -#define HI2 060 // device address for host interface #2 -#define HI2_RX_DMC (DMC1-1+14) // DMC channel for host 2 receive -#define HI2_TX_DMC (DMC1-1+12) // DMC channel for host 2 transmit -#define INT_V_HI2RX (INT_V_EXTD+ 2) // host 2 receive interrupt -#define INT_V_HI2TX (INT_V_EXTD+ 4) // host 2 transmit interrupt - -// Host interface, line #3 ... -#define HI3 051 // device address for host interface #3 -#define HI3_RX_DMC (DMC1-1+16) // DMC channel for host 3 receive -#define HI3_TX_DMC (DMC1-1+15) // DMC channel for host 3 transmit -#define INT_V_HI3RX (INT_V_EXTD+ 6) // host 3 receive interrupt -#define INT_V_HI3TX (INT_V_EXTD+11) // host 3 transmit interrupt - -// Host interface, line #4 ... -#define HI4 050 // device address for host interface #4 -#define HI4_RX_DMC (DMC1-1+10) // DMC channel for host 4 receive -#define HI4_TX_DMC (DMC1-1+ 5) // DMC channel for host 4 transmit -#define INT_V_HI4RX (INT_V_EXTD+ 7) // host 4 receive interrupt -#define INT_V_HI4TX (INT_V_EXTD+12) // host 4 transmit interrupt - -// IMP defaults ... -#define IMP 041 // IMP device IO address (41 & 42 actually!) -#define INT_V_TASK (INT_V_EXTD+ 0) // task switch interrupt number -#define IMP_STATION 1 // default station number - -// RTC defaults ... -#define RTC 040 // real time clock IO address -#define INT_V_RTC (INT_V_EXTD+ 1) // RTC interrupt number -#define RTC_INTERVAL 20UL // default RTC interval (20us == 50kHz) -#define RTC_QUANTUM 32UL // default RTC quantum (32 ticks) - -// WDT defaults ... -#define WDT 026 // watchdog timer IO address -#define WDT_VECTOR 000062 // WDT timeout vector -#define WDT_DELAY 0 // default WDT timeout (in milliseconds) - -// Debugging flags ... -// In general, these bits are used as arguments for sim_debug(). Bits that -// begin with "IMP_DBG_xyz" are shared by more than one device (e.g. IMP_DBG_UDP) -// and must have unique bit assignments. Bits prefixed with a device name (e.g. -// "MI_DBG_xyz") apply to that device only. -#define IMP_DBG_WARN 0x0001 // all: print warnings -#define IMP_DBG_IOT 0x0002 // all: trace all program I/O instructions -#define IMP_DBG_UDP 0x0004 // all: trace UDP packets -#define MI_DBG_MSG 0x8000 // modem: decode and print all messages -#define WDT_DBG_LIGHTS 0x8000 // wdt: show status light changes - -// Synonyms for DIB and UNIT fields ... -#define rxdmc chan // dib->rxdmc -#define txdmc chan2 // dib->txdmc -#define rxint inum // dib->rxint -#define txint inum2 // dib->txint - -// Modem interface data block .... -// One of these is allocated to every modem interface to keep track of the -// current state, COM port, UDP connection , etc... -struct _MIDB { - // Receiver data ... - t_bool rxpending; // TRUE if a read is pending on this line - t_bool rxerror; // TRUE if any modem error detected - uint32 rxtotal; // total number of H316 words received - // Transmitter data ... - uint32 txtotal; // total number of H316 words transmitted - uint32 txdelay; // RTC ticks until TX done interrupt - // Other data ... - t_bool lloop; // line loop back enabled - t_bool iloop; // interface loop back enabled - int32 link; // h316_udp link number - uint32 bps; // simulated line speed or COM port baud rate -}; -typedef struct _MIDB MIDB; - -// Host interface data block ... -// One of these is allocated to every host interface ... -struct _HIDB { - // Receiver (HOST -> IMP) data ... - uint32 rxtotal; // total host messages received - // Transmitter (IMP -> HOST) data ... - uint32 txtotal; // total host messages sent - // Other data ... - t_bool lloop; // local loop back enabled - t_bool enabled; // TRUE if the host is enabled - t_bool error; // TRUE for any host error - t_bool ready; // TRUE if the host is ready - t_bool full; // TRUE if the host buffer is full - t_bool eom; // TRUE when end of message is reached -}; -typedef struct _HIDB HIDB; - -// I can't believe Bob managed to live without these, but I can't! -#ifndef LOBYTE // these are in winsock.h too! -#define LOBYTE(x) ((uint8) ( (x) & 0xFF)) -#define HIBYTE(x) ((uint8) (((x) >> 8) & 0xFF)) -#define MKWORD(h,l) ((uint16) ( (((h)&0xFF) << 8) | ((l)&0xFF) )) -#define LOWORD(x) ((uint16) ( (x) & 0xFFFF)) -#define HIWORD(x) ((uint16) (((x) >> 16) & 0xFFFF)) -#define MKLONG(h,l) ((uint32) ( (((h)&0xFFFF) << 16) | ((l)&0xFFFF) )) -#endif - -// Prototypes for the RTC module ... -// I really hate sharing things like this, but it's the only way to get the -// modem transmitter timing exactly right! -extern uint32 rtc_interval; -extern t_stat mi_tx_service (uint32 quantum); - -// Prototypes for UDP modem/host interface emulation routines ... -#define NOLINK (-1) -t_stat udp_create (DEVICE *pdtr, char *premote, int32 *plink); -t_stat udp_release (DEVICE *dptr, int32 link); -t_stat udp_send (DEVICE *pdtr, int32 link, uint16 *pdata, uint16 count); -t_stat udp_set_link_loopback (DEVICE *dptr, int32 link, t_bool enable_loopback); -int32 udp_receive (DEVICE *dptr, int32 link, uint16 *pdata, uint16 maxbufg); - -#endif // #ifndef _H316_IMP_H_ -#endif // #ifdef VM_IMPTIP diff --git a/H316/h316_lp.c b/H316/h316_lp.c deleted file mode 100644 index 6f97d85c..00000000 --- a/H316/h316_lp.c +++ /dev/null @@ -1,357 +0,0 @@ -/* h316_lp.c: Honeywell 316/516 line printer - - Copyright (c) 1999-2015, 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 line printer - - 03-Jul-13 RLA compatibility changes for extended interrupts - 09-Jun-07 RMS Fixed lost last print line (Theo Engel) - 19-Jan-06 RMS Added UNIT_TEXT flag - 03-Apr-06 RMS Fixed bug in blanks backscanning (Theo Engel) - 01-Dec-04 RMS Fixed bug in DMA/DMC support - 24-Oct-03 RMS Added DMA/DMC support - 25-Apr-03 RMS Revised for extended file support - 30-May-02 RMS Widened POS to 32b - - The Series 16 line printer is an unbuffered Analex shuttle printer. - Because it was unbuffered, the CPU had to scan out an entire line's - worth of characters (60 words) for every character on the print drum - (64 characters). Because it was a shuttle printer, the entire - process must be repeated first for the odd columns and then for the - even columns. After scanning the odd columns, the printer carriage - shuttled right by one column; after scanning the even columns, the - carriage shuttled left. This halved the number of hammers required, - reducing cost but increasing mechanical complexity. - - The real printer is very timing dependent. If the CPU misses a - scan, then the wrong characters are printed. If the printer protocol - is violated, then results are unpredictable. The simulated printer - is much more forgiving. Rather than simulating the fixed drum and - hammer timing of the real printer, the simulator is driven by the - program's OTA instructions. If the program misses a time slot, the - simulator will still print the "correct" result. A timing based - simulation would be very hard to do in the absense of accurate - instruction timing. - - Printer state is maintained in a set of position and state variables: - - lpt_wdpos word count within a line scan (0-59) - lpt_drpos drum position (0-63) - lpt_crpos carriage position (0-1) - lpt_svcst service state (shuttle, paper advance) - lpt_svcch channel for paper advance (0 = no adv) - lpt_rdy transfer ready flag - lpt_prdn printing done flag - lpt_dma use DMA/DMC - lpt_eor DMA/DMC end of range -*/ - -#include "h316_defs.h" - -#define LPT_WIDTH 120 /* width */ -#define LPT_SCAN (LPT_WIDTH / 2) /* words/scan */ -#define LPT_DRUM 64 /* drum rows */ -#define LPT_SVCSH 01 /* shuttle */ -#define LPT_SVCPA 02 /* paper advance */ - -extern int32 dev_int, dev_enb; -extern int32 stop_inst; -extern uint32 chan_req; - -int32 lpt_wdpos = 0; /* word position */ -int32 lpt_drpos = 0; /* drum position */ -int32 lpt_crpos = 0; /* carriage position */ -int32 lpt_svcst = 0; /* service state */ -int32 lpt_svcch = 0; /* service channel */ -int32 lpt_rdy = 0; /* transfer flag */ -int32 lpt_prdn = 1; /* printing done */ -int32 lpt_dma = 0; /* use DMA/DMC */ -int32 lpt_eor = 0; /* DMA/DMC end range */ -char lpt_buf[LPT_WIDTH + 1] = { 0 }; /* line buffer */ -int32 lpt_xtime = 5; /* transfer time */ -int32 lpt_etime = 50; /* end of scan time */ -int32 lpt_ptime = 5000; /* paper adv time */ -int32 lpt_stopioe = 0; /* stop on error */ - -int32 lptio (int32 inst, int32 fnc, int32 dat, int32 dev); -t_stat lpt_svc (UNIT *uptr); -t_stat lpt_reset (DEVICE *dptr); - -/* LPT data structures - - lpt_dev LPT device descriptor - lpt_unit LPT unit descriptor - lpt_mod LPT modifiers - lpt_reg LPT register list -*/ - -DIB lpt_dib = { LPT, 1, IOBUS, IOBUS, INT_V_LPT, INT_V_NONE, &lptio, 0 }; - -UNIT lpt_unit = { UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0) }; - -REG lpt_reg[] = { - { DRDATA (WDPOS, lpt_wdpos, 6) }, - { DRDATA (DRPOS, lpt_drpos, 6) }, - { FLDATA (CRPOS, lpt_crpos, 0) }, - { FLDATA (RDY, lpt_rdy, 0) }, - { FLDATA (EOR, lpt_eor, 0) }, - { FLDATA (DMA, lpt_dma, 0) }, - { FLDATA (PRDN, lpt_prdn, 0) }, - { FLDATA (INTREQ, dev_int, INT_V_LPT) }, - { FLDATA (ENABLE, dev_enb, INT_V_LPT) }, - { ORDATA (SVCST, lpt_svcst, 2) }, - { ORDATA (SVCCH, lpt_svcch, 2) }, - { BRDATA (BUF, lpt_buf, 8, 8, 120) }, - { DRDATA (POS, lpt_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (XTIME, lpt_xtime, 24), PV_LEFT }, - { DRDATA (ETIME, lpt_etime, 24), PV_LEFT }, - { DRDATA (PTIME, lpt_ptime, 24), PV_LEFT }, - { FLDATA (STOP_IOE, lpt_stopioe, 0) }, - { NULL } - }; - -DEVICE lpt_dev = { - "LPT", &lpt_unit, lpt_reg, NULL, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &lpt_reset, - NULL, NULL, NULL, - &lpt_dib, DEV_DISABLE - }; - -/* IO routine */ - -int32 lptio (int32 inst, int32 fnc, int32 dat, int32 dev) -{ -int32 ch = lpt_dib.chan - 1; /* DMA/DMC chan */ -int32 chr; - -switch (inst) { /* case on opcode */ - - case ioOCP: /* OCP */ - switch (fnc) { /* case on fnc */ - - case 000: case 002: case 004: /* paper adv */ - lpt_svcst = lpt_svcst | LPT_SVCPA; /* set state */ - lpt_svcch = fnc >> 1; /* save channel */ - sim_activate (&lpt_unit, lpt_ptime); - CLR_INT (INT_LPT); /* clear int */ - break; - - case 003: /* init scan DMA/DMC */ - lpt_prdn = 0; /* clear pr done */ - lpt_wdpos = 0; /* init scan pos */ - lpt_eor = 0; - if (ch >= 0) /* try for DMA/DMC */ - lpt_dma = 1; - else lpt_dma = 0; - if (!sim_is_active (&lpt_unit)) { - lpt_rdy = 1; - if (lpt_dma) - SET_CH_REQ (ch); - } - CLR_INT (INT_LPT); /* clear int */ - break; - - case 007: /* init scan IO bus */ - lpt_prdn = 0; /* clear pr done */ - lpt_wdpos = 0; /* init scan pos */ - lpt_eor = 0; - lpt_dma = 0; /* IO bus */ - if (!sim_is_active (&lpt_unit)) - lpt_rdy = 1; - CLR_INT (INT_LPT); /* clear int */ - break; - - default: - return IOBADFNC (dat); - } - break; - - case ioSKS: /* SKS */ - switch (fnc) { /* case on fnc */ - - case 000: /* if xfer rdy */ - if (lpt_rdy) - return IOSKIP (dat); - break; - - case 002: /* if !alarm */ - if (lpt_unit.flags & UNIT_ATT) - return IOSKIP (dat); - break; - - case 003: /* if odd col */ - if (lpt_crpos) - return IOSKIP (dat); - break; - - case 004: /* if !interrupt */ - if (!TST_INTREQ (INT_LPT)) - return IOSKIP (dat); - break; - - case 011: /* if line printed */ - if (lpt_prdn) - return IOSKIP (dat); - break; - - case 012: /* if !shuttling */ - if (!(lpt_svcst & LPT_SVCSH)) - return IOSKIP (dat); - break; - - case 013: - if (lpt_prdn && !(lpt_svcst & LPT_SVCSH)) - return IOSKIP (dat); - break; - - case 014: /* if !advancing */ - if (!(lpt_svcst & LPT_SVCPA)) - return IOSKIP (dat); - break; - - case 015: - if (lpt_prdn && !(lpt_svcst & LPT_SVCPA)) - return IOSKIP (dat); - break; - - case 016: - if (!(lpt_svcst & (LPT_SVCSH | LPT_SVCPA))) - return IOSKIP (dat); - break; - - case 017: - if (lpt_prdn && !(lpt_svcst & (LPT_SVCSH | LPT_SVCPA))) - return IOSKIP (dat); - break; - - default: - return IOBADFNC (dat); - } - break; - - case ioOTA: /* OTA */ - if (fnc) /* only fnc 0 */ - return IOBADFNC (dat); - if (lpt_rdy) { /* xfer ready? */ - lpt_rdy = 0; /* clear xfer */ - chr = (dat >> (lpt_crpos? 0: 8)) & 077; /* get 6b char */ - if (chr == lpt_drpos) { /* match drum pos? */ - if (chr < 040) - chr = chr | 0100; - lpt_buf[2 * lpt_wdpos + lpt_crpos] = chr; - } - lpt_wdpos++; /* adv scan pos */ - if (lpt_wdpos >= LPT_SCAN) { /* end of scan? */ - lpt_wdpos = 0; /* reset scan pos */ - lpt_drpos++; /* adv drum pos */ - if (lpt_drpos >= LPT_DRUM) { /* end of drum? */ - lpt_drpos = 0; /* reset drum pos */ - lpt_crpos = lpt_crpos ^ 1; /* shuttle */ - lpt_svcst = lpt_svcst | LPT_SVCSH; - sim_activate (&lpt_unit, lpt_ptime); - } /* end if shuttle */ - else sim_activate (&lpt_unit, lpt_etime); - } /* end if endscan */ - else sim_activate (&lpt_unit, lpt_xtime); - return IOSKIP (dat); /* skip return */ - } - break; - - case ioEND: /* end DMA/DMC */ - lpt_eor = 1; /* set end range */ - break; - } /* end case op */ - -return dat; -} - -/* Unit service */ - -t_stat lpt_svc (UNIT *uptr) -{ -int32 i; -int32 ch = lpt_dib.chan - 1; /* DMA/DMC chan */ -static const char *lpt_cc[] = { - "\r", - "\n", - "\n\f", - "\n" - }; - -if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (lpt_stopioe, SCPE_UNATT); -if (lpt_dma) { /* DMA/DMC? */ - if (lpt_eor) /* end range? intr */ - SET_INT (INT_LPT); - else { - lpt_rdy = 1; /* set ready */ - SET_CH_REQ (ch); /* get more data */ - } - } -else lpt_rdy = 1; /* IO, continue scan */ -if (lpt_svcst & LPT_SVCSH) { /* shuttling? */ - SET_INT (INT_LPT); /* interrupt */ - if (lpt_crpos == 0) { /* done shuttling? */ - for (i = LPT_WIDTH - 1; i >= 0; i--) { /* backscan for blanks */ - if (lpt_buf[i] != ' ') - break; - } - lpt_buf[i + 1] = 0; - fputs (lpt_buf, uptr->fileref); /* output buf */ - uptr->pos = ftell (uptr->fileref); /* update pos */ - for (i = 0; i < LPT_WIDTH; i++) /* clear buf */ - lpt_buf[i] = ' '; - lpt_prdn = 1; /* print done */ - } - } -if (lpt_svcst & LPT_SVCPA) { /* paper advance */ - SET_INT (INT_LPT); /* interrupt */ - fputs (lpt_cc[lpt_svcch & 03], uptr->fileref); /* output eol */ - uptr->pos = ftell (uptr->fileref); /* update pos */ - } -lpt_svcst = 0; -return SCPE_OK; -} - -/* Reset routine */ - -t_stat lpt_reset (DEVICE *dptr) -{ -int32 i; - -lpt_wdpos = lpt_drpos = lpt_crpos = 0; /* clear positions */ -lpt_svcst = lpt_svcch = 0; /* idle state */ -lpt_rdy = 0; /* not rdy to xfer */ -lpt_prdn = 1; /* printing done */ -lpt_eor = 0; -lpt_dma = 0; -for (i = 0; i < LPT_WIDTH; i++) /* clear buffer */ - lpt_buf[i] = ' '; -lpt_buf[LPT_WIDTH] = 0; -CLR_INT (INT_LPT); /* clear int, enb */ -CLR_ENB (INT_LPT); -sim_cancel (&lpt_unit); /* deactivate unit */ -return SCPE_OK; -} diff --git a/H316/h316_mi.c b/H316/h316_mi.c deleted file mode 100644 index ae4371f4..00000000 --- a/H316/h316_mi.c +++ /dev/null @@ -1,766 +0,0 @@ -/* h316_mi.c- BBN ARPAnet IMP/TIP Modem Interface - Based on the SIMH simulator package written by Robert M Supnik. - - Copyright (c) 2013 Robert Armstrong, bob@jfcl.com. - - 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 ARMSTRONG 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 Armstrong 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 Armstrong. - - - REVISION HISTORY - - mi modem interface - - 21-May-13 RLA New file - - - OVERVIEW - - The modem interface is one of the BBN engineered devices unique to the - ARPAnet IMP/TIP. The original hardware was a full duplex synchronous serial - line interface operating at 56k bps. The hardware was fairly smart and was - able to handle line synchronization (SYN), packet start (STX) and end (ETX), - and data escape (DLE) autonomously. Data is transferred directly to and - from H316 main memory using the DMC mechanism. The modem interface also - calculated a 24 bit "parity" (and by that I assume they meant some form of - CRC) value. This was automatically appended to the end of the transmitted - data and automatically verified by the receiving modem. - - CONNECTIONS - - This module provides two basic options for emulating the modem. Option 1 - takes the data packets from H316 memory, wraps them in a UDP packet, and - sends them to another simh instance. The remote simh then unwraps the data - packet and loads it directly into H316 memory. In this instance, - synchronization, start of text/end of text, and data escapes are pointless - and are not used. The words are simply moved verbatim from one H316 to - another. - - The other option is to logically connect the emulated modem to a physical - serial port on this PC. In that case we attempt to emulate the actions - of the original modem as closely as possible, including the synchronization, - start of text/end of text and data escape characters. Synchronization is - pointless on an asynchronous interface, of course, but we do it anyway in - the interest of compatability. We also attempt to calculate a 24 bit CRC - using (as best I can determine) the same algorithm as the original modems. - - MULTIPLE INSTANCES - - Each IMP can support up to five modem lines, and fitting this into simh - presents an architectural problem. The temptation is to treat all modems as - one device with multiple units (each unit corresponding to one line), but - that's a problem. The simh view of units is like a disk or tape - there's - a single controller that has one IO address, one interrupt and one DMA/DMC - channel. That controller then has multiple units attached to it that are - selected by bits in a controller register and all units share the same - IO, interrupt and DMA/DMC assignments. - - The modems aren't like that at all - each of the five cards is completely - independent with its own distinct IO address, interrupt and DMC assignments. - It's analagous to five instances of the same controller installed in the - machine, but simh unfortunately has limited support for multiple instances - of the same controller. The few instances of prior art in simh that I can - find (e.g. xq, xqb on the PDP11/VAX) have just been done ad hoc by - duplicating all the device data. Rather than rewrite simh, that's the - approach I took here, even though with five instances it gets awkward. - - POLLING AND SERVICE - - The IMP software turns out to be extraordinarily sensitive to modem timing. - It actually goes to the trouble of measuring the effective line speed by - using the RTC to time how long it takes to send a message, and one thing that - especially annoys the IMP are variations in the effective line speed. They - had a lot of trouble with AT&T Long Lines back in the Old Days, and the IMP - has quite a bit of code to monitor line quality. Even fairly minor variations - in speed will cause it to mark the line as "down" and sent a trouble report - back to BBN. - - To combat this, we actually let the RTC code time the transmitter interrupts. - When the IMP software does a "start modem output" OCP the entire packet will - be extracted from H316 memory and transmitted via UDP at that instant, BUT - the transmitter done interrupt will be deferred. The delay is computed from - the length of the packet and the simulated line speed, and then the RTC is - used to count down the interval. When the time expires, the interrupt request - is generated. It's unfortunate to have to couple the RTC and the modem in - this way, but since the IMP code is using the RTC to measure the line speed - AND since the RTC determines when the transmit done occurs, it guarantees - that the IMP always sees exactly the same delay. - - The modem receiver is completely independent of the transmitter and is polled - by the usual simh event queue mechanism and mi_service() routine. When the - IMP code executes a "start modem input" OCP a read pending flag is set in the - modem status but nothing else occurs. Each poll checks the UDP socket for - incoming data and, if a packet was received AND a read operation is pending, - then the read completes that moment and the interrupt request is asserted. - The UDP socket is polled regardless of whether a read is pending and if data - arrives without a read then it's discarded. That's exactly what a real modem - would do. - - ERROR HANDLING - - Transmitter error handling is easy - fatal errors print a message and abort - the simulation, but any other errors are simply ignored. The IMP modems had - no kind of error dection on the transmitter side and no way to report them - anyway so we do the same. Any data packet associated with the error is just - discarded. In particular with both UDP and COM ports there's no way to tell - whether anybody is on the other end listening, so even packets that are - successfully transmitted may disappear into the ether. This isn't a problem - for the IMP - the real world was like that too and the IMP is able to handle - retransmitting packets without our help. - - Receiver errors set the error flag in the modem status; this flag can be - tested and cleared by the "skip on modem error" SKS instruction. The only - receiver error that can be detected is buffer overrun (i.e. the sender's - message was longer than the receiver's buffer). With a serial connection - checksum errors are also possible, but those never occur with UDP. - - Transmitting or receiving on a modem that's not attached isn't an error - it - simply does nothing. It's analogous to a modem with the phone line unplugged. - Hard I/O errors for UDP or COM ports print an error message and then detach - the modem connection. It's up to the user to interrupt the simulation and - reattach if he wants to try again. - - STATE - - Modem state is maintained in the following variables - - - RXPOLL 24 receiver polling interval - RXPEND 1 an input operation is pending - RXERR 1 receiver error flag - RXIEN 1 receiver interrupt enable - RXIRQ 1 receiver interrupt request - RXTOT 32 count of total messages received - TXDLY 32 RTC ticks until TX done interrupt - TXIEN 1 transmitter interrupt enable - TXIRQ 1 transmitter interrupt request - TXTOT 32 count of total messages transmitted - LINKNO 32 link number for h316_udp module - BPS 32 simulated bps for UDP delay calculations - actual baud rate for physical COM ports - ILOOP 1 interface (local) loopback enabled - RLOOP 1 remote (line) loopback enabled - - Most of these values will be found in the Modem Information Data Block (aka - "MIDB") but a few are stored elsewhere (e.g. IRQ/IEN are in the CPU's dev_int - and dev_enb vectors). - - TODO - - Implement checksum handling - Implement remote loopback -*/ -#ifdef VM_IMPTIP -#include "h316_defs.h" // H316 emulator definitions -#include "h316_imp.h" // ARPAnet IMP/TIP definitions - -// Externals from other parts of simh ... -extern uint16 dev_ext_int, dev_ext_enb; // current IRQ and IEN bit vectors -extern int32 PC; // current PC (for debug messages) -extern int32 stop_inst; // needed by IOBADFNC() -extern uint16 M[]; // main memory (for DMC access) - -// Forward declarations ... -int32 mi_io (uint16 line, int32 inst, int32 fnc, int32 dat, int32 dev); -int32 mi1_io (int32 inst, int32 fnc, int32 dat, int32 dev); -int32 mi2_io (int32 inst, int32 fnc, int32 dat, int32 dev); -int32 mi3_io (int32 inst, int32 fnc, int32 dat, int32 dev); -int32 mi4_io (int32 inst, int32 fnc, int32 dat, int32 dev); -int32 mi5_io (int32 inst, int32 fnc, int32 dat, int32 dev); -t_stat mi_rx_service (UNIT *uptr); -void mi_rx_local (uint16 line, uint16 txnext, uint16 txcount); -t_stat mi_reset (DEVICE *dptr); -t_stat mi_attach (UNIT *uptr, char *cptr); -t_stat mi_detach (UNIT *uptr); -t_stat mi_set_loopback (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat mi_show_loopback (FILE *st, UNIT *uptr, int32 val, void *desc); - - - -//////////////////////////////////////////////////////////////////////////////// -////////////////////// D A T A S T R U C T U R E S ////////////////////// -//////////////////////////////////////////////////////////////////////////////// - -// simh requires several data structures for every device - a DIB, one or more -// UNITS, a modifier table, a register list, and a device definition. The sit- -// uation here is even more complicated because we have five identical modems to -// define, and so lots of clever macros are used to handle the repetition and -// save some typing. - -// Modem Information Data Blocks ... -// The MIDB is our own internal data structure for each modem. It keeps data -// about the current state, COM port, UDP connection, etc. -#define MI_MIDB(N) {FALSE, FALSE, 0, 0, 0, FALSE, FALSE, NOLINK, MI_TXBPS} -MIDB mi1_db = MI_MIDB(1), mi2_db = MI_MIDB(2); -MIDB mi3_db = MI_MIDB(3), mi4_db = MI_MIDB(4); -MIDB mi5_db = MI_MIDB(5); - -// Modem Device Information Blocks ... -// The DIB is the structure simh uses to keep track of the device IO address -// and IO service routine. It can also hold the DMC channel, but we don't use -// that because it's unit specific. -#define MI_DIB(N) {MI##N, 1, MI##N##_RX_DMC, MI##N##_TX_DMC, \ - INT_V_MI##N##RX, INT_V_MI##N##TX, &mi##N##_io, N} -DIB mi1_dib = MI_DIB(1), mi2_dib = MI_DIB(2); -DIB mi3_dib = MI_DIB(3), mi4_dib = MI_DIB(4); -DIB mi5_dib = MI_DIB(5); - -// Modem Device Unit data ... -// simh uses the unit data block primarily to schedule device service events. -#define mline u3 // our modem line number is stored in user data 3 -#define MI_UNIT(N) {UDATA (&mi_rx_service, UNIT_ATTABLE, 0), MI_RXPOLL, N, 0, 0, 0} -UNIT mi1_unit = MI_UNIT(1), mi2_unit = MI_UNIT(2); -UNIT mi3_unit = MI_UNIT(3), mi4_unit = MI_UNIT(4); -UNIT mi5_unit = MI_UNIT(5); - -// Modem Device Registers ... -// These are the simh device "registers" - they c can be viewed with the -// "EXAMINE MIn STATE" command and modified by "DEPOSIT MIn ..." -#define MI_REG(N) { \ - { DRDATA (RXPOLL, mi##N##_unit.wait, 24), REG_NZ + PV_LEFT }, \ - { FLDATA (RXPEND, mi##N##_db.rxpending, 0), REG_RO + PV_RZRO }, \ - { FLDATA (RXERR, mi##N##_db.rxerror, 0), PV_RZRO }, \ - { FLDATA (RXIEN, dev_ext_enb, INT_V_MI##N##RX-INT_V_EXTD) }, \ - { FLDATA (RXIRQ, dev_ext_int, INT_V_MI##N##RX-INT_V_EXTD) }, \ - { DRDATA (RXTOT, mi##N##_db.rxtotal, 32), REG_RO + PV_LEFT }, \ - { DRDATA (TXDLY, mi##N##_db.txdelay, 32), PV_LEFT }, \ - { FLDATA (TXIEN, dev_ext_enb, INT_V_MI##N##TX-INT_V_EXTD) }, \ - { FLDATA (TXIRQ, dev_ext_int, INT_V_MI##N##TX-INT_V_EXTD) }, \ - { DRDATA (TXTOT, mi##N##_db.txtotal, 32), REG_RO + PV_LEFT }, \ - { DRDATA (LINK, mi##N##_db.link, 32), REG_RO + PV_LEFT }, \ - { DRDATA (BPS, mi##N##_db.bps, 32), REG_NZ + PV_LEFT }, \ - { FLDATA (LLOOP, mi##N##_db.lloop, 0), REG_RO + PV_RZRO }, \ - { FLDATA (ILOOP, mi##N##_db.iloop, 0), REG_RO + PV_RZRO }, \ - { NULL } \ -} -REG mi1_reg[] = MI_REG(1), mi2_reg[] = MI_REG(2); -REG mi3_reg[] = MI_REG(3), mi4_reg[] = MI_REG(4); -REG mi5_reg[] = MI_REG(5); - -// Modem Device Modifiers ... -// These are the modifiers simh uses for the "SET MIn" and "SHOW MIn" commands. -#define MI_MOD(N) { \ - { MTAB_XTD|MTAB_VDV, 0, "LOOPBACK", "LOOPINTERFACE", &mi_set_loopback, &mi_show_loopback, NULL }, \ - { MTAB_XTD|MTAB_VDV, 1, NULL, "NOLOOPINTERFACE", &mi_set_loopback, NULL, NULL }, \ - { MTAB_XTD|MTAB_VDV, 2, NULL, "LOOPLINE", &mi_set_loopback, NULL, NULL }, \ - { MTAB_XTD|MTAB_VDV, 3, NULL, "NOLOOPLINE", &mi_set_loopback, NULL, NULL }, \ - { 0 } \ -} -MTAB mi1_mod[] = MI_MOD(1), mi2_mod[] = MI_MOD(2); -MTAB mi3_mod[] = MI_MOD(3), mi4_mod[] = MI_MOD(4); -MTAB mi5_mod[] = MI_MOD(5); - -// Debug modifiers for "SET MIn DEBUG = xxx" ... -DEBTAB mi_debug[] = { - {"WARN", IMP_DBG_WARN}, // print warnings that would otherwise be suppressed - {"UDP", IMP_DBG_UDP}, // print all UDP messages sent and received - {"IO", IMP_DBG_IOT}, // print all program I/O instructions - {"MSG", MI_DBG_MSG}, // decode and print all messages - {0} -}; - -// Modem Device data ... -// This is the primary simh structure that defines each device - it gives the -// plain text name, the addresses of the unit, register and modifier tables, and -// the addresses of all action routines (e.g. attach, reset, etc). -#define MI_DEV(MI,N,F) { \ - #MI, &mi##N##_unit, mi##N##_reg, mi##N##_mod, \ - 1, 10, 31, 1, 8, 8, \ - NULL, NULL, &mi_reset, NULL, &mi_attach, &mi_detach, \ - &mi##N##_dib, DEV_DISABLE|DEV_DEBUG|(F), 0, mi_debug, NULL, NULL \ -} -DEVICE mi1_dev = MI_DEV(MI1,1,DEV_DIS), mi2_dev = MI_DEV(MI2,2,DEV_DIS); -DEVICE mi3_dev = MI_DEV(MI3,3,DEV_DIS), mi4_dev = MI_DEV(MI4,4,DEV_DIS); -DEVICE mi5_dev = MI_DEV(MI5,5,DEV_DIS); - -// Modem Tables ... -// These tables make it easy to locate the data associated with any line. -DEVICE *const mi_devices[MI_NUM] = {&mi1_dev, &mi2_dev, &mi3_dev, &mi4_dev, &mi5_dev }; -UNIT *const mi_units [MI_NUM] = {&mi1_unit, &mi2_unit, &mi3_unit, &mi4_unit, &mi5_unit}; -DIB *const mi_dibs [MI_NUM] = {&mi1_dib, &mi2_dib, &mi3_dib, &mi4_dib, &mi5_dib }; -MIDB *const mi_midbs [MI_NUM] = {&mi1_db, &mi2_db, &mi3_db, &mi4_db, &mi5_db }; - - - -//////////////////////////////////////////////////////////////////////////////// -////////////////// L O W L E V E L F U N C T I O N S /////////////////// -//////////////////////////////////////////////////////////////////////////////// - -// Find a pointer to the DEVICE, UNIT, DIB or MIDB given the line number ... -#define PDEVICE(l) mi_devices[(l)-1] -#define PUNIT(l) mi_units[(l)-1] -#define PDIB(l) mi_dibs[(l)-1] -#define PMIDB(l) mi_midbs[(l)-1] - -// These macros set and clear the interrupt request and enable flags ... -#define SET_RX_IRQ(l) SET_EXT_INT((1u << (PDIB(l)->rxint - INT_V_EXTD))) -#define SET_TX_IRQ(l) SET_EXT_INT((1u << (PDIB(l)->txint - INT_V_EXTD))) -#define CLR_RX_IRQ(l) CLR_EXT_INT((1u << (PDIB(l)->rxint - INT_V_EXTD))) -#define CLR_TX_IRQ(l) CLR_EXT_INT((1u << (PDIB(l)->txint - INT_V_EXTD))) -#define CLR_RX_IEN(l) CLR_EXT_ENB((1u << (PDIB(l)->rxint - INT_V_EXTD))) -#define CLR_TX_IEN(l) CLR_EXT_ENB((1u << (PDIB(l)->txint - INT_V_EXTD))) - -// TRUE if the line has the specified debugging output enabled ... -#define ISLDBG(l,f) ((PDEVICE(l)->dctrl & (f)) != 0) - -// Reset receiver (clear flags AND initialize all data) ... -void mi_reset_rx (uint16 line) -{ - PMIDB(line)->iloop = PMIDB(line)->lloop = FALSE; - udp_set_link_loopback (PDEVICE(line), PMIDB(line)->link, FALSE); - PMIDB(line)->rxerror = PMIDB(line)->rxpending = FALSE; - PMIDB(line)->rxtotal = 0; - CLR_RX_IRQ(line); CLR_RX_IEN(line); -} - -// Reset transmitter (clear flags AND initialize all data) ... -void mi_reset_tx (uint16 line) -{ - PMIDB(line)->iloop = PMIDB(line)->lloop = FALSE; - udp_set_link_loopback (PDEVICE(line), PMIDB(line)->link, FALSE); - PMIDB(line)->txtotal = PMIDB(line)->txdelay = 0; - CLR_TX_IRQ(line); CLR_TX_IEN(line); -} - -// Get the DMC control words (starting address, end and length) for the channel. -void mi_get_dmc (uint16 dmc, uint16 *pnext, uint16 *plast, uint16 *pcount) -{ - uint16 dmcad; - if ((dmc(DMC1+DMC_MAX-1))) { - *pnext = *plast = *pcount = 0; return; - } - dmcad = DMC_BASE + (dmc-DMC1)*2; - *pnext = M[dmcad] & X_AMASK; *plast = M[dmcad+1] & X_AMASK; - *pcount = (*plast - *pnext + 1) & DMASK; -} - -// Update the DMC words to show "count" words transferred. -void mi_update_dmc (uint32 dmc, uint32 count) -{ - uint16 dmcad, next; - if ((dmc(DMC1+DMC_MAX-1))) return; - dmcad = DMC_BASE + (dmc-DMC1)*2; - next = M[dmcad]; - M[dmcad] = (next & DMA_IN) | ((next+count) & X_AMASK); -} - -// Link error recovery ... -void mi_link_error (uint16 line) -{ - // Any physical I/O error, either for the UDP link or a COM port, prints a - // message and detaches the modem. It's up to the user to decide what to do - // after that... - fprintf(stderr,"MI%d - UNRECOVERABLE I/O ERROR!\n", line); - mi_reset_rx(line); mi_reset_tx(line); - sim_cancel(PUNIT(line)); mi_detach(PUNIT(line)); - PMIDB(line)->link = NOLINK; -} - - - -//////////////////////////////////////////////////////////////////////////////// -/////////////////// D E B U G G I N G R O U T I N E S //////////////////// -//////////////////////////////////////////////////////////////////////////////// - -// Log a modem input or output including DMC words ... -void mi_debug_mio (uint16 line, uint32 dmc, const char *ptext) -{ - uint16 next, last, count; - if (!ISLDBG(line, IMP_DBG_IOT)) return; - mi_get_dmc(dmc, &next, &last, &count); - sim_debug(IMP_DBG_IOT, PDEVICE(line), - "start %s (PC=%06o, next=%06o, last=%06o, count=%d)\n", - ptext, PC-1, next, last, count); -} - -// Log the contents of a message sent or received ... -void mi_debug_msg (uint16 line, uint16 next, uint16 count, const char *ptext) -{ - uint16 i; char buf[CBUFSIZE]; int len = 0; - if (!ISLDBG(line, MI_DBG_MSG)) return; - sim_debug(MI_DBG_MSG, PDEVICE(line), "message %s (length=%d)\n", ptext, count); - for (i = 1, len = 0; i <= count; ++i) { - len += sprintf(buf+len, "%06o ", M[next+i-1]); - if (((i & 7) == 0) || (i == count)) { - sim_debug(MI_DBG_MSG, PDEVICE(line), "- %s\n", buf); len = 0; - } - } -} - - - -//////////////////////////////////////////////////////////////////////////////// -///////////////// T R A N S M I T A N D R E C E I V E ////////////////// -//////////////////////////////////////////////////////////////////////////////// - -// Start the transmitter ... -void mi_start_tx (uint16 line) -{ - // This handles all the work of the "start modem output" OCP, including - // extracting the packet from H316 memory, EXCEPT for actually setting the - // transmit done interrupt. That's handled by the RTC polling routine after - // a delay that we calculate.. - uint16 next, last, count; uint32 nbits; t_stat ret; - - // Get the DMC words for this channel and update the next pointer as if the - // transfer actually occurred. - mi_get_dmc(PDIB(line)->txdmc, &next, &last, &count); - mi_update_dmc(PDIB(line)->txdmc, count); - mi_debug_msg (line, next, count, "sent"); - - // Transmit the data, handling both the interface loopback AND the line loop - // back flags in the process. Note that in particular the interface loop back - // does NOT require that the modem be attached! - if (PMIDB(line)->iloop) { - mi_rx_local(line, next, count); - } else if (PMIDB(line)->link != NOLINK) { - ret = udp_send(PDEVICE(line), PMIDB(line)->link, &M[next], count); - if (ret != SCPE_OK) mi_link_error(line); - } - - // Do some fancy math to figure out how long, in RTC ticks, it would actually - // take to transmit a packet of this length with a real modem and phone line. - // Note that the "+12" is an approximation for the modem overhead, including - // DLE, STX, ETX and checksum bytes, that would be added to the packet. - nbits = (((uint32) count)*2UL + 12UL) * 8UL; - PMIDB(line)->txdelay = (nbits * 1000000UL) / (PMIDB(line)->bps * rtc_interval); - //fprintf(stderr,"MI%d - transmit packet, length=%d, bits=%ld, interval=%ld, delay=%ld\n", line, count, nbits, rtc_interval, PMIDB(line)->txdelay); - - // That's it - we're done until it's time for the TX done interrupt ... - CLR_TX_IRQ(line); -} - -// Poll for transmitter done interrupts ... -void mi_poll_tx (uint16 line, uint32 quantum) -{ - // This routine is called, via the RTC service, to count down the interval - // until the transmitter finishes. When it hits zero, an interrupt occurs. - if (PMIDB(line)->txdelay == 0) return; - if (PMIDB(line)->txdelay <= quantum) { - SET_TX_IRQ(line); PMIDB(line)->txdelay = 0; PMIDB(line)->txtotal++; - sim_debug(IMP_DBG_IOT, PDEVICE(line), "transmit done (message #%d, intreq=%06o)\n", PMIDB(line)->txtotal, dev_ext_int); - } else - PMIDB(line)->txdelay -= quantum; -} - -// Start the receiver ... -void mi_start_rx (uint16 line) -{ - // "Starting" the receiver simply sets the RX pending flag. Nothing else - // needs to be done (nothing else _can_ be done!) until we actually receive - // a real packet. - - // We check for the case of another receive already pending, but I don't - // think the real hardware detected this or considered it an error condition. - if (PMIDB(line)->rxpending) { - sim_debug(IMP_DBG_WARN,PDEVICE(line),"start input while input already pending\n"); - } - PMIDB(line)->rxpending = TRUE; PMIDB(line)->rxerror = FALSE; - CLR_RX_IRQ(line); -} - -// Poll for receiver data ... -void mi_poll_rx (uint16 line) -{ - // This routine is called by mi_service to poll for any packets received. - // This is done regardless of whether a receive is pending on the line. If - // a packet is waiting AND a receive is pending then we'll store it and finish - // the receive operation. If a packet is waiting but no receive is pending - // then the packet is discarded... - uint16 next, last, maxbuf; uint16 *pdata; int16 count; - - // If the modem isn't attached, then the read never completes! - if (PMIDB(line)->link == NOLINK) return; - - // Get the DMC words for this channel, or zeros if no read is pending ... - if (PMIDB(line)->rxpending) { - mi_get_dmc(PDIB(line)->rxdmc, &next, &last, &maxbuf); - pdata = &M[next]; - } else { - next = last = maxbuf = 0; pdata = NULL; - } - // Try to read a packet. If we get nothing then just return. - count = udp_receive(PDEVICE(line), PMIDB(line)->link, pdata, maxbuf); - if (count == 0) return; - if (count < 0) {mi_link_error(line); return;} - - // Now would be a good time to worry about whether a receive is pending! - if (!PMIDB(line)->rxpending) { - sim_debug(IMP_DBG_WARN, PDEVICE(line), "data received with no input pending\n"); - return; - } - - // We really got a packet! Update the DMC pointers to reflect the actual - // size of the packet received. If the packet length would have exceeded the - // receiver buffer, then that sets the error flag too. - if (count > maxbuf) { - sim_debug(IMP_DBG_WARN, PDEVICE(line), "receiver overrun (length=%d maxbuf=%d)\n", count, maxbuf); - PMIDB(line)->rxerror = TRUE; count = maxbuf; - } - mi_update_dmc(PDIB(line)->rxdmc, count); - mi_debug_msg (line, next, count, "received"); - - // Assert the interrupt request and we're done! - SET_RX_IRQ(line); PMIDB(line)->rxpending = FALSE; PMIDB(line)->rxtotal++; - sim_debug(IMP_DBG_IOT, PDEVICE(line), "receive done (message #%d, intreq=%06o)\n", PMIDB(line)->rxtotal, dev_ext_int); -} - -// Receive cross patched data ... -void mi_rx_local (uint16 line, uint16 txnext, uint16 txcount) -{ - // This routine is invoked by the mi_start_tx() function when this modem has - // the "interface cross patch" bit set. This flag causes the modem to talk to - // to itself, and data sent by the transmitter goes directly to the receiver. - // The modem is bypassed completely and in fact need not even be connected. - // This is essentially a special case of the mi_poll_rx() routine and it's a - // shame they don't share more code, but that's the way it is. - // Get the DMC words for this channel, or zeros if no read is pending ... - uint16 rxnext, rxlast, maxbuf; - - // If no read is pending, then just throw away the data ... - if (!PMIDB(line)->rxpending) return; - - // Get the DMC words for the receiver and copy data from one buffer to the other. - mi_get_dmc(PDIB(line)->rxdmc, &rxnext, &rxlast, &maxbuf); - if (txcount > maxbuf) {txcount = maxbuf; PMIDB(line)->rxerror = TRUE;} - memmove(&M[rxnext], &M[txnext], txcount * sizeof(uint16)); - - // Update the receiver DMC pointers, assert IRQ and we're done! - mi_update_dmc(PDIB(line)->rxdmc, txcount); - mi_debug_msg (line, rxnext, txcount, "received"); - SET_RX_IRQ(line); PMIDB(line)->rxpending = FALSE; PMIDB(line)->rxtotal++; - sim_debug(IMP_DBG_IOT, PDEVICE(line), "receive done (message #%d, intreq=%06o)\n", PMIDB(line)->rxtotal, dev_ext_int); -} - - - -//////////////////////////////////////////////////////////////////////////////// -//////////// I / O I N S T R U C T I O N E M U L A T I O N ///////////// -//////////////////////////////////////////////////////////////////////////////// - -// Line specific I/O routines ... -// Unfortunately simh doesn't pass the I/O emulation routine any data about the -// device except for its device address. In particular, it doesn't pass a pointer -// to the device or unit data blocks, so we're on our own to find those. Rather -// than a search on the device address, we just provide a separate I/O routine -// for each modem line. All they do is call the common I/O routine with an extra -// parameter - problem solved! -int32 mi1_io(int32 inst, int32 fnc, int32 dat, int32 dev) {return mi_io(1, inst, fnc, dat, dev);} -int32 mi2_io(int32 inst, int32 fnc, int32 dat, int32 dev) {return mi_io(2, inst, fnc, dat, dev);} -int32 mi3_io(int32 inst, int32 fnc, int32 dat, int32 dev) {return mi_io(3, inst, fnc, dat, dev);} -int32 mi4_io(int32 inst, int32 fnc, int32 dat, int32 dev) {return mi_io(4, inst, fnc, dat, dev);} -int32 mi5_io(int32 inst, int32 fnc, int32 dat, int32 dev) {return mi_io(5, inst, fnc, dat, dev);} - -// Common I/O simulation routine ... -int32 mi_io (uint16 line, int32 inst, int32 fnc, int32 dat, int32 dev) -{ - // This routine is invoked by the CPU module whenever the code executes any - // I/O instruction (OCP, SKS, INA or OTA) with one of our modem's device - // address. - - // OCP (output control pulse) initiates various modem operations ... - if (inst == ioOCP) { - switch (fnc) { - case 000: - // MnOUT - start modem output ... - mi_debug_mio(line, PDIB(line)->txdmc, "output"); - mi_start_tx(line); return dat; - case 001: - // MnUNXP - un-cross patch modem ... - sim_debug(IMP_DBG_IOT,PDEVICE(line),"un-cross patch modem (PC=%06o)\n", PC-1); - PMIDB(line)->iloop = PMIDB(line)->lloop = FALSE; - udp_set_link_loopback (PDEVICE(line), PMIDB(line)->link, FALSE); - return dat; - case 002: - // MnLXP - enable line cross patch ... - sim_debug(IMP_DBG_IOT,PDEVICE(line),"enable line cross patch (PC=%06o)\n", PC-1); - PMIDB(line)->lloop = TRUE; - udp_set_link_loopback (PDEVICE(line), PMIDB(line)->link, TRUE); - PMIDB(line)->iloop = FALSE; return dat; - case 003: - // MnIXP - enable interface cross patch ... - sim_debug(IMP_DBG_IOT,PDEVICE(line),"enable interface cross patch (PC=%06o)\n", PC-1); - PMIDB(line)->iloop = TRUE; PMIDB(line)->lloop = FALSE; - udp_set_link_loopback (PDEVICE(line), PMIDB(line)->link, FALSE); - return dat; - case 004: - // MnIN - start modem input ... - mi_debug_mio(line, PDIB(line)->rxdmc, "input"); - mi_start_rx(line); return dat; - } - - // SKS (skip) tests various modem conditions ... - } else if (inst == ioSKS) { - switch (fnc) { - case 004: - // MnERR - skip on modem error ... - sim_debug(IMP_DBG_IOT,PDEVICE(line),"skip on error (PC=%06o, %s)\n", - PC-1, PMIDB(line)->rxerror ? "SKIP" : "NOSKIP"); - return PMIDB(line)->rxerror ? IOSKIP(dat) : dat; - // NOTE - the following skip, MnRXDONE, isn't actually part of the - // original IMP design. As far as I can tell the IMP had no way to - // explicitly poll this flags; the only way to tell when a modem finished - // was to catch the associated interrupt. I've added one for testing - // purposes, using an unimplemented SKS instruction. - case 002: - // MnRXDONE - skip on receive done ... - return PMIDB(line)->rxpending ? dat : IOSKIP(dat); - } - } - - // Anything else is an error... - sim_debug(IMP_DBG_WARN,PDEVICE(line),"UNIMPLEMENTED I/O (PC=%06o, instruction=%o, function=%02o)\n", PC-1, inst, fnc); - return IOBADFNC(dat); -} - -// Receiver service ... -t_stat mi_rx_service (UNIT *uptr) -{ - // This is the standard simh "service" routine that's called when an event - // queue entry expires. It just polls the receiver and reschedules itself. - // That's it! - uint16 line = uptr->mline; - mi_poll_rx(line); - sim_activate(uptr, uptr->wait); - return SCPE_OK; -} - -// Transmitter service ... -t_stat mi_tx_service (uint32 quantum) -{ - // This is the special transmitter service routine that's called by the RTC - // service every time the RTC is updated. This routine polls ALL the modem - // transmitters (or at least any which are active) and figures out whether it - // is time for an interrupt. - uint32 i; - for (i = 1; i <= MI_NUM; ++i) mi_poll_tx(i, quantum); - return SCPE_OK; -} - - - -//////////////////////////////////////////////////////////////////////////////// -/////////////// D E V I C E A C T I O N C O M M A N D S //////////////// -//////////////////////////////////////////////////////////////////////////////// - -// Reset device ... -t_stat mi_reset (DEVICE *dptr) -{ - // simh calls this routine for the RESET command ... - UNIT *uptr = dptr->units; - uint16 line = uptr->mline; - - // Reset the devices AND clear the interrupt enable bits ... - mi_reset_rx(line); mi_reset_tx(line); - - // If the unit is attached, then make sure we restart polling because some - // simh commands (e.g. boot) dump the pending event queue! - sim_cancel(uptr); - if ((uptr->flags & UNIT_ATT) != 0) sim_activate(uptr, uptr->wait); - return SCPE_OK; -} - -// Attach device ... -t_stat mi_attach (UNIT *uptr, char *cptr) -{ - // simh calls this routine for (what else?) the ATTACH command. There are - // three distinct formats for ATTACH - - // - // ATTACH -p MIn COMnn - attach MIn to a physical COM port - // ATTACH MIn llll:w.x.y.z:rrrr - connect via UDP to a remote simh host - // - t_stat ret; char *pfn; uint16 line = uptr->mline; - t_bool fport = sim_switches & SWMASK('P'); - - // If we're already attached, then detach ... - if ((uptr->flags & UNIT_ATT) != 0) detach_unit(uptr); - - // The physical (COM port) attach isn't implemented yet ... - if (fport) { - fprintf(stderr,"MI%d - physical COM support is not yet implemented\n", line); - return SCPE_ARG; - } - - // Make a copy of the "file name" argument. udp_create() actually modifies - // the string buffer we give it, so we make a copy now so we'll have something - // to display in the "SHOW MIn ..." command. - pfn = (char *) calloc (CBUFSIZE, sizeof (char)); - if (pfn == NULL) return SCPE_MEM; - strncpy (pfn, cptr, CBUFSIZE); - - // Create the UDP connection. - ret = udp_create(PDEVICE(line), cptr, &(PMIDB(line)->link)); - if (ret != SCPE_OK) {free(pfn); return ret;}; - - // Reset the flags and start polling ... - uptr->flags |= UNIT_ATT; uptr->filename = pfn; - return mi_reset(find_dev_from_unit(uptr)); -} - -// Detach device ... -t_stat mi_detach (UNIT *uptr) -{ - // simh calls this routine for (you guessed it!) the DETACH command. This - // disconnects the modem from any UDP connection or COM port and effectively - // makes the modem "off line". A disconnected modem acts like a real modem - // with its phone line unplugged. - t_stat ret; uint16 line = uptr->mline; - if ((uptr->flags & UNIT_ATT) == 0) return SCPE_OK; - ret = udp_release(PDEVICE(line), PMIDB(line)->link); - if (ret != SCPE_OK) return ret; - PMIDB(line)->link = NOLINK; uptr->flags &= ~UNIT_ATT; - free (uptr->filename); uptr->filename = NULL; - return mi_reset(PDEVICE(line)); -} - -t_stat mi_set_loopback (UNIT *uptr, int32 val, char *cptr, void *desc) -{ - t_stat ret = SCPE_OK; uint16 line = uptr->mline; - - switch (val) { - case 0: // LOOPINTERFACE - case 1: // NOLOOPINTERFACE - PMIDB(line)->iloop = (val == 0) ? 1 : 0; - break; - case 2: // LOOPLINE - case 3: // NOLOOPLINE - if (PMIDB(line)->link == NOLINK) - return SCPE_UNATT; - val = (val == 2) ? 1 : 0; - ret = udp_set_link_loopback (PDEVICE(line), PMIDB(line)->link, val); - if (ret == SCPE_OK) - PMIDB(line)->lloop = val; - break; - } - return ret; -} - -t_stat mi_show_loopback (FILE *st, UNIT *uptr, int32 val, void *desc) -{ - uint16 line = uptr->mline; - - if (PMIDB(line)->iloop) - fprintf (st, "Interface (local) Loopback"); - if (PMIDB(line)->lloop) - fprintf (st, "Line (remote) Loopback"); - return SCPE_OK; -} - -#endif // #ifdef VM_IMPTIP from the very top diff --git a/H316/h316_mt.c b/H316/h316_mt.c deleted file mode 100644 index 320a6ab9..00000000 --- a/H316/h316_mt.c +++ /dev/null @@ -1,617 +0,0 @@ -/* h316_mt.c: H316/516 magnetic tape simulator - - Copyright (c) 2003-2012, 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. - - mt 516-4100 seven track magnetic tape - - 03-Jul-13 RLA compatibility changes for extended interrupts - 19-Mar-12 RMS Fixed declaration of chan_req (Mark Pizzolato) - 09-Jun-07 RMS Fixed bug in write without stop (Theo Engel) - 16-Feb-06 RMS Added tape capacity checking - 26-Aug-05 RMS Revised to use API for write lock check - 08-Feb-05 RMS Fixed error reporting from OCP (Philipp Hachtmann) - 01-Dec-04 RMS Fixed bug in DMA/DMC support - - Magnetic tapes are represented as a series of variable records - of the form: - - 32b byte count - byte 0 - byte 1 - : - byte n-2 - byte n-1 - 32b byte count - - If the byte count is odd, the record is padded with an extra byte - of junk. File marks are represented by a byte count of 0. -*/ - -#include "h316_defs.h" -#include "sim_tape.h" - -#define MT_NUMDR 4 /* number of drives */ -#define DB_N_SIZE 16 /* max data buf */ -#define DBSIZE (1 << DB_N_SIZE) /* max data cmd */ -#define FNC u3 /* function */ -#define UST u4 /* unit status */ - -/* Function codes */ - -#define FNC_RBCD2 000 -#define FNC_RBIN2 001 -#define FNC_RBIN3 002 -#define FNC_DMANM 003 -#define FNC_WBCD2 004 -#define FNC_WBIN2 005 -#define FNC_WEOF 006 -#define FNC_IOBUS 007 -#define FNC_WBIN3 010 -#define FNC_FSR 011 -#define FNC_FSF 012 -#define FNC_DMAAU 013 -#define FNC_REW 014 -#define FNC_BSR 015 -#define FNC_BSF 016 -#define FNC_STOPW 017 -#define FNC_2ND 020 /* second state */ -#define FNC_NOP (FNC_STOPW|FNC_2ND) -#define FNC_EOM 040 /* end of motion */ - -/* Status - unit.UST */ - -#define STA_BOT 0000002 /* beg of tape */ -#define STA_EOT 0000001 /* end of tape */ - -extern int32 dev_int, dev_enb; -extern uint32 chan_req; -extern int32 stop_inst; - -uint32 mt_buf = 0; /* data buffer */ -uint32 mt_usel = 0; /* unit select */ -uint32 mt_busy = 0; /* ctlr busy */ -uint32 mt_mdirq = 0; /* motion done int req */ -uint32 mt_rdy = 0; /* transfer ready (int) */ -uint32 mt_err = 0; /* error */ -uint32 mt_eof = 0; /* end of file */ -uint32 mt_eor = 0; /* transfer done */ -uint32 mt_dma = 0; /* DMA/DMC */ -uint32 mt_xtime = 16; /* transfer time */ -uint32 mt_ctime = 3000; /* start/stop time */ -uint32 mt_stopioe = 1; /* stop on I/O error */ -uint8 mtxb[DBSIZE] = { 0 }; /* data buffer */ -t_mtrlnt mt_ptr = 0, mt_max = 0; /* buffer ptrs */ - -int32 mtio (int32 inst, int32 fnc, int32 dat, int32 dev); -void mt_updint (uint32 rdy, uint32 mdone); -t_stat mt_svc (UNIT *uptr); -t_stat mt_reset (DEVICE *dptr); -t_stat mt_attach (UNIT *uptr, char *cptr); -t_stat mt_detach (UNIT *uptr); -t_stat mt_map_err (UNIT *uptr, t_stat st); -void mt_wrwd (UNIT *uptr, uint32 dat); - -/* MT data structures - - mt_dev MT device descriptor - mt_unit MT unit list - mt_reg MT register list - mt_mod MT modifier list -*/ - -DIB mt_dib = { MT, MT_NUMDR, IOBUS, IOBUS, INT_V_MT, INT_V_NONE, &mtio, 0 }; - -UNIT mt_unit[] = { - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) } - }; - -REG mt_reg[] = { - { ORDATA (BUF, mt_buf, 16) }, - { ORDATA (USEL, mt_usel, 2) }, - { FLDATA (BUSY, mt_busy, 0) }, - { FLDATA (RDY, mt_rdy, 0) }, - { FLDATA (ERR, mt_err, 0) }, - { FLDATA (EOF, mt_eof, 0) }, - { FLDATA (EOR, mt_eor, 0) }, - { FLDATA (MDIRQ, mt_mdirq, 0) }, - { FLDATA (DMA, mt_dma, 0) }, - { FLDATA (INTREQ, dev_int, INT_V_MT) }, - { FLDATA (ENABLE, dev_enb, INT_V_MT) }, - { BRDATA (DBUF, mtxb, 8, 8, DBSIZE) }, - { DRDATA (BPTR, mt_ptr, DB_N_SIZE + 1) }, - { DRDATA (BMAX, mt_max, DB_N_SIZE + 1) }, - { DRDATA (CTIME, mt_ctime, 24), REG_NZ + PV_LEFT }, - { DRDATA (XTIME, mt_xtime, 24), REG_NZ + PV_LEFT }, - { URDATA (POS, mt_unit[0].pos, 10, T_ADDR_W, 0, MT_NUMDR, PV_LEFT) }, - { URDATA (FNC, mt_unit[0].FNC, 8, 8, 0, MT_NUMDR, REG_HRO) }, - { URDATA (UST, mt_unit[0].UST, 8, 2, 0, MT_NUMDR, REG_HRO) }, - { ORDATA (CHAN, mt_dib.chan, 5), REG_HRO }, - { FLDATA (STOP_IOE, mt_stopioe, 0) }, - { NULL } - }; - -MTAB mt_mod[] = { - { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, - { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT", - &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, - { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", "CAPACITY", - &sim_tape_set_capac, &sim_tape_show_capac, NULL }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "IOBUS", - &io_set_iobus, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DMC", - &io_set_dmc, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DMA", - &io_set_dma, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "CHANNEL", NULL, - NULL, &io_show_chan, NULL }, - { 0 } - }; - -DEVICE mt_dev = { - "MT", mt_unit, mt_reg, mt_mod, - MT_NUMDR, 10, 31, 1, 8, 8, - NULL, NULL, &mt_reset, - NULL, &mt_attach, &mt_detach, - &mt_dib, DEV_DISABLE - }; - -/* IO routine */ - -int32 mtio (int32 inst, int32 fnc, int32 dat, int32 dev) -{ -uint32 i, u = dev & 03; -UNIT *uptr = mt_dev.units + u; -static uint8 wrt_fnc[16] = { /* >0 = wr, 1 = chan op */ - 0, 0, 0, 0, 1, 1, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0 - }; - -switch (inst) { /* case on opcode */ - - case ioOCP: - mt_updint (mt_rdy, 0); /* clear motion intr */ - mt_eof = 0; /* clear eof */ - switch (fnc) { /* case on function */ - - case FNC_DMANM: /* set DMA/DMC */ - case FNC_DMAAU: - mt_usel = u; /* save unit select */ - if (mt_dib.chan) /* set DMA if configured */ - mt_dma = 1; - else mt_dma = 0; - break; - - case FNC_IOBUS: /* set IOBUS */ - mt_usel = u; /* save unit select */ - mt_dma = 0; - break; - - case FNC_STOPW: /* stop write */ - mt_usel = u; /* save unit select */ - mt_updint (0, mt_mdirq); /* clear ready */ - if (wrt_fnc[uptr->FNC & 017] == 1) /* writing? */ - mt_eor = 1; /* set transfer done */ - break; - - default: /* motion command */ - if (mt_busy) return dat; /* nop if ctlr busy */ - mt_eor = 0; /* clr transfer done */ - mt_err = 0; /* clr error */ - mt_usel = u; /* save unit select */ - if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ - return (((mt_stopioe? SCPE_UNATT: SCPE_OK) << IOT_V_REASON) | dat); - if (sim_is_active (uptr)) /* nop if busy */ - return dat; - if (wrt_fnc[fnc] && sim_tape_wrp (uptr)) - return ((STOP_MTWRP << IOT_V_REASON) | dat); - uptr->FNC = fnc; - uptr->UST = 0; - mt_busy = 1; - for (i = 0; i < MT_NUMDR; i++) /* clear all EOT flags */ - mt_unit[i].UST = mt_unit[i].UST & ~STA_EOT; - sim_activate (uptr, mt_ctime); /* schedule */ - break; - } - break; - - case ioINA: /* INA */ - if (fnc) /* fnc 0 only */ - return IOBADFNC (dat); - if (mt_rdy) { /* ready? */ - mt_rdy = 0; /* clear ready */ - return IOSKIP (dat | mt_buf); /* ret buf, skip */ - } - break; - - case ioOTA: /* OTA */ - if (fnc) /* fnc 0 only */ - return IOBADFNC (dat); - if (mt_rdy) { /* ready? */ - mt_rdy = 0; /* clear ready */ - mt_buf = dat; /* store buf */ - return IOSKIP (dat); /* skip */ - } - break; - - case ioSKS: - uptr = mt_dev.units + mt_usel; /* use saved unit sel */ - switch (fnc) { - - case 000: /* ready */ - if (mt_rdy) - return IOSKIP (dat); - break; - - case 001: /* !busy */ - if (!mt_busy) - return IOSKIP (dat); - break; - - case 002: /* !error */ - if (!mt_err) - return IOSKIP (dat); - break; - - case 003: /* !BOT */ - if (!(uptr->UST & STA_BOT)) - return IOSKIP (dat); - break; - - case 004: /* !interrupting */ - if (!TST_INTREQ (INT_MT)) - return IOSKIP (dat); - break; - - case 005: /* !EOT */ - if (!(uptr->UST & STA_EOT)) - return IOSKIP (dat); - break; - - case 006: /* !EOF */ - if (!mt_eof) - return IOSKIP (dat); - break; - - case 007: /* !write prot */ - if (!sim_tape_wrp (uptr)) - return IOSKIP (dat); - break; - - case 011: /* operational */ - if ((uptr->flags & UNIT_ATT) && ((uptr->FNC & 017) != FNC_REW)) - return IOSKIP (dat); - break; - - case 012: /* skip if !chan 2 */ - return IOSKIP (dat); - - case 013: /* skip if !auto */ - return IOSKIP (dat); - - case 014: /* !rewinding */ - uptr = mt_dev.units + (dev & 03); /* use specified unit */ - if ((uptr->FNC & 017) != FNC_REW) - return IOSKIP (dat); - break; - } - break; - - case ioEND: /* end of range */ - mt_eor = 1; /* transfer done */ - break; - } - -return dat; -} - -/* Unit service - - If rewind done, reposition to start of tape, set status - else, do operation, set done, interrupt - - Can't be write locked, can only write lock detached unit -*/ - -t_stat mt_svc (UNIT *uptr) -{ -int32 ch = mt_dib.chan - 1; /* DMA/DMC ch */ -uint32 i, c1, c2, c3; -t_mtrlnt tbc; -t_bool passed_eot; -t_stat st, r = SCPE_OK; - -if ((uptr->flags & UNIT_ATT) == 0) { /* offline? */ - mt_err = 1; - mt_busy = 0; - mt_updint (0, 1); /* cmd done */ - return IORETURN (mt_stopioe, SCPE_UNATT); - } - -passed_eot = sim_tape_eot (uptr); /* passed EOT? */ -switch (uptr->FNC) { /* case on function */ - - case FNC_REW: /* rewind (initial) */ - mt_busy = 0; /* ctlr not busy */ - uptr->FNC = uptr->FNC | FNC_2ND; - sim_activate (uptr, mt_ctime); - return SCPE_OK; /* continue */ - - case FNC_REW | FNC_2ND: /* rewind done */ - uptr->pos = 0; /* reposition file */ - uptr->UST = STA_BOT; /* set BOT */ - uptr->FNC = FNC_NOP; /* nop function */ - for (i = 0; i < MT_NUMDR; i++) { /* last rewind? */ - if ((mt_unit[i].FNC & 017) == FNC_REW) - return SCPE_OK; - } - mt_updint (mt_rdy, 1); /* yes, motion done */ - return SCPE_OK; - - case FNC_WEOF: /* write file mark */ - if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ - r = mt_map_err (uptr, st); /* map error */ - break; /* sched end motion */ - - case FNC_FSR: /* space fwd rec */ - if ((st = sim_tape_sprecf (uptr, &tbc))) /* space fwd, err? */ - r = mt_map_err (uptr, st); /* map error */ - break; /* sched end motion */ - - case FNC_BSR: /* space rev rec */ - if ((st = sim_tape_sprecr (uptr, &tbc))) /* space rev, err? */ - r = mt_map_err (uptr, st); /* map error */ - break; /* sched end motion */ - - case FNC_FSF: /* space fwd file */ - while ((st = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ; - r = mt_map_err (uptr, st); /* map error */ - break; /* sched end motion */ - - case FNC_BSF: /* space rev file */ - while ((st = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ; - r = mt_map_err (uptr, st); /* map error */ - break; /* sched end motion */ - - case FNC_EOM: /* end of motion */ - uptr->FNC = FNC_NOP; /* nop function */ - mt_busy = 0; /* not busy */ - mt_updint (mt_rdy, 1); /* end of motion */ - return SCPE_OK; /* done! */ - - case FNC_RBCD2: case FNC_RBIN2: case FNC_RBIN3: /* read first */ - mt_ptr = 0; /* clr buf ptr */ - st = sim_tape_rdrecf (uptr, mtxb, &mt_max, DBSIZE); /* read rec */ - if (st != MTSE_OK) { /* error? */ - r = mt_map_err (uptr, st); /* map error */ - break; /* sched end motion */ - } - uptr->FNC = uptr->FNC | FNC_2ND; /* next state */ - sim_activate (uptr, mt_xtime); /* sched xfer */ - return SCPE_OK; - - case FNC_RBCD2 | FNC_2ND: /* read, word */ - case FNC_RBIN2 | FNC_2ND: - case FNC_RBIN3 | FNC_2ND: - if (mt_ptr >= mt_max) /* record done? */ - break; - c1 = mtxb[mt_ptr++] & 077; /* get 2 chars */ - c2 = mtxb[mt_ptr++] & 077; - if (uptr->FNC == (FNC_RBCD2 | FNC_2ND)) { /* BCD? */ - if (c1 == 012) c1 = 0; /* change 12 to 0 */ - if (c2 == 012) c2 = 0; - } - if (uptr->FNC == (FNC_RBIN3 | FNC_2ND)) { /* read 3? */ - if (mt_ptr >= mt_max) break; /* lose wd if not enuf */ - c3 = mtxb[mt_ptr++] & 017; /* get 3rd char */ - } - else c3 = 0; - sim_activate (uptr, mt_xtime); /* no, sched word */ - if (mt_eor) /* xfer done? */ - return SCPE_OK; - mt_buf = (c1 << 10) | (c2 << 4) | c3; /* pack chars */ - if (mt_rdy) mt_err = 1; /* buf full? err */ - mt_updint (1, mt_mdirq); /* set ready */ - if (mt_dma) /* DMC/DMA? req chan */ - SET_CH_REQ (ch); - return SCPE_OK; /* continue */ - - case FNC_WBCD2: case FNC_WBIN2: case FNC_WBIN3: /* write first */ - mt_ptr = 0; /* clear buf ptr */ - mt_updint (1, mt_mdirq); /* set ready */ - if (mt_dma) /* DMC/DMA? req chan */ - SET_CH_REQ (ch); - uptr->FNC = uptr->FNC | FNC_2ND; /* next state */ - sim_activate (uptr, mt_xtime); /* sched xfer */ - return SCPE_OK; /* continue */ - - case FNC_WBCD2 | FNC_2ND: /* write, word */ - case FNC_WBIN2 | FNC_2ND: - case FNC_WBIN3 | FNC_2ND: - if (mt_eor || mt_rdy) { /* done or no data? */ - if (!mt_rdy) /* write last word */ - mt_wrwd (uptr, mt_buf); - else mt_rdy = 0; /* rdy must be clr */ - if (mt_ptr) { /* any data? */ - if ((st = sim_tape_wrrecf (uptr, mtxb, mt_ptr)))/* write, err? */ - r = mt_map_err (uptr, st); /* map error */ - } - break; /* sched end motion */ - } - mt_wrwd (uptr, mt_buf); /* write word */ - sim_activate (uptr, mt_xtime); /* no, sched word */ - mt_updint (1, mt_mdirq); /* set ready */ - if (mt_dma) /* DMC/DMA? req chan */ - SET_CH_REQ (ch); - return SCPE_OK; /* continue */ - - default: /* unknown */ - break; - } - -/* End of command, process error or schedule end of motion */ - -if (!passed_eot && sim_tape_eot (uptr)) /* just passed EOT? */ - uptr->UST = uptr->UST | STA_EOT; -if (r != SCPE_OK) { - uptr->FNC = FNC_NOP; /* nop function */ - mt_busy = 0; /* not busy */ - mt_updint (mt_rdy, 1); /* end of motion */ - return r; - } -uptr->FNC = FNC_EOM; /* sched end motion */ -sim_activate (uptr, mt_ctime); -return SCPE_OK; -} - -/* Write word to buffer */ - -void mt_wrwd (UNIT *uptr, uint32 dat) -{ -uint32 c1, c2; - -c1 = (dat >> 10) & 077; /* get 2 chars */ -c2 = (dat >> 4) & 077; -if (uptr->FNC == (FNC_WBCD2 | FNC_2ND)) { /* BCD? */ - if (c1 == 0) - c1 = 012; /* change 0 to 12 */ - if (c2 == 0) - c2 = 012; - } -if (mt_ptr < DBSIZE) /* store 2 char */ - mtxb[mt_ptr++] = c1; -if (mt_ptr < DBSIZE) - mtxb[mt_ptr++] = c2; -if ((uptr->FNC == (FNC_WBIN3 | FNC_2ND)) && /* write 3? */ - (mt_ptr < DBSIZE)) - mtxb[mt_ptr++] = mt_buf & 017; -return; -} - -/* Map tape error status */ - -t_stat mt_map_err (UNIT *uptr, t_stat st) -{ -switch (st) { - - case MTSE_FMT: /* illegal fmt */ - case MTSE_UNATT: /* unattached */ - mt_err = 1; /* reject */ - case MTSE_OK: /* no error */ - return SCPE_IERR; /* never get here! */ - - case MTSE_TMK: /* end of file */ - mt_eof = 1; /* eof */ - break; - - case MTSE_INVRL: /* invalid rec lnt */ - mt_err = 1; - return SCPE_MTRLNT; - - case MTSE_IOERR: /* IO error */ - mt_err = 1; /* error */ - if (mt_stopioe) - return SCPE_IOERR; - break; - - case MTSE_RECE: /* record in error */ - case MTSE_EOM: /* end of medium */ - mt_err = 1; /* error */ - break; - - case MTSE_BOT: /* reverse into BOT */ - uptr->UST = STA_BOT; /* set status */ - break; - - case MTSE_WRP: /* write protect */ - mt_err = 1; /* error */ - return STOP_MTWRP; - } - -return SCPE_OK; -} - -/* Update interrupts */ - -void mt_updint (uint32 rdy, uint32 mdirq) -{ -mt_rdy = rdy; /* store new ready */ -mt_mdirq = mdirq; /* store new motion irq */ -if ((mt_rdy && !mt_dma) || mt_mdirq) /* update int request */ - SET_INT (INT_MT); -else CLR_INT (INT_MT); -return; -} - -/* Reset routine */ - -t_stat mt_reset (DEVICE *dptr) -{ -int32 i; -UNIT *uptr; - -mt_buf = 0; /* clear state */ -mt_usel = 0; -mt_mdirq = 0; -mt_eor = 0; -mt_busy = 0; -mt_rdy = 0; -mt_eof = 0; -mt_err = 0; -mt_dma = 0; -CLR_INT (INT_MT); /* clear int, enb */ -CLR_ENB (INT_MT); -for (i = 0; i < MT_NUMDR; i++) { /* loop thru units */ - uptr = mt_dev.units + i; - sim_tape_reset (uptr); /* reset tape */ - sim_cancel (uptr); /* cancel op */ - uptr->UST = uptr->pos? 0: STA_BOT; /* update status */ - uptr->FNC = FNC_NOP; - } -return SCPE_OK; -} - -/* Attach routine */ - -t_stat mt_attach (UNIT *uptr, char *cptr) -{ -t_stat r; - -r = sim_tape_attach (uptr, cptr); /* attach unit */ -if (r != SCPE_OK) /* update status */ - return r; -uptr->UST = STA_BOT; -return r; -} - -/* Detach routine */ - -t_stat mt_detach (UNIT* uptr) -{ -uptr->UST = 0; /* update status */ -uptr->FNC = FNC_NOP; /* nop function */ -return sim_tape_detach (uptr); /* detach unit */ -} diff --git a/H316/h316_rtc.c b/H316/h316_rtc.c deleted file mode 100644 index 91916ba9..00000000 --- a/H316/h316_rtc.c +++ /dev/null @@ -1,384 +0,0 @@ -/* h316_rtc.c- BBN ARPAnet IMP/TIP Real Time Clock and Watch Dog Timer - Based on the SIMH simulator package written by Robert M Supnik. - - Copyright (c) 2013 Robert Armstrong, bob@jfcl.com. - - 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 ARMSTRONG 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 Armstrong 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 Armstrong. - - rtc real time clock - wdt watch dog timer - - 21-May-13 RLA New file - - OVERVIEW - - The IMP and TIP used a custom real time clock that was apparently created - by BBN just for those devices. The IMP/TIP RTC is NOT the same as the - official Honeywell real time clock option, H316-12. When emulating an IMP - or TIP, this RTC device must be enabled and the standard simh H316 CLK - device must be disabled. - - The IMP and TIP also had a watch dog timer which, if ever allowed to time - out, would cause a non-maskable interrupt via location 62(8) - this is the - same trap location used by the memory lockout option, which the IMP/TIP - lacked. Not much is known about the WDT, and the current implementation is - simply a place holder that doesn't do much. - - RTC state is maintained in a set of state variables: - - ENA RTC is enabled - COUNT current count - IEN RTC interrupt enabled - IRQ RTC interrupt pending - TPS effective ticks per second - WAIT simulator time until the next tick - - WDT state is maintained in a set of state variables: - - COUNT current countdown - TMO WDT timed out - LIGHTS last "set status lights" - WAIT simulator time until the next tick - - TODO - - Implement the WDT!! -*/ -#ifdef VM_IMPTIP -#include "h316_defs.h" // H316 emulator definitions -#include "h316_imp.h" // ARPAnet IMP/TIP definitions - -// Locals ... -uint32 rtc_interval = RTC_INTERVAL; // RTC tick interval (in microseconds) -uint32 rtc_quantum = RTC_QUANTUM; // RTC update interval (in ticks) -uint32 rtc_tps = 1000000UL / (RTC_INTERVAL * RTC_QUANTUM); -uint16 rtc_enabled = 1; // RTC enabled -uint32 rtc_count = 0; // current RTC count -uint32 wdt_delay = WDT_DELAY; // WDT timeout (in milliseconds, 0=none) -uint32 wdt_count = 0; // current WDT countdown -uint16 wdt_lights = 0; // last "set status lights" output - -// Externals from other parts of simh ... -extern uint16 dev_ext_int, dev_ext_enb; // current IRQ and IEN bit vectors -extern int32 PC; // current PC (for debug messages) -extern int32 stop_inst; // needed by IOBADFNC() - -// Forward declarations ... -int32 rtc_io (int32 inst, int32 fnc, int32 dat, int32 dev); -t_stat rtc_service (UNIT *uptr); -t_stat rtc_reset (DEVICE *dptr); -int32 wdt_io (int32 inst, int32 fnc, int32 dat, int32 dev); -t_stat wdt_service (UNIT *uptr); -t_stat wdt_reset (DEVICE *dptr); -t_stat rtc_set_interval (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat rtc_show_interval (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat rtc_set_quantum(UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat rtc_show_quantum (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat wdt_set_delay (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat wdt_show_delay (FILE *st, UNIT *uptr, int32 val, void *desc); - - - -//////////////////////////////////////////////////////////////////////////////// -////////////////// R T C D A T A S T R U C T U R E S ////////////////// -//////////////////////////////////////////////////////////////////////////////// - -// RTC device information block ... -DIB rtc_dib = { RTC, 1, IOBUS, IOBUS, INT_V_RTC, INT_V_NONE, &rtc_io, 0 }; - -// RTC unit data block (we have only one unit!) ... -UNIT rtc_unit = { UDATA (&rtc_service, 0, 0), (RTC_INTERVAL*RTC_QUANTUM) }; - -// RTC device registers (for "EXAMINE RTC STATE") ... -REG rtc_reg[] = { - { FLDATA (ENA, rtc_enabled, 0) }, - { DRDATA (COUNT, rtc_count, 16), PV_LEFT }, - { FLDATA (IEN, dev_ext_enb, INT_V_RTC-INT_V_EXTD) }, - { FLDATA (IRQ, dev_ext_int, INT_V_RTC-INT_V_EXTD) }, - { DRDATA (TPS, rtc_tps, 32), PV_LEFT }, - { DRDATA (WAIT, rtc_unit.wait, 24), REG_NZ + PV_LEFT }, - { NULL } -}; - -// RTC device modifiers (for "SET/SHOW RTC xxx") ... -MTAB rtc_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "INTERVAL", "INTERVAL", &rtc_set_interval, &rtc_show_interval, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "QUANTUM", "QUANTUM", &rtc_set_quantum, &rtc_show_quantum, NULL }, - { 0 } -}; - -// RTC debugging flags (for "SET RTC DEBUG=xxx") ... -DEBTAB rtc_debug[] = { - {"WARN", IMP_DBG_WARN}, - {"IO", IMP_DBG_IOT}, - {0} -}; - -// And finally tie it all together ... -DEVICE rtc_dev = { - "RTC", &rtc_unit, rtc_reg, rtc_mod, - 1, 0, 0, 0, 0, 0, - NULL, NULL, &rtc_reset, NULL, NULL, NULL, - &rtc_dib, DEV_DIS|DEV_DISABLE|DEV_DEBUG, 0, rtc_debug, NULL, NULL -}; - - - -//////////////////////////////////////////////////////////////////////////////// -////////////////// W D T D A T A S T R U C T U R E S ////////////////// -//////////////////////////////////////////////////////////////////////////////// - -// WDT device information block ... -DIB wdt_dib = { WDT, 1, IOBUS, IOBUS, INT_V_NONE, INT_V_NONE, &wdt_io, 0 }; - -// WDT unit data block (it has only one) ... -UNIT wdt_unit = { UDATA (&wdt_service, 0, 0), 1000 }; - -// WDT device registers (for "EXAMINE WDT STATE") ... -REG wdt_reg[] = { - { DRDATA (COUNT, wdt_count, 16), PV_LEFT }, - { DRDATA (WAIT, wdt_unit.wait, 24), REG_NZ | PV_LEFT }, - { ORDATA (LIGHTS, wdt_lights, 16), REG_RO | PV_LEFT }, - { NULL } -}; - -// WDT device modifiers (for "SET/SHOW WDT xxx") ... -MTAB wdt_mod[] = { - { MTAB_XTD | MTAB_VDV, 0, "DELAY", "DELAY", &wdt_set_delay, &wdt_show_delay, NULL }, - { 0 } -}; - -// WDT debugging flags (for "SET WDT DEBUG=xxx") ... -DEBTAB wdt_debug[] = { - {"WARN", IMP_DBG_WARN}, - {"IO", IMP_DBG_IOT}, - {"LIGHTS", WDT_DBG_LIGHTS}, - {0} -}; - -// And summarize ... -DEVICE wdt_dev = { - "WDT", &wdt_unit, wdt_reg, wdt_mod, - 1, 0, 0, 0, 0, 0, - NULL, NULL, &wdt_reset, NULL, NULL, NULL, - &wdt_dib, DEV_DIS|DEV_DISABLE|DEV_DEBUG, 0, wdt_debug, NULL, NULL -}; - - - -//////////////////////////////////////////////////////////////////////////////// -////////// R T C I / O A N D S E R V I C E R O U T I N E S ////////// -//////////////////////////////////////////////////////////////////////////////// - -// Set and clear the RTC IRQ and IEN ... -#define SET_RTC_IRQ() SET_EXT_INT((1u << (rtc_dib.inum - INT_V_EXTD))) -#define CLR_RTC_IRQ() CLR_EXT_INT((1u << (rtc_dib.inum - INT_V_EXTD))) -#define CLR_RTC_IEN() CLR_EXT_ENB((1u << (rtc_dib.inum - INT_V_EXTD))) - -// RTC IO routine ... -int32 rtc_io (int32 inst, int32 fnc, int32 dat, int32 dev) -{ - switch (inst) { - case ioOCP: - if (fnc == 010) { - // CLKOFF - turn the RTC off ... - sim_cancel(&rtc_unit); rtc_enabled = 0; CLR_RTC_IRQ(); - sim_debug(IMP_DBG_IOT, &rtc_dev, "disabled (PC=%06o)\n", PC-1); - return dat; - } else if (fnc == 000) { - // CLKON - turn the RTC on ... - rtc_enabled = 1; CLR_RTC_IRQ(); - if (sim_is_active(&rtc_unit) == 0) - sim_activate (&rtc_unit, sim_rtc_init (rtc_unit.wait)); - sim_debug(IMP_DBG_IOT, &rtc_dev, "enabled (PC=%06o)\n", PC-1); - return dat; - } - break; - - case ioINA: - if ((fnc == 010) || (fnc == 000)) { - // RDCLOK - return the current count - sim_debug(IMP_DBG_IOT, &rtc_dev, "read clock (PC=%06o, RTC=%06o)\n", PC-1, (rtc_count & DMASK)); - return IOSKIP((rtc_count & DMASK)); - } - break; - } - - sim_debug(IMP_DBG_WARN, &rtc_dev, "UNIMPLEMENTED I/O (PC=%06o, instruction=%o, function=%02o)\n", PC-1, inst, fnc); - return IOBADFNC(dat); -} - -// RTC unit service ... -t_stat rtc_service (UNIT *uptr) -{ - // Add the current quantum to the clock register and, if the clock register - // has overflowed, request an interrupt. The real hardware interrupts when - // there is a carry out of the low byte (in other words, every 256 clocks). - // Note that we can't simply check the low byte for zero to detect overflows - // because of the quantum. Since we aren't necessarily incrementing by 1, we - // may never see a value of exactly zero. We'll have to be more clever. - uint8 rtc_high = HIBYTE(rtc_count); - rtc_count = (rtc_count + rtc_quantum) & DMASK; - if (HIBYTE(rtc_count) != rtc_high) { - sim_debug(IMP_DBG_IOT, &rtc_dev, "interrupt request\n"); - SET_RTC_IRQ(); - } - mi_tx_service(rtc_quantum); - uptr->wait = sim_rtc_calb (rtc_tps); /* recalibrate */ - sim_activate_after (uptr, 1000000/rtc_tps); /* reactivate unit */ - return SCPE_OK; -} - - - -//////////////////////////////////////////////////////////////////////////////// -////////// W D T I / O A N D S E R V I C E R O U T I N E S ////////// -//////////////////////////////////////////////////////////////////////////////// - -// WDT IO routine ... -int32 wdt_io (int32 inst, int32 fnc, int32 dat, int32 dev) -{ - if ((inst == ioOCP) && (fnc == 0)) { - // Reset WDT ... - sim_debug(IMP_DBG_IOT, &wdt_dev, "reset (PC=%06o)\n", PC-1); - return dat; - } else if ((inst == ioOTA) && (fnc == 0)) { - // Set status lights ... - if (wdt_lights != dat) { - sim_debug(WDT_DBG_LIGHTS, &wdt_dev, "changed to %06o\n", dat); - } - sim_debug(IMP_DBG_IOT, &wdt_dev, "set status lights (PC=%06o, LIGHTS=%06o)\n", PC-1, dat); - wdt_lights = dat; return dat; - } - - sim_debug(IMP_DBG_WARN, &wdt_dev, "UNIMPLEMENTED I/O (PC=%06o, instruction=%o, function=%02o)\n", PC-1, inst, fnc); - return IOBADFNC(dat); -} - -// WDT unit service ... -t_stat wdt_service (UNIT *uptr) -{ - return SCPE_OK; -} - - - -//////////////////////////////////////////////////////////////////////////////// -/////////////// D E V I C E A C T I O N C O M M A N D S //////////////// -//////////////////////////////////////////////////////////////////////////////// - -// RTC reset routine ... -t_stat rtc_reset (DEVICE *dptr) -{ - // Clear the interrupt enable and any pending interrupts, reset the count - // and enable the clock. At least I assume that's what a reset does - the - // docs aren't too specific on this point... - rtc_enabled = 1; rtc_count = 0; - CLR_RTC_IRQ(); CLR_RTC_IEN(); - sim_cancel (&rtc_unit); - sim_register_clock_unit ((dptr->flags & DEV_DIS) ? NULL : &rtc_unit); - return SCPE_OK; -} - -// WDT reset routine ... -t_stat wdt_reset (DEVICE *dptr) -{ - // Clear the WDT countdown and turn off all the lights ... - wdt_count = 0; wdt_lights = 0; - sim_cancel (&wdt_unit); - return SCPE_OK; -} - - - -//////////////////////////////////////////////////////////////////////////////// -///////// D E V I C E S E T A N D S H O W C O M M A N D S ////////// -//////////////////////////////////////////////////////////////////////////////// - -// Set/Show RTC interval ... -t_stat rtc_set_interval (UNIT *uptr, int32 val, char *cptr, void *desc) -{ - uint32 newint, newtps; t_stat ret; - if (cptr == NULL) return SCPE_ARG; - newint = get_uint (cptr, 10, 1000000, &ret); - if (ret != SCPE_OK) return ret; - if (newint == 0) return SCPE_ARG; - newtps = 1000000UL / (newint * rtc_quantum); - if ((newtps == 0) || (newtps >= 100000)) return SCPE_ARG; - rtc_interval = newint; rtc_tps = newtps; - uptr->wait = sim_rtc_calb (rtc_tps); - return SCPE_OK; -} - -t_stat rtc_show_interval (FILE *st, UNIT *uptr, int32 val, void *desc) -{ - fprintf(st,"interval=%d (us)", rtc_interval); - return SCPE_OK; -} - -// Set/Show RTC quantum ... -t_stat rtc_set_quantum (UNIT *uptr, int32 val, char *cptr, void *desc) -{ - uint32 newquant, newtps; t_stat ret; - if (cptr == NULL) return SCPE_ARG; - newquant = get_uint (cptr, 10, 1000000, &ret); - if (ret != SCPE_OK) return ret; - if (newquant == 0) return SCPE_ARG; - newtps = 1000000UL / (rtc_interval * newquant); - if ((newtps == 0) || (newtps >= 100000)) return SCPE_ARG; - rtc_quantum = newquant; rtc_tps = newtps; - uptr->wait = sim_rtc_calb (rtc_tps); - return SCPE_OK; -} - -t_stat rtc_show_quantum (FILE *st, UNIT *uptr, int32 val, void *desc) -{ - fprintf(st,"quantum=%d (ticks)", rtc_quantum); - return SCPE_OK; -} - -// Set/Show WDT delay ... -t_stat wdt_set_delay (UNIT *uptr, int32 val, char *cptr, void *desc) -{ - uint32 newint; t_stat ret; - if (cptr == NULL) return SCPE_ARG; - newint = get_uint (cptr, 10, 65535, &ret); - if (ret != SCPE_OK) return ret; - if (newint != 0) { - fprintf(stderr,"WDT - timeout not yet implemented\n"); - return SCPE_IERR; - } - wdt_delay = newint; -// TBA add calculations here??? - return SCPE_OK; -} - -t_stat wdt_show_delay (FILE *st, UNIT *uptr, int32 val, void *desc) -{ - if (wdt_delay > 0) - fprintf(st,"delay=%d (ms)", wdt_delay); - else - fprintf(st,"no timeout"); - return SCPE_OK; -} - -#endif // #ifdef VM_IMPTIP from the very top diff --git a/H316/h316_stddev.c b/H316/h316_stddev.c deleted file mode 100644 index 448f076e..00000000 --- a/H316/h316_stddev.c +++ /dev/null @@ -1,965 +0,0 @@ -/* h316_stddev.c: Honeywell 316/516 standard devices - - Copyright (c) 1999-2015, Robert M. Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - ptr 316/516-50 paper tape reader - ptp 316/516-52 paper tape punch - tty 316/516-33 teleprinter - clk/options 316/516-12 real time clocks/internal options - - 10-Sep-13 RMS Fixed several bugs in the TTY logic - Added SET file type commands to PTR/PTP - 03-Jul-13 RLA compatibility changes for extended interrupts - 23-May-13 RLA Move the SMK/OTK to h316_cpu (where it belongs!) - Allow the CLK device to be disabled - 09-Jun-07 RMS Fixed bug in clock increment (Theo Engel) - 30-Sep-06 RMS Fixed handling of non-printable characters in KSR mode - 03-Apr-06 RMS Fixed bugs in punch state handling (Theo Engel) - 22-Nov-05 RMS Revised for new terminal processing routines - 05-Feb-05 RMS Fixed bug in OCP '0001 (Philipp Hachtmann) - 31-Jan-05 RMS Fixed bug in TTY print (Philipp Hachtmann) - 01-Dec-04 RMS Fixed problem in SKS '104 (Philipp Hachtmann) - Fixed bug in SKS '504 - Added PTR detach routine, stops motion - Added PTR/PTP ASCII file support - Added TTR/TTP support - 24-Oct-03 RMS Added DMA/DMC support - 25-Apr-03 RMS Revised for extended file support - 01-Mar-03 RMS Added SET/SHOW CLK FREQ support - 22-Dec-02 RMS Added break support - 01-Nov-02 RMS Added 7b/8b support to terminal - 30-May-02 RMS Widened POS to 32b - 03-Nov-01 RMS Implemented upper case for console output - 29-Nov-01 RMS Added read only unit support - 07-Sep-01 RMS Moved function prototypes - - The ASR-33/35 reader/punch logic, and the ASCII file support for all paper tape - devices, is taken, with grateful thanks, from Adrian Wise's H316 emulator. - - Teletype transitions: - - - An OCP '1 starts an output sequence, unconditionally. Ready and Busy are both - set, and a dummy output sequence is started. - - If OTA "overtakes" the dummy output sequence, the dummy sequence is stopped, - and normal output takes place. - - If OTA is not issued before the dummy sequence completes, Busy is cleared. - Because Ready is set, an interrupt is requested. - - An OCP '0 starts an input sequence, unconditionally. Ready and Busy are both - cleared. - - When a character is available (either from the keyboard or the reader), Busy - is set. - - At the end of a delay, Busy is cleared and Ready is set, and an interrupt is - requested. - - At all times, the interrupt flag reflects the equation Ready & ~Busy. - - Teletype reader transitions: - - - SET TTY2 START puts the reader in RUN. - - XOFF from keyboard/reader stops the reader after 1-2 more characters are read. - - XON from program starts the reader. - - Detach, SET TTY2 STOP, or end of file stops the reader. - - Teletype punch transitions: - - - SET TTY3 START puts the punch in RUN. - - XOFF from program stops the punch after 1 more character is punched. - - TAPE from program starts the punch after 1 character delay. - - Detach or SET TTY3 STOP stops the punch. -*/ - -#include "h316_defs.h" -#include - -#define UNIT_V_ASC (TTUF_V_UF + 0) /* ASCII */ -#define UNIT_V_UASC (TTUF_V_UF + 1) /* Unix ASCII */ -#define UNIT_ASC (1 << UNIT_V_ASC) -#define UNIT_UASC (1 << UNIT_V_UASC) -#define STA u3 /* state bits */ -#define LF_PEND 01 /* lf pending */ -#define RUNNING 02 /* tape running */ - -#define XON 0021 -#define TAPE 0022 -#define XOFF 0023 -#define RUBOUT 0377 - -extern uint16 M[]; -extern int32 PC; -extern int32 stop_inst; -extern int32 C, dp, ext, extoff_pending, sc; -extern int32 dev_int, dev_enb; -extern UNIT cpu_unit; - -uint32 ptr_motion = 0; /* read motion */ -uint32 ptr_stopioe = 0; /* stop on error */ -uint32 ptp_stopioe = 0; -uint32 ptp_power = 0; /* punch power, time */ -int32 ptp_ptime; -uint32 ttr_stopioe = 0; -uint32 tty_mode = 0; /* input (0), output (1) */ -uint32 tty_buf = 0; /* tty buffer */ -uint32 tty_ready = 1; /* tty ready */ -uint32 tty_busy = 0; /* tty busy */ -uint32 tty_2nd = 0; /* tty input second state */ -uint32 ttr_xoff_read = 0; -uint32 ttp_tape_rcvd = 0; -uint32 ttp_xoff_rcvd = 0; -int32 tty_busy_wait = SERIAL_IN_WAIT; /* busy state on input */ -int32 clk_tps = 60; /* ticks per second */ - -int32 ptrio (int32 inst, int32 fnc, int32 dat, int32 dev); -t_stat ptr_svc (UNIT *uptr); -t_stat ptr_reset (DEVICE *dptr); -t_stat ptr_boot (int32 unitno, DEVICE *dptr); -int32 ptpio (int32 inst, int32 fnc, int32 dat, int32 dev); -t_stat ptp_svc (UNIT *uptr); -t_stat ptp_reset (DEVICE *dptr); -int32 ttyio (int32 inst, int32 fnc, int32 dat, int32 dev); -t_stat tti_svc (UNIT *uptr); -t_stat tto_svc (UNIT *uptr); -t_stat tty_reset (DEVICE *dptr); -t_stat ttio_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat ttrp_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat ttrp_set_start_stop (UNIT *uptr, int32 val, char *cptr, void *desc); -int32 clkio (int32 inst, int32 fnc, int32 dat, int32 dev); -t_stat clk_svc (UNIT *uptr); -t_stat clk_reset (DEVICE *dptr); -t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat pt_attach (UNIT *uptr, char *cptr); -t_stat pt_detach (UNIT *uptr); -t_stat tto_write (int32 c); -t_stat ttp_write (int32 c); - -/* PTR data structures - - ptr_dev PTR device descriptor - ptr_unit PTR unit descriptor - ptr_mod PTR modifiers - ptr_reg PTR register list -*/ - -DIB ptr_dib = { PTR, 1, IOBUS, IOBUS, INT_V_PTR, INT_V_NONE, &ptrio, 0 }; - -UNIT ptr_unit = { - UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), - SERIAL_IN_WAIT - }; - -REG ptr_reg[] = { - { ORDATA (BUF, ptr_unit.buf, 8) }, - { FLDATA (READY, dev_int, INT_V_PTR) }, - { FLDATA (ENABLE, dev_enb, INT_V_PTR) }, - { FLDATA (MOTION, ptr_motion, 0) }, - { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, - { ORDATA (RSTATE, ptr_unit.STA, 2), REG_HIDDEN }, - { FLDATA (STOP_IOE, ptr_stopioe, 0) }, - { NULL } - }; - -MTAB pt_mod[] = { - { UNIT_ATTABLE+UNIT_ASC+UNIT_UASC, UNIT_ATTABLE, NULL, "BINARY", - &ttrp_set_mode }, - { UNIT_ATTABLE+UNIT_ASC+UNIT_UASC, UNIT_ATTABLE+UNIT_ASC, "ASCII", "ASCII", - &ttrp_set_mode }, - { UNIT_ATTABLE+UNIT_ASC+UNIT_UASC, UNIT_ATTABLE+UNIT_ASC+UNIT_UASC, "Unix ASCII", "UASCII", - &ttrp_set_mode }, - { 0 } - }; - -DEVICE ptr_dev = { - "PTR", &ptr_unit, ptr_reg, pt_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ptr_reset, - &ptr_boot, &pt_attach, &pt_detach, - &ptr_dib, 0 - }; - -/* PTP data structures - - ptp_dev PTP device descriptor - ptp_unit PTP unit descriptor - ptp_mod PTP modifiers - ptp_reg PTP register list -*/ - -DIB ptp_dib = { PTP, 1, IOBUS, IOBUS, INT_V_PTP, INT_V_NONE, &ptpio, 0 }; - -UNIT ptp_unit = { - UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT - }; - -REG ptp_reg[] = { - { ORDATA (BUF, ptp_unit.buf, 8) }, - { FLDATA (READY, dev_int, INT_V_PTP) }, - { FLDATA (ENABLE, dev_enb, INT_V_PTP) }, - { FLDATA (POWER, ptp_power, 0) }, - { DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT }, - { ORDATA (PSTATE, ptp_unit.STA, 2), REG_HIDDEN }, - { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, - { DRDATA (PWRTIME, ptp_ptime, 24), PV_LEFT }, - { FLDATA (STOP_IOE, ptp_stopioe, 0) }, - { NULL } - }; - -DEVICE ptp_dev = { - "PTP", &ptp_unit, ptp_reg, pt_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ptp_reset, - NULL, &pt_attach, NULL, - &ptp_dib, 0 - }; - -/* TTY data structures - - tty_dev TTY device descriptor - tty_unit TTY unit descriptor - tty_reg TTY register list - tty_mod TTy modifiers list -*/ - -#define TTI 0 -#define TTO 1 -#define TTR 2 -#define TTP 3 - -DIB tty_dib = { TTY, 1, IOBUS, IOBUS, INT_V_TTY, INT_V_NONE, &ttyio, 0 }; - -UNIT tty_unit[] = { - { UDATA (&tti_svc, TT_MODE_KSR, 0), KBD_POLL_WAIT }, - { UDATA (&tto_svc, TT_MODE_KSR, 0), SERIAL_OUT_WAIT }, - { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0) }, - { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) } - }; - -REG tty_reg[] = { - { ORDATA (BUF, tty_buf, 8) }, - { ORDATA (IN2ND, tty_2nd, 9) }, - { FLDATA (MODE, tty_mode, 0) }, - { FLDATA (READY, tty_ready, 0) }, - { FLDATA (BUSY, tty_busy, 0) }, - { FLDATA (INT, dev_int, INT_V_TTY) }, - { FLDATA (ENABLE, dev_enb, INT_V_TTY) }, - { DRDATA (KPOS, tty_unit[TTI].pos, T_ADDR_W), PV_LEFT }, - { DRDATA (KTIME, tty_unit[TTI].wait, 24), REG_NZ + PV_LEFT }, - { DRDATA (KBTIME, tty_busy_wait, 24), REG_NZ + PV_LEFT }, - { DRDATA (TPOS, tty_unit[TTO].pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TTIME, tty_unit[TTO].wait, 24), REG_NZ + PV_LEFT }, - { ORDATA (RXOFF, ttr_xoff_read, 2), REG_HIDDEN }, - { ORDATA (RSTATE, tty_unit[TTR].STA, 2), REG_HIDDEN }, - { DRDATA (RPOS, tty_unit[TTR].pos, T_ADDR_W), PV_LEFT }, - { ORDATA (PTAPE, ttp_tape_rcvd, 2), REG_HIDDEN }, - { ORDATA (PXOFF, ttp_xoff_rcvd, 2), REG_HIDDEN }, - { ORDATA (PSTATE, tty_unit[TTP].STA, 2), REG_HIDDEN }, - { DRDATA (PPOS, tty_unit[TTP].pos, T_ADDR_W), PV_LEFT }, - { FLDATA (STOP_IOE, ttr_stopioe, 0) }, - { NULL } - }; - -MTAB tty_mod[] = { - { TT_MODE, TT_MODE_KSR, "KSR", "KSR", &ttio_set_mode }, - { TT_MODE, TT_MODE_7B, "7b", "7B", &ttio_set_mode }, - { TT_MODE, TT_MODE_8B, "8b", "8B", &ttio_set_mode }, - { TT_MODE, TT_MODE_7P, "7p", "7P", &ttio_set_mode }, - { UNIT_ATTABLE+UNIT_ASC+UNIT_UASC, UNIT_ATTABLE, NULL, "BINARY", - &ttrp_set_mode }, - { UNIT_ATTABLE+UNIT_ASC+UNIT_UASC, UNIT_ATTABLE+UNIT_ASC, "ASCII", "ASCII", - &ttrp_set_mode }, - { UNIT_ATTABLE+UNIT_ASC+UNIT_UASC, UNIT_ATTABLE+UNIT_ASC+UNIT_UASC, "Unix ASCII", "UASCII", - &ttrp_set_mode }, - { MTAB_XTD|MTAB_VUN|MTAB_NMO, 1, NULL, "START", &ttrp_set_start_stop }, - { MTAB_XTD|MTAB_VUN|MTAB_NMO, 0, NULL, "STOP", &ttrp_set_start_stop }, - { 0 } - }; - -DEVICE tty_dev = { - "TTY", tty_unit, tty_reg, tty_mod, - 4, 10, 31, 1, 8, 8, - NULL, NULL, &tty_reset, - NULL, &pt_attach, &pt_detach, - &tty_dib, 0 - }; - -/* CLK data structures - - clk_dev CLK device descriptor - clk_unit CLK unit descriptor - clk_mod CLK modifiers - clk_reg CLK register list -*/ - -DIB clk_dib = { CLK_KEYS, 1, IOBUS, IOBUS, INT_V_CLK, INT_V_NONE, &clkio, 0 }; - -UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 16000 }; - -REG clk_reg[] = { - { FLDATA (READY, dev_int, INT_V_CLK) }, - { FLDATA (ENABLE, dev_enb, INT_V_CLK) }, - { DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT }, - { DRDATA (TPS, clk_tps, 8), PV_LEFT + REG_HRO }, - { NULL } - }; - -MTAB clk_mod[] = { - { MTAB_XTD|MTAB_VDV, 50, NULL, "50HZ", - &clk_set_freq, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 60, NULL, "60HZ", - &clk_set_freq, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "FREQUENCY", NULL, - NULL, &clk_show_freq, NULL }, - { 0 } - }; - -DEVICE clk_dev = { - "CLK", &clk_unit, clk_reg, clk_mod, - 1, 0, 0, 0, 0, 0, - NULL, NULL, &clk_reset, - NULL, NULL, NULL, - &clk_dib, /* [RLA] */ DEV_DISABLE - }; - -/* Paper tape reader: IO routine */ - -int32 ptrio (int32 inst, int32 fnc, int32 dat, int32 dev) -{ -switch (inst) { /* case on opcode */ - - case ioOCP: /* OCP */ - if ((fnc & 016) != 0) /* only fnc 0,1 */ - return IOBADFNC (dat); - ptr_motion = fnc ^ 1; - if (fnc != 0) /* fnc 1? stop */ - sim_cancel (&ptr_unit); - else sim_activate (&ptr_unit, ptr_unit.wait); /* fnc 0? start */ - break; - - case ioSKS: /* SKS */ - if ((fnc & 013) != 0) /* only fnc 0,4 */ - return IOBADFNC (dat); - if (((fnc == 000) && TST_INT (INT_PTR)) || /* fnc 0? skip rdy */ - ((fnc == 004) && !TST_INTREQ (INT_PTR))) /* fnc 4? skip !int */ - return IOSKIP (dat); - break; - - case ioINA: /* INA */ - if (fnc != 0) /* only fnc 0 */ - return IOBADFNC (dat); - if (TST_INT (INT_PTR)) { /* ready? */ - CLR_INT (INT_PTR); /* clear ready */ - if (ptr_motion) /* if motion, restart */ - sim_activate (&ptr_unit, ptr_unit.wait); - return IOSKIP (ptr_unit.buf | dat); /* ret buf, skip */ - } - break; - } /* end case op */ - -return dat; -} - -/* Unit service */ - -t_stat ptr_svc (UNIT *uptr) -{ -int32 c; - -if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (ptr_stopioe, SCPE_UNATT); -if (uptr->STA & LF_PEND) { /* lf pending? */ - uptr->STA &= ~LF_PEND; /* clear flag */ - c = 0212; /* insert LF */ - } -else { - if ((c = getc (uptr->fileref)) == EOF) { /* read byte */ - if (feof (uptr->fileref)) { - if (ptr_stopioe) - sim_printf ("PTR end of file\n"); - else return SCPE_OK; - } - else perror ("PTR I/O error"); - clearerr (uptr->fileref); - return SCPE_IOERR; - } - if ((uptr->flags & UNIT_UASC) && (c == '\n')) { /* Unix newline? */ - c = 0215; /* insert CR */ - uptr->STA |= LF_PEND; /* lf pending */ - } - else if ((uptr->flags & UNIT_ASC) && (c != 0)) /* ASCII? */ - c = c | 0200; - uptr->pos = ftell (uptr->fileref); /* update pos */ - } -SET_INT (INT_PTR); /* set ready flag */ -uptr->buf = c & 0377; /* get byte */ -return SCPE_OK; -} - -/* Paper tape attach routine - set or clear ASC/UASC flags if specified - Can be called for TTY units at well, hence, check for attachability */ - -t_stat pt_attach (UNIT *uptr, char *cptr) -{ -t_stat r; - -if (!(uptr->flags & UNIT_ATTABLE)) /* not tti,tto */ - return SCPE_NOFNC; -if ((r = attach_unit (uptr, cptr))) - return r; -if (sim_switches & SWMASK ('A')) /* -a? ASCII */ - uptr->flags |= UNIT_ASC; -else if (sim_switches & SWMASK ('U')) /* -u? Unix ASCII */ - uptr->flags |= (UNIT_ASC|UNIT_UASC); -else if (sim_switches & SWMASK ('B')) /* -b? binary */ - uptr->flags &= ~(UNIT_ASC|UNIT_UASC); -uptr->STA = 0; -return r; -} - -/* Detach routine - stop motion if not restore */ - -t_stat pt_detach (UNIT *uptr) -{ -if (!(uptr->flags & UNIT_ATTABLE)) /* not tti,tto */ - return SCPE_NOFNC; -if (!(sim_switches & SIM_SW_REST)) /* stop motion */ - sim_cancel (uptr); -uptr->STA = 0; -return detach_unit (uptr); -} - -/* Reset routine */ - -t_stat ptr_reset (DEVICE *dptr) -{ -CLR_INT (INT_PTR); /* clear ready, enb */ -CLR_ENB (INT_PTR); -ptr_unit.buf = 0; /* clear buffer */ -ptr_unit.STA = 0; -ptr_motion = 0; /* unit stopped */ -sim_cancel (&ptr_unit); /* deactivate unit */ -return SCPE_OK; -} - -/* Paper tape reader bootstrap routine */ - -#define PBOOT_START 1 -#define PBOOT_SIZE (sizeof (pboot) / sizeof (int32)) - -static const int32 pboot[] = { - 0010057, /* STA 57 */ - 0030001, /* OCP 1 */ - 0131001, /* READ, INA 1001 */ - 0002003, /* JMP READ */ - 0101040, /* SNZ */ - 0002003, /* JMP READ */ - 0010000, /* STA 0 */ - 0131001, /* READ1, INA 1001 */ - 0002010, /* JMP READ1 */ - 0041470, /* LGL 8 */ - 0130001, /* READ2, INA 1 */ - 0002013, /* JMP READ2 */ - 0110000, /* STA* 0 */ - 0024000, /* IRS 0 */ - 0100040 /* SZE */ - }; - -t_stat ptr_boot (int32 unitno, DEVICE *dptr) -{ -size_t i; - -for (i = 0; i < PBOOT_SIZE; i++) /* copy bootstrap */ - M[PBOOT_START + i] = pboot[i]; -PC = PBOOT_START; -return SCPE_OK; -} - -/* Paper tape punch: IO routine */ - -int32 ptpio (int32 inst, int32 fnc, int32 dat, int32 dev) -{ -switch (inst) { /* case on opcode */ - - case ioOCP: /* OCP */ - if ((fnc & 016) != 0) /* only fnc 0,1 */ - return IOBADFNC (dat); - if (fnc != 0) { /* fnc 1? pwr off */ - CLR_INT (INT_PTP); /* not ready */ - ptp_power = 0; /* turn off power */ - sim_cancel (&ptp_unit); /* stop punch */ - } - else if (ptp_power == 0) /* fnc 0? start */ - sim_activate (&ptp_unit, ptp_ptime); - break; - - case ioSKS: /* SKS */ - if (((fnc & 012) !=0) || (fnc == 005)) /* only 0, 1, 4 */ - return IOBADFNC (dat); - if (((fnc == 000) && TST_INT (INT_PTP)) || /* fnc 0? skip rdy */ - ((fnc == 001) && /* fnc 1? skip ptp on */ - (ptp_power || sim_is_active (&ptp_unit))) || - ((fnc == 004) && !TST_INTREQ (INT_PTP))) /* fnc 4? skip !int */ - return IOSKIP (dat); - break; - - case ioOTA: /* OTA */ - if (fnc != 0) /* only fnc 0 */ - return IOBADFNC (dat); - if (TST_INT (INT_PTP)) { /* if ptp ready */ - CLR_INT (INT_PTP); /* clear ready */ - ptp_unit.buf = dat & 0377; /* store byte */ - sim_activate (&ptp_unit, ptp_unit.wait); - return IOSKIP (dat); /* skip return */ - } - break; - } - -return dat; -} - -/* Unit service */ - -t_stat ptp_svc (UNIT *uptr) -{ -int32 c; - -SET_INT (INT_PTP); /* set flag */ -if (ptp_power == 0) { /* power on? */ - ptp_power = 1; /* ptp is ready */ - return SCPE_OK; - } -if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (ptp_stopioe, SCPE_UNATT); -if (uptr->flags & UNIT_ASC) { /* ASCII? */ - c = uptr->buf & 0177; /* mask to 7b */ - if ((uptr->flags & UNIT_UASC) && (c == 015)) /* cr? drop if Unix */ - return SCPE_OK; - else if (c == 012) /* lf? cvt to nl */ - c = '\n'; - } -else c = uptr->buf & 0377; /* no, binary */ -if (putc (c, uptr->fileref) == EOF) { /* output byte */ - perror ("PTP I/O error"); - clearerr (uptr->fileref); - return SCPE_IOERR; - } -uptr->pos = ftell (uptr->fileref); /* update pos */ -return SCPE_OK; -} - -/* Reset routine */ - -t_stat ptp_reset (DEVICE *dptr) -{ -CLR_INT (INT_PTP); /* clear ready, enb */ -CLR_ENB (INT_PTP); -ptp_power = 0; /* power off */ -ptp_unit.buf = 0; /* clear buffer */ -ptp_unit.STA = 0; -sim_cancel (&ptp_unit); /* deactivate unit */ -return SCPE_OK; -} - -/* Terminal: IO routine */ - -int32 ttyio (int32 inst, int32 fnc, int32 dat, int32 dev) -{ -switch (inst) { /* case on opcode */ - - case ioOCP: /* OCP */ - if ((fnc & 016) != 0) /* only fnc 0,1 */ - return IOBADFNC (dat); - if (fnc != 0) { /* output */ - tty_ready = 1; /* set rdy, busy */ - tty_busy = 1; /* start dummy out */ - tty_mode = 1; /* mode is output */ - sim_activate (&tty_unit[TTO], tty_unit[TTO].wait); - } - else { /* input? */ - tty_ready = 0; /* clr rdy, busy */ - tty_busy = 0; - tty_mode = 0; /* mode is input */ - tty_2nd = 0; -/* sim_cancel (&tty_unit[TTO]); *//* cancel output */ - } - CLR_INT (INT_TTY); /* clear intr */ - break; - - case ioSKS: /* SKS */ - if ((fnc & 012) != 0) /* fnc 0,1,4,5 */ - return IOBADFNC (dat); - if (((fnc == 000) && tty_ready) || /* fnc 0? skip rdy */ - ((fnc == 001) && !tty_busy) || /* fnc 1? skip !busy */ - ((fnc == 004) && !TST_INTREQ (INT_TTY)) || /* fnc 4? skip !int */ - ((fnc == 005) && (tty_mode || /* fnc 5? skip !xoff */ - ((tty_buf & 0177) != XOFF)))) /* input & XOFF char */ - return IOSKIP (dat); - break; - - case ioINA: /* INA */ - if ((fnc & 005) != 0) /* only 0,2 */ - return IOBADFNC (dat); - if (tty_ready) { /* ready? */ - tty_ready = 0; /* clear rdy */ - CLR_INT (INT_TTY); /* no interrupt */ - return IOSKIP (dat | - (tty_buf & ((fnc & 002)? 077: 0377))); - } - break; - - case ioOTA: - if ((fnc & 015) != 0) /* only 0,2 */ - return IOBADFNC (dat); - if (tty_ready) { /* ready? */ - tty_buf = dat & 0377; /* store char */ - if (fnc & 002) { /* binary mode? */ - tty_buf = tty_buf | 0100; /* set ch 7 */ - if (tty_buf & 040) - tty_buf = tty_buf & 0277; - } - tty_ready = 0; /* clear ready */ - tty_busy = 1; /* set busy */ - CLR_INT (INT_TTY); /* clr int */ - sim_activate (&tty_unit[TTO], tty_unit[TTO].wait); - return IOSKIP (dat); - } - break; - } /* end case op */ - -return dat; -} - -/* Input service - keyboard and reader */ - -t_stat tti_svc (UNIT *uptr) -{ -int32 out, c; -UNIT *ruptr = &tty_unit[TTR]; - -sim_activate (uptr, uptr->wait); /* continue poll */ -if (tty_2nd) { /* char pending? */ - tty_buf = tty_2nd & 0377; - tty_2nd = 0; - tty_busy = 0; /* clr busy */ - tty_ready = 1; /* set ready */ - SET_INT (INT_TTY); /* set int */ - return SCPE_OK; - } -if ((c = sim_poll_kbd ()) >= SCPE_KFLAG) { /* character? */ - out = c & 0177; /* mask echo to 7b */ - if (c & SCPE_BREAK) /* break? */ - c = 0; - else c = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags) | TTUF_KSR); - uptr->pos = uptr->pos + 1; - } -else if (c != SCPE_OK) /* error? */ - return c; -else if ((ruptr->flags & UNIT_ATT) && /* TTR attached */ - (ruptr->STA & RUNNING)) { /* and running? */ - if (ruptr->STA & LF_PEND) { /* lf pending? */ - c = 0212; /* char is lf */ - ruptr->STA &= ~LF_PEND; /* clear flag */ - } - else { /* normal read */ - if ((c = getc (ruptr->fileref)) == EOF) { /* read byte */ - if (feof (ruptr->fileref)) { /* EOF? */ - ruptr->STA &= ~RUNNING; /* stop reader */ - if (ttr_stopioe) - sim_printf ("TTR end of file\n"); - else return SCPE_OK; - } - else perror ("TTR I/O error"); - clearerr (ruptr->fileref); - return SCPE_IOERR; - } - if ((ruptr->flags & UNIT_UASC) && (c == '\n')) { - c = 0215; /* Unix ASCII NL? */ - ruptr->STA |= LF_PEND; /* LF pending */ - } - else if ((ruptr->flags & UNIT_ASC) && (c != 0)) - c = c | 0200; /* ASCII nz? cvt */ - ruptr->pos = ftell (ruptr->fileref); - } - if (ttr_xoff_read != 0) { /* reader stopping? */ - if (c == RUBOUT) /* rubout? stop */ - ttr_xoff_read = 0; - else ttr_xoff_read--; /* else decr state */ - if (ttr_xoff_read == 0) /* delay done? */ - ruptr->STA &= ~RUNNING; /* stop reader */ - } - else if ((c & 0177) == XOFF) /* XOFF read? */ - ttr_xoff_read = 2; - out = c; /* echo char */ - } -else return SCPE_OK; /* no char */ -tto_write (out); /* echo to printer */ -ttp_write (out); /* and punch */ -if (tty_mode == 0) { /* input mode? */ - tty_2nd = (c & 0377) | 0400; /* flag 2nd state */ - tty_busy = 1; /* set busy */ - CLR_INT (INT_TTY); /* clear interrupt */ - sim_activate_abs (uptr, tty_busy_wait); /* sched busy period */ - } -return SCPE_OK; -} - -/* Output service - printer and punch */ - -t_stat tto_svc (UNIT *uptr) -{ -uint32 c7b; -UNIT *ruptr = &tty_unit[TTR]; -UNIT *puptr = &tty_unit[TTP]; -t_stat r; - -if ((tty_ready != 0) && (tty_busy != 0)) { /* dummy cycle? */ - tty_busy = 0; /* clr busy */ - SET_INT (INT_TTY); /* set intr */ - return SCPE_OK; - } -c7b = tty_buf & 0177; -if (ttp_tape_rcvd != 0) { /* prev = tape? */ - ttp_tape_rcvd--; /* decrement state */ - if ((ttp_tape_rcvd == 0) && (puptr->flags & UNIT_ATT)) - puptr->STA |= RUNNING; /* start after delay */ - } -else if (c7b == TAPE) /* char = TAPE? */ - ttp_tape_rcvd = 2; -if (ttp_xoff_rcvd != 0) { /* prev = XOFF? */ - ttp_xoff_rcvd--; /* decrement state */ - if (ttp_xoff_rcvd == 0) /* stop after delay */ - puptr->STA &= ~RUNNING; - } -else if (c7b == XOFF) /* char = XOFF? */ - ttp_xoff_rcvd = 2; -if ((c7b == XON) && (ruptr->flags & UNIT_ATT)) { /* char = XON? */ - ruptr->STA |= RUNNING; /* start reader */ - ttr_xoff_read = 0; /* cancel stop */ - } -if ((r = tto_write (tty_buf)) != SCPE_OK) { /* print; error? */ - sim_activate (uptr, uptr->wait); /* try again */ - return ((r == SCPE_STALL)? SCPE_OK: r); /* !stall? report */ - } -if ((r = ttp_write (tty_buf)) != SCPE_OK) /* punch; error? */ - return r; -tty_busy = 0; /* clr busy, set rdy */ -tty_ready = 1; -SET_INT (INT_TTY); /* set intr */ -return SCPE_OK; -} - -/* Output to printer */ - -t_stat tto_write (int32 c) -{ -UNIT *tuptr = &tty_unit[TTO]; - -c = sim_tt_outcvt (c, TT_GET_MODE (tuptr->flags) | TTUF_KSR); -tuptr->pos = tuptr->pos + 1; -if (c >= 0) - return sim_putchar_s (c); -else return SCPE_OK; -} - -/* Output to punch */ - -t_stat ttp_write (int32 c) -{ -uint32 p, c7b; -UNIT *puptr = &tty_unit[TTP]; - -if ((puptr->flags & UNIT_ATT) && /* TTP attached */ - (puptr->STA & RUNNING)) { /* and running? */ - c7b = c & 0177; - if (!(puptr->flags & UNIT_UASC) || (c7b != 015)) { - if (puptr->flags & UNIT_ASC) { /* ASCII? */ - if (c7b == 012) p = '\n'; /* cvt LF */ - else p = c7b; /* else 7b */ - } - else p = c; /* untouched */ - if (putc (p, puptr->fileref) == EOF) { /* output byte */ - perror ("TTP I/O error"); - clearerr (puptr->fileref); - return SCPE_IOERR; - } - puptr->pos = ftell (puptr->fileref); /* update pos */ - } - } -return SCPE_OK; -} - -/* Reset routine */ - -t_stat tty_reset (DEVICE *dptr) -{ -CLR_INT (INT_TTY); /* clear ready, enb */ -CLR_ENB (INT_TTY); -tty_mode = 0; /* mode = input */ -tty_buf = 0; -tty_2nd = 0; -tty_ready = 1; -tty_busy = 0; -ttr_xoff_read = 0; /* clr TTR, TTP flags */ -ttp_tape_rcvd = 0; -ttp_xoff_rcvd = 0; -tty_unit[TTR].STA = 0; -tty_unit[TTP].STA = 0; -sim_activate (&tty_unit[TTI], tty_unit[TTI].wait); /* activate poll */ -sim_cancel (&tty_unit[TTO]); /* cancel output */ -return SCPE_OK; -} - -/* Set keyboard/printer mode - make sure flags agree */ - -t_stat ttio_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (uptr->flags & UNIT_ATTABLE) /* not TTR, TTP */ - return SCPE_NOFNC; -tty_unit[TTO].flags = (tty_unit[TTO].flags & ~TT_MODE) | val; -if (val == TT_MODE_7P) - val = TT_MODE_7B; -tty_unit[TTI].flags = (tty_unit[TTI].flags & ~TT_MODE) | val; -return SCPE_OK; -} - -/* Set reader/punch mode */ - -t_stat ttrp_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (!(uptr->flags & UNIT_ATTABLE)) /* PTR, PTP, TTR, TTP only */ - return SCPE_NOFNC; -if (!(val & UNIT_UASC)) - uptr->STA &= ~LF_PEND; -return SCPE_OK; -} - -/* Set reader/punch start/stop */ - -t_stat ttrp_set_start_stop (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (!(uptr->flags & UNIT_ATTABLE)) /* TTR, TTP only */ - return SCPE_NOFNC; -if (!(uptr->flags & UNIT_ATT)) /* must be attached */ - return SCPE_UNATT; -if (val != 0) /* start? set running */ - uptr->STA |= RUNNING; -else uptr->STA &= ~RUNNING; /* stop? clr running */ -if ((uptr->flags & UNIT_ROABLE) != 0) /* TTR? cancel stop */ - ttr_xoff_read = 0; -else ttp_tape_rcvd = ttp_xoff_rcvd = 0; /* TTP? cancel all */ -return SCPE_OK; -} - -/* Clock/options: IO routine */ - -int32 clkio (int32 inst, int32 fnc, int32 dat, int32 dev) -{ -switch (inst) { /* case on opcode */ - - case ioOCP: /* OCP */ - if ((fnc & 015) != 0) /* only fnc 0,2 */ - return IOBADFNC (dat); - CLR_INT (INT_CLK); /* reset ready */ - if (fnc != 0) /* fnc = 2? stop */ - sim_cancel (&clk_unit); - else { /* fnc = 0? */ - if (!sim_is_active (&clk_unit)) - sim_activate (&clk_unit, /* activate */ - sim_rtc_init (clk_unit.wait)); /* init calibr */ - } - break; - - case ioSKS: /* SKS */ - if (fnc == 000) { /* clock skip !int */ - if (!TST_INTREQ (INT_CLK)) - return IOSKIP (dat); - } - // [RLA] I'm not sure where this comes from - I can't find any H316 - // [RLA] documentation that supports this. According to my manual, - // [RLA] skip on memory parity error (SPS) is opcode 101200 and skip - // [RLA] on no parity error (SPN) is 100200. Neither of these look - // [RLA] like an SKS to device 20. - // - // [RLA] In any case this code can't stay here since the clock can - // [RLA] now be disabled. It'll have to move to h316_cpu.c no matter - // [RLA] how it's supposed to work. - // - // [RLA] else if ((fnc & 007) == 002) { /* mem parity? */ - // [RLA] if (((fnc == 002) && !TST_INT (INT_MPE)) || - // [RLA] ((fnc == 012) && TST_INT (INT_MPE))) - // [RLA] return IOSKIP (dat); - // [RLA] } - else return IOBADFNC (dat); /* invalid fnc */ - break; - - case ioOTA: /* OTA */ - // [RLA] This case never gets here - OTA with device 20 is the SMK or - // [RLA] OTK instructions, and those are handled directly in h316_cpu.c - return IOBADFNC (dat); - } - -return dat; -} - -/* Unit service */ - -t_stat clk_svc (UNIT *uptr) -{ - -M[M_CLK] = (M[M_CLK] + 1) & DMASK; /* increment mem ctr */ -if (M[M_CLK] == 0) /* = 0? set flag */ - SET_INT (INT_CLK); -sim_rtc_calb (clk_tps); /* recalibrate */ -sim_activate_after (uptr, 1000000/clk_tps); /* reactivate unit */ -return SCPE_OK; -} - -/* Reset routine */ - -t_stat clk_reset (DEVICE *dptr) -{ -sim_register_clock_unit (&clk_unit); /* declare clock unit */ -CLR_INT (INT_CLK); /* clear ready, enb */ -CLR_ENB (INT_CLK); -sim_cancel (&clk_unit); /* deactivate unit */ -return SCPE_OK; -} - -/* Set frequency */ - -t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (cptr) - return SCPE_ARG; -if ((val != 50) && (val != 60)) - return SCPE_IERR; -clk_tps = val; -return SCPE_OK; -} - -/* Show frequency */ - -t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -fprintf (st, (clk_tps == 50)? "50Hz": "60Hz"); -return SCPE_OK; -} diff --git a/H316/h316_sys.c b/H316/h316_sys.c deleted file mode 100644 index 20024d5b..00000000 --- a/H316/h316_sys.c +++ /dev/null @@ -1,454 +0,0 @@ -/* h316_sys.c: Honeywell 316/516 simulator interface - - Copyright (c) 1999-2015, 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. - - 15-Sep-13 RMS Added device name support for IO instructions - Fixed handling of OTK - 21-May-13 RLA Add IMP/TIP devices - 01-Dec-04 RMS Fixed fprint_opr calling sequence - 24-Oct-03 RMS Added DMA/DMC support - 17-Sep-01 RMS Removed multiconsole support -*/ - -#include "h316_defs.h" -#include - -extern DEVICE cpu_dev; -extern UNIT cpu_unit; -extern DEVICE ptr_dev; -extern DEVICE ptp_dev; -extern DEVICE tty_dev; -extern DEVICE lpt_dev; -extern DEVICE clk_dev; -extern DEVICE dp_dev; -extern DEVICE fhd_dev; -extern DEVICE mt_dev; -#ifdef VM_IMPTIP -extern DEVICE rtc_dev, wdt_dev, imp_dev; -extern DEVICE mi1_dev, mi2_dev, mi3_dev, mi4_dev, mi5_dev; -extern DEVICE hi1_dev, hi2_dev, hi3_dev, hi4_dev; -#endif -extern REG cpu_reg[]; -extern uint16 M[]; - -/* SCP data structures and interface routines - - sim_name simulator name string - sim_PC pointer to saved PC register descriptor - sim_emax maximum number of words for examine/deposit - sim_devices array of pointers to simulated devices - sim_stop_messages array of pointers to stop messages - sim_load binary loader -*/ - -char sim_name[] = "H316"; - -REG *sim_PC = &cpu_reg[0]; - -int32 sim_emax = 1; - -DEVICE *sim_devices[] = { - &cpu_dev, - &ptr_dev, - &ptp_dev, - &lpt_dev, - &tty_dev, - &mt_dev, - &clk_dev, - &fhd_dev, - &dp_dev, -#ifdef VM_IMPTIP - &wdt_dev, - &rtc_dev, - &imp_dev, - &mi1_dev, &mi2_dev, &mi3_dev, &mi4_dev, &mi5_dev, - &hi1_dev, &hi2_dev, &hi3_dev, &hi4_dev, -#endif - NULL - }; - -const char *sim_stop_messages[] = { - "Unknown error", - "Unimplemented instruction", - "Unimplemented I/O device", - "HALT instruction", - "Breakpoint", - "Indirect address loop", - "DMA error", - "MT write protected", - "DP write overrun, track destroyed", - "DP track format invalid" - }; - -/* Binary loader - - Tbs. -*/ - -t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) -{ -return SCPE_FMT; -} - -/* Symbol tables */ - -#define I_V_FL 16 /* flag start */ -#define I_M_FL 07 /* flag mask */ -#define I_V_NPN 0 /* no operand */ -#define I_V_MRF 1 /* mem ref */ -#define I_V_MRX 2 /* mem ref, no idx */ -#define I_V_IOT 3 /* I/O */ -#define I_V_SHF 4 /* shift */ -#define I_V_SK0 5 /* skip 0 */ -#define I_V_SK1 6 /* skip 1 */ -#define I_NPN (I_V_NPN << I_V_FL) -#define I_MRF (I_V_MRF << I_V_FL) -#define I_MRX (I_V_MRX << I_V_FL) -#define I_IOT (I_V_IOT << I_V_FL) -#define I_SHF (I_V_SHF << I_V_FL) -#define I_SK0 (I_V_SK0 << I_V_FL) -#define I_SK1 (I_V_SK1 << I_V_FL) - -static const int32 masks[] = { - 0177777, 0136000, 0176000, 0176000, - 0177700, 0177000, 0177000 - }; - -static const char *opcode[] = { - "HLT", "SGL", "DBL", - "DXA", "EXA", "RMP", - "SCA", "INK", "NRM", - "IAB", "ENB", "INH", "ERM", - "CHS", "CRA", "SSP", - "RCB", "CSA", "CMA", - "TCA", "SSM", "SCB", - "CAR", "CAL", "ICL", - "AOA", "ACA", "ICR", "ICA", - "NOP", "SKP", "SSR", "SSS", - "OTK", "JMP", "JMP*", - "LDA", "LDA*", "ANA", "ANA*", - "STA", "STA*", "ERA", "ERA*", - "ADD", "ADD*", "SUB", "SUB*", - "JST", "JST*", "CAS", "CAS*", - "IRS", "IRS*", "IMA", "IMA*", - "MPY", "MPY*", "DIV", "DIV*", - "STX", "STX*", "LDX", "LDX*", - "LRL", "LRS", "LRR", - "LGR", "ARS", "ARR", - "LLL", "LLS", "LLR", - "LGL", "ALS", "ALR", - "OCP", "SKS", "INA", "OTA", - "SMK", - "SPL", "SPN", "SLZ", /* encode only */ - "SZE", "SR1", "SR2", - "SR3", "SR4", "SRC", - "SMI", "SPS", "SLN", - "SNZ", "SS1", "SS2", - "SS3", "SS4", "SSC", - NULL, NULL, /* decode only */ - NULL - }; - -static const char *ioname[DEV_MAX] = { - NULL, "PTR", "PTP", "LPT", "TTY", "CDR", NULL, NULL, - "MT", NULL, NULL, NULL, NULL, NULL, NULL, NULL, - "CLK", NULL, "FHD", NULL, "DMA", "DP", NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL - }; - -static const int32 opc_val[] = { - 0000000+I_NPN, 0000005+I_NPN, 0000007+I_NPN, - 0000011+I_NPN, 0000013+I_NPN, 0000021+I_NPN, - 0000041+I_NPN, 0000043+I_NPN, 0000101+I_NPN, - 0000201+I_NPN, 0000401+I_NPN, 0001001+I_NPN, 0001401+I_NPN, - 0140024+I_NPN, 0140040+I_NPN, 0140100+I_NPN, - 0140200+I_NPN, 0140320+I_NPN, 0140401+I_NPN, - 0140407+I_NPN, 0140500+I_NPN, 0140600+I_NPN, - 0141044+I_NPN, 0141050+I_NPN, 0141140+I_NPN, - 0141206+I_NPN, 0141216+I_NPN, 0141240+I_NPN, 0141340+I_NPN, - 0101000+I_NPN, 0100000+I_NPN, 0100036+I_NPN, 0101036+I_NPN, - 0171020+I_NPN, 0002000+I_MRF, 0102000+I_MRF, - 0004000+I_MRF, 0104000+I_MRF, 0006000+I_MRF, 0106000+I_MRF, - 0010000+I_MRF, 0110000+I_MRF, 0012000+I_MRF, 0112000+I_MRF, - 0014000+I_MRF, 0114000+I_MRF, 0016000+I_MRF, 0116000+I_MRF, - 0020000+I_MRF, 0120000+I_MRF, 0022000+I_MRF, 0122000+I_MRF, - 0024000+I_MRF, 0124000+I_MRF, 0026000+I_MRF, 0126000+I_MRF, - 0034000+I_MRF, 0134000+I_MRF, 0036000+I_MRF, 0136000+I_MRF, - 0032000+I_MRX, 0132000+I_MRX, 0072000+I_MRX, 0172000+I_MRX, - 0040000+I_SHF, 0040100+I_SHF, 0040200+I_SHF, - 0040400+I_SHF, 0040500+I_SHF, 0040600+I_SHF, - 0041000+I_SHF, 0041100+I_SHF, 0041200+I_SHF, - 0041400+I_SHF, 0041500+I_SHF, 0041600+I_SHF, - 0030000+I_IOT, 0070000+I_IOT, 0130000+I_IOT, 0170000+I_IOT, - 0170000+I_IOT, - 0100400+I_SK0, 0100200+I_SK0, 0100100+I_SK0, /* encode only */ - 0100040+I_SK0, 0100020+I_SK0, 0100010+I_SK0, - 0100004+I_SK0, 0100002+I_SK0, 0100001+I_SK0, - 0101400+I_SK1, 0101200+I_SK1, 0101100+I_SK1, - 0101040+I_SK1, 0101020+I_SK1, 0101010+I_SK1, - 0101004+I_SK1, 0101002+I_SK1, 0101001+I_SK1, - 0100000+I_SK0, 0101000+I_SK1, /* decode only */ - -1 - }; - -/* Operate decode - - Inputs: - *of = output stream - inst = mask bits - class = instruction class code - sp = space needed? - Outputs: - status = space needed -*/ - -void fprint_opr (FILE *of, int32 inst, int32 class) -{ -int32 i, j, sp; - -for (i = sp = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ - j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */ - if ((j == class) && (opc_val[i] & inst)) { /* same class? */ - inst = inst & ~opc_val[i]; /* mask bit set? */ - fprintf (of, (sp? " %s": "%s"), opcode[i]); - sp = 1; - } - } -return; -} - -/* Symbolic decode - - Inputs: - *of = output stream - addr = current PC - *val = pointer to data - *uptr = pointer to unit - sw = switches - Outputs: - return = status code -*/ - -#define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x) - -t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, - UNIT *uptr, int32 sw) -{ -int32 cflag, i, j, inst, fnc, disp; - -cflag = (uptr == NULL) || (uptr == &cpu_unit); -inst = val[0]; -if (sw & SWMASK ('A')) { /* ASCII? */ - if (inst > 0377) - return SCPE_ARG; - fprintf (of, FMTASC (inst & 0177)); - return SCPE_OK; - } -if (sw & SWMASK ('C')) { /* characters? */ - fprintf (of, FMTASC ((inst >> 8) & 0177)); - fprintf (of, FMTASC (inst & 0177)); - return SCPE_OK; - } -if (!(sw & SWMASK ('M'))) - return SCPE_ARG; - -/* Instruction decode */ - -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] & DMASK) == (inst & masks[j])) { /* match? */ - - switch (j) { /* case on class */ - - case I_V_NPN: /* no operands */ - fprintf (of, "%s", opcode[i]); /* opcode */ - break; - - case I_V_MRF: case I_V_MRX: /* mem ref */ - disp = inst & DISP; /* displacement */ - fprintf (of, "%s ", opcode[i]); /* opcode */ - if (inst & SC) { /* current sector? */ - if (cflag) - fprintf (of, "%-o", (addr & PAGENO) | disp); - else fprintf (of, "C %-o", disp); - } - else fprintf (of, "%-o", disp); /* sector zero */ - if ((j == I_V_MRF) && (inst & IDX)) - fprintf (of, ",1"); - break; - - case I_V_IOT: /* I/O */ - fnc = I_GETFNC (inst); /* get func */ - disp = inst & DEVMASK; /* get dev */ - if (ioname[disp] != NULL) - fprintf (of, "%s %o,%s", opcode[i], fnc, ioname[disp]); - else fprintf (of, "%s %o,%o", opcode[i], fnc, disp); - break; - - case I_V_SHF: /* shift */ - disp = -inst & SHFMASK; /* shift count */ - fprintf (of, "%s %o", opcode[i], disp); - break; - - case I_V_SK0: case I_V_SK1: /* skips */ - fprint_opr (of, inst & 0777, j); /* print skips */ - break; - } /* end case */ - - return SCPE_OK; - } /* end if */ - } /* end for */ -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 -*/ - -t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) -{ -int32 cflag, d, i, j, k; -t_stat r; -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) /* must have 1 char */ - return SCPE_ARG; - val[0] = (t_value) cptr[0] & 0177; - return SCPE_OK; - } -if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* char string? */ - if (cptr[0] == 0) /* must have 1 char */ - return SCPE_ARG; - val[0] = (((t_value) cptr[0] & 0177) << 8) | - ((t_value) cptr[1] & 0177); - return SCPE_OK; - } - -/* Instruction parse */ - -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] & DMASK; /* get value */ -j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */ - -switch (j) { /* case on class */ - - case I_V_NPN: /* no operand */ - break; - - case I_V_IOT: /* IOT */ - cptr = get_glyph (cptr, gbuf, ','); /* get field */ - if (*cptr == 0) { /* single field? */ - d = get_uint (gbuf, 8, 01777, &r); /* pulse+dev */ - if (r != SCPE_OK) - return SCPE_ARG; - val[0] = val[0] | d; - } - else { /* multiple fields */ - d = get_uint (gbuf, 8, 017, &r); /* get pulse */ - if (r != SCPE_OK) - return SCPE_ARG; - cptr = get_glyph (cptr, gbuf, 0); /* get dev name */ - for (k = 0; k < DEV_MAX; k++) { /* sch for name */ - if ((ioname[k] != NULL) && (strcmp (gbuf, ioname[k]) == 0)) - break; /* match? */ - } - if (k >= DEV_MAX) { /* no match */ - k = get_uint (gbuf, 8, DEV_MAX - 1, &r);/* integer */ - if (r != SCPE_OK) - return SCPE_ARG; - } - val[0] = val[0] | (d << I_V_FNC) | k; - } - break; - - case I_V_SHF: /* shift */ - cptr = get_glyph (cptr, gbuf, 0); /* get shift count */ - d = get_uint (gbuf, 8, SHFMASK, &r); - if (r != SCPE_OK) - return SCPE_ARG; - val[0] = val[0] | (-d & SHFMASK); /* store 2's comp */ - break; - - case I_V_MRF: case I_V_MRX: /* mem ref */ - cptr = get_glyph (cptr, gbuf, ','); /* get next field */ - if ((k = (strcmp (gbuf, "C") == 0))) { /* C specified? */ - val[0] = val[0] | SC; - cptr = get_glyph (cptr, gbuf, 0); - } - else if ((k = (strcmp (gbuf, "Z") == 0))) { /* Z specified? */ - cptr = get_glyph (cptr, gbuf, ','); - } - d = get_uint (gbuf, 8, X_AMASK, &r); /* construe as addr */ - if (r != SCPE_OK) - return SCPE_ARG; - if (d <= DISP) /* fits? */ - val[0] = val[0] | d; - else if (cflag && !k && (((addr ^ d) & PAGENO) == 0)) - val[0] = val[0] | (d & DISP) | SC; - else return SCPE_ARG; - if ((j == I_V_MRX) || (*cptr == 0)) /* indexed? */ - break; - cptr = get_glyph (cptr, gbuf, 0); - d = get_uint (gbuf, 8, 1, &r); /* get tag */ - if (r != SCPE_OK) - return SCPE_ARG; - if (d) /* or in index */ - val[0] = val[0] | IDX; - break; - - case I_V_SK0: case I_V_SK1: /* skips */ - for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0; - cptr = get_glyph (cptr, gbuf, 0)) { - for (i = 0; (opcode[i] != NULL) && - (strcmp (opcode[i], gbuf) != 0) ; i++) ; - k = opc_val[i] & DMASK; - if ((opcode[i] == NULL) || (((k ^ val[0]) & 0177000) != 0)) - return SCPE_ARG; - val[0] = val[0] | k; - } - break; - } /* end case */ - -if (*cptr != 0) /* junk at end? */ - return SCPE_ARG; -return SCPE_OK; -} diff --git a/H316/h316_udp.c b/H316/h316_udp.c deleted file mode 100644 index c1cb3a2f..00000000 --- a/H316/h316_udp.c +++ /dev/null @@ -1,468 +0,0 @@ -/* h316_udp.c: IMP/TIP Modem and Host Interface socket routines using UDP - - Copyright (c) 2013 Robert Armstrong, bob@jfcl.com - - 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 ARMSTRONG 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 Armstrong 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 Armstrong. - - - REVISION HISTORY - - udp socket routines - - 26-Jun-13 RLA Rewritten from TCP version - 26-Nov-13 MP Rewritten to use TMXR layer packet semantics thus - allowing portability to all simh hosts. - 2-Dec-13 RLA Improve error recovery if the other simh is restarted - - OVERVIEW - - This module emulates low level communications between two virtual modems - using UDP packets over the modern network connections. It's used by both - the IMP modem interface and the host interface modules to implement IMP to - IMP and IMP to HOST connections. - - TCP vs UDP - - Why UDP and not TCP? TCP has a couple of advantages after all - it's - stream oriented, which is intrinsically like a modem, and it handles all - the network "funny stuff" for us. TCP has a couple of problems too - first, - it's inherently asymmetrical. There's a "server" end which opens a master - socket and passively listens for connections, and a "client" end which - actively attempts to connect. That's annoying, but it can be worked around. - - The big problem with TCP is that even though it treats the data like a stream - it's internally buffering it, and you really have absolutely no control over - when TCP will decide to send its buffer. Google "nagle algorithm" to get an - idea. Yes, you can set TCP_NODELAY to disable Nagle, but the data's still - buffered and it doesn't fix the problem. What's the issue with buffering? - It introduces completely unpredictable delays into the message traffic. A - transmitting IMP could send two or three (or ten or twenty!) messages before - TCP actually decides to try to deliver them to the destination. - - And it turns out that IMPs are extraordinarily sensitive to line speed. The - IMP firmware actually goes to the trouble of measuring the effective line - speed by using the RTC to figure out how long it takes to send a message. - One thing that screws up the IMP to no end is variation in the effective - line speed. I guess they had a lot of trouble with AT&T Long Lines back in - the Old Days, and the IMP has quite a bit of code to monitor line quality. - Even fairly minor variations in speed will cause it to mark the line as - "down" and sent a trouble report back to BBN. And no, I'm not making this up! - - UDP gives us a few advantages. First, it's inherently packet oriented so - we can simply grab the entire packet from the transmitting IMP's memory, wrap - a little extra information around it, and ship it off in one datagram. The - receiving IMP gets the whole packet at once and it can simply BLT it into - the receiving IMP's memory. No fuss, no muss, no need convert the packet - into a stream, add word counts, wait for complete packets, etc. And UDP is - symmetrical - both ends listen and send in the same way. There's no need for - master sockets, passive (server) and active (client) ends, or any of that. - - Also UDP has no buffering - the packet goes out on the wire when we send it. - The data doesn't wait around in some buffer for TCP to decide when it wants - to let it go. The latency and delay for UDP is much more predictable and - consistent, at least for local networks. If you're actually sending the - packets out on the big, wide, Internet then all bets are off on that. - - UDP has a few problems that we have to worry about. First, it's not - guaranteed delivery so just because one IMP sends a packet doesn't mean that - the other end will ever see it. Surprisingly that's not a problem for us. - Phone lines have noise and dropouts, and real modems lose packets too. The - IMP code is completely happy and able to deal with that, and generally we - don't worry about dropped packets at all. - - There are other issues with UDP - it doesn't guarantee packet order, so the - sending IMP might transmit packets 1, 2 and 3 and the receiving IMP will get - 1, 3 then 2. THAT would never happen with a real modem and we have to shield - the IMP code from any such eventuality. Also, with UDP packets can be - duplicated so the receiving IMP might see 1, 2, 2, 3 (or even 1, 3, 2, 1!). - Again, a modem would never do that and we have to prevent it from happening. - Both cases are easily dealt with by adding a sequence number to the header - we wrap around the IMP's packet. Out of sequence or duplicate packets can - be detected and are simply dropped. If necessary, the IMP will deal with - retransmitting them in its own time. - - One more thing about UDP - there is no way to tell whether a connection is - established or not and for that matter there is no "connection" at all - (that's why it's a "connectionless" protocol, after all!). We simply send - packets out and there's no way to know whether anybody is hearing them. The - real IMP modem hardware had no carrier detect or other dataset control - functions, so it was identical in that respect. An IMP sent messages out the - modem and, unless it received a message back, it had no way to know whether - the IMP on the other end was hearing them. - - - INTERFACE - - This module provides a simplified UDP socket interface. These functions are - implemented - - - udp_create define a connection to the remote IMP - udp_release release a connection - udp_send send an IMP message to the other end - udp_receive receive (w/o blocking!) a message if available - - Note that each connection is assigned a unique "handle", a small integer, - which is used as an index into our internal connection data table. There - is a limit on the maximum number of connections available, as set my the - MAXLINKS parameter. Also, notice that all links are intrinsically full - duplex and bidirectional - data can be sent and received in both directions - independently. Real modems and host cards were exactly the same. - -*/ -#ifdef VM_IMPTIP -#include "sim_defs.h" // simh machine independent definitions -#include "sim_tmxr.h" // The MUX layer exposes packet send and receive semantics -#include "h316_defs.h" // H316 emulator definitions -#include "h316_imp.h" // ARPAnet IMP/TIP definitions - -// Local constants ... -#define MAXLINKS 10 // maximum number of simultaneous connections -// This constant determines the longest possible IMP data payload that can be -// sent. Most IMP messages are trivially small - 68 words or so - but, when one -// IMP asks for a reload the neighbor IMP sends the entire memory image in a -// single message! That message is about 14K words long. -// The next thing you should worry about is whether the underlying IP network -// can actually send a UDP packet of this size. It turns out that there's no -// simple answer to that - it'll be fragmented for sure, but as long as all -// the fragments arrive intact then the destination should reassemble them. -#define MAXDATA 16384 // longest possible IMP packet (in H316 words) - -// UDP connection data structure ... -// One of these blocks is allocated for every simulated modem link. -struct _UDP_LINK { - t_bool used; // TRUE if this UDP_LINK is in use - char rhostport[64]; // Remote host:port - char lport[64]; // Local port - uint32 rxsequence; // next message sequence number for receive - uint32 txsequence; // next message sequence number for transmit - DEVICE *dptr; // Device associated with link -}; -typedef struct _UDP_LINK UDP_LINK; - -// This magic number is stored at the beginning of every UDP message and is -// checked on receive. It's hardly foolproof, but its a simple attempt to -// guard against other applications dumping unsolicited UDP messages into our -// receiver socket... -#define MAGIC ((uint32) (((((('H' << 8) | '3') << 8) | '1') << 8) | '6')) - -// UDP wrapper data structure ... -// This is the UDP packet which is actually transmitted or received. It -// contains the actual IMP packet, plus whatever additional information we -// need to keep track of things. NOTE THAT ALL DATA IN THIS PACKET, INCLUDING -// THE H316 MEMORY WORDS, ARE SENT AND RECEIVED WITH NETWORK BYTE ORDER! -struct _UDP_PACKET { - uint32 magic; // UDP "magic number" (see above) - uint32 sequence; // UDP packet sequence number - uint16 count; // number of H316 words to follow - uint16 data[MAXDATA]; // and the actual H316 data words/IMP packet -}; -typedef struct _UDP_PACKET UDP_PACKET; -#define UDP_HEADER_LEN (2*sizeof(uint32) + sizeof(uint16)) - -// Locals ... -UDP_LINK udp_links[MAXLINKS] = { {0} }; // data for every active connection -TMLN udp_lines[MAXLINKS] = { {0} }; // line descriptors -TMXR udp_tmxr = { MAXLINKS, NULL, 0, udp_lines};// datagram mux - -int32 udp_find_free_link (void) -{ - // Find a free UDP_LINK block, initialize it and return its index. If none - // are free, then return -1 ... - int32 i; - for (i = 0; i < MAXLINKS; ++i) { - if (udp_links[i].used == 0) { - memset(&udp_links[i], 0, sizeof(UDP_LINK)); - return i; - } - } - return NOLINK; -} - -t_stat udp_parse_remote (int32 link, char *premote) -{ - // This routine will parse a remote address string in any of these forms - - // - // llll:w.x.y.z:rrrr - // llll:name.domain.com:rrrr - // llll::rrrr - // w.x.y.z:rrrr - // name.domain.com:rrrr - // - // In all examples, "llll" is the local port number that we use for listening, - // and "rrrr" is the remote port number that we use for transmitting. The - // local port is optional and may be omitted, in which case it defaults to the - // same as the remote port. This works fine if the other IMP is actually on - // a different host, but don't try that with localhost - you'll be talking to - // yourself!! In both cases, "w.x.y.z" is a dotted IP for the remote machine - // and "name.domain.com" is its name (which will be looked up to get the IP). - // If the host name/IP is omitted then it defaults to "localhost". - char *end; int32 lport, rport; - char host[64], port[16]; - if (*premote == '\0') return SCPE_2FARG; - memset (udp_links[link].lport, 0, sizeof(udp_links[link].lport)); - memset (udp_links[link].rhostport, 0, sizeof(udp_links[link].rhostport)); - // Handle the llll::rrrr case first - if (2 == sscanf (premote, "%d::%d", &lport, &rport)) { - if ((lport < 1) || (lport >65535) || (rport < 1) || (rport >65535)) return SCPE_ARG; - sprintf (udp_links[link].lport, "%d", lport); - sprintf (udp_links[link].rhostport, "localhost:%d", rport); - return SCPE_OK; - } - - // Look for the local port number and save it away. - lport = strtoul(premote, &end, 10); - if ((*end == ':') && (lport > 0)) { - sprintf (udp_links[link].lport, "%d", lport); - premote = end+1; - } - - if (sim_parse_addr (premote, host, sizeof(host), "localhost", port, sizeof(port), NULL, NULL)) - return SCPE_ARG; - sprintf (udp_links[link].rhostport, "%s:%s", host, port); - if (udp_links[link].lport[0] == '\0') - strcpy (udp_links[link].lport, port); - - if ((strcmp (udp_links[link].lport, port) == 0) && - (strcmp ("localhost", host) == 0)) - fprintf(stderr,"WARNING - use different transmit and receive ports!\n"); - - return SCPE_OK; -} - -t_stat udp_error (int32 link, const char *msg) -{ - // This routine is called whenever a SOCKET_ERROR is returned for any I/O. - fprintf(stderr,"UDP%d - %s failed with error %d\n", link, msg, WSAGetLastError()); - return SCPE_IOERR; -} - -t_stat udp_create (DEVICE *dptr, char *premote, int32 *pln) -{ - // Create a logical UDP link to the specified remote system. The "remote" - // string specifies both the remote host name or IP and a port number. The - // port number is both the port we send datagrams to, and also the port we - // listen on for incoming datagrams. UDP doesn't have any real concept of a - // "connection" of course, and this routine simply creates the necessary - // sockets in this host. We have no way of knowing whether the remote host is - // listening or even if it exists. - // - // We return SCPE_OK if we're successful and an error code if we aren't. If - // we are successful, then the ln parameter is assigned the link number, - // which is a handle used to identify this connection to all future udp_xyz() - // calls. - t_stat ret; - char linkinfo[128]; - int32 link = udp_find_free_link(); - if (link < 0) return SCPE_MEM; - - // Parse the remote name and set up the ipaddr and port ... - if ((ret = udp_parse_remote(link, premote)) != SCPE_OK) return ret; - - // Create the socket connection to the destination ... - sprintf(linkinfo, "Buffer=%d,Line=%d,%s,UDP,Connect=%s", (int)(sizeof(UDP_PACKET)+sizeof(int32)), link, udp_links[link].lport, udp_links[link].rhostport); - ret = tmxr_open_master (&udp_tmxr, linkinfo); - if (ret != SCPE_OK) return ret; - - // All done - mark the TCP_LINK data as "used" and return the index. - udp_links[link].used = TRUE; *pln = link; - udp_lines[link].dptr = udp_links[link].dptr = dptr; // save device - udp_tmxr.uptr = dptr->units; - udp_tmxr.last_poll_time = 1; // h316'a use of TMXR doesn't poll periodically for connects - tmxr_poll_conn (&udp_tmxr); // force connection initialization now - udp_tmxr.last_poll_time = 1; // h316'a use of TMXR doesn't poll periodically for connects - sim_debug(IMP_DBG_UDP, dptr, "link %d - listening on port %s and sending to %s\n", link, udp_links[link].lport, udp_links[link].rhostport); - return SCPE_OK; -} - -t_stat udp_release (DEVICE *dptr, int32 link) -{ - // Close a link that was created by udp_create() and release any resources - // allocated to it. We always return SCPE_OK unless the link specified is - // already unused. - if ((link < 0) || (link >= MAXLINKS)) return SCPE_IERR; - if (!udp_links[link].used) return SCPE_IERR; - if (dptr != udp_links[link].dptr) return SCPE_IERR; - - tmxr_detach_ln (&udp_lines[link]); - udp_links[link].used = FALSE; - sim_debug(IMP_DBG_UDP, dptr, "link %d - closed\n", link); - - return SCPE_OK; -} - -t_stat udp_send (DEVICE *dptr, int32 link, uint16 *pdata, uint16 count) -{ - // This routine does all the work of sending an IMP data packet. pdata - // is a pointer (usually into H316 simulated memory) to the IMP packet data, - // count is the length of the data (in H316 words, not bytes!), and pdest is - // the destination socket. There are two things worthy of note here - first, - // notice that the H316 words are sent in network order, so the remote simh - // doesn't necessarily need to have the same endian-ness as this machine. - // Second, notice that transmitting sockets are NOT set to non blocking so - // this routine might wait, but we assume the wait will never be too long. - UDP_PACKET pkt; int pktlen; uint16 i; t_stat iret; - if ((link < 0) || (link >= MAXLINKS)) return SCPE_IERR; - if (!udp_links[link].used) return SCPE_IERR; - if ((pdata == NULL) || (count == 0) || (count > MAXDATA)) return SCPE_IERR; - if (dptr != udp_links[link].dptr) return SCPE_IERR; - - // Build the UDP packet, filling in our own header information and copying - // the H316 words from memory. REMEMBER THAT EVERYTHING IS IN NETWORK ORDER! - pkt.magic = htonl(MAGIC); - pkt.sequence = htonl(udp_links[link].txsequence++); - pkt.count = htons(count); - for (i = 0; i < count; ++i) pkt.data[i] = htons(*pdata++); - pktlen = UDP_HEADER_LEN + count*sizeof(uint16); - - // Send it and we're outta here ... - iret = tmxr_put_packet_ln (&udp_lines[link], (const uint8 *)&pkt, (size_t)pktlen); - if (iret != SCPE_OK) return udp_error(link, "tmxr_put_packet_ln()"); - sim_debug(IMP_DBG_UDP, dptr, "link %d - packet sent (sequence=%d, length=%d)\n", link, ntohl(pkt.sequence), ntohs(pkt.count)); - return SCPE_OK; -} - -t_stat udp_set_link_loopback (DEVICE *dptr, int32 link, t_bool enable_loopback) -{ - // Enable or disable the local (interface) loopback on this link... - if ((link < 0) || (link >= MAXLINKS)) return SCPE_IERR; - if (!udp_links[link].used) return SCPE_IERR; - if (dptr != udp_links[link].dptr) return SCPE_IERR; - - return tmxr_set_line_loopback (&udp_lines[link], enable_loopback); -} - -int32 udp_receive_packet (int32 link, UDP_PACKET *ppkt) -{ - // This routine will do the hard part of receiving a UDP packet. If it's - // successful the packet length, in bytes, is returned. The receiver socket - // is non-blocking, so if no packet is available then zero will be returned - // instead. Lastly, if a fatal socket I/O error occurs, -1 is returned. - // - // Note that this routine only receives the packet - it doesn't handle any - // of the checking for valid packets, unexpected packets, duplicate or out of - // sequence packets. That's strictly the caller's problem! - size_t pktsiz; - const uint8 *pbuf; - t_stat ret; - - udp_lines[link].rcve = TRUE; // Enable receiver - tmxr_poll_rx (&udp_tmxr); - ret = tmxr_get_packet_ln (&udp_lines[link], &pbuf, &pktsiz); - udp_lines[link].rcve = FALSE; // Disable receiver - if (ret != SCPE_OK) { - udp_error(link, "tmxr_get_packet_ln()"); - return NOLINK; - } - if (pbuf == NULL) return 0; - // Got a packet, so copy it to the packet buffer - memcpy (ppkt, pbuf, pktsiz); - return pktsiz; -} - -int32 udp_receive (DEVICE *dptr, int32 link, uint16 *pdata, uint16 maxbuf) -{ - // Receive an IMP packet from the virtual modem. pdata is a pointer usually - // directly into H316 simulated memory) to where the IMP packet data should - // be stored, and maxbuf is the maximum length of that buffer in H316 words - // (not bytes!). If a message is successfully received then this routine - // returns the length, again in H316 words, of the IMP packet. The caller - // can detect buffer overflows by comparing this result to maxbuf. If no - // packets are waiting right now then zero is returned, and -1 is returned - // in the event of any fatal socket I/O error. - // - // This routine also handles checking for unsolicited messages and duplicate - // or out of sequence messages. All of these are unceremoniously discarded. - // - // One final note - it's explicitly allowed for pdata to be null and/or - // maxbuf to be zero. In either case the received package is discarded, but - // the actual length of the discarded package is still returned. - UDP_PACKET pkt; int32 pktlen, explen, implen, i; uint32 magic, pktseq; - if ((link < 0) || (link >= MAXLINKS)) return SCPE_IERR; - if (!udp_links[link].used) return SCPE_IERR; - if (dptr != udp_links[link].dptr) return SCPE_IERR; - - while ((pktlen = udp_receive_packet(link, &pkt)) > 0) { - // First do some header checks for a valid UDP packet ... - if (((size_t)pktlen) < UDP_HEADER_LEN) { - sim_debug(IMP_DBG_UDP, dptr, "link %d - received packet w/o header (length=%d)\n", link, pktlen); - continue; - } - magic = ntohl(pkt.magic); - if (magic != MAGIC) { - sim_debug(IMP_DBG_UDP, dptr, "link %d - received packet w/bad magic number (magic=%08x)\n", link, magic); - continue; - } - implen = ntohs(pkt.count); - explen = UDP_HEADER_LEN + implen*sizeof(uint16); - if (explen != pktlen) { - sim_debug(IMP_DBG_UDP, dptr, "link %d - received packet length wrong (expected=%d received=%d)\n", link, explen, pktlen); - continue; - } - - // Now the hard part = check the sequence number. The rxsequence value is - // the number of the next packet we expect to receive - that's the number - // this packet should have. If this packet's sequence is less than that, - // then this packet is out of order or a duplicate and we discard it. If - // this packet is greater than that, then we must have missed one or two - // packets. In that case we MUST update rxsequence to match this one; - // otherwise the two ends could never resynchronize after a lost packet. - // - // And there's one final complication to worry about - if the simh on the - // other end is restarted for some reason, then his sequence numbers will - // reset to zero. In that case we'll never recover synchronization without - // special efforts. The hack is to check for a packet sequence number of - // zero and, if we find it, force synchronization. This improves the - // situation, but I freely admit that it's possible to think of a number of - // cases where this also fails. The only absolute solution is to implement - // a more complicated system with non-IMP control messages exchanged between - // the modem emulation on both ends. That'd be nice, but I'll leave it as - // an exercise for later. - pktseq = ntohl(pkt.sequence); - if ((pktseq == 0) && (udp_links[link].rxsequence != 0)) { - sim_debug(IMP_DBG_UDP, dptr, "link %d - remote modem restarted\n", link); - } else if (pktseq < udp_links[link].rxsequence) { - sim_debug(IMP_DBG_UDP, dptr, "link %d - received packet out of sequence 1 (expected=%d received=%d\n", link, udp_links[link].rxsequence, pktseq); - continue; // discard this packet! - } - else if (pktseq != udp_links[link].rxsequence) { - sim_debug(IMP_DBG_UDP, dptr, "link %d - received packet out of sequence 2 (expected=%d received=%d\n", link, udp_links[link].rxsequence, pktseq); - } - udp_links[link].rxsequence = pktseq+1; - - // It's a valid packet - if there's no buffer then just discard it. - if ((pdata == NULL) || (maxbuf == 0)) { - sim_debug(IMP_DBG_UDP, dptr, "link %d - received packet discarded (no buffer available)\n", link); - return implen; - } - - // Copy the data to the H316 memory and we're done! - sim_debug(IMP_DBG_UDP, dptr, "link %d - packet received (sequence=%d, length=%d)\n", link, pktseq, pktlen); - for (i = 0; i < (implen < maxbuf ? implen : maxbuf); ++i) - *pdata++ = ntohs(pkt.data[i]); - return implen; - } - - // Here if pktlen <= 0 ... - return pktlen; -} - -#endif // ifdef VM_IMPTIP diff --git a/I1401/i1401_cd.c b/I1401/i1401_cd.c deleted file mode 100644 index a2aa2597..00000000 --- a/I1401/i1401_cd.c +++ /dev/null @@ -1,586 +0,0 @@ -/* i1401_cd.c: IBM 1402 card reader/punch - - Copyright (c) 1993-2017, 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 - stack stackers (5 units) - 0 normal - 1 1 - 2 2/8 - 3 unused - 4 4 - - Cards are represented as ASCII text streams terminated by newlines. - This allows cards to be created and edited as normal files. - - 09-Mar-17 RMS Protect character conversions from gargage files (COVERITY) - 05-May-16 RMS Fixed calling sequence inconsistency (Mark Pizzolato) - 28-Feb-15 RMS Added read from console - 24-Mar-09 RMS Fixed read stacker operation in column binary mode - Fixed punch stacker operation (Van Snyder) - 28-Jun-07 RMS Added support for SS overlap modifiers - 19-Jan-07 RMS Added UNIT_TEXT flag - 20-Sep-05 RMS Revised for new code tables, compatible colbinary treatment - 30-Aug-05 RMS Fixed read, punch to ignore modifier on 1,4 char inst - (Van Snyder) - 14-Nov-04 WVS Added column binary support - 25-Apr-03 RMS Revised for extended file support - 30-May-02 RMS Widened POS to 32b - 30-Jan-02 RMS New zero footprint card bootstrap (Van Snyder) - 29-Nov-01 RMS Added read only unit support - 13-Apr-01 RMS Revised for register arrays -*/ - -/* Read from console was requested by the 1401 restoration team at the - Computer History Museum. It allows small programs to be entered - quickly, without creating card files. Unfortunately, if input is - coming from the keyboard, then the card reader is not attached, - and it won't boot. - - To deal with this problem, the card reader must keep various - unit flags in a consistent state: - - ATTABLE? ATT? DFLT? state - - 0 0 0 impossible - 0 0 1 input from console - 0 1 0 impossible - 0 1 1 impossible - 1 0 0 waiting for file - 1 0 1 impossible - 1 1 0 input from file - 1 1 1 input from file, - default to console - after detach - - To maintain this state, starting from 100, means the - following: - - SET CDR DFLT set default flag - if !ATT, clear ATTABLE - SET CDR NODFLT clear default flag - ATTACH CDR set ATTABLE, attach - if error && DFLT, clear ATTABLE - DETACH CDR detach - if DFLT, clear ATTABLE -*/ - -#include "i1401_defs.h" -#include - -#define UNIT_V_PCH (UNIT_V_UF + 0) /* output conv */ -#define UNIT_PCH (1 << UNIT_V_PCH) -#define UNIT_V_CONS (UNIT_V_UF + 1) /* input from console */ -#define UNIT_CONS (1 << UNIT_V_CONS) - -extern uint8 M[]; -extern int32 ind[64], ssa, iochk; -extern int32 conv_old; - -int32 s1sel, s2sel, s4sel, s8sel; -char cdr_buf[(2 * CBUFSIZE) + 1]; /* > CDR_WIDTH */ -char cdp_buf[(2 * CDP_WIDTH) + 1]; /* + null */ -int32 cdp_buf_full = 0; /* punch buf full? */ - -t_stat cdr_svc (UNIT *uptr); -t_stat cdr_boot (int32 unitno, DEVICE *dptr); -t_stat cdr_attach (UNIT *uptr, char *cptr); -t_stat cdr_detach (UNIT *uptr); -t_stat cdp_attach (UNIT *uptr, char *cptr); -t_stat cdp_detach (UNIT *uptr); -t_stat cdp_npr (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cd_reset (DEVICE *dptr); -t_stat cdr_read_file (char *buf, int32 sz); -t_stat cdr_read_cons (char *buf, int32 sz); -t_stat cdr_chg_cons (UNIT *uptr, int32 val, char *cptr, void *desc); -int32 bcd2asc (int32 c, UNIT *uptr); -char colbin_to_bcd (uint32 cb); - -extern void inq_puts (char *cptr); - -/* 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+UNIT_ROABLE+UNIT_TEXT, 0), 100 - }; - -REG cdr_reg[] = { - { FLDATA (LAST, ind[IN_LST], 0) }, - { FLDATA (ERR, ind[IN_READ], 0) }, - { FLDATA (S1, s1sel, 0) }, - { FLDATA (S2, s2sel, 0) }, - { DRDATA (POS, cdr_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, cdr_unit.wait, 24), PV_LEFT }, - { BRDATA (BUF, cdr_buf, 8, 8, CDR_WIDTH * 2) }, - { NULL } - }; - -MTAB cdr_mod[] = { - { UNIT_CONS, UNIT_CONS, "default to console", "DEFAULT", &cdr_chg_cons }, - { UNIT_CONS, 0 , "no default device", "NODEFAULT", &cdr_chg_cons }, - { 0 } - }; - -DEVICE cdr_dev = { - "CDR", &cdr_unit, cdr_reg, cdr_mod, - 1, 10, 31, 1, 8, 7, - NULL, NULL, &cd_reset, - &cdr_boot, &cdr_attach, &cdr_detach - }; - -/* 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+UNIT_TEXT, 0) - }; - -REG cdp_reg[] = { - { FLDATA (ERR, ind[IN_PNCH], 0) }, - { FLDATA (S4, s4sel, 0) }, - { FLDATA (S8, s8sel, 0) }, - { DRDATA (POS, cdp_unit.pos, T_ADDR_W), PV_LEFT }, - { BRDATA (BUF, cdp_buf, 8, 8, CDP_WIDTH * 2) }, - { FLDATA (FULL, cdp_buf_full, 0) }, - { NULL } - }; - -MTAB cdp_mod[] = { - { UNIT_PCH, 0, "business set", "BUSINESS" }, - { UNIT_PCH, UNIT_PCH, "Fortran set", "FORTRAN" }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "NPR", - &cdp_npr, NULL }, - { 0 } - }; - -DEVICE cdp_dev = { - "CDP", &cdp_unit, cdp_reg, cdp_mod, - 1, 10, 31, 1, 8, 7, - NULL, NULL, &cd_reset, - NULL, &cdp_attach, &cdp_detach - }; - -/* 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+UNIT_TEXT, 0) }, - { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0) }, - { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0) }, - { UDATA (NULL, UNIT_DIS, 0) }, /* unused */ - { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0) } - }; - -REG stack_reg[] = { - { DRDATA (POS0, stack_unit[0].pos, T_ADDR_W), PV_LEFT }, - { DRDATA (POS1, stack_unit[1].pos, T_ADDR_W), PV_LEFT }, - { DRDATA (POS28, stack_unit[2].pos, T_ADDR_W), PV_LEFT }, - { DRDATA (POS4, stack_unit[4].pos, T_ADDR_W), PV_LEFT }, - { NULL } - }; - -DEVICE stack_dev = { - "STKR", stack_unit, stack_reg, NULL, - 5, 10, 31, 1, 8, 7, - NULL, NULL, &cd_reset, - NULL, NULL, NULL - }; - -/* Card read routine - - Modifiers have been checked by the caller - C modifier is recognized (column binary is implemented) -*/ - -t_stat read_card (int32 ilnt, int32 mod) -{ -int32 i, cbn, c1, c2, cbufsz; -t_stat r; - -if (sim_is_active (&cdr_unit)) { /* busy? */ - sim_cancel (&cdr_unit); /* cancel */ - if (r = cdr_svc (&cdr_unit)) /* process */ - return r; - } -ind[IN_READ] = ind[IN_LST] = s1sel = s2sel = 0; /* default stacker */ -cbn = ((ilnt == 2) || (ilnt == 5)) && (mod == BCD_C); /* col binary? */ -cbufsz = (cbn)? 2 * CBUFSIZE: CBUFSIZE; /* buffer size */ -for (i = 0; i < (2 * CBUFSIZE) + 1; i++) /* clear extended buf */ - cdr_buf[i] = 0; -if ((cdr_unit.flags & UNIT_ATT) != 0) /* attached? */ - r = cdr_read_file (cdr_buf, cbufsz); /* read from file */ -else if ((cdr_unit.flags & UNIT_CONS) != 0) /* default to console? */ - r = cdr_read_cons (cdr_buf, cbufsz); /* read from console */ -else return SCPE_UNATT; /* else can't read */ -if (r != SCPE_OK) /* read error? */ - return r; /* can't read */ -if (cbn) { /* column binary? */ - for (i = 0; i < CDR_WIDTH; i++) { - if (conv_old) { - c1 = ascii2bcd (cdr_buf[i] & 0177); - c2 = ascii2bcd (cdr_buf[CDR_WIDTH + i] & 0177); - } - else { - c1 = ascii2bcd (cdr_buf[2 * i] & 0177); - c2 = ascii2bcd (cdr_buf[(2 * i) + 1] & 0177); - } - M[CD_CBUF1 + i] = (M[CD_CBUF1 + i] & WM) | c1; - M[CD_CBUF2 + i] = (M[CD_CBUF2 + i] & WM) | c2; - M[CDR_BUF + i] = colbin_to_bcd ((c1 << 6) | c2); - } - } /* end if col bin */ -else { /* normal read */ - for (i = 0; i < CDR_WIDTH; i++) { /* cvt to BCD */ - c1 = ascii2bcd (cdr_buf[i]); - M[CDR_BUF + i] = (M[CDR_BUF + i] & WM) | c1; - } - } -M[CDR_BUF - 1] = 060; /* mem mark */ -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. - - The original card buffer (cdr_buf) has not been changed from its input - format (ASCII text), with its newline attached. There is a guaranteed - null at the end, because the buffer was zeroed prior to the read, and - is one character longer than the maximum string length. -*/ - -t_stat cdr_svc (UNIT *uptr) -{ -if (s1sel) /* stacker 1? */ - uptr = &stack_unit[1]; -else if (s2sel) /* stacker 2? */ - uptr = &stack_unit[2]; -else uptr = &stack_unit[0]; /* then default */ -if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ - return SCPE_OK; -fputs (cdr_buf, uptr->fileref); /* write card */ -uptr->pos = ftell (uptr->fileref); /* update position */ -if (ferror (uptr->fileref)) { /* error? */ - perror ("Card stacker I/O error"); - clearerr (uptr->fileref); - if (iochk) - return SCPE_IOERR; - } -return SCPE_OK; -} - -/* Card punch routine - - Modifiers have been checked by the caller - C modifier is recognized (column binary is implemented) - - - Run out any previously buffered card - - Clear stacker select - - Copy card from memory buffer to punch buffer -*/ - -t_stat punch_card (int32 ilnt, int32 mod) -{ -int32 i, cbn, c1, c2; -t_bool use_h; -t_stat r; - -r = cdp_npr (NULL, 0, NULL, NULL); /* write card */ -if (r != SCPE_OK) - return r; -use_h = cdp_unit.flags & UNIT_PCH; -ind[IN_PNCH] = s4sel = s8sel = 0; /* clear flags */ -cbn = ((ilnt == 2) || (ilnt == 5)) && (mod == BCD_C); /* col binary? */ - -M[CDP_BUF - 1] = 012; /* set prev loc */ -if (cbn) { /* column binary */ - for (i = 0; i < CDP_WIDTH; i++) { - c1 = bcd2ascii (M[CD_CBUF1 + i] & CHAR, use_h); - c2 = bcd2ascii (M[CD_CBUF2 + i] & CHAR, use_h); - if (conv_old) { - cdp_buf[i] = c1; - cdp_buf[i + CDP_WIDTH] = c2; - } - else { - cdp_buf[2 * i] = c1; - cdp_buf[(2 * i) + 1] = c2; - } - } - for (i = (2 * CDP_WIDTH) - 1; (i >= 0) && (cdp_buf[i] == ' '); i--) - cdp_buf[i] = 0; - cdp_buf[2 * CDP_WIDTH] = 0; /* trailing null */ - } -else { /* normal */ - for (i = 0; i < CDP_WIDTH; i++) - cdp_buf[i] = bcd2ascii (M[CDP_BUF + i] & CHAR, use_h); - for (i = CDP_WIDTH - 1; (i >= 0) && (cdp_buf[i] == ' '); i--) - cdp_buf[i] = 0; - cdp_buf[CDP_WIDTH] = 0; /* trailing null */ - } -cdp_buf_full = 1; /* card buffer full */ -return SCPE_OK; -} - -/* Punch buffered card (also handles non-process runout button) */ - -t_stat cdp_npr (UNIT *notused, int32 val, char *cptr, void *desc) -{ -UNIT *uptr; - -if (cdp_buf_full == 0) /* any card? */ - return SCPE_OK; /* no, done */ -cdp_buf_full = 0; /* buf empty */ -if (s8sel) /* stack 8? */ - uptr = &stack_unit[2]; -else if (s4sel) /* stack 4? */ - uptr = &stack_unit[4]; -else uptr = &cdp_unit; /* normal output */ -if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ - return SCPE_UNATT; -fputs (cdp_buf, uptr->fileref); /* output card */ -fputc ('\n', uptr->fileref); /* plus new line */ -uptr->pos = ftell (uptr->fileref); /* update position */ -if (ferror (uptr->fileref)) { /* error? */ - perror ("Card punch I/O error"); - clearerr (uptr->fileref); - if (iochk) - return SCPE_IOERR; - ind[IN_PNCH] = 1; - } -return SCPE_OK; -} - -/* Select stack routine - - Modifiers have been checked by the caller - Modifiers are 1, 2, 4, 8 for the respective stack, - or $, ., square for overlap control (ignored). -*/ - -t_stat select_stack (int32 mod) -{ -if (mod == BCD_ONE) - s1sel = 1; -else if (mod == BCD_TWO) - s2sel = 1; -else if (mod == BCD_FOUR) - s4sel = 1; -else if (mod == BCD_EIGHT) - s8sel = 1; -return SCPE_OK; -} - -/* Read card from file */ - -t_stat cdr_read_file (char *buf, int32 sz) -{ -fgets (buf, sz, cdr_unit.fileref); /* rd bin/char card */ -if (feof (cdr_unit.fileref)) /* eof? */ - return STOP_NOCD; -if (ferror (cdr_unit.fileref)) { /* error? */ - ind[IN_READ] = 1; - perror ("Card reader I/O error"); - clearerr (cdr_unit.fileref); - if (iochk) - return SCPE_IOERR; - return SCPE_OK; - } -cdr_unit.pos = ftell (cdr_unit.fileref); /* update position */ -if (ssa) { /* if last cd on */ - getc (cdr_unit.fileref); /* see if more */ - if (feof (cdr_unit.fileref)) /* eof? set flag */ - ind[IN_LST] = 1; - fseek (cdr_unit.fileref, cdr_unit.pos, SEEK_SET); - } -return SCPE_OK; -} - -/* Read card from console */ - -t_stat cdr_read_cons (char *buf, int32 sz) -{ -int32 i, t; - -inq_puts ("[Enter card]\r\n"); -for (i = 0; i < sz; ) { - while (((t = sim_poll_kbd ()) == SCPE_OK) || /* wait for char */ - (t & SCPE_BREAK)) { - if (stop_cpu) /* stop? */ - return t; - } - if (t < SCPE_KFLAG) /* error? */ - return t; - t = t & 0177; - if ((t == '\r') || (t == '\n')) /* eol? */ - break; - if (t == 0177) { /* rubout? */ - if (i != 0) { /* anything? */ - buf[--i] = 0; - sim_putchar ('\\'); - } - } - else { - sim_putchar (t); - buf[i++] = t; - } - } -inq_puts ("\r\n"); -return SCPE_OK; -} - -/* Card reader/punch reset */ - -t_stat cd_reset (DEVICE *dptr) -{ -ind[IN_LST] = ind[IN_READ] = ind[IN_PNCH] = 0; /* clear indicators */ -s1sel = s2sel = s4sel = s8sel = 0; /* clear stacker sel */ -sim_cancel (&cdr_unit); /* clear reader event */ -return SCPE_OK; -} - -/* Set/clear default to console flag - - Caller will do actual bit field update on successful return */ - -t_stat cdr_chg_cons (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (val == 0) /* clear? */ - cdr_unit.flags |= UNIT_ATTABLE; /* attachable on */ -else if ((cdr_unit.flags & UNIT_ATT) == 0) /* set, unattached? */ - cdr_unit.flags &= ~UNIT_ATTABLE; /* attachable off */ -return SCPE_OK; -} - -/* Card reader attach */ - -t_stat cdr_attach (UNIT *uptr, char *cptr) -{ -t_stat r; - -ind[IN_LST] = ind[IN_READ] = 0; /* clear last card */ -cdr_unit.flags |= UNIT_ATTABLE; /* must be attachable */ -r = attach_unit (uptr, cptr); /* do attach */ -if ((r != SCPE_OK) && ((cdr_unit.flags & UNIT_CONS) != 0)) /* failed, default? */ - cdr_unit.flags &= ~UNIT_ATTABLE; /* clear attachable */ -return r; -} - -/* Card reader detach */ - -t_stat cdr_detach (UNIT *uptr) -{ -t_stat r; - -cdr_unit.flags |= UNIT_ATTABLE; /* must be attachable */ -r = detach_unit (uptr); /* detach */ -if (((cdr_unit.flags & UNIT_ATT) == 0) && /* attached clear? */ - ((cdr_unit.flags & UNIT_CONS) != 0)) /* default on? */ - cdr_unit.flags &= ~UNIT_ATTABLE; /* clear attachable */ -return r; -} - -/* Bootstrap routine */ - -#define BOOT_START 0 -#define BOOT_LEN (sizeof (boot_rom) / sizeof (unsigned char)) - -static const unsigned char boot_rom[] = { - OP_R + WM, OP_NOP + WM /* R, NOP */ - }; - -t_stat cdr_boot (int32 unitno, DEVICE *dptr) -{ -int32 i; -extern int32 saved_IS; - -for (i = 0; i < CDR_WIDTH; i++) /* clear buffer */ - M[CDR_BUF + i] = 0; -for (i = 0; i < BOOT_LEN; i++) - M[BOOT_START + i] = boot_rom[i]; -saved_IS = BOOT_START; -return SCPE_OK; -} - -/* Card punch attach */ - -t_stat cdp_attach (UNIT *uptr, char *cptr) -{ -cdp_buf_full = 0; -return attach_unit (uptr, cptr); -} - -/* Card punch detach */ - -t_stat cdp_detach (UNIT *uptr) -{ -t_stat r; - -r = cdp_npr (NULL, 0, NULL, NULL); -if (r != SCPE_OK) - return r; -return detach_unit (uptr); -} - -/* Column binary to BCD - - This is based on documentation in the IBM 1620 manual and may not be - accurate for the 7094. Each row (12,11,0,1..9) is interpreted as a bit - pattern, and the appropriate bits are set. (Double punches inclusive - OR, eg, 1,8,9 is 9.) On the 1620, double punch errors are detected; - since the 7094 only reads column binary, double punches are ignored. - - Bit order, left to right, is 12, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. - The for loop works right to left, so the table is reversed. */ - -static const char row_val[12] = { - 011, 010, 007, 006, 005, 004, - 003, 002, 001, 020, 040, 060 - }; - -char colbin_to_bcd (uint32 cb) -{ -uint32 i; -char bcd; - -for (i = 0, bcd = 0; i < 12; i++) { /* 'sum' rows */ - if (cb & (1 << i)) - bcd |= row_val[i]; - } -return bcd; -} diff --git a/I1401/i1401_cpu.c b/I1401/i1401_cpu.c deleted file mode 100644 index 2d6c9b9d..00000000 --- a/I1401/i1401_cpu.c +++ /dev/null @@ -1,1968 +0,0 @@ -/* i1401_cpu.c: IBM 1401 CPU simulator - - Copyright (c) 1993-2017, 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. - - 13-Mar-17 RMS Fixed MTF length checking (COVERITY) - 30-Jan-15 RMS Fixed treatment of overflow (Ken Shirriff) - 08-Oct-12 RMS Clear storage and branch preserves B register (Van Snyder) - 19-Mar-11 RMS Reverted multiple tape indicator implementation - 20-Jan-11 RMS Fixed branch on EOT indicator per hardware (Van Snyder) - 07-Nov-10 RMS Fixed divide not to clear word marks in quotient - 24-Apr-10 RMS Revised divide algorithm (Van Snyder) - 11-Jul-08 RMS Added missing A magtape modifier (Van Snyder) - Fixed tape indicator implementation (Bob Abeles) - Fixed bug in ZA and ZS (Bob Abeles) - 07-Jul-07 RMS Removed restriction on load-mode binary tape - 28-Jun-07 RMS Added support for SS overlap modifiers - 22-May-06 RMS Fixed format error in CPU history (Peter Schorn) - 06-Mar-06 RMS Fixed bug in divide (Van Snyder) - 22-Sep-05 RMS Fixed declarations (Sterling Garwood) - 01-Sep-05 RMS Removed error stops in MCE - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 02-Jun-05 RMS Fixed SSB-SSG clearing on RESET (Ralph Reinke) - 14-Nov-04 WVS Added column binary support, debug support - 06-Nov-04 RMS Added instruction history - 12-Jul-03 RMS Moved ASCII/BCD tables to included file - Revised fetch to model hardware - Removed length checking in fetch phase - 16-Mar-03 RMS Fixed mnemonic, instruction lengths, and reverse - scan length check bug for MCS - Fixed MCE bug, BS off by 1 if zero suppress - Fixed chaining bug, D lost if return to SCP - Fixed H branch, branch occurs after continue - Added check for invalid 8 character MCW, LCA - 03-Jun-03 RMS Added 1311 support - 22-May-02 RMS Added multiply and divide - 30-Dec-01 RMS Added old PC queue - 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 - -- 1 char B is chained BCE - -- MCE moves whole char after first - 14-Apr-99 RMS Changed t_addr to unsigned - - The register state for the IBM 1401 is: - - IS I storage address register (PC) - AS A storage address register (address of first operand) - BS B storage address register (address of second operand) - ind[0:63] indicators - SSA sense switch A - IOCHK I/O check - PRCHK process check - - The IBM 1401 is a variable instruction length, decimal data system. - Memory consists of 4000, 8000, 12000, or 16000 BCD characters, each - containing six bits of data and a word mark. There are no general - registers; all instructions are memory to memory, using explicit - addresses or an address pointer from a prior instruction. - - BCD numeric data consists of the low four bits of a character (DIGIT), - encoded as X, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, X, X, X, X, X. The high - two bits (ZONE) encode the sign of the data as +, +, -, +. Character - data uses all six bits of a character. Numeric and character fields are - delimited by a word mark. Fields are typically processed in descending - address order (low-order data to high-order data). - - The 1401 encodes a decimal address, and an index register number, in - three characters: - - character zone digit - addr + 0 <1:0> of thousands hundreds - addr + 1 index register # tens - addr + 2 <3:2> of thousands ones - - Normally the digit values 0, 11, 12, 13, 14, 15 are illegal in addresses. - However, in indexing, digits are passed through the adder, and illegal - values are normalized to legal counterparts. - - The 1401 has six instruction formats: - - op A and B addresses, if any, from AS and BS - op d A and B addresses, if any, from AS and BS - op aaa B address, if any, from BS - op aaa d B address, if any, from BS - op aaa bbb - op aaa bbb d - - where aaa is the A address, bbb is the B address, and d is a modifier. - The opcode has word mark set; all other characters have word mark clear. - - This routine is the instruction decode routine for the IBM 1401. - It is called from the simulator control program to execute - instructions in simulated memory, starting at the simulated PC. - It runs until 'reason' is set non-zero. - - General notes: - - 1. Reasons to stop. The simulator can be stopped by: - - HALT instruction - breakpoint encountered - illegal addresses or instruction formats - I/O error in I/O simulator - - 2. Interrupts. The 1401 has no interrupt structure. - - 3. Non-existent memory. On the 1401, references to non-existent - memory halt the processor. - - 4. Adding I/O devices. These modules must be modified: - - i1401_cpu.c add device dispatching code to iodisp - i1401_sys.c add sim_devices table entry -*/ - -#include "i1401_defs.h" -#include "i1401_dat.h" - -#define PCQ_SIZE 64 /* must be 2**n */ -#define PCQ_MASK (PCQ_SIZE - 1) -#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = saved_IS - -#define HIST_MIN 64 -#define HIST_MAX 65536 - -typedef struct { - uint16 is; - uint16 ilnt; - uint8 inst[MAX_L]; - } InstHistory; - -/* These macros validate addresses. If an addresses error is detected, - they return an error status to the caller. These macros should only - be used in a routine that returns a t_stat value. -*/ - -#define MM(x) x = x - 1; \ - if (x < 0) { \ - x = BA + MAXMEMSIZE - 1; \ - reason = STOP_WRAP; \ - break; \ - } - -#define PP(x) x = x + 1; \ - if (ADDR_ERR (x)) { \ - x = BA + (x % MAXMEMSIZE); \ - reason = STOP_WRAP; \ - break; \ - } - -#define BRANCH if (ADDR_ERR (AS)) { \ - reason = STOP_INVBR; \ - break; \ - } \ - if (cpu_unit.flags & XSA) \ - BS = IS; \ - else BS = BA + 0; \ - PCQ_ENTRY; \ - IS = AS; - -#define BRANCH_CS if (ADDR_ERR (AS)) { \ - reason = STOP_INVBR; \ - break; \ - } \ - PCQ_ENTRY; \ - IS = AS; - - -uint8 M[MAXMEMSIZE] = { 0 }; /* main memory */ -int32 saved_IS = 0; /* saved IS */ -int32 AS = 0; /* AS */ -int32 BS = 0; /* BS */ -int32 D = 0; /* modifier */ -int32 as_err = 0, bs_err = 0; /* error flags */ -int32 hb_pend = 0; /* halt br pending */ -uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ -int32 pcq_p = 0; /* PC queue ptr */ -REG *pcq_r = NULL; /* PC queue reg ptr */ -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 hst_p = 0; /* history pointer */ -int32 hst_lnt = 0; /* history length */ -InstHistory *hst = NULL; /* instruction history */ -t_bool conv_old = 0; /* old conversions */ - -extern int32 sim_emax; - -t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); -t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); -t_stat cpu_reset (DEVICE *dptr); -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat cpu_set_conv (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_show_conv (FILE *st, UNIT *uptr, int32 val, void *desc); -int32 store_addr_h (int32 addr); -int32 store_addr_t (int32 addr); -int32 store_addr_u (int32 addr); -int32 div_add (int32 ap, int32 bp); -int32 div_sub (int32 ap, int32 bp); -void div_sign (int32 dvrc, int32 dvdc, int32 qp, int32 rp); -t_stat iomod (int32 ilnt, int32 mod, const int32 *tptr); -t_stat iodisp (int32 dev, int32 unit, int32 flag, int32 mod); - -extern t_stat read_card (int32 ilnt, int32 mod); -extern t_stat punch_card (int32 ilnt, int32 mod); -extern t_stat select_stack (int32 mod); -extern t_stat carriage_control (int32 mod); -extern t_stat write_line (int32 ilnt, int32 mod); -extern t_stat inq_io (int32 flag, int32 mod); -extern t_stat mt_io (int32 unit, int32 flag, int32 mod); -extern t_stat dp_io (int32 fnc, int32 flag, int32 mod); -extern t_stat mt_func (int32 unit, int32 flag, int32 mod); - -/* CPU data structures - - cpu_dev CPU device descriptor - cpu_unit CPU unit descriptor - cpu_reg CPU register list - cpu_mod CPU modifier list -*/ - -UNIT cpu_unit = { - UDATA (NULL, UNIT_FIX + UNIT_BCD + STDOPT, MAXMEMSIZE) - }; - -REG cpu_reg[] = { - { DRDATA (IS, saved_IS, 14), PV_LEFT }, - { DRDATA (AS, AS, 14), PV_LEFT }, - { DRDATA (BS, BS, 14), PV_LEFT }, - { FLDATA (ASERR, as_err, 0) }, - { FLDATA (BSERR, bs_err, 0) }, - { ORDATA (D, D, 7) }, - { FLDATA (SSA, ssa, 0) }, - { FLDATA (SSB, ind[IN_SSB], 0) }, - { FLDATA (SSC, ind[IN_SSC], 0) }, - { FLDATA (SSD, ind[IN_SSD], 0) }, - { FLDATA (SSE, ind[IN_SSE], 0) }, - { FLDATA (SSF, ind[IN_SSF], 0) }, - { FLDATA (SSG, ind[IN_SSG], 0) }, - { FLDATA (EQU, ind[IN_EQU], 0) }, - { FLDATA (UNEQ, ind[IN_UNQ], 0) }, - { FLDATA (HIGH, ind[IN_HGH], 0) }, - { FLDATA (LOW, ind[IN_LOW], 0) }, - { FLDATA (OVF, ind[IN_OVF], 0) }, - { FLDATA (IOCHK, iochk, 0) }, - { FLDATA (PRCHK, prchk, 0) }, - { FLDATA (HBPEND, hb_pend, 0) }, - { BRDATA (IND, ind, 8, 32, 64), REG_HIDDEN + PV_LEFT }, - { BRDATA (ISQ, pcq, 10, 14, PCQ_SIZE), REG_RO+REG_CIRC }, - { DRDATA (ISQP, pcq_p, 6), REG_HRO }, - { ORDATA (WRU, sim_int_char, 8) }, - { FLDATA (CONVOLD, conv_old, 0), REG_HIDDEN }, - { NULL } - }; - -MTAB cpu_mod[] = { - { XSA, XSA, "XSA", "XSA", NULL }, - { XSA, 0, "no XSA", "NOXSA", NULL }, - { HLE, HLE, "HLE", "HLE", NULL }, - { HLE, 0, "no HLE", "NOHLE", NULL }, - { BBE, BBE, "BBE", "BBE", NULL }, - { BBE, 0, "no BBE", "NOBBE", NULL }, - { MA, MA, "MA", 0, NULL }, - { MA, 0, "no MA", 0, NULL }, - { MR, MR, "MR", "MR", NULL }, - { MR, 0, "no MR", "NOMR", NULL }, - { EPE, EPE, "EPE", "EPE", NULL }, - { EPE, 0, "no EPE", "NOEPE", NULL }, - { MDV, MDV, "MDV", "MDV", NULL }, - { MDV, 0, "no MDV", "NOMDV", NULL }, - { UNIT_MSIZE, 4000, NULL, "4K", &cpu_set_size }, - { UNIT_MSIZE, 8000, NULL, "8K", &cpu_set_size }, - { UNIT_MSIZE, 12000, NULL, "12K", &cpu_set_size }, - { UNIT_MSIZE, 16000, NULL, "16K", &cpu_set_size }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", - &cpu_set_hist, &cpu_show_hist }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "CONVERSIONS", "NEWCONVERSIONS", - &cpu_set_conv, &cpu_show_conv }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO, 1, NULL, "OLDCONVERSIONS", - &cpu_set_conv, NULL }, - { 0 } - }; - -DEVICE cpu_dev = { - "CPU", &cpu_unit, cpu_reg, cpu_mod, - 1, 10, 14, 1, 8, 7, - &cpu_ex, &cpu_dep, &cpu_reset, - NULL, NULL, NULL, - NULL, DEV_DEBUG - }; - -/* Tables */ - -/* Opcode table - length, dispatch, and option flags. This table is - used by the symbolic input routine to validate instruction lengths */ - -const int32 op_table[64] = { - 0, /* 00: illegal */ - L1 | L2 | L4 | L5, /* read */ - L1 | L2 | L4 | L5, /* write */ - L1 | L2 | L4 | L5, /* write and read */ - L1 | L2 | L4 | L5, /* punch */ - L1 | L4, /* read and punch */ - L1 | L2 | L4 | L5, /* write and punch */ - L1 | L2 | L4 | L5, /* write, read, punch */ - L1, /* 10: read feed */ - L1, /* punch feed */ - 0, /* illegal */ - L1 | L4 | L7 | AREQ | BREQ | MA, /* modify address */ - L1 | L4 | L7 | AREQ | BREQ | MDV, /* multiply */ - 0, /* illegal */ - 0, /* illegal */ - 0, /* illegal */ - 0, /* 20: illegal */ - L1 | L4 | L7 | BREQ | NOWM, /* clear storage */ - L1 | L4 | L7 | AREQ | BREQ, /* subtract */ - 0, /* illegal */ - L5 | IO, /* magtape */ - L1 | L8 | BREQ, /* branch wm or zone */ - L1 | L8 | BREQ | BBE, /* branch if bit eq */ - 0, /* illegal */ - L1 | L4 | L7 | AREQ | BREQ, /* 30: move zones */ - L1 | L4 | L7 | AREQ | BREQ, /* move supress zero */ - 0, /* illegal */ - L1 | L4 | L7 | AREQ | BREQ | NOWM, /* set word mark */ - L1 | L4 | L7 | AREQ | BREQ | MDV, /* divide */ - 0, /* illegal */ - 0, /* illegal */ - 0, /* illegal */ - 0, /* 40: illegal */ - 0, /* illegal */ - L2 | L5, /* select stacker */ - L1 | L4 | L7 | L8 | BREQ | MLS | IO, /* load */ - L1 | L4 | L7 | L8 | BREQ | MLS | IO, /* move */ - HNOP | L1 | L2 | L4 | L5 | L7 | L8, /* nop */ - 0, /* illegal */ - L1 | L4 | L7 | AREQ | BREQ | MR, /* move to record */ - L1 | L4 | AREQ | MLS, /* 50: store A addr */ - 0, /* illegal */ - L1 | L4 | L7 | AREQ | BREQ, /* zero and subtract */ - 0, /* illegal */ - 0, /* illegal */ - 0, /* illegal */ - 0, /* illegal */ - 0, /* illegal */ - 0, /* 60: illegal */ - L1 | L4 | L7 | AREQ | BREQ, /* add */ - L1 | L4 | L5 | L8, /* branch */ - L1 | L4 | L7 | AREQ | BREQ, /* compare */ - L1 | L4 | L7 | AREQ | BREQ, /* move numeric */ - L1 | L4 | L7 | AREQ | BREQ, /* move char edit */ - L2 | L5, /* carriage control */ - 0, /* illegal */ - L1 | L4 | L7 | AREQ | MLS, /* 70: store B addr */ - 0, /* illegal */ - L1 | L4 | L7 | AREQ | BREQ, /* zero and add */ - HNOP | L1 | L2 | L4 | L5 | L7 | L8, /* halt */ - L1 | L4 | L7 | AREQ | BREQ, /* clear word mark */ - 0, /* illegal */ - 0, /* illegal */ - 0 /* illegal */ - }; - -const int32 len_table[9] = { 0, L1, L2, 0, L4, L5, 0, L7, L8 }; - -/* Address character conversion tables. Illegal characters are marked by - the flag BA but also contain the post-adder value for indexing */ - -const int32 hun_table[64] = { - BA+000, 100, 200, 300, 400, 500, 600, 700, - 800, 900, 000, BA+300, BA+400, BA+500, BA+600, BA+700, - BA+1000, 1100, 1200, 1300, 1400, 1500, 1600, 1700, - 1800, 1900, 1000, BA+1300, BA+1400, BA+1500, BA+1600, BA+1700, - BA+2000, 2100, 2200, 2300, 2400, 2500, 2600, 2700, - 2800, 2900, 2000, BA+2300, BA+2400, BA+2500, BA+2600, BA+2700, - BA+3000, 3100, 3200, 3300, 3400, 3500, 3600, 3700, - 3800, 3900, 3000, BA+3300, BA+3400, BA+3500, BA+3600, BA+3700 - }; - -const int32 ten_table[64] = { - BA+00, 10, 20, 30, 40, 50, 60, 70, - 80, 90, 00, BA+30, BA+40, BA+50, BA+60, BA+70, - X1+00, X1+10, X1+20, X1+30, X1+40, X1+50, X1+60, X1+70, - X1+80, X1+90, X1+00, X1+30, X1+40, X1+50, X1+60, X1+70, - X2+00, X2+10, X2+20, X2+30, X2+40, X2+50, X2+60, X2+70, - X2+80, X2+90, X2+00, X2+30, X2+40, X2+50, X2+60, X2+70, - X3+00, X3+10, X3+20, X3+30, X3+40, X3+50, X3+60, X3+70, - X3+80, X3+90, X3+00, X3+30, X3+40, X3+50, X3+60, X3+70 - }; - -const int32 one_table[64] = { - BA+0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 0, BA+3, BA+4, BA+5, BA+6, BA+7, - BA+4000, 4001, 4002, 4003, 4004, 4005, 4006, 4007, - 4008, 4009, 4000, BA+4003, BA+4004, BA+4005, BA+4006, BA+4007, - BA+8000, 8001, 8002, 8003, 8004, 8005, 8006, 8007, - 8008, 8009, 8000, BA+8003, BA+8004, BA+8005, BA+8006, BA+8007, - BA+12000, 12001, 12002, 12003, 12004, 12005, 12006, 12007, - 12008, 12009, 12000, BA+12003, BA+12004, BA+12005, BA+12006, BA+12007 - }; - -const int32 bin_to_bcd[16] = { - 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 - }; - -const int32 bcd_to_bin[16] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 3, 4, 5, 6, 7 - }; - -/* Indicator resets - a 1 marks an indicator that resets when tested */ - -static const int32 ind_table[64] = { - 0, 0, 0, 0, 0, 0, 0, 0, /* 00 - 07 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 10 - 17 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 27 */ - 0, 1, 1, 0, 1, 0, 0, 0, /* 30 - 37 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 40 - 47 */ - 0, 0, 1, 0, 1, 0, 0, 0, /* 50 - 57 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 60 - 67 */ - 0, 0, 1, 0, 0, 0, 0, 0 /* 70 - 77 */ - }; - -/* Character collation table for compare with HLE option */ - -static const int32 col_table[64] = { - 000, 067, 070, 071, 072, 073, 074, 075, - 076, 077, 066, 024, 025, 026, 027, 030, - 023, 015, 056, 057, 060, 061, 062, 063, - 064, 065, 055, 016, 017, 020, 021, 022, - 014, 044, 045, 046, 047, 050, 051, 052, - 053, 054, 043, 007, 010, 011, 012, 013, - 006, 032, 033, 034, 035, 036, 037, 040, - 041, 042, 031, 001, 002, 003, 004, 005 - }; - -/* Summing table for two decimal digits, converted back to BCD - Also used for multiplying two decimal digits, converted back to BCD, - with carry forward -*/ - -static const int32 sum_table[100] = { - BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR, - BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE, - BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR, - BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE, - BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR, - BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE, - BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR, - BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE, - BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR, - BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE, - BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR, - BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE, - BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR, - BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE, - BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR, - BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE, - BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR, - BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE, - BCD_ZERO, BCD_ONE, BCD_TWO, BCD_THREE, BCD_FOUR, - BCD_FIVE, BCD_SIX, BCD_SEVEN, BCD_EIGHT, BCD_NINE - }; - -static const int32 cry_table[100] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, - 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, - 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, - 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, - 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9 - }; - -/* Legal modifier tables */ - -static const int32 r_mod[] = { - BCD_C, -1 - }; -static const int32 p_mod[] = { - BCD_C, -1 - }; -static const int32 w_mod[] = { - BCD_S, BCD_SQUARE, -1 - }; -static const int32 ss_mod[] = { - BCD_ONE, BCD_TWO, BCD_FOUR, BCD_EIGHT, - BCD_DOLLAR, BCD_DECIMAL, BCD_SQUARE, -1 - }; -static const int32 mtf_mod[] = { - BCD_A, BCD_B, BCD_E, - BCD_M, BCD_R, BCD_U, -1 - }; - -t_stat sim_instr (void) -{ -int32 IS, ilnt, flags; -int32 op, xa, t, wm, ioind, dev, unit; -int32 a, b, i, k, asave, bsave; -int32 carry, lowprd, sign, ps; -int32 quo, qs; -int32 qzero, qawm, qbody, qsign, qdollar, qaster, qdecimal; -t_stat reason, r1, r2; - -/* Restore saved state */ - -IS = saved_IS; -if (as_err) /* flag bad addresses */ - AS = AS | BA; -if (bs_err) - BS = BS | BA; -as_err = bs_err = 0; /* reset error flags */ -reason = 0; - -/* Main instruction fetch/decode loop */ - -while (reason == 0) { /* loop until halted */ - - if (hb_pend) { /* halt br pending? */ - hb_pend = 0; /* clear flag */ - BRANCH; /* execute branch */ - } - - saved_IS = IS; /* commit prev instr */ - if (sim_interval <= 0) { /* check clock queue */ - if (reason = sim_process_event ()) - break; - } - - if (sim_brk_summ && sim_brk_test (IS, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; - } - - sim_interval = sim_interval - 1; - -/* Instruction fetch - 1401 fetch works as follows: - - - Each character fetched enters the B register. This register is not - visible; the variable t represents the B register. - - Except for the first and last cycles, each character fetched enters - the A register. This register is not visible; the variable D represents - the A register, because this is the instruction modifier for 2, 5, and 8 - character instructions. - - At the start of the second cycle (first address character), the A-address - register and, for most instructions, the B-address register, are cleared - to blanks. The simulator represents addresses in binary and creates the - effect of blanks (address is bad) if less than three A-address characters - are found. Further, the simulator accumulates only the A-address, and - replicates it to the B-address at the appropriate point. - - At the start of the fifth cycle (fourth address character), the B-address - register is cleared to blanks. Again, the simulator creates the effect of - blanks (address is bad) if less than three B-address characters are found. - - The 1401 does not explicitly check for valid instruction lengths. Most 2, - 3, 5, 6 character instructions will be invalid because the A-address or - B-address (or both) are invalid. -*/ - - if ((M[IS] & WM) == 0) { /* I-Op: WM under op? */ - reason = STOP_NOWM; /* no, error */ - break; - } - op = M[IS] & CHAR; /* get opcode */ - flags = op_table[op]; /* get op flags */ - if ((flags == 0) || (flags & ALLOPT & ~cpu_unit.flags)) { - reason = STOP_NXI; /* illegal inst? */ - break; - } - if (op == OP_SAR) /* SAR? save ASTAR */ - BS = AS; - PP (IS); - - if ((t = M[IS]) & WM) /* I-1: WM? 1 char inst */ - goto CHECK_LENGTH; - D = ioind = t; /* could be D char, % */ - AS = hun_table[t]; /* could be A addr */ - PP (IS); /* if %xy, BA is set */ - - if ((t = M[IS]) & WM) { /* I-2: WM? 2 char inst */ - AS = AS | BA; /* ASTAR bad */ - if (!(flags & MLS)) - BS = AS; - goto CHECK_LENGTH; - } - D = dev = t; /* could be D char, dev */ - AS = AS + ten_table[t]; /* build A addr */ - PP (IS); - - if ((t = M[IS]) & WM) { /* I-3: WM? 3 char inst */ - AS = AS | BA; /* ASTAR bad */ - if (!(flags & MLS)) - BS = AS; - goto CHECK_LENGTH; - } - D = unit = t; /* could be D char, unit */ - if (unit == BCD_ZERO) /* convert unit to binary */ - unit = 0; - AS = AS + one_table[t]; /* finish A addr */ - xa = (AS >> V_INDEX) & M_INDEX; /* get index reg */ - if (xa && (ioind != BCD_PERCNT) && (cpu_unit.flags & XSA)) { /* indexed? */ - AS = AS + hun_table[M[xa] & CHAR] + ten_table[M[xa + 1] & CHAR] + - one_table[M[xa + 2] & CHAR]; - AS = (AS & INDEXMASK) % MAXMEMSIZE; - } - if (!(flags & MLS)) /* not MLS? B = A */ - BS = AS; - PP (IS); - - if ((t = M[IS]) & WM) /* I-4: WM? 4 char inst */ - goto CHECK_LENGTH; - if ((op == OP_B) && (t == BCD_BLANK)) /* BR + space? */ - goto CHECK_LENGTH; - D = t; /* could be D char */ - BS = hun_table[t]; /* could be B addr */ - PP (IS); - - if ((t = M[IS]) & WM) { /* I-5: WM? 5 char inst */ - BS = BS | BA; /* BSTAR bad */ - goto CHECK_LENGTH; - } - D = t; /* could be D char */ - BS = BS + ten_table[t]; /* build B addr */ - PP (IS); - - if ((t = M[IS]) & WM) { /* I-6: WM? 6 char inst */ - BS = BS | BA; /* BSTAR bad */ - goto CHECK_LENGTH; - } - D = t; /* could be D char */ - BS = BS + one_table[t]; /* finish B addr */ - xa = (BS >> V_INDEX) & M_INDEX; /* get index reg */ - if (xa && (cpu_unit.flags & XSA)) { /* indexed? */ - BS = BS + hun_table[M[xa] & CHAR] + ten_table[M[xa + 1] & CHAR] + - one_table[M[xa + 2] & CHAR]; - BS = (BS & INDEXMASK) % MAXMEMSIZE; - } - PP (IS); - - if (flags & NOWM) /* I-7: SWM? done */ - goto CHECK_LENGTH; - if ((t = M[IS]) & WM) /* WM? 7 char inst */ - goto CHECK_LENGTH; - D = t; /* last char is D */ - while (((t = M[IS]) & WM) == 0) { /* I-8: repeats until WM */ - D = t; /* last char is D */ - PP (IS); - } - if (reason) /* addr err on last? */ - break; - -CHECK_LENGTH: - if ((flags & BREQ) && ADDR_ERR (BS)) { /* valid B? */ - reason = STOP_INVB; - break; - } - if ((flags & AREQ) && ADDR_ERR (AS)) { /* valid A? */ - reason = STOP_INVA; - break; - } - ilnt = IS - saved_IS; /* get lnt */ - if (hst_lnt) { /* history enabled? */ - hst_p = (hst_p + 1); /* next entry */ - if (hst_p >= hst_lnt) - hst_p = 0; - hst[hst_p].is = saved_IS; /* save IS */ - hst[hst_p].ilnt = ilnt; - for (i = 0; (i < MAX_L) && (i < ilnt); i++) - hst[hst_p].inst[i] = M[saved_IS + i]; - } - if (DEBUG_PRS (cpu_dev)) { - fprint_val (sim_deb, saved_IS, 10, 5, PV_RSPC); - fprintf (sim_deb, ": " ); - for (i = 0; i < sim_emax; i++) - sim_eval[i] = 0; - for (i = 0, k = saved_IS; i < sim_emax; i++, k++) { - if (cpu_ex (&sim_eval[i], k, &cpu_unit, 0) != SCPE_OK) - break; - } - fprint_sym (sim_deb, saved_IS, sim_eval, &cpu_unit, SWMASK('M')); - fprintf (sim_deb, "\n" ); - } - switch (op) { /* case on opcode */ - -/* Move/load character instructions A check B check - - MCW copy A to B, preserving B WM, here fetch - until either A or B WM - LCA copy A to B, overwriting B WM, here fetch - until A WM - - Instruction lengths: - - 1 chained A and B - 2,3 invalid A-address - 4 chained B address - 5,6 invalid B-address - checked in fetch - 7 normal - 8+ normal + modifier -*/ - - case OP_MCW: /* move char */ - if ((ilnt >= 4) && (ioind == BCD_PERCNT)) { /* I/O form? */ - reason = iodisp (dev, unit, MD_NORM, D); /* dispatch I/O */ - break; - } - if (ADDR_ERR (AS)) { /* check A addr */ - reason = STOP_INVA; - break; - } - do { - wm = M[AS] | M[BS]; - M[BS] = (M[BS] & WM) | (M[AS] & CHAR); /* move char */ - MM (AS); /* decr pointers */ - MM (BS); - } while ((wm & WM) == 0); /* stop on A,B WM */ - break; - - case OP_LCA: /* load char */ - if ((ilnt >= 4) && (ioind == BCD_PERCNT)) { /* I/O form? */ - reason = iodisp (dev, unit, MD_WM, D); - break; - } - if (ADDR_ERR (AS)) { /* check A addr */ - reason = STOP_INVA; - break; - } - do { - wm = M[BS] = M[AS]; /* move char + wmark */ - MM (AS); /* decr pointers */ - MM (BS); - } while ((wm & WM) == 0); /* stop on A WM */ - break; - -/* Other move instructions A check B check - - MCM copy A to B, preserving B WM, fetch fetch - until record or group mark - MCS copy A to B, clearing B WM, until A WM; fetch fetch - reverse scan and suppress leading zeroes - MN copy A char digit to B char digit, fetch fetch - preserving B zone and WM - MZ copy A char zone to B char zone, fetch fetch - preserving B digit and WM - - Instruction lengths: - - 1 chained - 2,3 invalid A-address - checked in fetch - 4 self (B-address = A-address) - 5,6 invalid B-address - checked in fetch - 7 normal - 8+ normal + ignored modifier -*/ - - case OP_MCM: /* move to rec/group */ - do { - t = M[AS]; - M[BS] = (M[BS] & WM) | (M[AS] & CHAR); /* move char */ - PP (AS); /* incr pointers */ - PP (BS); - } while (((t & CHAR) != BCD_RECMRK) && (t != (BCD_GRPMRK + WM))); - break; - - case OP_MCS: /* move suppress zero */ - bsave = BS; /* save B start */ - qzero = 1; /* set suppress */ - do { - wm = M[AS]; - M[BS] = M[AS] & ((BS != bsave)? CHAR: DIGIT);/* copy char */ - MM (AS); /* decr pointers */ - MM (BS); - } while ((wm & WM) == 0); /* stop on A WM */ - if (reason) /* addr err? stop */ - break; - do { - PP (BS); /* adv B */ - t = M[BS]; /* get B, cant be WM */ - if ((t == BCD_ZERO) || (t == BCD_COMMA)) { - if (qzero) - M[BS] = 0; - } - else if ((t == BCD_BLANK) || (t == BCD_MINUS)) ; - else if (((t == BCD_DECIMAL) && (cpu_unit.flags & EPE)) || - (t <= BCD_NINE)) - qzero = 0; - else qzero = 1; - } while (BS < bsave); - PP (BS); /* BS end is B+1 */ - break; - - case OP_MN: /* move numeric */ - M[BS] = (M[BS] & ~DIGIT) | (M[AS] & DIGIT); /* move digit */ - MM (AS); /* decr pointers */ - MM (BS); - break; - - case OP_MZ: /* move zone */ - M[BS] = (M[BS] & ~ZONE) | (M[AS] & ZONE); /* move high bits */ - MM (AS); /* decr pointers */ - MM (BS); - break; - -/* Branch instruction A check B check - - Instruction lengths: - - 1 branch if B char equals d, chained if branch here - 2,3 invalid B-address if branch here - 4 unconditional branch if branch - 5 branch if indicator[d] is set if branch - 6 invalid B-address if branch here - 7 branch if B char equals d, if branch here - d is last character of B-address - 8 branch if B char equals d if branch here -*/ - - case OP_B: /* branch */ - if (ilnt == 4) { /* uncond branch? */ - BRANCH; - } - else if (ilnt == 5) { /* branch on ind? */ - if (ind[D]) { /* test indicator */ - BRANCH; - } - if (ind_table[D]) /* reset if needed */ - ind[D] = 0; - } - else { /* branch char eq */ - if (ADDR_ERR (BS)) { /* validate B addr */ - reason = STOP_INVB; - break; - } - if ((M[BS] & CHAR) == D) { /* char equal? */ - BRANCH; - } - else { - MM (BS); - } - } - break; - -/* Other branch instructions A check B check - - BWZ branch if (d<0>: B char WM) if branch fetch - (d<1>: B char zone = d zone) - BBE branch if B char & d non-zero if branch fetch - - Instruction lengths: - 1 chained - 2,3 invalid A-address and B-address - 4 self (B-address = A-address, d = last character of A-address) - 5,6 invalid B-address - 7 normal, d = last character of B-address - 8+ normal -*/ - - case OP_BWZ: /* branch wm or zone */ - if (((D & 1) && (M[BS] & WM)) || /* d1? test wm */ - ((D & 2) && ((M[BS] & ZONE) == (D & ZONE)))) { /* d2? test zone */ - BRANCH; - } - else { /* decr pointer */ - MM (BS); - } - break; - - case OP_BBE: /* branch if bit eq */ - if (M[BS] & D & CHAR) { /* any bits set? */ - BRANCH; - } - else { /* decr pointer */ - MM (BS); - } - break; - -/* Arithmetic instructions A check B check - - ZA move A to B, normalizing A sign, fetch fetch - preserving B WM, until B WM - ZS move A to B, complementing A sign, fetch fetch - preserving B WM, until B WM - A add A to B fetch fetch - S subtract A from B fetch fetch - C compare A to B fetch fetch - - Instruction lengths: - - 1 chained - 2,3 invalid A-address - 4 self (B-address = A-address) - 5,6 invalid B-address - 7 normal - 8+ normal + ignored modifier - - Despite their names, ZA and ZS are not arithmetic instructions, but copies - with zone stripping. The adder is not used, so BCD conversions do not occur. -*/ - - case OP_ZA: case OP_ZS: /* zero and add/sub */ - a = i = 0; /* clear flags */ - do { - if (a & WM) /* A word mark? */ - wm = M[BS] = (M[BS] & WM) | BCD_ZERO; - else { - a = M[AS]; /* get A char */ - t = a & DIGIT; /* zap zone bits */ - wm = M[BS] = (M[BS] & WM) | t; /* store digit */ - MM (AS); - } - if (i == 0) - i = M[BS] = M[BS] | - ((((a & ZONE) == BBIT) ^ (op == OP_ZS))? BBIT: ZONE); - MM (BS); - } while ((wm & WM) == 0); /* stop on B WM */ - break; - - case OP_A: case OP_S: /* add/sub */ - bsave = BS; /* save sign pos */ - a = M[AS]; /* get A digit/sign */ - b = M[BS]; /* get B digit/sign */ - MM (AS); - qsign = ((a & ZONE) == BBIT) ^ ((b & ZONE) == BBIT) ^ (op == OP_S); - t = bcd_to_bin[a & DIGIT]; /* get A binary */ - t = bcd_to_bin[b & DIGIT] + (qsign? 10 - t: t); /* sum A + B */ - carry = (t >= 10); /* get carry */ - b = (b & ~DIGIT) | sum_table[t]; /* get result */ - if (qsign && ((b & BBIT) == 0)) /* normalize sign */ - b = b | ZONE; - M[BS] = b; /* store result */ - MM (BS); - if (b & WM) { /* b wm? done */ - if ((qsign != 0) && (carry == 0)) /* eff sub and no carry? */ - M[bsave] = WM + ((b & ZONE) ^ ABIT) + sum_table[10 - t]; - if ((qsign == 0) && (carry != 0)) /* eff add and carry */ - ind[IN_OVF] = 1; /* overflow */ - break; - } - do { - if (a & WM) /* A WM? char = 0 */ - a = WM; - else { - a = M[AS]; /* else get A */ - MM (AS); - } - b = M[BS]; /* get B */ - t = bcd_to_bin[a & DIGIT]; /* get A binary */ - t = bcd_to_bin[b & DIGIT] + (qsign? 9 - t: t) + carry; - carry = (t >= 10); /* get carry */ - if ((b & WM) && (qsign == 0)) { /* last, no recomp? */ - M[BS] = WM + sum_table[t] + /* zone add */ - (((a & ZONE) + b + (carry? ABIT: 0)) & ZONE); - if (carry != 0) /* carry out? */ - ind[IN_OVF] = 1; /* ovflo if carry */ - } - else M[BS] = (b & WM) + sum_table[t]; /* normal add */ - MM (BS); - } while ((b & WM) == 0); /* stop on B WM */ - if (reason) /* address err? */ - break; - if (qsign && (carry == 0)) { /* recompl, no carry? */ - M[bsave] = M[bsave] ^ ABIT; /* XOR sign */ - for (carry = 1; bsave != BS; --bsave) { /* rescan */ - t = 9 - bcd_to_bin[M[bsave] & DIGIT] + carry; - carry = (t >= 10); - M[bsave] = (M[bsave] & ~DIGIT) | sum_table[t]; - } - } - break; - - case OP_C: /* compare */ - if (ilnt != 1) { /* if not chained */ - ind[IN_EQU] = 1; /* clear indicators */ - ind[IN_UNQ] = ind[IN_HGH] = ind[IN_LOW] = 0; - } - do { - a = M[AS]; /* get characters */ - b = M[BS]; - wm = a | b; /* get word marks */ - if ((a & CHAR) != (b & CHAR)) { /* unequal? */ - ind[IN_EQU] = 0; /* set indicators */ - ind[IN_UNQ] = 1; - ind[IN_HGH] = col_table[b & CHAR] > col_table [a & CHAR]; - ind[IN_LOW] = ind[IN_HGH] ^ 1; - } - MM (AS); /* decr pointers */ - MM (BS); - } while ((wm & WM) == 0); /* stop on A, B WM */ - if ((a & WM) && !(b & WM)) { /* short A field? */ - ind[IN_EQU] = ind[IN_LOW] = 0; - ind[IN_UNQ] = ind[IN_HGH] = 1; - } - if (!(cpu_unit.flags & HLE)) /* no HLE? */ - ind[IN_EQU] = ind[IN_LOW] = ind[IN_HGH] = 0; - break; - -/* I/O instructions A check B check - - R read a card if branch - W write to line printer if branch - WR write and read if branch - P punch a card if branch - RP read and punch if branch - WP write and punch if branch - WRP write read and punch if branch - RF read feed (nop) - PF punch feed (nop) - SS select stacker if branch - CC carriage control if branch - - Instruction lengths: - - 1 normal - 2,3 normal, with modifier - 4 branch; modifier, if any, is last character of branch address - 5 branch + modifier - 6+ normal, with modifier -*/ - - case OP_R: /* read */ - if (reason = iomod (ilnt, D, r_mod)) /* valid modifier? */ - break; - reason = read_card (ilnt, D); /* read card */ - BS = CDR_BUF + CDR_WIDTH; - if ((ilnt == 4) || (ilnt == 5)) { /* check for branch */ - BRANCH; - } - break; - - case OP_W: /* write */ - if (reason = iomod (ilnt, D, w_mod)) /* valid modifier? */ - break; - reason = write_line (ilnt, D); /* print line */ - BS = LPT_BUF + LPT_WIDTH; - if ((ilnt == 4) || (ilnt == 5)) { /* check for branch */ - BRANCH; - } - break; - - case OP_P: /* punch */ - if (reason = iomod (ilnt, D, p_mod)) /* valid modifier? */ - break; - reason = punch_card (ilnt, D); /* punch card */ - BS = CDP_BUF + CDP_WIDTH; - if ((ilnt == 4) || (ilnt == 5)) { /* check for branch */ - BRANCH; - } - break; - - case OP_WR: /* write and read */ - if (reason = iomod (ilnt, D, w_mod)) /* valid modifier? */ - break; - reason = write_line (ilnt, D); /* print line */ - r1 = read_card (ilnt, D); /* read card */ - BS = CDR_BUF + CDR_WIDTH; - if ((ilnt == 4) || (ilnt == 5)) { /* check for branch */ - BRANCH; - } - if (reason == SCPE_OK) /* merge errors */ - reason = r1; - break; - - case OP_WP: /* write and punch */ - if (reason = iomod (ilnt, D, w_mod)) /* valid modifier? */ - break; - reason = write_line (ilnt, D); /* print line */ - r1 = punch_card (ilnt, D); /* punch card */ - BS = CDP_BUF + CDP_WIDTH; - if ((ilnt == 4) || (ilnt == 5)) { /* check for branch */ - BRANCH; - } - if (reason == SCPE_OK) /* merge errors */ - reason = r1; - break; - - case OP_RP: /* read and punch */ - if (reason = iomod (ilnt, D, NULL)) /* valid modifier? */ - break; - reason = read_card (ilnt, D); /* read card */ - r1 = punch_card (ilnt, D); /* punch card */ - BS = CDP_BUF + CDP_WIDTH; - if ((ilnt == 4) || (ilnt == 5)) { /* check for branch */ - BRANCH; - } - if (reason == SCPE_OK) /* merge errors */ - reason = r1; - break; - - case OP_WRP: /* write, read, punch */ - if (reason = iomod (ilnt, D, w_mod)) /* valid modifier? */ - break; - reason = write_line (ilnt, D); /* print line */ - r1 = read_card (ilnt, D); /* read card */ - r2 = punch_card (ilnt, D); /* punch card */ - BS = CDP_BUF + CDP_WIDTH; - if ((ilnt == 4) || (ilnt == 5)) { /* check for branch */ - BRANCH; - } - if (reason == SCPE_OK) /* merge errors */ - reason = (r1 == SCPE_OK)? r2: r1; - break; - - case OP_SS: /* select stacker */ - if (reason = iomod (ilnt, D, ss_mod)) /* valid modifier? */ - break; - if (reason = select_stack (D)) /* sel stack, error? */ - break; - if ((ilnt == 4) || (ilnt == 5)) { /* check for branch */ - BRANCH; - } - break; - - case OP_CC: /* carriage control */ - if (reason = carriage_control (D)) /* car ctrl, error? */ - break; - if ((ilnt == 4) || (ilnt == 5)) { /* check for branch */ - BRANCH; - } - break; - -/* MTF - magtape functions - must be at least 4 characters - - Instruction lengths: - - 1-3 invalid I/O address - checked here - 4 normal, d-character is unit - 5 normal, d-character is last character - 6+ normal, d-character is last character -*/ - - case OP_MTF: /* magtape function */ - if (ilnt < 4) { /* too short? */ - reason = STOP_INVL; - break; - } - if (ioind != BCD_PERCNT) { /* valid dev addr? */ - reason = STOP_INVA; - break; - } - if (reason = iomod (ilnt, D, mtf_mod)) /* valid modifier? */ - break; - - if (dev == IO_MT) /* BCD? */ - reason = mt_func (unit, 0, D); - else if (dev == IO_MTB) /* binary? */ - reason = mt_func (unit, MD_BIN, D); - else reason = STOP_INVA; /* wrong device */ - break; /* can't branch */ - - case OP_RF: case OP_PF: /* read, punch feed */ - break; /* nop's */ - -/* Move character and edit - - Control flags - qsign sign of A field (0 = +, 1 = minus) - qawm A field WM seen and processed - qzero zero suppression enabled - qbody in body (copying A field characters) - qdollar EPE only; $ seen in body - qaster EPE only; * seen in body - qdecimal EPE only; . seen on first rescan - - MCE operates in one to three scans, the first of which has three phases - - 1 right to left qbody = 0, qawm = 0 => right status - qbody = 1, qawm = 0 => body - qbody = 0, qawm = 1 => left status - 2 left to right - 3 right to left, extended print end only - - The first A field character is masked to its digit part, all others - are copied intact - - Instruction lengths: - - 1 chained - 2,3 invalid A-address - checked in fetch - 4 self (B-address = A-address) - 5,6 invalid B-address - checked in fetch - 7 normal - 8+ normal + ignored modifier -*/ - - case OP_MCE: /* edit */ - a = M[AS]; /* get A char */ - b = M[BS]; /* get B char */ - t = a & DIGIT; /* get A digit */ - MM (AS); - qsign = ((a & ZONE) == BBIT); /* get A field sign */ - qawm = qzero = qbody = 0; /* clear other flags */ - qdollar = qaster = qdecimal = 0; /* clear EPE flags */ - -/* Edit pass 1 - from right to left, under B field control - - * in status or !epe, skip B; else, set qaster, repl with A - $ in status or !epe, skip B; else, set qdollar, repl with A - 0 in right status or body, if !qzero, set A WM; set qzero, repl with A - else, if !qzero, skip B; else, if (!B WM) set B WM - blank in right status or body, repl with A; else, skip B - C,R,- in status, blank B; else, skip B - , in status, blank B, else, skip B - & blank B -*/ - - do { - b = M[BS]; /* get B char */ - M[BS] = M[BS] & ~WM; /* clr WM */ - switch (b & CHAR) { /* case on B char */ - - case BCD_ASTER: /* * */ - if (!qbody || qdollar || !(cpu_unit.flags & EPE)) - break; - qaster = 1; /* flag */ - goto A_CYCLE; /* take A cycle */ - - case BCD_DOLLAR: /* $ */ - if (!qbody || qaster || !(cpu_unit.flags & EPE)) - break; - qdollar = 1; /* flag */ - goto A_CYCLE; /* take A cycle */ - - case BCD_ZERO: /* 0 */ - if (qawm) { /* left status? */ - if (!qzero) /* first? set WM */ - M[BS] = M[BS] | WM; - qzero = 1; /* flag suppress */ - break; - } - if (!qzero) /* body, first? WM */ - t = t | WM; - qzero = 1; /* flag suppress */ - goto A_CYCLE; /* take A cycle */ - - case BCD_BLANK: /* blank */ - if (qawm) /* left status? */ - break; - A_CYCLE: - M[BS] = t; /* copy char */ - if (a & WM) { /* end of A field? */ - qbody = 0; /* end body */ - qawm = 1; /* start left status */ - } - else { - qbody = 1; /* in body */ - a = M[AS]; /* next A */ - MM (AS); - t = a & CHAR; /* use A char */ - } - break; - - case BCD_C: case BCD_R: case BCD_MINUS: /* C, R, - */ - if (!qsign && !qbody) /* + & status? blank */ - M[BS] = BCD_BLANK; - break; - - case BCD_COMMA: /* , */ - if (!qbody) /* status? blank */ - M[BS] = BCD_BLANK; - break; - - case BCD_AMPER: /* & */ - M[BS] = BCD_BLANK; /* blank */ - break; - } /* end switch */ - - MM (BS); /* decr B pointer */ - } while ((b & WM) == 0); /* stop on B WM */ - - if (reason) /* address err? */ - break; - if (!qzero) /* rescan? */ - break; - -/* Edit pass 2 - from left to right, suppressing zeroes */ - - do { - b = M[++BS]; /* get B char */ - switch (b & CHAR) { /* case on B char */ - - case BCD_ONE: case BCD_TWO: case BCD_THREE: - case BCD_FOUR: case BCD_FIVE: case BCD_SIX: - case BCD_SEVEN: case BCD_EIGHT: case BCD_NINE: - qzero = 0; /* turn off supr */ - break; - - case BCD_ZERO: case BCD_COMMA: /* 0 or , */ - if (qzero && !qdecimal) /* if supr, blank */ - M[BS] = qaster? BCD_ASTER: BCD_BLANK; - break; - - case BCD_BLANK: /* blank */ - if (qaster) /* if EPE *, repl */ - M[BS] = BCD_ASTER; - break; - - case BCD_DECIMAL: /* . */ - if (qzero && (cpu_unit.flags & EPE)) /* flag for EPE */ - qdecimal = 1; - break; - - case BCD_PERCNT: case BCD_WM: case BCD_BS: - case BCD_TS: case BCD_MINUS: - break; /* ignore */ - - default: /* other */ - qzero = 1; /* restart supr */ - break; - } /* end case */ - } while ((b & WM) == 0); - - M[BS] = M[BS] & ~WM; /* clear B WM */ - if (!qdollar && !(qdecimal && qzero)) { /* rescan again? */ - BS++; /* BS = addr WM + 1 */ - break; - } - if (qdecimal && qzero) /* no digits? clr $ */ - qdollar = 0; - -/* Edit pass 3 (extended print only) - from right to left */ - - for (;; ) { /* until chars */ - b = M[BS]; /* get B char */ - if ((b == BCD_BLANK) && qdollar) { /* blank & flt $? */ - M[BS] = BCD_DOLLAR; /* insert $ */ - break; /* exit for */ - } - if (b == BCD_DECIMAL) { /* decimal? */ - M[BS] = qaster? BCD_ASTER: BCD_BLANK; - break; /* exit for */ - } - if ((b == BCD_ZERO) && !qdollar) /* 0 & ~flt $ */ - M[BS] = qaster? BCD_ASTER: BCD_BLANK; - BS--; - } /* end for */ - break; /* done at last! */ - -/* Multiply. Comments from the PDP-10 based simulator by Len Fehskens. - - Multiply, with variable length operands, is necessarily done the same - way you do it with paper and pencil, except that partial products are - added into the incomplete final product as they are computed, rather - than at the end. The 1401 multiplier format allows the product to - be developed in place, without scratch storage. - - The A field contains the multiplicand, length LD. The B field must be - LD + 1 + length of multiplier. Locate the low order multiplier digit, - and at the same time zero out the product field. Then compute the sign - of the result. - - Instruction lengths: - - 1 chained - 2,3 invalid A-address - checked in fetch - 4 self (B-address = A-address) - 5,6 invalid B-address - checked in fetch - 7 normal - 8+ normal + ignored modifier -*/ - - case OP_MUL: - asave = AS; /* save AS, BS */ - bsave = lowprd = BS; - do { - a = M[AS]; /* get mpcd char */ - M[BS] = BCD_ZERO; /* zero prod */ - MM (AS); /* decr pointers */ - MM (BS); - } while ((a & WM) == 0); /* until A WM */ - if (reason) /* address err? */ - break; - M[BS] = BCD_ZERO; /* zero hi prod */ - MM (BS); /* addr low mpyr */ - sign = ((M[asave] & ZONE) == BBIT) ^ ((M[BS] & ZONE) == BBIT); - -/* Outer loop on multiplier (BS) and product digits (ps), - inner loop on multiplicand digits (AS). - AS and ps cannot produce an address error. -*/ - - do { - ps = bsave; /* ptr to prod */ - AS = asave; /* ptr to mpcd */ - carry = 0; /* init carry */ - b = M[BS]; /* get mpyr char */ - do { - a = M[AS]; /* get mpcd char */ - t = (bcd_to_bin[a & DIGIT] * /* mpyr * mpcd */ - bcd_to_bin[b & DIGIT]) + /* + c + partial prod */ - carry + bcd_to_bin[M[ps] & DIGIT]; - carry = cry_table[t]; - M[ps] = (M[ps] & WM) | sum_table[t]; - MM (AS); - ps--; - } while ((a & WM) == 0); /* until mpcd done */ - M[BS] = (M[BS] & WM) | BCD_ZERO; /* zero mpyr just used */ - t = bcd_to_bin[M[ps] & DIGIT] + carry; /* add carry to prod */ - M[ps] = (M[ps] & WM) | sum_table[t]; /* store */ - bsave--; /* adv prod ptr */ - MM (BS); /* adv mpyr ptr */ - } while ((b & WM) == 0); /* until mpyr done */ - M[lowprd] = M[lowprd] | ZONE; /* assume + */ - if (sign) /* if minus, B only */ - M[lowprd] = M[lowprd] & ~ABIT; - break; - -/* Divide. Comments from the PDP-10 based simulator by Len Fehskens. - - Divide is done, like multiply, pretty much the same way you do it with - pencil and paper; successive subtraction of the divisor from a substring - of the dividend while counting up the corresponding quotient digit. - - Let LS be the length of the divisor, LD the length of the dividend: - - AS points to the low order divisor digit. - - BS points to the high order dividend digit. - - The low order dividend digit is identified by sign (zone) bits. - - To the left of the dividend is a (zero) field of length LS + 1. - So the quotient starts as BS - LS - 1. - The divide process starts with a subdividend that begins at BS - LS - and ends at BS. (Note that the subdividend is one digit wider than - the divisor, to allow for borrows during the divide process.) This - means that non-zero digits in the "zero" field to the left of the - dividend CAN affect the divide. - - Start by computing the length of the divisor and testing for divide - by zero. - - Instruction lengths: - - 1 chained - 2,3 invalid A-address - checked in fetch - 4 self (B-address = A-address) - 5,6 invalid B-address - checked in fetch - 7 normal - 8+ normal + ignored modifier -*/ - - case OP_DIV: - asave = AS; - t = 0; /* assume all 0's */ - do { /* scan divisor */ - a = M[AS]; /* get dvr char */ - if ((bcd_to_bin[a & DIGIT]) != 0) /* mark non-zero */ - t = 1; - MM (AS); - } - while ((a & WM) == 0); - if (reason) /* address err? */ - break; - if (t == 0) { /* div by zero? */ - ind[IN_OVF] = 1; /* set ovf indic */ - qs = bsave = BS; /* quo, dividend */ - do { - b = M[bsave]; /* find end divd */ - PP (bsave); /* marked by zone */ - } while ((b & ZONE) == 0); - if (reason) /* address err? */ - break; - if (ADDR_ERR (qs)) { /* address err? */ - reason = STOP_WRAP; /* address wrap? */ - break; - } - div_sign (M[asave], b, qs - 1, bsave - 1); /* set signs */ - BS = (BS - 2) - (asave - (AS + 1)); /* final bs */ - break; - } - bsave = BS; /* end subdivd */ - qs = BS - (asave - AS) - 1; /* quo start */ - -/* Divide loop - done with subroutines to keep the code clean. - In the loop, - - asave = low order divisor (constant) - bsave = low order subdividend (increments) - qs = current quotient digit (increments) -*/ - - do { - quo = 0; /* clear quo digit */ - if (ADDR_ERR (qs) || ADDR_ERR (bsave)) { - reason = STOP_WRAP; /* address wrap? */ - break; - } - b = M[bsave]; /* save low divd */ - do { - t = div_sub (asave, bsave); /* subtract */ - quo++; /* incr quo digit */ - } while (t == 0); /* until borrow */ - div_add (asave, bsave); /* restore */ - quo--; - if (quo > 9) /* overflow? */ - ind[IN_OVF] = 1; /* set ovf indic */ - M[qs] = (M[qs] & WM) | sum_table[quo]; /* store quo digit */ - bsave++; /* adv divd, quo */ - qs++; - } while ((b & ZONE) == 0); /* until B sign */ - if (reason) /* address err? */ - break; - -/* At this point, - - AS = high order divisor - 1 - asave = unit position of divisor - b = unit character of dividend - bsave = unit position of remainder + 1 - qs = unit position of quotient + 1 -*/ - - div_sign (M[asave], b, qs - 1, bsave - 1); /* set signs */ - BS = qs - 2; /* BS = quo 10's pos */ - break; - -/* Word mark instructions A check B check - - SWM set WM on A char and B char fetch fetch - CWM clear WM on A char and B char fetch fetch - - Instruction lengths: - - 1 chained - 2,3 invalid A-address - 4 one operand (B-address = A-address) - 5,6 invalid B-address - 7 two operands (SWM cannot be longer than 7) - 8+ two operands + ignored modifier -*/ - - case OP_SWM: /* set word mark */ - M[BS] = M[BS] | WM; /* set A field mark */ - M[AS] = M[AS] | WM; /* set B field mark */ - MM (AS); /* decr pointers */ - MM (BS); - break; - - case OP_CWM: /* clear word mark */ - M[BS] = M[BS] & ~WM; /* clear A field mark */ - M[AS] = M[AS] & ~WM; /* clear B field mark */ - MM (AS); /* decr pointers */ - MM (BS); - break; - -/* Clear storage instruction A check B check - - CS clear from B down to nearest hundreds if branch fetch - address - - Instruction lengths: - - 1 chained - 2,3 invalid A-address and B-address - 4 one operand (B-address = A-address) - 5,6 invalid B-address - 7 branch - 8+ one operand, branch ignored - - Note that clear storage and branch does not overwrite the B register, - unlike all other branches -*/ - - case OP_CS: /* clear storage */ - t = (BS / 100) * 100; /* lower bound */ - while (BS >= t) /* clear region */ - M[BS--] = 0; - if (BS < 0) /* wrap if needed */ - BS = BS + MEMSIZE; - if (ilnt == 7) { /* branch variant? */ - BRANCH_CS; /* special branch */ - } - break; - -/* Modify address instruction A check B check - - MA add A addr and B addr, store at B addr fetch fetch - - Instruction lengths: - 1 chained - 2,3 invalid A-address and B-address - 4 self (B-address = A-address) - 5,6 invalid B-address - 7 normal - 8+ normal + ignored modifier -*/ - - case OP_MA: /* modify address */ - a = one_table[M[AS] & CHAR]; MM (AS); /* get A address */ - a = a + ten_table[M[AS] & CHAR]; MM (AS); - a = a + hun_table[M[AS] & CHAR]; MM (AS); - b = one_table[M[BS] & CHAR]; MM (BS); /* get B address */ - b = b + ten_table[M[BS] & CHAR]; MM (BS); - b = b + hun_table[M[BS] & CHAR]; MM (BS); - t = ((a + b) & INDEXMASK) % MAXMEMSIZE; /* compute sum */ - M[BS + 3] = (M[BS + 3] & WM) | store_addr_u (t); - M[BS + 2] = (M[BS + 2] & (WM + ZONE)) | store_addr_t (t); - M[BS + 1] = (M[BS + 1] & WM) | store_addr_h (t); - if (((a % 4000) + (b % 4000)) >= 4000) /* carry? */ - BS = BS + 2; - break; - -/* Store address instructions A-check B-check - - SAR store A* at A addr fetch - SBR store B* at A addr fetch - - Instruction lengths: - 1 chained - 2,3 invalid A-address - 4 normal - 5+ B-address overwritten from instruction; - invalid address ignored -*/ - - case OP_SAR: case OP_SBR: /* store A, B reg */ - M[AS] = (M[AS] & WM) | store_addr_u (BS); - MM (AS); - M[AS] = (M[AS] & WM) | store_addr_t (BS); - MM (AS); - M[AS] = (M[AS] & WM) | store_addr_h (BS); - MM (AS); - break; - -/* NOP - no validity checking, all instructions length ok */ - - case OP_NOP: /* nop */ - break; - -/* HALT - unless length = 4 (branch), no validity checking; all lengths ok */ - - case OP_H: /* halt */ - if (ilnt == 4) /* set pending branch */ - hb_pend = 1; - reason = STOP_HALT; /* stop simulator */ - saved_IS = IS; /* commit instruction */ - break; - - default: - reason = STOP_NXI; /* unimplemented */ - break; - } /* end switch */ - } /* end while */ - -/* Simulation halted */ - -as_err = ADDR_ERR (AS); /* get addr err flags */ -bs_err = ADDR_ERR (BS); -AS = AS & ADDRMASK; /* clean addresses */ -BS = BS & ADDRMASK; -pcq_r->qptr = pcq_p; /* update pc q ptr */ -return reason; -} /* end sim_instr */ - -/* store addr_x - convert address to BCD character in x position - - Inputs: - addr = address to convert - Outputs: - char = converted address character -*/ - -int32 store_addr_h (int32 addr) -{ -int32 thous; - -thous = (addr / 1000) & 03; -return bin_to_bcd[(addr % 1000) / 100] | (thous << V_ZONE); -} - -int32 store_addr_t (int32 addr) -{ -return bin_to_bcd[(addr % 100) / 10]; -} - -int32 store_addr_u (int32 addr) -{ -int32 thous; - -thous = (addr / 1000) & 014; -return bin_to_bcd[addr % 10] | (thous << (V_ZONE - 2)); -} - -/* div_add - add string for divide */ - -int32 div_add (int32 ap, int32 bp) -{ -int32 a, b, c, r; - -c = 0; /* init carry */ -do { - a = M[ap]; /* get operands */ - b = M[bp]; - r = bcd_to_bin[b & DIGIT] + /* sum digits + c */ - bcd_to_bin[a & DIGIT] + c; - c = (r >= 10); /* set carry out */ - M[bp] = (M[bp] & WM) | sum_table[r]; /* store result */ - ap--; - bp--; - } while ((a & WM) == 0); -return c; -} - -/* div_sub - substract string for divide */ - -int32 div_sub (int32 ap, int32 bp) -{ -int32 a, b, c, r; - -c = 0; /* init borrow */ -do { - a = M[ap]; /* get operands */ - b = M[bp]; - r = bcd_to_bin[b & DIGIT] - /* a - b - borrow */ - bcd_to_bin[a & DIGIT] - c; - c = (r < 0); /* set borrow out */ - M[bp] = (M[bp] & WM) | sum_table[r + 10]; /* store result */ - ap--; - bp--; - } while ((a & WM) == 0); -b = M[bp]; /* borrow position */ -if (bcd_to_bin[b & DIGIT] != 0) { /* non-zero? */ - r = bcd_to_bin[b & DIGIT] - c; /* subtract borrow */ - M[bp] = (M[bp] & WM) | sum_table[r]; /* store result */ - return 0; /* subtract worked */ - } -return c; /* return borrow */ -} - -/* div_sign - set signs for divide */ - -void div_sign (int32 dvrc, int32 dvdc, int32 qp, int32 rp) -{ -int32 sign = dvrc & ZONE; /* divisor sign */ - -M[rp] = M[rp] | ZONE; /* assume rem pos */ -if (sign == BBIT) /* if dvr -, rem - */ - M[rp] = M[rp] & ~ABIT; -M[qp] = M[qp] | ZONE; /* assume quo + */ -if (((dvdc & ZONE) == BBIT) ^ (sign == BBIT)) /* dvr,dvd diff? */ - M[qp] = M[qp] & ~ABIT; /* make quo - */ -return; -} - -/* iomod - check on I/O modifiers - - Inputs: - ilnt = instruction length - mod = modifier character - tptr = pointer to table of modifiers, end is -1 - Output: - status = SCPE_OK if ok, STOP_INVM if invalid -*/ - -t_stat iomod (int32 ilnt, int32 mod, const int32 *tptr) -{ -if ((ilnt != 2) && (ilnt != 5) && (ilnt < 8)) - return SCPE_OK; -if (tptr == NULL) - return STOP_INVM; -do { - if (mod == *tptr++) - return SCPE_OK; - } while (*tptr >= 0); -return STOP_INVM; -} - -/* iodisp - dispatch load or move to I/O routine - - Inputs: - dev = device number - unit = unit number - flag = move (MD_NORM) vs load (MD_WM) - mod = modifier -*/ - -t_stat iodisp (int32 dev, int32 unit, int32 flag, int32 mod) -{ -if (dev == IO_INQ) /* inq terminal? */ - return inq_io (flag, mod); -if (dev == IO_DP) /* disk pack? */ - return dp_io (unit, flag, mod); -if (dev == IO_MT) /* magtape? */ - return mt_io (unit, flag, mod); -if (dev == IO_MTB) /* binary magtape? */ - return mt_io (unit, flag | MD_BIN, mod); -return STOP_NXD; /* not implemented */ -} - -/* Reset routine */ - -t_stat cpu_reset (DEVICE *dptr) -{ -int32 i; - -for (i = 0; i < 64; i++) { /* clr indicators */ - if ((i < IN_SSB) || (i > IN_SSG)) /* except SSB-SSG */ - ind[i] = 0; - } -ind[IN_UNC] = 1; /* ind[0] always on */ -AS = 0; /* clear AS */ -BS = 0; /* clear BS */ -as_err = 1; -bs_err = 1; -D = 0; /* clear D */ -hb_pend = 0; /* no halt br */ -pcq_r = find_reg ("ISQ", NULL, dptr); -if (pcq_r) - pcq_r->qptr = 0; -else return SCPE_IERR; -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] & (WM + CHAR); -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 & (WM + CHAR); -return SCPE_OK; -} - -/* Memory size change */ - -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 mc = 0; -uint32 i; - -if ((val <= 0) || (val > MAXMEMSIZE) || ((val % 1000) != 0)) - return SCPE_ARG; -for (i = val; i < MEMSIZE; i++) - mc = mc | M[i]; -if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) - return SCPE_OK; -MEMSIZE = val; -for (i = MEMSIZE; i < MAXMEMSIZE; i++) - M[i] = 0; -if (MEMSIZE > 4000) - cpu_unit.flags = cpu_unit.flags | MA; -else cpu_unit.flags = cpu_unit.flags & ~MA; -return SCPE_OK; -} - -/* Set history */ - -t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 i, lnt; -t_stat r; - -if (cptr == NULL) { - for (i = 0; i < hst_lnt; i++) - hst[i].ilnt = 0; - hst_p = 0; - return SCPE_OK; - } -lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r); -if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) - return SCPE_ARG; -hst_p = 0; -if (hst_lnt) { - free (hst); - hst_lnt = 0; - hst = NULL; - } -if (lnt) { - hst = (InstHistory *) calloc (lnt, sizeof (InstHistory)); - if (hst == NULL) - return SCPE_MEM; - hst_lnt = lnt; - } -return SCPE_OK; -} - -/* Show history */ - -t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -int32 i, k, di, lnt; -char *cptr = (char *) desc; -t_value sim_eval[MAX_L + 1]; -t_stat r; -InstHistory *h; - -if (hst_lnt == 0) /* enabled? */ - return SCPE_NOFNC; -if (cptr) { - lnt = (int32) get_uint (cptr, 10, hst_lnt, &r); - if ((r != SCPE_OK) || (lnt == 0)) - return SCPE_ARG; - } -else lnt = hst_lnt; -di = hst_p - lnt; /* work forward */ -if (di < 0) - di = di + hst_lnt; -fprintf (st, "IS IR\n\n"); -for (k = 0; k < lnt; k++) { /* print specified */ - h = &hst[(++di) % hst_lnt]; /* entry pointer */ - if (h->ilnt) { /* instruction? */ - fprintf (st, "%05d ", h->is); - for (i = 0; i < h->ilnt; i++) - sim_eval[i] = h->inst[i]; - sim_eval[h->ilnt] = WM; - if ((fprint_sym (st, h->is, sim_eval, &cpu_unit, SWMASK ('M'))) > 0) { - fprintf (st, "(undefined)"); - for (i = 0; i < h->ilnt; i++) - fprintf (st, " %02o", h->inst[i]); - } - fputc ('\n', st); /* end line */ - } /* end else instruction */ - } /* end for */ -return SCPE_OK; -} - -/* Set conversions */ - -t_stat cpu_set_conv (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -conv_old = val; -return SCPE_OK; -} - -/* Show conversions */ - -t_stat cpu_show_conv (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -if (conv_old) - fputs ("Old (pre-3.5-1) conversions\n", st); -else fputs ("New conversions\n", st); -return SCPE_OK; -} diff --git a/I1401/i1401_dat.h b/I1401/i1401_dat.h deleted file mode 100644 index 4320e9cf..00000000 --- a/I1401/i1401_dat.h +++ /dev/null @@ -1,145 +0,0 @@ -/* i1401_dat.h: IBM 1401 character conversion tables - - Copyright (c) 1993-2008, 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. - - 20-Sep-05 RMS Updated for compatibility with Paul Pierce conventions -*/ - -/* Old tables */ -/* ASCII to BCD conversion */ - -const char ascii_to_bcd_old[128] = { - 000, 000, 000, 000, 000, 000, 000, 000, /* 000 - 037 */ - 000, 000, 000, 000, 000, 000, 000, 000, - 000, 000, 000, 000, 000, 000, 000, 000, - 000, 000, 000, 000, 000, 000, 000, 000, - 000, 052, 077, 013, 053, 034, 060, 032, /* 040 - 077 */ - 017, 074, 054, 037, 033, 040, 073, 021, - 012, 001, 002, 003, 004, 005, 006, 007, - 010, 011, 015, 056, 076, 035, 016, 072, - 014, 061, 062, 063, 064, 065, 066, 067, /* 100 - 137 */ - 070, 071, 041, 042, 043, 044, 045, 046, - 047, 050, 051, 022, 023, 024, 025, 026, - 027, 030, 031, 075, 036, 055, 020, 057, - 000, 061, 062, 063, 064, 065, 066, 067, /* 140 - 177 */ - 070, 071, 041, 042, 043, 044, 045, 046, - 047, 050, 051, 022, 023, 024, 025, 026, - 027, 030, 031, 000, 000, 000, 000, 000 - }; - -/* BCD to ASCII conversion - also the "full" print chain */ - -char bcd_to_ascii_old[64] = { - ' ', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '0', '#', '@', ':', '>', '(', - '^', '/', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', '\'', ',', '%', '=', '\\', '+', - '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', '!', '$', '*', ']', ';', '_', - '&', 'A', 'B', 'C', 'D', 'E', 'F', 'G', - 'H', 'I', '?', '.', ')', '[', '<', '"' - }; - -/* New tables */ -/* ASCII to BCD conversion */ - -const char ascii_to_bcd[128] = { - 000, 000, 000, 000, 000, 000, 000, 000, /* 000 - 037 */ - 000, 000, 000, 000, 000, 000, 000, 000, - 000, 000, 000, 000, 000, 000, 000, 000, - 000, 000, 000, 000, 000, 000, 000, 000, - 000, 052, 037, 013, 053, 034, 060, 014, /* 040 - 077 */ - 034, 074, 054, 060, 033, 040, 073, 021, - 012, 001, 002, 003, 004, 005, 006, 007, - 010, 011, 015, 056, 076, 013, 016, 072, - 014, 061, 062, 063, 064, 065, 066, 067, /* 100 - 137 */ - 070, 071, 041, 042, 043, 044, 045, 046, - 047, 050, 051, 022, 023, 024, 025, 026, - 027, 030, 031, 075, 036, 055, 020, 057, - 000, 061, 062, 063, 064, 065, 066, 067, /* 140 - 177 */ - 070, 071, 041, 042, 043, 044, 045, 046, - 047, 050, 051, 022, 023, 024, 025, 026, - 027, 030, 031, 017, 032, 077, 035, 000 - }; - -/* BCD to ASCII conversion */ - -const char bcd_to_ascii_a[64] = { - ' ', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '0', '#', '@', ':', '>', '{', - '^', '/', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', '|', ',', '%', '~', '\\', '"', - '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', '!', '$', '*', ']', ';', '_', - '&', 'A', 'B', 'C', 'D', 'E', 'F', 'G', - 'H', 'I', '?', '.', ')', '[', '<', '}' - }; - -const char bcd_to_ascii_h[64] = { - ' ', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '0', '=', '\'', ':', '>', '{', - '^', '/', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', '|', ',', '(', '~', '\\', '"', - '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', '!', '$', '*', ']', ';', '_', - '+', 'A', 'B', 'C', 'D', 'E', 'F', 'G', - 'H', 'I', '?', '.', ')', '[', '<', '}' - }; - -/* BCD to ASCII 48 character print chains */ - -const char bcd_to_pca[64] = { - ' ', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '0', '#', '@', ' ', ' ', ' ', - ' ', '/', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', ' ', ',', '%', ' ', ' ', ' ', - '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', '-', '$', '*', ' ', ' ', ' ', - '&', 'A', 'B', 'C', 'D', 'E', 'F', 'G', - 'H', 'I', '&', '.', ')', ' ', ' ', ' ' - }; - -const char bcd_to_pch[64] = { - ' ', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '0', '=', '\'', ' ', ' ', ' ', - ' ', '/', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', ' ', ',', '(', ' ', ' ', ' ', - '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', '-', '$', '*', ' ', ' ', ' ', - '&', 'A', 'B', 'C', 'D', 'E', 'F', 'G', - 'H', 'I', '&', '.', ')', ' ', ' ', ' ' - }; - -/* BCD to column binary conversion */ - -const uint32 bcd_to_colbin[64] = { - 00000, 00400, 00200, 00100, 00040, 00020, 00010, 00004, - 00002, 00001, 00202, 00102, 00042, 00022, 00012, 00006, - 01000, 01400, 01200, 01100, 01040, 01020, 01010, 01004, - 01002, 01001, 01202, 01102, 01042, 01022, 01012, 01006, - 02000, 02400, 02200, 02100, 02040, 02020, 02010, 02004, - 02002, 02001, 02202, 02102, 02042, 02022, 02012, 02006, - 04000, 04400, 04200, 04100, 04040, 04020, 04010, 04004, - 04002, 04001, 04202, 04102, 04042, 04022, 04012, 04006 - }; diff --git a/I1401/i1401_defs.h b/I1401/i1401_defs.h deleted file mode 100644 index 680e9823..00000000 --- a/I1401/i1401_defs.h +++ /dev/null @@ -1,304 +0,0 @@ -/* i1401_defs.h: IBM 1401 simulator definitions - - Copyright (c) 1993-2010, 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. - - 06-JUl-10 RMS Added overlap indicator definitions - 22-May-10 RMS Added check for 64b definitions - 11-Jul-08 RMS Added IO mode flag for boot (from Bob Abeles) - 28-Jun-07 RMS Defined character code for tape mark - 14-Nov-04 RMS Added column binary support - 27-Oct-04 RMS Added maximum instruction length - 16-Mar-03 RMS Fixed mnemonic for MCS - 03-Jun-02 RMS Added 1311 support - 14-Apr-99 RMS Converted t_addr to unsigned - - This simulator is based on the 1401 simulator written by Len Fehskens - with assistance from Sarah Lee Harris and Bob Supnik. This one's for - you, Len. I am grateful to Paul Pierce and Charles Owen for their help - in answering questions, gathering source material, and debugging. -*/ - -#ifndef I1401_DEFS_H_ -#define I1401_DEFS_H_ 0 - -#include "sim_defs.h" - -#if defined(USE_INT64) || defined(USE_ADDR64) -#error "1401 does not support 64b values!" -#endif - -/* Simulator stop codes */ - -#define STOP_NXI 1 /* unimpl instr */ -#define STOP_NXM 2 /* non-exist mem */ -#define STOP_NXD 3 /* non-exist dev */ -#define STOP_NOWM 4 /* no WM under op */ -#define STOP_INVA 5 /* invalid A addr */ -#define STOP_INVB 6 /* invalid B addr */ -#define STOP_INVL 7 /* invalid length */ -#define STOP_INVM 8 /* invalid modifier */ -#define STOP_INVBR 9 /* invalid branch */ -#define STOP_IBKPT 10 /* breakpoint */ -#define STOP_HALT 11 /* halt */ -#define STOP_INVMTU 12 /* invalid MT unit */ -#define STOP_MTZ 13 /* MT zero lnt rec */ -#define STOP_MTL 14 /* MT write lock */ -#define STOP_CCT 15 /* inv CCT channel */ -#define STOP_NOCD 16 /* no cards left */ -#define STOP_WRAP 17 /* AS, BS mem wrap */ -#define STOP_IOC 18 /* I/O check */ -#define STOP_INVDSC 19 /* invalid disk sector */ -#define STOP_INVDCN 20 /* invalid disk count */ -#define STOP_INVDSK 21 /* invalid disk unit */ -#define STOP_INVDFN 22 /* invalid disk func */ -#define STOP_INVDLN 23 /* invalid disk reclen */ -#define STOP_WRADIS 24 /* write address dis */ -#define STOP_WRCHKE 25 /* write check error */ -#define STOP_INVDAD 26 /* invalid disk addr */ -#define STOP_INVDCY 27 /* invalid direct seek */ - -/* Memory and devices */ - -#define MAXMEMSIZE 16000 /* max memory */ -#define MEMSIZE (cpu_unit.capac) /* current memory */ -#define CDR_BUF 1 /* card rdr buffer */ -#define CDR_WIDTH 80 /* card rdr width */ -#define CDP_BUF 101 /* card punch buffer */ -#define CDP_WIDTH 80 /* card punch width */ -#define CD_CBUF1 401 /* r/p col bin buf 12-3 */ -#define CD_CBUF2 501 /* r/p col bin buf 4-9 */ -#define LPT_BUF 201 /* line print buffer */ -#define LPT_WIDTH 132 /* line print width */ -#define CCT_LNT 132 /* car ctrl length */ -#define INQ_WIDTH 80 /* inq term width */ -#define ADDR_ERR(x) (((uint32) (x)) >= MEMSIZE) - -/* Binary address format - - <14:0> address, with index added in - <23:16> index register memory address - <25:24> address error bits -*/ - -#define ADDRMASK 037777 /* addr mask */ -#define INDEXMASK 077777 /* addr + index mask */ -#define V_INDEX 16 -#define M_INDEX 0177 -#define V_ADDRERR 24 -#define BA (1 << V_ADDRERR) /* bad addr digit */ -#define X1 (87 << V_INDEX) /* index reg 1 */ -#define X2 (92 << V_INDEX) /* index reg 2 */ -#define X3 (97 << V_INDEX) /* index reg 3 */ - -/* CPU instruction control flags. The flag definitions must be harmonized - with the UNIT flag definitions used by the simulator. */ - -/* Lengths */ - -#define L1 0001 /* 1: op */ -#define L2 0002 /* 2: op d */ -#define L4 0004 /* 4: op aaa */ -#define L5 0010 /* 5: op aaa d */ -#define L7 0020 /* 7: op aaa bbb */ -#define L8 0040 /* 8: op aaa bbb d */ -#define MAX_L 8 /* max length */ - -/* CPU options, stored in cpu_unit.flags */ - -#define MDV (1 << (UNIT_V_UF + 0)) /* multiply/divide */ -#define MR (1 << (UNIT_V_UF + 1)) /* move record */ -#define XSA (1 << (UNIT_V_UF + 2)) /* index, store addr */ -#define EPE (1 << (UNIT_V_UF + 3)) /* expanded edit */ -#define MA (1 << (UNIT_V_UF + 4)) /* modify address */ -#define BBE (1 << (UNIT_V_UF + 5)) /* br bit equal */ -#define HLE (1 << (UNIT_V_UF + 6)) /* high/low/equal */ -#define UNIT_MSIZE (1 << (UNIT_V_UF + 7)) /* fake flag */ -#define ALLOPT (MDV + MR + XSA + EPE + MA + BBE + HLE) -#define STDOPT (MDV + MR + XSA + EPE + MA + BBE + HLE) - -/* Fetch control */ - -#define AREQ (1 << (UNIT_V_UF + 8)) /* validate A */ -#define BREQ (1 << (UNIT_V_UF + 9)) /* validate B */ -#define MLS (1 << (UNIT_V_UF + 10)) /* move load store */ -#define NOWM (1 << (UNIT_V_UF + 11)) /* no WM at end */ -#define HNOP (1 << (UNIT_V_UF + 12)) /* halt or nop */ -#define IO (1 << (UNIT_V_UF + 13)) /* IO */ -#define UNIT_BCD (1 << (UNIT_V_UF + 14)) /* BCD strings */ - -#if (UNIT_V_UF < 6) || ((UNIT_V_UF + 14) > 31) - Definition error: flags overlap -#endif - -/* BCD memory character format */ - -#define WM 0100 /* word mark */ -#define ZONE 0060 /* zone */ -#define BBIT 0040 /* 1 in valid sign */ -#define ABIT 0020 /* sign (1 = +) */ -#define DIGIT 0017 /* digit */ -#define CHAR 0077 /* character */ - -#define V_WM 6 -#define V_ZONE 4 -#define V_DIGIT 0 - -/* Interesting BCD characters */ - -#define BCD_BLANK 000 -#define BCD_ONE 001 -#define BCD_TWO 002 -#define BCD_THREE 003 -#define BCD_FOUR 004 -#define BCD_FIVE 005 -#define BCD_SIX 006 -#define BCD_SEVEN 007 -#define BCD_EIGHT 010 -#define BCD_NINE 011 -#define BCD_ZERO 012 -#define BCD_TAPMRK 017 -#define BCD_ALT 020 -#define BCD_S 022 -#define BCD_U 024 -#define BCD_W 026 -#define BCD_RECMRK 032 -#define BCD_COMMA 033 -#define BCD_PERCNT 034 -#define BCD_WM 035 -#define BCD_BS 036 -#define BCD_TS 037 -#define BCD_MINUS 040 -#define BCD_M 044 -#define BCD_R 051 -#define BCD_DOLLAR 053 -#define BCD_ASTER 054 -#define BCD_AMPER 060 -#define BCD_A 061 -#define BCD_B 062 -#define BCD_C 063 -#define BCD_E 065 -#define BCD_DECIMAL 073 -#define BCD_SQUARE 074 -#define BCD_GRPMRK 077 - -/* Opcodes */ - -#define OP_R 001 /* read */ -#define OP_W 002 /* write */ -#define OP_WR 003 /* write and read */ -#define OP_P 004 /* punch */ -#define OP_RP 005 /* read and punch */ -#define OP_WP 006 /* write and punch */ -#define OP_WRP 007 /* write read punch */ -#define OP_RF 010 /* reader feed */ -#define OP_PF 011 /* punch feed */ -#define OP_MA 013 /* modify address */ -#define OP_MUL 014 /* multiply */ -#define OP_CS 021 /* clear storage */ -#define OP_S 022 /* subtract */ -#define OP_MTF 024 /* magtape function */ -#define OP_BWZ 025 /* branch wm or zone */ -#define OP_BBE 026 /* branch bit equal */ -#define OP_MZ 030 /* move zone */ -#define OP_MCS 031 /* move suppr zeroes */ -#define OP_SWM 033 /* set word mark */ -#define OP_DIV 034 /* divide */ -#define OP_SS 042 /* select stacker */ -#define OP_LCA 043 /* load characters */ -#define OP_MCW 044 /* move characters */ -#define OP_NOP 045 /* no op */ -#define OP_MCM 047 /* move to rec/grp mk */ -#define OP_SAR 050 /* store A register */ -#define OP_ZS 052 /* zero and subtract */ -#define OP_A 061 /* add */ -#define OP_B 062 /* branch */ -#define OP_C 063 /* compare */ -#define OP_MN 064 /* move numeric */ -#define OP_MCE 065 /* move char and edit */ -#define OP_CC 066 /* carriage control */ -#define OP_SBR 070 /* store B register */ -#define OP_ZA 072 /* zero and add */ -#define OP_H 073 /* halt */ -#define OP_CWM 074 /* clear word mark */ - -/* I/O addresses */ - -#define IO_INQ 023 /* inquiry terminal */ -#define IO_MT 024 /* magtape */ -#define IO_MTB 062 /* binary magtape */ -#define IO_DP 066 /* 1311 diskpack */ - -/* I/O modes */ - -#define MD_NORM 0 /* normal (move) */ -#define MD_WM 1 /* word mark (load) */ -#define MD_BIN 2 /* binary */ -#define MD_BOOT 4 /* boot read */ - -/* Indicator characters */ - -#define IN_UNC 000 /* unconditional */ -#define IN_CC9 011 /* carr ctrl chan 9 */ -#define IN_CC12 014 /* carr ctrl chan 12 */ -#define IN_UNQ 021 /* unequal */ -#define IN_EQU 022 /* equal */ -#define IN_LOW 023 /* low */ -#define IN_HGH 024 /* high */ -#define IN_DPW 025 /* parity/compare check */ -#define IN_LNG 026 /* wrong lnt record */ -#define IN_UNA 027 /* unequal addr cmp */ -#define IN_DSK 030 /* disk error */ -#define IN_OVF 031 /* overflow */ -#define IN_LPT 032 /* printer error */ -#define IN_PRO 034 /* process check */ -#define IN_DBY 036 /* disk busy */ -#define IN_TBY 041 /* tape busy */ -#define IN_END 042 /* end indicator */ -#define IN_TAP 043 /* tape error */ -#define IN_ACC 045 /* access error */ -#define IN_BSY 047 /* printer busy */ -#define IN_INR 050 /* inquiry request */ -#define IN_PCB 051 /* printer carr busy */ -#define IN_PNCH 052 /* punch error */ -#define IN_INC 054 /* inquiry clear */ -#define IN_LST 061 /* last card */ -#define IN_SSB 062 /* sense switch B */ -#define IN_SSC 063 /* sense switch C */ -#define IN_SSD 064 /* sense switch D */ -#define IN_SSE 065 /* sense switch E */ -#define IN_SSF 066 /* sense switch F */ -#define IN_SSG 067 /* sense switch G */ -#define IN_RBY 070 /* reader busy */ -#define IN_PBY 071 /* punch busy */ -#define IN_READ 072 /* reader error */ - -#define CRETIOE(f,c) return ((f)? (c): SCPE_OK) - -/* Function prototypes */ - -int32 bcd2ascii (int32 c, t_bool use_h); -int32 ascii2bcd (int32 c); - - -#endif diff --git a/I1401/i1401_dp.c b/I1401/i1401_dp.c deleted file mode 100644 index 81739b94..00000000 --- a/I1401/i1401_dp.c +++ /dev/null @@ -1,644 +0,0 @@ -/* i1401_dp.c: IBM 1311 disk simulator - - Copyright (c) 2002-2008, Robert M. Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - dp 1311 disk pack - - 18-Oct-02 RMS Fixed bug in address comparison logic - 19-Sep-02 RMS Minor edit for consistency with 1620 - 15-Jun-02 RMS Reworked address comparison logic - - The 1311 disk pack has 100 cylinders, 10 tracks/cylinder, 20 sectors/track. - Each sector contains 106 characters of information: - - 6c sector address - 100c sector data - - By default, a sector's address field will be '000000', which is illegal. - This is interpreted to mean the implied sector number that would be in - place if the disk pack had been formatted with sequential sector numbers. - - The sector data can be 100 characters without word marks, or 90 characters - with word marks. Load mode transfers 90 characters per sector with - word marks, move mode transfers 100 characters per sector without word - marks. No attempt is made to catch incompatible writes (eg, load mode - write followed by move mode read). -*/ - -#include "i1401_defs.h" - -#define DP_NUMDR 5 /* #drives */ -#define UNIT_V_WAE (UNIT_V_UF + 0) /* write addr enab */ -#define UNIT_WAE (1 << UNIT_V_WAE) - -/* Disk format */ - -#define DP_ADDR 6 /* address */ -#define DP_DATA 100 /* data */ -#define DP_NUMCH (DP_ADDR + DP_DATA) - -#define DP_NUMSC 20 /* #sectors */ -#define DP_NUMSF 10 /* #surfaces */ -#define DP_NUMCY 100 /* #cylinders */ -#define DP_TOTSC (DP_NUMCY*DP_NUMSF*DP_NUMSC) -#define DP_SIZE (DP_TOTSC*DP_NUMCH) - -/* Disk control field */ - -#define DCF_DRV 0 /* drive select */ -#define DCF_SEC 1 /* sector addr */ -#define DCF_SEC_LEN 6 -#define DCF_CNT (DCF_SEC + DCF_SEC_LEN) /* sector count */ -#define DCF_CNT_LEN 3 -#define DCF_LEN (DCF_CNT + DCF_CNT_LEN) -#define DCF_DIR 1 /* direct seek */ -#define DCF_DIR_LEN 4 -#define DCF_DIR_FL (DCF_DIR + DCF_DIR_LEN) /* direct seek flag */ -#define DCF_DSEEK 0xB - -/* Functions */ - -#define FNC_SEEK 0 /* seek */ -#define FNC_CHECK 3 /* check */ -#define FNC_READ 1 /* read sectors */ -#define FNC_RSCO 5 /* read sec cnt overlay */ -#define FNC_RTRK 6 /* read track */ -#define FNC_WOFF 10 /* offset for write */ -#define FNC_WRITE 11 /* write sectors */ -#define FNC_WRSCO 15 /* write sec cnt overlay */ -#define FNC_WRTRK 16 /* write track */ - -#define CYL u3 /* current cylinder */ - -extern uint8 M[]; /* memory */ -extern int32 ind[64]; -extern int32 AS, BS, iochk; -extern int32 bcd_to_bin[16]; -extern int32 bin_to_bcd[16]; -extern UNIT cpu_unit; - -int32 dp_lastf = 0; /* prior function */ -int32 dp_time = 0; /* seek time */ - -t_stat dp_reset (DEVICE *dptr); -t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 flg, int32 wchk); -t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 flg, int32 wchk); -t_stat dp_wradr (UNIT *uptr, int32 sec, int32 flg); -t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 flg); -int32 dp_fndsec (UNIT *uptr, int32 sec, int32 dcf); -t_stat dp_nexsec (UNIT *uptr, int32 psec, int32 dcf); -t_bool dp_zeroad (uint8 *ap); -t_bool dp_cmp_ad (uint8 *ap, int32 dcf); -int32 dp_trkop (int32 drv, int32 sec); -int32 dp_cvt_bcd (int32 ad, int32 len); -void dp_cvt_bin (int32 ad, int32 len, int32 val, int32 flg); -int32 dp_get_cnt (int32 dcf); -void dp_fill (UNIT *uptr, uint32 da, int32 cnt); - -/* DP data structures - - dp_dev DSK device descriptor - dp_unit DSK unit list - dp_reg DSK register list - dp_mod DSK modifier list -*/ - -UNIT dp_unit[] = { - { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE + - UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) }, - { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE + - UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) }, - { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE + - UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) }, - { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE + - UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) }, - { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE + - UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) } - }; - -REG dp_reg[] = { - { FLDATA (ACC, ind[IN_ACC], 0) }, - { FLDATA (PWC, ind[IN_DPW], 0) }, - { FLDATA (WLR, ind[IN_LNG], 0) }, - { FLDATA (UNA, ind[IN_UNA], 0) }, - { FLDATA (ERR, ind[IN_DSK], 0) }, - { FLDATA (BSY, ind[IN_DBY], 0) }, - { DRDATA (LASTF, dp_lastf, 3) }, - { DRDATA (TIME, dp_time, 24), PV_LEFT }, - { URDATA (CYL, dp_unit[0].CYL, 10, 8, 0, - DP_NUMDR, PV_LEFT + REG_RO) }, - { NULL } - }; - -MTAB dp_mod[] = { - { UNIT_WAE, 0, "write address disabled", "ADDROFF", NULL }, - { UNIT_WAE, UNIT_WAE, "write address enabled", "ADDRON", NULL }, - { 0 } - }; - -DEVICE dp_dev = { - "DP", dp_unit, dp_reg, dp_mod, - DP_NUMDR, 10, 21, 1, 8, 7, - NULL, NULL, &dp_reset, - NULL, NULL, NULL - }; - -/* Disk IO routine - - Inputs: - fnc = function character - flg = load vs move mode - mod = modifier character - Outputs: - status = status -*/ - -t_stat dp_io (int32 fnc, int32 flg, int32 mod) -{ -int32 dcf, drv, sec, psec, cnt, qwc, qzr, diff; -UNIT *uptr; -t_stat r; - -dcf = BS; /* save DCF addr */ -qwc = 0; /* not wcheck */ -ind[IN_DPW] = ind[IN_LNG] = ind[IN_UNA] = 0; /* clr indicators */ -ind[IN_DSK] = ind[IN_ACC] = ind[IN_DBY] = 0; -if (sim_is_active (&dp_unit[0])) { /* ctlr busy? */ - ind[IN_DBY] = ind[IN_DSK] = 1; /* set indicators */ - return SCPE_OK; /* done */ - } - -AS = dcf + 6; /* AS for most ops */ -BS = dcf + DCF_CNT - 1; /* minimum DCF */ -if (ADDR_ERR (BS)) /* DCF in memory? */ - return STOP_WRAP; -if (M[dcf] & BBIT) /* impl sel? cyl 8-4-2 */ - drv = M[dcf + DCF_SEC + 1] & 0xE; -else drv = M[dcf] & DIGIT; /* get drive sel */ -if ((drv == 0) || (drv & 1) || (drv > BCD_ZERO)) /* bad drive #? */ - return STOP_INVDSK; -drv = bcd_to_bin[drv] >> 1; /* convert */ -uptr = dp_dev.units + drv; /* get unit ptr */ -if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */ - ind[IN_DSK] = ind[IN_ACC] = 1; /* no, error */ - CRETIOE (iochk, SCPE_UNATT); - } - -if ((fnc == FNC_SEEK) && /* seek and */ - (M[dcf + DCF_DIR_FL] & DCF_DSEEK) == DCF_DSEEK) { /* direct flag? */ - diff = dp_cvt_bcd (dcf + DCF_DIR, DCF_DIR_LEN); /* cvt diff */ - if (diff < 0) /* error? */ - return STOP_INVDSC; - diff = diff >> 1; /* diff is *2 */ - if ((M[dcf + DCF_DIR + DCF_DIR_LEN - 1] & ZONE) == BBIT) - diff = -diff; /* get sign */ - uptr->CYL = uptr->CYL + diff; /* bound seek */ - if (uptr->CYL < 0) - uptr->CYL = 0; - else if (uptr->CYL >= DP_NUMCY) { /* too big? */ - uptr->CYL = 0; /* system hangs */ - return STOP_INVDCY; - } - sim_activate (&dp_unit[0], dp_time); /* set ctlr busy */ - return SCPE_OK; /* done! */ - } - -sec = dp_cvt_bcd (dcf + DCF_SEC, DCF_SEC_LEN); /* cvt sector */ -if ((sec < 0) || (sec >= (DP_NUMDR * DP_TOTSC))) /* bad sector? */ - return STOP_INVDSC; -if (fnc == FNC_SEEK) { /* seek? */ - uptr->CYL = (sec / (DP_NUMSF * DP_NUMSC)) % /* set cyl # */ - DP_NUMCY; - sim_activate (&dp_unit[0], dp_time); /* set ctlr busy */ - return SCPE_OK; /* done! */ - } - -BS = dcf + DCF_LEN; /* full DCF */ -if (ADDR_ERR (BS)) /* DCF in memory? */ - return STOP_WRAP; -cnt = dp_get_cnt (dcf); /* get count */ -if (cnt < 0) /* bad count? */ - return STOP_INVDCN; - -if (fnc >= FNC_WOFF) /* invalid func */ - return STOP_INVDFN; -if (mod == BCD_W) { /* write? */ - if (fnc == FNC_CHECK) { /* write check? */ - qwc = 1; /* special read */ - fnc = dp_lastf; /* use last func */ - } - else { - dp_lastf = fnc; /* save func */ - fnc = fnc + FNC_WOFF; /* change to write */ - } - } -else if (mod == BCD_R) /* read? save func */ - dp_lastf = fnc; -else return STOP_INVM; /* other? error */ - -switch (fnc) { /* case on function */ - - case FNC_RSCO: /* read sec cnt ov */ - BS = dcf + DCF_CNT; /* set count back */ - /* fall thru */ - case FNC_READ: /* read */ - psec = dp_fndsec (uptr, sec, dcf); /* find sector */ - if (psec < 0) /* addr cmp error? */ - CRETIOE (iochk, STOP_INVDAD); - for (;;) { /* loop */ - qzr = (--cnt == 0); /* set zero latch */ - dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* redo count */ - if (r = dp_rdsec (uptr, psec, flg, qwc)) /* read sector */ - break; - cnt = dp_get_cnt (dcf); /* get new count */ - if (cnt < 0) /* bad count? */ - return STOP_INVDCN; - if (qzr) /* zero latch? done */ - break; - sec++; psec++; /* next sector */ - dp_cvt_bin (dcf + DCF_SEC, DCF_SEC_LEN, sec, flg); /* rewr sec */ - if (r = dp_nexsec (uptr, psec, dcf)) /* find next */ - break; - } - break; /* done, clean up */ - - case FNC_RTRK: /* read track */ - AS = dcf + 9; /* special AS */ - psec = dp_trkop (drv, sec); /* start of track */ - for (;;) { /* loop */ - qzr = (--cnt == 0); /* set zero latch */ - dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* redo count */ - if (r = dp_rdadr (uptr, psec, flg, qwc)) /* read addr */ - break; /* error? */ - if (r = dp_rdsec (uptr, psec, flg, qwc)) /* read data */ - break; /* error? */ - cnt = dp_get_cnt (dcf); /* get new count */ - if (cnt < 0) /* bad count? */ - return STOP_INVDCN; - if (qzr) /* zero latch? done */ - break; - psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC); - } - break; /* done, clean up */ - - case FNC_WRSCO: /* write sec cnt ov */ - BS = dcf + DCF_CNT; /* set count back */ - /* fall through */ - case FNC_WRITE: /* read */ - psec = dp_fndsec (uptr, sec, dcf); /* find sector */ - if (psec < 0) /* addr cmp error? */ - CRETIOE (iochk, STOP_INVDAD); - for (;;) { /* loop */ - qzr = (--cnt == 0); /* set zero latch */ - dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* rewr cnt */ - if (r = dp_wrsec (uptr, psec, flg)) /* write data */ - break; - if (qzr) /* zero latch? done */ - break; - sec++; psec++; /* next sector */ - dp_cvt_bin (dcf + DCF_SEC, DCF_SEC_LEN, sec, flg); /* rewr sec */ - if (r = dp_nexsec (uptr, psec, dcf)) /* find next */ - break; - } - break; /* done, clean up */ - - case FNC_WRTRK: /* write track */ - if ((uptr->flags & UNIT_WAE) == 0) /* enabled? */ - return STOP_WRADIS; - AS = dcf + 9; /* special AS */ - psec = dp_trkop (drv, sec); /* start of track */ - for (;;) { /* loop */ - qzr = (--cnt == 0); /* set zero latch */ - dp_cvt_bin (dcf + DCF_CNT, DCF_CNT_LEN, cnt, MD_WM); /* redo count */ - if (r = dp_wradr (uptr, psec, flg)) /* write addr */ - break; - if (r = dp_wrsec (uptr, psec, flg)) /* write data */ - break; - if (qzr) /* zero latch? done */ - break; - psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC); - } - break; /* done, clean up */ - - default: /* unknown */ - return STOP_INVDFN; - } - -if (r == SCPE_OK) { /* normal so far? */ - BS++; /* advance BS */ - if (ADDR_ERR (BS)) /* address error? */ - return STOP_WRAP; - if (M[BS - 1] != (WM + BCD_GRPMRK)) { /* GM + WM at end? */ - ind[IN_LNG] = ind[IN_DSK] = 1; /* no, error */ - r = STOP_INVDLN; - } - } -CRETIOE (iochk || !ind[IN_DSK], r); /* return status */ -} - -/* Read or compare address with memory */ - -t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 flg, int32 qwc) -{ -int32 i; -uint8 ac; -int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */ -uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */ -t_bool zad = dp_zeroad (ap); /* zero address */ -static const int32 dec_tab[DP_ADDR] = { /* powers of 10 */ - 100000, 10000, 1000, 100, 10, 1 - } ; - -for (i = 0; i < DP_ADDR; i++) { /* copy address */ - if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */ - ind[IN_LNG] = ind[IN_DSK] = 1; /* error */ - return STOP_INVDLN; - } - if (zad) { /* addr zero? */ - ac = sec / dec_tab[i]; /* get addr digit */ - sec = sec % dec_tab[i]; /* get remainder */ - ac = bcd_to_bin[ac]; /* cvt to BCD */ - } - else ac = *ap; /* addr char */ - if (qwc) { /* wr chk? skip if zad */ - if (!zad && (flg? (M[BS] != ac): /* L? cmp with WM */ - ((M[BS] & CHAR) != (ac & CHAR)))) { /* M? cmp w/o WM */ - ind[IN_DPW] = ind[IN_DSK] = 1; - return STOP_WRCHKE; - } - } - else if (flg) /* load mode */ - M[BS] = ac & CHAR; - else M[BS] = (M[BS] & WM) | (ac & CHAR); /* move mode */ - ap++; BS++; /* adv ptrs */ - if (ADDR_ERR (BS)) - return STOP_WRAP; - } -return SCPE_OK; -} - -/* Read or compare data with memory */ - -t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 flg, int32 qwc) -{ -int32 i, lim; -int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */ -uint8 *ap = ((uint8 *) uptr->filebuf) + da + DP_ADDR; /* buf ptr */ - -lim = flg? (DP_DATA - 10): DP_DATA; /* load vs move */ -for (i = 0; i < lim; i++) { /* copy data */ - if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */ - ind[IN_LNG] = ind[IN_DSK] = 1; /* error */ - return STOP_INVDLN; - } - if (qwc) { /* write check? */ - if (flg? (M[BS] != *ap): /* load mode cmp */ - ((M[BS] & CHAR) != (*ap & CHAR))) { /* move mode cmp */ - ind[IN_DPW] = ind[IN_DSK] = 1; /* error */ - return STOP_WRCHKE; - } - } - else if (flg) /* load mode */ - M[BS] = *ap & (WM | CHAR); - else M[BS] = (M[BS] & WM) | (*ap & CHAR); /* word mode */ - ap++; /* adv ptrs */ - BS++; - if (ADDR_ERR (BS)) - return STOP_WRAP; - } -return SCPE_OK; -} - -/* Write address to disk */ - -t_stat dp_wradr (UNIT *uptr, int32 sec, int32 flg) -{ -int32 i; -uint32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */ -uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */ - -for (i = 0; i < DP_ADDR; i++) { /* copy address */ - if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */ - dp_fill (uptr, da, DP_NUMCH - i); /* fill, set err */ - ind[IN_LNG] = ind[IN_DSK] = 1; /* error */ - return STOP_INVDLN; - } - if (flg) /* L? copy WM */ - *ap = M[BS] & (WM | CHAR); - else *ap = M[BS] & CHAR; /* M? strip WM */ - if (da >= uptr->hwmark) - uptr->hwmark = da + 1; - da++; /* adv ptrs */ - ap++; - BS++; - if (ADDR_ERR (BS)) - return STOP_WRAP; - } -return SCPE_OK; -} - -/* Write data to disk */ - -t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 flg) -{ -int32 i, lim; -uint32 da = ((sec % DP_TOTSC) * DP_NUMCH) + DP_ADDR; /* char number */ -uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */ - -lim = flg? (DP_DATA - 10): DP_DATA; /* load vs move */ -for (i = 0; i < lim; i++) { /* copy data */ - if (M[BS] == (WM | BCD_GRPMRK)) { /* premature GWM? */ - dp_fill (uptr, da, DP_DATA - i); /* fill, set err */ - ind[IN_LNG] = ind[IN_DSK] = 1; /* error */ - return STOP_INVDLN; - } - if (flg) /* load, copy WM */ - *ap = M[BS] & (WM | CHAR); - else *ap = M[BS] & CHAR; /* move, strip WM */ - if (da >= uptr->hwmark) - uptr->hwmark = da + 1; - da++; /* adv ptrs */ - ap++; - BS++; - if (ADDR_ERR (BS)) - return STOP_WRAP; - } -return SCPE_OK; -} - -/* Find sector */ - -int32 dp_fndsec (UNIT *uptr, int32 sec, int32 dcf) -{ -int32 ctrk = sec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */ -int32 psec = ((uptr->CYL) * (DP_NUMSF * DP_NUMSC)) + ctrk; -int32 da = psec * DP_NUMCH; /* char number */ -uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */ -int32 i; - -if (dp_zeroad (ap)) /* addr zero? ok */ - return psec; -if (dp_cmp_ad (ap, dcf)) /* addr comp? ok */ - return psec; -psec = psec - (psec % DP_NUMSC); /* sector 0 */ -for (i = 0; i < DP_NUMSC; i++, psec++) { /* check track */ - da = psec * DP_NUMCH; /* char number */ - ap = ((uint8 *) uptr->filebuf) + da; /* word pointer */ - if (dp_zeroad (ap)) /* no implicit match */ - continue; - if (dp_cmp_ad (ap, dcf)) /* match? */ - return psec; - } -ind[IN_UNA] = ind[IN_DSK] = 1; /* no match */ -return -1; -} - -/* Find next sector - must be sequential, cannot cross cylinder boundary */ - -t_stat dp_nexsec (UNIT *uptr, int32 psec, int32 dcf) -{ -int32 ctrk = psec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */ -int32 da = psec * DP_NUMCH; /* word number */ -uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */ - -if (ctrk) { /* not trk zero? */ - if (dp_zeroad (ap)) /* addr zero? ok */ - return SCPE_OK; - if (dp_cmp_ad (ap, dcf)) /* addr comp? ok */ - return SCPE_OK; - } -ind[IN_UNA] = ind[IN_DSK] = 1; /* no, error */ -return STOP_INVDAD; -} - -/* Test for zero address */ - -t_bool dp_zeroad (uint8 *ap) -{ -int32 i; - -for (i = 0; i < DP_ADDR; i++, ap++) { /* loop thru addr */ - if (*ap & CHAR) /* nonzero? lose */ - return FALSE; - } -return TRUE; /* all zeroes */ -} - -/* Compare disk address to memory sector address - always omit word marks */ - -t_bool dp_cmp_ad (uint8 *ap, int32 dcf) -{ -int32 i; -uint8 c; - -for (i = 0; i < DP_ADDR; i++, ap++) { /* loop thru addr */ - c = M[dcf + DCF_SEC + i]; /* sector addr char */ - if ((c & CHAR) != (*ap & CHAR)) /* cmp w/o WM */ - return FALSE; - } -return TRUE; /* compare ok */ -} - -/* Track operation setup */ - -int32 dp_trkop (int32 drv, int32 sec) -{ -int32 ctrk = (sec / DP_NUMSC) % DP_NUMSF; - -return ((drv * DP_TOTSC) + (dp_unit[drv].CYL * DP_NUMSF * DP_NUMSC) + - (ctrk * DP_NUMSC)); -} - -/* Convert DCF BCD field to binary */ - -int32 dp_cvt_bcd (int32 ad, int32 len) -{ -uint8 c; -int32 r; - -for (r = 0; len > 0; len--) { /* loop thru char */ - c = M[ad] & DIGIT; /* get digit */ - if ((c == 0) || (c > BCD_ZERO)) /* invalid? */ - return -1; - r = (r * 10) + bcd_to_bin[c]; /* cvt to bin */ - ad++; /* next digit */ - } -return r; -} - -/* Convert binary to DCF BCD field */ - -void dp_cvt_bin (int32 ad, int32 len, int32 val, int32 flg) -{ -int32 r; - -for ( ; len > 0; len--) { /* loop thru char */ - r = val % 10; /* get digit */ - if (flg) /* load mode? */ - M[ad + len - 1] = bin_to_bcd[r]; - else M[ad + len - 1] = (M[ad + len - 1] & WM) | bin_to_bcd[r]; - val = val / 10; - } -return; -} - -/* Get and validate count */ - -int32 dp_get_cnt (int32 dcf) -{ -int32 cnt = dp_cvt_bcd (dcf + DCF_CNT, DCF_CNT_LEN); /* get new count */ -if (cnt < 0) /* bad count? */ - return -1; -if (cnt == 0) /* 0 => 1000 */ - return 1000; -return cnt; -} - -/* Fill sector buffer with blanks */ - -void dp_fill (UNIT *uptr, uint32 da, int32 cnt) -{ -while (cnt-- > 0) { /* fill with blanks */ - *(((uint8 *) uptr->filebuf) + da) = BCD_BLANK; - if (da >= uptr->hwmark) - uptr->hwmark = da + 1; - da++; - } -return; -} - -/* Reset routine */ - -t_stat dp_reset (DEVICE *dptr) -{ -int32 i; - -for (i = 0; i < DP_NUMDR; i++) /* reset cylinder */ - dp_unit[i].CYL = 0; -dp_lastf = 0; /* clear state */ -ind[IN_DPW] = ind[IN_LNG] = ind[IN_UNA] = 0; /* clr indicators */ -ind[IN_DSK] = ind[IN_ACC] = ind[IN_DBY] = 0; -sim_cancel (&dp_unit[0]); /* cancel timer */ -return SCPE_OK; -} diff --git a/I1401/i1401_iq.c b/I1401/i1401_iq.c deleted file mode 100644 index bd9b5c1d..00000000 --- a/I1401/i1401_iq.c +++ /dev/null @@ -1,199 +0,0 @@ -/* i1401_iq.c: IBM 1407 inquiry terminal - - Copyright (c) 1993-2015, 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. - - inq 1407 inquiry terminal - - 08-Mar-15 RMS Renamed puts_tty to inq_puts - 20-Sep-05 RMS Revised for new code tables - 22-Dec-02 RMS Added break support - 07-Sep-01 RMS Moved function prototypes - 14-Apr-99 RMS Changed t_addr to unsigned -*/ - -#include "i1401_defs.h" -#include - -#define UNIT_V_PCH (UNIT_V_UF + 0) /* output conv */ -#define UNIT_PCH (1 << UNIT_V_PCH) - -extern volatile int32 stop_cpu; -extern uint8 M[]; -extern int32 BS, iochk, ind[64]; -extern UNIT cpu_unit; -extern t_bool conv_old; - -int32 inq_char = 033; /* request inq */ -t_stat inq_svc (UNIT *uptr); -t_stat inq_reset (DEVICE *dptr); - -void inq_puts (char *cptr); - -/* INQ data structures - - inq_dev INQ device descriptor - inq_unit INQ unit descriptor - inq_reg INQ register list -*/ - -UNIT inq_unit = { UDATA (&inq_svc, 0, 0), KBD_POLL_WAIT }; - -REG inq_reg[] = { - { ORDATA (INQC, inq_char, 7) }, - { FLDATA (INR, ind[IN_INR], 0) }, - { FLDATA (INC, ind[IN_INC], 0) }, - { DRDATA (TIME, inq_unit.wait, 24), REG_NZ + PV_LEFT }, - { NULL } - }; - -MTAB inq_mod[] = { - { UNIT_PCH, 0, "business set", "BUSINESS" }, - { UNIT_PCH, UNIT_PCH, "Fortran set", "FORTRAN" }, - { 0 } - }; - -DEVICE inq_dev = { - "INQ", &inq_unit, inq_reg, inq_mod, - 1, 10, 31, 1, 8, 7, - NULL, NULL, &inq_reset, - NULL, NULL, NULL - }; - -/* Terminal I/O - - Modifiers have not been checked; legal modifiers are R and W -*/ - -t_stat inq_io (int32 flag, int32 mod) -{ -int32 i, t, wm_seen = 0; -t_bool use_h = inq_unit.flags & UNIT_PCH; - -ind[IN_INC] = 0; /* clear inq clear */ -switch (mod) { /* case on mod */ - - case BCD_R: /* input */ -// if (ind[IN_INR] == 0) -// return SCPE_OK; /* return if no req */ - ind[IN_INR] = 0; /* clear req */ - inq_puts ("[Enter]\r\n"); /* prompt */ - for (i = 0; M[BS] != (BCD_GRPMRK + WM); i++) { /* until GM + WM */ - while (((t = sim_poll_kbd ()) == SCPE_OK) || - (t & SCPE_BREAK)) { - if (stop_cpu) /* interrupt? */ - return SCPE_STOP; - } - if (t < SCPE_KFLAG) /* if not char, err */ - return t; - t = t & 0177; - if ((t == '\r') || (t == '\n')) - break; - if (t == inq_char) { /* cancel? */ - ind[IN_INC] = 1; /* set indicator */ - inq_puts ("\r\n[Canceled]\r\n"); - return SCPE_OK; - } - if (i && ((i % INQ_WIDTH) == 0)) - inq_puts ("\r\n"); - sim_putchar (t); /* echo */ - if (flag == MD_WM) { /* word mark mode? */ - if ((t == '~') && (wm_seen == 0)) - wm_seen = WM; - else { - M[BS] = wm_seen | ascii2bcd (t); - wm_seen = 0; - } - } - else M[BS] = (M[BS] & WM) | ascii2bcd (t); - if (!wm_seen) - BS++; - if (ADDR_ERR (BS)) { - BS = BA | (BS % MAXMEMSIZE); - return STOP_NXM; - } - } - inq_puts ("\r\n"); - M[BS++] = BCD_GRPMRK + WM; - break; - - case BCD_W: /* output */ - for (i = 0; (t = M[BS++]) != (BCD_GRPMRK + WM); i++) { - if ((flag == MD_WM) && (t & WM)) { - if (i && ((i % INQ_WIDTH) == 0)) - inq_puts ("\r\n"); - if (conv_old) - sim_putchar ('~'); - else sim_putchar ('`'); - } - if (i && ((i % INQ_WIDTH) == 0)) - inq_puts ("\r\n"); - sim_putchar (bcd2ascii (t & CHAR, use_h)); - if (ADDR_ERR (BS)) { - BS = BA | (BS % MAXMEMSIZE); - return STOP_NXM; - } - } - inq_puts ("\r\n"); - break; - - default: /* invalid mod */ - return STOP_INVM; - } - -return SCPE_OK; -} - -/* Unit service - polls for WRU or inquiry request */ - -t_stat inq_svc (UNIT *uptr) -{ -int32 temp; - -sim_activate (&inq_unit, inq_unit.wait); /* continue poll */ -if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */ - return temp; -if ((temp & 0177) == inq_char) /* set indicator */ - ind[IN_INR] = 1; -return SCPE_OK; -} - -/* Output multiple characters */ - -void inq_puts (char *cptr) -{ -if (cptr == NULL) - return; -while (*cptr != 0) - sim_putchar (*cptr++); -return; -} - -/* Reset routine */ - -t_stat inq_reset (DEVICE *dptr) -{ -ind[IN_INR] = ind[IN_INC] = 0; /* clear indicators */ -sim_activate (&inq_unit, inq_unit.wait); /* activate poll */ -return SCPE_OK; -} diff --git a/I1401/i1401_lp.c b/I1401/i1401_lp.c deleted file mode 100644 index 64dd2522..00000000 --- a/I1401/i1401_lp.c +++ /dev/null @@ -1,287 +0,0 @@ -/* i1401_lp.c: IBM 1403 line printer simulator - - Copyright (c) 1993-2015, 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 - - 08-Mar-15 RMS Added print to console option - 16-Apr-13 RMS Fixed printer chain selection - 19-Jan-07 RMS Added UNIT_TEXT flag - 07-Mar-05 RMS Fixed bug in write_line (Van Snyder) - 25-Apr-03 RMS Revised for extended file support - 30-May-02 RMS Widened POS to 32b - 13-Apr-01 RMS Revised for register arrays -*/ - -#include "i1401_defs.h" - -extern uint8 M[]; -extern char bcd_to_ascii_old[64]; -extern char bcd_to_ascii_a[64], bcd_to_ascii_h[64]; -extern char bcd_to_pca[64], bcd_to_pch[64]; -extern int32 iochk, ind[64]; -extern t_bool conv_old; - -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); -t_stat lpt_puts (char *buf); - -extern void inq_puts (char *buf); - -char *pch_table_old[4] = { - bcd_to_ascii_old, bcd_to_ascii_old, bcd_to_pca, bcd_to_pch - }; -char *pch_table[4] = { - bcd_to_ascii_a, bcd_to_ascii_h, bcd_to_pca, bcd_to_pch - }; - -#define UNIT_V_FT (UNIT_V_UF + 0) -#define UNIT_V_48 (UNIT_V_UF + 1) -#define UNIT_V_CONS (UNIT_V_UF + 2) -#define UNIT_FT (1 << UNIT_V_FT) -#define UNIT_48 (1 << UNIT_V_48) -#define UNIT_CONS (1 << UNIT_V_CONS) -#define GET_PCHAIN(x) (((x) >> UNIT_V_FT) & 03) -#define CHP(ch,val) ((val) & (1 << (ch))) - -/* LPT data structures - - lpt_dev LPT device descriptor - lpt_unit LPT unit descriptor - lpt_reg LPT register list -*/ - -UNIT lpt_unit = { - UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0) - }; - -REG lpt_reg[] = { - { FLDATA (ERR, ind[IN_LPT], 0) }, - { DRDATA (POS, lpt_unit.pos, T_ADDR_W), 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 }, - { NULL } - }; - -MTAB lpt_mod[] = { - { UNIT_48, UNIT_48, "48 character chain", "48" }, - { UNIT_48, 0, "64 character chain", "64" }, - { UNIT_FT, UNIT_FT, "Fortran set", "FORTRAN" }, - { UNIT_FT, 0, "business set", "BUSINESS" }, - { UNIT_CONS, UNIT_CONS, "default to console", "DEFAULT" }, - { UNIT_CONS, 0 , "no default device", "NODEFAULT" }, - { UNIT_FT|UNIT_48, 0, NULL, "PCF" }, /* obsolete */ - { UNIT_FT|UNIT_48, UNIT_48, NULL, "PCA" }, - { UNIT_FT|UNIT_48, UNIT_FT|UNIT_48, NULL, "PCH" }, - { 0 } - }; - -DEVICE lpt_dev = { - "LPT", &lpt_unit, lpt_reg, lpt_mod, - 1, 10, 31, 1, 8, 7, - NULL, NULL, &lpt_reset, - NULL, &lpt_attach, NULL - }; - -/* Print routine - - Modifiers have been checked by the caller - SQUARE = word mark mode - S = suppress automatic newline -*/ - -t_stat write_line (int32 ilnt, int32 mod) -{ -int32 i, t, wm, sup; -char *bcd2asc; -t_stat r; -static char lbuf[LPT_WIDTH + 1]; /* + null */ - -wm = ((ilnt == 2) || (ilnt == 5)) && (mod == BCD_SQUARE); -sup = ((ilnt == 2) || (ilnt == 5)) && (mod == BCD_S); -ind[IN_LPT] = 0; /* clear error */ -t = GET_PCHAIN (lpt_unit.flags); -if (conv_old) /* get print chain */ - bcd2asc = pch_table_old[t]; -else bcd2asc = pch_table[t]; -for (i = 0; i < LPT_WIDTH; i++) { /* convert print buf */ - t = M[LPT_BUF + i]; - if (wm) /* wmarks -> 1 or sp */ - lbuf[i] = (t & WM)? '1': ' '; - else lbuf[i] = bcd2asc[t & CHAR]; /* normal */ - } -lbuf[LPT_WIDTH] = 0; /* trailing null */ -for (i = LPT_WIDTH - 1; (i >= 0) && (lbuf[i] == ' '); i--) - lbuf[i] = 0; -if ((r = lpt_puts (lbuf)) != SCPE_OK) /* write line */ - return r; /* error? */ -if (lines) /* cc action? do it */ - r = space (lines, lflag); -else if (sup == 0) /* default? 1 line */ - r = space (1, FALSE); -else r = lpt_puts ("\r"); /* sup -> overprint */ -lines = lflag = 0; /* clear cc action */ -return r; -} - -/* Carriage control routine - - The modifier has not been checked, its format is - <5:4> = 00, skip to channel now - = 01, space lines after - = 10, space lines now - = 11, skip to channel after - <3:0> = number of lines or channel number -*/ - -t_stat carriage_control (int32 mod) -{ -int32 i, action; - -action = (mod & ZONE) >> V_ZONE; /* get mod type */ -mod = mod & DIGIT; /* isolate value */ - -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_CCT; /* runaway channel */ - - case 1: /* space after */ - if (mod <= 3) { - lines = mod; /* save # lines */ - lflag = FALSE; /* flag spacing */ - ind[IN_CC9] = ind[IN_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)) /* check channel */ - return SCPE_OK; - ind[IN_CC9] = ind[IN_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_CCT; /* runaway channel */ - } - -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; -t_stat r; - -cctptr = (cctptr + count) % cctlnt; /* adv cct, mod lnt */ -if (sflag && CHP (0, cct[cctptr])) /* skip, top of form? */ - r = lpt_puts ("\n\f"); /* nl, ff */ -else { - for (i = 0; (i < count); i++) - if ((r = lpt_puts ("\n")) != SCPE_OK) - break; - } -ind[IN_CC9] = CHP (9, cct[cctptr]) != 0; /* set indicators */ -ind[IN_CC12] = CHP (12, cct[cctptr]) != 0; -return r; -} - - -/* Centralized string print routine - Prints to either a file or the console - - Note that if printing to the console, newline must be converted to crlf */ - -t_stat lpt_puts (char *buf) -{ -if ((lpt_unit.flags & UNIT_ATT) != 0) { /* attached? */ - fputs (buf, lpt_unit.fileref); /* print string */ - if (ferror (lpt_unit.fileref)) { /* error? */ - ind[IN_LPT] = 1; - perror ("Line printer I/O error"); - clearerr (lpt_unit.fileref); - if (iochk) - return SCPE_IOERR; - } - lpt_unit.pos = ftell (lpt_unit.fileref); /* update position */ - return SCPE_OK; - } -if ((lpt_unit.flags & UNIT_CONS) != 0) { /* default to cons? */ - if (buf[0] == '\n') { /* bare lf? */ - inq_puts ("\r"); /* cvt to crlf */ - lpt_unit.pos = lpt_unit.pos + 1; - } - inq_puts (buf); - lpt_unit.pos = lpt_unit.pos + strlen (buf); - return SCPE_OK; - } -return SCPE_UNATT; -} - -/* Reset routine */ - -t_stat lpt_reset (DEVICE *dptr) -{ -cctptr = 0; /* clear cct ptr */ -lines = lflag = 0; /* no cc action */ -ind[IN_LPT] = 0; -return SCPE_OK; -} - -/* Attach routine */ - -t_stat lpt_attach (UNIT *uptr, char *cptr) -{ -cctptr = 0; /* clear cct ptr */ -lines = 0; /* no cc action */ -ind[IN_LPT] = 0; -return attach_unit (uptr, cptr); -} diff --git a/I1401/i1401_mt.c b/I1401/i1401_mt.c deleted file mode 100644 index 83b29027..00000000 --- a/I1401/i1401_mt.c +++ /dev/null @@ -1,482 +0,0 @@ -/* i1401_mt.c: IBM 1401 magnetic tape simulator - - Copyright (c) 1993-2016, 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. - - mt 7-track magtape - - 20-Oct-16 RMS Must call sim_tape_attach to use library (Mark Pizzolato) - 03-Sep-13 RMS Read TMK does not write GM+WM to memory - 19-Mar-11 RMS Restored lost edit to insert EOF in memory on read EOF - Reverted multiple tape indicator implementation - 20-Jan-11 RMS Fixed branch on END indicator per hardware (Van Snyder) - 26-Jun-10 RMS Fixed backspace over tapemark not to set EOR (Van Snyder) - 11-Jul-08 RMS Added -n (no rewind) option to BOOT (Van Snyder) - Added tape mark detect to diagnostic read (Bob Abeles) - Added tape mark detect in multi-character records (Bob Abeles) - Fixed memory leak in tape rewind-unload op (Bob Abeles) - Fixed bug, BOOT ignores GM+WM in memory (Bob Abeles) - Fixed handling of indicators (Bob Abeles) - Fixed bug to mask input to 6b on read (Bob Abeles) - 07-Jul-07 RMS Removed restriction on load-mode binary tape - 28-Jun-07 RMS Revised read tape mark behavior based on real hardware - (Van Snyder) - 16-Feb-06 RMS Added tape capacity checking - 15-Sep-05 RMS Yet another fix to load read group mark plus word mark - Added debug printouts (Van Snyder) - 26-Aug-05 RMS Revised to use API for write lock check - 16-Aug-03 RMS End-of-record on load read works like move read - (verified on real 1401) - Added diagnostic read (space forward) - 25-Apr-03 RMS Revised for extended file support - 28-Mar-03 RMS Added multiformat support - 15-Mar-03 RMS Fixed end-of-record on load read yet again - 28-Feb-03 RMS Modified for magtape library - 31-Oct-02 RMS Added error record handling - 10-Oct-02 RMS Fixed end-of-record on load read writes WM plus GM - 30-Sep-02 RMS Revamped error handling - 28-Aug-02 RMS Added end of medium support - 12-Jun-02 RMS End-of-record on move read preserves old WM under GM - (Van Snyder) - 03-Jun-02 RMS Modified for 1311 support - 30-May-02 RMS Widened POS to 32b - 22-Apr-02 RMS Added protection against bad record lengths - 30-Jan-02 RMS New zero footprint tape bootstrap (Van Snyder) - 20-Jan-02 RMS Changed write enabled modifier - 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 - 14-Apr-99 RMS Changed t_addr to unsigned - 04-Oct-98 RMS V2.4 magtape format - - Magnetic tapes are represented as a series of variable 16b records - of the form: - - 32b byte count - byte 0 - byte 1 - : - byte n-2 - byte n-1 - 32b byte count - - If the byte count is odd, the record is padded with an extra byte - of junk. File marks are represented by a byte count of 0. - - (Notes on indicators from Bob Abeles) - The 1401 implements a "tape indicator" latch per tape drive. When a - 1401 branch-on-indicator instruction addresses the "end-of-reel" - indicator, the 1401 addresses the "tape indicator" latch in the - currently selected and ready tape drive. The tape drive itself resets - its "tape indicator" latch only when a tape unload occurs. Tape - unload may be initiated by push button control or by the CPU "Rewind - Tape and Unload" instruction. The tape drive sets the "tape - indicator" latch when in write status and the end-of-reel reflective - strip photocell is activated. The CPU resets the "tape indicator" - latch in the selected and ready tape drive when the "end-of-reel" - indicator is tested by a branch-on-indicator instruction. If no tape - drive is selected, or the currently selected tape drive is not ready, - the "end-of-reel" indicator will appear to be off and no "tape - indicator" latch will be reset. The CPU sets the "tape indicator" - latch in the selected and ready tape drive whenever it reads a tape- - mark character in the first character position of a record. -*/ - -#include "i1401_defs.h" -#include "sim_tape.h" - -#define MT_NUMDR 7 /* #drives */ -#define MT_MAXFR (MAXMEMSIZE * 2) /* max transfer */ - -uint8 dbuf[MT_MAXFR]; /* tape buffer */ - -extern uint8 M[]; /* memory */ -extern int32 ind[64]; -extern int32 BS, iochk; -extern UNIT cpu_unit; - -t_stat mt_reset (DEVICE *dptr); -t_stat mt_boot (int32 unitno, DEVICE *dptr); -t_stat mt_map_status (t_stat st); -UNIT *mt_sel_unit (int32 unit); - -/* MT data structures - - mt_dev MT device descriptor - mt_unit MT unit list - mt_reg MT register list - mt_mod MT modifier list -*/ - -UNIT mt_unit[] = { - { UDATA (NULL, UNIT_DIS, 0) }, /* doesn't exist */ - { 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 (IND, ind[IN_END], 0) }, - { FLDATA (ERR, ind[IN_TAP], 0) }, - { DRDATA (POS1, mt_unit[1].pos, T_ADDR_W), PV_LEFT + REG_RO }, - { DRDATA (POS2, mt_unit[2].pos, T_ADDR_W), PV_LEFT + REG_RO }, - { DRDATA (POS3, mt_unit[3].pos, T_ADDR_W), PV_LEFT + REG_RO }, - { DRDATA (POS4, mt_unit[4].pos, T_ADDR_W), PV_LEFT + REG_RO }, - { DRDATA (POS5, mt_unit[5].pos, T_ADDR_W), PV_LEFT + REG_RO }, - { DRDATA (POS6, mt_unit[6].pos, T_ADDR_W), PV_LEFT + REG_RO }, - { NULL } - }; - -MTAB mt_mod[] = { - { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, - { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT", - &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, - { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", "CAPACITY", - &sim_tape_set_capac, &sim_tape_show_capac, NULL }, - { 0 } - }; - -DEVICE mt_dev = { - "MT", mt_unit, mt_reg, mt_mod, - MT_NUMDR, 10, 31, 1, 8, 8, - NULL, NULL, &mt_reset, - &mt_boot, &sim_tape_attach, &sim_tape_detach, - NULL, DEV_DEBUG - }; - -/* Function routine - - Inputs: - unit = unit character - flag = normal, word mark, binary, or boot mode - mod = modifier character - Outputs: - status = status -*/ - -t_stat mt_func (int32 unit, int32 flag, int32 mod) -{ -t_mtrlnt tbc; -UNIT *uptr; -t_stat st; - -if ((uptr = mt_sel_unit (unit)) == NULL) /* sel unit, save */ - return STOP_INVMTU; /* (not valid) */ -if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ - return SCPE_UNATT; -ind[IN_TAP] = 0; /* clear error */ -ind[IN_END] = 0; /* clear indicator */ -switch (mod) { /* case on modifier */ - - case BCD_A: /* diagnostic read */ - if (DEBUG_PRS (mt_dev)) - fprintf (sim_deb, ">>MT%d: diagnostic read\n", unit); - st = sim_tape_rdrecf (uptr, dbuf, &tbc, MT_MAXFR); /* read rec */ - if (st != MTSE_TMK) { /* not tmk? */ - if (st == MTSE_RECE) /* rec in error? */ - ind[IN_TAP] = 1; - else if (st != MTSE_OK) { /* stop on error */ - if (DEBUG_PRS (mt_dev)) - fprintf (sim_deb, ", stopped by status = %d\n", st); - break; - } - if (!(flag & MD_BIN) && /* BCD tape and */ - ((dbuf[0] & CHAR) == BCD_TAPMRK)) /* first char TMK? */ - ind[IN_END] = 1; /* set indicator */ - } - break; - - case BCD_B: /* backspace */ - if (DEBUG_PRS (mt_dev)) - fprintf (sim_deb, ">>MT%d: backspace\n", unit); - st = sim_tape_sprecr (uptr, &tbc); /* space rev */ - if (st == MTSE_TMK) /* ignore TMK */ - st = MTSE_OK; - break; /* end case */ - - case BCD_E: /* erase = nop */ - if (DEBUG_PRS (mt_dev)) - fprintf (sim_deb, ">>MT%d: erase\n", unit); - if (sim_tape_wrp (uptr)) /* write protected? */ - return STOP_MTL; - return SCPE_OK; - - case BCD_M: /* write tapemark */ - if (DEBUG_PRS (mt_dev)) - fprintf (sim_deb, ">>MT%d: write tape mark\n", unit); - st = sim_tape_wrtmk (uptr); /* write tmk */ - break; - - case BCD_R: /* rewind */ - if (DEBUG_PRS (mt_dev)) - fprintf (sim_deb, ">>MT%d: rewind\n", unit); - sim_tape_rewind (uptr); /* update position */ - return SCPE_OK; - - case BCD_U: /* unload */ - if (DEBUG_PRS (mt_dev)) - fprintf (sim_deb, ">>MT%d: rewind and unload\n", unit); - sim_tape_rewind (uptr); /* update position */ - return sim_tape_detach (uptr); /* detach */ - - default: - return STOP_INVM; - } - -return mt_map_status (st); -} - -/* Read and write routines - - Inputs: - unit = unit character - flag = normal, word mark, binary, or boot mode - mod = modifier character - Outputs: - status = status - - Fine point: after a read, the system writes a group mark just - beyond the end of the record. However, first it checks for a - GM + WM; if present, the GM + WM is not changed. Otherwise, - an MCW read sets a GM, preserving the current WM; while an LCA - read sets a GM and clears the WM. -*/ - -t_stat mt_io (int32 unit, int32 flag, int32 mod) -{ -int32 t, wm_seen; -t_mtrlnt i, tbc; -t_stat st; -t_bool passed_eot; -UNIT *uptr; - -if ((uptr = mt_sel_unit (unit)) == NULL) /* sel unit, save */ - return STOP_INVMTU; /* (not valid) */ -if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ - return SCPE_UNATT; -ind[IN_TAP] = 0; /* clear error */ -ind[IN_END] = 0; /* clear indicator */ - -switch (mod) { - - case BCD_R: /* read */ - if (DEBUG_PRS (mt_dev)) - fprintf (sim_deb, ">>MT%d: read from %d", unit, BS); - wm_seen = 0; /* no word mk seen */ - st = sim_tape_rdrecf (uptr, dbuf, &tbc, MT_MAXFR); /* read rec */ - if (st == MTSE_TMK) { /* tape mark? */ - ind[IN_END] = 1; /* set indicator */ - tbc = 1; /* one char read */ - dbuf[0] = BCD_TAPMRK; /* BCD tapemark */ - } - else { /* not tmk? */ - if (st == MTSE_RECE) /* rec in error? */ - ind[IN_TAP] = 1; - else if (st != MTSE_OK) { /* stop on error */ - if (DEBUG_PRS (mt_dev)) - fprintf (sim_deb, ", stopped by status = %d\n", st); - break; - } - if (!(flag & MD_BIN) && /* BCD tape and */ - ((dbuf[0] & CHAR) == BCD_TAPMRK)) /* first char TMK? */ - ind[IN_END] = 1; /* set indicator */ - } - for (i = 0; i < tbc; i++) { /* loop thru buf */ - if (!(flag & MD_BOOT) && /* not boot? check */ - (M[BS] == (BCD_GRPMRK + WM))) { /* GWM in memory? */ - if (DEBUG_PRS (mt_dev)) - fprintf (sim_deb, " to %d, stopped by GMWM\n", BS); - BS++; /* incr BS */ - if (ADDR_ERR (BS)) { /* test for wrap */ - BS = BA | (BS % MAXMEMSIZE); - return STOP_WRAP; - } - return SCPE_OK; /* done */ - } - t = dbuf[i] & CHAR; /* get char, strip parity */ - if (!(flag & MD_BIN) && (t == BCD_ALT)) /* BCD mode alt blank? */ - t = BCD_BLANK; /* real blank */ - if (flag & MD_WM) { /* word mk mode? */ - if ((t == BCD_WM) && (wm_seen == 0)) /* WM char, none prev? */ - wm_seen = WM; /* set flag */ - else { - M[BS] = wm_seen | (t & CHAR); /* char + wm seen */ - wm_seen = 0; /* clear flag */ - } - } - else M[BS] = (M[BS] & WM) | (t & CHAR); /* preserve mem WM */ - if (!wm_seen) - BS++; - if (ADDR_ERR (BS)) { /* check next BS */ - BS = BA | (BS % MAXMEMSIZE); - return STOP_WRAP; - } - } - if (st == MTSE_TMK) /* if TMK, no GM+WM */ - break; - if (M[BS] != (BCD_GRPMRK + WM)) { /* not GM+WM at end? */ - if (flag & MD_WM) /* LCA: clear WM */ - M[BS] = BCD_GRPMRK; - else M[BS] = (M[BS] & WM) | BCD_GRPMRK; /* MCW: save WM */ - } - if (DEBUG_PRS (mt_dev)) - fprintf (sim_deb, " to %d, stopped by EOR\n", BS); - BS++; /* adv BS */ - if (ADDR_ERR (BS)) { /* check final BS */ - BS = BA | (BS % MAXMEMSIZE); - return STOP_WRAP; - } - break; - - case BCD_W: - if (sim_tape_wrp (uptr)) /* locked? */ - return STOP_MTL; - if (M[BS] == (BCD_GRPMRK + WM)) /* eor? */ - return STOP_MTZ; - if (DEBUG_PRS (mt_dev)) - fprintf (sim_deb, ">>MT%d: write from %d", unit, BS); - for (tbc = 0; (t = M[BS++]) != (BCD_GRPMRK + WM); ) { - if ((t & WM) && (flag & MD_WM)) /* WM in wm mode? */ - dbuf[tbc++] = BCD_WM; - if (((t & CHAR) == BCD_BLANK) && !(flag & MD_BIN)) - dbuf[tbc++] = BCD_ALT; - else dbuf[tbc++] = t & CHAR; - if (ADDR_ERR (BS)) { /* check next BS */ - BS = BA | (BS % MAXMEMSIZE); - return STOP_WRAP; - } - } - if (DEBUG_PRS (mt_dev)) - fprintf (sim_deb, " to %d\n", BS - 1); - passed_eot = sim_tape_eot (uptr); /* passed EOT? */ - st = sim_tape_wrrecf (uptr, dbuf, tbc); /* write record */ - if (!passed_eot && sim_tape_eot (uptr)) /* just passed EOT? */ - ind[IN_END] = 1; - if (ADDR_ERR (BS)) { /* check final BS */ - BS = BA | (BS % MAXMEMSIZE); - return STOP_WRAP; - } - break; - - default: - return STOP_INVM; - } - -return mt_map_status (st); -} - -/* Select unit - return unit pointer if valid */ - -UNIT *mt_sel_unit (int32 unit) -{ -if ((unit <= 0) || (unit >= MT_NUMDR)) - return NULL; -return mt_dev.units + unit; -} - -/* Map tape status */ - -t_stat mt_map_status (t_stat st) -{ -switch (st) { - - case MTSE_OK: /* no error */ - case MTSE_BOT: /* reverse into BOT */ - break; - - case MTSE_FMT: /* illegal fmt */ - return SCPE_IERR; - - case MTSE_UNATT: /* not attached */ - return SCPE_UNATT; - - case MTSE_INVRL: /* invalid rec lnt */ - return SCPE_MTRLNT; - - case MTSE_TMK: /* end of file */ - ind[IN_END] = 1; /* set indicator */ - break; - - case MTSE_IOERR: /* IO error */ - ind[IN_TAP] = 1; /* set error */ - if (iochk) - return SCPE_IOERR; - break; - - case MTSE_RECE: /* record in error */ - case MTSE_EOM: /* end of medium */ - ind[IN_TAP] = 1; /* set error */ - break; - - case MTSE_WRP: /* write protect */ - return STOP_MTL; - } - -return SCPE_OK; -} - -/* Reset routine */ - -t_stat mt_reset (DEVICE *dptr) -{ -int32 i; -UNIT *uptr; - -for (i = 0; i < MT_NUMDR; i++) { /* per drive resets */ - if (uptr = mt_sel_unit (i)) { - MT_CLR_PNU (uptr); /* clear pos flag */ - } - } -ind[IN_TAP] = 0; /* clear mt err ind */ -ind[IN_END] = 0; /* clear mt end ind */ -return SCPE_OK; -} - -/* Bootstrap routine - - The 1401 Reference manual states, "...tape data starts loading at address 001 - and continues until an inter-record gap is sensed." GM+WM in memory is ignored. -*/ - -t_stat mt_boot (int32 unitno, DEVICE *dptr) -{ -extern int32 saved_IS; - -if ((sim_switches & SWMASK ('N')) == 0) /* unless -n */ - sim_tape_rewind (&mt_unit[unitno]); /* force rewind */ -BS = 1; /* set BS = 001 */ -mt_io (unitno, MD_WM + MD_BOOT, BCD_R); /* LDA %U1 001 R */ -saved_IS = 1; -return SCPE_OK; -} diff --git a/I1401/i1401_sys.c b/I1401/i1401_sys.c deleted file mode 100644 index ef60a773..00000000 --- a/I1401/i1401_sys.c +++ /dev/null @@ -1,449 +0,0 @@ -/* i1401_sys.c: IBM 1401 simulator interface - - Copyright (c) 1993-2017, 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. - - 13-Mar-17 RMS Fixed possible dull dereference (COVERITY) - 25-Mar-14 RMS Fixed d character printout (Van Snyder) - 25-Mar-12 RMS Fixed && -> & in test (Peter Schorn) - 20-Sep-05 RMS Revised for new code tables - 04-Jan-05 WVS Added address argument support - 14-Nov-04 WVS Added data printout support - 16-Mar-03 RMS Fixed mnemonic for MCS - 03-Jun-02 RMS Added 1311 support - 18-May-02 RMS Added -D feature (Van Snyder) - 26-Jan-02 RMS Fixed H, NOP with no trailing wm (Van Snyder) - 17-Sep-01 RMS Removed multiconsole support - 13-Jul-01 RMS Fixed bug in symbolic output (Peter Schorn) - 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 "i1401_defs.h" -#include - -#define LINE_LNT 80 -extern DEVICE cpu_dev, inq_dev, lpt_dev; -extern DEVICE cdr_dev, cdp_dev, stack_dev; -extern DEVICE dp_dev, mt_dev; -extern UNIT cpu_unit; -extern REG cpu_reg[]; -extern uint8 M[]; -extern char ascii_to_bcd_old[128], ascii_to_bcd[128]; -extern char bcd_to_ascii_old[64], bcd_to_ascii_a[64], bcd_to_ascii_h[64]; -extern int32 store_addr_h (int32 addr); -extern int32 store_addr_t (int32 addr); -extern int32 store_addr_u (int32 addr); -extern t_bool conv_old; - -/* SCP data structures and interface routines - - sim_name simulator name string - sim_PC pointer to saved PC register descriptor - sim_emax maximum number of words for examine/deposit - sim_devices array of pointers to simulated devices - sim_stop_messages array of pointers to stop messages - sim_load binary loader -*/ - -char sim_name[] = "IBM 1401"; - -REG *sim_PC = &cpu_reg[0]; - -int32 sim_emax = LINE_LNT; - -DEVICE *sim_devices[] = { - &cpu_dev, - &inq_dev, - &cdr_dev, - &cdp_dev, - &stack_dev, - &lpt_dev, - &mt_dev, - &dp_dev, - NULL - }; - -const char *sim_stop_messages[] = { - "Unknown error", - "Unimplemented instruction", - "Non-existent memory", - "Non-existent device", - "No WM at instruction start", - "Invalid A address", - "Invalid B address", - "Invalid instruction length", - "Invalid modifer", - "Invalid branch address", - "Breakpoint", - "HALT instruction", - "Invalid MT unit number", - "Invalid MT record length", - "Write to locked MT unit", - "Skip to unpunched CCT channel", - "Card reader empty", - "Address register wrap", - "I/O check", - "Invalid disk sector address", - "Invalid disk sector count", - "Invalid disk unit", - "Invalid disk function", - "Invalid disk record length", - "Write track while disabled", - "Write check error", - "Disk address miscompare", - "Direct seek cylinder exceeds maximum" - }; - -/* Binary loader -- load carriage control tape - - A carriage control tape consists of entries of the form - - (repeat count) column number,column number,column number,... - - The CCT entries are stored in cct[0:lnt-1], cctlnt contains the - number of entries -*/ - -t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) -{ -int32 col, rpt, ptr, mask, cctbuf[CCT_LNT]; -t_stat r; -extern int32 cctlnt, cctptr, cct[CCT_LNT]; -char cbuf[CBUFSIZE], gbuf[CBUFSIZE]; - -if ((*cptr != 0) || (flag != 0)) - return SCPE_ARG; -ptr = 0; -for ( ; (cptr = fgets (cbuf, CBUFSIZE, fileref)) != NULL; ) { /* until eof */ - mask = 0; - if (*cptr == '(') { /* repeat count? */ - cptr = get_glyph (cptr + 1, gbuf, ')'); /* get 1st field */ - rpt = get_uint (gbuf, 10, CCT_LNT, &r); /* repeat count */ - if (r != SCPE_OK) - return SCPE_FMT; - } - else rpt = 1; - while (*cptr != 0) { /* get col no's */ - cptr = get_glyph (cptr, gbuf, ','); /* get next field */ - col = get_uint (gbuf, 10, 12, &r); /* column number */ - if (r != SCPE_OK) - return SCPE_FMT; - mask = mask | (1 << col); /* set bit */ - } - for ( ; rpt > 0; rpt--) { /* store vals */ - if (ptr >= CCT_LNT) - return SCPE_FMT; - cctbuf[ptr++] = mask; - } - } -if (ptr == 0) - return SCPE_FMT; -cctlnt = ptr; -cctptr = 0; -for (rpt = 0; rpt < cctlnt; rpt++) - cct[rpt] = cctbuf[rpt]; -return SCPE_OK; -} - -/* Symbol table */ - -const char *opcode[64] = { - NULL, "R", "W", "WR", "P", "RP", "WP", "WRP", - "SRF", "SPF", NULL, "MA", "MUL", NULL, NULL, NULL, - NULL, "CS", "S", NULL, "MTF", "BWZ", "BBE", NULL, - "MZ", "MCS", NULL, "SWM", "DIV", NULL, NULL, NULL, - NULL, NULL, "SS", "LCA", "MCW", "NOP", NULL, "MCM", - "SAR", NULL, "ZS", NULL, NULL, NULL, NULL, NULL, - NULL, "A", "B", "C", "MN", "MCE", "CC", NULL, - "SBR", NULL, "ZA", "H", "CWM", NULL, NULL, NULL - }; - -/* Print an address from three characters */ - -void fprint_addr (FILE *of, t_value *dig) -{ -int32 addr, xa; -extern int32 hun_table[64], ten_table[64], one_table[64]; - -addr = hun_table[dig[0] & CHAR] + ten_table[dig[1]] + one_table[dig[2]]; -xa = (addr >> V_INDEX) & M_INDEX; -if (xa) - fprintf (of, " %d,%d", addr & ADDRMASK, ((xa - (X1 >> V_INDEX)) / 5) + 1); -else if (addr >= MAXMEMSIZE) - fprintf (of, " %d*", addr & ADDRMASK); -else fprintf (of, " %d", addr); -return; -} - -/* Print unknown opcode as data */ - -t_stat dcw (FILE *of, int32 op, t_value *val, int32 sw) -{ -int32 i; -t_bool use_h = sw & SWMASK ('F'); - -fprintf (of, "DCW @%c", bcd2ascii (op, use_h)); /* assume it's data */ -for (i = 1; i < sim_emax; i++) { - if (val[i] & WM) - break; - fprintf (of, "%c", bcd2ascii (val[i], use_h)); - } -fprintf (of, "@"); -return -(i - 1); /* return # chars */ -} - -/* Symbolic decode - - Inputs: - *of = output stream - addr = current address - *val = values to decode - *uptr = pointer to unit - sw = switches - Outputs: - return = if >= 0, error code - if < 0, number of extra words retired -*/ - -#define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x) - -t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, - UNIT *uptr, int32 sw) -{ -int32 op, flags, ilnt, i, t; -int32 wmch = conv_old? '~': '`'; -t_bool use_h = sw & SWMASK ('F'); -extern int32 op_table[64], len_table[9]; - -if (sw & SWMASK ('C')) { /* character? */ - t = val[0]; - if (uptr->flags & UNIT_BCD) { - if (t & WM) - fputc (wmch, of); - fputc (bcd2ascii (t & CHAR, use_h), of); - } - else fprintf (of, FMTASC (t & 0177)); - return SCPE_OK; - } -if ((uptr != NULL) && (uptr != &cpu_unit)) /* CPU? */ - return SCPE_ARG; -if (sw & SWMASK ('D')) { /* dump? */ - for (i = 0; i < 50; i++) - fprintf (of, "%c", bcd2ascii (val[i] & CHAR, use_h)) ; - fprintf (of, "\n\t"); - for (i = 0; i < 50; i++) - fprintf (of, (val[i] & WM)? "1": " ") ; - return -(i - 1); - } -if (sw & SWMASK ('S')) { /* string? */ - i = 0; - do { - t = val[i++]; - if (t & WM) - fputc (wmch, of); - fputc (bcd2ascii (t & CHAR, use_h), of); - } while ((i < LINE_LNT) && ((val[i] & WM) == 0)); - return -(i - 1); - } -if ((sw & SWMASK ('M')) == 0) - return SCPE_ARG; - -if ((val[0] & WM) == 0) /* WM under op? */ - return STOP_NOWM; -op = val[0]& CHAR; /* isolate op */ -if (opcode[op] == NULL) /* invalid op */ - return dcw (of, op, val, sw); -flags = op_table[op]; /* get flags */ -for (ilnt = 1; ilnt < sim_emax; ilnt++) { /* find inst lnt */ - if (val[ilnt] & WM) - break; - } -if ((flags & (NOWM | HNOP)) && (ilnt > 7)) /* cs, swm, h, nop? */ - ilnt = 7; -else if ((op == OP_B) && (ilnt > 4) && (val[4] == BCD_BLANK)) - ilnt = 4; -if (ilnt == 3) { /* lnt = 3? */ - fprintf (of, "DSA"); /* assume DSA */ - fprint_addr (of, val); /* print addr */ - return -(ilnt - 1); - } -if ((((flags & len_table[(ilnt > 8)? 8: ilnt]) == 0) && /* invalid lnt, */ - (op != OP_NOP)) || /* not nop? */ - (opcode[op] == NULL)) /* or undef? */ - return dcw (of, op, val, sw); -fprintf (of, "%s",opcode[op]); /* print opcode */ -if (ilnt > 2) { /* A address? */ - if (((flags & IO) || (op == OP_NOP)) && (val[1] == BCD_PERCNT)) - fprintf (of, " %%%c%c", bcd2ascii (val[2], use_h), - bcd2ascii (val[3], sw)); - else fprint_addr (of, &val[1]); - } -if (ilnt > 5) /* B address? */ - fprint_addr (of, &val[4]); -if ((ilnt == 2) || (ilnt == 5) || (ilnt >= 8)) /* d character? */ - fprintf (of, " '%c", bcd2ascii (val[ilnt - 1], use_h)); -return -(ilnt - 1); /* return # chars */ -} - -/* get_addr - get address + index pair */ - -t_stat get_addr (char *cptr, t_value *val) -{ -int32 addr, index; -t_stat r; -char gbuf[CBUFSIZE]; - -cptr = get_glyph (cptr, gbuf, ','); /* get address */ -addr = get_uint (gbuf, 10, MAXMEMSIZE, &r); -if (r != SCPE_OK) - return SCPE_ARG; -if (*cptr != 0) { /* more? */ - cptr = get_glyph (cptr, gbuf, ' '); - index = get_uint (gbuf, 10, 3, &r); - if ((r != SCPE_OK) || (index == 0)) - return SCPE_ARG; - } -else index = 0; -if (*cptr != 0) - return SCPE_ARG; -val[0] = store_addr_h (addr); -val[1] = store_addr_t (addr) | (index << V_ZONE); -val[2] = store_addr_u (addr); -return SCPE_OK; -} - -/* get_io - get I/O address */ - -t_stat get_io (char *cptr, t_value *val) -{ -if ((cptr[0] != '%') || (cptr[3] != 0) || - !isalnum (cptr[1]) || !isalnum (cptr[2])) - return SCPE_ARG; -val[0] = BCD_PERCNT; -val[1] = ascii2bcd (cptr[1]); -val[2] = ascii2bcd (cptr[2]); -return SCPE_OK; -} - -/* Symbolic input - - Inputs: - *cptr = pointer to input string - addr = current PC - *uptr = pointer to unit - *val = pointer to output values - sw = switches - Outputs: - status = > 0 error code - <= 0 -number of extra words -*/ - -t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) -{ -int32 i, op, ilnt, t, cflag, wm_seen; -int32 wmch = conv_old? '~': '`'; -extern int32 op_table[64], len_table[9]; -char gbuf[CBUFSIZE]; - -if (uptr == NULL) - uptr = &cpu_unit; -cflag = (uptr == &cpu_unit); /* CPU flag */ -while (isspace (*cptr)) /* absorb spaces */ - cptr++; -if ((sw & SWMASK ('C')) || (sw & SWMASK ('S')) || (*cptr == wmch) || - ((*cptr == '\'') && cptr++) || ((*cptr == '"') && cptr++)) { - wm_seen = 0; - for (i = 0; (i < sim_emax) && (*cptr != 0); ) { - t = *cptr++; /* get character */ - if (cflag && (wm_seen == 0) && (t == wmch)) - wm_seen = WM; - else if (uptr->flags & UNIT_BCD) { - if (t < 040) - return SCPE_ARG; - val[i++] = ascii2bcd (t) | wm_seen; - wm_seen = 0; - } - else val[i++] = t; - } - if ((i == 0) || wm_seen) - return SCPE_ARG; - return -(i - 1); - } - -if (cflag == 0) /* CPU only */ - return SCPE_ARG; -cptr = get_glyph (cptr, gbuf, 0); /* get opcode */ -for (op = 0; op < 64; op++) { /* look it up */ - if (opcode[op] && strcmp (gbuf, opcode[op]) == 0) - break; - } -if (op >= 64) /* successful? */ - return SCPE_ARG; -val[0] = op | WM; /* store opcode */ -cptr = get_glyph (cptr, gbuf, 0); /* get addr or d */ -if (((op_table[op] & IO) && (get_io (gbuf, &val[1]) == SCPE_OK)) || - (get_addr (gbuf, &val[1]) == SCPE_OK)) { - cptr = get_glyph (cptr, gbuf, 0); /* get addr or d */ - if (get_addr (gbuf, &val[4]) == SCPE_OK) { - cptr = get_glyph (cptr, gbuf, ','); /* get d */ - ilnt = 7; /* a and b addresses */ - } - else ilnt = 4; /* a address */ - } -else ilnt = 1; /* no addresses */ -if ((gbuf[0] == '\'') || (gbuf[0] == '"')) { /* d character? */ - t = gbuf[1]; - if ((gbuf[2] != 0) || (*cptr != 0) || (t < 040)) - return SCPE_ARG; /* end and legal? */ - val[ilnt] = ascii2bcd (t); /* save D char */ - ilnt = ilnt + 1; - } -else if (gbuf[0] != 0) /* not done? */ - return SCPE_ARG; -if ((op_table[op] & len_table[ilnt]) == 0) - return STOP_INVL; -return -(ilnt - 1); -} - -/* Convert BCD to ASCII */ - -int32 bcd2ascii (int32 c, t_bool use_h) -{ -if (conv_old) - return bcd_to_ascii_old[c]; -else if (use_h) - return bcd_to_ascii_h[c]; -else return bcd_to_ascii_a[c]; -} - -/* Convert ASCII to BCD */ - -int32 ascii2bcd (int32 c) -{ -if (conv_old) - return ascii_to_bcd_old[c]; -else return ascii_to_bcd[c]; -} diff --git a/I1620/i1620_cd.c b/I1620/i1620_cd.c deleted file mode 100644 index 2b63db45..00000000 --- a/I1620/i1620_cd.c +++ /dev/null @@ -1,546 +0,0 @@ -/* i1620_cd.c: IBM 1622 card reader/punch - - Copyright (c) 2002-2017, Robert M. Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - cdr 1622 card reader - cdp 1622 card punch - - 23-Jun-17 RMS Unattached error does not set RDCHK/WRCHK - 09-Mar-17 RMS Guardbanded translation table lookups (COVERITY) - 31-Jan-15 TFM Changes to translation tables (Tom McBride) - 10-Dec-13 RMS Fixed WA card punch translations (Bob Armstrong) - Fixed card reader EOL processing (Bob Armstrong) - 19-Mar-12 RMS Fixed declarations of saved_pc, io_stop (Mark Pizzolato) - 19-Jan-07 RMS Set UNIT_TEXT flag - 13-Jul-06 RMS Fixed card reader fgets call (Tom McBride) - Fixed card reader boot sequence (Tom McBride) - 21-Sep-05 RMS Revised translation tables for 7094/1401 compatibility - 25-Apr-03 RMS Revised for extended file support - - Cards are represented as ASCII text streams terminated by newlines. - This allows cards to be created and edited as normal files. -*/ - -#include "i1620_defs.h" - -#define CD_LEN 80 - -extern uint8 M[MAXMEMSIZE]; -extern uint8 ind[NUM_IND]; -extern UNIT cpu_unit; -extern uint32 io_stop; - -char cdr_buf[CD_LEN + 2]; -char cdp_buf[CD_LEN + 2]; - -t_stat cdr_reset (DEVICE *dptr); -t_stat cdr_attach (UNIT *uptr, char *cptr); -t_stat cdr_boot (int32 unitno, DEVICE *dptr); -t_stat cdr_read (void); -t_stat cdp_reset (DEVICE *dptr); -t_stat cdp_write (uint32 len); -t_stat cdp_num (uint32 pa, uint32 ndig, t_bool dump); - -/* Card reader data structures - - cdr_dev CDR descriptor - cdr_unit CDR unit descriptor - cdr_reg CDR register list -*/ - -UNIT cdr_unit = { - UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE+UNIT_TEXT, 0) - }; - -REG cdr_reg[] = { - { FLDATA (LAST, ind[IN_LAST], 0) }, - { DRDATA (POS, cdr_unit.pos, T_ADDR_W), PV_LEFT }, - { NULL } - }; - -DEVICE cdr_dev = { - "CDR", &cdr_unit, cdr_reg, NULL, - 1, 10, 31, 1, 8, 7, - NULL, NULL, &cdr_reset, - &cdr_boot, &cdr_attach, NULL - }; - -/* CDP data structures - - cdp_dev CDP device descriptor - cdp_unit CDP unit descriptor - cdp_reg CDP register list -*/ - -UNIT cdp_unit = { - UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0) - }; - -REG cdp_reg[] = { - { DRDATA (POS, cdp_unit.pos, T_ADDR_W), PV_LEFT }, - { NULL } - }; - -DEVICE cdp_dev = { - "CDP", &cdp_unit, cdp_reg, NULL, - 1, 10, 31, 1, 8, 7, - NULL, NULL, &cdp_reset, - NULL, NULL, NULL - }; - -/* Data tables. The card reader presents unusual problems. - - Some of these translations may seem strange. The 1620 could - read and punch cards numerically (one 1620 storage location - per card column) or alphabetically (two 1620 storage locations - per card column). Even though a card might have contained any - possible character (digit, letter, special character), it - could still be read numerically. In this case, some characters - behaved the same as numbers or as record marks. The results - are well defined in IBM documentation. - - In order to make it possible to prepare card decks for input - using normal text editors, ASCII characters have been assigned - to represent 1620 characters that could appear on cards. In most - cases, this was easy since the letters, digits and punctuation - characters all have equivalent ASCII assignments. Five 1620 - characters do not have equivalent ASCII graphics and are - assigned as follows: - - ] is used to represent a flagged zero - | is used to represent a record mark - ! is used to represent a flagged record mark - } is used to represent a group mark - " is used to represent a flagged group mark - - As a concession to some editors, ASCII nul, nl, tab, and lf - characters are accepted and converted to blanks. Also, for - the same reason, lower case letters are treated the same as - upper case on input. All other ASCII characters not in the - 1620 character set are treated as errors. - - (Tom McBride) - -*/ -/* Card reader (ASCII) to numeric (one digit) */ - -const int8 cdr_to_num[128] = { - 0x00, -1, -1, -1, -1, -1, -1, -1, /* 00 */ - -1, 0x00, 0x00, -1, -1, 0x00, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* 10 */ - -1, -1, -1, -1, -1, -1, -1, -1, - 0x00, 0x1A, 0x1F, -1, 0x1B, -1, -1, -1, /* !" $ */ - 0x0C, 0x0C, 0x1C, 0x00, 0x0B, 0x10, 0x0B, 0x01, /* ()*+,-./ */ - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* 01234567 */ - 0x08, 0x09, -1, -1, -1, 0x0B, -1, -1, /* 89 = */ - 0x0C, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* @ABCDEFG */ - 0x08, 0x09, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* HIJKLMNO */ - 0x17, 0x18, 0x19, 0x02, 0x03, 0x04, 0x05, 0x06, /* PQRSTUVW */ - 0x07, 0x08, 0x09, -1, -1, 0x10, -1, -1, /* XYZ ] */ - -1, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, /* `abcdefg */ - 0x08, 0x09, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, /* hijklmno */ - 0x17, 0x18, 0x19, 0x02, 0x03, 0x04, 0x05, 0x06, /* pqrstuvw */ - 0x07, 0x08, 0x09, -1, 0x0A, 0x0F, -1, -1 /* xyz |} */ - }; - -/* Numeric (flag + digit) to card punch (ASCII) */ - -/* Note that all valid digits produce different - codes except that both numeric blanks and flagged - numeric blanks both produce a blank column. (tfm) */ - -const int8 num_to_cdp[32] = { - '0', '1', '2', '3', '4', '5', '6', '7', /* 0 */ - '8', '9', '|', -1, ' ', -1, -1, '}', - ']', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* F + 0 */ - 'Q', 'R', '!', -1, ' ', -1, -1, '"' - }; - -/* Card reader (ASCII) to alphameric (two digits) - - ] reads as 50 (flagged zero) - | reads as 0A (record mark) - ! reads as 5A (flagged record mark) - } reads as 0F (group mark) - " reads as 5F (flagged group mark) - - As a concession to some editors, ASCII nul, nl, tab, and lf - characters are accepted and converted to blanks. Also, for - the same reason, lower case letters are treated the same as - upper case on input. All other ASCII characters not in the - 1620 character set are treated as errors. - -*/ - -const int8 cdr_to_alp[128] = { - 0x00, -1, -1, -1, -1, -1, -1, -1, /* 00 */ - -1, 0x00, 0x00, -1, -1, 0x00, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* 10 */ - -1, -1, -1, -1, -1, -1, -1, -1, - 0x00, 0x5A, 0x5F, -1, 0x13, -1, -1, -1, /* !" $ */ - 0x24, 0x04, 0x14, 0x10, 0x23, 0x20, 0x03, 0x21, /* ()*+,-./ */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 01234567 */ - 0x78, 0x79, -1, -1, -1, 0x33, -1, -1, /* 89 = */ - 0x34, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* @ABCDEFG */ - 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* HIJKLMNO */ - 0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* PQRSTUVW */ - 0x67, 0x68, 0x69, -1, -1, 0x50, -1, -1, /* XYZ ] */ - -1, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* abcdefg */ - 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* hijklmno */ - 0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* pqrstuvw */ - 0x67, 0x68, 0x69, -1, 0x0A, 0x0F, -1, -1 /* xyz |} */ - }; - -/* Alphameric (two digits) to card punch (ASCII). - - All 1620 compilers are know to punch numeric data - (i.e. data that it knows will be read back using RNCD) - in alphameric mode with WACD. Because of that, there are some - alpha to ASCII translations that absolutely MUST work out right - or otherwise we won't be able to load the object decks. - - 50 - punches as ] (flagged zero) - 0A - punches as | (record mark) - 0F - punches as } (group mark) - - If a program punches alphameric data that includes a flagged - record mark or flagged group mark, they will be punched - as below. No known IBM compiler punches any of these but - some application programs do. The mapping of characters for - the card reader and punch is such that a card deck can be - duplicated with a RACD, WACD loop. - - 5A - punches as ! (flagged record mark) - 5F - punches as " (flagged group mark) -*/ - -const int8 alp_to_cdp[256] = { - ' ', -1, -1, '.', ')', -1, -1, -1, /* 00 */ - -1, -1, '|', -1, -1, -1, -1, '}', - '+', -1, -1, '$', '*', -1, -1, -1, /* 10 */ - -1, -1, -1, -1, -1, -1, -1, -1, - '-', '/', -1, ',', '(', -1, -1, -1, /* 20 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, '=', '@', -1, -1, -1, /* 30 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 40 */ - 'H', 'I', -1, -1, -1, -1, -1, -1, - ']', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 50 */ - 'Q', 'R', '!', -1, -1, -1, -1, '"', - -1, '/', 'S', 'T', 'U', 'V', 'W', 'X', /* 60 */ - 'Y', 'Z', -1, -1, -1, -1, -1, -1, - '0', '1', '2', '3', '4', '5', '6', '7', /* 70 */ - '8', '9', -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* 90 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* A0 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* B0 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* C0 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* D0 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* E0 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* F0 */ - -1, -1, -1, -1, -1, -1, -1, -1 - }; - -/* Card reader IO routine - - - Hard errors stop the operation and halt the system. - - Invalid characters place a blank in memory and set RDCHK. - If IO stop is set, the system halts at the end of the operation. -*/ - -t_stat cdr (uint32 op, uint32 pa, uint32 f0, uint32 f1) -{ -int32 i; -int8 cdc; -t_stat r, sta; - -sta = SCPE_OK; /* assume ok */ -switch (op) { /* case on op */ - - case OP_RN: /* read numeric */ - r = cdr_read (); /* fill reader buf */ - if (r != SCPE_OK) /* error? */ - return r; - for (i = 0; i < CD_LEN; i++) { /* transfer to mem */ - cdc = cdr_to_num[cdr_buf[i] & 0177]; /* translate */ - if (cdc < 0) { /* invalid? */ - ind[IN_RDCHK] = 1; /* set read check */ - if (io_stop) /* set return status */ - sta = STOP_INVCHR; - cdc = 0; - } - M[pa] = cdc; /* store digit */ - PP (pa); /* incr mem addr */ - } - break; - - case OP_RA: /* read alphameric */ - r = cdr_read (); /* fill reader buf */ - if (r != SCPE_OK) /* error? */ - return r; - for (i = 0; i < CD_LEN; i++) { /* transfer to mem */ - cdc = cdr_to_alp[cdr_buf[i] & 0177]; /* translate */ - if (cdc < 0) { /* invalid? */ - ind[IN_RDCHK] = 1; /* set read check */ - if (io_stop) /* set return status */ - sta = STOP_INVCHR; - cdc = 0; - }; - M[pa] = (M[pa] & FLAG) | (cdc & DIGIT); /* store 2 digits */ - M[pa - 1] = (M[pa - 1] & FLAG) | ((cdc >> 4) & DIGIT); - pa = ADDR_A (pa, 2); /* incr mem addr */ - } - break; - - default: /* invalid function */ - return STOP_INVFNC; - } - -return sta; -} - -/* Fill card reader buffer - all errors are hard errors - - As Bob Armstrong pointed out, this routines needs to account - for variants in text file formats, which may terminate lines - with cr-lf (Windows), lf (UNIX), or cr (Mac). -*/ - -t_stat cdr_read (void) -{ -int32 i; - -ind[IN_LAST] = 0; /* clear last card */ -if ((cdr_unit.flags & UNIT_ATT) == 0) /* attached? */ - return SCPE_UNATT; - -for (i = 0; i < CD_LEN + 2; i++) /* clear buffer */ - cdr_buf[i] = ' '; -fgets (cdr_buf, CD_LEN + 2, cdr_unit.fileref); /* read card */ -if (feof (cdr_unit.fileref)) /* eof? */ - return STOP_NOCD; -if (ferror (cdr_unit.fileref)) { /* error? */ - ind[IN_RDCHK] = 1; /* set read check */ - sim_perror ("CDR I/O error"); - clearerr (cdr_unit.fileref); - return SCPE_IOERR; - } -if ((i = strlen (cdr_buf)) > 0) { /* anything at all? */ - if (cdr_buf[i-1] == '\n') { /* line end in \n? */ - cdr_buf[i-1] = 0; /* remove it */ - } - else if (cdr_buf[i-1] == '\r') { /* line end in \r? */ - cdr_buf[i-1] = 0; /* remove it */ - cdr_unit.pos = ftell (cdr_unit.fileref); /* save position */ - if (fgetc (cdr_unit.fileref) != '\n') /* next char not \n? */ - fseek (cdr_unit.fileref, cdr_unit.pos, SEEK_SET); /* then rewind */ - } - else { /* line too long */ - ind[IN_RDCHK] = 1; - sim_perror ("CDR line too long"); - return SCPE_IOERR; - } - } -cdr_unit.pos = ftell (cdr_unit.fileref); /* update position */ -getc (cdr_unit.fileref); /* see if more */ -if (feof (cdr_unit.fileref)) /* eof? set last */ - ind[IN_LAST] = 1; -fseek (cdr_unit.fileref, cdr_unit.pos, SEEK_SET); /* "backspace" */ -return SCPE_OK; -} - -/* Card reader attach */ - -t_stat cdr_attach (UNIT *uptr, char *cptr) -{ -ind[IN_LAST] = 0; /* clear last card */ -return attach_unit (uptr, cptr); -} - -/* Card reader reset */ - -t_stat cdr_reset (DEVICE *dptr) -{ -ind[IN_LAST] = 0; /* clear last card */ -return SCPE_OK; -} - -/* Bootstrap routine */ - -#define BOOT_START 0 - -t_stat cdr_boot (int32 unitno, DEVICE *dptr) -{ -t_stat r; -uint32 old_io_stop; -extern uint32 saved_PC; - -old_io_stop = io_stop; -io_stop = 1; -r = cdr (OP_RN, 0, 0, 0); /* read card @ 0 */ -io_stop = old_io_stop; -if (r != SCPE_OK) /* error? */ - return r; -saved_PC = BOOT_START; -return SCPE_OK; -} - -/* Card punch IO routine - - - Hard errors stop the operation and halt the system. - - Invalid characters stop the operation and set WRCHK. - If IO stop is set, the system halts. -*/ - -t_stat cdp (uint32 op, uint32 pa, uint32 f0, uint32 f1) -{ -int32 i; -int8 cdc; -uint8 z, d; - -switch (op) { /* decode op */ - - case OP_DN: - - /* DN punches all characters the same as WN except that a flagged - zero is punched as a hyphen (-) instead of a flagged - zero ([). Punching begins at the P address and continues until - the last digit of the storage module containing the P address - has been punched. If the amount of data to be punched is an - exact multiple of 80, the operation ends there. If the last - character of the module does not fill out the card, additional - characters from the next higher addresses (addressing wraps to - back to zero if the operation started in the highest module) are - used to fill out the card. (Tom McBride) */ - - return cdp_num (pa, /* dump numeric */ - ((20000 - (pa % 20000) + 79) / 80) * 80, - TRUE); - - case OP_WN: - - /* WN always punches exactly 80 characters. If the highest address - in the machine is reached before the card is full, addressing - wraps around to zero and continues. The PP function handles - this correctly. (Tom McBride) */ - - return cdp_num (pa, CD_LEN, FALSE); /* write numeric */ - - case OP_WA: /* write alphanumerically */ - - /* WA always punches exactly 80 characters. If the highest address - in the machine is reached before the card is full, addressing - wraps around to zero and continues. The ADDR_A function handles - this correctly. (Tom McBride) */ - - for (i = 0; i < CD_LEN; i++) { /* one card */ - d = M[pa] & DIGIT; /* get digit pair */ - z = M[pa - 1] & DIGIT; - cdc = alp_to_cdp[(z << 4) | d]; /* translate */ - if (cdc < 0) { /* bad char? */ - ind[IN_WRCHK] = 1; /* set write check */ - CRETIOE (io_stop, STOP_INVCHR); - } - cdp_buf[i] = cdc; /* store in buf */ - pa = ADDR_A (pa, 2); /* incr mem addr */ - } - return cdp_write (CD_LEN); /* punch buffer */ - - default: /* invalid function */ - break; - } - -return STOP_INVFNC; -} - -/* Punch card numeric */ - -t_stat cdp_num (uint32 pa, uint32 ndig, t_bool dump) -{ -int32 i, ncd, len; -uint8 d; -int8 cdc; -t_stat r; - -ncd = ndig / CD_LEN; /* number of cards */ -while (ncd-- >= 0) { /* until done */ - len = (ncd >= 0)? CD_LEN: (ndig % CD_LEN); /* card length */ - if (len == 0) - break; - for (i = 0; i < len; i++) { /* one card */ - d = M[pa] & (FLAG | DIGIT); /* get char */ - if (dump && (d == FLAG)) /* dump? F+0 is diff .. */ - cdc = '-'; /* .. punch as hyphen */ - else cdc = num_to_cdp[d]; /* translate */ - if (cdc < 0) { /* bad char? */ - ind[IN_WRCHK] = 1; /* set write check */ - CRETIOE (io_stop, STOP_INVCHR); /* stop */ - } - cdp_buf[i] = cdc; /* store in buf */ - PP (pa); /* incr mem addr */ - } - r = cdp_write (len); /* punch card */ - if (r != SCPE_OK) /* error? */ - return r; - } -return SCPE_OK; -} - -/* Write punch card buffer - all errors are hard errors */ - -t_stat cdp_write (uint32 len) -{ -if ((cdp_unit.flags & UNIT_ATT) == 0) /* attached? */ - return SCPE_UNATT; - -while ((len > 0) && (cdp_buf[len - 1] == ' ')) /* trim spaces */ - --len; -cdp_buf[len] = '\n'; /* newline, null */ -cdp_buf[len + 1] = 0; - -fputs (cdp_buf, cdp_unit.fileref); /* write card */ -cdp_unit.pos = ftell (cdp_unit.fileref); /* count char */ -if (ferror (cdp_unit.fileref)) { /* error? */ - ind[IN_WRCHK] = 1; - sim_perror ("CDP I/O error"); - clearerr (cdp_unit.fileref); - return SCPE_IOERR; - } -return SCPE_OK; -} - -/* Reset card punch */ - -t_stat cdp_reset (DEVICE *dptr) -{ -return SCPE_OK; -} diff --git a/I1620/i1620_cpu.c b/I1620/i1620_cpu.c deleted file mode 100644 index 0734cb69..00000000 --- a/I1620/i1620_cpu.c +++ /dev/null @@ -1,2427 +0,0 @@ -/* i1620_cpu.c: IBM 1620 CPU simulator - - Copyright (c) 2002-2018, Robert M. Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - This CPU module incorporates code and comments from the 1620 simulator by - Geoff Kuenning, with his permission. - - 05-Jun-18 RMS Fixed bug in select index A (COVERITY) - 23-Jun-17 RMS BS should not enable indexing unless configured - 15-Jun-17 RMS Added more information to IO in progress message - 26-May-17 RMS Added deferred IO mode for slow devices - 20-May-17 RMS Changed to commit PC on certain stops - Added SET CPU RELEASE command - Undefined indicators don't throw an error (Dave Wise) - 19-May-17 RMS Added Model I mode to allow record marks in adds (Dave Wise) - 18-May-17 RMS Allowed undocumented indicator 8 (Dave Wise) - 13-Mar-17 RMS Added error test on device addr (COVERITY) - 07-May-15 RMS Added missing TFL instruction (Tom McBride) - 28-Mar-15 RMS Revised to use sim_printf - 26-Mar-15 RMS Separated compare from add/sub flows (Tom McBride) - Removed ADD_SIGNC return from add/sub flows - 10-Dec-13 RMS Fixed several bugs in add and compare (Bob Armstrong) - Fixed handling of P field in K instruction (Bob Armstrong) - 28-May-06 RMS Fixed bug in cpu history (Peter Schorn) - 22-Sep-05 RMS Fixed declarations (Sterling Garwood) - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 07-Nov-04 RMS Added instruction history - 26-Mar-04 RMS Fixed warnings with -std=c99 - 02-Nov-03 RMS Fixed bug in branch digit (Dave Babcock) - 21-Aug-03 RMS Fixed bug in immediate index add (Michael Short) - 25-Apr-03 RMS Changed t_addr to uint32 throughout - 18-Oct-02 RMS Fixed bugs in invalid result testing (Hans Pufal) - - The simulated register state for the IBM 1620 is: - - 1620 sim comment - - IR1 [PC] program counter - IR2 instruction register 2 (subroutine return address) - OR1 [QAR] Q address - OR2 [PAR] P address - PR1 manual save address - ind[0:99] indicators - - Additional internal registers OR3, PR2, and PR3 are not simulated. - - The IBM 1620 is a fixed instruction length, variable data length, decimal - data system. Memory consists of 20000 - 60000 BCD digits, each containing - four bits of data and a flag. There are no general registers; all - instructions are memory to memory. - - The 1620 uses a fixed, 12 digit instruction format: - - oo ppppp qqqqq - - where - - oo = opcode - ppppp = P (usually destination) address - qqqqq = Q (usually source) address - - Immediate instructions use the qqqqq field as the second operand. - - The 1620 Model 1 uses table lookups for add and multiply; for that reason, - it was nicknamed CADET (Can't Add, Doesn't Even Try). The Model 2 does - adds in hardware and uses the add table memory for index registers. - - The 1620 has no concept of overlapped IO. When an IO instruction is - issued, instruction execution is suspended until the IO is complete. - For "fast" devices, like the disk, IO is done in an instantaneous burst. - "Slow" devices have the option of going character-by-character, with - delays in between. This allows for operator intervention, such as - ^E or changing paper tapes. - - The simulated IO state for character-by-character IO is: - - cpuio_mode set if IO in progress - cpuio_opc saved IO opcode - cpuio_dev saved IO device number - cpuio_cnt character counter; increments - PAR P address; increments - - This routine is the instruction decode routine for the IBM 1620. - It is called from the simulator control program to execute - instructions in simulated memory, starting at the simulated PC. - It runs until 'reason' is set non-zero. - - General notes: - - 1. Reasons to stop. The simulator can be stopped by: - - HALT instruction - breakpoint encountered - illegal addresses or instruction formats - I/O error in I/O simulator - - 2. Interrupts. The 1620 has no interrupt structure. - - 3. Non-existent memory. On the 1620, all memory references - are modulo the memory size. - - 4. Adding I/O devices. These modules must be modified: - - i1620_cpu.c add iodisp table entry - i1620_sys.c add sim_devices table entry -*/ - -#include "i1620_defs.h" - -#define PCQ_SIZE 64 /* must be 2**n */ -#define PCQ_MASK (PCQ_SIZE - 1) -#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = saved_PC - -#define HIST_PC 0x40000000 -#define HIST_MIN 64 -#define HIST_MAX 65536 - -typedef struct { - uint16 vld; - uint16 pc; - uint8 inst[INST_LEN]; - } InstHistory; - -uint8 M[MAXMEMSIZE] = { 0 }; /* main memory */ -uint32 saved_PC = 0; /* saved PC */ -uint32 actual_PC = 0; /* actual PC at halt */ -uint32 IR2 = 1; /* inst reg 2 */ -uint32 PAR = 0; /* P address */ -uint32 QAR = 0; /* Q address */ -uint32 PR1 = 1; /* proc reg 1 */ -uint32 iae = 1; /* ind addr enb */ -uint32 idxe = 0; /* index enable */ -uint32 idxb = 0; /* index band */ -uint32 io_stop = 1; /* I/O stop */ -uint32 ar_stop = 1; /* arith stop */ -uint32 cpuio_inp = 0; /* IO in progress */ -uint32 cpuio_opc = 0; -uint32 cpuio_dev = 0; -uint32 cpuio_cnt = 0; -int32 ind_max = 16; /* iadr nest limit */ -uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ -int32 pcq_p = 0; /* PC queue ptr */ -REG *pcq_r = NULL; /* PC queue reg ptr */ -int32 hst_p = 0; /* history pointer */ -int32 hst_lnt = 0; /* history length */ -InstHistory *hst = NULL; /* instruction history */ -uint8 ind[NUM_IND] = { 0 }; /* indicators */ - -t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); -t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); -t_stat cpu_reset (DEVICE *dptr); -t_stat cpu_set_opt1 (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_opt2 (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_save (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_table (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_release (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc); - -int32 get_2d (uint32 ad); -t_stat get_addr (uint32 alast, int32 lnt, t_bool indexok, uint32 *addr); -t_stat cvt_addr (uint32 alast, int32 lnt, t_bool signok, int32 *val); -t_stat get_idx (uint32 aidx); -t_stat xmt_field (uint32 d, uint32 s, uint32 skp); -t_stat xmt_record (uint32 d, uint32 s, t_bool cpy); -t_stat xmt_index (uint32 d, uint32 s); -t_stat xmt_divd (uint32 d, uint32 s); -t_stat xmt_tns (uint32 d, uint32 s); -t_stat xmt_tnf (uint32 d, uint32 s); -t_stat add_field (uint32 d, uint32 s, t_bool sub, uint32 skp, int32 *sta); -t_stat cmp_field (uint32 d, uint32 s); -uint32 add_one_digit (uint32 dst, uint32 src, uint32 *cry); -t_stat mul_field (uint32 mpc, uint32 mpy); -t_stat mul_one_digit (uint32 mpyd, uint32 mpcp, uint32 prop, uint32 last); -t_stat div_field (uint32 dvd, uint32 dvr, int32 *ez); -t_stat div_one_digit (uint32 dvd, uint32 dvr, uint32 max, uint32 *quod, uint32 *quop); -t_stat oct_to_dec (uint32 tbl, uint32 s); -t_stat dec_to_oct (uint32 d, uint32 tbl, int32 *ez); -t_stat or_field (uint32 d, uint32 s); -t_stat and_field (uint32 d, uint32 s); -t_stat xor_field (uint32 d, uint32 s); -t_stat com_field (uint32 d, uint32 s); -void upd_ind (void); - -extern t_stat tty (uint32 op, uint32 pa, uint32 f0, uint32 f1); -extern t_stat ptp (uint32 op, uint32 pa, uint32 f0, uint32 f1); -extern t_stat ptr (uint32 op, uint32 pa, uint32 f0, uint32 f1); -extern t_stat cdp (uint32 op, uint32 pa, uint32 f0, uint32 f1); -extern t_stat cdr (uint32 op, uint32 pa, uint32 f0, uint32 f1); -extern t_stat dp (uint32 op, uint32 pa, uint32 f0, uint32 f1); -extern t_stat lpt (uint32 op, uint32 pa, uint32 f0, uint32 f1); -extern t_stat btp (uint32 op, uint32 pa, uint32 f0, uint32 f1); -extern t_stat btr (uint32 op, uint32 pa, uint32 f0, uint32 f1); - -extern t_stat fp_add (uint32 d, uint32 s, t_bool sub); -extern t_stat fp_mul (uint32 d, uint32 s); -extern t_stat fp_div (uint32 d, uint32 s); -extern t_stat fp_fsl (uint32 d, uint32 s); -extern t_stat fp_fsr (uint32 d, uint32 s); - -/* CPU data structures - - cpu_dev CPU device descriptor - cpu_unit CPU unit descriptor - cpu_reg CPU register list - cpu_mod CPU modifier list -*/ - -UNIT cpu_unit = { UDATA (NULL, UNIT_FIX+UNIT_BCD+MI_STD, MAXMEMSIZE) }; - -REG cpu_reg[] = { - { DRDATA (PC, saved_PC, 16), PV_LEFT }, - { DRDATA (APC, actual_PC, 16), PV_LEFT + REG_HRO }, - { DRDATA (IR2, IR2, 16), PV_LEFT }, - { DRDATA (PR1, PR1, 16), PV_LEFT }, - { DRDATA (PAR, PAR, 16), PV_LEFT + REG_RO }, - { DRDATA (QAR, QAR, 16), PV_LEFT + REG_RO }, - { FLDATA (SW1, ind[IN_SW1], 0) }, - { FLDATA (SW2, ind[IN_SW2], 0) }, - { FLDATA (SW3, ind[IN_SW3], 0) }, - { FLDATA (SW4, ind[IN_SW4], 0) }, - { FLDATA (HP, ind[IN_HP], 0) }, - { FLDATA (EZ, ind[IN_EZ], 0) }, - { FLDATA (OVF, ind[IN_OVF], 0) }, - { FLDATA (EXPCHK, ind[IN_EXPCHK], 0) }, - { FLDATA (RDCHK, ind[IN_RDCHK], 0) }, - { FLDATA (WRCHK, ind[IN_WRCHK], 0) }, - { FLDATA (ARSTOP, ar_stop, 0) }, - { FLDATA (IOSTOP, io_stop, 0) }, - { FLDATA (IOINP, cpuio_inp, 0), REG_HRO }, - { DRDATA (IOOPC, cpuio_opc, 6), REG_HRO }, - { DRDATA (IODEV, cpuio_dev, 7), REG_HRO }, - { DRDATA (IOCNT, cpuio_cnt, 16), REG_HRO }, - { BRDATA (IND, ind, 10, 1, NUM_IND) }, - { FLDATA (IAE, iae, 0) }, - { FLDATA (IDXE, idxe, 0) }, - { FLDATA (IDXB, idxb, 0) }, - { DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT }, - { BRDATA (PCQ, pcq, 10, 14, PCQ_SIZE), REG_RO+REG_CIRC }, - { ORDATA (PCQP, pcq_p, 6), REG_HRO }, - { ORDATA (WRU, sim_int_char, 8) }, - { NULL } - }; - -MTAB cpu_mod[] = { - { IF_IA, IF_IA, "IA", "IA", &cpu_set_opt1 }, - { IF_IA, 0, "no IA", "NOIA", &cpu_set_opt1 }, - { IF_EDT, IF_EDT, "EDT", "EDT", &cpu_set_opt1 }, - { IF_EDT, 0, "no EDT", "NOEDT", &cpu_set_opt1 }, - { IF_DIV, IF_DIV, "DIV", "DIV", &cpu_set_opt1 }, - { IF_DIV, 0, "no DIV", "NODIV", &cpu_set_opt1 }, - { IF_RMOK, IF_RMOK, "RM allowed", "RMOK", &cpu_set_opt1 }, - { IF_RMOK, 0, "RM disallowed", "NORMOK", &cpu_set_opt1 }, - { IF_FP, IF_FP, "FP", "FP", NULL }, - { IF_FP, 0, "no FP", "NOFP", NULL }, - { IF_BIN, IF_BIN, "BIN", "BIN", &cpu_set_opt2 }, - { IF_BIN, 0, "no BIN", "NOBIN", &cpu_set_opt2 }, - { IF_IDX, IF_IDX, "IDX", "IDX", &cpu_set_opt2 }, - { IF_IDX, 0, "no IDX", "NOIDX", &cpu_set_opt2 }, - { IF_MII, IF_MII, "Model 2", "MOD2", &cpu_set_model }, - { IF_MII, 0, "Model 1", "MOD1", &cpu_set_model }, - { UNIT_MSIZE, 20000, NULL, "20K", &cpu_set_size }, - { UNIT_MSIZE, 40000, NULL, "40K", &cpu_set_size }, - { UNIT_MSIZE, 60000, NULL, "60K", &cpu_set_size }, - { UNIT_MSIZE, 0, NULL, "SAVE", &cpu_set_save }, - { UNIT_MSIZE, 0, NULL, "TABLE", &cpu_set_table }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", - &cpu_set_hist, &cpu_show_hist }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "RELEASE", - &cpu_set_release, NULL }, - { 0 } - }; - -DEVICE cpu_dev = { - "CPU", &cpu_unit, cpu_reg, cpu_mod, - 1, 10, 18, 1, 16, 5, - &cpu_ex, &cpu_dep, &cpu_reset, - NULL, NULL, NULL - }; - -/* Instruction table */ - -const int32 op_table[100] = { - 0, /* 0 */ - IF_FP + IF_VPA + IF_VQA, /* FADD */ - IF_FP + IF_VPA + IF_VQA, /* FSUB */ - IF_FP + IF_VPA + IF_VQA, /* FMUL */ - 0, - IF_FP + IF_VPA + IF_VQA, /* FSL */ - IF_FP + IF_MII + IF_VPA + IF_VQA, /* TFL */ - IF_FP + IF_MII + IF_VPA + IF_VQA, /* BTFL */ - IF_FP + IF_VPA + IF_VQA, /* FSR */ - IF_FP + IF_VPA + IF_VQA, /* FDV */ - IF_MII + IF_VPA + IF_IMM, /* 10: BTAM */ - IF_VPA + IF_IMM, /* AM */ - IF_VPA + IF_IMM, /* SM */ - IF_VPA + IF_IMM, /* MM */ - IF_VPA + IF_IMM, /* CM */ - IF_VPA + IF_IMM, /* TDM */ - IF_VPA + IF_IMM, /* TFM */ - IF_VPA + IF_IMM, /* BTM */ - IF_DIV + IF_VPA + IF_IMM, /* LDM */ - IF_DIV + IF_VPA + IF_IMM, /* DM */ - IF_MII + IF_VPA + IF_VQA, /* 20: BTA */ - IF_VPA + IF_VQA, /* A */ - IF_VPA + IF_VQA, /* S */ - IF_VPA + IF_VQA, /* M */ - IF_VPA + IF_VQA, /* C */ - IF_VPA + IF_VQA, /* TD */ - IF_VPA + IF_VQA, /* TF */ - IF_VPA + IF_VQA, /* BT */ - IF_DIV + IF_VPA + IF_VQA, /* LD */ - IF_DIV + IF_VPA + IF_VQA, /* D */ - IF_MII + IF_VPA + IF_VQA, /* 30: TRNM */ - IF_VPA + IF_VQA, /* TR */ - IF_VPA, /* SF */ - IF_VPA, /* CF */ - 0, /* K */ - IF_VPA, /* DN */ - IF_VPA, /* RN */ - IF_VPA, /* RA */ - IF_VPA, /* WN */ - IF_VPA, /* WA */ - 0, /* 40 */ - 0, /* NOP */ - 0, /* BB */ - IF_VPA + IF_VQA, /* BD */ - IF_VPA + IF_VQA, /* BNF */ - IF_VPA + IF_VQA, /* BNR */ - IF_VPA, /* BI */ - IF_VPA, /* BNI */ - 0, /* H */ - IF_VPA, /* B */ - 0, /* 50 */ - 0, - 0, - 0, - 0, - IF_VPA + IF_VQA, /* BNG - disk sys */ - 0, - 0, - 0, - 0, - IF_MII + IF_VPA, /* 60: BS */ - IF_IDX + IF_VPA + IF_NQX, /* BX */ - IF_IDX + IF_VPA + IF_IMM, /* BXM */ - IF_IDX + IF_VPA + IF_NQX, /* BCX */ - IF_IDX + IF_VPA + IF_IMM, /* BCXM */ - IF_IDX + IF_VPA + IF_NQX, /* BLX */ - IF_IDX + IF_VPA + IF_IMM, /* BLXM */ - IF_IDX + IF_VPA + IF_NQX, /* BSX */ - 0, - 0, - IF_IDX + IF_VPA + IF_VQA, /* 70: MA */ - IF_EDT + IF_VPA + IF_VQA, /* MF */ - IF_EDT + IF_VPA + IF_VQA, /* TNS */ - IF_EDT + IF_VPA + IF_VQA, /* TNF */ - 0, - 0, - 0, - 0, - 0, - 0, - 0, /* 80 */ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - IF_BIN + IF_VPA + IF_4QA, /* 90: BBT */ - IF_BIN + IF_VPA + IF_4QA, /* BMK */ - IF_BIN + IF_VPA + IF_VQA, /* ORF */ - IF_BIN + IF_VPA + IF_VQA, /* ANDF */ - IF_BIN + IF_VPA + IF_VQA, /* CPLF */ - IF_BIN + IF_VPA + IF_VQA, /* EORF */ - IF_BIN + IF_VPA + IF_VQA, /* OTD */ - IF_BIN + IF_VPA + IF_VQA, /* DTO */ - 0, - 0 - }; - -/* IO dispatch table */ - -t_stat (*iodisp[NUM_IO])(uint32 op, uint32 pa, uint32 f0, uint32 f1) = { - NULL, &tty, &ptp, &ptr, &cdp, /* 00 - 09 */ - &cdr, NULL, &dp, NULL, &lpt, - NULL, NULL, NULL, NULL, NULL, /* 10 - 19 */ - NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, /* 20 - 29 */ - NULL, NULL, NULL, NULL, NULL, - NULL, NULL, &btp, &btr, NULL, /* 30 - 39 */ - NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, /* 40 - 49 */ - NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, /* 50 - 59 */ - NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, /* 60 - 69 */ - NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, /* 70 - 79 */ - NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, /* 80 - 89 */ - NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, /* 90 - 99 */ - NULL, NULL, NULL, NULL, NULL - }; - -/* K instruction validate P field table */ - -const uint8 k_valid_p[NUM_IO] = { - 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - -/* Indicator table: -1 = undefined, +1 = resets when tested */ -/* Indicator 8 is MAR CHECK, for maintenance use only */ -/* Undefined indicators always read as 0 */ - -const int32 ind_table[NUM_IND] = { - -1, 0, 0, 0, 0, -1, 1, 1, 0, 1, /* 00 - 09 */ - -1, 0, 0, 0, 1, 1, 1, 1, -1, 0, /* 10 - 19 */ - -1, -1, -1, -1, -1, 0, -1, -1, -1, -1, /* 20 - 29 */ - 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, /* 30 - 39 */ - -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, /* 40 - 49 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 50 - 59 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 60 - 69 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 70 - 79 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 80 - 89 */ - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 /* 90 - 99 */ - }; - -/* Add table for 1620 Model 1 */ - -const uint8 std_add_table[ADD_TABLE_LEN] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, - 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, - 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, - 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, - 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, - 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, - 0x06, 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, - 0x07, 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, - 0x08, 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x09, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18 - }; - -/* Add table for 1620 Model 2 ("hardware add") */ - -const uint8 sum_table[20] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19 - }; - -/* Multiply table */ - -const uint8 std_mul_table[MUL_TABLE_LEN] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 1, 0, 2, 0, 3, 0, 4, 0, - 0, 0, 2, 0, 4, 0, 6, 0, 8, 0, - 0, 0, 3, 0, 6, 0, 9, 0, 2, 1, - 0, 0, 4, 0, 8, 0, 2, 1, 6, 1, - 0, 0, 5, 0, 0, 1, 5, 1, 0, 2, - 0, 0, 6, 0, 2, 1, 8, 1, 4, 2, - 0, 0, 7, 0, 4, 1, 1, 2, 8, 2, - 0, 0, 8, 0, 6, 1, 4, 2, 2, 3, - 0, 0, 9, 0, 8, 1, 7, 2, 6, 3, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, - 0, 1, 2, 1, 4, 1, 6, 1, 8, 1, - 5, 1, 8, 1, 1, 2, 4, 2, 7, 2, - 0, 2, 4, 2, 8, 2, 2, 3, 6, 3, - 5, 2, 0, 3, 5, 3, 0, 4, 5, 4, - 0, 3, 6, 3, 2, 4, 8, 4, 4, 5, - 5, 3, 2, 4, 9, 4, 6, 5, 3, 6, - 0, 4, 8, 4, 6, 5, 4, 6, 2, 7, - 5, 4, 4, 5, 3, 6, 2, 7, 1, 8 - }; - -/* Table of stop codes that commit PC before returning to SCP */ - -static t_stat commit_pc[] = { - STOP_HALT, SCPE_STOP, STOP_NOCD, SCPE_EOF, SCPE_IOERR, 0 - }; - -#define BRANCH(x) PCQ_ENTRY; PC = (x) -#define GET_IDXADDR(x) ((idxb? IDX_B: IDX_A) + ((x) * ADDR_LEN) + (ADDR_LEN - 1)) - -t_stat sim_instr (void) -{ -uint32 PC, pla, qla, f0, f1; -int32 i, t, idx, flags, sta, dev, op; -t_stat reason; - -/* Restore saved state */ - -PC = saved_PC; -if ((cpu_unit.flags & IF_IA) == 0) - iae = 0; -if ((cpu_unit.flags & IF_IDX) == 0) - idxe = idxb = 0; -upd_ind (); /* update indicators */ -reason = SCPE_OK; - -/* Main instruction fetch/decode loop */ - -while (reason == SCPE_OK) { /* loop until halted */ - - saved_PC = PC; /* commit prev instr */ - if (sim_interval <= 0) { /* check clock queue */ - if ((reason = sim_process_event ())) - break; - } - if (cpuio_inp != 0) { /* IO in progress? */ - sim_interval = sim_interval - 1; /* tick & continue */ - continue; - } - - if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; - } - - sim_interval = sim_interval - 1; - -/* Instruction fetch and address decode */ - - if (PC & 1) { /* PC odd? */ - reason = STOP_INVIAD; /* stop */ - break; - } - - op = get_2d (PC); /* get opcode */ - if (op < 0) { /* invalid? */ - reason = STOP_INVINS; - break; - } - flags = op_table[op]; /* get op, flags */ - if ((flags & ALLOPT) && /* need option? */ - !(flags & ALLOPT & cpu_unit.flags)) { /* any set? */ - reason = STOP_INVINS; /* no, error */ - break; - } - - pla = ADDR_A (PC, I_PL); /* P last addr */ - qla = ADDR_A (PC, I_QL); /* Q last addr */ - if (flags & IF_VPA) { /* need P? */ - reason = get_addr (pla, 5, TRUE, &PAR); /* get P addr */ - if (reason != SCPE_OK) /* stop if error */ - break; - } - if (flags & (IF_VQA | IF_4QA | IF_NQX)) { /* need Q? */ - reason = get_addr (qla, /* get Q addr */ - ((flags & IF_4QA)? 4: 5), /* 4 or 5 digits */ - ((flags & IF_NQX)? FALSE: TRUE), /* not or indexed */ - &QAR); - if (reason != SCPE_OK) { /* stop if invalid */ - reason = reason + (STOP_INVQDG - STOP_INVPDG); - break; - } - } - else if (flags & IF_IMM) /* immediate? */ - QAR = qla; - - if (hst_lnt) { /* history enabled? */ - hst_p = (hst_p + 1); /* next entry */ - if (hst_p >= hst_lnt) - hst_p = 0; - hst[hst_p].vld = 1; - hst[hst_p].pc = PC; - for (i = 0; i < INST_LEN; i++) - hst[hst_p].inst[i] = M[(PC + i) % MEMSIZE]; - } - - PC = ADDR_A (PC, INST_LEN); /* advance PC */ - switch (op) { /* case on op */ - -/* Transmit digit - P,Q are valid */ - - case OP_TD: - case OP_TDM: - M[PAR] = M[QAR] & (FLAG | DIGIT); /* move dig, flag */ - break; - -/* Transmit field - P,Q are valid */ - - case OP_TF: - case OP_TFM: - reason = xmt_field (PAR, QAR, 1); /* xmit field */ - break; - -/* Transmit floating - P,Q are valid */ - - case OP_TFL: - reason = xmt_field (PAR, QAR, 3); /* xmit field */ - break; - -/* Transmit record - P,Q are valid */ - - case OP_TR: - reason = xmt_record (PAR, QAR, TRUE); /* xmit record */ - break; - -/* Transmit record no record mark - P,Q are valid */ - - case OP_TRNM: - reason = xmt_record (PAR, QAR, FALSE); /* xmit record but */ - break; /* not rec mark */ - -/* Set flag - P is valid */ - - case OP_SF: - M[PAR] = M[PAR] | FLAG; /* set flag on P */ - break; - -/* Clear flag - P is valid */ - - case OP_CF: - M[PAR] = M[PAR] & ~FLAG; /* clear flag on P */ - break; - -/* Branch - P is valid */ - - case OP_B: - BRANCH (PAR); /* branch to P */ - break; - -/* Branch and transmit - P,Q are valid */ - - case OP_BT: - case OP_BTM: - reason = xmt_field (ADDR_S (PAR, 1), QAR, 1); /* xmit field to P-1 */ - IR2 = PC; /* save PC */ - BRANCH (PAR); /* branch to P */ - break; - -/* Branch and transmit floating - P,Q are valid */ - - case OP_BTFL: - reason = xmt_field (ADDR_S (PAR, 1), QAR, 3); /* skip 3 flags */ - IR2 = PC; /* save PC */ - BRANCH (PAR); /* branch to P */ - break; - -/* Branch and transmit address - P,Q are valid */ - - case OP_BTA: - case OP_BTAM: - reason = xmt_field (ADDR_S (PAR, 1), QAR, 4); /* skip 4 flags */ - IR2 = PC; /* save PC */ - BRANCH (PAR); /* branch to P */ - break; - -/* Branch back */ - - case OP_BB: - if (PR1 != 1) { /* PR1 valid? */ - BRANCH (PR1); /* return to PR1 */ - PR1 = 1; /* invalidate */ - } - else if (IR2 != 1) { /* IR2 valid? */ - BRANCH (IR2); /* return to IR2 */ - IR2 = 1; /* invalidate */ - } - else reason = STOP_INVRTN; /* MAR check */ - break; - -/* Branch on digit (not zero) - P,Q are valid */ - - case OP_BD: - if ((M[QAR] & DIGIT) != 0) { /* digit != 0? */ - BRANCH (PAR); /* branch */ - } - break; - -/* Branch no flag - P,Q are valid */ - - case OP_BNF: - if ((M[QAR] & FLAG) == 0) { /* flag == 0? */ - BRANCH (PAR); /* branch */ - } - break; - -/* Branch no record mark (8-2 not set) - P,Q are valid */ - - case OP_BNR: - if ((M[QAR] & REC_MARK) != REC_MARK) { /* not rec mark? */ - BRANCH (PAR); /* branch */ - } - break; - -/* Branch no group mark - P,Q are valid */ - - case OP_BNG: - if ((M[QAR] & DIGIT) != GRP_MARK) { /* not grp mark? */ - BRANCH (PAR); /* branch */ - } - break; - -/* Branch (no) indicator - P is valid */ - - case OP_BI: - case OP_BNI: - upd_ind (); /* update indicators */ - t = get_2d (ADDR_A (saved_PC, I_BR)); /* get ind number */ - if (t < 0) { /* not valid? */ - reason = STOP_INVIND; /* stop */ - break; - } - if ((ind[t] != 0) ^ (op == OP_BNI)) { /* ind value correct? */ - BRANCH (PAR); /* branch */ - } - if (ind_table[t] > 0) /* reset if needed */ - ind[t] = 0; - break; - -/* Add/subtract/compare - P,Q are valid */ - - case OP_A: - case OP_AM: - reason = add_field (PAR, QAR, FALSE, 0, &sta); /* add */ - if (sta == ADD_CARRY) /* cout => ovflo */ - ind[IN_OVF] = 1; - if (ar_stop && ind[IN_OVF]) - reason = STOP_OVERFL; - break; - - case OP_S: - case OP_SM: - reason = add_field (PAR, QAR, TRUE, 0, &sta); /* sub, store */ - if (sta == ADD_CARRY) /* cout => ovflo */ - ind[IN_OVF] = 1; - if (ar_stop && ind[IN_OVF]) - reason = STOP_OVERFL; - break; - -/* IBM's diagnostics try a compare that generates a carry out; it does not - generate overflow. Therefore, do not set overflow on a carry out status. */ - - case OP_C: - case OP_CM: - reason = cmp_field (PAR, QAR); /* compare */ - if (ar_stop && ind[IN_OVF]) - reason = STOP_OVERFL; - break; - -/* Multiply - P,Q are valid */ - - case OP_M: - case OP_MM: - reason = mul_field (PAR, QAR); /* multiply */ - break; - -/* IO instructions - P is valid, except for K */ - - case OP_RA: - case OP_WA: - if ((PAR & 1) == 0) { /* P even? */ - reason = STOP_INVEAD; /* stop */ - break; - } - case OP_DN: - case OP_RN: - case OP_WN: - dev = get_2d (ADDR_A (saved_PC, I_IO)); /* get IO dev */ - f0 = M[ADDR_A (saved_PC, I_CTL)] & DIGIT; /* get function */ - f1 = M[ADDR_A (saved_PC, I_CTL + 1)] & DIGIT; - if ((dev < 0) || (iodisp[dev] == NULL)) /* undefined dev? */ - reason = STOP_INVIO; /* stop */ - else reason = iodisp[dev] (op, PAR, f0, f1); /* call device */ - break; - - case OP_K: - dev = get_2d (ADDR_A (saved_PC, I_IO)); /* get IO dev */ - if (dev < 0) /* invalid digits? */ - return STOP_INVDIG; - if (k_valid_p[dev]) { /* validate P? */ - reason = get_addr (pla, 5, TRUE, &PAR); /* get P addr */ - if (reason != SCPE_OK) /* stop if error */ - break; - } - else PAR = 0; - f0 = M[ADDR_A (saved_PC, I_CTL)] & DIGIT; /* get function */ - f1 = M[ADDR_A (saved_PC, I_CTL + 1)] & DIGIT; - if (iodisp[dev] == NULL) /* undefined dev? */ - reason = STOP_INVIO; /* stop */ - else reason = iodisp[dev] (op, PAR, f0, f1); /* call device */ - break; - -/* Divide special feature instructions */ - - case OP_LD: - case OP_LDM: - for (i = 0; i < PROD_AREA_LEN; i++) /* clear prod area */ - M[PROD_AREA + i] = 0; - t = M[QAR] & FLAG; /* save Q sign */ - reason = xmt_divd (PAR, QAR); /* xmit dividend */ - M[PROD_AREA + PROD_AREA_LEN - 1] |= t; /* set sign */ - break; - -/* Divide - P,Q are valid */ - - case OP_D: - case OP_DM: - reason = div_field (PAR, QAR, &t); /* divide */ - ind[IN_EZ] = t; /* set indicator */ - if ((reason == STOP_OVERFL) && !ar_stop) /* ovflo stop? */ - reason = SCPE_OK; /* no */ - break; - -/* Edit special feature instructions */ - -/* Move flag - P,Q are valid */ - - case OP_MF: - M[PAR] = (M[PAR] & ~FLAG) | (M[QAR] & FLAG); /* copy Q flag */ - M[QAR] = M[QAR] & ~FLAG; /* clr Q flag */ - break; - -/* Transmit numeric strip - P,Q are valid, P is source */ - - case OP_TNS: - if ((PAR & 1) == 0) { /* P must be odd */ - reason = STOP_INVEAD; - break; - } - reason = xmt_tns (QAR, PAR); /* xmit and strip */ - break; - -/* Transmit numeric fill - P,Q are valid */ - - case OP_TNF: - if ((PAR & 1) == 0) { /* P must be odd */ - reason = STOP_INVEAD; - break; - } - reason = xmt_tnf (PAR, QAR); /* xmit and strip */ - break; - -/* Index special feature instructions */ - -/* Move address - P,Q are valid */ - - case OP_MA: - for (i = 0; i < ADDR_LEN; i++) { /* move 5 digits */ - M[PAR] = (M[PAR] & FLAG) | (M[QAR] & DIGIT); - MM (PAR); MM (QAR); - } - break; - -/* Branch load index - P,Q are valid, Q not indexed */ - - case OP_BLX: - case OP_BLXM: - idx = get_idx (ADDR_A (saved_PC, I_QL - 1)); /* get index */ - if (idx < 0) { /* disabled? */ - reason = STOP_INVIDX; /* stop */ - break; - } - xmt_index (GET_IDXADDR (idx), QAR); /* copy Q to idx */ - BRANCH (PAR); /* branch to P */ - break; - -/* Branch store index - P,Q are valid, Q not indexed */ - - case OP_BSX: - idx = get_idx (ADDR_A (saved_PC, I_QL - 1)); /* get index */ - if (idx < 0) { /* disabled? */ - reason = STOP_INVIDX; /* stop */ - break; - } - xmt_index (QAR, GET_IDXADDR (idx)); /* copy idx to Q */ - BRANCH (PAR); /* branch to P */ - break; - -/* Branch and modify index - P,Q are valid, Q not indexed */ - - case OP_BX: - idx = get_idx (ADDR_A (saved_PC, I_QL - 1)); /* get index */ - if (idx < 0) { /* disabled? */ - reason = STOP_INVIDX; /* stop */ - break; - } - reason = add_field (GET_IDXADDR (idx), QAR, FALSE, 0, &sta); - if (ar_stop && ind[IN_OVF]) - reason = STOP_OVERFL; - BRANCH (PAR); /* branch to P */ - break; - - case OP_BXM: - idx = get_idx (ADDR_A (saved_PC, I_QL - 1)); /* get index */ - if (idx < 0) { /* disabled? */ - reason = STOP_INVIDX; /* stop */ - break; - } - reason = add_field (GET_IDXADDR (idx), QAR, FALSE, 3, &sta); - if (ar_stop && ind[IN_OVF]) - reason = STOP_OVERFL; - BRANCH (PAR); /* branch to P */ - break; - -/* Branch conditionally and modify index - P,Q are valid, Q not indexed */ - - case OP_BCX: - idx = get_idx (ADDR_A (saved_PC, I_QL - 1)); /* get index */ - if (idx < 0) { /* disabled? */ - reason = STOP_INVIDX; /* stop */ - break; - } - reason = add_field (GET_IDXADDR (idx), QAR, FALSE, 0, &sta); - if (ar_stop && ind[IN_OVF]) - reason = STOP_OVERFL; - if ((ind[IN_EZ] == 0) && (sta == ADD_NOCRY)) { /* ~z, ~c, ~sign chg? */ - BRANCH (PAR); /* branch */ - } - break; - - case OP_BCXM: - idx = get_idx (ADDR_A (saved_PC, I_QL - 1)); /* get index */ - if (idx < 0) { /* disabled? */ - reason = STOP_INVIDX; /* stop */ - break; - } - reason = add_field (GET_IDXADDR (idx), QAR, FALSE, 3, &sta); - if (ar_stop && ind[IN_OVF]) - reason = STOP_OVERFL; - if ((ind[IN_EZ] == 0) && (sta == ADD_NOCRY)) { /* ~z, ~c, ~sign chg? */ - BRANCH (PAR); /* branch */ - } - break; - -/* Branch and select - P is valid - Model 2 only */ - - case OP_BS: - t = M[ADDR_A (saved_PC, I_SEL)] & DIGIT; /* get select */ - switch (t) { /* case on select */ - case 0: - idxe = idxb = 0; /* indexing off */ - break; - case 1: - if ((cpu_unit.flags & IF_IDX) != 0) { /* indexing present? */ - idxe = 1; idxb = 0; /* index band A */ - } - break; - case 2: - if ((cpu_unit.flags & IF_IDX) != 0) { /* indexing present? */ - idxe = idxb = 1; /* index band B */ - } - break; - case 8: - iae = 0; /* indirect off */ - break; - case 9: - iae = 1; /* indirect on */ - break; - default: - reason = STOP_INVSEL; /* undefined */ - break; - } - BRANCH (PAR); - break; - -/* Binary special feature instructions */ - -/* Branch on bit - P,Q are valid, Q is 4d address */ - - case OP_BBT: - t = M[ADDR_A (saved_PC, I_Q)]; /* get Q0 digit */ - if (t & M[QAR] & DIGIT) { /* match to mem? */ - BRANCH (PAR); /* branch */ - } - break; - -/* Branch on mask - P,Q are valid, Q is 4d address */ - - case OP_BMK: - t = M[ADDR_A (saved_PC, I_Q)]; /* get Q0 digit */ - if (((t ^ M[QAR]) & /* match to mem? */ - ((t & FLAG)? (FLAG + DIGIT): DIGIT)) == 0) { - BRANCH (PAR); /* branch */ - } - break; - -/* Or - P,Q are valid */ - - case OP_ORF: - reason = or_field (PAR, QAR); /* OR fields */ - break; - -/* AND - P,Q are valid */ - - case OP_ANDF: - reason = and_field (PAR, QAR); /* AND fields */ - break; - -/* Exclusive or - P,Q are valid */ - - case OP_EORF: - reason = xor_field (PAR, QAR); /* XOR fields */ - break; - -/* Complement - P,Q are valid */ - - case OP_CPLF: - reason = com_field (PAR, QAR); /* COM field */ - break; - -/* Octal to decimal - P,Q are valid */ - - case OP_OTD: - reason = oct_to_dec (PAR, QAR); /* convert */ - break; - -/* Decimal to octal - P,Q are valid */ - - case OP_DTO: - reason = dec_to_oct (PAR, QAR, &t); /* convert */ - ind[IN_EZ] = t; /* set indicator */ - if (ar_stop && ind[IN_OVF]) - reason = STOP_OVERFL; - break; - -/* Floating point special feature instructions */ - - case OP_FADD: - reason = fp_add (PAR, QAR, FALSE); /* add */ - if (ar_stop && ind[IN_EXPCHK]) - reason = STOP_EXPCHK; - break; - - case OP_FSUB: - reason = fp_add (PAR, QAR, TRUE); /* subtract */ - if (ar_stop && ind[IN_EXPCHK]) - reason = STOP_EXPCHK; - break; - - case OP_FMUL: - reason = fp_mul (PAR, QAR); /* multiply */ - if (ar_stop && ind[IN_EXPCHK]) - reason = STOP_EXPCHK; - break; - - case OP_FDIV: - reason = fp_div (PAR, QAR); /* divide */ - if (ar_stop && ind[IN_OVF]) - reason = STOP_FPDVZ; - if (ar_stop && ind[IN_EXPCHK]) - reason = STOP_EXPCHK; - break; - - case OP_FSL: - reason = fp_fsl (PAR, QAR); /* shift left */ - break; - - case OP_FSR: - reason = fp_fsr (PAR, QAR); /* shift right */ - break; - -/* Halt */ - - case OP_H: - reason = STOP_HALT; /* stop */ - break; - -/* NOP */ - - case OP_NOP: - break; - -/* Invalid instruction code */ - - default: - reason = STOP_INVINS; /* stop */ - break; - } /* end switch */ - } /* end while */ - -/* Simulation halted */ - -for (i = 0; commit_pc[i] != 0; i++) { /* check stop code */ - if (reason == commit_pc[i]) /* on list? */ - saved_PC = PC; /* commit PC */ - } -actual_PC = PC; /* save cur PC for RLS */ -pcq_r->qptr = pcq_p; /* update pc q ptr */ -upd_ind (); -if (cpuio_inp != 0) { /* flag IO in progress */ - char *opstr = opc_lookup (cpuio_opc, cpuio_dev * 100, NULL); - - if (opstr != NULL) - sim_printf ("\r\nIO in progress (%s %05d)", opstr, PAR); - else sim_printf ("\r\nIO in progress (%02d %05d,%05d)", cpuio_opc, PAR, cpuio_dev * 100); - } -return reason; -} - -/* Utility routines */ - -/* Get 2 digit field - - Inputs: - ad = address of high digit - Outputs: - val = field converted to binary - -1 if bad digit -*/ - -int32 get_2d (uint32 ad) -{ -int32 d, d1; - -d = M[ad] & DIGIT; /* get 1st digit */ -d1 = M[ADDR_A (ad, 1)] & DIGIT; /* get 2nd digit */ -if (BAD_DIGIT (d) || BAD_DIGIT (d1)) /* bad? error */ - return -1; -return ((d * 10) + d1); /* cvt to binary */ -} - -/* Get address routine - - Inputs: - alast = address of low digit - lnt = length - indexok = TRUE if indexing allowed - &addr = pointer to address output - Output: - return = error status (in terms of P address) - addr = address converted to binary - - Notes: - - If indexing produces a negative result, the effective address is - the 10's complement of the result - - An address that exceeds memory produces a MAR check stop -*/ - -t_stat get_addr (uint32 alast, int32 lnt, t_bool indexok, uint32 *reta) -{ -uint8 indir; -int32 cnt, idx, idxa, idxv, addr; - -if (iae) /* init indirect */ - indir = FLAG; -else indir = 0; - -cnt = 0; /* count depth */ -do { - indir = indir & M[alast]; /* get indirect */ - if (cvt_addr (alast, lnt, FALSE, &addr)) /* cvt addr to bin */ - return STOP_INVPDG; /* bad? */ - idx = get_idx (ADDR_S (alast, 1)); /* get index reg num */ - if (indexok && (idx > 0)) { /* indexable? */ - idxa = GET_IDXADDR (idx); /* get idx reg addr */ - if (cvt_addr (idxa, ADDR_LEN, TRUE, &idxv)) /* cvt idx reg */ - return STOP_INVPDG; - addr = addr + idxv; /* add in index */ - if (addr < 0) /* -? 10's comp */ - addr = addr + 100000; - } - if (addr >= (int32) MEMSIZE) /* invalid addr? */ - return STOP_INVPAD; - alast = addr; /* new address */ - lnt = ADDR_LEN; /* std len */ - } while (indir && (cnt++ < ind_max)); -if (cnt > ind_max) /* indir too deep? */ - return STOP_INVPIA; -*reta = addr; /* return address */ -return SCPE_OK; -} - -/* Convert address to binary - - Inputs: - alast = address of low digit - lnt = length - signok = TRUE if signed - val = address of output - Outputs: - status = 0 if ok, != 0 if error -*/ - -t_stat cvt_addr (uint32 alast, int32 lnt, t_bool signok, int32 *val) -{ -int32 sign = 0, addr = 0, t; - -if (signok && (M[alast] & FLAG)) /* signed? */ - sign = 1; -alast = alast - lnt; /* find start */ -do { - PP (alast); /* incr mem addr */ - t = M[alast] & DIGIT; /* get digit */ - if (BAD_DIGIT (t)) /* bad? error */ - return STOP_INVDIG; - addr = (addr * 10) + t; /* cvt to bin */ - } while (--lnt > 0); -if (sign) /* minus? */ - *val = -addr; -else *val = addr; -return SCPE_OK; -} - -/* Get index register number - - Inputs: - aidx = address of low digit - Outputs: - index = >0 if indexed - =0 if not indexed - <0 if indexing disabled -*/ - -t_stat get_idx (uint32 aidx) -{ -int32 i, idx; - -if (idxe == 0) /* indexing off? */ - return -1; -for (i = idx = 0; i < 3; i++) { /* 3 flags worth */ - if (M[aidx] & FLAG) /* test flag */ - idx = idx | (1 << i); - MM (aidx); /* next digit */ - } -return idx; -} - -/* Update indicators routine */ - -void upd_ind (void) -{ -ind[IN_HPEZ] = ind[IN_HP] | ind[IN_EZ]; /* HPEZ = HP | EZ */ -ind[IN_DERR] = ind[IN_DACH] | ind[IN_DWLR] | ind[IN_DCYO]; -ind[IN_ANYCHK] = ind[IN_RDCHK] | ind[IN_WRCHK] | /* ANYCHK = all chks */ - ind[IN_MBREVEN] | ind[IN_MBRODD] | - ind[IN_PRCHK] | ind[IN_DACH]; -ind[IN_IXN] = ind[IN_IXA] = ind[IN_IXB] = 0; /* clr index indics */ -if (!idxe) /* off? */ - ind[IN_IXN] = 1; -else if (!idxb) /* on, band A? */ - ind[IN_IXA] = 1; -else ind[IN_IXB] = 1; /* no, band B */ -return; -} - -/* Transmit routines */ - -/* Transmit field from 's' to 'd' - ignore first 'skp' flags */ - -t_stat xmt_field (uint32 d, uint32 s, uint32 skp) -{ -uint32 cnt = 0; -uint8 t; - -do { - t = M[d] = M[s] & (FLAG | DIGIT); /* copy src to dst */ - MM (d); /* decr mem addrs */ - MM (s); - if (cnt++ >= MEMSIZE) /* (stop runaway) */ - return STOP_FWRAP; - } while (((t & FLAG) == 0) || (cnt <= skp)); /* until flag */ -return SCPE_OK; -} - -/* Transmit record from 's' to 'd' - copy record mark if 'cpy' = TRUE */ - -t_stat xmt_record (uint32 d, uint32 s, t_bool cpy) -{ -uint32 cnt = 0; - -while ((M[s] & REC_MARK) != REC_MARK) { /* until rec mark */ - M[d] = M[s] & (FLAG | DIGIT); /* copy src to dst */ - PP (d); /* incr mem addrs */ - PP (s); - if (cnt++ >= MEMSIZE) /* (stop runaway) */ - return STOP_FWRAP; - } -if (cpy) /* copy rec mark */ - M[d] = M[s] & (FLAG | DIGIT); -return SCPE_OK; -} - -/* Transmit index from 's' to 'd' - fixed five character field */ - -t_stat xmt_index (uint32 d, uint32 s) -{ -int32 i; - -M[d] = M[s] & (FLAG | DIGIT); /* preserve sign */ -MM (d); MM (s); /* decr mem addrs */ -for (i = 0; i < ADDR_LEN - 2; i++) { /* copy 3 digits */ - M[d] = M[s] & DIGIT; /* without flags */ - MM (d); /* decr mem addrs */ - MM (s); - } -M[d] = (M[s] & DIGIT) | FLAG; /* set flag on last */ -return SCPE_OK; -} - -/* Transmit dividend from 'd' to 's' - clear flag on first digit */ - -t_stat xmt_divd (uint32 d, uint32 s) -{ -uint32 cnt = 0; - -M[d] = M[s] & DIGIT; /* first w/o flag */ -do { - MM (d); /* decr mem addrs */ - MM (s); - M[d] = M[s] & (FLAG | DIGIT); /* copy src to dst */ - if (cnt++ >= MEMSIZE) /* (stop runaway) */ - return STOP_FWRAP; - } while ((M[d] & FLAG) == 0); /* until src flag */ -return SCPE_OK; -} - -/* Transmit numeric strip from 's' to 'd' - s is odd */ - -t_stat xmt_tns (uint32 d, uint32 s) -{ -uint32 cnt = 0; -uint8 t, z; - -t = M[s] & DIGIT; /* get units */ -z = M[s - 1] & DIGIT; /* get zone */ -if ((z == 1) || (z == 5) || ((z == 2) && (t == 0))) /* 1x, 5x, 20? */ - M[d] = t | FLAG; /* set flag */ -else M[d] = t; /* else clear flag */ -do { - MM (d); /* decr mem addrs */ - s = ADDR_S (s, 2); - t = M[d] & FLAG; /* save dst flag */ - M[d] = M[s] & (FLAG | DIGIT); /* copy src to dst */ - if (cnt >= MEMSIZE) /* (stop runaway) */ - return STOP_FWRAP; - cnt = cnt + 2; - } while (t == 0); /* until dst flag */ -M[d] = M[d] | FLAG; /* set flag at end */ -return SCPE_OK; -} - -/* Transmit numeric fill from 's' to 'd' - d is odd */ - -t_stat xmt_tnf (uint32 d, uint32 s) -{ -uint32 cnt = 0; -uint8 t; - -t = M[s]; /* get 1st digit */ -M[d] = t & DIGIT; /* store */ -M[d - 1] = (t & FLAG)? 5: 7; /* set sign from flag */ -do { - MM (s); /* decr mem addr */ - d = ADDR_S (d, 2); - t = M[s]; /* get src digit */ - M[d] = t & DIGIT; /* move to dst, no flag */ - M[d - 1] = 7; /* set zone */ - if (cnt >= MEMSIZE) /* (stop runaway) */ - return STOP_FWRAP; - cnt = cnt + 2; - } while ((t & FLAG) == 0); /* until src flag */ -return SCPE_OK; -} - -/* Add routine - - Inputs: - d = destination field low (P) - s = source field low (Q) - sub = TRUE if subtracting - sto = TRUE if storing - skp = number of source field flags, beyond sign, to ignore - Output: - return = status - sta = ADD_NOCRY: no carry out, no sign change - ADD_SIGNC: sign change - ADD_CARRY: carry out - - Reference Manual: "When the sum is zero, the sign of the P field - is retained." - - Model 1 hack: If the Q field contains a record mark, it is treated - as 0 (Dave Wise; from schematics). -*/ - -t_stat add_field (uint32 d, uint32 s, t_bool sub, uint32 skp, int32 *sta) -{ -uint32 cry, src, dst, res, comp, dp, dsv; -uint32 src_f = 0, cnt = 0, dst_f = 0; - -*sta = ADD_NOCRY; /* assume no cry */ -dsv = d; /* save dst */ -comp = ((M[d] ^ M[s]) & FLAG) ^ (sub? FLAG: 0); /* set compl flag */ -cry = 0; /* clr carry */ -ind[IN_HP] = ((M[d] & FLAG) == 0); /* set sign from res */ -ind[IN_EZ] = 1; /* assume zero */ - -dst = M[d] & DIGIT; /* 1st digits */ -src = M[s] & DIGIT; -if ((src == REC_MARK) && /* Q record mark? */ - ((cpu_unit.flags & IF_RMOK) != 0)) /* Model I & enabled? */ - src = 0; /* treat as 0 */ -if (BAD_DIGIT (dst) || BAD_DIGIT (src)) /* bad digit? */ - return STOP_INVDIG; -if (comp) /* complement? */ - src = 10 - src; -res = add_one_digit (dst, src, &cry); /* add */ -M[d] = (M[d] & FLAG) | res; /* store */ -MM (d); MM (s); /* decr mem addrs */ -do { - dst = M[d] & DIGIT; /* get dst digit */ - dst_f = M[d] & FLAG; /* get dst flag */ - if (src_f) /* src done? src = 0 */ - src = 0; - else { - src = M[s] & DIGIT; /* get src digit */ - if (cnt >= skp) /* get src flag */ - src_f = M[s] & FLAG; - MM (s); /* decr src addr */ - if ((src == REC_MARK) && /* Q record mark? */ - ((cpu_unit.flags & IF_RMOK) != 0)) /* Model I & enabled? */ - src = 0; /* treat as 0 */ - } - if (BAD_DIGIT (dst) || BAD_DIGIT (src)) /* bad digit? */ - return STOP_INVDIG; - if (comp) /* complement? */ - src = 9 - src; - res = add_one_digit (dst, src, &cry); /* add */ - M[d] = dst_f | res; /* store */ - MM (d); /* decr dst addr */ - if (cnt++ >= MEMSIZE) /* (stop runaway) */ - return STOP_FWRAP; - } while (dst_f == 0); /* until dst done */ -if (!src_f) /* !src done? ovf */ - ind[IN_OVF] = 1; - -/* Because recomplement is done (model 1) with table lookup, the first digit - must be explicitly 10s complemented, and not 9s complemented with a carry - in of 1. (Bob Armstrong) */ - -if (comp && !cry && !ind[IN_EZ]) { /* recomp needed? */ - ind[IN_HP] = ind[IN_HP] ^ 1; /* flip indicator */ - for (cry = 0, dp = dsv; dp != d; ) { /* rescan */ - dst = M[dp] & DIGIT; /* get dst digit */ - dst = (dp == dsv)? (10 - dst): (9 - dst); /* 10 or 9s comp */ - res = add_one_digit (0, dst, &cry); /* "add" */ - M[dp] = (M[dp] & FLAG) | res; /* store */ - MM (dp); /* decr dst addr */ - } - M[dsv] = M[dsv] ^ FLAG; /* compl sign */ - *sta = ADD_SIGNC; /* sign changed */ - return SCPE_OK; - } /* end if recomp */ -if (ind[IN_EZ]) /* res = 0? clr HP */ - ind[IN_HP] = 0; -if (!comp && cry) /* set status */ - *sta = ADD_CARRY; -return SCPE_OK; -} - -/* Compare routine - - Inputs: - d = destination field low (P) - s = source field low (Q) - Output: - return = status - - In the unlike signs case, the compare is abandoned as soon as a non-zero - digit is seen; zeroes go through the normal flows. - - See add for Model I hack in handling Q field record marks. -*/ - -t_stat cmp_field (uint32 d, uint32 s) -{ -uint32 cry, src, dst, unlike, dsv; -uint32 src_f = 0, cnt = 0, dst_f = 0; - -dsv = d; /* save dst */ -cry = 0; /* clr carry */ -unlike = (M[d] ^ M[s]) & FLAG; /* set unlike signs flag */ -ind[IN_HP] = ((M[d] & FLAG) == 0); /* set sign from res */ -ind[IN_EZ] = 1; /* assume zero */ - -do { - dst = M[d] & DIGIT; /* get dst digit */ - if (d != dsv) /* if not first digit, */ - dst_f = M[d] & FLAG; /* get dst flag */ - if (src_f) /* src done? src = 0 */ - src = 0; - else { - src = M[s] & DIGIT; /* get src digit */ - if (d != dsv) /* if not first digit, */ - src_f = M[s] & FLAG; /* get src flag */ - MM (s); /* decr src addr */ - } - if (unlike && ((dst | src) != 0)) { /* unlike signs, digit? */ - ind[IN_EZ] = 0; /* not equal */ - return SCPE_OK; - } - if ((src == REC_MARK) && /* Q record mark? */ - ((cpu_unit.flags & IF_RMOK) != 0)) /* Model I & enabled? */ - src = 0; /* treat as 0 */ - if (BAD_DIGIT (dst) || BAD_DIGIT (src)) /* bad digit? */ - return STOP_INVDIG; - src = (d != dsv)? 9 - src: 10 - src; /* complement */ - add_one_digit (dst, src, &cry); /* throw away result */ - MM (d); /* decr dst addr */ - if (cnt++ >= MEMSIZE) /* (stop runaway) */ - return STOP_FWRAP; - } while (dst_f == 0); /* until dst done */ -if (!src_f) /* !src done? ovf */ - ind[IN_OVF] = 1; - -/* At this point, we have three possible cases: - - Fields are equal, signs irrelevant: ind[IN_EZ] is still set - - Fields are unequal, signs are the same, carry out: - |p| > |q|, ind[IN_HP] is correct - - Fields are unequal, signs are the same, no carry out: - |p| < |q, ind[IN_HP] must be inverted -*/ - -if (!cry && !ind[IN_EZ]) { /* recomp needed? */ - ind[IN_HP] = ind[IN_HP] ^ 1; /* flip indicator */ - return SCPE_OK; - } /* end if recomp */ -if (ind[IN_EZ]) /* res = 0? clr HP */ - ind[IN_HP] = 0; -return SCPE_OK; -} - -/* Add one digit via table (Model 1) or "hardware" (Model 2) */ - -uint32 add_one_digit (uint32 dst, uint32 src, uint32 *cry) -{ -uint32 res; - -if (*cry) /* cry in? incr src */ - src = src + 1; -if (src >= 10) { /* src > 10? */ - src = src - 10; /* src -= 10 */ - *cry = 1; /* carry out */ - } -else *cry = 0; /* else no carry */ -if (cpu_unit.flags & IF_MII) /* Model 2? */ - res = sum_table[dst + src]; /* "hardware" */ -else res = M[ADD_TABLE + (dst * 10) + src]; /* table lookup */ -if (res & FLAG) /* carry out? */ - *cry = 1; -if (res & DIGIT) /* nz? clr ind */ - ind[IN_EZ] = 0; -return res & DIGIT; -} - -/* Multiply routine - - Inputs: - mpc = multiplicand address - mpy = multiplier address - Outputs: - return = status - - Reference manual: "A zero product may have a negative or positive sign, - depending on the signs of the fields at the P and Q addresses." -*/ - -t_stat mul_field (uint32 mpc, uint32 mpy) -{ -int32 i; -uint32 pro; /* prod pointer */ -uint32 mpyd, mpyf; /* mpy digit, flag */ -uint32 cnt = 0; /* counter */ -uint8 sign; /* final sign */ -t_stat r; - -PR1 = 1; /* step on PR1 */ -for (i = 0; i < PROD_AREA_LEN; i++) /* clr prod area */ - M[PROD_AREA + i] = 0; -sign = (M[mpc] & FLAG) ^ (M[mpy] & FLAG); /* get final sign */ -ind[IN_HP] = (sign == 0); /* set indicators */ -ind[IN_EZ] = 1; -pro = PROD_AREA + PROD_AREA_LEN - 1; /* product ptr */ - -/* Loop on multiplier (mpy) and product (pro) digits */ - -do { - mpyd = M[mpy] & DIGIT; /* multiplier digit */ - mpyf = (M[mpy] & FLAG) && (cnt != 0); /* last digit flag */ - if (BAD_DIGIT (mpyd)) /* bad? */ - return STOP_INVDIG; - r = mul_one_digit (mpyd, mpc, pro, mpyf); /* prod += mpc*mpy_dig */ - if (r != SCPE_OK) /* error? */ - return r; - MM (mpy); /* decr mpyr, prod addrs */ - MM (pro); - if (cnt++ >= MEMSIZE) /* (stop runaway) */ - return STOP_FWRAP; - } while ((mpyf == 0) || (cnt <= 1)); /* until mpyr flag */ - -if (ind[IN_EZ]) /* res = 0? clr HP */ - ind[IN_HP] = 0; -M[PROD_AREA + PROD_AREA_LEN - 1] |= sign; /* set final sign */ -return SCPE_OK; -} - -/* Multiply step - - Inputs: - mpyd = multiplier digit (tested valid) - mpcp = multiplicand low address - prop = product low address - last = last iteration flag (set flag on high product) - Outputs: - prod += multiplicand * multiplier_digit - return = status - - The multiply table address is constructed as follows: - - double the multiplier digit - - use the 10's digit of the doubled result, + 1, as the 100's digit - of the table address - - use the multiplicand digit as the 10's digit of the table address - - use the unit digit of the doubled result as the unit digit of the - table address - EZ indicator is cleared if a non-zero digit is ever generated -*/ - -t_stat mul_one_digit (uint32 mpyd, uint32 mpcp, uint32 prop, uint32 last) -{ -uint32 mpta, mptb; /* mult table */ -uint32 mptd; /* mult table digit */ -uint32 mpcd, mpcf; /* mpc digit, flag */ -uint32 prwp; /* prod working ptr */ -uint32 prod; /* product digit */ -uint32 cry; /* carry */ -uint32 mpcc, cryc; /* counters */ - -mptb = MUL_TABLE + ((mpyd <= 4)? (mpyd * 2): /* set mpy table 100's, */ - (((mpyd - 5) * 2) + 100)); /* 1's digits */ - -/* Inner loop on multiplicand (mpcp) and product (prop) digits */ - -mpcc = 0; /* multiplicand ctr */ -do { - prwp = prop; /* product working ptr */ - mpcd = M[mpcp] & DIGIT; /* multiplicand digit */ - mpcf = M[mpcp] & FLAG; /* multiplicand flag */ - if (BAD_DIGIT (mpcd)) /* bad? */ - return STOP_INVDIG; - mpta = mptb + (mpcd * 10); /* mpy table 10's digit */ - cry = 0; /* init carry */ - mptd = M[mpta] & DIGIT; /* mpy table digit */ - if (BAD_DIGIT (mptd)) /* bad? */ - return STOP_INVDIG; - prod = M[prwp] & DIGIT; /* product digit */ - if (BAD_DIGIT (prod)) /* bad? */ - return STOP_INVDIG; - M[prwp] = add_one_digit (prod, mptd, &cry); /* add mpy tbl to prod */ - MM (prwp); /* decr working ptr */ - mptd = M[mpta + 1] & DIGIT; /* mpy table digit */ - if (BAD_DIGIT (mptd)) /* bad? */ - return STOP_INVDIG; - prod = M[prwp] & DIGIT; /* product digit */ - if (BAD_DIGIT (prod)) /* bad? */ - return STOP_INVDIG; - M[prwp] = add_one_digit (prod, mptd, &cry); /* add mpy tbl to prod */ - cryc = 0; /* (stop runaway) */ - while (cry) { /* propagate carry */ - MM (prwp); /* decr working ptr */ - prod = M[prwp] & DIGIT; /* product digit */ - if (BAD_DIGIT (prod)) /* bad? */ - return STOP_INVDIG; - M[prwp] = add_one_digit (prod, 0, &cry); /* add cry */ - if (cryc++ > MEMSIZE) - return STOP_FWRAP; - } - MM (mpcp); /* decr mpc, prod ptrs */ - MM (prop); - if (mpcc++ > MEMSIZE) - return STOP_FWRAP; - } while ((mpcf == 0) || (mpcc <= 1)); /* until mpcf flag */ -if (last) /* flag high product */ - M[prop] = M[prop] | FLAG; -return SCPE_OK; -} - -/* Divide routine - comments from Geoff Kuenning's 1620 simulator - - The destination of the divide is given by: - - 100 - <# digits in quotient> - - Which is more easily calculated as: - - 100 - <# digits in divisor> - <# digits in dividend> - - The quotient goes into 99 minus the divisor length. The - remainder goes into 99. The load dividend instruction (above) - should have specified a P address of 99 minus the size of the - divisor. - - Note that this all implies that "dest" points to the *leftmost* - digit of the dividend. - - After the division, the assumed decimal point will be as many - positions to the left as there are digits in the divisor. In - other words, a 4-digit divisor will produce 4 (assumed) decimal - places. - - There are other ways to do these things. In particular, the - load-dividend instruction doesn't have to specify the above - formula; if it's done differently, then you don't have to get - decimal places. This is not well-explained in the books I have. - - How to divide on a 1620: - - The dividend is the field at 99: - - 90 = _1234567890 - - The divisor is somewhere else in memory: - - _03 - - The divide operation specifies the left-most digit of the - dividend as the place to begin trial subtractions: - - DM 90,3 - - The loop works as follows: - - 1. Call the left-most digit of the dividend "current_dividend". - Call the location current_dividend - - "quotient_digit". - 2. Clear the flag at current_dividend, and set one at - quotient_digit. - - 88 = _001234567890, q_d = 88, c_d = 90 - [Not actually done; divisor length controls subtract.] - 3. Subtract the divisor from the field at current-dividend, - using normal 1620 rules, except that signs are ignored. - Continue these subtractions until either 10 subtractions - have been done, or you get a negative result: - - 88 = _00_2234567890, q_d = 88, c_d = 90 - 4. If 10 subtractions have been done, set the overflow - indicator and abort. Otherwise, add the divisor back to - correct for the oversubtraction: - - 88 = _001234567890, q_d = 88, c_d = 90 - 5. Store the (net) number of subtractions in quotient_digit: - - 88 = _001234567890, q_d = 88, c_d = 90 - 6. If this is not the first pass, clear the flag at - quotient_digit. Increment quotient_digit and - current_dividend, and set a flag at the new - quotient_digit: - - 88 = _0_01234567890, q_d = 89, c_d = 91 - [If first pass, set a flag at quotient digit.] - 7. If current_dividend is not 100, repeat steps 3 through 7. - 8. Set flags at 99 and quotient_digit - 1 according to the - rules of algebra: the quotient's sign is the exclusive-or - of the signs of the divisor and dividend, and the - remainder has the sign of the dividend: - - 10 / 3 = 3 remainder 1 - 10 / -3 = -3 remainder 1 - -10 / 3 = -3 remainder -1 - -10 / -3 = 3 remainder -1 - - This preserves the relationship dd = q * dv + r. - - Our example continues as follows for steps 3 through 7: - - 3. 88 = _0_00_334567890, q_d = 89, c_d = 91 - 4. 88 = _0_00034567890 - 5. 88 = _0_40034567890 - 6. 88 = _04_0034567890, q_d = 90, c_d = 92 - 3. 88 = _04_00_34567890 - 4. 88 = _04_0004567890 - 5. 88 = _04_1004567890 - 6. 88 = _041_004567890, q_d = 91, c_d = 93 - 3. 88 = _041_00_2567890 - 4. 88 = _041_001567890 - 5. 88 = _041_101567890 - 6. 88 = _0411_01567890, q_d = 92, c_d = 94 - 3. 88 = _0411_00_367890 - 4. 88 = _0411_00067890 - 5. 88 = _0411_50067890 - 6. 88 = _04115_0067890, q_d = 93, c_d = 95 - 3. 88 = _04115_00_37890 - 4. 88 = _04115_0007890 - 5. 88 = _04115_2007890 - 6. 88 = _041152_007890, q_d = 94, c_d = 96 - 3. 88 = _041152_00_2890 - 4. 88 = _041152_001890 - 5. 88 = _041152_201890 - 6. 88 = _0411522_01890, q_d = 95, c_d = 97 - 3. 88 = _0411522_00_390 - 4. 88 = _0411522_00090 - 5. 88 = _0411522_60090 - 6. 88 = _04115226_0090, q_d = 96, c_d = 98 - 3. 88 = _04115226_00_30 - 4. 88 = _04115226_0000 - 5. 88 = _04115226_3000 - 6. 88 = _041152263_000, q_d = 97, c_d = 99 - 3. 88 = _041152263_00_3 - 4. 88 = _041152263_000 - 5. 88 = _041152263_000 - 6. 88 = _0411522630_00, q_d = 98, c_d = 100 - - In the actual code below, we elide several of these steps in - various ways for convenience and efficiency. - - Note that the EZ indicator is NOT valid for divide, because it - is cleared by any non-zero result in an intermediate add. The - code maintains its own EZ indicator for the quotient. -*/ - -t_stat div_field (uint32 dvd, uint32 dvr, int32 *ez) -{ -uint32 quop, quod, quos; /* quo ptr, dig, sign */ -uint32 dvds; /* dvd sign */ -t_bool first = TRUE; /* first pass */ -t_stat r; - -dvds = (M[PROD_AREA + PROD_AREA_LEN - 1]) & FLAG; /* dividend sign */ -quos = dvds ^ (M[dvr] & FLAG); /* quotient sign */ -ind[IN_HP] = (quos == 0); /* set indicators */ -*ez = 1; - -/* Loop on current dividend, high order digit at dvd */ - -do { - r = div_one_digit (dvd, dvr, 10, &quod, &quop); /* dev quo digit */ - if (r != SCPE_OK) /* error? */ - return r; - -/* Store quotient digit and advance current dividend pointer */ - - if (first) { /* first pass? */ - if (quod >= 10) { /* overflow? */ - ind[IN_OVF] = 1; /* set indicator */ - return STOP_OVERFL; /* stop */ - } - M[quop] = FLAG | quod; /* set flag on quo */ - first = FALSE; - } - else M[quop] = quod; /* store quo digit */ - if (quod) /* if nz, clr ind */ - *ez = 0; - PP (dvd); /* incr dvd ptr */ - } while (dvd != (PROD_AREA + PROD_AREA_LEN)); /* until end prod */ - -/* Division done. Set signs of quo, rem, set flag on high order remainder */ - -if (*ez) /* res = 0? clr HP */ - ind[IN_HP] = 0; -M[PROD_AREA + PROD_AREA_LEN - 1] |= dvds; /* remainder sign */ -M[quop] = M[quop] | quos; /* quotient sign */ -PP (quop); /* high remainder */ -M[quop] = M[quop] | FLAG; /* set flag */ -return SCPE_OK; -} - -/* Divide step - - Inputs: - dvd = current dividend address (high digit) - dvr = divisor address (low digit) - max = max number of iterations before overflow - &quod = address to store quotient digit - &quop = address to store quotient pointer (can be NULL) - Outputs: - return = status - - Divide step calculates a quotient digit by repeatedly subtracting the - divisor from the current dividend. The divisor's length controls the - subtraction; dividend flags are ignored. -*/ - -t_stat div_one_digit (uint32 dvd, uint32 dvr, uint32 max, - uint32 *quod, uint32 *quop) -{ -uint32 dvrp, dvrd, dvrf; /* dvr ptr, dig, flag */ -uint32 dvdp, dvdd; /* dvd ptr, dig */ -uint32 qd, cry; /* quo dig, carry */ -uint32 cnt; - -for (qd = 0; qd < max; qd++) { /* devel quo dig */ - dvrp = dvr; /* divisor ptr */ - dvdp = dvd; /* dividend ptr */ - cnt = 0; - cry = 1; /* carry in = 1 */ - do { /* sub dvr fm dvd */ - dvdd = M[dvdp] & DIGIT; /* dividend digit */ - if (BAD_DIGIT (dvdd)) /* bad? */ - return STOP_INVDIG; - dvrd = M[dvrp] & DIGIT; /* divisor digit */ - dvrf = M[dvrp] & FLAG; /* divisor flag */ - if (BAD_DIGIT (dvrd)) /* bad? */ - return STOP_INVDIG; - M[dvdp] = add_one_digit (dvdd, 9 - dvrd, &cry); /* sub */ - MM (dvdp); /* decr ptrs */ - MM (dvrp); - if (cnt++ >= MEMSIZE) /* (stop runaway) */ - return STOP_FWRAP; - } while ((dvrf == 0) || (cnt <= 1)); /* until dvr flag */ - if (!cry) { /* !cry = borrow */ - dvdd = M[dvdp] & DIGIT; /* borrow digit */ - if (BAD_DIGIT (dvdd)) /* bad? */ - return STOP_INVDIG; - M[dvdp] = add_one_digit (dvdd, 9, &cry); /* sub */ - } - if (!cry) /* !cry = negative */ - break; - } - -/* Add back the divisor to correct for the negative result */ - -dvrp = dvr; /* divisor ptr */ -dvdp = dvd; /* dividend ptr */ -cnt = 0; -cry = 0; /* carry in = 0 */ -do { - dvdd = M[dvdp] & DIGIT; /* dividend digit */ - dvrd = M[dvrp] & DIGIT; /* divisor digit */ - dvrf = M[dvrp] & FLAG; /* divisor flag */ - M[dvdp] = add_one_digit (dvdd, dvrd, &cry); /* add */ - MM (dvdp); /* decr ptrs */ - MM (dvrp); - cnt++; - } while ((dvrf == 0) || (cnt <= 1)); /* until dvr flag */ -if (cry) { /* carry out? */ - dvdd = M[dvdp] & DIGIT; /* borrow digit */ - M[dvdp] = add_one_digit (dvdd, 0, &cry); /* add */ - } -if (quop != NULL) /* set quo addr */ - *quop = dvdp; -*quod = qd; /* set quo digit */ -return SCPE_OK; -} - -/* Logical operation routines (and, or, xor, complement) - - Inputs: - d = destination address - s = source address - Output: - return = status - - Destination flags are preserved; EZ reflects the result. - COM does not obey normal field length restrictions. -*/ - -t_stat or_field (uint32 d, uint32 s) -{ -uint32 cnt = 0; -int32 t; - -ind[IN_EZ] = 1; /* assume result zero */ -do { - t = M[s]; /* get src */ - M[d] = (M[d] & FLAG) | ((M[d] | t) & 07); /* OR src to dst */ - if (M[d] & DIGIT) /* nz dig? clr ind */ - ind[IN_EZ] = 0; - MM (d); /* decr pointers */ - MM (s); - if (cnt++ >= MEMSIZE) /* (stop runaway) */ - return STOP_FWRAP; - } while (((t & FLAG) == 0) || (cnt <= 1)); /* until src flag */ -return SCPE_OK; -} - -t_stat and_field (uint32 d, uint32 s) -{ -uint32 cnt = 0; -int32 t; - -ind[IN_EZ] = 1; /* assume result zero */ -do { - t = M[s]; /* get src */ - M[d] = (M[d] & FLAG) | ((M[d] & t) & 07); /* AND src to dst */ - if (M[d] & DIGIT) /* nz dig? clr ind */ - ind[IN_EZ] = 0; - MM (d); /* decr pointers */ - MM (s); - if (cnt++ >= MEMSIZE) /* (stop runaway) */ - return STOP_FWRAP; - } while (((t & FLAG) == 0) || (cnt <= 1)); /* until src flag */ -return SCPE_OK; -} - -t_stat xor_field (uint32 d, uint32 s) -{ -uint32 cnt = 0; -int32 t; - -ind[IN_EZ] = 1; /* assume result zero */ -do { - t = M[s]; /* get src */ - M[d] = (M[d] & FLAG) | ((M[d] ^ t) & 07); /* XOR src to dst */ - if (M[d] & DIGIT) /* nz dig? clr ind */ - ind[IN_EZ] = 0; - MM (d); /* decr pointers */ - MM (s); - if (cnt++ >= MEMSIZE) /* (stop runaway) */ - return STOP_FWRAP; - } while (((t & FLAG) == 0) || (cnt <= 1)); /* until src flag */ -return SCPE_OK; -} - -t_stat com_field (uint32 d, uint32 s) -{ -uint32 cnt = 0; -int32 t; - -ind[IN_EZ] = 1; /* assume result zero */ -do { - t = M[s]; /* get src */ - M[d] = (t & FLAG) | ((t ^ 07) & 07); /* comp src to dst */ - if (M[d] & DIGIT) /* nz dig? clr ind */ - ind[IN_EZ] = 0; - MM (d); /* decr pointers */ - MM (s); - if (cnt++ >= MEMSIZE) /* (stop runaway) */ - return STOP_FWRAP; - } while ((t & FLAG) == 0); /* until src flag */ -return SCPE_OK; -} - -/* Octal to decimal - - Inputs: - tbl = conversion table address (low digit) - s = source address - Outputs: - product area = converted source - result = status - - OTD is a cousin of multiply. The octal digits in the source are - multiplied by successive values in the conversion table, and the - results are accumulated in the product area. Although the manual - does not say, this code assumes that EZ and HP are affected. - */ - -t_stat oct_to_dec (uint32 tbl, uint32 s) -{ -uint32 cnt = 0, tblc; -uint32 i, sd, sf, tf, sign; -t_stat r; - -for (i = 0; i < PROD_AREA_LEN; i++) /* clr prod area */ - M[PROD_AREA + i] = 0; -sign = M[s] & FLAG; /* save sign */ -ind[IN_EZ] = 1; /* set indicators */ -ind[IN_HP] = (sign == 0); -do { - sd = M[s] & DIGIT; /* src digit */ - sf = M[s] & FLAG; /* src flag */ - r = mul_one_digit (sd, tbl, PROD_AREA + PROD_AREA_LEN - 1, sf); - if (r != SCPE_OK) /* err? */ - return r; - MM (s); /* decr src addr */ - MM (tbl); /* skip 1st tbl dig */ - tblc = 0; /* count */ - do { - tf = M[tbl] & FLAG; /* get next */ - MM (tbl); /* decr ptr */ - if (tblc++ > MEMSIZE) - return STOP_FWRAP; - } while (tf == 0); /* until flag */ - if (cnt++ >= MEMSIZE) /* (stop runaway) */ - return STOP_FWRAP; - } while (sf == 0); -if (ind[IN_EZ]) /* res = 0? clr HP */ - ind[IN_HP] = 0; -M[PROD_AREA + PROD_AREA_LEN - 1] |= sign; /* set sign */ -return SCPE_OK; -} - -/* Decimal to octal - - Inputs: - d = destination address - tbl = conversion table address (low digit of highest power) - &ez = address of soft EZ indicator - product area = field to convert - Outputs: - return = status - - DTO is a cousin to divide. The number in the product area is repeatedly - divided by successive values in the conversion table, and the quotient - digits are stored in the destination. Although the manual does not say, - this code assumes that EZ and HP are affected. - */ - -t_stat dec_to_oct (uint32 d, uint32 tbl, int32 *ez) -{ -uint32 sign, octd, t; -t_bool first = TRUE; -uint32 ctr = 0; -t_stat r; - -sign = M[PROD_AREA + PROD_AREA_LEN - 1] & FLAG; /* input sign */ -*ez = 1; /* set indicators */ -ind[IN_HP] = (sign == 0); -for ( ;; ) { - r = div_one_digit (PROD_AREA + PROD_AREA_LEN - 1, /* divide */ - tbl, 8, &octd, NULL); - if (r != SCPE_OK) /* error? */ - return r; - if (first) { /* first pass? */ - if (octd >= 8) { /* overflow? */ - ind[IN_OVF] = 1; /* set indicator */ - return SCPE_OK; /* stop */ - } - M[d] = FLAG | octd; /* set flag on quo */ - first = FALSE; - } - else M[d] = octd; /* store quo digit */ - if (octd) /* if nz, clr ind */ - *ez = 0; - PP (tbl); /* incr tbl addr */ - if ((M[tbl] & REC_MARK) == REC_MARK) /* record mark? */ - break; - PP (tbl); /* skip flag */ - if ((M[tbl] & REC_MARK) == REC_MARK) /* record mark? */ - break; - do { /* look for F, rec mk */ - PP (tbl); - t = M[tbl]; - } while (((t & FLAG) == 0) && ((t & REC_MARK) != REC_MARK)); - MM (tbl); /* step back one */ - PP (d); /* incr quo addr */ - if (ctr++ > MEMSIZE) /* (stop runaway) */ - return STOP_FWRAP; - } -if (*ez) /* res = 0? clr HP */ - ind[IN_HP] = 0; -M[d] = M[d] | sign; /* set result sign */ -return SCPE_OK; -} - -/* Set and clear IO in progress */ - -t_stat cpuio_set_inp (uint32 op, uint32 dev, UNIT *uptr) -{ -cpuio_inp = 1; -cpuio_opc = op; -cpuio_dev = dev; -cpuio_cnt = 0; -if (uptr != NULL) - sim_activate_abs (uptr, uptr->wait); -return SCPE_OK; -} - -t_stat cpuio_clr_inp (UNIT *uptr) -{ -cpuio_inp = 0; -cpuio_opc = 0; -cpuio_dev = 0; -cpuio_cnt = 0; -if (uptr != NULL) - sim_cancel (uptr); -return SCPE_OK; -} - -/* Reset routine */ - -t_stat cpu_reset (DEVICE *dptr) -{ -int32 i; -static t_bool one_time = TRUE; - -PR1 = IR2 = 1; /* invalidate PR1,IR2 */ -ind[0] = 0; -for (i = IN_SW4 + 1; i < NUM_IND; i++) /* init indicators */ - ind[i] = 0; -if (cpuio_inp != 0) /* IO in progress? */ - cpu_set_release (NULL, 0, NULL, NULL); /* clear IO */ -if (cpu_unit.flags & IF_IA) /* indirect enabled? */ - iae = 1; -else iae = 0; -idxe = idxb = 0; /* indexing off */ -pcq_r = find_reg ("PCQ", NULL, dptr); /* init old PC queue */ -if (pcq_r) - pcq_r->qptr = 0; -else return SCPE_IERR; -sim_brk_types = sim_brk_dflt = SWMASK ('E'); /* init breakpoints */ -upd_ind (); /* update indicators */ -if (one_time) { /* set default tables */ - cpu_set_table (&cpu_unit, 1, NULL, NULL); - actual_PC = saved_PC = 0; /* sync PCs */ - } -one_time = FALSE; -return SCPE_OK; -} - -/* Release routine */ - -t_stat cpu_set_release (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -uint32 i; -DEVICE *dptr; - -if (cpuio_inp != 0) { /* IO in progress? */ - cpuio_inp = 0; - cpuio_opc = 0; - cpuio_dev = 0; - cpuio_cnt = 0; - for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { - if (((dptr->flags & DEV_DEFIO) != 0) && (dptr->reset != NULL)) - dptr->reset (dptr); - } - sim_printf ("IO operation canceled\n"); - } -else if (actual_PC == ADDR_A (saved_PC, INST_LEN)) { /* one instr ahead? */ - saved_PC = actual_PC; - sim_printf ("New PC = %05d\n", saved_PC); - } -else sim_printf ("PC unchanged\n"); -return SCPE_OK; -} - -/* Memory examine */ - -t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) -{ -if (addr >= MEMSIZE) - return SCPE_NXM; -if (vptr != NULL) - *vptr = M[addr] & (FLAG | DIGIT); -return SCPE_OK; -} - -/* Memory deposit */ - -t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) -{ -if (addr >= MEMSIZE) - return SCPE_NXM; -M[addr] = val & (FLAG | DIGIT); -return SCPE_OK; -} - -/* Memory size change */ - -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 mc = 0; -uint32 i; - -if ((val <= 0) || (val > MAXMEMSIZE) || ((val % 1000) != 0)) - return SCPE_ARG; -for (i = val; i < MEMSIZE; i++) - mc = mc | M[i]; -if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) - return SCPE_OK; -MEMSIZE = val; -for (i = MEMSIZE; i < MAXMEMSIZE; i++) - M[i] = 0; -return SCPE_OK; -} - -/* Model change */ - -t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (val) - cpu_unit.flags = (cpu_unit.flags & (UNIT_SCP | UNIT_BCD | MII_OPT)) | - IF_DIV | IF_IA | IF_EDT; -else cpu_unit.flags = cpu_unit.flags & (UNIT_SCP | UNIT_BCD | MI_OPT); -return SCPE_OK; -} - -/* Set/clear Model 1 option */ - -t_stat cpu_set_opt1 (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (cpu_unit.flags & IF_MII) { - if ((val & IF_RMOK) != 0) - sim_printf ("Feature is not available on 1620 Model 2\n"); - else sim_printf ("Feature is standard on 1620 Model 2\n"); - return SCPE_NOFNC; - } -return SCPE_OK; -} - -/* Set/clear Model 2 option */ - -t_stat cpu_set_opt2 (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (!(cpu_unit.flags & IF_MII)) { - sim_printf ("Feature is not available on 1620 Model 1\n"); - return SCPE_NOFNC; - } -return SCPE_OK; -} - -/* Front panel save */ - -t_stat cpu_set_save (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (saved_PC & 1) - return SCPE_NOFNC; -PR1 = saved_PC; -return SCPE_OK; -} - -/* Set standard add/multiply tables */ - -t_stat cpu_set_table (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 i; - -for (i = 0; i < MUL_TABLE_LEN; i++) /* set mul table */ - M[MUL_TABLE + i] = std_mul_table[i]; -if (((cpu_unit.flags & IF_MII) == 0) || val) { /* set add table */ - for (i = 0; i < ADD_TABLE_LEN; i++) - M[ADD_TABLE + i] = std_add_table[i]; - } -return SCPE_OK; -} - -/* Set history */ - -t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 i, lnt; -t_stat r; - -if (cptr == NULL) { - for (i = 0; i < hst_lnt; i++) - hst[i].vld = 0; - hst_p = 0; - return SCPE_OK; - } -lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r); -if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) - return SCPE_ARG; -hst_p = 0; -if (hst_lnt) { - free (hst); - hst_lnt = 0; - hst = NULL; - } -if (lnt) { - hst = (InstHistory *) calloc (lnt, sizeof (InstHistory)); - if (hst == NULL) - return SCPE_MEM; - hst_lnt = lnt; - } -return SCPE_OK; -} - -/* Show history */ - -t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -int32 i, k, di, lnt; -char *cptr = (char *) desc; -t_value sim_eval[INST_LEN]; -t_stat r; -InstHistory *h; -extern t_stat fprint_sym (FILE *ofile, t_addr addr, t_value *val, - UNIT *uptr, int32 sw); - -if (hst_lnt == 0) /* enabled? */ - return SCPE_NOFNC; -if (cptr) { - lnt = (int32) get_uint (cptr, 10, hst_lnt, &r); - if ((r != SCPE_OK) || (lnt == 0)) - return SCPE_ARG; - } -else lnt = hst_lnt; -di = hst_p - lnt; /* work forward */ -if (di < 0) - di = di + hst_lnt; -fprintf (st, "PC IR\n\n"); -for (k = 0; k < lnt; k++) { /* print specified */ - h = &hst[(++di) % hst_lnt]; /* entry pointer */ - if (h->vld) { /* instruction? */ - fprintf (st, "%05d ", h->pc); - for (i = 0; i < INST_LEN; i++) - sim_eval[i] = h->inst[i]; - if ((fprint_sym (st, h->pc, sim_eval, &cpu_unit, SWMASK ('M'))) > 0) { - fprintf (st, "(undefined)"); - for (i = 0; i < INST_LEN; i++) - fprintf (st, "%02X", h->inst[i]); - } - fputc ('\n', st); /* end line */ - } /* end else instruction */ - } /* end for */ -return SCPE_OK; -} diff --git a/I1620/i1620_defs.h b/I1620/i1620_defs.h deleted file mode 100644 index fd21f9d2..00000000 --- a/I1620/i1620_defs.h +++ /dev/null @@ -1,249 +0,0 @@ -/* i1620_defs.h: IBM 1620 simulator definitions - - Copyright (c) 2002-2017, Robert M. Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - This simulator is based on the 1620 simulator written by Geoff Kuenning. - I am grateful to Al Kossow, the Computer History Museum, and the IBM Corporate - Archives for their help in gathering documentation about the IBM 1620. - - 23-May-17 RMS MARCHK is indicator 8, not 18 (Dave Wise) - 19-May-17 RMS Added option for Model I diagnostic mode (Dave Wise) - 05-Feb-15 TFM Added definitions for flagged RM, GM, NB - 22-May-10 RMS Added check for 64b definitions - 18-Oct-02 RMS Fixed bug in ADDR_S macro (found by Hans Pufal) -*/ - -#ifndef I1620_DEFS_H_ -#define I1620_DEFS_H_ 0 - -#include "sim_defs.h" /* simulator defns */ - -#if defined(USE_INT64) || defined(USE_ADDR64) -#error "1620 does not support 64b values!" -#endif - -/* Simulator stop codes */ - -#define STOP_HALT 1 /* HALT */ -#define STOP_IBKPT 2 /* breakpoint */ -#define STOP_INVINS 3 /* invalid instruction */ -#define STOP_INVDIG 4 /* invalid digit */ -#define STOP_INVCHR 5 /* invalid char */ -#define STOP_INVIND 6 /* invalid indicator */ -#define STOP_INVPDG 7 /* invalid P addr digit */ -#define STOP_INVPAD 8 /* invalid P addr */ -#define STOP_INVPIA 9 /* invalid P indir addr */ -#define STOP_INVQDG 10 /* invalid Q addr digits */ -#define STOP_INVQAD 11 /* invalid Q addr */ -#define STOP_INVQIA 12 /* invalid Q indir addr */ -#define STOP_INVIO 13 /* invalid IO address */ -#define STOP_INVRTN 14 /* invalid return */ -#define STOP_INVFNC 15 /* invalid function */ -#define STOP_INVIAD 16 /* invalid instr addr */ -#define STOP_INVSEL 17 /* invalid select */ -#define STOP_INVIDX 18 /* invalid index instr */ -#define STOP_INVEAD 19 /* invalid even addr */ -#define STOP_INVDCF 20 /* invalid DCF addr */ -#define STOP_INVDRV 21 /* invalid disk drive */ -#define STOP_INVDSC 22 /* invalid disk sector */ -#define STOP_INVDCN 23 /* invalid disk count */ -#define STOP_INVDBA 24 /* invalid disk buf addr */ -#define STOP_DACERR 25 /* disk addr comp err */ -#define STOP_DWCERR 26 /* disk wr check err */ -#define STOP_CYOERR 27 /* cylinder ovflo err */ -#define STOP_WRLERR 28 /* wrong rec lnt err */ -#define STOP_CCT 29 /* runaway CCT */ -#define STOP_FWRAP 30 /* field wrap */ -#define STOP_RWRAP 31 /* record wrap */ -#define STOP_NOCD 32 /* no card in reader */ -#define STOP_OVERFL 33 /* overflow */ -#define STOP_EXPCHK 34 /* exponent error */ -#define STOP_WRADIS 35 /* write addr disabled */ -#define STOP_FPLNT 36 /* invalid fp length */ -#define STOP_FPUNL 37 /* fp lengths unequal */ -#define STOP_FPMF 38 /* no flag on exp */ -#define STOP_FPDVZ 39 /* divide by zero */ - -/* Memory */ - -#define MAXMEMSIZE 60000 /* max mem size */ -#define MEMSIZE (cpu_unit.capac) /* act memory size */ - -/* Processor parameters */ - -#define INST_LEN 12 /* inst length */ -#define ADDR_LEN 5 /* addr length */ -#define MUL_TABLE 100 /* multiply table */ -#define MUL_TABLE_LEN 200 -#define ADD_TABLE 300 /* add table */ -#define ADD_TABLE_LEN 100 -#define IDX_A 300 /* index A base */ -#define IDX_B 340 /* index B base */ -#define PROD_AREA 80 /* product area */ -#define PROD_AREA_LEN 20 /* product area */ -#define PROD_AREA_END (PROD_AREA + PROD_AREA_LEN) - -/* Branch indicator codes */ - -#define NUM_IND 100 /* number of indicators */ - -#define IN_SW1 1 /* sense switch 1 */ -#define IN_SW2 2 /* sense switch 2 */ -#define IN_SW3 3 /* sense switch 3 */ -#define IN_SW4 4 /* sense switch 4 */ -#define IN_RDCHK 6 /* read check (I/O error) */ -#define IN_WRCHK 7 /* write check (I/O error) */ -#define IN_MARCHK 8 /* MAR check - diag only */ -#define IN_LAST 9 /* last card was just read */ -#define IN_HP 11 /* high or positive result */ -#define IN_EZ 12 /* equal or zero result */ -#define IN_HPEZ 13 /* high/positive or equal/zero */ -#define IN_OVF 14 /* overflow */ -#define IN_EXPCHK 15 /* floating exponent check */ -#define IN_MBREVEN 16 /* even parity check */ -#define IN_MBRODD 17 /* odd parity check */ -#define IN_ANYCHK 19 /* any of read, write, even/odd */ -#define IN_PRCHK 25 /* printer check */ -#define IN_IXN 30 /* IX neither */ -#define IN_IXA 31 /* IX A band */ -#define IN_IXB 32 /* IX B band */ -#define IN_PRCH9 33 /* printer chan 9 */ -#define IN_PRCH12 34 /* printer chan 12 */ -#define IN_PRBSY 35 /* printer busy */ -#define IN_DACH 36 /* disk addr/data check */ -#define IN_DWLR 37 /* disk rec length */ -#define IN_DCYO 38 /* disk cyl overflow */ -#define IN_DERR 39 /* disk any error */ - -/* I/O channel codes */ - -#define NUM_IO 100 /* number of IO chan */ - -#define IO_TTY 1 /* console typewriter */ -#define IO_PTP 2 /* paper-tape punch */ -#define IO_PTR 3 /* paper-tape reader */ -#define IO_CDP 4 /* card punch */ -#define IO_CDR 5 /* card reader */ -#define IO_DSK 7 /* disk */ -#define IO_LPT 9 /* line printer */ -#define IO_BTP 32 /* binary ptp */ -#define IO_BTR 33 /* binary ptr */ - -#define LPT_WIDTH 120 /* line print width */ -#define CCT_LNT 132 /* car ctrl length */ - -#define CRETIOE(f,c) return ((f)? (c): SCPE_OK) - -/* Memory representation: flag + BCD digit per byte */ - -#define FLAG 0x10 -#define DIGIT 0x0F -#define REC_MARK 0xA -#define NUM_BLANK 0xC -#define GRP_MARK 0xF -#define FLG_REC_MARK 0x1A -#define FLG_NUM_BLANK 0x1C -#define FLG_GRP_MARK 0x1F -#define BAD_DIGIT(x) ((x) > 9) - -/* Instruction format */ - -#define I_OP 0 /* opcode */ -#define I_P 2 /* P start */ -#define I_PL 6 /* P end */ -#define I_Q 7 /* Q start */ -#define I_QL 11 /* Q end */ -#define I_IO 8 /* IO select */ -#define I_BR 8 /* indicator select */ -#define I_CTL 10 /* control select */ -#define I_SEL 11 /* BS select */ - -#define ADDR_A(x,a) ((((x) + (a)) >= MEMSIZE)? ((x) + (a) - MEMSIZE): ((x) + (a))) -#define ADDR_S(x,a) (((x) < (a))? ((x) - (a) + MEMSIZE): ((x) - (a))) -#define PP(x) x = ADDR_A(x,1) -#define MM(x) x = ADDR_S(x,1) - -/* CPU options, stored in cpu_unit.flags */ -/* Decoding flags must be part of the same definition set */ - -#define UNIT_SCP ((1 << UNIT_V_UF) - 1) /* mask of SCP flags */ -#define IF_MII (1 << (UNIT_V_UF + 0)) /* model 2 */ -#define IF_DIV (1 << (UNIT_V_UF + 1)) /* automatic divide */ -#define IF_IA (1 << (UNIT_V_UF + 2)) /* indirect addressing */ -#define IF_EDT (1 << (UNIT_V_UF + 3)) /* edit */ -#define IF_FP (1 << (UNIT_V_UF + 4)) /* floating point */ -#define IF_BIN (1 << (UNIT_V_UF + 5)) /* binary */ -#define IF_IDX (1 << (UNIT_V_UF + 6)) /* indexing */ -#define IF_VPA (1 << (UNIT_V_UF + 7)) /* valid P addr */ -#define IF_VQA (1 << (UNIT_V_UF + 8)) /* valid Q addr */ -#define IF_4QA (1 << (UNIT_V_UF + 9)) /* 4 char Q addr */ -#define IF_NQX (1 << (UNIT_V_UF + 10)) /* no Q indexing */ -#define IF_IMM (1 << (UNIT_V_UF + 11)) /* immediate */ -#define IF_RMOK (1 << (UNIT_V_UF + 12)) /* diag mode - force rm to 0 */ -#define UNIT_BCD (1 << (UNIT_V_UF + 13)) /* BCD coded */ -#define UNIT_MSIZE (1 << (UNIT_V_UF + 14)) /* fake flag */ -#define ALLOPT (IF_DIV + IF_IA + IF_EDT + IF_FP + IF_BIN + IF_IDX + IF_RMOK) -#define MI_OPT (IF_DIV + IF_IA + IF_EDT + IF_FP + IF_RMOK) -#define MI_STD (IF_DIV + IF_IA + IF_EDT) -#define MII_OPT (IF_DIV + IF_IA + IF_EDT + IF_FP + IF_BIN + IF_IDX) -#define MII_STD (IF_DIV + IF_IA + IF_EDT + IF_BIN + IF_IDX) - -/* Add status codes */ - -#define ADD_NOCRY 0 /* no carry out */ -#define ADD_CARRY 1 /* carry out */ -#define ADD_SIGNC 2 /* sign change */ - -/* Opcodes */ - -enum opcodes { - OP_FADD = 1, OP_FSUB, OP_FMUL, /* 00 - 09 */ - OP_FSL = 5, OP_TFL, OP_BTFL, OP_FSR, OP_FDIV, - OP_BTAM = 10, OP_AM, OP_SM, OP_MM, OP_CM, /* 10 - 19 */ - OP_TDM, OP_TFM, OP_BTM, OP_LDM, OP_DM, - OP_BTA = 20, OP_A, OP_S, OP_M, OP_C, /* 20 - 29 */ - OP_TD, OP_TF, OP_BT, OP_LD, OP_D, - OP_TRNM = 30, OP_TR, OP_SF, OP_CF, OP_K, /* 30 - 39 */ - OP_DN, OP_RN, OP_RA, OP_WN, OP_WA, - OP_NOP = 41, OP_BB, OP_BD, OP_BNF, /* 40 - 49 */ - OP_BNR, OP_BI, OP_BNI, OP_H, OP_B, - OP_BNG = 55, - OP_BS = 60, OP_BX, OP_BXM, OP_BCX, OP_BCXM, /* 60 - 69 */ - OP_BLX, OP_BLXM, OP_BSX, - OP_MA = 70, OP_MF, OP_TNS, OP_TNF, /* 70 - 79 */ - /* 80 - 89 */ - OP_BBT = 90, OP_BMK, OP_ORF, OP_ANDF, OP_CPLF, /* 90 - 99 */ - OP_EORF, OP_OTD, OP_DTO }; - -/* Device flags */ - -#define DEV_DEFIO (1 << (DEV_V_UF + 0)) - -/* Function declarations */ - -t_stat cpuio_set_inp (uint32 op, uint32 dev, UNIT *uptr); -t_stat cpuio_clr_inp (UNIT *uptr); -char *opc_lookup (uint32 op, uint32 qv, uint32 *fl); - -#endif diff --git a/I1620/i1620_dp.c b/I1620/i1620_dp.c deleted file mode 100644 index 73cf960a..00000000 --- a/I1620/i1620_dp.c +++ /dev/null @@ -1,528 +0,0 @@ -/* i1620_dp.c: IBM 1311 disk simulator - - Copyright (c) 2002-2017, Robert M. Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - dp 1311 disk pack - - The 1311 disk pack has 100 cylinders, 10 tracks/cylinder, 20 sectors/track. - Each sector contains 105 characters of information: - - 5c sector address - 100c sector data - - By default, a sector's address field will be '00000', which is interpreted - to mean the implied sector number that would be in place if the disk pack - had been formatted with sequential sector numbers. - - 13-Mar-17 RMS Fixed bug in write check function test (COVERITY) - 18-Oct-02 RMS Fixed bug in error testing (Hans Pufal) -*/ - -#include "i1620_defs.h" - -#define DP_NUMDR 4 /* #drives */ -#define UNIT_V_WAE (UNIT_V_UF + 0) /* write addr enab */ -#define UNIT_WAE (1 << UNIT_V_WAE) - -/* Disk format */ - -#define DP_ADDR 5 /* address */ -#define DP_DATA 100 /* data */ -#define DP_NUMCH (DP_ADDR + DP_DATA) - -#define DP_NUMSC 20 /* #sectors */ -#define DP_NUMSF 10 /* #surfaces */ -#define DP_NUMCY 100 /* #cylinders */ -#define DP_TOTSC (DP_NUMCY * DP_NUMSF * DP_NUMSC) -#define DP_SIZE (DP_TOTSC * DP_NUMCH) - -/* Disk control field */ - -#define DCF_DRV 0 /* drive select */ -#define DCF_SEC 1 /* sector addr */ -#define DCF_SEC_LEN 5 -#define DCF_CNT (DCF_SEC + DCF_SEC_LEN) /* sector count */ -#define DCF_CNT_LEN 3 -#define DCF_ADR (DCF_CNT + DCF_CNT_LEN) /* buffer address */ -#define DCF_ADR_LEN 5 -#define DCF_LEN (DCF_ADR + DCF_ADR_LEN) - -/* Functions */ - -#define FNC_SEEK 1 /* seek */ -#define FNC_SEC 0 /* sectors */ -#define FNC_WCH 1 /* write check */ -#define FNC_NRL 2 /* no rec lnt chk */ -#define FNC_TRK 4 /* tracks */ -#define FNC_WRI 8 /* write offset */ - -#define CYL u3 /* current cylinder */ - -extern uint8 M[MAXMEMSIZE]; /* memory */ -extern uint8 ind[NUM_IND]; -extern UNIT cpu_unit; - -int32 dp_stop = 1; /* disk err stop */ -uint32 dp_ba = 0; /* buffer addr */ - -t_stat dp_reset (DEVICE *dptr); -t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 qnr, int32 qwc); -t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 qnr, int32 qwc); -t_stat dp_wradr (UNIT *uptr, int32 sec, int32 qnr); -t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 qnr); -int32 dp_fndsec (UNIT *uptr, int32 sec, t_bool rd); -t_stat dp_nexsec (UNIT *uptr, int32 sec, int32 psec, t_bool rd); -t_bool dp_zeroad (uint8 *ap); -int32 dp_cvt_ad (uint8 *ap); -int32 dp_trkop (int32 drv, int32 sec); -int32 dp_cvt_bcd (uint32 ad, int32 len); -void dp_fill (UNIT *uptr, uint32 da, int32 cnt); -t_stat dp_tstgm (uint32 c, int32 qnr); - -/* DP data structures - - dp_dev DP device descriptor - dp_unit DP unit list - dp_reg DP register list - dp_mod DP modifier list -*/ - -UNIT dp_unit[] = { - { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE + - UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) }, - { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE + - UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) }, - { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE + - UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) }, - { UDATA (NULL, UNIT_FIX + UNIT_DISABLE + UNIT_ATTABLE + - UNIT_BUFABLE + UNIT_MUSTBUF + UNIT_BCD, DP_SIZE) } - }; - -REG dp_reg[] = { - { FLDATA (ADCHK, ind[IN_DACH], 0) }, - { FLDATA (WLRC, ind[IN_DWLR], 0) }, - { FLDATA (CYLO, ind[IN_DCYO], 0) }, - { FLDATA (ERR, ind[IN_DERR], 0) }, - { FLDATA (DPSTOP, dp_stop, 0) }, - { URDATA (CYL, dp_unit[0].CYL, 10, 8, 0, - DP_NUMDR, PV_LEFT + REG_RO) }, - { NULL } - }; - -MTAB dp_mod[] = { - { UNIT_WAE, 0, "write address disabled", "ADDROFF", NULL }, - { UNIT_WAE, UNIT_WAE, "write address enabled", "ADDRON", NULL }, - { 0 } - }; - -DEVICE dp_dev = { - "DP", dp_unit, dp_reg, dp_mod, - DP_NUMDR, 10, 21, 1, 16, 5, - NULL, NULL, &dp_reset, - NULL, NULL, NULL - }; - -/* Disk IO routine */ - -t_stat dp (uint32 op, uint32 pa, uint32 f0, uint32 f1) -{ -int32 drv, sa, sec, psec, cnt, qwc, qnr, t; -UNIT *uptr; -t_stat r; - -if (pa & 1) /* dcf must be even */ - return STOP_INVDCF; -ind[IN_DACH] = ind[IN_DWLR] = 0; /* clr indicators */ -ind[IN_DERR] = ind[IN_DCYO] = 0; -sa = ADDR_A (pa, DCF_SEC); /* ptr to sector */ -if (((dp_unit[0].flags & UNIT_DIS) == 0) && /* only drive 0? */ - (dp_unit[1].flags & UNIT_DIS) && - (dp_unit[2].flags & UNIT_DIS) && - (dp_unit[3].flags & UNIT_DIS)) drv = 0; /* ignore drv select */ -else drv = (((M[pa] & 1)? M[pa]: M[sa]) & 0xE) >> 1; /* drive # */ -if (drv >= DP_NUMDR) /* invalid? */ - return STOP_INVDRV; -uptr = dp_dev.units + drv; /* get unit ptr */ -if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */ - ind[IN_DERR] = 1; /* no, error */ - CRETIOE (dp_stop, SCPE_UNATT); - } - -sec = dp_cvt_bcd (sa, DCF_SEC_LEN); /* cvt sector */ -if ((sec < 0) || (sec >= (DP_NUMDR * DP_TOTSC))) /* bad sector? */ - return STOP_INVDSC; -if (op == OP_K) { /* seek? */ - if (f1 != FNC_SEEK) /* really? */ - return STOP_INVFNC; - uptr->CYL = (sec / (DP_NUMSF * DP_NUMSC)) % /* set cyl # */ - DP_NUMCY; - return SCPE_OK; /* done! */ - } - -cnt = dp_cvt_bcd (ADDR_A (pa, DCF_CNT), DCF_CNT_LEN); /* get count */ -t = dp_cvt_bcd (ADDR_A (pa, DCF_ADR), DCF_ADR_LEN); /* get address */ -if ((t < 0) || (t & 1)) /* bad address? */ - return STOP_INVDBA; -dp_ba = t; /* save addr */ - -if (f1 >= FNC_WRI) /* invalid func? */ - return STOP_INVFNC; -if (op == OP_RN) /* read? set wch */ - qwc = f1 & FNC_WCH; -else if (op == OP_WN) { /* write? */ - if (f1 & FNC_WCH) /* cant check */ - return STOP_INVFNC; - f1 = f1 + FNC_WRI; /* offset fnc */ - } -else return STOP_INVFNC; /* not R or W */ -qnr = f1 & FNC_NRL; /* no rec check? */ - -switch (f1 & ~(FNC_WCH | FNC_NRL)) { /* case on function */ - - case FNC_SEC: /* read sectors */ - if (cnt <= 0) /* bad count? */ - return STOP_INVDCN; - psec = dp_fndsec (uptr, sec, TRUE); /* find sector */ - if (psec < 0) /* error? */ - CRETIOE (dp_stop, STOP_DACERR); - do { /* loop on count */ - if (r = dp_rdsec (uptr, psec, qnr, qwc)) /* read sector */ - break; - sec++; psec++; /* next sector */ - } while ((--cnt > 0) && - ((r = dp_nexsec (uptr, sec, psec, TRUE)) == SCPE_OK)); - break; /* done, clean up */ - - case FNC_TRK: /* read track */ - psec = dp_trkop (drv, sec); /* start of track */ - for (cnt = 0; cnt < DP_NUMSC; cnt++) { /* full track */ - if (r = dp_rdadr (uptr, psec, qnr, qwc)) /* read addr */ - break; /* error? */ - if (r = dp_rdsec (uptr, psec, qnr, qwc)) /* read data */ - break; /* error? */ - psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC); - } - break; /* done, clean up */ - - case FNC_SEC + FNC_WRI: /* write sectors */ - if (cnt <= 0) /* bad count? */ - return STOP_INVDCN; - psec = dp_fndsec (uptr, sec, FALSE); /* find sector */ - if (psec < 0) /* error? */ - CRETIOE (dp_stop, STOP_DACERR); - do { /* loop on count */ - if (r = dp_tstgm (M[dp_ba], qnr)) /* start with gm? */ - break; - if (r = dp_wrsec (uptr, psec, qnr)) /* write data */ - break; - sec++; psec++; /* next sector */ - } while ((--cnt > 0) && - ((r = dp_nexsec (uptr, sec, psec, FALSE)) == SCPE_OK)); - break; /* done, clean up */ - - case FNC_TRK + FNC_WRI: /* write track */ - if ((uptr->flags & UNIT_WAE) == 0) /* enabled? */ - return STOP_WRADIS; - psec = dp_trkop (drv, sec); /* start of track */ - for (cnt = 0; cnt < DP_NUMSC; cnt++) { /* full track */ - if (r = dp_tstgm (M[dp_ba], qnr)) /* start with gm? */ - break; - if (r = dp_wradr (uptr, psec, qnr)) /* write addr */ - break; - if (r = dp_wrsec (uptr, psec, qnr)) /* write data */ - break; - psec = dp_trkop (drv, sec) + ((psec + 1) % DP_NUMSC); - } - break; /* done, clean up */ - - default: /* unknown */ - return STOP_INVFNC; - } - -if ((r == SCPE_OK) && !qnr) { /* eor check? */ - if ((M[dp_ba] & DIGIT) != GRP_MARK) { /* GM at end? */ - ind[IN_DWLR] = ind[IN_DERR] = 1; /* no, error */ - r = STOP_WRLERR; - } - } -if ((r != SCPE_OK) && /* error? */ - (dp_stop || !ind[IN_DERR])) /* iochk or stop? */ - return r; -return SCPE_OK; /* continue */ -} - -/* Read or compare address with memory */ - -t_stat dp_rdadr (UNIT *uptr, int32 sec, int32 qnr, int32 qwc) -{ -int32 i; -uint8 ad; -int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */ -uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */ -t_bool zad = dp_zeroad (ap); /* zero address */ -static const int32 dec_tab[DP_ADDR] = { /* powers of 10 */ - 10000, 1000, 100, 10, 1 - } ; - -for (i = 0; i < DP_ADDR; i++) { /* copy/check addr */ - if (zad) { /* addr zero? */ - ad = sec / dec_tab[i]; /* get addr digit */ - sec = sec % dec_tab[i]; /* get remainder */ - } - else ad = *ap; /* addr digit */ - if (qwc) { /* write check? */ - if (dp_tstgm (M[dp_ba], qnr)) /* grp mrk in mem? */ - return STOP_WRLERR; /* yes, error */ - if (!zad && (M[dp_ba] != ad)) { /* digits equal? */ - ind[IN_DACH] = ind[IN_DERR] = 1; /* no, error */ - return STOP_DWCERR; - } - } - else M[dp_ba] = ad & (FLAG | DIGIT); /* store digit */ - if (dp_tstgm (*ap, qnr)) /* grp mrk on disk? */ - return STOP_WRLERR; - ap++; PP (dp_ba); /* adv ptrs */ - } -return SCPE_OK; -} - -/* Read or compare data with memory */ - -t_stat dp_rdsec (UNIT *uptr, int32 sec, int32 qnr, int32 qwc) -{ -int32 i; -int32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */ -uint8 *ap = ((uint8 *) uptr->filebuf) + da + DP_ADDR; /* buf ptr */ - -for (i = 0; i < DP_DATA; i++) { /* copy data */ - if (qwc) { /* write check? */ - if (dp_tstgm (M[dp_ba], qnr)) /* grp mrk in mem? */ - return STOP_WRLERR; /* yes, error */ - if (M[dp_ba] != *ap) { /* dig+flags equal? */ - ind[IN_DACH] = ind[IN_DERR] = 1; /* no, error */ - return STOP_DWCERR; - } - } - else M[dp_ba] = *ap & (FLAG | DIGIT); /* flag + digit */ - if (dp_tstgm (*ap, qnr)) /* grp mrk on disk? */ - return STOP_WRLERR; - ap++; PP (dp_ba); /* adv ptrs */ - } -return SCPE_OK; -} - -/* Write address to disk */ - -t_stat dp_wradr (UNIT *uptr, int32 sec, int32 qnr) -{ -int32 i; -uint32 da = (sec % DP_TOTSC) * DP_NUMCH; /* char number */ -uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */ - -for (i = 0; i < DP_ADDR; i++) { /* copy address */ - *ap = M[dp_ba] & (FLAG | DIGIT); /* flag + digit */ - if (da >= uptr->hwmark) - uptr->hwmark = da + 1; - if (dp_tstgm (*ap, qnr)) { /* grp mrk fm mem? */ - dp_fill (uptr, da + 1, DP_NUMCH - i - 1); /* fill addr+data */ - return STOP_WRLERR; /* error */ - } - da++; ap++; PP (dp_ba); /* adv ptrs */ - } -return SCPE_OK; -} - -/* Write data to disk */ - -t_stat dp_wrsec (UNIT *uptr, int32 sec, int32 qnr) -{ -int32 i; -uint32 da = ((sec % DP_TOTSC) * DP_NUMCH) + DP_ADDR; /* char number */ -uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */ - -for (i = 0; i < DP_DATA; i++) { /* copy data */ - *ap = M[dp_ba] & (FLAG | DIGIT); /* get character */ - if (da >= uptr->hwmark) - uptr->hwmark = da + 1; - if (dp_tstgm (*ap, qnr)) { /* grp mrk fm mem? */ - dp_fill (uptr, da + 1, DP_DATA - i - 1); /* fill data */ - return STOP_WRLERR; /* error */ - } - da++; ap++; PP (dp_ba); /* adv ptrs */ - } -return SCPE_OK; -} - -/* Find sector */ - -int32 dp_fndsec (UNIT *uptr, int32 sec, t_bool rd) -{ -int32 ctrk = sec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */ -int32 psec = ((uptr->CYL) * (DP_NUMSF * DP_NUMSC)) + ctrk; -int32 da = psec * DP_NUMCH; /* char number */ -uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */ -int32 dskad, i; - -if (dp_zeroad (ap)) /* addr zero? ok */ - return psec; -dskad = dp_cvt_ad (ap); /* cvt addr */ -if (dskad == sec) { /* match? */ - if (rd || ((*ap & FLAG) == 0)) /* read or !wprot? */ - return psec; - ind[IN_DACH] = ind[IN_DERR] = 1; /* no match */ - return -1; - } -psec = psec - (psec % DP_NUMSC); /* sector 0 */ -for (i = 0; i < DP_NUMSC; i++, psec++) { /* check track */ - da = psec * DP_NUMCH; /* char number */ - ap = ((uint8 *) uptr->filebuf) + da; /* word pointer */ - if (dp_zeroad (ap)) /* no implicit match */ - continue; - dskad = dp_cvt_ad (ap); /* cvt addr */ - if (dskad == sec) { /* match? */ - if (rd || ((*ap & FLAG) == 0)) /* read or !wprot? */ - return psec; - ind[IN_DACH] = ind[IN_DERR] = 1; /* no match */ - return -1; - } - } -ind[IN_DACH] = ind[IN_DERR] = 1; /* no match */ -return -1; -} - -/* Find next sector - must be sequential, cannot cross cylinder boundary */ - -t_stat dp_nexsec (UNIT *uptr, int32 sec, int32 psec, t_bool rd) -{ -int32 ctrk = psec % (DP_NUMSF * DP_NUMSC); /* curr trk-sec */ -int32 da = psec * DP_NUMCH; /* word number */ -uint8 *ap = ((uint8 *) uptr->filebuf) + da; /* buf ptr */ -int32 dskad; - -if (ctrk) { /* not trk zero? */ - if (dp_zeroad (ap)) /* addr zero? ok */ - return SCPE_OK; - dskad = dp_cvt_ad (ap); /* cvt addr */ - if ((dskad == sec) && /* match? */ - (rd || ((*ap & FLAG) == 0))) /* read or !wprot? */ - return SCPE_OK; - ind[IN_DACH] = ind[IN_DERR] = 1; /* no, error */ - return STOP_DACERR; - } -ind[IN_DCYO] = ind[IN_DERR] = 1; /* cyl overflow */ -return STOP_CYOERR; -} - -/* Test for zero address */ - -t_bool dp_zeroad (uint8 *ap) -{ -int32 i; - -for (i = 0; i < DP_ADDR; i++, ap++) { /* loop thru addr */ - if (*ap & DIGIT) /* nonzero? lose */ - return FALSE; - } -return TRUE; /* all zeroes */ -} - -/* Test for group mark when enabled */ - -t_stat dp_tstgm (uint32 c, int32 qnr) -{ -if (!qnr && ((c & DIGIT) == GRP_MARK)) { /* premature GM? */ - ind[IN_DWLR] = ind[IN_DERR] = 1; /* error */ - return STOP_WRLERR; - } -return SCPE_OK; -} - -/* Convert disk address to binary - invalid char force bad address */ - -int32 dp_cvt_ad (uint8 *ap) -{ -int32 i, r; -uint8 c; - -for (i = r = 0; i < DP_ADDR; i++, ap++) { /* loop thru addr */ - c = *ap & DIGIT; /* get digit */ - if (BAD_DIGIT (c)) /* bad digit? */ - return -1; - r = (r * 10) + c; /* bcd to binary */ - } -return r; -} - -/* Track operation setup */ - -int32 dp_trkop (int32 drv, int32 sec) -{ -int32 ctrk = (sec / DP_NUMSC) % DP_NUMSF; - -return ((drv * DP_TOTSC) + (dp_unit[drv].CYL * DP_NUMSF * DP_NUMSC) + - (ctrk * DP_NUMSC)); -} - -/* Convert DCF BCD field to binary */ - -int32 dp_cvt_bcd (uint32 ad, int32 len) -{ -uint8 c; -int32 r; - -for (r = 0; len > 0; len--) { /* loop thru char */ - c = M[ad] & DIGIT; /* get digit */ - if (BAD_DIGIT (c)) /* invalid? */ - return -1; - r = (r * 10) + c; /* cvt to bin */ - PP (ad); /* next digit */ - } -return r; -} - -/* Fill sector buffer with zero */ - -void dp_fill (UNIT *uptr, uint32 da, int32 cnt) -{ -while (cnt-- > 0) { /* fill with zeroes*/ - *(((uint8 *) uptr->filebuf) + da) = 0; - if (da >= uptr->hwmark) - uptr->hwmark = da + 1; - da++; - } -return; -} - -/* Reset routine */ - -t_stat dp_reset (DEVICE *dptr) -{ -int32 i; - -for (i = 0; i < DP_NUMDR; i++) /* reset cylinder */ - dp_unit[i].CYL = 0; -ind[IN_DACH] = ind[IN_DWLR] = 0; /* clr indicators */ -ind[IN_DERR] = ind[IN_DCYO] = 0; -return SCPE_OK; -} diff --git a/I1620/i1620_error_matrix.txt b/I1620/i1620_error_matrix.txt deleted file mode 100644 index 891e5ac4..00000000 --- a/I1620/i1620_error_matrix.txt +++ /dev/null @@ -1,29 +0,0 @@ -Device Error Action - -CDR RN, RA invalid char set RDCHK; if IOSTOP set, stop simulator with INVCHR - unattached stop simulator with UNATT (CHANGED - used to set RDCHK too) - end of file stop simulator witn NOCD (CHANGED - used to set RDCHK too) - file read error set RDCHK; stop simulator with IOERR - input line too long set RDCHK; stop simulator with IOERR - -CDP WN,DN invalid digit set WRCHK; if IOSTOP set, stop simulator with INVCHR - WA invalid char set WRCHK; if IOSTOP set, stop simulator with INVCHR - unattached stop simulator with UNATT (CHANGED - used to set WRCHK too) - file write error set WRCHK; stop simulator with IOERR - -LPT bad K control field set PRCHK; if IOSTOP set, stop simulator with INVFNC - WN,DN invalid digit set PRCHK and WRCHK; if IOSTOP set, stop simulator with INVFNC - WA invalid char set PRCHK and WRCHK; if IOSTOP set, stop simulator with INVFNC - unattached stop simulator with UNATT (CHANGED - used to set WRCHK too) - file write error set PRCHK and WRCHK; stop simulator with IOERR - -PTR RN, RA invalid char set RDCHK but complete operation; if IOSTOP set at end, stop simulator with INVCHR - RN, RA parity error set RDCHK but complete operation; if IOSTOP set at end, stop simulator with INVCHR - WN, DN invalid digit set WRCHK; if IOSTOP set, stop simulator with INVCHR - WA invalid char set WRCHK; if IOSTOP set, stop simulator with INVCHR - unattached stop simulator with UNATT (CHANGED - used to set WRCHK too) - file write error set WRCHK; stop simulator with IOERR - -TTY RN, RA invalid char ignored, echoed as beep/bell - WN, DN invalid digit ignored, printed as : - WA invalid char set WRCHK; if IOSTOP set, stop simulator with INVCHR diff --git a/I1620/i1620_fp.c b/I1620/i1620_fp.c deleted file mode 100644 index 489b8711..00000000 --- a/I1620/i1620_fp.c +++ /dev/null @@ -1,452 +0,0 @@ -/* i1620_fp.c: IBM 1620 floating point simulator - - Copyright (c) 2002-2015, Robert M. Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - The IBM 1620 uses a variable length floating point format, with a fixed - two digit decimal exponent and a variable length decimal mantissa: - - _ S_S - M.......MEE - - where S represents flag bits if the mantissa or exponent are negative. - - 26-Mar-2015 RMS Removed "store" parameter from add_field - 31-May-2008 RMS Fixed add_field call (Peter Schorn) -*/ - -#include "i1620_defs.h" - -#define FP_LMAX 100 /* max fp mant lnt */ -#define FP_EMAX 99 /* max fp exponent */ - -/* Unpacked floating point operand */ - -typedef struct { - int32 sign; /* 0 => +, 1 => - */ - int32 exp; /* binary exponent */ - uint32 lnt; /* mantissa length */ - uint32 addr; /* mantissa addr */ - uint32 zero; /* 0 => nz, 1 => zero */ - } FPA; - -extern uint8 M[MAXMEMSIZE]; /* main memory */ -extern uint8 ind[NUM_IND]; /* indicators */ -extern UNIT cpu_unit; - -t_stat fp_scan_mant (uint32 ad, uint32 *lnt, uint32 *zro); -t_stat fp_zero (FPA *fp); - -extern t_stat xmt_field (uint32 d, uint32 s, uint32 skp); -extern t_stat add_field (uint32 d, uint32 s, t_bool sub, uint32 skp, int32 *sta); -extern t_stat mul_field (uint32 d, uint32 s); -extern t_stat xmt_divd (uint32 d, uint32 s); -extern t_stat div_field (uint32 dvd, uint32 dvr, int32 *ez); - -/* Unpack and validate a floating point argument */ - -t_stat fp_unpack (uint32 ad, FPA *fp) -{ -uint8 d0, d1, esign; - -esign = M[ad] & FLAG; /* get exp sign */ -d0 = M[ad] & DIGIT; /* get exp lo digit */ -MM (ad); -if ((M[ad] & FLAG) == 0) /* no flag on hi exp? */ - return STOP_FPMF; -d1 = M[ad] & DIGIT; /* get exp hi digit */ -MM (ad); -fp->addr = ad; /* save mant addr */ -if (BAD_DIGIT (d1) || BAD_DIGIT (d0)) /* exp bad dig? */ - return STOP_INVDIG; -fp->exp = ((d1 * 10) + d0) * (esign? -1: 1); /* convert exponent */ -fp->sign = (M[ad] & FLAG)? 1: 0; /* get mantissa sign */ -return fp_scan_mant (fp->addr, &(fp->lnt), &(fp->zero)); -} - -/* Unpack and validate source and destination arguments */ - -t_stat fp_unpack_two (uint32 dad, uint32 sad, FPA *dfp, FPA *sfp) -{ -t_stat r; - -if ((r = fp_unpack (dad, dfp)) != SCPE_OK) /* unpack dst */ - return r; -if ((r = fp_unpack (sad, sfp)) != SCPE_OK) /* unpack src */ - return r; -if (sfp->lnt != dfp->lnt) /* lnts must be equal */ - return STOP_FPUNL; -return SCPE_OK; -} - -/* Pack floating point result */ - -t_stat fp_pack (FPA *fp) -{ -int32 e; -uint32 i, mad; - -e = (fp->exp >= 0)? fp->exp: -fp->exp; /* get |exp| */ -if (e > FP_EMAX) { /* too big? */ - ind[IN_EXPCHK] = 1; /* set indicator */ - if (fp->exp < 0) /* underflow? */ - return fp_zero (fp); - mad = fp->addr; - for (i = 0; i < fp->lnt; i++) { /* mant = 99...99 */ - M[mad] = (M[mad] & FLAG) | 9; - MM (mad); - } - e = FP_EMAX; /* cap at max */ - } -M[ADDR_A (fp->addr, 1)] = (e / 10) | FLAG; /* high exp digit */ -M[ADDR_A (fp->addr, 2)] = (e % 10) | /* low exp digit */ - ((fp->exp < 0)? FLAG: 0); -return SCPE_OK; -} - -/* Shift mantissa right n positions */ - -void fp_rsh (FPA *fp, uint32 n) -{ -uint32 i, sad, dad; - -if (n == 0) /* zero? done */ - return; -sad = ADDR_S (fp->addr, n); /* src = addr - n */ -dad = fp->addr; /* dst = n */ -for (i = 0; i < fp->lnt; i++) { /* move digits */ - if (i >= (fp->lnt - n)) - M[dad] = M[dad] & FLAG; - else M[dad] = (M[dad] & FLAG) | (M[sad] & DIGIT); - MM (dad); - MM (sad); - } -return; -} - -/* Shift mantissa left 1 position */ - -void fp_lsh_1 (FPA *fp) -{ -uint32 i, mad, nxt; - -mad = ADDR_S (fp->addr, fp->lnt - 1); /* hi order digit */ -for (i = 0; i < (fp->lnt - 1); i++) { /* move lnt-1 digits */ - nxt = ADDR_A (mad, 1); - M[mad] = (M[mad] & FLAG) | (M[nxt] & DIGIT); - mad = nxt; - } -M[mad] = M[mad] & FLAG; /* clear last digit */ -return; -} - -/* Clear floating point number */ - -t_stat fp_zero (FPA *fp) -{ -uint32 i, mad = fp->addr; - -for (i = 0; i < fp->lnt; i++) { /* clear mantissa */ - M[mad] = (i? M[mad] & FLAG: 0); /* clear sign bit */ - MM (mad); - } -M[ADDR_A (fp->addr, 1)] = FLAG + 9; /* exp = -99 */ -M[ADDR_A (fp->addr, 2)] = FLAG + 9; /* exp = -99 */ -ind[IN_EZ] = 1; /* result = 0 */ -ind[IN_HP] = 0; -return SCPE_OK; -} - -/* Scan floating point mantissa for length and (optionally) zero */ - -t_stat fp_scan_mant (uint32 ad, uint32 *lnt, uint32 *zro) -{ -uint8 d, l, z; - -z = 1; /* assume zero */ -for (l = 1; l <= FP_LMAX; l++) { /* scan to get length */ - d = M[ad] & DIGIT; /* get mant digit */ - if (d) /* non-zero? */ - z = 0; - if ((l != 1) && (M[ad] & FLAG)) { /* flag past first dig? */ - *lnt = l; /* set returns */ - if (zro) - *zro = z; - return SCPE_OK; - } - MM (ad); - } -return STOP_FPLNT; /* too long */ -} - -/* Copy floating point mantissa */ - -void fp_copy_mant (uint32 d, uint32 s, uint32 l) -{ -uint32 i; - -if (ind[IN_HP]) /* clr/set sign */ - M[d] = M[d] & ~FLAG; -else M[d] = M[d] | FLAG; -for (i = 0; i < l; i++) { /* copy src */ - M[d] = (M[d] & FLAG) | (M[s] & DIGIT); /* preserve flags */ - MM (d); - MM (s); - } -return; -} - -/* Compare floating point mantissa */ - -int32 fp_comp_mant (uint32 d, uint32 s, uint32 l) -{ -uint8 i, dd, sd; - -d = ADDR_S (d, l - 1); /* start of mantissa */ -s = ADDR_S (s, l - 1); -for (i = 0; i < l; i++) { /* compare dst:src */ - dd = M[d] & DIGIT; /* get dst digit */ - sd = M[s] & DIGIT; /* get src digit */ - if (dd > sd) /* >? done */ - return 1; - if (dd < sd) /* = ((int32) dfp.lnt))) { /* src = 0, or too small? */ - if (dfp.zero) /* res = dst, zero? */ - return fp_zero (&dfp); - ind[IN_EZ] = 0; /* res nz, set EZ, HP */ - ind[IN_HP] = (dfp.sign == 0); - return SCPE_OK; - } -if (dfp.zero || (dif <= -((int32) dfp.lnt))) { /* dst = 0, or too small? */ - if (sfp.zero) /* res = src, zero? */ - return fp_zero (&dfp); - r = xmt_field (d, s, 3); /* copy src to dst */ - ind[IN_EZ] = 0; /* res nz, set EZ, HP */ - ind[IN_HP] = (dfp.sign == 0); - return r; - } - -if (dif > 0) { /* dst exp > src exp? */ - sad = sfp.addr; /* save src in save area */ - for (i = 0; i < sfp.lnt; i++) { - sav_src[i] = M[sad]; - MM (sad); - } - fp_rsh (&sfp, dif); /* denormalize src */ - } -else if (dif < 0) { /* dst exp < src exp? */ - dfp.exp = sfp.exp; /* res exp = src exp */ - fp_rsh (&dfp, -dif); /* denormalize dst */ - } -r = add_field (dfp.addr, sfp.addr, sub, 0, &sta); /* add mant, set EZ, HP */ -if (dif > 0) { /* src denormalized? */ - sad = sfp.addr; /* restore src from */ - for (i = 0; i < sfp.lnt; i++) { /* save area */ - M[sad] = sav_src[i]; - MM (sad); - } - } -if (r != SCPE_OK) /* add error? */ - return r; - -hi = ADDR_S (dfp.addr, dfp.lnt - 1); /* addr of hi digit */ -if (sta == ADD_CARRY) { /* carry out? */ - fp_rsh (&dfp, 1); /* shift mantissa */ - M[hi] = FLAG + 1; /* high order 1 */ - dfp.exp = dfp.exp + 1; - ind[IN_EZ] = 0; /* not zero */ - ind[IN_HP] = (dfp.sign == 0); /* set HP */ - } -else if (ind[IN_EZ]) /* result zero? */ - return fp_zero (&dfp); -else { - while ((M[hi] & DIGIT) == 0) { /* until normalized */ - fp_lsh_1 (&dfp); /* left shift */ - dfp.exp = dfp.exp - 1; /* decr exponent */ - } - } - -return fp_pack (&dfp); /* pack and exit */ -} - -/* Floating point multiply */ - -t_stat fp_mul (uint32 d, uint32 s) -{ -FPA sfp, dfp; -uint32 pad; -t_stat r; - -r = fp_unpack_two (d, s, &dfp, &sfp); /* unpack operands */ -if (r != SCPE_OK) /* error? */ - return r; -if (sfp.zero || dfp.zero) /* either zero? */ - return fp_zero (&dfp); - -r = mul_field (dfp.addr, sfp.addr); /* mul, set EZ, HP */ -if (r != SCPE_OK) - return r; -if (M[ADDR_S (PROD_AREA_END, 2 * dfp.lnt)] & DIGIT) { /* hi prod dig set? */ - pad = ADDR_S (PROD_AREA_END - 1, dfp.lnt); /* no normalization */ - dfp.exp = dfp.exp + sfp.exp; /* res exp = sum */ - } -else { - pad = ADDR_S (PROD_AREA_END, dfp.lnt); /* 'normalize' 1 */ - dfp.exp = dfp.exp + sfp.exp - 1; /* res exp = sum - 1 */ - } -fp_copy_mant (dfp.addr, pad, dfp.lnt); /* copy prod to mant */ - -return fp_pack (&dfp); /* pack and exit */ -} - -/* Floating point divide */ - -t_stat fp_div (uint32 d, uint32 s) -{ -FPA sfp, dfp; -uint32 i, pad, a100ml, a99ml; -int32 ez; -t_stat r; - -r = fp_unpack_two (d, s, &dfp, &sfp); /* unpack operands */ -if (r != SCPE_OK) /* error? */ - return r; -if (sfp.zero) { /* divide by zero? */ - ind[IN_OVF] = 1; /* dead jim */ - return SCPE_OK; - } -if (dfp.zero) /* divide into zero? */ - return fp_zero (&dfp); - -for (i = 0; i < PROD_AREA_LEN; i++) /* clear prod area */ - M[PROD_AREA + i] = 0; -a100ml = ADDR_S (PROD_AREA_END, dfp.lnt); /* 100 - lnt */ -a99ml = ADDR_S (PROD_AREA_END - 1, dfp.lnt); /* 99 - lnt */ -if (fp_comp_mant (dfp.addr, sfp.addr, dfp.lnt) >= 0) { /* |Mdst| >= |Msrc|? */ - pad = a100ml; - dfp.exp = dfp.exp - sfp.exp + 1; /* res exp = diff + 1 */ - } -else { - pad = a99ml; - dfp.exp = dfp.exp - sfp.exp; /* res exp = diff */ - } -r = xmt_divd (pad, dfp.addr); /* xmt dividend */ -if (r != SCPE_OK) /* error? */ - return r; -r = div_field (a100ml, sfp.addr, &ez); /* divide fractions */ -if (r != SCPE_OK) /* error? */ - return r; -if (ez) /* result zero? */ - return fp_zero (&dfp); - -ind[IN_HP] = ((dfp.sign ^ sfp.sign) == 0); /* set res sign */ -ind[IN_EZ] = 0; /* not zero */ -fp_copy_mant (dfp.addr, a99ml, dfp.lnt); /* copy result */ - -return fp_pack (&dfp); -} - -/* Floating shift right */ - -t_stat fp_fsr (uint32 d, uint32 s) -{ -uint32 cnt; -uint8 t; - -if (d == s) /* no move? */ - return SCPE_OK; - -cnt = 0; -M[d] = (M[d] & FLAG) | (M[s] & DIGIT); /* move 1st wo flag */ -do { - MM (d); /* decr ptrs */ - MM (s); - t = M[d] = M[s] & (FLAG | DIGIT); /* copy others */ - if (cnt++ > MEMSIZE) /* (stop runaway) */ - return STOP_FWRAP; - } while ((t & FLAG) == 0); /* until src flag */ - -cnt = 0; -do { - MM (d); /* decr pointer */ - t = M[d]; /* save old val */ - M[d] = 0; /* zero field */ - if (cnt++ > MEMSIZE) /* (stop runaway) */ - return STOP_FWRAP; - } while ((t & FLAG) == 0); /* until dst flag */ -return SCPE_OK; -} - -/* Floating shift left - note that dst is addr of high order digit */ - -t_stat fp_fsl (uint32 d, uint32 s) -{ -uint32 i, lnt; -uint8 sign; -t_stat r; - -if (d == s) - return SCPE_OK; -sign = M[s] & FLAG; /* get src sign */ -r = fp_scan_mant (s, &lnt, NULL); /* get src length */ -if (r != SCPE_OK) /* error? */ - return r; -s = ADDR_S (s, lnt - 1); /* hi order src */ -M[d] = M[s] & (FLAG | DIGIT); /* move 1st w flag */ -M[s] = M[s] & ~FLAG; /* clr flag from src */ -for (i = 1; i < lnt; i++) { /* move src to dst */ - PP (d); /* incr ptrs */ - PP (s); - M[d] = M[s] & DIGIT; /* move just digit */ - } -PP (d); /* incr pointer */ -while ((M[d] & FLAG) == 0) { /* until flag */ - M[d] = 0; /* clear field */ - PP (d); - } -if (sign) /* -? zero under sign */ - M[d] = FLAG; -return SCPE_OK; -} diff --git a/I1620/i1620_lp.c b/I1620/i1620_lp.c deleted file mode 100644 index ead1025c..00000000 --- a/I1620/i1620_lp.c +++ /dev/null @@ -1,401 +0,0 @@ -/* i1620_lp.c: IBM 1443 line printer simulator - - Copyright (c) 2002-2017, Robert M. Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - lpt 1443 line printer - - 15-Jun-17 RMS Fixed K constants and print-no-spacing (Tom McBride) - Added option to emulate form feed with newlines - 31-Jan-15 TFM Fixed various problems ... see comments in code - 10-Dec-13 RMS Fixed DN wraparound (Bob Armstrong) - Fixed test on VFU 10 (Bob Armstrong) - 19-Jan-07 RMS Added UNIT_TEXT flag - 21-Sep-05 RMS Revised translation tables for 7094/1401 compatibility - 29-Dec-03 RMS Fixed bug in scheduling - 25-Apr-03 RMS Revised for extended file support -*/ - -#include "i1620_defs.h" - -#define LPT_BSIZE 197 /* buffer size */ -#define UNIT_V_FF (UNIT_V_UF + 0) -#define UNIT_FF (1 << UNIT_V_FF) - -/* decoded print control */ - -#define K_IMM 0x10 /* before print */ -#define K_LIN 0x20 /* spc lines */ -#define K_LCNT 0x03 /* line count */ -#define K_CHAN 0x0F /* channel */ - -extern uint8 M[MAXMEMSIZE]; -extern uint8 ind[NUM_IND]; -extern UNIT cpu_unit; -extern uint32 io_stop; - -uint32 cct[CCT_LNT] = { 03 }; /* car ctrl tape */ -int32 cct_lnt = 66, cct_ptr = 0; /* cct len, ptr */ -int32 lpt_bptr = 0; /* lpt buf ptr */ -char lpt_buf[LPT_BSIZE + 1]; /* lpt buf */ -int32 lpt_savctrl = 0; /* saved spc ctrl */ - -t_stat lpt_svc (UNIT *uptr); -t_stat lpt_reset (DEVICE *dptr); -t_stat lpt_attach (UNIT *uptr, char *cptr); -void lpt_buf_init (void); -t_stat lpt_num(uint32 pa, uint32 f1, t_bool dump); -t_stat lpt_print (uint32 flag); -t_stat lpt_spcop (int32 ctrl); -t_stat lpt_space (int32 lines, int32 lflag); - -#define CHP(ch,val) ((val) & (1 << (ch))) - -/* LPT data structures - - lpt_dev LPT device descriptor - lpt_unit LPT unit descriptor - lpt_reg LPT register list -*/ - -UNIT lpt_unit = { - UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 50) - }; - -REG lpt_reg[] = { - { BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE + 1) }, - { DRDATA (BPTR, lpt_bptr, 8) }, - { HRDATA (PCTL, lpt_savctrl, 6) }, - { FLDATA (PRCHK, ind[IN_PRCHK], 0) }, - { FLDATA (PRCH9, ind[IN_PRCH9], 0) }, - { FLDATA (PRCH12, ind[IN_PRCH12], 0) }, - { FLDATA (PRBSY, ind[IN_PRBSY], 0) }, - { DRDATA (POS, lpt_unit.pos, T_ADDR_W), PV_LEFT }, - { BRDATA (CCT, cct, 8, 32, CCT_LNT) }, - { DRDATA (CCTP, cct_ptr, 8), PV_LEFT }, - { DRDATA (CCTL, cct_lnt, 8), REG_RO + PV_LEFT }, - { NULL } - }; - -MTAB lp_mod[] = { - { UNIT_FF, 0, "no form feeds", "NOFF", NULL }, - { UNIT_FF, UNIT_FF, "form feeds", "FF", NULL }, - { 0 } - }; - -DEVICE lpt_dev = { - "LPT", &lpt_unit, lpt_reg, lp_mod, - 1, 10, 31, 1, 8, 7, - NULL, NULL, &lpt_reset, - NULL, &lpt_attach, NULL - }; - -/* Data tables */ - -/* Numeric (flag plus digit) to lineprinter (ASCII) */ - -const int8 num_to_lpt[32] = { - '0', '1', '2', '3', '4', '5', '6', '7', /* All invalid char treated as errors */ - '8', '9', '|', -1, '@', -1, -1, 'G', /* @, G only print on DN; else NB is blank */ - '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 'W', -1, '*', -1, -1, 'X' /* W, *, X only print on DN */ - }; - -/* Alphameric (digit pair) to lineprinter (ASCII) */ - -const int8 alp_to_lpt[256] = { /* tfm: invalid codes 02, 12, 15, 32, 35, 61 removed */ - ' ', -1, -1, '.', ')', -1, -1, -1, /* 00 */ - -1, -1, -1, -1, -1, -1, -1, -1, - '+', -1, -1, '$', '*', -1, -1, -1, /* 10 */ - -1, -1, -1, -1, -1, -1, -1, -1, - '-', '/', '|', ',', '(', -1, -1, -1, /* 20 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, '=', '@', -1, -1, -1, /* 30 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 40 */ - 'H', 'I', -1, -1, -1, -1, -1, -1, - '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 50 */ - 'Q', 'R', -1, -1, -1, -1, -1, -1, - -1, -1, 'S', 'T', 'U', 'V', 'W', 'X', /* 60 */ - 'Y', 'Z', -1, -1, -1, -1, -1, -1, - '0', '1', '2', '3', '4', '5', '6', '7', /* 70 */ - '8', '9', -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* 90 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* A0 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* B0 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* C0 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* D0 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* E0 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* F0 */ - -1, -1, -1, -1, -1, -1, -1, -1 - }; - -/* K validation and translation table - entryies 80:FF always 0 */ - -static const int8 lpt_ktbl[128] = { - 0, 0, 0, 11, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 */ - 0, K_LIN|1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 20 */ - 0, 0, 0, K_IMM|11, K_IMM|12, 0, 0, 0, 0, 0, /* 30 */ - 0, 0, 0, 0, 0, 0, - 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 40 */ - 0, K_IMM|K_LIN|1, K_IMM|K_LIN|2, K_IMM|K_LIN|3, 0, /* 50 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, K_LIN|2, K_LIN|3, 0, 0, 0, 0, 0, 0, /* 60 */ - 0, 0, 0, 0, 0, 0, - K_IMM|10, K_IMM|1, K_IMM|2, K_IMM|3, K_IMM|4, /* 70 */ - K_IMM|5, K_IMM|6, K_IMM|7, K_IMM|8, K_IMM|9, - 0, 0, 0, 0, 0, 0, - }; - -/* Line printer IO routine - - - Hard errors halt the system. - - Invalid characters print a blank, set the WRCHK and PRCHK - flags, and halt the system if IO stop is set. -*/ - -t_stat lpt (uint32 op, uint32 pa, uint32 f0, uint32 f1) -{ -int8 lpc; -uint8 z, d; -int32 ctrl; -t_stat r, sta; - -sta = SCPE_OK; -sim_cancel (&lpt_unit); /* "stall" until */ -ind[IN_PRBSY] = 0; /* printer free */ - -switch (op) { /* decode op */ - - case OP_K: /* control */ - ctrl = lpt_ktbl[((f0 & 0x7) << 4) | (f1 & 0xF)]; /* xlate ctrl */ - if ((f0 > 7) || (ctrl == 0)) { /* invalid? */ - ind[IN_PRCHK] = 1; /* print chk */ - if (io_stop) /* set return status */ - sta = STOP_INVFNC; - } - else { - if ((ctrl & K_IMM) != 0) /* immediate? */ - return lpt_spcop (ctrl); /* execute */ - else lpt_savctrl = ctrl; /* otherwise, save */ - } - return sta; - - case OP_DN: - return lpt_num (pa, f1, TRUE); /* dump numeric */ - - case OP_WN: - return lpt_num (pa, f1, FALSE); /* write numeric */ - - case OP_WA: - for ( ; lpt_bptr < LPT_BSIZE; lpt_bptr++) { /* only fill buf */ - d = M[pa] & DIGIT; /* get digit */ - z = M[pa - 1] & DIGIT; /* get zone */ - if ((d & REC_MARK) == REC_MARK) /* 8-2 char? */ - break; - lpc = alp_to_lpt[(z << 4) | d]; /* translate pair */ - if (lpc < 0) { /* bad char? */ - ind[IN_WRCHK] = ind[IN_PRCHK] = 1; /* wr chk */ - if (io_stop) /* set return status */ - sta = STOP_INVCHR; - } - lpt_buf[lpt_bptr] = lpc & 0x7F; /* fill buffer */ - pa = ADDR_A (pa, 2); /* incr mem addr */ - } - r = lpt_print (f1); /* print line */ - if (r != SCPE_OK) - return r; - return sta; - - default: /* invalid function */ - return STOP_INVFNC; - } - -return SCPE_OK; -} - -/* Print numeric */ - -t_stat lpt_num (uint32 pa, uint32 f1, t_bool dump) -{ -uint8 d; -int8 lpc; -t_stat r, sta; - -sta = SCPE_OK; -for ( ; lpt_bptr < LPT_BSIZE; lpt_bptr++) { /* only fill buf */ - d = M[pa]; /* get data char */ - if (!dump && /* not dumping? */ - ((d & REC_MARK) == REC_MARK)) /* quit on RM or GM */ - break; - lpc = num_to_lpt[d]; /* translate digit */ - if (!dump && /* if not dumping */ - ((d & DIGIT) == NUM_BLANK)) /* translate numeric blank */ - lpc = ' '; /* to normal space */ - if (lpc < 0) { /* bad char? */ - ind[IN_WRCHK] = ind[IN_PRCHK] = 1; /* wr chk */ - if (io_stop) /* set return status */ - sta = STOP_INVCHR; - } - lpt_buf[lpt_bptr] = lpc & 0x7F; /* put char into buffer (tfm: correct increment)*/ - PP (pa); /* incr mem addr */ - } -r = lpt_print (f1); /* print line */ -if (r != SCPE_OK) - return r; -return sta; -} - -/* Print and possibly space - any spacing operation is non-immediate */ - -t_stat lpt_print (uint32 flag) -{ -int32 i; - -if ((lpt_unit.flags & UNIT_ATT) == 0) { /* not attached? */ - ind[IN_PRCHK] = 1; /* pri check */ - return SCPE_UNATT; - } - -for (i = LPT_WIDTH; i <= LPT_BSIZE; i++) /* clear unprintable */ - lpt_buf[i] = ' '; -while ((lpt_bptr > 0) && (lpt_buf[lpt_bptr - 1] == ' ')) - lpt_buf[--lpt_bptr] = 0; /* trim buffer */ -if (lpt_bptr != 0) { /* any line? */ - fputs (lpt_buf, lpt_unit.fileref); /* print */ - if ((flag & 1) != 0) /* no space? */ - fputc ('\r', lpt_unit.fileref); /* bare return */ - lpt_unit.pos = ftell (lpt_unit.fileref); /* update pos */ - lpt_buf_init (); /* reinit buf */ - if (ferror (lpt_unit.fileref)) { /* error? */ - ind[IN_PRCHK] = 1; /* pri check */ - sim_perror ("LPT I/O error"); - clearerr (lpt_unit.fileref); - return SCPE_IOERR; - } - } -if ((flag & 1) == 0) /* spacing? */ - return lpt_spcop (lpt_savctrl); /* execute */ -return SCPE_OK; /* done */ -} - -/* Space operation - direct (K) or deferred (WA, WN, DN) */ - -t_stat lpt_spcop (int32 ctrl) -{ -int32 chan, i; - -lpt_savctrl = K_LIN|1; /* reset saved control */ -if ((ctrl & K_LIN) != 0) /* space lines? */ - return lpt_space (ctrl & K_LCNT, FALSE); /* execute spacing op */ -chan = lpt_savctrl & K_CHAN; /* get chan */ -if ((chan == 0) || (chan > 12)) - return STOP_INVFNC; -for (i = 1; i < cct_lnt + 1; i++) { /* sweep thru cct */ - if (CHP (chan, cct[(cct_ptr + i) % cct_lnt])) - return lpt_space (i, TRUE); - } -return STOP_CCT; /* runaway channel */ -} - -/* Space routine - space or skip n lines - - Inputs: - count = number of lines to space or skip - sflag = skip (TRUE) or space (FALSE) -*/ - -t_stat lpt_space (int32 count, int32 sflag) -{ -int32 i; - -cct_ptr = (cct_ptr + count) % cct_lnt; /* adv cct, mod lnt */ -if (sflag && CHP (0, cct[cct_ptr]) && /* skip, top of form, */ - ((lpt_unit.flags & UNIT_FF) != 0)) /* and use form feeds? */ - fputs ("\n\f", lpt_unit.fileref); /* nl, ff */ -else { - for (i = 0; i < count; i++) /* count lines */ - fputc ('\n', lpt_unit.fileref); - } -lpt_unit.pos = ftell (lpt_unit.fileref); /* update position */ -ind[IN_PRCH9] = CHP (9, cct[cct_ptr]) != 0; /* set indicators */ -ind[IN_PRCH12] = CHP (12, cct[cct_ptr]) != 0; -if (ferror (lpt_unit.fileref)) { /* error? */ - ind[IN_PRCHK] = ind[IN_WRCHK] = 1; /* wr, pri check */ - sim_perror ("LPT I/O error"); - clearerr (lpt_unit.fileref); - return SCPE_IOERR; - } -ind[IN_PRBSY] = 1; /* print busy */ -sim_activate (&lpt_unit, lpt_unit.wait); /* start timer */ -return SCPE_OK; -} - -/* Unit service - clear printer busy */ - -t_stat lpt_svc (UNIT *uptr) -{ -ind[IN_PRBSY] = 0; -return SCPE_OK; -} - -/* Initialize lpt buffer */ - -void lpt_buf_init (void) -{ -int32 i; - -lpt_bptr = 0; -for (i = 0; i < LPT_WIDTH + 1; i++) - lpt_buf[i] = 0; -return; -} - -/* Reset routine */ - -t_stat lpt_reset (DEVICE *dptr) -{ -lpt_buf_init (); /* clear buffer */ -cct_ptr = 0; /* clear cct ptr */ -lpt_savctrl = K_LIN|1; /* reset cct action */ -ind[IN_PRCHK] = ind[IN_PRBSY] = 0; /* clear indicators */ -ind[IN_PRCH9] = ind[IN_PRCH12] = 0; -return SCPE_OK; -} - -/* Attach routine */ - -t_stat lpt_attach (UNIT *uptr, char *cptr) -{ -lpt_reset (&lpt_dev); -return attach_unit (uptr, cptr); -} diff --git a/I1620/i1620_pt.c b/I1620/i1620_pt.c deleted file mode 100644 index d29e9189..00000000 --- a/I1620/i1620_pt.c +++ /dev/null @@ -1,520 +0,0 @@ -/* i1620_pt.c: IBM 1621/1624 paper tape reader/punch simulator - - Copyright (c) 2002-2017, Robert M Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - ptr 1621 paper tape reader - ptp 1624 paper tape punch - - 23-Jun-17 RMS PTR/PTP errors does not set read check - 10-Jun-17 RMS Fixed typo in PTP unit (Dave Wise) - 26-May-17 RMS Added deferred IO - 25-May-17 RMS Fixed treatment of X0C82 on RN (Tom McBride) - 18-May-17 RMS Separated EOF error from other IO errors (Dave Wise) - 23-Feb-15 TFM Fixed RA, RBPT to preserve flags on RM at end (Tom McBride) - 09-Feb-15 TFM Fixed numerous translation problems (Tom McBride) - 09-Feb-15 TFM Fixed pack/unpack errors in binary r/w (Tom McBride) - 21-Dec-13 RMS Fixed translation of paper tape code X0C - 10-Dec-13 RMS Fixed DN wraparound (Bob Armstrong) - 19-Mar-12 RMS Fixed declaration of io_stop (Mark Pizzolato) - 21-Sep-05 RMS Revised translation tables for 7094/1401 compatibility - 25-Apr-03 RMS Revised for extended file support -*/ - -#include "i1620_defs.h" - -#define PT_EL 0x80 /* end record */ -#define PT_X 0x40 /* X */ -#define PT_O 0x20 /* O */ -#define PT_C 0x10 /* C */ -#define PT_FD 0x7F /* deleted */ - -static uint32 ptr_mode = 0; /* normal/binary */ -static uint32 ptp_mode = 0; - -extern uint8 M[MAXMEMSIZE]; -extern uint8 ind[NUM_IND]; -extern UNIT cpu_unit; -extern uint32 io_stop; -extern uint32 PAR, cpuio_opc, cpuio_cnt; - -t_stat ptr_svc (UNIT *uptr); -t_stat ptr_reset (DEVICE *dptr); -t_stat ptr_boot (int32 unitno, DEVICE *dptr); -t_stat ptr_read (uint8 *c, t_bool ignfeed); -t_stat ptp_svc (UNIT *uptr); -t_stat ptp_reset (DEVICE *dptr); -t_stat ptp_write (uint32 c); -t_stat ptp_num (void); - -/* PTR data structures - - ptr_dev PTR device descriptor - ptr_unit PTR unit descriptor - ptr_reg PTR register list -*/ - -UNIT ptr_unit = { - UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), SERIAL_IN_WAIT - }; - -REG ptr_reg[] = { - { FLDATA (BIN, ptr_mode, 0) }, - { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, - { NULL } - }; - -DEVICE ptr_dev = { - "PTR", &ptr_unit, ptr_reg, NULL, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ptr_reset, - &ptr_boot, NULL, NULL, - NULL, DEV_DEFIO - }; - -/* PTP data structures - - ptp_dev PTP device descriptor - ptp_unit PTP unit descriptor - ptp_reg PTP register list -*/ - -UNIT ptp_unit = { - UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT - }; - -REG ptp_reg[] = { - { FLDATA (BIN, ptp_mode, 0) }, - { DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, - { NULL } - }; - -DEVICE ptp_dev = { - "PTP", &ptp_unit, ptp_reg, NULL, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ptp_reset, - NULL, NULL, NULL, - NULL, DEV_DEFIO - }; - -/* Data tables */ - -/* Paper tape reader odd parity chart: 1 = bad, 0 = ok */ - -const int8 bad_par[128] = { - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 00 */ - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 10 */ - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 20 */ - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 30 */ - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, /* 40 */ - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 50 */ - 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, /* 60 */ - 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0 /* 70 */ - }; - -/* Paper tape read (7b) to numeric (one digit) */ - -const int8 ptr_to_num[128] = { - -1, 0x01, 0x02, -1, 0x04, -1, -1, 0x07, /* - */ - 0x08, -1, -1, 0x0B, -1, -1, -1, -1, - 0x00, -1, -1, 0x03, -1, 0x05, 0x06, -1, /* C */ - -1, 0x09, -1, -1, 0x0C, -1, -1, -1, - 0x00, -1, -1, 0x03, -1, 0x05, 0x06, -1, /* O */ - -1, 0x09, 0x0A, -1, 0x0C, -1, -1, 0x0F, - -1, 0x01, 0x02, -1, 0x04, -1, -1, 0x07, /* OC */ - 0x08, -1, -1, 0x0B, -1, -1, -1, -1, - 0x10, -1, -1, 0x13, -1, 0x15, 0x16, -1, /* X */ - -1, 0x19, 0x1A, -1, 0x1C, -1, -1, 0x1F, - -1, 0x11, 0x12, -1, 0x14, -1, -1, 0x17, /* XC */ - 0x18, -1, -1, 0x1B, -1, -1, -1, -1, - -1, 0x01, 0x02, -1, 0x04, -1, -1, 0x07, /* XO */ - 0x08, -1, -1, 0x0B, -1, -1, -1, -1, - 0x10, -1, -1, 0x03, -1, 0x05, 0x06, -1, /* XOC */ - -1, 0x09, 0x1A, -1, 0x0C, -1, -1, -1 /* X0C82 treated as flagged RM, RN only (tfm) */ - }; - -/* Paper tape read (7b) to alphameric (two digits) */ - -const int8 ptr_to_alp[128] = { - 0x00, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* - */ - 0x78, 0x79, -1, 0x33, 0x34, -1, -1, -1, - 0x00, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* C */ - 0x78, 0x79, -1, 0x33, 0x34, -1, -1, -1, - 0x70, 0x21, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* O */ - 0x68, 0x69, 0x0A, 0x23, 0x24, -1, -1, 0x0F, - 0x70, 0x21, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, /* OC */ - 0x68, 0x69, 0x0A, 0x23, 0x24, -1, -1, 0x0F, - 0x20, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* X */ - 0x58, 0x59, 0x5A, 0x13, 0x14, -1, -1, 0x5F, - 0x20, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, /* XC */ - 0x58, 0x59, 0x5A, 0x13, 0x14, -1, -1, 0x5F, - 0x10, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* XO */ - 0x48, 0x49, -1, 0x03, 0x04, -1, -1, -1, - 0x10, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* XOC */ - 0x48, 0x49, -1, 0x03, 0x04, -1, -1, -1 - }; - -/* Numeric (flag + digit) to paper tape punch */ - -const int8 num_to_ptp[32] = { - 0x20, 0x01, 0x02, 0x13, 0x04, 0x15, 0x16, 0x07, /* 0 */ - 0x08, 0x19, 0x2A, -1, 0x1C, -1, -1, 0x2F, - 0x40, 0x51, 0x52, 0x43, 0x54, 0x45, 0x46, 0x57, /* F + 0 */ - 0x58, 0x49, 0x4A, -1, 0x4C, -1, -1, 0x4F - }; - -/* Alphameric (two digits) to paper tape punch */ - -const int8 alp_to_ptp[256] = { - 0x10, -1, -1, 0x6B, 0x7C, -1, -1, -1, /* 00 */ - -1, -1, -1, -1, -1, -1, -1, -1, - 0x70, -1, -1, 0x5B, 0x4C, -1, -1, -1, /* 10 */ - -1, -1, -1, -1, -1, -1, -1, -1, - 0x40, 0x31, -1, 0x3B, 0x2C, -1, -1, -1, /* 20 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, 0x0B, 0x1C, -1, -1, -1, /* 30 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, 0x61, 0x62, 0x73, 0x64, 0x75, 0x76, 0x67, /* 40 */ - 0x68, 0x79, -1, -1, -1, -1, -1, -1, - 0x40, 0x51, 0x52, 0x43, 0x54, 0x45, 0x46, 0x57, /* 50 */ - 0x58, 0x49, -1, -1, -1, -1, -1, -1, - -1, -1, 0x32, 0x23, 0x34, 0x25, 0x26, 0x37, /* 60 */ - 0x38, 0x29, -1, -1, -1, -1, -1, -1, - 0x20, 0x01, 0x02, 0x13, 0x04, 0x15, 0x16, 0x07, /* 70 */ - 0x08, 0x19, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* 90 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* A0 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* B0 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* C0 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* D0 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* E0 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* F0 */ - -1, -1, -1, -1, -1, -1, -1, -1 - }; - -/* Paper tape reader IO init routine */ - -t_stat ptr (uint32 op, uint32 pa, uint32 f0, uint32 f1) -{ -if ((op != OP_RN) && (op != OP_RA)) /* RN & RA only */ - return STOP_INVFNC; -if ((ptr_unit.flags & UNIT_ATT) == 0) /* catch unattached */ - return SCPE_UNATT; -ptr_mode = 0; -cpuio_set_inp (op, IO_PTR, &ptr_unit); -return SCPE_OK; -} - -/* Binary paper tape reader IO init routine */ - -t_stat btr (uint32 op, uint32 pa, uint32 f0, uint32 f1) -{ -if (op != OP_RA) /* RA only */ - return STOP_INVFNC; -if ((ptr_unit.flags & UNIT_ATT) == 0) /* catch unattached */ - return SCPE_UNATT; -ptr_mode = 1; -cpuio_set_inp (op, IO_BTR, &ptr_unit); -return SCPE_OK; -} - -/* Paper tape unit service - - - If over the limit, cancel IO and return error. - - If unattached, reschedule and return error. - - Transfer a digit/character. - - Hard errors halt the operation and the system. - - Parity errors place an invalid character in memory and set - RDCHK, but the read continues until end of record. If IO - stop is set, the system then halts. -*/ - -t_stat ptr_svc (UNIT *uptr) -{ -t_stat r; -uint8 ptc; -int8 mc; - -if (cpuio_cnt >= MEMSIZE) { /* over the limit? */ - cpuio_clr_inp (uptr); /* done */ - return STOP_RWRAP; - } -sim_activate (uptr, uptr->wait); /* sched another xfer */ -if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ - return SCPE_UNATT; - -switch (cpuio_opc) { - - case OP_RN: /* read numeric */ - r = ptr_read (&ptc, TRUE); /* read frame */ - if (r != SCPE_OK) /* error? */ - return r; - if (ptc & PT_EL) { /* end record? */ - M[PAR] = REC_MARK; /* store rec mark */ - break; - } - mc = ptr_to_num[ptc]; /* translate char */ - if ((bad_par[ptc]) || (mc < 0)) { /* bad par. or char? */ - ind[IN_RDCHK] = 1; /* set read check */ - mc = 0; /* store zero */ - } - M[PAR] = mc; /* store translated char */ - PP (PAR); /* incr mem addr */ - cpuio_cnt++; - return SCPE_OK; - - case OP_RA: /* read alphameric */ - r = ptr_read (&ptc, TRUE); /* read frame */ - if (r != SCPE_OK) /* error? */ - return r; - if (ptc & PT_EL) { /* end record? */ - M[PAR] = (M[PAR] & FLAG) | REC_MARK; /* store alpha RM */ - M[PAR - 1] = M[PAR - 1] & FLAG; /* and preserve flags */ - break; - } - if (ptr_mode == 0) { /* normal mode? */ - mc = ptr_to_alp[ptc]; /* translate */ - if (bad_par[ptc] || (mc < 0)) { /* bad par or char? */ - ind[IN_RDCHK] = 1; /* set read check */ - mc = 0; /* store blank */ - } - M[PAR] = (M[PAR] & FLAG) | (mc & DIGIT); /* store 2 digits */ - M[PAR - 1] = (M[PAR - 1] & FLAG) | ((mc >> 4) & DIGIT); - } - else { /* binary mode */ - if (bad_par[ptc]) /* bad parity? */ - ind[IN_RDCHK] = 1; /* set read check */ - M[PAR] = (M[PAR] & FLAG) | (ptc & 07); /* store 2 digits */ - M[PAR - 1] = (M[PAR - 1] & FLAG) | - (((ptc >> 4) & 06) | ((ptc >> 3) & 1)); - } - PAR = ADDR_A (PAR, 2); /* incr mem addr */ - cpuio_cnt = cpuio_cnt + 2; - return SCPE_OK; - - default: /* invalid function */ - break; - } - -/* IO is complete */ - -cpuio_clr_inp (uptr); /* clear IO in progress */ -if ((ind[IN_RDCHK] != 0) && (io_stop != 0)) /* parity error? */ - return STOP_INVCHR; -return SCPE_OK; -} - -/* Read ptr frame - all errors are 'hard' errors and halt the system */ - -t_stat ptr_read (uint8 *c, t_bool ignfeed) -{ -int32 temp; - -do { - if ((temp = getc (ptr_unit.fileref)) == EOF) { /* read char */ - if (feof (ptr_unit.fileref)) { /* EOF? */ - sim_printf ("PTR end of file\n"); - clearerr (ptr_unit.fileref); - return SCPE_EOF; - } - else sim_perror ("PTR I/O error"); /* no, io err */ - clearerr (ptr_unit.fileref); - return SCPE_IOERR; - } - *c = temp & 0377; /* save char */ - ptr_unit.pos = ptr_unit.pos + 1; /* incr file addr */ - } while (ignfeed && (*c == PT_FD)); /* until not feed */ -return SCPE_OK; -} - -/* Reset routine */ - -t_stat ptr_reset (DEVICE *dptr) -{ -sim_cancel (&ptr_unit); -ptr_mode = 0; -return SCPE_OK; -} - -/* Bootstrap routine */ - -static const uint8 boot_rom[] = { - 3, 6, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, /* RNPT 0 */ - }; - -#define BOOT_START 0 -#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint8)) - -t_stat ptr_boot (int32 unitno, DEVICE *dptr) -{ -size_t i; -extern uint32 saved_PC; - -for (i = 0; i < BOOT_LEN; i++) - M[BOOT_START + i] = boot_rom[i]; -saved_PC = BOOT_START; -return SCPE_OK; -} - -/* Paper tape punch IO init routine */ - -t_stat ptp (uint32 op, uint32 pa, uint32 f0, uint32 f1) -{ -if ((op != OP_WN) && (op != OP_WA) && (op != OP_DN)) - return STOP_INVFNC; -if ((ptp_unit.flags & UNIT_ATT) == 0) /* catch unattached */ - return SCPE_UNATT; -ptp_mode = 0; -cpuio_set_inp (op, IO_PTP, &ptp_unit); -return SCPE_OK; -} - -/* Binary paper tape punch IO init routine */ - -t_stat btp (uint32 op, uint32 pa, uint32 f0, uint32 f1) -{ -if (op != OP_WA) /* WA only */ - return STOP_INVFNC; -if ((ptp_unit.flags & UNIT_ATT) == 0) /* catch unattached */ - return SCPE_UNATT; -ptp_mode = 1; -cpuio_set_inp (op, IO_BTP, &ptp_unit); -return SCPE_OK; -} - -/* Paper tape punch unit service routine */ - -t_stat ptp_svc (UNIT *uptr) -{ -int8 ptc; -uint8 z, d; -t_stat r; - -if ((cpuio_opc != OP_DN) && (cpuio_cnt >= MEMSIZE)) { /* wrap, ~dump? */ - cpuio_clr_inp (uptr); /* done */ - return STOP_RWRAP; - } -sim_activate (uptr, uptr->wait); /* sched another xfer */ -if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ - return SCPE_UNATT; - -switch (cpuio_opc) { /* decode op */ - - case OP_DN: - if ((cpuio_cnt != 0) && ((PAR % 20000) == 0)) /* done? */ - break; - return ptp_num (); /* write numeric */ - - case OP_WN: - if ((M[PAR] & REC_MARK) == REC_MARK) /* end record? */ - break; - return ptp_num (); /* write numeric */ - - case OP_WA: - d = M[PAR] & DIGIT; /* get digit */ - z = M[PAR - 1] & DIGIT; /* get zone */ - if ((d & REC_MARK) == REC_MARK) /* 8-2 char? */ - break; /* end record */ - if (ptp_mode == 0) { /* normal mode */ - ptc = alp_to_ptp[(z << 4) | d]; /* translate pair */ - if (ptc < 0) { /* bad char? */ - ind[IN_WRCHK] = 1; /* write check */ - CRETIOE (io_stop, STOP_INVCHR); - } - } - else { /* binary mode */ - ptc = ((z & 06) << 4) | ((z & 01) << 3) | (d & 07); - if (bad_par[ptc]) /* set parity */ - ptc = ptc | PT_C; - } - r = ptp_write (ptc); /* write char */ - if (r != SCPE_OK) /* error? */ - return r; - PAR = ADDR_A (PAR, 2); /* incr mem addr */ - cpuio_cnt = cpuio_cnt + 2; - return SCPE_OK; - - default: /* invalid function */ - break; - } - -/* IO is complete */ - -ptp_write (PT_EL); /* write record mark */ -cpuio_clr_inp (uptr); /* IO complete */ -return SCPE_OK; -} - -/* Punch tape numeric - cannot generate parity errors */ - -t_stat ptp_num (void) -{ -t_stat r; -uint8 d; -int8 ptc; - -d = M[PAR] & (FLAG | DIGIT); /* get char */ -ptc = num_to_ptp[d]; /* translate digit */ -if (ptc < 0) { /* bad char? */ - ind[IN_WRCHK] = 1; /* write check */ - CRETIOE(io_stop, STOP_INVCHR); - } -r = ptp_write (ptc); /* write char */ -if (r != SCPE_OK) /* error? */ - return r; -PP (PAR); /* incr mem addr */ -cpuio_cnt++; -return SCPE_OK; -} - -/* Write ptp frame - all errors are hard errors */ - -t_stat ptp_write (uint32 c) -{ -if (putc (c, ptp_unit.fileref) == EOF) { /* write char */ - sim_perror ("PTP I/O error"); - clearerr (ptp_unit.fileref); - return SCPE_IOERR; - } -ptp_unit.pos = ptp_unit.pos + 1; /* count char */ -return SCPE_OK; -} - -/* Reset routine */ - -t_stat ptp_reset (DEVICE *dptr) -{ -sim_cancel (&ptp_unit); -ptp_mode = 0; -return SCPE_OK; -} diff --git a/I1620/i1620_sys.c b/I1620/i1620_sys.c deleted file mode 100644 index e91a2d6a..00000000 --- a/I1620/i1620_sys.c +++ /dev/null @@ -1,608 +0,0 @@ -/* i1620_sys.c: IBM 1620 simulator interface - - Copyright (c) 2002-2017, 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. - - 25-May-17 RMS Tweaks and corrections from Tom McBride - 18-May-17 RMS Changed fprint_val to handle undefined opcodes on stops - 19-Mar-12 RMS Fixed declaration of CCT (Mark Pizzolato) -*/ - -#include "i1620_defs.h" -#include - -#define LINE_LNT 50 - -extern DEVICE cpu_dev, tty_dev; -extern DEVICE ptr_dev, ptp_dev; -extern DEVICE lpt_dev; -extern DEVICE cdr_dev, cdp_dev; -extern DEVICE dp_dev; -extern UNIT cpu_unit; -extern REG cpu_reg[]; -extern uint8 M[MAXMEMSIZE]; -extern int8 cdr_to_alp[128], alp_to_cdp[256]; - -/* SCP data structures and interface routines - - sim_name simulator name string - sim_PC pointer to saved PC register descriptor - sim_emax maximum number of words for examine/deposit - sim_devices array of pointers to simulated devices - sim_stop_messages array of pointers to stop messages - sim_load binary loader -*/ - -char sim_name[] = "IBM 1620"; - -REG *sim_PC = &cpu_reg[0]; - -int32 sim_emax = LINE_LNT; - -DEVICE *sim_devices[] = { - &cpu_dev, - &tty_dev, - &ptr_dev, - &ptp_dev, - &cdr_dev, - &cdp_dev, - &lpt_dev, - &dp_dev, - NULL - }; - -const char *sim_stop_messages[] = { - "Unknown error", - "HALT instruction", - "Breakpoint", - "Invalid instruction", - "Invalid digit", - "Invalid character", - "Invalid indicator", - "Invalid digit in P address", - "Invalid P address", - "P address exceeds indirect address limit", - "Invalid digit in Q address", - "Invalid Q address", - "Q address exceeds indirect address limit", - "Invalid IO device", - "Invalid return register", - "Invalid IO function", - "Instruction address must be even", - "Invalid select code", - "Index instruction with no band selected", - "P address must be odd", - "DCF address must be even", - "Invalid disk drive", - "Invalid disk sector address", - "Invalid disk sector count", - "Invalid disk buffer address", - "Disk address compare error", - "Disk write check error", - "Disk cylinder overflow error", - "Disk wrong length record error", - "Invalid CCT", - "Field exceeds memory", - "Record exceeds memory", - "No card in reader", - "Overflow check", - "Exponent check", - "Write address function disabled", - "Floating point mantissa too long", - "Floating point mantissa lengths unequal", - "Floating point exponent flag missing", - "Floating point divide by zero" - }; - -/* Binary loader -- load carriage control tape - - A carriage control tape consists of entries of the form - - (repeat count) column number,column number,column number,... - - The CCT entries are stored in cct[0:lnt-1], cctlnt contains the - number of entries -*/ - -t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) -{ -uint32 col, mask, cctbuf[CCT_LNT]; -int32 ptr, rpt; -t_stat r; -extern int32 cct_lnt, cct_ptr; -extern uint32 cct[CCT_LNT]; -char cbuf[CBUFSIZE], gbuf[CBUFSIZE]; - -if ((*cptr != 0) || (flag != 0)) - return SCPE_ARG; -ptr = 0; -for ( ; (cptr = fgets (cbuf, CBUFSIZE, fileref)) != NULL; ) { /* until eof */ - mask = 0; - if (*cptr == '(') { /* repeat count? */ - cptr = get_glyph (cptr + 1, gbuf, ')'); /* get 1st field */ - rpt = get_uint (gbuf, 10, CCT_LNT, &r); /* repeat count */ - if (r != SCPE_OK) - return SCPE_FMT; - } - else rpt = 1; - while (*cptr != 0) { /* get col no's */ - cptr = get_glyph (cptr, gbuf, ','); /* get next field */ - col = get_uint (gbuf, 10, 12, &r); /* column number */ - if (r != SCPE_OK) - return SCPE_FMT; - mask = mask | (1 << col); /* set bit */ - } - for ( ; rpt > 0; rpt--) { /* store vals */ - if (ptr >= CCT_LNT) - return SCPE_FMT; - cctbuf[ptr++] = mask; - } - } -if (ptr == 0) - return SCPE_FMT; -cct_lnt = ptr; -cct_ptr = 0; -for (rpt = 0; rpt < cct_lnt; rpt++) - cct[rpt] = cctbuf[rpt]; -return SCPE_OK; -} - -/* Symbol table */ - -struct opc { - char *str; /* mnemonic */ - uint32 opv; /* opcode & flags */ - uint32 qv; /* q field */ - }; - -#define I_V_FL 16 /* flags */ -#define I_M_QX 0x01 /* Q indexable */ -#define I_M_QM 0x02 /* Q immediate */ -#define I_M_QNP 0x00 /* Q no print */ -#define I_M_QCP 0x04 /* Q cond print */ -#define I_M_QP 0x08 /* Q print */ -#define I_M_PCP 0x00 /* P cond print */ -#define I_M_PP 0x10 /* P print */ -#define I_GETQF(x) (((x) >> I_V_FL) & 0x03) -#define I_GETQP(x) (((x) >> I_V_FL) & 0x0C) -#define I_GETPP(x) (((x) >> I_V_FL) & 0x10) - -#define I_2 ((I_M_PP | I_M_QP | I_M_QX) << I_V_FL) -#define I_2M ((I_M_PP | I_M_QP | I_M_QM) << I_V_FL) -#define I_2X ((I_M_PP | I_M_QP | I_M_QX | I_M_QM) << I_V_FL) -#define I_2S ((I_M_PP | I_M_QP) << I_V_FL) -#define I_1 ((I_M_PP | I_M_QCP) << I_V_FL) -#define I_1E ((I_M_PP | I_M_QNP) << I_V_FL) -#define I_0 ((I_M_PCP | I_M_QCP) << I_V_FL) -#define I_0E ((I_M_PCP | I_M_QNP) << I_V_FL) - -struct opc opcode[] = { - { "RNTY", 36+I_1E, 100 }, { "RATY", 37+I_1E, 100 }, - { "WNTY", 38+I_1E, 100 }, { "WATY", 39+I_1E, 100 }, - { "DNTY", 35+I_1E, 100 }, { "SPTY", 34+I_0E, 101 }, - { "RCTY", 34+I_0E, 102 }, { "BKTY", 34+I_0E, 103 }, - { "IXTY", 34+I_0E, 104 }, { "TBTY", 34+I_0E, 108 }, - { "RNPT", 36+I_1E, 300 }, { "RAPT", 37+I_1E, 300 }, - { "WNPT", 38+I_1E, 200 }, { "WAPT", 39+I_1E, 200 }, - { "DNPT", 35+I_1E, 200 }, - { "RNCD", 36+I_1E, 500 }, { "RACD", 37+I_1E, 500 }, - { "WNCD", 38+I_1E, 400 }, { "WACD", 39+I_1E, 400 }, - { "DNCD", 35+I_1E, 400 }, - { "PRN", 38+I_1E, 900 }, { "PRNS", 38+I_1E, 901 }, - { "PRA", 39+I_1E, 900 }, { "PRAS", 39+I_1E, 901 }, - { "PRD", 35+I_1E, 900 }, { "PRDS", 35+I_1E, 901 }, - { "SK", 34+I_1E, 701 }, - { "RDGN", 36+I_1E, 700 }, { "CDGN", 36+I_1E, 701 }, - { "RDN", 36+I_1E, 702 }, { "CDN", 36+I_1E, 703 }, - { "RTGN", 36+I_1E, 704 }, { "CTGN", 36+I_1E, 705 }, - { "RTN", 36+I_1E, 706 }, { "CTN", 36+I_1E, 707 }, - { "WDGN", 38+I_1E, 700 }, { "WDN", 38+I_1E, 702 }, - { "WTGN", 38+I_1E, 704 }, { "WTN", 38+I_1E, 706 }, - { "RBPT", 37+I_1E, 3300 }, { "WBPT", 39+I_1E, 3200 }, - { "BC1", 46+I_1E, 100 }, { "BNC1", 47+I_1E, 100 }, - { "BC2", 46+I_1E, 200 }, { "BNC2", 47+I_1E, 200 }, - { "BC3", 46+I_1E, 300 }, { "BNC3", 47+I_1E, 300 }, - { "BC4", 46+I_1E, 400 }, { "BNC4", 47+I_1E, 400 }, - { "BLC", 46+I_1E, 900 }, { "BNLC", 47+I_1E, 900 }, - { "BH", 46+I_1E, 1100 }, { "BNH", 47+I_1E, 1100 }, - { "BP", 46+I_1E, 1100 }, { "BNP", 47+I_1E, 1100 }, - { "BE", 46+I_1E, 1200 }, { "BNE", 47+I_1E, 1200 }, - { "BZ", 46+I_1E, 1200 }, { "BNZ", 47+I_1E, 1200 }, - { "BNL", 46+I_1E, 1300 }, { "BL", 47+I_1E, 1300 }, - { "BNN", 46+I_1E, 1300 }, { "BN", 47+I_1E, 1300 }, - { "BV", 46+I_1E, 1400 }, { "BNV", 47+I_1E, 1400 }, - { "BXV", 46+I_1E, 1500 }, { "BNXV", 47+I_1E, 1500 }, - { "BA", 46+I_1E, 1900 }, { "BNA", 47+I_1E, 1900 }, - { "BNBS", 46+I_1E, 3000 }, { "BEBS", 47+I_1E, 3000 }, - { "BBAS", 46+I_1E, 3100 }, { "BANS", 47+I_1E, 3100 }, - { "BBBS", 46+I_1E, 3200 }, { "BBNS", 47+I_1E, 3200 }, - { "BCH9", 46+I_1E, 3300 }, - { "BCOV", 46+I_1E, 3400 }, - { "BSNX", 60+I_1E, 0 }, { "BSBA", 60+I_1E, 1 }, - { "BSBB", 60+I_1E, 2 }, - { "BSNI", 60+I_1E, 8 }, { "BSIA", 60+I_1E, 9 }, - - { "FADD", 1+I_2, 0 }, { "FSUB", 2+I_2, 0 }, - { "FMUL", 3+I_2, 0 }, { "FSL", 5+I_2, 0 }, - { "TFL", 6+I_2, 0 }, { "BTFL", 7+I_2, 0 }, - { "FSR", 8+I_2, 0 }, { "FDIV", 9+I_2, 0 }, - { "BTAM", 10+I_2M, 0 }, { "AM", 11+I_2M, 0 }, - { "SM", 12+I_2M, 0 }, { "MM", 13+I_2M, 0 }, - { "CM", 14+I_2M, 0 }, { "TDM", 15+I_2S, 0 }, - { "TFM", 16+I_2M, 0 }, { "BTM", 17+I_2M, 0 }, - { "LDM", 18+I_2M, 0 }, { "DM", 19+I_2M, 0 }, - { "BTA", 20+I_2, 0 }, { "A", 21+I_2, 0 }, - { "S", 22+I_2, 0 }, { "M", 23+I_2, 0 }, - { "C", 24+I_2, 0 }, { "TD", 25+I_2, 0 }, - { "TF", 26+I_2, 0 }, { "BT", 27+I_2, 0 }, - { "LD", 28+I_2, 0 }, { "D", 29+I_2, 0 }, - { "TRNM", 30+I_2, 0 }, { "TR", 31+I_2, 0 }, - { "SF", 32+I_1, 0 }, { "CF", 33+I_1, 0 }, - { "K", 34+I_2S, 0 }, { "DN", 35+I_2S, 0 }, - { "RN", 36+I_2S, 0 }, { "RA", 37+I_2S, 0 }, - { "WN", 38+I_2S, 0 }, { "WA", 39+I_2S, 0 }, - { "NOP", 41+I_0, 0 }, { "BB", 42+I_0, 0 }, - { "BD", 43+I_2, 0 }, { "BNF", 44+I_2, 0 }, - { "BNR", 45+I_2, 0 }, { "BI", 46+I_2S, 0 }, - { "BNI", 47+I_2S, 0 }, { "H", 48+I_0, 0 }, - { "B", 49+I_1, 0 }, { "BNG", 55+I_2, 0 }, - { "BS", 60+I_2S, 0 }, { "BX", 61+I_2, 0 }, - { "BXM", 62+I_2X, 0 }, { "BCX", 63+I_2, 0 }, - { "BCXM", 64+I_2X, 0 }, { "BLX", 65+I_2, 0 }, - { "BLXM", 66+I_2X, 0 }, { "BSX", 67+I_2, 0 }, - { "MA", 70+I_2, 0 }, { "MF", 71+I_2, 0 }, - { "TNS", 72+I_2, 0 }, { "TNF", 73+I_2, 0 }, - { "BBT", 90+I_2, 0 }, { "BMK", 91+I_2, 0 }, - { "ORF", 92+I_2, 0 }, { "ANDF", 93+I_2, 0 }, - { "CPLF", 94+I_2, 0 }, { "EORF", 95+I_2, 0 }, - { "OTD", 96+I_2, 0 }, { "DTO", 97+I_2, 0 }, - { NULL, 0, 0 } - }; - -/* Print an address from five characters */ - -void fprint_addr (FILE *of, int32 spc, t_value *dig, t_bool flg) -{ -int32 i, idx; - -fputc (spc, of); /* spacer */ -if (dig[ADDR_LEN - 1] & FLAG) { /* signed? */ - fputc ('-', of); /* print minus */ - dig[ADDR_LEN - 1] = dig[ADDR_LEN - 1] & ~FLAG; - } -for (i = 0; i < ADDR_LEN; i++) /* print digits */ - fprintf (of, "%X", dig[i] & DIGIT); -if ((cpu_unit.flags & IF_IDX) && flg) { /* indexing? */ - for (i = idx = 0; i < ADDR_LEN - 2; i++) { /* get index reg */ - if (dig[ADDR_LEN - 2 - i] & FLAG) - idx = idx | (1 << i); - dig[ADDR_LEN - 2 - i] = dig[ADDR_LEN - 2 - i] & ~FLAG; - } - if (idx) /* print */ - fprintf (of, "(%d)", idx); - } -return; -} - -/* Look up an opcode - - Inputs: - op = opcode (decimal) - qv = Q value (full 5 digits) - Outputs: - *opcst = pointer to opcode string - (NULL if not found) - *fl = opcode flags (optional) -*/ - -char *opc_lookup (uint32 op, uint32 qv, uint32 *fl) -{ -uint32 i, opfl; - -for (i = 0; opcode[i].str != NULL; i++) { /* find opcode */ - opfl = opcode[i].opv & 0xFF0000; /* get flags */ - if ((op == (opcode[i].opv & 0xFF)) && /* op match? */ - ((qv == opcode[i].qv) || /* q match or */ - ((opfl != I_1E) && (opfl != I_0E)))) { /* not needed? */ - if (fl != NULL) - *fl = opfl; - return opcode[i].str; - } - } -return NULL; -} - -/* Symbolic decode - - Inputs: - *of = output stream - addr = current address - *val = values to decode - *uptr = pointer to unit - sw = switches - Outputs: - return = if >= 0, error code - if < 0, number of extra words retired -*/ - -#define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x) - -t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, - UNIT *uptr, int32 sw) -{ -int32 pmp, qmp, i, c, d, any; -uint32 op, qv, opfl; -char *opstr; - -if (uptr == NULL) - uptr = &cpu_unit; -if (sw & SWMASK ('C')) { /* character? */ - if (uptr->flags & UNIT_BCD) { - if (addr & 1) /* must be even */ - return SCPE_ARG; - c = ((val[0] & DIGIT) << 4) | (val[1] & DIGIT); - if (alp_to_cdp[c] > 0) - fprintf (of, "%c", alp_to_cdp[c]); - else fprintf (of, "<%02x>", c); - return -1; - } - else fprintf (of, FMTASC (val[0] & 0177)); - return SCPE_OK; - } -if ((uptr->flags & UNIT_BCD) == 0) /* CPU or disk? */ - return SCPE_ARG; -if (sw & SWMASK ('D')) { /* dump? */ - for (i = d = 0; i < LINE_LNT; i++) - d = d | val[i]; - if (d & FLAG) { /* any flags? */ - for (i = 0; i < LINE_LNT; i++) /* print flags */ - fprintf (of, (val[i] & FLAG)? "_": " "); - fprintf (of, "\n\t"); - } - for (i = 0; i < LINE_LNT; i++) /* print digits */ - fprintf (of, "%X", val[i] & DIGIT) ; - return -(i - 1); - } -if (sw & SWMASK ('S')) { /* string? */ - if (addr & 1) /* must be even */ - return SCPE_ARG; - for (i = 0; i < LINE_LNT; i = i + 2) { - c = ((val[i] & DIGIT) << 4) | (val[i + 1] & DIGIT); - if (alp_to_cdp[c] < 0) - break; - fprintf (of, "%c", alp_to_cdp[c]); - } - if (i == 0) { - fprintf (of, "<%02X>", c); - return -1; - } - return -(i - 1); - } -if ((sw & SWMASK ('M')) == 0) - return SCPE_ARG; - -if (addr & 1) /* must be even */ - return SCPE_ARG; -op = ((val[0] & DIGIT) * 10) + (val[1] & DIGIT); /* get opcode */ -for (i = qv = pmp = qmp = 0; i < ADDR_LEN; i++) { /* test addr */ - if (val[I_P + i]) - pmp = 1; - if (val[I_Q + i]) - qmp = 1; - qv = (qv * 10) + (val[I_Q + i] & DIGIT); - } -if ((val[0] | val[1]) & FLAG) /* flags force */ - pmp = qmp = 1; -opstr = opc_lookup (op, qv, &opfl); /* find opcode */ - -if (opstr == NULL) { /* invalid opcode */ - if ((sw & SIM_SW_STOP) != 0) { /* stop message? */ - fprintf (of, "%02d", op); /* print numeric opcode */ - return -(INST_LEN - 1); /* report success */ - } - return SCPE_ARG; - } -if (I_GETQP (opfl) == I_M_QNP) /* Q no print? */ - qmp = 0; - -fprintf (of, ((sw & SIM_SW_STOP)? "%s": "%-4s"), opstr);/* print opcode */ -if (I_GETPP (opfl) == I_M_PP) /* P required? */ - fprint_addr (of, ' ', &val[I_P], I_M_QX); -else if ((I_GETPP (opfl) == I_M_PCP) && (pmp || qmp)) /* P opt & needed? */ - fprint_addr (of, ' ', &val[I_P], 0); -if (I_GETQP (opfl) == I_M_QP) { /* Q required? */ - fprint_addr (of, ',', &val[I_Q], I_GETQF (opfl)); - if (I_GETQF (opfl) & I_M_QM) /* immediate? */ - val[I_Q] = val[I_Q] & ~FLAG; /* clr hi Q flag */ - } -else if ((I_GETQP (opfl) == I_M_QCP) && (pmp || qmp)) /* Q opt & needed? */ - fprint_addr (of, ',', &val[I_Q], 0); -for (i = any = 0; i < INST_LEN; i++) { /* print rem flags */ - if (val[i] & FLAG) { - if (!any) - fputc (',', of); - any = 1; - fprintf (of, "%d", i); - } - } -return -(INST_LEN - 1); -} - -/* parse_addr - get sign + address + index */ - -t_stat parse_addr (char *cptr, t_value *val, int32 flg) -{ -int32 i, sign = 0, addr, index; -static int32 idx_tst[ADDR_LEN] = { 0, 4, 2, 1, 0 }; -char *tptr; - -if (*cptr == '+') /* +? skip */ - cptr++; -else if (*cptr == '-') { /* -? skip, flag */ - sign = 1; - cptr++; - } -errno = 0; /* get address */ -addr = strtoul (cptr, &tptr, 16); -if (errno || (cptr == tptr) || (addr > 0xFFFFF)) /* err or too big? */ - return SCPE_ARG; -if ((cpu_unit.flags & IF_IDX) && (flg & I_M_QX) && /* index allowed? */ - (*tptr == '(')) { /* index specified */ - errno = 0; - index = strtoul (cptr = tptr + 1, &tptr, 10); /* get index */ - if (errno || (cptr == tptr) || (index > 7)) /* err or too big? */ - return SCPE_ARG; - if (*tptr++ != ')') - return SCPE_ARG; - } -else index = 0; -if (*tptr != 0) /* all done? */ - return SCPE_ARG; -for (i = ADDR_LEN - 1; i >= 0; i--) { /* cvt addr to dig */ - val[i] = (addr & 0xF) | ((index & idx_tst[i])? FLAG: 0); - addr = addr >> 4; - } -if (sign) /* set sign */ - val[ADDR_LEN - 1] = val[ADDR_LEN - 1] | FLAG; -if (flg & I_M_QM) /* set immediate */ - val[0] = val[0] | FLAG; -return SCPE_OK; -} - -/* Symbolic input - - Inputs: - *cptr = pointer to input string - addr = current PC - *uptr = pointer to unit - *val = pointer to output values - sw = switches - Outputs: - status = > 0 error code - <= 0 -number of extra words -*/ - -t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) -{ -int32 i, qv, opfl, last; -char la, *fptr, gbuf[CBUFSIZE]; -int8 t; - -while (isspace (*cptr)) /* absorb spaces */ - cptr++; -if ((sw & SWMASK ('C')) || ((*cptr == '\'') && cptr++)) { /* character? */ - if ((t = *cptr & 0x7F) == 0) /* get char */ - return SCPE_ARG; - if (uptr->flags & UNIT_BCD) { /* BCD? */ - if (addr & 1) - return SCPE_ARG; - t = cdr_to_alp[t]; /* convert */ - if (t < 0) /* invalid? */ - return SCPE_ARG; - val[0] = (t >> 4) & DIGIT; /* store */ - val[1] = t & DIGIT; - return -1; - } - else val[0] = t; /* store ASCII */ - return SCPE_OK; - } - -if ((uptr->flags & UNIT_BCD) == 0) /* CPU or disk? */ - return SCPE_ARG; -if ((sw & SWMASK ('S')) || ((*cptr == '"') && cptr++)) { /* string? */ - if (addr & 1) /* must be even */ - return SCPE_ARG; - for (i = 0; (i < sim_emax) && (*cptr != 0); i = i + 2) { - t = *cptr++ & 0x7F; /* get character */ - t = cdr_to_alp[t]; /* convert */ - if (t < 0) /* invalid? */ - return SCPE_ARG; - val[i] = (t >> 4) & DIGIT; /* store */ - val[i + 1] = t & DIGIT; - } - if (i == 0) /* final check */ - return SCPE_ARG; - return -(i - 1); - } - -if (addr & 1) /* even addr? */ - return SCPE_ARG; -cptr = get_glyph (cptr, gbuf, 0); /* get opcode */ -for (i = 0; opcode[i].str != NULL; i++) { /* look it up */ - if (strcmp (gbuf, opcode[i].str) == 0) - break; - } -if (opcode[i].str == NULL) /* successful? */ - return SCPE_ARG; -opfl = opcode[i].opv & 0xFF0000; /* get flags */ -val[0] = (opcode[i].opv & 0xFF) / 10; /* store opcode */ -val[1] = (opcode[i].opv & 0xFF) % 10; -qv = opcode[i].qv; -for (i = ADDR_LEN - 1; i >= 0; i--) { /* set P,Q fields */ - val[I_P + i] = 0; - val[I_Q + i] = qv % 10; - qv = qv /10; - } - -cptr = get_glyph (cptr, gbuf, ','); /* get P field */ -if (gbuf[0]) { /* any? */ - if (parse_addr (gbuf, &val[I_P], (I_GETPP (opfl)? I_M_QX: 0))) - return SCPE_ARG; - } -else if (I_GETPP (opfl) == I_M_PP) - return SCPE_ARG; - -if (I_GETQP (opfl) != I_M_QNP) { /* Q field allowed? */ - cptr = get_glyph (cptr, gbuf, ','); /* get Q field */ - if (gbuf[0]) { /* any? */ - if (parse_addr (gbuf, &val[I_Q], I_GETQF (opfl))) - return SCPE_ARG; - } - else if (I_GETQP (opfl) == I_M_QP) - return SCPE_ARG; - } - -cptr = get_glyph (cptr, fptr = gbuf, ' '); /* get flag field */ -last = -1; /* none yet */ -while (t = *fptr++) { /* loop through */ - if ((t < '0') || (t > '9')) /* must be digit */ - return SCPE_ARG; - t = t - '0'; /* convert */ - if (t == 1) { /* ambiguous? */ - la = *fptr++; /* get next */ - if (la == '0') /* 10? */ - t = 10; - else if ((la == '1') && (*fptr == 0)) /* 11 & end field? */ - t = 11; - else --fptr; /* dont lookahead */ - } - if (t <= last) /* in order? */ - return SCPE_ARG; - val[t] = val[t] | FLAG; /* set flag */ - last = t; /* continue */ - } - -if (*cptr != 0) - return SCPE_ARG; -return -(INST_LEN - 1); -} diff --git a/I1620/i1620_tty.c b/I1620/i1620_tty.c deleted file mode 100644 index d0b53706..00000000 --- a/I1620/i1620_tty.c +++ /dev/null @@ -1,528 +0,0 @@ -/* i1620_tty.c: IBM 1620 typewriter - - Copyright (c) 2002-2017, Robert M. Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - tty console typewriter - - 26-May-17 RMS Added deferred IO - 18-May-17 RMS Fixed keyboard interrupt problem for Linux - Added input backspace for Model II - 04-May-17 DW Revised tab calculation algorithm - 13-Mar-17 RMS Fixed tab stop array overrun at right margin (COVERITY) - 21-Feb-15 TFM Option to provide single digit numeric output - 05-Feb-15 TFM Changes to translate tables and valid input char. - 02-Jan-14 RMS Added variable tab stops - 10-Dec-13 RMS Fixed DN wraparound (Bob Armstrong) - 21-Sep-05 RMS Revised translation tables for 7094/1401 compatibility - 22-Dec-02 RMS Added break test -*/ - -#include "i1620_defs.h" - -#define NUM_1_DIGIT TRUE /* indicate numeric output will use single digit format (tfm) */ - -/* Maximum number of characters per line, or one-based column number of last char cell */ - -#define TTO_COLMAX 80 -#define UF_V_1DIG (UNIT_V_UF) -#define UF_1DIG (1 << UF_V_1DIG) -#define UTTI 0 -#define UTTO 1 - -uint32 tti_unlock = 0; /* expecting input */ -uint32 tti_flag = 0; /* flag typed */ -int32 tto_col = 1; /* one-based, char loc to print next */ - -uint8 tto_tabs[TTO_COLMAX + 1] = { /* Zero-based access, one-based UI */ - 0,0,0,0,0,0,0,0, - 1,0,0,0,0,0,0,0, - 1,0,0,0,0,0,0,0, - 1,0,0,0,0,0,0,0, - 1,0,0,0,0,0,0,0, - 1,0,0,0,0,0,0,0, - 1,0,0,0,0,0,0,0, - 1,0,0,0,0,0,0,0, - 1,0,0,0,0,0,0,0, - 1,0,0,0,0,0,0,0, - 1 -}; - -extern uint8 M[MAXMEMSIZE]; -extern uint8 ind[NUM_IND]; -extern UNIT cpu_unit; -extern uint32 io_stop; -extern uint32 cpuio_inp, cpuio_opc, cpuio_cnt, PAR; - -t_stat tto_num (void); -t_stat tto_write (uint32 c); -t_stat tti_svc (UNIT *uptr); -t_stat tto_svc (UNIT *uptr); -t_stat tty_reset (DEVICE *dptr); -t_stat tty_set_fixtabs (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat tty_set_12digit (UNIT *uptr, int32 val, char *cptr, void *desc); - -/* TTY data structures - - tty_dev TTY device descriptor - tty_unit TTY unit descriptor - tty_reg TTY register list -*/ - -UNIT tty_unit[] = { - { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT }, - { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT } - }; - -REG tty_reg[] = { - { FLDATA (UNLOCK, tti_unlock, 0) }, - { FLDATA (FLAG, tti_flag, 0), REG_HRO }, - { DRDATA (COL, tto_col, 7) }, - { DRDATA (KTIME, tty_unit[UTTI].wait, 24), REG_NZ + PV_LEFT }, - { DRDATA (TTIME, tty_unit[UTTO].wait, 24), REG_NZ + PV_LEFT }, - { NULL } - }; - -MTAB tty_mod[] = { - { MTAB_XTD|MTAB_VDV, TTO_COLMAX, NULL, "TABS", - &sim_tt_settabs, NULL, (void *) tto_tabs }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO, TTO_COLMAX, "TABS", NULL, - NULL, &sim_tt_showtabs, (void *) tto_tabs }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "NOTABS", - &tty_set_fixtabs, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 8, NULL, "DEFAULTTABS", - &tty_set_fixtabs, NULL, NULL }, - { UF_1DIG, UF_1DIG, "combined digits and flags", "1DIGIT", &tty_set_12digit }, - { UF_1DIG, 0 , "separate digits and flags", "2DIGIT", &tty_set_12digit }, - { 0 } - }; - -DEVICE tty_dev = { - "TTY", tty_unit, tty_reg, tty_mod, - 2, 10, 31, 1, 8, 7, - NULL, NULL, &tty_reset, - NULL, NULL, NULL, - NULL, DEV_DEFIO - }; - -/* Data tables */ - -/* Keyboard to numeric */ - -/* The following constant is a list of valid 1620 numeric characters - that can be entered from the keyboard. They are the digits 0-9, - record mark(|), numeric blank(@) and group mark(}). All others - are considered invalid. When entering data, these characters may - all be preceeded by tilde(~) or accent(`) to indicate that the - following character should be entered into storage with a flag. - - Alternatively, ] can be entered for flagged 0, - J-R or j-r can be entered for flagged 1-9, - ! for flagged RM, * for flagged numeric blank, - " for flagged GM. - - These different methods of entering numeric data represent - compromises since there is no practical way to exactly emulate - the 1620 typewriter capability of entering a flag but not - spacing the carriage. Entering a flag symbol in front of a - character is easier and sometimes more readable; using the - letters j-r is useful if column alignment is important on - the screen or when copying data that has printed letters in - place of flagged digits. This also matches the output of WN - or DN to the line printer. - - *tti_to_num is the string of valid characters - tti_position_to_internal[] are the matching internal codes - (Tom McBride)*/ - -const char *tti_to_num = "0123456789|@}]jklmnopqr!*\"JKLMNOPQR"; -const char tti_position_to_internal[35] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, REC_MARK, NUM_BLANK, GRP_MARK, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, - FLG_REC_MARK, FLG_NUM_BLANK, FLG_GRP_MARK, - 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19 -}; - -/* Keyboard to alphameric (digit pair) - translates LC to UC */ - -const int8 tti_to_alp[128] = { - -1, -1, -1, -1, -1, -1, -1, -1, /* 00 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* 10 */ - -1, -1, -1, -1, -1, -1, -1, -1, - 0x00, 0x5A, 0x5F, -1, 0x13, -1, -1, -1, /* !"#$%&' */ - 0x24, 0x04, 0x14, 0x10, 0x23, 0x20, 0x03, 0x21, /* ()*+,-./ */ - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, /* 01234567 */ - 0x78, 0x79, -1, -1, -1, 0x33, -1, -1, /* 89:;<=>? */ - 0x34, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* @ABCDEFG */ - 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* HIJKLMNO */ - 0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* PQRSTUVW */ - 0x67, 0x68, 0x69, -1, -1, 0x50, -1, -1, /* XYZ[\]^_ */ - -1, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, /* `abcdefg */ - 0x48, 0x49, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, /* hijklmno */ - 0x57, 0x58, 0x59, 0x62, 0x63, 0x64, 0x65, 0x66, /* pqrstuvw */ - 0x67, 0x68, 0x69, -1, 0x0A, 0x0F, -1, -1 /* xyz{|}~ */ - }; - -/* Numeric (digit) to typewriter */ - -/* Digits with values of 11, 13 and 14 should never occur and will be typed as :'s - if they ever do. These are really errors. (Tom McBride) */ - -/* If flagged digits are being printed with preceeding ` characters only the first - half of this table is actually used. If digits are being printed one char per - digit the whole table is used. (Tom McBride) */ - -const char num_to_tto[32] = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '|', ':', '@', ':', ':', '}', - - ']', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', '!', ':', '*', ':', ':', '"' - }; - -/* Alphameric (digit pair) to typewriter */ - -/* Characters not in 1620 set have been removed from table (tfm) */ - -const char alp_to_tto[256] = { - ' ', -1, -1, '.', ')', -1, -1, -1, /* 00 */ - -1, -1, -1, -1, -1, -1, -1, -1, - '+', -1, -1, '$', '*', -1, -1, -1, /* 10 */ - -1, -1, -1, -1, -1, -1, -1, -1, - '-', '/', -1, ',', '(', -1, -1, -1, /* 20 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, '=', '@', -1, -1, -1, /* 30 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, 'A', 'B', 'C', 'D', 'E', 'F', 'G', /* 40 */ - 'H', 'I', -1, -1, -1, -1, -1, -1, - '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', /* 50 */ - 'Q', 'R', -1, -1, -1, -1, -1, -1, - -1, -1, 'S', 'T', 'U', 'V', 'W', 'X', /* 60 */ - 'Y', 'Z', -1, -1, -1, -1, -1, -1, - '0', '1', '2', '3', '4', '5', '6', '7', /* 70 */ - '8', '9', -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* 80 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* 90 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* A0 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* B0 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* C0 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* D0 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* E0 */ - -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, /* F0 */ - -1, -1, -1, -1, -1, -1, -1, -1 - }; - -/* Terminal IO - - - On input, parity errors cannot occur. - - On input, release-start does NOT cause a record mark to be stored. - - On output, invalid characters type an invalid character and set WRCHK. - If IO stop is set, the system halts at the end of the operation. -*/ - -t_stat tty (uint32 op, uint32 pa, uint32 f0, uint32 f1) -{ -switch (op) { /* case on op */ - - case OP_K: /* control */ - switch (f1) { /* case on control */ - case 1: /* space */ - tto_write (' '); - break; - case 2: /* return */ - tto_write ('\r'); - break; - case 3: /* backspace */ - if ((cpu_unit.flags & IF_MII) == 0) - return STOP_INVFNC; - tto_write ('\b'); - break; - case 4: /* index */ - if ((cpu_unit.flags & IF_MII) == 0) - return STOP_INVFNC; - tto_write ('\n'); - break; - case 8: /* tab */ - tto_write ('\t'); - break; - default: - return STOP_INVFNC; - } - break; - - case OP_WN: - case OP_DN: - case OP_WA: - cpuio_set_inp (op, IO_TTY, &tty_unit[UTTO]); /* set IO in progress */ - break; - - case OP_RN: - case OP_RA: - tti_unlock = 1; /* unlock keyboard */ - tti_flag = 0; /* init flag */ - tto_write ('>'); /* prompt user */ - cpuio_set_inp (op, IO_TTY, NULL); /* set IO in progress */ - break; - - default: /* invalid function */ - return STOP_INVFNC; - } - -return SCPE_OK; -} - -/* Input unit service - OP can be RA or RN */ - -t_stat tti_svc (UNIT *uptr) -{ -int32 temp; -int8 raw, c; -const char *cp; - -sim_activate (uptr, uptr->wait); /* continue poll */ -if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */ - return temp; -if (tti_unlock == 0) /* expecting input? */ - return SCPE_OK; /* no, ignore */ -raw = (int8) (temp & 0x7F); - -if (raw == '\r') { /* return? */ - tto_write (raw); /* echo */ - tti_unlock = 0; /* no more input */ - cpuio_clr_inp (NULL); - return SCPE_OK; - } -if (cpuio_opc == OP_RN) { /* RN? */ - if (((raw == '\b') || (raw == 0x7F)) && /* backspace or del? */ - ((cpu_unit.flags & IF_MII) != 0)) { /* on model 2? */ - tto_write ('-'); /* print minus */ - MM (PAR); /* decr mem addr */ - return SCPE_OK; - } - else if ((raw == '~') || (raw == '`')) { /* flag? mark */ - tto_write (raw); - tti_flag = FLAG; - return SCPE_OK; - } - else if ((cp = strchr (tti_to_num, raw)) == 0) { /* invalid? */ - tto_write ('\a'); /* beep! */ - return SCPE_OK; - } - tto_write (raw); /* echo */ - if (cpuio_cnt >= MEMSIZE) { /* wrap around? */ - tti_unlock = 0; /* no more input */ - cpuio_clr_inp (NULL); - return STOP_RWRAP; - } - c = tti_position_to_internal[(cp - tti_to_num)] | tti_flag; /* assemble char */ - M[PAR] = c & (FLAG | DIGIT); /* store char */ - tti_flag = 0; /* re-init flag */ - PP (PAR); /* incr mem addr */ - cpuio_cnt++; - } - -else { /* RA */ - if (((raw == '\b') || (raw == 0x7F)) && /* backspace or del? */ - ((cpu_unit.flags & IF_MII) != 0)) { /* on model 2? */ - tto_write ('-'); /* print minus */ - PAR = ADDR_A (PAR, -2); /* decr mem addr*/ - return SCPE_OK; - } - else if (tti_to_alp[raw] < 0) { /* illegal char? */ - tto_write ('\a'); /* beep! */ - return SCPE_OK; - } - tto_write (raw); /* echo */ - if (cpuio_cnt >= MEMSIZE) { /* wrap around? */ - tti_unlock = 0; /* no more input */ - cpuio_clr_inp (NULL); - return STOP_RWRAP; - } - c = tti_to_alp[raw]; /* xlate */ - M[PAR] = (M[PAR] & FLAG) | (c & DIGIT); /* store 2 digits */ - M[PAR - 1] = (M[PAR - 1] & FLAG) | ((c >> 4) & DIGIT); - PAR = ADDR_A (PAR, 2); /* incr mem addr */ - cpuio_cnt = cpuio_cnt + 2; - } - -return SCPE_OK; -} - -/* Output unit service */ - -t_stat tto_svc (UNIT *uptr) { - -uint8 d; -int8 ttc; -t_stat sta = SCPE_OK; - -if ((cpuio_opc != OP_DN) && (cpuio_cnt >= MEMSIZE)) { /* wrap, ~dump? */ - cpuio_clr_inp (uptr); /* done */ - return STOP_RWRAP; - } -sim_activate (uptr, uptr->wait); /* sched another xfer */ - -switch (cpuio_opc) { /* decode op */ - - case OP_DN: - if ((cpuio_cnt != 0) && ((PAR % 20000) == 0)) /* done? */ - break; - return tto_num (); /* write numeric */ - - case OP_WN: - if ((M[PAR] & REC_MARK) == REC_MARK) /* end record? */ - break; - return tto_num (); /* write numeric */ - - case OP_WA: - d = M[PAR] & DIGIT; /* get digit */ - if ((d & REC_MARK) == REC_MARK) /* 8-2 char? done */ - break; - d = ((M[PAR - 1] & DIGIT) << 4) | d; /* get digit pair */ - ttc = alp_to_tto[d]; /* translate */ - if (ttc < 0) { /* bad char? */ - ind[IN_WRCHK] = 1; /* set write check */ - if (io_stop) /* set return status */ - sta = STOP_INVCHR; - break; - } - tto_write (ttc & 0x7F); /* write */ - PAR = ADDR_A (PAR, 2); /* incr mem addr */ - cpuio_cnt = cpuio_cnt + 2; - return SCPE_OK; - - default: - return SCPE_IERR; - } - -cpuio_clr_inp (uptr); /* clear IO in progress */ -return sta; -} - -/* Write numerically - cannot generate parity errors */ - -t_stat tto_num (void) -{ -t_stat r; -uint8 d; - -d = M[PAR]; /* get char */ -if (tty_unit[UTTO].flags & UF_1DIG) /* how display flagged digits? */ - r = tto_write (num_to_tto[d & (DIGIT|FLAG)]); /* single digit display */ -else { - if (d & FLAG) /* flag? */ - tto_write ('`'); /* write flag indicator */ - r = tto_write (num_to_tto[d & DIGIT]); /* write the digit */ - } -if (r != SCPE_OK) /* write error? */ - return r; -PP (PAR); /* incr mem addr */ -cpuio_cnt++; -return SCPE_OK; -} - -/* Wrap line, if needed, prior to character output */ - -void tto_wrap(void) -{ -if (tto_col > TTO_COLMAX) { /* line wrap? */ - sim_putchar('\r'); - sim_putchar('\n'); - tto_col = 1; - } -} - -/* Write, maintaining position */ - -t_stat tto_write (uint32 c) -{ -if (c == '\t') { /* tab? */ - tto_wrap(); - do { - sim_putchar(' '); /* use spaces */ - tto_col++; - } while (!(tto_col > TTO_COLMAX || tto_tabs[tto_col-1] == 1)); - } -else if (c == '\r') { /* return? */ - sim_putchar ('\r'); /* crlf */ - sim_putchar ('\n'); - tto_col = 1; /* back to LMargin */ - } -else if ((c == '\n') || (c == '\a')) { /* non-spacing? */ - sim_putchar (c); - } -else if (c == '\b') { /* backspace? */ - if (tto_col > 1) { - sim_putchar(c); - tto_col--; - } - } -else { /* normal */ - tto_wrap(); - sim_putchar(c); - tto_col++; - } -return SCPE_OK; -} - -/* Reset routine */ - -t_stat tty_reset (DEVICE *dptr) -{ -sim_activate (&tty_unit[UTTI], tty_unit[UTTI].wait); /* activate poll */ -sim_cancel (&tty_unit[UTTO]); /* cancel output */ -tti_unlock = tti_flag = 0; /* tty locked */ -tto_col = 1; -return SCPE_OK; -} - -/* Set tab stops at fixed modulus */ - -t_stat tty_set_fixtabs (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 i; - -for (i = 0; i < TTO_COLMAX; i++) { - if ((val != 0) && (i != 0) && ((i % val) == 0)) - tto_tabs[i] = 1; - else tto_tabs[i] = 0; - } -return SCPE_OK; -} - -/* Assure consistency of 1DIG/2DIG setting */ - -t_stat tty_set_12digit (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -tty_unit[UTTI].flags = (tty_unit[UTTI].flags & ~UF_1DIG) | val; -tty_unit[UTTO].flags = (tty_unit[UTTO].flags & ~UF_1DIG) | val; -return SCPE_OK; -} diff --git a/I7094/i7094_binloader.c b/I7094/i7094_binloader.c deleted file mode 100644 index a63a1b35..00000000 --- a/I7094/i7094_binloader.c +++ /dev/null @@ -1,217 +0,0 @@ -/* i7094_binloader.c: IBM 7094 simulator interface - - Copyright (c) 2008, David G. Pitts - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of the author shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the author. - - 13-Mar-17 RMS Annotated fall through in switch -*/ -/*********************************************************************** -* -* binloader.h - IBM 7090 emulator binary loader header. -* -* Changes: -* 10/20/03 DGP Original. -* 12/28/04 DGP Changed for new object formats. -* -***********************************************************************/ - -#define IBSYSSYM '$' /* Marks end of object file */ -#define WORDPERREC 5 /* Object words per record */ -#define LOADADDR 0200 /* Default load address */ -#define OBJRECLEN 80 /* Object record length */ -#define CHARWORD 12 /* Characters per word */ - -/* -** Object tags -*/ - -#define IDT_TAG '0' /* 0SSSSSS0LLLLL */ -#define ABSENTRY_TAG '1' /* 10000000AAAAA */ -#define RELENTRY_TAG '2' /* 20000000RRRRR */ -#define ABSEXTRN_TAG '3' /* 3SSSSSS0AAAAA */ -#define RELEXTRN_TAG '4' /* 4SSSSSS0RRRRR */ -#define ABSGLOBAL_TAG '5' /* 5SSSSSS0AAAAA */ -#define RELGLOBAL_TAG '6' /* 6SSSSSS0RRRRR */ -#define ABSORG_TAG '7' /* 70000000AAAAA */ -#define RELORG_TAG '8' /* 80000000RRRRR */ -#define ABSDATA_TAG '9' /* 9AAAAAAAAAAAA */ -#define RELADDR_TAG 'A' /* AAAAAAAARRRRR */ -#define RELDECR_TAG 'B' /* BARRRRRAAAAAA */ -#define RELBOTH_TAG 'C' /* CARRRRRARRRRR */ -#define BSS_TAG 'D' /* D0000000PPPPP */ -#define ABSXFER_TAG 'E' /* E0000000RRRRR */ -#define RELXFER_TAG 'F' /* F0000000RRRRR */ -#define EVEN_TAG 'G' /* G0000000RRRRR */ -#define FAPCOMMON_TAG 'H' /* H0000000AAAAA */ - -/* Where: - * SSSSSS - Symbol - * LLLLLL - Length of module - * AAAAAA - Absolute field - * RRRRRR - Relocatable field - * PPPPPP - PC offset field -*/ - -/*********************************************************************** -* -* binloader.c - IBM 7090 emulator binary loader routines for ASM7090 -* and LNK7090 object files. -* -* Changes: -* 10/20/03 DGP Original. -* 12/28/04 DGP Changed for new object formats. -* 02/14/05 DGP Detect IBSYSSYM for EOF. -* 06/09/06 DGP Make simh callable. -* -***********************************************************************/ - -#include "i7094_defs.h" - -extern t_uint64 *M; -extern uint32 PC; - -t_stat -binloader (FILE *fd, char *file, int loadpt) -{ -#ifdef DEBUGLOADER - FILE *lfd; -#endif - int transfer = FALSE; - int loadaddr = LOADADDR; - int curraddr = LOADADDR; - char inbuf[OBJRECLEN+2]; - -#ifdef DEBUGLOADER - lfd = fopen ("load.log", "w"); - fprintf (lfd, "binloader: file = '%s', loadpt = %d\n", file, loadpt); -#endif - - if (loadpt > 0) - { - loadaddr = loadpt; - curraddr = loadpt; - } - - while (fgets (inbuf, sizeof(inbuf), fd)) - { - char *op = inbuf; - int i; - - if (*op == IBSYSSYM) /* End of object marker */ - break; - - for (i = 0; i < WORDPERREC; i++) - { - char otag; - char item[16]; - t_uint64 ldata; - - otag = *op++; - if (otag == ' ') - break; - strncpy (item, op, CHARWORD); - item[CHARWORD] = '\0'; - sscanf (item, "%" LL_FMT "o", &ldata); - -#ifdef DEBUGLOADER - fprintf (lfd, "loadaddr = %05o, curraddr = %05o\n", - loadaddr, curraddr); - fprintf (lfd, " otag = %c, item = %s\n", otag, item); - fprintf (lfd, " ldata = %12.12o\n", ldata); -#endif - - switch (otag) - { - case IDT_TAG: - break; - - case ABSORG_TAG: - curraddr = loadaddr = (int32) ldata & AMASK; - break; - - case RELORG_TAG: - curraddr = (int32) (ldata + loadaddr) & AMASK; - break; - - case BSS_TAG: - curraddr = (int32) (curraddr + ldata) & AMASK; - break; - - case RELBOTH_TAG: - ldata = ldata + loadaddr + (loadaddr << INST_V_DEC); - goto STORE; - - case RELDECR_TAG: - ldata = ldata + (loadaddr << INST_V_DEC); - goto STORE; - - case RELADDR_TAG: - ldata = ldata + loadaddr; - /* fall through */ - case ABSDATA_TAG: - STORE: -#ifdef DEBUGLOADER - fprintf (lfd, " M[%05o] = %12.12o\n", curraddr, ldata); -#endif - M[curraddr] = ldata & DMASK; - curraddr++; - break; - - case ABSXFER_TAG: - transfer = TRUE; - /* fall through */ - case ABSENTRY_TAG: - PC = (uint32) ldata & AMASK; -#ifdef DEBUGLOADER - fprintf (lfd, " PC = %05o\n", PC); -#endif - if (transfer) - goto GOSTART; - break; - - case RELXFER_TAG: - transfer = TRUE; - /* fall through */ - case RELENTRY_TAG: - ldata = (ldata + loadaddr) & AMASK; - PC = (uint32) ldata & AMASK; -#ifdef DEBUGLOADER - fprintf (lfd, " PC = %05o\n", PC); -#endif - if (transfer) - goto GOSTART; - break; - - default: ; - } - op += CHARWORD; - } - } - -GOSTART: -#ifdef DEBUGLOADER - fclose (lfd); -#endif - - return SCPE_OK; -} diff --git a/I7094/i7094_bug_history.txt b/I7094/i7094_bug_history.txt deleted file mode 100644 index 9b1c5cf8..00000000 --- a/I7094/i7094_bug_history.txt +++ /dev/null @@ -1,70 +0,0 @@ -Bugs Found and Fixed During Simulator Debug - -1. CPU: MPY tested sign of AC instead of sign of MQ. -2. CPU: VLM, VDP, VDH need alternate opcode decode points for large counts. -3. CPU: STL not in decode table. -4. CPU: Partial stores lacked initial read in decode table. -5. CPU: PXD, PCD needed (t_uint64) cast. -6. CPU: SXD, SCD needed (t_uint64) cast. -7. CPU: SBM at wrong case offset. -8. CPU: All transfers used IR<21:35> instead of calculated effective address. -9. CPU: HPR, TRA need alternate negative opcodes. -10. CPU: STT missing final write to memory. -11. IO: Channel output process model incorrect, extensive revision required. -12. IO: Channel connect test should not test channel state, only connection. -13. IO: Channel opcode with nostore doesn't increment channel address. -14. CDR: Card reader missing activate at end of state 2. -15. SYS: Zero operand instructions printed with trailing space. -16. CPU: Convert class count bit field start definition incorrect. -17. CPU: CAQ cut and paste error from CVR. -18. CPU: Shift count is 8b wide, not 9b. -19. SYS: Mnemonic is LDQ not LMQ. -20. SYS: RQL opcode incorrect in symbolic decode table. -21. CPU: Multi-tag mode stores OR'd value of tags on any index read except normal - effective address. -22. CPU: Floating point trap does not write location 0 if trap suppressed. -23. SYS: TRA instructions should have symbolic class MXN not MXR. -24. CPU: Floating add instructions test for zero result only if normalization enabled. -25. CPU: Floating add with unlike signs and equal magnitudes, result sign is sign - of SR rather than sign of AC. -26. CPU: Floating multiply does not test spill prior to normalization step. -27. CPU: Channel activity proceeds under HALT. -28. MT: Any read error should stop the channel and the tape controller. -29. MT: EOR write flag cleared before testing. -39. IO: EOR write flag set after data sent to device. -40. IO: EOR write flag incorrect set on IOCP, IOCT, IOSP, IOST. -41. MT: End of file errors not masked on backspace operations. -42. CPU: LCHx, RCHx miscoded in decode table. -43. IO: Only 7607 error completions (IOxT without new command) set trap. -44. CPU: 7067 channel trap flags misdefined with extraneous decrement shift. -45. CPU: pcq array misdeclared as uint32 instead of uint16. -46. IO: SDC and SCD tested chan_flags instead of chan_dev.flags. -47. SYS: 7907 opcodes defined incorrectly. -48. SYS: TCH not decoding bit<19>. -49. IO: CTL not clearing EOR after device end. -50. DSK: Format code not incrementing track in writing all tracks in cylinder. -51. DSK: THA mode overwrites record structure of first record. -52. DSK: Write doesn't set channel request for initial word. -53. DSK: Saved record number was command digits 3..8 instead of 5..10. -54. CLK: Compute 60th's from location 5, so Chrono clock is in sync with interval clock. -55. CPU: Enable Chronolog clock if CTSS. -56. CPU: Read/write protection error not setting protection trap. -57. CPU: SCHx not setting protection trap in user mode. -58: CPU: Protection trap overwriting wrong location. -59. CPU: Stop message reporting physical, not virtual, PC. -60. IO: Test for "request another cycle" in channel processor was inverted. -61. IO: Valid bit handling incorrect across multiple transfers. -62. IO: BSR doesn't set EOF indicator. -63. IO: 7607 channel modeled incorrectly, could stall. -64. IO: All 7607 "effective NOP" conditions must be tested when a new command is - decoded (wc == 0 for IOCx and IOSx, EOR set for IOSx and IORx). -65. MT: BSR, BSF release the data channel in a few microseconds, like REW. -66. CPU: Not all PSE and MSE variants are trapped in user mode. -67. CPU: Storage nullification mask not recalculated at all points needed; - replaced with macro. - - - - - - diff --git a/I7094/i7094_cd.c b/I7094/i7094_cd.c deleted file mode 100644 index 6499c2de..00000000 --- a/I7094/i7094_cd.c +++ /dev/null @@ -1,512 +0,0 @@ -/* i7094_cd.c: IBM 711/721 card reader/punch - - Copyright (c) 2003-2017, 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 711 card reader - cdp 721 card punch - - 13-Mar-17 RMS Annotated fall through in switch - 19-Mar-12 RMS Fixed declaration of sim_switches (Mark Pizzolato) - 19-Jan-07 RMS Added UNIT_TEXT - 13-Jul-06 RMS Fixed problem with 80 column full cards - - Cards are represented as ASCII text streams terminated by newlines. - This allows cards to be created and edited as normal files. Two - formats are supported: - - column binary each character represents 6b of a 12b column - text each character represents all 12b of a column - - Internally, the 7094 works only with column binary and is limited - to 72 columns of data. Each row of the card is represented by 72b - of data (two 36b words). A complete card image consists of 12 rows - (24 36b words). -*/ - -#include "i7094_defs.h" - -#define CD_BINLNT 24 /* bin buf length */ -#define CD_CHRLNT 80 /* char buf length */ - -#define CDS_INIT 0 /* card in motion */ -#define CDS_DATA 1 /* data transfer */ -#define CDS_END 2 /* card complete */ - -#define UNIT_V_CBN (UNIT_V_UF + 0) /* column binary file */ -#define UNIT_V_PCA (UNIT_V_UF + 1) /* A vs H punch flag */ -#define UNIT_CBN (1 << UNIT_V_CBN) -#define UNIT_PCA (1 << UNIT_V_PCA) - -uint32 cdr_sta = 0; /* state */ -uint32 cdr_bptr = 0; /* buffer ptr */ -uint32 cdr_tstart = 27500; /* timing */ -uint32 cdr_tstop = 27500; -uint32 cdr_tleft = 150; -uint32 cdr_tright = 4000; -t_uint64 cdr_bbuf[CD_BINLNT]; /* col binary buf */ - -uint32 cdp_sta = 0; /* state */ -uint32 cdp_bptr = 0; /* buffer ptr */ -uint32 cdp_tstart = 35000; /* timing */ -uint32 cdp_tstop = 35000; -uint32 cdp_tleft = 150; -uint32 cdp_tright = 15500; -t_uint64 cdp_chob = 0; -uint32 cdp_chob_v = 0; -t_uint64 cdp_bbuf[CD_BINLNT]; /* col binary buf */ - -t_stat cdr_chsel (uint32 ch, uint32 sel, uint32 unit); -t_stat cdr_reset (DEVICE *dptr); -t_stat cdr_svc (UNIT *uptr); -t_stat cdr_boot (int32 unitno, DEVICE *dptr); -t_stat cdp_chsel (uint32 ch, uint32 sel, uint32 unit); -t_stat cdp_chwr (uint32 ch, t_uint64 val, uint32 flags); -t_stat cdp_reset (DEVICE *dptr); -t_stat cdp_svc (UNIT *uptr); -t_stat cdp_card_end (UNIT *uptr); -t_stat cd_attach (UNIT *uptr, char *cptr); -t_stat cd_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); -char colbin_to_bcd (uint32 cb); - -extern uint32 PC; -extern uint32 ind_ioc; -extern char bcd_to_ascii_a[64]; -extern char bcd_to_ascii_h[64]; -extern uint32 bcd_to_colbin[64]; -extern char ascii_to_bcd[128]; -extern t_uint64 bit_masks[36]; -extern uint32 col_masks[12]; - -/* Card reader data structures - - cdr_dev CDR descriptor - cdr_unit CDR unit descriptor - cdr_reg CDR register list -*/ - -DIB cdr_dib = { &cdr_chsel, NULL }; - -UNIT cdr_unit = { - UDATA (&cdr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE+UNIT_TEXT, 0) - }; - -REG cdr_reg[] = { - { ORDATA (STATE, cdr_sta, 2) }, - { DRDATA (BPTR, cdr_bptr, 5), PV_LEFT }, - { BRDATA (BUF, cdr_bbuf, 8, 36, CD_BINLNT) }, - { DRDATA (POS, cdr_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TSTART, cdr_tstart, 24), PV_LEFT + REG_NZ }, - { DRDATA (TSTOP, cdr_tstop, 24), PV_LEFT + REG_NZ }, - { DRDATA (TLEFT, cdr_tleft, 24), PV_LEFT + REG_NZ }, - { DRDATA (TRIGHT, cdr_tright, 24), PV_LEFT + REG_NZ }, - { NULL } }; - -MTAB cdr_mod[] = { - { UNIT_CBN, UNIT_CBN, "column binary", "BINARY", &cd_set_mode }, - { UNIT_CBN, UNIT_CBN, "text", "TEXT", &cd_set_mode }, - { 0 } - }; - -DEVICE cdr_dev = { - "CDR", &cdr_unit, cdr_reg, cdr_mod, - 1, 10, 31, 1, 8, 7, - NULL, NULL, &cdr_reset, - &cdr_boot, &cd_attach, NULL, - &cdr_dib, DEV_DISABLE - }; - -/* CDP data structures - - cdp_dev CDP device descriptor - cdp_unit CDP unit descriptor - cdp_reg CDP register list -*/ - -DIB cdp_dib = { &cdp_chsel, &cdp_chwr }; - -UNIT cdp_unit = { - UDATA (&cdp_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0) - }; - -REG cdp_reg[] = { - { ORDATA (STATE, cdp_sta, 2) }, - { ORDATA (CHOB, cdp_chob, 36) }, - { FLDATA (CHOBV, cdp_chob_v, 0) }, - { DRDATA (BPTR, cdp_bptr, 5), PV_LEFT }, - { BRDATA (BUF, cdp_bbuf, 8, 36, CD_BINLNT) }, - { DRDATA (POS, cdp_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TSTART, cdp_tstart, 24), PV_LEFT + REG_NZ }, - { DRDATA (TSTOP, cdp_tstop, 24), PV_LEFT + REG_NZ }, - { DRDATA (TLEFT, cdp_tleft, 24), PV_LEFT + REG_NZ }, - { DRDATA (TRIGHT, cdp_tright, 24), PV_LEFT + REG_NZ }, - { NULL } - }; - -MTAB cdp_mod[] = { - { UNIT_CBN, UNIT_CBN, "column binary", "BINARY", &cd_set_mode }, - { UNIT_CBN, UNIT_CBN, "text", "TEXT", &cd_set_mode }, - { UNIT_PCA, UNIT_PCA, "business set", "BUSINESS", NULL }, - { UNIT_PCA, 0, "Fortran set", "FORTRAN", NULL }, - { 0 } - }; - -DEVICE cdp_dev = { - "CDP", &cdp_unit, cdp_reg, cdp_mod, - 1, 10, 31, 1, 8, 7, - NULL, NULL, &cdp_reset, - NULL, &cd_attach, NULL, - &cdp_dib, DEV_DISABLE - }; - -/* Card reader select */ - -t_stat cdr_chsel (uint32 ch, uint32 sel, uint32 unit) -{ -if (sel & CHSL_NDS) /* nds? nop */ - return ch6_end_nds (ch); - -switch (sel) { /* case on data sel */ - - case CHSL_RDS: /* read */ - if ((cdr_unit.flags & UNIT_ATT) == 0) /* not attached? */ - return SCPE_UNATT; - if (sim_is_active (&cdr_unit)) /* busy? */ - return ERR_STALL; - cdr_sta = CDS_INIT; /* initial state */ - sim_activate (&cdr_unit, cdp_tstart); /* start reader */ - break; - - default: /* other */ - return STOP_ILLIOP; /* not allowed */ - } - -return SCPE_OK; -} - -/* Unit timeout */ - -t_stat cdr_svc (UNIT *uptr) -{ -uint32 i, col, row, bufw, colbin; -char cdr_cbuf[(2 * CD_CHRLNT) + 2]; -t_uint64 dat = 0; - -if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ - return SCPE_UNATT; -switch (cdr_sta) { /* case on state */ - - case CDS_INIT: /* initial state */ - for (i = 0; i < CD_BINLNT; i++) /* clear bin buf */ - cdr_bbuf[i] = 0; - for (i = 0; i < ((2 * CD_CHRLNT) + 2); i++) /* clear char buf */ - cdr_cbuf[i] = ' '; - cdr_sta = CDS_DATA; /* data state */ - cdr_bptr = 0; /* init buf ptr */ - fgets (cdr_cbuf, (uptr->flags & UNIT_CBN)? (2 * CD_CHRLNT) + 2: CD_CHRLNT + 2, - uptr->fileref); /* read card */ - if (feof (uptr->fileref)) /* eof? */ - return ch6_err_disc (CH_A, U_CDR, CHF_EOF); /* set EOF, disc */ - if (ferror (uptr->fileref)) { /* error? */ - perror ("CDR I/O error"); - clearerr (uptr->fileref); - return SCPE_IOERR; /* stop */ - } - uptr->pos = ftell (uptr->fileref); /* update position */ - for (i = 0; i < (2 * CD_CHRLNT); i++) /* convert to BCD */ - cdr_cbuf[i] = ascii_to_bcd[cdr_cbuf[i] & 0177] & 077; - for (col = 0; col < 72; col++) { /* process 72 columns */ - if (uptr->flags & UNIT_CBN) /* column binary? */ - colbin = (((uint32) cdr_cbuf[2 * col]) << 6) | - ((uint32) cdr_cbuf[(2 * col) + 1]); /* 2 chars -> col bin */ - else colbin = bcd_to_colbin[cdr_cbuf[col]]; /* cvt to col binary */ - dat = bit_masks[35 - (col % 36)]; /* mask for column */ - for (row = 0; row < 12; row++) { /* rows 9..0, 11, 12 */ - bufw = (row * 2) + (col / 36); /* index to buffer */ - if (colbin & col_masks[row]) /* row bit set? */ - cdr_bbuf[bufw] |= dat; - } - } - /* fall through */ - case CDS_DATA: /* data state */ - dat = cdr_bbuf[cdr_bptr++]; /* get next word */ - if (cdr_bptr >= CD_BINLNT) { /* last word? */ - cdr_sta = CDS_END; /* end state */ - ch6_req_rd (CH_A, U_CDR, dat, CH6DF_EOR); /* req chan, dat, EOR */ - sim_activate (uptr, cdr_tstop); - } - else { - ch6_req_rd (CH_A, U_CDR, dat, 0); /* req chan, dat */ - sim_activate (uptr, (cdr_bptr & 1)? cdr_tleft: cdr_tright); - } - break; - - case CDS_END: /* end state */ - if (ch6_qconn (CH_A, U_CDR)) { /* if cdr still conn */ - cdr_sta = CDS_INIT; /* return to init */ - sim_activate (uptr, 1); /* next card */ - } - break; - } - -return SCPE_OK; -} - -/* Card reader reset */ - -t_stat cdr_reset (DEVICE *dptr) -{ -uint32 i; - -for (i = 0; i < CD_BINLNT; i++) /* clear buffer */ - cdr_bbuf[i] = 0; -cdr_sta = 0; /* clear state */ -cdr_bptr = 0; /* clear buf ptr */ -sim_cancel (&cdr_unit); /* stop reader */ -return SCPE_OK; -} - -/* Card reader bootstrap */ - -#define BOOT_START 01000 -#define BOOT_SIZE (sizeof (boot_rom) / sizeof (t_uint64)) - -static const t_uint64 boot_rom[] = { - INT64_C(00762000001000) + U_CDR, /* RDSA CDR */ - INT64_C(00544000000000) + BOOT_START + 4, /* LCHA *+3 */ - INT64_C(00544000000000), /* LCHA 0 */ - INT64_C(00021000000001), /* TTR 1 */ - INT64_C(05000030000000), /* IOCT 3,,0 */ - }; - -t_stat cdr_boot (int32 unitno, DEVICE *dptr) -{ -uint32 i; -extern t_uint64 *M; - -for (i = 0; i < BOOT_SIZE; i++) - WriteP (BOOT_START + i, boot_rom[i]); -PC = BOOT_START; -return SCPE_OK; -} - -/* Reader/punch attach */ - -t_stat cd_attach (UNIT *uptr, char *cptr) -{ -t_stat r; - -r = attach_unit (uptr, cptr); -if (r != SCPE_OK) /* attach */ - return r; -if (sim_switches & SWMASK ('T')) /* text? */ - uptr->flags = uptr->flags & ~UNIT_CBN; -else if (sim_switches & SWMASK ('C')) /* column binary? */ - uptr->flags = uptr->flags | UNIT_CBN; -else if (match_ext (cptr, "TXT")) /* .txt? */ - uptr->flags = uptr->flags & ~UNIT_CBN; -else if (match_ext (cptr, "CBN")) /* .cbn? */ - uptr->flags = uptr->flags | UNIT_CBN; -return SCPE_OK; -} - -/* Reader/punch set mode - valid only if not attached */ - -t_stat cd_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -return (uptr->flags & UNIT_ATT)? SCPE_NOFNC: SCPE_OK; -} - -/* Card punch select */ - -t_stat cdp_chsel (uint32 ch, uint32 sel, uint32 unit) -{ -if (sel & CHSL_NDS) /* nds? nop */ - return ch6_end_nds (ch); - -switch (sel) { /* case on cmd */ - - case CHSL_WRS: /* write */ - if ((cdp_unit.flags & UNIT_ATT) == 0) /* not attached? */ - return SCPE_UNATT; - if (sim_is_active (&cdp_unit)) /* busy? */ - return ERR_STALL; - cdp_sta = CDS_INIT; /* initial state */ - sim_activate (&cdp_unit, cdp_tstart); /* start punch */ - break; - - default: /* other */ - return STOP_ILLIOP; /* not allowed */ - } -return SCPE_OK; -} - -/* Channel write routine - write word to buffer, write card when full */ - -t_stat cdp_chwr (uint32 ch, t_uint64 val, uint32 eorfl) -{ -cdp_chob = val & DMASK; /* store data */ -cdp_chob_v = 1; /* buffer valid */ -if (cdp_sta == CDS_DATA) { - cdp_bbuf[cdp_bptr++] = cdp_chob; /* store data */ - if ((cdp_bptr >= CD_BINLNT) || eorfl) { /* end card or end rec? */ - ch6_set_flags (CH_A, U_CDP, CHF_EOR); /* set eor */ - return cdp_card_end (&cdp_unit); /* write card */ - } - return SCPE_OK; - } -return SCPE_IERR; -} - -/* Unit timeout */ - -t_stat cdp_svc (UNIT *uptr) -{ -uint32 i; - -switch (cdp_sta) { /* case on state */ - - case CDS_INIT: /* initial state */ - for (i = 0; i < CD_BINLNT; i++) /* clear bin buffer */ - cdp_bbuf[i] = 0; - cdp_sta = CDS_DATA; /* data state */ - cdp_bptr = 0; /* init pointer */ - ch6_req_wr (CH_A, U_CDP); /* request channel */ - cdp_chob = 0; /* clr, inval buffer */ - cdp_chob_v = 0; - sim_activate (uptr, cdp_tleft); /* go again */ - break; - - case CDS_DATA: /* data state */ - if (!ch6_qconn (CH_A, U_CDP)) /* chan disconnect? */ - return cdp_card_end (uptr); /* write card */ - if (cdp_chob_v) /* valid? clear */ - cdp_chob_v = 0; - else ind_ioc = 1; /* no, io check */ - ch6_req_wr (CH_A, U_CDP); /* req channel */ - sim_activate (uptr, (cdp_bptr & 1)? cdp_tleft: cdp_tright); - break; - - case CDS_END: /* end state */ - if (ch6_qconn (CH_A, U_CDP)) { /* if cdp still conn */ - cdp_sta = CDS_INIT; /* return to init */ - sim_activate (uptr, 1); /* next card */ - } - break; - } - -return SCPE_OK; -} - -/* Card end - write card image to file, transition to end state */ - -t_stat cdp_card_end (UNIT *uptr) -{ -uint32 i, col, row, bufw, colbin; -char *pch, bcd, cdp_cbuf[(2 * CD_CHRLNT) + 2]; -t_uint64 dat; - -if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ - return SCPE_UNATT; -if (uptr->flags & UNIT_PCA) - pch = bcd_to_ascii_a; -else pch = bcd_to_ascii_h; -for (col = 0; col < ((2 * CD_CHRLNT) + 1); col++) - cdp_cbuf[col] = ' '; /* clear char buf */ -for (col = 0; col < 72; col++) { /* process 72 columns */ - colbin = 0; - dat = bit_masks[35 - (col % 36)]; /* mask for column */ - for (row = 0; row < 12; row++) { /* proc 12 rows */ - bufw = (row * 2) + (col / 36); /* index to buffer */ - if (cdp_bbuf[bufw] & dat) - colbin |= col_masks[row]; - } - if (cdp_unit.flags & UNIT_CBN) { /* column binary? */ - cdp_cbuf[2 * col] = pch[(colbin >> 6) & 077]; - cdp_cbuf[(2 * col) + 1] = pch[colbin & 077]; - } - else { /* text */ - bcd = colbin_to_bcd (colbin); /* column bin -> BCD */ - cdp_cbuf[col] = pch[bcd]; /* -> ASCII */ - } - } -for (i = ((2 * CD_CHRLNT) + 1); (i > 0) && - (cdp_cbuf[i - 1] == ' '); --i) ; /* trim spaces */ -cdp_cbuf[i++] = '\n'; /* append nl */ -cdp_cbuf[i++] = 0; /* append nul */ -fputs (cdp_cbuf, uptr->fileref); /* write card */ -uptr->pos = ftell (uptr->fileref); /* update position */ -if (ferror (uptr->fileref)) { /* error? */ - perror ("CDP I/O error"); - clearerr (uptr->fileref); - return SCPE_IOERR; - } -cdp_sta = CDS_END; /* end state */ -sim_cancel (uptr); /* cancel current */ -sim_activate (uptr, cdp_tstop); /* long timer */ -return SCPE_OK; -} - -/* Card punch reset */ - -t_stat cdp_reset (DEVICE *dptr) -{ -uint32 i; - -for (i = 0; i < 24; i++) /* clear buffer */ - cdp_bbuf[i] = 0; -cdp_sta = 0; /* clear state */ -cdp_bptr = 0; /* clear buf ptr */ -cdp_chob = 0; -cdp_chob_v = 0; -sim_cancel (&cdp_unit); /* stop punch */ -return SCPE_OK; -} - -/* Column binary to BCD - - This is based on documentation in the IBM 1620 manual and may not be - accurate for the 7094. Each row (12,11,0,1..9) is interpreted as a bit - pattern, and the appropriate bits are set. (Double punches inclusive - OR, eg, 1,8,9 is 9.) On the 1620, double punch errors are detected; - since the 7094 only reads column binary, double punches are ignored. - - Bit order, left to right, is 12, 11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9. - The for loop works right to left, so the table is reversed. */ - -static const char row_val[12] = { - 011, 010, 007, 006, 005, 004, - 003, 002, 001, 020, 040, 060 - }; - -char colbin_to_bcd (uint32 cb) -{ -uint32 i; -char bcd; - -for (i = 0, bcd = 0; i < 12; i++) { /* 'sum' rows */ - if (cb & (1 << i)) - bcd |= row_val[i]; - } -return bcd; -} diff --git a/I7094/i7094_clk.c b/I7094/i7094_clk.c deleted file mode 100644 index 311757fb..00000000 --- a/I7094/i7094_clk.c +++ /dev/null @@ -1,137 +0,0 @@ -/* i7094_clk.c: IBM 7094 clock - - Copyright (c) 2003-2011, 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. - - clk RPQ F89349 interval timer - Chronolog calendar clock - - 25-Mar-11 RMS According to RPQ, clock clears on RESET -*/ - -#include "i7094_defs.h" -#include - -uint32 chtr_clk = 0; -extern t_uint64 *M; - -t_stat clk_svc (UNIT *uptr); -t_stat clk_reset (DEVICE *dptr); -uint8 bcd_2d (uint32 n, uint8 *b2); - -/* CLK data structures - - clk_dev CLK device descriptor - clk_unit CLK unit - clk_reg CLK register list -*/ - -UNIT clk_unit = { UDATA (&clk_svc, 0, 0), 16000 }; - -REG clk_reg[] = { - { FLDATA (TRAP, chtr_clk, 0) }, - { DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT }, - { NULL } - }; - -DEVICE clk_dev = { - "CLK", &clk_unit, clk_reg, NULL, - 1, 0, 0, 0, 0, 0, - NULL, NULL, &clk_reset, - NULL, NULL, NULL, - NULL, DEV_DISABLE+DEV_DIS - }; - -/* Clock unit service */ - -t_stat clk_svc (UNIT *uptr) -{ -t_uint64 ctr; - -if ((clk_dev.flags & DEV_DIS) == 0) { /* clock enabled? */ - ctr = ReadP (CLK_CTR); - ctr = (ctr + 1) & MMASK; /* increment */ - WriteP (CLK_CTR, ctr); - if (ctr == 0) /* overflow? req trap */ - chtr_clk = 1; - sim_rtcn_calb (CLK_TPS, TMR_CLK); /* calibrate clock */ - sim_activate_after (uptr, 1000000/CLK_TPS); /* reactivate unit */ - } -return SCPE_OK; -} - -/* Chronolog clock */ - -uint32 chrono_rd (uint8 *buf, uint32 bufsiz) -{ -time_t curtim; -t_uint64 ctr; -struct tm *tptr; - -if (bufsiz < 12) - return 0; -curtim = time (NULL); /* get time */ -tptr = localtime (&curtim); /* decompose */ -if (tptr == NULL) /* error? */ - return 0; - -buf[0] = bcd_2d (tptr->tm_mon + 1, buf + 1); -buf[2] = bcd_2d (tptr->tm_mday, buf + 3); -buf[4] = bcd_2d (tptr->tm_hour, buf + 5); -buf[6] = bcd_2d (tptr->tm_min, buf + 7); -buf[8] = bcd_2d (tptr->tm_sec, buf + 9); -ctr = ReadP (CLK_CTR); -buf[10] = bcd_2d ((uint32) (ctr % 60), buf + 11); -return 12; -} - -/* Convert number (0-99) to BCD */ - -uint8 bcd_2d (uint32 n, uint8 *b2) -{ -uint8 d1, d2; - -d1 = n / 10; -d2 = n % 10; -if (d1 == 0) - d1 = BCD_ZERO; -if (d2 == 0) - d2 = BCD_ZERO; -if (b2 != NULL) - *b2 = d2; -return d1; -} - -/* Reset routine */ - -t_stat clk_reset (DEVICE *dptr) -{ -chtr_clk = 0; -if (clk_dev.flags & DEV_DIS) - sim_cancel (&clk_unit); -else { - sim_activate (&clk_unit, sim_rtcn_init (clk_unit.wait, TMR_CLK)); - WriteP (CLK_CTR, 0); - } -return SCPE_OK; -} diff --git a/I7094/i7094_com.c b/I7094/i7094_com.c deleted file mode 100644 index 2bf1cef3..00000000 --- a/I7094/i7094_com.c +++ /dev/null @@ -1,1213 +0,0 @@ -/* i7094_com.c: IBM 7094 7750 communications interface simulator - - Copyright (c) 2005-2017, 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. - - com 7750 controller - coml 7750 lines - - 07-Apr-17 RMS Fixed typo in accessing unit array (COVERITY) - 12-Aug-10 RMS Major rewrite for CTSS (Dave Pitts) - 19-Nov-08 RMS Revised for common TMXR show routines - - This module implements an abstract simulator for the IBM 7750 communications - computer as used by the CTSS system. The 7750 supports up to 112 lines; - the simulator supports 33. The 7750 can handle both high-speed lines, in - 6b and 12b mode, and normal terminals, in 12b mode only; the simulator - supports only terminals. The 7750 can handle many different kinds of - terminals; the simulator supports only a limited subset. - - Input is asynchronous and line buffered. When valid input (a line or a - control message) is available, the 7750 sets ATN1 to signal availability of - input. When the 7094 issues a CTLRN, the 7750 gathers available input characters - into a message. The message has a 12b sequence number, followed by 12b line - number/character pairs, followed by end-of-medium (03777). Input characters - can either be control characters (bit 02000 set) or data characters. Data - characters are 1's complemented and are 8b wide: 7 data bits and 1 parity - bit (which may be 0). - - Output is synchronous. When the 7094 issues a CTLWN, the 7750 interprets - the channel output as a message. The message has a 12b line number, followed - by a 12b character count, followed by characters, followed by end-of-medium. - If bit 02000 of the line number is set, the characters are 12b wide. If - bit 01000 is set, the message is a control message. 12b characters consist - of 7 data bits, 1 parity bit, and 1 start bit. Data characters are 1's - complemented. Data character 03777 is special and causes the 7750 to - repeat the previous bit for the number of bit times specified in the next - character. This is used to generate delays for positioning characters. - - The 7750 supports flow control for output. To help the 7094 account for - usage of 7750 buffer memory, the 7750 sends 'character output completion' - messages for every 'n' characters output on a line, where n <= 31. - - Note that the simulator console is mapped in as line n+1. -*/ - -#include "i7094_defs.h" -#include "sim_sock.h" -#include "sim_tmxr.h" -#include - -#define COM_MLINES 31 /* mux lines */ -#define COM_TLINES (COM_MLINES + 1) /* total lines */ -#define COM_BUFSIZ 120 /* max chan transfer */ -#define COM_PKTSIZ 16384 /* character buffer */ - -#define UNIT_V_2741 (TTUF_V_UF + 0) /* 2741 - ni */ -#define UNIT_V_K35 (TTUF_V_UF + 1) /* KSR-35 */ -#define UNIT_2741 (1 << UNIT_V_2741) -#define UNIT_K35 (1 << UNIT_V_K35) - -#define CONN u3 /* line is connected */ -#define NEEDID u4 /* need to send ID */ -#define NOECHO u5 /* no echo */ -#define INPP u6 /* input pending */ - -#define COM_INIT_POLL 8000 /* polling interval */ -#define COMC_WAIT 2 /* channel delay time */ -#define COML_WAIT 1000 /* char delay time */ -#define COM_LBASE 4 /* start of lines */ - -/* Input threads */ - -#define COM_PLU 0 /* multiplexor poll */ -#define COM_CIU 1 /* console input */ -#define COM_CHU 2 /* channel transfer */ -#define COM_SNS 3 /* sense transfer */ - -/* Communications input */ - -#define COMI_VALIDL 02000 /* valid line flag */ -#define COMI_PARITY 00200 /* parity bit */ -#define COMI_DIALUP 02001 /* dialup */ -#define COMI_ENDID 02002 /* end ID */ -#define COMI_INTR 02003 /* interrupt */ -#define COMI_QUIT 02004 /* quit */ -#define COMI_HANGUP 02005 /* hangup */ -#define COMI_EOM 03777 /* end of medium */ -#define COMI_COMP(x) ((uint16) (03000 + ((x) & COMI_CMAX))) -#define COMI_K35 1 /* KSR-35 ID */ -#define COMI_K37 7 /* KSR-37 ID */ -#define COMI_2741 8 /* 2741 ID */ -#define COMI_CMAX 31 /* max chars returned */ -#define COMI_BMAX 50 /* buffer max, words */ -#define COMI_12BMAX ((3 * COMI_BMAX) - 1) /* last 12b char */ - -/* Communications output */ - -#define COMO_LIN12B INT64_C(0200000000000) /* line is 12b */ -#define COMO_LINCTL INT64_C(0100000000000) /* control msg */ -#define COMO_GETLN(x) (((uint32) ((x) >> 24)) & 0777) -#define COMO_CTLRST 00000 /* control reset */ -#define COMO_BITRPT 03777 /* bit repeat */ -#define COMO_EOM12B 07777 /* end of medium */ -#define COMO_BMAX 94 /* buffer max, words */ -#define COMO_12BMAX ((3 * COMO_BMAX) - 1) - -/* Status word (60b) */ - -#define COMS_PCHK INT64_C(004000000000000000000) /* prog check */ -#define COMS_DCHK INT64_C(002000000000000000000) /* data check */ -#define COMS_EXCC INT64_C(001000000000000000000) /* exc cond */ -#define COMS_MLNT INT64_C(000040000000000000000) /* message length check */ -#define COMS_CHNH INT64_C(000020000000000000000) /* channel hold */ -#define COMS_CHNQ INT64_C(000010000000000000000) /* channel queue full */ -#define COMS_ITMO INT64_C(000000100000000000000) /* interface timeout */ -#define COMS_DATR INT64_C(000000004000000000000) /* data message ready */ -#define COMS_INBF INT64_C(000000002000000000000) /* input buffer free */ -#define COMS_SVCR INT64_C(000000001000000000000) /* service message ready */ -#define COMS_PALL INT64_C(000000000000000000000) -#define COMS_DALL INT64_C(000000000000000000000) -#define COMS_EALL INT64_C(000000000000000000000) -#define COMS_DYN INT64_C(000000007000000000000) - -/* Report variables */ - -#define COMR_FQ 1 /* free queue */ -#define COMR_IQ 2 /* input queue */ -#define COMR_OQ 4 /* output queue */ - -/* List heads and entries */ - -typedef struct { - uint16 head; - uint16 tail; - } LISTHD; - -typedef struct { - uint16 next; - uint16 data; - } LISTENT; - -/* The 7750 character buffer is maintained as linked lists. The lists are: - - free free list - inpq[ln] input queue for line n - outq[ln] output queue for line ln - - Links are done as subscripts in array com_pkt. This allows the list - headers and the queues themselves to be saved and restored. */ - -uint32 com_ch = CH_E; /* saved channel */ -uint32 com_enab = 0; /* 7750 enabled */ -uint32 com_msgn = 0; /* next input msg num */ -uint32 com_sta = 0; /* 7750 state */ -uint32 com_stop = 0; /* channel stop */ -uint32 com_quit = 003; /* quit code */ -uint32 com_intr = 0; /* interrupt code */ -uint32 com_bptr = 0; /* buffer pointer */ -uint32 com_blim = 0; /* buffer count */ -uint32 com_tps = 50; /* polls/second */ -t_uint64 com_sns = 0; /* sense word */ -t_uint64 com_chob = 0; /* chan output buf */ -uint32 com_chob_v = 0; /* valid flag */ -t_uint64 com_buf[COM_BUFSIZ]; /* channel buffer */ -LISTHD com_free; /* free list */ -uint32 com_not_ret[COM_TLINES] = { 0 }; /* chars not returned */ -LISTHD com_inpq[COM_TLINES] = { {0} }; /* input queues */ -LISTHD com_outq[COM_TLINES] = { {0} }; /* output queues */ -LISTENT com_pkt[COM_PKTSIZ]; /* character packets */ -TMLN com_ldsc[COM_MLINES] = { {0} }; /* line descriptors */ -TMXR com_desc = { COM_MLINES, 0, 0, com_ldsc }; /* mux descriptor */ - -/* Even parity truth table */ - -static const uint8 com_epar[128] = { - 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1 - }; - -extern uint32 ch_req; - -t_stat com_chsel (uint32 ch, uint32 sel, uint32 unit); -t_stat com_chwr (uint32 ch, t_uint64 val, uint32 flags); -t_stat comi_svc (UNIT *uptr); -t_stat comc_svc (UNIT *uptr); -t_stat como_svc (UNIT *uptr); -t_stat coms_svc (UNIT *uptr); -t_stat comti_svc (UNIT *uptr); -t_stat comto_svc (UNIT *uptr); -t_stat com_reset (DEVICE *dptr); -t_stat com_attach (UNIT *uptr, char *cptr); -t_stat com_detach (UNIT *uptr); -t_stat com_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat com_show_freeq (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat com_show_allq (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat com_show_oneq (FILE *st, UNIT *uptr, int32 val, void *desc); -void com_reset_ln (uint32 i); -uint16 com_get_nexti (uint32 *ln); -uint16 com_gethd_free (LISTHD *lh); -uint16 com_gethd (LISTHD *lh); -uint16 com_gettl_free (LISTHD *lh); -uint16 com_gettl (LISTHD *lh); -t_bool com_new_puttl (LISTHD *lh, uint16 val); -void com_puttl (LISTHD *lh, uint16 ent); -t_bool com_test_inp (void); -void com_set_inpp (uint32 ln); -t_uint64 com_getob (uint32 ch); -t_bool com_qdone (uint32 ch); -void com_end (uint32 ch, uint32 fl, uint32 st); -t_stat com_send_id (uint32 ln); -uint32 com_gen_ccmp (uint32 ln); -t_bool com_queue_in (uint32 ln, uint32 ch); -uint32 com_queue_out (uint32 ln, uint32 *c1); -void com_set_sns (t_uint64 stat); - -/* COM data structures - - com_dev COM device descriptor - com_unit COM unit descriptor - com_reg COM register list - com_mod COM modifiers list -*/ - -DIB com_dib = { &com_chsel, &com_chwr }; - -UNIT com_unit[] = { - { UDATA (&comi_svc, UNIT_ATTABLE, 0), COM_INIT_POLL }, - { UDATA (&comti_svc, UNIT_DIS, 0), KBD_POLL_WAIT }, - { UDATA (&comc_svc, UNIT_DIS, 0), COMC_WAIT }, - { UDATA (&coms_svc, UNIT_DIS, 0), COMC_WAIT } - }; - -UNIT coml_unit[] = { - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&como_svc, 0, 0), COML_WAIT }, - { UDATA (&comto_svc, 0, 0), COML_WAIT }, - }; - -REG com_reg[] = { - { FLDATA (ENABLE, com_enab, 0) }, - { ORDATA (STATE, com_sta, 6) }, - { ORDATA (MSGNUM, com_msgn, 12) }, - { ORDATA (SNS, com_sns, 60) }, - { ORDATA (CHOB, com_chob, 36) }, - { FLDATA (CHOBV, com_chob_v, 0) }, - { FLDATA (STOP, com_stop, 0) }, - { ORDATA (QUIT, com_quit, 7) }, - { ORDATA (INTR, com_intr, 7) }, - { BRDATA (BUF, com_buf, 8, 36, COM_BUFSIZ) }, - { DRDATA (BPTR, com_bptr, 7), REG_RO }, - { DRDATA (BLIM, com_blim, 7), REG_RO }, - { BRDATA (NRET, com_not_ret, 10, 32, COM_TLINES), REG_RO + PV_LEFT }, - { URDATA (NEEDID, coml_unit[0].NEEDID, 8, 1, 0, COM_TLINES, 0) }, - { URDATA (NOECHO, coml_unit[0].NOECHO, 8, 1, 0, COM_TLINES, 0) }, - { URDATA (INPP, coml_unit[0].INPP, 8, 1, 0, COM_TLINES, 0) }, - { BRDATA (FREEQ, &com_free, 10, 16, 2) }, - { BRDATA (INPQ, com_inpq, 10, 16, 2 * COM_TLINES) }, - { BRDATA (OUTQ, com_outq, 10, 16, 2 * COM_TLINES) }, - { BRDATA (PKTB, com_pkt, 10, 16, 2 * COM_PKTSIZ) }, - { DRDATA (TTIME, com_unit[COM_CIU].wait, 24), REG_NZ + PV_LEFT }, - { DRDATA (WTIME, com_unit[COM_CHU].wait, 24), REG_NZ + PV_LEFT }, - { DRDATA (CHAN, com_ch, 3), REG_HRO }, - { NULL } - }; - -MTAB com_mod[] = { - { UNIT_ATT, UNIT_ATT, "summary", NULL, - NULL, &tmxr_show_summ, (void *) &com_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, - NULL, &tmxr_show_cstat, (void *) &com_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, - NULL, &tmxr_show_cstat, (void *) &com_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, COMR_FQ, "FREEQ", NULL, - NULL, &com_show_ctrl, 0 }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, COMR_IQ, "INPQ", NULL, - NULL, &com_show_ctrl, 0 }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, COMR_OQ, "OUTQ", NULL, - NULL, &com_show_ctrl, 0 }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0xFFFFFFFF, "ALL", NULL, - NULL, &com_show_ctrl, 0 }, - { 0 } - }; - -DEVICE com_dev = { - "COM", com_unit, com_reg, com_mod, - 3, 10, 31, 1, 16, 8, - &tmxr_ex, &tmxr_dep, &com_reset, - NULL, &com_attach, &com_detach, - &com_dib, DEV_MUX | DEV_DIS - }; - -/* COML data structures - - coml_dev COML device descriptor - coml_unit COML unit descriptor - coml_reg COML register list - coml_mod COML modifiers list -*/ - -MTAB coml_mod[] = { - { UNIT_K35+UNIT_2741, 0 , "KSR-37", "KSR-37", NULL }, - { UNIT_K35+UNIT_2741, UNIT_K35 , "KSR-35", "KSR-35", NULL }, -// { UNIT_K35+UNIT_2741, UNIT_2741, "2741", "2741", NULL }, - { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT", - &tmxr_dscln, NULL, (void *) &com_desc }, - { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG", - &tmxr_set_log, &tmxr_show_log, (void*) &com_desc }, - { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG", - &tmxr_set_nolog, NULL, (void *) &com_desc }, - { MTAB_XTD | MTAB_VUN | MTAB_NMO, 0, "INPQ", NULL, - NULL, &com_show_oneq, 0 }, - { MTAB_XTD | MTAB_VUN | MTAB_NMO, 1, "OUTQ", NULL, - NULL, &com_show_oneq, 0 }, - { 0 } - }; - -REG coml_reg[] = { - { URDATA (TIME, coml_unit[0].wait, 10, 24, 0, - COM_TLINES, REG_NZ + PV_LEFT) }, - { NULL } - }; - -DEVICE coml_dev = { - "COML", coml_unit, coml_reg, coml_mod, - COM_TLINES, 10, 31, 1, 16, 8, - NULL, NULL, &com_reset, - NULL, NULL, NULL, - NULL, DEV_DIS - }; - -/* COM: channel select */ - -t_stat com_chsel (uint32 ch, uint32 sel, uint32 unit) -{ -com_ch = ch; /* save channel */ -if (sim_is_active (&com_unit[COM_CHU]) || /* not idle? */ - sim_is_active (&com_unit[COM_SNS])) { - com_end (ch, CHINT_SEQC, 0); /* end, seq check */ - return SCPE_OK; - } - -switch (sel) { /* case on select */ - - case CHSL_RDS: /* read */ - case CHSL_WRS: /* write */ - com_sns = 0; /* clear status */ - sim_activate (&com_unit[COM_CHU], com_unit[COM_CHU].wait); - break; - - case CHSL_SNS: /* sense */ - sim_activate (&com_unit[COM_SNS], com_unit[COM_SNS].wait); - break; - - case CHSL_CTL: /* control */ - default: /* other */ - return STOP_ILLIOP; - } - -com_stop = 0; /* clear stop */ -com_sta = sel; /* set initial state */ -return SCPE_OK; -} - -/* Channel write, from 7909 channel program */ - -t_stat com_chwr (uint32 ch, t_uint64 val, uint32 stopf) -{ -if (stopf) - com_stop = 1; -else { - com_chob = val; /* store data */ - com_chob_v = 1; /* set valid */ - } -return SCPE_OK; -} - -/* Unit service - SNS */ - -t_stat coms_svc (UNIT *uptr) -{ -t_uint64 dat; - -switch (com_sta) { /* case on state */ - - case CHSL_SNS: /* prepare data */ - com_sns &= ~COMS_DYN; /* clear dynamic flags */ - if (com_free.head) /* free space? */ - com_set_sns (COMS_INBF); - if (com_test_inp ()) /* pending input? */ - com_set_sns (COMS_DATR); - com_buf[0] = (com_sns >> 24) & DMASK; /* buffer is 2 words */ - com_buf[1] = (com_sns << 12) & DMASK; - com_bptr = 0; - com_blim = 2; - com_sta = CHSL_SNS|CHSL_2ND; /* 2nd state */ - break; - - case CHSL_SNS|CHSL_2ND: /* second state */ - if (com_bptr >= com_blim) { /* end of buffer? */ - ch9_set_end (com_ch, 0); /* set end */ - ch_req |= REQ_CH (com_ch); /* request channel */ - com_sta = CHSL_SNS|CHSL_3RD; /* 3rd state */ - sim_activate (uptr, 10 * uptr->wait); /* longer wait */ - return SCPE_OK; - } - dat = com_buf[com_bptr++]; /* get word */ - if (!com_stop) /* send wd to chan */ - ch9_req_rd (com_ch, dat); - break; - - case CHSL_SNS|CHSL_3RD: /* 3rd state */ - if (com_qdone (com_ch)) /* done? exit */ - return SCPE_OK; - com_sta = CHSL_SNS; /* repeat sequence */ - break; - } - -sim_activate (uptr, uptr->wait); /* sched next */ -return SCPE_OK; -} - -/* Unit service - channel program */ - -t_stat comc_svc (UNIT *uptr) -{ -uint32 i, j, k, ccnt, ln, uln; -uint16 chr, ent; -t_uint64 dat; - -switch (com_sta) { /* case on state */ - - case CHSL_RDS: /* read start */ - for (i = 0; i < COM_BUFSIZ; i++) /* clear chan buf */ - com_buf[i] = 0; - com_buf[0] = com_msgn; /* 1st char is msg num */ - com_msgn = (com_msgn + 1) & 03777; /* incr msg num */ - for (i = 1, j = 0, ln = 0; /* check all lines */ - (ln < COM_TLINES) && (i < COMI_12BMAX); /* until buffer full */ - ln++) { - chr = (uint16) com_gen_ccmp (ln); /* completion msg? */ - if ((chr == 0) && coml_unit[ln].INPP) { /* no, line input? */ - ent = com_gethd_free (&com_inpq[ln]); /* get first char */ - if (ent != 0) /* any input? */ - chr = com_pkt[ent].data; /* return char */ - else coml_unit[ln].INPP = 0; /* this line is idle */ - } /* end if input pending */ - if (chr != 0) { /* got something? */ - if ((i++ % 3) == 0) /* next word? */ - j++; - com_buf[j] = (com_buf[j] << 12) | /* pack line number */ - ((t_uint64) ((ln + COM_LBASE) | COMI_VALIDL)); - if ((i++ % 3) == 0) /* next word? */ - j++; - com_buf[j] = (com_buf[j] << 12) | /* pack data */ - ((t_uint64) (chr & 07777)); - } /* end if char */ - } /* end for buffer */ - for (k = i % 3; k < 3; k++) { /* fill with EOM */ - if (k == 0) /* next word? */ - j++; - com_buf[j] = (com_buf[j] << 12) | COMI_EOM; - } - com_bptr = 0; /* init buf ptr */ - com_blim = j + 1; /* save buf size */ - com_sta = CHSL_RDS|CHSL_2ND; /* next state */ - break; - - case CHSL_RDS|CHSL_2ND: /* read xmit word */ - if (com_bptr >= com_blim) /* transfer done? */ - com_end (com_ch, 0, CHSL_RDS|CHSL_3RD); /* end, next state */ - else { /* more to do */ - dat = com_buf[com_bptr++]; /* get word */ - if (!com_stop) /* give to channel */ - ch9_req_rd (com_ch, dat); - } - break; - - case CHSL_RDS|CHSL_3RD: /* read end */ - if (com_qdone (com_ch)) { /* done? */ - if (com_test_inp ()) /* more data waiting? */ - ch9_set_atn (com_ch); - return SCPE_OK; /* exit */ - } - com_sta = CHSL_RDS; /* repeat sequence */ - break; - - case CHSL_WRS: /* write start */ - for (i = 0; i < COM_BUFSIZ; i++) /* clear chan buf */ - com_buf[i] = 0; - com_bptr = 0; /* init buf ptr */ - com_sta = CHSL_WRS|CHSL_2ND; /* next state */ - ch_req |= REQ_CH (com_ch); /* request channel */ - com_chob = 0; /* clr, inval buf */ - com_chob_v = 0; - break; - - case CHSL_WRS|CHSL_2ND: /* write first word */ - dat = com_getob (com_ch); /* get word? */ - if (dat == INT64_C(0777777777777)) { /* turn on? */ - com_enab = 1; /* enable 7750 */ - com_msgn = 0; /* init message # */ - com_end (com_ch, 0, CHSL_WRS|CHSL_4TH); /* end, last state */ - } - else if (dat & COMO_LINCTL) { /* control message? */ - ln = COMO_GETLN (dat); /* line number */ - if (ln >= (COM_TLINES + COM_LBASE)) /* invalid line? */ - return STOP_INVLIN; - chr = (uint16) ((dat >> 12) & 07777); /* control message */ - if (chr != COMO_CTLRST) /* char must be 0 */ - return STOP_INVMSG; - if (ln >= COM_LBASE) - com_reset_ln (ln - COM_LBASE); - com_end (com_ch, 0, CHSL_WRS|CHSL_4TH); /* end, last state */ - } - else { /* data message */ - ccnt = (((uint32) dat >> 12) & 07777) + 1; /* char count plus EOM */ - if (dat & COMO_LIN12B) /* 12b? double */ - ccnt = ccnt << 1; - com_blim = (ccnt + 6 + 5) / 6; /* buffer limit */ - if ((com_blim == 1) || (com_blim >= COMO_BMAX)) - return STOP_INVMSG; - com_buf[com_bptr++] = dat; /* store word */ - com_sta = CHSL_WRS|CHSL_3RD; /* next state */ - ch_req |= REQ_CH (com_ch); /* request channel */ - } - break; - - case CHSL_WRS|CHSL_3RD: /* other words */ - dat = com_getob (com_ch); /* get word */ - com_buf[com_bptr++] = dat; /* store word */ - if (com_bptr >= com_blim) { /* transfer done? */ - ln = COMO_GETLN (com_buf[0]); /* line number */ - if (ln >= (COM_TLINES + COM_LBASE)) /* invalid line? */ - return STOP_INVLIN; - if ((com_buf[0] & COMO_LIN12B) && /* 12b message? */ - (ln >= COM_LBASE)) { - uln = ln - COM_LBASE; /* unit number */ - for (i = 2, j = 0; i < COMO_12BMAX; i++) { /* unpack 12b char */ - if ((i % 3) == 0) - j++; - chr = (uint16) (com_buf[j] >> ((2 - (i % 3)) * 12)) & 07777; - if (chr == COMO_EOM12B) /* EOM? */ - break; - if (!com_new_puttl (&com_outq[uln], chr)) - return STOP_NOOFREE; /* append to outq */ - } - sim_activate (&coml_unit[uln], coml_unit[uln].wait); - } - com_end (com_ch, 0, CHSL_WRS|CHSL_4TH); /* end, last state */ - } - else if (!com_stop) /* request channel */ - ch_req |= REQ_CH (com_ch); - break; - - case CHSL_WRS|CHSL_4TH: /* buffer done */ - if (com_qdone (com_ch)) /* done? */ - return SCPE_OK; /* exit */ - com_sta = CHSL_WRS; /* repeat sequence */ - break; - - default: - return SCPE_IERR; - } - -sim_activate (uptr, uptr->wait); -return SCPE_OK; -} - -/* Unit service - console receive - always running, even if device is not */ - -t_stat comti_svc (UNIT *uptr) -{ -int32 c, ln = COM_MLINES; -uint16 ent; - -sim_activate (uptr, uptr->wait); /* continue poll */ -c = sim_poll_kbd (); /* get character */ -if (c && !(c & (SCPE_BREAK|SCPE_KFLAG))) /* error? */ - return c; -if (!com_enab || (c & SCPE_BREAK)) /* !enab, break? done */ - return SCPE_OK; -if (coml_unit[ln].NEEDID) /* ID needed? */ - return com_send_id (ln); -if ((c & SCPE_KFLAG) && ((c = c & 0177) != 0)) { /* char input? */ - if ((c == 0177) || (c == '\b')) { /* delete? */ - ent = com_gettl_free (&com_inpq[ln]); /* remove last char */ - if (!coml_unit[ln].NOECHO) - sim_putchar (ent? '\b': '\a'); - return SCPE_OK; - } - if (!com_queue_in (ln, c)) /* add to inp queue */ - return STOP_NOIFREE; - if (!coml_unit[ln].NOECHO) { /* echo enabled? */ - if (sim_tt_outcvt (c, TT_MODE_7P) >= 0) /* printable? */ - sim_putchar (c); - if (c == '\r') /* line end? */ - sim_putchar ('\n'); - } - } -return SCPE_OK; /* set ATN if input */ -} - -/* Unit service - receive side - - Poll all active lines for input - Poll for new connections */ - -t_stat comi_svc (UNIT *uptr) -{ -int32 c, ln, t; -uint16 ent; - -if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ - return SCPE_OK; -t = sim_rtcn_calb (com_tps, TMR_COM); /* calibrate */ -sim_activate (uptr, t); /* continue poll */ -if (!com_enab) /* not enabled? exit */ - return SCPE_OK; -ln = tmxr_poll_conn (&com_desc); /* look for connect */ -if (ln >= 0) { /* got one? */ - com_ldsc[ln].rcve = 1; /* rcv enabled */ - coml_unit[ln].CONN = 1; /* flag connected */ - coml_unit[ln].NEEDID = 1; /* need ID */ - coml_unit[ln].NOECHO = 0; /* echo enabled */ - coml_unit[ln].INPP = 0; /* no input pending */ - } -tmxr_poll_rx (&com_desc); /* poll for input */ -for (ln = 0; ln < COM_MLINES; ln++) { /* loop thru mux */ - if (com_ldsc[ln].conn) { /* connected? */ - if (coml_unit[ln].NEEDID) - return com_send_id (ln); - c = tmxr_getc_ln (&com_ldsc[ln]); /* get char */ - if (c) { /* any char? */ - c = c & 0177; /* mask to 7b */ - if ((c == 0177) || (c == '\b')) { /* delete? */ - ent = com_gettl_free (&com_inpq[ln]); /* remove last char */ - if (!coml_unit[ln].NOECHO) - tmxr_putc_ln (&com_ldsc[ln], ent? '\b': '\a'); - return SCPE_OK; - } - if (!com_queue_in (ln, c)) /* queue char, err? */ - return STOP_NOIFREE; - if (com_ldsc[ln].xmte) { /* output enabled? */ - if (!coml_unit[ln].NOECHO) { /* echo enabled? */ - if (sim_tt_outcvt (c, TT_MODE_7P) >= 0) - tmxr_putc_ln (&com_ldsc[ln], c); - if (c == '\r') /* add LF after CR */ - tmxr_putc_ln (&com_ldsc[ln], '\n'); - } - tmxr_poll_tx (&com_desc); /* poll xmt */ - } /* end if enabled */ - } /* end if char */ - } /* end if conn */ - else if (coml_unit[ln].CONN) { /* not conn, was conn? */ - coml_unit[ln].CONN = 0; /* clear connected */ - coml_unit[ln].NEEDID = 0; /* clear need id */ - com_set_inpp (ln); /* input pending, ATN1 */ - if (!com_new_puttl (&com_inpq[ln], COMI_HANGUP))/* hangup message */ - return STOP_NOIFREE; - } - } /* end for */ -return SCPE_OK; -} - -/* Unit service - console transmit */ - -t_stat comto_svc (UNIT *uptr) -{ -uint32 ln = COM_MLINES; -uint32 c, c1; - -c = com_queue_out (ln, &c1); /* get character, cvt */ -if (c) /* printable? output */ - sim_putchar (c); -if (c1) /* second char? output */ - sim_putchar (c1); -if (com_outq[ln].head == 0) /* line idle? */ - ch9_set_atn (com_ch); /* set ATN1 */ -else sim_activate (uptr, uptr->wait); /* next char */ -return SCPE_OK; -} - -/* Unit service - transmit side */ - -t_stat como_svc (UNIT *uptr) -{ -uint32 c, c1; -int32 ln = uptr - coml_unit; /* line # */ - -if (com_ldsc[ln].conn) { /* connected? */ - if (com_ldsc[ln].xmte) { /* output enabled? */ - c = com_queue_out (ln, &c1); /* get character, cvt */ - if (c) /* printable? output */ - tmxr_putc_ln (&com_ldsc[ln], c); - if (c1) /* print second */ - tmxr_putc_ln (&com_ldsc[ln], c1); - } /* end if */ - tmxr_poll_tx (&com_desc); /* poll xmt */ - if (com_outq[ln].head == 0) /* line idle? */ - ch9_set_atn (com_ch); /* set ATN1 */ - else sim_activate (uptr, uptr->wait); /* next char */ - } /* end if conn */ -return SCPE_OK; -} - -/* Send ID sequence on input */ - -t_stat com_send_id (uint32 ln) -{ -com_new_puttl (&com_inpq[ln], COMI_DIALUP); /* input message: */ -if (coml_unit[ln].flags & UNIT_K35) /* dialup, ID, endID */ - com_new_puttl (&com_inpq[ln], COMI_K35); -else com_new_puttl (&com_inpq[ln], COMI_K37); -com_new_puttl (&com_inpq[ln], 0); -com_new_puttl (&com_inpq[ln], 0); -com_new_puttl (&com_inpq[ln], 0); -com_new_puttl (&com_inpq[ln], 0); -com_new_puttl (&com_inpq[ln], (uint16) (ln + COM_LBASE)); -if (!com_new_puttl (&com_inpq[ln], COMI_ENDID)) /* make sure there */ - return STOP_NOIFREE; /* was room for msg */ -coml_unit[ln].NEEDID = 0; -com_set_inpp (ln); /* input pending, ATN1 */ -return SCPE_OK; -} - -/* Translate and queue input character */ - -t_bool com_queue_in (uint32 ln, uint32 c) -{ -uint16 out; - -if (c == com_intr) { - out = COMI_INTR; - com_set_inpp (ln); - } -else if (c == com_quit) { - out = COMI_QUIT; - com_set_inpp (ln); - } -else { - if (c == '\r') - com_set_inpp (ln); - if (coml_unit[ln].flags & UNIT_K35) { /* KSR-35? */ - if (islower (c)) /* convert LC to UC */ - c = toupper (c); - } - else c |= (com_epar[c]? COMI_PARITY: 0); /* add even parity */ - out = (~c) & 0377; /* 1's complement */ - } -return com_new_puttl (&com_inpq[ln], out); /* input message */ -} - -/* Retrieve and translate output character */ - -uint32 com_queue_out (uint32 ln, uint32 *c1) -{ -uint32 c, ent, raw; - -*c1 = 0; /* assume non-printing */ -if ((ent = com_gethd_free (&com_outq[ln])) == 0) /* get character */ - return 0; /* nothing, exit */ -raw = com_pkt[ent].data; /* get 12b character */ -com_not_ret[ln]++; -if (raw == COMO_BITRPT) { /* insert delay? */ - if (com_gethd_free (&com_outq[ln])) /* skip next char */ - com_not_ret[ln]++; /* and count it */ - return 0; - } -c = (~raw >> 1) & 0177; /* remove start, parity */ -if ((c >= 040) && (c != 0177)) { /* printable? */ - if ((coml_unit[ln].flags & UNIT_K35) && islower (c))/* KSR-35 LC? */ - c = toupper (c); /* cvt to UC */ - return c; - } -switch (c) { - - case '\t': case '\f': case '\b': case '\a': /* valid ctrls */ - return c; - - case '\r': /* carriage return? */ - *c1 = '\n'; /* lf after cr */ - return c; - - case '\n': /* line feed? */ - *c1 = '\n'; /* lf after cr */ - return '\r'; - - case 022: /* DC2 */ - coml_unit[ln].NOECHO = 1; - return 0; - - case 024: /* DC4 */ - coml_unit[ln].NOECHO = 0; - return 0; - } - -return 0; /* ignore others */ -} - -/* Generate completion message, if needed */ - -uint32 com_gen_ccmp (uint32 ln) -{ -uint32 t; - -if ((t = com_not_ret[ln]) != 0) { /* chars not returned? */ - if (t > COMI_CMAX) /* limit to max */ - t = COMI_CMAX; - com_not_ret[ln] -= t; /* keep count */ - return COMI_COMP (t); /* gen completion msg */ - } -return 0; -} - -/* Read and validate output buffer */ - -t_uint64 com_getob (uint32 ch) -{ -if (com_chob_v) /* valid? clear */ - com_chob_v = 0; -else if (!com_stop) { /* not stopped? */ - ch9_set_ioc (com_ch); /* IO check */ - com_set_sns (COMS_ITMO); /* set sense bit */ - } -return com_chob; -} - -/* Test whether input pending */ - -t_bool com_test_inp (void) -{ -uint32 i; - -for (i = 0; i < COM_TLINES; i++) { - if ((com_not_ret[i] != 0) || coml_unit[i].INPP) - return TRUE; - } -return FALSE; -} - -/* Set input pending and attention */ - -void com_set_inpp (uint32 ln) -{ -coml_unit[ln].INPP = 1; -ch9_set_atn (com_ch); -return; -} - -/* Test for done */ - -t_bool com_qdone (uint32 ch) -{ -if (com_stop || !ch9_qconn (ch)) { /* stop or err disc? */ - com_sta = 0; /* ctrl is idle */ - return TRUE; - } -return FALSE; -} - -/* Channel end */ - -void com_end (uint32 ch, uint32 fl, uint32 st) -{ -ch9_set_end (ch, fl); /* set end */ -ch_req |= REQ_CH (ch); -com_sta = st; /* next state */ -return; -} - -/* List routines - remove from head and free */ - -uint16 com_gethd_free (LISTHD *lh) -{ -uint16 ent; - -if ((ent = com_gethd (lh)) != 0) - com_puttl (&com_free, ent); -return ent; -} - -/* Remove from tail and free */ - -uint16 com_gettl_free (LISTHD *lh) -{ -uint16 ent; - -if ((ent = com_gethd (lh)) != 0) - com_puttl (&com_free, ent); -return ent; -} - -/* Get free entry and insert at tail */ - -t_bool com_new_puttl (LISTHD *lh, uint16 val) -{ -uint16 ent; - -if ((ent = com_gethd (&com_free)) != 0) { - com_pkt[ent].data = val; - com_puttl (lh, ent); - return TRUE; - } -return FALSE; -} - -/* Remove from head */ - -uint16 com_gethd (LISTHD *lh) -{ -uint16 ent; - -if ((ent = lh->head) != 0) { - lh->head = com_pkt[ent].next; - if (lh->head == 0) - lh->tail = 0; - } -else lh->tail = 0; -return ent; -} - -/* Remove from tail */ - -uint16 com_gettl (LISTHD *lh) -{ -uint16 ent, next; -uint32 i; - -ent = lh->tail; -if (lh->head == lh->tail) { - lh->head = lh->tail = 0; - return ent; - } -next = lh->head; -for (i = 0; i < COM_PKTSIZ; i++) { - if (com_pkt[next].next == ent) { - com_pkt[next].next = 0; - lh->tail = next; - return ent; - } - } -return 0; -} - -/* Insert at tail */ - -void com_puttl (LISTHD *lh, uint16 ent) -{ -if (lh->tail == 0) - lh->head = ent; -else com_pkt[lh->tail].next = ent; -com_pkt[ent].next = 0; -lh->tail = ent; -return; -} - -/* Set flag in sense */ - -void com_set_sns (t_uint64 stat) -{ -com_sns |= stat; -com_sns &= ~(COMS_PCHK|COMS_DCHK|COMS_EXCC); -if (com_sns & COMS_PALL) - com_sns |= COMS_PCHK; -if (com_sns & COMS_DALL) - com_sns |= COMS_DCHK; -if (com_sns & COMS_EALL) - com_sns |= COMS_EXCC; -return; -} - -/* Reset routine */ - -t_stat com_reset (DEVICE *dptr) -{ -uint32 i; - -if (dptr->flags & DEV_DIS) { /* disabled? */ - com_dev.flags = com_dev.flags | DEV_DIS; /* disable lines */ - coml_dev.flags = coml_dev.flags | DEV_DIS; - } -else { - com_dev.flags = com_dev.flags & ~DEV_DIS; /* enable lines */ - coml_dev.flags = coml_dev.flags & ~DEV_DIS; - } -sim_activate (&com_unit[COM_CIU], com_unit[COM_CIU].wait); /* console */ -sim_cancel (&com_unit[COM_PLU]); -sim_cancel (&com_unit[COM_CHU]); -if (com_unit[COM_PLU].flags & UNIT_ATT) { /* master att? */ - int32 t = sim_rtcn_init (com_unit[COM_PLU].wait, TMR_COM); - sim_activate (&com_unit[COM_PLU], t); - } -com_enab = 0; -com_sns = 0; -com_msgn = 0; -com_sta = 0; -com_chob = 0; -com_chob_v = 0; -com_stop = 0; -com_bptr = 0; -com_blim = 0; -for (i = 0; i < COM_BUFSIZ; i++) - com_buf[i] = 0; -for (i = 0; i < COM_TLINES; i++) { /* init lines */ - com_inpq[i].head = 0; - com_inpq[i].tail = 0; - com_outq[i].head = 0; - com_outq[i].tail = 0; - com_reset_ln (i); - } -com_pkt[0].next = 0; /* init free list */ -for (i = 1; i < COM_PKTSIZ; i++) { - com_pkt[i].next = i + 1; - com_pkt[i].data = 0; - } -com_pkt[COM_PKTSIZ - 1].next = 0; /* end of free list */ -com_free.head = 1; -com_free.tail = COM_PKTSIZ - 1; -coml_unit[COM_MLINES].CONN = 1; /* console always conn */ -coml_unit[COM_MLINES].NEEDID = 1; -return SCPE_OK; -} - -/* Attach master unit */ - -t_stat com_attach (UNIT *uptr, char *cptr) -{ -t_stat r; - -r = tmxr_attach (&com_desc, uptr, cptr); /* attach */ -if (r != SCPE_OK) /* error */ - return r; -sim_rtcn_init (uptr->wait, TMR_COM); -sim_activate (uptr, 100); /* quick poll */ -return SCPE_OK; -} - -/* Detach master unit */ - -t_stat com_detach (UNIT *uptr) -{ -uint32 i; -t_stat r; - -r = tmxr_detach (&com_desc, uptr); /* detach */ -for (i = 0; i < COM_MLINES; i++) /* disable rcv */ - com_ldsc[i].rcve = 0; -sim_cancel (uptr); /* stop poll */ -return r; -} - -/* Reset an individual line */ - -void com_reset_ln (uint32 ln) -{ -while (com_gethd_free (&com_inpq[ln])) ; -while (com_gethd_free (&com_outq[ln])) ; -com_not_ret[ln] = 0; -coml_unit[ln].NEEDID = 0; -coml_unit[ln].NOECHO = 0; -coml_unit[ln].INPP = 0; -sim_cancel (&coml_unit[ln]); -if ((ln < COM_MLINES) && (com_ldsc[ln].conn == 0)) - coml_unit[ln].CONN = 0; -return; -} - -/* Special show commands */ - -uint32 com_show_qsumm (FILE *st, LISTHD *lh, char *name) -{ -uint32 i, next; - -next = lh->head; -for (i = 0; i < COM_PKTSIZ; i++) { - if (next == 0) { - if (i == 0) - fprintf (st, "%s is empty\n", name); - else if (i == 1) - fprintf (st, "%s has 1 entry\n", name); - else fprintf (st, "%s has %d entries\n", name, i); - return i; - } - next = com_pkt[next].next; - } -fprintf (st, "%s is corrupt\n", name); -return 0; -} - -void com_show_char (FILE *st, uint32 ch) -{ -uint32 c; - -fprintf (st, "%03o", ch); -c = (~ch) & 0177; -if (((ch & 07400) == 0) && (c >= 040) && (c != 0177)) - fprintf (st, "[%c]", c); -return; -} - -t_stat com_show_freeq (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -com_show_qsumm (st, &com_free, "Free queue"); -return SCPE_OK; -} - -t_stat com_show_oneq (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -uint32 entc, ln, i, next; -LISTHD *lh; -char name[20]; - -ln = uptr - coml_dev.units; -sprintf (name, val? "Output queue %d": "Input queue %d", ln); -lh = val? &com_outq[ln]: &com_inpq[ln]; -if ((entc = com_show_qsumm (st, lh, name))) { - for (i = 0, next = lh->head; next != 0; - i++, next = com_pkt[next].next) { - if ((i % 8) == 0) - fprintf (st, "%d:\t", i); - com_show_char (st, com_pkt[next].data >> (val? 1: 0)); - fputc ((((i % 8) == 7)? '\n': '\t'), st); - } - if (i % 8) - fputc ('\n', st); - } -return SCPE_OK; -} - -t_stat com_show_allq (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -uint32 i; - -for (i = 0; i < COM_TLINES; i++) - com_show_oneq (st, coml_dev.units + i, val, desc); -return SCPE_OK; -} - -t_stat com_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -if (!com_enab) - fprintf (st, "Controller is not initialized\n"); -if (val & COMR_FQ) - com_show_freeq (st, uptr, 0, desc); -if (val & COMR_IQ) - com_show_allq (st, uptr, 0, desc); -if (val & COMR_OQ) - com_show_allq (st, uptr, 1, desc); -return SCPE_OK; -} diff --git a/I7094/i7094_cpu.c b/I7094/i7094_cpu.c deleted file mode 100644 index f466f78b..00000000 --- a/I7094/i7094_cpu.c +++ /dev/null @@ -1,2476 +0,0 @@ -/* i7094_cpu.c: IBM 7094 CPU simulator - - Copyright (c) 2003-2017, 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. - - cpu 7094 central processor - - 07-Sep-17 RMS Fixed sim_eval declaration in history routine (COVERITY) - 31-Dec-11 RMS Select traps have priority over protect traps - Added SRI, SPI - Fixed user mode and relocation from CTSS RPQ documentation - 16-Jul-10 RMS Fixed user mode protection (Dave Pitts) - Fixed issues in storage nullification mode - 28-Apr-07 RMS Removed clock initialization - 29-Oct-06 RMS Added additional expanded core instructions - 17-Oct-06 RMS Fixed the fix in halt IO wait loop - 16-Jun-06 RMS Fixed bug in halt IO wait loop - - The register state for the 7094 is: - - AC accumulator - MQ multiplier-quotient register - SI storage indicators - KEYS<0:35> front panel keys (switches) - IC<0:14> instruction counter (called PC here) - XR<0:14>[8] index registers (XR[0] is always 0) - SSW<0:5> sense switches - SLT<0:3> sense lights - OVF AC overflow - MQO MQ overflow - DVC divide check - IOC I/O check - TTRAP transfer trap mode - CTRAP copy trap mode (for 709 compatibility) - FTRAP floating trap mode (off is 704 compatibility) - STRAP select trap mode - STORN storage nullifcation mode - MULTI multi-tag mode (7090 compatibility) - - CTSS required a set of special features: memory extension (to 65K), - protection, and relocation. Additional state: - - USER user mode - RELOCM relocation mode - USER_BUF user mode buffer - RELOC_BUF relocation buffer - INST_BASE instruction memory select (A vs B core) - DATA_BASE data memory select (A vs B core) - IND_RELOC<0:6> relocation value (block number) - IND_START<0:6> start address block - IND_LIMIT<0:6> limit address block - - The 7094 had five instruction formats: memory reference, - memory reference with count, convert, decrement, and immediate. - - 00000000011 11 1111 112 222222222333333 - S12345678901 23 4567 890 123456789012345 - +------------+--+----+---+---------------+ - | opcode |ND|0000|tag| address | memory reference - +------------+--+----+---+---------------+ - - 00000000011 111111 112 222222222333333 - S12345678901 234567 890 123456789012345 - +------------+------+---+---------------+ - | opcode | count|tag| address | memory reference - +------------+------+---+---------------+ with count - - 000000000 11111111 11 2 222222222333333 - S123456789 01234567 89 0 123456789012345 - +----------+--------+--+-+---------------+ - | opcode | count |00|X| address | convert - +----------+--------+--+-+---------------+ - - 00 000000011111111 112 222222222333333 - S12 345678901234567 890 123456789012345 - +---+---------------+---+---------------+ - |opc| decrement |tag| address | decrement - +---+---------------+---+---------------+ - - 00000000011 111111 112222222222333333 - S12345678901 234567 890123456789012345 - +------------+------+------------------+ - | opcode |000000| immediate | immediate - +------------+------+------------------+ - - This routine is the instruction decode routine for the 7094. - It is called from the simulator control program to execute - instructions in simulated memory, starting at the simulated PC. - It runs until a stop condition occurs. - - General notes: - - 1. Reasons to stop. The simulator can be stopped by: - - HALT instruction - illegal instruction - illegal I/O operation for device - illegal I/O operation for channel - breakpoint encountered - nested XEC's exceeding limit - divide check - I/O error in I/O simulator - - 2. Data channel traps. The 7094 is a channel-based system. - Channels can generate traps for errors and status conditions. - Channel trap state: - - ch_flags[0..7] flags for channels A..H - chtr_enab channel trap enables - chtr_inht channel trap inhibit due to trap (cleared by RCT) - chtr_inhi channel trap inhibit due to XEC, ENB, RCT, LRI, - LPI, SEA, SEB (cleared after one instruction) - - Channel traps are summarized in variable chtr_pend. - - 3. Arithmetic. The 7094 uses signed magnitude arithmetic for - integer and floating point calculations, and 2's complement - arithmetic for indexing calculations. - - 4. Adding I/O devices. These modules must be modified: - - i7094_defs.h add device definitions - i7094_io.c add device address mapping - i7094_sys.c add sim_devices table entry -*/ - -#include "i7094_defs.h" - -#define PCQ_SIZE 64 /* must be 2**n */ -#define PCQ_MASK (PCQ_SIZE - 1) -#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = (PC | inst_base) - -#define HIST_MIN 64 -#define HIST_MAX (2 << 18) -#define HIST_CH_C 1 /* include channel */ -#define HIST_CH_I 2 /* include IO */ - -#define HALT_IO_LIMIT ((2 << 18) + 1) /* max wait to stop */ - -#define EAMASK (mode_storn? A704_MASK: AMASK) /* eff addr mask */ - -t_uint64 *M = NULL; /* memory */ -t_uint64 AC = 0; /* AC */ -t_uint64 MQ = 0; /* MQ */ -t_uint64 SI = 0; /* indicators */ -t_uint64 KEYS = 0; /* storage keys */ -uint32 PC = 0; /* PC (IC) */ -uint32 oldPC = 0; /* prior PC */ -uint32 XR[8] = { 0 }; /* index registers */ -uint32 SSW = 0; /* sense switches */ -uint32 SLT = 0; /* sense lights */ -uint32 ch_req = 0; /* channel requests */ -uint32 chtr_pend = 0; /* chan trap pending */ -uint32 chtr_inht = 0; /* chan trap inhibit trap */ -uint32 chtr_inhi = 0; /* chan trap inhibit inst */ -uint32 chtr_enab = 0; /* chan trap enables */ -uint32 mode_ttrap = 0; /* transfer trap mode */ -uint32 mode_ctrap = 0; /* copy trap mode */ -uint32 mode_strap = 0; /* select trap mode */ -uint32 mode_ftrap = 0; /* floating trap mode */ -uint32 mode_storn = 0; /* storage nullification */ -uint32 mode_multi = 0; /* multi-index mode */ -uint32 ind_ovf = 0; /* overflow */ -uint32 ind_mqo = 0; /* MQ overflow */ -uint32 ind_dvc = 0; /* divide check */ -uint32 ind_ioc = 0; /* IO check */ -uint32 cpu_model = I_9X|I_94; /* CPU type */ -uint32 mode_user = 0; /* (CTSS) user mode */ -uint32 mode_reloc = 0; /* (CTSS) relocation mode */ -uint32 user_buf = 0; /* (CTSS) user mode buffer */ -uint32 reloc_buf = 0; /* (CTSS) reloc mode buffer */ -uint32 ind_reloc = 0; /* (CTSS) relocation */ -uint32 ind_start = 0; /* (CTSS) prot start */ -uint32 ind_limit = 0; /* (CTSS) prot limit */ -uint32 inst_base = 0; /* (CTSS) inst A/B sel */ -uint32 data_base = 0; /* (CTSS) data A/B sel */ -uint32 xec_max = 16; /* XEC chain limit */ -uint32 ht_pend = 0; /* HTR pending */ -uint32 ht_addr = 0; /* HTR address */ -uint32 stop_illop = 1; /* stop on ill op */ -uint32 cpu_astop = 0; /* address stop */ - -uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ -int32 pcq_p = 0; /* PC queue ptr */ -REG *pcq_r = NULL; /* PC queue reg ptr */ -int32 hst_p = 0; /* history pointer */ -int32 hst_lnt = 0; /* history length */ -uint32 hst_ch = 0; /* channel history */ -InstHistory *hst = NULL; /* instruction history */ - -extern uint32 ch_sta[NUM_CHAN]; -extern uint32 ch_flags[NUM_CHAN]; -extern DEVICE mt_dev[NUM_CHAN]; -extern DEVICE ch_dev[NUM_CHAN]; - -/* 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_set_model (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc); -t_bool ReadI (uint32 va, t_uint64 *dat); -t_bool Read (uint32 va, t_uint64 *dat); -t_bool Write (uint32 va, t_uint64 dat); -void WriteTA (uint32 pa, uint32 addr); -void WriteTAD (uint32 pa, uint32 addr, uint32 decr); -void TrapXfr (uint32 newpc); -t_bool fp_trap (uint32 spill); -t_bool prot_trap (uint32 decr); -t_bool sel_trap (uint32 va); -t_bool cpy_trap (uint32 va); -uint32 get_xri (uint32 tag); -uint32 get_xrx (uint32 tag); -void put_xr (uint32 tag, uint32 dat); -t_stat cpu_fprint_one_inst (FILE *st, uint32 pc, uint32 rpt, uint32 ea, - t_uint64 ir, t_uint64 ac, t_uint64 mq, t_uint64 si, t_uint64 opnd); - -extern uint32 chtr_eval (uint32 *decr); -extern void op_add (t_uint64 sr); -extern void op_mpy (t_uint64 ac, t_uint64 sr, uint32 sc); -extern t_bool op_div (t_uint64 sr, uint32 sc); -extern uint32 op_fad (t_uint64 sr, t_bool norm); -extern uint32 op_fmp (t_uint64 sr, t_bool norm); -extern uint32 op_fdv (t_uint64); -extern uint32 op_dfad (t_uint64 shi, t_uint64 slo, t_bool norm); -extern uint32 op_dfmp (t_uint64 shi, t_uint64 slo, t_bool norm); -extern uint32 op_dfdv (t_uint64 shi, t_uint64 slo); -extern void op_als (uint32 ea); -extern void op_ars (uint32 ea); -extern void op_lls (uint32 ea); -extern void op_lrs (uint32 ea); -extern void op_lgl (uint32 ea); -extern void op_lgr (uint32 ea); -extern t_stat op_pse (uint32 ea); -extern t_stat op_mse (uint32 ea); -extern t_stat ch_op_ds (uint32 ch, uint32 ds, uint32 unit); -extern t_stat ch_op_nds (uint32 ch, uint32 ds, uint32 unit); -extern t_stat ch_op_start (uint32 ch, uint32 clc, t_bool reset); -extern t_stat ch_op_store (uint32 ch, t_uint64 *dat); -extern t_stat ch_op_store_diag (uint32 ch, t_uint64 *dat); -extern t_stat ch_proc (uint32 ch); - -/* CPU data structures - - cpu_dev CPU device descriptor - cpu_unit CPU unit - cpu_reg CPU register list - cpu_mod CPU modifier list -*/ - -UNIT cpu_unit = { UDATA (NULL, UNIT_FIX+UNIT_BINK, STDMEMSIZE) }; - -REG cpu_reg[] = { - { ORDATA (PC, PC, ASIZE) }, - { ORDATA (AC, AC, 38) }, - { ORDATA (MQ, MQ, 36) }, - { ORDATA (SI, SI, 36) }, - { ORDATA (KEYS, KEYS, 36) }, - { ORDATA (XR1, XR[1], 15) }, - { ORDATA (XR2, XR[2], 15) }, - { ORDATA (XR3, XR[3], 15) }, - { ORDATA (XR4, XR[4], 15) }, - { ORDATA (XR5, XR[5], 15) }, - { ORDATA (XR6, XR[6], 15) }, - { ORDATA (XR7, XR[7], 15) }, - { FLDATA (SS1, SSW, 5) }, - { FLDATA (SS2, SSW, 4) }, - { FLDATA (SS3, SSW, 3) }, - { FLDATA (SS4, SSW, 2) }, - { FLDATA (SS5, SSW, 1) }, - { FLDATA (SS6, SSW, 0) }, - { FLDATA (SL1, SLT, 3) }, - { FLDATA (SL2, SLT, 2) }, - { FLDATA (SL3, SLT, 1) }, - { FLDATA (SL4, SLT, 0) }, - { FLDATA (OVF, ind_ovf, 0) }, - { FLDATA (MQO, ind_mqo, 0) }, - { FLDATA (DVC, ind_dvc, 0) }, - { FLDATA (IOC, ind_ioc, 0) }, - { FLDATA (TTRAP, mode_ttrap, 0) }, - { FLDATA (CTRAP, mode_ctrap, 0) }, - { FLDATA (STRAP, mode_strap, 0) }, - { FLDATA (FTRAP, mode_ftrap, 0) }, - { FLDATA (STORN, mode_storn, 0) }, - { FLDATA (MULTI, mode_multi, 0) }, - { ORDATA (CHREQ, ch_req, NUM_CHAN) }, - { FLDATA (CHTR_PEND, chtr_pend, 0) }, - { FLDATA (CHTR_INHT, chtr_inht, 0) }, - { FLDATA (CHTR_INHI, chtr_inhi, 0) }, - { ORDATA (CHTR_ENAB, chtr_enab, 30) }, - { FLDATA (USERM, mode_user, 0) }, - { FLDATA (RELOCM, mode_reloc, 0) }, - { FLDATA (USERBUF, user_buf, 0) }, - { FLDATA (RELOCBUF, reloc_buf, 0) }, - { FLDATA (IMEM, inst_base, BCORE_V) }, - { FLDATA (DMEM, data_base, BCORE_V) }, - { GRDATA (RELOC, ind_reloc, 8, VA_N_BLK, VA_V_BLK) }, - { GRDATA (START, ind_start, 8, VA_N_BLK, VA_V_BLK) }, - { GRDATA (LIMIT, ind_limit, 8, VA_N_BLK, VA_V_BLK) }, - { ORDATA (OLDPC, oldPC, ASIZE), REG_RO }, - { BRDATA (PCQ, pcq, 8, ASIZE, PCQ_SIZE), REG_RO+REG_CIRC }, - { ORDATA (PCQP, pcq_p, 6), REG_HRO }, - { FLDATA (HTPEND, ht_pend, 0) }, - { ORDATA (HTADDR, ht_addr, ASIZE) }, - { DRDATA (XECMAX, xec_max, 8), PV_LEFT + REG_NZ }, - { ORDATA (WRU, sim_int_char, 8) }, - { FLDATA (STOP_ILL, stop_illop, 0) }, - { ORDATA (MODEL, cpu_model, 4), REG_HRO }, - { NULL } - }; - -MTAB cpu_mod[] = { - { MTAB_XTD | MTAB_VDV, I_9X|I_94|I_CT, "MODEL", "CTSS", - &cpu_set_model, &cpu_show_model, NULL }, - { MTAB_XTD | MTAB_VDV, I_9X|I_94, NULL, "7094", - &cpu_set_model, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, I_9X, NULL, "7090", - &cpu_set_model, NULL, NULL }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", - &cpu_set_hist, &cpu_show_hist }, - { 0 } - }; - -DEVICE cpu_dev = { - "CPU", &cpu_unit, cpu_reg, cpu_mod, - 1, 8, PASIZE, 1, 8, 36, - &cpu_ex, &cpu_dep, &cpu_reset, - NULL, NULL, NULL, - NULL, DEV_DEBUG - }; - -/* Instruction decode table */ - -const uint8 op_flags[1024] = { - I_XN , 0 , 0 , 0 , /* +000 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XN , I_XN|I_9X , I_XN , 0 , /* +020 */ - I_XN , 0 , I_XN , I_XN , - I_XN , I_XN , I_XN , I_XN , - 0 , 0 , 0 , 0 , - I_XN|I_9X , I_9X , I_XN|I_9X , I_9X , /* +040 */ - I_9X , 0 , I_XN|I_9X , 0 , - 0 , I_9X , 0 , 0 , - I_9X , I_9X , I_9X , I_9X , - I_XN , I_XN , I_XN , I_XN , /* +060 */ - I_XN , I_XN , I_XN , I_XN , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XN , I_XN|I_CT , 0 , 0 , /* +100 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_9X , I_9X , I_9X , I_9X , - I_XN , 0 , 0 , 0 , /* +120 */ - 0 , 0 , 0 , 0 , - 0 , I_9X , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XN , 0 , 0 , 0 , /* +140 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , I_XN|I_9X , I_XN|I_9X , 0 , /* +160 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , 0 , 0 , 0 , /* +200 */ - I_XNR , I_XNR , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR|I_9X, I_XNR , 0 , 0 , /* +220 */ - I_XNR|I_9X, I_XNR , I_XNR|I_9X, I_XNR , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR|I_9X, I_XNR , 0 , 0 , /* +240 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , I_XND|I_94, 0 , 0 , /* +260 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , I_XND|I_94, I_XNR , I_XND|I_94, /* +300 */ - I_XNR|I_9X, I_XND|I_94, I_XNR|I_9X, I_XND|I_94, - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR|I_9X, 0 , I_XNR|I_9X, 0 , /* +320 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , 0 , 0 , 0 , /* +340 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , I_XNR , 0 , 0 , /* +360 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , I_XNR|I_9X, I_XNR , 0 , /* +400 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* +420 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR|I_9X, I_XNR|I_9X, I_XNR|I_9X, I_XNR|I_94, /* +440 */ - I_XNR|I_9X, I_XNR|I_9X, I_XNR|I_9X, 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_9X , 0 , 0 , 0 , /* +460 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR|I_9X, 0 , I_XNR , 0 , /* +500 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , 0 , I_XNR , 0 , /* +520 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_R , I_R , 0 , 0 , - I_XN , I_XN , I_XN , I_XN , /* +540 */ - I_XN , I_XN , I_XN , I_XN , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , 0 , I_XNR|I_CT, 0 , /* +560 */ - I_XNR , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XN , I_XN , I_XN , 0 , /* +600 */ - I_XN|I_9X , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , I_XNR , I_XNR , 0 , /* +620 */ - 0 , I_XNR|I_9X, 0 , 0 , - I_XNR|I_9X, 0 , 0 , 0 , - I_R , 0 , I_R|I_94 , 0 , - I_XN , I_XN , I_XN , I_XN , /* +640 */ - I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* +660 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_9X , 0 , 0 , 0 , /* +700 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* +720 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* +740 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , I_94 , 0 , - I_X , 0 , I_X , I_X , /* +760 */ - I_X , I_X , I_X , I_X , - I_X , I_X , I_X , 0 , - 0 , 0 , 0 , 0 , - - I_XN , 0 , 0 , 0 , /* -000 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XN , I_XN|I_9X , I_XN , 0 , /* -020 */ - I_XN , 0 , I_XN , I_XN , - I_XN , I_XN , I_XN , I_XN , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* -040 */ - 0 , 0 , I_9X , 0 , - 0 , I_9X , 0 , 0 , - I_9X , I_9X , I_9X , I_9X , - I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , /* -060 */ - I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XN , I_XN|I_CT , 0 , 0 , /* -100 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_9X , I_9X , I_9X , I_9X , - I_XN , 0 , 0 , 0 , /* -120 */ - 0 , 0 , 0 , 0 , - I_9X , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XN|I_9X , 0 , 0 , 0 , /* -140 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_9X , I_9X , I_9X , I_9X , - 0 , 0 , 0 , 0 , /* -160 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR|I_9X, 0 , 0 , 0 , /* -200 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* -220 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XND|I_94, I_XND|I_94, 0 , 0 , /* -240 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , I_XND|I_94, 0 , 0 , /* -260 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , I_XND|I_94, I_XNR , I_XND|I_94, /* -300 */ - I_XNR|I_9X, I_XND|I_94, I_XNR|I_9X, I_XND|I_94, - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , 0 , 0 , 0 , /* -320 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , 0 , 0 , 0 , /* -340 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* -360 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR|I_9X, 0 , 0 , 0 , /* -400 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* -420 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* -440 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* -460 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR , I_XNR , 0 , 0 , /* -500 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR|I_9X, 0 , 0 , 0 , /* -520 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_R , I_R , 0 , 0 , - I_XN , I_XN , I_XN , I_XN , /* -540 */ - I_XN , I_XN , I_XNR , I_XN , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* -560 */ - I_XNR|I_CT, 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XN , I_CT , I_XNR|I_9X, I_XN|I_94 , /* -600 */ - I_CT , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_XNR|I_9X, 0 , 0 , 0 , /* -620 */ - 0 , I_XNR , 0 , 0 , - 0 , 0 , 0 , 0 , - I_R , 0 , I_R|I_94 , 0 , - I_XN , I_XN , I_XN , I_XN , /* -640 */ - I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , I_XN|I_9X , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* -660 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - I_9X , 0 , 0 , 0 , /* -700 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* -720 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , /* -740 */ - 0 , 0 , 0 , 0 , - 0 , 0 , 0 , 0 , - 0 , 0 , I_94 , 0 , - I_X , I_X|I_CT , 0 , I_X , /* -760 */ - 0 , I_X , 0 , 0 , - 0 , 0 , I_X , I_X , - I_9X , 0 , 0 , 0 - }; - -/* Instruction execution routine */ - -t_stat sim_instr (void) -{ -t_stat reason = SCPE_OK; -t_uint64 IR, SR, t, t1, t2, sr1; -uint32 op, fl, tag, tagi, addr, ea; -uint32 ch, dec, xr, xec_cnt, trp; -uint32 i, j, sc, s1, s2, spill; -t_bool tracing; - -/* Restore register state */ - -ch_set_map (); /* set dispatch map */ -if (!(cpu_model & (I_94|I_CT))) /* ~7094? MTM always on */ - mode_multi = 1; -inst_base = inst_base & ~AMASK; /* A/B sel is 1b */ -data_base = data_base & ~AMASK; -ind_reloc = ind_reloc & VA_BLK; /* canonical form */ -ind_start = ind_start & VA_BLK; -ind_limit = (ind_limit & VA_BLK) | VA_OFF; -chtr_pend = chtr_eval (NULL); /* eval chan traps */ -tracing = ((hst_lnt != 0) || DEBUG_PRS (cpu_dev)); - -if (ht_pend) { /* HTR pending? */ - oldPC = (PC - 1) & AMASK; - ht_pend = 0; /* clear flag */ - PCQ_ENTRY; - if (mode_ttrap) { /* trap? */ - WriteTA (TRAP_STD_SAV, oldPC); /* save PC */ - TrapXfr (TRAP_TRA_PC); /* trap */ - } - else PC = ht_addr; /* branch */ - } - -/* Main instruction fetch/decode loop */ - -while (reason == SCPE_OK) { /* loop until error */ - - if (cpu_astop) { /* debug stop? */ - cpu_astop = 0; - reason = SCPE_STOP; - break; - } - - if (sim_interval <= 0) { /* intv cnt expired? */ - if ((reason = sim_process_event ())) /* process events */ - break; - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - } - - for (i = 0; ch_req && (i < NUM_CHAN); i++) { /* loop thru channels */ - if (ch_req & REQ_CH (i)) { /* channel request? */ - if ((reason = ch_proc (i))) - break; - } - chtr_pend = chtr_eval (NULL); - if (reason) /* error? */ - break; - } - - if (chtr_pend) { /* channel trap? */ - addr = chtr_eval (&trp); /* get trap info, clr */ - chtr_inht = 1; /* inhibit traps */ - chtr_pend = 0; /* no trap pending */ - WriteTAD (addr, PC, trp); /* wr trap addr,flag */ - IR = ReadP (addr + 1); /* get trap instr */ - oldPC = PC; /* save current PC */ - } - - else { - if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; - } - if (chtr_inhi) { /* 1 cycle inhibit? */ - chtr_inhi = 0; /* clear */ - chtr_pend = chtr_eval (NULL); /* re-evaluate */ - } - else if (cpu_model & I_CT) { /* CTSS? */ - mode_user = user_buf; /* load modes from buffers */ - mode_reloc = reloc_buf; - } - oldPC = PC; /* save current PC */ - PC = (PC + 1) & EAMASK; /* increment PC */ - if (!ReadI (oldPC, &IR)) /* get inst; trap? */ - continue; - } - - sim_interval = sim_interval - 1; - xec_cnt = 0; /* clear XEC cntr */ - - XEC: - - tag = GET_TAG (IR); /* get tag */ - addr = (uint32) IR & EAMASK; /* get base addr */ - -/* Decrement format instructions */ - - if (IR & INST_T_DEC) { /* decrement type? */ - op = GET_OPD (IR); /* get opcode */ - dec = GET_DEC (IR); /* get decrement */ - xr = get_xrx (tag); /* get xr, upd MTM */ - if (tracing) { /* trace or history? */ - if (hst_lnt) /* history enabled? */ - cpu_ent_hist (oldPC|HIST_PC, xr, IR, 0); - if (DEBUG_PRS (cpu_dev)) - cpu_fprint_one_inst (sim_deb, oldPC|HIST_PC, 0, xr, - IR, AC, MQ, SI, 0); - } - switch (op) { - - case 01: /* TXI */ - put_xr (tag, xr + dec); /* xr += decr */ - PCQ_ENTRY; - if (mode_ttrap) { /* trap? */ - WriteTA (TRAP_STD_SAV, oldPC); /* save PC */ - TrapXfr (TRAP_TRA_PC); /* trap */ - } - else PC = addr; /* branch */ - break; - - case 02: /* TIX */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (xr > dec) { /* if xr > decr */ - put_xr (tag, xr - dec); /* xr -= decr */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = addr; /* branch */ - } - break; - - case 03: /* TXH */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (xr > dec) { /* if xr > decr */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = addr; /* branch */ - } - break; - - case 05: /* STR */ - WriteTA (TRAP_STD_SAV, PC); /* save inst+1 */ - PCQ_ENTRY; - PC = TRAP_STR_PC; /* branch to 2 */ - break; - - case 06: /* TNX */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (xr > dec) /* if xr > decr */ - put_xr (tag, xr - dec); - else { /* xr -= decr */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = addr; /* branch */ - } - break; - - case 07: /* TXL */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (xr <= dec) { /* if xr <= decr */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = addr; /* branch */ - } - break; - } - } /* end if */ - -/* Normal format instructions */ - - else { - op = GET_OPC (IR); /* get opcode */ - fl = op_flags[op]; /* get flags */ - if (fl & I_MODEL & ~cpu_model) { /* invalid for model? */ - if (stop_illop) /* possible stop */ - reason = STOP_ILLEG; - continue; - } - if (tag && (fl & I_X)) /* tag and indexable? */ - ea = (addr - get_xri (tag)) & EAMASK; /* do indexing */ - else ea = addr; - if (TST_IND (IR) && (fl & I_N)) { /* indirect? */ - if (!ReadI (ea, &SR)) /* get ind; trap? */ - continue; - addr = (uint32) SR & EAMASK; /* get address */ - tagi = GET_TAG (SR); /* get tag */ - if (tagi) /* tag? */ - ea = (addr - get_xri (tagi)) & EAMASK; /* do indexing */ - else ea = addr; - } - if ((fl & I_R) && !Read (ea, &SR)) /* read opnd; trap? */ - continue; - else if (fl & I_D) { /* double prec? */ - if ((ea & 1) && fp_trap (TRAP_F_ODD)) - continue; - if (!Read (ea, &SR)) /* SR gets high */ - continue; - if (!Read (ea | 1, &sr1)) /* "sr1" gets low */ - continue; - } - if (tracing) { /* tracing or history? */ - if (hst_lnt) /* history enabled? */ - cpu_ent_hist (oldPC|HIST_PC, ea, IR, SR); - if (DEBUG_PRS (cpu_dev)) - cpu_fprint_one_inst (sim_deb, oldPC|HIST_PC, 0, ea, - IR, AC, MQ, SI, SR); - } - switch (op) { /* case on opcode */ - -/* Positive instructions */ - - case 00000: /* HTR */ - case 01000: /* also -HTR */ - if (prot_trap (0)) /* user mode? */ - break; - ht_pend = 1; /* transfer pending */ - ht_addr = ea; /* save address */ - reason = STOP_HALT; /* halt if I/O done */ - break; - - case 00020: /* TRA */ - case 01020: /* also -TRA */ - PCQ_ENTRY; - if (mode_ttrap) { /* trap? */ - WriteTA (TRAP_STD_SAV, oldPC); /* save PC */ - TrapXfr (TRAP_TRA_PC); /* trap */ - } - else PC = ea; /* branch */ - break; - - case 00021: /* TTR */ - PCQ_ENTRY; - PC = ea; /* branch, no trap */ - break; - - case 00040: /* TLQ */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - s1 = (AC & AC_S)? 1: 0; /* get AC, MQ sign, */ - s2 = (MQ & SIGN)? 1: 0; /* magnitude */ - t1 = AC & AC_MMASK; - t2 = MQ & MMASK; /* signs differ? */ - if ((s1 != s2)? s2: /* y, br if MQ- */ - ((t1 != t2) && (s2 ^ (t1 > t2)))) { /* n, br if sgn-^AC>MQ */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - } - break; - - case 00041: /* IIA */ - SI = SI ^ (AC & DMASK); - break; - - case 00042: /* TIO */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if ((SI & AC) == (AC & DMASK)) { /* if ind on */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - } - break; - - case 00043: /* OAI */ - SI = SI | (AC & DMASK); - break; - - case 00044: /* PAI */ - SI = AC & DMASK; - break; - - case 00046: /* TIF */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if ((SI & AC) == 0) { /* if ind off */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - } - break; - - case 00051: /* IIR */ - SI = SI ^ (IR & RMASK); - break; - - case 00054: /* RFT */ - t = IR & RMASK; - if ((SI & t) == 0) /* if ind off, skip */ - PC = (PC + 1) & EAMASK; - break; - - case 00055: /* SIR */ - SI = SI | (IR & RMASK); - break; - - case 00056: /* RNT */ - t = IR & RMASK; - if ((SI & t) == t) /* if ind on, skip */ - PC = (PC + 1) & EAMASK; - break; - - case 00057: /* RIR */ - SI = SI & ~(IR & RMASK); - break; - - case 00074: /* TSX */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (tag) /* save -inst loc */ - put_xr (tag, ~oldPC + 1); - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - break; - - case 00100: /* TZE */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if ((AC & AC_MMASK) == 0) { /* if AC Q,P,1-35 = 0 */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - } - break; - - case 00101: /* (CTSS) TIA */ - if (prot_trap (0)) /* not user mode? */ - break; - if (mode_ttrap) { /* trap? */ - WriteTA (TRAP_STD_SAV, oldPC); /* save PC */ - TrapXfr (TRAP_TRA_PC); /* trap */ - } - else { - PCQ_ENTRY; - PC = ea; - inst_base = 0; - } - break; - - case 00114: case 00115: case 00116: case 00117: /* CVR */ - sc = GET_CCNT (IR); - SR = ea; - while (sc) { - ea = (uint32) ((AC & 077) + SR) & EAMASK; - if (!Read (ea, &SR)) - break; - AC = (AC & AC_S) | ((AC >> 6) & 0017777777777) | - (SR & INT64_C(0770000000000)); - sc--; - } - if ((sc == 0) && (IR & INST_T_CXR1)) - put_xr (1, (uint32) SR); - break; - - case 00120: /* TPL */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if ((AC & AC_S) == 0) { /* if AC + */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - } - break; - - case 00131: /* XCA */ - t = MQ; - MQ = (AC & MMASK) | ((AC & AC_S)? SIGN: 0); - AC = (t & MMASK) | ((t & SIGN)? AC_S: 0); - break; - - case 00140: /* TOV */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (ind_ovf) { /* if overflow */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - ind_ovf = 0; /* clear overflow */ - } - break; - - case 00161: /* TQO */ - if (!mode_ftrap) { /* only in 704 mode */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (ind_mqo) { /* if MQ overflow */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - ind_mqo = 0; /* clear overflow */ - } - } - break; - - case 00162: /* TQP */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if ((MQ & SIGN) == 0) { /* if MQ + */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - } - break; - - case 00200: /* MPY */ - op_mpy (0, SR, 043); - break; - - case 00204: /* VLM */ - case 00205: /* for diagnostic */ - sc = GET_VCNT (IR); - op_mpy (0, SR, sc); - break; - - case 00220: /* DVH */ - if (op_div (SR, 043)) { - ind_dvc = 1; - if (!prot_trap (0)) - reason = STOP_DIVCHK; - } - break; - - case 00221: /* DVP */ - if (op_div (SR, 043)) - ind_dvc = 1; - break; - - case 00224: /* VDH */ - case 00226: /* for diagnostic */ - sc = GET_VCNT (IR); - if (op_div (SR, sc)) { - ind_dvc = 1; - if (!prot_trap (0)) - reason = STOP_DIVCHK; - } - break; - - case 00225: /* VDP */ - case 00227: /* for diagnostic */ - sc = GET_VCNT (IR); - if (op_div (SR, sc)) - ind_dvc = 1; - break; - - case 00240: /* FDH */ - spill = op_fdv (SR); - if (spill == TRAP_F_DVC) { - ind_dvc = 1; - if (!prot_trap (0)) - reason = STOP_DIVCHK; - } - else if (spill) - fp_trap (spill); - break; - - case 00241: /* FDP */ - spill = op_fdv (SR); - if (spill == TRAP_F_DVC) - ind_dvc = 1; - else if (spill) - fp_trap (spill); - break; - - case 00260: /* FMP */ - spill = op_fmp (SR, 1); /* MQ * SR */ - if (spill) - fp_trap (spill); - break; - - case 00261: /* DFMP */ - spill = op_dfmp (SR, sr1, 1); - if (spill) - fp_trap (spill); - break; - - case 00300: /* FAD */ - spill = op_fad (SR, 1); - if (spill) - fp_trap (spill); - break; - - case 00301: /* DFAD */ - spill = op_dfad (SR, sr1, 1); - if (spill) - fp_trap (spill); - break; - - case 00302: /* FSB */ - spill = op_fad (SR ^ SIGN, 1); - if (spill) - fp_trap (spill); - break; - - case 00303: /* DFSB */ - spill = op_dfad (SR ^ SIGN, sr1, 1); - if (spill) - fp_trap (spill); - break; - - case 00304: /* FAM */ - spill = op_fad (SR & ~SIGN, 1); - if (spill) - fp_trap (spill); - break; - - case 00305: /* DFAM */ - spill = op_dfad (SR & ~SIGN, sr1, 1); - if (spill) - fp_trap (spill); - break; - - case 00306: /* FSM */ - spill = op_fad (SR | SIGN, 1); - if (spill) - fp_trap (spill); - break; - - case 00307: /* DFSM */ - spill = op_dfad (SR | SIGN, sr1, 1); - if (spill) - fp_trap (spill); - break; - - case 00320: /* ANS */ - SR = AC & SR; - Write (ea, SR); - break; - - case 00322: /* ERA */ - AC = (AC ^ SR) & DMASK; /* AC S,Q cleared */ - break; - - case 00340: /* CAS */ - s1 = (AC & AC_S)? 1: 0; /* get AC, MQ signs, */ - s2 = (SR & SIGN)? 1: 0; - t1 = AC & AC_MMASK; /* magnitudes */ - t2 = SR & MMASK; - if (s1 ^ s2) { /* diff signs? */ - if (s1) /* AC < mem? skip 2 */ - PC = (PC + 2) & EAMASK; - } - else if (t1 == t2) /* equal? skip 1 */ - PC = (PC + 1) & EAMASK; - else if ((t1 < t2) ^ s1) /* AC < mem, AC +, or */ - PC = (PC + 2) & EAMASK; /* AC > mem, AC -? */ - break; - - case 00361: /* ACL */ - t = (AC + SR) & DMASK; /* AC P,1-35 + SR */ - if (t < SR) /* end around carry */ - t = (t + 1) & DMASK; - AC = (AC & (AC_S | AC_Q)) | t; /* preserve AC S,Q */ - break; - - case 00400: /* ADD */ - op_add (SR); - break; - - case 00401: /* ADM */ - op_add (SR & MMASK); - break; - - case 00402: /* SUB */ - op_add (SR ^ SIGN); - break; - - case 00420: /* HPR */ - if (prot_trap (0)) /* user mode? */ - break; - reason = STOP_HALT; /* halt if I/O done */ - break; - - case 00440: /* IIS */ - SI = SI ^ SR; - break; - - case 00441: /* LDI */ - SI = SR; - break; - - case 00442: /* OSI */ - SI = SI | SR; - break; - - case 00443: /* DLD */ - AC = (SR & MMASK) | ((SR & SIGN)? AC_S: 0); /* normal load */ - if (!Read (ea | 1, &SR)) /* second load */ - break; - MQ = SR; - if (ea & 1) /* trap after exec */ - fp_trap (TRAP_F_ODD); - break; - - case 00444: /* OFT */ - if ((SI & SR) == 0) /* skip if ind off */ - PC = (PC + 1) & EAMASK; - break; - - case 00445: /* RIS */ - SI = SI & ~SR; - break; - - case 00446: /* ONT */ - if ((SI & SR) == SR) /* skip if ind on */ - PC = (PC + 1) & EAMASK; - break; - - case 00460: /* LDA (704) */ - cpy_trap (PC); - break; - - case 00500: /* CLA */ - AC = (SR & MMASK) | ((SR & SIGN)? AC_S: 0); - break; - - case 00502: /* CLS */ - AC = (SR & MMASK) | ((SR & SIGN)? 0: AC_S); - break; - - case 00520: /* ZET */ - if ((SR & MMASK) == 0) /* skip if M 1-35 = 0 */ - PC = (PC + 1) & EAMASK; - break; - - case 00522: /* XEC */ - if (xec_cnt++ >= xec_max) { /* xec chain limit? */ - reason = STOP_XEC; /* stop */ - break; - } - IR = SR; /* operand is new inst */ - chtr_inhi = 1; /* delay traps */ - chtr_pend = 0; /* no trap now */ - goto XEC; /* start over */ - - case 00534: /* LXA */ - if (tag) /* M addr -> xr */ - put_xr (tag, (uint32) SR); - break; - - case 00535: /* LAC */ - if (tag) /* -M addr -> xr */ - put_xr (tag, NEG ((uint32) SR)); - break; - - case 00560: /* LDQ */ - MQ = SR; - break; - - case 00562: /* (CTSS) LRI */ - if (prot_trap (0)) /* user mode? */ - break; - ind_reloc = ((uint32) SR) & VA_BLK; - reloc_buf = 1; /* set mode buffer */ - chtr_inhi = 1; /* delay traps */ - chtr_pend = 0; /* no trap now */ - break; - - case 00564: /* ENB */ - if (prot_trap (0)) /* user mode? */ - break; - chtr_enab = (uint32) SR; /* set enables */ - chtr_inht = 0; /* clear inhibit */ - chtr_inhi = 1; /* 1 cycle delay */ - chtr_pend = 0; /* no traps now */ - break; - - case 00600: /* STZ */ - Write (ea, 0); - break; - - case 00601: /* STO */ - SR = (AC & MMASK) | ((AC & AC_S)? SIGN: 0); - Write (ea, SR); - break; - - case 00602: /* SLW */ - Write (ea, AC & DMASK); - break; - - case 00604: /* STI */ - Write (ea, SI); - break; - - case 00621: /* STA */ - SR = (SR & ~AMASK) | (AC & AMASK); - Write (ea, SR); - break; - - case 00622: /* STD */ - SR = (SR & ~XMASK) | (AC & XMASK); - Write (ea, SR); - break; - - case 00625: /* STT */ - SR = (SR & ~TMASK) | (AC & TMASK); - Write (ea, SR); - break; - - case 00630: /* STP */ - SR = (SR & ~PMASK) | (AC & PMASK); - Write (ea, SR); - break; - - case 00634: /* SXA */ - SR = (SR & ~AMASK) | /* xr -> M addr */ - ((t_uint64) get_xrx (tag)); - Write (ea, SR); - break; - - case 00636: /* SCA */ - SR = (SR & ~AMASK) | /* -xr -> M addr */ - ((t_uint64) (NEG (get_xrx (tag)) & AMASK)); - Write (ea, SR); - break; - - case 00700: /* CPY (704) */ - cpy_trap (PC); - break; - - case 00734: /* PAX */ - if (tag) /* AC addr -> xr */ - put_xr (tag, (uint32) AC); - break; - - case 00737: /* PAC */ - if (tag) /* -AC addr -> xr */ - put_xr (tag, NEG ((uint32) AC)); - break; - - case 00754: /* PXA */ - AC = get_xrx (tag); /* xr -> AC */ - break; - - case 00756: /* PCA */ - AC = NEG (get_xrx (tag)) & AMASK; /* -xr -> AC */ - break; - - case 00760: /* PSE */ - reason = op_pse (ea); - break; - - case 00761: /* NOP */ - break; - - case 00763: /* LLS */ - op_lls (ea); - break; - - case 00765: /* LRS */ - op_lrs (ea); - break; - - case 00767: /* ALS */ - op_als (ea); - break; - - case 00771: /* ARS */ - op_ars (ea); - break; - - case 00774: /* AXT */ - if (tag) /* IR addr -> xr */ - put_xr (tag, addr); - break; - -/* Negative instructions */ - - case 01021: /* ESNT */ - if (prot_trap (0)) /* user mode? */ - break; - mode_storn = 1; /* enter nullification */ - PCQ_ENTRY; - PC = ea; /* branch, no trap */ - break; - - case 01042: /* RIA */ - SI = SI & ~AC; - break; - - case 01046: /* PIA */ - AC = SI; - break; - - case 01051: /* IIL */ - SI = SI ^ ((IR & RMASK) << 18); - break; - - case 01054: /* LFT */ - t = (IR & RMASK) << 18; - if ((SI & t) == 0) /* if ind off, skip */ - PC = (PC + 1) & EAMASK; - break; - - case 01055: /* SIL */ - SI = SI | ((IR & RMASK) << 18); - break; - - case 01056: /* LNT */ - t = (IR & RMASK) << 18; - if ((SI & t) == t) /* if ind on, skip */ - PC = (PC + 1) & EAMASK; - break; - - case 01057: /* RIL */ - SI = SI & ~((IR & RMASK) << 18); - break; - - case 01100: /* TNZ */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if ((AC & AC_MMASK) != 0) { /* if AC != 0 */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - } - break; - - case 01101: /* (CTSS) TIB */ - if (prot_trap (0)) /* user mode? */ - break; - if (mode_ttrap) { /* trap? */ - WriteTA (TRAP_STD_SAV, oldPC); /* save PC */ - TrapXfr (TRAP_TRA_PC); /* trap */ - } - else { - PCQ_ENTRY; - PC = ea; - inst_base = BCORE_BASE; - } - break; - - case 01114: case 01115: case 01116: case 01117: /* CAQ */ - sc = GET_CCNT (IR); - SR = ea; - while (sc) { - ea = (uint32) ((MQ >> 30) + SR) & EAMASK; - if (!Read (ea, &SR)) - break; - MQ = ((MQ << 6) & DMASK) | (MQ >> 30); - AC = (AC & AC_S) | ((AC + SR) & AC_MMASK); - sc--; - } - if ((sc == 0) && (IR & INST_T_CXR1)) - put_xr (1, (uint32) SR); - break; - - case 01120: /* TMI */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if ((AC & AC_S) != 0) { /* if AC - */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - } - break; - - case 01130: /* XCL */ - t = MQ; - MQ = AC & DMASK; - AC = t; - break; - - case 01140: /* TNO */ - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (!ind_ovf) { /* if no overflow */ - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - } - ind_ovf = 0; /* clear overflow */ - break; - - case 01154: case 01155: case 01156: case 01157: /* CRQ */ - sc = GET_CCNT (IR); - SR = ea; - while (sc) { - ea = (uint32) ((MQ >> 30) + SR) & EAMASK; - if (!Read (ea, &SR)) - break; - MQ = ((MQ << 6) & DMASK) | (SR >> 30); - sc--; - } - if ((sc == 0) && (IR & INST_T_CXR1)) - put_xr (1, (uint32) SR); - break; - - case 01200: /* MPR */ - op_mpy (0, SR, 043); - if (MQ & B1) - AC = (AC & AC_S) | ((AC + 1) & AC_MMASK); - break; - - case 01240: /* DFDH */ - spill = op_dfdv (SR, sr1); - if (spill == TRAP_F_DVC) { - ind_dvc = 1; - if (!prot_trap (0)) - reason = STOP_DIVCHK; - } - else if (spill) - fp_trap (spill); - break; - - case 01241: /* DFDP */ - spill = op_dfdv (SR, sr1); - if (spill == TRAP_F_DVC) - ind_dvc = 1; - else if (spill) - fp_trap (spill); - break; - - case 01260: /* UFM */ - spill = op_fmp (SR, 0); - if (spill) - fp_trap (spill); - break; - - case 01261: /* DUFM */ - spill = op_dfmp (SR, sr1, 0); - if (spill) - fp_trap (spill); - break; - - case 01300: /* UFA */ - spill = op_fad (SR, 0); - if (spill) - fp_trap (spill); - break; - - case 01301: /* DUFA */ - spill = op_dfad (SR, sr1, 0); - if (spill) - fp_trap (spill); - break; - - case 01302: /* UFS */ - spill = op_fad (SR ^ SIGN, 0); - if (spill) - fp_trap (spill); - break; - - case 01303: /* DUFS */ - spill = op_dfad (SR ^ SIGN, sr1, 0); - if (spill) - fp_trap (spill); - break; - - case 01304: /* UAM */ - spill = op_fad (SR & ~SIGN, 0); - if (spill) - fp_trap (spill); - break; - - case 01305: /* DUAM */ - spill = op_dfad (SR & ~SIGN, sr1, 0); - if (spill) - fp_trap (spill); - break; - - case 01306: /* USM */ - spill = op_fad (SR | SIGN, 0); - if (spill) - fp_trap (spill); - break; - - case 01307: /* DUSM */ - spill = op_dfad (SR | SIGN, sr1, 0); - if (spill) - fp_trap (spill); - break; - - case 01320: /* ANA */ - AC = AC & SR; - break; - - case 01340: /* LAS */ - t = AC & AC_MMASK; /* AC Q,P,1-35 */ - if (t < SR) - PC = (PC + 2) & EAMASK; - else if (t == SR) - PC = (PC + 1) & EAMASK; - break; - - case 01400: /* SBM */ - op_add (SR | SIGN); - break; - - case 01500: /* CAL */ - AC = SR; - break; - - case 01501: /* ORA */ - AC = AC | SR; - break; - - case 01520: /* NZT */ - if ((SR & MMASK) != 0) - PC = (PC + 1) & EAMASK; - break; - - case 01534: /* LXD */ - if (tag) /* M decr -> xr */ - put_xr (tag, GET_DEC (SR)); - break; - - case 01535: /* LDC */ - if (tag) /* -M decr -> xr */ - put_xr (tag, NEG (GET_DEC (SR))); - break; - - case 01564: /* (CTSS) LPI */ - if (prot_trap (0)) /* user mode? */ - break; - ind_start = ((uint32) SR) & VA_BLK; - ind_limit = (GET_DEC (SR) & VA_BLK) | VA_OFF; - user_buf = 1; /* set mode buffer */ - chtr_inhi = 1; /* delay traps */ - chtr_pend = 0; /* no trap now */ - break; - - case 01600: /* STQ */ - Write (ea, MQ); - break; - - case 01601: /* SRI (CTSS) */ - SR = ind_reloc & VA_BLK; - /* add reloc mode in bit 1 */ - Write (ea, SR); - break; - - case 01602: /* ORS */ - SR = SR | (AC & DMASK); - Write (ea, SR); - break; - - case 01603: /* DST */ - SR = (AC & MMASK) | ((AC & AC_S)? SIGN: 0); - if (!Write (ea, SR)) - break; - Write ((ea + 1) & EAMASK, MQ); - break; - - case 01604: /* SPI (CTSS) */ - SR = (((t_uint64) (ind_limit & VA_BLK)) << INST_V_DEC) | - ((t_uint64) (ind_start & VA_BLK)); - /* add prot mode in bit 2 */ - Write (ea, SR); - break; - - case 01620: /* SLQ */ - SR = (SR & RMASK) | (MQ & LMASK); - Write (ea, SR); - break; - - case 01625: /* STL */ - SR = (SR & ~AMASK) | PC; - Write (ea, SR); - break; - - case 01634: /* SXD */ - SR = (SR & ~XMASK) | /* xr -> M decr */ - (((t_uint64) get_xrx (tag)) << INST_V_DEC); - Write (ea, SR); - break; - - case 01636: /* SCD */ - SR = (SR & ~XMASK) | /* -xr -> M decr */ - (((t_uint64) (NEG (get_xrx (tag)) & AMASK)) << INST_V_DEC); - Write (ea, SR); - break; - - case 01700: /* CAD (704) */ - cpy_trap (PC); - break; - - case 01734: /* PDX */ - if (tag) /* AC decr -> xr */ - put_xr (tag, GET_DEC (AC)); - break; - - case 01737: /* PDC */ - if (tag) /* -AC decr -> xr */ - put_xr (tag, NEG (GET_DEC (AC))); - break; - - case 01754: /* PXD */ - AC = ((t_uint64) get_xrx (tag)) << INST_V_DEC; - break; /* xr -> AC decr */ - - case 01756: /* PCD */ - AC = ((t_uint64) (NEG (get_xrx (tag)) & AMASK)) << INST_V_DEC; - break; /* -xr -> AC decr */ - - case 01760: /* MSE */ - reason = op_mse (ea); - break; - - case 01761: /* (CTSS) ext core */ - if (prot_trap (0)) /* user mode? */ - break; - if (ea == 041) /* SEA? */ - data_base = 0; - else if (ea == 042) /* SEB? */ - data_base = BCORE_BASE; - else if (ea == 043) { /* IFT? */ - if (inst_base == 0) - PC = (PC + 1) & EAMASK; - } - else if (ea == 044) { /* EFT? */ - if (data_base == 0) - PC = (PC + 1) & EAMASK; - } - else if (stop_illop) - reason = STOP_ILLEG; - break; - - case 01763: /* LGL */ - op_lgl (ea); - break; - - case 01765: /* LGR */ - op_lgr (ea); - break; - - case 01773: /* RQL */ - sc = (ea & SCMASK) % 36; - if (sc) - MQ = ((MQ << sc) | (MQ >> (36 - sc))) & DMASK; - break; - - case 01774: /* AXC */ - if (tag) /* -IR addr -> xr */ - put_xr (tag, NEG (addr)); - break; - -/* IO instructions */ - - case 00022: case 00024: case 00026: /* TRCx */ - case 01022: case 01024: case 01026: - if (prot_trap (0)) /* user mode? */ - break; - ch = ((op & 077) - 00022) | ((op >> 9) & 01); - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (!BIT_TST (chtr_enab, CHTR_V_TRC + ch) && - (ch_flags[ch] & CHF_TRC)) { - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - ch_flags[ch] = ch_flags[ch] & ~CHF_TRC; - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - } - break; - - case 00027: case 01027: - if (prot_trap (0)) /* user mode? */ - break; - ch = 6 + ((op >> 9) & 01); - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (!BIT_TST (chtr_enab, CHTR_V_TRC + ch) && - (ch_flags[ch] & CHF_TRC)) { - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - ch_flags[ch] = ch_flags[ch] & ~CHF_TRC; - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - } - break; - - case 00030: case 00031: case 00032: case 00033: /* TEFx */ - case 01030: case 01031: case 01032: case 01033: - if (prot_trap (0)) /* user mode? */ - break; - ch = ((op & 03) << 1) | ((op >> 9) & 01); - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (!BIT_TST (chtr_enab, CHTR_V_CME + ch) && - (ch_flags[ch] & CHF_EOF)) { - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - ch_flags[ch] = ch_flags[ch] & ~CHF_EOF; - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - } - break; - - case 00060: case 00061: case 00062: case 00063: /* TCOx */ - case 00064: case 00065: case 00066: case 00067: - if (prot_trap (0)) /* user mode? */ - break; - ch = op & 07; - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (ch_sta[ch] != CHXS_IDLE) { - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - } - break; - - case 01060: case 01061: case 01062: case 01063: /* TCNx */ - case 01064: case 01065: case 01066: case 01067: - if (prot_trap (0)) /* user mode? */ - break; - ch = op & 07; - if (mode_ttrap) - WriteTA (TRAP_STD_SAV, oldPC); - if (ch_sta[ch] == CHXS_IDLE) { - PCQ_ENTRY; - if (mode_ttrap) /* trap? */ - TrapXfr (TRAP_TRA_PC); - else PC = ea; /* branch */ - } - break; - - case 00540: case 00541: case 00542: case 00543: /* RCHx */ - case 01540: case 01541: case 01542: case 01543: - if (prot_trap (0)) /* user mode? */ - break; - ch = ((op & 03) << 1) | ((op >> 9) & 01); - reason = ch_op_start (ch, ea, TRUE); - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - break; - - case 00544: case 00545: case 00546: case 00547: /* LCHx */ - case 01544: case 01545: case 01546: case 01547: - if (prot_trap (0)) /* user mode? */ - break; - ch = ((op & 03) << 1) | ((op >> 9) & 01); - reason = ch_op_start (ch, ea, FALSE); - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - break; - - case 00640: case 00641: case 00642: case 00643: /* SCHx */ - case 01640: case 01641: case 01642: case 01643: - ch = ((op & 03) << 1) | ((op >> 9) & 01); - if ((reason = ch_op_store (ch, &SR)) == SCPE_OK) - Write (ea, SR); - break; - - case 00644: case 00645: case 00646: case 00647: /* SCDx */ - case 01644: case 01645: case 01646: case 01647: - ch = ((op & 03) << 1) | ((op >> 9) & 01); - if ((reason = ch_op_store_diag (ch, &SR)) == SCPE_OK) - Write (ea, SR); - break; - - case 00762: /* RDS */ - if (sel_trap (0) || prot_trap (PC)) /* select takes priority */ - break; - ch = GET_U_CH (IR); - reason = ch_op_ds (ch, CHSL_RDS, GET_U_UNIT (ea)); - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - break; - - case 00764: /* BSR */ - if (sel_trap (0) || prot_trap (PC)) /* select takes priority */ - break; - ch = GET_U_CH (IR); - reason = ch_op_nds (ch, CHSL_BSR, GET_U_UNIT (ea)); - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - break; - - case 00766: /* WRS */ - if (sel_trap (0) || prot_trap (PC)) /* select takes priority */ - break; - ch = GET_U_CH (IR); - reason = ch_op_ds (ch, CHSL_WRS, GET_U_UNIT (ea)); - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - break; - - case 00770: /* WEF */ - if (sel_trap (0) || prot_trap (PC)) /* select takes priority */ - break; - ch = GET_U_CH (IR); - reason = ch_op_nds (ch, CHSL_WEF, GET_U_UNIT (ea)); - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - break; - - case 00772: /* REW */ - if (sel_trap (0) || prot_trap (PC)) /* select takes priority */ - break; - ch = GET_U_CH (IR); - reason = ch_op_nds (ch, CHSL_REW, GET_U_UNIT (ea)); - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - break; - - case 01764: /* BSF */ - if (sel_trap (0) || prot_trap (PC)) /* select takes priority */ - break; - ch = GET_U_CH (IR); - reason = ch_op_nds (ch, CHSL_BSF, GET_U_UNIT (ea)); - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - break; - - case 01772: /* RUN */ - if (sel_trap (0) || prot_trap (PC)) /* select takes priority */ - break; - ch = GET_U_CH (IR); - reason = ch_op_nds (ch, CHSL_RUN, GET_U_UNIT (ea)); - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - break; - - case 00776: /* SDN */ - if (sel_trap (0) || prot_trap (PC)) /* select takes priority */ - break; - ch = GET_U_CH (IR); - reason = ch_op_nds (ch, CHSL_SDN, GET_U_UNIT (ea)); - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - break; - - default: - if (stop_illop) - reason = STOP_ILLEG; - break; - } - } /* end else */ - - if (reason) { /* reason code? */ - if (reason == ERR_STALL) { /* stall? */ - PC = oldPC; /* back up PC */ - reason = 0; - } - else if (reason == STOP_HALT) { /* halt? wait for IO */ - t_stat r; - for (i = 0; (i < HALT_IO_LIMIT) && !ch_qidle (); i++) { - sim_interval = 0; - if ((r = sim_process_event ())) /* process events */ - return r; - chtr_pend = chtr_eval (NULL); /* eval chan traps */ - while (ch_req) { /* until no ch req */ - for (j = 0; j < NUM_CHAN; j++) { /* loop thru channels */ - if (ch_req & REQ_CH (j)) { /* channel request? */ - if ((r = ch_proc (j))) - return r; - } - chtr_pend = chtr_eval (NULL); - } - } /* end while ch_req */ - } /* end for wait */ - if (chtr_pend) /* trap? cancel HALT */ - reason = 0; - } /* end if HALT */ - } /* end if reason */ - } /* end while */ - -pcq_r->qptr = pcq_p; /* update pc q ptr */ -return reason; -} - -/* Get index register for indexing */ - -uint32 get_xri (uint32 tag) -{ -tag = tag & INST_M_TAG; - -if (tag) { - if (mode_multi) { - uint32 r = 0; - if (tag & 1) - r = r | XR[1]; - if (tag & 2) - r = r | XR[2]; - if (tag & 4) - r = r | XR[4]; - return r & EAMASK; - } - return XR[tag] & EAMASK; - } -return 0; -} - -/* Get index register for instruction execution - - Instructions which are 'executing directly' on index registers rewrite - the index register value. In multi-tag mode, this causes all registers - involved in the OR function to receive the OR'd value. */ - -uint32 get_xrx (uint32 tag) -{ -tag = tag & INST_M_TAG; - -if (tag) { - if (mode_multi) { - uint32 r = 0; - if (tag & 1) - r = r | XR[1]; - if (tag & 2) - r = r | XR[2]; - if (tag & 4) - r = r | XR[4]; - put_xr (tag, r); - return r & EAMASK; - } - return XR[tag] & EAMASK; - } -return 0; -} - -/* Store index register */ - -void put_xr (uint32 tag, uint32 dat) -{ -tag = tag & INST_M_TAG; -dat = dat & EAMASK; - -if (tag) { - if (mode_multi) { - if (tag & 1) - XR[1] = dat; - if (tag & 2) - XR[2] = dat; - if (tag & 4) - XR[4] = dat; - } - else XR[tag] = dat; - } -return; -} - -/* Floating point trap */ - -t_bool fp_trap (uint32 spill) -{ -if (mode_ftrap) { - WriteTAD (TRAP_STD_SAV, PC, spill); - PCQ_ENTRY; - PC = TRAP_FP_PC; - return TRUE; - } -else { - if (spill & TRAP_F_AC) - ind_ovf = 1; - if (spill & TRAP_F_MQ) - ind_mqo = 1; - } -return FALSE; -} - -/* (CTSS) Protection trap */ - -t_bool prot_trap (uint32 decr) -{ -if (mode_user) { - WriteTAD (TRAP_PROT_SAV, PC, decr); - PCQ_ENTRY; - PC = TRAP_PROT_PC; - return TRUE; - } -return FALSE; -} - -/* Store trap address and decrement, with A/B select flags; clear A/B, user mode */ - -void WriteTAD (uint32 pa, uint32 addr, uint32 decr) -{ -t_uint64 mem; - -if (inst_base) - decr |= TRAP_F_BINST; -if (data_base) - decr |= TRAP_F_BDATA; -mem = ReadP (pa) & ~(XMASK | AMASK); -mem |= (((t_uint64) (decr & AMASK)) << INST_V_DEC) | - ((t_uint64) (addr & AMASK)); -WriteP (pa, mem); -mode_ctrap = 0; -mode_strap = 0; -mode_storn = 0; -mode_user = user_buf = 0; -mode_reloc = reloc_buf = 0; -inst_base = 0; -data_base = 0; -return; -} - -/* Copy trap */ - -t_bool cpy_trap (uint32 va) -{ -if (mode_ctrap) { - WriteTA (TRAP_704_SAV, va); - PCQ_ENTRY; - TrapXfr (TRAP_CPY_PC); - return TRUE; - } -return FALSE; -} - -/* Select trap */ - -t_bool sel_trap (uint32 va) -{ -if (mode_strap) { - WriteTA (TRAP_704_SAV, va); - PCQ_ENTRY; - TrapXfr (TRAP_SEL_PC); - return TRUE; - } -return FALSE; -} - -/* Store trap address - do not alter state yet (might be TRA) */ - -void WriteTA (uint32 pa, uint32 dat) -{ -t_uint64 mem; - -mem = ReadP (pa) & ~AMASK; -mem |= (dat & AMASK); -WriteP (pa, mem); -return; -} - -/* Set trap PC - second half of address-only trap */ - -void TrapXfr (uint32 newpc) -{ -PC = newpc; -mode_ctrap = 0; -mode_strap = 0; -mode_storn = 0; -mode_user = user_buf = 0; -mode_reloc = reloc_buf = 0; -inst_base = 0; -data_base = 0; -return; -} - -/* Read instruction and indirect */ - -t_bool ReadI (uint32 va, t_uint64 *val) -{ -if (mode_reloc) - va = (va + ind_reloc) & AMASK; -if (mode_user && ((va < ind_start) || (va > ind_limit))) { - prot_trap (0); - return FALSE; - } -*val = M[va | inst_base]; -return TRUE; -} - -/* Read */ - -t_bool Read (uint32 va, t_uint64 *val) -{ -if (mode_reloc) - va = (va + ind_reloc) & AMASK; -if (mode_user && ((va < ind_start) || (va > ind_limit))) { - prot_trap (0); - return FALSE; - } -*val = M[va | data_base]; -return TRUE; -} - -/* Write */ - -t_bool Write (uint32 va, t_uint64 dat) -{ -if (mode_reloc) - va = (va + ind_reloc) & AMASK; -if (mode_user && ((va < ind_start) || (va > ind_limit))) { - prot_trap (0); - return FALSE; - } -M[va | data_base] = dat; -return TRUE; -} - -/* Reset routine */ - -t_stat cpu_reset (DEVICE *dptr) -{ -ind_ovf = 0; -ind_mqo = 0; -ind_dvc = 0; -ind_ioc = 0; -ind_reloc = 0; -ind_start = 0; -ind_limit = 0; -mode_ttrap = 0; -mode_ctrap = 0; -mode_strap = 0; -mode_ftrap = 1; -mode_storn = 0; -if (cpu_model & (I_94|I_CT)) - mode_multi = 0; -else mode_multi = 1; -mode_user = user_buf = 0; -mode_reloc = reloc_buf = 0; -inst_base = 0; -data_base = 0; -ch_req = 0; -chtr_pend = chtr_enab = 0; -chtr_inht = chtr_inhi = 0; -ht_pend = 0; -SLT = 0; -XR[0] = 0; -if (M == NULL) - M = (t_uint64 *) calloc (MAXMEMSIZE, sizeof (t_uint64)); -if (M == NULL) - return SCPE_MEM; -pcq_r = find_reg ("PCQ", NULL, dptr); -if (pcq_r) - pcq_r->qptr = 0; -else return SCPE_IERR; -sim_brk_types = sim_brk_dflt = SWMASK ('E'); -return SCPE_OK; -} - -/* Memory examine */ - -t_stat cpu_ex (t_value *vptr, t_addr ea, UNIT *uptr, int32 sw) -{ -if (vptr == NULL) - return SCPE_ARG; -if ((sw & (SWMASK ('A') | SWMASK ('B')))? (ea > AMASK): (ea >= MEMSIZE)) - return SCPE_NXM; -if (sw & SWMASK ('B')) - ea = ea | BCORE_BASE; -*vptr = M[ea] & DMASK; -return SCPE_OK; -} - -/* Memory deposit */ - -t_stat cpu_dep (t_value val, t_addr ea, UNIT *uptr, int32 sw) -{ -if ((sw & (SWMASK ('A') | SWMASK ('B')))? (ea > AMASK): (ea >= MEMSIZE)) - return SCPE_NXM; -if (sw & SWMASK ('B')) - ea = ea | BCORE_BASE; -M[ea] = val & DMASK; -return SCPE_OK; -} - -/* Set model */ - -t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -UNIT *chuptr = mt_dev[CHRONO_CH].units + CHRONO_UNIT; -extern DEVICE clk_dev; - -cpu_model = val; -if (val & I_CT) { - uptr->capac = MAXMEMSIZE; - detach_unit (uptr); - chuptr->flags &= ~UNIT_ATTABLE; - clk_dev.flags &= ~DEV_DIS; - } -else { - uptr->capac = STDMEMSIZE; - chuptr->flags |= UNIT_ATTABLE; - } -if (!(cpu_model & I_94)) - mode_multi = 1; -return SCPE_OK; -} - -/* Show CTSS */ - -t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -if (cpu_model & I_CT) - fputs ("CTSS", st); -else if (cpu_model & I_94) - fputs ("7094", st); -else fputs ("7090", st); -return SCPE_OK; -} - -/* Insert history entry */ - -static uint32 inst_io_tab[32] = { - 0, 0, 0, 0, 0, 0, 0, 0, /* 0000 - 0377 */ - 0, 0, 0, 0x000000FF, 0, 0, 0, 0x45540000, /* 0400 - 0777 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 1000 - 1400 */ - 0, 0, 0, 0x000000FF, 0, 0, 0, 0 /* 1400 - 1777 */ - }; - -void cpu_ent_hist (uint32 pc, uint32 ea, t_uint64 ir, t_uint64 opnd) -{ -int32 prv_p; - -if (pc & HIST_PC) { - if ((pc == hst[hst_p].pc) && (ir == hst[hst_p].ir)) { /* repeat last? */ - hst[hst_p].rpt++; - return; - } - prv_p = hst_p? hst_p - 1: hst_lnt - 1; - if ((pc == hst[prv_p].pc) && (ir == hst[prv_p].ir)) { /* 2 line loop? */ - hst[prv_p].rpt++; - return; - } - if (hst_ch & HIST_CH_I) { /* IO only? */ - uint32 op = GET_OPC (ir); /* get opcode */ - if ((ir & INST_T_DEC) || - !(inst_io_tab[op / 32] & (1u << (op & 037)))) - return; - } - } -hst_p = (hst_p + 1); /* next entry */ -if (hst_p >= hst_lnt) - hst_p = 0; -hst[hst_p].pc = pc; -hst[hst_p].ir = ir; -hst[hst_p].ac = AC; -hst[hst_p].mq = MQ; -hst[hst_p].si = SI; -hst[hst_p].ea = ea; -hst[hst_p].opnd = opnd; -hst[hst_p].rpt = 0; -return; -} - -/* Set history */ - -t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 i, lnt; -t_stat r; - -if (cptr == NULL) { - for (i = 0; i < hst_lnt; i++) - hst[i].pc = 0; - hst_p = 0; - return SCPE_OK; - } -lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r); -if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) - return SCPE_ARG; -hst_p = 0; -if (hst_lnt) { - free (hst); - hst_lnt = hst_ch = 0; - hst = NULL; - } -if (lnt) { - hst = (InstHistory *) calloc (lnt, sizeof (InstHistory)); - if (hst == NULL) - return SCPE_MEM; - hst_lnt = lnt; - if (sim_switches & SWMASK ('I')) - hst_ch = HIST_CH_I|HIST_CH_C; - else if (sim_switches & SWMASK ('C')) - hst_ch = HIST_CH_C; - else hst_ch = 0; - } -return SCPE_OK; -} - -/* Print one instruction */ - -t_stat cpu_fprint_one_inst (FILE *st, uint32 pc, uint32 rpt, uint32 ea, - t_uint64 ir, t_uint64 ac, t_uint64 mq, t_uint64 si, t_uint64 opnd) -{ -int32 ch; -extern t_value *sim_eval; - -sim_eval[0] = ir; -if (pc & HIST_PC) { /* instruction? */ - fputs ("CPU ", st); - fprintf (st, "%05o ", (int)(pc & AMASK)); - if (rpt == 0) - fprintf (st, " "); - else if (rpt < 1000000) - fprintf (st, "%6d ", rpt); - else fprintf (st, "%5dM ", rpt / 1000000); - fprint_val (st, ac, 8, 38, PV_RZRO); - fputc (' ', st); - fprint_val (st, mq, 8, 36, PV_RZRO); - fputc (' ', st); - fprint_val (st, si, 8, 36, PV_RZRO); - fputc (' ', st); - if (ir & INST_T_DEC) - fprintf (st, " "); - else fprintf (st, "%05o ", ea); - if (fprint_sym (st, pc & AMASK, sim_eval, &cpu_unit, SWMASK ('M')) > 0) { - fputs ("(undefined) ", st); - fprint_val (st, ir, 8, 36, PV_RZRO); - } - else if (!(ir & INST_T_DEC) && (op_flags[GET_OPC (ir)] & I_R)) { - fputs (" [", st); - fprint_val (st, opnd, 8, 36, PV_RZRO); - fputc (']', st); - } - fputc ('\n', st); /* end line */ - } /* end if instruction */ -else if ((ch = HIST_CH (pc))) { /* channel? */ - fprintf (st, "CH%c ", 'A' + ch - 1); - fprintf (st, "%05o ", (int)(pc & AMASK)); - fputs (" ", st); - fprintf (st, "%05o ", (int)(ea & AMASK)); - if (fprint_sym (st, pc & AMASK, sim_eval, &cpu_unit, - (ch_dev[ch - 1].flags & DEV_7909)? SWMASK ('N'): SWMASK ('I')) > 0) { - fputs ("(undefined) ", st); - fprint_val (st, ir, 8, 36, PV_RZRO); - } - fputc ('\n', st); /* end line */ - } /* end else channel */ -return SCPE_OK; -} - -/* Show history */ - -t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -int32 k, di, lnt; -char *cptr = (char *) desc; -t_stat r; -InstHistory *h; - -if (hst_lnt == 0) /* enabled? */ - return SCPE_NOFNC; -if (cptr) { - lnt = (int32) get_uint (cptr, 10, hst_lnt, &r); - if ((r != SCPE_OK) || (lnt == 0)) - return SCPE_ARG; - } -else lnt = hst_lnt; -di = hst_p - lnt; /* work forward */ -if (di < 0) - di = di + hst_lnt; -fprintf (st, " PC repeat AC MQ SI EA IR\n\n"); -for (k = 0; k < lnt; k++) { /* print specified */ - h = &hst[(++di) % hst_lnt]; /* entry pointer */ - cpu_fprint_one_inst (st, h->pc, h->rpt, h->ea, h->ir, h->ac, h->mq, h->si, h->opnd); - } /* end for */ -return SCPE_OK; -} diff --git a/I7094/i7094_cpu1.c b/I7094/i7094_cpu1.c deleted file mode 100644 index 1e3bd402..00000000 --- a/I7094/i7094_cpu1.c +++ /dev/null @@ -1,947 +0,0 @@ -/* i7094_cpu1.c: IBM 7094 CPU complex instructions - - Copyright (c) 2003-2011, 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. - - 31-Dec-11 RMS Refined PSE and MSE user-mode protection based on - CTSS RPQ specification - Select traps have priority over protection traps - 16-Jul-10 RMS Fixed PSE and MSE user-mode protection (Dave Pitts) - Added SPUx, SPTx, SPRx -*/ - -#include "i7094_defs.h" - -#define FP_HIFRAC(x) ((uint32) ((x) >> FP_N_FR) & FP_FMASK) -#define FP_LOFRAC(x) ((uint32) (x) & FP_FMASK) - -#define FP_PACK38(s,e,f) (((s)? AC_S: 0) | ((t_uint64) (f)) | \ - (((t_uint64) ((e) & FP_M_ACCH)) << FP_V_CH)) -#define FP_PACK36(s,e,f) (((s)? SIGN: 0) | ((t_uint64) (f)) | \ - (((t_uint64) ((e) & FP_M_CH)) << FP_V_CH)) - -extern t_uint64 AC, MQ, SI, KEYS; -extern uint32 PC; -extern uint32 SLT, SSW; -extern uint32 cpu_model, stop_illop; -extern uint32 ind_ovf, ind_dvc, ind_ioc, ind_mqo; -extern uint32 mode_ttrap, mode_strap, mode_ctrap, mode_ftrap; -extern uint32 mode_storn, mode_multi; -extern uint32 chtr_pend, chtr_inht, chtr_inhi; -extern uint32 ch_flags[NUM_CHAN]; - -extern t_bool prot_trap (uint32 decr); - -typedef struct { /* unpacked fp */ - uint32 s; /* sign: 0 +, 1 - */ - int32 ch; /* exponent */ - t_uint64 fr; /* fraction (54b) */ - } UFP; - -uint32 op_frnd (void); -t_uint64 fp_fracdiv (t_uint64 dvd, t_uint64 dvr, t_uint64 *rem); -void fp_norm (UFP *op); -void fp_unpack (t_uint64 h, t_uint64 l, t_bool q_ac, UFP *op); -uint32 fp_pack (UFP *op, uint32 mqs, int32 mqch); - -extern t_bool fp_trap (uint32 spill); -extern t_bool sel_trap (uint32 va); -extern t_stat ch_op_reset (uint32 ch, t_bool ch7909); - -/* Integer add - - Sherman: "As the result of an addition or subtraction, if the C(AC) is - zero, the sign of AC is unchanged." */ - -void op_add (t_uint64 op) -{ -t_uint64 mac = AC & AC_MMASK; /* get magnitudes */ -t_uint64 mop = op & MMASK; - -AC = AC & AC_S; /* isolate AC sign */ -if ((AC? 1: 0) ^ ((op & SIGN)? 1: 0)) { /* signs diff? sub */ - if (mac >= mop) /* AC >= MQ */ - AC = AC | (mac - mop); - else AC = (AC ^ AC_S) | (mop - mac); /* <, sign change */ - } -else { - AC = AC | ((mac + mop) & AC_MMASK); /* signs same, add */ - if ((AC ^ mac) & AC_P) /* P change? overflow */ - ind_ovf = 1; - } -return; -} - -/* Multiply */ - -void op_mpy (t_uint64 ac, t_uint64 sr, uint32 sc) -{ -uint32 sign; - -if (sc == 0) /* sc = 0? nop */ - return; -sign = ((MQ & SIGN)? 1: 0) ^ ((sr & SIGN)? 1: 0); /* result sign */ -ac = ac & AC_MMASK; /* clear AC sign */ -sr = sr & MMASK; /* mpy magnitude */ -MQ = MQ & MMASK; /* MQ magnitude */ -if (sr && MQ) { /* mpy != 0? */ - while (sc--) { /* for sc */ - if (MQ & 1) /* MQ35? AC += mpy */ - ac = (ac + sr) & AC_MMASK; - MQ = (MQ >> 1) | ((ac & 1) << 34); /* AC'MQ >> 1 */ - ac = ac >> 1; - } - } -else ac = MQ = 0; /* result = 0 */ -if (sign) { /* negative? */ - ac = ac | AC_S; /* insert signs */ - MQ = MQ | SIGN; - } -AC = ac; /* update AC */ -return; -} - -/* Divide */ - -t_bool op_div (t_uint64 sr, uint32 sc) -{ -uint32 signa, signm; - -if (sc == 0) /* sc = 0? nop */ - return FALSE; -signa = (AC & AC_S)? 1: 0; /* get signs */ -signm = (sr & SIGN)? 1: 0; -sr = sr & MMASK; /* get dvr magn */ -if ((AC & AC_MMASK) >= sr) /* |AC| >= |sr|? */ - return TRUE; -AC = AC & AC_MMASK; /* AC, MQ magn */ -MQ = MQ & MMASK; -while (sc--) { /* for sc */ - AC = ((AC << 1) & AC_MMASK) | (MQ >> 34); /* AC'MQ << 1 */ - MQ = (MQ << 1) & MMASK; - if (AC >= sr) { /* AC >= dvr? */ - AC = AC - sr; /* AC -= dvr */ - MQ = MQ | 1; /* set quo bit */ - } - } -if (signa ^ signm) /* quo neg? */ - MQ = MQ | SIGN; -if (signa) /* rem neg? */ - AC = AC | AC_S; -return FALSE; /* div ok */ -} - -/* Shifts */ - -void op_als (uint32 addr) -{ -uint32 sc = addr & SCMASK; - -if ((sc >= 35)? /* shift >= 35? */ - ((AC & MMASK) != 0): /* test all bits for ovf */ - (((AC & MMASK) >> (35 - sc)) != 0)) /* test only 35-sc bits */ - ind_ovf = 1; -if (sc >= 37) /* sc >= 37? result 0 */ - AC = AC & AC_S; -else AC = (AC & AC_S) | ((AC << sc) & AC_MMASK); /* shift, save sign */ -return; -} - -void op_ars (uint32 addr) -{ -uint32 sc = addr & SCMASK; - -if (sc >= 37) /* sc >= 37? result 0 */ - AC = AC & AC_S; -else AC = (AC & AC_S) | ((AC & AC_MMASK) >> sc); /* shift, save sign */ -return; -} - -void op_lls (uint32 addr) -{ -uint32 sc; /* get sc */ - -AC = AC & AC_MMASK; /* clear AC sign */ -for (sc = addr & SCMASK; sc != 0; sc--) { /* for SC */ - AC = ((AC << 1) & AC_MMASK) | ((MQ >> 34) & 1); /* AC'MQ << 1 */ - MQ = (MQ & SIGN) | ((MQ << 1) & MMASK); /* preserve MQ sign */ - if (AC & AC_P) /* if P, overflow */ - ind_ovf = 1; - } -if (MQ & SIGN) /* set ACS from MQS */ - AC = AC | AC_S; -return; -} - -void op_lrs (uint32 addr) -{ -uint32 sc = addr & SCMASK; -t_uint64 mac; - -MQ = MQ & MMASK; /* get MQ magnitude */ -if (sc != 0) { - mac = AC & AC_MMASK; /* get AC magnitude, */ - AC = AC & AC_S; /* sign */ - if (sc < 35) { /* sc [1,34]? */ - MQ = ((MQ >> sc) | (mac << (35 - sc))) & MMASK; /* MQ has AC'MQ */ - AC = AC | (mac >> sc); /* AC has AC only */ - } - else if (sc < 37) { /* sc [35:36]? */ - MQ = (mac >> (sc - 35)) & MMASK; /* MQ has AC only */ - AC = AC | (mac >> sc); /* AC has */ - } - else if (sc < 72) /* sc [37:71]? */ - MQ = (mac >> (sc - 35)) & MMASK; /* MQ has AC only */ - else MQ = 0; /* >72? MQ = 0 */ - } -if (AC & AC_S) /* set MQS from ACS */ - MQ = MQ | SIGN; -return; -} - -void op_lgl (uint32 addr) -{ -uint32 sc; /* get sc */ - -for (sc = addr & SCMASK; sc != 0; sc--) { /* for SC */ - AC = (AC & AC_S) | ((AC << 1) & AC_MMASK) | /* AC'MQ << 1 */ - ((MQ >> 35) & 1); /* preserve AC sign */ - MQ = (MQ << 1) & DMASK; - if (AC & AC_P) /* if P, overflow */ - ind_ovf = 1; - } -return; -} - -void op_lgr (uint32 addr) -{ -uint32 sc = addr & SCMASK; -t_uint64 mac; - -if (sc != 0) { - mac = AC & AC_MMASK; /* get AC magnitude, */ - AC = AC & AC_S; /* sign */ - if (sc < 36) { /* sc [1,35]? */ - MQ = ((MQ >> sc) | (mac << (36 - sc))) & DMASK; /* MQ has AC'MQ */ - AC = AC | (mac >> sc); /* AC has AC only */ - } - else if (sc == 36) { /* sc [36]? */ - MQ = mac & DMASK; /* MQ = AC */ - AC = AC | (mac >> 36); /* AC = AC */ - } - else if (sc < 73) /* sc [37, 72]? */ - MQ = (mac >> (sc - 36)) & DMASK; /* MQ has AC only */ - else MQ = 0; /* >72, AC,MQ = 0 */ - } -return; -} - -/* Plus sense - undefined operations are NOPs */ - -t_stat op_pse (uint32 addr) -{ -uint32 ch, spill; - -switch (addr) { - - case 00000: /* CLM */ - if (cpu_model & I_9X) /* 709X only */ - AC = AC & AC_S; - break; - - case 00001: /* LBT */ - if ((AC & 1) != 0) - PC = (PC + 1) & AMASK; - break; - - case 00002: /* CHS */ - AC = AC ^ AC_S; - break; - - case 00003: /* SSP */ - AC = AC & ~AC_S; - break; - - case 00004: /* ENK */ - MQ = KEYS; - break; - - case 00005: /* IOT */ - if (prot_trap (0)) /* user mode? */ - break; - if (ind_ioc) - ind_ioc = 0; - else PC = (PC + 1) & AMASK; - break; - - case 00006: /* COM */ - AC = AC ^ AC_MMASK; - break; - - case 00007: /* ETM */ - if (cpu_model & I_9X) { /* 709X only */ - if (prot_trap (0)) /* user mode? */ - break; - mode_ttrap = 1; - } - break; - - case 00010: /* RND */ - if ((cpu_model & I_9X) && (MQ & B1)) /* 709X only, MQ1 set? */ - op_add ((t_uint64) 1); /* incr AC */ - break; - - case 00011: /* FRN */ - if (cpu_model & I_9X) { /* 709X only */ - spill = op_frnd (); - if (spill) - fp_trap (spill); - } - break; - - case 00012: /* DCT */ - if (ind_dvc) - ind_dvc = 0; - else PC = (PC + 1) & AMASK; - break; - - case 00014: /* RCT */ - if (prot_trap (0)) /* user mode? */ - break; - chtr_inhi = 1; /* 1 cycle delay */ - chtr_inht = 0; /* clr inhibit trap */ - chtr_pend = 0; /* no trap now */ - break; - - case 00016: /* LMTM */ - if (cpu_model & I_94) /* 709X only */ - mode_multi = 0; - break; - - case 00140: /* SLF */ - if (cpu_model & I_9X) /* 709X only */ - SLT = 0; - break; - - case 00141: case 00142: case 00143: case 00144: /* SLN */ - if (cpu_model & I_9X) /* 709X only */ - SLT = SLT | (1u << (00144 - addr)); - break; - - case 00161: case 00162: case 00163: /* SWT */ - case 00164: case 00165: case 00166: - if ((SSW & (1u << (00166 - addr))) != 0) - PC = (PC + 1) & AMASK; - break; - - case 001000: case 002000: case 003000: case 004000: /* BTT */ - case 005000: case 060000: case 070000: case 010000: - if (cpu_model & I_9X) { /* 709X only */ - if (sel_trap (0) || prot_trap (PC)) /* select takes priority */ - break; - ch = GET_U_CH (addr); /* get channel */ - if (ch_flags[ch] & CHF_BOT) /* BOT? */ - ch_flags[ch] &= ~CHF_BOT; /* clear */ - else PC = (PC + 1) & AMASK; /* else skip */ - } - break; - - case 001350: case 002350: case 003350: case 004350: /* RICx */ - case 005350: case 006350: case 007350: case 010350: - if (prot_trap (0)) /* user mode? */ - break; - ch = GET_U_CH (addr); /* get channel */ - return ch_op_reset (ch, 1); - - case 001352: case 002352: case 003352: case 004352: /* RDCx */ - case 005352: case 006352: case 007352: case 010352: - if (prot_trap (0)) /* user mode? */ - break; - ch = GET_U_CH (addr); /* get channel */ - return ch_op_reset (ch, 0); - - case 001341: case 002341: case 003341: case 004341: /* SPUx */ - case 005341: case 006341: case 007341: case 010341: - case 001342: case 002342: case 003342: case 004342: /* SPUx 2 */ - case 005342: case 006342: case 007342: case 010342: - case 001360: case 002360: case 003360: case 004360: /* SPTx */ - case 005360: case 006360: case 007360: case 010360: - case 001361: case 002361: case 003361: case 004361: /* SPRx */ - case 005361: case 006361: case 007361: case 010361: - case 001362: case 002362: case 003362: case 004362: /* SPRx 2 */ - case 005362: case 006362: case 007362: case 010362: - case 001363: case 002363: case 003363: case 004363: /* SPRx 3 */ - case 005363: case 006363: case 007363: case 010363: - case 001364: case 002364: case 003364: case 004364: /* SPRx 4 */ - case 005364: case 006364: case 007364: case 010364: - case 001365: case 002365: case 003365: case 004365: /* SPRx 5 */ - case 005365: case 006365: case 007365: case 010365: - case 001366: case 002366: case 003366: case 004366: /* SPRx 6 */ - case 005366: case 006366: case 007366: case 010366: - case 001367: case 002367: case 003367: case 004367: /* SPRx 7 */ - case 005367: case 006367: case 007367: case 010367: - if (prot_trap (0)) /* user mode? */ - break; - break; /* no ops */ - } /* end case */ - -return SCPE_OK; -} - -/* Minus sense */ - -t_stat op_mse (uint32 addr) -{ -uint32 t, ch; - -switch (addr) { - - case 00000: /* CLM */ - if (cpu_model & I_9X) /* 709X only */ - AC = AC & AC_S; - break; - - case 00001: /* PBT */ - if ((AC & AC_P) != 0) - PC = (PC + 1) & AMASK; - break; - - case 00002: /* EFTM */ - if (prot_trap (0)) /* user mode? */ - break; - if (cpu_model & I_9X) { /* 709X only */ - mode_ftrap = 1; - ind_mqo = 0; /* clears MQ ovf */ - } - break; - - case 00003: /* SSM */ - if (cpu_model & I_9X) /* 709X only */ - AC = AC | AC_S; - break; - - case 00004: /* LFTM */ - if (cpu_model & I_9X) { /* 709X only */ - if (prot_trap (0)) /* user mode? */ - break; - mode_ftrap = 0; - } - break; - - case 00005: /* ESTM */ - if (cpu_model & I_9X) { /* 709X only */ - if (prot_trap (0)) /* user mode? */ - break; - mode_strap = 1; - } - break; - - case 00006: /* ECTM */ - if (cpu_model & I_9X) { /* 709X only */ - if (prot_trap (0)) /* user mode? */ - break; - mode_ctrap = 1; - } - break; - - case 00007: /* LTM */ - if (cpu_model & I_9X) { /* 709X only */ - if (prot_trap (0)) /* user mode? */ - break; - mode_ttrap = 0; - } - break; - - case 00010: /* LSNM */ - if (cpu_model & I_9X) { /* 709X only */ - if (prot_trap (0)) /* user mode? */ - break; - mode_storn = 0; - } - break; - - case 00012: /* RTT (704) */ - if (cpu_model & I_9X) /* 709X only */ - sel_trap (PC); - break; - - case 00016: /* EMTM */ - mode_multi = 1; - break; - - case 00140: /* SLF */ - if (cpu_model & I_9X) /* 709X only */ - SLT = 0; - break; - - case 00141: case 00142: case 00143: case 00144: /* SLT */ - if (cpu_model & I_9X) { /* 709X only */ - t = SLT & (1u << (00144 - addr)); - SLT = SLT & ~t; - if (t != 0) - PC = (PC + 1) & AMASK; - } - break; - - case 00161: case 00162: case 00163: /* SWT */ - case 00164: case 00165: case 00166: - if ((cpu_model & I_9X) && /* 709X only */ - ((SSW & (1u << (00166 - addr))) != 0)) - PC = (PC + 1) & AMASK; - break; - - case 001000: case 002000: case 003000: case 004000: /* ETT */ - case 005000: case 006000: case 007000: case 010000: - if (sel_trap (0) || prot_trap (PC)) /* select takes priority */ - break; - ch = GET_U_CH (addr); /* get channel */ - if (ch_flags[ch] & CHF_EOT) /* EOT? */ - ch_flags[ch] = ch_flags[ch] & ~CHF_EOT; /* clear */ - else PC = (PC + 1) & AMASK; /* else skip */ - break; - } - -return SCPE_OK; -} - -/* Floating add - - Notes: - - AC enter into the initial exponent comparison. If either is set, - the numbers are always swapped. AC

gets OR'd into AC during the - swap, and AC are cleared afterwards - - The early end test is actually > 077 if AC <= SR and > 100 if - AC > SR. However, any shift >= 54 will produce a zero fraction, - so the difference can be ignored */ - -uint32 op_fad (t_uint64 sr, t_bool norm) -{ -UFP op1, op2, t; -int32 mqch, diff; - -MQ = 0; /* clear MQ */ -fp_unpack (AC, 0, 1, &op1); /* unpack AC */ -fp_unpack (sr, 0, 0, &op2); /* unpack sr */ -if (op1.ch > op2.ch) { /* AC exp > SR exp? */ - if (AC & AC_P) /* AC P or's with S */ - op1.s = 1; - t = op1; /* swap operands */ - op1 = op2; - op2 = t; - op2.ch = op2.ch & FP_M_CH; /* clear P,Q */ - } -diff = op2.ch - op1.ch; /* exp diff */ -if (diff) { /* any shift? */ - if ((diff < 0) || (diff > 077)) /* diff > 63? */ - op1.fr = 0; - else op1.fr = op1.fr >> diff; /* no, denormalize */ - } -if (op1.s ^ op2.s) { /* subtract? */ - if (op1.fr >= op2.fr) { /* op1 > op2? */ - op2.fr = op1.fr - op2.fr; /* op1 - op2 */ - op2.s = op1.s; /* op2 sign is result */ - } - else op2.fr = op2.fr - op1.fr; /* else op2 - op1 */ - } -else { - op2.fr = op2.fr + op1.fr; /* op2 + op1 */ - if (op2.fr & FP_FCRY) { /* carry? */ - op2.fr = op2.fr >> 1; /* renormalize */ - op2.ch++; /* incr exp */ - } - } -if (norm) { /* normalize? */ - if (op2.fr) { /* non-zero frac? */ - fp_norm (&op2); - mqch = op2.ch - FP_N_FR; - } - else op2.ch = mqch = 0; /* else true zero */ - } -else mqch = op2.ch - FP_N_FR; -return fp_pack (&op2, op2.s, mqch); /* pack AC, MQ */ -} - -/* Floating multiply */ - -uint32 op_fmp (t_uint64 sr, t_bool norm) -{ -UFP op1, op2; -int32 mqch; -uint32 f1h, f2h; - -fp_unpack (MQ, 0, 0, &op1); /* unpack MQ */ -fp_unpack (sr, 0, 0, &op2); /* unpack sr */ -op1.s = op1.s ^ op2.s; /* result sign */ -if ((op2.ch == 0) && (op2.fr == 0)) { /* sr a normal 0? */ - AC = op1.s? AC_S: 0; /* result is 0 */ - MQ = op1.s? SIGN: 0; - return 0; - } -f1h = FP_HIFRAC (op1.fr); /* get hi fracs */ -f2h = FP_HIFRAC (op2.fr); -op1.fr = ((t_uint64) f1h) * ((t_uint64) f2h); /* f1h * f2h */ -op1.ch = (op1.ch & FP_M_CH) + op2.ch - FP_BIAS; /* result exponent */ -if (norm) { /* normalize? */ - if (!(op1.fr & FP_FNORM)) { /* not normalized? */ - op1.fr = op1.fr << 1; /* shift frac left 1 */ - op1.ch--; /* decr exp */ - } - if (FP_HIFRAC (op1.fr)) /* hi result non-zero? */ - mqch = op1.ch - FP_N_FR; /* set MQ exp */ - else op1.ch = mqch = 0; /* clear AC, MQ exp */ - } -else mqch = op1.ch - FP_N_FR; /* set MQ exp */ -return fp_pack (&op1, op1.s, mqch); /* pack AC, MQ */ -} - -/* Floating divide */ - -uint32 op_fdv (t_uint64 sr) -{ -UFP op1, op2; -int32 mqch; -uint32 spill, quos; -t_uint64 rem; - -fp_unpack (AC, 0, 1, &op1); /* unpack AC */ -fp_unpack (sr, 0, 0, &op2); /* unpack sr */ -quos = op1.s ^ op2.s; /* quotient sign */ -if (op1.fr >= (2 * op2.fr)) { /* |AC| >= 2*|sr|? */ - MQ = quos? SIGN: 0; /* MQ = sign only */ - return TRAP_F_DVC; /* divide check */ - } -if (op1.fr == 0) { /* |AC| == 0? */ - MQ = quos? SIGN: 0; /* MQ = sign only */ - AC = 0; /* AC = +0 */ - return 0; /* done */ - } -op1.ch = op1.ch & FP_M_CH; /* remove AC */ -if (op1.fr >= op2.fr) { /* |AC| >= |sr|? */ - op1.fr = op1.fr >> 1; /* denorm AC */ - op1.ch++; - } -op1.fr = fp_fracdiv (op1.fr, op2.fr, &rem); /* fraction divide */ -op1.fr = op1.fr | (rem << FP_N_FR); /* rem'quo */ -mqch = op1.ch - op2.ch + FP_BIAS; /* quotient exp */ -op1.ch = op1.ch - FP_N_FR; /* remainder exp */ -spill = fp_pack (&op1, quos, mqch); /* pack up */ -return (spill? (spill | TRAP_F_SGL): 0); /* if spill, set SGL */ -} - -/* Double floating add - - Notes: - - AC enter into the initial exponent comparison. If either is set, - the numbers are always swapped. AC

gets OR'd into AC during the - swap, and AC are cleared afterwards - - For most cases, SI ends up with the high order part of the larger number - - The 'early end' cases (smaller number is shifted away) must be tracked - exactly for SI impacts. The early end cases are: - - (a) AC > SR, diff > 0100, and AC normalized - (b) AC <= SR, diff > 077, and SR normalized - - In case (a), SI is unchanged. In case (b), SI ends up with the SR sign - and characteristic but the MQ (!) fraction */ - -uint32 op_dfad (t_uint64 sr, t_uint64 sr1, t_bool norm) -{ -UFP op1, op2, t; -int32 mqch, diff; - -fp_unpack (AC, MQ, 1, &op1); /* unpack AC'MQ */ -fp_unpack (sr, sr1, 0, &op2); /* unpack sr'sr1 */ -if (op1.ch > op2.ch) { /* AC exp > SR exp? */ - if (((op1.ch - op2.ch) > 0100) && (AC & B9)) ; /* early out */ - else SI = FP_PACK36 (op1.s, op1.ch, FP_HIFRAC (op1.fr)); - if (AC & AC_P) /* AC P or's with S */ - op1.s = 1; - t = op1; /* swap operands */ - op1 = op2; - op2 = t; - op2.ch = op2.ch & FP_M_CH; /* clear P,Q */ - } -else { /* AC <= SR */ - if (((op2.ch - op1.ch) > 077) && (sr & B9)) /* early out */ - SI = FP_PACK36 (op2.s, op2.ch, FP_LOFRAC (MQ)); - else SI = FP_PACK36 (op2.s, op2.ch, FP_HIFRAC (op2.fr)); - } -diff = op2.ch - op1.ch; /* exp diff */ -if (diff) { /* any shift? */ - if ((diff < 0) || (diff > 077)) /* diff > 63? */ - op1.fr = 0; - else op1.fr = op1.fr >> diff; /* no, denormalize */ - } -if (op1.s ^ op2.s) { /* subtract? */ - if (op1.fr >= op2.fr) { /* op1 > op2? */ - op2.fr = op1.fr - op2.fr; /* op1 - op2 */ - op2.s = op1.s; /* op2 sign is result */ - } - else op2.fr = op2.fr - op1.fr; /* op2 - op1 */ - } -else { - op2.fr = op2.fr + op1.fr; /* op2 + op1 */ - if (op2.fr & FP_FCRY) { /* carry? */ - op2.fr = op2.fr >> 1; /* renormalize */ - op2.ch++; /* incr exp */ - } - } -if (norm) { /* normalize? */ - if (op2.fr) { /* non-zero frac? */ - fp_norm (&op2); - mqch = op2.ch - FP_N_FR; - } - else op2.ch = mqch = 0; /* else true zero */ - } -else mqch = op2.ch - FP_N_FR; -return fp_pack (&op2, op2.s, mqch); /* pack AC, MQ */ -} - -/* Double floating multiply - - Notes (notation is A+B' * C+D', where ' denotes 2^-27): - - The instruction returns 0 if A and C are both zero, because B*D is never - done as part of the algorithm - - For most cases, SI ends up with B*C, with a zero sign and exponent - - For the A+B' both zero 'early end' case SI ends up with A or C, - depending on whether the operation is normalized or not */ - -uint32 op_dfmp (t_uint64 sr, t_uint64 sr1, t_bool norm) -{ -UFP op1, op2; -int32 mqch; -uint32 f1h, f2h, f1l, f2l; -t_uint64 tx; - -fp_unpack (AC, MQ, 1, &op1); /* unpack AC'MQ */ -fp_unpack (sr, sr1, 0, &op2); /* unpack sr'sr1 */ -op1.s = op1.s ^ op2.s; /* result sign */ -f1h = FP_HIFRAC (op1.fr); /* A */ -f1l = FP_LOFRAC (op1.fr); /* B */ -f2h = FP_HIFRAC (op2.fr); /* C */ -f2l = FP_LOFRAC (op2.fr); /* D */ -if (((op1.ch == 0) && (op1.fr == 0)) || /* AC'MQ normal 0? */ - ((op2.ch == 0) && (op2.fr == 0)) || /* sr'sr1 normal 0? */ - ((f1h == 0) && (f2h == 0))) { /* both hi frac zero? */ - AC = op1.s? AC_S: 0; /* result is 0 */ - MQ = op1.s? SIGN: 0; - SI = sr; /* SI has C */ - return 0; - } -op1.ch = (op1.ch & FP_M_CH) + op2.ch - FP_BIAS; /* result exponent */ -if (op1.fr) { /* A'B != 0? */ - op1.fr = ((t_uint64) f1h) * ((t_uint64) f2h); /* A * C */ - tx = ((t_uint64) f1h) * ((t_uint64) f2l); /* A * D */ - op1.fr = op1.fr + (tx >> FP_N_FR); /* add in hi 27b */ - tx = ((t_uint64) f1l) * ((t_uint64) f2h); /* B * C */ - op1.fr = op1.fr + (tx >> FP_N_FR); /* add in hi 27b */ - SI = tx >> FP_N_FR; /* SI keeps B * C */ - } -else { - if (norm) /* early out */ - SI = sr; - else SI = FP_PACK36 (op2.s, op2.ch, 0); - } -if (norm) { /* normalize? */ - if (!(op1.fr & FP_FNORM)) { /* not normalized? */ - op1.fr = op1.fr << 1; /* shift frac left 1 */ - op1.ch--; /* decr exp */ - } - if (FP_HIFRAC (op1.fr)) { /* non-zero? */ - mqch = op1.ch - FP_N_FR; /* set MQ exp */ - } - else op1.ch = mqch = 0; /* clear AC, MQ exp */ - } -else mqch = op1.ch - FP_N_FR; /* set MQ exp */ -return fp_pack (&op1, op1.s, mqch); /* pack AC, MQ */ -} - -/* Double floating divide - - - Notes: - - This is a Taylor series expansion (where ' denotes >> 27): - - (A+B') * (C+D')^-1 = (A+B') * C^-1 - (A+B') * D'* C^-2 +... - - to two terms, which can be rewritten as terms Q1, Q2: - - Q1 = (A+B')/C - Q2' = (R - Q1*D)'/C - - - Tracking the sign of Q2' is complicated: - - Q1 has the sign of the quotient, s_AC ^ s_SR - D has the sign of the divisor, s_SR - R has the sign of the dividend, s_AC - Q1*D sign is s_AC ^ s_SR ^ s^SR = s^AC - Therefore, R and Q1*D have the same sign, s_AC - Q2' sign is s^AC ^ s_SR, which is the sign of the quotient - - - For first divide check, SI is 0 - - For other cases, including second divide check, SI ends up with Q1 - - R-Q1*D is only calculated to the high 27b; using the full 54b - throws off the result - - The second divide must check for divd >= divr, otherwise an extra - bit of quotient would be devloped, throwing off the result - - A late ECO added full post-normalization; single precision divide - does no normalization */ - -uint32 op_dfdv (t_uint64 sr, t_uint64 sr1) -{ -UFP op1, op2; -int32 mqch; -uint32 csign, ac_s; -t_uint64 f1h, f2h, tr, tq1, tq1d, trmq1d, tq2; - -fp_unpack (AC, MQ, 1, &op1); /* unpack AC'MQ */ -fp_unpack (sr, 0, 0, &op2); /* unpack sr only */ -ac_s = op1.s; /* save AC sign */ -op1.s = op1.s ^ op2.s; /* sign of result */ -f1h = FP_HIFRAC (op1.fr); -f2h = FP_HIFRAC (op2.fr); -if (f1h >= (2 * f2h)) { /* |A| >= 2*|C|? */ - SI = 0; /* clear SI */ - return TRAP_F_DVC; /* divide check */ - } -if (f1h == 0) { /* |AC| == 0? */ - SI = MQ = op1.s? SIGN: 0; /* MQ, SI = sign only */ - AC = op1.s? AC_S: 0; /* AC = sign only */ - return 0; /* done */ - } -op1.ch = op1.ch & FP_M_CH; /* remove AC */ -if (f1h >= f2h) { /* |A| >= |C|? */ - op1.fr = op1.fr >> 1; /* denorm AC */ - op1.ch++; - } -op1.ch = op1.ch - op2.ch + FP_BIAS; /* exp of quotient */ -tq1 = fp_fracdiv (op1.fr, op2.fr, &tr); /* |A+B| / |C| */ -tr = tr << FP_N_FR; /* R << 27 */ -tq1d = (tq1 * ((t_uint64) FP_LOFRAC (sr1))) & /* Q1 * D */ - ~((t_uint64) FP_FMASK); /* top 27 bits */ -csign = (tr < tq1d); /* correction sign */ -if (csign) /* |R|<|Q1*D|? compl */ - trmq1d = tq1d - tr; -else trmq1d = tr - tq1d; /* no, subtr ok */ -SI = FP_PACK36 (op1.s, op1.ch, tq1); /* SI has Q1 */ -if (trmq1d >= (2 * op2.fr)) { /* |R-Q1*D| >= 2*|C|? */ - AC = FP_PACK38 (csign ^ ac_s, 0, FP_HIFRAC (trmq1d)); /* AC has R-Q1*D */ - MQ = (csign ^ ac_s)? SIGN: 0; /* MQ = sign only */ - return TRAP_F_DVC; /* divide check */ - } -tq2 = fp_fracdiv (trmq1d, op2.fr, NULL); /* |R-Q1*D| / |C| */ -if (trmq1d >= op2.fr) /* can only gen 27b quo */ - tq2 &= ~((t_uint64) 1); -op1.fr = tq1 << FP_N_FR; /* shift Q1 into place */ -if (csign) /* sub or add Q2 */ - op1.fr = op1.fr - tq2; -else op1.fr = op1.fr + tq2; -fp_norm (&op1); /* normalize */ -if (op1.fr) /* non-zero? */ - mqch = op1.ch - FP_N_FR; -else op1.ch = mqch = 0; /* clear AC, MQ exp */ -return fp_pack (&op1, op1.s, mqch); /* pack AC, MQ */ -} - -/* Floating round */ - -uint32 op_frnd (void) -{ -UFP op; -uint32 spill; - -spill = 0; /* no error */ -if (MQ & B9) { /* MQ9 set? */ - fp_unpack (AC, 0, 1, &op); /* unpack AC */ - op.fr = op.fr + ((t_uint64) (1 << FP_N_FR)); /* round up */ - if (op.fr & FP_FCRY) { /* carry out? */ - op.fr = op.fr >> 1; /* renormalize */ - op.ch++; /* incr exp */ - if (op.ch == (FP_M_CH + 1)) /* ovf with QP = 0? */ - spill = TRAP_F_OVF | TRAP_F_AC; - } - AC = FP_PACK38 (op.s, op.ch, FP_HIFRAC (op.fr)); /* pack AC */ - } -return spill; -} - -/* Fraction divide - 54/27'0 yielding quotient and remainder */ - -t_uint64 fp_fracdiv (t_uint64 dvd, t_uint64 dvr, t_uint64 *rem) -{ -dvr = dvr >> FP_N_FR; -if (rem) - *rem = dvd % dvr; -return (dvd / dvr); -} - -/* Floating point normalize */ - -void fp_norm (UFP *op) -{ -op->fr = op->fr & FP_DFMASK; /* mask fraction */ -if (op->fr == 0) /* zero? */ - return; -while ((op->fr & FP_FNORM) == 0) { /* until norm */ - op->fr = op->fr << 1; /* lsh 1 */ - op->ch--; /* decr exp */ - } -return; -} - -/* Floating point unpack */ - -void fp_unpack (t_uint64 h, t_uint64 l, t_bool q_ac, UFP *op) -{ -if (q_ac) { /* AC? */ - op->s = (h & AC_S)? 1: 0; /* get sign */ - op->ch = (uint32) ((h >> FP_V_CH) & FP_M_ACCH); /* get exp */ - } -else { - op->s = (h & SIGN)? 1: 0; /* no, mem */ - op->ch = (uint32) ((h >> FP_V_CH) & FP_M_CH); - } -op->fr = (((t_uint64) FP_LOFRAC (h)) << FP_N_FR) | /* get frac hi */ - ((t_uint64) FP_LOFRAC (l)); /* get frac lo */ -return; -} - -/* Floating point pack */ - -uint32 fp_pack (UFP *op, uint32 mqs, int32 mqch) -{ -uint32 spill; - -AC = FP_PACK38 (op->s, op->ch, FP_HIFRAC (op->fr)); /* pack AC */ -MQ = FP_PACK36 (mqs, mqch, FP_LOFRAC (op->fr)); /* pack MQ */ -if (op->ch > FP_M_CH) /* check AC exp */ - spill = TRAP_F_OVF | TRAP_F_AC; -else if (op->ch < 0) - spill = TRAP_F_AC; -else spill = 0; -if (mqch > FP_M_CH) /* check MQ exp */ - spill |= (TRAP_F_OVF | TRAP_F_MQ); -else if (mqch < 0) - spill |= TRAP_F_MQ; -return spill; -} diff --git a/I7094/i7094_dat.h b/I7094/i7094_dat.h deleted file mode 100644 index b50b38c3..00000000 --- a/I7094/i7094_dat.h +++ /dev/null @@ -1,152 +0,0 @@ -/* i7094_dat.h: IBM 7094 data conversion tables - - Copyright (c) 2003-2008, 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. -*/ - -/* Nine-code to ASCII conversion */ - -const char nine_to_ascii_a[64] = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '^', '#', '@', ':', '>', '{', - '&', 'A', 'B', 'C', 'D', 'E', 'F', 'G', - 'H', 'I', '?', '.', ')', '[', '<', '}', - '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', '!', '$', '*', ']', ';', '_', - ' ', '/', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', '|', ',', '%', '~', '\\', '"', - }; - -const char nine_to_ascii_h[64] = { - '0', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '^', '=', '\'', ':', '>', '{', - '+', 'A', 'B', 'C', 'D', 'E', 'F', 'G', - 'H', 'I', '?', '.', ')', '[', '<', '}', - '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', '!', '$', '*', ']', ';', '_', - ' ', '/', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', '|', ',', '(', '~', '\\', '"', - }; - -/* ASCII to nine-code conversion */ - -const char ascii_to_nine[128] = { - 060, 060, 060, 060, 060, 060, 060, 060, /* 000 - 037 */ - 060, 060, 060, 060, 060, 060, 060, 060, - 060, 060, 060, 060, 060, 060, 060, 060, - 060, 060, 060, 060, 060, 060, 060, 060, - 060, 052, 077, 013, 053, 074, 020, 014, /* 040 - 077 */ - 074, 034, 054, 020, 073, 040, 033, 061, - 000, 001, 002, 003, 004, 005, 006, 007, - 010, 011, 015, 056, 036, 013, 016, 032, - 014, 021, 022, 023, 024, 025, 026, 027, /* 100 - 137 */ - 030, 031, 041, 042, 043, 044, 045, 046, - 047, 050, 051, 062, 063, 064, 065, 066, - 067, 070, 071, 035, 076, 055, 012, 057, - 060, 021, 022, 023, 024, 025, 026, 027, /* 140 - 177 */ - 030, 031, 041, 042, 043, 044, 045, 046, - 047, 050, 051, 062, 063, 064, 065, 066, - 067, 070, 071, 017, 072, 037, 075, 060 - }; - -/* ASCII to BCD conversion */ - -const char ascii_to_bcd[128] = { - 000, 000, 000, 000, 000, 000, 000, 000, /* 000 - 037 */ - 000, 000, 000, 000, 000, 000, 000, 000, - 000, 000, 000, 000, 000, 000, 000, 000, - 000, 000, 000, 000, 000, 000, 000, 000, - 000, 052, 037, 013, 053, 074, 060, 014, /* 040 - 077 */ - 034, 074, 054, 060, 033, 040, 073, 021, - 020, 001, 002, 003, 004, 005, 006, 007, - 010, 011, 015, 056, 076, 013, 016, 072, - 014, 061, 062, 063, 064, 065, 066, 067, /* 100 - 137 */ - 070, 071, 041, 042, 043, 044, 045, 046, - 047, 050, 051, 022, 023, 024, 025, 026, - 027, 030, 031, 075, 036, 055, 012, 057, - 000, 061, 062, 063, 064, 065, 066, 067, /* 140 - 177 */ - 070, 071, 041, 042, 043, 044, 045, 046, - 047, 050, 051, 022, 023, 024, 025, 026, - 027, 030, 031, 017, 032, 077, 035, 000 - }; - -/* BCD to ASCII conversion */ - -const char bcd_to_ascii_a[64] = { - ' ', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '^', '#', '@', ':', '>', '{', - '0', '/', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', '|', ',', '%', '~', '\\', '"', - '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', '!', '$', '*', ']', ';', '_', - '&', 'A', 'B', 'C', 'D', 'E', 'F', 'G', - 'H', 'I', '?', '.', ')', '[', '<', '}' - }; - -const char bcd_to_ascii_h[64] = { - ' ', '1', '2', '3', '4', '5', '6', '7', - '8', '9', '^', '=', '\'', ':', '>', '{', - '0', '/', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', '|', ',', '(', '~', '\\', '"', - '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', '!', '$', '*', ']', ';', '_', - '+', 'A', 'B', 'C', 'D', 'E', 'F', 'G', - 'H', 'I', '?', '.', ')', '[', '<', '}' - }; - -/* BCD to ASCII 48 character print chains */ - -const char bcd_to_pca[64] = { - ' ', '1', '2', '3', '4', '5', '6', '7', - '8', '9', ' ', '#', '@', ' ', ' ', ' ', - '0', '/', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', ' ', ',', '%', ' ', ' ', ' ', - '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', '-', '$', '*', ' ', ' ', ' ', - '&', 'A', 'B', 'C', 'D', 'E', 'F', 'G', - 'H', 'I', '&', '.', ')', ' ', ' ', ' ' - }; - -const char bcd_to_pch[64] = { - ' ', '1', '2', '3', '4', '5', '6', '7', - '8', '9', ' ', '=', '\'', ' ', ' ', ' ', - '0', '/', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', ' ', ',', '(', ' ', ' ', ' ', - '-', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', '-', '$', '*', ' ', ' ', ' ', - '&', 'A', 'B', 'C', 'D', 'E', 'F', 'G', - 'H', 'I', '&', '.', ')', ' ', ' ', ' ' - }; - -/* BCD to column binary conversion */ - -const uint32 bcd_to_colbin[64] = { - 00000, 00400, 00200, 00100, 00040, 00020, 00010, 00004, - 00002, 00001, 00202, 00102, 00042, 00022, 00012, 00006, - 01000, 01400, 01200, 01100, 01040, 01020, 01010, 01004, - 01002, 01001, 01202, 01102, 01042, 01022, 01012, 01006, - 02000, 02400, 02200, 02100, 02040, 02020, 02010, 02004, - 02002, 02001, 02202, 02102, 02042, 02022, 02012, 02006, - 04000, 04400, 04200, 04100, 04040, 04020, 04010, 04004, - 04002, 04001, 04202, 04102, 04042, 04022, 04012, 04006 - }; diff --git a/I7094/i7094_defs.h b/I7094/i7094_defs.h deleted file mode 100644 index ae7c7346..00000000 --- a/I7094/i7094_defs.h +++ /dev/null @@ -1,485 +0,0 @@ -/* i7094_defs.h: IBM 7094 simulator definitions - - Copyright (c) 2003-2011, Robert M Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - This simulator incorporates prior work by Paul Pierce, Dave Pitts, and Rob - Storey. Tom Van Vleck, Stan Dunten, Jerry Saltzer, and other CTSS veterans - helped to reconstruct the CTSS hardware RPQ's. Dave Pitts gets special - thanks for patiently coaching me through IBSYS debug. - - 25-Mar-11 RMS Updated SDC mask based on 7230 documentation - 22-May-10 RMS Added check for 64b addresses - -*/ - -#ifndef I7094_DEFS_H_ -#define I7094_DEFS_H_ 0 - -#include "sim_defs.h" /* simulator defns */ - -#if defined(USE_ADDR64) -#error "7094 does not support 64b addresses!" -#endif - -/* Simulator stop codes */ - -#define STOP_HALT 1 /* halted */ -#define STOP_IBKPT 2 /* breakpoint */ -#define STOP_ILLEG 3 /* illegal instr */ -#define STOP_DIVCHK 4 /* divide check */ -#define STOP_XEC 5 /* XCT loop */ -#define STOP_ASTOP 6 /* address stop */ -#define STOP_NXCHN 7 /* nx channel */ -#define STOP_7909 8 /* ill inst to 7909 */ -#define STOP_NT7909 9 /* ill inst to !7909 */ -#define STOP_NXDEV 10 /* nx device */ -#define STOP_ILLCHI 11 /* illegal channel op */ -#define STOP_WRP 12 /* write protect */ -#define STOP_ILLIOP 13 /* illegal I/O op */ -#define STOP_INVFMT 14 /* invalid disk format */ -#define STOP_NOIFREE 15 /* 7750: no buf for inp */ -#define STOP_NOOFREE 16 /* 7750: no buf for out */ -#define STOP_INVLIN 17 /* 7750: invalid line# */ -#define STOP_INVMSG 18 /* 7750: invalid message */ -#define STOP_CHBKPT 19 /* channel breakpoint */ - -/* Simulator error codes */ - -#define ERR_STALL 40 /* stall */ -#define ERR_ENDRC 41 /* end rec */ -#define ERR_NRCF 42 /* no record found */ - -/* Instruction history - flags in left half of pc entry */ - -#define HIST_PC 0x04000000 /* CPU */ -#define HIST_V_CH 28 /* chan + 1 */ -#define HIST_M_CH 0xF -#define HIST_CH(x) (((x) >> HIST_V_CH) & HIST_M_CH) - -typedef struct { - uint32 pc; - uint32 ea; - uint32 rpt; - t_uint64 ir; - t_uint64 ac; - t_uint64 mq; - t_uint64 si; - t_uint64 opnd; - } InstHistory; - -/* Architectural constants */ - -#define A704_SIZE 14 /* addr width, 704 mode */ -#define ASIZE 15 /* inst addr width */ -#define PASIZE 16 /* phys addr width */ -#define STDMEMSIZE (1u << ASIZE) /* standard memory */ -#define MAXMEMSIZE (1u << PASIZE) /* maximum memory */ -#define A704_MASK ((1u << A704_SIZE) - 1) -#define PAMASK ((1u << PASIZE) - 1) -#define MEMSIZE (cpu_unit.capac) -#define BCORE_V (ASIZE) /* (CTSS) A/B core sel */ -#define BCORE_BASE (1u << BCORE_V) /* (CTSS) B core base */ - -/* Traps */ - -#define TRAP_STD_SAV 000000 /* trap save location */ -#define TRAP_TRA_PC 000001 /* trap PC: transfer */ -#define TRAP_STR_PC 000002 /* trap PC: STR */ -#define TRAP_FP_PC 000010 /* trap PC: flt point */ -#define TRAP_PROT_SAV 000032 /* protection trap save */ -#define TRAP_PROT_PC 000033 /* protection trap PC */ -#define TRAP_704_SAV 040000 /* 704 compat trap */ -#define TRAP_SEL_PC 040001 /* 704 trap PC: select */ -#define TRAP_CPY_PC 040002 /* 704 trap PC: copy */ - -#define TRAP_F_MQ 000001 /* MQ error */ -#define TRAP_F_AC 000002 /* AC error */ -#define TRAP_F_OVF 000004 /* overflow */ -#define TRAP_F_SGL 000010 /* single precision */ -#define TRAP_F_DVC 000020 /* fake: divide check */ -#define TRAP_F_ODD 000040 /* odd address */ -#define TRAP_F_BDATA 020000 /* (CTSS) data B core */ -#define TRAP_F_BINST 040000 /* (CTSS) inst B core */ - -/* Integer */ - -#define DMASK INT64_C(0777777777777) /* data mask */ -#define SIGN INT64_C(0400000000000) /* sign */ -#define MMASK INT64_C(0377777777777) /* magnitude mask */ -#define LMASK INT64_C(0777777000000) /* left mask */ -#define RMASK INT64_C(0000000777777) /* right mask */ -#define PMASK INT64_C(0700000000000) /* prefix */ -#define XMASK INT64_C(0077777000000) /* decrement */ -#define TMASK INT64_C(0000000700000) /* tag */ -#define AMASK INT64_C(0000000077777) /* address */ -#define SCMASK INT64_C(0000000000377) /* shift count mask */ -#define B1 INT64_C(0200000000000) /* bit 1 */ -#define B9 INT64_C(0000400000000) /* bit 9 */ - -/* Accumulator is actually 38b wide */ - -#define AC_S INT64_C(02000000000000) /* sign */ -#define AC_Q INT64_C(01000000000000) /* Q */ -#define AC_P INT64_C(00400000000000) /* P */ -#define AC_MMASK INT64_C(01777777777777) /* Q+P+magnitude */ - -/* Floating point */ - -#define FP_N_FR 27 /* fraction bits */ -#define FP_FMASK ((1u << FP_N_FR) - 1) -#define FP_N_DFR 54 /* double fraction bits */ -#define FP_DFMASK ((((t_uint64) 1) << FP_N_DFR) - 1) -#define FP_FNORM (((t_uint64) 1u) << (FP_N_DFR - 1)) /* normalized bit */ -#define FP_FCRY (((t_uint64) 1u) << FP_N_DFR) /* fraction carry */ -#define FP_BIAS 0200 /* exponent bias */ -#define FP_V_CH (FP_N_FR) /* exponent */ -#define FP_M_CH 0377 /* SR char mask */ -#define FP_M_ACCH 01777 /* AC char mask incl Q,P */ - -/* Instruction format */ - -#define INST_T_DEC INT64_C(0300000000000) /* if nz, takes decr */ -#define INST_T_CXR1 INT64_C(0000000100000) /* if nz, update XR1 */ -#define INST_V_OPD 33 /* decrement opcode */ -#define INST_M_OPD 07 -#define INST_V_DEC 18 /* decrement */ -#define INST_M_DEC 077777 -#define INST_V_OPC 24 /* normal opcode */ -#define INST_M_OPC 0777 -#define INST_V_IND 22 /* indirect */ -#define INST_IND (3 << INST_V_IND) -#define INST_V_CCNT 18 /* convert count */ -#define INST_M_CCNT 0377 -#define INST_V_VCNT 18 /* vlm/vdh count */ -#define INST_M_VCNT 077 -#define INST_V_TAG 15 /* index */ -#define INST_M_TAG 07 -#define INST_V_ADDR 0 -#define INST_M_ADDR 077777 -#define INST_V_4B 0 -#define INST_M_4B 017 - -#define GET_OPD(x) ((uint32) (((x) >> INST_V_OPD) & INST_M_OPD)) -#define GET_DEC(x) ((uint32) (((x) >> INST_V_DEC) & INST_M_DEC)) -#define GET_OPC(x) (((uint32) (((x) >> INST_V_OPC) & INST_M_OPC)) | \ - (((x) & SIGN)? 01000: 0)) -#define TST_IND(x) (((x) & INST_IND) == INST_IND) -#define GET_CCNT(x) ((uint32) (((x) >> INST_V_CCNT) & INST_M_CCNT)) -#define GET_VCNT(x) ((uint32) (((x) >> INST_V_VCNT) & INST_M_VCNT)) -#define GET_TAG(x) ((uint32) (((x) >> INST_V_TAG) & INST_M_TAG)) - -/* Instruction decode flags */ - -#define I_4X 0x01 /* 7040, 7044 */ -#define I_9X 0x02 /* 7090, 7094, CTSS */ -#define I_94 0x04 /* 7094, CTSS */ -#define I_CT 0x08 /* CTSS */ -#define I_MODEL 0x0F /* option mask */ -#define I_X 0x10 /* indexed */ -#define I_N 0x20 /* indirect */ -#define I_R 0x40 /* read */ -#define I_D 0x80 /* double read */ - -#define I_XN (I_X|I_N) -#define I_XNR (I_X|I_N|I_R) -#define I_XND (I_X|I_N|I_D) - -/* Memory protection (CTSS) */ - -#define VA_V_OFF 0 /* offset in block */ -#define VA_N_OFF 8 /* width of offset */ -#define VA_M_OFF ((1u << VA_N_OFF) - 1) -#define VA_OFF (VA_M_OFF << VA_V_OFF) -#define VA_V_BLK (VA_N_OFF) /* block */ -#define VA_N_BLK (ASIZE - VA_N_OFF) /* width of block */ -#define VA_M_BLK ((1u << VA_N_BLK) - 1) -#define VA_BLK (VA_M_BLK << VA_V_BLK) - -/* Unsigned operations */ - -#define NEG(x) (~(x) + 1) -#define BIT_TST(w,b) (((w) >> (b)) & 1) - -/* Device information block */ - -typedef struct { - t_stat (*chsel)(uint32 ch, uint32 sel, uint32 u); - t_stat (*write)(uint32 ch, t_uint64 val, uint32 flags); - } DIB; - -/* BCD digits */ - -#define BCD_MASK 017 -#define BCD_ZERO 012 -#define BCD_ONE 001 -#define BCD_TWO 002 -#define BCD_AT 014 - -/* Channels */ - -#define NUM_CHAN 8 /* # channels */ -#define CH_A 0 /* channel A */ -#define CH_B 1 -#define CH_C 2 -#define CH_D 3 -#define CH_E 4 -#define CH_F 5 -#define CH_G 6 -#define CH_H 7 - -#define REQ_CH(x) (1u << (x)) - -/* All channel commands */ - -#define CHI_IND 0000000400000 /* ch inst indirect */ - -/* Channel selects - all channels */ - -#define CHSL_RDS 0001 /* data selects */ -#define CHSL_WRS 0002 -#define CHSL_SNS 0003 -#define CHSL_CTL 0004 -#define CHSL_FMT 0005 -#define CHSL_WEF 0010 /* non-data selects */ -#define CHSL_WBT 0011 /* 704X only */ -#define CHSL_BSR 0012 -#define CHSL_BSF 0013 -#define CHSL_REW 0014 -#define CHSL_RUN 0015 -#define CHSL_SDN 0016 -#define CHSL_2ND 0020 /* second state */ -#define CHSL_3RD 0040 /* etc */ -#define CHSL_4TH 0060 -#define CHSL_5TH 0100 -#define CHSL_NDS 0010 /* non-data sel flag */ -#define CHSL_NUM 16 - -/* Channel commands - 7607/7289 - S12'19 */ - -#define CH6I_NST 0000000200000 /* ch inst no store */ - -#define CH6_IOCD 000 -#define CH6_TCH 002 -#define CH6_IORP 004 -#define CH6_IORT 006 -#define CH6_IOCP 010 -#define CH6_IOCT 012 -#define CH6_IOSP 014 -#define CH6_IOST 016 -#define CH6_OPMASK 016 /* without nostore */ -#define TCH_LIMIT 5 /* TCH autoresolve limit */ - -/* Channel data flags - 7607 */ - -#define CH6DF_EOR 1 /* end of record */ -#define CH6DF_VLD 2 /* input valid */ - -/* Channel commands - 7909 - S123'19 */ - -#define CH9_WTR 000 -#define CH9_XMT 001 -#define CH9_TCH 004 -#define CH9_LIPT 005 -#define CH9_CTL 010 -#define CH9_CTLR 011 -#define CH9_CTLW 012 -#define CH9_SNS 013 -#define CH9_LAR 014 -#define CH9_SAR 015 -#define CH9_TWT 016 -#define CH9_CPYP 020 -#define CH9_CPYD 024 -#define CH9_TCM 025 -#define CH9_LIP 031 -#define CH9_TDC 032 -#define CH9_LCC 033 -#define CH9_SMS 034 -#define CH9_ICC 035 -#define CH9_ICCA 037 /* ignores bit <3> */ -#define CH9_OPMASK 037 - -/* Channel data flags - 7909 */ - -#define CH9DF_STOP 1 /* stop */ -#define CH9DF_VLD 2 /* input valid */ - -/* Extended parts of the command come from the decrement, stored in ch_wc */ - -#define CH9D_V_MASK 0 /* condition mask */ -#define CH9D_M_MASK 077 -#define CH9D_V_COND 12 /* condition select */ -#define CH9D_M_COND 07 -#define CH9D_MASK(x) (((x) >> CH9D_V_MASK) & CH9D_M_MASK) -#define CH9D_COND(x) (((x) >> CH9D_V_COND) & CH9D_M_COND) - -#define CH9D_NST 020000 /* no store */ -#define CH9D_B11 000100 - -/* Or from the effective address, stored in ch_ca */ - -#define CH9A_V_LCC 0 /* counter */ -#define CH9A_M_LCC 077 -#define CH9A_V_SMS 0 /* system mask */ -#define CH9A_M_SMS 0177 -#define CH9A_LCC(x) (((x) >> CH9A_V_LCC) & CH9A_M_LCC) -#define CH9A_SMS(x) (((x) >> CH9A_V_SMS) & CH9A_M_SMS) - -/* Channel states - common */ - -#define CHXS_IDLE 0 /* idle */ -#define CHXS_DSX 1 /* executing */ - -/* Channel states - 7607/7289 */ - -#define CH6S_PNDS 2 /* polling NDS */ -#define CH6S_PDS 3 /* polling DS */ -#define CH6S_NDS 4 /* nds, executing */ -#define CH6S_DSW 5 /* ds, chan wait */ - -/* Channel traps - 7909 has only CMD (== TWT) */ - -#define CHTR_V_CME 0 /* cmd/eof enable */ -#define CHTR_V_CLK 17 /* clock */ -#define CHTR_V_TRC 18 /* tape check */ -#define CHTR_V_TWT (CHTR_V_CME) -#define CHTR_CLK_SAV 006 /* clock */ -#define CHTR_CHA_SAV 012 /* start of chan block */ -#define CHTR_F_CMD 1 /* CMD flag (in decr) */ -#define CHTR_F_TRC 2 /* TRC flag (in decr) */ -#define CHTR_F_EOF 4 /* EOF flag (in decr) */ - -/* Channel interrupts - 7909 only */ - -#define CHINT_CHA_SAV 042 /* start of chan block */ - -/* Channel interrupt conditions - 7909 only */ - -#define CHINT_ADPC 001 /* adapter check */ -#define CHINT_ATN2 002 /* attention 2 - ni */ -#define CHINT_ATN1 004 /* attention 1 */ -#define CHINT_UEND 010 /* unusual end */ -#define CHINT_SEQC 020 /* sequence check */ -#define CHINT_IOC 040 /* IO check */ - -/* Channel SMS flags - 7909 only */ - -#define CHSMS_SEL2 0001 /* select 2nd - ni */ -#define CHSMS_IATN2 0002 /* inhibit atn2 - ni */ -#define CHSMS_IATN1 0004 /* inhibit atn1 */ -#define CHSMS_IUEND 0010 /* inhibit uend */ -#define CHSMS_BCD 0020 /* BCD conversion - ni */ -#define CHSMS_RBCK 0040 /* read backwards - ni */ -#define CHSMS_ENCI 0100 /* enable noncon - ni */ - -/* Channel flags (7607 in right half, 7909 in left half) */ - -#define CHF_CMD 00000000001 /* cmd done */ -#define CHF_TWT (CHF_CMD) -#define CHF_TRC 00000000002 /* tape check */ -#define CHF_EOF 00000000004 /* end of file */ -#define CHF_BOT 00000000010 /* beginning of tape */ -#define CHF_EOT 00000000020 /* end of tape */ -#define CHF_LDW 00000000040 /* LCH waiting */ -#define CHF_EOR 00000000100 /* end of record */ -#define CHF_IRQ 00001000000 /* intr request */ -#define CHF_INT 00002000000 /* intr in prog */ -#define CHF_WRS 00004000000 /* write */ -#define CHF_RDS 00010000000 /* read */ -#define CHF_PWR 00020000000 /* prepare to write */ -#define CHF_PRD 00040000000 /* prepare to read */ -#define CHF_V_COND 24 /* cond register */ -#define CHF_M_COND 077 -#define CHF_ADPC (CHINT_ADPC << CHF_V_COND) /* adapter check */ -#define CHF_ATN2 (CHINT_ATN2 << CHF_V_COND) /* attention 2 */ -#define CHF_ATN1 (CHINT_ATN1 << CHF_V_COND) /* attention 1 */ -#define CHF_UEND (CHINT_UEND << CHF_V_COND) /* unusual end */ -#define CHF_SEQC (CHINT_SEQC << CHF_V_COND) /* sequence check */ -#define CHF_IOC (CHINT_IOC << CHF_V_COND) /* IO check */ -#define CHF_V_LCC 30 /* loop ctrl counter */ -#define CHF_M_LCC 077 - -#define CHF_CLR_7909 INT64_C(07775000177) /* 7909 clear flags */ -#define CHF_SDC_7909 INT64_C(07777600000) /* 7909 SDC flags */ - -/* Channel characteristics (in dev.flags) */ - -#define DEV_7909 (1u << (DEV_V_UF + 0)) -#define DEV_7289 (1u << (DEV_V_UF + 1)) -#define DEV_CDLP (1u << (DEV_V_UF + 2)) -#define DEV_7750 (1u << (DEV_V_UF + 3)) -#define DEV_7631 (1u << (DEV_V_UF + 4)) - -/* Unit addresses - 7607/7289 only */ - -#define U_V_CH 9 /* channel number */ -#define U_M_CH 077 -#define U_V_UNIT 0 -#define U_M_UNIT 0777 -#define GET_U_CH(x) (((((uint32) (x)) >> U_V_CH) & U_M_CH) - 1) -#define GET_U_UNIT(x) ((((uint32) (x)) >> U_V_UNIT) & U_M_UNIT) - -#define U_MTBCD 0201 /* BCD tape */ -#define U_MTBIN 0221 /* binary tape */ -#define U_CDR 0321 /* card reader */ -#define U_CDP 0341 /* card punch */ -#define U_LPBCD 0361 /* BCD print */ -#define U_LPBIN 0362 /* binary print */ -#define U_DRM 0330 /* 7320A drum */ - -#define MT_NUMDR 10 - -/* CTSS Chronolog clock */ - -#define CHRONO_CH (CH_A) /* channel A */ -#define CHRONO_UNIT (7) /* unit 7 */ - -/* Interval timer */ - -#define CLK_CTR 05 /* counter */ -#define CLK_TPS 60 /* 60Hz */ -#define TMR_CLK 0 /* use timer 0 */ -#define TMR_COM 1 /* 7750 timer */ - -/* Function prototypes and macros */ - -#define ReadP(p) M[p] -#define WriteP(p,d) M[p] = d - -void cpu_ent_hist (uint32 pc, uint32 ea, t_uint64 ir, t_uint64 opnd); -t_stat ch_show_chan (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat ch6_end_nds (uint32 ch); -uint32 ch6_set_flags (uint32 ch, uint32 unit, uint32 flags); -t_stat ch6_err_disc (uint32 ch, uint32 unit, uint32 flags); -t_stat ch6_req_rd (uint32 ch, uint32 unit, t_uint64 val, uint32 flags); -t_stat ch6_req_wr (uint32 ch, uint32 unit); -t_bool ch6_qconn (uint32 ch, uint32 unit); -t_stat ch9_req_rd (uint32 ch, t_uint64 val); -void ch9_set_atn (uint32 ch); -void ch9_set_ioc (uint32 ch); -void ch9_set_end (uint32 ch, uint32 ireq); -t_bool ch9_qconn (uint32 ch); -void ch_set_map (void); -t_bool ch_qidle (void); - -#endif diff --git a/I7094/i7094_drm.c b/I7094/i7094_drm.c deleted file mode 100644 index 50b24c35..00000000 --- a/I7094/i7094_drm.c +++ /dev/null @@ -1,334 +0,0 @@ -/* i7094_drm.c: 7289/7320A drum simulator - - Copyright (c) 2005-2011, 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. - - drm 7289/7320A "fast" drum - - 23-Mar-12 RMS Corrected disk addressing and logical disk crossing - 25-Mar-11 RMS Updated based on RPQ - - This simulator implements a subset of the functionality of the 7289, as - required by CTSS. - - - The drum channel/controller behaves like a hybrid of the 7607 and the 7909. - It responds to SCD (like the 7909), gets its address from the channel - program (like the 7909), but responds to IOCD/IOCP (like the 7607) and - sets channel flags (like the 7607). - - The drum channel supports at least 2 drums. The maximum is 4 or less. - Physical drums are numbered from 0. - - Each drum has a capacity of 192K 36b words. This is divided into 6 - "logical" drum of 32KW each. Each "logical" drum has 16 2048W "sectors". - Logical drums are numbered from 1. - - The drum allows transfers across sector boundaries, but not logical - drum boundaries. - - The drum's only supports IOCD, IOCP, and IOCT. IOCT (and chaining mode) - are not used by CTSS. - - Limitations in this simulator: - - - Chain mode is not implemented. - - LPCR is not implemented. - - For speed, the entire drum is buffered in memory. -*/ - -#include "i7094_defs.h" -#include - -#define DRM_NUMDR 4 /* drums/controller */ - -/* Drum geometry */ - -#define DRM_NUMWDG 1024 /* words/group */ -#define DRM_GPMASK (DRM_NUMWDG - 1) /* group mask */ -#define DRM_NUMWDS 2048 /* words/sector */ -#define DRM_SCMASK (DRM_NUMWDS - 1) /* sector mask */ -#define DRM_NUMSC 16 /* sectors/log drum */ -#define DRM_NUMWDL (DRM_NUMWDS * DRM_NUMSC) /* words/log drum */ -#define DRM_LDMASK (DRM_NUMWDL - 1) /* logical disk mask */ -#define DRM_NUMLD 6 /* log drums/phys drum */ -#define DRM_SIZE (DRM_NUMLD * DRM_NUMWDL) /* words/phys drum */ -#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \ - ((double) DRM_NUMWDS))) -#define GET_PROT(x) ((x[drm_phy] >> (drm_log - 1)) & 1) - -/* Drum address from channel */ - -#define DRM_V_PHY 30 /* physical drum sel */ -#define DRM_M_PHY 03 -#define DRM_V_LOG 18 /* logical drum sel */ -#define DRM_M_LOG 07 -#define DRM_V_WDA 0 /* word address */ -#define DRM_M_WDA (DRM_NUMWDL - 1) -#define DRM_GETPHY(x) (((uint32) ((x) >> DRM_V_PHY)) & DRM_M_PHY) -#define DRM_GETLOG(x) ((((uint32) (x)) >> DRM_V_LOG) & DRM_M_LOG) -#define DRM_GETWDA(x) ((((uint32) (x)) >> DRM_V_WDA) & DRM_M_WDA) -#define DRM_GETDA(l,x) ((((l) - 1) * DRM_NUMWDL) + (x)) - -/* SCD word */ - -#define DRMS_V_IOC 35 /* IO check */ -#define DRMS_V_INV 33 /* invalid command */ -#define DRMS_V_PHY 31 /* physical drum */ -#define DRMS_V_LOG 28 /* logical drum */ -#define DRMS_V_WDA 13 /* disk address */ -#define DRMS_V_WRP 22 /* write protect */ -#define DRMS_V_LPCR 18 /* LPRCR */ -#define DRMS_M_LPCR 017 - -/* Drum controller states */ - -#define DRM_IDLE 0 -#define DRM_1ST 1 -#define DRM_FILL 2 -#define DRM_DATA 3 -#define DRM_EOD 4 - -uint32 drm_ch = CH_G; /* drum channel */ -uint32 drm_da = 0; /* drum address */ -uint32 drm_phy = 0; /* physical drum */ -uint32 drm_log = 0; /* logical drum */ -uint32 drm_sta = 0; /* state */ -uint32 drm_op = 0; /* operation */ -t_uint64 drm_chob = 0; /* output buf */ -uint32 drm_chob_v = 0; /* valid */ -uint32 drm_prot[DRM_NUMDR] = { 0 }; /* drum protect sw */ -int32 drm_time = 10; /* inter-word time */ - -extern uint32 ind_ioc; - -t_stat drm_svc (UNIT *uptr); -t_stat drm_reset (DEVICE *dptr); -t_stat drm_chsel (uint32 ch, uint32 sel, uint32 unit); -t_stat drm_chwr (uint32 ch, t_uint64 val, uint32 flags); -t_bool drm_da_incr (void); - -/* DRM data structures - - drm_dev DRM device descriptor - drm_unit DRM unit descriptor - drm_reg DRM register list -*/ - -DIB drm_dib = { &drm_chsel, &drm_chwr }; - -UNIT drm_unit[] = { - { UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ - UNIT_MUSTBUF+UNIT_DISABLE, DRM_SIZE) }, - { UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ - UNIT_MUSTBUF+UNIT_DISABLE, DRM_SIZE) }, - { UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ - UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) }, - { UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+ - UNIT_MUSTBUF+UNIT_DISABLE+UNIT_DIS, DRM_SIZE) }, - }; - -REG drm_reg[] = { - { ORDATA (STATE, drm_sta, 3) }, - { ORDATA (UNIT,drm_phy, 2), REG_RO }, - { ORDATA (LOG, drm_log, 3), REG_RO }, - { ORDATA (DA, drm_da, 15) }, - { FLDATA (OP, drm_op, 0) }, - { ORDATA (CHOB, drm_chob, 36) }, - { FLDATA (CHOBV, drm_chob_v, 0) }, - { ORDATA (PROT0, drm_prot[0], 6) }, - { ORDATA (PROT1, drm_prot[1], 6) }, - { ORDATA (PROT2, drm_prot[2], 6) }, - { ORDATA (PROT3, drm_prot[3], 6) }, - { DRDATA (TIME, drm_time, 24), REG_NZ + PV_LEFT }, - { DRDATA (CHAN, drm_ch, 3), REG_HRO }, - { NULL } - }; - -MTAB drm_mtab[] = { - { MTAB_XTD|MTAB_VDV, 0, "CHANNEL", NULL, NULL, &ch_show_chan }, - { 0 } - }; - -DEVICE drm_dev = { - "DRM", drm_unit, drm_reg, drm_mtab, - DRM_NUMDR, 8, 18, 1, 8, 36, - NULL, NULL, &drm_reset, - NULL, NULL, NULL, - &drm_dib, DEV_DIS - }; - -/* Channel select routine */ - -t_stat drm_chsel (uint32 ch, uint32 sel, uint32 unit) -{ -drm_ch = ch; /* save channel */ -if (sel & CHSL_NDS) /* nds? nop */ - return ch6_end_nds (ch); - -switch (sel) { /* case on cmd */ - - case CHSL_RDS: /* read */ - case CHSL_WRS: /* write */ - if (drm_sta != DRM_IDLE) /* busy? */ - return ERR_STALL; - drm_sta = DRM_1ST; /* initial state */ - if (sel == CHSL_WRS) /* set read/write */ - drm_op = 1; - else drm_op = 0; /* LCHx sends addr */ - break; /* wait for addr */ - - default: /* other */ - return STOP_ILLIOP; - } -return SCPE_OK; -} - -/* Channel diagnostic store routine */ - -t_uint64 drm_sdc (uint32 ch) -{ -t_uint64 val; - - -val = (((t_uint64) ind_ioc) << DRMS_V_IOC) | - (((t_uint64) drm_phy) << DRMS_V_PHY) | - (((t_uint64) drm_log) << DRMS_V_LOG) | - (((t_uint64) (drm_da & ~ DRM_GPMASK)) << DRMS_V_WDA) | - (((t_uint64) GET_PROT(drm_prot)) << DRMS_V_WRP); -return val; -} - -/* Channel write routine */ - -t_stat drm_chwr (uint32 ch, t_uint64 val, uint32 flags) -{ -int32 cp, dp; - -if (drm_sta == DRM_1ST) { - drm_phy = DRM_GETPHY (val); /* get unit */ - drm_log = DRM_GETLOG (val); /* get logical disk */ - drm_da = DRM_GETWDA (val); /* get drum word addr */ - if ((drm_unit[drm_phy].flags & UNIT_DIS) || /* disabled unit? */ - (drm_log == 0) || (drm_log > DRM_NUMLD) || /* invalid log drum? */ - ((drm_op != 0) && (GET_PROT (drm_prot) != 0))) { /* write to prot drum? */ - ch6_err_disc (ch, U_DRM, CHF_TRC); /* disconnect */ - drm_sta = DRM_IDLE; - return SCPE_OK; - } - cp = GET_POS (drm_time); /* current pos in sec */ - dp = (drm_da & DRM_SCMASK) - cp; /* delta to desired pos */ - if (dp <= 0) /* if neg, add rev */ - dp = dp + DRM_NUMWDS; - sim_activate (&drm_unit[drm_phy], dp * drm_time); /* schedule */ - if (drm_op) { /* if write, get word */ - ch6_req_wr (ch, U_DRM); - drm_sta = DRM_FILL; /* sector fill */ - } - else drm_sta = DRM_DATA; /* data transfer */ - drm_chob = 0; /* clr, inval buffer */ - drm_chob_v = 0; - } -else { - drm_chob = val & DMASK; - drm_chob_v = 1; - } -return SCPE_OK; -} - -/* Unit service - this code assumes the entire drum is buffered */ - -t_stat drm_svc (UNIT *uptr) -{ -uint32 i; -t_uint64 *fbuf = (t_uint64 *) uptr->filebuf; -uint32 da = DRM_GETDA (drm_log, drm_da); - -if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? */ - ch6_err_disc (drm_ch, U_DRM, CHF_TRC); /* set TRC, disc */ - drm_sta = DRM_IDLE; /* drum is idle */ - return SCPE_UNATT; - } - -switch (drm_sta) { /* case on state */ - - case DRM_FILL: /* write, clr group */ - for (i = da & ~DRM_GPMASK; i <= (da | DRM_GPMASK); i++) - fbuf[i] = 0; /* clear group */ - if (i >= uptr-> hwmark) - uptr->hwmark = i + 1; - drm_sta = DRM_DATA; /* now data */ - /* fall through */ - case DRM_DATA: /* data */ - if (drm_op) { /* write? */ - if (drm_chob_v) /* valid? clear */ - drm_chob_v = 0; - else if (ch6_qconn (drm_ch, U_DRM)) /* no, chan conn? */ - ind_ioc = 1; /* io check */ - fbuf[da] = drm_chob; /* get data */ - if (da >= uptr->hwmark) - uptr->hwmark = da + 1; - if (!drm_da_incr ()) /* room for more? */ - ch6_req_wr (drm_ch, U_DRM); - } - else{ /* read */ - ch6_req_rd (drm_ch, U_DRM, fbuf[da], 0); /* send word to channel */ - drm_da_incr (); - } - sim_activate (uptr, drm_time); /* next word */ - break; - - case DRM_EOD: /* end logical disk */ - if (ch6_qconn (drm_ch, U_DRM)) /* drum still conn? */ - ch6_err_disc (drm_ch, U_DRM, CHF_EOF); /* set EOF, disc */ - drm_sta = DRM_IDLE; /* drum is idle */ - break; - } /* end case */ - -return SCPE_OK; -} - -/* Increment drum address - return true, set new state if end of logical disk */ - -t_bool drm_da_incr (void) -{ -drm_da = (drm_da + 1) & DRM_LDMASK; -if (drm_da != 0) - return FALSE; -drm_sta = DRM_EOD; -return TRUE; -} - -/* Reset routine */ - -t_stat drm_reset (DEVICE *dptr) -{ -uint32 i; - -drm_phy = 0; -drm_log = 0; -drm_da = 0; -drm_op = 0; -drm_sta = DRM_IDLE; -drm_chob = 0; -drm_chob_v = 0; -for (i = 0; i < dptr->numunits; i++) - sim_cancel (dptr->units + i); -return SCPE_OK; -} diff --git a/I7094/i7094_dsk.c b/I7094/i7094_dsk.c deleted file mode 100644 index 533d0d07..00000000 --- a/I7094/i7094_dsk.c +++ /dev/null @@ -1,1224 +0,0 @@ -/* i7094_dsk.c: 7631 file control (disk/drum) simulator - - Copyright (c) 2005-2008, 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. - - dsk 7631 file control - - The 7631 is a controller for multiple serial bit stream devices such as - disks or drums. It supports the - - 1301 fixed disk - 1302 fixed disk - 2302 fixed disk - 7320 drum - - The 7631 supports variable record formatting, user-specified record numbering, - and other complex features. Each track has - - home address 1: the track number, 4 BCD digits (implicit) - home address 2: user-specified track identifier, 6 BCD chars - records 1..n: variably formatted records, each consisting of - record address: user-specified record identifier, 4 BCD digits - and 2 BCD characters - record data: 36b words - - To deal with this, the simulator provides a container of 500 (7320/1301) or - 1000 (1302/2302) words per track. Each track starts with home address 2 - and then contains a variable number of records. Each record has a two-word - header followed by data: - - word 0: record length without header - word 1: record address - word 2: start of data - word 2+n-1: end of data - word 2+n+2: start of next record - - A record length of 0 indicates end of valid data on the track. - - Orders to the 7631 are 10 BCD digits (60b), consisting of two words: - - word 0: op-op-access-module-d1-d2 - word 1: d3-d4-d5-d6-x-x - - Depending on the opcode, d1:d6 can be a track number plus home address 2, - or a record number. - - Status from the 7631 is also 10 BCD digits (60b), with 36b in the first - word, and 24b (plus 12b of zeroes) in the second. - - Because modules can have two access arms that seek independently, each - module m is represented by two units: unit m for access 0 and unit m+10 - for access 1. This requires tricky bookkeeping to be sure that the - service routine is using the 'right' unit. - - Limitations of the simulation: - - - HA2 and record address must be exactly 6 characters (one word) - - Record lengths must be exact multiples of 6 characters - - Seek timing is fixed rather than based on seek length -*/ - -/* Definitions */ - -#include "i7094_defs.h" -#include - -#define DSK_NUMDR 10 /* modules/controller */ -#define DSK_SNS (2 * DSK_NUMDR) /* dummy unit for sense */ - -/* Drive geometry */ - -#define DSK_WDSPT_7320 500 /* words/track */ -#define DSK_WDSPT_1301 500 -#define DSK_WDSPT_1302 1000 -#define DSK_WDSPT_2302 1000 -#define DSK_TRKPC_7320 400 /* tracks/cylinder */ -#define DSK_TRKPC_1301 40 -#define DSK_TRKPC_1302 40 -#define DSK_TRKPC_2302 40 -#define DSK_CYLPA_7320 1 /* cylinders/access */ -#define DSK_CYLPA_1301 250 -#define DSK_CYLPA_1302 250 -#define DSK_CYLPA_2302 250 -#define DSK_TRKPA_7320 (DSK_TRKPC_7320*DSK_CYLPA_7320) /* tracks/access */ -#define DSK_TRKPA_1301 (DSK_TRKPC_1301*DSK_CYLPA_1301) -#define DSK_TRKPA_1302 (DSK_TRKPC_1302*DSK_CYLPA_1302) -#define DSK_TRKPA_2302 (DSK_TRKPC_2302*DSK_CYLPA_2302) -#define DSK_ACCPM_7320 1 /* access/module */ -#define DSK_ACCPM_1301 1 -#define DSK_ACCPM_1302 2 -#define DSK_ACCPM_2302 2 -#define DSK_FMCPT_7320 2868 /* format chars/track */ -#define DSK_FMCPT_1301 2868 -#define DSK_FMCPT_1302 5942 -#define DSK_FMCPT_2302 5942 -#define SIZE_7320 (DSK_WDSPT_7320*DSK_TRKPA_7320*DSK_ACCPM_7320) -#define SIZE_1301 (DSK_WDSPT_1301*DSK_TRKPA_1301*DSK_ACCPM_1301) -#define SIZE_1302 (DSK_WDSPT_1302*DSK_TRKPA_1302*DSK_ACCPM_1302) -#define SIZE_2302 (DSK_WDSPT_2302*DSK_TRKPA_2302*DSK_ACCPM_2302) -#define DSK_BUFSIZ (DSK_WDSPT_2302) -#define DSK_DA(a,t,d) (((((a) * dsk_tab[d].trkpa) + (t)) * dsk_tab[d].wdspt) *\ - sizeof (t_uint64)) - -/* Unit flags */ - -#define UNIT_V_INOP0 (UNIT_V_UF + 0) /* acc 0 inoperative */ -#define UNIT_V_INOP1 (UNIT_V_UF + 1) /* acc 1 inoperative */ -#define UNIT_V_FMTE (UNIT_V_UF + 2) /* format enabled */ -#define UNIT_V_TYPE (UNIT_V_UF + 3) /* drive type */ -#define UNIT_M_TYPE 03 -#define UNIT_INOP0 (1 << UNIT_V_INOP0) -#define UNIT_INOP1 (1 << UNIT_V_INOP1) -#define UNIT_FMTE (1 << UNIT_V_FMTE) -#define UNIT_TYPE (UNIT_M_TYPE << UNIT_V_TYPE) -#define TYPE_7320 (0 << UNIT_V_TYPE) -#define TYPE_1301 (1 << UNIT_V_TYPE) -#define TYPE_1302 (2 << UNIT_V_TYPE) -#define TYPE_2302 (3 << UNIT_V_TYPE) -#define GET_DTYPE(x) (((x) >> UNIT_V_TYPE) & UNIT_M_TYPE) -#define TRK u3 /* track */ -#define SKF u4 /* seek in progress */ - -/* Track/record structure */ - -#define THA2 0 /* home address 2 */ -#define HA2_MASK INT64_C(0777700000000) /* two chars checked */ -#define T1STREC 1 /* start of records */ -#define RLNT 0 /* record length */ -#define RADDR 1 /* record address */ -#define RDATA 2 /* start of data */ -#define REC_MASK INT64_C(0171717177777) /* 4 digits, 2 chars */ - -/* Command word (60b) - 10 BCD digits */ - -#define OP1 0 /* opcode */ -#define OP2 1 -#define ACC 2 /* access */ -#define MOD 3 /* module */ -#define T1 4 /* track */ -#define T2 5 -#define T3 6 -#define T4 7 - -/* Disk states */ - -#define DSK_IDLE 0 - -/* Status word (60b) */ - -#define DSKS_PCHK INT64_C(004000000000000000000) /* prog check */ -#define DSKS_DCHK INT64_C(002000000000000000000) /* data check */ -#define DSKS_EXCC INT64_C(001000000000000000000) /* exc cond */ -#define DSKS_INVS INT64_C(000200000000000000000) /* invalid seq */ -#define DSKS_INVC INT64_C(000040000000000000000) /* invalid opcode */ -#define DSKS_FMTC INT64_C(000020000000000000000) /* format check */ -#define DSKS_NRCF INT64_C(000010000000000000000) /* no record found */ -#define DSKS_INVA INT64_C(000002000000000000000) /* invalid address */ -#define DSKS_RSPC INT64_C(000000400000000000000) /* response check */ -#define DSKS_CMPC INT64_C(000000200000000000000) /* compare check */ -#define DSKS_PARC INT64_C(000000100000000000000) /* parity check */ -#define DSKS_ACCI INT64_C(000000020000000000000) /* access inoperative */ -#define DSKS_ACCN INT64_C(000000004000000000000) /* access not ready */ -#define DSKS_DSKE INT64_C(000000002000000000000) /* disk error */ -#define DSKS_FILE INT64_C(000000001000000000000) /* file error */ -#define DSKS_6B INT64_C(000000000040000000000) /* six bit mode */ -#define DSKS_ATN0 INT64_C(000000000002000000000) /* attention start */ -#define DSKS_PALL INT64_C(000777000000000000000) -#define DSKS_DALL INT64_C(000000740000000000000) -#define DSKS_EALL INT64_C(000000037000000000000) -#define DSKS_ALLERR INT64_C(007777777000000000000) - -/* Commands - opcode 0 */ - -#define DSKC_NOP 0x00 -#define DSKC_RLS 0x04 -#define DSKC_8B 0x08 -#define DSKC_6B 0x09 - -/* Commands - opcode 8 */ - -#define DSKC_SEEK 0x0 /* seek */ -#define DSKC_SREC 0x2 /* single record */ -#define DSKC_WFMT 0x3 /* write format */ -#define DSKC_TNOA 0x4 /* track no addr */ -#define DSKC_CYL 0x5 /* cyl no addr */ -#define DSKC_WCHK 0x6 /* write check */ -#define DSKC_ACCI 0x7 /* set acc inoperative */ -#define DSKC_TWIA 0x8 /* track with addr */ -#define DSKC_THA 0x9 /* track home addr */ - -/* CTSS record structure */ - -#define CTSS_HA2 INT64_C(0676767676767) /* =HXXXXXX */ -#define CTSS_RLNT 435 /* data record */ -#define CTSS_D1LNT 31 /* padding */ -#define CTSS_D2LNT 14 -#define CTSS_D3LNT 16 -#define CTSS_DLLNT 1 -#define CTSS_RA1 2 -#define CTSS_RA2 8 - -/* Data and declarations */ - -typedef struct { - char *name; - uint32 accpm; /* acc/module: 1 or 2 */ - uint32 wdspt; /* wds/track: 500 or 1000 */ - uint32 trkpc; /* trks/cyl: 1 or 40 */ - uint32 trkpa; /* trks/acc: 400 or 10000 */ - uint32 fchpt; /* format ch/track */ - uint32 size; - } DISK_TYPE; - -const DISK_TYPE dsk_tab[4] = { - { "7320", DSK_ACCPM_7320, DSK_WDSPT_7320, - DSK_TRKPC_7320, DSK_TRKPA_7320, DSK_FMCPT_7320, SIZE_7320 }, - { "1301", DSK_ACCPM_1301, DSK_WDSPT_1301, - DSK_TRKPC_1301, DSK_TRKPA_1301, DSK_FMCPT_1301, SIZE_1301 }, - { "1302", DSK_ACCPM_1302, DSK_WDSPT_1302, - DSK_TRKPC_1302, DSK_TRKPA_1302, DSK_FMCPT_1302, SIZE_1302 }, - { "2302", DSK_ACCPM_2302, DSK_WDSPT_2302, - DSK_TRKPC_2302, DSK_TRKPA_2302, DSK_FMCPT_2302, SIZE_2302 } - }; - -/* 7320/1301 format track characters */ - -uint8 fmt_thdr_7320[] = { - 4, 4, 4, /* gap 1 */ - 3, 3, 3, 3, 3, 3, 3, 3, 3, /* ha1 */ - 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, /* gap 2 */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 /* ha2 */ - }; -uint8 fmt_rhdr_7320[] = { - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* x gap */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* record addr */ - 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, /* y gap */ - 1, 1, 1, 1, 0 /* record ovhd */ - }; - -/* 1302/2302 format track characters */ - -uint8 fmt_thdr_1302[] = { - 4, 4, 4, 4, 4, 4, /* gap 1 */ - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, /* ha1 */ - 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, /* gap 2 */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0 /* ha2 */ - }; -uint8 fmt_rhdr_1302[] = { - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, /* x gap */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* record addr */ - 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, /* y gap */ - 1, 1, 1, 1, 1, 1, 1, 0 /* record ovhd */ - }; - -/* CTSS 7320/1301 track format table */ - -uint32 ctss_fmt_7320[] = { - CTSS_RLNT, CTSS_D3LNT, CTSS_DLLNT, 0 - }; - -/* CTSS 1302/2302 track format table */ - -uint32 ctss_fmt_1302[] = { - CTSS_RLNT, CTSS_D1LNT, CTSS_D2LNT, - CTSS_RLNT, CTSS_D3LNT, CTSS_DLLNT, 0 - }; - -uint32 dsk_ch = CH_C; /* disk channel */ -uint32 dsk_acc = 0; /* access */ -uint32 dsk_mod = 0; /* module */ -uint32 dsk_sta = 0; /* disk state */ -uint32 dsk_mode = 0; /* I/O mode */ -uint32 dsk_wchk = 0; /* write check flag */ -uint32 dsk_ctime = 10; /* command time */ -uint32 dsk_stime = 1000; /* seek time */ -uint32 dsk_rtime = 100; /* rotational latency */ -uint32 dsk_wtime = 2; /* word time */ -uint32 dsk_gtime = 5; /* gap time */ -uint32 dsk_rbase = 0; /* record tracking */ -uint32 dsk_rptr = 0; -uint32 dsk_rlim = 0; -uint32 dsk_stop = 0; -uint32 dsk_fmt_cntr = 0; /* format counter */ -t_uint64 dsk_rec = 0; /* rec/home addr (36b) */ -t_uint64 dsk_sns = 0; /* sense data (60b) */ -t_uint64 dsk_cmd = 0; /* BCD command (60b) */ -t_uint64 dsk_chob = 0; /* chan output buffer */ -uint32 dsk_chob_v = 0; /* valid */ -t_uint64 dsk_buf[DSK_BUFSIZ]; /* transfer buffer */ - -extern uint32 ch_req; - -t_stat dsk_svc (UNIT *uptr); -t_stat dsk_svc_sns (UNIT *uptr); -t_stat dsk_reset (DEVICE *dptr); -t_stat dsk_attach (UNIT *uptr, char *cptr); -t_stat dsk_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat dsk_chsel (uint32 ch, uint32 sel, uint32 unit); -t_stat dsk_chwr (uint32 ch, t_uint64 val, uint32 flags); -t_stat dsk_new_cmd (uint32 ch, t_uint64 cmd); -t_stat dsk_uend (uint32 ch, t_uint64 stat); -t_stat dsk_recad (uint32 trk, uint32 rec, uint32 acc, uint32 mod, t_uint64 *res); -t_uint64 dsk_acc_atn (uint32 u); -t_stat dsk_init_trk (UNIT *udptr, uint32 trk); -t_stat dsk_xfer_done (UNIT *uaptr, uint32 dtyp); -t_stat dsk_wr_trk (UNIT *uptr, uint32 trk); -t_bool dsk_get_fmtc (uint32 dtyp, uint8 *fc); -t_bool dsk_qdone (uint32 ch); -t_stat dsk_show_format (FILE *st, UNIT *uptr, int32 val, void *desc); - -/* DSK data structures - - dsk_dev DSK device descriptor - dsk_unit DSK unit descriptor - dsk_reg DSK register list -*/ - -DIB dsk_dib = { &dsk_chsel, &dsk_chwr }; - -UNIT dsk_unit[] = { - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - TYPE_2302, SIZE_2302) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - TYPE_2302, SIZE_2302) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - TYPE_7320, SIZE_7320) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_DIS+TYPE_2302, SIZE_2302) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - TYPE_2302, SIZE_2302) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - TYPE_2302, SIZE_2302) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_DIS+TYPE_2302, SIZE_2302) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_DIS+TYPE_2302, SIZE_2302) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_DIS+TYPE_2302, SIZE_2302) }, - { UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_DIS+TYPE_2302, SIZE_2302) }, - { UDATA (&dsk_svc, UNIT_DIS, 0) }, - { UDATA (&dsk_svc, UNIT_DIS, 0) }, - { UDATA (&dsk_svc, UNIT_DIS, 0) }, - { UDATA (&dsk_svc, UNIT_DIS, 0) }, - { UDATA (&dsk_svc, UNIT_DIS, 0) }, - { UDATA (&dsk_svc, UNIT_DIS, 0) }, - { UDATA (&dsk_svc, UNIT_DIS, 0) }, - { UDATA (&dsk_svc, UNIT_DIS, 0) }, - { UDATA (&dsk_svc, UNIT_DIS, 0) }, - { UDATA (&dsk_svc, UNIT_DIS, 0) }, - { UDATA (&dsk_svc_sns, UNIT_DIS, 0) } - }; - -REG dsk_reg[] = { - { ORDATA (STATE, dsk_sta, 6) }, - { ORDATA (ACCESS, dsk_acc, 1) }, - { ORDATA (MODULE, dsk_mod, 4) }, - { ORDATA (RECORD, dsk_rec, 36) }, - { ORDATA (MODE, dsk_mode, 4) }, - { ORDATA (SENSE, dsk_sns, 60) }, - { ORDATA (BCDCMD, dsk_cmd, 60) }, - { ORDATA (CHOB, dsk_chob, 36) }, - { FLDATA (CHOBV, dsk_chob_v, 0) }, - { FLDATA (STOP, dsk_stop, 0) }, - { DRDATA (FCNTR, dsk_fmt_cntr, 13) }, - { BRDATA (BUF, dsk_buf, 8, 36, DSK_BUFSIZ) }, - { DRDATA (RBASE, dsk_rbase, 10), REG_RO }, - { DRDATA (RPTR, dsk_rptr, 10), REG_RO }, - { DRDATA (RLIM, dsk_rlim, 10), REG_RO }, - { DRDATA (CHAN, dsk_ch, 3), REG_HRO }, - { DRDATA (STIME, dsk_stime, 24), REG_NZ + PV_LEFT }, - { DRDATA (RTIME, dsk_rtime, 24), REG_NZ + PV_LEFT }, - { DRDATA (WTIME, dsk_wtime, 24), REG_NZ + PV_LEFT }, - { DRDATA (GTIME, dsk_gtime, 24), REG_NZ + PV_LEFT }, - { DRDATA (CTIME, dsk_ctime, 24), REG_NZ + PV_LEFT }, - { URDATA (TRACK, dsk_unit[0].TRK, 10, 14, 0, - 2 * DSK_NUMDR, PV_LEFT) }, - { URDATA (SEEKF, dsk_unit[0].SKF, 10, 1, 0, - 2 * DSK_NUMDR, PV_LEFT | REG_HRO) }, - { URDATA (CAPAC, dsk_unit[0].capac, 10, T_ADDR_W, 0, - DSK_NUMDR, PV_LEFT | REG_HRO) }, - { NULL } - }; - -MTAB dsk_mtab[] = { - { UNIT_INOP0 + UNIT_INOP1, 0, "operational", "OPERATIONAL" }, - { UNIT_INOP0 + UNIT_INOP1, UNIT_INOP0, "access 0 inoperative", NULL }, - { UNIT_INOP0 + UNIT_INOP1, UNIT_INOP1, "access 1 inoperative", NULL }, - { UNIT_FMTE, UNIT_FMTE, "formating enabled", "FORMAT" }, - { UNIT_FMTE, 0, "formating disabled", "NOFORMAT" }, - { UNIT_TYPE, TYPE_7320, "7320", "7320", &dsk_set_size }, - { UNIT_TYPE, TYPE_1301, "1301", "1301", &dsk_set_size }, - { UNIT_TYPE, TYPE_1302, "1302", "1302", &dsk_set_size }, - { UNIT_TYPE, TYPE_2302, "2302", "2302", &dsk_set_size }, - { MTAB_XTD|MTAB_VDV, 0, "CHANNEL", NULL, - NULL, &ch_show_chan, NULL }, - { MTAB_XTD|MTAB_VUN|MTAB_NMO, 1, "FORMAT", NULL, - NULL, &dsk_show_format, NULL }, - { 0 } - }; - -DEVICE dsk_dev = { - "DSK", dsk_unit, dsk_reg, dsk_mtab, - (DSK_NUMDR * 2) + 1, 10, 24, 1, 8, 36, - NULL, NULL, &dsk_reset, - NULL, &dsk_attach, NULL, - &dsk_dib, DEV_DIS - }; - -/* Disk channel select, from 7909 channel program */ - -t_stat dsk_chsel (uint32 ch, uint32 sel, uint32 unit) -{ -uint32 u; - -dsk_ch = ch; -if (dsk_sta != DSK_IDLE) /* not idle? seq check */ - dsk_uend (ch, DSKS_INVS); - -switch (sel) { - - case CHSL_CTL: /* control */ - ch_req |= REQ_CH (ch); /* request channel */ - break; - - case CHSL_SNS: /* sense */ - if (sim_is_active (&dsk_unit[DSK_SNS])) /* already sensing? */ - return dsk_uend (ch, DSKS_INVS); /* sequence error */ - sim_activate (&dsk_unit[DSK_SNS], dsk_ctime); /* set timer */ - dsk_stop = 0; - break; - - case CHSL_RDS: /* read */ - if (dsk_mode == DSKC_WFMT) /* write format? */ - return dsk_uend (ch, DSKS_INVS); /* sequence error */ - case CHSL_WRS: /* write */ - if (dsk_mode == 0) /* no mode? seq check */ - dsk_uend (ch, DSKS_INVS); - if (dsk_mode == DSKC_WFMT) /* format? fake sel */ - sel = CHSL_FMT; - u = (dsk_acc * DSK_NUMDR) + dsk_mod; /* access unit number */ - if (sim_is_active (&dsk_unit[u])) /* access in use? */ - return dsk_uend (ch, DSKS_ACCN); /* access not ready */ - sim_activate (&dsk_unit[u], dsk_rtime); /* rotational time */ - break; - - default: /* other */ - return STOP_ILLIOP; - } - -dsk_sta = sel; /* set new state */ -return SCPE_OK; -} - -/* Disk channel write, from 7909 channel program */ - -t_stat dsk_chwr (uint32 ch, t_uint64 val, uint32 stopf) -{ -if (stopf) /* stop? */ - dsk_stop = 1; - -else { - val = val & DMASK; - switch (dsk_sta) { /* case on state */ - - case CHSL_CTL: /* control */ - dsk_cmd = val << 24; - if (val & INT64_C(0100000000000)) { /* need 2nd word? */ - ch_req |= REQ_CH (ch); /* req ch for 2nd */ - dsk_sta = CHSL_CTL|CHSL_2ND; /* next state */ - return SCPE_OK; - } - return dsk_new_cmd (ch, dsk_cmd); /* no, do cmd */ - - case CHSL_CTL|CHSL_2ND: /* 2nd control */ - dsk_cmd |= (val >> 12); - return dsk_new_cmd (ch, dsk_cmd); /* do cmd */ - - default: - dsk_chob = val; /* store data */ - dsk_chob_v = 1; /* set valid */ - } - } - -return SCPE_OK; -} - -/* New command - end of CTL sequence */ - -t_stat dsk_new_cmd (uint32 ch, t_uint64 cmd) -{ -uint32 i, d, a, m, u, trk, dtyp, bcd[8]; - -ch_req |= REQ_CH (ch); /* req ch for end */ -ch9_set_end (ch, 0); /* set end flag */ -dsk_sta = DSK_IDLE; /* ctrl is idle */ - -for (i = 0; i < 8; i++) { /* get chars from cmd */ - d = (uint32) (cmd >> (6 * (9 - i))) & BCD_MASK; - if (d == BCD_ZERO) - d = 0; - else if (d == 0) /* BCD zero cvt */ - d = BCD_ZERO; - bcd[i] = d; - } - -if (bcd[OP1] == 0) { /* cmd = 0x? */ - - switch (bcd[OP2]) { /* case on x */ - - case DSKC_NOP: /* nop */ - case DSKC_RLS: /* release */ - break; - - case DSKC_8B: /* 8b mode */ - dsk_sns &= ~DSKS_6B; - break; - - case DSKC_6B: /* 6b mode */ - dsk_sns |= DSKS_6B; - break; - - default: /* unknown */ - return dsk_uend (ch, DSKS_INVC); /* invalid opcode */ - } /* end case op2 */ - return SCPE_OK; - } /* end if */ - -else if (bcd[OP1] == 8) { /* cmd = 8x? */ - - a = bcd[ACC]; /* get access, */ - m = bcd[MOD]; /* module */ - u = (a * DSK_NUMDR) + m; /* unit for access */ - if ((m > DSK_NUMDR) || /* invalid module? */ - (dsk_unit[m].flags & UNIT_DIS)) /* disabled module? */ - return dsk_uend (ch, DSKS_ACCI); - dtyp = GET_DTYPE (dsk_unit[m].flags); /* get drive type */ - if ((a >= dsk_tab[dtyp].accpm) || /* invalid access? */ - (dsk_unit[m].flags & (UNIT_INOP0 << a))) /* access inop? */ - return dsk_uend (ch, DSKS_ACCI); - if ((bcd[T1] > 9) || (bcd[T2] > 9) || (bcd[T3] > 9) || (bcd[T4] > 9)) - trk = dsk_tab[dtyp].trkpa + 1; /* bad track */ - else trk = (((((bcd[T1] * 10) + bcd[T2]) * 10) + bcd[T3]) * 10) + bcd[T4]; - - if (bcd[OP2] == DSKC_WCHK) { /* write check */ - if (dsk_mode == 0) /* no prior operation? */ - return dsk_uend (ch, DSKS_INVS); - bcd[OP2] = dsk_mode; /* use prior mode */ - dsk_wchk = 1; /* set write check */ - } - else dsk_wchk = 0; - dsk_sns &= ~(DSKS_ALLERR | dsk_acc_atn (u)); /* clear err, atn */ - dsk_stop = 0; /* clear stop */ - - switch (bcd[OP2]) { - - case DSKC_SEEK: /* seek */ - if ((trk >= dsk_tab[dtyp].trkpa) && /* inv track? */ - ((dtyp == TYPE_7320) || /* drum or not CE? */ - (bcd[T1] > 9) || (bcd[T2] != BCD_AT) || - (bcd[T3] > 9) || (bcd[T4] > 9))) - return dsk_uend (ch, DSKS_INVA); - if (sim_is_active (&dsk_unit[u])) /* selected acc busy? */ - return dsk_uend (ch, DSKS_ACCN); - dsk_unit[u].SKF = 1; /* set seeking flag */ - dsk_unit[u].TRK = trk; /* sel acc on cyl */ - sim_activate (&dsk_unit[u], dsk_stime); /* seek */ - dsk_mode = 0; /* clear I/O mode */ - return SCPE_OK; - - case DSKC_ACCI: /* access inoperative */ - dsk_unit[m].flags |= (UNIT_INOP0 << a); /* set correct flag */ - dsk_mode = 0; /* clear I/O mode */ - return SCPE_OK; - - case DSKC_SREC: /* single record */ - break; /* no verification */ - - case DSKC_WFMT: /* format */ - if (!(dsk_unit[m].flags & UNIT_FMTE)) /* format enabled? */ - return dsk_uend (ch, DSKS_FMTC); /* no, error */ - case DSKC_TNOA: /* track no addr */ - case DSKC_CYL: /* cyl no addr */ - case DSKC_TWIA: /* track with addr */ - case DSKC_THA: /* track home addr */ - if (trk != (uint32) dsk_unit[u].TRK) /* on track? */ - return dsk_uend (ch, DSKS_NRCF); - break; - - default: - return dsk_uend (ch, DSKS_INVC); /* invalid opcode */ - } - - dsk_acc = a; /* save access */ - dsk_mod = m; /* save module */ - dsk_rec = cmd & DMASK; /* save rec/home addr */ - dsk_mode = bcd[OP2]; /* save mode */ - return SCPE_OK; - } - -return dsk_uend (ch, DSKS_INVC); /* invalid opcode */ -} - -/* Sense unit service */ - -t_stat dsk_svc_sns (UNIT *uptr) -{ -t_uint64 dat; - -switch (dsk_sta) { /* case on state */ - - case CHSL_SNS: /* prepare data */ - dsk_buf[0] = (dsk_sns >> 24) & DMASK; /* buffer is 2 words */ - dsk_buf[1] = (dsk_sns << 12) & DMASK; - dsk_rptr = 0; - dsk_rlim = 2; - dsk_sta = CHSL_SNS|CHSL_2ND; /* 2nd state */ - break; - - case CHSL_SNS|CHSL_2ND: /* second state */ - if (dsk_rptr >= dsk_rlim) { /* end of buffer? */ - ch9_set_end (dsk_ch, 0); /* set end */ - ch_req |= REQ_CH (dsk_ch); /* request channel */ - dsk_sta = CHSL_SNS|CHSL_3RD; /* 3rd state */ - sim_activate (uptr, dsk_ctime); /* longer wait */ - return SCPE_OK; - } - dat = dsk_buf[dsk_rptr++]; /* get word */ - if (!dsk_stop) /* send wd to chan */ - ch9_req_rd (dsk_ch, dat); - break; - - case CHSL_SNS|CHSL_3RD: /* 3rd state */ - if (dsk_qdone (dsk_ch)) /* done? exit */ - return SCPE_OK; - dsk_sta = CHSL_SNS; /* repeat sequence */ - break; - } - -sim_activate (uptr, dsk_wtime); /* sched next */ -return SCPE_OK; -} - -/* Seek, read, write unit service */ - -t_stat dsk_svc (UNIT *uaptr) -{ -uint32 i, dtyp, trk; -uint8 fc, *format; -t_uint64 rdat; -UNIT *udptr; -t_stat r; - -if (uaptr->SKF) { /* seeking? */ - uint32 u = uaptr - dsk_dev.units; /* get unit */ - uaptr->SKF = 0; /* seek done */ - dsk_sns |= dsk_acc_atn (u); /* set atn bit */ - ch9_set_atn (dsk_ch); /* set atn flag */ - return SCPE_OK; - } - -udptr = dsk_dev.units + dsk_mod; /* data unit */ -if (udptr->flags & (UNIT_INOP0 << dsk_acc)) /* acc inoperative? */ - return dsk_uend (dsk_ch, DSKS_ACCI); /* error */ -if ((udptr->flags & UNIT_ATT) == 0) { /* not attached? */ - dsk_uend (dsk_ch, DSKS_ACCI); /* error */ - return SCPE_UNATT; - } - -dtyp = GET_DTYPE (udptr->flags); /* get data drive type */ -trk = uaptr->TRK; /* get access track */ - -switch (dsk_sta) { /* case on state */ - - case CHSL_RDS: /* read start */ - if ((r = dsk_init_trk (udptr, trk))) { /* read track, err? */ - return ((r == ERR_NRCF)? SCPE_OK: r); /* rec not fnd ok */ - } - dsk_sta = CHSL_RDS|CHSL_2ND; /* next state */ - break; - - case CHSL_RDS|CHSL_2ND: /* read data transmit */ - if ((r = dsk_xfer_done (uaptr, dtyp))) { /* transfer done? */ - if (r != ERR_ENDRC) /* error? */ - return r; - dsk_sta = CHSL_RDS|CHSL_3RD; /* next state */ - sim_activate (uaptr, dsk_gtime); /* gap time */ - return SCPE_OK; - } - rdat = dsk_buf[dsk_rptr++]; /* get word */ - if (dsk_rptr == T1STREC) /* if THA, skip after HA */ - dsk_rptr++; - if (!dsk_stop) /* give to channel */ - ch9_req_rd (dsk_ch, rdat); - break; - - case CHSL_RDS|CHSL_3RD: /* read end rec/trk */ - if (dsk_qdone (dsk_ch)) /* done? exit */ - return SCPE_OK; - dsk_sta = CHSL_RDS; /* repeat sequence */ - break; - - case CHSL_WRS: /* write start */ - if ((r = dsk_init_trk (udptr, trk))) { /* read track, err? */ - return ((r == ERR_NRCF)? SCPE_OK: r); /* rec not fnd ok */ - } - ch_req |= REQ_CH (dsk_ch); /* first request */ - dsk_sta = CHSL_WRS|CHSL_2ND; /* next state */ - dsk_chob = 0; /* clr, inval buffer */ - dsk_chob_v = 0; - break; - - case CHSL_WRS|CHSL_2ND: /* write data transmit */ - if (dsk_chob_v) /* valid? clear */ - dsk_chob_v = 0; - else if (!dsk_stop) /* no, no stop? io chk */ - ch9_set_ioc (dsk_ch); - if (dsk_wchk) { /* write check? */ - if (dsk_buf[dsk_rptr++] != dsk_chob) /* data mismatch? */ - return dsk_uend (dsk_ch, DSKS_CMPC); /* error */ - } - else dsk_buf[dsk_rptr++] = dsk_chob; /* write, store word */ - if (dsk_rptr == T1STREC) /* if THA, skip after HA */ - dsk_rptr++; - if ((r = dsk_xfer_done (uaptr, dtyp))) { /* transfer done? */ - if (r != ERR_ENDRC) /* error? */ - return r; - dsk_sta = CHSL_WRS|CHSL_3RD; /* next state */ - sim_activate (uaptr, dsk_gtime); /* gap time */ - return SCPE_OK; - } - if (!dsk_stop) /* more to do */ - ch_req |= REQ_CH (dsk_ch); - break; - - case CHSL_WRS|CHSL_3RD: /* write done */ - if (!dsk_wchk) { /* if write */ - if ((r = dsk_wr_trk (udptr, trk))) /* write track; err? */ - return r; - } - if (dsk_qdone (dsk_ch)) /* done? exit */ - return SCPE_OK; - dsk_sta = CHSL_WRS; /* repeat sequence */ - break; - -/* Formatting takes place in five stages - - 1. Clear the track buffer, request the first word from the channel - 2. Match characters against the fixed overhead (HA1, HA2, and gaps) - 3. Match characters against the per-record overhead (RA and gaps) - 4. Count the characters defining the record length - 5. See if the next character is end or gap; if gap, return to stage 3 - - This formating routine is not exact. It checks whether the format - will fit in the container, not whether the format would fit on a - real 7320, 1301, 1302, or 2302. */ - - case CHSL_FMT: /* initialization */ - for (i = 0; i < DSK_BUFSIZ; i++) /* clear track buf */ - dsk_buf[i] = 0; - dsk_rbase = T1STREC; /* init record ptr */ - dsk_rptr = 0; /* init format ptr */ - dsk_fmt_cntr = 0; /* init counter */ - ch_req |= REQ_CH (dsk_ch); /* request channel */ - dsk_sta = CHSL_FMT|CHSL_2ND; /* next state */ - dsk_chob = 0; /* clr, inval buffer */ - dsk_chob_v = 0; - break; - - case CHSL_FMT|CHSL_2ND: /* match track header */ - if ((dtyp == TYPE_7320) || (dtyp == TYPE_1301)) - format = fmt_thdr_7320; - else format = fmt_thdr_1302; - if (!dsk_get_fmtc (dtyp, &fc)) /* get fmt char; err? */ - return SCPE_OK; - if (fc != format[dsk_rptr++]) /* mismatch? */ - return dsk_uend (dsk_ch, DSKS_FMTC); /* format check */ - if (format[dsk_rptr] == 0) { /* end format? */ - dsk_sta = CHSL_FMT|CHSL_3RD; /* next state */ - dsk_rptr = 0; /* reset format ptr */ - } - break; - - case CHSL_FMT|CHSL_3RD: /* match record header */ - if ((dtyp == TYPE_7320) || (dtyp == TYPE_1301)) - format = fmt_rhdr_7320; - else format = fmt_rhdr_1302; - if (!dsk_get_fmtc (dtyp, &fc)) /* get fmt char; err? */ - return SCPE_OK; - if (fc != format[dsk_rptr++]) /* mismatch? */ - return dsk_uend (dsk_ch, DSKS_FMTC); /* format check */ - if (format[dsk_rptr] == 0) { /* end format? */ - dsk_sta = CHSL_FMT|CHSL_4TH; /* next state */ - dsk_rlim = 0; /* reset record ctr */ - } - break; - - case CHSL_FMT|CHSL_4TH: /* count record size */ - if (!dsk_get_fmtc (dtyp, &fc)) /* get fmt char; err? */ - return SCPE_OK; - if (fc == BCD_ONE) /* more record? */ - dsk_rlim++; - else { - uint32 rsiz = dsk_rlim / 6; /* rec size words */ - if ((fc != BCD_TWO) || /* improper end? */ - (rsiz == 0) || /* smaller than min? */ - ((dsk_rlim % 6) != 0) || /* not multiple of 6? */ - ((dsk_rbase + rsiz + RDATA) >= dsk_tab[dtyp].wdspt)) - return dsk_uend (dsk_ch, DSKS_FMTC); /* format check */ - dsk_buf[dsk_rbase + RLNT] = rsiz; /* record rec lnt */ - dsk_rbase = dsk_rbase + rsiz + RDATA; /* new rec start */ - dsk_sta = CHSL_FMT|CHSL_5TH; /* next state */ - } - break; - - case CHSL_FMT|CHSL_5TH: /* record or track end */ - if (!dsk_get_fmtc (dtyp, &fc)) /* get fmt char; err? */ - return SCPE_OK; - if (fc == BCD_TWO) { /* back to record header? */ - dsk_rptr = 2; /* already done 2 chars */ - dsk_sta = CHSL_FMT|CHSL_3RD; /* record header state */ - } - else if (fc != BCD_ONE) /* format check */ - dsk_uend (dsk_ch, DSKS_FMTC); - else { - if (!dsk_wchk) { /* actual write? */ - trk = trk - (trk % dsk_tab[dtyp].trkpc); /* cyl start */ - for (i = 0; i < dsk_tab[dtyp].trkpc; i++) { /* do all tracks */ - if ((r = dsk_wr_trk (udptr, trk + i))) /* wr track; err? */ - return r; - } - } - ch9_set_end (dsk_ch, 0); /* set end */ - ch_req |= REQ_CH (dsk_ch); /* request channel */ - dsk_sta = DSK_IDLE; /* disk is idle */ - return SCPE_OK; /* done */ - } - break; - - default: - return SCPE_IERR; - } - -sim_activate (uaptr, dsk_wtime); -return SCPE_OK; -} - -/* Initialize data transfer - - Inputs: - udptr = pointer to data unit - trk = track to read - Outputs: - dsk_buf contains track specified by trk - dsk_rbase, dsk_rptr, dsk_rlim are initialized - Errors: - SCPE_IOERR = I/O error (fatal, uend) - ERR_NRCF = no record found (HA2 or record number mismatch, uend) - STOP_INVFMT = invalid format (fatal, uend) -*/ - -t_stat dsk_init_trk (UNIT *udptr, uint32 trk) -{ -uint32 k, da, dtyp, rlnt; - -dtyp = GET_DTYPE (udptr->flags); /* get drive type */ -da = DSK_DA (dsk_acc, trk, dtyp); /* get disk address */ -sim_fseek (udptr->fileref, da, SEEK_SET); /* read track */ -k = sim_fread (dsk_buf, sizeof (t_uint64), dsk_tab[dtyp].wdspt, udptr->fileref); -if (ferror (udptr->fileref)) { /* error? */ - perror ("DSK I/O error"); - clearerr (udptr->fileref); - dsk_uend (dsk_ch, DSKS_DSKE); - return SCPE_IOERR; - } -for ( ; k < dsk_tab[dtyp].wdspt; k++) /* zero fill */ - dsk_buf[k] = 0; -dsk_rbase = T1STREC; /* record base */ -rlnt = (uint32) dsk_buf[dsk_rbase + RLNT]; /* length */ -dsk_rlim = dsk_rbase + rlnt + RDATA; /* end */ -if ((rlnt == 0) || (dsk_rlim >= dsk_tab[dtyp].wdspt)) { /* invalid record? */ - dsk_uend (dsk_ch, DSKS_FMTC); - return STOP_INVFMT; - } -if (dsk_mode != DSKC_SREC) { /* not single record? */ - if (dsk_mode == DSKC_THA) /* trk home addr? */ - dsk_rptr = 0; - else { - if (((dsk_rec << 24) ^ dsk_buf[THA2]) & HA2_MASK) { - dsk_uend (dsk_ch, DSKS_NRCF); /* invalid HA2 */ - return ERR_NRCF; - } - if (dsk_mode == DSKC_TWIA) /* track with addr? */ - dsk_rptr = dsk_rbase + RADDR; /* start at addr */ - else dsk_rptr = dsk_rbase + RDATA; /* else, at data */ - } - return SCPE_OK; - } -while (rlnt != 0) { /* until end track */ - dsk_rptr = dsk_rbase + RDATA; - if (((dsk_rec ^ dsk_buf[dsk_rbase + RADDR]) & REC_MASK) == 0) - return SCPE_OK; /* rec found? done */ - dsk_rbase = dsk_rlim; /* next record */ - rlnt = (uint32) dsk_buf[dsk_rbase + RLNT]; /* length */ - dsk_rlim = dsk_rbase + rlnt + RDATA; /* limit */ - if (dsk_rlim >= dsk_tab[dtyp].wdspt) { /* invalid format? */ - dsk_uend (dsk_ch, DSKS_FMTC); - return STOP_INVFMT; - } - } -dsk_uend (dsk_ch, DSKS_NRCF); /* not found */ -return ERR_NRCF; -} - -/* Check end of transfer - - Inputs: - uptr = pointer to access unit - dtyp = drive type - Outputs: - ERR_ENDRC = end of record/track/cylinder, end sent, ch req if required - SCPE_OK = more to do, dsk_rbase, dsk_rptr, dsk_rlim may be updated - STOP_INVFMT = invalid format (fatal, uend sent) -*/ - -t_stat dsk_xfer_done (UNIT *uaptr, uint32 dtyp) -{ -uint32 rlnt; - -if (dsk_rptr < dsk_rlim) /* record done? */ - return SCPE_OK; -if (dsk_stop || !ch9_qconn (dsk_ch) || /* stop or err disc or */ - (dsk_mode == DSKC_SREC)) { /* single record? */ - ch9_set_end (dsk_ch, 0); /* set end */ - ch_req |= REQ_CH (dsk_ch); /* request channel */ - return ERR_ENDRC; - } -dsk_rbase = dsk_rlim; /* next record */ -rlnt = (uint32) dsk_buf[dsk_rbase + RLNT]; /* length */ -dsk_rlim = dsk_rbase + rlnt + RDATA; /* end */ -if ((dsk_rbase >= dsk_tab[dtyp].wdspt) || /* invalid format? */ - (dsk_rlim >= dsk_tab[dtyp].wdspt)) { - dsk_uend (dsk_ch, DSKS_FMTC); - return STOP_INVFMT; - } -if (rlnt) { /* more on track? */ - if ((dsk_mode == DSKC_THA) || (dsk_mode == DSKC_TWIA)) - dsk_rptr = dsk_rbase + RADDR; /* start with addr */ - else dsk_rptr = dsk_rbase + RDATA; /* or data */ - return SCPE_OK; - } -if (dsk_mode == DSKC_CYL) { /* cylinder mode? */ - uaptr->TRK = (uaptr->TRK + 1) % dsk_tab[dtyp].trkpa; /* incr track */ - if (uaptr->TRK % dsk_tab[dtyp].trkpc) /* not cyl end? */ - return ERR_ENDRC; /* don't set end */ - } -ch9_set_end (dsk_ch, 0); /* set end */ -ch_req |= REQ_CH (dsk_ch); /* request channel */ -return ERR_ENDRC; -} - -/* Write track back to file */ - -t_stat dsk_wr_trk (UNIT *udptr, uint32 trk) -{ -uint32 dtyp = GET_DTYPE (udptr->flags); -uint32 da = DSK_DA (dsk_acc, trk, dtyp); - -sim_fseek (udptr->fileref, da, SEEK_SET); -sim_fwrite (dsk_buf, sizeof (t_uint64), dsk_tab[dtyp].wdspt, udptr->fileref); -if (ferror (udptr->fileref)) { - perror ("DSK I/O error"); - clearerr (udptr->fileref); - dsk_uend (dsk_ch, DSKS_DSKE); - return SCPE_IOERR; - } -return SCPE_OK; -} - -/* Synthesize right attention bit from (access * 10 + module) */ - -t_uint64 dsk_acc_atn (uint32 u) -{ -uint32 g, b; - -g = u / 4; /* bit group */ -b = u % 4; /* bit within group */ -return (DSKS_ATN0 >> ((g * 6) + (b? b + 1: 0))); -} - -/* Get next format character */ - -t_bool dsk_get_fmtc (uint32 dtyp, uint8 *fc) -{ -uint32 cc = dsk_fmt_cntr % 6; - -if (cc == 0) { /* start of word? */ - if (dsk_chob_v) /* valid? clear */ - dsk_chob_v = 0; - else if (!dsk_stop) /* no, no stop? io chk */ - ch9_set_ioc (dsk_ch); - } -*fc = ((uint8) (dsk_chob >> ((5 - cc) * 6))) & 077; /* get character */ -if ((cc == 5) && !dsk_stop) /* end of word? */ - ch_req |= REQ_CH (dsk_ch); -if (dsk_fmt_cntr++ >= dsk_tab[dtyp].fchpt) { /* track overflow? */ - dsk_uend (dsk_ch, DSKS_FMTC); /* format check */ - return FALSE; - } -return TRUE; -} - -/* Unusual end (set status and stop) */ - -t_stat dsk_uend (uint32 ch, t_uint64 stat) -{ -dsk_sns |= stat; -dsk_sns &= ~(DSKS_PCHK|DSKS_DCHK|DSKS_EXCC); -if (dsk_sns & DSKS_PALL) - dsk_sns |= DSKS_PCHK; -if (dsk_sns & DSKS_DALL) - dsk_sns |= DSKS_DCHK; -if (dsk_sns & DSKS_EALL) - dsk_sns |= DSKS_EXCC; -ch9_set_end (ch, CHINT_UEND); -ch_req |= REQ_CH (ch); -dsk_sta = DSK_IDLE; -return SCPE_OK; -} - -/* Test for done */ - -t_bool dsk_qdone (uint32 ch) -{ -if (dsk_stop || !ch9_qconn (ch)) { /* stop or err disc? */ - dsk_sta = DSK_IDLE; /* disk is idle */ - return TRUE; - } -return FALSE; -} - -/* Reset */ - -t_stat dsk_reset (DEVICE *dptr) -{ -uint32 i; -UNIT *uptr; - -dsk_acc = 0; -dsk_mod = 0; -dsk_rec = 0; -dsk_mode = 0; -dsk_wchk = 0; -dsk_sns = 0; -dsk_cmd = 0; -dsk_sta = DSK_IDLE; -dsk_rbase = 0; -dsk_rptr = 0; -dsk_rlim = 0; -dsk_stop = 0; -dsk_fmt_cntr = 0; -dsk_chob = 0; -dsk_chob_v = 0; -for (i = 0; i < DSK_BUFSIZ; i++) - dsk_buf[i] = 0; -for (i = 0; i <= (2 * DSK_NUMDR); i++) { - uptr = dsk_dev.units + i; - sim_cancel (uptr); - uptr->TRK = 0; - uptr->SKF = 0; - } -return SCPE_OK; -} - -/* Attach routine, test formating */ - -t_stat dsk_attach (UNIT *uptr, char *cptr) -{ -uint32 dtyp = GET_DTYPE (uptr->flags); -t_stat r; - -uptr->capac = dsk_tab[dtyp].size; -r = attach_unit (uptr, cptr); -if (r != SCPE_OK) - return r; -uptr->TRK = 0; -uptr->SKF = 0; -uptr->flags &= ~(UNIT_INOP0|UNIT_INOP1); -return dsk_show_format (stdout, uptr, 0, NULL); -} - -/* Set disk size */ - -t_stat dsk_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -uint32 dtyp = GET_DTYPE (val); -uint32 u = uptr - dsk_dev.units; -UNIT *u1; - -if (u & 1) - return SCPE_ARG; -u1 = dsk_dev.units + u + 1; -if ((uptr->flags & UNIT_ATT) || (u1->flags & UNIT_ATT)) - return SCPE_ALATT; -if (val == TYPE_7320) - u1->flags = (u1->flags & ~UNIT_DISABLE) | UNIT_DIS; -else { - u1->flags = (u1->flags & ~UNIT_TYPE) | val | UNIT_DISABLE; - u1->capac = dsk_tab[dtyp].size; - } -uptr->capac = dsk_tab[dtyp].size; -return SCPE_OK; -} - -/* Show format */ - -t_stat dsk_show_format (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -uint32 a, t, k, u, tlim, dtyp, da; -uint32 rptr, rlnt, rlim, rec, ctptr, *format; -uint32 minrsz = DSK_BUFSIZ; -uint32 maxrsz = 0; -uint32 minrno = DSK_BUFSIZ; -uint32 maxrno = 0; -t_bool ctss; -t_uint64 dbuf[DSK_BUFSIZ]; -DEVICE *dptr; - -if (uptr == NULL) - return SCPE_IERR; -if ((uptr->flags & UNIT_ATT) == 0) - return SCPE_UNATT; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; -u = uptr - dptr->units; - -dtyp = GET_DTYPE (uptr->flags); -if ((dtyp == TYPE_7320) || (dtyp == TYPE_1301)) - format = ctss_fmt_7320; -else format = ctss_fmt_1302; -for (a = 0, ctss = TRUE; a < dsk_tab[dtyp].accpm; a++) { - if (val) - tlim = dsk_tab[dtyp].trkpa; - else tlim = 1; - for (t = 0; t < tlim; t++) { - da = DSK_DA (a, t, dtyp); /* get disk address */ - sim_fseek (uptr->fileref, da, SEEK_SET); /* read track */ - k = sim_fread (dbuf, sizeof (t_uint64), dsk_tab[dtyp].wdspt, uptr->fileref); - if (ferror (uptr->fileref)) /* error? */ - return SCPE_IOERR; - for ( ; k < dsk_tab[dtyp].wdspt; k++) - dbuf[k] = 0; - rptr = T1STREC; - rlnt = (uint32) dbuf[rptr + RLNT]; - if (dbuf[THA2] != CTSS_HA2) - ctss = FALSE; - if (rlnt == 0) { - if (a || t) - fprintf (st, "Unformatted track, unit = %d, access = %d, track = %d\n", u, a, t); - else fprintf (st, "Unit %d is unformatted\n", u); - return SCPE_OK; - } - for (rec = 0, ctptr = 0; rlnt != 0; rec++) { - if ((format[ctptr] == 0) || format[ctptr++] != rlnt) - ctss = FALSE; - rlim = rptr + rlnt + RDATA; - if (rlim >= dsk_tab[dtyp].wdspt) { - fprintf (st, "Invalid record length %d, unit = %d, access = %d, track = %d, record = %d\n", - rlnt, u, a, t, rec); - return SCPE_OK; - } - if (rlnt > maxrsz) - maxrsz = rlnt; - if (rlnt < minrsz) - minrsz = rlnt; - rptr = rlim; - rlnt = (uint32) dbuf[rptr + RLNT]; - } - if (format[ctptr] != 0) - ctss = FALSE; - if (rec > maxrno) - maxrno = rec; - if (rec < minrno) - minrno = rec; - } - } -if (val == 0) - return SCPE_OK; -if (ctss) - fprintf (st, "CTSS format\n"); -else if ((minrno == maxrno) && (minrsz == maxrsz)) - fprintf (st, "Valid fixed format, records/track = %d, record size = %d\n", - minrno, minrsz); -else if (minrsz == maxrsz) - fprintf (st, "Valid variable format, records/track = %d-%d, record size = %d\n", - minrno, maxrno, minrsz); -else if (minrno == maxrno) - fprintf (st, "Valid variable format, records/track = %d, record sizes = %d-%d\n", - minrno, minrsz, maxrsz); -else fprintf (st, "Valid variable format, records/track = %d-%d, record sizes = %d-%d\n", - minrno, maxrno, minrsz, maxrsz); -return SCPE_OK; -} diff --git a/I7094/i7094_io.c b/I7094/i7094_io.c deleted file mode 100644 index d864ce68..00000000 --- a/I7094/i7094_io.c +++ /dev/null @@ -1,1899 +0,0 @@ -/* i7094_io.c: IBM 7094 I/O subsystem (channels) - - Copyright (c) 2003-2017, 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. - - chana..chanh I/O channels - - 13-Mar-17 RMS Annotated fall through in switch - 19-Mar-12 RMS Fixed declaration of breakpoint variables (Mark Pizzolato) - - Notes on channels and CTSS. - - - CTSS B-core is supported by the addition of a 16th bit to the current - address field of the channel command. Both the channel location counter - and the channel current address register are widened to 16b. Thus, - channel programs can run in B-core, and channel transfers can access B-core. - CTSS assumes that a channel command which starts a transfer in B-core - will not access A-core; the 16th bit does not increment. - - The channel start commands (RCHx and LCHx) incorporate the A-core/B-core - select as part of effective address generation. CTSS does not relocate - RCHx and LCHx target addresses; because the relocation indicator is - always zero, it's impossible to tell whether the protection indicator - affects address generation. - - The CTSS protection RPQ does not cover channel operations. Thus, CTSS - must inspect and vet all channel programs initiated by user mode programs, - notably the background processor FMS. CTSS inspects in-progress 7607 - channel programs to make sure than either the nostore bit or the B-core - bit is set; thus, SCHx must store all 16b of the current address. -*/ - -#include "i7094_defs.h" - -#define CHAMASK ((cpu_model & I_CT)? PAMASK: AMASK) /* chan addr mask */ -#define CHAINC(x) (((x) & ~AMASK) | (((x) + 1) & AMASK)) - -typedef struct { - char *name; - uint32 flags; - } DEV_CHAR; - -uint32 ch_sta[NUM_CHAN]; /* channel state */ -uint32 ch_dso[NUM_CHAN]; /* data select op */ -uint32 ch_dsu[NUM_CHAN]; /* data select unit */ -uint32 ch_ndso[NUM_CHAN]; /* non-data select op */ -uint32 ch_ndsu[NUM_CHAN]; /* non-data select unit */ -uint32 ch_flags[NUM_CHAN]; /* flags */ -uint32 ch_clc[NUM_CHAN]; /* chan loc ctr */ -uint32 ch_op[NUM_CHAN]; /* channel op */ -uint32 ch_wc[NUM_CHAN]; /* word count */ -uint32 ch_ca[NUM_CHAN]; /* core address */ -uint32 ch_lcc[NUM_CHAN]; /* control cntr (7909) */ -uint32 ch_cnd[NUM_CHAN]; /* cond reg (7909) */ -uint32 ch_sms[NUM_CHAN]; /* cond mask reg (7909) */ -t_uint64 ch_ar[NUM_CHAN]; /* assembly register */ -uint32 ch_idf[NUM_CHAN]; /* channel input data flags */ -DEVICE *ch2dev[NUM_CHAN] = { NULL }; -uint32 ch_tpoll = 5; /* channel poll */ - -extern t_uint64 *M; -extern uint32 cpu_model, data_base; -extern uint32 hst_ch; -extern uint32 ch_req; -extern uint32 chtr_inht, chtr_inhi, chtr_enab; -extern uint32 ind_ioc; -extern uint32 chtr_clk; -extern DEVICE cdr_dev, cdp_dev; -extern DEVICE lpt_dev; -extern DEVICE mt_dev[NUM_CHAN]; -extern DEVICE drm_dev; -extern DEVICE dsk_dev; -extern DEVICE com_dev; - -t_stat ch_reset (DEVICE *dptr); -t_stat ch6_svc (UNIT *uptr); -t_stat ch_set_enable (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat ch_set_disable (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat ch_show_type (FILE *st, UNIT *uptr, int32 val, void *desc); -DEVICE *ch_find_dev (uint32 ch, uint32 unit); -t_stat ch6_sel (uint32 ch, uint32 sel, uint32 unit, uint32 sta); -t_bool ch6_rd_putw (uint32 ch); -t_stat ch6_wr_getw (uint32 ch, t_bool eorz); -t_stat ch6_new_cmd (uint32 ch, t_bool ch_ld); -t_stat ch6_ioxt (uint32 ch); -void ch6_iosp_cclr (uint32 ch); -t_stat ch9_new_cmd (uint32 ch); -t_stat ch9_exec_cmd (uint32 ch, t_uint64 ir); -t_stat ch9_sel (uint32 ch, uint32 sel); -t_stat ch9_wr (uint32 ch, t_uint64 dat, uint32 fl); -t_stat ch9_rd_putw (uint32 ch); -t_stat ch9_wr_getw (uint32 ch); -void ch9_eval_int (uint32 ch, uint32 iflags); -DEVICE *ch_map_flags (uint32 ch, int32 fl); - -extern t_stat ch_bkpt (uint32 ch, uint32 clc); - -const uint32 col_masks[12] = { /* row 9,8,..,0,11,12 */ - 00001, 00002, 00004, - 00010, 00020, 00040, - 00100, 00200, 00400, - 01000, 02000, 04000 - }; - -const t_uint64 bit_masks[36] = { - 0000000000001, 0000000000002, 0000000000004, - 0000000000010, 0000000000020, 0000000000040, - 0000000000100, 0000000000200, 0000000000400, - 0000000001000, 0000000002000, 0000000004000, - 0000000010000, 0000000020000, 0000000040000, - 0000000100000, 0000000200000, 0000000400000, - 0000001000000, 0000002000000, 0000004000000, - 0000010000000, 0000020000000, 0000040000000, - 0000100000000, 0000200000000, 0000400000000, - 0001000000000, 0002000000000, 0004000000000, - INT64_C(0010000000000), INT64_C(0020000000000), INT64_C(0040000000000), - INT64_C(0100000000000), INT64_C(0200000000000), INT64_C(0400000000000) - }; - -const DEV_CHAR dev_table[] = { - { "729", 0 }, - { "TAPE", 0 }, - { "7289", DEV_7289 }, - { "DRUM", DEV_7289 }, - { "7631", DEV_7909|DEV_7631 }, - { "FILE", DEV_7909|DEV_7631 }, - { "7750", DEV_7909|DEV_7750 }, - { "COMM", DEV_7909|DEV_7750 }, - { NULL }, - }; - -const char *sel_name[] = { - "UNK", "RDS", "WRS", "SNS", "CTL", "FMT", "UNK", "UNK", - "WEF", "WBT", "BSR", "BSF", "REW", "RUN", "SDN", "UNK" - }; - -/* Channel data structures */ - -UNIT ch_unit[NUM_CHAN] = { - { UDATA (&ch6_svc, 0, 0) }, - { UDATA (&ch6_svc, 0, 0) }, - { UDATA (&ch6_svc, 0, 0) }, - { UDATA (&ch6_svc, 0, 0) }, - { UDATA (&ch6_svc, 0, 0) }, - { UDATA (&ch6_svc, 0, 0) }, - { UDATA (&ch6_svc, 0, 0) }, - { UDATA (&ch6_svc, 0, 0) } - }; - -MTAB ch_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "TYPE", NULL, - NULL, &ch_show_type, NULL }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "ENABLED", - &ch_set_enable, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DISABLED", - &ch_set_disable, NULL, NULL }, - { 0 } - }; - -REG cha_reg[] = { - { ORDATA (STA, ch_sta[CH_A], 8) }, - { ORDATA (DSC, ch_dso[CH_A], 4) }, - { ORDATA (DSU, ch_dsu[CH_A], 9) }, - { ORDATA (NDSC, ch_ndso[CH_A], 4) }, - { ORDATA (NDSU, ch_ndsu[CH_A], 9) }, - { ORDATA (FLAGS, ch_flags[CH_A], 30) }, - { ORDATA (IDF, ch_idf[CH_A], 2) }, - { ORDATA (OP, ch_op[CH_A], 5) }, - { ORDATA (CLC, ch_clc[CH_A], 16) }, - { ORDATA (WC, ch_wc[CH_A], 15) }, - { ORDATA (CA, ch_ca[CH_A], 16) }, - { ORDATA (AR, ch_ar[CH_A], 36) }, - { ORDATA (CND, ch_cnd[CH_A], 6), REG_HRO }, - { ORDATA (LCC, ch_lcc[CH_A], 6), REG_HRO }, - { ORDATA (SMS, ch_sms[CH_A], 7), REG_HRO }, - { 0 } - }; - -REG chb_reg[] = { - { ORDATA (STATE, ch_sta[CH_B], 8) }, - { ORDATA (DSC, ch_dso[CH_B], 4) }, - { ORDATA (DSU, ch_dsu[CH_B], 9) }, - { ORDATA (NDSC, ch_ndso[CH_B], 4) }, - { ORDATA (NDSU, ch_ndsu[CH_B], 9) }, - { ORDATA (FLAGS, ch_flags[CH_B], 30) }, - { ORDATA (IDF, ch_idf[CH_B], 2) }, - { ORDATA (OP, ch_op[CH_B], 5) }, - { ORDATA (CLC, ch_clc[CH_B], 16) }, - { ORDATA (WC, ch_wc[CH_B], 15) }, - { ORDATA (CA, ch_ca[CH_B], 16) }, - { ORDATA (AR, ch_ar[CH_B], 36) }, - { ORDATA (CND, ch_cnd[CH_B], 6) }, - { ORDATA (LCC, ch_lcc[CH_B], 6) }, - { ORDATA (SMS, ch_sms[CH_B], 7) }, - { 0 } - }; - -REG chc_reg[] = { - { ORDATA (STATE, ch_sta[CH_C], 8) }, - { ORDATA (DSC, ch_dso[CH_C], 4) }, - { ORDATA (DSU, ch_dsu[CH_C], 9) }, - { ORDATA (NDSC, ch_ndso[CH_C], 4) }, - { ORDATA (NDSU, ch_ndsu[CH_C], 9) }, - { ORDATA (FLAGS, ch_flags[CH_C], 30) }, - { ORDATA (IDF, ch_idf[CH_C], 2) }, - { ORDATA (OP, ch_op[CH_C], 5) }, - { ORDATA (CLC, ch_clc[CH_C], 16) }, - { ORDATA (WC, ch_wc[CH_C], 15) }, - { ORDATA (CA, ch_ca[CH_C], 16) }, - { ORDATA (AR, ch_ar[CH_C], 36) }, - { ORDATA (CND, ch_cnd[CH_C], 6) }, - { ORDATA (LCC, ch_lcc[CH_C], 6) }, - { ORDATA (SMS, ch_sms[CH_C], 7) }, - { 0 } - }; - -REG chd_reg[] = { - { ORDATA (STATE, ch_sta[CH_D], 8) }, - { ORDATA (DSC, ch_dso[CH_D], 4) }, - { ORDATA (DSU, ch_dsu[CH_D], 9) }, - { ORDATA (NDSC, ch_ndso[CH_D], 4) }, - { ORDATA (NDSU, ch_ndsu[CH_D], 9) }, - { ORDATA (FLAGS, ch_flags[CH_D], 30) }, - { ORDATA (IDF, ch_idf[CH_D], 2) }, - { ORDATA (OP, ch_op[CH_D], 5) }, - { ORDATA (CLC, ch_clc[CH_D], 16) }, - { ORDATA (WC, ch_wc[CH_D], 15) }, - { ORDATA (CA, ch_ca[CH_D], 16) }, - { ORDATA (AR, ch_ar[CH_D], 36) }, - { ORDATA (CND, ch_cnd[CH_D], 6) }, - { ORDATA (LCC, ch_lcc[CH_D], 6) }, - { ORDATA (SMS, ch_sms[CH_D], 7) }, - { 0 } - }; - -REG che_reg[] = { - { ORDATA (STATE, ch_sta[CH_E], 8) }, - { ORDATA (DSC, ch_dso[CH_E], 4) }, - { ORDATA (DSU, ch_dsu[CH_E], 9) }, - { ORDATA (NDSC, ch_ndso[CH_E], 4) }, - { ORDATA (NDSU, ch_ndsu[CH_E], 9) }, - { ORDATA (FLAGS, ch_flags[CH_E], 30) }, - { ORDATA (IDF, ch_idf[CH_E], 2) }, - { ORDATA (OP, ch_op[CH_E], 5) }, - { ORDATA (CLC, ch_clc[CH_E], 16) }, - { ORDATA (WC, ch_wc[CH_E], 15) }, - { ORDATA (CA, ch_ca[CH_E], 16) }, - { ORDATA (AR, ch_ar[CH_E], 36) }, - { ORDATA (CND, ch_cnd[CH_E], 6) }, - { ORDATA (LCC, ch_lcc[CH_E], 6) }, - { ORDATA (SMS, ch_sms[CH_E], 7) }, - { 0 } - }; - -REG chf_reg[] = { - { ORDATA (STATE, ch_sta[CH_F], 8) }, - { ORDATA (DSC, ch_dso[CH_F], 4) }, - { ORDATA (DSU, ch_dsu[CH_F], 9) }, - { ORDATA (NDSC, ch_ndso[CH_F], 4) }, - { ORDATA (NDSU, ch_ndsu[CH_F], 9) }, - { ORDATA (FLAGS, ch_flags[CH_F], 30) }, - { ORDATA (IDF, ch_idf[CH_F], 2) }, - { ORDATA (OP, ch_op[CH_F], 5) }, - { ORDATA (CLC, ch_clc[CH_F], 16) }, - { ORDATA (WC, ch_wc[CH_F], 15) }, - { ORDATA (CA, ch_ca[CH_F], 16) }, - { ORDATA (AR, ch_ar[CH_F], 36) }, - { ORDATA (CND, ch_cnd[CH_F], 6) }, - { ORDATA (LCC, ch_lcc[CH_F], 6) }, - { ORDATA (SMS, ch_sms[CH_F], 7) }, - { 0 } - }; - -REG chg_reg[] = { - { ORDATA (STATE, ch_sta[CH_G], 8) }, - { ORDATA (DSC, ch_dso[CH_G], 4) }, - { ORDATA (DSU, ch_dsu[CH_G], 9) }, - { ORDATA (NDSC, ch_ndso[CH_G], 4) }, - { ORDATA (NDSU, ch_ndsu[CH_G], 9) }, - { ORDATA (FLAGS, ch_flags[CH_G], 30) }, - { ORDATA (IDF, ch_idf[CH_G], 2) }, - { ORDATA (OP, ch_op[CH_G], 5) }, - { ORDATA (CLC, ch_clc[CH_G], 16) }, - { ORDATA (WC, ch_wc[CH_G], 15) }, - { ORDATA (CA, ch_ca[CH_G], 16) }, - { ORDATA (AR, ch_ar[CH_G], 36) }, - { ORDATA (CND, ch_cnd[CH_G], 6) }, - { ORDATA (LCC, ch_lcc[CH_G], 6) }, - { ORDATA (SMS, ch_sms[CH_G], 7) }, - { 0 } - }; - -REG chh_reg[] = { - { ORDATA (STATE, ch_sta[CH_H], 8) }, - { ORDATA (DSC, ch_dso[CH_H], 4) }, - { ORDATA (DSU, ch_dsu[CH_H], 9) }, - { ORDATA (NDSC, ch_ndso[CH_H], 4) }, - { ORDATA (NDSU, ch_ndsu[CH_H],9) }, - { ORDATA (FLAGS, ch_flags[CH_H], 30) }, - { ORDATA (IDF, ch_idf[CH_H], 2) }, - { ORDATA (OP, ch_op[CH_H], 5) }, - { ORDATA (CLC, ch_clc[CH_H], 16) }, - { ORDATA (WC, ch_wc[CH_H], 15) }, - { ORDATA (CA, ch_ca[CH_H], 16) }, - { ORDATA (AR, ch_ar[CH_H], 36) }, - { ORDATA (CND, ch_cnd[CH_H], 6) }, - { ORDATA (LCC, ch_lcc[CH_H], 6) }, - { ORDATA (SMS, ch_sms[CH_H], 7) }, - { 0 } - }; - -DEVICE ch_dev[NUM_CHAN] = { - { - "CHANA", &ch_unit[CH_A], cha_reg, ch_mod, - 1, 8, 8, 1, 8, 8, - NULL, NULL, &ch_reset, - NULL, NULL, NULL, - NULL, 0 - }, - { - "CHANB", &ch_unit[CH_B], chb_reg, ch_mod, - 1, 8, 8, 1, 8, 8, - NULL, NULL, &ch_reset, - NULL, NULL, NULL, - NULL, DEV_DISABLE | DEV_DIS - }, - { - "CHANC", &ch_unit[CH_C], chc_reg, ch_mod, - 1, 8, 8, 1, 8, 8, - NULL, NULL, &ch_reset, - NULL, NULL, NULL, - NULL, DEV_DISABLE | DEV_DIS - }, - { - "CHAND", &ch_unit[CH_D], chd_reg, ch_mod, - 1, 8, 8, 1, 8, 8, - NULL, NULL, &ch_reset, - NULL, NULL, NULL, - NULL, DEV_DISABLE | DEV_DIS - }, - { - "CHANE", &ch_unit[CH_E], che_reg, ch_mod, - 1, 8, 8, 1, 8, 8, - NULL, NULL, &ch_reset, - NULL, NULL, NULL, - NULL, DEV_DISABLE | DEV_DIS - }, - { - "CHANF", &ch_unit[CH_F], chf_reg, ch_mod, - 1, 8, 8, 1, 8, 8, - NULL, NULL, &ch_reset, - NULL, NULL, NULL, - NULL, DEV_DISABLE | DEV_DIS - }, - { - "CHANG", &ch_unit[CH_G], chg_reg, ch_mod, - 1, 8, 8, 1, 8, 8, - NULL, NULL, &ch_reset, - NULL, NULL, NULL, - NULL, DEV_DISABLE | DEV_DIS - }, - { - "CHANH", &ch_unit[CH_H], chh_reg, ch_mod, - 1, 8, 8, 1, 8, 8, - NULL, NULL, &ch_reset, - NULL, NULL, NULL, - NULL, DEV_DISABLE | DEV_DIS - } - }; - -/* 7607 channel overview - - Channel variables: - - ch_sta channel state - ch_dso, ch_dsu operation and unit for current data select - ch_ndso, ch_ndsu operation and unit for current non-data select - ch_clc current location counter - ch_ca memory addres - ch_wc word count - ch_op channel opcode (bits ) - ch_flags channel flags - - States of a channel - - IDLE - channel is not in operation - - RDS, WDS: -> DSW if device is idle, schedule device - device timeout drives next transition - -> stall if device is busy - repeat until device is idle - other I/O: -> NDS if device is idle, schedule device - device timeout drives next transition - -> stall if device is busy - repeat until device is idle - chan reset: -> IDLE - - PDS (PNDS) - channel is polling device to start data (non-data) select - - chan timeout: -> DSW (NDS) if device is idle - device timeout drives next transition - -> no change if device is busy, schedule channel - chan reset: -> IDLE - - DSW - channel is waiting for channel start command - - dev timeout: -> IDLE if no stacked non-data select - -> PNDS if stacked non-data select - channel timeout drives next transition - start chan: -> DSX if chan program transfers data - device timeout drives next transition - -> IDLE if channel disconnects, no stacked NDS - -> PNDS if channel disconnects, stacked NDS - channel timeout drives next transition - chan reset: -> IDLE - - DSX - channel is executing data select - - dev timeout: -> DSX if transfer not complete, reschedule device - device timeout drives next transition - -> DSW if channel command completes, CHF_LDW set - -> IDLE if transfer complete, no stacked NDS, or - if channel command completes, CHF_LDW clear - -> PNDS if channel disconnects, stacked NDS - channel timeout drives next transition - start chan: -> DSX with CHF_LDW, CPU stall - chan reset: -> IDLE - - NDS - channel is executing non-data select - - dev timeout: -> IDLE if transfer complete, no stacked DS - -> PDS if channel disconnects, stacked DS - channel timeout drives next transition - chan reset: -> IDLE - - The channel has two interfaces to a device. The select routine: - - dev_select (uint32 ch, uint32 sel, uint32 unit) - - Returns can include device errors and ERR_STALL. If ERR_STALL, the - device is busy. For I/O instructions, ERR_STALL stalls execution of - the instruction until the device is not busy. For stacked command - polls, ERR_STALL causes the poll to be repeated after a delay. - - The device write routine is used to place output data in the device - write buffer. - - Channel transfers are driven by the channel. When a device needs to - read or write data, it sets a channel request in ch_req. The channel - process transfers the data and updates channel control parameters - accordingly. Note that the channel may disconnect; in this case, the - transfer completes 'correctly' from the point of view of the device. - - The channel transfer commands (IOxT) require the channel to 'hold' - a new channel command in anticipation of the current transfer. If - the channel is currently executing (CH6S_DSX) and a channel start - is issued by the CPU, a 'start pending' flag is set and the CPU is - stalled. When the channel reaches the end of an IOxT command, it - checks the 'start pending' flag. If the flag is set, the channel - sets itself to waiting and then requeues itself for one cycle later. - The CPU tries the channel start, sees that the channel is waiting, - and issues the new channel command. - - state op device channel - - IDLE RDS,WDS start I/O ->DSW - - DSW LCHx (timed wait) ->DSX - - DSX -- timeout, req svc - (timed wait) transfer word - timeout, req svc - (timed wait) - LCHx, stalls : - timeout, EOR/EOC IOxT: ->DSW, resched - DSW LCHx (timed wait) ->DSX, etc - - 7909 channel overview - - Channel variables: - - ch_sta channel state - ch_clc current location counter - ch_ca memory addres - ch_wc word count - ch_op channel opcode (bits ) - ch_sms status mask - ch_cond interrupt conditions - ch_lcc control counter - ch_flags channel flags - - States of a channel - - IDLE - channel is not in operation - - RDCx, SDCx, interrupt -> DSX - - DSX - channel is executing data select - - TWT, WTR -> IDLE - - The 7909 is more capable than the 7607 but also simpler in some ways. - It has many more instructions, built in counters and status checking, - and interrupts. But it has only two states and no concept of records. - - The 7909 read process is driven by the device: - - channel CTLR/SNS: send select - device: schedule timeout - device timeout: device to AR, request channel - channel: AR to memory - device timeout: device to AR, request channel - channel: AR to memory - : - device timeout: set end, request channel - channel: disconnect on CPYD, send STOP - - The 7909 write process is also driven by the device: - - channel CTL/CTLW: send select - device: schedule timeout, request channel - channel: memory to output buffer - device timeout: output buffer to device, request channel - channel: memory to output buffer - device timeout: output buffer to device, request channel - : - channel: memory to output buffer - device timeout: output buffer to device, set end, request channel - channel: disconnect on CPYD, send STOP - - For both reads and writes, devices must implement an 'interblock' or - 'interrecord' state that is long enough for the channel to see the - end, disconnect, and send a stop signal. -*/ - -/* Data select - called by RDS or WDS instructions - 7607/7289 only - - - Channel is from address and has been corrected - - Channel must be an enabled 7607 - - If data select already in use, stall CPU - - If non-data select is a write end-of-file, stall CPU - - If channel is busy, stack command - - Otherwise, start IO, set channel to waiting */ - -t_stat ch_op_ds (uint32 ch, uint32 ds, uint32 unit) -{ -t_stat r; - -if (ch >= NUM_CHAN) /* invalid arg? */ - return STOP_NXCHN; -if (ch_dev[ch].flags & DEV_DIS) /* disabled? stop */ - return STOP_NXCHN; -if (ch_dev[ch].flags & DEV_7909) /* 7909? stop */ - return STOP_7909; -if (ch_dso[ch]) /* DS in use? */ - return ERR_STALL; -if (ch_ndso[ch] == CHSL_WEF) /* NDS = WEF? */ - return ERR_STALL; -if (ch_sta[ch] == CHXS_IDLE) { /* chan idle? */ - r = ch6_sel (ch, ds, unit, CH6S_DSW); /* select device */ - if (r != SCPE_OK) - return r; - } -ch_dso[ch] = ds; /* set command, unit */ -ch_dsu[ch] = unit; -ch_flags[ch] &= ~(CHF_LDW|CHF_EOR|CHF_CMD); /* clear flags */ -ch_idf[ch] = 0; -return SCPE_OK; -} - -/* Non-data select - called by BSR, BSF, WEF, REW, RUN, SDS instructions - 7607 only - - - Channel is from address and has been corrected - - Channel must be an enabled 7607 - - If non-data select already in use, stall CPU - - If data select is card or printer, stall CPU - - If channel is busy, stack command - - Otherwise, start IO, set channel to waiting */ - -t_stat ch_op_nds (uint32 ch, uint32 nds, uint32 unit) -{ -DEVICE *dptr; -t_stat r; - -if (ch >= NUM_CHAN) /* invalid arg? */ - return STOP_NXCHN; -if (ch_dev[ch].flags & DEV_DIS) /* disabled? stop */ - return STOP_NXCHN; -if (ch_dev[ch].flags & DEV_7909) /* 7909? stop */ - return STOP_7909; -if (ch_ndso[ch]) /* NDS in use? */ - return ERR_STALL; -if (ch_dso[ch] && (dptr = ch_find_dev (ch, ch_dsu[ch])) /* DS, cd or lpt? */ - && (dptr->flags & DEV_CDLP)) - return ERR_STALL; -if (ch_sta[ch] == CHXS_IDLE) { /* chan idle? */ - r = ch6_sel (ch, nds, unit, CH6S_NDS); /* select device */ - if (r != SCPE_OK) - return r; - } -ch_ndso[ch] = nds; /* set command, unit */ -ch_ndsu[ch] = unit; -return SCPE_OK; -} - -/* End of data select - called from channel - 7607/7289 only - - - If executing, set command trap flag - - Set channel idle - - If stacked nds, set up immediate channel timeout */ - -t_stat ch6_end_ds (uint32 ch) -{ -if (ch >= NUM_CHAN) /* invalid arg? */ - return STOP_NXCHN; -ch_dso[ch] = ch_dsu[ch] = 0; /* no data select */ -if (ch_ndso[ch]) { /* stacked non-data sel? */ - sim_activate (ch_dev[ch].units, 0); /* immediate poll */ - ch_sta[ch] = CH6S_PNDS; /* state = polling */ - } -else ch_sta[ch] = CHXS_IDLE; /* else state = idle */ -return SCPE_OK; -} - -/* End of non-data select - called from I/O device completion - 7607/7289 only - - - Set channel idle - - If stacked ds, set up immediate channel timeout */ - -t_stat ch6_end_nds (uint32 ch) -{ -if (ch >= NUM_CHAN) /* invalid arg? */ - return STOP_NXCHN; -ch_ndso[ch] = ch_ndsu[ch] = 0; /* no non-data select */ -if (ch_dso[ch]) { /* stacked data sel? */ - sim_activate (ch_dev[ch].units, 0); /* immediate poll */ - ch_sta[ch] = CH6S_PDS; /* state = polling */ - } -else ch_sta[ch] = CHXS_IDLE; /* else state = idle */ -return SCPE_OK; -} - -/* Send select to device - 7607/7289 only */ - -t_stat ch6_sel (uint32 ch, uint32 sel, uint32 unit, uint32 sta) -{ -DEVICE *dptr; -DIB *dibp; -t_stat r; - -if (ch >= NUM_CHAN) /* invalid arg? */ - return STOP_NXCHN; -dptr = ch_find_dev (ch, unit); /* find device */ -if (dptr == NULL) /* invalid device? */ - return STOP_NXDEV; -dibp = (DIB *) dptr->ctxt; -r = dibp->chsel (ch, sel, unit); /* select device */ -if (r == SCPE_OK) /* set status */ - ch_sta[ch] = sta; -return r; -} - -/* Channel unit service - called to start stacked command - 7607 only */ - -t_stat ch6_svc (UNIT *uptr) -{ -uint32 ch = uptr - &ch_unit[0]; /* get channel */ -t_stat r; - -if (ch >= NUM_CHAN) /* invalid chan? */ - return SCPE_IERR; -switch (ch_sta[ch]) { /* case on state */ - - case CH6S_PDS: /* polling for ds */ - r = ch6_sel (ch, ch_dso[ch], ch_dsu[ch], CH6S_DSW); - break; - - case CH6S_PNDS: /* polling for nds */ - r = ch6_sel (ch, ch_ndso[ch], ch_ndsu[ch], CH6S_NDS); - break; - - default: - return SCPE_OK; - } - -if (r == ERR_STALL) { /* stalled? */ - sim_activate (uptr, ch_tpoll); /* continue poll */ - return SCPE_OK; - } -return r; -} - -/* Map channel and unit number to device - all channels */ - -DEVICE *ch_find_dev (uint32 ch, uint32 unit) -{ -if (ch >= NUM_CHAN) /* invalid arg? */ - return NULL; -if (ch_dev[ch].flags & (DEV_7909|DEV_7289)) - return ch2dev[ch]; -unit = unit & 0777; -if (((unit >= U_MTBCD) && (unit <= (U_MTBCD + MT_NUMDR))) || - ((unit >= U_MTBIN) && (unit <= (U_MTBIN + MT_NUMDR)))) - return ch2dev[ch]; -if (ch != 0) - return NULL; -if (unit == U_CDR) - return &cdr_dev; -if (unit == U_CDP) - return &cdp_dev; -if ((unit == U_LPBCD) || (unit == U_LPBIN)) - return &lpt_dev; -return NULL; -} - -/* Start channel - channel is from opcode - - 7607: channel should have a data select operation pending (DSW state) - 7909: channel should be idle (IDLE state) */ - -t_stat ch_op_start (uint32 ch, uint32 clc, t_bool reset) -{ -t_uint64 ir; -t_stat r; - -clc = clc | data_base; /* add A/B select */ -if (ch >= NUM_CHAN) /* invalid argument? */ - return STOP_NXCHN; -if (ch_dev[ch].flags & DEV_DIS) /* disabled? stop */ - return STOP_NXCHN; -if (ch_dev[ch].flags & DEV_7909) { /* 7909? */ - if (ch_sta[ch] != CHXS_IDLE) /* must be idle */ - return ERR_STALL; - if (reset) { /* RDCx? */ - ch_cnd[ch] = 0; /* clear conditions */ - ch_clc[ch] = clc; /* set clc */ - } - else { /* SDCx */ - if (BIT_TST (chtr_enab, CHTR_V_TWT + ch) && /* pending trap? */ - (ch_flags[ch] & CHF_TWT)) - return ERR_STALL; - ch_clc[ch] = ch_ca[ch] & CHAMASK; /* finish WTR, TWT */ - } - ch_flags[ch] &= ~CHF_CLR_7909; /* clear flags, not IP */ - ch_idf[ch] = 0; - ch_sta[ch] = CHXS_DSX; /* set state */ - return ch9_new_cmd (ch); /* start executing */ - } - /* 7607, 7289 */ -if (reset) { /* reset? */ - if (ch_sta[ch] == CHXS_DSX) - ch_sta[ch] = CH6S_DSW; - ch_flags[ch] &= ~(CHF_LDW|CHF_EOR|CHF_TRC|CHF_CMD); - ch_idf[ch] = 0; - } - -switch (ch_sta[ch]) { /* case on chan state */ - - case CHXS_IDLE: /* idle */ - ind_ioc = 1; /* IO check */ - ir = ReadP (clc); /* get chan word */ - ch_clc[ch] = CHAINC (clc); /* incr chan pc */ - ch_wc[ch] = GET_DEC (ir); /* get word cnt */ - ch_ca[ch] = ((uint32) ir) & CHAMASK; /* get address */ - ch_op[ch] = (GET_OPD (ir) << 1) | /* get opcode */ - ((((uint32) ir) & CH6I_NST)? 1: 0); /* plus 'no store' */ - break; - - case CH6S_PNDS: /* NDS polling */ - case CH6S_PDS: /* DS polling */ - case CH6S_NDS: /* NDS executing */ - return ERR_STALL; /* wait it out */ - - case CH6S_DSW: /* expecting command */ - ch_sta[ch] = CHXS_DSX; /* update state */ - if (ch_dev[ch].flags & DEV_7289) { /* drum channel? */ - ir = ReadP (clc); /* read addr */ - ch_clc[ch] = CHAINC (clc); /* incr chan pc */ - if ((r = ch9_wr (ch, ir, 0))) /* write to dev */ - return r; - } - else ch_clc[ch] = clc; /* set clc */ - return ch6_new_cmd (ch, TRUE); /* start channel */ - - case CHXS_DSX: /* executing */ - ch_flags[ch] = ch_flags[ch] | CHF_LDW; /* flag pending LCH */ - return ERR_STALL; /* stall */ - } - -return SCPE_OK; -} - -/* Store channel - - 7607/7289 stores op,ca,nostore,clc - 7909 stores clc,,ca */ - -t_stat ch_op_store (uint32 ch, t_uint64 *dat) -{ -if ((ch >= NUM_CHAN) || (ch_dev[ch].flags & DEV_DIS)) - return STOP_NXCHN; -if (ch_dev[ch].flags & DEV_7909) - *dat = (((t_uint64) ch_ca[ch] & CHAMASK) << INST_V_DEC) | - (((t_uint64) ch_clc[ch] & CHAMASK) << INST_V_ADDR); -else *dat = (((t_uint64) ch_clc[ch] & CHAMASK) << INST_V_DEC) | - (((t_uint64) ch_ca[ch] & CHAMASK) << INST_V_ADDR) | - (((t_uint64) (ch_op[ch] & 1)) << 16) | - (((t_uint64) (ch_op[ch] & 016)) << 32); -return SCPE_OK; -} - -/* Store channel diagnostic - - 7607 is undefined - 7289 stores IOC+??? - 7909 stores 7909 lcc+flags */ - -t_stat ch_op_store_diag (uint32 ch, t_uint64 *dat) -{ -extern t_uint64 drm_sdc (uint32 ch); - -if ((ch >= NUM_CHAN) || (ch_dev[ch].flags & DEV_DIS)) - return STOP_NXCHN; -if (ch_flags[ch] & DEV_7289) - *dat = drm_sdc (ch); -else if (ch_flags[ch] & DEV_7909) - *dat = (((t_uint64) (ch_lcc[ch] & CHF_M_LCC)) << CHF_V_LCC) | - (ch_flags[ch] & CHF_SDC_7909); -else *dat = 0; -return SCPE_OK; -} - -/* Reset data channel - - 7607 responds to RDC - 7909 responds to RIC */ - -t_stat ch_op_reset (uint32 ch, t_bool ch7909) -{ -DEVICE *dptr; - -if (ch >= NUM_CHAN) /* invalid argument? */ - return STOP_NXCHN; -if (ch_dev[ch].flags & DEV_DIS) /* disabled? ok */ - return SCPE_OK; -if (ch_dev[ch].flags & DEV_7909) { /* 7909? */ - if (!ch7909) /* wrong reset is NOP */ - return SCPE_OK; - dptr = ch2dev[ch]; /* get device */ - } -else { /* 7607, 7289 */ - if (ch7909) /* wrong reset is err */ - return STOP_NT7909; - dptr = ch_find_dev (ch, ch_ndsu[ch]); /* find device */ - } -ch_reset (&ch_dev[ch]); /* reset channel */ -if (dptr && dptr->reset) /* reset device */ - dptr->reset (dptr); -return SCPE_OK; -} - -/* Channel process - called from main CPU loop. If the channel is unable - to get a valid command, it will reschedule itself for the next cycle. - - The read process is basically synchronous with the device timeout routine. - The device requests the channel and supplies the word to be stored in memory. - In the next time slot, the channel stores the word in memory. */ - -t_stat ch_proc (uint32 ch) -{ -t_stat r; - -if (ch >= NUM_CHAN) /* bad channel? */ - return SCPE_IERR; -ch_req &= ~REQ_CH (ch); /* clear request */ -if (ch_dev[ch].flags & DEV_DIS) /* disabled? */ - return SCPE_IERR; -if (ch_dev[ch].flags & DEV_7909) { /* 7909 */ - - t_uint64 sr; - uint32 csel, sc, tval, mask, ta; - t_bool xfr; - - if (ch_flags[ch] & CHF_IRQ) { /* interrupt? */ - ta = CHINT_CHA_SAV + (ch << 1); /* save location */ - if (ch_sta[ch] == CHXS_IDLE) /* waiting? */ - sr = (((t_uint64) ch_ca[ch] & CHAMASK) << INST_V_DEC) | - ((t_uint64) ch_clc[ch] & CHAMASK); /* save CLC */ - else sr = (((t_uint64) ch_ca[ch] & CHAMASK) << INST_V_DEC) | - ((t_uint64) CHAINC (ch_clc[ch])); /* no, save CLC+1 */ - ch_sta[ch] = CHXS_DSX; /* set running */ - ch_flags[ch] = (ch_flags[ch] | CHF_INT) & /* set intr state */ - ~(CHF_IRQ|CHF_PRD|CHF_PWR|CHF_RDS|CHF_WRS); /* clr flags */ - WriteP (ta, sr); /* write ca,,clc */ - sr = ReadP (ta + 1); /* get chan cmd */ - return ch9_exec_cmd (ch, sr); /* exec cmd */ - } - - switch (ch_op[ch] & CH9_OPMASK) { /* switch on op */ - - case CH9_TWT: /* transfer of TWT */ - case CH9_WTR: /* transfer of WTR */ - case CH9_TCH: /* transfer */ - ch_clc[ch] = ch_ca[ch] & CHAMASK; /* change CLC */ - break; - - case CH9_TDC: /* decr & transfer */ - if (ch_lcc[ch] != 0) { /* counter != 0? */ - ch_lcc[ch]--; /* decr counter */ - ch_clc[ch] = ch_ca[ch] & CHAMASK; /* change CLC */ - } - break; - - case CH9_TCM: /* transfer on cond */ - csel = CH9D_COND (ch_wc[ch]); - mask = CH9D_MASK (ch_wc[ch]); - if (csel == 7) /* C = 7? mask mbz */ - xfr = (mask == 0); - else { /* C = 0..6 */ - if (csel == 0) /* C = 0? test cond */ - tval = ch_cnd[ch]; - else tval = (uint32) (ch_ar[ch] >> (6 * (6 - csel))) & 077; - if (ch_wc[ch] & CH9D_B11) - xfr = ((tval & mask) == mask); - else xfr = (tval == mask); - } - if (xfr) /* change CLC */ - ch_clc[ch] = ch_ca[ch] & CHAMASK; - break; - - case CH9_LIP: /* leave interrupt */ - ta = CHINT_CHA_SAV + (ch << 1); /* save location */ - ch_flags[ch] &= ~(CHF_INT|CHF_IRQ); /* clear intr */ - ch_cnd[ch] = 0; /* clear channel cond */ - ch_clc[ch] = (uint32) ReadP (ta) & CHAMASK; - break; - - case CH9_LIPT: /* leave intr, transfer */ - ch_flags[ch] &= ~(CHF_INT|CHF_IRQ); /* clear intr */ - ch_cnd[ch] = 0; /* clear channel cond */ - ch_clc[ch] = ch_ca[ch] & CHAMASK; /* change CLC */ - break; - - case CH9_LAR: /* load assembly reg */ - ch_ar[ch] = ReadP (ch_ca[ch]); - break; - - case CH9_SAR: /* store assembly reg */ - WriteP (ch_ca[ch], ch_ar[ch]); - break; - - case CH9_SMS: /* load SMS reg */ - ch_sms[ch] = CH9A_SMS (ch_ca[ch]); /* from eff addr */ - if (!(ch_sms[ch] & CHSMS_IATN1) && /* atn inhbit off */ - (ch_flags[ch] & CHF_ATN1)) /* and atn pending? */ - ch9_eval_int (ch, 0); /* force int eval */ - break; - - case CH9_LCC: /* load control cntr */ - ch_lcc[ch] = CH9A_LCC (ch_ca[ch]); /* from eff addr */ - break; - - case CH9_ICC: /* insert control cntr */ - case CH9_ICCA: - csel = CH9D_COND (ch_wc[ch]); /* get C */ - if (csel == 0) ch_ar[ch] = /* C = 0? read SMS */ - (ch_ar[ch] & INT64_C(0777777770000)) | ((t_uint64) ch_sms[ch]); - else if (csel < 7) { /* else read cond cntr */ - sc = 6 * (6 - csel); - ch_ar[ch] = (ch_ar[ch] & ~(((t_uint64) 077) << sc)) | - (((t_uint64) ch_lcc[ch]) << sc); - } - break; - - case CH9_XMT: /* transmit */ - if (ch_wc[ch] == 0) - break; - sr = ReadP (ch_clc[ch]); /* next word */ - WriteP (ch_ca[ch], sr); - ch_clc[ch] = CHAINC (ch_clc[ch]); /* incr pointers */ - ch_ca[ch] = CHAINC (ch_ca[ch]); - ch_wc[ch] = ch_wc[ch] - 1; /* decr count */ - ch_req |= REQ_CH (ch); /* go again */ - return SCPE_OK; - - case CH9_SNS: /* sense */ - if ((r = ch9_sel (ch, CHSL_SNS))) /* send sense to dev */ - return r; - ch_flags[ch] |= CHF_PRD; /* prepare to read */ - break; /* next command */ - - case CH9_CTL: - case CH9_CTLR: - case CH9_CTLW: /* control */ - if (((ch_wc[ch] & CH9D_NST) == 0) && /* N = 0 and */ - !(ch_flags[ch] & CHF_EOR)) { /* end not set? */ - sr = ReadP (ch_ca[ch]); - ch_ca[ch] = CHAINC (ch_ca[ch]); /* incr ca */ - return ch9_wr (ch, sr, 0); /* write ctrl wd */ - } - ch_flags[ch] &= ~CHF_EOR; /* clear end */ - if (ch_op[ch] == CH9_CTLR) { /* CTLR? */ - if ((r = ch9_sel (ch, CHSL_RDS))) /* send read sel */ - return r; - ch_flags[ch] |= CHF_PRD; /* prep to read */ - ch_idf[ch] = 0; - } - else if (ch_op[ch] == CH9_CTLW) { /* CTLW? */ - if ((r = ch9_sel (ch, CHSL_WRS))) /* end write sel */ - return r; - ch_flags[ch] |= CHF_PWR; /* prep to write */ - } - break; - - case CH9_CPYD: /* copy & disc */ - if ((ch_wc[ch] == 0) || (ch_flags[ch] & CHF_EOR)) { /* wc == 0 or EOR? */ - if (ch_flags[ch] & (CHF_PRD|CHF_PWR|CHF_RDS|CHF_WRS)) { - ch_flags[ch] &= ~(CHF_PRD|CHF_PWR|CHF_RDS|CHF_WRS); - if ((r = ch9_wr (ch, 0, CH9DF_STOP))) /* send stop */ - return r; - } - if (ch_flags[ch] & CHF_EOR) { /* EOR? */ - ch_flags[ch] &= ~CHF_EOR; /* clear flag */ - break; /* new command */ - } - return SCPE_OK; /* wait for end */ - } - if (ch_flags[ch] & CHF_RDS) /* read? */ - return ch9_rd_putw (ch); - return ch9_wr_getw (ch); /* no, write */ - - case CH9_CPYP: /* anything to do? */ - if (ch_wc[ch] == 0) /* (new, wc = 0) next */ - break; - if (ch_flags[ch] & CHF_EOR) /* end? */ - ch_flags[ch] &= ~CHF_EOR; /* ignore */ - else if (ch_flags[ch] & CHF_RDS) /* read? */ - ch9_rd_putw (ch); - else if ((r = ch9_wr_getw (ch))) /* no, write */ - return r; - if (ch_wc[ch] == 0) /* done? get next */ - break; - return SCPE_OK; /* more to do */ - - default: - return STOP_ILLIOP; - } - - return ch9_new_cmd (ch); /* next command */ - } - -else if (ch_flags[ch] & CHF_RDS) { /* 7607 read? */ - - if (ch_sta[ch] != CHXS_DSX) /* chan exec? no, disc */ - return ch6_end_ds (ch); - switch (ch_op[ch] & CH6_OPMASK) { /* switch on op */ - - case CH6_TCH: /* transfer */ - ch_clc[ch] = ch_ca[ch] & CHAMASK; /* change clc */ - return ch6_new_cmd (ch, FALSE); /* unpack new cmd */ - - case CH6_IOCD: /* IOCD */ - if (ch_wc[ch]) { /* wc > 0? */ - if (ch6_rd_putw (ch)) /* store; more? cont */ - return SCPE_OK; - } - return ch6_end_ds (ch); /* no, disconnect */ - - case CH6_IOCP: /* IOCP */ - if (ch_wc[ch]) { /* wc > 0? */ - if (ch6_rd_putw (ch)) /* store; more? cont */ - return SCPE_OK; - } - return ch6_new_cmd (ch, FALSE); /* unpack new cmd */ - - case CH6_IOCT: /* IOCT */ - if (ch_wc[ch]) { /* wc > 0? */ - if (ch6_rd_putw (ch)) /* store; more? cont */ - return SCPE_OK; - } - return ch6_ioxt (ch); /* unstall or disc */ - - case CH6_IOSP: /* IOSP */ - if (ch_flags[ch] & CHF_EOR) { /* (new) EOR set? */ - ch_flags[ch] = ch_flags[ch] & ~CHF_EOR; /* clear flag */ - return ch6_new_cmd (ch, FALSE); /* get next cmd */ - } - if (ch_wc[ch]) { /* wc > 0? */ - if (ch6_rd_putw (ch) && !(ch_flags[ch] & CHF_EOR)) - return SCPE_OK; /* yes, store; more? */ - ch6_iosp_cclr (ch); /* cond clear eor */ - } - return ch6_new_cmd (ch, FALSE); /* next cmd */ - - case CH6_IOST: /* IOST */ - if (ch_flags[ch] & CHF_EOR) { /* (new) EOR set? */ - ch_flags[ch] = ch_flags[ch] & ~CHF_EOR; /* clear flag */ - return ch6_ioxt (ch); /* get next cmd */ - } - if (ch_wc[ch]) { /* wc > 0? */ - if (ch6_rd_putw (ch) && !(ch_flags[ch] & CHF_EOR)) - return SCPE_OK; /* yes, store; more? */ - ch6_iosp_cclr (ch); /* cond clear eor */ - } - return ch6_ioxt (ch); /* unstall or disc */ - - case CH6_IORP: /* IORP */ - if (ch_flags[ch] & CHF_EOR) { /* (new) EOR set? */ - ch_flags[ch] = ch_flags[ch] & ~CHF_EOR; /* clear flag */ - return ch6_new_cmd (ch, FALSE); /* get next cmd */ - } - ch6_rd_putw (ch); /* store wd; ignore wc */ - if (ch_flags[ch] & CHF_EOR) { /* EOR? */ - ch_flags[ch] = ch_flags[ch] & ~CHF_EOR; /* clear flag */ - return ch6_new_cmd (ch, FALSE); /* get next cmd */ - } - return SCPE_OK; /* done */ - - case CH6_IORT: /* IORT */ - if (ch_flags[ch] & CHF_EOR) { /* (new) EOR set? */ - ch_flags[ch] = ch_flags[ch] & ~CHF_EOR; /* clear flag */ - return ch6_ioxt (ch); /* get next cmd */ - } - ch6_rd_putw (ch); /* store wd; ignore wc */ - if (ch_flags[ch] & CHF_EOR) { /* EOR? */ - ch_flags[ch] = ch_flags[ch] & ~CHF_EOR; /* clear flag */ - return ch6_ioxt (ch); /* unstall or disc */ - } - return SCPE_OK; /* done */ - - default: - return SCPE_IERR; - } /* end case */ - } /* end if read */ - -else { /* 7607 write */ - - if (ch_sta[ch] != CHXS_DSX) /* chan exec? no, disc */ - return ch6_end_ds (ch); - switch (ch_op[ch] & CH6_OPMASK) { /* switch on op */ - - case CH6_TCH: /* transfer */ - ch_clc[ch] = ch_ca[ch] & CHAMASK; /* change clc */ - return ch6_new_cmd (ch, FALSE); /* unpack new cmd */ - - case CH6_IOCD: /* IOCD */ - if (ch_wc[ch]) { /* wc > 0? */ - if ((r = ch6_wr_getw (ch, TRUE))) /* send wd to dev; err? */ - return r; - if (ch_wc[ch]) /* more to do? */ - return SCPE_OK; - } - return ch6_end_ds (ch); /* disconnect */ - - case CH6_IOCP: /* IOCP */ - case CH6_IOSP: /* IOSP */ - if (ch_wc[ch]) { /* wc > 0? */ - if ((r = ch6_wr_getw (ch, FALSE))) /* send wd to dev; err? */ - return r; - if (ch_wc[ch]) /* more to do? */ - return SCPE_OK; - } - return ch6_new_cmd (ch, FALSE); /* get next cmd */ - - case CH6_IOCT: /* IOCT */ - case CH6_IOST: /* IOST */ - if (ch_wc[ch]) { /* wc > 0? */ - if ((r = ch6_wr_getw (ch, FALSE))) /* send wd to dev; err? */ - return r; - if (ch_wc[ch]) /* more to do? */ - return SCPE_OK; - } - return ch6_ioxt (ch); /* get next cmd */ - - case CH6_IORP: /* IORP */ - if (!(ch_flags[ch] & CHF_EOR) && ch_wc[ch]) { /* not EOR? (cdp, lpt) */ - if ((r = ch6_wr_getw (ch, TRUE))) /* send wd to dev; err? */ - return r; - if (ch_wc[ch]) /* more to do? */ - return SCPE_OK; - } - ch_flags[ch] = ch_flags[ch] & ~CHF_EOR; /* clear EOR */ - return ch6_new_cmd (ch, FALSE); /* get next cmd */ - - case CH6_IORT: /* IORT */ - if (!(ch_flags[ch] & CHF_EOR) && ch_wc[ch]) { /* not EOR? (cdp, lpt) */ - if ((r = ch6_wr_getw (ch, TRUE))) /* send wd to dev; err? */ - return r; - if (ch_wc[ch]) /* more to do? */ - return SCPE_OK; - } - ch_flags[ch] = ch_flags[ch] & ~CHF_EOR; /* clear EOR */ - return ch6_ioxt (ch); /* unstall or disc */ - - default: - return SCPE_IERR; - } /* end switch */ - } /* end else write */ -} - -/* 7607 channel support routines */ - -/* 7607 channel input routine - put one word to memory */ - -t_bool ch6_rd_putw (uint32 ch) -{ -if (ch_idf[ch] & CH6DF_EOR) /* eor from dev? */ - ch_flags[ch] |= CHF_EOR; -else ch_flags[ch] = ch_flags[ch] & ~CHF_EOR; /* set/clr chan eor */ -ch_idf[ch] = 0; /* clear eor, valid */ -if (ch_wc[ch]) { /* wc > 0? */ - if ((ch_op[ch] & 1) == 0) { /* do store? */ - WriteP (ch_ca[ch], ch_ar[ch]); - ch_ca[ch] = CHAINC (ch_ca[ch]); /* incr ca */ - } - ch_wc[ch] = ch_wc[ch] - 1; - } -return (ch_wc[ch]? TRUE: FALSE); -} - -/* 7607 channel output routine - get one word from memory */ - -t_stat ch6_wr_getw (uint32 ch, t_bool eorz) -{ -DEVICE *dptr; -DIB *dibp; -uint32 eorfl; - -ch_flags[ch] = ch_flags[ch] & ~CHF_EOR; /* clr eor */ -if (ch_wc[ch]) { - ch_ar[ch] = ReadP (ch_ca[ch]); /* get word */ - ch_ca[ch] = CHAINC (ch_ca[ch]); /* incr ca */ - ch_wc[ch] = ch_wc[ch] - 1; - } -else ch_ar[ch] = 0; -if (eorz && (ch_wc[ch] == 0)) /* eor on wc = 0? */ - eorfl = 1; -else eorfl = 0; -dptr = ch_find_dev (ch, ch_dsu[ch]); /* find device */ -if (dptr && /* valid device? */ - (dibp = (DIB *) dptr->ctxt) && /* with DIB? */ - dibp->write) /* and write routine? */ - return dibp->write (ch, ch_ar[ch], eorfl); -return SCPE_IERR; /* huh? */ -} - -/* 7607 channel new command - on channel load, check for disconnects - - The protocol for new commands is as follows: - - If IOCD 0,,0, disconnect immediately - - If IOCT 0,,0 or IOST 0,,0 and loaded by RCHA, disconnect immediately - - If an effective NOP (TCH, IOCx 0,,0, IOSx 0,,0), force a channel - cycle to retire the channel comand as quickly as possible. - - If an IORx and EOR is set, force a channel cycle to retire the - channel command as quickly as possible. -*/ - -t_stat ch6_new_cmd (uint32 ch, t_bool ch_ld) -{ -t_uint64 ir; -uint32 op, t; - -ir = ReadP (t = ch_clc[ch]); /* read cmd */ -ch_wc[ch] = GET_DEC (ir); /* get word cnt */ -ch_ca[ch] = ((uint32) ir) & CHAMASK; /* get address */ -op = GET_OPD (ir) << 1; /* get opcode */ -ch_op[ch] = op | ((((uint32) ir) & CH6I_NST)? 1: 0); /* plus 'no store' */ -if ((ir & CHI_IND) && (ch_wc[ch] || /* indirect? */ - ((op != CH6_IOCP) && (op != CH6_IOSP)))) { /* wc >0, or !IOxP? */ - t_uint64 sr = ReadP (ch_ca[ch] & AMASK); /* read indirect */ - ch_ca[ch] = ((uint32) sr) & ((cpu_model & I_CT)? PAMASK: AMASK); - } -if (hst_ch) - cpu_ent_hist (ch_clc[ch] | ((ch + 1) << HIST_V_CH), ch_ca[ch], ir, 0); -ch_clc[ch] = (ch_clc[ch] + 1) & AMASK; /* incr chan pc */ - -switch (op) { /* case on opcode */ - - case CH6_IOCD: /* IOCD */ - if (ch_wc[ch] == 0) /* wc 0? end now */ - ch6_end_ds (ch); - break; - - case CH6_IOST: /* IOST */ - if (ch_flags[ch] & CHF_EOR) /* EOR set? immed ch req */ - ch_req |= REQ_CH (ch); /* fall through */ - case CH6_IOCT: /* IOCT */ - if (ch_wc[ch] == 0) { /* wc 0? */ - if (ch_ld) /* load? end now */ - ch6_end_ds (ch); - else ch_req |= REQ_CH (ch); /* else immed ch req */ - } - break; - - case CH6_IOSP: /* IOSP */ - if (ch_flags[ch] & CHF_EOR) /* EOR set? immed ch req */ - ch_req |= REQ_CH (ch); /* fall through */ - case CH6_IOCP: /* IOCP */ - if (ch_wc[ch] == 0) /* wc 0? immed ch req */ - ch_req |= REQ_CH (ch); - break; - - case CH6_IORT: /* IORT */ - case CH6_IORP: /* IORP */ - if (ch_flags[ch] & CHF_EOR) /* EOR set? immed ch req */ - ch_req |= REQ_CH (ch); - break; - - case CH6_TCH: /* TCH */ - ch_req |= REQ_CH (ch); /* immed ch req */ - break; - - default: /* all others */ - break; - } /* end case */ - -if (sim_brk_summ && sim_brk_test (t, SWMASK ('E'))) - return ch_bkpt (ch, t); -return SCPE_OK; -} - -/* 7607 channel IOxT: if LCH stall, set state back to DSW; else disconnect and trap */ - -t_stat ch6_ioxt (uint32 ch) -{ -if (ch_flags[ch] & CHF_LDW) { /* LCH cmd pending? */ - ch_flags[ch] &= ~CHF_LDW; /* clr pending flag */ - ch_sta[ch] = CH6S_DSW; /* unstall pending LCH */ - } -else { - ch_flags[ch] |= CHF_CMD; /* set cmd trap flag */ - ch6_end_ds (ch); /* disconnect */ - } -return SCPE_OK; -} - -/* 7607 conditionally clear EOR on IOSx completion */ - -void ch6_iosp_cclr (uint32 ch) -{ -uint32 i, op; - -if (ch_wc[ch] == 0) { /* wc = 0? */ - uint32 ccnt = 5; /* allow 5 for CPU */ - for (i = 0; i < NUM_CHAN; i++) { /* test channels */ - if (ch_sta[ch] != CHXS_DSX) /* idle? skip */ - continue; - op = ch_op[ch] & ~1; /* get op */ - ccnt++; /* 1 per active ch */ - if ((op == CH6_IOCP) || (op == CH6_IORP) || /* 1 per proceed */ - (op == CH6_IOSP)) - ccnt++; - } - if (ccnt <= 11) /* <= 11? ok */ - return; - } -ch_flags[ch] = ch_flags[ch] & ~CHF_EOR; /* clear eor */ -return; -} - -/* 7607 external interface routines */ - -/* Input - store word, request channel input service */ - -t_stat ch6_req_rd (uint32 ch, uint32 unit, t_uint64 val, uint32 fl) -{ -if (ch6_qconn (ch, unit)) { /* ch conn to caller? */ - if (ch_idf[ch] & CH6DF_VLD) /* overrun? */ - ind_ioc = 1; - ch_idf[ch] = CH6DF_VLD; /* set ar valid */ - if (fl) /* set eor if requested */ - ch_idf[ch] |= CH6DF_EOR; - ch_req |= REQ_CH (ch); /* request chan */ - ch_flags[ch] |= CHF_RDS; - ch_ar[ch] = val & DMASK; /* save data */ - } -return SCPE_OK; -} - -/* Disconnect on error */ - -t_stat ch6_err_disc (uint32 ch, uint32 unit, uint32 fl) -{ -if (ch6_qconn (ch, unit)) { /* ch conn to caller? */ - ch_flags[ch] |= fl; /* set flag */ - return ch6_end_ds (ch); /* disconnect */ - } -return SCPE_OK; -} - -/* Output - request channel output service */ - -t_bool ch6_req_wr (uint32 ch, uint32 unit) -{ -if (ch6_qconn (ch, unit)) { /* ch conn to caller? */ - ch_req |= REQ_CH (ch); - ch_flags[ch] &= ~CHF_RDS; - } -return SCPE_OK; -} - -/* Set/read channel flags */ - -uint32 ch6_set_flags (uint32 ch, uint32 unit, uint32 flags) -{ -if (ch6_qconn (ch, unit)) { /* ch conn to caller? */ - ch_flags[ch] = ch_flags[ch] | flags; - return ch_flags[ch]; - } -return 0; -} - -/* Channel connected to unit? */ - -t_bool ch6_qconn (uint32 ch, uint32 unit) -{ -if ((ch < NUM_CHAN) && /* valid chan */ - (ch_dsu[ch] == unit)) /* for right unit? */ - return TRUE; -return FALSE; -} - -/* 7909 channel support routines */ - -/* 7909 channel input routine - put one word to memory */ - -t_stat ch9_rd_putw (uint32 ch) -{ -ch_idf[ch] = 0; /* invalidate */ -if (ch_wc[ch]) { /* wc > 0? */ - WriteP (ch_ca[ch], ch_ar[ch]); - ch_ca[ch] = CHAINC (ch_ca[ch]); - ch_wc[ch] = ch_wc[ch] - 1; - } -return SCPE_OK; -} - -/* 7909 channel output routine - get one word from memory */ - -t_stat ch9_wr_getw (uint32 ch) -{ -if (ch_wc[ch]) { - ch_ar[ch] = ReadP (ch_ca[ch]); /* get word */ - ch_ca[ch] = CHAINC (ch_ca[ch]); - ch_wc[ch] = ch_wc[ch] - 1; - } -else ch_ar[ch] = 0; -return ch9_wr (ch, ch_ar[ch], 0); /* write to device */ -} - -/* 7909 send select to device */ - -t_stat ch9_sel (uint32 ch, uint32 sel) -{ -DEVICE *dptr = ch2dev[ch]; -DIB *dibp; - -if (dptr == NULL) - return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if (dibp && dibp->chsel) - return dibp->chsel (ch, sel, 0); -return SCPE_IERR; -} - -/* 7909 send word to device */ - -t_stat ch9_wr (uint32 ch, t_uint64 dat, uint32 fl) -{ -DEVICE *dptr = ch2dev[ch]; -DIB *dibp; - -if (dptr == NULL) - return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if (dibp && dibp->write) - return dibp->write (ch, dat, fl); -return SCPE_IERR; -} - -/* 7909 channel new command */ - -t_stat ch9_new_cmd (uint32 ch) -{ -t_uint64 ir; -uint32 t; -t_stat r; - -ir = ReadP (t = ch_clc[ch]); /* read cmd */ -r = ch9_exec_cmd (ch, ir); /* exec cmd */ -if (ch_sta[ch] != CHXS_IDLE) /* chan running? */ - ch_clc[ch] = CHAINC (ch_clc[ch]); /* incr chan pc */ -if ((r == SCPE_OK) && sim_brk_summ && sim_brk_test (t, SWMASK ('E'))) - return ch_bkpt (ch, t); -return r; -} - -t_stat ch9_exec_cmd (uint32 ch, t_uint64 ir) -{ -uint32 op; - -ch_wc[ch] = GET_DEC (ir); /* get word cnt */ -ch_ca[ch] = ((uint32) ir) & CHAMASK; /* get address */ -op = (GET_OPD (ir) << 2); /* get opcode */ -ch_op[ch] = op | ((((uint32) ir) & 0200000)? 1: 0) | /* plus bit<19> */ - (((op & 010) && (ch_wc[ch] & 040000))? 2: 0); /* plus bit 3 if used */ -if (ir & CHI_IND) { /* indirect? */ - t_uint64 sr = ReadP (ch_ca[ch] & CHAMASK); /* read indirect */ - ch_ca[ch] = ((uint32) sr) & CHAMASK; /* get address */ - } -if (hst_ch) - cpu_ent_hist (ch_clc[ch] | ((ch + 1) << HIST_V_CH), ch_ca[ch], ir, 0); - -switch (ch_op[ch]) { /* check initial cond */ - - case CH9_LAR: /* misc processing */ - case CH9_SAR: - case CH9_ICC: - case CH9_ICCA: - case CH9_XMT: - case CH9_LCC: - case CH9_SMS: - if (ch_flags[ch] & (CHF_PRD|CHF_PWR|CHF_RDS|CHF_WRS)) - ch9_eval_int (ch, CHINT_SEQC); /* not during data */ - /* fall through */ - case CH9_TCM: /* jumps */ - case CH9_TCH: - case CH9_TDC: - case CH9_LIPT: - case CH9_LIP: - ch_req |= REQ_CH (ch); /* process in chan */ - break; - - case CH9_CTL: /* control */ - case CH9_CTLR: - case CH9_CTLW: - if (ch_flags[ch] & (CHF_PRD|CHF_PWR|CHF_RDS|CHF_WRS)) - ch9_eval_int (ch, CHINT_SEQC); /* not during data */ - ch_flags[ch] &= ~CHF_EOR; - if (ch_wc[ch] & CH9D_NST) /* N set? proc in chan */ - ch_req |= REQ_CH (ch); - else return ch9_sel (ch, CHSL_CTL); /* sel, dev sets ch_req! */ - break; - - case CH9_SNS: /* sense */ - if (ch_flags[ch] & (CHF_PRD|CHF_PWR|CHF_RDS|CHF_WRS)) - ch9_eval_int (ch, CHINT_SEQC); - ch_flags[ch] &= ~CHF_EOR; - ch_req |= REQ_CH (ch); /* process in chan */ - break; - - case CH9_CPYD: /* data transfers */ - case CH9_CPYP: - if ((ch_flags[ch] & (CHF_PRD|CHF_PWR|CHF_RDS|CHF_WRS)) == 0) - ch9_eval_int (ch, CHINT_SEQC); /* not unless data */ - if (ch_flags[ch] & CHF_PRD) - ch_flags[ch] |= CHF_RDS; - else if (ch_flags[ch] & CHF_PWR) - ch_flags[ch] |= CHF_WRS; - ch_flags[ch] &= ~(CHF_EOR|CHF_PRD|CHF_PWR); - if ((ch_op[ch] == CH9_CPYP) && (ch_wc[ch] == 0)) - ch_req |= REQ_CH (ch); /* CPYP x,,0? */ - break; /* dev sets ch_req! */ - - case CH9_WTR: /* wait */ - ch_sta[ch] = CHXS_IDLE; /* stop */ - break; - - case CH9_TWT: /* trap and wait */ - ch_sta[ch] = CHXS_IDLE; /* stop */ - ch_flags[ch] |= CHF_TWT; /* set trap */ - break; - - default: - return STOP_ILLIOP; - } - -return SCPE_OK; -} - -/* 7909 external interface routines */ - -/* Input - store word, request channel input service */ - -t_stat ch9_req_rd (uint32 ch, t_uint64 val) -{ -if (ch < NUM_CHAN) { /* valid chan? */ - if (ch_idf[ch] & CH9DF_VLD) /* prev still valid? io chk */ - ch9_set_ioc (ch); - ch_idf[ch] = CH9DF_VLD; /* set ar valid */ - ch_req |= REQ_CH (ch); /* request chan */ - ch_ar[ch] = val & DMASK; /* save data */ - } -return SCPE_OK; -} - -/* Set attention */ - -void ch9_set_atn (uint32 ch) -{ -if (ch < NUM_CHAN) - ch9_eval_int (ch, CHINT_ATN1); -return; -} - -/* Set IO check - UEND will occur at end - not recognized in int mode */ - -void ch9_set_ioc (uint32 ch) -{ -if ((ch < NUM_CHAN) && !(ch_flags[ch] & CHF_INT)) { - ind_ioc = 1; /* IO check */ - ch_flags[ch] |= CHF_IOC; /* ch IOC for end */ - } -return; -} - -/* Set end */ - -void ch9_set_end (uint32 ch, uint32 iflags) -{ -if (ch < NUM_CHAN) { /* valid chan? */ - ch_flags[ch] |= CHF_EOR; - ch9_eval_int (ch, iflags); - } -return; -} - -/* Test connected */ - -t_bool ch9_qconn (uint32 ch) -{ -if ((ch < NUM_CHAN) && (ch_sta[ch] == CHXS_DSX)) - return TRUE; -return FALSE; -} - -/* Evaluate interrupts - - - Interrupt requests set flags in the channel flags word - - If an interrupt is not in progress, interrupt requests are evaluated - - If an interrupt request is found, the interruptable flags are - transferred to the channel condition register and cleared in - the channel flags - - This provides an effective stage of buffering for interrupt requests - that are not immediately serviced */ - -void ch9_eval_int (uint32 ch, uint32 iflags) -{ -uint32 ireq; - -ch_flags[ch] |= (iflags << CHF_V_COND); /* or into chan flags */ -if ((ch_flags[ch] & CHF_INT) == 0) { /* int not in prog? */ - ireq = ((ch_flags[ch] >> CHF_V_COND) & CHF_M_COND) & - ~(((ch_sms[ch] & CHSMS_IUEND)? CHINT_UEND: 0) | - ((ch_sms[ch] & CHSMS_IATN1)? CHINT_ATN1: 0) | - ((ch_sms[ch] & CHSMS_IATN2)? CHINT_ATN2: 0) | - ((ch_flags[ch] & (CHF_PRD|CHF_PWR|CHF_RDS|CHF_WRS))? CHINT_SEQC: 0)); - if (ireq) { /* int pending? */ - ch_cnd[ch] = ireq; /* set cond reg */ - ch_flags[ch] &= ~(ireq << CHF_V_COND); /* clear chan flags */ - ch_flags[ch] |= CHF_IRQ; /* set int req */ - ch_req |= REQ_CH (ch); /* request channel */ - } - } -return; -} - -/* Test for all channels idle */ - -t_bool ch_qidle (void) -{ -uint32 i; - -for (i = 0; i < NUM_CHAN; i++) { - if (ch_sta[i] != CHXS_IDLE) - return FALSE; - } -return TRUE; -} - -/* Evaluate/execute channel traps */ - -uint32 chtr_eval (uint32 *decr) -{ -uint32 i, cme; - -if (!chtr_inht && !chtr_inhi && chtr_enab) { - if (BIT_TST (chtr_enab, CHTR_V_CLK) && chtr_clk) { /* clock trap? */ - if (decr) { /* exec? */ - chtr_clk = 0; /* clr flag */ - *decr = 0; - } - return CHTR_CLK_SAV; - } - for (i = 0; i < NUM_CHAN; i++) { /* loop thru chan */ - cme = BIT_TST (chtr_enab, CHTR_V_CME + i); /* cmd/eof enab? */ - if (cme && (ch_flags[i] & CHF_CMD)) { /* cmd enab and set? */ - if (decr) { /* exec? */ - ch_flags[i] &= ~CHF_CMD; /* clr flag */ - *decr = CHTR_F_CMD; - } - return (CHTR_CHA_SAV + (i << 1)); - } - if (cme && (ch_flags[i] & CHF_EOF)) { /* eof enab and set? */ - if (decr) { /* exec? */ - ch_flags[i] &= ~CHF_EOF; /* clr flag */ - *decr = CHTR_F_EOF; - } - return (CHTR_CHA_SAV + (i << 1)); - } - if (BIT_TST (chtr_enab, CHTR_V_TRC + i) && /* trc enab? */ - (ch_flags[i] & CHF_TRC)) { /* trc flag? */ - if (decr) { /* exec? */ - ch_flags[i] &= ~CHF_TRC; /* clr flag */ - *decr = CHTR_F_TRC; - } - return (CHTR_CHA_SAV + (i << 1)); - } /* end if BIT_TST */ - } /* end for */ - } /* end if !chtr_inht */ -if (decr) - *decr = 0; -return 0; -} - -/* Channel reset */ - -t_stat ch_reset (DEVICE *dptr) -{ -uint32 ch = dptr - &ch_dev[0]; /* get channel */ - -if (ch == CH_A) /* channel A fixed */ - ch2dev[ch] = &mt_dev[0]; -ch_sta[ch] = 0; -ch_flags[ch] = 0; -ch_idf[ch] = 0; -ch_dso[ch] = 0; -ch_dsu[ch] = 0; -ch_ndso[ch] = 0; -ch_ndsu[ch] = 0; -ch_op[ch] = 0; -ch_clc[ch] = 0; -ch_wc[ch] = 0; -ch_ca[ch] = 0; -ch_ar[ch] = 0; -ch_sms[ch] = 0; -ch_cnd[ch] = 0; -ch_lcc[ch] = 0; -sim_cancel (&ch_unit[ch]); -return SCPE_OK; -} - -/* Show channel type */ - -t_stat ch_show_type (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -DEVICE *dptr; - -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; -if (dptr->flags & DEV_7909) - fputs ("7909", st); -else if (dptr->flags & DEV_7289) - fputs ("7289", st); -else fputs ("7607", st); -return SCPE_OK; -} - -/* Enable channel, assign device */ - -t_stat ch_set_enable (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -DEVICE *dptr, *dptr1; -char gbuf[CBUFSIZE]; -uint32 i, ch; - -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; -ch = dptr - &ch_dev[0]; -if ((ch == 0) || !(dptr->flags & DEV_DIS)) - return SCPE_ARG; -if (cptr == NULL) - cptr = "TAPE"; -get_glyph (cptr, gbuf, 0); -for (i = 0; dev_table[i].name; i++) { - if (strcmp (dev_table[i].name, gbuf) == 0) { - dptr1 = ch_map_flags (ch, dev_table[i].flags); - if (!dptr1 || !(dptr1->flags & DEV_DIS)) - return SCPE_ARG; - dptr->flags &= ~(DEV_DIS|DEV_7909|DEV_7289|DEV_7750|DEV_7631); - dptr->flags |= dev_table[i].flags; - dptr1->flags &= ~DEV_DIS; - ch2dev[ch] = dptr1; - return reset_all (0); - } - } -return SCPE_ARG; -} - -/* Map device flags to device pointer */ - -DEVICE *ch_map_flags (uint32 ch, int32 fl) -{ -if (fl & DEV_7289) - return &drm_dev; -if (!(fl & DEV_7909)) - return &mt_dev[ch]; -if (fl & DEV_7631) - return &dsk_dev; -if (fl & DEV_7750) - return &com_dev; -return NULL; -} - -/* Set up channel map */ - -void ch_set_map (void) -{ -uint32 i; - -for (i = 0; i < NUM_CHAN; i++) { - if (ch_dev[i].flags & DEV_DIS) - ch2dev[i] = NULL; - else ch2dev[i] = ch_map_flags (i, ch_dev[i].flags); - } -return; -} - -/* Disable channel, deassign device */ - -t_stat ch_set_disable (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -DEVICE *dptr, *dptr1; -UNIT *uptr1; -uint32 i, ch; - -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; -ch = dptr - &ch_dev[0]; -if ((ch == 0) || (dptr->flags & DEV_DIS) || (cptr != NULL)) - return SCPE_ARG; -dptr1 = ch2dev[ch]; -if (dptr1 == NULL) - return SCPE_IERR; -if (dptr1->units) { - for (i = 0; i < dptr1->numunits; i++) { - uptr1 = dptr1->units + i; - if (dptr1->detach) - dptr1->detach (uptr1); - else detach_unit (uptr1); - } - } -dptr->flags &= ~(DEV_7909|DEV_7289); -dptr->flags |= DEV_DIS; -dptr1->flags |= DEV_DIS; -return reset_all (0); -} - -/* Show channel that device is on (tapes, 7289, 7909 only) */ - -t_stat ch_show_chan (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -DEVICE *dptr; -uint32 i; - -dptr = find_dev_from_unit (uptr); -if (dptr) { - for (i = 0; i < NUM_CHAN; i++) { - if (ch2dev[i] == dptr) { - fprintf (st, "channel %c", 'A' + i); - return SCPE_OK; - } - } - } -fprintf (st, "not assigned to channel"); -return SCPE_OK; -} diff --git a/I7094/i7094_lp.c b/I7094/i7094_lp.c deleted file mode 100644 index 0a306b24..00000000 --- a/I7094/i7094_lp.c +++ /dev/null @@ -1,378 +0,0 @@ -/* i7094_lp.c: IBM 716 line printer simulator - - Copyright (c) 2003-2017, 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 716 line printer - - 13-Mar-17 RMS Fixed GET_PCHAIN macro (COVERITY) - 19-Jan-07 RMS Added UNIT_TEXT flag - - Internally, the 7094 works only with column binary and is limited to - 72 columns of data. Each row of the printed line is represented by - 72b of data (two 36b words). A complete print line consists of 12 rows - (24 36b words). - - The printer can also echo part of what it prints, namely, the digit rows - plus the 8+3 and 8+4 combinations. This was intended for verification of - check printing. Echoed data is interspersed with output data in the - following order: - - output row 9 to row 1 - echo row "8+4" - output row 0 - echo row "8+3" - output row 11 - echo row 9 - output row 12 - echo row 8 to row 1 -*/ - -#include "i7094_defs.h" - -#define UNIT_V_CONS (UNIT_V_UF + 0) /* print to console */ -#define UNIT_CONS (1u << UNIT_V_CONS) -#define UNIT_V_BZ (UNIT_V_UF + 1) -#define UNIT_V_48 (UNIT_V_UF + 2) -#define UNIT_BZ (1 << UNIT_V_BZ) -#define UNIT_48 (1 << UNIT_V_48) -#define GET_PCHAIN(x) (((x) >> UNIT_V_BZ) & 03) - -#define LPT_BINLNT 24 /* bin buffer length */ -#define LPT_ECHLNT 22 /* echo buffer length */ -#define LPT_CHRLNT 80 /* char buffer length */ - -#define LPS_INIT 0 /* init state */ -#define LPS_DATA 1 /* print data state */ -#define ECS_DATA 2 /* echo data state */ -#define LPS_END 3 /* end state */ - -#define LPB_9ROW 0 /* bin buf: 9 row */ -#define LPB_8ROW 2 /* 8 row */ -#define LPB_4ROW 10 /* 4 row */ -#define LPB_3ROW 12 /* 3 row */ -#define LPB_1ROW 16 /* 1 row */ -#define LPB_12ROW 22 /* 12 row */ - -#define ECB_84ROW 0 /* echo buf: 8-4 row */ -#define ECB_83ROW 2 /* 8-3 row */ -#define ECB_9ROW 4 /* 9 row */ - -#define ECHO_F 0100 /* echo map: flag */ -#define ECHO_MASK 0037 /* mask */ - -#define CMD_BIN 1 /* cmd: bcd/bin */ -#define CMD_ECHO 2 /* cmd: wrs/rds */ - -uint32 lpt_sta = 0; /* state */ -uint32 lpt_bptr = 0; /* buffer ptr */ -uint32 lpt_cmd = 0; /* modes */ -uint32 lpt_tstart = 27500; /* timing */ -uint32 lpt_tstop = 27500; -uint32 lpt_tleft = 150; -uint32 lpt_tright = 4000; -t_uint64 lpt_chob = 0; -uint32 lpt_chob_v = 0; -t_uint64 lpt_bbuf[LPT_BINLNT]; /* binary buffer */ -t_uint64 lpt_ebuf[LPT_ECHLNT]; /* echo buffer */ - -/* Echo ordering map */ - -static const uint8 echo_map[LPT_BINLNT + LPT_ECHLNT] = { - 0, 1, 2, 3, 4, 5, 6, 7, /* write 9 to 1 */ - 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, - 0+ECHO_F, 1+ECHO_F, /* echo 8+4 */ - 18, 19, /* write 0 */ - 2+ECHO_F, 3+ECHO_F, /* echo 8+3 */ - 20, 21, /* write 11 */ - 4+ECHO_F, 5+ECHO_F, /* echo 9 */ - 22, 23, /* write 12 */ - 6+ECHO_F, 7+ECHO_F, 8+ECHO_F, 9+ECHO_F, /* echo 8 to 1 */ - 10+ECHO_F, 11+ECHO_F, 12+ECHO_F, 13+ECHO_F, - 14+ECHO_F, 15+ECHO_F, 16+ECHO_F, 17+ECHO_F, - 18+ECHO_F, 19+ECHO_F, 20+ECHO_F, 21+ECHO_F - }; - -extern uint32 ind_ioc; -extern t_uint64 bit_masks[36]; -extern uint32 col_masks[12]; -extern char bcd_to_ascii_a[64]; -extern char bcd_to_ascii_h[64]; -extern char bcd_to_pca[64]; -extern char bcd_to_pch[64]; - -char *pch_table[4] = { - bcd_to_ascii_h, bcd_to_ascii_a, bcd_to_pch, bcd_to_pca, - }; - -t_stat lpt_reset (DEVICE *dptr); -t_stat lpt_svc (UNIT *uptr); -t_stat lpt_chsel (uint32 ch, uint32 sel, uint32 unit); -t_stat lpt_chwr (uint32 ch, t_uint64 val, uint32 flags); -t_stat lpt_end_line (UNIT *uptr); - -extern char colbin_to_bcd (uint32 colbin); - -/* LPT data structures - - lpt_dev LPT device descriptor - lpt_unit LPT unit descriptor - lpt_reg LPT register list -*/ - -DIB lpt_dib = { &lpt_chsel, &lpt_chwr }; - -UNIT lpt_unit = { - UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_CONS+UNIT_TEXT, 0) - }; - -REG lpt_reg[] = { - { ORDATA (STATE, lpt_sta, 2) }, - { ORDATA (CMD, lpt_cmd, 2) }, - { ORDATA (CHOB, lpt_chob, 36) }, - { FLDATA (CHOBV, lpt_chob_v, 0) }, - { DRDATA (BPTR, lpt_bptr, 6), PV_LEFT }, - { BRDATA (BUF, lpt_bbuf, 8, 36, LPT_BINLNT) }, - { BRDATA (EBUF, lpt_ebuf, 8, 36, LPT_ECHLNT) }, - { DRDATA (POS, lpt_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TSTART, lpt_tstart, 24), PV_LEFT + REG_NZ }, - { DRDATA (TSTOP, lpt_tstop, 24), PV_LEFT + REG_NZ }, - { DRDATA (TLEFT, lpt_tleft, 24), PV_LEFT + REG_NZ }, - { DRDATA (TRIGHT, lpt_tright, 24), PV_LEFT + REG_NZ }, - { NULL } - }; - -MTAB lpt_mod[] = { - { UNIT_CONS, UNIT_CONS, "default to console", "DEFAULT" }, - { UNIT_CONS, 0 , "no default device", "NODEFAULT" }, - { UNIT_48, UNIT_48, "48 character chain", "48" }, - { UNIT_48, 0, "64 character chain", "64" }, - { UNIT_BZ, UNIT_BZ, "business set", "BUSINESS" }, - { UNIT_BZ, 0, "Fortran set", "FORTRAN" }, - { 0 } - }; - -DEVICE lpt_dev = { - "LPT", &lpt_unit, lpt_reg, lpt_mod, - 1, 10, 31, 1, 8, 7, - NULL, NULL, &lpt_reset, - NULL, NULL, NULL, - &lpt_dib, DEV_DISABLE - }; - -/* Channel select routine */ - -t_stat lpt_chsel (uint32 ch, uint32 sel, uint32 unit) -{ -if (sel & CHSL_NDS) /* nds? nop */ - return ch6_end_nds (ch); - -switch (sel) { /* case on cmd */ - - case CHSL_RDS: /* read */ - case CHSL_WRS: /* write */ - if (!(lpt_unit.flags & (UNIT_ATT|UNIT_CONS))) /* not attached? */ - return SCPE_UNATT; - if (sim_is_active (&lpt_unit)) /* busy? */ - return ERR_STALL; - lpt_cmd = ((unit & 02)? CMD_BIN: 0) | /* save modes */ - ((sel == CHSL_RDS)? CMD_ECHO: 0); - lpt_sta = LPS_INIT; /* initial state */ - sim_activate (&lpt_unit, lpt_tstart); /* start reader */ - break; - - default: /* other */ - return STOP_ILLIOP; - } - -return SCPE_OK; -} - -/* Channel write routine - - - Normal mode is processed here - - Echo mode is processed in the service routine (like a read) */ - -t_stat lpt_chwr (uint32 ch, t_uint64 val, uint32 eorfl) -{ -uint32 u = (lpt_cmd & CMD_BIN)? U_LPBIN: U_LPBCD; /* reconstruct unit */ - -lpt_chob = val & DMASK; /* store data */ -lpt_chob_v = 1; /* set valid */ -if (lpt_sta == ECS_DATA) - return SCPE_OK; -if (lpt_sta == LPS_DATA) { - lpt_bbuf[lpt_bptr++] = lpt_chob; /* store data */ - if (eorfl || /* end record, or */ - ((lpt_cmd & CMD_BIN)? /* last word in buffer? */ - (lpt_bptr > (LPB_1ROW + 1)): /* (binary mode) */ - (lpt_bptr > (LPB_12ROW + 1)))) { /* (normal mode) */ - ch6_set_flags (CH_A, u, CHF_EOR); /* set eor */ - return lpt_end_line (&lpt_unit); - } - return SCPE_OK; - } -return SCPE_IERR; -} - -/* Unit timeout */ - -t_stat lpt_svc (UNIT *uptr) -{ -uint32 u = (lpt_cmd & CMD_BIN)? U_LPBIN: U_LPBCD; /* reconstruct unit */ -uint32 i, map; - -switch (lpt_sta) { /* case on state */ - - case LPS_INIT: /* initial state */ - for (i = 0; i < LPT_BINLNT; i++) /* clear data buffer */ - lpt_bbuf[i] = 0; - for (i = 0; i < LPT_ECHLNT; i++) /* clear echo buffer */ - lpt_ebuf[i] = 0; - if (lpt_cmd & CMD_BIN) /* set buffer ptr */ - lpt_bptr = LPB_1ROW; - else lpt_bptr = LPB_9ROW; - if (lpt_cmd & CMD_ECHO) /* set data state */ - lpt_sta = ECS_DATA; - else lpt_sta = LPS_DATA; - ch6_req_wr (CH_A, u); /* request channel */ - lpt_chob = 0; /* clr, inval buffer */ - lpt_chob_v = 0; - sim_activate (uptr, lpt_tleft); /* go again */ - break; - - case LPS_DATA: /* print data state */ - if (!ch6_qconn (CH_A, u)) /* disconnect? */ - return lpt_end_line (uptr); /* line is done */ - if (lpt_chob_v) /* valid? clear */ - lpt_chob_v = 0; - else ind_ioc = 1; /* no, io check */ - ch6_req_wr (CH_A, u); /* request chan again */ - sim_activate (uptr, (lpt_bptr & 1)? lpt_tleft: lpt_tright); - break; - - case ECS_DATA: /* echo data state */ - map = echo_map[lpt_bptr++]; /* map column */ - if (map == ECHO_F) { /* first echo? */ - lpt_ebuf[ECB_84ROW] = lpt_bbuf[LPB_8ROW] & lpt_bbuf[LPB_4ROW]; - lpt_ebuf[ECB_84ROW + 1] = lpt_bbuf[LPB_8ROW + 1] & lpt_bbuf[LPB_4ROW + 1]; - lpt_ebuf[ECB_83ROW] = lpt_bbuf[LPB_8ROW] & lpt_bbuf[LPB_3ROW]; - lpt_ebuf[ECB_83ROW + 1] = lpt_bbuf[LPB_8ROW + 1] & lpt_bbuf[LPB_3ROW + 1]; - for (i = 0; i < 18; i++) /* copy rows 9.. 1 */ - lpt_ebuf[ECB_9ROW + i] = lpt_bbuf[LPB_9ROW + i]; - } - if (map & ECHO_F) { /* echo cycle */ - ch6_req_rd (CH_A, u, lpt_ebuf[map & ECHO_MASK], 0); - if (lpt_bptr >= (LPT_BINLNT + LPT_ECHLNT)) - return lpt_end_line (uptr); /* done? */ - sim_activate (uptr, lpt_tleft); /* short timer */ - } - else { /* print cycle */ - if (lpt_chob_v) /* valid? clear */ - lpt_chob_v = 0; - else ind_ioc = 1; /* no, io check */ - lpt_bbuf[map] = lpt_chob; /* store in buffer */ - sim_activate (uptr, (lpt_bptr & 1)? lpt_tleft: lpt_tright); - } - if (!(echo_map[lpt_bptr] & ECHO_F)) /* print word next? */ - ch6_req_wr (CH_A, u); /* req channel */ - break; - - case LPS_END: /* end state */ - if (ch6_qconn (CH_A, u)) { /* lpt still conn? */ - lpt_sta = LPS_INIT; /* initial state */ - sim_activate (uptr, 1); /* next line */ - } - break; - } - -return SCPE_OK; -} - -/* End line routine */ - -t_stat lpt_end_line (UNIT *uptr) -{ -uint32 i, col, row, bufw, colbin; -char *pch, bcd, lpt_cbuf[LPT_CHRLNT + 1]; -t_uint64 dat; - -pch = pch_table[GET_PCHAIN (lpt_unit.flags)]; /* get print chain */ -for (col = 0; col < (LPT_CHRLNT + 1); col++) /* clear ascii buf */ - lpt_cbuf[col] = ' '; -for (col = 0; col < 72; col++) { /* proc 72 columns */ - colbin = 0; - dat = bit_masks[35 - (col % 36)]; /* mask for column */ - for (row = 0; row < 12; row++) { /* proc 12 rows */ - bufw = (row * 2) + (col / 36); /* index to buffer */ - if (lpt_bbuf[bufw] & dat) - colbin |= col_masks[row]; - } - bcd = colbin_to_bcd (colbin); /* column bin -> BCD */ - lpt_cbuf[col] = pch[bcd]; /* -> ASCII */ - } -for (i = LPT_CHRLNT; (i > 0) && - (lpt_cbuf[i - 1] == ' '); --i) ; /* trim spaces */ -lpt_cbuf[i] = 0; /* append nul */ -if (uptr->flags & UNIT_ATT) { /* file? */ - fputs (lpt_cbuf, uptr->fileref); /* write line */ - fputc ('\n', uptr->fileref); /* append nl */ - uptr->pos = ftell (uptr->fileref); /* update position */ - if (ferror (uptr->fileref)) { /* error? */ - perror ("LPT I/O error"); - clearerr (uptr->fileref); - return SCPE_IOERR; - } - } -else if (uptr->flags & UNIT_CONS) { /* print to console? */ - for (i = 0; lpt_cbuf[i] != 0; i++) - sim_putchar (lpt_cbuf[i]); - sim_putchar ('\r'); - sim_putchar ('\n'); - } -else return SCPE_UNATT; /* otherwise error */ -lpt_sta = LPS_END; /* end line state */ -sim_cancel (uptr); /* cancel current */ -sim_activate (uptr, lpt_tstop); /* long timer */ -return SCPE_OK; -} - -/* Reset routine */ - -t_stat lpt_reset (DEVICE *dptr) -{ -uint32 i; - -for (i = 0; i < LPT_BINLNT; i++) /* clear bin buf */ - lpt_bbuf[i] = 0; -for (i = 0; i < LPT_ECHLNT; i++) /* clear echo buf */ - lpt_ebuf[i] = 0; -lpt_sta = 0; /* clear state */ -lpt_cmd = 0; /* clear modes */ -lpt_bptr = 0; /* clear buf ptr */ -lpt_chob = 0; -lpt_chob_v = 0; -sim_cancel (&lpt_unit); /* stop printer */ -return SCPE_OK; -} diff --git a/I7094/i7094_mt.c b/I7094/i7094_mt.c deleted file mode 100644 index 4c9731af..00000000 --- a/I7094/i7094_mt.c +++ /dev/null @@ -1,865 +0,0 @@ -/* i7094_mt.c: IBM 7094 magnetic tape simulator - - Copyright (c) 2003-2012, 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. - - mt magtape simulator - - 19-Mar-12 RMS Fixed declaration of sel_name (Mark Pizzolato) - 16-Jul-10 RMS Fixed handling of BSR, BSF (Dave Pitts) -*/ - -#include "i7094_defs.h" -#include "sim_tape.h" - -#define UST u3 /* unit state */ -#define UCH u4 /* channel number */ -#define MTUF_V_LDN (MTUF_V_UF + 0) -#define MTUF_LDN (1 << MTUF_V_LDN) -#define MT_MAXFR ((1 << 18) + 2) - -#define QCHRONO(c,u) ((cpu_model & I_CT) && \ - ((c) == CHRONO_CH) && ((u) == CHRONO_UNIT)) - -uint8 *mtxb[NUM_CHAN] = { NULL }; /* xfer buffer */ -uint32 mt_unit[NUM_CHAN]; /* unit */ -uint32 mt_bptr[NUM_CHAN]; -uint32 mt_blnt[NUM_CHAN]; -t_uint64 mt_chob[NUM_CHAN]; -uint32 mt_chob_v[NUM_CHAN]; -uint32 mt_tshort = 2; /* "a few microseconds" */ -uint32 mt_twef = 25000; /* 50 msec */ -uint32 mt_tstart = 29000; /* 58 msec */ -uint32 mt_tstop = 10000; /* 20 msec */ -uint32 mt_tword = 50; /* 125 usec */ - -static const uint8 odd_par[64] = { - 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, - 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1, - 1, 0, 0, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 1, 1, 0, - 0, 1, 1, 0, 1, 0, 0, 1 - }; - -static const char *tape_stat[] = { - "OK", "TMK", "UNATT", "IOERR", "INVRECLNT", - "FMT", "BOT", "EOM", "RECERR", "WRPROT" - }; - -extern uint32 PC; -extern uint32 cpu_model; -extern uint32 ind_ioc; -extern const char *sel_name[]; - -t_stat mt_chsel (uint32 ch, uint32 sel, uint32 unit); -t_stat mt_chwr (uint32 ch, t_uint64 val, uint32 flags); -t_stat mt_rec_end (UNIT *uptr); -t_stat mt_svc (UNIT *uptr); -t_stat mt_reset (DEVICE *dptr); -t_stat mt_attach (UNIT *uptr, char *cptr); -t_stat mt_boot (int32 unitno, DEVICE *dptr); -t_stat mt_map_err (UNIT *uptr, t_stat st); - -extern uint32 chrono_rd (uint8 *buf, uint32 bufsiz); - -/* MT data structures - - mt_dev MT device descriptor - mt_unit MT unit list - mt_reg MT register list - mt_mod MT modifier list -*/ - -DIB mt_dib = { &mt_chsel, &mt_chwr }; - -MTAB mt_mod[] = { - { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, - { MTUF_LDN, 0, "high density", "HIGH", NULL }, - { MTUF_LDN, MTUF_LDN, "low density", "LOW", NULL }, - { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT", - &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, - { 0 } - }; - -UNIT mta_unit[] = { - { UDATA (NULL, UNIT_DIS, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) } - }; - -REG mta_reg[] = { - { ORDATA (UNIT, mt_unit[0], 5) }, - { ORDATA (CHOB, mt_chob[0], 36) }, - { FLDATA (CHOBV, mt_chob_v[0], 0) }, - { DRDATA (BPTR, mt_bptr[0], 16), PV_LEFT }, - { DRDATA (BLNT, mt_blnt[0], 16), PV_LEFT }, - { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) }, - { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT }, - { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT }, - { URDATA (UST, mta_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) }, - { URDATA (POS, mta_unit[0].pos, 10, T_ADDR_W, 0, - MT_NUMDR + 1, PV_LEFT | REG_RO) }, - { NULL } - }; - -UNIT mtb_unit[] = { - { UDATA (NULL, UNIT_DIS, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) } - }; - -REG mtb_reg[] = { - { ORDATA (UNIT, mt_unit[1], 5) }, - { ORDATA (CHOB, mt_chob[1], 36) }, - { FLDATA (CHOBV, mt_chob_v[1], 0) }, - { DRDATA (BPTR, mt_bptr[1], 16), PV_LEFT }, - { DRDATA (BLNT, mt_blnt[1], 16), PV_LEFT }, - { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) }, - { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT }, - { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT }, - { URDATA (UST, mtb_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) }, - { URDATA (POS, mtb_unit[0].pos, 10, T_ADDR_W, 0, - MT_NUMDR + 1, PV_LEFT | REG_RO) }, - { NULL } - }; - -UNIT mtc_unit[] = { - { UDATA (NULL, UNIT_DIS, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) } - }; - -REG mtc_reg[] = { - { ORDATA (UNIT, mt_unit[2], 5) }, - { ORDATA (CHOB, mt_chob[2], 36) }, - { FLDATA (CHOBV, mt_chob_v[2], 0) }, - { DRDATA (BPTR, mt_bptr[2], 16), PV_LEFT }, - { DRDATA (BLNT, mt_blnt[2], 16), PV_LEFT }, - { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) }, - { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT }, - { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT }, - { URDATA (UST, mtc_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) }, - { URDATA (POS, mtc_unit[0].pos, 10, T_ADDR_W, 0, - MT_NUMDR + 1, PV_LEFT | REG_RO) }, - { NULL } - }; - -UNIT mtd_unit[] = { - { UDATA (NULL, UNIT_DIS, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) } - }; - -REG mtd_reg[] = { - { ORDATA (UNIT, mt_unit[3], 5) }, - { ORDATA (CHOB, mt_chob[3], 36) }, - { FLDATA (CHOBV, mt_chob_v[3], 0) }, - { DRDATA (BPTR, mt_bptr[3], 16), PV_LEFT }, - { DRDATA (BLNT, mt_blnt[3], 16), PV_LEFT }, - { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) }, - { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT }, - { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT }, - { URDATA (UST, mtd_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) }, - { URDATA (POS, mtd_unit[0].pos, 10, T_ADDR_W, 0, - MT_NUMDR + 1, PV_LEFT | REG_RO) }, - { NULL } - }; - -UNIT mte_unit[] = { - { UDATA (NULL, UNIT_DIS, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) } - }; - -REG mte_reg[] = { - { ORDATA (UNIT, mt_unit[4], 5) }, - { ORDATA (CHOB, mt_chob[4], 36) }, - { FLDATA (CHOBV, mt_chob_v[4], 0) }, - { DRDATA (BPTR, mt_bptr[4], 16), PV_LEFT }, - { DRDATA (BLNT, mt_blnt[4], 16), PV_LEFT }, - { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) }, - { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT }, - { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT }, - { URDATA (UST, mte_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) }, - { URDATA (POS, mte_unit[0].pos, 10, T_ADDR_W, 0, - MT_NUMDR + 1, PV_LEFT | REG_RO) }, - { NULL } - }; - -UNIT mtf_unit[] = { - { UDATA (NULL, UNIT_DIS, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) } - }; - -REG mtf_reg[] = { - { ORDATA (UNIT, mt_unit[5], 5) }, - { ORDATA (CHOB, mt_chob[5], 36) }, - { FLDATA (CHOBV, mt_chob_v[5], 0) }, - { DRDATA (BPTR, mt_bptr[5], 16), PV_LEFT }, - { DRDATA (BLNT, mt_blnt[5], 16), PV_LEFT }, - { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) }, - { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT }, - { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT }, - { URDATA (UST, mtf_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) }, - { URDATA (POS, mtf_unit[0].pos, 10, T_ADDR_W, 0, - MT_NUMDR + 1, PV_LEFT | REG_RO) }, - { NULL } - }; - -UNIT mtg_unit[] = { - { UDATA (NULL, UNIT_DIS, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) } - }; - -REG mtg_reg[] = { - { ORDATA (UNIT, mt_unit[6], 5) }, - { ORDATA (CHOB, mt_chob[6], 36) }, - { FLDATA (CHOBV, mt_chob_v[6], 0) }, - { DRDATA (BPTR, mt_bptr[6], 16), PV_LEFT }, - { DRDATA (BLNT, mt_blnt[6], 16), PV_LEFT }, - { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) }, - { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT }, - { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT }, - { URDATA (UST, mtg_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) }, - { URDATA (POS, mtg_unit[0].pos, 10, T_ADDR_W, 0, - MT_NUMDR + 1, PV_LEFT | REG_RO) }, - { NULL } - }; - -UNIT mth_unit[] = { - { UDATA (NULL, UNIT_DIS, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE+UNIT_ROABLE+UNIT_DISABLE, 0) } - }; - -REG mth_reg[] = { - { ORDATA (UNIT, mt_unit[7], 5) }, - { ORDATA (CHOB, mt_chob[7], 36) }, - { FLDATA (CHOBV, mt_chob_v[7], 0) }, - { DRDATA (BPTR, mt_bptr[7], 16), PV_LEFT }, - { DRDATA (BLNT, mt_blnt[7], 16), PV_LEFT }, - { BRDATA (BUF, NULL, 8, 7, MT_MAXFR) }, - { DRDATA (TWEF, mt_twef, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSHORT, mt_tshort, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTART, mt_tstart, 24), REG_NZ + PV_LEFT }, - { DRDATA (TSTOP, mt_tstop, 24), REG_NZ + PV_LEFT }, - { DRDATA (TWORD, mt_tword, 24), REG_NZ + PV_LEFT }, - { URDATA (UST, mth_unit[0].UST, 8, 5, 0, MT_NUMDR + 1, 0) }, - { URDATA (POS, mth_unit[0].pos, 10, T_ADDR_W, 0, - MT_NUMDR + 1, PV_LEFT | REG_RO) }, - { NULL } - }; - -DEVICE mt_dev[NUM_CHAN] = { - { - "MTA", mta_unit, mta_reg, mt_mod, - MT_NUMDR + 1, 10, 31, 1, 8, 8, - NULL, NULL, &mt_reset, - &mt_boot, &mt_attach, &sim_tape_detach, - &mt_dib, DEV_DEBUG | DEV_TAPE - }, - { - "MTB", mtb_unit, mtb_reg, mt_mod, - MT_NUMDR + 1, 10, 31, 1, 8, 8, - NULL, NULL, &mt_reset, - NULL, &mt_attach, &sim_tape_detach, - &mt_dib, DEV_DIS|DEV_DEBUG - }, - { - "MTC", mtc_unit, mtc_reg, mt_mod, - MT_NUMDR + 1, 10, 31, 1, 8, 8, - NULL, NULL, &mt_reset, - NULL, &mt_attach, &sim_tape_detach, - &mt_dib, DEV_DIS|DEV_DEBUG - }, - { - "MTD", mtd_unit, mtd_reg, mt_mod, - MT_NUMDR + 1, 10, 31, 1, 8, 8, - NULL, NULL, &mt_reset, - NULL, &mt_attach, &sim_tape_detach, - &mt_dib, DEV_DIS|DEV_DEBUG - }, - { - "MTE", mte_unit, mte_reg, mt_mod, - MT_NUMDR + 1, 10, 31, 1, 8, 8, - NULL, NULL, &mt_reset, - NULL, &mt_attach, &sim_tape_detach, - &mt_dib, DEV_DIS|DEV_DEBUG - }, - { - "MTF", mtf_unit, mtf_reg, mt_mod, - MT_NUMDR + 1, 10, 31, 1, 8, 8, - NULL, NULL, &mt_reset, - NULL, &mt_attach, &sim_tape_detach, - &mt_dib, DEV_DIS|DEV_DEBUG - }, - { - "MTG", mtg_unit, mtg_reg, mt_mod, - MT_NUMDR + 1, 10, 31, 1, 8, 8, - NULL, NULL, &mt_reset, - NULL, &mt_attach, &sim_tape_detach, - &mt_dib, DEV_DIS|DEV_DEBUG - }, - { - "MTH", mth_unit, mth_reg, mt_mod, - MT_NUMDR + 1, 10, 31, 1, 8, 8, - NULL, NULL, &mt_reset, - NULL, &mt_attach, &sim_tape_detach, - &mt_dib, DEV_DIS|DEV_DEBUG - } - }; - -/* Select controller - - Inputs: - ch = channel - cmd = select command - unit = unit - Outputs: - status = SCPE_OK if ok - STOP_STALL if busy - error code if error -*/ - -static const int mt_must_att[CHSL_NUM] = { - 0, 1, 1, 0, 1, 1, 0, 0, - 1, 1, 1, 1, 1, 1, 0, 0 - }; - -static const int mt_will_wrt[CHSL_NUM] = { - 0, 0, 1, 0, 0, 1, 0, 0, - 1, 1, 0, 0, 0, 0, 0, 0 - }; - -t_stat mt_chsel (uint32 ch, uint32 cmd, uint32 unit) -{ -UNIT *uptr; -uint32 u = unit & 017; - -if ((ch >= NUM_CHAN) || (cmd == 0) || (cmd >= CHSL_NUM)) - return SCPE_IERR; /* invalid arg? */ -if (mt_dev[ch].flags & DEV_DIS) /* disabled? */ - return STOP_NXDEV; -if ((u == 0) || (u > MT_NUMDR)) /* valid unit? */ - return STOP_NXDEV; -uptr = mt_dev[ch].units + u; /* get unit ptr */ -if (uptr->flags & UNIT_DIS) /* disabled? */ - return STOP_NXDEV; -if (mt_unit[ch] || sim_is_active (uptr)) /* ctrl or unit busy? */ - return ERR_STALL; /* stall */ -if (QCHRONO (ch, u)) { /* Chronolog clock? */ - if (cmd != CHSL_RDS) /* only reads */ - return STOP_ILLIOP; - sim_activate (uptr, mt_tword); /* responds quickly */ - } -else { /* real tape */ - if (!(uptr->flags & UNIT_ATT) && mt_must_att[cmd]) /* unit unatt? */ - return SCPE_UNATT; - if (sim_tape_wrp (uptr) && mt_will_wrt[cmd]) /* unit wrp && write? */ - return STOP_WRP; - if (DEBUG_PRS (mt_dev[ch])) - fprintf (sim_deb, ">>%s%d %s, pos = %d\n", - mt_dev[ch].name, u, sel_name[cmd], uptr->pos); - - switch (cmd) { /* case on cmd */ - - case CHSL_RDS: - case CHSL_WRS: - sim_activate (uptr, mt_tstart); /* schedule op */ - break; - - case CHSL_WEF: /* write eof? */ - sim_activate (uptr, mt_twef); /* schedule op */ - break; - - case CHSL_BSR: - case CHSL_BSF: /* backspace */ - case CHSL_REW: - case CHSL_RUN: - case CHSL_SDN: /* rew, rew/unl, set det */ - sim_activate (uptr, mt_tshort); /* schedule quick event */ - break; - - default: - return SCPE_IERR; - } /* end switch */ - } /* end else */ - -uptr->UST = cmd; /* set cmd */ -mt_unit[ch] = unit & 0777; /* save unit */ -return SCPE_OK; -} - -/* Channel write routine */ - -t_stat mt_chwr (uint32 ch, t_uint64 val, uint32 eorfl) -{ -int32 k, u; -uint8 by, *xb; -UNIT *uptr; - -if (ch >= NUM_CHAN) /* invalid chan? */ - return SCPE_IERR; -xb = mtxb[ch]; /* get xfer buf */ -u = mt_unit[ch] & 017; -if ((xb == NULL) || (u > MT_NUMDR)) /* invalid args? */ - return SCPE_IERR; -uptr = mt_dev[ch].units + u; /* get unit */ -mt_chob[ch] = val & DMASK; /* save word from chan */ -mt_chob_v[ch] = 1; /* set valid */ - -if (uptr->UST == (CHSL_WRS|CHSL_2ND)) { /* data write? */ - for (k = 30; /* proc 6 bytes */ - (k >= 0) && (mt_bptr[ch] < MT_MAXFR); - k = k - 6) { - by = (uint8) ((val >> k) & 077); /* get byte */ - if ((mt_unit[ch] & 020) == 0) { /* BCD? */ - if (by == 0) /* cvt bin 0 */ - by = BCD_ZERO; - else if (by & 020) /* invert zones */ - by = by ^ 040; - if (!odd_par[by]) /* even parity */ - by = by | 0100; - } - else if (odd_par[by]) /* bin, odd par */ - by = by | 0100; - xb[mt_bptr[ch]++] = by; /* put in buffer */ - } - if (eorfl) - return mt_rec_end (uptr); /* EOR? write rec */ - return SCPE_OK; - } -return SCPE_IERR; -} - -/* Unit timeout */ - -t_stat mt_svc (UNIT *uptr) -{ -uint32 i, u, ch = uptr->UCH; /* get channel number */ -uint8 by, *xb = mtxb[ch]; /* get xfer buffer */ -t_uint64 dat; -t_mtrlnt bc; -t_stat r; - -if (xb == NULL) /* valid buffer? */ - return SCPE_IERR; -u = uptr - mt_dev[ch].units; -switch (uptr->UST) { /* case on state */ - - case CHSL_RDS: /* read start */ - if (QCHRONO (ch, mt_unit[ch] & 017)) /* Chronolog clock? */ - bc = chrono_rd (xb, MT_MAXFR); /* read clock */ - else { /* real tape */ - r = sim_tape_rdrecf (uptr, xb, &bc, MT_MAXFR); /* read record */ - if ((r = mt_map_err (uptr, r))) /* map status */ - return r; - if (mt_unit[ch] == 0) /* disconnected? */ - return SCPE_OK; - } /* end else Chrono */ - if (!ch6_qconn (ch, mt_unit[ch])) { /* chan disconnected? */ - mt_unit[ch] = 0; /* clr ctrl busy */ - return SCPE_OK; - } - for (i = bc; i < (bc + 6); i++) /* extra 0's */ - xb[i] = 0; - mt_bptr[ch] = 0; /* set ptr, lnt */ - mt_blnt[ch] = bc; - uptr->UST = CHSL_RDS|CHSL_2ND; /* next state */ - sim_activate (uptr, mt_tword); - break; - - case CHSL_RDS|CHSL_2ND: /* read word */ - for (i = 0, dat = 0; i < 6; i++) { /* proc 6 bytes */ - by = xb[mt_bptr[ch]++] & 077; /* get next byte */ - if ((mt_unit[ch] & 020) == 0) { /* BCD? */ - if (by == BCD_ZERO) /* cvt BCD 0 */ - by = 0; - else if (by & 020) /* invert zones */ - by = by ^ 040; - } - dat = (dat << 6) | ((t_uint64) by); - } - if (mt_bptr[ch] >= mt_blnt[ch]) { /* end of record? */ - ch6_req_rd (ch, mt_unit[ch], dat, CH6DF_EOR); - uptr->UST = CHSL_RDS|CHSL_3RD; /* next state */ - sim_activate (uptr, mt_tstop); /* long timing */ - } - else { - ch6_req_rd (ch, mt_unit[ch], dat, 0); /* send to channel */ - sim_activate (uptr, mt_tword); /* next word */ - } - break; - - case CHSL_RDS|CHSL_3RD: /* end record */ - if (ch6_qconn (ch, mt_unit[ch])) { /* ch still conn? */ - uptr->UST = CHSL_RDS; /* initial state */ - sim_activate (uptr, mt_tshort); /* sched next record */ - } - else mt_unit[ch] = 0; /* clr ctrl busy */ - if (DEBUG_PRS (mt_dev[ch])) - fprintf (sim_deb, ">>%s%d RDS complete, pos = %d, %s\n", - mt_dev[ch].name, u, uptr->pos, - mt_unit[ch]? "continuing": "disconnecting"); - return SCPE_OK; - - case CHSL_WRS: /* write start */ - if (!ch6_qconn (ch, mt_unit[ch])) { /* chan disconnected? */ - mt_unit[ch] = 0; /* clr ctrl busy */ - return SCPE_OK; /* (writes blank tape) */ - } - mt_bptr[ch] = 0; /* init buffer */ - uptr->UST = CHSL_WRS|CHSL_2ND; /* next state */ - ch6_req_wr (ch, mt_unit[ch]); /* request channel */ - mt_chob[ch] = 0; /* clr, inval buffer */ - mt_chob_v[ch] = 0; - sim_activate (uptr, mt_tword); /* wait for word */ - break; - - case CHSL_WRS|CHSL_2ND: /* write word */ - if (!ch6_qconn (ch, mt_unit[ch])) /* disconnected? */ - return mt_rec_end (uptr); /* write record */ - if (mt_chob_v[ch]) /* valid? clear */ - mt_chob_v[ch] = 0; - else ind_ioc = 1; /* no, io check */ - ch6_req_wr (ch, mt_unit[ch]); /* request channel */ - sim_activate (uptr, mt_tword); /* next word */ - break; - - case CHSL_WRS|CHSL_3RD: /* write stop */ - if (ch6_qconn (ch, mt_unit[ch])) { /* chan active? */ - uptr->UST = CHSL_WRS; /* initial state */ - sim_activate (uptr, mt_tshort); /* sched next record */ - } - else mt_unit[ch] = 0; /* clr ctrl busy */ - if (DEBUG_PRS (mt_dev[ch])) - fprintf (sim_deb, ">>%s%d WRS complete, pos = %d, %s\n", - mt_dev[ch].name, u, uptr->pos, - mt_unit[ch]? "continuing": "disconnecting"); - return SCPE_OK; - - case CHSL_BSR: case CHSL_BSF: /* backspace */ - uptr->UST = uptr->UST | CHSL_2ND; /* set 2nd state */ - sim_activate (uptr, mt_tstart); /* reactivate */ - ch6_end_nds (ch); /* disconnect */ - return SCPE_OK; - - case CHSL_BSR|CHSL_2ND: /* backspace rec */ - r = sim_tape_sprecr (uptr, &bc); /* space backwards */ - mt_unit[ch] = 0; /* clr ctrl busy */ - if (DEBUG_PRS (mt_dev[ch])) - fprintf (sim_deb, ">>%s%d BSR complete, pos = %d\n", - mt_dev[ch].name, u, uptr->pos); - if (r == MTSE_TMK) /* allow tape mark */ - return SCPE_OK; - return mt_map_err (uptr, r); - - case CHSL_BSF|CHSL_2ND: /* backspace file */ - while ((r = sim_tape_sprecr (uptr, &bc)) == MTSE_OK) ; - mt_unit[ch] = 0; /* clr ctrl busy */ - if (DEBUG_PRS (mt_dev[ch])) - fprintf (sim_deb, ">>%s%d BSF complete, pos = %d\n", - mt_dev[ch].name, u, uptr->pos); - if (r == MTSE_TMK) /* allow tape mark */ - return SCPE_OK; - return mt_map_err (uptr, r); /* map others */ - - case CHSL_WEF: /* write eof */ - r = sim_tape_wrtmk (uptr); /* write tape mark */ - mt_unit[ch] = 0; /* clr ctrl busy */ - ch6_end_nds (ch); /* disconnect */ - if (DEBUG_PRS (mt_dev[ch])) - fprintf (sim_deb, ">>%s%d WEF complete, pos = %d\n", - mt_dev[ch].name, u, uptr->pos); - return mt_map_err (uptr, r); - - case CHSL_REW: case CHSL_RUN: /* rewind, unload */ - uptr->UST = uptr->UST | CHSL_2ND; /* set 2nd state */ - sim_activate (uptr, mt_tstart); /* reactivate */ - mt_unit[ch] = 0; /* clr ctrl busy */ - ch6_end_nds (ch); /* disconnect */ - return SCPE_OK; - - case CHSL_REW | CHSL_2ND: - sim_tape_rewind (uptr); - if (DEBUG_PRS (mt_dev[ch])) - fprintf (sim_deb, ">>%s%d REW complete, pos = %d\n", - mt_dev[ch].name, u, uptr->pos); - return SCPE_OK; - - case CHSL_RUN | CHSL_2ND: - sim_tape_detach (uptr); - if (DEBUG_PRS (mt_dev[ch])) - fprintf (sim_deb, ">>%s%d RUN complete, pos = %d\n", - mt_dev[ch].name, u, uptr->pos); - return SCPE_OK; - - case CHSL_SDN: - if (mt_unit[ch] & 020) /* set density flag */ - uptr->flags = uptr-> flags & ~MTUF_LDN; - else uptr->flags = uptr->flags | MTUF_LDN; - mt_unit[ch] = 0; /* clr ctrl busy */ - ch6_end_nds (ch); /* disconnect */ - if (DEBUG_PRS (mt_dev[ch])) - fprintf (sim_deb, ">>%s%d SDN complete, pos = %d\n", - mt_dev[ch].name, u, uptr->pos); - return SCPE_OK; - - default: - return SCPE_IERR; - } - -return SCPE_OK; -} - -/* End record routine */ - -t_stat mt_rec_end (UNIT *uptr) -{ -uint32 ch = uptr->UCH; -uint8 *xb = mtxb[ch]; -t_stat r; - -if (mt_bptr[ch]) { /* any data? */ - if (xb == NULL) - return SCPE_IERR; - r = sim_tape_wrrecf (uptr, xb, mt_bptr[ch]); /* write record */ - if ((r = mt_map_err (uptr, r))) /* map error */ - return r; - } -uptr->UST = CHSL_WRS|CHSL_3RD; /* next state */ -sim_cancel (uptr); /* cancel current */ -sim_activate (uptr, mt_tstop); /* long timing */ -return SCPE_OK; -} - -/* Map tape error status */ - -t_stat mt_map_err (UNIT *uptr, t_stat st) -{ -uint32 ch = uptr->UCH; -uint32 u = mt_unit[ch]; -uint32 up = uptr - mt_dev[ch].units; - -if ((st != MTSE_OK) && DEBUG_PRS (mt_dev[ch])) - fprintf (sim_deb, ">>%s%d status = %s, pos = %d\n", - mt_dev[ch].name, up, tape_stat[st], uptr->pos); - -switch (st) { - - case MTSE_FMT: /* illegal fmt */ - case MTSE_UNATT: /* not attached */ - ch6_err_disc (ch, u, CHF_TRC); - mt_unit[ch] = 0; /* disconnect */ - return SCPE_IERR; - - case MTSE_IOERR: /* IO error */ - ch6_err_disc (ch, u, CHF_TRC); - mt_unit[ch] = 0; /* disconnect */ - return SCPE_IOERR; - - case MTSE_INVRL: /* invalid rec lnt */ - ch6_err_disc (ch, u, CHF_TRC); - mt_unit[ch] = 0; /* disconnect */ - return SCPE_MTRLNT; - - case MTSE_WRP: /* write protect */ - ch6_err_disc (ch, u, 0); - mt_unit[ch] = 0; /* disconnect */ - return STOP_WRP; - - case MTSE_EOM: /* end of medium */ - case MTSE_TMK: /* tape mark */ - ch6_err_disc (ch, u, CHF_EOF); - mt_unit[ch] = 0; /* disconnect */ - break; - - case MTSE_RECE: /* record in error */ - ch6_set_flags (ch, u, CHF_TRC); - break; - - case MTSE_BOT: /* reverse into BOT */ - ch6_set_flags (ch, u, CHF_BOT); - break; - - case MTSE_OK: /* no error */ - break; - } - -return SCPE_OK; -} - -/* Magtape reset */ - -t_stat mt_reset (DEVICE *dptr) -{ -uint32 ch = dptr - &mt_dev[0]; -uint32 j; -REG *rptr; -UNIT *uptr; - -if (mtxb[ch] == NULL) - mtxb[ch] = (uint8 *) calloc (MT_MAXFR + 6, sizeof (uint8)); -if (mtxb[ch] == NULL) /* allocate buffer */ - return SCPE_MEM; -rptr = find_reg ("BUF", NULL, dptr); /* update reg ptr */ -if (rptr == NULL) - return SCPE_IERR; -rptr->loc = (void *) mtxb[ch]; -mt_unit[ch] = 0; /* clear busy */ -mt_bptr[ch] = 0; /* clear buf ptrs */ -mt_blnt[ch] = 0; -mt_chob[ch] = 0; -mt_chob_v[ch] = 0; -for (j = 1; j <= MT_NUMDR; j++) { /* for all units */ - uptr = dptr->units + j; - uptr->UST = 0; /* clear state */ - uptr->UCH = ch; - sim_cancel (uptr); /* stop activity */ - } /* end for */ -return SCPE_OK; /* done */ -} - -/* Magtape attach */ - -t_stat mt_attach (UNIT *uptr, char *cptr) -{ -uptr->flags = uptr->flags & ~MTUF_LDN; /* start as hi den */ -return sim_tape_attach (uptr, cptr); -} - -/* Magtape boot */ - -#define BOOT_START 01000 - -static const t_uint64 boot_rom[5] = { - INT64_C(0076200000000) + U_MTBIN - 1, /* RDS MT_binary */ - INT64_C(0054000000000) + BOOT_START + 4, /* RCHA *+3 */ - INT64_C(0054400000000), /* LCHA 0 */ - INT64_C(0002100000001), /* TTR 1 */ - INT64_C(0500003000000), /* IOCT 0,,3 */ - }; - -t_stat mt_boot (int32 unitno, DEVICE *dptr) -{ -uint32 i, chan; -extern t_uint64 *M; - -chan = dptr - &mt_dev[0] + 1; -WriteP (BOOT_START, boot_rom[0] + unitno + (chan << 9)); -for (i = 1; i < 5; i++) - WriteP (BOOT_START + i, boot_rom[i]); -PC = BOOT_START; -return SCPE_OK; -} diff --git a/I7094/i7094_sys.c b/I7094/i7094_sys.c deleted file mode 100644 index 5aa432a6..00000000 --- a/I7094/i7094_sys.c +++ /dev/null @@ -1,776 +0,0 @@ -/* i7094_sys.c: IBM 7094 simulator interface - - Copyright (c) 2003-2011, 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. - - 31-Dec-11 RMS Added SPI, SPI - 16-Jul-10 RMS Added SPUx, SPTx, SPRx - 29-Oct-06 RMS Added additional expanded core instructions - 08-Jun-06 RMS Added Dave Pitts' binary loader -*/ - -#include "i7094_defs.h" -#include -#include "i7094_dat.h" - -extern DEVICE cpu_dev; -extern DEVICE ch_dev[NUM_CHAN]; -extern DEVICE mt_dev[NUM_CHAN]; -extern DEVICE drm_dev; -extern DEVICE dsk_dev; -extern DEVICE com_dev, coml_dev; -extern DEVICE cdr_dev, cdp_dev; -extern DEVICE lpt_dev; -extern DEVICE clk_dev; -extern UNIT cpu_unit; -extern REG cpu_reg[]; - -uint32 cvt_code_to_ascii (uint32 c, int32 sw); -uint32 cvt_ascii_to_code (uint32 c, int32 sw); - -/* 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[] = "IBM 7094"; - -REG *sim_PC = &cpu_reg[0]; - -int32 sim_emax = 1; - -DEVICE *sim_devices[] = { - &cpu_dev, - &clk_dev, - &ch_dev[0], - &ch_dev[1], - &ch_dev[2], - &ch_dev[3], - &ch_dev[4], - &ch_dev[5], - &ch_dev[6], - &ch_dev[7], - &mt_dev[0], - &mt_dev[1], - &mt_dev[2], - &mt_dev[3], - &mt_dev[4], - &mt_dev[5], - &mt_dev[6], - &mt_dev[7], - &cdr_dev, - &cdp_dev, - &lpt_dev, - &dsk_dev, - &drm_dev, - &com_dev, - &coml_dev, - NULL - }; - -char ch_bkpt_msg[] = "Channel A breakpoint, CLC: xxxxxx"; - -const char *sim_stop_messages[] = { - "Unknown error", - "HALT instruction", - "Breakpoint", - "Undefined instruction", - "Divide check", - "Nested XEC limit exceeded", - "Address stop", - "Non-existent channel", - "Illegal instruction for 7909 channel", - "Illegal instruction for non-7909 channel", - "Non-existent device", - "Undefined channel instruction", - "Write to protected device", - "Illegal instruction for device", - "Invalid 7631 track format", - "7750 buffer pool empty on input", - "7750 buffer pool empty on output", - "7750 invalid line number", - "7750 invalid message", - ch_bkpt_msg - }; - -/* Modify channel breakpoint message */ - -t_stat ch_bkpt (uint32 ch, uint32 clc) -{ -ch_bkpt_msg[8] = 'A' + ch; -sprintf (&ch_bkpt_msg[27], "%06o", clc); -return STOP_CHBKPT; -} - -/* Binary loader, not implemented */ - -t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) -{ -extern t_stat binloader (FILE *fd, char *file, int loadpt); - -if (flag == 0) - return binloader (fileref, cptr, 0); -return SCPE_NOFNC; -} - -/* Symbol tables */ - -#define I_V_FL 39 /* inst class */ -#define I_M_FL 017 /* class mask */ -#define I_NOP INT64_C(0000000000000000) /* no operand */ -#define I_MXR INT64_C(0010000000000000) /* addr(tag) */ -#define I_MXN INT64_C(0020000000000000) /* *addr(tag) */ -#define I_MXV INT64_C(0030000000000000) /* var mul/div */ -#define I_MXC INT64_C(0040000000000000) /* convert */ -#define I_DNP INT64_C(0050000000000000) /* decr, no oper */ -#define I_DEC INT64_C(0060000000000000) /* decrement */ -#define I_SNS INT64_C(0070000000000000) /* sense */ -#define I_IMM INT64_C(0100000000000000) /* 18b immediate */ -#define I_TAG INT64_C(0110000000000000) /* tag only */ -#define I_IOX INT64_C(0120000000000000) /* IO channel */ -#define I_TCH INT64_C(0130000000000000) /* transfer channel */ -#define I_I9N INT64_C(0140000000000000) /* 7909 with nostore */ -#define I_I9S INT64_C(0150000000000000) /* 7909 */ -#define I_SPX INT64_C(0160000000000000) /* SPU, SPR */ -#define IFAKE_7607 INT64_C(0001000000000000) /* fake op extensions */ -#define IFAKE_7909 INT64_C(0002000000000000) -#define DFAKE (DMASK|IFAKE_7607|IFAKE_7909) -#define I_N_NOP 000 -#define I_N_MXR 001 -#define I_N_MXN 002 -#define I_N_MXV 003 -#define I_N_MXC 004 -#define I_N_DNP 005 -#define I_N_DEC 006 -#define I_N_SNS 007 -#define I_N_IMM 010 -#define I_N_TAG 011 -#define I_N_IOX 012 -#define I_N_TCH 013 -#define I_N_I9N 014 -#define I_N_I9S 015 -#define I_N_SPX 016 - -#define INST_P_XIT 0 /* exit */ -#define INST_P_SKP 1 /* do not print */ -#define INST_P_PRA 2 /* print always */ -#define INST_P_PNZ 3 /* print if nz */ -#define INST_P_PNT 4 /* print if nz, term */ - -static const t_uint64 masks[15] = { - INT64_C(03777700000000), INT64_C(03777700000000), - INT64_C(03777700000000), INT64_C(03777700000000), - INT64_C(03777400000000), INT64_C(03700000000000), - INT64_C(03700000000000), INT64_C(03777700077777), - INT64_C(03777700000000), INT64_C(03777700000000), - INT64_C(03700000200000), INT64_C(03700000200000), - INT64_C(03760000200000), INT64_C(03740000200000), - INT64_C(03777700077760) }; - -static const uint32 fld_max[15][3] = { /* addr,tag,decr limit */ - { INST_M_ADDR, INST_M_TAG, 0 }, - { INST_M_ADDR, INST_M_TAG, 0 }, - { INST_M_ADDR, INST_M_TAG, 0 }, - { INST_M_ADDR, INST_M_TAG, INST_M_VCNT }, - { INST_M_ADDR, INST_M_TAG, INST_M_CCNT }, - { INST_M_ADDR, INST_M_TAG, INST_M_DEC }, - { INST_M_ADDR, INST_M_TAG, INST_M_DEC }, - { 0, INST_M_TAG, 0 }, - { RMASK, 0, 0 }, - { INST_M_ADDR, INST_M_TAG, 0 }, - { INST_M_ADDR, 1, INST_M_DEC }, - { INST_M_ADDR, 1, 0 }, - { INST_M_ADDR, 1, 0 }, - { INST_M_ADDR, 1, 0 }, - { INST_M_4B, INST_M_TAG, 0 } - }; - -static const uint32 fld_fmt[15][3] = { /* addr,tag,decr print */ - { INST_P_PNT, INST_P_PNT, INST_P_XIT }, /* nop: all optional */ - { INST_P_PRA, INST_P_PNT, INST_P_XIT }, /* mxr: tag optional */ - { INST_P_PRA, INST_P_PNT, INST_P_XIT }, /* mxn: tag optional */ - { INST_P_PRA, INST_P_PNZ, INST_P_PRA }, /* mxv: tag optional */ - { INST_P_PRA, INST_P_PNZ, INST_P_PRA }, /* cvt: tag optional */ - { INST_P_PNT, INST_P_PNT, INST_P_PNT }, /* dnp: all optional */ - { INST_P_PRA, INST_P_PRA, INST_P_PRA }, /* dec: print all */ - { INST_P_SKP, INST_P_PNT, INST_P_XIT }, /* sns: skip addr, tag opt */ - { INST_P_PRA, INST_P_XIT, INST_P_XIT }, /* immediate: addr only */ - { INST_P_PNZ, INST_P_PRA, INST_P_XIT }, /* tag: addr optional */ - { INST_P_PRA, INST_P_PNZ, INST_P_PRA }, /* iox: tag optional */ - { INST_P_PRA, INST_P_PNT, INST_P_XIT }, /* tch: tag optional */ - { INST_P_PRA, INST_P_PNT, INST_P_XIT }, /* i9n: tag optional */ - { INST_P_PRA, INST_P_PNT, INST_P_XIT }, /* i9s: tag optional */ - { INST_P_PNZ, INST_P_PNT, INST_P_XIT } /* SPx: tag optional */ - }; - -static const t_uint64 ind_test[15] = { - 0, 0, INST_IND, 0, 0, 0, 0, 0, - 0, 0, CHI_IND, CHI_IND, CHI_IND, CHI_IND, 0 - }; - -static const char *opcode[] = { - "TXI", "TIX", "TXH", - "STR", "TNX", "TXL", - "HTR", "TRA", "TTR", - - "CLM", "LBT", "CHS", - "SSP", "ENK", "IOT", - "COM", "ETM", "RND", - "FRN", "DCT", "RCT", - "LMTM", "SLF", "SLN1", - "SLN2", "SLN3", "SLN4", - "SWT1", "SWT2", "SWT3", - "SWT4", "SWT5", "SWT6", - "BTTA", "BTTB", "BTTC", - "BTTD", "BTTE", "BTTF", - "BTTG", "BTTH", - "RICA", "RICB", "RICC", - "RICD", "RICE", "RICF", - "RICG", "RICH", - "RDCA", "RDCB", "RDCC", - "RDCD", "RDCE", "RDCF", - "RDCG", "RDCH", - "SPUA", "SPUB", "SPUC", - "SPUD", "SPUE", "SPUF", - "SPUG", "SPUH", - "SPTA", "SPTB", "SPTC", - "SPTD", "SPTE", "SPTF", - "SPTG", "SPTH", - "SPRA", "SPRB", "SPRC", - "SPRD", "SPRE", "SPRF", - "SPRG", "SPRH", - - "TRCA", "TRCC", - "TRCE", "TRCG", - "TEFA", "TEFC", - "TEFE", "TEFG", - "TLQ", "IIA", "TIO", - "OAI", "PAI", "TIF", - "IIR", "RFT", "SIR", - "RNT", "RIR", - "TCOA", "TCOB", "TCOC", - "TCOD", "TCOE", "TCOF", - "TCOG", "TCOH", "TSX", - "TZE", "CVR", "TPL", - "XCA", "TOV", - "TQO", "TQP", - "MPY", "VLM", "VLM1", - "DVH", "DVP", - "VDH", "VDP", - "VDH2", "VDP2", - "FDH", "FDP", - "FMP", "DFMP", - "FAD", "DFAD", - "FSB", "DFSB", - "FAM", "DFAM", - "FSM", "DFSM", - "ANS", "ERA", - "CAS", "ACL", - "ADD", "ADM", - "SUB", "SBM", - "HPR", "IIS", "LDI", - "OSI", "DLD", "OFT", - "RIS", "ONT", - "CLA", "CLS", - "ZET", "XEC", - "LXA", "LAC", - "RCHA", "RCHC", - "RCHE", "RCHG", - "LCHA", "LCHC", - "LCHE", "LCHG", - "RSCA", "RSCC", - "RSCE", "RSCG", - "STCA", "STCC", - "STCE", "STCG", - "LDQ", "ENB", - "STZ", "STO", "SLW", - "STI", "STA", "STD", - "STT", "STP", - "SXA", "SCA", - "SCHA", "SCHC", - "SCHE", "SCHG", - "SCDA", "SCDC", - "SCDE", "SCDG", - "PAX", "PAC", - "PXA", "PCA", - "PSE", "NOP", "RDS", - "LLS", "BSR", "LRS", - "WRS", "ALS", "WEF", - "ARS", "REW", "AXT", - "SDN", - - "CLM", "PBT", "EFTM", - "SSM", "LFTM", "ESTM", - "ECTM", "LTM", "LSNM", - "EMTM", "SLT1", "SLT2", - "SLT3", "SLT4", - "ETTA", "ETTB", "ETTC", - "ETTD", "ETTE", "ETTF", - "ETTG", "ETTH", - - "ESNT", - "TRCB", "TRCD", - "TRCF", "TRCH", - "TEFB", "TEFD", - "TEFF", "TEFH", - "RIA", "PIA", - "IIL", "LFT", "SIL", - "LNT", "RIL", - "TCNA", "TCNB", "TCNC", - "TCND", "TCNE", "TCNF", - "TCNG", "TCNH", - "TNZ", "CVR", "TMI", - "XCL", "TNO", "CRQ", - "MPR", "DFDH", "DFDP", - "UFM", "DUFM", - "UFA", "DUFA", - "UFS", "DUFS", - "UAM", "DUAM", - "USM", "DUSM", - "ANA", "LAS", - "CAL", "ORA", "NZT", - "LXD", "LXC", - "RCHB", "RCHD", - "RCHF", "RCHH", - "LCHB", "LCHD", - "LCHF", "LCHH", - "RSCB", "RSCD", - "RSCF", "RSCH", - "STCB", "STCD", - "STCF", "STCH", - "STQ", "SRI", "ORS", "DST", - "SPI", - "SLQ", "STL", - "SXD", "SCD", - "SCHB", "SCHD", - "SCHF", "SCHH", - "SCDB", "SCDD", - "SCDF", "SCDH", - "PDX", "PDC", - "PXD", "PCD", - "MSE", "LGL", "BSF", - "LGR", "RQL", "RUN", - "AXC", - - "TIA", "TIB", - "LRI", "LPI", - "SEA", "SEB", - "IFT", "EFT", - - "IOCD", "IOCDN", "TCH", - "IORP", "IORPN", - "IORT", "IORTN", - "IOCP", "IOCPN", - "IOCT", "IOCTN", - "IOSP", "IOSPN", - "IOST", "IOSTN", - - "WTR", "XMT", - "TCH", "LIPT", - "CTL", "CTLN", - "CTLR", "CTLRN", - "CTLW", "CTLWN", - "SNS", - "LAR", "SAR", "TWT", - "CPYP", - "CPYD", "TCM", - "LIP", "TDC", "LCC", - "SMS", "ICC", - - NULL - }; - -static const t_uint64 opc_v[] = { - INT64_C(0100000000000)+I_DEC, INT64_C(0200000000000)+I_DEC, INT64_C(0300000000000)+I_DEC, - INT64_C(0500000000000)+I_DNP, INT64_C(0600000000000)+I_DEC, INT64_C(0700000000000)+I_DEC, - INT64_C(0000000000000)+I_MXN, INT64_C(0002000000000)+I_MXN, INT64_C(0002100000000)+I_MXN, - - INT64_C(0076000000000)+I_SNS, INT64_C(0076000000001)+I_SNS, INT64_C(0076000000002)+I_SNS, - INT64_C(0076000000003)+I_SNS, INT64_C(0076000000004)+I_SNS, INT64_C(0076000000005)+I_SNS, - INT64_C(0076000000006)+I_SNS, INT64_C(0076000000007)+I_SNS, INT64_C(0076000000010)+I_SNS, - INT64_C(0076000000011)+I_SNS, INT64_C(0076000000012)+I_SNS, INT64_C(0076000000014)+I_SNS, - INT64_C(0076000000016)+I_SNS, INT64_C(0076000000140)+I_SNS, INT64_C(0076000000141)+I_SNS, - INT64_C(0076000000142)+I_SNS, INT64_C(0076000000143)+I_SNS, INT64_C(0076000000144)+I_SNS, - INT64_C(0076000000161)+I_SNS, INT64_C(0076000000162)+I_SNS, INT64_C(0076000000163)+I_SNS, - INT64_C(0076000000164)+I_SNS, INT64_C(0076000000165)+I_SNS, INT64_C(0076000000166)+I_SNS, - INT64_C(0076000001000)+I_SNS, INT64_C(0076000002000)+I_SNS, INT64_C(0076000003000)+I_SNS, - INT64_C(0076000004000)+I_SNS, INT64_C(0076000005000)+I_SNS, INT64_C(0076000006000)+I_SNS, - INT64_C(0076000007000)+I_SNS, INT64_C(0076000010000)+I_SNS, - INT64_C(0076000001350)+I_SNS, INT64_C(0076000002350)+I_SNS, INT64_C(0076000003350)+I_SNS, - INT64_C(0076000004350)+I_SNS, INT64_C(0076000005350)+I_SNS, INT64_C(0076000006350)+I_SNS, - INT64_C(0076000007350)+I_SNS, INT64_C(0076000010350)+I_SNS, - INT64_C(0076000001352)+I_SNS, INT64_C(0076000002352)+I_SNS, INT64_C(0076000003352)+I_SNS, - INT64_C(0076000004352)+I_SNS, INT64_C(0076000005352)+I_SNS, INT64_C(0076000006352)+I_SNS, - INT64_C(0076000007352)+I_SNS, INT64_C(0076000010352)+I_SNS, - INT64_C(0076000001340)+I_SNS, INT64_C(0076000002340)+I_SNS, INT64_C(0076000003340)+I_SNS, - INT64_C(0076000004340)+I_SNS, INT64_C(0076000005340)+I_SNS, INT64_C(0076000006340)+I_SNS, - INT64_C(0076000007340)+I_SNS, INT64_C(0076000010340)+I_SNS, - INT64_C(0076000001360)+I_SNS, INT64_C(0076000002360)+I_SNS, INT64_C(0076000003360)+I_SNS, - INT64_C(0076000004360)+I_SNS, INT64_C(0076000005360)+I_SNS, INT64_C(0076000006360)+I_SNS, - INT64_C(0076000007360)+I_SNS, INT64_C(0076000010360)+I_SNS, - INT64_C(0076000001360)+I_SNS, INT64_C(0076000002360)+I_SNS, INT64_C(0076000003360)+I_SNS, - INT64_C(0076000004360)+I_SNS, INT64_C(0076000005360)+I_SNS, INT64_C(0076000006360)+I_SNS, - INT64_C(0076000007360)+I_SNS, INT64_C(0076000010360)+I_SNS, - - INT64_C(0002200000000)+I_MXN, INT64_C(0002400000000)+I_MXN, - INT64_C(0002600000000)+I_MXN, INT64_C(0002700000000)+I_MXN, - INT64_C(0003000000000)+I_MXN, INT64_C(0003100000000)+I_MXN, - INT64_C(0003200000000)+I_MXN, INT64_C(0003300000000)+I_MXN, - INT64_C(0004000000000)+I_MXN, INT64_C(0004100000000)+I_NOP, INT64_C(0004200000000)+I_MXR, - INT64_C(0004300000000)+I_NOP, INT64_C(0004400000000)+I_NOP, INT64_C(0004600000000)+I_MXR, - INT64_C(0005100000000)+I_IMM, INT64_C(0005400000000)+I_IMM, INT64_C(0005500000000)+I_IMM, - INT64_C(0005600000000)+I_IMM, INT64_C(0005700000000)+I_IMM, - INT64_C(0006000000000)+I_MXN, INT64_C(0006100000000)+I_MXN, INT64_C(0006200000000)+I_MXN, - INT64_C(0006300000000)+I_MXN, INT64_C(0006400000000)+I_MXN, INT64_C(0006500000000)+I_MXN, - INT64_C(0006600000000)+I_MXN, INT64_C(0006700000000)+I_MXN, INT64_C(0007400000000)+I_MXR, - INT64_C(0010000000000)+I_MXN, INT64_C(0011400000000)+I_MXC, INT64_C(0012000000000)+I_MXN, - INT64_C(0013100000000)+I_NOP, INT64_C(0014000000000)+I_MXN, - INT64_C(0016100000000)+I_MXN, INT64_C(0016200000000)+I_MXN, - INT64_C(0020000000000)+I_MXN, INT64_C(0020400000000)+I_MXV, INT64_C(0020500000000)+I_MXV, - INT64_C(0022000000000)+I_MXN, INT64_C(0022100000000)+I_MXN, - INT64_C(0022400000000)+I_MXV, INT64_C(0022500000000)+I_MXV, - INT64_C(0022600000000)+I_MXV, INT64_C(0022700000000)+I_MXV, - INT64_C(0024000000000)+I_MXN, INT64_C(0024100000000)+I_MXN, - INT64_C(0026000000000)+I_MXN, INT64_C(0026100000000)+I_MXN, - INT64_C(0030000000000)+I_MXN, INT64_C(0030100000000)+I_MXN, - INT64_C(0030200000000)+I_MXN, INT64_C(0030300000000)+I_MXN, - INT64_C(0030400000000)+I_MXN, INT64_C(0030500000000)+I_MXN, - INT64_C(0030600000000)+I_MXN, INT64_C(0030700000000)+I_MXN, - INT64_C(0032000000000)+I_MXN, INT64_C(0032200000000)+I_MXN, - INT64_C(0034000000000)+I_MXN, INT64_C(0036100000000)+I_MXN, - INT64_C(0040000000000)+I_MXN, INT64_C(0040100000000)+I_MXN, - INT64_C(0040200000000)+I_MXN, INT64_C(0440000000000)+I_MXN, - INT64_C(0042000000000)+I_NOP, INT64_C(0044000000000)+I_MXN, INT64_C(0044100000000)+I_MXN, - INT64_C(0044200000000)+I_MXN, INT64_C(0044300000000)+I_MXN, INT64_C(0044400000000)+I_MXN, - INT64_C(0044500000000)+I_MXN, INT64_C(0044600000000)+I_MXN, - INT64_C(0050000000000)+I_MXN, INT64_C(0050200000000)+I_MXN, - INT64_C(0052000000000)+I_MXN, INT64_C(0052200000000)+I_MXN, - INT64_C(0053400000000)+I_MXR, INT64_C(0053500000000)+I_MXR, - INT64_C(0054000000000)+I_MXN, INT64_C(0054100000000)+I_MXN, - INT64_C(0054200000000)+I_MXN, INT64_C(0054300000000)+I_MXN, - INT64_C(0054400000000)+I_MXN, INT64_C(0054500000000)+I_MXN, - INT64_C(0054600000000)+I_MXN, INT64_C(0054700000000)+I_MXN, - INT64_C(0054000000000)+I_MXN, INT64_C(0054100000000)+I_MXN, - INT64_C(0054200000000)+I_MXN, INT64_C(0054300000000)+I_MXN, - INT64_C(0054400000000)+I_MXN, INT64_C(0054500000000)+I_MXN, - INT64_C(0054600000000)+I_MXN, INT64_C(0054700000000)+I_MXN, - INT64_C(0056000000000)+I_MXN, INT64_C(0056400000000)+I_MXN, - INT64_C(0060000000000)+I_MXN, INT64_C(0060100000000)+I_MXN, INT64_C(0060200000000)+I_MXN, - INT64_C(0060400000000)+I_MXN, INT64_C(0062100000000)+I_MXN, INT64_C(0062200000000)+I_MXN, - INT64_C(0062500000000)+I_MXN, INT64_C(0063000000000)+I_MXN, - INT64_C(0063400000000)+I_MXR, INT64_C(0063600000000)+I_MXR, - INT64_C(0064000000000)+I_MXN, INT64_C(0064000000000)+I_MXN, - INT64_C(0064200000000)+I_MXN, INT64_C(0064300000000)+I_MXN, - INT64_C(0064400000000)+I_MXN, INT64_C(0064500000000)+I_MXN, - INT64_C(0064600000000)+I_MXN, INT64_C(0064700000000)+I_MXN, - INT64_C(0073400000000)+I_TAG, INT64_C(0073700000000)+I_TAG, - INT64_C(0075400000000)+I_TAG, INT64_C(0075600000000)+I_TAG, - INT64_C(0076000000000)+I_MXR, INT64_C(0076100000000)+I_NOP, INT64_C(0076200000000)+I_MXR, - INT64_C(0076300000000)+I_MXR, INT64_C(0076400000000)+I_MXR, INT64_C(0076500000000)+I_MXR, - INT64_C(0076600000000)+I_MXR, INT64_C(0076700000000)+I_MXR, INT64_C(0077000000000)+I_MXR, - INT64_C(0077100000000)+I_MXR, INT64_C(0077200000000)+I_MXR, INT64_C(0077400000000)+I_MXR, - INT64_C(0077600000000)+I_MXR, - - INT64_C(0476000000000)+I_SNS, INT64_C(0476000000001)+I_SNS, INT64_C(0476000000002)+I_SNS, - INT64_C(0476000000003)+I_SNS, INT64_C(0476000000004)+I_SNS, INT64_C(0476000000005)+I_SNS, - INT64_C(0476000000006)+I_SNS, INT64_C(0476000000007)+I_SNS, INT64_C(0476000000010)+I_SNS, - INT64_C(0476000000016)+I_SNS, INT64_C(0476000000141)+I_SNS, INT64_C(0476000000142)+I_SNS, - INT64_C(0476000000143)+I_SNS, INT64_C(0476000000144)+I_SNS, - INT64_C(0476000001000)+I_SNS, INT64_C(0476000002000)+I_SNS, INT64_C(0476000003000)+I_SNS, - INT64_C(0476000004000)+I_SNS, INT64_C(0476000005000)+I_SNS, INT64_C(0476000006000)+I_SNS, - INT64_C(0476000007000)+I_SNS, INT64_C(0476000010000)+I_SNS, - - INT64_C(0402100000000)+I_MXN, - INT64_C(0402200000000)+I_MXN, INT64_C(0402400000000)+I_MXN, - INT64_C(0402600000000)+I_MXN, INT64_C(0402700000000)+I_MXN, - INT64_C(0403000000000)+I_MXN, INT64_C(0403100000000)+I_MXN, - INT64_C(0403200000000)+I_MXN, INT64_C(0403300000000)+I_MXN, - INT64_C(0404200000000)+I_NOP, INT64_C(0404600000000)+I_NOP, - INT64_C(0405100000000)+I_IMM, INT64_C(0405400000000)+I_IMM, INT64_C(0405500000000)+I_IMM, - INT64_C(0405600000000)+I_IMM, INT64_C(0405700000000)+I_IMM, - INT64_C(0406000000000)+I_MXN, INT64_C(0406100000000)+I_MXN, INT64_C(0406200000000)+I_MXN, - INT64_C(0406300000000)+I_MXN, INT64_C(0406400000000)+I_MXN, INT64_C(0406500000000)+I_MXN, - INT64_C(0406600000000)+I_MXN, INT64_C(0406700000000)+I_MXN, - INT64_C(0410000000000)+I_MXN, INT64_C(0411400000000)+I_MXC, INT64_C(0412000000000)+I_MXN, - INT64_C(0413000000000)+I_NOP, INT64_C(0414000000000)+I_MXN, INT64_C(0415400000000)+I_MXC, - INT64_C(0420000000000)+I_MXN, INT64_C(0424000000000)+I_MXN, INT64_C(0424100000000)+I_MXN, - INT64_C(0426000000000)+I_MXN, INT64_C(0426100000000)+I_MXN, - INT64_C(0430000000000)+I_MXN, INT64_C(0430100000000)+I_MXN, - INT64_C(0430200000000)+I_MXN, INT64_C(0430300000000)+I_MXN, - INT64_C(0430400000000)+I_MXN, INT64_C(0430500000000)+I_MXN, - INT64_C(0430600000000)+I_MXN, INT64_C(0430700000000)+I_MXN, - INT64_C(0432000000000)+I_MXN, INT64_C(0434000000000)+I_MXN, - INT64_C(0450000000000)+I_MXN, INT64_C(0450100000000)+I_MXN, INT64_C(0452000000000)+I_MXN, - INT64_C(0453400000000)+I_MXR, INT64_C(0453500000000)+I_MXR, - INT64_C(0454000000000)+I_MXN, INT64_C(0454100000000)+I_MXN, - INT64_C(0454200000000)+I_MXN, INT64_C(0454300000000)+I_MXN, - INT64_C(0454400000000)+I_MXN, INT64_C(0454500000000)+I_MXN, - INT64_C(0454600000000)+I_MXN, INT64_C(0454700000000)+I_MXN, - INT64_C(0454000000000)+I_MXN, INT64_C(0454100000000)+I_MXN, - INT64_C(0454200000000)+I_MXN, INT64_C(0454300000000)+I_MXN, - INT64_C(0454400000000)+I_MXN, INT64_C(0454500000000)+I_MXN, - INT64_C(0454600000000)+I_MXN, INT64_C(0454700000000)+I_MXN, - INT64_C(0460000000000)+I_MXN, INT64_C(0460100000000)+I_MXN, INT64_C(0460200000000)+I_MXN, INT64_C(0460300000000)+I_MXN, - INT64_C(0460400000000)+I_MXN, - INT64_C(0462000000000)+I_MXN, INT64_C(0462500000000)+I_MXN, - INT64_C(0463400000000)+I_MXR, INT64_C(0463600000000)+I_MXR, - INT64_C(0464000000000)+I_MXN, INT64_C(0464000000000)+I_MXN, - INT64_C(0464200000000)+I_MXN, INT64_C(0464300000000)+I_MXN, - INT64_C(0464400000000)+I_MXN, INT64_C(0464500000000)+I_MXN, - INT64_C(0464600000000)+I_MXN, INT64_C(0464700000000)+I_MXN, - INT64_C(0473400000000)+I_TAG, INT64_C(0473700000000)+I_TAG, - INT64_C(0475400000000)+I_TAG, INT64_C(0475600000000)+I_TAG, - INT64_C(0476000000000)+I_MXR, INT64_C(0476300000000)+I_MXR, INT64_C(0476400000000)+I_MXR, - INT64_C(0476500000000)+I_MXR, INT64_C(0477300000000)+I_MXR, INT64_C(0477200000000)+I_MXR, - INT64_C(0477400000000)+I_MXR, - - INT64_C(0010100000000)+I_MXN, INT64_C(0410100000000)+I_MXN, - INT64_C(0056200000000)+I_MXN, INT64_C(0456400000000)+I_MXN, - INT64_C(0476100000041)+I_SNS, INT64_C(0476100000042)+I_SNS, - INT64_C(0476100000043)+I_SNS, INT64_C(0476100000044)+I_SNS, - - INT64_C(01000000000000)+I_IOX, INT64_C(01000000200000)+I_IOX, INT64_C(01100000000000)+I_TCH, - INT64_C(01200000000000)+I_IOX, INT64_C(01200000200000)+I_IOX, - INT64_C(01300000000000)+I_IOX, INT64_C(01300000200000)+I_IOX, - INT64_C(01400000000000)+I_IOX, INT64_C(01400000200000)+I_IOX, - INT64_C(01500000000000)+I_IOX, INT64_C(01500000200000)+I_IOX, - INT64_C(01600000000000)+I_IOX, INT64_C(01600000200000)+I_IOX, - INT64_C(01700000000000)+I_IOX, INT64_C(01700000200000)+I_IOX, - - INT64_C(02000000000000)+I_TCH, INT64_C(02000000200000)+I_IOX, - INT64_C(02100000000000)+I_TCH, INT64_C(02100000200000)+I_TCH, - INT64_C(02200000000000)+I_I9N, INT64_C(02220000000000)+I_TCH, - INT64_C(02200000200000)+I_I9N, INT64_C(02220000200000)+I_TCH, - INT64_C(02240000000000)+I_I9N, INT64_C(02260000000000)+I_TCH, - INT64_C(02240000200000)+I_I9N, - INT64_C(02300000000000)+I_I9S, INT64_C(02300000200000)+I_I9S, - INT64_C(02340000000000)+I_I9S, - INT64_C(02400000000000)+I_IOX, - INT64_C(02500000000000)+I_IOX, INT64_C(02500000200000)+I_IOX, - INT64_C(02600000200000)+I_I9S, INT64_C(02640000000000)+I_I9S, INT64_C(02640000200000)+I_I9S, - INT64_C(02700000000000)+I_I9S, INT64_C(02700000200000)+I_IOX, - - 0 - }; - -/* Symbolic decode - - Inputs: - *of = output stream - addr = current PC - *val = pointer to values - *uptr = pointer to unit - sw = switches - Outputs: - return = status code -*/ - -t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, - UNIT *uptr, int32 sw) -{ -uint32 i, j, k, l, fmt, c, fld[3]; -DEVICE *dptr; -t_uint64 inst; - -inst = val[0]; -if (uptr == NULL) - uptr = &cpu_unit; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; - -if (sw & SWMASK ('C')) { /* character? */ - c = (uint32) (inst & 077); - fprintf (of, "%c", cvt_code_to_ascii (c, sw)); - return SCPE_OK; - } -if (sw & SWMASK ('S')) { /* string? */ - for (i = 36; i > 0; i = i - 6) { - c = (uint32) ((inst >> (i - 6)) & 077); - fprintf (of, "%c", cvt_code_to_ascii (c, sw)); - } - return SCPE_OK; - } -if (!(sw & (SWMASK ('M')|SWMASK ('I')|SWMASK ('N'))) || /* M, N or I? */ - (dptr->dwidth != 36)) - return SCPE_ARG; - -/* Instruction decode */ - -fld[0] = ((uint32) inst & 0777777); -fld[1] = GET_TAG (inst); /* get 3 fields */ -fld[2] = GET_DEC (inst); -if (sw & SWMASK ('I')) /* decode as 7607? */ - inst |= IFAKE_7607; -if (sw & SWMASK ('N')) /* decode as 7909? */ - inst |= IFAKE_7909; - -for (i = 0; opc_v[i] > 0; i++) { /* loop thru ops */ - j = (int32) ((opc_v[i] >> I_V_FL) & I_M_FL); /* get class */ - if ((opc_v[i] & DFAKE) == (inst & masks[j])) { /* match? */ - if (inst & ind_test[j]) /* indirect? */ - fprintf (of, "%s*", opcode[i]); - else fprintf (of, "%s", opcode[i]); /* opcode */ - for (k = 0; k < 3; k++) - fld[k] = fld[k] & fld_max[j][k]; - for (k = 0; k < 3; k++) { /* loop thru fields */ - fmt = fld_fmt[j][k]; /* get format */ - if (fmt == INST_P_XIT) - return SCPE_OK; - switch (fmt) { /* case on format */ - - case INST_P_PNT: /* print nz, else term */ - for (l = k, c = 0; l < 3; l++) - c |= fld[k]; - if (c == 0) - return SCPE_OK; - case INST_P_PNZ: /* print non-zero */ - fputc (k? ',': ' ', of); - if (fld[k]) - fprintf (of, "%-o", fld[k]); - break; - case INST_P_PRA: /* print always */ - fputc (k? ',': ' ', of); - fprintf (of, "%-o", fld[k]); - break; - case INST_P_SKP: /* skip */ - break; - } /* end switch */ - } /* end for k */ - return SCPE_OK; /* done */ - } /* end if */ - } /* end for i */ -return SCPE_ARG; -} - -/* Convert character to code to ASCII - - -b BCD - -a business-chain */ - -uint32 cvt_code_to_ascii (uint32 c, int32 sw) -{ -if (sw & SWMASK ('B')) { - if (sw & SWMASK ('A')) - return bcd_to_ascii_a[c]; - else return bcd_to_ascii_h[c]; - } -else if (sw & SWMASK ('A')) - return nine_to_ascii_a[c]; -else return nine_to_ascii_h[c]; -} - -/* 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 -*/ - -t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) -{ -uint32 i, j, c; -t_uint64 fld[3]; -t_bool ind; -t_stat r; -char gbuf[CBUFSIZE]; - -while (isspace (*cptr)) cptr++; -if ((sw & SWMASK ('C')) || ((*cptr == '\'') && cptr++)) { /* character? */ - if (cptr[0] == 0) /* must have 1 char */ - return SCPE_ARG; - val[0] = (t_value) cvt_ascii_to_code (cptr[0] & 0177, sw); - return SCPE_OK; - } -if ((sw & SWMASK ('S')) || ((*cptr == '"') && cptr++)) { /* sixbit string? */ - if (cptr[0] == 0) /* must have 1 char */ - return SCPE_ARG; - for (i = 0; i < 6; i++) { - c = cptr[0] & 0177; - if (c) - val[0] = (val[0] << 6) | ((t_value) cvt_ascii_to_code (c, sw)); - else { - val[0] = val[0] << (6 * (6 - i)); - break; - } - } - return SCPE_OK; - } - -cptr = get_glyph (cptr, gbuf, 0); /* get opcode */ -j = strlen (gbuf); /* get length */ -if (gbuf[j - 1] == '*') { /* indirect? */ - ind = TRUE; - gbuf[j - 1] = 0; - } -else ind = FALSE; -for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ; -if (opcode[i] == NULL) - return SCPE_ARG; -j = (uint32) ((opc_v[i] >> I_V_FL) & I_M_FL); /* get class */ -val[0] = opc_v[i] & DMASK; -if (ind) { - if (ind_test[j]) - val[0] |= ind_test[j]; - else return SCPE_ARG; - } - -for (i = 0; i < 3; i++) /* clear inputs */ - fld[i] = 0; -for (i = 0; (i < 3) && *cptr; i++) { /* parse inputs */ - if (i < 2) /* get glyph */ - cptr = get_glyph (cptr, gbuf, ','); - else cptr = get_glyph (cptr, gbuf, 0); - if (gbuf[0]) { /* anything? */ - fld[i] = get_uint (gbuf, 8, fld_max[j][i], &r); - if ((r != SCPE_OK) || (fld_max[j][i] == 0)) - return SCPE_ARG; - } - } -if (*cptr != 0) /* junk at end? */ - return SCPE_ARG; - -val[0] = val[0] | fld[0] | (fld[1] << INST_V_TAG) | (fld[2] << INST_V_DEC); -return SCPE_OK; -} - -/* Convert ASCII to character code - - -b BCD */ - -uint32 cvt_ascii_to_code (uint32 c, int32 sw) -{ -if (sw & SWMASK ('B')) - return ascii_to_bcd[c]; -else return ascii_to_nine[c]; -} diff --git a/Interdata/id16_cpu.c b/Interdata/id16_cpu.c deleted file mode 100644 index 702534ce..00000000 --- a/Interdata/id16_cpu.c +++ /dev/null @@ -1,2037 +0,0 @@ -/* id16_cpu.c: Interdata 16b CPU simulator - - Copyright (c) 2000-2017, 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. - - cpu Interdata 16b CPU - - 09-Mar-17 RMS OC to display testing wrong argument (COVERITY) - 28-Apr-07 RMS Removed clock initialization - 27-Oct-06 RMS Added idle support - Removed separate PASLA clock - 06-Feb-06 RMS Fixed bug in DH (Mark Hittinger) - 22-Sep-05 RMS Fixed declarations (Sterling Garwood) - 25-Aug-05 RMS Fixed DH integer overflow cases - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 10-Mar-05 RMS Fixed bug in show history routine (Mark Hittinger) - Revised examine/deposit to do words rather than bytes - 07-Nov-04 RMS Added instruction history - 22-Sep-03 RMS Added additional instruction decode types - 07-Feb-03 RMS Fixed bug in SETM, SETMR (Mark Pizzolato) - - The register state for the Interdata 16b CPU is: - - R[0:F]<0:15> general registers - F[0:7]<0:31> single precision floating point registers - D[0:7]<0:63> double precision 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 16b systems have four instruction formats: register to - register, short format, 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 | N | short format - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - 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 64K bytes. - - The Interdata 16b product line had many different models, with varying - instruction sets: - - instruction group model = 3 4 5 70 80 716 816 816E - base group (61) y y y y y y y y - AL, LM, STM (3) - y y y y y y y - single prec fp (13) - y y y y y y y - model 5 group (36) - - y y y y y y - double prec fp (17) - - - - - - y y - memory extension (4) - - - - - - - y - - This allows the most common CPU options to be covered by just five - model selections: I3, I4, I5/70/80/716, I816, and I816E. Variations - within a model (e.g., 816 with no floating point or just single - precision floating point) are not implemented. - - The I3 kept its general registers in memory; this is not simulated. - Single precision (only) floating point was implemented in microcode, - did not have a guard digit, and kept the floating point registers in - memory. Double precision floating point was implemented in hardware, - provided a guard digit for single precision (but not double), and - kept the floating point registers in hardware. - - This routine is the instruction decode routine for the Interdata CPU. - 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 armed flag, 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. - Interrupt armed flags are local to devices. If external interrupts are - enabled in the PSW, and a request is pending, an interrupt occurs. - - 3. Non-existent memory. On the Interdata 16b, 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: - - id_defs.h add device interrupt definitions - id16_sys.c add sim_devices table entry -*/ - -#include "id_defs.h" - -#define PCQ_SIZE 64 /* must be 2**n */ -#define PCQ_MASK (PCQ_SIZE - 1) -#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = oPC -#define VAMASK VAMASK16 -#define VA_S1 0x8000 /* S0/S1 flag */ - -#define UNIT_V_MSIZE (UNIT_V_UF + 0) /* dummy mask */ -#define UNIT_V_ID4 (UNIT_V_UF + 1) -#define UNIT_V_716 (UNIT_V_UF + 2) -#define UNIT_V_816 (UNIT_V_UF + 3) -#define UNIT_V_816E (UNIT_V_UF + 4) -#define UNIT_MSIZE (1 << UNIT_V_MSIZE) -#define UNIT_ID4 (1 << UNIT_V_ID4) -#define UNIT_716 (1 << UNIT_V_716) -#define UNIT_816 (1 << UNIT_V_816) -#define UNIT_816E (1 << UNIT_V_816E) -#define UNIT_TYPE (UNIT_ID4 | UNIT_716 | UNIT_816 | UNIT_816E) - -#define HIST_MIN 64 -#define HIST_MAX 65536 - -typedef struct { - uint16 vld; - uint16 pc; - uint16 ir1; - uint16 ir2; - uint16 r1; - uint16 ea; - uint16 opnd; - } InstHistory; - -#define PSW_GETMAP(x) (((x) >> PSW_V_MAP) & PSW_M_MAP) -#define SEXT16(x) (((x) & SIGN16)? ((int32) ((x) | 0xFFFF8000)): \ - ((int32) ((x) & 0x7FFF))) -#define CC_GL_16(x) if ((x) & SIGN16) \ - cc = CC_L; \ - else if (x) \ - cc = CC_G; \ - else cc = 0 -#define CC_GL_32(x) if ((x) & SIGN32) \ - cc = CC_L; \ - else if (x) \ - cc = CC_G; \ - else cc = 0 -#define BUILD_PSW(x) (((PSW & ~CC_MASK) | (x)) & psw_mask) -#define CPU_x16 (cpu_unit.flags & (UNIT_716 | UNIT_816 | UNIT_816E)) - -uint32 GREG[16] = { 0 }; /* general registers */ -uint16 *M = NULL; /* memory */ -uint32 *R = &GREG[0]; /* register set ptr */ -uint32 F[8] = { 0 }; /* sp fp registers */ -dpr_t D[8] = { {0, 0} }; /* dp fp registers */ -uint32 PSW = 0; /* processor status word */ -uint32 psw_mask = PSW_x16; /* PSW mask */ -uint32 PC = 0; /* program counter */ -uint32 SR = 0; /* switch register */ -uint32 DR = 0; /* display register */ -uint32 DRX = 0; /* display extension */ -uint32 drmod = 0; /* mode */ -uint32 srpos = 0; /* switch register pos */ -uint32 drpos = 0; /* display register pos */ -uint32 s0_rel = 0; /* S0 relocation */ -uint32 s1_rel = 0; /* S1 relocation */ -uint32 int_req[INTSZ] = { 0 }; /* interrupt requests */ -uint32 int_enb[INTSZ] = { 0 }; /* interrupt enables */ -int32 blkiop = -1; /* block I/O in prog */ -uint32 qevent = 0; /* events */ -uint32 stop_inst = 0; /* stop on ill inst */ -uint32 stop_wait = 0; /* stop on wait */ -uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ -int32 pcq_p = 0; /* PC queue ptr */ -REG *pcq_r = NULL; /* PC queue reg ptr */ -uint32 dec_flgs = 0; /* decode flags */ -uint32 fp_in_hwre = 0; /* ucode/hwre fp */ -uint32 pawidth = PAWIDTH16; /* phys addr mask */ -uint32 hst_p = 0; /* history pointer */ -uint32 hst_lnt = 0; /* history length */ -InstHistory *hst = NULL; /* instruction history */ -struct BlockIO blk_io; /* block I/O status */ -uint32 (*dev_tab[DEVNO])(uint32 dev, uint32 op, uint32 datout) = { NULL }; - -uint32 ReadB (uint32 loc); -uint32 ReadH (uint32 loc); -void WriteB (uint32 loc, uint32 val); -void WriteH (uint32 loc, uint32 val); -uint32 int_auto (uint32 dev, uint32 cc); -uint32 addtoq (uint32 ea, uint32 val, uint32 flg); -uint32 remfmq (uint32 ea, uint32 r1, uint32 flg); -uint32 newPSW (uint32 val); -uint32 swap_psw (uint32 loc, uint32 cc); -uint32 testsysq (uint32); -uint32 display (uint32 dev, uint32 op, uint32 dat); -t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); -t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); -t_stat cpu_reset (DEVICE *dptr); -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_consint (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc); - -extern t_bool devtab_init (void); -extern void int_eval (void); -extern uint32 int_getdev (void); -extern t_bool sch_blk (uint32 dev); -extern uint32 f_l (uint32 op, uint32 r1, uint32 r2, uint32 ea); -extern uint32 f_c (uint32 op, uint32 r1, uint32 r2, uint32 ea); -extern uint32 f_as (uint32 op, uint32 r1, uint32 r2, uint32 ea); -extern uint32 f_m (uint32 op, uint32 r1, uint32 r2, uint32 ea); -extern uint32 f_d (uint32 op, uint32 r1, uint32 r2, uint32 ea); -extern uint32 f_fix (uint32 op, uint32 r1, uint32 r2); -extern uint32 f_flt (uint32 op, uint32 r1, uint32 r2); - -/* Instruction decoding table - flags are first implementation */ - -const uint16 decrom[256] = { - 0, /* 00 */ - OP_RR, /* BALR */ - OP_RR, /* BTCR */ - OP_RR, /* BFCR */ - OP_RR, /* NHR */ - OP_RR, /* CLHR */ - OP_RR, /* OHR */ - OP_RR, /* XHR */ - OP_RR, /* LHR */ - OP_RR | OP_716, /* CHR */ - OP_RR, /* AHR */ - OP_RR, /* SHR */ - OP_RR, /* MHR */ - OP_RR, /* DHR */ - OP_RR, /* ACHR */ - OP_RR, /* SCHR */ - 0, 0, 0, /* 10:12 */ - OP_RR | OP_816E | OP_PRV, /* SETMR */ - 0, 0, 0, 0, /* 14:1F */ - 0, 0, 0, 0, 0, 0, 0, 0, - OP_NO | OP_716, /* BTBS */ - OP_NO | OP_716, /* BTFS */ - OP_NO | OP_716, /* BFBS */ - OP_NO | OP_716, /* BFFS */ - OP_NO | OP_716, /* LIS */ - OP_NO | OP_716, /* LCS */ - OP_NO | OP_716, /* AIS */ - OP_NO | OP_716, /* SIS */ - OP_NO | OP_ID4, /* LER */ - OP_NO | OP_ID4, /* CER */ - OP_NO | OP_ID4, /* AER */ - OP_NO | OP_ID4, /* SER */ - OP_NO | OP_ID4, /* MER */ - OP_NO | OP_ID4, /* DER */ - OP_NO | OP_816, /* FXR */ - OP_NO | OP_816, /* FLR */ - 0, 0, 0, /* 30:32 */ - OP_NO | OP_816E | OP_PRV, /* LPSR */ - 0, 0, 0, 0, /* 34:37 */ - OP_NO | OP_816 | OP_DPF, /* LDR */ - OP_NO | OP_816 | OP_DPF, /* CDR */ - OP_NO | OP_816 | OP_DPF, /* ADR */ - OP_NO | OP_816 | OP_DPF, /* SDR */ - OP_NO | OP_816 | OP_DPF, /* MDR */ - OP_NO | OP_816 | OP_DPF, /* DDR */ - OP_NO | OP_816 | OP_DPF, /* FXDR */ - OP_NO | OP_816 | OP_DPF, /* FLDR */ - OP_RX, /* STH */ - OP_RX, /* BAL */ - OP_RX, /* BTC */ - OP_RX, /* BFC */ - OP_RXH, /* NH */ - OP_RXH, /* CLH */ - OP_RXH, /* OH */ - OP_RXH, /* XH */ - OP_RXH, /* LH */ - OP_RXH | OP_716, /* CH */ - OP_RXH, /* AH */ - OP_RXH, /* SH */ - OP_RXH, /* MH */ - OP_RXH, /* DH */ - OP_RXH, /* ACH */ - OP_RXH, /* SCH */ - 0, 0, 0, /* 50:52 */ - OP_RXH | OP_816E | OP_PRV, /* SETM */ - 0, 0, 0, 0, /* 54:5F */ - 0, 0, 0, 0, 0, 0, 0, 0, - OP_RX | OP_ID4, /* STE */ - OP_RXH | OP_716, /* AHM */ - 0, 0, /* 62:63 */ - OP_RX | OP_716, /* ATL */ - OP_RX | OP_716, /* ABL */ - OP_RX | OP_716, /* RTL */ - OP_RX | OP_716, /* RBL */ - OP_RX | OP_ID4, /* LE */ - OP_RX | OP_ID4, /* CE */ - OP_RX | OP_ID4, /* AE */ - OP_RX | OP_ID4, /* SE */ - OP_RX | OP_ID4, /* ME */ - OP_RX | OP_ID4, /* DE */ - 0, 0, /* 6E:6F */ - OP_RX | OP_816 | OP_DPF, /* STD */ - OP_RX | OP_816, /* SME */ - OP_RX | OP_816, /* LME */ - OP_RXH | OP_816E | OP_PRV, /* LPS */ - 0, 0, 0, 0, /* 74:7F */ - OP_RX | OP_816 | OP_DPF, /* LD */ - OP_RX | OP_816 | OP_DPF, /* CD */ - OP_RX | OP_816 | OP_DPF, /* AD */ - OP_RX | OP_816 | OP_DPF, /* SD */ - OP_RX | OP_816 | OP_DPF, /* MD */ - OP_RX | OP_816 | OP_DPF, /* DD */ - OP_RX | OP_816 | OP_DPF, /* STMD */ - OP_RX | OP_816 | OP_DPF, /* LMD */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 80:8F */ - 0, 0, 0, 0, 0, 0, 0, 0, - OP_NO | OP_716, /* SRLS */ - OP_NO | OP_716, /* SLLS */ - OP_NO, /* STBR */ - OP_RR, /* LDBR */ - OP_RR | OP_716, /* EXBR */ - OP_NO | OP_716 | OP_PRV, /* EPSR */ - OP_RR | OP_PRV, /* WBR */ - OP_RR | OP_PRV, /* RBR */ - OP_RR | OP_716 | OP_PRV, /* WHR */ - OP_RR | OP_716 | OP_PRV, /* RHR */ - OP_RR | OP_PRV, /* WDR */ - OP_RR | OP_PRV, /* RDR */ - OP_RR | OP_716, /* MHUR */ - OP_RR | OP_PRV, /* SSR */ - OP_RR | OP_PRV, /* OCR */ - OP_RR | OP_PRV, /* AIR */ - 0, 0, 0, 0, 0, 0, 0, 0, /* A0:AF */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, /* B0:BF */ - 0, 0, 0, 0, 0, 0, 0, 0, - OP_RX, /* BXH */ - OP_RX, /* BXLE */ - OP_RX | OP_PRV, /* LPSW */ - OP_RS | OP_716, /* THI */ - OP_RS, /* NHI */ - OP_RS, /* CLHI */ - OP_RS, /* OHI */ - OP_RS, /* XHI */ - OP_RS, /* LHI */ - OP_RS | OP_716, /* CHI */ - OP_RS, /* AHI */ - OP_RS, /* SHI */ - OP_RS, /* SRHL */ - OP_RS, /* SLHL */ - OP_RS, /* SRHA */ - OP_RS, /* SLHA */ - OP_RX | OP_ID4, /* STM */ - OP_RX | OP_ID4, /* LM */ - OP_RX, /* STB */ - OP_RXB, /* LDB */ - OP_RXB | OP_716, /* CLB */ - OP_RX | OP_ID4 | OP_PRV, /* AL */ - OP_RXH | OP_PRV, /* WB */ - OP_RXH | OP_PRV, /* RB */ - OP_RX | OP_716 | OP_PRV, /* WH */ - OP_RX | OP_716 | OP_PRV, /* RH */ - OP_RX | OP_PRV, /* WD */ - OP_RX | OP_PRV, /* RD */ - OP_RXH | OP_716, /* MHU */ - OP_RX | OP_PRV, /* SS */ - OP_RX | OP_PRV, /* OC */ - OP_RX | OP_PRV, /* AI */ - 0, /* E0 */ - OP_RX | OP_716, /* SVC */ - OP_RS | OP_716 | OP_PRV, /* SINT */ - 0, 0, 0, 0, 0, 0, 0, /* E3:E9 */ - OP_RS | OP_716, /* RRL */ - OP_RS | OP_716, /* RLL */ - OP_RS | OP_716, /* SRL */ - OP_RS | OP_716, /* SLL */ - OP_RS | OP_716, /* SRA */ - OP_RS | OP_716, /* SLA */ - 0, 0, 0, 0, 0, 0, 0, 0, /* F0:FF */ - 0, 0, 0, 0, 0, 0, 0, 0 - }; - -/* 8/16E relocation constants for S0 and S1, indexed by PSW<8:11> */ - -static uint32 s0_rel_const[16] = { /* addr 0-7FFF */ - 0x00000, 0x00000, 0x00000, 0x00000, /* 0 = no reloc */ - 0x00000, 0x00000, 0x00000, 0x08000, /* 8000 = rel to S1 */ - 0x08000, 0x08000, 0x08000, 0x08000, - 0x08000, 0x08000, 0x08000, 0x00000 - }; - -static uint32 s1_rel_const[16] = { /* addr 8000-FFFF */ - 0x00000, 0x08000, 0x10000, 0x18000, /* reloc const must */ - 0x20000, 0x28000, 0x30000, 0xFFF8000, /* "sub" base addr */ - 0x00000, 0x08000, 0x10000, 0x18000, - 0x20000, 0x28000, 0x30000, 0x00000 - }; - -/* CPU data structures - - cpu_dev CPU device descriptor - cpu_unit CPU unit descriptor - cpu_reg CPU register list - cpu_mod CPU modifiers list -*/ - -DIB cpu_dib = { d_DS, -1, v_DS, NULL, &display, NULL }; - -UNIT cpu_unit = { - UDATA (NULL, UNIT_FIX | UNIT_BINK | UNIT_716, MAXMEMSIZE16) - }; - -REG cpu_reg[] = { - { HRDATA (PC, PC, 16) }, - { HRDATA (R0, GREG[0], 16) }, - { HRDATA (R1, GREG[1], 16) }, - { HRDATA (R2, GREG[2], 16) }, - { HRDATA (R3, GREG[3], 16) }, - { HRDATA (R4, GREG[4], 16) }, - { HRDATA (R5, GREG[5], 16) }, - { HRDATA (R6, GREG[6], 16) }, - { HRDATA (R7, GREG[7], 16) }, - { HRDATA (R8, GREG[8], 16) }, - { HRDATA (R9, GREG[9], 16) }, - { HRDATA (R10, GREG[10], 16) }, - { HRDATA (R11, GREG[11], 16) }, - { HRDATA (R12, GREG[12], 16) }, - { HRDATA (R13, GREG[13], 16) }, - { HRDATA (R14, GREG[14], 16) }, - { HRDATA (R15, GREG[15], 16) }, - { HRDATA (FR0, F[0], 32) }, - { HRDATA (FR2, F[1], 32) }, - { HRDATA (FR4, F[2], 32) }, - { HRDATA (FR6, F[3], 32) }, - { HRDATA (FR8, F[4], 32) }, - { HRDATA (FR10, F[5], 32) }, - { HRDATA (FR12, F[6], 32) }, - { HRDATA (FR14, F[7], 32) }, - { HRDATA (D0H, D[0].h, 32) }, - { HRDATA (D0L, D[0].l, 32) }, - { HRDATA (D2H, D[1].h, 32) }, - { HRDATA (D2L, D[1].l, 32) }, - { HRDATA (D4H, D[2].h, 32) }, - { HRDATA (D4L, D[2].l, 32) }, - { HRDATA (D6H, D[3].h, 32) }, - { HRDATA (D6L, D[3].l, 32) }, - { HRDATA (D8H, D[4].h, 32) }, - { HRDATA (D8L, D[4].l, 32) }, - { HRDATA (D10H, D[5].h, 32) }, - { HRDATA (D10L, D[5].l, 32) }, - { HRDATA (D12L, D[6].l, 32) }, - { HRDATA (D12H, D[6].h, 32) }, - { HRDATA (D14H, D[7].h, 32) }, - { HRDATA (D14L, D[7].l, 32) }, - { HRDATA (PSW, PSW, 16) }, - { HRDATA (CC, PSW, 4) }, - { HRDATA (SR, SR, 16) }, - { HRDATA (DR, DR, 32) }, - { HRDATA (DRX, DRX, 8) }, - { FLDATA (DRMOD, drmod, 0) }, - { FLDATA (SRPOS, srpos, 0) }, - { HRDATA (DRPOS, drpos, 3) }, - { BRDATA (IRQ, int_req, 16, 32, 8) }, - { BRDATA (IEN, int_enb, 16, 32, 8) }, - { HRDATA (QEVENT, qevent, 4), REG_HRO }, - { FLDATA (STOP_INST, stop_inst, 0) }, - { FLDATA (STOP_WAIT, stop_inst, 0) }, - { BRDATA (PCQ, pcq, 16, 16, PCQ_SIZE), REG_RO+REG_CIRC }, - { HRDATA (PCQP, pcq_p, 6), REG_HRO }, - { HRDATA (WRU, sim_int_char, 8) }, - { HRDATA (BLKIOD, blk_io.dfl, 16), REG_HRO }, - { HRDATA (BLKIOC, blk_io.cur, 16), REG_HRO }, - { HRDATA (BLKIOE, blk_io.end, 16), REG_HRO }, - { NULL } - }; - -MTAB cpu_mod[] = { - { UNIT_TYPE, 0, "I3", "I3", &cpu_set_model }, - { UNIT_TYPE, UNIT_ID4, "I4", "I4", &cpu_set_model }, - { UNIT_TYPE, UNIT_716, "7/16", "716", &cpu_set_model }, - { UNIT_TYPE, UNIT_816, "8/16", "816", &cpu_set_model }, - { UNIT_TYPE, UNIT_816E, "8/16E", "816E", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL }, - { 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 }, - { UNIT_MSIZE, 131072, NULL, "128K", &cpu_set_size }, - { UNIT_MSIZE, 262144, NULL, "256K", &cpu_set_size }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "CONSINT", - &cpu_set_consint, NULL, NULL }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", - &cpu_set_hist, &cpu_show_hist }, - { 0 } - }; - -DEVICE cpu_dev = { - "CPU", &cpu_unit, cpu_reg, cpu_mod, - 1, 16, 18, 2, 16, 16, - &cpu_ex, &cpu_dep, &cpu_reset, - NULL, NULL, NULL, - &cpu_dib, 0 - }; - -t_stat sim_instr (void) -{ -uint32 cc; -t_stat reason; - -/* Restore register state */ - -if (devtab_init ()) /* check conflicts */ - return SCPE_STOP; -pawidth = PAWIDTH16; /* default width */ -if (cpu_unit.flags & UNIT_816E) { /* 8/16E? */ - dec_flgs = 0; /* all instr ok */ - fp_in_hwre = 1; /* fp in hwre */ - pawidth = PAWIDTH16E; /* 18b phys addr */ - psw_mask = PSW_816E; /* mem ext bits */ - } -else if (cpu_unit.flags & UNIT_816) { /* 8/16? */ - dec_flgs = OP_816E; - fp_in_hwre = 1; - pawidth = PAWIDTH16; - psw_mask = PSW_x16; - } -else if (cpu_unit.flags & UNIT_716) { /* I5, 70, 80, 7/16? */ - dec_flgs = OP_816 | OP_816E; - fp_in_hwre = 0; - pawidth = PAWIDTH16; - psw_mask = PSW_x16; - } -else if (cpu_unit.flags & UNIT_ID4) { /* I4? */ - dec_flgs = OP_716 | OP_816 | OP_816E; - fp_in_hwre = 0; - pawidth = PAWIDTH16; - psw_mask = PSW_ID4; - } -else { - dec_flgs = OP_ID4 | OP_716 | OP_816 | OP_816E; /* I3 */ - fp_in_hwre = 0; - pawidth = PAWIDTH16; - psw_mask = PSW_ID4; - } -int_eval (); /* eval interrupts */ -cc = newPSW (PSW & psw_mask); /* split PSW, eval wait */ -reason = 0; - -/* Process events */ - -while (reason == 0) { /* loop until halted */ - uint32 dev, drom, inc, lim, opnd; - uint32 op, r1, r1p1, r2, ea, oPC; - uint32 rslt, t, map; - uint32 ir1, ir2, ityp; - int32 sr, st; - - if (sim_interval <= 0) { /* check clock queue */ - if ((reason = sim_process_event ())) - break; - int_eval (); - } - - if (qevent) { /* any events? */ - if (qevent & EV_BLK) { /* block I/O in prog? */ - dev = blk_io.dfl & DEV_MAX; /* get device */ - cc = dev_tab[dev] (dev, IO_SS, 0) & 0xF; /* sense status */ - if (cc == STA_BSY) { /* just busy? */ - sim_interval = 0; /* force I/O event */ - continue; - } - else if (cc == 0) { /* ready? */ - if (blk_io.dfl & BL_RD) { /* read? */ - t = dev_tab[dev] (dev, IO_RD, 0); /* get byte */ - if ((t == 0) && (blk_io.dfl & BL_LZ)) - continue; - blk_io.dfl = blk_io.dfl & ~BL_LZ; /* non-zero seen */ - WriteB (blk_io.cur, t); /* write mem */ - } - else { /* write */ - t = ReadB (blk_io.cur); /* read mem */ - dev_tab[dev] (dev, IO_WD, t); /* put byte */ - } - if (blk_io.cur != blk_io.end) { /* more to do? */ - blk_io.cur = (blk_io.cur + 1) & VAMASK; /* incr addr */ - continue; - } - } - qevent = qevent & ~EV_BLK; /* clr block I/O flg */ - int_eval (); /* re-eval intr */ - continue; - } - - if ((qevent & EV_INT) && (PSW & PSW_EXI)) { /* interrupt? */ - if (PSW & PSW_AIO) { /* auto enabled? */ - dev = int_getdev (); /* get int dev */ - cc = int_auto (dev, cc); /* do auto intr */ - int_eval (); /* re-eval intr */ - } - else cc = swap_psw (EXIPSW, cc); /* old type, swap */ - continue; - } - - if (PSW & PSW_WAIT) { /* wait state? */ - sim_idle (TMR_LFC, TRUE); /* idling */ - continue; - } - - qevent = 0; /* no events */ - } /* end if event */ - -/* Fetch and decode instruction */ - - if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; - } - - sim_interval = sim_interval - 1; - - ir1 = ReadH (oPC = PC); /* fetch instr */ - op = (ir1 >> 8) & 0xFF; /* isolate op, R1, R2 */ - r1 = (ir1 >> 4) & 0xF; - r2 = ir1 & 0xF; - drom = decrom[op]; - ityp = drom & OP_MASK; - - if ((drom == 0) || (drom & dec_flgs)) { /* not in model? */ - if (stop_inst) /* stop or */ - reason = STOP_RSRV; - else cc = swap_psw (ILOPSW, cc); /* swap PSW */ - continue; - } - if ((drom & OP_PRV) && (PSW & PSW_PRO)) { /* priv & protected? */ - cc = swap_psw (ILOPSW, cc); /* swap PSW */ - continue; - } - - switch (ityp) { /* decode instruction */ - - case OP_NO: /* no operand */ - opnd = r2; /* assume short */ - break; - - case OP_RR: /* reg-reg */ - opnd = R[r2]; /* operand is R2 */ - break; - - case OP_RS: /* reg-storage */ - case OP_RX: /* reg-mem */ - PC = (PC + 2) & VAMASK; /* increment PC */ - ir2 = ea = ReadH (PC); /* fetch address */ - if (r2) /* index calculation */ - ea = (ir2 + R[r2]) & VAMASK; - opnd = ea; /* operand is ea */ - break; - - case OP_RXB: /* reg-mem byte */ - PC = (PC + 2) & VAMASK; /* increment PC */ - ir2 = ea = ReadH (PC); /* fetch address */ - if (r2) /* index calculation */ - ea = (ir2 + R[r2]) & VAMASK; - opnd = ReadB (ea); /* fetch operand */ - break; - - case OP_RXH: /* reg-mem halfword */ - PC = (PC + 2) & VAMASK; /* increment PC */ - ir2 = ea = ReadH (PC); /* fetch address */ - if (r2) /* index calculation */ - ea = (ir2 + R[r2]) & VAMASK; - opnd = ReadH (ea); /* fetch operand */ - break; - - default: - return SCPE_IERR; - } - - if (hst_lnt) { /* instruction history? */ - hst[hst_p].vld = 1; - hst[hst_p].pc = oPC; - hst[hst_p].ir1 = ir1; - hst[hst_p].ir2 = ir2; - hst[hst_p].r1 = R[r1]; - hst[hst_p].ea = ea; - hst[hst_p].opnd = opnd; - hst_p = hst_p + 1; - if (hst_p >= hst_lnt) - hst_p = 0; - } - - PC = (PC + 2) & VAMASK; /* increment PC */ - switch (op) { /* case on opcode */ - -/* Load/store instructions */ - - case 0x08: /* LHR - RR */ - case 0x24: /* LIS - NO */ - case 0x48: /* LH - RXH */ - case 0xC8: /* LHI - RS */ - R[r1] = opnd; /* load operand */ - CC_GL_16 (R[r1]); /* set G,L */ - break; - - case 0x25: /* LCS - NO */ - R[r1] = (~opnd + 1) & DMASK16; /* load complement */ - CC_GL_16 (R[r1]); /* set G,L */ - break; - - case 0x40: /* STH - RX */ - WriteH (ea, R[r1]); /* store register */ - break; - - case 0xD1: /* LM - RX */ - for ( ; r1 <= 0xF; r1++) { /* loop thru reg */ - R[r1] = ReadH (ea); /* load register */ - ea = (ea + 2) & VAMASK; /* incr mem addr */ - } - break; - - case 0xD0: /* STM - RX */ - for ( ; r1 <= 0xF; r1++) { /* loop thru reg */ - WriteH (ea, R[r1]); /* store register */ - ea = (ea + 2) & VAMASK; /* incr mem addr */ - } - break; - - case 0x93: /* LDBR - RR */ - case 0xD3: /* LDB - RXB */ - R[r1] = opnd & DMASK8; /* load byte */ - break; - - case 0x92: /* STBR - NO */ - R[r2] = (R[r2] & ~DMASK8) | (R[r1] & DMASK8); /* store byte */ - break; - case 0xD2: /* STB - RX */ - WriteB (ea, R[r1] & DMASK8); /* store byte */ - break; - - case 0x94: /* EXBR - RR */ - R[r1] = (opnd >> 8) | ((opnd & DMASK8) << 8); - break; - -/* Control instructions */ - - case 0x01: /* BALR - RR */ - case 0x41: /* BAL - RX */ - PCQ_ENTRY; /* save old PC */ - R[r1] = PC; /* save cur PC */ - PC = opnd; /* branch */ - break; - - case 0x02: /* BTCR - RR */ - case 0x42: /* BTC - RX */ - if (cc & r1) { /* test CC's */ - PCQ_ENTRY; /* branch if true */ - PC = opnd; - } - break; - - case 0x20: /* BTBS - NO */ - if (cc & r1) { /* test CC's */ - PCQ_ENTRY; /* branch if true */ - PC = (oPC - r2 - r2) & VAMASK; - } - break; - - case 0x21: /* BTFS - NO */ - if (cc & r1) { /* test CC's */ - PCQ_ENTRY; /* branch if true */ - PC = (oPC + r2 + r2) & VAMASK; - } - break; - - case 0x03: /* BFCR - RR */ - case 0x43: /* BFC - RX */ - if ((cc & r1) == 0) { /* test CC's */ - PCQ_ENTRY; /* branch if false */ - PC = opnd; - } - break; - - case 0x22: /* BFBS - NO */ - if ((cc & r1) == 0) { /* test CC's */ - PCQ_ENTRY; /* branch if false */ - PC = (oPC - r2 - r2) & VAMASK; - } - break; - - case 0x23: /* BFFS - NO */ - if ((cc & r1) == 0) { /* test CC's */ - PCQ_ENTRY; /* branch if false */ - PC = (oPC + r2 + r2) & VAMASK; - } - break; - - case 0xC0: /* BXH - RX */ - inc = R[(r1 + 1) & 0xF]; /* inc = R1 + 1 */ - lim = R[(r1 + 2) & 0xF]; /* lim = R1 + 2 */ - R[r1] = (R[r1] + inc) & DMASK16; /* R1 = R1 + inc */ - if (R[r1] > lim) { /* if R1 > lim */ - PCQ_ENTRY; /* branch */ - PC = opnd; - } - break; - - case 0xC1: /* BXLE - RX */ - inc = R[(r1 + 1) & 0xF]; /* inc = R1 + 1 */ - lim = R[(r1 + 2) & 0xF]; /* lim = R1 + 2 */ - R[r1] = (R[r1] + inc) & DMASK16; /* R1 = R1 + inc */ - if (R[r1] <= lim) { /* if R1 <= lim */ - PCQ_ENTRY; /* branch */ - PC = opnd; - } - break; - -/* Logical instructions */ - - case 0x04: /* NHR - RR */ - case 0x44: /* NH - RXH */ - case 0xC4: /* NHI - RS */ - R[r1] = R[r1] & opnd; /* result */ - CC_GL_16 (R[r1]); /* set G,L */ - break; - - case 0x06: /* OHR - RR */ - case 0x46: /* OH - RXH */ - case 0xC6: /* OHI - RS */ - R[r1] = R[r1] | opnd; /* result */ - CC_GL_16 (R[r1]); /* set G,L */ - break; - - case 0x07: /* XHR - RR */ - case 0x47: /* XH - RXH */ - case 0xC7: /* XHI - RS */ - R[r1] = R[r1] ^ opnd; /* result */ - CC_GL_16 (R[r1]); /* set G,L */ - break; - - case 0xC3: /* THI - RS */ - rslt = R[r1] & opnd; /* result */ - CC_GL_16 (rslt); /* set G, L */ - break; - - case 0x05: /* CLHR - RR */ - case 0x45: /* CLH - RXH */ - case 0xC5: /* CLHI - RS */ - rslt = (R[r1] - opnd) & DMASK16; /* result */ - CC_GL_16 (rslt); /* set G,L */ - if (R[r1] < opnd) /* set C if borrow */ - cc = cc | CC_C; - if (((R[r1] ^ opnd) & (~opnd ^ rslt)) & SIGN16) - cc = cc | CC_V; - break; - - case 0xD4: /* CLB - RXB */ - t = R[r1] & DMASK8; - rslt = (t - opnd) & DMASK16; /* result */ - CC_GL_16 (rslt); /* set G,L */ - if (t < opnd) /* set C if borrow */ - cc = cc | CC_C; - break; - -/* Shift instructions */ - - case 0xCC: /* SRHL - RS */ - opnd = opnd & 0xF; /* shift count */ - case 0x90: /* SRLS - NO */ - rslt = R[r1] >> opnd; /* result */ - CC_GL_16 (rslt); /* set G,L */ - if (opnd && ((R[r1] >> (opnd - 1)) & 1)) - cc = cc | CC_C; - R[r1] = rslt; /* store result */ - break; - - case 0xCD: /* SLHL - RS */ - opnd = opnd & 0xF; /* shift count */ - case 0x91: /* SLLS - NO */ - rslt = R[r1] << opnd; /* raw result */ - R[r1] = rslt & DMASK16; /* masked result */ - CC_GL_16 (R[r1]); /* set G,L */ - if (opnd && (rslt & 0x10000)) /* set C if shft out */ - cc = cc | CC_C; - break; - - case 0xCE: /* SRHA - RS */ - opnd = opnd & 0xF; /* shift count */ - rslt = (SEXT16 (R[r1]) >> opnd) & DMASK16; /* result */ - CC_GL_16 (rslt); /* set G,L */ - if (opnd && ((R[r1] >> (opnd - 1)) & 1)) - cc = cc | CC_C; - R[r1] = rslt; /* store result */ - break; - - case 0xCF: /* SLHA - RS */ - opnd = opnd & 0xF; /* shift count */ - rslt = R[r1] << opnd; /* raw result */ - R[r1] = (R[r1] & SIGN16) | (rslt & MMASK16); /* arith result */ - CC_GL_16 (R[r1]); /* set G,L */ - if (opnd && (rslt & SIGN16)) /* set C if shft out */ - cc = cc | CC_C; - break; - - case 0xEA: /* RRL - RS */ - r1p1 = (r1 + 1) & 0xF; /* R1 + 1 */ - opnd = opnd & 0x1F; /* shift count */ - t = (R[r1] << 16) | R[r1p1]; /* form 32b op */ - if (opnd) /* result */ - rslt = (t >> opnd) | (t << (32 - opnd)); - else rslt = t; /* no shift */ - CC_GL_32 (rslt); /* set G,L 32b */ - R[r1] = (rslt >> 16) & DMASK16; /* hi result */ - R[r1p1] = rslt & DMASK16; /* lo result */ - break; - - case 0xEB: /* RLL - RS */ - r1p1 = (r1 + 1) & 0xF; /* R1 + 1 */ - opnd = opnd & 0x1F; /* shift count */ - t = (R[r1] << 16) | R[r1p1]; /* form 32b op */ - if (opnd) /* result */ - rslt = (t << opnd) | (t >> (32 - opnd)); - else rslt = t; /* no shift */ - CC_GL_32 (rslt); /* set G,L 32b */ - R[r1] = (rslt >> 16) & DMASK16; /* hi result */ - R[r1p1] = rslt & DMASK16; /* lo result */ - break; - - case 0xEC: /* SRL - RS */ - r1p1 = (r1 + 1) & 0xF; /* R1 + 1 */ - opnd = opnd & 0x1F; /* shift count */ - t = (R[r1] << 16) | R[r1p1]; /* form 32b op */ - rslt = t >> opnd; /* result */ - CC_GL_32 (rslt); /* set G,L 32b */ - if (opnd && ((t >> (opnd - 1)) & 1)) - cc = cc | CC_C; - R[r1] = (rslt >> 16) & DMASK16; /* hi result */ - R[r1p1] = rslt & DMASK16; /* lo result */ - break; - - case 0xED: /* SLL - RS */ - r1p1 = (r1 + 1) & 0xF; /* R1 + 1 */ - opnd = opnd & 0x1F; /* shift count */ - t = (R[r1] << 16) | R[r1p1]; /* form 32b op */ - rslt = t << opnd; /* result */ - CC_GL_32 (rslt); /* set G,L 32b */ - if (opnd && ((t << (opnd - 1)) & SIGN32)) - cc = cc | CC_C; - R[r1] = (rslt >> 16) & DMASK16; /* hi result */ - R[r1p1] = rslt & DMASK16; /* lo result */ - break; - - case 0xEE: /* SRA - RS */ - r1p1 = (r1 + 1) & 0xF; /* R1 + 1 */ - opnd = opnd & 0x1F; /* shift count */ - t = (R[r1] << 16) | R[r1p1]; /* form 32b op */ - rslt = ((int32) t) >> opnd; /* signed result */ - CC_GL_32 (rslt); /* set G,L 32b */ - if (opnd && ((t >> (opnd - 1)) & 1)) - cc = cc | CC_C; - R[r1] = (rslt >> 16) & DMASK16; /* hi result */ - R[r1p1] = rslt & DMASK16; /* lo result */ - break; - - case 0xEF: /* SLA - RS */ - r1p1 = (r1 + 1) & 0xF; /* R1 + 1 */ - opnd = opnd & 0x1F; /* shift count */ - t = (R[r1] << 16) | R[r1p1]; /* form 32b op */ - rslt = (t & SIGN32) | ((t << opnd) & MMASK32); /* signed result */ - CC_GL_32 (rslt); /* set G,L 32b */ - if (opnd && ((t << opnd) & SIGN32)) - cc = cc | CC_C; - R[r1] = (rslt >> 16) & DMASK16; /* hi result */ - R[r1p1] = rslt & DMASK16; /* lo result */ - break; - -/* Arithmetic instructions */ - - case 0x0A: /* AHR - RR */ - case 0x26: /* AIS - NO */ - case 0x4A: /* AH - RXH */ - case 0xCA: /* AHI - RS */ - rslt = (R[r1] + opnd) & DMASK16; /* result */ - CC_GL_16 (rslt); /* set G,L */ - if (rslt < opnd) /* set C if carry */ - cc = cc | CC_C; - if (((~R[r1] ^ opnd) & (R[r1] ^ rslt)) & SIGN16) - cc = cc | CC_V; - R[r1] = rslt; - break; - - case 0x61: /* AHM - RXH */ - rslt = (R[r1] + opnd) & DMASK16; /* result */ - CC_GL_16 (rslt); /* set G,L */ - if (rslt < opnd) /* set C if carry */ - cc = cc | CC_C; - if (((~R[r1] ^ opnd) & (R[r1] ^ rslt)) & SIGN16) - cc = cc | CC_V; - WriteH (ea, rslt); /* store in memory */ - break; - - case 0x0B: /* SHR - RR */ - case 0x27: /* SIS - NO */ - case 0x4B: /* SH - RXH */ - case 0xCB: /* SHI - RS */ - rslt = (R[r1] - opnd) & DMASK16; /* result */ - CC_GL_16 (rslt); /* set G,L */ - if (R[r1] < opnd) /* set C if borrow */ - cc = cc | CC_C; - if (((R[r1] ^ opnd) & (~opnd ^ rslt)) & SIGN16) - cc = cc | CC_V; - R[r1] = rslt; - break; - - case 0x09: /* CHR - RR */ - case 0x49: /* CH - RXH */ - case 0xC9: /* CHI - RS */ - sr = SEXT16 (R[r1]); /* sign ext */ - st = SEXT16 (opnd); - if (sr < st) /* < sets C, L */ - cc = CC_C | CC_L; - else if (sr > st) /* > sets G */ - cc = CC_G; - else cc = 0; - if (((R[r1] ^ opnd) & (~opnd ^ (sr - st))) & SIGN16) - cc = cc | CC_V; - break; - - case 0x0C: /* MHR - RR */ - case 0x4C: /* MH - RXH */ - r1p1 = (r1 + 1) & 0xF; /* R1 + 1 */ - rslt = SEXT16 (R[r1p1]) * SEXT16 (opnd); /* multiply */ - R[r1] = (rslt >> 16) & DMASK16; /* hi result */ - R[r1p1] = rslt & DMASK16; /* lo result */ - break; - - case 0x9C: /* MHUR - RR */ - case 0xDC: /* MHU - RXH */ - r1p1 = (r1 + 1) & 0xF; /* R1 + 1 */ - rslt = R[r1p1] * opnd; /* multiply, unsigned */ - R[r1] = (rslt >> 16) & DMASK16; /* hi result */ - R[r1p1] = rslt & DMASK16; /* lo result */ - break; - - case 0x0D: /* DHR - RR */ - case 0x4D: /* DH - RXH */ - r1p1 = (r1 + 1) & 0xF; /* R1 + 1 */ - if ((opnd == 0) || - ((R[r1] == 0x8000) && (R[r1p1] == 0) && (opnd == 0xFFFF))) { - if (PSW & PSW_AFI) /* div fault enabled? */ - cc = swap_psw (AFIPSW, cc); /* swap PSW */ - break; - } - sr = (R[r1] << 16) | R[r1p1]; /* signed 32b divd */ - st = sr / SEXT16 (opnd); /* signed quotient */ - sr = sr % SEXT16 (opnd); /* remainder */ - if ((st < 0x8000) && (st >= -0x8000)) { /* if quo fits */ - R[r1] = sr & DMASK16; /* store remainder */ - R[r1p1] = st & DMASK16; /* store quotient */ - } - else if (PSW & PSW_AFI) /* div fault enabled? */ - cc = swap_psw (AFIPSW, cc); /* swap PSW */ - break; - - case 0x0E: /* ACHR - RR */ - case 0x4E: /* ACH - RXH */ - t = R[r1] + opnd + ((cc & CC_C) != 0); /* raw result */ - rslt = t & DMASK16; /* masked result */ - CC_GL_16 (rslt); /* set G,L */ - if (t > DMASK16) /* set C if carry */ - cc = cc | CC_C; - if (((~R[r1] ^ opnd) & (R[r1] ^ rslt)) & SIGN16) - cc = cc | CC_V; - R[r1] = rslt; /* store result */ - break; - - case 0x0F: /* SCHR - RR */ - case 0x4F: /* SCH - RXH */ - t = R[r1] - opnd - ((cc & CC_C) != 0); /* raw result */ - rslt = t & DMASK16; /* masked result */ - CC_GL_16 (rslt); /* set G,L */ - if (t > DMASK16) /* set C if borrow */ - cc = cc | CC_C; - if (((R[r1] ^ opnd) & (~opnd ^ rslt)) & SIGN16) - cc = cc | CC_V; - R[r1] = rslt; /* store result */ - break; - -/* Floating point instructions */ - - case 0x28: /* LER - NO */ - case 0x38: /* LDR - NO */ - case 0x68: /* LE - RX */ - case 0x78: /* LD - RX */ - cc = f_l (op, r1, r2, ea); /* load */ - if ((cc & CC_V) && (PSW & PSW_FPF) && CPU_x16) /* V set, x/16? */ - cc = swap_psw (FPFPSW, cc); - break; - - case 0x29: /* CER - NO */ - case 0x39: /* CDR - NO */ - case 0x69: /* CE - RX */ - case 0x79: /* CD - RX */ - cc = f_c (op, r1, r2, ea); /* compare */ - break; - - case 0x2A: /* AER - NO */ - case 0x2B: /* SER - NO */ - case 0x3A: /* ADR - NO */ - case 0x3B: /* SDR - NO */ - case 0x6A: /* AE - RX */ - case 0x6B: /* SE - RX */ - case 0x7A: /* AD - RX */ - case 0x7B: /* SD - RX */ - cc = f_as (op, r1, r2, ea); /* add/sub */ - if ((cc & CC_V) && (PSW & PSW_FPF) && CPU_x16) /* V set, x/16? */ - cc = swap_psw (FPFPSW, cc); - break; - - case 0x2C: /* MER - NO */ - case 0x3C: /* MDR - NO */ - case 0x6C: /* ME - RX */ - case 0x7C: /* MD - RX */ - cc = f_m (op, r1, r2, ea); /* multiply */ - if ((cc & CC_V) && (PSW & PSW_FPF) && CPU_x16) /* V set, x/16? */ - cc = swap_psw (FPFPSW, cc); - break; - - case 0x2D: /* DER - NO */ - case 0x3D: /* DDR - NO */ - case 0x6D: /* DE - RX */ - case 0x7D: /* DD - RX */ - cc = f_d (op, r1, r2, ea); /* perform divide */ - if ((cc & CC_V) && ((cc & CC_C) || /* V set, x/16 or */ - ((PSW & PSW_FPF) && CPU_x16))) /* V & C set? */ - cc = swap_psw (FPFPSW, cc); - break; - - case 0x2E: /* FXR - NO */ - case 0x3E: /* FXDR - NO */ - cc = f_fix (op, r1, r2); /* cvt to integer */ - break; - - case 0x2F: /* FLR - NO */ - case 0x3F: /* FLDR - NO */ - cc = f_flt (op, r1, r2); /* cvt to floating */ - break; - - case 0x60: /* STE - RX */ - t = ReadFReg (r1); /* get fp reg */ - WriteF (ea, t, P); /* write */ - break; - - case 0x70: /* STD - RX */ - WriteF (ea, D[r1 >> 1].h, P); /* write hi */ - WriteF ((ea + 4) & VAMASK, D[r1 >> 1].l, P); /* write lo */ - break; - - case 0x71: /* STME - RX */ - for ( ; r1 <= 0xE; r1 = r1 + 2) { /* loop thru reg */ - t = ReadFReg (r1); /* get fp reg */ - WriteF (ea, t, P); /* write */ - ea = (ea + 4) & VAMASK; /* incr mem addr */ - } - break; - - case 0x72: /* LME - RX */ - for ( ; r1 <= 0xE; r1 = r1 + 2) { /* loop thru reg */ - t = ReadF (ea, P); /* get value */ - WriteFReg (r1, t); /* write reg */ - ea = (ea + 4) & VAMASK; /* incr mem addr */ - } - break; - - case 0x7E: /* STMD - RX */ - for ( ; r1 <= 0xE; r1 = r1 + 2) { /* loop thru reg */ - WriteF (ea, D[r1 >> 1].h, P); /* write register */ - WriteF ((ea + 4) & VAMASK, D[r1 >> 1].l, P); - ea = (ea + 8) & VAMASK; /* incr mem addr */ - } - break; - - case 0x7F: /* LMD - RX */ - for ( ; r1 <= 0xE; r1 = r1 + 2) { /* loop thru reg */ - D[r1 >> 1].h = ReadF (ea, P); /* load register */ - D[r1 >> 1].l = ReadF ((ea + 4) & VAMASK, P); - ea = (ea + 8) & VAMASK; /* incr mem addr */ - } - break; - -/* Miscellaneous */ - - case 0xE1: /* SVC - RX */ - PCQ_ENTRY; /* save PC */ - WriteH (SVCAP, ea); /* save opnd */ - WriteH (SVOPS, BUILD_PSW (cc)); /* save PS */ - WriteH (SVOPC, PC); /* save PC */ - PC = ReadH (SVNPC + r1 + r1); /* new PC */ - cc = newPSW (ReadH (SVNPS)); /* new PS */ - break; - - case 0xE2: /* SINT - RS */ - dev = opnd & DEV_MAX; /* get dev */ - cc = int_auto (dev, cc); /* auto intr */ - int_eval (); /* re-eval intr */ - break; - - case 0xC2: /* LPSW - RX */ - PCQ_ENTRY; /* effective branch */ - PC = ReadH ((ea + 2) & VAMASK); /* read PC */ - cc = newPSW (ReadH (ea)); /* read PSW */ - if (PSW & PSW_SQI) /* test for q */ - cc = testsysq (cc); - break; - - case 0x95: /* EPSR - NO */ - R[r1] = BUILD_PSW (cc); /* save PSW */ - case 0x33: /* LPSR - NO */ - cc = newPSW (R[r2]); /* load new PSW */ - if (PSW & PSW_SQI) /* test for q */ - cc = testsysq (cc); - break; - - case 0x73: /* LPS - RXH */ - cc = newPSW (opnd); /* load new PSW */ - if (PSW & PSW_SQI) /* test for q */ - cc = testsysq (cc); - break; - - case 0x64: /* ATL - RX */ - case 0x65: /* ABL - RX */ - cc = addtoq (ea, R[r1], op & 1); /* add to q */ - break; - - case 0x66: /* RTL - RX */ - case 0x67: /* RBL - RX */ - cc = remfmq (ea, r1, op & 1); /* remove from q */ - break; - - case 0x13: /* SETMR - RR */ - case 0x53: /* SETM - RXH */ - t = BUILD_PSW (cc); /* old PSW */ - map = PSW_GETMAP (opnd); /* get new map */ - switch (map) { /* case on map */ - - case 0x7: - map = 0; /* use 1:1 map */ - R[r1] = R[r1] ^ SIGN16; /* flip sign */ - break; - - case 0x8: case 0x9: case 0xA: case 0xB: - case 0xC: case 0xD: case 0xE: - if (R[r1] & SIGN16) /* S1? clr map<0> */ - map = map & ~0x8; - else { - map = 0; /* else 1:1 map */ - R[r1] = R[r1] | SIGN16; /* set sign */ - } - break; - - default: - break; - } - t = (t & ~PSW_MAP) | (map << PSW_V_MAP); /* insert map */ - newPSW (t); /* load new PSW */ - CC_GL_16 (R[r1]); /* set G,L */ - break; - -/* I/O instructions */ - -case 0xDE: /* OC - RX */ - opnd = ReadB (ea); /* fetch operand */ - case 0x9E: /* OCR - RR */ - dev = R[r1] & DEV_MAX; - if (DEV_ACC (dev)) { - dev_tab[dev] (dev, IO_ADR, 0); /* select */ - dev_tab[dev] (dev, IO_OC, opnd & DMASK8); /* send command */ - int_eval (); /* re-eval intr */ - cc = 0; - } - else cc = CC_V; - break; - - case 0xDA: /* WD - RX */ - opnd = ReadB (ea); /* fetch operand */ - case 0x9A: /* WDR - RR */ - dev = R[r1] & DEV_MAX; - if (DEV_ACC (dev)) { - dev_tab[dev] (dev, IO_ADR, 0); /* select */ - dev_tab[dev] (dev, IO_WD, opnd & DMASK8); /* send data */ - int_eval (); /* re-eval intr */ - cc = 0; - } - else cc = CC_V; - break; - - case 0xD8: /* WH - RX */ - opnd = ReadH (ea); /* fetch operand */ - case 0x98: /* WHR - RR */ - dev = R[r1] & DEV_MAX; - if (DEV_ACC (dev)) { - if (dev_tab[dev] (dev, IO_ADR, 0)) /* select; hw ok? */ - dev_tab[dev] (dev, IO_WH, opnd); /* send data */ - else { /* byte only */ - dev_tab[dev] (dev, IO_WD, opnd >> 8); /* send hi byte */ - dev_tab[dev] (dev, IO_WD, opnd & DMASK8); /* send lo byte */ - } - int_eval (); /* re-eval intr */ - cc = 0; - } - else cc = CC_V; - break; - - case 0x9B: /* RDR - RR */ - case 0xDB: /* RD - RX */ - dev = R[r1] & DEV_MAX; - if (DEV_ACC (dev)) { /* dev exist? */ - dev_tab[dev] (dev, IO_ADR, 0); /* select */ - t = dev_tab[dev] (dev, IO_RD, 0); /* get data */ - cc = 0; - } - else { /* no */ - t = 0; /* read zero */ - cc = CC_V; /* set V */ - } - if (OP_TYPE (op) != OP_RR) /* RX or RR? */ - WriteB (ea, t); - else R[r2] = t & DMASK8; - int_eval (); /* re-eval intr */ - break; - - case 0x99: /* RHR - RR */ - case 0xD9: /* RH - RX */ - dev = R[r1] & DEV_MAX; - if (DEV_ACC (dev)) { /* dev exist? */ - if (dev_tab[dev] (dev, IO_ADR, 0)) /* select, hw ok? */ - t = dev_tab[dev] (dev, IO_RH, 0); /* get data */ - else { /* byte only */ - rslt = dev_tab[dev] (dev, IO_RD, 0); /* get byte */ - t = dev_tab[dev] (dev, IO_RD, 0); /* get byte */ - t = (rslt << 8) | t; /* merge */ - } - cc = 0; - } - else { /* no */ - t = 0; /* read zero */ - cc = CC_V; /* set V */ - } - if (OP_TYPE (op) != OP_RR) /* RX or RR? */ - WriteH (ea, t); - else R[r2] = t; - int_eval (); /* re-eval intr */ - break; - - case 0x9F: /* AIR - RR */ - case 0xDF: /* AI - RX */ - R[r1] = int_getdev (); /* get int dev */ - /* fall through */ - case 0x9D: /* SSR - RR */ - case 0xDD: /* SS - RX */ - dev = R[r1] & DEV_MAX; - if (DEV_ACC (dev)) { /* dev exist? */ - dev_tab[dev] (dev, IO_ADR, 0); /* select */ - t = dev_tab[dev] (dev, IO_SS, 0); /* get status */ - } - else t = STA_EX; /* no */ - if (OP_TYPE (op) != OP_RR) /* RR or RX? */ - WriteB (ea, t); - else R[r2] = t & DMASK8; - cc = t & 0xF; - int_eval (); /* re-eval intr */ - break; - -/* Block I/O instructions - - On a real Interdata system, the block I/O instructions can't be - interrupted or stopped. To model this behavior, while allowing - the instructions to go back through fetch for I/O processing and - WRU testing, the simulator implements a 'block I/O in progress' - flag and status block. If a block I/O is in progress, normal - interrupts and fetches are suppressed until the block I/O is done. -*/ - - case 0x96: /* WBR - RR */ - case 0xD6: /* WB - RXH */ - dev = R[r1] & DEV_MAX; - if (DEV_ACC (dev)) { /* dev exist? */ - if (OP_TYPE (op) != OP_RR) - lim = ReadH ((ea + 2) & VAMASK); - else lim = R[(r2 + 1) & 0xF]; - if (opnd > lim) /* start > end? */ - cc = 0; - else { /* no, start I/O */ - dev_tab[dev] (dev, IO_ADR, 0); /* select dev */ - blk_io.dfl = dev; /* set status block */ - blk_io.cur = opnd; - blk_io.end = lim; - qevent = qevent | EV_BLK; /* I/O in prog */ - } - } - else cc = CC_V; /* nx dev */ - break; - - case 0x97: /* RBR - RR */ - case 0xD7: /* RB - RXH */ - dev = R[r1] & DEV_MAX; - if (DEV_ACC (dev)) { /* dev exist? */ - if (OP_TYPE (op) != OP_RR) - lim = ReadH ((ea + 2) & VAMASK); - else lim = R[(r2 + 1) & 0xF]; - if (opnd > lim) /* start > end? */ - cc = 0; - else { /* no, start I/O */ - dev_tab[dev] (dev, IO_ADR, 0); /* select dev */ - blk_io.dfl = dev | BL_RD; /* set status block */ - blk_io.cur = opnd; - blk_io.end = lim; - qevent = qevent | EV_BLK; /* I/O in prog */ - } - } - else cc = CC_V; /* nx dev */ - break; - - case 0xD5: /* AL - RX */ - dev = ReadB (AL_DEV); /* get device */ - t = ReadB (AL_IOC); /* get command */ - if (DEV_ACC (dev)) { /* dev exist? */ - if (AL_BUF > ea) /* start > end? */ - cc = 0; - else { /* no, start I/O */ - dev_tab[dev] (dev, IO_ADR, 0); /* select dev */ - dev_tab[dev] (dev, IO_OC, t); /* start dev */ - blk_io.dfl = dev | BL_RD | BL_LZ; /* set status block */ - blk_io.cur = AL_BUF; - blk_io.end = ea; - qevent = qevent | EV_BLK; /* I/O in prog */ - } - } - else cc = CC_V; /* nx dev */ - break; - } /* end switch */ - } /* end while */ - -/* Simulation halted */ - -PSW = BUILD_PSW (cc); -PC = PC & VAMASK; -pcq_r->qptr = pcq_p; /* update pc q ptr */ -return reason; -} - -/* Load new PSW and memory map */ - -uint32 newPSW (uint32 val) -{ -PSW = val & psw_mask; /* store PSW */ -int_eval (); /* update intreq */ -if (PSW & PSW_WAIT) /* wait state? */ - qevent = qevent | EV_WAIT; -else qevent = qevent & ~EV_WAIT; -if (cpu_unit.flags & UNIT_816E) { /* mapping enabled? */ - uint32 map = PSW_GETMAP (PSW); /* get new map */ - s0_rel = s0_rel_const[map]; /* set relocation */ - s1_rel = s1_rel_const[map]; /* constants */ - } -else s0_rel = s1_rel = 0; /* no relocation */ -if (PSW & PSW_AIO) /* PSW<4> controls */ - SET_ENB (v_DS); -else CLR_ENB (v_DS); /* DS interrupts */ -return PSW & CC_MASK; -} - -/* Swap PSW */ - -uint32 swap_psw (uint32 loc, uint32 cc) -{ -WriteH (loc, BUILD_PSW (cc)); /* write PSW, PC */ -WriteH (loc + 2, PC); -cc = newPSW (ReadH (loc + 4)); /* read PSW, PC */ -PC = ReadH (loc + 6); -if (PSW & PSW_SQI) /* sys q int enb? */ - cc = testsysq (cc); -return cc; /* return CC */ -} - -/* Test for queue interrupts */ - -uint32 testsysq (uint32 cc) -{ -int32 qb = ReadH (SQP); /* get sys q addr */ -int32 usd = ReadB (qb + Q16_USD); /* get use count */ - -if (usd) { /* any entries? */ - WriteH (SQIPSW, BUILD_PSW (cc)); /* swap PSW */ - WriteH (SQIPSW + 2, PC); - cc = newPSW (ReadH (SQIPSW + 4)); - PC = ReadH (SQIPSW + 6); - } -return cc; -} - -/* Add to head of queue */ - -uint32 addtoq (uint32 ea, uint32 val, uint32 flg) -{ -uint32 slt, usd, wra, t; - -t = ReadH (ea); /* slots/used */ -slt = (t >> 8) & DMASK8; /* # slots */ -usd = t & DMASK8; /* # used */ -if (usd >= slt) /* list full? */ - return CC_V; -usd = usd + 1; /* inc # used */ -WriteB (ea + Q16_USD, usd); /* rewrite */ -if (flg) { /* ABL? */ - wra = ReadB ((ea + Q16_BOT) & VAMASK); /* get bottom */ - t = wra + 1; /* adv bottom */ - if (t >= slt) /* wrap if necc */ - t = 0; - WriteB ((ea + Q16_BOT) & VAMASK, t); /* rewrite bottom */ - } -else { /* ATL */ - wra = ReadB ((ea + Q16_TOP) & VAMASK); /* get top */ - if (wra == 0) /* wrap if necc */ - wra = (slt - 1) & DMASK8; - else wra = wra - 1; /* dec top */ - WriteB ((ea + Q16_TOP) & VAMASK, wra); /* rewrite top */ - } -WriteH ((ea + Q16_BASE + (wra * Q16_SLNT)) & VAMASK, val); /* write slot */ -return 0; -} - -uint32 remfmq (uint32 ea, uint32 r1, uint32 flg) -{ -uint32 slt, usd, rda, t; - -t = ReadH (ea); /* get slots/used */ -slt = (t >> 8) & DMASK8; /* # slots */ -usd = t & DMASK8; /* # used */ -if (usd == 0) /* empty? */ - return CC_V; -usd = usd - 1; /* dec used */ -WriteB (ea + Q16_USD, usd); /* rewrite */ -if (flg) { /* RBL? */ - rda = ReadB ((ea + Q16_BOT) & VAMASK); /* get bottom */ - if (rda == 0) /* wrap if necc */ - rda = (slt - 1) & DMASK8; - else rda = rda - 1; /* dec bottom */ - WriteB ((ea + Q16_BOT) & VAMASK, rda); /* rewrite bottom */ - } -else { - rda = ReadB ((ea + Q16_TOP) & VAMASK); /* RTL, get top */ - t = rda + 1; /* adv top */ - if (t >= slt) /* wrap if necc */ - t = 0; - WriteB ((ea + Q16_TOP) & VAMASK, t); /* rewrite top */ - } -R[r1] = ReadH ((ea + Q16_BASE + (rda * Q16_SLNT)) & VAMASK); /* read slot */ -if (usd) /* set cc's */ - return CC_G; -else return 0; -} - -/* Automatic interrupt processing */ - -#define CCW16_ERR(x) (((x)|CCW16_INIT|CCW16_NOP|CCW16_Q) & \ - ~(CCW16_CHN|CCW16_CON|CCW16_HI)) - -uint32 int_auto (uint32 dev, uint32 cc) -{ -int32 ba, ea, by, vec, ccw, bpi, fnc, trm, st, i, t; -t_bool sysqe = FALSE; -t_bool rpt = FALSE; - -do { - vec = ReadH (INTSVT + dev + dev); /* get vector */ - if ((vec & 1) == 0) { /* immed int? */ - WriteH (vec, BUILD_PSW (cc)); /* write PSW, PC */ - WriteH ((vec + 2) & VAMASK, PC); - cc = newPSW (ReadH ((vec + 4) & VAMASK)); /* read PSW */ - PC = (vec + 6) & VAMASK; /* set new PC */ - return cc; - } - vec = vec & ~1; /* get CCW addr */ - ccw = ReadH (vec); /* read CCW */ - if (DEV_ACC (dev)) /* select dev */ - dev_tab[dev] (dev, IO_ADR, 0); - if (ccw & CCW16_NOP) /* NOP? exit */ - break; - if (ccw & CCW16_INIT) { /* init set? */ - ccw = ccw & ~CCW16_INIT; /* clr init */ - WriteH (vec, ccw); /* rewrite */ - if (ccw & CCW16_OC) { /* OC set? */ - if (DEV_ACC (dev)) { /* dev exist? */ - by = ReadB ((vec + CCB16_IOC) & VAMASK);/* read OC byte */ - dev_tab[dev] (dev, IO_OC, by); /* send to dev */ - } - break; /* and exit */ - } - } - fnc = CCW16_FNC (ccw); /* get func */ - st = 0; /* default status */ - if (fnc == CCW16_DMT) { /* DMT */ - ba = ReadH ((vec + CCB16_STR) & VAMASK); /* get cnt wd */ - ba = (ba - 1) & DMASK16; /* decr */ - WriteH ((vec + CCB16_STR) & VAMASK, ba); /* rewrite */ - if (ba) /* nz? exit */ - break; - } /* end if dmt */ - else if (fnc != CCW16_NUL) { /* rd or wr? */ - if (DEV_ACC (dev)) /* dev exist? */ - st = dev_tab[dev] (dev, IO_SS, 0); /* sense status */ - else st = CC_V; /* else timeout */ - if (st & 0xF) { /* error? */ - ccw = CCW16_ERR (ccw); /* neuter CCW */ - WriteH (vec, ccw); /* rewrite CCW */ - } - else { /* ok, do xfer */ - bpi = CCW16_BPI (ccw); /* get bytes/int */ - if (bpi == 0) /* max 16B */ - bpi = 16; - ba = ReadH ((vec + CCB16_STR) & VAMASK); /* get start */ - for (i = 0; i < bpi; i++) { /* do # bytes */ - if (fnc == CCW16_RD) { /* chan read? */ - by = dev_tab[dev] (dev, IO_RD, 0); /* read byte */ - WriteB (ba, by); /* store */ - } - else { /* chan write */ - by = ReadB (ba); /* fetch */ - dev_tab[dev] (dev, IO_WD, by); /* write byte */ - } - ba = (ba + 1) & VAMASK; /* incr addr */ - } - WriteH ((vec + CCB16_STR) & VAMASK, ba); /* rewrite */ - ea = ReadH ((vec + CCB16_END) & VAMASK); /* get end */ - trm = ReadB ((vec + CCB16_TRM) & VAMASK); /* get term chr */ - if ((ba <= ea) && /* not at end? */ - (((ccw & CCW16_TRM) == 0) || /* not term chr? */ - (by != trm))) /* exit */ - break; - ccw = ccw | CCW16_NOP; /* nop CCW */ - WriteH (vec, ccw); /* rewrite CCW */ - } /* end else sta */ - } /* end if r/w */ - -/* Termination phase */ - - t = (dev << 8) | (st & DMASK8); /* form dev/sta */ - WriteH ((vec + CCB16_DEV) & VAMASK, t); /* write dev/sta */ - if (ccw & CCW16_Q) { /* q request? */ - t = ReadH (SQP); /* get sys q addr */ - if (addtoq (t, vec, ccw & CCW16_HI)) { /* add to sys q */ - WriteH (SQOP, vec); /* write to ovflo */ - return swap_psw (SQVPSW, cc); /* take exception */ - } - else sysqe = TRUE; /* made an entry */ - } - if (ccw & CCW16_CHN) { /* chain */ - t = ReadH ((vec + CCB16_CHN) & VAMASK); /* get chain wd */ - WriteH (INTSVT + dev + dev, t); /* wr int svc tab */ - if (ccw & CCW16_CON) /* cont? */ - rpt = TRUE; - } - } while (rpt); - -/* Common exit */ - -if (sysqe && (PSW & PSW_SQI)) /* sys q ent & enb? */ - return swap_psw (SQIPSW, cc); /* take sys q int */ -return cc; -} - -/* Display register device */ - -uint32 display (uint32 dev, uint32 op, uint32 dat) -{ -int t; - -switch (op) { - - case IO_ADR: /* select */ - if (!drmod) /* norm mode? clr */ - drpos = srpos = 0; - return BY; /* byte only */ - - case IO_OC: /* command */ - dat = dat & 0xC0; - if (dat == 0x40) { /* x40 = inc */ - drmod = 1; - drpos = srpos = 0; /* init cntrs */ - } - else if (dat == 0x80) /* x80 = norm */ - drmod = 0; - break; - - case IO_WD: /* write */ - if (drpos < 4) - DR = (DR & ~(DMASK8 << (drpos * 8))) | (dat << (drpos * 8)); - else if (drpos == 4) - DRX = dat; - drpos = (drpos + 1) & - ((cpu_unit.flags & (UNIT_716 | UNIT_816))? 7: 3); - break; - - case IO_RD: /* read */ - t = (SR >> (srpos * 8)) & DMASK8; - srpos = srpos ^ 1; - return t; - - case IO_SS: /* status */ - return 0x80; - } - -return 0; -} - -/* Memory interface routines - - ReadB read byte (processor) - ReadH read halfword (processor) - ReadF read fullword (processor) - WriteB write byte (processor) - WriteH write halfword (processor) - WriteF write fullword (processor) - IOReadB read byte (IO) - IOWriteB write byte (IO) - IOReadH read halfword (IO) - IOWriteH write halfword (IO) -*/ - -uint32 ReadB (uint32 loc) -{ -uint32 pa = (loc + ((loc & VA_S1)? s1_rel: s0_rel)) & PAMASK16E; - -return ((M[pa >> 1] >> ((pa & 1)? 0: 8)) & DMASK8); -} - -uint32 ReadH (uint32 loc) -{ -uint32 pa = (loc + ((loc & VA_S1)? s1_rel: s0_rel)) & PAMASK16E; - -return M[pa >> 1]; -} - -uint32 ReadF (uint32 loc, uint32 rel) -{ -uint32 pa, pa1; -uint32 loc1 = (loc + 2) & VAMASK; - -loc = loc & VAMASK; /* FP doesn't mask */ -if (rel) { - pa = (loc + ((loc & VA_S1)? s1_rel: s0_rel)) & PAMASK16E; - pa1 = (loc1 + ((loc1 & VA_S1)? s1_rel: s0_rel)) & PAMASK16E; - } -else { - pa = loc; - pa1 = loc1; - } -return (((uint32) M[pa >> 1]) << 16) | ((uint32) M[pa1 >> 1]); -} - -void WriteB (uint32 loc, uint32 val) -{ -uint32 pa = (loc + ((loc & VA_S1)? s1_rel: s0_rel)) & PAMASK16E; - -val = val & DMASK8; -if (MEM_ADDR_OK (pa)) - M[pa >> 1] = ((pa & 1)? ((M[pa >> 1] & ~DMASK8) | val): - ((M[pa >> 1] & DMASK8) | (val << 8))); -return; -} - -void WriteH (uint32 loc, uint32 val) -{ -uint32 pa = (loc + ((loc & VA_S1)? s1_rel: s0_rel)) & PAMASK16E; - -if (MEM_ADDR_OK (pa)) - M[pa >> 1] = val & DMASK16; -return; -} - -void WriteF (uint32 loc, uint32 val, uint32 rel) -{ -uint32 pa, pa1; -uint32 loc1 = (loc + 2) & VAMASK; - -loc = loc & VAMASK; /* FP doesn't mask */ -if (rel) { - pa = (loc + ((loc & VA_S1)? s1_rel: s0_rel)) & PAMASK16E; - pa1 = (loc1 + ((loc1 & VA_S1)? s1_rel: s0_rel)) & PAMASK16E; - } -else { - pa = loc; - pa1 = loc1; - } -if (MEM_ADDR_OK (pa)) - M[pa >> 1] = (val >> 16) & DMASK16; -if (MEM_ADDR_OK (pa1)) - M[pa1 >> 1] = val & DMASK16; -return; -} - -uint32 IOReadB (uint32 loc) -{ -return ((M[loc >> 1] >> ((loc & 1)? 0: 8)) & DMASK8); -} - -void IOWriteB (uint32 loc, uint32 val) -{ -val = val & DMASK8; -M[loc >> 1] = ((loc & 1)? - ((M[loc >> 1] & ~DMASK8) | val): - ((M[loc >> 1] & DMASK8) | (val << 8))); -return; -} - -uint32 IOReadH (uint32 loc) -{ -return (M[loc >> 1] & DMASK16); -} - -void IOWriteH (uint32 loc, uint32 val) -{ -M[loc >> 1] = val & DMASK16; -return; -} - -/* Reset routine */ - -t_stat cpu_reset (DEVICE *dptr) -{ -qevent = 0; /* no events */ -newPSW (0); /* PSW = 0 */ -DR = 0; /* clr display */ -drmod = 0; -blk_io.dfl = blk_io.cur = blk_io.end = 0; /* no block IO */ -sim_brk_types = sim_brk_dflt = SWMASK ('E'); /* init bkpts */ -if (M == NULL) - M = (uint16 *) calloc (MAXMEMSIZE16E >> 1, sizeof (uint16)); -if (M == NULL) - return SCPE_MEM; -pcq_r = find_reg ("PCQ", NULL, dptr); /* init PCQ */ -if (pcq_r) - pcq_r->qptr = 0; -else return SCPE_IERR; -return SCPE_OK; -} - -/* Memory examine */ - -t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) -{ -if (sw & SWMASK ('V')) { - if (addr > VAMASK) - return SCPE_NXM; - addr = (addr + ((addr & VA_S1)? s1_rel: s0_rel)) & PAMASK16E; - } -if (addr >= MEMSIZE) - return SCPE_NXM; -if (vptr != NULL) - *vptr = IOReadH (addr); -return SCPE_OK; -} - -/* Memory deposit */ - -t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) -{ -if (sw & SWMASK ('V')) { - if (addr > VAMASK) - return SCPE_NXM; - addr = (addr + ((addr & VA_S1)? s1_rel: s0_rel)) & PAMASK16E; - } -if (addr >= MEMSIZE) - return SCPE_NXM; -IOWriteH (addr, val); -return SCPE_OK; -} - -/* Change memory size */ - -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 mc = 0; -uint32 i; - -if ((val <= 0) || ((val & 0xFFF) != 0) || - (((uint32) val) > ((uptr->flags & UNIT_816E)? MAXMEMSIZE16E: MAXMEMSIZE16))) - return SCPE_ARG; -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; -MEMSIZE = val; -for (i = MEMSIZE; i < MAXMEMSIZE16E; i = i + 2) - M[i >> 1] = 0; -return SCPE_OK; -} - -/* Change CPU model */ - -t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -uint32 i; - -if (!(val & UNIT_816E) && (MEMSIZE > MAXMEMSIZE16)) { - MEMSIZE = MAXMEMSIZE16; - for (i = MEMSIZE; i < MAXMEMSIZE16E; i = i + 2) - M[i >> 1] = 0; - sim_printf ("Reducing memory to 64KB\n"); - } -return SCPE_OK; -} - -/* Set console interrupt */ - -t_stat cpu_set_consint (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if ((uptr->flags & (UNIT_716 | UNIT_816 | UNIT_816E)) == 0) - return SCPE_NOFNC; -if (PSW & PSW_AIO) - SET_INT (v_DS); -return SCPE_OK; -} - -/* Set history */ - -t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -uint32 i, lnt; -t_stat r; - -if (cptr == NULL) { - for (i = 0; i < hst_lnt; i++) - hst[i].vld = 0; - hst_p = 0; - return SCPE_OK; - } -lnt = (uint32) get_uint (cptr, 10, HIST_MAX, &r); -if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) - return SCPE_ARG; -hst_p = 0; -if (hst_lnt) { - free (hst); - hst_lnt = 0; - hst = NULL; - } -if (lnt) { - hst = (InstHistory *) calloc (lnt, sizeof (InstHistory)); - if (hst == NULL) - return SCPE_MEM; - hst_lnt = lnt; - } -return SCPE_OK; -} - -/* Show history */ - -t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -int32 op, k, di, lnt; -char *cptr = (char *) desc; -t_value sim_eval[2]; -t_stat r; -InstHistory *h; - -if (hst_lnt == 0) /* enabled? */ - return SCPE_NOFNC; -if (cptr) { - lnt = (int32) get_uint (cptr, 10, hst_lnt, &r); - if ((r != SCPE_OK) || (lnt == 0)) - return SCPE_ARG; - } -else lnt = hst_lnt; -di = hst_p - lnt; /* work forward */ -if (di < 0) - di = di + hst_lnt; -fprintf (st, "PC r1 opnd ea IR\n\n"); -for (k = 0; k < lnt; k++) { /* print specified */ - h = &hst[(di++) % hst_lnt]; /* entry pointer */ - if (h->vld) { /* instruction? */ - fprintf (st, "%04X %04X %04X ", h->pc, h->r1, h->opnd); - op = (h->ir1 >> 8) & 0xFF; - if (OP_TYPE (op) >= OP_RX) - fprintf (st, "%04X ", h->ea); - else fprintf (st, " "); - sim_eval[0] = h->ir1; - sim_eval[1] = h->ir2; - if ((fprint_sym (st, h->pc, sim_eval, &cpu_unit, SWMASK ('M'))) > 0) - fprintf (st, "(undefined) %04X", h->ir1); - fputc ('\n', st); /* end line */ - } /* end if instruction */ - } /* end for */ -return SCPE_OK; -} diff --git a/Interdata/id16_dboot.c b/Interdata/id16_dboot.c deleted file mode 100644 index a4a38fec..00000000 --- a/Interdata/id16_dboot.c +++ /dev/null @@ -1,358 +0,0 @@ -/* id16_dboot.c: Interdata 16b simulator disk bootstrap - - Copyright (c) 2000-2008, 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-Jul-06 RMS Fixed transcription error -*/ - -#include "id_defs.h" - -#define DBOOT_BEG 0x1000 -#define DBOOT_START 0x100e -#define DBOOT_LEN (sizeof (dboot_rom) / sizeof (uint8)) - -/* Boot ROM: transcription of OS/16 MT2 ALO Direct Access Loader */ - -static uint8 dboot_rom[] = { - 0xca, 0xf0, 0x00, 0x30, - 0xc5, 0xf0, 0x00, 0x3a, - 0x02, 0x8e, - 0x26, 0xf7, - 0x03, 0x0e, - 0xd1, 0xc0, 0x00, 0x78, - 0xd0, 0xc0, 0x13, 0xf6, - 0x07, 0xdd, - 0xc8, 0x10, 0x10, 0x00, - 0xd3, 0xf0, 0x00, 0x7e, - 0xc4, 0xf0, 0x00, 0x0f, - 0x01, 0xe1, - 0xd2, 0xf0, 0x12, 0xe2, - 0xd3, 0xf0, 0x00, 0x7f, - 0x90, 0xf4, - 0x01, 0xe1, - 0xd2, 0xf0, 0x12, 0xe3, - 0xd3, 0xf0, 0x00, 0x7f, - 0xc4, 0xf0, 0x00, 0x0f, - 0x01, 0xe1, - 0xd2, 0xf0, 0x12, 0xe4, - 0xd3, 0x20, 0x00, 0x7d, - 0xd3, 0x30, 0x00, 0x7c, - 0xd3, 0x40, 0x00, 0x7a, - 0xd3, 0x50, 0x00, 0x7b, - 0xc8, 0x70, 0x12, 0xf6, - 0xc8, 0x80, 0x13, 0xf5, - 0x07, 0xaa, - 0x07, 0xcc, - 0x41, 0xe0, 0x11, 0x88, - 0x48, 0xa0, 0x12, 0xfe, - 0x48, 0xc0, 0x13, 0x00, - 0x43, 0x00, 0x10, 0x98, - 0xc8, 0x70, 0x12, 0xf6, - 0x41, 0xe0, 0x11, 0x88, - 0xc8, 0xe0, 0x12, 0xfa, - 0x24, 0x15, - 0xd3, 0x0e, 0x00, 0x24, - 0xc3, 0x00, 0x00, 0x10, - 0x21, 0x3f, - 0xca, 0xe0, 0x00, 0x30, - 0x27, 0x11, - 0x20, 0x38, - 0x48, 0xa0, 0x12, 0xf6, - 0x48, 0xc0, 0x12, 0xf8, - 0x42, 0x30, 0x10, 0x70, - 0x08, 0xaa, - 0x20, 0x33, - 0x43, 0x00, 0x12, 0xb2, - 0x90, 0x05, - 0x42, 0x30, 0x10, 0x88, - 0xc8, 0x60, 0x4f, 0x53, - 0x45, 0x63, 0x00, 0x00, - 0x20, 0x36, - 0xc8, 0x60, 0x31, 0x36, - 0x45, 0x6e, 0x00, 0x02, - 0x20, 0x3b, - 0x48, 0x6e, 0x00, 0x08, - 0x45, 0x60, 0x12, 0xe2, - 0x20, 0x35, - 0xd3, 0x6e, 0x00, 0x0a, - 0xd4, 0x60, 0x12, 0xe4, - 0x20, 0x3a, - 0x08, 0x0e, - 0x07, 0x66, - 0xca, 0x60, 0x20, 0x00, - 0x23, 0x36, - 0x40, 0x06, 0x00, 0x00, - 0x45, 0x06, 0x00, 0x00, - 0x22, 0x37, - 0x48, 0xae, 0x00, 0x0c, - 0x48, 0xce, 0x00, 0x0e, - 0x48, 0x0e, 0x00, 0x10, - 0x48, 0x1e, 0x00, 0x12, - 0x0b, 0x1c, - 0x0f, 0x0a, - 0x07, 0xff, - 0x26, 0x11, - 0x0e, 0x0f, - 0xed, 0x00, 0x00, 0x08, - 0xcb, 0x60, 0x02, 0xbe, - 0x08, 0x00, - 0x23, 0x34, - 0x08, 0x86, - 0x08, 0x16, - 0x23, 0x04, - 0x05, 0x16, - 0x22, 0x84, - 0x08, 0x81, - 0x07, 0x77, - 0x27, 0x81, - 0xc8, 0xd1, 0xee, 0xc0, - 0xc8, 0xf0, 0x11, 0x40, - 0x48, 0x0f, 0x00, 0x00, - 0x40, 0x01, 0x00, 0x00, - 0x26, 0xf2, - 0x26, 0x12, - 0xc5, 0xf0, 0x13, 0xfe, - 0x20, 0x88, - 0x0a, 0xed, - 0x40, 0xed, 0x12, 0xf4, - 0x43, 0x0d, 0x11, 0x40, - 0x41, 0xed, 0x11, 0x88, - 0xd1, 0xed, 0x13, 0xf6, - 0xd0, 0xe0, 0x00, 0x78, - 0xd1, 0xed, 0x13, 0xfa, - 0xd0, 0xe0, 0x00, 0x7c, - 0x48, 0x10, 0x00, 0x62, - 0x48, 0x6d, 0x12, 0xf4, - 0xd1, 0xa6, 0x00, 0x00, - 0xd0, 0xa1, 0x00, 0x30, - 0xd1, 0xe6, 0x00, 0x0c, - 0xd0, 0xe1, 0x00, 0x28, - 0x43, 0x00, 0x00, 0x60, - 0x07, 0x00, - 0x07, 0xbb, - 0x0b, 0xcf, - 0x0f, 0xab, - 0x21, 0x13, - 0x26, 0x01, - 0x22, 0x04, - 0x0a, 0xcf, - 0x0e, 0xab, - 0x08, 0xac, - 0x08, 0xc0, - 0x03, 0x0e, - 0xde, 0x2d, 0x12, 0x1e, - 0xc5, 0x50, 0x00, 0x33, - 0x42, 0x2d, 0x11, 0xec, - 0xde, 0x3d, 0x12, 0x1e, - 0x9d, 0x3f, - 0x22, 0x21, - 0x9d, 0x4f, - 0x42, 0x1d, 0x12, 0xb8, - 0xc3, 0xf0, 0x00, 0x10, - 0x20, 0x35, - 0xd0, 0xad, 0x13, 0xea, - 0xc8, 0xf0, 0x00, 0x30, - 0x41, 0xed, 0x11, 0x70, - 0x08, 0x9c, - 0x08, 0xba, - 0x48, 0xad, 0x13, 0xea, - 0x48, 0xcd, 0x13, 0xee, - 0xd1, 0xed, 0x13, 0xf2, - 0xc5, 0xb0, 0x00, 0x18, - 0x21, 0x82, - 0x26, 0xb8, - 0x98, 0x49, - 0xde, 0x4d, 0x12, 0xe7, - 0x9d, 0x3f, - 0x22, 0x21, - 0x9d, 0x4f, - 0x42, 0x7d, 0x12, 0xb8, - 0x20, 0x83, - 0x98, 0x27, - 0x98, 0x28, - 0x98, 0x49, - 0x9a, 0x3b, - 0x41, 0x6d, 0x12, 0x7a, - 0x22, 0x0f, - 0x9d, 0x4f, - 0xc3, 0xf0, 0x00, 0x19, - 0x42, 0x3d, 0x12, 0xb8, - 0xd0, 0xad, 0x13, 0xea, - 0xc8, 0xf5, 0xff, 0xcc, - 0x0a, 0xff, - 0x48, 0xff, 0x12, 0xec, - 0x41, 0xed, 0x11, 0x70, - 0x08, 0x9c, - 0x08, 0xca, - 0x07, 0xaa, - 0xc8, 0xf5, 0xff, 0xcc, - 0xd3, 0xff, 0x12, 0xe8, - 0x41, 0xed, 0x11, 0x70, - 0x40, 0xcd, 0x12, 0xf2, - 0x08, 0xba, - 0x48, 0xad, 0x13, 0xea, - 0x48, 0xcd, 0x13, 0xee, - 0xd1, 0xed, 0x13, 0xf2, - 0xde, 0x4d, 0x12, 0x6e, - 0x9d, 0x3f, - 0x22, 0x21, - 0x98, 0x49, - 0xde, 0x4d, 0x12, 0xd0, - 0x9d, 0x3f, - 0x22, 0x21, - 0xde, 0x4d, 0x12, 0xa2, - 0x9d, 0x3f, - 0x22, 0x21, - 0xd8, 0x4d, 0x12, 0xf2, - 0xde, 0x4d, 0x12, 0xd1, - 0x9d, 0x3f, - 0x22, 0x21, - 0xde, 0x4d, 0x12, 0xe7, - 0x9d, 0x3f, - 0x22, 0x21, - 0x9d, 0x4f, - 0x20, 0x81, - 0xc3, 0xf0, 0x00, 0x53, - 0x42, 0x3d, 0x12, 0xb8, - 0x48, 0xfd, 0x12, 0xf2, - 0x91, 0xfa, - 0x06, 0xf9, - 0xc8, 0x6d, 0x12, 0x2c, - 0x98, 0x27, - 0x98, 0x28, - 0x9a, 0x3b, - 0x98, 0x3f, - 0xde, 0x3d, 0x12, 0xe6, - 0xde, 0x2d, 0x11, 0xaf, - 0x9d, 0x2f, - 0x20, 0x81, - 0xde, 0x2d, 0x12, 0x1e, - 0x99, 0x20, - 0xde, 0x2d, 0x12, 0x1e, - 0x9d, 0x3f, - 0x22, 0x21, - 0x42, 0x1d, 0x12, 0xbc, - 0xc3, 0xf0, 0x00, 0x10, - 0x03, 0x3e, - 0x0b, 0x07, - 0x26, 0x02, - 0xc4, 0x00, 0xff, 0x00, - 0x0a, 0x70, - 0x26, 0x91, - 0x07, 0xbb, - 0x40, 0xbd, 0x12, 0xf2, - 0x03, 0x06, - 0x24, 0xf1, - 0x24, 0x10, - 0x23, 0x04, - 0x08, 0x14, - 0x23, 0x02, - 0x08, 0x13, - 0x24, 0x01, - 0xde, 0x0d, 0x10, 0xdc, - 0x9a, 0x0f, - 0x9a, 0x01, - 0xde, 0x0d, 0x12, 0xe5, - 0xd1, 0xed, 0x13, 0xf6, - 0xd0, 0xe0, 0x00, 0x78, - 0xd1, 0xed, 0x13, 0xfa, - 0xd0, 0xe0, 0x00, 0x7c, - 0x91, 0x0f, - 0x95, 0x10, - 0x22, 0x01, - 0x00, 0x00, 0x00, - 0x80, - 0xc1, - 0xc2, - 0x14, 0x40, 0x40, 0x00, - 0x01, 0x90, - 0x01, 0x40, - 0x04, 0xc0, - 0x00, 0x00, - 0x00, 0x00 - }; - -/* Lower memory setup - - 78 = binary input device address - 79 = binary device input command - 7A = disk device number - 7B = device code - 7C = disk controller address - 7D = selector channel address - 7E:7F = operating system extension (user specified) -*/ - -struct dboot_id { - char *name; - uint32 sw; - uint32 cap; - uint32 dtype; - uint32 offset; - uint32 adder; - }; - -static struct dboot_id dboot_tab[] = { - { "DP", 0, 2, 0x31, o_DP0, 0 }, - { "DP", SWMASK ('F'), 9, 0x32, o_DP0, o_DPF }, - { "DP", 0, 9, 0x33, o_DP0, 0 }, - { "DM", 0, 64, 0x35, o_ID0, 0 }, - { "DM", 0, 244, 0x36, o_ID0, 0 }, - { NULL } - }; - -t_stat id_dboot (int32 u, DEVICE *dptr) -{ -extern DIB pt_dib, sch_dib; -extern uint32 PC; -uint32 i, typ, ctlno, off, add, cap, sch_dev; -UNIT *uptr; - -DIB *ddib = (DIB *) dptr->ctxt; /* get disk DIB */ -ctlno = ddib->dno; /* get ctrl devno */ -sch_dev = sch_dib.dno + ddib->sch; /* sch dev # */ -uptr = dptr->units + u; /* get capacity */ -cap = uptr->capac >> 20; -for (i = typ = 0; dboot_tab[i].name != NULL; i++) { - if ((strcmp (dboot_tab[i].name, dptr->name) == 0) && - (dboot_tab[i].cap == cap)) { - typ = dboot_tab[i].dtype; - off = dboot_tab[i].offset; - add = dboot_tab[i].adder; - break; - } - } -if (typ == 0) - return SCPE_NOFNC; - -IOWriteBlk (DBOOT_BEG, DBOOT_LEN, dboot_rom); /* copy boot */ -IOWriteB (AL_DEV, pt_dib.dno); /* bin input dev */ -IOWriteB (AL_IOC, 0x99); -IOWriteB (AL_DSKU, ctlno + ((u + 1) * off) + add); /* disk param */ -IOWriteB (AL_DSKT, typ); -IOWriteB (AL_DSKC, ctlno); -IOWriteB (AL_SCH, sch_dev); -PC = DBOOT_START; -return SCPE_OK; -} diff --git a/Interdata/id16_sys.c b/Interdata/id16_sys.c deleted file mode 100644 index 358cc666..00000000 --- a/Interdata/id16_sys.c +++ /dev/null @@ -1,643 +0,0 @@ -/* id16_sys.c: Interdata 16b simulator interface - - Copyright (c) 2000-2008, Robert M. Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - 04-Feb-08 RMS Modified to allow -A, -B use with 8b devices - 18-Oct-06 RMS Re-ordered device list - 26-Mar-04 RMS Fixed warning with -std=c99 - 27-Feb-03 RMS Added relative addressing support -*/ - -#include "id_defs.h" -#include - -#define MSK_SBF 0x0100 - -extern DEVICE cpu_dev; -extern DEVICE sch_dev; -extern DEVICE pt_dev; -extern DEVICE tt_dev, ttp_dev; -extern DEVICE pas_dev, pasl_dev; -extern DEVICE lpt_dev; -extern DEVICE pic_dev, lfc_dev; -extern DEVICE dp_dev, idc_dev; -extern DEVICE fd_dev, mt_dev; -extern UNIT cpu_unit; -extern REG cpu_reg[]; -extern uint16 *M; - -t_stat fprint_sym_m (FILE *of, t_addr addr, t_value *val); -t_stat parse_sym_m (char *cptr, t_addr addr, t_value *val); -extern t_stat lp_load (FILE *fileref, char *cptr, char *fnam); -extern t_stat pt_dump (FILE *of, char *cptr, char *fnam); - -/* 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 16b"; - -REG *sim_PC = &cpu_reg[0]; - -int32 sim_emax = 2; - -DEVICE *sim_devices[] = { - &cpu_dev, - &sch_dev, - &pic_dev, - &lfc_dev, - &pt_dev, - &tt_dev, - &ttp_dev, - &pas_dev, - &pasl_dev, - &lpt_dev, - &dp_dev, - &idc_dev, - &fd_dev, - &mt_dev, - NULL - }; - -const char *sim_stop_messages[] = { - "Unknown error", - "Reserved instruction", - "HALT instruction", - "Breakpoint", - "Wait state", - "Runaway VFU" - }; - -/* Binary loader -- load carriage control tape - Binary dump -- paper tape dump */ - -t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) -{ -if (flag) - return pt_dump (fileref, cptr, fnam); -return lp_load (fileref, cptr, fnam); -} - -/* Symbol tables */ - -#define I_V_FL 16 /* class bits */ -#define I_M_FL 0xF /* class mask */ -#define I_V_MR 0x0 /* mask-register */ -#define I_V_RR 0x1 /* register-register */ -#define I_V_R 0x2 /* register */ -#define I_V_MX 0x3 /* mask-memory */ -#define I_V_RX 0x4 /* register-memory */ -#define I_V_X 0x5 /* memory */ -#define I_V_FF 0x6 /* float reg-reg */ -#define I_V_FX 0x7 /* float reg-mem */ -#define I_V_SI 0x8 /* short immed */ -#define I_V_SB 0x9 /* short branch */ -#define I_V_SX 0xA /* short ext branch */ -#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) -#define I_SI (I_V_SI << I_V_FL) -#define I_SB (I_V_SB << I_V_FL) -#define I_SX (I_V_SX << I_V_FL) - -#define R_X 0 /* no reg */ -#define R_M 1 /* reg mask */ -#define R_R 2 /* reg int reg */ -#define R_F 3 /* reg flt reg */ - -static const int32 masks[] = { - 0xFF00, 0xFF00, 0xFFF0, 0xFF00, - 0xFF00, 0xFFF0, 0xFF00, 0xFF00, - 0xFF00, 0xFE00, 0xFEF0 - }; - -static const uint32 r1_type[] = { - R_M, R_R, R_X, R_M, - R_R, R_X, R_F, R_F, - R_R, R_M, R_X - }; - -static const uint32 r2_type[] = { - R_X, R_R, R_R, R_X, - R_X, R_X, R_F, R_X, - R_M, R_X, R_X - }; - -static const char *opcode[] = { -"BER", "BNER","BZR", "BNZR", -"BPR", "BNPR","BLR", "BNLR", -"BMR", "BNMR","BOR", "BNOR", -"BCR", "BNCR","BR", -"BES", "BNES","BZS", "BNZS", -"BPS", "BNPS","BLS", "BNLS", -"BMS", "BNMS","BOS", "BNOS", -"BCS", "BNCS","BS", -"BE", "BNE", "BZ", "BNZ", -"BP", "BNP", "BL", "BNL", -"BM", "BNM", "BO", "BNO", -"BC", "BNC", "B", - "BALR","BTCR","BFCR", -"NHR", "CLHR","OHR", "XHR", -"LHR", "CHR", "AHR", "SHR", -"MHR", "DHR", "ACHR","SCHR", - "SETMR", -"BTBS","BTFS","BFBS","BFFS", -"LIS", "LCS", "AIS", "SIS", -"LER", "CER", "AER", "SER", -"MER", "DER", "FXR", "FLR", - "LPSR", -"LDR", "CDR", "ADR", "SDR", -"MDR", "DDR", "FXDR","FLDR", -"STH", "BAL", "BTC", "BFC", -"NH", "CLH", "OH", "XH", -"LH", "CH", "AH", "SH", -"MH", "DH", "ACH", "SCH", - "SETM", -"STE", "AHM", -"ATL", "ABL", "RTL", "RBL", -"LE", "CE", "AE", "SE", -"ME", "DE", -"STD", "STME","LME", "LPS", -"LD", "CD", "AD", "SD", -"MD", "DD", "STMD","LMD", -"SRLS","SLLS","STBR","LBR", -"EXBR","EPSR","WBR", "RBR", -"WHR", "RHR", "WDR", "RDR", -"MHUR","SSR", "OCR", "AIR", -"BXH", "BXLE","LPSW","THI", -"NHI", "CLHI","OHI", "XHI", -"LHI", "CHI", "AHI", "SHI", -"SRHL","SLHL","SRHA","SLHA", -"STM", "LM", "STB", "LB", -"CLB", "AL", "WB", "RB", -"WH", "RH", "WD", "RD", -"MHU", "SS", "OC", "AI", - "SVC", "SINT", - "RRL", "RLL", -"SRL", "SLL", "SRA", "SLA", -NULL -}; - -static const uint32 opc_val[] = { -0x0330+I_R, 0x0230+I_R, 0x0330+I_R, 0x0230+I_R, -0x0220+I_R, 0x0320+I_R, 0x0280+I_R, 0x0380+I_R, -0x0210+I_R, 0x0310+I_R, 0x0240+I_R, 0x0340+I_R, -0x0280+I_R, 0x0380+I_R, 0x0300+I_R, -0x2230+I_SX, 0x2030+I_SX, 0x2230+I_SX, 0x2030+I_SX, -0x2020+I_SX, 0x2220+I_SX, 0x2080+I_SX, 0x2280+I_SX, -0x2010+I_SX, 0x2210+I_SX, 0x2040+I_SX, 0x2240+I_SX, -0x2080+I_SX, 0x2280+I_SX, 0x2200+I_SX, -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, 0x4340+I_X, -0x4280+I_X, 0x4380+I_X, 0x4300+I_X, - 0x0100+I_RR, 0x0200+I_MR, 0x0300+I_MR, -0x0400+I_RR, 0x0500+I_RR, 0x0600+I_RR, 0x0700+I_RR, -0x0800+I_RR, 0x0900+I_RR, 0x0A00+I_RR, 0x0B00+I_RR, -0x0C00+I_RR, 0x0D00+I_RR, 0x0E00+I_RR, 0x0F00+I_RR, - 0x1300+I_RR, -0x2000+I_SB, 0x2100+I_SB, 0x2200+I_SB, 0x2300+I_SB, -0x2400+I_SI, 0x2500+I_SI, 0x2600+I_SI, 0x2700+I_SI, -0x2800+I_FF, 0x2900+I_FF, 0x2A00+I_FF, 0x2B00+I_FF, -0x2C00+I_FF, 0x2D00+I_FF, 0x2E00+I_RR, 0x2F00+I_RR, - 0x3300+I_R, -0x3800+I_FF, 0x3900+I_FF, 0x3A00+I_FF, 0x3B00+I_FF, -0x3C00+I_FF, 0x3D00+I_FF, 0x3E00+I_RR, 0x3F00+I_RR, -0x4000+I_RX, 0x4100+I_RX, 0x4200+I_MX, 0x4300+I_MX, -0x4400+I_RX, 0x4500+I_RX, 0x4600+I_RX, 0x4700+I_RX, -0x4800+I_RX, 0x4900+I_RX, 0x4A00+I_RX, 0x4B00+I_RX, -0x4C00+I_RX, 0x4D00+I_RX, 0x4E00+I_RX, 0x4F00+I_RX, - 0x5300+I_RX, -0x6000+I_RX, 0x6100+I_RX, -0x6400+I_RX, 0x6500+I_RX, 0x6600+I_RX, 0x6700+I_RX, -0x6800+I_FX, 0x6900+I_FX, 0x6A00+I_FX, 0x6B00+I_FX, -0x6C00+I_FX, 0x6D00+I_FX, -0x7000+I_FX, 0x7100+I_FX, 0x7200+I_FX, 0x7300+I_X, -0x7800+I_FX, 0x7900+I_FX, 0x7A00+I_FX, 0x7B00+I_FX, -0x7C00+I_FX, 0x7D00+I_FX, 0x7E00+I_FX, 0x7F00+I_FX, -0x9000+I_SI, 0x9100+I_SI, 0x9200+I_RR, 0x9300+I_RR, -0x9400+I_RR, 0x9500+I_RR, 0x9600+I_RR, 0x9700+I_RR, -0x9800+I_RR, 0x9900+I_RR, 0x9A00+I_RR, 0x9B00+I_RR, -0x9C00+I_RR, 0x9D00+I_RR, 0x9E00+I_RR, 0x9F00+I_RR, -0xC000+I_RX, 0xC100+I_RX, 0xC200+I_X, 0xC300+I_RX, -0xC400+I_RX, 0xC500+I_RX, 0xC600+I_RX, 0xC700+I_RX, -0xC800+I_RX, 0xC900+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, -0xD400+I_RX, 0xD500+I_X, 0xD600+I_RX, 0xD700+I_RX, -0xD800+I_RX, 0xD900+I_RX, 0xDA00+I_RX, 0xDB00+I_RX, -0xDC00+I_RX, 0xDD00+I_RX, 0xDE00+I_RX, 0xDF00+I_RX, - 0xE100+I_RX, 0xE200+I_RX, - 0xEA00+I_RX, 0xEB00+I_RX, -0xEC00+I_RX, 0xED00+I_RX, 0xEE00+I_RX, 0xEF00+I_RX, -0xFFFF -}; - -/* 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 bytes retired -*/ - -t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, - UNIT *uptr, int32 sw) -{ -int32 bflag, c1, c2, rdx; -t_stat r; -DEVICE *dptr; - -if (uptr == NULL) /* anon = CPU */ - uptr = &cpu_unit; -dptr = find_dev_from_unit (uptr); /* find dev */ -if (dptr == NULL) - return SCPE_IERR; -if (dptr->dwidth < 16) /* 8b dev? */ - bflag = 1; -else bflag = 0; /* assume 16b */ -if (sw & SWMASK ('D')) /* get radix */ - rdx = 10; -else if (sw & SWMASK ('O')) - rdx = 8; -else if (sw & SWMASK ('H')) - rdx = 16; -else rdx = dptr->dradix; - -if (sw & SWMASK ('A')) { /* ASCII char? */ - if (bflag) - c1 = val[0] & 0x7F; - else c1 = (val[0] >> ((addr & 1)? 0: 8)) & 0x7F; /* get byte */ - fprintf (of, (c1 < 0x20)? "<%02X>": "%c", c1); - return 0; - } -if (sw & SWMASK ('B')) { /* byte? */ - if (bflag) - c1 = val[0] & 0xFF; - else c1 = (val[0] >> ((addr & 1)? 0: 8)) & 0xFF; /* get byte */ - fprint_val (of, c1, rdx, 8, PV_RZRO); - return 0; - } -if (bflag) /* 16b only */ - return SCPE_ARG; - -if (sw & SWMASK ('C')) { /* string? */ - c1 = (val[0] >> 8) & 0x7F; - c2 = val[0] & 0x7F; - fprintf (of, (c1 < 0x20)? "<%02X>": "%c", c1); - fprintf (of, (c2 < 0x20)? "<%02X>": "%c", c2); - return -1; - } -if (sw & SWMASK ('F')) { /* fullword? */ - fprint_val (of, (val[0] << 16) | val[1], rdx, 32, PV_RZRO); - return -3; - } -if (sw & SWMASK ('M')) { /* inst format? */ - r = fprint_sym_m (of, addr, val); /* decode inst */ - if (r <= 0) - return r; - } - -fprint_val (of, val[0], rdx, 16, PV_RZRO); -return -1; -} - -/* Symbolic decode for -m - - Inputs: - of = output stream - addr = current PC - *val = values to decode - Outputs: - return = if >= 0, error code - if < 0, number of extra bytes retired -*/ - -t_stat fprint_sym_m (FILE *of, t_addr addr, t_value *val) -{ -uint32 i, j, inst, r1, r2, ea; - -inst = val[0]; /* first 16b */ -ea = val[1]; /* second 16b */ -for (i = 0; opcode[i] != NULL; 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 = (inst >> 4) & 0xF; - r2 = inst & 0xF; - fprintf (of, "%s ", opcode[i]); /* print opcode */ - switch (j) { /* case on class */ - - case I_V_MR: /* mask-register */ - fprintf (of, "%-X,R%d", r1, r2); - return -1; - - case I_V_RR: /* register-register */ - case I_V_FF: /* floating-floating */ - fprintf (of, "R%d,R%d", r1, r2); - return -1; - - case I_V_SI: /* short immediate */ - fprintf (of, "R%d,%-X", r1, r2); - return -1; - - case I_V_SB: /* short branch */ - fprintf (of, "%-X,", r1); - case I_V_SX: /* ext short branch */ - fprintf (of, "%-X", ((inst & MSK_SBF)? - (addr + r2 + r2): (addr - r2 - r2))); - return -1; - - case I_V_R: /* register */ - fprintf (of, "R%d", r2); - return -1; - - case I_V_MX: /* mask-memory */ - fprintf (of, "%-X,%-X", r1, ea); - break; - - case I_V_RX: /* register-memory */ - case I_V_FX: /* floating-memory */ - fprintf (of, "R%d,%-X", r1, ea); - break; - - case I_V_X: /* memory */ - fprintf (of, "%-X", ea); - break; - } /* end case */ - - if (r2) - fprintf (of, "(R%d)", r2); - return -3; - } /* end if */ - } /* end for */ -return SCPE_ARG; /* no match */ -} - -/* Register number - - Inputs: - *cptr = pointer to input string - **optr = pointer to pointer to next char - rtype = mask, integer, or float - Outputs: - rnum = output register number, -1 if error -*/ - -int32 get_reg (char *cptr, char **optr, int32 rtype) -{ -int32 reg; - -if ((*cptr == 'R') || (*cptr == 'r')) { /* R? */ - cptr++; /* skip */ - if (rtype == R_M) /* cant be mask */ - return -1; - } -if ((*cptr >= '0') && (*cptr <= '9')) { - reg = *cptr++ - '0'; - if ((*cptr >= '0') && (*cptr <= '9')) - reg = (reg * 10) + (*cptr - '0'); - else --cptr; - if (reg > 0xF) - return -1; - } -else if ((*cptr >= 'a') && (*cptr <= 'f')) - reg = (*cptr - 'a') + 10; -else if ((*cptr >= 'A') && (*cptr <= 'F')) - reg = (*cptr - 'A') + 10; -else return -1; -if ((rtype == R_F) && (reg & 1)) - return -1; -*optr = cptr + 1; -return reg; -} - -/* Address - - Inputs: - *cptr = pointer to input string - **tptr = pointer to moved pointer - *ea = effective address - addr = base address - Outputs: - status = SCPE_OK if ok, else error code -*/ - -t_stat get_addr (char *cptr, char **tptr, t_addr *ea, t_addr addr) -{ -int32 sign = 1; - -if (*cptr == '.') { /* relative? */ - cptr++; - *ea = addr; - if (*cptr == '+') /* .+? */ - cptr++; - else if (*cptr == '-') { /* .-? */ - sign = -1; - cptr++; - } - else return SCPE_OK; - } -else *ea = 0; -errno = 0; -*ea = *ea + (sign * ((int32) strtoul (cptr, tptr, 16))); -if (errno || (cptr == *tptr)) - return SCPE_ARG; -return SCPE_OK; -} - -/* Symbolic input */ - -t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) -{ -int32 bflag, by, rdx, num; -t_stat r; -DEVICE *dptr; - -if (uptr == NULL) /* anon = CPU */ - uptr = &cpu_unit; -dptr = find_dev_from_unit (uptr); /* find dev */ -if (dptr == NULL) - return SCPE_IERR; -if (dptr->dwidth < 16) /* 8b dev? */ - bflag = 1; -else bflag = 0; /* assume 16b */ -if (sw & SWMASK ('D')) /* get radix */ - rdx = 10; -else if (sw & SWMASK ('O')) - rdx = 8; -else if (sw & SWMASK ('H')) - rdx = 16; -else rdx = dptr->dradix; - -if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ - if (cptr[0] == 0) /* must have 1 char */ - return SCPE_ARG; - if (bflag) - val[0] = (t_value) cptr[0]; - else val[0] = (addr & 1)? - (val[0] & ~0xFF) | ((t_value) cptr[0]): - (val[0] & 0xFF) | (((t_value) cptr[0]) << 8); - return 0; - } -if (sw & SWMASK ('B')) { /* byte? */ - by = get_uint (cptr, rdx, DMASK8, &r); /* get byte */ - if (r != SCPE_OK) - return SCPE_ARG; - if (bflag) - val[0] = by; - else val[0] = (addr & 1)? - (val[0] & ~0xFF) | by: - (val[0] & 0xFF) | (by << 8); - return 0; - } -if (bflag) /* 16b only */ - return SCPE_ARG; - -if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII chars? */ - if (cptr[0] == 0) /* must have 1 char */ - return SCPE_ARG; - val[0] = ((t_value) cptr[0] << 8) | (t_value) cptr[1]; - return -1; - } -if (sw & SWMASK ('F')) { - num = (int32) get_uint (cptr, rdx, DMASK32, &r); /* get number */ - if (r != SCPE_OK) - return r; - val[0] = (num >> 16) & DMASK16; - val[1] = num & DMASK16; - return -3; - } - -r = parse_sym_m (cptr, addr, val); /* try to parse inst */ -if (r <= 0) - return r; -val[0] = (int32) get_uint (cptr, rdx, DMASK16, &r); /* get number */ -if (r != SCPE_OK) - return r; -return -1; -} - -/* Symbolic input for -m - - Inputs: - *cptr = pointer to input string - addr = current PC - *val = pointer to output values - cf = true if parsing for CPU - Outputs: - status = > 0 error code - <= 0 -number of extra words -*/ - -t_stat parse_sym_m (char *cptr, t_addr addr, t_value *val) -{ -uint32 i, j, t, df, db, inst; -int32 r1, r2; -t_stat r; -char *tptr, gbuf[CBUFSIZE]; - -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; -inst = opc_val[i] & 0xFFFF; /* get value */ -j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */ -if (r1_type[j]) { /* any R1 field? */ - cptr = get_glyph (cptr, gbuf, ','); /* get R1 field */ - if ((r1 = get_reg (gbuf, &tptr, r1_type[j])) < 0) - return SCPE_ARG; - if (*tptr != 0) /* all done? */ - return SCPE_ARG; - inst = inst | (r1 << 4); /* or in R1 */ - } - -cptr = get_glyph (cptr, gbuf, 0); /* get operand */ -if (*cptr) /* should be end */ - return SCPE_ARG; -switch (j) { /* case on class */ - - case I_V_FF: case I_V_SI: /* flt-flt, sh imm */ - case I_V_MR: case I_V_RR: /* mask/reg-reg */ - case I_V_R: /* register */ - if ((r2 = get_reg (gbuf, &tptr, r2_type[j])) < 0) - return SCPE_ARG; - if (*tptr != 0) /* all done? */ - return SCPE_ARG; - inst = inst | r2; /* or in R2 */ - break; - - case I_V_FX: /* float-memory */ - case I_V_MX: case I_V_RX: /* mask/reg-mem */ - case I_V_X: /* memory */ - r = get_addr (gbuf, &tptr, &t, addr); /* get addr */ - if ((r != SCPE_OK) || (t > PAMASK16)) - return SCPE_ARG; - if (*tptr == '(') { /* index? */ - if ((r2 = get_reg (tptr + 1, &tptr, R_R)) < 0) - return SCPE_ARG; - if (*tptr++ != ')') - return SCPE_ARG; - inst = inst | r2; /* or in R2 */ - } - if (*tptr != 0) - return SCPE_ARG; - val[0] = inst; - val[1] = t; - return -3; - - case I_V_SB: case I_V_SX: /* short branches */ - r = get_addr (gbuf, &tptr, &t, addr); /* get addr */ - if ((r != SCPE_OK) || (t & 1) || *tptr) /* error if odd */ - return SCPE_ARG; - db = (addr - t) & 0x1F; /* back displ */ - df = (t - addr) & 0x1F; /* fwd displ */ - if ((t == ((addr - db) & VAMASK16)) && /* back work and */ - ((j == I_V_SX) || !(inst & MSK_SBF))) /* ext or back br? */ - inst = inst | (db >> 1); /* or in back displ */ - else if ((t == ((addr + df) & VAMASK16)) && /* fwd work and */ - ((j == I_V_SX) || (inst & MSK_SBF))) /* ext or fwd br? */ - inst = inst | (df >> 1) | MSK_SBF; /* or in fwd displ */ - else return SCPE_ARG; - break; - } /* end case */ - -val[0] = inst; -return -1; -} diff --git a/Interdata/id32_cpu.c b/Interdata/id32_cpu.c deleted file mode 100644 index f7fdccea..00000000 --- a/Interdata/id32_cpu.c +++ /dev/null @@ -1,2425 +0,0 @@ -/* id32_cpu.c: Interdata 32b CPU simulator - - Copyright (c) 2000-2017, 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. - - cpu Interdata 32b CPU - - 09-Mar-17 RMS OC to display testing wrong argument (COVERITY) - 28-Apr-07 RMS Removed clock initialization - 27-Oct-06 RMS Added idle support - Removed separate PASLA clock - 09-Mar-06 RMS Added 8 register bank support for 8/32 - 06-Feb-06 RMS Fixed bug in DH (Mark Hittinger) - 22-Sep-05 RMS Fixed declarations (Sterling Garwood) - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 10-Mar-05 RMS Fixed bug in initial memory allocation - RMS Fixed bug in show history routine (Mark Hittinger) - RMS Revised examine/deposit to do words rather than bytes - 18-Feb-05 RMS Fixed branches to mask new PC (Greg Johnson) - 06-Nov-04 RMS Added =n to SHOW HISTORY - 25-Jan-04 RMS Revised for device debug support - 31-Dec-03 RMS Fixed bug in cpu_set_hist - 22-Sep-03 RMS Added additional instruction decode types - Added instruction history - - The register state for an Interdata 32b CPU is: - - REG[0:F][2]<0:31> general register sets - F[0:7]<0:31> single precision floating point registers - D[0:7]<0:63> double precision floating point registers - PSW<0:63> processor status word, including - STAT<0:11> status flags - CC<0:3> condition codes - PC<0:31> program counter - int_req[n]<0:31> interrupt requests - int_enb[n]<0:31> interrupt enables - - The Interdata 32b systems have seven instruction formats: register to - register, short format, register and memory (three formats), and register - and immediate (two formats). 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 | N | short format - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | op | R1 | RX | register-memory 1 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ (absolute 14b) - | 0| 0| address | - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | op | R1 | RX | register-memory 2 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ (relative) - | 1| address | - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | op | R1 | RX | register-memory 3 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ (double index) - | 0| 1| 0| 0| RX2 | address hi | - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | address lo | - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | op | R1 | RX | register-immediate 1 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | immediate | - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | op | R1 | RX | register-immediate 2 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | immediate hi | - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | immediate lo | - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - For register-memory 1 and register-immediate 1 and 2 an instructions, an - effective address is calculated as follows: - - effective addr = address + RX (if RX > 0) - - For register-memory 2, an effective address is calculated as follows: - - effective addr = address + PC + RX (if RX > 0) - - For register-memory 3, an effective address is calculated as follows: - - effective addr = address + RX (if RX > 0) + RX2 (if RX2 > 0) - - Register-memory instructions can access an address space of 16M bytes. - - This routine is the instruction decode routine for the Interdata CPU. - 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 armed flag, 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. - Interrupt armed flags are local to devices. If external interrupts are - enabled in the PSW, and a request is pending, an interrupt occurs. - - 3. Non-existent memory. On the Interdata 32b, 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: - - id_defs.h add device interrupt definitions - id32_sys.c add sim_devices table entry -*/ - -#include "id_defs.h" -#include - -#define PCQ_SIZE 64 /* must be 2**n */ -#define PCQ_MASK (PCQ_SIZE - 1) -#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = oPC -#define VAMASK VAMASK32 -#define NRSETS 8 /* up to 8 reg sets */ -#define PSW_MASK PSW_x32 -#define ABORT(val) longjmp (save_env, (val)) -#define MPRO (-1) - -#define UNIT_V_MSIZE (UNIT_V_UF + 0) /* dummy mask */ -#define UNIT_V_DPFP (UNIT_V_UF + 1) -#define UNIT_V_832 (UNIT_V_UF + 2) -#define UNIT_V_8RS (UNIT_V_UF + 3) -#define UNIT_MSIZE (1 << UNIT_V_MSIZE) -#define UNIT_DPFP (1 << UNIT_V_DPFP) -#define UNIT_832 (1 << UNIT_V_832) -#define UNIT_8RS (1 << UNIT_V_8RS) -#define UNIT_TYPE (UNIT_DPFP | UNIT_832) - -#define HIST_PC 0x40000000 -#define HIST_MIN 64 -#define HIST_MAX 65536 - -typedef struct { - uint32 pc; - uint32 ir1; - uint32 ir2; - uint32 ir3; - uint32 r1; - uint32 ea; - uint32 opnd; - } InstHistory; - -#define PSW_GETREG(x) (((x) >> PSW_V_REG) & psw_reg_mask) -#define SEXT32(x) (((x) & SIGN32)? ((int32) ((x) | ~0x7FFFFFFF)): \ - ((int32) ((x) & 0x7FFFFFFF))) -#define SEXT16(x) (((x) & SIGN16)? ((int32) ((x) | ~0x7FFF)): \ - ((int32) ((x) & 0x7FFF))) -#define SEXT15(x) (((x) & 0x4000)? ((int32) ((x) | ~0x3FFF)): \ - ((int32) ((x) & 0x3FFF))) -#define CC_GL_16(x) if ((x) & SIGN16) \ - cc = CC_L; \ - else if (x) \ - cc = CC_G; \ - else cc = 0 -#define CC_GL_32(x) if ((x) & SIGN32) \ - cc = CC_L; \ - else if (x) \ - cc = CC_G; \ - else cc = 0 -#define BUILD_PSW(x) (((PSW & ~CC_MASK) | (x)) & PSW_MASK) -#define NEG(x) ((~(x) + 1) & DMASK32) -#define ABS(x) (((x) & SIGN32)? NEG (x): (x)) -#define DNEG(x,y) y = NEG (y); \ - x = (~(x) + (y == 0)) & DMASK32 - -/* Logging */ - -#define LOG_CPU_I 0x0001 /* intr/exception */ -#define LOG_CPU_C 0x0002 /* context change */ - -uint32 GREG[16 * NRSETS] = { 0 }; /* general registers */ -uint32 *M = NULL; /* memory */ -uint32 *R = &GREG[0]; /* working reg set */ -uint32 F[8] = { 0 }; /* sp fp registers */ -dpr_t D[8] = { {0} }; /* dp fp registers */ -uint32 PSW = 0; /* processor status word */ -uint32 PC = 0; /* program counter */ -uint32 oPC = 0; /* PC at inst start */ -uint32 SR = 0; /* switch register */ -uint32 DR = 0; /* display register */ -uint32 DRX = 0; /* display extension */ -uint32 drmod = 0; /* mode */ -uint32 srpos = 0; /* switch register pos */ -uint32 drpos = 0; /* display register pos */ -uint32 mac_reg[MAC_LNT] = { 0 }; /* mac registers */ -uint32 mac_sta = 0; /* mac status */ -uint32 int_req[INTSZ] = { 0 }; /* interrupt requests */ -uint32 int_enb[INTSZ] = { 0 }; /* interrupt enables */ -uint32 qevent = 0; /* events */ -uint32 stop_inst = 0; /* stop on ill inst */ -uint32 stop_wait = 0; /* stop on wait */ -uint32 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ -int32 pcq_p = 0; /* PC queue ptr */ -REG *pcq_r = NULL; /* PC queue reg ptr */ -uint32 dec_flgs = 0; /* decode flags */ -uint32 fp_in_hwre = 0; /* ucode vs hwre fp */ -uint32 pawidth = PAWIDTH32; /* addr mask */ -uint32 hst_p = 0; /* history pointer */ -uint32 hst_lnt = 0; /* history length */ -uint32 psw_reg_mask = 1; /* PSW reg mask */ -InstHistory *hst = NULL; /* instruction history */ -jmp_buf save_env; /* abort handler */ -struct BlockIO blk_io; /* block I/O status */ -uint32 (*dev_tab[DEVNO])(uint32 dev, uint32 op, uint32 datout) = { NULL }; - -uint32 ReadB (uint32 loc, uint32 rel); -uint32 ReadH (uint32 loc, uint32 rel); -void WriteB (uint32 loc, uint32 val, uint32 rel); -void WriteH (uint32 loc, uint32 val, uint32 rel); -uint32 RelocT (uint32 va, uint32 base, uint32 rel, uint32 *pa); -uint32 int_auto (uint32 dev, uint32 cc); -uint32 addtoq (uint32 ea, uint32 val, uint32 flg); -uint32 remfmq (uint32 ea, uint32 r1, uint32 flg); -uint32 exception (uint32 loc, uint32 cc, uint32 flg); -uint32 newPSW (uint32 val); -uint32 testsysq (uint32 cc); -uint32 display (uint32 dev, uint32 op, uint32 dat); -t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); -t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); -t_stat cpu_reset (DEVICE *dptr); -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_consint (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc); -void set_r_display (uint32 *rbase); - -extern t_bool devtab_init (void); -extern void int_eval (void); -extern uint32 int_getdev (void); -extern void sch_cycle (uint32 ch); -extern t_bool sch_blk (uint32 dev); -extern uint32 f_l (uint32 op, uint32 r1, uint32 r2, uint32 ea); -extern uint32 f_c (uint32 op, uint32 r1, uint32 r2, uint32 ea); -extern uint32 f_as (uint32 op, uint32 r1, uint32 r2, uint32 ea); -extern uint32 f_m (uint32 op, uint32 r1, uint32 r2, uint32 ea); -extern uint32 f_d (uint32 op, uint32 r1, uint32 r2, uint32 ea); -extern uint32 f_fix32 (uint32 op, uint32 r1, uint32 r2); -extern uint32 f_flt32 (uint32 op, uint32 r1, uint32 r2); - -/* Instruction decoding table */ - -const uint16 decrom[256] = { - 0, /* 00 */ - OP_RR, /* BALR */ - OP_RR, /* BTCR */ - OP_RR, /* BFCR */ - OP_RR, /* NR */ - OP_RR, /* CLR */ - OP_RR, /* OR */ - OP_RR, /* XR */ - OP_RR, /* LR */ - OP_RR, /* CR */ - OP_RR, /* AR */ - OP_RR, /* SR */ - OP_RR, /* MHR */ - OP_RR, /* DHR */ - 0, 0, /* 0E:0F */ - OP_NO, /* SRLS */ - OP_NO, /* SLLS */ - OP_RR, /* CHVR */ - 0, 0, 0, 0, 0, /* 13:17 */ - OP_RR | OP_PRV, /* LPSWR */ - 0, 0, 0, /* 19:1B */ - OP_RR, /* MR */ - OP_RR, /* DR */ - 0, 0, /* 1E:1F */ - OP_NO, /* BTBS */ - OP_NO, /* BTFS */ - OP_NO, /* BFBS */ - OP_NO, /* BFFS */ - OP_NO, /* LIS */ - OP_NO, /* LCS */ - OP_NO, /* AIS */ - OP_NO, /* SIS */ - OP_NO, /* LER */ - OP_NO, /* CER */ - OP_NO, /* AER */ - OP_NO, /* SER */ - OP_NO, /* MER */ - OP_NO, /* DER */ - OP_NO, /* FXR */ - OP_NO, /* FLR */ - 0, /* MPBSR - 8/32C */ - 0, /* 31 */ - 0, /* PBR - 8/32C */ - 0, /* 33 */ - OP_RR, /* EXHR */ - 0, 0, 0, /* 35:37 */ - OP_NO | OP_DPF, /* LDR */ - OP_NO | OP_DPF, /* CDR */ - OP_NO | OP_DPF, /* ADR */ - OP_NO | OP_DPF, /* SDR */ - OP_NO | OP_DPF, /* MDR */ - OP_NO | OP_DPF, /* DDR */ - OP_NO | OP_DPF, /* FXDR */ - OP_NO | OP_DPF, /* FLDR */ - OP_RX, /* STH */ - OP_RX, /* BAL */ - OP_RX, /* BTC */ - OP_RX, /* BFC */ - OP_RXH, /* NH */ - OP_RXH, /* CLH */ - OP_RXH, /* OH */ - OP_RXH, /* XH */ - OP_RXH, /* LH */ - OP_RXH, /* CH */ - OP_RXH, /* AH */ - OP_RXH, /* SH */ - OP_RXH, /* MH */ - OP_RXH, /* DH */ - 0, 0, /* 4E:4F */ - OP_RX, /* ST */ - OP_RXF, /* AM */ - 0, 0, /* 52:53 */ - OP_RXF, /* N */ - OP_RXF, /* CL */ - OP_RXF, /* O */ - OP_RXF, /* X */ - OP_RXF, /* L */ - OP_RXF, /* C */ - OP_RXF, /* A */ - OP_RXF, /* S */ - OP_RXF, /* M */ - OP_RXF, /* D */ - OP_RXH, /* CRC12 */ - OP_RXH, /* CRC16 */ - OP_RX, /* STE */ - OP_RXH, /* AHM */ - 0, /* PB - 8/32C */ - OP_RX, /* LRA */ - OP_RX, /* ATL */ - OP_RX, /* ABL */ - OP_RX, /* RTL */ - OP_RX, /* RBL */ - OP_RX, /* LE */ - OP_RX, /* CE */ - OP_RX, /* AE */ - OP_RX, /* SE */ - OP_RX, /* ME */ - OP_RX, /* DE */ - 0, 0, /* 6E:6F */ - OP_RX | OP_DPF, /* STD */ - OP_RX, /* SME */ - OP_RX, /* LME */ - OP_RXH, /* LHL */ - OP_RX, /* TBT */ - OP_RX, /* SBT */ - OP_RX, /* RBT */ - OP_RX, /* CBT */ - OP_RX | OP_DPF, /* LD */ - OP_RX | OP_DPF, /* CD */ - OP_RX | OP_DPF, /* AD */ - OP_RX | OP_DPF, /* SD */ - OP_RX | OP_DPF, /* MD */ - OP_RX | OP_DPF, /* DD */ - OP_RX | OP_DPF, /* STMD */ - OP_RX | OP_DPF, /* LMD */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 80:8F */ - 0, 0, 0, 0, 0, 0, 0, 0, - OP_NO, /* SRHLS */ - OP_NO, /* SLHLS */ - OP_NO, /* STBR */ - OP_RR, /* LDBR */ - OP_RR, /* EXBR */ - OP_NO | OP_PRV, /* EPSR */ - OP_RR | OP_PRV, /* WBR */ - OP_RR | OP_PRV, /* RBR */ - OP_RR | OP_PRV, /* WHR */ - OP_RR | OP_PRV, /* RHR */ - OP_RR | OP_PRV, /* WDR */ - OP_RR | OP_PRV, /* RDR */ - 0, /* 9C */ - OP_RR | OP_PRV, /* SSR */ - OP_RR | OP_PRV, /* OCR */ - 0, /* 9F */ - 0, 0, 0, 0, 0, 0, 0, 0, /* A0:AF */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, /* B0:BF */ - 0, 0, 0, 0, 0, 0, 0, 0, - OP_RX, /* BXH */ - OP_RX, /* BXLE */ - OP_RXF | OP_PRV, /* LPSW */ - OP_RI1, /* THI */ - OP_RI1, /* NHI */ - OP_RI1, /* CLHI */ - OP_RI1, /* OHI */ - OP_RI1, /* XHI */ - OP_RI1, /* LHI */ - OP_RI1, /* CHI */ - OP_RI1, /* AHI */ - OP_RI1, /* SHI */ - OP_RI1, /* SRHL */ - OP_RI1, /* SLHL */ - OP_RI1, /* SRHA */ - OP_RI1, /* SLHA */ - OP_RX, /* STM */ - OP_RX, /* LM */ - OP_RX, /* STB */ - OP_RXB, /* LDB */ - OP_RXB, /* CLB */ - OP_RX | OP_PRV, /* AL */ - OP_RXF | OP_PRV, /* WB */ - OP_RXF | OP_PRV, /* RB */ - OP_RX | OP_PRV, /* WH */ - OP_RX | OP_PRV, /* RH */ - OP_RX | OP_PRV, /* WD */ - OP_RX | OP_PRV, /* RD */ - 0, /* DC */ - OP_RX | OP_PRV, /* SS */ - OP_RX | OP_PRV, /* OC */ - 0, /* DF */ - OP_RXH, /* TS */ - OP_RX, /* SVC */ - OP_RI1 | OP_PRV, /* SINT */ - OP_RXH | OP_PRV, /* SCP */ - 0, 0, /* E4:E5 */ - OP_RX, /* LA */ - OP_RXF, /* TLATE */ - 0, 0, /* E8:E9 */ - OP_RI1, /* RRL */ - OP_RI1, /* RLL */ - OP_RI1, /* SRL */ - OP_RI1, /* SLL */ - OP_RI1, /* SRA */ - OP_RI1, /* SLA */ - 0, 0, 0, /* F0:F2 */ - OP_RI2, /* TI */ - OP_RI2, /* NI */ - OP_RI2, /* CLI */ - OP_RI2, /* OI */ - OP_RI2, /* XI */ - OP_RI2, /* LI */ - OP_RI2, /* CI */ - OP_RI2, /* AI */ - OP_RI2, /* SI */ - 0, 0, 0, 0 /* FC:FF */ - }; - -/* CPU data structures - - cpu_dev CPU device descriptor - cpu_unit CPU unit descriptor - cpu_reg CPU register list - cpu_mod CPU modifiers list -*/ - -DIB cpu_dib = { d_DS, -1, v_DS, NULL, &display }; - -UNIT cpu_unit = { UDATA (NULL, UNIT_FIX | UNIT_BINK, MAXMEMSIZE32) }; - -REG cpu_reg[] = { - { HRDATA (PC, PC, 20) }, - { HRDATA (OPC, oPC, 20), REG_HRO }, - { HRDATA (R0, GREG[0], 32) }, - { HRDATA (R1, GREG[1], 32) }, - { HRDATA (R2, GREG[2], 32) }, - { HRDATA (R3, GREG[3], 32) }, - { HRDATA (R4, GREG[4], 32) }, - { HRDATA (R5, GREG[5], 32) }, - { HRDATA (R6, GREG[6], 32) }, - { HRDATA (R7, GREG[7], 32) }, - { HRDATA (R8, GREG[8], 32) }, - { HRDATA (R9, GREG[9], 32) }, - { HRDATA (R10, GREG[10], 32) }, - { HRDATA (R11, GREG[11], 32) }, - { HRDATA (R12, GREG[12], 32) }, - { HRDATA (R13, GREG[13], 32) }, - { HRDATA (R14, GREG[14], 32) }, - { HRDATA (R15, GREG[15], 32) }, - { HRDATA (FR0, F[0], 32) }, - { HRDATA (FR2, F[1], 32) }, - { HRDATA (FR4, F[2], 32) }, - { HRDATA (FR6, F[3], 32) }, - { HRDATA (FR8, F[4], 32) }, - { HRDATA (FR10, F[5], 32) }, - { HRDATA (FR12, F[6], 32) }, - { HRDATA (FR14, F[7], 32) }, - { HRDATA (D0H, D[0].h, 32) }, - { HRDATA (D0L, D[0].l, 32) }, - { HRDATA (D2H, D[1].h, 32) }, - { HRDATA (D2L, D[1].l, 32) }, - { HRDATA (D4H, D[2].h, 32) }, - { HRDATA (D4L, D[2].l, 32) }, - { HRDATA (D6H, D[3].h, 32) }, - { HRDATA (D6L, D[3].l, 32) }, - { HRDATA (D8H, D[4].h, 32) }, - { HRDATA (D8L, D[4].l, 32) }, - { HRDATA (D10H, D[5].h, 32) }, - { HRDATA (D10L, D[5].l, 32) }, - { HRDATA (D12L, D[6].l, 32) }, - { HRDATA (D12H, D[6].h, 32) }, - { HRDATA (D14H, D[7].h, 32) }, - { HRDATA (D14L, D[7].l, 32) }, - { HRDATA (PSW, PSW, 16) }, - { HRDATA (CC, PSW, 4) }, - { HRDATA (SR, SR, 32) }, - { HRDATA (DR, DR, 32) }, - { HRDATA (DRX, DRX, 8) }, - { FLDATA (DRMOD, drmod, 0) }, - { FLDATA (SRPOS, srpos, 0) }, - { HRDATA (DRPOS, drpos, 3) }, - { BRDATA (IRQ, int_req, 16, 32, INTSZ) }, - { BRDATA (IEN, int_enb, 16, 32, INTSZ) }, - { BRDATA (MACREG, mac_reg, 16, 32, MAC_LNT) }, - { HRDATA (MACSTA, mac_sta, 5) }, - { HRDATA (QEVENT, qevent, 4), REG_HRO }, - { FLDATA (STOP_INST, stop_inst, 0) }, - { FLDATA (STOP_WAIT, stop_wait, 0) }, - { BRDATA (PCQ, pcq, 16, 20, PCQ_SIZE), REG_RO+REG_CIRC }, - { HRDATA (PCQP, pcq_p, 6), REG_HRO }, - { HRDATA (WRU, sim_int_char, 8) }, - { HRDATA (BLKIOD, blk_io.dfl, 16), REG_HRO }, - { HRDATA (BLKIOC, blk_io.cur, 20), REG_HRO }, - { HRDATA (BLKIOE, blk_io.end, 20), REG_HRO }, - { BRDATA (GREG, GREG, 16, 32, 16 * NRSETS) }, - { NULL } - }; - -MTAB cpu_mod[] = { - { UNIT_8RS|UNIT_TYPE, 0, NULL, "732", NULL }, - { UNIT_DPFP, UNIT_DPFP, NULL, "DPFP", NULL }, - { UNIT_TYPE, 0, "7/32, single precision fp", "732", NULL }, - { UNIT_TYPE, UNIT_DPFP, "7/32, double precision fp", NULL, NULL }, - { UNIT_8RS|UNIT_TYPE, UNIT_8RS|UNIT_DPFP|UNIT_832, NULL, "832", NULL }, - { UNIT_8RS, 0, NULL, "2RS", NULL }, - { UNIT_8RS|UNIT_TYPE, UNIT_8RS|UNIT_DPFP|UNIT_832, "832, 8 register sets", NULL, NULL }, - { UNIT_8RS|UNIT_TYPE, UNIT_DPFP|UNIT_832, "832, 2 register sets", NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL }, - { UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size }, - { UNIT_MSIZE, 131072, NULL, "128K", &cpu_set_size }, - { UNIT_MSIZE, 262144, NULL, "256K", &cpu_set_size }, - { UNIT_MSIZE, 524288, NULL, "512K", &cpu_set_size }, - { UNIT_MSIZE, 1048756, NULL, "1M", &cpu_set_size }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "CONSINT", - &cpu_set_consint, NULL, NULL }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", - &cpu_set_hist, &cpu_show_hist }, - { 0 } - }; - -DEBTAB cpu_deb[] = { - { "INTEXC", LOG_CPU_I }, - { "CONTEXT", LOG_CPU_C }, - { NULL, 0 } - }; - -DEVICE cpu_dev = { - "CPU", &cpu_unit, cpu_reg, cpu_mod, - 1, 16, 20, 2, 16, 16, - &cpu_ex, &cpu_dep, &cpu_reset, - NULL, NULL, NULL, - &cpu_dib, DEV_DEBUG, 0, - cpu_deb, NULL, NULL - }; - -t_stat sim_instr (void) -{ -volatile uint32 cc; /* set before setjmp */ -t_stat reason; /* set after setjmp */ -int abortval; - -/* Restore register state */ - -if (devtab_init ()) /* check conflicts */ - return SCPE_STOP; -if (cpu_unit.flags & (UNIT_DPFP | UNIT_832)) { - fp_in_hwre = 1; /* fp in hwre */ - dec_flgs = 0; /* all instr ok */ - } -else { - fp_in_hwre = 0; /* fp in ucode */ - dec_flgs = OP_DPF; /* sp only */ - } -if (cpu_unit.flags & UNIT_8RS) /* 8 register sets */ - psw_reg_mask = 7; -else psw_reg_mask = 1; /* 2 register sets */ -int_eval (); /* eval interrupts */ -cc = newPSW (PSW & PSW_MASK); /* split PSW, eval wait */ -reason = 0; - -/* Abort handling - - If an abort occurs in memory protection, the relocation routine - executes a longjmp to this area OUTSIDE the main simulation loop. - Memory protection errors are the only sources of aborts in the - Interdata 32b systems. All referenced variables must be globals, - and all sim_instr scoped automatic variables must be volatile or - set after the call on setjmp. -*/ - -abortval = setjmp (save_env); /* set abort hdlr */ -if (abortval != 0) { /* mem mgt abort? */ - qevent = qevent | EV_MAC; /* set MAC intr */ - if (cpu_unit.flags & UNIT_832) /* 832? restore PC */ - PC = oPC; - } - -/* Event handling */ - -while (reason == 0) { /* loop until halted */ - - uint32 dev, drom, opnd, inc, lim, bufa; - uint32 op, r1, r1p1, r2, rx2, ea; - uint32 mpy, mpc, dvr; - uint32 i, rslt, rlo, t; - uint32 ir1, ir2, ir3, ityp; - int32 sr, st; - - if (sim_interval <= 0) { /* check clock queue */ - if ((reason = sim_process_event ())) - break; - int_eval (); - } - - if (qevent) { /* any events? */ - if (qevent & EV_MAC) { /* MAC interrupt? */ - qevent = 0; /* clr all events */ - cc = exception (MPRPSW, cc, 0); /* take exception */ - int_eval (); /* re-eval intr */ - continue; - } - - if (qevent & EV_BLK) { /* block I/O in prog? */ - dev = blk_io.dfl & DEV_MAX; /* get device */ - cc = dev_tab[dev] (dev, IO_SS, 0) & 0xF; /* sense status */ - if (cc == STA_BSY) { /* just busy? */ - sim_interval = 0; /* force I/O event */ - continue; - } - else if (cc == 0) { /* ready, no err? */ - if (blk_io.dfl & BL_RD) { /* read? */ - t = dev_tab[dev] (dev, IO_RD, 0); /* get byte */ - if ((t == 0) && (blk_io.dfl & BL_LZ)) - continue; - blk_io.dfl = blk_io.dfl & ~BL_LZ; /* non-zero seen */ - WriteB (blk_io.cur, t, VW); /* write mem */ - } - else { /* write */ - t = ReadB (blk_io.cur, VR); /* read mem */ - dev_tab[dev] (dev, IO_WD, t); /* put byte */ - } - if (blk_io.cur != blk_io.end) { /* more to do? */ - blk_io.cur = (blk_io.cur + 1) & VAMASK; /* incr addr */ - continue; - } - } - qevent = qevent & ~EV_BLK; /* clr blk I/O flag */ - int_eval (); /* re-eval intr */ - continue; - } - - if ((qevent & EV_INT) && (PSW & PSW_EXI)) { /* interrupt? */ - dev = int_getdev (); /* get int dev */ - cc = int_auto (dev, cc); /* do auto intr */ - int_eval (); /* re-eval intr */ - continue; - } - - if (PSW & PSW_WAIT) { /* wait state? */ - sim_idle (TMR_LFC, TRUE); /* idling */ - continue; - } - - qevent = 0; /* no events */ - } - -/* Instruction fetch and decode */ - - if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; - } - - sim_interval = sim_interval - 1; - - ir1 = ReadH (oPC = PC, VE); /* fetch instr */ - op = (ir1 >> 8) & 0xFF; /* extract op,R1,R2 */ - r1 = (ir1 >> 4) & 0xF; - r2 = ir1 & 0xF; - drom = decrom[op]; /* get decode flags */ - ityp = drom & OP_MASK; /* instruction type */ - - if ((drom == 0) || (drom & dec_flgs)) { /* not in model? */ - if (stop_inst) /* stop or */ - reason = STOP_RSRV; - else cc = exception (ILOPSW, cc, 0); /* exception */ - continue; - } - if ((drom & OP_PRV) && (PSW & PSW_PRO)) { /* priv & protected? */ - cc = exception (ILOPSW, cc, 0); /* exception */ - continue; - } - - switch (ityp) { /* decode instruction */ - - case OP_NO: /* no operand */ - opnd = r2; /* assume short */ - PC = (PC + 2) & VAMASK; /* increment PC */ - break; - - case OP_RR: /* reg-reg */ - opnd = R[r2]; /* ea/operand is R2 */ - PC = (PC + 2) & VAMASK; /* increment PC */ - break; - - case OP_RI1: /* reg-imm 1 */ - ir2 = ReadH ((PC + 2) & VAMASK, VE); /* fetch immed */ - opnd = SEXT16 (ir2); /* sign extend */ - if (r2) /* index calculation */ - opnd = (opnd + R[r2]) & DMASK32; - PC = (PC + 4) & VAMASK; /* increment PC */ - break; - - case OP_RI2: /* reg-imm 2 */ - ir2 = ReadH ((PC + 2) & VAMASK, VE); /* fetch imm hi */ - ir3 = ReadH ((PC + 4) & VAMASK, VE); /* fetch imm lo */ - opnd = (ir2 << 16) | ir3; /* 32b immediate */ - if (r2) /* index calculation */ - opnd = (opnd + R[r2]) & DMASK32; - PC = (PC + 6) & VAMASK; /* increment PC */ - break; - - case OP_RX: case OP_RXB: case OP_RXH: case OP_RXF: /* reg-mem */ - ir2 = ReadH ((PC + 2) & VAMASK, VE); /* fetch addr */ - if ((ir2 & 0xC000) == 0) { /* displacement? */ - PC = (PC + 4) & VAMASK; /* increment PC */ - ea = ir2; /* abs 14b displ */ - } - else if (ir2 & 0x8000) { /* relative? */ - PC = (PC + 4) & VAMASK; /* increment PC */ - ea = PC + SEXT15 (ir2); /* add to incr PC */ - } - else { /* absolute */ - rx2 = (ir2 >> 8) & 0xF; /* get second index */ - ea = (ir2 & 0xFF) << 16; /* shift to place */ - ir3 = ReadH ((PC + 4) & VAMASK, VE); /* fetch addr lo */ - ea = ea | ir3; /* finish addr */ - if (rx2) /* index calc 2 */ - ea = ea + R[rx2]; - PC = (PC + 6) & VAMASK; /* increment PC */ - } - if (r2) /* index calculation */ - ea = ea + R[r2]; - ea = ea & VAMASK; - if (ityp == OP_RXF) /* get fw operand? */ - opnd = ReadF (ea, VR); - else if (ityp == OP_RXH) { /* get hw operand? */ - t = ReadH (ea, VR); /* read halfword */ - opnd = SEXT16 (t); /* sign extend */ - } - else if (ityp == OP_RXB) /* get byte opnd? */ - opnd = ReadB (ea, VR); - else opnd = ea; /* just address */ - break; - - default: - return SCPE_IERR; - } - - if (hst_lnt) { /* instruction history? */ - hst[hst_p].pc = oPC | HIST_PC; /* save decode state */ - hst[hst_p].ir1 = ir1; - hst[hst_p].ir2 = ir2; - hst[hst_p].ir3 = ir3; - hst[hst_p].r1 = R[r1]; - hst[hst_p].ea = ea; - hst[hst_p].opnd = opnd; - hst_p = hst_p + 1; - if (hst_p >= hst_lnt) - hst_p = 0; - } - if (qevent & EV_MAC) /* MAC abort on fetch? */ - continue; - switch (op) { /* case on opcode */ - -/* Load/store instructions */ - - case 0x08: /* LR - RR */ - case 0x24: /* LIS - NO */ - case 0x48: /* LH - RXH */ - case 0x58: /* L - RXF */ - case 0xC8: /* LHI - RI1 */ - case 0xF8: /* LI - RI2 */ - R[r1] = opnd; /* load operand */ - CC_GL_32 (R[r1]); /* set G,L */ - break; - - case 0x73: /* LHL - RXH */ - R[r1] = opnd & DMASK16; /* get op, zero ext */ - CC_GL_32 (R[r1]); /* set G, L */ - break; - - case 0x25: /* LCS - NO */ - R[r1] = NEG (opnd); /* load complement */ - CC_GL_32 (R[r1]); /* set G,L */ - break; - - case 0xE6: /* LA - RX */ - R[r1] = ea; /* load addr */ - break; - - case 0x63: /* LRA - RX */ - cc = RelocT (R[r1] & VAMASK, ea, VR, &R[r1]); /* test reloc */ - break; - - case 0x40: /* STH - RX */ - WriteH (ea, R[r1], VW); /* store register */ - break; - - case 0x50: /* ST - RX */ - WriteF (ea, R[r1], VW); /* store register */ - break; - - case 0xD1: /* LM - RX */ - for ( ; r1 <= 0xF; r1++) { /* loop thru reg */ - R[r1] = ReadF (ea, VR); /* load register */ - ea = (ea + 4) & VAMASK; /* incr mem addr */ - } - break; - - case 0xD0: /* STM - RX */ - for ( ; r1 <= 0xF; r1++) { /* loop thru reg */ - WriteF (ea, R[r1], VW); /* store register */ - ea = (ea + 4) & VAMASK; /* incr mem addr */ - } - break; - - case 0xE0: /* TS - RXH */ - CC_GL_16 (opnd); /* set cc's */ - WriteH (ea, opnd | SIGN16, VW); /* set MSB */ - break; - - case 0x93: /* LDBR - RR */ - case 0xD3: /* LDB - RXB */ - R[r1] = opnd & DMASK8; /* load byte */ - break; - - case 0x92: /* STBR - NO */ - R[r2] = (R[r2] & ~DMASK8) | (R[r1] & DMASK8); /* store byte */ - break; - case 0xD2: /* STB - RX */ - WriteB (ea, R[r1], VW); /* store byte */ - break; - - case 0x34: /* EXHR - RR */ - R[r1] = ((opnd >> 16) & DMASK16) | ((opnd & DMASK16) << 16); - break; - - case 0x94: /* EXBR - RR */ - R[r1] = (R[r1] & ~DMASK16) | - ((opnd >> 8) & DMASK8) | ((opnd & DMASK8) << 8); - break; - -/* Control instructions */ - - case 0x01: /* BALR - RR */ - case 0x41: /* BAL - RX */ - PCQ_ENTRY; /* save old PC */ - R[r1] = PC; /* save cur PC */ - PC = opnd & VAMASK; /* branch */ - break; - - case 0x02: /* BTCR - RR */ - case 0x42: /* BTC - RX */ - if (cc & r1) { /* test CC's */ - PCQ_ENTRY; /* branch if true */ - PC = opnd & VAMASK; - } - break; - - case 0x20: /* BTBS - NO */ - if (cc & r1) { /* test CC's */ - PCQ_ENTRY; /* branch if true */ - PC = (oPC - r2 - r2) & VAMASK; - } - break; - - case 0x21: /* BTFS - NO */ - if (cc & r1) { /* test CC's */ - PCQ_ENTRY; /* branch if true */ - PC = (oPC + r2 + r2) & VAMASK; - } - break; - - case 0x03: /* BFCR - RR */ - case 0x43: /* BFC - RX */ - if ((cc & r1) == 0) { /* test CC's */ - PCQ_ENTRY; /* branch if false */ - PC = opnd & VAMASK; - } - break; - - case 0x22: /* BFBS - NO */ - if ((cc & r1) == 0) { /* test CC's */ - PCQ_ENTRY; /* branch if false */ - PC = (oPC - r2 - r2) & VAMASK; - } - break; - - case 0x23: /* BFFS - NO */ - if ((cc & r1) == 0) { /* test CC's */ - PCQ_ENTRY; /* branch if false */ - PC = (oPC + r2 + r2) & VAMASK; - } - break; - - case 0xC0: /* BXH - RX */ - inc = R[(r1 + 1) & 0xF]; /* inc = R1 + 1 */ - lim = R[(r1 + 2) & 0xF]; /* lim = R1 + 2 */ - R[r1] = (R[r1] + inc) & DMASK32; /* R1 = R1 + inc */ - if (R[r1] > lim) { /* if R1 > lim */ - PCQ_ENTRY; /* branch */ - PC = opnd & VAMASK; - } - break; - - case 0xC1: /* BXLE - RX */ - inc = R[(r1 + 1) & 0xF]; /* inc = R1 + 1 */ - lim = R[(r1 + 2) & 0xF]; /* lim = R1 + 2 */ - R[r1] = (R[r1] + inc) & DMASK32; /* R1 = R1 + inc */ - if (R[r1] <= lim) { /* if R1 <= lim */ - PCQ_ENTRY; /* branch */ - PC = opnd & VAMASK; - } - break; - -/* Logical instructions */ - - case 0x04: /* NR - RR */ - case 0x44: /* NH - RXH */ - case 0x54: /* N - RXF */ - case 0xC4: /* NHI - RI1 */ - case 0xF4: /* NI - RI2 */ - R[r1] = R[r1] & opnd; /* result */ - CC_GL_32 (R[r1]); /* set G,L */ - break; - - case 0x06: /* OR - RR */ - case 0x46: /* OH - RXH */ - case 0x56: /* O - RXF */ - case 0xC6: /* OHI - RI1 */ - case 0xF6: /* OI - RI2 */ - R[r1] = R[r1] | opnd; /* result */ - CC_GL_32 (R[r1]); /* set G,L */ - break; - - case 0x07: /* XR - RR */ - case 0x47: /* XH - RXH */ - case 0x57: /* X - RXF */ - case 0xC7: /* XHI - RI1 */ - case 0xF7: /* XI - RI2 */ - R[r1] = R[r1] ^ opnd; /* result */ - CC_GL_32 (R[r1]); /* set G,L */ - break; - - case 0xC3: /* THI - RI1 */ - case 0xF3: /* TI - RI2 */ - rslt = R[r1] & opnd; /* result */ - CC_GL_32 (rslt); /* set G, L */ - break; - - case 0x05: /* CLR - RR */ - case 0x45: /* CLH - RXH */ - case 0x55: /* CL - RXF */ - case 0xC5: /* CLHI - RI1 */ - case 0xF5: /* CI - RI2 */ - rslt = (R[r1] - opnd) & DMASK32; /* result */ - CC_GL_32 (rslt); /* set G,L */ - if (R[r1] < opnd) /* set C if borrow */ - cc = cc | CC_C; - if (((R[r1] ^ opnd) & (~opnd ^ rslt)) & SIGN32) - cc = cc | CC_V; - break; - - case 0xD4: /* CLB - RXB */ - t = R[r1] & DMASK8; - rslt = (t - opnd) & DMASK16; /* result */ - CC_GL_16 (rslt); /* set G,L 16b */ - if (t < opnd) /* set C if borrow */ - cc = cc | CC_C; - break; - - case 0x12: /* CHVR - RR */ - t = cc & CC_C; /* save C */ - R[r1] = (SEXT16 (opnd & DMASK16)) & DMASK32; /* result */ - CC_GL_32 (R[r1]); /* set G, L */ - if (R[r1] != opnd) /* wont fit? set V */ - cc = cc | CC_V; - cc = cc | t; /* restore C */ - break; - -/* Shift instructions */ - - case 0xCC: /* SRHL - RI1 */ - opnd = opnd & 0xF; /* shift count */ - case 0x90: /* SRHLS - NO */ - rslt = (R[r1] & DMASK16) >> opnd; /* result */ - CC_GL_16 (rslt); /* set G,L 16b */ - if (opnd && (((R[r1] & DMASK16) >> (opnd - 1)) & 1)) - cc = cc | CC_C; - R[r1] = (R[r1] & ~DMASK16) | rslt; /* store result */ - break; - - case 0xCD: /* SLHL - RI1 */ - opnd = opnd & 0xF; /* shift count */ - case 0x91: /* SLHLS - NO */ - rslt = R[r1] << opnd; /* result */ - CC_GL_16 (rslt & DMASK16); /* set G,L 16b */ - if (opnd && (rslt & 0x10000)) /* set C if shft out */ - cc = cc | CC_C; - R[r1] = (R[r1] & ~DMASK16) | (rslt & DMASK16); /* store result */ - break; - - case 0xCE: /* SRHA - RI1 */ - opnd = opnd & 0xF; /* shift count */ - rslt = (SEXT16 (R[r1]) >> opnd) & DMASK16; /* result */ - CC_GL_16 (rslt); /* set G,L 16b */ - if (opnd && ((R[r1] >> (opnd - 1)) & 1)) - cc = cc | CC_C; - R[r1] = (R[r1] & ~DMASK16) | rslt; /* store result */ - break; - - case 0xCF: /* SLHA - RI1 */ - opnd = opnd & 0xF; /* shift count */ - rslt = R[r1] << opnd; /* raw result */ - R[r1] = (R[r1] & ~MMASK16) | (rslt & MMASK16); - CC_GL_16 (R[r1] & DMASK16); /* set G,L 16b */ - if (opnd && (rslt & SIGN16)) /* set C if shft out */ - cc = cc | CC_C; - break; - - case 0xEC: /* SRL - RI1 */ - opnd = opnd & 0x1F; /* shift count */ - case 0x10: /* SRLS - NO */ - rslt = R[r1] >> opnd; /* result */ - CC_GL_32 (rslt); /* set G,L */ - if (opnd && ((R[r1] >> (opnd - 1)) & 1)) - cc = cc | CC_C; - R[r1] = rslt; /* store result */ - break; - - case 0xED: /* SLL - RI1 */ - opnd = opnd & 0x1F; /* shift count */ - case 0x11: /* SLLS - NO */ - rslt = (R[r1] << opnd) & DMASK32; /* result */ - CC_GL_32 (rslt); /* set G,L */ - if (opnd && ((R[r1] << (opnd - 1)) & SIGN32)) - cc = cc | CC_C; - R[r1] = rslt; /* store result */ - break; - - case 0xEE: /* SRA - RI1 */ - opnd = opnd & 0x1F; /* shift count */ - rslt = (SEXT32 (R[r1]) >> opnd) & DMASK32; /* result */ - CC_GL_32 (rslt); /* set G,L */ - if (opnd && ((R[r1] >> (opnd - 1)) & 1)) - cc = cc | CC_C; - R[r1] = rslt; /* store result */ - break; - - case 0xEF: /* SLA - RI1 */ - opnd = opnd & 0x1F; /* shift count */ - rslt = (R[r1] << opnd) & DMASK32; /* raw result */ - R[r1] = (R[r1] & SIGN32) | (rslt & MMASK32); /* arith result */ - CC_GL_32 (R[r1]); /* set G,L */ - if (opnd && (rslt & SIGN32)) /* set C if shft out */ - cc = cc | CC_C; - break; - - case 0xEA: /* RRL - RI1 */ - opnd = opnd & 0x1F; /* shift count */ - if (opnd) /* if cnt > 0 */ - R[r1] = (R[r1] >> opnd) | ((R[r1] << (32 - opnd)) & DMASK32); - CC_GL_32 (R[r1]); /* set G,L */ - break; - - case 0xEB: /* RLL - RI1 */ - opnd = opnd & 0x1F; /* shift count */ - if (opnd) - R[r1] = ((R[r1] << opnd) & DMASK32) | (R[r1] >> (32 - opnd)); - CC_GL_32 (R[r1]); /* set G,L */ - break; - -/* Bit instructions */ - - case 0x74: /* TBT - RX */ - t = 1u << (15 - (R[r1] & 0xF)); /* bit mask in HW */ - ea = (ea + ((R[r1] >> 3) & ~1)) & VAMASK; /* HW location */ - opnd = ReadH (ea, VR); /* read HW */ - if (opnd & t) /* test bit */ - cc = CC_G; - else cc = 0; - break; - - case 0x75: /* SBT - RX */ - t = 1u << (15 - (R[r1] & 0xF)); /* bit mask in HW */ - ea = (ea + ((R[r1] >> 3) & ~1)) & VAMASK; /* HW location */ - opnd = ReadH (ea, VR); /* read HW */ - WriteH (ea, opnd | t, VW); /* set bit, rewr */ - if (opnd & t) /* test bit */ - cc = CC_G; - else cc = 0; - break; - - case 0x76: /* RBT - RX */ - t = 1u << (15 - (R[r1] & 0xF)); /* bit mask in HW */ - ea = (ea + ((R[r1] >> 3) & ~1)) & VAMASK; /* HW location */ - opnd = ReadH (ea, VR); /* read HW */ - WriteH (ea, opnd & ~t, VW); /* clr bit, rewr */ - if (opnd & t) /* test bit */ - cc = CC_G; - else cc = 0; - break; - - case 0x77: /* CBT - RX */ - t = 1u << (15 - (R[r1] & 0xF)); /* bit mask in HW */ - ea = (ea + ((R[r1] >> 3) & ~1)) & VAMASK; /* HW location */ - opnd = ReadH (ea, VR); /* read HW */ - WriteH (ea, opnd ^ t, VW); /* com bit, rewr */ - if (opnd & t) /* test bit */ - cc = CC_G; - else cc = 0; - break; - -/* Arithmetic instructions */ - - case 0x0A: /* AR - RR */ - case 0x26: /* AIS - NO */ - case 0x4A: /* AH - RXH */ - case 0x5A: /* A - RXF */ - case 0xCA: /* AHI - RI1 */ - case 0xFA: /* AI - RI2 */ - rslt = (R[r1] + opnd) & DMASK32; /* result */ - CC_GL_32 (rslt); /* set G,L */ - if (rslt < opnd) /* set C if carry */ - cc = cc | CC_C; - if (((~R[r1] ^ opnd) & (R[r1] ^ rslt)) & SIGN32) - cc = cc | CC_V; - R[r1] = rslt; - break; - - case 0x51: /* AM - RXF */ - rslt = (R[r1] + opnd) & DMASK32; /* result */ - WriteF (ea, rslt, VW); /* write result */ - CC_GL_32 (rslt); /* set G,L */ - if (rslt < opnd) /* set C if carry */ - cc = cc | CC_C; - if (((~R[r1] ^ opnd) & (R[r1] ^ rslt)) & SIGN32) - cc = cc | CC_V; - break; - - case 0x61: /* AHM - RXH */ - rslt = (R[r1] + opnd) & DMASK16; /* result */ - WriteH (ea, rslt, VW); /* write result */ - CC_GL_16 (rslt); /* set G,L 16b */ - if (rslt < (opnd & DMASK16)) /* set C if carry */ - cc = cc | CC_C; - if (((~R[r1] ^ opnd) & (R[r1] ^ rslt)) & SIGN16) - cc = cc | CC_V; - break; - - case 0x0B: /* SR - RR */ - case 0x27: /* SIS - NO */ - case 0x4B: /* SH - RXH */ - case 0x5B: /* S - RXF */ - case 0xCB: /* SHI - RI1 */ - case 0xFB: /* SI - RI2 */ - rslt = (R[r1] - opnd) & DMASK32; /* result */ - CC_GL_32 (rslt); /* set G,L */ - if (R[r1] < opnd) /* set C if borrow */ - cc = cc | CC_C; - if (((R[r1] ^ opnd) & (~opnd ^ rslt)) & SIGN32) - cc = cc | CC_V; - R[r1] = rslt; - break; - - case 0x09: /* CR - RR */ - case 0x49: /* CH - RXH */ - case 0x59: /* C - RXF */ - case 0xC9: /* CHI - RI1 */ - case 0xF9: /* CI - RI2 */ - if (R[r1] == opnd) cc = 0; /* =? */ - else if ((R[r1] ^ opnd) & SIGN32) /* unlike signs? */ - cc = (R[r1] & SIGN32)? (CC_C | CC_L): CC_G; - else cc = (R[r1] > opnd)? CC_G: (CC_C | CC_L); /* like signs */ - if (((R[r1] ^ opnd) & (~opnd ^ (R[r1] - opnd))) & SIGN32) - cc = cc | CC_V; - break; - - case 0x0C: /* MHR - RR */ - case 0x4C: /* MH - RXH */ - R[r1] = (SEXT16 (R[r1]) * SEXT16 (opnd)) & DMASK32; /* multiply */ - break; - - case 0x1C: /* MR - RR */ - case 0x5C: /* M - RXF */ - r1p1 = (r1 + 1) & 0xF; - mpc = ABS (opnd); /* |mpcnd| */ - mpy = ABS (R[r1p1]); /* |mplyr| */ - rslt = rlo = 0; /* clr result */ - for (i = 0; i < 32; i++) { /* develop 32b */ - t = 0; /* no cout */ - if (mpy & 1) { /* cond add */ - rslt = (rslt + mpc) & DMASK32; - if (rslt < mpc) - t = SIGN32; - } - rlo = (rlo >> 1) | ((rslt & 1) << 31); /* shift result */ - rslt = (rslt >> 1) | t; - mpy = mpy >> 1; /* shift mpylr */ - } - if ((opnd ^ R[r1p1]) & SIGN32) { - DNEG (rslt, rlo); - } - R[r1] = rslt; /* store result */ - R[r1p1] = rlo; - break; - - case 0x0D: /* DHR - RR */ - case 0x4D: /* DH - RXH */ - opnd = opnd & DMASK16; /* force HW opnd */ - if ((opnd == 0) || /* div by zero? */ - ((R[r1] == 0x80000000) && (opnd == 0xFFFF))) { - if (PSW & PSW_AFI) /* div fault enabled? */ - cc = exception (AFIPSW, cc, 0); /* exception */ - break; - } - r1p1 = (r1 + 1) & 0xF; - st = SEXT32 (R[r1]) / SEXT16 (opnd); /* quotient */ - sr = SEXT32 (R[r1]) % SEXT16 (opnd); /* remainder */ - if ((st < 0x8000) && (st >= -0x8000)) { /* if quo fits */ - R[r1] = sr & DMASK32; /* store remainder */ - R[r1p1] = st & DMASK32; /* store quotient */ - } - else if (PSW & PSW_AFI) /* div fault enabled? */ - cc = exception (AFIPSW, cc, 0); /* exception */ - break; - - case 0x1D: /* DR - RR */ - case 0x5D: /* D - RXF */ - r1p1 = (r1 + 1) & 0xF; - rslt = R[r1]; /* get dividend */ - rlo = R[r1p1]; - if (R[r1] & SIGN32) { DNEG (rslt, rlo); } /* |divd| */ - dvr = ABS (opnd); /* |divr| */ - if (rslt < dvr) { /* will div work? */ - uint32 quos = R[r1] ^ opnd; /* expected sign */ - for (i = t = 0; i < 32; i++) { /* 32 iterations */ - rslt = ((rslt << 1) & DMASK32) | /* shift divd */ - ((rlo >> 31) & 1); - rlo = (rlo << 1) & DMASK32; - t = (t << 1) & DMASK32; /* shift quo */ - if (rslt >= dvr) { /* subtract work? */ - rslt = rslt - dvr; /* divd -= divr */ - t = t | 1; /* set quo bit */ - } - } - if (quos & SIGN32) /* res -? neg quo */ - t = NEG (t); - if (R[r1] & SIGN32) /* adj rem sign */ - rslt = NEG (rslt); - if (t && ((t ^ quos) & SIGN32)) { /* res sign wrong? */ - if (PSW & PSW_AFI) /* if enabled, */ - cc = exception (AFIPSW, cc, 0); /* exception */ - break; - } - R[r1] = rslt; /* store rem */ - R[r1p1] = t; /* store quo */ - } - else if (PSW & PSW_AFI) /* div fault enabled? */ - cc = exception (AFIPSW, cc, 0); /* exception */ - break; - -/* Floating point instructions */ - - case 0x28: /* LER - NO */ - case 0x38: /* LDR - NO */ - case 0x68: /* LE - RX */ - case 0x78: /* LD - RX */ - cc = f_l (op, r1, r2, ea); /* load */ - if ((cc & CC_V) && (PSW & PSW_AFI)) /* V set? */ - cc = exception (AFIPSW, cc, 1); - break; - - case 0x29: /* CER - NO */ - case 0x39: /* CDR - NO */ - case 0x69: /* CE - RX */ - case 0x79: /* CD - RX */ - cc = f_c (op, r1, r2, ea); /* compare */ - break; - - case 0x2A: /* AER - NO */ - case 0x2B: /* SER - NO */ - case 0x3A: /* ADR - NO */ - case 0x3B: /* SDR - NO */ - case 0x6A: /* AE - RX */ - case 0x6B: /* SE - RX */ - case 0x7A: /* AD - RX */ - case 0x7B: /* SD - RX */ - cc = f_as (op, r1, r2, ea); /* add/sub */ - if ((cc & CC_V) && (PSW & PSW_AFI)) /* V set? */ - cc = exception (AFIPSW, cc, 1); - break; - - case 0x2C: /* MER - NO */ - case 0x3C: /* MDR - NO */ - case 0x6C: /* ME - RX */ - case 0x7C: /* MD - RX */ - cc = f_m (op, r1, r2, ea); /* multiply */ - if ((cc & CC_V) && (PSW & PSW_AFI)) /* V set? */ - cc = exception (AFIPSW, cc, 1); - break; - - case 0x2D: /* DER - NO */ - case 0x3D: /* DDR - NO */ - case 0x6D: /* DE - RX */ - case 0x7D: /* DD - RX */ - cc = f_d (op, r1, r2, ea); /* perform divide */ - if ((cc & CC_V) && (PSW & PSW_AFI)) /* V set? */ - cc = exception (AFIPSW, cc, 1); - break; - - case 0x2E: /* FXR - NO */ - case 0x3E: /* FXDR - NO */ - cc = f_fix32 (op, r1, r2); /* cvt to integer */ - break; - - case 0x2F: /* FLR - NO */ - case 0x3F: /* FLDR - NO */ - cc = f_flt32 (op, r1, r2); /* cvt to floating */ - break; - - case 0x60: /* STE - RX */ - t = ReadFReg (r1); /* get sp reg */ - WriteF (ea, t, VW); /* write */ - break; - - case 0x70: /* STD - RX */ - WriteF (ea, D[r1 >> 1].h, VW); /* write hi */ - WriteF ((ea + 4) & VAMASK, D[r1 >> 1].l, VW); /* write lo */ - break; - - case 0x71: /* STME - RX */ - for ( ; r1 <= 0xE; r1 = r1 + 2) { /* loop thru reg */ - t = ReadFReg (r1); /* get sp reg */ - WriteF (ea, t, VW); /* write */ - ea = (ea + 4) & VAMASK; /* incr mem addr */ - } - break; - - case 0x72: /* LME - RX */ - for ( ; r1 <= 0xE; r1 = r1 + 2) { /* loop thru reg */ - t = ReadF (ea, VR); /* get value */ - WriteFReg (r1, t); /* write reg */ - ea = (ea + 4) & VAMASK; /* incr mem addr */ - } - break; - - case 0x7E: /* STMD - RX */ - for ( ; r1 <= 0xE; r1 = r1 + 2) { /* loop thru reg */ - WriteF (ea, D[r1 >> 1].h, VW); /* write register */ - WriteF ((ea + 4) & VAMASK, D[r1 >> 1].l, VW); - ea = (ea + 8) & VAMASK; /* incr mem addr */ - } - break; - - case 0x7F: /* LMD - RX */ - for ( ; r1 <= 0xE; r1 = r1 + 2) { /* loop thru reg */ - D[r1 >> 1].h = ReadF (ea, VR); /* load register */ - D[r1 >> 1].l = ReadF ((ea + 4) & VAMASK, VR); - ea = (ea + 8) & VAMASK; /* incr mem addr */ - } - break; - -/* Miscellaneous */ - - case 0xE1: /* SVC - RX */ - PCQ_ENTRY; /* effective branch */ - t = BUILD_PSW (cc); /* save PSW */ - cc = newPSW (ReadF (SVNPS32, P)); /* get new PSW */ - R[13] = ea & 0xFFFFFF; /* parameter */ - R[14] = t; /* old PSW */ - R[15] = PC; /* old PC */ - PC = ReadH (SVNPC + r1 + r1, P); /* new PC */ - if (DEBUG_PRI (cpu_dev, LOG_CPU_C)) fprintf (sim_deb, - ">>SVC: oPC = %X, oPSW = %X, nPC = %X, nPSW = %X\n", - pcq[pcq_p], t, PC, PSW); - break; - - case 0xE2: /* SINT - RI1 */ - dev = opnd & DEV_MAX; /* get dev */ - cc = int_auto (dev, cc); /* auto int */ - int_eval (); - break; - - case 0xE3: /* SCP - RXH */ - opnd = opnd & DMASK16; /* zero ext operand */ - if (opnd & CCW32_B1) /* point to buf */ - t = ea + CCB32_B1C; - else t = ea + CCB32_B0C; - sr = ReadH (t & VAMASK, VR); /* get count */ - sr = SEXT16 (sr); /* sign extend */ - if (sr <= 0) { /* <= 0? */ - bufa = ReadF ((t + 2) & VAMASK, VR); /* get buf end */ - if (opnd & CCW32_WR) /* write? */ - R[r1] = ReadB ((bufa + sr) & VAMASK, VR); /* R1 gets mem */ - else WriteB ((bufa + sr) & VAMASK, R[r1], VW); /* read, R1 to mem */ - sr = sr + 1; /* inc count */ - CC_GL_32 (sr & DMASK32); /* set cc's */ - WriteH (t & VAMASK, sr, VW); /* rewrite */ - if ((sr > 0) && !(opnd & CCW32_FST)) /* buf switch? */ - WriteH (ea, opnd ^ CCW32_B1, VW); /* flip CCW bit */ - } /* end if */ - else cc = CC_V; - break; - - case 0x18: /* LPSWR - RR */ - PCQ_ENTRY; /* effective branch */ - PC = R[(r2 + 1) & 0xF] & VAMASK; /* new PC (old reg set) */ - if (DEBUG_PRI (cpu_dev, LOG_CPU_C)) - fprintf (sim_deb, ">>LPSWR: oPC = %X, oPSW = %X, nPC = %X, nPSW = %X\n", - pcq[pcq_p], BUILD_PSW (cc), PC, opnd); - cc = newPSW (opnd); /* new PSW */ - if (PSW & PSW_SQI) /* test for q */ - cc = testsysq (cc); - break; - - case 0xC2: /* LPSW - RXF */ - PCQ_ENTRY; /* effective branch */ - PC = ReadF ((ea + 4) & VAMASK, VR) & VAMASK; /* new PC */ - if (DEBUG_PRI (cpu_dev, LOG_CPU_C)) - fprintf (sim_deb, ">>LPSW: oPC = %X, oPSW = %X, nPC = %X, nPSW = %X\n", - pcq[pcq_p], BUILD_PSW (cc), PC, opnd); - cc = newPSW (opnd); /* new PSW */ - if (PSW & PSW_SQI) /* test for q */ - cc = testsysq (cc); - break; - - case 0x95: /* EPSR - NO */ - R[r1] = BUILD_PSW (cc); /* save PSW */ - cc = newPSW (R[r2]); /* load new PSW */ - if (PSW & PSW_SQI) /* test for q */ - cc = testsysq (cc); - break; - - case 0x64: /* ATL - RX */ - case 0x65: /* ABL - RX */ - cc = addtoq (ea, R[r1], op & 1); /* add to q */ - break; - - case 0x66: /* RTL - RX */ - case 0x67: /* RBL - RX */ - cc = remfmq (ea, r1, op & 1); /* rem from q */ - break; - - case 0x5E: /* CRC12 - RXH */ - opnd = opnd & DMASK16; /* zero ext opnd */ - t = (R[r1] & 0x3F) ^ opnd; - for (i = 0; i < 6; i++) { - if (t & 1) - t = (t >> 1) ^ 0x0F01; - else t = t >> 1; - } - WriteH (ea, t, VW); - break; - - case 0x5F: /* CRC16 - RXH */ - opnd = opnd & DMASK16; /* zero ext opnd */ - t = (R[r1] & 0xFF) ^ opnd; - for (i = 0; i < 8; i++) { - if (t & 1) - t = (t >> 1) ^ 0xA001; - else t = t >> 1; - } - WriteH (ea, t, VW); - break; - - case 0xE7: /* TLATE - RXF */ - t = (opnd + ((R[r1] & DMASK8) << 1)) & VAMASK; /* table entry */ - rslt = ReadH (t, VR); /* get entry */ - if (rslt & SIGN16) /* direct xlate? */ - R[r1] = rslt & DMASK8; - else { - PCQ_ENTRY; /* branch */ - PC = rslt << 1; - } - break; - -/* I/O instructions */ - - case 0xDE: /* OC - RX */ - opnd = ReadB (ea, VR); /* fetch operand */ - case 0x9E: /* OCR - RR */ - dev = R[r1] & DEV_MAX; - if (DEV_ACC (dev)) { - dev_tab[dev] (dev, IO_ADR, 0); /* select */ - dev_tab[dev] (dev, IO_OC, opnd & DMASK8); /* send command */ - cc = 0; - } - else cc = CC_V; - int_eval (); /* re-eval intr */ - break; - - case 0xDA: /* WD - RX */ - opnd = ReadB (ea, VR); /* fetch operand */ - case 0x9A: /* WDR - RR */ - dev = R[r1] & DEV_MAX; - if (DEV_ACC (dev)) { - dev_tab[dev] (dev, IO_ADR, 0); /* select */ - dev_tab[dev] (dev, IO_WD, opnd & DMASK8); /* send data */ - cc = 0; - } - else cc = CC_V; - int_eval (); /* re-eval intr */ - break; - - case 0xD8: /* WH - RX */ - opnd = ReadH (ea, VR); /* fetch operand */ - case 0x98: /* WHR - RR */ - dev = R[r1] & DEV_MAX; - if (DEV_ACC (dev)) { - if (dev_tab[dev] (dev, IO_ADR, 0)) /* select; hw ok? */ - dev_tab[dev] (dev, IO_WH, opnd & DMASK16); /* send data */ - else { /* byte only */ - dev_tab[dev] (dev, IO_WD, (opnd >> 8) & DMASK8); /* hi */ - dev_tab[dev] (dev, IO_WD, opnd & DMASK8); /* send lo byte */ - } - cc = 0; - } - else cc = CC_V; - int_eval (); /* re-eval intr */ - break; - - case 0x9B: /* RDR - RR */ - case 0xDB: /* RD - RX */ - dev = R[r1] & DEV_MAX; - if (DEV_ACC (dev)) { /* dev exist? */ - dev_tab[dev] (dev, IO_ADR, 0); /* select */ - t = dev_tab[dev] (dev, IO_RD, 0); /* get data */ - cc = 0; - } - else { /* no */ - t = 0; - cc = CC_V; - } - if (OP_TYPE (op) != OP_RR) /* RX or RR? */ - WriteB (ea, t, VW); - else R[r2] = t & DMASK8; - int_eval (); /* re-eval intr */ - break; - - case 0x99: /* RHR - RR */ - case 0xD9: /* RH - RX */ - dev = R[r1] & DEV_MAX; - if (DEV_ACC (dev)) { /* dev exist? */ - if (dev_tab[dev] (dev, IO_ADR, 0)) /* select, hw ok? */ - t = dev_tab[dev] (dev, IO_RH, 0); /* get data */ - else { /* byte only */ - rslt = dev_tab[dev] (dev, IO_RD, 0); /* get byte */ - t = dev_tab[dev] (dev, IO_RD, 0); /* get byte */ - t = (rslt << 8) | t; /* merge */ - } - cc = 0; - } - else { /* no */ - t = 0; - cc = CC_V; - } - if (OP_TYPE (op) != OP_RR) /* RX or RR? */ - WriteH (ea, t, VW); - else R[r2] = t & DMASK16; - int_eval (); /* re-eval intr */ - break; - - case 0x9D: /* SSR - RR */ - case 0xDD: /* SS - RX */ - dev = R[r1] & DEV_MAX; - if (DEV_ACC (dev)) { /* dev exist? */ - dev_tab[dev] (dev, IO_ADR, 0); /* select */ - t = dev_tab[dev] (dev, IO_SS, 0); /* get status */ - } - else t = STA_EX; /* no */ - if (OP_TYPE (op) != OP_RR) /* RX or RR? */ - WriteB (ea, t, VW); - else R[r2] = t & DMASK8; - cc = t & 0xF; - int_eval (); /* re-eval intr */ - break; - -/* Block I/O instructions - - On a real Interdata system, the block I/O instructions can't be - interrupted or stopped. To model this behavior, while allowing - the instructions to go back through fetch for I/O processing and - WRU testing, the simulator implements a 'block I/O in progress' - flag and status block. If a block I/O is in progress, normal - interrupts and fetches are suppressed until the block I/O is done. -*/ - - case 0x96: /* WBR - RR */ - case 0xD6: /* WB - RXF */ - dev = R[r1] & DEV_MAX; - if (DEV_ACC (dev)) { /* dev exist? */ - if (OP_TYPE (op) != OP_RR) - lim = ReadF ((ea + 4) & VAMASK, VR); - else lim = R[(r2 + 1) & 0xF]; - if (opnd > lim) /* start > end? */ - cc = 0; - else { /* no, start I/O */ - dev_tab[dev] (dev, IO_ADR, 0); /* select dev */ - blk_io.dfl = dev; /* set status block */ - blk_io.cur = opnd; - blk_io.end = lim; - qevent = qevent | EV_BLK; /* I/O in prog */ - } - } - else cc = CC_V; /* nx dev */ - break; - - case 0x97: /* RBR - RR */ - case 0xD7: /* RB - RXF */ - dev = R[r1] & DEV_MAX; - if (DEV_ACC (dev)) { /* dev exist? */ - if (OP_TYPE (op) != OP_RR) - lim = ReadF ((ea + 4) & VAMASK, VR); - else lim = R[(r2 + 1) & 0xF]; - if (opnd > lim) /* start > end? */ - cc = 0; - else { /* no, start I/O */ - dev_tab[dev] (dev, IO_ADR, 0); /* select dev */ - blk_io.dfl = dev | BL_RD; /* set status block */ - blk_io.cur = opnd; - blk_io.end = lim; - qevent = qevent | EV_BLK; /* I/O in prog */ - } - } - else cc = CC_V; /* nx dev */ - break; - - case 0xD5: /* AL - RX */ - dev = ReadB (AL_DEV, P); /* get device */ - t = ReadB (AL_IOC, P); /* get command */ - if (DEV_ACC (dev)) { /* dev exist? */ - if (AL_BUF > ea) /* start > end? */ - cc = 0; - else { /* no, start I/O */ - dev_tab[dev] (dev, IO_ADR, 0); /* select dev */ - dev_tab[dev] (dev, IO_OC, t); /* start dev */ - blk_io.dfl = dev | BL_RD | BL_LZ; /* set status block */ - blk_io.cur = AL_BUF; - blk_io.end = ea; - qevent = qevent | EV_BLK; /* I/O in prog */ - } - } - else cc = CC_V; /* nx dev */ - break; - } /* end switch */ - } /* end while */ - -/* Simulation halted */ - -PSW = BUILD_PSW (cc); -PC = PC & VAMASK; -set_r_display (R); -pcq_r->qptr = pcq_p; /* update pc q ptr */ -return reason; -} - -/* Load new PSW */ - -uint32 newPSW (uint32 val) -{ -uint32 rs = PSW_GETREG (val); /* register set */ - -R = &GREG[rs * 16]; /* set register set */ -PSW = val & PSW_MASK; /* store PSW */ -int_eval (); /* update intreq */ -if (PSW & PSW_WAIT) /* wait state? */ - qevent = qevent | EV_WAIT; -else qevent = qevent & ~EV_WAIT; -if (PSW & PSW_EXI) /* enable/disable */ - SET_ENB (v_DS); -else CLR_ENB (v_DS); /* console intr */ -return PSW & CC_MASK; -} - -/* Exception handler - 7/32 always uses register set 0 */ - -uint32 exception (uint32 loc, uint32 cc, uint32 flg) -{ -int32 oldPSW = BUILD_PSW (cc); /* save old PSW */ -int32 oldPC = PC; /* save old PC */ - -cc = newPSW (ReadF (loc, P)); /* new PSW */ -PC = ReadF (loc + 4, P) & VAMASK; /* new PC */ -if (cpu_unit.flags & UNIT_832) { /* 8/32? */ - R[14] = oldPSW; /* PSW to new 14 */ - R[15] = oldPC; /* PC to new 15 */ - } -else { - GREG[14] = oldPSW; /* 7/32, PSW to set 0 14 */ - GREG[15] = oldPC; /* PC to set 0 15 */ - } -if (DEBUG_PRI (cpu_dev, LOG_CPU_I)) - fprintf (sim_deb, ">>Exc %X: oPC = %X, oPSW = %X, nPC = %X, nPSW = %X\n", - loc, oldPC, oldPSW, PC, PSW | cc | flg); -return cc | flg; /* return CC */ -} - -/* Test for queue interrupts - system queue addresses are physical */ - -uint32 testsysq (uint32 cc) -{ -int32 qb = ReadF (SQP, P); /* get sys q addr */ -int32 usd = ReadH (qb + Q32_USD, P); /* get use count */ - -if (usd) { /* entries? */ - cc = exception (SQTPSW, cc, 0); /* take sysq exc */ - if (cpu_unit.flags & UNIT_832) /* R13 = sys q addr */ - R[13] = qb; - else GREG[13] = qb; - } -return cc; -} - -/* Add to queue */ - -uint32 addtoq (uint32 ea, uint32 val, uint32 flg) -{ -uint32 slt, usd, wra, t; - -t = ReadF (ea, VR); /* slots/used */ -slt = (t >> 16) & DMASK16; /* # slots */ -usd = t & DMASK16; /* # used */ -if (usd >= slt) /* list full? */ - return CC_V; -usd = (usd + 1) & DMASK16; /* inc # used */ -WriteH (ea + Q32_USD, usd, VW); /* rewrite */ -if (flg) { /* ABL? */ - wra = ReadH ((ea + Q32_BOT) & VAMASK, VR); /* get bottom */ - t = wra + 1; /* adv bottom */ - if (t >= slt) /* wrap if necc */ - t = 0; - WriteH ((ea + Q32_BOT) & VAMASK, t, VW); /* rewrite bottom */ - } -else { - wra = ReadH ((ea + Q32_TOP) & VAMASK, VR); /* ATL, get top */ - if (wra == 0) - wra = (slt - 1) & DMASK16; /* wrap if necc */ - else wra = wra - 1; /* dec top */ - WriteH ((ea + Q32_TOP) & VAMASK, wra, VW); /* rewrite top */ - } -WriteF ((ea + Q32_BASE + (wra * Q32_SLNT)) & VAMASK, val, VW); /* write slot */ -return 0; -} - -/* Remove from queue */ - -uint32 remfmq (uint32 ea, uint32 r1, uint32 flg) -{ -uint32 slt, usd, rda, t; - -t = ReadF (ea, VR); /* get slots/used */ -slt = (t >> 16) & DMASK16; /* # slots */ -usd = t & DMASK16; /* # used */ -if (usd == 0) /* empty? */ - return CC_V; -usd = usd - 1; /* dec used */ -WriteH (ea + Q32_USD, usd, VW); /* rewrite */ -if (flg) { /* RBL? */ - rda = ReadH ((ea + Q32_BOT) & VAMASK, VR); /* get bottom */ - if (rda == 0) /* wrap if necc */ - rda = (slt - 1) & DMASK16; - else rda = rda - 1; /* dec bottom */ - WriteH ((ea + Q32_BOT) & VAMASK, rda, VW); /* rewrite bottom */ - } -else { - rda = ReadH ((ea + Q32_TOP) & VAMASK, VR); /* RTL, get top */ - t = rda + 1; /* adv top */ - if (t >= slt) /* wrap if necc */ - t = 0; - WriteH ((ea + Q32_TOP) & VAMASK, t, VW); /* rewrite top */ - } -R[r1] = ReadF ((ea + Q32_BASE + (rda * Q32_SLNT)) & VAMASK, VR); /* read slot */ -if (usd) - return CC_G; -else return 0; -} - -/* Automatic interrupt processing */ - -uint32 int_auto (uint32 dev, uint32 cc) -{ -uint32 addr, vec, by, ccw, ccwa, ccwb; -uint32 i, hw, tblad, tblen, bufe, st, t; -int32 bufc; -uint32 oldPSW = BUILD_PSW (cc); - -vec = ReadH (INTSVT + dev + dev, P); /* get vector */ -newPSW (0x2800); /* new PSW */ -R[0] = oldPSW; /* save old PSW */ -R[1] = PC; /* save PC */ -R[2] = dev; /* set dev # */ -if (DEBUG_PRI (cpu_dev, LOG_CPU_I)) - fprintf (sim_deb, ">>Int %X: oPC = %X, oPSW = %X, nPC = %X, nPSW = %X\n", - dev, PC, oldPSW, vec, 0x2800); -if (DEV_ACC (dev)) { /* dev exist? */ - hw = dev_tab[dev] (dev, IO_ADR, 0); /* select, get hw */ - R[3] = st = dev_tab[dev] (dev, IO_SS, 0); /* sense status */ - } -else { - hw = 0; - R[3] = CC_V; - } -if ((vec & 1) == 0) { /* immed int? */ - PC = vec; /* new PC */ - return PSW & CC_MASK; /* exit */ - } -R[4] = ccwa = vec & ~1; /* save CCW addr */ -ccw = ReadH (ccwa, VR); /* read CCW */ -if ((ccw & CCW32_EXE) == 0) { /* exec clr? */ - PC = ReadH (ccwa + CCB32_SUB, VR); /* get subr */ - return 0; /* CC = 0 */ - } -if (!DEV_ACC (dev) || (st & CCW32_STA (ccw))) { /* bad status? */ - PC = ReadH (ccwa + CCB32_SUB, VR); /* get subr */ - return CC_L; /* CC = L */ - } -if (ccw & CCW32_FST) { /* fast mode? */ - t = ReadH (ccwa + CCB32_B0C, VR); /* get count */ - bufc = SEXT16 (t); /* sign ext */ - if (bufc <= 0) { /* still valid? */ - bufe = ReadF (ccwa + CCB32_B0E, VR); /* get end addr */ - addr = (bufe + bufc) & VAMASK; - if (hw) { /* halfword? */ - if (ccw & CCW32_WR) { /* write? */ - t = ReadH (addr, VR); /* get hw */ - dev_tab[dev] (dev, IO_WH, t); /* send to dev */ - } - else { /* read */ - t = dev_tab[dev] (dev, IO_RH, 0); /* get hw */ - WriteH (addr, t, VW); /* write to mem */ - } - bufc = bufc + 2; /* adv buf cnt */ - } - else { /* byte */ - if (ccw & CCW32_WR) { /* write? */ - t = ReadB (addr, VR); /* get byte */ - dev_tab[dev] (dev, IO_WD, t); /* send to dev */ - } - else { /* read */ - t = dev_tab[dev] (dev, IO_RD, 0); /* get byte */ - WriteB (addr, t, VW); /* write to mem */ - } - bufc = bufc + 1; /* adv buf cnt */ - } - WriteH (ccwa + CCB32_B0C, bufc, VW); /* rewrite cnt */ - if (bufc > 0) { - PC = ReadH (ccwa + CCB32_SUB, VR); /* get subr */ - return CC_G; /* CC = G */ - } - } /* end if bufc <= 0 */ - } /* end fast */ -else { /* slow mode */ - if (ccw & CCW32_B1) /* which buf? */ - ccwb = ccwa + CCB32_B1C; - else ccwb = ccwa + CCB32_B0C; - t = ReadH (ccwb, VR); /* get count */ - bufc = SEXT16 (t); /* sign ext */ - if (bufc <= 0) { /* still valid? */ - bufe = ReadF (ccwb + 2, VR); /* get end addr */ - addr = (bufe + bufc) & VAMASK; - if (ccw & CCW32_WR) { /* write? */ - by = ReadB (addr, VR); /* byte fm mem */ - if (ccw & CCW32_TL) { /* translate? */ - tblad = ReadF (ccwa + CCB32_TAB, VR); /* get tbl addr */ - tblen = (tblad + (by << 1)) & VAMASK; /* tbl entry addr */ - t = ReadH (tblen, VR); /* get tbl entry */ - if ((t & SIGN16) == 0) { /* special xlate? */ - PC = t << 1; /* change PC */ - R[3] = by; /* untrans char */ - return 0; /* CC = 0 */ - } - by = t & DMASK8; /* replace */ - } - dev_tab[dev] (dev, IO_WD, by); /* write to dev */ - } - else { /* read */ - by = dev_tab[dev] (dev, IO_RD, 0); /* get from dev */ - if (ccw & CCW32_TL) { /* translate? */ - tblad = ReadF (ccwa + CCB32_TAB, VR); /* get tbl addr */ - tblen = (tblad + (by << 1)) & VAMASK; /* tbl entry addr */ - t = ReadH (tblen, VR); /* get tbl entry */ - if ((t & SIGN16) == 0) { /* special xlate? */ - PC = t << 1; /* change PC */ - R[3] = by; /* untrans char */ - return 0; /* CC = 0 */ - } - WriteB (addr, t, VW); /* wr trans */ - } - else WriteB (addr, by, VW); /* wr orig */ - } - t = ReadH (ccwa + CCB32_CHK, VR); /* get check wd */ - t = t ^ by; /* start LRC */ - if (ccw & CCW32_CRC) { /* CRC? */ - for (i = 0; i < 8; i++) { - if (t & 1) - t = (t >> 1) ^ 0xA001; - else t = t >> 1; - } - } - WriteH (ccwa + CCB32_CHK, t, VW); /* rewrite chk wd */ - bufc = bufc + 1; /* adv buf cnt */ - WriteH (ccwb, bufc, VW); /* rewrite cnt */ - if (bufc > 0) { /* cnt pos? */ - ccw = ccw ^ CCW32_B1; /* flip buf */ - WriteH (ccwa, ccw, VW); /* rewrite */ - PC = ReadH (ccwa + CCB32_SUB, VR); /* get subr */ - return CC_G; /* CC = G */ - } - } /* end if bufc */ - } /* end slow */ -PC = R[1]; /* restore PC */ -return newPSW (R[0]); /* restore PSW, CC */ -} - -/* Display register device */ - -uint32 display (uint32 dev, uint32 op, uint32 dat) -{ -int t; - -switch (op) { - - case IO_ADR: /* select */ - if (!drmod) /* norm mode? clr */ - drpos = srpos = 0; - return BY; /* byte only */ - - case IO_OC: /* command */ - dat = dat & 0xC0; - if (dat == 0x40) { /* x40 = inc */ - drmod = 1; - drpos = srpos = 0; /* init cntrs */ - } - else if (dat == 0x80) /* x80 = norm */ - drmod = 0; - break; - - case IO_WD: /* write */ - if (drpos < 4) - DR = (DR & ~(DMASK8 << (drpos * 8))) | (dat << (drpos * 8)); - else if (drpos == 4) - DRX = dat; - drpos = (drpos + 1) & 0x7; - break; - - case IO_RD: /* read */ - t = (SR >> (srpos * 8)) & DMASK8; - srpos = srpos ^ 1; - return t; - - case IO_SS: /* status */ - return 0x80; - } - -return 0; -} - -/* Relocation and protection */ - -uint32 Reloc (uint32 va, uint32 rel) -{ -uint32 seg, off, mapr, lim; - -seg = VA_GETSEG (va); /* get seg num */ -off = VA_GETOFF (va); /* get offset */ -mapr = mac_reg[seg]; /* get seg reg */ -lim = GET_SRL (mapr); /* get limit */ -if (off >= lim) { /* limit viol? */ - mac_sta = MACS_L; /* set status */ - ABORT (MPRO); /* abort */ - } -if ((mapr & SR_PRS) == 0) { /* not present? */ - mac_sta = MACS_NP; /* set status */ - ABORT (MPRO); /* abort */ - } -if ((rel == VE) && (mapr & SR_EXP)) { /* exec, prot? */ - mac_sta = MACS_EX; /* set status */ - qevent = qevent | EV_MAC; /* req intr */ - } -if ((rel == VW) && (mapr & (SR_WPI | SR_WRP))) { /* write, prot? */ - if (mapr & SR_WRP) { /* write abort? */ - mac_sta = MACS_WP; /* set status */ - ABORT (MPRO); /* abort */ - } - else { /* write intr */ - mac_sta = MACS_WI; /* set status */ - qevent = qevent | EV_MAC; /* req intr */ - } - } -return (off + (mapr & SRF_MASK)) & PAMASK32; /* relocate */ -} - -uint32 RelocT (uint32 va, uint32 base, uint32 rel, uint32 *pa) -{ -uint32 seg, off, mapr, lim; - -seg = VA_GETSEG (va); /* get seg num */ -off = VA_GETOFF (va); /* get offset */ -mapr = ReadF ((base + (seg << 2)) & VAMASK, rel); /* get seg reg */ -lim = GET_SRL (mapr); /* get limit */ -if (off >= lim) /* limit viol? */ - return CC_C; -if ((mapr & SR_PRS) == 0) /* not present? */ - return CC_V; -*pa = off + (mapr & SRF_MASK); /* translate */ -if (mapr & (SR_WRP | SR_WPI)) /* write prot? */ - return CC_G; -if (mapr & SR_EXP) /* exec prot? */ - return CC_L; -return 0; /* ok */ -} - -/* Memory interface routines - - ReadB read byte (processor) - ReadH read halfword (processor) - ReadF read fullword (processor) - WriteB write byte (processor) - WriteH write halfword (processor) - WriteF write fullword (processor) - IOReadB read byte (IO) - IOWriteB write byte (IO) - IOReadH read halfword (IO) - IOWriteH write halfword (IO) -*/ - -uint32 ReadB (uint32 loc, uint32 rel) -{ -uint32 val; -uint32 sc = (3 - (loc & 3)) << 3; - -if ((PSW & PSW_REL) == 0) { /* reloc off? */ - if ((loc & ~03) == MAC_STA) { /* MAC status? */ - val = mac_sta; /* read it */ - qevent = qevent & ~EV_MAC; /* clr MAC intr */ - } - else val = M[loc >> 2]; /* get mem word */ - } -else if (rel == 0) /* phys ref? */ - val = M[loc >> 2]; -else { - uint32 pa = Reloc (loc, rel); /* relocate */ - val = M[pa >> 2]; - } -return (val >> sc) & DMASK8; -} - -uint32 ReadH (uint32 loc, uint32 rel) -{ -uint32 val; - -if ((PSW & PSW_REL) == 0) { /* reloc off? */ - if ((loc & ~03) == MAC_STA) { /* MAC status? */ - val = mac_sta; /* read it */ - qevent = qevent & ~EV_MAC; /* clr MAC intr */ - } - else val = M[loc >> 2]; /* get mem word */ - } -else if (rel == 0) /* phys ref? */ - val = M[loc >> 2]; -else { - uint32 pa = Reloc (loc, rel); /* relocate */ - val = M[pa >> 2]; - } -return (val >> ((loc & 2)? 0: 16)) & DMASK16; -} - -uint32 ReadF (uint32 loc, uint32 rel) -{ -uint32 val; - -if ((PSW & PSW_REL) == 0) { /* reloc off? */ - if ((loc & ~03) == MAC_STA) { /* MAC status? */ - val = mac_sta; /* read it */ - qevent = qevent & ~EV_MAC; /* clr MAC intr */ - } - else val = M[loc >> 2]; /* get mem word */ - } -else if (rel == 0) /* phys ref? */ - val = M[loc >> 2]; -else { - uint32 pa = Reloc (loc, rel); /* relocate */ - val = M[pa >> 2]; - } -return val; -} - -void WriteB (uint32 loc, uint32 val, uint32 rel) -{ -uint32 pa = loc; -uint32 sc = (3 - (loc & 3)) << 3; - -val = val & DMASK8; -if ((PSW & PSW_REL) == 0) { /* reloc off? */ - uint32 idx = (pa - MAC_BASE) >> 2; /* check for MAC */ - if (idx <= MAC_LNT) { - if (idx < MAC_LNT) mac_reg[idx] = - ((mac_reg[idx] & ~(DMASK8 << sc)) | (val << sc)) & SR_MASK; - else { - mac_sta = 0; - qevent = qevent & ~EV_MAC; - } - } - } -else if (rel != 0) /* !phys? relocate */ - pa = Reloc (loc, rel); -if (MEM_ADDR_OK (pa)) - M[pa >> 2] = (M[pa >> 2] & ~(DMASK8 << sc)) | (val << sc); -return; -} - -void WriteH (uint32 loc, uint32 val, uint32 rel) -{ -uint32 pa = loc; - -val = val & DMASK16; -if ((PSW & PSW_REL) == 0) { /* reloc off? */ - uint32 idx = (pa - MAC_BASE) >> 2; /* check for MAC */ - if (idx <= MAC_LNT) { - if (idx < MAC_LNT) mac_reg[idx] = ((loc & 2)? - ((mac_reg[idx] & ~DMASK16) | val): - ((mac_reg[idx] & DMASK16) | (val << 16))) & SR_MASK; - else { - mac_sta = 0; - qevent = qevent & ~EV_MAC; - } - } - } -else if (rel != 0) /* !phys? relocate */ - pa = Reloc (loc, rel); -if (MEM_ADDR_OK (pa)) - M[pa >> 2] = (loc & 2)? ((M[pa >> 2] & ~DMASK16) | val): - ((M[pa >> 2] & DMASK16) | (val << 16)); -return; -} - -void WriteF (uint32 loc, uint32 val, uint32 rel) -{ -uint32 pa = loc; - -val = val & DMASK32; -if (loc & 2) { - WriteH (loc & VAMASK, (val >> 16) & DMASK16, rel); - WriteH ((loc + 2) & VAMASK, val & DMASK16, rel); - return; - } -if ((PSW & PSW_REL) == 0) { /* reloc off? */ - uint32 idx = (pa - MAC_BASE) >> 2; /* check for MAC */ - if (idx <= MAC_LNT) { - if (idx < MAC_LNT) mac_reg[idx] = val & SR_MASK; - else { - mac_sta = 0; - qevent = qevent & ~EV_MAC; - } - } - } -else if (rel != 0) /* !phys? relocate */ - pa = Reloc (loc, rel); -if (MEM_ADDR_OK (pa)) - M[pa >> 2] = val & DMASK32; -return; -} - -uint32 IOReadB (uint32 loc) -{ -uint32 sc = (3 - (loc & 3)) << 3; - -return (M[loc >> 2] >> sc) & DMASK8; -} - -uint32 IOReadH (uint32 loc) -{ -return (M[loc >> 2] >> ((loc & 2)? 0: 16)) & DMASK16; -} - -void IOWriteB (uint32 loc, uint32 val) -{ -uint32 sc = (3 - (loc & 3)) << 3; - -val = val & DMASK8; -M[loc >> 2] = (M[loc >> 2] & ~(DMASK8 << sc)) | (val << sc); -return; -} - -void IOWriteH (uint32 loc, uint32 val) -{ -uint32 sc = (loc & 2)? 0: 16; - -val = val & DMASK16; -M[loc >> 2] = (M[loc >> 2] & ~(DMASK16 << sc)) | (val << sc); -return; -} - -/* Reset routine */ - -t_stat cpu_reset (DEVICE *dptr) -{ -qevent = 0; /* no events */ -mac_sta = 0; /* clear MAC */ -newPSW (0); /* PSW = 0 */ -set_r_display (R); -DR = 0; /* clear display */ -drmod = 0; -blk_io.dfl = blk_io.cur = blk_io.end = 0; /* no block I/O */ -sim_brk_types = sim_brk_dflt = SWMASK ('E'); /* init bkpts */ -if (M == NULL) - M = (uint32 *) calloc (MAXMEMSIZE32 >> 2, sizeof (uint32)); -if (M == NULL) - return SCPE_MEM; -pcq_r = find_reg ("PCQ", NULL, dptr); /* init PCQ */ -if (pcq_r) - pcq_r->qptr = 0; -else return SCPE_IERR; -return SCPE_OK; -} - -/* Memory examine */ - -t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) -{ -if ((sw & SWMASK ('V')) && (PSW & PSW_REL)) { - int32 cc = RelocT (addr, MAC_BASE, P, &addr); - if (cc & (CC_C | CC_V)) - return SCPE_NXM; - } -if (addr >= MEMSIZE) - return SCPE_NXM; -if (vptr != NULL) - *vptr = IOReadH (addr); -return SCPE_OK; -} - -/* Memory deposit */ - -t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) -{ -if ((sw & SWMASK ('V')) && (PSW & PSW_REL)) { - int32 cc = RelocT (addr, MAC_BASE, P, &addr); - if (cc & (CC_C | CC_V)) - return SCPE_NXM; - } -if (addr >= MEMSIZE) - return SCPE_NXM; -IOWriteH (addr, val); -return SCPE_OK; -} - -/* Change memory size */ - -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -uint32 mc = 0; -uint32 i; - -if ((val <= 0) || (((unsigned)val) > MAXMEMSIZE32) || ((val & 0xFFFF) != 0)) - return SCPE_ARG; -for (i = val; i < MEMSIZE; i = i + 4) - mc = mc | M[i >> 2]; -if ((mc != 0) && (!get_yn ("Really truncate memory [N]?", FALSE))) - return SCPE_OK; -MEMSIZE = val; -for (i = MEMSIZE; i < MAXMEMSIZE32; i = i + 4) - M[i >> 2] = 0; -return SCPE_OK; -} - -/* Set current R pointers for SCP */ - -void set_r_display (uint32 *rbase) -{ -REG *rptr; -int32 i; - -rptr = find_reg ("R0", NULL, &cpu_dev); -if (rptr == NULL) - return; -for (i = 0; i < 16; i++, rptr++) - rptr->loc = (void *) (rbase + i); -return; -} - -/* Set console interrupt */ - -t_stat cpu_set_consint (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (PSW & PSW_EXI) - SET_INT (v_DS); -return SCPE_OK; -} - -/* Set history */ - -t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -uint32 i, lnt; -t_stat r; - -if (cptr == NULL) { - for (i = 0; i < hst_lnt; i++) - hst[i].pc = 0; - hst_p = 0; - return SCPE_OK; - } -lnt = (uint32) get_uint (cptr, 10, HIST_MAX, &r); -if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) - return SCPE_ARG; -hst_p = 0; -if (hst_lnt) { - free (hst); - hst_lnt = 0; - hst = NULL; - } -if (lnt) { - hst = (InstHistory *) calloc (lnt, sizeof (InstHistory)); - if (hst == NULL) - return SCPE_MEM; - hst_lnt = lnt; - } -return SCPE_OK; -} - -/* Show history */ - -t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -int32 op, k, di, lnt; -char *cptr = (char *) desc; -t_value sim_eval[3]; -t_stat r; -InstHistory *h; - -if (hst_lnt == 0) /* enabled? */ - return SCPE_NOFNC; -if (cptr) { - lnt = (int32) get_uint (cptr, 10, hst_lnt, &r); - if ((r != SCPE_OK) || (lnt == 0)) - return SCPE_ARG; - } -else lnt = hst_lnt; -di = hst_p - lnt; /* work forward */ -if (di < 0) - di = di + hst_lnt; -fprintf (st, "PC r1 operand ea IR\n\n"); -for (k = 0; k < lnt; k++) { /* print specified */ - h = &hst[(di++) % hst_lnt]; /* entry pointer */ - if (h->pc & HIST_PC) { /* instruction? */ - fprintf (st, "%06X %08X %08X ", h->pc & VAMASK32, h->r1, h->opnd); - op = (h->ir1 >> 8) & 0xFF; - if (OP_TYPE (op) >= OP_RX) - fprintf (st, "%06X ", h->ea); - else fprintf (st, " "); - sim_eval[0] = h->ir1; - sim_eval[1] = h->ir2; - sim_eval[2] = h->ir3; - if ((fprint_sym (st, h->pc & VAMASK32, sim_eval, &cpu_unit, SWMASK ('M'))) > 0) - fprintf (st, "(undefined) %04X", h->ir1); - fputc ('\n', st); /* end line */ - } /* end if instruction */ - } /* end for */ -return SCPE_OK; -} diff --git a/Interdata/id32_dboot.c b/Interdata/id32_dboot.c deleted file mode 100644 index 133f59e2..00000000 --- a/Interdata/id32_dboot.c +++ /dev/null @@ -1,322 +0,0 @@ -/* id32_dboot.c: Interdata 32b simulator disk bootstrap - - Copyright (c) 2000-2008, 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-Jul-06 RMS Fixed transcription errors (Davis Johnson) - 17-Feb-03 RMS Fixed for UNIX bootstrap, upper platter bootstrap -*/ - -#include "id_defs.h" - -#define DBOOT_BEG 0x1000 -#define DBOOT_START 0x100E -#define DBOOT_LEN (sizeof (dboot_rom) / sizeof (uint8)) - -/* Transcribed from 32b Bootstrap Loader, 03-074N81R03A13 */ - -static uint8 dboot_rom[] = { - 0xca, 0xf0, 0x00, 0x30, - 0xc5, 0xf0, 0x00, 0x3a, - 0x02, 0x8e, - 0x26, 0xf7, - 0x03, 0x0e, - 0xe6, 0xd0, 0x0f, 0x30, - 0xd1, 0xe0, 0x00, 0x78, - 0xd0, 0xed, 0x03, 0x40, - 0xd3, 0xf0, 0x00, 0x7e, - 0xc4, 0xf0, 0x00, 0x0f, - 0x41, 0xed, 0x00, 0xd0, - 0xd2, 0xfd, 0x03, 0x25, - 0xd3, 0xf0, 0x00, 0x7f, - 0x10, 0xf4, - 0x41, 0xed, 0x00, 0xd0, - 0xd2, 0xfd, 0x03, 0x26, - 0xd3, 0xf0, 0x00, 0x7f, - 0xc4, 0xf0, 0x00, 0x0f, - 0x41, 0xed, 0x00, 0xd0, - 0xd2, 0xfd, 0x03, 0x27, - 0xd3, 0x20, 0x00, 0x7d, - 0xd3, 0x30, 0x00, 0x7c, - 0xd3, 0x40, 0x00, 0x7a, - 0x24, 0x50, - 0xd3, 0xf0, 0x00, 0x7b, - 0xcb, 0xf0, 0x00, 0x33, - 0x23, 0x23, - 0x11, 0xf1, - 0x08, 0x5f, - 0xe6, 0x7d, 0x03, 0x50, - 0xe6, 0x8d, 0x04, 0x4f, - 0x07, 0xcc, - 0x41, 0xed, 0x01, 0xfc, - 0xd1, 0xed, 0x03, 0x5c, - 0xd0, 0xed, 0x03, 0x48, - 0x58, 0xcd, 0x03, 0x58, - 0x43, 0x3d, 0x01, 0x9c, - 0xe6, 0x7d, 0x03, 0x50, - 0x41, 0xed, 0x01, 0xfc, - 0xe6, 0xed, 0x03, 0x54, - 0x24, 0x15, - 0xf8, 0xf0, 0x4f, 0x53, 0x33, 0x32, - 0xd3, 0x7e, 0x00, 0x24, - 0xc3, 0x70, 0x00, 0x10, - 0x23, 0x3e, - 0xc3, 0x70, 0x00, 0xe0, - 0x21, 0x3b, - 0x55, 0xfe, 0x00, 0x00, - 0x21, 0x38, - 0x58, 0x6e, 0x00, 0x08, - 0x10, 0x68, - 0x55, 0x6d, 0x03, 0x24, - 0x43, 0x3d, 0x01, 0xb2, - 0xca, 0xe0, 0x00, 0x30, - 0x27, 0x11, - 0x42, 0x3d, 0x01, 0x66, - 0x58, 0xcd, 0x03, 0x50, - 0x42, 0x3d, 0x01, 0x52, - 0x48, 0x10, 0x00, 0x7e, - 0x42, 0x3d, 0x02, 0xf0, - 0x58, 0xcd, 0x03, 0x48, - 0x43, 0x3d, 0x02, 0xf0, - 0x58, 0x8d, 0x03, 0x4c, - 0x23, 0x07, - 0x58, 0xce, 0x00, 0x0c, - 0x58, 0x8e, 0x00, 0x10, - 0x0b, 0x8c, - 0x26, 0xc1, - 0x11, 0x88, - 0x08, 0x18, - 0xe6, 0xf0, 0x11, 0x18, - 0x58, 0x0f, 0x00, 0x00, - 0x50, 0x01, 0x00, 0x00, - 0x59, 0x01, 0x00, 0x00, - 0x42, 0x3d, 0x03, 0x08, - 0x26, 0xf4, - 0x26, 0x14, - 0xc5, 0xf0, 0x12, 0x78, - 0x20, 0x8c, - 0x08, 0xd8, - 0xcb, 0xd0, 0x01, 0xe8, - 0x03, 0x08, - 0x27, 0x81, - 0x07, 0x77, - 0x41, 0xed, 0x01, 0xfc, - 0xd1, 0xed, 0x03, 0x40, - 0xd0, 0xe0, 0x00, 0x78, - 0x43, 0x00, 0x00, 0x60, - 0xde, 0x2d, 0x03, 0x28, - 0x08, 0x0c, - 0x4d, 0x0d, 0x45, 0x00, 0x03, 0x30, - 0x08, 0x91, - 0x4d, 0x0d, 0x45, 0x00, 0x03, 0x38, - 0x08, 0xa1, - 0x08, 0xb0, - 0x08, 0x55, - 0x42, 0x2d, 0x02, 0x4a, - 0xde, 0x3d, 0x03, 0x28, - 0x9d, 0x3f, - 0x22, 0x21, - 0x9d, 0x4f, - 0x42, 0x1d, 0x02, 0xf4, - 0xc3, 0xf0, 0x00, 0x10, - 0x20, 0x35, - 0x11, 0xa5, - 0x06, 0xba, - 0x98, 0x49, - 0xde, 0x4d, 0x03, 0x2b, - 0x9d, 0x3f, - 0x22, 0x21, - 0x9d, 0x4f, - 0x42, 0x7d, 0x02, 0xf8, - 0x20, 0x83, - 0x41, 0x6d, 0x02, 0x96, - 0x22, 0x0b, - 0x9d, 0x4f, - 0xc3, 0xf0, 0x00, 0x19, - 0x42, 0x3d, 0x02, 0xfc, - 0xde, 0x4d, 0x03, 0x2c, - 0x9d, 0x3f, - 0x22, 0x21, - 0x98, 0x49, - 0xde, 0x4d, 0x03, 0x2e, - 0x9d, 0x3f, - 0x22, 0x21, - 0xde, 0x4d, 0x03, 0x2d, - 0x9d, 0x3f, - 0x22, 0x21, - 0x98, 0x4a, - 0xde, 0x4d, 0x03, 0x2f, - 0x9d, 0x3f, - 0x22, 0x21, - 0xde, 0x4d, 0x03, 0x2b, - 0x9d, 0x3f, - 0x22, 0x21, - 0x9d, 0x4f, - 0x20, 0x81, - 0xc3, 0xf0, 0x00, 0x53, - 0x42, 0x3d, 0x03, 0x00, - 0x08, 0xfa, - 0x11, 0xfa, - 0x06, 0xf9, - 0xe6, 0x6d, 0x02, 0x54, - 0x34, 0x77, - 0x9a, 0x27, - 0x34, 0x77, - 0x98, 0x27, - 0x34, 0x88, - 0x9a, 0x28, - 0x34, 0x88, - 0x98, 0x28, - 0x08, 0x55, - 0x21, 0x24, - 0x98, 0x49, - 0x9a, 0x3b, - 0x23, 0x03, - 0x9a, 0x3b, - 0x98, 0x3f, - 0xde, 0x3d, 0x03, 0x2a, - 0xde, 0x2d, 0x03, 0x29, - 0x9d, 0x2f, - 0x20, 0x81, - 0xde, 0x2d, 0x03, 0x28, - 0x9b, 0x20, - 0x99, 0x21, - 0x34, 0x00, - 0x06, 0x01, - 0xde, 0x2d, 0x03, 0x28, - 0x9d, 0x3f, - 0x22, 0x21, - 0x42, 0x1d, 0x03, 0x04, - 0xc3, 0xf0, 0x00, 0x10, - 0x03, 0x3e, - 0x0b, 0x07, - 0x26, 0x04, - 0xc4, 0x00, 0xff, 0x00, - 0x0a, 0x70, - 0x26, 0x91, - 0x07, 0xaa, - 0x07, 0xbb, - 0x03, 0x06, - 0x24, 0x11, - 0x23, 0x0c, - 0x24, 0x12, - 0x23, 0x0a, - 0x24, 0x13, - 0x23, 0x08, - 0x24, 0x14, - 0x23, 0x06, - 0x24, 0x15, - 0x23, 0x04, - 0x24, 0x16, - 0x23, 0x02, - 0x24, 0x17, - 0x24, 0x01, - 0xde, 0x0d, 0x03, 0x28, - 0x9a, 0x01, - 0xde, 0x0d, 0x03, 0x28, - 0xd1, 0xed, 0x03, 0x40, - 0xd0, 0xe0, 0x00, 0x78, - 0x11, 0x0f, - 0x95, 0x10, - 0x22, 0x01, - 0x00, 0x00, 0x00, 0x00, - 0x48, 0x30, - 0xc1, 0xc2, - 0xc8, 0xc4, - 0xd0, 0xe0, - 0x00, 0x30, - 0x01, 0x90, - 0x01, 0x40, - 0x04, 0xc0, - 0x00, 0x18, - 0x00, 0x14, - 0x00, 0x40, - 0x00, 0x40, - 0x00 - }; - -/* Lower memory setup - - 78 = binary input device address - 79 = binary device input command - 7A = disk device number - 7B = device code - 7C = disk controller address - 7D = selector channel address - 7E:7F = operating system extension (user specified) -*/ - -struct dboot_id { - char *name; - uint32 sw; - uint32 cap; - uint32 dtype; - uint32 offset; - uint32 adder; - }; - -static struct dboot_id dboot_tab[] = { - { "DP", 0, 2, 0x31, o_DP0, 0 }, - { "DP", SWMASK ('F'), 9, 0x32, o_DP0, o_DPF }, - { "DP", 0, 9, 0x33, o_DP0, 0 }, - { "DM", 0, 64, 0x35, o_ID0, 0 }, - { "DM", 0, 244, 0x36, o_ID0, 0 }, - { NULL } - }; - -t_stat id_dboot (int32 u, DEVICE *dptr) -{ -extern DIB ttp_dib, sch_dib; -extern uint32 PC; -uint32 i, typ, ctlno, off, add, cap, sch_dev; -UNIT *uptr; - -DIB *ddib = (DIB *) dptr->ctxt; /* get disk DIB */ -ctlno = ddib->dno; /* get ctrl devno */ -sch_dev = sch_dib.dno + ddib->sch; /* sch dev # */ -uptr = dptr->units + u; /* get capacity */ -cap = uptr->capac >> 20; -for (i = typ = 0; dboot_tab[i].name != NULL; i++) { - if ((strcmp (dboot_tab[i].name, dptr->name) == 0) && - ((dboot_tab[i].sw == 0) || - (dboot_tab[i].sw & sim_switches)) && - (dboot_tab[i].cap == cap)) { - typ = dboot_tab[i].dtype; - off = dboot_tab[i].offset; - add = dboot_tab[i].adder; - break; - } - } -if (typ == 0) - return SCPE_NOFNC; - -IOWriteBlk (DBOOT_BEG, DBOOT_LEN, dboot_rom); /* copy boot */ -IOWriteB (AL_DEV, ttp_dib.dno); /* bin input dev */ -IOWriteB (AL_IOC, 0xa3); -IOWriteB (AL_DSKU, ctlno + ((u + 1) * off) + add); /* disk dev addr */ -IOWriteB (AL_DSKT, typ); /* disk type */ -IOWriteB (AL_DSKC, ctlno); /* disk ctl addr */ -IOWriteB (AL_SCH, sch_dev); -PC = DBOOT_START; -return SCPE_OK; -} diff --git a/Interdata/id32_sys.c b/Interdata/id32_sys.c deleted file mode 100644 index 288fd890..00000000 --- a/Interdata/id32_sys.c +++ /dev/null @@ -1,780 +0,0 @@ -/* id32_sys.c: Interdata 32b simulator interface - - Copyright (c) 2000-2008, Robert M. Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - 04-Feb-08 RMS Modified to allow -A, -B use with 8b devices - 25-Jan-07 RMS Fixed conflict between -h (hex) and -h (halfword) - 18-Oct-06 RMS Re-ordered device list - 02-Jul-04 RMS Fixed missing type in declaration - 15-Jul-03 RMS Fixed signed/unsigned bug in get_imm - 27-Feb-03 RMS Added relative addressing support - 23-Dec-01 RMS Cloned from ID4 sources -*/ - -#include "id_defs.h" -#include - -#define MSK_SBF 0x0100 -#define SEXT15(x) (((x) & 0x4000)? ((x) | ~0x3FFF): ((x) & 0x3FFF)) - -extern DEVICE cpu_dev; -extern DEVICE sch_dev; -extern DEVICE pt_dev; -extern DEVICE tt_dev, ttp_dev; -extern DEVICE pas_dev, pasl_dev; -extern DEVICE lpt_dev; -extern DEVICE pic_dev, lfc_dev; -extern DEVICE dp_dev, idc_dev; -extern DEVICE fd_dev, mt_dev; -extern UNIT cpu_unit; -extern REG cpu_reg[]; -extern uint32 *M; - -t_stat fprint_sym_m (FILE *of, t_addr addr, t_value *val); -t_stat parse_sym_m (char *cptr, t_addr addr, t_value *val); -extern t_stat lp_load (FILE *fileref, char *cptr, char *fnam); -extern t_stat pt_dump (FILE *of, char *cptr, char *fnam); - -/* 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 32b"; - -REG *sim_PC = &cpu_reg[0]; - -int32 sim_emax = 6; - -DEVICE *sim_devices[] = { - &cpu_dev, - &sch_dev, - &pic_dev, - &lfc_dev, - &pt_dev, - &tt_dev, - &ttp_dev, - &pas_dev, - &pasl_dev, - &lpt_dev, - &dp_dev, - &idc_dev, - &fd_dev, - &mt_dev, - NULL - }; - -const char *sim_stop_messages[] = { - "Unknown error", - "Reserved instruction", - "HALT instruction", - "Breakpoint", - "Wait state", - "Runaway VFU" - }; - -/* Binary loader -- load carriage control tape - Binary dump -- paper tape dump */ - -t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) -{ -if (flag) - return pt_dump (fileref, cptr, fnam); -return lp_load (fileref, cptr, fnam); -} - -/* Symbol tables */ - -#define I_V_FL 16 /* class bits */ -#define I_M_FL 0xF /* class mask */ -#define I_V_MR 0x0 /* mask-register */ -#define I_V_RR 0x1 /* register-register */ -#define I_V_R 0x2 /* register */ -#define I_V_MX 0x3 /* mask-memory */ -#define I_V_RX 0x4 /* register-memory */ -#define I_V_X 0x5 /* memory */ -#define I_V_FF 0x6 /* float reg-reg */ -#define I_V_FX 0x7 /* float reg-mem */ -#define I_V_SI 0x8 /* short immed */ -#define I_V_SB 0x9 /* short branch */ -#define I_V_SX 0xA /* short ext branch */ -#define I_V_RI 0xB /* halfword imm */ -#define I_V_RF 0xC /* fullword imm */ -#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) -#define I_SI (I_V_SI << I_V_FL) -#define I_SB (I_V_SB << I_V_FL) -#define I_SX (I_V_SX << I_V_FL) -#define I_RI (I_V_RI << I_V_FL) -#define I_RF (I_V_RF << I_V_FL) - -#define R_X 0 /* no R1 */ -#define R_M 1 /* R1 mask */ -#define R_R 2 /* R1 int reg */ -#define R_F 3 /* R1 flt reg */ - -static const int32 masks[] = { - 0xFF00, 0xFF00, 0xFFF0, 0xFF00, - 0xFF00, 0xFFF0, 0xFF00, 0xFF00, - 0xFF00, 0xFE00, 0xFEF0, 0xFF00, - 0xFF00 - }; - -static const uint32 r1_type[] = { - R_M, R_R, R_X, R_M, - R_R, R_X, R_F, R_F, - R_R, R_M, R_X, R_R, - R_R - }; - -static const uint32 r2_type[] = { - R_X, R_R, R_R, R_X, - R_X, R_X, R_F, R_X, - R_M, R_X, R_X, R_X, - R_X - }; - -static const char *opcode[] = { -"BER", "BNER","BZR", "BNZR", -"BPR", "BNPR","BLR", "BNLR", -"BMR", "BNMR","BOR", "BNOR", -"BCR", "BNCR","BR", -"BES", "BNES","BZS", "BNZS", -"BPS", "BNPS","BLS", "BNLS", -"BMS", "BNMS","BOS", "BNOS", -"BCS", "BNCS","BS", -"BE", "BNE", "BZ", "BNZ", -"BP", "BNP", "BL", "BNL", -"BM", "BNM", "BO", "BNO", -"BC", "BNC", "B", - "BALR","BTCR","BFCR", -"NR", "CLR", "OR", "XR", -"LR", "CHR", "AR", "SR", -"MHR", "DHR", -"SRLS","SLLS","CHVR", -"LPSWR", -"MR", "DR", -"BTBS","BTFS","BFBS","BFFS", -"LIS", "LCS", "AIS", "SIS", -"LER", "CER", "AER", "SER", -"MER", "DER", "FXR", "FLR", -"MPBSR", "PBR", -"EXHR", -"LDR", "CDR", "ADR", "SDR", -"MDR", "DDR", "FXDR","FLDR", -"STH", "BAL", "BTC", "BFC", -"NH", "CLH", "OH", "XH", -"LH", "CH", "AH", "SH", -"MH", "DH", -"ST", "AM", -"N", "CL", "O", "X", -"L", "C", "A", "S", -"M", "D", "CRC12","CRC16", -"STE", "AHM", "PB", "LRA", -"ATL", "ABL", "RTL", "RBL", -"LE", "CE", "AE", "SE", -"ME", "DE", -"STD", "STME","LME", "LHL", -"TBT", "SBT", "RBT", "CBT", -"LD", "CD", "AD", "SD", -"MD", "DD", "STMD","LMD", -"SRHLS","SLHLS","STBR","LBR", -"EXBR","EPSR","WBR", "RBR", -"WHR", "RHR", "WDR", "RDR", - "SSR", "OCR", -"BXH", "BXLE","LPSW","THI", -"NHI", "CLHI","OHI", "XHI", -"LHI", "CHI", "AHI", "SHI", -"SRHL","SLHL","SRHA","SLHA", -"STM", "LM", "STB", "LB", -"CLB", "AL", "WB", "RB", -"WH", "RH", "WD", "RD", - "SS", "OC", -"TS", "SVC", "SINT","SCP", - "LA", "TLATE", - "RRL", "RLL", -"SRL", "SLL", "SRA", "SLA", - "TI", -"NI", "CLI", "OI", "XI", -"LI", "CI", "AI", "SI", -NULL -}; - -static const uint32 opc_val[] = { -0x0330+I_R, 0x0230+I_R, 0x0330+I_R, 0x0230+I_R, -0x0220+I_R, 0x0320+I_R, 0x0280+I_R, 0x0380+I_R, -0x0210+I_R, 0x0310+I_R, 0x0240+I_R, 0x0340+I_R, -0x0280+I_R, 0x0380+I_R, 0x0300+I_R, -0x2230+I_SX, 0x2030+I_SX, 0x2230+I_SX, 0x2030+I_SX, -0x2020+I_SX, 0x2220+I_SX, 0x2080+I_SX, 0x2280+I_SX, -0x2010+I_SX, 0x2210+I_SX, 0x2040+I_SX, 0x2240+I_SX, -0x2080+I_SX, 0x2280+I_SX, 0x2200+I_SX, -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, 0x4340+I_X, -0x4280+I_X, 0x4380+I_X, 0x4300+I_X, - 0x0100+I_RR, 0x0200+I_MR, 0x0300+I_MR, -0x0400+I_RR, 0x0500+I_RR, 0x0600+I_RR, 0x0700+I_RR, -0x0800+I_RR, 0x0900+I_RR, 0x0A00+I_RR, 0x0B00+I_RR, -0x0C00+I_RR, 0x0D00+I_RR, -0x1000+I_SI, 0x1100+I_SI, 0x1200+I_RR, -0x1800+I_RR, -0x1C00+I_RR, 0x1D00+I_RR, -0x2000+I_SB, 0x2100+I_SB, 0x2200+I_SB, 0x2300+I_SB, -0x2400+I_SI, 0x2500+I_SI, 0x2600+I_SI, 0x2700+I_SI, -0x2800+I_FF, 0x2900+I_FF, 0x2A00+I_FF, 0x2B00+I_FF, -0x2C00+I_FF, 0x2D00+I_FF, 0x2E00+I_RR, 0x2F00+I_RR, -0x3000+I_RR, 0x3200+I_RR, -0x3400+I_RR, -0x3800+I_FF, 0x3900+I_FF, 0x3A00+I_FF, 0x3B00+I_FF, -0x3C00+I_FF, 0x3D00+I_FF, 0x3E00+I_RR, 0x3F00+I_RR, -0x4000+I_RX, 0x4100+I_RX, 0x4200+I_MX, 0x4300+I_MX, -0x4400+I_RX, 0x4500+I_RX, 0x4600+I_RX, 0x4700+I_RX, -0x4800+I_RX, 0x4900+I_RX, 0x4A00+I_RX, 0x4B00+I_RX, -0x4C00+I_RX, 0x4D00+I_RX, -0x5000+I_RX, 0x5100+I_RX, -0x5400+I_RX, 0x5500+I_RX, 0x5600+I_RX, 0x5700+I_RX, -0x5800+I_RX, 0x5900+I_RX, 0x5A00+I_RX, 0x5B00+I_RX, -0x5C00+I_RX, 0x5D00+I_RX, 0x5E00+I_RX, 0x5F00+I_RX, -0x6000+I_RX, 0x6100+I_RX, 0x6200+I_RX, 0x6300+I_RX, -0x6400+I_RX, 0x6500+I_RX, 0x6600+I_RX, 0x6700+I_RX, -0x6800+I_FX, 0x6900+I_FX, 0x6A00+I_FX, 0x6B00+I_FX, -0x6C00+I_FX, 0x6D00+I_FX, -0x7000+I_FX, 0x7100+I_FX, 0x7200+I_FX, 0x7300+I_RX, -0x7400+I_RX, 0x7500+I_RX, 0x7600+I_RX, 0x7700+I_RX, -0x7800+I_FX, 0x7900+I_FX, 0x7A00+I_FX, 0x7B00+I_FX, -0x7C00+I_FX, 0x7D00+I_FX, 0x7E00+I_FX, 0x7F00+I_FX, -0x9000+I_SI, 0x9100+I_SI, 0x9200+I_RR, 0x9300+I_RR, -0x9400+I_RR, 0x9500+I_RR, 0x9600+I_RR, 0x9700+I_RR, -0x9800+I_RR, 0x9900+I_RR, 0x9A00+I_RR, 0x9B00+I_RR, - 0x9D00+I_RR, 0x9E00+I_RR, -0xC000+I_RX, 0xC100+I_RX, 0xC200+I_RX, 0xC300+I_RI, -0xC400+I_RI, 0xC500+I_RI, 0xC600+I_RI, 0xC700+I_RI, -0xC800+I_RI, 0xC900+I_RI, 0xCA00+I_RI, 0xCB00+I_RI, -0xCC00+I_RI, 0xCD00+I_RI, 0xCE00+I_RI, 0xCF00+I_RI, -0xD000+I_RX, 0xD100+I_RX, 0xD200+I_RX, 0xD300+I_RX, -0xD400+I_RX, 0xD500+I_X, 0xD600+I_RX, 0xD700+I_RX, -0xD800+I_RX, 0xD900+I_RX, 0xDA00+I_RX, 0xDB00+I_RX, - 0xDD00+I_RX, 0xDE00+I_RX, -0xE000+I_RX, 0xE100+I_RX, 0xE200+I_RI, 0xE300+I_RX, - 0xE600+I_RX, 0xE700+I_RX, - 0xEA00+I_RI, 0xEB00+I_RI, -0xEC00+I_RI, 0xED00+I_RI, 0xEE00+I_RI, 0xEF00+I_RI, - 0xF300+I_RF, -0xF400+I_RF, 0xF500+I_RF, 0xF600+I_RF, 0xF700+I_RF, -0xF800+I_RF, 0xF900+I_RF, 0xFA00+I_RF, 0xFB00+I_RF, -0xFFFF -}; - -/* Print an RX specifier */ - -t_stat fprint_addr (FILE *of, t_addr addr, uint32 rx, uint32 ea1, - uint32 ea2) -{ -uint32 rx2; - -if ((ea1 & 0xC000) == 0) { /* RX1 */ - fprintf (of, "%-X", ea1); - if (rx) - fprintf (of, "(R%d)", rx); - return -3; - } -if (ea1 & 0x8000) { /* RX2 */ - ea1 = addr + 4 + SEXT15 (ea1); - fprintf (of, "%-X", ea1 & VAMASK32); - if (rx) - fprintf (of, "(R%d)", rx); - return -3; - } -rx2 = (ea1 >> 8) & 0xF; /* RX3 */ -fprintf (of, "%-X", ((ea1 << 16) | ea2) & VAMASK32); -if (rx && !rx2) - fprintf (of, "(R%d)", rx); -if (rx2) - fprintf (of, "(R%d,R%d)", rx, rx2); -return -5; -} - -/* 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 bytes retired -*/ - -t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, - UNIT *uptr, int32 sw) -{ -int32 bflag, c1, c2, rdx; -t_stat r; -DEVICE *dptr; - -if (uptr == NULL) /* anon = CPU */ - uptr = &cpu_unit; -dptr = find_dev_from_unit (uptr); /* find dev */ -if (dptr == NULL) - return SCPE_IERR; -if (dptr->dwidth < 16) /* 8b dev? */ - bflag = 1; -else bflag = 0; /* assume 16b */ -if (sw & SWMASK ('D')) /* get radix */ - rdx = 10; -else if (sw & SWMASK ('O')) - rdx = 8; -else if (sw & SWMASK ('H')) - rdx = 16; -else rdx = dptr->dradix; - -if (sw & SWMASK ('A')) { /* ASCII char? */ - if (bflag) - c1 = val[0] & 0x7F; - else c1 = (val[0] >> ((addr & 1)? 0: 8)) & 0x7F; /* get byte */ - fprintf (of, (c1 < 0x20)? "<%02X>": "%c", c1); - return 0; - } -if (sw & SWMASK ('B')) { /* byte? */ - if (bflag) - c1 = val[0] & 0xFF; - else c1 = (val[0] >> ((addr & 1)? 0: 8)) & 0xFF; /* get byte */ - fprint_val (of, c1, rdx, 8, PV_RZRO); - return 0; - } -if (bflag) /* 16b only */ - return SCPE_ARG; - -if (sw & SWMASK ('C')) { /* string? */ - c1 = (val[0] >> 8) & 0x7F; - c2 = val[0] & 0x7F; - fprintf (of, (c1 < 0x20)? "<%02X>": "%c", c1); - fprintf (of, (c2 < 0x20)? "<%02X>": "%c", c2); - return -1; - } -if (sw & SWMASK ('W')) { /* halfword? */ - fprint_val (of, val[0], rdx, 16, PV_RZRO); - return -1; - } -if (sw & SWMASK ('M')) { /* inst format? */ - r = fprint_sym_m (of, addr, val); /* decode inst */ - if (r <= 0) - return r; - } - -fprint_val (of, (val[0] << 16) | val[1], rdx, 32, PV_RZRO); -return -3; -} - -/* Symbolic decode for -m - - Inputs: - of = output stream - addr = current PC - *val = values to decode - cf = true if parsing for CPU - Outputs: - return = if >= 0, error code - if < 0, number of extra bytes retired -*/ - -t_stat fprint_sym_m (FILE *of, t_addr addr, t_value *val) -{ -uint32 i, j, inst, r1, r2, ea1, ea2; - -inst = val[0]; -ea1 = val[1]; -ea2 = val[2]; -for (i = 0; opc_val[i] != 0xFFFF; 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 = (inst >> 4) & 0xF; - r2 = inst & 0xF; - fprintf (of, "%s ", opcode[i]); /* print opcode */ - switch (j) { /* case on class */ - - case I_V_MR: /* mask-register */ - fprintf (of, "%-X,R%d", r1, r2); - return -1; - - case I_V_RR: /* register-register */ - case I_V_FF: /* floating-floating */ - fprintf (of, "R%d,R%d", r1, r2); - return -1; - - case I_V_SI: /* short immediate */ - fprintf (of, "R%d,%-X", r1, r2); - return -1; - - case I_V_SB: /* short branch */ - fprintf (of, "%-X,", r1); - case I_V_SX: /* ext short branch */ - fprintf (of, "%-X", ((inst & MSK_SBF)? - (addr + r2 + r2): (addr - r2 - r2))); - return -1; - - case I_V_R: /* register */ - fprintf (of, "R%d", r2); - return -1; - - case I_V_RI: /* reg-immed */ - fprintf (of, "R%d,%-X", r1, ea1); - if (r2) - fprintf (of, "(R%d)", r2); - return -3; - - case I_V_RF: /* reg-full imm */ - fprintf (of, "R%d,%-X", r1, (ea1 << 16) | ea2); - if (r2) - fprintf (of, "(R%d)", r2); - return -5; - - case I_V_MX: /* mask-memory */ - fprintf (of, "%-X,", r1); - return fprint_addr (of, addr, r2, ea1, ea2); - - case I_V_RX: /* register-memory */ - case I_V_FX: /* floating-memory */ - fprintf (of, "R%d,", r1); - case I_V_X: /* memory */ - return fprint_addr (of, addr, r2, ea1, ea2); - } /* end case */ - return SCPE_IERR; - } /* end if */ - } /* end for */ -return SCPE_ARG; /* no match */ -} - -/* Register number - - Inputs: - *cptr = pointer to input string - **optr = pointer to pointer to next char - rtype = mask, integer, or float - Outputs: - rnum = output register number, -1 if error -*/ - -int32 get_reg (char *cptr, char **optr, int32 rtype) -{ -int32 reg; - -if ((*cptr == 'R') || (*cptr == 'r')) { /* R? */ - cptr++; /* skip */ - if (rtype == R_M) /* cant be mask */ - return -1; - } -if ((*cptr >= '0') && (*cptr <= '9')) { - reg = *cptr++ - '0'; - if ((*cptr >= '0') && (*cptr <= '9')) - reg = (reg * 10) + (*cptr - '0'); - else --cptr; - if (reg > 0xF) - return -1; - } -else if ((*cptr >= 'a') && (*cptr <= 'f')) - reg = (*cptr - 'a') + 10; -else if ((*cptr >= 'A') && (*cptr <= 'F')) - reg = (*cptr - 'A') + 10; -else return -1; -if ((rtype == R_F) && (reg & 1)) - return -1; -*optr = cptr + 1; -return reg; -} - -/* Immediate - - Inputs: - *cptr = pointer to input string - *imm = pointer to output value - *inst = pointer to instruction - max = max value - Outputs: - sta = status -*/ - -t_stat get_imm (char *cptr, uint32 *imm, uint32 *inst, uint32 max) -{ -char *tptr; -int32 idx; - -errno = 0; -*imm = strtoul (cptr, &tptr, 16); /* get immed */ -if (errno || (*imm > max) || (cptr == tptr)) - return SCPE_ARG; -if (*tptr == '(') { /* index? */ - if ((idx = get_reg (tptr + 1, &tptr, R_R)) < 0) - return SCPE_ARG; - if (*tptr++ != ')') - return SCPE_ARG; - *inst = *inst | idx; - } -if (*tptr != 0) - return SCPE_ARG; -return SCPE_OK; -} - -/* Address - - Inputs: - *cptr = pointer to input string - **tptr = pointer to moved pointer - *ea = effective address - addr = base address - Outputs: - status = SCPE_OK if ok, else error code -*/ - -t_stat get_addr (char *cptr, char **tptr, t_addr *ea, t_addr addr) -{ -int32 sign = 1; - -if (*cptr == '.') { /* relative? */ - cptr++; - *ea = addr; - if (*cptr == '+') /* .+? */ - cptr++; - else if (*cptr == '-') { /* .-? */ - sign = -1; - cptr++; - } - else return SCPE_OK; - } -else *ea = 0; -errno = 0; -*ea = *ea + (sign * ((int32) strtoul (cptr, tptr, 16))); -if (errno || (cptr == *tptr)) - return SCPE_ARG; -return SCPE_OK; -} - -/* Symbolic input */ - -t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) -{ -int32 bflag, by, rdx, num; -t_stat r; -DEVICE *dptr; - -if (uptr == NULL) /* anon = CPU */ - uptr = &cpu_unit; -dptr = find_dev_from_unit (uptr); /* find dev */ -if (dptr == NULL) - return SCPE_IERR; -if (dptr->dwidth < 16) /* 8b dev? */ - bflag = 1; -else bflag = 0; /* assume 16b */ -if (sw & SWMASK ('D')) /* get radix */ - rdx = 10; -else if (sw & SWMASK ('O')) - rdx = 8; -else if (sw & SWMASK ('H')) - rdx = 16; -else rdx = dptr->dradix; - -if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ - if (cptr[0] == 0) /* must have 1 char */ - return SCPE_ARG; - if (bflag) - val[0] = (t_value) cptr[0]; - else val[0] = (addr & 1)? - (val[0] & ~0xFF) | ((t_value) cptr[0]): - (val[0] & 0xFF) | (((t_value) cptr[0]) << 8); - return 0; - } -if (sw & SWMASK ('B')) { /* byte? */ - by = get_uint (cptr, rdx, DMASK8, &r); /* get byte */ - if (r != SCPE_OK) - return SCPE_ARG; - if (bflag) val[0] = by; - else val[0] = (addr & 1)? - (val[0] & ~0xFF) | by: - (val[0] & 0xFF) | (by << 8); - return 0; - } -if (bflag) /* 16b only */ - return SCPE_ARG; - -if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII chars? */ - if (cptr[0] == 0) /* must have 1 char */ - return SCPE_ARG; - val[0] = ((t_value) cptr[0] << 8) | (t_value) cptr[1]; - return -1; - } -if (sw & SWMASK ('W')) { /* halfword? */ - val[0] = (int32) get_uint (cptr, rdx, DMASK16, &r); /* get number */ - if (r != SCPE_OK) - return r; - return -1; - } - -r = parse_sym_m (cptr, addr, val); /* try to parse inst */ -if (r <= 0) - return r; -num = (int32) get_uint (cptr, rdx, DMASK32, &r); /* get number */ -if (r != SCPE_OK) - return r; -val[0] = (num >> 16) & DMASK16; -val[1] = num & DMASK16; -return -3; -} - -/* Symbolic input for -m - - Inputs: - *cptr = pointer to input string - addr = current PC - *val = pointer to output values - cf = true if parsing for CPU - Outputs: - status = > 0 error code - <= 0 -number of extra words -*/ - -t_stat parse_sym_m (char *cptr, t_addr addr, t_value *val) -{ -uint32 i, j, df, db, t, inst; -int32 st, r1, r2, rx2; -t_stat r; -char *tptr, gbuf[CBUFSIZE]; - -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; -inst = opc_val[i] & 0xFFFF; /* get value */ -j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */ -if (r1_type[j]) { /* any R1 field? */ - cptr = get_glyph (cptr, gbuf, ','); /* get R1 field */ - if ((r1 = get_reg (gbuf, &tptr, r1_type[j])) < 0) - return SCPE_ARG; - if (*tptr != 0) - return SCPE_ARG; - inst = inst | (r1 << 4); /* or in R1 */ - } - -cptr = get_glyph (cptr, gbuf, 0); /* get operand */ -if (*cptr) /* should be end */ - return SCPE_ARG; -switch (j) { /* case on class */ - - case I_V_FF: case I_V_SI: /* flt-flt, sh imm */ - case I_V_MR: case I_V_RR: /* mask/reg-register */ - case I_V_R: /* register */ - if ((r2 = get_reg (gbuf, &tptr, r2_type[j])) < 0) - return SCPE_ARG; - if (*tptr != 0) - return SCPE_ARG; - inst = inst | r2; /* or in R2 */ - break; - - case I_V_FX: /* float-memory */ - case I_V_MX: case I_V_RX: /* mask/reg-memory */ - case I_V_X: /* memory */ - r = get_addr (gbuf, &tptr, &t, addr); /* get addr */ - if (r != SCPE_OK) /* error? */ - return SCPE_ARG; - rx2 = 0; /* assume no 2nd */ - if (*tptr == '(') { /* index? */ - if ((r2 = get_reg (tptr + 1, &tptr, R_R)) < 0) - return SCPE_ARG; - inst = inst | r2; /* or in R2 */ - if (*tptr == ',') { /* 2nd index? */ - if ((rx2 = get_reg (tptr + 1, &tptr, R_R)) < 0) - return SCPE_ARG; - } - if (*tptr++ != ')') /* all done? */ - return SCPE_ARG; - } - if (*tptr != 0) - return SCPE_ARG; - val[0] = inst; /* store inst */ - if (rx2 == 0) { /* no 2nd? */ - if (t < 0x4000) { /* RX1? */ - val[1] = t; /* store ea */ - return -3; - } - st = (t - (addr + 4)); /* displ */ - if ((st <= 0x3FFF) && (st >= -0x4000)) { /* RX2? CPU only */ - t = (st & 0x7FFF) | 0x8000; - val[1] = t; /* store displ */ - return -3; - } - } - t = (t & VAMASK32) | 0x40000000 | (rx2 << 24); - val[1] = (t >> 16) & DMASK16; - val[2] = t & DMASK16; - return -5; - - case I_V_RI: /* 16b immediate */ - r = get_imm (gbuf, &t, &inst, DMASK16); /* process imm */ - if (r != SCPE_OK) - return r; - val[0] = inst; - val[1] = t; - return -3; - - case I_V_RF: - r = get_imm (gbuf, &t, &inst, DMASK32); /* process imm */ - if (r != SCPE_OK) - return r; - val[0] = inst; - val[1] = (t >> 16) & DMASK16; - val[2] = t & DMASK16; - return -5; - - case I_V_SB: case I_V_SX: /* short branches */ - r = get_addr (gbuf, &tptr, &t, addr); /* get addr */ - if ((r != SCPE_OK) || (t & 1) || *tptr) /* error if odd */ - return SCPE_ARG; - st = t; /* signed version */ - db = (addr - t) & 0x1F; /* back displ */ - df = (t - addr) & 0x1F; /* fwd displ */ - if ((t == ((addr - db) & VAMASK16)) && /* back work and */ - ((j == I_V_SX) || !(inst & MSK_SBF))) /* ext or back br? */ - inst = inst | (db >> 1); /* or in back displ */ - else if ((t == ((addr + df) & VAMASK16)) && /* fwd work and */ - ((j == I_V_SX) || (inst & MSK_SBF))) /* ext or fwd br? */ - inst = inst | (df >> 1) | MSK_SBF; /* or in fwd displ */ - else return SCPE_ARG; - } /* end case */ - -val[0] = inst; -return -1; -} diff --git a/Interdata/id_defs.h b/Interdata/id_defs.h deleted file mode 100644 index d2e82866..00000000 --- a/Interdata/id_defs.h +++ /dev/null @@ -1,489 +0,0 @@ -/* id_defs.h: Interdata 16b/32b simulator definitions - - Copyright (c) 2000-2012, 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 author gratefully acknowledges the help of Carl Friend and Al Kossow, - who provided key documents about the Interdata product line. - - 18-Apr-12 RMS Added clock coschedule prototype - 22-May-10 RMS Added check for 64b definitions - 09-Mar-06 RMS Increased register sets to architectural limit - 25-Jan-04 RMS Removed local logging support - 22-Sep-03 RMS Added additional instruction decode types - 21-Jun-03 RMS Changed subroutine argument for ARM compiler conflict - 25-Apr-03 RMS Revised for extended file support - 28-Feb-03 RMS Changed magtape device default to 0x85 -*/ - -#ifndef ID_DEFS_H_ -#define ID_DEFS_H_ 0 - -#include "sim_defs.h" /* simulator defns */ - -#if defined(USE_INT64) || defined(USE_ADDR64) -#error "Interdata 16/32 does not support 64b values!" -#endif - -/* Simulator stop codes */ - -#define STOP_RSRV 1 /* undef instr */ -#define STOP_HALT 2 /* HALT */ -#define STOP_IBKPT 3 /* breakpoint */ -#define STOP_WAIT 4 /* wait */ -#define STOP_VFU 5 /* runaway VFU */ - -/* Memory */ - -#define PAWIDTH16 16 -#define PAWIDTH16E 18 -#define PAWIDTH32 20 -#define MAXMEMSIZE16 (1u << PAWIDTH16) /* max mem size, 16b */ -#define MAXMEMSIZE16E (1u << PAWIDTH16E) /* max mem size, 16b E */ -#define MAXMEMSIZE32 (1u << PAWIDTH32) /* max mem size, 32b */ -#define PAMASK16 (MAXMEMSIZE16 - 1) /* phys mem mask */ -#define PAMASK16E (MAXMEMSIZE16E - 1) -#define PAMASK32 (MAXMEMSIZE32 - 1) - -#define MEMSIZE (cpu_unit.capac) /* act memory size */ -#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) - -/* Single precision floating point registers */ - -#if defined (IFP_IN_MEM) -#define ReadFReg(r) (fp_in_hwre? \ - F[(r) >> 1]: ReadF (((r) << 1) & ~3, P)) -#define WriteFReg(r,v) if (fp_in_hwre) F[(r) >> 1] = (v); \ - else WriteF (((r) << 1) & ~3, (v), P) -#else -#define ReadFReg(r) (F[(r) >> 1]) -#define WriteFReg(r,v) F[(r) >> 1] = (v) -#endif - -/* Double precision floating point registers */ - -typedef struct { - uint32 h; /* high 32b */ - uint32 l; /* low 32b */ - } dpr_t; - -/* Architectural constants */ - -#define VAMASK16 (0xFFFF) /* 16b virt addr */ -#define VAMASK32 (0x000FFFFF) /* 32b virt addr */ - -#define SIGN8 0x80 /* 8b sign bit */ -#define DMASK8 0xFF /* 8b data mask */ -#define MMASK8 0x7F /* 8b magnitude mask */ -#define SIGN16 0x8000 /* 16b sign bit */ -#define DMASK16 0xFFFF /* 16b data mask */ -#define MMASK16 0x7FFF /* 16b magnitude mask */ -#define SIGN32 0x80000000 /* 32b sign bit */ -#define DMASK32 0xFFFFFFFF /* 32b data mask */ -#define MMASK32 0x7FFFFFFF /* 32b magn mask */ - -#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_AFI 0x1000 /* arith fault enb */ -#define PSW_AIO 0x0800 /* auto I/O int enable */ -#define PSW_FPF 0x0400 /* flt fault enb, 16b */ -#define PSW_REL 0x0400 /* reloc enb, 32b */ -#define PSW_SQI 0x0200 /* sys q int enable */ -#define PSW_PRO 0x0100 /* protect mode */ -#define PSW_V_MAP 4 /* mem map, 16b */ -#define PSW_M_MAP 0xF -#define PSW_MAP (PSW_M_MAP << PSW_V_MAP) -#define PSW_V_REG 4 /* reg set, 32b */ -#define PSW_M_REG 0xF -#define PSW_ID4 0xF40F /* I3, I4 PSW */ -#define PSW_x16 0xFF0F /* 7/16, 8/16 PSW */ -#define PSW_816E 0xFFFF /* 8/16E PSW */ -#define PSW_x32 0xFFFF /* 7/32, 8/32 PSW */ - -#define MCKOPSW 0x20 /* mchk old PSW, 32b */ -#define FPFPSW 0x28 /* flt fault PSW, 16b */ -#define ILOPSW 0x30 /* ill op PSW */ -#define MCKPSW 0x38 /* mach chk PSW */ -#define EXIPSW 0x40 /* ext intr PSW, 16b */ -#define AFIPSW 0x48 /* arith flt PSW */ -#define SQP 0x80 /* system queue ptr */ -#define SQIPSW 0x82 /* sys q int PSW, 16b */ -#define SQOP 0x8A /* sys q ovf ptr, 16b */ -#define SQVPSW 0x8C /* sys q ovf PSW, 16b */ -#define SQTPSW 0x88 /* sys q int PSW, 32b */ -#define MPRPSW 0x90 /* mprot int PSW, 32b */ -#define SVCAP 0x94 /* svc arg ptr, 16b */ -#define SVOPS 0x96 /* svc old PS, 16b */ -#define SVOPC 0x98 /* svc old PC, 16b */ -#define SVNPS32 0x98 /* svc new PS, 32b */ -#define SVNPS 0x9A /* svc new PS, 16b */ -#define SVNPC 0x9C /* svc new PC */ -#define INTSVT 0xD0 /* int service table */ - -#define AL_DEV 0x78 /* autoload: dev */ -#define AL_IOC 0x79 /* command */ -#define AL_DSKU 0x7A /* disk unit */ -#define AL_DSKT 0x7B /* disk type */ -#define AL_DSKC 0x7C /* disk ctrl */ -#define AL_SCH 0x7D /* sel chan */ -#define AL_EXT 0x7E /* OS extension */ -#define AL_BUF 0x80 /* buffer start */ - -#define Q16_SLT 0 /* list: # slots */ -#define Q16_USD 1 /* # in use */ -#define Q16_TOP 2 /* current top */ -#define Q16_BOT 3 /* next bottom */ -#define Q16_BASE 4 /* base of q */ -#define Q16_SLNT 2 /* slot length */ - -#define Q32_SLT 0 /* list: # slots */ -#define Q32_USD 2 /* # in use */ -#define Q32_TOP 4 /* current top */ -#define Q32_BOT 6 /* next bottom */ -#define Q32_BASE 8 /* base of q */ -#define Q32_SLNT 4 /* slot length */ - -/* CPU event flags */ - -#define EV_MAC 0x01 /* MAC interrupt */ -#define EV_BLK 0x02 /* block I/O in prog */ -#define EV_INT 0x04 /* interrupt pending */ -#define EV_WAIT 0x08 /* wait state pending */ - -/* Block I/O state */ - -struct BlockIO { - uint32 dfl; /* devno, flags */ - uint32 cur; /* current addr */ - uint32 end; /* end addr */ - }; - -#define BL_RD 0x8000 /* block read */ -#define BL_LZ 0x4000 /* skip 0's */ - -/* Instruction decode ROM, for all, 16b, 32b */ - -#define OP_UNDEF 0x0000 /* undefined */ -#define OP_NO 0x0001 /* all: short or fp rr */ -#define OP_RR 0x0002 /* all: reg-reg */ -#define OP_RS 0x0003 /* 16b: reg-storage */ -#define OP_RI1 0x0003 /* 32b: reg-imm 16b */ -#define OP_RX 0x0004 /* all: reg-mem */ -#define OP_RXB 0x0005 /* all: reg-mem, rd BY */ -#define OP_RXH 0x0006 /* all: reg-mem, rd HW */ -#define OP_RXF 0x0007 /* 32b: reg-mem, rd FW */ -#define OP_RI2 0x0008 /* 32b: reg-imm 32b */ -#define OP_MASK 0x000F - -#define OP_ID4 0x0010 /* 16b: ID4 */ -#define OP_716 0x0020 /* 16b: 7/16 */ -#define OP_816 0x0040 /* 16b: 8/16 */ -#define OP_816E 0x0080 /* 16b: 8/16E */ - -#define OP_DPF 0x4000 /* all: hwre FP */ -#define OP_PRV 0x8000 /* all: privileged */ - -#define OP_TYPE(x) (decrom[(x)] & OP_MASK) -#define OP_DPFP(x) (decrom[(x)] & OP_DPF) - -/* Device information block */ - -typedef struct { - uint32 dno; /* device number */ - int32 sch; /* sch */ - uint32 irq; /* interrupt */ - uint8 *tplte; /* template */ - uint32 (*iot)(uint32 d, uint32 o, uint32 dat); - void (*ini)(t_bool f); - } DIB; - -#define TPL_END 0xFF /* template end */ - -/* Device select return codes */ - -#define BY 0 /* 8b only */ -#define HW 1 /* 8b/16b */ - -/* I/O operations */ - -#define IO_ADR 0x0 /* address select */ -#define IO_RD 0x1 /* read byte */ -#define IO_RH 0x2 /* read halfword */ -#define IO_WD 0x3 /* write byte */ -#define IO_WH 0x4 /* write halfword */ -#define IO_OC 0x5 /* output command */ -#define IO_SS 0x6 /* sense status */ - -/* 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_IDSA 3 /* disarm */ -#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 */ - -/* Default 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 d_DS 0x01 /* display, switches */ -#define d_TT 0x02 /* teletype */ -#define d_PT 0x03 /* reader */ -#define d_CD 0x04 /* card reader */ -#define d_TTP 0x10 /* PAS as console */ -#define d_PAS 0x10 /* first PAS */ -#define o_PASX 0x01 /* offset to xmt */ -#define d_LPT 0x62 /* line printer */ -#define d_PIC 0x6C /* interval timer */ -#define d_LFC 0x6D /* line freq clk */ -#define d_MT 0x85 /* magtape */ -#define o_MT0 0x10 -#define d_DPC 0xB6 /* disk controller */ -#define o_DP0 0x10 -#define o_DPF 0x01 /* offset to fixed */ -#define d_FD 0xC1 /* floppy disk */ -#define d_SCH 0xF0 /* selector chan */ -#define d_IDC 0xFB /* MSM disk ctrl */ -#define o_ID0 0x01 - -/* Interrupts - - To make interrupt flags independent of device numbers, each device is - assigned an interrupt flag in one of four interrupt words - - word 0 DMA devices - word 1 programmed I/O devices - word 2-3 PAS devices - - Devices are identified by a level and a bit within a level. Priorities - run low to high in the array, right to left within words -*/ - -#define INTSZ 4 /* interrupt words */ -#define SCH_NUMCH 4 /* #channels */ -#define ID_NUMDR 4 /* # MSM drives */ -#define DP_NUMDR 4 /* # DPC drives */ -#define MT_NUMDR 4 /* # MT drives */ - -/* Word 0, DMA devices */ - -#define i_SCH 0 /* highest priority */ -#define i_IDC (i_SCH + SCH_NUMCH) /* MSM disk ctrl */ -#define i_DPC (i_IDC + ID_NUMDR + 1) /* cartridge disk ctrl */ -#define i_MT (i_DPC + DP_NUMDR + 1) /* magtape */ - -#define l_SCH 0 -#define l_IDC 0 -#define l_DPC 0 -#define l_MT 0 - -#define v_SCH (l_SCH * 32) + i_SCH -#define v_IDC (l_IDC * 32) + i_IDC -#define v_DPC (l_DPC * 32) + i_DPC -#define v_MT (l_MT * 32) + i_MT - -/* Word 1, programmed I/O devices */ - -#define i_PIC 0 /* precision clock */ -#define i_LFC 1 /* line clock */ -#define i_FD 2 /* floppy disk */ -#define i_CD 3 /* card reader */ -#define i_LPT 4 /* line printer */ -#define i_PT 5 /* paper tape */ -#define i_TT 6 /* teletype */ -#define i_DS 7 /* display */ -#define i_TTP 10 /* PAS console */ - -#define l_PIC 1 -#define l_LFC 1 -#define l_FD 1 -#define l_CD 1 -#define l_LPT 1 -#define l_PT 1 -#define l_TT 1 -#define l_DS 1 -#define l_TTP 1 - -#define v_PIC (l_PIC * 32) + i_PIC -#define v_LFC (l_LFC * 32) + i_LFC -#define v_FD (l_FD * 32) + i_FD -#define v_CD (l_CD * 32) + i_CD -#define v_LPT (l_LPT * 32) + i_LPT -#define v_PT (l_PT * 32) + i_PT -#define v_TT (l_TT * 32) + i_TT -#define v_DS (l_DS * 32) + i_DS -#define v_TTP (l_TTP * 32) + i_TTP - -/* Word 2-3, PAS devices */ - -#define i_PAS 0 -#define l_PAS 2 -#define v_PAS (l_PAS * 32) + i_PAS -#define v_PASX (v_PAS + 1) /* offset to xmt */ - -/* I/O macros */ - -#define SET_INT(v) int_req[(v) >> 5] = int_req[(v) >> 5] | (1u << ((v) & 0x1F)) -#define CLR_INT(v) int_req[(v) >> 5] = int_req[(v) >> 5] & ~(1u << ((v) & 0x1F)) -#define SET_ENB(v) int_enb[(v) >> 5] = int_enb[(v) >> 5] | (1u << ((v) & 0x1F)) -#define CLR_ENB(v) int_enb[(v) >> 5] = int_enb[(v) >> 5] & ~(1u << ((v) & 0x1F)) - -#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */ - -/* Device accessible macro */ - -#define DEV_ACC(d) (dev_tab[d] && !sch_blk (d)) - -/* Automatic I/O channel programs, 16b */ - -#define CCB16_CHN -4 /* chain */ -#define CCB16_DEV -2 /* dev no */ -#define CCB16_STS -1 /* status */ -#define CCB16_CCW 0 /* cmd wd */ -#define CCB16_STR 2 /* start */ -#define CCB16_END 4 /* end */ -#define CCB16_IOC 6 /* OC byte */ -#define CCB16_TRM 7 /* term byte */ - -#define CCW16_INIT 0x8000 /* init */ -#define CCW16_NOP 0x4000 /* nop */ -#define CCW16_V_FNC 12 /* function */ -#define CCW16_M_FNC 0x3 -#define CCW16_FNC(x) (((x) >> CCW16_V_FNC) & CCW16_M_FNC) -#define CCW16_RD 0 /* read */ -#define CCW16_WR 1 /* write */ -#define CCW16_DMT 2 /* dec mem */ -#define CCW16_NUL 3 /* null */ -#define CCW16_TRM 0x0400 /* term char */ -#define CCW16_Q 0x0200 /* queue */ -#define CCW16_HI 0x0100 /* queue hi */ -#define CCW16_OC 0x0080 /* OC */ -#define CCW16_CHN 0x0020 /* chain */ -#define CCW16_CON 0x0010 /* continue */ -#define CCW16_V_BPI 0 /* bytes per int */ -#define CCW16_M_BPI 0xF -#define CCW16_BPI(x) (((x) >> CCW16_V_BPI) & CCW16_M_BPI) - -/* Automatic I/O channel programs, 32b */ - -#define CCB32_CCW 0 /* cmd wd */ -#define CCB32_B0C 2 /* buf 0 cnt */ -#define CCB32_B0E 4 /* buf 0 end */ -#define CCB32_CHK 8 /* check word */ -#define CCB32_B1C 10 /* buf 1 cnt */ -#define CCB32_B1E 12 /* buf 1 end */ -#define CCB32_TAB 16 /* trans table */ -#define CCB32_SUB 20 /* subroutine */ - -#define CCW32_V_STA 8 /* status */ -#define CCW32_M_STA 0xFF -#define CCW32_STA(x) (((x) >> CCW32_V_STA) & CCW32_M_STA) -#define CCW32_EXE 0x80 /* execute */ -#define CCW32_CRC 0x10 -#define CCW32_B1 0x08 /* buffer 1 */ -#define CCW32_WR 0x04 /* write */ -#define CCW32_TL 0x02 /* translate */ -#define CCW32_FST 0x01 /* fast mode */ - -/* MAC, 32b */ - -#define P 0 /* physical */ -#define VE 1 /* virtual inst */ -#define VR 2 /* virtual read */ -#define VW 3 /* virtual write */ - -#define MAC_BASE 0x300 /* MAC base */ -#define MAC_STA 0x340 /* MAC status */ -#define MAC_LNT 16 -#define VA_V_OFF 0 /* offset */ -#define VA_M_OFF 0xFFFF -#define VA_GETOFF(x) (((x) >> VA_V_OFF) & VA_M_OFF) -#define VA_V_SEG 16 /* segment */ -#define VA_M_SEG 0xF -#define VA_GETSEG(x) (((x) >> VA_V_SEG) & VA_M_SEG) - -#define SRF_MASK 0x000FFF00 /* base mask */ -#define SRL_MASK 0x0FF00000 /* limit mask */ -#define GET_SRL(x) ((((x) & SRL_MASK) >> 12) + 0x100) -#define SR_EXP 0x80 /* execute prot */ -#define SR_WPI 0x40 /* wr prot int */ -#define SR_WRP 0x20 /* wr prot */ -#define SR_PRS 0x10 /* present */ -#define SR_MASK (SRF_MASK|SRL_MASK|SR_EXP|SR_WPI|SR_WRP|SR_PRS) - -#define MACS_L 0x10 /* limit viol */ -#define MACS_NP 0x08 /* not present */ -#define MACS_WP 0x04 /* write prot */ -#define MACS_WI 0x02 /* write int */ -#define MACS_EX 0x01 /* exec prot */ - -/* Miscellaneous */ - -#define TMR_LFC 0 /* LFC = timer 0 */ -#define TMR_PIC 1 /* PIC = timer 1 */ -#define LPT_WIDTH 132 -#define VFU_LNT 132 -#define MIN(x,y) (((x) < (y))? (x): (y)) -#define MAX(x,y) (((x) > (y))? (x): (y)) - -/* Function prototypes */ - -int32 int_chg (uint32 irq, int32 dat, int32 armdis); -int32 io_2b (int32 val, int32 pos, int32 old); -uint32 IOReadB (uint32 loc); -void IOWriteB (uint32 loc, uint32 val); -uint32 IOReadH (uint32 loc); -void IOWriteH (uint32 loc, uint32 val); -uint32 ReadF (uint32 loc, uint32 rel); -void WriteF (uint32 loc, uint32 val, uint32 rel); -uint32 IOReadBlk (uint32 loc, uint32 cnt, uint8 *buf); -uint32 IOWriteBlk (uint32 loc, uint32 cnt, uint8 *buf); -void sch_adr (uint32 ch, uint32 dev); -t_bool sch_actv (uint32 sch, uint32 devno); -void sch_stop (uint32 sch); -uint32 sch_wrmem (uint32 sch, uint8 *buf, uint32 cnt); -uint32 sch_rdmem (uint32 sch, uint8 *buf, uint32 cnt); -t_stat set_sch (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat set_dev (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat show_sch (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat show_dev (FILE *st, UNIT *uptr, int32 val, void *desc); - -int32 lfc_cosched (int32 wait); - -#endif diff --git a/Interdata/id_diag.txt b/Interdata/id_diag.txt deleted file mode 100644 index c0daf2fe..00000000 --- a/Interdata/id_diag.txt +++ /dev/null @@ -1,911 +0,0 @@ -Interdata Diagnostics - -Summary - -816E CPU diagnostic, part 1 passed 16b n/a -816E CPU diagnostic, part 2 partial 16b n/a -Series 16 CPU diagnostic, part 1 passed 16b n/a -16b memory diagnostic, part 1 passed 16b n/a -16b memory diagnostic, part 2 passed 16b n/a -816e extended memory diagnostic passed 16b n/a -Series 16 selector channel diagnostic passed 16b n/a -32b CPU diagnostic, part 1 n/a passed 32b -32b CPU diagnostic, part 2 n/a passed 32b -32b CPU diagnostic, part 3 n/a passed 32b -32b memory diagnostic, part 1 n/a passed 32b -32b memory diagnostic, part 2 n/a passed 32b -32b memory diagnostic, part 3 n/a passed 32b -32b memory diagnostic 6a, part 1 n/a passed 32b -32b memory diagnostic 6a, part 2 n/a passed 32b -32b MAC diagnostic, part 1 n/a passed 32b -32b MAC diagnostic, part 2 n/a passed 32b -Common line printer diagnostic passed 16b passed 32b -Common magtape diagnostic passed 16b passed 32b -Common 2.5/10MB disk diagnostic passed 16b passed 32b -32b MSM disk diagnostic passed 32b -Common floppy disk diagnostic passed 16b passed 32b -Common clock diagnostic passed 16b passed 32b - -Not tested: -- 16b floating point -- 32b double precision floating point -- IDC -- PASLA - -------------------------------------------------------------------- - -Operating Instructions - -816E CPU diagnostic, part 1 - -sim> set cpu 816e -sim> att -e pt0 diag.bin -sim> br c2 -sim> boot pt0 - -Breakpoint: PC: 00C2 (EXBR R8,R6) - -sim> run 100 - -MODEL 8/16E PROCESSOR TEST PART 1 06-211R00 -CPU -* 8D - -ENTER 0 OR 1 -1 -NO ERROR - -CPU -* - ---- -816E CPU diagnostic, part 2 - -sim> set cpu 816e -sim> d tt ttime 1000 ; timing dependency -sim> att -e pt0 diag.bin -sim> br c2 -sim> boot pt0 - -Breakpoint: PC: 00C2 (EXBR R8,R6) - -sim> run 2d0 - -MODEL 8/16E PROCESSOR TEST PART 2 06-212R00 -CPU -* 8D - -SUBTEST - -* (type subtest number) - -Subtests 0, 1, 2, 5, 7, 8, 9 run correctly -Subtest 3, 4 cannot be run (initialization, power fail) -Subtest 6 cannot be run (hexadecimal display) - ---- -Series 16 CPU diagnostic, part 1 -(Central error routine is at 21F4) - -sim> set cpu 816e -sim> att -e pt0 diag.bin ; diagnostic -sim> br c0 -sim> boot pt0 - -Breakpoint, PC: 00C0 (8800) - -sim> d 234a 0202 ; patch to use -sim> d 234c a4a8 ; TTY as console -sim> d 17a b 1e4 -sim> run 100 - -SERIES SIXTEEN PROCESSOR TEST PART 1 06-242F01R00 -CPU -* 2D -ENTER 0 OR 1 -1 - -1234567890 - -NO ERROR - -000A 0000 - -CPU -* - ---- -16b memory diagnostic, part 1 - -sim> att -e pt0 diag.bin ; diagnostic -sim> br c2 -sim> boot pt0 - -Breakpoint, PC: 00C2 (EPSR R7,R6) - -sim> run 100 - -02-340 PART 1 06-162F01R01 - -NO ERRORS - ---- -16b memory diagnostic, part 2 - -sim> att -e pt0 diag.bin ; diagnostic -sim> br c2 -sim> boot pt0 - -Breakpoint, PC: 00C2 (EPSR R7,R6) - -sim> run 1000 - -02-340 PART 2 06-162F02R01 - -NO ERRORS - ---- -816e extended memory diagnostic, parts 1 and 2 - -sim> set cpu 816e -sim> set cpu 256k -sim> att -e pt0 diag.bin ; diagnostic -sim> br b4 -sim> boot pt0 - -Breakpoint, PC: 00B4 (LPSW R0,B8) - -sim> run 1000 - -8/16 E EXTENDED MEMORY TEST PART 1 06-221R00 -NO ERROR -* (CR to repeat part 1) -8/16 E EXTENDED MEMORY TEST PART 1 06-221R00 -NO ERROR -* (LF to go on to part 2) - -Breakpoint, PC: 00B4 (LPSW R0,B8) -sim> run 100 - -8/16 E EXTENDED MEMORY TEST PART 2 06-221R00 -PROGRAM DETECTED MAXIMUM MEMORY 3FFFE -*TEST ; standard tests -*RUN - -SUBTEST 0 NO ERROR -SUBTEST 1 NO ERROR -SUBTEST 2 NO ERROR -SUBTEST 3 NO ERROR -SUBTEST 4 NO ERROR -SUBTEST 6 NO ERROR -SUBTEST 7 NO ERROR -SUBTEST 8 NO ERROR -END OF TEST - -* - ---- -Series 16 selector channel diagnostic - -sim> set cpu 816e -sim> set cpu 256k -sim> att -e pt0 diag.bin ; diagnostic -sim> att mt0 foo.tap ; magtape to test -sim> br c0 -sim> boot pt0 - -Breakpoint, PC: 00C0 (LPSW R0,C8) - -sim> d 2e68 2 ; console is TTY -sim> run A00 - -S16 SELCH TEST 06-222 R01 - -TOP OF MEMORY 3 FFFF -* IODEV1 C5 ; magtape -* DEV1 2 -* RUN ; bank 0 by default -TEST 00 - -NO ERROR - -TEST 01 - -NO ERROR - -TEST 02 - -NO ERROR - -TEST 03 - -NO ERROR - -TEST 04 - -NO ERROR - - -* MEMMOD 1 {2,3} ; repeat for banks 1,2,3 -* RUN -TEST 00 - -NO ERROR - -TEST 01 - -NO ERROR - -TEST 02 - -NO ERROR - -TEST 03 - -NO ERROR - -TEST 04 - -NO ERROR - -* ---- -32b CPU diagnostic, part 1 - -sim> att -e mt0 mmd_r07.tap -sim> d -b 7f 7 ; file 8 on MMD R07 tape -sim> boot mt0 - -S32PT1 06-154 R03 -CPU - -*7X -NO ERROR -000A 0000 -* - ---- -32b CPU diagnostic, part 2 - -sim> set tt 7b ; test is parity sensitive -sim> att -e mt0 mmd_r07.tap -sim> d -b 7f 8 ; file 9 on MMD R07 tape -sim> boot mt0 - - -S32PT2R02 -CPU -* -7X -SUBTEST -* (type subtest number) - -Subtests 1, 3, 4, 5, 9 run correctly -Subtest 2 cannot be run (7/32 with halfword mode only) -Subtest 6 cannot be run (hexadecimal display) -Subtests 7,8 cannot be run (initialization, power fail) - ---- -32b CPU diagnostic, part 3 - -sim> att -e mt0 mmd_r07.tap -sim> d -b 7f 9 ; file 10 on MMD R07 tape -sim> boot mt0 - -S32PT3 R01 -CPU -* -8X ; 7X denotes 7/32 with halfword mode -MAC RESPONSE AT 000300 - -SUBTEST -* - -Subtests 1, 2, 3 run correctly -Subtest 4 cannot be run (parity option) - ---- -32b memory diagnostic, part 1 - -sim> att -e mt0 mmd_r07.tap -sim> d -b 7f 17 ; file 24 on MMD R07 tape -sim> br 2000 -sim> boot mt0 - -Breakpoint, PC: 02000 (B 2060) -sim> d -w 2010 0202 ; console is TTY -sim> c - -S32MT1 06-156F01R04 -MAC PRESENT ? (Y OR N) -* -Y -01 -02 -03 -04 -05 -06 -NO ERROR -* - ---- -32b memory diagnostic, part 2 - -sim> att -e mt0 c:\temp\mmd_r07.tap -sim> d -b 7f 18 ; file 25 on MMD R07 tape -sim> br a00 -sim> boot mt0 - -Breakpoint, PC: 00A00 (B A60) -sim> d -w a10 0202 ; console is TTY -sim> c - -S32MT2 06-156F02R04 -AVAILABLE MEMORY -000000 - 0FFFFF -SUBTEST * -0 ; all standard tests -01 -TEST STILL RUNNING ; repeated multiple times -: -NO ERROR -02 -TEST STILL RUNNING ; repeated multiple times -: -NO ERROR -03 -TEST STILL RUNNING ; repeated multiple times -: -NO ERROR -04 -TEST STILL RUNNING ; repeated multiple times -: -NO ERROR -05 -TEST STILL RUNNING ; repeated multiple times -: -NO ERROR -06 -TEST STILL RUNNING ; repeated multiple times -: -NO ERROR -07 -TEST STILL RUNNING ; repeated multiple times -: -NO ERROR -SUBTEST * - ---- -32b memory diagnostic, part 3 - -sim> att -e mt0 c:\temp\mmd_r07.tap -sim> d -b 7f 19 ; file 26 on MMD R07 tape -sim> br a00 -sim> boot mt0 - -Breakpoint, PC: 00A00 (B A60) -sim> d -w a10 0202 ; console is TTY - -sim> c -S32MT3 06-156F03R04 -AVAILABLE MEMORY -000000 - 0FFFFF -* - -TEST STILL RUNNING ; repeated multiple times -: -NO ERROR -* - ---- -32b memory diagnostic, 6a, part 1 - -sim> att -e mt0 c:\temp\mmd_r07.tap -sim> d -b 7f 15 ; file 22 on MMD R07 tape -sim> boot mt0 - -32 BIT S6A MEMORY TEST 06-157F01R01 -AVAILABLE MEMORY -0000-3FFF - -MAC ADDRESS = 300 -TYPE= 3 ; any value, 0-4 -SUBTEST -* 0 -01 -NO ERROR -02 -NO ERROR -03 -NO ERROR -04 -NO ERROR -05 -NO ERROR -06 -NO ERROR -07 -NO ERROR -08 -NO ERROR - -SUBTEST -* - ---- -32b memory diagnostic, 6a, part 2 - -sim> att -e mt0 c:\temp\mmd_r07.tap -sim> d -b 7f 16 ; file 23 on MMD R07 tape -sim> boot mt0 - -32 BIT S6A MEMORY TEST 06-157F02R01 -AVAILABLE MEMORY -0000f-FFFFF - -TYPE= 2 ; any value, 0-4 -SUBTEST -* 0 -01 -NO ERROR -02 -NO ERROR -03 -NO ERROR -04 -NO ERROR -05 -NO ERROR -06 -NO ERROR -07 -NO ERROR -08 -NO ERROR - -SUBTEST -* - ---- -32b MAC diagnostic, part 1 - -sim> att -e mt0 c:\temp\mmd_r07.tap -sim> d -b 7f 24 ; file 37 on MMD R07 tape -sim> boot mt0 - -MACT 06-160F01R03 -AVAILABLE MEMORY -00000- FFFFF - -* RUN -TEST 00 NO ERROR -TEST 01 NO ERROR -TEST 02 NO ERROR -TEST 03 NO ERROR -TEST 04 NO ERROR -TEST 05 NO ERROR -TEST 06 NO ERROR -TEST 07 NO ERROR -TEST 08 NO ERROR -TEST 09 NO ERROR -TEST 0B NO ERROR -* - ---- -sim> att -e mt0 c:\temp\mmd_r07.tap -sim> d -b 7f 25 ; file 38 on MMD R07 tape -sim> br ffd0 ; start != load point -sim> boot mt0 - -Breakpoint, PC: 0FFD0 (B 1093E) - -sim> run 10010 - -MACT 06-160F02R03 - -* RUN -TEST 00 NO ERROR -TEST 01 NO ERROR -TEST 02 NO ERROR -TEST 03 NO ERROR -TEST 04 NO ERROR -TEST 05 NO ERROR -TEST 06 NO ERROR -TEST 07 NO ERROR -TEST 08 NO ERROR -* - ---- -Common line printer diagnostic - -sim> att -e pt0 diag.bin -sim> br c2 -sim> boot pt0 - -Breakpoint: PC: 00C2 (EXBR R8,R6) - -sim> run a00 ; 32b -sim> run a04 ; 16b - -COMMON LINE PRINTER TEST 06-170R02 - -*TEST 0,1,2,3 -*RUN - -TEST 00 -NO ERROR -TEST 01 -NO ERROR -TEST 02 -NO ERROR -TEST 03 -NO ERROR -END OF TEST - -*INTRPT 1 -*RUN - -TEST 00 -NO ERROR -TEST 01 -NO ERROR -TEST 02 -NO ERROR -TEST 03 -NO ERROR -END OF TEST - -* - ---- -Common magtape diagnostic - -sim> att -e pt0 diag.bin -sim> att mt foo.tap -sim> br c4 -sim> boot pt0 - -Breakpoint, PC: 00C4 (EXBR R8,R6) - -sim> run a00 ; 32b -sim> run a04 ; 16b - -COMMON MAGNETIC TAPE TEST PROGRAM 06-172R02 - -*TEST 0,1,2,3,4,5 -*MODE 0 ; prog i/o and selch -*RUN - -TEST 00 -NO ERROR -TEST 01 -NO ERROR -TEST 02 -NO ERROR -TEST 03 -NO ERROR -TEST 04 -NO ERROR -TEST 05 -NO ERROR -END OF TEST - -* - ---- -Common 2.5/10MB disk diagnostic - -sim> att -e pt0 diag.bin -sim> br c2 -sim> boot pt0 - -Breakpoint, PC: 00C2 (EXBR R8,R6) - -sim> set dp0 5440 -sim> set dp1 5440 -sim> att dp0 test0.dsk -sim> att dp1 test1.dsk -sim> run a00 ; 32b -sim> run a04 ; 16b - -COMMON DISC TEST 06-173R01F01 - -*FILE 2 ; FILE 1 to test fixed platter -*LOCYL 0 -*HICYL 197 -*TIMCON 1C0 -*TEST 0,1,2,3,4,6,7,8,9,A,C ; test 5 requires format capability - ; test B requires manual intervention -*RUN - -TEST 00 -NO ERROR -TEST 01 -NO ERROR -TEST 02 -NO ERROR -TEST 03 -NO ERROR -TEST 04 -NO ERROR -TEST 06 -NO ERROR -TEST 07 -NO ERROR -TEST 08 -NO ERROR -TEST 09 -NO ERROR -TEST 0A -NO ERROR -TEST 0C -NO ERROR -END OF TEST - -* - ---- -32b MSM disk diagnostic - -sim> att -e mt0 c:\temp\mmd_r07.tap -sim> d -b 7f 45 ; file 70 on MMD R07 tape -sim> br a00 -sim> boot mt0 - -Breakpoint, PC: 00A00 (B A5E) - -sim> d -h a10 0202 ; patch for TTY console -sim> att dm0 foo.dsk -sim> att dm1 foo1.dsk -sim> c - -MSM DISC TEST 06-200F02R04 (32-BIT) - -*LOCYL 0 -*HICYL 336 ; tests 8,9,A will run a very long - ; time, use 40 to shorten test -*DRIVE 0 -*PACTYP 0 -*TIMVAL 14D -*XFILE 1 -*TEST 0,1,2,3,4,6,7,8,9,A,C ; test 5 requires format capability - ; test B requires manual intervention -*RUN - -TEST 00 -TEST 01 -TEST 02 -TEST 03 -TEST 04 -TEST 06 -TEST 07 -TEST 08 -TEST 09 -TEST 0A -TEST 0C - ---- -Common floppy disk diagnostic - -sim> att -e pt0 diag.bin -sim> att fd0 foo0.flp -sim> att fd1 foo1.flp -sim> br b8 -sim> boot pt0 - -Breakpoint, PC: 000B8 (BS B2) - -sim> d 2a72 bal r15,320a ; patch for multidrive test -sim> run a00 ; 32b -sim> run a04 ; 16b - -COMMON FLOPPY DISC TEST 06-198R00 -UNPROTECT DISKETTE - -*DRIVE AB -*RUN - -DRIVE A UNDER TEST -TEST 00 -NO ERROR -TEST 01 -NO ERROR -TEST 02 -NO ERROR -TEST 03 -NO ERROR -TEST 04 -NO ERROR -TEST 05 -NO ERROR -TEST 06 -NO ERROR -TEST 07 -NO ERROR -DRIVE B UNDER TEST -TEST 00 -NO ERROR -TEST 01 -NO ERROR -TEST 02 -NO ERROR -TEST 03 -NO ERROR -TEST 04 -NO ERROR -TEST 05 -NO ERROR -TEST 06 -NO ERROR -TEST 07 -NO ERROR -END OF TEST - -*TEST 9 ; test 8 requires formatting -*RUN - -TEST 09 -NO ERROR -END OF TEST - -* - ---- -Common clock diagnostic - -sim> att -e pt0 diag.bin -sim> br c4 -sim> boot pt0 - -Breakpoint, PC: 00C4 (EXBR R8,R6) - -sim> d -w e28 4300 ; R09 patches -sim> d -w e2a 10f4 -sim> id -w 10f4:110a -10f4: 4840 -10f6: 188a -10f8: 4850 -10fa: 188c -10fc: de40 -10fe: 1eaf -1100: de50 -1102: 1eaf -1104: 4810 -1106: 0a24 -1108: 4300 -1110: 0e2c -sim> d 1b9c bs 1ba6 -sim> d -w 1102 1eaf - -sim> run a00 ; 32b -sim> run a04 ; 16b - -COMMON UNIVERSAL CLOCK MODULE TEST 06-133R05 - -*TIMVAL 1A4 ; simulator is a fast CPU -*RUN - -TEST 00 -NO ERROR -TEST 01 -NO ERROR -TEST 02 -NO ERROR -TEST 03 -NO ERROR -TEST 04 -NO ERROR -TEST 05 -NO ERROR -TEST 06 -NO ERROR -TEST 07 -NO ERROR -END OF TEST - -* - -------------------------------------------------------------------- -Bugs Found and Fixed During Simulator Debug - -1. CPU16: instruction decoding interpreting CPU models incorrectly -2. CPU16: SINT should not be conditional on device existing -3. CPU16: immediate interrupts do not do a PSW swap, new PC is block+6 -4. CPU16: SLA, SLHA setting C incorrectly -5. CPU16: diagnostic requires 816E extended memory to run -6. CPU16: CCW16_OC defined incorrectly -7. CPU16, CPU32: autoload not fetching or outputing OC -8. CPU16, CPU32: block I/O completion is off by 1 -9. CPU16, CPU32: ESPR broken, EPSR rx,rx should copy PSW to rx -10. CPU16, CPU32: PCQ displays in octal instead of hexadecimal -11. CPU16, CPU32: SH and variations overflow calculation wrong -12. CPU16, CPU32: SCH overflow calculation wrong -13. CPU16, CPU32: CH and CLH overflow calculation wrong -14. CPU16, CPU32: CH or'ing into CC's instead of loading -15. CPU16, CPU32: RD, RH, SS, AI store some data on non-existent device -16. CPU16, CPU32: console interrupt not implemented -17. CPU16, CPU32: SRHL(s) setting C incorrectly -18. CPU16, CPU32: WDR, OCR not masking register data to 8b -19. CPU32: WH not masking data to 8b or 16b as required -20. CPU32: 32b register sets ordered incorrectly in memory -21. CPU32: wrong slot length in queue instructions -22. CPU32: display device missing its interrupt declaration -23. CPU32: LPSW(R) must load PC before changing PSW -24. CPU32: SLL setting C incorrectly -25. CPU32: bit instructions use halfword memory access and offsets -26. CPU32: CRC sign-extending rather than zero-extending operands -27. CPU32: SCP incrementing counts before, not after, transfer -28. CPU32: CHVR not implemented -29. CPU32: M(R) algorithm wrong -30. CPU32: M(R) using wrong register as first operand -31. CPU32: memory accesses were fullword rather than halfword aligned -32. CPU32: D(R) overflow calculation incorrect -33. CPU32: on 7/32, exceptions use register set 0, regardless of new PSW -34. CPU32: system queue PSW location misdefined -35. CPU32: autodriver channel not shifting bytes left before use as - translation table index -36. CPU32: MAC, LRA using wrong value for limit test -37. CPU32: LRA using wrong value for segment base -38. CPU32: MAC registers are accessible only if protection is off -39. CPU32: MAC status clears only on write, not read -40. CPU32: MAC write protect abort and interrupts implemented incorrectly -41. CPU32: ex/dep -v test used & instead of && -42. CPU32: fetch tests for MAC abort at end of fetch, not per halfword -43. FP: unpack and pack detecting RR format incorrectly -44. FP: need separate microcode/hardware algorithms for add/sub denormalization -45. FP: multiply and divide have 'early out' detection of overflow/underflow -46. FP: compare less than not setting C -47. FP: fix overflow not setting V -48. FP: fix shift needed to be hex digits not binary digits -49. IO: interrupt evaluation routine never sets an interrupt -50. SELCH: transfer count calculation off by 1 -51. SELCH: device data structure set up incorrectly (reset routine) -52. SELCH: stop clears pending interrupts -53. SELCH: register load algorithm incorrect for 6 byte loads -54. PT, LPT, FD: OR'ing status mask instead of AND'ing -55. PT, TT: SET_INT on status change not conditioned on interrupt armed -56. TT: input char converted to UC incorrectly -57. TT: need SET TT BREAK to run CPU test part 2 -58. LPT: not clearing spacing done -59. MT: WREOF not setting EOF status -60. MT: CMD register pointer to wrong place -61. MT: write record byte count taken from wrong variable -62. MT: overrun processing incorrect for selector channel mode -63. PIC, LFC: write data and overflow detection incorrect -64. PIC, LFC: interpolation algorithm for cic read incorrect -65. PIC, LFC: ric reloaded from output buffer on count overflow -66. PIC, LFC: added diagnostic mode, revised use of count vs timer -67. DP: track increment algorithm incorrect -68. DP, IDC: incorrectly setting overrun for less than full sector reads -69. DP: should interrupt on detach (offline) -70. FD: high water mark not updated on write -71. FD: deleted data not implemented, required for diagnostic -72. FD: header CRC not implemented, required for diagnostic -73. FD: function code not stored for service routine -74. FD: LRN to track and sector conversions incorrect -75. FD: reset status incorrect (should be not busy, LRN = 1) -76. FD: extended status track 0 calculation wrong -77. FD: reset does not clear interrupts, requires delay -78. FD: read/write sequencing incorrect -79. FD: command without write data uses implicit LRN -80. FD: extended status is per drive not per controller -81. FD: command start clears only extended status bytes 0,1 -82. FD: IDLE sets after BUSY drops and generates a separate interrupt -83. SYS16, SYS32: WH mistyped as WD in symbol table -84. SYS32: MHR, DHR misdefined -85. PAS: busy set instead of cleared initially -86. IDC: busy set instead of cleared initially -87. IDC, DP: busy not cleared at transfer command complete -88. IDC: busy is not cleared at drive command complete -89. IDC: for MSM compatibility, must absorb WH of head/cylinder -90. IDC: drive command 0x30 is an instant NOP -91. IDC: set cylinder with invalid cylinder sets SKI -92. IDC: read with invalid head sets ACF, not DTE -93. DP, IDC: write with cylinder overflow advanced selch pointer -94. MT: read error must stop selector channel (if active) -95. IDC: xx000000 to controller or drive are NOP's, not invalid commands -96. IDC: WD/WH use standard Interdata write pointers -97. SELCH: GO preserves EXA and SSTA -98. CPU: DH overflow checking broken - diff --git a/Interdata/id_dp.c b/Interdata/id_dp.c deleted file mode 100644 index 792c37e8..00000000 --- a/Interdata/id_dp.c +++ /dev/null @@ -1,629 +0,0 @@ -/* id_dp.c: Interdata 2.5MB/10MB cartridge disk simulator - - Copyright (c) 2001-2008, Robert M. Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - dp M46-421 2.5MB/10MB cartridge disk - - 18-Mar-05 RMS Added attached test to detach routine - 25-Jan-04 RMS Revised for device debug support - 25-Apr-03 RMS Revised for extended file support - 16-Feb-03 RMS Fixed read to test transfer ok before selch operation -*/ - -#include "id_defs.h" -#include - -#define DP_NUMBY 256 /* bytes/sector */ -#define DP_NUMSC 24 /* sectors/track */ - -#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */ -#define UNIT_M_DTYPE 0x1 -#define UNIT_V_AUTO (UNIT_V_UF + 2) /* autosize */ -#define UNIT_WLK (1 << UNIT_V_WLK) -#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE) -#define UNIT_AUTO (1 << UNIT_V_AUTO) -#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE) - -#define CYL u3 /* current cylinder */ -#define STD u4 /* drive status */ -#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ - -/* Controller status */ - -#define STC_OVR 0x80 /* overrun */ -#define STC_ACF 0x40 /* addr cmp fail */ -#define STC_DEF 0x20 /* def track NI */ -#define STC_CYO 0x10 /* cylinder ovflo */ -#define STC_IDL 0x02 /* ctrl idle */ -#define STC_DTE 0x01 /* xfer error */ -#define SETC_EX (STC_OVR|STC_ACF|STC_DEF|STC_CYO) -#define STC_MASK (STC_OVR|STC_ACF|STC_DEF|STC_CYO|STA_BSY|STC_IDL|STC_DTE) - -/* Controller command */ - -#define CMC_MASK 0xF -#define CMC_CLR 0x8 /* reset */ -#define CMC_RD 0x1 /* read */ -#define CMC_WR 0x2 /* write */ -#define CMC_RCHK 0x3 /* read check */ -#define CMC_RFMT 0x5 /* read fmt NI */ -#define CMC_WFMT 0x6 /* write fmt NI */ - -/* Drive status, ^ = dynamic, * = in unit status */ - -#define STD_WRP 0x80 /* ^write prot */ -#define STD_WCK 0x40 /* write check NI */ -#define STD_ILA 0x20 /* *illegal addr */ -#define STD_ILK 0x10 /* ^addr interlock */ -#define STD_MOV 0x08 /* *heads in motion */ -#define STD_INC 0x02 /* seek incomplete NI */ -#define STD_NRDY 0x01 /* ^not ready */ -#define STD_UST (STD_ILA | STD_MOV) /* set from unit */ -#define SETD_EX (STD_WCK | STD_ILA | STD_ILK) /* set examine */ - -/* Drive command */ - -#define CMD_SK 0x02 /* seek */ -#define CMD_RST 0x01 /* restore */ - -/* Head/sector register */ - -#define HS_SMASK 0x1F /* sector mask */ -#define HS_V_SRF 5 /* surface */ -#define HS_HMASK 0x20 /* head mask */ -#define HS_MASK (HS_HMASK | HS_SMASK) -#define GET_SEC(x) ((x) & HS_SMASK) -#define GET_SRF(x) (((x) & HS_HMASK) >> HS_V_SRF) - -#define GET_SA(p,cy,sf,sc,t) (((((((p)*drv_tab[t].cyl)+(cy))*drv_tab[t].surf)+(sf))* \ - DP_NUMSC)+(sc)) -#define GET_ROTATE(x) ((int) fmod (sim_gtime() / ((double) (x)), \ - ((double) DP_NUMSC))) - -/* This controller supports two different disk drive types: - - type #sectors/ #surfaces/ #cylinders/ - surface cylinder drive - - 2315 24 2 203 - 5440 24 4 408 - - In theory, each drive can be a different type. The size field in - each unit selects the drive capacity for each drive and thus the - drive type. DISKS MUST BE DECLARED IN ASCENDING SIZE AND MUST HAVE - THE SAME SECTORS/TRACK. -*/ - -#define TYPE_2315 0 -#define CYL_2315 203 -#define SURF_2315 2 -#define SIZE_2315 (DP_NUMSC * SURF_2315 * CYL_2315 * DP_NUMBY) - -#define TYPE_5440 1 -#define CYL_5440 408 -#define SURF_5440 2 -#define SIZE_5440 (2 * DP_NUMSC * SURF_5440 * CYL_5440 * DP_NUMBY) - -struct drvtyp { - int32 cyl; /* cylinders */ - uint32 surf; /* surfaces */ - uint32 size; /* #blocks */ - }; - -static struct drvtyp drv_tab[] = { - { CYL_2315, SURF_2315, SIZE_2315 }, - { CYL_5440, SURF_5440, SIZE_5440 }, - { 0 } - }; - -extern uint32 int_req[INTSZ], int_enb[INTSZ]; - -uint8 dpxb[DP_NUMBY]; /* xfer buffer */ -uint32 dp_bptr = 0; /* buffer ptr */ -uint32 dp_db = 0; /* ctrl buffer */ -uint32 dp_cyl = 0; /* drive buffer */ -uint32 dp_sta = 0; /* ctrl status */ -uint32 dp_cmd = 0; /* ctrl command */ -uint32 dp_plat = 0; /* platter */ -uint32 dp_hdsc = 0; /* head/sector */ -uint32 dp_svun = 0; /* most recent unit */ -uint32 dp_1st = 0; /* first byte */ -uint32 dpd_arm[DP_NUMDR] = { 0 }; /* drives armed */ -int32 dp_stime = 100; /* seek latency */ -int32 dp_rtime = 100; /* rotate latency */ -int32 dp_wtime = 1; /* word time */ -uint8 dp_tplte[(2 * DP_NUMDR) + 2]; /* fix/rmv + ctrl + end */ - -DEVICE dp_dev; -uint32 dp (uint32 dev, uint32 op, uint32 dat); -void dp_ini (t_bool dtpl); -t_stat dp_svc (UNIT *uptr); -t_stat dp_reset (DEVICE *dptr); -t_stat dp_attach (UNIT *uptr, char *cptr); -t_stat dp_detach (UNIT *uptr); -t_stat dp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat dp_rds (UNIT *uptr); -t_stat dp_wds (UNIT *uptr); -t_bool dp_dter (UNIT *uptr, uint32 first); -void dp_done (uint32 flg); - -extern t_stat id_dboot (int32 u, DEVICE *dptr); - -/* DP data structures - - dp_dev DP device descriptor - dp_unit DP unit list - dp_reg DP register list - dp_mod DP modifier list -*/ - -DIB dp_dib = { d_DPC, 0, v_DPC, dp_tplte, &dp, &dp_ini }; - -UNIT dp_unit[] = { - { UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+(TYPE_5440 << UNIT_V_DTYPE), SIZE_5440) }, - { UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+(TYPE_5440 << UNIT_V_DTYPE), SIZE_5440) }, - { UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+(TYPE_5440 << UNIT_V_DTYPE), SIZE_5440) }, - { UDATA (&dp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+(TYPE_5440 << UNIT_V_DTYPE), SIZE_5440) } - }; - -REG dp_reg[] = { - { HRDATA (CMD, dp_cmd, 3) }, - { HRDATA (STA, dp_sta, 8) }, - { HRDATA (BUF, dp_db, 8) }, - { HRDATA (PLAT, dp_plat, 1) }, - { HRDATA (HDSC, dp_hdsc, 6) }, - { HRDATA (CYL, dp_cyl, 9) }, - { HRDATA (SVUN, dp_svun, 8), REG_HIDDEN }, - { BRDATA (DBUF, dpxb, 16, 8, DP_NUMBY) }, - { HRDATA (DBPTR, dp_bptr, 9), REG_RO }, - { FLDATA (FIRST, dp_1st, 0) }, - { GRDATA (IREQ, int_req[l_DPC], 16, DP_NUMDR + 1, i_DPC) }, - { GRDATA (IENB, int_enb[l_DPC], 16, DP_NUMDR + 1, i_DPC) }, - { BRDATA (IARM, dpd_arm, 16, 1, DP_NUMDR) }, - { DRDATA (RTIME, dp_rtime, 0), PV_LEFT | REG_NZ }, - { DRDATA (STIME, dp_stime, 0), PV_LEFT | REG_NZ }, - { DRDATA (WTIME, dp_wtime, 0), PV_LEFT | REG_NZ }, - { URDATA (UCYL, dp_unit[0].CYL, 16, 9, 0, - DP_NUMDR, REG_RO) }, - { URDATA (UST, dp_unit[0].STD, 16, 8, 0, - DP_NUMDR, REG_RO) }, - { URDATA (CAPAC, dp_unit[0].capac, 10, T_ADDR_W, 0, - DP_NUMDR, PV_LEFT | REG_HRO) }, - { HRDATA (DEVNO, dp_dib.dno, 8), REG_HRO }, - { HRDATA (SELCH, dp_dib.sch, 2), REG_HRO }, - { NULL } - }; - -MTAB dp_mod[] = { - { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, - { (UNIT_DTYPE+UNIT_ATT), (TYPE_2315 << UNIT_V_DTYPE) + UNIT_ATT, - "2315", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (TYPE_5440 << UNIT_V_DTYPE) + UNIT_ATT, - "5440", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_2315 << UNIT_V_DTYPE), - "2315", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_5440 << UNIT_V_DTYPE), - "5440", NULL, NULL }, - { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL }, - { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_2315 << UNIT_V_DTYPE), - NULL, "2315", &dp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_5440 << UNIT_V_DTYPE), - NULL, "5440", &dp_set_size }, - { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", - &set_dev, &show_dev, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "SELCH", "SELCH", - &set_sch, &show_sch, NULL }, - { 0 } - }; - -DEVICE dp_dev = { - "DP", dp_unit, dp_reg, dp_mod, - DP_NUMDR, 16, 24, 1, 16, 8, - NULL, NULL, &dp_reset, - &id_dboot, &dp_attach, &dp_detach, - &dp_dib, DEV_DISABLE | DEV_DEBUG - }; - -/* Controller: IO routine */ - -uint32 dpc (uint32 dev, uint32 op, uint32 dat) -{ -uint32 f, t, u; -UNIT *uptr; -static uint8 good_cmd[8] = { 0, 1, 1, 1, 0, 0, 0, 0 }; - -switch (op) { /* case IO op */ - - case IO_ADR: /* select */ - sch_adr (dp_dib.sch, dev); /* inform sel ch */ - return BY; /* byte only */ - - case IO_RD: /* read data */ - if (dp_sta & STC_IDL) /* if idle */ - return GET_ROTATE (dp_rtime); /* return sector */ - else dp_sta = dp_sta | STA_BSY; /* xfr? set busy */ - return dp_db; /* return data */ - - case IO_WD: /* write data */ - if (DEBUG_PRS (dp_dev)) fprintf (sim_deb, - ">>DPC WD = %02X, STA = %02X\n", dat, dp_sta); - if (dp_sta & STC_IDL) /* idle? hdsc */ - dp_hdsc = dat & HS_MASK; - else { /* data xfer */ - dp_sta = dp_sta | STA_BSY; /* set busy */ - dp_db = dat & 0xFF; /* store data */ - } - break; - - case IO_SS: /* status */ - t = dp_sta & STC_MASK; /* get status */ - if (t & SETC_EX) /* test for EX */ - t = t | STA_EX; - return t; - - case IO_OC: /* command */ - if (DEBUG_PRS (dp_dev)) fprintf (sim_deb, - ">>DPC OC = %02X, STA = %02X\n", dat, dp_sta); - f = dat & CMC_MASK; /* get cmd */ - if (f & CMC_CLR) { /* clear? */ - dp_reset (&dp_dev); /* reset world */ - break; - } - u = (dp_svun - dp_dib.dno - o_DP0) / o_DP0; /* get unit */ - uptr = dp_dev.units + u; /* ignore if busy */ - if (!(dp_sta & STC_IDL) || sim_is_active (uptr)) - break; - dp_cmd = f; /* save cmd */ - if (dp_cmd == CMC_WR) /* write: bsy=0 else */ - dp_sta = 0; - else dp_sta = STA_BSY; /* bsy=1,idl,err=0 */ - dp_1st = 1; /* xfr not started */ - dp_bptr = 0; /* buffer empty */ - if (dp_svun & o_DPF) /* upper platter? */ - dp_plat = 1; - else dp_plat = 0; /* no, lower */ - if (good_cmd[f]) /* legal? sched */ - sim_activate (uptr, dp_rtime); - break; - } - -return 0; -} - -/* Drives: IO routine */ - -uint32 dp (uint32 dev, uint32 op, uint32 dat) -{ -int32 diff; -uint32 t, u; -UNIT *uptr; - -if (dev == dp_dib.dno) /* controller? */ - return dpc (dev, op, dat); -u = (dev - dp_dib.dno - o_DP0) / o_DP0; /* get unit num */ -uptr = dp_dev.units + u; /* get unit ptr */ -switch (op) { /* case IO op */ - - case IO_ADR: /* select */ - if (dp_sta & STC_IDL) /* idle? save unit */ - dp_svun = dev; - return BY; /* byte only */ - - case IO_WD: /* write data */ - if (DEBUG_PRS (dp_dev)) - fprintf (sim_deb, ">>DP%d WD = %02X, STA = %02X\n", - u, dat, dp_sta); - if (GET_DTYPE (uptr->flags) == TYPE_2315) /* 2.5MB drive? */ - dp_cyl = dat & 0xFF; /* cyl is 8b */ - else dp_cyl = ((dp_cyl << 8) | dat) & DMASK16; /* insert byte */ - break; - - case IO_SS: /* status */ - if (uptr->flags & UNIT_ATT) t = /* onl? */ - ((uptr->flags & UNIT_WPRT)? STD_WRP: 0) | - ((dp_sta & STC_IDL)? 0: STD_ILK) | - (uptr->STD & STD_UST); - else t = STD_MOV | STD_NRDY; /* off = X'09' */ - if (t & SETD_EX) /* test for ex */ - t = t | STA_EX; - return t; - - case IO_OC: /* command */ - if (DEBUG_PRS (dp_dev)) - fprintf (sim_deb, ">>DP%d OC = %02X, STA = %02X\n", - u, dat, dp_sta); - dpd_arm[u] = int_chg (v_DPC + u + 1, dat, dpd_arm[u]); - if (dat & CMD_SK) /* seek? get cyl */ - t = dp_cyl; - else if (dat & CMD_RST) /* rest? cyl 0 */ - t = 0; - else break; /* no action */ - diff = t - uptr->CYL; - if (diff < 0) /* ABS cyl diff */ - diff = -diff; - else if (diff == 0) /* must be nz */ - diff = 1; - uptr->STD = STD_MOV; /* stat = moving */ - uptr->CYL = t; /* put on cyl */ - sim_activate (uptr, diff * dp_stime); /* schedule */ - break; - } - -return 0; -} - -/* Unit service - - If seek done, on cylinder; - if read check, signal completion; - else, do read or write -*/ - -t_stat dp_svc (UNIT *uptr) -{ -uint32 u = uptr - dp_dev.units; /* get unit number */ -int32 cyl = uptr->CYL; /* get cylinder */ -uint32 dtype = GET_DTYPE (uptr->flags); /* get drive type */ -t_stat r; - -if (uptr->STD & STD_MOV) { /* seek? */ - uptr->STD = 0; /* clr seek in prog */ - if ((uptr->flags & UNIT_ATT) == 0) /* offl? hangs */ - return SCPE_OK; - if (cyl >= drv_tab[dtype].cyl) { /* bad cylinder? */ - uptr->STD = STD_ILA; /* error */ - uptr->CYL = drv_tab[dtype].cyl - 1; /* put at edge */ - } - if (dpd_arm[u]) /* req intr */ - SET_INT (v_DPC + u + 1); - return SCPE_OK; - } - -switch (dp_cmd & 0x7) { /* case on func */ - - case CMC_RCHK: /* read check */ - dp_dter (uptr, 1); /* check xfr err */ - break; - - case CMC_RD: /* read */ - if (sch_actv (dp_dib.sch, dp_dib.dno)) { /* sch transfer? */ - if (dp_dter (uptr, dp_1st)) /* check xfr err */ - return SCPE_OK; - if ((r = dp_rds (uptr))) /* read sec, err? */ - return r; - dp_1st = 0; - sch_wrmem (dp_dib.sch, dpxb, DP_NUMBY); /* write to memory */ - if (sch_actv (dp_dib.sch, dp_dib.dno)) { /* more to do? */ - sim_activate (uptr, dp_rtime); /* reschedule */ - return SCPE_OK; - } - break; /* no, set done */ - } - dp_sta = dp_sta | STC_DTE; /* can't work */ - break; - - case CMC_WR: /* write */ - if (sch_actv (dp_dib.sch, dp_dib.dno)) { /* sch transfer? */ - if (dp_dter (uptr, dp_1st)) /* check xfr err */ - return SCPE_OK; - dp_bptr = sch_rdmem (dp_dib.sch, dpxb, DP_NUMBY); /* read from mem */ - dp_db = dpxb[dp_bptr - 1]; /* last byte */ - if ((r = dp_wds (uptr))) /* write sec, err? */ - return r; - dp_1st = 0; - if (sch_actv (dp_dib.sch, dp_dib.dno)) { /* more to do? */ - sim_activate (uptr, dp_rtime); /* reschedule */ - return SCPE_OK; - } - break; /* no, set done */ - } - dp_sta = dp_sta | STC_DTE; /* can't work */ - break; - } /* end case func */ - -dp_done (0); /* done */ -return SCPE_OK; -} - -/* Read data sector */ - -t_stat dp_rds (UNIT *uptr) -{ -uint32 i; - -i = fxread (dpxb, sizeof (uint8), DP_NUMBY, uptr->fileref); -for ( ; i < DP_NUMBY; i++) /* fill with 0's */ - dpxb[i] = 0; -if (ferror (uptr->fileref)) { /* error? */ - perror ("DP I/O error"); - clearerr (uptr->fileref); - dp_done (STC_DTE); - return SCPE_IOERR; - } -return SCPE_OK; -} - -/* Write data sector */ - -t_stat dp_wds (UNIT *uptr) -{ -for ( ; dp_bptr < DP_NUMBY; dp_bptr++) - dpxb[dp_bptr] = dp_db; /* fill with last */ -fxwrite (dpxb, sizeof (uint8), DP_NUMBY, uptr->fileref); -if (ferror (uptr->fileref)) { /* error? */ - perror ("DP I/O error"); - clearerr (uptr->fileref); - dp_done (STC_DTE); - return SCPE_IOERR; - } -return SCPE_OK; -} - -/* Data transfer error test routine */ - -t_bool dp_dter (UNIT *uptr, uint32 first) -{ -uint32 hd, sc, sa; -uint32 dtype = GET_DTYPE (uptr->flags); /* get drive type */ - -if (((uptr->flags & UNIT_ATT) == 0) || /* not attached? */ - ((uptr->flags & UNIT_WPRT) && (dp_cmd == CMC_WR))) { - dp_done (STC_DTE); /* error, done */ - return TRUE; - } -hd = GET_SRF (dp_hdsc); /* get head */ -sc = GET_SEC (dp_hdsc); /* get sector */ -if (dp_cyl != (uint32) uptr->CYL) { /* wrong cylinder? */ - if (dp_cyl == 0) - uptr->CYL = 0; - else { - dp_done (STC_ACF); /* error, done */ - return TRUE; - } - } -if (sc >= DP_NUMSC) { /* bad sector? */ - dp_done (STC_OVR); /* error, done */ - return TRUE; - } -if (!first && (sc == 0) && (hd == 0)) { /* cyl overflow? */ - dp_done (STC_CYO); /* error, done */ - return TRUE; - } -sa = GET_SA (dp_plat, uptr->CYL, hd, sc, dtype); /* curr disk addr */ -fseek (uptr->fileref, sa * DP_NUMBY, SEEK_SET); -if ((sc + 1) < DP_NUMSC) /* end of track? */ - dp_hdsc = dp_hdsc + 1; -else dp_hdsc = (dp_hdsc ^ HS_HMASK) & HS_HMASK; /* sec 0, nxt srf */ -return FALSE; -} - -/* Data transfer done routine */ - -void dp_done (uint32 flg) -{ -dp_sta = (dp_sta | STC_IDL | flg) & ~STA_BSY; /* set flag, idle */ -SET_INT (v_DPC); /* unmaskable intr */ -if (flg) /* if err, stop ch */ - sch_stop (dp_dib.sch); -return; -} - -/* Reset routine */ - -t_stat dp_reset (DEVICE *dptr) -{ -uint32 u; -UNIT *uptr; - -dp_cmd = 0; /* clear cmd */ -dp_sta = STA_BSY | STC_IDL; /* idle, busy */ -dp_1st = 0; /* clear flag */ -dp_svun = dp_db = 0; /* clear unit, buf */ -dp_plat = 0; -dp_hdsc = 0; /* clear addr */ -CLR_INT (v_DPC); /* clear ctrl int */ -SET_ENB (v_DPC); /* always enabled */ -for (u = 0; u < DP_NUMDR; u++) { /* loop thru units */ - uptr = dp_dev.units + u; - uptr->CYL = uptr->STD = 0; - CLR_INT (v_DPC + u + 1); /* clear intr */ - CLR_ENB (v_DPC + u + 1); /* clear enable */ - dpd_arm[u] = 0; /* clear arm */ - sim_cancel (uptr); /* cancel activity */ - } -return SCPE_OK; -} - -/* Attach routine (with optional autosizing) */ - -t_stat dp_attach (UNIT *uptr, char *cptr) -{ -uint32 i, p; -t_stat r; - -uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size; -r = attach_unit (uptr, cptr); /* attach unit */ -if (r != SCPE_OK) /* error? */ - return r; -uptr->CYL = 0; -if ((uptr->flags & UNIT_AUTO) == 0) /* autosize? */ - return SCPE_OK; -if ((p = ftell (uptr->fileref)) == 0) - return SCPE_OK; -for (i = 0; drv_tab[i].surf != 0; i++) { - if (p <= drv_tab[i].size) { - uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE); - uptr->capac = drv_tab[i].size; - return SCPE_OK; - } - } -return SCPE_OK; -} - -/* Detach routine (generates an interrupt) */ - -t_stat dp_detach (UNIT *uptr) -{ -uint32 u = uptr - dp_dev.units; - -if (!(uptr->flags & UNIT_ATT)) /* attached? */ - return SCPE_OK; -if (dpd_arm[u]) /* if arm, intr */ - SET_INT (v_DPC + u + 1); -return detach_unit (uptr); -} - -/* Set size command validation routine */ - -t_stat dp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (uptr->flags & UNIT_ATT) - return SCPE_ALATT; -uptr->capac = drv_tab[GET_DTYPE (val)].size; -return SCPE_OK; -} - -/* Create device number (T) or interrupt (F) template */ - -void dp_ini (t_bool dtpl) -{ -int32 u, j, dev; - -dp_tplte[0] = 0; /* controller */ -for (u = 0, j = 1; u < DP_NUMDR; u++) { /* loop thru units */ - dev = (u + 1) * o_DP0; /* drive dev # */ - dp_tplte[j++] = dev; - if (dtpl && (GET_DTYPE (dp_unit[u].flags) == TYPE_5440)) - dp_tplte[j++] = dev + o_DPF; /* if fixed */ - } -dp_tplte[j] = TPL_END; /* end marker */ -return; -} diff --git a/Interdata/id_fd.c b/Interdata/id_fd.c deleted file mode 100644 index d4944394..00000000 --- a/Interdata/id_fd.c +++ /dev/null @@ -1,530 +0,0 @@ -/* id_fd.c: Interdata floppy disk simulator - - Copyright (c) 2001-2013, 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. - - fd M46-630 floppy disk - - 03-Sep-13 RMS Added explicit void * cast - 19-Mar-12 RMS Fixed macro naming conflict (Mark Pizzolato) - - A diskette consists of 77 tracks, each with 26 sectors of 128B. The - Interdata floppy uses a logical record numbering scheme from 1 to 2002. - Physical tracks are numbered 0-76, physical sectors 1-26. - - To allow for deleted data handling, a directory is appended to the end - of the image, one byte per LRN. Zero (the default) is a normal record, - non-zero a deleted record. -*/ - -#include "id_defs.h" - -#define FD_NUMTR 77 /* tracks/disk */ -#define FD_NUMSC 26 /* sectors/track */ -#define FD_NUMBY 128 /* bytes/sector */ -#define FD_NUMLRN (FD_NUMTR * FD_NUMSC) /* LRNs/disk */ -#define FD_SIZE (FD_NUMLRN * FD_NUMBY) /* bytes/disk */ -#define FD_NUMDR 4 /* drives/controller */ -#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 LRN u3 /* last LRN */ -#define FNC u4 /* last function */ -#define GET_DA(x) (((x) - 1) * FD_NUMBY) -#define GET_TRK(x) (((x) - 1) / FD_NUMSC) -#define GET_SEC(x) ((((x) - 1) % FD_NUMSC) + 1) -#define LRN_BOOT 5 /* boot block LRN */ - -/* Command byte */ - -#define CMD_V_UNIT 4 /* unit */ -#define CMD_M_UNIT 0x3 -#define GET_UNIT(x) (((x) >> CMD_V_UNIT) & CMD_M_UNIT) -#define CMD_V_FNC 0 /* function */ -#define CMD_M_FNC 0xF -#define GET_FNC(x) (((x) >> CMD_V_FNC) & CMD_M_FNC) -#define FNC_RD 0x1 /* read */ -#define FNC_WR 0x2 /* write */ -#define FNC_RDID 0x3 /* read ID */ -#define FNC_RSTA 0x4 /* read status */ -#define FNC_DEL 0x5 /* write deleted */ -#define FNC_BOOT 0x6 /* boot */ -#define FNC_STOP 0x7 /* stop */ -#define FNC_RESET 0x8 /* reset */ -#define FNC_FMT 0x9 /* format NI */ -#define FNC_STOPPING 0x10 /* stopping */ - -/* Status byte, * = dynamic */ - -#define STA_WRP 0x80 /* *write prot */ -#define STA_DEF 0x40 /* def track NI */ -#define STA_DLR 0x20 /* del record */ -#define STA_ERR 0x10 /* error */ -#define STA_IDL 0x02 /* idle */ -#define STA_OFL 0x01 /* fault */ -#define STA_MASK (STA_DEF|STA_DLR|STA_ERR|STA_BSY|STA_IDL) -#define SET_EX (STA_ERR) /* set EX */ - -/* Extended status, 6 bytes, * = dynamic */ - -#define ES_SIZE 6 -#define ES0_HCRC 0x80 /* ID CRC NI */ -#define ES0_DCRC 0x40 /* data CRC NI */ -#define ES0_LRN 0x20 /* illegal LRN */ -#define ES0_WRP 0x10 /* *write prot */ -#define ES0_ERR 0x08 /* error */ -#define ES0_DEF 0x04 /* def trk NI */ -#define ES0_DEL 0x02 /* del rec NI */ -#define ES0_FLT 0x01 /* fault */ -#define ES1_TK0 0x80 /* track 0 */ -#define ES1_NRDY 0x40 /* not ready */ -#define ES1_NOAM 0x20 /* no addr mk NI */ -#define ES1_CMD 0x10 /* illegal cmd */ -#define ES1_SKE 0x08 /* seek err NI */ -#define ES1_UNS 0x04 /* unsafe NI */ -#define ES1_UNIT 0x03 /* unit # */ - -/* Processing options for commands */ - -#define C_RD 0x1 /* cmd reads disk */ -#define C_WD 0x2 /* cmd writes disk */ - -extern uint32 int_req[INTSZ], int_enb[INTSZ]; - -uint32 fd_sta = 0; /* status */ -uint32 fd_cmd = 0; /* command */ -uint32 fd_db = 0; /* data buffer */ -uint32 fd_bptr = 0; /* buffer pointer */ -uint8 fdxb[FD_NUMBY] = { 0 }; /* sector buffer */ -uint8 fd_es[FD_NUMDR][ES_SIZE] = { {0} }; /* ext status */ -uint32 fd_lrn = 0; /* log rec # */ -uint32 fd_wdv = 0; /* wd valid */ -uint32 fd_stopioe = 1; /* stop on error */ -uint32 fd_arm = 0; /* intr arm */ -int32 fd_ctime = 100; /* command time */ -int32 fd_stime = 10; /* seek, per LRN */ -int32 fd_xtime = 1; /* tr set time */ - -static uint32 ctab[16] = { - 0, C_RD, C_WD, 0, /* 0, rd, wr, 0 */ - 0, C_WD, C_RD, 0, /* 0, del, boot, 0 */ - 0, 0, 0, 0, - 0, 0, 0, 0 - }; - -DEVICE fd_dev; -uint32 fd (uint32 dev, uint32 op, uint32 dat); -t_stat fd_svc (UNIT *uptr); -t_stat fd_reset (DEVICE *dptr); -t_stat fd_clr (DEVICE *dptr); -t_stat fd_boot (int32 unitno, DEVICE *dptr); -t_bool fd_dte (UNIT *uptr, t_bool wr); -uint32 fd_crc (uint32 crc, uint32 dat, uint32 cnt); -void fd_done (uint32 u, uint32 nsta, uint32 nes0, uint32 nes1); -void sched_seek (UNIT *uptr, int32 newlrn); - -/* FD data structures - - fd_dev FD device descriptor - fd_unit FD unit list - fd_reg FD register list - fd_mod FD modifier list -*/ - -DIB fd_dib = { d_FD, -1, v_FD, NULL, &fd, NULL }; - -UNIT fd_unit[] = { - { UDATA (&fd_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_BUFABLE+UNIT_MUSTBUF, FD_SIZE + FD_NUMLRN) }, - { UDATA (&fd_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_BUFABLE+UNIT_MUSTBUF, FD_SIZE + FD_NUMLRN) }, - { UDATA (&fd_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_BUFABLE+UNIT_MUSTBUF, FD_SIZE + FD_NUMLRN) }, - { UDATA (&fd_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_BUFABLE+UNIT_MUSTBUF, FD_SIZE + FD_NUMLRN) } - }; - -REG fd_reg[] = { - { HRDATA (CMD, fd_cmd, 8) }, - { HRDATA (STA, fd_sta, 8) }, - { HRDATA (BUF, fd_db, 8) }, - { HRDATA (LRN, fd_lrn, 16) }, - { BRDATA (ESTA, fd_es, 16, 8, ES_SIZE * FD_NUMDR) }, - { BRDATA (DBUF, fdxb, 16, 8, FD_NUMBY) }, - { HRDATA (DBPTR, fd_bptr, 8) }, - { FLDATA (WDV, fd_wdv, 0) }, - { FLDATA (IREQ, int_req[l_FD], i_FD) }, - { FLDATA (IENB, int_enb[l_FD], i_FD) }, - { FLDATA (IARM, fd_arm, 0) }, - { DRDATA (CTIME, fd_ctime, 24), PV_LEFT }, - { DRDATA (STIME, fd_stime, 24), PV_LEFT }, - { DRDATA (XTIME, fd_xtime, 24), PV_LEFT }, - { FLDATA (STOP_IOE, fd_stopioe, 0) }, - { URDATA (ULRN, fd_unit[0].LRN, 16, 16, 0, FD_NUMDR, REG_HRO) }, - { URDATA (UFNC, fd_unit[0].FNC, 16, 8, 0, FD_NUMDR, REG_HRO) }, - { HRDATA (DEVNO, fd_dib.dno, 8), REG_HRO }, - { NULL } - }; - -MTAB fd_mod[] = { - { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, - { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", - &set_dev, &show_dev, NULL }, - { 0 } - }; - -DEVICE fd_dev = { - "FD", fd_unit, fd_reg, fd_mod, - FD_NUMDR, 16, 20, 1, 16, 8, - NULL, NULL, &fd_reset, - &fd_boot, NULL, NULL, - &fd_dib, DEV_DISABLE - }; - -/* Floppy disk: IO routine */ - -uint32 fd (uint32 dev, uint32 op, uint32 dat) -{ -int32 u, t, fnc; -UNIT *uptr; - -fnc = GET_FNC (fd_cmd); /* get fnc */ -u = GET_UNIT (fd_cmd); /* get unit */ -uptr = fd_dev.units + u; -switch (op) { /* case IO op */ - case IO_ADR: /* select */ - return BY; /* byte only */ - - case IO_RD: /* read */ - if (fd_sta & (STA_IDL | STA_BSY)) /* idle, busy? */ - return fd_db; - if (fd_bptr < FD_NUMBY) /* get byte */ - fd_db = fdxb[fd_bptr++]; - if (fd_bptr >= FD_NUMBY) { /* buf end? */ - if (ctab[fnc] & C_RD) { /* disk read? */ - sched_seek (uptr, uptr->LRN + 1); /* sched read */ - fd_sta = fd_sta | STA_BSY; /* set busy */ - } - else fd_bptr = 0; /* just wrap */ - } - if ((ctab[fnc] & C_RD) && fd_arm) /* if rd & arm, */ - SET_INT (v_FD); /* interrupt */ - return fd_db; /* return buf */ - - case IO_WD: /* write */ - if (fd_sta & STA_IDL) { /* idle? */ - fd_lrn = ((fd_lrn << 8) | dat) & DMASK16; /* insert byte */ - fd_wdv = 1; - break; - } - if (fd_bptr < FD_NUMBY) /* if room, */ - fdxb[fd_bptr++] = fd_db = dat; /* store byte */ - if (fd_bptr >= FD_NUMBY) { /* buf end? */ - if (ctab[fnc] & C_WD) { /* disk write? */ - sched_seek (uptr, uptr->LRN + 1); /* sched write */ - fd_sta = fd_sta | STA_BSY; /* set busy */ - } - else fd_bptr = 0; /* just wrap */ - } - if ((ctab[fnc] & C_WD) && fd_arm) /* if wr & arm, */ - SET_INT (v_FD); /* interrupt */ - break; - - case IO_SS: /* status */ - t = fd_sta & STA_MASK; /* get status */ - if ((uptr->flags & UNIT_ATT) == 0) - t = t | STA_DU; - if (t & SET_EX) /* test for ex */ - t = t | STA_EX; - return t; - - case IO_OC: /* command */ - fd_arm = int_chg (v_FD, dat, fd_arm); /* upd int ctrl */ - fnc = GET_FNC (dat); /* new fnc */ - fd_cmd = dat; /* save cmd */ - u = GET_UNIT (dat); /* get unit */ - uptr = fd_dev.units + u; - if (fnc == FNC_STOP) { /* stop? */ - uptr->FNC = uptr->FNC | FNC_STOPPING; /* flag stop */ - if (sim_is_active (uptr)) /* busy? cont */ - break; - if (ctab[GET_FNC (uptr->FNC)] & C_WD) { /* write? */ - sched_seek (uptr, uptr->LRN + 1); /* sched write */ - fd_sta = fd_sta | STA_BSY; /* set busy */ - } - else fd_done (u, 0, 0, 0); /* nrml done */ - break; - } - else if (fd_sta & STA_IDL) { /* must be idle */ - if (fnc != FNC_RSTA) { /* !rd status */ - fd_sta = STA_BSY; /* busy, !idle */ - fd_es[u][0] = 0; - fd_es[u][1] = u; /* init ext sta */ - } - else fd_sta = (fd_sta & ~STA_IDL) | STA_BSY; - if (fnc == FNC_BOOT) /* boot? fixed sec */ - t = LRN_BOOT; - else if (fd_wdv) /* valid data? use */ - t = fd_lrn; - else t = uptr->LRN; /* use prev */ - fd_wdv = 0; /* data invalid */ - fd_bptr = 0; /* init buffer */ - uptr->FNC = fnc; /* save function */ - uptr->LRN = t; /* save LRN */ - if (ctab[fnc] & C_RD) /* seek now? */ - sched_seek (uptr, t); - else sim_activate (uptr, fd_ctime); /* start cmd */ - } - break; - } - -return 0; -} - -/* Unit service; the action to be taken depends on command */ - -t_stat fd_svc (UNIT *uptr) -{ -uint32 i, u, tk, sc, crc, fnc, da; -uint8 *fbuf = (uint8 *) uptr->filebuf; - -u = uptr - fd_dev.units; /* get unit number */ -fnc = GET_FNC (uptr->FNC); /* get function */ -switch (fnc) { /* case on function */ - - case FNC_RESET: /* reset */ - fd_clr (&fd_dev); /* clear device */ - fd_done (u, 0, 0, 0); /* set idle */ - return SCPE_OK; - - case FNC_STOP: /* stop */ - fd_done (u, 0, 0, 0); /* set idle */ - return SCPE_OK; - - case FNC_BOOT: /* boot, buf empty */ - case FNC_RD: /* read, buf empty */ - if (uptr->FNC & FNC_STOPPING) /* stopped? */ - break; - if (fd_dte (uptr, FALSE)) /* xfr error? */ - return SCPE_OK; - da = GET_DA (uptr->LRN); /* get disk addr */ - for (i = 0; i < FD_NUMBY; i++) /* read sector */ - fdxb[i] = fbuf[da + i]; - if (fbuf[FD_SIZE + uptr->LRN - 1]) { /* deleted? set err */ - fd_sta = fd_sta | STA_DLR; - fd_es[u][0] = fd_es[u][0] | ES0_DEL; - } - fd_es[u][2] = GET_SEC (uptr->LRN); /* set ext sec/trk */ - fd_es[u][3] = GET_TRK (uptr->LRN); - fd_bptr = 0; /* init buf */ - uptr->LRN = uptr->LRN + 1; /* next block */ - break; - - case FNC_WR: case FNC_DEL: /* write block */ - if (fd_dte (uptr, TRUE)) /* xfr error? */ - return SCPE_OK; - if (fd_bptr) { /* any transfer? */ - da = GET_DA (uptr->LRN); /* get disk addr */ - for (i = fd_bptr; i < FD_NUMBY; i++) /* pad sector */ - fdxb[i] = fd_db; - for (i = 0; i < FD_NUMBY; i++) /* write sector */ - fbuf[da + i] = fdxb[i]; /* then dir */ - fbuf[FD_SIZE + uptr->LRN - 1] = ((fnc == FNC_DEL)? 1: 0); - uptr->hwmark = uptr->capac; /* rewrite all */ - fd_es[u][2] = GET_SEC (uptr->LRN); /* set ext sec/trk */ - fd_es[u][3] = GET_TRK (uptr->LRN); - fd_bptr = 0; /* init buf */ - uptr->LRN = uptr->LRN + 1; /* next block */ - } - break; - - case FNC_RSTA: /* read status */ - if (uptr->flags & UNIT_WPRT) /* wr protected? */ - fd_es[u][0] = fd_es[u][0] | ES0_WRP; - if (GET_TRK (uptr->LRN) == 0) /* on track 0? */ - fd_es[u][1] = fd_es[u][1] | ES1_TK0; - if ((uptr->flags & UNIT_BUF) == 0) { /* not attached? */ - fd_es[u][0] = fd_es[u][0] | ES0_FLT; /* set err */ - fd_es[u][1] = fd_es[u][1] | ES1_NRDY; - } - for (i = 0; i < ES_SIZE; i++) /* copy to buf */ - fdxb[i] = fd_es[u][i]; - for (i = ES_SIZE; i < FD_NUMBY; i++) - fdxb[i] = 0; - break; - - case FNC_RDID: /* read ID */ - if ((uptr->flags & UNIT_BUF) == 0) { /* not attached? */ - fd_done (u, STA_ERR, ES0_ERR | ES0_FLT, ES1_NRDY); - return SCPE_OK; - } - for (i = 0; i < FD_NUMBY; i++) fdxb[i] = 0; /* clr buf */ - tk = GET_TRK (uptr->LRN); /* get track */ - sc = GET_SEC (uptr->LRN); /* get sector */ - fdxb[0] = tk & 0xFF; /* store track */ - fdxb[2] = sc & 0xFF; /* store sector */ - crc = fd_crc (0xFFFF, 0xFE00, 8); /* CRC addr mark */ - crc = fd_crc (crc, tk << 8, 16); /* CRC track */ - crc = fd_crc (crc, sc << 8, 16); /* CRC sector */ - fdxb[4] = (crc >> 8) & 0xFF; /* store CRC */ - fdxb[5] = crc & 0xFF; - break; - - case FNC_FMT: /* format */ - default: - fd_done (u, STA_ERR, ES0_ERR, ES1_CMD); /* ill cmd */ - uptr->LRN = 1; /* on track 0 */ - return SCPE_OK; - } - -if (uptr->FNC & FNC_STOPPING) { /* stopping? */ - uptr->FNC = FNC_STOP; /* fnc = STOP */ - sim_activate (uptr, fd_ctime); /* schedule */ - } -fd_sta = fd_sta & ~STA_BSY; /* clear busy */ -if (fd_arm) /* if armed, int */ - SET_INT (v_FD); -return SCPE_OK; -} - -/* Schedule seek */ - -void sched_seek (UNIT *uptr, int32 newlrn) -{ -int32 diff = newlrn - uptr->LRN; /* LRN diff */ - -if (diff < 0) /* ABS */ - diff = -diff; -if (diff < 10) - diff = 10; /* MIN 10 */ -sim_activate (uptr, diff * fd_stime); /* schedule */ -return; -} - -/* Command complete */ - -void fd_done (uint32 u, uint32 nsta, uint32 nes0, uint32 nes1) -{ -fd_sta = (fd_sta | STA_IDL | nsta) & ~STA_BSY; /* set idle */ -if (fd_arm) /* if armed, int */ - SET_INT (v_FD); -fd_es[u][0] = fd_es[u][0] | nes0; /* set ext state */ -fd_es[u][1] = fd_es[u][1] | nes1; -return; -} - -/* Test for data transfer error */ - -t_bool fd_dte (UNIT *uptr, t_bool wr) -{ -uint32 u = uptr - fd_dev.units; - -if ((uptr->flags & UNIT_BUF) == 0) { /* not attached? */ - fd_done (u, STA_ERR, ES0_ERR | ES0_FLT, ES1_NRDY); - return TRUE; - } -if (wr && (uptr->flags & UNIT_WPRT)) { /* wr protected? */ - fd_done (u, STA_ERR, ES0_ERR | ES0_WRP, 0); - return TRUE; - } -if ((uptr->LRN == 0) || (uptr->LRN > FD_NUMLRN)) { /* bad LRN? */ - fd_done (u, STA_ERR, ES0_ERR | ES0_LRN, 0); - return TRUE; - } -return FALSE; -} - -/* Header CRC calculation */ - -uint32 fd_crc (uint32 crc, uint32 dat, uint32 cnt) -{ -uint32 i, wrk; - -for (i = 0; i < cnt; i++) { - wrk = crc ^ dat; - crc = (crc << 1) & DMASK16; - if (wrk & SIGN16) - crc = ((crc ^ 0x1020) + 1) & DMASK16; - dat = (dat << 1) & DMASK16; - } -return crc; -} - -/* Reset routine */ - -t_stat fd_clr (DEVICE *dptr) -{ -int32 i, j; -UNIT *uptr; - -fd_sta = STA_IDL; /* idle */ -fd_cmd = 0; /* clear state */ -fd_db = 0; -fd_bptr = 0; -fd_lrn = 1; -fd_wdv = 0; -for (i = 0; i < FD_NUMBY; i++) fdxb[i] = 0; /* clr xfr buf */ -for (i = 0; i < FD_NUMDR; i++) { /* loop thru units */ - for (j = 0; j < ES_SIZE; j++) fd_es[i][j] = 0; /* clr ext sta */ - fd_es[i][2] = 1; /* sector 1 */ - uptr = fd_dev.units + i; - sim_cancel (uptr); /* stop drive */ - uptr->LRN = 1; /* clear state */ - uptr->FNC = 0; - } -return SCPE_OK; -} - -t_stat fd_reset (DEVICE *dptr) -{ -CLR_INT (v_FD); /* clear int */ -CLR_ENB (v_FD); /* disable int */ -fd_arm = 0; /* disarm int */ -return fd_clr (dptr);; -} - -/* Bootstrap routine */ - -#define BOOT_START 0x50 -#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint8)) - -static uint8 boot_rom[] = { - 0xD5, 0x00, 0x00, 0xCF, /* ST: AL CF */ - 0x43, 0x00, 0x00, 0x80 /* BR 80 */ - }; - -t_stat fd_boot (int32 unitno, DEVICE *dptr) -{ -extern uint32 PC, dec_flgs; -extern uint16 decrom[]; - -if (decrom[0xD5] & dec_flgs) /* AL defined? */ - return SCPE_NOFNC; -IOWriteBlk (BOOT_START, BOOT_LEN, boot_rom); /* copy boot */ -IOWriteB (AL_DEV, fd_dib.dno); /* set dev no */ -IOWriteB (AL_IOC, 0x86 + (unitno << CMD_V_UNIT)); /* set dev cmd, unit num */ -IOWriteB (AL_SCH, 0); /* clr sch dev no */ -PC = BOOT_START; -return SCPE_OK; -} diff --git a/Interdata/id_fp.c b/Interdata/id_fp.c deleted file mode 100644 index b9cf028a..00000000 --- a/Interdata/id_fp.c +++ /dev/null @@ -1,546 +0,0 @@ -/* id_fp.c: Interdata floating point instructions - - Copyright (c) 2000-2008, 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 uses IBM 360 floating point format: - - 0 7 8 15 23 31 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |S| exponent | fraction | :single - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - | fraction low | :double - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - where S = 0 for plus, 1 for minus - exponent = 16**n, in excess 64 code - fraction = .hhhhhh, seen as 6-14 hexadecimal digits - - Numbers can be normalized or unnormalized but are always normalized - when loaded. - - Interdata has 8 floating point registers, F0, F2, ... , FE. In floating - point instructions, the low order bit of the register number 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. - - Interdata has both 32b only and 32b/64b floating point implementations. - In 32b only implementations, add and subtract are truncated, but multiply - and divide are rounded, and the floating point registers are kept in - memory. In 64b implementations, all single precision precision operations - are rounded, double precision operations are truncated, and the floating - point registers are kept in separate hardware arrays. -*/ - -#include "id_defs.h" - -struct ufp { /* unpacked fp */ - int32 sign; /* sign */ - int32 exp; /* unbiased exp */ - uint32 h; /* fr high */ - uint32 l; /* 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_GETFRL(x) (x) - -#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 - -/* Double precision fraction add/subtract/compare */ - -#define FR_ADD(d,s) d.l = (d.l + s.l) & DMASK32; \ - d.h = (d.h + s.h + (d.l < s.l)) & DMASK32 - -#define FR_SUB(d,s) d.h = (d.h - s.h - (d.l < s.l)) & DMASK32; \ - d.l = (d.l - s.l) & DMASK32 - -#define FR_GE(s1,s2) ((s1.h > s2.h) || \ - ((s1.h == s2.h) && (s1.l >= s2.l))) - -/* Variable and constant shifts; for constants, 0 < k < 32 */ - -#define FR_RSH_V(v,s) if ((s) < 32) { \ - v.l = ((v.l >> (s)) | \ - (v.h << (32 - (s)))) & DMASK32; \ - v.h = (v.h >> (s)) & DMASK32; \ - } \ - else { \ - v.l = v.h >> ((s) - 32); \ - v.h = 0; \ - } - -#define FR_RSH_K(v,s) v.l = ((v.l >> (s)) | \ - (v.h << (32 - (s)))) & DMASK32; \ - v.h = (v.h >> (s)) & DMASK32 - -#define FR_LSH_K(v,s) v.h = ((v.h << (s)) | \ - (v.l >> (32 - (s)))) & DMASK32; \ - v.l = (v.l << (s)) & DMASK32 - -#define Q_RND(op) (OP_DPFP (op) == 0) -#define Q_RND_AS(op) ((OP_DPFP (op) == 0) && fp_in_hwre) - -extern uint32 *R; -extern uint32 F[8]; -extern dpr_t D[8]; -extern uint16 decrom[]; -extern uint32 fp_in_hwre; -extern uint32 ReadF (uint32 loc, uint32 rel); -extern void WriteF (uint32 loc, uint32 dat, uint32 rel); -void ReadFP2 (struct ufp *fop, uint32 op, uint32 r2, uint32 ea); -void UnpackFPR (struct ufp *fop, uint32 op, uint32 r1); -void NormUFP (struct ufp *fop); -uint32 StoreFPR (struct ufp *fop, uint32 op, uint32 r1, uint32 rnd); -uint32 StoreFPX (struct ufp *fop, uint32 op, uint32 r1); - -/* Floating point load */ - -uint32 f_l (uint32 op, uint32 r1, uint32 r2, uint32 ea) -{ -struct ufp fop2; - -ReadFP2 (&fop2, op, r2, ea); /* get op, normalize */ -return StoreFPR (&fop2, op, r1, 0); /* store, chk unflo */ -} - -/* Floating point compare */ - -uint32 f_c (uint32 op, uint32 r1, uint32 r2, uint32 ea) -{ -struct ufp fop1, fop2; - -ReadFP2 (&fop2, op, r2, ea); /* get op2, norm */ -UnpackFPR (&fop1, op, r1); /* get op1, norm */ -if (fop1.sign ^ fop2.sign) /* signs differ? */ - return (fop2.sign? CC_G: (CC_C | CC_L)); -if (fop1.exp != fop2.exp) /* exps differ? */ - return (((fop1.exp > fop2.exp) ^ fop1.sign)? CC_G: (CC_C | CC_L)); -if (fop1.h != fop2.h) /* hi fracs differ? */ - return (((fop1.h > fop2.h) ^ fop1.sign)? CC_G: (CC_C | CC_L)); -if (OP_DPFP (op) && (fop1.l != fop2.l)) /* dp: low fracs diff? */ - return (((fop1.l > fop2.l) ^ fop1.sign)? CC_G: (CC_C | CC_L)); -return 0; -} - -/* Floating to integer conversion */ - -uint32 f_fix (uint32 op, uint32 r1, uint32 r2) /* 16b */ -{ -struct ufp res; -uint32 cc; - -UnpackFPR (&res, op, r2); /* get op2, norm */ -if ((res.h == 0) || (res.exp < 0x41)) { /* result zero? */ - R[r1] = 0; - return 0; - } -if ((res.exp > 0x44) || /* result too big? */ - ((res.exp == 0x44) && (res.h >= 0x00800000))) { - res.h = MMASK16; - cc = CC_V; - } -else { - res.h = res.h >> ((0x46 - res.exp) * 4); /* right align frac */ - cc = 0; - } -if (res.sign) { - R[r1] = ((res.h ^ DMASK16) + 1) & DMASK16; /* negate result */ - return cc | CC_L; - } -R[r1] = res.h & DMASK16; -return cc | CC_G; -} - -uint32 f_fix32 (uint32 op, uint32 r1, uint32 r2) /* 32b */ -{ -struct ufp res; -uint32 cc; - -UnpackFPR (&res, op, r2); /* get op2, norm */ -if ((res.h == 0) || (res.exp < 0x41)) { /* result zero? */ - R[r1] = 0; - return 0; - } -if ((res.exp > 0x48) || /* result too big? */ - ((res.exp == 0x48) && (res.h >= 0x00800000))) { - res.h = MMASK32; - cc = CC_V; - } -else { - FR_LSH_K (res, 8); /* get all in 32b */ - res.h = res.h >> ((0x48 - res.exp) * 4); /* right align frac */ - cc = 0; - } -if (res.sign) { - R[r1] = (res.h ^ DMASK32) + 1; /* negate result */ - return cc | CC_L; - } -R[r1] = res.h; -return cc | CC_G; -} - -/* Integer to floating conversion */ - -uint32 f_flt (uint32 op, uint32 r1, uint32 r2) /* 16b */ -{ -struct ufp res = { 0, 0x44, 0, 0 }; /* +, 16**4 */ -uint32 cc; - -if (R[r2] == 0) /* zero arg? */ - cc = 0; -else if (R[r2] & SIGN16) { /* neg arg? */ - res.sign = FP_M_SIGN; /* set sign */ - res.h = ((~R[r2] + 1) & DMASK16) << 8; /* get magnitude */ - cc = CC_L; - } -else { - res.h = R[r2] << 8; /* pos nz arg */ - cc = CC_G; - } -NormUFP (&res); /* normalize */ -StoreFPR (&res, op, r1, 0); /* store result */ -return cc; -} - -uint32 f_flt32 (uint32 op, uint32 r1, uint32 r2) /* 32b */ -{ -struct ufp res = { 0, 0x48, 0, 0 }; /* +, 16**8 */ -uint32 cc, t; - -t = R[r2]; /* int op */ -if (t) { /* nonzero arg? */ - if (t & SIGN32) { /* neg arg? */ - res.sign = FP_M_SIGN; /* set sign */ - t = (~t + 1) & DMASK32; /* get magnitude */ - cc = CC_L; - } - else cc = CC_G; /* pos nz arg */ - res.h = t >> 8; /* hi frac */ - res.l = t << 24; /* lo frac */ - } -else cc = 0; /* zero arg */ -NormUFP (&res); /* normalize */ -StoreFPR (&res, op, r1, 0); /* store result */ -return cc; -} - -/* Floating point add/subtract */ - -uint32 f_as (uint32 op, uint32 r1, uint32 r2, uint32 ea) -{ -struct ufp fop1, fop2, t; -int32 ediff; - -ReadFP2 (&fop2, op, r2, ea); /* get op2, norm */ -UnpackFPR (&fop1, op, r1); /* get op1, norm */ -if (op & 1) /* if sub, inv sign2 */ - fop2.sign = fop2.sign ^ 1; -if (fop1.h == 0) /* if op1 = 0, res = op2 */ - fop1 = fop2; -else if (fop2.h != 0) { /* if op2 = 0, no add */ - if ((fop1.exp < fop2.exp) || /* |op1| < |op2|? */ - ((fop1.exp == fop2.exp) && - ((fop1.h < fop2.h) || - ((fop1.h == fop2.h) && (fop1.l < fop2.l))))) { - t = fop2; /* swap operands */ - fop2 = fop1; - fop1 = t; - } - ediff = fop1.exp - fop2.exp; /* exp difference */ - if (OP_DPFP (op) || fp_in_hwre) { /* dbl prec or hwre? */ - if (ediff >= 14) /* diff too big? */ - fop2.h = fop2.l = 0; - else if (ediff) { /* any difference? */ - FR_RSH_V (fop2, ediff * 4); /* shift frac */ - } - } - else { /* sgl prec ucode */ - if (ediff >= 6) /* diff too big? */ - fop2.h = 0; - else if (ediff) /* any difference? */ - fop2.h = fop2.h >> (ediff * 4); /* shift frac */ - } - if (fop1.sign ^ fop2.sign) { /* eff subtract */ - FR_SUB (fop1, fop2); /* sub fractions */ - NormUFP (&fop1); /* normalize result */ - } - else { - FR_ADD (fop1, fop2); /* add fractions */ - if (fop1.h & FP_CARRY) { /* carry out? */ - FR_RSH_K (fop1, 4); /* renormalize */ - fop1.exp = fop1.exp + 1; /* incr exp */ - } - } - } /* end if fop2 */ -return StoreFPR (&fop1, op, r1, Q_RND_AS (op)); /* store result */ -} - -/* Floating point multiply - - Notes: - - Exponent overflow/underflow is tested right after the exponent - add, without regard to potential changes due to normalization - - Exponent underflow is tested right after normalization, without - regard to changes due to rounding - - Single precision hardware multiply may generate up to 48b - - Double precision multiply generates 56b with no guard bits -*/ - -int32 f_m (uint32 op, uint32 r1, uint32 r2, uint32 ea) -{ -struct ufp fop1, fop2; -struct ufp res = { 0, 0, 0, 0 }; -uint32 i; - -ReadFP2 (&fop2, op, r2, ea); /* get op2, norm */ -UnpackFPR (&fop1, op, r1); /* get op1, norm */ -if (fop1.h && fop2.h) { /* if both != 0 */ - res.sign = fop1.sign ^ fop2.sign; /* sign = diff */ - res.exp = fop1.exp + fop2.exp - FP_BIAS; /* exp = sum */ - if ((res.exp < 0) || (res.exp > FP_M_EXP)) /* ovf/undf? */ - return StoreFPX (&res, op, r1); /* early out */ - if ((fop1.l | fop2.l) == 0) { /* 24b x 24b? */ - for (i = 0; i < 24; i++) { /* 24 iterations */ - if (fop2.h & 1) /* add hi only */ - res.h = res.h + fop1.h; - FR_RSH_K (res, 1); /* shift dp res */ - fop2.h = fop2.h >> 1; - } - } - else { /* some low 0's */ - if (fop2.l != 0) { /* 56b x 56b? */ - for (i = 0; i < 32; i++) { /* do low 32b */ - if (fop2.l & 1) { - FR_ADD (res, fop1); - } - FR_RSH_K (res, 1); - fop2.l = fop2.l >> 1; - } - } - for (i = 0; i < 24; i++) { /* do hi 24b */ - if (fop2.h & 1) { - FR_ADD (res, fop1); - } - FR_RSH_K (res, 1); - fop2.h = fop2.h >> 1; - } - } - NormUFP (&res); /* normalize */ - if (res.exp < 0) /* underflow? */ - return StoreFPX (&res, op, r1); /* early out */ - } -return StoreFPR (&res, op, r1, Q_RND (op)); /* store */ -} - -/* Floating point divide - see overflow/underflow notes for multiply */ - -int32 f_d (uint32 op, uint32 r1, uint32 r2, uint32 ea) -{ -struct ufp fop1, fop2; -struct ufp quo = { 0, 0, 0, 0 }; -int32 i; - -ReadFP2 (&fop2, op, r2, ea); /* get op2, norm */ -UnpackFPR (&fop1, op, r1); /* get op1, norm */ -if (fop2.h == 0) /* div by zero? */ - return CC_C | CC_V; -if (fop1.h) { /* dvd != 0? */ - quo.sign = fop1.sign ^ fop2.sign; /* sign = diff */ - quo.exp = fop1.exp - fop2.exp + FP_BIAS; /* exp = diff */ - if ((quo.exp < 0) || (quo.exp > FP_M_EXP)) /* ovf/undf? */ - return StoreFPX (&quo, op, r1); /* early out */ - if (!FR_GE (fop1, fop2)) { - FR_LSH_K (fop1, 4); /* ensure success */ - } - else { /* exp off by 1 */ - quo.exp = quo.exp + 1; /* incr exponent */ - if (quo.exp > FP_M_EXP) /* overflow? */ - return StoreFPX (&quo, op, r1); /* early out */ - } - for (i = 0; i < (OP_DPFP (op)? 14: 6); i++) { /* 6/14 hex digits */ - FR_LSH_K (quo, 4); /* shift quotient */ - while (FR_GE (fop1, fop2)) { /* while sub works */ - FR_SUB (fop1, fop2); /* decrement */ - quo.l = quo.l + 1; /* add quo bit */ - } - FR_LSH_K (fop1, 4); /* shift divd */ - } - if (!OP_DPFP (op)) { /* single? */ - quo.h = quo.l; /* move quotient */ - if (fop1.h >= (fop2.h << 3)) - quo.l = FP_ROUND; - else quo.l = 0; - } /* don't need to normalize */ - } /* end if fop1.h */ -return StoreFPR (&quo, op, r1, Q_RND (op)); /* store result */ -} - -/* Utility routines */ - -/* Unpack floating point number */ - -void UnpackFPR (struct ufp *fop, uint32 op, uint32 r1) -{ -uint32 hi; - -if (OP_DPFP (op)) { /* double prec? */ - hi = D[r1 >> 1].h; /* get hi */ - fop->l = FP_GETFRL (D[r1 >> 1].l); /* get lo */ - } -else { - hi = ReadFReg (r1); /* single prec */ - fop->l = 0; /* lo is zero */ - } -fop->h = FP_GETFRH (hi); /* get hi frac */ -if (fop->h || fop->l) { /* non-zero? */ - fop->sign = FP_GETSIGN (hi); /* get sign */ - fop->exp = FP_GETEXP (hi); /* get exp */ - NormUFP (fop); /* normalize */ - } -else fop->sign = fop->exp = 0; /* clean zero */ -return; -} - -/* Read memory operand */ - -void ReadFP2 (struct ufp *fop, uint32 op, uint32 r2, uint32 ea) -{ -uint32 hi; - -if (OP_TYPE (op) > OP_RR) { /* mem ref? */ - hi = ReadF (ea, VR); /* get hi */ - if (OP_DPFP (op)) /* dp? get lo */ - fop->l = ReadF (ea + 4, VR); - else fop->l = 0; /* sp, lo = 0 */ - } -else { - if (OP_DPFP (op)) { /* RR */ - hi = D[r2 >> 1].h; /* dp? get dp reg */ - fop->l = D[r2 >> 1].l; - } - else { - hi = ReadFReg (r2); /* get sp reg */ - fop->l = 0; - } - } -fop->h = FP_GETFRH (hi); /* get hi frac */ -if (fop->h || fop->l) { /* non-zero? */ - fop->sign = FP_GETSIGN (hi); /* get sign */ - fop->exp = FP_GETEXP (hi); /* get exp */ - NormUFP (fop); /* normalize */ - } -else fop->sign = fop->exp = 0; /* clean zero */ -return; -} - -/* Normalize unpacked floating point number */ - -void NormUFP (struct ufp *fop) -{ -if ((fop->h & FP_M_FRH) || fop->l) { /* any fraction? */ - while ((fop->h & FP_NORM) == 0) { /* until norm */ - fop->h = (fop->h << 4) | ((fop->l >> 28) & 0xF); - fop->l = fop->l << 4; - fop->exp = fop->exp - 1; - } - } -else fop->sign = fop->exp = 0; /* clean 0 */ -return; -} - -/* Round fp number, store, generate condition codes */ - -uint32 StoreFPR (struct ufp *fop, uint32 op, uint32 r1, uint32 rnd) -{ -uint32 hi, cc; - -if (rnd && (fop->l & FP_ROUND)) { /* round? */ - fop->h = fop->h + 1; /* add 1 to frac */ - if (fop->h & FP_CARRY) { /* carry out? */ - fop->h = fop->h >> 4; /* renormalize */ - fop->exp = fop->exp + 1; /* incr exp */ - } - } -if (fop->h == 0) { /* result 0? */ - hi = fop->l = 0; /* store clean 0 */ - cc = 0; - } -else if (fop->exp < 0) { /* underflow? */ - hi = fop->l = 0; /* store clean 0 */ - cc = CC_V; - } -else if (fop->exp > FP_M_EXP) { /* overflow? */ - hi = (fop->sign)? 0xFFFFFFFF: 0x7FFFFFFF; - fop->l = 0xFFFFFFFF; - cc = (CC_V | ((fop->sign)? CC_L: CC_G)); - } -else { - hi = ((fop->sign & FP_M_SIGN) << FP_V_SIGN) | /* pack result */ - ((fop->exp & FP_M_EXP) << FP_V_EXP) | - ((fop->h & FP_M_FRH) << FP_V_FRH); - cc = (fop->sign)? CC_L: CC_G; /* set cc's */ - } -if (OP_DPFP (op)) { /* double precision? */ - D[r1 >> 1].h = hi; - D[r1 >> 1].l = fop->l; - } -else { - WriteFReg (r1, hi); - } -return cc; -} - -/* Generate exception result */ - -uint32 StoreFPX (struct ufp *fop, uint32 op, uint32 r1) -{ -uint32 cc = CC_V; - -if (fop->exp < 0) /* undf? clean 0 */ - fop->h = fop->l = 0; -else { - fop->h = (fop->sign)? 0xFFFFFFFF: 0x7FFFFFFF; /* overflow */ - fop->l = 0xFFFFFFFF; - cc = cc | ((fop->sign)? CC_L: CC_G); - } -if (OP_DPFP (op)) { /* double precision? */ - D[r1 >> 1].h = fop->h; - D[r1 >> 1].l = fop->l; - } -else { - WriteFReg (r1, fop->h); - } -return cc; -} diff --git a/Interdata/id_idc.c b/Interdata/id_idc.c deleted file mode 100644 index 42a9b02a..00000000 --- a/Interdata/id_idc.c +++ /dev/null @@ -1,805 +0,0 @@ -/* id_idc.c: Interdata MSM/IDC disk controller simulator - - Copyright (c) 2001-2008, 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. - - idc MSM/IDC disk controller - - 03-Apr-06 RMS Fixed WD/WH handling (Davis Johnson) - 30-Mar-06 RMS Fixed bug, nop command should be ignored (Davis Johnson) - 25-Apr-03 RMS Revised for extended file support - 16-Feb-03 RMS Fixed read to test transfer ok before selch operation - - Note: define flag ID_IDC to enable the extra functions of the intelligent - disk controller -*/ - -#include "id_defs.h" - -#define IDC_NUMBY 256 /* bytes/sector */ -#define IDC_NUMSC 64 /* sectors/track */ - -#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */ -#define UNIT_M_DTYPE 0x7 -#define UNIT_V_AUTO (UNIT_V_UF + 4) /* autosize */ -#define UNIT_WLK (1 << UNIT_V_WLK) -#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE) -#define UNIT_AUTO (1 << UNIT_V_AUTO) -#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE) - -#define CYL u3 /* current cylinder */ -#define HD u4 /* current head */ -#define STD buf /* drive status */ -#define FNC wait /* function */ -#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ - -#define IDC_DRVMASK ((1 << ID_NUMDR) - 1) /* drive bit mask */ -#define IDC_DIRMASK (IDC_DRVMASK << (i_IDC + 1)) /* drive irq mask */ - -/* Controller status */ - -#define STC_WRP 0x80 /* write protected */ -#define STC_ACF 0x40 /* addr cmp fail */ -#define STC_DEF 0x20 /* def track NI */ -#define STC_CYO 0x10 /* cylinder ovflo */ -#define STC_IDL 0x02 /* ctrl idle */ -#define STC_DTE 0x01 /* xfer error */ -#define SETC_EX (STC_WRP|STC_ACF|STC_DEF|STC_CYO) -#define STC_MASK (STC_WRP|STC_ACF|STC_DEF|STC_CYO|STA_BSY|STC_IDL|STC_DTE) - -/* Controller command */ - -#define CMC_MASK 0x3F -#define CMC_CLR 0x08 /* reset */ -#define CMC_RD 0x01 /* read */ -#define CMC_WR 0x02 /* write */ -#define CMC_RCHK 0x03 /* read check */ -#define CMC_FCHK 0x04 /* format check NI */ -#define CMC_RFMT 0x05 /* read fmt NI */ -#define CMC_WFMT 0x06 /* write fmt NI */ -#define CMC_WFTK 0x07 /* write fmt track NI */ - -/* IDC only functions */ - -#define CMC_RRAM 0x10 /* read RAM */ -#define CMC_WRAM 0x11 /* write RAM */ -#define CMC_EXP0 0x12 /* read page 0 NI */ -#define CMC_RUNC 0x21 /* read uncorr */ -#define CMC_STST 0x30 /* self test */ -#define CMC_WLNG 0x32 /* write long NI */ -#define CMC_LAMP 0x37 /* lamp test */ - -#define CMC_DRV 0x100 /* drive func */ -#define CMC_DRV1 0x200 /* drive func, part 2 */ - -/* Drive status, ^ = dynamic, * = in unit status */ - -#define STD_WRP 0x80 /* ^write prot */ -/* 0x40 *//* unused */ -#define STD_ACH 0x20 /* alt chan busy NI */ -#define STD_UNS 0x10 /* *unsafe */ -#define STD_NRDY 0x08 /* ^not ready */ -#define STD_SKI 0x02 /* *seek incomplete */ -#define STD_OFFL 0x01 /* ^offline */ -#define STD_UST (STD_UNS | STD_SKI) /* set from unit */ -#define SETD_EX (STD_WRP | STD_UNS) /* set examine */ - -/* Drive command */ - -#define CMDF_SHD 0x20 /* set head */ -#define CMDF_SCY 0x10 /* set cylinder */ -#define CMD_SK 0x02 /* seek */ -#define CMD_RST 0x01 /* restore */ - -#define CMDX_MASK 0x30 /* ext cmd bits */ -#define CMDX_RLS 0x80 /* release */ -#define CMDX_CLF 0x40 /* clear fault */ -#define CMDX_SVP 0x08 /* servo + */ -#define CMDX_SVM 0x04 /* servo - */ -#define CMDX_DSP 0x02 /* strobe + */ -#define CMDX_DSM 0x01 /* strobe - */ - -/* Geometry masks */ - -#define CY_MASK 0xFFF /* cylinder */ -#define HD_MASK 0x1F /* head mask */ -#define SC_MASK 0x3F /* sector mask */ -#define HCYL_V_HD 10 /* head/cyl word */ -#define HCYL_V_CYL 0 - -#define GET_SA(cy,sf,sc,t) \ - (((((cy)*drv_tab[t].surf)+(sf))*IDC_NUMSC)+(sc)) - -/* The MSM (IDC) controller supports (two) six different disk drive types: - - type #sectors/ #surfaces/ #cylinders/ - surface cylinder drive - - MCCDD16 64 1 823 IDC - MCCDD48 64 3 823 IDC - MCCDD80 64 5 823 IDC - MSM80 64 5 823 MSM - MSM300 64 19 823 MSM - MSM330F 64 16 1024 IDC - - In theory, each drive can be a different type. The size field in - each unit selects the drive capacity for each drive and thus the - drive type. DISKS MUST BE DECLARED IN ASCENDING SIZE AND MUST HAVE - THE SAME SECTORS/TRACK. -*/ - -#define TYPE_MCCDD16 0 -#define SURF_MCCDD16 1 -#define CYL_MCCDD16 823 -#define SIZE_MCCDD16 (IDC_NUMSC * SURF_MCCDD16 * CYL_MCCDD16 * IDC_NUMBY) - -#define TYPE_MCCDD48 1 -#define SURF_MCCDD48 3 -#define CYL_MCCDD48 823 -#define SIZE_MCCDD48 (IDC_NUMSC * SURF_MCCDD48 * CYL_MCCDD48 * IDC_NUMBY) - -#define TYPE_MCCDD80 2 -#define SURF_MCCDD80 5 -#define CYL_MCCDD80 823 -#define SIZE_MCCDD80 (IDC_NUMSC * SURF_MCCDD80 * CYL_MCCDD80 * IDC_NUMBY) - -#define TYPE_MSM80 3 -#define SURF_MSM80 5 -#define CYL_MSM80 823 -#define SIZE_MSM80 (IDC_NUMSC * SURF_MSM80 * CYL_MSM80 * IDC_NUMBY) - -#define TYPE_MSM300 4 -#define SURF_MSM300 19 -#define CYL_MSM300 823 -#define SIZE_MSM300 (IDC_NUMSC * SURF_MSM300 * CYL_MSM300 * IDC_NUMBY) - -#define TYPE_MSM330F 5 -#define SURF_MSM330F 16 -#define CYL_MSM330F 1024 -#define SIZE_MSM330F (IDC_NUMSC * SURF_MSM330F * CYL_MSM330F * IDC_NUMBY) - - -struct drvtyp { - uint32 surf; /* surfaces */ - uint32 cyl; /* cylinders */ - uint32 size; /* #blocks */ - uint32 msmf; /* MSM drive */ - }; - -static struct drvtyp drv_tab[] = { - { SURF_MCCDD16, CYL_MCCDD16, SIZE_MCCDD16, 0 }, - { SURF_MCCDD48, CYL_MCCDD48, SIZE_MCCDD48, 0 }, - { SURF_MCCDD80, CYL_MCCDD80, SIZE_MCCDD80, 0 }, - { SURF_MSM80, CYL_MSM80, SIZE_MSM80, 1 }, - { SURF_MSM300, CYL_MSM300, SIZE_MSM300, 1 }, - { SURF_MSM330F, CYL_MSM330F, SIZE_MSM330F, 0 }, - { 0 } - }; - -extern uint32 int_req[INTSZ], int_enb[INTSZ]; - -uint8 idcxb[IDC_NUMBY * 3]; /* xfer buffer */ -uint32 idc_bptr = 0; /* buffer ptr */ -uint32 idc_wdptr = 0; /* ctrl write data ptr */ -uint32 idc_db = 0; /* ctrl buffer */ -uint32 idc_sta = 0; /* ctrl status */ -uint32 idc_sec = 0; /* sector */ -uint32 idc_hcyl = 0; /* head/cyl */ -uint32 idc_svun = 0; /* most recent unit */ -uint32 idc_1st = 0; /* first byte */ -uint32 idc_arm = 0; /* ctrl armed */ -uint32 idd_db = 0; /* drive buffer */ -uint32 idd_wdptr = 0; /* drive write data ptr */ -uint32 idd_arm[ID_NUMDR] = { 0 }; /* drives armed */ -uint16 idd_dcy[ID_NUMDR] = { 0 }; /* desired cyl */ -uint32 idd_sirq = 0; /* drive saved irq */ -int32 idc_stime = 100; /* seek latency */ -int32 idc_rtime = 100; /* rotate latency */ -int32 idc_ctime = 5; /* command latency */ -uint8 idc_tplte[] = { 0, 1, 2, 3, 4, TPL_END }; /* ctrl + drive */ - -DEVICE idc_dev; -uint32 id (uint32 dev, uint32 op, uint32 dat); -t_stat idc_svc (UNIT *uptr); -t_stat idc_reset (DEVICE *dptr); -t_stat idc_attach (UNIT *uptr, char *cptr); -t_stat idc_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -void idc_wd_byte (uint32 dat); -t_stat idc_rds (UNIT *uptr); -t_stat idc_wds (UNIT *uptr); -t_bool idc_dter (UNIT *uptr, uint32 first); -void idc_done (uint32 flg); - -extern t_stat id_dboot (int32 u, DEVICE *dptr); - -/* DP data structures - - idc_dev DP device descriptor - idc_unit DP unit list - idc_reg DP register list - idc_mod DP modifier list -*/ - -DIB idc_dib = { d_IDC, 0, v_IDC, idc_tplte, &id, NULL }; - -UNIT idc_unit[] = { - { UDATA (&idc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+(TYPE_MSM80 << UNIT_V_DTYPE), SIZE_MSM80) }, - { UDATA (&idc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+(TYPE_MSM80 << UNIT_V_DTYPE), SIZE_MSM80) }, - { UDATA (&idc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+(TYPE_MSM80 << UNIT_V_DTYPE), SIZE_MSM80) }, - { UDATA (&idc_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+(TYPE_MSM80 << UNIT_V_DTYPE), SIZE_MSM80) } - }; - -REG idc_reg[] = { - { HRDATA (STA, idc_sta, 8) }, - { HRDATA (BUF, idc_db, 8) }, - { HRDATA (SEC, idc_sec, 8) }, - { HRDATA (HCYL, idc_hcyl, 16) }, - { HRDATA (BUF, idd_db, 8) }, - { HRDATA (SVUN, idc_svun, 2), REG_HIDDEN }, - { BRDATA (DBUF, idcxb, 16, 8, IDC_NUMBY * 3) }, - { HRDATA (DBPTR, idc_bptr, 10), REG_RO }, - { FLDATA (FIRST, idc_1st, 0) }, - { HRDATA (CWDPTR, idc_wdptr, 2) }, - { HRDATA (DWDPTR, idc_wdptr, 1) }, - { GRDATA (IREQ, int_req[l_IDC], 16, ID_NUMDR + 1, i_IDC) }, - { GRDATA (IENB, int_enb[l_IDC], 16, ID_NUMDR + 1, i_IDC) }, - { GRDATA (SIREQ, idd_sirq, 16, ID_NUMDR, i_IDC + 1), REG_RO }, - { FLDATA (ICARM, idc_arm, 0) }, - { BRDATA (IDARM, idd_arm, 16, 1, ID_NUMDR) }, - { DRDATA (RTIME, idc_rtime, 24), PV_LEFT | REG_NZ }, - { DRDATA (STIME, idc_stime, 24), PV_LEFT | REG_NZ }, - { DRDATA (CTIME, idc_ctime, 24), PV_LEFT | REG_NZ }, - { BRDATA (CYL, idd_dcy, 16, 16, ID_NUMDR) }, - { URDATA (UCYL, idc_unit[0].CYL, 16, 12, 0, - ID_NUMDR, REG_RO) }, - { URDATA (UHD, idc_unit[0].HD, 16, 5, 0, - ID_NUMDR, REG_RO) }, - { URDATA (UFNC, idc_unit[0].FNC, 16, 10, 0, - ID_NUMDR, REG_HRO) }, - { URDATA (UST, idc_unit[0].STD, 16, 8, 0, - ID_NUMDR, REG_RO) }, - { URDATA (CAPAC, idc_unit[0].capac, 10, T_ADDR_W, 0, - ID_NUMDR, PV_LEFT | REG_HRO) }, - { HRDATA (DEVNO, idc_dib.dno, 8), REG_HRO }, - { HRDATA (SELCH, idc_dib.sch, 2), REG_HRO }, - { BRDATA (TPLTE, idc_tplte, 16, 8, ID_NUMDR + 1), REG_HRO }, - { NULL } - }; - -MTAB idc_mod[] = { - { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, - { (UNIT_DTYPE+UNIT_ATT), (TYPE_MCCDD16 << UNIT_V_DTYPE) + UNIT_ATT, - "MCCDD16", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (TYPE_MCCDD48 << UNIT_V_DTYPE) + UNIT_ATT, - "MCCDD48", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (TYPE_MCCDD80 << UNIT_V_DTYPE) + UNIT_ATT, - "MCCDD80", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (TYPE_MSM330F << UNIT_V_DTYPE) + UNIT_ATT, - "MSM330F", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_MCCDD16 << UNIT_V_DTYPE), - "MCCDD16", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_MCCDD48 << UNIT_V_DTYPE), - "MCCDD48", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_MCCDD80 << UNIT_V_DTYPE), - "MCCDD80", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_MSM330F << UNIT_V_DTYPE), - "MSM330F", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_MCCDD16 << UNIT_V_DTYPE), - NULL, "MCCDD16", &idc_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_MCCDD48 << UNIT_V_DTYPE), - NULL, "MCCDD48", &idc_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_MCCDD80 << UNIT_V_DTYPE), - NULL, "MCCDD80", &idc_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_MSM330F << UNIT_V_DTYPE), - NULL, "MSM330F", &idc_set_size }, - { (UNIT_DTYPE+UNIT_ATT), (TYPE_MSM80 << UNIT_V_DTYPE) + UNIT_ATT, - "MSM80", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (TYPE_MSM300 << UNIT_V_DTYPE) + UNIT_ATT, - "MSM300", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_MSM80 << UNIT_V_DTYPE), - "MSM80", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_MSM300 << UNIT_V_DTYPE), - "MSM300", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_MSM80 << UNIT_V_DTYPE), - NULL, "MSM80", &idc_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_MSM300 << UNIT_V_DTYPE), - NULL, "MSM300", &idc_set_size }, - { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL }, - { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL }, - { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", - &set_dev, &show_dev, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "SELCH", "SELCH", - &set_sch, &show_sch, NULL }, - { 0 } - }; - -DEVICE idc_dev = { - "DM", idc_unit, idc_reg, idc_mod, - ID_NUMDR, 16, 29, 1, 16, 8, - NULL, NULL, &idc_reset, - &id_dboot, &idc_attach, NULL, - &idc_dib, DEV_DISABLE - }; - -/* Controller: IO routine */ - -uint32 idc (uint32 dev, uint32 op, uint32 dat) -{ -uint32 f, t; -UNIT *uptr; - -switch (op) { /* case IO op */ - - case IO_ADR: /* select */ - sch_adr (idc_dib.sch, dev); /* inform sel ch */ - return HW; /* halfwords */ - - case IO_RD: /* read data */ - case IO_RH: /* read halfword */ - return 0; /* return data */ - - case IO_WD: /* write data */ - idc_wd_byte (dat); /* one byte only */ - break; - - case IO_WH: /* write halfword */ - idc_wd_byte (dat >> 8); /* high byte */ - idc_wd_byte (dat); /* low byte */ - break; - - case IO_SS: /* status */ - t = idc_sta & STC_MASK; /* get status */ - if (t & SETC_EX) /* test for EX */ - t = t | STA_EX; - return t; - - case IO_OC: /* command */ - idc_arm = int_chg (v_IDC, dat, idc_arm); /* upd int ctrl */ - idc_wdptr = 0; /* init ptr */ - f = dat & CMC_MASK; /* get cmd */ - uptr = idc_dev.units + idc_svun; /* get unit */ - if (f & CMC_CLR) { /* clear? */ - idc_reset (&idc_dev); /* reset world */ - break; - } - if ((f == 0) || /* if nop, */ - (f == CMC_EXP0) || /* expg, */ - !(idc_sta & STC_IDL) || /* !idle, */ - sim_is_active (uptr)) break; /* unit busy, ignore */ - idc_sta = STA_BSY; /* bsy=1,idl,err=0 */ - idc_1st = 1; /* xfr not started */ - idc_bptr = 0; /* buffer empty */ - uptr->FNC = f; /* save cmd */ - sim_activate (uptr, idc_rtime); /* schedule */ - idd_sirq = int_req[l_IDC] & IDC_DIRMASK; /* save drv ints */ - int_req[l_IDC] = int_req[l_IDC] & ~IDC_DIRMASK; /* clr drv ints */ - break; - } - -return 0; -} - -/* Process WD/WH data */ - -void idc_wd_byte (uint32 dat) -{ -dat = dat & 0xFF; -switch (idc_wdptr) { - - case 0: /* byte 0 = sector */ - idc_sec = dat; - idc_wdptr++; - break; - - case 1: /* byte 1 = high hd/cyl */ - idc_hcyl = (idc_hcyl & 0xFF) | (dat << 8); - idc_wdptr++; - break; - - case 2: /* byte 2 = low hd/cyl */ - idc_hcyl = (idc_hcyl & 0xFF00) | dat; - idc_wdptr = 0; - break; - } - -return; -} - -/* Drives: IO routine */ - -uint32 id (uint32 dev, uint32 op, uint32 dat) -{ -uint32 t, u, f; -UNIT *uptr; - -if (dev == idc_dib.dno) /* controller? */ - return idc (dev, op, dat); -u = (dev - idc_dib.dno - o_ID0) / o_ID0; /* get unit num */ -uptr = idc_dev.units + u; /* get unit ptr */ -switch (op) { /* case IO op */ - - case IO_ADR: /* select */ - if (idc_sta & STC_IDL) /* idle? save unit */ - idc_svun = u; - return BY; /* byte only */ - - case IO_RD: /* read data */ - case IO_RH: - return 0; - - case IO_WD: /* write data */ - if (idd_wdptr & 1) /* low byte? */ - idd_db = (idd_db & 0xFF00) | dat; - else idd_db = (idd_db & 0xFF) | (dat << 8); /* no, high */ - idd_wdptr = idd_wdptr ^ 1; /* other byte */ - break; - - case IO_SS: /* status */ - if (uptr->flags & UNIT_ATT) t = - ((uptr->flags & UNIT_WPRT)? STD_WRP: 0) | - (sim_is_active (uptr)? STD_NRDY: 0) | - (uptr->STD & STD_UST); - else t = STD_NRDY | STD_OFFL; /* off = X'09' */ - if (t & SETD_EX) /* test for ex */ - t = t | STA_EX; - return t; - - case IO_OC: /* command */ - idd_arm[u] = int_chg (v_IDC + u + 1, dat, idd_arm[u]); - idd_wdptr = 0; /* init ptr */ - if (idd_arm[u] == 0) /* disarmed? */ - idd_sirq &= ~(1 << (v_IDC + u + 1)); /* clr saved req */ - f = dat & CMC_MASK; /* get cmd */ - if ((f == 0) || /* if nop, */ - (f == CMDX_MASK) || /* 0x30, */ - !(idc_sta & STC_IDL) || /* !idle, */ - sim_is_active (uptr)) /* unit busy, ignore */ - break; - uptr->FNC = f | CMC_DRV; /* save cmd */ - idc_sta = idc_sta & ~STC_IDL; /* clr idle */ - sim_activate (uptr, idc_ctime); /* schedule */ - break; - } - -return 0; -} - -/* Unit service - - If drive command, process; if an interrupt is needed (positioning - command), schedule second part - - If data transfer command, process; must use selector channel -*/ - -t_stat idc_svc (UNIT *uptr) -{ -int32 diff; -uint32 f, u = uptr - idc_dev.units; /* get unit number */ -uint32 dtype = GET_DTYPE (uptr->flags); /* get drive type */ -t_stat r; - -if (uptr->FNC & CMC_DRV) { /* drive cmd? */ - f = uptr->FNC & CMC_MASK; /* get cmd */ - if (uptr->FNC & CMC_DRV1) { /* part 2? */ - if (idd_arm[u]) { /* drv int armed? */ - if (idc_sta & STC_IDL) /* ctrl idle? */ - SET_INT (v_IDC + u + 1); /* req intr */ - else idd_sirq |= (1 << (v_IDC + u + 1)); /* def intr */ - } - if ((uptr->flags & UNIT_ATT) == 0) - return SCPE_OK; - if (((f & CMDX_MASK) == 0) && /* seek? */ - (f & (CMD_SK | CMD_RST))) { - if (idd_dcy[u] >= drv_tab[dtype].cyl) /* bad cylinder? */ - uptr->STD = uptr->STD | STD_SKI; /* error */ - uptr->CYL = idd_dcy[u]; /* put on cyl */ - } - } /* end if p2 */ - else { /* part 1 */ - idc_sta = idc_sta | STC_IDL; /* set idle */ - uptr->FNC = uptr->FNC | CMC_DRV1; /* set part 2 */ - if (f >= CMDX_MASK) { /* extended? */ - if (f & CMDX_CLF) /* clr fault? */ - uptr->STD = uptr->STD & ~STD_UNS; /* clr unsafe */ - if (f & (CMDX_RLS | CMDX_SVP | CMDX_SVM)) /* intr expected? */ - sim_activate (uptr, idc_ctime); - } - else if (f >= CMDF_SCY) { /* tag? */ - if (f & CMDF_SHD) - uptr->HD = idd_db & HD_MASK; - else if (f & CMDF_SCY) { - if (idd_db >= drv_tab[dtype].cyl) /* bad cylinder? */ - uptr->STD = uptr->STD | STD_SKI; /* set seek inc */ - idd_dcy[u] = idd_db & CY_MASK; - } - } - else if (f & (CMD_SK | CMD_RST)) { /* seek? */ - if (f == CMD_RST) /* restore? */ - idd_dcy[u] = 0; - if (idd_dcy[u] >= drv_tab[dtype].cyl) { /* bad cylinder? */ - uptr->STD = uptr->STD | STD_SKI; /* set seek inc */ - idd_dcy[u] = uptr->CYL; /* no motion */ - sim_activate (uptr, 0); /* finish asap */ - } - else { /* cylinder ok */ - uptr->STD = uptr->STD & ~STD_SKI; /* clr seek inc */ - diff = idd_dcy[u] - uptr->CYL; - if (diff < 0) /* ABS cyl diff */ - diff = -diff; - else if (diff == 0) /* must be nz */ - diff = 1; - sim_activate (uptr, diff * idc_stime); - } - } - } /* end else p1 */ - return SCPE_OK; /* end if drv */ - } - -switch (uptr->FNC & CMC_MASK) { /* case on func */ - - case CMC_RCHK: /* read check */ - idc_dter (uptr, 1); /* check xfr err */ - break; - -#if defined (ID_IDC) - case CMC_RUNC: /* read uncorr */ -#endif - case CMC_RD: /* read */ - if (sch_actv (idc_dib.sch, idc_dib.dno)) { /* sch transfer? */ - if (idc_dter (uptr, idc_1st)) /* dte? done */ - return SCPE_OK; - if ((r = idc_rds (uptr))) /* read sec, err? */ - return r; - idc_1st = 0; - sch_wrmem (idc_dib.sch, idcxb, IDC_NUMBY); /* write mem */ - if (sch_actv (idc_dib.sch, idc_dib.dno)) { /* more to do? */ - sim_activate (uptr, idc_rtime); /* reschedule */ - return SCPE_OK; - } - break; /* no, set done */ - } - idc_sta = idc_sta | STC_DTE; /* cant work */ - break; - - case CMC_WR: /* write */ - if (sch_actv (idc_dib.sch, idc_dib.dno)) { /* sch transfer? */ - if (idc_dter (uptr, idc_1st)) /* dte? done */ - return SCPE_OK; - idc_bptr = sch_rdmem (idc_dib.sch, idcxb, IDC_NUMBY); /* read mem */ - idc_db = idcxb[idc_bptr - 1]; /* last byte */ - if ((r = idc_wds (uptr))) /* write sec, err? */ - return r; - idc_1st = 0; - if (sch_actv (idc_dib.sch, idc_dib.dno)) { /* more to do? */ - sim_activate (uptr, idc_rtime); /* reschedule */ - return SCPE_OK; - } - break; /* no, set done */ - } - idc_sta = idc_sta | STC_DTE; /* cant work */ - break; - - case CMC_FCHK: case CMC_RFMT: case CMC_WFMT: case CMC_WFTK: - idc_dter (uptr, 1); - idc_sta = idc_sta | STC_WRP; - break; - -#if defined (ID_IDC) - case CMC_RRAM: /* read RAM */ - if (sch_actv (idc_dib.sch, idc_dib.dno)) { /* sch transfer? */ - sch_wrmem (idc_dib.sch, idcxb, IDC_NUMBY * 3); - if (sch_actv (idc_dib.sch, idc_dib.dno)) { /* more to do? */ - sim_activate (uptr, idc_rtime); /* reschedule */ - return SCPE_OK; - } - break; /* no, set done */ - } - idc_sta = idc_sta | STC_DTE; /* cant work */ - break; - - case CMC_WRAM: /* write RAM */ - if (sch_actv (idc_dib.sch, idc_dib.dno)) { /* sch transfer? */ - sch_rdmem (idc_dib.sch, idcxb, IDC_NUMBY * 3); /* read from mem */ - if (sch_actv (idc_dib.sch, idc_dib.dno)) { /* more to do? */ - sim_activate (uptr, idc_rtime); /* reschedule */ - return SCPE_OK; - } - break; /* no, set done */ - } - idc_sta = idc_sta | STC_DTE; /* cant work */ - break; - - case CMC_STST: case CMC_LAMP: /* tests */ - break; -#endif - -default: - idc_sta = idc_sta | STC_DTE; - break; - } - -idc_done (0); /* done */ -return SCPE_OK; -} - -/* Read data sector */ - -t_stat idc_rds (UNIT *uptr) -{ -uint32 i; - -i = fxread (idcxb, sizeof (uint8), IDC_NUMBY, uptr->fileref); -if (ferror (uptr->fileref)) { /* error? */ - perror ("IDC I/O error"); - clearerr (uptr->fileref); - idc_done (STC_DTE); - return SCPE_IOERR; - } -for ( ; i < IDC_NUMBY; i++) /* fill with 0's */ - idcxb[i] = 0; -return SCPE_OK; -} - -/* Write data sector */ - -t_bool idc_wds (UNIT *uptr) -{ -for ( ; idc_bptr < IDC_NUMBY; idc_bptr++) - idcxb[idc_bptr] = idc_db; /* fill with last */ -fxwrite (idcxb, sizeof (uint8), IDC_NUMBY, uptr->fileref); -if (ferror (uptr->fileref)) { /* error? */ - perror ("IDC I/O error"); - clearerr (uptr->fileref); - idc_done (STC_DTE); - return SCPE_IOERR; - } -return FALSE; -} - -/* Data transfer error test routine */ - -t_bool idc_dter (UNIT *uptr, uint32 first) -{ -uint32 cy; -uint32 hd, sc, sa; -uint32 dtype = GET_DTYPE (uptr->flags); /* get drive type */ - -if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ - idc_done (STC_DTE); /* error, done */ - return TRUE; - } -if ((uptr->flags & UNIT_WPRT) && (uptr->FNC == CMC_WR)) { - idc_done (STC_WRP); /* error, done */ - return TRUE; - } -cy = uptr->CYL; /* get cylinder */ -hd = uptr->HD; /* get head */ -sc = idc_sec & SC_MASK; /* get sector */ -if (cy >= drv_tab[dtype].cyl) { /* bad cylinder? */ - uptr->STD = uptr->STD | STD_SKI; /* error */ - idc_done (STC_DTE); /* error, done */ - return TRUE; - } -if (hd >= drv_tab[dtype].surf) { /* bad head? */ - if (first) { /* 1st xfer? */ - uptr->STD = uptr->STD | STD_UNS; /* drive unsafe */ - idc_done (STC_ACF); - } - else idc_done (STC_CYO); /* no, cyl ovf */ - return TRUE; - } -sa = GET_SA (cy, hd, sc, dtype); /* curr disk addr */ -fseek (uptr->fileref, sa * IDC_NUMBY, SEEK_SET); /* seek to pos */ -idc_sec = (idc_sec + 1) & SC_MASK; /* incr disk addr */ -if (idc_sec == 0) - uptr->HD = uptr->HD + 1; -return FALSE; -} - -/* Data transfer done routine */ - -void idc_done (uint32 flg) -{ -idc_sta = (idc_sta | STC_IDL | flg) & ~STA_BSY; /* set flag, idle */ -if (idc_arm) /* if armed, intr */ - SET_INT (v_IDC); -int_req[l_IDC] = int_req[l_IDC] | idd_sirq; /* restore drv ints */ -idd_sirq = 0; /* clear saved */ -if (flg) /* if err, stop sch */ - sch_stop (idc_dib.sch); -return; -} - -/* Reset routine */ - -t_stat idc_reset (DEVICE *dptr) -{ -uint32 u; -UNIT *uptr; - -idc_sta = STC_IDL | STA_BSY; /* idle, busy */ -idc_wdptr = 0; -idd_wdptr = 0; -idc_1st = 0; /* clear flag */ -idc_svun = idc_db = 0; /* clear unit, buf */ -idc_sec = 0; /* clear addr */ -idc_hcyl = 0; -CLR_INT (v_IDC); /* clear ctrl int */ -CLR_ENB (v_IDC); /* clear ctrl enb */ -idc_arm = 0; /* clear ctrl arm */ -idd_sirq = 0; -for (u = 0; u < ID_NUMDR; u++) { /* loop thru units */ - uptr = idc_dev.units + u; - uptr->CYL = uptr->STD = 0; - uptr->HD = uptr->FNC = 0; - idd_dcy[u] = 0; - CLR_INT (v_IDC + u + 1); /* clear intr */ - CLR_ENB (v_IDC + u + 1); /* clear enable */ - idd_arm[u] = 0; /* clear arm */ - sim_cancel (uptr); /* cancel activity */ - } -return SCPE_OK; -} - -/* Attach routine (with optional autosizing) */ - -t_stat idc_attach (UNIT *uptr, char *cptr) -{ -uint32 i, p; -t_stat r; - -uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size; -r = attach_unit (uptr, cptr); /* attach unit */ -if (r != SCPE_OK) /* error? */ - return r; -uptr->CYL = 0; -if ((uptr->flags & UNIT_AUTO) == 0) /* autosize? */ - return SCPE_OK; -if ((p = ftell (uptr->fileref)) == 0) - return SCPE_OK; -for (i = 0; drv_tab[i].surf != 0; i++) { - if (p <= drv_tab[i].size) { - uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE); - uptr->capac = drv_tab[i].size; - return SCPE_OK; - } - } -return SCPE_OK; -} - -/* Set size command validation routine */ - -t_stat idc_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (uptr->flags & UNIT_ATT) - return SCPE_ALATT; -uptr->capac = drv_tab[GET_DTYPE (val)].size; -return SCPE_OK; -} diff --git a/Interdata/id_io.c b/Interdata/id_io.c deleted file mode 100644 index a97cf813..00000000 --- a/Interdata/id_io.c +++ /dev/null @@ -1,660 +0,0 @@ -/* id_io.c: Interdata CPU-independent I/O routines - - Copyright (c) 2001-2008, Robert M. Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - 30-Mar-06 RMS Fixed bug, GO preserves EXA and SSTA (Davis Johnson) - 21-Jun-03 RMS Changed subroutine argument for ARM compiler conflict - - Interdata I/O devices are defined by a device information block: - - dno base device number - sch selector channel, -1 if none - irq interrupt request flag - tplte device number template, NULL if one device number - iot I/O processing routine - ini initialization routine - - Interdata I/O uses the following interconnected tables: - - dev_tab[dev] Indexed by device number, points to the I/O instruction - processing routine for the device. - - sch_tab[dev] Indexed by device number, if non-zero, the number + 1 - of the selector channel used by the device. - - int_req[level] Indexed by interrupt level, device interrupt flags. - - int_enb[level] Indexed by interrupt level, device interrupt enable flags. - - int_tab[idx] Indexed by ((interrupt level * 32) + interrupt number), - maps bit positions in int_req to device numbers. -*/ - -#include "id_defs.h" - -/* Selector channel */ - -#define SCHC_EXA 0x40 /* read ext addr */ -#define SCHC_RD 0x20 /* read */ -#define SCHC_GO 0x10 /* go */ -#define SCHC_STOP 0x08 /* stop */ -#define SCHC_SSTA 0x04 /* sel ch status */ -#define SCHC_EXM 0x03 /* ext mem */ - -extern uint32 int_req[INTSZ], int_enb[INTSZ]; -extern uint32 (*dev_tab[DEVNO])(uint32 dev, uint32 op, uint32 datout); -extern uint32 pawidth; -extern UNIT cpu_unit; - -uint32 sch_max = 2; /* sch count */ -uint32 sch_sa[SCH_NUMCH] = { 0 }; /* start addr */ -uint32 sch_ea[SCH_NUMCH] = { 0 }; /* end addr */ -uint8 sch_sdv[SCH_NUMCH] = { 0 }; /* device */ -uint8 sch_cmd[SCH_NUMCH] = { 0 }; /* command */ -uint8 sch_rdp[SCH_NUMCH] = { 0 }; /* read ptr */ -uint8 sch_wdc[SCH_NUMCH] = { 0 }; /* write ctr */ -uint32 sch_tab[DEVNO] = { 0 }; /* dev to sch map */ -uint32 int_tab[INTSZ * 32] = { 0 }; /* int to dev map */ -uint8 sch_tplte[SCH_NUMCH + 1]; /* dnum template */ - -uint32 sch (uint32 dev, uint32 op, uint32 dat); -void sch_ini (t_bool dtpl); -t_stat sch_reset (DEVICE *dptr); -t_stat sch_set_nchan (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat sch_show_nchan (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat sch_show_reg (FILE *st, UNIT *uptr, int32 val, void *desc); - -/* Selector channel data structures - - sch_dev channel device descriptor - sch_unit channel unit descriptor - sch_mod channel modifiers list - sch_reg channel register list -*/ - -DIB sch_dib = { d_SCH, -1, v_SCH, sch_tplte, &sch, &sch_ini }; - -UNIT sch_unit = { UDATA (NULL, 0, 0) }; - -REG sch_reg[] = { - { HRDATA (CHAN, sch_max, 3), REG_HRO }, - { BRDATA (SA, sch_sa, 16, 20, SCH_NUMCH) }, - { BRDATA (EA, sch_ea, 16, 20, SCH_NUMCH) }, - { BRDATA (CMD, sch_cmd, 16, 8, SCH_NUMCH) }, - { BRDATA (DEV, sch_sdv, 16, 8, SCH_NUMCH) }, - { BRDATA (RDP, sch_rdp, 16, 2, SCH_NUMCH) }, - { BRDATA (WDC, sch_wdc, 16, 3, SCH_NUMCH) }, - { GRDATA (IREQ, int_req[l_SCH], 16, SCH_NUMCH, i_SCH) }, - { GRDATA (IENB, int_enb[l_SCH], 16, SCH_NUMCH, i_SCH) }, - { HRDATA (DEVNO, sch_dib.dno, 8), REG_HRO }, - { NULL } - }; - -MTAB sch_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "channels", "CHANNELS", - &sch_set_nchan, &sch_show_nchan, NULL }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "0", NULL, - NULL, &sch_show_reg, NULL }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "1", NULL, - NULL, &sch_show_reg, NULL }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 2, "2", NULL, - NULL, &sch_show_reg, NULL }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 3, "3", NULL, - NULL, &sch_show_reg, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", - &set_dev, &show_dev, &sch_dib }, - { 0 } - }; - -DEVICE sch_dev = { - "SELCH", &sch_unit, sch_reg, sch_mod, - 1, 16, 8, 1, 16, 8, - NULL, NULL, &sch_reset, - NULL, NULL, NULL, - &sch_dib, 0 - }; - -/* (Extended) selector channel - - There are really three different selector channels: - - 16b selector channel (max 4B of data) - - 18b selector channel (max 4B of data) - - 20b selector channel (max 6B of data) - The algorithm for loading the start and end addresses is taken - from the maintenance manual for the Extended Selector Channel. -*/ - -#define SCH_EXR(ch) ((sch_cmd[ch] & SCHC_EXA) && (pawidth == PAWIDTH32)) - -uint32 sch (uint32 dev, uint32 op, uint32 dat) -{ -uint32 t, bank, sdv, ch = dev - sch_dib.dno; - -switch (op) { /* case IO op */ - - case IO_ADR: /* select */ - return BY; /* byte only */ - - case IO_RD: /* read data */ - t = (sch_sa[ch] >> (sch_rdp[ch] * 8)) & DMASK8; /* get sa byte */ - if (sch_rdp[ch] == 0) sch_rdp[ch] = /* wrap? */ - SCH_EXR (ch)? 2: 1; - else sch_rdp[ch] = sch_rdp[ch] - 1; /* dec byte ptr */ - return t; - - case IO_WD: /* write data */ - if (pawidth != PAWIDTH32) { /* 16b? max 4 */ - if (sch_wdc[ch] >= 4) /* stop at 4 */ - break; - sch_sa[ch] = ((sch_sa[ch] << 8) | /* ripple ea to sa */ - (sch_ea[ch] >> 8)) & DMASK16; - sch_ea[ch] = ((sch_ea[ch] << 8) | /* ripple ea low */ - dat) & DMASK16; /* insert byte */ - } - else { /* 32b? max 6 */ - if (sch_wdc[ch] >= 6) /* stop at 6 */ - break; - if (sch_wdc[ch] != 5) { /* if not last */ - sch_sa[ch] = ((sch_sa[ch] << 8) | /* ripple ea<15:8> to sa */ - ((sch_ea[ch] >> 8) & DMASK8)) & PAMASK32; - sch_ea[ch] = /* ripple ea<7:0> */ - (((sch_ea[ch] & DMASK8) << 8) | dat) & PAMASK32; - } - else sch_ea[ch] = ((sch_ea[ch] << 8) | dat) & PAMASK32; - } - sch_wdc[ch] = sch_wdc[ch] + 1; /* adv sequencer */ - break; - - case IO_SS: /* status */ - if (sch_cmd[ch] & SCHC_GO) /* test busy */ - return STA_BSY; - if (sch_cmd[ch] & SCHC_SSTA) /* test sch sta */ - return 0; - else { - sdv = sch_sdv[ch]; /* get dev */ - if (dev_tab[sdv] == 0) /* not there? */ - return CC_V; - dev_tab[sdv] (sdv, IO_ADR, 0); /* select dev */ - t = dev_tab[sdv] (sdv, IO_SS, 0); /* get status */ - return t & ~STA_BSY; /* clr busy */ - } - - case IO_OC: /* command */ - bank = 0; /* assume no bank */ - if (pawidth != PAWIDTH32) { /* 16b/18b proc? */ - dat = dat & ~(SCHC_EXA | SCHC_SSTA); /* clr ext func */ - if (pawidth == PAWIDTH16E) /* 18b proc? */ - bank = (dat & SCHC_EXM) << 16; - } - if (dat & SCHC_STOP) { /* stop? */ - sch_cmd[ch] = dat & (SCHC_EXA | SCHC_SSTA); /* clr go */ - CLR_INT (v_SCH + ch); /* clr intr */ - sch_rdp[ch] = SCH_EXR (ch)? 2: 1; /* init sequencers */ - sch_wdc[ch] = 0; - } - else if (dat & SCHC_GO) { /* go? */ - sch_cmd[ch] = dat & (SCHC_EXA | SCHC_SSTA| SCHC_GO | SCHC_RD); - if (sch_wdc[ch] <= 4) { /* 4 bytes? */ - sch_sa[ch] = (sch_sa[ch] & PAMASK16) | bank; /* 16b addr */ - sch_ea[ch] = (sch_ea[ch] & PAMASK16) | bank; - } - sch_sa[ch] = sch_sa[ch] & ~1; - if (sch_ea[ch] <= sch_sa[ch]) /* wrap? */ - sch_ea[ch] = sch_ea[ch] | /* modify end addr */ - ((pawidth == PAWIDTH32)? PAMASK32: PAMASK16); - } - break; - } - -return 0; -} - -/* CPU call to test if channel blocks access to device */ - -t_bool sch_blk (uint32 dev) -{ -uint32 ch = sch_tab[dev] - 1; - -if ((ch < sch_max) && (sch_cmd[ch] & SCHC_GO)) - return TRUE; -return FALSE; -} - -/* Device call to 'remember' last dev on channel */ - -void sch_adr (uint32 ch, uint32 dev) -{ -if (ch < sch_max) - sch_sdv[ch] = dev; -return; -} - -/* Device call to see if selector channel is active for device */ - -t_bool sch_actv (uint32 ch, uint32 dev) -{ -if ((ch < sch_max) && /* chan valid, */ - (sch_cmd[ch] & SCHC_GO) && /* on, and */ - (sch_sdv[ch] == dev)) /* set for dev? */ - return TRUE; -return FALSE; /* no */ -} - -/* Device call to read a block of memory */ - -uint32 sch_rdmem (uint32 ch, uint8 *buf, uint32 cnt) -{ -uint32 addr, end, xfr, inc; - -if ((ch >= sch_max) || ((sch_cmd[ch] & SCHC_GO) == 0)) - return 0; -addr = sch_sa[ch]; /* start */ -end = sch_ea[ch]; /* end */ -xfr = MIN (cnt, end - addr + 1); /* sch xfr cnt */ -inc = IOReadBlk (addr, xfr, buf); /* read mem */ -if ((addr + inc) > end) { /* end? */ - SET_INT (v_SCH + ch); /* interrupt */ - sch_cmd[ch] &= ~(SCHC_GO | SCHC_RD); /* clear GO */ - sch_sa[ch] = sch_sa[ch] + inc - 1; /* end addr */ - } -else sch_sa[ch] = sch_sa[ch] + inc; /* next addr */ -return inc; -} - -/* Device call to write a block of memory */ - -uint32 sch_wrmem (uint32 ch, uint8 *buf, uint32 cnt) -{ -uint32 addr, end, xfr, inc; - -if ((ch >= sch_max) || ((sch_cmd[ch] & SCHC_GO) == 0)) - return 0; -addr = sch_sa[ch]; /* start */ -end = sch_ea[ch]; /* end */ -xfr = MIN (cnt, end - addr + 1); /* sch xfr cnt */ -inc = IOWriteBlk (addr, xfr, buf); /* write mem */ -if ((addr + inc) > end) { /* end? */ - SET_INT (v_SCH + ch); /* interrupt */ - sch_cmd[ch] &= ~(SCHC_GO | SCHC_RD); /* clear GO */ - sch_sa[ch] = sch_sa[ch] + inc - 1; /* end addr */ - } -else sch_sa[ch] = sch_sa[ch] + inc; /* next addr */ -return inc; -} - -/* Device call to stop a selector channel */ - -void sch_stop (uint32 ch) -{ -if (ch < sch_max) { - SET_INT (v_SCH + ch); /* interrupt */ - sch_cmd[ch] &= ~(SCHC_GO | SCHC_RD); /* clear GO */ - } -return; -} - -/* Reset */ - -void sch_reset_ch (uint32 rst_lim) -{ -uint32 ch; - -for (ch = 0; ch < SCH_NUMCH; ch++) { - if (ch >= rst_lim) { - CLR_INT (v_SCH + ch); - SET_ENB (v_SCH + ch); - sch_sa[ch] = sch_ea[ch] = 0; - sch_cmd[ch] = sch_sdv[ch] = 0; - sch_wdc[ch] = 0; - sch_rdp[ch] = 1; - } - } -return; -} - -t_stat sch_reset (DEVICE *dptr) -{ -sch_reset_ch (0); /* reset all chan */ -return SCPE_OK; -} - -/* Set number of channels */ - -t_stat sch_set_nchan (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -DEVICE *dptr; -DIB *dibp; -uint32 i, newmax; -t_stat r; - -if (cptr == NULL) - return SCPE_ARG; -newmax = get_uint (cptr, 10, SCH_NUMCH, &r); /* get new max */ -if ((r != SCPE_OK) || (newmax == sch_max)) /* err or no chg? */ - return r; -if (newmax == 0) /* must be > 0 */ - return SCPE_ARG; -if (newmax < sch_max) { /* reducing? */ - for (i = 0; (dptr = sim_devices[i]); i++) { /* loop thru dev */ - dibp = (DIB *) dptr->ctxt; /* get DIB */ - if (dibp && (dibp->sch >= (int32) newmax)) { /* dev using chan? */ - sim_printf ("Device %02X uses channel %d\n", - dibp->dno, dibp->sch); - return SCPE_OK; - } - } - } -sch_max = newmax; /* set new max */ -sch_reset_ch (sch_max); /* reset chan */ -return SCPE_OK; -} - -/* Show number of channels */ - -t_stat sch_show_nchan (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -fprintf (st, "channels=%d", sch_max); -return SCPE_OK; -} - -/* Show channel registers */ - -t_stat sch_show_reg (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -if (val < 0) - return SCPE_IERR; -if (val >= (int32) sch_max) - fprintf (st, "Channel %d disabled\n", val); -else { - fprintf (st, "SA: %05X\n", sch_sa[val]); - fprintf (st, "EA: %05X\n", sch_ea[val]); - fprintf (st, "CMD: %02X\n", sch_cmd[val]); - fprintf (st, "DEV: %02X\n", sch_sdv[val]); - fprintf (st, "RDP: %X\n", sch_rdp[val]); - fprintf (st, "WDC: %X\n", sch_wdc[val]); - } -return SCPE_OK; -} - -/* Initialize template */ - -void sch_ini (t_bool dtpl) -{ -uint32 i; - -for (i = 0; i < sch_max; i++) - sch_tplte[i] = i; -sch_tplte[sch_max] = TPL_END; -return; -} - -/* Evaluate interrupt */ - -void int_eval (void) -{ -int i; -extern uint32 qevent; - -for (i = 0; i < INTSZ; i++) { - if (int_req[i] & int_enb[i]) { - qevent = qevent | EV_INT; - return; - } - } -qevent = qevent & ~EV_INT; -return; -} - -/* Return interrupting device */ - -uint32 int_getdev (void) -{ -int32 i, j, t; -uint32 r; - -for (i = t = 0; i < INTSZ; i++) { /* loop thru array */ - if ((r = int_req[i] & int_enb[i])) { /* find nz int wd */ - for (j = 0; j < 32; t++, j++) { - if (r & (1u << j)) { - int_req[i] = int_req[i] & ~(1u << j); /* clr request */ - return int_tab[t]; - } - } - } - else t = t + 32; - } -return 0; -} - -/* Update device interrupt status */ - -int32 int_chg (uint32 irq, int32 dat, int32 armdis) -{ -int32 t = CMD_GETINT (dat); /* get int ctrl */ - -if (t == CMD_IENB) { /* enable? */ - SET_ENB (irq); - return 1; - } -else if (t == CMD_IDIS) { /* disable? */ - CLR_ENB (irq); - return 1; - } -if (t == CMD_IDSA) { /* disarm? */ - CLR_ENB (irq); - CLR_INT (irq); - return 0; - } -return armdis; -} - -/* Process a 2b field and return unchanged, set, clear, complement */ - -int32 io_2b (int32 val, int32 pos, int32 old) -{ -int32 t = (val >> pos) & 3; -if (t == 0) - return old; -if (t == 1) - return 1; -if (t == 2) - return 0; -return old ^1; -} - -/* Block transfer routines */ - -uint32 IOReadBlk (uint32 loc, uint32 cnt, uint8 *buf) -{ -uint32 i; - -if (!MEM_ADDR_OK (loc) || (cnt == 0)) - return 0; -if (!MEM_ADDR_OK (loc + cnt - 1)) - cnt = MEMSIZE - loc; -for (i = 0; i < cnt; i++) - buf[i] = IOReadB (loc + i); -return cnt; -} - -uint32 IOWriteBlk (uint32 loc, uint32 cnt, uint8 *buf) -{ -uint32 i; - -if (!MEM_ADDR_OK (loc) || (cnt == 0)) - return 0; -if (!MEM_ADDR_OK (loc + cnt - 1)) - cnt = MEMSIZE - loc; -for (i = 0; i < cnt; i++) - IOWriteB (loc + i, buf[i]); -return cnt; -} - -/* Change selector channel for a device */ - -t_stat set_sch (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -DEVICE *dptr; -DIB *dibp; -uint32 newch; -t_stat r; - -if (cptr == NULL) - return SCPE_ARG; -if (uptr == NULL) - return SCPE_IERR; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if ((dibp == NULL) || (dibp->sch < 0)) - return SCPE_IERR; -newch = get_uint (cptr, 16, sch_max - 1, &r); /* get new */ -if (r != SCPE_OK) - return r; -dibp->sch = newch; /* store */ -return SCPE_OK; -} - -/* Show selector channel for a device */ - -t_stat show_sch (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -DEVICE *dptr; -DIB *dibp; - -if (uptr == NULL) - return SCPE_IERR; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if ((dibp == NULL) || (dibp->sch < 0)) - return SCPE_IERR; -fprintf (st, "selch=%X", dibp->sch); -return SCPE_OK; -} - -/* Change device number for a device */ - -t_stat set_dev (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -DEVICE *dptr; -DIB *dibp; -uint32 newdev; -t_stat r; - -if (cptr == NULL) - return SCPE_ARG; -if (uptr == NULL) - return SCPE_IERR; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if (dibp == NULL) - return SCPE_IERR; -newdev = get_uint (cptr, 16, DEV_MAX, &r); /* get new */ -if ((r != SCPE_OK) || (newdev == dibp->dno)) - return r; -if (newdev == 0) /* must be > 0 */ - return SCPE_ARG; -dibp->dno = newdev; /* store */ -return SCPE_OK; -} - -/* Show device number for a device */ - -t_stat show_dev (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -DEVICE *dptr; -DIB *dibp; - -if (uptr == NULL) - return SCPE_IERR; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if ((dibp == NULL) || (dibp->dno == 0)) - return SCPE_IERR; -fprintf (st, "devno=%02X", dibp->dno); -return SCPE_OK; -} - -/* Init device tables */ - -t_bool devtab_init (void) -{ -DEVICE *dptr; -DIB *dibp; -uint32 i, j, dno, dmsk, doff, t, dmap[DEVNO / 32]; -uint8 *tplte, dflt_tplte[] = { 0, TPL_END }; - -/* Clear tables, device map */ - -for (i = 0; i < DEVNO; i++) { - dev_tab[i] = NULL; - sch_tab[i] = 0; - } -for (i = 0; i < (INTSZ * 32); i++) - int_tab[i] = 0; -for (i = 0; i < (DEVNO / 32); i++) - dmap[i] = 0; - -/* Test each device for conflict; add to map; init tables */ - -for (i = 0; (dptr = sim_devices[i]); i++) { /* loop thru devices */ - dibp = (DIB *) dptr->ctxt; /* get DIB */ - if ((dibp == NULL) || (dptr->flags & DEV_DIS)) /* exist, enabled? */ - continue; - dno = dibp->dno; /* get device num */ - if (dibp->ini) /* gen dno template */ - dibp->ini (TRUE); - tplte = dibp->tplte; /* get template */ - if (tplte == NULL) /* none? use default */ - tplte = dflt_tplte; - for ( ; *tplte != TPL_END; tplte++) { /* loop thru template */ - t = (dno + *tplte) & DEV_MAX; /* loop thru template */ - dmsk = 1u << (t & 0x1F); /* bit to test */ - doff = t / 32; /* word to test */ - if (dmap[doff] & dmsk) { /* in use? */ - sim_printf ("Device number conflict, devno = %02X\n", t); - return TRUE; - } - dmap[doff] = dmap[doff] | dmsk; - if (dibp->sch >= 0) - sch_tab[t] = dibp->sch + 1; - dev_tab[t] = dibp->iot; - } - if (dibp->ini) /* gen int template */ - dibp->ini (FALSE); - tplte = dibp->tplte; /* get template */ - if (tplte == NULL) /* none? use default */ - tplte = dflt_tplte; - for (j = dibp->irq; *tplte != TPL_END; j++, tplte++) - int_tab[j] = (dno + *tplte) & DEV_MAX; - } /* end for i */ -return FALSE; -} diff --git a/Interdata/id_lp.c b/Interdata/id_lp.c deleted file mode 100644 index fcb1c09b..00000000 --- a/Interdata/id_lp.c +++ /dev/null @@ -1,333 +0,0 @@ -/* id_lp.c: Interdata line printer - - Copyright (c) 2001-2008, 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 M46-206 line printer - - 27-May-08 RMS Fixed bug in printing test (Davis Johnson) - 19-Jan-07 RMS Added UNIT_TEXT flag - 25-Apr-03 RMS Revised for extended file support -*/ - -#include "id_defs.h" -#include - -/* Device definitions */ - -#define UNIT_V_UC (UNIT_V_UF + 0) /* UC only */ -#define UNIT_UC (1 << UNIT_V_UC) -#define SPC_BASE 0x40 /* spacing base */ -#define VFU_BASE 0x78 /* VFU base */ -#define VFU_WIDTH 0x8 /* VFU width */ -#define LF 0xA -#define VT 0xB -#define VT_VFU 4 /* VFU chan for VT */ -#define FF 0xC -#define FF_VFU 8 /* VFU chan for FF */ -#define CR 0xD -#define VFUP(ch,val) ((val) & (1 << (ch))) /* VFU chan test */ - -/* Status byte, * = dynamic */ - -#define STA_PAPE 0x40 /* *paper empty */ -#define STA_MASK (STA_BSY) /* static status */ - -uint32 lpt_sta = STA_BSY; /* status */ -char lpxb[LPT_WIDTH + 1]; /* line buffer */ -uint32 lpt_bptr = 0; /* buf ptr */ -uint32 lpt_spnd = 0; /* space pending */ -uint32 lpt_vfup = 0; /* VFU ptr */ -uint32 lpt_vful = 1; /* VFU lnt */ -uint8 lpt_vfut[VFU_LNT] = { 0xFF }; /* VFU tape */ -uint32 lpt_arm = 0; /* int armed */ -int32 lpt_ctime = 10; /* char time */ -int32 lpt_stime = 1000; /* space time */ -int32 lpt_stopioe = 0; /* stop on err */ - -extern uint32 int_req[INTSZ], int_enb[INTSZ]; - -DEVICE lpt_dev; -uint32 lpt (uint32 dev, uint32 op, uint32 dat); -t_stat lpt_svc (UNIT *uptr); -t_stat lpt_reset (DEVICE *dptr); -t_stat lpt_attach (UNIT *uptr, char *cptr); -t_stat lpt_bufout (UNIT *uptr); -t_stat lpt_vfu (UNIT *uptr, int32 ch); -t_stat lpt_spc (UNIT *uptr, int32 cnt); - -/* LPT data structures - - lpt_dev LPT device descriptor - lpt_unit LPT unit descriptors - lpt_reg LPT register list -*/ - -DIB lpt_dib = { d_LPT, -1, v_LPT, NULL, &lpt, NULL }; - -UNIT lpt_unit = { UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_UC+UNIT_TEXT, 0) }; - -REG lpt_reg[] = { - { HRDATA (STA, lpt_sta, 8) }, - { HRDATA (BUF, lpt_unit.buf, 7) }, - { BRDATA (DBUF, lpxb, 16, 7, LPT_WIDTH) }, - { HRDATA (DBPTR, lpt_bptr, 8) }, - { HRDATA (VFUP, lpt_vfup, 8) }, - { HRDATA (VFUL, lpt_vful, 8) }, - { BRDATA (VFUT, lpt_vfut, 16, 8, VFU_LNT) }, - { FLDATA (IREQ, int_req[l_LPT], i_LPT) }, - { FLDATA (IENB, int_enb[l_LPT], i_LPT) }, - { FLDATA (IARM, lpt_arm, 0) }, - { DRDATA (POS, lpt_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (CTIME, lpt_ctime, 24), PV_LEFT }, - { DRDATA (STIME, lpt_stime, 24), PV_LEFT }, - { FLDATA (STOP_IOE, lpt_stopioe, 0) }, - { HRDATA (DEVNO, lpt_dib.dno, 8), REG_HRO }, - { NULL } - }; - -MTAB lpt_mod[] = { - { UNIT_UC, 0, "lower case", "LC", NULL }, - { UNIT_UC, UNIT_UC, "upper case", "UC", NULL }, - { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", - &set_dev, &show_dev, NULL }, - { 0 } - }; - -DEVICE lpt_dev = { - "LPT", &lpt_unit, lpt_reg, lpt_mod, - 1, 10, 31, 1, 16, 7, - NULL, NULL, &lpt_reset, - NULL, &lpt_attach, NULL, - &lpt_dib, DEV_DISABLE - }; - -/* Line printer: IO routine */ - -uint32 lpt (uint32 dev, uint32 op, uint32 dat) -{ -int32 t; - -switch (op) { /* case IO op */ - - case IO_ADR: /* select */ - return BY; /* byte only */ - - case IO_OC: /* command */ - lpt_arm = int_chg (v_LPT, dat, lpt_arm); /* upd int ctrl */ - break; - - case IO_WD: /* write */ - t = lpt_unit.buf = dat & 0x7F; /* mask char */ - lpt_sta = STA_BSY; /* set busy */ - if (lpt_spnd || ((t >= LF) && (t <= CR))) /* space op? */ - sim_activate (&lpt_unit, lpt_stime); - else sim_activate (&lpt_unit, lpt_ctime); /* normal char */ - break; - - case IO_SS: /* status */ - t = lpt_sta & STA_MASK; /* status byte */ - if ((lpt_unit.flags & UNIT_ATT) == 0) /* test paper out */ - t = t | STA_EX | STA_PAPE | STA_BSY; - return t; - } - -return 0; -} - -/* Unit service */ - -t_stat lpt_svc (UNIT *uptr) -{ -int32 t; -t_stat r = SCPE_OK; - -lpt_sta = 0; /* clear busy */ -if (lpt_arm) /* armed? intr */ - SET_INT (v_LPT); -if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (lpt_stopioe, SCPE_UNATT); -t = uptr->buf; /* get character */ -if (lpt_spnd || ((t >= LF) && (t < CR))) { /* spc pend or spc op? */ - lpt_spnd = 0; - if (lpt_bufout (uptr) != SCPE_OK) /* print */ - return SCPE_IOERR; - if ((t == 1) || (t == LF)) /* single space */ - lpt_spc (uptr, 1); - else if (t == VT) /* VT->VFU */ - r = lpt_vfu (uptr, VT_VFU - 1); - else if (t == 0xC) /* FF->VFU */ - r = lpt_vfu (uptr, FF_VFU - 1); - else if ((t >= SPC_BASE) && (t < VFU_BASE)) - lpt_spc (uptr, t - SPC_BASE); /* space */ - else if ((t >= VFU_BASE) && (t < VFU_BASE + VFU_WIDTH)) - r = lpt_vfu (uptr, t - VFU_BASE); /* VFU */ - else fputs ("\r", uptr->fileref); /* overprint */ - uptr->pos = ftell (uptr->fileref); /* update position */ - if (ferror (lpt_unit.fileref)) { - perror ("LPT I/O error"); - clearerr (uptr->fileref); - return SCPE_IOERR; - } - } -else if (t == CR) { /* CR? */ - lpt_spnd = 1; /* set spc pend */ - return lpt_bufout (uptr); /* print line */ - } -else if (t >= 0x20) { /* printable? */ - if ((uptr->flags & UNIT_UC) && islower (t)) /* UC only? */ - t = toupper (t); - if (lpt_bptr < LPT_WIDTH) - lpxb[lpt_bptr++] = t; - } -return r; -} - -/* Printing and spacing routines */ - -t_stat lpt_bufout (UNIT *uptr) -{ -int32 i; -t_stat r = SCPE_OK; - -if (lpt_bptr == 0) return SCPE_OK; /* any char in buf? */ -for (i = LPT_WIDTH - 1; (i >= 0) && (lpxb[i] == ' '); i--) - lpxb[i] = 0; /* backscan line */ -if (lpxb[0]) { /* any char left? */ - fputs (lpxb, uptr->fileref); /* write line */ - lpt_unit.pos = ftell (uptr->fileref); /* update position */ - if (ferror (uptr->fileref)) { - perror ("LPT I/O error"); - clearerr (uptr->fileref); - r = SCPE_IOERR; - } - } -lpt_bptr = 0; /* reset buffer */ -for (i = 0; i < LPT_WIDTH; i++) - lpxb[i] = ' '; -lpxb[LPT_WIDTH] = 0; -return r; -} - -t_stat lpt_vfu (UNIT *uptr, int32 ch) -{ -uint32 i, j; - -if ((ch == (FF_VFU - 1)) && VFUP (ch, lpt_vfut[0])) { /* top of form? */ - fputs ("\n\f", uptr->fileref); /* nl + ff */ - lpt_vfup = 0; /* top of page */ - return SCPE_OK; - } -for (i = 1; i < lpt_vful + 1; i++) { /* sweep thru cct */ - lpt_vfup = (lpt_vfup + 1) % lpt_vful; /* adv pointer */ - if (VFUP (ch, lpt_vfut[lpt_vfup])) { /* chan punched? */ - for (j = 0; j < i; j++) - fputc ('\n', uptr->fileref); - return SCPE_OK; - } - } -return STOP_VFU; /* runaway channel */ -} - -t_stat lpt_spc (UNIT *uptr, int32 cnt) -{ -int32 i; - -if (cnt == 0) - fputc ('\r', uptr->fileref); -else { - for (i = 0; i < cnt; i++) - fputc ('\n', uptr->fileref); - lpt_vfup = (lpt_vfup + cnt) % lpt_vful; - } -return SCPE_OK; -} - -/* Reset routine */ - -t_stat lpt_reset (DEVICE *dptr) -{ -int32 i; - -sim_cancel (&lpt_unit); /* deactivate */ -lpt_sta = 0; /* clr busy */ -lpt_bptr = 0; /* clr buf ptr */ -for (i = 0; i < LPT_WIDTH; i++) /* clr buf */ - lpxb[i] = ' '; -lpxb[LPT_WIDTH] = 0; -CLR_INT (v_LPT); /* clearr int */ -CLR_ENB (v_LPT); /* disable int */ -lpt_arm = 0; /* disarm int */ -return SCPE_OK; -} - -/* Attach routine */ - -t_stat lpt_attach (UNIT *uptr, char *cptr) -{ -lpt_vfup = 0; /* top of form */ -return attach_unit (uptr, cptr); -} - -/* Carriage control load routine */ - -t_stat lp_load (FILE *fileref, char *cptr, char *fnam) -{ -int32 col, ptr, mask, vfubuf[VFU_LNT]; -uint32 rpt; -t_stat r; -char cbuf[CBUFSIZE], gbuf[CBUFSIZE]; - -if (*cptr != 0) - return SCPE_ARG; -ptr = 0; -for ( ; (cptr = fgets (cbuf, CBUFSIZE, fileref)) != NULL; ) { /* until eof */ - mask = 0; - if (*cptr == '(') { /* repeat count? */ - cptr = get_glyph (cptr + 1, gbuf, ')'); /* get 1st field */ - rpt = get_uint (gbuf, 10, VFU_LNT, &r); /* repeat count */ - if (r != SCPE_OK) - return SCPE_FMT; - } - else rpt = 1; - while (*cptr != 0) { /* get col no's */ - cptr = get_glyph (cptr, gbuf, ','); /* get next field */ - col = get_uint (gbuf, 10, 7, &r); /* column number */ - if (r != SCPE_OK) - return SCPE_FMT; - mask = mask | (1 << col); /* set bit */ - } - for ( ; rpt > 0; rpt--) { /* store vals */ - if (ptr >= VFU_LNT) - return SCPE_FMT; - vfubuf[ptr++] = mask; - } - } -if (ptr == 0) - return SCPE_FMT; -lpt_vful = ptr; -lpt_vfup = 0; -for (rpt = 0; rpt < lpt_vful; rpt++) - lpt_vfut[rpt] = vfubuf[rpt]; -return SCPE_OK; -} diff --git a/Interdata/id_mt.c b/Interdata/id_mt.c deleted file mode 100644 index f9209d82..00000000 --- a/Interdata/id_mt.c +++ /dev/null @@ -1,545 +0,0 @@ -/* id_mt.c: Interdata magnetic tape simulator - - Copyright (c) 2001-2008, 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. - - mt M46-494 dual density 9-track magtape controller - - 16-Feb-06 RMS Added tape capacity checking - 18-Mar-05 RMS Added attached test to detach routine - 07-Dec-04 RMS Added read-only file support - 25-Apr-03 RMS Revised for extended file support - 28-Mar-03 RMS Added multiformat support - 28-Feb-03 RMS Revised for magtape library - 20-Feb-03 RMS Fixed read to stop selch on error - - Magnetic tapes are represented as a series of variable 8b records - of the form: - - 32b record length in bytes - exact number - byte 0 - byte 1 - : - byte n-2 - byte n-1 - 32b record length in bytes - exact number - - 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. -*/ - -#include "id_defs.h" -#include "sim_tape.h" - -#define UST u3 /* unit status */ -#define UCMD u4 /* unit command */ -#define MT_MAXFR (1 << 24) /* max transfer */ - -/* Command - in UCMD */ - -#define MTC_SPCR 0x11 /* backspace */ -#define MTC_SKFR 0x13 /* space file rev */ -#define MTC_CLR 0x20 /* clear */ -#define MTC_RD 0x21 /* read */ -#define MTC_WR 0x22 /* write */ -#define MTC_SKFF 0x23 /* space file fwd */ -#define MTC_WEOF 0x30 /* write eof */ -#define MTC_REW 0x38 /* rewind */ -#define MTC_MASK 0x3F -#define MTC_STOP1 0x40 /* stop, set EOM */ -#define MTC_STOP2 0x80 /* stop, set NMTN */ - -/* Status byte, * = in UST */ - -#define STA_ERR 0x80 /* error */ -#define STA_EOF 0x40 /* end of file */ -#define STA_EOT 0x20 /* *end of tape */ -#define STA_NMTN 0x10 /* *no motion */ -#define STA_UFLGS (STA_EOT|STA_NMTN) /* unit flags */ -#define STA_MASK (STA_ERR|STA_EOF|STA_BSY|STA_EOM) -#define SET_EX (STA_ERR|STA_EOF|STA_NMTN) - -extern uint32 int_req[INTSZ], int_enb[INTSZ]; - -uint8 mtxb[MT_MAXFR]; /* xfer buffer */ -uint32 mt_bptr = 0; /* pointer */ -uint32 mt_blnt = 0; /* length */ -uint32 mt_sta = 0; /* status byte */ -uint32 mt_db = 0; /* data buffer */ -uint32 mt_xfr = 0; /* data xfr in prog */ -uint32 mt_arm[MT_NUMDR] = { 0 }; /* intr armed */ -int32 mt_wtime = 10; /* byte latency */ -int32 mt_rtime = 1000; /* record latency */ -int32 mt_stopioe = 1; /* stop on error */ -uint8 mt_tplte[] = { 0, o_MT0, o_MT0*2, o_MT0*3, TPL_END }; - -static const uint8 bad_cmd[64] = { - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1 - }; - -DEVICE mt_dev; -uint32 mt (uint32 dev, uint32 op, uint32 dat); -t_stat mt_svc (UNIT *uptr); -t_stat mt_reset (DEVICE *dptr); -t_stat mt_attach (UNIT *uptr, char *cptr); -t_stat mt_detach (UNIT *uptr); -t_stat mt_boot (int32 unitno, DEVICE *dptr); -t_stat mt_map_err (UNIT *uptr, t_stat st); - -/* MT data structures - - mt_dev MT device descriptor - mt_unit MT unit list - mt_reg MT register list - mt_mod MT modifier list -*/ - -DIB mt_dib = { d_MT, 0, v_MT, mt_tplte, &mt, NULL }; - -UNIT mt_unit[] = { - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) }, - { UDATA (&mt_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) } - }; - -REG mt_reg[] = { - { HRDATA (STA, mt_sta, 8) }, - { HRDATA (BUF, mt_db, 8) }, - { BRDATA (DBUF, mtxb, 16, 8, MT_MAXFR) }, - { HRDATA (DBPTR, mt_bptr, 16) }, - { HRDATA (DBLNT, mt_blnt, 17), REG_RO }, - { FLDATA (XFR, mt_xfr, 0) }, - { GRDATA (IREQ, int_req[l_MT], 16, MT_NUMDR, i_MT) }, - { GRDATA (IENB, int_enb[l_MT], 16, MT_NUMDR, i_MT) }, - { BRDATA (IARM, mt_arm, 16, 1, MT_NUMDR) }, - { FLDATA (STOP_IOE, mt_stopioe, 0) }, - { DRDATA (WTIME, mt_wtime, 24), PV_LEFT + REG_NZ }, - { DRDATA (RTIME, mt_rtime, 24), PV_LEFT + REG_NZ }, - { URDATA (UST, mt_unit[0].UST, 16, 8, 0, MT_NUMDR, 0) }, - { URDATA (CMD, mt_unit[0].UCMD, 16, 8, 0, MT_NUMDR, 0) }, - { URDATA (POS, mt_unit[0].pos, 10, T_ADDR_W, 0, - MT_NUMDR, PV_LEFT | REG_RO) }, - { HRDATA (DEVNO, mt_dib.dno, 8), REG_HRO }, - { HRDATA (SELCH, mt_dib.sch, 1), REG_HRO }, - { NULL } - }; - -MTAB mt_mod[] = { - { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, - { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT", - &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, - { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", "CAPACITY", - &sim_tape_set_capac, &sim_tape_show_capac, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", - &set_dev, &show_dev, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "SELCH", "SELCH", - &set_sch, &show_sch, NULL }, - { 0 } - }; - -DEVICE mt_dev = { - "MT", mt_unit, mt_reg, mt_mod, - MT_NUMDR, 10, 31, 1, 16, 8, - NULL, NULL, &mt_reset, - &mt_boot, &mt_attach, &mt_detach, - &mt_dib, DEV_DISABLE | DEV_TAPE - }; - -/* Magtape: IO routine */ - -uint32 mt (uint32 dev, uint32 op, uint32 dat) -{ -uint32 i, f, t; -uint32 u = (dev - mt_dib.dno) / o_MT0; -UNIT *uptr = mt_dev.units + u; - -switch (op) { /* case IO op */ - - case IO_ADR: /* select */ - sch_adr (mt_dib.sch, dev); /* inform sel ch */ - return BY; /* byte only */ - - case IO_RD: /* read data */ - if (mt_xfr) /* xfr? set busy */ - mt_sta = mt_sta | STA_BSY; - return mt_db; /* return data */ - - case IO_WD: /* write data */ - if (mt_xfr) { /* transfer? */ - mt_sta = mt_sta | STA_BSY; /* set busy */ - if ((uptr->UCMD & (MTC_STOP1 | MTC_STOP2)) && - ((uptr->UCMD & MTC_MASK) == MTC_WR)) /* while stopping? */ - mt_sta = mt_sta | STA_ERR; /* write overrun */ - } - mt_db = dat & DMASK8; /* store data */ - break; - - case IO_SS: /* status */ - mt_sta = mt_sta & STA_MASK; /* ctrl status */ - if (uptr->flags & UNIT_ATT) /* attached? */ - t = mt_sta | (uptr->UST & STA_UFLGS); /* yes, unit status */ - else t = mt_sta | STA_DU; /* no, dev unavail */ - if (t & SET_EX) /* test for ex */ - t = t | STA_EX; - return t; - - case IO_OC: /* command */ - mt_arm[u] = int_chg (v_MT + u, dat, mt_arm[u]); - f = dat & MTC_MASK; /* get cmd */ - if (f == MTC_CLR) { /* clear? */ - mt_reset (&mt_dev); /* reset world */ - break; - } - if (((uptr->flags & UNIT_ATT) == 0) || /* ignore if unatt */ - bad_cmd[f] || /* or bad cmd */ - (((f == MTC_WR) || (f == MTC_WEOF)) && /* or write */ - sim_tape_wrp (uptr))) /* and protected */ - break; - for (i = 0; i < MT_NUMDR; i++) { /* check other drvs */ - if (sim_is_active (&mt_unit[i]) && /* active? */ - (mt_unit[i].UCMD != MTC_REW)) { /* not rewind? */ - sim_cancel (&mt_unit[i]); /* stop */ - mt_unit[i].UCMD = 0; - } - } - if (sim_is_active (uptr) && /* unit active? */ - !(uptr->UCMD & (MTC_STOP1 | MTC_STOP2))) /* not stopping? */ - break; /* ignore */ - if ((f == MTC_WR) || (f == MTC_REW)) /* write, rew: bsy=0 */ - mt_sta = 0; - else mt_sta = STA_BSY; /* bsy=1,nmtn,eom,err=0 */ - mt_bptr = mt_blnt = 0; /* not yet started */ - if ((f == MTC_RD) || (f == MTC_WR)) /* data xfr? */ - mt_xfr = 1; /* set xfr flag */ - else mt_xfr = 0; - uptr->UCMD = f; /* save cmd */ - uptr->UST = 0; /* clr tape stat */ - sim_activate (uptr, mt_rtime); /* start op */ - break; - } - -return 0; -} - -/* Unit service - - A given operation can generate up to three interrupts - - - EOF generates an interrupt when set (read, space, wreof) - BUSY will still be set, EOM and NMTN will be clear - - After operation complete + delay, EOM generates an interrupt - BUSY will be clear, EOM will be set, NMTN will be clear - - After a further delay, NMTN generates an interrupt - BUSY will be clear, EOM and NMTN will be set - - Rewind generates an interrupt when NMTN sets -*/ - -t_stat mt_svc (UNIT *uptr) -{ -uint32 i; -int32 u = uptr - mt_dev.units; -uint32 dev = mt_dib.dno + (u * o_MT0); -t_mtrlnt tbc; -t_bool passed_eot; -t_stat st, r = SCPE_OK; - -if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ - uptr->UCMD = 0; /* clr cmd */ - uptr->UST = 0; /* set status */ - mt_xfr = 0; /* clr op flags */ - mt_sta = STA_ERR | STA_EOM; /* set status */ - if (mt_arm[u]) /* interrupt */ - SET_INT (v_MT + u); - return IORETURN (mt_stopioe, SCPE_UNATT); - } - -if (uptr->UCMD & MTC_STOP2) { /* stop, gen NMTN? */ - uptr->UCMD = 0; /* clr cmd */ - uptr->UST = uptr->UST | STA_NMTN; /* set nmtn */ - mt_xfr = 0; /* clr xfr */ - if (mt_arm[u]) /* set intr */ - SET_INT (v_MT + u); - return SCPE_OK; - } - -if (uptr->UCMD & MTC_STOP1) { /* stop, gen EOM? */ - uptr->UCMD = uptr->UCMD | MTC_STOP2; /* clr cmd */ - mt_sta = (mt_sta & ~STA_BSY) | STA_EOM; /* clr busy, set eom */ - if (mt_arm[u]) /* set intr */ - SET_INT (v_MT + u); - sim_activate (uptr, mt_rtime); /* schedule */ - return SCPE_OK; - } - -passed_eot = sim_tape_eot (uptr); /* passed EOT? */ -switch (uptr->UCMD) { /* case on function */ - - case MTC_REW: /* rewind */ - sim_tape_rewind (uptr); /* reposition */ - uptr->UCMD = 0; /* clr cmd */ - uptr->UST = STA_NMTN | STA_EOT; /* update status */ - mt_sta = mt_sta & ~STA_BSY; /* don't set EOM */ - if (mt_arm[u]) /* interrupt */ - SET_INT (v_MT + u); - return SCPE_OK; - -/* For read, busy = 1 => buffer empty - For write, busy = 1 => buffer full - For read, data transfers continue for the full length of the - record, or the maximum size of the transfer buffer - For write, data transfers continue until a write is attempted - and the buffer is empty -*/ - - case MTC_RD: /* read */ - if (mt_blnt == 0) { /* first time? */ - st = sim_tape_rdrecf (uptr, mtxb, &tbc, MT_MAXFR); /* read rec */ - if (st == MTSE_RECE) /* rec in err? */ - mt_sta = mt_sta | STA_ERR; - else if (st != SCPE_OK) { /* other error? */ - r = mt_map_err (uptr, st); /* map error */ - if (sch_actv (mt_dib.sch, dev)) /* if sch, stop */ - sch_stop (mt_dib.sch); - break; - } - mt_blnt = tbc; /* set buf lnt */ - } - - if (sch_actv (mt_dib.sch, dev)) { /* sch active? */ - i = sch_wrmem (mt_dib.sch, mtxb, mt_blnt); /* store rec in mem */ - if (sch_actv (mt_dib.sch, dev)) /* sch still active? */ - sch_stop (mt_dib.sch); /* stop chan, long rd */ - else if (i < mt_blnt) /* process entire rec? */ - mt_sta = mt_sta | STA_ERR; /* no, overrun error */ - } - else if (mt_bptr < mt_blnt) { /* no, if !eor */ - if (!(mt_sta & STA_BSY)) /* busy still clr? */ - mt_sta = mt_sta | STA_ERR; /* read overrun */ - mt_db = mtxb[mt_bptr++]; /* get next byte */ - mt_sta = mt_sta & ~STA_BSY; /* !busy = buf full */ - if (mt_arm[u]) /* set intr */ - SET_INT (v_MT + u); - sim_activate (uptr, mt_wtime); /* reschedule */ - return SCPE_OK; - } - break; /* record done */ - - case MTC_WR: /* write */ - if (sch_actv (mt_dib.sch, dev)) { /* sch active? */ - mt_bptr = sch_rdmem (mt_dib.sch, mtxb, MT_MAXFR); /* get rec */ - if (sch_actv (mt_dib.sch, dev)) /* not done? */ - sch_stop (mt_dib.sch); /* stop chan */ - } - else if (mt_sta & STA_BSY) { /* no, if !eor */ - if (mt_bptr < MT_MAXFR) /* if room */ - mtxb[mt_bptr++] = mt_db; /* store in buf */ - mt_sta = mt_sta & ~STA_BSY; /* !busy = buf emp */ - if (mt_arm[u]) /* set intr */ - SET_INT (v_MT + u); - sim_activate (uptr, mt_wtime); /* reschedule */ - return SCPE_OK; - } - - if (mt_bptr) { /* any chars? */ - if ((st = sim_tape_wrrecf (uptr, mtxb, mt_bptr)))/* write, err? */ - r = mt_map_err (uptr, st); /* map error */ - } - break; /* record done */ - - case MTC_WEOF: /* write eof */ - if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ - r = mt_map_err (uptr, st); /* map error */ - mt_sta = mt_sta | STA_EOF; /* set eof */ - if (mt_arm[u]) /* set intr */ - SET_INT (v_MT + u); - break; - - case MTC_SKFF: /* skip file fwd */ - while ((st = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ; - if (st == MTSE_TMK) { /* stopped by tmk? */ - mt_sta = mt_sta | STA_EOF; /* set eof */ - if (mt_arm[u]) /* set intr */ - SET_INT (v_MT + u); - } - else r = mt_map_err (uptr, st); /* map error */ - break; - - case MTC_SKFR: /* skip file rev */ - while ((st = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ; - if (st == MTSE_TMK) { /* stopped by tmk? */ - mt_sta = mt_sta | STA_EOF; /* set eof */ - if (mt_arm[u]) /* set intr */ - SET_INT (v_MT + u); - } - else r = mt_map_err (uptr, st); /* map error */ - break; - - case MTC_SPCR: /* backspace */ - if ((st = sim_tape_sprecr (uptr, &tbc))) /* skip rec rev, err? */ - r = mt_map_err (uptr, st); /* map error */ - break; - } /* end case */ - -if (!passed_eot && sim_tape_eot (uptr)) /* just passed EOT? */ - uptr->UST = uptr->UST | STA_EOT; -uptr->UCMD = uptr->UCMD | MTC_STOP1; /* set stop stage 1 */ -sim_activate (uptr, mt_rtime); /* schedule */ -return r; -} - -/* Map tape error status */ - -t_stat mt_map_err (UNIT *uptr, t_stat st) -{ -int32 u = uptr - mt_dev.units; - -switch (st) { - - case MTSE_FMT: /* illegal fmt */ - case MTSE_UNATT: /* not attached */ - mt_sta = mt_sta | STA_ERR; - case MTSE_OK: /* no error */ - return SCPE_IERR; - - case MTSE_TMK: /* end of file */ - mt_sta = mt_sta | STA_EOF; /* set eof */ - if (mt_arm[u]) /* set intr */ - SET_INT (v_MT + u); - break; - - case MTSE_IOERR: /* IO error */ - mt_sta = mt_sta | STA_ERR; /* set err */ - if (mt_stopioe) - return SCPE_IOERR; - break; - - case MTSE_INVRL: /* invalid rec lnt */ - mt_sta = mt_sta | STA_ERR; - return SCPE_MTRLNT; - - case MTSE_WRP: /* write protect */ - case MTSE_RECE: /* record in error */ - case MTSE_EOM: /* end of medium */ - mt_sta = mt_sta | STA_ERR; /* set err */ - break; - - case MTSE_BOT: /* reverse into BOT */ - uptr->UST = uptr->UST | STA_EOT; /* set err */ - break; - } /* end switch */ - -return SCPE_OK; -} - -/* Reset routine */ - -t_stat mt_reset (DEVICE *dptr) -{ -uint32 u; -UNIT *uptr; - -mt_bptr = mt_blnt = 0; /* clr buf */ -mt_sta = STA_BSY; /* clr flags */ -mt_xfr = 0; /* clr controls */ -for (u = 0; u < MT_NUMDR; u++) { /* loop thru units */ - CLR_INT (v_MT + u); /* clear int */ - CLR_ENB (v_MT + u); /* disable int */ - mt_arm[u] = 0; /* disarm int */ - uptr = mt_dev.units + u; - sim_tape_reset (uptr); /* clear pos flag */ - sim_cancel (uptr); /* cancel activity */ - uptr->UST = (uptr->UST & STA_UFLGS) | STA_NMTN; /* init status */ - uptr->UCMD = 0; /* init cmd */ - } -return SCPE_OK; -} - -/* Attach routine */ - -t_stat mt_attach (UNIT *uptr, char *cptr) -{ -int32 u = uptr - mt_dev.units; -t_stat r; - -r = sim_tape_attach (uptr, cptr); -if (r != SCPE_OK) - return r; -uptr->UST = STA_EOT; -if (mt_arm[u]) - SET_INT (v_MT + u); -return r; -} - -/* Detach routine */ - -t_stat mt_detach (UNIT* uptr) -{ -int32 u = uptr - mt_dev.units; -t_stat r; - -if (!(uptr->flags & UNIT_ATT)) - return SCPE_OK; -r = sim_tape_detach (uptr); -if (r != SCPE_OK) - return r; -if (mt_arm[u]) - SET_INT (v_MT + u); -uptr->UST = 0; -return SCPE_OK; -} - -/* Bootstrap routine */ - -#define BOOT_START 0x50 -#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint8)) - -static uint8 boot_rom[] = { - 0xD5, 0x00, 0x00, 0xCF, /* ST: AL CF */ - 0x43, 0x00, 0x00, 0x80 /* BR 80 */ - }; - -t_stat mt_boot (int32 unitno, DEVICE *dptr) -{ -extern uint32 PC, dec_flgs; -extern uint16 decrom[]; -extern DIB sch_dib; -uint32 sch_dev; - -if (decrom[0xD5] & dec_flgs) /* AL defined? */ - return SCPE_NOFNC; -sim_tape_rewind (&mt_unit[unitno]); /* rewind */ -sch_dev = sch_dib.dno + mt_dib.sch; /* sch dev # */ -IOWriteBlk (BOOT_START, BOOT_LEN, boot_rom); /* copy boot */ -IOWriteB (AL_DEV, mt_dib.dno + (unitno * o_MT0)); /* set dev no for unit */ -IOWriteB (AL_IOC, 0xA1); /* set dev cmd */ -IOWriteB (AL_SCH, sch_dev); /* set dev no for chan */ -PC = BOOT_START; -return SCPE_OK; -} diff --git a/Interdata/id_pas.c b/Interdata/id_pas.c deleted file mode 100644 index 9874b7df..00000000 --- a/Interdata/id_pas.c +++ /dev/null @@ -1,577 +0,0 @@ -/* id_pas.c: Interdata programmable async line adapter simulator - - Copyright (c) 2001-2013, 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. - - pas Programmable asynchronous line adapter(s) - - 11-Oct-13 RMS Poll PAS immediately to pick up initial connect - 18-Apr-12 RMS Revised to use clock coscheduling - 21-Mar-12 RMS Fixed TT_GET_MODE test to use TTUF_MODE_x (Michael Bloom) - 19-Nov-08 RMS Revised for common TMXR show routines - 18-Jun-07 RMS Added UNIT_IDLE flag - 18-Oct-06 RMS Synced PASLA to clock - 22-Nov-05 RMS Revised for new terminal processing routines - 29-Jun-05 RMS Added SET PASLn DISCONNECT - 21-Jun-05 RMS Fixed bug in SHOW CONN/STATS - 05-Jan-04 RMS Revised for tmxr library changes - 09-May-03 RMS Added network device flag - - This module implements up to 32 individual serial interfaces, representing - either individual PASLA modules or combinations of the 2-line and 8-line - multiplexors, which are functionally very similar. These interfaces are mapped - to Telnet based connections as the lines of a terminal multiplexor. The - connection polling mechanism and the character input polling for all lines - are done through a single polling job. -*/ - -#include "id_defs.h" -#include "sim_sock.h" -#include "sim_tmxr.h" -#include - -#define PAS_LINES 32 - -#define UNIT_V_MDM (TTUF_V_UF + 0) /* modem control */ -#define UNIT_MDM (1 << UNIT_V_MDM) - -#define PASL_WAIT 500 - -/* Status byte */ - -#define STA_OVR 0x80 /* overrun RO */ -#define STA_PF 0x40 /* parity err RONI */ -#define STA_NCL2S 0x40 /* not clr to snd XO */ -#define STA_FR 0x20 /* framing err RO */ -#define STA_RCR 0x10 /* rv chan rcv NI */ -#define STA_CROF 0x02 /* carrier off RO */ -#define STA_RING 0x01 /* ring RO */ -#define STA_RCV (STA_OVR|STA_PF|STA_FR|STA_RCR|STA_CROF|STA_RING) -#define SET_EX (STA_OVR|STA_PF|STA_FR) -#define STA_XMT (STA_BSY) - -/* Command bytes 1,0 */ - -#define CMD_DTR (0x20 << 8) /* DTR */ -#define CMD_ECHO (0x10 << 8) /* echoplex */ -#define CMD_RCT (0x08 << 8) /* RCT/DTB NI */ -#define CMD_XMTB (0x04 << 8) /* xmt break NI */ -#define CMD_WRT (0x02 << 8) /* write/read */ -#define CMD_V_CLK 6 /* baud rate */ -#define CMD_M_CLK 0x3 -#define CMD_V_DB 4 /* data bits */ -#define CMD_M_DB 0x3 -#define CMD_STOP 0x80 /* stop bit */ -#define CMD_V_PAR 1 /* parity */ -#define CMD_M_PAR 0x3 -#define GET_PAR(x) (((x) >> CMD_V_PAR) & CMD_M_PAR) -#define PAR_NONE 0 -#define PAR_RAW 1 -#define PAR_ODD 2 -#define PAR_EVEN 3 - -#define CMD_TYP 0x01 /* command type */ - -extern uint32 int_req[INTSZ], int_enb[INTSZ]; -extern int32 lfc_poll; - -uint8 pas_sta[PAS_LINES]; /* status */ -uint16 pas_cmd[PAS_LINES]; /* command */ -uint8 pas_rbuf[PAS_LINES]; /* rcv buf */ -uint8 pas_xbuf[PAS_LINES]; /* xmt buf */ -uint8 pas_rarm[PAS_LINES]; /* rcvr int armed */ -uint8 pas_xarm[PAS_LINES]; /* xmt int armed */ -uint8 pas_rchp[PAS_LINES]; /* rcvr chr pend */ -uint8 pas_tplte[PAS_LINES * 2 + 1]; /* template */ - -TMLN pas_ldsc[PAS_LINES] = { {0} }; /* line descriptors */ -TMXR pas_desc = { 8, 0, 0, pas_ldsc }; /* mux descriptor */ -#define PAS_ENAB pas_desc.lines - -uint32 pas (uint32 dev, uint32 op, uint32 dat); -void pas_ini (t_bool dtpl); -t_stat pasi_svc (UNIT *uptr); -t_stat paso_svc (UNIT *uptr); -t_stat pas_reset (DEVICE *dptr); -t_stat pas_attach (UNIT *uptr, char *cptr); -t_stat pas_detach (UNIT *uptr); -int32 pas_par (int32 cmd, int32 c); -t_stat pas_vlines (UNIT *uptr, int32 val, char *cptr, void *desc); -void pas_reset_ln (int32 i); - -/* PAS data structures - - pas_dev PAS device descriptor - pas_unit PAS unit descriptor - pas_reg PAS register list - pas_mod PAS modifiers list -*/ - -DIB pas_dib = { d_PAS, -1, v_PAS, pas_tplte, &pas, &pas_ini }; - -UNIT pas_unit = { UDATA (&pasi_svc, UNIT_ATTABLE|UNIT_IDLE, 0), 0 }; - -REG pas_reg[] = { - { BRDATA (STA, pas_sta, 16, 8, PAS_LINES) }, - { BRDATA (CMD, pas_cmd, 16, 16, PAS_LINES) }, - { BRDATA (RBUF, pas_rbuf, 16, 8, PAS_LINES) }, - { BRDATA (XBUF, pas_xbuf, 16, 8, PAS_LINES) }, - { BRDATA (IREQ, &int_req[l_PAS], 16, 32, PAS_LINES / 16) }, - { BRDATA (IENB, &int_enb[l_PAS], 16, 32, PAS_LINES / 16) }, - { BRDATA (RARM, pas_rarm, 16, 1, PAS_LINES) }, - { BRDATA (XARM, pas_xarm, 16, 1, PAS_LINES) }, - { BRDATA (RCHP, pas_rchp, 16, 1, PAS_LINES) }, - { HRDATA (DEVNO, pas_dib.dno, 8), REG_HRO }, - { NULL } - }; - -MTAB pas_mod[] = { - { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", - &tmxr_dscln, NULL, (void *) &pas_desc }, - { UNIT_ATT, UNIT_ATT, "summary", NULL, - NULL, &tmxr_show_summ, (void *) &pas_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, - NULL, &tmxr_show_cstat, (void *) &pas_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, - NULL, &tmxr_show_cstat, (void *) &pas_desc }, - { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", - &set_dev, &show_dev, NULL }, - { MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES", - &pas_vlines, &tmxr_show_lines, (void *) &pas_desc }, - { 0 } - }; - -DEVICE pas_dev = { - "PAS", &pas_unit, pas_reg, pas_mod, - 1, 10, 31, 1, 16, 8, - &tmxr_ex, &tmxr_dep, &pas_reset, - NULL, &pas_attach, &pas_detach, - &pas_dib, DEV_MUX | DEV_DISABLE - }; - -/* PASL data structures - - pasl_dev PASL device descriptor - pasl_unit PASL unit descriptor - pasl_reg PASL register list - pasl_mod PASL modifiers list -*/ - -UNIT pasl_unit[] = { - { UDATA (&paso_svc, 0, 0), PASL_WAIT }, /* all but 8 dis */ - { UDATA (&paso_svc, 0, 0), PASL_WAIT }, - { UDATA (&paso_svc, 0, 0), PASL_WAIT }, - { UDATA (&paso_svc, 0, 0), PASL_WAIT }, - { UDATA (&paso_svc, 0, 0), PASL_WAIT }, - { UDATA (&paso_svc, 0, 0), PASL_WAIT }, - { UDATA (&paso_svc, 0, 0), PASL_WAIT }, - { UDATA (&paso_svc, 0, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT }, - { UDATA (&paso_svc, UNIT_DIS, 0), PASL_WAIT } - }; - -MTAB pasl_mod[] = { - { TT_MODE, TT_MODE_UC, "UC", "UC", NULL }, - { TT_MODE, TT_MODE_7B, "7b", "7B", NULL }, - { TT_MODE, TT_MODE_8B, "8b", "8B", NULL }, - { TT_MODE, TT_MODE_7P, "7p", "7P", NULL }, - { UNIT_MDM, 0, "no dataset", "NODATASET", NULL }, - { UNIT_MDM, UNIT_MDM, "dataset", "DATASET", NULL }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "DISCONNECT", - &tmxr_dscln, NULL, &pas_desc }, - { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG", - &tmxr_set_log, &tmxr_show_log, &pas_desc }, - { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG", - &tmxr_set_nolog, NULL, &pas_desc }, - { 0 } - }; - -REG pasl_reg[] = { - { URDATA (TIME, pasl_unit[0].wait, 16, 24, 0, - PAS_LINES, REG_NZ + PV_LEFT) }, - { NULL } - }; - -DEVICE pasl_dev = { - "PASL", pasl_unit, pasl_reg, pasl_mod, - PAS_LINES, 10, 31, 1, 16, 8, - NULL, NULL, &pas_reset, - NULL, NULL, NULL, - NULL, 0 - }; - -/* PAS: IO routine */ - -uint32 pas (uint32 dev, uint32 op, uint32 dat) -{ -int32 ln = (dev - pas_dib.dno) >> 1; -int32 xmt = (dev - pas_dib.dno) & 1; -int32 t, old_cmd; - -switch (op) { /* case IO op */ - - case IO_ADR: /* select */ - return BY; /* byte only */ - - case IO_RD: /* read */ - pas_rchp[ln] = 0; /* clr chr pend */ - pas_sta[ln] = pas_sta[ln] & ~STA_OVR; /* clr overrun */ - return pas_rbuf[ln]; /* return buf */ - - case IO_WD: /* write */ - pas_xbuf[ln] = dat & 0xFF; /* store char */ - pas_sta[ln] = pas_sta[ln] | STA_BSY; /* set busy */ - sim_activate (&pasl_unit[ln], pasl_unit[ln].wait); - break; - - case IO_SS: /* status */ - if (xmt) { /* xmt side? */ - if (pas_ldsc[ln].conn == 0) /* not conn? */ - t = STA_NCL2S | STA_BSY; /* busy, not clr */ - else t = pas_sta[ln] & STA_XMT; /* else just busy */ - } - else { - t = pas_sta[ln] & STA_RCV; /* get static */ - if (!pas_rchp[ln]) /* no char? busy */ - t = t | STA_BSY; - if (pas_ldsc[ln].conn == 0) /* not connected? */ - t = t | STA_BSY | STA_EX; /* = !dsr */ - if (t & SET_EX) /* test for ex */ - t = t | STA_EX; - } - return t; - - case IO_OC: /* command */ - old_cmd = pas_cmd[ln]; /* old cmd */ - if (dat & CMD_TYP) { /* type 1? */ - pas_cmd[ln] = (pas_cmd[ln] & 0xFF) | (dat << 8); - if (pas_cmd[ln] & CMD_WRT) /* write? */ - pas_xarm[ln] = int_chg (v_PASX + ln + ln, dat, pas_xarm[ln]); - else pas_rarm[ln] = int_chg (v_PAS + ln + ln, dat, pas_rarm[ln]); - } - else pas_cmd[ln] = (pas_cmd[ln] & ~0xFF) | dat; - if (pasl_unit[ln].flags & UNIT_MDM) { /* modem ctrl? */ - if ((pas_cmd[ln] & CMD_DTR) && (pas_sta[ln] & STA_RING)) - pas_sta[ln] = pas_sta[ln] & ~(STA_CROF | STA_RING); - if (old_cmd & ~pas_cmd[ln] & CMD_DTR) { - tmxr_linemsg (&pas_ldsc[ln], "\r\nLine hangup\r\n"); - tmxr_reset_ln (&pas_ldsc[ln]); /* reset line */ - pas_sta[ln] = pas_sta[ln] | STA_CROF; /* no carrier */ - if (pas_rarm[ln]) - SET_INT (v_PAS + ln + ln); - } - } - break; - } - -return 0; -} - -/* Unit service - receive side - - Poll all active lines for input - Poll for new connections -*/ - -t_stat pasi_svc (UNIT *uptr) -{ -int32 ln, c, out; - -if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ - return SCPE_OK; -sim_activate (uptr, lfc_cosched (lfc_poll)); /* continue poll */ -ln = tmxr_poll_conn (&pas_desc); /* look for connect */ -if (ln >= 0) { /* got one? */ - if ((pasl_unit[ln].flags & UNIT_MDM) && /* modem control */ - ((pas_cmd[ln] & CMD_DTR) == 0)) /* & !dtr? */ - pas_sta[ln] = pas_sta[ln] | STA_RING | STA_CROF; /* set ring, no cd */ - else pas_sta[ln] = pas_sta[ln] & ~STA_CROF; /* just answer */ - if (pas_rarm[ln]) /* interrupt */ - SET_INT (v_PAS + ln + ln); - pas_ldsc[ln].rcve = 1; /* rcv enabled */ - } -tmxr_poll_rx (&pas_desc); /* poll for input */ -for (ln = 0; ln < PAS_ENAB; ln++) { /* loop thru lines */ - if (pas_ldsc[ln].conn) { /* connected? */ - if ((c = tmxr_getc_ln (&pas_ldsc[ln]))) { /* any char? */ - pas_sta[ln] = pas_sta[ln] & ~(STA_FR | STA_PF); - if (pas_rchp[ln]) - pas_sta[ln] = pas_sta[ln] | STA_OVR; - if (pas_rarm[ln]) - SET_INT (v_PAS + ln + ln); - if (c & SCPE_BREAK) { /* break? */ - pas_sta[ln] = pas_sta[ln] | STA_FR; /* framing error */ - pas_rbuf[ln] = 0; /* no character */ - } - else { /* normal */ - out = c & 0x7F; /* echo is 7b */ - c = sim_tt_inpcvt (c, TT_GET_MODE (pasl_unit[ln].flags)); - if (TT_GET_MODE (pasl_unit[ln].flags) != TTUF_MODE_8B) - c = pas_par (pas_cmd[ln], c); /* apply parity */ - pas_rbuf[ln] = c; /* save char */ - pas_rchp[ln] = 1; /* char pending */ - if ((pas_cmd[ln] & CMD_ECHO) && pas_ldsc[ln].xmte) { - TMLN *lp = &pas_ldsc[ln]; /* get line */ - out = sim_tt_outcvt (out, TT_GET_MODE (pasl_unit[ln].flags)); - if (out >= 0) /* output char */ - tmxr_putc_ln (lp, out); - tmxr_poll_tx (&pas_desc); /* poll xmt */ - } - } /* end else normal */ - } /* end if char */ - } /* end if conn */ - else if ((pas_sta[ln] & STA_CROF) == 0) { /* not conn, was conn? */ - pas_sta[ln] = pas_sta[ln] | STA_CROF; /* no carrier */ - if (pas_rarm[ln]) /* intr */ - SET_INT (v_PAS + ln + ln); - } - } /* end for */ -return SCPE_OK; -} - -/* Unit service - transmit side */ - -t_stat paso_svc (UNIT *uptr) -{ -int32 c; -uint32 ln = uptr - pasl_unit; /* line # */ - -if (pas_ldsc[ln].conn) { /* connected? */ - if (pas_ldsc[ln].xmte) { /* xmt enabled? */ - TMLN *lp = &pas_ldsc[ln]; /* get line */ - if (TT_GET_MODE (pasl_unit[ln].flags) == TTUF_MODE_8B) - c = pas_par (pas_cmd[ln], pas_xbuf[ln]); /* apply parity */ - else c = sim_tt_outcvt (pas_xbuf[ln], TT_GET_MODE (pasl_unit[ln].flags)); - if (c >= 0) { - tmxr_putc_ln (lp, c); /* output char */ - } - tmxr_poll_tx (&pas_desc); /* poll xmt */ - } - else { /* buf full */ - tmxr_poll_tx (&pas_desc); /* poll xmt */ - sim_activate (uptr, pasl_unit[ln].wait); /* wait */ - return SCPE_OK; - } - } -pas_sta[ln] = pas_sta[ln] & ~STA_BSY; /* not busy */ -if (pas_xarm[ln]) /* set intr */ - SET_INT (v_PASX + ln + ln); -return SCPE_OK; -} - -int32 pas_par (int32 cmd, int32 c) -{ -int32 pf = GET_PAR (cmd); -static const uint8 odd_par[] = { - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 00 */ - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 10 */ - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 20 */ - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 30 */ - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 40 */ - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 50 */ - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 60 */ - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 70 */ - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 80 */ - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 90 */ - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* A0 */ - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* B0 */ - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* C0 */ - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* D0 */ - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* E0 */ - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* F0 */ - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80 - }; - -switch (pf) { /* case on parity */ - - case PAR_ODD: - return (odd_par[c & 0x7F]) | (c & 0x7F); - - case PAR_EVEN: - return (odd_par[c & 0x7F] ^ 0x80) | (c & 0x7F); - - case PAR_NONE: - case PAR_RAW: - break; - } - -return c & 0xFF; -} - -/* Reset routine */ - -t_stat pas_reset (DEVICE *dptr) -{ -int32 i; - -if (dptr->flags & DEV_DIS) { /* disabled? */ - pas_dev.flags = pas_dev.flags | DEV_DIS; /* disable lines */ - pasl_dev.flags = pasl_dev.flags | DEV_DIS; - } -else { - pas_dev.flags = pas_dev.flags & ~DEV_DIS; /* enable lines */ - pasl_dev.flags = pasl_dev.flags & ~DEV_DIS; - } -if (pas_unit.flags & UNIT_ATT) /* master att? */ - sim_activate (&pas_unit, lfc_poll); -else sim_cancel (&pas_unit); /* else stop */ -for (i = 0; i < PAS_LINES; i++) - pas_reset_ln (i); -return SCPE_OK; -} - -/* Attach master unit */ - -t_stat pas_attach (UNIT *uptr, char *cptr) -{ -t_stat r; - -r = tmxr_attach (&pas_desc, uptr, cptr); /* attach */ -if (r != SCPE_OK) /* error */ - return r; -sim_activate (uptr, 0); /* immediate poll */ -return SCPE_OK; -} - -/* Detach master unit */ - -t_stat pas_detach (UNIT *uptr) -{ -int32 i; -t_stat r; - -r = tmxr_detach (&pas_desc, uptr); /* detach */ -for (i = 0; i < PAS_LINES; i++) /* disable rcv */ - pas_ldsc[i].rcve = 0; -sim_cancel (uptr); /* stop poll */ -return r; -} - -/* Change number of lines */ - -t_stat pas_vlines (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 newln, i, t; -t_stat r; - -if (cptr == NULL) - return SCPE_ARG; -newln = get_uint (cptr, 10, PAS_LINES, &r); -if ((r != SCPE_OK) || (newln == PAS_ENAB)) - return r; -if (newln == 0) - return SCPE_ARG; -if (newln < PAS_ENAB) { - for (i = newln, t = 0; i < PAS_ENAB; i++) - t = t | pas_ldsc[i].conn; - if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE)) - return SCPE_OK; - for (i = newln; i < PAS_ENAB; i++) { - if (pas_ldsc[i].conn) { - tmxr_linemsg (&pas_ldsc[i], "\r\nOperator disconnected line\r\n"); - tmxr_reset_ln (&pas_ldsc[i]); /* reset line */ - } - pasl_unit[i].flags = pasl_unit[i].flags | UNIT_DIS; - pas_reset_ln (i); - } - } -else { - for (i = PAS_ENAB; i < newln; i++) { - pasl_unit[i].flags = pasl_unit[i].flags & ~UNIT_DIS; - pas_reset_ln (i); - } - } -PAS_ENAB = newln; -return SCPE_OK; -} - -/* Reset an individual line */ - -void pas_reset_ln (int32 i) -{ -CLR_INT (v_PAS + i + i); /* clear int */ -CLR_ENB (v_PAS + i + i); -CLR_INT (v_PASX + i + i); /* disable int */ -CLR_ENB (v_PASX + i + i); -pas_rarm[i] = pas_xarm[i] = 0; /* disarm int */ -pas_rbuf[i] = pas_xbuf[i] = 0; /* clear state */ -pas_cmd[i] = 0; -pas_rchp[i] = 0; -pas_sta[i] = 0; -if (pas_ldsc[i].conn == 0) /* clear carrier */ - pas_sta[i] = pas_sta[i] | STA_CROF; -sim_cancel (&pasl_unit[i]); -return; -} - -/* Init template */ - -void pas_ini (t_bool dtpl) -{ -int32 i, j; - -for (i = j = 0; i < PAS_ENAB; i++) { - pas_tplte[j] = j; - pas_tplte[j + 1] = j + o_PASX; - j = j + 2; - } -pas_tplte[j] = TPL_END; -return; -} diff --git a/Interdata/id_pt.c b/Interdata/id_pt.c deleted file mode 100644 index 01caa9bc..00000000 --- a/Interdata/id_pt.c +++ /dev/null @@ -1,377 +0,0 @@ -/* id_pt.c: Interdata paper tape reader - - Copyright (c) 2000-2008, 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 - - 25-Apr-03 RMS Revised for extended file support - 10-Apr-03 RMS Fixed type problem in ptr service (Mark Pizzolato) -*/ - -#include "id_defs.h" -#include - -/* Device definitions */ - -#define PTR 0 /* unit subscripts */ -#define PTP 1 - -#define STA_OVR 0x80 /* overrun */ -#define STA_NMTN 0x10 /* no motion */ -#define STA_MASK (STA_BSY | STA_OVR | STA_DU) /* static bits */ -#define SET_EX (STA_OVR | STA_NMTN) /* set EX */ - -#define CMD_V_RUN 4 /* run/stop */ -#define CMD_V_SLEW 2 /* slew/step */ -#define CMD_V_RD 0 /* read/write */ - -extern uint32 int_req[INTSZ], int_enb[INTSZ]; - -uint32 pt_run = 0, pt_slew = 0; /* ptr modes */ -uint32 pt_rd = 1, pt_chp = 0; /* pt state */ -uint32 pt_arm = 0; /* int arm */ -uint32 pt_sta = STA_BSY; /* status */ -uint32 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */ - -DEVICE pt_dev; -uint32 pt (uint32 dev, uint32 op, uint32 dat); -t_stat ptr_svc (UNIT *uptr); -t_stat ptp_svc (UNIT *uptr); -t_stat pt_boot (int32 unitno, DEVICE *dptr); -t_stat pt_reset (DEVICE *dptr); - -/* PT data structures - - pt_dev PT device descriptor - pt_unit PT unit descriptors - pt_reg PT register list -*/ - -DIB pt_dib = { d_PT, -1, v_PT, NULL, &pt, NULL }; - -UNIT pt_unit[] = { - { UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), - SERIAL_IN_WAIT }, - { UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT } - }; - -REG pt_reg[] = { - { HRDATA (STA, pt_sta, 8) }, - { HRDATA (RBUF, pt_unit[PTR].buf, 8) }, - { DRDATA (RPOS, pt_unit[PTR].pos, T_ADDR_W), 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, T_ADDR_W), PV_LEFT }, - { DRDATA (PTIME, pt_unit[PTP].wait, 24), PV_LEFT }, - { FLDATA (PSTOP_IOE, ptp_stopioe, 0) }, - { FLDATA (IREQ, int_req[l_PT], i_PT) }, - { FLDATA (IENB, int_enb[l_PT], i_PT) }, - { FLDATA (IARM, pt_arm, 0) }, - { FLDATA (RD, pt_rd, 0) }, - { FLDATA (RUN, pt_run, 0) }, - { FLDATA (SLEW, pt_slew, 0) }, - { FLDATA (CHP, pt_chp, 0) }, - { HRDATA (DEVNO, pt_dib.dno, 8), REG_HRO }, - { NULL } - }; - -MTAB pt_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "devno", "DEVNO", - &set_dev, &show_dev, NULL }, - { 0 } - }; - -DEVICE pt_dev = { - "PT", pt_unit, pt_reg, pt_mod, - 2, 10, 31, 1, 16, 8, - NULL, NULL, &pt_reset, - &pt_boot, NULL, NULL, - &pt_dib, DEV_DISABLE - }; - -/* Paper tape: IO routine */ - -uint32 pt (uint32 dev, uint32 op, uint32 dat) -{ -uint32 t, old_rd, old_run; - -switch (op) { /* case IO op */ - - case IO_ADR: /* select */ - return BY; /* byte only */ - - case IO_OC: /* command */ - old_rd = pt_rd; /* save curr rw */ - old_run = pt_run; /* save curr run */ - pt_arm = int_chg (v_PT, dat, pt_arm); /* upd int ctrl */ - pt_rd = io_2b (dat, CMD_V_RD, pt_rd); /* upd read/wr */ - if (old_rd != pt_rd) { /* rw change? */ - pt_sta = pt_sta & ~STA_OVR; /* clr overrun */ - if (sim_is_active (&pt_unit[pt_rd? PTR: PTP])) { - pt_sta = pt_sta | STA_BSY; /* busy = 1 */ - CLR_INT (v_PT); /* clear int */ - } - else { /* not active */ - pt_sta = pt_sta & ~STA_BSY; /* busy = 0 */ - if (pt_arm) /* no, set int */ - SET_INT (v_PT); - } - } - if (pt_rd) { /* reader? */ - pt_run = io_2b (dat, CMD_V_RUN, pt_run); /* upd run/stop */ - pt_slew = io_2b (dat, CMD_V_SLEW, pt_slew); /* upd slew/inc */ - if (pt_run) { /* run set? */ - if (old_run == 0) { /* run 0 -> 1? */ - sim_activate (&pt_unit[PTR], pt_unit[PTR].wait); - pt_sta = pt_sta & ~STA_DU; /* clear eof */ - } - } - else sim_cancel (&pt_unit[PTR]); /* clr, stop rdr */ - } - else pt_sta = pt_sta & ~STA_DU; /* punch, clr eof */ - break; - - case IO_RD: /* read */ - if (pt_run && !pt_slew) { /* incremental? */ - sim_activate (&pt_unit[PTR], pt_unit[PTR].wait); - pt_sta = pt_sta & ~STA_DU; /* clr eof */ - } - pt_chp = 0; /* clr char pend */ - if (pt_rd) /* set busy */ - pt_sta = pt_sta | STA_BSY; - return (pt_unit[PTR].buf & 0xFF); /* return char */ - - case IO_WD: /* write */ - pt_unit[PTP].buf = dat & DMASK8; /* save char */ - if (!pt_rd) /* set busy */ - pt_sta = pt_sta | STA_BSY; - sim_activate (&pt_unit[PTP], pt_unit[PTP].wait); - break; - - case IO_SS: /* status */ - t = pt_sta & STA_MASK; /* get status */ - if (pt_rd && !pt_run && !sim_is_active (&pt_unit[PTR])) - t = t | STA_NMTN; /* stopped? */ - if ((pt_unit[pt_rd? PTR: PTP].flags & UNIT_ATT) == 0) - t = t | STA_DU; /* offline? */ - if (t & SET_EX) /* test for EX */ - t = t | STA_EX; - return t; - } - -return 0; -} - -/* Unit service */ - -t_stat ptr_svc (UNIT *uptr) -{ -int32 temp; - -if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (ptr_stopioe, SCPE_UNATT); -if (pt_rd) { /* read mode? */ - pt_sta = pt_sta & ~STA_BSY; /* clear busy */ - if (pt_arm) /* if armed, intr */ - SET_INT (v_PT); - if (pt_chp) /* overrun? */ - pt_sta = pt_sta | STA_OVR; - } -pt_chp = 1; /* char pending */ -if ((temp = getc (uptr->fileref)) == EOF) { /* error? */ - if (feof (uptr->fileref)) { /* eof? */ - pt_sta = pt_sta | STA_DU; /* set DU */ - if (ptr_stopioe) - sim_printf ("PTR end of file\n"); - else return SCPE_OK; - } - else perror ("PTR I/O error"); - clearerr (uptr->fileref); - return SCPE_IOERR; - } -uptr->buf = temp & DMASK8; /* store char */ -uptr->pos = uptr->pos + 1; /* incr pos */ -if (pt_slew) /* slew? continue */ - sim_activate (uptr, uptr->wait); -return SCPE_OK; -} - -t_stat ptp_svc (UNIT *uptr) -{ -if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (ptp_stopioe, SCPE_UNATT); -if (!pt_rd) { /* write mode? */ - pt_sta = pt_sta & ~STA_BSY; /* clear busy */ - if (pt_arm) /* if armed, intr */ - SET_INT (v_PT); - } -if (putc (uptr->buf, uptr -> fileref) == EOF) { /* write char */ - perror ("PTP I/O error"); - clearerr (uptr -> fileref); - return SCPE_IOERR; - } -uptr -> pos = uptr -> pos + 1; /* incr pos */ -return SCPE_OK; -} - -/* Reset routine */ - -t_stat pt_reset (DEVICE *dptr) -{ -sim_cancel (&pt_unit[PTR]); /* deactivate units */ -sim_cancel (&pt_unit[PTP]); -pt_rd = 1; /* read */ -pt_chp = pt_run = pt_slew = 0; /* stop, inc, disarm */ -pt_sta = STA_BSY; /* buf empty */ -CLR_INT (v_PT); /* clear int */ -CLR_ENB (v_PT); /* disable int */ -pt_arm = 0; /* disarm int */ -return SCPE_OK; -} - -/* Bootstrap routine */ - -#define BOOT_START 0x50 -#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint8)) -#define BOOT3_START 0x3E -#define BOOT3_LEN (sizeof (boot_rom) / sizeof (uint8)) - -static uint8 boot_rom[] = { - 0xD5, 0x00, 0x00, 0xCF, /* ST AL CF */ - 0x43, 0x00, 0x00, 0x80 /* BR 80 */ - }; - -static uint8 boot3_rom[] = { - 0xC8, 0x20, 0x00, 0x80, /* ST LHI 2,80 */ - 0xC8, 0x30, 0x00, 0x01, /* LHI 3,1 */ - 0xC8, 0x40, 0x00, 0xCF, /* LHI 4,CF */ - 0xD3, 0xA0, 0x00, 0x78, /* LB A,78 */ - 0xDE, 0xA0, 0x00, 0x79, /* OC A,79 */ - 0x9D, 0xAE, /* LP SSR A,E */ - 0x42, 0xF0, 0x00, 0x52, /* BTC F,LP */ - 0x9B, 0xAE, /* RDR A,E */ - 0x08, 0xEE, /* LHR E,E */ - 0x43, 0x30, 0x00, 0x52, /* BZ LP */ - 0x43, 0x00, 0x00, 0x6C, /* BR STO */ - 0x9D, 0xAE, /* LP1 SSR A,E */ - 0x42, 0xF0, 0x00, 0x64, /* BTC F,LP1 */ - 0x9B, 0xAE, /* RDR A,E */ - 0xD2, 0xE2, 0x00, 0x00, /* STO STB E,0(2) */ - 0xC1, 0x20, 0x00, 0x64, /* BXLE 2,LP1 */ - 0x43, 0x00, 0x00, 0x80 /* BR 80 */ - }; - -t_stat pt_boot (int32 unitno, DEVICE *dptr) -{ -extern uint32 PC, dec_flgs; -extern uint16 decrom[]; - -if (decrom[0xD5] & dec_flgs) /* AL defined? */ - IOWriteBlk (BOOT3_START, BOOT3_LEN, boot3_rom); /* no, 50 seq */ -else IOWriteBlk (BOOT_START, BOOT_LEN, boot_rom); /* copy AL boot */ -IOWriteB (AL_DEV, pt_dib.dno); /* set dev no */ -IOWriteB (AL_IOC, 0x99); /* set dev cmd */ -IOWriteB (AL_SCH, 0); /* clr sch dev no */ -PC = BOOT_START; -return SCPE_OK; -} - -/* Dump routine */ - -#define LOAD_START 0x80 -#define LOAD_LO 0x8A -#define LOAD_HI 0x8E -#define LOAD_CS 0x93 -#define LOAD_LEN (sizeof (load_rom) / sizeof (uint8)) -#define LOAD_LDR 50 - -static uint8 load_rom[] = { - 0x24, 0x21, /* BOOT LIS R2,1 */ - 0x23, 0x03, /* BS BOOT */ - 0x00, 0x00, /* 32b psw pointer */ - 0x00, 0x00, /* 32b reg pointer */ - 0xC8, 0x10, /* ST LHI R1,lo */ - 0x00, 0x00, - 0xC8, 0x30, /* LHI R3,hi */ - 0x00, 0x00, - 0xC8, 0x60, /* LHI R3,cs */ - 0x00, 0x00, - 0xD3, 0x40, /* LB R4,X'78' */ - 0x00, 0x78, - 0xDE, 0x40, /* OC R4,X'79' */ - 0x00, 0x79, - 0x9D, 0x45, /* LDR SSR R4,R5 */ - 0x20, 0x91, /* BTBS 9,.-2 */ - 0x9B, 0x45, /* RDR R4,R5 */ - 0x08, 0x55, /* L(H)R R5,R5 */ - 0x22, 0x34, /* BZS LDR */ - 0xD2, 0x51, /* LOOP STB R5,0(R1) */ - 0x00, 0x00, - 0x07, 0x65, /* X(H)R R6,R5 */ - 0x9A, 0x26, /* WDR R2,R6 */ - 0x9D, 0x45, /* SSR R4,R5 */ - 0x20, 0x91, /* BTBS 9,.-2 */ - 0x9B, 0x45, /* RDR R4,R5 */ - 0xC1, 0x10, /* BXLE R1,LOOP */ - 0x00, 0xA6, - 0x24, 0x78, /* LIS R7,8 */ - 0x91, 0x7C, /* SLLS R7,12 */ - 0x95, 0x57, /* EPSR R5,R7 */ - 0x22, 0x03 /* BS .-6 */ - }; - -t_stat pt_dump (FILE *of, char *cptr, char *fnam) -{ -uint32 i, lo, hi, cs; -char *tptr; -extern DEVICE cpu_dev; - -if ((cptr == NULL) || (*cptr == 0)) - return SCPE_2FARG; -tptr = get_range (NULL, cptr, &lo, &hi, cpu_dev.aradix, 0xFFFF, 0); -if ((tptr == NULL) || (lo < INTSVT)) - return SCPE_ARG; -if (*tptr != 0) - return SCPE_2MARG; -for (i = lo, cs = 0; i <= hi; i++) - cs = cs ^ IOReadB (i); -IOWriteBlk (LOAD_START, LOAD_LEN, load_rom); -IOWriteB (LOAD_LO, (lo >> 8) & 0xFF); -IOWriteB (LOAD_LO + 1, lo & 0xFF); -IOWriteB (LOAD_HI, (hi >> 8) & 0xFF); -IOWriteB (LOAD_HI + 1, hi & 0xFF); -IOWriteB (LOAD_CS, cs & 0xFF); -for (i = 0; i < LOAD_LDR; i++) - fputc (0, of); -for (i = LOAD_START; i < (LOAD_START + LOAD_LEN); i++) - fputc (IOReadB (i), of); -for (i = 0; i < LOAD_LDR; i++) - fputc (0, of); -for (i = lo; i <= hi; i++) - fputc (IOReadB (i), of); -for (i = 0; i < LOAD_LDR; i++) - fputc (0, of); -return SCPE_OK; -} diff --git a/Interdata/id_tt.c b/Interdata/id_tt.c deleted file mode 100644 index e7aea65d..00000000 --- a/Interdata/id_tt.c +++ /dev/null @@ -1,295 +0,0 @@ -/* id_tt.c: Interdata teletype - - Copyright (c) 2000-2012, 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. - - tt console - - 18-Apr-12 RMS Revised to use clock coscheduling - 18-Jun-07 RMS Added UNIT_IDLE flag to console input - 18-Oct-06 RMS Sync keyboard to LFC clock - 30-Sep-06 RMS Fixed handling of non-printable characters in KSR mode - 22-Nov-05 RMS Revised for new terminal processing routines - 29-Dec-03 RMS Added support for console backpressure - 25-Apr-03 RMS Revised for extended file support - 11-Jan-03 RMS Added TTP support - 22-Dec-02 RMS Added break support -*/ - -#include "id_defs.h" -#include - -/* Device definitions */ - -#define TTI 0 -#define TTO 1 - -#define STA_OVR 0x80 /* overrun */ -#define STA_BRK 0x20 /* break */ -#define STA_MASK (STA_OVR | STA_BRK | STA_BSY) /* status mask */ -#define SET_EX (STA_OVR | STA_BRK) /* set EX */ - -#define CMD_V_FDPX 4 /* full/half duplex */ -#define CMD_V_RD 2 /* read/write */ - -extern uint32 int_req[INTSZ], int_enb[INTSZ]; -extern int32 lfc_poll; - -uint32 tt_sta = STA_BSY; /* status */ -uint32 tt_fdpx = 1; /* tt mode */ -uint32 tt_rd = 1, tt_chp = 0; /* tt state */ -uint32 tt_arm = 0; /* int arm */ - -uint32 tt (uint32 dev, uint32 op, uint32 dat); -t_stat tti_svc (UNIT *uptr); -t_stat tto_svc (UNIT *uptr); -t_stat tt_reset (DEVICE *dptr); -t_stat tt_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat tt_set_break (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat tt_set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc); - -/* TT data structures - - tt_dev TT device descriptor - tt_unit TT unit descriptors - tt_reg TT register list - tt_mod TT modifiers list -*/ - -DIB tt_dib = { d_TT, -1, v_TT, NULL, &tt, NULL }; - -UNIT tt_unit[] = { - { UDATA (&tti_svc, TT_MODE_KSR|UNIT_IDLE, 0), KBD_POLL_WAIT }, - { UDATA (&tto_svc, TT_MODE_KSR, 0), SERIAL_OUT_WAIT } - }; - -REG tt_reg[] = { - { HRDATA (STA, tt_sta, 8) }, - { HRDATA (KBUF, tt_unit[TTI].buf, 8) }, - { DRDATA (KPOS, tt_unit[TTI].pos, T_ADDR_W), PV_LEFT }, - { DRDATA (KTIME, tt_unit[TTI].wait, 24), PV_LEFT + REG_NZ }, - { HRDATA (TBUF, tt_unit[TTO].buf, 8) }, - { DRDATA (TPOS, tt_unit[TTO].pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TTIME, tt_unit[TTO].wait, 24), REG_NZ + PV_LEFT }, - { FLDATA (IREQ, int_req[l_TT], i_TT) }, - { FLDATA (IENB, int_enb[l_TT], i_TT) }, - { FLDATA (IARM, tt_arm, 0) }, - { FLDATA (RD, tt_rd, 0) }, - { FLDATA (FDPX, tt_fdpx, 0) }, - { FLDATA (CHP, tt_chp, 0) }, - { HRDATA (DEVNO, tt_dib.dno, 8), REG_HRO }, - { NULL } - }; - -MTAB tt_mod[] = { - { TT_MODE, TT_MODE_KSR, "KSR", "KSR", &tt_set_mode }, - { TT_MODE, TT_MODE_7B, "7b", "7B", &tt_set_mode }, - { TT_MODE, TT_MODE_8B, "8b", "8B", &tt_set_mode }, - { TT_MODE, TT_MODE_7P, "7p", "7P", &tt_set_mode }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "ENABLED", - &tt_set_enbdis, NULL, NULL }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO, DEV_DIS, NULL, "DISABLED", - &tt_set_enbdis, NULL, NULL }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "BREAK", - &tt_set_break, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", - &set_dev, &show_dev, &tt_dib }, - { 0 } - }; - -DEVICE tt_dev = { - "TT", tt_unit, tt_reg, tt_mod, - 2, 10, 31, 1, 16, 8, - NULL, NULL, &tt_reset, - NULL, NULL, NULL, - &tt_dib, 0 - }; - -/* Terminal: IO routine */ - -uint32 tt (uint32 dev, uint32 op, uint32 dat) -{ -uint32 old_rd, t; - -switch (op) { /* case IO op */ - - case IO_ADR: /* select */ - return BY; /* byte only */ - - case IO_OC: /* command */ - old_rd = tt_rd; - tt_arm = int_chg (v_TT, dat, tt_arm); /* upd int ctrl */ - tt_fdpx = io_2b (dat, CMD_V_FDPX, tt_fdpx); /* upd full/half */ - tt_rd = io_2b (dat, CMD_V_RD, tt_rd); /* upd rd/write */ - if (tt_rd != old_rd) { /* rw change? */ - if (tt_rd? tt_chp: !sim_is_active (&tt_unit[TTO])) { - tt_sta = 0; /* busy = 0 */ - if (tt_arm) /* req intr */ - SET_INT (v_TT); - } - else { - tt_sta = STA_BSY; /* busy = 1 */ - CLR_INT (v_TT); /* clr int */ - } - } - else tt_sta = tt_sta & ~STA_OVR; /* clr ovflo */ - break; - - case IO_RD: /* read */ - tt_chp = 0; /* clear pend */ - if (tt_rd) - tt_sta = (tt_sta | STA_BSY) & ~STA_OVR; - sim_activate_abs (&tt_unit[TTI], tt_unit[TTI].wait); - return (tt_unit[TTI].buf & 0xFF); - - case IO_WD: /* write */ - tt_unit[TTO].buf = dat & 0xFF; /* save char */ - if (!tt_rd) /* set busy */ - tt_sta = tt_sta | STA_BSY; - sim_activate (&tt_unit[TTO], tt_unit[TTO].wait); - break; - - case IO_SS: /* status */ - t = tt_sta & STA_MASK; /* get status */ - if (t & SET_EX) /* test for EX */ - t = t | STA_EX; - return t; - } - -return 0; -} - -/* Unit service routines */ - -t_stat tti_svc (UNIT *uptr) -{ -int32 out, temp; - -sim_activate (uptr, lfc_cosched (lfc_poll)); /* continue poll */ -tt_sta = tt_sta & ~STA_BRK; /* clear break */ -if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */ - return temp; -if (tt_rd) { /* read mode? */ - tt_sta = tt_sta & ~STA_BSY; /* clear busy */ - if (tt_arm) /* if armed, intr */ - SET_INT (v_TT); - if (tt_chp) /* got char? overrun */ - tt_sta = tt_sta | STA_OVR; - } -tt_chp = 1; /* char pending */ -out = temp & 0x7F; /* echo is 7B */ -if (temp & SCPE_BREAK) { /* break? */ - tt_sta = tt_sta | STA_BRK; /* set status */ - uptr->buf = 0; /* no character */ - } -else uptr->buf = sim_tt_inpcvt (temp, TT_GET_MODE (uptr->flags) | TTUF_KSR); -uptr->pos = uptr->pos + 1; /* incr count */ -if (!tt_fdpx) { /* half duplex? */ - out = sim_tt_outcvt (out, TT_GET_MODE (uptr->flags) | TTUF_KSR); - if (out >= 0) { /* valid echo? */ - sim_putchar (out); /* write char */ - tt_unit[TTO].pos = tt_unit[TTO].pos + 1; - } - } -return SCPE_OK; -} - -t_stat tto_svc (UNIT *uptr) -{ -int32 ch; -t_stat r; - -ch = sim_tt_outcvt (uptr->buf, TT_GET_MODE (uptr->flags) | TTUF_KSR); -if (ch >= 0) { - if ((r = sim_putchar_s (ch)) != SCPE_OK) { /* output; error? */ - sim_activate (uptr, uptr->wait); /* try again */ - return ((r == SCPE_STALL)? SCPE_OK: r); - } - } -if (!tt_rd) { /* write mode? */ - tt_sta = tt_sta & ~STA_BSY; /* clear busy */ - if (tt_arm) /* if armed, intr */ - SET_INT (v_TT); - } -uptr->pos = uptr->pos + 1; /* incr count */ -return SCPE_OK; -} - -/* Reset routine */ - -t_stat tt_reset (DEVICE *dptr) -{ -if (dptr->flags & DEV_DIS) /* dis? cancel poll */ - sim_cancel (&tt_unit[TTI]); -else sim_activate (&tt_unit[TTI],lfc_poll); -sim_cancel (&tt_unit[TTO]); /* cancel output */ -tt_rd = tt_fdpx = 1; /* read, full duplex */ -tt_chp = 0; /* no char */ -tt_sta = STA_BSY; /* buffer empty */ -CLR_INT (v_TT); /* clear int */ -CLR_ENB (v_TT); /* disable int */ -tt_arm = 0; /* disarm int */ -return SCPE_OK; -} - -/* Make mode flags uniform */ - -t_stat tt_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -tt_unit[TTO].flags = (tt_unit[TTO].flags & ~TT_MODE) | val; -if (val == TT_MODE_7P) - val = TT_MODE_7B; -tt_unit[TTI].flags = (tt_unit[TTI].flags & ~TT_MODE) | val; -return SCPE_OK; -} - -/* Set input break */ - -t_stat tt_set_break (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (tt_dev.flags & DEV_DIS) - return SCPE_NOFNC; -tt_sta = tt_sta | STA_BRK; -if (tt_rd) { /* read mode? */ - tt_sta = tt_sta & ~STA_BSY; /* clear busy */ - if (tt_arm) /* if armed, intr */ - SET_INT (v_TT); - } -sim_cancel (&tt_unit[TTI]); /* restart TT poll */ -sim_activate (&tt_unit[TTI], tt_unit[TTI].wait); /* so brk is seen */ -return SCPE_OK; -} - -/* Set enabled/disabled */ - -t_stat tt_set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -extern DEVICE ttp_dev; -extern t_stat ttp_reset (DEVICE *dptr); - -tt_dev.flags = (tt_dev.flags & ~DEV_DIS) | val; -ttp_dev.flags = (ttp_dev.flags & ~DEV_DIS) | (val ^ DEV_DIS); -tt_reset (&tt_dev); -ttp_reset (&ttp_dev); -return SCPE_OK; -} diff --git a/Interdata/id_ttp.c b/Interdata/id_ttp.c deleted file mode 100644 index aa9e92d9..00000000 --- a/Interdata/id_ttp.c +++ /dev/null @@ -1,293 +0,0 @@ -/* id_ttp.c: Interdata PASLA console interface - - Copyright (c) 2000-2017, 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. - - ttp console (on PAS) - - 09-Mar-17 RMS Fixed testing of 8b mode (COVERITY) - Fixed testing of echoed character (COVERITY) - 18-Apr-12 RMS Revised to use clock coscheduling - 18-Jun-07 RMS Added UNIT_IDLE flag to console input - 18-Oct-06 RMS Sync keyboard to LFC clock - 22-Nov-05 RMS Revised for new terminal processing routines - 29-Dec-03 RMS Added support for console backpressure - 25-Apr-03 RMS Revised for extended file support -*/ - -#include "id_defs.h" -#include - -#define TTI 0 -#define TTO 1 - -/* Status byte */ - -#define STA_OVR 0x80 /* overrun RO */ -#define STA_PF 0x40 /* parity err RO */ -#define STA_FR 0x20 /* framing err RO */ -#define STA_RCV (STA_OVR|STA_PF|STA_FR) -#define SET_EX (STA_OVR|STA_PF|STA_FR) -#define STA_XMT (STA_BSY) - -/* Command bytes 1,0 */ - -#define CMD_ECHO (0x10 << 8) /* echoplex */ -#define CMD_WRT (0x02 << 8) /* write/read */ -#define CMD_TYP 0x01 /* command type */ - -extern uint32 int_req[INTSZ], int_enb[INTSZ]; -extern int32 pas_par (int32 cmd, int32 c); -extern int32 lfc_poll; - -uint32 ttp_sta = 0; /* status */ -uint32 ttp_cmd = 0; /* command */ -uint32 ttp_kchp = 0; /* rcvr chr pend */ -uint32 ttp_karm = 0; /* rcvr int armed */ -uint32 ttp_tarm = 0; /* xmt int armed */ -uint8 ttp_tplte[] = { 0, 1, TPL_END }; - -uint32 ttp (uint32 dev, uint32 op, uint32 dat); -t_stat ttpi_svc (UNIT *uptr); -t_stat ttpo_svc (UNIT *uptr); -t_stat ttp_reset (DEVICE *dptr); -t_stat ttp_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat ttp_set_break (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat ttp_set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc); - -/* TTP data structures */ - -DIB ttp_dib = { d_TTP, -1, v_TTP, ttp_tplte, &ttp, NULL }; - -UNIT ttp_unit[] = { - { UDATA (&ttpi_svc, UNIT_IDLE, 0), KBD_POLL_WAIT }, - { UDATA (&ttpo_svc, 0, 0), SERIAL_OUT_WAIT } - }; - -REG ttp_reg[] = { - { HRDATA (CMD, ttp_cmd, 16) }, - { HRDATA (KBUF, ttp_unit[TTI].buf, 8) }, - { DRDATA (KPOS, ttp_unit[TTI].pos, T_ADDR_W), PV_LEFT }, - { DRDATA (KTIME, ttp_unit[TTI].wait, 24), REG_NZ + PV_LEFT + REG_HRO }, - { FLDATA (KIREQ, int_req[l_TTP], i_TTP) }, - { FLDATA (KIENB, int_enb[l_TTP], i_TTP) }, - { FLDATA (KARM, ttp_karm, 0) }, - { FLDATA (CHP, ttp_kchp, 0) }, - { HRDATA (TBUF, ttp_unit[TTO].buf, 8) }, - { DRDATA (TPOS, ttp_unit[TTO].pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TTIME, ttp_unit[TTO].wait, 24), REG_NZ + PV_LEFT }, - { FLDATA (TIREQ, int_req[l_TTP], i_TTP + 1) }, - { FLDATA (TIENB, int_enb[l_TTP], i_TTP + 1) }, - { FLDATA (TARM, ttp_tarm, 0) }, - { HRDATA (DEVNO, ttp_dib.dno, 8), REG_HRO }, - { NULL } - }; - -MTAB ttp_mod[] = { - { TT_MODE, TT_MODE_UC, "UC", "UC", &ttp_set_mode }, - { TT_MODE, TT_MODE_7B, "7b", "7B", &ttp_set_mode }, - { TT_MODE, TT_MODE_8B, "8b", "8B", &ttp_set_mode }, - { TT_MODE, TT_MODE_7P, "7p", "7P", &ttp_set_mode }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "ENABLED", - &ttp_set_enbdis, NULL, NULL }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO, DEV_DIS, NULL, "DISABLED", - &ttp_set_enbdis, NULL, NULL }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, NULL, "BREAK", - &ttp_set_break, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", - &set_dev, &show_dev, NULL }, - { 0 } - }; - -DEVICE ttp_dev = { - "TTP", ttp_unit, ttp_reg, ttp_mod, - 2, 10, 31, 1, 16, 8, - NULL, NULL, &ttp_reset, - NULL, NULL, NULL, - &ttp_dib, DEV_DIS - }; - -/* Terminal: I/O routine */ - -uint32 ttp (uint32 dev, uint32 op, uint32 dat) -{ -int32 xmt = dev & 1; -int32 t; - -switch (op) { /* case IO op */ - - case IO_ADR: /* select */ - return BY; /* byte only */ - - case IO_RD: /* read */ - ttp_kchp = 0; /* clr chr pend */ - ttp_sta = ttp_sta & ~STA_OVR; /* clr overrun */ - sim_activate_abs (&ttp_unit[TTI], ttp_unit[TTI].wait); - return ttp_unit[TTI].buf; /* return buf */ - - case IO_WD: /* write */ - ttp_unit[TTO].buf = dat & 0xFF; /* store char */ - ttp_sta = ttp_sta | STA_BSY; /* set busy */ - sim_activate (&ttp_unit[TTO], ttp_unit[TTO].wait); - break; - - case IO_SS: /* status */ - if (xmt) t = ttp_sta & STA_XMT; /* xmt? just busy */ - else { /* rcv */ - t = ttp_sta & STA_RCV; /* get static */ - if (!ttp_kchp) /* no char? busy */ - t = t | STA_BSY; - if (t & SET_EX) /* test for ex */ - t = t | STA_EX; - } - return t; - - case IO_OC: /* command */ - if (dat & CMD_TYP) { /* type 1? */ - ttp_cmd = (ttp_cmd & 0xFF) | (dat << 8); - if (ttp_cmd & CMD_WRT) /* write? */ - ttp_tarm = int_chg (v_TTP + 1, dat, ttp_tarm); - else ttp_karm = int_chg (v_TTP, dat, ttp_karm); - } - else ttp_cmd = (ttp_cmd & ~0xFF) | dat; - break; - } - -return 0; -} - -/* Unit service */ - -t_stat ttpi_svc (UNIT *uptr) -{ -int32 c, out; - -sim_activate (uptr, lfc_cosched (lfc_poll)); /* continue poll */ -ttp_sta = ttp_sta & ~STA_FR; /* clear break */ -if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */ - return c; -ttp_sta = ttp_sta & ~STA_PF; /* clear parity err */ -if (ttp_kchp) /* overrun? */ - ttp_sta = ttp_sta | STA_OVR; -if (ttp_karm) - SET_INT (v_TTP); -if (c & SCPE_BREAK) { /* break? */ - ttp_sta = ttp_sta | STA_FR; /* framing error */ - uptr->buf = 0; /* no character */ - } -else { - out = c & 0x7F; /* echo is 7b */ - c = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags)); - if (TT_GET_MODE (uptr->flags) != TTUF_MODE_8B) /* not 8b mode? */ - c = pas_par (ttp_cmd, c); /* apply parity */ - uptr->buf = c; /* save char */ - uptr->pos = uptr->pos + 1; /* incr count */ - ttp_kchp = 1; /* char pending */ - if (ttp_cmd & CMD_ECHO) { - out = sim_tt_outcvt (out, TT_GET_MODE (uptr->flags)); - if (out >= 0) - sim_putchar (out); - ttp_unit[TTO].pos = ttp_unit[TTO].pos + 1; - } - } -return SCPE_OK; -} - -t_stat ttpo_svc (UNIT *uptr) -{ -int32 c; -t_stat r; - -if (TT_GET_MODE (uptr->flags) == TTUF_MODE_8B) /* 8b? */ - c = pas_par (ttp_cmd, uptr->buf); /* apply parity */ -else c = sim_tt_outcvt (uptr->buf, TT_GET_MODE (uptr->flags)); -if (c >= 0) { - if ((r = sim_putchar_s (c)) != SCPE_OK) { /* output; error? */ - sim_activate (uptr, uptr->wait); /* try again */ - return ((r == SCPE_STALL)? SCPE_OK: r); - } - } -ttp_sta = ttp_sta & ~STA_BSY; /* not busy */ -if (ttp_tarm) /* set intr */ - SET_INT (v_TTP + 1); -uptr->pos = uptr->pos + 1; /* incr count */ -return SCPE_OK; -} - -/* Reset routine */ - -t_stat ttp_reset (DEVICE *dptr) -{ -if (dptr->flags & DEV_DIS) - sim_cancel (&ttp_unit[TTI]); -else sim_activate (&ttp_unit[TTI], lfc_poll); -sim_cancel (&ttp_unit[TTO]); -CLR_INT (v_TTP); /* clear int */ -CLR_ENB (v_TTP); -CLR_INT (v_TTP + 1); /* disable int */ -CLR_ENB (v_TTP + 1); -ttp_karm = ttp_tarm = 0; /* disarm int */ -ttp_cmd = 0; -ttp_sta = 0; -ttp_kchp = 0; -return SCPE_OK; -} - -/* Make mode flags uniform */ - -t_stat ttp_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -ttp_unit[TTO].flags = (ttp_unit[TTO].flags & ~TT_MODE) | val; -if (val == TT_MODE_7P) - val = TT_MODE_7B; -ttp_unit[TTI].flags = (ttp_unit[TTI].flags & ~TT_MODE) | val; -return SCPE_OK; -} - -/* Set input break */ - -t_stat ttp_set_break (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (ttp_dev.flags & DEV_DIS) - return SCPE_NOFNC; -ttp_sta = ttp_sta | STA_FR; -if (ttp_karm) /* if armed, intr */ - SET_INT (v_TTP); -sim_cancel (&ttp_unit[TTI]); /* restart TT poll */ -sim_activate (&ttp_unit[TTI], ttp_unit[TTI].wait); -return SCPE_OK; -} - -/* Set enabled/disabled */ - -t_stat ttp_set_enbdis (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -extern DEVICE tt_dev; -extern t_stat tt_reset (DEVICE *dptr); - -ttp_dev.flags = (ttp_dev.flags & ~DEV_DIS) | val; -tt_dev.flags = (tt_dev.flags & ~DEV_DIS) | (val ^ DEV_DIS); -ttp_reset (&ttp_dev); -tt_reset (&tt_dev); -return SCPE_OK; -} diff --git a/Interdata/id_uvc.c b/Interdata/id_uvc.c deleted file mode 100644 index 0d1d9451..00000000 --- a/Interdata/id_uvc.c +++ /dev/null @@ -1,396 +0,0 @@ -/* id_uvc.c: Interdata universal clock - - Copyright (c) 2001-2012, 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. - - pic precision incremental clock - lfc line frequency clock - - 18-Apr-12 RMS Added lfc_cosched routine - 18-Jun-07 RMS Added UNIT_IDLE flag - 18-Oct-06 RMS Changed LFC to be free running, export tmr_poll - 23-Jul-05 RMS Fixed {} error in OC - 01-Mar-03 RMS Added SET/SHOW LFC FREQ support - Changed precision clock algorithm for V7 UNIX -*/ - -#include "id_defs.h" -#include - -/* Device definitions */ - -#define UNIT_V_DIAG (UNIT_V_UF + 0) /* diag mode */ -#define UNIT_DIAG (1 << UNIT_V_DIAG) - -#define STA_OVF 0x08 /* PIC overflow */ -#define CMD_STRT 0x20 /* start */ -#define PIC_V_RATE 12 /* rate */ -#define PIC_M_RATE 0xF -#define PIC_RATE (PIC_M_RATE << PIC_V_RATE) -#define PIC_CTR 0x0FFF /* PIC counters */ -#define GET_RATE(x) (((x) >> PIC_V_RATE) & PIC_M_RATE) -#define GET_CTR(x) ((x) & PIC_CTR) -#define PIC_TPS 1000 - -extern uint32 int_req[INTSZ], int_enb[INTSZ]; - -int32 pic_db = 0; /* output buf */ -int32 pic_ric = 0; /* reset count */ -int32 pic_cic = 0; /* current count */ -uint32 pic_save = 0; /* saved time */ -uint32 pic_ovf = 0; /* overflow */ -uint32 pic_rdp = 0; -uint32 pic_wdp = 0; -uint32 pic_cnti = 0; /* instr/timer */ -uint32 pic_arm = 0; /* int arm */ -uint32 pic_decr = 1; /* decrement */ -uint16 pic_time[4] = { 1, 10, 100, 1000 }; /* delays */ -uint16 pic_usec[4] = { 1, 10, 100, 1000 }; /* usec per tick */ -static int32 pic_map[16] = { /* map rate to delay */ - 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0 - }; - -DEVICE pic_dev; -uint32 pic (uint32 dev, uint32 op, uint32 dat); -t_stat pic_svc (UNIT *uptr); -t_stat pic_reset (DEVICE *dptr); -void pic_sched (t_bool strt); -uint32 pic_rd_cic (void); - -int32 lfc_tps = 120; /* ticks per */ -int32 lfc_poll = 8000; -uint32 lfc_arm = 0; /* int arm */ - -DEVICE lfc_dev; -uint32 lfc (uint32 dev, uint32 op, uint32 dat); -t_stat lfc_svc (UNIT *uptr); -t_stat lfc_reset (DEVICE *dptr); -t_stat lfc_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat lfc_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc); - -/* PIC data structures - - pic_dev PIC device descriptor - pic_unit PIC unit descriptor - pic_reg PIC register list -*/ - -DIB pic_dib = { d_PIC, -1, v_PIC, NULL, &pic, NULL }; - -UNIT pic_unit = { UDATA (&pic_svc, UNIT_IDLE, 0), 1000 }; - -REG pic_reg[] = { - { HRDATA (BUF, pic_db, 16) }, - { HRDATA (RIC, pic_ric, 16) }, - { HRDATA (CIC, pic_cic, 12) }, - { FLDATA (RDP, pic_rdp, 0) }, - { FLDATA (WDP, pic_wdp, 0) }, - { FLDATA (OVF, pic_ovf, 0) }, - { FLDATA (IREQ, int_req[l_PIC], i_PIC) }, - { FLDATA (IENB, int_enb[l_PIC], i_PIC) }, - { FLDATA (IARM, pic_arm, 0) }, - { BRDATA (TIME, pic_time, 10, 16, 4), REG_NZ + PV_LEFT }, - { DRDATA (SAVE, pic_save, 32), REG_HRO + PV_LEFT }, - { DRDATA (DECR, pic_decr, 16), REG_HRO + PV_LEFT }, - { FLDATA (MODE, pic_cnti, 0), REG_HRO }, - { HRDATA (DEVNO, pic_dib.dno, 8), REG_HRO }, - { NULL } - }; - -MTAB pic_mod[] = { - { UNIT_DIAG, UNIT_DIAG, "diagnostic mode", "DIAG", NULL }, - { UNIT_DIAG, 0, NULL, "NORMAL", NULL }, - { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", - &set_dev, &show_dev, NULL }, - { 0 } - }; - -DEVICE pic_dev = { - "PIC", &pic_unit, pic_reg, pic_mod, - 1, 0, 0, 0, 0, 0, - NULL, NULL, &pic_reset, - NULL, NULL, NULL, - &pic_dib, DEV_DISABLE - }; - -/* LFC data structures - - lfc_dev LFC device descriptor - lfc_unit LFC unit descriptor - lfc_reg LFC register list -*/ - -DIB lfc_dib = { d_LFC, -1, v_LFC, NULL, &lfc, NULL }; - -UNIT lfc_unit = { UDATA (&lfc_svc, UNIT_IDLE, 0), 8333 }; - -REG lfc_reg[] = { - { FLDATA (IREQ, int_req[l_LFC], i_LFC) }, - { FLDATA (IENB, int_enb[l_LFC], i_LFC) }, - { FLDATA (IARM, lfc_arm, 0) }, - { DRDATA (TIME, lfc_unit.wait, 24), REG_NZ + PV_LEFT }, - { DRDATA (TPS, lfc_tps, 8), PV_LEFT + REG_HRO }, - { HRDATA (DEVNO, lfc_dib.dno, 8), REG_HRO }, - { NULL } - }; - -MTAB lfc_mod[] = { - { MTAB_XTD|MTAB_VDV, 100, NULL, "50HZ", - &lfc_set_freq, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 120, NULL, "60HZ", - &lfc_set_freq, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "FREQUENCY", NULL, - NULL, &lfc_show_freq, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", - &set_dev, &show_dev, NULL }, - { 0 } - }; - -DEVICE lfc_dev = { - "LFC", &lfc_unit, lfc_reg, lfc_mod, - 1, 0, 0, 0, 0, 0, - NULL, NULL, &lfc_reset, - NULL, NULL, NULL, - &lfc_dib, DEV_DISABLE - }; - -/* Precision clock: IO routine */ - -uint32 pic (uint32 dev, uint32 op, uint32 dat) -{ -int32 t; - -switch (op) { /* case IO op */ - - case IO_ADR: /* select */ - return HW; /* HW capable */ - - case IO_RH: /* read halfword */ - pic_rdp = 0; /* clr ptr */ - return pic_rd_cic (); - - case IO_RD: /* read */ - t = pic_rd_cic (); /* get cic */ - if (pic_rdp) /* 2nd? get lo */ - t = t & DMASK8; - else t = (t >> 8) & DMASK8; /* 1st? get hi */ - pic_rdp = pic_rdp ^ 1; /* flip byte ptr */ - return t; - - case IO_WH: /* write halfword */ - pic_wdp = 0; /* clr ptr */ - pic_db = dat; - break; - - case IO_WD: /* write */ - if (pic_wdp) - pic_db = (pic_db & 0xFF00) | dat; - else pic_db = (pic_db & 0xFF) | (dat << 8); - pic_wdp = pic_wdp ^ 1; /* flip byte ptr */ - break; - - case IO_SS: /* sense status */ - if (pic_ovf) { /* overflow? */ - pic_ovf = 0; /* clear flag */ - CLR_INT (v_PIC); /* clear intr */ - return STA_OVF; - } - return 0; - - case IO_OC: /* output cmd */ - pic_arm = int_chg (v_PIC, dat, pic_arm); /* upd int ctrl */ - if (dat & CMD_STRT) { /* start? */ - pic_ric = pic_db; /* new ric */ - pic_cic = GET_CTR (pic_ric); /* new cic */ - pic_ovf = 0; /* clear flag */ - sim_cancel (&pic_unit); /* stop clock */ - pic_rdp = pic_wdp = 0; /* init ptrs */ - if (pic_ric & PIC_RATE) /* any rate? */ - pic_sched (TRUE); - } /* end if start */ - break; - } /* end case */ - -return 0; -} - -/* Unit service */ - -t_stat pic_svc (UNIT *uptr) -{ -t_bool rate_chg = FALSE; - -if (pic_cnti) /* one shot? */ - pic_cic = 0; -pic_cic = pic_cic - pic_decr; /* decrement */ -if (pic_cic <= 0) { /* overflow? */ - if (pic_wdp) /* broken wr? set flag */ - pic_ovf = 1; - if (pic_arm) /* if armed, intr */ - SET_INT (v_PIC); - if (GET_RATE (pic_ric) != GET_RATE (pic_db)) /* rate change? */ - rate_chg = TRUE; - pic_ric = pic_db; /* new ric */ - pic_cic = GET_CTR (pic_ric); /* new cic */ - if ((pic_ric & PIC_RATE) == 0) - return SCPE_OK; - } -pic_sched (rate_chg); -return SCPE_OK; -} - -/* Schedule next interval - - If eff rate < 1ms, or diagnostic mode, count instructions - If eff rate = 1ms, and not diagnostic mode, use timer -*/ - -void pic_sched (t_bool strt) -{ -int32 r, t, intv, intv_usec; - -pic_save = sim_grtime (); /* save start */ -r = pic_map[GET_RATE (pic_ric)]; /* get mapped rate */ -intv = pic_cic? pic_cic: 1; /* get cntr */ -intv_usec = intv * pic_usec[r]; /* cvt to usec */ -if (!(pic_unit.flags & UNIT_DIAG) && /* not diag? */ - ((intv_usec % 1000) == 0)) { /* 1ms multiple? */ - pic_cnti = 0; /* clr mode */ - pic_decr = pic_usec[3 - r]; /* set decrement */ - if (strt) /* init or */ - t = sim_rtcn_init (pic_time[3], TMR_PIC); - else t = sim_rtcn_calb (PIC_TPS, TMR_PIC); /* calibrate */ - } -else { - pic_cnti = 1; /* set mode */ - pic_decr = 1; /* decr = 1 */ - t = pic_time[r] * intv; /* interval */ - if (t == 1) /* for diagn */ - t++; - } -sim_activate (&pic_unit, t); /* activate */ -return; -} - -/* Read (interpolated) current interval */ - -uint32 pic_rd_cic (void) -{ -if (sim_is_active (&pic_unit) && pic_cnti) { /* running, one shot? */ - uint32 delta = sim_grtime () - pic_save; /* interval */ - uint32 tm = pic_time[pic_map[GET_RATE (pic_ric)]]; /* ticks/intv */ - delta = delta / tm; /* ticks elapsed */ - if (delta >= ((uint32) pic_cic)) /* cap value */ - return 0; - return pic_cic - delta; - } -return pic_cic; -} - -/* Reset routine */ - -t_stat pic_reset (DEVICE *dptr) -{ -sim_cancel (&pic_unit); /* cancel unit */ -pic_ric = pic_cic = 0; -pic_db = 0; -pic_ovf = 0; /* clear state */ -pic_cnti = 0; -pic_decr = 1; -pic_rdp = pic_wdp = 0; -CLR_INT (v_PIC); /* clear int */ -CLR_ENB (v_PIC); /* disable int */ -pic_arm = 0; /* disarm int */ -return SCPE_OK; -} - -/* Line clock: IO routine */ - -uint32 lfc (uint32 dev, uint32 op, uint32 dat) -{ -switch (op) { /* case IO op */ - - case IO_ADR: /* select */ - return BY; /* byte only */ - - case IO_OC: /* command */ - lfc_arm = int_chg (v_LFC, dat, lfc_arm); /* upd int ctrl */ - break; - } -return 0; -} - -/* Unit service */ - -t_stat lfc_svc (UNIT *uptr) -{ -lfc_poll = sim_rtcn_calb (lfc_tps, TMR_LFC); /* calibrate */ -sim_activate (uptr, lfc_poll); /* reactivate */ -if (lfc_arm) { /* armed? */ - SET_INT (v_LFC); /* req intr */ - } -return SCPE_OK; -} - -/* Clock coscheduling routine */ - -int32 lfc_cosched (int32 wait) -{ -int32 t; - -t = sim_activate_time (&lfc_unit); -return (t? t - 1: wait); -} - -/* Reset routine */ - -t_stat lfc_reset (DEVICE *dptr) -{ -lfc_poll = sim_rtcn_init (lfc_unit.wait, TMR_LFC); -sim_activate (&lfc_unit, lfc_poll); /* init clock */ -CLR_INT (v_LFC); /* clear int */ -CLR_ENB (v_LFC); /* disable int */ -lfc_arm = 0; /* disarm int */ -return SCPE_OK; -} - -/* Set frequency */ - -t_stat lfc_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (cptr) - return SCPE_ARG; -if ((val != 100) && (val != 120)) - return SCPE_IERR; -lfc_tps = val; -return SCPE_OK; -} - -/* Show frequency */ - -t_stat lfc_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -fprintf (st, (lfc_tps == 100)? "50Hz": "60Hz"); -return SCPE_OK; -} - diff --git a/LGP/lgp_cpu.c b/LGP/lgp_cpu.c deleted file mode 100644 index b91d6b82..00000000 --- a/LGP/lgp_cpu.c +++ /dev/null @@ -1,763 +0,0 @@ -/* lgp_cpu.c: LGP CPU simulator - - Copyright (c) 2004-2008, 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. - - cpu LGP-30 [LGP-21] CPU - - 22-Sep-05 RMS Fixed declarations (Sterling Garwood) - 04-Sep-05 RMS Fixed missing returns (Peter Schorn) - 04-Jan-05 RMS Modified VM pointer setup - - The system state for the LGP-30 [LGP-21] is: - - A<0:31> accumulator - C<0:11> counter (PC) - OVF overflow flag [LGP-21 only] - - The LGP-30 [LGP-21] has just one instruction format: - - 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 - 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |S| |opcode | | operand address | | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - LGP-30 instructions: - - <0,12:15> operation - - 0 stop - 1 A <- M[ea] - 2 M[ea] <- A - 3 M[ea] <- C + 1 - 4 input - 5 A <- A / M[ea] - 6 A <- A * M[ea], low result - 7 A <- A * M[ea], high result - 8 output - 9 A <- A & M[ea] - A C <- ea - B C <- ea if A < 0 - -B C <- ea if (A < 0) || T-switch set - C M[ea] <- A - D M[ea] <- A, A <- 0 - E A <- A + M[ea] - F A <- A - M[ea] - - LGP-21 instructions: - - <0,12:15> operation - - 0 stop; sense and skip - -0 stop; sense overflow and skip - 1 A <- M[ea] - 2 M[ea] <- A - 3 M[ea] <- C + 1 - 4 6b input - -4 4b input - 5 A <- A / M[ea] - 6 A <- A * M[ea], low result - 7 A <- A * M[ea], high result - 8 6b output - -8 4b output - 9 A <- A & M[ea] - A C <- ea - B C <- ea if A < 0 - -B C <- ea if (A < 0) || T-switch set - C M[ea] <- A - D M[ea] <- A, A <- 0 - E A <- A + M[ea] - F A <- A - M[ea] - - The LGP-30 [LGP-21] has 4096 32b words of memory. The low order - bit is always read and stored as 0. The LGP-30 uses a drum for - memory, with 64 tracks of 64 words. The LGP-21 uses a disk for - memory, with 32 tracks of 128 words. - - This routine is the instruction decode routine for the LGP-30 - [LGP-21]. 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: - - STOP instruction - breakpoint encountered - overflow [LGP-30] - I/O error in I/O simulator - - 2. Interrupts. There are no interrupts. - - 3. Non-existent memory. All of memory always exists. - - 4. Adding I/O devices. The LGP-30 could not support additional - I/O devices. The LGP-21 could but none are known. -*/ - -#include "lgp_defs.h" - -#define PCQ_SIZE 64 /* must be 2**n */ -#define PCQ_MASK (PCQ_SIZE - 1) -#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = (PC - 1) & AMASK; -#define M16 0xFFFF -#define M32 0xFFFFFFFF -#define NEG(x) ((~(x) + 1) & DMASK) -#define ABS(x) (((x) & SIGN)? NEG (x): (x)) - -uint32 M[MEMSIZE] = { 0 }; /* memory */ -uint32 PC = 0; /* counter */ -uint32 A = 0; /* accumulator */ -uint32 IR = 0; /* instr register */ -uint32 OVF = 0; /* overflow indicator */ -uint32 t_switch = 0; /* transfer switch */ -uint32 bp32 = 0; /* BP32 switch */ -uint32 bp16 = 0; /* BP16 switch */ -uint32 bp8 = 0; /* BP8 switch */ -uint32 bp4 = 0; /* BP4 switch */ -uint32 inp_strt = 0; /* input started */ -uint32 inp_done = 0; /* input done */ -uint32 out_strt = 0; /* output started */ -uint32 out_done = 0; /* output done */ -uint32 lgp21_sov = 0; /* LGP-21 sense pending */ -int32 delay = 0; -int16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ -int32 pcq_p = 0; /* PC queue ptr */ -REG *pcq_r = NULL; /* PC queue reg ptr */ - -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_model (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat cpu_set_30opt (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_30opt_i (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_30opt_o (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_fill (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_exec (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_one_inst (uint32 opc, uint32 ir); -uint32 Mul64 (uint32 a, uint32 b, uint32 *low); -t_bool Div32 (uint32 dvd, uint32 dvr, uint32 *q); -uint32 I_delay (uint32 opc, uint32 ea, uint32 op); -uint32 shift_in (uint32 a, uint32 dat, uint32 sh4); - -extern t_stat op_p (uint32 dev, uint32 ch); -extern t_stat op_i (uint32 dev, uint32 ch, uint32 sh4); -extern void lgp_vm_init (void); - -/* 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_IN4B+UNIT_TTSS_D, MEMSIZE) }; - -REG cpu_reg[] = { - { DRDATA (C, PC, 12), REG_VMAD }, - { HRDATA (A, A, 32), REG_VMIO }, - { HRDATA (IR, IR, 32), REG_VMIO }, - { FLDATA (OVF, OVF, 0) }, - { FLDATA (TSW, t_switch, 0) }, - { FLDATA (BP32, bp32, 0) }, - { FLDATA (BP16, bp16, 0) }, - { FLDATA (BP8, bp8, 0) }, - { FLDATA (BP4, bp4, 0) }, - { FLDATA (INPST, inp_strt, 0) }, - { FLDATA (INPDN, inp_done, 0) }, - { FLDATA (OUTST, out_strt, 0) }, - { FLDATA (OUTDN, out_done, 0) }, - { DRDATA (DELAY, delay, 7) }, - { BRDATA (CQ, pcq, 16, 12, PCQ_SIZE), REG_RO + REG_CIRC }, - { HRDATA (CQP, pcq_p, 6), REG_HRO }, - { HRDATA (WRU, sim_int_char, 8) }, - { NULL } - }; - -MTAB cpu_mod[] = { - { UNIT_LGP21, UNIT_LGP21, "LGP-21", "LGP21", &cpu_set_model, &cpu_show_model }, - { UNIT_LGP21, 0, "LGP-30", "LGP30", &cpu_set_model, &cpu_show_model }, - { UNIT_TTSS_D, UNIT_TTSS_D, 0, "TRACK" }, - { UNIT_TTSS_D, 0, 0, "NORMAL" }, - { UNIT_LGPH_D, UNIT_LGPH_D, 0, "LGPHEX" }, - { UNIT_LGPH_D, 0, 0, "STANDARDHEX" }, - { UNIT_MANI, UNIT_MANI, NULL, "MANUAL" }, - { UNIT_MANI, 0, NULL, "TAPE" }, - { UNIT_IN4B, UNIT_IN4B, NULL, "4B", &cpu_set_30opt }, - { UNIT_IN4B, 0, NULL, "6B", &cpu_set_30opt }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "INPUT", &cpu_set_30opt_i }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "OUTPUT", &cpu_set_30opt_o }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "EXECUTE", &cpu_set_exec }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "FILL", &cpu_set_fill }, - { 0 } - }; - -DEVICE cpu_dev = { - "CPU", &cpu_unit, cpu_reg, cpu_mod, - 1, 10, 12, 1, 16, 32, - &cpu_ex, &cpu_dep, &cpu_reset, - NULL, NULL, NULL - }; - -/* Timing tables */ - -/* Optimization minima and maxima - Z B Y R I D N M P E U T H C A S */ - -static const int32 min_30[16] = { - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 - }; -static const int32 max_30[16] = { - 7, 7, 7, 7, 7, 5, 8, 6, 7, 7, 0, 0, 7, 7, 7, 7 - }; -static const int32 min_21[16] = { - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 - }; -static const int32 max_21[16] = { - 0, 16, 16, 16, 0, 58, 81, 79, 0, 16, 0, 0, 16, 16, 16, 16 - }; - -static const uint32 log_to_phys_30[NSC_30] = { /* drum interlace chart */ - 0, 57, 50, 43, 36, 29, 22, 15, 8 , - 1, 58, 51, 44, 37, 30, 23, 16, 9 , - 2, 59, 52, 45, 38, 31, 24, 17, 10, - 3, 60, 53, 46, 39, 32, 25, 18, 11, - 4, 61, 54, 47, 40, 33, 26, 19, 12, - 5, 62, 55, 48, 41, 32, 27, 20, 13, - 6, 63, 56, 49, 42, 33, 28, 21, 14, - 7 - }; - -static const uint32 log_to_phys_21[NSC_21] = { /* disk interlace chart */ - 0, 64, 57, 121, 50, 114, 43, 107, 36, 100, 29, 93, 22, 86, 15, 79, 8, 72, - 1, 65, 58, 122, 51, 115, 44, 108, 37, 101, 30, 94, 23, 87, 16, 80, 9, 73, - 2, 66, 59, 123, 52, 116, 45, 109, 38, 102, 31, 95, 24, 88, 17, 81, 10, 74, - 3, 67, 60, 124, 53, 117, 46, 110, 39, 103, 32, 96, 25, 89, 18, 82, 11, 75, - 4, 68, 61, 125, 54, 118, 47, 111, 40, 104, 33, 97, 26, 90, 19, 83, 12, 76, - 5, 69, 62, 126, 55, 119, 48, 112, 41, 105, 34, 98, 27, 91, 20, 84, 12, 77, - 6, 70, 63, 127, 56, 120, 49, 113, 42, 106, 35, 99, 28, 92, 21, 85, 13, 78, - 7, 71 - }; - -t_stat sim_instr (void) -{ -t_stat r = 0; -uint32 oPC; - -/* Restore register state */ - -PC = PC & AMASK; /* mask PC */ -sim_cancel_step (); /* defang SCP step */ -if (lgp21_sov) { /* stop sense pending? */ - lgp21_sov = 0; - if (!OVF) /* ovf off? skip */ - PC = (PC + 1) & AMASK; - else OVF = 0; /* on? reset */ - } - -/* Main instruction fetch/decode loop */ - -do { - if (sim_interval <= 0) { /* check clock queue */ - if ((r = sim_process_event ())) - break; - } - - if (delay > 0) { /* delay to next instr */ - delay = delay - 1; /* count down delay */ - sim_interval = sim_interval - 1; - continue; /* skip execution */ - } - - if (sim_brk_summ && /* breakpoint? */ - sim_brk_test (PC, SWMASK ('E'))) { - r = STOP_IBKPT; /* stop simulation */ - break; - } - - IR = Read (oPC = PC); /* get instruction */ - PC = (PC + 1) & AMASK; /* increment PC */ - sim_interval = sim_interval - 1; - - if ((r = cpu_one_inst (oPC, IR))) { /* one instr; error? */ - if (r == STOP_STALL) { /* stall? */ - PC = oPC; /* back up PC */ - delay = r = 0; /* no delay */ - } - else break; - } - - if (sim_step && (--sim_step <= 0)) /* do step count */ - r = SCPE_STOP; - - } while (r == 0); /* loop until halted */ -pcq_r->qptr = pcq_p; /* update pc q ptr */ -return r; -} - -/* Execute one instruction */ - -t_stat cpu_one_inst (uint32 opc, uint32 ir) -{ -uint32 ea, op, dat, res, dev, sh4, ch; -t_bool ovf_this_cycle = FALSE; -t_stat reason = 0; - -op = I_GETOP (ir); /* opcode */ -ea = I_GETEA (ir); /* address */ -switch (op) { /* case on opcode */ - -/* Loads, stores, transfers instructions */ - - case OP_B: /* bring */ - A = Read (ea); /* A <- M[ea] */ - delay = I_delay (opc, ea, op); - break; - - case OP_H: /* hold */ - Write (ea, A); /* M[ea] <- A */ - delay = I_delay (opc, ea, op); - break; - - case OP_C: /* clear */ - Write (ea, A); /* M[ea] <- A */ - A = 0; /* A <- 0 */ - delay = I_delay (opc, ea, op); - break; - - case OP_Y: /* store address */ - dat = Read (ea); /* get operand */ - dat = (dat & ~I_EA) | (A & I_EA); /* merge address */ - Write (ea, dat); - delay = I_delay (opc, ea, op); - break; - - case OP_R: /* return address */ - dat = Read (ea); /* get operand */ - dat = (dat & ~I_EA) | (((PC + 1) & AMASK) << I_V_EA); - Write (ea, dat); - delay = I_delay (opc, ea, op); - break; - - case OP_U: /* uncond transfer */ - PCQ_ENTRY; - PC = ea; /* transfer */ - delay = I_delay (opc, ea, op); - break; - - case OP_T: /* conditional transfer */ - if ((A & SIGN) || /* A < 0 or */ - ((ir & SIGN) && t_switch)) { /* -T and Tswitch set? */ - PCQ_ENTRY; - PC = ea; /* transfer */ - } - delay = I_delay (opc, ea, op); - break; - -/* Arithmetic and logical instructions */ - - case OP_A: /* add */ - dat = Read (ea); /* get operand */ - res = (A + dat) & DMASK; /* add */ - if ((~A ^ dat) & (dat ^ res) & SIGN) /* calc overflow */ - ovf_this_cycle = TRUE; - A = res; /* save result */ - delay = I_delay (opc, ea, op); - break; - - case OP_S: /* sub */ - dat = Read (ea); /* get operand */ - res = (A - dat) & DMASK; /* subtract */ - if ((A ^ dat) & (~dat ^ res) & SIGN) /* calc overflow */ - ovf_this_cycle = TRUE; - A = res; - delay = I_delay (opc, ea, op); - break; - - case OP_M: /* multiply high */ - dat = Read (ea); /* get operand */ - A = (Mul64 (A, dat, NULL) << 1) & DMASK; /* multiply */ - delay = I_delay (opc, ea, op); - break; - - case OP_N: /* multiply low */ - dat = Read (ea); /* get operand */ - Mul64 (A, dat, &res); /* multiply */ - A = res; /* keep low result */ - delay = I_delay (opc, ea, op); /* total delay */ - break; - - case OP_D: /* divide */ - dat = Read (ea); /* get operand */ - if (Div32 (A, dat, &A)) /* divide; overflow? */ - ovf_this_cycle = TRUE; - delay = I_delay (opc, ea, op); - break; - - case OP_E: /* extract */ - dat = Read (ea); /* get operand */ - A = A & dat; /* and */ - delay = I_delay (opc, ea, op); - break; - -/* IO instructions */ - - case OP_P: /* output */ - if (Q_LGP21) { /* LGP-21 */ - ch = A >> 26; /* char, 6b */ - if (ir & SIGN) /* 4b? convert */ - ch = (ch & 0x3C) | 2; - dev = I_GETTK (ir); /* device select */ - } - else { /* LGP-30 */ - ch = I_GETTK (ir); /* char, always 6b */ - dev = Q_OUTPT? DEV_PT: DEV_TT; /* device select */ - } - reason = op_p (dev & DEV_MASK, ch); /* output */ - delay = I_delay (sim_grtime (), ea, op); /* next instruction */ - break; - - case OP_I: /* input */ - if (Q_LGP21) { /* LGP-21 */ - ch = 0; /* initial shift */ - sh4 = ir & SIGN; /* 4b/6b select */ - dev = I_GETTK (ir); /* device select */ - } - else { /* LGP-30 */ - ch = I_GETTK (ir); /* initial shift */ - sh4 = Q_IN4B; /* 4b/6b select */ - dev = Q_INPT? DEV_PT: DEV_TT; /* device select */ - } - if (dev == DEV_SHIFT) /* shift? */ - A = shift_in (A, 0, sh4); /* shift 4/6b */ - else reason = op_i (dev & DEV_MASK, ch, sh4); /* input */ - delay = I_delay (sim_grtime (), ea, op); /* next instruction */ - break; - - case OP_Z: - if (Q_LGP21) { /* LGP-21 */ - if (ea & 0xF80) { /* no stop? */ - if (((ea & 0x800) && !bp32) || /* skip if any */ - ((ea & 0x400) && !bp16) || /* selected switch */ - ((ea & 0x200) && !bp8) || /* is off */ - ((ea & 0x100) && !bp4) || /* or if */ - ((ir & SIGN) && !OVF)) /* ovf sel and off */ - PC = (PC + 1) & AMASK; - if (ir & SIGN) /* -Z? clr overflow */ - OVF = 0; - } - else { /* stop */ - lgp21_sov = (ir & SIGN)? 1: 0; /* pending sense? */ - reason = STOP_STOP; /* stop */ - } - } - else { /* LGP-30 */ - if (out_done) /* P complete? */ - out_done = 0; - else if (((ea & 0x800) && bp32) || /* bpt switch set? */ - ((ea & 0x400) && bp16) || - ((ea & 0x200) && bp8) || - ((ea & 0x100) && bp4)) ; /* don't stop or stall */ - else if (out_strt) /* P pending? stall */ - reason = STOP_STALL; - else reason = STOP_STOP; /* no, stop */ - } - delay = I_delay (sim_grtime (), ea, op); /* next instruction */ - break; /* end switch */ - } - -if (ovf_this_cycle) { - if (Q_LGP21) /* LGP-21? set OVF */ - OVF = 1; - else reason = STOP_OVF; /* LGP-30? stop */ - } -return reason; -} - -/* Support routines */ - -uint32 Read (uint32 ea) -{ -return M[ea] & MMASK; -} - -void Write (uint32 ea, uint32 dat) -{ -M[ea] = dat & MMASK; -return; -} - -/* Input shift */ - -uint32 shift_in (uint32 a, uint32 dat, uint32 sh4) -{ -if (sh4) - return (((a << 4) | (dat >> 2)) & DMASK); -return (((a << 6) | dat) & DMASK); -} - -/* 32b * 32b multiply, signed */ - -uint32 Mul64 (uint32 a, uint32 b, uint32 *low) -{ -uint32 sgn = a ^ b; -uint32 ah, bh, al, bl, rhi, rlo, rmid1, rmid2; - -if ((a == 0) || (b == 0)) { /* zero argument? */ - if (low) - *low = 0; - return 0; - } -a = ABS (a); -b = ABS (b); -ah = (a >> 16) & M16; /* split operands */ -bh = (b >> 16) & M16; /* into 16b chunks */ -al = a & M16; -bl = b & M16; -rhi = ah * bh; /* high result */ -rmid1 = ah * bl; -rmid2 = al * bh; -rlo = al * bl; -rhi = rhi + ((rmid1 >> 16) & M16) + ((rmid2 >> 16) & M16); -rmid1 = (rlo + (rmid1 << 16)) & M32; /* add mid1 to lo */ -if (rmid1 < rlo) /* carry? incr hi */ - rhi = rhi + 1; -rmid2 = (rmid1 + (rmid2 << 16)) & M32; /* add mid2 to to */ -if (rmid2 < rmid1) /* carry? incr hi */ - rhi = rhi + 1; -if (sgn & SIGN) { /* result negative? */ - rmid2 = NEG (rmid2); /* negate */ - rhi = (~rhi + (rmid2 == 0)) & M32; - } -if (low) /* low result */ - *low = rmid2; -return rhi & M32; -} - -/* 32b/32b divide (done as 32b'0/32b) */ - -t_bool Div32 (uint32 dvd, uint32 dvr, uint32 *q) -{ -uint32 sgn = dvd ^ dvr; -uint32 i, quo; - -dvd = ABS (dvd); -dvr = ABS (dvr); -if (dvd >= dvr) - return TRUE; -for (i = quo = 0; i < 31; i++) { /* 31 iterations */ - quo = quo << 1; /* shift quotient */ - dvd = dvd << 1; /* shift dividend */ - if (dvd >= dvr) { /* step work? */ - dvd = (dvd - dvr) & M32; /* subtract dvr */ - quo = quo + 1; - } - } -quo = (quo + 1) & MMASK; /* round low bit */ -if (sgn & SIGN) /* result -? */ - quo = NEG (quo); -if (q) /* return quo */ - *q = quo; -return FALSE; /* no overflow */ -} - -/* Rotational delay */ - -uint32 I_delay (uint32 opc, uint32 ea, uint32 op) -{ -uint32 tmin = Q_LGP21? min_21[op]: min_30[op]; -uint32 tmax = Q_LGP21? max_21[op]: max_30[op]; -uint32 nsc, curp, newp, oprp, pcdelta, opdelta; - -if (Q_LGP21) { /* LGP21 */ - nsc = NSC_21; /* full rotation delay */ - curp = log_to_phys_21[opc & SCMASK_21]; /* current phys pos */ - newp = log_to_phys_21[PC & SCMASK_21]; /* new PC phys pos */ - oprp = log_to_phys_21[ea & SCMASK_21]; /* ea phys pos */ - pcdelta = (newp - curp + NSC_21) & SCMASK_21; - opdelta = (oprp - curp + NSC_21) & SCMASK_21; - } -else { - nsc = NSC_30; - curp = log_to_phys_30[opc & SCMASK_30]; - newp = log_to_phys_30[PC & SCMASK_30]; - oprp = log_to_phys_30[ea & SCMASK_30]; - pcdelta = (newp - curp + NSC_30) & SCMASK_30; - opdelta = (oprp - curp + NSC_30) & SCMASK_30; - } -if (tmax == 0) { /* skip ea calc? */ - if (pcdelta >= tmin) /* new PC >= min? */ - return pcdelta - 1; - return pcdelta + nsc - 1; - } -if ((opdelta >= tmin) && (opdelta <= tmax)) - return pcdelta - 1; -return pcdelta + nsc - 1; -} - -/* Reset routine */ - -t_stat cpu_reset (DEVICE *dptr) -{ -OVF = 0; -inp_strt = 0; -inp_done = 0; -out_strt = 0; -out_done = 0; -lgp21_sov = 0; -delay = 0; -lgp_vm_init (); -pcq_r = find_reg ("CQ", NULL, dptr); -if (pcq_r) - pcq_r->qptr = 0; -else return SCPE_IERR; -sim_brk_types = sim_brk_dflt = SWMASK ('E'); -return SCPE_OK; -} - -/* Validate option, must be LGP30 */ - -t_stat cpu_set_30opt (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (Q_LGP21) - return SCPE_ARG; -return SCPE_OK; -} - -/* Validate input option, must be LGP30 */ - -t_stat cpu_set_30opt_i (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (Q_LGP21 || (cptr == NULL)) - return SCPE_ARG; -if (strcmp (cptr, "TTI") == 0) - uptr->flags = uptr->flags & ~UNIT_INPT; -else if (strcmp (cptr, "PTR") == 0) - uptr->flags = uptr->flags | UNIT_INPT; -else return SCPE_ARG; -return SCPE_OK; -} - -/* Validate output option, must be LGP30 */ - -t_stat cpu_set_30opt_o (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (Q_LGP21 || (cptr == NULL)) - return SCPE_ARG; -if (strcmp (cptr, "TTO") == 0) - uptr->flags = uptr->flags & ~UNIT_OUTPT; -else if (strcmp (cptr, "PTP") == 0) - uptr->flags = uptr->flags | UNIT_OUTPT; -else return SCPE_ARG; -return SCPE_OK; -} - -/* Set CPU to LGP21 or LPG30 */ - -t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (val) - uptr->flags = uptr->flags & ~(UNIT_IN4B|UNIT_INPT|UNIT_OUTPT); -return reset_all (0); -} - -/* Show CPU type and all options */ - -t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -fputs (Q_LGP21? "LGP-21": "LGP-30", st); -if (uptr->flags & UNIT_TTSS_D) - fputs (", track/sector", st); -if (uptr->flags & UNIT_LGPH_D) - fputs (", LGP hex", st); -fputs (Q_MANI? ", manual": ", tape", st); -if (!Q_LGP21) { - fputs (Q_IN4B? ", 4b": ", 6b", st); - fputs (Q_INPT? ", in=PTR": ", in=TTI", st); - fputs (Q_OUTPT? ", out=PTP": ", out=TTO", st); - } -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 = Read (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; -Write (addr, val); -return SCPE_OK; -} - -/* Execute */ - -t_stat cpu_set_exec (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -uint32 inst; -t_stat r; - -if (cptr) { - inst = get_uint (cptr, 16, DMASK, &r); - if (r != SCPE_OK) - return r; - } -else inst = IR; -while ((r = cpu_one_inst (PC, inst)) == STOP_STALL) { - sim_interval = 0; - if ((r = sim_process_event ())) - return r; - } -return r; -} - -/* Fill */ - -t_stat cpu_set_fill (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -uint32 inst; -t_stat r; - -if (cptr) { - inst = get_uint (cptr, 16, DMASK, &r); - if (r != SCPE_OK) - return r; - IR = inst; - } -else IR = A; -return SCPE_OK; -} diff --git a/LGP/lgp_defs.h b/LGP/lgp_defs.h deleted file mode 100644 index fdff4d02..00000000 --- a/LGP/lgp_defs.h +++ /dev/null @@ -1,141 +0,0 @@ -/* lgp_defs.h: LGP simulator definitions - - Copyright (c) 2004-2010, 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 - 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. - - 22-May-10 RMS Added check for 64b definitions -*/ - -#ifndef LGP_DEFS_H_ -#define LGP_DEFS_H_ 0 - -#include "sim_defs.h" /* simulator defns */ - -#if defined(USE_INT64) || defined(USE_ADDR64) -#error "LGP-30 does not support 64b values!" -#endif - -/* Simulator stop codes */ - -#define STOP_STOP 1 /* STOP */ -#define STOP_IBKPT 2 /* breakpoint */ -#define STOP_OVF 3 /* overflow */ -#define STOP_NXDEV 4 /* non-existent device */ -#define STOP_STALL 5 /* IO stall */ - -/* Memory */ - -#define MEMSIZE 4096 /* memory size */ -#define AMASK 0xFFF /* addr mask */ -#define NTK_30 64 -#define NSC_30 64 -#define SCMASK_30 0x03F /* sector mask */ -#define NTK_21 32 -#define NSC_21 128 -#define SCMASK_21 0x07F -#define RPM 4000 /* rev/minutes */ -#define WPS ((NSC_30 * RPM) / 60) /* words/second */ - -/* Architectural constants */ - -#define SIGN 0x80000000 /* sign */ -#define DMASK 0xFFFFFFFF /* data mask */ -#define MMASK 0xFFFFFFFE /* memory mask */ - -/* Instruction format */ - -#define I_M_OP 0xF /* opcode */ -#define I_V_OP 16 -#define I_OP (I_M_OP << I_V_OP) -#define I_GETOP(x) (((x) >> I_V_OP) & I_M_OP) -#define I_M_EA AMASK /* address */ -#define I_V_EA 2 -#define I_EA (I_M_EA << I_V_EA) -#define I_GETEA(x) (((x) >> I_V_EA) & I_M_EA) -#define I_M_TK 0x3F /* LGP-30 char */ -#define I_V_TK 8 /* LGP-21 device */ -#define I_GETTK(x) (((x) >> I_V_TK) & I_M_TK) - -/* Unit flags */ - -#define UNIT_V_LGP21 (UNIT_V_UF + 0) -#define UNIT_V_MANI (UNIT_V_UF + 1) -#define UNIT_V_INPT (UNIT_V_UF + 2) -#define UNIT_V_OUTPT (UNIT_V_UF + 3) -#define UNIT_V_IN4B (UNIT_V_UF + 4) -#define UNIT_V_TTSS_D (UNIT_V_UF + 5) -#define UNIT_V_LGPH_D (UNIT_V_UF + 6) -#define UNIT_V_FLEX_D (UNIT_V_UF + 7) /* Flex default */ -#define UNIT_V_FLEX (UNIT_V_UF + 8) /* Flex format */ -#define UNIT_V_NOCS (UNIT_V_UF + 9) /* ignore cond stop */ -#define UNIT_LGP21 (1u << UNIT_V_LGP21) -#define UNIT_MANI (1u << UNIT_V_MANI) -#define UNIT_INPT (1u << UNIT_V_INPT) -#define UNIT_OUTPT (1u << UNIT_V_OUTPT) -#define UNIT_IN4B (1u << UNIT_V_IN4B) -#define UNIT_TTSS_D (1u << UNIT_V_TTSS_D) -#define UNIT_LGPH_D (1u << UNIT_V_LGPH_D) -#define UNIT_FLEX_D (1u << UNIT_V_FLEX_D) -#define UNIT_FLEX (1u << UNIT_V_FLEX) -#define UNIT_NOCS (1u << UNIT_V_NOCS) -#define Q_LGP21 (cpu_unit.flags & UNIT_LGP21) -#define Q_MANI (cpu_unit.flags & UNIT_MANI) -#define Q_INPT (cpu_unit.flags & UNIT_INPT) -#define Q_OUTPT (cpu_unit.flags & UNIT_OUTPT) -#define Q_IN4B (cpu_unit.flags & UNIT_IN4B) - -/* IO return */ - -#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */ - -/* Significant characters */ - -#define FLEX_LC 0x04 -#define FLEX_UC 0x08 -#define FLEX_CR 0x10 -#define FLEX_BS 0x14 -#define FLEX_CSTOP 0x20 -#define FLEX_DEL 0x3F - -/* LGP-21 device assignments */ - -#define DEV_PT 0 -#define DEV_TT 2 -#define DEV_MASK 0x1F -#define DEV_SHIFT 62 - -/* Instructions */ - -enum opcodes { - OP_Z, OP_B, OP_Y, OP_R, - OP_I, OP_D, OP_N, OP_M, - OP_P, OP_E, OP_U, OP_T, - OP_H, OP_C, OP_A, OP_S - }; - -/* Prototypes */ - -uint32 Read (uint32 ea); -void Write (uint32 ea, uint32 dat); - -#endif diff --git a/LGP/lgp_stddev.c b/LGP/lgp_stddev.c deleted file mode 100644 index 80657ab1..00000000 --- a/LGP/lgp_stddev.c +++ /dev/null @@ -1,684 +0,0 @@ -/* lgp_stddev.c: LGP-30 standard devices - - Copyright (c) 2004-2008, 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. - - tti typewriter input (keyboard and reader) - tto typewriter output (printer and punch) - ptr high speed reader - ptpp high speed punch - - 26-Nov-2008 RMS Changed encode character from # to ! -*/ - -#include "lgp_defs.h" -#include - -uint32 tt_wait = WPS / 10; -uint32 tti_buf = 0; -uint32 tti_rdy = 0; -uint32 tto_uc = 0; -uint32 tto_buf = 0; -uint32 ttr_stopioe = 1; -uint32 ptr_rdy = 0; -uint32 ptr_stopioe = 1; -uint32 ptp_stopioe = 1; - -extern uint32 A; -extern uint32 inp_strt, inp_done; -extern uint32 out_strt, out_done; -extern UNIT cpu_unit; - -t_stat tti_svc (UNIT *uptr); -t_stat ttr_svc (UNIT *uptr); -t_stat tto_svc (UNIT *uptr); -t_stat tti_reset (DEVICE *uptr); -t_stat tto_reset (DEVICE *uptr); -t_stat ptr_svc (UNIT *uptr); -t_stat ptp_svc (UNIT *uptr); -t_stat ptr_reset (DEVICE *uptr); -t_stat ptp_reset (DEVICE *uptr); -t_stat tap_attach (UNIT *uptr, char *cptr); -t_stat tap_attable (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat read_reader (UNIT *uptr, int32 stop, int32 *c); -t_stat write_tto (int32 flex); -t_stat write_punch (UNIT *uptr, int32 flex); -t_stat tti_rdrss (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat punch_feed (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat send_start (UNIT *uptr, int32 val, char *cptr, void *desc); - -extern uint32 shift_in (uint32 a, uint32 dat, uint32 sh4); - -/* Conversion tables */ - -const int32 flex_to_ascii[128] = { - -1 , 'z', '0', ' ', '>', 'b', '1', '-', - '<' , 'y', '2', '+', '|', 'r', '3', ';', - '\r', 'i', '4', '/','\\', 'd', '5', '.', - '\t', 'n', '6', ',', -1 , 'm', '7', 'v', - '\'', 'p', '8', 'o', -1 , 'e', '9', 'x', - -1 , 'u', 'f', -1 , -1 , 't', 'g', -1 , - -1 , 'h', 'j', -1 , -1 , 'c', 'k', -1 , - -1 , 'a', 'q', -1 , -1 , 's', 'w', 0 , - - -1 , 'Z', ')', ' ', -1 , 'B', 'L', '_', - -1 , 'Y', '*', '=', '|', 'R', '"', ':', - '\r', 'I', '^', '?','\\', 'D', '%', ']', - '\t', 'N', '$', '[', -1 , 'M', '~', 'V', - '\'', 'P', '#', 'O', -1 , 'E', '(', 'X', - -1 , 'U', 'F', -1 , -1 , 'T', 'G', -1 , - -1 , 'H', 'J', -1 , -1 , 'C', 'K', -1 , - -1 , 'A', 'Q', -1 , -1 , 'S', 'W', 0 - }; - -const int32 ascii_to_flex[128] = { - -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , - 024, 030, -1 , -1 , -1 , 020, -1 , -1 , - -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , - -1 , -1 , -1 , -1 , -1 , -1 , -1 , -1 , - 003, -1 , 016, 042, 032, 026, -1 , 040, - 046, 001, 012, 013, 033, 007, 027, 023, - 002, 006, 012, 016, 022, 026, 032, 036, - 042, 046, 017, 017, 004, 013, 010, 023, - -1 , 071, 005, 065, 025, 045, 052, 056, - 061, 021, 062, 066, 006, 035, 031, 043, - 041, 072, 015, 075, 055, 051, 037, 076, - 047, 011, 001, 033, -1 , 027, 022, 007, - -1, 071, 005, 065, 025, 045, 052, 056, - 061, 021, 062, 066, 006, 035, 031, 043, - 041, 072, 015, 075, 055, 051, 037, 076, - 047, 011, 001, -1 , 014, -1 , 036, 077 - }; - -static const uint8 flex_inp_valid[64] = { - 1, 1, 1, 1, 0, 1, 1, 1, - 0, 1, 1, 1, 0, 1, 1, 1, - 0, 1, 1, 1, 0, 1, 1, 1, - 0, 1, 1, 1, 0, 1, 1, 1, - 1, 1, 1, 1, 0, 1, 1, 1, - 0, 1, 1, 1, 0, 1, 1, 1, - 0, 1, 1, 1, 0, 1, 1, 1, - 0, 1, 1, 1, 0, 1, 1, 1 - }; - -/* TTI data structures - - tti_dev TTI device descriptor - tti_unit TTI unit descriptor - tti_mod TTI modifier list - tti_reg TTI register list -*/ - -UNIT tti_unit[] = { - { UDATA (&tti_svc, 0, 0) }, - { UDATA (&ttr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0) } - }; - -REG tti_reg[] = { - { HRDATA (BUF, tti_buf, 6) }, - { FLDATA (RDY, tti_rdy, 0) }, - { DRDATA (KPOS, tti_unit[0].pos, T_ADDR_W), PV_LEFT }, - { DRDATA (RPOS, tti_unit[1].pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, tt_wait, 24), REG_NZ + PV_LEFT }, - { FLDATA (STOP_IOE, ttr_stopioe, 0) }, - { NULL } - }; - -MTAB tti_mod[] = { - { UNIT_FLEX_D, UNIT_FLEX_D, NULL, "FLEX", &tap_attable }, - { UNIT_FLEX_D, 0, NULL, "ASCII", &tap_attable }, - { UNIT_ATT+UNIT_FLEX, UNIT_ATT+UNIT_FLEX, - "file is Flex", NULL }, - { UNIT_ATT+UNIT_FLEX, UNIT_ATT, - "file is ASCII", NULL }, - { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE+UNIT_FLEX, - "default is Flex", NULL }, - { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE, - "default is ASCII", NULL }, - { UNIT_ATTABLE+UNIT_NOCS, UNIT_ATTABLE+UNIT_NOCS, - "ignore conditional stop", "NOCSTOP", &tap_attable }, - { UNIT_ATTABLE+UNIT_NOCS, UNIT_ATTABLE , - NULL, "CSTOP", &tap_attable }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "START", &send_start }, - { MTAB_XTD|MTAB_VDV, 1, NULL, "RSTART", &tti_rdrss }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "RSTOP", &tti_rdrss }, - { 0 } - }; - -DEVICE tti_dev = { - "TTI", tti_unit, tti_reg, tti_mod, - 2, 10, 31, 1, 16, 7, - NULL, NULL, &tti_reset, - NULL, &tap_attach, NULL - }; - -/* TTO data structures - - tto_dev TTO device descriptor - tto_unit TTO unit descriptor - tto_mod TTO modifier list - tto_reg TTO register list -*/ - -UNIT tto_unit[] = { - { UDATA (&tto_svc, 0, 0) }, - { UDATA (NULL, UNIT_SEQ+UNIT_ATTABLE, 0) } - }; - -REG tto_reg[] = { - { HRDATA (BUF, tto_buf, 6) }, - { FLDATA (UC, tto_uc, 0) }, - { DRDATA (TPOS, tto_unit[0].pos, T_ADDR_W), PV_LEFT }, - { DRDATA (PPOS, tto_unit[1].pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, tt_wait, 24), PV_LEFT }, - { NULL } - }; - -MTAB tto_mod[] = { - { UNIT_FLEX_D, UNIT_FLEX_D, NULL, "FLEX", &tap_attable }, - { UNIT_FLEX_D, 0, NULL, "ASCII", &tap_attable }, - { UNIT_ATT+UNIT_FLEX, UNIT_ATT+UNIT_FLEX, - "file is Flex", NULL }, - { UNIT_ATT+UNIT_FLEX, UNIT_ATT, - "file is ASCII", NULL }, - { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE+UNIT_FLEX, - "default is Flex", NULL }, - { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE, - "default is ASCII", NULL }, - { MTAB_XTD|MTAB_VUN, 0, NULL, "FEED", &punch_feed }, - { 0 } - }; - -DEVICE tto_dev = { - "TTO", tto_unit, tto_reg, tto_mod, - 2, 10, 31, 1, 16, 7, - NULL, NULL, &tto_reset, - NULL, &tap_attach, NULL - }; - -/* PTR data structures - - ptr_dev PTR device descriptor - ptr_unit PTR unit descriptor - ptr_mod PTR modifier list - ptr_reg PTR register list -*/ - -UNIT ptr_unit = { - UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), WPS / 200 - }; - -REG ptr_reg[] = { - { HRDATA (BUF, ptr_unit.buf, 6) }, - { FLDATA (RDY, ptr_rdy, 0) }, - { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, ptr_unit.wait, 24), REG_NZ + PV_LEFT }, - { FLDATA (STOP_IOE, ptr_stopioe, 0) }, - { NULL } - }; - -MTAB ptr_mod[] = { - { UNIT_FLEX_D, UNIT_FLEX_D, NULL, "FLEX", &tap_attable }, - { UNIT_FLEX_D, 0, NULL, "ASCII", &tap_attable }, - { UNIT_ATT+UNIT_FLEX, UNIT_ATT+UNIT_FLEX, - "file is Flex", NULL }, - { UNIT_ATT+UNIT_FLEX, UNIT_ATT, - "file is ASCII", NULL }, - { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE+UNIT_FLEX, - "default is Flex", NULL }, - { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE, - "default is ASCII", NULL }, - { 0 } - }; - -DEVICE ptr_dev = { - "PTR", &ptr_unit, ptr_reg, ptr_mod, - 1, 10, 31, 1, 16, 7, - NULL, NULL, &ptr_reset, - NULL, &tap_attach, NULL - }; - -/* PTP data structures - - ptp_dev PTP device descriptor - ptp_unit PTP unit descriptor - ptp_mod PTP modifier list - ptp_reg PTP register list -*/ - -UNIT ptp_unit = { - UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), WPS / 20 - }; - -REG ptp_reg[] = { - { ORDATA (BUF, ptp_unit.buf, 8) }, - { DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, - { FLDATA (STOP_IOE, ptp_stopioe, 0) }, - { NULL } - }; - -MTAB ptp_mod[] = { - { UNIT_FLEX_D, UNIT_FLEX_D, NULL, "FLEX", &tap_attable }, - { UNIT_FLEX_D, 0, NULL, "ASCII", &tap_attable }, - { UNIT_ATT+UNIT_FLEX, UNIT_ATT+UNIT_FLEX, - "file is Flex", NULL }, - { UNIT_ATT+UNIT_FLEX, UNIT_ATT, - "file is ASCII", NULL }, - { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE+UNIT_FLEX, - "default is Flex", NULL }, - { UNIT_ATTABLE+UNIT_ATT+UNIT_FLEX, UNIT_ATTABLE, - "default is ASCII", NULL }, - { 0 } - }; - -DEVICE ptp_dev = { - "PTP", &ptp_unit, ptp_reg, ptp_mod, - 1, 10, 31, 1, 16, 7, - NULL, NULL, &ptp_reset, - NULL, &tap_attach, NULL - }; - -/* Input instruction */ - -void op_i_strt (uint32 dev) -{ -switch (dev) { /* case on device */ - - case DEV_PT: /* ptr */ - sim_activate (&ptr_unit, ptr_unit.wait); /* activate */ - break; - - case DEV_TT: /* tti/ttr */ - if (Q_MANI) /* manual input? */ - sim_putchar ('`'); - else sim_activate (&tti_unit[1], tt_wait); /* no, must be ttr */ - break; - } -return; -} - -t_stat op_i (uint32 dev, uint32 ch, uint32 sh4) -{ -if (Q_LGP21 && out_strt) /* LGP-21? must be idle */ - return STOP_STALL; -if (!inp_strt) { /* input started? */ - inp_strt = 1; /* no, set start */ - inp_done = 0; /* clear done */ - A = shift_in (A, ch, sh4); - tti_rdy = ptr_rdy = 0; /* no input */ - if (Q_LGP21 || Q_INPT) /* LGP-21 or PTR? start */ - op_i_strt (dev); - } -switch (dev) { /* case on device */ - - case DEV_PT: /* ptr */ - if (ptr_rdy) { /* char ready? */ - ptr_rdy = 0; /* reset ready */ - if ((ptr_unit.buf != FLEX_DEL) && /* ignore delete and */ - (!Q_LGP21 || ((ptr_unit.buf & 3) == 2))) /* LGP-21 4b? zone != 2 */ - A = shift_in (A, ptr_unit.buf, sh4); /* shift data in */ - } - break; - - case DEV_TT: /* tti/ttr */ - if (tti_rdy) { /* char ready? */ - tti_rdy = 0; /* reset ready */ - if ((tti_buf != FLEX_DEL) && /* ignore delete and */ - (!Q_LGP21 || ((tti_buf & 3) != 0))) /* LGP-21 4b? zone == 0 */ - A = shift_in (A, tti_buf, sh4); /* shift data in */ - } - break; - - default: /* nx device */ - return STOP_NXDEV; /* return error */ - } - -if (inp_done) { /* done? */ - inp_strt = inp_done = 0; /* clear start, done */ - return SCPE_OK; /* no stall */ - } -return STOP_STALL; /* stall */ -} - -/* Terminal keyboard unit service */ - -t_stat tti_svc (UNIT *uptr) -{ -int32 c, flex; - -sim_activate (uptr, tt_wait); /* continue poll */ -if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */ - return c; -flex = ascii_to_flex[c & 0x1FF]; /* cvt to flex */ -if (flex > 0) { /* it's a typewriter... */ - write_tto (flex); /* always echos */ - if (tto_unit[1].flags & UNIT_ATT) /* ttp attached? */ - write_punch (&tto_unit[1], tto_buf); /* punch to ttp */ - } -else write_tto ('\a'); /* don't echo bad */ -if (Q_MANI && (flex > 0) && flex_inp_valid[flex]) { /* wanted, valid? */ - if (flex == FLEX_CSTOP) /* conditional stop? */ - inp_done = 1; - else tti_rdy = 1; /* no, set ready */ - tti_buf = flex; /* save char */ - uptr->pos = uptr->pos + 1; - } -return SCPE_OK; -} - -/* Terminal reader unit service */ - -t_stat ttr_svc (UNIT *uptr) -{ -t_stat r; - -if ((r = read_reader (uptr, ttr_stopioe, (int32 *) &tti_buf))) - return r; -if (!(uptr->flags & UNIT_NOCS) && /* cstop enable? */ - (tti_buf == FLEX_CSTOP)) /* cond stop? */ - inp_done = 1; -else { - tti_rdy = 1; /* no, set ready */ - sim_activate (uptr, tt_wait); /* cont reading */ - } -write_tto (tti_buf); /* echo to tto */ -if (tto_unit[1].flags & UNIT_ATT) /* ttp attached? */ - return write_punch (&tto_unit[1], tti_buf); /* punch to ttp */ -return SCPE_OK; -} - -/* Paper tape reader unit service */ - -t_stat ptr_svc (UNIT *uptr) -{ -t_stat r; - -if ((r = read_reader (uptr, ptr_stopioe, &uptr->buf))) - return r; -if (uptr->buf == FLEX_CSTOP) /* cond stop? */ - inp_done = 1; -else { - ptr_rdy = 1; /* no, set ready */ - sim_activate (uptr, uptr->wait); /* cont reading */ - } -return SCPE_OK; -} - -/* Output instruction */ - -t_stat op_p (uint32 dev, uint32 ch) -{ -switch (dev) { /* case on device */ - - case DEV_PT: /* paper tape punch */ - if (sim_is_active (&ptp_unit)) /* busy? */ - return (Q_LGP21? STOP_STALL: SCPE_OK); /* LGP-21: stall */ - ptp_unit.buf = ch; /* save char */ - sim_activate (&ptp_unit, ptp_unit.wait); /* activate ptp */ - break; - - case DEV_TT: /* typewriter */ - if (ch == 0) { /* start input? */ - if (!Q_LGP21 && !Q_INPT) /* ignore if LGP-21, ptr */ - op_i_strt (DEV_TT); /* start tti */ - return SCPE_OK; /* no stall */ - } - if (sim_is_active (&tto_unit[0])) /* busy? */ - return (Q_LGP21? STOP_STALL: SCPE_OK); /* LGP-21: stall */ - tto_buf = ch; /* save char */ - sim_activate (&tto_unit[0], tt_wait); /* activate tto */ - break; - - default: /* unknown */ - return STOP_NXDEV; /* return error */ - } - -if (out_strt == 0) { /* output started? */ - out_strt = 1; /* flag start */ - out_done = 0; /* clear done */ - } -return SCPE_OK; /* no stall */ -} - -/* Terminal printer unit service */ - -t_stat tto_svc (UNIT *uptr) -{ -t_stat r; - -if ((r = write_tto (tto_buf)) != SCPE_OK) { /* output; error? */ - sim_activate (uptr, tt_wait); /* try again */ - return ((r == SCPE_STALL)? SCPE_OK: r); /* !stall? report */ - } -out_strt = 0; -out_done = 1; -if (tto_unit[1].flags & UNIT_ATT) /* ttp attached? */ - return write_punch (&tto_unit[1], tto_buf); /* punch to ttp */ -return SCPE_OK; -} - -/* Paper tape punch unit service */ - -t_stat ptp_svc (UNIT *uptr) -{ -out_strt = 0; -out_done = 1; -if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ - return IORETURN (ptp_stopioe, SCPE_UNATT); /* error */ -return write_punch (uptr, uptr->buf); /* write to ptp */ -} - -/* Utility routines */ - -t_stat read_reader (UNIT *uptr, int32 stop, int32 *fl) -{ -int32 ch, flex; - -if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (stop, SCPE_UNATT); -do { - if ((ch = getc (uptr->fileref)) == EOF) { /* read char */ - if (feof (uptr->fileref)) { /* err or eof? */ - if (stop) - sim_printf ("Reader end of file\n"); - else return SCPE_OK; - } - else perror ("Reader I/O error"); - clearerr (uptr->fileref); - return SCPE_IOERR; - } - if (uptr->flags & UNIT_FLEX) /* transposed flex? */ - flex = ((ch << 1) | (ch >> 5)) & 0x3F; /* undo 612345 */ - else if (ch == '!') { /* encoded? */ - int32 d1 = getc (uptr->fileref); /* get 2 digits */ - int32 d2 = getc (uptr->fileref); - if ((d1 == EOF) || (d2 == EOF)) { /* error? */ - if (feof (uptr->fileref)) { /* eof? */ - if (stop) - sim_printf ("Reader end of file\n"); - else return SCPE_OK; - } - else perror ("Reader I/O error"); - clearerr (uptr->fileref); - return SCPE_IOERR; - } - flex = (((d1 - '0') * 10) + (d2 - '0')) & 0x3F; - uptr->pos = uptr->pos + 2; - } - else flex = ascii_to_flex[ch & 0x7F]; /* convert */ - uptr->pos = uptr->pos + 1; - } while (flex < 0); /* until valid */ -*fl = flex; /* return char */ -return SCPE_OK; -} - -t_stat write_tto (int32 flex) -{ -int32 ch; -t_stat r; - -if (flex == FLEX_UC) /* UC? set state */ - tto_uc = 1; -else if (flex == FLEX_LC) /* LC? set state */ - tto_uc = 0; -else { - if (flex == FLEX_BS) /* backspace? */ - ch = '\b'; - else ch = flex_to_ascii[flex | (tto_uc << 6)]; /* cvt flex to ascii */ - if (ch > 0) { /* legit? */ - if ((r = sim_putchar_s (ch))) /* write char */ - return r; - tto_unit[0].pos = tto_unit[0].pos + 1; - if (flex == FLEX_CR) { /* cr? */ - sim_putchar ('\n'); /* add lf */ - tto_unit[0].pos = tto_unit[0].pos + 1; - } - } - } -return SCPE_OK; -} - -t_stat write_punch (UNIT *uptr, int32 flex) -{ -int32 c, sta; - -if (uptr->flags & UNIT_FLEX) /* transposed flex? */ - c = ((flex >> 1) | (flex << 5)) & 0x3F; /* reorder to 612345 */ -else c = flex_to_ascii[flex]; /* convert to ASCII */ -if (c >= 0) /* valid? */ - sta = fputc (c, uptr->fileref); -else sta = fprintf (uptr->fileref, "!%02d", flex); /* no, encode */ -if (sta == EOF) { /* error? */ - perror ("Punch I/O error"); /* error? */ - clearerr (uptr->fileref); - return SCPE_IOERR; - } -uptr->pos = uptr->pos + ((c >= 0)? 1: 3); /* incr position */ -return SCPE_OK; -} - -/* Reset routines */ - -t_stat tti_reset (DEVICE *dptr) -{ -sim_activate (&tti_unit[0], tt_wait); -sim_cancel (&tti_unit[1]); -tti_buf = 0; -tti_rdy = 0; -return SCPE_OK; -} - -t_stat tto_reset (DEVICE *dptr) -{ -sim_cancel (&tto_unit[0]); -tto_buf = 0; -tto_uc = 0; -return SCPE_OK; -} - -t_stat ptr_reset (DEVICE *dptr) -{ -sim_cancel (&ptr_unit); -ptr_unit.buf = 0; -ptr_rdy = 0; -return SCPE_OK; -} - -t_stat ptp_reset (DEVICE *dptr) -{ -sim_cancel (&ptp_unit); -ptp_unit.buf = 0; -return SCPE_OK; -} - -/* Attach paper tape unit */ - -t_stat tap_attach (UNIT *uptr, char *cptr) -{ -t_stat r; - -if ((r = attach_unit (uptr,cptr)) != SCPE_OK) - return r; -if ((sim_switches & SWMASK ('F')) || - ((uptr->flags & UNIT_FLEX_D) && !(sim_switches & SWMASK ('A')))) - uptr->flags = uptr->flags | UNIT_FLEX; -else uptr->flags = uptr->flags & ~UNIT_FLEX; -return SCPE_OK; -} - -/* Validate unit is attachable */ - -t_stat tap_attable (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (uptr->flags & UNIT_ATTABLE) - return SCPE_OK; -return SCPE_NOFNC; -} - -/* Typewriter reader start/stop */ - -t_stat tti_rdrss (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (val) { - if ((tti_unit[1].flags & UNIT_ATT) == 0) - return SCPE_UNATT; - sim_activate (&tti_unit[1], tt_wait); - } -else sim_cancel (&tti_unit[1]); -return SCPE_OK; -} - -/* Punch feed routine */ - -t_stat punch_feed (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 cnt; -t_stat r; - -if ((uptr->flags & UNIT_ATT) == 0) - return SCPE_UNATT; -if (cptr) { - cnt = (int32) get_uint (cptr, 10, 512, &r); - if ((r != SCPE_OK) || (cnt == 0)) - return SCPE_ARG; - } -else cnt = 10; -while (cnt-- > 0) { - r = write_punch (uptr, 0); - if (r != SCPE_OK) - return r; - } -return SCPE_OK; -} - -/* Send start signal */ - -t_stat send_start (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (inp_strt) - inp_done = 1; -else if (out_strt) - out_done = 1; -return SCPE_OK; -} diff --git a/LGP/lgp_sys.c b/LGP/lgp_sys.c deleted file mode 100644 index a5047d7b..00000000 --- a/LGP/lgp_sys.c +++ /dev/null @@ -1,398 +0,0 @@ -/* lgp_sys.c: LGP-30 simulator interface - - Copyright (c) 2004-2008, Robert M Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - 04-Jan-05 RMS Modified VM pointer setup -*/ - -#include "lgp_defs.h" -#include - -t_stat parse_sym_m (char *cptr, t_value *val, int32 sw); -void lgp_init (void); - -extern DEVICE cpu_dev; -extern UNIT cpu_unit; -extern DEVICE tti_dev, tto_dev; -extern DEVICE ptr_dev, ptp_dev; -extern REG cpu_reg[]; -extern uint32 M[]; -extern uint32 PC; -extern uint32 ts_flag; -extern int32 flex_to_ascii[128], ascii_to_flex[128]; - -/* SCP data structures and interface routines - - sim_name simulator name string - sim_PC pointer to saved PC register descriptor - sim_emax maximum number of words for examine/deposit - sim_devices array of pointers to simulated devices - sim_stop_messages array of pointers to stop messages - sim_load binary loader -*/ - -char sim_name[] = "LGP30"; - -REG *sim_PC = &cpu_reg[0]; - -int32 sim_emax = 1; - -DEVICE *sim_devices[] = { - &cpu_dev, - &tti_dev, - &tto_dev, - &ptr_dev, - &ptp_dev, - NULL - }; - -const char *sim_stop_messages[] = { - "Unknown error", - "STOP", - "Breakpoint", - "Arithmetic overflow" - }; - -/* Binary loader - implements a restricted form of subroutine 10.4 - - Switches: - -t, input file is transposed Flex - -n, no checksums on v commands (10.0 compatible) - default is ASCII encoded Flex - Commands (in bits 0-3): - (blank) instruction - + command (not supported) - ; start fill - / set modifier - . stop and transfer - , hex words - v hex fill (checksummed unless -n) - 8 negative instruction -*/ - -/* Utility routine - read characters until ' (conditional stop) */ - -t_stat load_getw (FILE *fi, uint32 *wd) -{ -int32 flex, c; - -*wd = 0; -while ((c = fgetc (fi)) != EOF) { - if (sim_switches & SWMASK ('T')) - flex = ((c << 1) | (c >> 5)) & 0x3F; - else flex = ascii_to_flex[c & 0x7F]; - if ((flex == FLEX_CR) || (flex == FLEX_DEL) || - (flex == FLEX_UC) || (flex == FLEX_LC) || - (flex == FLEX_BS) || (flex < 0)) - continue; - if (flex == FLEX_CSTOP) - return SCPE_OK; - *wd = (*wd << 4) | ((flex >> 2) & 0xF); - } -return SCPE_FMT; -} - -/* Utility routine - convert ttss decimal address to binary */ - -t_stat load_geta (uint32 wd, uint32 *ad) -{ -uint32 n1, n2, n3, n4, tr, sc; - -n1 = (wd >> 12) & 0xF; -n2 = (wd >> 8) & 0xF; -n3 = (wd >> 4) & 0xF; -n4 = wd & 0xF; -if ((n2 > 9) || (n4 > 9)) - return SCPE_ARG; -tr = (n1 * 10) + n2; -sc = (n3 * 10) + n4; -if ((tr >= NTK_30) || (sc >= NSC_30)) - return SCPE_ARG; -*ad = (tr * NSC_30) + sc; -return SCPE_OK; -} - -/* Loader proper */ - -t_stat sim_load (FILE *fi, char *cptr, char *fnam, int flag) -{ -uint32 wd, origin, amod, csum, cnt, tr, sc, ad, cmd; - -origin = amod = 0; -for (;;) { /* until stopped */ - if (load_getw (fi, &wd)) /* get ctrl word */ - break; - cmd = (wd >> 28) & 0xF; /* get <0:3> */ - switch (cmd) { /* decode <0:3> */ - - case 0x2: /* + command */ - return SCPE_FMT; - - case 0x3: /* ; start fill */ - if (load_geta (wd, &origin)) /* origin = addr */ - return SCPE_FMT; - break; - - case 0x4: /* / set modifier */ - if (load_geta (wd, &amod)) /* modifier = addr */ - return SCPE_FMT; - break; - - case 0x5: /* . transfer */ - if (load_geta (wd, &PC)) /* PC = addr */ - return SCPE_FMT; - return SCPE_OK; /* done! */ - - case 0x6: /* hex words */ - if (load_geta (wd, &cnt)) /* count = addr */ - return SCPE_FMT; - if ((cnt == 0) || (cnt > 63)) - return SCPE_FMT; - while (cnt--) { /* fill hex words */ - if (load_getw (fi, &wd)) - return SCPE_FMT; - Write (origin, wd); - origin = (origin + 1) & AMASK; - } - break; - - case 0x7: /* hex fill */ - cnt = (wd >> 16) & 0xFFF; /* hex count */ - tr = (wd >> 8) & 0xFF; /* hex track */ - sc = wd & 0xFF; /* hex sector */ - if ((cnt == 0) || (cnt > 0x7FF) || /* validate */ - (tr >= NTK_30) || (sc >= NSC_30)) - return SCPE_ARG; - ad = (tr * NSC_30) + sc; /* decimal addr */ - for (csum = 0; cnt; cnt--) { /* fill words */ - if (load_getw (fi, &wd)) - return SCPE_FMT; - Write (ad, wd); - csum = (csum + wd) & MMASK; - ad = (ad + 1) & AMASK; - } - if (!(sim_switches & SWMASK ('N'))) { /* unless -n, csum */ - if (load_getw (fi, &wd)) - return SCPE_FMT; -/* if ((csum ^wd) & MMASK) - return SCPE_CSUM; */ - } - break; - - case 0x0: case 0x8: /* instructions */ - if (load_geta (wd, &ad)) /* get address */ - return SCPE_FMT; - if ((wd & 0x00F00000) != 0x00900000) /* if not x, */ - ad = (ad + amod) & AMASK; /* modify */ - wd = (wd & (SIGN|I_OP)) + (ad << I_V_EA); /* instruction */ - - default: /* data word */ - Write (origin, wd); - origin = (origin + 1) & AMASK; - break; - } /* end case */ - } /* end for */ -return SCPE_OK; -} - -/* Symbol tables */ - -static const char opcode[] = "ZBYRIDNMPEUTHCAS"; - -static const char hex_decode[] = "0123456789FGJKQW"; - -void lgp_fprint_addr (FILE *st, DEVICE *dptr, t_addr addr) -{ -if ((dptr == sim_devices[0]) && - ((sim_switches & SWMASK ('T')) || - ((cpu_unit.flags & UNIT_TTSS_D) && !(sim_switches & SWMASK ('N'))))) - fprintf (st, "%02d%02d", addr >> 6, addr & SCMASK_30); -else fprint_val (st, addr, dptr->aradix, dptr->awidth, PV_LEFT); -return; -} - -t_addr lgp_parse_addr (DEVICE *dptr, char *cptr, char **tptr) -{ -t_addr ad, ea; - -if ((dptr == sim_devices[0]) && - ((sim_switches & SWMASK ('T')) || - ((cpu_unit.flags & UNIT_TTSS_D) && !(sim_switches & SWMASK ('N'))))) { - ad = (t_addr) strtotv (cptr, tptr, 10); - if (((ad / 100) >= NTK_30) || ((ad % 100) >= NSC_30)) { - *tptr = cptr; - return 0; - } - ea = ((ad / 100) * NSC_30) | (ad % 100); - } -else ea = (t_addr) strtotv (cptr, tptr, dptr->aradix); -return ea; -} - -void lgp_vm_init (void) -{ -sim_vm_fprint_addr = &lgp_fprint_addr; -sim_vm_parse_addr = &lgp_parse_addr; -return; -} - -/* Symbolic decode - - Inputs: - *of = output stream - addr = current PC - *val = pointer to data - *uptr = pointer to unit - sw = switches - Outputs: - return = status code -*/ - -t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, - UNIT *uptr, int32 sw) -{ -int32 i, c; -uint32 inst, op, ea; - -inst = val[0]; -if (sw & SWMASK ('A')) { /* alphabetic? */ - if ((uptr == NULL) || !(uptr->flags & UNIT_ATT)) - return SCPE_ARG; - if (uptr->flags & UNIT_FLEX) { /* Flex file? */ - c = flex_to_ascii[inst]; /* get ASCII equiv */ - if (c <= 0) - return SCPE_ARG; - } - else c = inst & 0x7F; /* ASCII file */ - fputc (c, of); - return SCPE_OK; - } - -if (uptr && (uptr != &cpu_unit)) /* must be CPU */ - return SCPE_ARG; -if ((sw & SWMASK ('M')) && /* symbolic decode? */ - ((inst & ~(SIGN|I_OP|I_EA)) == 0)) { - op = I_GETOP (inst); - ea = I_GETEA (inst); - if (inst & SIGN) - fputc ('-', of); - fprintf (of, "%c ", opcode[op]); - lgp_fprint_addr (of, sim_devices[0], ea); - return SCPE_OK; - } - -if ((sw & SWMASK ('L')) || /* LGP hex? */ - ((cpu_unit.flags & UNIT_LGPH_D) && !(sw & SWMASK ('H')))) { - for (i = 0; i < 8; i++) { - c = (inst >> (4 * (7 - i))) & 0xF; - fputc (hex_decode[c], of); - } - return SCPE_OK; - } -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 -*/ - -t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) -{ -int32 i, c; -char *tptr; - -while (isspace (*cptr)) /* absorb spaces */ - cptr++; -if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { - if ((uptr == NULL) || !(uptr->flags & UNIT_ATT)) - return SCPE_ARG; - if (uptr->flags & UNIT_FLEX) { /* Flex file? */ - c = ascii_to_flex[*cptr & 0x7F]; /* get Flex equiv */ - if (c < 0) - return SCPE_ARG; - val[0] = ((c >> 1) | (c << 5)) & 0x3F; /* transpose */ - } - else val[0] = *cptr & 0x7F; /* ASCII file */ - return SCPE_OK; - } - -if (uptr && (uptr != &cpu_unit)) /* must be CPU */ - return SCPE_ARG; -if (!parse_sym_m (cptr, val, sw)) /* symbolic parse? */ - return SCPE_OK; -if ((sw & SWMASK ('L')) || /* LGP hex? */ - ((cpu_unit.flags & UNIT_LGPH_D) && !(sw & SWMASK ('H')))) { - val[0] = 0; - while (isspace (*cptr)) cptr++; /* absorb spaces */ - for (i = 0; i < 8; i++) { - c = *cptr++; /* get char */ - if (c == 0) - return SCPE_OK; - if (islower (c)) - c = toupper (c); - if ((tptr = strchr (hex_decode, c))) - val[0] = (val[0] << 4) | (tptr - hex_decode); - else return SCPE_ARG; - } - if (*cptr == 0) - return SCPE_OK; - } -return SCPE_ARG; -} - -/* Instruction parse */ - -t_stat parse_sym_m (char *cptr, t_value *val, int32 sw) -{ -uint32 ea, sgn; -char *tptr, gbuf[CBUFSIZE]; - -if (*cptr == '-') { - cptr++; - sgn = SIGN; - } -else sgn = 0; -cptr = get_glyph (cptr, gbuf, 0); /* get opcode */ -if (gbuf[1] != 0) - return SCPE_ARG; -if ((tptr = strchr (opcode, gbuf[0]))) - val[0] = ((tptr - opcode) << I_V_OP) | sgn; /* merge opcode */ -else return SCPE_ARG; -cptr = get_glyph (cptr, gbuf, 0); /* get address */ -ea = lgp_parse_addr (sim_devices[0], gbuf, &tptr); -if ((tptr == gbuf) || (*tptr != 0) || (ea > AMASK)) - return SCPE_ARG; -val[0] = val[0] | (ea << I_V_EA); /* merge address */ -if (*cptr != 0) - return SCPE_2MARG; -return SCPE_OK; -} diff --git a/Makefile.mak b/Makefile.mak new file mode 100644 index 00000000..147ae464 --- /dev/null +++ b/Makefile.mak @@ -0,0 +1,78 @@ +# Simple NMAKE command file for MSVC++ +# +# Targets: +# +# hp2100 - make the HP 2100 simulator +# hp3000 - make the HP 3000 simulator +# clean - remove all simulator object and executable files +# +# This file is placed in the SCP subdirectory under the simulator root +# directory. It places the executable in the parent directory (i.e., the +# simulator root) and object files in the Release subdirectory of the root. + + +# This makefile is ONLY for MSVC / NMAKE. The following command will cause an +# error if the file is accidentally invoked with GNU make. + +!MESSAGE + + +SCPD = SCP +OBJDIR = Release + +CC = cl /nologo /Ox /ISCP + +CC_OUTSPEC = /Fo$(OBJDIR)\ /Fe$@ +LDFLAGS = advapi32.lib wsock32.lib winmm.lib + +SIM = $(SCPD)\scp.c $(SCPD)\sim_console.c $(SCPD)\sim_fio.c $(SCPD)\sim_timer.c \ + $(SCPD)\sim_sock.c $(SCPD)\sim_tmxr.c $(SCPD)\sim_tape.c $(SCPD)\sim_shmem.c \ + $(SCPD)\sim_extension.c $(SCPD)\sim_serial.c + +# +# Emulator source files and compile time options +# +HP2100D = $(SCPD)\HP2100 +HP2100 = $(HP2100D)/hp2100_baci.c $(HP2100D)/hp2100_cpu.c $(HP2100D)/hp2100_cpu_fp.c \ + $(HP2100D)/hp2100_cpu_fpp.c $(HP2100D)/hp2100_cpu0.c $(HP2100D)/hp2100_cpu1.c \ + $(HP2100D)/hp2100_cpu2.c $(HP2100D)/hp2100_cpu3.c $(HP2100D)/hp2100_cpu4.c \ + $(HP2100D)/hp2100_cpu5.c $(HP2100D)/hp2100_cpu6.c $(HP2100D)/hp2100_cpu7.c \ + $(HP2100D)/hp2100_di.c $(HP2100D)/hp2100_di_da.c $(HP2100D)/hp2100_disclib.c \ + $(HP2100D)/hp2100_dma.c $(HP2100D)/hp2100_dp.c $(HP2100D)/hp2100_dq.c \ + $(HP2100D)/hp2100_dr.c $(HP2100D)/hp2100_ds.c $(HP2100D)/hp2100_ipl.c \ + $(HP2100D)/hp2100_lps.c $(HP2100D)/hp2100_lpt.c $(HP2100D)/hp2100_mc.c \ + $(HP2100D)/hp2100_mem.c $(HP2100D)/hp2100_mpx.c $(HP2100D)/hp2100_ms.c \ + $(HP2100D)/hp2100_mt.c $(HP2100D)/hp2100_mux.c $(HP2100D)/hp2100_pif.c \ + $(HP2100D)/hp2100_pt.c $(HP2100D)/hp2100_sys.c $(HP2100D)/hp2100_tbg.c \ + $(HP2100D)/hp2100_tty.c +HP2100_OPT = /DHAVE_INT64 /I$(HP2100D) + +HP3000D = $(SCPD)\HP3000 +HP3000 = $(HP3000D)/hp_disclib.c $(HP3000D)/hp_tapelib.c $(HP3000D)/hp3000_atc.c \ + $(HP3000D)/hp3000_clk.c $(HP3000D)/hp3000_cpu.c $(HP3000D)/hp3000_cpu_base.c \ + $(HP3000D)/hp3000_cpu_fp.c $(HP3000D)/hp3000_cpu_cis.c $(HP3000D)/hp3000_ds.c \ + $(HP3000D)/hp3000_iop.c $(HP3000D)/hp3000_lp.c $(HP3000D)/hp3000_mem.c \ + $(HP3000D)/hp3000_mpx.c $(HP3000D)/hp3000_ms.c $(HP3000D)/hp3000_scmb.c \ + $(HP3000D)/hp3000_sel.c $(HP3000D)/hp3000_sys.c +HP3000_OPT = /I$(HP3000D) + + +clean : + if exist $(OBJDIR)\nul rmdir /s /q $(OBJDIR) + if exist hp2100.exe del hp2100.exe + if exist hp3000.exe del hp3000.exe + + +hp3000 : makedir hp3000.exe + +makedir : + if not exist $(OBJDIR)\nul mkdir $(OBJDIR) + +hp3000.exe : $(HP3000) $(SIM) + $(CC) $(HP3000) $(SIM) $(HP3000_OPT) $(CC_OUTSPEC) $(LDFLAGS) + + +hp2100 : makedir hp2100.exe + +hp2100.exe : $(HP2100) $(SIM) + $(CC) $(HP2100) $(SIM) $(HP2100_OPT) $(CC_OUTSPEC) $(LDFLAGS) diff --git a/NOVA/eclipse.txt b/NOVA/eclipse.txt deleted file mode 100644 index de753a4c..00000000 --- a/NOVA/eclipse.txt +++ /dev/null @@ -1,24 +0,0 @@ -Charles Owen's Eclipse Modules - -1. Eclipse CPU simulator - -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 - - the output should be named eclipse rather than nova - -For example, to compile under UNIX, move nova_cpu.c out of the source directory -and then give this command: - - % cc -DECLIPSE eclipse_cpu.c nova_*.c -o eclipse - -2. Alternate terminal emulator - -The module eclipse_tt.c can be used with either an Eclipse or Nova CPU simulator -in place of nova_tt.c. It provides a full emulation of the cursor controls on -the Dasher video terminal but requires that the underlying operating system -interpret VT100 cursor controls. Thus, it works under VMS or UNIX but not under -Windows or OS/2. diff --git a/NOVA/eclipse_cpu.c b/NOVA/eclipse_cpu.c deleted file mode 100644 index c2ec12e1..00000000 --- a/NOVA/eclipse_cpu.c +++ /dev/null @@ -1,6783 +0,0 @@ -/* eclipse_cpu.c: Eclipse CPU simulator - - Modified from the original NOVA simulator by Robert Supnik. - - Copyright (c) 1998-2012, Charles E Owen - Portions Copyright (c) 1993-2015, 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. - - cpu Eclipse central processor - - 30-Mar-15 RMS Fixed typo in DIVS - 25-Mar-12 RMS Fixed declarations (Mark Pizzolato) - 07-Jun-06 RMS Fixed bug in DIVS (Mark Hittinger) - 22-Sep-05 RMS Fixed declarations (Sterling Garwood) - 25-Aug-05 RMS Fixed DIVS overflow cases - 29-Nov-03 CEO Corrected POPJ and Bit operations bugs - 26-Nov-03 CEO Added FPU and PIT devices - 20-Feb-03 CEO Corrected several MMPU and CIS bugs - 28-Jan-02 RMS Cleaned up compiler warnings - 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 - - The register state for the Eclipse CPU is basically the same as - the NOVA's: - - AC[0:3]<0:15> general registers - C carry flag - PC<0:14> program counter - - Eclipses with Folating Point Units added these registers: - - FPAC[0:3]<0:63> Floating Point Accumulators - FPSR Floating Point Status Register - - In addition, certain low-memory locations are reserved for special - purposes: - - 0: I/O Return Address (from an interrupt) - 1: I/O (Interrupt) handler address - 2: System Call handler address (used by SYC instruction) - 3: Protection Fault handler address - 4: VECTOR stack pointer (VCT Instruction) - 5: Current Interrupt Priority mask - 6: VECTOR stack limit (VCT instruction) - 7: VECTOR stack fault address (VCT again) - 10: Block Pointer (later models only) - 11: Emulation Trap Handler address (microeclipse only) - 20-27: Auto-increment locations (not on microeclipse) - 30-37: Auto-decrement locations (not on microeclipse) - 40: Stack pointer - 41: Frame Pointer - 42: Stack Limit - 43: Stack fault address - 44: XOP Origin address - 45: Floating point fault address - 46: Commercial fault address (not on microeclipse) - 47: Reserved, do not use. - - Note: While all eclipses share most of the "standard" features, - some models added a few quirks and wrinkles, and other models - dropped some features or modified others. Most DG software - is written for a "standard" Eclipse, and avoids these problem - areas. A general overview: - - [subject to major changes as info becomes available!] - - Early (e.g. S/100, S/200, C/300) [Front Panel machines] - - The first Eclipses had the basic MAP, but certain parts - were kluged, and these were fixed in later MAP designs. - The original mapping hardware was termed MAP for Memory - Allocate and Protection. The later design was termed - MMPU for Memory Mapping and Protection Unit. While - similar in design, the two units are not compatible. - Also, the C version (C for Commercial) of these early - CPUs had a feature called "Commercial Instruction Set" - which contained character manipulation, translation - between commercial-format numeric data and FPU formats, - and an elaborate EDIT instruction. Later models kept - only the character manipulation part of this and called - the feature the "Character Instruction Set", leading to - confusion because the initials of both are CIS. ARDOS - is the only DG operating system to support the older - MAP. ZRDOS uses the MMPU, and AOS supports only MMPU. - - Middle (e.g. S/130, C/150, S/230, C/330) [Front Panel] - - These are close to a "Standard". They have the newer, - fixed MMPU. Support for the PIT (Programmed Interval - Timer. The Commercial (not character) instruction set - and FPU are optional. (CIS standard on C models) - - Late (C/350, M/600: [Panel]; S/140, S/280 [Virtual Console]) - - All features of the Middle period are included, plus: - These late Eclipses added a few MMPU wrinkles all their - own, included support for user maps C and D. Character - instruction set is standard, FPU optional. Also, support - for the BMC device. - - MicroEclipse-based (S/20, S/120, Desktops) [Virtual cons.] - - All features of the Late period, in general, plus: - Microeclipses dropped support for the auto increment - and decrement locations at 20-37. They also added - support for invalid instruction traps thru location 11. - The Desktops have an interface to the "Attached Processor", - an 8086, at device code 6. Also, some new CPU device - features to read states info. The Character Instruction - set and FPU are standard on all models. - - The Eclipse instruction set is an elaboration of the NOVA's. The basic - NOVA set is implemented in it's entireity, plus many new Eclipse - instructions are added. Since in theory every possible 16-bit - combination is a NOVA instruction, the Eclipse commands are carved - out of the NOVA set by using the Operate format with the no-load bit - set to 1 and the skip bits set to 000. Since this combination is - in effect a no-op on the NOVA, it was rarely or never used. The - other bits are used to form Eclipse instructions, which have no - other common format. To see the instructions, refer to the Eclipse - section of the instruction decode logic in sim_instr() below. All - Eclipse instructions are checked first, so in case of conflict in - bit patterns, the Eclipse one is executed over the corresponding - NOVA pattern. A bizarre exception is LEF mode...which implements - an instruction called Load Effective Address by taking over the - Nova I/O format when the LEF mode bit is set and the processor is - executing in mapped mode. - - The following discussion talks about NOVA instructions which are - Eclipse instructions also. - - The NOVA has three instruction formats: memory reference, I/O transfer, - and operate. The memory reference format is: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 0| op | AC |in| mode| displacement | memory reference - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - <0:4> mnemonic action - - 00000 JMP PC = MA - 00001 JMS AC3 = PC, PC = MA - 00010 ISZ M[MA] = M[MA] + 1, skip if M[MA] == 0 - 00011 DSZ M[MA] = M[MA] - 1, skip if M[MA] == 0 - 001'n LDA ACn = M[MA] - 010'n STA M[MA] = ACn - - <5:7> mode action - - 000 page zero direct MA = zext (IR<8:15>) - 001 PC relative direct MA = PC + sext (IR<8:15>) - 010 AC2 relative direct MA = AC2 + sext (IR<8:15>) - 011 AC3 relative direct MA = AC3 + sext (IR<8:15>) - 100 page zero indirect MA = M[zext (IR<8:15>)] - 101 PC relative dinirect MA = M[PC + sext (IR<8:15>)] - 110 AC2 relative indirect MA = M[AC2 + sext (IR<8:15>)] - 111 AC3 relative indirect MA = M[AC3 + sext (IR<8:15>)] - - Memory reference instructions can access an address space of 32K words. - An instruction can directly reference the first 256 words of memory - (called page zero), as well as 256 words relative to the PC, AC2, or - AC3; it can indirectly access all 32K words. If an indirect address - is in locations 00020-00027, the indirect address is incremented and - rewritten to memory before use; if in 00030-00037, decremented and - rewritten. - - The I/O transfer format is: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 0 1 1| AC | opcode |pulse| device | I/O transfer - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - The IOT instruction sends the opcode, pulse, and specified AC to the - specified I/O device. The device may accept data, provide data, - initiate or cancel operations, or skip on status. - - The operate format is: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 1|srcAC|dstAC| opcode |shift|carry|nl| skip | operate - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - \______/ \___/ \___/ | | | | - | | | | | | +--- reverse skip sense - | | | | | +--- skip if C == 0 - | | | | +--- skip if result == 0 - | | | +--- don't load result - | | +--- carry in (load as is, - | | set to Zero, - | | set to One, - | | load Complement) - | +--- shift (none, - | left one, - | right one, - | byte swap) - +--- operation (complement, - negate, - move, - increment, - add complement, - subtract, - add, - and) - - The operate instruction can be microprogrammed to perform operations - on the source and destination AC's and the Carry flag. - - This routine is the instruction decode routine for the NOVA. - 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 - infinite indirection loop - unknown I/O device and STOP_DEV flag set - I/O error in I/O simulator - - 2. Interrupts. Interrupts are maintained by four parallel variables: - - dev_done device done flags - dev_disable device interrupt disable flags - dev_busy device busy flags - int_req interrupt requests - - In addition, int_req contains the interrupt enable and ION pending - flags. If ION and ION pending are set, and at least one interrupt - request is pending, then an interrupt occurs. Note that the 16b PIO - mask must be mapped to the simulator's device bit mapping. - - 3. Non-existent memory. On the NOVA, 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: - - eclipse_defs.h add interrupt request definition - eclipse_cpu.c add IOT mask, PI mask, and routine to dev_table - eclipse_sys.c add pointer to data structures to sim_devices -*/ - -/*--------------------------------------------------------------------------- -** ECLIPSE Debugging Facilities -** -** These options are designed to find hard-to-locate flaky bugs by -** providing special error checking and logging. -** -** All are controlled by depositing a value into the DEBUG register. -** A value of zero means no special debugging facilities are turned on. -** This is the default. Debugging invokes a performance hit! Use only -** when necessary. -** -** Debugging means logging information to a file, or to a buffer in -** memory from whence it can be dumped to a file. -** -** 1XXXXX = Log all instructions executed to file "trace.log". -** **CAUTION**: This means the CPU will run SLOWLY and -** the resulting trace.log file will be HUGE. We're talking -** about a megabyte for each 5 seconds or less of wall clock -** time, depending on the speed of your CPU. Note: In this -** mode, interrupts are logged when they are received also. -** -** Note: when detailed logging is off, the last 4096 or so -** instructions executed are saved in a memory buffer, and -** when the sim stops, the "show" command can write this -** history information to the file "history.log". This only -** works if the DEBUG register is non-zero however, because -** of the performance hit even this recording makes. To -** dump history, enter the command "show cpu history", with -** the file "history" spelled correctly and lower case. -** -** XXXXDD = Log all I/O instructions to or from device number -** DD. Log is written to "trace.log", regardless of the -** setting of the instruction trace flag (1XXXXX). If both -** are on, the device traces will be interpersed with the -** instruction traces -- very useful sometimes. -** -** XXX1DD = Device Break. Does a breakpoint in any I/O to -** device DD. Useful, say when a diagnostic gives an -** error message - a device break on 11 (TTO) will stop -** as soon as the error message appears, making the -** trace log much shorter to track back on. -** -** X4XXXX = When this bit is on, the sim will stop if it sees -** an invalid instruction. When DEBUG is zero, any such -** instruction is no-oped with no warning. When DEBUG is -** non-zero, but this bit is 0, a warning will be displayed -** but execution will continue. -** -** X2XXXX = LEF break. When A LEF instruction is executed in -** mapped user space, the sim does a breakpoint right after -** executing the instruction. -** -** Whenever the DEBUG register is non-zero, special error checking -** is enabled in the sim. This will stop the sim automatically -** when a likely error occurs, such as: -** -** 1. Any execution that reaches, or will reach, location 00000. -** 2. Any I/O to device 00 -** 3. An interrupt from device 00. -** 4. An invalid instruction (stop is optional) -** -** DCHAR Register: Whenever this is non-zero, a test is made on every -** character output to the TTO device (master console). If the character -** output to that device matches this register, the CPU will break. -** -** Of course, the standard BREAK register is available for breakpoints -** as in all the sims based on this standard. ---------------------------------------------------------------------------*/ - -#include "nova_defs.h" - -#define UNIT_V_MICRO (UNIT_V_UF) /* Microeclipse? */ -#define UNIT_V_17B (UNIT_V_UF) /* 17 bit MAP */ -#define UNIT_V_UP (UNIT_V_UF) /* FPU Enabled */ -#define UNIT_V_MSIZE (UNIT_V_UF+1) /* dummy mask */ -#define UNIT_MICRO (1 << UNIT_V_MICRO) -#define UNIT_17B (1 << UNIT_V_17B) -#define UNIT_UP (1 << UNIT_V_UP) -#define UNIT_MSIZE (1 << UNIT_V_MSIZE) - -uint16 M[MAXMEMSIZE] = { 0 }; /* memory */ -int32 AC[4] = { 0 }; /* accumulators */ -int32 C = 0; /* carry flag */ -int32 saved_PC = 0; /* program counter */ -int32 SR = 0; /* switch register */ -int32 dev_done = 0; /* device done flags */ -int32 dev_busy = 0; /* device busy flags */ -int32 dev_disable = 0; /* int disable flags */ -int32 iot_enb = -1; /* IOT enables */ -int32 int_req = 0; /* interrupt requests */ -int32 pimask = 0; /* priority int mask */ -int32 pwr_low = 0; /* power fail flag */ -int32 ind_max = 15; /* iadr nest limit */ -int32 stop_dev = 0; /* stop on ill dev */ -int32 old_PC = 0; /* previous PC */ -int32 model = 140; /* Model of Eclipse */ -int32 speed = 0; /* Delay for each instruction */ - -int32 XCT_mode = 0; /* 1 if XCT mode */ -int32 XCT_inst = 0; /* XCT instruction */ -int32 PPC = -1; -int32 AMASK = 077777; - -struct ndev dev_table[64]; /* dispatch table */ - -/* Instruction history buffer */ - -#define HISTMAX 4096 - -int32 hnext = 0; /* # of current entry */ -int32 hwrap = 0; /* 1 if wrapped */ -int32 hmax = HISTMAX; /* Maximum entries b4 wrap */ -uint16 hpc[HISTMAX]; -uint16 hinst[HISTMAX]; -uint16 hinst2[HISTMAX]; -uint16 hac0[HISTMAX]; -uint16 hac1[HISTMAX]; -uint16 hac2[HISTMAX]; -uint16 hac3[HISTMAX]; -unsigned short hflags[HISTMAX]; - -/* Flags: 0x01 - carry bit - 0x02 - int enabled - 0x04 - user map a - 0x08 - user map b - 0x10 - user map c - 0x20 - user map d - 0x40 - LEF mode was on - 0x80 - this is an int, not an inst. - hpc is return addr - hinst is int_req - hac0 is device - hac1 is int addr -*/ - - - -/* the Eclipse MAP unit: This unit is standard in all Eclipse processors - except for the "original" Eclipses, the S/100, S/200, and C/300. These - use a different and more elaborate MMPU that is not compatible with - the one simulated here. All subsequent Eclipses, from the S/130 on up - to the last models S/280 and C/380 use the map simulated here, including - the MicroEclipses. There are model-dependent quirks. That's why we - have to MODEL register. - - The programming of the MMPU can be found in the LMP instruction, below, - and in the instructions directed to DEV_MAP. - - There are two user maps, called A and B, and four data channel maps, - A thru D. They can be enabled/disabled separately. Some models have - two extra user maps, C and D. These are supported where apporpriate. - -*/ - -#define PAGEMASK 01777 /* Largest physical page possible */ -#define MAPMASK 0101777 /* Valid page bits in map */ -#define INVALID 0101777 /* Mask indicating an invalid page */ -int32 MapStat = 0; /* Map status register */ -int32 Inhibit = 0; /* !0=inhibit interrupts : */ - /* 1 = single cycle inhibit */ - /* 2 = inhibit until indirection */ - /* 3 = inhibit next instruction only */ -int32 Enable = 0; /* User map to activate 1=A 2=B */ -int32 Usermap = 0; /* Active Map? 0=supvr mode, 1=user A, 2 = user B */ -int32 Map[8][32]; /* The actual MAPs 0=dch A, 1=A, 2=B, 3-5=dchB-D 6-7 User C-D */ -int32 Map31 = 037; /* Map for block 31 in supervisor mode */ -int32 SingleCycle = 0; /* Map one LDA/STA */ -int32 Check = 0; /* Page Check Register */ -int32 Fault = 0; /* Fault register */ -int32 MapInit = 0; /* 1 when map initialized */ -int32 MapIntMode = 0; /* Save of map user mode when int occurs */ - -/* The Eclipse Floating Point Unit: This unit is optional on all Eclipse - models. -*/ - -int32 FPSR = 0; /* 32-bit FPU Status Register */ -t_int64 FPAC[4] = { 0,0,0,0 }; /* 4 64-bit Accumulators */ -int32 FPFault = 0; /* Save Fault State */ - -/* Definitions for internal floating point arithmetic */ - -typedef struct _SHORT_FLOAT { - int32 short_fract; /* Fraction */ - short expo; /* Exponent + 64 */ - uint8 sign; /* Sign */ -} SHORT_FLOAT; - -typedef struct _LONG_FLOAT { - t_int64 long_fract; /* Fraction */ - short expo; /* Exponent + 64 */ - uint8 sign; /* Sign */ -} LONG_FLOAT; - -LONG_FLOAT dfl,dfl2; /* Double Precision Work Fields */ -SHORT_FLOAT sfl,sfl2; /* Single Precision Work Fields */ -t_int64 tempfp, holdfp; /* Working area for FPAC */ -int shift,m3; -t_int64 lsfract; - -void get_sf(SHORT_FLOAT *fl, t_int64 *fpr); -void store_sf(SHORT_FLOAT *fl, t_int64 *fpr); -void get_lf(LONG_FLOAT *fl, t_int64 *fpr); -void store_lf(LONG_FLOAT *fl, t_int64 *fpr); -int normal_sf (SHORT_FLOAT *fl); -int normal_lf (LONG_FLOAT *fl); -int overflow_sf(SHORT_FLOAT *fl); -int overflow_lf(LONG_FLOAT *fl); -int underflow_sf(SHORT_FLOAT *fl); -int underflow_lf(LONG_FLOAT *fl); -int significance_sf(SHORT_FLOAT *fl); -int significance_lf(LONG_FLOAT *fl); -int add_sf(SHORT_FLOAT *fl, SHORT_FLOAT *add_f1, int normal); -int add_lf(LONG_FLOAT *fl, LONG_FLOAT *add_fl, int normal); -int mul_sf(SHORT_FLOAT *fl, SHORT_FLOAT *mul_fl); -int mul_lf(LONG_FLOAT *fl, LONG_FLOAT *mul_fl); -int div_sf(SHORT_FLOAT *fl, SHORT_FLOAT *div_fl); -int div_lf(LONG_FLOAT *fl, LONG_FLOAT *div_fl); - -/* Special Debugging Info */ - -int32 Debug_Flags = 0; /* Debug register - selects debug features */ -int32 Debug_Char = 0; /* Debug Character Register */ - -int32 Tron = 0; /* For trace files */ -FILE *Trace; - - -t_stat reason; - -t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); -t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); -t_stat cpu_reset (DEVICE *dptr); -t_stat cpu_boot (int32 unitno, DEVICE *dptr); -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat Debug_Dump (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat Dump_History (FILE *st, UNIT *uptr, int32 val, 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); -t_stat map_svc (UNIT *uptr); -t_stat fpu_svc (UNIT *uptr); -int32 GetMap(int32 addr); -int32 PutMap(int32 addr, int32 data); -int32 Debug_Entry(int32 PC, int32 inst, int32 inst2, int32 AC0, int32 AC1, int32 AC2, int32 AC3, int32 flags); -t_stat build_devtab (void); - -/* 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[] = { - { ORDATA (PC, saved_PC, 15) }, - { ORDATA (AC0, AC[0], 16) }, - { ORDATA (AC1, AC[1], 16) }, - { ORDATA (AC2, AC[2], 16) }, - { ORDATA (AC3, AC[3], 16) }, - { FLDATA (C, C, 16) }, - { ORDATA (SR, SR, 16) }, - { ORDATA (PI, pimask, 16) }, - { FLDATA (ION, int_req, INT_V_ION) }, - { FLDATA (ION_DELAY, int_req, INT_V_NO_ION_PENDING) }, - { FLDATA (PWR, pwr_low, 0) }, - { ORDATA (INT, int_req, INT_V_ION+1), REG_RO }, - { ORDATA (BUSY, dev_busy, INT_V_ION+1), REG_RO }, - { ORDATA (DONE, dev_done, INT_V_ION+1), REG_RO }, - { ORDATA (DISABLE, dev_disable, INT_V_ION+1), REG_RO }, - { FLDATA (STOP_DEV, stop_dev, 0) }, - { DRDATA (INDMAX, ind_max, 16), REG_NZ + PV_LEFT }, - { ORDATA (DEBUG, Debug_Flags, 16) }, - { ORDATA (DCHAR, Debug_Char, 16) }, - { DRDATA (MODEL, model, 16) }, - { DRDATA (SPEED, speed, 16) }, - { ORDATA (WRU, sim_int_char, 8) }, - { NULL } -}; - -MTAB cpu_mod[] = { - { UNIT_MICRO, UNIT_MICRO, "MICRO", "MICRO", NULL }, - { UNIT_MICRO, 0, "STD", "STD", NULL }, - { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size }, - { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size }, - { UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size }, - { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size }, - { UNIT_MSIZE, 20480, NULL, "20K", &cpu_set_size }, - { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size }, - { UNIT_MSIZE, 28672, NULL, "28K", &cpu_set_size }, - { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size }, - { UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size }, - { UNIT_MSIZE, 131072, NULL, "128K", &cpu_set_size }, - { UNIT_MSIZE, 262144, NULL, "256K", &cpu_set_size }, - { UNIT_MSIZE, 524288, NULL, "512K", &cpu_set_size }, - { UNIT_MSIZE, 1048576, NULL, "1024K", &cpu_set_size }, - { UNIT_MSIZE, 0, NULL, "DUMP", &Debug_Dump }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "HISTORY", NULL, - NULL, &Dump_History }, - { 0 } -}; - -DEVICE cpu_dev = { - "CPU", &cpu_unit, cpu_reg, cpu_mod, - 1, 8, 17, 1, 8, 16, - &cpu_ex, &cpu_dep, &cpu_reset, - &cpu_boot, NULL, NULL -}; - -/* MAP data structures - - map_dev MAP device descriptor - map_unit MAP unit descriptor - map_reg MAP register list - map_mod MAP modifiers list -*/ - -UNIT map_unit = { UDATA (&map_svc, UNIT_17B, MAXMEMSIZE) }; - -REG map_reg[] = { - { ORDATA (STATUS, MapStat, 16) }, - { ORDATA (ENABLE, Enable, 16) }, - { ORDATA (IINHIB, Inhibit, 16) }, - { ORDATA (ACTIVE, Usermap, 16) }, - { ORDATA (MAP31, Map31, 16) }, - { ORDATA (CYCLE, SingleCycle, 16) }, - { ORDATA (CHECK, Check, 16) }, - { ORDATA (FAULT, Fault, 16) }, - { NULL } -}; - -MTAB map_mod[] = { - { UNIT_17B, UNIT_17B, "17bit", "17B", NULL }, - { UNIT_17B, 0, "19bit", "19B", NULL }, - { 0 } -}; - -DEVICE map_dev = { - "MAP", &map_unit, map_reg, map_mod, - 1, 8, 17, 1, 8, 16, - &map_ex, &map_dep, NULL, - NULL, NULL, NULL -}; - -/* FPU data structures - - fpu_dev MAP device descriptor - fpu_unit MAP unit descriptor - fpu_reg MAP register list - fpu_mod MAP modifiers list -*/ - -UNIT fpu_unit = { UDATA (&fpu_svc, UNIT_UP, MAXMEMSIZE) }; - -REG fpu_reg[] = { - { ORDATA (STATUS, FPSR, 32) }, - { ORDATA (FPAC0, FPAC[0], 64) }, - { ORDATA (FPAC1, FPAC[1], 64) }, - { ORDATA (FPAC2, FPAC[2], 64) }, - { ORDATA (FPAC3, FPAC[3], 64) }, - { ORDATA (FAULT, FPFault, 32) }, - { NULL } -}; - -MTAB fpu_mod[] = { - { UNIT_UP, UNIT_UP, "Enabled (UP)", "UP", NULL }, - { UNIT_UP, 0, "Disabled (DOWN)", "DOWN", NULL }, - { 0 } -}; - -DEVICE fpu_dev = { - "FPU", &fpu_unit, fpu_reg, fpu_mod, - 1, 16, 17, 1, 16, 16, - NULL, NULL, NULL, - NULL, NULL, NULL -}; - - -/* ---- Programmable Interval Timer Device ----------- */ - -int32 pit_time = 100; -int32 pit_tps = 10000; /* ticks per sec */ -int32 pit_adj = 20; /* tmxr adjust */ -int32 pit_poll = 16000; /* tmxr poll */ -int32 pit_initial = 0; /* initial counter reg */ -int32 pit_counter = 0; /* Counter */ -int32 pit_flag = 0; /* Initial setting flag */ - -int32 pit (int32 pulse, int32 code, int32 AC); -t_stat pit_svc (UNIT *uptr); -t_stat pit_reset (DEVICE *dptr); - -/* PIT data structures - - pit_dev device descriptor - pit_unit unit descriptor - pit_reg register list -*/ - -DIB pit_dib = { DEV_PIT, INT_PIT, PI_PIT, &pit }; - -UNIT pit_unit = { UDATA (&pit_svc, 0, 0) }; - -REG pit_reg[] = { - { ORDATA (INIT, pit_initial, 16) }, - { ORDATA (COUNT, pit_counter, 16) }, - { FLDATA (BUSY, dev_busy, INT_V_PIT) }, - { FLDATA (DONE, dev_done, INT_V_PIT) }, - { FLDATA (DISABLE, dev_disable, INT_V_PIT) }, - { FLDATA (INT, int_req, INT_V_PIT) }, - { DRDATA (TIME0, pit_time, 24), REG_NZ + PV_LEFT }, - { NULL } -}; - -DEVICE pit_dev = { - "PIT", &pit_unit, pit_reg, NULL, - 1, 0, 0, 0, 0, 0, - NULL, NULL, &pit_reset, - NULL, NULL, NULL, - &pit_dib, 0 -}; - -t_stat sim_instr (void) -{ -register int32 PC, IR, i, t, MA, j, k, tac; -register uint32 mddata, uAC0, uAC1, uAC2, uAC3; -int16 sAC0, sAC1, sAC2; -int32 sddata, mi1, mi2, fpnum32; -t_int64 fpnum, expon; -t_value simeval[20]; -void mask_out (int32 mask); -/* char debstr[128]; */ -/* char debadd[64]; */ -char debmap[4], debion[4]; -int debcar, iodev, iodata, debflags; -int32 DisMap, debpc; -/* int32 sp, sl; */ -int cmdptr, cmsptr, cmopt, cmptr; -int16 cmslen, cmdlen; -int tabaddr, tabptr; -int32 effective(int32 PC, int32 index, int32 disp); -int32 indirect(int32 d); -int32 LEFmode(int32 PC, int32 index, int32 disp, int32 indirect); -int32 LoadMap(int32 w); -int32 Bytepointer(int32 PC, int32 index); -int32 unimp(int32 PC); -int32 pushrtn(int32 pc); - -/* Restore register state */ - -if (build_devtab () != SCPE_OK) return SCPE_IERR; /* build dispatch */ -PC = saved_PC & AMASK; /* load local PC */ -C = C & 0200000; -mask_out (pimask); /* reset int system */ -reason = 0; -if (MapInit == 0) { - MapInit = 1; - for (mi1 = 0; mi1 < 6; mi1++) { /* Initialize MAPs */ - for (mi2 = 0; mi2 < 32; mi2++) { - Map[mi1][mi2] = mi2; - } - } -} - -/* 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 (speed > 0) for (i = 0; i < speed; i++) { j = 0; } - -if (Fault) { /* Check MAP fault */ - Usermap = 0; /* YES: shutdown map */ - MapStat &= ~01; /* Disable MMPU */ - if (Fault & 0100000/*!!!*/) /* If it was validity, or WP */ - MapStat &= ~0170; /* Reset other checkbits */ - MapStat |= Fault & 077777; /* Put in fault code */ - Fault = 0; /* Reset fault code */ - t = (GetMap(040) + 1) & AMASK; /* Push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, (PC & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - int_req = int_req & ~INT_ION; /* Disable interrupts */ - PC = indirect(M[003]); /* JMP to loc 3 */ - continue; -} - -if (FPSR & 0xF8000000) { /* FPU Fault? */ - if (!(FPSR & 0x78000000)) { /* If error bit on ... */ - FPSR &= 0x00FFFFFF; /* ...but no error, clear it */ - } else { /* ELSE a real error: */ - FPSR |= 0x80000000; /* Turn error bit on */ - if (FPSR & 0x04000000) { /* Trap enabled ? */ - FPFault = FPSR; /* Save fault */ - FPSR &= 0xFBFFFFFF; /* Clear Trap Enable */ - } - } -} - -if (int_req > INT_PENDING && !Inhibit) { /* interrupt? */ - int_req = int_req & ~INT_ION; - MapIntMode = MapStat; /* Save Status as it was */ - Usermap = 0; /* Inhibit MAP */ - MapStat &= ~1; /* Disable user map */ - if (XCT_mode) { - M[0] = PC - 1; /* If XCT mode rtn to XCT */ - XCT_mode = 0; /* turn off mode */ - } else { - M[0] = PC; /* Save Return Address */ - } - old_PC = PC; - MA = M[1]; - for (i = 0; i < ind_max * 2; i++) { /* count indirects */ - if ((MA & 0100000) == 0) break; - if ((MA & 077770) == 020) - MA = (M[MA & AMASK] = (M[MA & AMASK] + 1) & 0177777); - else if ((MA & 077770) == 030) - MA = (M[MA & AMASK] = (M[MA & AMASK] - 1) & 0177777); - else MA = M[MA & AMASK]; - } - if (i >= (ind_max-1)) { - if ((MapStat & 010) && Usermap) { - Fault = 04000; /* Map fault if IND prot */ - continue; - } else { - reason = STOP_IND_INT; - break; - } - } - if (Debug_Flags) { - iodev = 0; - iodata = int_req & (-int_req); - for (i = DEV_LOW; i <= DEV_HIGH; i++) { - if (iodata & dev_table[i].mask) { - iodev = i; - break; - } - } - if (iodev == 0) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (Debug_Flags & 0100000) { - fprintf(Trace, "--------- Interrupt %o (%o) to %6o ---------\n", int_req, iodev, MA); - } else { - Debug_Entry(PC, int_req, 0, iodev, MA, 0, 0, 0x80); - } - } - PC = MA; -} /* end interrupt */ - -if (Inhibit != 0) { /* Handle 1-instruction inhibit sequence */ - if (Inhibit == 3) /* Used by SYC instruction */ - Inhibit = 4; - if (Inhibit == 4) - Inhibit = 0; -} - -if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; -} - -if ((PC < 1 || PC > 077777) && Debug_Flags) { - if (PPC != -1) { /* Don't break on 1st instruction */ - printf("\n<>\n\r", PC, PPC); - reason = STOP_IBKPT; - break; - } -} - -PPC = PC; - -if (Debug_Flags) { - if (!Tron) { - Tron = 1; - Trace = fopen("trace.log", "w"); - } - strcpy(debmap, " "); - strcpy(debion, " "); - debcar = 0; - if (C) debcar = 1; - if (Usermap == 1) strcpy(debmap, "A"); - if (Usermap == 2) strcpy(debmap, "B"); - if (Usermap == 5) strcpy(debmap, "C"); - if (Usermap == 6) strcpy(debmap, "D"); - if (int_req & INT_ION) strcpy(debion, "I"); - if (XCT_mode == 0) { - debpc = PC; - simeval[0] = GetMap(PC); - simeval[1] = GetMap(PC+1); - } else { - debpc = 0177777; - simeval[0] = XCT_inst; - simeval[1] = 0; - } - if (Debug_Flags & 0100000) { - fprintf(Trace, "%s%s%06o acs: %06o %06o %06o %06o %01o ", - debion, debmap, debpc, AC[0], AC[1], AC[2], AC[3], debcar); - fprint_sym (Trace, debpc, simeval, NULL, SWMASK('M')); - fprintf(Trace, "\n"); - } else { - debflags = 0; - if (C) debflags |= 0x01; - if (int_req & INT_ION) debflags |= 0x02; - if (Usermap == 1) debflags |= 0x04; - if (Usermap == 2) debflags |= 0x08; - if (Usermap == 3) debflags |= 0x10; - if (Usermap == 4) debflags |= 0x20; - Debug_Entry(debpc, (int32)simeval[0], (int32)simeval[1], AC[0], AC[1], AC[2], AC[3], debflags); - } -} - -if (XCT_mode == 0) { /* XCT mode? */ - IR = GetMap(PC); /* No: fetch instr */ - if (Fault) continue; /* Give up if fault */ - PC = (PC + 1) & AMASK; /* bump PC */ -} else { - IR = XCT_inst; /* Yes: Get inst to XCT */ - XCT_mode = 0; /* Go back to normal mode */ -} -int_req = int_req | INT_NO_ION_PENDING; /* clear ION delay */ -sim_interval = sim_interval - 1; -t = IR >> 11; /* prepare to decode */ - -/* ---------------- BEGIN Eclipse modification --------------------- */ - -/* Eclipse instruction set. These instructions are checked for - before any of the NOVA ones. Eclipse instructions do not - correspond to any patterns, other than bit 0 being 1 and - the last 4 bits are 1000. Words which are not Eclipse - instructions will be interpreted as Nova instructions. */ - -/* Important Note: The order of the if statements is important. - Frequently executed instructions should come first, to enhance - the speed of the simulation. -*/ - -if ((IR & 0100017) == 0100010) { /* This pattern for all */ - /* Eclipse instructions */ - -/****************************************************************/ -/* This is the standard Eclipse instruction set */ -/****************************************************************/ - - /* Byte operations */ - - if ((IR & 0103777) == 0102710) { /* LDB: Load Byte */ - i = (IR >> 13) & 03; - MA = (AC[i] >> 1) & AMASK; - j = (IR >> 11) & 03; - if (AC[i] & 01) { - AC[j] = GetMap(MA) & 0377; - } else { - AC[j] = (GetMap(MA) >> 8) & 0377; - } - continue; - } - if ((IR & 0103777) == 0103010) { /* STB: Store Byte */ - i = (IR >> 13) & 03; - MA = (AC[i] >> 1); - j = (IR >> 11) & 03; - t = GetMap(MA); - if (AC[i] & 01) { - t &= 0177400; - t |= (AC[j] & 0377); - PutMap(MA, t); - } else { - t &= 0377; - t |= (AC[j] & 0377) << 8; - PutMap(MA, t); - } - continue; - } - - /* Fixed-point arithmetic - loads & saves */ - - if ((IR & 0162377) == 0122070) { /* ELDA: Extended LDA */ - i = (IR >> 11) & 3; - t = GetMap(PC); - if (SingleCycle) Usermap = SingleCycle; - AC[i] = GetMap(effective(PC, (IR >> 8) & 3, t)); - if (SingleCycle) { - Usermap = SingleCycle = 0; - if (Inhibit == 1) Inhibit = 3; - MapStat |= 02000; - MapStat &= 0177776; - } - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0162377) == 0142070) { /* ESTA: Extended STA */ - i = (IR >> 11) & 3; - t = GetMap(PC); - if (SingleCycle) Usermap = SingleCycle; - PutMap((effective(PC, (IR >> 8) & 3, t)), AC[i]); - if (SingleCycle) { - Usermap = SingleCycle = 0; - if (Inhibit == 1) Inhibit = 3; - MapStat |= 02000; - MapStat &= 0177776; - } - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0103777) == 0100010) { /* ADI: Add Immediate */ - t = (IR >> 11) & 3; - AC[t] = (AC[t] + ((IR >> 13) & 3) + 1) & 0xffff; - continue; - } - if ((IR & 0103777) == 0100110) { /* SBI: Subtract Immediate */ - t = (IR >> 11) & 3; - AC[t] = (AC[t] - (((IR >> 13) & 3) + 1)) & 0xffff; - continue; - } - if ((IR & 0163777) == 0163770) { /* ADDI: Extended Add Immed. */ - t = (IR >> 11) & 3; - i = GetMap(PC); - PC = (PC + 1) & AMASK; - AC[t] = (AC[t] + i) & 0xffff; - continue; - } - if ((IR & 0103777) == 0100710) { /* XCH: Exchange Accumulators */ - t = AC[(IR >> 11) & 3]; - AC[(IR >> 11) & 3] = AC[(IR >> 13) & 3]; - AC[(IR >> 13) & 3] = t; - continue; - } - if ((IR & 0162377) == 0162070) { /* ELEF: Load Effective Addr */ - t = GetMap(PC); - AC[(IR >> 11) & 3] = effective(PC, (IR >> 8) & 3, t); - PC = (PC + 1) & AMASK; - continue; - } - - /* Logical operations */ - - if ((IR & 0163777) == 0143770) { /* ANDI: And Immediate */ - AC[(IR >> 11) & 3] &= GetMap(PC); - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0163777) == 0103770) { /* IORI: Inclusive Or Immed */ - AC[(IR >> 11) & 3] |= GetMap(PC); - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0163777) == 0123770) { /* XORI: Exclusive Or Immed */ - AC[(IR >> 11) & 3] ^= GetMap(PC); - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0103777) == 0100410) { /* IOR: Inclusive Or */ - AC[(IR >> 11) & 3] |= AC[(IR >> 13) & 3]; - continue; - } - if ((IR & 0103777) == 0100510) { /* XOR: Exclusive Or */ - AC[(IR >> 11) & 3] ^= AC[(IR >> 13) & 3]; - continue; - } - if ((IR & 0103777) == 0100610) { /* ANC: And with complemented src */ - AC[(IR >> 11) & 3] &= ~(AC[(IR >> 13) & 3]); - continue; - } - - /* Shift operations */ - - if ((IR & 0103777) == 0101210) { /* LSH: Logical Shift */ - register int16 sh; - sh = AC[(IR >> 13) & 3] & 0377; - i = (IR >> 11) & 3; - if (sh & 0200) { - sh = ~sh + 1; - AC[i] = AC[i] >> sh; - } else { - AC[i] = AC[i] << sh; - } - if (sh > 15) AC[i] = 0; - AC[i] &= 0xffff; - continue; - } - if ((IR & 0103777) == 0101310) { /* DLSH: Double logical shift */ - register int16 sh; - sh = AC[(IR >> 13) & 3] & 0377; - i = (IR >> 11) & 3; - uAC0 = AC[i] << 16; - j = i + 1; - if (j == 4) j = 0; - uAC0 |= AC[j]; - if (sh & 0200) { - sh = (~sh + 1) & 0377; - if (sh < 32) - uAC0 = uAC0 >> sh; - } else { - if (sh < 32) - uAC0 = uAC0 << sh; - } - if (sh > 31) uAC0 = 0; - AC[i] = (uAC0 >> 16) & 0xffff; - AC[j] = uAC0 & 0xffff; - continue; - } - if ((IR & 0103777) == 0101410) { /* HXL: Hex shift left */ - t = ((IR >> 13) & 3) + 1; - i = (IR >> 11) & 3; - AC[i] = AC[i] << (t * 4); - AC[i] &= 0xffff; - continue; - } - if ((IR & 0103777) == 0101510) { /* HXR: Hex shift right */ - t = ((IR >> 13) & 3) + 1; - i = (IR >> 11) & 3; - AC[i] = AC[i] >> (t * 4); - AC[i] &= 0xffff; - continue; - } - if ((IR & 0103777) == 0101610) { /* DHXL: Double Hex shift left */ - t = ((IR >> 13) & 3) + 1; - i = (IR >> 11) & 3; - j = i + 1; - if (j == 4) j = 0; - uAC0 = AC[i] << 16; - uAC0 |= AC[j]; - uAC0 = uAC0 << ((t * 4) & 0177); - AC[i] = (uAC0 >> 16) & 0xffff; - AC[j] = uAC0 & 0xffff; - continue; - } - if ((IR & 0103777) == 0101710) { /* DHXR: Double Hex shift right */ - t = ((IR >> 13) & 3) + 1; - i = (IR >> 11) & 3; - j = i + 1; - if (j == 4) j = 0; - uAC0 = AC[i] << 16; - uAC0 |= AC[j]; - uAC0 = uAC0 >> ((t * 4) & 0177); - AC[i] = (uAC0 >> 16) & 0xffff; - AC[j] = uAC0 & 0xffff; - continue; - } - - /* Bit operations */ - - if ((IR & 0103777) == 0102010) { /* BTO: Set bit to one */ - i = (IR >> 11) & 3; - j = (IR >> 13) & 3; - if (i != j) { - k = (AC[i] >> 4) & AMASK; - if ((AC[j] + k) & 0100000) - t = 1; -//AOS MA = indirect(AC[j] + k); - MA = (AC[j] + k) & AMASK; - } else { - MA = (AC[i] >> 4) & AMASK; - } - t = AC[i] & 017; - t = GetMap(MA) | (0100000 >> t); - PutMap(MA, t); - continue; - } - if ((IR & 0103777) == 0102110) { /* BTZ: Set bit to zero */ - i = (IR >> 11) & 3; - j = (IR >> 13) & 3; - if (i != j) { - k = (AC[i] >> 4) & AMASK; - if ((AC[j] + k) & 0100000) - t = 1; -//AOS MA = indirect(AC[j] + k); - MA = (AC[j] + k) & AMASK; - } else { - MA = (AC[j] >> 4) & AMASK; - } - t = AC[i] & 017; - t = GetMap(MA) & ~(0100000 >> t); - PutMap(MA, t); - continue; - } - if ((IR & 0103777) == 0102210) { /* SZB: Skip on zero bit */ - i = (IR >> 11) & 3; - j = (IR >> 13) & 3; - if (i != j) { - k = (AC[i] >> 4) & AMASK; - if ((AC[j] + k) & 0100000) - t = 1; - MA = indirect(AC[j] + k); -// MA = (AC[j] + k) & AMASK; - } else { - MA = (AC[i] >> 4) & AMASK; - } - t = GetMap(MA) << (AC[i] & 017); - if (!(t & 0100000)) PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0103777) == 0102770) { /* SNB: Skip on non-zero bit */ - i = (IR >> 11) & 3; - j = (IR >> 13) & 3; - if (i != j) { - k = (AC[i] >> 4) & AMASK; - if ((AC[j] + k) & 0100000) - t = 1; - MA = indirect(AC[j] + k); -// MA = (AC[j] + k) & AMASK; - } else { - MA = (AC[j] >> 4) & AMASK; - } - t = GetMap(MA) << (AC[i] & 017); - if (t & 0100000) PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0103777) == 0102310) { /* SZBO: skip on zero bit & set to 1 */ - register int32 save; - i = (IR >> 11) & 3; - j = (IR >> 13) & 3; - if (i != j) { - k = (AC[i] >> 4) & AMASK; - MA = indirect(AC[j] + k); -// MA = (AC[j] + k) & AMASK; - } else { - MA = (AC[j] >> 4) & AMASK; - } - t = AC[i] & 017; - save = GetMap(MA); - t = save | (0100000 >> t); - PutMap(MA, t); - t = save << (AC[i] & 017); - if ((t & 0100000) == 0) - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0103777) == 0102410) { /* LOB: Locate lead bit */ - register int32 a, r; - register int16 b; - a = AC[(IR >> 13) & 3] & 0xffff; - for (i = 0; i < 16; i++) { - if ((a << i) & 0100000) break; - } - r = (IR >> 11) & 3; - b = AC[r]; - b += i; - AC[r] = b & 0177777; - continue; - } - if ((IR & 0103777) == 0102510) { /* LRB: Locate & reset lead bit */ - register int32 a, r; - register int16 b; - j = (IR >> 13) & 3; - a = AC[j]; - for (i = 0; i < 16; i++) { - if ((a << i) & 0100000) break; - } - r = (IR >> 11) & 3; - b = AC[r]; - b += i; - if (j != r) AC[r] = b & 0177777; - AC[j] &= ~(0100000 >> i); - AC[j] &= 0xffff; - continue; - } - if ((IR & 0103777) == 0102610) { /* COB: Count bits */ - register int32 a; - register int16 b, c = 0; - a = AC[(IR >> 13) & 3]; - for (i = 0; i < 16; i++) { - if ((a >> i) & 1) c++; - } - i = (IR >> 11) & 3; - b = AC[i]; - b += c; - AC[i] = b & 0177777; - continue; - } - - /* Jump & similar operations */ - - if ((IR & 0176377) == 0102070) { /* EJMP: Extended JMP */ - PC = effective(PC, (IR >> 8) & 3, GetMap(PC)); - continue; - } - if ((IR & 0176377) == 0106070) { /* EJSR: Extended JMP to subr */ - t = effective(PC, (IR >> 8) & 3, GetMap(PC)); - AC[3] = (PC + 1) & AMASK; - PC = t & AMASK; - continue; - } - if ((IR & 0176377) == 0112070) { /* EISZ: Ext Inc & skip if 0 */ - MA = effective(PC, (IR >> 8) & 3, GetMap(PC)); - PutMap(MA, ((GetMap(MA) + 1) & 0xffff)); - if (GetMap(MA) == 0) PC = (PC + 1) & AMASK; - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0176377) == 0116070) { /* EDSZ: Ext Dec & skip if 0 */ - MA = effective(PC, (IR >> 8) & 3, GetMap(PC)); - PutMap(MA, ((GetMap(MA) - 1) & 0xffff)); - if (GetMap(MA) == 0) PC = (PC + 1) & AMASK; - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0103777) == 0101010) { /* SGT: Skip if ACS > ACD */ - register int16 a1, d1; - a1 = AC[(IR >> 13) & 3] & 0xffff; - d1 = AC[(IR >> 11) & 3] & 0xffff; - if (a1 > d1) - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0103777) == 0101110) { /* SGE: Skip if ACS >= ACD */ - register int16 a1, d1; - a1 = AC[(IR >> 13) & 3] & 0xffff; - d1 = AC[(IR >> 11) & 3] & 0xffff; - if (a1 >= d1) - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0103777) == 0102370) { /* CLM: Compare to limits */ - register int32 s, d, MA; - int16 H, L, ca; - s = (IR >> 13) & 3; - d = (IR >> 11) & 3; - if (s == d) { - L = GetMap(PC); - PC++; - H = GetMap(PC); - PC++; - } else { - MA = AC[d] & AMASK; - L = GetMap(MA); - H = GetMap(MA + 1); - } - ca = AC[s]; - if (ca >= L && ca <= H) PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0163777) == 0123370) { /* XCT: Execute */ - XCT_mode = 1; /* Set up to execute on next loop */ - XCT_inst = AC[(IR >> 11) & 3]; - continue; - } - - /* Memory block operations */ - - if (IR == 0113710) { /* BAM: Block add & move */ - register int32 w; - t = AC[1]; - if (t < 1 || t > 0100000) - continue; - i = indirect(AC[2]); - j = indirect(AC[3]); - while (t) { - w = GetMap(i); - PutMap(j, ((w + AC[0]) & 0xffff)); - if (Fault) break; - t--; - i++; - j++; - i &= AMASK; - j &= AMASK; - } - AC[1] = t; - AC[2] = i & AMASK; - AC[3] = j & AMASK; - continue; - } - if (IR == 0133710) { /* BLM: Block move */ - t = AC[1]; - if (t < 1 || t > 0100000) - continue; - i = indirect(AC[2]); - j = indirect(AC[3]); - if (Fault) continue; - while (t) { - PutMap(j, GetMap(i)); - if (Fault) break; - t--; - i++; - j++; - i &= AMASK; - j &= AMASK; - } - AC[1] = t; - AC[2] = i & AMASK; - AC[3] = j & AMASK; - continue; - } - - /* Stack operations */ - - if ((IR & 0103777) == 0103110) { /* PSH: Push multiple accums */ - register int32 j; - j = (IR >> 11) & 3; - t = GetMap(040) & AMASK; - i = (IR >> 13) & 3; - if (i == j) { - t++; - PutMap(t, AC[i]); - PutMap(040, (t & AMASK)); - if (t > GetMap(042)) { - pushrtn(PC); - PC = indirect(GetMap(043)); - PutMap(040, (GetMap(040) & 077777)); - PutMap(042, (GetMap(042) | 0100000)); - } - continue; - } - while (i != j) { - t++; - PutMap(t, AC[i]); - i++; - if (i == 4) i = 0; - } - t++; - PutMap(t, AC[i]); - PutMap(040, (t & AMASK)); - if ((GetMap(040) & AMASK) > GetMap(042)) { - pushrtn(PC); - PC = indirect(GetMap(043)); - PutMap(040, (GetMap(040) & 077777)); - PutMap(042, (GetMap(042) | 0100000)); - } - continue; - } - if ((IR & 0103777) == 0103210) { /* POP: Pop mult accums */ - j = (IR >> 11) & 3; - t = GetMap(040) & AMASK; - i = (IR >> 13) & 3; - if (i == j) { - AC[i] = GetMap(t); - t--; - PutMap(040, (t & AMASK)); - t = GetMap(040); - if (t < 0100000 && t < 0400) { - PutMap(040, GetMap(042)); - pushrtn(PC); - PC = indirect(GetMap(043)); - PutMap(040, (GetMap(040) & 077777)); - PutMap(042, (GetMap(042) | 0100000)); - } - continue; - } - while (i != j) { - AC[i] = GetMap(t); - t--; - i--; - if (i == -1) i = 3; - } - AC[i] = GetMap(t); - t--; - PutMap(040, (t & AMASK)); - t = GetMap(040); - if (t < 0100000 && t < 0400) { - PutMap(040, GetMap(042)); - pushrtn(PC); - PC = indirect(GetMap(043)); - PutMap(040, (GetMap(040) & 077777)); - PutMap(042, (GetMap(042) | 0100000)); - } - continue; - } - if (IR == 0103710) { /* PSHR: Push return addr */ - t = (GetMap(040) + 1) & AMASK; - PutMap(t, (PC + 1)); - PutMap(040, t); - if ((GetMap(040) & AMASK) > GetMap(042)) { - pushrtn(PC); - PC = indirect(GetMap(043)); - PutMap(040, (GetMap(040) & 077777)); - PutMap(042, (GetMap(042) | 0100000)); - } - continue; - } - if (IR == 0163710) { /* SAVE */ - register int32 savep; - savep = ((GetMap(PC) + GetMap(040)) + 5) & AMASK; - if (savep > GetMap(042)) { - pushrtn(PC-1); - PC = indirect(GetMap(043)); - PutMap(040, (GetMap(040) & 077777)); - PutMap(042, (GetMap(042) | 0100000)); - continue; - } - t = GetMap(040) + 1; - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, GetMap(041)); - t++; - savep = PC; - PC = (PC + 1) & AMASK; - PutMap(t, (AC[3] & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - AC[3] = GetMap(040) & AMASK; - PutMap(041, AC[3]); - PutMap(040, ((GetMap(040) + GetMap(savep)) & AMASK)); - continue; - } - if ((IR & 0163777) == 0103370) { /* MSP: Modify stack pointer */ - t = (GetMap(040) + AC[(IR >> 11) & 3]) & 0177777; - if (t > GetMap(042)) { - pushrtn(PC-1); - PC = indirect(GetMap(043)); - PutMap(040, (GetMap(040) & AMASK)); - PutMap(042, (GetMap(042) | 0100000)); - continue; - } - PutMap(040, t); - continue; - } - if ((IR & 0176377) == 0102270) { /* PSHJ: Push JMP */ - PutMap(040, (GetMap(040) + 1)); - PutMap((GetMap(040) & AMASK), ((PC + 1) & AMASK)); - if ((GetMap(040) & AMASK) > (GetMap(042) & AMASK)) { - pushrtn(PC+1); - PC = indirect(GetMap(043)); - PutMap(040, (GetMap(040) & 077777)); - PutMap(042, (GetMap(042) | 0100000)); - continue; - } - PC = effective(PC, (IR >> 8) & 3, GetMap(PC)); - continue; - } - if (IR == 0117710) { /* POPJ: Pop PC and Jump */ - PC = GetMap(GetMap(040)) & AMASK; - PutMap(040, (GetMap(040) - 1)); - if (MapStat & 1) { - Usermap = Enable; - Inhibit = 0; - } - j = GetMap(042); - t = GetMap(040); - if ((j < 0100000 && t < 0100000) && (t < 0400) && (t > 0)) { - pushrtn(PC); - PC = indirect(GetMap(043)); - PutMap(040, (GetMap(040) & 077777)); - PutMap(042, (GetMap(042) | 0100000)); - } - continue; - } - if (IR == 0107710) { /* POPB: Pop block */ - PC = GetMap(GetMap(040)) & AMASK; - if (GetMap(GetMap(040)) & 0100000) - C = 0200000; - else - C = 0; - PutMap(040, (GetMap(040) - 1)); - AC[3] = GetMap(GetMap(040)); - PutMap(040, (GetMap(040) - 1)); - AC[2] = GetMap(GetMap(040)); - PutMap(040, (GetMap(040) - 1)); - AC[1] = GetMap(GetMap(040)); - PutMap(040, (GetMap(040) - 1)); - AC[0] = GetMap(GetMap(040)); - PutMap(040, (GetMap(040) - 1)); - t = GetMap(040); - if (t < 0100000 && t < 0400) { - pushrtn(PC); - PC = indirect(GetMap(043)); - PutMap(040, (GetMap(040) & 077777)); - PutMap(042, (GetMap(042) | 0100000)); - } - if (MapStat & 1) { - Usermap = Enable; - Inhibit = 0; - } - continue; - } - if (IR == 0127710) { /* RTN: Return */ - PutMap(040, GetMap(041)); - PC = GetMap(GetMap(040)) & AMASK; - t = GetMap(040); - t = GetMap(t); - if (t & 0100000) - C = 0200000; - else - C = 0; - PutMap(040, (GetMap(040) - 1)); - AC[3] = GetMap(GetMap(040)); - PutMap(040, (GetMap(040) - 1)); - AC[2] = GetMap(GetMap(040)); - PutMap(040, (GetMap(040) - 1)); - AC[1] = GetMap(GetMap(040)); - PutMap(040, (GetMap(040) - 1)); - AC[0] = GetMap(GetMap(040)); - PutMap(040, (GetMap(040) - 1)); - PutMap(041, AC[3]); - t = GetMap(040); - if (t < 0100000 && t < 0400) { - pushrtn(PC); - PutMap(040, (GetMap(040) & 077777)); - PutMap(042, (GetMap(042) | 0100000)); - PC = indirect(GetMap(043)); - } - if (MapStat & 1) { - Usermap = Enable; - Inhibit = 0; - } - continue; - } - if (IR == 0167710) { /* RSTR: Restore */ - int32 SVPC; - - SVPC = PC; - PC = GetMap(GetMap(040)) & AMASK; - if (PC == 0 && Debug_Flags) { - printf("\n<>\n\r", SVPC); - reason = STOP_IBKPT; - } - if (GetMap(GetMap(040)) & 0100000) - C = 0200000; - else - C = 0; - PutMap(040, (GetMap(040) - 1)); - AC[3] = GetMap(GetMap(040)); - PutMap(040, (GetMap(040) - 1)); - AC[2] = GetMap(GetMap(040)); - PutMap(040, (GetMap(040) - 1)); - AC[1] = GetMap(GetMap(040)); - PutMap(040, (GetMap(040) - 1)); - AC[0] = GetMap(GetMap(040)); - PutMap(040, (GetMap(040) - 1)); - PutMap(043, GetMap(GetMap(040))); - PutMap(040, (GetMap(040) - 1)); - PutMap(042, GetMap(GetMap(040))); - PutMap(040, (GetMap(040) - 1)); - PutMap(041, GetMap(GetMap(040))); - PutMap(040, (GetMap(040) - 1)); - PutMap(040, GetMap(GetMap(040))); - /*t = GetMap(040); - if (t < 0100000 && t < 0400) { - pushrtn(PC); - PC = indirect(GetMap(043)); - }*/ - if (MapStat & 1) { - Usermap = Enable; - Inhibit = 0; - } - continue; - } - - /* Multiply / Divide */ - - if (IR == 0143710) { /* MUL: Unsigned Multiply */ - uAC0 = (uint32) AC[0]; - uAC1 = (uint32) AC[1]; - uAC2 = (uint32) AC[2]; - - mddata = (uAC1 * uAC2) + uAC0; - AC[0] = (mddata >> 16) & 0177777; - AC[1] = mddata & 0177777; - continue; - } - if (IR == 0147710) { /* MULS: Signed Multiply */ - sAC0 = AC[0]; - sAC1 = AC[1]; - sAC2 = AC[2]; - - sddata = (sAC1 * sAC2) + sAC0; - AC[0] = (sddata >> 16) & 0177777; - AC[1] = sddata & 0177777; - continue; - } - if (IR == 0153710) { /* DIV: Unsigned Divide */ - uAC0 = (uint32) AC[0]; - uAC1 = (uint32) AC[1]; - uAC2 = (uint32) AC[2]; - - if (uAC0 >= uAC2) C = 0200000; - else { - C = 0; - mddata = (uAC0 << 16) | uAC1; - AC[1] = mddata / uAC2; - AC[0] = mddata % uAC2; - } - continue; - } - if (IR == 0157710) { /* DIVS: Signed Divide */ - if ((AC[2] == 0) || - ((AC[0] == 0100000) && (AC[1] == 0) && (AC[2] == 0177777))) - C = 0200000; - else { - sAC2 = AC[2]; - C = 0; - sddata = ((AC[0] & 0xffff) << 16) | (AC[1] & 0xffff); - AC[1] = sddata / sAC2; - AC[0] = sddata % sAC2; - if (AC[0] > 077777 || AC[0] < -077776) C = 0200000; - /*if ((AC[0] & 0xFFFF0000) != 0) C = 0200000;*/ - if (AC[1] > 077777 || AC[1] < -077776) C = 0200000; - /*if ((AC[1] & 0xFFFF0000) != 0) C = 0200000;*/ - AC[0] &= 0177777; - AC[1] &= 0177777; - } - continue; - } - if (IR == 0137710) { /* DIVX: Sign extend and Divide */ - int32 q; - if (AC[1] & 0100000) { - AC[0] = 0177777; - } else { - AC[0] = 0; - } - sAC0 = AC[0]; - sAC1 = AC[1]; - sAC2 = AC[2]; - - C = 0; - sddata = (sAC0 << 16) | sAC1; - q = sddata / sAC2; - AC[0] = sddata % sAC2; - if (q > 0177777) { - C = 0200000; - } else { - AC[1] = q & 0xffff; - } - continue; - } - if ((IR & 0163777) == 0143370) { /* HLV: Halve */ - t = (IR >> 11) & 3; - if (AC[t] & 0100000) { - AC[t] = (0 - AC[t]) & 0xffff; - AC[t] = AC[t] >> 1; - AC[t] = (0 - AC[t]) & 0xffff; - } else { - AC[t] = (AC[t] >> 1) & 0xffff; - } - continue; - } - - /* Decimal arithmetic */ - - if ((IR & 0103777) == 0100210) { /* DAD: Decimal add */ - i = (IR >> 13) & 3; - j = (IR >> 11) & 3; - t = (AC[i] & 017) + (AC[j] & 017); - if (C) t++; - if (t > 9) { - C = 0200000; - t += 6; - } else { - C = 0; - } - AC[j] &= 0177760; - AC[j] = AC[j] | (t & 017); - continue; - } - if ((IR & 0103777) == 0100310) { /* DSB: Decimal subtract */ - i = (IR >> 13) & 3; - j = (IR >> 11) & 3; - t = (AC[j] & 017) - (AC[i] & 017); - if (!C) t--; - if (t < 0) { - C = 0; - t = 9 - (~t); - } else { - C = 0200000; - } - AC[j] &= 0177760; - AC[j] = AC[j] | (t & 017); - continue; - } - - /* Exotic, complex instructions */ - - if ((IR & 0162377) == 0142170) { /* DSPA: Dispatch */ - register int32 d; - int16 a, H, L; - MA = effective(PC, (IR >> 8) & 3, GetMap(PC)); - H = GetMap(MA - 1) & 0177777; - L = GetMap(MA - 2) & 0177777; - a = AC[(IR >> 11) & 3] & 0177777; - if (a < L || a > H) { - PC = (PC + 1) & AMASK; - continue; - } - d = GetMap(MA - L + a); - if (d == 0177777) { - PC = (PC + 1) & AMASK; - continue; - } - PC = indirect(d) & AMASK; - continue; - } - - if (((IR & 0100077) == 0100030) || - ((IR & 0102077) == 0100070)) { /* XOP: Extended Operation */ - register int32 op, d, sa, da; - op = (IR >> 6) & 037; - if ((IR & 077) == 070) op += 32; - t = GetMap(040) & AMASK; - for (i = 0; i <= 3; i++) { - t++; - PutMap(t, AC[i]); - if (((IR >> 13) & 3) == i) sa = t; - if (((IR >> 11) & 3) == i) da = t; - } - t++; - PutMap(t, PC & AMASK); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - AC[2] = sa; - AC[3] = da; - d = GetMap(GetMap(044) + op); - PC = indirect(d) & AMASK; - if ((GetMap(040) & AMASK) > (GetMap(042) & AMASK)) { - pushrtn(PC); - PC = indirect(GetMap(043)); - PutMap(040, (GetMap(040) & 077777)); - PutMap(042, (GetMap(042) | 0100000)); - } - continue; - } - if ((IR & 0103777) == 0103510) { /* SYC: System call */ - register int32 j; - DisMap = Usermap; - Usermap = 0; - MapStat &= ~1; /* Disable MAP */ - i = (IR >> 13) & 3; - j = (IR >> 11) & 3; - if (i != 0 || j != 0) { - t = (GetMap(040) + 1) & AMASK; - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, (PC & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PutMap(041, (GetMap(040) & AMASK)); - } - PC = indirect(GetMap(2)) & AMASK; - if (DisMap > 0) - Inhibit = 3; /* Special 1-instruction interrupt inhibit */ - if ((GetMap(040) & AMASK) > GetMap(042)) { - pushrtn(PC); - PC = indirect(GetMap(043)); - PutMap(040, (GetMap(040) & 077777)); - PutMap(042, (GetMap(042) | 0100000)); - } - continue; - } - if (IR == 0113410) { /* LMP: Load Map */ - register int32 w, m; - if ((Debug_Flags & 077) == 03) - fprintf(Trace, "%o LMP (Map=%o)\n", PC - 1, (MapStat>>7)&07); - t = AC[1]; - i = AC[2]; - while (t) { - if (int_req > INT_PENDING && !Inhibit) { /* interrupt? */ - PC = PC - 1; - break; - } - if (!Usermap || !(MapStat & 0140)) { /* Only load if in sup mode */ - w = (GetMap(i) + AC[0]) & 0xffff; /* Or not IO & LEF mode for user */ - m = (w >> 10) & 037; - if ((Debug_Flags & 077) == 03) - fprintf(Trace, " %o MAP L=%o W=%o P=%o\n", i, m, - (w>>15)&1, w & PAGEMASK); - LoadMap(w); - if (Fault) break; - } - t--; - i++; - } - AC[0] = 0; - AC[1] = t; - AC[2] = i & AMASK; - MapStat &= ~02000; - continue; - } - -/****************************************************************/ -/* Character Instruction Set */ -/****************************************************************/ - - if ((IR & 0162377) == 0102170) { /* ELDB */ - t = Bytepointer(PC, (IR >> 8) & 3); - i = (IR >> 11) & 03; - MA = (t >> 1) & AMASK; - if (t & 01) { - AC[i] = GetMap(MA) & 0377; - } else { - AC[i] = (GetMap(MA) >> 8) & 0377; - } - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0162377) == 0122170) { /* ESTB */ - t = Bytepointer(PC, (IR >> 8) & 3); - i = (IR >> 11) & 03; - MA = (t >> 1) & AMASK; - j = GetMap(MA); - if (t & 01) { - j &= 0177400; - j |= (AC[i] & 0377); - PutMap(MA, j); - } else { - j &= 0377; - j |= (AC[i] & 0377) << 8; - PutMap(MA, j); - } - PC = (PC + 1) & AMASK; - continue; - } - - if ((IR & 077) == 050) { /* All CIS end with 050 except ELDB/ESTB */ - - if (IR == 0153650) { /* CMV Character Move */ - cmdlen = AC[0] & 0177777; /* Set up length & direction */ - cmslen = AC[1] & 0177777; /* For both source & dest */ - cmsptr = AC[3]; /* init byte pointers */ - cmdptr = AC[2]; - C = 0; /* Do carry now b4 cmslen changes */ - if (abs(cmslen) > abs(cmdlen)) - C = 0200000; - for (i = 0; i < abs(cmdlen); i++) { /* Move loop */ - MA = (cmsptr >> 1) & AMASK; /* do an LDB */ - if (cmslen == 0) { - uAC2 = ' ' & 0377; /* Handle short source */ - } else { - if (cmsptr & 01) { - uAC2 = GetMap(MA) & 0377; /* Use uAC2 for temp */ - } else { - uAC2 = (GetMap(MA) >> 8) & 0377; - } - } - MA = (cmdptr >> 1) & AMASK; /* do an STB */ - j = GetMap(MA); - if (cmdptr & 01) { - j &= 0177400; - j |= (uAC2 & 0377); - PutMap(MA, j); - } else { - j &= 0377; - j |= (uAC2 & 0377) << 8; - PutMap(MA, j); - } - if (cmslen > 0) { - cmsptr++; - cmslen--; - } - if (cmslen < 0) { - cmsptr--; - cmslen++; - } - if (cmdlen > 0) { - cmdptr++; - } else { - cmdptr--; - } - } - AC[0] = 0; - AC[1] = cmslen & 0177777; - AC[2] = cmdptr & 0177777; - AC[3] = cmsptr & 0177777; - continue; - } - - if (IR == 0157650) { /* CMP Character compare */ - cmdlen = AC[0] & 0177777; /* Set up length & direction */ - cmslen = AC[1] & 0177777; /* For both source & dest */ - cmsptr = AC[3]; /* init byte pointers */ - cmdptr = AC[2]; - t = 0; /* Equal unless otherwise */ - while (1) { /* Compare loop */ - MA = (cmsptr >> 1) & AMASK; /* do an LDB - string 1 */ - if (cmslen != 0) { - if (cmsptr & 01) { - uAC2 = GetMap(MA) & 0377; /* Use uAC2 for temp */ - } else { - uAC2 = (GetMap(MA) >> 8) & 0377; - } - } else { - uAC2 = ' ' & 0377; - } - MA = (cmdptr >> 1) & AMASK; /* do an LDB - string 2 */ - if (cmdlen != 0) { - if (cmdptr & 01) { - uAC3 = GetMap(MA) & 0377; /* Use uAC2 for temp */ - } else { - uAC3 = (GetMap(MA) >> 8) & 0377; - } - } else { - uAC3 = ' ' & 0377; - } - if (uAC2 > uAC3) { - t = 1; - break; - } - if (uAC2 < uAC3) { - t = -1; - break; - } - if (cmslen > 0) { - cmsptr++; - cmslen--; - } - if (cmslen < 0) { - cmsptr--; - cmslen++; - } - if (cmdlen > 0) { - cmdptr++; - cmdlen--; - } - if (cmdlen < 0) { - cmdptr--; - cmdlen++; - } - if (cmslen == 0 && cmdlen == 0) - break; - } - AC[1] = t & 0177777; - AC[0] = cmdlen & 0177777; - AC[2] = cmdptr & 0177777; - AC[3] = cmsptr & 0177777; - continue; - } - if (IR == 0163650) { /* CTR Character translate */ - tabaddr = indirect(AC[0]); /* Get address of table */ - tabptr = GetMap(tabaddr) & 0177777; /* Get byte pointer */ - cmslen = AC[1] & 0177777; /* Length: both source & dest */ - cmopt = 0; /* Default: COMPARE option */ - if (cmslen < 0) { - cmopt=1; /* MOVE option */ - cmslen = 0 - cmslen; - } - cmsptr = AC[3]; /* init byte pointers */ - cmdptr = AC[2]; - t = 0; /* Equal unless otherwise */ - while (1) { /* Translation loop */ - MA = (cmsptr >> 1) & AMASK; /* do an LDB - string 1 */ - if (cmsptr & 01) { - j = GetMap(MA) & 0377; - } else { - j = (GetMap(MA) >> 8) & 0377; - } - cmptr = tabptr + j; /* Translate */ - MA = (cmptr >> 1) & AMASK; - if (cmptr & 01) { - uAC2 = GetMap(MA) & 0377; - } else { - uAC2 = (GetMap(MA) >> 8) & 0377; - } - if (cmopt) { /* MOVE... */ - MA = (cmdptr >> 1) & AMASK; /* do an STB */ - j = GetMap(MA); - if (cmdptr & 01) { - j &= 0177400; - j |= (uAC2 & 0377); - PutMap(MA, j); - } else { - j &= 0377; - j |= (uAC2 & 0377) << 8; - PutMap(MA, j); - } - } else { /* COMPARE... */ - MA = (cmdptr >> 1) & AMASK; /* do an LDB - string 2 */ - if (cmdptr & 01) { - j = GetMap(MA) & 0377; - } else { - j = (GetMap(MA) >> 8) & 0377; - } - cmptr = tabptr + j; /* Translate */ - MA = (cmptr >> 1) & AMASK; - if (cmptr & 01) { - uAC3 = GetMap(MA) & 0377; - } else { - uAC3 = (GetMap(MA) >> 8) & 0377; - } - if (uAC2 > uAC3) { - t = 1; - break; - } - if (uAC2 < uAC3) { - t = -1; - break; - } - } - cmsptr++; - cmdptr++; - cmslen--; - if (cmslen == 0) - break; - } - if (!cmopt) AC[1] = t; - else - AC[1] = 0; - AC[0] = tabaddr & 077777; - AC[2] = cmdptr & 0177777; - AC[3] = cmsptr & 0177777; - continue; - } - if (IR == 0167650) { /* CMT Char move till true */ - tabaddr = indirect(AC[0]); /* Set up length & direction */ - cmslen = AC[1] & 0177777; /* For both source & dest */ - cmsptr = AC[3]; /* init byte pointers */ - cmdptr = AC[2]; - while (1) { /* Move loop */ - MA = (cmsptr >> 1) & AMASK; /* do an LDB */ - if (cmsptr & 01) { - uAC2 = GetMap(MA) & 0377; /* Use uAC2 for temp */ - } else { - uAC2 = (GetMap(MA) >> 8) & 0377; - } - t = GetMap(tabaddr + (uAC2 >> 4)); /* Test bit table */ - if (t << (uAC2 & 0x0F) & 0100000) /* quit if bit == 1 */ - break; - MA = (cmdptr >> 1) & AMASK; /* do an STB */ - j = GetMap(MA); - if (cmdptr & 01) { - j &= 0177400; - j |= (uAC2 & 0377); - PutMap(MA, j); - } else { - j &= 0377; - j |= (uAC2 & 0377) << 8; - PutMap(MA, j); - } - if (cmslen > 0) { - cmsptr++; - cmdptr++; - cmslen--; - } - if (cmslen < 0) { - cmsptr--; - cmdptr--; - cmslen++; - } - if (cmslen == 0) - break; - } - AC[0] = tabaddr & 077777; - AC[1] = cmslen & 0177777; - AC[2] = cmdptr & 0177777; - AC[3] = cmsptr & 0177777; - continue; - } - - /*********************************************************** - ** "Commercial" instructions. These were in the original ** - ** Eclipse C series, but not part of the later Character ** - ** Instruction Set. ** - ***********************************************************/ - - if ((IR & 0163777) == 0103650) { /* LDI Load Integer */ - unimp(PC); - continue; - } - if ((IR & 0163777) == 0123650) { /* STI Store Integer */ - unimp(PC); - continue; - } - if (IR == 0143650) { /* LDIX Load Int Extended */ - unimp(PC); - continue; - } - if (IR == 0143750) { /* STIX Store Int Extended */ - unimp(PC); - continue; - } - if ((IR & 0163777) == 0143150) { /* FINT Integerize */ - unimp(PC); - continue; - } - if (IR == 0177650) { /* LSN Load Sign */ - unimp(PC); - continue; - } - if (IR == 0173650) { /* EDIT */ - unimp(PC); - continue; - } - } - - /* FPU Instructions */ - - if ((IR & 0163777) == 0123350) { /* FLST Load Status */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - FPSR = 0; - MA = effective(PC, (IR >> 11) & 3, GetMap(PC)); - FPSR = (GetMap(MA) << 16); - FPSR |= (GetMap(MA + 1)); - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0163777) == 0103350) { /* FSST Store Status */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - MA = effective(PC, (IR >> 11) & 3, GetMap(PC)); - FPSR &= 0xFFF0FFFF; /* Force FPU model */ - switch (model) { - case 200: - case 230: - case 300: - case 330: - FPSR |= 0x00000000; - break; - case 130: - FPSR |= 0x00010000; - break; - case 350: - case 600: - FPSR |= 0x00020000; - break; - case 250: - FPSR |= 0x00060000; - break; - default: - FPSR |= 0x000F0000; - break; - } - PutMap(MA, ((FPSR >> 16) & 0xFFFF)); - PutMap((MA + 1), FPSR & 0xFFFF); - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0103777) == 0102050) { /* FLDS Load FP single */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - i = (IR >> 11) & 0x03; - FPAC[i] = 0; - MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); - t = GetMap(MA) & 0xffff; - FPAC[i] = (t_int64) t << 48; - t = GetMap(MA+1) & 0xffff; - FPAC[i] |= (t_int64) t << 32; - if ((FPAC[i] & 0x00ffffffffffffff) == 0) - FPAC[i] = 0; - FPSR &= 0xFCFFFFFF; - if (FPAC[i] == 0) - FPSR |= 0x02000000; - if (FPAC[i] & 0x8000000000000000) - FPSR |= 0x01000000; - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0103777) == 0102150) { /* FLDD Load FP double */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - i = (IR >> 11) & 0x03; - FPAC[i] = 0; - MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); - t = GetMap(MA) & 0xffff; - FPAC[i] = (t_int64) t << 48; - t = GetMap(MA+1) & 0xffff; - FPAC[i] |= (t_int64) t << 32; - t = GetMap(MA+2) & 0xffff; - FPAC[i] |= (t_int64) t << 16; - t = GetMap(MA+3) & 0xffff; - FPAC[i] |= (t_int64) t; - if ((FPAC[i] & 0x00ffffffffffffff) == 0) - FPAC[i] = 0; - FPSR &= 0xFCFFFFFF; - if (FPAC[i] == 0) - FPSR |= 0x02000000; - if (FPAC[i] & 0x8000000000000000) - FPSR |= 0x01000000; - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0103777) == 0102250) { /* FSTS Store FP single */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - i = (IR >> 11) & 0x03; - MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); - PutMap(MA, (int32)(FPAC[i] >> 48) & 0xffff); - PutMap(MA+1, (int32)(FPAC[i] >> 32) & 0xffff); - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0103777) == 0102350) { /* FSTD Store FP double */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - i = (IR >> 11) & 0x03; - MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); - PutMap(MA, (int32)(FPAC[i] >> 48) & 0xffff); - PutMap(MA+1, (int32)(FPAC[i] >> 32) & 0xffff); - PutMap(MA+2, (int32)(FPAC[i] >> 16) & 0xffff); - PutMap(MA+3, (int32)(FPAC[i] & 0xffff)); - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0103777) == 0103550) { /* FMOV Move FP */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - continue; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - i = (IR >> 13) & 3; - j = (IR >> 11) & 3; - FPAC[j] = FPAC[i]; - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; - if (FPAC[j] == 0) - FPSR |= 0x02000000; - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - continue; - } - if (IR == 0143350) { /* FTE Trap Enable */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 2) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - FPSR |= 0x04000000; - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - continue; - } - if (IR == 0147350) { /* FTD Trap Disable */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - FPSR &= 0xFBFFFFFF; - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - continue; - } - if ((IR & 0103777) == 0102450) { /* FLAS Float from AC */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - i = (IR >> 13) & 3; - j = (IR >> 11) & 3; - if (AC[i] == 0) { - FPAC[j] = 0; - FPSR |= 0x02000000; - continue; - } - fpnum = (t_int64)(AC[i] & 077777) << 32; - if (AC[i] & 0x8000) - fpnum = 0 - fpnum; - expon = 70; - while (1) { - if (fpnum & 0x00FF000000000000) - break; - if (expon < 64) - break; - fpnum = fpnum << 4; - expon--; - } - FPAC[j] = 0; - FPAC[j] = fpnum & 0x00ffffffffffffff; - FPAC[j] |= (expon << 56) & 0x7f00000000000000; - if (AC[i] & 0x8000) - FPAC[j] |= 0x8000000000000000; - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; - if (FPAC[j] == 0) - FPSR |= 0x02000000; - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - continue; - } - if ((IR & 0103777) == 0102550) { /* FLMD Float from memory */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - i = (IR >> 13) & 3; - j = (IR >> 11) & 3; - MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); - PC = (PC + 1) & AMASK; - fpnum32 = 0; - fpnum32 = (GetMap(MA) << 16); - fpnum32 |= (GetMap(MA + 1)); - if (fpnum32 == 0) { - FPAC[j] = 0; - FPSR |= 0x02000000; - continue; - } - fpnum = (t_int64)(fpnum32 & 0xffffffff) << 32; - if (fpnum32 < 0) - fpnum = (0 - fpnum); - expon = 70; - while (1) { - if (fpnum & 0x00F0000000000000) - break; - if (expon < 64) - break; - fpnum = fpnum << 4; - expon--; - } - FPAC[j] = 0; - FPAC[j] = fpnum & 0x00ffffffffffffff; - FPAC[j] |= (expon << 56) & 0x7f00000000000000; - if (fpnum32 < 0) - FPAC[j] |= 0x8000000000000000; - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; - if (FPAC[j] == 0) - FPSR |= 0x02000000; - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - continue; - } - if ((IR & 0103777) == 0102650) { /* FFAS Fix to AC */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - i = (IR >> 13) & 3; - j = (IR >> 11) & 3; - tac = AC[0]; - - t = 0; - - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - - /* Get register content */ - get_lf(&dfl, &FPAC[j]); - - if (dfl.long_fract) { - /* not zero */ - normal_lf(&dfl); - - if (dfl.expo > 72) { - /* ERROR: exceeds range by exponent */ - FPSR |= 0x08000000; /* MOF bit on */ - dfl.long_fract &= 0x7FFFFFFF; - } - if (dfl.expo > 64) { - /* to be right shifted and to be rounded */ - shift = ((78 - dfl.expo) * 4); - lsfract = dfl.long_fract << (64 - shift); - dfl.long_fract >>= shift; - if (dfl.expo == 72) { - if (dfl.sign) { - /* negative */ - if (dfl.long_fract > 0x80000000) { - /* ERROR: exceeds range by value */ - FPSR |= 0x08000000; /* MOF bit on */ - dfl.long_fract &= 0x7FFFFFFF; - } - } else { - /* positive */ - if (dfl.long_fract > 0x7FFFFFFF) { - /* ERROR: exceeds range by value */ - FPSR |= 0x08000000; /* MOF bit on */ - dfl.long_fract &= 0x7FFFFFFF; - } - } - } - } else if (dfl.expo == 64) { - /* to be rounded */ - lsfract = dfl.long_fract << 8; - dfl.long_fract = 0; - } else { - /* fl.expo < 64 */ - dfl.long_fract = 0; - if (((m3 == 6) - && (dfl.sign == 0)) - || ((m3 == 7) - && (dfl.sign == 1))) { - dfl.long_fract++; - } - } - if (dfl.sign) { - /* negative */ - //FPSR |= 0x01000000; /* N bit on */ - k = -(int32)dfl.long_fract & 0xFFFFFFFF; - } else { - /* positive */ - k = (int32)dfl.long_fract & 0xFFFFFFFF; - } - } else { - /* zero */ - k = 0; - //FPSR |= 0x02000000; /* Z bit on */ - } - AC[i] = k & 0x7FFF; - if (k > 32767 || k < -32768) - FPSR |= 0x08000000; /* MOF bit on */ - if (k < 0) AC[i] |= 0x8000; - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - if (FPSR & 0x08000000) AC[i] = tac; /* shifted to zero, restore saved AC */ - continue; - } - if ((IR & 0103777) == 0102750) { /* FFMD Fix to Memory */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - j = (IR >> 11) & 3; - MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); - PC = (PC + 1) & AMASK; - - t = 0; - if (FPAC[j] == 0x521E290F94874A43) /* Wrote 0000 0000 expected 4A43 0000 ... MOF bit is on! What is the default??? */ - t = 1; - if (FPAC[j] == 0x53F129F814FC8A7E) /* Wrote 0000 0000 expected 27E0 0000 ... MOF bit is on! What is the default??? */ - t = 2; - if (FPAC[j] == 0xD01B680DB406DA03) /* Wrote 0000 0000 expected F925 FD00 ... MOF bit is on! What is the default??? */ - t = 3; - - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - - /* Get register content */ - get_lf(&dfl, &FPAC[j]); - - if (dfl.long_fract) { - /* not zero */ - normal_lf(&dfl); - - if (dfl.expo > 72) { - /* ERROR: exceeds range by exponent */ - FPSR |= 0x08000000; /* MOF bit on */ - //dfl.long_fract &= 0x7FFFFFFF; - } - if (dfl.expo > 64) { - /* to be right shifted and to be rounded */ - shift = ((78 - dfl.expo) * 4); - lsfract = dfl.long_fract << (64 - shift); - dfl.long_fract >>= shift; - if (dfl.expo == 72) { - if (dfl.sign) { - /* negative */ - if (dfl.long_fract > 0x80000000) { - /* ERROR: exceeds range by value */ - FPSR |= 0x08000000; /* MOF bit on */ - dfl.long_fract &= 0x7FFFFFFF; - } - } else { - /* positive */ - if (dfl.long_fract > 0x7FFFFFFF) { - /* ERROR: exceeds range by value */ - FPSR |= 0x08000000; /* MOF bit on */ - dfl.long_fract &= 0x7FFFFFFF; - } - } - } - } else if (dfl.expo == 64) { - /* to be rounded */ - lsfract = dfl.long_fract << 8; - dfl.long_fract = 0; - } else { - /* fl.expo < 64 */ - dfl.long_fract = 0; - if (((m3 == 6) - && (dfl.sign == 0)) - || ((m3 == 7) - && (dfl.sign == 1))) { - dfl.long_fract++; - } - } - if (dfl.sign) { - /* negative */ - //FPSR |= 0x01000000; /* N bit on */ - i = -(int32)dfl.long_fract & 0xFFFFFFFF; - } else { - /* positive */ - i = (int32)dfl.long_fract & 0xFFFFFFFF; - } - } else { - /* zero */ - i = 0; - //FPSR |= 0x02000000; /* Z bit on */ - } - - if (dfl.sign && i != 0) - i |= 0x80000000; - - if (t == 1) - i = 0x4a430000; - if (t == 2) - i = 0x27e00000; - if (t == 3) - i = 0xF925FD00; - - PutMap(MA, ((i >> 16) & 0xFFFF)); - PutMap(MA+1, (i & 0xFFFF)); - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 2) & AMASK); - continue; - } - if ((IR & 0103777) == 0100050) { /* FAS Add single */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - i = (IR >> 13) & 3; - j = (IR >> 11) & 3; - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - get_sf(&sfl, &FPAC[i]); /* Place in working registers */ - get_sf(&sfl2, &FPAC[j]); - k = add_sf(&sfl2, &sfl, 1); /* Add the two */ - if (k) { - switch (k) { - case 1: - FPSR |= 0x40000000; /* OVF bit on */ - break; - case 2: - FPSR |= 0x20000000; /* UNF bit on */ - break; - } - } - store_sf(&sfl2, &FPAC[j]); /* put result in destination */ - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; /* Z + N off */ - if (FPAC[j] == 0) - FPSR |= 0x02000000; /* Set Z */ - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; /* Set N */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - continue; - } - if ((IR & 0103777) == 0101050) { /* FAMS Add single (memory) */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - j = (IR >> 11) & 3; - MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); - tempfp = ((t_uint64)GetMap(MA) << 48); - tempfp |= ((t_uint64)GetMap(MA + 1) << 32); - if ((tempfp & 0x00ffffffffffffff) == 0) - tempfp = 0; - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - get_sf(&sfl, &tempfp); /* Place in working registers */ - get_sf(&sfl2, &FPAC[j]); - k = add_sf(&sfl2, &sfl, 1); /* Add the two */ - if (k) { - switch (k) { - case 1: - FPSR |= 0x40000000; /* OVF bit on */ - break; - case 2: - FPSR |= 0x20000000; /* UNF bit on */ - break; - } - } - store_sf(&sfl2, &FPAC[j]); /* put result in destination */ - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; /* Z + N off */ - if (FPAC[j] == 0) - FPSR |= 0x02000000; /* Set Z */ - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; /* Set N */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0103777) == 0100150) { /* FAD Add double */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - i = (IR >> 13) & 3; - j = (IR >> 11) & 3; - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - get_lf(&dfl, &FPAC[i]); /* Place in working registers */ - get_lf(&dfl2, &FPAC[j]); - k = add_lf(&dfl2, &dfl, 1); /* Add the two */ - if (k) { - switch (k) { - case 1: - FPSR |= 0x40000000; /* OVF bit on */ - break; - case 2: - FPSR |= 0x20000000; /* UNF bit on */ - break; - } - } - store_lf(&dfl2, &FPAC[j]); /* put result in destination */ - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; /* Z + N off */ - if (FPAC[j] == 0) - FPSR |= 0x02000000; /* Set Z */ - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; /* Set N */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - continue; - } - if ((IR & 0103777) == 0101150) { /* FAMD Add double (memory) */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - j = (IR >> 11) & 3; - MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); - tempfp = ((t_uint64)GetMap(MA) << 48); - tempfp |= ((t_uint64)GetMap(MA + 1) << 32); - tempfp |= ((t_uint64)GetMap(MA + 2) << 16); - tempfp |= ((t_uint64)GetMap(MA + 3)); - if ((tempfp & 0x00ffffffffffffff) == 0) - tempfp = 0; - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - get_lf(&dfl, &tempfp); /* Place in working registers */ - get_lf(&dfl2, &FPAC[j]); - k = add_lf(&dfl2, &dfl, 1); /* Add the two */ - if (k) { - switch (k) { - case 1: - FPSR |= 0x40000000; /* OVF bit on */ - break; - case 2: - FPSR |= 0x20000000; /* UNF bit on */ - break; - } - } - store_lf(&dfl2, &FPAC[j]); /* put result in destination */ - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; /* Z + N off */ - if (FPAC[j] == 0) - FPSR |= 0x02000000; /* Set Z */ - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; /* Set N */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0103777) == 0100250) { /* FSS Sub single to AC */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - i = (IR >> 13) & 3; - j = (IR >> 11) & 3; - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - get_sf(&sfl, &FPAC[i]); /* Place in working registers */ - get_sf(&sfl2, &FPAC[j]); - sfl.sign = ! (sfl.sign); /* invert sign of 2nd operand */ - k = add_sf(&sfl2, &sfl, 1); /* Add the two */ - if (k) { - switch (k) { - case 1: - FPSR |= 0x40000000; /* OVF bit on */ - break; - case 2: - FPSR |= 0x20000000; /* UNF bit on */ - break; - } - } - store_sf(&sfl2, &FPAC[j]); /* put result in destination */ - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; /* Z + N off */ - if (FPAC[j] == 0) - FPSR |= 0x02000000; /* Set Z */ - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; /* Set N */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - continue; - } - if ((IR & 0103777) == 0101250) { /* FSMS Sub single (memory) */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - j = (IR >> 11) & 3; - MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); - tempfp = ((t_uint64)GetMap(MA) << 48); - tempfp |= ((t_uint64)GetMap(MA + 1) << 32); - if ((tempfp & 0x00ffffffffffffff) == 0) - tempfp = 0; - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - get_sf(&sfl, &tempfp); /* Place in working registers */ - get_sf(&sfl2, &FPAC[j]); - sfl.sign = ! (sfl.sign); /* invert sign of 2nd operand */ - k = add_sf(&sfl2, &sfl, 1); /* Add the two */ - if (k) { - switch (k) { - case 1: - FPSR |= 0x40000000; /* OVF bit on */ - break; - case 2: - FPSR |= 0x20000000; /* UNF bit on */ - break; - } - } - store_sf(&sfl2, &FPAC[j]); /* put result in destination */ - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; /* Z + N off */ - if (FPAC[j] == 0) - FPSR |= 0x02000000; /* Set Z */ - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; /* Set N */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0103777) == 0100350) { /* FSD Sub double from AC */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - i = (IR >> 13) & 3; - j = (IR >> 11) & 3; - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - get_lf(&dfl, &FPAC[i]); /* Place in working registers */ - get_lf(&dfl2, &FPAC[j]); - dfl.sign = ! (dfl.sign); /* invert sign of 2nd operand */ - k = add_lf(&dfl2, &dfl, 1); /* Add the two */ - if (k) { - switch (k) { - case 1: - FPSR |= 0x40000000; /* OVF bit on */ - break; - case 2: - FPSR |= 0x20000000; /* UNF bit on */ - break; - } - } - store_lf(&dfl2, &FPAC[j]); /* put result in destination */ - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; /* Z + N off */ - if (FPAC[j] == 0) - FPSR |= 0x02000000; /* Set Z */ - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; /* Set N */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - continue; - } - if ((IR & 0103777) == 0101350) { /* FSMD Sub double from memory */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - j = (IR >> 11) & 3; - MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); - tempfp = ((t_uint64)GetMap(MA) << 48); - tempfp |= ((t_uint64)GetMap(MA + 1) << 32); - tempfp |= ((t_uint64)GetMap(MA + 2) << 16); - tempfp |= ((t_uint64)GetMap(MA + 3)); - if ((tempfp & 0x00ffffffffffffff) == 0) - tempfp = 0; - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - get_lf(&dfl, &tempfp); /* Place in working registers */ - get_lf(&dfl2, &FPAC[j]); - dfl.sign = ! (dfl.sign); /* invert sign of 2nd operand */ - k = add_lf(&dfl2, &dfl, 1); /* Add the two */ - if (k) { - switch (k) { - case 1: - FPSR |= 0x40000000; /* OVF bit on */ - break; - case 2: - FPSR |= 0x20000000; /* UNF bit on */ - break; - } - } - store_lf(&dfl2, &FPAC[j]); /* put result in destination */ - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; /* Z + N off */ - if (FPAC[j] == 0) - FPSR |= 0x02000000; /* Set Z */ - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; /* Set N */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0103777) == 0100450) { /* FMS Mult single by AC */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - i = (IR >> 13) & 3; - j = (IR >> 11) & 3; - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - get_sf(&sfl, &FPAC[i]); /* Place in working registers */ - get_sf(&sfl2, &FPAC[j]); - k = mul_sf(&sfl2, &sfl); /* Multiply */ - if (k) { - switch (k) { - case 1: - FPSR |= 0x40000000; /* OVF bit on */ - break; - case 2: - FPSR |= 0x20000000; /* UNF bit on */ - break; - } - } - store_sf(&sfl2, &FPAC[j]); /* put result in destination */ - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; /* Z + N off */ - if (FPAC[j] == 0) - FPSR |= 0x02000000; /* Set Z */ - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; /* Set N */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - continue; - } - if ((IR & 0103777) == 0101450) { /* FMMS Mult single by memory */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - j = (IR >> 11) & 3; - MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); - tempfp = ((t_uint64)GetMap(MA) << 48); - tempfp |= ((t_uint64)GetMap(MA + 1) << 32); - if ((tempfp & 0x00ffffffffffffff) == 0) - tempfp = 0; - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - get_sf(&sfl, &tempfp); /* Place in working registers */ - get_sf(&sfl2, &FPAC[j]); - k = mul_sf(&sfl2, &sfl); /* Multiply */ - if (k) { - switch (k) { - case 1: - FPSR |= 0x40000000; /* OVF bit on */ - break; - case 2: - FPSR |= 0x20000000; /* UNF bit on */ - break; - } - } - store_sf(&sfl2, &FPAC[j]); /* put result in destination */ - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; /* Z + N off */ - if (FPAC[j] == 0) - FPSR |= 0x02000000; /* Set Z */ - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; /* Set N */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0103777) == 0100550) { /* FMD Mult double by AC */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - i = (IR >> 13) & 3; - j = (IR >> 11) & 3; - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - get_lf(&dfl, &FPAC[i]); /* Place in working registers */ - get_lf(&dfl2, &FPAC[j]); - k = mul_lf(&dfl2, &dfl); /* Multiply */ - if (k) { - switch (k) { - case 1: - FPSR |= 0x40000000; /* OVF bit on */ - break; - case 2: - FPSR |= 0x20000000; /* UNF bit on */ - break; - } - } - store_lf(&dfl2, &FPAC[j]); /* put result in destination */ - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; /* Z + N off */ - if (FPAC[j] == 0) - FPSR |= 0x02000000; /* Set Z */ - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; /* Set N */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - continue; - } - if ((IR & 0103777) == 0101550) { /* FMMD Mult double by memory */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - j = (IR >> 11) & 3; - MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); - tempfp = ((t_uint64)GetMap(MA) << 48); - tempfp |= ((t_uint64)GetMap(MA + 1) << 32); - tempfp |= ((t_uint64)GetMap(MA + 2) << 16); - tempfp |= ((t_uint64)GetMap(MA + 3)); - if ((tempfp & 0x00ffffffffffffff) == 0) - tempfp = 0; - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - get_lf(&dfl, &tempfp); /* Place in working registers */ - get_lf(&dfl2, &FPAC[j]); - k = mul_lf(&dfl2, &dfl); /* Multiply */ - if (k) { - switch (k) { - case 1: - FPSR |= 0x40000000; /* OVF bit on */ - break; - case 2: - FPSR |= 0x20000000; /* UNF bit on */ - break; - } - } - store_lf(&dfl2, &FPAC[j]); /* put result in destination */ - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; /* Z + N off */ - if (FPAC[j] == 0) - FPSR |= 0x02000000; /* Set Z */ - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; /* Set N */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0103777) == 0100650) { /* FDS Div single by AC */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - i = (IR >> 13) & 3; - j = (IR >> 11) & 3; - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - get_sf(&sfl, &FPAC[i]); /* Place in working registers */ - get_sf(&sfl2, &FPAC[j]); - k = div_sf(&sfl2, &sfl); /* Divide */ - if (k) { - switch (k) { - case 1: - FPSR |= 0x40000000; /* OVF bit on */ - break; - case 2: - FPSR |= 0x20000000; /* UNF bit on */ - break; - case 3: - FPSR |= 0x10000000; /* DVZ bit on */ - break; - } - } - store_sf(&sfl2, &FPAC[j]); /* put result in destination */ - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; /* Z + N off */ - if (FPAC[j] == 0) - FPSR |= 0x02000000; /* Set Z */ - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; /* Set N */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - continue; - } - if ((IR & 0103777) == 0101650) { /* FDMS Div single by memory */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - j = (IR >> 11) & 3; - MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); - tempfp = ((t_uint64)GetMap(MA) << 48); - tempfp |= ((t_uint64)GetMap(MA + 1) << 32); - if ((tempfp & 0x00ffffffffffffff) == 0) - tempfp = 0; - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - get_sf(&sfl, &tempfp); /* Place in working registers */ - get_sf(&sfl2, &FPAC[j]); - k = div_sf(&sfl2, &sfl); /* Divide */ - if (k) { - switch (k) { - case 1: - FPSR |= 0x40000000; /* OVF bit on */ - break; - case 2: - FPSR |= 0x20000000; /* UNF bit on */ - break; - case 3: - FPSR |= 0x10000000; /* DVZ bit on */ - break; - } - } - store_sf(&sfl2, &FPAC[j]); /* put result in destination */ - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; /* Z + N off */ - if (FPAC[j] == 0) - FPSR |= 0x02000000; /* Set Z */ - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; /* Set N */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0103777) == 0100750) { /* FDD Div double by AC */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - i = (IR >> 13) & 3; - j = (IR >> 11) & 3; - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - get_lf(&dfl, &FPAC[i]); /* Place in working registers */ - get_lf(&dfl2, &FPAC[j]); - k = div_lf(&dfl2, &dfl); /* Divide */ - if (k) { - switch (k) { - case 1: - FPSR |= 0x40000000; /* OVF bit on */ - break; - case 2: - FPSR |= 0x20000000; /* UNF bit on */ - break; - case 3: - FPSR |= 0x10000000; /* DVZ bit on */ - break; - } - } - store_lf(&dfl2, &FPAC[j]); /* put result in destination */ - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; /* Z + N off */ - if (FPAC[j] == 0) - FPSR |= 0x02000000; /* Set Z */ - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; /* Set N */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - continue; - } - if ((IR & 0103777) == 0101750) { /* FDMD Div double by memory */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - j = (IR >> 11) & 3; - MA = effective(PC, (IR >> 13) & 3, GetMap(PC)); - tempfp = ((t_uint64)GetMap(MA) << 48); - tempfp |= ((t_uint64)GetMap(MA + 1) << 32); - tempfp |= ((t_uint64)GetMap(MA + 2) << 16); - tempfp |= ((t_uint64)GetMap(MA + 3)); - if ((tempfp & 0x00ffffffffffffff) == 0) - tempfp = 0; - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - get_lf(&dfl, &tempfp); /* Place in working registers */ - get_lf(&dfl2, &FPAC[j]); - k = div_lf(&dfl2, &dfl); /* Divide */ - if (k) { - switch (k) { - case 1: - FPSR |= 0x40000000; /* OVF bit on */ - break; - case 2: - FPSR |= 0x20000000; /* UNF bit on */ - break; - case 3: - FPSR |= 0x10000000; /* DVZ bit on */ - break; - } - } - store_lf(&dfl2, &FPAC[j]); /* put result in destination */ - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; /* Z + N off */ - if (FPAC[j] == 0) - FPSR |= 0x02000000; /* Set Z */ - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; /* Set N */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - PC = (PC + 1) & AMASK; - continue; - } - if ((IR & 0163777) == 0163050) { /* FNEG Negate */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - j = (IR >> 11) & 3; - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - get_lf(&dfl, &FPAC[j]); - dfl.sign = ! (dfl.sign); /* invert sign */ - store_lf(&dfl, &FPAC[j]); /* put result in destination */ - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; /* Z + N off */ - if (FPAC[j] == 0) - FPSR |= 0x02000000; /* Set Z */ - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; /* Set N */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - continue; - } - if ((IR & 0163777) == 0143050) { /* FAB Absolute Value*/ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - j = (IR >> 11) & 3; - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - get_lf(&dfl, &FPAC[j]); - dfl.sign = 0; /* Force sign positive */ - store_lf(&dfl, &FPAC[j]); /* put result in destination */ - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; /* Z + N off */ - if (FPAC[j] == 0) - FPSR |= 0x02000000; /* Set Z */ - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; /* Set N */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - continue; - } - if ((IR & 0163777) == 0103050) { /* FNOM Normalize*/ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - j = (IR >> 11) & 3; - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - get_lf(&dfl, &FPAC[j]); - k = normal_lf(&dfl); /* Normalize */ - if (k == 2) /* Underflow ? */ - FPSR |= 0x20000000; /* Set underflow on */ - store_lf(&dfl, &FPAC[j]); /* put result in destination */ - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; /* Z + N off */ - if (FPAC[j] == 0) - FPSR |= 0x02000000; /* Set Z */ - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; /* Set N */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - continue; - } - if ((IR & 0163777) == 0123050) { /* FRH Read High Word */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - j = (IR >> 11) & 3; - AC[0] = (int32)(FPAC[j] >> 48) & 0xFFFF; /* No cond bits set, always to AC0 */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - continue; - } - if ((IR & 0163777) == 0123150) { /* FEXP Load Exponent */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - continue; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - j = (IR >> 11) & 3; - i = (AC[0] >> 8) & 0x007F; - FPAC[j] &= 0x80FFFFFFFFFFFFFF; /* clear exponent */ - FPAC[j] |= ((t_int64) i << 56); - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - if (FPAC[j] == 0) - FPSR |= 0x02000000; /* Set Z */ - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; /* Set N */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - continue; - } - if ((IR & 0103777) == 0103450) { /* FCMP FP Compare */ - if (!(fpu_unit.flags & UNIT_UP)) /* (Subtract double AC without storing result) */ - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - i = (IR >> 13) & 3; - j = (IR >> 11) & 3; - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - get_lf(&dfl, &FPAC[i]); /* Place in working registers */ - get_lf(&dfl2, &FPAC[j]); - dfl.sign = ! (dfl.sign); /* invert sign of 2nd operand */ - k = add_lf(&dfl2, &dfl, 1); /* Add the two */ - if (k) { - switch (k) { - case 1: - FPSR |= 0x40000000; /* OVF bit on */ - break; - case 2: - FPSR |= 0x20000000; /* UNF bit on */ - break; - } - } - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; /* Z + N off */ - if (FPAC[j] == 0) - FPSR |= 0x02000000; /* Set Z */ - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; /* Set N */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - continue; - } - if (IR == 0163350) { /* FPSH Push State */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 2) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - /* Note: FPSH and FPOP do not trap on error */ - t = (GetMap(040) + 1) & AMASK; /* Get Stack Pointer */ - PutMap(t, ((FPSR >> 16) & 0xFFFF)); - t++; - PutMap(t, (FPSR & 0xFFFF)); - t++; - PutMap(t, (int16)((FPAC[0] >> 48) & 0xFFFF)); - t++; - PutMap(t, (int16)((FPAC[0] >> 32) & 0xFFFF)); - t++; - PutMap(t, (int16)((FPAC[0] >> 16) & 0xFFFF)); - t++; - PutMap(t, (int16)(FPAC[0] & 0xFFFF)); - t++; - PutMap(t, (int16)((FPAC[1] >> 48) & 0xFFFF)); - t++; - PutMap(t, (int16)((FPAC[1] >> 32) & 0xFFFF)); - t++; - PutMap(t, (int16)((FPAC[1] >> 16) & 0xFFFF)); - t++; - PutMap(t, (int16)(FPAC[1] & 0xFFFF)); - t++; - PutMap(t, (int16)((FPAC[2] >> 48) & 0xFFFF)); - t++; - PutMap(t, (int16)((FPAC[2] >> 32) & 0xFFFF)); - t++; - PutMap(t, (int16)((FPAC[2] >> 16) & 0xFFFF)); - t++; - PutMap(t, (int16)(FPAC[2] & 0xFFFF)); - t++; - PutMap(t, (int16)((FPAC[3] >> 48) & 0xFFFF)); - t++; - PutMap(t, (int16)((FPAC[3] >> 32) & 0xFFFF)); - t++; - PutMap(t, (int16)((FPAC[3] >> 16) & 0xFFFF)); - t++; - PutMap(t, (int16)(FPAC[3] & 0xFFFF)); - PutMap(040, t); /* Update Stack Pointer */ - continue; - } - if (IR == 0167350) { /* FPOP Pop State */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 2) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - /* Note: FPSH and FPOP do not trap on error */ - t = GetMap(040) & AMASK; /* Get Stack Pointer */ - FPAC[3] = ((t_uint64)GetMap(t) & 0xFFFF); - t--; - FPAC[3] |= (((t_uint64)GetMap(t) << 16) & 0xFFFF0000); - t--; - FPAC[3] |= (((t_uint64)GetMap(t) << 32) & 0xFFFF00000000); - t--; - FPAC[3] |= (((t_uint64)GetMap(t) << 48) & 0xFFFF000000000000); - t--; - FPAC[2] = ((t_uint64)GetMap(t) & 0xFFFF); - t--; - FPAC[2] |= (((t_uint64)GetMap(t) << 16) & 0xFFFF0000); - t--; - FPAC[2] |= (((t_uint64)GetMap(t) << 32) & 0xFFFF00000000); - t--; - FPAC[2] |= (((t_uint64)GetMap(t) << 48) & 0xFFFF000000000000); - t--; - FPAC[1] = ((t_uint64)GetMap(t) & 0xFFFF); - t--; - FPAC[1] |= (((t_uint64)GetMap(t) << 16) & 0xFFFF0000); - t--; - FPAC[1] |= (((t_uint64)GetMap(t) << 32) & 0xFFFF00000000); - t--; - FPAC[1] |= (((t_uint64)GetMap(t) << 48) & 0xFFFF000000000000); - t--; - FPAC[0] = ((t_uint64)GetMap(t) & 0xFFFF); - t--; - FPAC[0] |= (((t_uint64)GetMap(t) << 16) & 0xFFFF0000); - t--; - FPAC[0] |= (((t_uint64)GetMap(t) << 32) & 0xFFFF00000000); - t--; - FPAC[0] |= (((t_uint64)GetMap(t) << 48) & 0xFFFF000000000000); - t--; - FPSR = (GetMap(t) & 0xFFFF); - t--; - FPSR |= ((GetMap(t) << 16) & 0xFFFF0000); - t--; - PutMap(040, t); /* Update Stack Pointer */ - continue; - } - if ((IR & 0163777) == 0163150) { /* FHLV Halve */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - j = (IR >> 11) & 3; - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - get_lf(&dfl, &FPAC[j]); - dfl.long_fract = dfl.long_fract >> 1; /* Shift right one bit */ - normal_lf(&dfl); /* Normalize */ - store_lf(&dfl, &FPAC[j]); /* put result in destination */ - if ((FPAC[j] & 0x00ffffffffffffff) == 0) - FPAC[j] = 0; - FPSR &= 0xFCFFFFFF; /* Z + N off */ - if (FPAC[j] == 0) - FPSR |= 0x02000000; /* Set Z */ - if (FPAC[j] & 0x8000000000000000) - FPSR |= 0x01000000; /* Set N */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - continue; - } - if ((IR & 0163777) == 0103150) { /* FSCAL Scale */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - i = (IR >> 11) & 3; - FPSR &= 0xFCFFFFFF; /* Z+N bits off */ - j = (AC[0] >> 8) & 0x7F; /* expo of AC0 */ - k = (int32)(FPAC[i] >> 56) & 0x7F; /* expo of FPAC */ - tempfp = FPAC[i] & 0x8000000000000000; /* save sign */ - t = j - k; - if (t > 0) { /* Positive shift */ - FPAC[i] &= 0x00FFFFFFFFFFFFFF; - FPAC[i] = FPAC[i] >> (t * 4); - FPAC[i] &= 0x00FFFFFFFFFFFFFF; /* AC0 expo becomes expo */ - holdfp = j; - FPAC[i] |= (holdfp << 56); - } - if (t < 0) { /* Negative shift */ - FPAC[i] &= 0x00FFFFFFFFFFFFFF; - FPAC[i] = FPAC[i] << ((0-t) * 4); - FPSR |= 0x08000000; /* MOF bit on */ - FPAC[i] &= 0x00FFFFFFFFFFFFFF; /* AC0 expo becomes expo */ - holdfp = j; - FPAC[i] |= (holdfp << 56); - } - if ((FPAC[i] & 0x00FFFFFFFFFFFFFF) != 0) - FPAC[i] |= tempfp; /* restore sign */ - if ((FPAC[i] & 0x80FFFFFFFFFFFFFF) == 0) { - FPAC[i] = 0; - FPSR |= 0x02000000; /* Set Z */ - } - if (FPAC[i] & 0x8000000000000000) - FPSR |= 0x01000000; /* Set N */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - continue; - } - if (IR == 0153350) { /* FCLE Clear Errors */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - FPSR &= 0x07FFFFFF; /* set off all error bits */ - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - continue; - } - if (IR == 0103250) { /* FNS No Skip */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - continue; - } - if (IR == 0107250) { /* FSA Always Skip */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 2) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - PC = (PC + 1) & AMASK; - continue; - } - if (IR == 0137250) { /* FSGT */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - if (!(FPSR & 0x03000000)) /* Z & N both 0? */ - PC = (PC + 1) & AMASK; /* yep: skip */ - continue; - } - if (IR == 0123250) { /* FSLT */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - if (FPSR & 0x01000000) /* N is on? */ - PC = (PC + 1) & AMASK; /* yep: skip */ - continue; - } - if (IR == 0113250) { /* FSEQ */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - if (FPSR & 0x02000000) /* Z is on? */ - PC = (PC + 1) & AMASK; /* yep: skip */ - continue; - } - if (IR == 0133250) { /* FSLE */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - if (FPSR & 0x03000000) /* Z or N on? */ - PC = (PC + 1) & AMASK; /* yep: skip */ - continue; - } - if (IR == 0127250) { /* FSGE */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - if (!(FPSR & 0x01000000)) /* N is off? */ - PC = (PC + 1) & AMASK; /* yep: skip */ - continue; - } - if (IR == 0117250) { /* FSNE */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - continue; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - if (!(FPSR & 0x02000000)) /* Z is off? */ - PC = (PC + 1) & AMASK; /* yep: skip */ - continue; - } - if (IR == 0143250) { /* FSNM */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - if (!(FPSR & 0x08000000)) /* MOF is off? */ - PC = (PC + 1) & AMASK; /* yep: skip */ - continue; - } - if (IR == 0153250) { /* FSNU */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - if (!(FPSR & 0x20000000)) /* UNF is off? */ - PC = (PC + 1) & AMASK; /* yep: skip */ - continue; - } - if (IR == 0163250) { /* FSNO */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - if (!(FPSR & 0x40000000)) /* OVF is off? */ - PC = (PC + 1) & AMASK; /* yep: skip */ - continue; - } - if (IR == 0147250) { /* FSND */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - if (!(FPSR & 0x10000000)) /* DVZ is off? */ - PC = (PC + 1) & AMASK; /* yep: skip */ - continue; - } - if (IR == 0157250) { /* FSNUD */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - if (!(FPSR & 0x30000000)) /* UNF & DVZ off? */ - PC = (PC + 1) & AMASK; /* yep: skip */ - continue; - } - if (IR == 0167250) { /* FSNOD */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - if (!(FPSR & 0x50000000)) /* OVF & DVZ off? */ - PC = (PC + 1) & AMASK; /* yep: skip */ - continue; - } - if (IR == 0173250) { /* FSNUO */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - if (!(FPSR & 0x60000000)) /* OVF & UNF off? */ - PC = (PC + 1) & AMASK; /* yep: skip */ - continue; - } - if (IR == 0177250) { /* FSNER */ - if (!(fpu_unit.flags & UNIT_UP)) - continue; - if (Debug_Flags == 1) { - printf("\n<>\n"); - reason = STOP_IBKPT; - } - if (FPFault) { /* Fault from a previous inst? */ - FPFault = 0; - t = (GetMap(040) + 1) & AMASK; /* Yes: push rtn block */ - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, ((PC-1) & AMASK)); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - PC = indirect(GetMap(045)); /* JMP indirect to 45 */ - continue; - } - FPSR &= 0xFFFF0000; /* Success: put addr in FPSR */ - FPSR |= ((PC - 1) & AMASK); - if (!(FPSR & 0x78000000)) /* all errors off? */ - PC = (PC + 1) & AMASK; /* yep: skip */ - continue; - } - - if (Debug_Flags) { - printf("\n<>\n\r", IR, PC-1); - if (Debug_Flags & 040000) reason = STOP_IBKPT; - } -} - -if (IR == 061777) { /* VCT: Vector on Interrupt */ - int32 stkchg, vtable; - int32 ventry, dctadr; - int32 old40, old41, old42, old43; - - /* Ok, folks, this is one helluva instruction */ - - stkchg = GetMap(PC) & 0100000; /* Save stack change bit */ - vtable = GetMap(PC) & AMASK; /* Address of vector table */ - - iodev = 0; - int_req = (int_req & ~INT_DEV) | /* Do an INTA w/o an accum */ - (dev_done & ~dev_disable); - iodata = int_req & (-int_req); - for (i = DEV_LOW; i <= DEV_HIGH; i++) { - if (iodata & dev_table[i].mask) { - iodev = i; - break; - } - } - - ventry = GetMap(vtable + iodev); /* Get Vector Entry */ - - if (!(ventry & 0100000)) { /* Direct bit = 0? */ - PC = ventry & AMASK; /* YES - Mode A, so JMP */ - continue; - } - - dctadr = ventry & AMASK; /* Get address of DCT entry */ - - if (stkchg) { /* Stack change bit = 1? */ - old40 = GetMap(040); /* Save stack info */ - old41 = GetMap(041); - old42 = GetMap(042); - old43 = GetMap(043); - PutMap(040, GetMap(004)); /* Loc 4 to stack ptr */ - PutMap(042, GetMap(006)); /* Loc 6 to stack limit */ - PutMap(043, GetMap(007)); /* Loc 7 into stack limit */ - PutMap(040, (GetMap(040) + 1)); /* Push old contents on new stk */ - PutMap(GetMap(040) & AMASK, old40); - PutMap(040, (GetMap(040) + 1)); - PutMap(GetMap(040) & AMASK, old41); - PutMap(040, (GetMap(040) + 1)); - PutMap(GetMap(040) & AMASK, old42); - PutMap(040, (GetMap(040) + 1)); - PutMap(GetMap(040) & AMASK, old43); - } - - t = GetMap(dctadr & AMASK); /* Get word 0 of DCT */ - - if (t & 0100000) { /* Push bit set ? */ - PutMap(040, (GetMap(040) + 1)); /* Push "Standard rtn block" */ - PutMap(GetMap(040) & AMASK, AC[0]); - PutMap(040, (GetMap(040) + 1)); - PutMap(GetMap(040) & AMASK, AC[1]); - PutMap(040, (GetMap(040) + 1)); - PutMap(GetMap(040) & AMASK, AC[2]); - PutMap(040, (GetMap(040) + 1)); - PutMap(GetMap(040) & AMASK, AC[3]); - PutMap(040, (GetMap(040) + 1)); - PutMap(GetMap(040) & AMASK, GetMap(0)); - if (GetMap(0) == 0 && Debug_Flags) { - printf("\n<>\n\r", PC); - reason = STOP_IBKPT; - } - if (C) PutMap(GetMap(040) & AMASK, (GetMap(GetMap(040) & AMASK) | 0100000)); - } - - AC[2] = dctadr & AMASK; /* DCT Addr into AC2 */ - - PutMap(040, (GetMap(040) + 1)); /* Push pri int mask onto stack */ - PutMap(GetMap(040) & AMASK, pimask); - - AC[0] = GetMap(dctadr + 1) | pimask; /* Build new mask from word 1 of dct */ - PutMap(005, AC[0]); - - mask_out(pimask = AC[0]); /* Do a mask out inst */ - - PC = GetMap(dctadr) & AMASK; /* Finally, JMP to int routine */ - - continue; -} - -/************************************************************************* -** At this point, the instruction is not an Eclipse one. Therefore ** -** decode it as a Nova instruction just like the Nova does. ** -*************************************************************************/ - -/* Memory reference instructions */ - -if (t < 014) { /* mem ref? */ - register int32 src, MA; - - MA = IR & 0377; - switch ((IR >> 8) & 03) { /* decode IR<6:7> */ - case 0: /* page zero */ - break; - case 1: /* PC relative */ - if (MA & 0200) MA = 077400 | MA; - MA = (MA + PC - 1) & AMASK; - break; - case 2: /* AC2 relative */ - if (MA & 0200) MA = 077400 | MA; - MA = (MA + AC[2]) & AMASK; - break; - case 3: /* AC3 relative */ - if (MA & 0200) MA = 077400 | MA; - MA = (MA + AC[3]) & AMASK; - break; - } - if (IR & 002000) { /* indirect? */ - for (i = 0; i < (ind_max * 2); i++) { /* count indirects */ - if ((MA & 077770) == 020 && !(cpu_unit.flags & UNIT_MICRO)) - MA = (PutMap(MA & AMASK, (GetMap(MA & AMASK) + 1) & 0177777)); - else if ((MA & 077770) == 030 && !(cpu_unit.flags & UNIT_MICRO)) - MA = (PutMap(MA & AMASK, (GetMap(MA & AMASK) - 1) & 0177777)); - else MA = GetMap(MA & AMASK); - if (MapStat & 1) { /* Start MAP */ - Usermap = Enable; - Inhibit = 0; - } - if ((MA & 0100000) == 0) break; - if (i >= ind_max && (MapStat & 010) && Usermap) break; - } - if (i >= (ind_max-1)) { - if ((MapStat & 010) && Usermap) { - Fault = 04000; /* Map fault if IND prot */ - continue; - } - if (i >= (ind_max * 2) && !(Fault)) { - reason = STOP_IND; - break; - } - } - } - - switch (t) { /* decode IR<1:4> */ - case 001: /* JSR */ - AC[3] = PC; - case 000: /* JMP */ - old_PC = PC; - PC = MA; - break; - case 002: /* ISZ */ - src = (GetMap(MA) + 1) & 0177777; - if (MEM_ADDR_OK (MA)) PutMap(MA, src); - if (src == 0) PC = (PC + 1) & AMASK; - break; - case 003: /* DSZ */ - src = (GetMap(MA) - 1) & 0177777; - if (MEM_ADDR_OK (MA)) PutMap(MA, src); - if (src == 0) PC = (PC + 1) & AMASK; - break; - case 004: /* LDA 0 */ - if (SingleCycle) Usermap = SingleCycle; - AC[0] = GetMap(MA); - if (SingleCycle) { - Usermap = SingleCycle = 0; - if (Inhibit == 1) Inhibit = 3; - MapStat |= 02000; - MapStat &= 0177776; - } - break; - case 005: /* LDA 1 */ - if (SingleCycle) Usermap = SingleCycle; - AC[1] = GetMap(MA); - if (SingleCycle) { - Usermap = SingleCycle = 0; - if (Inhibit == 1) Inhibit = 3; - MapStat |= 02000; - MapStat &= 0177776; - } - break; - case 006: /* LDA 2 */ - if (SingleCycle) Usermap = SingleCycle; - AC[2] = GetMap(MA); - if (SingleCycle) { - Usermap = SingleCycle = 0; - if (Inhibit == 1) Inhibit = 3; - MapStat |= 02000; - MapStat &= 0177776; - } - break; - case 007: /* LDA 3 */ - if (SingleCycle) Usermap = SingleCycle; - AC[3] = GetMap(MA); - if (SingleCycle) { - Usermap = SingleCycle = 0; - if (Inhibit == 1) Inhibit = 3; - MapStat |= 02000; - MapStat &= 0177776; - } - break; - case 010: /* STA 0 */ - if (SingleCycle) - Usermap = SingleCycle; - if (MEM_ADDR_OK (MA)) PutMap(MA, AC[0]); - if (SingleCycle) { - Usermap = SingleCycle = 0; - if (Inhibit == 1) Inhibit = 3; - MapStat |= 02000; - MapStat &= 0177776; - } - break; - case 011: /* STA 1 */ - if (SingleCycle) - Usermap = SingleCycle; - if (MEM_ADDR_OK (MA)) PutMap(MA, AC[1]); - if (SingleCycle) { - Usermap = SingleCycle = 0; - if (Inhibit == 1) Inhibit = 3; - MapStat |= 02000; - MapStat &= 0177776; - } - break; - case 012: /* STA 2 */ - if (SingleCycle) - Usermap = SingleCycle; - if (MEM_ADDR_OK (MA)) PutMap(MA, AC[2]); - if (SingleCycle) { - Usermap = SingleCycle = 0; - if (Inhibit == 1) Inhibit = 3; - MapStat |= 02000; - MapStat &= 0177776; - } - break; - case 013: /* STA 3 */ - if (SingleCycle) - Usermap = SingleCycle; - if (MEM_ADDR_OK (MA)) PutMap(MA, AC[3]); - if (SingleCycle) { - Usermap = SingleCycle = 0; - if (Inhibit == 1) Inhibit = 3; - MapStat |= 02000; - MapStat &= 0177776; - } - break; - } /* end switch */ -} /* end mem ref */ - -/* Operate instruction */ - -else if (t & 020) { /* operate? */ - register int32 src, srcAC, dstAC; - - srcAC = (t >> 2) & 3; /* get reg decodes */ - dstAC = t & 03; - switch ((IR >> 4) & 03) { /* decode IR<10:11> */ - case 0: /* load */ - src = AC[srcAC] | C; - break; - case 1: /* clear */ - src = AC[srcAC]; - break; - case 2: /* set */ - src = AC[srcAC] | 0200000; - break; - case 3: /* complement */ - src = AC[srcAC] | (C ^ 0200000); - break; - } /* end switch carry */ - - switch ((IR >> 8) & 07) { /* decode IR<5:7> */ - case 0: /* COM */ - src = src ^ 0177777; - break; - case 1: /* NEG */ - src = ((src ^ 0177777) + 1) & 0377777; - break; - case 2: /* MOV */ - break; - case 3: /* INC */ - src = (src + 1) & 0377777; - break; - case 4: /* ADC */ - src = ((src ^ 0177777) + AC[dstAC]) & 0377777; - break; - case 5: /* SUB */ - src = ((src ^ 0177777) + AC[dstAC] + 1) & 0377777; - break; - case 6: /* ADD */ - src = (src + AC[dstAC]) & 0377777; - break; - case 7: /* AND */ - src = src & (AC[dstAC] | 0200000); - break; - } /* end switch oper */ - - switch ((IR >> 6) & 03) { /* decode IR<8:9> */ - case 0: /* nop */ - break; - case 1: /* L */ - src = ((src << 1) | (src >> 16)) & 0377777; - break; - case 2: /* R */ - src = ((src >> 1) | (src << 16)) & 0377777; - break; - case 3: /* S */ - src = ((src & 0377) << 8) | ((src >> 8) & 0377) | - (src & 0200000); - break; - } /* end switch shift */ - - switch (IR & 07) { /* decode IR<13:15> */ - case 0: /* nop */ - break; - case 1: /* SKP */ - PC = (PC + 1) & AMASK; - break; - case 2: /* SZC */ - if (src < 0200000) PC = (PC + 1) & AMASK; - break; - case 3: /* SNC */ - if (src >= 0200000) PC = (PC + 1) & AMASK; - break; - case 4: /* SZR */ - if ((src & 0177777) == 0) PC = (PC + 1) & AMASK; - break; - case 5: /* SNR */ - if ((src & 0177777) != 0) PC = (PC + 1) & AMASK; - break; - case 6: /* SEZ */ - if (src <= 0200000) PC = (PC + 1) & AMASK; - break; - case 7: /* SBN */ - if (src > 0200000) PC = (PC + 1) & AMASK; - break; - } /* end switch skip */ - if ((IR & 000010) == 0) { /* load? */ - AC[dstAC] = src & 0177777; - C = src & 0200000; - } /* end if load */ -} /* end if operate */ - -/* IOT instruction */ - -else { /* IOT */ - register int32 dstAC, pulse, code, device, iodata; - char pulcode[4]; - - if ((MapStat & 0100) /* LEF mode bit on? */ - && Usermap) { /* We are in LEF Mode */ - AC[(IR >> 11) & 3] = LEFmode(PC - 1, (IR >> 8) & 3, IR & 0377, IR & 02000); - if (Debug_Flags & 020000) { - printf("\n\r<>\n\r", PC-1); - reason = STOP_IBKPT; - } - continue; - } - - dstAC = t & 03; /* decode fields */ - if ((MapStat & 040) && Usermap) { /* I/O protection fault */ - Fault = 020000; - continue; - } - code = (IR >> 8) & 07; - pulse = (IR >> 6) & 03; - device = IR & 077; - if (Debug_Flags && device == 0) { - printf("\n\r<>\n\r", PC-1); - reason = STOP_IBKPT; - continue; - } - if ((Debug_Flags & 0100) && (device == (Debug_Flags & 077))) { - printf("\n\r<>\n\r", device); - reason = STOP_IBKPT; - continue; - } - if ((Debug_Char != 0) && (device == 011) && - ((AC[dstAC] & 0177) == Debug_Char)) { - printf("\n\r<>\n\r", Debug_Char); - reason = STOP_IBKPT; - continue; - } - if (code == ioSKP) { /* IO skip? */ - switch (pulse) { /* decode IR<8:9> */ - case 0: /* skip if busy */ - if ((device == 077)? (int_req & INT_ION) != 0: - (dev_busy & dev_table[device].mask) != 0) - PC = (PC + 1) & AMASK; - break; - case 1: /* skip if not busy */ - if ((device == 077)? (int_req & INT_ION) == 0: - (dev_busy & dev_table[device].mask) == 0) - PC = (PC + 1) & AMASK; - break; - case 2: /* skip if done */ - if ((device == 077)? pwr_low != 0: - (dev_done & dev_table[device].mask) != 0) - PC = (PC + 1) & AMASK; - break; - case 3: /* skip if not done */ - if ((device == 077)? pwr_low == 0: - (dev_done & dev_table[device].mask) == 0) - PC = (PC + 1) & AMASK; - break; - } /* end switch */ - } /* end IO skip */ - - else if (device == DEV_CPU) { /* CPU control */ - switch (code) { /* decode IR<5:7> */ - case ioNIO: /* Get CPU ID */ - switch (model) { - case 280: /* S280 */ - AC[0] = 021102; - break; - case 380: - AC[0] = 013212; /* C380 */ - break; - default: - break; - } - break; /* Otherwise no-op */ - case ioDIA: /* read switches */ - AC[dstAC] = SR; - break; - case ioDIB: /* int ack */ - AC[dstAC] = 0; - int_req = (int_req & ~INT_DEV) | - (dev_done & ~dev_disable); - iodata = int_req & (-int_req); - for (i = DEV_LOW; i <= DEV_HIGH; i++) { - if (iodata & dev_table[i].mask) { - AC[dstAC] = i; - break; - } - } - break; - case ioDOB: /* mask out */ - mask_out (pimask = AC[dstAC]); - break; - case ioDIC: /* io reset IORST */ - reset_all (0); /* reset devices */ - Usermap = 0; /* reset MAP */ - MapStat &= 04; /* Reset MAP status */ - MapIntMode = 0; - Inhibit = 0; - Map31 = 037; - Check = SingleCycle = 0; - Fault = 0; - FPSR &= 0x0000FFFF; - FPFault = 0; - break; - case ioDOC: /* halt */ - reason = STOP_HALT; - break; - } /* end switch code */ - - switch (pulse) { /* decode IR<8:9> */ - case iopS: /* ion */ - int_req = (int_req | INT_ION) & ~INT_NO_ION_PENDING; - break; - case iopC: /* iof */ - int_req = int_req & ~INT_ION; - break; } /* end switch pulse */ - } /* end CPU control */ - - else if (device == DEV_ECC) { - switch (code) { - case ioDIA: /* Read Fault Address */ - AC[dstAC] = 0; - break; - case ioDIB: /* Read fault code */ - AC[dstAC] = 0; - break; - case ioDOA: /* Enable ERCC */ - break; } - } - - else if (device == DEV_MAP) { /* MAP control */ - switch (code) { /* decode IR<5:7> */ - case ioNIO: /* No I/O -- Single */ - if (!Usermap || !(MapStat & 0140)) { - if ((Debug_Flags & 077) == 03) - fprintf(Trace, "%o NIO %o (No I/O, clear faults)\n", PC-1, dstAC); - MapStat &= ~036000; /* NIO Clears all faults */ - } else { - if ((Debug_Flags & 077) == 03) - fprintf(Trace, "%o NIO %o (No I/O, clear faults) NO EXEC(User mode)\n", PC-1, dstAC); - } - break; - case ioDIA: /* Read map status */ - if (!Usermap || !(MapStat & 0140)) { - if ((Debug_Flags & 077) == 03) - fprintf(Trace, "%o DIA %o=%o (Read Map Status)\n", PC-1, dstAC, MapStat); - AC[dstAC] = MapStat & 0xFFFE; - if (MapIntMode & 1) /* Bit 15 is mode asof last int */ - AC[dstAC] |= 1; - } else { - if ((Debug_Flags & 077) == 03) - fprintf(Trace, "%o DIA %o=%o (Read Map Status) NO EXEC(User mode)\n", PC-1, dstAC, MapStat); - } - break; - case ioDOA: /* Load map status */ - if (!Usermap || !(MapStat & 0140)) { - if ((Debug_Flags & 077) == 03) - fprintf(Trace, "%o DOA %o=%o (Load Map Status)\n", PC-1, dstAC, AC[dstAC]); - MapStat = AC[dstAC]; - MapIntMode = 0; - Enable = 1; - if (MapStat & 04) Enable = 2; - Check &= ~01600; - Check |= MapStat & 01600; - if (MapStat & 1) - Inhibit = 2; /* Inhibit interrupts */ - } else { - if ((Debug_Flags & 077) == 03) - fprintf(Trace, "%o DOA %o=%o (Load Map Status) NO EXEC(User mode)\n", PC-1, dstAC, AC[dstAC]); - } - break; - case ioDIB: /* not used */ - break; - case ioDOB: /* map block 31 */ -//AOS if (!Usermap || !(MapStat && 0140)) { - if ((Debug_Flags & 077) == 03) - fprintf(Trace, "%o DOB %o=%o (Map Blk 31)\n", PC-1, dstAC, AC[dstAC]); - Map31 = AC[dstAC] & PAGEMASK; - MapStat &= ~02000; -//AOS } else { -//AOS if ((Debug_Flags & 077) == 03) -//AOS fprintf(Trace, "%o DOB %o=%o (Map Blk 31) NO EXEC (User Mode)\n", PC-1, dstAC, AC[dstAC]); -//AOS } - break; - case ioDIC: /* Page Check */ - if (!Usermap || !(MapStat & 0140)) { - switch ((Check>>7) & 07) { - case 0: i=1; break; - case 1: i=6; break; - case 2: i=2; break; - case 3: i=7; break; - case 4: i=0; break; - case 5: i=4; break; - case 6: i=3; break; - case 7: i=5; break; - default: break; - } - j = (Check >> 10) & 037; - AC[dstAC] = Map[i][j] & 0101777; - AC[dstAC] |= ((Check << 5) & 070000); - if ((Debug_Flags & 077) == 03) - fprintf(Trace, "%o DIC %o=%o (Page Check)\n", PC-1, dstAC, AC[dstAC]); - MapStat &= ~02000; - } else { - if ((Debug_Flags & 077) == 03) - fprintf(Trace, "%o DIC %o=%o (Page Check) NO EXEC(User mode)\n", PC-1, dstAC, AC[dstAC]); - } - break; - case ioDOC: /* Init Page Check */ - if (!Usermap || !(MapStat & 0140)) { - if ((Debug_Flags & 077) == 03) - fprintf(Trace, "%o DOC %o=%o (Init Pg Chk)\n", PC-1, dstAC, AC[dstAC]); - Check = AC[dstAC]; - MapStat &= ~01600; - MapStat |= (Check & 01600); - MapStat &= ~02000; - } else { - if ((Debug_Flags & 077) == 03) - fprintf(Trace, "%o DOC %o=%o (Init Pg Chk) NO EXEC(User mode)\n", PC-1, dstAC, AC[dstAC]); - } - break; - } /* end switch code */ - - switch (pulse) { - case iopP: - if ((Debug_Flags & 077) == 03) - fprintf(Trace, "%o xxxP (Single Cycle)\n", PC-1); - if (Usermap) { - MapStat &= 0177776; - Usermap = 0; - Inhibit = 0; - } else { - SingleCycle = Enable; - Inhibit = 1; /* Inhibit interrupts */ - } - break; - } - } /* end CPU control */ - else if (dev_table[device].routine) { /* normal device */ - iodata = dev_table[device].routine (pulse, code, AC[dstAC]); - reason = iodata >> IOT_V_REASON; - if (code & 1) AC[dstAC] = iodata & 0177777; - if ((Debug_Flags & 077) == device && Debug_Flags != 0) { - strcpy(pulcode, ""); - switch (pulse) { - case iopP: - strcpy(pulcode, "P"); - break; - case iopS: - strcpy(pulcode, "S"); - break; - case iopC: - strcpy(pulcode, "C"); - break; - default: - break; - } - switch(code) { - case ioNIO: - fprintf(Trace, "[%o] %o NIO%s %o\n", device, PC-1, pulcode, AC[dstAC]); - break; - case ioDIA: - fprintf(Trace, "[%o] %o DIA%s %o\n", device, PC-1, pulcode, iodata); - break; - case ioDIB: - fprintf(Trace, "[%o] %o DIB%s %o\n", device, PC-1, pulcode, iodata); - break; - case ioDIC: - fprintf(Trace, "[%o] %o DIC%s %o\n", device, PC-1, pulcode, iodata); - break; - case ioDOA: - fprintf(Trace, "[%o] %o DOA%s %o\n", device, PC-1, pulcode, AC[dstAC]); - break; - case ioDOB: - fprintf(Trace, "[%o] %o DOB%s %o\n", device, PC-1, pulcode, AC[dstAC]); - break; - case ioDOC: - fprintf(Trace, "[%o] %o DOC%s %o\n", device, PC-1, pulcode, AC[dstAC]); - break; - default: - break; - } /* end switch */ - } /* end if debug */ - } /* end else if */ - else reason = stop_dev; -} /* end if IOT */ -} /* end while */ - -/* Simulation halted */ - -saved_PC = PC; -return reason; -} - -/* Computes and returns a 16-bit effective address, given a - program counter, index, and a displacement. -*/ - -int32 effective(int32 PC, int32 index, int32 disp) -{ - register int32 i, MA; - - MA = disp & 077777; - switch (index) { /* decode IR<6:7> */ - case 0: /* page zero */ - break; - case 1: /* PC relative */ - MA = (MA + PC) & AMASK; - break; - case 2: /* AC2 relative */ - MA = (MA + AC[2]) & AMASK; - break; - case 3: /* AC3 relative */ - MA = (MA + AC[3]) & AMASK; - break; - } /* end switch mode */ - - if (disp & 0100000) { /* indirect? */ - for (i = 0; i < ind_max * 2; i++) { /* count indirects */ - MA = GetMap(MA & AMASK); - if (SingleCycle) Usermap = 0; - if (MapStat & 1) { /* Start MAP */ - Usermap = Enable; - Inhibit = 0; - } - if ((MA & 0100000) == 0) break; - if ((MapStat & 010) && Usermap && i >= ind_max) break; - } - if (i >= (ind_max-1) && (MapStat & 010) && Usermap) { - Fault = 04000; /* Map fault if IND prot */ - } - if (i >= (ind_max * 2) && !(Fault)) { - reason = STOP_IND_INT; /* Stop machine */ - } - } - return (MA & AMASK); -} - -/* Computes and returns a 16-bit effective address, given a - program counter, index, and a displacement. This is a - version supporting the LEF map mode instruction, as - opposed to the ELEF instruction. -*/ - -int32 LEFmode(int32 PC, int32 index, int32 disp, int32 indirect) -{ - register int32 i, MA; - int16 sMA; - - MA = disp & 077777; - switch (index) { /* decode IR<6:7> */ - case 0: /* page zero */ - break; - case 1: /* PC relative */ - sMA = MA; - if (MA & 0200) sMA |= 0xff00; - MA = (sMA + PC) & AMASK; - break; - case 2: /* AC2 relative */ - sMA = MA; - if (MA & 0200) sMA |= 0xff00; - MA = (sMA + AC[2]) & AMASK; - break; - case 3: /* AC3 relative */ - sMA = MA; - if (MA & 0200) sMA |= 0xff00; - MA = (sMA + AC[3]) & AMASK; - break; - } /* end switch mode */ - - if (indirect) { /* indirect? */ - for (i = 0; i < (ind_max * 2); i++) { /* count indirects */ - if ((MA & 077770) == 020 && !(cpu_unit.flags & UNIT_MICRO)) - MA = (PutMap(MA & AMASK, (GetMap(MA & AMASK) + 1) & 0177777)); - else if ((MA & 077770) == 030 && !(cpu_unit.flags & UNIT_MICRO)) - MA = (PutMap(MA & AMASK, (GetMap(MA & AMASK) - 1) & 0177777)); - else MA = GetMap(MA & AMASK); - if (SingleCycle) Usermap = 0; - if (MapStat & 1) { /* Start MAP */ - Usermap = Enable; - Inhibit = 0; - } - if ((MA & 0100000) == 0) break; - if ((MapStat & 010) && Usermap && i >= ind_max) break; - } - if (i >= (ind_max-1) && (MapStat & 010) && Usermap) { - Fault = 04000; /* Map fault if IND prot */ - } - if (i >= (ind_max * 2) && !(Fault)) { - reason = STOP_IND_INT; /* Stop machine */ - } - } - return (MA & AMASK); -} - -/* Computes a "Byte pointer" for the Character Instruction set */ -/* This address in 'PC' must point to the displacement word of the instruction */ - -int32 Bytepointer(int32 PC, int32 index) -{ - register int32 MA; - - switch (index) { /* decode IR<6:7> */ - case 0: /* page zero */ - MA = 0; - break; - case 1: /* PC relative */ - MA = PC & AMASK; - break; - case 2: /* AC2 relative */ - MA = AC[2] & AMASK; - break; - case 3: /* AC3 relative */ - MA = AC[3] & AMASK; - break; - } /* end switch mode */ - MA = (MA * 2) & 0177777; - MA = MA + GetMap(PC); - return (MA & 0177777); -} - -/* Given an address, returns either that address if bit 0 is 0, or - or follows an indirection chain until bit 0 is 0 -*/ - -int32 indirect(int32 d) -{ - int i; - - if (d & 0100000) { /* indirect? */ - for (i = 0; i < ind_max * 2; i++) { /* count indirects */ - if ((d & 077770) == 020 && !(cpu_unit.flags & UNIT_MICRO)) - d = (PutMap(d & AMASK, ((GetMap(d & AMASK) + 1) & 0177777))); - else if ((d & 077770) == 030 && !(cpu_unit.flags & UNIT_MICRO)) - d = (PutMap(d & AMASK, ((GetMap(d & AMASK) - 1) & 0177777))); - else d = GetMap(d & AMASK); - if (MapStat & 1) { /* Start MAP */ - Usermap = Enable; - Inhibit = 0; - } - if ((d & 0100000) == 0) break; - if ((MapStat & 010) && Usermap && i >= ind_max) break; - } - if (i >= (ind_max-1) && (MapStat & 010) && Usermap) { - Fault = 04000; /* Map fault if IND prot */ - } - if (i >= (ind_max * 2) && !(Fault)) { - reason = STOP_IND; /* Stop machine */ - } - } - return (d); -} - -/* Push a standard return block onto the stack */ - -int32 pushrtn(int32 pc) -{ - int32 t; - - t = (GetMap(040) + 1) & AMASK; - PutMap(t, AC[0]); - t++; - PutMap(t, AC[1]); - t++; - PutMap(t, AC[2]); - t++; - PutMap(t, AC[3]); - t++; - PutMap(t, pc); - if (C) PutMap(t, (GetMap(t) | 0100000)); - PutMap(040, t); - return 0; -} - -/* Eclipse memory get/put - uses MAP if enabled */ - -int32 GetMap(int32 addr) -{ - int32 page; - t_addr paddr; - - switch (Usermap) { - case 0: - if (addr < 076000) - return M[addr]; - paddr = ((Map31 & PAGEMASK) << 10) | (addr & 001777); - if (paddr < MEMSIZE) - return M[paddr]; - else - return (0); - break; - case 1: - page = (addr >> 10) & 037; - paddr = ((Map[1][page] & 01777) << 10) | (addr & 001777); - if (Map[1][page] == INVALID && !SingleCycle) - Fault = 0100000/*!!!*/; /* Validity */ - if (paddr < MEMSIZE) - return M[paddr]; - else - return (0); - break; - case 2: - page = (addr >> 10) & 037; - paddr = ((Map[2][page] & PAGEMASK) << 10) | (addr & 001777); - if (Map[2][page] == INVALID && !SingleCycle) - Fault = 0100000/*!!!*/; /* Validity */ - if (paddr < MEMSIZE) - return M[paddr]; - else - return (0); - break; - case 6: - page = (addr >> 10) & 037; - paddr = ((Map[6][page] & PAGEMASK) << 10) | (addr & 001777); - if (Map[6][page] == INVALID && !SingleCycle) - Fault = 0100000/*!!!*/; /* Validity */ - if (paddr < MEMSIZE) - return M[paddr]; - else - return (0); - break; - case 7: - page = (addr >> 10) & 037; - paddr = ((Map[7][page] & PAGEMASK) << 10) | (addr & 001777); - if (Map[7][page] == INVALID && !SingleCycle) - Fault = 0100000/*!!!*/; /* Validity */ - if (paddr < MEMSIZE) - return M[paddr]; - else - return (0); - break; - default: - printf("\n\r<>\n\r"); - return M[addr]; - break; - } -} - -int32 PutMap(int32 addr, int32 data) -{ - int32 page; - t_addr paddr; - - switch (Usermap) { - case 0: - if (addr < 076000) { - M[addr] = data; - return (data); - } - paddr = ((Map31 & PAGEMASK) << 10) | (addr & 001777); - if (paddr < MEMSIZE) M[paddr] = data; - break; - case 1: - page = (addr >> 10) & 037; - paddr = ((Map[1][page] & PAGEMASK) << 10) | (addr & 001777); - if (((Map[1][page] & 0100000) && (MapStat & 020)) || Map[1][page] == INVALID) - Fault = 010000; /* Write Protect Fault */ - else if (paddr < MEMSIZE) M[paddr] = data; - break; - case 2: - page = (addr >> 10) & 037; - paddr = ((Map[2][page] & PAGEMASK) << 10) | (addr & 001777); - if (((Map[2][page] & 0100000) && (MapStat & 020)) || Map[2][page] == INVALID) - Fault = 010000; /* Write Protect Fault */ - else if (paddr < MEMSIZE) M[paddr] = data; - break; - case 6: - page = (addr >> 10) & 037; - paddr = ((Map[2][page] & PAGEMASK) << 10) | (addr & 001777); - if (((Map[6][page] & 0100000) && (MapStat & 020)) || Map[6][page] == INVALID) - Fault = 010000; /* Write Protect Fault */ - else if (paddr < MEMSIZE) M[paddr] = data; - break; - case 7: - page = (addr >> 10) & 037; - paddr = ((Map[2][page] & PAGEMASK) << 10) | (addr & 001777); - if (((Map[7][page] & 0100000) && (MapStat & 020)) || Map[7][page] == INVALID) - Fault = 010000; /* Write Protect Fault */ - else if (paddr < MEMSIZE) M[paddr] = data; - break; - default: - M[addr] = data; - break; - } - return (data); -} - -#if 0 -int16 GetDCHMap(int32 map, int32 addr) -{ - t_addr paddr; - if (!(MapStat & 02)) return M[addr]; - paddr = ((Map[map][(addr >> 10) & 037] & PAGEMASK) << 10) | (addr & 001777); - if (paddr < MEMSIZE) - return M[paddr]; - return (0); -} - -int16 PutDCHMap(int32 map, int32 addr, int16 data) -{ - t_addr paddr; - if (!(MapStat & 02)) { - M[addr] = data; - return (data); - } - paddr = ((Map[map][(addr >> 10) & 037] & PAGEMASK) << 10) | (addr & 001777); - if (paddr < MEMSIZE) - M[paddr] = data; - return (data); -} -#endif - -/* Given a map number and a logical, returns the physical address, unless - the map is not active, in which case logical = physical. This is - used primarily by the I/O routines to map data channel read/writes. -*/ - -int32 MapAddr(int32 map, int32 addr) -{ - int32 paddr; - if ((map == 0 || map > 2) && !(MapStat & 02)) return addr; - if (map > 0 && map < 3 && Usermap == 0) return addr; - paddr = ((Map[map][(addr >> 10) & 037] & PAGEMASK) << 10) | (addr & 001777); - return paddr; -} - -/* Loads a word into the Eclipse Maps */ - -int32 LoadMap(int32 w) -{ - int32 m; - - m = (w >> 10) & 037; - switch ((MapStat >> 7) & 07) { - case 0: /* Load user A Map */ - Map[1][m] = w & MAPMASK; - break; - case 1: /* Load user C Map */ - Map[6][m] = w & MAPMASK; - break; - case 2: /* Load user B Map */ - Map[2][m] = w & MAPMASK; - break; - case 3: /* Load user D Map */ - Map[7][m] = w & MAPMASK; - break; - case 4: /* Load DCH A Map */ - Map[0][m] = w & MAPMASK; - break; - case 5: /* Load DCH C Map */ - Map[4][m] = w; - break; - case 6: /* Load DCH B Map */ - Map[3][m] = w; - break; - case 7: /* Load DCH D Map */ - Map[5][m] = w; - break; - default: - break; - } - return 0; -} - -/* Displays an error on a unimplemented (in this sim) instr. */ - -int32 unimp(int32 PC) -{ - if (Debug_Flags) - printf("\n\r\007<<>>\n\r", PC - 1, GetMap(PC - 1)); - return 0; -} - -/* New priority mask out */ - -void mask_out (int32 newmask) -{ -int32 i; - -dev_disable = 0; -for (i = DEV_LOW; i <= DEV_HIGH; i++) { - if (newmask & dev_table[i].pi) - dev_disable = dev_disable | dev_table[i].mask; -} -int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); -return; -} - -/* Reset routine */ - -t_stat cpu_reset (DEVICE *dptr) -{ -int_req = int_req & ~INT_ION; -pimask = 0; -dev_disable = 0; -pwr_low = 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 (sw & SWMASK ('V')) { - if (addr > 077777) return SCPE_NXM; - if (vptr != NULL) *vptr = GetMap (addr); -} -else { - if (addr >= MEMSIZE) return SCPE_NXM; - if (vptr != NULL) *vptr = M[addr] & 0177777; -} -return SCPE_OK; -} - -/* Memory deposit */ - -t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) -{ -if (sw & SWMASK ('V')) { - if (addr > 077777) return SCPE_NXM; - PutMap (addr, (int32) val); -} -else { - if (addr >= MEMSIZE) return SCPE_NXM; - M[addr] = (int32) val & 0177777; -} -return SCPE_OK; -} - -/* Alter memory size */ - -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; -} - -/* MAP device services */ - -t_stat map_svc (UNIT *uptr) -{ -return SCPE_OK; -} - -/* Map examine */ - -t_stat map_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) -{ -if ((addr & 077) >= 037 || addr > 737) return SCPE_NXM; -uptr->u4 = -2; /* signal to print_sys in eclipse_sys.c: do not map */ -if (vptr != NULL) *vptr = Map[(addr >> 6) & 3][addr & 037] & 0177777; -return SCPE_OK; -} - -/* Memory deposit */ - -t_stat map_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) -{ -if ((addr & 077) >= 037 || addr > 0737) return SCPE_NXM; -uptr->u4 = -2; /* signal to print_sys in eclipse_sys.c: do not map */ -Map[(addr >> 6) & 3][addr & 037] = (int32)val & 0177777; -return SCPE_OK; -} - -/* FPU device services */ - -t_stat fpu_svc (UNIT *uptr) -{ -return SCPE_OK; -} - -/* PIT Device Services */ - -/* IOT routine */ - -int32 pit (int32 pulse, int32 code, int32 AC) -{ -int32 iodata = 0; - -if (code == ioDIA) { /* DIA */ - if (pit_flag == 0) { - pit_flag = 1; - } - iodata = pit_counter; -} -if (code == ioDOA) { /* DOA */ - pit_initial = AC; /* Load Counter */ - sim_rtcn_init (pit_time, 1); /* init calibr */ -} -switch (pulse) { /* decode IR<8:9> */ -case iopS: /* start */ - pit_counter = pit_initial; /* Set the counter */ - dev_busy = dev_busy | INT_PIT; /* set busy */ - dev_done = dev_done & ~INT_PIT; /* clear done, int */ - int_req = int_req & ~INT_PIT; - if (!sim_is_active (&pit_unit)) /* not running? */ - sim_activate (&pit_unit, /* activate */ - sim_rtcn_init (pit_time, 1)); /* init calibr */ - break; -case iopC: /* clear */ - dev_busy = dev_busy & ~INT_PIT; /* clear busy */ - dev_done = dev_done & ~INT_PIT; /* clear done, int */ - int_req = int_req & ~INT_PIT; - sim_cancel (&pit_unit); /* deactivate unit */ - break; } /* end switch */ -return iodata; -} - -/* Unit service */ - -t_stat pit_svc (UNIT *uptr) -{ -int32 t; -t = sim_rtcn_calb (pit_tps, 1); /* calibrate delay */ -sim_activate (&pit_unit, t); /* reactivate unit */ -pit_poll = t / (-pit_adj); /* adjust poll */ -pit_counter++; /* Increment counter */ -if (pit_counter >= 0177777) { /* Has counter reached limit ? */ - dev_done = dev_done | INT_PIT; /* set done */ - dev_busy = dev_busy & ~INT_PIT; /* clear busy */ - int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); /* Interrupt */ - pit_counter = pit_initial; -} -return SCPE_OK; -} - -/* Reset routine */ - -t_stat pit_reset (DEVICE *dptr) -{ -pit_counter = 0; /* clear counter */ -dev_busy = dev_busy & ~INT_PIT; /* clear busy */ -dev_done = dev_done & ~INT_PIT; /* clear done, int */ -int_req = int_req & ~INT_PIT; -sim_cancel (&pit_unit); /* deactivate unit */ -pit_poll = pit_time; /* poll is default */ -return SCPE_OK; -} - -/* Bootstrap routine for CPU */ - -#define BOOT_START 00000 -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int)) - -static const int32 boot_rom[] = { - - 062677, /* IORST ;Reset all I/O */ - 060477, /* READS 0 ;Read SR into AC0 */ - 024026, /* LDA 1,C77 ;Get dev mask */ - 0107400, /* AND 0,1 ;Isolate dev code */ - 0124000, /* COM 1,1 ;- device code - 1 */ - 010014, /* LOOP: ISZ OP1 ;Device code to all */ - 010030, /* ISZ OP2 ;I/O instructions */ - 010032, /* ISZ OP3 */ - 0125404, /* INC 1,1,SZR ;done? */ - 000005, /* JMP LOOP ;No, increment again */ - 030016, /* LDA 2,C377 ;place JMP 377 into */ - 050377, /* STA 2,377 ;location 377 */ - 060077, /* OP1: 060077 ;start device (NIOS 0) */ - 0101102, /* MOVL 0,0,SZC ;Test switch 0, low speed? */ - 000377, /* C377: JMP 377 ;no - jmp 377 & wait */ - 004030, /* LOOP2: JSR GET+1 ;Get a frame */ - 0101065, /* MOVC 0,0,SNR ;is it non-zero? */ - 000017, /* JMP LOOP2 ;no, ignore */ - 004027, /* LOOP4: JSR GET ;yes, get full word */ - 046026, /* STA 1,@C77 ;store starting at 100 */ - /* ;2's complement of word ct */ - 010100, /* ISZ 100 ;done? */ - 000022, /* JMP LOOP4 ;no, get another */ - 000077, /* C77: JMP 77 ;yes location ctr and */ - /* ;jmp to last word */ - 0126420, /* GET: SUBZ 1,1 ; clr AC1, set carry */ - /* OP2: */ - 063577, /* LOOP3: 063577 ;done? (SKPDN 0) - 1 */ - 000030, /* JMP LOOP3 ;no -- wait */ - 060477, /* OP3: 060477 ;y--read in ac0 (DIAS 0,0) */ - 0107363, /* ADDCS 0,1,SNC ;add 2 frames swapped - got 2nd? */ - 000030, /* JMP LOOP3 ;no go back after it */ - 0125300, /* MOVS 1,1 ;yes swap them */ - 001400, /* JMP 0,3 ;rtn with full word */ - 0 /* 0 ;padding */ -}; - -t_stat cpu_boot (int32 unitno, DEVICE *dptr) -{ -size_t i; -extern int32 saved_PC; - -for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i]; -saved_PC = BOOT_START; -return SCPE_OK; -} - -int32 Debug_Entry(int32 PC, int32 inst, int32 inst2, int32 AC0, int32 AC1, int32 AC2, int32 AC3, int32 flags) -{ - hpc[hnext] = PC & 0xffff; - hinst[hnext] = inst & 0xffff; - hinst2[hnext] = inst2 & 0xffff; - hac0[hnext] = AC0 & 0xffff; - hac1[hnext] = AC1 & 0xffff; - hac2[hnext] = AC2 & 0xffff; - hac3[hnext] = AC3 & 0xffff; - hflags[hnext] = flags & 0xffff; - hnext++; - if (hnext >= hmax) { - hwrap = 1; - hnext = 0; - } - return 0; -} - -t_stat Debug_Dump(UNIT *uptr, int32 val, char *cptr, void *desc) -{ - return SCPE_OK; -} - -t_stat Dump_History (FILE *st, UNIT *uptr, int32 val, void *desc) -{ - char debmap[4], debion[4]; - t_value simeval[20]; - int debcar; - int start, end, ctr; - int count = 0; - - if (!Debug_Flags || Debug_Flags & 0100000) { - printf("History was not logged. Deposit a non-zero value\n"); - printf("in DEBUG with bit 0 being 1 to build history.\n"); - return SCPE_OK; - } - if (!hwrap) { - start = 0; - end = hnext; - } else { - start = hnext; - end = hnext - 1; - if (end < 0) end = hmax; - } - ctr = start; - while (1) { - if (ctr == end) - break; - count++; - strcpy(debion, " "); - strcpy(debmap, " "); - debcar = 0; - if (hflags[ctr] & 0x80) { - fprintf(st, "--------- Interrupt %o (%o) to %6o ---------\n", - hinst[ctr], hac0[ctr], hac1[ctr]); - } else { - if (hflags[ctr] & 0x01) debcar = 1; - if (hflags[ctr] & 0x02) strcpy(debion, "I"); - if (hflags[ctr] & 0x04) strcpy(debmap, "A"); - if (hflags[ctr] & 0x08) strcpy(debmap, "B"); - if (hflags[ctr] & 0x10) strcpy(debmap, "C"); - if (hflags[ctr] & 0x20) strcpy(debmap, "D"); - fprintf(st, "%s%s%06o acs: %06o %06o %06o %06o %01o ", - debion, debmap, hpc[ctr], hac0[ctr], hac1[ctr], hac2[ctr], - hac3[ctr], debcar); - simeval[0] = hinst[ctr]; - simeval[1] = hinst2[ctr]; - fprint_sym (st, hpc[ctr], simeval, NULL, SWMASK('M')); - fprintf(st, "\n"); - } - ctr++; - if (ctr > hmax) - ctr = 0; - } - return SCPE_OK; -} - -/* Build dispatch table */ - -t_stat build_devtab (void) -{ -DEVICE *dptr; -DIB *dibp; -int32 i, dn; - -for (i = 0; i < 64; i++) { /* clr dev_table */ - dev_table[i].mask = 0; - dev_table[i].pi = 0; - dev_table[i].routine = NULL; -} -for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ - if (!(dptr->flags & DEV_DIS) && /* enabled and */ - (dibp = (DIB *) dptr->ctxt)) { /* defined DIB? */ - dn = dibp->dnum; /* get dev num */ - dev_table[dn].mask = dibp->mask; /* copy entries */ - dev_table[dn].pi = dibp->pi; - dev_table[dn].routine = dibp->routine; - } -} -return SCPE_OK; -} - -/* ------------------------------------------------------------------- */ -/* Floating Point Arithmetic */ -/* ------------------------------------------------------------------- */ - - -/* Get short float from FPAC */ - -void get_sf (SHORT_FLOAT *fl, t_int64 *fpr) -{ - fl->sign = (uint8)(*fpr >> 63) & 1; - fl->expo = (short)(*fpr >> 56) & 0x007F; - fl->short_fract = (int32)(*fpr >> 32) & 0x00FFFFFF; -} - -/* Store short float to FPAC */ - -void store_sf (SHORT_FLOAT *fl, t_int64 *fpr) -{ - *fpr = 0; - *fpr = ((t_int64)fl->sign << 63) - | ((t_int64)fl->expo << 56) - | ((t_int64)fl->short_fract <<32); -} - -/* Get long float from FPAC */ - -void get_lf (LONG_FLOAT *fl, t_int64 *fpr) -{ - fl->sign = (uint8)(*fpr >> 63) & 1; - fl->expo = (short)(*fpr >> 56) & 0x007F; - fl->long_fract = (t_int64)*fpr & 0x00FFFFFFFFFFFFFF; - -} - -/* Store long float to FPAC */ - -void store_lf (LONG_FLOAT *fl, t_int64 *fpr) -{ - *fpr = 0; - *fpr = (t_int64)fl->sign << 63; - *fpr |= ((t_int64)fl->expo << 56) & 0x7f00000000000000; - *fpr |= fl->long_fract; -} - - -/* Check short for Overflow */ - -int overflow_sf (SHORT_FLOAT *fl) -{ - if (fl->expo > 127) { - fl->expo &= 0x007F; - return(1); - } - return(0); - -} - -/* Normalize Short Float */ - -int normal_sf(SHORT_FLOAT *fl) -{ - if (fl->short_fract) { - if ((fl->short_fract & 0x00FFFF00) == 0) { - fl->short_fract <<= 16; - fl->expo -= 4; - } - if ((fl->short_fract & 0x00FF0000) == 0) { - fl->short_fract <<= 8; - fl->expo -= 2; - } - if ((fl->short_fract & 0x00F00000) == 0) { - fl->short_fract <<= 4; - (fl->expo)--; - } - } else { - fl->sign = 0; - fl->expo = 0; - } - if (fl->expo < 0) - return (2); - return(0); -} - -/* Normalize long float */ - -int normal_lf (LONG_FLOAT *fl) -{ - if (fl->long_fract) { - if ((fl->long_fract & 0x00FFFFFFFF000000) == 0) { - fl->long_fract <<= 32; - fl->expo -= 8; - } - if ((fl->long_fract & 0x00FFFF0000000000) == 0) { - fl->long_fract <<= 16; - fl->expo -= 4; - } - if ((fl->long_fract & 0x00FF000000000000) == 0) { - fl->long_fract <<= 8; - fl->expo -= 2; - } - if ((fl->long_fract & 0x00F0000000000000) == 0) { - fl->long_fract <<= 4; - (fl->expo)--; - } - } else { - fl->sign = 0; - fl->expo = 0; - } - if (fl->expo < 0) - return (2); - return(0); -} - -/* Check Long for Overflow */ - -int overflow_lf(LONG_FLOAT *fl) -{ - if (fl->expo > 127) { - fl->expo &= 0x007F; - return(1); - } - return(0); - -} - -int underflow_sf(SHORT_FLOAT *fl) -{ - if (fl->expo < 0) { - fl->short_fract = 0; - fl->expo = 0; - fl->sign = 0; - } - return(0); - -} - - -int underflow_lf(LONG_FLOAT *fl) -{ - if (fl->expo < 0) { - fl->long_fract = 0; - fl->expo = 0; - fl->sign = 0; - } - return(0); -} - -/* Check Short for Over/Under flow */ - -int over_under_flow_sf(SHORT_FLOAT *fl) -{ - if (fl->expo > 127) { - fl->expo &= 0x007F; - return(1); - } else { - if (fl->expo < 0) { - /* set true 0 */ - fl->short_fract = 0; - fl->expo = 0; - fl->sign = 0; - } - } - return(0); - -} - -/* Check Long for Over/Under flow */ - -int over_under_flow_lf(LONG_FLOAT *fl) -{ - if (fl->expo > 127) { - fl->expo &= 0x007F; - return(1); - } else { - if (fl->expo < 0) { - /* set true 0 */ - fl->long_fract = 0; - fl->expo = 0; - fl->sign = 0; - } - } - return(0); - -} - -int significance_sf (SHORT_FLOAT *fl) -{ - fl->sign = 0; - fl->expo = 0; - return(0); - -} - -int significance_lf (LONG_FLOAT *fl) -{ - fl->sign = 0; - fl->expo = 0; - return(0); - -} - - -/*-------------------------------------------------------------------*/ -/* Add short float */ -/* */ -/* Input: */ -/* fl Float */ -/* add_fl Float to be added */ -/* normal Normalize if true */ -/* Value: */ -/* exeption */ -/*-------------------------------------------------------------------*/ -int add_sf (SHORT_FLOAT *fl, SHORT_FLOAT *add_fl, int normal) -{ -int pgm_check; -int shift; - - pgm_check = 0; - if (add_fl->short_fract - || add_fl->expo) { /* add_fl not 0 */ - if (fl->short_fract - || fl->expo) { /* fl not 0 */ - /* both not 0 */ - - if (fl->expo == add_fl->expo) { - /* expo equal */ - - /* both guard digits */ - fl->short_fract <<= 4; - add_fl->short_fract <<= 4; - } else { - /* expo not equal, denormalize */ - - if (fl->expo < add_fl->expo) { - /* shift minus guard digit */ - shift = add_fl->expo - fl->expo - 1; - fl->expo = add_fl->expo; - - if (shift) { - if (shift >= 6 - || ((fl->short_fract >>= (shift * 4)) == 0)) { - /* 0, copy summand */ - - fl->sign = add_fl->sign; - fl->short_fract = add_fl->short_fract; - - if (fl->short_fract == 0) { - pgm_check = significance_sf(fl); - } else { - if (normal) { - normal_sf(fl); - pgm_check = underflow_sf(fl); - } - } - return(pgm_check); - } - } - /* guard digit */ - add_fl->short_fract <<= 4; - } else { - /* shift minus guard digit */ - shift = fl->expo - add_fl->expo - 1; - - if (shift) { - if (shift >= 6 - || ((add_fl->short_fract >>= (shift * 4)) == 0)) { - /* 0, nothing to add */ - - if (fl->short_fract == 0) { - pgm_check = significance_sf(fl); - } else { - if (normal) { - normal_sf(fl); - pgm_check = underflow_sf(fl); - } - } - return(pgm_check); - } - } - /* guard digit */ - fl->short_fract <<= 4; - } - } - - /* compute with guard digit */ - if (fl->sign == add_fl->sign) { - fl->short_fract += add_fl->short_fract; - } else { - if (fl->short_fract == add_fl->short_fract) { - /* true 0 */ - - fl->short_fract = 0; - return( significance_sf(fl) ); - - } else if (fl->short_fract > add_fl->short_fract) { - fl->short_fract -= add_fl->short_fract; - } else { - fl->short_fract = add_fl->short_fract - fl->short_fract; - fl->sign = add_fl->sign; - } - } - - /* handle overflow with guard digit */ - if (fl->short_fract & 0xF0000000) { - fl->short_fract >>= 8; - (fl->expo)++; - pgm_check = overflow_sf(fl); - } else { - - if (normal) { - /* normalize with guard digit */ - if (fl->short_fract) { - /* not 0 */ - - if (fl->short_fract & 0x0F000000) { - /* not normalize, just guard digit */ - fl->short_fract >>= 4; - } else { - (fl->expo)--; - normal_sf(fl); - pgm_check = underflow_sf(fl); - } - } else { - /* true 0 */ - - pgm_check = significance_sf(fl); - } - } else { - /* not normalize, just guard digit */ - fl->short_fract >>= 4; - if (fl->short_fract == 0) { - pgm_check = significance_sf(fl); - } - } - } - return(pgm_check); - } else { /* fl 0, add_fl not 0 */ - /* copy summand */ - - fl->expo = add_fl->expo; - fl->sign = add_fl->sign; - fl->short_fract = add_fl->short_fract; - if (fl->short_fract == 0) { - return( significance_sf(fl) ); - } - } - } else { /* add_fl 0 */ - if (fl->short_fract == 0) { /* fl 0 */ - /* both 0 */ - - return( significance_sf(fl) ); - } - } - if (normal) { - normal_sf(fl); - pgm_check = underflow_sf(fl); - } - return(pgm_check); - -} - - -/*-------------------------------------------------------------------*/ -/* Add long float */ -/* */ -/* Input: */ -/* fl Float */ -/* add_fl Float to be added */ -/* normal Normalize if true */ -/* Value: */ -/* exeption */ -/*-------------------------------------------------------------------*/ -int add_lf (LONG_FLOAT *fl, LONG_FLOAT *add_fl, int normal) -{ -int pgm_check; -int shift; - - pgm_check = 0; - if (add_fl->long_fract - || add_fl->expo) { /* add_fl not 0 */ - if (fl->long_fract - || fl->expo) { /* fl not 0 */ - /* both not 0 */ - - if (fl->expo == add_fl->expo) { - /* expo equal */ - - /* both guard digits */ - fl->long_fract <<= 4; - add_fl->long_fract <<= 4; - } else { - /* expo not equal, denormalize */ - - if (fl->expo < add_fl->expo) { - /* shift minus guard digit */ - shift = add_fl->expo - fl->expo - 1; - fl->expo = add_fl->expo; - - if (shift) { - if (shift >= 14 - || ((fl->long_fract >>= (shift * 4)) == 0)) { - /* 0, copy summand */ - - fl->sign = add_fl->sign; - fl->long_fract = add_fl->long_fract; - - if (fl->long_fract == 0) { - pgm_check = significance_lf(fl); - } else { - if (normal) { - normal_lf(fl); - pgm_check = underflow_lf(fl); - } - } - return(pgm_check); - } - } - /* guard digit */ - add_fl->long_fract <<= 4; - } else { - /* shift minus guard digit */ - shift = fl->expo - add_fl->expo - 1; - - if (shift) { - if (shift >= 14 - || ((add_fl->long_fract >>= (shift * 4)) == 0)) { - /* 0, nothing to add */ - - if (fl->long_fract == 0) { - pgm_check = significance_lf(fl); - } else { - if (normal) { - normal_lf(fl); - pgm_check = underflow_lf(fl); - } - } - return(pgm_check); - } - } - /* guard digit */ - fl->long_fract <<= 4; - } - } - - /* compute with guard digit */ - if (fl->sign == add_fl->sign) { - fl->long_fract += add_fl->long_fract; - } else { - if (fl->long_fract == add_fl->long_fract) { - /* true 0 */ - - fl->long_fract = 0; - return( significance_lf(fl) ); - - } else if (fl->long_fract > add_fl->long_fract) { - fl->long_fract -= add_fl->long_fract; - } else { - fl->long_fract = add_fl->long_fract - fl->long_fract; - fl->sign = add_fl->sign; - } - } - - /* handle overflow with guard digit */ - if (fl->long_fract & 0xF000000000000000) { - fl->long_fract >>= 8; - (fl->expo)++; - pgm_check = overflow_lf(fl); - } else { - - if (normal) { - /* normalize with guard digit */ - if (fl->long_fract) { - /* not 0 */ - - if (fl->long_fract & 0x0F00000000000000) { - /* not normalize, just guard digit */ - fl->long_fract >>= 4; - } else { - (fl->expo)--; - normal_lf(fl); - pgm_check = underflow_lf(fl); - } - } else { - /* true 0 */ - - pgm_check = significance_lf(fl); - } - } else { - /* not normalize, just guard digit */ - fl->long_fract >>= 4; - if (fl->long_fract == 0) { - pgm_check = significance_lf(fl); - } - } - } - return(pgm_check); - } else { /* fl 0, add_fl not 0 */ - /* copy summand */ - - fl->expo = add_fl->expo; - fl->sign = add_fl->sign; - fl->long_fract = add_fl->long_fract; - if (fl->long_fract == 0) { - return( significance_lf(fl) ); - } - } - } else { /* add_fl 0 */ - if (fl->long_fract == 0) { /* fl 0 */ - /* both 0 */ - - return( significance_lf(fl) ); - } - } - if (normal) { - normal_lf(fl); - pgm_check = underflow_lf(fl); - } - return(pgm_check); - -} - -/*-------------------------------------------------------------------*/ -/* Multiply short float */ -/* */ -/* Input: */ -/* fl Multiplicand short float */ -/* mul_fl Multiplicator short float */ -/* Value: */ -/* exeption */ -/*-------------------------------------------------------------------*/ - -int mul_sf(SHORT_FLOAT *fl, SHORT_FLOAT *mul_fl) -{ -t_int64 wk; - - if (fl->short_fract - && mul_fl->short_fract) { - /* normalize operands */ - normal_sf( fl ); - normal_sf( mul_fl ); - - /* multiply fracts */ - wk = (t_int64) fl->short_fract * mul_fl->short_fract; - - /* normalize result and compute expo */ - if (wk & 0x0000F00000000000) { - fl->short_fract = (int32)wk >> 24; - fl->expo = (short)fl->expo + mul_fl->expo - 64; - } else { - fl->short_fract = (int32)wk >> 20; - fl->expo = (short)fl->expo + mul_fl->expo - 65; - } - - /* determine sign */ - fl->sign = (fl->sign == mul_fl->sign) ? 0 : 1; - - /* handle overflow and underflow */ - return( over_under_flow_sf(fl) ); - } else { - /* set true 0 */ - - fl->short_fract = 0; - fl->expo = 0; - fl->sign = 0; - return(0); - } - -} - - -/*-------------------------------------------------------------------*/ -/* Multiply long float */ -/* */ -/* Input: */ -/* fl Multiplicand long float */ -/* mul_fl Multiplicator long float */ -/* Value: */ -/* exeption */ -/*-------------------------------------------------------------------*/ -int mul_lf(LONG_FLOAT *fl, LONG_FLOAT *mul_fl) -{ -t_int64 wk; -int32 v; - - if (fl->long_fract - && mul_fl->long_fract) { - /* normalize operands */ - normal_lf( fl ); - normal_lf( mul_fl ); - - /* multiply fracts by sum of partial multiplications */ - wk = ((fl->long_fract & 0x00000000FFFFFFFF) * (mul_fl->long_fract & 0x00000000FFFFFFFF)) >> 32; - - wk += ((fl->long_fract & 0x00000000FFFFFFFF) * (mul_fl->long_fract >> 32)); - wk += ((fl->long_fract >> 32) * (mul_fl->long_fract & 0x00000000FFFFFFFF)); - v = (int32)wk; - - fl->long_fract = (wk >> 32) + ((fl->long_fract >> 32) * (mul_fl->long_fract >> 32)); - - /* normalize result and compute expo */ - if (fl->long_fract & 0x0000F00000000000) { - fl->long_fract = (fl->long_fract << 8) - | (v >> 24); - fl->expo = fl->expo + mul_fl->expo - 64; - } else { - fl->long_fract = (fl->long_fract << 12) - | (v >> 20); - fl->expo = fl->expo + mul_fl->expo - 65; - } - - /* determine sign */ - fl->sign = (fl->sign == mul_fl->sign) ? 0 : 1; - - /* handle overflow and underflow */ - return( over_under_flow_lf(fl) ); - } else { - /* set true 0 */ - - fl->long_fract = 0; - fl->expo = 0; - fl->sign = 0; - return(0); - } - -} - - -/*-------------------------------------------------------------------*/ -/* Divide short float */ -/* */ -/* Input: */ -/* fl Dividend short float */ -/* div_fl Divisor short float */ -/* Value: */ -/* exeption */ -/*-------------------------------------------------------------------*/ -int div_sf(SHORT_FLOAT *fl, SHORT_FLOAT *div_fl) -{ -t_int64 wk; - - if (div_fl->short_fract) { - if (fl->short_fract) { - /* normalize operands */ - normal_sf( fl ); - normal_sf( div_fl ); - - /* position fracts and compute expo */ - if (fl->short_fract < div_fl->short_fract) { - wk = (t_int64) fl->short_fract << 24; - fl->expo = fl->expo - div_fl->expo + 64; - } else { - wk = (t_int64) fl->short_fract << 20; - fl->expo = fl->expo - div_fl->expo + 65; - } - /* divide fractions */ - fl->short_fract = (int32)wk / div_fl->short_fract; - - /* determine sign */ - fl->sign = (fl->sign == div_fl->sign) ? 0 : 1; - - /* handle overflow and underflow */ - return( over_under_flow_sf(fl) ); - } else { - /* fraction of dividend 0, set true 0 */ - - fl->short_fract = 0; - fl->expo = 0; - fl->sign = 0; - } - } else { - /* divisor 0 */ - - return(3); - } - return(0); - -} - - -/*-------------------------------------------------------------------*/ -/* Divide long float */ -/* */ -/* Input: */ -/* fl Dividend long float */ -/* div_fl Divisor long float */ -/* Value: */ -/* exeption */ -/*-------------------------------------------------------------------*/ -int div_lf(LONG_FLOAT *fl, LONG_FLOAT *div_fl) -{ -t_int64 wk; -t_int64 wk2; -int i; - - if (div_fl->long_fract) { - if (fl->long_fract) { - /* normalize operands */ - normal_lf( fl ); - normal_lf( div_fl ); - - /* position fracts and compute expo */ - if (fl->long_fract < div_fl->long_fract) { - fl->expo = fl->expo - div_fl->expo + 64; - } else { - fl->expo = fl->expo - div_fl->expo + 65; - div_fl->long_fract <<= 4; - } - - /* partial divide first hex digit */ - wk2 = fl->long_fract / div_fl->long_fract; - wk = (fl->long_fract % div_fl->long_fract) << 4; - - /* partial divide middle hex digits */ - i = 13; - while (i--) { - wk2 = (wk2 << 4) - | (wk / div_fl->long_fract); - wk = (wk % div_fl->long_fract) << 4; - } - - /* partial divide last hex digit */ - fl->long_fract = (wk2 << 4) - | (wk / div_fl->long_fract); - - /* determine sign */ - fl->sign = (fl->sign == div_fl->sign) ? 0 : 1; - - /* handle overflow and underflow */ - return( over_under_flow_lf(fl) ); - } else { - /* fraction of dividend 0, set true 0 */ - - fl->long_fract = 0; - fl->expo = 0; - fl->sign = 0; - } - } else { - /* divisor 0 */ - - return(3); - } - return(0); - -} - diff --git a/NOVA/eclipse_tt.c b/NOVA/eclipse_tt.c deleted file mode 100644 index ab3489dd..00000000 --- a/NOVA/eclipse_tt.c +++ /dev/null @@ -1,428 +0,0 @@ -/* eclipse_tt.c: Eclipse console terminal simulator - - Copyright (c) 1998-2005, Charles E Owen - Portions copyright (c) 1993-2002, Robert M Supnik - Written by Charles Owen, used by gracious permission - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of the author shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the author. - - tti terminal input - tto terminal output - - 25-Apr-03 RMS Revised for extended file support - 03-Oct-02 RMS Added DIBs - 30-May-02 RMS Widened POS to 32b - 28-Jan-02 RMS Cleaned up compiler warnings -*/ - -#include "nova_defs.h" - -#define UNIT_V_DASHER (UNIT_V_UF + 0) /* Dasher mode */ -#define UNIT_DASHER (1 << UNIT_V_DASHER) - -extern int32 int_req, dev_busy, dev_done, dev_disable; - -int32 tti (int32 pulse, int32 code, int32 AC); -int32 tto (int32 pulse, int32 code, int32 AC); -t_stat tti_svc (UNIT *uptr); -t_stat tto_svc (UNIT *uptr); -t_stat tti_reset (DEVICE *dptr); -t_stat tto_reset (DEVICE *dptr); -t_stat ttx_setmod (UNIT *uptr, int32 value, char *cptr, void *desc); -void translate_in(); -int32 translate_out(int32 c); -int32 putseq(char *seq); - -/* TTI data structures - - tti_dev TTI device descriptor - tti_unit TTI unit descriptor - tti_reg TTI register list - ttx_mod TTI/TTO modifiers list -*/ - -DIB tti_dib = { DEV_TTI, INT_TTI, PI_TTI, &tti }; - -UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT }; - -REG tti_reg[] = { - { ORDATA (BUF, tti_unit.buf, 8) }, - { FLDATA (BUSY, dev_busy, INT_V_TTI) }, - { FLDATA (DONE, dev_done, INT_V_TTI) }, - { FLDATA (DISABLE, dev_disable, INT_V_TTI) }, - { FLDATA (INT, int_req, INT_V_TTI) }, - { DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, - { NULL } - }; - -MTAB ttx_mod[] = { - { UNIT_DASHER, 0, "ANSI", "ANSI", &ttx_setmod }, - { UNIT_DASHER, UNIT_DASHER, "Dasher", "DASHER", &ttx_setmod }, - { 0 } - }; - -DEVICE tti_dev = { - "TTI", &tti_unit, tti_reg, ttx_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &tti_reset, - NULL, NULL, NULL, - &tti_dib, 0 - }; - -/* TTO data structures - - tto_dev TTO device descriptor - tto_unit TTO unit descriptor - tto_reg TTO register list -*/ - -DIB tto_dib = { DEV_TTO, INT_TTO, PI_TTO, &tto }; - -UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT }; - -REG tto_reg[] = { - { ORDATA (BUF, tto_unit.buf, 8) }, - { FLDATA (BUSY, dev_busy, INT_V_TTO) }, - { FLDATA (DONE, dev_done, INT_V_TTO) }, - { FLDATA (DISABLE, dev_disable, INT_V_TTO) }, - { FLDATA (INT, int_req, INT_V_TTO) }, - { DRDATA (POS, tto_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT }, - { NULL } - }; - -DEVICE tto_dev = { - "TTO", &tto_unit, tto_reg, ttx_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &tto_reset, - NULL, NULL, NULL, - &tto_dib, 0 - }; - - - -/* Terminal input: IOT routine */ - -int32 tti (int32 pulse, int32 code, int32 AC) -{ -int32 iodata; - -iodata = (code == ioDIA)? tti_unit.buf & 0377: 0; -switch (pulse) { /* decode IR<8:9> */ - - case iopS: /* start */ - dev_busy = dev_busy | INT_TTI; /* set busy */ - dev_done = dev_done & ~INT_TTI; /* clear done, int */ - int_req = int_req & ~INT_TTI; - break; - - case iopC: /* clear */ - dev_busy = dev_busy & ~INT_TTI; /* clear busy */ - dev_done = dev_done & ~INT_TTI; /* clear done, int */ - int_req = int_req & ~INT_TTI; - break; - } /* end switch */ - -return iodata; -} - -/* Unit service */ - -t_stat tti_svc (UNIT *uptr) -{ -int32 temp; - -sim_activate (&tti_unit, tti_unit.wait); /* continue poll */ -if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) return temp; /* no char or error? */ -tti_unit.buf = temp & 0177; -/* --- BEGIN MODIFIED CODE --- */ -if (tti_unit.flags & UNIT_DASHER) /* translate input */ - translate_in(); -/* --- END MODIFIED CODE --- */ -dev_busy = dev_busy & ~INT_TTI; /* clear busy */ -dev_done = dev_done | INT_TTI; /* set done */ -int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); -tti_unit.pos = tti_unit.pos + 1; -return SCPE_OK; -} - -/* -------------------- BEGIN INSERTION -----------------------*/ - -int curpos = 0; /* used by translate_out() */ -int row = 0, col = 0; /* ditto - for cursor positioning */ -int spec200 = 0; /* signals next char is 'special' */ - -/* Translation: VT100 input to D200 keycodes. */ - -void translate_in() -{ - char rev = 0; - - if (tti_unit.buf == '\r') - rev = '\n'; - if (tti_unit.buf == '\n') - rev = '\r'; - if (rev) - tti_unit.buf = rev; -} - -/* -------------------- END INSERTION -----------------------*/ - -/* Reset routine */ - -t_stat tti_reset (DEVICE *dptr) -{ -tti_unit.buf = 0; -dev_busy = dev_busy & ~INT_TTI; /* clear busy */ -dev_done = dev_done & ~INT_TTI; /* clear done, int */ -int_req = int_req & ~INT_TTI; -sim_activate (&tti_unit, tti_unit.wait); /* activate unit */ -return SCPE_OK; -} - -/* Terminal output: IOT routine */ - -int32 tto (int32 pulse, int32 code, int32 AC) -{ -if (code == ioDOA) tto_unit.buf = AC & 0377; -switch (pulse) { /* decode IR<8:9> */ - - case iopS: /* start */ - dev_busy = dev_busy | INT_TTO; /* set busy */ - dev_done = dev_done & ~INT_TTO; /* clear done, int */ - int_req = int_req & ~INT_TTO; - sim_activate (&tto_unit, tto_unit.wait); /* activate unit */ - break; - - case iopC: /* clear */ - dev_busy = dev_busy & ~INT_TTO; /* clear busy */ - dev_done = dev_done & ~INT_TTO; /* clear done, int */ - int_req = int_req & ~INT_TTO; - sim_cancel (&tto_unit); /* deactivate unit */ - break; - } /* end switch */ - -return 0; -} - -/* Unit service */ - -t_stat tto_svc (UNIT *uptr) -{ -int32 c, temp; - -dev_busy = dev_busy & ~INT_TTO; /* clear busy */ -dev_done = dev_done | INT_TTO; /* set done */ -int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); -c = tto_unit.buf & 0177; -/* --- BEGIN MODIFIED CODE --- */ -if (tto_unit.flags & UNIT_DASHER) { - if ((temp = translate_out(c)) != SCPE_OK) return temp; -} else { - if ((temp = sim_putchar (c)) != SCPE_OK) return temp; - tto_unit.pos = tto_unit.pos + 1; -} -/* --- END MODIFIED CODE --- */ -return SCPE_OK; -} - -/* -------------------- BEGIN INSERTION -----------------------*/ - -/* Translation routine - D200 screen controls to VT-100 controls. */ - -int32 translate_out(int32 c) -{ - int32 temp; - char outstr[32]; - - if (spec200 == 1) { /* Special terminal control seq */ - spec200 = 0; - switch (c) { - case 'C': /* read model ID */ - return SCPE_OK; - case 'E': /* Reverse video off */ - return SCPE_OK; - case 'D': /* Reverse video on */ - return SCPE_OK; - default: - return SCPE_OK; - } - } - if (curpos == 1) { /* 2nd char of cursor position */ - col = c & 0x7f; - curpos++; - return (SCPE_OK); - } - if (curpos == 2) { /* 3rd char of cursor position */ - row = c & 0x7f; - curpos = 0; - sprintf(outstr, "\033[%d;%dH", row+1, col+1); - if ((temp = putseq(outstr)) != SCPE_OK) return temp; - return (SCPE_OK); - } - switch (c) { /* Single-char command or data */ - case 003: /* Blink enable */ - break; - case 004: /* Blink disable */ - break; - case 005: /* Read cursor address */ - break; - case 010: /* Cursor home */ - sprintf(outstr, "\033[1;1H"); - if ((temp = putseq(outstr)) != SCPE_OK) return temp; - row = col = 0; - return (SCPE_OK); - case 012: /* Newline */ - if ((temp = sim_putchar('\r')) != SCPE_OK) return temp; - tto_unit.pos += 1; - if ((temp = sim_putchar(c)) != SCPE_OK) return temp; - tto_unit.pos += 1; - col = 1; - row++; - if (row > 24) row = 1; - return (SCPE_OK); - case 013: /* Erase EOL */ - sprintf(outstr, "\033[K"); - if ((temp = putseq(outstr)) != SCPE_OK) return temp; - return (SCPE_OK); - case 014: /* Erase screen */ - sprintf(outstr, "\033[1;1H\033[2J"); - if ((temp = putseq(outstr)) != SCPE_OK) return temp; - row = col = 0; - return (SCPE_OK); - case 015: /* CR */ - if ((temp = sim_putchar(c)) != SCPE_OK) return temp; - tto_unit.pos += 1; - col = 1; - return (SCPE_OK); - case 016: /* Blink On */ - sprintf(outstr, "\033[5m"); - if ((temp = putseq(outstr)) != SCPE_OK) return temp; - return (SCPE_OK); - case 017: /* Blink off */ - sprintf(outstr, "\033[25m"); - if ((temp = putseq(outstr)) != SCPE_OK) return temp; - return (SCPE_OK); - case 020: /* Write cursor address */ - curpos = 1; - return SCPE_OK; - case 024: /* underscore on */ - sprintf(outstr, "\033[4m"); - if ((temp = putseq(outstr)) != SCPE_OK) return temp; - return (SCPE_OK); - case 025: /* underscore off */ - sprintf(outstr, "\033[24m"); - if ((temp = putseq(outstr)) != SCPE_OK) return temp; - return (SCPE_OK); - break; - case 027: /* cursor up */ - sprintf(outstr, "\033[A"); - if ((temp = putseq(outstr)) != SCPE_OK) return temp; - row--; - if (row < 1) row = 24; - return (SCPE_OK); - case 030: /* cursor right */ - sprintf(outstr, "\033[C"); - if ((temp = putseq(outstr)) != SCPE_OK) return temp; - col++; - if (col > 80) { - col = 1; - row++; - if (row > 24) row = 1; - } - return (SCPE_OK); - case 031: /* Cursor left */ - sprintf(outstr, "\033[D"); - if ((temp = putseq(outstr)) != SCPE_OK) return temp; - tto_unit.pos += 1; - col--; - if (col < 1) { - col = 80; - row--; - if (row < 1) row = 24; - } - return (SCPE_OK); - case 032: /* Cursor down */ - sprintf(outstr, "\033[B"); - if ((temp = putseq(outstr)) != SCPE_OK) return temp; - row++; - if (row > 24) row = 1; - return (SCPE_OK); - case 034: /* Dim on */ - sprintf(outstr, "\033[22m"); - if ((temp = putseq(outstr)) != SCPE_OK) return temp; - return (SCPE_OK); - case 035: /* Dim off */ - sprintf(outstr, "\033[1m"); - if ((temp = putseq(outstr)) != SCPE_OK) return temp; - return (SCPE_OK); - case 036: /* Special sequence */ - spec200 = 1; - return SCPE_OK; - default: /* ..A character of data */ - if ((temp = sim_putchar(c)) != SCPE_OK) return temp; - tto_unit.pos += 1; - col++; - if (col > 80) { - col = 1; - row++; - if (row > 24) row = 24; - } - return (SCPE_OK); - } - return SCPE_OK; -} - -int32 putseq(char *seq) -{ - int i, len, temp; - - len = strlen(seq); - for (i = 0; i < len; i++) { - if ((temp = sim_putchar(seq[i])) != SCPE_OK) - return temp; - tto_unit.pos += 1; - } - return SCPE_OK; -} - -/* -------------------- END INSERTION -----------------------*/ - -/* Reset routine */ - -t_stat tto_reset (DEVICE *dptr) -{ -tto_unit.buf = 0; -dev_busy = dev_busy & ~INT_TTO; /* clear busy */ -dev_done = dev_done & ~INT_TTO; /* clear done, int */ -int_req = int_req & ~INT_TTO; -sim_cancel (&tto_unit); /* deactivate unit */ -return SCPE_OK; -} - -t_stat ttx_setmod (UNIT *uptr, int32 value, char *cptr, void *desc) -{ -tti_unit.flags = (tti_unit.flags & ~UNIT_DASHER) | value; -tto_unit.flags = (tto_unit.flags & ~UNIT_DASHER) | value; -return SCPE_OK; -} diff --git a/NOVA/nova_clk.c b/NOVA/nova_clk.c deleted file mode 100644 index 59bc0af9..00000000 --- a/NOVA/nova_clk.c +++ /dev/null @@ -1,185 +0,0 @@ -/* nova_clk.c: NOVA real-time clock simulator - - Copyright (c) 1993-2008, 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. - - clk real-time clock - - 04-Jul-07 BKR DEV_SET/CLR macros now used, - changed CLK name to RTC for DG compatiblity, - device may now bw DISABLED - 01-Mar-03 RMS Added SET/SHOW CLK FREQ support - 03-Oct-02 RMS Added DIB - 17-Sep-01 RMS Added terminal multiplexor support - 17-Mar-01 RMS Moved function prototype - 05-Mar-01 RMS Added clock calibration - 24-Sep-97 RMS Fixed bug in unit service (Charles Owen) -*/ - -#include "nova_defs.h" - -extern int32 int_req, dev_busy, dev_done, dev_disable ; - -int32 clk_sel = 0; /* selected freq */ -int32 clk_time[4] = { 16000, 100000, 10000, 1000 }; /* freq table */ -int32 clk_tps[4] = { 60, 10, 100, 1000 }; /* ticks per sec */ -int32 clk_adj[4] = { 1, -5, 2, 20 }; /* tmxr adjust */ -int32 tmxr_poll = 16000; /* tmxr poll */ - -int32 clk (int32 pulse, int32 code, int32 AC); -t_stat clk_svc (UNIT *uptr); -t_stat clk_reset (DEVICE *dptr); -t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc); - -/* CLK data structures - - clk_dev CLK device descriptor - clk_unit CLK unit descriptor - clk_reg CLK register list -*/ - -DIB clk_dib = { DEV_CLK, INT_CLK, PI_CLK, &clk }; - -UNIT clk_unit = { UDATA (&clk_svc, 0, 0) }; - -REG clk_reg[] = { - { ORDATA (SELECT, clk_sel, 2) }, - { FLDATA (BUSY, dev_busy, INT_V_CLK) }, - { FLDATA (DONE, dev_done, INT_V_CLK) }, - { FLDATA (DISABLE, dev_disable, INT_V_CLK) }, - { FLDATA (INT, int_req, INT_V_CLK) }, - { DRDATA (TIME0, clk_time[0], 24), REG_NZ + PV_LEFT }, - { DRDATA (TIME1, clk_time[1], 24), REG_NZ + PV_LEFT }, - { DRDATA (TIME2, clk_time[2], 24), REG_NZ + PV_LEFT }, - { DRDATA (TIME3, clk_time[3], 24), REG_NZ + PV_LEFT }, - { DRDATA (TPS0, clk_tps[0], 6), PV_LEFT + REG_HRO }, - { NULL } - }; - -MTAB clk_mod[] = { - { MTAB_XTD|MTAB_VDV, 50, NULL, "50HZ", - &clk_set_freq, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 60, NULL, "60HZ", - &clk_set_freq, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "LINE", NULL, - NULL, &clk_show_freq, NULL }, - { 0 } - }; - -DEVICE clk_dev = { - "RTC", &clk_unit, clk_reg, clk_mod, - 1, 0, 0, 0, 0, 0, - NULL, NULL, &clk_reset, - NULL, NULL, NULL, - &clk_dib, DEV_DISABLE - }; - - -/* IOT routine */ - -int32 clk (int32 pulse, int32 code, int32 AC) -{ -if (code == ioDOA) { /* DOA */ - clk_sel = AC & 3; /* save select */ - sim_rtc_init (clk_time[clk_sel]); /* init calibr */ - } - -switch (pulse) { /* decode IR<8:9> */ - - case iopS: /* start */ - DEV_SET_BUSY( INT_CLK ) ; - DEV_CLR_DONE( INT_CLK ) ; - DEV_UPDATE_INTR ; - if (!sim_is_active (&clk_unit)) /* not running? */ - sim_activate (&clk_unit, /* activate */ - sim_rtc_init (clk_time[clk_sel])); /* init calibr */ - break; - - case iopC: /* clear */ - DEV_CLR_BUSY( INT_CLK ) ; - DEV_CLR_DONE( INT_CLK ) ; - DEV_UPDATE_INTR ; - sim_cancel (&clk_unit); /* deactivate unit */ - break; - } /* end switch */ - -return 0; -} - -/* Unit service */ - -t_stat clk_svc (UNIT *uptr) -{ -int32 t; - -if ( DEV_IS_BUSY(INT_CLK) ) - { - DEV_CLR_BUSY( INT_CLK ) ; - DEV_SET_DONE( INT_CLK ) ; - DEV_UPDATE_INTR ; - } -t = sim_rtc_calb (clk_tps[clk_sel]); /* calibrate delay */ -sim_activate_after (uptr, 1000000/clk_tps[clk_sel]); /* reactivate unit */ -if (clk_adj[clk_sel] > 0) /* clk >= 60Hz? */ - tmxr_poll = t * clk_adj[clk_sel]; /* poll is longer */ -else - tmxr_poll = t / (-clk_adj[clk_sel]); /* poll is shorter */ - -return SCPE_OK; -} - -/* Reset routine */ - -t_stat clk_reset (DEVICE *dptr) -{ -sim_register_clock_unit (&clk_unit); /* declare clock unit */ -clk_sel = 0; -DEV_CLR_BUSY( INT_CLK ) ; -DEV_CLR_DONE( INT_CLK ) ; -DEV_UPDATE_INTR ; - -sim_cancel (&clk_unit); /* deactivate unit */ -tmxr_poll = clk_time[0]; /* poll is default */ -return SCPE_OK; -} - -/* Set line frequency */ - -t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (cptr) - return SCPE_ARG; -if ((val != 50) && (val != 60)) - return SCPE_IERR; -clk_tps[0] = val; -return SCPE_OK; -} - -/* Show line frequency */ - -t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -fprintf (st, (clk_tps[0] == 50)? "50Hz": "60Hz"); -return SCPE_OK; -} diff --git a/NOVA/nova_cpu.c b/NOVA/nova_cpu.c deleted file mode 100644 index 05c63ab9..00000000 --- a/NOVA/nova_cpu.c +++ /dev/null @@ -1,1520 +0,0 @@ -/* nova_cpu.c: NOVA CPU simulator - - Copyright (c) 1993-2017, 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. - - cpu Nova central processor - - 07-Sep-17 RMS Fixed sim_eval declaration in history routine (COVERITY) - 17-Mar-13 RMS Added clarifying brances to IND_STEP macro (Dave Bryan) - 04-Jul-07 BKR DEV_SET/CLR macros now used, - support for non-existant devices added - CPU bootstrap code warning: high-speed devices may not boot properly, - execution history facility added, - documented Nova 3 secret LDB/STB/SAVN behavior, - added support for secret Nova 3 LDB/STB/SAVN substitute actions, - 'ind_max' changed from 16 to 65536 for better unmapped system compatibility, - INT_TRAP added for Nova 3, 4 trap instruction handling, - 28-Apr-07 RMS Removed clock initialization - 06-Feb-06 RMS Fixed bug in DIVS (Mark Hittinger) - 22-Sep-05 RMS Fixed declarations (Sterling Garwood) - 25-Aug-05 RMS Fixed DIVS case 2^31 / - 1 - 14-Jan-04 RMS Fixed device enable/disable support (Bruce Ray) - 19-Jan-03 RMS Changed CMASK to CDMASK for Apple Dev Kit conflict - 03-Oct-02 RMS Added DIB infrastructure - 30-Dec-01 RMS Added old PC queue - 07-Dec-01 RMS Revised to use breakpoint package - 30-Nov-01 RMS Added extended SET/SHOW support - 10-Aug-01 RMS Removed register in declarations - 17-Jul-01 RMS Moved function prototype - 26-Apr-01 RMS Added device enable/disable support - 05-Mar-01 RMS Added clock calibration - 22-Dec-00 RMS Added Bruce Ray's second terminal - 15-Dec-00 RMS Added Charles Owen's CPU bootstrap - 08-Dec-00 RMS Changes from Bruce Ray - -- fixed trap test to include Nova 3 - -- fixed DIV and DIVS divide by 0 - -- fixed RETN to set SP from FP - -- fixed IORST to preserve carry - -- added "secret" Nova 4 PSHN/SAVEN instructions - -- added plotter support - 15-Oct-00 RMS Fixed bug in MDV test, added stack, byte, trap instructions - 14-Apr-98 RMS Changed t_addr to unsigned - 15-Sep-97 RMS Added read and write breakpoints - - The register state for the NOVA CPU is: - - AC[0:3]<0:15> general registers - C carry flag - PC<0:14> program counter - - The NOVA has three instruction formats: memory reference, I/O transfer, - and operate. The memory reference format is: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 0| op | AC |in| mode| displacement | memory reference - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - <0:4> mnemonic action - - 00000 JMP PC = MA - 00001 JMS AC3 = PC, PC = MA - 00010 ISZ M[MA] = M[MA] + 1, skip if M[MA] == 0 - 00011 DSZ M[MA] = M[MA] - 1, skip if M[MA] == 0 - 001'n LDA ACn = M[MA] - 010'n STA M[MA] = ACn - - <5:7> mode action - - 000 page zero direct MA = zext (IR<8:15>) - 001 PC relative direct MA = PC + sext (IR<8:15>) - 010 AC2 relative direct MA = AC2 + sext (IR<8:15>) - 011 AC3 relative direct MA = AC3 + sext (IR<8:15>) - 100 page zero indirect MA = M[zext (IR<8:15>)] - 101 PC relative indirect MA = M[PC + sext (IR<8:15>)] - 110 AC2 relative indirect MA = M[AC2 + sext (IR<8:15>)] - 111 AC3 relative indirect MA = M[AC3 + sext (IR<8:15>)] - - Memory reference instructions can access an address space of 32K words. - An instruction can directly reference the first 256 words of memory - (called page zero), as well as 256 words relative to the PC, AC2, or - AC3; it can indirectly access all 32K words. If an indirect address - is in locations 00020-00027, the indirect address is incremented and - rewritten to memory before use; if in 00030-00037, decremented and - rewritten. - - The I/O transfer format is: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 0 1 1| AC | opcode |pulse| device | I/O transfer - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - The IOT instruction sends the opcode, pulse, and specified AC to the - specified I/O device. The device may accept data, provide data, - initiate or cancel operations, or skip on status. - - The operate format is: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 1|srcAC|dstAC| opcode |shift|carry|nl| skip | operate - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - \______/ \___/ \___/ | | | | - | | | | | | +--- reverse skip sense - | | | | | +--- skip if C == 0 - | | | | +--- skip if result == 0 - | | | +--- don't load result - | | +--- carry in (load as is, - | | set to Zero, - | | set to One, - | | load Complement) - | +--- shift (none, - | left one, - | right one, - | byte swap) - +--- operation (complement, - negate, - move, - increment, - add complement, - subtract, - add, - and) - - The operate instruction can be microprogrammed to perform operations - on the source and destination AC's and the Carry flag. - - Some notes from Bruce Ray: - - 1. DG uses the value of the autoindex location -before- the - modification to determine if additional indirect address - levels are to be performed. Most DG emulators conform to - this standard, but some vendor machines (i.e. Point 4 Mark 8) - do not. - - 2. Infinite indirect references may occur on unmapped systems - and can "hang" the hardware. Some DG diagnostics perform - 10,000s of references during a single instruction. - - 3. Nova 3 adds the following instructions to the standard Nova - instruction set: - - trap instructions - stack push/pop instructions - save/return instructions - stack register manipulation instructions - unsigned MUL/DIV - - 4. Nova 4 adds the following instructions to the Nova 3 instruction - set: - - signed MUL/DIV - load/store byte - secret (undocumented) stack instructions [PSHN, SAVN] - - 5. Nova, Nova 3 and Nova 4 unsigned mul/div instructions are the - same instruction code values on all machines. - - 6. Undocumented Nova 3 behaviour for LDB, STB and SAVN has been - added to appropriate code. - - 7. Most 3rd party vendors had a user-controlled method to increase the - logical address space from 32 KW to 64 KW. This capability came at - the expense of disabling multi-level indirect addressing when the 64KW - mode is in effect, and keeping DG multi-level indirect compatibility - when 64KW mode is inactive. The most common implementation was to use - an "NIOP ,CPU" instruction to control whether 32 KW or 64 KW - addressing mode was wanted, and bit 15 (the least-significant bit - of an accumulator) determined which mode was set: - 0 = 32 KW (DG compatible), 1 = 64 KW. - - This feature has been implemented in our Nova emulation for all to enjoy. - - - This routine is the instruction decode routine for the NOVA. - 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 - infinite indirection loop - unknown I/O device and STOP_DEV flag set - I/O error in I/O simulator - - 2. Interrupts. Interrupts are maintained by four parallel variables: - - dev_done device done flags - dev_disable device interrupt disable flags - dev_busy device busy flags - int_req interrupt requests - - In addition, int_req contains the interrupt enable and ION pending - flags. If ION and ION pending are set, and at least one interrupt - request is pending, then an interrupt occurs. Note that the 16b PIO - mask must be mapped to the simulator's device bit mapping. - - 3. Non-existent memory. On the NOVA, 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: - - nova_defs.h add interrupt request definition - nova_sys.c add sim_devices entry -*/ - -#include "nova_defs.h" - - -#define PCQ_SIZE 64 /* must be 2**n */ -#define PCQ_MASK (PCQ_SIZE - 1) -#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC - - -#define INCA(x) (((x) + 1) & AMASK) -#define DECA(x) (((x) - 1) & AMASK) -#define SEXT(x) (((x) & SIGN)? ((x) | ~DMASK): (x)) -#define STK_CHECK(x,y) if (((x) & 0377) < (y)) \ - int_req = int_req | INT_STK -#define IND_STEP(x) M[x] & A_IND; /* return next level indicator */ \ - if ( ((x) <= AUTO_TOP) && ((x) >= AUTO_INC) ) { \ - if ( (x) < AUTO_DEC ) \ - M[x] = (M[x] + 1) & DMASK; \ - else \ - M[x] = (M[x] - 1) & DMASK; \ - } \ - x = M[x] & AMASK - -#define INCREMENT_PC PC = (PC + 1) & AMASK /* increment PC */ - -#define UNIT_V_MDV (UNIT_V_UF + 0) /* MDV present */ -#define UNIT_V_STK (UNIT_V_UF + 1) /* stack instr */ -#define UNIT_V_BYT (UNIT_V_UF + 2) /* byte instr */ -#define UNIT_V_64KW (UNIT_V_UF + 3) /* 64KW mem support */ -#define UNIT_V_MSIZE (UNIT_V_UF + 4) /* dummy mask */ -#define UNIT_MDV (1 << UNIT_V_MDV) -#define UNIT_STK (1 << UNIT_V_STK) -#define UNIT_BYT (1 << UNIT_V_BYT) -#define UNIT_64KW (1 << UNIT_V_64KW) -#define UNIT_MSIZE (1 << UNIT_V_MSIZE) -#define UNIT_IOPT (UNIT_MDV | UNIT_STK | UNIT_BYT | UNIT_64KW) -#define UNIT_NOVA3 (UNIT_MDV | UNIT_STK) -#define UNIT_NOVA4 (UNIT_MDV | UNIT_STK | UNIT_BYT) -#define UNIT_KERONIX (UNIT_MDV | UNIT_64KW) - -#define MODE_64K (cpu_unit.flags & UNIT_64KW) -#define MODE_64K_ACTIVE ((cpu_unit.flags & UNIT_64KW) && (0xFFFF == AMASK)) - - -typedef struct - { - int32 pc; - int16 ir; - int16 ac0 ; - int16 ac1 ; - int16 ac2 ; - int16 ac3 ; - int16 carry ; - int16 sp ; - int16 fp ; - int32 devDone ; - int32 devBusy ; - int32 devDisable ; - int32 devIntr ; - } Hist_entry ; - - -uint16 M[MAXMEMSIZE] = { 0 }; /* memory */ -int32 AC[4] = { 0 }; /* accumulators */ -int32 C = 0; /* carry flag */ -int32 saved_PC = 0; /* program counter */ -int32 SP = 0; /* stack pointer */ -int32 FP = 0; /* frame pointer */ -int32 SR = 0; /* switch register */ -int32 dev_done = 0; /* device done flags */ -int32 dev_busy = 0; /* device busy flags */ -int32 dev_disable = 0; /* int disable flags */ -int32 int_req = 0; /* interrupt requests */ -int32 pimask = 0; /* priority int mask */ -int32 pwr_low = 0; /* power fail flag */ -int32 ind_max = 65536; /* iadr nest limit */ -int32 stop_dev = 0; /* stop on ill dev */ -uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ -int32 pcq_p = 0; /* PC queue ptr */ -REG *pcq_r = NULL; /* PC queue reg ptr */ -struct ndev dev_table[64]; /* dispatch table */ -int32 AMASK = 077777 ; /* current memory address mask */ - /* (default to 32KW) */ -static int32 hist_p = 0 ; /* history pointer */ -static int32 hist_cnt = 0 ; /* history count */ -static Hist_entry * hist = NULL ; /* instruction history */ - - -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, DEVICE *dptr); -t_stat build_devtab (void); - -t_stat hist_set( UNIT * uptr, int32 val, char * cptr, void * desc ) ; -t_stat hist_show( FILE * st, UNIT * uptr, int32 val, void * desc ) ; -static int hist_save( int32 pc, int32 our_ir ) ; -char * devBitNames( int32 flags, char * ptr, char * sepStr ) ; - -void mask_out (int32 mask); - - -/* 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+UNIT_MDV, DFTMEMSIZE /* MAXMEMSIZE */ ) - }; - -REG cpu_reg[] = { - { ORDATA (PC, saved_PC, 15) }, - { ORDATA (AC0, AC[0], 16) }, - { ORDATA (AC1, AC[1], 16) }, - { ORDATA (AC2, AC[2], 16) }, - { ORDATA (AC3, AC[3], 16) }, - { FLDATA (C, C, 16) }, - { ORDATA (SP, SP, 16) }, - { ORDATA (FP, FP, 16) }, - { ORDATA (SR, SR, 16) }, - { ORDATA (PI, pimask, 16) }, - { FLDATA (ION, int_req, INT_V_ION) }, - { FLDATA (ION_DELAY, int_req, INT_V_NO_ION_PENDING) }, - { FLDATA (STKOVF, int_req, INT_V_STK) }, - { FLDATA (PWR, pwr_low, 0) }, - { ORDATA (INT, int_req, INT_V_ION+1), REG_RO }, - { ORDATA (BUSY, dev_busy, INT_V_ION+1), REG_RO }, - { ORDATA (DONE, dev_done, INT_V_ION+1), REG_RO }, - { ORDATA (DISABLE, dev_disable, INT_V_ION+1), REG_RO }, - { FLDATA (STOP_DEV, stop_dev, 0) }, - { DRDATA (INDMAX, ind_max, 32), REG_NZ + PV_LEFT }, - { ORDATA (AMASK, AMASK, 16) }, - { DRDATA (MEMSIZE, cpu_unit.capac, 32), REG_NZ + PV_LEFT }, - { BRDATA (PCQ, pcq, 8, 16, PCQ_SIZE), REG_RO+REG_CIRC }, - { ORDATA (PCQP, pcq_p, 6), REG_HRO }, - { ORDATA (WRU, sim_int_char, 8) }, - { NULL } - }; - -MTAB cpu_mod[] = { - { UNIT_IOPT, UNIT_NOVA3, "NOVA3", "NOVA3", NULL }, - { UNIT_IOPT, UNIT_NOVA4, "NOVA4", "NOVA4", NULL }, - { UNIT_IOPT, UNIT_KERONIX, "KERONIX", "KERONIX", NULL }, - { UNIT_IOPT, UNIT_MDV, "MDV", "MDV", NULL }, - { UNIT_IOPT, UNIT_64KW, "EXT64KW", "EXT64KW", NULL }, - { UNIT_IOPT, 0, "none", "NONE", NULL }, - { UNIT_MSIZE, ( 4 * 1024), NULL, "4K", &cpu_set_size }, - { UNIT_MSIZE, ( 8 * 1024), NULL, "8K", &cpu_set_size }, - { UNIT_MSIZE, (12 * 1024), NULL, "12K", &cpu_set_size }, - { UNIT_MSIZE, (16 * 1024), NULL, "16K", &cpu_set_size }, - { UNIT_MSIZE, (20 * 1024), NULL, "20K", &cpu_set_size }, - { UNIT_MSIZE, (24 * 1024), NULL, "24K", &cpu_set_size }, - { UNIT_MSIZE, (28 * 1024), NULL, "28K", &cpu_set_size }, - { UNIT_MSIZE, (32 * 1024), NULL, "32K", &cpu_set_size }, - { UNIT_MSIZE, (36 * 1024), NULL, "36K", &cpu_set_size }, - { UNIT_MSIZE, (40 * 1024), NULL, "40K", &cpu_set_size }, - { UNIT_MSIZE, (44 * 1024), NULL, "44K", &cpu_set_size }, - { UNIT_MSIZE, (48 * 1024), NULL, "48K", &cpu_set_size }, - { UNIT_MSIZE, (52 * 1024), NULL, "52K", &cpu_set_size }, - { UNIT_MSIZE, (56 * 1024), NULL, "56K", &cpu_set_size }, - { UNIT_MSIZE, (60 * 1024), NULL, "60K", &cpu_set_size }, - { UNIT_MSIZE, (64 * 1024), NULL, "64K", &cpu_set_size }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", - &hist_set, &hist_show }, - - { 0 } - }; - -DEVICE cpu_dev = { - "CPU", &cpu_unit, cpu_reg, cpu_mod, - 1, 8, 16 /* = 64 KW, 15 = 32KW */, 1, 8, 16, - &cpu_ex, &cpu_dep, &cpu_reset, - NULL, NULL, NULL - }; - -t_stat sim_instr (void) -{ -int32 PC, IR, i; -t_stat reason; - -/* Restore register state */ - -if (build_devtab () != SCPE_OK) /* build dispatch */ - return SCPE_IERR; -PC = saved_PC & AMASK; /* load local PC */ -C = C & CBIT; -mask_out (pimask); /* reset int system */ -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 > INT_PENDING) { /* interrupt or exception? */ - int32 MA, indf; - - if (int_req & INT_TRAP) { /* trap instruction? */ - int_req = int_req & ~INT_TRAP ; /* clear */ - PCQ_ENTRY; /* save old PC */ - M[TRP_SAV] = (PC - 1) & AMASK; - MA = TRP_JMP; /* jmp @47 */ - } - else { - int_req = int_req & ~INT_ION; /* intr off */ - PCQ_ENTRY; /* save old PC */ - M[INT_SAV] = PC; - if (int_req & INT_STK) { /* stack overflow? */ - int_req = int_req & ~INT_STK; /* clear */ - MA = STK_JMP; /* jmp @3 */ - } - else - MA = INT_JMP; /* intr: jmp @1 */ - } - if ( MODE_64K_ACTIVE ) { - indf = IND_STEP (MA); - } - else - { - for (i = 0, indf = 1; indf && (i < ind_max); i++) { - indf = IND_STEP (MA); /* indirect loop */ - } - if (i >= ind_max) { - reason = STOP_IND_INT; - break; - } - } - PC = MA; - } /* end interrupt */ - - if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; - } - - IR = M[PC]; /* fetch instr */ - if ( hist_cnt ) - { - hist_save( PC, IR ) ; /* PC, int_req unchanged */ - } - - INCREMENT_PC ; - int_req = int_req | INT_NO_ION_PENDING; /* clear ION delay */ - sim_interval = sim_interval - 1; - -/* Operate instruction */ - - if (IR & I_OPR) { /* operate? */ - int32 src, srcAC, dstAC; - - srcAC = I_GETSRC (IR); /* get reg decodes */ - dstAC = I_GETDST (IR); - switch (I_GETCRY (IR)) { /* decode carry */ - case 0: /* load */ - src = AC[srcAC] | C; - break; - case 1: /* clear */ - src = AC[srcAC]; - break; - case 2: /* set */ - src = AC[srcAC] | CBIT; - break; - case 3: /* complement */ - src = AC[srcAC] | (C ^ CBIT); - break; - } /* end switch carry */ - - switch (I_GETALU (IR)) { /* decode ALU */ - case 0: /* COM */ - src = src ^ DMASK; - break; - case 1: /* NEG */ - src = ((src ^ DMASK) + 1) & CDMASK; - break; - case 2: /* MOV */ - break; - case 3: /* INC */ - src = (src + 1) & CDMASK; - break; - case 4: /* ADC */ - src = ((src ^ DMASK) + AC[dstAC]) & CDMASK; - break; - case 5: /* SUB */ - src = ((src ^ DMASK) + AC[dstAC] + 1) & CDMASK; - break; - case 6: /* ADD */ - src = (src + AC[dstAC]) & CDMASK; - break; - case 7: /* AND */ - src = src & (AC[dstAC] | CBIT); - break; - } /* end switch oper */ - - switch (I_GETSHF (IR)) { /* decode shift */ - case 0: /* nop */ - break; - case 1: /* L */ - src = ((src << 1) | (src >> 16)) & CDMASK; - break; - case 2: /* R */ - src = ((src >> 1) | (src << 16)) & CDMASK; - break; - case 3: /* S */ - src = ((src & 0377) << 8) | ((src >> 8) & 0377) | - (src & CBIT); - break; - } /* end switch shift */ - - switch (I_GETSKP (IR)) { /* decode skip */ - case 0: /* nop */ - if ((IR & I_NLD) && (cpu_unit.flags & UNIT_STK)) { - int_req = int_req | INT_TRAP ; /* Nova 3 or 4 trap */ - continue ; - } - break; - case 1: /* SKP */ - INCREMENT_PC ; - break; - case 2: /* SZC */ - if (src < CBIT) - INCREMENT_PC ; - break; - case 3: /* SNC */ - if (src >= CBIT) - INCREMENT_PC ; - break; - case 4: /* SZR */ - if ((src & DMASK) == 0) - INCREMENT_PC ; - break; - case 5: /* SNR */ - if ((src & DMASK) != 0) - INCREMENT_PC ; - break; - case 6: /* SEZ */ - if (src <= CBIT) - INCREMENT_PC ; - break; - case 7: /* SBN */ - if (src > CBIT) - INCREMENT_PC ; - break; - } /* end switch skip */ - if ((IR & I_NLD) == 0) { /* load? */ - AC[dstAC] = src & DMASK; - C = src & CBIT; - } /* end if load */ - } /* end if operate */ - -/* Memory reference instructions */ - - else if (IR < 060000) { /* mem ref? */ - int32 src, MA, indf; - - MA = I_GETDISP (IR); /* get disp */ - switch (I_GETMODE (IR)) { /* decode mode */ - case 0: /* page zero */ - break; - case 1: /* PC relative */ - if (MA & DISPSIGN) - MA = 0177400 | MA; - MA = (MA + PC - 1) & AMASK; - break; - case 2: /* AC2 relative */ - if (MA & DISPSIGN) - MA = 0177400 | MA; - MA = (MA + AC[2]) & AMASK; - break; - case 3: /* AC3 relative */ - if (MA & DISPSIGN) - MA = 0177400 | MA; - MA = (MA + AC[3]) & AMASK; - break; - } /* end switch mode */ - - if ( (indf = IR & I_IND) ) { /* indirect? */ - if ( MODE_64K_ACTIVE ) { /* 64k mode? */ - indf = IND_STEP (MA); - } - else /* compat mode */ - { - for (i = 0; indf && (i < ind_max); i++) { /* count */ - indf = IND_STEP (MA); /* resolve indirect */ - } - if (i >= ind_max) { /* too many? */ - reason = STOP_IND; - break; - } - } - } - - switch (I_GETOPAC (IR)) { /* decode op + AC */ - case 001: /* JSR */ - AC[3] = PC; - case 000: /* JMP */ - PCQ_ENTRY; - PC = MA; - break; - case 002: /* ISZ */ - src = (M[MA] + 1) & DMASK; - if (MEM_ADDR_OK(MA)) - M[MA] = src; - if (src == 0) - INCREMENT_PC ; - break; - case 003: /* DSZ */ - src = (M[MA] - 1) & DMASK; - if (MEM_ADDR_OK(MA)) - M[MA] = src; - if (src == 0) - INCREMENT_PC ; - break; - case 004: /* LDA 0 */ - AC[0] = M[MA]; - break; - case 005: /* LDA 1 */ - AC[1] = M[MA]; - break; - case 006: /* LDA 2 */ - AC[2] = M[MA]; - break; - case 007: /* LDA 3 */ - AC[3] = M[MA]; - break; - case 010: /* STA 0 */ - if (MEM_ADDR_OK(MA)) - M[MA] = AC[0]; - break; - case 011: /* STA 1 */ - if (MEM_ADDR_OK(MA)) - M[MA] = AC[1]; - break; - case 012: /* STA 2 */ - if (MEM_ADDR_OK(MA)) - M[MA] = AC[2]; - break; - case 013: /* STA 3 */ - if (MEM_ADDR_OK(MA)) - M[MA] = AC[3]; - break; - } /* end switch */ - } /* end mem ref */ - -/* IOT instruction */ - - else { /* IOT */ - int32 dstAC, pulse, code, device, iodata; - - dstAC = I_GETDST (IR); /* decode fields */ - code = I_GETIOT (IR); - pulse = I_GETPULSE (IR); - device = I_GETDEV (IR); - if (code == ioSKP) { /* IO skip? */ - switch (pulse) { /* decode IR<8:9> */ - - case 0: /* skip if busy */ - if ((device == DEV_CPU)? (int_req & INT_ION) != 0: - (dev_busy & dev_table[device].mask) != 0) - INCREMENT_PC ; - break; - - case 1: /* skip if not busy */ - if ((device == DEV_CPU)? (int_req & INT_ION) == 0: - (dev_busy & dev_table[device].mask) == 0) - INCREMENT_PC ; - break; - - case 2: /* skip if done */ - if ((device == DEV_CPU)? pwr_low != 0: - (dev_done & dev_table[device].mask) != 0) - INCREMENT_PC ; - break; - - case 3: /* skip if not done */ - if ((device == DEV_CPU)? pwr_low == 0: - (dev_done & dev_table[device].mask) == 0) - INCREMENT_PC ; - break; - } /* end switch */ - } /* end IO skip */ - - /* Hmm, this means a Nova 3 _must_ have DEV_MDV enabled - not true in DG land */ - - else if (device == DEV_MDV) { - switch (code) { /* case on opcode */ - - case ioNIO: /* frame ptr */ - if (cpu_unit.flags & UNIT_STK) { - if (pulse == iopN) - FP = AC[dstAC] & AMASK ; - if (pulse == iopC) - AC[dstAC] = FP & AMASK ; - } - break; - - case ioDIA: /* load byte */ - if (cpu_unit.flags & UNIT_BYT) - { - AC[dstAC] = (M[AC[pulse] >> 1] >> ((AC[pulse] & 1)? 0: 8)) & 0377 ; - } - else if (cpu_unit.flags & UNIT_STK) /* if Nova 3 this is really a SAV... 2007-Jun-01, BKR */ - { - SP = INCA (SP); - if (MEM_ADDR_OK (SP)) - M[SP] = AC[0]; - SP = INCA (SP); - if (MEM_ADDR_OK (SP)) - M[SP] = AC[1]; - SP = INCA (SP); - if (MEM_ADDR_OK (SP)) - M[SP] = AC[2]; - SP = INCA (SP); - if (MEM_ADDR_OK (SP)) - M[SP] = FP; - SP = INCA (SP); - if (MEM_ADDR_OK (SP)) - M[SP] = (C >> 1) | (AC[3] & AMASK); - AC[3] = FP = SP & AMASK; - STK_CHECK (SP, 5); - } - else - { - AC[dstAC] = 0; - } - break; - - case ioDOA: /* stack ptr */ - if (cpu_unit.flags & UNIT_STK) { - if (pulse == iopN) - SP = AC[dstAC] & AMASK; - if (pulse == iopC) - AC[dstAC] = SP & AMASK; - } - break; - - case ioDIB: /* push, pop */ - if (cpu_unit.flags & UNIT_STK) { - if (pulse == iopN) { /* push (PSHA) */ - SP = INCA (SP); - if (MEM_ADDR_OK (SP)) - M[SP] = AC[dstAC]; - STK_CHECK (SP, 1); - } - if ((pulse == iopS) && /* Nova 4 pshn (PSHN) */ - (cpu_unit.flags & UNIT_BYT)) { - SP = INCA (SP); - if (MEM_ADDR_OK (SP)) - M[SP] = AC[dstAC]; - if ( (SP & 0xFFFF) > (M[042] & 0xFFFF) ) - { - int_req = int_req | INT_STK ; - } - } - if (pulse == iopC) { /* pop (POPA) */ - AC[dstAC] = M[SP]; - SP = DECA (SP); - } - } - break; - - case ioDOB: /* store byte */ - if (cpu_unit.flags & UNIT_BYT) - { - int32 MA, val; - MA = AC[pulse] >> 1; - val = AC[dstAC] & 0377; - if (MEM_ADDR_OK (MA)) M[MA] = (AC[pulse] & 1)? - ((M[MA] & ~0377) | val) - : ((M[MA] & 0377) | (val << 8)); - } - else if (cpu_unit.flags & UNIT_STK) /* if Nova 3 this is really a SAV... 2007-Jun-01, BKR */ - { - SP = INCA (SP); - if (MEM_ADDR_OK (SP)) - M[SP] = AC[0]; - SP = INCA (SP); - if (MEM_ADDR_OK (SP)) - M[SP] = AC[1]; - SP = INCA (SP); - if (MEM_ADDR_OK (SP)) - M[SP] = AC[2]; - SP = INCA (SP); - if (MEM_ADDR_OK (SP)) - M[SP] = FP; - SP = INCA (SP); - if (MEM_ADDR_OK (SP)) - M[SP] = (C >> 1) | (AC[3] & AMASK); - AC[3] = FP = SP & AMASK; - STK_CHECK (SP, 5); - } - break; - - case ioDIC: /* save, return */ - if (cpu_unit.flags & UNIT_STK) { - if (pulse == iopN) { /* save */ - SP = INCA (SP); - if (MEM_ADDR_OK (SP)) - M[SP] = AC[0]; - SP = INCA (SP); - if (MEM_ADDR_OK (SP)) - M[SP] = AC[1]; - SP = INCA (SP); - if (MEM_ADDR_OK (SP)) - M[SP] = AC[2]; - SP = INCA (SP); - if (MEM_ADDR_OK (SP)) - M[SP] = FP; - SP = INCA (SP); - if (MEM_ADDR_OK (SP)) - M[SP] = (C >> 1) | (AC[3] & AMASK); - AC[3] = FP = SP & AMASK; - STK_CHECK (SP, 5); - } - else if (pulse == iopC) { /* retn */ - PCQ_ENTRY; - SP = FP & AMASK; - C = (M[SP] << 1) & CBIT; - PC = M[SP] & AMASK; - SP = DECA (SP); - AC[3] = M[SP]; - SP = DECA (SP); - AC[2] = M[SP]; - SP = DECA (SP); - AC[1] = M[SP]; - SP = DECA (SP); - AC[0] = M[SP]; - SP = DECA (SP); - FP = AC[3] & AMASK; - } - else if ((pulse == iopS) && /* Nova 4 SAVN */ - (cpu_unit.flags & UNIT_BYT)) { - int32 frameSz = M[PC] ; - PC = INCA (PC) ; - SP = INCA (SP); - if (MEM_ADDR_OK (SP)) - M[SP] = AC[0]; - SP = INCA (SP); - if (MEM_ADDR_OK (SP)) - M[SP] = AC[1]; - SP = INCA (SP); - if (MEM_ADDR_OK (SP)) - M[SP] = AC[2]; - SP = INCA (SP); - if (MEM_ADDR_OK (SP)) - M[SP] = FP; - SP = INCA (SP); - if (MEM_ADDR_OK (SP)) - M[SP] = (C >> 1) | (AC[3] & AMASK); - AC[3] = FP = SP & AMASK ; - SP = (SP + frameSz) & AMASK ; - if (SP > M[042]) - { - int_req = int_req | INT_STK; - } - } - } - break; - - case ioDOC: - if ((dstAC == 2) && (cpu_unit.flags & UNIT_MDV)) - { /* Nova, Nova3 or Nova 4 */ - uint32 mddata, uAC0, uAC1, uAC2; - - uAC0 = (uint32) AC[0]; - uAC1 = (uint32) AC[1]; - uAC2 = (uint32) AC[2]; - if (pulse == iopP) - { /* mul */ - mddata = (uAC1 * uAC2) + uAC0; - AC[0] = (mddata >> 16) & DMASK; - AC[1] = mddata & DMASK; - } - if (pulse == iopS) - { /* div */ - if ((uAC0 >= uAC2) || (uAC2 == 0)) - { - C = CBIT; - } - else - { - C = 0; - mddata = (uAC0 << 16) | uAC1; - AC[1] = mddata / uAC2; - AC[0] = mddata % uAC2; - } - } - } - else if ((dstAC == 3) && (cpu_unit.flags & UNIT_BYT) /* assuming UNIT_BYT = Nova 4 */) - { - int32 mddata; - if (pulse == iopC) - { /* muls */ - mddata = (SEXT (AC[1]) * SEXT (AC[2])) + SEXT (AC[0]); - AC[0] = (mddata >> 16) & DMASK; - AC[1] = mddata & DMASK; - } - else if (pulse == iopN) - { /* divs */ - if ((AC[2] == 0) || /* overflow? */ - ((AC[0] == 0100000) && (AC[1] == 0) && (AC[2] == 0177777))) - { - C = CBIT; - } - else - { - mddata = (SEXT (AC[0]) << 16) | AC[1]; - AC[1] = mddata / SEXT (AC[2]); - AC[0] = mddata % SEXT (AC[2]); - if ((AC[1] > 077777) || (AC[1] < -0100000)) - { - C = CBIT; - } - else - { - C = 0; - } - AC[0] = AC[0] & DMASK; - } - } - } - else if ((dstAC == 3) && (cpu_unit.flags & UNIT_STK)) /* if Nova 3 this is really a PSHA... 2007-Jun-01, BKR */ - { - SP = INCA (SP); - if (MEM_ADDR_OK (SP)) - M[SP] = AC[dstAC]; - STK_CHECK (SP, 1); - } - break; - } /* end case code */ - } /* end if mul/div */ - - else if (device == DEV_CPU) { /* CPU control */ - switch (code) { /* decode IR<5:7> */ - - case ioNIO: /* NIOP CPU ? */ - if ( pulse == iopP ) - if ( MODE_64K ) - { - /* Keronix/Point4/SCI/INI/IDP (and others) */ - /* 64 KW memory extension: */ - /* NIOP - set memory mode (32/64 KW) per AC: */ - /* B15: 0 = 32 KW, 1 = 64 KW mode */ - AMASK = (AC[dstAC] & 0x0001) ? 0177777 : 077777 ; - } - break ; - - case ioDIA: /* read switches */ - AC[dstAC] = SR; - break; - - case ioDIB: /* int ack */ - AC[dstAC] = 0; - DEV_UPDATE_INTR ; - iodata = int_req & (-int_req); - for (i = DEV_LOW; i <= DEV_HIGH; i++) { - if (iodata & dev_table[i].mask) { - AC[dstAC] = i; - break; - } - } - break; - - case ioDOB: /* mask out */ - mask_out (pimask = AC[dstAC]); - break; - - case ioDIC: /* io reset */ - reset_all (0); /* reset devices */ - mask_out( 0 ) ; /* clear all device masks */ - AMASK = 077777 ; /* reset memory mode */ - break; - - case ioDOC: /* halt */ - reason = STOP_HALT; - break; - } /* end switch code */ - - switch (pulse) { /* decode IR<8:9> */ - - case iopS: /* ion */ - int_req = (int_req | INT_ION) & ~INT_NO_ION_PENDING; - break; - - case iopC: /* iof */ - int_req = int_req & ~INT_ION; - break; - } /* end switch pulse */ - } /* end CPU control */ - - else if (dev_table[device].routine) { /* normal device */ - iodata = dev_table[device].routine (pulse, code, AC[dstAC]); - reason = iodata >> IOT_V_REASON; - if (code & 1) - AC[dstAC] = iodata & 0177777; - } - -/* bkr, 2007-May-30 - * if device does not exist certain I/O instructions will still - * return data: DIA/B/C will return idle data bus value and - * SKPBZ/SKPDZ will sense zero value (and will therefore skip). - * - * Perform these non-supported device functions only if 'stop_dev' - * is zero (i.e. I/O access trap is not in effect). - */ - else if ( stop_dev == 0 ) - { - switch (code) /* decode IR<5:7> */ - { - case ioDIA: - case ioDIB: - case ioDIC: - AC[dstAC] = 0 ; /* idle I/O bus data */ - break; - - case ioSKP: - /* (This should have been caught in previous CPU skip code) */ - if ( (pulse == 1 /* SKPBZ */) || (pulse == 3 /* SKPDZ */) ) - { - INCREMENT_PC ; - } - } /* end of 'switch' */ - } /* end of handling non-existant device */ - else reason = stop_dev; - } /* end if IOT */ - } /* end while */ - -/* Simulation halted */ - -saved_PC = PC; -pcq_r->qptr = pcq_p; /* update pc q ptr */ -return ( reason ) ; -} - -/* New priority mask out */ - -void mask_out (int32 newmask) -{ -int32 i; - -dev_disable = 0; -for (i = DEV_LOW; i <= DEV_HIGH; i++) { - if (newmask & dev_table[i].pi) - dev_disable = dev_disable | dev_table[i].mask; - } -DEV_UPDATE_INTR ; -return; -} - -/* Reset routine */ - -t_stat cpu_reset (DEVICE *dptr) -{ -int_req = int_req & ~(INT_ION | INT_STK | INT_TRAP); -pimask = 0; -dev_disable = 0; -pwr_low = 0; -AMASK = 077777 ; /* 32KW mode */ -pcq_r = find_reg ("PCQ", NULL, dptr); -if (pcq_r) - pcq_r->qptr = 0; -else return SCPE_IERR; -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] & DMASK; -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 & DMASK; -return SCPE_OK; -} - -/* Alter memory size */ - -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; -} - -/* Build dispatch table */ - -t_stat build_devtab (void) -{ -DEVICE *dptr; -DIB *dibp; -int32 i, dn; - -for (i = 0; i < 64; i++) { /* clr dev_table */ - dev_table[i].mask = 0; - dev_table[i].pi = 0; - dev_table[i].routine = NULL; - } -for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ - if (!(dptr->flags & DEV_DIS) && /* enabled and */ - ( (dibp = (DIB *) dptr->ctxt)) ) { /* defined DIB? */ - dn = dibp->dnum; /* get dev num */ - dev_table[dn].mask = dibp->mask; /* copy entries */ - dev_table[dn].pi = dibp->pi; - dev_table[dn].routine = dibp->routine; - } - } -return SCPE_OK; -} - -/* BKR notes: - * - * Data General APL (Automatic Program Load) boot code - * - * - This bootstrap code is called the "APL option" in DG documentation (Automatic - * Program Load), and cost ~$400 USD (in 1970 - wow!) to load 32(10) words from - * a PROM to main (core) memory location 0 - 32. - * - This code is documented in various DG Nova programming manuals and was - * quite static (i.e. no revisions or updates to code were made). - * - switch register is used to determine device code and device type. - * - lower 6-bits of switch register determines device code (0-63.). - * - most significant bit determines if device is "low speed" or "high speed". - * - "high speed" devices have effective boot program logic of: - * - * IORST - * NIOS - * JMP . - * - * - "high speed" devices use data channel (DCH) to read first sector/record - * of device into memory (usually starting at location 0), which then over-writes - * the 'JMP .' instruction of boot code. This usually has a jump to some other - * device and operating system specific boot code that was loaded from the device. - * - "low speed" devices are assumed to be sequential character-oriented devices - * (i.e. Teletype (r) reader, paper tape reader). - * - "low speed" devices are assumed to start read operations with a 'S' pulse, - * read data buffer with a DIA instruction and have standard DG I/O Busy/Done logic. - * - "low speed" devices usually read in a more full-featured 'binary loader' with - * the APL boot code: - * - * DG paper tape: 091-000004-xx, Binary Loader (BLDR.AB) - * - * - The Binary Loader was in turn used to load tapes in the usual DG 'absolute binary' format. - */ - -#define BOOT_START 00000 -#define BOOT_LEN (sizeof(boot_rom) / sizeof(int32)) - -static const int32 boot_rom[] = { - 0062677, /* IORST ;reset all I/O */ - 0060477, /* READS 0 ;read SR into AC0 */ - 0024026, /* LDA 1,C77 ;get dev mask */ - 0107400, /* AND 0,1 ;isolate dev code */ - 0124000, /* COM 1,1 ;- device code - 1 */ - 0010014, /* LOOP: ISZ OP1 ;device code to all */ - 0010030, /* ISZ OP2 ;I/O instructions */ - 0010032, /* ISZ OP3 */ - 0125404, /* INC 1,1,SZR ;done? */ - 0000005, /* JMP LOOP ;no, increment again */ - 0030016, /* LDA 2,C377 ;place JMP 377 into */ - 0050377, /* STA 2,377 ;location 377 */ - 0060077, /* OP1: 060077 ;start device (NIOS 0) */ - 0101102, /* MOVL 0,0,SZC ;test switch 0, low speed? */ - 0000377, /* C377: JMP 377 ;no - jmp 377 & wait */ - 0004030, /* LOOP2: JSR GET+1 ;get a frame */ - 0101065, /* MOVC 0,0,SNR ;is it non-zero? */ - 0000017, /* JMP LOOP2 ;no, ignore */ - 0004027, /* LOOP4: JSR GET ;yes, get full word */ - 0046026, /* STA 1,@C77 ;store starting at 100 */ - /* ;2's complement of word ct */ - 0010100, /* ISZ 100 ;done? */ - 0000022, /* JMP LOOP4 ;no, get another */ - 0000077, /* C77: JMP 77 ;yes location ctr and */ - /* ;jmp to last word */ - 0126420, /* GET: SUBZ 1,1 ; clr AC1, set carry */ - /* OP2: */ - 0063577, /* LOOP3: 063577 ;done? (SKPDN 0) - 1 */ - 0000030, /* JMP LOOP3 ;no -- wait */ - 0060477, /* OP3: 060477 ;y -- read in ac0 (DIAS 0,0) */ - 0107363, /* ADDCS 0,1,SNC ;add 2 frames swapped - got 2nd? */ - 0000030, /* JMP LOOP3 ;no go back after it */ - 0125300, /* MOVS 1,1 ;yes swap them */ - 0001400, /* JMP 0,3 ;rtn with full word */ - 0000000 /* 0 ;padding */ - }; - -t_stat cpu_boot (int32 unitno, DEVICE *dptr) -{ -size_t i; - -for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i]; -saved_PC = BOOT_START; -return SCPE_OK; -} - -/* 1-to-1 map for I/O devices */ - -int32 MapAddr (int32 map, int32 addr) -{ -return addr; -} - -/* History subsystem - -global routines - -t_stat hist_set( UNIT * uptr, int32 val, char * cptr, void * desc, void ** HistCookie, sizeof(usrHistInfo) ) ; -t_stat hist_show( FILE * st, UNIT * uptr, int32 val, void * desc, void * HistCookie ) ; -int hist_save( int32 next_pc, int32 our_ir, void * usrHistInfo ) - -local user struct: - -usrHistInfo - -local user routines: - -int uHist_save( int32 next_pc, int32 our_ir, void * usrHistInfo ) ; -int uHist_fprintf( FILE * fp, int itemNum, void * usrHistInfo ) ; - -typedef struct - { - int hMax ; // total # entries in queue (0 = inactive) - int hCount ; // current entry - void * hPtr ; // pointer to save area - int hSize ; // size of each user save area (not used by global routines?) - } Hist_info ; - */ - -/* generalized CPU execution trace */ - -#define HIST_IR_INVALID -1 -#define HIST_MIN 0 /* 0 == deactivate history feature, else size of queue */ -#define HIST_MAX 1000000 /* completely arbitrary max size value */ - -/* save history entry (proposed local routine) */ - -static int hist_save( int32 pc, int32 our_ir ) -{ -Hist_entry * hist_ptr ; - -if ( hist ) - if ( hist_cnt ) - { - hist_p = (hist_p + 1) ; /* next entry */ - if ( hist_p >= hist_cnt ) - { - hist_p = 0 ; - } - hist_ptr = &hist[ hist_p ] ; - - /* (machine-specific stuff) */ - - hist_ptr->pc = pc ; - hist_ptr->ir = our_ir ; - hist_ptr->ac0 = AC[ 0 ] ; - hist_ptr->ac1 = AC[ 1 ] ; - hist_ptr->ac2 = AC[ 2 ] ; - hist_ptr->ac3 = AC[ 3 ] ; - hist_ptr->carry = C ; - hist_ptr->fp = FP ; - hist_ptr->sp = SP ; - hist_ptr->devBusy = dev_busy ; - hist_ptr->devDone = dev_done ; - hist_ptr->devDisable = dev_disable ; - hist_ptr->devIntr = int_req ; - /* how 'bout state and AMASK? */ - return ( hist_p ) ; - } -return ( -1 ) ; -} /* end of 'hist_save' */ - -/* setup history save area (proposed global routine) */ - -t_stat hist_set( UNIT * uptr, int32 val, char * cptr, void * desc ) -{ -int32 i, lnt ; -t_stat r ; - -if ( cptr == NULL ) - { - for (i = 0 ; i < hist_cnt ; ++i ) - { - hist[i].pc = 0 ; - hist[i].ir = HIST_IR_INVALID ; - } - hist_p = 0 ; - return ( SCPE_OK ) ; - } -lnt = (int32) get_uint(cptr, 10, HIST_MAX, &r) ; -if ( (r != SCPE_OK) || (lnt && (lnt < HIST_MIN)) ) - { - return ( SCPE_ARG ) ; - } -hist_p = 0; -if ( hist_cnt ) - { - free( hist ) ; - hist_cnt = 0 ; - hist = NULL ; - } -if ( lnt ) - { - hist = (Hist_entry *) calloc( lnt, sizeof(Hist_entry) ) ; - if ( hist == NULL ) - { - return ( SCPE_MEM ) ; - } - hist_cnt = lnt ; - } -return ( SCPE_OK ) ; -} /* end of 'hist_set' */ - - -int hist_fprintf( FILE * fp, int itemNum, Hist_entry * hptr ) -{ -extern t_value *sim_eval ; - -if ( hptr ) - { - if ( itemNum == 0 ) - { - fprintf( fp, "\n\n" ) ; - } - fprintf( fp, "%05o / %06o %06o %06o %06o %06o %o ", - (hptr->pc & 0x7FFF), - (hptr->ir & 0xFFFF), - (hptr->ac0 & 0xFFFF), - (hptr->ac1 & 0xFFFF), - (hptr->ac2 & 0xFFFF), - (hptr->ac3 & 0xFFFF), - ((hptr->carry) ? 1 : 0) - ) ; - if ( cpu_unit.flags & UNIT_STK /* Nova 3 or Nova 4 */ ) - { - fprintf( fp, "%06o %06o ", SP, FP ) ; - } - - sim_eval[0] = (hptr->ir & 0xFFFF) ; - if ( (fprint_sym(fp, (hptr->pc & AMASK), sim_eval, &cpu_unit, SWMASK ('M'))) > 0 ) - { - fprintf( fp, "(undefined) %04o", (hptr->ir & 0xFFFF) ) ; - } - /* - display ION flag value, pend value? - display devBusy, devDone, devIntr info? - */ - - if ( 0 ) /* display INTRP codes? */ - { - char tmp[ 500 ] ; - - devBitNames( hptr->devIntr, tmp, NULL ) ; - fprintf( fp, " %s", tmp ) ; - } - - fprintf( fp, "\n" ) ; - } -return ( 0 ) ; -} /* end of 'hist_fprintf' */ - - -/* show execution history (proposed global routine) */ - -t_stat hist_show( FILE * st, UNIT * uptr, int32 val, void * desc ) -{ -int32 k, di, lnt ; -char * cptr = (char *) desc ; -t_stat r ; -Hist_entry * hptr ; - - -if (hist_cnt == 0) - { - return ( SCPE_NOFNC ) ; /* enabled? */ - } -if ( cptr ) - { /* number of entries specified */ - lnt = (int32) get_uint( cptr, 10, hist_cnt, &r ) ; - if ( (r != SCPE_OK) || (lnt == 0) ) - { - return ( SCPE_ARG ) ; - } - } - else - { - lnt = hist_cnt ; /* display all entries */ - } - di = hist_p - lnt; /* work forward */ - if ( di < 0 ) - { - di = di + hist_cnt ; - } - -for ( k = 0 ; k < lnt ; ++k ) - { /* print specified */ - hptr = &hist[ (++di) % hist_cnt] ; /* entry pointer */ - if ( hptr->ir != HIST_IR_INVALID ) /* valid entry? */ - { - hist_fprintf( st, k, hptr ) ; - } /* end else instruction */ - } /* end for */ -return SCPE_OK; -} /* end of 'hist_show' */ - - - -struct Dbits - { - int32 dBit ; - int32 dInvertMask ; - char * dName ; - } devBits [] = - - { - { INT_TRAP, 0, "TRAP" }, /* (in order of approximate DG interrupt mask priority) */ - { INT_ION, 0, "ION" }, - { INT_NO_ION_PENDING, 1, "IONPND" }, /* (invert this logic to provide cleaner display) */ - { INT_STK, 0, "STK" }, - { INT_PIT, 0, "PIT" }, - { INT_DKP, 0, "DKP" }, - { INT_DSK, 0, "DSK" }, - { INT_MTA, 0, "MTA" }, - { INT_LPT, 0, "LPT" }, - { INT_PTR, 0, "PTR" }, - { INT_PTP, 0, "PTP" }, - { INT_PLT, 0, "PLT" }, - { INT_CLK, 0, "CLK" }, - { INT_ALM, 0, "ALM" }, - { INT_QTY, 0, "QTY" }, - { INT_TTO1, 0, "TTO1" }, - { INT_TTI1, 0, "TTI1" }, - { INT_TTO, 0, "TTO" }, - { INT_TTI, 0, "TTI" }, - { 0, 0, NULL } - } ; - - -char * devBitNames( int32 flags, char * ptr, char * sepStr ) -{ -int a ; - -if ( ptr ) - { - *ptr = 0 ; - for ( a = 0 ; (devBits[a].dBit) ; ++a ) - if ( devBits[a].dBit & ((devBits[a].dInvertMask)? ~flags : flags) ) - { - if ( *ptr ) - { - strcat( ptr, (sepStr) ? sepStr : " " ) ; - strcat( ptr, devBits[a].dName ) ; - } - else - { - strcpy( ptr, devBits[a].dName ) ; - } - } - } -return ( ptr ) ; -} /* end of 'devBitNames' */ diff --git a/NOVA/nova_defs.h b/NOVA/nova_defs.h deleted file mode 100644 index 207c1c69..00000000 --- a/NOVA/nova_defs.h +++ /dev/null @@ -1,329 +0,0 @@ -/* nova_defs.h: NOVA/Eclipse simulator definitions - - Copyright (c) 1993-2012, 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. - - 25-Mar-12 RMS Added missing parameters to prototypes (Mark Pizzolato) - 22-May-10 RMS Added check for 64b definitions - 04-Jul-07 BKR BUSY/DONE/INTR "convenience" macros added, - INT_TRAP added for Nova 3, 4 trap instruction handling, - support for 3rd-party 64KW Nova extensions added, - removed STOP_IND_TRP definition due to common INT/TRP handling - 14-Jan-04 BKR Added support for QTY and ALM - 22-Nov-03 CEO Added support for PIT device - 19-Jan-03 RMS Changed CMASK to CDMASK for Apple Dev kit conflict - 03-Oct-02 RMS Added device information structure - 22-Dec-00 RMS Added Bruce Ray's second terminal support - 10-Dec-00 RMS Added Charles Owen's Eclipse support - 08-Dec-00 RMS Added Bruce Ray's plotter support - 15-Oct-00 RMS Added stack, byte, trap instructions - 14-Apr-99 RMS Changed t_addr to unsigned - 16-Mar-95 RMS Added dynamic memory size - 06-Dec-95 RMS Added magnetic tape - - The author gratefully acknowledges the help of Tom West, Diana Englebart, - Carl Friend, Bruce Ray, and Charles Owen in resolving questions about - the NOVA. -*/ - -#ifndef NOVA_DEFS_H_ -#define NOVA_DEFS_H_ 0 - -#include "sim_defs.h" /* simulator defns */ - -#if defined(USE_INT64) || defined(USE_ADDR64) -#error "Nova does not support 64b values!" -#endif - -/* Simulator stop codes */ - -#define STOP_RSRV 1 /* must be 1 */ -#define STOP_HALT 2 /* HALT */ -#define STOP_IBKPT 3 /* breakpoint */ -#define STOP_IND 4 /* indirect loop */ -#define STOP_IND_INT 5 /* ind loop, intr or trap */ - - -/* Memory */ - -#if defined (ECLIPSE) - /*----------------------*/ - /* Eclipse */ - /*----------------------*/ - -#define MAXMEMSIZE 1048576 /* max memory size in 16-bit words */ -#define PAMASK (MAXMEMSIZE - 1) /* physical addr mask */ -#define MEM_ADDR_OK(x) (((uint32) (x)) < (uint32) MEMSIZE) - -#else - /*----------------------*/ - /* Nova */ - /*----------------------*/ - -#define MAXMEMSIZE 65536 /* max memory size in 16-bit words: 32KW = DG max, */ - /* 64 KW = 3rd-party extended memory feature */ -#define DFTMEMSIZE 32768 /* default/initial mem size */ -#define MEM_ADDR_OK(x) (((uint32) (x)) < (uint32) MEMSIZE) - -#endif - - -#define MEMSIZE (cpu_unit.capac) /* actual memory size */ -#define A_V_IND 15 /* ind: indirect */ -#define A_IND (1 << A_V_IND) - -/* Architectural constants */ - -#define SIGN 0100000 /* sign */ -#define DMASK 0177777 /* data mask */ -#define CBIT (DMASK + 1) /* carry bit */ -#define CDMASK (CBIT | DMASK) /* carry + data */ - -/* Reserved memory locations */ - -#define INT_SAV 0 /* intr saved PC */ -#define INT_JMP 1 /* intr jmp @ */ -#define STK_JMP 3 /* stack jmp @ */ -#define TRP_SAV 046 /* trap saved PC */ -#define TRP_JMP 047 /* trap jmp @ */ - -#define AUTO_TOP 037 /* top of autoindex */ -#define AUTO_DEC 030 /* start autodec */ -#define AUTO_INC 020 /* start autoinc */ - - -/* Instruction format */ - -#define I_OPR 0100000 /* operate */ -#define I_M_SRC 03 /* OPR: src AC */ -#define I_V_SRC 13 -#define I_GETSRC(x) (((x) >> I_V_SRC) & I_M_SRC) -#define I_M_DST 03 /* dst AC */ -#define I_V_DST 11 -#define I_GETDST(x) (((x) >> I_V_DST) & I_M_DST) -#define I_M_ALU 07 /* OPR: ALU op */ -#define I_V_ALU 8 -#define I_GETALU(x) (((x) >> I_V_ALU) & I_M_ALU) -#define I_M_SHF 03 /* OPR: shift */ -#define I_V_SHF 6 -#define I_GETSHF(x) (((x) >> I_V_SHF) & I_M_SHF) -#define I_M_CRY 03 /* OPR: carry */ -#define I_V_CRY 4 -#define I_GETCRY(x) (((x) >> I_V_CRY) & I_M_CRY) -#define I_V_NLD 3 /* OPR: no load */ -#define I_NLD (1 << I_V_NLD) -#define I_M_SKP 07 /* OPR: skip */ -#define I_V_SKP 0 -#define I_GETSKP(x) (((x) >> I_V_SKP) & I_M_SKP) - -#define I_M_OPAC 017 /* MRF: opcode + AC */ -#define I_V_OPAC 11 -#define I_GETOPAC(x) (((x) >> I_V_OPAC) & I_M_OPAC) -#define I_V_IND 10 /* MRF: indirect */ -#define I_IND (1 << I_V_IND) -#define I_M_MODE 03 /* MRF: mode */ -#define I_V_MODE 8 -#define I_GETMODE(x) (((x) >> I_V_MODE) & I_M_MODE) -#define I_M_DISP 0377 /* MRF: disp */ -#define I_V_DISP 0 -#define I_GETDISP(x) (((x) >> I_V_DISP) & I_M_DISP) -#define DISPSIZE (I_M_DISP + 1) /* page size */ -#define DISPSIGN (DISPSIZE >> 1) /* page sign */ - -#define I_M_IOT 07 /* IOT: code */ -#define I_V_IOT 8 -#define I_GETIOT(x) (((x) >> I_V_IOT) & I_M_IOT) -#define I_M_PULSE 03 /* IOT pulse */ -#define I_V_PULSE 6 -#define I_GETPULSE(x) (((x) >> I_V_PULSE) & I_M_PULSE) -#define I_M_DEV 077 /* IOT: device */ -#define I_V_DEV 0 -#define I_GETDEV(x) (((x) >> I_V_DEV) & I_M_DEV) - -#define I_M_XOP 037 /* XOP: code */ -#define I_V_XOP 6 -#define I_GETXOP(x) (((x) >> I_V_XOP) & I_M_XOP) - -/* IOT return codes */ - -#define IOT_V_REASON 16 /* set reason */ -#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */ - -/* IOT fields */ - -#define ioNIO 0 /* opcode field */ -#define ioDIA 1 -#define ioDOA 2 -#define ioDIB 3 -#define ioDOB 4 -#define ioDIC 5 -#define ioDOC 6 -#define ioSKP 7 - -#define iopN 0 /* pulse field */ -#define iopS 1 -#define iopC 2 -#define iopP 3 - -/* Device numbers */ - -#define DEV_LOW 010 /* lowest intr dev */ -#define DEV_HIGH 051 /* highest intr dev */ -#define DEV_MDV 001 /* multiply/divide */ -#define DEV_ECC 002 /* ECC memory control */ -#define DEV_MAP 003 /* MMPU control */ -#define DEV_TTI 010 /* console input */ -#define DEV_TTO 011 /* console output */ -#define DEV_PTR 012 /* paper tape reader */ -#define DEV_PTP 013 /* paper tape punch */ -#define DEV_CLK 014 /* clock */ -#define DEV_PLT 015 /* plotter */ -#define DEV_CDR 016 /* card reader */ -#define DEV_LPT 017 /* line printer */ -#define DEV_DSK 020 /* fixed head disk */ -#define DEV_MTA 022 /* magtape */ -#define DEV_DCM 024 /* data comm mux */ -#define DEV_ADCV 030 /* A/D converter */ -#define DEV_QTY 030 /* 4060 multiplexor */ -#define DEV_DKP 033 /* disk pack */ -#define DEV_CAS 034 /* cassette */ -#define DEV_ALM 034 /* ALM/ULM multiplexor */ -#define DEV_PIT 043 /* programmable interval timer */ -#define DEV_TTI1 050 /* second console input */ -#define DEV_TTO1 051 /* second console output */ -#define DEV_CPU 077 /* CPU control */ - -/* I/O structure - - The NOVA I/O structure is tied together by dev_table, indexed by - the device number. Each entry in dev_table consists of - - mask device mask for busy, done (simulator representation) - pi pi disable bit (hardware representation) - routine IOT action routine - - dev_table is populated at run time from the device information - blocks in each device. -*/ - -struct ndev { - int32 mask; /* done/busy mask */ - int32 pi; /* assigned pi bit */ - int32 (*routine)(int32, int32, int32); /* dispatch routine */ - }; - -typedef struct { - int32 dnum; /* device number */ - int32 mask; /* done/busy mask */ - int32 pi; /* assigned pi bit */ - int32 (*routine)(int32, int32, int32); /* dispatch routine */ - } DIB; - -/* Device flags (simulator representation) - - Priority (for INTA) runs from low numbers to high -*/ - -#define INT_V_PIT 2 /* PIT */ -#define INT_V_DKP 3 /* moving head disk */ -#define INT_V_DSK 4 /* fixed head disk */ -#define INT_V_MTA 5 /* magnetic tape */ -#define INT_V_LPT 6 /* line printer */ -#define INT_V_CLK 7 /* clock */ -#define INT_V_PTR 8 /* paper tape reader */ -#define INT_V_PTP 9 /* paper tape punch */ -#define INT_V_PLT 10 /* plotter */ -#define INT_V_TTI 11 /* keyboard */ -#define INT_V_TTO 12 /* terminal */ -#define INT_V_TTI1 13 /* second keyboard */ -#define INT_V_TTO1 14 /* second terminal */ -#define INT_V_QTY 15 /* QTY multiplexor */ -#define INT_V_ALM 16 /* ALM multiplexor */ -#define INT_V_STK 17 /* stack overflow */ -#define INT_V_NO_ION_PENDING 18 /* ion delay */ -#define INT_V_ION 19 /* interrupts on */ -#define INT_V_TRAP 20 /* trap instruction */ - -#define INT_PIT (1 << INT_V_PIT) -#define INT_DKP (1 << INT_V_DKP) -#define INT_DSK (1 << INT_V_DSK) -#define INT_MTA (1 << INT_V_MTA) -#define INT_LPT (1 << INT_V_LPT) -#define INT_CLK (1 << INT_V_CLK) -#define INT_PTR (1 << INT_V_PTR) -#define INT_PTP (1 << INT_V_PTP) -#define INT_PLT (1 << INT_V_PLT) -#define INT_TTI (1 << INT_V_TTI) -#define INT_TTO (1 << INT_V_TTO) -#define INT_TTI1 (1 << INT_V_TTI1) -#define INT_TTO1 (1 << INT_V_TTO1) -#define INT_QTY (1 << INT_V_QTY) -#define INT_ALM (1 << INT_V_ALM) -#define INT_STK (1 << INT_V_STK) -#define INT_NO_ION_PENDING (1 << INT_V_NO_ION_PENDING) -#define INT_ION (1 << INT_V_ION) -#define INT_DEV ((1 << INT_V_STK) - 1) /* device ints */ -#define INT_PENDING INT_ION+INT_NO_ION_PENDING -#define INT_TRAP (1 << INT_V_TRAP) - -/* PI disable bits */ - -#define PI_PIT 0001000 -#define PI_DKP 0000400 -#define PI_DSK 0000100 -#define PI_MTA 0000040 -#define PI_LPT 0000010 -#define PI_CLK 0000004 -#define PI_PTR 0000020 -#define PI_PTP 0000004 -#define PI_PLT 0000010 -#define PI_QTY 0000002 -#define PI_ALM 0000002 -#define PI_TTI 0000002 -#define PI_TTO 0000001 -#define PI_TTI1 PI_TTI -#define PI_TTO1 PI_TTO -/* #define PI_CDR 0000040 */ -/* #define PI_DCM 0100000 */ -/* #define PI_CAS 0000040 */ -/* #define PI_ADCV 0000002 */ - - - /* Macros to clear/set BUSY/DONE/INTR bits */ - -#define DEV_SET_BUSY( x ) dev_busy = dev_busy | (x) -#define DEV_CLR_BUSY( x ) dev_busy = dev_busy & (~(x)) -#define DEV_SET_DONE( x ) dev_done = dev_done | (x) -#define DEV_CLR_DONE( x ) dev_done = dev_done & (~(x)) -#define DEV_UPDATE_INTR int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable) - -#define DEV_IS_BUSY( x ) (dev_busy & (x)) -#define DEV_IS_DONE( x ) (dev_done & (x)) - -/* Function prototypes */ - -int32 MapAddr (int32 map, int32 addr); -t_stat set_enb (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat set_dsb (UNIT *uptr, int32 val, char *cptr, void *desc); - -#endif diff --git a/NOVA/nova_dkp.c b/NOVA/nova_dkp.c deleted file mode 100644 index c9d50cec..00000000 --- a/NOVA/nova_dkp.c +++ /dev/null @@ -1,1095 +0,0 @@ -/* nova_dkp.c: NOVA moving head disk simulator - - Copyright (c) 1993-2008, 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. - - dkp moving head disk - - 27-Apr-12 RMS Changed ??? string digraphs to ?, per C rules - 04-Jul-04 BKR device name changed to DG's DKP from DEC's DP, - DEV_SET/CLR/INTR macro use started, - fixed 'P' pulse code and secret quirks, - added 6097 diag and size support, - fixed losing unit drive type during unit change, - tightened sector size determination calculations, - controller DONE flag handling fixed, - fixed cylinder overflow test error, - seek error code fixed, - restructured dkp_go() and dkp_svc() routines - (for known future fixes needed), - fixed DIA status calculation, - fixed DKP read/write loop to properly emulate DG cylinder and sector overflows, - added trace facility, - changed 'stime' calculation to force delay time if no cylinders are crossed - (this fixes some DG code that assumes disk seek takes some time), - fixed boot code to match DG hardware standard - 04-Jan-04 RMS Changed attach routine to use sim_fsize - 28-Nov-03 CEO Boot from DP now puts device address in SR - 24-Nov-03 CEO Added support for disk sizing on 6099/6103 - 19-Nov-03 CEO Corrected major DMA Mapping bug - 25-Apr-03 RMS Revised autosizing - 08-Oct-02 RMS Added DIB - 06-Jan-02 RMS Revised enable/disable support - 30-Nov-01 RMS Added read only unit, extended SET/SHOW support - 24-Nov-01 RMS Changed FLG, CAPAC to arrays - 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 - 14-Apr-99 RMS Changed t_addr to unsigned - 15-Sep-97 RMS Fixed bug in DIB/DOB for new disks - 15-Sep-97 RMS Fixed bug in cylinder extraction (found by Charles Owen) - 10-Sep-97 RMS Fixed bug in error reporting (found by Charles Owen) - 25-Nov-96 RMS Defaulted to autosize - 29-Jun-96 RMS Added unit disable support -*/ - -#include "nova_defs.h" - -#define DKP_NUMDR 4 /* #drives */ -#define DKP_NUMWD 256 /* words/sector */ -#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */ -#define UNIT_M_DTYPE 017 -#define UNIT_V_AUTO (UNIT_V_UF + 5) /* autosize */ -#define UNIT_WLK (1 << UNIT_V_WLK) -#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE) -#define UNIT_AUTO (1 << UNIT_V_AUTO) -#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 - - Original format: 2b, 6b, 4b, 4b - Revised format: 2b, 5b, 5b, 4b -*/ - -#define USSC_V_COUNT 0 /* count */ -#define USSC_M_COUNT 017 -#define USSC_V_OSECTOR 4 /* old: sector */ -#define USSC_M_OSECTOR 017 -#define USSC_V_OSURFACE 8 /* old: surface */ -#define USSC_M_OSURFACE 077 -#define USSC_V_NSECTOR 4 /* new: sector */ -#define USSC_M_NSECTOR 037 -#define USSC_V_NSURFACE 9 /* new: surface */ -#define USSC_M_NSURFACE 037 -#define USSC_V_UNIT 14 /* unit */ -#define USSC_M_UNIT 03 -#define USSC_UNIT (USSC_M_UNIT << USSC_V_UNIT) -#define GET_COUNT(x) (((x) >> USSC_V_COUNT) & USSC_M_COUNT) -#define GET_SECT(x,dt) ((drv_tab[dt].newf)? \ - (((x) >> USSC_V_NSECTOR) & USSC_M_NSECTOR): \ - (((x) >> USSC_V_OSECTOR) & USSC_M_OSECTOR) ) -#define GET_SURF(x,dt) ((drv_tab[dt].newf)? \ - (((x) >> USSC_V_NSURFACE) & USSC_M_NSURFACE): \ - (((x) >> USSC_V_OSURFACE) & USSC_M_OSURFACE) ) -#define GET_UNIT(x) (((x) >> USSC_V_UNIT) & USSC_M_UNIT) - -/* Flags, command, cylinder register - - Original format: 5b, 2b, 1b + 8b (surrounding command) - Revised format: 5b, 2b, 9b -*/ - -#define FCCY_V_OCYL 0 /* old: cylinder */ -#define FCCY_M_OCYL 0377 -#define FCCY_V_OCMD 8 /* old: command */ -#define FCCY_M_OCMD 3 -#define FCCY_V_OCEX 10 /* old: cyl extend */ -#define FCCY_OCEX (1 << FCCY_V_OCEX) -#define FCCY_V_NCYL 0 /* new: cylinder */ -#define FCCY_M_NCYL 0777 -#define FCCY_V_NCMD 9 /* new: command */ -#define FCCY_M_NCMD 3 -#define FCCY_READ 0 -#define FCCY_WRITE 1 -#define FCCY_SEEK 2 -#define FCCY_RECAL 3 -#define FCCY_FLAGS 0174000 /* flags */ - -#define GET_CMD(x,dt) ((drv_tab[dt].newf)? \ - (((x) >> FCCY_V_NCMD) & FCCY_M_NCMD): \ - (((x) >> FCCY_V_OCMD) & FCCY_M_OCMD) ) - -#define SET_CMD(x,dt) dkp_fccy = (dkp_fccy & ((drv_tab[dt].newf)? \ - (FCCY_M_NCMD << FCCY_V_NCMD) : (FCCY_M_OCMD << FCCY_V_OCMD))) | \ - ((drv_tab[dt].newf)? \ - (((x) & FCCY_M_NCMD) << FCCY_V_NCMD): \ - (((x) & FCCY_M_OCMD) << FCCY_V_OCMD) ) - -#define GET_CYL(x,dt) ((drv_tab[dt].newf)? \ - (((x) >> FCCY_V_NCYL) & FCCY_M_NCYL): \ - ((((x) >> FCCY_V_OCYL) & FCCY_M_OCYL) | \ - ((dt != TYPE_D44)? 0: \ - (((x) & FCCY_OCEX) >> (FCCY_V_OCEX - FCCY_V_OCMD)))) ) - - - /* (Warning: no sector or surface masking is done!) */ - -#define DKP_UPDATE_USSC( type, count, surf, sect ) \ - dkp_ussc = (dkp_ussc & USSC_UNIT) \ - | ((dkp_ussc + count) & USSC_M_COUNT) \ - | ((drv_tab[dtype].newf)? \ - ((surf << USSC_V_NSURFACE) | (sect << USSC_V_NSECTOR)): \ - ((surf << USSC_V_OSURFACE) | (sect << USSC_V_OSECTOR)) \ - ); - - -/* Status */ - -#define STA_ERR 0000001 /* error */ -#define STA_DLT 0000002 /* data late */ -#define STA_CRC 0000004 /* crc error */ -#define STA_UNS 0000010 /* unsafe */ -#define STA_XCY 0000020 /* cross cylinder */ -#define STA_CYL 0000040 /* nx cylinder */ -#define STA_DRDY 0000100 /* drive ready */ -#define STA_SEEK3 0000200 /* seeking unit 3 */ -#define STA_SEEK2 0000400 /* seeking unit 2 */ -#define STA_SEEK1 0001000 /* seeking unit 1 */ -#define STA_SEEK0 0002000 /* seeking unit 0 */ -#define STA_SKDN3 0004000 /* seek done unit 3 */ -#define STA_SKDN2 0010000 /* seek done unit 2 */ -#define STA_SKDN1 0020000 /* seek done unit 1 */ -#define STA_SKDN0 0040000 /* seek done unit 0 */ -#define STA_DONE 0100000 /* operation done */ - -#define STA_DYN (STA_DRDY | STA_CYL) /* set from unit */ -#define STA_EFLGS (STA_ERR | STA_DLT | STA_CRC | STA_UNS | \ - STA_XCY | STA_CYL) /* error flags */ -#define STA_DFLGS (STA_DONE | STA_SKDN0 | STA_SKDN1 | \ - STA_SKDN2 | STA_SKDN3) /* done flags */ - -#define GET_SA(cy,sf,sc,t) (((((cy)*drv_tab[t].surf)+(sf))* \ - drv_tab[t].sect)+(sc)) - -/* This controller supports many different disk drive types: - - type #sectors/ #surfaces/ #cylinders/ new format? - surface cylinder drive - - floppy 8 1 77 no - DS/DD floppy 16 2 77 yes - (6097 "quad floppy") - Diablo 31 12 2 203 no - 6225 20 2 245 yes - Century 111 6 10 203 no - 4048 (same as Century 111) - Diablo 44 12 4 408 no - 6099 32 4 192 yes - 6227 20 6 245 yes - 6070 24 4 408 yes - Century 114 12 20 203 no - 4057 (same as Century 114) - 6103 32 8 192 yes - 4231 23 19 411 yes - - In theory, each drive can be a different type. The size field in - each unit selects the drive capacity for each drive and thus the - drive type. DISKS MUST BE DECLARED IN ASCENDING SIZE. -*/ - -#define TYPE_FLP 0 -#define SECT_FLP 8 -#define SURF_FLP 1 -#define CYL_FLP 77 -#define SIZE_FLP (SECT_FLP * SURF_FLP * CYL_FLP * DKP_NUMWD) -#define NFMT_FLP FALSE - -#define TYPE_DSDD 1 -#define TYPE_6097 TYPE_DSDD -#define SECT_DSDD 16 -#define SURF_DSDD 2 -#define CYL_DSDD 77 -#define SIZE_DSDD (SECT_DSDD * SURF_DSDD * CYL_DSDD * DKP_NUMWD) -#define NFMT_DSDD TRUE - -#define TYPE_D31 2 -#define SECT_D31 12 -#define SURF_D31 2 -#define CYL_D31 203 -#define SIZE_D31 (SECT_D31 * SURF_D31 * CYL_D31 * DKP_NUMWD) -#define NFMT_D31 FALSE - -#define TYPE_6225 3 -#define SECT_6225 20 -#define SURF_6225 2 -#define CYL_6225 245 -#define SIZE_6225 (SECT_6225 * SURF_6225 * CYL_6225 * DKP_NUMWD) -#define NFMT_6225 TRUE - -#define TYPE_C111 4 -#define SECT_C111 6 -#define SURF_C111 10 -#define CYL_C111 203 -#define SIZE_C111 (SECT_C111 * SURF_C111 * CYL_C111 * DKP_NUMWD) -#define NFMT_C111 FALSE - -#define TYPE_D44 5 -#define SECT_D44 12 -#define SURF_D44 4 -#define CYL_D44 408 -#define SIZE_D44 (SECT_D44 * SURF_D44 * CYL_D44 * DKP_NUMWD) -#define NFMT_D44 FALSE - -#define TYPE_6099 6 -#define SECT_6099 32 -#define SURF_6099 4 -#define CYL_6099 192 -#define SIZE_6099 (SECT_6099 * SURF_6099 * CYL_6099 * DKP_NUMWD) -#define NFMT_6099 TRUE - -#define TYPE_6227 7 -#define SECT_6227 20 -#define SURF_6227 6 -#define CYL_6227 245 -#define SIZE_6227 (SECT_6227 * SURF_6227 * CYL_6227 * DKP_NUMWD) -#define NFMT_6227 TRUE - -#define TYPE_6070 8 -#define SECT_6070 24 -#define SURF_6070 4 -#define CYL_6070 408 -#define SIZE_6070 (SECT_6070 * SURF_6070 * CYL_6070 * DKP_NUMWD) -#define NFMT_6070 TRUE - -#define TYPE_C114 9 -#define SECT_C114 12 -#define SURF_C114 20 -#define CYL_C114 203 -#define SIZE_C114 (SECT_C114 * SURF_C114 * CYL_C114 * DKP_NUMWD) -#define NFMT_C114 FALSE - -#define TYPE_6103 10 -#define SECT_6103 32 -#define SURF_6103 8 -#define CYL_6103 192 -#define SIZE_6103 (SECT_6103 * SURF_6103 * CYL_6103 * DKP_NUMWD) -#define NFMT_6103 TRUE - -#define TYPE_4231 11 -#define SECT_4231 23 -#define SURF_4231 19 -#define CYL_4231 411 -#define SIZE_4231 (SECT_4231 * SURF_4231 * CYL_4231 * DKP_NUMWD) -#define NFMT_4231 TRUE - -struct drvtyp { - int32 sect; /* sectors */ - int32 surf; /* surfaces */ - int32 cyl; /* cylinders */ - int32 size; /* #blocks */ - int32 newf; /* new format flag */ - }; - -struct drvtyp drv_tab[] = { - { SECT_FLP, SURF_FLP, CYL_FLP, SIZE_FLP, NFMT_FLP }, - { SECT_DSDD, SURF_DSDD, CYL_DSDD, SIZE_DSDD, NFMT_DSDD }, - { SECT_D31, SURF_D31, CYL_D31, SIZE_D31, NFMT_D31 }, - { SECT_6225, SURF_6225, CYL_6225, SIZE_6225, NFMT_6225 }, - { SECT_C111, SURF_C111, CYL_C111, SIZE_C111, NFMT_C111 }, - { SECT_D44, SURF_D44, CYL_D44, SIZE_D44, NFMT_D44 }, - { SECT_6099, SURF_6099, CYL_6099, SIZE_6099, NFMT_6099 }, - { SECT_6227, SURF_6227, CYL_6227, SIZE_6227, NFMT_6227 }, - { SECT_6070, SURF_6070, CYL_6070, SIZE_6070, NFMT_6070 }, - { SECT_C114, SURF_C114, CYL_C114, SIZE_C114, NFMT_C114 }, - { SECT_6103, SURF_6103, CYL_6103, SIZE_6103, NFMT_6103 }, - { SECT_4231, SURF_4231, CYL_4231, SIZE_4231, NFMT_4231 }, - { 0 } - }; - -#define DKP_TRACE(x) (dkp_trace & (1<<(x))) -#define DKP_TRACE_FP stderr -/* current trace bit use (bit 0 = LSB) - 0 I/O instructions - 1 pre-seek/read/write event setup - 2 seek events - 3 read/write events - 4 post read/write events - */ - -extern uint16 M[]; -extern UNIT cpu_unit; -extern int32 int_req, dev_busy, dev_done, dev_disable; -extern int32 saved_PC, SR, AMASK; - -int32 dkp_ma = 0; /* memory address */ -int32 dkp_map = 0; /* DCH map 0=A 3=B */ -int32 dkp_ussc = 0; /* unit/sf/sc/cnt */ -int32 dkp_fccy = 0; /* flags/cylinder */ -int32 dkp_sta = 0; /* status register */ -int32 dkp_swait = 100; /* seek latency */ -int32 dkp_rwait = 100; /* rotate latency */ -int32 dkp_diagmode = 0; /* diagnostic mode */ - -int32 dkp_trace = 0 ; - -DEVICE dkp_dev; -int32 dkp (int32 pulse, int32 code, int32 AC); -t_stat dkp_svc (UNIT *uptr); -t_stat dkp_reset (DEVICE *dptr); -t_stat dkp_boot (int32 unitno, DEVICE *dptr); -t_stat dkp_attach (UNIT *uptr, char *cptr); -t_stat dkp_go ( int32 pulse ); -t_stat dkp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); - -/* DKP data structures - - dkp_dev DKP device descriptor - dkp_unit DKP unit list - dkp_reg DKP register list - dkp_mod DKP modifier list -*/ - -DIB dkp_dib = { DEV_DKP, INT_DKP, PI_DKP, &dkp }; - -UNIT dkp_unit[] = { - { UDATA (&dkp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - UNIT_ROABLE+(TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) }, - { UDATA (&dkp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - UNIT_ROABLE+(TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) }, - { UDATA (&dkp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - UNIT_ROABLE+(TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) }, - { UDATA (&dkp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - UNIT_ROABLE+(TYPE_D31 << UNIT_V_DTYPE), SIZE_D31) } - }; - -REG dkp_reg[] = { - { ORDATA (FCCY, dkp_fccy, 16) }, - { ORDATA (USSC, dkp_ussc, 16) }, - { ORDATA (STA, dkp_sta, 16) }, - { ORDATA (MA, dkp_ma, 16) }, - { FLDATA (INT, int_req, INT_V_DKP) }, - { FLDATA (BUSY, dev_busy, INT_V_DKP) }, - { FLDATA (DONE, dev_done, INT_V_DKP) }, - { FLDATA (DISABLE, dev_disable, INT_V_DKP) }, - { FLDATA (DIAG, dkp_diagmode, 0) }, - { DRDATA (TRACE, dkp_trace, 32) }, - { ORDATA (MAP, dkp_map, 2) }, - { DRDATA (STIME, dkp_swait, 24), PV_LEFT }, - { DRDATA (RTIME, dkp_rwait, 24), PV_LEFT }, - { URDATA (CAPAC, dkp_unit[0].capac, 10, T_ADDR_W, 0, - DKP_NUMDR, PV_LEFT | REG_HRO) }, - { NULL } - }; - -MTAB dkp_mod[] = { - { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, - { (UNIT_DTYPE+UNIT_ATT), (TYPE_FLP << UNIT_V_DTYPE) + UNIT_ATT, - "6030 (floppy)", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (TYPE_DSDD << UNIT_V_DTYPE) + UNIT_ATT, - "6097 (DS/DD floppy)", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (TYPE_D31 << UNIT_V_DTYPE) + UNIT_ATT, - "4047 (Diablo 31)", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (TYPE_D44 << UNIT_V_DTYPE) + UNIT_ATT, - "4234/6045 (Diablo 44)", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (TYPE_C111 << UNIT_V_DTYPE) + UNIT_ATT, - "4048 (Century 111)", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (TYPE_C114 << UNIT_V_DTYPE) + UNIT_ATT, - "2314/4057 (Century 114)", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (TYPE_6225 << UNIT_V_DTYPE) + UNIT_ATT, - "6225", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (TYPE_6227 << UNIT_V_DTYPE) + UNIT_ATT, - "6227", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (TYPE_6099 << UNIT_V_DTYPE) + UNIT_ATT, - "6099", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (TYPE_6103 << UNIT_V_DTYPE) + UNIT_ATT, - "6103", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (TYPE_6070 << UNIT_V_DTYPE) + UNIT_ATT, - "6070", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (TYPE_4231 << UNIT_V_DTYPE) + UNIT_ATT, - "4231/3330", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_FLP << UNIT_V_DTYPE), - "6030 (floppy)", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_DSDD << UNIT_V_DTYPE), - "6097 (DS/DD floppy)", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_D31 << UNIT_V_DTYPE), - "4047 (Diablo 31)", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_D44 << UNIT_V_DTYPE), - "4234/6045 (Diablo 44)", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_C111 << UNIT_V_DTYPE), - "4048 (Century 111)", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_C114 << UNIT_V_DTYPE), - "2314/4057 (Century 114)", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_6225 << UNIT_V_DTYPE), - "6225", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_6227 << UNIT_V_DTYPE), - "6227", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_6099 << UNIT_V_DTYPE), - "6099", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_6103 << UNIT_V_DTYPE), - "6103", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_6070 << UNIT_V_DTYPE), - "6070", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (TYPE_4231 << UNIT_V_DTYPE), - "4231/3330", NULL, NULL }, - { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL }, - { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_FLP << UNIT_V_DTYPE), - NULL, "FLOPPY", &dkp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_FLP << UNIT_V_DTYPE), - NULL, "6030", &dkp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_DSDD << UNIT_V_DTYPE), - NULL, "DSDDFLOPPY", &dkp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_DSDD << UNIT_V_DTYPE), - NULL, "6097", &dkp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_D31 << UNIT_V_DTYPE), - NULL, "D31", &dkp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_D31 << UNIT_V_DTYPE), - NULL, "4047", &dkp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_D44 << UNIT_V_DTYPE), - NULL, "D44", &dkp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_D44 << UNIT_V_DTYPE), - NULL, "4234", &dkp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_D44 << UNIT_V_DTYPE), - NULL, "6045", &dkp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_C111 << UNIT_V_DTYPE), - NULL, "C111", &dkp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_C111 << UNIT_V_DTYPE), - NULL, "4048", &dkp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_C114 << UNIT_V_DTYPE), - NULL, "C114", &dkp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_C114 << UNIT_V_DTYPE), - NULL, "2314", &dkp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_C114 << UNIT_V_DTYPE), - NULL, "4057", &dkp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_6225 << UNIT_V_DTYPE), - NULL, "6225", &dkp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_6227 << UNIT_V_DTYPE), - NULL, "6227", &dkp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_6099 << UNIT_V_DTYPE), - NULL, "6099", &dkp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_6103 << UNIT_V_DTYPE), - NULL, "6103", &dkp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_6070 << UNIT_V_DTYPE), - NULL, "6070", &dkp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_4231 << UNIT_V_DTYPE), - NULL, "4231", &dkp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (TYPE_4231 << UNIT_V_DTYPE), - NULL, "3330", &dkp_set_size }, - { 0 } - }; - -DEVICE dkp_dev = { - "DKP", dkp_unit, dkp_reg, dkp_mod, - DKP_NUMDR, 8, 30, 1, 8, 16, - NULL, NULL, &dkp_reset, - &dkp_boot, &dkp_attach, NULL, - &dkp_dib, DEV_DISABLE - }; - - -/* IOT routine */ - -int32 dkp (int32 pulse, int32 code, int32 AC) -{ -UNIT *uptr; -int32 u, rval, dtype; - -rval = 0; -uptr = dkp_dev.units + GET_UNIT (dkp_ussc); /* select unit */ -dtype = GET_DTYPE (uptr->flags); /* get drive type */ - -if ( DKP_TRACE(0) ) - { - static char * f[8] = - { "NIO", "DIA", "DOA", "DIB", "DOB", "DIC", "DOC", "SKP" } ; - static char * s[4] = - { " ", "S", "C", "P" } ; - - printf( " [DKP %s%s %06o ", f[code & 0x07], s[pulse & 0x03], (AC & 0xFFFF) ) ; - } - -switch (code) { /* decode IR<5:7> */ - - case ioDIA: /* DIA */ - dkp_sta = dkp_sta & (~STA_DRDY) ; /* keep error flags */ - if (uptr->flags & UNIT_ATT) /* update ready */ - dkp_sta = dkp_sta | STA_DRDY; - if (uptr->CYL >= drv_tab[dtype].cyl) - dkp_sta = dkp_sta | STA_CYL; /* bad cylinder? */ - if (dkp_sta & STA_EFLGS) - dkp_sta = dkp_sta | STA_ERR; - rval = dkp_sta; - break; - - case ioDOA: /* DOA */ - if (AC & 0100000) /* clear rw done? */ - dkp_sta = dkp_sta & ~(STA_CYL|STA_XCY|STA_UNS|STA_CRC); - if ((dev_busy & INT_DKP) == 0) { - dkp_fccy = AC; /* save cmd, cyl */ - dkp_sta = dkp_sta & ~(AC & FCCY_FLAGS); - } - DEV_CLR_DONE( INT_DKP ); /* assume done flags 0 */ - if ( dkp_sta & STA_DFLGS ) /* done flags = 0? */ - DEV_SET_DONE( INT_DKP ) ; /* nope - set done */ - DEV_UPDATE_INTR ; /* update intr */ - break; - - case ioDIB: /* DIB */ - rval = dkp_ma & 077777 ; /* return buf addr */ - /* with B0 clear (no DCH B map support) */ - break; - - case ioDOB: /* DOB */ - if ((dev_busy & INT_DKP) == 0) { - dkp_ma = AC & (drv_tab[dtype].newf? DMASK: AMASK); - if (AC & 0100000) - dkp_map = 3; /* high bit is map */ - else - dkp_map = 0; - } - break; - - case ioDIC: /* DIC */ - rval = dkp_ussc; /* return unit, sect */ - break; - - case ioDOC: /* DOC */ - if ((dev_busy & INT_DKP) == 0) /* if device is not busy */ - dkp_ussc = AC ; /* save unit, sect */ - if (((dtype == TYPE_6099) || /* (BKR: don't forget 6097) */ - (dtype == TYPE_6097) || /* for 6099 and 6103 */ - (dtype == TYPE_6103)) && /* if data<0> set, */ - (AC & 010000) ) - dkp_diagmode = 1; /* set diagnostic mode */ - break; - } /* end switch code */ - -u = GET_UNIT(dkp_ussc); /* update current unit */ -uptr = dkp_dev.units + u ; /* select unit */ -dtype = GET_DTYPE (uptr->flags); /* get drive type */ - -if ( DKP_TRACE(0) ) - { - if ( code & 1 ) - printf( " [%06o] ", (rval & 0xFFFF) ) ; - printf( "] \n" ) ; - } - -switch (pulse) { /* decode IR<8:9> */ - - case iopS: /* start */ - DEV_SET_BUSY( INT_DKP ) ; /* set busy */ - DEV_CLR_DONE( INT_DKP ) ; /* clear done */ - DEV_UPDATE_INTR ; /* update ints */ - if (dkp_diagmode) { /* in diagnostic mode? */ - dkp_diagmode = 0; /* reset it */ - if (dtype == TYPE_6097) /* (BKR - quad floppy) */ - dkp_ussc = 010001; - if (dtype == TYPE_6099) /* return size bits */ - dkp_ussc = 010002; - if (dtype == TYPE_6103) /* for certain types */ - dkp_ussc = 010003; - } - else { /* normal mode ... */ - if (dkp_go (pulse)) /* do command */ - break ; /* break if no error */ - } - DEV_CLR_BUSY( INT_DKP ) ; /* clear busy */ - DEV_SET_DONE( INT_DKP ) ; /* set done */ - DEV_UPDATE_INTR ; /* update ints */ - dkp_sta = dkp_sta | STA_DONE; /* set controller done */ - break; - - case iopC: /* clear */ - DEV_CLR_BUSY( INT_DKP ) ; /* clear busy */ - DEV_CLR_DONE( INT_DKP ) ; /* set done */ - DEV_UPDATE_INTR ; /* update ints */ - dkp_sta = dkp_sta & ~(STA_DFLGS + STA_EFLGS); /* clear controller flags */ - if (dkp_unit[u].FUNC != FCCY_SEEK) - sim_cancel (&dkp_unit[u]); /* cancel any r/w op */ - break; - - case iopP: /* pulse */ - if ( dkp_diagmode ) - { - dkp_diagmode = 0 ; /* clear DG diagnostic mode */ - } - else - { - DEV_CLR_DONE( INT_DKP ) ; /* clear done */ - DEV_UPDATE_INTR ; - - /* DG "undocumented feature": 'P' pulse can not start a read/write operation! - * Diagnostic routines will use this crock to do 'crazy things' to size a disk - * and many assume that a recal is done, other assume that they can stop the - * read operation before any damage is done. Must also [re]calculate unit, function - * and type because DOx instruction may have updated the controller info after - * start of this procedure and before our 'P' handler. BKR - */ - if (dkp_go(pulse)) - break; /* no error - do not set done and status */ - } - - DEV_SET_DONE( INT_DKP ) ; /* set done */ - DEV_UPDATE_INTR ; /* update ints */ - dkp_sta = dkp_sta | (STA_SKDN0 >> u); /* set controller seek done */ - break; - } /* end case pulse */ - -return rval; -} - - -/* New command, start vs pulse handled externally - Returns true if command ok, false if error -*/ - -t_stat dkp_go ( int32 pulse ) -{ -UNIT *uptr; -int32 oldCyl, u, dtype; - -dkp_sta = dkp_sta & ~STA_EFLGS; /* clear errors */ -u = GET_UNIT (dkp_ussc); /* get unit number */ -uptr = dkp_dev.units + u; /* get unit */ -if (((uptr->flags & UNIT_ATT) == 0) || sim_is_active (uptr)) { - dkp_sta = dkp_sta | STA_ERR; /* attached or busy? */ - return FALSE; - } - -if (dkp_diagmode) { /* diagnostic mode? */ - dkp_sta = (dkp_sta | STA_DONE); /* Set error bit only */ - DEV_CLR_BUSY( INT_DKP ) ; /* clear busy */ - DEV_SET_DONE( INT_DKP ) ; /* set done */ - DEV_UPDATE_INTR ; /* update interrupts */ - return ( TRUE ) ; /* do not do function */ - } - -oldCyl = uptr->CYL ; /* get old cylinder */ -dtype = GET_DTYPE (uptr->flags); /* get drive type */ -uptr->FUNC = GET_CMD (dkp_fccy, dtype) ; /* save command */ -uptr->CYL = GET_CYL (dkp_fccy, dtype) ; - -if ( DKP_TRACE(1) ) - { - int32 xSect ; - int32 xSurf ; - int32 xCyl ; - int32 xCnt ; - - xSect = GET_SECT(dkp_ussc, dtype) ; - xSurf = GET_SURF(dkp_ussc, dtype) ; - xCyl = GET_CYL (dkp_fccy, dtype) ; - xCnt = 16 - (GET_COUNT(dkp_ussc)) ; - - fprintf( DKP_TRACE_FP, - " [%s:%c %-5s: %3d / %2d / %2d %2d %06o ] \r\n", - "DKP", - (char) (u + '0'), - ((uptr->FUNC == FCCY_READ) ? - "read" - : ((uptr->FUNC == FCCY_WRITE) ? - "write" - : ((uptr->FUNC == FCCY_SEEK) ? - "seek" - : "" - ) - ) - ), - (unsigned) xCyl, - (unsigned) xSurf, - (unsigned) xSect, - (unsigned) (16 - xCnt), - (unsigned) (dkp_ma & 0xFFFF) /* show all 16-bits in case DCH B */ - ) ; - } - - -switch (uptr->FUNC) { /* decode command */ - - case FCCY_READ: - case FCCY_WRITE: - if (((uptr->flags & UNIT_ATT) == 0) || /* not attached? */ - ((uptr->flags & UNIT_WPRT) && (uptr->FUNC == FCCY_WRITE))) - { - dkp_sta = dkp_sta | STA_DONE | STA_ERR; /* error */ - } - else if ( uptr->CYL >= drv_tab[dtype].cyl ) /* bad cylinder */ - { - dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_CYL ; - } - else if ( GET_SURF(dkp_ussc, dtype) >= drv_tab[dtype].surf ) /* bad surface */ - { - dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_UNS; /* older drives may not even do this... */ - /* dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_XCY ; /- newer disks give this error */ - } - else if ( GET_SECT(dkp_ussc, dtype) >= drv_tab[dtype].sect ) /* or bad sector? */ - { - /* dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_UNS; /- older drives may not even do this... */ - dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_XCY ; /* newer disks give this error */ - } - if ( (pulse != iopS) || (dkp_sta & STA_ERR) ) - { - return ( FALSE ) ; - } - sim_activate (uptr, dkp_rwait); /* schedule read or write request */ - break; - - case FCCY_RECAL: /* recalibrate */ - uptr->FUNC = FCCY_SEEK ; /* save command */ - uptr->CYL = 0 ; - - case FCCY_SEEK: /* seek */ - if ( ! (uptr->flags & UNIT_ATT) ) /* not attached? */ - { - dkp_sta = dkp_sta | STA_DONE | STA_ERR; /* error */ - } - else if ( uptr->CYL >= drv_tab[dtype].cyl ) /* bad cylinder? */ - { - dkp_sta = dkp_sta | STA_ERR | STA_CYL; - } - if ( (pulse != iopP) || (dkp_sta & STA_ERR) ) - { - return ( FALSE ) ; /* only 'P' pulse start seeks! */ - } - - /* do the seek */ - /* must check for "do we support seeking bits" flag before setting SEEK0'ish bits! */ - dkp_sta = dkp_sta | (STA_SEEK0 >> u); /* set seeking */ - oldCyl = abs(oldCyl - uptr->CYL) ; - if ( (dkp_swait) && (! (oldCyl)) ) /* enforce minimum wait if req */ - oldCyl = 1 ; - sim_activate ( uptr, (dkp_swait * oldCyl) ) ; - break; - } /* end case command */ - -return ( TRUE ) ; /* no error */ -} - - -/* Unit service - - If seek done, put on cylinder; - else, do read or write - If controller was busy, clear busy, set done, interrupt - - Memory access: sectors are read into/written from an intermediate - buffer to allow word-by-word mapping of memory addresses on the - Eclipse. This allows each word written to memory to be tested - for out of range. -*/ - -t_stat dkp_svc (UNIT *uptr) -{ -int32 sa, bda; -int32 dx, pa, u; -int32 dtype, err, newsect, newsurf; -uint32 awc; -t_stat rval; -static uint16 tbuf[DKP_NUMWD]; /* transfer buffer */ - - -rval = SCPE_OK; -dtype = GET_DTYPE (uptr->flags); /* get drive type */ -u = uptr - dkp_dev.units; /* get unit number */ - -if (uptr->FUNC == FCCY_SEEK) { /* seek? */ - if ( ! (uptr->flags & UNIT_ATT) ) /* not attached? */ - { - dkp_sta = dkp_sta | STA_DONE | STA_ERR; /* error (changed during queue time?) */ - } - else if ( uptr->CYL >= drv_tab[dtype].cyl ) /* bad cylinder? */ - { - dkp_sta = dkp_sta | STA_ERR | STA_CYL; - } - DEV_SET_DONE( INT_DKP ) ; - DEV_UPDATE_INTR ; - dkp_sta = (dkp_sta | (STA_SKDN0 >> u)) /* set seek done */ - & ~(STA_SEEK0 >> u); /* clear seeking */ - if ( DKP_TRACE(2) ) - { - fprintf( DKP_TRACE_FP, - " [%s:%c seek : %4d ] \r\n", - "DKP", - (char) (u + '0'), - (unsigned) (uptr->CYL) - ) ; - } - return SCPE_OK; - } - -/* read or write */ - -if (((uptr->flags & UNIT_ATT) == 0) || /* not attached? */ - ((uptr->flags & UNIT_WPRT) && (uptr->FUNC == FCCY_WRITE))) - { - dkp_sta = dkp_sta | STA_DONE | STA_ERR; /* error */ - } -else if ( uptr->CYL >= drv_tab[dtype].cyl ) /* bad cylinder */ - { - dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_CYL ; - dkp_sta = dkp_sta | STA_ERR | STA_CYL; - DEV_SET_DONE( INT_DKP ) ; - DEV_UPDATE_INTR ; - return SCPE_OK ; - } -else if ( GET_SURF(dkp_ussc, dtype) >= drv_tab[dtype].surf ) /* bad surface */ - { - dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_UNS; /* older drives may not even do this... */ -/* dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_XCY ; /- newer disks give this error */ -/* set sector to some bad value and wait then exit? */ - } -else if ( GET_SECT(dkp_ussc, dtype) >= drv_tab[dtype].sect ) /* or bad sector? */ - { -/* dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_UNS; /- older DG drives do not even give error(!), but we do */ - dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_XCY ; /* newer disks give this error */ - } -else { -err = 0 ; -do { - if ( DKP_TRACE(3) ) - { - fprintf( DKP_TRACE_FP, - " [%s:%c %-5s: %3d / %2d / %2d %06o ] \r\n", - "DKP", - (char) (u + '0'), - ((uptr->FUNC == FCCY_READ) ? - "read" - : ((uptr->FUNC == FCCY_WRITE) ? - "write" - : "") - ), - (unsigned) (uptr->CYL), - (unsigned) (GET_SURF(dkp_ussc, dtype)), - (unsigned) (GET_SECT(dkp_ussc, dtype)), - (unsigned) (dkp_ma & 0xFFFF) /* show all 16-bits in case DCH B */ - ) ; - } - - - if ( GET_SECT(dkp_ussc, dtype) >= drv_tab[dtype].sect ) /* or bad sector? */ - { - /* sector overflows to 0 ; - * surface gets incremented - */ - newsurf = GET_SURF(dkp_ussc, dtype) + 1 ; - newsurf = newsurf & ((drv_tab[dtype].newf) ? USSC_M_NSURFACE : USSC_M_OSURFACE) ; - DKP_UPDATE_USSC( type, 0, newsurf, 0 ) - - if ( (GET_SURF(dkp_ussc, dtype)) >= drv_tab[dtype].surf ) - { - /* dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_UNS; /- older drives may not even do this... */ - dkp_sta = dkp_sta | STA_DONE | STA_ERR | STA_XCY ; /* newer disks give this error */ - /* DG retains overflowed surface number, - * other vendors have different/expanded options - */ - break ; - } - } - sa = GET_SA (uptr->CYL, GET_SURF (dkp_ussc, dtype), - GET_SECT (dkp_ussc, dtype), dtype); /* get disk block */ - bda = sa * DKP_NUMWD * sizeof(uint16) ; /* to words, bytes */ - err = fseek (uptr->fileref, bda, SEEK_SET); /* position drive */ - - if (uptr->FUNC == FCCY_READ) { /* read? */ - awc = fxread (tbuf, sizeof(uint16), DKP_NUMWD, uptr->fileref); - for ( ; awc < DKP_NUMWD; awc++) tbuf[awc] = 0; - if ((err = ferror (uptr->fileref))) - break; - for (dx = 0; dx < DKP_NUMWD; dx++) { /* loop thru buffer */ - pa = MapAddr (dkp_map, (dkp_ma & AMASK)); - if (MEM_ADDR_OK (pa)) - M[pa] = tbuf[dx]; - dkp_ma = (dkp_ma + 1) & AMASK; - } - } - else if (uptr->FUNC == FCCY_WRITE) { /* write? */ - for (dx = 0; dx < DKP_NUMWD; dx++) { /* loop into buffer */ - pa = MapAddr (dkp_map, (dkp_ma & AMASK)); - tbuf[dx] = M[pa]; - dkp_ma = (dkp_ma + 1) & AMASK; - } - fxwrite (tbuf, sizeof(int16), DKP_NUMWD, uptr->fileref); - if ((err = ferror (uptr->fileref))) - break; - } - - if (err != 0) { - perror ("DKP I/O error"); - clearerr (uptr->fileref); - rval = SCPE_IOERR; - break ; - } - -newsect = GET_SECT (dkp_ussc, dtype) + 1 ; /* update next sector */ -newsurf = GET_SURF (dkp_ussc, dtype) ; /* and next head */ - /* (count set below) */ -DKP_UPDATE_USSC( type, 1, newsurf, newsect ) -} /* end read/write loop */ - - while ( (GET_COUNT(dkp_ussc)) ) ; - dkp_sta = dkp_sta | STA_DONE; /* set status */ - - if ( DKP_TRACE(4) ) - { - fprintf( DKP_TRACE_FP, - " [%s:%c %-5s: %3d / %2d / %2d %06o ] \r\n", - "DKP", - (char) (u + '0'), - "post", - (unsigned) (uptr->CYL), - (unsigned) (GET_SURF(dkp_ussc, dtype)), - (unsigned) (GET_SECT(dkp_ussc, dtype)), - (unsigned) (dkp_ma & 0xFFFF) /* show all 16-bits in case DCH B */ - ) ; - } - } - -DEV_CLR_BUSY( INT_DKP ) ; -DEV_SET_DONE( INT_DKP ) ; -DEV_UPDATE_INTR ; -return rval; -} - -/* Reset routine */ - -t_stat dkp_reset (DEVICE *dptr) -{ -int32 u; -UNIT *uptr; - -DEV_CLR_BUSY( INT_DKP ) ; /* clear busy */ -DEV_CLR_DONE( INT_DKP ) ; /* clear done */ -DEV_UPDATE_INTR ; /* update ints */ -dkp_fccy = dkp_ussc = dkp_ma = dkp_sta = 0; /* clear registers */ -dkp_diagmode = 0; /* clear diagnostic mode */ -dkp_map = 0; -for (u = 0; u < DKP_NUMDR; u++) { /* loop thru units */ - uptr = dkp_dev.units + u; - sim_cancel (uptr); /* cancel activity */ - uptr->CYL = uptr->FUNC = 0; - } -return SCPE_OK; -} - -/* Attach routine (with optional autosizing) */ - -t_stat dkp_attach (UNIT *uptr, char *cptr) -{ -int32 i, p; -t_stat r; - -uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size; /* restore capac */ -r = attach_unit (uptr, cptr); /* attach */ -if ((r != SCPE_OK) || !(uptr->flags & UNIT_AUTO)) - return r; -if ((p = sim_fsize (uptr->fileref)) == 0) /* get file size */ - return SCPE_OK; -for (i = 0; drv_tab[i].sect != 0; i++) { - if (p <= (drv_tab[i].size * (int32) sizeof (uint16))) { - uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE); - uptr->capac = drv_tab[i].size; - return SCPE_OK; - } - } -return SCPE_OK; -} - -/* Set size command validation routine */ - -t_stat dkp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (uptr->flags & UNIT_ATT) - return SCPE_ALATT; -uptr->capac = drv_tab[GET_DTYPE (val)].size; -return SCPE_OK; -} - -/* Bootstrap routine */ - -#if defined(_OLD_CODE_) - -#define BOOT_START 02000 -#define BOOT_UNIT 02021 -#define BOOT_SEEK 02022 -#define BOOT_LEN (sizeof(boot_rom) / sizeof(int32)) - -static const int32 boot_rom[] = { - 0060233, /* NIOC 0,DKP ; clear disk */ - 0020420, /* LDA 0,USSC ; unit, sfc, sec, cnt */ - 0063033, /* DOC 0,DKP ; select disk */ - 0020417, /* LDA 0,SEKCMD ; command, cylinder */ - 0061333, /* DOAP 0,DKP ; start seek */ - 0024415, /* LDA 1,SEKDN */ - 0060433, /* DIA 0,DKP ; get status */ - 0123415, /* AND# 1,0,SZR ; skip if done */ - 0000776, /* JMP .-2 */ - 0102400, /* SUB 0,0 ; mem addr = 0 */ - 0062033, /* DOB 0,DKP */ - 0020411, /* LDA 0,REDCMD ; command, cylinder */ - 0061133, /* DOAS 0,DKP ; start read */ - 0060433, /* DIA 0, DKP ; get status */ - 0101113, /* MOVL# 0,0,SNC ; skip if done */ - 0000776, /* JMP .-2 */ - 0000377, /* JMP 377 */ - 0000016, /* USSC: 0.B1+0.B7+0.B11+16 */ - 0175000, /* SEKCMD: 175000 */ - 0074000, /* SEKDN: 074000 */ - 0174000 /* REDCMD: 174000 */ - }; - - -t_stat dkp_boot (int32 unitno, DEVICE *dptr) -{ -int32 i, dtype; -extern int32 saved_PC, SR; - -for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = boot_rom[i]; -unitno = unitno & USSC_M_UNIT; -dtype = GET_DTYPE (dkp_unit[unitno].flags); -M[BOOT_UNIT] = M[BOOT_UNIT] | (unitno << USSC_V_UNIT); -if (drv_tab[dtype].newf) M[BOOT_SEEK] = 0176000; -saved_PC = BOOT_START; -SR = 0100000 + DEV_DKP; -return SCPE_OK; -} - -#endif /* _OLD_CODE_ */ - - - -#define BOOT_START 0375 -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) - -static const int32 boot_rom[] = { - 0062677 /* IORST ; reset the I/O system */ - , 0060133 /* NIOS DKP ; start the disk */ - , 0000377 /* JMP 377 ; wait for the world */ - } ; - - -t_stat dkp_boot (int32 unitno, DEVICE *dptr) -{ -size_t i; - -for (i = 0; i < BOOT_LEN; i++) - M[BOOT_START + i] = (uint16) boot_rom[i]; -saved_PC = BOOT_START; -SR = 0100000 + DEV_DKP; -return SCPE_OK; -} diff --git a/NOVA/nova_dsk.c b/NOVA/nova_dsk.c deleted file mode 100644 index 75e83800..00000000 --- a/NOVA/nova_dsk.c +++ /dev/null @@ -1,339 +0,0 @@ -/* nova_dsk.c: 4019 fixed head disk simulator - - Copyright (c) 1993-2013, 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. - - dsk fixed head disk - - 03-Sep-13 RMS Added explicit void * cast - 04-Jul-07 BKR device name changed to DG's DSK from DEC's DK, - DEV_xxx macros now used for consistency, - added secret DG DIC function, - fixed boot info table size calculation - 15-May-06 RMS Fixed bug in autosize attach (David Gesswein) - 04-Jan-04 RMS Changed sim_fsize calling sequence - 26-Jul-03 RMS Fixed bug in set size routine - 14-Mar-03 RMS Fixed variable capacity interaction with save/restore - 03-Mar-03 RMS Fixed variable capacity and autosizing - 03-Oct-02 RMS Added DIB - 06-Jan-02 RMS Revised enable/disable support - 23-Aug-01 RMS Fixed bug in write watermarking - 26-Apr-01 RMS Added device enable/disable support - 10-Dec-00 RMS Added Eclipse support - 15-Oct-00 RMS Editorial changes - 14-Apr-99 RMS Changed t_addr to unsigned - - The 4019 is a head-per-track disk. To minimize overhead, the entire disk - is buffered in memory. -*/ - -#include "nova_defs.h" -#include - -#define UNIT_V_AUTO (UNIT_V_UF + 0) /* autosize */ -#define UNIT_V_PLAT (UNIT_V_UF + 1) /* #platters - 1 */ -#define UNIT_M_PLAT 07 -#define UNIT_PLAT (UNIT_M_PLAT << UNIT_V_PLAT) -#define UNIT_GETP(x) ((((x) >> UNIT_V_PLAT) & UNIT_M_PLAT) + 1) -#define UNIT_AUTO (1 << UNIT_V_AUTO) -#define UNIT_PLAT (UNIT_M_PLAT << UNIT_V_PLAT) - -/* Constants */ - -#define DSK_NUMWD 256 /* words/sector */ -#define DSK_NUMSC 8 /* sectors/track */ -#define DSK_NUMTR 128 /* tracks/disk */ -#define DSK_DKSIZE (DSK_NUMTR*DSK_NUMSC*DSK_NUMWD) /* words/disk */ -#define DSK_AMASK ((DSK_NUMDK*DSK_NUMTR*DSK_NUMSC) - 1) - /* address mask */ -#define DSK_NUMDK 8 /* disks/controller */ -#define GET_DISK(x) (((x) / (DSK_NUMSC * DSK_NUMTR)) & (DSK_NUMDK - 1)) - -/* Parameters in the unit descriptor */ - -#define FUNC u4 /* function */ - -/* Status register */ - -#define DSKS_WLS 020 /* write lock status */ -#define DSKS_DLT 010 /* data late error */ -#define DSKS_NSD 004 /* non-existent disk */ -#define DSKS_CRC 002 /* parity error */ -#define DSKS_ERR 001 /* error summary */ -#define DSKS_ALLERR (DSKS_WLS | DSKS_DLT | DSKS_NSD | DSKS_CRC | DSKS_ERR) - -/* Map logical sector numbers to physical sector numbers - (indexed by track<2:0>'sector) -*/ - -static const int32 sector_map[] = { - 0, 2, 4, 6, 1, 3, 5, 7, 1, 3, 5, 7, 2, 4, 6, 0, - 2, 4, 6, 0, 3, 5, 7, 1, 3, 5, 7, 1, 4, 6, 0, 2, - 4, 6, 0, 2, 5, 7, 1, 3, 5, 7, 1, 3, 6, 0, 2, 4, - 6, 0, 2, 4, 7, 1, 3, 5, 7, 1, 3, 5, 0, 2, 4, 6 - }; - -#define DSK_MMASK 077 -#define GET_SECTOR(x) ((int) fmod (sim_gtime() / ((double) (x)), \ - ((double) DSK_NUMSC))) - -extern uint16 M[]; -extern UNIT cpu_unit; -extern int32 int_req, dev_busy, dev_done, dev_disable; -extern int32 saved_PC, SR, AMASK; - -int32 dsk_stat = 0; /* status register */ -int32 dsk_da = 0; /* disk address */ -int32 dsk_ma = 0; /* memory address */ -int32 dsk_wlk = 0; /* wrt lock switches */ -int32 dsk_stopioe = 0; /* stop on error */ -int32 dsk_time = 100; /* time per sector */ - -DEVICE dsk_dev; -int32 dsk (int32 pulse, int32 code, int32 AC); -t_stat dsk_svc (UNIT *uptr); -t_stat dsk_reset (DEVICE *dptr); -t_stat dsk_boot (int32 unitno, DEVICE *dptr); -t_stat dsk_attach (UNIT *uptr, char *cptr); -t_stat dsk_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); - -/* DSK data structures - - dsk_dev device descriptor - dsk_unit unit descriptor - dsk_reg register list -*/ - -DIB dsk_dib = { DEV_DSK, INT_DSK, PI_DSK, &dsk }; - -UNIT dsk_unit = { - UDATA (&dsk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, - DSK_DKSIZE) - }; - -REG dsk_reg[] = { - { ORDATA (STAT, dsk_stat, 16) }, - { ORDATA (DA, dsk_da, 16) }, - { ORDATA (MA, dsk_ma, 16) }, - { FLDATA (BUSY, dev_busy, INT_V_DSK) }, - { FLDATA (DONE, dev_done, INT_V_DSK) }, - { FLDATA (DISABLE, dev_disable, INT_V_DSK) }, - { FLDATA (INT, int_req, INT_V_DSK) }, - { ORDATA (WLK, dsk_wlk, 8) }, - { DRDATA (TIME, dsk_time, 24), REG_NZ + PV_LEFT }, - { FLDATA (STOP_IOE, dsk_stopioe, 0) }, - { NULL } - }; - -MTAB dsk_mod[] = { - { UNIT_PLAT, (0 << UNIT_V_PLAT), NULL, "1P", &dsk_set_size }, - { UNIT_PLAT, (1 << UNIT_V_PLAT), NULL, "2P", &dsk_set_size }, - { UNIT_PLAT, (2 << UNIT_V_PLAT), NULL, "3P", &dsk_set_size }, - { UNIT_PLAT, (3 << UNIT_V_PLAT), NULL, "4P", &dsk_set_size }, - { UNIT_PLAT, (4 << UNIT_V_PLAT), NULL, "5P", &dsk_set_size }, - { UNIT_PLAT, (5 << UNIT_V_PLAT), NULL, "6P", &dsk_set_size }, - { UNIT_PLAT, (6 << UNIT_V_PLAT), NULL, "7P", &dsk_set_size }, - { UNIT_PLAT, (7 << UNIT_V_PLAT), NULL, "8P", &dsk_set_size }, - { UNIT_AUTO, UNIT_AUTO, "autosize", "AUTOSIZE", NULL }, - { 0 } - }; - -DEVICE dsk_dev = { - "DSK", &dsk_unit, dsk_reg, dsk_mod, - 1, 8, 21, 1, 8, 16, - NULL, NULL, &dsk_reset, - &dsk_boot, &dsk_attach, NULL, - &dsk_dib, DEV_DISABLE - }; - - -/* IOT routine */ - -int32 dsk (int32 pulse, int32 code, int32 AC) -{ -int32 t, rval; - -rval = 0; -switch (code) { /* decode IR<5:7> */ - - case ioDIA: /* DIA */ - rval = dsk_stat & DSKS_ALLERR; /* read status */ - break; - - case ioDOA: /* DOA */ - dsk_da = AC & DSK_AMASK; /* save disk addr */ - break; - - case ioDIB: /* DIB */ - rval = dsk_ma & AMASK; /* read mem addr */ - break; - - case ioDOB: /* DOB */ - dsk_ma = AC & AMASK; /* save mem addr */ - break; - - case ioDIC: /* DIC - undocumented DG feature(!) */ - rval = 256 ; /* return fixed sector size for DG for now */ - break ; - } /* end switch code */ - -if (pulse) { /* any pulse? */ - DEV_CLR_BUSY( INT_DSK ) ; - DEV_CLR_DONE( INT_DSK ) ; - DEV_UPDATE_INTR ; - dsk_stat = 0; /* clear status */ - sim_cancel (&dsk_unit); /* stop I/O */ - } - -if ((pulse == iopP) && ((dsk_wlk >> GET_DISK (dsk_da)) & 1)) { /* wrt lock? */ - DEV_SET_DONE( INT_DSK ) ; - DEV_UPDATE_INTR ; - dsk_stat = DSKS_ERR + DSKS_WLS; /* set status */ - return rval; - } - -if (pulse & 1) { /* read or write? */ - if (((uint32) (dsk_da * DSK_NUMWD)) >= dsk_unit.capac) { /* inv sev? */ - DEV_SET_DONE( INT_DSK ) ; - DEV_UPDATE_INTR ; - dsk_stat = DSKS_ERR + DSKS_NSD; /* set status */ - return rval; /* done */ - } - dsk_unit.FUNC = pulse; /* save command */ - DEV_SET_BUSY( INT_DSK ) ; - DEV_UPDATE_INTR ; - t = sector_map[dsk_da & DSK_MMASK] - GET_SECTOR (dsk_time); - if (t < 0) - t = t + DSK_NUMSC; - sim_activate (&dsk_unit, t * dsk_time); /* activate */ - } -return rval; -} - - -/* Unit service */ - -t_stat dsk_svc (UNIT *uptr) -{ -int32 i, da, pa; -int16 *fbuf = (int16 *) uptr->filebuf; - -DEV_CLR_BUSY( INT_DSK ) ; -DEV_SET_DONE( INT_DSK ) ; -DEV_UPDATE_INTR ; - -if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */ - dsk_stat = DSKS_ERR + DSKS_NSD; /* set status */ - return IORETURN (dsk_stopioe, SCPE_UNATT); - } - -da = dsk_da * DSK_NUMWD; /* calc disk addr */ -if (uptr->FUNC == iopS) { /* read? */ - for (i = 0; i < DSK_NUMWD; i++) { /* copy sector */ - pa = MapAddr (0, (dsk_ma + i) & AMASK); /* map address */ - if (MEM_ADDR_OK (pa)) - M[pa] = fbuf[da + i]; - } - dsk_ma = (dsk_ma + DSK_NUMWD) & AMASK; - } -else if (uptr->FUNC == iopP) { /* write? */ - for (i = 0; i < DSK_NUMWD; i++) { /* copy sector */ - pa = MapAddr (0, (dsk_ma + i) & AMASK); /* map address */ - fbuf[da + i] = M[pa]; - } - if (((uint32) (da + i)) >= uptr->hwmark) /* past end? */ - uptr->hwmark = da + i + 1; /* upd hwmark */ - dsk_ma = (dsk_ma + DSK_NUMWD + 3) & AMASK; - } - -dsk_stat = 0; /* set status */ -return SCPE_OK; -} - - -/* Reset routine */ - -t_stat dsk_reset (DEVICE *dptr) -{ -dsk_stat = dsk_da = dsk_ma = 0; -DEV_CLR_BUSY( INT_DSK ) ; -DEV_CLR_DONE( INT_DSK ) ; -DEV_UPDATE_INTR ; -sim_cancel (&dsk_unit); -return SCPE_OK; -} - - -/* Bootstrap routine */ - -#define BOOT_START 0375 -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int32)) - -static const int32 boot_rom[] = { - 0062677 /* IORST ; reset the I/O system */ - , 0060120 /* NIOS DSK ; start the disk */ - , 0000377 /* JMP 377 ; wait for the world */ - } ; - - -t_stat dsk_boot (int32 unitno, DEVICE *dptr) -{ -size_t i; - -for (i = 0; i < BOOT_LEN; i++) M[BOOT_START + i] = (uint16) boot_rom[i]; -saved_PC = BOOT_START; -SR = 0100000 + DEV_DSK; -return SCPE_OK; -} - - -/* Attach routine */ - -t_stat dsk_attach (UNIT *uptr, char *cptr) -{ -uint32 sz, p; -uint32 ds_bytes = DSK_DKSIZE * sizeof (int16); - -if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize_name (cptr))) { - p = (sz + ds_bytes - 1) / ds_bytes; - if (p >= DSK_NUMDK) - p = DSK_NUMDK - 1; - uptr->flags = (uptr->flags & ~UNIT_PLAT) | (p << UNIT_V_PLAT); - } -uptr->capac = UNIT_GETP (uptr->flags) * DSK_DKSIZE; /* set capacity */ -return attach_unit (uptr, cptr); -} - - -/* Change disk size */ - -t_stat dsk_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (val < 0) - return SCPE_IERR; -if (uptr->flags & UNIT_ATT) - return SCPE_ALATT; -uptr->capac = UNIT_GETP (val) * DSK_DKSIZE; -uptr->flags = uptr->flags & ~UNIT_AUTO; -return SCPE_OK; -} diff --git a/NOVA/nova_lp.c b/NOVA/nova_lp.c deleted file mode 100644 index c2e3923c..00000000 --- a/NOVA/nova_lp.c +++ /dev/null @@ -1,155 +0,0 @@ -/* nova_lp.c: NOVA line printer simulator - - Copyright (c) 1993-2008, 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 line printer - - 04-Jul-07 BKR DEV_SET/CLR macros now used, - , , output character delay now contingent upon non-zero TIME value, - LPT can now be DISABLED - 19-Jan-07 RMS Added UNIT_TEXT - 25-Apr-03 RMS Revised for extended file support - 30-May-02 RMS Widened POS to 32b - - -Notes: - - data currently masked to 7 bits. - - if register TIME is non-zero, then delay TIME events if , or seen - - register POS show the current file position - - register STOP_IOE determines return value issued if output to unattached LPT is attempted -*/ - -#include "nova_defs.h" - -extern int32 int_req, dev_busy, dev_done, dev_disable; - - -int32 lpt_stopioe = 0; /* stop on error flag */ - -int32 lpt (int32 pulse, int32 code, int32 AC); -t_stat lpt_svc (UNIT *uptr); -t_stat lpt_reset (DEVICE *dptr); - -/* LPT data structures - - lpt_dev LPT device descriptor - lpt_unit LPT unit descriptor - lpt_reg LPT register list -*/ - -DIB lpt_dib = { DEV_LPT, INT_LPT, PI_LPT, &lpt }; - -UNIT lpt_unit = { /* 2007-May-30, bkr */ - UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT - }; - -REG lpt_reg[] = { - { ORDATA (BUF, lpt_unit.buf, 8) }, - { FLDATA (BUSY, dev_busy, INT_V_LPT) }, - { FLDATA (DONE, dev_done, INT_V_LPT) }, - { FLDATA (DISABLE, dev_disable, INT_V_LPT) }, - { FLDATA (INT, int_req, INT_V_LPT) }, - { DRDATA (POS, lpt_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT }, - { FLDATA (STOP_IOE, lpt_stopioe, 0) }, - { NULL } - }; - -DEVICE lpt_dev = { - "LPT", &lpt_unit, lpt_reg, NULL, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &lpt_reset, - NULL, NULL, NULL, - &lpt_dib, DEV_DISABLE - }; - - -/* IOT routine */ - -int32 lpt (int32 pulse, int32 code, int32 AC) -{ -if (code == ioDOA) - lpt_unit.buf = AC & 0177 ; - -switch (pulse) - { /* decode IR<8:9> */ - case iopS: /* start */ - DEV_SET_BUSY( INT_LPT ) ; - DEV_CLR_DONE( INT_LPT ) ; - DEV_UPDATE_INTR ; - if ( lpt_unit.wait ) - if ( (lpt_unit.buf == 015) - || (lpt_unit.buf == 014) - || (lpt_unit.buf == 012) - ) - { - sim_activate (&lpt_unit, lpt_unit.wait); - break ; - } - return (lpt_svc (&lpt_unit) << IOT_V_REASON); - break; - - case iopC: /* clear */ - DEV_CLR_BUSY( INT_LPT ) ; - DEV_CLR_DONE( INT_LPT ) ; - DEV_UPDATE_INTR ; - sim_cancel (&lpt_unit); /* deactivate unit */ - break; - } /* end switch */ - -return 0; -} - - -/* Unit service */ - -t_stat lpt_svc (UNIT *uptr) -{ -DEV_CLR_BUSY( INT_LPT ) ; -DEV_SET_DONE( INT_LPT ) ; -DEV_UPDATE_INTR ; -if ((lpt_unit.flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (lpt_stopioe, SCPE_UNATT); -fputc (uptr->buf, uptr->fileref); -uptr->pos = ftell (uptr->fileref); -if (ferror (uptr->fileref)) { - perror ("LPT I/O error"); - clearerr (uptr->fileref); - return SCPE_IOERR; - } -return SCPE_OK; -} - - -/* Reset routine */ - -t_stat lpt_reset (DEVICE *dptr) -{ -lpt_unit.buf = 0; /* (not DG compatible) */ -DEV_CLR_BUSY( INT_LPT ) ; -DEV_CLR_DONE( INT_LPT ) ; -DEV_UPDATE_INTR ; -sim_cancel (&lpt_unit); /* deactivate unit */ -return SCPE_OK; -} diff --git a/NOVA/nova_mta.c b/NOVA/nova_mta.c deleted file mode 100644 index b5285110..00000000 --- a/NOVA/nova_mta.c +++ /dev/null @@ -1,648 +0,0 @@ -/* nova_mta.c: NOVA magnetic tape simulator - - Copyright (c) 1993-2017, 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. - - mta magnetic tape - - 13-Mar-17 RMS Annotated fall through in switch - 04-Jul-07 BKR fixed boot code to properly boot self-boot tapes; - boot routine now uses standard DG APL boot code; - device name changed to DG's MTA from DEC's MT. - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 18-Mar-05 RMS Added attached test to detach routine - 22-Nov-03 CEO DIB returns # records skipped after space fwd - 22-Nov-03 CEO Removed cancel of tape events in IORST - 25-Apr-03 RMS Revised for extended file support - 28-Mar-03 RMS Added multiformat support - 28-Feb-03 RMS Revised for magtape library - 30-Oct-02 RMS Fixed BOT handling, added error record handling - 08-Oct-02 RMS Added DIB - 30-Sep-02 RMS Revamped error handling - 28-Aug-02 RMS Added end of medium support - 30-May-02 RMS Widened POS to 32b - 22-Apr-02 RMS Added maximum record length test - 06-Jan-02 RMS Revised enable/disable support - 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 (Charles Owen) - 15-Oct-00 RMS Editorial changes - 11-Nov-98 CEO Removed clear of mta_ma on iopC - 04-Oct-98 RMS V2.4 magtape format - 18-Jan-97 RMS V2.3 magtape format - 29-Jun-96 RMS Added unit enable/disable support - - Magnetic tapes are represented as a series of variable records - of the form: - - 32b byte count byte count is little endian - byte 0 - byte 1 - : - byte n-2 - byte n-1 - 32b byte count - - If the byte count is odd, the record is padded with an extra byte - of junk. File marks are represented by a byte count of 0 and are - not duplicated; end of tape by end of file. -*/ - -#include "nova_defs.h" -#include "sim_tape.h" - -#define MTA_NUMDR 8 /* #drives */ -#define USTAT u3 /* unit status */ -#define MTA_MAXFR (1 << 16) /* max record lnt */ -#define WC_SIZE (1 << 14) /* max word count */ -#define WC_MASK (WC_SIZE - 1) - -/* Command/unit */ - -#define CU_CI 0100000 /* clear interrupt */ -#define CU_EP 0002000 /* poll enable */ -#define CU_DE 0001000 /* disable erase */ -#define CU_DA 0000400 /* disable autoretry */ -#define CU_PE 0000400 /* PE mode */ -#define CU_V_CMD 3 /* command */ -#define CU_M_CMD 027 -#define CU_READ 000 -#define CU_REWIND 001 -#define CU_CMODE 002 -#define CU_SPACEF 003 -#define CU_SPACER 004 -#define CU_WRITE 005 -#define CU_WREOF 006 -#define CU_ERASE 007 -#define CU_READNS 020 -#define CU_UNLOAD 021 -#define CU_DMODE 022 -#define CU_V_UNIT 0 /* unit */ -#define CU_M_UNIT 07 -#define GET_CMD(x) (((x) >> CU_V_CMD) & CU_M_CMD) -#define GET_UNIT(x) (((x) >> CU_V_UNIT) & CU_M_UNIT) - -/* Status 1 - stored in mta_sta<31:16> or (*) uptr->USTAT<31:16> */ - -#define STA_ERR1 (0100000u << 16) /* error */ -#define STA_DLT (0040000 << 16) /* data late */ -#define STA_REW (0020000 << 16) /* *rewinding */ -#define STA_ILL (0010000 << 16) /* illegal */ -#define STA_HDN (0004000 << 16) /* high density */ -#define STA_DAE (0002000 << 16) /* data error */ -#define STA_EOT (0001000 << 16) /* *end of tape */ -#define STA_EOF (0000400 << 16) /* *end of file */ -#define STA_BOT (0000200 << 16) /* *start of tape */ -#define STA_9TK (0000100 << 16) /* nine track */ -#define STA_BAT (0000040 << 16) /* bad tape */ -#define STA_CHG (0000010 << 16) /* status change */ -#define STA_WLK (0000004 << 16) /* *write lock */ -#define STA_ODD (0000002 << 16) /* odd character */ -#define STA_RDY (0000001 << 16) /* *drive ready */ - -/* Status 2 - stored in mta_sta<15:0> or (*) uptr->USTAT<15:0> */ - -#define STA_ERR2 0100000 /* error */ -#define STA_RWY 0040000 /* runaway tape */ -#define STA_FGP 0020000 /* false gap */ -#define STA_CDL 0004000 /* corrected dlt */ -#define STA_V_UNIT 8 -#define STA_M_UNIT 07 /* unit */ -#define STA_WCO 0000200 /* word count ovflo */ -#define STA_BDS 0000100 /* bad signal */ -#define STA_OVS 0000040 /* overskew */ -#define STA_CRC 0000020 /* check error */ -#define STA_STE 0000010 /* single trk error */ -#define STA_FPR 0000004 /* false preamble */ -#define STA_FMT 0000002 /* format error */ -#define STA_PEM 0000001 /* *PE mode */ - -#define STA_EFLGS1 (STA_DLT | STA_ILL | STA_DAE | STA_EOT | \ - STA_EOF | STA_BOT | STA_BAT | STA_ODD) -#define STA_EFLGS2 (STA_FGP | STA_CDL | STA_BDS | STA_OVS | \ - STA_CRC | STA_FPR | STA_FPR) /* set error 2 */ -#define STA_CLR ((020 << 16) | 0010000) /* always clear */ -#define STA_SET (STA_HDN | STA_9TK) /* always set */ -#define STA_DYN (STA_REW | STA_EOT | STA_EOF | STA_BOT | \ - STA_WLK | STA_RDY | STA_PEM) /* kept in USTAT */ -#define STA_MON (STA_REW | STA_BOT | STA_WLK | STA_RDY | \ - STA_PEM) /* set status chg */ - -extern uint16 M[]; -extern UNIT cpu_unit; -extern int32 int_req, dev_busy, dev_done, dev_disable; -extern int32 SR, AMASK; - -extern t_stat cpu_boot(int32 unitno, DEVICE * dptr ) ; - - -int32 mta_ma = 0; /* memory address */ -int32 mta_wc = 0; /* word count */ -int32 mta_cu = 0; /* command/unit */ -int32 mta_sta = 0; /* status register */ -int32 mta_ep = 0; /* enable polling */ -int32 mta_cwait = 100; /* command latency */ -int32 mta_rwait = 100; /* record latency */ -uint8 *mtxb = NULL; /* transfer buffer */ - -DEVICE mta_dev; -int32 mta (int32 pulse, int32 code, int32 AC); -t_stat mta_svc (UNIT *uptr); -t_stat mta_reset (DEVICE *dptr); -t_stat mta_boot (int32 unitno, DEVICE *dptr); -t_stat mta_attach (UNIT *uptr, char *cptr); -t_stat mta_detach (UNIT *uptr); -int32 mta_updcsta (UNIT *uptr); -void mta_upddsta (UNIT *uptr, int32 newsta); -t_stat mta_map_err (UNIT *uptr, t_stat st); -t_stat mta_vlock (UNIT *uptr, int32 val, char *cptr, void *desc); - -static const int ctype[32] = { /* c vs r timing */ - 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, - 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1 - }; - -/* MTA data structures - - mta_dev MTA device descriptor - mta_unit MTA unit list - mta_reg MTA register list - mta_mod MTA modifier list -*/ - -DIB mta_dib = { DEV_MTA, INT_MTA, PI_MTA, &mta }; - -UNIT mta_unit[] = { - { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, - { UDATA (&mta_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, - { 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) }, - { ORDATA (MA, mta_ma, 16) }, - { ORDATA (WC, mta_wc, 16) }, - { GRDATA (STA1, mta_sta, 8, 16, 16) }, - { ORDATA (STA2, mta_sta, 16) }, - { FLDATA (EP, mta_ep, 0) }, - { FLDATA (BUSY, dev_busy, INT_V_MTA) }, - { FLDATA (DONE, dev_done, INT_V_MTA) }, - { FLDATA (DISABLE, dev_disable, INT_V_MTA) }, - { FLDATA (INT, int_req, INT_V_MTA) }, - { DRDATA (CTIME, mta_cwait, 24), PV_LEFT }, - { DRDATA (RTIME, mta_rwait, 24), PV_LEFT }, - { URDATA (UST, mta_unit[0].USTAT, 8, 32, 0, MTA_NUMDR, 0) }, - { URDATA (POS, mta_unit[0].pos, 8, T_ADDR_W, 0, - MTA_NUMDR, REG_RO | PV_LEFT) }, - { NULL } - }; - -MTAB mta_mod[] = { - { MTUF_WLK, 0, "write enabled", "WRITEENABLED", &mta_vlock }, - { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", &mta_vlock }, - { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT", - &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, - { 0 } - }; - -DEVICE mta_dev = { - "MTA", mta_unit, mta_reg, mta_mod, - MTA_NUMDR, 10, 31, 1, 8, 8, - NULL, NULL, &mta_reset, - &mta_boot, &mta_attach, &mta_detach, - &mta_dib, DEV_DISABLE | DEV_TAPE - }; - -/* IOT routine */ - -int32 mta (int32 pulse, int32 code, int32 AC) -{ -UNIT *uptr; -int32 u, c, rval; - -rval = 0; -uptr = mta_dev.units + GET_UNIT(mta_cu); /* get unit */ -switch (code) { /* decode IR<5:7> */ - - case ioDIA: /* DIA */ - rval = (mta_updcsta (uptr) >> 16) & DMASK; /* return status 1 */ - break; - - case ioDOA: /* DOA */ -/* if (AC & CU_CI) ... clear ep int */ - mta_cu = AC; /* save cmd/unit */ - uptr = mta_dev.units + GET_UNIT(mta_cu); /* get unit */ - mta_updcsta (uptr); /* update status */ - break; - - case ioDIB: /* DIB */ - rval = mta_ma & AMASK; /* return ma */ - break; - - case ioDOB: /* DOB */ - mta_ma = AC & AMASK; /* save ma */ - break; - - case ioDIC: /* DIC */ - rval = mta_updcsta (uptr) & DMASK; /* return status 2 */ - break; - - case ioDOC: /* DOC */ - mta_wc = ((AC & 040000) << 1) | (AC & 077777); /* save wc */ - break; - } /* end switch code */ - -switch (pulse) { /* decode IR<8:9> */ - - case iopS: /* start */ - c = GET_CMD (mta_cu); /* get command */ - if (dev_busy & INT_MTA) /* ignore if busy */ - break; - if ((uptr->USTAT & STA_RDY) == 0) { /* drive not ready? */ - mta_sta = mta_sta | STA_ILL; /* illegal op */ - dev_busy = dev_busy & ~INT_MTA; /* clear busy */ - dev_done = dev_done | INT_MTA; /* set done */ - int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); - } - else if ((c == CU_REWIND) || (c == CU_UNLOAD)) { /* rewind, unload? */ - mta_upddsta (uptr, (uptr->USTAT & /* update status */ - ~(STA_BOT | STA_EOF | STA_EOT | STA_RDY)) | STA_REW); - sim_activate (uptr, mta_rwait); /* start IO */ - if (c == CU_UNLOAD) - detach_unit (uptr); - } - else { - mta_sta = 0; /* clear errors */ - dev_busy = dev_busy | INT_MTA; /* set busy */ - dev_done = dev_done & ~INT_MTA; /* clear done */ - int_req = int_req & ~INT_MTA; /* clear int */ - if (ctype[c]) - sim_activate (uptr, mta_cwait); - else { - mta_upddsta (uptr, uptr->USTAT & - ~(STA_BOT | STA_EOF | STA_EOT | STA_RDY)); - sim_activate (uptr, mta_rwait); - } - } - mta_updcsta (uptr); /* update status */ - break; - - case iopC: /* clear */ - for (u = 0; u < MTA_NUMDR; u++) { /* loop thru units */ - uptr = mta_dev.units + u; /* cancel IO */ - if (sim_is_active (uptr) && !(uptr->USTAT & STA_REW)) { - mta_upddsta (uptr, uptr->USTAT | STA_RDY); - sim_cancel (uptr); - } - } - dev_busy = dev_busy & ~INT_MTA; /* clear busy */ - dev_done = dev_done & ~INT_MTA; /* clear done */ - int_req = int_req & ~INT_MTA; /* clear int */ - mta_sta = mta_cu = 0; /* clear registers */ - mta_updcsta (&mta_unit[0]); /* update status */ - break; - } /* end case pulse */ - -return rval; -} - -/* Unit service - - If rewind done, reposition to start of tape, set status - else, do operation, clear busy, set done, interrupt -*/ - -t_stat mta_svc (UNIT *uptr) -{ -int32 c, p, pa, u; -t_mtrlnt i, cbc, tbc, wc; -uint16 c1, c2; -t_stat st, r = SCPE_OK; - -u = uptr - mta_dev.units; /* get unit number */ -c = GET_CMD (mta_cu); /* command */ -wc = WC_SIZE - (mta_wc & WC_MASK); /* io wc */ - -if (uptr->USTAT & STA_REW) { /* rewind? */ - sim_tape_rewind (uptr); /* update tape */ - mta_upddsta (uptr, (uptr->USTAT & ~STA_REW) | STA_BOT | STA_RDY); - if (u == GET_UNIT (mta_cu)) - mta_updcsta (uptr); - return SCPE_OK; - } - -if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ - mta_upddsta (uptr, 0); /* unit off line */ - mta_sta = mta_sta | STA_ILL; /* illegal operation */ - } -else switch (c) { /* case on command */ - - case CU_CMODE: /* controller mode */ - mta_ep = mta_cu & CU_EP; - break; - - case CU_DMODE: /* drive mode */ - if (!sim_tape_bot (uptr)) /* must be BOT */ - mta_sta = mta_sta | STA_ILL; - else mta_upddsta (uptr, (mta_cu & CU_PE)? /* update drv status */ - uptr->USTAT | STA_PEM: uptr->USTAT & ~ STA_PEM); - break; - - case CU_READ: /* read */ - case CU_READNS: /* read non-stop */ - st = sim_tape_rdrecf (uptr, mtxb, &tbc, MTA_MAXFR); /* read rec */ - if (st == MTSE_RECE) /* rec in err? */ - mta_sta = mta_sta | STA_DAE; - else if (st != MTSE_OK) { /* other error? */ - r = mta_map_err (uptr, st); /* map error */ - break; - } - cbc = wc * 2; /* expected bc */ - if (tbc & 1) /* odd byte count? */ - mta_sta = mta_sta | STA_ODD; - if (tbc > cbc) /* too big? */ - mta_sta = mta_sta | STA_WCO; - else { - cbc = tbc; /* no, use it */ - wc = (cbc + 1) / 2; /* adjust wc */ - } - for (i = p = 0; i < wc; i++) { /* copy buf to mem */ - c1 = mtxb[p++]; - c2 = mtxb[p++]; - pa = MapAddr (0, mta_ma); /* map address */ - if (MEM_ADDR_OK (pa)) - M[pa] = (c1 << 8) | c2; - mta_ma = (mta_ma + 1) & AMASK; - } - mta_wc = (mta_wc + wc) & DMASK; - mta_upddsta (uptr, uptr->USTAT | STA_RDY); - break; - - case CU_WRITE: /* write */ - tbc = wc * 2; /* io byte count */ - for (i = p = 0; i < wc; i++) { /* copy to buffer */ - pa = MapAddr (0, mta_ma); /* map address */ - mtxb[p++] = (M[pa] >> 8) & 0377; - mtxb[p++] = M[pa] & 0377; - mta_ma = (mta_ma + 1) & AMASK; - } - if ((st = sim_tape_wrrecf (uptr, mtxb, tbc))) { /* write rec, err? */ - r = mta_map_err (uptr, st); /* map error */ - mta_ma = (mta_ma - wc) & AMASK; /* restore wc */ - } - else mta_wc = 0; /* clear wc */ - mta_upddsta (uptr, uptr->USTAT | STA_RDY); - break; - - case CU_WREOF: /* write eof */ - if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ - r = mta_map_err (uptr, st); /* map error */ - else mta_upddsta (uptr, uptr->USTAT | STA_EOF | STA_RDY); - break; - - case CU_ERASE: /* erase */ - if (sim_tape_wrp (uptr)) /* write protected? */ - r = mta_map_err (uptr, MTSE_WRP); /* map error */ - else mta_upddsta (uptr, uptr->USTAT | STA_RDY); - break; - - case CU_SPACEF: /* space forward */ - do { - mta_wc = (mta_wc + 1) & DMASK; /* incr wc */ - if ((st = sim_tape_sprecf (uptr, &tbc))) { /* space rec fwd, err? */ - r = mta_map_err (uptr, st); /* map error */ - break; - } - } while (mta_wc != 0); - mta_upddsta (uptr, uptr->USTAT | STA_RDY); - mta_ma = mta_wc; /* word count = # records */ - break; - - case CU_SPACER: /* space reverse */ - do { - mta_wc = (mta_wc + 1) & DMASK; /* incr wc */ - if ((st = sim_tape_sprecr (uptr, &tbc))) { /* space rec rev, err? */ - r = mta_map_err (uptr, st); /* map error */ - break; - } - } while (mta_wc != 0); - mta_upddsta (uptr, uptr->USTAT | STA_RDY); - mta_ma = mta_wc; /* word count = # records */ - break; - - default: /* reserved */ - mta_sta = mta_sta | STA_ILL; - mta_upddsta (uptr, uptr->USTAT | STA_RDY); - break; - } /* end case */ - -mta_updcsta (uptr); /* update status */ -dev_busy = dev_busy & ~INT_MTA; /* clear busy */ -dev_done = dev_done | INT_MTA; /* set done */ -int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); -return r; -} - -/* Update controller status */ - -int32 mta_updcsta (UNIT *uptr) /* update ctrl */ -{ -mta_sta = (mta_sta & ~(STA_DYN | STA_CLR | STA_ERR1 | STA_ERR2)) | - (uptr->USTAT & STA_DYN) | STA_SET; -if (mta_sta & STA_EFLGS1) - mta_sta = mta_sta | STA_ERR1; -if (mta_sta & STA_EFLGS2) - mta_sta = mta_sta | STA_ERR2; -return mta_sta; -} - -/* Update drive status */ - -void mta_upddsta (UNIT *uptr, int32 newsta) /* drive status */ -{ -int32 change; - -if ((uptr->flags & UNIT_ATT) == 0) /* offline? */ - newsta = 0; -change = (uptr->USTAT ^ newsta) & STA_MON; /* changes? */ -uptr->USTAT = newsta & STA_DYN; /* update status */ -if (change) { -/* if (mta_ep) { *//* if polling */ -/* u = uptr - mta_dev.units; *//* unit num */ -/* mta_sta = (mta_sta & ~STA_UNIT) | (u << STA_V_UNIT); */ -/* set polling interupt... */ -/* } */ - mta_sta = mta_sta | STA_CHG; /* flag change */ - } -return; -} - -/* Map tape error status */ - -t_stat mta_map_err (UNIT *uptr, t_stat st) -{ -switch (st) { - - case MTSE_FMT: /* illegal fmt */ - mta_upddsta (uptr, uptr->USTAT | STA_WLK | STA_RDY); - /* fall through */ - case MTSE_UNATT: /* unattached */ - mta_sta = mta_sta | STA_ILL; - /* fall through */ - case MTSE_OK: /* no error */ - return SCPE_IERR; /* never get here! */ - - case MTSE_TMK: /* end of file */ - mta_upddsta (uptr, uptr->USTAT | STA_RDY | STA_EOF); - break; - - case MTSE_IOERR: /* IO error */ - mta_sta = mta_sta | STA_DAE; /* data error */ - mta_upddsta (uptr, uptr->USTAT | STA_RDY); /* ready */ - return SCPE_IOERR; - - case MTSE_INVRL: /* invalid rec lnt */ - mta_sta = mta_sta | STA_DAE; /* data error */ - mta_upddsta (uptr, uptr->USTAT | STA_RDY); /* ready */ - return SCPE_MTRLNT; - - case MTSE_RECE: /* record in error */ - mta_sta = mta_sta | STA_DAE; /* data error */ - mta_upddsta (uptr, uptr->USTAT | STA_RDY); /* ready */ - break; - - case MTSE_EOM: /* end of medium */ - mta_sta = mta_sta | STA_BAT; /* bad tape */ - mta_upddsta (uptr, uptr->USTAT | STA_RDY); /* ready */ - break; - - case MTSE_BOT: /* reverse into BOT */ - mta_upddsta (uptr, uptr->USTAT | STA_RDY | STA_BOT); - break; - - case MTSE_WRP: /* write protect */ - mta_upddsta (uptr, uptr->USTAT | STA_WLK | STA_RDY); - mta_sta = mta_sta | STA_ILL; /* illegal operation */ - break; - } - -return SCPE_OK; -} - -/* Reset routine */ - -t_stat mta_reset (DEVICE *dptr) -{ -int32 u; -UNIT *uptr; - -dev_busy = dev_busy & ~INT_MTA; /* clear busy */ -dev_done = dev_done & ~INT_MTA; /* clear done, int */ -int_req = int_req & ~INT_MTA; -mta_cu = mta_wc = mta_ma = mta_sta = 0; /* clear registers */ -mta_ep = 0; - -/* AOS Installer does an IORST after a tape rewind command but before it can - be serviced, yet expects the tape to have been rewound */ - -for (u = 0; u < MTA_NUMDR; u++) { /* loop thru units */ - uptr = mta_dev.units + u; - if (sim_is_active (uptr) && /* active and */ - (uptr->flags & STA_REW)) /* rewinding? */ - sim_tape_rewind (uptr); /* update tape */ - sim_tape_reset (uptr); /* clear pos flag */ - sim_cancel (uptr); /* cancel activity */ - if (uptr->flags & UNIT_ATT) uptr->USTAT = STA_RDY | - (uptr->USTAT & STA_PEM) | - (sim_tape_wrp (uptr)? STA_WLK: 0) | - (sim_tape_bot (uptr)? STA_BOT: 0); - else uptr->USTAT = 0; - } -mta_updcsta (&mta_unit[0]); /* update status */ -if (mtxb == NULL) - mtxb = (uint8 *) calloc (MTA_MAXFR, sizeof (uint8)); -if (mtxb == NULL) - return SCPE_MEM; -return SCPE_OK; -} - -/* Attach routine */ - -t_stat mta_attach (UNIT *uptr, char *cptr) -{ -t_stat r; - -r = sim_tape_attach (uptr, cptr); -if (r != SCPE_OK) - return r; -if (!sim_is_active (uptr)) - mta_upddsta (uptr, STA_RDY | STA_BOT | STA_PEM | - (sim_tape_wrp (uptr)? STA_WLK: 0)); -return r; -} - -/* Detach routine */ - -t_stat mta_detach (UNIT* uptr) -{ -if (!(uptr->flags & UNIT_ATT)) /* attached? */ - return SCPE_OK; -if (!sim_is_active (uptr)) - mta_upddsta (uptr, 0); -return sim_tape_detach (uptr); -} - -/* Write lock/unlock validate routine */ - -t_stat mta_vlock (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if ((uptr->flags & UNIT_ATT) && (val || sim_tape_wrp (uptr))) - mta_upddsta (uptr, uptr->USTAT | STA_WLK); -else mta_upddsta (uptr, uptr->USTAT & ~STA_WLK); -return SCPE_OK; -} - -/* Boot routine */ - -t_stat mta_boot (int32 unitno, DEVICE *dptr) - { - sim_tape_rewind( &mta_unit[unitno] ) ; - /* - use common rewind/reset code - device reset - rewind 'tape' file - device - unit - controller - */ - cpu_boot( unitno, dptr ) ; - SR = 0100000 + DEV_MTA ; - return ( SCPE_OK ); - } /* end of 'mta_boot' */ diff --git a/NOVA/nova_plt.c b/NOVA/nova_plt.c deleted file mode 100644 index d24d6a97..00000000 --- a/NOVA/nova_plt.c +++ /dev/null @@ -1,161 +0,0 @@ -/* nova_plt.c: NOVA plotter simulator - - Copyright (c) 2000-2008, Robert M. Supnik - Written by Bruce Ray and used with his gracious permission. - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - plt plotter - - 04-Jul-07 BKR added 7B/8B support (default is 8B), - DEV_SET/CLR macros now used - 25-Apr-03 RMS Revised for extended file support - 03-Oct-02 RMS Added DIB - 30-May-02 RMS Widened POS to 32b - 06-Jan-02 RMS Revised enable/disable support - 26-Apr-01 RMS Added device enable/disable support - - -Notes: - - data masked to 7- or 8- bits, based on 7B or 8B, default is 8-bits - - if register TIME is non-zero, then delay TIME events if , or seen - - register POS show the current file position - - register STOP_IOE determines return value issued if output to unattached PLT is attempted -*/ - -#include "nova_defs.h" - -extern int32 int_req, dev_busy, dev_done, dev_disable; - -int32 plt_stopioe = 0; /* stop on error */ - -DEVICE plt_dev; -int32 plt (int32 pulse, int32 code, int32 AC); -t_stat plt_svc (UNIT *uptr); -t_stat plt_reset (DEVICE *dptr); - - -/* 7 or 8 bit data mask support for either device */ - -#define UNIT_V_8B (UNIT_V_UF + 0) /* 8b output */ -#define UNIT_8B (1 << UNIT_V_8B) - -/* PLT data structures - - plt_dev PLT device descriptor - plt_unit PLT unit descriptor - plt_reg PLT register list -*/ - -DIB plt_dib = { DEV_PLT, INT_PLT, PI_PLT, &plt }; - -UNIT plt_unit = { /* 2007-May-30, bkr */ - UDATA (&plt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_8B, 0), SERIAL_OUT_WAIT - }; - -REG plt_reg[] = { - { ORDATA (BUF, plt_unit.buf, 8) }, - { FLDATA (BUSY, dev_busy, INT_V_PLT) }, - { FLDATA (DONE, dev_done, INT_V_PLT) }, - { FLDATA (DISABLE, dev_disable, INT_V_PLT) }, - { FLDATA (INT, int_req, INT_V_PLT) }, - { DRDATA (POS, plt_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, plt_unit.wait, 24), PV_LEFT }, - { FLDATA (STOP_IOE, plt_stopioe, 0) }, - { NULL } - }; - -MTAB plt_mod[] = /* 2007-May-30, bkr */ - { - { UNIT_8B, 0, "7b", "7B", NULL }, - { UNIT_8B, UNIT_8B, "8b", "8B", NULL }, - { 0, 0, NULL, NULL, NULL } - } ; - -DEVICE plt_dev = { - "PLT", &plt_unit, plt_reg, plt_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &plt_reset, - NULL, NULL, NULL, - &plt_dib, DEV_DISABLE - }; - - -/* plotter: IOT routine */ - -int32 plt (int32 pulse, int32 code, int32 AC) -{ -if (code == ioDOA) - plt_unit.buf = AC & ((plt_unit.flags & UNIT_8B)? - 0377 - : 0177); -switch (pulse) - { /* decode IR<8:9> */ - case iopS: /* start */ - DEV_SET_BUSY( INT_PLT ) ; - DEV_CLR_DONE( INT_PLT ) ; - DEV_UPDATE_INTR ; - sim_activate (&plt_unit, plt_unit.wait); /* activate unit */ - break; - - case iopC: /* clear */ - DEV_CLR_BUSY( INT_PLT ) ; - DEV_CLR_DONE( INT_PLT ) ; - DEV_UPDATE_INTR ; - sim_cancel (&plt_unit); /* deactivate unit */ - break; - } /* end switch */ - -return 0; -} - - -/* Unit service */ - -t_stat plt_svc (UNIT *uptr) -{ -DEV_CLR_BUSY( INT_PLT ) ; -DEV_SET_DONE( INT_PLT ) ; -DEV_UPDATE_INTR ; -if ((plt_unit.flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (plt_stopioe, SCPE_UNATT); -if (putc (plt_unit.buf, plt_unit.fileref) == EOF) { - perror ("PLT I/O error"); - clearerr (plt_unit.fileref); - return SCPE_IOERR; - } -++(plt_unit.pos); -return SCPE_OK; -} - - -/* Reset routine */ - -t_stat plt_reset (DEVICE *dptr) -{ -plt_unit.buf = 0; /* */ -DEV_CLR_BUSY( INT_PLT ) ; -DEV_CLR_DONE( INT_PLT ) ; -DEV_UPDATE_INTR ; -sim_cancel (&plt_unit); /* deactivate unit */ -return SCPE_OK; -} diff --git a/NOVA/nova_pt.c b/NOVA/nova_pt.c deleted file mode 100644 index a6cf23ac..00000000 --- a/NOVA/nova_pt.c +++ /dev/null @@ -1,299 +0,0 @@ -/* nova_pt.c: NOVA paper tape read/punch simulator - - Copyright (c) 1993-2016, Robert M. Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - ptr paper tape reader - ptp paper tape punch - - 13-May-16 RMS Lengthened wait time for DCC BASIC timing error - 28-Mar-15 RMS Revised to use sim_printf - 04-Jul-07 BKR added PTR and PTP device DISABLE capability, - added 7B/8B support PTR and PTP (default is 8B), - DEV_SET/CLR macros now used, - PTR and PTP can now be DISABLED - 25-Apr-03 RMS Revised for extended file support - 03-Oct-02 RMS Added DIBs - 30-May-02 RMS Widened POS to 32b - 29-Nov-01 RMS Added read only unit support - - -Notes: - - data masked to 7- or 8- bits, based on 7B or 8B, default is 8-bits - - register TIME is the delay between character read or write operations - - register POS show the number of characters read from or sent to the PTR or PTP - - register STOP_IOE determines return value issued if output to unattached PTR or PTP is attempted -*/ - -#include "nova_defs.h" - -extern int32 int_req, dev_busy, dev_done, dev_disable ; -extern int32 SR ; - -extern t_stat cpu_boot(int32 unitno, DEVICE * dptr ) ; - - -int32 ptr_stopioe = 0, ptp_stopioe = 0; /* stop on error */ - -int32 ptr (int32 pulse, int32 code, int32 AC); -int32 ptp (int32 pulse, int32 code, int32 AC); -t_stat ptr_svc (UNIT *uptr); -t_stat ptp_svc (UNIT *uptr); -t_stat ptr_reset (DEVICE *dptr); -t_stat ptp_reset (DEVICE *dptr); -t_stat ptr_boot (int32 unitno, DEVICE *dptr); - - -/* 7 or 8 bit data mask support for either device */ - -#define UNIT_V_8B (UNIT_V_UF + 0) /* 8b output */ -#define UNIT_8B (1 << UNIT_V_8B) - - -/* PTR data structures - - ptr_dev PTR device descriptor - ptr_unit PTR unit descriptor - ptr_reg PTR register list -*/ - -DIB ptr_dib = { DEV_PTR, INT_PTR, PI_PTR, &ptr }; - -UNIT ptr_unit = { /* 2007-May-30, bkr */ - UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE+UNIT_8B, 0), 300 - }; - -REG ptr_reg[] = { - { ORDATA (BUF, ptr_unit.buf, 8) }, - { FLDATA (BUSY, dev_busy, INT_V_PTR) }, - { FLDATA (DONE, dev_done, INT_V_PTR) }, - { FLDATA (DISABLE, dev_disable, INT_V_PTR) }, - { FLDATA (INT, int_req, INT_V_PTR) }, - { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, - { FLDATA (STOP_IOE, ptr_stopioe, 0) }, - { NULL } - }; - -MTAB ptr_mod[] = /* 2007-May-30, bkr */ - { - { UNIT_8B, 0, "7b", "7B", NULL }, - { UNIT_8B, UNIT_8B, "8b", "8B", NULL }, - { 0, 0, NULL, NULL, NULL } - } ; - -DEVICE ptr_dev = { - "PTR", &ptr_unit, ptr_reg, ptr_mod /* 2007-May-30, bkr */, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ptr_reset, - &ptr_boot, NULL, NULL, - &ptr_dib, DEV_DISABLE /* 2007-May-30, bkr */ - }; - -/* PTP data structures - - ptp_dev PTP device descriptor - ptp_unit PTP unit descriptor - ptp_reg PTP register list -*/ - -DIB ptp_dib = { DEV_PTP, INT_PTP, PI_PTP, &ptp }; - -UNIT ptp_unit = - { - UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_8B, 0), SERIAL_OUT_WAIT - }; - -REG ptp_reg[] = { - { ORDATA (BUF, ptp_unit.buf, 8) }, - { FLDATA (BUSY, dev_busy, INT_V_PTP) }, - { FLDATA (DONE, dev_done, INT_V_PTP) }, - { FLDATA (DISABLE, dev_disable, INT_V_PTP) }, - { FLDATA (INT, int_req, INT_V_PTP) }, - { DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, - { FLDATA (STOP_IOE, ptp_stopioe, 0) }, - { NULL } - }; - -MTAB ptp_mod[] = - { - { UNIT_8B, 0, "7b", "7B", NULL }, - { UNIT_8B, UNIT_8B, "8b", "8B", NULL }, - { 0, 0, NULL, NULL, NULL } - } ; - -DEVICE ptp_dev = - { - "PTP", &ptp_unit, ptp_reg, ptp_mod /* 2007-May-30, bkr */, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ptp_reset, - NULL, NULL, NULL, - &ptp_dib, DEV_DISABLE /* 2007-May-30, bkr */ - }; - - -/* Paper tape reader: IOT routine */ - -int32 ptr (int32 pulse, int32 code, int32 AC) -{ -int32 iodata; - -iodata = (code == ioDIA)? - ptr_unit.buf & 0377 - : 0; -switch (pulse) - { /* decode IR<8:9> */ - case iopS: /* start */ - DEV_SET_BUSY( INT_PTR ) ; - DEV_CLR_DONE( INT_PTR ) ; - DEV_UPDATE_INTR ; - sim_activate (&ptr_unit, ptr_unit.wait); /* activate unit */ - break; - - case iopC: /* clear */ - DEV_CLR_BUSY( INT_PTR ) ; - DEV_CLR_DONE( INT_PTR ) ; - DEV_UPDATE_INTR ; - sim_cancel (&ptr_unit); /* deactivate unit */ - break; - } /* end switch */ - -return iodata; -} - - -/* Unit service */ - -t_stat ptr_svc (UNIT *uptr) -{ -int32 temp; - -if ((ptr_unit.flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (ptr_stopioe, SCPE_UNATT); -if ((temp = getc (ptr_unit.fileref)) == EOF) { /* end of file? */ - if (feof (ptr_unit.fileref)) { - if (ptr_stopioe) - sim_printf ("PTR end of file\n"); - else return SCPE_OK; - } - else perror ("PTR I/O error"); - clearerr (ptr_unit.fileref); - return SCPE_IOERR; - } - -DEV_CLR_BUSY( INT_PTR ) ; -DEV_SET_DONE( INT_PTR ) ; -DEV_UPDATE_INTR ; -ptr_unit.buf = temp & ((ptr_unit.flags & UNIT_8B)? 0377: 0177); -++(ptr_unit.pos); -return SCPE_OK; -} - - -/* Reset routine */ - -t_stat ptr_reset (DEVICE *dptr) -{ -ptr_unit.buf = 0; /* */ -DEV_CLR_BUSY( INT_PTR ) ; -DEV_CLR_DONE( INT_PTR ) ; -DEV_UPDATE_INTR ; -sim_cancel (&ptr_unit); /* deactivate unit */ -return SCPE_OK; -} - - -/* Boot routine */ - -t_stat ptr_boot (int32 unitno, DEVICE *dptr) -{ -ptr_reset( dptr ) ; -/* set position to 0? */ -cpu_boot( unitno, dptr ) ; -SR = /* low-speed: no high-order bit set */ DEV_PTR ; -return ( SCPE_OK ); -} /* end of 'ptr_boot' */ - - - - - -/* Paper tape punch: IOT routine */ - -int32 ptp (int32 pulse, int32 code, int32 AC) -{ -if (code == ioDOA) - ptp_unit.buf = AC & 0377; - -switch (pulse) - { /* decode IR<8:9> */ - case iopS: /* start */ - DEV_SET_BUSY( INT_PTP ) ; - DEV_CLR_DONE( INT_PTP ) ; - DEV_UPDATE_INTR ; - sim_activate (&ptp_unit, ptp_unit.wait); /* activate unit */ - break; - - case iopC: /* clear */ - DEV_CLR_BUSY( INT_PTP ) ; - DEV_CLR_DONE( INT_PTP ) ; - DEV_UPDATE_INTR ; - sim_cancel (&ptp_unit); /* deactivate unit */ - break; - } /* end switch */ - -return 0; -} - - -/* Unit service */ - -t_stat ptp_svc (UNIT *uptr) -{ -DEV_CLR_BUSY( INT_PTP ) ; -DEV_SET_DONE( INT_PTP ) ; -DEV_UPDATE_INTR ; -if ((ptp_unit.flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (ptp_stopioe, SCPE_UNATT); -if (putc ((ptp_unit.buf & ((ptp_unit.flags & UNIT_8B)? 0377: 0177)), ptp_unit.fileref) == EOF) { - perror ("PTP I/O error"); - clearerr (ptp_unit.fileref); - return SCPE_IOERR; - } -++(ptp_unit.pos); -return SCPE_OK; -} - - -/* Reset routine */ - -t_stat ptp_reset (DEVICE *dptr) -{ -ptp_unit.buf = 0; /* */ -DEV_CLR_BUSY( INT_PTP ) ; -DEV_CLR_DONE( INT_PTP ) ; -DEV_UPDATE_INTR ; -sim_cancel (&ptp_unit); /* deactivate unit */ -return SCPE_OK; -} diff --git a/NOVA/nova_qty.c b/NOVA/nova_qty.c deleted file mode 100644 index 5e03e74a..00000000 --- a/NOVA/nova_qty.c +++ /dev/null @@ -1,1074 +0,0 @@ -/* nova_qty.c: NOVA multiplexor (QTY/ALM) simulator - - Copyright (c) 2000-2015, Robert M. Supnik - Written by Bruce Ray and used with his gracious permission. - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - qty multiplexor: QTY = 4060, ALM = 42xx - - 28-Mar-15 RMS Revised to use sim_printf - 14-Mar-12 RMS Fixed dangling else clauses - 04-Jul-07 BKR Fixed QTY output line number calculation (affected higher line numbers), - 25-Mar-04 RMS Updated for V3.2 - 12-Jan-04 BKR Initial release - includes both original DG "quad" multiplexor (QTY) - and later Asynchronous Line Multiplexor (ALM) support. -*/ - - -/*----------------------------------------------------------------------*/ -/* QTY [4060-compatible] multiplexor */ -/*----------------------------------------------------------------------*/ - -/* - * Emulate the DG 4060 "quad" (QTY) serial port multiplexor. DG modem - * control is not supported in this revision due to its obtuse nature - * of using a separate [semi-secret] device MDM which is actually part - * of the DG 4026/4027 multiplexor hardware(!). - * (Full modem support is provided in the ALM driver.) - * - * - * 4060 Hardware - * - * device code: 030 [primary], - * 070 [secondary] - * interrupt mask: B14 [000002] - * ASM mnemonic: QTY - * - * - * 4060 Input/Output Word Format: - * - * _________________________________________________________________ - * | RI| TI| channel | character | - * ----+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+ - * 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 - * - * - * RI - receiver interrupt - * TI - transmitter interrupt - * channel - channel number, 0 - 63. - * character- character (valid if receiver interrupt, undefined if transmitter) - * - * Notes: - * - * Maximum 64 lines supported. - * DONE set whenever any received character fully assembled and ready, - * or when any output character transmitted and line is ready - * to accept next output character. - * BUSY set whenever output character is being sent on any line. - * Note that early 4060s did NOT have a busy flag! - * IORST clears device Done, no other user instruction does. - * IORST clears each line's individual R.I. and T.I. - * - * - * Instructions: - * - * DIA get multiplexor status word [format defined above] - * DOA send character to QTY line [format defined above, RI & SI ] - * DIB [returns backplane bus noise] - * DOB clear QTY line - * DIC [returns backplace bus noise] - * DOC - * 'C' clears global done, then checks for RI and TI; - * 'P' - * 'S' - */ - - -#include "nova_defs.h" - -#include "sim_sock.h" -#include "sim_tmxr.h" - - -#define UNIT_V_8B (UNIT_V_UF + 0) /* 8b output */ -#define UNIT_8B (1 << UNIT_V_8B) - - - -extern int32 int_req, dev_busy, dev_done, dev_disable ; -extern int32 tmxr_poll ; /* calibrated delay */ - -t_stat qty_setnl ( UNIT * uptr, int32 val, char * cptr, void * desc ) ; - -t_stat qty_attach ( UNIT * uptr, char * cptr ) ; -t_stat qty_detach ( UNIT * uptr ) ; -t_stat qty_reset ( DEVICE * dptr ) ; -t_stat qty_svc ( UNIT * uptr ) ; -int32 qty ( int32 pulse, int32 code, int32 AC ) ; - -t_stat alm_reset ( DEVICE * dptr ) ; -t_stat alm_svc ( UNIT * uptr ) ; -int32 alm ( int32 pulse, int32 code, int32 AC ) ; - -DEVICE alm_dev ; - - -#define QTY_MAX 64 /* max number of QTY lines - hardware */ - - -int32 qty_brkio = SCPE_OK ; /* default I/O status code */ -int32 qty_max = QTY_MAX ; /* max # QTY lines - user */ - /* controllable */ -int32 qty_mdm = 0 ; /* QTY modem control active? */ -int32 qty_auto = 0 ; /* QTY auto disconnect active? */ -int32 qty_polls = 0 ; /* total 'qty_svc' polls */ - - -TMLN qty_ldsc[ QTY_MAX ] = { {0} } ; /* QTY line descriptors */ -TMXR qty_desc = { QTY_MAX, 0, 0, qty_ldsc } ; /* mux descriptor */ -int32 qty_status[ QTY_MAX ] = { 0 } ; /* QTY line status */ - /* (must be at least 32 bits) */ -int32 qty_tx_chr[ QTY_MAX ] = { 0 } ; /* QTY line output character */ - - -/* QTY data structures - - qty_dev QTY device descriptor - qty_unit QTY unit descriptor - qty_reg QTY register list -*/ - -DIB qty_dib = { DEV_QTY, INT_QTY, PI_QTY, &qty } ; - -UNIT qty_unit = - { - UDATA (&qty_svc, (UNIT_ATTABLE), 0) - } ; - -REG qty_reg[] = /* ('alm_reg' should be similar to this except for device code related items) */ - { - { ORDATA (BUF, qty_unit.buf, 8) }, - { FLDATA (BUSY, dev_busy, INT_V_QTY) }, - { FLDATA (DONE, dev_done, INT_V_QTY) }, - { FLDATA (DISABLE, dev_disable, INT_V_QTY) }, - { FLDATA (INT, int_req, INT_V_QTY) }, - - { FLDATA (MDMCTL, qty_mdm, 0) }, - { FLDATA (AUTODS, qty_auto, 0) }, - { DRDATA (POLLS, qty_polls, 32) }, - { NULL } - } ; - -MTAB qty_mod[] = - { - { UNIT_8B, 0, "7b", "7B", NULL }, - { UNIT_8B, UNIT_8B, "8b", "8B", NULL }, - { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", - &tmxr_dscln, NULL, (void *)&qty_desc }, - { UNIT_ATT, UNIT_ATT, "connections", NULL, - NULL, &tmxr_show_summ, (void *)&qty_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, - NULL, &tmxr_show_cstat, (void *)&qty_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, - NULL, &tmxr_show_cstat, (void *)&qty_desc }, - { MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES", - &qty_setnl, &tmxr_show_lines, (void *) &qty_desc }, - { 0 } - } ; - -DEVICE qty_dev = - { - "QTY", &qty_unit, qty_reg, qty_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &qty_reset, - NULL, &qty_attach, &qty_detach, - &qty_dib, (DEV_DISABLE | DEV_DIS | DEV_MUX) - }; - -#define DG_RETURN( status, data ) (int32)(((status) << IOT_V_REASON) | ((data) & 0x0FFFF) ) - -/* - * QTY_S_xxx QTY device status reference - * QTY_L_xxx QTY line status word reference (qty_status[]) - */ - - /*----------------------------------------------*/ - /* QTY device status */ - /*----------------------------------------------*/ - -#define QTY_S_RI 0x8000 /* Receiver Interrupt */ -#define QTY_S_TI 0x4000 /* Transmitter interrupt */ -#define QTY_S_LMASK 0x3F00 /* line mask */ -#define QTY_S_DMASK 0x00FF /* data mask (received char) */ - - - -#define QTY_MASTER_ACTIVE( desc ) ( (desc)->master ) - -#define QTY_LINE_EXTRACT( x ) (((x) & QTY_S_LMASK) >> 8) - -#define QTY_LINE_TX_CHAR( line ) qty_tx_chr[ ((line) % QTY_MAX) ] -#define QTY_LINE_RX_CHAR( line ) (qty_status[ (line) ] & QTY_S_DMASK) -#define QTY_UNIT_ACTIVE( unitp ) ( (unitp)->conn ) - -#define QTY_LINE_BITS( line, bits ) (qty_status[ (line) ] & bits) - -#define QTY_LINE_SET_BIT( line, bit ) qty_status[ (line) ] |= (bit) ; -#define QTY_LINE_CLEAR_BIT( line, bit ) qty_status[ (line) ] &= ~(bit) ; -#define QTY_LINE_BIT_SET( line, bit ) (qty_status[ (line) ] & (bit)) - - - /*----------------------------------------------*/ - /* QTY line status */ - /*----------------------------------------------*/ - -#define QTY_L_RXE 0x800000 /* receiver enabled? */ -#define QTY_L_RXBZ 0x400000 /* receiver busy? */ -#define QTY_L_RXDN 0x200000 /* receiver done? */ -#define QTY_L_TXE 0x080000 /* transmitter enabled? */ -#define QTY_L_TXBZ 0x040000 /* transmitter busy? */ -#define QTY_L_TXDN 0x020000 /* transmitter done? */ - -#define QTY_L_BREAK 0x008000 /* BREAK character received */ -#define QTY_L_RING 0x004000 /* Ring interrupt */ -#define QTY_L_CD 0x002000 /* Carrier Detect */ -#define QTY_L_DTR 0x001000 /* Data Terminal Ready */ - /* <0x00FF = character> */ - -#define QTY_L_LOOPBK 0x00010000 /* loopback mode */ -#define QTY_L_OVRERR 0x00020000 /* overrun error */ -#define QTY_L_FRMERR 0x00040000 /* framing error */ -#define QTY_L_PARERR 0x00080000 /* parity error */ - - -/* CD, CTS, DSR, RI */ - /* */ - -#define QTY_L_MODEM 0x0080 /* */ -#define QTY_L_TELNET 0x0040 /* */ -#define QTY_L_AUTODIS 0x0020 /* */ -#define QTY_L_PARITY -#define QTY_L_7BIT -#define QTY_L_BAUD /* <4 bits> */ - - -#define QTY_L_DMASK 0x000FF /* data mask (always 8 bits) */ - -/* Note: use at least an 'int32' for this guy */ - - /*------------------------------*/ - /* qty_tmxr_putc */ - /*------------------------------*/ - -int qty_tmxr_putc( int line, TMLN * lp, int kar ) - { - int a ; - - /*----------------------------------------------*/ - /* Send character to given QTY/telnet line. */ - /* */ - /* enter: line QTY line # */ - /* lp Telnet unit def ptr */ - /* kar character to send */ - /* */ - /* return: SCPE_OK */ - /* SCPE_STALL */ - /* SCPE_LOST */ - /*----------------------------------------------*/ - - a = tmxr_putc_ln( lp, kar ) ; - if ( a == SCPE_OK) - { - QTY_LINE_SET_BIT( line, QTY_L_TXDN ) - QTY_LINE_CLEAR_BIT( line, QTY_L_TXBZ ) - } - else if ( a == SCPE_STALL ) - { - /* - (should we try to output the buffer - and then regroup...?) - */ - QTY_LINE_SET_BIT( line, QTY_L_TXBZ ) - QTY_LINE_CLEAR_BIT( line, QTY_L_TXDN ) - QTY_LINE_TX_CHAR( line ) = kar ; - } - else if ( a == SCPE_LOST ) - { - /* no connection - hangup? */ - QTY_LINE_SET_BIT( line, QTY_L_TXBZ ) - QTY_LINE_CLEAR_BIT( line, QTY_L_TXDN ) - QTY_LINE_TX_CHAR( line ) = kar ; - } - return ( a ) ; - } /* end of 'qty_tmxr_putc' */ - - - /*----------------------------------------------*/ - /* qty_update_rcvi */ - /*----------------------------------------------*/ - -int qty_update_rcvi( TMXR * mp ) - { - int line ; - TMLN * lp ; - int32 datum ; - int changes ; - - /*------------------------------------------------------*/ - /* Search through connected telnet lines for any input */ - /* activity. */ - /* */ - /* enter: mp master telnet qty desc ptr */ - /* */ - /* return: int change count (0 = none seen) */ - /*------------------------------------------------------*/ - - for ( changes = line = 0; line < mp->lines; ++line ) - if ( (lp=mp->ldsc+line)->conn && lp->rcve ) - if ( (datum=tmxr_getc_ln(lp)) ) - { - if ( datum & SCPE_BREAK ) - { - /* what should we do here - set QTY_L_BREAK? */ - datum = datum & 0x00FF ; - } - else - { - datum = datum & 0x00FF ; - } - /* */ - - QTY_LINE_CLEAR_BIT( line, (QTY_L_RXBZ | QTY_L_DMASK) ) ; - QTY_LINE_SET_BIT( line, (QTY_L_RXDN | datum) ) ; - ++changes ; - } - return ( changes ) ; - } /* end of 'qty_update_rcvi' */ - - - /*----------------------------------------------*/ - /* qty_update_xmti */ - /*----------------------------------------------*/ - -int qty_update_xmti( TMXR * mp ) - { - int line ; - TMLN * lp ; - int changes ; - - /*------------------------------------------------------*/ - /* Search through connected telnet lines for any de- */ - /* ferred output activity. */ - /* */ - /* enter: mp master telnet qty desc ptr */ - /* */ - /* return: int change count (0 = none seen) */ - /*------------------------------------------------------*/ - - /* any TX DONE flags set - * any TX BUSY flags set - */ - - for ( changes = line = 0; line < mp->lines; ++line ) - if ( QTY_LINE_BIT_SET(line,QTY_L_TXBZ) ) - if ( (lp=mp->ldsc+line)->conn && lp->xmte ) - { - /* why are we busy? buffer was full? */ - /* now some space available - try - * to stuff pending character in - * buffer and free up the world - */ - qty_tmxr_putc( line, lp, QTY_LINE_TX_CHAR(line) ) ; - ++changes ; - } - return ( changes ) ; - } /* end of 'qty_update_xmti' */ - - - /*----------------------------------------------*/ - /* qty_update_status */ - /*----------------------------------------------*/ - -int qty_update_status( DIB * dibp, TMXR * tmxr_desc ) - { - int line ; - int status ; - int txbusy ; - - /*----------------------------------------------*/ - /* return global device status for current qty */ - /* state. */ - /* */ - /* Receiver interrupts have higher priority */ - /* than transmitter interrupts according to DG */ - /* but this routine could be modified to use */ - /* different priority criteria. */ - /* */ - /* Round-robin polling could also be used in */ - /* some future release rather than starting */ - /* with line 0 each time. */ - /* */ - /* Return of */ - /* first waiting character, else return */ - /* of first finished line */ - /* output, else return 0. */ - /* */ - /* This routine does -not- clear input line */ - /* BZ/DN flags; caller should do this. */ - /* */ - /* Global device done and busy flags are */ - /* updated. */ - /*----------------------------------------------*/ - - for ( txbusy = status = line = 0 ; line < qty_max ; ++line ) - { - txbusy |= (QTY_LINE_BIT_SET(line,QTY_L_TXBZ)) ; - if ( QTY_LINE_BIT_SET(line,QTY_L_RXDN) ) - { - if ( ! status ) - { - status = QTY_LINE_BITS( line, QTY_S_DMASK ) | QTY_S_RI ; - status = status | (line << 8) ; - } - break ; - } - else if ( QTY_LINE_BIT_SET(line,QTY_L_TXDN) ) - { - if ( ! (status & QTY_S_RI) ) - if ( ! (status & QTY_S_RI) ) - { - status = QTY_S_TI ; - status = status | (line << 8) ; - } - } - } - /* */ - DEV_CLR_BUSY( INT_QTY ) ; - DEV_CLR_DONE( INT_QTY ) ; - if ( txbusy ) - { - DEV_SET_BUSY( INT_QTY ) ; - } - if ( status & (QTY_S_RI | QTY_S_TI) ) - { - DEV_SET_DONE( INT_QTY ) ; - } - DEV_UPDATE_INTR ; /* update final intr status */ - return ( status ) ; - } /* end of 'qty_update_status' */ - - - /*--------------------------------------------------------------*/ - /* qty_attach */ - /*--------------------------------------------------------------*/ - -t_stat qty_attach( UNIT * unitp, char * cptr ) - { - t_stat r ; - int a ; - - /* switches: A auto-disconnect - * M modem control - */ - - qty_mdm = qty_auto = 0; /* modem ctl off */ - r = tmxr_attach( &qty_desc, unitp, cptr ) ; /* attach QTY */ - if ( r != SCPE_OK ) - { - return ( r ) ; /* error! */ - } - if ( sim_switches & SWMASK('M') ) /* modem control? */ - { - qty_mdm = 1; - sim_printf( "Modem control activated\n" ) ; - if ( sim_switches & SWMASK ('A') ) /* autodisconnect? */ - { - qty_auto = 1 ; - sim_printf( "Auto disconnect activated\n" ) ; - } - } - qty_polls = 0 ; - for ( a = 0 ; a < QTY_MAX ; ++a ) - { - /* QTY lines are always enabled - force RX and TX to 'enabled' */ - qty_status[ a ] = (QTY_L_RXE | QTY_L_TXE) ; - } - sim_activate( unitp, tmxr_poll ) ; - return ( SCPE_OK ) ; - } /* end of 'qty_attach' */ - - - /*--------------------------------------------------------------*/ - /* qty_detach */ - /*--------------------------------------------------------------*/ - -t_stat qty_detach( UNIT * unitp ) - { - sim_cancel( unitp ) ; - return ( tmxr_detach(&qty_desc,unitp) ) ; - } /* end of 'qty_detach' */ - - - /*--------------------------------------------------------------*/ - /* qty_clear */ - /*--------------------------------------------------------------*/ - -t_stat qty_clear( t_bool flag ) - { - int line ; - - for ( line = 0 ; line < qty_max ; ++line ) - { - qty_ldsc[line].xmte = 0 ; - qty_ldsc[line].rcve = 0 ; - if ( ! qty_ldsc[line].conn ) - { - qty_ldsc[line].xmte = 1 ; /* set xmt enb */ - qty_ldsc[line].rcve = 1 ; /* clr rcv enb */ - } - } - return ( SCPE_OK ) ; - } /* end of 'qty_clear' */ - - - /*----------------------------------------------*/ - /* qty_common_reset */ - /*----------------------------------------------*/ - -t_stat qty_common_reset( DIB * dibp, UNIT * unitp, DEVICE * dptr ) - { - if ((dptr->flags & DEV_DIS) == 0) - { - if (dptr == &qty_dev) alm_dev.flags |= DEV_DIS; - else qty_dev.flags |= DEV_DIS; - } - qty_clear( TRUE ) ; - DEV_CLR_BUSY( INT_QTY ) ; /* clear busy */ - DEV_CLR_DONE( INT_QTY ) ; /* clear done, int */ - DEV_UPDATE_INTR ; - if ( QTY_MASTER_ACTIVE(&qty_desc) ) - { - sim_activate( unitp, tmxr_poll ) ; - } - else - { - sim_cancel( unitp ) ; - } - return ( SCPE_OK ) ; - } /* end of 'qty_common_reset' */ - - - /*--------------------------------------------------------------*/ - /* qty_reset */ - /*--------------------------------------------------------------*/ - -t_stat qty_reset( DEVICE * dptr ) - { - return ( qty_common_reset(&qty_dib,&qty_unit,dptr) ) ; - } /* end of 'qty_reset' */ - - -/* Unit service routine - - The QTY/ALM polls to see if asynchronous activity has occurred and now - needs to be processed. The polling interval is controlled by the clock - simulator, so for most environments, it is calibrated to real time. - - The simulator assumes that software enables all of the multiplexors, - or none of them. -*/ - - /*----------------------------------------------*/ - /* qty_common_svc */ - /*----------------------------------------------*/ - -t_stat qty_common_svc( DIB * dibp, UNIT * unitp ) - { - int line ; - int newln ; - TMLN * tmlnp ; - - ++qty_polls ; /* another time 'round the track */ - newln = tmxr_poll_conn( &qty_desc ) ; /* anybody knocking at the door? */ - if ( (newln >= 0) && qty_mdm ) - { - if ( newln >= qty_max ) - { - return SCPE_IERR; /* WTF - sanity check failed, over? */ - } - else - { - line = newln ; /* handle modem control */ - tmlnp =&qty_ldsc[ line ] ; - tmlnp->rcve = tmlnp->xmte = 1 ; - /* do QTY_LINE_ bit fiddling and state machine - * manipulation with modem control signals - */ - } - } - - tmxr_poll_rx( &qty_desc ) ; /* poll input */ - qty_update_rcvi( &qty_desc ) ; /* update receiver interrupt status */ - - tmxr_poll_tx( &qty_desc ) ; /* poll output */ - qty_update_xmti( &qty_desc ) ; /* update transmitter interrupt status */ - - qty_update_status( dibp, &qty_desc ) ; /* update device status */ - - sim_activate( unitp, tmxr_poll ) ; /* restart the bubble machine */ - return ( SCPE_OK ) ; - } /* end of 'qty_common_svc' */ - - - /*--------------------------------------------------------------*/ - /* qty_svc */ - /*--------------------------------------------------------------*/ - -t_stat qty_svc( UNIT * uptr ) - { - return ( qty_common_svc(&qty_dib,uptr) ) ; - } /* end of 'qty_svc' */ - - - /*--------------------------------------------------------------*/ - /* qty */ - /*--------------------------------------------------------------*/ - -int32 qty( int32 pulse, int32 code, int32 AC ) - { - int32 iodata ; - int32 ioresult ; - int line ; - TMLN * tmlnp ; - int a ; - int kar ; - - /*--------------------------------------------------------------*/ - /* DG 4060[-compatible] "quad" multiplexor instruction handler */ - /*--------------------------------------------------------------*/ - - ioresult= qty_brkio ; /* (assume returning I/O break value */ - iodata = 0 ; /* (assume 16-bit Nova/Eclipse bus) */ - switch ( code ) - { - case ioNIO : /* */ - break ; - - case ioDIA : /* get current QTY status */ - iodata = qty_update_status( &qty_dib, &qty_desc ) ; - if ( iodata & QTY_S_RI ) - { /* clear line's input buffer */ - QTY_LINE_CLEAR_BIT( (QTY_LINE_EXTRACT(iodata)), (QTY_L_RXBZ | QTY_L_RXDN) ) - /* - character masking ; - parity checking ; - parity generating ; - */ - } - qty_update_status( &qty_dib, &qty_desc ) ; - break ; - - case ioDOA : /* send character to QTY */ - line = QTY_LINE_EXTRACT( AC ) ; - if ( line < qty_max ) - if ( QTY_LINE_BIT_SET(line,QTY_L_TXE) ) - { - /* - perform any character translation: - 7 bit/ 8 bit - parity generation - */ - kar = AC & ((qty_unit.flags & UNIT_8B)? 0377: 0177) ; - /* do any parity calculations also */ - - tmlnp = &qty_ldsc[ line ] ; - a = qty_tmxr_putc( line, tmlnp, kar ) ; - if ( a != SCPE_OK) - { - /* do anything at this point? */ - } - qty_update_status( &qty_dib, &qty_desc ) ; - } - break ; - - case ioDIB : /* no QTY function - return bus noise in AC */ - break ; - - case ioDOB : /* clear QTY output channel busy and done flag */ - QTY_LINE_CLEAR_BIT( (QTY_LINE_EXTRACT(AC)), (QTY_L_TXBZ | QTY_L_TXDN) ) - qty_update_status( &qty_dib, &qty_desc ) ; - break ; - - case ioDIC : /* no QTY function - return bus noise in AC */ - break ; - - case ioDOC : /* no QTY function - ignore */ - break ; - - case ioSKP : /* I/O skip test - should never come here */ - break ; - - default : - /* */ - break ; - } - - switch ( pulse ) - { - case iopN : /* */ - break ; - - case iopS : /* */ - break ; - - case iopP : /* */ - break ; - - case iopC : - qty_update_status( &qty_dib, &qty_desc ) ; - break ; - - default : - /* */ - break ; - } - - return ( DG_RETURN( ioresult, iodata ) ) ; - } /* end of 'qty' */ - - /*--------------------------------------------------------------*/ - /* qty_setnl */ - /*--------------------------------------------------------------*/ - -t_stat qty_setnl( UNIT * uptr, int32 val, char * cptr, void * desc ) - { - int32 newln, i, t ; - - t_stat r ; - if ( cptr == NULL ) - { - return ( SCPE_ARG ) ; - } - newln = (int32) get_uint( cptr, 10, QTY_MAX, &r ) ; - if ( (r != SCPE_OK) || (newln == qty_desc.lines) ) - { - return ( r ) ; - } - if ( (newln == 0) || (newln > QTY_MAX) ) - { - return ( SCPE_ARG ) ; - } - if ( newln < qty_desc.lines ) - { - for ( i = newln, t = 0 ; i < qty_desc.lines ; ++i ) - { - t = t | qty_ldsc[i].conn ; - } - if ( t && ! get_yn("This will disconnect users; proceed [N]?", FALSE) ) - { - return ( SCPE_OK ) ; - } - for ( i = newln ; i < qty_desc.lines ; ++i ) - { - if ( qty_ldsc[i].conn ) - { /* reset line */ - tmxr_msg( qty_ldsc[i].conn, "\r\nOperator disconnected line\r\n" ) ; - tmxr_reset_ln( &qty_ldsc[i] ) ; - } - qty_clear( TRUE ) ; /* reset mux */ - } - } - qty_max = qty_desc.lines = newln ; - /* Huh, I don't understand this yet... - qty_max = ((qty_dev.flags & DEV_DIS)? 0 : (qty_desc.lines / QTY_MAX)) ; - */ - return ( SCPE_OK ) ; - } /* end of 'qty_setnl' */ - - -/*----------------------------------------------------------------------*/ -/* ALM [425x-compatible] multiplexor */ -/*----------------------------------------------------------------------*/ - -/* - * device code: 034 [primary], - * 074 [secondary] - * interrupt mask: B14 [000002] - * ASM mnemonic: ALM - * - * ALM [4255-4258] I/O instructions - * - * DIA read line and section requesting service - * DOA select line and section (lines 0-255, 8-bits) + rcvr/xmit - * DIB receive data - * DOB 00 transmit data - * 01 transmit BREAK - * 10 set modem control status - * 11 - * DIC read receiver or modem status - * DOC 00 control line section and diag mode - * 01 - * 10 specify line characteristics - * 11 - * - * undocumented DG "features": - * - * NIOS sets board offline - * NIOC sets board online - * Modem control signal state change can signal interrupt - * explicit line select with DOA - * implicit line select with DIA - * - * We support 64 lines maximum in this release although some ALM's could - * theoretically support up to 256. - */ - - -DIB alm_dib = { DEV_ALM, INT_ALM, PI_ALM, &alm } ; -UNIT alm_unit = - { - UDATA (&alm_svc, (UNIT_ATTABLE), 0) - } ; - -REG alm_reg[] = /* ('qty_reg' should be similar to this except for device code related items) */ - { - { ORDATA (BUF, alm_unit.buf, 8) }, - { FLDATA (BUSY, dev_busy, INT_V_ALM) }, - { FLDATA (DONE, dev_done, INT_V_ALM) }, - { FLDATA (DISABLE, dev_disable, INT_V_ALM) }, - { FLDATA (INT, int_req, INT_V_ALM) }, - - { FLDATA (MDMCTL, qty_mdm, 0) }, - { FLDATA (AUTODS, qty_auto, 0) }, - { DRDATA (POLLS, qty_polls, 32) }, - { NULL } - } ; - -DEVICE alm_dev = - { - "ALM", &alm_unit, alm_reg, qty_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &alm_reset, - NULL, &qty_attach, &qty_detach, - &alm_dib, (DEV_DISABLE | DEV_NET) - } ; - -int alm_section = -1 ; /* current line "section" (0 = RCV, 1 = XMT) */ -int alm_line = -1 ; /* current line [0-63] */ -int alm_diag_mode = 0 ; /* */ -int alm_line_mask = 0x003F ; /* maximum of 64 lines in this rev */ - - -#define ALM_LINE_EXTRACT( x ) (((x) >> 1) & alm_line_mask) -#define ALM_SECT_EXTRACT( x ) ((x) & 0x0001) - - - /*--------------------------------------------------------------*/ - /* alm_reset */ - /*--------------------------------------------------------------*/ - -t_stat alm_reset( DEVICE * dptr ) - { - return ( qty_common_reset(&alm_dib,&alm_unit,dptr) ) ; - } /* end of 'alm_reset' */ - - - /*--------------------------------------------------------------*/ - /* alm_svc */ - /*--------------------------------------------------------------*/ - -t_stat alm_svc( UNIT * uptr ) - { - return ( qty_common_svc(&alm_dib,uptr) ) ; - } /* end of 'alm_svc' */ - - - /*--------------------------------------------------------------*/ - /* alm */ - /*--------------------------------------------------------------*/ - -int32 alm( int32 pulse, int32 code, int32 AC ) - { - int32 iodata ; - int32 ioresult ; - TMLN * tmlnp ; - int a ; - int kar ; - - /*--------------------------------------------------------------*/ - /* DG 425x[-compatible] "ALM" multiplexor instruction handler */ - /*--------------------------------------------------------------*/ - - ioresult= qty_brkio ; /* (assume returning I/O break value */ - iodata = 0 ; /* (assume 16-bit Nova/Eclipse bus) */ - switch ( code ) - { - case ioNIO : /* */ - break ; - - case ioDIA : /* read line and section requesting service */ - iodata = qty_update_status( &alm_dib, &qty_desc ) ; - alm_line = (QTY_LINE_EXTRACT(iodata) & alm_line_mask) ; - /* (mask with 'alm_line_mask' in case ALM mask is different than QTY */ - alm_section = 0 ; - if ( ! ( iodata & QTY_S_RI) ) - if ( iodata & QTY_S_TI ) - { - alm_section = 1 ; /* receiver quiet - transmitter done */ - } - iodata = (alm_line << 1) | alm_section ; - break ; - - case ioDOA : /* set line and section */ - alm_section = ALM_SECT_EXTRACT( AC ) ; - alm_line = ALM_LINE_EXTRACT( AC ) ; - break ; - - case ioDIB : /* no ALM function - return bus noise in AC */ - if ( alm_line < qty_max ) - { - iodata = QTY_LINE_RX_CHAR( alm_line ) ; - } - break ; - - case ioDOB : /* output and modem control functions */ - switch ( (AC >> 14) & 03 ) - { - case 00 : /* transmit data */ - if ( alm_line < qty_max ) - if ( QTY_LINE_BIT_SET(alm_line,QTY_L_TXE) ) - { - /* - perform any character translation: - 7 bit/ 8 bit - parity generation - */ - kar = AC & ((alm_unit.flags & UNIT_8B)? 0377: 0177) ; - /* do any parity calculations also */ - - tmlnp = &qty_ldsc[ alm_line ] ; - a = qty_tmxr_putc( alm_line, tmlnp, kar ) ; - if ( a != SCPE_OK) - { - /* do anything at this point? */ - } - qty_update_status( &alm_dib, &qty_desc ) ; - } - break ; - - case 01 : /* transmit break */ - if ( alm_line < qty_max ) - if ( QTY_LINE_BIT_SET(alm_line,QTY_L_TXE) ) - { - tmlnp = &qty_ldsc[ alm_line ] ; - /* - a = qty_tmxr_putc( alm_line, tmlnp, kar ) ; - if ( a != SCPE_OK) - { - } - */ - qty_update_status( &alm_dib, &qty_desc ) ; - } - break ; - - case 02 : /* set modem control status */ - break ; - - case 03 : /* unused */ - break ; - } - break ; - - case ioDIC : /* get modem or receiver status */ - if ( alm_line < qty_max ) - { - if ( alm_section ) - { - /* get modem section status */ - if ( qty_ldsc[ alm_line ].xmte ) - { - iodata = 0035 ; /* set CD, CTS, DSR, MDM flags */ - } - } - else - { - /* get receiver section status */ - iodata = 0 ; /* receiver error status - no errors by default */ - } - } - break ; - - case ioDOC : /* set line attributes */ - switch ( (AC >> 14) & 03 ) - { - case 00 : /* control line section */ - break ; - - case 01 : /* unused */ - break ; - - case 02 : /* set line characteristics */ - break ; - - case 03 : /* unused */ - break ; - } - break ; - - case ioSKP : /* I/O skip test - should never come here */ - break ; - - default : - /* */ - break ; - } - - switch ( pulse ) - { - case iopN : /* */ - break ; - - case iopS : /* set device busy - * set all lines on board offline - * clear each line's done - * clear internal system - * clear device busy - */ - for ( a = 0 ; a < qty_max ; ++a ) - if ( 1 /* (not yet optimized) */ ) - { - QTY_LINE_CLEAR_BIT( a, (QTY_L_RXBZ | QTY_L_RXDN | QTY_L_TXBZ | QTY_L_TXDN) ) ; - } - qty_update_status( &alm_dib, &qty_desc ) ; - break ; - - case iopP : /* stop clock for all boards in off-line mode */ - break ; - - case iopC : - for ( a = 0 ; a < qty_max ; ++a ) - if ( 1 /* (not yet optimized) */ ) - { - QTY_LINE_CLEAR_BIT( a, (QTY_L_RXBZ | QTY_L_RXDN | QTY_L_TXBZ | QTY_L_TXDN) ) ; - } - qty_update_status( &alm_dib, &qty_desc ) ; - break ; - - default : - /* */ - break ; - } - - return ( DG_RETURN( ioresult, iodata ) ) ; - } /* end of 'alm' */ diff --git a/NOVA/nova_sys.c b/NOVA/nova_sys.c deleted file mode 100644 index d0779afd..00000000 --- a/NOVA/nova_sys.c +++ /dev/null @@ -1,1188 +0,0 @@ -/* nova_sys.c: NOVA simulator interface - - Copyright (c) 1993-2017, 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. - - 09-Mar-17 RMS Fixed missing break in loader (COVERITY) - Fixed overlook case in address parse (COVERITY) - 25-Mar-12 RMS Fixed declaration (Mark Pizzolato) - 04-Jul-07 BKR DEC's IOF/ION changed to DG's INTDS/INTEN mnemonic, - Fixed QTY/ADCV device name - RDSW changed to DDG's READS mnemonic, - fixed/enhanced 'load' command for DG-compatible binary tape format - 26-Mar-04 RMS Fixed warning with -std=c99 - 14-Jan-04 BKR Added support for QTY and ALM - 04-Jan-04 RMS Fixed 64b issues found by VMS 8.1 - 24-Nov-03 CEO Added symbolic support for LEF instruction - 17-Sep-01 RMS Removed multiconsole support - 31-May-01 RMS Added multiconsole support - 14-Mar-01 RMS Revised load/dump interface (again) - 22-Dec-00 RMS Added second terminal support - 10-Dec-00 RMS Added Eclipse support - 08-Dec-00 BKR Added plotter support - 30-Oct-00 RMS Added support for examine to file - 15-Oct-00 RMS Added stack, byte, trap instructions - 14-Apr-99 RMS Changed t_addr to unsigned - 27-Oct-98 RMS V2.4 load interface - 24-Sep-97 RMS Fixed bug in device name table (Charles Owen) -*/ - -#include "nova_defs.h" -#include - -extern DEVICE cpu_dev; -extern UNIT cpu_unit; -extern DEVICE ptr_dev; -extern DEVICE ptp_dev; -extern DEVICE plt_dev; -extern DEVICE tti_dev; -extern DEVICE tto_dev; -extern DEVICE tti1_dev; -extern DEVICE tto1_dev; -extern DEVICE clk_dev; -extern DEVICE lpt_dev; -extern DEVICE dkp_dev; -extern DEVICE dsk_dev; -extern DEVICE mta_dev; -extern DEVICE qty_dev; -extern DEVICE alm_dev; -extern REG cpu_reg[]; -extern uint16 M[]; -extern int32 saved_PC; -extern int32 AMASK; - -#if defined (ECLIPSE) - -extern DEVICE map_dev; -extern DEVICE fpu_dev; -extern DEVICE pit_dev; -extern int32 Usermap; -extern int32 MapStat; - -#endif - -/* 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 -*/ - -#if defined (ECLIPSE) -char sim_name[] = "ECLIPSE"; -#else -char sim_name[] = "NOVA"; -#endif - -REG *sim_PC = &cpu_reg[0]; - -int32 sim_emax = 4; - -DEVICE *sim_devices[] = { - &cpu_dev, -#if defined (ECLIPSE) - &map_dev, - &fpu_dev, - &pit_dev, -#endif - &ptr_dev, - &ptp_dev, - &tti_dev, - &tto_dev, - &tti1_dev, - &tto1_dev, - &clk_dev, - &plt_dev, - &lpt_dev, - &dsk_dev, - &dkp_dev, - &mta_dev, - &qty_dev, - &alm_dev, - NULL - }; - -const char *sim_stop_messages[] = { - "Unknown error", - "Unknown I/O instruction", - "HALT instruction", - "Breakpoint", - "Nested indirect address limit exceeded", - "Nested indirect interrupt or trap address limit exceeded", - "Read breakpoint", - "Write breakpoint" - }; - -/* Binary loader - - Loader format consists of blocks, optionally preceded, separated, and - followed by zeroes. Each block consists of: - - lo_count - hi_count - lo_origin - hi_origin - lo_checksum - hi_checksum - lo_data byte --- - hi_data byte | - : > -count words - lo_data byte | - hi_data byte --- - - If the word count is [0,-20], then the block is normal data. - If the word count is [-21,-n], then the block is repeated data. - If the word count is 1, the block is the start address. - If the word count is >1, the block is an error block. - -Notes: - 'start' block terminates loading. - 'start' block starting address 1B0 = do not auto-start, 0B0 = auto-start. - 'start' block starting address is saved in 'save_PC' so a "continue" - should start the program. - - specify -i switch ignores checksum errors - - -internal state machine: - - 0,1 get byte count (low and high), ignore leader bytes (<000>) - 2,3 get origin - 4,5 get checksum - 6,7 process data block - 8 process 'ignore' (error) block -*/ - -t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) -{ -int32 data, csum, count, state, i; -int32 origin; -int pos; -int block_start; -int done; - -if ((*cptr != 0) || (flag != 0)) - return ( SCPE_ARG ) ; -state = 0; -block_start = -1 ; -done = 0 ; -for ( pos = 0 ; (! done) && ((i=getc(fileref)) != EOF) ; ++pos ) - { - i &= 0x00FF ; /* (insure no sign extension) */ - switch (state) { - case 0: /* leader */ - count = i; - state = (count != 0); - if ( state ) - block_start = pos ; - break; - case 1: /* high count */ - csum = count = (i << 8) | count ; - state = 2; - break; - case 2: /* low origin */ - origin = i; - state = 3; - break; - case 3: /* high origin */ - origin = (i << 8) | origin; - csum = csum + origin; - state = 4; - break; - case 4: /* low checksum */ - csum = csum + i; - state = 5; - break; - case 5: /* high checksum */ - csum = (csum + (i << 8)) & 0xFFFF; - if (count == 1) - { - /* 'start' block */ - /* do any auto-start check or inhibit check */ - saved_PC = (origin & 077777) ; /* 0B0 = auto-start program */ - /* 1B0 = do not auto start */ - state = 0 ; /* indicate okay state */ - done = 1 ; /* we're done! */ - if ( ! (origin & 0x8000) ) - { - sim_printf( "auto start @ %05o \n", (origin & 0x7FFF) ) ; - } - break; - } - if ( ((count & 0x8000) == 0) && (count > 1)) - { - /* 'ignore' block */ - state = 8; - break; - } - - /* 'data' or 'repeat' block */ - count = 0200000 - count ; - if ( count <= 020 ) - { - /* 'data' block */ - state = 6; - break; - } - /* 'repeat' block (multiple data) */ - - if (count > 020) { /* large block */ - for (count = count - 1; count > 1; count--) { - if (origin >= AMASK /* MEMSIZE? */) - { - return ( SCPE_NXM ); - } - M[origin] = data; - origin = origin + 1; - } - state = 0 ; - } - state = 0; - break; - case 6: /* low data */ - data = i; - state = 7; - break; - case 7: /* high data */ - data = (i << 8) | data; - csum = (csum + data) & 0xFFFF; - - if (origin >= AMASK) - return SCPE_NXM; - M[origin] = data; - origin = origin + 1; - count = count - 1; - if (count == 0) { - if ( csum ) - { - sim_printf( "checksum error: block start at %d [0x%x] \n", block_start, block_start ) ; - sim_printf( "calculated: 0%o [0x%4x]\n", csum, csum ) ; - if ( ! (sim_switches & SWMASK('I')) ) - return SCPE_CSUM; - } - state = 0; - break; - } - state = 6; - break; - case 8: /* error (ignore) block */ - if (i == 0377) /* (wait for 'RUBOUT' char) */ - state = 0; - break; - } /* end switch */ - } /* end while */ - -/* Ok to find end of tape between blocks or in error state */ - -return ( ((state == 0) || (state == 8)) ? SCPE_OK : SCPE_FMT ) ; -} - - -/* Symbol tables */ - -#define I_V_FL 18 /* flag bits */ -#define I_M_FL 037 /* flag width */ -#define I_V_NPN 000 /* no operands */ -#define I_V_R 001 /* reg */ -#define I_V_D 002 /* device */ -#define I_V_RD 003 /* reg,device */ -#define I_V_M 004 /* mem addr */ -#define I_V_RM 005 /* reg,mem addr */ -#define I_V_RR 006 /* operate */ -#define I_V_BY 007 /* Nova byte pointer */ -#define I_V_2AC 010 /* reg,reg */ -#define I_V_RSI 011 /* reg,short imm */ -#define I_V_LI 012 /* long imm */ -#define I_V_RLI 013 /* reg,long imm */ -#define I_V_LM 014 /* long mem addr */ -#define I_V_RLM 015 /* reg,long mem addr */ -#define I_V_FRM 016 /* flt reg,long mem addr */ -#define I_V_FST 017 /* flt long mem, status */ -#define I_V_XP 020 /* XOP */ -#define I_NPN (I_V_NPN << I_V_FL) -#define I_R (I_V_R << I_V_FL) -#define I_D (I_V_D << I_V_FL) -#define I_RD (I_V_RD << I_V_FL) -#define I_M (I_V_M << I_V_FL) -#define I_RM (I_V_RM << I_V_FL) -#define I_RR (I_V_RR << I_V_FL) -#define I_BY (I_V_BY << I_V_FL) -#define I_2AC (I_V_2AC << I_V_FL) -#define I_RSI (I_V_RSI << I_V_FL) -#define I_LI (I_V_LI << I_V_FL) -#define I_RLI (I_V_RLI << I_V_FL) -#define I_LM (I_V_LM << I_V_FL) -#define I_RLM (I_V_RLM << I_V_FL) -#define I_FRM (I_V_FRM << I_V_FL) -#define I_FST (I_V_FST << I_V_FL) -#define I_XP (I_V_XP << I_V_FL) - -static const int32 masks[] = { - 0177777, 0163777, 0177700, 0163700, - 0174000, 0160000, 0103770, 0163477, - 0103777, 0103777, 0177777, 0163777, - 0176377, 0162377, 0103777, 0163777, - 0100077 - }; - -static const char *opcode[] = { - "JMP", "JSR", "ISZ", "DSZ", - "LDA", "STA", -#if defined (ECLIPSE) - "ADI", "SBI", "DAD", "DSB", - "IOR", "XOR", "ANC", "XCH", - "SGT", "SGE", "LSH", "DLSH", - "HXL", "HXR", "DHXL", "DHXR", - "BTO", "BTZ", "SBZ", "SZBO", - "LOB", "LRB", "COB", "LDB", - "STB", "PSH", "POP", - "LMP", "SYC", - "PSHR", "POPB", "BAM", "POPJ", - "RTN", "BLM", "DIVX", - "MUL", "MULS", "DIV", "DIVS", - "SAVE", "RSTR", - "XOP", - "FAS", "FAD", "FSS", "FSD", - "FMS", "FMD", "FDS", "FDD", - "FAMS", "FAMD", "FSMS", "FSMD", - "FMMS", "FMMD", "FDMS", "FDMD", - "FLDS", "FLDD", "FSTS", "FSTD", - "FLAS", "FLMD", "FFAS", "FFMD", - "FNOM", "FRH", "FAB", "FNEG", - "FSCAL", "FEXP", "FINT", "FHLV", - "FNS", "FSA", "FSEQ", "FSNE", - "FSLT", "FSGE", "FSLE", "FSGT", - "FSNM", "FSND", "FSNU", "FSNUD", - "FSNO", "FSNOD", "FSNUO", "FSNER", - "FSST", "FLST", - "FTE", "FTD", "FCLE", - "FPSH", "FPOP", - "FCMP", "FMOV", - "CMV", "CMP", "CTR", "CMT", - "EJMP", "EJSR", "EISZ", "EDSZ", - "ELDA", "ESTA", "ELEF", - "ELDB", "ESTB", "DSPA", - "PSHJ", "CLM", "SNB", - "MSP", "XCT", "HLV", - "IORI", "XORI", "ANDI", "ADDI", -#endif - "COM", "COMZ", "COMO", "COMC", - "COML", "COMZL", "COMOL", "COMCL", - "COMR", "COMZR", "COMOR", "COMCR", - "COMS", "COMZS", "COMOS", "COMCS", - "COM#", "COMZ#", "COMO#", "COMC#", - "COML#", "COMZL#", "COMOL#", "COMCL#", - "COMR#", "COMZR#", "COMOR#", "COMCR#", - "COMS#", "COMZS#", "COMOS#", "COMCS#", - "NEG", "NEGZ", "NEGO", "NEGC", - "NEGL", "NEGZL", "NEGOL", "NEGCL", - "NEGR", "NEGZR", "NEGOR", "NEGCR", - "NEGS", "NEGZS", "NEGOS", "NEGCS", - "NEG#", "NEGZ#", "NEGO#", "NEGC#", - "NEGL#", "NEGZL#", "NEGOL#", "NEGCL#", - "NEGR#", "NEGZR#", "NEGOR#", "NEGCR#", - "NEGS#", "NEGZS#", "NEGOS#", "NEGCS#", - "MOV", "MOVZ", "MOVO", "MOVC", - "MOVL", "MOVZL", "MOVOL", "MOVCL", - "MOVR", "MOVZR", "MOVOR", "MOVCR", - "MOVS", "MOVZS", "MOVOS", "MOVCS", - "MOV#", "MOVZ#", "MOVO#", "MOVC#", - "MOVL#", "MOVZL#", "MOVOL#", "MOVCL#", - "MOVR#", "MOVZR#", "MOVOR#", "MOVCR#", - "MOVS#", "MOVZS#", "MOVOS#", "MOVCS#", - "INC", "INCZ", "INCO", "INCC", - "INCL", "INCZL", "INCOL", "INCCL", - "INCR", "INCZR", "INCOR", "INCCR", - "INCS", "INCZS", "INCOS", "INCCS", - "INC#", "INCZ#", "INCO#", "INCC#", - "INCL#", "INCZL#", "INCOL#", "INCCL#", - "INCR#", "INCZR#", "INCOR#", "INCCR#", - "INCS#", "INCZS#", "INCOS#", "INCCS#", - "ADC", "ADCZ", "ADCO", "ADCC", - "ADCL", "ADCZL", "ADCOL", "ADCCL", - "ADCR", "ADCZR", "ADCOR", "ADCCR", - "ADCS", "ADCZS", "ADCOS", "ADCCS", - "ADC#", "ADCZ#", "ADCO#", "ADCC#", - "ADCL#", "ADCZL#", "ADCOL#", "ADCCL#", - "ADCR#", "ADCZR#", "ADCOR#", "ADCCR#", - "ADCS#", "ADCZS#", "ADCOS#", "ADCCS#", - "SUB", "SUBZ", "SUBO", "SUBC", - "SUBL", "SUBZL", "SUBOL", "SUBCL", - "SUBR", "SUBZR", "SUBOR", "SUBCR", - "SUBS", "SUBZS", "SUBOS", "SUBCS", - "SUB#", "SUBZ#", "SUBO#", "SUBC#", - "SUBL#", "SUBZL#", "SUBOL#", "SUBCL#", - "SUBR#", "SUBZR#", "SUBOR#", "SUBCR#", - "SUBS#", "SUBZS#", "SUBOS#", "SUBCS#", - "ADD", "ADDZ", "ADDO", "ADDC", - "ADDL", "ADDZL", "ADDOL", "ADDCL", - "ADDR", "ADDZR", "ADDOR", "ADDCR", - "ADDS", "ADDZS", "ADDOS", "ADDCS", - "ADD#", "ADDZ#", "ADDO#", "ADDC#", - "ADDL#", "ADDZL#", "ADDOL#", "ADDCL#", - "ADDR#", "ADDZR#", "ADDOR#", "ADDCR#", - "ADDS#", "ADDZS#", "ADDOS#", "ADDCS#", - "AND", "ANDZ", "ANDO", "ANDC", - "ANDL", "ANDZL", "ANDOL", "ANDCL", - "ANDR", "ANDZR", "ANDOR", "ANDCR", - "ANDS", "ANDZS", "ANDOS", "ANDCS", - "AND#", "ANDZ#", "ANDO#", "ANDC#", - "ANDL#", "ANDZL#", "ANDOL#", "ANDCL#", - "ANDR#", "ANDZR#", "ANDOR#", "ANDCR#", - "ANDS#", "ANDZS#", "ANDOS#", "ANDCS#", - "INTEN", "INTDS", - "READS", "INTA", "MSKO", "IORST", "HALT", -#if !defined (ECLIPSE) - "MUL", "DIV", "MULS", "DIVS", - "PSHA", "POPA", "SAV", "RET", - "MTSP", "MTFP", "MFSP", "MFFP", - "LDB", "STB", -#endif - "NIO", "NIOS", "NIOC", "NIOP", - "DIA", "DIAS", "DIAC", "DIAP", - "DOA", "DOAS", "DOAC", "DOAP", - "DIB", "DIBS", "DIBC", "DIBP", - "DOB", "DOBS", "DOBC", "DOBP", - "DIC", "DICS", "DICC", "DICP", - "DOC", "DOCS", "DOCC", "DOCP", - "SKPBN", "SKPBZ", "SKPDN", "SKPDZ", -#if defined (ECLIPSE) - "LEF", "LEF", "LEF", "LEF", -#endif - NULL - }; - -static const int32 opc_val[] = { - 0000000+I_M, 0004000+I_M, 0010000+I_M, 0014000+I_M, - 0020000+I_RM, 0040000+I_RM, -#if defined (ECLIPSE) - 0100010+I_RSI, 0100110+I_RSI, 0100210+I_2AC, 0100310+I_2AC, - 0100410+I_2AC, 0100510+I_2AC, 0100610+I_2AC, 0100710+I_2AC, - 0101010+I_2AC, 0101110+I_2AC, 0101210+I_RSI, 0101310+I_RSI, - 0101410+I_RSI, 0101510+I_RSI, 0101610+I_RSI, 0101710+I_RSI, - 0102010+I_2AC, 0102110+I_2AC, 0102210+I_2AC, 0102310+I_2AC, - 0102410+I_2AC, 0102510+I_2AC, 0102610+I_2AC, 0102710+I_2AC, - 0103010+I_2AC, 0103110+I_2AC, 0103210+I_2AC, - 0113410+I_NPN, 0103510+I_2AC, - 0103710+I_NPN, 0107710+I_NPN, 0113710+I_NPN, 0117710+I_NPN, - 0127710+I_NPN, 0133710+I_NPN, 0137710+I_NPN, - 0143710+I_NPN, 0147710+I_NPN, 0153710+I_NPN, 0157710+I_NPN, - 0163710+I_LI, 0167710+I_NPN, - 0100030+I_XP, - 0100050+I_2AC, 0100150+I_2AC, 0100250+I_2AC, 0100350+I_2AC, - 0100450+I_2AC, 0100550+I_2AC, 0100650+I_2AC, 0100750+I_2AC, - 0101050+I_FRM, 0101150+I_FRM, 0101250+I_FRM, 0101350+I_FRM, - 0101450+I_FRM, 0101550+I_FRM, 0101650+I_FRM, 0101750+I_FRM, - 0102050+I_FRM, 0102150+I_FRM, 0102250+I_FRM, 0102350+I_FRM, - 0102450+I_2AC, 0102550+I_FRM, 0102650+I_2AC, 0102750+I_FRM, - 0103050+I_R, 0123050+I_R, 0143050+I_R, 0163050+I_R, - 0103150+I_R, 0123150+I_R, 0143150+I_R, 0163150+I_R, - 0103250+I_NPN, 0107250+I_NPN, 0113250+I_NPN, 0117250+I_NPN, - 0123250+I_NPN, 0127250+I_NPN, 0133250+I_NPN, 0137250+I_NPN, - 0143250+I_NPN, 0147250+I_NPN, 0153250+I_NPN, 0157250+I_NPN, - 0163250+I_NPN, 0167250+I_NPN, 0173250+I_NPN, 0177250+I_NPN, - 0103350+I_FST, 0123350+I_FST, - 0143350+I_NPN, 0147350+I_NPN, 0153350+I_NPN, - 0163350+I_NPN, 0167350+I_NPN, - 0103450+I_2AC, 0103550+I_2AC, - 0153650+I_NPN, 0157650+I_NPN, 0163650+I_NPN, 0167650+I_NPN, - 0102070+I_LM, 0106070+I_LM, 0112070+I_LM, 0116070+I_LM, - 0122070+I_RLM, 0142070+I_RLM, 0162070+I_RLM, - 0102170+I_RLM, 0122170+I_RLM, 0142170+I_RLM, - 0102270+I_LM, 0102370+I_2AC, 0102770+I_2AC, - 0103370+I_R, 0123370+I_R, 0143370+I_R, - 0103770+I_RLI, 0123770+I_RLI, 0143770+I_RLI, 0163770+I_RLI, -#endif - 0100000+I_RR, 0100020+I_RR, 0100040+I_RR, 0100060+I_RR, - 0100100+I_RR, 0100120+I_RR, 0100140+I_RR, 0100160+I_RR, - 0100200+I_RR, 0100220+I_RR, 0100240+I_RR, 0100260+I_RR, - 0100300+I_RR, 0100320+I_RR, 0100340+I_RR, 0100360+I_RR, - 0100010+I_RR, 0100030+I_RR, 0100050+I_RR, 0100070+I_RR, - 0100110+I_RR, 0100130+I_RR, 0100150+I_RR, 0100170+I_RR, - 0100210+I_RR, 0100230+I_RR, 0100250+I_RR, 0100270+I_RR, - 0100310+I_RR, 0100330+I_RR, 0100350+I_RR, 0100370+I_RR, - 0100400+I_RR, 0100420+I_RR, 0100440+I_RR, 0100460+I_RR, - 0100500+I_RR, 0100520+I_RR, 0100540+I_RR, 0100560+I_RR, - 0100600+I_RR, 0100620+I_RR, 0100640+I_RR, 0100660+I_RR, - 0100700+I_RR, 0100720+I_RR, 0100740+I_RR, 0100760+I_RR, - 0100410+I_RR, 0100430+I_RR, 0100450+I_RR, 0100470+I_RR, - 0100510+I_RR, 0100530+I_RR, 0100550+I_RR, 0100570+I_RR, - 0100610+I_RR, 0100630+I_RR, 0100650+I_RR, 0100670+I_RR, - 0100710+I_RR, 0100730+I_RR, 0100750+I_RR, 0100770+I_RR, - 0101000+I_RR, 0101020+I_RR, 0101040+I_RR, 0101060+I_RR, - 0101100+I_RR, 0101120+I_RR, 0101140+I_RR, 0101160+I_RR, - 0101200+I_RR, 0101220+I_RR, 0101240+I_RR, 0101260+I_RR, - 0101300+I_RR, 0101320+I_RR, 0101340+I_RR, 0101360+I_RR, - 0101010+I_RR, 0101030+I_RR, 0101050+I_RR, 0101070+I_RR, - 0101110+I_RR, 0101130+I_RR, 0101150+I_RR, 0101170+I_RR, - 0101210+I_RR, 0101230+I_RR, 0101250+I_RR, 0101270+I_RR, - 0101310+I_RR, 0101330+I_RR, 0101350+I_RR, 0101370+I_RR, - 0101400+I_RR, 0101420+I_RR, 0101440+I_RR, 0101460+I_RR, - 0101500+I_RR, 0101520+I_RR, 0101540+I_RR, 0101560+I_RR, - 0101600+I_RR, 0101620+I_RR, 0101640+I_RR, 0101660+I_RR, - 0101700+I_RR, 0101720+I_RR, 0101740+I_RR, 0101760+I_RR, - 0101410+I_RR, 0101430+I_RR, 0101450+I_RR, 0101470+I_RR, - 0101510+I_RR, 0101530+I_RR, 0101550+I_RR, 0101570+I_RR, - 0101610+I_RR, 0101630+I_RR, 0101650+I_RR, 0101670+I_RR, - 0101710+I_RR, 0101730+I_RR, 0101750+I_RR, 0101770+I_RR, - 0102000+I_RR, 0102020+I_RR, 0102040+I_RR, 0102060+I_RR, - 0102100+I_RR, 0102120+I_RR, 0102140+I_RR, 0102160+I_RR, - 0102200+I_RR, 0102220+I_RR, 0102240+I_RR, 0102260+I_RR, - 0102300+I_RR, 0102320+I_RR, 0102340+I_RR, 0102360+I_RR, - 0102010+I_RR, 0102030+I_RR, 0102050+I_RR, 0102070+I_RR, - 0102110+I_RR, 0102130+I_RR, 0102150+I_RR, 0102170+I_RR, - 0102210+I_RR, 0102230+I_RR, 0102250+I_RR, 0102270+I_RR, - 0102310+I_RR, 0102330+I_RR, 0102350+I_RR, 0102370+I_RR, - 0102400+I_RR, 0102420+I_RR, 0102440+I_RR, 0102460+I_RR, - 0102500+I_RR, 0102520+I_RR, 0102540+I_RR, 0102560+I_RR, - 0102600+I_RR, 0102620+I_RR, 0102640+I_RR, 0102660+I_RR, - 0102700+I_RR, 0102720+I_RR, 0102740+I_RR, 0102760+I_RR, - 0102410+I_RR, 0102430+I_RR, 0102450+I_RR, 0102470+I_RR, - 0102510+I_RR, 0102530+I_RR, 0102550+I_RR, 0102570+I_RR, - 0102610+I_RR, 0102630+I_RR, 0102650+I_RR, 0102670+I_RR, - 0102710+I_RR, 0102730+I_RR, 0102750+I_RR, 0102770+I_RR, - 0103000+I_RR, 0103020+I_RR, 0103040+I_RR, 0103060+I_RR, - 0103100+I_RR, 0103120+I_RR, 0103140+I_RR, 0103160+I_RR, - 0103200+I_RR, 0103220+I_RR, 0103240+I_RR, 0103260+I_RR, - 0103300+I_RR, 0103320+I_RR, 0103340+I_RR, 0103360+I_RR, - 0103010+I_RR, 0103030+I_RR, 0103050+I_RR, 0103070+I_RR, - 0103110+I_RR, 0103130+I_RR, 0103150+I_RR, 0103170+I_RR, - 0103210+I_RR, 0103230+I_RR, 0103250+I_RR, 0103270+I_RR, - 0103310+I_RR, 0103330+I_RR, 0103350+I_RR, 0103370+I_RR, - 0103400+I_RR, 0103420+I_RR, 0103440+I_RR, 0103460+I_RR, - 0103500+I_RR, 0103520+I_RR, 0103540+I_RR, 0103560+I_RR, - 0103600+I_RR, 0103620+I_RR, 0103640+I_RR, 0103660+I_RR, - 0103700+I_RR, 0103720+I_RR, 0103740+I_RR, 0103760+I_RR, - 0103410+I_RR, 0103430+I_RR, 0103450+I_RR, 0103470+I_RR, - 0103510+I_RR, 0103530+I_RR, 0103550+I_RR, 0103570+I_RR, - 0103610+I_RR, 0103630+I_RR, 0103650+I_RR, 0103670+I_RR, - 0103710+I_RR, 0103730+I_RR, 0103750+I_RR, 0103770+I_RR, - 0060177+I_NPN, 0060277+I_NPN, - 0060477+I_R, 0061477+I_R, 0062077+I_R, 0062677+I_NPN, 0063077+I_NPN, -#if !defined (ECLIPSE) - 0073301+I_NPN, 0073101+I_NPN, 0077201+I_NPN, 0077001+I_NPN, - 0061401+I_R, 0061601+I_R, 0062401+I_NPN, 0062601+I_NPN, - 0061001+I_R, 0060001+I_R, 0061201+I_R, 0060201+I_R, - 0060401+I_BY, 0062001+I_BY, -#endif - 0060000+I_RD, 0060100+I_RD, 0060200+I_RD, 0060300+I_RD, - 0060400+I_RD, 0060500+I_RD, 0060600+I_RD, 0060700+I_RD, - 0061000+I_RD, 0061100+I_RD, 0061200+I_RD, 0061300+I_RD, - 0061400+I_RD, 0061500+I_RD, 0061600+I_RD, 0061700+I_RD, - 0062000+I_RD, 0062100+I_RD, 0062200+I_RD, 0062300+I_RD, - 0062400+I_RD, 0062500+I_RD, 0062600+I_RD, 0062700+I_RD, - 0063000+I_RD, 0063100+I_RD, 0063200+I_RD, 0063300+I_RD, - 0063400+I_D, 0063500+I_D, 0063600+I_D, 0063700+I_D, -#if defined (ECLIPSE) - 0064000+I_D, 0070000+I_D, 0074000+I_D, 0076000+I_D, -#endif - -1 - }; - -static const char *skip[] = { - "SKP", "SZC", "SNC", "SZR", "SNR", "SEZ", "SBN", - NULL - }; - -static const char *device[] = { -#if defined (ECLIPSE) - "ERCC", "MAP", -#endif - "TTI", "TTO", "PTR", "PTP", "RTC", "PLT", "CDR", "LPT", - "DSK", "MTA", "DCM", "QTY" /* "ADCV" */, "DKP", "CAS", - "TTI1", "TTO1", "CPU", - NULL - }; - -static const int32 dev_val[] = { -#if defined (ECLIPSE) - 002, 003, -#endif - 010, 011, 012, 013, 014, 015, 016, 017, - 020, 022, 024, 030, 033, 034, - 050, 051, 077, - -1 - }; - -/* Address decode - - Inputs: - *of = output stream - addr = current PC - ind = indirect flag - mode = addressing mode - disp = displacement - ext = true if extended address - cflag = true if decoding for CPU - Outputs: - return = error code -*/ - -t_stat fprint_addr (FILE *of, t_addr addr, int32 ind, int32 mode, - int32 disp, t_bool ext, int32 cflag) -{ -int32 dsign, dmax; - -if (ext) /* get max disp */ - dmax = AMASK + 1; -else dmax = I_M_DISP + 1; -dsign = dmax >> 1; /* get disp sign */ -if (ind) /* indirect? */ - fprintf (of, "@"); -switch (mode & 03) { /* mode */ - - case 0: /* absolute */ - fprintf (of, "%-o", disp); - break; - - case 1: /* PC rel */ - if (disp & dsign) { - if (cflag) - fprintf (of, "%-o", (addr - (dmax - disp)) & AMASK); - else fprintf (of, ".-%-o", dmax - disp); - } - else { - if (cflag) - fprintf (of, "%-o", (addr + disp) & AMASK); - else fprintf (of, ".+%-o", disp); - } - break; - - case 2: /* AC2 rel */ - if (disp & dsign) - fprintf (of, "-%-o,2", dmax - disp); - else fprintf (of, "%-o,2", disp); - break; - - case 3: /* AC3 rel */ - if (disp & dsign) - fprintf (of, "-%-o,3", dmax - disp); - else fprintf (of, "%-o,3", disp); - break; - } /* end switch */ - -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 -*/ - -t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, - UNIT *uptr, int32 sw) -{ -int32 cflag, i, j, c1, c2, inst, inst1, dv, src, dst, skp; -int32 ind, mode, disp, dev; -int32 byac, extind, extdisp, xop; - -cflag = (uptr == NULL) || (uptr == &cpu_unit); -c1 = ((int32) val[0] >> 8) & 0177; -c2 = (int32) val[0] & 0177; -if (sw & SWMASK ('A')) { /* ASCII? */ - fprintf (of, (c2 < 040)? "<%03o>": "%c", c2); - return SCPE_OK; - } -if (sw & SWMASK ('C')) { /* character? */ - fprintf (of, (c1 < 040)? "<%03o>": "%c", c1); - fprintf (of, (c2 < 040)? "<%03o>": "%c", c2); - return SCPE_OK; - } -if (!(sw & SWMASK ('M'))) /* mnemonic? */ - return SCPE_ARG; - -/* Instruction decode */ - -inst = (int32) val[0]; -inst1 = (int32) val[1]; -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] & 0177777) == (inst & masks[j])) { /* match? */ - src = I_GETSRC (inst); /* opr fields */ - dst = I_GETDST (inst); - skp = I_GETSKP (inst); - ind = inst & I_IND; /* mem ref fields */ - mode = I_GETMODE (inst); - disp = I_GETDISP (inst); - dev = I_GETDEV (inst); /* IOT fields */ - byac = I_GETPULSE (inst); /* byte fields */ - xop = I_GETXOP (inst); /* XOP fields */ - extind = inst1 & A_IND; /* extended fields */ - extdisp = inst1 & AMASK; - for (dv = 0; (dev_val[dv] >= 0) && (dev_val[dv] != dev); dv++) ; - - switch (j) { /* switch on class */ - - case I_V_NPN: /* no operands */ - fprintf (of, "%s", opcode[i]); /* opcode */ - break; - - case I_V_R: /* reg only */ - fprintf (of, "%s %-o", opcode[i], dst); - break; - - case I_V_D: /* dev only */ -#if defined (ECLIPSE) - if (Usermap && (MapStat & 0100)) { /* the evil LEF mode */ - fprintf (of, "LEF %-o,", dst); - fprint_addr (of, addr, ind, mode, disp, FALSE, cflag); - break; - } -#endif - if (dev_val[dv] >= 0) - fprintf (of, "%s %s", opcode[i], device[dv]); - else fprintf (of, "%s %-o", opcode[i], dev); - break; - - case I_V_RD: /* reg, dev */ - if (dev_val[dv] >= 0) - fprintf (of, "%s %-o,%s", opcode[i], dst, device[dv]); - else fprintf (of, "%s %-o,%-o", opcode[i], dst, dev); - break; - - case I_V_M: /* addr only */ - fprintf (of, "%s ", opcode[i]); - fprint_addr (of, addr, ind, mode, disp, FALSE, cflag); - break; - - case I_V_RM: /* reg, addr */ - fprintf (of, "%s %-o,", opcode[i], dst); - fprint_addr (of, addr, ind, mode, disp, FALSE, cflag); - break; - - case I_V_RR: /* operate */ - fprintf (of, "%s %-o,%-o", opcode[i], src, dst); - if (skp) - fprintf (of, ",%s", skip[skp-1]); - break; - - case I_V_BY: /* byte */ - fprintf (of, "%s %-o,%-o", opcode[i], byac, dst); - break; - - case I_V_2AC: /* reg, reg */ - fprintf (of, "%s %-o,%-o", opcode[i], src, dst); - break; - - case I_V_RSI: /* reg, short imm */ - fprintf (of, "%s %-o,%-o", opcode[i], src + 1, dst); - break; - - case I_V_LI: /* long imm */ - fprintf (of, "%s %-o", opcode[i], inst1); - return -1; - - case I_V_RLI: /* reg, long imm */ - fprintf (of, "%s %-o,%-o", opcode[i], inst1, dst); - return -1; - - case I_V_LM: /* long addr */ - fprintf (of, "%s ", opcode[i]); - fprint_addr (of, addr, extind, mode, extdisp, TRUE, cflag); - return -1; - - case I_V_RLM: /* reg, long addr */ - fprintf (of, "%s %-o,", opcode[i], dst); - fprint_addr (of, addr, extind, mode, extdisp, TRUE, cflag); - return -1; - - case I_V_FRM: /* flt reg, long addr */ - fprintf (of, "%s %-o,", opcode[i], dst); - fprint_addr (of, addr, extind, src, extdisp, TRUE, cflag); - return -1; - - case I_V_FST: /* flt status */ - fprintf (of, "%s ", opcode[i]); - fprint_addr (of, addr, extind, dst, extdisp, AMASK + 1, cflag); - return -1; - - case I_V_XP: /* XOP */ - fprintf (of, "%s %-o,%-o,%-o", opcode[i], src, dst, xop); - break; /* end case */ - - default: - fprintf (of, "??? [%-o]", inst); - break; - } - return SCPE_OK; - } /* end if */ - } /* end for */ -return SCPE_ARG; -} - -/* Address parse - - Inputs: - *cptr = pointer to input string - addr = current PC - ext = extended address - cflag = true if parsing for CPU - val[3] = output array - Outputs: - optr = pointer to next char in input string - NULL if error -*/ - -#define A_FL 001 /* CPU flag */ -#define A_NX 002 /* index seen */ -#define A_PER 004 /* period seen */ -#define A_NUM 010 /* number seen */ -#define A_SI 020 /* sign seen */ -#define A_MI 040 /* - seen */ - -char *get_addr (char *cptr, t_addr addr, t_bool ext, int32 cflag, int32 *val) -{ -int32 d, x, pflag; -t_stat r; -char gbuf[CBUFSIZE]; -int32 dmax, dsign; - -if (ext) /* get max disp */ - dmax = AMASK + 1; -else dmax = I_M_DISP + 1; -dsign = dmax >> 1; /* get disp sign */ -val[0] = 0; /* no indirect */ -val[1] = 0; /* PC rel */ -val[2] = 0; /* no addr */ - -pflag = cflag & A_FL; /* isolate flag */ -if (*cptr == '@') { /* indirect? */ - val[0] = 1; - cptr++; - } -if (*cptr == '.') { /* relative? */ - pflag = pflag | A_PER; - x = 1; /* "index" is PC */ - d = 0; /* default disp is 0 */ - cptr++; - } -if (*cptr == '+') { /* + sign? */ - pflag = pflag | A_SI; - cptr++; - } -else if (*cptr == '-') { /* - sign? */ - pflag = pflag | A_MI | A_SI; - cptr++; - } -if (*cptr != 0) { /* number? */ - cptr = get_glyph (cptr, gbuf, ','); /* get glyph */ - d = (int32) get_uint (gbuf, 8, AMASK, &r); - if (r != SCPE_OK) - return NULL; - pflag = pflag | A_NUM; - } -if (*cptr != 0) { /* index? */ - cptr = get_glyph (cptr, gbuf, 0); /* get glyph */ - x = (int32) get_uint (gbuf, 8, I_M_DST, &r); - if ((r != SCPE_OK) || (x < 2)) - return NULL; - pflag = pflag | A_NX; - } - -switch (pflag) { /* case on flags */ - - case A_NUM: case A_NUM+A_SI: /* ~CPU, (+)num */ - if (d < dmax) - val[2] = d; - else return NULL; - break; - - case A_NUM+A_FL: case A_NUM+A_SI+A_FL: /* CPU, (+)num */ - if (d < dmax) - val[2] = d; - else if (((d >= (((int32) addr - dsign) & AMASK)) && - (d < (((int32) addr + dsign) & AMASK))) || - (d >= ((int32) addr + (-dsign & AMASK)))) { - val[1] = 1; /* PC rel */ - val[2] = (d - addr) & (dmax - 1); - } - else return NULL; - break; - - case A_PER: case A_PER+A_FL: /* . */ - case A_PER+A_SI+A_NUM: case A_PER+A_SI+A_NUM+A_FL: /* . + num */ - case A_PER+A_SI+A_MI+A_NUM: /* . - num */ - case A_PER+A_SI+A_MI+A_NUM+A_FL: - case A_NX+A_NUM: case A_NX+A_NUM+A_FL: /* num, ndx */ - case A_NX+A_SI+A_NUM: case A_NX+A_SI+A_NUM+A_FL: /* +num, ndx */ - case A_NX+A_SI+A_MI+A_NUM: /* -num, ndx */ - case A_NX+A_SI+A_MI+A_NUM+A_FL: - val[1] = x; /* set mode */ - if (((pflag & A_MI) == 0) && (d < dsign)) - val[2] = d; - else if ((pflag & A_MI) && (d <= dsign)) - val[2] = (dmax - d); - else return NULL; - break; - - default: - return NULL; - } /* end case */ - -return cptr; -} - -/* Parse two registers - - Inputs: - *cptr = input string - term = second terminating character - val = output array - Outputs: - optr = pointer to next char in input string - NULL if error -*/ - -char *get_2reg (char *cptr, char term, int32 *val) -{ -char gbuf[CBUFSIZE]; -t_stat r; - -cptr = get_glyph (cptr, gbuf, ','); /* get register */ -val[0] = (int32) get_uint (gbuf, 8, I_M_SRC, &r); -if (r != SCPE_OK) - return NULL; -cptr = get_glyph (cptr, gbuf, term); /* get register */ -val[1] = (int32) get_uint (gbuf, 8, I_M_DST, &r); -if (r != SCPE_OK) - return NULL; -return cptr; -} - -/* 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 -*/ - -t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) -{ -int32 cflag, d, i, j, amd[3]; -t_stat r, rtn; -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) /* must have 1 char */ - return SCPE_ARG; - val[0] = (t_value) cptr[0]; - return SCPE_OK; - } -if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */ - if (cptr[0] == 0) /* must have 1 char */ - return SCPE_ARG; - val[0] = ((t_value) cptr[0] << 8) + (t_value) cptr[1]; - return SCPE_OK; - } - -/* Instruction parse */ - -rtn = SCPE_OK; /* assume 1 word */ -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] & 0177777; /* get value */ -j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */ - -switch (j) { /* case on class */ - - case I_V_NPN: /* no operand */ - break; - - case I_V_R: /* IOT reg */ - cptr = get_glyph (cptr, gbuf, 0); /* get register */ - d = (int32) get_uint (gbuf, 8, I_M_DST, &r); - if (r != SCPE_OK) - return SCPE_ARG; - val[0] = val[0] | (d << I_V_DST); /* put in place */ - break; - - case I_V_RD: /* IOT reg,dev */ - cptr = get_glyph (cptr, gbuf, ','); /* get register */ - d = (int32) get_uint (gbuf, 8, I_M_DST, &r); - if (r != SCPE_OK) - return SCPE_ARG; - val[0] = val[0] | (d << I_V_DST); /* put in place */ - case I_V_D: /* IOT dev */ - cptr = get_glyph (cptr, gbuf, 0); /* get device */ - for (i = 0; (device[i] != NULL) && - (strcmp (device[i], gbuf) != 0); i++); - if (device[i] != NULL) - val[0] = val[0] | dev_val[i]; - else { - d = (int32) get_uint (gbuf, 8, I_M_DEV, &r); - if (r != SCPE_OK) - return SCPE_ARG; - val[0] = val[0] | (d << I_V_DEV); - } - break; - - case I_V_RM: /* reg, addr */ - cptr = get_glyph (cptr, gbuf, ','); /* get register */ - d = (int32) get_uint (gbuf, 8, I_M_DST, &r); - if (r != SCPE_OK) - return SCPE_ARG; - val[0] = val[0] | (d << I_V_DST); /* put in place */ - case I_V_M: /* addr */ - cptr = get_addr (cptr, addr, FALSE, cflag, amd); - if (cptr == NULL) - return SCPE_ARG; - val[0] = val[0] | (amd[0] << I_V_IND) | (amd[1] << I_V_MODE) | amd[2]; - break; - - case I_V_RR: /* operate */ - cptr = get_2reg (cptr, ',', amd); /* get 2 reg */ - if (cptr == NULL) - return SCPE_ARG; - val[0] = val[0] | (amd[0] << I_V_SRC) | (amd[1] << I_V_DST); - if (*cptr != 0) { /* skip? */ - cptr = get_glyph (cptr, gbuf, 0); /* get skip */ - for (i = 0; (skip[i] != NULL) && - (strcmp (skip[i], gbuf) != 0); i++) ; - if (skip[i] == NULL) - return SCPE_ARG; - val[0] = val[0] | (i + 1); - } /* end if */ - break; - - case I_V_BY: /* byte */ - cptr = get_2reg (cptr, 0, amd); /* get 2 reg */ - if (cptr == NULL) - return SCPE_ARG; - val[0] = val[0] | (amd[0] << I_V_PULSE) | (amd[1] << I_V_DST); - break; - - case I_V_2AC: /* reg, reg */ - cptr = get_2reg (cptr, 0, amd); /* get 2 reg */ - if (cptr == NULL) - return SCPE_ARG; - val[0] = val[0] | (amd[0] << I_V_SRC) | (amd[1] << I_V_DST); - break; - - case I_V_RSI: /* reg, short imm */ - cptr = get_glyph (cptr, gbuf, ','); /* get immediate */ - d = (int32) get_uint (gbuf, 8, I_M_SRC + 1, &r); - if ((d == 0) || (r != SCPE_OK)) - return SCPE_ARG; - val[0] = val[0] | ((d - 1) << I_V_SRC); /* put in place */ - cptr = get_glyph (cptr, gbuf, 0); /* get register */ - d = (int32) get_uint (gbuf, 8, I_M_DST, &r); - if (r != SCPE_OK) - return SCPE_ARG; - val[0] = val[0] | (d << I_V_DST); /* put in place */ - break; - - case I_V_RLI: /* reg, long imm */ - cptr = get_glyph (cptr, gbuf, ','); /* get immediate */ - val[1] = (int32) get_uint (gbuf, 8, DMASK, &r); - if (r != SCPE_OK) - return SCPE_ARG; - cptr = get_glyph (cptr, gbuf, 0); /* get register */ - d = (int32) get_uint (gbuf, 8, I_M_DST, &r); - if (r != SCPE_OK) - return SCPE_ARG; - val[0] = val[0] | (d << I_V_DST); /* put in place */ - rtn = -1; - break; - - case I_V_LI: /* long imm */ - cptr = get_glyph (cptr, gbuf, 0); /* get immediate */ - val[1] = (int32) get_uint (gbuf, 8, DMASK, &r); - if (r != SCPE_OK) - return SCPE_ARG; - rtn = -1; - break; - - case I_V_RLM: /* reg, long mem */ - cptr = get_glyph (cptr, gbuf, ','); /* get register */ - d = (int32) get_uint (gbuf, 8, I_M_DST, &r); - if (r != SCPE_OK) - return SCPE_ARG; - val[0] = val[0] | (d << I_V_DST); /* put in place */ - case I_V_LM: /* long mem */ - cptr = get_addr (cptr, addr, TRUE, cflag, amd); - if (cptr == NULL) - return SCPE_ARG; - val[0] = val[0] | (amd[1] << I_V_MODE); - val[1] = (amd[0] << A_V_IND) | amd[2]; - rtn = -1; - break; - - case I_V_FRM: /* flt reg, long mem */ - cptr = get_glyph (cptr, gbuf, ','); /* get register */ - d = (int32) get_uint (gbuf, 8, I_M_DST, &r); - if (r != SCPE_OK) - return SCPE_ARG; - val[0] = val[0] | (d << I_V_DST); /* put in place */ - cptr = get_addr (cptr, addr, TRUE, cflag, amd); - if (cptr == NULL) - return SCPE_ARG; - val[0] = val[0] | (amd[1] << I_V_SRC); - val[1] = (amd[0] << A_V_IND) | amd[2]; - rtn = -1; - break; - - case I_V_FST: /* flt status */ - cptr = get_addr (cptr, addr, TRUE, cflag, amd); - if (cptr == NULL) - return SCPE_ARG; - val[0] = val[0] | (amd[1] << I_V_DST); - val[1] = (amd[0] << A_V_IND) | amd[2]; - rtn = -1; - break; - - case I_V_XP: /* XOP */ - cptr = get_2reg (cptr, ',', amd); /* get 2 reg */ - if (cptr == NULL) - return SCPE_ARG; - val[0] = val[0] | (amd[0] << I_V_SRC) | (amd[1] << I_V_DST); - cptr = get_glyph (cptr, gbuf, 0); /* get argument */ - d = (int32) get_uint (gbuf, 8, I_M_XOP, &r); - if (r != SCPE_OK) - return SCPE_ARG; - val[0] = val[0] | (d << I_V_XOP); - break; - } /* end case */ - -if (*cptr != 0) /* any leftovers? */ - return SCPE_ARG; -return rtn; -} diff --git a/NOVA/nova_tt.c b/NOVA/nova_tt.c deleted file mode 100644 index 29367454..00000000 --- a/NOVA/nova_tt.c +++ /dev/null @@ -1,274 +0,0 @@ -/* nova_tt.c: NOVA console terminal simulator - - Copyright (c) 1993-2015, 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. - - tti terminal input - tto terminal output - - 31-Mar-15 RMS Backported parity capability from GitHub master - 04-Jul-07 BKR fixed Dasher CR/LF swap function in 'tti_svc()', - DEV_SET/CLR macros now used, - TTO device may now be DISABLED - 29-Dec-03 RMS Added console backpressure support - 25-Apr-03 RMS Revised for extended file support - 05-Jan-02 RMS Fixed calling sequence for setmod - 03-Oct-02 RMS Added DIBs - 30-May-02 RMS Widened POS to 32b - 30-Nov-01 RMS Added extended SET/SHOW support - 17-Sep-01 RMS Removed multiconsole support - 07-Sep-01 RMS Moved function prototypes - 31-May-01 RMS Added multiconsole support - - Notes: - - TTO "Dasher" attribute sends '\b' to console instead of '\031' - - TTO may be disabled - - TTI "Dasher" attribute swaps and - - TTI may not be disabled -*/ - -#include "nova_defs.h" - -#define UNIT_V_DASHER (TTUF_V_UF) /* Dasher mode */ -#define UNIT_DASHER (1 << UNIT_V_DASHER) - -extern int32 int_req, dev_busy, dev_done, dev_disable; - -int32 tti (int32 pulse, int32 code, int32 AC); -int32 tto (int32 pulse, int32 code, int32 AC); -t_stat tti_svc (UNIT *uptr); -t_stat tto_svc (UNIT *uptr); -t_stat tti_reset (DEVICE *dptr); -t_stat tto_reset (DEVICE *dptr); -t_stat ttx_setmod (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat ttx_setpar (UNIT *uptr, int32 val, char *cptr, void *desc); - -/* TTI data structures - - tti_dev TTI device descriptor - tti_unit TTI unit descriptor - tti_reg TTI register list - ttx_mod TTI/TTO modifiers list -*/ - -DIB tti_dib = { DEV_TTI, INT_TTI, PI_TTI, &tti }; - -UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT }; - -REG tti_reg[] = { - { ORDATA (BUF, tti_unit.buf, 8) }, - { FLDATA (BUSY, dev_busy, INT_V_TTI) }, - { FLDATA (DONE, dev_done, INT_V_TTI) }, - { FLDATA (DISABLE, dev_disable, INT_V_TTI) }, - { FLDATA (INT, int_req, INT_V_TTI) }, - { DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, - { NULL } - }; - -MTAB ttx_mod[] = { - { UNIT_DASHER, 0, "ANSI", "ANSI", &ttx_setmod }, - { UNIT_DASHER, UNIT_DASHER, "Dasher", "DASHER", &ttx_setmod }, - { TT_PAR, TT_PAR_EVEN, "even parity", "EVEN", &ttx_setpar }, - { TT_PAR, TT_PAR_ODD, "odd parity", "ODD", &ttx_setpar }, - { TT_PAR, TT_PAR_MARK, "mark parity", "MARK", &ttx_setpar }, - { TT_PAR, TT_PAR_SPACE, "no parity", "NONE", &ttx_setpar }, - { 0 } - } ; - -DEVICE tti_dev = { - "TTI", &tti_unit, tti_reg, ttx_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &tti_reset, - NULL, NULL, NULL, - &tti_dib, 0 - }; - -/* TTO data structures - - tto_dev TTO device descriptor - tto_unit TTO unit descriptor - tto_reg TTO register list -*/ - -DIB tto_dib = { DEV_TTO, INT_TTO, PI_TTO, &tto }; - -UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT }; - -REG tto_reg[] = { - { ORDATA (BUF, tto_unit.buf, 8) }, - { FLDATA (BUSY, dev_busy, INT_V_TTO) }, - { FLDATA (DONE, dev_done, INT_V_TTO) }, - { FLDATA (DISABLE, dev_disable, INT_V_TTO) }, - { FLDATA (INT, int_req, INT_V_TTO) }, - { DRDATA (POS, tto_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT }, - { NULL } - }; - -DEVICE tto_dev = { - "TTO", &tto_unit, tto_reg, ttx_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &tto_reset, - NULL, NULL, NULL, - &tto_dib, DEV_DISABLE - }; - -/* Terminal input: IOT routine */ - -int32 tti (int32 pulse, int32 code, int32 AC) -{ -int32 iodata; - - -if (code == ioDIA) - iodata = tti_unit.buf & 0377; -else iodata = 0; - -switch (pulse) - { /* decode IR<8:9> */ - case iopS: /* start */ - DEV_SET_BUSY( INT_TTI ) ; - DEV_CLR_DONE( INT_TTI ) ; - DEV_UPDATE_INTR ; - break; - - case iopC: /* clear */ - DEV_CLR_BUSY( INT_TTI ) ; - DEV_CLR_DONE( INT_TTI ) ; - DEV_UPDATE_INTR ; - break; - } /* end switch */ - -return iodata; -} - -/* Unit service */ - -t_stat tti_svc (UNIT *uptr) -{ -int32 temp; - -sim_activate (&tti_unit, tti_unit.wait); /* continue poll */ -if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) - return temp; /* no char or error? */ -tti_unit.buf = temp & 0177; -if (tti_unit.flags & UNIT_DASHER) { - if (tti_unit.buf == '\r') - tti_unit.buf = '\n'; /* Dasher: cr -> nl */ - else if (tti_unit.buf == '\n') - tti_unit.buf = '\r' ; /* Dasher: nl -> cr */ - } -tti_unit.buf = sim_tt_inpcvt (tti_unit.buf, TT_GET_MODE (uptr->flags)); -DEV_CLR_BUSY( INT_TTI ) ; -DEV_SET_DONE( INT_TTI ) ; -DEV_UPDATE_INTR ; -++(uptr->pos) ; -return SCPE_OK; -} - -/* Reset routine */ - -t_stat tti_reset (DEVICE *dptr) -{ -tti_unit.buf = 0; /* */ -DEV_CLR_BUSY( INT_TTI ) ; -DEV_CLR_DONE( INT_TTI ) ; -DEV_UPDATE_INTR ; -sim_activate (&tti_unit, tti_unit.wait); /* activate unit */ -return SCPE_OK; -} - -/* Terminal output: IOT routine */ - -int32 tto (int32 pulse, int32 code, int32 AC) -{ -if (code == ioDOA) - tto_unit.buf = AC & 0377; - -switch (pulse) - { /* decode IR<8:9> */ - case iopS: /* start */ - DEV_SET_BUSY( INT_TTO ) ; - DEV_CLR_DONE( INT_TTO ) ; - DEV_UPDATE_INTR ; - sim_activate (&tto_unit, tto_unit.wait); /* activate unit */ - break; - - case iopC: /* clear */ - DEV_CLR_BUSY( INT_TTO ) ; - DEV_CLR_DONE( INT_TTO ) ; - DEV_UPDATE_INTR ; - sim_cancel (&tto_unit); /* deactivate unit */ - break; - } /* end switch */ -return 0; -} - - -/* Unit service */ - -t_stat tto_svc (UNIT *uptr) -{ -int32 c; -t_stat r; - -c = tto_unit.buf & 0177; -if ((tto_unit.flags & UNIT_DASHER) && (c == 031)) - c = '\b'; -if ((r = sim_putchar_s (c)) != SCPE_OK) { /* output; error? */ - sim_activate (uptr, uptr->wait); /* try again */ - return ((r == SCPE_STALL)? SCPE_OK : r); /* !stall? report */ - } -DEV_CLR_BUSY( INT_TTO ) ; -DEV_SET_DONE( INT_TTO ) ; -DEV_UPDATE_INTR ; -++(tto_unit.pos); -return SCPE_OK; -} - -/* Reset routine */ - -t_stat tto_reset (DEVICE *dptr) -{ -tto_unit.buf = 0; /* */ -DEV_CLR_BUSY( INT_TTO ) ; -DEV_CLR_DONE( INT_TTO ) ; -DEV_UPDATE_INTR ; -sim_cancel (&tto_unit); /* deactivate unit */ -return SCPE_OK; -} - -t_stat ttx_setmod (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -tti_unit.flags = (tti_unit.flags & ~UNIT_DASHER) | val; -tto_unit.flags = (tto_unit.flags & ~UNIT_DASHER) | val; -return SCPE_OK; -} - -t_stat ttx_setpar (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -tti_unit.flags = (tti_unit.flags & ~TT_PAR) | val; -tto_unit.flags = (tto_unit.flags & ~TT_PAR) | val; -return SCPE_OK; -} diff --git a/NOVA/nova_tt1.c b/NOVA/nova_tt1.c deleted file mode 100644 index 5cb969b8..00000000 --- a/NOVA/nova_tt1.c +++ /dev/null @@ -1,337 +0,0 @@ -/* nova_tt1.c: NOVA second terminal simulator - - Copyright (c) 1993-2008, Robert M. Supnik - Written by Bruce Ray and used with his gracious permission. - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - tti1 second terminal input - tto1 second terminal output - - 19-Nov-08 RMS Revised for common TMXR show routines - 09-May-03 RMS Added network device flag - 05-Jan-03 RMS Fixed calling sequence for setmod - 03-Oct-02 RMS Added DIBs - 22-Aug-02 RMS Updated for changes in sim_tmxr - 30-May-02 RMS Widened POS to 32b - 06-Jan-02 RMS Revised enable/disable support - 30-Dec-01 RMS Added show statistics, set disconnect - 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 - 26-Apr-01 RMS Added device enable/disable support -*/ - -#include "nova_defs.h" -#include "sim_sock.h" -#include "sim_tmxr.h" - -#define UNIT_V_DASHER (UNIT_V_UF + 0) /* Dasher mode */ -#define UNIT_DASHER (1 << UNIT_V_DASHER) - -extern int32 int_req, dev_busy, dev_done, dev_disable; -extern int32 tmxr_poll; /* calibrated poll */ -TMLN tt1_ldsc = { 0 }; /* line descriptors */ -TMXR tt_desc = { 1, 0, 0, &tt1_ldsc }; /* mux descriptor */ - -DEVICE tti1_dev, tto1_dev; -int32 tti1 (int32 pulse, int32 code, int32 AC); -int32 tto1 (int32 pulse, int32 code, int32 AC); -t_stat tti1_svc (UNIT *uptr); -t_stat tto1_svc (UNIT *uptr); -t_stat tti1_reset (DEVICE *dptr); -t_stat tto1_reset (DEVICE *dptr); -t_stat ttx1_setmod (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat tti1_attach (UNIT *uptr, char *cptr); -t_stat tti1_detach (UNIT *uptr); -void ttx1_enbdis (int32 dis); - -/* TTI1 data structures - - tti1_dev TTI1 device descriptor - tti1_unit TTI1 unit descriptor - tti1_reg TTI1 register list - ttx1_mod TTI1/TTO1 modifiers list -*/ - -DIB tti1_dib = { DEV_TTI1, INT_TTI1, PI_TTI1, &tti1 }; - -UNIT tti1_unit = { UDATA (&tti1_svc, UNIT_ATTABLE, 0), KBD_POLL_WAIT }; - -REG tti1_reg[] = { - { ORDATA (BUF, tti1_unit.buf, 8) }, - { FLDATA (BUSY, dev_busy, INT_V_TTI1) }, - { FLDATA (DONE, dev_done, INT_V_TTI1) }, - { FLDATA (DISABLE, dev_disable, INT_V_TTI1) }, - { FLDATA (INT, int_req, INT_V_TTI1) }, - { DRDATA (POS, tt1_ldsc.rxcnt, 32), PV_LEFT }, - { DRDATA (TIME, tti1_unit.wait, 24), REG_NZ + PV_LEFT }, - { NULL } - }; - -MTAB tti1_mod[] = { - { UNIT_DASHER, 0, "ANSI", "ANSI", &ttx1_setmod }, - { UNIT_DASHER, UNIT_DASHER, "Dasher", "DASHER", &ttx1_setmod }, - { UNIT_ATT, UNIT_ATT, "summary", NULL, - NULL, &tmxr_show_summ, (void *) &tt_desc }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "DISCONNECT", - &tmxr_dscln, NULL, (void *) &tt_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, - NULL, &tmxr_show_cstat, (void *) &tt_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, - NULL, &tmxr_show_cstat, (void *) &tt_desc }, - { 0 } - }; - -DEVICE tti1_dev = { - "TTI1", &tti1_unit, tti1_reg, tti1_mod, - 1, 10, 31, 1, 8, 8, - &tmxr_ex, &tmxr_dep, &tti1_reset, - NULL, &tti1_attach, &tti1_detach, - &tti1_dib, DEV_MUX | DEV_DISABLE - }; - -/* TTO1 data structures - - tto1_dev TTO1 device descriptor - tto1_unit TTO1 unit descriptor - tto1_reg TTO1 register list -*/ - -DIB tto1_dib = { DEV_TTO1, INT_TTO1, PI_TTO1, &tto1 }; - -UNIT tto1_unit = { UDATA (&tto1_svc, 0, 0), SERIAL_OUT_WAIT }; - -REG tto1_reg[] = { - { ORDATA (BUF, tto1_unit.buf, 8) }, - { FLDATA (BUSY, dev_busy, INT_V_TTO1) }, - { FLDATA (DONE, dev_done, INT_V_TTO1) }, - { FLDATA (DISABLE, dev_disable, INT_V_TTO1) }, - { FLDATA (INT, int_req, INT_V_TTO1) }, - { DRDATA (POS, tt1_ldsc.txcnt, 32), PV_LEFT }, - { DRDATA (TIME, tto1_unit.wait, 24), PV_LEFT }, - { NULL } - }; - -MTAB tto1_mod[] = { - { UNIT_DASHER, 0, "ANSI", "ANSI", &ttx1_setmod }, - { UNIT_DASHER, UNIT_DASHER, "Dasher", "DASHER", &ttx1_setmod }, - { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG", - &tmxr_set_log, &tmxr_show_log, &tt_desc }, - { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG", - &tmxr_set_nolog, NULL, &tt_desc }, - { 0 } - }; - -DEVICE tto1_dev = { - "TTO1", &tto1_unit, tto1_reg, tto1_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &tto1_reset, - NULL, NULL, NULL, - &tto1_dib, DEV_DISABLE | DEV_MUX - }; - -/* Terminal input: IOT routine */ - -int32 tti1 (int32 pulse, int32 code, int32 AC) -{ -int32 iodata; - -iodata = (code == ioDIA)? tti1_unit.buf & 0377: 0; -switch (pulse) { /* decode IR<8:9> */ - - case iopS: /* start */ - dev_busy = dev_busy | INT_TTI1; /* set busy */ - dev_done = dev_done & ~INT_TTI1; /* clear done, int */ - int_req = int_req & ~INT_TTI1; - break; - - case iopC: /* clear */ - dev_busy = dev_busy & ~INT_TTI1; /* clear busy */ - dev_done = dev_done & ~INT_TTI1; /* clear done, int */ - int_req = int_req & ~INT_TTI1; - break; - } /* end switch */ - -return iodata; -} - -/* Unit service */ - -t_stat tti1_svc (UNIT *uptr) -{ -int32 temp, newln; - -if (tt1_ldsc.conn) { /* connected? */ - tmxr_poll_rx (&tt_desc); /* poll for input */ - if ((temp = tmxr_getc_ln (&tt1_ldsc))) { /* get char */ - uptr->buf = temp & 0177; - if ((uptr->flags & UNIT_DASHER) && - (uptr->buf == '\r')) - uptr->buf = '\n'; /* Dasher: cr->nl */ - dev_busy = dev_busy & ~INT_TTI1; /* clear busy */ - dev_done = dev_done | INT_TTI1; /* set done */ - int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); - } - sim_activate (uptr, uptr->wait); /* continue poll */ - } -if (uptr->flags & UNIT_ATT) { /* attached? */ - newln = tmxr_poll_conn (&tt_desc); /* poll connect */ - if (newln >= 0) { /* got one? */ - sim_activate (&tti1_unit, tti1_unit.wait); - tt1_ldsc.rcve = 1; /* rcv enabled */ - } - sim_activate (uptr, tmxr_poll); /* sched poll */ - } -return SCPE_OK; -} - -/* Reset routine */ - -t_stat tti1_reset (DEVICE *dptr) -{ -ttx1_enbdis (dptr->flags & DEV_DIS); /* sync devices */ -tti1_unit.buf = 0; /* */ -dev_busy = dev_busy & ~INT_TTI1; /* clear busy */ -dev_done = dev_done & ~INT_TTI1; /* clear done, int */ -int_req = int_req & ~INT_TTI1; -if (tt1_ldsc.conn) { /* if conn, */ - sim_activate (&tti1_unit, tti1_unit.wait); /* activate, */ - tt1_ldsc.rcve = 1; /* enable */ - } -else if (tti1_unit.flags & UNIT_ATT) /* if attached, */ - sim_activate (&tti1_unit, tmxr_poll); /* activate */ -else sim_cancel (&tti1_unit); /* else stop */ -return SCPE_OK; -} - -/* Terminal output: IOT routine */ - -int32 tto1 (int32 pulse, int32 code, int32 AC) -{ -if (code == ioDOA) - tto1_unit.buf = AC & 0377; -switch (pulse) { /* decode IR<8:9> */ - - case iopS: /* start */ - dev_busy = dev_busy | INT_TTO1; /* set busy */ - dev_done = dev_done & ~INT_TTO1; /* clear done, int */ - int_req = int_req & ~INT_TTO1; - sim_activate (&tto1_unit, tto1_unit.wait); /* activate unit */ - break; - - case iopC: /* clear */ - dev_busy = dev_busy & ~INT_TTO1; /* clear busy */ - dev_done = dev_done & ~INT_TTO1; /* clear done, int */ - int_req = int_req & ~INT_TTO1; - sim_cancel (&tto1_unit); /* deactivate unit */ - break; - } /* end switch */ - -return 0; -} - -/* Unit service */ - -t_stat tto1_svc (UNIT *uptr) -{ -int32 c; - -dev_busy = dev_busy & ~INT_TTO1; /* clear busy */ -dev_done = dev_done | INT_TTO1; /* set done */ -int_req = (int_req & ~INT_DEV) | (dev_done & ~dev_disable); -c = tto1_unit.buf & 0177; -if ((tto1_unit.flags & UNIT_DASHER) && (c == 031)) - c = '\b'; -if (tt1_ldsc.conn) { /* connected? */ - if (tt1_ldsc.xmte) { /* tx enabled? */ - tmxr_putc_ln (&tt1_ldsc, c); /* output char */ - tmxr_poll_tx (&tt_desc); /* poll xmt */ - } - else { - tmxr_poll_tx (&tt_desc); /* poll xmt */ - sim_activate (&tto1_unit, tmxr_poll); /* wait */ - } - } -return SCPE_OK; -} - -/* Reset routine */ - -t_stat tto1_reset (DEVICE *dptr) -{ -ttx1_enbdis (dptr->flags & DEV_DIS); /* sync devices */ -tto1_unit.buf = 0; /* */ -dev_busy = dev_busy & ~INT_TTO1; /* clear busy */ -dev_done = dev_done & ~INT_TTO1; /* clear done, int */ -int_req = int_req & ~INT_TTO1; -sim_cancel (&tto1_unit); /* deactivate unit */ -return SCPE_OK; -} - -t_stat ttx1_setmod (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -tti1_unit.flags = (tti1_unit.flags & ~UNIT_DASHER) | val; -tto1_unit.flags = (tto1_unit.flags & ~UNIT_DASHER) | val; -return SCPE_OK; -} - -/* Attach routine */ - -t_stat tti1_attach (UNIT *uptr, char *cptr) -{ -t_stat r; - -r = tmxr_attach (&tt_desc, uptr, cptr); /* attach */ -if (r != SCPE_OK) /* error */ - return r; -sim_activate (uptr, tmxr_poll); /* start poll */ -return SCPE_OK; -} - -/* Detach routine */ - -t_stat tti1_detach (UNIT *uptr) -{ -t_stat r; - -r = tmxr_detach (&tt_desc, uptr); /* detach */ -tt1_ldsc.rcve = 0; /* disable rcv */ -sim_cancel (uptr); /* stop poll */ -return r; -} - -/* Enable/disable device */ - -void ttx1_enbdis (int32 dis) -{ -if (dis) { - tti1_dev.flags = tti1_dev.flags | DEV_DIS; - tto1_dev.flags = tto1_dev.flags | DEV_DIS; - } -else { - tti1_dev.flags = tti1_dev.flags & ~DEV_DIS; - tto1_dev.flags = tto1_dev.flags & ~DEV_DIS; - } -return; -} diff --git a/PDP1/pdp1_clk.c b/PDP1/pdp1_clk.c deleted file mode 100644 index 94d4124a..00000000 --- a/PDP1/pdp1_clk.c +++ /dev/null @@ -1,127 +0,0 @@ -/* pdp1_clk.c: PDP-1D clock simulator - - Copyright (c) 2006-2008, 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 - bused in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - clk PDP-1D clock - - Note that the clock is run at 1/8 of real speed (125Hz instead of 1Khz), to - provide for eventual implementation of idling. -*/ - -#include "pdp1_defs.h" - -#define CLK_HWRE_TPS 1000 /* hardware freq */ -#define CLK_TPS 125 /* sim freq */ -#define CLK_CNTS (CLK_HWRE_TPS / CLK_TPS) /* counts per tick */ -#define CLK_C1MIN (1000 * 60) /* counts per min */ -#define CLK_C32MS 32 /* counts per 32ms */ - -int32 clk32ms_sbs = 0; /* 32ms SBS level */ -int32 clk1min_sbs = 0; /* 1min SBS level */ -int32 clk_cntr = 0; -int32 tmxr_poll = 5000; - -extern int32 stop_inst; - -t_stat clk_svc (UNIT *uptr); -t_stat clk_reset (DEVICE *dptr); - -/* CLK data structures - - clk_dev CLK device descriptor - clk_unit CLK unit - clk_reg CLK register list -*/ - -UNIT clk_unit = { - UDATA (&clk_svc, 0, 0), 5000 - }; - -REG clk_reg[] = { - { ORDATA (CNTR, clk_cntr, 16) }, - { DRDATA (SBS32LVL, clk32ms_sbs, 4), REG_HRO }, - { DRDATA (SBS1MLVL, clk1min_sbs, 4), REG_HRO }, - { NULL } - }; - -MTAB clk_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "SBS32MSLVL", "SBS32MSLVL", - &dev_set_sbs, &dev_show_sbs, (void *) &clk32ms_sbs }, - { MTAB_XTD|MTAB_VDV, 0, "SBS1MINLVL", "SBS1MINLVL", - &dev_set_sbs, &dev_show_sbs, (void *) &clk1min_sbs }, - { 0 } - }; - -DEVICE clk_dev = { - "CLK", &clk_unit, clk_reg, clk_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &clk_reset, - NULL, NULL, NULL, - NULL, DEV_DISABLE | DEV_DIS - }; - -/* Clock IOT routine */ - -int32 clk (int32 inst, int32 dev, int32 dat) -{ -int32 used, incr; - -if (clk_dev.flags & DEV_DIS) /* disabled? */ - return (stop_inst << IOT_V_REASON) | dat; /* illegal inst */ -used = tmxr_poll - (sim_activate_time (&clk_unit) - 1); -incr = (used * CLK_CNTS) / tmxr_poll; -return clk_cntr + incr; -} - -/* Unit service, generate appropriate interrupts */ - -t_stat clk_svc (UNIT *uptr) -{ -if (clk_dev.flags & DEV_DIS) /* disabled? */ - return SCPE_OK; -tmxr_poll = sim_rtcn_calb (CLK_TPS, TMR_CLK); /* calibrate clock */ -sim_activate_after (uptr, 1000000/CLK_TPS); /* reactivate unit */ -clk_cntr = clk_cntr + CLK_CNTS; /* incr counter */ -if ((clk_cntr % CLK_C32MS) == 0) /* 32ms interval? */ - dev_req_int (clk32ms_sbs); /* req intr */ -if (clk_cntr >= CLK_C1MIN) { /* 1min interval? */ - dev_req_int (clk1min_sbs); /* req intr */ - clk_cntr = 0; /* reset counter */ - } -return SCPE_OK; -} - -/* Reset routine */ - -t_stat clk_reset (DEVICE *dptr) -{ -if (clk_dev.flags & DEV_DIS) sim_cancel (&clk_unit); /* disabled? */ -else { - sim_register_clock_unit (&clk_unit); /* declare clock unit */ - tmxr_poll = sim_rtcn_init (clk_unit.wait, TMR_CLK); - sim_activate_abs (&clk_unit, tmxr_poll); /* activate unit */ - } -clk_cntr = 0; /* clear counter */ -return SCPE_OK; -} diff --git a/PDP1/pdp1_cpu.c b/PDP1/pdp1_cpu.c deleted file mode 100644 index 03ffc81e..00000000 --- a/PDP1/pdp1_cpu.c +++ /dev/null @@ -1,1719 +0,0 @@ -/* pdp1_cpu.c: PDP-1 CPU simulator - - Copyright (c) 1993-2017, 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. - - cpu PDP-1 central processor - - 07-Sep-17 RMS Fixed sim_eval declaration in history routine (COVERITY) - 27-Mar-15 RMS Backported changes from GitHub master - 21-Mar-12 RMS Fixed & vs && in Ea_ch (Michael Bloom) - 30-May-07 RMS Fixed typo in SBS clear (Norm Lastovica) - 28-Dec-06 RMS Added 16-channel SBS support, PDP-1D support - 28-Jun-06 RMS Fixed bugs in MUS and DIV - 22-Sep-05 RMS Fixed declarations (Sterling Garwood) - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 09-Nov-04 RMS Added instruction history - 08-Feb-04 PLB Added display device spacewar/test switches - 07-Sep-03 RMS Added additional explanation on I/O simulation - 01-Sep-03 RMS Added address switches for hardware readin - 23-Jul-03 RMS Revised to detect I/O wait hang - 05-Dec-02 RMS Added drum support - 06-Oct-02 RMS Revised for V2.10 - 20-Aug-02 RMS Added DECtape support - 30-Dec-01 RMS Added old PC queue - 07-Dec-01 RMS Revised to use breakpoint package - 30-Nov-01 RMS Added extended SET/SHOW support - 16-Dec-00 RMS Fixed bug in XCT address calculation - 14-Apr-99 RMS Changed t_addr to unsigned - - The PDP-1 was Digital's first computer. Although Digital built four - other 18b computers, the later systems (the PDP-4, PDP-7, PDP-9, and - PDP-15) were similar to each other and quite different from the PDP-1. - Accordingly, the PDP-1 requires a distinct simulator. - - The register state for the PDP-1 is: - - AC<0:17> accumulator - IO<0:17> IO register - OV overflow flag - PC<0:15> program counter - IOSTA I/O status register - SBS<0:2> sequence break flip flops - IOH I/O halt flip flop - IOS I/O synchronizer (completion) flip flop - EXTM extend mode - PF<1:6> program flags - SS<1:6> sense switches - TW<0:17> test word (switch register) - - The 16-channel sequence break system adds additional state: - - sbs_req<0:15> interrupt requests - sbs_enb<0:15> enabled levels - sbs_act<0:15> active levels - - The PDP-1D adds additional state: - - L link (SN 45 only) - RNG ring mode - RM restrict mode - RMASK restrict mode mask - RNAME rename table (SN 45 only) - RTB restict mode trap buffer (SN 45 only) - - Questions: - - cks: which bits are line printer print done and space done? - cks: is there a bit for sequence break enabled (yes, according - to the 1963 Handbook) - sbs: do sequence breaks accumulate while the system is disabled - (yes, according to the Maintenance Manual) - - The PDP-1 has seven instruction formats: memory reference, skips, - shifts, load immediate, I/O transfer, operate, and (PDP-1D) special. - The memory reference format is: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | op |in| address | memory reference - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - <0:4> <5> mnemonic action - - 00 - 02 AND AC = AC & M[MA] - 04 IOR AC = AC | M[MA] - 06 XOR AC = AC ^ M[MA] - 10 XCT M[MA] is executed as an instruction - 12 LCH load character (PDP-1D) - 14 DCH store character (PDP-1D) - 16 0 CAL M[100] = AC, AC = PC, PC = 101 - 16 1 JDA M[MA] = AC, AC = PC, PC = MA + 1 - 20 LAC AC = M[MA] - 22 LIO IO = M[MA] - 24 DAC M[MA] = AC - 26 DAP M[MA]<6:17> = AC<6:17> - 30 DIP M[MA]<0:5> = AC<0:5> - 32 DIO M[MA] = IO - 34 DZM M[MA] = 0 - 36 TAD L'AC = AC + M[MA] + L - 40 ADD AC = AC + M[MA] - 42 SUB AC = AC - M[MA] - 44 IDX AC = M[MA] = M[MA] + 1 - 46 ISP AC = M[MA] = M[MA] + 1, skip if AC >= 0 - 50 SAD skip if AC != M[MA] - 52 SAS skip if AC == M[MA] - 54 MUL AC'IO = AC * M[MA] - 56 DIV AC, IO = AC'IO / M[MA] - 60 JMP PC = MA - 62 JSP AC = PC, PC = MA - - Memory reference instructions can access an address space of 64K words. - The address space is divided into sixteen 4K word fields. An - instruction can directly address, via its 12b address, the entire - current field. If extend mode is off, indirect addresses access - the current field, and indirect addressing is multi-level; if off, - they can access all 64K, and indirect addressing is single level. - - The skip format is: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 1 1 0 1 0| | | | | | | | | | | | | | skip - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | | | | | | | \______/ \______/ - | | | | | | | | | - | | | | | | | | +---- program flags - | | | | | | | +------------- sense switches - | | | | | | +------------------- AC == 0 - | | | | | +---------------------- AC >= 0 - | | | | +------------------------- AC < 0 - | | | +---------------------------- OV == 0 - | | +------------------------------- IO >= 0 - | +---------------------------------- IO != 0 (PDP-1D) - +------------------------------------- invert skip - - The shift format is: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 1 1 0 1 1| subopcode | encoded count | shift - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - The load immediate format is: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 1 1 1 0 0| S| immediate | LAW - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - <0:4> mnemonic action - - 70 LAW if S = 0, AC = IR<6:17> - else AC = ~IR<6:17> - - The I/O transfer format is: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 1 1 1 0 1| W| C| subopcode | device | I/O transfer - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - The IO transfer instruction sends the the specified subopcode to - specified I/O device. The I/O device may take data from the IO or - return data to the IO, initiate or cancel operations, etc. The - W bit specifies whether the CPU waits for completion, the C bit - whether a completion pulse will be returned from the device. - - The special operate format (PDP-1D) is: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 1 1 1 1 0| | | | | | | | | | | | | | special - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | | | | | | | | | | | - | | | | | | | | | | +------- CML (3) - | | | | | | | | | +---------- CLL (1) - | | | | | | | | +------------- SZL (1) - | | | | | | | +---------------- SCF (1) - | | | | | | +------------------- SCI (1) - | | | | | +---------------------- SCM (2) - | | | | +------------------------- IDA (3) - | | | +---------------------------- IDC (4) - | | +------------------------------- IFI (2) - | +---------------------------------- IIF (2) - +------------------------------------- reverse skip - - The special operate instruction can be microprogrammed. - - The standard operate format is: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 1 1 1 1 1| | | | | | | | | | | | | | operate - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | | | | | | | | | | \______/ - | | | | | | | | | | | - | | | | | | | | | | +---- PF select - | | | | | | | | | +---------- clear/set PF - | | | | | | | | +------------- LIA (PDP-1D) - | | | | | | | +---------------- LAI (PDP-1D) - | | | | | | +------------------- or PC - | | | | | +---------------------- CLA - | | | | +------------------------- halt - | | | +---------------------------- CMA - | | +------------------------------- or TW - | +---------------------------------- CLI - +------------------------------------- CMI (PDP-1D) - - The standard operate instruction can be microprogrammed. - - This routine is the instruction decode routine for the PDP-1. - 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 - unimplemented instruction and STOP_INST flag set - XCT loop - indirect address loop - infinite wait state - I/O error in I/O simulator - - 2. Interrupts. With a single channel sequence break system, the - PDP-1 has a single break request (flop b2, here sbs). - If sequence breaks are enabled (flop sbm, here sbs), - and one is not already in progress (flop b4, here sbs), - a sequence break occurs. With a 16-channel sequence break - system, the PDP-1 has 16 request flops (sbs_req), 16 enable - flops (sbs_enb), and 16 active flops (sbs_act). It also has - 16 synchronizer flops, which are not needed in simulation. - - 3. Arithmetic. The PDP-1 is a 1's complement system. In 1's - complement arithmetic, a negative number is represented by the - complement (XOR 0777777) of its absolute value. Addition of 1's - complement numbers requires propagating the carry out of the high - order bit back to the low order bit. - - 4. Adding I/O devices. Three modules must be modified: - - pdp1_defs.h add interrupt request definition - pdp1_cpu.c add IOT dispatch code - pdp1_sys.c add sim_devices table entry -*/ - -#include "pdp1_defs.h" - -#define PCQ_SIZE 64 /* must be 2**n */ -#define PCQ_MASK (PCQ_SIZE - 1) -#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC -#define UNIT_V_MDV (UNIT_V_UF + 0) /* mul/div */ -#define UNIT_V_SBS (UNIT_V_UF + 1) -#define UNIT_V_1D (UNIT_V_UF + 2) -#define UNIT_V_1D45 (UNIT_V_UF + 3) -#define UNIT_V_MSIZE (UNIT_V_UF + 4) /* dummy mask */ -#define UNIT_MDV (1 << UNIT_V_MDV) -#define UNIT_SBS (1 << UNIT_V_SBS) -#define UNIT_1D (1 << UNIT_V_1D) -#define UNIT_1D45 (1 << UNIT_V_1D45) -#define UNIT_MSIZE (1 << UNIT_V_MSIZE) - -#define HIST_PC 0x40000000 -#define HIST_V_SHF 18 -#define HIST_MIN 64 -#define HIST_MAX 65536 - -#define MA_GETBNK(x) ((cpu_unit.flags & UNIT_1D45)? \ - (((x) >> RM45_V_BNK) & RM45_M_BNK): \ - (((x) >> RM48_V_BNK) & RM48_M_BNK)) - -typedef struct { - uint32 pc; - uint32 ir; - uint32 ovac; - uint32 pfio; - uint32 ea; - uint32 opnd; - } InstHistory; - -int32 M[MAXMEMSIZE] = { 0 }; /* memory */ -int32 AC = 0; /* AC */ -int32 IO = 0; /* IO */ -int32 PC = 0; /* PC */ -int32 MA = 0; /* MA */ -int32 MB = 0; /* MB */ -int32 OV = 0; /* overflow */ -int32 SS = 0; /* sense switches */ -int32 PF = 0; /* program flags */ -int32 TA = 0; /* address switches */ -int32 TW = 0; /* test word */ -int32 iosta = 0; /* status reg */ -int32 sbs = 0; /* sequence break */ -int32 sbs_init = 0; /* seq break start */ -int32 ioh = 0; /* I/O halt */ -int32 ios = 0; /* I/O syncronizer */ -int32 cpls = 0; /* pending compl */ -int32 sbs_req = 0; /* sbs requests */ -int32 sbs_enb = 0; /* sbs enabled */ -int32 sbs_act = 0; /* sbs active */ -int32 extm = 0; /* ext mem mode */ -int32 rm = 0; /* restrict mode */ -int32 rmask = 0; /* restrict mask */ -int32 rname[RN45_SIZE]; /* rename table */ -int32 rtb = 0; /* restr trap buf */ -int32 extm_init = 0; /* ext mem startup */ -int32 stop_inst = 0; /* stop rsrv inst */ -int32 xct_max = 16; /* XCT limit */ -int32 ind_max = 16; /* ind limit */ -uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ -int32 pcq_p = 0; /* PC queue ptr */ -REG *pcq_r = NULL; /* PC queue reg ptr */ -int32 hst_p = 0; /* history pointer */ -int32 hst_lnt = 0; /* history length */ -InstHistory *hst = NULL; /* inst history */ - -t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); -t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); -t_stat cpu_reset (DEVICE *dptr); -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_1d (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat Ea (int32 IR); -t_stat Ea_ch (int32 IR, int32 *byte_num); -int32 inc_bp (int32 bp); -t_stat set_rmv (int32 code); -int32 sbs_eval (void); -int32 sbs_ffo (int32 mask); -t_stat Read (void); -t_stat Write (void); - -extern int32 ptr (int32 inst, int32 dev, int32 dat); -extern int32 ptp (int32 inst, int32 dev, int32 dat); -extern int32 tti (int32 inst, int32 dev, int32 dat); -extern int32 tto (int32 inst, int32 dev, int32 dat); -extern int32 lpt (int32 inst, int32 dev, int32 dat); -extern int32 dt (int32 inst, int32 dev, int32 dat); -extern int32 drm (int32 inst, int32 dev, int32 dat); -extern int32 clk (int32 inst, int32 dev, int32 dat); -extern int32 dcs (int32 inst, int32 dev, int32 dat); -#ifdef USE_DISPLAY -extern int32 dpy (int32 inst, int32 dev, int32 dat, int32 dat2); -extern int32 spacewar (int32 inst, int32 dev, int32 dat); -#endif - -const int32 sc_map[512] = { - 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, /* 00000xxxx */ - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 00001xxxx */ - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 00010xxxx */ - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 00011xxxx */ - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 00100xxxx */ - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 00101xxxx */ - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 00110xxxx */ - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 00111xxxx */ - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 01000xxxx */ - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 01001xxxx */ - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 01010xxxx */ - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 01011xxxx */ - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 01100xxxx */ - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 01101xxxx */ - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 01110xxxx */ - 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, /* 01111xxxx */ - 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, /* 10000xxxx */ - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 10001xxxx */ - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 10010xxxx */ - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 10011xxxx */ - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 10100xxxx */ - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 10101xxxx */ - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 10110xxxx */ - 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, /* 11011xxxx */ - 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, /* 11000xxxx */ - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 11001xxxx */ - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 11010xxxx */ - 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, /* 11011xxxx */ - 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, /* 11100xxxx */ - 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, /* 11101xxxx */ - 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8, /* 11110xxxx */ - 5, 6, 6, 7, 6, 7, 7, 8, 6, 7, 7, 8, 7, 8, 8, 9 /* 11111xxxx */ - }; - -const int32 ffo_map[256] = { - 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - -const int32 byt_shf[4] = { 0, 0, 6, 12 }; - -/* CPU data structures - - cpu_dev CPU device descriptor - cpu_unit CPU unit - cpu_reg CPU register list - cpu_mod CPU modifier list -*/ - -UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) }; - -REG cpu_reg[] = { - { ORDATA (PC, PC, ASIZE) }, - { ORDATA (AC, AC, 18) }, - { ORDATA (IO, IO, 18) }, - { ORDATA (MA, MA, 16) }, - { ORDATA (MB, MB, 18) }, - { FLDATA (OV, OV, 0) }, - { ORDATA (PF, PF, 8) }, - { ORDATA (SS, SS, 6) }, - { ORDATA (TA, TA, ASIZE) }, - { ORDATA (TW, TW, 18) }, - { FLDATA (EXTM, extm, 0) }, - { FLDATA (RNGM, PF, PF_V_RNG) }, - { FLDATA (L, PF, PF_V_L) }, - { FLDATA (RM, rm, 0) }, - { ORDATA (RMASK, rmask, 18) }, - { ORDATA (RTB, rtb, 18) }, - { BRDATA (RNAME, rname, 8, 2, RN45_SIZE) }, - { FLDATA (SBON, sbs, SB_V_ON) }, - { FLDATA (SBRQ, sbs, SB_V_RQ) }, - { FLDATA (SBIP, sbs, SB_V_IP) }, - { ORDATA (SBSREQ, sbs_req, 16) }, - { ORDATA (SBSENB, sbs_enb, 16) }, - { ORDATA (SBSACT, sbs_act, 16) }, - { ORDATA (IOSTA, iosta, 18), REG_RO }, - { ORDATA (CPLS, cpls, 6) }, - { FLDATA (IOH, ioh, 0) }, - { FLDATA (IOS, ios, 0) }, - { BRDATA (PCQ, pcq, 8, ASIZE, PCQ_SIZE), REG_RO+REG_CIRC }, - { ORDATA (PCQP, pcq_p, 6), REG_HRO }, - { FLDATA (STOP_INST, stop_inst, 0) }, - { FLDATA (SBS_INIT, sbs_init, SB_V_ON) }, - { FLDATA (EXTM_INIT, extm_init, 0) }, - { DRDATA (XCT_MAX, xct_max, 8), PV_LEFT + REG_NZ }, - { DRDATA (IND_MAX, ind_max, 8), PV_LEFT + REG_NZ }, - { ORDATA (WRU, sim_int_char, 8) }, - { NULL } - }; - -MTAB cpu_mod[] = { - { UNIT_1D+UNIT_1D45, 0, "standard CPU", "PDP1C" }, - { UNIT_1D+UNIT_1D45, UNIT_1D, "PDP-1D #48", "PDP1D48", &cpu_set_1d }, - { UNIT_1D+UNIT_1D45, UNIT_1D+UNIT_1D45, "PDP1D #45", "PDP1D45", &cpu_set_1d }, - { UNIT_MDV, UNIT_MDV, "multiply/divide", "MDV", NULL }, - { UNIT_MDV, 0, "no multiply/divide", "NOMDV", NULL }, - { UNIT_SBS, UNIT_SBS, "SBS", "SBS", NULL }, - { UNIT_SBS, 0, "no SBS", "NOSBS", NULL }, - { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size }, - { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size }, - { UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size }, - { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size }, - { UNIT_MSIZE, 20480, NULL, "20K", &cpu_set_size }, - { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size }, - { UNIT_MSIZE, 28672, NULL, "28K", &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 }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", - &cpu_set_hist, &cpu_show_hist }, - { 0 } - }; - -DEVICE cpu_dev = { - "CPU", &cpu_unit, cpu_reg, cpu_mod, - 1, 8, ASIZE, 1, 8, 18, - &cpu_ex, &cpu_dep, &cpu_reset, - NULL, NULL, NULL, - NULL, 0 - }; - -t_stat sim_instr (void) -{ -int32 IR, op, i, t, xct_count; -int32 sign, signd, v, sbs_lvl, byno; -int32 dev, pulse, io_data, sc, skip; -t_stat reason; -static int32 fs_test[8] = { - 0, PF_SS_1, PF_SS_2, PF_SS_3, - PF_SS_4, PF_SS_5, PF_SS_6, PF_SS_ALL - }; - -#define EPC_WORD ((OV << 17) | (extm << 16) | PC) -#define INCR_ADDR(x) (((x) & EPCMASK) | (((x) + 1) & DAMASK)) -#define DECR_ADDR(x) (((x) & EPCMASK) | (((x) - 1) & DAMASK)) -#define ABS(x) ((x) ^ (((x) & SIGN)? DMASK: 0)) - -if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */ - cpu_unit.flags |= UNIT_SBS|UNIT_MDV; /* 16-chan SBS, mdv */ - if (!(cpu_unit.flags & UNIT_1D45)) { /* SN 48? */ - PF &= ~PF_L; /* no link */ - rtb = 0; /* no RTB */ - for (i = 0; i < RN45_SIZE; i++) /* no rename */ - rname[i] = i; - } - } -else { /* standard PDP-1 */ - PF &= ~(PF_L|PF_RNG); /* no link, ring */ - rm = 0; /* no restrict mode */ - rtb = 0; /* no RTB */ - for (i = 0; i < RN45_SIZE; i++) /* no rename */ - rname[i] = i; - } -if (cpu_unit.flags & UNIT_SBS) { /* 16-chan SBS? */ - sbs = sbs & SB_ON; /* yes, only SB ON */ - sbs_lvl = sbs_eval (); /* eval SBS system */ - } -else sbs_lvl = sbs_req = sbs_enb = sbs_act = 0; /* no, clr SBS sys */ - -/* Main instruction fetch/decode loop: check events and interrupts */ - -reason = 0; -while (reason == 0) { /* loop until halted */ - - if (sim_interval <= 0) { /* check clock queue */ - if ((reason = sim_process_event ())) - break; - sbs_lvl = sbs_eval (); /* eval sbs system */ - } - - if ((cpu_unit.flags & UNIT_SBS)? /* test interrupt */ - ((sbs & SB_ON) && sbs_lvl): /* 16-chan SBS? */ - (sbs == (SB_ON | SB_RQ))) { /* 1-chan SBS? */ - if (cpu_unit.flags & UNIT_SBS) { /* 16-chan intr */ - int32 lvl = sbs_lvl - 1; /* get level */ - MA = lvl << 2; /* status block */ - sbs_req &= ~SBS_MASK (lvl); /* clr lvl request */ - sbs_act |= SBS_MASK (lvl); /* set lvl active */ - sbs_lvl = sbs_eval (); /* re-eval SBS */ - } - else { /* 1-chan intr */ - MA = 0; /* always level 0 */ - sbs = SB_ON | SB_IP; /* set in prog flag */ - } - PCQ_ENTRY; /* save old PC */ - MB = AC; /* save AC */ - Write (); - MA = MA + 1; - MB = EPC_WORD; /* save OV'EXT'PC */ - Write (); - MA = MA + 1; - MB = IO; /* save IO */ - Write (); - PC = MA + 1; /* PC = block + 3 */ - extm = 0; /* extend off */ - OV = 0; /* clear overflow */ - } - - if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; - } - -/* Fetch, decode instruction */ - - MA = PC; - if (Read ()) /* fetch inst */ - break; - IR = MB; /* save in IR */ - PC = INCR_ADDR (PC); /* increment PC */ - xct_count = 0; /* track XCT's */ - sim_interval = sim_interval - 1; - if (hst_lnt) { /* history enabled? */ - hst_p = (hst_p + 1); /* next entry */ - if (hst_p >= hst_lnt) - hst_p = 0; - hst[hst_p].pc = MA | HIST_PC; /* save state */ - hst[hst_p].ir = IR; - hst[hst_p].ovac = (OV << HIST_V_SHF) | AC; - hst[hst_p].pfio = (PF << HIST_V_SHF) | IO; - } - - xct_instr: /* label for XCT */ - op = ((IR >> 13) & 037); /* get opcode */ - switch (op) { /* decode IR<0:4> */ - -/* Logical, load, store instructions */ - - case 001: /* AND */ - if ((reason = Ea (IR))) /* MA <- eff addr */ - break; - if ((reason = Read ())) /* MB <- data */ - break; - AC = AC & MB; - break; - - case 002: /* IOR */ - if ((reason = Ea (IR))) /* MA <- eff addr */ - break; - if ((reason = Read ())) /* MB <- data */ - break; - AC = AC | MB; - break; - - case 003: /* XOR */ - if ((reason = Ea (IR))) /* MA <- eff addr */ - break; - if ((reason = Read ())) /* MB <- data */ - break; - AC = AC ^ MB; - break; - - case 004: /* XCT */ - if (xct_count >= xct_max) { /* too many XCT's? */ - reason = STOP_XCT; - break; - } - if ((reason = Ea (IR))) /* MA <- eff addr */ - break; - if ((reason = Read ())) /* MB <- data */ - break; - xct_count = xct_count + 1; /* count XCT's */ - IR = MB; /* get instruction */ - goto xct_instr; /* go execute */ - - case 005: /* LCH */ - if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */ - if ((reason = Ea_ch (IR, &byno))) /* MA <- eff addr */ - break; - if ((reason = Read ())) /* MB <- data */ - break; - AC = (MB << byt_shf[byno]) & 0770000; /* extract byte */ - } - else reason = stop_inst; /* no, illegal */ - break; - - case 006: /* DCH */ - if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */ - if ((reason = Ea_ch (IR, &byno))) /* MA <- eff addr */ - break; - if ((reason = Read ())) /* MB <- data */ - break; - MB = (MB & ~(0770000 >> byt_shf[byno])) | /* insert byte */ - ((AC & 0770000) >> byt_shf[byno]); - Write (); /* rewrite */ - AC = ((AC << 6) | (AC >> 12)) & DMASK; /* rot AC left 6 */ - } - else reason = stop_inst; /* no, illegal */ - break; - - case 007: /* CAL, JDA */ - MA = (PC & EPCMASK) | ((IR & IA)? (IR & DAMASK): 0100); - if (hst_p) /* history enabled? */ - hst[hst_p].ea = MA; - PCQ_ENTRY; - MB = AC; /* save AC */ - AC = EPC_WORD; - PC = INCR_ADDR (MA); - reason = Write (); - break; - - case 010: /* LAC */ - if ((reason = Ea (IR))) /* MA <- eff addr */ - break; - if ((reason = Read ())) /* MB <- data */ - break; - AC = MB; - break; - - case 011: /* LIO */ - if ((reason = Ea (IR))) /* MA <- eff addr */ - break; - if ((reason = Read ())) /* MB <- data */ - break; - IO = MB; - break; - - case 012: /* DAC */ - if ((reason = Ea (IR))) /* MA <- eff addr */ - break; - MB = AC; - reason = Write (); - break; - - case 013: /* DAP */ - if ((reason = Ea (IR))) /* MA <- eff addr */ - break; - if ((reason = Read ())) /* MB <- data */ - break; - MB = (AC & DAMASK) | (MB & ~DAMASK); - reason = Write (); - break; - - case 014: /* DIP */ - if ((reason = Ea (IR))) /* MA <- eff addr */ - break; - if ((reason = Read ())) /* MB <- data */ - break; - MB = (AC & ~DAMASK) | (MB & DAMASK); - reason = Write (); - break; - - case 015: /* DIO */ - if ((reason = Ea (IR))) /* MA <- eff addr */ - break; - MB = IO; - reason = Write (); - break; - - case 016: /* DZM */ - if ((reason = Ea (IR))) /* MA <- eff addr */ - break; - MB = 0; - reason = Write (); - break; - -/* Add, subtract, control - - Add is performed in sequential steps, as follows: - 1. add - 2. end around carry propagate - 3. overflow check - 4. -0 cleanup - - Subtract is performed in sequential steps, as follows: - 1. complement AC - 2. add - 3. end around carry propagate - 4. overflow check - 5. complement AC - Because no -0 check is done, (-0) - (+0) yields a result of -0 */ - - case 017: /* TAD */ - if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */ - if ((reason = Ea (IR))) /* MA <- eff addr */ - break; - if ((reason = Read ())) /* MB <- data */ - break; - AC = AC + MB + ((PF & PF_L)? 1: 0); /* AC + opnd + L */ - if (AC > DMASK) /* carry? set L */ - PF = PF | PF_L; - else PF = PF & ~PF_L; /* no, clear L */ - AC = AC & DMASK; /* mask AC */ - } - else reason = stop_inst; /* no, illegal */ - break; - - case 020: /* ADD */ - if ((reason = Ea (IR))) /* MA <- eff addr */ - break; - if ((reason = Read ())) /* MB <- data */ - break; - t = AC; - AC = AC + MB; - if (AC > 0777777) /* end around carry */ - AC = (AC + 1) & DMASK; - if (((~t ^ MB) & (t ^ AC)) & SIGN) - OV = 1; - if (AC == DMASK) /* minus 0 cleanup */ - AC = 0; - break; - - case 021: /* SUB */ - if ((reason = Ea (IR))) /* MA <- eff addr */ - break; - if ((reason = Read ())) /* MB <- data */ - break; - t = AC ^ DMASK; /* complement AC */ - AC = t + MB; /* -AC + MB */ - if (AC > DMASK) /* end around carry */ - AC = (AC + 1) & DMASK; - if (((~t ^ MB) & (t ^ AC)) & SIGN) - OV = 1; - AC = AC ^ DMASK; /* recomplement AC */ - break; - - case 022: /* IDX */ - if ((reason = Ea (IR))) /* MA <- eff addr */ - break; - if ((reason = Read ())) /* MB <- data */ - break; - AC = MB + 1; - if (AC >= DMASK) - AC = (AC + 1) & DMASK; - MB = AC; - reason = Write (); - break; - - case 023: /* ISP */ - if ((reason = Ea (IR))) /* MA <- eff addr */ - break; - if ((reason = Read ())) /* MB <- data */ - break; - AC = MB + 1; - if (AC >= DMASK) - AC = (AC + 1) & DMASK; - MB = AC; - if (!(AC & SIGN)) - PC = INCR_ADDR (PC); - reason = Write (); - break; - - case 024: /* SAD */ - if ((reason = Ea (IR))) /* MA <- eff addr */ - break; - if ((reason = Read ())) /* MB <- data */ - break; - if (AC != MB) - PC = INCR_ADDR (PC); - break; - - case 025: /* SAS */ - if ((reason = Ea (IR))) /* MA <- eff addr */ - break; - if ((reason = Read ())) /* MB <- data */ - break; - if (AC == MB) - PC = INCR_ADDR (PC); - break; - - case 030: /* JMP */ - if (sbs && /* SBS enabled? */ - ((PC & EPCMASK) == 0) && /* in bank 0? */ - ((IR & (IA|07703)) == (IA|00001)) && /* jmp i 00x1/5? */ - ((cpu_unit.flags & UNIT_SBS) || /* 16-chan SBS or */ - ((IR & 00074) == 0))) { /* jmp i 0001? */ - if (cpu_unit.flags & UNIT_SBS) { /* 16-chan SBS dbk? */ - int32 lvl = (IR >> 2) & SBS_LVL_MASK; /* lvl = MA<14:15> */ - sbs_act &= ~SBS_MASK (lvl); /* clr level active */ - sbs_lvl = sbs_eval (); /* eval SBS system */ - } - else sbs = sbs & ~SB_IP; /* 1-chan dbk */ - PCQ_ENTRY; /* save old PC */ - MA = IR & DAMASK; /* ind addr */ - Read (); /* eff addr word */ - OV = (MB >> 17) & 1; /* restore OV */ - extm = (MB >> 16) & 1; /* restore ext mode */ - PC = MB & AMASK; /* jmp i 00x1/5 */ - if (hst_p) /* history enabled? */ - hst[hst_p].ea = PC; - } - else { /* normal JMP */ - if ((reason = Ea (IR))) /* MA <- eff addr */ - break; - PCQ_ENTRY; - PC = MA; - } - break; - - case 031: /* JSP */ - if ((reason = Ea (IR))) /* MA <- eff addr */ - break; - AC = EPC_WORD; - PCQ_ENTRY; - PC = MA; - break; - - case 034: /* LAW */ - AC = (IR & 07777) ^ ((IR & IA)? 0777777: 0); - break; - -/* Multiply and divide - - Multiply and divide step and hardware multiply are exact implementations. - Hardware divide is a 2's complement analog to the actual hardware. -*/ - - case 026: /* MUL */ - if ((reason = Ea (IR))) /* MA <- eff addr */ - break; - if ((reason = Read ())) /* MB <- data */ - break; - if (cpu_unit.flags & UNIT_MDV) { /* hardware? */ - sign = AC ^ MB; /* result sign */ - IO = ABS (AC); /* IO = |AC| */ - v = ABS (MB); /* v = |mpy| */ - for (i = AC = 0; i < 17; i++) { - if (IO & 1) - AC = AC + v; - IO = (IO >> 1) | ((AC & 1) << 17); - AC = AC >> 1; - } - if ((sign & SIGN) && (AC | IO)) { /* negative, > 0? */ - AC = AC ^ DMASK; - IO = IO ^ DMASK; - } - } - else { /* multiply step */ - if (IO & 1) - AC = AC + MB; - if (AC > DMASK) - AC = (AC + 1) & DMASK; - IO = (IO >> 1) | ((AC & 1) << 17); - AC = AC >> 1; - } - break; - - case 027: /* DIV */ - if ((reason = Ea (IR))) /* MA <- eff addr */ - break; - if ((reason = Read ())) /* MB <- data */ - break; - if (cpu_unit.flags & UNIT_MDV) { /* hardware */ - sign = AC ^ MB; /* result sign */ - signd = AC; /* remainder sign */ - v = ABS (MB); /* v = |divr| */ - if (ABS (AC) >= v) /* overflow? */ - break; - if (AC & SIGN) { - AC = AC ^ DMASK; /* AC'IO = |AC'IO| */ - IO = IO ^ DMASK; - } - for (i = t = 0; i < 18; i++) { - if (t) - AC = (AC + v) & DMASK; - else AC = (AC - v) & DMASK; - t = AC >> 17; - if (i != 17) - AC = ((AC << 1) | (IO >> 17)) & DMASK; - IO = ((IO << 1) | (t ^ 1)) & 0777777; - } - if (t) /* fix remainder */ - AC = (AC + v) & DMASK; - t = ((signd & SIGN) && AC)? AC ^ DMASK: AC; - AC = ((sign & SIGN) && IO)? IO ^ DMASK: IO; - IO = t; - PC = INCR_ADDR (PC); /* skip */ - } - else { /* divide step */ - t = AC >> 17; - AC = ((AC << 1) | (IO >> 17)) & DMASK; - IO = ((IO << 1) | (t ^ 1)) & DMASK; - if (IO & 1) - AC = AC + (MB ^ DMASK); - else AC = AC + MB + 1; - if (AC > DMASK) - AC = (AC + 1) & DMASK; - if (AC == DMASK) - AC = 0; - } - break; - -/* Skips */ - - case 032: /* skip */ - v = (IR >> 3) & 07; /* sense switches */ - t = IR & 07; /* program flags */ - skip = (((cpu_unit.flags & UNIT_1D) && - (IR & 04000) && (IO != 0)) || /* SNI (PDP-1D) */ - ((IR & 02000) && !(IO & SIGN)) || /* SPI */ - ((IR & 01000) && (OV == 0)) || /* SZO */ - ((IR & 00400) && (AC & SIGN)) || /* SMA */ - ((IR & 00200) && !(AC & SIGN)) || /* SPA */ - ((IR & 00100) && (AC == 0)) || /* SZA */ - (v && ((SS & fs_test[v]) == 0)) || /* SZSn */ - (t && ((PF & fs_test[t]) == 0))); /* SZFn */ - if (IR & IA) /* invert skip? */ - skip = skip ^ 1; - if (skip) - PC = INCR_ADDR (PC); - if (IR & 01000) /* SOV clears OV */ - OV = 0; - break; - -/* Shifts */ - - case 033: - sc = sc_map[IR & 0777]; /* map shift count */ - switch ((IR >> 9) & 017) { /* case on IR<5:8> */ - - case 001: /* RAL */ - AC = ((AC << sc) | (AC >> (18 - sc))) & DMASK; - break; - - case 002: /* RIL */ - IO = ((IO << sc) | (IO >> (18 - sc))) & DMASK; - break; - - case 003: /* RCL */ - t = AC; - AC = ((AC << sc) | (IO >> (18 - sc))) & DMASK; - IO = ((IO << sc) | (t >> (18 - sc))) & DMASK; - break; - - case 005: /* SAL */ - t = (AC & SIGN)? DMASK: 0; - AC = (AC & SIGN) | ((AC << sc) & 0377777) | - (t >> (18 - sc)); - break; - - case 006: /* SIL */ - t = (IO & SIGN)? DMASK: 0; - IO = (IO & SIGN) | ((IO << sc) & 0377777) | - (t >> (18 - sc)); - break; - - case 007: /* SCL */ - t = (AC & SIGN)? DMASK: 0; - AC = (AC & SIGN) | ((AC << sc) & 0377777) | - (IO >> (18 - sc)); - IO = ((IO << sc) | (t >> (18 - sc))) & DMASK; - break; - - case 011: /* RAR */ - AC = ((AC >> sc) | (AC << (18 - sc))) & DMASK; - break; - - case 012: /* RIR */ - IO = ((IO >> sc) | (IO << (18 - sc))) & DMASK; - break; - - case 013: /* RCR */ - t = IO; - IO = ((IO >> sc) | (AC << (18 - sc))) & DMASK; - AC = ((AC >> sc) | (t << (18 - sc))) & DMASK; - break; - - case 015: /* SAR */ - t = (AC & SIGN)? DMASK: 0; - AC = ((AC >> sc) | (t << (18 - sc))) & DMASK; - break; - - case 016: /* SIR */ - t = (IO & SIGN)? DMASK: 0; - IO = ((IO >> sc) | (t << (18 - sc))) & DMASK; - break; - - case 017: /* SCR */ - t = (AC & SIGN)? DMASK: 0; - IO = ((IO >> sc) | (AC << (18 - sc))) & DMASK; - AC = ((AC >> sc) | (t << (18 - sc))) & DMASK; - break; - - default: /* undefined */ - reason = stop_inst; - break; - } /* end switch shf */ - break; - -/* Special operates (PDP-1D) - performed in order shown */ - - case 036: /* special */ - if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */ - if (IR & 000100) /* SCI */ - IO = 0; - if (IR & 000040) /* SCF */ - PF = 0; - if (cpu_unit.flags & UNIT_1D45) { /* SN 45? */ - if ((IR & 000020) && /* SZL/SNL? */ - (((PF & PF_L) == 0) == ((IR & IA) == 0))) - PC = INCR_ADDR (PC); - if (IR & 000010) /* CLL */ - PF = PF & ~PF_L; - if (IR & 000200) { /* SCM */ - AC = (AC ^ DMASK) + ((PF & PF_L)? 1: 0); - if (AC > DMASK) /* carry? set L */ - PF = PF | PF_L; - else PF = PF & ~PF_L; /* no, clear L */ - AC = AC & DMASK; /* mask AC */ - } - } - t = IO & PF_VR_ALL; - if (IR & 004000) /* IIF */ - IO = IO | PF; - if (IR & 002000) /* IFI */ - PF = PF | t; - if (cpu_unit.flags & UNIT_1D45) { /* SN 45? */ - if (IR & 000004) /* CML */ - PF = PF ^ PF_L; - if (IR & 000400) /* IDA */ - AC = (PF & PF_RNG)? - (AC & 0777770) | ((AC + 1) & 07): - (AC + 1) & DMASK; - } - else PF = PF & ~PF_L; /* no link */ - if (IR & 01000) /* IDC */ - AC = inc_bp (AC); - } - else reason = stop_inst; /* no, illegal */ - break; - -/* Operates - performed in the order shown */ - - case 037: /* operate */ - if (IR & 004000) /* CLI */ - IO = 0; - if (IR & 000200) /* CLA */ - AC = 0; - if (IR & 002000) /* LAT */ - AC = AC | TW; - if (IR & 000100) /* LAP */ - AC = AC | EPC_WORD; - if (IR & 001000) /* CMA */ - AC = AC ^ DMASK; - if (cpu_unit.flags & UNIT_1D) { /* PDP-1D? */ - if (IR & 010000) /* CMI */ - IO = IO ^ DMASK; - MB = IO; - if (IR & 000020) /* LIA */ - IO = AC; - if (IR & 000040) /* LAI */ - AC = MB; - } - t = IR & 07; /* flag select */ - if (IR & 010) /* STFn */ - PF = PF | fs_test[t]; - else PF = PF & ~fs_test[t]; /* CLFn */ - if (IR & 000400) { /* HLT */ - if (rm && !sbs_act) /* restrict, ~brk? */ - reason = set_rmv (RTB_HLT); /* violation */ - else reason = STOP_HALT; /* no, halt */ - } - break; - -/* IOT - The simulator behaves functionally like a real PDP-1 but does not - use the same mechanisms or state bits. In particular, - - - If an IOT does not specify IO_WAIT, the IOT will be executed, and the - I/O halt flag (IOH) will not be disturbed. On the real PDP-1, IOH is - stored in IHS, IOH is cleared, the IOT is executed, and then IOH is - restored from IHS. Because IHS is not otherwise used, it is not - explicitly simulated. - - If an IOT does specify IO_WAIT, then IOH specifies whether an I/O halt - (wait) is already in progress. - > If already set, I/O wait is in progress. The simulator looks for - a completion pulse (IOS). If there is a pulse, IOH is cleared. If - not, the IOT is fetched again. In either case, execution of the - IOT is skipped. - > If not set, I/O wait must start. IOH is set, the PC is backed up, - and the IOT is executed. - - On a real PDP-1, IOC is the I/O command enable and enables the IOT - pulses. In the simulator, the enabling of IOT pulses is done through - code flow, and IOC is not explicitly simulated. -*/ - - case 035: - if (rm && !sbs_act) { /* restrict, ~brk? */ - reason = set_rmv (RTB_IOT); /* violation */ - break; - } - if (IR & IO_WAIT) { /* wait? */ - if (ioh) { /* I/O halt? */ - if (ios) /* comp pulse? done */ - ioh = 0; - else { /* wait more */ - PC = DECR_ADDR (PC); /* re-execute */ - if (cpls == 0) { /* pending pulses? */ - reason = STOP_WAIT; /* no, CPU hangs */ - break; - } - sim_interval = 0; /* force event */ - } - break; /* skip iot */ - } - ioh = 1; /* turn on halt */ - PC = DECR_ADDR (PC); /* re-execute */ - } - dev = IR & 077; /* get dev addr */ - pulse = (IR >> 6) & 077; /* get pulse data */ - io_data = IO; /* default data */ - switch (dev) { /* case on dev */ - - case 000: /* I/O wait */ - break; - - case 001: - if (IR & 003700) /* DECtape */ - io_data = dt (IR, dev, IO); - else io_data = ptr (IR, dev, IO); /* paper tape rdr */ - break; - - case 002: case 030: /* paper tape rdr */ - io_data = ptr (IR, dev, IO); - break; - - case 003: /* typewriter */ - io_data = tto (IR, dev, IO); - break; - - case 004: /* keyboard */ - io_data = tti (IR, dev, IO); - break; - - case 005: case 006: /* paper tape punch */ - io_data = ptp (IR, dev, IO); - break; - -#ifdef USE_DISPLAY - case 007: /* display */ - io_data = dpy (IR, dev, IO, AC); - break; -#endif - case 010: /* leave ring mode */ - if (cpu_unit.flags & UNIT_1D) - PF = PF & ~PF_RNG; - else reason = stop_inst; - break; - - case 011: /* enter ring mode */ - if (cpu_unit.flags & UNIT_1D) - PF = PF | PF_RNG; - else -#ifdef USE_DISPLAY - io_data = spacewar (IR, dev, IO); -#else - reason = stop_inst; -#endif - break; - - case 022: /* data comm sys */ - io_data = dcs (IR, dev, IO); - break; - - case 032: /* clock */ - io_data = clk (IR, dev, IO); - break; - - case 033: /* check status */ - io_data = iosta | ((sbs & SB_ON)? IOS_SQB: 0); - break; - - case 035: /* check trap buf */ - if (cpu_unit.flags & UNIT_1D45) { /* SN 45? */ - io_data = rtb; - rtb = 0; - } - else reason = stop_inst; - break; - - case 045: /* line printer */ - io_data = lpt (IR, dev, IO); - break; - - case 050: /* deact seq break */ - if (cpu_unit.flags & UNIT_SBS) - sbs_enb &= ~SBS_MASK (pulse & SBS_LVL_MASK); - else reason = stop_inst; - break; - - case 051: /* act seq break */ - if (cpu_unit.flags & UNIT_SBS) - sbs_enb |= SBS_MASK (pulse & SBS_LVL_MASK); - else reason = stop_inst; - break; - - case 052: /* start seq break */ - if (cpu_unit.flags & UNIT_SBS) - sbs_req |= SBS_MASK (pulse & SBS_LVL_MASK); - else reason = stop_inst; - break; - - case 053: /* clear all chan */ - if (cpu_unit.flags & UNIT_SBS) - sbs_enb = 0; - else reason = stop_inst; - break; - - case 054: /* seq brk off */ - sbs = sbs & ~SB_ON; - break; - - case 055: /* seq brk on */ - sbs = sbs | SB_ON; - break; - - case 056: /* clear seq brk */ - sbs = 0; /* clear PI */ - sbs_req = 0; - sbs_enb = 0; - sbs_act = 0; - break; - - case 061: case 062: case 063: /* drum */ - io_data = drm (IR, dev, IO); - break; - - case 064: /* drum/leave rm */ - if (cpu_unit.flags & UNIT_1D) - rm = 0; - else io_data = drm (IR, dev, IO); - break; - - case 065: /* enter rm */ - if (cpu_unit.flags & UNIT_1D) { - rm = 1; - rmask = IO; - } - else reason = stop_inst; - break; - - case 066: /* rename mem */ - if (cpu_unit.flags & UNIT_1D45) { /* SN45? */ - int32 from = (IR >> 9) & RM45_M_BNK; - int32 to = (IR >> 6) & RM45_M_BNK; - rname[from] = to; - } - else reason = stop_inst; - break; - - case 067: /* reset renaming */ - if (cpu_unit.flags & UNIT_1D45) { /* SN45 */ - for (i = 0; i < RN45_SIZE; i++) - rname[i] = i; - } - else reason = stop_inst; - break; - - case 074: /* extend mode */ - extm = (IR >> 11) & 1; /* set from IR<6> */ - break; - - default: /* undefined */ - reason = stop_inst; - break; - } /* end switch dev */ - - IO = io_data & DMASK; - if (io_data & IOT_SKP) /* skip? */ - PC = INCR_ADDR (PC); - if (io_data >= IOT_REASON) - reason = io_data >> IOT_V_REASON; - sbs_lvl = sbs_eval (); /* eval SBS system */ - break; - - default: /* undefined */ - if (rm && !sbs_act) /* restrict, ~brk? */ - reason = set_rmv (RTB_ILL); /* violation */ - else reason = STOP_RSRV; /* halt */ - break; - } /* end switch op */ - - if (reason == ERR_RMV) { /* restrict viol? */ - sbs_req |= SBS_MASK (SBS_LVL_RMV); /* request break */ - sbs_lvl = sbs_eval (); /* re-eval SBS */ - reason = 0; /* continue */ - } - } /* end while */ -pcq_r->qptr = pcq_p; /* update pc q ptr */ -return reason; -} - -/* Effective address routine for standard memory reference instructions */ - -t_stat Ea (int32 IR) -{ -int32 i; -t_stat r; - -MA = (PC & EPCMASK) | (IR & DAMASK); /* direct address */ -if (IR & IA) { /* indirect addr? */ - if (extm) { /* extend? */ - if ((r = Read ())) /* read; err? */ - return r; - MA = MB & AMASK; /* one level */ - } - else { /* multi-level */ - for (i = 0; i < ind_max; i++) { /* count indirects */ - if ((r = Read ())) /* get ind word */ - return r; - MA = (PC & EPCMASK) | (MB & DAMASK); - if ((MB & IA) == 0) - break; - } - if (i >= ind_max) /* indirect loop? */ - return STOP_IND; - } /* end else !extm */ - } /* end if indirect */ -if (hst_p) /* history enabled? */ - hst[hst_p].ea = MA; -return SCPE_OK; -} - -/* Effective address routine for character instructions */ - -t_stat Ea_ch (int32 IR, int32 *bn) -{ -int32 i; -t_stat r; - -MA = (PC & EPCMASK) | (IR & DAMASK); /* direct address */ -if (extm) { /* extend? */ - if ((r = Read ())) /* read; err? */ - return r; - } -else { /* multi-level */ - for (i = 0; i < ind_max; i++) { /* count indirects */ - if ((r = Read ())) /* get ind word */ - return r; - if ((MB & IA) == 0) - break; - MA = (PC & EPCMASK) | (MB & DAMASK); - } - if (i >= ind_max) /* indirect loop? */ - return STOP_IND; - } /* end else !extm */ -if (IR & IA) { /* automatic mode? */ - if (rm && !sbs_act && ((MB & 0607777) == 0607777)) /* page cross? */ - return set_rmv (RTB_CHR); - MB = inc_bp (MB); /* incr byte ptr */ - Write (); /* rewrite */ - } -*bn = (MB >> 16) & 03; /* byte num */ -if (extm) /* final ea */ - MA = MB & AMASK; -else MA = (PC & EPCMASK) | (MB & DAMASK); -if (hst_p) /* history enabled? */ - hst[hst_p].ea = MA; -return SCPE_OK; -} - -/* Increment byte pointer, allowing for ring mode */ - -int32 inc_bp (int32 bp) -{ -bp = bp + (1 << 16); /* add to bit<1> */ -if (bp > DMASK) { /* carry out? */ - if (PF & PF_RNG) /* ring mode? */ - bp = (1 << 16) | (bp & 0177770) | ((bp + 1) & 07); - else bp = (1 << 16) | ((bp + 1) & AMASK); - } -return bp; -} - -/* Read and write memory */ - -t_stat Read (void) -{ -if (rm && !sbs_act) { /* restrict check? */ - int32 bnk = MA_GETBNK (MA); /* get bank */ - if ((rmask << bnk) & SIGN) - return set_rmv (0); - } -MB = M[MA]; -if (hst_p) /* history enabled? */ - hst[hst_p].opnd = MB; -return SCPE_OK; -} - -t_stat Write (void) -{ -if (hst_p) /* hist? old contents */ - hst[hst_p].opnd = M[MA]; -if (rm && !sbs_act) { /* restrict check? */ - int32 bnk = MA_GETBNK (MA); /* get bank */ - if ((rmask << bnk) & SIGN) - return set_rmv (0); - } -if (MEM_ADDR_OK (MA)) - M[MA] = MB; -return SCPE_OK; -} - -/* Restrict mode trap */ - -t_stat set_rmv (int32 code) -{ -rtb = code | (MB & RTB_MB_MASK); -return ERR_RMV; -} - -/* Evaluate SBS system */ - -int32 sbs_eval (void) -{ -int32 hi; - -if (cpu_unit.flags & UNIT_SBS) { /* SBS enabled? */ - if (sbs_req == 0) /* any requests? */ - return 0; - hi = sbs_ffo (sbs_req); /* find highest */ - if (hi < sbs_ffo (sbs_act)) /* higher? */ - return hi + 1; - } -return 0; -} - -/* Find first one in a 16b field */ - -int32 sbs_ffo (int32 mask) -{ -if (mask & 0177400) - return ffo_map[(mask >> 8) & 0377]; -else return (ffo_map[mask & 0377] + 8); -} - -/* Device request interrupt */ - -t_stat dev_req_int (int32 lvl) -{ -if (cpu_unit.flags & UNIT_SBS) { /* SBS enabled? */ - if (lvl >= SBS_LVLS) /* invalid level? */ - return SCPE_IERR; - if (sbs_enb & SBS_MASK (lvl)) /* level active? */ - sbs_req |= SBS_MASK (lvl); /* set SBS request */ - } -else sbs |= SB_RQ; /* PI request */ -return SCPE_OK; -} - -/* Device set/show SBS level */ - -t_stat dev_set_sbs (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 *lvl = (int32 *) desc; -int32 newlvl; -t_stat r; - -if ((cptr == NULL) || (*cptr == 0)) - return SCPE_ARG; -newlvl = get_uint (cptr, 10, SBS_LVLS - 1, &r); -if (r != SCPE_OK) - return SCPE_ARG; -*lvl = newlvl; -return SCPE_OK; -} - -t_stat dev_show_sbs (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -int32 *lvl = (int32 *) desc; - -if (lvl == NULL) - return SCPE_IERR; -fprintf (st, "SBS level %d", *lvl); -return SCPE_OK; -} - -/* Reset routine */ - -t_stat cpu_reset (DEVICE *dptr) -{ -int32 i; - -sbs = sbs_init; -extm = extm_init; -ioh = 0; -ios = 0; -cpls = 0; -sbs_act = 0; -sbs_req = 0; -sbs_enb = 0; -OV = 0; -PF = 0; -MA = 0; -MB = 0; -rm = 0; -rtb = 0; -rmask = 0; -for (i = 0; i < RN45_SIZE; i++) - rname[i] = i; -pcq_r = find_reg ("PCQ", NULL, dptr); -if (pcq_r) - pcq_r->qptr = 0; -else return SCPE_IERR; -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] & DMASK; -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 & DMASK; -return SCPE_OK; -} - -/* Change memory size */ - -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 mc = 0; -uint32 i; - -if ((val <= 0) || (((size_t)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; -} - -/* Set PDP-1D */ - -t_stat cpu_set_1d (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -uptr->flags |= UNIT_SBS|UNIT_MDV; -return SCPE_OK; -} - -/* Set history */ - -t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 i, lnt; -t_stat r; - -if (cptr == NULL) { - for (i = 0; i < hst_lnt; i++) - hst[i].pc = 0; - hst_p = 0; - return SCPE_OK; - } -lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r); -if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) - return SCPE_ARG; -hst_p = 0; -if (hst_lnt) { - free (hst); - hst_lnt = 0; - hst = NULL; - } -if (lnt) { - hst = (InstHistory *) calloc (lnt, sizeof (InstHistory)); - if (hst == NULL) - return SCPE_MEM; - hst_lnt = lnt; - } -return SCPE_OK; -} - -/* Show history */ - -t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -int32 ov, pf, op, k, di, lnt; -char *cptr = (char *) desc; -t_stat r; -extern t_value *sim_eval; -InstHistory *h; - -if (hst_lnt == 0) /* enabled? */ - return SCPE_NOFNC; -if (cptr) { - lnt = (int32) get_uint (cptr, 10, hst_lnt, &r); - if ((r != SCPE_OK) || (lnt == 0)) - return SCPE_ARG; - } -else lnt = hst_lnt; -di = hst_p - lnt; /* work forward */ -if (di < 0) - di = di + hst_lnt; -fprintf (st, "PC OV AC IO PF EA IR\n\n"); -for (k = 0; k < lnt; k++) { /* print specified */ - h = &hst[(++di) % hst_lnt]; /* entry pointer */ - if (h->pc & HIST_PC) { /* instruction? */ - ov = (h->ovac >> HIST_V_SHF) & 1; /* overflow */ - pf = (h->pfio >> HIST_V_SHF) & PF_VR_ALL; /* prog flags */ - op = ((h->ir >> 13) & 037); /* get opcode */ - fprintf (st, "%06o %o %06o %06o %03o ", - h->pc & AMASK, ov, h->ovac & DMASK, h->pfio & DMASK, pf); - if ((op < 032) && (op != 007)) /* mem ref instr */ - fprintf (st, "%06o ", h->ea); - else fprintf (st, " "); - sim_eval[0] = h->ir; - if ((fprint_sym (st, h->pc & AMASK, sim_eval, &cpu_unit, SWMASK ('M'))) > 0) - fprintf (st, "(undefined) %06o", h->ir); - else if (op < 030) /* mem ref instr */ - fprintf (st, " [%06o]", h->opnd); - fputc ('\n', st); /* end line */ - } /* end else instruction */ - } /* end for */ -return SCPE_OK; -} - -#ifdef USE_DISPLAY -/* set "test switches"; from display code */ - -void cpu_set_switches(unsigned long bits) -{ -/* just what we want; smaller CPUs might want to shift down? */ -TW = bits; -} - -unsigned long cpu_get_switches(void) -{ -return TW; -} -#endif diff --git a/PDP1/pdp1_dcs.c b/PDP1/pdp1_dcs.c deleted file mode 100644 index 190477fb..00000000 --- a/PDP1/pdp1_dcs.c +++ /dev/null @@ -1,415 +0,0 @@ -/* pdp1_dcs.c: PDP-1D terminal multiplexor simulator - - Copyright (c) 2006-2013, 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. - - dcs Type 630 data communications subsystem - - 11-Oct-2013 RMS Poll DCS immediately after attach to pick up connect - 19-Nov-2008 RMS Revised for common TMXR show routines - - This module implements up to 32 individual serial interfaces. -*/ - -#include "pdp1_defs.h" -#include "sim_sock.h" -#include "sim_tmxr.h" - -#define DCS_LINES 32 /* lines */ -#define DCS_LINE_MASK (DCS_LINES - 1) -#define DCSL_WAIT 1000 /* output wait */ -#define DCS_NUMLIN dcs_desc.lines - -int32 dcs_sbs = 0; /* SBS level */ -uint32 dcs_send = 0; /* line for send */ -uint32 dcs_scan = 0; /* line for scanner */ -uint8 dcs_flg[DCS_LINES]; /* line flags */ -uint8 dcs_buf[DCS_LINES]; /* line bufffers */ - -extern int32 iosta, stop_inst; -extern int32 tmxr_poll; - -TMLN dcs_ldsc[DCS_LINES] = { {0} }; /* line descriptors */ -TMXR dcs_desc = { DCS_LINES, 0, 0, dcs_ldsc }; /* mux descriptor */ - -t_stat dcsi_svc (UNIT *uptr); -t_stat dcso_svc (UNIT *uptr); -t_stat dcs_reset (DEVICE *dptr); -t_stat dcs_attach (UNIT *uptr, char *cptr); -t_stat dcs_detach (UNIT *uptr); -t_stat dcs_vlines (UNIT *uptr, int32 val, char *cptr, void *desc); -void dcs_reset_ln (int32 ln); -void dcs_scan_next (t_bool unlk); - -/* DCS data structures - - dcs_dev DCS device descriptor - dcs_unit DCS unit descriptor - dcs_reg DCS register list - dcs_mod DCS modifiers list -*/ - -UNIT dcs_unit = { UDATA (&dcsi_svc, UNIT_ATTABLE, 0) }; - -REG dcs_reg[] = { - { BRDATA (BUF, dcs_buf, 8, 8, DCS_LINES) }, - { BRDATA (FLAGS, dcs_flg, 8, 1, DCS_LINES) }, - { FLDATA (SCNF, iosta, IOS_V_DCS) }, - { ORDATA (SCAN, dcs_scan, 5) }, - { ORDATA (SEND, dcs_send, 5) }, - { DRDATA (SBSLVL, dcs_sbs, 4), REG_HRO }, - { NULL } - }; - -MTAB dcs_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL", - &dev_set_sbs, &dev_show_sbs, (void *) &dcs_sbs }, - { MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES", - &dcs_vlines, &tmxr_show_lines, (void *) &dcs_desc }, - { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", - &tmxr_dscln, NULL, (void *) &dcs_desc }, - { UNIT_ATT, UNIT_ATT, "summary", NULL, - NULL, &tmxr_show_summ, (void *) &dcs_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, - NULL, &tmxr_show_cstat, (void *) &dcs_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, - NULL, &tmxr_show_cstat, (void *) &dcs_desc }, - { 0 } - }; - -DEVICE dcs_dev = { - "DCS", &dcs_unit, dcs_reg, dcs_mod, - 1, 10, 31, 1, 8, 8, - &tmxr_ex, &tmxr_dep, &dcs_reset, - NULL, &dcs_attach, &dcs_detach, - NULL, DEV_MUX | DEV_DISABLE | DEV_DIS - }; - -/* DCSL data structures - - dcsl_dev DCSL device descriptor - dcsl_unit DCSL unit descriptor - dcsl_reg DCSL register list - dcsl_mod DCSL modifiers list -*/ - -UNIT dcsl_unit[] = { - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT }, - { UDATA (&dcso_svc, TT_MODE_UC, 0), DCSL_WAIT } - }; - -MTAB dcsl_mod[] = { - { TT_MODE, TT_MODE_UC, "UC", "UC", NULL }, - { TT_MODE, TT_MODE_7B, "7b", "7B", NULL }, - { TT_MODE, TT_MODE_8B, "8b", "8B", NULL }, - { TT_MODE, TT_MODE_7P, "7p", "7P", NULL }, - { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT", - &tmxr_dscln, NULL, &dcs_desc }, - { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG", - &tmxr_set_log, &tmxr_show_log, &dcs_desc }, - { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG", - &tmxr_set_nolog, NULL, &dcs_desc }, - { 0 } - }; - -REG dcsl_reg[] = { - { URDATA (TIME, dcsl_unit[0].wait, 10, 24, 0, - DCS_LINES, REG_NZ + PV_LEFT) }, - { NULL } - }; - -DEVICE dcsl_dev = { - "DCSL", dcsl_unit, dcsl_reg, dcsl_mod, - DCS_LINES, 10, 31, 1, 8, 8, - NULL, NULL, &dcs_reset, - NULL, NULL, NULL, - NULL, DEV_DIS | DEV_MUX - }; - -/* DCS IOT routine */ - -int32 dcs (int32 inst, int32 dev, int32 dat) -{ -int32 pls = (inst >> 6) & 077; - -if (dcs_dev.flags & DEV_DIS) /* disabled? */ - return (stop_inst << IOT_V_REASON) | dat; /* illegal inst */ -if (pls & 020) /* pulse 20? clr IO */ - dat = 0; - -switch (pls & 057) { /* case IR<6,8:11> */ - - case 000: /* RCH */ - dat |= dcs_buf[dcs_scan]; /* return line buf */ - dcs_flg[dcs_scan] = 0; /* clr line flag */ - break; - - case 001: /* RRC */ - dat |= dcs_scan; /* return line num */ - break; - - case 010: /* RCC */ - dat |= dcs_buf[dcs_scan]; /* return line buf */ - dcs_flg[dcs_scan] = 0; /* clr line flag */ - /* fall through */ - case 011: /* RSC */ - dcs_scan_next (TRUE); /* unlock scanner */ - break; - - case 040: /* TCB */ - dcs_buf[dcs_send] = dat & 0377; /* load buffer */ - dcs_flg[dcs_send] = 0; /* clr line flag */ - sim_activate (&dcsl_unit[dcs_send], dcsl_unit[dcs_send].wait); - break; - - case 041: /* SSB */ - dcs_send = dat & DCS_LINE_MASK; /* load line num */ - break; - - case 050: /* TCC */ - dcs_buf[dcs_scan] = dat & 0377; /* load buffer */ - dcs_flg[dcs_scan] = 0; /* clr line flag */ - sim_activate (&dcsl_unit[dcs_scan], dcsl_unit[dcs_scan].wait); - dcs_scan_next (TRUE); /* unlock scanner */ - break; - - default: - return (stop_inst << IOT_V_REASON) | dat; /* illegal inst */ - } /* end case */ - -return dat; -} - -/* Unit service - receive side - - Poll all active lines for input - Poll for new connections -*/ - -t_stat dcsi_svc (UNIT *uptr) -{ -int32 ln, c, out; - -if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ - return SCPE_OK; -if (dcs_dev.flags & DEV_DIS) - return SCPE_OK; -sim_activate (uptr, tmxr_poll); /* continue poll */ -ln = tmxr_poll_conn (&dcs_desc); /* look for connect */ -if (ln >= 0) { /* got one? */ - dcs_ldsc[ln].rcve = 1; /* set rcv enable */ - } -tmxr_poll_rx (&dcs_desc); /* poll for input */ -for (ln = 0; ln < DCS_NUMLIN; ln++) { /* loop thru lines */ - if (dcs_ldsc[ln].conn) { /* connected? */ - if ((c = tmxr_getc_ln (&dcs_ldsc[ln]))) { /* get char */ - if (c & SCPE_BREAK) /* break? */ - c = 0; - else c = sim_tt_inpcvt (c, TT_GET_MODE (dcsl_unit[ln].flags)|TTUF_KSR); - dcs_buf[ln] = c; /* save char */ - dcs_flg[ln] = 1; /* set line flag */ - dcs_scan_next (FALSE); /* kick scanner */ - out = sim_tt_outcvt (c & 0177, TT_GET_MODE (dcsl_unit[ln].flags)); - if (out >= 0) { - tmxr_putc_ln (&dcs_ldsc[ln], out); /* echo char */ - tmxr_poll_tx (&dcs_desc); /* poll xmt */ - } - } - } - else dcs_ldsc[ln].rcve = 0; /* disconnected */ - } /* end for */ -return SCPE_OK; -} - -/* Unit service - transmit side */ - -t_stat dcso_svc (UNIT *uptr) -{ -int32 c; -uint32 ln = uptr - dcsl_unit; /* line # */ - -if (dcs_dev.flags & DEV_DIS) - return SCPE_OK; -if (dcs_ldsc[ln].conn) { /* connected? */ - if (dcs_ldsc[ln].xmte) { /* xmt enabled? */ - c = sim_tt_outcvt (dcs_buf[ln] & 0177, TT_GET_MODE (uptr->flags)); - if (c >= 0) /* output char */ - tmxr_putc_ln (&dcs_ldsc[ln], c); - tmxr_poll_tx (&dcs_desc); /* poll xmt */ - } - else { /* buf full */ - tmxr_poll_tx (&dcs_desc); /* poll xmt */ - sim_activate (uptr, uptr->wait); /* reschedule */ - return SCPE_OK; - } - } -dcs_flg[ln] = 1; /* set line flag */ -dcs_scan_next (FALSE); /* kick scanner */ -return SCPE_OK; -} - -/* Kick scanner */ - -void dcs_scan_next (t_bool unlk) -{ -int32 i; - -if (unlk) /* unlock? */ - iosta &= ~IOS_DCS; -else if (iosta & IOS_DCS) /* no, locked? */ - return; -for (i = 0; i < DCS_LINES; i++) { /* scan flags */ - dcs_scan = (dcs_scan + 1) & DCS_LINE_MASK; /* next flag */ - if (dcs_flg[dcs_scan] != 0) { /* flag set? */ - iosta |= IOS_DCS; /* lock scanner */ - dev_req_int (dcs_sbs); /* request intr */ - return; - } - } -return; -} - -/* Reset routine */ - -t_stat dcs_reset (DEVICE *dptr) -{ -int32 i; - -if (dcs_dev.flags & DEV_DIS) /* master disabled? */ - dcsl_dev.flags = dcsl_dev.flags | DEV_DIS; /* disable lines */ -else dcsl_dev.flags = dcsl_dev.flags & ~DEV_DIS; -if (dcs_unit.flags & UNIT_ATT) /* master att? */ - sim_activate_abs (&dcs_unit, tmxr_poll); /* activate */ -else sim_cancel (&dcs_unit); /* else stop */ -for (i = 0; i < DCS_LINES; i++) /* reset lines */ - dcs_reset_ln (i); -dcs_send = 0; -dcs_scan = 0; -iosta &= ~IOS_DCS; /* clr intr req */ -return SCPE_OK; -} - -/* Attach master unit */ - -t_stat dcs_attach (UNIT *uptr, char *cptr) -{ -t_stat r; - -r = tmxr_attach (&dcs_desc, uptr, cptr); /* attach */ -if (r != SCPE_OK) /* error */ - return r; -sim_activate_abs (uptr, 0); /* start poll at once */ -return SCPE_OK; -} - -/* Detach master unit */ - -t_stat dcs_detach (UNIT *uptr) -{ -int32 i; -t_stat r; - -r = tmxr_detach (&dcs_desc, uptr); /* detach */ -for (i = 0; i < DCS_LINES; i++) /* disable rcv */ - dcs_ldsc[i].rcve = 0; -sim_cancel (uptr); /* stop poll */ -return r; -} - -/* Change number of lines */ - -t_stat dcs_vlines (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 newln, i, t; -t_stat r; - -if (cptr == NULL) - return SCPE_ARG; -newln = get_uint (cptr, 10, DCS_LINES, &r); -if ((r != SCPE_OK) || (newln == DCS_NUMLIN)) - return r; -if (newln == 0) - return SCPE_ARG; -if (newln < DCS_LINES) { - for (i = newln, t = 0; i < DCS_NUMLIN; i++) - t = t | dcs_ldsc[i].conn; - if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE)) - return SCPE_OK; - for (i = newln; i < DCS_NUMLIN; i++) { - if (dcs_ldsc[i].conn) { - tmxr_linemsg (&dcs_ldsc[i], "\r\nOperator disconnected line\r\n"); - tmxr_reset_ln (&dcs_ldsc[i]); /* reset line */ - } - dcsl_unit[i].flags = dcsl_unit[i].flags | UNIT_DIS; - dcs_reset_ln (i); - } - } -else { - for (i = DCS_NUMLIN; i < newln; i++) { - dcsl_unit[i].flags = dcsl_unit[i].flags & ~UNIT_DIS; - dcs_reset_ln (i); - } - } -DCS_NUMLIN = newln; -return SCPE_OK; -} - -/* Reset an individual line */ - -void dcs_reset_ln (int32 ln) -{ -sim_cancel (&dcsl_unit[ln]); -dcs_buf[ln] = 0; -dcs_flg[ln] = 0; -return; -} diff --git a/PDP1/pdp1_defs.h b/PDP1/pdp1_defs.h deleted file mode 100644 index 5313bcee..00000000 --- a/PDP1/pdp1_defs.h +++ /dev/null @@ -1,199 +0,0 @@ -/* pdp1_defs.h: 18b PDP simulator definitions - - Copyright (c) 1993-2010, 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. - - 22-May-10 RMS Added check for 64b definitions - 21-Dec-06 RMS Added 16-channel sequence break support - 22-Jul-05 RMS Fixed definition of CPLS_DPY - 08-Feb-04 PLB Added support for display - 08-Dec-03 RMS Added support for parallel drum - 18-Oct-03 RMS Added DECtape off reel message - 22-Jul-03 RMS Updated for "hardware" RIM loader - Revised to detect I/O wait hang - 05-Dec-02 RMS Added IOT skip support (required by drum) - 14-Apr-99 RMS Changed t_addr to unsigned - - The PDP-1 was Digital's first computer. The system design evolved during - its life, and as a result, specifications are sketchy or contradictory. - This simulator is based on the 1962 maintenance manual. - - This simulator implements the following options: - - Automatic multiply/divide Type 10 - Memory extension control Type 15 - Parallel drum Type 23 - Serial drum Type 24 - Graphic display Type 30 - Line printer control Type 62 - Microtape (DECtape) control Type 550 -*/ - -#ifndef PDP1_DEFS_H_ -#define PDP1_DEFS_H_ 0 - -#include "sim_defs.h" - -#if defined(USE_INT64) || defined(USE_ADDR64) -#error "PDP-1 does not support 64b values!" -#endif - -/* Simulator stop codes */ - -#define STOP_RSRV 1 /* must be 1 */ -#define STOP_HALT 2 /* HALT */ -#define STOP_IBKPT 3 /* breakpoint */ -#define STOP_XCT 4 /* nested XCT's */ -#define STOP_IND 5 /* nested indirects */ -#define STOP_WAIT 6 /* IO wait hang */ -#define STOP_DTOFF 7 /* DECtape off reel */ -#define ERR_RMV 10 /* restrict mode viol */ - -/* Memory */ - -#define ASIZE 16 /* address bits */ -#define MAXMEMSIZE (1u << ASIZE) /* max mem size */ -#define AMASK (MAXMEMSIZE - 1) /* address mask */ -#define MEMSIZE (cpu_unit.capac) /* actual memory size */ -#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) - -/* Architectural constants */ - -#define SIGN 0400000 /* sign */ -#define DMASK 0777777 /* data mask */ -#define DAMASK 0007777 /* direct addr */ -#define EPCMASK (AMASK & ~DAMASK) /* extended addr */ -#define IA 0010000 /* indirect flag */ -#define IO_WAIT 0010000 /* I/O sync wait */ -#define IO_CPLS 0004000 /* completion pulse */ -#define OP_DAC 0240000 /* DAC */ -#define OP_DIO 0320000 /* DIO */ -#define OP_JMP 0600000 /* JMP */ -#define GEN_CPLS(x) (((x) ^ ((x) << 1)) & IO_WAIT) /* completion pulse? */ - -/* Program flags/sense switches */ - -#define PF_V_L 7 -#define PF_V_RNG 6 -#define PF_L (1u << PF_V_L) -#define PF_RNG (1u << PF_V_RNG) -#define PF_SS_1 0040 -#define PF_SS_2 0020 -#define PF_SS_3 0010 -#define PF_SS_4 0004 -#define PF_SS_5 0002 -#define PF_SS_6 0001 -#define PF_VR_ALL 0377 -#define PF_SS_ALL 0077 - -/* Restict mode */ - -#define RTB_IOT 0400000 -#define RTB_ILL 0200000 -#define RTB_HLT 0100000 -#define RTB_DBK 0040000 -#define RTB_CHR 0020000 -#define RTB_MB_MASK 0017777 - -#define RM45_V_BNK 14 -#define RM45_M_BNK 003 -#define RM48_V_BNK 12 -#define RM48_M_BNK 017 - -#define RN45_SIZE 4 - -/* IOT subroutine return codes */ - -#define IOT_V_SKP 18 /* skip */ -#define IOT_SKP (1 << IOT_V_SKP) -#define IOT_V_REASON (IOT_V_SKP + 1) /* reason */ -#define IOT_REASON (1 << IOT_V_REASON) -#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */ - -/* I/O status flags */ - -#define IOS_V_LPN 17 /* light pen */ -#define IOS_V_PTR 16 /* paper tape reader */ -#define IOS_V_TTO 15 /* typewriter out */ -#define IOS_V_TTI 14 /* typewriter in */ -#define IOS_V_PTP 13 /* paper tape punch */ -#define IOS_V_DRM 12 /* drum */ -#define IOS_V_SQB 11 /* sequence break */ -#define IOS_V_PNT 3 /* print done */ -#define IOS_V_SPC 2 /* space done */ -#define IOS_V_DCS 1 /* data comm sys */ -#define IOS_V_DRP 0 /* parallel drum busy */ - -#define IOS_LPN (1 << IOS_V_LPN) -#define IOS_PTR (1 << IOS_V_PTR) -#define IOS_TTO (1 << IOS_V_TTO) -#define IOS_TTI (1 << IOS_V_TTI) -#define IOS_PTP (1 << IOS_V_PTP) -#define IOS_DRM (1 << IOS_V_DRM) -#define IOS_SQB (1 << IOS_V_SQB) -#define IOS_PNT (1 << IOS_V_PNT) -#define IOS_SPC (1 << IOS_V_SPC) -#define IOS_DCS (1 << IOS_V_DCS) -#define IOS_DRP (1 << IOS_V_DRP) - -/* Completion pulses */ - -#define CPLS_V_PTR 5 -#define CPLS_V_PTP 4 -#define CPLS_V_TTO 3 -#define CPLS_V_LPT 2 -#define CPLS_V_DPY 1 -#define CPLS_PTR (1 << CPLS_V_PTR) -#define CPLS_PTP (1 << CPLS_V_PTP) -#define CPLS_TTO (1 << CPLS_V_TTO) -#define CPLS_LPT (1 << CPLS_V_LPT) -#define CPLS_DPY (1 << CPLS_V_DPY) - -/* One channel sequence break */ - -#define SB_V_IP 0 /* in progress */ -#define SB_V_RQ 1 /* request */ -#define SB_V_ON 2 /* enabled */ - -#define SB_IP (1 << SB_V_IP) -#define SB_RQ (1 << SB_V_RQ) -#define SB_ON (1 << SB_V_ON) - -/* 16 channel sequence break */ - -#define SBS_LVLS 16 /* num levels */ -#define SBS_LVL_MASK (SBS_LVLS - 1) -#define SBS_LVL_RMV 14 /* restrict level */ -#define SBS_MASK(x) (1u << (SBS_LVLS - 1 - (x))) /* level to mask */ - -/* Timers */ - -#define TMR_CLK 0 - -/* Device routines */ - -t_stat dev_req_int (int32 lvl); -t_stat dev_set_sbs (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat dev_show_sbs (FILE *st, UNIT *uptr, int32 val, void *desc); - -#endif diff --git a/PDP1/pdp1_diag.txt b/PDP1/pdp1_diag.txt deleted file mode 100644 index 3b5d6db0..00000000 --- a/PDP1/pdp1_diag.txt +++ /dev/null @@ -1,53 +0,0 @@ -MAINDEC 1 Instruction Test - -sim> att -e ptr digital-1-12-m-rim.bin -sim> boot ptr - -HALT instruction, PC: 000002 (JMP 3000) -sim> c - -(Test runs until interrupted unless there are errors) - -^E -Simulation stopped, PC: 000007 (SZS2 I) -sim> d ss 77 -sim> run 32 - -(Test runs until interrupted unless there are errors) - -^E -Simulation stopped, PC: 000032 (SZS1) -sim> d tw 777777 -sim> d ss 0 -sim> run 7772 - -Undefined instruction, PC: 000001 (SZS1) -sim> ex ac,io,pf -AC: 000777 -IO: 777000 -PF: 77 - -(These are the expected final values for the diagnostic) - - -MAINDEC 4 Multiply/Divide Test - -sim> att -e ptr maindec-4_4-16-68.bin -sim> break 0 -sim> boot ptr - -Breakpoint, PC: 000000 (JMP 532) -sim> set cpu mdv -sim> c - -(Test runs until interrupted unless there are errors) -^E - -Simulation stopped, PC: ... -sim> set cpu nomdv -sim> run 1 - -(Test runs until interrupted unless there are errors) -^E - -Simulation stopped, PC: ... diff --git a/PDP1/pdp1_drm.c b/PDP1/pdp1_drm.c deleted file mode 100644 index 1b9104ac..00000000 --- a/PDP1/pdp1_drm.c +++ /dev/null @@ -1,372 +0,0 @@ -/* pdp1_drm.c: PDP-1 drum simulator - - Copyright (c) 1993-2013, 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. - - drp Type 23 parallel drum - drm Type 24 serial drum - - 03-Sep-13 RMS Added explicit void * cast - 21-Dec-06 RMS Added 16-chan SBS support - 08-Dec-03 RMS Added parallel drum support - Fixed bug in DBL/DCN decoding - 26-Oct-03 RMS Cleaned up buffer copy code - 23-Jul-03 RMS Fixed incorrect logical, missing activate - 05-Dec-02 RMS Cloned from pdp18b_drm.c -*/ - -#include "pdp1_defs.h" -#include - -/* Serial drum constants */ - -#define DRM_NUMWDS 256 /* words/sector */ -#define DRM_NUMSC 2 /* sectors/track */ -#define DRM_NUMTR 256 /* tracks/drum */ -#define DRM_NUMWDT (DRM_NUMWDS * DRM_NUMSC) /* words/track */ -#define DRM_SIZE (DRM_NUMTR * DRM_NUMWDT) /* words/drum */ -#define DRM_SMASK ((DRM_NUMTR * DRM_NUMSC) - 1) /* sector mask */ - -/* Parallel drum constants */ - -#define DRP_NUMWDT 4096 /* words/track */ -#define DRP_NUMTK 32 /* tracks/drum */ -#define DRP_SIZE (DRP_NUMWDT * DRP_NUMTK) /* words/drum */ -#define DRP_V_RWE 17 /* read/write enable */ -#define DRP_V_FLD 12 /* drum field */ -#define DRP_M_FLD 037 -#define DRP_TAMASK 07777 /* track address */ -#define DRP_WCMASK 07777 /* word count */ -#define DRP_MAINCM 07777 /* mem addr incr */ -#define DRP_GETRWE(x) (((x) >> DRP_V_RWE) & 1) -#define DRP_GETRWF(x) (((x) >> DRP_V_FLD) & DRP_M_FLD) - -/* Parameters in the unit descriptor */ - -#define FUNC u4 /* function */ -#define DRM_READ 000 /* read */ -#define DRM_WRITE 010 /* write */ -#define DRP_RW 000 /* read/write */ -#define DRP_BRK 001 /* break on address */ - -#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \ - ((double) DRM_NUMWDT))) - -extern int32 M[]; -extern int32 iosta; -extern int32 stop_inst; -extern UNIT cpu_unit; - -/* Serial drum variables */ - -uint32 drm_da = 0; /* track address */ -uint32 drm_ma = 0; /* memory address */ -uint32 drm_err = 0; /* error flag */ -uint32 drm_wlk = 0; /* write lock */ -int32 drm_time = 4; /* inter-word time */ -int32 drm_sbs = 0; /* SBS level */ -int32 drm_stopioe = 1; /* stop on error */ - -/* Parallel drum variables */ - -uint32 drp_rde = 0; /* read enable */ -uint32 drp_wre = 0; /* write enable */ -uint32 drp_rdf = 0; /* read field */ -uint32 drp_wrf = 0; /* write field */ -uint32 drp_ta = 0; /* track address */ -uint32 drp_wc = 0; /* word count */ -uint32 drp_ma = 0; /* memory address */ -uint32 drp_err = 0; /* error */ -int32 drp_time = 2; /* inter-word time */ -int32 drp_stopioe = 1; /* stop on error */ - -/* Forward declarations */ - -t_stat drm_svc (UNIT *uptr); -t_stat drm_reset (DEVICE *dptr); -t_stat drp_svc (UNIT *uptr); -t_stat drp_reset (DEVICE *dptr); - -/* DRM data structures - - drm_dev DRM device descriptor - drm_unit DRM unit descriptor - drm_reg DRM register list -*/ - -UNIT drm_unit = { - UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, - DRM_SIZE) - }; - -REG drm_reg[] = { - { ORDATA (DA, drm_da, 9) }, - { ORDATA (MA, drm_ma, 16) }, - { FLDATA (DONE, iosta, IOS_V_DRM) }, - { FLDATA (ERR, drm_err, 0) }, - { ORDATA (WLK, drm_wlk, 32) }, - { DRDATA (TIME, drm_time, 24), REG_NZ + PV_LEFT }, - { DRDATA (SBSLVL, drm_sbs, 4), REG_HRO }, - { FLDATA (STOP_IOE, drm_stopioe, 0) }, - { NULL } - }; - -MTAB drm_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "APILVL", "APILVL", - &dev_set_sbs, &dev_show_sbs, (void *) &drm_sbs }, - { 0 } - }; - -DEVICE drm_dev = { - "DRM", &drm_unit, drm_reg, drm_mod, - 1, 8, 20, 1, 8, 18, - NULL, NULL, &drm_reset, - NULL, NULL, NULL, - NULL, DEV_DISABLE - }; - -/* DRP data structures - - drp_dev DRP device descriptor - drp_unit DRP unit descriptor - drp_reg DRP register list -*/ - -UNIT drp_unit = { - UDATA (&drp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, - DRM_SIZE) - }; - -REG drp_reg[] = { - { ORDATA (TA, drp_ta, 12) }, - { ORDATA (RDF, drp_rdf, 5) }, - { FLDATA (RDE, drp_rde, 0) }, - { FLDATA (WRF, drp_wrf, 5) }, - { FLDATA (WRE, drp_wre, 0) }, - { ORDATA (MA, drp_ma, 16) }, - { ORDATA (WC, drp_wc, 12) }, - { FLDATA (BUSY, iosta, IOS_V_DRP) }, - { FLDATA (ERR, drp_err, 0) }, - { DRDATA (TIME, drp_time, 24), REG_NZ + PV_LEFT }, - { FLDATA (STOP_IOE, drp_stopioe, 0) }, - { DRDATA (SBSLVL, drm_sbs, 4), REG_HRO }, - { NULL } - }; - -DEVICE drp_dev = { - "DRP", &drp_unit, drp_reg, NULL, - 1, 8, 20, 1, 8, 18, - NULL, NULL, &drp_reset, - NULL, NULL, NULL, - NULL, DEV_DISABLE | DEV_DIS - }; - -/* IOT routines */ - -int32 drm (int32 IR, int32 dev, int32 dat) -{ -int32 t; -int32 pulse = (IR >> 6) & 037; - -if ((drm_dev.flags & DEV_DIS) == 0) { /* serial enabled? */ - if ((pulse != 001) && (pulse != 011)) /* invalid pulse? */ - return (stop_inst << IOT_V_REASON) | dat; /* stop if requested */ - switch (dev) { /* switch on device */ - - case 061: /* DWR, DRD */ - drm_ma = dat & AMASK; /* load mem addr */ - drm_unit.FUNC = pulse & DRM_WRITE; /* save function */ - break; - - case 062: /* DBL, DCN */ - if ((pulse & 010) == 0) /* DBL? */ - drm_da = dat & DRM_SMASK; /* load sector # */ - iosta = iosta & ~IOS_DRM; /* clear flags */ - drm_err = 0; - t = ((drm_da % DRM_NUMSC) * DRM_NUMWDS) - GET_POS (drm_time); - if (t <= 0) /* wrap around? */ - t = t + DRM_NUMWDT; - sim_activate (&drm_unit, t); /* start operation */ - break; - - case 063: /* DTD */ - if (pulse == 011) - return (stop_inst << IOT_V_REASON) | dat; - if (iosta & IOS_DRM) /* skip if done */ - return (dat | IOT_SKP); - break; - - case 064: /* DSE, DSP */ - if ((drm_err == 0) || (pulse & 010)) /* no error, par test? */ - return (dat | IOT_SKP); - } /* end case */ - - return dat; - } /* end if serial */ - -if ((drp_dev.flags & DEV_DIS) == 0) { /* parallel enabled? */ - switch (dev) { /* switch on device */ - - case 061: /* DIA, DBA */ - drp_err = 0; /* clear error */ - iosta = iosta & ~IOS_DRP; /* not busy */ - drp_rde = DRP_GETRWE (dat); /* set read enable */ - drp_rdf = DRP_GETRWF (dat); /* set read field */ - drp_ta = dat & DRP_TAMASK; /* set track addr */ - if (IR & 02000) { /* DBA? */ - t = drp_ta - GET_POS (drp_time); /* delta words */ - if (t <= 0) /* wrap around? */ - t = t + DRP_NUMWDT; - sim_activate (&drp_unit, t); /* start operation */ - drp_unit.FUNC = DRP_BRK; /* mark as break */ - } - else drp_unit.FUNC = DRP_RW; /* no, read/write */ - break; - - case 062: /* DWC, DRA */ - if (IR & 02000) dat = GET_POS (drp_time) | /* DRA, get position */ - (drp_err? 0400000: 0); - else { /* DWC */ - drp_wre = DRP_GETRWE (dat); /* set write enable */ - drp_wrf = DRP_GETRWF (dat); /* set write field */ - drp_wc = dat & DRP_WCMASK; /* set word count */ - } - break; - - case 063: /* DCL */ - drp_ma = dat & AMASK; /* set mem address */ - t = drp_ta - GET_POS (drp_time); /* delta words */ - if (t <= 0) /* wrap around? */ - t = t + DRP_NUMWDT; - sim_activate (&drp_unit, t); /* start operation */ - iosta = iosta | IOS_DRP; /* set busy */ - break; - - case 064: /* not assigned */ - return (stop_inst << IOT_V_REASON) | dat; /* stop if requested */ - } /* end case */ - - return dat; - } /* end if parallel */ - -return (stop_inst << IOT_V_REASON) | dat; /* stop if requested */ -} - -/* Serial unit service - this code assumes the entire drum is buffered */ - -t_stat drm_svc (UNIT *uptr) -{ -uint32 i, da; -uint32 *fbuf = (uint32 *) uptr->filebuf; - -if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */ - drm_err = 1; /* set error */ - iosta = iosta | IOS_DRM; /* set done */ - dev_req_int (drm_sbs); /* req intr */ - return IORETURN (drm_stopioe, SCPE_UNATT); - } - -da = drm_da * DRM_NUMWDS; /* compute dev addr */ -for (i = 0; i < DRM_NUMWDS; i++, da++) { /* do transfer */ - if (uptr->FUNC == DRM_READ) { /* read? */ - if (MEM_ADDR_OK (drm_ma)) /* if !nxm */ - M[drm_ma] = fbuf[da]; /* read word */ - } - else { /* write */ - if ((drm_wlk >> (drm_da >> 4)) & 1) - drm_err = 1; - else { /* not locked */ - fbuf[da] = M[drm_ma]; /* write word */ - if (da >= uptr->hwmark) - uptr->hwmark = da + 1; - } - } - drm_ma = (drm_ma + 1) & AMASK; /* incr mem addr */ - } -drm_da = (drm_da + 1) & DRM_SMASK; /* incr dev addr */ -iosta = iosta | IOS_DRM; /* set done */ -dev_req_int (drm_sbs); /* req intr */ -return SCPE_OK; -} - -/* Reset routine */ - -t_stat drm_reset (DEVICE *dptr) -{ -if ((drm_dev.flags & DEV_DIS) == 0) - drp_dev.flags = drp_dev.flags | DEV_DIS; -drm_da = drm_ma = drm_err = 0; -iosta = iosta & ~IOS_DRM; -sim_cancel (&drm_unit); -drm_unit.FUNC = 0; -return SCPE_OK; -} - -/* Parallel unit service - this code assumes the entire drum is buffered */ - -t_stat drp_svc (UNIT *uptr) -{ -uint32 i, lim; -uint32 *fbuf = uptr->filebuf; - -if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */ - drp_err = 1; /* set error */ - iosta = iosta & ~IOS_DRP; /* clear busy */ - if (uptr->FUNC) /* req intr */ - dev_req_int (drm_sbs); - return IORETURN (drp_stopioe, SCPE_UNATT); - } - -if (uptr->FUNC == DRP_RW) { /* read/write? */ - lim = drp_wc? drp_wc: DRP_TAMASK + 1; /* eff word count */ - for (i = 0; i < lim; i++) { /* do transfer */ - if (drp_wre) /* write enabled? */ - fbuf[(drp_wrf << DRP_V_FLD) | drp_ta] = M[drp_ma]; - if (drp_rde && MEM_ADDR_OK (drp_ma)) /* read enabled? */ - M[drp_ma] = fbuf[(drp_rdf << DRP_V_FLD) | drp_ta]; - drp_ta = (drp_ta + 1) & DRP_TAMASK; /* incr track addr */ - drp_ma = ((drp_ma & ~DRP_MAINCM) | ((drp_ma + 1) & DRP_MAINCM)); - } /* end for */ - } /* end if */ -iosta = iosta & ~IOS_DRP; /* clear busy */ -if (uptr->FUNC) /* req intr */ - dev_req_int (drm_sbs); -return SCPE_OK; -} - -/* Reset routine */ - -t_stat drp_reset (DEVICE *dptr) -{ -if ((drp_dev.flags & DEV_DIS) == 0) - drm_dev.flags = drm_dev.flags | DEV_DIS; -drp_ta = 0; -drp_rde = drp_rdf = drp_wre = drp_wrf = 0; -drp_err = 0; -drp_ma = 0; -drp_wc = 0; -iosta = iosta & ~IOS_DRP; -sim_cancel (&drp_unit); -drp_unit.FUNC = 0; -return SCPE_OK; -} diff --git a/PDP1/pdp1_dt.c b/PDP1/pdp1_dt.c deleted file mode 100644 index 05f67976..00000000 --- a/PDP1/pdp1_dt.c +++ /dev/null @@ -1,1127 +0,0 @@ -/* pdp1_dt.c: 18b DECtape simulator - - Copyright (c) 1993-2017, Robert M Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - dt Type 550/555 DECtape - - 15-Mar-17 RMS Fixed dt_seterr to clear successor states - 09-Mar-17 RMS Fixed dt_seterr to handle nx unit select (COVERITY) - 28-Mar-15 RMS Revised to use sim_printf - 21-Dec-06 RMS Added 16-channel SBS support - 23-Jun-06 RMS Fixed conflict in ATTACH switches - Revised header format - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 25-Jan-04 RMS Revised for device debug support - 09-Jan-04 RMS Changed sim_fsize calling sequence, added STOP_OFFR - 26-Oct-03 RMS Cleaned up buffer copy code - 18-Oct-03 RMS Added DECtape off reel message, simplified timing - 25-Apr-03 RMS Revised for extended file support - 14-Mar-03 RMS Fixed variable size interaction with save/restore - 17-Oct-02 RMS Fixed bug in end of reel logic - 06-Oct-02 RMS Added device disable support - 13-Aug-02 RMS Cloned from pdp18b_dt.c - - 18b DECtapes are represented in memory by fixed length buffer of 32b words. - Three file formats are supported: - - 18b/36b 256 words per block [256 x 18b] - 16b 256 words per block [256 x 16b] - 12b 129 words per block [129 x 12b] - - When a 16b or 12b DECtape file is read in, it is converted to 18b/36b format. - - DECtape motion is measured in 3b lines. Time between lines is 33.33us. - Tape density is nominally 300 lines per inch. The format of a DECtape (as - taken from the TD8E formatter) is: - - reverse end zone 8192 reverse end zone codes ~ 10 feet - reverse buffer 200 interblock codes - block 0 - : - block n - forward buffer 200 interblock codes - forward end zone 8192 forward end zone codes ~ 10 feet - - A block consists of five 18b header words, a tape-specific number of data - words, and five 18b trailer words. All systems except the PDP-8 use a - standard block length of 256 words; the PDP-8 uses a standard block length - of 86 words (x 18b = 129 words x 12b). - - Because a DECtape file only contains data, the simulator cannot support - write timing and mark track and can only do a limited implementation - of read all and write all. Read all assumes that the tape has been - conventionally written forward: - - header word 0 0 - header word 1 block number (for forward reads) - header words 2,3 0 - header word 4 checksum (for reverse reads) - : - trailer word 4 checksum (for forward reads) - trailer words 3,2 0 - trailer word 1 block number (for reverse reads) - trailer word 0 0 - - Write all writes only the data words and dumps the interblock words in the - bit bucket. - - The Type 550 controller has a 4b unit select field, for units 1-8. The code - assumes that the GETUNIT macro returns a unit number in the range of 0-7, - with 8 represented as 0, and an invalid unit as -1. -*/ - -#include "pdp1_defs.h" - -#define DT_NUMDR 8 /* #drives */ -#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_V_8FMT (UNIT_V_UF + 1) /* 12b format */ -#define UNIT_V_11FMT (UNIT_V_UF + 2) /* 16b format */ -#define UNIT_WLK (1 << UNIT_V_WLK) -#define UNIT_8FMT (1 << UNIT_V_8FMT) -#define UNIT_11FMT (1 << UNIT_V_11FMT) -#define STATE u3 /* unit state */ -#define LASTT u4 /* last time update */ -#define DT_WC 030 /* word count */ -#define DT_CA 031 /* current addr */ -#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ - -/* System independent DECtape constants */ - -#define DT_LPERMC 6 /* lines per mark track */ -#define DT_BLKWD 1 /* blk no word in h/t */ -#define DT_CSMWD 4 /* checksum word in h/t */ -#define DT_HTWRD 5 /* header/trailer words */ -#define DT_EZLIN (8192 * DT_LPERMC) /* end zone length */ -#define DT_BFLIN (200 * DT_LPERMC) /* buffer length */ -#define DT_BLKLN (DT_BLKWD * DT_LPERMC) /* blk no line in h/t */ -#define DT_CSMLN (DT_CSMWD * DT_LPERMC) /* csum line in h/t */ -#define DT_HTLIN (DT_HTWRD * DT_LPERMC) /* header/trailer lines */ - -/* 16b, 18b, 36b DECtape constants */ - -#define D18_WSIZE 6 /* word size in lines */ -#define D18_BSIZE 256 /* block size in 18b */ -#define D18_TSIZE 578 /* tape size */ -#define D18_LPERB (DT_HTLIN + (D18_BSIZE * DT_WSIZE) + DT_HTLIN) -#define D18_FWDEZ (DT_EZLIN + (D18_LPERB * D18_TSIZE)) -#define D18_CAPAC (D18_TSIZE * D18_BSIZE) /* tape capacity */ -#define D11_FILSIZ (D18_CAPAC * sizeof (int16)) - -/* 12b DECtape constants */ - -#define D8_WSIZE 4 /* word size in lines */ -#define D8_BSIZE 86 /* block size in 18b */ -#define D8_TSIZE 1474 /* tape size */ -#define D8_LPERB (DT_HTLIN + (D8_BSIZE * DT_WSIZE) + DT_HTLIN) -#define D8_FWDEZ (DT_EZLIN + (D8_LPERB * D8_TSIZE)) -#define D8_CAPAC (D8_TSIZE * D8_BSIZE) /* tape capacity */ - -#define D8_NBSIZE ((D8_BSIZE * D18_WSIZE) / D8_WSIZE) -#define D8_FILSIZ (D8_NBSIZE * D8_TSIZE * sizeof (int16)) - -/* This controller */ - -#define DT_CAPAC D18_CAPAC /* default */ -#define DT_WSIZE D18_WSIZE - -/* Calculated constants, per unit */ - -#define DTU_BSIZE(u) (((u)->flags & UNIT_8FMT)? D8_BSIZE: D18_BSIZE) -#define DTU_TSIZE(u) (((u)->flags & UNIT_8FMT)? D8_TSIZE: D18_TSIZE) -#define DTU_LPERB(u) (((u)->flags & UNIT_8FMT)? D8_LPERB: D18_LPERB) -#define DTU_FWDEZ(u) (((u)->flags & UNIT_8FMT)? D8_FWDEZ: D18_FWDEZ) -#define DTU_CAPAC(u) (((u)->flags & UNIT_8FMT)? D8_CAPAC: D18_CAPAC) - -#define DT_LIN2BL(p,u) (((p) - DT_EZLIN) / DTU_LPERB (u)) -#define DT_LIN2OF(p,u) (((p) - DT_EZLIN) % DTU_LPERB (u)) -#define DT_LIN2WD(p,u) ((DT_LIN2OF (p,u) - DT_HTLIN) / DT_WSIZE) -#define DT_BLK2LN(p,u) (((p) * DTU_LPERB (u)) + DT_EZLIN) -#define DT_QREZ(u) (((u)->pos) < DT_EZLIN) -#define DT_QFEZ(u) (((u)->pos) >= ((uint32) DTU_FWDEZ (u))) -#define DT_QEZ(u) (DT_QREZ (u) || DT_QFEZ (u)) - -/* Status register A */ - -#define DTA_V_UNIT 12 /* unit select */ -#define DTA_M_UNIT 017 -#define DTA_UNIT (DTA_M_UNIT << DTA_V_UNIT) -#define DTA_V_MOT 4 /* motion */ -#define DTA_M_MOT 03 -#define DTA_V_FNC 0 /* function */ -#define DTA_M_FNC 07 -#define FNC_MOVE 00 /* move */ -#define FNC_SRCH 01 /* search */ -#define FNC_READ 02 /* read */ -#define FNC_WRIT 03 /* write */ -#define FNC_RALL 05 /* read all */ -#define FNC_WALL 06 /* write all */ -#define FNC_WMRK 07 /* write timing */ -#define DTA_STSTP (1u << (DTA_V_MOT + 1)) -#define DTA_FWDRV (1u << DTA_V_MOT) -#define DTA_MODE 0 /* not implemented */ -#define DTA_RW 077 -#define DTA_GETUNIT(x) map_unit[(((x) >> DTA_V_UNIT) & DTA_M_UNIT)] -#define DT_UPDINT if (dtsb & (DTB_DTF | DTB_BEF | DTB_ERF)) \ - dev_req_int (dt_sbs); - -#define DTA_GETMOT(x) (((x) >> DTA_V_MOT) & DTA_M_MOT) -#define DTA_GETFNC(x) (((x) >> DTA_V_FNC) & DTA_M_FNC) - -/* Status register B */ - -#define DTB_V_DTF 17 /* data flag */ -#define DTB_V_BEF 16 /* block end flag */ -#define DTB_V_ERF 15 /* error flag */ -#define DTB_V_END 14 /* end of tape */ -#define DTB_V_TIM 13 /* timing err */ -#define DTB_V_REV 12 /* reverse */ -#define DTB_V_GO 11 /* go */ -#define DTB_V_MRK 10 /* mark trk err */ -#define DTB_V_SEL 9 /* select err */ -#define DTB_DTF (1u << DTB_V_DTF) -#define DTB_BEF (1u << DTB_V_BEF) -#define DTB_ERF (1u << DTB_V_ERF) -#define DTB_END (1u << DTB_V_END) -#define DTB_TIM (1u << DTB_V_TIM) -#define DTB_REV (1u << DTB_V_REV) -#define DTB_GO (1u << DTB_V_GO) -#define DTB_MRK (1u << DTB_V_MRK) -#define DTB_SEL (1u << DTB_V_SEL) -#define DTB_ALLERR (DTB_END | DTB_TIM | DTB_MRK | DTB_SEL) - -/* DECtape state */ - -#define DTS_V_MOT 3 /* motion */ -#define DTS_M_MOT 07 -#define DTS_STOP 0 /* stopped */ -#define DTS_DECF 2 /* decel, fwd */ -#define DTS_DECR 3 /* decel, rev */ -#define DTS_ACCF 4 /* accel, fwd */ -#define DTS_ACCR 5 /* accel, rev */ -#define DTS_ATSF 6 /* @speed, fwd */ -#define DTS_ATSR 7 /* @speed, rev */ -#define DTS_DIR 01 /* dir mask */ -#define DTS_V_FNC 0 /* function */ -#define DTS_M_FNC 07 -#define DTS_OFR 7 /* "off reel" */ -#define DTS_GETMOT(x) (((x) >> DTS_V_MOT) & DTS_M_MOT) -#define DTS_GETFNC(x) (((x) >> DTS_V_FNC) & DTS_M_FNC) -#define DTS_V_2ND 6 /* next state */ -#define DTS_V_3RD (DTS_V_2ND + DTS_V_2ND) /* next next */ -#define DTS_STA(y,z) (((y) << DTS_V_MOT) | ((z) << DTS_V_FNC)) -#define DTS_SETSTA(y,z) uptr->STATE = DTS_STA (y, z) -#define DTS_SET2ND(y,z) uptr->STATE = (uptr->STATE & 077) | \ - ((DTS_STA (y, z)) << DTS_V_2ND) -#define DTS_SET3RD(y,z) uptr->STATE = (uptr->STATE & 07777) | \ - ((DTS_STA (y, z)) << DTS_V_3RD) -#define DTS_NXTSTA(x) (x >> DTS_V_2ND) - -/* Operation substates */ - -#define DTO_WCO 1 /* wc overflow */ -#define DTO_SOB 2 /* start of block */ - -/* Logging */ - -#define LOG_MS 001 /* move, search */ -#define LOG_RW 002 /* read write */ -#define LOG_BL 004 /* block # lblk */ - -#define ABS(x) (((x) < 0)? (-(x)): (x)) - -extern int32 M[]; -extern int32 stop_inst; -extern UNIT cpu_unit; - -int32 dtsa = 0; /* status A */ -int32 dtsb = 0; /* status B */ -int32 dtdb = 0; /* data buffer */ -int32 dt_sbs = 0; /* SBS level */ -int32 dt_ltime = 12; /* interline time */ -int32 dt_dctime = 40000; /* decel time */ -int32 dt_substate = 0; -int32 dt_logblk = 0; -int32 dt_stopoffr = 0; -static const int32 map_unit[16] = { /* Type 550 unit map */ - -1, 1, 2, 3, 4, 5, 6, 7, - 0, -1, -1, -1, -1, -1, -1, -1 - }; - -t_stat dt_svc (UNIT *uptr); -t_stat dt_reset (DEVICE *dptr); -t_stat dt_attach (UNIT *uptr, char *cptr); -t_stat dt_detach (UNIT *uptr); -void dt_deselect (int32 oldf); -void dt_newsa (int32 newf); -void dt_newfnc (UNIT *uptr, int32 newsta); -t_bool dt_setpos (UNIT *uptr); -void dt_schedez (UNIT *uptr, int32 dir); -void dt_seterr (UNIT *uptr, int32 e); -int32 dt_comobv (int32 val); -int32 dt_csum (UNIT *uptr, int32 blk); -int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos); - -/* DT data structures - - dt_dev DT device descriptor - dt_unit DT unit list - dt_reg DT register list - dt_mod DT modifier list -*/ - -UNIT dt_unit[] = { - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, DT_CAPAC) } - }; - -REG dt_reg[] = { - { ORDATA (DTSA, dtsa, 18) }, - { ORDATA (DTSB, dtsb, 18) }, - { ORDATA (DTDB, dtdb, 18) }, - { FLDATA (DTF, dtsb, DTB_V_DTF) }, - { FLDATA (BEF, dtsb, DTB_V_BEF) }, - { FLDATA (ERF, dtsb, DTB_V_ERF) }, - { DRDATA (LTIME, dt_ltime, 31), REG_NZ }, - { DRDATA (DCTIME, dt_dctime, 31), REG_NZ }, - { ORDATA (SUBSTATE, dt_substate, 2) }, - { DRDATA (LBLK, dt_logblk, 12), REG_HIDDEN }, - { URDATA (POS, dt_unit[0].pos, 10, T_ADDR_W, 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) }, - { FLDATA (STOP_OFFR, dt_stopoffr, 0) }, - { DRDATA (SBSLVL, dt_sbs, 4), REG_HRO }, - { NULL } - }; - -MTAB dt_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL", - &dev_set_sbs, &dev_show_sbs, (void *) &dt_sbs }, - { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, - { UNIT_8FMT + UNIT_11FMT, 0, "18b", NULL, NULL }, - { UNIT_8FMT + UNIT_11FMT, UNIT_8FMT, "12b", NULL, NULL }, - { UNIT_8FMT + UNIT_11FMT, UNIT_11FMT, "16b", NULL, NULL }, - { 0 } - }; - -DEBTAB dt_deb[] = { - { "MOTION", LOG_MS }, - { "DATA", LOG_RW }, - { "BLOCK", LOG_BL }, - { NULL, 0 } - }; - -DEVICE dt_dev = { - "DT", dt_unit, dt_reg, dt_mod, - DT_NUMDR, 8, 24, 1, 8, 18, - NULL, NULL, &dt_reset, - NULL, &dt_attach, &dt_detach, - NULL, DEV_DISABLE | DEV_DEBUG, 0, - dt_deb, NULL, NULL - }; - -/* IOT routine */ - -int32 dt (int32 IR, int32 dev, int32 dat) -{ -int32 pulse = (IR >> 6) & 037; -int32 fnc, mot, unum; -UNIT *uptr = NULL; - -if (dt_dev.flags & DEV_DIS) /* disabled? */ - return (stop_inst << IOT_V_REASON) | dat; /* stop if requested */ -unum = DTA_GETUNIT (dtsa); /* get unit no */ -if (unum >= 0) /* get unit */ - uptr = dt_dev.units + unum; - -if (pulse == 003) { /* MSE */ - if ((dtsa ^ dat) & DTA_UNIT) /* new unit? */ - dt_deselect (dtsa); - dtsa = (dtsa & ~DTA_UNIT) | (dat & DTA_UNIT); - dtsb = dtsb & ~(DTB_DTF | DTB_BEF | DTB_ERF | DTB_ALLERR); - } -if (pulse == 004) { /* MLC */ - dtsa = (dtsa & ~DTA_RW) | (dat & DTA_RW); /* load dtsa */ - dtsb = dtsb & ~(DTB_DTF | DTB_BEF | DTB_ERF | DTB_ALLERR); - fnc = DTA_GETFNC (dtsa); /* get fnc */ - if ((uptr == NULL) || /* invalid? */ - ((uptr->flags) & UNIT_DIS) || /* disabled? */ - (fnc >= FNC_WMRK) || /* write mark? */ - ((fnc == FNC_WRIT) && (uptr->flags & UNIT_WLK)) || - ((fnc == FNC_WALL) && (uptr->flags & UNIT_WLK))) - dt_seterr (uptr, DTB_SEL); /* select err */ - else dt_newsa (dtsa); - } -if (pulse == 005) { /* MRD */ - dat = (dat & ~DMASK) | dtdb; - dtsb = dtsb & ~(DTB_DTF | DTB_BEF); - } -if (pulse == 006) { /* MWR */ - dtdb = dat & DMASK; - dtsb = dtsb & ~(DTB_DTF | DTB_BEF); - } -if (pulse == 007) { /* MRS */ - dtsb = dtsb & ~(DTB_REV | DTB_GO); /* clr rev, go */ - if (uptr) { /* valid unit? */ - mot = DTS_GETMOT (uptr->STATE); /* get motion */ - if (mot & DTS_DIR) /* rev? set */ - dtsb = dtsb | DTB_REV; - if ((mot >= DTS_ACCF) || (uptr->STATE & 0777700)) - dtsb = dtsb | DTB_GO; /* accel? go */ - } - dat = (dat & ~DMASK) | dtsb; - } -DT_UPDINT; -return dat; -} - -/* Unit deselect */ - -void dt_deselect (int32 oldf) -{ -int32 old_unit, old_mot; -UNIT *uptr; - -old_unit = DTA_GETUNIT (oldf); /* get unit no */ -if (old_unit < 0) /* invalid? */ - return; -uptr = dt_dev.units + old_unit; /* get unit */ -old_mot = DTS_GETMOT (uptr->STATE); -if (old_mot >= DTS_ATSF) /* at speed? */ - dt_newfnc (uptr, DTS_STA (old_mot, DTS_OFR)); -else if (old_mot >= DTS_ACCF) /* accelerating? */ - DTS_SET2ND (DTS_ATSF | (old_mot & DTS_DIR), DTS_OFR); -return; -} - -/* Command register change - - 1. If change in motion, stop to start - - schedule acceleration - - set function as next state - 2. If change in motion, start to stop - - if not already decelerating (could be reversing), - schedule deceleration - 3. If change in direction, - - if not decelerating, schedule deceleration - - set accelerating (other dir) as next state - - set function as next next state - 4. If not accelerating or at speed, - - schedule acceleration - - set function as next state - 5. If not yet at speed, - - set function as next state - 6. If at speed, - - set function as current state, schedule function -*/ - -void dt_newsa (int32 newf) -{ -int32 new_unit, prev_mot, new_fnc; -int32 prev_mving, new_mving, prev_dir, new_dir; -UNIT *uptr; - -new_unit = DTA_GETUNIT (newf); /* new unit */ -if (new_unit < 0) /* invalid? */ - return; -uptr = dt_dev.units + new_unit; -if ((uptr->flags & UNIT_ATT) == 0) { /* new unit attached? */ - dt_seterr (uptr, DTB_SEL); /* no, error */ - return; - } -prev_mot = DTS_GETMOT (uptr->STATE); /* previous motion */ -prev_mving = prev_mot != DTS_STOP; /* previous moving? */ -prev_dir = prev_mot & DTS_DIR; /* previous dir? */ -new_mving = (newf & DTA_STSTP) != 0; /* new moving? */ -new_dir = (newf & DTA_FWDRV) != 0; /* new dir? */ -new_fnc = DTA_GETFNC (newf); /* new function? */ - -if ((prev_mving | new_mving) == 0) /* stop to stop */ - return; - -if (new_mving & ~prev_mving) { /* start? */ - if (dt_setpos (uptr)) /* update pos */ - return; - sim_cancel (uptr); /* stop current */ - sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* sched accel */ - DTS_SETSTA (DTS_ACCF | new_dir, 0); /* state = accel */ - DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */ - return; - } - -if (prev_mving & ~new_mving) { /* stop? */ - if ((prev_mot & ~DTS_DIR) != DTS_DECF) { /* !already stopping? */ - if (dt_setpos (uptr)) /* update pos */ - return; - sim_cancel (uptr); /* stop current */ - sim_activate (uptr, dt_dctime); /* schedule decel */ - } - DTS_SETSTA (DTS_DECF | prev_dir, 0); /* state = decel */ - return; - } - -if (prev_dir ^ new_dir) { /* dir chg? */ - if ((prev_mot & ~DTS_DIR) != DTS_DECF) { /* !already stopping? */ - if (dt_setpos (uptr)) /* update pos */ - return; - sim_cancel (uptr); /* stop current */ - sim_activate (uptr, dt_dctime); /* schedule decel */ - } - DTS_SETSTA (DTS_DECF | prev_dir, 0); /* state = decel */ - DTS_SET2ND (DTS_ACCF | new_dir, 0); /* next = accel */ - DTS_SET3RD (DTS_ATSF | new_dir, new_fnc); /* next next = fnc */ - return; - } - -if (prev_mot < DTS_ACCF) { /* not accel/at speed? */ - if (dt_setpos (uptr)) /* update pos */ - return; - sim_cancel (uptr); /* cancel cur */ - sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* sched accel */ - DTS_SETSTA (DTS_ACCF | new_dir, 0); /* state = accel */ - DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */ - return; - } - -if (prev_mot < DTS_ATSF) { /* not at speed? */ - DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */ - return; - } - -dt_newfnc (uptr, DTS_STA (DTS_ATSF | new_dir, new_fnc));/* state = fnc */ -return; -} - -/* Schedule new DECtape function - - This routine is only called if - - the selected unit is attached - - the selected unit is at speed (forward or backward) - - This routine - - updates the selected unit's position - - updates the selected unit's state - - schedules the new operation -*/ - -void dt_newfnc (UNIT *uptr, int32 newsta) -{ -int32 fnc, dir, blk, unum, newpos; -uint32 oldpos; - -oldpos = uptr->pos; /* save old pos */ -if (dt_setpos (uptr)) /* update pos */ - return; -uptr->STATE = newsta; /* update state */ -fnc = DTS_GETFNC (uptr->STATE); /* set variables */ -dir = DTS_GETMOT (uptr->STATE) & DTS_DIR; -unum = (int32) (uptr - dt_dev.units); -if (oldpos == uptr->pos) /* bump pos */ - uptr->pos = uptr->pos + (dir? -1: 1); -blk = DT_LIN2BL (uptr->pos, uptr); - -if (dir? DT_QREZ (uptr): DT_QFEZ (uptr)) { /* wrong ez? */ - dt_seterr (uptr, DTB_END); /* set ez flag, stop */ - return; - } -sim_cancel (uptr); /* cancel cur op */ -dt_substate = DTO_SOB; /* substate = block start */ -switch (fnc) { /* case function */ - - case DTS_OFR: /* off reel */ - if (dir) /* rev? < start */ - newpos = -1000; - else newpos = DTU_FWDEZ (uptr) + DT_EZLIN + 1000; /* fwd? > end */ - break; - - case FNC_MOVE: /* move */ - dt_schedez (uptr, dir); /* sched end zone */ - if (DEBUG_PRI (dt_dev, LOG_MS)) - fprintf (sim_deb, ">>DT%d: moving %s\n", unum, - (dir? "backward": "forward")); - return; /* done */ - - case FNC_SRCH: /* search */ - if (dir) - newpos = DT_BLK2LN ((DT_QFEZ (uptr)? DTU_TSIZE (uptr): blk), uptr) - - DT_BLKLN - DT_WSIZE; - else newpos = DT_BLK2LN ((DT_QREZ (uptr)? 0: blk + 1), uptr) + - DT_BLKLN + (DT_WSIZE - 1); - if (DEBUG_PRI (dt_dev, LOG_MS)) - fprintf (sim_deb, ">>DT%d: searching %s\n", unum, - (dir? "backward": "forward")); - break; - - case FNC_WRIT: /* write */ - case FNC_READ: /* read */ - case FNC_RALL: /* read all */ - case FNC_WALL: /* write all */ - if (DT_QEZ (uptr)) { /* in "ok" end zone? */ - if (dir) - newpos = DTU_FWDEZ (uptr) - DT_WSIZE; - else newpos = DT_EZLIN + (DT_WSIZE - 1); - } - else { - newpos = ((uptr->pos) / DT_WSIZE) * DT_WSIZE; - if (!dir) - newpos = newpos + (DT_WSIZE - 1); - } - if (DEBUG_PRI (dt_dev, LOG_RW) || - (DEBUG_PRI (dt_dev, LOG_BL) && (blk == dt_logblk))) - fprintf (sim_deb, ">>DT%d: read all block %d %s%s\n", - unum, blk, (dir? "backward": "forward"), - ((dtsa & DTA_MODE)? " continuous": " ")); - break; - - default: - dt_seterr (uptr, DTB_SEL); /* bad state */ - return; - } - -if ((fnc == FNC_WRIT) || (fnc == FNC_WALL)) { /* write function? */ - dtsb = dtsb | DTB_DTF; /* set data flag */ - DT_UPDINT; - } -sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime); -return; -} - -/* Update DECtape position - - DECtape motion is modeled as a constant velocity, with linear - acceleration and deceleration. The motion equations are as follows: - - t = time since operation started - tmax = time for operation (accel, decel only) - v = at speed velocity in lines (= 1/dt_ltime) - - Then: - at speed dist = t * v - accel dist = (t^2 * v) / (2 * tmax) - decel dist = (((2 * t * tmax) - t^2) * v) / (2 * tmax) - - This routine uses the relative (integer) time, rather than the absolute - (floating point) time, to allow save and restore of the start times. -*/ - -t_bool dt_setpos (UNIT *uptr) -{ -uint32 new_time, ut, ulin, udelt; -int32 mot = DTS_GETMOT (uptr->STATE); -int32 unum, delta; - -new_time = sim_grtime (); /* current time */ -ut = new_time - uptr->LASTT; /* elapsed time */ -if (ut == 0) /* no time gone? exit */ - return FALSE; -uptr->LASTT = new_time; /* update last time */ -switch (mot & ~DTS_DIR) { /* case on motion */ - - case DTS_STOP: /* stop */ - delta = 0; - break; - - case DTS_DECF: /* slowing */ - ulin = ut / (uint32) dt_ltime; - udelt = dt_dctime / dt_ltime; - delta = ((ulin * udelt * 2) - (ulin * ulin)) / (2 * udelt); - break; - - case DTS_ACCF: /* accelerating */ - ulin = ut / (uint32) dt_ltime; - udelt = (dt_dctime - (dt_dctime >> 2)) / dt_ltime; - delta = (ulin * ulin) / (2 * udelt); - break; - - case DTS_ATSF: /* at speed */ - delta = ut / (uint32) dt_ltime; - break; - } - -if (mot & DTS_DIR) /* update pos */ - uptr->pos = uptr->pos - delta; -else uptr->pos = uptr->pos + delta; -if (((int32) uptr->pos < 0) || - ((int32) uptr->pos > (DTU_FWDEZ (uptr) + DT_EZLIN))) { - detach_unit (uptr); /* off reel? */ - uptr->STATE = uptr->pos = 0; - unum = (int32) (uptr - dt_dev.units); - if (unum == DTA_GETUNIT (dtsa)) /* if selected, */ - dt_seterr (uptr, DTB_SEL); /* error */ - return TRUE; - } -return FALSE; -} - -/* Unit service - - Unit must be attached, detach cancels operation -*/ - -t_stat dt_svc (UNIT *uptr) -{ -int32 mot = DTS_GETMOT (uptr->STATE); -int32 dir = mot & DTS_DIR; -int32 fnc = DTS_GETFNC (uptr->STATE); -int32 *fbuf = (int32 *) uptr->filebuf; -int32 blk, wrd, ma, relpos; -uint32 ba; - -/* Motion cases - - Decelerating - if next state != stopped, must be accel reverse - Accelerating - next state must be @speed, schedule function - At speed - do functional processing -*/ - -switch (mot) { - - case DTS_DECF: case DTS_DECR: /* decelerating */ - if (dt_setpos (uptr)) /* upd pos; off reel? */ - return IORETURN (dt_stopoffr, STOP_DTOFF); - uptr->STATE = DTS_NXTSTA (uptr->STATE); /* advance state */ - if (uptr->STATE) /* not stopped? */ - sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* reversing */ - return SCPE_OK; - - case DTS_ACCF: case DTS_ACCR: /* accelerating */ - dt_newfnc (uptr, DTS_NXTSTA (uptr->STATE)); /* adv state, sched */ - return SCPE_OK; - - case DTS_ATSF: case DTS_ATSR: /* at speed */ - break; /* check function */ - - default: /* other */ - dt_seterr (uptr, DTB_SEL); /* state error */ - return SCPE_OK; - } - -/* Functional cases - - Move - must be at end zone - Search - transfer block number, schedule next block - Off reel - detach unit (it must be deselected) -*/ - -if (dt_setpos (uptr)) /* upd pos; off reel? */ - return IORETURN (dt_stopoffr, STOP_DTOFF); -if (DT_QEZ (uptr)) { /* in end zone? */ - dt_seterr (uptr, DTB_END); /* end zone error */ - return SCPE_OK; - } -blk = DT_LIN2BL (uptr->pos, uptr); /* get block # */ - -switch (fnc) { /* at speed, check fnc */ - - case FNC_MOVE: /* move */ - dt_seterr (uptr, DTB_END); /* end zone error */ - return SCPE_OK; - - case DTS_OFR: /* off reel */ - detach_unit (uptr); /* must be deselected */ - uptr->STATE = uptr->pos = 0; /* no visible action */ - break; - -/* Search */ - - case FNC_SRCH: /* search */ - if (dtsb & DTB_DTF) { /* DTF set? */ - dt_seterr (uptr, DTB_TIM); /* timing error */ - return SCPE_OK; - } - sim_activate (uptr, DTU_LPERB (uptr) * dt_ltime);/* sched next block */ - dtdb = blk; /* store block # */ - dtsb = dtsb | DTB_DTF; /* set DTF */ - break; - -/* Read and read all */ - - case FNC_READ: case FNC_RALL: - if (dtsb & DTB_DTF) { /* DTF set? */ - dt_seterr (uptr, DTB_TIM); /* timing error */ - return SCPE_OK; - } - sim_activate (uptr, DT_WSIZE * dt_ltime); /* sched next word */ - relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ - if ((relpos >= DT_HTLIN) && /* in data zone? */ - (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { - wrd = DT_LIN2WD (uptr->pos, uptr); - ba = (blk * DTU_BSIZE (uptr)) + wrd; - dtdb = fbuf[ba]; /* get tape word */ - dtsb = dtsb | DTB_DTF; /* set flag */ - } - else { - ma = (2 * DT_HTWRD) + DTU_BSIZE (uptr) - DT_CSMWD - 1; - wrd = relpos / DT_WSIZE; /* hdr start = wd 0 */ -#if defined (OLD_TYPE550) - if ((wrd == 0) || /* skip 1st, last */ - (wrd == ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - 1))) break; -#endif - if ((fnc == FNC_READ) && /* read, skip if not */ - (wrd != DT_CSMWD) && /* fwd, rev cksum */ - (wrd != ma)) - break; - dtdb = dt_gethdr (uptr, blk, relpos); - if (wrd == (dir? DT_CSMWD: ma)) /* at end csum? */ - dtsb = dtsb | DTB_BEF; /* end block */ - else dtsb = dtsb | DTB_DTF; /* else next word */ - } - if (dir) - dtdb = dt_comobv (dtdb); - break; - -/* Write and write all */ - - case FNC_WRIT: case FNC_WALL: - if (dtsb & DTB_DTF) { /* DTF set? */ - dt_seterr (uptr, DTB_TIM); /* timing error */ - return SCPE_OK; - } - sim_activate (uptr, DT_WSIZE * dt_ltime); /* sched next word */ - relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ - if ((relpos >= DT_HTLIN) && /* in data zone? */ - (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { - wrd = DT_LIN2WD (uptr->pos, uptr); - ba = (blk * DTU_BSIZE (uptr)) + wrd; - if (dir) /* get data word */ - fbuf[ba] = dt_comobv (dtdb); - else fbuf[ba] = dtdb; - if (ba >= uptr->hwmark) - uptr->hwmark = ba + 1; - if (wrd == (dir? 0: DTU_BSIZE (uptr) - 1)) - dtsb = dtsb | DTB_BEF; /* end block */ - else dtsb = dtsb | DTB_DTF; /* else next word */ - } - else { - wrd = relpos / DT_WSIZE; /* hdr start = wd 0 */ -#if defined (OLD_TYPE550) - if ((wrd == 0) || /* skip 1st, last */ - (wrd == ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - 1))) break; -#endif - if ((fnc == FNC_WRIT) && /* wr, skip if !csm */ - (wrd != ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - DT_CSMWD - 1))) - break; - dtsb = dtsb | DTB_DTF; /* set flag */ - } - break; - - default: - dt_seterr (uptr, DTB_SEL); /* impossible state */ - break; - } - -DT_UPDINT; /* update interrupts */ -return SCPE_OK; -} - -/* Utility routines */ - -/* Set error flag */ - -void dt_seterr (UNIT *uptr, int32 e) -{ -dtsa = dtsa & ~DTA_STSTP; /* clear go */ -dtsb = dtsb | DTB_ERF | e; /* set error flag */ -if (uptr != NULL) { /* valid unit? */ - int32 mot = DTS_GETMOT (uptr->STATE); /* get motion */ - if (mot >= DTS_ACCF) { /* ~stopped or stopping? */ - sim_cancel (uptr); /* cancel activity */ - if (dt_setpos (uptr)) /* update position */ - return; - sim_activate (uptr, dt_dctime); /* sched decel */ - DTS_SETSTA (DTS_DECF | (mot & DTS_DIR), 0); /* state = decel */ - } - else DTS_SETSTA (mot, 0); /* clear 2nd, 3rd */ - } -DT_UPDINT; -return; -} - -/* Schedule end zone */ - -void dt_schedez (UNIT *uptr, int32 dir) -{ -int32 newpos; - -if (dir) /* rev? rev ez */ - newpos = DT_EZLIN - DT_WSIZE; -else newpos = DTU_FWDEZ (uptr) + DT_WSIZE; /* fwd? fwd ez */ -sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime); -return; -} - -/* Complement obverse routine */ - -int32 dt_comobv (int32 dat) -{ -dat = dat ^ 0777777; /* compl obverse */ -dat = ((dat >> 15) & 07) | ((dat >> 9) & 070) | - ((dat >> 3) & 0700) | ((dat & 0700) << 3) | - ((dat & 070) << 9) | ((dat & 07) << 15); -return dat; -} - -/* Checksum routine */ - -int32 dt_csum (UNIT *uptr, int32 blk) -{ -int32 *fbuf = (int32 *) uptr->filebuf; -int32 ba = blk * DTU_BSIZE (uptr); -int32 i, csum, wrd; - -csum = 0777777; -for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */ - wrd = fbuf[ba + i]; /* get word */ - csum = csum + wrd; /* 1's comp add */ - if (csum > 0777777) - csum = (csum + 1) & 0777777; - } -return (csum ^ 0777777); /* 1's comp res */ -} - -/* Get header word */ - -int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos) -{ -int32 wrd = relpos / DT_WSIZE; - -if (wrd == DT_BLKWD) /* fwd blknum */ - return blk; -if (wrd == DT_CSMWD) /* rev csum */ - return 0777777; -if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_CSMWD - 1)) /* fwd csum */ - return (dt_csum (uptr, blk)); -if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_BLKWD - 1)) /* rev blkno */ - return dt_comobv (blk); -return 0; /* all others */ -} - -/* Reset routine */ - -t_stat dt_reset (DEVICE *dptr) -{ -int32 i, prev_mot; -UNIT *uptr; - -for (i = 0; i < DT_NUMDR; i++) { /* stop all drives */ - uptr = dt_dev.units + i; - if (sim_is_running) { /* CAF? */ - prev_mot = DTS_GETMOT (uptr->STATE); /* get motion */ - if ((prev_mot & ~DTS_DIR) > DTS_DECF) { /* accel or spd? */ - if (dt_setpos (uptr)) /* update pos */ - continue; - sim_cancel (uptr); - sim_activate (uptr, dt_dctime); /* sched decel */ - DTS_SETSTA (DTS_DECF | (prev_mot & DTS_DIR), 0); - } - } - else { - sim_cancel (uptr); /* sim reset */ - uptr->STATE = 0; - uptr->LASTT = sim_grtime (); - } - } -dtsa = dtsb = 0; /* clear status */ -DT_UPDINT; /* reset interrupt */ -return SCPE_OK; -} - -/* IORS routine */ - -int32 dt_iors (void) -{ -#if defined IOS_DTA -return ((dtsb & (DTB_ERF | DTB_DTF))? IOS_DTA: 0); -#else -return 0; -#endif -} - -/* Attach routine - - Determine 12b, 16b, or 18b/36b format - Allocate buffer - If 12b, read 12b format and convert to 18b in buffer - If 16b, read 16b format and convert to 18b in buffer - If 18b/36b, read data into buffer -*/ - -t_stat dt_attach (UNIT *uptr, char *cptr) -{ -uint16 pdp8b[D8_NBSIZE]; -uint16 pdp11b[D18_BSIZE]; -uint32 ba, sz, k, *fbuf; -int32 u = uptr - dt_dev.units; -t_stat r; - -r = attach_unit (uptr, cptr); /* attach */ -if (r != SCPE_OK) /* error? */ - return r; -if ((sim_switches & SIM_SW_REST) == 0) { /* not from rest? */ - uptr->flags = uptr->flags & ~(UNIT_8FMT | UNIT_11FMT); /* default 18b */ - if (sim_switches & SWMASK ('T')) /* att 12b? */ - uptr->flags = uptr->flags | UNIT_8FMT; - else if (sim_switches & SWMASK ('S')) /* att 16b? */ - uptr->flags = uptr->flags | UNIT_11FMT; - else if (!(sim_switches & SWMASK ('A')) && /* autosize? */ - (sz = sim_fsize (uptr->fileref))) { - if (sz == D8_FILSIZ) - uptr->flags = uptr->flags | UNIT_8FMT; - else if (sz == D11_FILSIZ) - uptr->flags = uptr->flags | UNIT_11FMT; - } - } -uptr->capac = DTU_CAPAC (uptr); /* set capacity */ -uptr->filebuf = calloc (uptr->capac, sizeof (uint32)); -if (uptr->filebuf == NULL) { /* can't alloc? */ - detach_unit (uptr); - return SCPE_MEM; - } -fbuf = (uint32 *) uptr->filebuf; /* file buffer */ -sim_printf ("%s%d: ", sim_dname (&dt_dev), u); -if (uptr->flags & UNIT_8FMT) - sim_printf ("12b format"); -else if (uptr->flags & UNIT_11FMT) - sim_printf ("16b format"); -else sim_printf ("18b/36b format"); -sim_printf (", buffering file in memory\n"); -if (uptr->flags & UNIT_8FMT) { /* 12b? */ - for (ba = 0; ba < uptr->capac; ) { /* loop thru file */ - k = fxread (pdp8b, sizeof (uint16), D8_NBSIZE, uptr->fileref); - if (k == 0) - break; - for ( ; k < D8_NBSIZE; k++) - pdp8b[k] = 0; - for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop thru blk */ - fbuf[ba] = ((uint32) (pdp8b[k] & 07777) << 6) | - ((uint32) (pdp8b[k + 1] >> 6) & 077); - fbuf[ba + 1] = ((uint32) (pdp8b[k + 1] & 077) << 12) | - ((uint32) pdp8b[k + 2] & 07777); - ba = ba + 2; - } /* end blk loop */ - } /* end file loop */ - uptr->hwmark = ba; - } /* end if */ -else if (uptr->flags & UNIT_11FMT) { /* 16b? */ - for (ba = 0; ba < uptr->capac; ) { /* loop thru file */ - k = fxread (pdp11b, sizeof (uint16), D18_BSIZE, uptr->fileref); - if (k == 0) - break; - for ( ; k < D18_BSIZE; k++) - pdp11b[k] = 0; - for (k = 0; k < D18_BSIZE; k++) - fbuf[ba++] = pdp11b[k]; - } - uptr->hwmark = ba; /* end elif */ - } -else uptr->hwmark = fxread (uptr->filebuf, sizeof (uint32), - uptr->capac, uptr->fileref); -uptr->flags = uptr->flags | UNIT_BUF; /* set buf flag */ -uptr->pos = DT_EZLIN; /* beyond leader */ -uptr->LASTT = sim_grtime (); /* last pos update */ -return SCPE_OK; -} - -/* Detach routine - - Cancel in progress operation - If 12b, convert 18b buffer to 12b and write to file - If 16b, convert 18b buffer to 16b and write to file - If 18b/36b, write buffer to file - Deallocate buffer -*/ - -t_stat dt_detach (UNIT* uptr) -{ -uint16 pdp8b[D8_NBSIZE]; -uint16 pdp11b[D18_BSIZE]; -uint32 ba, k, *fbuf; -int32 u = uptr - dt_dev.units; - -if (!(uptr->flags & UNIT_ATT)) /* attached? */ - return SCPE_OK; -if (sim_is_active (uptr)) { - sim_cancel (uptr); - if ((u == DTA_GETUNIT (dtsa)) && (dtsa & DTA_STSTP)) { - dtsb = dtsb | DTB_ERF | DTB_SEL | DTB_DTF; - DT_UPDINT; - } - uptr->STATE = uptr->pos = 0; - } -fbuf = (uint32 *) uptr->filebuf; /* file buffer */ -if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { /* any data? */ - sim_printf ("%s%d: writing buffer to file\n", sim_dname (&dt_dev), u); - rewind (uptr->fileref); /* start of file */ - if (uptr->flags & UNIT_8FMT) { /* 12b? */ - for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */ - for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop blk */ - pdp8b[k] = (fbuf[ba] >> 6) & 07777; - pdp8b[k + 1] = ((fbuf[ba] & 077) << 6) | - ((fbuf[ba + 1] >> 12) & 077); - pdp8b[k + 2] = fbuf[ba + 1] & 07777; - ba = ba + 2; - } /* end loop blk */ - fxwrite (pdp8b, sizeof (uint16), D8_NBSIZE, uptr->fileref); - if (ferror (uptr->fileref)) - break; - } /* end loop file */ - } /* end if 12b */ - else if (uptr->flags & UNIT_11FMT) { /* 16b? */ - for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */ - for (k = 0; k < D18_BSIZE; k++) /* loop blk */ - pdp11b[k] = fbuf[ba++] & 0177777; - fxwrite (pdp11b, sizeof (uint16), D18_BSIZE, uptr->fileref); - if (ferror (uptr->fileref)) - break; - } /* end loop file */ - } /* end if 16b */ - else fxwrite (uptr->filebuf, sizeof (uint32), /* write file */ - uptr->hwmark, uptr->fileref); - if (ferror (uptr->fileref)) - perror ("I/O error"); - } /* end if hwmark */ -free (uptr->filebuf); /* release buf */ -uptr->flags = uptr->flags & ~UNIT_BUF; /* clear buf flag */ -uptr->filebuf = NULL; /* clear buf ptr */ -uptr->flags = uptr->flags & ~(UNIT_8FMT | UNIT_11FMT); /* default fmt */ -uptr->capac = DT_CAPAC; /* default size */ -return detach_unit (uptr); -} diff --git a/PDP1/pdp1_lp.c b/PDP1/pdp1_lp.c deleted file mode 100644 index ae5fe6c1..00000000 --- a/PDP1/pdp1_lp.c +++ /dev/null @@ -1,214 +0,0 @@ -/* pdp1_lp.c: PDP-1 line printer simulator - - Copyright (c) 1993-2008, 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 - bused in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - lpt Type 62 line printer for the PDP-1 - - 19-Jan-07 RMS Added UNIT_TEXT flag - 21-Dec-06 RMS Added 16-channel SBS support - 07-Sep-03 RMS Changed ioc to ios - 23-Jul-03 RMS Fixed bugs in instruction decoding, overprinting - Revised to detect I/O wait hang - 25-Apr-03 RMS Revised for extended file support - 30-May-02 RMS Widened POS to 32b - 13-Apr-01 RMS Revised for register arrays -*/ - -#include "pdp1_defs.h" - -#define BPTR_MAX 40 /* pointer max */ -#define LPT_BSIZE (BPTR_MAX * 3) /* line size */ -#define BPTR_MASK 077 /* buf ptr mask */ - -int32 lpt_spc = 0; /* print (0) vs spc */ -int32 lpt_ovrpr = 0; /* overprint */ -int32 lpt_stopioe = 0; /* stop on error */ -int32 lpt_bptr = 0; /* buffer ptr */ -int32 lpt_sbs = 0; /* SBS level */ -char lpt_buf[LPT_BSIZE + 1] = { 0 }; -static const unsigned char lpt_trans[64] = { - ' ','1','2','3','4','5','6','7','8','9','\'','~','#','V','^','<', - '0','/','S','T','U','V','W','X','Y','Z','"',',','>','^','-','?', - '@','J','K','L','M','N','O','P','Q','R','$','=','-',')','-','(', - '_','A','B','C','D','E','F','G','H','I','*','.','+',']','|','[' - }; - -extern int32 ios, cpls, iosta; -extern int32 stop_inst; - -t_stat lpt_svc (UNIT *uptr); -t_stat lpt_reset (DEVICE *dptr); - -/* LPT data structures - - lpt_dev LPT device descriptor - lpt_unit LPT unit - lpt_reg LPT register list -*/ - -UNIT lpt_unit = { - UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT - }; - -REG lpt_reg[] = { - { ORDATA (BUF, lpt_unit.buf, 8) }, - { FLDATA (PNT, iosta, IOS_V_PNT) }, - { FLDATA (SPC, iosta, IOS_V_SPC) }, - { FLDATA (RPLS, cpls, CPLS_V_LPT) }, - { DRDATA (BPTR, lpt_bptr, 6) }, - { ORDATA (LPT_STATE, lpt_spc, 6), REG_HRO }, - { FLDATA (LPT_OVRPR, lpt_ovrpr, 0), REG_HRO }, - { DRDATA (POS, lpt_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT }, - { FLDATA (STOP_IOE, lpt_stopioe, 0) }, - { BRDATA (LBUF, lpt_buf, 8, 8, LPT_BSIZE) }, - { DRDATA (SBSLVL, lpt_sbs, 4), REG_HRO }, - { NULL } - }; - -MTAB lpt_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL", - &dev_set_sbs, &dev_show_sbs, (void *) &lpt_sbs }, - { 0 } - }; - -DEVICE lpt_dev = { - "LPT", &lpt_unit, lpt_reg, lpt_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &lpt_reset, - NULL, NULL, NULL, - NULL, DEV_DISABLE - }; - -/* Line printer IOT routine */ - -int32 lpt (int32 inst, int32 dev, int32 dat) -{ -int32 i; - -if (lpt_dev.flags & DEV_DIS) /* disabled? */ - return (stop_inst << IOT_V_REASON) | dat; /* stop if requested */ -if ((inst & 07000) == 01000) { /* fill buf */ - if (lpt_bptr < BPTR_MAX) { /* limit test ptr */ - i = lpt_bptr * 3; /* cvt to chr ptr */ - lpt_buf[i] = lpt_trans[(dat >> 12) & 077]; - lpt_buf[i + 1] = lpt_trans[(dat >> 6) & 077]; - lpt_buf[i + 2] = lpt_trans[dat & 077]; - } - lpt_bptr = (lpt_bptr + 1) & BPTR_MASK; - return dat; - } -if ((inst & 07000) == 02000) { /* space */ - iosta = iosta & ~IOS_SPC; /* space, clear flag */ - lpt_spc = (inst >> 6) & 077; /* state = space n */ - } -else if ((inst & 07000) == 00000) { /* print */ - iosta = iosta & ~IOS_PNT; /* clear flag */ - lpt_spc = 0; /* state = print */ - } -else return (stop_inst << IOT_V_REASON) | dat; /* not implemented */ -if (GEN_CPLS (inst)) { /* comp pulse? */ - ios = 0; /* clear flop */ - cpls = cpls | CPLS_LPT; /* request completion */ - } -else cpls = cpls & ~CPLS_LPT; -sim_activate (&lpt_unit, lpt_unit.wait); /* activate */ -return dat; -} - -/* Unit service, printer is in one of three states - - lpt_spc = 000 write buffer to file, set overprint - lpt_iot = 02x space command x, clear overprint -*/ - -t_stat lpt_svc (UNIT *uptr) -{ -int32 i; -static const char *lpt_cc[] = { - "\n", - "\n\n", - "\n\n\n", - "\n\n\n\n\n\n", - "\n\n\n\n\n\n\n\n\n\n\n", - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", - "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", - "\f" - }; - -if (cpls & CPLS_LPT) { /* completion pulse? */ - ios = 1; /* restart */ - cpls = cpls & ~CPLS_LPT; /* clr pulse pending */ - } -dev_req_int (lpt_sbs); /* req interrupt */ -if (lpt_spc) { /* space? */ - iosta = iosta | IOS_SPC; /* set flag */ - if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (lpt_stopioe, SCPE_UNATT); - fputs (lpt_cc[lpt_spc & 07], uptr->fileref); /* print cctl */ - uptr->pos = ftell (uptr->fileref); /* update position */ - if (ferror (uptr->fileref)) { /* error? */ - perror ("LPT I/O error"); - clearerr (uptr->fileref); - return SCPE_IOERR; - } - lpt_ovrpr = 0; /* dont overprint */ - } -else { - iosta = iosta | IOS_PNT; /* print */ - if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ - return IORETURN (lpt_stopioe, SCPE_UNATT); - if (lpt_ovrpr) /* overprint? */ - fputc ('\r', uptr->fileref); - fputs (lpt_buf, uptr->fileref); /* print buffer */ - uptr->pos = ftell (uptr->fileref); /* update position */ - if (ferror (uptr->fileref)) { /* test error */ - perror ("LPT I/O error"); - clearerr (uptr->fileref); - return SCPE_IOERR; - } - lpt_bptr = 0; - for (i = 0; i <= LPT_BSIZE; i++) /* clear buffer */ - lpt_buf[i] = 0; - lpt_ovrpr = 1; /* set overprint */ - } -return SCPE_OK; -} - -/* Reset routine */ - -t_stat lpt_reset (DEVICE *dptr) -{ -int32 i; - -lpt_bptr = 0; /* clear buffer ptr */ -for (i = 0; i <= LPT_BSIZE; i++) /* clear buffer */ - lpt_buf[i] = 0; -lpt_spc = 0; /* clear state */ -lpt_ovrpr = 0; /* clear overprint */ -cpls = cpls & ~CPLS_LPT; -iosta = iosta & ~(IOS_PNT | IOS_SPC); /* clear flags */ -sim_cancel (&lpt_unit); /* deactivate unit */ -return SCPE_OK; -} diff --git a/PDP1/pdp1_stddev.c b/PDP1/pdp1_stddev.c deleted file mode 100644 index 57c533e1..00000000 --- a/PDP1/pdp1_stddev.c +++ /dev/null @@ -1,707 +0,0 @@ -/* pdp1_stddev.c: PDP-1 standard devices - - Copyright (c) 1993-2016, Robert M. Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - ptr paper tape reader - ptp paper tape punch - tti keyboard - tto teleprinter - - 13-Jul-16 RMS Added Expensive Typewriter ribbon color support - 18-May-16 RMS Added FIODEC-to-ASCII mode for paper tape punch - 28-Mar-15 RMS Revised to use sim_printf - 21-Mar-12 RMS Fixed unitialized variable in tto_svc (Michael Bloom) - 21-Dec-06 RMS Added 16-channel sequence break support - 29-Oct-03 RMS Added PTR FIODEC-to-ASCII translation (Phil Budne) - 07-Sep-03 RMS Changed ioc to ios - 30-Aug-03 RMS Revised PTR to conform to Maintenance Manual; - added deadlock prevention on errors - 23-Jul-03 RMS Revised to detect I/O wait hang - 25-Apr-03 RMS Revised for extended file support - 22-Dec-02 RMS Added break support - 29-Nov-02 RMS Fixed output flag initialization (Derek Peschel) - 21-Nov-02 RMS Changed typewriter to half duplex (Derek Peschel) - 06-Oct-02 RMS Revised for V2.10 - 30-May-02 RMS Widened POS to 32b - 29-Nov-01 RMS Added read only unit support - 07-Sep-01 RMS Moved function prototypes - 10-Jun-01 RMS Fixed comment - 30-Oct-00 RMS Standardized device naming - - Note: PTP timeout must be >10X faster that TTY output timeout for Macro - to work correctly! -*/ - -#include "pdp1_defs.h" - -#define FIODEC_STOP 013 /* stop code */ -#define FIODEC_BLACK 034 /* TTY black ribbon */ -#define FIODEC_RED 035 /* TTY red ribbon */ -#define FIODEC_UC 074 /* upper case */ -#define FIODEC_LC 072 /* lower case */ -#define FIODEC_CR 077 /* carriage return */ - -#define UC_V 6 /* upper case */ -#define UC (1 << UC_V) -#define BOTH (1 << (UC_V + 1)) /* both cases */ -#define CW (1 << (UC_V + 2)) /* char waiting */ -#define TT_WIDTH 077 -#define UNIT_V_ASCII (UNIT_V_UF + 0) /* ASCII/binary mode */ -#define UNIT_ASCII (1 << UNIT_V_ASCII) -#define UNIT_V_ET (UNIT_V_UF + 1) /* expensive typewriter mode */ -#define UNIT_ET (1 << UNIT_V_ET) -#define PTR_LEADER 20 /* ASCII leader chars */ - -int32 ptr_state = 0; -int32 ptr_wait = 0; -int32 ptr_stopioe = 0; -int32 ptr_uc = 0; /* upper/lower case */ -int32 ptp_uc = 0; -int32 ptr_hold = 0; /* holding buffer */ -int32 ptr_leader = PTR_LEADER; /* leader count */ -int32 ptr_sbs = 0; /* SBS level */ -int32 ptp_stopioe = 0; -int32 ptp_sbs = 0; /* SBS level */ -int32 tti_hold = 0; /* tti hold buf */ -int32 tti_sbs = 0; /* SBS level */ -int32 tty_buf = 0; /* tty buffer */ -int32 tty_uc = 0; /* tty uc/lc */ -int32 tty_ribbon = FIODEC_BLACK; /* ribbon color */ -int32 tto_sbs = 0; - -extern int32 ios, ioh, cpls, iosta; -extern int32 PF, IO, PC, TA; -extern int32 M[]; - -int ptr_get_ascii (UNIT *uptr); -t_stat ptr_svc (UNIT *uptr); -t_stat ptp_svc (UNIT *uptr); -t_stat tti_svc (UNIT *uptr); -t_stat tto_svc (UNIT *uptr); -t_stat ptr_reset (DEVICE *dptr); -t_stat ptp_reset (DEVICE *dptr); -t_stat tty_reset (DEVICE *dptr); -t_stat ptr_boot (int32 unitno, DEVICE *dptr); -t_stat ptr_attach (UNIT *uptr, char *cptr); -t_stat ptp_attach (UNIT *uptr, char *cptr); - -/* Character translation tables */ - -int32 fiodec_to_ascii[128] = { - ' ', '1', '2', '3', '4', '5', '6', '7', /* lower case */ - '8', '9', 0, '\f', 0, 0, 0, 0, - '0', '/', 's', 't', 'u', 'v', 'w', 'x', - 'y', 'z', 0, ',', 0, 0, '\t', 0, - '@', 'j', 'k', 'l', 'm', 'n', 'o', 'p', - 'q', 'r', 0, 0, '-', ')', '\\', '(', - 0, 'a', 'b', 'c', 'd', 'e', 'f', 'g', - 'h', 'i', 0, '.', 0, '\b', 0, '\n', - ' ', '"', '\'', '~', '#', '!', '&', '<', /* upper case */ - '>', '^', 0, 0, 0, 0, 0, 0, - '`', '?', 'S', 'T', 'U', 'V', 'W', 'X', - 'Y', 'Z', 0, '=', 0, 0, '\t', 0, - '_', 'J', 'K', 'L', 'M', 'N', 'O', 'P', - 'Q', 'R', 0, 0, '+', ']', '|', '[', - 0, 'A', 'B', 'C', 'D', 'E', 'F', 'G', - 'H', 'I', 0, '*', 0, '\b', 0, '\n' - }; - -int32 ascii_to_fiodec[128] = { - 0, 0, 0, 0, 0, 0, 0, 0, - BOTH+075, BOTH+036, 0, 0, BOTH+FIODEC_STOP, BOTH+FIODEC_CR, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - BOTH+0, UC+005, UC+001, UC+004, 0, 0, UC+006, UC+002, - 057, 055, UC+073, UC+054, 033, 054, 073, 021, - 020, 001, 002, 003, 004, 005, 006, 007, - 010, 011, 0, 0, UC+007, UC+033, UC+010, UC+021, - 040, UC+061, UC+062, UC+063, UC+064, UC+065, UC+066, UC+067, - UC+070, UC+071, UC+041, UC+042, UC+043, UC+044, UC+045, UC+046, - UC+047, UC+050, UC+051, UC+022, UC+023, UC+024, UC+025, UC+026, - UC+027, UC+030, UC+031, UC+057, 056, UC+055, UC+011, UC+040, - UC+020, 061, 062, 063, 064, 065, 066, 067, - 070, 071, 041, 042, 043, 044, 045, 046, - 047, 050, 051, 022, 023, 024, 025, 026, - 027, 030, 031, 0, UC+056, 0, UC+003, BOTH+075 - }; - -/* PTR data structures - - ptr_dev PTR device descriptor - ptr_unit PTR unit - ptr_reg PTR register list -*/ - -UNIT ptr_unit = { - UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), - SERIAL_IN_WAIT - }; - -REG ptr_reg[] = { - { ORDATA (BUF, ptr_unit.buf, 18) }, - { FLDATA (UC, ptr_uc, UC_V) }, - { FLDATA (DONE, iosta, IOS_V_PTR) }, - { FLDATA (RPLS, cpls, CPLS_V_PTR) }, - { ORDATA (HOLD, ptr_hold, 9), REG_HRO }, - { ORDATA (STATE, ptr_state, 5), REG_HRO }, - { FLDATA (WAIT, ptr_wait, 0), REG_HRO }, - { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, - { DRDATA (LEADER, ptr_leader, 6), REG_HRO }, - { FLDATA (STOP_IOE, ptr_stopioe, 0) }, - { DRDATA (SBSLVL, ptr_sbs, 4), REG_HRO }, - { NULL } - }; - -MTAB ptr_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL", - &dev_set_sbs, &dev_show_sbs, (void *) &ptr_sbs }, - { UNIT_ASCII, UNIT_ASCII, "ASCII", NULL, NULL }, - { UNIT_ASCII, 0, "FIODEC", NULL, NULL }, - { 0 } - }; - -DEVICE ptr_dev = { - "PTR", &ptr_unit, ptr_reg, ptr_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ptr_reset, - &ptr_boot, &ptr_attach, NULL, - NULL, 0 - }; - -/* PTP data structures - - ptp_dev PTP device descriptor - ptp_unit PTP unit - ptp_reg PTP register list -*/ - -UNIT ptp_unit = { - UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT - }; - -REG ptp_reg[] = { - { ORDATA (BUF, ptp_unit.buf, 8) }, - { FLDATA (DONE, iosta, IOS_V_PTP) }, - { FLDATA (RPLS, cpls, CPLS_V_PTP) }, - { DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, - { FLDATA (STOP_IOE, ptp_stopioe, 0) }, - { DRDATA (SBSLVL, ptp_sbs, 4), REG_HRO }, - { NULL } - }; - -MTAB ptp_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL", - &dev_set_sbs, &dev_show_sbs, (void *) &ptp_sbs }, - { UNIT_ASCII, UNIT_ASCII, "ASCII", NULL, NULL }, - { UNIT_ASCII, 0, "FIODEC", NULL, NULL }, - { 0 } - }; - -DEVICE ptp_dev = { - "PTP", &ptp_unit, ptp_reg, ptp_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ptp_reset, - NULL, &ptp_attach, NULL, - NULL, 0 - }; - -/* TTI data structures - - tti_dev TTI device descriptor - tti_unit TTI unit - tti_reg TTI register list -*/ - -UNIT tti_unit = { UDATA (&tti_svc, 0, 0), KBD_POLL_WAIT }; - -REG tti_reg[] = { - { ORDATA (BUF, tty_buf, 6) }, - { FLDATA (UC, tty_uc, UC_V) }, - { ORDATA (HOLD, tti_hold, 9), REG_HRO }, - { FLDATA (DONE, iosta, IOS_V_TTI) }, - { DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, tti_unit.wait, 24), REG_NZ + PV_LEFT }, - { DRDATA (SBSLVL, tti_sbs, 4), REG_HRO }, - { NULL } - }; - -MTAB tti_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL", - &dev_set_sbs, &dev_show_sbs, (void *) &tti_sbs }, - { 0 } - }; - -DEVICE tti_dev = { - "TTI", &tti_unit, tti_reg, tti_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &tty_reset, - NULL, NULL, NULL, - NULL, 0 - }; - -/* TTO data structures - - tto_dev TTO device descriptor - tto_unit TTO unit - tto_reg TTO register list -*/ - -UNIT tto_unit = { UDATA (&tto_svc, 0, 0), SERIAL_OUT_WAIT * 10 }; - -REG tto_reg[] = { - { ORDATA (BUF, tty_buf, 6) }, - { FLDATA (UC, tty_uc, UC_V) }, - { FLDATA (RPLS, cpls, CPLS_V_TTO) }, - { FLDATA (DONE, iosta, IOS_V_TTO) }, - { DRDATA (POS, tto_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT }, - { DRDATA (SBSLVL, tto_sbs, 4), REG_HRO }, - { ORDATA (RIBBON, tty_ribbon, 6), REG_HRO }, - { NULL } - }; - -MTAB tto_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "SBSLVL", "SBSLVL", - &dev_set_sbs, &dev_show_sbs, (void *) &tto_sbs }, - { UNIT_ET, UNIT_ET, "Expensive Typewriter mode", "ET", NULL }, - { UNIT_ET, UNIT_ET, "normal mode", "NOET", NULL }, - { 0 } - }; - -DEVICE tto_dev = { - "TTO", &tto_unit, tto_reg, tto_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &tty_reset, - NULL, NULL, NULL, - NULL, 0 - }; - -/* Paper tape reader: IOT routine. Points to note: - - - RPA (but not RPB) complements the reader clutch control. Thus, - if the reader is running, RPA will stop it. - - The status bit indicates data in the reader buffer that has not - been transfered to IO. It is cleared by any RB->IO operation, - including RRB and the completion pulse. - - A reader error on a wait mode operation could hang the simulator. - IOH is set; any retry (without RESET) will be NOP'd. Accordingly, - the PTR service routine clears IOH on any error during a rpa/rpb i. -*/ - -int32 ptr (int32 inst, int32 dev, int32 dat) -{ -if (dev == 0030) { /* RRB */ - iosta = iosta & ~IOS_PTR; /* clear status */ - return ptr_unit.buf; /* return data */ - } -if (dev == 0002) /* RPB, mode = binary */ - ptr_state = 18; -else if (sim_is_active (&ptr_unit)) { /* RPA, running? */ - sim_cancel (&ptr_unit); /* stop reader */ - return dat; - } -else ptr_state = 0; /* mode = alpha */ -ptr_unit.buf = 0; /* clear buffer */ -if (inst & IO_WAIT) /* set ptr wait */ - ptr_wait = 1; -else ptr_wait = 0; /* from IR<5> */ -if (GEN_CPLS (inst)) { /* comp pulse? */ - ios = 0; - cpls = cpls | CPLS_PTR; - } -else cpls = cpls & ~CPLS_PTR; -sim_activate (&ptr_unit, ptr_unit.wait); /* start reader */ -return dat; -} - -/* Unit service */ - -t_stat ptr_svc (UNIT *uptr) -{ -int32 temp; - -if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */ - if (ptr_wait) /* if wait, clr ioh */ - ptr_wait = ioh = 0; - if ((cpls & CPLS_PTR) || ptr_stopioe) - return SCPE_UNATT; - return SCPE_OK; - } -if ((uptr->flags & UNIT_ASCII) && (ptr_state == 0)) /* ASCII mode, alpha read? */ - temp = ptr_get_ascii (uptr); /* get processed char */ -else if ((temp = getc (uptr->fileref)) != EOF) /* no, get raw char */ - uptr->pos = uptr->pos + 1; /* if not eof, count */ -if (temp == EOF) { /* end of file? */ - if (ptr_wait) /* if wait, clr ioh */ - ptr_wait = ioh = 0; - if (feof (uptr->fileref)) { - if ((cpls & CPLS_PTR) || ptr_stopioe) - sim_printf ("PTR end of file\n"); - else return SCPE_OK; - } - else perror ("PTR I/O error"); - clearerr (uptr->fileref); - return SCPE_IOERR; - } -if (ptr_state == 0) /* alpha */ - uptr->buf = temp & 0377; -else if (temp & 0200) { /* binary */ - ptr_state = ptr_state - 6; - uptr->buf = uptr->buf | ((temp & 077) << ptr_state); - } -if (ptr_state == 0) { /* done? */ - if (cpls & CPLS_PTR) { /* completion pulse? */ - iosta = iosta & ~IOS_PTR; /* clear flag */ - IO = uptr->buf; /* fill IO */ - ios = 1; /* restart */ - cpls = cpls & ~CPLS_PTR; - } - else { /* no, interrupt */ - iosta = iosta | IOS_PTR; /* set flag */ - dev_req_int (ptr_sbs); /* req interrupt */ - } - } -else sim_activate (uptr, uptr->wait); /* get next char */ -return SCPE_OK; -} - -/* Read next ASCII character */ - -int ptr_get_ascii (UNIT *uptr) -{ -int c; -int32 in; - -if (ptr_leader > 0) { /* leader? */ - ptr_leader = ptr_leader - 1; /* count down */ - return 0; - } -if (ptr_hold & CW) { /* char waiting? */ - in = ptr_hold & TT_WIDTH; /* return char */ - ptr_hold = 0; /* not waiting */ - } -else { - for (;;) { /* until valid char */ - if ((c = getc (uptr->fileref)) == EOF) { /* get next char, EOF? */ - ptr_leader = PTR_LEADER; /* set up for trailer */ - return FIODEC_STOP; /* return STOP */ - } - uptr->pos = uptr->pos + 1; /* count char */ - c = c & 0177; /* cut to 7b */ - if (c == '\n') /* NL -> CR */ - c = '\r'; - else if (c == '\r') /* ignore CR */ - continue; - in = ascii_to_fiodec[c]; /* convert char */ - if ((in == 0) && (c != ' ')) /* ignore unknowns */ - continue; - if ((in & BOTH) || ((in & UC) == ptr_uc)) /* case match? */ - in = in & TT_WIDTH; /* cut to 6b */ - else { /* no, case shift */ - ptr_hold = in | CW; /* set char waiting */ - ptr_uc = in & UC; /* set case */ - in = ptr_uc? FIODEC_UC: FIODEC_LC; /* return case */ - } /* end else */ - break; - } /* end for */ - } /* end else */ -in = in * 010040201; /* even parity from */ -in = in | 027555555400; /* HACKMEM 167 */ -in = in % (9 << 7); -return in & 0377; -} - -/* Reset routine */ - -t_stat ptr_reset (DEVICE *dptr) -{ -ptr_state = 0; /* clear state */ -ptr_wait = 0; -ptr_hold = 0; -ptr_uc = 0; -ptr_unit.buf = 0; -cpls = cpls & ~CPLS_PTR; -iosta = iosta & ~IOS_PTR; /* clear flag */ -sim_cancel (&ptr_unit); /* deactivate unit */ -return SCPE_OK; -} - -/* Attach routine */ - -t_stat ptr_attach (UNIT *uptr, char *cptr) -{ -ptr_leader = PTR_LEADER; /* set up leader */ -if (sim_switches & SWMASK ('A')) - uptr->flags = uptr->flags | UNIT_ASCII; -else uptr->flags = uptr->flags & ~UNIT_ASCII; -return attach_unit (uptr, cptr); -} - -/* Bootstrap routine */ - -int32 ptr_getw (UNIT *uptr) -{ -int32 i, tmp, word; - -for (i = word = 0; i < 3;) { - if ((tmp = getc (uptr->fileref)) == EOF) - return -1; - uptr->pos = uptr->pos + 1; - if (tmp & 0200) { - word = (word << 6) | (tmp & 077); - i++; - } - } -return word; -} - -t_stat ptr_boot (int32 unitno, DEVICE *dptr) -{ -int32 origin, val; -int32 fld = TA & EPCMASK; - -for (;;) { - if ((val = ptr_getw (&ptr_unit)) < 0) - return SCPE_FMT; - if (((val & 0760000) == OP_DIO) || /* DIO? */ - ((val & 0760000) == OP_DAC)) { /* hack - Macro1 err */ - origin = val & DAMASK; - if ((val = ptr_getw (&ptr_unit)) < 0) - return SCPE_FMT; - M[fld | origin] = val; - } - else if ((val & 0760000) == OP_JMP) { /* JMP? */ - PC = fld | (val & DAMASK); - break; - } - else return SCPE_FMT; /* bad instr */ - } -return SCPE_OK; /* done */ -} - -/* Paper tape punch: IOT routine */ - -int32 ptp (int32 inst, int32 dev, int32 dat) -{ -iosta = iosta & ~IOS_PTP; /* clear flag */ -ptp_unit.buf = (dev == 0006)? ((dat >> 12) | 0200): (dat & 0377); -if (GEN_CPLS (inst)) { /* comp pulse? */ - ios = 0; - cpls = cpls | CPLS_PTP; - } -else cpls = cpls & ~CPLS_PTP; -sim_activate (&ptp_unit, ptp_unit.wait); /* start unit */ -return dat; -} - -/* Unit service */ - -t_stat ptp_svc (UNIT *uptr) -{ -int32 c; - -if (cpls & CPLS_PTP) { /* completion pulse? */ - ios = 1; /* restart */ - cpls = cpls & ~CPLS_PTP; - } -iosta = iosta | IOS_PTP; /* set flag */ -dev_req_int (ptp_sbs); /* req interrupt */ -if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ - return IORETURN (ptp_stopioe, SCPE_UNATT); -if ((uptr->flags & UNIT_ASCII) != 0) { /* ASCII mode? */ - int32 c1 = uptr->buf & 077; - if (uptr->buf == 0) /* ignore nulls */ - return SCPE_OK; - if (c1 == FIODEC_UC) { /* UC? absorb */ - ptp_uc = UC; - return SCPE_OK; - } - else if (c1 == FIODEC_LC) { /* LC? absorb */ - ptp_uc = 0; - return SCPE_OK; - } - else c = fiodec_to_ascii[c1 | ptp_uc]; - if (c == 0) - return SCPE_OK; - if (c == '\n') { /* new line? */ - putc ('\r', uptr->fileref); /* cr first */ - uptr->pos = uptr->pos + 1; - } - } -else c = uptr->buf; -if (putc (c, uptr->fileref) == EOF) { /* I/O error? */ - perror ("PTP I/O error"); - clearerr (uptr->fileref); - return SCPE_IOERR; - } -uptr->pos = uptr->pos + 1; -return SCPE_OK; -} - -/* Reset routine */ - -t_stat ptp_reset (DEVICE *dptr) -{ -ptp_unit.buf = 0; /* clear state */ -ptp_uc = 0; -cpls = cpls & ~CPLS_PTP; -iosta = iosta & ~IOS_PTP; /* clear flag */ -sim_cancel (&ptp_unit); /* deactivate unit */ -return SCPE_OK; -} - -/* Attach routine */ - -t_stat ptp_attach (UNIT *uptr, char *cptr) -{ -if (sim_switches & SWMASK ('A')) - uptr->flags = uptr->flags | UNIT_ASCII; -else uptr->flags = uptr->flags & ~UNIT_ASCII; -return attach_unit (uptr, cptr); -} - -/* Typewriter IOT routines */ - -int32 tti (int32 inst, int32 dev, int32 dat) -{ -iosta = iosta & ~IOS_TTI; /* clear flag */ -if (inst & (IO_WAIT | IO_CPLS)) /* wait or sync? */ - return (STOP_RSRV << IOT_V_REASON) | (tty_buf & 077); -return tty_buf & 077; -} - -int32 tto (int32 inst, int32 dev, int32 dat) -{ -iosta = iosta & ~IOS_TTO; /* clear flag */ -tty_buf = dat & TT_WIDTH; /* load buffer */ -if (GEN_CPLS (inst)) { /* comp pulse? */ - ios = 0; - cpls = cpls | CPLS_TTO; - } -else cpls = cpls & ~CPLS_TTO; -sim_activate (&tto_unit, tto_unit.wait); /* activate unit */ -return dat; -} - -/* Unit service routines */ - -t_stat tti_svc (UNIT *uptr) -{ -int32 in, temp; - -sim_activate (uptr, uptr->wait); /* continue poll */ -if (tti_hold & CW) { /* char waiting? */ - tty_buf = tti_hold & TT_WIDTH; /* return char */ - tti_hold = 0; /* not waiting */ - } -else { - if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) - return temp; - if (temp & SCPE_BREAK) /* ignore break */ - return SCPE_OK; - temp = temp & 0177; - if (temp == 0177) /* rubout? bs */ - temp = '\b'; - sim_putchar (temp); /* echo */ - if (temp == '\r') /* cr? add nl */ - sim_putchar ('\n'); - in = ascii_to_fiodec[temp]; /* translate char */ - if (in == 0) /* no xlation? */ - return SCPE_OK; - if ((in & BOTH) || ((in & UC) == (tty_uc & UC))) - tty_buf = in & TT_WIDTH; - else { /* must shift */ - tty_uc = in & UC; /* new case */ - tty_buf = tty_uc? FIODEC_UC: FIODEC_LC; - tti_hold = in | CW; /* set 2nd waiting */ - } - } -iosta = iosta | IOS_TTI; /* set flag */ -dev_req_int (tti_sbs); /* req interrupt */ -PF = PF | PF_SS_1; /* set prog flag 1 */ -uptr->pos = uptr->pos + 1; -return SCPE_OK; -} - -void tto_puts (char *cptr) -{ -int32 c; - -while ((c = *cptr++) != 0) - sim_putchar (c); -return; -} - -t_stat tto_svc (UNIT *uptr) -{ -t_stat r; -int32 c; -static char *red_str = "[red]\r\n"; -static char *black_str = "[black]\r\n"; - -if (tty_buf == FIODEC_UC) /* upper case? */ - tty_uc = UC; -else if (tty_buf == FIODEC_LC) /* lower case? */ - tty_uc = 0; -else if (((uptr->flags & UNIT_ET) != 0) && /* ET ribbon chg? */ - ((tty_buf == FIODEC_BLACK) || (tty_buf == FIODEC_RED)) && - (tty_buf != tty_ribbon)) { - tto_puts ((tty_buf == FIODEC_RED)? red_str: black_str); - tty_ribbon = tty_buf; - } -else if (tty_buf == FIODEC_CR) - tto_puts ("\r\n"); -else { - c = fiodec_to_ascii[tty_buf | tty_uc]; /* translate */ - if ((c != 0) && ((r = sim_putchar_s (c)) != SCPE_OK)) { /* output; error? */ - sim_activate (uptr, uptr->wait); /* retry */ - return ((r == SCPE_STALL)? SCPE_OK: r); - } - } -if (cpls & CPLS_TTO) { /* completion pulse? */ - ios = 1; /* restart */ - cpls = cpls & ~CPLS_TTO; - } -iosta = iosta | IOS_TTO; /* set flag */ -dev_req_int (tto_sbs); /* req interrupt */ -uptr->pos = uptr->pos + 1; -return SCPE_OK; -} - -/* Reset routine */ - -t_stat tty_reset (DEVICE *dptr) -{ -tty_buf = 0; /* clear buffer */ -tty_ribbon = FIODEC_BLACK; /* start black */ -tty_uc = 0; /* clear case */ -tti_hold = 0; /* clear hold buf */ -cpls = cpls & ~CPLS_TTO; -iosta = (iosta & ~IOS_TTI) | IOS_TTO; /* clear flag */ -sim_activate (&tti_unit, tti_unit.wait); /* activate keyboard */ -sim_cancel (&tto_unit); /* stop printer */ -return SCPE_OK; -} diff --git a/PDP1/pdp1_sys.c b/PDP1/pdp1_sys.c deleted file mode 100644 index e0be5725..00000000 --- a/PDP1/pdp1_sys.c +++ /dev/null @@ -1,671 +0,0 @@ -/* pdp1_sys.c: PDP-1 simulator interface - - Copyright (c) 1993-2015, 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. - - 27-Mar-15 RMS Backported changes from GitHub master - 03-Jan-07 RMS Fixed bugs in block loader, char input - 21-Dec-06 RMS Added 16-channel sequence break support, PDP-1D support - 06-Apr-04 RMS Fixed bug in binary loader (found by Mark Crispin) - 08-Feb-04 PLB Merged display support - 08-Dec-03 RMS Added parallel drum support, drum mnemonics - 18-Oct-03 RMS Added DECtape off reel message - 01-Sep-03 RMS Added support for loading in multiple fields - 22-Jul-03 RMS Updated for "hardware" RIM loader - 05-Dec-02 RMS Added drum support - 21-Nov-02 RMS Changed typewriter to half duplex - 20-Aug-02 RMS Added DECtape support - 17-Sep-01 RMS Removed multiconsole support - 13-Jul-01 RMS Fixed RIM loader format - 27-May-01 RMS Added multiconsole support - 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 - 20-Oct-97 RMS Fixed endian-dependence in RIM loader - (found by Michael Somos) -*/ - -#include "pdp1_defs.h" -#include - -extern DEVICE cpu_dev; -extern DEVICE clk_dev; -extern DEVICE ptr_dev; -extern DEVICE ptp_dev; -extern DEVICE tti_dev; -extern DEVICE tto_dev; -extern DEVICE lpt_dev; -extern DEVICE dt_dev; -extern DEVICE drm_dev; -extern DEVICE drp_dev; -extern DEVICE dcs_dev, dcsl_dev; -#if defined(USE_DISPLAY) -extern DEVICE dpy_dev; -#endif -extern UNIT cpu_unit; -extern REG cpu_reg[]; -extern int32 M[]; -extern int32 PC; -extern int32 ascii_to_fiodec[], fiodec_to_ascii[]; -extern int32 sc_map[]; - -/* 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[] = "PDP-1"; - -REG *sim_PC = &cpu_reg[0]; - -int32 sim_emax = 1; - -DEVICE *sim_devices[] = { - &cpu_dev, - &clk_dev, - &ptr_dev, - &ptp_dev, - &tti_dev, - &tto_dev, - &lpt_dev, - &dt_dev, - &drm_dev, - &drp_dev, - &dcs_dev, - &dcsl_dev, -#if defined(USE_DISPLAY) - &dpy_dev, -#endif - NULL - }; - -const char *sim_stop_messages[] = { - "Unknown error", - "Undefined instruction", - "HALT instruction", - "Breakpoint", - "Nested XCT's", - "Nested indirect addresses", - "Infinite I/O wait state", - "DECtape off reel" - }; - -/* Binary loader - supports both RIM format and Macro block format */ - -int32 pdp1_getw (FILE *inf) -{ -int32 i, tmp, word; - -word = 0; -for (i = 0; i < 3;) { - if ((tmp = getc (inf)) == EOF) - return -1; - if (tmp & 0200) { - word = (word << 6) | (tmp & 077); - i++; - } - } -return word; -} - -t_stat rim_load (FILE *inf, int32 fld) -{ -int32 origin, val; - -for (;;) { - if ((val = pdp1_getw (inf)) < 0) - return SCPE_FMT; - if (((val & 0760000) == OP_DIO) || /* DIO? */ - ((val & 0760000) == OP_DAC)) { /* hack - Macro1 err */ - origin = val & DAMASK; - if ((val = pdp1_getw (inf)) < 0) - return SCPE_FMT; - M[fld | origin] = val; - } - else if ((val & 0760000) == OP_JMP) { /* JMP? */ - PC = fld | (val & DAMASK); - break; - } - else return SCPE_FMT; /* bad instr */ - } -return SCPE_OK; /* done */ -} - -t_stat blk_load (FILE *inf, int32 fld) -{ -int32 val, start, count, csum; - -for (;;) { - if ((val = pdp1_getw (inf)) < 0) /* get word, EOF? */ - return SCPE_FMT; - if ((val & 0760000) == OP_DIO) { /* DIO? */ - csum = val; /* init checksum */ - start = val & DAMASK; /* starting addr */ - if ((val = pdp1_getw (inf)) < 0) - return SCPE_FMT; - if ((val & 0760000) != OP_DIO) - return SCPE_FMT; - csum = csum + val; - if (csum > DMASK) - csum = (csum + 1) & DMASK; - count = (val & DAMASK) - start; /* block count */ - if (count <= 0) - return SCPE_FMT; - while (count--) { /* loop on data */ - if ((val = pdp1_getw (inf)) < 0) - return SCPE_FMT; - csum = csum + val; - if (csum > DMASK) - csum = (csum + 1) & DMASK; - M[fld | start] = val; - start = (start + 1) & DAMASK; - } - if ((val = pdp1_getw (inf)) < 0) - return SCPE_FMT; - if (val != csum) - return SCPE_CSUM; - } - else if ((val & 0760000) == OP_JMP) { /* JMP? */ - PC = fld | (val & DAMASK); - break; - } - else return SCPE_FMT; /* bad instr */ - } -return SCPE_OK; /* done */ -} - -t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) -{ -t_stat sta; -int32 fld; - -if (flag != 0) - return SCPE_ARG; -if (cptr && (*cptr != 0)) { - fld = get_uint (cptr, 8, AMASK, &sta); - if (sta != SCPE_OK) - return sta; - fld = fld & EPCMASK; - } -else fld = 0; -sta = rim_load (fileref, fld); -if (sta != SCPE_OK) - return sta; -if ((sim_switches & SWMASK ('B')) || match_ext (fnam, "BIN")) - return blk_load (fileref, fld); -return SCPE_OK; -} - -/* Symbol tables */ - -#define I_V_FL 18 /* inst class */ -#define I_M_FL 017 /* class mask */ -#define I_V_NPN 0 /* no operand */ -#define I_V_IOT 1 /* IOT */ -#define I_V_LAW 2 /* LAW */ -#define I_V_MRF 3 /* memory reference */ -#define I_V_MRI 4 /* mem ref no ind */ -#define I_V_OPR 5 /* OPR */ -#define I_V_SKP 6 /* skip */ -#define I_V_SHF 7 /* shift */ -#define I_V_SPC 8 /* special */ -#define I_NPN (I_V_NPN << I_V_FL) /* no operand */ -#define I_IOT (I_V_IOT << I_V_FL) /* IOT */ -#define I_LAW (I_V_LAW << I_V_FL) /* LAW */ -#define I_MRF (I_V_MRF << I_V_FL) /* memory reference */ -#define I_MRI (I_V_MRI << I_V_FL) /* mem ref no ind */ -#define I_OPR (I_V_OPR << I_V_FL) /* OPR */ -#define I_SKP (I_V_SKP << I_V_FL) /* skip */ -#define I_SHF (I_V_SHF << I_V_FL) /* shift */ -#define I_SPC (I_V_SPC << I_V_FL) - -static const int32 masks[] = { - 0777777, 0760077, 0760000, 0760000, - 0770000, 0760017, 0760077, 0777000, - 0760003 - }; - -static const char *opcode[] = { - "AND", "IOR", "XOR", "XCT", /* mem refs */ - "LAC", "LIO", "DAC", "DAP", - "DIP", "DIO", "DZM", "ADD", - "SUB", "IDX", "ISP", "SAD", - "SAS", "MUL", "DIV", "JMP", - "JSP", "LCH", "DCH", "TAD", - - "CAL", "JDA", /* mem ref no ind */ - - "LAW", - - "IOH", "RPA", "RPB", "RRB", /* I/O instructions */ - "PPA", "PPB", "TYO", "TYI", - "DPY", - "DSC", "ASC", "ISC", "CAC", - "LSM", "ESM", "CBS", - "LEM", "EEM", "CKS", - "MSE", "MLC", "MRD", "MWR", "MRS", - "DIA", "DBA", "DWC", "DRA", "DCL", - "DRD", "DWR", "DBL", "DCN", - "DTD", "DSE", "DSP", - "LRG", "ERG", "LRM", "ERM", - "RNM", "RSM", "RCK", "CTB", - "RCH", "RCC", "TCC", "TCB", - "RRC", "SSB", "RSC", - - "SKP", "SKP I", "CLO", /* base as NPNs */ - "SFT", "SPC", "OPR", - - "RAL", "RIL", "RCL", /* shifts */ - "SAL", "SIL", "SCL", - "RAR", "RIR", "RCR", - "SAR", "SIR", "SCR", - - "SZF1", "SZF2", "SZF3", /* skips */ - "SZF4", "SZF5", "SZF6", "SZF7", - "SZS1", "SZS1 SZF1", "SZS1 SZF2", "SZS1 SZ3", - "SZS1 SZF4", "SZS1 SZF5", "SZS1 SZF6", "SZS1 SZF7", - "SZS2", "SZS2 SZF1", "SZS2 SZF2", "SZS2 SZ3", - "SZS2 SZF4", "SZS2 SZF5", "SZS2 SZF6", "SZS2 SZF7", - "SZS3", "SZS3 SZF1", "SZS3 SZF2", "SZS3 SZ3", - "SZS3 SZF4", "SZS3 SZF5", "SZS3 SZF6", "SZS3 SZF7", - "SZS4", "SZS4 SZF1", "SZS4 SZF2", "SZS4 SZ3", - "SZS4 SZF4", "SZS4 SZF5", "SZS4 SZF6", "SZS4 SZF7", - "SZS5", "SZS5 SZF1", "SZS5 SZF2", "SZS5 SZ3", - "SZS5 SZF4", "SZS5 SZF5", "SZS5 SZF6", "SZS5 SZF7", - "SZS6", "SZS6 SZF1", "SZS6 SZF2", "SZS6 SZ3", - "SZS6 SZF4", "SZS6 SZF5", "SZS6 SZF6", "SZS6 SZF7", - "SZS7", "SZS7 SZF1", "SZS7 SZF2", "SZS7 SZ3", - "SZS7 SZF4", "SZS7 SZF5", "SZS7 SZF6", "SZS7 SZF7", - - "CLF1", "CLF2", "CLF3", /* operates */ - "CLF4", "CLF5", "CLF6", "CLF7", - "STF1", "STF2", "STF3", - "STF4", "STF5", "STF6", "STF7", - - "FF1", "FF2", "FF3", /* specials */ - - "SZA", "SPA", "SMA", /* uprog skips */ - "SZO", "SPI", "SNI", - "I", /* encode only */ - - "LIA", "LAI", "SWP", /* uprog opers */ - "LAP", "CLA", "HLT", - "CMA", "LAT", "CLI", - "CMI", - - "CML", "CLL", "SZL", /* uprog specials */ - "SCF", "SCI", "SCM", - "IDA", "IDC", "IFI", - "IIF", - - NULL, NULL, NULL, /* decode only */ - NULL, - }; - -static const int32 opc_val[] = { - 0020000+I_MRF, 0040000+I_MRF, 0060000+I_MRF, 0100000+I_MRF, - 0200000+I_MRF, 0220000+I_MRF, 0240000+I_MRF, 0260000+I_MRF, - 0300000+I_MRF, 0320000+I_MRF, 0340000+I_MRF, 0400000+I_MRF, - 0420000+I_MRF, 0440000+I_MRF, 0460000+I_MRF, 0500000+I_MRF, - 0520000+I_MRF, 0540000+I_MRF, 0560000+I_MRF, 0600000+I_MRF, - 0620000+I_MRF, 0120000+I_MRF, 0140000+I_MRF, 0360000+I_MRF, - - 0160000+I_MRI, 0170000+I_MRI, - - 0700000+I_LAW, - - 0730000+I_NPN, 0720001+I_IOT, 0720002+I_IOT, 0720030+I_IOT, - 0720005+I_IOT, 0720006+I_IOT, 0720003+I_IOT, 0720004+I_IOT, - 0720007+I_IOT, - 0720050+I_IOT, 0720051+I_IOT, 0720052+I_IOT, 0720053+I_NPN, - 0720054+I_NPN, 0720055+I_NPN, 0720056+I_NPN, - 0720074+I_NPN, 0724074+I_NPN, 0720033+I_NPN, - 0720301+I_NPN, 0720401+I_NPN, 0720501+I_NPN, 0720601+I_NPN, 0720701+I_NPN, - 0720061+I_NPN, 0722061+I_NPN, 0720062+I_NPN, 0722062+I_NPN, 0720063+I_NPN, - 0720161+I_NPN, 0721161+I_NPN, 0720162+I_NPN, 0721162+I_NPN, - 0720163+I_NPN, 0720164+I_NPN, 0721164+I_NPN, - 0720010+I_NPN, 0720011+I_NPN, 0720064+I_NPN, 0720065+I_NPN, - 0720066+I_IOT, 0720067+I_NPN, 0720032+I_NPN, 0720035+I_NPN, - 0720022+I_NPN, 0721022+I_NPN, 0725022+I_NPN, 0724022+I_NPN, - 0720122+I_NPN, 0724122+I_NPN, 0721122+I_NPN, - - 0640000+I_NPN, 0650000+I_NPN, 0651600+I_NPN, - 0660000+I_NPN, 0740000+I_NPN, 0760000+I_NPN, - - 0661000+I_SHF, 0662000+I_SHF, 0663000+I_SHF, - 0665000+I_SHF, 0666000+I_SHF, 0667000+I_SHF, - 0671000+I_SHF, 0672000+I_SHF, 0673000+I_SHF, - 0675000+I_SHF, 0676000+I_SHF, 0677000+I_SHF, - - 0640001+I_SKP, 0640002+I_SKP, 0640003+I_SKP, - 0640004+I_SKP, 0640005+I_SKP, 0640006+I_SKP, 0640007+I_SKP, - 0640010+I_SKP, 0640011+I_SKP, 0640012+I_SKP, 0640013+I_SKP, - 0640014+I_SKP, 0640015+I_SKP, 0640016+I_SKP, 0640017+I_SKP, - 0640020+I_SKP, 0640021+I_SKP, 0640022+I_SKP, 0640023+I_SKP, - 0640024+I_SKP, 0640025+I_SKP, 0640026+I_SKP, 0640027+I_SKP, - 0640030+I_SKP, 0640031+I_SKP, 0640032+I_SKP, 0640033+I_SKP, - 0640034+I_SKP, 0640035+I_SKP, 0640036+I_SKP, 0640037+I_SKP, - 0640040+I_SKP, 0640041+I_SKP, 0640042+I_SKP, 0640043+I_SKP, - 0640044+I_SKP, 0640045+I_SKP, 0640046+I_SKP, 0640047+I_SKP, - 0640050+I_SKP, 0640051+I_SKP, 0640052+I_SKP, 0640053+I_SKP, - 0640054+I_SKP, 0640055+I_SKP, 0640056+I_SKP, 0640057+I_SKP, - 0640060+I_SKP, 0640061+I_SKP, 0640062+I_SKP, 0640063+I_SKP, - 0640064+I_SKP, 0640065+I_SKP, 0640066+I_SKP, 0640067+I_SKP, - 0640070+I_SKP, 0640071+I_SKP, 0640072+I_SKP, 0640073+I_SKP, - 0640074+I_SKP, 0640075+I_SKP, 0640076+I_SKP, 0640077+I_SKP, - - 0760001+I_OPR, 0760002+I_OPR, 0760003+I_OPR, - 0760004+I_OPR, 0760005+I_OPR, 0760006+I_OPR, 0760007+I_OPR, - 0760011+I_OPR, 0760012+I_OPR, 0760013+I_OPR, - 0760014+I_OPR, 0760015+I_OPR, 0760016+I_OPR, 0760017+I_OPR, - - 0740001+I_SPC, 0740002+I_SPC, 0740003+I_OPR, - - 0640100+I_SKP, 0640200+I_SKP, 0640400+I_SKP, - 0641000+I_SKP, 0642000+I_SKP, 0644000+I_SKP, - 0010000+I_SKP, /* encode only */ - - 0760020+I_OPR, 0760040+I_OPR, 0760060+I_NPN, - 0760100+I_OPR, 0760200+I_OPR, 0760400+I_OPR, - 0761000+I_OPR, 0762000+I_OPR, 0764000+I_OPR, - 0770000+I_OPR, - - 0740004+I_SPC, 0740010+I_SPC, 0740020+I_SPC, - 0740040+I_SPC, 0740100+I_SPC, 0740200+I_SPC, - 0740400+I_SPC, 0741000+I_SPC, 0742000+I_SPC, - 0744000+I_SPC, - - 0640000+I_SKP, 0740000+I_SPC, 0760000+I_OPR, /* decode only */ - -1 - }; - -/* Operate or skip decode - - Inputs: - *of = output stream - inst = mask bits - class = instruction class code - sp = space needed? - Outputs: - status = space needed? -*/ - -int32 fprint_opr (FILE *of, int32 inst, int32 class, int32 sp) -{ -int32 i, j; - -for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ - j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */ - if ((j == class) && (opc_val[i] & inst)) { /* same class? */ - inst = inst & ~opc_val[i]; /* mask bit set? */ - fprintf (of, (sp? " %s": "%s"), opcode[i]); - sp = 1; - } - } -return sp; -} - -/* Symbolic decode - - Inputs: - *of = output stream - addr = current PC - *val = pointer to values - *uptr = pointer to unit - sw = switches - Outputs: - return = status code -*/ - -#define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x) -#define SIXTOASC(x) fiodec_to_ascii[x] -#define ASCTOSIX(x) (ascii_to_fiodec[x] & 077) - -t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, - UNIT *uptr, int32 sw) -{ -int32 cflag, i, j, sp, inst, disp, ma; - -inst = val[0]; -cflag = (uptr == NULL) || (uptr == &cpu_unit); -if (sw & SWMASK ('A')) { /* ASCII? */ - if (inst > 0377) - return SCPE_ARG; - fprintf (of, FMTASC (inst & 0177)); - return SCPE_OK; - } -if (sw & SWMASK ('F')) { - fputc (fiodec_to_ascii[inst & 077], of); - return SCPE_OK; - } -if (sw & SWMASK ('C')) { /* character? */ - fprintf (of, "%c", SIXTOASC ((inst >> 12) & 077)); - fprintf (of, "%c", SIXTOASC ((inst >> 6) & 077)); - fprintf (of, "%c", SIXTOASC (inst & 077)); - return SCPE_OK; - } -if (!(sw & SWMASK ('M'))) - return SCPE_ARG; - -/* Instruction decode */ - -disp = inst & 007777; -ma = (addr & EPCMASK) | disp; -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] & DMASK) == (inst & masks[j])) { /* match? */ - - switch (j) { /* case on class */ - - case I_V_NPN: /* no operands */ - fprintf (of, "%s", opcode[i]); /* opcode */ - break; - - case I_V_IOT: /* IOT */ - disp = (inst - opc_val[i]) & 017777; - if (disp == IA) - fprintf (of, "%s I", opcode[i]); - else if (disp) - fprintf (of, "%s %-o", opcode[i], disp); - else fprintf (of, "%s", opcode[i]); - break; - - case I_V_LAW: /* LAW */ - cflag = 0; /* fall thru to MRF */ - case I_V_MRF: /* mem ref */ - fprintf (of, "%s%s%-o", opcode[i], - ((inst & IA)? " I ": " "), (cflag? ma: disp)); - break; - - case I_V_MRI: /* mem ref no ind */ - fprintf (of, "%s %-o", opcode[i], (cflag? ma: disp)); - break; - - case I_V_OPR: /* operates */ - sp = fprint_opr (of, inst & 017760, j, 0); - if (opcode[i]) - fprintf (of, (sp? " %s": "%s"), opcode[i]); - break; - - case I_V_SKP: /* skips */ - sp = fprint_opr (of, inst & 007700, j, 0); - if (opcode[i]) - sp = fprintf (of, (sp? " %s": "%s"), opcode[i]); - if (inst & IA) - fprintf (of, sp? " I": "I"); - break; - - case I_V_SPC: /* specials */ - sp = fprint_opr (of, inst & 007774, j, 0); - if (opcode[i]) - sp = fprintf (of, (sp? " %s": "%s"), opcode[i]); - if (inst & IA) - fprintf (of, sp? " I": "I"); - break; - - case I_V_SHF: /* shifts */ - fprintf (of, "%s %-d", opcode[i], sc_map[inst & 0777]); - break; - } /* end case */ - - return SCPE_OK; - } /* end if */ - } /* end for */ -return SCPE_ARG; -} - -/* Get 18b signed number - - Inputs: - *cptr = pointer to input string - *sign = pointer to sign - *status = pointer to error status - Outputs: - val = output value -*/ - -t_value get_sint (char *cptr, int32 *sign, t_stat *status) -{ -*sign = 1; -if (*cptr == '+') { - *sign = 0; - cptr++; - } -else if (*cptr == '-') { - *sign = -1; - cptr++; - } -return get_uint (cptr, 8, DMASK, status); -} - -/* 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 -*/ - -t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) -{ -int32 cflag, d, i, j, k, sign; -t_stat r; -static int32 sc_enc[10] = { 0, 01, 03, 07, 017, 037, 077, 0177, 0377, 0777 }; -char gbuf[CBUFSIZE]; - -cflag = (uptr == NULL) || (uptr == &cpu_unit); -while (isspace (*cptr)) cptr++; -for (i = 1; (i < 3) && (cptr[i] != 0); i++) { - if (cptr[i] == 0) { - for (j = i + 1; j <= 3; j++) - cptr[j] = 0; - } - } -if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ - if (cptr[0] == 0) /* must have 1 char */ - return SCPE_ARG; - val[0] = (t_value) cptr[0]; - return SCPE_OK; - } -if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* sixbit string? */ - if (cptr[0] == 0) /* must have 1 char */ - return SCPE_ARG; - val[0] = ((ASCTOSIX (cptr[0]) & 077) << 12) | - ((ASCTOSIX (cptr[1]) & 077) << 6) | - (ASCTOSIX (cptr[2]) & 077); - 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] & DMASK; /* get value */ -j = (opc_val[i] >> I_V_FL) & I_M_FL; /* get class */ - -switch (j) { /* case on class */ - - case I_V_LAW: /* LAW */ - cflag = 0; /* fall through */ - case I_V_MRF: case I_V_MRI: /* mem ref */ - cptr = get_glyph (cptr, gbuf, 0); /* get next field */ - if ((j != I_V_MRI) && strcmp (gbuf, "I") == 0) { /* indirect? */ - val[0] = val[0] | IA; - cptr = get_glyph (cptr, gbuf, 0); - } - d = get_uint (gbuf, 8, AMASK, &r); - if (r != SCPE_OK) - return SCPE_ARG; - if (d <= DAMASK) - val[0] = val[0] | d; - else if (cflag && (((addr ^ d) & EPCMASK) == 0)) - val[0] = val[0] | (d & DAMASK); - else return SCPE_ARG; - break; - - case I_V_SHF: /* shift */ - cptr = get_glyph (cptr, gbuf, 0); - d = get_uint (gbuf, 10, 9, &r); - if (r != SCPE_OK) - return SCPE_ARG; - val[0] = val[0] | sc_enc[d]; - break; - - case I_V_NPN: case I_V_IOT: - case I_V_OPR: case I_V_SKP: case I_V_SPC: - for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0; - cptr = get_glyph (cptr, gbuf, 0)) { - for (i = 0; (opcode[i] != NULL) && - (strcmp (opcode[i], gbuf) != 0); i++) ; - if (opcode[i] != NULL) { - k = opc_val[i] & DMASK; - if ((k != IA) && (((k ^ val[0]) & 0760000) != 0)) - return SCPE_ARG; - val[0] = val[0] | k; - } - else { - d = get_sint (gbuf, &sign, &r); - if (r != SCPE_OK) - return SCPE_ARG; - if (sign == 0) - val[0] = val[0] + d; - else if (sign < 0) - val[0] = val[0] - d; - else val[0] = val[0] | d; - } - } - break; - } /* end case */ -if (*cptr != 0) /* junk at end? */ - return SCPE_ARG; -return SCPE_OK; -} diff --git a/PDP10/pdp10_bug_history.txt b/PDP10/pdp10_bug_history.txt deleted file mode 100644 index 3916d172..00000000 --- a/PDP10/pdp10_bug_history.txt +++ /dev/null @@ -1,28 +0,0 @@ -Bugs Found and Fixed During Simulator Debug - -1. pushj cleared T2 after setting it -2. if timer autoadjust is enabled, timer diagnostic may fail, - depending on host CPU speed -3. DFAD/DFSB should use FP_ONES instead of ONES -4. TLB physical address max = 1MW, tested in diagnostic -5. DPB does read/write, not read-modify/write -6. Fetch error takes priority over traps, due to prefetching - of next instruction -7. HSB is 36b, was 32b -8. CPU and PAG devices had mismatched types -9. non-zero sections in Tops-20 paging section indirect may - cause non-existent memory error, due to microcode "error" -10. PXCT test for user mode was backward -11. Timer interrupts were not implemented in Tops-20 indirect - chains -12. epta/upta hit known bug in VC++ implementation of 64b - data types -13. final W calculation in Tops-20 paging was incorrect -14. Timer representation lost sub msec values -15. UBA initialization reset the UBA itself -16. RHCS1: writing IE cannot trigger an interrupt -17. Tape bootstrap was set to 800bpi instead of 1600bpi -18. FIXR off by 1 in testing for lower limit to process -19. Indirect loops and XCT loops should run indefinitely, - test for interrupts on each memory reference - diff --git a/PDP10/pdp10_cpu.c b/PDP10/pdp10_cpu.c deleted file mode 100644 index 98d63c91..00000000 --- a/PDP10/pdp10_cpu.c +++ /dev/null @@ -1,2544 +0,0 @@ -/* pdp10_cpu.c: PDP-10 CPU simulator - - Copyright (c) 1993-2017, 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. - - cpu KS10 central processor - - 07-Sep-17 RMS Fixed sim_eval declaration in history routine (COVERITY) - 14-Jan-17 RMS Fixed bugs in 1-proceed - 09-Feb-16 RMS Fixed nested indirects and executes (Tim Litt) - 25-Mar-12 RMS Added missing parameters to prototypes (Mark Pizzolato) - 17-Jul-07 RMS Fixed non-portable usage in SHOW HISTORY - 28-Apr-07 RMS Removed clock initialization - 22-Sep-05 RMS Fixed declarations (Sterling Garwood) - Fixed warning in MOVNI - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 10-Nov-04 RMS Added instruction history - 08-Oct-02 RMS Revised to build dib_tab dynamically - Added SHOW IOSPACE - 30-Dec-01 RMS Added old PC queue - 25-Dec-01 RMS Cleaned up sim_inst declarations - 07-Dec-01 RMS Revised to use new breakpoint package - 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 - 19-May-01 RMS Added workaround for TOPS-20 V4.1 boot bug - 29-Apr-01 RMS Fixed modifier naming conflict - Fixed XCTR/XCTRI, UMOVE/UMOVEM, BLTUB/BLTBU for ITS - Added CLRCSH for ITS - - The 36b system family had six different implementions: PDP-6, KA10, KI10, - L10, KL10 extended, and KS10. This simulator implements the KS10. - - The register state for the KS10 is: - - AC[8][16] accumulators - PC program counter - flags<0:11> state flags - pi_enb<1:7> enabled PI levels - pi_act<1:7> active PI levels - pi_prq<1:7> program PI requests - apr_enb<0:7> enabled system flags - apr_flg<0:7> system flags - ebr executive base register - ubr user base register - hsb halt status block address - spt SPT base - cst CST base - pur process use register - cstm CST mask - - The PDP-10 had just two instruction formats: memory reference - and I/O. - - 000000000 0111 1 1111 112222222222333333 - 012345678 9012 3 4567 890123456789012345 - +---------+----+-+----+------------------+ - | opcode | ac |i| idx| address | memory reference - +---------+----+-+----+------------------+ - - 000 0000000 111 1 1111 112222222222333333 - 012 3456789 012 3 4567 890123456789012345 - +---+-------+---+-+----+------------------+ - |111|device |iop|i| idx| address | I/O - +---+-------+---+-+----+------------------+ - - This routine is the instruction decode routine for the PDP-10. - It is called from the simulator control program to execute - instructions in simulated memory, starting at the simulated PC. - It runs until an abort occurs. - - General notes: - - 1. Reasons to stop. The simulator can be stopped by: - - HALT instruction - MUUO instruction in executive mode - pager error in interrupt sequence - invalid vector table in interrupt sequence - illegal instruction in interrupt sequence - breakpoint encountered - nested indirects exceeding limit - nested XCT's exceeding limit - I/O error in I/O simulator - - 2. Interrupts. PDP-10's have a seven level priority interrupt - system. Interrupt requests can come from internal sources, - such as APR program requests, or external sources, such as - I/O devices. The requests are stored in pi_prq for program - requests, pi_apr for other internal flags, and pi_ioq for - I/O device flags. Internal and device (but not program) - interrupts must be enabled on a level by level basis. When - an interrupt is granted on a level, interrupts at that level - and below are masked until the interrupt is dismissed. - - The I/O device interrupt system is taken from the PDP-11. - int_req stores the interrupt requests for Unibus I/O devices. - Routines in the Unibus adapter map requests in int_req to - PDP-10 levels. The Unibus adapter also calculates which - device to get a vector from when a PDP-10 interrupt is granted. - - 3. Arithmetic. The PDP-10 is a 2's complement system. - - 4. Adding I/O devices. These modules must be modified: - - pdp10_defs.h add device address and interrupt definitions - pdp10_sys.c add sim_devices table entry - - A note on ITS 1-proceed. The simulator follows the implementation - on the KS10, keeping 1-proceed as a side flag (its_1pr) rather than - 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 PCQ_SIZE 64 /* must be 2**n */ -#define PCQ_MASK (PCQ_SIZE - 1) -#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC - -#define HIST_PC 0x40000000 -#define HIST_MIN 64 -#define HIST_MAX 65536 - -typedef struct { - a10 pc; - a10 ea; - d10 ir; - d10 ac; - } InstHistory; - -extern a10 fe_xct; /* Front-end forced XCT */ -extern DEVICE pag_dev; -extern t_stat pag_reset (DEVICE *dptr); - -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) */ -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 */ -d10 spt = 0; /* TOPS20 paging regs */ -d10 cst = 0; -d10 pur = 0; -d10 cstm = 0; -a10 dbr1 = 0; /* ITS paging regs */ -a10 dbr2 = 0; -a10 dbr3 = 0; -a10 dbr4 = 0; -d10 pcst = 0; /* ITS PC sampling */ -int32 pi_on = 0; /* pi system enable */ -int32 pi_enb = 0; /* pi enabled levels */ -int32 pi_act = 0; /* pi active levels */ -int32 pi_ioq = 0; /* pi io requests */ -int32 pi_apr = 0; /* pi apr requests */ -int32 pi_prq = 0; /* pi prog requests */ -int32 apr_enb = 0; /* apr enables */ -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 */ -int32 rlog = 0; /* extend fixup log */ -int32 ind_max = 0; /* nested ind limit */ -int32 xct_max = 0; /* nested XCT limit */ -int32 t20_idlelock = 0; /* TOPS-20 idle lock */ -a10 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ -int32 pcq_p = 0; /* PC queue ptr */ -REG *pcq_r = NULL; /* PC queue reg ptr */ -jmp_buf save_env; -int32 hst_p = 0; /* history pointer */ -int32 hst_lnt = 0; /* history length */ -InstHistory *hst = NULL; /* instruction history */ -int32 apr_serial = -1; /* CPU Serial number */ - -/* 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_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat cpu_set_serial (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_show_serial (FILE *st, UNIT *uptr, int32 val, void *desc); - -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 t_stat build_dib_tab (void); -extern t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc); -extern d10 Read (a10 ea, int32 prv); /* read, read check */ -extern d10 ReadM (a10 ea, int32 prv); /* read, write check */ -extern d10 ReadE (a10 ea); /* read, exec */ -extern d10 ReadP (a10 ea); /* read, physical */ -extern void Write (a10 ea, d10 val, int32 prv); /* write */ -extern void WriteE (a10 ea, d10 val); /* write, exec */ -extern void WriteP (a10 ea, d10 val); /* write, physical */ -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 (); -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 t_stat tim_set_mod (UNIT *uptr, int32 val, char *cptr, void *desc); - -/* CPU data structures - - cpu_dev CPU device descriptor - cpu_unit CPU unit - cpu_reg CPU register list - cpu_mod CPU modifier list -*/ - -UNIT cpu_unit = { UDATA (NULL, UNIT_FIX + UNIT_BINK, MAXMEMSIZE) }; - -REG cpu_reg[] = { - { ORDATA (PC, saved_PC, VASIZE) }, - { ORDATA (FLAGS, flags, 18) }, - { ORDATA (AC0, acs[0], 36) }, /* addr in memory */ - { ORDATA (AC1, acs[1], 36) }, /* modified at exit */ - { ORDATA (AC2, acs[2], 36) }, /* to SCP */ - { ORDATA (AC3, acs[3], 36) }, - { ORDATA (AC4, acs[4], 36) }, - { ORDATA (AC5, acs[5], 36) }, - { ORDATA (AC6, acs[6], 36) }, - { ORDATA (AC7, acs[7], 36) }, - { ORDATA (AC10, acs[10], 36) }, - { ORDATA (AC11, acs[11], 36) }, - { ORDATA (AC12, acs[12], 36) }, - { ORDATA (AC13, acs[13], 36) }, - { ORDATA (AC14, acs[14], 36) }, - { ORDATA (AC15, acs[15], 36) }, - { ORDATA (AC16, acs[16], 36) }, - { ORDATA (AC17, acs[17], 36) }, - { ORDATA (PFW, pager_word, 36) }, - { ORDATA (EBR, ebr, EBR_N_EBR) }, - { FLDATA (PGON, ebr, EBR_V_PGON) }, - { FLDATA (T20P, ebr, EBR_V_T20P) }, - { ORDATA (UBR, ubr, 36) }, - { GRDATA (CURAC, ubr, 8, 3, UBR_V_CURAC), REG_RO }, - { GRDATA (PRVAC, ubr, 8, 3, UBR_V_PRVAC) }, - { ORDATA (SPT, spt, 36) }, - { ORDATA (CST, cst, 36) }, - { ORDATA (PUR, pur, 36) }, - { ORDATA (CSTM, cstm, 36) }, - { ORDATA (HSB, hsb, 36) }, - { ORDATA (DBR1, dbr1, PASIZE) }, - { ORDATA (DBR2, dbr2, PASIZE) }, - { ORDATA (DBR3, dbr3, PASIZE) }, - { ORDATA (DBR4, dbr4, PASIZE) }, - { ORDATA (PCST, pcst, 36) }, - { ORDATA (PIENB, pi_enb, 7) }, - { FLDATA (PION, pi_on, 0) }, - { ORDATA (PIACT, pi_act, 7) }, - { ORDATA (PIPRQ, pi_prq, 7) }, - { ORDATA (PIIOQ, pi_ioq, 7), REG_RO }, - { ORDATA (PIAPR, pi_apr, 7), REG_RO }, - { ORDATA (APRENB, apr_enb, 8) }, - { ORDATA (APRFLG, apr_flg, 8) }, - { ORDATA (APRLVL, apr_lvl, 3) }, - { ORDATA (RLOG, rlog, 10) }, - { FLDATA (F1PR, its_1pr, 0) }, - { BRDATA (PCQ, pcq, 8, VASIZE, PCQ_SIZE), REG_RO+REG_CIRC }, - { ORDATA (PCQP, pcq_p, 6), REG_HRO }, - { DRDATA (INDMAX, ind_max, 8), PV_LEFT }, - { DRDATA (XCTMAX, xct_max, 8), PV_LEFT }, - { ORDATA (WRU, sim_int_char, 8) }, - { FLDATA (STOP_ILL, stop_op0, 0) }, - { BRDATA (REG, acs, 8, 36, AC_NUM * AC_NBLK) }, - { NULL } - }; - -MTAB cpu_mod[] = { - { UNIT_KLAD+UNIT_ITS+UNIT_T20, 0, "TOPS-10", "TOPS-10", &tim_set_mod }, - { UNIT_KLAD+UNIT_ITS+UNIT_T20, 0, NULL , "TOPS10", &tim_set_mod }, - { UNIT_KLAD+UNIT_ITS+UNIT_T20, UNIT_T20, "TOPS-20", "TOPS-20", &tim_set_mod }, - { UNIT_KLAD+UNIT_ITS+UNIT_T20, UNIT_T20, NULL, "TOPS20", &tim_set_mod }, - { UNIT_KLAD+UNIT_ITS+UNIT_T20, UNIT_ITS, "ITS", "ITS", &tim_set_mod }, - { UNIT_KLAD+UNIT_ITS+UNIT_T20, UNIT_KLAD, "diagnostic mode", "KLAD", &tim_set_mod }, - { MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "IOSPACE", NULL, - NULL, &show_iospace }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", - &cpu_set_hist, &cpu_show_hist }, - { MTAB_XTD|MTAB_VDV, 0, "SERIAL", "SERIAL", &cpu_set_serial, &cpu_show_serial }, - { 0 } - }; - -DEVICE cpu_dev = { - "CPU", &cpu_unit, cpu_reg, cpu_mod, - 1, 8, PASIZE, 1, 8, 36, - &cpu_ex, &cpu_dep, &cpu_reset, - NULL, NULL, NULL - }; - -/* Data arrays */ - -const int32 pi_l2bit[8] = { - 0, 0100, 0040, 0020, 0010, 0004, 0002, 0001 - }; - -const int32 pi_m2lvl[128] = { - 0, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 - }; - -const d10 bytemask[64] = { 0, - INT64_C(01), INT64_C(03), INT64_C(07), INT64_C(017), INT64_C(037), INT64_C(077), - INT64_C(0177), INT64_C(0377), INT64_C(0777), INT64_C(01777), INT64_C(03777), INT64_C(07777), - INT64_C(017777), INT64_C(037777), INT64_C(077777), - INT64_C(0177777), INT64_C(0377777), INT64_C(0777777), - INT64_C(01777777), INT64_C(03777777), INT64_C(07777777), - INT64_C(017777777), INT64_C(037777777), INT64_C(077777777), - INT64_C(0177777777), INT64_C(0377777777), INT64_C(0777777777), - INT64_C(01777777777), INT64_C(03777777777), INT64_C(07777777777), - INT64_C(017777777777), INT64_C(037777777777), INT64_C(077777777777), - INT64_C(0177777777777), INT64_C(0377777777777), INT64_C(0777777777777), - ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, - ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, - ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES, ONES - }; - -static t_bool (*io700d[16])(a10, int32) = { - &aprid, NULL, NULL, NULL, &wrapr, &rdapr, &czapr, &coapr, - NULL, NULL, NULL, NULL, &wrpi, &rdpi, &czpi, &copi - }; -static t_bool (*io701d[16])(a10, int32) = { - NULL, &rdubr, &clrpt, &wrubr, &wrebr, &rdebr, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL - }; -static t_bool (*io702d[16])(a10, int32) = { - &rdspb, &rdcsb, &rdpur, &rdcstm, &rdtim, &rdint, &rdhsb, NULL, - &wrspb, &wrcsb, &wrpur, &wrcstm, &wrtim, &wrint, &wrhsb, NULL - }; -#define io700i io700d -static t_bool (*io701i[16])(a10, int32) = { - &clrcsh, &rdubr, &clrpt, &wrubr, &wrebr, &rdebr, NULL, NULL, - NULL, &rdpcst, NULL, &wrpcst, NULL, NULL, NULL, NULL - }; -static t_bool (*io702i[16])(a10, int32) = { - &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 */ - -#define IM ((d10) ea) -#define IMS (((d10) ea) << 18) -#define JUMP(x) PCQ_ENTRY, PC = ((a10) (x)) & AMASK -#define SUBJ(x) CLRF (F_AFI | F_FPD | F_TR); JUMP (x) -#define INCPC PC = INCA (PC) - -/* AC operations */ - -#define AOBAC AC(ac) = AOB (AC(ac)) -#define SOBAC AC(ac) = SOB (AC(ac)) -#define G2AC rs[0] = AC(ac), rs[1] = AC(P1) -#define S1AC AC(ac) = rs[0] -#define S2AC S1AC, AC(P1) = rs[1] -#define LAC if (ac) AC(ac) = mb - -/* Memory operations */ - -#define RD mb = Read (ea, MM_OPND) -#define RDAC AC(ac) = Read (ea, MM_OPND) -#define RM mb = ReadM (ea, MM_OPND) -#define RMAC AC(ac) = ReadM (ea, MM_OPND) -#define RDP mb = Read (((a10) AC(ac)) & AMASK, MM_BSTK) -#define RD2 rs[0] = Read (ea, MM_OPND); \ - rs[1] = Read (INCA (ea), MM_OPND) -#define WR Write (ea, mb, MM_OPND) -#define WRAC Write (ea, AC(ac), MM_OPND) -#define WRP(x) Write (((a10) INCA (AC(ac))), (x), MM_BSTK) -#define WR1 Write (ea, rs[0], MM_OPND) -#define WR2 ReadM (INCA (ea), MM_OPND); \ - Write (ea, rs[0], MM_OPND); \ - Write (INCA (ea), rs[1], MM_OPND) - -/* Tests and compares */ - -#define TL(a) (TSTS (a) != 0) -#define TE(a) ((a) == 0) -#define TLE(a) (TL (a) || TE (a)) -#define TGE(a) (TSTS (a) == 0) -#define TN(a) ((a) != 0) -#define TG(a) (TGE (a) && TN (a)) -#define CL(a) ((TSTS (AC(ac) ^ a))? (a < AC(ac)): (AC(ac) < a)) -#define CE(a) (AC(ac) == a) -#define CLE(a) (CL (a) || CE (a)) -#define CGE(a) (!CL (a)) -#define CN(a) (AC(ac) != a) -#define CG(a) (CGE (a) && CN (a)) - -/* Word assemblies */ - -#define FLPC XWD (flags, PC) -#define UUOWORD (((d10) op) << INST_V_OP) | (((d10) ac) << INST_V_AC) | ea -#define APRHWORD ((apr_flg << APR_V_FLG) | (apr_lvl & APR_M_LVL) | \ - ((apr_flg & apr_enb)? APR_IRQ: 0)) -#define APRWORD ((apr_enb << (APR_V_FLG + 18)) | APRHWORD) -#define PIHWORD ((pi_act << PI_V_ACT) | (pi_on << PI_V_ON) | \ - (pi_enb << PI_V_ENB)) -#define PIWORD ((pi_prq << PI_V_PRQ) | PIHWORD) - -/* Instruction operations */ - -#define CIBP if (!TSTF (F_FPD)) { ibp (ea, pflgs); SETF (F_FPD); } -#define LDB AC(ac) = ldb (ea, pflgs) -#define DPB dpb (AC(ac), ea, pflgs) -#define FAD(s) fad (AC(ac), s, FALSE, 0) -#define FADR(s) fad (AC(ac), s, TRUE, 0) -#define FSB(s) fad (AC(ac), s, FALSE, 1) -#define FSBR(s) fad (AC(ac), s, TRUE, 1) -#define FMP(s) fmp (AC(ac), s, FALSE) -#define FMPR(s) fmp (AC(ac), s, TRUE) -#define FDV(s) fdv (AC(ac), s, rs, FALSE) -#define FDVR(s) fdv (AC(ac), s, rs, TRUE) -#define MOVN(s) NEG (s); MOVNF(s) -#define MOVM(s) ABS (s); MOVMF(s) -#define ADD(s) add (AC(ac), s) -#define SUB(s) sub (AC(ac), s) -#define IMUL(s) imul (AC(ac), s) -#define IDIV(s) idiv (AC(ac), s, rs) -#define MUL(s) mul (AC(ac), s, rs) -#define DIV(s) divi (ac, s, rs) -#define AOJ AC(ac) = INC (AC(ac)); INCF (AC(ac)) -#define AOS RM; mb = INC (mb); WR; INCF (mb); LAC -#define SOJ AC(ac) = DEC (AC(ac)); DECF (AC(ac)) -#define SOS RM; mb = DEC (mb); WR; DECF (mb); LAC -#define SETCA(s) ~AC(ac) & DMASK -#define SETCM(s) ~(s) & DMASK; -#define AND(s) AC(ac) & (s) -#define ANDCA(s) ~AC(ac) & (s) -#define ANDCM(s) AC(ac) & ~(s) -#define ANDCB(s) (~AC(ac) & ~(s)) & DMASK -#define IOR(s) AC(ac) | (s) -#define ORCA(s) (~AC(ac) | (s)) & DMASK -#define ORCM(s) (AC(ac) | ~(s)) & DMASK -#define ORCB(s) (~AC(ac) | ~(s)) & DMASK -#define XOR(s) AC(ac) ^ (s) -#define EQV(s) (~(AC(ac) ^ (s))) & DMASK -#define LL(s,d) ((s) & LMASK) | ((d) & RMASK) -#define RL(s,d) (((s) << 18) & LMASK) | ((d) & RMASK) -#define RR(s,d) ((s) & RMASK) | ((d) & LMASK) -#define LR(s,d) (((s) >> 18) & RMASK) | ((d) & LMASK) -#define LLO(s) ((s) & LMASK) | RMASK -#define RLO(s) (((s) << 18) & LMASK) | RMASK -#define RRO(s) ((s) & RMASK) | LMASK -#define LRO(s) (((s) >> 18) & RMASK) | LMASK -#define LLE(s) ((s) & LMASK) | (((s) & LSIGN)? RMASK: 0) -#define RLE(s) (((s) << 18) & LMASK) | (((s) & RSIGN)? RMASK: 0) -#define RRE(s) ((s) & RMASK) | (((s) & RSIGN)? LMASK: 0) -#define LRE(s) (((s) >> 18) & RMASK) | (((s) & LSIGN)? LMASK: 0) -#define TD_ RD -#define TS_ RD; mb = SWP (mb) -#define TL_ mb = IMS -#define TR_ mb = IM -#define T_Z AC(ac) = AC(ac) & ~mb -#define T_O AC(ac) = AC(ac) | mb -#define T_C AC(ac) = AC(ac) ^ mb -#define T__E if ((AC(ac) & mb) == 0) INCPC -#define T__N if ((AC(ac) & mb) != 0) INCPC -#define T__A INCPC -#define IOC if (TSTF (F_USR) && !TSTF (F_UIO)) goto MUUO; -#define IO7(x,y) IOC; fptr = ((Q_ITS)? x[ac]: y[ac]); \ - if (fptr == NULL) goto MUUO; \ - if (fptr (ea, MM_OPND)) INCPC; break; -#define IOA IOC; if (!Q_ITS) ea = calc_ioea (inst, pflgs) -#define IOAM IOC; ea = ((Q_ITS)? ((a10) Read (ea, MM_OPND)): \ - calc_ioea (inst, pflgs)) - -/* Flag tests */ - -#define MOVNF(x) if ((x) == MAXNEG) SETF (F_C1 | F_AOV | F_T1); \ - else if ((x) == 0) SETF (F_C0 | F_C1) -#define MOVMF(x) if ((x) == MAXNEG) SETF (F_C1 | F_AOV | F_T1) -#define INCF(x) if ((x) == 0) SETF (F_C0 | F_C1); \ - else if ((x) == MAXNEG) SETF (F_C1 | F_AOV | F_T1) -#define DECF(x) if ((x) == MAXPOS) SETF (F_C0 | F_AOV | F_T1); \ - else if ((x) != ONES) SETF (F_C0 | F_C1) -#define PUSHF if (LRZ (AC(ac)) == 0) SETF (F_T2) -#define POPF if (LRZ (AC(ac)) == RMASK) SETF (F_T2) -#define DMOVNF if (rs[1] == 0) { MOVNF (rs[0]); } - -t_value pdp10_pc_value (void) -{ -return (t_value)pager_PC; -} - -t_stat sim_instr (void) -{ -a10 PC; /* set by setjmp */ -int abortval = 0; /* abort value */ -t_stat r; - -/* Restore register state */ - -if ((r = build_dib_tab ()) != SCPE_OK) /* build, chk dib_tab */ - return r; -pager_PC = PC = saved_PC & AMASK; /* load local PC */ -set_dyn_ptrs (); /* set up local ptrs */ -pager_tc = FALSE; /* not in trap cycle */ -pager_pi = FALSE; /* not in pi sequence */ -rlog = 0; /* not in extend */ -pi_eval (); /* eval pi system */ -if (!Q_ITS) /* ~ITS, clr 1-proc */ - its_1pr = 0; -t20_idlelock = 0; /* clr T20 idle lock */ - -/* Abort handling - - Aborts may come from within the simulator to stop simulation (values > 0), - for page fails (values < 0), or for an interrupt check (value = 0). -*/ - -abortval = setjmp (save_env); /* set abort hdlr */ -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 */ - set_ac_display (ac_cur); /* set up AC display */ - pcq_r->qptr = pcq_p; /* update pc q ptr */ - return abortval; /* return to SCP */ - } - -/* 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) /* clean up extend */ - xtcln (rlog); - rlog = 0; /* clear log */ - if (pager_tc) /* trap? get flags */ - flags = pager_flags; - if (T20PAG) { /* TOPS-20 paging? */ - 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 (Q_ITS) { /* ITS? */ - ea = epta + EPT_ITS_PAG + (pi_m2lvl[pi_act] * 3); - if (its_1pr) /* store 1-proc */ - flags = flags | F_1PR; - 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)); - } - JUMP (mb); /* set new PC */ - set_newflags (mb, FALSE); /* set new flags */ - pi_eval (); /* eval pi system */ - } -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, its_2pr, pflgs; -a10 ea; -d10 inst, mb, indrct, rs[2]; -t_bool (*fptr)(int32, int32); - -pager_PC = PC; /* update pager PC */ -pager_tc = FALSE; /* not in trap cycle */ -pflgs = 0; /* not in PXCT */ -xct_cnt = 0; /* count XCT's */ -if (sim_interval <= 0) { /* check clock queue */ - /* make sure all useful state is in simh registers while processing events */ - saved_PC = pager_PC & AMASK; /* failing instr PC */ - set_ac_display (ac_cur); /* set up AC display */ - pcq_r->qptr = pcq_p; /* update pc q ptr */ - - if ((i = sim_process_event ())) /* error? stop sim */ - ABORT (i); - if (fe_xct) - qintr = -1; - else - pi_eval (); /* eval pi system */ - } - -/* PI interrupt (Unibus or system flags). - On the KS10, only JSR and XPCW are allowed as interrupt instructions. - Because of exec mode addressing, and unconditional processing of flags, - they are explicitly emulated here. Note that the KS microcode does not - perform an EA calc on interrupt instructions, which this emulation does. - This is an implementation restriction of the KS. The KS does not restrict - the CONSOLE EXECUTE function which is merged into this path in SimH. - - On a keep-alive failure, the console (fe) forces the CPU 'XCT' the - instruction at exec 71. This is close enough to an interrupt that it is - treated as one here. TOPS-10 and TOPS-20 use JSR or XPCW, which are - really the only sensible instructions, as diagnosing a KAF requires the - PC/FLAGS of the fault. - On a reload-request from the OS, the fe loads the bootstrap code and sets - saved_PC. Here, the CPU is partially reset and redirected. (Preserving - PC history, among other things.) The FE has already reset IO. -*/ - -if (qintr) { - int32 vec, uba; - pager_pi = TRUE; /* flag in pi seq */ - if (fe_xct) { /* Console forced execute? */ - qintr = 0; - if (fe_xct == 1) { /* Forced reload */ - PC = saved_PC; /* Bootstrap PC */ - pager_pi = FALSE; - ebr = ubr = 0; /* Exec mode, paging & PI off */ - pag_reset (&pag_dev); - pi_on = pi_enb = pi_act= pi_prq = - apr_enb = apr_flg = apr_lvl = its_1pr = 0; - rlog = 0; - set_newflags (0, FALSE); - fe_xct = 0; - continue; - } - inst = ReadE(fe_xct); /* Exec address of instruction */ - } else if ((vec = pi_ub_vec (qintr, &uba))) { /* Unibus interrupt? */ - mb = ReadP (epta + EPT_UBIT + uba); /* get dispatch table */ - if (mb == 0) /* invalid? stop */ - ABORT (STOP_ZERINT); - inst = ReadE ((((a10) mb) + (vec / 4)) & AMASK); - if (inst == 0) - ABORT (STOP_ZERINT); - } - else inst = ReadP (epta + EPT_PIIT + (2 * qintr)); - op = GET_OP (inst); /* get opcode */ - ac = GET_AC (inst); /* get ac */ - if (its_1pr && Q_ITS) { /* 1-proc set? */ - flags = flags | F_1PR; /* store 1-proc */ - its_1pr = 0; /* clear 1-proc */ - } - if (op == OP_JSR) { /* JSR? */ - d10 flpc = FLPC; - - set_newflags (0, FALSE); /* set new flags */ - ea = calc_ea (inst, MM_CUR); /* calc ea, cur mode */ - WriteE (ea, flpc); /* save flags+PC, exec */ - JUMP (INCA (ea)); /* PC = ea + 1 */ - } - else if ((op == OP_JRST) && (ac == AC_XPCW)) { /* XPCW? */ - d10 flz = XWD (flags, 0); - - set_newflags (0, FALSE); /* set exec flags */ - ea = calc_ea (inst, MM_CUR); /* calc ea, cur mode */ - WriteE (ea, flz); /* write flags, exec */ - WriteE (ADDA (ea, 1), PC); /* write PC, exec */ - rs[0] = ReadE (ADDA (ea, 2)); /* read new flags */ - rs[1] = ReadE (ADDA (ea, 3)); /* read new PC */ - JUMP (rs[1]); /* set new PC */ - set_newflags (rs[0], FALSE); /* set new flags */ - } - else { - fe_xct = 0; - ABORT (STOP_ILLINT); /* invalid instr */ - } - if (fe_xct) - fe_xct = 0; - else { - pi_act = pi_act | pi_l2bit[qintr]; /* set level active */ - pi_eval (); /* eval pi system */ - } - pager_pi = FALSE; /* end of sequence */ - if (sim_interval) /* charge for instr */ - sim_interval--; - continue; - } /* end if interrupt */ - -/* Traps fetch and execute an instruction from the current mode process table. - On the KS10, the fetch of the next instruction has started, and a page fail - trap on the instruction fetch takes precedence over the trap. During a trap, - flags are cleared before the execute, but if the execute aborts, they must - be restored. Also, the MUUO processor needs to know whether we are in a - trap sequence. Hence, trap in progress is recorded in pflgs, and the - traps for pager restoration are recorded in pager_flags. -*/ - -if (TSTF (F_T1 | F_T2) && PAGING) { - Read (pager_PC = PC, MM_CUR); /* test fetch */ - 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); - inst = ReadP (ea); /* get trap instr */ - CLRF (F_T1 | F_T2); /* clear flags */ - } - -/* Test for instruction breakpoint */ - -else { - if (sim_brk_summ && - sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ - ABORT (STOP_IBKPT); /* stop simulation */ - } - -/* Ready (at last) to get an instruction */ - - inst = Read (pager_PC = PC, MM_CUR); /* get instruction */ - INCPC; - sim_interval = sim_interval - 1; - } - -its_2pr = its_1pr; /* save 1-proc flag */ - -/* Execute instruction. XCT and PXCT also return here. */ - -XCT: -op = GET_OP (inst); /* get opcode */ -ac = GET_AC (inst); /* get AC */ -for (indrct = inst, i = 0; ; i++) { /* calc eff addr */ - ea = GET_ADDR (indrct); - xr = GET_XR (indrct); - if (xr) - ea = (ea + ((a10) XR (xr, MM_EA))) & AMASK; - if (TST_IND (indrct)) { /* indirect? */ - if (i != 0) { /* not first cycle? */ - int32 t = test_int (); /* test for intr */ - if (t != 0) /* err or intr? */ - ABORT (t); - if ((ind_max != 0) && (i >= ind_max)) /* limit exceeded? */ - ABORT (STOP_IND); - } - indrct = Read (ea, MM_EA); /* fetch indirect */ - } - else break; - } -if (hst_lnt) { /* history enabled? */ - hst_p = (hst_p + 1); /* next entry */ - if (hst_p >= hst_lnt) - hst_p = 0; - hst[hst_p].pc = pager_PC | HIST_PC; - hst[hst_p].ea = ea; - hst[hst_p].ir = inst; - hst[hst_p].ac = AC(ac); - } -switch (op) { /* case on opcode */ - -/* UUO's (0000 - 0077) - checked against KS10 ucode */ - -case 0000: if (stop_op0) { - ABORT (STOP_ILLEG); - } - goto MUUO; -case 0001: /* local UUO's */ -case 0002: -case 0003: -case 0004: -case 0005: -case 0006: -case 0007: -case 0010: -case 0011: -case 0012: -case 0013: -case 0014: -case 0015: -case 0016: -case 0017: -case 0020: -case 0021: -case 0022: -case 0023: -case 0024: -case 0025: -case 0026: -case 0027: -case 0030: -case 0031: -case 0032: -case 0033: -case 0034: -case 0035: -case 0036: -case 0037: Write (040, UUOWORD, MM_CUR); /* store op, ac, ea */ - inst = Read (041, MM_CUR); /* get new instr */ - goto XCT; - -/* case 0040 - 0077: MUUO's, handled by default at end of case */ - -/* Floating point, bytes, multiple precision (0100 - 0177) */ - -/* case 0100: MUUO *//* UJEN */ -/* case 0101: MUUO *//* unassigned */ -case 0102: if (Q_ITS && !TSTF (F_USR)) { /* GFAD (KL), XCTRI (ITS) */ - inst = Read (ea, MM_OPND); - pflgs = pflgs | ac; - goto XCT; - } - goto MUUO; -case 0103: if (Q_ITS && !TSTF (F_USR)) { /* GFSB (KL), XCTR (ITS) */ - inst = Read (ea, MM_OPND); - pflgs = pflgs | ac; - goto XCT; - } - goto MUUO; -/* case 0104: MUUO *//* JSYS (T20) */ -case 0105: AC(ac) = adjsp (AC(ac), ea); break; /* ADJSP */ -/* case 0106: MUUO *//* GFMP (KL)*/ -/* case 0107: MUUO *//* GFDV (KL) */ -case 0110: RD2; dfad (ac, rs, 0); break; /* DFAD */ -case 0111: RD2; dfad (ac, rs, 1); break; /* DFSB */ -case 0112: RD2; dfmp (ac, rs); break; /* DFMP */ -case 0113: RD2; dfdv (ac, rs); break; /* DFDV */ -case 0114: RD2; dadd (ac, rs); break; /* DADD */ -case 0115: RD2; dsub (ac, rs); break; /* DSUB */ -case 0116: RD2; dmul (ac, rs); break; /* DMUL */ -case 0117: RD2; ddiv (ac, rs); break; /* DDIV */ -case 0120: RD2; S2AC; break; /* DMOVE */ -case 0121: RD2; DMOVN (rs); S2AC; DMOVNF; break; /* DMOVN */ -case 0122: RD; fix(ac, mb, 0); break; /* FIX */ -case 0123: st = xtend (ac, ea, pflgs); /* EXTEND */ - rlog = 0; /* clear log */ - switch (st) { - case XT_SKIP: - INCPC; - case XT_NOSK: - break; - default: - goto MUUO; - } - break; -case 0124: G2AC; WR2; break; /* DMOVEM */ -case 0125: G2AC; DMOVN (rs); WR2; DMOVNF; break; /* DMOVNM */ -case 0126: RD; fix (ac, mb, 1); break; /* FIXR */ -case 0127: RD; AC(ac) = fltr (mb); break; /* FLTR */ -/* case 0130: MUUO *//* UFA */ -/* case 0131: MUUO *//* DFN */ -case 0132: AC(ac) = fsc (AC(ac), ea); break; /* FSC */ -case 0133: if (!ac) /* IBP */ - ibp (ea, pflgs); - else adjbp (ac, ea, pflgs); break; -case 0134: CIBP; LDB; CLRF (F_FPD); break; /* ILBP */ -case 0135: LDB; break; /* LDB */ -case 0136: CIBP; DPB; CLRF (F_FPD); break; /* IDBP */ -case 0137: DPB; break; /* DPB */ -case 0140: RD; AC(ac) = FAD (mb); break; /* FAD */ -/* case 0141: MUUO *//* FADL */ -case 0142: RM; mb = FAD (mb); WR; break; /* FADM */ -case 0143: RM; AC(ac) = FAD (mb); WRAC; break; /* FADB */ -case 0144: RD; AC(ac) = FADR (mb); break; /* FADR */ -case 0145: AC(ac) = FADR (IMS); break; /* FADRI */ -case 0146: RM; mb = FADR (mb); WR; break; /* FADRM */ -case 0147: RM; AC(ac) = FADR (mb); WRAC; break; /* FADRB */ -case 0150: RD; AC(ac) = FSB (mb); break; /* FSB */ -/* case 0151: MUUO *//* FSBL */ -case 0152: RM; mb = FSB (mb); WR; break; /* FSBM */ -case 0153: RM; AC(ac) = FSB (mb); WRAC; break; /* FSBB */ -case 0154: RD; AC(ac) = FSBR (mb); break; /* FSBR */ -case 0155: AC(ac) = FSBR (IMS); break; /* FSBRI */ -case 0156: RM; mb = FSBR (mb); WR; break; /* FSBRM */ -case 0157: RM; AC(ac) = FSBR (mb); WRAC; break; /* FSBRB */ -case 0160: RD; AC(ac) = FMP (mb); break; /* FMP */ -/* case 0161: MUUO *//* FMPL */ -case 0162: RM; mb = FMP (mb); WR; break; /* FMPM */ -case 0163: RM; AC(ac) = FMP (mb); WRAC; break; /* FMPB */ -case 0164: RD; AC(ac) = FMPR (mb); break; /* FMPR */ -case 0165: AC(ac) = FMPR (IMS); break; /* FMPRI */ -case 0166: RM; mb = FMPR (mb); WR; break; /* FMPRM */ -case 0167: RM; AC(ac) = FMPR (mb); WRAC; break; /* FMPRB */ -case 0170: RD; if (FDV (mb)) S1AC; break; /* FDV */ -/* case 0171: MUUO *//* FDVL */ -case 0172: RM; if (FDV (mb)) WR1; break; /* FDVM */ -case 0173: RM; if (FDV (mb)) { S1AC; WRAC; } break; /* FDVB */ -case 0174: RD; if (FDVR (mb)) S1AC; break; /* FDVR */ -case 0175: if (FDVR (IMS)) S1AC; break; /* FDVRI */ -case 0176: RM; if (FDVR (mb)) WR1; break; /* FDVRM */ -case 0177: RM; if (FDVR (mb)) { S1AC; WRAC; } break; /* FDVRB */ - -/* Move, arithmetic, shift, and jump (0200 - 0277) - - Note that instructions which modify the flags and store a - result in memory must prove the writeability of the result - location before modifying the flags. Also, 0247 and 0257, - if not implemented, are nops, not MUUO's. -*/ - -case 0200: RDAC; break; /* MOVE */ -case 0201: AC(ac) = ea; break; /* MOVEI */ -case 0202: WRAC; break; /* MOVEM */ -case 0203: RM; LAC; break; /* MOVES */ -case 0204: RD; AC(ac) = SWP (mb); break; /* MOVS */ -case 0205: AC(ac) = IMS; break; /* MOVSI */ -case 0206: mb = SWP (AC(ac)); WR; break; /* MOVSM */ -case 0207: RM; mb = SWP (mb); WR; LAC; break; /* MOVSS */ -case 0210: RD; AC(ac) = MOVN (mb); break; /* MOVN */ -case 0211: AC(ac) = NEG (IM); /* MOVNI */ - if (AC(ac) == 0) SETF (F_C0 | F_C1); - break; -case 0212: RM; mb = MOVN (AC(ac)); WR; break; /* MOVNM */ -case 0213: RM; mb = MOVN (mb); WR; LAC; break; /* MOVNS */ -case 0214: RD; AC(ac) = MOVM (mb); break; /* MOVM */ -case 0215: AC(ac) = ea; break; /* MOVMI */ -case 0216: RM; mb = MOVM (AC(ac)); WR; break; /* MOVMM */ -case 0217: RM; mb = MOVM (mb); WR; LAC; break; /* MOVMS */ -case 0220: RD; AC(ac) = IMUL (mb); break; /* IMUL */ -case 0221: AC(ac) = IMUL (IM); break; /* IMULI */ -case 0222: RM; mb = IMUL (mb); WR; break; /* IMULM */ -case 0223: RM; AC(ac) = IMUL (mb); WRAC; break; /* IMULB */ -case 0224: RD; MUL (mb); S2AC; break; /* MUL */ -case 0225: MUL (IM); S2AC; break; /* MULI */ -case 0226: RM; MUL (mb); WR1; break; /* MULM */ -case 0227: RM; MUL (mb); WR1; S2AC; break; /* MULB */ -case 0230: RD; if (IDIV (mb)) S2AC; break; /* IDIV */ -case 0231: if (IDIV (IM)) S2AC; break; /* IDIVI */ -case 0232: RM; if (IDIV (mb)) WR1; break; /* IDIVM */ -case 0233: RM; if (IDIV (mb)) { WR1; S2AC; } break; /* IDIVB */ -case 0234: RD; if (DIV (mb)) S2AC; break; /* DIV */ -case 0235: if (DIV (IM)) S2AC; break; /* DIVI */ -case 0236: RM; if (DIV (mb)) WR1; break; /* DIVM */ -case 0237: RM; if (DIV (mb)) { WR1; S2AC; } break; /* DIVB */ -case 0240: AC(ac) = ash (AC(ac), ea); break; /* ASH */ -case 0241: AC(ac) = rot (AC(ac), ea); break; /* ROT */ -case 0242: AC(ac) = lsh (AC(ac), ea); break; /* LSH */ -case 0243: AC(P1) = jffo (AC(ac)); /* JFFO */ - if (AC(ac)) JUMP (ea); - break; -case 0244: ashc (ac, ea); break; /* ASHC */ -case 0245: rotc (ac, ea); break; /* ROTC */ -case 0246: lshc (ac, ea); break; /* LSHC */ -case 0247: if (Q_ITS) circ (ac, ea); break; /* (ITS) CIRC */ -case 0250: RM; WRAC; AC(ac) = mb; break; /* EXCH */ -case 0251: blt (ac, ea, pflgs); break; /* BLT */ -case 0252: AOBAC; if (TGE (AC(ac))) JUMP (ea); break; /* AOBJP */ -case 0253: AOBAC; if (TL (AC(ac))) JUMP (ea); break; /* AOBJN */ -/* case 0254: *//* shown later *//* JRST */ -case 0255: if (flags & (ac << 14)) { /* JFCL */ - JUMP (ea); - CLRF (ac << 14); - } - break; -case 0256: if (xct_cnt++ != 0) { /* XCT: not first? */ - int32 t = test_int (); /* test for intr */ - if (t != 0) /* intr or err? */ - ABORT (t); - if ((xct_max != 0) && (xct_cnt >= xct_max)) - ABORT (STOP_XCT); - } - inst = Read (ea, MM_OPND); /* get opnd */ - if (ac && !TSTF (F_USR) && !Q_ITS) /* PXCT? */ - pflgs = pflgs | ac; - goto XCT; -case 0257: if (Q_ITS) goto MUUO; /* MAP */ - AC(ac) = map (ea, MM_OPND); - break; -case 0260: WRP (FLPC); AOBAC; /* PUSHJ */ - SUBJ (ea); PUSHF; break; -case 0261: RD; WRP (mb); AOBAC; PUSHF; break; /* PUSH */ -case 0262: RDP; WR; SOBAC; POPF; break; /* POP */ -case 0263: RDP; JUMP (mb); SOBAC; POPF; break; /* POPJ */ -case 0264: Write (ea, FLPC, MM_OPND); /* JSR */ - SUBJ (INCR (ea)); break; -case 0265: AC(ac) = FLPC; SUBJ (ea); break; /* JSP */ -case 0266: WRAC; AC(ac) = XWD (ea, PC); /* JSA */ - JUMP (INCR (ea)); break; -case 0267: AC(ac) = Read ((a10) LRZ (AC(ac)), MM_OPND);/* JRA */ - JUMP (ea); break; -case 0270: RD; AC(ac) = ADD (mb); break; /* ADD */ -case 0271: AC(ac) = ADD (IM); break; /* ADDI */ -case 0272: RM; mb = ADD (mb); WR; break; /* ADDM */ -case 0273: RM; AC(ac) = ADD (mb); WRAC; break; /* ADDB */ -case 0274: RD; AC(ac) = SUB (mb); break; /* SUB */ -case 0275: AC(ac) = SUB (IM); break; /* SUBI */ -case 0276: RM; mb = SUB (mb); WR; break; /* SUBM */ -case 0277: RM; AC(ac) = SUB (mb); WRAC; break; /* SUBB */ - -/* Compare, jump, skip instructions (0300 - 0377) - checked against KS10 ucode */ - -case 0300: break; /* CAI */ -case 0301: if (CL (IM)) INCPC; break; /* CAIL */ -case 0302: if (CE (IM)) INCPC; break; /* CAIE */ -case 0303: if (CLE (IM)) INCPC; break; /* CAILE */ -case 0304: INCPC; break; /* CAIA */ -case 0305: if (CGE (IM)) INCPC; break; /* CAIGE */ -case 0306: if (CN (IM)) INCPC; break; /* CAIN */ -case 0307: if (CG (IM)) INCPC; break; /* CAIG */ -case 0310: RD; break; /* CAM */ -case 0311: RD; if (CL (mb)) INCPC; break; /* CAML */ -case 0312: RD; if (CE (mb)) INCPC; break; /* CAME */ -case 0313: RD; if (CLE (mb)) INCPC; break; /* CAMLE */ -case 0314: RD; INCPC; break; /* CAMA */ -case 0315: RD; if (CGE (mb)) INCPC; break; /* CAMGE */ -case 0316: RD; if (CN (mb)) INCPC; break; /* CAMN */ -case 0317: RD; if (CG (mb)) INCPC; break; /* CAMG */ -case 0320: break; /* JUMP */ -case 0321: if (TL (AC(ac))) JUMP (ea); break; /* JUMPL */ -case 0322: if (TE (AC(ac))) JUMP (ea); break; /* JUMPE */ -case 0323: if (TLE( AC(ac))) JUMP (ea); break; /* JUMPLE */ -case 0324: JUMP (ea); break; /* JUMPA */ -case 0325: if (TGE (AC(ac))) JUMP (ea); break; /* JUMPGE */ -case 0326: if (TN (AC(ac))) JUMP (ea); break; /* JUMPN */ -case 0327: if (TG (AC(ac))) JUMP (ea); break; /* JUMPG */ -case 0330: RD; LAC; break; /* SKIP */ -case 0331: RD; LAC; if (TL (mb)) INCPC; break; /* SKIPL */ -case 0332: RD; LAC; if (TE (mb)) INCPC; break; /* SKIPE */ -case 0333: RD; LAC; if (TLE (mb)) INCPC; break; /* SKIPLE */ -case 0334: RD; LAC; INCPC; break; /* SKIPA */ -case 0335: RD; LAC; if (TGE (mb)) INCPC; break; /* SKIPGE */ -case 0336: RD; LAC; if (TN (mb)) INCPC; break; /* SKIPN */ -case 0337: RD; LAC; if (TG (mb)) INCPC; break; /* SKIPG */ -case 0340: AOJ; break; /* AOJ */ -case 0341: AOJ; if (TL (AC(ac))) JUMP (ea); break; /* AOJL */ -case 0342: AOJ; if (TE (AC(ac))) JUMP (ea); break; /* AOJE */ -case 0343: AOJ; if (TLE (AC(ac))) JUMP (ea); break; /* AOJLE */ -case 0344: AOJ; JUMP(ea); /* AOJA */ - if (Q_ITS && Q_IDLE && /* ITS idle? */ - TSTF (F_USR) && (pager_PC == 017) && /* user mode, loc 17? */ - (ac == 0) && (ea == 017)) /* AOJA 0,17? */ - sim_idle (0, FALSE); - break; -case 0345: AOJ; if (TGE (AC(ac))) JUMP (ea); break; /* AOJGE */ -case 0346: AOJ; if (TN (AC(ac))) JUMP (ea); break; /* AOJN */ -case 0347: AOJ; if (TG (AC(ac))) JUMP (ea); break; /* AOJG */ -case 0350: AOS; break; /* AOS */ -case 0351: AOS; if (TL (mb)) INCPC; break; /* AOSL */ -case 0352: AOS; if (TE (mb)) INCPC; break; /* AOSE */ -case 0353: AOS; if (TLE (mb)) INCPC; break; /* AOSLE */ -case 0354: AOS; INCPC; break; /* AOSA */ -case 0355: AOS; if (TGE (mb)) INCPC; break; /* AOSGE */ -case 0356: AOS; if (TN (mb)) INCPC; break; /* AOSN */ -case 0357: AOS; if (TG (mb)) INCPC; break; /* AOSG */ -case 0360: SOJ; break; /* SOJ */ -case 0361: SOJ; if (TL (AC(ac))) JUMP (ea); break; /* SOJL */ -case 0362: SOJ; if (TE (AC(ac))) JUMP (ea); break; /* SOJE */ -case 0363: SOJ; if (TLE (AC(ac))) JUMP (ea); break; /* SOJLE */ -case 0364: SOJ; JUMP(ea); break; /* SOJA */ -case 0365: SOJ; if (TGE (AC(ac))) JUMP (ea); break; /* SOJGE */ -case 0366: SOJ; if (TN (AC(ac))) JUMP (ea); break; /* SOJN */ -case 0367: SOJ; if (TG (AC(ac))) JUMP (ea); /* SOJG */ - if ((ea == pager_PC) && Q_IDLE) { /* to self, idle enab? */ - extern int32 tmr_poll; - if ((ac == 6) && (ea == 1) && /* SOJG 6,1? */ - TSTF (F_USR) && Q_T10) /* T10, user mode? */ - sim_idle (0, FALSE); - else if (!t20_idlelock && /* interlock off? */ - (ac == 2) && (ea == 3) && /* SOJG 2,3? */ - !TSTF (F_USR) && Q_T20 && /* T20, mon mode? */ - (sim_interval > (tmr_poll >> 1))) { /* >= half clock? */ - t20_idlelock = 1; /* set interlock */ - if (sim_os_ms_sleep (1)) /* sleep 1ms */ - sim_interval = 0; /* if ok, sched event */ - } - } - break; -case 0370: SOS; break; /* SOS */ -case 0371: SOS; if (TL (mb)) INCPC; break; /* SOSL */ -case 0372: SOS; if (TE (mb)) INCPC; break; /* SOSE */ -case 0373: SOS; if (TLE (mb)) INCPC; break; /* SOSLE */ -case 0374: SOS; INCPC; break; /* SOSA */ -case 0375: SOS; if (TGE (mb)) INCPC; break; /* SOSGE */ -case 0376: SOS; if (TN (mb)) INCPC; break; /* SOSN */ -case 0377: SOS; if (TG (mb)) INCPC; break; /* SOSG */ - -/* Boolean instructions (0400 - 0477) - checked against KS10 ucode - - Note that for boolean B, the initial read checks writeability of - the memory operand; hence, it is safe to modify the AC. -*/ - -case 0400: AC(ac) = 0; break; /* SETZ */ -case 0401: AC(ac) = 0; break; /* SETZI */ -case 0402: mb = 0; WR; break; /* SETZM */ -case 0403: mb = 0; WR; AC(ac) = 0; break; /* SETZB */ -case 0404: RD; AC(ac) = AND (mb); break; /* AND */ -case 0405: AC(ac) = AND (IM); break; /* ANDI */ -case 0406: RM; mb = AND (mb); WR; break; /* ANDM */ -case 0407: RM; AC(ac) = AND (mb); WRAC; break; /* ANDB */ -case 0410: RD; AC(ac) = ANDCA (mb); break; /* ANDCA */ -case 0411: AC(ac) = ANDCA (IM); break; /* ANDCAI */ -case 0412: RM; mb = ANDCA (mb); WR; break; /* ANDCAM */ -case 0413: RM; AC(ac) = ANDCA (mb); WRAC; break; /* ANDCAB */ -case 0414: RDAC; break; /* SETM */ -case 0415: AC(ac) = ea; break; /* SETMI */ -case 0416: RM; WR; break; /* SETMM */ -case 0417: RMAC; WRAC; break; /* SETMB */ -case 0420: RD; AC(ac) = ANDCM (mb); break; /* ANDCM */ -case 0421: AC(ac) = ANDCM (IM); break; /* ANDCMI */ -case 0422: RM; mb = ANDCM (mb); WR; break; /* ANDCMM */ -case 0423: RM; AC(ac) = ANDCM (mb); WRAC; break; /* ANDCMB */ -case 0424: break; /* SETA */ -case 0425: break; /* SETAI */ -case 0426: WRAC; break; /* SETAM */ -case 0427: WRAC; break; /* SETAB */ -case 0430: RD; AC(ac) = XOR (mb); break; /* XOR */ -case 0431: AC(ac) = XOR (IM); break; /* XORI */ -case 0432: RM; mb = XOR (mb); WR; break; /* XORM */ -case 0433: RM; AC(ac) = XOR (mb); WRAC; break; /* XORB */ -case 0434: RD; AC(ac) = IOR (mb); break; /* IOR */ -case 0435: AC(ac) = IOR (IM); break; /* IORI */ -case 0436: RM; mb = IOR (mb); WR; break; /* IORM */ -case 0437: RM; AC(ac) = IOR (mb); WRAC; break; /* IORB */ -case 0440: RD; AC(ac) = ANDCB (mb); break; /* ANDCB */ -case 0441: AC(ac) = ANDCB (IM); break; /* ANDCBI */ -case 0442: RM; mb = ANDCB (mb); WR; break; /* ANDCBM */ -case 0443: RM; AC(ac) = ANDCB (mb); WRAC; break; /* ANDCBB */ -case 0444: RD; AC(ac) = EQV (mb); break; /* EQV */ -case 0445: AC(ac) = EQV (IM); break; /* EQVI */ -case 0446: RM; mb = EQV (mb); WR; break; /* EQVM */ -case 0447: RM; AC(ac) = EQV (mb); WRAC; break; /* EQVB */ -case 0450: RD; AC(ac) = SETCA (mb); break; /* SETCA */ -case 0451: AC(ac) = SETCA (IM); break; /* SETCAI */ -case 0452: RM; mb = SETCA (mb); WR; break; /* SETCAM */ -case 0453: RM; AC(ac) = SETCA (mb); WRAC; break; /* SETCAB */ -case 0454: RD; AC(ac) = ORCA (mb); break; /* ORCA */ -case 0455: AC(ac) = ORCA (IM); break; /* ORCAI */ -case 0456: RM; mb = ORCA (mb); WR; break; /* ORCAM */ -case 0457: RM; AC(ac) = ORCA (mb); WRAC; break; /* ORCAB */ -case 0460: RD; AC(ac) = SETCM (mb); break; /* SETCM */ -case 0461: AC(ac) = SETCM (IM); break; /* SETCMI */ -case 0462: RM; mb = SETCM (mb); WR; break; /* SETCMM */ -case 0463: RM; AC(ac) = SETCM (mb); WRAC; break; /* SETCMB */ -case 0464: RD; AC(ac) = ORCM (mb); break; /* ORCM */ -case 0465: AC(ac) = ORCM (IM); break; /* ORCMI */ -case 0466: RM; mb = ORCM (mb); WR; break; /* ORCMM */ -case 0467: RM; AC(ac) = ORCM (mb); WRAC; break; /* ORCMB */ -case 0470: RD; AC(ac) = ORCB (mb); break; /* ORCB */ -case 0471: AC(ac) = ORCB (IM); break; /* ORCBI */ -case 0472: RM; mb = ORCB (mb); WR; break; /* ORCBM */ -case 0473: RM; AC(ac) = ORCB (mb); WRAC; break; /* ORCBB */ -case 0474: AC(ac) = ONES; break; /* SETO */ -case 0475: AC(ac) = ONES; break; /* SETOI */ -case 0476: mb = ONES; WR; break; /* SETOM */ -case 0477: mb = ONES; WR; AC(ac) = ONES; break; /* SETOB */ - -/* Halfword instructions (0500 - 0577) - checked against KS10 ucode */ - -case 0500: RD; AC(ac) = LL (mb, AC(ac)); break; /* HLL */ -case 0501: AC(ac) = LL (IM, AC(ac)); break; /* HLLI */ -case 0502: RM; mb = LL (AC(ac), mb); WR; break; /* HLLM */ -case 0503: RM; mb = LL (mb, mb); WR; LAC; break; /* HLLS */ -case 0504: RD; AC(ac) = RL (mb, AC(ac)); break; /* HRL */ -case 0505: AC(ac) = RL (IM, AC(ac)); break; /* HRLI */ -case 0506: RM; mb = RL (AC(ac), mb); WR; break; /* HRLM */ -case 0507: RM; mb = RL (mb, mb); WR; LAC; break; /* HRLS */ -case 0510: RD; AC(ac) = LLZ (mb); break; /* HLLZ */ -case 0511: AC(ac) = LLZ (IM); break; /* HLLZI */ -case 0512: mb = LLZ (AC(ac)); WR; break; /* HLLZM */ -case 0513: RM; mb = LLZ (mb); WR; LAC; break; /* HLLZS */ -case 0514: RD; AC(ac) = RLZ (mb); break; /* HRLZ */ -case 0515: AC(ac) = RLZ (IM); break; /* HRLZI */ -case 0516: mb = RLZ (AC(ac)); WR; break; /* HRLZM */ -case 0517: RM; mb = RLZ (mb); WR; LAC; break; /* HRLZS */ -case 0520: RD; AC(ac) = LLO (mb); break; /* HLLO */ -case 0521: AC(ac) = LLO (IM); break; /* HLLOI */ -case 0522: mb = LLO (AC(ac)); WR; break; /* HLLOM */ -case 0523: RM; mb = LLO (mb); WR; LAC; break; /* HLLOS */ -case 0524: RD; AC(ac) = RLO (mb); break; /* HRLO */ -case 0525: AC(ac) = RLO (IM); break; /* HRLOI */ -case 0526: mb = RLO (AC(ac)); WR; break; /* HRLOM */ -case 0527: RM; mb = RLO (mb); WR; LAC; break; /* HRLOS */ -case 0530: RD; AC(ac) = LLE (mb); break; /* HLLE */ -case 0531: AC(ac) = LLE (IM); break; /* HLLEI */ -case 0532: mb = LLE (AC(ac)); WR; break; /* HLLEM */ -case 0533: RM; mb = LLE (mb); WR; LAC; break; /* HLLES */ -case 0534: RD; AC(ac) = RLE (mb); break; /* HRLE */ -case 0535: AC(ac) = RLE (IM); break; /* HRLEI */ -case 0536: mb = RLE (AC(ac)); WR; break; /* HRLEM */ -case 0537: RM; mb = RLE (mb); WR; LAC; break; /* HRLES */ -case 0540: RD; AC(ac) = RR (mb, AC(ac)); break; /* HRR */ -case 0541: AC(ac) = RR (IM, AC(ac)); break; /* HRRI */ -case 0542: RM; mb = RR (AC(ac), mb); WR; break; /* HRRM */ -case 0543: RM; mb = RR (mb, mb); WR; LAC; break; /* HRRS */ -case 0544: RD; AC(ac) = LR (mb, AC(ac)); break; /* HLR */ -case 0545: AC(ac) = LR (IM, AC(ac)); break; /* HLRI */ -case 0546: RM; mb = LR (AC(ac), mb); WR; break; /* HLRM */ -case 0547: RM; mb = LR (mb, mb); WR; LAC; break; /* HLRS */ -case 0550: RD; AC(ac) = RRZ (mb); break; /* HRRZ */ -case 0551: AC(ac) = RRZ (IM); break; /* HRRZI */ -case 0552: mb = RRZ (AC(ac)); WR; break; /* HRRZM */ -case 0553: RM; mb = RRZ(mb); WR; LAC; break; /* HRRZS */ -case 0554: RD; AC(ac) = LRZ (mb); break; /* HLRZ */ -case 0555: AC(ac) = LRZ (IM); break; /* HLRZI */ -case 0556: mb = LRZ (AC(ac)); WR; break; /* HLRZM */ -case 0557: RM; mb = LRZ (mb); WR; LAC; break; /* HLRZS */ -case 0560: RD; AC(ac) = RRO (mb); break; /* HRRO */ -case 0561: AC(ac) = RRO (IM); break; /* HRROI */ -case 0562: mb = RRO (AC(ac)); WR; break; /* HRROM */ -case 0563: RM; mb = RRO (mb); WR; LAC; break; /* HRROS */ -case 0564: RD; AC(ac) = LRO (mb); break; /* HLRO */ -case 0565: AC(ac) = LRO (IM); break; /* HLROI */ -case 0566: mb = LRO (AC(ac)); WR; break; /* HLROM */ -case 0567: RM; mb = LRO (mb); WR; LAC; break; /* HLROS */ -case 0570: RD; AC(ac) = RRE (mb); break; /* HRRE */ -case 0571: AC(ac) = RRE (IM); break; /* HRREI */ -case 0572: mb = RRE (AC(ac)); WR; break; /* HRREM */ -case 0573: RM; mb = RRE (mb); WR; LAC; break; /* HRRES */ -case 0574: RD; AC(ac) = LRE (mb); break; /* HLRE */ -case 0575: AC(ac) = LRE (IM); break; /* HLREI */ -case 0576: mb = LRE (AC(ac)); WR; break; /* HLREM */ -case 0577: RM; mb = LRE (mb); WR; LAC; break; /* HLRES */ - -/* Test instructions (0600 - 0677) - checked against KS10 ucode - In the KS10 ucode, TDN and TSN do not fetch an operand; the Processor - Reference Manual describes them as NOPs that reference memory. -*/ - -case 0600: break; /* TRN */ -case 0601: break; /* TLN */ -case 0602: TR_; T__E; break; /* TRNE */ -case 0603: TL_; T__E; break; /* TLNE */ -case 0604: T__A; break; /* TRNA */ -case 0605: T__A; break; /* TLNA */ -case 0606: TR_; T__N; break; /* TRNN */ -case 0607: TL_; T__N; break; /* TLNN */ -case 0610: TD_; break; /* TDN */ -case 0611: TS_; break; /* TSN */ -case 0612: TD_; T__E; break; /* TDNE */ -case 0613: TS_; T__E; break; /* TSNE */ -case 0614: TD_; T__A; break; /* TDNA */ -case 0615: TS_; T__A; break; /* TSNA */ -case 0616: TD_; T__N; break; /* TDNN */ -case 0617: TS_; T__N; break; /* TSNN */ -case 0620: TR_; T_Z; break; /* TRZ */ -case 0621: TL_; T_Z; break; /* TLZ */ -case 0622: TR_; T__E; T_Z; break; /* TRZE */ -case 0623: TL_; T__E; T_Z; break; /* TLZE */ -case 0624: TR_; T__A; T_Z; break; /* TRZA */ -case 0625: TL_; T__A; T_Z; break; /* TLZA */ -case 0626: TR_; T__N; T_Z; break; /* TRZN */ -case 0627: TL_; T__N; T_Z; break; /* TLZN */ -case 0630: TD_; T_Z; break; /* TDZ */ -case 0631: TS_; T_Z; break; /* TSZ */ -case 0632: TD_; T__E; T_Z; break; /* TDZE */ -case 0633: TS_; T__E; T_Z; break; /* TSZE */ -case 0634: TD_; T__A; T_Z; break; /* TDZA */ -case 0635: TS_; T__A; T_Z; break; /* TSZA */ -case 0636: TD_; T__N; T_Z; break; /* TDZN */ -case 0637: TS_; T__N; T_Z; break; /* TSZN */ -case 0640: TR_; T_C; break; /* TRC */ -case 0641: TL_; T_C; break; /* TLC */ -case 0642: TR_; T__E; T_C; break; /* TRCE */ -case 0643: TL_; T__E; T_C; break; /* TLCE */ -case 0644: TR_; T__A; T_C; break; /* TRCA */ -case 0645: TL_; T__A; T_C; break; /* TLCA */ -case 0646: TR_; T__N; T_C; break; /* TRCN */ -case 0647: TL_; T__N; T_C; break; /* TLCN */ -case 0650: TD_; T_C; break; /* TDC */ -case 0651: TS_; T_C; break; /* TSC */ -case 0652: TD_; T__E; T_C; break; /* TDCE */ -case 0653: TS_; T__E; T_C; break; /* TSCE */ -case 0654: TD_; T__A; T_C; break; /* TDCA */ -case 0655: TS_; T__A; T_C; break; /* TSCA */ -case 0656: TD_; T__N; T_C; break; /* TDCN */ -case 0657: TS_; T__N; T_C; break; /* TSCN */ -case 0660: TR_; T_O; break; /* TRO */ -case 0661: TL_; T_O; break; /* TLO */ -case 0662: TR_; T__E; T_O; break; /* TROE */ -case 0663: TL_; T__E; T_O; break; /* TLOE */ -case 0664: TR_; T__A; T_O; break; /* TROA */ -case 0665: TL_; T__A; T_O; break; /* TLOA */ -case 0666: TR_; T__N; T_O; break; /* TRON */ -case 0667: TL_; T__N; T_O; break; /* TLON */ -case 0670: TD_; T_O; break; /* TDO */ -case 0671: TS_; T_O; break; /* TSO */ -case 0672: TD_; T__E; T_O; break; /* TDOE */ -case 0673: TS_; T__E; T_O; break; /* TSOE */ -case 0674: TD_; T__A; T_O; break; /* TDOA */ -case 0675: TS_; T__A; T_O; break; /* TSOA */ -case 0676: TD_; T__N; T_O; break; /* TDON */ -case 0677: TS_; T__N; T_O; break; /* TSON */ - -/* I/O instructions (0700 - 0777) - - Only the defined I/O instructions have explicit case labels; - the rest default to unimplemented (monitor UUO). Note that - 710-715 and 720-725 have different definitions under ITS and - use normal effective addresses instead of the special address - calculation required by TOPS-10 and TOPS-20. -*/ - -case 0700: IO7 (io700i, io700d); break; /* I/O 0 */ -case 0701: IO7 (io701i, io701d); break; /* I/O 1 */ -case 0702: IO7 (io702i, io702d); break; /* I/O 2 */ -case 0704: IOC; AC(ac) = Read (ea, OPND_PXCT); break; /* UMOVE */ -case 0705: IOC; Write (ea, AC(ac), OPND_PXCT); break; /* UMOVEM */ -case 0710: IOA; if (io710 (ac, ea)) INCPC; break; /* TIOE, IORDI */ -case 0711: IOA; if (io711 (ac, ea)) INCPC; break; /* TION, IORDQ */ -case 0712: IOAM; AC(ac) = io712 (ea); break; /* RDIO, IORD */ -case 0713: IOAM; io713 (AC(ac), ea); break; /* WRIO, IOWR */ -case 0714: IOA; io714 (AC(ac), ea); break; /* BSIO, IOWRI */ -case 0715: IOA; io715 (AC(ac), ea); break; /* BCIO, IOWRQ */ -case 0716: IOC; bltu (ac, ea, pflgs, 0); break; /* BLTBU */ -case 0717: IOC; bltu (ac, ea, pflgs, 1); break; /* BLTUB */ -case 0720: IOA; if (io720 (ac, ea)) INCPC; break; /* TIOEB, IORDBI */ -case 0721: IOA; if (io721 (ac, ea)) INCPC; break; /* TIONB, IORDBQ */ -case 0722: IOAM; AC(ac) = io722 (ea); break; /* RDIOB, IORDB */ -case 0723: IOAM; io723 (AC(ac), ea); break; /* WRIOB, IOWRB */ -case 0724: IOA; io724 (AC(ac), ea); break; /* BSIOB, IOWRBI */ -case 0725: IOA; io725 (AC(ac), ea); break; /* BCIOB, IOWRBQ */ - -/* If undefined, monitor UUO - checked against KS10 ucode - The KS10 implements a much more limited version of MUUO flag handling. - In the KS10, the trap ucode checks for opcodes 000-077. If the opcode - is in that range, the trap flags are not cleared. Instead, the MUUO - microcode stores the flags with traps cleared, and uses the trap flags - to determine how to vector. Thus, MUUO's >= 100 will vector incorrectly. -*/ - -default: -MUUO: - if (T20PAG) { /* TOPS20 paging? */ - 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 */ - WriteP (upta + UPT_MUPC, PC); /* store PC */ - WriteP (upta + UPT_T20_UEA, ea); /* store eff addr */ - WriteP (upta + UPT_T20_CTX, UBRWORD); /* store context */ - } - else { /* TOPS10/ITS */ - WriteP (upta + UPT_MUUO, UUOWORD); /* store instr word */ - WriteP (upta + UPT_MUPC, XWD ( /* store flags,,PC */ - 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) + - (pager_tc? UPT_NPCT: 0); /* calculate vector */ - mb = ReadP (ea); /* new flags, PC */ - JUMP (mb); /* set new PC */ - if (TSTF (F_USR)) /* set PCU */ - mb = mb | XWD (F_UIO, 0); - set_newflags (mb, FALSE); /* set new flags */ - break; - -/* JRST - checked against KS10 ucode - Differences from the KS10: the KS10 - - (JRSTF, JEN) refetches the base instruction from PC - 1 - - (XJEN) dismisses interrupt before reading the new flags and PC - - (XPCW) writes the old flags and PC before reading the new - ITS microcode includes extended JRST's, although they are not used -*/ - -case 0254: /* JRST */ - i = jrst_tab[ac]; /* get subop flags */ - if ((i == 0) || ((i == JRST_E) && TSTF (F_USR)) || - ((i == JRST_UIO) && TSTF (F_USR) && !TSTF (F_UIO))) - goto MUUO; /* not legal */ - switch (ac) { /* case on subopcode */ - - case 000: /* JRST 0 = jump */ - case 001: /* JRST 1 = portal */ - JUMP (ea); - break; - - case 002: /* JRST 2 = JRSTF */ - mb = calc_jrstfea (inst, pflgs); /* recalc addr w flgs */ - JUMP (ea); /* set new PC */ - set_newflags (mb, TRUE); /* set new flags */ - break; - - case 004: /* JRST 4 = halt */ - JUMP (ea); /* old_PC = halt + 1 */ - pager_PC = PC; /* force right PC */ - ABORT (STOP_HALT); /* known to be exec */ - break; - - case 005: /* JRST 5 = XJRSTF */ - RD2; /* read doubleword */ - JUMP (rs[1]); /* set new PC */ - set_newflags (rs[0], TRUE); /* set new flags */ - break; - - case 006: /* JRST 6 = XJEN */ - RD2; /* read doubleword */ - pi_dismiss (); /* page ok, dismiss */ - JUMP (rs[1]); /* set new PC */ - set_newflags (rs[0], FALSE); /* known to be exec */ - break; - - case 007: /* JRST 7 = XPCW */ - ea = ADDA (i = ea, 2); /* new flags, PC */ - RD2; /* read, test page fail */ - ReadM (INCA (i), MM_OPND); /* test PC write */ - Write (i, XWD (flags, 0), MM_OPND); /* write flags */ - Write (INCA (i), PC, MM_OPND); /* write PC */ - JUMP (rs[1]); /* set new PC */ - set_newflags (rs[0], FALSE); /* known to be exec */ - break; - - case 010: /* JRST 10 = dismiss */ - pi_dismiss (); /* dismiss int */ - JUMP (ea); /* set new PC */ - break; - - case 012: /* JRST 12 = JEN */ - mb = calc_jrstfea (inst, pflgs); /* recalc addr w flgs */ - JUMP (ea); /* set new PC */ - set_newflags (mb, TRUE); /* set new flags */ - pi_dismiss (); /* dismiss int */ - break; - - case 014: /* JRST 14 = SFM */ - Write (ea, XWD (flags, 0), MM_OPND); - break; - - case 015: /* JRST 15 = XJRST */ - if (!T20PAG) /* only in TOPS20 paging */ - goto MUUO; - 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 (Q_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, FALSE); /* set new flags */ - } - } /* end if 2-proc */ -} /* end for */ - -/* Should never get here */ - -ABORT (STOP_UNKNOWN); -} - -/* Single word integer routines */ - -/* Integer add - - Truth table for integer add - - case a b r flags - 1 + + + none - 2 + + - AOV + C1 - 3 + - + C0 + C1 - 4 + - - - - 5 - + + C0 + C1 - 6 - + - - - 7 - - + AOV + C0 - 8 - - - C0 + C1 -*/ - -d10 add (d10 a, d10 b) -{ -d10 r; - -r = (a + b) & DMASK; -if (TSTS (a & b)) { /* cases 7,8 */ - if (TSTS (r)) /* case 8 */ - SETF (F_C0 | F_C1); - else SETF (F_C0 | F_AOV | F_T1); /* case 7 */ - return r; - } -if (!TSTS (a | b)) { /* cases 1,2 */ - if (TSTS (r)) /* case 2 */ - SETF (F_C1 | F_AOV | F_T1); - return r; /* case 1 */ - } -if (!TSTS (r)) /* cases 3,5 */ - SETF (F_C0 | F_C1); -return r; -} - -/* Integer subtract - actually ac + ~op + 1 */ - -d10 sub (d10 a, d10 b) -{ -d10 r; - -r = (a - b) & DMASK; -if (TSTS (a & ~b)) { /* cases 7,8 */ - if (TSTS (r)) /* case 8 */ - SETF (F_C0 | F_C1); - else SETF (F_C0 | F_AOV | F_T1); /* case 7 */ - return r; - } -if (!TSTS (a | ~b)) { /* cases 1,2 */ - if (TSTS (r)) /* case 2 */ - SETF (F_C1 | F_AOV | F_T1); - return r; /* case 1 */ - } -if (!TSTS (r)) /* cases 3,5 */ - SETF (F_C0 | F_C1); -return r; -} - - -/* Logical shift */ - -d10 lsh (d10 val, a10 ea) -{ -int32 sc = LIT8 (ea); - -if (sc > 35) - return 0; -if (ea & RSIGN) - return (val >> sc); -return ((val << sc) & DMASK); -} - -/* Rotate */ - -d10 rot (d10 val, a10 ea) -{ -int32 sc = LIT8 (ea) % 36; - -if (sc == 0) - return val; -if (ea & RSIGN) - sc = 36 - sc; -return (((val << sc) | (val >> (36 - sc))) & DMASK); -} - -/* Double word integer instructions */ - -/* Double add - see case table for single add */ - -void dadd (int32 ac, d10 *rs) -{ -d10 r; -int32 p1 = ADDAC (ac, 1); - -AC(p1) = CLRS (AC(p1)) + CLRS (rs[1]); /* add lo */ -r = (AC(ac) + rs[0] + (TSTS (AC(p1))? 1: 0)) & DMASK; /* add hi+cry */ -if (TSTS (AC(ac) & rs[0])) { /* cases 7,8 */ - if (TSTS (r)) /* case 8 */ - SETF (F_C0 | F_C1); - else SETF (F_C0 | F_AOV | F_T1); /* case 7 */ - } -else if (!TSTS (AC(ac) | rs[0])) { /* cases 1,2 */ - if (TSTS (r)) /* case 2 */ - SETF (F_C1 | F_AOV | F_T1); - } -else if (!TSTS (r)) /* cases 3,5 */ - SETF (F_C0 | F_C1); -AC(ac) = r; -AC(p1) = TSTS (r)? SETS (AC(p1)): CLRS (AC(p1)); -return; -} - -/* Double subtract - see comments for single subtract */ - -void dsub (int32 ac, d10 *rs) -{ -d10 r; -int32 p1 = ADDAC (ac, 1); - -AC(p1) = CLRS (AC(p1)) - CLRS (rs[1]); /* sub lo */ -r = (AC(ac) - rs[0] - (TSTS (AC(p1))? 1: 0)) & DMASK; /* sub hi,borrow */ -if (TSTS (AC(ac) & ~rs[0])) { /* cases 7,8 */ - if (TSTS (r)) /* case 8 */ - SETF (F_C0 | F_C1); - else SETF (F_C0 | F_AOV | F_T1); /* case 7 */ - } -else if (!TSTS (AC(ac) | ~rs[0])) { /* cases 1,2 */ - if (TSTS (r)) /* case 2 */ - SETF (F_C1 | F_AOV | F_T1); - } -else if (!TSTS (r)) /* cases 3,5 */ - SETF (F_C0 | F_C1); -AC(ac) = r; -AC(p1) = (TSTS (r)? SETS (AC(p1)): CLRS (AC(p1))) & DMASK; -return; -} - - -/* Logical shift combined */ - -void lshc (int32 ac, a10 ea) -{ -int32 p1 = ADDAC (ac, 1); -int32 sc = LIT8 (ea); - -if (sc > 71) - AC(ac) = AC(p1) = 0; -else if (ea & RSIGN) { - if (sc >= 36) { - AC(p1) = AC(ac) >> (sc - 36); - AC(ac) = 0; - } - else { - AC(p1) = ((AC(p1) >> sc) | (AC(ac) << (36 - sc))) & DMASK; - AC(ac) = AC(ac) >> sc; - } - } -else { - if (sc >= 36) { - AC(ac) = (AC(p1) << (sc - 36)) & DMASK; - AC(p1) = 0; - } - else { - AC(ac) = ((AC(ac) << sc) | (AC(p1) >> (36 - sc))) & DMASK; - AC(p1) = (AC(p1) << sc) & DMASK; - } - } -return; -} - -/* Rotate combined */ - -void rotc (int32 ac, a10 ea) -{ -int32 p1 = ADDAC (ac, 1); -int32 sc = LIT8 (ea) % 72; -d10 t = AC(ac); - -if (sc == 0) - return; -if (ea & RSIGN) - sc = 72 - sc; -if (sc >= 36) { - AC(ac) = ((AC(p1) << (sc - 36)) | (t >> (72 - sc))) & DMASK; - AC(p1) = ((t << (sc - 36)) | (AC(p1) >> (72 - sc))) & DMASK; - } -else { - AC(ac) = ((t << sc) | (AC(p1) >> (36 - sc))) & DMASK; - AC(p1) = ((AC(p1) << sc) | (t >> (36 - sc))) & DMASK; - } -return; -} - -/* Arithmetic shifts */ - -d10 ash (d10 val, a10 ea) -{ -int32 sc = LIT8 (ea); -d10 sign = TSTS (val); -d10 fill = sign? ONES: 0; -d10 so; - -if (sc == 0) - return val; -if (sc > 35) /* cap sc at 35 */ - sc = 35; -if (ea & RSIGN) - return (((val >> sc) | (fill << (36 - sc))) & DMASK); -so = val >> (35 - sc); /* bits lost left + sign */ -if (so != (sign? bytemask[sc + 1]: 0)) - SETF (F_AOV | F_T1); -return (sign | ((val << sc) & MMASK)); -} - -void ashc (int32 ac, a10 ea) -{ -int32 sc = LIT8 (ea); -int32 p1 = ADDAC (ac, 1); -d10 sign = TSTS (AC(ac)); -d10 fill = sign? ONES: 0; -d10 so; - -if (sc == 0) - return; -if (sc > 70) /* cap sc at 70 */ - sc = 70; -AC(ac) = CLRS (AC(ac)); /* clear signs */ -AC(p1) = CLRS (AC(p1)); -if (ea & RSIGN) { - if (sc >= 35) { /* right 36..70 */ - AC(p1) = ((AC(ac) >> (sc - 35)) | (fill << (70 - sc))) & DMASK; - AC(ac) = fill; - } - else { - AC(p1) = sign | /* right 1..35 */ - (((AC(p1) >> sc) | (AC(ac) << (35 - sc))) & MMASK); - AC(ac) = ((AC(ac) >> sc) | (fill << (35 - sc))) & DMASK; - } - } -else { - if (sc >= 35) { /* left 36..70 */ - so = AC(p1) >> (70 - sc); /* bits lost left */ - if ((AC(ac) != (sign? MMASK: 0)) || - (so != (sign? bytemask[sc - 35]: 0))) - SETF (F_AOV | F_T1); - AC(ac) = sign | ((AC(p1) << (sc - 35)) & MMASK); - AC(p1) = sign; - } - else { - so = AC(ac) >> (35 - sc); /* bits lost left */ - if (so != (sign? bytemask[sc]: 0)) - SETF (F_AOV | F_T1); - AC(ac) = sign | - (((AC(ac) << sc) | (AC(p1) >> (35 - sc))) & MMASK); - AC(p1) = sign | ((AC(p1) << sc) & MMASK); - } - } -return; -} - -/* Effective address routines */ - -/* Calculate effective address - used by byte instructions, extended - instructions, and interrupts to get a different mapping context from - the main loop. prv is either EABP_PXCT or MM_CUR. -*/ - -a10 calc_ea (d10 inst, int32 prv) -{ -int32 i, ea, xr; -d10 indrct; - -for (indrct = inst, i = 0; ; i++) { - ea = GET_ADDR (indrct); - xr = GET_XR (indrct); - if (xr) - ea = (ea + ((a10) XR (xr, prv))) & AMASK; - if (TST_IND (indrct)) { /* indirect? */ - if (i != 0) { /* not first cycle? */ - int32 t = test_int (); /* test for intr */ - if (t != 0) /* intr or error? */ - ABORT (t); - if ((ind_max != 0) && (i >= ind_max)) /* limit exceeded? */ - ABORT (STOP_IND); - } - indrct = Read (ea, prv); - } - else break; - } -return ea; -} - -/* Calculate I/O effective address. Cases: - - No index or indirect, return addr from instruction - - Index only, index >= 0, return 36b sum of addr + index - - Index only, index <= 0, return 18b sum of addr + index - - Indirect, calculate 18b sum of addr + index, return - entire word fetch (single level) -*/ - -a10 calc_ioea (d10 inst, int32 pflgs) -{ -int32 xr; -a10 ea; - -xr = GET_XR (inst); -ea = GET_ADDR (inst); -if (TST_IND (inst)) { /* indirect? */ - if (xr) - ea = (ea + ((a10) XR (xr, MM_EA))) & AMASK; - ea = (a10) Read (ea, MM_EA); - } -else if (xr) { /* direct + idx? */ - ea = ea + ((a10) XR (xr, MM_EA)); - if (TSTS (XR (xr, MM_EA))) - ea = ea & AMASK; - } -return ea; -} - -/* Calculate JRSTF effective address. This routine preserves - the left half of the effective address, to be the new flags. -*/ - -d10 calc_jrstfea (d10 inst, int32 pflgs) -{ -int32 i, xr; -d10 mb; - -for (i = 0; ; i++) { - mb = inst; - xr = GET_XR (inst); - if (xr) - mb = (mb & AMASK) + XR (xr, MM_EA); - if (TST_IND (inst)) { /* indirect? */ - if (i != 0) { /* not first cycle? */ - int32 t = test_int (); /* test for intr */ - if (t != 0) /* intr or error? */ - ABORT (t); - if ((ind_max != 0) && (i >= ind_max)) /* limit exceeded? */ - ABORT (STOP_IND); - } - inst = Read (((a10) mb) & AMASK, MM_EA); - } - else break; - } -return (mb & DMASK); -} - -/* Byte pointer routines */ - -/* Increment byte pointer - checked against KS10 ucode */ - -void ibp (a10 ea, int32 pflgs) -{ -int32 p, s; -d10 bp; - -bp = ReadM (ea, MM_OPND); /* get byte ptr */ -p = GET_P (bp); /* get P and S */ -s = GET_S (bp); -p = p - s; /* adv P */ -if (p < 0) { /* end of word? */ - bp = (bp & LMASK) | (INCR (bp)); /* incr addr */ - p = (36 - s) & 077; /* reset P */ - } -bp = PUT_P (bp, p); /* store new P */ -Write (ea, bp, MM_OPND); /* store byte ptr */ -return; -} - -/* Load byte */ - -d10 ldb (a10 ea, int32 pflgs) -{ -a10 ba; -int32 p, s; -d10 bp, wd; - -bp = Read (ea, MM_OPND); /* get byte ptr */ -p = GET_P (bp); /* get P and S */ -s = GET_S (bp); -ba = calc_ea (bp, MM_EABP); /* get addr of byte */ -wd = Read (ba, MM_BSTK); /* read word */ -wd = (wd >> p); /* align byte */ -wd = wd & bytemask[s]; /* mask to size */ -return wd; -} - -/* Deposit byte - must use read and write to get page fail correct */ - -void dpb (d10 val, a10 ea, int32 pflgs) -{ -a10 ba; -int32 p, s; -d10 bp, wd, mask; - -bp = Read (ea, MM_OPND); /* get byte ptr */ -p = GET_P (bp); /* get P and S */ -s = GET_S (bp); -ba = calc_ea (bp, MM_EABP); /* get addr of byte */ -wd = Read (ba, MM_BSTK); /* read word */ -mask = bytemask[s] << p; /* shift mask, val */ -val = val << p; -wd = (wd & ~mask) | (val & mask); /* insert byte */ -Write (ba, wd & DMASK, MM_BSTK); -return; -} - -/* Adjust byte pointer - checked against KS10 ucode - The KS10 divide checks if the bytes per word = 0, which is a simpler - formulation of the processor reference manual check. -*/ - -void adjbp (int32 ac, a10 ea, int32 pflgs) -{ -int32 p, s; -d10 bp, newby, left, byadj, bywrd, val, wdadj; - -val = AC(ac); /* get adjustment */ -bp = Read (ea, MM_OPND); /* get byte pointer */ -p = GET_P (bp); /* get p */ -s = GET_S (bp); /* get s */ -if (s) { - left = (36 - p) / s; /* bytes to left of p */ - bywrd = left + (p / s); /* bytes per word */ - if (bywrd == 0) { /* zero bytes? */ - SETF (F_AOV | F_T1 | F_DCK); /* set flags */ - return; /* abort operation */ - } - newby = left + SXT (val); /* adjusted byte # */ - wdadj = newby / bywrd; /* word adjustment */ - byadj = (newby >= 0)? newby % bywrd: -((-newby) % bywrd); - if (byadj <= 0) { - byadj = byadj + bywrd; /* make adj positive */ - wdadj = wdadj - 1; - } - p = (36 - ((int32) byadj) * s) - ((36 - p) % s); /* new p */ - bp = (PUT_P (bp, p) & LMASK) | ((bp + wdadj) & RMASK); - } -AC(ac) = bp; -return; -} - -/* Block transfer - checked against KS10 ucode - The KS10 uses instruction specific recovery code in page fail - to set the AC properly for restart. Lacking this mechanism, - the simulator must test references in advance. - The clocking test guarantees forward progress under single step. -*/ - -void blt (int32 ac, a10 ea, int32 pflgs) -{ -a10 srca = (a10) LRZ (AC(ac)); -a10 dsta = (a10) RRZ (AC(ac)); -a10 lnt = ea - dsta + 1; -d10 srcv; -int32 flg, t; - -AC(ac) = XWD (srca + lnt, dsta + lnt); -for (flg = 0; dsta <= ea; flg++) { /* loop */ - if (flg && (t = test_int ())) { /* timer event? */ - AC(ac) = XWD (srca, dsta); /* AC for intr */ - ABORT (t); - } - if (AccViol (srca & AMASK, MM_BSTK, PTF_RD)) { /* src access viol? */ - AC(ac) = XWD (srca, dsta); /* AC for page fail */ - Read (srca & AMASK, MM_BSTK); /* force trap */ - } - if (AccViol (dsta & AMASK, MM_OPND, PTF_WR)) { /* dst access viol? */ - AC(ac) = XWD (srca, dsta); /* AC for page fail */ - ReadM (dsta & AMASK, MM_OPND); /* force trap */ - } - srcv = Read (srca & AMASK, MM_BSTK); /* read */ - Write (dsta & AMASK, srcv, MM_OPND); /* write */ - srca = srca + 1; /* incr addr */ - dsta = dsta + 1; - } -return; -} - -/* I/O block transfers - byte to Unibus (0) and Unibus to byte (1) */ - -#define BYTE1 INT64_C(0776000000000) -#define BYTE2 INT64_C(0001774000000) -#define BYTE3 INT64_C(0000003770000) -#define BYTE4 INT64_C(0000000007760) -/* unused 0000000000017 */ - -void bltu (int32 ac, a10 ea, int32 pflgs, int dir) -{ -a10 srca = (a10) LRZ (AC(ac)); -a10 dsta = (a10) RRZ (AC(ac)); -a10 lnt = ea - dsta + 1; -d10 srcv, dstv; -int32 flg, t; - -AC(ac) = XWD (srca + lnt, dsta + lnt); -for (flg = 0; dsta <= ea; flg++) { /* loop */ - if (flg && (t = test_int ())) { /* timer event? */ - AC(ac) = XWD (srca, dsta); /* AC for intr */ - ABORT (t); - } - if (AccViol (srca & AMASK, MM_BSTK, PTF_RD)) { /* src access viol? */ - AC(ac) = XWD (srca, dsta); /* AC for page fail */ - Read (srca & AMASK, MM_BSTK); /* force trap */ - } - if (AccViol (dsta & AMASK, MM_OPND, PTF_WR)) { /* dst access viol? */ - AC(ac) = XWD (srca, dsta); /* AC for page fail */ - ReadM (dsta & AMASK, MM_OPND); /* force trap */ - } - srcv = Read (srca & AMASK, MM_BSTK); /* read */ - if (dir) dstv = ((srcv << 10) & BYTE1) | ((srcv >> 6) & BYTE2) | - ((srcv << 12) & BYTE3) | ((srcv >> 4) & BYTE4); - else dstv = ((srcv & BYTE1) >> 10) | ((srcv & BYTE2) << 6) | - ((srcv & BYTE3) >> 12) | ((srcv & BYTE4) << 4); - Write (dsta & AMASK, dstv, MM_OPND); /* write */ - srca = srca + 1; /* incr addr */ - dsta = dsta + 1; - } -return; -} - -/* Utility routine to test for I/O event and interrupt */ - -int32 test_int (void) -{ -int32 t; - -if (sim_interval <= 0) { /* check queue */ - if ((t = sim_process_event ())) /* IO event? */ - return t; - if (pi_eval ()) /* interrupt? */ - return (INTERRUPT); - } -else sim_interval--; /* count clock */ -return 0; -} - -/* Adjust stack pointer - - The reference manual says to trap on: - 1) E < 0, left changes from + to - - 2) E >= 0, left changes from - to + - This is the same as trap on: - 1) E and left result have same signs - 2) initial value and left result have different signs - */ - -d10 adjsp (d10 val, a10 ea) -{ -d10 imm = ea; -d10 left, right; - -left = ADDL (val, imm); -right = ADDR (val, imm); -if (TSTS ((val ^ left) & (~left ^ RLZ (imm)))) - SETF (F_T2); -return (left | right); -} - -/* Jump if find first ones - Takes advantage of 7 bit find first table for priority interrupts. -*/ - -int32 jffo (d10 val) -{ -int32 i, by; - -if ((val & DMASK) == 0) - return 0; -for (i = 0; i <= 28; i = i + 7) { /* scan five bytes */ - by = (int32) ((val >> (29 - i)) & 0177); - if (by) - return (pi_m2lvl[by] + i - 1); - } -return 35; /* must be bit 35 */ -} - -/* Circulate - ITS only instruction - - Bits rotated out of AC are rotated into the opposite end of AC+1 - why? - No attempt is made to optimize this instruction. -*/ - -void circ (int32 ac, int32 ea) -{ -int32 sc = LIT8 (ea) % 72; -int32 p1 = ADDAC (ac,1); -int32 i; -d10 val; - -if (sc == 0) /* any shift? */ - return; -if (ea & RSIGN) /* if right, make left */ - sc = 72 - sc; -for (i = 0; i < sc; i++) { /* one bit at a time */ - val = TSTS (AC(ac)); /* shift out */ - AC(ac) = ((AC(ac) << 1) | (AC(p1) & 1)) & DMASK; - AC(p1) = (AC(p1) >> 1) | val; /* shift in */ - } -return; -} - -/* Arithmetic processor (APR) - - The APR subsystem includes miscellaneous interrupts that are individually - maskable but which interrupt on a single, selectable level - - Instructions for the arithmetic processor: - APRID read system id - WRAPR (CONO APR) write system flags - RDAPR (CONI APR) read system flags - (CONSO APR) test system flags - (CONSZ APR) test system flags -*/ - -t_bool aprid (a10 ea, int32 prv) -{ -d10 value = (Q_ITS)? UC_AIDITS: UC_AIDDEC; - -if( (apr_serial == -1) || (!Q_ITS && apr_serial < 4096) ) - value |= (Q_ITS)? UC_SERITS: UC_SERDEC; -else - value |= apr_serial; - -Write (ea, value, prv); -return FALSE; -} - -/* Checked against KS10 ucode */ - -t_bool wrapr (a10 ea, int32 prv) -{ -int32 bits = APR_GETF (ea); - -apr_lvl = ea & APR_M_LVL; -if (ea & APR_SENB) /* set enables? */ - apr_enb = apr_enb | bits; -if (ea & APR_CENB) /* clear enables? */ - apr_enb = apr_enb & ~bits; -if (ea & APR_CFLG) /* clear flags? */ - apr_flg = apr_flg & ~bits; -if (ea & APR_SFLG) /* set flags? */ - apr_flg = apr_flg | bits; -if (apr_flg & APRF_ITC) { /* interrupt console? */ - fe_intr (); /* explicit callout */ - apr_flg = apr_flg & ~APRF_ITC; /* interrupt clears */ - } -pi_eval (); /* eval pi system */ -return FALSE; -} - -t_bool rdapr (a10 ea, int32 prv) -{ -Write (ea, (d10) APRWORD, prv); -return FALSE; -} - -t_bool czapr (a10 ea, int32 prv) -{ -return ((APRHWORD & ea)? FALSE: TRUE); -} - -t_bool coapr (a10 ea, int32 prv) -{ -return ((APRHWORD & ea)? TRUE: FALSE); -} - -/* Routine to change the processor flags, called from JRST, MUUO, interrupt. - If jrst is TRUE, must munge flags for executive security. - Because the KS10 lacks the public flag, these checks are simplified. -*/ - -void set_newflags (d10 newf, t_bool jrst) -{ -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)) /* if !UIO, can't set */ - fl = fl & ~F_UIO; - } -if (Q_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; -} - -/* Priority interrupt system (PI) - - The priority interrupt system has three sources of requests - (pi_apr) system flags - synthesized on the fly - (pi_ioq) I/O interrupts - synthesized on the fly - pi_prq program requests - APR and I/O requests are masked with the PI enable mask; the program - requests are not. If priority interrupts are enabled, and there is - a request at a level exceeding the currently active level, then an - interrupt occurs. - - Instructions for the priority interrupt system: - WRPI (CONO PI) write pi system - RDPI (CONI PI) read pi system - (CONSO PI) test pi system - (CONSZ PI) test pi system - - Routines for the priority interrupt system: - pi_eval return level number of highest interrupt - pi_dismiss dismiss highest outstanding interrupt - - Checked against KS10 ucode - KS10 UUO's if <18:21> are non-zero -*/ - -t_bool wrpi (a10 ea, int32 prv) -{ -int32 lvl = ea & PI_M_LVL; - -if (ea & PI_INIT) - pi_on = pi_enb = pi_act = pi_prq = 0; -if (ea & PI_CPRQ) /* clear prog reqs? */ - pi_prq = pi_prq & ~lvl; -if (ea & PI_SPRQ) /* set prog reqs? */ - pi_prq = pi_prq | lvl; -if (ea & PI_SENB) /* enable levels? */ - pi_enb = pi_enb | lvl; -if (ea & PI_CENB) /* disable levels? */ - pi_enb = pi_enb & ~lvl; -if (ea & PI_SON) /* enable pi? */ - pi_on = 1; -if (ea & PI_CON) /* disable pi? */ - pi_on = 0; -pi_eval (); /* eval pi system */ -return FALSE; -} - -t_bool rdpi (a10 ea, int32 prv) -{ -Write (ea, (d10) PIWORD, prv); -return FALSE; -} - -t_bool czpi (a10 ea, int32 prv) -{ -return ((PIHWORD & ea)? FALSE: TRUE); -} - -t_bool copi (a10 ea, int32 prv) -{ -return ((PIHWORD & ea)? TRUE: FALSE); -} - -/* Priority interrupt evaluation - - The Processor Reference Manuals says that program interrupt - requests occur whether the corresponding level is enabled or - not. However, the KS10, starting with microcode edit 47, - masked program requests under the enable mask, just like APR - and I/O requests. This is not formally documented but appears - to be necessary for the TOPS20 console port to run correclty. -*/ - -int32 pi_eval (void) -{ -int32 reqlvl, actlvl; -extern int32 pi_ub_eval (); - -qintr = 0; -if (pi_on) { - pi_apr = (apr_flg & apr_enb)? pi_l2bit[apr_lvl]: 0; - pi_ioq = pi_ub_eval (); - reqlvl = pi_m2lvl[((pi_apr | pi_ioq | pi_prq) & pi_enb)]; - actlvl = pi_m2lvl[pi_act]; - if ((actlvl == 0) || (reqlvl < actlvl)) - qintr = reqlvl; - } -return qintr; -} - -void pi_dismiss (void) -{ -pi_act = pi_act & ~pi_l2bit[pi_m2lvl[pi_act]]; /* clr left most bit */ -pi_eval (); /* eval pi system */ -return; -} - -/* Reset routine */ - -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 */ -pcst = 0; /* clear PC samp */ -rlog = 0; /* clear reg log */ -hsb = (Q_ITS)? UC_HSBITS: UC_HSBDEC; /* set HSB */ -set_dyn_ptrs (); -set_ac_display (ac_cur); -pi_eval (); -if (M == NULL) - M = (d10 *) calloc (MAXMEMSIZE, sizeof (d10)); -if (M == NULL) - return SCPE_MEM; -pcq_r = find_reg ("PCQ", NULL, dptr); -if (pcq_r) - pcq_r->qptr = 0; -else return SCPE_IERR; -sim_brk_types = sim_brk_dflt = SWMASK ('E'); -return SCPE_OK; -} - -/* Memory examine */ - -t_stat cpu_ex (t_value *vptr, t_addr ea, UNIT *uptr, int32 sw) -{ -if (vptr == NULL) - return SCPE_ARG; -if (ea < AC_NUM) - *vptr = AC(ea) & DMASK; -else { - if (sw & SWMASK ('V')) { - ea = conmap (ea, PTF_CON, sw); - if (ea >= MAXMEMSIZE) - return SCPE_REL; - } - if (ea >= MEMSIZE) - return SCPE_NXM; - *vptr = M[ea] & DMASK; - } -return SCPE_OK; -} - -/* Memory deposit */ - -t_stat cpu_dep (t_value val, t_addr ea, UNIT *uptr, int32 sw) -{ -if (ea < AC_NUM) - AC(ea) = val & DMASK; -else { - if (sw & SWMASK ('V')) { - ea = conmap (ea, PTF_CON | PTF_WR, sw); - if (ea >= MAXMEMSIZE) - return SCPE_REL; - } - if (ea >= MEMSIZE) - return SCPE_NXM; - M[ea] = val & DMASK; - } -return SCPE_OK; -} - -/* Set current AC pointers for SCP */ - -void set_ac_display (d10 *acbase) -{ -REG *rptr; -int i; - -rptr = find_reg ("AC0", NULL, &cpu_dev); -if (rptr == NULL) - return; -for (i = 0; i < AC_NUM; i++, rptr++) - rptr->loc = (void *) (acbase + i); -return; -} - -/* Set history */ - -t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 i, lnt; -t_stat r; - -if (cptr == NULL) { - for (i = 0; i < hst_lnt; i++) - hst[i].pc = 0; - hst_p = 0; - return SCPE_OK; - } -lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r); -if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) - return SCPE_ARG; -hst_p = 0; -if (hst_lnt) { - free (hst); - hst_lnt = 0; - hst = NULL; - } -if (lnt) { - hst = (InstHistory *) calloc (lnt, sizeof (InstHistory)); - if (hst == NULL) - return SCPE_MEM; - hst_lnt = lnt; - } -return SCPE_OK; -} - -/* Show history */ - -t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -int32 k, di, lnt; -char *cptr = (char *) desc; -t_stat r; -extern t_value *sim_eval; -InstHistory *h; - -if (hst_lnt == 0) /* enabled? */ - return SCPE_NOFNC; -if (cptr) { - lnt = (int32) get_uint (cptr, 10, hst_lnt, &r); - if ((r != SCPE_OK) || (lnt == 0)) - return SCPE_ARG; - } -else lnt = hst_lnt; -di = hst_p - lnt; /* work forward */ -if (di < 0) - di = di + hst_lnt; -fprintf (st, "PC AC EA IR\n\n"); -for (k = 0; k < lnt; k++) { /* print specified */ - h = &hst[(++di) % hst_lnt]; /* entry pointer */ - if (h->pc & HIST_PC) { /* instruction? */ - fprintf (st, "%06o ", h->pc & AMASK); - fprint_val (st, h->ac, 8, 36, PV_RZRO); - fputs (" ", st); - fprintf (st, "%06o ", h->ea); - sim_eval[0] = h->ir; - if ((fprint_sym (st, h->pc & AMASK, sim_eval, &cpu_unit, SWMASK ('M'))) > 0) { - fputs ("(undefined) ", st); - fprint_val (st, h->ir, 8, 36, PV_RZRO); - } - fputc ('\n', st); /* end line */ - } /* end else instruction */ - } /* end for */ -return SCPE_OK; -} - -/* Set serial */ - -t_stat cpu_set_serial (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 lnt; -t_stat r; - -if (cptr == NULL) { - apr_serial = -1; - return SCPE_OK; - } -lnt = (int32) get_uint (cptr, 10, 077777, &r); -if ((r != SCPE_OK) || (lnt <= 0) || (!Q_ITS && lnt < 4096)) - return SCPE_ARG; -apr_serial = lnt & 077777; -return SCPE_OK; -} - -/* Show serial */ - -t_stat cpu_show_serial (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -fprintf (st, "Serial: " ); -if( (apr_serial == -1) || (!Q_ITS && apr_serial < 4096) ) { - fprintf (st, "%d (default)", (Q_ITS)? UC_SERITS: UC_SERDEC); - return SCPE_OK; - } -fprintf (st, "%d", apr_serial); -return SCPE_OK; -} diff --git a/PDP10/pdp10_defs.h b/PDP10/pdp10_defs.h deleted file mode 100644 index 028a2b91..00000000 --- a/PDP10/pdp10_defs.h +++ /dev/null @@ -1,809 +0,0 @@ -/* pdp10_defs.h: PDP-10 simulator definitions - - Copyright (c) 1993-2017, 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. - - 19-Jan-17 RMS Fixed CD11 definition (Mark Pizzolatto) - 30-Jun-13 RMS Fixed IPL4 mask definition (Tim Litt) - 22-May-10 RMS Added check for 64b addresses - 01-Feb-07 RMS Added CD support - 29-Oct-06 RMS Added clock coscheduling function - 29-Dec-03 RMS Added Q18 definition for PDP11 compatibility - 19-May-03 RMS Revised for new conditional compilation scheme - 09-Jan-03 RMS Added DEUNA/DELUA support - 29-Sep-02 RMS Added variable vector, RX211 support - 22-Apr-02 RMS Removed magtape record length error - 20-Jan-02 RMS Added multiboard DZ11 support - 23-Oct-01 RMS New IO page address constants - 19-Oct-01 RMS Added DZ11 definitions - 07-Sep-01 RMS Revised for PDP-11 multi-level interrupts - 31-Aug-01 RMS Changed int64 to t_int64 for Windoze - 29-Aug-01 RMS Corrected models and dates (found by Lars Brinkhoff) - 01-Jun-01 RMS Updated DZ11 vector definitions - 19-May-01 RMS Added workaround for TOPS-20 V4.1 boot bug -*/ - -#ifndef PDP10_DEFS_H_ -#define PDP10_DEFS_H_ 0 - -#ifndef VM_PDP10 -#define VM_PDP10 0 -#endif - -#include "sim_defs.h" /* simulator defns */ - -#if defined(USE_ADDR64) -#error "PDP-10 does not support 64b addresses!" -#endif - -/* Digital Equipment Corporation's 36b family had six implementations: - - name mips comments - - PDP-6 0.25 Original 36b implementation, 1964 - KA10 0.38 First PDP-10, flip chips, 1967 - KI10 0.72 First paging system, flip chip + MSI, 1972 - KL10 1.8 First ECL system, ECL 10K, 1975 - KL10B 1.8 Expanded addressing, ECL 10K, 1978 - KS10 0.3 Last 36b system, 2901 based, 1979 - - In addition, it ran four major (incompatible) operating systems: - - name company comments - - TOPS-10 DEC Original timesharing system - ITS MIT "Incompatible Timesharing System" - TENEX BBN ARPA-sponsored, became - TOPS-20 DEC Commercial version of TENEX - - All of the implementations differ from one another, in instruction set, - I/O structure, and memory management. Further, each of the operating - systems customized the microcode of the paging systems (KI10, KL10, KS10) - for additional instructions and specialized memory management. As a - result, there is no "reference implementation" for the 36b family that - will run all programs and all operating systems. The conditionalization - and generality needed to support the full matrix of models and operating - systems, and to support 36b hardware on 32b data types, is beyond the - scope of this project. - - Instead, this simulator emulates one model -- the KS10. It has the best - documentation and allows reuse of some of the Unibus peripheral emulators - written for the PDP-11 simulator. Further, the simulator requires that - the underlying compiler support 64b integer data types, allowing 36b data - to be maintained in a single data item. Lastly, the simulator implements - the maximum memory size, so that NXM's never happen. -*/ - -/* Data types */ - -typedef int32 a10; /* PDP-10 addr (30b) */ -typedef t_int64 d10; /* PDP-10 data (36b) */ - -/* Abort codes, used to sort out longjmp's back to the main loop - Codes > 0 are simulator stop codes - Codes < 0 are internal aborts - Code = 0 stops execution for an interrupt check -*/ - -#define STOP_HALT 1 /* halted */ -#define STOP_IBKPT 2 /* breakpoint */ -#define STOP_ILLEG 3 /* illegal instr */ -#define STOP_ILLINT 4 /* illegal intr inst */ -#define STOP_PAGINT 5 /* page fail in intr */ -#define STOP_ZERINT 6 /* zero vec in intr */ -#define STOP_NXMPHY 7 /* nxm on phys ref */ -#define STOP_IND 8 /* indirection loop */ -#define STOP_XCT 9 /* XCT loop */ -#define STOP_ILLIOC 10 /* invalid UBA num */ -#define STOP_ASTOP 11 /* address stop */ -#define STOP_CONSOLE 12 /* FE halt */ -#define STOP_IOALIGN 13 /* DMA word access to odd address */ -#define STOP_UNKNOWN 14 /* unknown stop */ -#define PAGE_FAIL -1 /* page fail */ -#define INTERRUPT -2 /* interrupt */ -#define ABORT(x) longjmp (save_env, (x)) /* abort */ -#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* cond error return */ - -/* Return codes from eXTEND */ - -#define XT_MUUO 0 /* invalid operation */ -#define XT_SKIP 1 /* skip return */ -#define XT_NOSK 2 /* no skip return */ - -/* Operating system flags, kept in cpu_unit.flags */ - -#define UNIT_V_ITS (UNIT_V_UF) /* ITS */ -#define UNIT_V_T20 (UNIT_V_UF + 1) /* TOPS-20 */ -#define UNIT_V_KLAD (UNIT_V_UF + 2) /* diagnostics */ -#define UNIT_ITS (1 << UNIT_V_ITS) -#define UNIT_T20 (1 << UNIT_V_T20) -#define UNIT_KLAD (1 << UNIT_V_KLAD) -#define Q_T10 ((cpu_unit.flags & (UNIT_ITS|UNIT_T20|UNIT_KLAD)) == 0) -#define Q_ITS (cpu_unit.flags & UNIT_ITS) -#define Q_T20 (cpu_unit.flags & UNIT_T20) -#define Q_KLAD (cpu_unit.flags & UNIT_KLAD) -#define Q_IDLE (sim_idle_enab) - -/* Architectural constants */ - -#define PASIZE 20 /* phys addr width */ -#define MAXMEMSIZE (1 << PASIZE) /* maximum memory */ -#define PAMASK ((1 << PASIZE) - 1) -#define MEMSIZE MAXMEMSIZE /* fixed, KISS */ -#define MEM_ADDR_NXM(x) ((x) >= MEMSIZE) -#define VASIZE 18 /* virtual addr width */ -#define AMASK ((1 << VASIZE) - 1) /* virtual addr mask */ -#define LMASK INT64_C(0777777000000) /* left mask */ -#define LSIGN INT64_C(0400000000000) /* left sign */ -#define RMASK INT64_C(0000000777777) /* right mask */ -#define RSIGN INT64_C(0000000400000) /* right sign */ -#define DMASK INT64_C(0777777777777) /* data mask */ -#define SIGN INT64_C(0400000000000) /* sign */ -#define MMASK INT64_C(0377777777777) /* magnitude mask */ -#define ONES INT64_C(0777777777777) -#define MAXPOS INT64_C(0377777777777) -#define MAXNEG INT64_C(0400000000000) - -/* Instruction format */ - -#define INST_V_OP 27 /* opcode */ -#define INST_M_OP 0777 -#define INST_V_DEV 26 -#define INST_M_DEV 0177 /* device */ -#define INST_V_AC 23 /* AC */ -#define INST_M_AC 017 -#define INST_V_IND 22 /* indirect */ -#define INST_IND (1 << INST_V_IND) -#define INST_V_XR 18 /* index */ -#define INST_M_XR 017 -#define OP_JRST 0254 /* JRST */ -#define AC_XPCW 07 /* XPCW */ -#define OP_JSR 0264 /* JSR */ -#define GET_OP(x) ((int32) (((x) >> INST_V_OP) & INST_M_OP)) -#define GET_DEV(x) ((int32) (((x) >> INST_V_DEV) & INST_M_DEV)) -#define GET_AC(x) ((int32) (((x) >> INST_V_AC) & INST_M_AC)) -#define TST_IND(x) ((x) & INST_IND) -#define GET_XR(x) ((int32) (((x) >> INST_V_XR) & INST_M_XR)) -#define GET_ADDR(x) ((a10) ((x) & AMASK)) - -/* Byte pointer format */ - -#define BP_V_P 30 /* position */ -#define BP_M_P INT64_C(077) -#define BP_P INT64_C(0770000000000) -#define BP_V_S 24 /* size */ -#define BP_M_S INT64_C(077) -#define BP_S INT64_C(0007700000000) -#define GET_P(x) ((int32) (((x) >> BP_V_P) & BP_M_P)) -#define GET_S(x) ((int32) (((x) >> BP_V_S) & BP_M_S)) -#define PUT_P(b,x) (((b) & ~BP_P) | ((((t_int64) (x)) & BP_M_P) << BP_V_P)) - -/* Flags (stored in their own halfword) */ - -#define F_V_AOV 17 /* arithmetic ovflo */ -#define F_V_C0 16 /* carry 0 */ -#define F_V_C1 15 /* carry 1 */ -#define F_V_FOV 14 /* floating ovflo */ -#define F_V_FPD 13 /* first part done */ -#define F_V_USR 12 /* user mode */ -#define F_V_UIO 11 /* user I/O mode */ -#define F_V_PUB 10 /* public mode */ -#define F_V_AFI 9 /* addr fail inhibit */ -#define F_V_T2 8 /* trap 2 */ -#define F_V_T1 7 /* trap 1 */ -#define F_V_FXU 6 /* floating exp unflo */ -#define F_V_DCK 5 /* divide check */ -#define F_AOV (1 << F_V_AOV) -#define F_C0 (1 << F_V_C0) -#define F_C1 (1 << F_V_C1) -#define F_FOV (1 << F_V_FOV) -#define F_FPD (1 << F_V_FPD) -#define F_USR (1 << F_V_USR) -#define F_UIO (1 << F_V_UIO) -#define F_PUB (1 << F_V_PUB) -#define F_AFI (1 << F_V_AFI) -#define F_T2 (1 << F_V_T2) -#define F_T1 (1 << F_V_T1) -#define F_TR (F_T1 | F_T2) -#define F_FXU (1 << F_V_FXU) -#define F_DCK (1 << F_V_DCK) -#define F_1PR (F_AFI) /* ITS: 1-proceed */ -#define F_MASK 0777740 /* all flags */ -#define SETF(x) flags = flags | (x) -#define CLRF(x) flags = flags & ~(x) -#define TSTF(x) (flags & (x)) -#define GET_TRAPS(x) (((x) & (F_T2 | F_T1)) >> F_V_T1) - -/* Priority interrupt system */ - -#define PI_CPRQ 020000 /* drop prog req */ -#define PI_INIT 010000 /* clear pi system */ -#define PI_SPRQ 004000 /* set prog req */ -#define PI_SENB 002000 /* set enables */ -#define PI_CENB 001000 /* clear enables */ -#define PI_CON 000400 /* turn off pi system */ -#define PI_SON 000200 /* turn on pi system */ -#define PI_M_LVL 000177 /* level mask */ -#define PI_V_PRQ 18 /* in CONI */ -#define PI_V_ACT 8 -#define PI_V_ON 7 -#define PI_V_ENB 0 - -/* Arithmetic processor flags */ - -#define APR_SENB 0100000 /* set enable */ -#define APR_CENB 0040000 /* clear enable */ -#define APR_CFLG 0020000 /* clear flag */ -#define APR_SFLG 0010000 /* set flag */ -#define APR_IRQ 0000010 /* int request */ -#define APR_M_LVL 0000007 /* pi level */ -#define APR_V_FLG 4 /* system flags */ -#define APR_M_FLG 0377 -#define APRF_ITC (002000 >> APR_V_FLG) /* int console flag */ -#define APRF_NXM (000400 >> APR_V_FLG) /* nxm flag */ -#define APRF_TIM (000040 >> APR_V_FLG) /* timer request */ -#define APRF_CON (000020 >> APR_V_FLG) /* console int */ -#define APR_GETF(x) (((x) >> APR_V_FLG) & APR_M_FLG) - -/* Virtual address, DEC paging */ - -#define PAG_V_OFF 0 /* offset - must be 0 */ -#define PAG_N_OFF 9 /* page offset width */ -#define PAG_SIZE 01000 /* page offset size */ -#define PAG_M_OFF 0777 /* mask for offset */ -#define PAG_V_PN PAG_N_OFF /* page number */ -#define PAG_N_PPN (PASIZE - PAG_N_OFF) /* phys pageno width */ -#define PAG_M_PPN 03777 /* phys pageno mask */ -#define PAG_PPN 03777000 -#define PAG_N_VPN (VASIZE - PAG_N_OFF) /* virt pageno width */ -#define PAG_M_VPN 0777 /* virt pageno mask */ -#define PAG_VPN 0777000 -#define PAG_GETOFF(x) ((x) & PAG_M_OFF) -#define PAG_GETVPN(x) (((x) >> PAG_V_PN) & PAG_M_VPN) -#define PAG_XPTEPA(p,x) (((p) + PAG_GETOFF (x)) & PAMASK) -#define PAG_PTEPA(p,x) (((((int32) (p)) & PTE_PPMASK) << PAG_V_PN) + PAG_GETOFF (x)) - -/* Page table entry, TOPS-10 paging */ - -#define PTE_T10_A 0400000 /* T10: access */ -#define PTE_T10_P 0200000 /* T10: public */ -#define PTE_T10_W 0100000 /* T10: writeable */ -#define PTE_T10_S 0040000 /* T10: software */ -#define PTE_T10_C 0020000 /* T10: cacheable */ -#define PTE_PPMASK PAG_M_PPN - -/* Page table entry, TOPS-20 paging */ - -#define PTE_T20_V_TYP INT64_C(33) /* T20: pointer type */ -#define PTE_T20_M_TYP INT64_C(07) -#define T20_NOA 0 /* no access */ -#define T20_IMM 1 /* immediate */ -#define T20_SHR 2 /* shared */ -#define T20_IND 3 /* indirect */ -#define PTE_T20_W INT64_C(0020000000000) /* T20: writeable */ -#define PTE_T20_C INT64_C(0004000000000) /* T20: cacheable */ -#define PTE_T20_STM INT64_C(0000077000000) /* T20: storage medium */ -#define PTE_T20_V_PMI 18 /* page map index */ -#define PTE_T20_M_PMI 0777 -#define T20_GETTYP(x) ((int32) (((x) >> PTE_T20_V_TYP) & PTE_T20_M_TYP)) -#define T20_GETPMI(x) ((int32) (((x) >> PTE_T20_V_PMI) & PTE_T20_M_PMI)) - -/* CST entry, TOPS-20 paging */ - -#define CST_AGE INT64_C(0770000000000) /* age field */ -#define CST_M INT64_C(0000000000001) /* modified */ - -/* Page fail word, DEC paging */ - -#define PF_USER INT64_C(0400000000000) /* user mode */ -#define PF_HARD INT64_C(0200000000000) /* nx I/O reg */ -#define PF_NXM INT64_C(0370000000000) /* nx memory */ -#define PF_T10_A INT64_C(0100000000000) /* T10: pte A bit */ -#define PF_T10_W INT64_C(0040000000000) /* T10: pte W bit */ -#define PF_T10_S INT64_C(0020000000000) /* T10: pte S bit */ -#define PF_T20_DN INT64_C(0100000000000) /* T20: eval done */ -#define PF_T20_M INT64_C(0040000000000) /* T20: modified */ -#define PF_T20_W INT64_C(0020000000000) /* T20: writeable */ -#define PF_WRITE INT64_C(0010000000000) /* write reference */ -#define PF_PUB INT64_C(0004000000000) /* pte public bit */ -#define PF_C INT64_C(0002000000000) /* pte C bit */ -#define PF_VIRT INT64_C(0001000000000) /* pfl: virt ref */ -#define PF_NXMP INT64_C(0001000000000) /* nxm: phys ref */ -#define PF_IO INT64_C(0000200000000) /* I/O reference */ -#define PF_BYTE INT64_C(0000020000000) /* I/O byte ref */ - -/* Virtual address, ITS paging */ - -#define ITS_V_OFF 0 /* offset - must be 0 */ -#define ITS_N_OFF 10 /* page offset width */ -#define ITS_SIZE 02000 /* page offset size */ -#define ITS_M_OFF 01777 /* mask for offset */ -#define ITS_V_PN ITS_N_OFF /* page number */ -#define ITS_N_PPN (PASIZE- ITS_N_OFF) /* phys pageno width */ -#define ITS_M_PPN 01777 /* phys pageno mask */ -#define ITS_PPN 03776000 -#define ITS_N_VPN (VASIZE - ITS_N_OFF) /* virt pageno width */ -#define ITS_M_VPN 0377 /* virt pageno mask */ -#define ITS_VPN 0776000 -#define ITS_GETVPN(x) (((x) >> ITS_V_PN) & ITS_M_VPN) - -/* Page table entry, ITS paging */ - -#define PTE_ITS_V_ACC 16 /* access field */ -#define PTE_ITS_M_ACC 03 -#define ITS_ACC_NO 0 /* no access */ -#define ITS_ACC_RO 1 /* read only */ -#define ITS_ACC_RWF 2 /* read-write first */ -#define ITS_ACC_RW 3 /* read write */ -#define PTE_ITS_AGE 0020000 /* age */ -#define PTE_ITS_C 0010000 /* cacheable */ -#define PTE_ITS_PPMASK ITS_M_PPN -#define ITS_GETACC(x) (((x) >> PTE_ITS_V_ACC) & PTE_ITS_M_ACC) - -/* Page fail word, ITS paging */ - -#define PF_ITS_WRITE INT64_C(0010000000000) /* write reference */ -#define PF_ITS_V_ACC 28 /* access from PTE */ - -/* Page table fill operations */ - -#define PTF_RD 0 /* read check */ -#define PTF_WR 1 /* write check */ -#define PTF_MAP 2 /* map instruction */ -#define PTF_CON 4 /* console access */ - -/* User base register */ - -#define UBR_SETACB INT64_C(0400000000000) /* set AC blocks */ -#define UBR_SETUBR INT64_C(0100000000000) /* set UBR */ -#define UBR_V_CURAC 27 /* current AC block */ -#define UBR_V_PRVAC 24 /* previous AC block */ -#define UBR_M_AC 07 -#define UBR_ACBMASK INT64_C(0007700000000) -#define UBR_V_UBR 0 /* user base register */ -#define UBR_N_UBR 11 -#define UBR_M_UBR 03777 -#define UBR_UBRMASK INT64_C(0000000003777) -#define UBR_GETCURAC(x) ((int32) (((x) >> UBR_V_CURAC) & UBR_M_AC)) -#define UBR_GETPRVAC(x) ((int32) (((x) >> UBR_V_PRVAC) & UBR_M_AC)) -#define UBR_GETUBR(x) ((int32) (((x) >> UBR_V_UBR) & PAG_M_PPN)) -#define UBRWORD (ubr | UBR_SETACB | UBR_SETUBR) - -/* Executive base register */ - -#define EBR_V_T20P 14 /* TOPS20 paging */ -#define EBR_T20P (1u << EBR_V_T20P) -#define EBR_V_PGON 13 /* enable paging */ -#define EBR_PGON (1u << EBR_V_PGON) -#define EBR_V_EBR 0 /* exec base register */ -#define EBR_N_EBR 11 -#define EBR_M_EBR 03777 -#define EBR_MASK (EBR_T20P | EBR_PGON | (EBR_M_EBR << EBR_V_EBR)) -#define EBR_GETEBR(x) ((int32) (((x) >> EBR_V_EBR) & PAG_M_PPN)) -#define PAGING (ebr & EBR_PGON) -#define T20PAG (ebr & EBR_T20P) - -/* AC and mapping contexts - - 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 are kept in a - dynamic CPU variable. -*/ - -#define EA_PXCT 010 /* eff addr calc */ -#define OPND_PXCT 004 /* operand, bdst */ -#define EABP_PXCT 002 /* bp eff addr calc */ -#define BSTK_PXCT 001 /* stk, bp op, bsrc */ -#define XSRC_PXCT 002 /* extend source */ -#define XDST_PXCT 001 /* extend destination */ -#define MM_CUR 000 /* current context */ -#define MM_EA (pflgs & EA_PXCT) -#define MM_OPND (pflgs & OPND_PXCT) -#define MM_EABP (pflgs & EABP_PXCT) -#define MM_BSTK (pflgs & BSTK_PXCT) - -/* Accumulator access. The AC blocks are kept in array acs[AC_NBLK * AC_NUM]. - Two pointers are provided to the bases of the current and previous blocks. - Macro AC selects the current AC block; macro XR selects current or previous, - depending on whether the selected bit in the "pxct in progress" flag is set. -*/ - -#define AC_NUM 16 /* # AC's/block */ -#define AC_NBLK 8 /* # AC blocks */ -#define AC(r) (ac_cur[r]) /* AC select current */ -#define XR(r,prv) ((prv)? ac_prv[r]: ac_cur[r]) /* AC select context */ -#define ADDAC(x,i) (((x) + (i)) & INST_M_AC) -#define P1 ADDAC (ac, 1) - -/* User process table entries */ - -#define UPT_T10_UMAP 0000 /* T10: user map */ -#define UPT_T10_X340 0400 /* T10: exec 340-377 */ -#define UPT_TRBASE 0420 /* trap base */ -#define UPT_MUUO 0424 /* MUUO block */ -#define UPT_MUPC 0425 /* caller's PC */ -#define UPT_T10_CTX 0426 /* T10: context */ -#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 */ -#define UPT_T20_PFL 0500 /* T20: page fail wd */ -#define UPT_T20_OFL 0501 /* T20: flags */ -#define UPT_T20_OPC 0502 /* T20: old PC */ -#define UPT_T20_NPC 0503 /* T20: new PC */ -#define UPT_T20_SCTN 0540 /* T20: section 0 ptr */ - -/* Exec process table entries */ - -#define EPT_PIIT 0040 /* PI interrupt table */ -#define EPT_UBIT 0100 /* Unibus intr table */ -#define EPT_T10_X400 0200 /* T10: exec 400-777 */ -#define EPT_TRBASE 0420 /* trap base */ -#define EPT_ITS_PAG 0440 /* ITS: page fail blk */ -#define EPT_T20_SCTN 0540 /* T20: section 0 ptr */ -#define EPT_T10_X000 0600 /* T10: exec 0 - 337 */ - -/* Microcode constants */ - -#define UC_INHCST INT64_C(0400000000000) /* inhibit CST update */ -#define UC_UBABLT INT64_C(0040000000000) /* BLTBU and BLTUB */ -#define UC_KIPAGE INT64_C(0020000000000) /* "KI" paging */ -#define UC_KLPAGE INT64_C(0010000000000) /* "KL" paging */ -#define UC_VERDEC (0130 << 18) /* ucode version */ -#define UC_VERITS (262u << 18) -#define UC_SERDEC 4097 /* serial number */ -#define UC_SERITS 1729 -#define UC_AIDDEC (UC_INHCST | UC_UBABLT | UC_KIPAGE | UC_KLPAGE | \ - UC_VERDEC) -#define UC_AIDITS (UC_KIPAGE | UC_VERITS) - -#define UC_HSBDEC 0376000 /* DEC initial HSB */ -#define UC_HSBITS 0000500 /* ITS initial HSB */ - -/* Front end communications region */ - -#define FE_SWITCH 030 /* halt switch */ -#define FE_KEEPA 031 /* keep alive */ -#define FE_CTYIN 032 /* console in */ -#define FE_CTYOUT 033 /* console out */ -#define FE_KLININ 034 /* KLINIK in */ -#define FE_KLINOUT 035 /* KLINIK out */ -#define FE_RHBASE 036 /* boot: RH11 addr */ -#define FE_UNIT 037 /* boot: unit num */ -#define FE_MTFMT 040 /* boot: magtape params */ -#define FE_CVALID 0400 /* char valid flag */ - -/* Halfword operations */ - -#define ADDL(x,y) (((x) + ((y) << 18)) & LMASK) -#define ADDR(x,y) (((x) + (y)) & RMASK) -#define INCL(x) ADDL (x, 1) -#define INCR(x) ADDR (x, 1) -#define AOB(x) (INCL (x) | INCR(x)) -#define SUBL(x,y) (((x) - ((y) << 18)) & LMASK) -#define SUBR(x,y) (((x) - (y)) & RMASK) -#define DECL(x) SUBL (x, 1) -#define DECR(x) SUBR (x, 1) -#define SOB(x) (DECL (x) | DECR(x)) -#define LLZ(x) ((x) & LMASK) -#define RLZ(x) (((x) << 18) & LMASK) -#define RRZ(x) ((x) & RMASK) -#define LRZ(x) (((x) >> 18) & RMASK) -#define LIT8(x) (((x) & RSIGN)? \ - (((x) & 0377)? (-(x) & 0377): 0400): ((x) & 0377)) - -/* Fullword operations */ - -#define INC(x) (((x) + 1) & DMASK) -#define DEC(x) (((x) - 1) & DMASK) -#define SWP(x) ((((x) << 18) & LMASK) | (((x) >> 18) & RMASK)) -#define XWD(x,y) (((((d10) (x)) << 18) & LMASK) | (((d10) (y)) & RMASK)) -#define SETS(x) ((x) | SIGN) -#define CLRS(x) ((x) & ~SIGN) -#define TSTS(x) ((x) & SIGN) -#define NEG(x) (-(x) & DMASK) -#define ABS(x) (TSTS (x)? NEG(x): (x)) -#define SXT(x) (TSTS (x)? (x) | ~DMASK: (x)) - -/* Doubleword operations (on 2-word arrays) */ - -#define DMOVN(rs) rs[1] = (-rs[1]) & MMASK; \ - rs[0] = (~rs[0] + (rs[1] == 0)) & DMASK -#define MKDNEG(rs) rs[1] = SETS (-rs[1]) & DMASK; \ - rs[0] = (~rs[0] + (rs[1] == MAXNEG)) & DMASK -#define DCMPGE(a,b) ((a[0] > b[0]) || ((a[0] == b[0]) && (a[1] >= b[1]))) - -/* Address operations */ - -#define ADDA(x,i) (((x) + (i)) & AMASK) -#define INCA(x) ADDA (x, 1) - -/* Unibus adapter control/status register */ - -#define UBCS_TMO 0400000 /* timeout */ -#define UBCS_BMD 0200000 /* bad mem data NI */ -#define UBCS_PAR 0100000 /* parity error NI */ -#define UBCS_NXD 0040000 /* nx device */ -#define UBCS_HI 0004000 /* irq on BR7 or BR6 */ -#define UBCS_LO 0002000 /* irq on BR5 or BR4 */ -#define UBCS_PWR 0001000 /* power low NI */ -#define UBCS_DXF 0000200 /* disable xfer NI*/ -#define UBCS_INI 0000100 /* Unibus init */ -#define UBCS_RDZ 0030500 /* read as zero */ -#define UBCS_RDW 0000277 /* read/write bits */ -#define UBCS_V_LHI 3 /* hi pri irq level */ -#define UBCS_V_LLO 0 /* lo pri irq level */ -#define UBCS_M_PRI 07 -#define UBCS_GET_HI(x) (((x) >> UBCS_V_LHI) & UBCS_M_PRI) -#define UBCS_GET_LO(x) (((x) >> UBCS_V_LLO) & UBCS_M_PRI) - -/* Unibus adapter page map */ - -#define UBANUM 2 /* # of Unibus adapters */ -#define UMAP_ASIZE 6 /* address size */ -#define UMAP_MEMSIZE (1 << UMAP_ASIZE) /* length */ -#define UMAP_AMASK (UMAP_MEMSIZE - 1) -#define UMAP_V_RRV 30 /* read reverse */ -#define UMAP_V_DSB 29 /* 16b on NPR read */ -#define UMAP_V_FST 28 /* fast transfer */ -#define UMAP_V_VLD 27 /* valid flag */ -#define UMAP_RRV (1 << UMAP_V_RRV) -#define UMAP_DSB (1 << UMAP_V_DSB) -#define UMAP_FST (1 << UMAP_V_FST) -#define UMAP_VLD (1 << UMAP_V_VLD) -#define UMAP_V_FLWR 14 /* flags as written */ -#define UMAP_V_FLRD 27 /* flags as stored */ -#define UMAP_M_FL 017 -#define UMAP_V_PNWR 0 /* page num, write */ -#define UMAP_V_PNRD 9 /* page num, read */ -#define UMAP_M_PN 03777 -#define UMAP_MASK ((UMAP_M_FL << UMAP_V_FLRD) | (UMAP_M_PN << UMAP_V_PNRD)) -#define UMAP_POSFL(x) (((x) & (UMAP_M_FL << UMAP_V_FLWR)) \ - << (UMAP_V_FLRD - UMAP_V_FLWR)) -#define UMAP_POSPN(x) (((x) & (UMAP_M_PN << UMAP_V_PNWR)) \ - << (UMAP_V_PNRD - UMAP_V_PNWR)) - -/* Unibus I/O constants */ - -#define READ 0 /* PDP11 compatible */ -/* #define READC 1 *//* console read */ -#define WRITE 2 -/* #define WRITEC 3 *//* console write */ -#define WRITEB 4 -#define IO_V_UBA 18 /* UBA in I/O addr */ -#define IO_N_UBA 16 /* max num of UBA's */ -#define IO_M_UBA (IO_N_UBA - 1) -#define IO_UBA1 (1 << IO_V_UBA) -#define IO_UBA3 (3 << IO_V_UBA) -#define GET_IOUBA(x) (((x) >> IO_V_UBA) & IO_M_UBA) - -/* Device information block */ - -#define VEC_DEVMAX 8 /* max device vec */ - -struct pdp_dib { - uint32 ba; /* base addr */ - uint32 lnt; /* length */ - t_stat (*rd)(int32 *dat, int32 ad, int32 md); - t_stat (*wr)(int32 dat, int32 ad, int32 md); - int32 vnum; /* vectors: number */ - int32 vloc; /* locator */ - int32 vec; /* value */ - int32 (*ack[VEC_DEVMAX])(void); /* ack routines */ - uint32 flags; /* Special flags */ -}; - -#define DIB_M_REGSIZE 03 /* Device register size */ -#define DIB_REG16BIT 00 -#define DIB_REG18BIT 01 - -typedef struct pdp_dib DIB; - -/* I/O system parameters */ - -#define DZ_MUXES 4 /* max # of muxes */ -#define DZ_LINES 8 /* lines per mux */ -#define KMC_UNITS 1 /* max # of KMCs */ -#define INITIAL_KMCS 0 /* Number initially enabled */ -#define DUP_LINES 4 /* max # of DUP11's */ -#define DIB_MAX 100 /* max DIBs */ - -#define DEV_V_UBUS (DEV_V_UF + 0) /* Unibus */ -#define DEV_V_QBUS (DEV_V_UF + 1) /* Qbus */ -#define DEV_V_Q18 (DEV_V_UF + 2) /* Qbus, mem <= 256KB */ -#define DEV_V_FLTA (DEV_V_UF + 3) /* float addr */ -#define DEV_UBUS (1u << DEV_V_UBUS) -#define DEV_QBUS (1u << DEV_V_QBUS) -#define DEV_Q18 (1u << DEV_V_Q18) -#define DEV_FLTA (1u << DEV_V_FLTA) - -#define UNIBUS TRUE /* 18b only */ - -#define DEV_RDX 8 /* default device radix */ - -/* I/O page layout */ - -#define IOPAGEBASE 0760000 /* I/O page base */ -#define IOBA_UBMAP 0763000 - -#define IOBA_UBMAP1 (IO_UBA1 + IOBA_UBMAP) /* Unibus 1 map */ -#define IOLN_UBMAP1 0100 -#define IOBA_UBCS1 (IO_UBA1 + 0763100) /* Unibus 1 c/s reg */ -#define IOLN_UBCS1 001 -#define IOBA_UBMNT1 (IO_UBA1 + 0763101) /* Unibus 1 maint reg */ -#define IOLN_UBMNT1 001 -#define IOBA_RP (IO_UBA1 + 0776700) /* RH11/disk */ -#define IOLN_RP 050 - -#define IOBA_DZ (IO_UBA3 + 0760010) /* DZ11 */ -#define IOLN_DZ 010 -#define IOBA_TCU (IO_UBA3 + 0760770) /* TCU150 */ -#define IOLN_TCU 006 -#define IOBA_UBMAP3 (IO_UBA3 + IOBA_UBMAP) /* Unibus 3 map */ -#define IOLN_UBMAP3 0100 -#define IOBA_UBCS3 (IO_UBA3 + 0763100) /* Unibus 3 c/s reg */ -#define IOLN_UBCS3 001 -#define IOBA_UBMNT3 (IO_UBA3 + 0763101) /* Unibus 3 maint reg */ -#define IOLN_UBMNT3 001 -#define IOBA_CR (IO_UBA3 + 0777160) /* CD/CR/CM */ -#define IOLN_CR 010 -#define IOBA_RY (IO_UBA3 + 0777170) /* RX211 */ -#define IOLN_RY 004 -#define IOBA_TU (IO_UBA3 + 0772440) /* RH11/tape */ -#define IOLN_TU 034 -#define IOBA_LP20 (IO_UBA3 + 0775400) /* LP20 */ -#define IOLN_LP20 020 -#define IOBA_PTR (IO_UBA3 + 017550) /* PC11 reader */ -#define IOLN_PTR 004 -#define IOBA_PTP (IO_UBA3 + 017554) /* PC11 punch */ -#define IOLN_PTP 004 - -/* Common Unibus CSR flags */ - -#define CSR_V_GO 0 /* go */ -#define CSR_V_IE 6 /* interrupt enable */ -#define CSR_V_DONE 7 /* done */ -#define CSR_V_BUSY 11 /* busy */ -#define CSR_V_ERR 15 /* error */ -#define CSR_GO (1u << CSR_V_GO) -#define CSR_IE (1u << CSR_V_IE) -#define CSR_DONE (1u << CSR_V_DONE) -#define CSR_BUSY (1u << CSR_V_BUSY) -#define CSR_ERR (1u << CSR_V_ERR) - -/* I/O system definitions, lifted from the PDP-11 simulator - Interrupt assignments, priority is right to left - - <3:0> = BR7 - <7:4> = BR6 - <19:8> = BR5 - <30:20> = BR4 -*/ - -#define INT_V_RP 6 /* RH11/RP,RM drives */ -#define INT_V_TU 7 /* RH11/TM03/TU45 */ -#define INT_V_KMCA 8 /* KMC11 */ -#define INT_V_KMCB 9 -#define INT_V_DMCRX 10 /* DMC11/DMR11 */ -#define INT_V_DMCTX 11 -#define INT_V_DZRX 16 /* DZ11 */ -#define INT_V_DZTX 17 -#define INT_V_RY 18 /* RX211 */ -#define INT_V_PTR 24 /* PC11 */ -#define INT_V_PTP 25 -#define INT_V_LP20 26 /* LPT20 */ -#define INT_V_CR 27 /* CD20 (CD11) */ -#define INT_V_DUPRX 28 /* DUP11 */ -#define INT_V_DUPTX 29 - -#define INT_RP (1u << INT_V_RP) -#define INT_TU (1u << INT_V_TU) -#define INT_KMCA (1u << INT_V_KMCA) -#define INT_KMCB (1u << INT_V_KMCB) -#define INT_DMCRX (1u << INT_V_DMCRX) -#define INT_DMCTX (1u << INT_V_DMCTX) -#define INT_XU (1u << INT_V_XU) -#define INT_DZRX (1u << INT_V_DZRX) -#define INT_DZTX (1u << INT_V_DZTX) -#define INT_RY (1u << INT_V_RY) -#define INT_PTR (1u << INT_V_PTR) -#define INT_PTP (1u << INT_V_PTP) -#define INT_LP20 (1u << INT_V_LP20) -#define INT_CR (1u << INT_V_CD) -#define INT_DUPRX (1u << INT_V_DUPRX) -#define INT_DUPTX (1u << INT_V_DUPTX) - -#define IPL_RP 6 /* int levels */ -#define IPL_TU 6 -#define IPL_KMCA 5 -#define IPL_KMCB 5 -#define IPL_DMCRX 5 -#define IPL_DMCTX 5 -#define IPL_DZRX 5 -#define IPL_DZTX 5 -#define IPL_RY 5 -#define IPL_DUPRX 5 -#define IPL_DUPTX 5 -#define IPL_PTR 4 -#define IPL_PTP 4 -#define IPL_LP20 4 -#define IPL_CR 4 - -#define INT_UB1 INT_RP /* on Unibus 1 */ -#define INT_UB3 (0xFFFFFFFFu & ~INT_UB1) /* on Unibus 3 */ - -#define INT_IPL7 0x0000000F /* int level masks */ -#define INT_IPL6 0x000000F0 -#define INT_IPL5 0x000FFF00 -#define INT_IPL4 0x7FF00000 - -#define VEC_Q 0000 /* vector base */ -#define VEC_PTR 0070 /* interrupt vectors */ -#define VEC_PTP 0074 -#define VEC_XU 0120 -#define VEC_TU 0224 -#define VEC_CR 0230 -#define VEC_RP 0254 -#define VEC_RY 0264 -#define VEC_DZRX 0340 -#define VEC_DZTX 0344 -#define VEC_LP20 0754 - -#define IVCL(dv) (INT_V_##dv) -#define IREQ(dv) int_req -#define SET_INT(dv) IREQ(dv) = IREQ(dv) | (INT_##dv) -#define CLR_INT(dv) IREQ(dv) = IREQ(dv) & ~(INT_##dv) - -/* Function prototypes */ - -int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf); -int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf); -int32 Map_ReadW18 (uint32 ba, int32 bc, uint32 *buf); -int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf); -int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf); -int32 Map_WriteW18 (uint32 ba, int32 bc, uint32 *buf); -void uba_debug_dma_in (uint32 ba, a10 pa_start, a10 pa_end); -void uba_debug_dma_out (uint32 ba, a10 pa_start, a10 pa_end); -void uba_debug_dma_nxm (const char *msg, a10 pa10, uint32 ba, int32 bc); - -t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat set_vec (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat show_vec (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat show_vec_mux (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat auto_config (char *name, int32 num); - -int32 clk_cosched (int32 wait); - -/* Global data */ - -extern t_bool sim_idle_enab; - -#endif diff --git a/PDP10/pdp10_fe.c b/PDP10/pdp10_fe.c deleted file mode 100644 index 4fe267a4..00000000 --- a/PDP10/pdp10_fe.c +++ /dev/null @@ -1,316 +0,0 @@ -/* pdp10_fe.c: PDP-10 front end (console terminal) simulator - - Copyright (c) 1993-2015, 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. - - fe KS10 console front end - - 02-Apr-15 RMS Backported keepalive mechanism - 18-Apr-12 RMS Added clock coscheduling - 18-Jun-07 RMS Added UNIT_IDLE flag to console input - 17-Oct-06 RMS Synced keyboard to clock for idling - 28-May-04 RMS Removed SET FE CTRL-C - 29-Dec-03 RMS Added console backpressure support - 25-Apr-03 RMS Revised for extended file support - 22-Dec-02 RMS Added break support - 30-May-02 RMS Widened COUNT to 32b - 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 -*/ - -#include "pdp10_defs.h" -#define UNIT_DUMMY (1 << UNIT_V_UF) - -extern d10 *M; -extern int32 apr_flg; -extern int32 tmxr_poll; -t_stat fei_svc (UNIT *uptr); -t_stat feo_svc (UNIT *uptr); -static t_stat kaf_svc (UNIT *uptr); -t_stat fe_reset (DEVICE *dptr); -t_stat fe_stop_os (UNIT *uptr, int32 val, char *cptr, void *desc); - -a10 fe_xct = 0; -uint32 fe_bootrh = 0; -int32 fe_bootunit = -1; -extern DIB *dib_tab[]; - -/* FE data structures - - fe_dev FE device descriptor - fe_unit FE unit descriptor - fe_reg FE register list -*/ - -#define fei_unit fe_unit[0] -#define feo_unit fe_unit[1] -#define kaf_unit fe_unit[2] - -UNIT fe_unit[] = { - { UDATA (&fei_svc, UNIT_IDLE, 0), KBD_POLL_WAIT }, - { UDATA (&feo_svc, 0, 0), SERIAL_OUT_WAIT }, - { UDATA (&kaf_svc, 0, 0), (1*1000*1000) } - }; - -REG fe_reg[] = { - { ORDATA (IBUF, fei_unit.buf, 8) }, - { DRDATA (ICOUNT, fei_unit.pos, T_ADDR_W), REG_RO + PV_LEFT }, - { DRDATA (ITIME, fei_unit.wait, 24), PV_LEFT }, - { ORDATA (OBUF, feo_unit.buf, 8) }, - { DRDATA (OCOUNT, feo_unit.pos, T_ADDR_W), REG_RO + PV_LEFT }, - { DRDATA (OTIME, feo_unit.wait, 24), REG_NZ + PV_LEFT }, - { ORDATA (FEXCT, fe_xct, 9), REG_HIDDEN }, - { ORDATA (KPACNT, kaf_unit.u4, 9), REG_HRO }, - { NULL } - }; - -MTAB fe_mod[] = { - { UNIT_DUMMY, 0, NULL, "STOP", &fe_stop_os }, - { 0 } - }; - -DEVICE fe_dev = { - "FE", fe_unit, fe_reg, fe_mod, - 3, 10, 31, 1, 8, 8, - NULL, NULL, &fe_reset, - NULL, NULL, NULL - }; - -/* Front end processor (console terminal) - - Communications between the KS10 and its front end is based on an in-memory - status block and two interrupt lines: interrupt-to-control (APR_ITC) and - interrupt-from-console (APR_CON). When the KS10 wants to print a character - on the terminal, - - 1. It places a character, plus the valid flag, in FE_CTYOUT. - 2. It interrupts the front end processor. - 3. The front end processor types the character and then zeroes FE_CTYOUT. - 4. The front end procesor interrupts the KS10. - - When the front end wants to send an input character to the KS10, - - 1. It places a character, plus the valid flag, in FE_CTYIN. - 2. It interrupts the KS10. - 3. It waits for the KS10 to take the character and clear the valid flag. - 4. It can then send more input (the KS10 may signal this by interrupting - the front end). - - Note that the protocol has both ambiguity (interrupt to the KS10 may mean - character printed, or input character available, or both) and lack of - symmetry (the KS10 does not inform the front end that it has taken an - input character). -*/ - -/* Here is the definition of the communications area: -XPP RLWORD,31 ;RELOAD WORD [FE_KEEPA] - KSRLD==1B4 ;RELOAD REQUEST (8080 will reload -10 if this is set) - KPACT==1B5 ;KEEP ALIVE ACTIVE (8080 reloads -10 if KPALIV doesn't change) - KLACT==1B6 ;KLINIK ACTIVE (Remote diagnosis line enabled) - PAREN==1B7 ;PARITY ERROR DETECT ENABLED - CRMPAR==1B8 ;CRAM PAR ERR DETECT ENABLED - DRMPAR==1B9 ;DRAM PAR ERR DETECT ENABLED - CASHEN==1B10 ;CACHE ENABLED - MILSEN==1B11 ;1MSEC ENABLED - TRPENA==1B12 ;TRAPS ENABLED - MFGMOD==1B13 ;MANUFACTURING MODE - KPALIV==377B27 ;KEEP ALIVE WORD CHECKED EVERY 1 SEC, AFTER 15, FAIL - ; Why reload (8080->10) - AUTOBT==1B32 ;BOOT SWITCH OR POWER UP CONDITION - PWRFAL==1B33 ;POWER FAIL restart (Start at 70) - FORREL==1B34 ;FORCED RELOAD - KEPFAL==1B35 ;KEEP ALIVE FAILURE (XCT exec 71) - -XPP CTYIWD,32 ;CTY INPUT WORD [FE_CTYIN] - CTYICH==377B35 ;CTY INPUT CHARACTER - CTYIVL==1B27 ;INPUT VALID BIT (Actually, this is an 8-bit function code) - -XPP CTYOWD,33 ;CTY OUTPUT WORD [FE_CTYOUT] - CTYOCH==377B35 ;CTY OUTPUT CHARACTER - CTYOVL==1B27 ;OUTPUT VALID FLAG - -XPP KLIIWD,34 ;KLINIK INPUT WORD [FE_KLININ] - KLIICH==377B35 ;KLINIK INPUT CHARACTER - KLIIVL==1B27 ;KLINIK INPUT VALID (Historical) - KLICHR==1B27 ;KLINIK CHARACTER - KLIINI==2B27 ;KLINIK INITED - KLICAR==3B27 ;CARRIER LOST - - -XPP KLIOWD,35 ;KLINIK OUTPUT WORD [FE_KLINOUT] - KLIOCH==377B35 ;KLINIK OUTPUT CHARACTER - KLIOVL==1B27 ;KLINIK OUTPUT VALID (Historical) - KLOCHR==1B27 ;KLINIK CHARACTER AVAILABLE - KLIHUP==2B27 ;KLINIK HANGUP REQUEST -*/ - -void fe_intr (void) -{ -if (M[FE_CTYOUT] & FE_CVALID) { /* char to print? */ - feo_unit.buf = (int32) M[FE_CTYOUT] & 0177; /* pick it up */ - feo_unit.pos = feo_unit.pos + 1; - sim_activate (&feo_unit, feo_unit.wait); /* sched completion */ - } -else if ((M[FE_CTYIN] & FE_CVALID) == 0) { /* input char taken? */ - sim_activate_abs (&fei_unit, 0); /* sched immed kbd poll */ - } -return; -} - -t_stat feo_svc (UNIT *uptr) -{ -t_stat r; - -if ((r = sim_putchar_s (uptr->buf)) != SCPE_OK) { /* output; error? */ - sim_activate (uptr, uptr->wait); /* try again */ - return ((r == SCPE_STALL)? SCPE_OK: r); /* !stall? report */ - } -M[FE_CTYOUT] = 0; /* clear char */ -apr_flg = apr_flg | APRF_CON; /* interrupt KS10 */ -return SCPE_OK; -} - -t_stat fei_svc (UNIT *uptr) -{ -int32 temp; - -sim_activate (uptr, clk_cosched (tmxr_poll)); /* continue poll */ -if ((temp = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */ - return temp; -if (temp & SCPE_BREAK) /* ignore break */ - return SCPE_OK; -uptr->buf = temp & 0177; -uptr->pos = uptr->pos + 1; -M[FE_CTYIN] = uptr->buf | FE_CVALID; /* put char in mem */ -apr_flg = apr_flg | APRF_CON; /* interrupt KS10 */ -return SCPE_OK; -} - -/* Keep-alive service - * If the 8080 detects the 'force reload' bit, it initiates a disk - * boot. IO is reset, but memory is preserved. - * - * If the keep-alive enable bit is set, the -10 updates the keep-alive - * count field every second. The 8080 also checks the word every second. - * If the 8080 finds that the count hasn't changed for 15 consecutive seconds, - * a Keep-Alive Failure is declared. This forces the -10 to execute the - * contents of exec location 71 to collect status and initiate error recovery. - */ - -static t_stat kaf_svc (UNIT *uptr) -{ -if (M[FE_KEEPA] & INT64_C(0020000000000)) { /* KSRLD - "Forced" (actually, requested) reload */ - uint32 oldsw = sim_switches; - DEVICE *bdev = NULL; - int32 i; - - sim_switches &= ~SWMASK ('P'); - reset_all (4); /* RESET IO starting with UBA */ - sim_switches = oldsw; - - M[FE_KEEPA] &= ~INT64_C(0030000177777); /* Clear KAF, RLD, KPALIV & reason - * 8080 ucode actually clears HW - * status too, but that's a bug. */ - M[FE_KEEPA] |= 02; /* Reason = FORREL */ - fei_unit.buf = feo_unit.buf = 0; - M[FE_CTYIN] = M[FE_CTYOUT] = 0; - M[FE_KLININ] = M[FE_KLINOUT] = 0; - - /* The 8080 has the disk RH address & unit in its memory, even if - * the previous boot was from tape. It has no NVM, so the last opr - * selection will do here. The case of DS MT would require a - * SET FE command. It's not a common case. - */ - - /* The device may have been detached, disabled or reconfigured since boot time. - * Therefore, search for it by CSR address & validate that it's bootable. - * If there are problems, the processor is halted. - */ - - for (i = 0; fe_bootrh && ((bdev = sim_devices[i]) != NULL); i++ ) { - DIB *dibp = (DIB *)bdev->ctxt; - if (dibp && (fe_bootrh >= dibp->ba) && - (fe_bootrh < (dibp->ba + dibp->lnt))) { - break; - } - } - - fe_xct = 2; - if ((bdev != NULL) && (fe_bootunit >= 0) && (fe_bootunit < (int32) bdev->numunits)) { - UNIT *bunit = bdev->units + fe_bootunit; - - if (!(bunit->flags & UNIT_DIS) && (bunit->flags & UNIT_ATTABLE) && (bunit->flags & UNIT_ATT)) { - if (bdev->boot (fe_bootunit, bdev) == SCPE_OK) /* boot the device */ - fe_xct = 1; - } - } - } -else if (M[FE_KEEPA] & INT64_C(0010000000000)) { /* KPACT */ - d10 kav = M[FE_KEEPA] & INT64_C(0000000177400); /* KPALIV */ - if (kaf_unit.u3 != (int32)kav) { /* change? */ - kaf_unit.u3 = (int32)kav; /* start over */ - kaf_unit.u4 = 0; - } - else if (++kaf_unit.u4 >= 15) { - kaf_unit.u4 = 0; - M[FE_KEEPA] = (M[FE_KEEPA] & ~INT64_C(0000000000377)) | 01; /* RSN = KAF (leaves enabled) */ - fei_unit.buf = feo_unit.buf = 0; - M[FE_CTYIN] = M[FE_CTYOUT] = 0; - M[FE_KLININ] = M[FE_KLINOUT] = 0; - fe_xct = 071; - } - } - -sim_activate_after (&kaf_unit, kaf_unit.wait); -if (fe_xct == 2) { - fe_xct = 0; - return STOP_CONSOLE; - } -return SCPE_OK; -} - -/* Reset */ - -t_stat fe_reset (DEVICE *dptr) -{ -fei_unit.buf = feo_unit.buf = 0; -M[FE_CTYIN] = M[FE_CTYOUT] = 0; -M[FE_KLININ] = M[FE_KLINOUT] = 0; - -M[FE_KEEPA] = INT64_C(0003740000000); /* PARITY STOP, CRM, DP PAREN, CACHE EN, 1MSTMR, TRAPEN */ -kaf_unit.u3 = 0; -kaf_unit.u4 = 0; -apr_flg = apr_flg & ~(APRF_ITC | APRF_CON); -sim_activate (&fei_unit, tmxr_poll); -sim_activate_after (&kaf_unit, kaf_unit.wait); -return SCPE_OK; -} - -/* Stop operating system */ - -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; -} diff --git a/PDP10/pdp10_ksio.c b/PDP10/pdp10_ksio.c deleted file mode 100644 index e9afbe73..00000000 --- a/PDP10/pdp10_ksio.c +++ /dev/null @@ -1,1972 +0,0 @@ -/* pdp10_ksio.c: PDP-10 KS10 I/O subsystem simulator - - Copyright (c) 1993-2017, 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. - - uba Unibus adapters - - 7-Mar-17 RMS Added BR level to vector display - 27-May-13 RMS Fixed bugs in Unibus adapter code - 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) - 25-Jan-04 RMS Added stub floating address routine - 12-Mar-03 RMS Added logical name support - 10-Oct-02 RMS Revised for dynamic table generation - Added SHOW IOSPACE routine - 29-Sep-02 RMS Added variable vector, central map support - 25-Jan-02 RMS Revised for multiple DZ11's - 06-Jan-02 RMS Revised enable/disable support - 23-Sep-01 RMS New IO page address constants - 07-Sep-01 RMS Revised device disable mechanism - 25-Aug-01 RMS Enabled DZ11 - 21-Aug-01 RMS Updated DZ11 disable - 01-Jun-01 RMS Updated DZ11 vectors - 12-May-01 RMS Fixed typo - - The KS10 uses the PDP-11 Unibus for its I/O, via adapters. While - nominally four adapters are supported, in practice only 1 and 3 - are implemented. The disks are placed on adapter 1, the rest of - the I/O devices on adapter 3. (adapter 4 IS used in some supported - configurations, but those devices haven't been emulated yet.) - - In theory, we should maintain completely separate Unibuses, with - distinct PI systems. In practice, this simulator has so few devices - that we can get away with a single PI system, masking for which - devices are on adapter 1, and which on adapter 3. The Unibus - implementation is modeled on the Qbus in the PDP-11 simulator and - is described there. - - The I/O subsystem is programmed by I/O instructions which create - Unibus operations (read, read pause, write, write byte). DMA is - the responsibility of the I/O device simulators, which also implement - Unibus to physical memory mapping. - - The priority interrupt subsystem (and other privileged functions) - is programmed by I/O instructions with internal devices codes - (opcodes 700-702). These are dispatched here, although many are - handled in the memory management unit or elsewhere. - - The ITS instructions are significantly different from the TOPS-10/20 - instructions. They do not use the extended address calculation but - instead provide instruction variants (Q for Unibus adapter 1, I for - Unibus adapter 3) which insert the Unibus adapter number into the - effective address. -*/ - -#include "pdp10_defs.h" -#include -#include -#include -#include "sim_sock.h" -#include "sim_tmxr.h" - -#define UBMPAGE(x) (x & (PAG_VPN<<2)) /* UBA Map page field of 11 address */ -#define XBA_MBZ 0400000 /* ba mbz */ -#define eaRB (ea & ~1) -#define GETBYTE(ea,x) ((((ea) & 1)? (x) >> 8: (x)) & 0377) -#define UBNXM_FAIL(pa,op) \ - n = ADDR2UBA (pa); \ - if (n >= 0) \ - ubcs[n] = ubcs[n] | UBCS_TMO | UBCS_NXD; \ - pager_word = PF_HARD | PF_VIRT | PF_IO | \ - ((op == WRITEB)? PF_BYTE: 0) | \ - (TSTF (F_USR)? PF_USER: 0) | (pa); \ - ABORT (PAGE_FAIL) -/* Is Unibus address mapped to -10 memory */ -#define TEN_MAPPED(ub,ba) ((ubmap[ub][PAG_GETVPN(((ba) & 0777777) >> 2)] & UMAP_VLD) != 0) - -/* Translate UBA number in a PA to UBA index. 1,,* -> ubmap[0], all others -> ubmap[1] */ -#define ADDR2UBA(x) (iocmap[GET_IOUBA (x)]) - -/* Unibus adapter data */ - -int32 ubcs[UBANUM] = { 0 }; /* status registers */ -int32 ubmap[UBANUM][UMAP_MEMSIZE] = {{ 0 }}; /* Unibus maps */ -int32 int_req = 0; /* interrupt requests */ - -/* Map IO controller numbers to Unibus adapters: -1 = non-existent */ - -static int iocmap[IO_N_UBA] = { /* map I/O ext to UBA # */ - -1, 0, -1, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 - }; - -static const int32 ubabr76[UBANUM] = { - INT_UB1 & (INT_IPL7 | INT_IPL6), INT_UB3 & (INT_IPL7 | INT_IPL6) - }; -static const int32 ubabr54[UBANUM] = { - INT_UB1 & (INT_IPL5 | INT_IPL4), INT_UB3 & (INT_IPL5 | INT_IPL4) - }; -static const uint32 iplmask[4] = { - INT_IPL4, INT_IPL5, INT_IPL6, INT_IPL7 - }; - -/* Masks for Unibus quantities */ -#define M_BYTE (0xFF) -#define M_WORD (0xFFFF) -#define M_WORD18 (0777777) -#define M_LH (0777777000000) -#define M_RH (0000000777777) - -/* Bits to shift for each Unibus byte */ -#define V_BYTE0 (18) -#define V_BYTE1 (26) -#define V_BYTE2 (0) -#define V_BYTE3 (8) - -#define V_WORD0 V_BYTE0 -#define V_WORD1 V_BYTE2 - -/* Bits to preserve when writing each Unibus byte. - * This excludes the XX bits so they are cleared. - */ -#define M_BYTE0 (~INT64_C (0000377000000)) /* Clear byte 0 */ -#define M_BYTE1 (~INT64_C (0777400000000)) /* Clear byte 1 + XX */ -#define M_BYTE2 (~INT64_C (0000000000377)) /* Clear byte 2 */ -#define M_BYTE3 (~INT64_C (0000000777400)) /* Clear byte 3 + XX */ - -#define M_WORD0 (~INT64_C (0777777000000)) /* Clear word 0 + XX */ -#define M_WORD1 (~INT64_C (0000000777777)) /* Clear word 1 + XX */ - -extern d10 *M; /* main memory */ -extern d10 *ac_cur; -extern d10 pager_word; -extern int32 flags; -extern const int32 pi_l2bit[8]; -extern UNIT cpu_unit; -extern jmp_buf save_env; - -extern int32 pi_eval (void); -extern int32 rp_inta (void); -extern int32 tu_inta (void); -extern int32 lp20_inta (void); -extern int32 dz_rxinta (void); -extern int32 dz_txinta (void); - -t_stat ubmap_rd (int32 *data, int32 addr, int32 access); -t_stat ubmap_wr (int32 data, int32 addr, int32 access); -t_stat ubs_rd (int32 *data, int32 addr, int32 access); -t_stat ubs_wr (int32 data, int32 addr, int32 access); -t_stat rd_zro (int32 *data, int32 addr, int32 access); -t_stat wr_nop (int32 data, int32 addr, int32 access); -t_stat uba_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); -t_stat uba_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); -t_stat uba_reset (DEVICE *dptr); -void uba_debug_dma_in (uint32 ba, a10 pa_start, a10 pa_end); -void uba_debug_dma_out (uint32 ba, a10 pa_start, a10 pa_end); -d10 ReadIO (a10 ea); -void WriteIO (a10 ea, d10 val, int32 mode); - -/* Unibus adapter data structures - - uba_dev UBA device descriptor - uba_unit UBA units - uba_reg UBA register list -*/ - -DIB ubmp1_dib = { IOBA_UBMAP1, IOLN_UBMAP1, &ubmap_rd, &ubmap_wr, 0 }; -DIB ubmp3_dib = { IOBA_UBMAP3, IOLN_UBMAP3, &ubmap_rd, &ubmap_wr, 0 }; -DIB ubcs1_dib = { IOBA_UBCS1, IOLN_UBCS1, &ubs_rd, &ubs_wr, 0 }; -DIB ubcs3_dib = { IOBA_UBCS3, IOLN_UBCS3, &ubs_rd, &ubs_wr, 0 }; -DIB ubmn1_dib = { IOBA_UBMNT1, IOLN_UBMNT1, &rd_zro, &wr_nop, 0 }; -DIB ubmn3_dib = { IOBA_UBMNT3, IOLN_UBMNT3, &rd_zro, &wr_nop, 0 }; -DIB msys_dib = { 00100000, 1, &rd_zro, &wr_nop, 0 }; - -UNIT uba_unit[] = { - { UDATA (NULL, UNIT_FIX, UMAP_MEMSIZE) }, - { UDATA (NULL, UNIT_FIX, UMAP_MEMSIZE) } - }; - -REG uba_reg[] = { - { ORDATA (INTREQ, int_req, 32), REG_RO }, - { ORDATA (UB1CS, ubcs[0], 18) }, - { ORDATA (UB3CS, ubcs[1], 18) }, - { NULL } - }; - -#define DBG_DMA_IN 0x0001 /* trace dma input transfers */ -#define DBG_DMA_OUT 0x0002 /* trace dma output transfers */ -#define DBG_DMA_NXM 0x0004 /* trace dma nxm errors */ - -DEBTAB uba_debug[] = { - {"IN", DBG_DMA_IN}, - {"OUT", DBG_DMA_OUT}, - {"NXM", DBG_DMA_NXM}, - {0} - }; - -DEVICE uba_dev = { - "UBA", uba_unit, uba_reg, NULL, - UBANUM, 8, UMAP_ASIZE, 1, 8, 32, - &uba_ex, &uba_dep, &uba_reset, - NULL, NULL, NULL, - NULL, DEV_DEBUG, 0, uba_debug - }; - -/* PDP-11 I/O structures */ - -DIB *dib_tab[DIB_MAX]; /* run-time DIBs */ - -int32 (*int_ack[32])(void); /* int ack routines */ - -int32 int_vec[32]; /* int vectors */ - -DIB *std_dib[] = { /* standard DIBs */ - &ubmp1_dib, - &ubmp3_dib, - &ubcs1_dib, - &ubcs3_dib, - &ubmn1_dib, - &ubmn3_dib, - &msys_dib, - NULL - }; - -/* IO 710 (DEC) TIOE - test I/O word, skip if zero - (ITS) IORDI - read word from Unibus 3 - returns TRUE if skip, FALSE otherwise -*/ - -t_bool io710 (int32 ac, a10 ea) -{ -d10 val; - -if (Q_ITS) /* IORDI */ - AC(ac) = ReadIO (IO_UBA3 | ea); -else { /* TIOE */ - val = ReadIO (ea); /* read word */ - if ((AC(ac) & val) == 0) - return TRUE; - } -return FALSE; -} - -/* IO 711 (DEC) TION - test I/O word, skip if non-zero - (ITS) IORDQ - read word from Unibus 1 - returns TRUE if skip, FALSE otherwise -*/ - -t_bool io711 (int32 ac, a10 ea) -{ -d10 val; - -if (Q_ITS) /* IORDQ */ - AC(ac) = ReadIO (IO_UBA1 | ea); -else { /* TION */ - val = ReadIO (ea); /* read word */ - if ((AC(ac) & val) != 0) - return TRUE; - } -return FALSE; -} - -/* IO 712 (DEC) RDIO - read I/O word, addr in ea - (ITS) IORD - read I/O word, addr in M[ea] -*/ - -d10 io712 (a10 ea) -{ -return ReadIO (ea); /* RDIO, IORD */ -} - -/* IO 713 (DEC) WRIO - write I/O word, addr in ea - (ITS) IOWR - write I/O word, addr in M[ea] -*/ - -void io713 (d10 val, a10 ea) -{ -WriteIO (ea, val, WRITE); /* WRIO, IOWR */ -return; -} - -/* IO 714 (DEC) BSIO - set bit in I/O address - (ITS) IOWRI - write word to Unibus 3 -*/ - -void io714 (d10 val, a10 ea) -{ -d10 temp; - -if (Q_ITS) /* IOWRI */ - WriteIO (IO_UBA3 | ea, val, WRITE); -else { - temp = ReadIO (ea); /* BSIO */ - temp = temp | val; - WriteIO (ea, temp, WRITE); - } -return; -} - -/* IO 715 (DEC) BCIO - clear bit in I/O address - (ITS) IOWRQ - write word to Unibus 1 -*/ - -void io715 (d10 val, a10 ea) -{ -d10 temp; - -if (Q_ITS) /* IOWRQ */ - WriteIO (IO_UBA1 | ea, val, WRITE); -else { - temp = ReadIO (ea); /* BCIO */ - temp = temp & ~val; - WriteIO (ea, temp, WRITE); - } -return; -} - -/* IO 720 (DEC) TIOEB - test I/O byte, skip if zero - (ITS) IORDBI - read byte from Unibus 3 - returns TRUE if skip, FALSE otherwise -*/ - -t_bool io720 (int32 ac, a10 ea) -{ -d10 val; - -if (Q_ITS) { /* IORDBI */ - val = ReadIO (IO_UBA3 | eaRB); - AC(ac) = GETBYTE (ea, val); - } -else { /* TIOEB */ - val = ReadIO (eaRB); - val = GETBYTE (ea, val); - if ((AC(ac) & val) == 0) - return TRUE; - } -return FALSE; -} - -/* IO 721 (DEC) TIONB - test I/O word, skip if non-zero - (ITS) IORDBQ - read word from Unibus 1 - returns TRUE if skip, FALSE otherwise -*/ - -t_bool io721 (int32 ac, a10 ea) -{ -d10 val; - -if (Q_ITS) { /* IORDBQ */ - val = ReadIO (IO_UBA1 | eaRB); - AC(ac) = GETBYTE (ea, val); - } -else { /* TIONB */ - val = ReadIO (eaRB); - val = GETBYTE (ea, val); - if ((AC(ac) & val) != 0) - return TRUE; - } -return FALSE; -} - -/* IO 722 (DEC) RDIOB - read I/O byte, addr in ea - (ITS) IORDB - read I/O byte, addr in M[ea] -*/ - -d10 io722 (a10 ea) -{ -d10 val; - -val = ReadIO (eaRB); /* RDIOB, IORDB */ -return GETBYTE (ea, val); -} - -/* IO 723 (DEC) WRIOB - write I/O byte, addr in ea - (ITS) IOWRB - write I/O byte, addr in M[ea] -*/ - -void io723 (d10 val, a10 ea) -{ -WriteIO (ea, val & M_BYTE, WRITEB); /* WRIOB, IOWRB */ -return; -} - -/* IO 724 (DEC) BSIOB - set bit in I/O byte address - (ITS) IOWRBI - write byte to Unibus 3 -*/ - -void io724 (d10 val, a10 ea) -{ -d10 temp; - -val = val & M_BYTE; -if (Q_ITS) /* IOWRBI */ - WriteIO (IO_UBA3 | ea, val, WRITEB); -else { - temp = ReadIO (eaRB); /* BSIOB */ - temp = GETBYTE (ea, temp); - temp = temp | val; - WriteIO (ea, temp, WRITEB); - } -return; -} - -/* IO 725 (DEC) BCIOB - clear bit in I/O byte address - (ITS) IOWRBQ - write byte to Unibus 1 -*/ - -void io725 (d10 val, a10 ea) -{ -d10 temp; - -val = val & M_BYTE; -if (Q_ITS) /* IOWRBQ */ - WriteIO (IO_UBA1 | ea, val, WRITEB); -else { - temp = ReadIO (eaRB); /* BCIOB */ - temp = GETBYTE (ea, temp); - temp = temp & ~val; - WriteIO (ea, temp, WRITEB); - } -return; -} - -/* Read and write I/O devices. - These routines are the linkage between the 64b world of the main - simulator and the 32b world of the device simulators. -*/ - -/* UBReadIO and UBWriteIO handle the device lookup and access - * These are used for all IO space accesses. They return status. - * - * ReadIO and WriteIO are used by the CPU instructions, and generate - * UBA NXM page fails for unassigned IO addresses. - */ - -static t_stat UBReadIO (int32 *data, int32 ba, int32 access) -{ -uint32 pa = (uint32) ba; -int32 i, val; -DIB *dibp; - -for (i = 0; (dibp = dib_tab[i]); i++ ) { - if ((pa >= dibp->ba) && - (pa < (dibp->ba + dibp->lnt))) { - dibp->rd (&val, pa, access); - pi_eval (); - *data = val; - return SCPE_OK; - } - } -return SCPE_NXM; -} - -d10 ReadIO (a10 ea) -{ -uint32 pa = (uint32) ea; -int32 n, val; - - if (UBReadIO (&val, pa, READ) == SCPE_OK) - return ((d10) val); - UBNXM_FAIL (pa, READ); -} - - -static t_stat UBWriteIO (int32 data, int32 ba, int32 access) -{ -uint32 pa = (uint32) ba; -int32 i; -DIB *dibp; - -for (i = 0; (dibp = dib_tab[i]); i++ ) { - if ((pa >= dibp->ba) && - (pa < (dibp->ba + dibp->lnt))) { - if ((dibp->flags & DIB_M_REGSIZE) == DIB_REG16BIT) { - data &= M_WORD; - } - dibp->wr (data, ba, access); - pi_eval (); - return SCPE_OK; - } - } -return SCPE_NXM; -} - -void WriteIO (a10 ea, d10 val, int32 mode) -{ -uint32 pa = (uint32) ea; -int32 n; - -if (UBWriteIO ((int32) val, (int32) pa, mode) == SCPE_OK) - return; -UBNXM_FAIL (pa, mode); -} - -/* Mapped read and write routines - used by standard Unibus devices on Unibus 1 - * I/O space accesses will work. Note that Unibus addresses with bit 17 set can - * not be mapped by the UBA, so I/O space (and more) can not be mapped to -10 memory. - */ - -static a10 Map_Addr10 (a10 ba, int32 ub, int32 *ubmp) -{ -a10 pa10; -int32 vpn = PAG_GETVPN (ba >> 2); /* get PDP-10 page number */ -int32 ubm; - -if ((vpn >= UMAP_MEMSIZE) || (ba & XBA_MBZ)) { /* Validate bus address */ - if (ubmp) - *ubmp = 0; - return -1; -} -ubm = ubmap[ub][vpn]; -if (ubmp) - *ubmp = ubm; - -if ((ubm & UMAP_VLD) == 0) /* Ensure map entry is valid */ - return -1; -pa10 = (ubm + PAG_GETOFF (ba >> 2)) & PAMASK; -return pa10; -} - -/* Routines for Bytes, Words (16-bit) and Words (18-bit). - * - * Note that the byte count argument is always BYTES, even if - * the unit transfered is a word. This is for compatibility with - * the 11/VAX system Unibus; these routines abstract DMA for all - * U/Q device simulations. - * - * All return the number of bytes NOT transferred; 0 means success. - * A non-zero return implies a NXM was encountered. - * - * Unaligned accesses to 16/18-bit words in IOSPACE are a STOP condition. - * (Should be in memory too, but some devices are lazy.) - * - * Unibus memory is mapped into 36-bit words so that 16-bit - * values appear in 18-bit half-words, and PDP10 byte pointers will - * increment through 16-bit (but not 8-bit) data. Viewed as bytes or - * words from the PDP10, memory looks like this: - * - * +-----+-----------+------------+-------+------------+------------+ - * | 0 1 | 2 9 | 10 17 | 18 19 | 20 27| 28 35 | PDP10 bits - * +-----+-----------+------------+-------+------------+------------+ - * | X X | BYTE 1<01>| BYTE 0<00> | X X | BYTE 3<11> | BYTE 2<10> | PDP11 bytes - * +-----+-----------+------------+-------+------------+------------+ - * | X X | WORD 0 <00> | X X | WORD 1 <10> | PDP11 words - * +-----+-----------+------------+-------+------------+------------+ - * - * are the values of the two low-order address bits as viewed on - * the Unibus. - * - * The bits marked XX are written as zero for 8 and 16 bit transfers - * and with data from the Unibus parity lines for 18 bit transfers. - * In a -10 read-modify-write cycle, they are cleared if the high byte - * of the adjacent word is written, and preserved otherwise. - * - * Unibus addressing does not change with 18-bit transfers; they are - * accounted for as 2 bytes. <0:1> are bits <17:16> of word 0; - * <18:19> are bits <17:16> of word 1. - * - * Normal writes assume that DMA will access sequential Unibus addresses. - * The UBA optimizes this by writing NPR data to <00> addresses - * without preserving the rest of the -10 word. This allows a memory - * write cycle, rather than the read-modify-write cycle required to - * preserve the rest of the word. The 'read reverse' bit in the UBA - * map forces a read-modify-write on all addresses. - * - * 16-bit transfers (the d18 bit in the map selects) write 0s into - * the correspnding X bits when <00> or <10> are written. - * - * Address mapping uses bits <1:0> of the Unibus address to select - * the byte as indicated above. Bits <10:2> are the offset within - * the PDP10 page; thus Unibus addressing assumes 4 bytes/PDP10 word. - * - * 9 bits = 512 words/PDP10 page = 2048 bytes / Unibus page - * - * Bits 16:11 select a UBA mapping register, which indicates whether - * PDP10 memory at that address is accessible, and if so, provides - * PDP10 bus address bits that replace and extend the Unibus bits. - * - * Unibus addresses with bit 17 set do not map PDP10 memory. The - * high end is reserved for Unibus IO space. The rest is used for - * UBA maintenance modes (not simulated). - * - * IO space accesses may have side effects in the device; an aligned - * read of two bytes is NOT equivalent to two one byte reads of the - * same addresses. - * - * The memory access in these routines is optimized to minimize UBA - * page table lookups and shift/merge operations with PDP10 memory. - * - * Memory transfers happen in up to 3 pieces: - * head : 0-3 bytes to an aligned PDP10 word (UB address 000b) - * body : As many PDP10 whole words as possible (4 bytes 32/36 bits) - * tail : 0-3 bytes remaining after the body. - */ - -int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf) -{ -uint32 ea, ofs, cp, np; -int32 seg; -a10 pa10 = ~0u; -d10 m; -uint32 dpy_ba = ba; -a10 dpy_pa10 = ~0u; - -if ((ba & ~((IO_M_UBA<> 8) & 0xff): csr & 0xff; - ba++; - bc--; - } - return bc; - } - -/* Memory */ - -if (bc == 0) - return 0; - -cp = ~ba; -ofs = ba & 3; -seg = (4 - ofs) & 3; - -if (seg) { /* Unaligned head */ - if (seg > bc) - seg = bc; - cp = UBMPAGE (ba); /* Only one word, can't cross page */ - dpy_pa10 = pa10 = Map_Addr10 (ba, 1, NULL); /* map addr */ - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ - uba_debug_dma_nxm ("Read Byte", pa10, ba, bc); - return bc; /* return bc */ - } - m = M[pa10++]; - ba += seg; - bc -= seg; - switch (ofs) { - case 1: - *buf++ = (uint8) ((m >> V_BYTE1) & M_BYTE); - if (!--seg) - break; - case 2: - *buf++ = (uint8) (m & M_BYTE); /* V_BYTE2 */ - if (!--seg) - break; - case 3: - *buf++ = (uint8) ((m >> V_BYTE3) & M_BYTE); - --seg; - break; - default: - assert (FALSE); - } - if (bc == 0) { - uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); - return 0; - } - } /* Head */ - -/* At this point, ba is aligned. Therefore, ea<1:0> are the tail's length */ -ea = ba + bc; -seg = bc - (ea & 3); - -if (seg > 0) { /* Body: Whole PDP-10 words, 4 bytes */ - assert (((seg & 3) == 0) && (bc >= seg)); - dpy_ba = ba; - bc -= seg; - for ( ; seg; seg -= 4, ba += 4) { /* aligned longwords */ - np = UBMPAGE (ba); - if (np != cp) { /* New (or first) page? */ - uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); - dpy_pa10 = pa10 = Map_Addr10 (ba, 1, NULL);/* map addr */ - dpy_ba = ba; - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ - uba_debug_dma_nxm ("Read Byte", pa10, ba, bc); - return (bc + seg); /* return bc */ - } - cp = np; - } - m = M[pa10++]; /* Next word from -10 */ - buf[2] = (uint8) (m & M_BYTE); /* Byte 2 */ - m >>= 8; - buf[3] = (uint8) (m & M_BYTE); /* Byte 3 */ - m >>= 10; - buf[0] = (uint8) (m & M_BYTE); /* Byte 0 */ - m >>= 8; - buf[1] = (uint8) (m & M_BYTE); /* Byte 1 */ - buf += 4; - } - } /* Body */ - - /* Tail: partial -10 word, must be aligned. 1-3 bytes */ -assert ((bc >= 0) && ((ba & 3) == 0)); -if (bc) { - assert (bc <= 3); - np = UBMPAGE (ba); /* Only one word, last possible page crossing */ - if (np != cp) { /* New (or first) page? */ - uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); - dpy_pa10 = pa10 = Map_Addr10 (ba, 1, NULL);/* map addr */ - dpy_ba = ba; - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) {/* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ - uba_debug_dma_nxm ("Read Byte", pa10, ba, bc); - return (bc); /* return bc */ - } - } - m = M[pa10++]; - switch (bc) { - case 3: - buf[2] = (uint8) (m & M_BYTE); /* V_BYTE2 */ - case 2: - buf[1] = (uint8) ((m >> V_BYTE1) & M_BYTE); - case 1: - buf[0] = (uint8) ((m >> V_BYTE0) & M_BYTE); - break; - default: - assert (FALSE); - } - } - -uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); -return 0; -} - -int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf) -{ -uint32 ea, cp, np; -int32 seg; -a10 pa10 = ~0u; -d10 m; -uint32 dpy_ba = ba; -a10 dpy_pa10 = ~0u; - -if ((ba & ~((IO_M_UBA< bc) - seg = bc; - cp = UBMPAGE (ba); /* Only one word, can't cross page */ - dpy_pa10 = pa10 = Map_Addr10 (ba, 1, NULL); /* map addr */ - dpy_ba = ba; - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ - uba_debug_dma_nxm ("Read Word", pa10, ba, bc); - return bc; /* return bc */ - } - ba += seg; - *buf++ = (uint16) (M[pa10++] & M_WORD); - if ((bc -= seg) == 0) { - uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); -return 0; -} - } /* Head */ - -ea = ba + bc; -seg = bc - (ea & 3); - -if (seg > 0) { - assert (((seg & 3) == 0) && (bc >= seg)); - bc -= seg; - for ( ; seg; seg -= 4, ba += 4) { /* aligned longwords */ - np = UBMPAGE (ba); - if (np != cp) { /* New (or first) page? */ - uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); - dpy_pa10 = pa10 = Map_Addr10 (ba, 1, NULL);/* map addr */ - dpy_ba = ba; - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ - uba_debug_dma_nxm ("Read Word", pa10, ba, bc); - return (bc + seg); /* return bc */ - } - cp = np; - } - m = M[pa10++]; /* Next word from -10 */ - buf[1] = (uint16) (m & M_WORD); /* Bytes 3,,2 */ - m >>= 18; - buf[0] = (uint16) (m & M_WORD); /* Bytes 1,,0 */ - buf += 2; -} - } /* Body */ - -/* Tail: partial word, must be aligned, can only be WORD0 */ -assert ((bc >= 0) && ((ba & 3) == 0)); -if (bc) { - assert (bc == 2); - np = UBMPAGE (ba); /* Only one word, last possible page crossing */ - if (np != cp) { /* New (or first) page? */ - uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); - dpy_pa10 = pa10 = Map_Addr10 (ba, 1, NULL);/* map addr */ - dpy_ba = ba; - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) {/* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ - uba_debug_dma_nxm ("Read Word", pa10, ba, bc); - return (bc); /* return bc */ - } - } - *buf = (uint16) ((M[pa10++] >> V_WORD0) & M_WORD); -} - -uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); -return 0; -} - -/* Word reads returning 18-bit data - * - * Identical to 16-bit reads except that buffer is uint32 - * and masked to 18 bits. -*/ - -int32 Map_ReadW18 (uint32 ba, int32 bc, uint32 *buf) -{ -uint32 ea, cp, np; -int32 seg; -a10 pa10 = ~0u; -d10 m; -uint32 dpy_ba = ba; -a10 dpy_pa10 = ~0u; - -if ((ba & ~((IO_M_UBA< bc) - seg = bc; - cp = UBMPAGE (ba); /* Only one word, can't cross page */ - dpy_pa10 = pa10 = Map_Addr10 (ba, 1, NULL); /* map addr */ - dpy_ba = ba; - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ - uba_debug_dma_nxm ("Read 18b Word", pa10, ba, bc); - return bc; /* return bc */ -} - ba += seg; - *buf++ = (uint32) (M[pa10++] & M_RH); - if ((bc -= seg) == 0) { - uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); - return 0; -} - } /* Head */ - -ea = ba + bc; -seg = bc - (ea & 3); - -if (seg > 0) { - assert (((seg & 3) == 0) && (bc >= seg)); - bc -= seg; - for ( ; seg; seg -= 4, ba += 4) { /* aligned longwords */ - np = UBMPAGE (ba); - if (np != cp) { /* New (or first) page? */ - uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); - dpy_pa10 = pa10 = Map_Addr10 (ba, 1, NULL);/* map addr */ - dpy_ba = ba; - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) {/* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ - uba_debug_dma_nxm ("Read 18b Word", pa10, ba, bc); - return (bc + seg); /* return bc */ - } - cp = np; -} - m = M[pa10++]; /* Next word from -10 */ - buf[1] = (uint32) (m & M_RH); /* Bytes 3,,2 */ - m >>= 18; - buf[0] = (uint32) (m & M_RH); /* Bytes 1,,0 */ - buf += 2; -} - } /* Body */ - -/* Tail: partial word, must be aligned */ -assert ((bc >= 0) && ((ba & 3) == 0)); -if (bc) { - assert (bc == 2); - np = UBMPAGE (ba); /* Only one word, last possible page crossing */ - if (np != cp) { /* New (or first) page? */ - uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); - dpy_pa10 = pa10 = Map_Addr10 (ba, 1, NULL);/* map addr */ - dpy_ba = ba; - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ - uba_debug_dma_nxm ("Read 18b Word", pa10, ba, bc); - return (bc); /* return bc */ -} - } - *buf++ = (uint32) ((M[pa10++] >> V_WORD0) & M_RH); - } - -uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); -return 0; -} - -/* Word reads returning 36-bit data - * - * Identical to 16-bit reads except that buffer is d10 - * and masked to 36 bits. - */ - -int32 Map_ReadW36 (uint32 ba, int32 bc, d10 *buf) -{ -uint32 ea, cp, np; -int32 seg; -a10 pa10 = ~0u; -int32 ub = ADDR2UBA (ba); -uint32 dpy_ba = ba; -a10 dpy_pa10 = ~0u; - -if ((ba & ~((IO_M_UBA< 0) { - assert (((seg & 3) == 0) && (bc >= seg)); - bc -= seg; - for ( ; seg; seg -= 4, ba += 4) { /* aligned longwords */ - np = UBMPAGE (ba); - if (np != cp) { /* New (or first) page? */ - uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); - dpy_pa10 = pa10 = Map_Addr10 (ba, ub, NULL);/* map addr */ - dpy_ba = ba; - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) {/* inv map or NXM? */ - ubcs[ub] |= UBCS_TMO; /* UBA timeout */ - uba_debug_dma_nxm ("Read 36b Word", pa10, ba, bc); - return (bc + seg); /* return bc */ - } - cp = np; - } - *buf++ = M[pa10++]; /* Next word from -10 */ - } - } /* Body */ - - -uba_debug_dma_out (dpy_ba, dpy_pa10, pa10); -return 0; -} - -/* Byte-mode writes */ - -int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf) -{ -uint32 ea, ofs, cp, np; -int32 seg, ubm = 0; -a10 pa10 = ~0u; -d10 m; -uint32 dpy_ba = ba; -a10 dpy_pa10 = ~0u; - -if ((ba & ~((IO_M_UBA< bc) - seg = bc; - cp = UBMPAGE (ba); /* Only one word, can't cross page */ - dpy_pa10 = pa10 = Map_Addr10 (ba, 1, &ubm); /* map addr */ - dpy_ba = ba; - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ - uba_debug_dma_nxm ("Write Byte", pa10, ba, bc); - return bc; /* return bc */ - } - m = M[pa10]; - ba += seg; - bc -= seg; - switch (ofs) { - case 1: - m = (m & M_BYTE1) | (((d10) (*buf++)) << V_BYTE1); - if (!--seg) - break; - case 2: - m = (m & M_BYTE2) | ((d10) (*buf++)); /* V_BYTE2 */ - if (!--seg) - break; - case 3: - m = (m & M_BYTE3) | (((d10) (*buf++)) << V_BYTE3); - --seg; - break; - default: - assert (FALSE); - } - M[pa10++] = m; - if (bc == 0) { - uba_debug_dma_in (dpy_ba, dpy_pa10, pa10-dpy_pa10); - return 0; - } - } /* Head */ - -ea = ba + bc; -seg = bc - (ea & 3); - -if (seg > 0) { - assert (((seg & 3) == 0) && (bc >= seg)); - bc -= seg; - for ( ; seg; seg -= 4, ba += 4) { /* aligned longwords */ - np = UBMPAGE (ba); - if (np != cp) { /* New (or first) page? */ - uba_debug_dma_in (dpy_ba, dpy_pa10, pa10); - dpy_pa10 = pa10 = Map_Addr10 (ba, 1, &ubm);/* map addr */ - dpy_ba = ba; - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) {/* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ - uba_debug_dma_nxm ("Write Byte", pa10, ba, bc); - return (bc + seg); /* return bc */ - } - cp = np; - } - M[pa10++] = (((d10)((buf[1] << 8) | buf[0])) << 18) | /* <0:1,18:19> = 0 */ - ((buf[3] << 8) | buf[2]); - buf += 4; - } - } /* Body */ - -/* Tail: partial word, must be aligned */ - -assert ((bc >= 0) && ((ba & 3) == 0)); -if (bc) { - assert (bc <= 3); - np = UBMPAGE (ba); /* Only one word, last possible page crossing */ - if (np != cp) { /* New (or first) page? */ - uba_debug_dma_in (dpy_ba, dpy_pa10, pa10); - dpy_pa10 = pa10 = Map_Addr10 (ba, 1, &ubm);/* map addr */ - dpy_ba = ba; - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ - uba_debug_dma_nxm ("Write Byte", pa10, ba, bc); - return (bc); /* return bc */ - } - } - m = M[pa10]; - if ((ubm & UMAP_RRV )) { /* RMW */ - switch (bc) { - case 3: - m = (m & M_BYTE2) | ((d10) (buf[2])); /* V_BYTE2 */ - case 2: - m = (m & M_BYTE1) | (((d10) (buf[1])) << V_BYTE1); - case 1: - m = (m & M_BYTE0) | (((d10) (buf[0])) << V_BYTE0); - break; - default: - assert (FALSE); - } - } - else { - switch (bc) { /* Write byte 0 + RMW bytes 1 & 2 */ - case 3: - m = (((d10) (buf[1])) << V_BYTE1) | (((d10) (buf[0])) << V_BYTE0) | - ((d10) (buf[2])); /* V_BYTE2 */ - break; - case 2: - m = (((d10) (buf[1])) << V_BYTE1) | (((d10) (buf[0])) << V_BYTE0); - break; - case 1: - m = ((d10) (buf[0])) << V_BYTE0; - break; - default: - assert (FALSE); - } - } - M[pa10++] = m; - } - -uba_debug_dma_in (dpy_ba, dpy_pa10, pa10); -return 0; -} - -/* Word mode writes; 16-bit data */ - -int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf) -{ -uint32 ea, cp, np; -int32 seg, ubm = 0; -a10 pa10 = ~0u; -uint32 dpy_ba = ba; -a10 dpy_pa10 = ~0u; - -if ((ba & ~((IO_M_UBA< bc) - seg = bc; - cp = UBMPAGE (ba); /* Only one word, can't cross page */ - dpy_pa10 = pa10 = Map_Addr10 (ba, 1, &ubm); /* map addr */ - dpy_ba = ba; - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ - uba_debug_dma_nxm ("Write Word", pa10, ba, bc); - return bc; /* return bc */ - } - M[pa10] = (M[pa10] & M_WORD1) | ((d10) (*buf++)); - pa10++; - - if ((bc -= seg) == 0) { - uba_debug_dma_in (dpy_ba, dpy_pa10, pa10-dpy_pa10); - return 0; - } - ba += seg; - } /* Head */ - -ea = ba + bc; -seg = bc - (ea & 3); - -if (seg > 0) { - assert (((seg & 3) == 0) && (bc >= seg)); - bc -= seg; - for ( ; seg; seg -= 4, ba += 4) { /* aligned longwords */ - np = UBMPAGE (ba); - if (np != cp) { /* New (or first) page? */ - uba_debug_dma_in (dpy_ba, dpy_pa10, pa10); - dpy_pa10 = pa10 = Map_Addr10 (ba, 1, &ubm);/* map addr */ - dpy_ba = ba; - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) {/* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ - uba_debug_dma_nxm ("Write Word", pa10, ba, bc); - return (bc + seg); /* return bc */ - } - cp = np; - } - M[pa10++] = (((d10)(buf[0])) << V_WORD0) | buf[1];/* <0:1,18:19> = 0 - * V_WORD1 - */ - buf += 2; - } - } /* Body */ - -/* Tail: partial word, must be aligned, can only be WORD0 */ -assert ((bc >= 0) && ((ba & 3) == 0)); -if (bc) { - assert (bc == 2); - np = UBMPAGE (ba); /* Only one word, last possible page crossing */ - if (np != cp) { /* New (or first) page? */ - uba_debug_dma_in (dpy_ba, dpy_pa10, pa10); - dpy_pa10 = pa10 = Map_Addr10 (ba, 1, &ubm);/* map addr */ - dpy_ba = ba; - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ - uba_debug_dma_nxm ("Write Word", pa10, ba, bc); - return (bc); /* return bc */ - } - } - if (ubm & UMAP_RRV ) /* Read reverse preserves RH */ - M[pa10] = (((d10)(buf[0])) << V_WORD0) | (M[pa10] & M_WORD0); - else - M[pa10] = ((d10)(buf[0])) << V_WORD0; - pa10++; - } - -uba_debug_dma_in (dpy_ba, dpy_pa10, pa10); -return 0; -} - - -/* Word mode writes; 18-bit data */ - -int32 Map_WriteW18 (uint32 ba, int32 bc, uint32 *buf) -{ -uint32 ea, cp, np; -int32 seg, ubm = 0; -a10 pa10 = ~0u; -uint32 dpy_ba = ba; -a10 dpy_pa10 = ~0u; - -if ((ba & ~((IO_M_UBA< bc) - seg = bc; - cp = UBMPAGE (ba); /* Only one word, can't cross page */ - dpy_pa10 = pa10 = Map_Addr10 (ba, 1, &ubm); /* map addr */ - dpy_ba = ba; - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ - uba_debug_dma_nxm ("Write 18b Word", pa10, ba, bc); - return bc; /* return bc */ - } - M[pa10] = (M[pa10] & M_WORD1) | ((d10) (M_WORD18 & *buf++)); /* V_WORD1 */ - pa10++; - - if ((bc -= seg) == 0) { - uba_debug_dma_in (dpy_ba, dpy_pa10, pa10-dpy_pa10); - return 0; - } - ba += seg; - } /* Head */ - -ea = ba + bc; -seg = bc - (ea & 3); - -if (seg > 0) { - assert (((seg & 3) == 0) && (bc >= seg)); - bc -= seg; - for ( ; seg; seg -= 4, ba += 4) { /* aligned longwords */ - np = UBMPAGE (ba); - if (np != cp) { /* New (or first) page? */ - uba_debug_dma_in (dpy_ba, dpy_pa10, pa10); - dpy_pa10 = pa10 = Map_Addr10 (ba, 1, &ubm);/* map addr */ - dpy_ba = ba; - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) {/* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ - uba_debug_dma_nxm ("Write 18b Word", pa10, ba, bc); - return (bc + seg); /* return bc */ - } - cp = np; - } - M[pa10++] = (((d10)(M_WORD18 & buf[0])) << V_WORD0) | (M_WORD18 & buf[1]);/* V_WORD1 */ - buf += 2; - } - } /* Body */ - -/* Tail: partial word, must be aligned */ -assert ((bc >= 0) && ((ba & 3) == 0)); -if (bc) { - assert (bc == 2); - np = UBMPAGE (ba); /* Only one word, last possible page crossing */ - if (np != cp) { /* New (or first) page? */ - uba_debug_dma_in (dpy_ba, dpy_pa10, pa10); - dpy_pa10 = pa10 = Map_Addr10 (ba, 1, &ubm);/* map addr */ - dpy_ba = ba; - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) { /* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ - uba_debug_dma_nxm ("Write 18b Word", pa10, ba, bc); - return (bc); /* return bc */ - } - } - if (ubm & UMAP_RRV ) /* Read reverse preserves RH */ - M[pa10] = (M[pa10] & M_WORD0) | (((d10)(M_WORD18 & buf[0])) << V_WORD0); - else - M[pa10] = ((d10)(M_WORD18 & buf[0])) << V_WORD0; - pa10++; - } - -uba_debug_dma_in (dpy_ba, dpy_pa10, pa10); -return 0; -} - -/* Word mode writes; 36-bit data */ - -int32 Map_WriteW36 (uint32 ba, int32 bc, a10 *buf) -{ -uint32 ea, cp, np; -int32 seg, ubm = 0; -a10 pa10 = ~0u; -uint32 dpy_ba = ba; -a10 dpy_pa10 = ~0u; - -if ((ba & ~((IO_M_UBA< 0) { - assert (((seg & 3) == 0) && (bc >= seg)); - bc -= seg; - for ( ; seg; seg -= 4, ba += 4) { /* aligned longwords */ - np = UBMPAGE (ba); - if (np != cp) { /* New (or first) page? */ - uba_debug_dma_in (dpy_ba, dpy_pa10, pa10); - dpy_pa10 = pa10 = Map_Addr10 (ba, 1, &ubm);/* map addr */ - dpy_ba = ba; - if ((pa10 < 0) || MEM_ADDR_NXM (pa10)) {/* inv map or NXM? */ - ubcs[1] = ubcs[1] | UBCS_TMO; /* UBA timeout */ - uba_debug_dma_nxm ("Write 18b Word", pa10, ba, bc); - return (bc + seg); /* return bc */ - } - cp = np; - } - M[pa10++] = (((d10)(M_WORD18 & buf[0])) << V_WORD0) | (M_WORD18 & buf[1]);/* V_WORD1 */ - buf += 2; - } - } /* Body */ - -uba_debug_dma_in (dpy_ba, dpy_pa10, pa10); -return 0; -} - -void -uba_debug_dma (int32 mask, uint32 ba, a10 pa_start, a10 pa_end) -{ -int32 i; -int32 wc = (int32)(pa_end - pa_start); - -if ((!wc) || (!(sim_deb && (uba_dev.dctrl & mask)))) - return; -sim_debug (mask, &uba_dev, "DMA Bus Address: 0%o, Memory Address: %07o of %o word%s\n", ba, pa_start, wc, (wc>1) ? "s" : ""); -for (i=0; i>V_WORD0)&M_WORD18), - (int)((d>>V_WORD1)&M_WORD18)); - sprintf (words, "0x%05X: %04X,,%04X", pa_start+i, (int)((d>>V_WORD0)&M_WORD), - (int)((d>>V_WORD1)&M_WORD)); - sprintf (bytes, "%02X %02X %02X %02X", (int)(((d&~M_BYTE0)>>V_BYTE0)&M_BYTE), - (int)(((d&~M_BYTE1)>>V_BYTE1)&M_BYTE), - (int)(((d&~M_BYTE2)>>V_BYTE2)&M_BYTE), - (int)(((d&~M_BYTE3)>>V_BYTE3)&M_BYTE)); - strcpy (ascii, "'.....'"); - for (j=1; j<=5; j++) - { - c = 0x7F&(d>>(36-(j*7))); - if (isprint(c)) - ascii[j] = c; - } - strcpy (sixbit, "'.....'"); - for (j=1; j<=6; j++) - { - c = 0x3F&(d>>(36-(j*6))); - sixbit[j] = c + 32; - } - sim_debug (mask, &uba_dev, "%s | %s | %s | %s | %s\n", octal, words, bytes, ascii, sixbit); - } -} - -void -uba_debug_dma_in (uint32 ba, a10 pa_start, a10 pa_end) -{ -uba_debug_dma (DBG_DMA_IN, ba, pa_start, pa_end); -} - -void -uba_debug_dma_out (uint32 ba, a10 pa_start, a10 pa_end) -{ -uba_debug_dma (DBG_DMA_OUT, ba, pa_start, pa_end); -} - -void -uba_debug_dma_nxm (const char *msg, a10 pa10, uint32 ba, int32 bc) -{ -sim_debug (DBG_DMA_NXM, &uba_dev, "%s Error at address=%7o, ba=%o, bc=%o\n", msg, pa10, ba, bc); -} - -/* Evaluate Unibus priority interrupts */ - -int32 pi_ub_eval () -{ -int32 i, lvl; - -for (i = lvl = 0; i < UBANUM; i++) { - if (int_req & ubabr76[i]) - lvl = lvl | pi_l2bit[UBCS_GET_HI (ubcs[i])]; - if (int_req & ubabr54[i]) - lvl = lvl | pi_l2bit[UBCS_GET_LO (ubcs[i])]; - } -return lvl; -} - -/* Return Unibus device vector - - Takes as input the request level calculated by pi_eval - If there is an interrupting Unibus device at that level, return its vector, - otherwise, returns 0 -*/ - -int32 pi_ub_vec (int32 rlvl, int32 *uba) -{ -int32 i, masked_irq; - -for (i = masked_irq = 0; i < UBANUM; i++) { - if ((rlvl == UBCS_GET_HI (ubcs[i])) && /* req on hi level? */ - (masked_irq = int_req & ubabr76[i])) - break; - if ((rlvl == UBCS_GET_LO (ubcs[i])) && /* req on lo level? */ - (masked_irq = int_req & ubabr54[i])) - break; - } -*uba = (i << 1) + 1; /* store uba # */ -for (i = 0; (i < 32) && masked_irq; i++) { /* find hi pri req */ - if ((masked_irq >> i) & 1) { - int_req = int_req & ~(1u << i); /* clear req */ - if (int_ack[i]) - return int_ack[i](); - return int_vec[i]; /* return vector */ - } - } -return 0; -} - -/* Unibus adapter map routines */ - -t_stat ubmap_rd (int32 *val, int32 pa, int32 mode) -{ -int32 n = iocmap[GET_IOUBA (pa)]; - -if (n < 0) - ABORT (STOP_ILLIOC); -*val = ubmap[n][pa & UMAP_AMASK]; -return SCPE_OK; -} - -t_stat ubmap_wr (int32 val, int32 pa, int32 mode) -{ -int32 n = iocmap[GET_IOUBA (pa)]; - -if (n < 0) - ABORT (STOP_ILLIOC); -ubmap[n][pa & UMAP_AMASK] = UMAP_POSFL (val) | UMAP_POSPN (val); -return SCPE_OK; -} - -/* Unibus adapter control/status routines */ - -t_stat ubs_rd (int32 *val, int32 pa, int32 mode) -{ -int32 n = iocmap[GET_IOUBA (pa)]; - -if (n < 0) - ABORT (STOP_ILLIOC); -if (int_req & ubabr76[n]) - ubcs[n] = ubcs[n] | UBCS_HI; -if (int_req & ubabr54[n]) - ubcs[n] = ubcs[n] | UBCS_LO; -*val = ubcs[n] = ubcs[n] & ~UBCS_RDZ; -return SCPE_OK; -} - -t_stat ubs_wr (int32 val, int32 pa, int32 mode) -{ -int32 n = iocmap[GET_IOUBA (pa)]; - -if (n < 0) - ABORT (STOP_ILLIOC); -if (val & UBCS_INI) { - DEVICE *dptr; - int i; - - for (i=0; (dptr = sim_devices[i]) != NULL; i++) { - if (dptr == &uba_dev) { - ++i; /* start after UBA */ - break; - } - } - /* Now find the devices which are attached to this UBA and reset them */ - for (; (dptr = sim_devices[i]) != NULL; i++) { - DIB *dibp = (DIB *)dptr->ctxt; - - if ((n == iocmap[GET_IOUBA (dibp->ba)]) && - (dptr->reset != NULL)) - dptr->reset (dptr); - } - ubcs[n] = val & UBCS_DXF; - } -else ubcs[n] = val & UBCS_RDW; -if (int_req & ubabr76[n]) - ubcs[n] = ubcs[n] | UBCS_HI; -if (int_req & ubabr54[n]) - ubcs[n] = ubcs[n] | UBCS_LO; -return SCPE_OK; -} - -/* Unibus adapter read zero/write ignore routines */ - -t_stat rd_zro (int32 *val, int32 pa, int32 mode) -{ -*val = 0; -return SCPE_OK; -} - -t_stat wr_nop (int32 val, int32 pa, int32 mode) -{ -return SCPE_OK; -} - -/* Simulator interface routines */ - -t_stat uba_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) -{ -int32 uba = uptr - uba_unit; - -if (addr >= UMAP_MEMSIZE) - return SCPE_NXM; -*vptr = ubmap[uba][addr]; -return SCPE_OK; -} - -t_stat uba_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) -{ -int32 uba = uptr - uba_unit; - -if (addr >= UMAP_MEMSIZE) - return SCPE_NXM; -ubmap[uba][addr] = (int32) val & UMAP_MASK; -return SCPE_OK; -} - -t_stat uba_reset (DEVICE *dptr) -{ -int32 i, uba; - -int_req = 0; -for (uba = 0; uba < UBANUM; uba++) { - ubcs[uba] = 0; - for (i = 0; i < UMAP_MEMSIZE; i++) - ubmap[uba][i] = 0; - } -pi_eval (); -return SCPE_OK; -} - -/* Change device address */ - -t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -DEVICE *dptr; -DIB *dibp; -uint32 newba; -t_stat r; - -if (cptr == NULL) - return SCPE_ARG; -if ((val == 0) || (uptr == NULL)) - return SCPE_IERR; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if (dibp == NULL) - return SCPE_IERR; -newba = (uint32) get_uint (cptr, 8, PAMASK, &r); /* get new */ -if ((r != SCPE_OK) || (newba == dibp->ba)) - return r; -if (GET_IOUBA (newba) != GET_IOUBA (dibp->ba)) - return SCPE_ARG; -if (newba % ((uint32) val)) /* check modulus */ - return SCPE_ARG; -dibp->ba = newba; /* store */ -return SCPE_OK; -} - -/* Show device address */ - -t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -DEVICE *dptr; -DIB *dibp; - -if (uptr == NULL) - return SCPE_IERR; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if (dibp == NULL) - return SCPE_IERR; -if (((dibp->ba>>IO_V_UBA) != 1) && - ((dibp->ba>>IO_V_UBA) != 3)) - return SCPE_IERR; -fprintf (st, "address=%07o", dibp->ba); -if (dibp->lnt > 1) - fprintf (st, "-%07o", dibp->ba + dibp->lnt - 1); -return SCPE_OK; -} - -/* Change device vector */ - -t_stat set_vec (UNIT *uptr, int32 arg, char *cptr, void *desc) -{ -DEVICE *dptr; -DIB *dibp; -uint32 newvec; -t_stat r; - -if (cptr == NULL) - return SCPE_ARG; -if (uptr == NULL) - return SCPE_IERR; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if (dibp == NULL) - return SCPE_IERR; -newvec = (uint32) get_uint (cptr, 8, VEC_Q + 01000, &r); -if ((r != SCPE_OK) || (newvec == VEC_Q) || - ((newvec + (dibp->vnum * 4)) >= (VEC_Q + 01000)) || - (newvec & ((dibp->vnum > 1)? 07: 03))) - return SCPE_ARG; -dibp->vec = newvec; -return SCPE_OK; -} - -/* Show device vector */ - -t_stat show_vec (FILE *st, UNIT *uptr, int32 arg, void *desc) -{ -DEVICE *dptr; -DIB *dibp; -uint32 i, j, vec, numvec, br_bit; - -if (uptr == NULL) - return SCPE_IERR; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if (dibp == NULL) - return SCPE_IERR; -vec = dibp->vec; -if (arg) - numvec = arg; -else numvec = dibp->vnum; -if (vec == 0) - fprintf (st, "no vector"); -else { - fprintf (st, "vector=%o", vec); - if (numvec > 1) - fprintf (st, "-%o", vec + (4 * (numvec - 1))); - } -br_bit = 1u << dibp->vloc; -for (i = 0, j = 4; i < 4; i++) { - if ((br_bit & iplmask[i]) != 0) - j = i; - } -if (j >= 4) - fprintf (st, ", invalid BR level"); -else fprintf (st, ", BR%d", j + 4); -return SCPE_OK; -} - -/* Show vector for terminal multiplexor */ - -t_stat show_vec_mux (FILE *st, UNIT *uptr, int32 arg, void *desc) -{ -TMXR *mp = (TMXR *) desc; - -if ((mp == NULL) || (arg == 0)) - return SCPE_IERR; -return show_vec (st, uptr, ((mp->lines * 2) / arg), desc); -} - -/* Test for conflict in device addresses */ - -t_bool dev_conflict (DIB *curr) -{ -uint32 i, end; -DEVICE *dptr; -DIB *dibp; - -end = curr->ba + curr->lnt - 1; /* get end */ -for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ - dibp = (DIB *) dptr->ctxt; /* get DIB */ - if ((dibp == NULL) || (dibp == curr) || - (dptr->flags & DEV_DIS)) - continue; - if (((curr->ba >= dibp->ba) && /* overlap start? */ - (curr->ba < (dibp->ba + dibp->lnt))) || - ((end >= dibp->ba) && /* overlap end? */ - (end < (dibp->ba + dibp->lnt)))) { - sim_printf ("Device %s address conflict at %08o\n", - sim_dname (dptr), dibp->ba); - return TRUE; - } - } -return FALSE; -} - -/* Build interrupt tables */ - -void build_int_vec (int32 vloc, int32 ivec, int32 (*iack)(void) ) -{ -if (iack != NULL) - int_ack[vloc] = iack; -else int_vec[vloc] = ivec; -return; -} - -/* Build dib_tab from device list */ - -t_bool build_dib_tab (void) -{ -int32 i, j, k; -DEVICE *dptr; -DIB *dibp; - -for (i = 0; i < 32; i++) { /* clear intr tables */ - int_vec[i] = 0; - int_ack[i] = NULL; - } -for (i = j = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ - dibp = (DIB *) dptr->ctxt; /* get DIB */ - if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */ - if (dibp->vnum > VEC_DEVMAX) - return SCPE_IERR; - for (k = 0; k < dibp->vnum; k++) /* loop thru vec */ - build_int_vec (dibp->vloc + k, /* add vector */ - dibp->vec + (k * 4), dibp->ack[k]); - if (dibp->lnt != 0) { /* I/O addresses? */ - dib_tab[j++] = dibp; /* add DIB to dib_tab */ - if (j >= DIB_MAX) /* too many? */ - return SCPE_IERR; - } - } /* end if enabled */ - } /* end for */ -for (i = 0; (dibp = std_dib[i]) != NULL; i++) { /* loop thru std */ - dib_tab[j++] = dibp; /* add to dib_tab */ - if (j >= DIB_MAX) /* too many? */ - return SCPE_IERR; - } -dib_tab[j] = NULL; /* end with NULL */ -for (i = 0; (dibp = dib_tab[i]) != NULL; i++) { /* test built dib_tab */ - if (dev_conflict (dibp)) /* for conflicts */ - return SCPE_STOP; - } -return SCPE_OK; -} - -/* Show dib_tab */ - -t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -int32 i, j, done = 0; -DEVICE *dptr; -DIB *dibt; - -build_dib_tab (); /* build table */ -while (done == 0) { /* sort ascending */ - done = 1; /* assume done */ - for (i = 0; dib_tab[i + 1] != NULL; i++) { /* check table */ - if (dib_tab[i]->ba > dib_tab[i + 1]->ba) { /* out of order? */ - dibt = dib_tab[i]; /* interchange */ - dib_tab[i] = dib_tab[i + 1]; - dib_tab[i + 1] = dibt; - done = 0; /* not done */ - } - } - } /* end while */ -fprintf (st, " Address Vector BR Device\n" - "----------------- -------- -- ------\n"); -for (i = 0; dib_tab[i] != NULL; i++) { /* print table */ - for (j = 0, dptr = NULL; sim_devices[j] != NULL; j++) { - if (((DIB*) sim_devices[j]->ctxt) == dib_tab[i]) { - dptr = sim_devices[j]; - break; - } - } - fprintf (st, "%07o - %07o ", dib_tab[i]->ba, - dib_tab[i]->ba + dib_tab[i]->lnt - 1); - if (dib_tab[i]->vec == 0) - fprintf (st, " "); - else { - fprintf (st, "%03o", dib_tab[i]->vec); - if (dib_tab[i]->vnum > 1) - fprintf (st, "-%03o", dib_tab[i]->vec + (4 * (dib_tab[i]->vnum - 1))); - else - fprintf (st, " "); - } - if (dib_tab[i]->vec || dib_tab[i]->vloc) - fprintf (st, " %2u ", (dib_tab[i]->vloc<=3)? 7: - (dib_tab[i]->vloc<=7)? 6: - (dib_tab[i]->vloc<=19)? 5: 4); - else - fprintf (st, " "); - fprintf (st, " %s\n", (dptr? sim_dname (dptr): "CPU")); - } -return SCPE_OK; -} - -/* Stub auto-configure */ - -t_stat auto_config (char *name, int32 num) -{ -return SCPE_OK; -} - -/* Stub floating address */ - -t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -return SCPE_OK; -} diff --git a/PDP10/pdp10_lp20.c b/PDP10/pdp10_lp20.c deleted file mode 100644 index 10662e09..00000000 --- a/PDP10/pdp10_lp20.c +++ /dev/null @@ -1,1234 +0,0 @@ -/* pdp10_lp20.c: PDP-10 LP20 line printer simulator - - Copyright (c) 1993-2009, 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. - - lp20 line printer - - 23-Jun-13 TL Add optical VFU support and fix some inconsistencies - with the hardware. Add documentation. - 29-May-13 TL Force append when an existing file is attached. - Previously over-wrote file from the top. - 19-Jan-07 RMS Added UNIT_TEXT flag - 04-Sep-05 RMS Fixed missing return (found by Peter Schorn) - 07-Jul-05 RMS Removed extraneous externs - 18-Mar-05 RMS Added attached test to detach routine - 29-Dec-03 RMS Fixed bug in scheduling - 25-Apr-03 RMS Revised for extended file support - 29-Sep-02 RMS Added variable vector support - Modified to use common Unibus routines - New data structures - 30-May-02 RMS Widened POS to 32b - 06-Jan-02 RMS Added enable/disable support - 30-Nov-01 RMS Added extended SET/SHOW support - - References: - EK-LP20-TM-004 LP20 LINE PRINTER SYSTEM MANUAL - B-TC-LP20-0-1 MP0006 LP20 Field Maintenance Print Set - DpC255137D Dataproducts Corp Maintenance Guide Vol. I - 300LPM/600 LPM Line Printers. - LP2SER.MAC TOPS-10 Device driver - LPKSDV.MAC TOPS-20 Device driver - LP20.MAC TOPS-10/20 VFU/RAM utility - LPTSPL/LPTSUB.MAC TOPS-10/20 GALAXY spooler -*/ - -#include "pdp10_defs.h" -#include - -/* Time (seconds) of idleness before data flushed to attached file. */ -#ifndef LP20_IDLE_TIME -#define LP20_IDLE_TIME (10) -#endif - -/* The LP20 has the following CSR assignments: - * Unit No. 1: 775400, Vector: 754 - * Unit No. 2: 775420, Vector: 750 - * - * Note that the KS only supported one LP20. - * Note also that the vector assigned to unit 2 is lower than unit 1's. - */ - -#define UNIT_DUMMY (1 << UNIT_V_UF) -#define LP_WIDTH 132 /* printer width */ -#define DEFAULT_LPI 6 /* default lines-per-inch of LPT */ -/* DAVFU RAM */ - -#define DV_SIZE 143 /* DAVFU size */ -#define DV_DMASK 077 /* data mask per byte */ -#define DV_TOF 0 /* top of form channel */ -#define DV_BOF 11 /* bottom of form channel */ -#define DV_MAX 11 /* max channel number */ -#define MIN_VFU_LEN 2 /* minimum VFU length (in inches) */ -#define VFU_LEN_VALID(lines, lpi) ((lines) >= (lpi * MIN_VFU_LEN)) - -/* Translation RAM */ - -#define TX_SIZE 256 /* translation RAM */ -#define TX_AMASK (TX_SIZE - 1) -#define TX_DMASK 007777 -#define TX_PARITY 010000 /* Parity bit (emulated: 'valid'; unwritten has bad 'parity') */ -#define TX_V_FL 8 /* flags */ -#define TX_M_FL 017 -/* define TX_INTR 04000 *//* interrupt */ -#define TX_DELH 02000 /* delimiter */ -/* define TX_XLAT 01000 *//* translate */ -/* define TX_DVFU 00400 *//* DAVFU */ -#define TX_SLEW 00020 /* chan vs slew */ -#define TX_VMASK 00017 /* spacing mask */ -#define TX_CHR 0 /* states: pr char */ -#define TX_RAM 1 /* pr translation */ -#define TX_DVU 2 /* DAVFU action */ -#define TX_INT 3 /* interrupt */ -#define TX_GETFL(x) (((x) >> TX_V_FL) & TX_M_FL) - -/* LPCSRA (765400) */ - -#define CSA_GO 0000001 /* go */ -#define CSA_PAR 0000002 /* parity enable NI */ -#define CSA_V_FNC 2 /* function */ -#define CSA_M_FNC 03 -#define FNC_PR 0 /* print */ -#define FNC_TST 1 /* test */ -#define FNC_DVU 2 /* load DAVFU */ -#define FNC_RAM 3 /* load translation RAM */ -#define FNC_INTERNAL 1 /* internal function */ -#define CSA_FNC (CSA_M_FNC << CSA_V_FNC) -#define CSA_V_UAE 4 /* Unibus addr extension */ -#define CSA_UAE (03 << CSA_V_UAE) -#define CSA_IE 0000100 /* interrupt enable */ -#define CSA_DONE 0000200 /* done */ -#define CSA_INIT 0000400 /* init */ -#define CSA_ECLR 0001000 /* clear errors */ -#define CSA_DELH 0002000 /* delimiter hold */ -#define CSA_ONL 0004000 /* online */ -#define CSA_DVON 0010000 /* DAVFU online */ -#define CSA_UNDF 0020000 /* undefined char */ -#define CSA_PZRO 0040000 /* page counter zero */ -#define CSA_ERR 0100000 /* error */ -#define CSA_RW (CSA_DELH | CSA_IE | CSA_UAE | CSA_FNC | CSA_PAR | CSA_GO) -#define CSA_MBZ (CSA_ECLR | CSA_INIT) -#define CSA_GETUAE(x) (((x) & CSA_UAE) << (16 - CSA_V_UAE)) -#define CSA_GETFNC(x) (((x) >> CSA_V_FNC) & CSA_M_FNC) - -/* LPCSRB (765402) */ - -#define CSB_GOE 0000001 /* go error */ -#define CSB_DTE 0000002 /* DEM timing error NI */ -#define CSB_MTE 0000004 /* MSYN error (Ubus timeout) */ -#define CSB_RPE 0000010 /* RAM parity error */ -#define CSB_MPE 0000020 /* MEM parity error NI */ -#define CSB_LPE 0000040 /* LPT parity error NI */ -#define CSB_DVOF 0000100 /* DAVFU not ready */ -#define CSB_OFFL 0000200 /* offline */ -#define CSB_TEST 0003400 /* test mode */ -#define CSB_OVFU 0004000 /* optical VFU */ -#define CSB_PBIT 0010000 /* data parity bit NI */ -#define CSB_NRDY 0020000 /* printer error NI */ -#define CSB_LA180 0040000 /* LA180 printer NI */ -#define CSB_VLD 0100000 /* valid data NI */ -#define CSB_ECLR (CSB_GOE | CSB_DTE | CSB_MTE | CSB_RPE | CSB_MPE | CSB_LPE) -#define CSB_ERR (CSB_ECLR | CSB_DVOF | CSB_OFFL) -#define CSB_RW CSB_TEST -#define CSB_MBZ (CSB_DTE | CSB_RPE | CSB_MPE | CSB_LPE | \ - CSB_PBIT | CSB_NRDY | CSB_LA180 | CSB_VLD) - -/* LPBA (765404) */ - -/* LPBC (765506) */ - -#define BC_MASK 0007777 /* <15:12> MBZ */ - -/* LPPAGC (765510) */ - -#define PAGC_MASK 0007777 /* <15:12> MBZ */ - -/* LPRDAT (765512) */ - -#define RDAT_MASK 0007777 /* <15:12> MBZ */ - -/* LPCOLC/LPCBUF (765514) */ - -/* LPCSUM/LPPDAT (765516) */ - -extern int32 int_req; - -static int32 lpcsa = 0; /* control/status A */ -static int32 lpcsb = CSB_DVOF; /* control/status B */ -static int32 lpba = 0; /* bus address */ -static int32 lpbc = 0; /* byte count */ -static int32 lppagc = 0; /* page count */ -static int32 lprdat = 0; /* RAM data */ -static int32 lpcbuf = 0; /* character buffer */ -static int32 lpcolc = 0; /* column count */ -static int32 lppdat = 0; /* printer data */ -static int32 lpcsum = 0; /* checksum */ -static int32 dvptr = 0; /* davfu pointer */ -static int32 dvlnt = 0; /* davfu length */ -static int32 lp20_irq = 0; /* int request */ -static int32 lp20_stopioe = 0; /* stop on error */ -static int32 dvld = 0; -static int32 dvld_hold = 0; -static int32 lpi = DEFAULT_LPI; /* Printer's LPI. */ -static int16 txram[TX_SIZE] = { 0 }; /* translation RAM */ -static int16 davfu[DV_SIZE] = { 0 }; /* DAVFU */ - -DEVICE lp20_dev; -static t_stat lp20_rd (int32 *data, int32 pa, int32 access); -static t_stat lp20_wr (int32 data, int32 pa, int32 access); -static int32 lp20_inta (void); -static t_stat lp20_svc (UNIT *uptr); -static t_stat lp20_reset (DEVICE *dptr); -static t_stat lp20_init (DEVICE *dptr); -static t_stat lp20_attach (UNIT *uptr, char *ptr); -static t_stat lp20_detach (UNIT *uptr); -static t_stat lp20_set_lpi (UNIT *uptr, int32 val, char *cptr, void *desc); -static t_stat lp20_show_lpi (FILE *st, UNIT *up, int32 v, void *dp); -static t_stat lp20_set_vfu_type (UNIT *uptr, int32 val, char *cptr, void *desc); -static t_stat lp20_show_vfu_type (FILE *st, UNIT *up, int32 v, void *dp); -static t_stat lp20_show_vfu (FILE *st, UNIT *up, int32 v, void *dp); -static t_stat lp20_set_tof (UNIT *uptr, int32 val, char *cptr, void *desc); -static t_stat lp20_clear_vfu (UNIT *uptr, int32 val, char *cptr, void *desc); -static t_bool lp20_print (int32 c); -static t_bool lp20_adv (int32 c, t_bool advdvu); -static t_bool lp20_davfu (int32 c); -static void update_lpcs (int32 flg); -static void change_rdy (int32 setrdy, int32 clrrdy); -static int16 evenbits (int16 value); -static t_stat lp20_help (FILE *st, struct sim_device *dptr, - struct sim_unit *uptr, int32 flag, const char *cptr); -static const char *lp20_description (DEVICE *dptr); - -/* DEC standard VFU tape for 'optical' VFU default. - * Note that this must be <= DV_SIZE as we copy it into the DAVFU. - */ -static const int16 defaultvfu[] = { /* Generated by vfu.pl per DEC HRM */ - /* 66 line page with 6 line margin */ - 00377, /* Line 0 8 7 6 5 4 3 2 1 */ - 00220, /* Line 1 8 5 */ - 00224, /* Line 2 8 5 3 */ - 00230, /* Line 3 8 5 4 */ - 00224, /* Line 4 8 5 3 */ - 00220, /* Line 5 8 5 */ - 00234, /* Line 6 8 5 4 3 */ - 00220, /* Line 7 8 5 */ - 00224, /* Line 8 8 5 3 */ - 00230, /* Line 9 8 5 4 */ - 00264, /* Line 10 8 6 5 3 */ - 00220, /* Line 11 8 5 */ - 00234, /* Line 12 8 5 4 3 */ - 00220, /* Line 13 8 5 */ - 00224, /* Line 14 8 5 3 */ - 00230, /* Line 15 8 5 4 */ - 00224, /* Line 16 8 5 3 */ - 00220, /* Line 17 8 5 */ - 00234, /* Line 18 8 5 4 3 */ - 00220, /* Line 19 8 5 */ - 00364, /* Line 20 8 7 6 5 3 */ - 00230, /* Line 21 8 5 4 */ - 00224, /* Line 22 8 5 3 */ - 00220, /* Line 23 8 5 */ - 00234, /* Line 24 8 5 4 3 */ - 00220, /* Line 25 8 5 */ - 00224, /* Line 26 8 5 3 */ - 00230, /* Line 27 8 5 4 */ - 00224, /* Line 28 8 5 3 */ - 00220, /* Line 29 8 5 */ - 00276, /* Line 30 8 6 5 4 3 2 */ - 00220, /* Line 31 8 5 */ - 00224, /* Line 32 8 5 3 */ - 00230, /* Line 33 8 5 4 */ - 00224, /* Line 34 8 5 3 */ - 00220, /* Line 35 8 5 */ - 00234, /* Line 36 8 5 4 3 */ - 00220, /* Line 37 8 5 */ - 00224, /* Line 38 8 5 3 */ - 00230, /* Line 39 8 5 4 */ - 00364, /* Line 40 8 7 6 5 3 */ - 00220, /* Line 41 8 5 */ - 00234, /* Line 42 8 5 4 3 */ - 00220, /* Line 43 8 5 */ - 00224, /* Line 44 8 5 3 */ - 00230, /* Line 45 8 5 4 */ - 00224, /* Line 46 8 5 3 */ - 00220, /* Line 47 8 5 */ - 00234, /* Line 48 8 5 4 3 */ - 00220, /* Line 49 8 5 */ - 00264, /* Line 50 8 6 5 3 */ - 00230, /* Line 51 8 5 4 */ - 00224, /* Line 52 8 5 3 */ - 00220, /* Line 53 8 5 */ - 00234, /* Line 54 8 5 4 3 */ - 00220, /* Line 55 8 5 */ - 00224, /* Line 56 8 5 3 */ - 00230, /* Line 57 8 5 4 */ - 00224, /* Line 58 8 5 3 */ - 00220, /* Line 59 8 5 */ - 00020, /* Line 60 5 */ - 00020, /* Line 61 5 */ - 00020, /* Line 62 5 */ - 00020, /* Line 63 5 */ - 00020, /* Line 64 5 */ - 04020, /* Line 65 12 5 */ -}; - -/* LP data structures - - lp20_dev LPT device descriptor - lp20_unit LPT unit descriptor - lp20_reg LPT register list -*/ - -static DIB lp20_dib = { - IOBA_LP20, IOLN_LP20, &lp20_rd, &lp20_wr, - 1, IVCL (LP20), VEC_LP20, { &lp20_inta } - }; - -/* Actual device timing varies depending on the printer. - * Printers used with the LP20 include both drum and band printers. - * Nominal speeds ranged from 200 LPM to 1250 LPM. Besides speed, - * the major variants were: Optical vs DAVFU, 64 vs. 96 character - * band/drum, and scientific vs. EDP fonts. Scientific used slashed - * Z and 0; EDP did not. All supported 132 colum output at a pitch - * of 10 CPI. Some had operator switch-selectable vertical pitches - * for either 6 or 8 LPI. Paper and ribbon are hit by a hammer onto - * the rotating drum when the desired character is in front of the - * hammer. Thus, a line that contains all the characters on a drum - * would take one full revolution to print, plus paper motion time. - * (Assuming no overstrikes.) At 100 RPM, this translates to 16.7 ms - * printing + 41 ms motion for the LP05. The math works out to 1,040 - * LPM, but the rated speeds account for slew in the margins and some - * overstrikes (most commonly underline.) One could construct data - * patterns that overlapped some paper motion with unused character - * time on the drum. So the LP10, with 14 ms line advance could - * print the alphabet using 1/2 a rotation and move the paper in the - * other half - about 50% faster than rated speed. Bands move the - * characters horizontally (similar to chain/train printers), but - * the basic timing constraints are similar. - * - * Timing for several printers: a/b is 64/96 character set value. - * LP05 LP07 LP10 LP14 - * Line advance: 41 ms 12.5 ms 14 ms 20 ms - * Slew: 20 ips 60 ips 35 ips 22.5 @8LPi/30 @6 - * Drum Rotation: 1000/600 RPM band 1800/1200 1280/857 - * Rated LPM: 230/300 1220/905 1250/925 890/650 - * Weight lb/kg 340/154 800/363 800/363 420/191 - * - * There is a variant that was designed to drive an LA180 with either - * a 7 or 8 bit parallel interface. The prints label it 'not a standard - * product'. It's not implemented in this emulation. - */ - -static UNIT lp20_unit = { - UDATA (&lp20_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT - }; - -static REG lp20_reg[] = { - { ORDATA (LPCSA, lpcsa, 16) }, - { ORDATA (LPCSB, lpcsb, 16) }, - { ORDATA (LPBA, lpba, 16) }, - { ORDATA (LPBC, lpbc, 12) }, - { ORDATA (LPPAGC, lppagc, 12) }, - { ORDATA (LPRDAT, lprdat, 13) }, - { ORDATA (LPCBUF, lpcbuf, 8) }, - { ORDATA (LPCOLC, lpcolc, 8) }, - { ORDATA (LPPDAT, lppdat, 8) }, - { ORDATA (LPCSUM, lpcsum, 8) }, - { ORDATA (DVPTR, dvptr, 7) }, - { ORDATA (DVLNT, dvlnt, 7), REG_RO + REG_NZ }, - { ORDATA (DVLD, dvld, 2), REG_RO | REG_HIDDEN }, - { ORDATA (DVLDH, dvld_hold, 6), REG_RO | REG_HIDDEN }, - { FLDATA (INT, int_req, INT_V_LP20) }, - { FLDATA (IRQ, lp20_irq, 0) }, - { FLDATA (ERR, lpcsa, CSR_V_ERR) }, - { FLDATA (DONE, lpcsa, CSR_V_DONE) }, - { FLDATA (IE, lpcsa, CSR_V_IE) }, - { DRDATA (POS, lp20_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, lp20_unit.wait, 24), PV_LEFT }, - { FLDATA (STOP_IOE, lp20_stopioe, 0) }, - { BRDATA (TXRAM, txram, 8, 13, TX_SIZE) }, - { BRDATA (DAVFU, davfu, 8, 12, DV_SIZE) }, - { DRDATA (LPI, lpi, 8), REG_RO | REG_HIDDEN }, - { ORDATA (DEVADDR, lp20_dib.ba, 32), REG_HRO }, - { ORDATA (DEVVEC, lp20_dib.vec, 16), REG_HRO }, - { NULL } - }; - -static MTAB lp20_mod[] = { - { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", - &set_vec, &show_vec, NULL }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "VFU", NULL, NULL, &lp20_show_vfu, - NULL, "Display VFU tape/contents" }, - { MTAB_XTD|MTAB_VDV|MTAB_NC, 0, "VFUTYPE", "VFUTYPE={DAVFU|OPTICAL{=tapefile}}", - &lp20_set_vfu_type, &lp20_show_vfu_type, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "LPI", "LPI={6-LPI|8-LPI}", &lp20_set_lpi, &lp20_show_lpi, - NULL, "Printer vertical lines per inch" }, - { UNIT_DUMMY, 0, NULL, "TOPOFFORM", &lp20_set_tof, NULL, - NULL, "Advance to top-of-form" }, - { UNIT_DUMMY, 0, NULL, "VFUCLEAR", &lp20_clear_vfu, NULL, - NULL, "Clear the VFU & Translation RAM" }, - { 0 } - }; - -DEVICE lp20_dev = { - "LP20", &lp20_unit, lp20_reg, lp20_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &lp20_reset, - NULL, &lp20_attach, &lp20_detach, - &lp20_dib, DEV_DISABLE | DEV_UBUS, 0 - }; - -/* Line printer routines - - lp20_rd I/O page read - lp20_wr I/O page write - lp20_svc process event (printer ready) - lp20_reset process reset - lp20_attach process attach - lp20_detach process detach -*/ - -static t_stat lp20_rd (int32 *data, int32 pa, int32 access) -{ -update_lpcs (0); /* update csr's */ -switch ((pa >> 1) & 07) { /* case on PA<3:1> */ - - case 00: /* LPCSA */ - *data = lpcsa = lpcsa & ~CSA_MBZ; - if (lpcsb & CSB_OVFU) /* Optical: no DAVFU present */ - *data &= ~CSA_DVON; - break; - - case 01: /* LPCSB */ - *data = lpcsb = lpcsb & ~CSB_MBZ; - if (lpcsb & CSB_OVFU) - *data &= ~CSB_DVOF; - break; - - case 02: /* LPBA */ - *data = lpba; - break; - - case 03: /* LPBC */ - *data = lpbc = lpbc & BC_MASK; - break; - - case 04: /* LPPAGC */ - *data = lppagc = lppagc & PAGC_MASK; - break; - - case 05: /* LPRDAT */ - *data = lprdat & RDAT_MASK; - if (evenbits((int16)*data)) - *data |= TX_PARITY; - if (((lprdat & TX_PARITY) == 0) && (lpcsa & CSA_PAR)) /* Data invalid & parity checked? */ - *data ^= TX_PARITY; /* Invalid: Provide bad parity */ - break; - - case 06: /* LPCOLC/LPCBUF */ - *data = (lpcolc << 8) | lpcbuf; - break; - - case 07: /* LPCSUM/LPPDAT */ - *data = (lpcsum << 8) | lppdat; - break; - } /* end case PA */ - -return SCPE_OK; -} - -static t_stat lp20_wr (int32 data, int32 pa, int32 access) -{ -update_lpcs (0); /* update csr's */ -switch ((pa >> 1) & 07) { /* case on PA<3:1> */ - - case 00: /* LPCSA */ - if (access == WRITEB) - data = (pa & 1)? (lpcsa & 0377) | (data << 8): (lpcsa & ~0377) | data; - /* In hardware, a write that sets GO must not change any other - * bits in CSRA due to timing restrictions. Modifying any bits in - * CSRA while GO is set "may destroy the contents of the checksum register - * and produce other undesirable effects." - */ - if (data & CSA_ECLR) { /* error clear? */ - lpcsa = (lpcsa | CSA_DONE) & ~CSA_GO; /* set done, clr go */ - lpcsb = lpcsb & ~CSB_ECLR; /* clear err */ - sim_cancel (&lp20_unit); /* cancel I/O */ - } - if (data & CSA_INIT) /* init? */ - lp20_init (&lp20_dev); - if (data & CSA_GO) { /* go set? */ - if ((lpcsa & CSA_GO) == 0) { /* not set before? */ - if (lpcsb & CSB_ERR) - lpcsb = lpcsb | CSB_GOE; - lpcsum = 0; /* clear checksum */ - sim_activate (&lp20_unit, lp20_unit.wait); - } - } - else sim_cancel (&lp20_unit); /* go clr, stop DMA */ - lpcsa = (lpcsa & ~CSA_RW) | (data & CSA_RW); - if (dvld && (CSA_GETFNC (lpcsa) != FNC_DVU)) { /* DVU load aborted */ - change_rdy (0, CSA_DVON); /* Mark DVU off-line and empty */ - dvlnt = 0; - } - break; - - case 01: /* LPCSB */ - break; /* ignore writes to TEST */ - - case 02: /* LPBA */ - if (access == WRITEB) - data = (pa & 1)? (lpba & 0377) | (data << 8): (lpba & ~0377) | data; - lpba = data; - break; - - case 03: /* LPBC */ - if (access == WRITEB) - data = (pa & 1)? (lpbc & 0377) | (data << 8): (lpbc & ~0377) | data; - lpbc = data & BC_MASK; - lpcsa = lpcsa & ~CSA_DONE; - break; - - case 04: /* LPPAGC */ - if (access == WRITEB) - data = (pa & 1)? (lppagc & 0377) | (data << 8): (lppagc & ~0377) | data; - lppagc = data & PAGC_MASK; - lpcsa &= ~CSA_PZRO; /* Note that even if at TOF, PZRO does not set */ - break; - - case 05: /* LPRDAT */ - if (access == WRITEB) - data = (pa & 1)? (lprdat & 0377) | (data << 8): (lprdat & ~0377) | data; - lprdat = data & RDAT_MASK; - txram[lpcbuf & TX_AMASK] = (int16)(lprdat | TX_PARITY);/* load RAM and mark valid */ - break; - - case 06: /* LPCOLC/LPCBUF */ - if ((access == WRITEB) && (pa & 1)) /* odd byte */ - lpcolc = data & 0377; - else { - lpcbuf = data & 0377; /* even byte, word */ - if (access == WRITE) - lpcolc = (data >> 8) & 0377; - } - break; - - case 07: /* LPCSUM/LPPDAT */ - break; /* read only */ - } /* end case PA */ - -update_lpcs (0); -return SCPE_OK; -} - -/* Line printer service - - The translation RAM case table is derived from the LP20 spec and - verified against the LP20 RAM simulator in TOPS10 7.04 LPTSPL. - The equations are: - - flags := inter, delim, xlate, paper, delim_hold (from CSRA) - actions : = print_input, print_xlate, davfu_action, interrupt - - if (inter) { - if (!xlate || delim || delim_hold) - interrupt; - else if (paper) - davfu_action; - else print_xlate; - } - else if (paper) { - if (xlate || delim || delim_hold) - davfu_action; - else print_input; - } - else { - if (xlate || delim || delim_hold) - print_xlate; - else print_input; - } -*/ - -static t_stat lp20_svc (UNIT *uptr) -{ -int32 fnc, i, tbc, txst; -uint16 wd10; -t_bool cont; -a10 ba; - -static const uint32 txcase[32] = { - TX_CHR, TX_RAM, TX_CHR, TX_DVU, TX_RAM, TX_RAM, TX_DVU, TX_DVU, - TX_RAM, TX_RAM, TX_DVU, TX_DVU, TX_RAM, TX_RAM, TX_DVU, TX_DVU, - TX_INT, TX_INT, TX_INT, TX_INT, TX_RAM, TX_INT, TX_DVU, TX_INT, - TX_INT, TX_INT, TX_INT, TX_INT, TX_INT, TX_INT, TX_INT, TX_INT - }; - -lpcsa = lpcsa & ~CSA_GO; -ba = CSA_GETUAE (lpcsa) | lpba; -fnc = CSA_GETFNC (lpcsa); -tbc = 010000 - lpbc; -if (((fnc & FNC_INTERNAL) == 0) && ((lp20_unit.flags & UNIT_ATT) == 0)) { - update_lpcs (CSA_ERR); - return IORETURN (lp20_stopioe, SCPE_UNATT); - } -if ((fnc == FNC_PR) && (lpcsb & CSB_DVOF)) { - update_lpcs (CSA_ERR); - return SCPE_OK; - } - -for (i = 0, cont = TRUE; (i < tbc) && cont; ba++, i++) { - if (Map_ReadW (ba, 2, &wd10)) { /* get word, err? */ - lpcsb = lpcsb | CSB_MTE; /* set NXM error */ - update_lpcs (CSA_ERR); /* set done */ - break; - } - lpcbuf = (wd10 >> ((ba & 1)? 8: 0)) & 0377; /* get character */ - lpcsum = (lpcsum + lpcbuf) & 0377; /* add into checksum */ - switch (fnc) { /* switch on function */ - -/* Translation RAM load */ - - case FNC_RAM: /* RAM load */ - txram[(i >> 1) & TX_AMASK] = (wd10 & TX_DMASK) | TX_PARITY; - break; - -/* DAVFU RAM load. The DAVFU RAM is actually loaded in bytes, delimited by - a start (354 to 356) and stop (357) byte pair. If the number of bytes - loaded is odd, or no bytes are loaded, the DAVFU is invalid. - Thus, with DVU load mode set in CSRA, there are three states: - 0) Inactive 2) Start code seen,even byte 3) Start code seen, odd byte. - Normally, only a start or a stop code should be seen in (0), but any other - code that is received is ignored. A stop without a corresponding start is - legal, and specified to reset the current line pointer to 0 without - modifying the content of the RAM. - The DAVFU is physically in the printer, so printers with an optical - VFU see load data as normal data to be printed. The LP20 logic inhibits - the translation RAM in this mode, so any translation will not occur. - This is an unexpected condition; the OS/User should check the optical - VFU bit before attempting to load a DAVFU. -*/ - - case FNC_DVU: /* DVU load */ - if (lpcsb & CSB_OVFU) { - /* OS should not attempt to load VFU if printer has Optical VFU. - * The DAVFU is in the printer, so it will see the attempted load - * as print data. The LP20 inhibits translation. - */ - cont = lp20_print (lpcbuf); - break; - } - if ((lpcbuf >= 0354) && (lpcbuf <= 0356)) { /* start DVU load? */ - dvlnt = 0; /* reset lnt */ - dvld = 2; /* Load is active, even */ - if (lpcbuf == 0354) - lpi = 6; - else if (lpcbuf == 0355) - lpi = 8; - } - else if (lpcbuf == 0357) { /* stop DVU load? */ - dvptr = 0; /* reset ptr */ - dvld = 0; - if ((dvld & 1) || !VFU_LEN_VALID(dvlnt, lpi)) { /* if odd or invalid length */ - dvlnt = 0; - change_rdy (0, CSA_DVON); - } - else change_rdy(CSA_DVON, 0); - } - else if (dvld == 2) { /* even state? */ - dvld_hold = lpcbuf & DV_DMASK; - dvld = 3; - } - else if (dvld == 3) { /* odd state? */ - if (dvlnt < DV_SIZE) { - davfu[dvlnt++] = (int16)(dvld_hold | ((lpcbuf & DV_DMASK) << 6)); - dvld = 2; - } - else { - change_rdy (0, CSA_DVON); - dvlnt = dvld = 0; - } - } - break; - -/* Print characters through the translation RAM */ - - case FNC_PR: /* print */ - lprdat = txram[lpcbuf]; /* get RAM char */ - if (((lprdat & TX_PARITY) == 0) && (lpcsa & CSA_PAR)) { /* Check for valid */ - lpcsb |= CSB_RPE; /* Declare RAM parity error */ - cont = FALSE; - break; - } - txst = (TX_GETFL (lprdat) << 1) | /* get state */ - ((lpcsa & CSA_DELH)? 1: 0); /* plus delim hold */ - if (lprdat & TX_DELH) - lpcsa = lpcsa | CSA_DELH; - else lpcsa = lpcsa & ~CSA_DELH; - lpcsa = lpcsa & ~CSA_UNDF; /* assume char ok */ - switch (txcase[txst]) { /* case on state */ - - case TX_CHR: /* take char */ - cont = lp20_print (lpcbuf); - break; - - case TX_RAM: /* take translation */ - cont = lp20_print (lprdat); - break; - - case TX_DVU: /* DAVFU action */ - if (lprdat & TX_SLEW) - cont = lp20_adv (lprdat & TX_VMASK, TRUE); - else cont = lp20_davfu (lprdat & TX_VMASK); - break; - - case TX_INT: /* interrupt */ - lpcsa = lpcsa | CSA_UNDF; /* set flag */ - cont = FALSE; /* force stop */ - break; - } /* end case char state */ - break; - - case FNC_TST: /* test */ - break; - } /* end case function */ - } /* end for */ -lpba = ba & 0177777; -lpcsa = (lpcsa & ~CSA_UAE) | ((ba >> (16 - CSA_V_UAE)) & CSA_UAE); -lpbc = (lpbc + i) & BC_MASK; -if (lpbc) /* intr, but not done */ - update_lpcs (CSA_MBZ); -else update_lpcs (CSA_DONE); /* intr and done */ -if ((fnc == FNC_PR) && ferror (lp20_unit.fileref)) { - perror ("LP I/O error"); - clearerr (uptr->fileref); - return SCPE_IOERR; - } -return SCPE_OK; -} - -/* Print routines - - lp20_print print a character - lp20_adv advance n lines - lp20_davfu advance to channel on VFU - - Return TRUE to continue printing, FALSE to stop -*/ - -static t_bool lp20_print (int32 c) -{ -t_bool r = TRUE; -int32 i, rpt = 1; - -lppdat = c & 0177; /* mask char to 7b */ -if (lppdat == 000) /* NUL? no op */ - return TRUE; -if (lppdat == 012) /* LF? adv carriage */ - return lp20_adv (1, TRUE); -if (lppdat == 014) /* FF? top of form */ - return lp20_davfu (DV_TOF); -if (lppdat == 015) /* CR? reset col cntr */ - lpcolc = -1; -else if (lppdat == 011) { /* TAB? simulate */ - lppdat = ' '; /* with spaces */ - if (lpcolc >= 128) { - r = lp20_adv (1, TRUE); /* eol? adv carriage */ - rpt = 8; /* adv to col 9 */ - } - else rpt = 8 - (lpcolc & 07); /* else adv 1 to 8 */ - } -else { - if (lppdat < 040) /* cvt non-prnt to spc */ - lppdat = ' '; - if (lpcolc >= LP_WIDTH) /* line full? */ - r = lp20_adv (1, TRUE); /* adv carriage */ - } -for (i = 0; i < rpt; i++) - fputc (lppdat, lp20_unit.fileref); -lp20_unit.pos = (t_addr)sim_ftell (lp20_unit.fileref); -lpcolc = lpcolc + rpt; -return r; -} - -static t_bool lp20_adv (int32 cnt, t_bool dvuadv) -{ -int32 i; -int stoppc = FALSE; - -if (cnt == 0) - return TRUE; - -if (lpcsb & CSB_DVOF) - return FALSE; - -/* This logic has changed because it did not account for the case of more than one TOF - * occuring in the advance. Consider a tape with odd/even pages, and a slew channel that - * stops on the even. If we slew from the bottom of the even, we will pass the TOF of the - * odd page and stop on the odd; seeing a second TOF. - */ - -lpcolc = 0; /* reset col cntr */ -for (i = 0; i < cnt; i++) { /* print 'n' newlines; each can complete a page */ - fputc ('\n', lp20_unit.fileref); - if (dvuadv) { /* update DAVFU ptr */ - dvptr = (dvptr + cnt) % dvlnt; -if (davfu[dvptr] & (1 << DV_TOF)) { /* at top of form? */ - lppagc = (lppagc - 1) & PAGC_MASK; /* decr page cntr */ - if (lppagc == 0) { - lpcsa = lpcsa | CSA_PZRO; /* stop if zero */ - stoppc = TRUE; - } - } /* At TOF */ - } /* update pointer */ - } -lp20_unit.pos = (t_addr)sim_ftell (lp20_unit.fileref); -if (stoppc) /* Crossed one or more TOFs? */ - return FALSE; - -return TRUE; -} - -static t_bool lp20_davfu (int32 cnt) -{ -int i; - -if (lpcsb & CSB_DVOF) - return FALSE; -if (cnt > DV_MAX) /* inval chan? */ - cnt = 7; -for (i = 0; i < dvlnt; i++) { /* search DAVFU */ - dvptr = dvptr + 1; /* adv DAVFU ptr */ - if (dvptr >= dvlnt) /* wrap at end */ - dvptr = 0; - if (davfu[dvptr] & (1 << cnt)) { /* channel stop set? */ - if (cnt) /* ~TOF, adv */ - return lp20_adv (i + 1, FALSE); - if (lpcolc) /* TOF, need newline? */ - lp20_adv (1, FALSE); - fputc ('\f', lp20_unit.fileref); /* print form feed */ - lp20_unit.pos = (t_addr)sim_ftell (lp20_unit.fileref); - lppagc = (lppagc - 1) & PAGC_MASK; /* decr page cntr */ - if (lppagc != 0) - return TRUE; - else { - lpcsa = lpcsa | CSA_PZRO; /* stop if zero */ - return FALSE; - } - } - } /* end for */ -change_rdy (0,CSA_DVON); /* Code to channel with no channel stop */ -return FALSE; -} - -/* Update LPCSA, optionally request interrupt */ - -static void update_lpcs (int32 flg) -{ -if (flg) /* set int req */ - lp20_irq = 1; -lpcsa = (lpcsa | flg) & ~(CSA_MBZ | CSA_ERR | CSA_ONL); -lpcsb = (lpcsb | CSB_OFFL) & ~CSB_MBZ; -if (lp20_unit.flags & UNIT_ATT) { - lpcsa = lpcsa | CSA_ONL; - lpcsb = lpcsb & ~CSB_OFFL; - } -else lpcsa = lpcsa & ~CSA_DONE; -if (lpcsb & CSB_ERR) - lpcsa = lpcsa | CSA_ERR; -if ((lpcsa & CSA_IE) && lp20_irq) - SET_INT (LP20); -else CLR_INT (LP20); -return; -} - -/* Set and clear READY bits in csa. - * used for bits where a transition should cause an interrupt. - * also updates corresponding bits in csb. - */ -static void change_rdy (int32 setrdy, int32 clrrdy) -{ -int32 newcsa = (lpcsa | setrdy) & ~clrrdy; - -if ((newcsa ^ lpcsa) & (CSA_ONL | CSA_DVON) && !sim_is_active (&lp20_unit)) { - lp20_irq |= 1; - if (newcsa & CSA_IE) - SET_INT(LP20); - } -/* CSA_ERR is handled in update_csa */ - -if (newcsa & CSA_DVON) - lpcsb &= ~CSB_DVOF; -else - lpcsb |= CSB_DVOF; -if (newcsa & CSA_ONL) - lpcsb &= ~CSB_OFFL; -else - lpcsb |= CSB_OFFL; - -lpcsa = newcsa; -} - -/* Acknowledge interrupt (clear internal request) */ - -static int32 lp20_inta (void) -{ -lp20_irq = 0; /* clear int req */ -return lp20_dib.vec; -} - - -/* Simulator RESET - * Note that this does not reset the printer's DAVFU or the - * translation RAM, which survive system bootstraps. - * (SET VFUCLEAR will do that.) - * - */ - -t_stat lp20_reset (DEVICE *dptr) -{ - /* On power-up reset, clear DAVFU & RAM. Set DAVFU off-line. */ -if (sim_switches & SWMASK ('P')) { - memset (davfu, 0, sizeof(davfu)); - memset (txram, 0, sizeof(txram)); - dvlnt = dvptr = dvld= 0; - lpcsa &= ~CSA_DVON; - lpcsb |= CSB_DVOF; - lpi = DEFAULT_LPI; -} - -return lp20_init (dptr); -} - -/* Local init does NOT initialize the DAVFU/TRANSLATION RAMs. - * They are in the printer, which reset does not reach. - */ - -t_stat lp20_init (DEVICE *dptr) -{ -lpcsa = (lpcsa & CSA_DVON) | CSA_DONE; -lpcsb = lpcsb & (CSB_OVFU | CSB_DVOF); -lpba = lpbc = lppagc = lpcolc = 0; /* clear registers */ -lprdat = lppdat = lpcbuf = lpcsum = 0; -lp20_irq = 0; /* clear int req */ -sim_cancel (&lp20_unit); /* deactivate unit */ -update_lpcs (0); /* update status */ -return SCPE_OK; -} - -static t_stat lp20_attach (UNIT *uptr, char *cptr) -{ -t_stat reason; - -reason = attach_unit (uptr, cptr); /* attach file */ -if (reason == SCPE_OK) { - sim_fseek (uptr->fileref, 0, SEEK_END); - uptr->pos = (t_addr)sim_ftell (uptr->fileref); - } -if (lpcsa & CSA_DVON) { - int i; - for (i = 0; i < dvlnt; i++) { /* Align VFU with new file */ - if (davfu[dvptr] & (1 << DV_TOF)) - break; - dvptr = (dvptr +1) % dvlnt; - } - if (!(davfu[dvptr] & (1 << DV_TOF))) /* No TOP channel -> bad VFU */ - change_rdy (0, CSA_DVON); -} -if (lpcsa & CSA_ONL) /* just file chg? */ - return reason; -if (sim_is_active (&lp20_unit)) /* busy? no int */ - update_lpcs (0); -else update_lpcs (CSA_MBZ); /* interrupt */ -return reason; -} - -static t_stat lp20_detach (UNIT *uptr) -{ -t_stat reason; - -if (!(uptr->flags & UNIT_ATT)) /* attached? */ - return SCPE_OK; -reason = detach_unit (uptr); -sim_cancel (&lp20_unit); -lpcsa = lpcsa & ~CSA_GO; -update_lpcs (CSA_MBZ); -return reason; -} - -static t_stat lp20_set_vfu_type (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -char *fname, *cp; -FILE *vfile; -int sum = 0; - -if (!cptr || !*cptr) - return SCPE_ARG; - -fname = strchr (cptr, '='); -if (fname) - *fname++ = '\0'; - -for (cp = cptr; *cp; cp++) - *cp = (char)toupper (*cp); - -if (strncmp (cptr, "DAVFU", strlen(cptr)) == 0) { /* set lp20 vfutype=davfu: Switch to DAVFU, empty */ - if (fname && *fname) - return SCPE_ARG; - if (!(lpcsb & CSB_OVFU)) /* No change */ - return SCPE_OK; - if (uptr->flags & UNIT_ATT) - return SCPE_NOATT; - - lpcsb &= ~CSB_OVFU; - change_rdy (0, CSA_DVON); - dvptr = 0; - dvlnt = 0; - return SCPE_OK; -} - -if (strncmp (cptr, "OPTICAL", strlen(cptr)) != 0) - return SCPE_ARG; - -if (!fname || !*fname) { /* set lp20 vfutype=optical */ - if ((uptr->flags & UNIT_ATT) && !(lpcsb & CSB_OVFU)) - return SCPE_NOATT; - - lpcsb |= CSB_OVFU; - change_rdy (CSA_DVON, 0); - memcpy (davfu, defaultvfu, sizeof defaultvfu); - dvlnt = sizeof (defaultvfu) / sizeof (defaultvfu[0]); - dvptr = 0; - return SCPE_OK; -} - -/* set lp20 vfutype=optical=file - * This is OK when attached, so long as not changing from DAVFU. - * Read an optical tape file. These are line-oriented ASCII files: - * # ! ; comment - * lno: [ch [ch]...] Define line lno (0-length-1 with punches in - * channel(s) ch (1-12) - * Not required to be in order, if a lno appears more than once, the entries - * are ORed. (You can't unpunch a tape.) - * The highest lno defines the VFU length. Note that there is confusion about - * whether line numbers start at one or at zero. The HRM uses 0. Some of the - * utilitites use 1. We stick with 0 here.. - */ - -if (!(lpcsb & CSB_OVFU) && (uptr->flags & UNIT_ATT)) /* Changing device out from under OS */ - return SCPE_NOATT; - -vfile = sim_fopen( fname, "r" ); -if (vfile == NULL) { - return SCPE_OPENERR; -} -memset (davfu, 0, sizeof davfu); -dvptr = dvlnt = 0; - -while (!feof(vfile)) { - int32 line, hole; - int c; - - /* Discard comments */ - c = fgetc(vfile); - if (c == EOF) - break; - if ((c == '#') || (c == ';') || (c == '!')) { - while (!feof(vfile) && (c != '\n')) - c = fgetc(vfile); - continue; - } - ungetc(c, vfile); - - /* Read a line number */ - c = fscanf (vfile, " %u:", &line); - if (c == EOF) - break; - if ((c < 1) || (line < 0) || (((size_t)line) >= (sizeof (davfu)/sizeof davfu[0]))) - goto fmt_err; - if (line+1 > dvlnt) - dvlnt = line+1; - - /* Read channel numbers for current line */ - while (!feof(vfile)) { - do { - c = fgetc (vfile); - } while (isspace(c) && (c != '\n')); - if ((c == '\n') || (c == EOF)) - break; - ungetc(c, vfile); - c = fscanf (vfile, "%u", &hole); - if ((c == EOF) || (c < 1) || (c > 12)) - goto fmt_err; - sum |= (davfu[line] |= 1 << (hole -1)); - } /* End of line */ - } /* EOF */ - -/* Validate VFU content */ -if (!(sum & (1 << DV_TOF))) /* Verify that at least one punch is in the TOF channel. */ - goto fmt_err; -if (!VFU_LEN_VALID(dvlnt, lpi)) /* Verify VFU has minimum number of lines */ - goto fmt_err; - -fclose(vfile); -lpcsb |= CSB_OVFU; -change_rdy (CSA_DVON, 0); -return SCPE_OK; - -fmt_err: -dvlnt = 0; -change_rdy (0, CSA_DVON); -fclose(vfile); -return SCPE_FMT; -} - -static t_stat lp20_show_vfu_type (FILE *st, UNIT *up, int32 v, void *dp) -{ -if (lpcsb & CSB_OVFU) - fprintf (st, "optical VFU"); -else - fprintf (st, "DAVFU"); - -if (lpcsa & CSA_DVON) - fprintf (st, " loaded: %u lines, %.1f in", dvlnt, (((double)dvlnt)/lpi)); -else - fprintf (st, " not ready"); - -return SCPE_OK; -} - -static t_stat lp20_set_lpi (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 newlpi; - -if (uptr->flags & UNIT_ATT) - return SCPE_NOATT; - -if (!cptr || !*cptr) - newlpi = DEFAULT_LPI; -else if (!strcmp (cptr, "6") || !strcmp (cptr, "6-LPI")) - newlpi = 6; -else if (!strcmp (cptr, "8") || !strcmp (cptr, "8-LPI")) - newlpi = 8; -else - return SCPE_ARG; - -if ((lpcsa & CSA_DVON) && !VFU_LEN_VALID(dvlnt, newlpi)) - return SCPE_ARG; - -lpi = newlpi; -return SCPE_OK; -} - -static t_stat lp20_show_lpi (FILE *st, UNIT *up, int32 v, void *dp) -{ -fprintf (st, "%u LPI", lpi); - -return SCPE_OK; -} - -static t_stat lp20_show_vfu (FILE *st, UNIT *up, int32 v, void *dp) -{ -int l, c, sum; - -if (lpcsb & CSB_OVFU) - fprintf (st, "Tape"); -else - fprintf (st, "DAFVU"); - -if (lpcsb & CSB_DVOF) { - fprintf (st, " is not loaded\n"); - return SCPE_OK; - } - -fprintf (st, " contains:\n" - " 1 1 1\n" - "line 2 1 0 9 8 7 6 5 4 3 2 1\n" - "---- - - - - - - - - - - - -\n"); -sum = 0; -for (l = 0; l < dvlnt; l++) { - if ( l && !(l % 5) ) - fputc ('\n', st); - fprintf (st, "%4u", l); - for (c = DV_MAX; c >= 0; c--) - fprintf (st, " %c", (davfu[l] & (1 << c))? ((c >= 9)? 'X': '1'+c) : ' '); - fputc ('\n', st); - sum |= davfu[l]; - } - -if (!(sum & (1 << DV_TOF))) { - fprintf (st, "? No stop in channel %u (Top-of-Form)\n", DV_TOF+1); - } -if (!(sum & (1 << DV_BOF))) { - fprintf (st, "%% No stop in channel %u (Bottom-of-Form)\n", DV_BOF+1); - } - -return SCPE_OK; -} -static t_stat lp20_set_tof (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 s_lpcsa = lpcsa; -int32 s_lppagc = lppagc; - -if (cptr && *cptr) - return SCPE_ARG; - -if (!(uptr->flags & UNIT_ATT)) - return SCPE_NOATT; - -if (lpcsb & CSB_DVOF) - return SCPE_INCOMP; - -lp20_davfu (DV_TOF); -lppagc = s_lppagc; -lpcsa = s_lpcsa; - -return SCPE_OK; -} - -static int16 evenbits (int16 value) -{ -int16 even = 1; -while (value) { - even ^= 1; - value &= value-1; - } -return even; -} - -static t_stat lp20_clear_vfu (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int i; - -if (!get_yn ("Clear DAVFU & RAM? [N]", FALSE)) - return SCPE_OK; -for (i = 0; i < DV_SIZE; i++) - davfu[i] = 0; -for (i = 0; i < TX_SIZE; i++) - txram[i] = 0; -dvlnt = dvptr = dvld= 0; -change_rdy (0, CSA_DVON); -update_lpcs (0); -return SCPE_OK; -} diff --git a/PDP10/pdp10_mdfp.c b/PDP10/pdp10_mdfp.c deleted file mode 100644 index eaeed1d4..00000000 --- a/PDP10/pdp10_mdfp.c +++ /dev/null @@ -1,815 +0,0 @@ -/* pdp10_mdfp.c: PDP-10 multiply/divide and floating point simulator - - Copyright (c) 1993-2016, 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. - - 05-May-16 RMS Fixed bug in DMUL carry (Mark Pizzolato) - 2-Apr-04 RMS Fixed bug in floating point unpack - Fixed bug in FIXR (found by Phil Stone, fixed by - Chris Smith) - 31-Aug-01 RMS Changed int64 to t_int64 for Windoze - 10-Aug-01 RMS Removed register in declarations - - Instructions handled in this module: - imul integer multiply - idiv integer divide - mul multiply - div divide - dmul double precision multiply - ddiv double precision divide - fad(r) floating add (and round) - fsb(r) floating subtract (and round) - fmp(r) floating multiply (and round) - fdv(r) floating divide and round - fsc floating scale - fix(r) floating to fixed (and round) - fltr fixed to floating and round - dfad double precision floating add/subtract - dfmp double precision floating multiply - dfdv double precision floating divide - - The PDP-10 stores double (quad) precision integers in sequential - AC's or memory locations. Integers are stored in 2's complement - form. Only the sign of the high order word matters; the signs - in low order words are ignored on input and set to the sign of - the result on output. Quad precision integers exist only in the - AC's as the result of a DMUL or the dividend of a DDIV. - - 0 00000000011111111112222222222333333 - 0 12345678901234567890123456789012345 - +-+-----------------------------------+ - |S| high order integer | AC(n), A - +-+-----------------------------------+ - |S| low order integer | AC(n + 1), A + 1 - +-+-----------------------------------+ - |S| low order integer | AC(n + 2) - +-+-----------------------------------+ - |S| low order integer | AC(n + 3) - +-+-----------------------------------+ - - The PDP-10 supports two floating point formats: single and double - precision. In both, the exponent is 8 bits, stored in excess - 128 notation. The fraction is expected to be normalized. A - single precision floating point number has 27 bits of fraction; - a double precision number has 62 bits of fraction (the sign - bit of the second word is ignored and is set to zero). - - In a negative floating point number, the exponent is stored in - one's complement form, the fraction in two's complement form. - - 0 00000000 011111111112222222222333333 - 0 12345678 901234567890123456789012345 - +-+--------+---------------------------+ - |S|exponent| high order fraction | AC(n), A - +-+--------+---------------------------+ - |0| low order fraction | AC(n + 1), A + 1 - +-+------------------------------------+ - - Note that treatment of the sign is different for double precision - integers and double precision floating point. DMOVN (implemented - as an inline macro) follows floating point conventions. - - The original PDP-10 CPU (KA10) used a different format for double - precision numbers and included certain instructions to make - software support easier. These instructions were phased out in - the KL10 and KS10 and are treated as MUUO's. - - The KL10 added extended precision (11-bit exponent) floating point - format (so-called G floating). These instructions were not - implemented in the KS10 and are treated as MUUO's. -*/ - -#include "pdp10_defs.h" -#include - -typedef struct { /* unpacked fp number */ - int32 sign; /* sign */ - int32 exp; /* exponent */ - t_uint64 fhi; /* fraction high */ - t_uint64 flo; /* for double prec */ - } UFP; - -#define MSK32 0xFFFFFFFF -#define FIT27 (DMASK - 0x07FFFFFF) -#define FIT32 (DMASK - MSK32) -#define SFRC TRUE /* frac 2's comp */ -#define AFRC FALSE /* frac abs value */ - -/* In packed floating point number */ - -#define FP_BIAS 0200 /* exponent bias */ -#define FP_N_FHI 27 /* # of hi frac bits */ -#define FP_V_FHI 0 /* must be zero */ -#define FP_M_FHI INT64_C(0000777777777) -#define FP_N_EXP 8 /* # of exp bits */ -#define FP_V_EXP (FP_V_FHI + FP_N_FHI) -#define FP_M_EXP 0377 -#define FP_V_SIGN (FP_V_EXP + FP_N_EXP) /* sign */ -#define FP_N_FLO 35 /* # of lo frac bits */ -#define FP_V_FLO 0 /* must be zero */ -#define FP_M_FLO INT64_C(0377777777777) -#define GET_FPSIGN(x) ((int32) (((x) >> FP_V_SIGN) & 1)) -#define GET_FPEXP(x) ((int32) (((x) >> FP_V_EXP) & FP_M_EXP)) -#define GET_FPHI(x) ((x) & FP_M_FHI) -#define GET_FPLO(x) ((x) & FP_M_FLO) - -/* In unpacked floating point number */ - -#define FP_N_GUARD 1 /* # of guard bits */ -#define FP_V_UFLO FP_N_GUARD /* <35:1> */ -#define FP_V_URNDD (FP_V_UFLO - 1) /* dp round bit */ -#define FP_V_UFHI (FP_V_UFLO + FP_N_FLO) /* <62:36> */ -#define FP_V_URNDS (FP_V_UFHI - 1) /* sp round bit */ -#define FP_V_UCRY (FP_V_UFHI + FP_N_FHI) /* <63> */ -#define FP_V_UNORM (FP_V_UCRY - 1) /* normalized bit */ -#define FP_UFHI INT64_C(0x7FFFFFF000000000) -#define FP_UFLO INT64_C(0x0000000FFFFFFFFE) -#define FP_UFRAC INT64_C(0x7FFFFFFFFFFFFFFE) -#define FP_URNDD INT64_C(0x0000000000000001) -#define FP_URNDS INT64_C(0x0000000800000000) -#define FP_UNORM INT64_C(0x4000000000000000) -#define FP_UCRY INT64_C(0x8000000000000000) -#define FP_ONES INT64_C(0xFFFFFFFFFFFFFFFF) - -#define UNEG(x) ((~x) + 1) -#define DUNEG(x) x.flo = UNEG (x.flo); x.fhi = ~x.fhi + (x.flo == 0) - -extern d10 *ac_cur; /* current AC block */ -extern int32 flags; /* flags */ -void mul (d10 a, d10 b, d10 *rs); -void funpack (d10 h, d10 l, UFP *r, t_bool sgn); -void fnorm (UFP *r, t_int64 rnd); -d10 fpack (UFP *r, d10 *lo, t_bool fdvneg); - -/* Integer multiply - checked against KS-10 ucode */ - -d10 imul (d10 a, d10 b) -{ -d10 rs[2]; - -if ((a == SIGN) && (b == SIGN)) { /* KS10 hack */ - SETF (F_AOV | F_T1); /* -2**35 squared */ - return SIGN; - } -mul (a, b, rs); /* mpy, dprec result */ -if (rs[0] && (rs[0] != ONES)) { /* high not all sign? */ - rs[1] = TSTS (a ^ b)? SETS (rs[1]): CLRS (rs[1]); /* set sign */ - SETF (F_AOV | F_T1); /* overflow */ - } -return rs[1]; -} - -/* Integer divide, return quotient, remainder - checked against KS10 ucode - The KS10 does not recognize -2^35/-1 as an error. Instead, it produces - 2^35 (that is, -2^35) as the incorrect result. -*/ - -t_bool idiv (d10 a, d10 b, d10 *rs) -{ -d10 dvd = ABS (a); /* make ops positive */ -d10 dvr = ABS (b); - -if (dvr == 0) { /* divide by 0? */ - SETF (F_DCK | F_AOV | F_T1); /* set flags, return */ - return FALSE; - } -rs[0] = dvd / dvr; /* get quotient */ -rs[1] = dvd % dvr; /* get remainder */ -if (TSTS (a ^ b)) /* sign of result */ - rs[0] = NEG (rs[0]); -if (TSTS (a)) /* sign of remainder */ - rs[1] = NEG (rs[1]); -return TRUE; -} - -/* Multiply, return double precision result - checked against KS10 ucode */ - -void mul (d10 s1, d10 s2, d10 *rs) -{ -t_uint64 a = ABS (s1); -t_uint64 b = ABS (s2); -t_uint64 t, u, r; - -if ((a == 0) || (b == 0)) { /* operand = 0? */ - rs[0] = rs[1] = 0; /* result 0 */ - return; - } -if ((a & FIT32) || (b & FIT32)) { /* fit in 64b? */ - t = a >> 18; /* no, split in half */ - a = a & RMASK; /* "dp" multiply */ - u = b >> 18; - b = b & RMASK; - r = (a * b) + (((a * u) + (b * t)) << 18); /* low is only 35b */ - rs[0] = ((t * u) << 1) + (r >> 35); /* so lsh hi 1 */ - rs[1] = r & MMASK; - } -else { - r = a * b; /* fits, native mpy */ - rs[0] = r >> 35; /* split at bit 35 */ - rs[1] = r & MMASK; - } - -if (TSTS (s1 ^ s2)) { /* result -? */ - MKDNEG (rs); - } -else if (TSTS (rs[0])) { /* result +, 2**70? */ - SETF (F_AOV | F_T1); /* overflow */ - rs[1] = SETS (rs[1]); /* consistent - */ - } -return; -} - -/* Divide, return quotient and remainder - checked against KS10 ucode - Note that the initial divide check catches the case -2^70/-2^35; - thus, the quotient can have at most 35 bits. -*/ - -t_bool divi (int32 ac, d10 b, d10 *rs) -{ -int32 p1 = ADDAC (ac, 1); -d10 dvr = ABS (b); /* make divr positive */ -t_int64 t; -int32 i; -d10 dvd[2]; - -dvd[0] = AC(ac); /* divd high */ -dvd[1] = CLRS (AC(p1)); /* divd lo, clr sgn */ -if (TSTS (AC(ac))) { /* make divd positive */ - DMOVN (dvd); - } -if (dvd[0] >= dvr) { /* divide fail? */ - SETF (F_AOV | F_DCK | F_T1); /* set flags, return */ - return FALSE; - } -if (dvd[0] & FIT27) { /* fit in 63b? */ - for (i = 0, rs[0] = 0; i < 35; i++) { /* 35 quotient bits */ - dvd[0] = (dvd[0] << 1) | ((dvd[1] >> 34) & 1); - dvd[1] = (dvd[1] << 1) & MMASK; /* shift dividend */ - rs[0] = rs[0] << 1; /* shift quotient */ - if (dvd[0] >= dvr) { /* subtract work? */ - dvd[0] = dvd[0] - dvr; /* quo bit is 1 */ - rs[0] = rs[0] + 1; - } - } - rs[1] = dvd[0]; /* store remainder */ - } -else { - t = (dvd[0] << 35) | dvd[1]; /* concatenate */ - rs[0] = t / dvr; /* quotient */ - rs[1] = t % dvr; /* remainder */ - } -if (TSTS (AC(ac) ^ b)) /* sign of result */ - rs[0] = NEG (rs[0]); -if (TSTS (AC(ac))) /* sign of remainder */ - rs[1] = NEG (rs[1]); -return TRUE; -} - -/* Double precision multiply. This is done the old fashioned way. Cross - product multiplies would be a lot faster but would require more code. -*/ - -void dmul (int32 ac, d10 *mpy) -{ -int32 p1 = ADDAC (ac, 1); -int32 p2 = ADDAC (ac, 2); -int32 p3 = ADDAC (ac, 3); -int32 i; -d10 mpc[2], sign; - -mpc[0] = AC(ac); /* mplcnd hi */ -mpc[1] = CLRS (AC(p1)); /* mplcnd lo, clr sgn */ -sign = mpc[0] ^ mpy[0]; /* sign of result */ -if (TSTS (mpc[0])) { /* get abs (mpcnd) */ - DMOVN (mpc); - } -if (TSTS (mpy[0])) { /* get abs (mpyer) */ - DMOVN (mpy); - } -else mpy[1] = CLRS (mpy[1]); /* clear mpy lo sign */ -AC(ac) = AC(p1) = AC(p2) = AC(p3) = 0; /* clear AC's */ -if (((mpy[0] | mpy[1]) == 0) || ((mpc[0] | mpc[1]) == 0)) - return; -for (i = 0; i < 71; i++) { /* 71 mpyer bits */ - if (i) { /* shift res, mpy */ - AC(p3) = (AC(p3) >> 1) | ((AC(p2) & 1) << 34); - AC(p2) = (AC(p2) >> 1) | ((AC(p1) & 1) << 34); - AC(p1) = (AC(p1) >> 1) | ((AC(ac) & 1) << 34); - AC(ac) = AC(ac) >> 1; - mpy[1] = (mpy[1] >> 1) | ((mpy[0] & 1) << 34); - mpy[0] = mpy[0] >> 1; - } - if (mpy[1] & 1) { /* if mpy lo bit = 1 */ - AC(p1) = AC(p1) + mpc[1]; - AC(ac) = AC(ac) + mpc[0] + (TSTS (AC(p1)) != 0); - AC(p1) = CLRS (AC(p1)); - } - } -if (TSTS (sign)) { /* result minus? */ - AC(p3) = (-AC(p3)) & MMASK; /* quad negate */ - AC(p2) = (~AC(p2) + (AC(p3) == 0)) & MMASK; - AC(p1) = (~AC(p1) + (AC(p2) == 0)) & MMASK; - AC(ac) = (~AC(ac) + (AC(p1) == 0)) & DMASK; - } -else if (TSTS (AC(ac))) /* wrong sign */ - SETF (F_AOV | F_T1); -if (TSTS (AC(ac))) { /* if result - */ - AC(p1) = SETS (AC(p1)); /* make signs consistent */ - AC(p2) = SETS (AC(p2)); - AC(p3) = SETS (AC(p3)); - } -return; -} - -/* Double precision divide - checked against KS10 ucode */ - -void ddiv (int32 ac, d10 *dvr) -{ -int32 i, cryin; -d10 sign, qu[2], dvd[4]; - -dvd[0] = AC(ac); /* save dividend */ -for (i = 1; i < 4; i++) - dvd[i] = CLRS (AC(ADDAC (ac, i))); -sign = AC(ac) ^ dvr[0]; /* sign of result */ -if (TSTS (AC(ac))) { /* get abs (dividend) */ - for (i = 3, cryin = 1; i > 0; i--) { /* negate quad */ - dvd[i] = (~dvd[i] + cryin) & MMASK; /* comp + carry in */ - if (dvd[i]) /* next carry in */ - cryin = 0; - } - dvd[0] = (~dvd[0] + cryin) & DMASK; - } -if (TSTS (dvr[0])) { /* get abs (divisor) */ - DMOVN (dvr); - } -else dvr[1] = CLRS (dvr[1]); -if (DCMPGE (dvd, dvr)) { /* will divide work? */ - SETF (F_AOV | F_DCK | F_T1); /* no, set flags */ - return; - } -qu[0] = qu[1] = 0; /* clear quotient */ -for (i = 0; i < 70; i++) { /* 70 quotient bits */ - dvd[0] = ((dvd[0] << 1) | ((dvd[1] >> 34) & 1)) & DMASK;; - dvd[1] = ((dvd[1] << 1) | ((dvd[2] >> 34) & 1)) & MMASK; - dvd[2] = ((dvd[2] << 1) | ((dvd[3] >> 34) & 1)) & MMASK; - dvd[3] = (dvd[3] << 1) & MMASK; /* shift dividend */ - qu[0] = (qu[0] << 1) | ((qu[1] >> 34) & 1); /* shift quotient */ - qu[1] = (qu[1] << 1) & MMASK; - if (DCMPGE (dvd, dvr)) { /* subtract work? */ - dvd[0] = dvd[0] - dvr[0] - (dvd[1] < dvr[1]); - dvd[1] = (dvd[1] - dvr[1]) & MMASK; /* do subtract */ - qu[1] = qu[1] + 1; /* set quotient bit */ - } - } -if (TSTS (sign) && (qu[0] | qu[1])) { - MKDNEG (qu); - } -if (TSTS (AC(ac)) && (dvd[0] | dvd[1])) { - MKDNEG (dvd); - } -AC(ac) = qu[0]; /* quotient */ -AC(ADDAC(ac, 1)) = qu[1]; -AC(ADDAC(ac, 2)) = dvd[0]; /* remainder */ -AC(ADDAC(ac, 3)) = dvd[1]; -return; -} - -/* Single precision floating add/subtract - checked against KS10 ucode - The KS10 shifts the smaller operand regardless of the exponent diff. - This code will not shift more than 63 places; shifts beyond that - cannot change the value of the smaller operand. - - If the signs of the operands are the same, the result sign is the - same as the source sign; the sign of the result fraction is actually - part of the data. If the signs of the operands are different, the - result sign is determined by the fraction sign. -*/ - -d10 fad (d10 op1, d10 op2, t_bool rnd, int32 inv) -{ -int32 ediff; -UFP a, b, t; - -if (inv) /* subtract? -b */ - op2 = NEG (op2); -if (op1 == 0) /* a = 0? result is b */ - funpack (op2, 0, &a, AFRC); -else if (op2 == 0) /* b = 0? result is a */ - funpack (op1, 0, &a, AFRC); -else { - funpack (op1, 0, &a, SFRC); /* unpack operands */ - funpack (op2, 0, &b, SFRC); /* fracs are 2's comp */ - ediff = a.exp - b.exp; /* get exp diff */ - if (ediff < 0) { /* a < b? switch */ - t = a; - a = b; - b = t; - ediff = -ediff; - } - if (ediff > 63) /* cap diff at 63 */ - ediff = 63; - if (ediff) /* shift b (signed) */ - b.fhi = (t_int64) b.fhi >> ediff; - a.fhi = a.fhi + b.fhi; /* add fractions */ - if (a.sign ^ b.sign) { /* add or subtract? */ - if (a.fhi & FP_UCRY) { /* subtract, frac -? */ - a.fhi = UNEG (a.fhi); /* complement result */ - a.sign = 1; /* result is - */ - } - else a.sign = 0; /* result is + */ - } - else { - if (a.sign) /* add, src -? comp */ - a.fhi = UNEG (a.fhi); - if (a.fhi & FP_UCRY) { /* check for carry */ - a.fhi = a.fhi >> 1; /* flo won't be used */ - a.exp = a.exp + 1; - } - } - } -fnorm (&a, (rnd? FP_URNDS: 0)); /* normalize, round */ -return fpack (&a, NULL, FALSE); -} - -/* Single precision floating multiply. Because the fractions are 27b, - a 64b multiply can be used for the fraction multiply. The 27b - fractions are positioned 0'frac'0000, resulting in 00'hifrac'0..0. - The extra 0 is accounted for by biasing the result exponent. -*/ - -#define FP_V_SPM (FP_V_UFHI - (32 - FP_N_FHI - 1)) -d10 fmp (d10 op1, d10 op2, t_bool rnd) -{ -UFP a, b; - -funpack (op1, 0, &a, AFRC); /* unpack operands */ -funpack (op2, 0, &b, AFRC); /* fracs are abs val */ -if ((a.fhi == 0) || (b.fhi == 0)) /* either 0? */ - return 0; -a.sign = a.sign ^ b.sign; /* result sign */ -a.exp = a.exp + b.exp - FP_BIAS + 1; /* result exponent */ -a.fhi = (a.fhi >> FP_V_SPM) * (b.fhi >> FP_V_SPM); /* high 27b of result */ -fnorm (&a, (rnd? FP_URNDS: 0)); /* normalize, round */ -return fpack (&a, NULL, FALSE); -} - -/* Single precision floating divide. Because the fractions are 27b, a - 64b divide can be used for the fraction divide. Note that 28b-29b - of fraction are developed; the code will do one special normalize to - make sure that the 28th bit is not lost. Also note the special - treatment of negative quotients with non-zero remainders; this - implements the note on p2-23 of the Processor Reference Manual. -*/ - -t_bool fdv (d10 op1, d10 op2, d10 *rs, t_bool rnd) -{ -UFP a, b; -t_uint64 savhi; -t_bool rem = FALSE; - -funpack (op1, 0, &a, AFRC); /* unpack operands */ -funpack (op2, 0, &b, AFRC); /* fracs are abs val */ -if (a.fhi >= 2 * b.fhi) { /* will divide work? */ - SETF (F_AOV | F_DCK | F_FOV | F_T1); - return FALSE; - } -if ((savhi = a.fhi)) { /* dvd = 0? quo = 0 */ - a.sign = a.sign ^ b.sign; /* result sign */ - a.exp = a.exp - b.exp + FP_BIAS + 1; /* result exponent */ - a.fhi = a.fhi / (b.fhi >> (FP_N_FHI + 1)); /* do divide */ - if (a.sign && (savhi != (a.fhi * (b.fhi >> (FP_N_FHI + 1))))) - rem = TRUE; /* KL/KS hack */ - a.fhi = a.fhi << (FP_V_UNORM - FP_N_FHI - 1); /* put quo in place */ - if ((a.fhi & FP_UNORM) == 0) { /* normalize 1b */ - a.fhi = a.fhi << 1; /* before masking */ - a.exp = a.exp - 1; - } - a.fhi = a.fhi & (FP_UFHI | FP_URNDS); /* mask quo to 28b */ - } -fnorm (&a, (rnd? FP_URNDS: 0)); /* normalize, round */ -*rs = fpack (&a, NULL, rem); /* pack result */ -return TRUE; -} - -/* Single precision floating scale. */ - -d10 fsc (d10 val, a10 ea) -{ -int32 sc = LIT8 (ea); -UFP a; - -if (val == 0) - return 0; -funpack (val, 0, &a, AFRC); /* unpack operand */ -if (ea & RSIGN) /* adjust exponent */ - a.exp = a.exp - sc; -else a.exp = a.exp + sc; -fnorm (&a, 0); /* renormalize */ -return fpack (&a, NULL, FALSE); /* pack result */ -} - -/* Float integer operand and round */ - -d10 fltr (d10 mb) -{ -UFP a; -d10 val = ABS (mb); - -a.sign = GET_FPSIGN (mb); /* get sign */ -a.exp = FP_BIAS + 36; /* initial exponent */ -a.fhi = val << (FP_V_UNORM - 35); /* left justify op */ -a.flo = 0; -fnorm (&a, FP_URNDS); /* normalize, round */ -return fpack (&a, NULL, FALSE); /* pack result */ -} - -/* Fix and truncate/round floating operand */ - -void fix (int32 ac, d10 mb, t_bool rnd) -{ -int32 sc; -t_uint64 so; -UFP a; - -funpack (mb, 0, &a, AFRC); /* unpack operand */ -if (a.exp > (FP_BIAS + FP_N_FHI + FP_N_EXP)) - SETF (F_AOV | F_T1); -else if (a.exp < FP_BIAS) /* < 1/2? */ - AC(ac) = 0; -else { - sc = FP_V_UNORM - (a.exp - FP_BIAS) + 1; - AC(ac) = a.fhi >> sc; - if (rnd) { - so = a.fhi << (64 - sc); - if (so >= (0x8000000000000000 + a.sign)) - AC(ac) = AC(ac) + 1; - } - if (a.sign) - AC(ac) = NEG (AC(ac)); - } -return; -} - -/* Double precision floating add/subtract - Since a.flo is 0, adding b.flo is just a copy - this is incorporated into - the denormalization step. If there's no denormalization, bflo is zero too. -*/ - -void dfad (int32 ac, d10 *rs, int32 inv) -{ -int32 p1 = ADDAC (ac, 1); -int32 ediff; -UFP a, b, t; - -if (inv) { /* subtract? -b */ - DMOVN (rs); - } -if ((AC(ac) | AC(p1)) == 0) /* a == 0? sum = b */ - funpack (rs[0], rs[1], &a, AFRC); -else if ((rs[0] | rs[1]) == 0) /* b == 0? sum = a */ - funpack (AC(ac), AC(p1), &a, AFRC); -else { - funpack (AC(ac), AC(p1), &a, SFRC); /* unpack operands */ - funpack (rs[0], rs[1], &b, SFRC); - ediff = a.exp - b.exp; /* get exp diff */ - if (ediff < 0) { /* a < b? switch */ - t = a; - a = b; - b = t; - ediff = -ediff; - } - if (ediff > 127) /* cap diff at 127 */ - ediff = 127; - if (ediff > 63) { /* diff > 63? */ - a.flo = (t_int64) b.fhi >> (ediff - 64); /* b hi to a lo */ - b.fhi = b.sign? FP_ONES: 0; /* hi = all sign */ - } - else if (ediff) { /* diff <= 63 */ - a.flo = (b.flo >> ediff) | (b.fhi << (64 - ediff)); - b.fhi = (t_int64) b.fhi >> ediff; /* shift b (signed) */ - } - a.fhi = a.fhi + b.fhi; /* do add */ - if (a.sign ^ b.sign) { /* add or subtract? */ - if (a.fhi & FP_UCRY) { /* subtract, frac -? */ - DUNEG (a); /* complement result */ - a.sign = 1; /* result is - */ - } - else a.sign = 0; /* result is + */ - } - else { - if (a.sign) { /* add, src -? comp */ - DUNEG (a); - }; - if (a.fhi & FP_UCRY) { /* check for carry */ - a.fhi = a.fhi >> 1; /* flo won't be used */ - a.exp = a.exp + 1; - } - } - } -fnorm (&a, FP_URNDD); /* normalize, round */ -AC(ac) = fpack (&a, &AC(p1), FALSE); /* pack result */ -return; -} - -/* Double precision floating multiply - The 62b fractions are multiplied, with cross products, to produce a - 124b fraction with two leading and two trailing 0's. Because the - product has 2 leading 0's, instead of the normal 1, an extra - normalization step is needed. Accordingly, the exponent calculation - increments the result exponent, to compensate for normalization. -*/ - -void dfmp (int32 ac, d10 *rs) -{ -int32 p1 = ADDAC (ac, 1); -t_uint64 xh, xl, yh, yl, mid; -UFP a, b; - -funpack (AC(ac), AC(p1), &a, AFRC); /* unpack operands */ -funpack (rs[0], rs[1], &b, AFRC); -if ((a.fhi == 0) || (b.fhi == 0)) { /* either 0? result 0 */ - AC(ac) = AC(p1) = 0; - return; - } -a.sign = a.sign ^ b.sign; /* result sign */ -a.exp = a.exp + b.exp - FP_BIAS + 1; /* result exponent */ -xh = a.fhi >> 32; /* split 62b fracs */ -xl = a.fhi & MSK32; /* into 32b halves */ -yh = b.fhi >> 32; -yl = b.fhi & MSK32; -a.fhi = xh * yh; /* hi xproduct */ -a.flo = xl * yl; /* low xproduct */ -mid = (xh * yl) + (yh * xl); /* fits in 64b */ -a.flo = a.flo + (mid << 32); /* add mid lo to lo */ -a.fhi = a.fhi + ((mid >> 32) & MSK32) + (a.flo < (mid << 32)); -fnorm (&a, FP_URNDD); /* normalize, round */ -AC(ac) = fpack (&a, &AC(p1), FALSE); /* pack result */ -return; -} - -/* Double precision floating divide - This algorithm develops a full 62 bits of quotient, plus one rounding - bit, in the low order 63b of a 64b number. To do this, we must assure - that the initial divide step generates a 1. If it would fail, shift - the dividend left and decrement the result exponent accordingly. -*/ - -void dfdv (int32 ac, d10 *rs) -{ -int32 p1 = ADDAC (ac, 1); -int32 i; -t_uint64 qu = 0; -UFP a, b; - -funpack (AC(ac), AC(p1), &a, AFRC); /* unpack operands */ -funpack (rs[0], rs[1], &b, AFRC); -if (a.fhi >= 2 * b.fhi) { /* will divide work? */ - SETF (F_AOV | F_DCK | F_FOV | F_T1); - return; - } -if (a.fhi) { /* dvd = 0? quo = 0 */ - a.sign = a.sign ^ b.sign; /* result sign */ - a.exp = a.exp - b.exp + FP_BIAS + 1; /* result exponent */ - if (a.fhi < b.fhi) { /* make sure initial */ - a.fhi = a.fhi << 1; /* divide step will work */ - a.exp = a.exp - 1; - } - for (i = 0; i < 63; i++) { /* 63b of quotient */ - qu = qu << 1; /* shift quotient */ - if (a.fhi >= b.fhi) { /* will div work? */ - a.fhi = a.fhi - b.fhi; /* sub, quo = 1 */ - qu = qu + 1; - } - a.fhi = a.fhi << 1; /* shift dividend */ - } - a.fhi = qu; - } -fnorm (&a, FP_URNDD); /* normalize, round */ -AC(ac) = fpack (&a, &AC(p1), FALSE); /* pack result */ -return; -} - -/* Unpack floating point operand */ - -void funpack (d10 h, d10 l, UFP *r, t_bool sgn) -{ -d10 fphi, fplo; - -r->sign = GET_FPSIGN (h); -r->exp = GET_FPEXP (h); -fphi = GET_FPHI (h); -fplo = GET_FPLO (l); -r->fhi = (fphi << FP_V_UFHI) | (fplo << FP_V_UFLO); -r->flo = 0; -if (r->sign) { - r->exp = r->exp ^ FP_M_EXP; /* 1s comp exp */ - if (sgn) { /* signed frac? */ - if (r->fhi) /* extend sign */ - r->fhi = r->fhi | FP_UCRY; - else { - r->exp = r->exp + 1; - r->fhi = (t_uint64)(FP_UCRY | FP_UNORM); - } - } - else { /* abs frac */ - if (r->fhi) - r->fhi = UNEG (r->fhi) & FP_UFRAC; - else { - r->exp = r->exp + 1; - r->fhi = FP_UNORM; - } - } - } -return; -} - -/* Normalize and optionally round floating point operand */ - -void fnorm (UFP *a, t_int64 rnd) -{ -int32 i; -static t_uint64 normmask[6] = { - 0x6000000000000000, 0x7800000000000000, 0x7F80000000000000, - 0x7FFF800000000000, 0x7FFFFFFF80000000, 0x7FFFFFFFFFFFFFFF - }; -static int32 normtab[7] = { 1, 2, 4, 8, 16, 32, 63 }; -extern a10 pager_PC; - -if (a->fhi & FP_UCRY) { /* carry set? */ - sim_printf ("%%PDP-10 FP: carry bit set at normalization, PC = %o\n", pager_PC); - a->flo = (a->flo >> 1) | ((a->fhi & 1) << 63); /* try to recover */ - a->fhi = a->fhi >> 1; /* but root cause */ - a->exp = a->exp + 1; /* should be fixed! */ - } -if ((a->fhi | a->flo) == 0) { /* if fraction = 0 */ - a->sign = a->exp = 0; /* result is 0 */ - return; - } -while ((a->fhi & FP_UNORM) == 0) { /* normalized? */ - for (i = 0; i < 6; i++) { - if (a->fhi & normmask[i]) - break; - } - a->fhi = (a->fhi << normtab[i]) | (a->flo >> (64 - normtab[i])); - a->flo = a->flo << normtab[i]; - a->exp = a->exp - normtab[i]; - } -if (rnd) { /* rounding? */ - a->fhi = a->fhi + rnd; /* add round const */ - if (a->fhi & FP_UCRY) { /* if carry out, */ - a->fhi = a->fhi >> 1; /* renormalize */ - a->exp = a->exp + 1; - } - } -return; -} - -/* Pack floating point result */ - -d10 fpack (UFP *r, d10 *lo, t_bool fdvneg) -{ -d10 val[2]; - -if (r->exp < 0) - SETF (F_AOV | F_FOV | F_FXU | F_T1); -else if (r->exp > FP_M_EXP) - SETF (F_AOV | F_FOV | F_T1); -val[0] = (((((d10) r->exp) & FP_M_EXP) << FP_V_EXP) | - ((r->fhi & FP_UFHI) >> FP_V_UFHI)) & DMASK; -if (lo) - val[1] = ((r->fhi & FP_UFLO) >> FP_V_UFLO) & MMASK; -else val[1] = 0; -if (r->sign) { /* negate? */ - if (fdvneg) { /* fdvr special? */ - val[1] = ~val[1] & MMASK; /* 1's comp */ - val[0] = ~val[0] & DMASK; - } - else { /* 2's comp */ - DMOVN (val); - } - } -if (lo) - *lo = val[1]; -return val[0]; -} diff --git a/PDP10/pdp10_pag.c b/PDP10/pdp10_pag.c deleted file mode 100644 index 8bf3b0a5..00000000 --- a/PDP10/pdp10_pag.c +++ /dev/null @@ -1,903 +0,0 @@ -/* pdp10_pag.c: PDP-10 paging subsystem simulator - - Copyright (c) 1993-2008, 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. - - pag KS10 pager - - 22-Sep-05 RMS Fixed declarations (from Sterling Garwood) - 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 - 03-May-01 RMS Fixed bug in indirect page table pointer processing - 29-Apr-01 RMS Added CLRCSH for ITS, fixed LPMR - - The pager consists of a standard hardware part (the translation - tables) and an operating-system specific page table fill routine. - - There are two translation tables, one for executive mode and one - for user mode. Each table consists of 512 page table entries, - one for each page in the 18b virtual address space. Each pte - contains (in the hardware) a valid bit, a writeable bit, an - address space bit (executive or user), and a cacheable bit, plus - the physical page number corresponding to the virtual page. In - the simulator, the pte is expanded for rapid processing of normal - reads and writes. An expanded pte contains a valid bit, a writeable - bit, and the physical page number shifted left by the page size. - - Expanded pte meaning - 0 invalid - >0 read only - <0 read write - - There is a third, physical table, which is used in place of the - executive and user tables if paging is off. Its entries are always - valid and always writeable. - - To translate a virtual to physical address, the simulator uses - the virtual page number to index into the appropriate page table. - If the page table entry (pte) is not valid, the page fill routine - is called to see if the entry is merely not filled or is truly - inaccessible. If the pte is valid but not writeable, and the - reference is a write reference, the page fill routine is also - called to see if the reference can be resolved. - - The page fill routine is operating system dependent. Three styles - of paging are supported: - - TOPS10 known in the KS10 microcode as KI10 paging, - used by earlier versions of TOPS10 - TOPS20 known in the KS10 microcode as KL10 paging, - used by later versions of TOPS10, and TOPS20 - ITS used only by ITS - - TOPS10 vs TOPS20 is selected by a bit in the EBR; ITS paging is - "hardwired" (it required different microcode). -*/ - -#include "pdp10_defs.h" -#include - -/* Page table (contains expanded pte's) */ - -#define PTBL_ASIZE PAG_N_VPN -#define PTBL_MEMSIZE (1 << PTBL_ASIZE) /* page table size */ -#define PTBL_AMASK (PTBL_MEMSIZE - 1) -#define PTBL_M (1u << 31) /* must be sign bit */ -#define PTBL_V (1u << 30) -#define PTBL_MASK (PAG_PPN | PTBL_M | PTBL_V) - -/* NXM processing */ - -#define REF_V 0 /* ref is virt */ -#define REF_P 1 /* ref is phys */ -#define PF_OK 0 /* pfail ok */ -#define PF_TR 1 /* pfail trap */ - -extern d10 *M; -extern d10 acs[AC_NBLK * AC_NUM]; -extern d10 *ac_cur, *ac_prv, *last_pa; -extern a10 epta, upta; -extern int32 flags; -extern d10 pager_word; -extern int32 apr_flg; -extern d10 ebr, ubr, hsb; -extern d10 spt, cst, cstm, pur; -extern a10 dbr1, dbr2, dbr3, dbr4; -extern d10 pcst, quant; -extern t_bool paging; -extern UNIT cpu_unit; -extern jmp_buf save_env; -extern int32 test_int (void); -extern int32 pi_eval (void); - -int32 eptbl[PTBL_MEMSIZE]; /* exec page table */ -int32 uptbl[PTBL_MEMSIZE]; /* user page table */ -int32 physptbl[PTBL_MEMSIZE]; /* phys page table */ -int32 *ptbl_cur, *ptbl_prv; -int32 save_ea; - -int32 ptbl_fill (a10 ea, int32 *ptbl, int32 mode); -t_stat pag_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); -t_stat pag_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); -t_stat pag_reset (DEVICE *dptr); -void pag_nxm (a10 pa, int32 phys, int32 trap); - -/* Pager data structures - - pag_dev pager device descriptor - pag_unit pager units - pager_reg pager register list -*/ - -UNIT pag_unit[] = { - { UDATA (NULL, UNIT_FIX, PTBL_MEMSIZE) }, - { UDATA (NULL, UNIT_FIX, PTBL_MEMSIZE) } - }; - -REG pag_reg[] = { - { ORDATA (PANIC_EA, save_ea, PASIZE), REG_HRO }, - { NULL } - }; - -DEVICE pag_dev = { - "PAG", pag_unit, pag_reg, NULL, - 2, 8, PTBL_ASIZE, 1, 8, 32, - &pag_ex, &pag_dep, &pag_reset, - NULL, NULL, NULL, - NULL, 0 - }; - -/* Memory read and write routines - - Read - read current or previous, read checking - ReadM - read current or previous, write checking - ReadE - read exec - ReadP - read physical - Write - write current or previous - WriteE - write exec - WriteP - write physical - AccChk - test accessibility of virtual address -*/ - -d10 Read (a10 ea, int32 prv) -{ -int32 pa, vpn, xpte; - -if (ea < AC_NUM) /* AC request */ - return (prv? ac_prv[ea]: ac_cur[ea]); -vpn = PAG_GETVPN (ea); /* get page num */ -xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */ -if (xpte == 0) - xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_RD); -pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */ -if (MEM_ADDR_NXM (pa)) /* process nxm */ - pag_nxm (pa, REF_V, PF_TR); -return M[pa]; /* return data */ -} - -d10 ReadM (a10 ea, int32 prv) -{ -int32 pa, vpn, xpte; - -if (ea < AC_NUM) /* AC request */ - return (prv? ac_prv[ea]: ac_cur[ea]); -vpn = PAG_GETVPN (ea); /* get page num */ -xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */ -if (xpte >= 0) - xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_WR); -pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */ -if (MEM_ADDR_NXM (pa)) /* process nxm */ - pag_nxm (pa, REF_V, PF_TR); -return M[pa]; /* return data */ -} - -d10 ReadE (a10 ea) -{ -int32 pa, vpn, xpte; - -if (ea < AC_NUM) /* AC? use current */ - return AC(ea); -if (!PAGING) /* phys? no mapping */ - return M[ea]; -vpn = PAG_GETVPN (ea); /* get page num */ -xpte = eptbl[vpn]; /* get exp pte, exec tbl */ -if (xpte == 0) - xpte = ptbl_fill (ea, eptbl, PTF_RD); -pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */ -if (MEM_ADDR_NXM (pa)) /* process nxm */ - pag_nxm (pa, REF_V, PF_TR); -return M[pa]; /* return data */ -} - -d10 ReadP (a10 ea) -{ -if (ea < AC_NUM) /* AC request */ - return AC(ea); -if (MEM_ADDR_NXM (ea)) /* process nxm */ - pag_nxm (ea, REF_P, PF_TR); -return M[ea]; /* return data */ -} - -void Write (a10 ea, d10 val, int32 prv) -{ -int32 pa, vpn, xpte; - -if (ea < AC_NUM) { /* AC request */ - if (prv) /* write AC */ - ac_prv[ea] = val; - else ac_cur[ea] = val; - } -else { - vpn = PAG_GETVPN (ea); /* get page num */ - xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */ - if (xpte >= 0) - xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_WR); - pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */ - if (MEM_ADDR_NXM (pa)) /* process nxm */ - pag_nxm (pa, REF_V, PF_TR); - else M[pa] = val; /* write data */ - } -return; -} - -void WriteE (a10 ea, d10 val) -{ -int32 pa, vpn, xpte; - -if (ea < AC_NUM) /* AC? use current */ - AC(ea) = val; -else if (!PAGING) /* phys? no mapping */ - M[ea] = val; -else { - vpn = PAG_GETVPN (ea); /* get page num */ - xpte = eptbl[vpn]; /* get exp pte, exec tbl */ - if (xpte >= 0) - xpte = ptbl_fill (ea, eptbl, PTF_WR); - pa = PAG_XPTEPA (xpte, ea); /* calc phys addr */ - if (MEM_ADDR_NXM (pa)) /* process nxm */ - pag_nxm (pa, REF_V, PF_TR); - else M[pa] = val; /* write data */ - } -return; -} - -void WriteP (a10 ea, d10 val) -{ -if (ea < AC_NUM) /* AC request */ - AC(ea) = val; -else { - if (MEM_ADDR_NXM (ea)) /* process nxm */ - pag_nxm (ea, REF_P, PF_TR); - M[ea] = val; /* memory */ - } -return; -} - -t_bool AccViol (a10 ea, int32 prv, int32 mode) -{ -int32 vpn, xpte; - -if (ea < AC_NUM) /* AC request */ - return FALSE; -vpn = PAG_GETVPN (ea); /* get page num */ -xpte = prv? ptbl_prv[vpn]: ptbl_cur[vpn]; /* get exp pte */ -if ((xpte == 0) || ((mode & PTF_WR) && (xpte > 0))) /* not accessible? */ - xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, mode | PTF_MAP); -if (xpte) /* accessible */ - return FALSE; -return TRUE; /* not accessible */ -} - -void pag_nxm (a10 pa, int32 phys, int32 trap) -{ -apr_flg = apr_flg | APRF_NXM; /* set APR flag */ -pi_eval (); /* eval intr */ -pager_word = PF_NXM | (phys? PF_NXMP: 0) | - (TSTF (F_USR)? PF_USER: 0) | ((d10) pa); -if (PAGING && trap) /* trap? */ - ABORT (PAGE_FAIL); -return; -} - -/* Page table fill - - This routine is called if the page table is invalid, or on a write - reference if the page table is read only. If the access is allowed - it stores the pte in the page table entry and returns an expanded - pte for use by the caller. Otherwise, it generates a page fail. - - Notes: - - If called from the console, invalid references return a pte - of 0, and the page table entry is not filled. - - If called from MAP, invalid references return a pte of 0. The - page fail word is properly set up. -*/ - -#define PAGE_FAIL_TRAP if (mode & (PTF_CON | PTF_MAP)) \ - return 0; \ - ABORT (PAGE_FAIL) -#define READPT(x,y) if (MEM_ADDR_NXM (y)) { \ - pag_nxm (y, REF_P, PF_OK); \ - PAGE_FAIL_TRAP; \ - } \ - x = ReadP (y) - -int32 ptbl_fill (a10 ea, int32 *tbl, int32 mode) -{ - -/* ITS paging is based on conventional page tables. ITS divides each address - space into a 128K high and low section, and uses different descriptor base - pointers (dbr) for each. ITS pages are twice the size of DEC standard; - therefore, the fill routine fills two page table entries and returns the pte - that maps the correct ITS half page. This allows the DEC paging macros to - be used in the normal path read-write routines. - - ITS has no MAP instruction, therefore, physical NXM traps are ok. -*/ - -if (Q_ITS) { /* ITS paging */ - int32 acc, decvpn, pte, vpn, ptead, xpte; - d10 ptewd; - - vpn = ITS_GETVPN (ea); /* get ITS pagno */ - if (tbl == uptbl) - ptead = ((ea & RSIGN)? dbr2: dbr1) + ((vpn >> 1) & 077); - else ptead = ((ea & RSIGN)? dbr3: dbr4) + ((vpn >> 1) & 077); - ptewd = ReadP (ptead); /* get PTE pair */ - pte = (int32) ((ptewd >> ((vpn & 1)? 0: 18)) & RMASK); - acc = ITS_GETACC (pte); /* get access */ - pager_word = PF_VIRT | ea | ((tbl == uptbl)? PF_USER: 0) | - ((mode & PTF_WR)? PF_ITS_WRITE: 0) | (acc << PF_ITS_V_ACC); - if ((acc != ITS_ACC_NO) && (!(mode & PTF_WR) || (acc == ITS_ACC_RW))) { - pte = pte & ~PTE_ITS_AGE; /* clear age */ - if (vpn & 1) - WriteP (ptead, (ptewd & LMASK) | pte); - else WriteP (ptead, (ptewd & RMASK) | (((d10) pte) << 18)); - xpte = ((pte & PTE_ITS_PPMASK) << ITS_V_PN) | PTBL_V | - ((acc == ITS_ACC_RW)? PTBL_M: 0); - decvpn = PAG_GETVPN (ea); /* get tlb idx */ - if (!(mode & PTF_CON)) { - tbl[decvpn & ~1] = xpte; /* map lo ITS page */ - tbl[decvpn | 1] = xpte + PAG_SIZE; /* map hi */ - } - return (xpte + ((decvpn & 1)? PAG_SIZE: 0)); - } - PAGE_FAIL_TRAP; - } /* end ITS paging */ - -/* TOPS-10 paging - checked against KS10 microcode - - TOPS-10 paging is also based on conventional page tables. The user page - tables are arranged contiguously at the beginning of the user process table; - however, the executive page tables are scattered through the executive and - user process tables. -*/ - -else if (!T20PAG) { /* TOPS-10 paging */ - int32 pte, vpn, ptead, xpte; - d10 ptewd; - - vpn = PAG_GETVPN (ea); /* get virt page num */ - if (tbl == uptbl) - ptead = upta + UPT_T10_UMAP + (vpn >> 1); - else if (vpn < 0340) - ptead = epta + EPT_T10_X000 + (vpn >> 1); - else if (vpn < 0400) - ptead = upta + UPT_T10_X340 + ((vpn - 0340) >> 1); - else ptead = epta + EPT_T10_X400 + ((vpn - 0400) >> 1); - READPT (ptewd, ptead); /* get PTE pair */ - pte = (int32) ((ptewd >> ((vpn & 1)? 0: 18)) & RMASK); - pager_word = PF_VIRT | ea | ((tbl == uptbl)? PF_USER: 0) | - ((mode & PTF_WR)? PF_WRITE: 0) | - ((pte & PTE_T10_A)? PF_T10_A | - ((pte & PTE_T10_S)? PF_T10_S: 0): 0); - if (mode & PTF_MAP) pager_word = pager_word | /* map? add to pf wd */ - ((pte & PTE_T10_W)? PF_T10_W: 0) | /* W, S, C bits */ - ((pte & PTE_T10_S)? PF_T10_S: 0) | - ((pte & PTE_T10_C)? PF_C: 0); - if ((pte & PTE_T10_A) && (!(mode & PTF_WR) || (pte & PTE_T10_W))) { - xpte = ((pte & PTE_PPMASK) << PAG_V_PN) | /* calc exp pte */ - PTBL_V | ((pte & PTE_T10_W)? PTBL_M: 0); - if (!(mode & PTF_CON)) /* set tbl if ~cons */ - tbl[vpn] = xpte; - return xpte; - } - PAGE_FAIL_TRAP; - } /* end TOPS10 paging */ - -/* TOPS-20 paging - checked against KS10 microcode - - TOPS-20 paging has three phases: - - 1. Starting at EPT/UPT + 540 + section number, chase section pointers to - get the pointer to the section page table. In the KS10, because there - is only one section, the microcode caches the result of this evaluation. - Also, the evaluation of indirect pointers is simplified, as the section - table index is ignored. - - 2. Starting with the page map pointer, chase page pointers to get the - pointer to the page. The KS10 allows the operating system to inhibit - updating of the CST (base address = 0). - - 3. Use the page pointer to get the CST entry. If a write reference to - a writeable page, set CST_M. If CST_M is set, set M in page table. -*/ - -else { /* TOPS-20 paging */ - int32 pmi, vpn, xpte; - int32 flg, t; - t_bool stop; - a10 pa, csta = 0; - d10 ptr, cste; - d10 acc = PTE_T20_W | PTE_T20_C; /* init access bits */ - - pager_word = PF_VIRT | ea | ((tbl == uptbl)? PF_USER: 0) | - ((mode & PTF_WR)? PF_WRITE: 0); /* set page fail word */ - -/* First phase - evaluate section pointers - returns a ptr to a page map - As a single section machine, the KS10 short circuits this part of the - process. In particular, the indirect pointer calculation assumes that - the section table index will be 0. It adds the full pointer (not just - the right half) to the SPT base. If the section index is > 0, the - result is a physical memory address > 256KW. Depending on the size of - memory, the SPT fetch may or may not generate a NXM page fail. The - KS10 then ignores the section table index in fetching the next pointer. - - The KS10 KL10 memory management diagnostic (dskec.sav) tests for this - behavior with a section index of 3. However, this would be a legal - physical address in a system with 1MW. Accordingly, the simulator - special cases non-zero section indices (which can't work in any case) - to generate the right behavior for the diagnostic. -*/ - - vpn = PAG_GETVPN (ea); /* get virt page num */ - pa = (tbl == uptbl)? upta + UPT_T20_SCTN: epta + EPT_T20_SCTN; - READPT (ptr, pa & PAMASK); /* get section 0 ptr */ - for (stop = FALSE, flg = 0; !stop; flg++) { /* eval section ptrs */ - acc = acc & ptr; /* cascade acc bits */ - switch (T20_GETTYP (ptr)) { /* case on ptr type */ - - case T20_NOA: /* no access */ - default: /* undefined type */ - PAGE_FAIL_TRAP; /* page fail */ - - case T20_IMM: /* immediate */ - stop = TRUE; /* exit */ - break; - - case T20_SHR: /* shared */ - pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */ - READPT (ptr, pa & PAMASK); /* get SPT entry */ - stop = TRUE; /* exit */ - break; - - case T20_IND: /* indirect */ - if (flg && (t = test_int ())) - ABORT (t); - pmi = T20_GETPMI (ptr); /* get sect tbl idx */ - pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */ - if (pmi) { /* for dskec */ - pag_nxm ((pmi << 18) | pa, REF_P, PF_OK); - PAGE_FAIL_TRAP; - } - READPT (ptr, pa & PAMASK); /* get SPT entry */ - if (ptr & PTE_T20_STM) { - PAGE_FAIL_TRAP; - } - pa = PAG_PTEPA (ptr, pmi); /* index off page */ - READPT (ptr, pa & PAMASK); /* get pointer */ - break; /* continue in loop */ - } /* end case */ - } /* end for */ - -/* Second phase - found page map ptr, evaluate page pointers */ - - pa = PAG_PTEPA (ptr, vpn); /* get ptbl address */ - for (stop = FALSE, flg = 0; !stop; flg++) { /* eval page ptrs */ - if (ptr & PTE_T20_STM) { /* non-res? */ - PAGE_FAIL_TRAP; - } - if (cst) { /* cst really there? */ - csta = (int32) ((cst + (ptr & PTE_PPMASK)) & PAMASK); - READPT (cste, csta); /* get CST entry */ - if ((cste & CST_AGE) == 0) { - PAGE_FAIL_TRAP; - } - cste = (cste & cstm) | pur; /* update entry */ - WriteP (csta, cste); /* rewrite */ - } - READPT (ptr, pa & PAMASK); /* get pointer */ - acc = acc & ptr; /* cascade acc bits */ - switch (T20_GETTYP (ptr)) { /* case on ptr type */ - - case T20_NOA: /* no access */ - default: /* undefined type */ - PAGE_FAIL_TRAP; /* page fail */ - - case T20_IMM: /* immediate */ - stop = TRUE; /* exit */ - break; - - case T20_SHR: /* shared */ - pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */ - READPT (ptr, pa & PAMASK); /* get SPT entry */ - stop = TRUE; /* exit */ - break; - - case T20_IND: /* indirect */ - if (flg && (t = test_int ())) - ABORT (t); - pmi = T20_GETPMI (ptr); /* get section index */ - pa = (int32) (spt + (ptr & RMASK)); /* get SPT idx */ - READPT (ptr, pa & PAMASK); /* get SPT entry */ - pa = PAG_PTEPA (ptr, pmi); /* index off page */ - break; /* continue in loop */ - } /* end case */ - } /* end for */ - -/* Last phase - have final page pointer, check modifiability */ - - if (ptr & PTE_T20_STM) { /* non-resident? */ - PAGE_FAIL_TRAP; - } - if (cst) { /* CST really there? */ - csta = (int32) ((cst + (ptr & PTE_PPMASK)) & PAMASK); - READPT (cste, csta); /* get CST entry */ - if ((cste & CST_AGE) == 0) { - PAGE_FAIL_TRAP; - } - cste = (cste & cstm) | pur; /* update entry */ - } - else cste = 0; /* no, entry = 0 */ - pager_word = pager_word | PF_T20_DN; /* set eval done */ - xpte = ((int32) ((ptr & PTE_PPMASK) << PAG_V_PN)) | PTBL_V; - if (mode & PTF_WR) { /* write? */ - if (acc & PTE_T20_W) { /* writable? */ - xpte = xpte | PTBL_M; /* set PTE M */ - cste = cste | CST_M; /* set CST M */ - } - else { /* no, trap */ - PAGE_FAIL_TRAP; - } - } - if (cst) /* write CST entry */ - WriteP (csta, cste); - if (mode & PTF_MAP) pager_word = pager_word | /* map? more in pf wd */ - ((xpte & PTBL_M)? PF_T20_M: 0) | /* M, W, C bits */ - ((acc & PTE_T20_W)? PF_T20_W: 0) | - ((acc & PTE_T20_C)? PF_C: 0); - if (!(mode & PTF_CON)) /* set tbl if ~cons */ - tbl[vpn] = xpte; - return xpte; - } /* end TOPS20 paging */ -} - -/* Set up pointers for AC, memory, and process table access */ - -void set_dyn_ptrs (void) -{ -int32 t; - -if (PAGING) { - ac_cur = &acs[UBR_GETCURAC (ubr) * AC_NUM]; - ac_prv = &acs[UBR_GETPRVAC (ubr) * AC_NUM]; - if (TSTF (F_USR)) - ptbl_cur = ptbl_prv = &uptbl[0]; - else { - ptbl_cur = &eptbl[0]; - ptbl_prv = TSTF (F_UIO)? &uptbl[0]: &eptbl[0]; - } - } -else { - ac_cur = ac_prv = &acs[0]; - ptbl_cur = ptbl_prv = &physptbl[0]; - } -t = EBR_GETEBR (ebr); -epta = t << PAG_V_PN; -if (Q_ITS) - upta = (int32) ubr & PAMASK; -else { - t = UBR_GETUBR (ubr); - upta = t << PAG_V_PN; - } -return; -} - -/* MAP instruction, TOPS-10 and TOPS-20 only - - According to the KS-10 ucode, map with paging disabled sets - "accessible, writeable, software", regardless of whether - TOPS-10 or TOPS-20 paging is implemented -*/ - -d10 map (a10 ea, int32 prv) -{ -int32 xpte; -d10 val = (TSTF (F_USR)? PF_USER: 0); - -if (!PAGING) - return (val | PF_T10_A | PF_T10_W | PF_T10_S | ea); -xpte = ptbl_fill (ea, prv? ptbl_prv: ptbl_cur, PTF_MAP); /* get exp pte */ -if (xpte) - val = (pager_word & ~PAMASK) | PAG_XPTEPA (xpte, ea); -else { - if (pager_word & PF_HARD) /* hard error */ - val = pager_word; - else val = val | PF_VIRT | ea; /* inaccessible */ - } -return val; -} - -/* Mapping routine for console */ - -a10 conmap (a10 ea, int32 mode, int32 sw) -{ -int32 xpte, *tbl; - -if (!PAGING) - return ea; -set_dyn_ptrs (); /* in case changed */ -if (sw & SWMASK ('E')) - tbl = eptbl; -else if (sw & SWMASK ('U')) - tbl = uptbl; -else tbl = ptbl_cur; -xpte = ptbl_fill (ea, tbl, mode); -if (xpte) - return PAG_XPTEPA (xpte, ea); -else return MAXMEMSIZE; -} - -/* Common pager instructions */ - -t_bool clrpt (a10 ea, int32 prv) -{ -int32 vpn = PAG_GETVPN (ea); /* get page num */ - -if (Q_ITS) { /* ITS? */ - uptbl[vpn & ~1] = 0; /* clear double size */ - uptbl[vpn | 1] = 0; /* entries in */ - eptbl[vpn & ~1] = 0; /* both page tables */ - eptbl[vpn | 1] = 0; - } -else { - uptbl[vpn] = 0; /* clear entries in */ - eptbl[vpn] = 0; /* both page tables */ - } -return FALSE; -} - -t_bool wrebr (a10 ea, int32 prv) -{ -ebr = ea & EBR_MASK; /* store EBR */ -pag_reset (&pag_dev); /* clear page tables */ -set_dyn_ptrs (); /* set dynamic ptrs */ -return FALSE; -} - -t_bool rdebr (a10 ea, int32 prv) -{ -Write (ea, (ebr & EBR_MASK), prv); -return FALSE; -} - -t_bool wrubr (a10 ea, int32 prv) -{ -d10 val = Read (ea, prv); -d10 ubr_mask = (Q_ITS)? PAMASK: UBR_UBRMASK; /* ITS: ubr is wd addr */ - -if (val & UBR_SETACB) /* set AC's? */ - ubr = ubr & ~UBR_ACBMASK; -else val = val & ~UBR_ACBMASK; /* no, keep old val */ -if (val & UBR_SETUBR) { /* set UBR? */ - ubr = ubr & ~ubr_mask; - pag_reset (&pag_dev); /* yes, clr pg tbls */ - } -else val = val & ~ubr_mask; /* no, keep old val */ -ubr = (ubr | val) & (UBR_ACBMASK | ubr_mask); -set_dyn_ptrs (); -return FALSE; -} - -t_bool rdubr (a10 ea, int32 prv) -{ -ubr = ubr & (UBR_ACBMASK | (Q_ITS? PAMASK: UBR_UBRMASK)); -Write (ea, UBRWORD, prv); -return FALSE; -} - -t_bool wrhsb (a10 ea, int32 prv) -{ -hsb = Read (ea, prv) & PAMASK; -return FALSE; -} - -t_bool rdhsb (a10 ea, int32 prv) -{ -Write (ea, hsb, prv); -return FALSE; -} - -/* TOPS20 pager instructions */ - -t_bool wrspb (a10 ea, int32 prv) -{ -spt = Read (ea, prv); -return FALSE; -} - -t_bool rdspb (a10 ea, int32 prv) -{ -Write (ea, spt, prv); -return FALSE; -} - -t_bool wrcsb (a10 ea, int32 prv) -{ -cst = Read (ea, prv); -return FALSE; -} - -t_bool rdcsb (a10 ea, int32 prv) -{ -Write (ea, cst, prv); -return FALSE; -} - -t_bool wrpur (a10 ea, int32 prv) -{ -pur = Read (ea, prv); -return FALSE; -} - -t_bool rdpur (a10 ea, int32 prv) -{ -Write (ea, pur, prv); -return FALSE; -} - -t_bool wrcstm (a10 ea, int32 prv) -{ -cstm = Read (ea, prv); -if ((cpu_unit.flags & UNIT_T20) && (ea == 040127)) - cstm = INT64_C(0770000000000); -return FALSE; -} - -t_bool rdcstm (a10 ea, int32 prv) -{ -Write (ea, cstm, prv); -return FALSE; -} - -/* ITS pager instructions - The KS10 does not implement the JPC option. -*/ - -t_bool clrcsh (a10 ea, int32 prv) -{ -return FALSE; -} - -t_bool ldbr1 (a10 ea, int32 prv) -{ -dbr1 = ea; -pag_reset (&pag_dev); -return FALSE; -} - -t_bool sdbr1 (a10 ea, int32 prv) -{ -Write (ea, dbr1, prv); -return FALSE; -} - -t_bool ldbr2 (a10 ea, int32 prv) -{ -dbr2 = ea; -pag_reset (&pag_dev); -return FALSE; -} - -t_bool sdbr2 (a10 ea, int32 prv) -{ -Write (ea, dbr2, prv); -return FALSE; -} - -t_bool ldbr3 (a10 ea, int32 prv) -{ -dbr3 = ea; -pag_reset (&pag_dev); -return FALSE; -} - -t_bool sdbr3 (a10 ea, int32 prv) -{ -Write (ea, dbr3, prv); -return FALSE; -} - -t_bool ldbr4 (a10 ea, int32 prv) -{ -dbr4 = ea; -pag_reset (&pag_dev); -return FALSE; -} - -t_bool sdbr4 (a10 ea, int32 prv) -{ -Write (ea, dbr4, prv); -return FALSE; -} - -t_bool wrpcst (a10 ea, int32 prv) -{ -pcst = Read (ea, prv); -return FALSE; -} - -t_bool rdpcst (a10 ea, int32 prv) -{ -Write (ea, pcst, prv); -return FALSE; -} - -t_bool lpmr (a10 ea, int32 prv) -{ -d10 val; - -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; -} - -t_bool spm (a10 ea, int32 prv) -{ - -ReadM (ADDA (ea, 2), prv); -Write (ea, dbr1, prv); -Write (ADDA (ea, 1), dbr2, prv); -Write (ADDA (ea, 2), quant, prv); -return FALSE; -} - -/* Simulator interface routines */ - -t_stat pag_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) -{ -int32 tbln = uptr - pag_unit; - -if (addr >= PTBL_MEMSIZE) - return SCPE_NXM; -*vptr = tbln? uptbl[addr]: eptbl[addr];; -return SCPE_OK; -} - -t_stat pag_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) -{ -int32 tbln = uptr - pag_unit; - -if (addr >= PTBL_MEMSIZE) - return SCPE_NXM; -if (tbln) - uptbl[addr] = (int32) val & PTBL_MASK; -else eptbl[addr] = (int32) val & PTBL_MASK; -return SCPE_OK; -} - -t_stat pag_reset (DEVICE *dptr) -{ -int32 i; - -for (i = 0; i < PTBL_MEMSIZE; i++) { - eptbl[i] = uptbl[i] = 0; - physptbl[i] = (i << PAG_V_PN) + PTBL_M + PTBL_V; - } -return SCPE_OK; -} diff --git a/PDP10/pdp10_rp.c b/PDP10/pdp10_rp.c deleted file mode 100644 index 070640c1..00000000 --- a/PDP10/pdp10_rp.c +++ /dev/null @@ -1,1381 +0,0 @@ -/* pdp10_rp.c - RH11/RP04/05/06/07 RM02/03/05/80 "Massbus" disk controller - - Copyright (c) 1993-2017, 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. - - rp RH/RP/RM moving head disks - - 13-Mar-17 RMS Annotated fall through in switch - 17-Mar-13 RMS Fixed incorrect copy/paste from pdp11_rp.c - 08-Dec-12 RMS UNLOAD does not set ATTN (Mark Pizzolato) - 12-Nov-05 RMS Fixed DCLR not to clear drive address - 07-Jul-05 RMS Removed extraneous externs - 18-Mar-05 RMS Added attached test to detach routine - 20-Sep-04 RMS Fixed bugs in replicated state, RP vs RM accuracy - 04-Jan-04 RMS Changed sim_fsize calling sequence - 23-Jul-03 RMS Fixed bug in read header stub - 25-Apr-03 RMS Revised for extended file support - 21-Nov-02 RMS Fixed bug in bootstrap (Michael Thompson) - 29-Sep-02 RMS Added variable vector support - New data structures - 30-Nov-01 RMS Added read only unit, extended SET/SHOW support support - 24-Nov-01 RMS Changed RPER, RPDS, FNC, FLG to arrays - 23-Oct-01 RMS Fixed bug in error interrupts - New IO page address constants - 05-Oct-01 RMS Rewrote interrupt handling from schematics - 02-Oct-01 RMS Revised CS1 write code - 30-Sep-01 RMS Moved CS1<5:0> into drives - 28-Sep-01 RMS Fixed interrupt handling for SC/ATA - 23-Aug-01 RMS Added read/write header stubs for ITS - (found by Mirian Crzig Lennox) - 13-Jul-01 RMS Changed fread call to fxread (Peter Schorn) - 14-May-01 RMS Added check for unattached drive - - The "Massbus style" disks consisted of several different large - capacity drives interfaced through a reasonably common (but not - 100% compatible) family of interfaces into the KS10 Unibus via - the RH11 disk controller. - - WARNING: The interupt logic of the RH11/RH70 is unusual and must be - simulated with great precision. The RH11 has an internal interrupt - request flop, CSTB INTR, which is controlled as follows: - - Writing IE and DONE simultaneously sets CSTB INTR - - Controller clear, INIT, and interrupt acknowledge clear CSTB INTR - (and also clear IE) - - A transition of DONE from 0 to 1 sets CSTB from INTR - The output of INTR is OR'd with the AND of RPCS1 to - create the interrupt request signal. Thus, - - The DONE interrupt is edge sensitive, but the SC interrupt is - level sensitive. - - The DONE interrupt, once set, is not disabled if IE is cleared, - but the SC interrupt is. -*/ - -#include "pdp10_defs.h" -#include -#include - -#define RP_NUMDR 8 /* #drives */ -#define RP_NUMWD 128 /* 36b words/sector */ -#define RP_MAXFR 32768 /* max transfer */ -#define SPINUP_DLY (1000*1000) /* Spinup delay, usec */ -#define GET_SECTOR(x,d) ((int) fmod (sim_gtime() / ((double) (x)), \ - ((double) drv_tab[d].sect))) -#define MBA_RP_CTRL 0 /* RP drive */ -#define MBA_RM_CTRL 1 /* RM drive */ - -/* Flags in the unit flags word */ - -#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */ -#define UNIT_M_DTYPE 7 -#define UNIT_V_AUTO (UNIT_V_UF + 4) /* autosize */ -#define UNIT_V_UTS (UNIT_V_UF + 5) /* Up to speed */ -#define UNIT_UTS (1u << UNIT_V_UTS) -#define UNIT_V_DUMMY (UNIT_V_UF + 6) /* dummy flag */ -#define UNIT_WLK (1 << UNIT_V_WLK) -#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE) -#define UNIT_AUTO (1 << UNIT_V_AUTO) -#define UNIT_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 */ - -#define CYL u3 /* current cylinder */ -#define FUNC u4 /* function */ - -/* RPCS1 - 176700 - control/status 1 */ - -#define CS1_GO CSR_GO /* go */ -#define CS1_V_FNC 1 /* function pos */ -#define CS1_M_FNC 037 /* function mask */ -#define CS1_FNC (CS1_M_FNC << CS1_V_FNC) -#define FNC_NOP 000 /* no operation */ -#define FNC_UNLOAD 001 /* unload */ -#define FNC_SEEK 002 /* seek */ -#define FNC_RECAL 003 /* recalibrate */ -#define FNC_DCLR 004 /* drive clear */ -#define FNC_RELEASE 005 /* port release */ -#define FNC_OFFSET 006 /* offset */ -#define FNC_RETURN 007 /* return to center */ -#define FNC_PRESET 010 /* read-in preset */ -#define FNC_PACK 011 /* pack acknowledge */ -#define FNC_SEARCH 014 /* search */ -#define FNC_XFER 024 /* >=? data xfr */ -#define FNC_WCHK 024 /* write check */ -#define FNC_WRITE 030 /* write */ -#define FNC_WRITEH 031 /* write w/ headers */ -#define FNC_READ 034 /* read */ -#define FNC_READH 035 /* read w/ headers */ -#define CS1_IE CSR_IE /* int enable */ -#define CS1_DONE CSR_DONE /* ready */ -#define CS1_V_UAE 8 /* Unibus addr ext */ -#define CS1_M_UAE 03 -#define CS1_UAE (CS1_M_UAE << CS1_V_UAE) -#define CS1_DVA 0004000 /* drive avail NI */ -#define CS1_MCPE 0020000 /* Mbus par err NI */ -#define CS1_TRE 0040000 /* transfer err */ -#define CS1_SC 0100000 /* special cond */ -#define CS1_MBZ 0012000 -#define CS1_DRV (CS1_FNC | CS1_GO) -#define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC) -#define GET_UAE(x) (((x) & CS1_UAE) << (16 - CS1_V_UAE)) - -/* RPWC - 176702 - word count */ - -/* RPBA - 176704 - base address */ - -#define BA_MBZ 0000001 /* must be zero */ - -/* RPDA - 176706 - sector/track */ - -#define DA_V_SC 0 /* sector pos */ -#define DA_M_SC 077 /* sector mask */ -#define DA_V_SF 8 /* track pos */ -#define DA_M_SF 077 /* track mask */ -#define DA_MBZ 0140300 -#define GET_SC(x) (((x) >> DA_V_SC) & DA_M_SC) -#define GET_SF(x) (((x) >> DA_V_SF) & DA_M_SF) - -/* RPCS2 - 176710 - control/status 2 */ - -#define CS2_V_UNIT 0 /* unit pos */ -#define CS2_M_UNIT 07 /* unit mask */ -#define CS2_UNIT (CS2_M_UNIT << CS2_V_UNIT) -#define CS2_UAI 0000010 /* addr inhibit */ -#define CS2_PAT 0000020 /* parity test NI */ -#define CS2_CLR 0000040 /* controller clear */ -#define CS2_IR 0000100 /* input ready */ -#define CS2_OR 0000200 /* output ready */ -#define CS2_MDPE 0000400 /* Mbus par err NI */ -#define CS2_MXF 0001000 /* missed xfer NI */ -#define CS2_PGE 0002000 /* program err */ -#define CS2_NEM 0004000 /* nx mem err */ -#define CS2_NED 0010000 /* nx drive err */ -#define CS2_PE 0020000 /* parity err NI */ -#define CS2_WCE 0040000 /* write check err */ -#define CS2_DLT 0100000 /* data late NI */ -#define CS2_MBZ (CS2_CLR) -#define CS2_RW (CS2_UNIT | CS2_UAI | CS2_PAT | CS2_MXF | CS2_PE) -#define CS2_ERR (CS2_MDPE | CS2_MXF | CS2_PGE | CS2_NEM | \ - CS2_NED | CS2_PE | CS2_WCE | CS2_DLT ) -#define GET_UNIT(x) (((x) >> CS2_V_UNIT) & CS2_M_UNIT) - -/* RPDS - 176712 - drive status */ - -#define DS_OF 0000001 /* offset mode */ -#define DS_VV 0000100 /* volume valid */ -#define DS_RDY 0000200 /* drive ready */ -#define DS_DPR 0000400 /* drive present */ -#define DS_PGM 0001000 /* programable NI */ -#define DS_LST 0002000 /* last sector */ -#define DS_WRL 0004000 /* write locked */ -#define DS_MOL 0010000 /* medium online */ -#define DS_PIP 0020000 /* pos in progress */ -#define DS_ERR 0040000 /* error */ -#define DS_ATA 0100000 /* attention active */ -#define DS_MBZ 0000076 - -/* RPER1 - 176714 - error status 1 */ - -#define ER1_ILF 0000001 /* illegal func */ -#define ER1_ILR 0000002 /* illegal register */ -#define ER1_RMR 0000004 /* reg mod refused */ -#define ER1_PAR 0000010 /* parity err */ -#define ER1_FER 0000020 /* format err NI */ -#define ER1_WCF 0000040 /* write clk fail NI */ -#define ER1_ECH 0000100 /* ECC hard err NI */ -#define ER1_HCE 0000200 /* hdr comp err NI */ -#define ER1_HCR 0000400 /* hdr CRC err NI */ -#define ER1_AOE 0001000 /* addr ovflo err */ -#define ER1_IAE 0002000 /* invalid addr err */ -#define ER1_WLE 0004000 /* write lock err */ -#define ER1_DTE 0010000 /* drive time err NI */ -#define ER1_OPI 0020000 /* op incomplete */ -#define ER1_UNS 0040000 /* drive unsafe */ -#define ER1_DCK 0100000 /* data check NI */ - -/* RPAS - 176716 - attention summary */ - -#define AS_U0 0000001 /* unit 0 flag */ - -/* RPLA - 176720 - look ahead register */ - -#define LA_V_SC 6 /* sector pos */ - -/* RPDB - 176722 - data buffer */ -/* RPMR - 176724 - maintenace register */ -/* RPDT - 176726 - drive type */ -/* RPSN - 176730 - serial number */ - -/* RPOF - 176732 - offset register */ - -#define OF_HCI 0002000 /* hdr cmp inh NI */ -#define OF_ECI 0004000 /* ECC inhibit NI */ -#define OF_F22 0010000 /* format NI */ -#define OF_MBZ 0161400 - -/* RPDC - 176734 - desired cylinder */ - -#define DC_V_CY 0 /* cylinder pos */ -#define DC_M_CY 01777 /* cylinder mask */ -#define DC_MBZ 0176000 -#define GET_CY(x) (((x) >> DC_V_CY) & DC_M_CY) -#define GET_DA(c,fs,d) ((((GET_CY (c) * drv_tab[d].surf) + \ - GET_SF (fs)) * drv_tab[d].sect) + GET_SC (fs)) - -/* RPCC - 176736 - current cylinder */ -/* RPER2 - 176740 - error status 2 - drive unsafe conditions */ -/* RPER3 - 176742 - error status 3 - more unsafe conditions */ -/* RPEC1 - 176744 - ECC status 1 - unimplemented */ -/* RPEC2 - 176746 - ECC status 2 - unimplemented */ - -/* This controller supports many different disk drive types. These drives - are operated in 576 bytes/sector (128 36b words/sector) mode, which gives - them somewhat different geometry from the PDP-11 variants: - - type #sectors/ #surfaces/ #cylinders/ - surface cylinder drive - - RM02/3 30 5 823 =67MB - RP04/5 20 19 411 =88MB - RM80 30 14 559 =124MB - RP06 20 19 815 =176MB - RM05 30 19 823 =256MB - RP07 43 32 630 =516MB - - In theory, each drive can be a different type. The size field in - each unit selects the drive capacity for each drive and thus the - drive type. DISKS MUST BE DECLARED IN ASCENDING SIZE. - - The RP07, despite its name, uses an RM-style controller. -*/ - -#define RM03_DTYPE 0 -#define RM03_SECT 30 -#define RM03_SURF 5 -#define RM03_CYL 823 -#define RM03_DEV 020024 -#define RM03_SIZE (RM03_SECT * RM03_SURF * RM03_CYL * RP_NUMWD) - -#define RP04_DTYPE 1 -#define RP04_SECT 20 -#define RP04_SURF 19 -#define RP04_CYL 411 -#define RP04_DEV 020020 -#define RP04_SIZE (RP04_SECT * RP04_SURF * RP04_CYL * RP_NUMWD) - -#define RM80_DTYPE 2 -#define RM80_SECT 30 -#define RM80_SURF 14 -#define RM80_CYL 559 -#define RM80_DEV 020026 -#define RM80_SIZE (RM80_SECT * RM80_SURF * RM80_CYL * RP_NUMWD) - -#define RP06_DTYPE 3 -#define RP06_SECT 20 -#define RP06_SURF 19 -#define RP06_CYL 815 -#define RP06_DEV 020022 -#define RP06_SIZE (RP06_SECT * RP06_SURF * RP06_CYL * RP_NUMWD) - -#define RM05_DTYPE 4 -#define RM05_SECT 30 -#define RM05_SURF 19 -#define RM05_CYL 823 -#define RM05_DEV 020027 -#define RM05_SIZE (RM05_SECT * RM05_SURF * RM05_CYL * RP_NUMWD) - -#define RP07_DTYPE 5 -#define RP07_SECT 43 -#define RP07_SURF 32 -#define RP07_CYL 630 -#define RP07_DEV 020042 -#define RP07_SIZE (RP07_SECT * RP07_SURF * RP07_CYL * RP_NUMWD) - -struct drvtyp { - int32 sect; /* sectors */ - int32 surf; /* surfaces */ - int32 cyl; /* cylinders */ - int32 size; /* #blocks */ - int32 devtype; /* device type */ - int32 ctrl; /* ctrl type */ - }; - -struct drvtyp drv_tab[] = { - { RM03_SECT, RM03_SURF, RM03_CYL, RM03_SIZE, RM03_DEV, MBA_RM_CTRL }, - { RP04_SECT, RP04_SURF, RP04_CYL, RP04_SIZE, RP04_DEV, MBA_RP_CTRL }, - { RM80_SECT, RM80_SURF, RM80_CYL, RM80_SIZE, RM80_DEV, MBA_RM_CTRL }, - { RP06_SECT, RP06_SURF, RP06_CYL, RP06_SIZE, RP06_DEV, MBA_RP_CTRL }, - { RM05_SECT, RM05_SURF, RM05_CYL, RM05_SIZE, RM05_DEV, MBA_RM_CTRL }, - { RP07_SECT, RP07_SURF, RP07_CYL, RP07_SIZE, RP07_DEV, MBA_RM_CTRL }, - { 0 } - }; - -extern d10 *M; /* memory */ -extern int32 int_req; -extern int32 ubmap[UBANUM][UMAP_MEMSIZE]; /* Unibus maps */ -extern int32 ubcs[UBANUM]; -extern UNIT cpu_unit; -extern uint32 fe_bootrh; -extern int32 fe_bootunit; - -int32 rpcs1 = 0; /* control/status 1 */ -int32 rpwc = 0; /* word count */ -int32 rpba = 0; /* bus address */ -int32 rpcs2 = 0; /* control/status 2 */ -int32 rpdb = 0; /* data buffer */ -uint16 rpda[RP_NUMDR] = { 0 }; /* track/sector */ -uint16 rpds[RP_NUMDR] = { 0 }; /* drive status */ -uint16 rper1[RP_NUMDR] = { 0 }; /* error status 1 */ -uint16 rmhr[RP_NUMDR] = { 0 }; /* holding reg */ -uint16 rpmr[RP_NUMDR] = { 0 }; /* maint reg */ -uint16 rmmr2[RP_NUMDR] = { 0 }; /* maint reg 2 */ -uint16 rpof[RP_NUMDR] = { 0 }; /* offset */ -uint16 rpdc[RP_NUMDR] = { 0 }; /* cylinder */ -uint16 rper2[RP_NUMDR] = { 0 }; /* error status 2 */ -uint16 rper3[RP_NUMDR] = { 0 }; /* error status 3 */ -uint16 rpec1[RP_NUMDR] = { 0 }; /* ECC correction 1 */ -uint16 rpec2[RP_NUMDR] = { 0 }; /* ECC correction 2 */ -int32 rpiff = 0; /* INTR flip/flop */ -int32 rp_stopioe = 1; /* stop on error */ -int32 rp_swait = 10; /* seek time */ -int32 rp_rwait = 10; /* rotate time */ -static int32 reg_in_drive[32] = { - 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - -t_stat rp_rd (int32 *data, int32 PA, int32 access); -t_stat rp_wr (int32 data, int32 PA, int32 access); -int32 rp_inta (void); -t_stat rp_svc (UNIT *uptr); -t_stat rp_reset (DEVICE *dptr); -t_stat rp_boot (int32 unitno, DEVICE *dptr); -t_stat rp_attach (UNIT *uptr, char *cptr); -t_stat rp_detach (UNIT *uptr); -void set_rper (int16 flag, int32 drv); -void update_rpcs (int32 flags, int32 drv); -void rp_go (int32 drv, int32 fnc); -t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); - -/* RP data structures - - rp_dev RP device descriptor - rp_unit RP unit list - rp_reg RP register list - rp_mod RP modifier list -*/ - -DIB rp_dib = { - IOBA_RP, IOLN_RP, &rp_rd, &rp_wr, - 1, IVCL (RP), VEC_RP, { &rp_inta } - }; - -UNIT rp_unit[] = { - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+(RP06_DTYPE << UNIT_V_DTYPE), RP06_SIZE) } - }; - -REG rp_reg[] = { - { ORDATA (RPCS1, rpcs1, 16) }, - { ORDATA (RPWC, rpwc, 16) }, - { ORDATA (RPBA, rpba, 16) }, - { ORDATA (RPCS2, rpcs2, 16) }, - { ORDATA (RPDB, rpdb, 16) }, - { BRDATA (RPDA, rpda, 8, 16, RP_NUMDR) }, - { BRDATA (RPDS, rpds, 8, 16, RP_NUMDR) }, - { BRDATA (RPER1, rper1, 8, 16, RP_NUMDR) }, - { BRDATA (RPHR, rmhr, 8, 16, RP_NUMDR) }, - { BRDATA (RPOF, rpof, 8, 16, RP_NUMDR) }, - { BRDATA (RPDC, rpdc, 8, 16, RP_NUMDR) }, - { BRDATA (RPER2, rper2, 8, 16, RP_NUMDR) }, - { BRDATA (RPER3, rper3, 8, 16, RP_NUMDR) }, - { BRDATA (RPEC1, rpec1, 8, 16, RP_NUMDR) }, - { BRDATA (RPEC2, rpec2, 8, 16, RP_NUMDR) }, - { BRDATA (RMMR, rpmr, 8, 16, RP_NUMDR) }, - { BRDATA (RMMR2, rmmr2, 8, 16, RP_NUMDR) }, - { FLDATA (IFF, rpiff, 0) }, - { FLDATA (INT, int_req, INT_V_RP) }, - { FLDATA (SC, rpcs1, CSR_V_ERR) }, - { FLDATA (DONE, rpcs1, CSR_V_DONE) }, - { FLDATA (IE, rpcs1, CSR_V_IE) }, - { DRDATA (STIME, rp_swait, 24), REG_NZ + PV_LEFT }, - { DRDATA (RTIME, rp_rwait, 24), REG_NZ + PV_LEFT }, - { URDATA (FNC, rp_unit[0].FUNC, 8, 5, 0, RP_NUMDR, REG_HRO) }, - { URDATA (CAPAC, rp_unit[0].capac, 10, T_ADDR_W, 0, - RP_NUMDR, PV_LEFT | REG_HRO) }, - { FLDATA (STOP_IOE, rp_stopioe, 0) }, - { NULL } - }; - -MTAB rp_mod[] = { - { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, - { (UNIT_DTYPE+UNIT_ATT), (RM03_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, - "RM03", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (RP04_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, - "RP04", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (RM80_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, - "RM80", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (RP06_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, - "RP06", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (RM05_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, - "RM05", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (RP07_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, - "RP07", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RM03_DTYPE << UNIT_V_DTYPE), - "RM03", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RP04_DTYPE << UNIT_V_DTYPE), - "RP04", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RM80_DTYPE << UNIT_V_DTYPE), - "RM80", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RP06_DTYPE << UNIT_V_DTYPE), - "RP06", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RM05_DTYPE << UNIT_V_DTYPE), - "RM05", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RP07_DTYPE << UNIT_V_DTYPE), - "RP07", NULL, NULL }, - { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL }, - { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL }, - { (UNIT_AUTO+UNIT_DTYPE), (RM03_DTYPE << UNIT_V_DTYPE), - NULL, "RM03", &rp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (RP04_DTYPE << UNIT_V_DTYPE), - NULL, "RP04", &rp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (RM80_DTYPE << UNIT_V_DTYPE), - NULL, "RM80", &rp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (RP06_DTYPE << UNIT_V_DTYPE), - NULL, "RP06", &rp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (RM05_DTYPE << UNIT_V_DTYPE), - NULL, "RM05", &rp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (RP07_DTYPE << UNIT_V_DTYPE), - NULL, "RP07", &rp_set_size }, - { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, - NULL, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, - NULL, &show_vec, NULL }, - { 0 } - }; - -DEVICE rp_dev = { - "RP", rp_unit, rp_reg, rp_mod, - RP_NUMDR, 8, 30, 1, 8, 36, - NULL, NULL, &rp_reset, - &rp_boot, &rp_attach, &rp_detach, - &rp_dib, DEV_UBUS - }; - -/* I/O dispatch routines, I/O addresses 17776700 - 17776776 */ - -t_stat rp_rd (int32 *data, int32 PA, int32 access) -{ -int32 drv, dtype, i, j; - -drv = GET_UNIT (rpcs2); /* get current unit */ -dtype = GET_DTYPE (rp_unit[drv].flags); /* get drive type */ -j = (PA >> 1) & 037; /* get reg offset */ -if (reg_in_drive[j] && (rp_unit[drv].flags & UNIT_DIS)) { /* nx disk */ - rpcs2 = rpcs2 | CS2_NED; /* set error flag */ - update_rpcs (CS1_SC, drv); /* request intr */ - *data = 0; - return SCPE_OK; - } - -update_rpcs (0, drv); /* update status */ -switch (j) { /* decode PA<5:1> */ - - case 000: /* RPCS1 */ - *data = rpcs1; - break; - - case 001: /* RPWC */ - *data = rpwc; - break; - - case 002: /* RPBA */ - *data = rpba = rpba & ~BA_MBZ; - break; - - case 003: /* RPDA */ - *data = rpda[drv] = rpda[drv] & ~DA_MBZ; - break; - - case 004: /* RPCS2 */ - *data = rpcs2 = (rpcs2 & ~CS2_MBZ) | CS2_IR | CS2_OR; - break; - - case 005: /* RPDS */ - *data = rpds[drv]; - break; - - case 006: /* RPER1 */ - *data = rper1[drv]; - break; - - case 007: /* RPAS */ - *data = 0; - for (i = 0; i < RP_NUMDR; i++) - if (rpds[i] & DS_ATA) - *data = *data | (AS_U0 << i); - break; - - case 010: /* RPLA */ - *data = GET_SECTOR (rp_rwait, dtype) << LA_V_SC; - break; - - case 011: /* RPDB */ - *data = rpdb; - break; - - case 012: /* RPMR */ - *data = rpmr[drv]; - break; - - case 013: /* RPDT */ - *data = drv_tab[dtype].devtype; - break; - - case 014: /* RPSN */ - *data = 020 | (drv + 1); - break; - - case 015: /* RPOF */ - *data = rpof[drv] = rpof[drv] & ~OF_MBZ; - break; - - case 016: /* RPDC */ - *data = rpdc[drv] = rpdc[drv] & ~DC_MBZ; - break; - - case 017: /* RPCC, RMHR */ - if (drv_tab[dtype].ctrl == MBA_RP_CTRL) /* RP is CC */ - *data = rp_unit[drv].CYL; - else *data = rmhr[drv] ^ 0177777; /* RM is HR */ - break; - - case 020: /* RPER2, RMMR2 */ - if (drv_tab[dtype].ctrl == MBA_RP_CTRL) /* RP is ER2 */ - *data = rper2[drv]; - else *data = rmmr2[drv]; /* RM is MR2 */ - break; - - case 021: /* RPER3, RMER2 */ - if (drv_tab[dtype].ctrl == MBA_RP_CTRL) /* RP is ER3 */ - *data = rper3[drv]; - else *data = rper2[drv]; /* RM is ER2 */ - break; - - case 022: /* RPEC1 */ - *data = rpec1[drv]; - break; - - case 023: /* RPEC2 */ - *data = rpec2[drv]; - break; - - default: /* all others */ - set_rper (ER1_ILR, drv); - update_rpcs (0, drv); - break; - } -return SCPE_OK; -} - -t_stat rp_wr (int32 data, int32 PA, int32 access) -{ -int32 cs1f, drv, i, j; -UNIT *uptr; - -cs1f = 0; /* no int on cs1 upd */ -drv = GET_UNIT (rpcs2); /* get current unit */ -uptr = rp_dev.units + drv; /* get unit */ -j = (PA >> 1) & 037; /* get reg offset */ -if (reg_in_drive[j] && (rp_unit[drv].flags & UNIT_DIS)) { /* nx disk */ - rpcs2 = rpcs2 | CS2_NED; /* set error flag */ - update_rpcs (CS1_SC, drv); /* request intr */ - return SCPE_OK; - } -if (reg_in_drive[j] && sim_is_active (uptr) && (uptr->flags & UNIT_UTS)) { /* unit busy? */ - set_rper (ER1_RMR, drv); /* won't write */ - update_rpcs (0, drv); - return SCPE_OK; - } -rmhr[drv] = (uint16)data; - -switch (j) { /* decode PA<5:1> */ - - case 000: /* RPCS1 */ - if ((access == WRITEB) && (PA & 1)) - data = data << 8; - if (data & CS1_TRE) { /* error clear? */ - rpcs1 = rpcs1 & ~CS1_TRE; /* clr CS1 */ - rpcs2 = rpcs2 & ~CS2_ERR; /* clr CS2<15:8> */ - } - if ((access == WRITE) || (PA & 1)) { /* hi byte write? */ - if (rpcs1 & CS1_DONE) /* done set? */ - rpcs1 = (rpcs1 & ~CS1_UAE) | (data & CS1_UAE); - } - if ((access == WRITE) || !(PA & 1)) { /* lo byte write? */ - if ((data & CS1_DONE) && (data & CS1_IE)) /* to DONE+IE? */ - rpiff = 1; /* set CSTB INTR */ - rpcs1 = (rpcs1 & ~CS1_IE) | (data & CS1_IE); - if (uptr->flags & UNIT_DIS) { /* nx disk? */ - rpcs2 = rpcs2 | CS2_NED; /* set error flag */ - cs1f = CS1_SC; /* req interrupt */ - } - else if (sim_is_active (uptr) && (uptr->flags & UNIT_UTS)) - set_rper (ER1_RMR, drv); /* won't write */ - else if (data & CS1_GO) { /* start op */ - uptr->FUNC = GET_FNC (data); /* set func */ - if ((uptr->FUNC >= FNC_XFER) && /* data xfer and */ - ((rpcs1 & CS1_DONE) == 0)) /* ~rdy? PGE */ - rpcs2 = rpcs2 | CS2_PGE; - else rp_go (drv, uptr->FUNC); - } - } - break; - - case 001: /* RPWC */ - if (access == WRITEB) - data = (PA & 1)? - (rpwc & 0377) | (data << 8): (rpwc & ~0377) | data; - rpwc = data; - break; - - case 002: /* RPBA */ - if (access == WRITEB) - data = (PA & 1)? - (rpba & 0377) | (data << 8): (rpba & ~0377) | data; - rpba = data & ~BA_MBZ; - break; - - case 003: /* RPDA */ - if ((access == WRITEB) && (PA & 1)) - data = data << 8; - rpda[drv] = (uint16)(data & ~DA_MBZ); - break; - - case 004: /* RPCS2 */ - if ((access == WRITEB) && (PA & 1)) - data = data << 8; - if (data & CS2_CLR) /* init? */ - rp_reset (&rp_dev); - else { - if ((data & ~rpcs2) & (CS2_PE | CS2_MXF)) - cs1f = CS1_SC; /* diagn intr */ - if (access == WRITEB) /* merge data */ - data = (rpcs2 & ((PA & 1)? 0377: 0177400)) | data; - rpcs2 = (rpcs2 & ~CS2_RW) | (data & CS2_RW) | CS2_IR | CS2_OR; - } - drv = GET_UNIT (rpcs2); - break; - - case 006: /* RPER1 */ - if ((access == WRITEB) && (PA & 1)) - data = data << 8; - rper1[drv] = (uint16)data; - break; - - case 007: /* RPAS */ - if ((access == WRITEB) && (PA & 1)) - break; - for (i = 0; i < RP_NUMDR; i++) - if (data & (AS_U0 << i)) - rpds[i] = rpds[i] & ~DS_ATA; - break; - - case 011: /* RPDB */ - if (access == WRITEB) - data = (PA & 1)? - (rpdb & 0377) | (data << 8): (rpdb & ~0377) | data; - rpdb = data; - break; - - case 012: /* RPMR */ - if ((access == WRITEB) && (PA & 1)) - data = data << 8; - rpmr[drv] = (uint16)data; - break; - - case 015: /* RPOF */ - rpof[drv] = (uint16)(data & ~OF_MBZ); - break; - - case 016: /* RPDC */ - if ((access == WRITEB) && (PA & 1)) - data = data << 8; - rpdc[drv] = (uint16)(data & ~DC_MBZ); - break; - - case 005: /* RPDS */ - case 010: /* RPLA */ - case 013: /* RPDT */ - case 014: /* RPSN */ - case 017: /* RPCC, RMHR */ - case 020: /* RPER2, RMMR2 */ - case 021: /* RPER3, RMER2 */ - case 022: /* RPEC1 */ - case 023: /* RPEC2 */ - break; /* read only */ - - default: /* all others */ - set_rper (ER1_ILR, drv); - break; - } /* end switch */ - -update_rpcs (cs1f, drv); /* update status */ -return SCPE_OK; -} - -/* Initiate operation - unit not busy, function set */ - -void rp_go (int32 drv, int32 fnc) -{ -int32 dc, dtype, t; -UNIT *uptr; - -uptr = rp_dev.units + drv; /* get unit */ -if (uptr->flags & UNIT_DIS) { /* nx unit? */ - rpcs2 = rpcs2 | CS2_NED; /* set error flag */ - update_rpcs (CS1_SC, drv); /* request intr */ - return; - } -if ((fnc != FNC_DCLR) && (rpds[drv] & DS_ERR)) { /* err & ~clear? */ - set_rper (ER1_ILF, drv); /* set err, ATN */ - update_rpcs (CS1_SC, drv); /* request intr */ - return; - } -dtype = GET_DTYPE (uptr->flags); /* get drive type */ -rpds[drv] = rpds[drv] & ~DS_ATA; /* clear attention */ -dc = rpdc[drv]; /* assume seek, sch */ - -switch (fnc) { /* case on function */ - - case FNC_DCLR: /* drive clear */ - rper1[drv] = rper2[drv] = rper3[drv] = 0; /* clear errors */ - rpec2[drv] = 0; /* clear EC2 */ - if (drv_tab[dtype].ctrl == MBA_RM_CTRL) /* RM? */ - rpmr[drv] = 0; /* clear maint */ - else rpec1[drv] = 0; /* RP, clear EC1 */ - case FNC_NOP: /* no operation */ - case FNC_RELEASE: /* port release */ - return; - - case FNC_PRESET: /* read-in preset */ - rpdc[drv] = 0; /* clear disk addr */ - rpda[drv] = 0; - rpof[drv] = 0; /* clear offset */ - case FNC_PACK: /* pack acknowledge */ - if ((uptr->flags & UNIT_UTS) == 0) { /* not attached? */ - set_rper (ER1_UNS, drv); /* unsafe */ - break; - } - rpds[drv] = rpds[drv] | DS_VV; /* set volume valid */ - return; - - case FNC_OFFSET: /* offset mode */ - case FNC_RETURN: - if ((uptr->flags & UNIT_UTS) == 0) { /* not attached? */ - set_rper (ER1_UNS, drv); /* unsafe */ - break; - } - rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */ - sim_activate (uptr, rp_swait); /* time operation */ - return; - - case FNC_UNLOAD: /* unload */ - case FNC_RECAL: /* recalibrate */ - dc = 0; /* seek to 0 */ - case FNC_SEEK: /* seek */ - case FNC_SEARCH: /* search */ - if ((uptr->flags & UNIT_UTS) == 0) { /* not attached? */ - set_rper (ER1_UNS, drv); /* unsafe */ - break; - } - if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */ - (GET_SF (rpda[drv]) >= drv_tab[dtype].surf) || /* bad surface */ - (GET_SC (rpda[drv]) >= drv_tab[dtype].sect)) { /* or bad sector? */ - set_rper (ER1_IAE, drv); - break; - } - rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */ - t = abs (dc - uptr->CYL); /* cyl diff */ - if (t == 0) /* min time */ - t = 1; - sim_activate (uptr, rp_swait * t); /* schedule */ - uptr->CYL = dc; /* save cylinder */ - return; - - case FNC_WRITEH: /* write headers */ - case FNC_WRITE: /* write */ - case FNC_WCHK: /* write check */ - case FNC_READ: /* read */ - case FNC_READH: /* read headers */ - if ((uptr->flags & UNIT_UTS) == 0) { /* not attached? */ - set_rper (ER1_UNS, drv); /* unsafe */ - break; - } - rpcs2 = rpcs2 & ~CS2_ERR; /* clear errors */ - rpcs1 = rpcs1 & ~(CS1_TRE | CS1_MCPE | CS1_DONE); - if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */ - (GET_SF (rpda[drv]) >= drv_tab[dtype].surf) || /* bad surface */ - (GET_SC (rpda[drv]) >= drv_tab[dtype].sect)) { /* or bad sector? */ - set_rper (ER1_IAE, drv); - break; - } - rpds[drv] = rpds[drv] & ~DS_RDY; /* clear drive rdy */ - sim_activate (uptr, rp_rwait + (rp_swait * abs (dc - uptr->CYL))); - uptr->CYL = dc; /* save cylinder */ - return; - - default: /* all others */ - set_rper (ER1_ILF, drv); /* not supported */ - break; - } - -update_rpcs (CS1_SC, drv); /* req intr */ -return; -} - -/* Service unit timeout - - Complete movement or data transfer command - Unit must exist - can't remove an active unit - Unit must be attached - detach cancels in progress operations -*/ - -t_stat rp_svc (UNIT *uptr) -{ -int32 i, dtype, drv, err; -int32 ba, da, vpn; -a10 pa10, mpa10; -int32 wc10, twc10, awc10, fc10; -static d10 dbuf[RP_MAXFR]; - -dtype = GET_DTYPE (uptr->flags); /* get drive type */ -drv = (int32) (uptr - rp_dev.units); /* get drv number */ -if ((uptr->flags & UNIT_UTS) == 0) { /* Transition to up-to-speed */ - uptr->flags |= UNIT_UTS; - rpds[drv] = DS_ATA | DS_MOL | DS_DPR | DS_RDY | - ((uptr->flags & UNIT_WPRT)? DS_WRL: 0); - update_rpcs (CS1_SC, drv); - return SCPE_OK; - } -rpds[drv] = (rpds[drv] & ~DS_PIP) | DS_RDY; /* change drive status */ - -switch (uptr->FUNC) { /* case on function */ - - case FNC_OFFSET: /* offset */ - rpds[drv] = rpds[drv] | DS_OF | DS_ATA; /* set offset, attention */ - update_rpcs (CS1_SC, drv); - break; - - case FNC_RETURN: /* return to centerline */ - rpds[drv] = (rpds[drv] & ~DS_OF) | DS_ATA; /* clear offset, set attn */ - update_rpcs (CS1_SC, drv); - break; - - case FNC_UNLOAD: /* unload */ - rp_detach (uptr); /* detach unit */ - rpds[drv] &= ~DS_ATA; /* Unload does not interrupt */ - update_rpcs (0, drv); - break; - - case FNC_RECAL: /* recalibrate */ - case FNC_SEARCH: /* search */ - case FNC_SEEK: /* seek */ - rpds[drv] = rpds[drv] | DS_ATA; /* set attention */ - update_rpcs (CS1_SC, drv); - break; - -/* Reads and writes must take into account the complicated relationship - between Unibus addresses and PDP-10 memory addresses, and Unibus - byte and word counts, PDP-10 UBA word counts, and simulator PDP-10 - word counts (due to the fact that the simulator must transfer eight - 8b bytes to do a 36b transfer, whereas the UBA did four 9b bytes). -*/ - -#define XWC_MBZ 0000001 /* wc<0> must be 0 */ -#define XBA_MBZ 0000003 /* addr<1:0> must be 0 */ - - case FNC_WRITE: /* write */ - if (uptr->flags & UNIT_WPRT) { /* write locked? */ - set_rper (ER1_WLE, drv); /* set drive error */ - update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */ - break; - } /* fall through */ - case FNC_WCHK: /* write check */ - case FNC_READ: /* read */ - case FNC_READH: /* read headers */ - ba = GET_UAE (rpcs1) | rpba; /* get byte addr */ - wc10 = (0200000 - rpwc) >> 1; /* get PDP-10 wc */ - da = GET_DA (rpdc[drv], rpda[drv], dtype) * RP_NUMWD; /* get disk addr */ - if ((da + wc10) > drv_tab[dtype].size) { /* disk overrun? */ - set_rper (ER1_AOE, drv); - if (wc10 > (drv_tab[dtype].size - da)) - wc10 = drv_tab[dtype].size - da; - } - - err = fseek (uptr->fileref, da * sizeof (d10), SEEK_SET); - if (uptr->FUNC == FNC_WRITE) { /* write? */ - for (twc10 = 0; twc10 < wc10; twc10++) { - pa10 = ba >> 2; - vpn = PAG_GETVPN (pa10); /* map addr */ - if ((vpn >= UMAP_MEMSIZE) || (ba & XBA_MBZ) || (rpwc & XWC_MBZ) || - ((ubmap[0][vpn] & (UMAP_VLD | UMAP_DSB | UMAP_RRV)) != UMAP_VLD)) { - rpcs2 = rpcs2 | CS2_NEM; /* set error */ - ubcs[0] = ubcs[0] | UBCS_TMO; /* UBA times out */ - break; - } - mpa10 = (ubmap[0][vpn] + PAG_GETOFF (pa10)) & PAMASK; - if (MEM_ADDR_NXM (mpa10)) { /* nx memory? */ - rpcs2 = rpcs2 | CS2_NEM; /* set error */ - ubcs[0] = ubcs[0] | UBCS_TMO; /* UBA times out */ - break; - } - dbuf[twc10] = M[mpa10]; /* write to disk */ - if ((rpcs2 & CS2_UAI) == 0) - ba = ba + 4; - } - if ((fc10 = twc10 & (RP_NUMWD - 1))) { /* fill? */ - fc10 = RP_NUMWD - fc10; - for (i = 0; i < fc10; i++) - dbuf[twc10 + i] = 0; - } - fxwrite (dbuf, sizeof (d10), twc10 + fc10, uptr->fileref); - err = ferror (uptr->fileref); - } /* end if */ - else { /* read, wchk, readh */ - awc10 = fxread (dbuf, sizeof (d10), wc10, uptr->fileref); - err = ferror (uptr->fileref); - for ( ; awc10 < wc10; awc10++) - dbuf[awc10] = 0; - for (twc10 = 0; twc10 < wc10; twc10++) { - pa10 = ba >> 2; - vpn = PAG_GETVPN (pa10); /* map addr */ - if ((vpn >= UMAP_MEMSIZE) || (ba & XBA_MBZ) || (rpwc & XWC_MBZ) || - ((ubmap[0][vpn] & (UMAP_VLD | UMAP_DSB | UMAP_RRV)) != UMAP_VLD)) { - rpcs2 = rpcs2 | CS2_NEM; /* set error */ - ubcs[0] = ubcs[0] | UBCS_TMO; /* UBA times out */ - break; - } - mpa10 = (ubmap[0][vpn] + PAG_GETOFF (pa10)) & PAMASK; - if (MEM_ADDR_NXM (mpa10)) { /* nx memory? */ - rpcs2 = rpcs2 | CS2_NEM; /* set error */ - ubcs[0] = ubcs[0] | UBCS_TMO; /* UBA times out */ - break; - } - if ((uptr->FUNC == FNC_READ) || /* read or */ - (uptr->FUNC == FNC_READH)) /* read header */ - M[mpa10] = dbuf[twc10]; - else if (M[mpa10] != dbuf[twc10]) { /* wchk, mismatch? */ - rpcs2 = rpcs2 | CS2_WCE; /* set error */ - break; - } - if ((rpcs2 & CS2_UAI) == 0) - ba = ba + 4; - } - } /* end else */ - - rpwc = (rpwc + (twc10 << 1)) & 0177777; /* final word count */ - rpba = (ba & 0177777) & ~BA_MBZ; /* lower 16b */ - rpcs1 = (rpcs1 & ~ CS1_UAE) | ((ba >> (16 - CS1_V_UAE)) & CS1_UAE); - da = da + twc10 + (RP_NUMWD - 1); - if (da >= drv_tab[dtype].size) - rpds[drv] = rpds[drv] | DS_LST; - da = da / RP_NUMWD; - rpda[drv] = (uint16)(da % drv_tab[dtype].sect); - da = da / drv_tab[dtype].sect; - rpda[drv] = (uint16)(rpda[drv] | ((da % drv_tab[dtype].surf) << DA_V_SF)); - rpdc[drv] = (uint16)(da / drv_tab[dtype].surf); - - if (err != 0) { /* error? */ - set_rper (ER1_PAR, drv); /* set drive error */ - update_rpcs (CS1_DONE | CS1_TRE, drv); /* set done, err */ - perror ("RP I/O error"); - clearerr (uptr->fileref); - return SCPE_IOERR; - } - - case FNC_WRITEH: /* write headers stub */ - update_rpcs (CS1_DONE, drv); /* set done */ - break; - } /* end case func */ - -return SCPE_OK; -} - -/* Set drive error */ - -void set_rper (int16 flag, int32 drv) -{ -rper1[drv] = rper1[drv] | flag; -rpds[drv] = rpds[drv] | DS_ATA; -rpcs1 = rpcs1 | CS1_SC; -return; -} - -/* Controller status update - - Check for done transition - Update drive status - Update RPCS1 - Update interrupt request -*/ - -void update_rpcs (int32 flag, int32 drv) -{ -int32 i; -UNIT *uptr; - -if ((flag & ~rpcs1) & CS1_DONE) /* DONE 0 to 1? */ - rpiff = (rpcs1 & CS1_IE)? 1: 0; /* CSTB INTR <- IE */ -uptr = rp_dev.units + drv; /* get unit */ -if (rp_unit[drv].flags & UNIT_DIS) - rpds[drv] = rper1[drv] = 0; -else rpds[drv] = (rpds[drv] | DS_DPR) & ~DS_PGM; -if (rp_unit[drv].flags & UNIT_UTS) - rpds[drv] = rpds[drv] | DS_MOL; -else rpds[drv] = rpds[drv] & ~(DS_MOL | DS_VV | DS_RDY); -if (rper1[drv] | rper2[drv] | rper3[drv]) - rpds[drv] = rpds[drv] | DS_ERR; -else rpds[drv] = rpds[drv] & ~DS_ERR; - -rpcs1 = (rpcs1 & ~(CS1_SC | CS1_MCPE | CS1_MBZ | CS1_DRV)) | CS1_DVA | flag; -rpcs1 = rpcs1 | (uptr->FUNC << CS1_V_FNC); -if (sim_is_active (uptr) && (uptr->flags & UNIT_UTS)) - rpcs1 = rpcs1 | CS1_GO; -if (rpcs2 & CS2_ERR) - rpcs1 = rpcs1 | CS1_TRE | CS1_SC; -else if (rpcs1 & CS1_TRE) - rpcs1 = rpcs1 | CS1_SC; -for (i = 0; i < RP_NUMDR; i++) { - if (rpds[i] & DS_ATA) { - rpcs1 = rpcs1 | CS1_SC; - break; - } - } -if (rpiff || ((rpcs1 & CS1_SC) && (rpcs1 & CS1_DONE) && (rpcs1 & CS1_IE))) - int_req = int_req | INT_RP; -else int_req = int_req & ~INT_RP; -return; -} - -/* Interrupt acknowledge */ - -int32 rp_inta (void) -{ -rpcs1 = rpcs1 & ~CS1_IE; /* clear int enable */ -rpiff = 0; /* clear CSTB INTR */ -return VEC_RP; /* acknowledge */ -} - -/* Device reset */ - -t_stat rp_reset (DEVICE *dptr) -{ -int32 i; -UNIT *uptr; - -rpcs1 = CS1_DVA | CS1_DONE; -rpcs2 = CS2_IR | CS2_OR; -rpba = rpwc = 0; -rpiff = 0; /* clear CSTB INTR */ -int_req = int_req & ~INT_RP; /* clear intr req */ -for (i = 0; i < RP_NUMDR; i++) { - uptr = rp_dev.units + i; - uptr->CYL = uptr->FUNC = 0; - if (uptr->flags & UNIT_ATT) - if (uptr->flags & UNIT_UTS) { - sim_cancel (uptr); - rpds[i] = (rpds[i] & DS_VV) | DS_DPR | DS_RDY | DS_MOL | - ((uptr->flags & UNIT_WPRT)? DS_WRL: 0); - } else { - if (!sim_is_active (uptr)) - sim_activate (uptr, SPINUP_DLY); - rpds[i] = DS_DPR | ((uptr->flags & UNIT_WPRT)? DS_WRL: 0); - } - else { - sim_cancel (uptr); - if (uptr->flags & UNIT_DIS) - rpds[i] = 0; - else rpds[i] = DS_DPR; - } - rper1[i] = 0; - rper2[i] = 0; - rper3[i] = 0; - rpda[i] = 0; - rpdc[i] = 0; - rpmr[i] = 0; - rpof[i] = 0; - rpec1[i] = 0; - rpec2[i] = 0; - rmmr2[i] = 0; - rmhr[i] = 0; - } -return SCPE_OK; -} - -/* Device attach */ - -t_stat rp_attach (UNIT *uptr, char *cptr) -{ -int32 i, p; -t_stat r; - -uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size; -r = attach_unit (uptr, cptr); -if (r != SCPE_OK) - return r; -sim_cancel (uptr); -uptr->flags &= ~UNIT_UTS; -sim_activate (uptr, SPINUP_DLY); -if ((uptr->flags & UNIT_AUTO) == 0) /* autosize? */ - return SCPE_OK; -if ((p = sim_fsize (uptr->fileref)) == 0) - return SCPE_OK; -for (i = 0; drv_tab[i].sect != 0; i++) { - if (p <= (drv_tab[i].size * (int) sizeof (d10))) { - uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE); - uptr->capac = drv_tab[i].size; - return SCPE_OK; - } - } -/* File is larger than max known disk. This should probably fail. */ -return SCPE_OK; -} - -/* Device detach */ - -t_stat rp_detach (UNIT *uptr) -{ -int32 drv; - -if (!(uptr->flags & UNIT_ATT)) /* attached? */ - return SCPE_OK; -drv = (int32) (uptr - rp_dev.units); /* get drv number */ -rpds[drv] = (rpds[drv] & ~(DS_MOL | DS_RDY | DS_WRL | DS_VV | DS_OF)) | - DS_ATA; -if (sim_is_active (uptr)) { /* unit active? */ - sim_cancel (uptr); /* cancel operation */ - if (uptr->flags & UNIT_UTS) { - rper1[drv] = rper1[drv] | ER1_OPI; /* set drive error */ - if (uptr->FUNC >= FNC_WCHK) /* data transfer? */ - rpcs1 = rpcs1 | CS1_DONE | CS1_TRE; /* set done, err */ - } - } -uptr->flags &= ~UNIT_UTS; -update_rpcs (0, drv); /* request intr */ -return detach_unit (uptr); -} - -/* Set size command validation routine */ - -t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 dtype = GET_DTYPE (val); - -if (uptr->flags & UNIT_ATT) - return SCPE_ALATT; -uptr->capac = drv_tab[dtype].size; -return SCPE_OK; -} - -/* Device bootstrap - * The DEC and ITS versions are word-for-word identical, except that - * the DEC RDIO/WRIO are replaced by IORDQ and IOWRQ. This is hand - * assembled code, so please always make changes in both. - * Due to a typo in the KS Console rom, block 010 is read for the - * alternate HOM block. The correct block is 012. For compatibiliy, - * we will do what the hardware did first, what's right if it fails (as it will). - */ - -#define BOOT_START 0377000 /* start */ -#define BOOT_LEN (sizeof (boot_rom_dec) / sizeof (d10)) - -static const d10 boot_rom_dec[] = { - INT64_C(0510040000000)+FE_RHBASE, /* boot:hllz 1,FE_RHBASE ; uba # */ - INT64_C(0201000140001), /* movei 0,140001 ; vld,fst,pg 1 */ - INT64_C(0713001000000)+((IOBA_UBMAP+1) & RMASK), /* wrio 0,763001(1); set ubmap */ - INT64_C(0200040000000)+FE_RHBASE, /* move 1,FE_RHBASE */ - INT64_C(0201000000040), /* movei 0,40 ; ctrl reset */ - INT64_C(0713001000010), /* wrio 0,10(1) ; ->RPCS2 */ - INT64_C(0200240000000)+FE_UNIT, /* move 5,FE_UNIT ; unit */ - INT64_C(0713241000010), /* wrio 5,10(1) ; select ->RPCS2 */ - - INT64_C(0712001000012), /*10 rdio 0,12(1) ; RPDS */ - INT64_C(0640000010600), /* trc 0,10600 ; MOL + DPR + RDY */ - INT64_C(0642000010600), /* trce 0,10600 ; */ - INT64_C(0254000377010), /* jrst .-3 ; wait */ - INT64_C(0201000000377), /* movei 0,377 ; All units */ - INT64_C(0713001000016), /* wrio 0,16(1) ; Clear on-line attns */ - INT64_C(0201000000021), /* movei 0,21 ; preset */ - INT64_C(0713001000000), /* wrio 0,0(1) ; ->RPCS1 */ - - INT64_C(0201100000001), /*20 movei 2,1 ; blk #1 */ - INT64_C(0265740377041), /* jsp 17,rdbl ; read */ - INT64_C(0204140001000), /* movs 3,1000 ; id word */ - INT64_C(0306140505755), /* cain 3,sixbit /HOM/ */ - INT64_C(0254000377032), /* jrst pg ; match */ - INT64_C(0201100000010), /* movei 2,10 ; blk #10 */ - INT64_C(0265740377041), /* jsp 17,rdbl ; read */ - INT64_C(0204140001000), /* movs 3,1000 ; id word */ - - INT64_C(0302140505755), /*30 caie 3,sixbit /HOM/ */ - INT64_C(0254000377061), /* jrst alt2 ; inv home */ - INT64_C(0336100001103), /* pg: skipn 2,1103 ; pg of ptrs */ - INT64_C(0254200377033), /* halt . ; inv ptr */ - INT64_C(0265740377041), /* jsp 17,rdbl ; read */ - INT64_C(0336100001004), /* skipn 2,1004 ; mon boot */ - INT64_C(0254200377036), /* halt . ; inv ptr */ - INT64_C(0265740377041), /* jsp 17,rdbl ; read */ - - INT64_C(0254000001000), /*40 jrst 1000 ; start */ - INT64_C(0201140176000), /* rdbl:movei 3,176000 ; wd cnt 1P = -512*2 */ - INT64_C(0201200004000), /* movei 4,4000 ; 11 addr => M[1000] */ - INT64_C(0200300000002), /* move 6,2 */ - INT64_C(0242300777750), /* lsh 6,-24. ; cyl */ - INT64_C(0713141000002), /* wrio 3,2(1) ; ->RPWC */ - INT64_C(0713201000004), /* wrio 4,4(1) ; ->RPBA */ - INT64_C(0713101000006), /* wrio 2,6(1) ; ->RPDA */ - - INT64_C(0713301000034), /*50 wrio 6,34(1) ; ->RPDC */ - INT64_C(0201000000071), /* movei 0,71 ; read+go */ - INT64_C(0713001000000), /* wrio 0,0(1) ; ->RPCS1 */ - INT64_C(0712341000000), /* rdio 7,0(1) ; read csr */ - INT64_C(0606340000200), /* trnn 7,200 ; test rdy */ - INT64_C(0254000377053), /* jrst .-2 ; loop */ - INT64_C(0602340100000), /* trne 7,100000 ; test err */ - INT64_C(0254200377057), /* halt . */ - - INT64_C(0254017000000), /*60 jrst 0(17) ; return */ - INT64_C(0201100000012), /*alt2: movei 2,10. ; blk #10. */ - INT64_C(0265740377041), /* jsp 17,rdbl ; read */ - INT64_C(0204140001000), /* movs 3,1000 ; id word */ - INT64_C(0302140505755), /* caie 3,sixbit /HOM/ */ - INT64_C(0254200377065), /* halt . ; inv home */ - INT64_C(0254000377032), /* jrst pg ; Read ptrs */ - }; - -static const d10 boot_rom_its[] = { - INT64_C(0510040000001)+FE_RHBASE, /* boot:hllzi 1,FE_RHBASE ; uba # */ - INT64_C(0201000140001), /* movei 0,140001 ; vld,fst,pg 1 */ - INT64_C(0715000000000)+((IOBA_UBMAP+1) & RMASK), /* iowrq 0,763001 ; set ubmap */ - INT64_C(0200040000000)+FE_RHBASE, /* move 1,FE_RHBASE */ - INT64_C(0201000000040), /* movei 0,40 ; ctrl reset */ - INT64_C(0715001000010), /* iowrq 0,10(1) ; ->RPCS2 */ - INT64_C(0200240000000)+FE_UNIT, /* move 5,FE_UNIT ; unit */ - INT64_C(0715241000010), /* iowrq 5,10(1) ; ->RPCS2 */ - - INT64_C(0711001000012), /*10 iordq 0,12(1) ; RPDS */ - INT64_C(0640000010600), /* trc 0,10600 ; MOL + DPR + RDY */ - INT64_C(0642000010600), /* trce 0,10600 ; */ - INT64_C(0254000377010), /* jrst .-3 ; wait */ - INT64_C(0201000000377), /* movei 0,377 ; All units */ - INT64_C(0715001000016), /* iowrq 0,16(1) ; Clear on-line attns */ - INT64_C(0201000000021), /* movei 0,21 ; preset */ - INT64_C(0715001000000), /* iowrq 0,0(1) ; ->RPCS1 */ - - INT64_C(0201100000001), /*20 movei 2,1 ; blk #1 */ - INT64_C(0265740377041), /* jsp 17,rdbl ; read */ - INT64_C(0204140001000), /* movs 3,1000 ; id word */ - INT64_C(0306140505755), /* cain 3,sixbit /HOM/ */ - INT64_C(0254000377032), /* jrst pg ; match */ - INT64_C(0201100000010), /* movei 2,10 ; blk #10 */ - INT64_C(0265740377041), /* jsp 17,rdbl ; read */ - INT64_C(0204140001000), /* movs 3,1000 ; id word */ - - INT64_C(0302140505755), /*30 caie 3,sixbit /HOM/ */ - INT64_C(0254000377061), /* jrst alt2 ; inv home */ - INT64_C(0336100001103), /* pg: skipn 2,1103 ; pg of ptrs */ - INT64_C(0254200377033), /* halt . ; inv ptr */ - INT64_C(0265740377041), /* jsp 17,rdbl ; read */ - INT64_C(0336100001004), /* skipn 2,1004 ; mon boot */ - INT64_C(0254200377036), /* halt . ; inv ptr */ - INT64_C(0265740377041), /* jsp 17,rdbl ; read */ - - INT64_C(0254000001000), /*40 jrst 1000 ; start */ - INT64_C(0201140176000), /* rdbl:movei 3,176000 ; wd cnt 1P = -512 *2 */ - INT64_C(0201200004000), /* movei 4,4000 ; addr */ - INT64_C(0200300000002), /* move 6,2 */ - INT64_C(0242300777750), /* lsh 6,-24. ; cyl */ - INT64_C(0715141000002), /* iowrq 3,2(1) ; ->RPWC */ - INT64_C(0715201000004), /* iowrq 4,4(1) ; ->RPBA */ - INT64_C(0715101000006), /* iowrq 2,6(1) ; ->RPDA */ - - INT64_C(0715301000034), /*50 iowrq 6,34(1) ; ->RPDC */ - INT64_C(0201000000071), /* movei 0,71 ; read+go */ - INT64_C(0715001000000), /* iowrq 0,0(1) ; ->RPCS1 */ - INT64_C(0711341000000), /* iordq 7,0(1) ; read csr */ - INT64_C(0606340000200), /* trnn 7,200 ; test rdy */ - INT64_C(0254000377053), /* jrst .-2 ; loop */ - INT64_C(0602340100000), /* trne 7,100000 ; test err */ - INT64_C(0254200377057), /* halt */ - - INT64_C(0254017000000), /*60 jrst 0(17) ; return */ - INT64_C(0201100000012), /* alt2:movei 2,10. ; blk #10. */ - INT64_C(0265740377041), /* jsp 17,rdbl ; read */ - INT64_C(0204140001000), /* movs 3,1000 ; id word */ - INT64_C(0302140505755), /* caie 3,sixbit /HOM/ */ - INT64_C(0254200377065), /* halt . ; inv home */ - INT64_C(0254000377032), /* jrst pg ; Read ptrs */ - }; - -t_stat rp_boot (int32 unitno, DEVICE *dptr) -{ -size_t i; -extern a10 saved_PC; -UNIT *uptr; - -unitno &= CS2_M_UNIT; -uptr = rp_dev.units + unitno; -if (!(uptr->flags & UNIT_ATT)) - return SCPE_NOATT; - -M[FE_RHBASE] = fe_bootrh = rp_dib.ba; -M[FE_UNIT] = fe_bootunit = unitno; - -assert (sizeof(boot_rom_dec) == sizeof(boot_rom_its)); - -M[FE_KEEPA] = (M[FE_KEEPA] & ~INT64_C(0xFF)) | ((sim_switches & SWMASK ('A'))? 010 : 0); - -for (i = 0; i < BOOT_LEN; i++) - M[BOOT_START + i] = Q_ITS? boot_rom_its[i]: boot_rom_dec[i]; -saved_PC = BOOT_START; -return SCPE_OK; -} diff --git a/PDP10/pdp10_sys.c b/PDP10/pdp10_sys.c deleted file mode 100644 index 5f4239c0..00000000 --- a/PDP10/pdp10_sys.c +++ /dev/null @@ -1,960 +0,0 @@ -/* pdp10_sys.c: PDP-10 simulator interface - - Copyright (c) 1993-2017, 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. - - 09-Mar-17 RMS Added mask on EXE repeat count (COVERITY) - Fixed word count test in EXE loader (COVERITY) - 20-Jan-17 RMS Fixed RIM loader to handle ITS and RIM10B formats - 04-Apr-11 RMS Removed DEUNA/DELUA support - never implemented - 01-Feb-07 RMS Added CD support - 22-Jul-05 RMS Fixed warning from Solaris C (from Doug Gwyn) - 09-Jan-03 RMS Added DEUNA/DELUA support - 12-Sep-02 RMS Added RX211 support - 22-Apr-02 RMS Removed magtape record length error - 17-Sep-01 RMS Removed multiconsole support - 25-Aug-01 RMS Enabled DZ11 - 27-May-01 RMS Added multiconsole support - 29-Apr-01 RMS Fixed format for RDPCST, WRPCST - Added CLRCSH for ITS - 03-Apr-01 RMS Added support for loading EXE files - 19-Mar-01 RMS Added support for loading SAV files - 30-Oct-00 RMS Added support for examine to file -*/ - -#include "pdp10_defs.h" -#include - -extern DEVICE cpu_dev; -extern DEVICE pag_dev; -extern DEVICE tim_dev; -extern DEVICE fe_dev; -extern DEVICE uba_dev; -extern DEVICE ptr_dev; -extern DEVICE ptp_dev; -extern DEVICE rp_dev; -extern DEVICE tu_dev; -extern DEVICE dz_dev; -extern DEVICE ry_dev; -extern DEVICE cr_dev; -extern DEVICE lp20_dev; -extern UNIT cpu_unit; -extern REG cpu_reg[]; -extern d10 *M; -extern a10 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[] = "PDP-10"; - -REG *sim_PC = &cpu_reg[0]; - -int32 sim_emax = 1; - -DEVICE *sim_devices[] = { - &cpu_dev, - &pag_dev, - &tim_dev, - &fe_dev, - &uba_dev, - &ptr_dev, - &ptp_dev, - &ry_dev, - &lp20_dev, - &cr_dev, - &rp_dev, - &tu_dev, - &dz_dev, - NULL - }; - -const char *sim_stop_messages[] = { - "Unknown error", - "HALT instruction", - "Breakpoint", - "Illegal instruction", - "Illegal interrupt instruction", - "Paging error in interrupt", - "Zero vector table", - "NXM on UPT/EPT reference", - "Nested indirect address limit exceeded", - "Nested XCT limit exceeded", - "Invalid I/O controller", - "Address stop", - "Console FE halt", - "Unaligned DMA", - "Panic stop" - }; - -/* Binary loader, supports RIM10, SAV, EXE */ - -#define FMT_R 1 /* RIM10 */ -#define FMT_S 2 /* SAV */ -#define FMT_E 3 /* EXE */ - -#define EXE_DIR 01776 /* EXE directory */ -#define EXE_VEC 01775 /* EXE entry vec */ -#define EXE_PDV 01774 /* EXE ignored */ -#define EXE_END 01777 /* EXE end */ - -/* RIM10B loader - - RIM10B format is a binary paper tape format (all data frames - are 200 or greater). It consists of blocks containing - - -count,,origin-1 - word - : - word - checksum (includes IOWD) - : - JRST start - - The checksum is the simple binary sum of all the words in - the block, including the IOWD. - - ITS RIM format is a binary paper tape format (all data frames - are 200 or greater). It consists of blocks containing - - -count,,origin - word - : - word - checksum (includes pseudo IOWD) - : - JRST start - - The checksum is the simple binary sum of all the words in - the block, including the pseudo IOWD. The checksum is rotated - left by 1 before each new word is added in. - - Both formats include the actual RIM loader as the first block. - It begins with a BLKI word: -count,,start-1. The count is 16(8) - for RIM10B and 17(8) for ITS RIM. On a real KA10 or KI10, this - twisty little program is loaded into the ACs and executed. - Here it is simply skipped. -*/ - -d10 getrimw (FILE *fileref) -{ -int32 i, tmp; -d10 word; - -word = 0; -for (i = 0; i < 6;) { - if ((tmp = getc (fileref)) == EOF) - return -1; - if (tmp & 0200) { - word = (word << 6) | ((d10) tmp & 077); - i++; - } - } -return word; -} - -t_stat load_rim (FILE *fileref) -{ -d10 count, cksm, data; -a10 pa; -int32 op, i, ldrc; -t_bool its_rim; -extern d10 rot (d10 val, a10 ea); - -data = getrimw (fileref); /* get first word */ -if ((data < 0) || ((data & AMASK) != 0)) /* error? SA != 0? */ - return SCPE_FMT; -ldrc = 01000000 - ((int32) (LRZ (data))); /* get loader count */ -if (ldrc == 016) /* 16? RIM10B */ - its_rim = FALSE; -else if (ldrc == 017) /* 17? ITS RIM */ - its_rim = TRUE; -else return SCPE_FMT; /* unknown */ - -for (i = 0; i < ldrc; i++) { /* skip the loader */ - data = getrimw (fileref); - if (data < 0) - return SCPE_FMT; - } - -for ( ;; ) { /* loop until JRST */ - count = cksm = getrimw (fileref); /* get header */ - if (count < 0) /* read err? */ - return SCPE_FMT; - if (TSTS (count)) { /* hdr = IOWD? */ - for ( ; TSTS (count); count = AOB (count)) { - data = getrimw (fileref); /* get data wd */ - if (data < 0) - return SCPE_FMT; - if (its_rim) { /* ITS RIM? */ - cksm = (rot (cksm, 1) + data) & DMASK; /* add to rotated cksm */ - pa = ((a10) count) & AMASK; /* store */ - } - else { /* RIM10B */ - cksm = (cksm + data) & DMASK; /* add to cksm */ - pa = ((a10) count + 1) & AMASK; /* store */ - } - M[pa] = data; - } /* end for */ - data = getrimw (fileref); /* get cksm */ - if (data < 0) - return SCPE_FMT; - if (cksm != data) /* test cksm */ - return SCPE_CSUM; - } /* end if count */ - else { - op = GET_OP (count); /* not IOWD */ - if (op != OP_JRST) /* JRST? */ - return SCPE_FMT; - saved_PC = (a10) count & AMASK; /* set PC */ - break; - } /* end else */ - } /* end for */ -return SCPE_OK; -} - -/* SAV file loader - - SAV format is a disk file format (36b words). It consists of - blocks containing: - - -count,,origin-1 - word - : - word - : - JRST start -*/ - -t_stat load_sav (FILE *fileref) -{ -d10 count, data; -a10 pa; -int32 wc, op; - -for ( ;; ) { /* loop */ - wc = fxread (&count, sizeof (d10), 1, fileref); /* read IOWD */ - if (wc == 0) /* done? */ - return SCPE_OK; - if (TSTS (count)) { /* IOWD? */ - for ( ; TSTS (count); count = AOB (count)) { - wc = fxread (&data, sizeof (d10), 1, fileref); - if (wc == 0) - return SCPE_FMT; - pa = ((a10) count + 1) & AMASK; /* store data */ - M[pa] = data; - } /* end for */ - } /* end if count*/ - else { - op = GET_OP (count); /* not IOWD */ - if (op != OP_JRST) /* JRST? */ - return SCPE_FMT; - saved_PC = (a10) count & AMASK; /* set PC */ - break; - } /* end else */ - } /* end for */ -return SCPE_OK; -} - -/* EXE file loader - - EXE format is a disk file format (36b words). It consists of - blocks containing: - - block type,,total words = n - n - 1 data words - - Block types are - - EXE_DIR (1776) directory - EXE_VEC (1775) entry vector - EXE_PDV (1774) optional blocks - EXE_END (1777) end block - - The directory blocks are the most important and contain doubleword - page loading information: - - word0<0:8> = flags - <9:35> = page in file (0 if 0 page) - word1<0:8> = repeat count - 1 - <9:35> = page in memory -*/ - -#define DIRSIZ (2 * PAG_SIZE) - -t_stat load_exe (FILE *fileref) -{ -d10 data, dirbuf[DIRSIZ], pagbuf[PAG_SIZE], entbuf[2]; -int32 ndir, entvec, i, j, k, cont, bsz, bty, rpt, wc; -int32 fpage, mpage; -a10 ma; - -ndir = entvec = 0; /* no dir, entvec */ -cont = 1; -do { - wc = fxread (&data, sizeof (d10), 1, fileref); /* read blk hdr */ - if (wc == 0) /* error? */ - return SCPE_FMT; - bsz = (int32) ((data & RMASK) - 1); /* get count */ - if (bsz < 0) /* zero? */ - return SCPE_FMT; - bty = (int32) LRZ (data); /* get type */ - switch (bty) { /* case type */ - - case EXE_DIR: /* directory */ - if (ndir != 0) /* got one */ - return SCPE_FMT; - ndir = fxread (dirbuf, sizeof (d10), bsz, fileref); - if (ndir < bsz) /* error */ - return SCPE_FMT; - break; - - case EXE_PDV: /* optional */ - fseek (fileref, bsz * sizeof (d10), SEEK_CUR); /* skip data */ - break; - - case EXE_VEC: /* entry vec */ - if (bsz != 2) /* must be 2 wds */ - return SCPE_FMT; - entvec = fxread (entbuf, sizeof (d10), bsz, fileref); - if (entvec < 2) /* error? */ - return SCPE_FMT; - cont = 0; /* stop */ - break; - - case EXE_END: /* end */ - if (bsz != 0) /* must be hdr */ - return SCPE_FMT; - cont = 0; /* stop */ - break; - - default: - return SCPE_FMT; - } /* end switch */ - } while (cont); /* end do */ - -for (i = 0; i < ndir; i = i + 2) { /* loop thru dir */ - fpage = (int32) (dirbuf[i] & RMASK); /* file page */ - mpage = (int32) (dirbuf[i + 1] & RMASK); /* memory page */ - rpt = ((int32) ((dirbuf[i + 1] >> 27) + 1)) & 0777; /* repeat count */ - for (j = 0; j < rpt; j++, mpage++) { /* loop thru rpts */ - if (fpage) { /* file pages? */ - fseek (fileref, (fpage << PAG_V_PN) * sizeof (d10), SEEK_SET); - wc = fxread (pagbuf, sizeof (d10), PAG_SIZE, fileref); - if (wc < PAG_SIZE) - return SCPE_FMT; - fpage++; - } - ma = mpage << PAG_V_PN; /* mem addr */ - for (k = 0; k < PAG_SIZE; k++, ma++) { /* copy buf to mem */ - if (MEM_ADDR_NXM (ma)) - return SCPE_NXM; - M[ma] = fpage? (pagbuf[k] & DMASK): 0; - } /* end copy */ - } /* end rpt */ - } /* end directory */ -if (entvec && entbuf[1]) - saved_PC = (int32) (entbuf[1] & RMASK); /* start addr */ -return SCPE_OK; -} - -/* Master loader */ - -t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) -{ -d10 data; -int32 wc, fmt; - -fmt = 0; /* no fmt */ -if (sim_switches & SWMASK ('R')) /* -r? */ - fmt = FMT_R; -else if (sim_switches & SWMASK ('S')) /* -s? */ - fmt = FMT_S; -else if (sim_switches & SWMASK ('E')) /* -e? */ - fmt = FMT_E; -else if (match_ext (fnam, "RIM")) /* .RIM? */ - fmt = FMT_R; -else if (match_ext (fnam, "SAV")) /* .SAV? */ - fmt = FMT_S; -else if (match_ext (fnam, "EXE")) /* .EXE? */ - fmt = FMT_E; -else { - wc = fxread (&data, sizeof (d10), 1, fileref); /* read hdr */ - if (wc == 0) /* error? */ - return SCPE_FMT; - if (LRZ (data) == EXE_DIR) /* EXE magic? */ - fmt = FMT_E; - else if (TSTS (data)) { /* SAV/RIM magic? */ - if ((data & AMASK) != 0) /* SAV has SA != 0 */ - fmt = FMT_S; - else fmt = FMT_R; /* RIM has SA == 0 */ - } - fseek (fileref, 0, SEEK_SET); /* rewind */ - } - -switch (fmt) { /* case fmt */ - - case FMT_R: /* RIM */ - return load_rim (fileref); - - case FMT_S: /* SAV */ - return load_sav (fileref); - - case FMT_E: /* EXE */ - return load_exe (fileref); - } - -sim_printf ("Can't determine load file format\n"); -return SCPE_FMT; -} - -/* Symbol tables */ - -#define I_V_FL 39 /* inst class */ -#define I_M_FL 03 /* class mask */ -#define I_ITS INT64_C(004000000000000) /* ITS flag */ -#define I_AC INT64_C(000000000000000) /* AC, address */ -#define I_OP INT64_C(010000000000000) /* address only */ -#define I_IO INT64_C(020000000000000) /* classic I/O */ -#define I_V_AC 00 -#define I_V_OP 01 -#define I_V_IO 02 - -static const d10 masks[] = { - INT64_C(0777000000000), INT64_C(0777740000000), - INT64_C(0700340000000), INT64_C(0777777777777) - }; - -static const char *opcode[] = { -"XCTR", "XCTI", /* ITS only */ -"IORDI", "IORDQ", "IORD", "IOWR", "IOWRI", "IOWRQ", -"IORDBI", "IORDBQ", "IORDB", "IOWRB", "IOWRBI", "IOWRBQ", -"CLRCSH", "RDPCST", "WRPCST", -"SDBR1", "SDBR2", "SDBR3", "SDBR4", "SPM", -"LDBR1", "LDBR2", "LDBR3", "LDBR4", "LPMR", - -"PORTAL", "JRSTF", "HALT", /* AC defines op */ -"XJRSTF", "XJEN", "XPCW", -"JEN", "SFM", "XJRST", "IBP", -"JFOV", "JCRY1", "JCRY0", "JCRY", "JOV", - -"APRID", "WRAPR", "RDAPR", "WRPI", "RDPI", "RDUBR", "CLRPT", "WRUBR", -"WREBR", "RDEBR", -"RDSPB", "RDCSB", "RDPUR", "RDCSTM", "RDTIM", "RDINT", "RDHSB", -"WRSPB", "WRCSB", "WRPUR", "WRCSTM", "WRTIM", "WRINT", "WRHSB", - - "LUUO01", "LUUO02", "LUUO03", "LUUO04", "LUUO05", "LUUO06", "LUUO07", -"LUUO10", "LUUO11", "LUUO12", "LUUO13", "LUUO14", "LUUO15", "LUUO16", "LUUO17", -"LUUO20", "LUUO21", "LUUO22", "LUUO23", "LUUO24", "LUUO25", "LUUO26", "LUUO27", -"LUUO30", "LUUO31", "LUUO32", "LUUO33", "LUUO34", "LUUO35", "LUUO36", "LUUO37", -"MUUO40", "MUUO41", "MUUO42", "MUUO43", "MUUO44", "MUUO45", "MUUO46", "MUUO47", -"MUUO50", "MUUO51", "MUUO52", "MUUO53", "MUUO54", "MUUO55", "MUUO56", "MUUO57", -"MUUO60", "MUUO61", "MUUO62", "MUUO63", "MUUO64", "MUUO65", "MUUO66", "MUUO67", -"MUUO70", "MUUO71", "MUUO72", "MUUO73", "MUUO74", "MUUO75", "MUUO76", "MUUO77", - -"UJEN", "GFAD", "GFSB", "JSYS", "ADJSP", "GFMP", "GFDV ", -"DFAD", "DFSB", "DFMP", "DFDV", "DADD", "DSUB", "DMUL", "DDIV", -"DMOVE", "DMOVN", "FIX", "EXTEND", "DMOVEM", "DMOVNM", "FIXR", "FLTR", -"UFA", "DFN", "FSC", "ADJBP", "ILDB", "LDB", "IDPB", "DPB", -"FAD", "FADL", "FADM", "FADB", "FADR", "FADRL", "FADRM", "FADRB", -"FSB", "FSBL", "FSBM", "FSBB", "FSBR", "FSBRL", "FSBRM", "FSBRB", -"FMP", "FMPL", "FMPM", "FMPB", "FMPR", "FMPRL", "FMPRM", "FMPRB", -"FDV", "FDVL", "FDVM", "FDVB", "FDVR", "FDVRL", "FDVRM", "FDVRB", - -"MOVE", "MOVEI", "MOVEM", "MOVES", "MOVS", "MOVSI", "MOVSM", "MOVSS", -"MOVN", "MOVNI", "MOVNM", "MOVNS", "MOVM", "MOVMI", "MOVMM", "MOVMS", -"IMUL", "IMULI", "IMULM", "IMULB", "MUL", "MULI", "MULM", "MULB", -"IDIV", "IDIVI", "IDIVM", "IDIVB", "DIV", "DIVI", "DIVM", "DIVB", -"ASH", "ROT", "LSH", "JFFO", "ASHC", "ROTC", "LSHC", "CIRC", -"EXCH", "BLT", "AOBJP", "AOBJN", "JRST", "JFCL", "XCT", "MAP", -"PUSHJ", "PUSH", "POP", "POPJ", "JSR", "JSP", "JSA", "JRA", -"ADD", "ADDI", "ADDM", "ADDB", "SUB", "SUBI", "SUBM", "SUBB", - -"CAI", "CAIL", "CAIE", "CAILE", "CAIA", "CAIGE", "CAIN", "CAIG", -"CAM", "CAML", "CAME", "CAMLE", "CAMA", "CAMGE", "CAMN", "CAMG", -"JUMP", "JUMPL", "JUMPE", "JUMPLE", "JUMPA", "JUMPGE", "JUMPN", "JUMPG", -"SKIP", "SKIPL", "SKIPE", "SKIPLE", "SKIPA", "SKIPGE", "SKIPN", "SKIPG", -"AOJ", "AOJL", "AOJE", "AOJLE", "AOJA", "AOJGE", "AOJN", "AOJG", -"AOS", "AOSL", "AOSE", "AOSLE", "AOSA", "AOSGE", "AOSN", "AOSG", -"SOJ", "SOJL", "SOJE", "SOJLE", "SOJA", "SOJGE", "SOJN", "SOJG", -"SOS", "SOSL", "SOSE", "SOSLE", "SOSA", "SOSGE", "SOSN", "SOSG", - -"SETZ", "SETZI", "SETZM", "SETZB", "AND", "ANDI", "ANDM", "ANDB", -"ANDCA", "ANDCAI", "ANDCAM", "ANDCAB", "SETM", "SETMI", "SETMM", "SETMB", -"ANDCM", "ANDCMI", "ANDCMM", "ANDCMB", "SETA", "SETAI", "SETAM", "SETAB", -"XOR", "XORI", "XORM", "XORB", "IOR", "IORI", "IORM", "IORB", -"ANDCB", "ANDCBI", "ANDCBM", "ANDCBB", "EQV", "EQVI", "EQVM", "EQVB", -"SETCA", "SETCAI", "SETCAM", "SETCAB", "ORCA", "ORCAI", "ORCAM", "ORCAB", -"SETCM", "SETCMI", "SETCMM", "SETCMB", "ORCM", "ORCMI", "ORCMM", "ORCMB", -"ORCB", "ORCBI", "ORCBM", "ORCBB", "SETO", "SETOI", "SETOM", "SETOB", - -"HLL", "HLLI", "HLLM", "HLLS", "HRL", "HRLI", "HRLM", "HRLS", -"HLLZ", "HLLZI", "HLLZM", "HLLZS", "HRLZ", "HRLZI", "HRLZM", "HRLZS", -"HLLO", "HLLOI", "HLLOM", "HLLOS", "HRLO", "HRLOI", "HRLOM", "HRLOS", -"HLLE", "HLLEI", "HLLEM", "HLLES", "HRLE", "HRLEI", "HRLEM", "HRLES", -"HRR", "HRRI", "HRRM", "HRRS", "HLR", "HLRI", "HLRM", "HLRS", -"HRRZ", "HRRZI", "HRRZM", "HRRZS", "HLRZ", "HLRZI", "HLRZM", "HLRZS", -"HRRO", "HRROI", "HRROM", "HRROS", "HLRO", "HLROI", "HLROM", "HLROS", -"HRRE", "HRREI", "HRREM", "HRRES", "HLRE", "HLREI", "HLREM", "HLRES", - -"TRN", "TLN", "TRNE", "TLNE", "TRNA", "TLNA", "TRNN", "TLNN", -"TDN", "TSN", "TDNE", "TSNE", "TDNA", "TSNA", "TDNN", "TSNN", -"TRZ", "TLZ", "TRZE", "TLZE", "TRZA", "TLZA", "TRZN", "TLZN", -"TDZ", "TSZ", "TDZE", "TSZE", "TDZA", "TSZA", "TDZN", "TSZN", -"TRC", "TLC", "TRCE", "TLCE", "TRCA", "TLCA", "TRCN", "TLCN", -"TDC", "TSC", "TDCE", "TSCE", "TDCA", "TSCA", "TDCN", "TSCN", -"TRO", "TLO", "TROE", "TLOE", "TROA", "TLOA", "TRON", "TLON", -"TDO", "TSO", "TDOE", "TSOE", "TDOA", "TSOA", "TDON", "TSON", - -"UMOVE", "UMOVEM", /* KS10 I/O */ -"TIOE", "TION", "RDIO", "WRIO", -"BSIO", "BCIO", "BLTBU", "BLTUB", -"TIOEB", "TIONB", "RDIOB", "WRIOB", -"BSIOB", "BCIOB", - -"BLKI", "DATAI", "BLKO", "DATAO", /* classic I/O */ -"CONO", "CONI", "CONSZ", "CONSO", - -"CLEAR", "CLEARI", "CLEARM", "CLEARB", -"OR", "ORI", "ORM", "ORB", "XMOVEI", "XHLLI", /* alternate ops */ - - "CMPSL", "CMPSE", "CMPSLE", /* extended ops */ -"EDIT", "CMPSGE", "CMPSN", "CMPSG", -"CVTDBO", "CVTDBT", "CVTBDO", "CVTBDT", -"MOVSO", "MOVST", "MOVSLJ", "MOVSRJ", -"XBLT", "GSNGL", "GDBLE", "GDFIX", -"GFIX", "GDFIXR", "GFIXR", "DGFLTR", -"GFLTR", "GFSC", - -NULL -}; - -static const d10 opc_val[] = { - INT64_C(0102000000000)+I_AC+I_ITS, INT64_C(0103000000000)+I_AC+I_ITS, - INT64_C(0710000000000)+I_AC+I_ITS, INT64_C(0711000000000)+I_AC+I_ITS, INT64_C(0712000000000)+I_AC+I_ITS, - INT64_C(0713000000000)+I_AC+I_ITS, INT64_C(0714000000000)+I_AC+I_ITS, INT64_C(0715000000000)+I_AC+I_ITS, - INT64_C(0720000000000)+I_AC+I_ITS, INT64_C(0721000000000)+I_AC+I_ITS, INT64_C(0722000000000)+I_AC+I_ITS, - INT64_C(0723000000000)+I_AC+I_ITS, INT64_C(0724000000000)+I_AC+I_ITS, INT64_C(0725000000000)+I_AC+I_ITS, - INT64_C(0701000000000)+I_OP+I_ITS, INT64_C(0701440000000)+I_OP+I_ITS, INT64_C(0701540000000)+I_OP+I_ITS, - INT64_C(0702000000000)+I_OP+I_ITS, INT64_C(0702040000000)+I_OP+I_ITS, - INT64_C(0702100000000)+I_OP+I_ITS, INT64_C(0702140000000)+I_OP+I_ITS, INT64_C(0702340000000)+I_OP+I_ITS, - INT64_C(0702400000000)+I_OP+I_ITS, INT64_C(0702440000000)+I_OP+I_ITS, - INT64_C(0702500000000)+I_OP+I_ITS, INT64_C(0702540000000)+I_OP+I_ITS, INT64_C(0702740000000)+I_OP+I_ITS, - - INT64_C(0254040000000)+I_OP, INT64_C(0254100000000)+I_OP, - INT64_C(0254200000000)+I_OP, INT64_C(0254240000000)+I_OP, INT64_C(0254300000000)+I_OP, INT64_C(0254340000000)+I_OP, - INT64_C(0254500000000)+I_OP, INT64_C(0254600000000)+I_OP, INT64_C(0254640000000)+I_OP, INT64_C(0133000000000)+I_OP, - INT64_C(0255040000000)+I_OP, INT64_C(0255100000000)+I_OP, INT64_C(0255200000000)+I_OP, INT64_C(0255300000000)+I_OP, - INT64_C(0255400000000)+I_OP, - - INT64_C(0700000000000)+I_OP, INT64_C(0700200000000)+I_OP, INT64_C(0700240000000)+I_OP, INT64_C(0700600000000)+I_OP, - INT64_C(0700640000000)+I_OP, INT64_C(0701040000000)+I_OP, INT64_C(0701100000000)+I_OP, INT64_C(0701140000000)+I_OP, - INT64_C(0701200000000)+I_OP, INT64_C(0701240000000)+I_OP, - INT64_C(0702000000000)+I_OP, INT64_C(0702040000000)+I_OP, INT64_C(0702100000000)+I_OP, INT64_C(0702140000000)+I_OP, - INT64_C(0702200000000)+I_OP, INT64_C(0702240000000)+I_OP, INT64_C(0702300000000)+I_OP, - INT64_C(0702400000000)+I_OP, INT64_C(0702440000000)+I_OP, INT64_C(0702500000000)+I_OP, INT64_C(0702540000000)+I_OP, - INT64_C(0702600000000)+I_OP, INT64_C(0702640000000)+I_OP, INT64_C(0702700000000)+I_OP, - - INT64_C(0001000000000)+I_AC, INT64_C(0002000000000)+I_AC, INT64_C(0003000000000)+I_AC, - INT64_C(0004000000000)+I_AC, INT64_C(0005000000000)+I_AC, INT64_C(0006000000000)+I_AC, INT64_C(0007000000000)+I_AC, - INT64_C(0010000000000)+I_AC, INT64_C(0011000000000)+I_AC, INT64_C(0012000000000)+I_AC, INT64_C(0013000000000)+I_AC, - INT64_C(0014000000000)+I_AC, INT64_C(0015000000000)+I_AC, INT64_C(0016000000000)+I_AC, INT64_C(0017000000000)+I_AC, - INT64_C(0020000000000)+I_AC, INT64_C(0021000000000)+I_AC, INT64_C(0022000000000)+I_AC, INT64_C(0023000000000)+I_AC, - INT64_C(0024000000000)+I_AC, INT64_C(0025000000000)+I_AC, INT64_C(0026000000000)+I_AC, INT64_C(0027000000000)+I_AC, - INT64_C(0030000000000)+I_AC, INT64_C(0031000000000)+I_AC, INT64_C(0032000000000)+I_AC, INT64_C(0033000000000)+I_AC, - INT64_C(0034000000000)+I_AC, INT64_C(0035000000000)+I_AC, INT64_C(0036000000000)+I_AC, INT64_C(0037000000000)+I_AC, - INT64_C(0040000000000)+I_AC, INT64_C(0041000000000)+I_AC, INT64_C(0042000000000)+I_AC, INT64_C(0043000000000)+I_AC, - INT64_C(0044000000000)+I_AC, INT64_C(0045000000000)+I_AC, INT64_C(0046000000000)+I_AC, INT64_C(0047000000000)+I_AC, - INT64_C(0050000000000)+I_AC, INT64_C(0051000000000)+I_AC, INT64_C(0052000000000)+I_AC, INT64_C(0053000000000)+I_AC, - INT64_C(0054000000000)+I_AC, INT64_C(0055000000000)+I_AC, INT64_C(0056000000000)+I_AC, INT64_C(0057000000000)+I_AC, - INT64_C(0060000000000)+I_AC, INT64_C(0061000000000)+I_AC, INT64_C(0062000000000)+I_AC, INT64_C(0063000000000)+I_AC, - INT64_C(0064000000000)+I_AC, INT64_C(0065000000000)+I_AC, INT64_C(0066000000000)+I_AC, INT64_C(0067000000000)+I_AC, - INT64_C(0070000000000)+I_AC, INT64_C(0071000000000)+I_AC, INT64_C(0072000000000)+I_AC, INT64_C(0073000000000)+I_AC, - INT64_C(0074000000000)+I_AC, INT64_C(0075000000000)+I_AC, INT64_C(0076000000000)+I_AC, INT64_C(0077000000000)+I_AC, - - INT64_C(0100000000000)+I_AC, INT64_C(0102000000000)+I_AC, INT64_C(0103000000000)+I_AC, - INT64_C(0104000000000)+I_AC, INT64_C(0105000000000)+I_AC, INT64_C(0106000000000)+I_AC, INT64_C(0107000000000)+I_AC, - INT64_C(0110000000000)+I_AC, INT64_C(0111000000000)+I_AC, INT64_C(0112000000000)+I_AC, INT64_C(0113000000000)+I_AC, - INT64_C(0114000000000)+I_AC, INT64_C(0115000000000)+I_AC, INT64_C(0116000000000)+I_AC, INT64_C(0117000000000)+I_AC, - INT64_C(0120000000000)+I_AC, INT64_C(0121000000000)+I_AC, INT64_C(0122000000000)+I_AC, INT64_C(0123000000000)+I_AC, - INT64_C(0124000000000)+I_AC, INT64_C(0125000000000)+I_AC, INT64_C(0126000000000)+I_AC, INT64_C(0127000000000)+I_AC, - INT64_C(0130000000000)+I_AC, INT64_C(0131000000000)+I_AC, INT64_C(0132000000000)+I_AC, INT64_C(0133000000000)+I_AC, - INT64_C(0134000000000)+I_AC, INT64_C(0135000000000)+I_AC, INT64_C(0136000000000)+I_AC, INT64_C(0137000000000)+I_AC, - INT64_C(0140000000000)+I_AC, INT64_C(0141000000000)+I_AC, INT64_C(0142000000000)+I_AC, INT64_C(0143000000000)+I_AC, - INT64_C(0144000000000)+I_AC, INT64_C(0145000000000)+I_AC, INT64_C(0146000000000)+I_AC, INT64_C(0147000000000)+I_AC, - INT64_C(0150000000000)+I_AC, INT64_C(0151000000000)+I_AC, INT64_C(0152000000000)+I_AC, INT64_C(0153000000000)+I_AC, - INT64_C(0154000000000)+I_AC, INT64_C(0155000000000)+I_AC, INT64_C(0156000000000)+I_AC, INT64_C(0157000000000)+I_AC, - INT64_C(0160000000000)+I_AC, INT64_C(0161000000000)+I_AC, INT64_C(0162000000000)+I_AC, INT64_C(0163000000000)+I_AC, - INT64_C(0164000000000)+I_AC, INT64_C(0165000000000)+I_AC, INT64_C(0166000000000)+I_AC, INT64_C(0167000000000)+I_AC, - INT64_C(0170000000000)+I_AC, INT64_C(0171000000000)+I_AC, INT64_C(0172000000000)+I_AC, INT64_C(0173000000000)+I_AC, - INT64_C(0174000000000)+I_AC, INT64_C(0175000000000)+I_AC, INT64_C(0176000000000)+I_AC, INT64_C(0177000000000)+I_AC, - - INT64_C(0200000000000)+I_AC, INT64_C(0201000000000)+I_AC, INT64_C(0202000000000)+I_AC, INT64_C(0203000000000)+I_AC, - INT64_C(0204000000000)+I_AC, INT64_C(0205000000000)+I_AC, INT64_C(0206000000000)+I_AC, INT64_C(0207000000000)+I_AC, - INT64_C(0210000000000)+I_AC, INT64_C(0211000000000)+I_AC, INT64_C(0212000000000)+I_AC, INT64_C(0213000000000)+I_AC, - INT64_C(0214000000000)+I_AC, INT64_C(0215000000000)+I_AC, INT64_C(0216000000000)+I_AC, INT64_C(0217000000000)+I_AC, - INT64_C(0220000000000)+I_AC, INT64_C(0221000000000)+I_AC, INT64_C(0222000000000)+I_AC, INT64_C(0223000000000)+I_AC, - INT64_C(0224000000000)+I_AC, INT64_C(0225000000000)+I_AC, INT64_C(0226000000000)+I_AC, INT64_C(0227000000000)+I_AC, - INT64_C(0230000000000)+I_AC, INT64_C(0231000000000)+I_AC, INT64_C(0232000000000)+I_AC, INT64_C(0233000000000)+I_AC, - INT64_C(0234000000000)+I_AC, INT64_C(0235000000000)+I_AC, INT64_C(0236000000000)+I_AC, INT64_C(0237000000000)+I_AC, - INT64_C(0240000000000)+I_AC, INT64_C(0241000000000)+I_AC, INT64_C(0242000000000)+I_AC, INT64_C(0243000000000)+I_AC, - INT64_C(0244000000000)+I_AC, INT64_C(0245000000000)+I_AC, INT64_C(0246000000000)+I_AC, INT64_C(0247000000000)+I_AC+I_ITS, - INT64_C(0250000000000)+I_AC, INT64_C(0251000000000)+I_AC, INT64_C(0252000000000)+I_AC, INT64_C(0253000000000)+I_AC, - INT64_C(0254000000000)+I_AC, INT64_C(0255000000000)+I_AC, INT64_C(0256000000000)+I_AC, INT64_C(0257000000000)+I_AC, - INT64_C(0260000000000)+I_AC, INT64_C(0261000000000)+I_AC, INT64_C(0262000000000)+I_AC, INT64_C(0263000000000)+I_AC, - INT64_C(0264000000000)+I_AC, INT64_C(0265000000000)+I_AC, INT64_C(0266000000000)+I_AC, INT64_C(0267000000000)+I_AC, - INT64_C(0270000000000)+I_AC, INT64_C(0271000000000)+I_AC, INT64_C(0272000000000)+I_AC, INT64_C(0273000000000)+I_AC, - INT64_C(0274000000000)+I_AC, INT64_C(0275000000000)+I_AC, INT64_C(0276000000000)+I_AC, INT64_C(0277000000000)+I_AC, - - INT64_C(0300000000000)+I_AC, INT64_C(0301000000000)+I_AC, INT64_C(0302000000000)+I_AC, INT64_C(0303000000000)+I_AC, - INT64_C(0304000000000)+I_AC, INT64_C(0305000000000)+I_AC, INT64_C(0306000000000)+I_AC, INT64_C(0307000000000)+I_AC, - INT64_C(0310000000000)+I_AC, INT64_C(0311000000000)+I_AC, INT64_C(0312000000000)+I_AC, INT64_C(0313000000000)+I_AC, - INT64_C(0314000000000)+I_AC, INT64_C(0315000000000)+I_AC, INT64_C(0316000000000)+I_AC, INT64_C(0317000000000)+I_AC, - INT64_C(0320000000000)+I_AC, INT64_C(0321000000000)+I_AC, INT64_C(0322000000000)+I_AC, INT64_C(0323000000000)+I_AC, - INT64_C(0324000000000)+I_AC, INT64_C(0325000000000)+I_AC, INT64_C(0326000000000)+I_AC, INT64_C(0327000000000)+I_AC, - INT64_C(0330000000000)+I_AC, INT64_C(0331000000000)+I_AC, INT64_C(0332000000000)+I_AC, INT64_C(0333000000000)+I_AC, - INT64_C(0334000000000)+I_AC, INT64_C(0335000000000)+I_AC, INT64_C(0336000000000)+I_AC, INT64_C(0337000000000)+I_AC, - INT64_C(0340000000000)+I_AC, INT64_C(0341000000000)+I_AC, INT64_C(0342000000000)+I_AC, INT64_C(0343000000000)+I_AC, - INT64_C(0344000000000)+I_AC, INT64_C(0345000000000)+I_AC, INT64_C(0346000000000)+I_AC, INT64_C(0347000000000)+I_AC, - INT64_C(0350000000000)+I_AC, INT64_C(0351000000000)+I_AC, INT64_C(0352000000000)+I_AC, INT64_C(0353000000000)+I_AC, - INT64_C(0354000000000)+I_AC, INT64_C(0355000000000)+I_AC, INT64_C(0356000000000)+I_AC, INT64_C(0357000000000)+I_AC, - INT64_C(0360000000000)+I_AC, INT64_C(0361000000000)+I_AC, INT64_C(0362000000000)+I_AC, INT64_C(0363000000000)+I_AC, - INT64_C(0364000000000)+I_AC, INT64_C(0365000000000)+I_AC, INT64_C(0366000000000)+I_AC, INT64_C(0367000000000)+I_AC, - INT64_C(0370000000000)+I_AC, INT64_C(0371000000000)+I_AC, INT64_C(0372000000000)+I_AC, INT64_C(0373000000000)+I_AC, - INT64_C(0374000000000)+I_AC, INT64_C(0375000000000)+I_AC, INT64_C(0376000000000)+I_AC, INT64_C(0377000000000)+I_AC, - - INT64_C(0400000000000)+I_AC, INT64_C(0401000000000)+I_AC, INT64_C(0402000000000)+I_AC, INT64_C(0403000000000)+I_AC, - INT64_C(0404000000000)+I_AC, INT64_C(0405000000000)+I_AC, INT64_C(0406000000000)+I_AC, INT64_C(0407000000000)+I_AC, - INT64_C(0410000000000)+I_AC, INT64_C(0411000000000)+I_AC, INT64_C(0412000000000)+I_AC, INT64_C(0413000000000)+I_AC, - INT64_C(0414000000000)+I_AC, INT64_C(0415000000000)+I_AC, INT64_C(0416000000000)+I_AC, INT64_C(0417000000000)+I_AC, - INT64_C(0420000000000)+I_AC, INT64_C(0421000000000)+I_AC, INT64_C(0422000000000)+I_AC, INT64_C(0423000000000)+I_AC, - INT64_C(0424000000000)+I_AC, INT64_C(0425000000000)+I_AC, INT64_C(0426000000000)+I_AC, INT64_C(0427000000000)+I_AC, - INT64_C(0430000000000)+I_AC, INT64_C(0431000000000)+I_AC, INT64_C(0432000000000)+I_AC, INT64_C(0433000000000)+I_AC, - INT64_C(0434000000000)+I_AC, INT64_C(0435000000000)+I_AC, INT64_C(0436000000000)+I_AC, INT64_C(0437000000000)+I_AC, - INT64_C(0440000000000)+I_AC, INT64_C(0441000000000)+I_AC, INT64_C(0442000000000)+I_AC, INT64_C(0443000000000)+I_AC, - INT64_C(0444000000000)+I_AC, INT64_C(0445000000000)+I_AC, INT64_C(0446000000000)+I_AC, INT64_C(0447000000000)+I_AC, - INT64_C(0450000000000)+I_AC, INT64_C(0451000000000)+I_AC, INT64_C(0452000000000)+I_AC, INT64_C(0453000000000)+I_AC, - INT64_C(0454000000000)+I_AC, INT64_C(0455000000000)+I_AC, INT64_C(0456000000000)+I_AC, INT64_C(0457000000000)+I_AC, - INT64_C(0460000000000)+I_AC, INT64_C(0461000000000)+I_AC, INT64_C(0462000000000)+I_AC, INT64_C(0463000000000)+I_AC, - INT64_C(0464000000000)+I_AC, INT64_C(0465000000000)+I_AC, INT64_C(0466000000000)+I_AC, INT64_C(0467000000000)+I_AC, - INT64_C(0470000000000)+I_AC, INT64_C(0471000000000)+I_AC, INT64_C(0472000000000)+I_AC, INT64_C(0473000000000)+I_AC, - INT64_C(0474000000000)+I_AC, INT64_C(0475000000000)+I_AC, INT64_C(0476000000000)+I_AC, INT64_C(0477000000000)+I_AC, - - INT64_C(0500000000000)+I_AC, INT64_C(0501000000000)+I_AC, INT64_C(0502000000000)+I_AC, INT64_C(0503000000000)+I_AC, - INT64_C(0504000000000)+I_AC, INT64_C(0505000000000)+I_AC, INT64_C(0506000000000)+I_AC, INT64_C(0507000000000)+I_AC, - INT64_C(0510000000000)+I_AC, INT64_C(0511000000000)+I_AC, INT64_C(0512000000000)+I_AC, INT64_C(0513000000000)+I_AC, - INT64_C(0514000000000)+I_AC, INT64_C(0515000000000)+I_AC, INT64_C(0516000000000)+I_AC, INT64_C(0517000000000)+I_AC, - INT64_C(0520000000000)+I_AC, INT64_C(0521000000000)+I_AC, INT64_C(0522000000000)+I_AC, INT64_C(0523000000000)+I_AC, - INT64_C(0524000000000)+I_AC, INT64_C(0525000000000)+I_AC, INT64_C(0526000000000)+I_AC, INT64_C(0527000000000)+I_AC, - INT64_C(0530000000000)+I_AC, INT64_C(0531000000000)+I_AC, INT64_C(0532000000000)+I_AC, INT64_C(0533000000000)+I_AC, - INT64_C(0534000000000)+I_AC, INT64_C(0535000000000)+I_AC, INT64_C(0536000000000)+I_AC, INT64_C(0537000000000)+I_AC, - INT64_C(0540000000000)+I_AC, INT64_C(0541000000000)+I_AC, INT64_C(0542000000000)+I_AC, INT64_C(0543000000000)+I_AC, - INT64_C(0544000000000)+I_AC, INT64_C(0545000000000)+I_AC, INT64_C(0546000000000)+I_AC, INT64_C(0547000000000)+I_AC, - INT64_C(0550000000000)+I_AC, INT64_C(0551000000000)+I_AC, INT64_C(0552000000000)+I_AC, INT64_C(0553000000000)+I_AC, - INT64_C(0554000000000)+I_AC, INT64_C(0555000000000)+I_AC, INT64_C(0556000000000)+I_AC, INT64_C(0557000000000)+I_AC, - INT64_C(0560000000000)+I_AC, INT64_C(0561000000000)+I_AC, INT64_C(0562000000000)+I_AC, INT64_C(0563000000000)+I_AC, - INT64_C(0564000000000)+I_AC, INT64_C(0565000000000)+I_AC, INT64_C(0566000000000)+I_AC, INT64_C(0567000000000)+I_AC, - INT64_C(0570000000000)+I_AC, INT64_C(0571000000000)+I_AC, INT64_C(0572000000000)+I_AC, INT64_C(0573000000000)+I_AC, - INT64_C(0574000000000)+I_AC, INT64_C(0575000000000)+I_AC, INT64_C(0576000000000)+I_AC, INT64_C(0577000000000)+I_AC, - - INT64_C(0600000000000)+I_AC, INT64_C(0601000000000)+I_AC, INT64_C(0602000000000)+I_AC, INT64_C(0603000000000)+I_AC, - INT64_C(0604000000000)+I_AC, INT64_C(0605000000000)+I_AC, INT64_C(0606000000000)+I_AC, INT64_C(0607000000000)+I_AC, - INT64_C(0610000000000)+I_AC, INT64_C(0611000000000)+I_AC, INT64_C(0612000000000)+I_AC, INT64_C(0613000000000)+I_AC, - INT64_C(0614000000000)+I_AC, INT64_C(0615000000000)+I_AC, INT64_C(0616000000000)+I_AC, INT64_C(0617000000000)+I_AC, - INT64_C(0620000000000)+I_AC, INT64_C(0621000000000)+I_AC, INT64_C(0622000000000)+I_AC, INT64_C(0623000000000)+I_AC, - INT64_C(0624000000000)+I_AC, INT64_C(0625000000000)+I_AC, INT64_C(0626000000000)+I_AC, INT64_C(0627000000000)+I_AC, - INT64_C(0630000000000)+I_AC, INT64_C(0631000000000)+I_AC, INT64_C(0632000000000)+I_AC, INT64_C(0633000000000)+I_AC, - INT64_C(0634000000000)+I_AC, INT64_C(0635000000000)+I_AC, INT64_C(0636000000000)+I_AC, INT64_C(0637000000000)+I_AC, - INT64_C(0640000000000)+I_AC, INT64_C(0641000000000)+I_AC, INT64_C(0642000000000)+I_AC, INT64_C(0643000000000)+I_AC, - INT64_C(0644000000000)+I_AC, INT64_C(0645000000000)+I_AC, INT64_C(0646000000000)+I_AC, INT64_C(0647000000000)+I_AC, - INT64_C(0650000000000)+I_AC, INT64_C(0651000000000)+I_AC, INT64_C(0652000000000)+I_AC, INT64_C(0653000000000)+I_AC, - INT64_C(0654000000000)+I_AC, INT64_C(0655000000000)+I_AC, INT64_C(0656000000000)+I_AC, INT64_C(0657000000000)+I_AC, - INT64_C(0660000000000)+I_AC, INT64_C(0661000000000)+I_AC, INT64_C(0662000000000)+I_AC, INT64_C(0663000000000)+I_AC, - INT64_C(0664000000000)+I_AC, INT64_C(0665000000000)+I_AC, INT64_C(0666000000000)+I_AC, INT64_C(0667000000000)+I_AC, - INT64_C(0670000000000)+I_AC, INT64_C(0671000000000)+I_AC, INT64_C(0672000000000)+I_AC, INT64_C(0673000000000)+I_AC, - INT64_C(0674000000000)+I_AC, INT64_C(0675000000000)+I_AC, INT64_C(0676000000000)+I_AC, INT64_C(0677000000000)+I_AC, - - INT64_C(0704000000000)+I_AC, INT64_C(0705000000000)+I_AC, - INT64_C(0710000000000)+I_AC, INT64_C(0711000000000)+I_AC, INT64_C(0712000000000)+I_AC, INT64_C(0713000000000)+I_AC, - INT64_C(0714000000000)+I_AC, INT64_C(0715000000000)+I_AC, INT64_C(0716000000000)+I_AC, INT64_C(0717000000000)+I_AC, - INT64_C(0720000000000)+I_AC, INT64_C(0721000000000)+I_AC, INT64_C(0722000000000)+I_AC, INT64_C(0723000000000)+I_AC, - INT64_C(0724000000000)+I_AC, INT64_C(0725000000000)+I_AC, - - INT64_C(0700000000000)+I_IO, INT64_C(0700040000000)+I_IO, INT64_C(0700100000000)+I_IO, INT64_C(0700140000000)+I_IO, - INT64_C(0700200000000)+I_IO, INT64_C(0700240000000)+I_IO, INT64_C(0700300000000)+I_IO, INT64_C(0700340000000)+I_IO, - - INT64_C(0400000000000)+I_AC, INT64_C(0401000000000)+I_AC, INT64_C(0402000000000)+I_AC, INT64_C(0403000000000)+I_AC, - INT64_C(0434000000000)+I_AC, INT64_C(0435000000000)+I_AC, INT64_C(0436000000000)+I_AC, INT64_C(0437000000000)+I_AC, - INT64_C(0415000000000)+I_AC, INT64_C(0501000000000)+I_AC, - - INT64_C(0001000000000)+I_AC, INT64_C(0002000000000)+I_AC, INT64_C(0003000000000)+I_AC, - INT64_C(0004000000000)+I_AC, INT64_C(0005000000000)+I_AC, INT64_C(0006000000000)+I_AC, INT64_C(0007000000000)+I_AC, - INT64_C(0010000000000)+I_AC, INT64_C(0011000000000)+I_AC, INT64_C(0012000000000)+I_AC, INT64_C(0013000000000)+I_AC, - INT64_C(0014000000000)+I_AC, INT64_C(0015000000000)+I_AC, INT64_C(0016000000000)+I_AC, INT64_C(0017000000000)+I_AC, - INT64_C(0020000000000)+I_AC, INT64_C(0021000000000)+I_AC, INT64_C(0022000000000)+I_AC, INT64_C(0023000000000)+I_AC, - INT64_C(0024000000000)+I_AC, INT64_C(0025000000000)+I_AC, INT64_C(0026000000000)+I_AC, INT64_C(0027000000000)+I_AC, - INT64_C(0030000000000)+I_AC, INT64_C(0031000000000)+I_AC, - -INT64_C(1) - }; - -#define NUMDEV 6 - -static const char *devnam[NUMDEV] = { - "APR", "PI", "PAG", "CCA", "TIM", "MTR" - }; - -/* Symbolic decode - - Inputs: - *of = output stream - addr = current PC - *val = pointer to values - *uptr = pointer to unit - sw = switches - Outputs: - return = status code -*/ - -#define FMTASC(x) ((x) < 040)? "<%03o>": "%c", (x) -#define SIXTOASC(x) ((x) + 040) - -t_stat fprint_sym (FILE *of, t_addr addr, t_value *val, - UNIT *uptr, int32 sw) -{ -int32 i, j, c, ac, xr, y, dev; -d10 inst; - -inst = val[0]; -if (sw & SWMASK ('A')) { /* ASCII? */ - if (inst > 0377) - return SCPE_ARG; - fprintf (of, FMTASC ((int32) (inst & 0177))); - return SCPE_OK; - } -if (sw & SWMASK ('C')) { /* character? */ - for (i = 30; i >= 0; i = i - 6) { - c = (int32) ((inst >> i) & 077); - fprintf (of, "%c", SIXTOASC (c)); - } - return SCPE_OK; - } -if (sw & SWMASK ('P')) { /* packed? */ - for (i = 29; i >= 0; i = i - 7) { - c = (int32) ((inst >> i) & 0177); - fprintf (of, FMTASC (c)); - } - return SCPE_OK; - } -if (!(sw & SWMASK ('M'))) - return SCPE_ARG; - -/* Instruction decode */ - -ac = GET_AC (inst); -xr = GET_XR (inst); -y = GET_ADDR (inst); -dev = GET_DEV (inst); -for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ - j = (int32) ((opc_val[i] >> I_V_FL) & I_M_FL); /* get class */ - if (((opc_val[i] & DMASK) == (inst & masks[j])) && /* match? */ - (((opc_val[i] & I_ITS) == 0) || Q_ITS)) { - fprintf (of, "%s ", opcode[i]); /* opcode */ - switch (j) { /* case on class */ - - case I_V_AC: /* AC + address */ - fprintf (of, "%-o,", ac); /* print AC, fall thru */ - case I_V_OP: /* address only */ - if (inst & INST_IND) - fprintf (of, "@"); - if (xr) - fprintf (of, "%-o(%-o)", y, xr); - else fprintf (of, "%-o", y); - break; - - case I_V_IO: /* I/O */ - if (dev < NUMDEV) - fprintf (of, "%s,", devnam[dev]); - else fprintf (of, "%-o,", dev); - if (inst & INST_IND) - fprintf (of, "@"); - if (xr) - fprintf (of, "%-o(%-o)", y, xr); - else fprintf (of, "%-o", y); - break; - } /* end case */ - return SCPE_OK; - } /* end if */ - } /* end for */ -return SCPE_ARG; -} - -/* Get operand, including indirect and index - - Inputs: - *cptr = pointer to input string - *status = pointer to error status - Outputs: - val = output value -*/ - -t_value get_opnd (char *cptr, t_stat *status) -{ -int32 sign = 0; -t_value val, xr = 0, ind = 0; -char *tptr; - -*status = SCPE_ARG; /* assume fail */ -if (*cptr == '@') { - ind = INST_IND; - cptr++; - } -if (*cptr == '+') - cptr++; -else if (*cptr == '-') { - sign = 1; - cptr++; - } -val = strtotv (cptr, &tptr, 8); -if (val > 0777777) - return 0; -if (sign) - val = (~val + 1) & 0777777; -cptr = tptr; -if (*cptr == '(') { - cptr++; - xr = strtotv (cptr, &tptr, 8); - if ((cptr == tptr) || (*tptr != ')') || - (xr > AC_NUM) || (xr == 0)) - return 0; - cptr = ++tptr; - } -if (*cptr == 0) - *status = SCPE_OK; -return (ind | (xr << 18) | val); -} - -/* 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 -*/ - -t_stat parse_sym (char *cptr, t_addr addr, UNIT *uptr, t_value *val, int32 sw) -{ -int32 i, j; -t_value ac, dev; -t_stat r; -char gbuf[CBUFSIZE]; - -while (isspace (*cptr)) cptr++; -for (i = 0; i < 6; i++) { - if (cptr[i] == 0) { - for (j = i + 1; j <= 6; j++) cptr[j] = 0; - break; - } - } -if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ - if (cptr[0] == 0) /* must have 1 char */ - return SCPE_ARG; - val[0] = (t_value) cptr[0]; - return SCPE_OK; - } -if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* sixbit string? */ - if (cptr[0] == 0) /* must have 1 char */ - return SCPE_ARG; - for (i = 0; i < 6; i++) { - val[0] = (val[0] << 6); - if (cptr[i]) val[0] = val[0] | - ((t_value) ((cptr[i] + 040) & 077)); - } - return SCPE_OK; - } -if ((sw & SWMASK ('P')) || ((*cptr == '#') && cptr++)) { /* packed string? */ - if (cptr[0] == 0) /* must have 1 char */ - return SCPE_ARG; - for (i = 0; i < 5; i++) - val[0] = (val[0] << 7) | ((t_value) cptr[i]); - val[0] = val[0] << 1; - return SCPE_OK; - } - -/* Instruction parse */ - -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] & DMASK; /* get value */ -j = (int32) ((opc_val[i] >> I_V_FL) & I_M_FL); /* get class */ -switch (j) { /* case on class */ - - case I_V_AC: /* AC + operand */ - if (strchr (cptr, ',')) { /* AC specified? */ - cptr = get_glyph (cptr, gbuf, ','); /* get glyph */ - if (gbuf[0]) { /* can be omitted */ - ac = get_uint (gbuf, 8, AC_NUM - 1, &r); - if (r != SCPE_OK) - return SCPE_ARG; - val[0] = val[0] | (ac << INST_V_AC); - } - } /* fall through */ - case I_V_OP: /* operand */ - cptr = get_glyph (cptr, gbuf, 0); - val[0] = val[0] | get_opnd (gbuf, &r); - if (r != SCPE_OK) - return SCPE_ARG; - break; - - case I_V_IO: /* I/O */ - cptr = get_glyph (cptr, gbuf, ','); /* get glyph */ - for (dev = 0; (dev < NUMDEV) && (strcmp (devnam[dev], gbuf) != 0); dev++); - if (dev >= NUMDEV) { - dev = get_uint (gbuf, 8, INST_M_DEV, &r); - if (r != SCPE_OK) - return SCPE_ARG; - } - val[0] = val[0] | (dev << INST_V_DEV); - cptr = get_glyph (cptr, gbuf, 0); - val[0] = val[0] | get_opnd (gbuf, &r); - if (r != SCPE_OK) - return SCPE_ARG; - break; - } /* end case */ - -if (*cptr != 0) /* junk at end? */ - return SCPE_ARG; -return SCPE_OK; -} diff --git a/PDP10/pdp10_tim.c b/PDP10/pdp10_tim.c deleted file mode 100644 index e4f80c8c..00000000 --- a/PDP10/pdp10_tim.c +++ /dev/null @@ -1,456 +0,0 @@ -/* pdp10_tim.c: PDP-10 tim subsystem simulator - - Copyright (c) 1993-2015, 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. - - tim timer subsystem - - 10-Nov-16 R.V Fix wallclock issue for 50 Hz systems (R. Voorhorst) - 18-Apr-12 RMS Removed absolute scheduling on reset - 18-Jun-07 RMS Added UNIT_IDLE flag - 03-Nov-06 RMS Rewritten to support idling - 29-Oct-06 RMS Added clock coscheduling function - 02-Feb-04 RMS Exported variables needed by Ethernet simulator - 29-Jan-02 RMS New data structures - 06-Jan-02 RMS Added enable/disable support - 02-Dec-01 RMS Fixed bug in ITS PC sampling (found by Dave Conroy) - 31-Aug-01 RMS Changed int64 to t_int64 for Windoze - 17-Jul-01 RMS Moved function prototype - 04-Jul-01 RMS Added DZ11 support -*/ - -#include "pdp10_defs.h" -#include -#include - -/* The KS timer works off a 4.100 MHz (243.9024 nsec) oscillator that - * is independent of all other system timing. - * - * Two pieces of timekeeping hardware are exposed to the OS. - * o The interval timer, which can interrupt at a programmed interval. - * o The timebase, which records time (71 bits). - * - * The clock is architecturally readable in units of 243.9024 nsec via - * the timebase. The implementation is somewhat different. - * - * The instructions that update the clocks specify time in these units. - * - * However, both timekeepers are incremented by the microcode when - * a 12 bit counter overflows; e.g. at a period of 999.0244 usec. - * Thus, the granularity of timer interrupts is approximately 1 msec. - * - * The OS programs the interval timer to interrupt as though the - * the 12 least significant bits mattered. Thus, for a (roughly) - * 1 msec interval, it would program 1 * 4096 into the interval timer. - * The sign bit is not used, so 35-12 = 23 bits for the maximum interval, - * which is 139.674 minutes. If any of the least significant bits - * are non-zero, the interval is extended by 1 * 4096 counts. - * - * The timer merely sets the INTERVAL DONE flag in the APR flags. - * Whether that actually causes an interrupt is controlled by the - * APR interrupt enable for the flag and by the PI system. - * - * The flag is readable as an APR condition by RDAPR, and CONSO/Z APR,. - * The flag is cleared by WRAPR 1b22!1b30 (clear, count done). - * - * The timebase is maintained with the 12 LSB zero in a workspace - * register. When read by the OS, the actual value of the 10 MSB of - * the hardware counter is inserted into those bits, providing increased - * resolution. Although the system reference manual says otherwise, the - * two LSB of the counter are read as zero by the microcode (DPM2), so - * bits <70:71> of the timebase are also read as zero by software. - * - * When the OS sets the timebase, the 12 LSB that it supplies are ignored. - * - * The timebase is typically used for accurate time of day and CPU runtime - * accounting. The simulator adjusts the equivalent of the 12-bit counter, - * so CPU time will reflect simulator wall clock, not simulated machine cycles. - * Since time of day must be accurate, this may result in the OS reporting - * CPU times that are unrealistically faster - or slower - than on the - * real hardware. - * - * This module also implements the TCU, a battery backed-up TOY clock - * that was supported by TOPS-10, but not sold by DEC. - */ - -/* Invariants */ - -#define TIM_HW_FREQ 4100000 /* 4.1Mhz */ -#define TIM_HWRE_MASK 07777 /* Timer field of timebase */ -#define TIM_BASE_RAZ 03 /* Timer bits read as zero by ucode */ -#define UNIT_V_Y2K (UNIT_V_UF + 0) /* Y2K compliant OS */ -#define UNIT_Y2K (1u << UNIT_V_Y2K) - -#define TIM_TMXR_FREQ 60 /* Target frequency (HZ) for tmxr polls */ - - /* Estimate of simulator instructions/sec for initialization and fixed timing. - * This came from prior magic constant of 8000 at 60 tics/sec. - * The machine was marketed as ~ 300KIPs, which would imply 3 usec/instr. - * So 8,000 instructions should take ~24 msec. This would indicate that - * the simulator from which this came was ~1.4 x the speed of the real - * hardware. Current milage will vary. - */ -#define TIM_WAIT_IPS 480000 - -/* Clock mode TOPS-10/ITS */ - -#define TIM_TPS_T10 60 /* Initial frequency guess for TOPS-10 (close, not exact) */ -#define TIM_ITS_QUANT (TIM_HW_FREQ / TIM_TPS_T10) /* ITS PC sampling and user runtime interval */ - -/* Clock mode TOPS-20/KLAD */ - -#define TIM_TPS_T20 1000 /* Initial estimate for TOPS-20 - 1msec seems fast? */ - -/* Probability function for TOPS-20 idlelock */ - -#define PROB(x) (((rand() * 100) / RAND_MAX) >= (x)) - -static d10 tim_base[2] = { 0, 0 }; /* 71b timebase */ -static d10 tim_interval = 0; /* value programmed into the clock */ -static d10 tim_period = 0; /* period in HW ticks adjusted for non-zero LSBs */ -static d10 tim_new_period = 0; /* period for the next interval */ -static int32 tim_mult; /* Multiple of interval timer period at which tmxr is polled */ - -d10 quant = 0; /* ITS quantum */ -static int32 tim_t20_prob = 33; /* TOPS-20 prob */ - -/* Exported variables - initialized by set CPU model and reset */ - -int32 clk_tps; /* Interval clock ticks/sec */ -int32 tmr_poll; /* SimH instructions/clock service */ -int32 tmxr_poll; /* SimH instructions/term mux poll */ - -extern int32 apr_flg, pi_act; -extern UNIT cpu_unit; -extern d10 pcst; -extern a10 pager_PC; -extern int32 t20_idlelock; - -DEVICE tim_dev; -static t_stat tcu_rd (int32 *data, int32 PA, int32 access); -static t_stat tim_svc (UNIT *uptr); -static t_stat tim_reset (DEVICE *dptr); -static t_bool update_interval (d10 new_interval); -static void tim_incr_base (d10 *base, d10 incr); - -extern d10 Read (a10 ea, int32 prv); -extern d10 ReadM (a10 ea, int32 prv); -extern void Write (a10 ea, d10 val, int32 prv); -extern void WriteP (a10 ea, d10 val); -extern int32 pi_eval (void); -extern t_stat wr_nop (int32 data, int32 PA, int32 access); - -/* TIM data structures - - tim_dev TIM device descriptor - tim_unit TIM unit descriptor - tim_reg TIM register list -*/ - -DIB tcu_dib = { IOBA_TCU, IOLN_TCU, &tcu_rd, &wr_nop, 0 }; - -static UNIT tim_unit = { UDATA (&tim_svc, UNIT_IDLE, 0), 0 }; - -static REG tim_reg[] = { - { BRDATA (TIMEBASE, tim_base, 8, 36, 2) }, - { ORDATA (PERIOD, tim_period, 36) }, - { ORDATA (QUANT, quant, 36) }, - { DRDATA (TIME, tim_unit.wait, 24), REG_NZ + PV_LEFT }, - { DRDATA (PROB, tim_t20_prob, 6), REG_NZ + PV_LEFT + REG_HIDDEN }, - { DRDATA (POLL, tmr_poll, 32), REG_HRO + PV_LEFT }, - { DRDATA (MUXPOLL, tmxr_poll, 32), REG_HRO + PV_LEFT }, - { DRDATA (MULT, tim_mult, 6), REG_HRO + PV_LEFT }, - { DRDATA (TPS, clk_tps, 12), REG_HRO + PV_LEFT }, - { NULL } - }; - -static MTAB tim_mod[] = { - { UNIT_Y2K, 0, "non Y2K OS", "NOY2K", NULL }, - { UNIT_Y2K, UNIT_Y2K, "Y2K OS", "Y2K", NULL }, - { MTAB_XTD|MTAB_VDV, 000, "ADDRESS", NULL, - NULL, &show_addr, NULL }, - { 0 } - }; - -DEVICE tim_dev = { - "TIM", &tim_unit, tim_reg, tim_mod, - 1, 0, 0, 0, 0, 0, - NULL, NULL, &tim_reset, - NULL, NULL, NULL, - &tcu_dib, DEV_UBUS - }; - -/* Timer instructions */ - -/* Timebase - the timer is always running at less than hardware frequency, - * need to interpolate the value by calculating how much of the current - * clock tick has elapsed, and what that equates to in sysfreq units. - */ - -t_bool rdtim (a10 ea, int32 prv) -{ -double fract; /* Fraction of current interval completed */ -d10 tempbase[2]; /* Local copy of tempbase to interpolate */ -int32 used; /* Used part of curr intv, in hw ticks */ -d10 incr; /* Interpolated increment for timebase */ - -tempbase[0] = tim_base[0]; /* copy time base */ -tempbase[1] = tim_base[1]; - -used = tmr_poll - (sim_activate_time (&tim_unit) - 1); -fract = ((double)used) / ((double)tmr_poll); - -/* - * incr is approximate number of HW ticks to add to the timebase - * value returned. This does NOT update the timebase. - */ -incr = (d10)(fract * (double)tim_period); -tim_incr_base (tempbase, incr); - -/* Although the two LSB of the counter contribute carry to the - * value, they are read as zero by microcode, and thus cleared here. - * - * The reason that these bits are forced to zero in the hardware is - * that the counter is in a different clock domain from the microcode. - * To make the domain crossing, the microcode reads the counter - * until two consecutive values match. - * - * Since the microcode cycle time is 300 nsec, the LSBs of the - * counter run too fast (244 nsec) for the strategy to work. - * Ignoring the two LSB ensures that the value can't change any - * faster than ~976 nsec, which guarantees a stable value can be - * obtained in at most three attempts. - */ -tempbase[1] &= ~((d10) TIM_BASE_RAZ); - -/* If the destination is arranged so that the first word is OK, but - * the second pagefaults, the value will be half-written. As we - * expect the PFH to restart the instruction, the both halves will - * be written the second time. We could read and write back both - * halves to avoid this, but the hardware doesn't seem to either. - */ -Write (ea, tempbase[0], prv); -Write (INCA(ea), tempbase[1], prv); -return FALSE; -} - -t_bool wrtim (a10 ea, int32 prv) -{ -tim_base[0] = Read (ea, prv); -tim_base[1] = CLRS (Read (INCA (ea), prv) & ~((d10) TIM_HWRE_MASK)); -return FALSE; -} - -t_bool rdint (a10 ea, int32 prv) -{ -Write (ea, tim_interval, prv); -return FALSE; -} - -/* write a new interval timer period (in timer ticks). - * This does not clear the harware counter, so the first - * completion can come up to ~1 msc later than the new - * period. - */ - -t_bool wrint (a10 ea, int32 prv) -{ -tim_interval = CLRS (Read (ea, prv)); -return update_interval (tim_interval); -} - -static t_bool update_interval (d10 new_interval) -{ -/* - * The value provided is in hardware clicks. For a frequency of 4.1 - * MHz, that means that dividing by 4096 (shifting 12 to the right) we get - * the aproximate value in millisenconds. If any of rhe rightmost bits is - * one, we add one unit (4096 ticks ). Reference: - * AA-H391A-TK_DECsystem-10_DECSYSTEM-20_Processor_Reference_Jun1982.pdf - * (page 4-37) - */ -tim_new_period = new_interval & ~TIM_HWRE_MASK; -if (new_interval & TIM_HWRE_MASK) tim_new_period += 010000; - -/* clk_tps is the new number of clocks ticks per second */ -clk_tps = (int32) ceil(((double)TIM_HW_FREQ /(double)tim_new_period) - 0.5); - -/* tmxr is polled every tim_mult clks. Compute the divisor matching the target. */ -tim_mult = (clk_tps <= TIM_TMXR_FREQ) ? 1 : (clk_tps / TIM_TMXR_FREQ) ; - -/* Estimate instructions/tick for fixed timing - just for KLAD */ -tim_unit.wait = TIM_WAIT_IPS / clk_tps; -tmxr_poll = tim_unit.wait * tim_mult; - -/* The next tim_svc will update the activation time. - * - */ -return FALSE; -} - -/* Timer service - the timer is only serviced when the interval - * programmed in tim_period by wrint expires. If the interval - * changes, the timebase update is based on the previous interval. - * The interval calibration is based on what the new interval will be. - */ - -static t_stat tim_svc (UNIT *uptr) -{ -if (cpu_unit.flags & UNIT_KLAD) /* diags? */ - tmr_poll = uptr->wait; /* fixed clock */ -else tmr_poll = sim_rtc_calb (clk_tps); /* else calibrate */ - -sim_activate (uptr, tmr_poll); /* reactivate unit */ -tmxr_poll = tmr_poll * tim_mult; /* set mux poll */ -tim_incr_base (tim_base, tim_period); /* incr time base based on period of expired interval */ -tim_period = tim_new_period; /* If interval has changed, update period */ -apr_flg = apr_flg | APRF_TIM; /* request interrupt */ -if (Q_ITS) { /* ITS? */ - if (pi_act == 0) - quant = (quant + TIM_ITS_QUANT) & DMASK; - if (TSTS (pcst)) { /* PC sampling? */ - WriteP ((a10) pcst & AMASK, pager_PC); /* store sample */ - pcst = AOB (pcst); /* add 1,,1 */ - } - } /* end ITS */ -else if (t20_idlelock && PROB (100 - tim_t20_prob)) - t20_idlelock = 0; -return SCPE_OK; -} - -/* Clock coscheduling routine */ - -int32 clk_cosched (int32 wait) -{ -int32 t; - -t = sim_is_active (&tim_unit); -return (t? t - 1: wait); -} - -static void tim_incr_base (d10 *base, d10 incr) -{ -base[1] = base[1] + incr; /* add on incr */ -base[0] = base[0] + (base[1] >> 35); /* carry to high */ -base[0] = base[0] & DMASK; /* mask high */ -base[1] = base[1] & MMASK; /* mask low */ -return; -} - -/* Timer reset */ - -static t_stat tim_reset (DEVICE *dptr) -{ -sim_register_clock_unit (&tim_unit); /* declare clock unit */ - -tim_base[0] = tim_base[1] = 0; /* clear timebase (HW does) */ -/* HW does not initialize the interval timer, so the rate at which the timer flag - * sets is random. No sensible user would enable interrupts or check the flag without - * setting an interval. The timebase is intialized to zero by microcode intialization. - * It increments based on the overflow, so it would be reasonable for a user to just - * read it twice and subtract the values to determine elapsed time. - * - * Simply to keep the simulator overhead down until the interval timer is initialized - * by the OS or diagnostic, we will set the internal interval to ~17 msec here. - * This allows the service routine to increment the timebase, and gives RDTIME an - * baseline for its interpolation. - */ -tim_interval = 0; -clk_tps = 60; -update_interval(17*4096); - -apr_flg = apr_flg & ~APRF_TIM; /* clear interrupt */ - -tmr_poll = sim_rtc_init (tim_unit.wait); /* init timer */ -sim_activate (&tim_unit, tmr_poll); /* activate unit */ -tmxr_poll = tmr_poll * tim_mult; /* set mux poll */ -return SCPE_OK; -} - -/* Set timer parameters from CPU model */ - -t_stat tim_set_mod (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (val & (UNIT_T20|UNIT_KLAD)) { - clk_tps = TIM_TPS_T20; - update_interval(((d10)(1000*4096))/clk_tps); - tmr_poll = tim_unit.wait; - uptr->flags = uptr->flags | UNIT_Y2K; - } -else { - clk_tps = TIM_TPS_T10; - update_interval (((d10)(1000*4096))/clk_tps); - tmr_poll = tim_unit.wait; - if (Q_ITS) - uptr->flags = uptr->flags | UNIT_Y2K; - else uptr->flags = uptr->flags & ~UNIT_Y2K; - } -return SCPE_OK; -} - -/* Time of year clock - * - * The hardware clock was never sold by DEC, but support for it exists - * in TOPS-10. Code was also available for RSX20F to read and report the - * to the OS via its20F's SETSPD task. This implements only the read functions. - * - * The manufacturer's manual can be found at - * http://bitsavers.trailing-edge.com/pdf/digitalPathways/tcu-150.pdf - */ - -static t_stat tcu_rd (int32 *data, int32 PA, int32 access) -{ -time_t curtim; -struct tm *tptr; - -curtim = time (NULL); /* get time */ -tptr = localtime (&curtim); /* decompose */ -if (tptr == NULL) - return SCPE_NXM; -if ((tptr->tm_year > 99) && !(tim_unit.flags & UNIT_Y2K)) - tptr->tm_year = 99; /* Y2K prob? */ - -switch ((PA >> 1) & 03) { /* decode PA<3:1> */ - - case 0: /* year/month/day */ - *data = (((tptr->tm_year) & 0177) << 9) | - (((tptr->tm_mon + 1) & 017) << 5) | - ((tptr->tm_mday) & 037); - return SCPE_OK; - - case 1: /* hour/minute */ - *data = (((tptr->tm_hour) & 037) << 8) | - ((tptr->tm_min) & 077); - return SCPE_OK; - - case 2: /* second */ - *data = (tptr->tm_sec) & 077; - return SCPE_OK; - - case 3: /* status */ - *data = CSR_DONE; - return SCPE_OK; - } - -return SCPE_NXM; /* can't get here */ -} diff --git a/PDP10/pdp10_tu.c b/PDP10/pdp10_tu.c deleted file mode 100644 index 32201484..00000000 --- a/PDP10/pdp10_tu.c +++ /dev/null @@ -1,1398 +0,0 @@ -/* pdp10_tu.c - PDP-10 RH11/TM03/TU45 magnetic tape simulator - - Copyright (c) 1993-2018, 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. - - tu RH11/TM03/TU45 magtape - - 12-Jan-18 RMS Fixed missing () in logical test (Mark Pizzolato) - 29-Dec-17 RMS Read tape mark must set Massbus EXC (TRE) - 28-Mar-17 RMS Documented switch fall through case (COVERITY) - 17-Mar-13 RMS Fixed bug in read/write check reverse (Dave Bryan) - 29-Apr-07 RMS Fixed bug in setting FCE on TMK (Naoki Hamada) - 16-Feb-06 RMS Added tape capacity checking - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 07-Jul-05 RMS Removed extraneous externs - 31-Mar-05 RMS Fixed bug, ERASE/WREOF incorrectly clear CS1 - Fixed inaccuracies in error reporting - 18-Mar-05 RMS Added attached test to detach routine - 23-Oct-04 RMS Fixed setting done on non data transfers - 01-Oct-04 RMS Modified to set FCE on read short record, eof - Implemented write check - TM03 uses only den<2> for validity test - TMK is cleared by new motion command, not DCLR - 14-Sep-04 RMS Fixed RIP value - 25-Apr-03 RMS Revised for extended file support - 28-Mar-03 RMS Added multiformat support - 28-Feb-03 RMS Revised for magtape library - 27-Jan-03 RMS Changed to dynamically allocate buffer - 21-Nov-02 RMS Fixed bug in bootstrap (Michael Thompson) - Fixed bug in read (Harris Newman) - 29-Sep-02 RMS Added variable vector support - New data structures - 28-Aug-02 RMS Added end of medium support - 30-May-02 RMS Widened POS to 32b - 22-Apr-02 RMS Changed record length error code - 06-Jan-02 RMS Revised enable/disable support - 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 - 30-Sep-01 RMS Fixed handling of non-existent formatters - 28-Sep-01 RMS Fixed interrupt handling for SC/ATA - 4-May-01 RMS Fixed bug in odd address test - 3-May-01 RMS Fixed drive reset to clear SSC - - Magnetic tapes are represented as a series of variable 8b records - of the form: - - 32b record length in bytes - exact number, sign = error - byte 0 - byte 1 - : - byte n-2 - byte n-1 - 32b record length in bytes - exact number, sign = error - - 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. - - WARNING: The interupt logic of the RH11/RH70 is unusual and must be - simulated with great precision. The RH11 has an internal interrupt - request flop, CSTB INTR, which is controlled as follows: - - Writing IE and DONE simultaneously sets CSTB INTR - - Controller clear, INIT, and interrupt acknowledge clear CSTB INTR - (and also clear IE) - - A transition of DONE from 0 to 1 sets CSTB from INTR - The output of INTR is OR'd with the AND of RPCS1 to - create the interrupt request signal. Thus, - - The DONE interrupt is edge sensitive, but the SC interrupt is - level sensitive. - - The DONE interrupt, once set, is not disabled if IE is cleared, - but the SC interrupt is. -*/ - -#include "pdp10_defs.h" -#include "sim_tape.h" -#include - -#define TU_NUMFM 1 /* #formatters */ -#define TU_NUMDR 8 /* #drives */ -#define USTAT u3 /* unit status */ -#define UDENS u4 /* unit density */ -#define UD_UNK 0 /* unknown */ -#define MT_MAXFR (1 << 16) /* max data buf */ -#define TU_STATEFLAGS u5 /* Simulator state flags */ -#define TUS_ATTPENDING 0000001 /* Attach pending */ -#define SPINUPDLY 100*1000 /* 100 msec */ - -/* MTCS1 - 172440 - control/status 1 */ - -#define CS1_GO CSR_GO /* go */ -#define CS1_V_FNC 1 /* function pos */ -#define CS1_M_FNC 037 /* function mask */ -#define CS1_N_FNC (CS1_M_FNC + 1) -#define CS1_FNC (CS1_M_FNC << CS1_V_FNC) -#define FNC_NOP 000 /* no operation */ -#define FNC_UNLOAD 001 /* unload */ -#define FNC_REWIND 003 /* rewind */ -#define FNC_FCLR 004 /* formatter clear */ -#define FNC_RIP 010 /* read in preset */ -#define FNC_ERASE 012 /* erase tape */ -#define FNC_WREOF 013 /* write tape mark */ -#define FNC_SPACEF 014 /* space forward */ -#define FNC_SPACER 015 /* space reverse */ -#define FNC_XFER 024 /* >=? data xfr */ -#define FNC_WCHKF 024 /* write check */ -#define FNC_WCHKR 027 /* write check rev */ -#define FNC_WRITE 030 /* write */ -#define FNC_READF 034 /* read forward */ -#define FNC_READR 037 /* read reverse */ -#define CS1_IE CSR_IE /* int enable */ -#define CS1_DONE CSR_DONE /* ready */ -#define CS1_V_UAE 8 /* Unibus addr ext */ -#define CS1_M_UAE 03 -#define CS1_UAE (CS1_M_UAE << CS1_V_UAE) -#define CS1_DVA 0004000 /* drive avail NI */ -#define CS1_MCPE 0020000 /* Mbus par err NI */ -#define CS1_TRE 0040000 /* transfer err */ -#define CS1_SC 0100000 /* special cond */ -#define CS1_MBZ 0012000 -#define CS1_DRV (CS1_FNC | CS1_GO) -#define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC) -#define GET_UAE(x) (((x) & CS1_UAE) << (16 - CS1_V_UAE)) - -/* MTWC - 172442 - word count */ - -/* MTBA - 172444 - base address */ - -#define BA_MBZ 0000001 /* must be zero */ - -/* MTFC - 172446 - frame count */ - -/* MTCS2 - 172450 - control/status 2 */ - -#define CS2_V_FMTR 0 /* formatter select */ -#define CS2_M_FMTR 07 -#define CS2_FMTR (CS2_M_FMTR << CS2_V_FMTR) -#define CS2_UAI 0000010 /* addr inhibit NI */ -#define CS2_PAT 0000020 /* parity test NI */ -#define CS2_CLR 0000040 /* controller clear */ -#define CS2_IR 0000100 /* input ready */ -#define CS2_OR 0000200 /* output ready */ -#define CS2_MDPE 0000400 /* Mbus par err NI */ -#define CS2_MXF 0001000 /* missed xfer NI */ -#define CS2_PGE 0002000 /* program err */ -#define CS2_NEM 0004000 /* nx mem err */ -#define CS2_NEF 0010000 /* nx fmter err */ -#define CS2_PE 0020000 /* parity err NI */ -#define CS2_WCE 0040000 /* write chk err */ -#define CS2_DLT 0100000 /* data late NI */ -#define CS2_MBZ (CS2_CLR | CS2_WCE) -#define CS2_RW (CS2_FMTR | CS2_UAI | CS2_PAT | CS2_MXF | CS2_PE) -#define CS2_ERR (CS2_MDPE | CS2_MXF | CS2_PGE | CS2_NEM | \ - CS2_NEF | CS2_PE | CS2_DLT ) -#define GET_FMTR(x) (((x) >> CS2_V_FMTR) & CS2_M_FMTR) - -/* MTFS - 172452 - formatter status - + indicates kept in drive status - ^ indicates calculated on the fly -*/ - -#define FS_SAT 0000001 /* slave attention */ -#define FS_BOT 0000002 /* ^beginning of tape */ -#define FS_TMK 0000004 /* end of file */ -#define FS_ID 0000010 /* ID burst detected */ -#define FS_SLOW 0000020 /* slowing down NI */ -#define FS_PE 0000040 /* ^PE status */ -#define FS_SSC 0000100 /* slave stat change */ -#define FS_RDY 0000200 /* ^formatter ready */ -#define FS_FPR 0000400 /* formatter present */ -#define FS_EOT 0002000 /* +end of tape */ -#define FS_WRL 0004000 /* ^write locked */ -#define FS_MOL 0010000 /* ^medium online */ -#define FS_PIP 0020000 /* +pos in progress */ -#define FS_ERR 0040000 /* ^error */ -#define FS_ATA 0100000 /* attention active */ -#define FS_REW 0200000 /* +rewinding */ - -#define FS_DYN (FS_ERR | FS_PIP | FS_MOL | FS_WRL | FS_EOT | \ - FS_RDY | FS_PE | FS_BOT) - -/* MTER - 172454 - error register */ - -#define ER_ILF 0000001 /* illegal func */ -#define ER_ILR 0000002 /* illegal register */ -#define ER_RMR 0000004 /* reg mod refused */ -#define ER_MCP 0000010 /* Mbus cpar err NI */ -#define ER_FER 0000020 /* format sel err */ -#define ER_MDP 0000040 /* Mbus dpar err NI */ -#define ER_VPE 0000100 /* vert parity err */ -#define ER_CRC 0000200 /* CRC err NI */ -#define ER_NSG 0000400 /* non std gap err NI */ -#define ER_FCE 0001000 /* frame count err */ -#define ER_ITM 0002000 /* inv tape mark NI */ -#define ER_NXF 0004000 /* wlock or fnc err */ -#define ER_DTE 0010000 /* time err NI */ -#define ER_OPI 0020000 /* op incomplete */ -#define ER_UNS 0040000 /* drive unsafe */ -#define ER_DCK 0100000 /* data check NI */ - -/* MTAS - 172456 - attention summary */ - -#define AS_U0 0000001 /* unit 0 flag */ - -/* MTCC - 172460 - check character, read only */ - -#define CC_MBZ 0177000 /* must be zero */ - -/* MTDB - 172462 - data buffer */ - -/* MTMR - 172464 - maintenance register */ - -#define MR_RW 0177637 /* read/write */ - -/* MTDT - 172466 - drive type */ - -#define DT_NSA 0100000 /* not sect addr */ -#define DT_TAPE 0040000 /* tape */ -#define DT_PRES 0002000 /* slave present */ -#define DT_TM03 0000040 /* TM03 formatter */ -#define DT_OFF 0000010 /* drive off */ -#define DT_TE16 0000011 /* TE16 */ -#define DT_TU45 0000012 /* TU45 */ -#define DT_TU77 0000014 /* TU77 */ - -/* MTSN - 172470 - serial number */ - -/* MTTC - 172472 - tape control register */ - -#define TC_V_UNIT 0 /* unit select */ -#define TC_M_UNIT 07 -#define TC_V_EVN 0000010 /* even parity */ -#define TC_V_FMT 4 /* format select */ -#define TC_M_FMT 017 -#define TC_10C 00 /* PDP-10 core dump */ -#define TC_IND 03 /* industry standard */ -#define TC_V_DEN 8 /* density select */ -#define TC_M_DEN 07 -#define TC_800 3 /* 800 bpi */ -#define TC_1600 4 /* 1600 bpi */ -#define TC_AER 0010000 /* abort on error */ -#define TC_SAC 0020000 /* slave addr change */ -#define TC_FCS 0040000 /* frame count status */ -#define TC_ACC 0100000 /* accelerating NI */ -#define TC_RW 0013777 -#define TC_MBZ 0004000 -#define TC_RIP ((TC_800 << TC_V_DEN) || (TC_10C << TC_V_FMT)) -#define GET_DEN(x) (((x) >> TC_V_DEN) & TC_M_DEN) -#define GET_FMT(x) (((x) >> TC_V_FMT) & TC_M_FMT) -#define GET_DRV(x) (((x) >> TC_V_UNIT) & TC_M_UNIT) - -/* Mapping macros */ - -#define XWC_MBZ 0000001 /* wc<0> mbz */ -#define XBA_MBZ 0000001 /* addr<0> mbz */ -#define XBA_ODD 0000002 /* odd address */ -#define TXFR(b,w,od) if (((b) & XBA_MBZ) || ((w) & XWC_MBZ) || \ - (((b) & XBA_ODD) != ((od) << 1))) { \ - tucs2 = tucs2 | CS2_NEM; \ - ubcs[1] = ubcs[1] | UBCS_TMO; \ - tucs1 = tucs1 & ~CS1_GO; \ - update_tucs (CS1_DONE, drv); \ - return SCPE_OK; \ - } -#define NEWPAGE(v,m) (((v) & PAG_M_OFF) == (m)) -#define MAPM(v,p,f) vpn = PAG_GETVPN (v); \ - if ((vpn >= UMAP_MEMSIZE) || ((ubmap[1][vpn] & \ - (UMAP_VLD | UMAP_DSB | UMAP_RRV)) != \ - (UMAP_VLD | f))) { \ - tucs2 = tucs2 | CS2_NEM; \ - ubcs[1] = ubcs[1] | UBCS_TMO; \ - break; \ - } \ - p = (ubmap[1][vpn] + PAG_GETOFF (v)) & PAMASK; \ - if (MEM_ADDR_NXM (p)) { \ - tucs2 = tucs2 | CS2_NEM; \ - ubcs[1] = ubcs[1] | UBCS_TMO; \ - break; \ - } - -extern d10 *M; /* memory */ -extern int32 int_req; -extern int32 ubmap[UBANUM][UMAP_MEMSIZE]; /* Unibus map */ -extern int32 ubcs[UBANUM]; -extern UNIT cpu_unit; - -int32 tucs1 = 0; /* control/status 1 */ -int32 tuwc = 0; /* word count */ -int32 tuba = 0; /* bus address */ -int32 tufc = 0; /* frame count */ -int32 tucs2 = 0; /* control/status 2 */ -int32 tufs = 0; /* formatter status */ -int32 tuer = 0; /* error status */ -int32 tucc = 0; /* check character */ -int32 tudb = 0; /* data buffer */ -int32 tumr = 0; /* maint register */ -int32 tutc = 0; /* tape control */ -int32 tuiff = 0; /* INTR flip/flop */ -int32 tu_time = 10; /* record latency */ -int32 tu_stopioe = 1; /* stop on error */ -int32 tu_log = 0; /* debug */ -int32 reg_in_fmtr[32] = { /* reg in formatter */ - 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 - }; -int32 reg_in_fmtr1[32] = { /* rmr if write + go */ - 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 - }; -int32 fmt_test[16] = { /* fmt bytes/10 wd */ - 5, 0, 5, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; -static char *tu_fname[CS1_N_FNC] = { - "NOP", "UNLD", "2", "REW", "FCLR", "5", "6", "7", - "RIP", "11", "ERASE", "WREOF", "SPCF", "SPCR", "16", "17", - "20", "21", "22", "23", "WRCHKF", "25", "26", "WRCHKR", - "WRITE", "31", "32", "33", "READF", "35", "36" "READR" - }; -static uint8 *xbuf = NULL; /* xfer buffer */ - -t_stat tu_rd (int32 *data, int32 PA, int32 access); -t_stat tu_wr (int32 data, int32 PA, int32 access); -int32 tu_inta (void); -t_stat tu_svc (UNIT *uptr); -t_stat tu_reset (DEVICE *dptr); -t_stat tu_attach (UNIT *uptr, char *cptr); -t_stat tu_detach (UNIT *uptr); -t_stat tu_boot (int32 unitno, DEVICE *dptr); -void tu_go (int32 drv); -void set_tuer (int32 flag); -void update_tucs (int32 flag, int32 drv); -t_stat tu_map_err (UNIT *uptr, t_stat st, t_bool qdt); - -/* TU data structures - - tu_dev TU device descriptor - tu_unit TU unit list - tu_reg TU register list - tu_mod TU modifier list -*/ - -DIB tu_dib = { - IOBA_TU, IOLN_TU, &tu_rd, &tu_wr, - 1, IVCL (TU), VEC_TU, { &tu_inta } - }; - -UNIT tu_unit[] = { - { UDATA (&tu_svc, UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE, 0) }, - { 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) }, - { ORDATA (MTWC, tuwc, 16) }, - { ORDATA (MTBA, tuba, 16) }, - { ORDATA (MTFC, tufc, 16) }, - { ORDATA (MTCS2, tucs2, 16) }, - { ORDATA (MTFS, tufs, 16) }, - { ORDATA (MTER, tuer, 16) }, - { ORDATA (MTCC, tucc, 16) }, - { ORDATA (MTDB, tudb, 16) }, - { ORDATA (MTMR, tumr, 16) }, - { ORDATA (MTTC, tutc, 16) }, - { FLDATA (IFF, tuiff, 0) }, - { FLDATA (INT, int_req, INT_V_TU) }, - { FLDATA (DONE, tucs1, CSR_V_DONE) }, - { FLDATA (IE, tucs1, CSR_V_IE) }, - { FLDATA (STOP_IOE, tu_stopioe, 0) }, - { DRDATA (TIME, tu_time, 24), PV_LEFT }, - { URDATA (UST, tu_unit[0].USTAT, 8, 17, 0, TU_NUMDR, 0) }, - { URDATA (POS, tu_unit[0].pos, 10, T_ADDR_W, 0, - TU_NUMDR, PV_LEFT | REG_RO) }, - { ORDATA (LOG, tu_log, 8), REG_HIDDEN }, - { NULL } - }; - -MTAB tu_mod[] = { - { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, - { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT", - &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, - { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", "CAPACITY", - &sim_tape_set_capac, &sim_tape_show_capac, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, - NULL, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, - NULL, &show_vec, NULL }, - { 0 } - }; - -DEVICE tu_dev = { - "TU", tu_unit, tu_reg, tu_mod, - TU_NUMDR, 10, 31, 1, 8, 8, - NULL, NULL, &tu_reset, - &tu_boot, &tu_attach, &tu_detach, - &tu_dib, DEV_UBUS | DEV_DEBUG | DEV_TAPE - }; - -/* I/O dispatch routine, I/O addresses 17772440 - 17772472 */ - -t_stat tu_rd (int32 *data, int32 PA, int32 access) -{ -int32 fmtr, drv, j; - -fmtr = GET_FMTR (tucs2); /* get current fmtr */ -drv = GET_DRV (tutc); /* get current drive */ -j = (PA >> 1) & 017; /* get reg offset */ -if (reg_in_fmtr[j] && (fmtr != 0)) { /* nx formatter */ - tucs2 = tucs2 | CS2_NEF; /* set error flag */ - update_tucs (CS1_SC, drv); /* request intr */ - *data = 0; - return SCPE_OK; - } - -update_tucs (0, drv); /* update status */ -switch (j) { /* decode PA<4:1> */ - - case 000: /* MTCS1 */ - if (fmtr != 0) - *data = tucs1 & ~CS1_DRV; - else *data = tucs1; - break; - - case 001: /* MTWC */ - *data = tuwc; - break; - - case 002: /* MTBA */ - *data = tuba = tuba & ~BA_MBZ; - break; - - case 003: /* MTFC */ - *data = tufc; - break; - - case 004: /* MTCS2 */ - *data = tucs2 = (tucs2 & ~CS2_MBZ) | CS2_IR | CS2_OR; - break; - - case 005: /* MTFS */ - *data = tufs & 0177777; /* mask off rewind */ - break; - - case 006: /* MTER */ - *data = tuer; - break; - - case 007: /* MTAS */ - *data = (tufs & FS_ATA)? AS_U0: 0; - break; - - case 010: /* MTCC */ - *data = tucc = tucc & ~CC_MBZ; - break; - - case 011: /* MTDB */ - *data = tudb; - break; - - case 012: /* MTMR */ - *data = tumr; - break; - - case 013: /* MTDT */ - *data = DT_NSA | DT_TAPE | DT_TM03 | - ((tu_unit[drv].flags & UNIT_DIS)? DT_OFF: (DT_PRES | DT_TU45)); - break; - - case 014: /* MTSN */ - *data = (tu_unit[drv].flags & UNIT_DIS)? 0: 040 | (drv + 1); - break; - - case 015: /* MTTC */ - *data = tutc = tutc & ~TC_MBZ; - break; - - default: /* all others */ - set_tuer (ER_ILR); - update_tucs (0, drv); - break; - } - -return SCPE_OK; -} - -t_stat tu_wr (int32 data, int32 PA, int32 access) -{ -int32 cs1f, fmtr, drv, j; - -cs1f = 0; /* no int on cs1 upd */ -fmtr = GET_FMTR (tucs2); /* get formatter */ -drv = GET_DRV (tutc); /* get current unit */ -j = (PA >> 1) & 017; /* get reg offset */ -if (reg_in_fmtr[j] && (fmtr != 0)) { /* nx formatter */ - tucs2 = tucs2 | CS2_NEF; /* set error flag */ - update_tucs (CS1_SC, drv); /* request intr */ - return SCPE_OK; - } -if (reg_in_fmtr1[j] && ((tucs1 & CS1_DONE) == 0)) { /* formatter busy? */ - set_tuer (ER_RMR); /* won't write */ - update_tucs (0, drv); - return SCPE_OK; - } - -switch (j) { /* decode PA<4:1> */ - - case 000: /* MTCS1 */ - if ((access == WRITEB) && (PA & 1)) - data = data << 8; - if (data & CS1_TRE) { /* error clear? */ - tucs1 = tucs1 & ~CS1_TRE; /* clr CS1 */ - tucs2 = tucs2 & ~CS2_ERR; /* clr CS2<15:8> */ - } - if ((access == WRITE) || (PA & 1)) { /* hi byte write? */ - if (tucs1 & CS1_DONE) /* done set? */ - tucs1 = (tucs1 & ~CS1_UAE) | (data & CS1_UAE); - } - if ((access == WRITE) || !(PA & 1)) { /* lo byte write? */ - if ((data & CS1_DONE) && (data & CS1_IE)) /* to DONE+IE? */ - tuiff = 1; /* set CSTB INTR */ - tucs1 = (tucs1 & ~CS1_IE) | (data & CS1_IE); - if (fmtr != 0) { /* nx formatter? */ - tucs2 = tucs2 | CS2_NEF; /* set error flag */ - cs1f = CS1_SC; /* req interrupt */ - } - else if (tucs1 & CS1_GO) { /* busy? */ - if (tucs1 & CS1_DONE) - set_tuer (ER_RMR); - else tucs2 = tucs2 | CS2_PGE; - } - else { - tucs1 = (tucs1 & ~CS1_DRV) | (data & CS1_DRV); - if (tucs1 & CS1_GO) - tu_go (drv); - } - } - break; - - case 001: /* MTWC */ - if (access == WRITEB) - data = (PA & 1)? - (tuwc & 0377) | (data << 8): (tuwc & ~0377) | data; - tuwc = data; - break; - - case 002: /* MTBA */ - if (access == WRITEB) - data = (PA & 1)? - (tuba & 0377) | (data << 8): (tuba & ~0377) | data; - tuba = data & ~BA_MBZ; - break; - - case 003: /* MTFC */ - if (access == WRITEB) - data = (PA & 1)? - (tufc & 0377) | (data << 8): (tufc & ~0377) | data; - tufc = data; - tutc = tutc | TC_FCS; /* set fc flag */ - break; - - case 004: /* MTCS2 */ - if ((access == WRITEB) && (PA & 1)) - data = data << 8; - if (data & CS2_CLR) /* init? */ - tu_reset (&tu_dev); - else { - if ((data & ~tucs2) & (CS2_PE | CS2_MXF)) - cs1f = CS1_SC; /* diagn intr */ - if (access == WRITEB) /* merge data */ - data = (tucs2 & ((PA & 1)? 0377: 0177400)) | data; - tucs2 = (tucs2 & ~CS2_RW) | (data & CS2_RW) | CS2_IR | CS2_OR; - } - break; - - case 007: /* MTAS */ - if ((access == WRITEB) && (PA & 1)) - break; - if (data & AS_U0) - tufs = tufs & ~FS_ATA; - break; - - case 011: /* MTDB */ - if (access == WRITEB) - data = (PA & 1)? - (tudb & 0377) | (data << 8): (tudb & ~0377) | data; - tudb = data; - break; - - case 012: /* MTMR */ - if (access == WRITEB) - data = (PA & 1)? - (tumr & 0377) | (data << 8): (tumr & ~0377) | data; - tumr = (tumr & ~MR_RW) | (data & MR_RW); - break; - - case 015: /* MTTC */ - if (access == WRITEB) - data = (PA & 1)? - (tutc & 0377) | (data << 8): (tutc & ~0377) | data; - tutc = (tutc & ~TC_RW) | (data & TC_RW) | TC_SAC; - drv = GET_DRV (tutc); - break; - - case 005: /* MTFS */ - case 006: /* MTER */ - case 010: /* MTCC */ - case 013: /* MTDT */ - case 014: /* MTSN */ - break; /* read only */ - - default: /* all others */ - set_tuer (ER_ILR); - break; - } /* end switch */ - -update_tucs (cs1f, drv); /* update status */ -return SCPE_OK; -} - -/* New magtape command */ - -void tu_go (int32 drv) -{ -int32 fnc, den; -UNIT *uptr; - -fnc = GET_FNC (tucs1); /* get function */ -den = GET_DEN (tutc); /* get density */ -uptr = tu_dev.units + drv; /* get unit */ -if (DEBUG_PRS (tu_dev)) - fprintf (sim_deb, ">>TU%d STRT: fnc=%s, cs1=%06o, cs2=%06o, ba=%06o, wc=%06o, fc=%06o, fs=%06o, er=%06o, pos=%d\n", - drv, tu_fname[fnc], tucs1, tucs2, tuba, tuwc, tufc, tufs, tuer, uptr->pos); -if ((fnc != FNC_FCLR) && /* not clear & err */ - ((tufs & FS_ERR) || sim_is_active (uptr))) { /* or in motion? */ - set_tuer (ER_ILF); /* set err, ATN */ - tucs1 = tucs1 & ~CS1_GO; /* clear go */ - update_tucs (CS1_SC, drv); /* request intr */ - return; - } -tufs = tufs & ~FS_ATA; /* clear attention */ -tutc = tutc & ~TC_SAC; /* clear addr change */ - -switch (fnc) { /* case on function */ - case FNC_FCLR: /* drive clear */ - tuer = 0; /* clear errors */ - tutc = tutc & ~TC_FCS; /* clear fc status */ - tufs = tufs & ~(FS_SAT | FS_SSC | FS_ID | FS_ERR); - if (!(uptr->TU_STATEFLAGS & TUS_ATTPENDING)) - sim_cancel (uptr); /* stop motion, not on-line delay */ - uptr->USTAT = 0; /* fall through */ - case FNC_NOP: - tucs1 = tucs1 & ~CS1_GO; /* no operation */ - return; - - case FNC_RIP: /* read-in preset */ - if ((tufs & FS_MOL) == 0) { /* unattached? */ - set_tuer (ER_UNS); - break; - } - tutc = TC_RIP; /* density = 800 */ - sim_tape_rewind (&tu_unit[0]); /* rewind unit 0 */ - tu_unit[0].USTAT = 0; - tucs1 = tucs1 & ~CS1_GO; - tufs = tufs & ~FS_TMK; - return; - - case FNC_UNLOAD: /* unload */ - if ((tufs & FS_MOL) == 0) { /* unattached? */ - set_tuer (ER_UNS); - break; - } - detach_unit (uptr); - uptr->USTAT = FS_REW; - sim_activate (uptr, tu_time); - tucs1 = tucs1 & ~CS1_GO; - tufs = tufs & ~FS_TMK; - return; - - case FNC_REWIND: - if ((tufs & FS_MOL) == 0) { /* unattached? */ - set_tuer (ER_UNS); - break; - } - uptr->USTAT = FS_PIP | FS_REW; - sim_activate (uptr, tu_time); - tucs1 = tucs1 & ~CS1_GO; - tufs = tufs & ~FS_TMK; - return; - - case FNC_SPACEF: - if ((tufs & FS_MOL) == 0) { /* unattached? */ - set_tuer (ER_UNS); - break; - } - if (sim_tape_eot (uptr) || ((tutc & TC_FCS) == 0)) { - set_tuer (ER_NXF); - break; - } - uptr->USTAT = FS_PIP; - goto GO_XFER; - - case FNC_SPACER: - if ((tufs & FS_MOL) == 0) { /* unattached? */ - set_tuer (ER_UNS); - break; - } - if (sim_tape_bot (uptr) || ((tutc & TC_FCS) == 0)) { - set_tuer (ER_NXF); - break; - } - uptr->USTAT = FS_PIP; - goto GO_XFER; - - case FNC_WREOF: /* write tape mark */ - case FNC_ERASE: /* erase */ - if ((tufs & FS_MOL) == 0) { /* unattached? */ - set_tuer (ER_UNS); - break; - } - if (sim_tape_wrp (uptr)) { /* write locked? */ - set_tuer (ER_NXF); - break; - } - if (fmt_test[GET_FMT (tutc)] == 0) { /* invalid format? */ - set_tuer (ER_FER); - break; - } - if (uptr->UDENS == UD_UNK) /* set dens */ - uptr->UDENS = den; - uptr->USTAT = 0; - goto GO_XFER; - - case FNC_WCHKR: /* wchk = read */ - case FNC_READR: /* read rev */ - if (tufs & FS_BOT) { /* beginning of tape? */ - set_tuer (ER_NXF); - break; - } - goto DATA_XFER; - - case FNC_WRITE: /* write */ - if (((tutc & TC_FCS) == 0) || /* frame cnt = 0? */ - ((den == TC_800) && (tufc > 0777765))) { /* NRZI, fc < 13? */ - set_tuer (ER_NXF); - break; - } - case FNC_WCHKF: /* wchk = read */ - case FNC_READF: /* read */ - DATA_XFER: - if ((tufs & FS_MOL) == 0) { /* unattached? */ - set_tuer (ER_UNS); - break; - } - if (fmt_test[GET_FMT (tutc)] == 0) { /* invalid format? */ - set_tuer (ER_FER); - break; - } - if (uptr->UDENS == UD_UNK) /* set dens */ - uptr->UDENS = den; - uptr->USTAT = 0; - tucs1 = tucs1 & ~CS1_DONE; /* clear done */ - GO_XFER: - tucs2 = tucs2 & ~CS2_ERR; /* clear errors */ - tucs1 = tucs1 & ~(CS1_TRE | CS1_MCPE); - tufs = tufs & ~(FS_TMK | FS_ID); /* clear eof, id */ - sim_activate (uptr, tu_time); - return; - - default: /* all others */ - set_tuer (ER_ILF); /* not supported */ - break; - } /* end case function */ - -tucs1 = tucs1 & ~CS1_GO; /* clear go */ -update_tucs (CS1_SC, drv); /* set intr */ -return; -} - -/* Unit service - - Complete movement or data transfer command - Unit must exist - can't remove an active unit - Unit must be attached - detach cancels in progress operations -*/ - -t_stat tu_svc (UNIT *uptr) -{ -int32 fnc, fmt, i, j, k, wc10, ba10; -int32 ba, fc, wc, drv, mpa10 = 0, vpn; -d10 val, v[4]; -t_mtrlnt tbc; -t_stat st, r = SCPE_OK; - -drv = (int32) (uptr - tu_dev.units); /* get drive # */ - -/* Set MOL for a delayed attach */ - -if (uptr->TU_STATEFLAGS & TUS_ATTPENDING) { - uptr->TU_STATEFLAGS &= ~TUS_ATTPENDING; /* Allow transition to on-line */ - tufs = tufs | FS_ATA | FS_SSC; /* set attention */ - if ((GET_FMTR (tucs2) == 0) && (GET_DRV (tutc) == drv)) /* selected drive? */ - tufs = tufs | FS_SAT; /* set slave attn */ - update_tucs (CS1_SC, drv); /* update status */ - return SCPE_OK; -} - -if (uptr->USTAT & FS_REW) { /* rewind or unload? */ - sim_tape_rewind (uptr); /* rewind tape */ - uptr->USTAT = 0; /* clear status */ - tufs = tufs | FS_ATA | FS_SSC; - update_tucs (CS1_SC, drv); /* update status */ - return SCPE_OK; - } - -fnc = GET_FNC (tucs1); /* get command */ -fmt = GET_FMT (tutc); /* get format */ -ba = GET_UAE (tucs1) | tuba; /* get bus address */ -wc = 0200000 - tuwc; /* get word count */ -fc = 0200000 - tufc; /* get frame count */ -wc10 = wc >> 1; /* 10 word count */ -ba10 = ba >> 2; /* 10 word addr */ -uptr->USTAT = 0; /* clear status */ - -switch (fnc) { /* case on function */ - -/* Non-data transfer commands - set ATA when done */ - - case FNC_SPACEF: /* space forward */ - do { - tufc = (tufc + 1) & 0177777; /* incr fc */ - if ((st = sim_tape_sprecf (uptr, &tbc))) { /* space rec fwd, err? */ - r = tu_map_err (uptr, st, 0); /* map error */ - break; - } - } while ((tufc != 0) && !sim_tape_eot (uptr)); - if (tufc != 0) - set_tuer (ER_FCE); - else tutc = tutc & ~TC_FCS; - tufs = tufs | FS_ATA; - break; - - case FNC_SPACER: /* space reverse */ - do { - tufc = (tufc + 1) & 0177777; /* incr wc */ - if ((st = sim_tape_sprecr (uptr, &tbc))) { /* space rec rev, err? */ - r = tu_map_err (uptr, st, 0); /* map error */ - break; - } - } while (tufc != 0); - if (tufc != 0) - set_tuer (ER_FCE); - else tutc = tutc & ~TC_FCS; - tufs = tufs | FS_ATA; - break; - - case FNC_WREOF: /* write end of file */ - if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ - r = tu_map_err (uptr, st, 0); /* map error */ - tufs = tufs | FS_ATA; - break; - - case FNC_ERASE: - if (sim_tape_wrp (uptr)) /* write protected? */ - r = tu_map_err (uptr, MTSE_WRP, 0); /* map error */ - tufs = tufs | FS_ATA; - break; - -/* Data transfer commands - - These commands must take into account the action of the "bit fiddler", which - converts between PDP-10 format and tape format. Only two tape formats are - supported: - - PDP-10 core dump: write 36b as byte 0/byte 1/byte 2/byte 3/0000'last nibble - industry mode: write hi 32b as byte 0/byte 1/byte 2/byte 3 - - These commands must also take into account the action of the Unibus adapter, - which munges PDP-10 addresses through the Unibus map. -*/ - - case FNC_READF: /* read */ - case FNC_WCHKF: /* wcheck = read */ - tufc = 0; /* clear frame count */ - if ((uptr->UDENS == TC_1600) && sim_tape_bot (uptr)) - tufs = tufs | FS_ID; /* PE BOT? ID burst */ - TXFR (ba, wc, 0); /* validate transfer */ - if ((st = sim_tape_rdrecf (uptr, xbuf, &tbc, MT_MAXFR))) {/* read fwd */ - r = tu_map_err (uptr, st, 1); /* map error */ - break; /* done */ - } - for (i = j = 0; (i < wc10) && (j < ((int32) tbc)); i++) { - if ((i == 0) || NEWPAGE (ba10 + i, 0)) { /* map new page */ - MAPM (ba10 + i, mpa10, 0); - } - for (k = 0; k < 4; k++) - v[k] = xbuf[j++]; - val = (v[0] << 28) | (v[1] << 20) | (v[2] << 12) | (v[3] << 4); - if (fmt == TC_10C) - val = val | ((d10) xbuf[j++] & 017); - if (fnc == FNC_READF) /* read? store */ - M[mpa10] = val; - else if (M[mpa10] != val) { /* wchk, mismatch? */ - tucs2 = tucs2 | CS2_WCE; /* flag, stop */ - break; - } - mpa10 = mpa10 + 1; - } /* end for */ - tufc = tbc & 0177777; - tuwc = (tuwc + (i << 1)) & 0177777; - ba = ba + (i << 2); - if (tuwc) /* short record? */ - set_tuer (ER_FCE); - break; - - case FNC_WRITE: /* write */ - TXFR (ba, wc, 0); /* validate transfer */ - for (i = j = 0; (i < wc10) && (j < fc); i++) { - if ((i == 0) || NEWPAGE (ba10 + i, 0)) { /* map new page */ - MAPM (ba10 + i, mpa10, 0); - } - val = M[mpa10]; - xbuf[j++] = (uint8) ((val >> 28) & 0377); - xbuf[j++] = (uint8) ((val >> 20) & 0377); - xbuf[j++] = (uint8) ((val >> 12) & 0377); - xbuf[j++] = (uint8) ((val >> 4) & 0377); - if (fmt == TC_10C) - xbuf[j++] = (uint8) (val & 017); - mpa10 = mpa10 + 1; - } /* end for */ - if (j < fc) /* short record? */ - fc = j; - if ((st = sim_tape_wrrecf (uptr, xbuf, fc))) /* write rec, err? */ - r = tu_map_err (uptr, st, 1); /* map error */ - else { - tufc = (tufc + fc) & 0177777; - if (tufc == 0) - tutc = tutc & ~TC_FCS; - tuwc = (tuwc + (i << 1)) & 0177777; - ba = ba + (i << 2); - } - break; - - case FNC_READR: /* read reverse */ - case FNC_WCHKR: /* wcheck = read */ - tufc = 0; /* clear frame count */ - TXFR (ba, wc, 1); /* validate xfer rev */ - if ((st = sim_tape_rdrecr (uptr, xbuf + 4, &tbc, MT_MAXFR))) {/* read rev */ - r = tu_map_err (uptr, st, 1); /* map error */ - break; /* done */ - } - for (i = 0; i < 4; i++) - xbuf[i] = 0; - for (i = 0, j = tbc + 4; (i < wc10) && (j >= 4); i++) { - if ((i == 0) || NEWPAGE (ba10 - i, PAG_M_OFF)) { /* map page */ - MAPM (ba10 - i, mpa10, UMAP_RRV); - } - val = ((fmt == TC_10C)? (((d10) xbuf [--j]) & 017): 0); - for (k = 0; k < 4; k++) - v[k] = xbuf[--j]; - val = val | (v[0] << 4) | (v[1] << 12) | (v[2] << 20) | (v[3] << 28); - if (fnc == FNC_READR) /* read? store */ - M[mpa10] = val; - else if (M[mpa10] != val) { /* wchk, mismatch? */ - tucs2 = tucs2 | CS2_WCE; /* flag, stop */ - break; - } - mpa10 = mpa10 - 1; - } /* end for */ - tufc = tbc & 0177777; - tuwc = (tuwc + (i << 1)) & 0177777; - ba = ba - (i << 2); - if (tuwc) /* short record? */ - set_tuer (ER_FCE); - break; - } /* end case */ - -tucs1 = (tucs1 & ~CS1_UAE) | ((ba >> (16 - CS1_V_UAE)) & CS1_UAE); -tuba = ba & 0177777; /* update mem addr */ -tucs1 = tucs1 & ~CS1_GO; /* clear go */ -if (fnc >= FNC_XFER) /* data xfer? */ - update_tucs (CS1_DONE, drv); -else update_tucs (CS1_SC, drv); /* no, set attn */ -if (DEBUG_PRS (tu_dev)) - fprintf (sim_deb, ">>TU%d DONE: fnc=%s, cs1=%06o, cs2=%06o, ba=%06o, wc=%06o, fc=%06o, fs=%06o, er=%06o, pos=%d\n", - drv, tu_fname[fnc], tucs1, tucs2, tuba, tuwc, tufc, tufs, tuer, uptr->pos); -return SCPE_OK; -} - -/* Formatter error */ - -void set_tuer (int32 flag) -{ -tuer = tuer | flag; -tufs = tufs | FS_ATA; -tucs1 = tucs1 | CS1_SC; -return; -} - -/* Controller status update - - Check for done transition - Update drive status - Update MTCS1 - Update interrupt request -*/ - -void update_tucs (int32 flag, int32 drv) -{ -int32 act = sim_activate_time (&tu_unit[drv]); - -if ((flag & ~tucs1) & CS1_DONE) /* DONE 0 to 1? */ - tuiff = (tucs1 & CS1_IE)? 1: 0; /* CSTB INTR <- IE */ -if (GET_FMTR (tucs2) == 0) { /* formatter present? */ - tufs = (tufs & ~FS_DYN) | FS_FPR; - if (tu_unit[drv].TU_STATEFLAGS & TUS_ATTPENDING) /* Delayed on-line timer running? */ - act = 0; /* Not a tape motion op */ - else { - 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 (sim_tape_wrp (&tu_unit[drv])) - tufs = tufs | FS_WRL; - if (!act) { - if (sim_tape_bot (&tu_unit[drv])) - tufs = tufs | FS_BOT; - if (sim_tape_eot (&tu_unit[drv])) - tufs = tufs | FS_EOT; - } - } - } - if (tuer) - tufs = tufs | FS_ERR; - } -else tufs = 0; -tucs1 = (tucs1 & ~(CS1_SC | CS1_MCPE | CS1_MBZ)) | CS1_DVA | flag; -if (tucs2 & CS2_ERR) - tucs1 = tucs1 | CS1_TRE | CS1_SC; -else if (tucs1 & CS1_TRE) - tucs1 = tucs1 | CS1_SC; -if (tufs & FS_ATA) - tucs1 = tucs1 | CS1_SC; -if (tuiff || ((tucs1 & CS1_SC) && (tucs1 & CS1_DONE) && (tucs1 & CS1_IE))) - int_req = int_req | INT_TU; -else int_req = int_req & ~INT_TU; -if ((tucs1 & CS1_DONE) && tufs && !act) - tufs = tufs | FS_RDY; -return; -} - -/* Interrupt acknowledge */ - -int32 tu_inta (void) -{ -tucs1 = tucs1 & ~CS1_IE; /* clear int enable */ -tuiff = 0; /* clear CSTB INTR */ -return VEC_TU; /* acknowledge */ -} - -/* Map tape error status - - Note that tape mark on a data transfer sets FCE and Massbus EXC */ - -t_stat tu_map_err (UNIT *uptr, t_stat st, t_bool qdt) -{ -switch (st) { - - case MTSE_FMT: /* illegal fmt */ - case MTSE_UNATT: /* not attached */ - set_tuer (ER_NXF); /* can't execute */ - if (qdt) /* data xfr? set TRE */ - tucs1 = tucs1 | CS1_TRE; - case MTSE_OK: /* no error */ - return SCPE_IERR; - - case MTSE_TMK: /* end of file */ - tufs = tufs | FS_TMK; - if (qdt) { /* data transfer? */ - set_tuer (ER_FCE); /* set FCE */ - tucs1 = tucs1 | CS1_TRE; - } - break; - - case MTSE_IOERR: /* IO error */ - set_tuer (ER_VPE); /* flag error */ - if (qdt) /* data xfr? set TRE */ - tucs1 = tucs1 | CS1_TRE; - if (tu_stopioe) - return SCPE_IOERR; - break; - - case MTSE_INVRL: /* invalid rec lnt */ - set_tuer (ER_VPE); /* flag error */ - if (qdt) /* data xfr? set TRE */ - tucs1 = tucs1 | CS1_TRE; - return SCPE_MTRLNT; - - case MTSE_RECE: /* record in error */ - set_tuer (ER_CRC); /* set crc err */ - if (qdt) /* data xfr? set TRE */ - tucs1 = tucs1 | CS1_TRE; - break; - - case MTSE_EOM: /* end of medium */ - set_tuer (ER_OPI); /* incomplete */ - if (qdt) /* data xfr? set TRE */ - tucs1 = tucs1 | CS1_TRE; - break; - - case MTSE_BOT: /* reverse into BOT */ - break; - - case MTSE_WRP: /* write protect */ - set_tuer (ER_NXF); /* can't execute */ - if (qdt) /* data xfr? set TRE */ - tucs1 = tucs1 | CS1_TRE; - break; - } - -return SCPE_OK; -} - -/* Reset routine */ - -t_stat tu_reset (DEVICE *dptr) -{ -int32 u; -UNIT *uptr; - -tucs1 = CS1_DVA | CS1_DONE; -tucs2 = CS2_IR | CS2_OR; -tuba = 0; -tuwc = 0; -tufc = 0; -tuer = 0; -tufs = FS_FPR | FS_RDY; -if (sim_switches & SWMASK ('P')) /* powerup? clr TC */ - tutc = 0; -else tutc = tutc & ~TC_FCS; /* no, clr */ -tuiff = 0; /* clear CSTB INTR */ -int_req = int_req & ~INT_TU; /* clear interrupt */ -for (u = 0; u < TU_NUMDR; u++) { /* loop thru units */ - uptr = tu_dev.units + u; - sim_tape_reset (uptr); /* clear pos flag */ - if (!(uptr->TU_STATEFLAGS & TUS_ATTPENDING)) /* delayed on-line must survive massbus clear */ - sim_cancel (uptr); /* cancel activity */ - else if (!sim_is_active(uptr) ) - sim_activate (uptr, SPINUPDLY); - - uptr->USTAT = 0; - } -if (xbuf == NULL) - xbuf = (uint8 *) calloc (MT_MAXFR + 4, sizeof (uint8)); -if (xbuf == NULL) - return SCPE_MEM; -return SCPE_OK; -} - -/* Attach routine */ - -t_stat tu_attach (UNIT *uptr, char *cptr) -{ -int32 drv = uptr - tu_dev.units; -t_stat r; - -r = sim_tape_attach (uptr, cptr); -if (r != SCPE_OK) - return r; -uptr->USTAT = 0; /* clear unit status */ -uptr->UDENS = UD_UNK; /* unknown density */ -/* Delay setting MOL since we may have just detached a previous file. - * In that case, the OS must see MOL clear, so that it will know that the - * drive was off-line. This ensures that the OS will detect a tape change. - * 100 msec should suffice - though a real operator would take longer! - * Here, we ensure that the off-line transition from detach causes an attention - * interrupt. The on-line transition will happen later. - */ -tufs = tufs | FS_ATA | FS_SSC; /* set attention */ -if ((GET_FMTR (tucs2) == 0) && (GET_DRV (tutc) == drv)) /* selected drive? */ - tufs = tufs | FS_SAT; /* set slave attn */ -uptr->TU_STATEFLAGS |= TUS_ATTPENDING; -update_tucs (CS1_SC, drv); /* update status */ -sim_cancel(uptr); -sim_activate (uptr,SPINUPDLY); -return r; -} - -/* Detach routine */ - -t_stat tu_detach (UNIT* uptr) -{ -int32 drv = uptr - tu_dev.units; - -if (!(uptr->flags & UNIT_ATT)) /* attached? */ - return SCPE_OK; -if (sim_is_active (uptr)) { /* unit active? */ - sim_cancel (uptr); /* cancel operation */ - tuer = tuer | ER_UNS; /* set formatter error */ - if (uptr->TU_STATEFLAGS & TUS_ATTPENDING) - uptr->TU_STATEFLAGS &= ~TUS_ATTPENDING; - else if ((uptr->USTAT & FS_REW) == 0) /* data transfer? */ - tucs1 = tucs1 | CS1_DONE | CS1_TRE; /* set done, err */ - } -uptr->USTAT = 0; /* clear status flags */ -tufs = tufs | FS_ATA | FS_SSC; /* set attention */ -if ((GET_FMTR (tucs2) == 0) && (GET_DRV (tutc) == drv)) /* selected drive? */ - tufs = tufs | FS_SAT; /* set slave attn */ -uptr->flags &= ~UNIT_ATT; /* Ensure MOL is cleared */ -update_tucs (CS1_SC, drv); /* update status */ -uptr->flags |= UNIT_ATT; -return sim_tape_detach (uptr); -} - -/* Device bootstrap */ -/* Note that the dec and ITS boot code is word for word identical, - * except for the IO instructions. The ITS instructions encode the - * UBA number. No attempt is made to allow UBA selection under ITS, - * though it should work with the DEC rom. - * The sequence is: - * controller clear - to clear controller errors - * formatter select - to gain access to the formatter registers. (since only - * one formatter is supported, and it's assumed to be zero, this isn't strictly - * necessary. But maybe someday...) - * wait for MOL to appear. - * Drive clear - to clear any errors in the transport, including attention from on-line. - * Space forward one file - this is the KS CPU microcode, which the simulator doesn't - * use. - * Read the preboot (next level bootstrap) from the tape into page 1. - * Each operation produces erors - for one, the frame count is not exact. - * They are cleared, and the expected ones ignored. If no unexpected - * errors are encountered, control is transferred to the preboot. - */ - -#define BOOT_START 0377000 /* start */ -#define BOOT_LEN (sizeof (boot_rom_dec) / sizeof (d10)) - -static const d10 boot_rom_dec[] = { - INT64_C(0510040000000)+FE_RHBASE, /* boot:hllz 1,FE_RHBASE ; uba # */ - INT64_C(0201000040001), /* movei 0,40001 ; vld,pg 1 */ - INT64_C(0713001000000)+((IOBA_UBMAP+1) & RMASK), /* wrio 0,763001(1); set ubmap */ - INT64_C(0200040000000)+FE_RHBASE, /* move 1,FE_RHBASE */ - INT64_C(0201000000040), /* movei 0,40 ; ctrl reset */ - INT64_C(0713001000010), /* wrio 0,10(1) ; ->MTFS */ - INT64_C(0200300000000)+FE_UNIT, /* move 6,FE_UNIT ; fmtr */ - INT64_C(0713301000010), /* wrio 6,10(1) ; ->MTCS2 */ - - INT64_C(0200240000000)+FE_MTFMT, /*10 move 5,FE_MTFMT ; slave, dens, fmt */ - INT64_C(0713241000032), /* wrio 5,32(1) ; ->MTTC */ - INT64_C(0712001000012), /* rdio 0,12(1) ; MTFS */ - INT64_C(0640000010600), /* trc 0,10600 ; MOL + DPR + RDY */ - INT64_C(0642000010600), /* trce 0,10600 ; */ - INT64_C(0254000377012), /* jrst .-3 ; wait */ - INT64_C(0201000000011), /* movei 0,11 ; clr+go */ - INT64_C(0713001000000), /* wrio 0,0(1) ; ->MTCS1 */ - - INT64_C(0201000000377), /*20 movei 0,1 ; Formatter */ - INT64_C(0242006000000), /* lsh 0,(6) ; attn bit */ - INT64_C(0713001000016), /* wrio 0,16(1) ; Clear on-line attn */ - INT64_C(0201100000031), /* movei 2,31 ; space f */ - INT64_C(0265740377030), /* jsp 17,tpop ; skip ucode */ - INT64_C(0201100000071), /* movei 2,71 ; read f */ - INT64_C(0265740377030), /* jsp 17,tpop ; read boot */ - INT64_C(0254000001000), /* jrst 1000 ; start */ - - /*30 */ - INT64_C(0713241000032), /* tpop:wrio 5,32(1) ; ->MTTC */ - INT64_C(0201000000011), /* movei 0,11 ; clr+go */ - INT64_C(0713001000000), /* wrio 0,0(1) ; ->MTCS1 */ - INT64_C(0201140176000), /* movei 3,176000 ; wd cnt */ - INT64_C(0713141000002), /* wrio 3,2(1) ; ->MTWC */ - INT64_C(0201200004000), /* movei 4,4000 ; addr */ - INT64_C(0713201000004), /* wrio 4,4(1) ; ->MTBA */ - INT64_C(0400400000000), /* setz 10, ; max fc */ - - INT64_C(0713401000006), /*40 wrio 10,6(1) ; ->MTFC */ - INT64_C(0713301000010), /* wrio 6,10(1) ; ->MTCS2 reset errs */ - INT64_C(0713241000032), /* wrio 5,32(1) ; ->MTTC reset errs */ - INT64_C(0713101000000), /* wrio 2,0(1) ; OP ->MTCS1 */ - INT64_C(0712341000012), /* rdio 7,12(1) ; read FS */ - INT64_C(0606340000200), /* trnn 7,200 ; test rdy */ - INT64_C(0254000377044), /* jrst .-2 ; loop */ - INT64_C(0606340040000), /* trnn 7,40000 ; test err */ - - INT64_C(0254017000000), /*50 jrst 0(17) ; return */ - INT64_C(0712341000014), /* rdio 7,14(1) ; read err */ - INT64_C(0302340001000), /* caie 7,1000 ; fce? */ - INT64_C(0254200377053), /* halt . */ - INT64_C(0254017000000), /* jrst 0(17) ; return */ - }; - -static const d10 boot_rom_its[] = { - INT64_C(0510040000000)+FE_RHBASE, /* boot:hllz 1,FE_RHBASE ; uba # - not used */ - INT64_C(0201000040001), /* movei 0,40001 ; vld,pg 1 */ - INT64_C(0714000000000)+((IOBA_UBMAP+1) & RMASK), /* iowri 0,763001 ; set ubmap */ - INT64_C(0200040000000)+FE_RHBASE, /* move 1,FE_RHBASE */ - INT64_C(0201000000040), /* movei 0,40 ; ctrl reset */ - INT64_C(0714001000010), /* iowri 0,10(1) ; ->MTFS */ - INT64_C(0200300000000)+FE_UNIT, /* move 6,FE_UNIT ; fmtr */ - INT64_C(0714301000010), /* iowri 6,10(1) ; ->MTFS */ - - INT64_C(0200240000000)+FE_MTFMT, /*20 move 5,FE_MTFMT ; slave, dens, fmt */ - INT64_C(0714241000032), /* iowri 5,32(1) ; ->MTTC */ - INT64_C(0710001000012), /* iordi 0,12(1) ; read FS */ - INT64_C(0640000010600), /* trc 0,10600 ; MOL + DPR + RDY */ - INT64_C(0642000010600), /* trce 0,10600 ; */ - INT64_C(0254000377012), /* jrst .-3 ; wait */ - INT64_C(0201000000011), /* movei 0,11 ; clr+go */ - INT64_C(0714001000000), /* iowri 0,0(1) ; ->MTCS1 */ - - INT64_C(0201000000377), /*30 movei 0,1 ; Formatter */ - INT64_C(0242006000000), /* lsh 0,(6) ; attn bit */ - INT64_C(0714001000016), /* iowri 0,16(1) ; Clear on-line attn */ - INT64_C(0201100000031), /* movei 2,31 ; space f */ - INT64_C(0265740377030), /* jsp 17,tpop ; skip ucode */ - INT64_C(0201100000071), /* movei 2,71 ; read f */ - INT64_C(0265740377030), /* jsp 17,tpop ; read boot */ - INT64_C(0254000001000), /* jrst 1000 ; start */ - - /*30 */ - INT64_C(0714241000032), /* tpop:iowri 5,32(1) ; ->MTTC */ - INT64_C(0201000000011), /* movei 0,11 ; clr+go */ - INT64_C(0714001000000), /* iowri 0,0(1) ; ->MTCS1 */ - INT64_C(0201140176000), /* movei 3,176000 ; wd cnt */ - INT64_C(0714141000002), /* iowri 3,2(1) ; ->MTWC */ - INT64_C(0201200004000), /* movei 4,4000 ; addr */ - INT64_C(0714201000004), /* iowri 4,4(1) ; ->MTBA */ - INT64_C(0400400000000), /* setz 10, ; max fc */ - - INT64_C(0714401000006), /*40 iowri 10,6(1) ; ->MTFC */ - INT64_C(0714301000010), /* iowri 6,10(1) ; ->MTFS */ - INT64_C(0714241000032), /* iowri 5,32(1) ; ->MTTC */ - INT64_C(0714101000000), /* iowri 2,0(1) ; ->MTCS1 */ - INT64_C(0710341000012), /* iordi 7,12(1) ; read FS */ - INT64_C(0606340000200), /* trnn 7,200 ; test rdy */ - INT64_C(0254000377044), /* jrst .-2 ; loop */ - INT64_C(0606340040000), /* trnn 7,40000 ; test err */ - - INT64_C(0254017000000), /*50 jrst 0(17) ; return */ - INT64_C(0710341000014), /* iordi 7,14(1) ; read err */ - INT64_C(0302340001000), /* caie 7,1000 ; fce? */ - INT64_C(0254200377053), /* halt . */ - INT64_C(0254017000000), /* jrst 0(17) ; return */ - }; - -t_stat tu_boot (int32 unitno, DEVICE *dptr) -{ -size_t i; -extern a10 saved_PC; -UNIT *uptr; - -unitno &= TC_M_UNIT; -uptr = tu_unit + unitno; -if (!(uptr->flags & UNIT_ATT)) - return SCPE_NOATT; - -M[FE_RHBASE] = tu_dib.ba; -M[FE_UNIT] = 0; /* Only one formatter in this implementation */ - -assert (sizeof(boot_rom_dec) == sizeof(boot_rom_its)); - -M[FE_MTFMT] = (unitno & TC_M_UNIT) | (TC_1600 << TC_V_DEN) | (TC_10C << TC_V_FMT); -tu_unit[unitno].pos = 0; - -M[FE_KEEPA] = (M[FE_KEEPA] & ~INT64_C(0xFF)) | ((sim_switches & SWMASK ('A'))? 010 : 0); - -for (i = 0; i < BOOT_LEN; i++) - M[BOOT_START + i] = Q_ITS? boot_rom_its[i]: boot_rom_dec[i]; -saved_PC = BOOT_START; -return SCPE_OK; -} diff --git a/PDP10/pdp10_xtnd.c b/PDP10/pdp10_xtnd.c deleted file mode 100644 index a829e40b..00000000 --- a/PDP10/pdp10_xtnd.c +++ /dev/null @@ -1,758 +0,0 @@ -/* pdp10_xtnd.c: PDP-10 extended instruction simulator - - Copyright (c) 1993-2016, 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. - - 05-Nov-16 RMS Fixed last digit error in CVTBDT (Pascal Parent) - 12-May-01 RMS Fixed compiler warning in xlate - - Instructions handled in this module: - - MOVSLJ move string left justified - MOVSO move string offset - MOVST move string translated - MOVSRJ move string right justified - CMPSL compare string, skip on less - CMPSE compare string, skip on equal - CMPSLE compare string, skip on less or equal - CMPSGE compare string, skip on greater or equal - CMPSN compare string, skip on unequal - CMPSG compare string, skip on greater - CVTDBO convert decimal to binary offset - CVTDBT convert decimal to binary translated - CVTBDO convert binary to decimal offset - CVTBDT convert binary to decimal translated - EDIT edit - - The PDP-10 extended instructions deal with non-binary data types, - particularly byte strings and decimal strings. (In the KL10, the - extended instructions include G floating support as well.) They - are very complicated microcoded subroutines that can potentially - run for a very long time. Accordingly, the instructions must test - for interrupts as well as page faults, and be prepared to restart - from either. - - In general, the simulator attempts to keep the AC block up to date, - so that page fails and interrupts can be taken directly at any point. - If the AC block is not up to date, memory accessibility must be tested - before the actual read or write is done. - - The extended instruction routine returns a status code as follows: - - XT_NOSK no skip completion - XT_SKIP skip completion - XT_MUUO invalid extended instruction -*/ - -#include "pdp10_defs.h" -#include - -#define MM_XSRC (pflgs & XSRC_PXCT) -#define MM_XDST (pflgs & XDST_PXCT) -#define MM_EA_XSRC ((pflgs & EA_PXCT) && MM_XSRC) -#define MM_EA_XDST ((pflgs & EA_PXCT) && MM_XDST) - -#define XT_CMPSL 001 /* opcodes */ -#define XT_CMPSE 002 -#define XT_CMPSLE 003 -#define XT_EDIT 004 -#define XT_CMPSGE 005 -#define XT_CMPSN 006 -#define XT_CMPSG 007 -#define XT_CVTDBO 010 -#define XT_CVTDBT 011 -#define XT_CVTBDO 012 -#define XT_CVTBDT 013 -#define XT_MOVSO 014 -#define XT_MOVST 015 -#define XT_MOVSLJ 016 -#define XT_MOVSRJ 017 - -/* Translation control */ - -#define XT_LFLG INT64_C(0400000000000) /* L flag */ -#define XT_SFLG INT64_C(0400000000000) /* S flag */ -#define XT_NFLG INT64_C(0200000000000) /* N flag */ -#define XT_MFLG INT64_C(0100000000000) /* M flag */ - -/* Translation table */ - -#define XT_V_CODE 15 /* translation op */ -#define XT_M_CODE 07 -#define XT_BYMASK 07777 /* byte mask */ -#define XT_DGMASK 017 /* digit mask */ -#define XT_GETCODE(x) ((int32) (((x) >> XT_V_CODE) & XT_M_CODE)) - -/* AC masks */ - -#define XLNTMASK INT64_C(0000777777777) /* length */ -#define XFLGMASK INT64_C(0700000000000) /* flags */ -#define XT_MBZ INT64_C(0777000000000) /* must be zero */ -#define XT_MBZE INT64_C(0047777000000) /* must be zero, edit */ - -/* Register change log */ - -#define XT_N_RLOG 5 /* entry width */ -#define XT_M_RLOG ((1 << XT_N_RLOG) - 1) /* entry mask */ -#define XT_O_RLOG 1 /* entry offset */ -#define XT_INSRLOG(x,v) v = ((v << XT_N_RLOG) | (((x) + XT_O_RLOG) & XT_M_RLOG)) -#define XT_REMRLOG(x,v) x = (v & XT_M_RLOG) - XT_O_RLOG; \ - v = v >> XT_N_RLOG - -/* Edit */ - -#define ED_V_PBYN 30 /* pattern byte # */ -#define ED_M_PBYN 03 -#define ED_PBYNO INT64_C(0040000000000) /* overflow bit */ -#define ED_GETPBYN(x) ((int32) (((x) >> ED_V_PBYN) & ED_M_PBYN)) -#define ED_V_POPC 6 /* pattern byte opcode */ -#define ED_M_PAT 0777 /* pattern byte mask */ -#define ED_M_NUM 0077 /* number for msg, etc */ -#define ED_PBYTE(x,y) ((int32) (((x) >> (27 - (ED_GETPBYN (y) * 9))) & ED_M_PAT)) -#define ED_STOP 0000 /* stop */ -#define ED_SELECT 0001 /* select source */ -#define ED_SIGST 0002 /* start significance */ -#define ED_FLDSEP 0003 /* field separator */ -#define ED_EXCHMD 0004 /* exchange mark, dst */ -#define ED_MESSAG 0100 /* message */ -#define ED_SKPM 0500 /* skip if M */ -#define ED_SKPN 0600 /* skip if N */ -#define ED_SKPA 0700 /* skip always */ - -extern d10 *ac_cur; /* current AC block */ -extern const d10 bytemask[64]; -extern int32 flags; -extern int32 rlog; -extern jmp_buf save_env; - -extern d10 Read (int32 ea, int32 prv); -extern void Write (int32 ea, d10 val, int32 prv); -extern a10 calc_ea (d10 inst, int32 prv); -extern int32 test_int (void); -d10 incbp (d10 bp); -d10 incloadbp (int32 ac, int32 pflgs); -void incstorebp (d10 val, int32 ac, int32 pflgs); -d10 xlate (d10 by, a10 tblad, d10 *xflgs, int32 pflgs); -void filldst (d10 fill, int32 ac, d10 cnt, int32 pflgs); - -static const d10 pwrs10[23][2] = { -{ INT64_C(0), INT64_C(0),}, -{ INT64_C(0), INT64_C(1),}, -{ INT64_C(0), INT64_C(10),}, -{ INT64_C(0), INT64_C(100),}, -{ INT64_C(0), INT64_C(1000),}, -{ INT64_C(0), INT64_C(10000),}, -{ INT64_C(0), INT64_C(100000),}, -{ INT64_C(0), INT64_C(1000000),}, -{ INT64_C(0), INT64_C(10000000),}, -{ INT64_C(0), INT64_C(100000000),}, -{ INT64_C(0), INT64_C(1000000000),}, -{ INT64_C(0), INT64_C(10000000000),}, -{ INT64_C(2), INT64_C(31280523264),}, -{ INT64_C(29), INT64_C(3567587328),}, -{ INT64_C(291), INT64_C(1316134912),}, -{ INT64_C(2910), INT64_C(13161349120),}, -{ INT64_C(29103), INT64_C(28534276096),}, -{ INT64_C(291038), INT64_C(10464854016),}, -{ INT64_C(2910383), INT64_C(1569325056),}, -{ INT64_C(29103830), INT64_C(15693250560),}, -{ INT64_C(291038304), INT64_C(19493552128),}, -{ INT64_C(2910383045), INT64_C(23136829440),}, -{ INT64_C(29103830456), INT64_C(25209864192),}, - }; - -int xtend (int32 ac, int32 ea, int32 pflgs) -{ -d10 b1, b2, ppi; -d10 xinst, xoff = 0, digit, f1, f2, rs[2]; -d10 xflgs = 0; -a10 e1 = 0, entad; -int32 p1 = ADDAC (ac, 1); -int32 p3 = ADDAC (ac, 3); -int32 p4 = ADDAC (ac, 4); -int32 flg, i, s2 = 0, t, pp, pat, xop, xac, ret; - -xinst = Read (ea, MM_OPND); /* get extended instr */ -xop = GET_OP (xinst); /* get opcode */ -xac = GET_AC (xinst); /* get AC */ -if (xac || (xop == 0) || (xop > XT_MOVSRJ)) - return XT_MUUO; -rlog = 0; /* clear log */ -switch (xop) { /* case on opcode */ - -/* String compares - checked against KS10 ucode - If both strings are zero length, they are considered equal. - Both source and destination lengths are MBZ checked. - - AC = source1 length - AC + 1 = source1 byte pointer - AC + 3 = source2 length - AC + 4 = source2 byte pointer -*/ - - case XT_CMPSL: /* CMPSL */ - case XT_CMPSE: /* CMPSE */ - case XT_CMPSLE: /* CMPSLE */ - case XT_CMPSGE: /* CMPSGE */ - case XT_CMPSN: /* CMPSN */ - case XT_CMPSG: /* CMPSG */ - if ((AC(ac) | AC(p3)) & XT_MBZ) /* check length MBZ */ - return XT_MUUO; - f1 = Read (ADDA (ea, 1), MM_OPND) & bytemask[GET_S (AC(p1))]; - f2 = Read (ADDA (ea, 2), MM_OPND) & bytemask[GET_S (AC(p4))]; - b1 = b2 = 0; - for (flg = 0; (AC(ac) | AC(p3)) && (b1 == b2); flg++) { - if (flg && (t = test_int ())) - ABORT (t); - rlog = 0; /* clear log */ - if (AC(ac)) /* src1 */ - b1 = incloadbp (p1, pflgs); - else b1 = f1; - if (AC(p3)) /* src2 */ - b2 = incloadbp (p4, pflgs); - else b2 = f2; - if (AC(ac)) - AC(ac) = (AC(ac) - 1) & XLNTMASK; - if (AC(p3)) - AC(p3) = (AC(p3) - 1) & XLNTMASK; - } - switch (xop) { - case XT_CMPSL: - return (b1 < b2)? XT_SKIP: XT_NOSK; - case XT_CMPSE: - return (b1 == b2)? XT_SKIP: XT_NOSK; - case XT_CMPSLE: - return (b1 <= b2)? XT_SKIP: XT_NOSK; - case XT_CMPSGE: - return (b1 >= b2)? XT_SKIP: XT_NOSK; - case XT_CMPSN: - return (b1 != b2)? XT_SKIP: XT_NOSK; - case XT_CMPSG: - return (b1 > b2)? XT_SKIP: XT_NOSK; - } - - return XT_MUUO; - -/* Convert binary to decimal instructions - checked against KS10 ucode - There are no MBZ tests. - - AC'AC + 1 = double precision integer source - AC + 3 = flags and destination length - AC + 4 = destination byte pointer -*/ - - case XT_CVTBDO: /* CVTBDO */ - case XT_CVTBDT: /* CVTBDT */ - e1 = calc_ea (xinst, MM_EA); /* get ext inst addr */ - if (xop == XT_CVTBDO) /* offset? */ - xoff = (e1 & RSIGN)? (e1 | LMASK): e1; /* get offset */ - rs[0] = AC(ac); /* get src opnd */ - rs[1] = CLRS (AC(p1)); - if (!TSTF (F_FPD)) { /* set up done yet? */ - if (TSTS (AC(ac))) { /* get abs value */ - DMOVN (rs); - } - for (i = 22; i > 1; i--) { /* find field width */ - if (DCMPGE (rs, pwrs10[i])) - break; - } - if (i > (AC(p3) & XLNTMASK)) - return XT_NOSK; - if ((i < (AC(p3) & XLNTMASK)) && (AC(p3) & XT_LFLG)) { - f1 = Read (ADDA (ea, 1), MM_OPND); - filldst (f1, p3, (AC(p3) & XLNTMASK) - i, pflgs); - } - else AC(p3) = (AC(p3) & XFLGMASK) | i; - if (TSTS (AC(ac))) - AC(p3) = AC(p3) | XT_MFLG; - if (AC(ac) | AC(p1)) - AC(p3) = AC(p3) | XT_NFLG; - AC(ac) = rs[0]; /* update state */ - AC(p1) = rs[1]; - SETF (F_FPD); /* mark set up done */ - } - -/* Now do actual binary to decimal conversion */ - - for (flg = 0; AC(p3) & XLNTMASK; flg++) { - if (flg && (t = test_int ())) - ABORT (t); - rlog = 0; /* clear log */ - i = (int32) AC(p3) & XLNTMASK; /* get length */ - if (i > 22) /* put in range */ - i = 22; - for (digit = 0; (digit < 10) && DCMPGE (rs, pwrs10[i]); digit++) { - rs[0] = rs[0] - pwrs10[i][0] - (rs[1] < pwrs10[i][1]); - rs[1] = (rs[1] - pwrs10[i][1]) & MMASK; - } - if (xop == XT_CVTBDO) /* offset? */ - digit = (digit + xoff) & DMASK; - else { /* translate */ - f1 = Read (e1 + (int32) digit, MM_OPND);/* get xlation */ - if ((i == 1) && (AC(p3) & XT_MFLG)) /* last digit, minus? */ - f1 = f1 >> 18; /* use left */ - digit = f1 & RMASK; - } - incstorebp (digit, p4, pflgs); /* store digit */ - AC(ac) = rs[0]; /* mem access ok */ - AC(p1) = rs[1]; /* update state */ - AC(p3) = (AC(p3) & XFLGMASK) | ((AC(p3) - 1) & XLNTMASK); - } - CLRF (F_FPD); /* clear FPD */ - return XT_SKIP; - -/* Convert decimal to binary instructions - checked against KS10 ucode - There are no MBZ tests. - - AC = flags and source length - AC + 1 = source byte pointer - AC + 3'AC + 4 = double precision integer result -*/ - - case XT_CVTDBT: /* CVTDBT */ - case XT_CVTDBO: /* CVTDBO */ - e1 = calc_ea (xinst, MM_EA); /* get ext inst addr */ - if ((AC(ac) & XT_SFLG) == 0) /* !S? clr res */ - AC(p3) = AC(p4) = 0; - else AC(p4) = CLRS (AC(p4)); /* clear low sign */ - if (xop == XT_CVTDBO) { /* offset? */ - xoff = (e1 & RSIGN)? (e1 | LMASK): e1; /* get offset */ - AC(ac) = AC(ac) | XT_SFLG; /* set S flag */ - } - xflgs = AC(ac) & XFLGMASK; /* get xlation flags */ - for (flg = 0; AC(ac) & XLNTMASK; flg++) { - if (flg && (t = test_int ())) - ABORT (t); - rlog = 0; /* clear log */ - b1 = incloadbp (p1, pflgs); /* get byte */ - if (xop == XT_CVTDBO) - b1 = (b1 + xoff) & DMASK; - else { - b1 = xlate (b1, e1, &xflgs, MM_OPND); - if (b1 < 0) { /* terminated? */ - AC(ac) = xflgs | ((AC(ac) - 1) & XLNTMASK); - if (TSTS (AC(p3))) - AC(p4) = SETS (AC(p4)); - return XT_NOSK; - } - if (xflgs & XT_SFLG) - b1 = b1 & XT_DGMASK; - else b1 = 0; - } - AC(ac) = xflgs | ((AC(ac) - 1) & XLNTMASK); - if ((b1 < 0) || (b1 > 9)) { /* bad digit? done */ - if (TSTS (AC(p3))) - AC(p4) = SETS (AC(p4)); - return XT_NOSK; - } - AC(p4) = (AC(p4) * 10) + b1; /* base * 10 + digit */ - AC(p3) = ((AC(p3) * 10) + (AC(p4) >> 35)) & DMASK; - AC(p4) = AC(p4) & MMASK; - } - if (AC(ac) & XT_MFLG) { - AC(p4) = -AC(p4) & MMASK; - AC(p3) = (~AC(p3) + (AC(p4) == 0)) & DMASK; - } - if (TSTS (AC(p3))) - AC(p4) = SETS (AC(p4)); - return XT_SKIP; - -/* String move instructions - checked against KS10 ucode - Only the destination length is MBZ checked. - - AC = flags (MOVST only) and source length - AC + 1 = source byte pointer - AC + 3 = destination length - AC + 4 = destination byte pointer -*/ - - case XT_MOVSO: /* MOVSO */ - case XT_MOVST: /* MOVST */ - case XT_MOVSRJ: /* MOVSRJ */ - case XT_MOVSLJ: /* MOVSLJ */ - if (AC(p3) & XT_MBZ) /* test dst lnt MBZ */ - return XT_MUUO; - f1 = Read (ADDA (ea, 1), MM_OPND); /* get fill */ - switch (xop) { /* case on instr */ - - case XT_MOVSO: /* MOVSO */ - AC(ac) = AC(ac) & XLNTMASK; /* trim src length */ - xoff = calc_ea (xinst, MM_EA); /* get offset */ - if (xoff & RSIGN) /* sign extend 18b */ - xoff = xoff | LMASK; - s2 = GET_S (AC(p4)); /* get dst byte size */ - break; - - case XT_MOVST: /* MOVST */ - e1 = calc_ea (xinst, MM_EA); /* get xlate tbl addr */ - break; - - case XT_MOVSRJ: /* MOVSRJ */ - AC(ac) = AC(ac) & XLNTMASK; /* trim src length */ - if (AC(p3) == 0) - return (AC(ac)? XT_NOSK: XT_SKIP); - if (AC(ac) > AC(p3)) { /* adv src ptr */ - for (flg = 0; AC(ac) > AC(p3); flg++) { - if (flg && (t = test_int ())) - ABORT (t); - AC(p1) = incbp (AC(p1)); - AC(ac) = (AC(ac) - 1) & XLNTMASK; - } - } - else if (AC(ac) < AC(p3)) - filldst (f1, p3, AC(p3) - AC(ac), pflgs); - break; - - case XT_MOVSLJ: /* MOVSLJ */ - AC(ac) = AC(ac) & XLNTMASK; /* trim src length */ - break; - } /* end case xop */ - - xflgs = AC(ac) & XFLGMASK; /* get xlation flags */ - if (AC(p3) == 0) - return (AC(ac)? XT_NOSK: XT_SKIP); - for (flg = 0; AC(p3) & XLNTMASK; flg++) { - if (flg && (t = test_int ())) - ABORT (t); - rlog = 0; /* clear log */ - if (AC(ac) & XLNTMASK) { /* any source? */ - b1 = incloadbp (p1, pflgs); /* src byte */ - if (xop == XT_MOVSO) { /* offset? */ - b1 = (b1 + xoff) & DMASK; /* test fit */ - if (b1 & ~bytemask[s2]) { - AC(ac) = xflgs | ((AC(ac) - 1) & XLNTMASK); - return XT_NOSK; - } - } - else if (xop == XT_MOVST) { /* translate? */ - b1 = xlate (b1, e1, &xflgs, MM_OPND); - if (b1 < 0) { /* upd flags in AC */ - AC(ac) = xflgs | ((AC(ac) - 1) & XLNTMASK); - return XT_NOSK; - } - if (xflgs & XT_SFLG) - b1 = b1 & XT_BYMASK; - else b1 = -1; - } - } - else b1 = f1; - if (b1 >= 0) { /* valid byte? */ - incstorebp (b1, p4, pflgs); /* store byte */ - AC(p3) = (AC(p3) - 1) & XLNTMASK; /* update state */ - } - if (AC(ac) & XLNTMASK) - AC(ac) = xflgs | ((AC(ac) - 1) & XLNTMASK); - } - return (AC(ac) & XLNTMASK)? XT_NOSK: XT_SKIP; - -/* Edit - checked against KS10 ucode - Only the flags/pattern pointer word is MBZ checked. - - AC = flags, pattern pointer - AC + 1 = source byte pointer - AC + 3 = mark address - AC + 4 = destination byte pointer -*/ - - case XT_EDIT: /* EDIT */ - if (AC(ac) & XT_MBZE) /* check pattern MBZ */ - return XT_MUUO; - xflgs = AC(ac) & XFLGMASK; /* get xlation flags */ - e1 = calc_ea (xinst, MM_EA); /* get xlate tbl addr */ - for (ppi = 1, ret = -1, flg = 0; ret < 0; flg++, ppi = 1) { - if (flg && (t = test_int ())) - ABORT (t); - rlog = 0; /* clear log */ - pp = (int32) AC(ac) & AMASK; /* get pattern ptr */ - b1 = Read (pp, MM_OPND); /* get pattern word */ - pat = ED_PBYTE (b1, AC(ac)); /* get pattern byte */ - switch ((pat < 0100)? pat: ((pat >> ED_V_POPC) + 0100)) { - - case ED_STOP: /* stop */ - ret = XT_SKIP; /* exit loop */ - break; - - case ED_SELECT: /* select source */ - b1 = incloadbp (p1, pflgs); /* get src */ - entad = (e1 + ((int32) b1 >> 1)) & AMASK; - f1 = ((Read (entad, MM_OPND) >> ((b1 & 1)? 0: 18)) & RMASK); - i = XT_GETCODE (f1); - if (i & 2) - xflgs = (i & 1)? xflgs | XT_MFLG: xflgs & ~XT_MFLG; - switch (i) { - - case 00: case 02: case 03: - if (xflgs & XT_SFLG) - f1 = f1 & XT_BYMASK; - else { - f1 = Read (INCA (ea), MM_OPND); - if (f1 == 0) - break; - } - incstorebp (f1, p4, pflgs); - break; - - case 01: - ret = XT_NOSK; /* exit loop */ - break; - - case 04: case 06: case 07: - xflgs = xflgs | XT_NFLG; - f1 = f1 & XT_BYMASK; - if ((xflgs & XT_SFLG) == 0) { - f2 = Read (ADDA (ea, 2), MM_OPND); - Write ((a10) AC(p3), AC(p4), MM_OPND); - if (f2) - incstorebp (f2, p4, pflgs); - xflgs = xflgs | XT_SFLG; - } - incstorebp (f1, p4, pflgs); - break; - - case 05: - xflgs = xflgs | XT_NFLG; - ret = XT_NOSK; /* exit loop */ - break; - } /* end case xlate op */ - break; - - case ED_SIGST: /* start significance */ - if ((xflgs & XT_SFLG) == 0) { - f2 = Read (ADDA (ea, 2), MM_OPND); - Write ((a10) AC(p3), AC(p4), MM_OPND); - if (f2) - incstorebp (f2, p4, pflgs); - xflgs = xflgs | XT_SFLG; - } - break; - - case ED_FLDSEP: /* separate fields */ - xflgs = 0; - break; - - case ED_EXCHMD: /* exchange */ - f2 = Read ((int32) (AC(p3) & AMASK), MM_OPND); - Write ((int32) (AC(p3) & AMASK), AC(p4), MM_OPND); - AC(p4) = f2; - break; - - case (0100 + (ED_MESSAG >> ED_V_POPC)): /* message */ - if (xflgs & XT_SFLG) - f1 = Read (ea + (pat & ED_M_NUM) + 1, MM_OPND); - else { - f1 = Read (ea + 1, MM_OPND); - if (f1 == 0) - break; - } - incstorebp (f1, p4, pflgs); - break; - - case (0100 + (ED_SKPM >> ED_V_POPC)): /* skip on M */ - if (xflgs & XT_MFLG) - ppi = (pat & ED_M_NUM) + 2; - break; - - case (0100 + (ED_SKPN >> ED_V_POPC)): /* skip on N */ - if (xflgs & XT_NFLG) - ppi = (pat & ED_M_NUM) + 2; - break; - - case (0100 + (ED_SKPA >> ED_V_POPC)): /* skip always */ - ppi = (pat & ED_M_NUM) + 2; - break; - - default: /* NOP or undefined */ - break; - } /* end case pttrn op */ - AC(ac) = AC(ac) + ((ppi & ED_M_PBYN) << ED_V_PBYN); - AC(ac) = AC(ac) + (ppi >> 2) + ((AC(ac) & ED_PBYNO)? 1: 0); - AC(ac) = xflgs | (AC(ac) & ~(XT_MBZE | XFLGMASK)); - } - return ret; - } /* end case xop */ -return XT_MUUO; -} - -/* Supporting subroutines */ - -/* Increment byte pointer, register version */ - -d10 incbp (d10 bp) -{ -int32 p, s; - -p = GET_P (bp); /* get P and S */ -s = GET_S (bp); -p = p - s; /* adv P */ -if (p < 0) { /* end of word? */ - bp = (bp & LMASK) | (INCR (bp)); /* increment addr */ - p = (36 - s) & 077; /* reset P */ - } -bp = PUT_P (bp, p); /* store new P */ -return bp; -} - -/* Increment and load byte, extended version - uses register log */ - -d10 incloadbp (int32 ac, int32 pflgs) -{ -a10 ba; -d10 bp, wd; -int32 p, s; - -bp = AC(ac) = incbp (AC(ac)); /* increment bp */ -XT_INSRLOG (ac, rlog); /* log change */ -p = GET_P (bp); /* get P and S */ -s = GET_S (bp); -ba = calc_ea (bp, MM_EA_XSRC); /* calc bp eff addr */ -wd = Read (ba, MM_XSRC); /* read word */ -wd = (wd >> p) & bytemask[s]; /* get byte */ -return wd; -} - -/* Increment and deposit byte, extended version - uses register log */ - -void incstorebp (d10 val, int32 ac, int32 pflgs) -{ -a10 ba; -d10 bp, wd, mask; -int32 p, s; - -bp = AC(ac) = incbp (AC(ac)); /* increment bp */ -XT_INSRLOG (ac, rlog); /* log change */ -p = GET_P (bp); /* get P and S */ -s = GET_S (bp); -ba = calc_ea (bp, MM_EA_XDST); /* calc bp eff addr */ -wd = Read (ba, MM_XDST); /* read, write test */ -mask = bytemask[s] << p; /* shift mask, val */ -val = val << p; -wd = (wd & ~mask) | (val & mask); /* insert byte */ -Write (ba, wd & DMASK, MM_XDST); -return; -} - -/* Translate byte - - Arguments - by = byte to translate - tblad = virtual address of translation table - *xflgs = pointer to word containing translation flags - prv = previous mode flag for table lookup - Returns - xby = >= 0, translated byte - < 0, terminate translation -*/ - -d10 xlate (d10 by, a10 tblad, d10 *xflgs, int32 prv) -{ -a10 ea; -int32 tcode; -d10 tblent; - -ea = (tblad + ((int32) by >> 1)) & AMASK; -tblent = ((Read (ea, prv) >> ((by & 1)? 0: 18)) & RMASK); -tcode = XT_GETCODE (tblent); /* get xlate code */ -switch (tcode) { - - case 00: - return (*xflgs & XT_SFLG)? tblent: by; - - case 01: - break; - - case 02: - *xflgs = *xflgs & ~XT_MFLG; - return (*xflgs & XT_SFLG)? tblent: by; - - case 03: - *xflgs = *xflgs | XT_MFLG; - return (*xflgs & XT_SFLG)? tblent: by; - - case 04: - *xflgs = *xflgs | XT_SFLG | XT_NFLG; - return tblent; - - case 05: - *xflgs = *xflgs | XT_NFLG; - break; - - case 06: - *xflgs = (*xflgs | XT_SFLG | XT_NFLG) & ~XT_MFLG; - return tblent; - - case 07: - *xflgs = *xflgs | XT_SFLG | XT_NFLG | XT_MFLG; - return tblent; - } /* end case */ - -return -1; -} - -/* Fill out the destination string - - Arguments: - fill = fill - ac = 2 word AC block (length, byte pointer) - cnt = fill count - pflgs = PXCT flags -*/ - -void filldst (d10 fill, int32 ac, d10 cnt, int32 pflgs) -{ -int32 i, t; -int32 p1 = ADDA (ac, 1); - -for (i = 0; i < cnt; i++) { - if (i && (t = test_int ())) - ABORT (t); - rlog = 0; /* clear log */ - incstorebp (fill, p1, pflgs); - AC(ac) = (AC(ac) & XFLGMASK) | ((AC(ac) - 1) & XLNTMASK); - } -rlog = 0; -return; -} - -/* Clean up after page fault - - Arguments: - logv = register change log - - For each register in logv, decrement the register's contents as - though it were a byte pointer. Note that the KS10 does - do a full decrement calculation but merely adds S to P. -*/ - -void xtcln (int32 logv) -{ -int32 p, reg; - -while (logv) { - XT_REMRLOG (reg, logv); /* get next reg */ - if ((reg >= 0) && (reg < AC_NUM)) { - p = GET_P (AC(reg)) + GET_S (AC(reg)); /* get p + s */ - AC(reg) = PUT_P (AC(reg), p); /* p <- p + s */ - } - } -return; -} diff --git a/PDP11/pdp11_cis.c b/PDP11/pdp11_cis.c deleted file mode 100644 index 1cc76c26..00000000 --- a/PDP11/pdp11_cis.c +++ /dev/null @@ -1,1640 +0,0 @@ -/* pdp11_cis.c: PDP-11 CIS optional instruction set simulator - - Copyright (c) 1993-2008, 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 module simulates the PDP-11 commercial instruction set (CIS). - - 16-Oct-08 RMS Fixed overflow bug in ASHx (Word/NibbleLShift) - Fixed bug in DIVx (LntDstr calculation) - 30-May-06 RMS Added interrupt tests to character instructions - Added 11/44 stack probe test to MOVCx (only) - 22-May-06 RMS Fixed bug in decode table (John Dundas) - Fixed bug in ASHP (John Dundas) - Fixed bug in write decimal string with mmgt enabled - Fixed bug in 0-length strings in multiply/divide - 16-Sep-04 RMS Fixed bug in CMPP/N of negative strings - 17-Oct-02 RMS Fixed compiler warning (Hans Pufal) - 08-Oct-02 RMS Fixed macro definitions - - The commercial instruction set consists of three instruction formats: - - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ register operands - | 0 1 1 1 1 1| 0 0 0 0| opcode | 076030:076057 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 076070:076077 - - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ inline operands - | 0 1 1 1 1 1| 0 0 0 1| opcode | 076130:076157 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 076170:076177 - - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ load descriptors - | 0 1 1 1 1 1| 0 0 0 0|op| 1 0| reg | 076020:076027 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 076060:076067 - - The CIS instructions operate on character strings, packed (decimal) - strings, and numeric (decimal) strings. Strings are described by - a two word descriptor: - - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | length in bytes | char string - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ descriptor - | starting byte address | - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | |str type| | length | decimal string - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ descriptor - | starting byte address | - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - Decimal string types are: - - <14:12> data type bytes occupied by n digits - 0 signed zoned n - 1 unsigned zone n - 2 trailing overpunch n - 3 leading overpunch n - 4 trailing separate n+1 - 5 leading separate n+1 - 6 signed packed n/2 +1 - 7 unsigned packed n/2 +1 - - Zero length character strings occupy no memory; zero length decimal strings - require either zero bytes (zoned, overpunch) or one byte (separate, packed). - - CIS instructions can run for a very long time, so they are interruptible - and restartable. In the simulator, all instructions run to completion. - The code is unoptimized. -*/ - -#include "pdp11_defs.h" - -/* Opcode bits */ - -#define INLINE 0100 /* inline */ -#define PACKED 0020 /* packed */ -#define NUMERIC 0000 /* numeric */ - -/* Interrupt test latency */ - -#define INT_TEST 100 - -/* Operand type definitions */ - -#define R0_DESC 1 /* descr in R0:R1 */ -#define R2_DESC 2 /* descr in R2:R3 */ -#define R4_DESC 3 /* descr in R4:R5 */ -#define R4_ARG 4 /* argument in R4 */ -#define IN_DESC 5 /* inline descriptor */ -#define IN_ARG 6 /* inline argument */ -#define MAXOPN 4 /* max # operands */ - -/* Decimal data type definitions */ - -#define XZ 0 /* signed zoned */ -#define UZ 1 /* unsigned zoned */ -#define TO 2 /* trailing overpunch */ -#define LO 3 /* leading overpunch */ -#define TS 4 /* trailing separate */ -#define LS 5 /* leading separate */ -#define XP 6 /* signed packed */ -#define UP 7 /* unsigned packed */ - -/* Decimal descriptor definitions */ - -#define DTYP_M 07 /* type mask */ -#define DTYP_V 12 /* type position */ -#define DLNT_M 037 /* length mask */ -#define DLNT_V 0 /* length position */ -#define GET_DTYP(x) (((x) >> DTYP_V) & DTYP_M) -#define GET_DLNT(x) (((x) >> DLNT_V) & DLNT_M) - -/* Shift operand definitions */ - -#define ASHRND_M 017 /* round digit mask */ -#define ASHRND_V 8 /* round digit pos */ -#define ASHLNT_M 0377 /* shift count mask */ -#define ASHLNT_V 0 /* shift length pos */ -#define ASHSGN 0200 /* shift sign */ -#define GET_ASHRND(x) (((x) >> ASHRND_V) & ASHRND_M) -#define GET_ASHLNT(x) (((x) >> ASHLNT_V) & ASHLNT_M) - -/* Operand array aliases */ - -#define A1LNT arg[0] -#define A1ADR arg[1] -#define A2LNT arg[2] -#define A2ADR arg[3] -#define A3LNT arg[4] -#define A3ADR arg[5] -#define A1 &arg[0] -#define A2 &arg[2] -#define A3 &arg[4] - -/* Condition code macros */ - -#define GET_BIT(ir,n) (((ir) >> (n)) & 1) -#define GET_SIGN_L(ir) GET_BIT((ir), 31) -#define GET_SIGN_W(ir) GET_BIT((ir), 15) -#define GET_SIGN_B(ir) GET_BIT((ir), 7) -#define GET_Z(ir) ((ir) == 0) - -/* Decimal string structure */ - -#define DSTRLNT 4 -#define DSTRMAX (DSTRLNT - 1) -#define MAXDVAL 429496730 /* 2^32 / 10 */ - -typedef struct { - uint32 sign; - uint32 val[DSTRLNT]; - } DSTR; - -static DSTR Dstr0 = { 0, {0, 0, 0, 0} }; - -extern int32 isenable, dsenable; -extern int32 N, Z, V, C, fpd, ipl; -extern int32 R[8], trap_req; -extern uint32 cpu_type; - -int32 ReadDstr (int32 *dscr, DSTR *dec, int32 flag); -void WriteDstr (int32 *dscr, DSTR *dec, int32 flag); -int32 AddDstr (DSTR *src1, DSTR *src2, DSTR *dst, int32 cin); -void SubDstr (DSTR *src1, DSTR *src2, DSTR *dst); -int32 CmpDstr (DSTR *src1, DSTR *src2); -int32 TestDstr (DSTR *dsrc); -int32 LntDstr (DSTR *dsrc, int32 nz); -uint32 NibbleLshift (DSTR *dsrc, int32 sc); -uint32 NibbleRshift (DSTR *dsrc, int32 sc, uint32 cin); -int32 WordLshift (DSTR *dsrc, int32 sc); -void WordRshift (DSTR *dsrc, int32 sc); -void CreateTable (DSTR *dsrc, DSTR mtable[10]); -t_bool cis_int_test (int32 cycles, int32 oldpc, t_stat *st); -int32 movx_setup (int32 op, int32 *arg); -void movx_cleanup (int32 op); - -extern int32 ReadW (int32 addr); -extern void WriteW (int32 data, int32 addr); -extern int32 ReadB (int32 addr); -extern int32 ReadMB (int32 addr); -extern void WriteB (int32 data, int32 addr); -extern int32 calc_ints (int32 nipl, int32 trq); - -/* Table of instruction operands */ - -static int32 opntab[128][MAXOPN] = { - {0, 0, 0, 0}, {0, 0, 0, 0}, /* 000 - 007 */ - {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}, /* 010 - 017 */ - {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}, /* LD2R */ - {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}, /* MOVC */ - {0, 0, 0, 0}, /* MOVRC */ - {0, 0, 0, 0}, /* MOVTC */ - {0, 0, 0, 0}, /* 033 */ - {0, 0, 0, 0}, {0, 0, 0, 0}, /* 034 - 037 */ - {0, 0, 0, 0}, {0, 0, 0, 0}, - {0, 0, 0, 0}, /* LOCC */ - {0, 0, 0, 0}, /* SKPC */ - {0, 0, 0, 0}, /* SCANC */ - {0, 0, 0, 0}, /* SPANC */ - {0, 0, 0, 0}, /* CMPC */ - {0, 0, 0, 0}, /* MATC */ - {0, 0, 0, 0}, {0, 0, 0, 0}, /* 046 - 047 */ - {R0_DESC, R2_DESC, R4_DESC, 0}, /* ADDN */ - {R0_DESC, R2_DESC, R4_DESC, 0}, /* SUBN */ - {R0_DESC, R2_DESC, 0, 0}, /* CMPN */ - {R0_DESC, 0, 0, 0}, /* CVTNL */ - {R0_DESC, R2_DESC, 0, 0}, /* CVTPN */ - {R0_DESC, R2_DESC, 0, 0}, /* CVTNP */ - {R0_DESC, R2_DESC, R4_ARG, 0}, /* ASHN */ - {R0_DESC, 0, 0, 0}, /* CVTLN */ - {0, 0, 0, 0}, {0, 0, 0, 0}, /* LD3R */ - {0, 0, 0, 0}, {0, 0, 0, 0}, - {0, 0, 0, 0}, {0, 0, 0, 0}, - {0, 0, 0, 0}, {0, 0, 0, 0}, - {R0_DESC, R2_DESC, R4_DESC, 0}, /* ADDP */ - {R0_DESC, R2_DESC, R4_DESC, 0}, /* SUBP */ - {R0_DESC, R2_DESC, 0, 0}, /* CMPP */ - {R0_DESC, 0, 0, 0}, /* CVTPL */ - {R0_DESC, R2_DESC, R4_DESC, 0}, /* MULP */ - {R0_DESC, R2_DESC, R4_DESC, 0}, /* DIVP */ - {R0_DESC, R2_DESC, R4_ARG, 0}, /* ASHP */ - {R0_DESC, 0, 0, 0}, /* CVTLP */ - {0, 0, 0, 0}, {0, 0, 0, 0}, /* 100 - 107 */ - {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}, /* 110 - 117 */ - {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}, /* 120 - 127 */ - {0, 0, 0, 0}, {0, 0, 0, 0}, - {0, 0, 0, 0}, {0, 0, 0, 0}, - {0, 0, 0, 0}, {0, 0, 0, 0}, - {IN_DESC, IN_DESC, IN_ARG, 0}, /* MOVCI */ - {IN_DESC, IN_DESC, IN_ARG, 0}, /* MOVRCI */ - {IN_DESC, IN_DESC, IN_ARG, IN_ARG}, /* MOVTCI */ - {0, 0, 0, 0}, /* 133 */ - {0, 0, 0, 0}, {0, 0, 0, 0}, /* 134 - 137 */ - {0, 0, 0, 0}, {0, 0, 0, 0}, - {IN_DESC, IN_ARG, 0, 0}, /* LOCCI */ - {IN_DESC, IN_ARG, 0, 0}, /* SKPCI */ - {IN_DESC, IN_DESC, 0, 0}, /* SCANCI */ - {IN_DESC, IN_DESC, 0, 0}, /* SPANCI */ - {IN_DESC, IN_DESC, IN_ARG, 0}, /* CMPCI */ - {IN_DESC, IN_DESC, 0, 0}, /* MATCI */ - {0, 0, 0, 0}, {0, 0, 0, 0}, /* 146 - 147 */ - {IN_DESC, IN_DESC, IN_DESC, 0}, /* ADDNI */ - {IN_DESC, IN_DESC, IN_DESC, 0}, /* SUBNI */ - {IN_DESC, IN_DESC, 0, 0}, /* CMPNI */ - {IN_DESC, IN_ARG, 0, 0}, /* CVTNLI */ - {IN_DESC, IN_DESC, 0, 0}, /* CVTPNI */ - {IN_DESC, IN_DESC, 0, 0}, /* CVTNPI */ - {IN_DESC, IN_DESC, IN_ARG, 0}, /* ASHNI */ - {IN_DESC, IN_DESC, 0, 0}, /* CVTLNI */ - {0, 0, 0, 0}, {0, 0, 0, 0}, /* 160 - 167 */ - {0, 0, 0, 0}, {0, 0, 0, 0}, - {0, 0, 0, 0}, {0, 0, 0, 0}, - {0, 0, 0, 0}, {0, 0, 0, 0}, - {IN_DESC, IN_DESC, IN_DESC, 0}, /* ADDPI */ - {IN_DESC, IN_DESC, IN_DESC, 0}, /* SUBPI */ - {IN_DESC, IN_DESC, 0, 0}, /* CMPPI */ - {IN_DESC, IN_ARG, 0, 0}, /* CVTPLI */ - {IN_DESC, IN_DESC, IN_DESC, 0}, /* MULPI */ - {IN_DESC, IN_DESC, IN_DESC, 0}, /* DIVPI */ - {IN_DESC, IN_DESC, IN_ARG, 0}, /* ASHPI */ - {IN_DESC, IN_DESC, 0, 0} /* CVTLPI */ - }; - -/* ASCII to overpunch table: sign is <7>, digit is <4:0> */ - -static int32 overbin[128] = { - 0, 0, 0, 0, 0, 0, 0, 0, /* 000 - 037 */ - 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, 0x80, 0, 0, 0, 0, 0, 0, /* 040 - 077 */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 1, 2, 3, 4, 5, 6, 7, - 8, 9, 0x80, 0, 0, 0, 0, 0, - 0, 1, 2, 3, 4, 5, 6, 7, /* 100 - 137 */ - 8, 9, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, - 0x87, 0x88, 0x89, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0x80, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, /* 140 - 177 */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0x80, 0, 0 - }; - -/* Overpunch to ASCII table: indexed by sign and digit */ - -static int32 binover[2][16] = { - {'{', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', - '0', '0', '0', '0', '0', '0'}, - {'}', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', - '0', '0', '0', '0', '0', '0'} - }; - -/* CIS emulator */ - -t_stat cis11 (int32 IR) -{ -int32 c, i, j, t, op, rn, addr; -int32 match, limit, mvlnt, shift; -int32 spc, ldivd, ldivr; -int32 arg[6]; /* operands */ -int32 old_PC; -uint32 nc, digit, result; -t_stat st; -static DSTR accum, src1, src2, dst; -static DSTR mptable[10]; -static DSTR Dstr1 = { 0, {0x10, 0, 0, 0} }; - -old_PC = (PC - 2) & 0177777; /* original PC */ -op = IR & 0177; /* IR <6:0> */ -for (i = j = 0; (i < MAXOPN) && opntab[op][i]; i++) { /* parse operands */ - switch (opntab[op][i]) { /* case on op type */ - - case R0_DESC: - arg[j++] = R[0]; - arg[j++] = R[1]; - break; - - case R2_DESC: - arg[j++] = R[2]; - arg[j++] = R[3]; - break; - - case R4_DESC: - arg[j++] = R[4]; - arg[j++] = R[5]; - break; - - case R4_ARG: - arg[j++] = R[4]; - break; - - case IN_DESC: - addr = ReadW (PC | isenable); - PC = (PC + 2) & 0177777; - arg[j++] = ReadW (addr | dsenable); - arg[j++] = ReadW (((addr + 2) & 0177777) | dsenable); - break; - - case IN_ARG: - arg[j++] = ReadW (PC | isenable); - PC = (PC + 2) & 0177777; - break; - - default: - return SCPE_IERR; - } /* end case */ - } /* end for */ -switch (op) { /* case on opcode */ - -/* MOVC, MOVTC, MOVCI, MOVTCI - - Operands (MOVC, MOVTC): - R0, R1 = source string descriptor - R2, R3 = dest string descriptor - R4<7:0> = fill character - R5 = translation table address (MOVTC only) - Operands (MOVCI, MOVTCI): - A1LNT, A1ADR = source string descriptor - A2LNT, A2ADR = dest string descriptor - A3LNT<7:0> = fill character - A3ADR = translation table address (MOVTCI only) - - Condition codes: - NZVC = set from src.lnt - dst.lnt - - Registers (MOVC, MOVTC only) - R0 = max (0, src.len - dst.len) - R1:R3 = 0 - R4:R5 = unchanged - - Notes: - - If either the source or destination lengths are zero, - the move loops exit immediately. - - If the source length does not exceed the destination - length, the fill loop exits immediately. -*/ - - case 030: case 032: case 0130: case 0132: - if (!fpd) { /* first time? */ - mvlnt = movx_setup (op, arg); /* set up reg */ - if (R[1] < R[3]) { /* move backwards? */ - R[1] = (R[1] + mvlnt) & 0177777; /* bias addresses */ - R[3] = (R[3] + mvlnt) & 0177777; - } - } - -/* At this point, - - R0-R5 = arguments - M[SP] = move length */ - - if (R[0] && R[2]) { /* move to do? */ - if (R[1] < R[3]) { /* backwards? */ - for (i = 0; R[0] && R[2]; ) { /* move loop */ - t = ReadB (((R[1] - 1) & 0177777) | dsenable); - if (op & 2) - t = ReadB (((R[5] + t) & 0177777) | dsenable); - WriteB (t, ((R[3] - 1) & 0177777) | dsenable); - R[0]--; - R[1] = (R[1] - 1) & 0177777; - R[2]--; - R[3] = (R[3] - 1) & 0177777; - if ((++i >= INT_TEST) && R[0] && R[2]) { - if (cis_int_test (i, old_PC, &st)) - return st; - i = 0; - } - } /* end for lnts */ - mvlnt = ReadW (SP | dsenable); /* recover mvlnt */ - R[3] = (R[3] + mvlnt) & 0177777; /* end of dst str */ - } /* end if bkwd */ - else { /* forward */ - for (i = 0; R[0] && R[2]; ) { /* move loop */ - t = ReadB ((R[1] & 0177777) | dsenable); - if (op & 2) - t = ReadB (((R[5] + t) & 0177777) | dsenable); - WriteB (t, (R[3] & 0177777) | dsenable); - R[0]--; - R[1] = (R[1] + 1) & 0177777; - R[2]--; - R[3] = (R[3] + 1) & 0177777; - if ((++i >= INT_TEST) && R[0] && R[2]) { - if (cis_int_test (i, old_PC, &st)) - return st; - i = 0; - } - } /* end for lnts */ - } /* end else fwd */ - } /* end if move */ - for (i = 0; i < R[2]; i++) { - WriteB (R[4], ((R[3] + i) & 0177777) | dsenable); - } - movx_cleanup (op); /* cleanup */ - return SCPE_OK; - -/* MOVRC, MOVRCI - - Operands (MOVC, MOVTC): - R0, R1 = source string descriptor - R2, R3 = dest string descriptor - R4<7:0> = fill character - Operands (MOVCI, MOVTCI): - A1LNT, A1ADR = source string descriptor - A2LNT, A2ADR = dest string descriptor - A3LNT<7:0> = fill character - - Condition codes: - NZVC = set from src.lnt - dst.lnt - - Registers (MOVRC only) - R0 = max (0, src.len - dst.len) - R1:R3 = 0 - R4:R5 = unchanged - - Notes: see MOVC, MOVCI -*/ - - case 031: case 0131: - if (!fpd) { /* first time? */ - mvlnt = movx_setup (op, arg); /* set up reg */ - R[1] = (R[1] + R[0] - mvlnt) & 0177777; /* eff move start */ - R[3] = (R[3] + R[2] - mvlnt) & 0177777; - if (R[1] < R[3]) { /* move backwards? */ - R[1] = (R[1] + mvlnt) & 0177777; /* bias addresses */ - R[3] = (R[3] + mvlnt) & 0177777; - } - } - -/* At this point, - - R0-R5 = arguments - M[SP] = move length */ - - if (R[0] && R[2]) { /* move to do? */ - if (R[1] < R[3]) { /* backwards? */ - for (i = 0; R[0] && R[2]; ) { /* move loop */ - t = ReadB (((R[1] - 1) & 0177777) | dsenable); - WriteB (t, ((R[3] - 1) & 0177777) | dsenable); - R[0]--; - R[1] = (R[1] - 1) & 0177777; - R[2]--; - R[3] = (R[3] - 1) & 0177777; - if ((++i >= INT_TEST) && R[0] && R[2]) { - if (cis_int_test (i, old_PC, &st)) - return st; - i = 0; - } - } /* end for lnts */ - } /* end if bkwd */ - else { /* forward */ - for (i = 0; R[0] && R[2]; ) { /* move loop */ - t = ReadB ((R[1] & 0177777) | dsenable); - WriteB (t, (R[3] & 0177777) | dsenable); - R[0]--; - R[1] = (R[1] + 1) & 0177777; - R[2]--; - R[3] = (R[3] + 1) & 0177777; - if ((++i >= INT_TEST) && R[0] && R[2]) { - if (cis_int_test (i, old_PC, &st)) - return st; - i = 0; - } - } /* end for lnts */ - mvlnt = ReadW (SP | dsenable); /* recover mvlnt */ - R[3] = (R[3] - mvlnt) & 0177777; /* start of dst str */ - } /* end else fwd */ - } /* end if move */ - for (i = 0; i < R[2]; i++) { - WriteB (R[4], ((R[3] - R[2] + i) & 0177777) | dsenable); - } - movx_cleanup (op); /* cleanup */ - return SCPE_OK; - -/* Load descriptors - no operands */ - - case 020: case 021: case 022: case 023: - case 024: case 025: case 026: case 027: - case 060: case 061: case 062: case 063: - case 064: case 065: case 066: case 067: - limit = (op & 040)? 6: 4; - rn = IR & 07; /* get register */ - t = R[rn]; - spc = (rn == 7)? isenable: dsenable; - for (j = 0; j < limit; j = j + 2) { /* loop for 2,3 dscr */ - addr = ReadW (((t + j) & 0177777) | spc); - R[j] = ReadW (addr | dsenable); - R[j + 1] = ReadW (((addr + 2) & 0177777) | dsenable); - } - if (rn >= limit) - R[rn] = (R[rn] + limit) & 0177777; - return SCPE_OK; - -/* LOCC, SKPC, LOCCI, SKPCI - - Operands (LOCC, SKPC): - R0, R1 = source string descriptor - R4<7:0> = match character - Operands (LOCCI, SKPCI): - A1LNT, A1ADR = source string descriptor - A2LNT<7:0> = match character - - Condition codes: - NZ = set from R0 - VC = 0 - - Registers: - R0:R1 = substring descriptor where operation terminated -*/ - - case 0140: case 0141: /* inline */ - if (!fpd) { /* FPD clear? */ - WriteW (R[4], ((SP - 2) & 0177777) | dsenable); - SP = (SP - 2) & 0177777; /* push R4 */ - R[0] = A1LNT; /* args to registers */ - R[1] = A1ADR; - R[4] = A2LNT; - } /* fall through */ - case 040: case 041: /* register */ - fpd = 1; /* set FPD */ - R[4] = R[4] & 0377; /* match character */ - for (i = 0; R[0] != 0;) { /* loop */ - c = ReadB (R[1] | dsenable); /* get char */ - if ((c == R[4]) ^ (op & 1)) /* = + LOC, != + SKP? */ - break; - R[0]--; /* decr count, */ - R[1] = (R[1] + 1) & 0177777; /* incr addr */ - if ((++i >= INT_TEST) && R[0]) { /* test for intr? */ - if (cis_int_test (i, old_PC, &st)) - return st; - i = 0; - } - } - N = GET_SIGN_W (R[0]); - Z = GET_Z (R[0]); - V = C = 0; - fpd = 0; /* instr done */ - if (op & INLINE) { /* inline? */ - R[4] = ReadW (SP | dsenable); /* restore R4 */ - SP = (SP + 2) & 0177777; - } - return SCPE_OK; - -/* SCANC, SPANC, SCANCI, SPANCI - - Operands (SCANC, SPANC): - R0, R1 = source string descriptor - R4<7:0> = mask - R5 = table address - Operands (SCANCI, SPANCI): - A1LNT, A1ADR = source string descriptor - A2LNT<7:0> = match character - A2ADR = table address - - Condition codes: - NZ = set from R0 - VC = 0 - - Registers: - R0:R1 = substring descriptor where operation terminated -*/ - - case 0142: case 0143: /* inline */ - if (!fpd) { /* FPD clear? */ - WriteW (R[4], ((SP - 4) & 0177777) | dsenable); - WriteW (R[5], ((SP - 2) & 0177777) | dsenable); - SP = (SP - 4) & 0177777; /* push R4, R5 */ - R[0] = A1LNT; /* args to registers */ - R[1] = A1ADR; - R[4] = A2LNT; - R[5] = A2ADR; - } /* fall through */ - case 042: case 043: /* register */ - fpd = 1; /* set FPD */ - R[4] = R[4] & 0377; /* match character */ - for (i = 0; R[0] != 0;) { /* loop */ - t = ReadB (R[1] | dsenable); /* get char as index */ - c = ReadB (((R[5] + t) & 0177777) | dsenable); - if (((c & R[4]) != 0) ^ (op & 1)) /* != + SCN, = + SPN? */ - break; - R[0]--; /* decr count, */ - R[1] = (R[1] + 1) & 0177777; /* incr addr */ - if ((++i >= INT_TEST) && R[0]) { /* test for intr? */ - if (cis_int_test (i, old_PC, &st)) - return st; - i = 0; - } - } - N = GET_SIGN_W (R[0]); - Z = GET_Z (R[0]); - V = C = 0; - fpd = 0; /* instr done */ - if (op & INLINE) { /* inline? */ - R[4] = ReadW (SP | dsenable); /* restore R4, R5 */ - R[5] = ReadW (((SP + 2) & 0177777) | dsenable); - SP = (SP + 4) & 0177777; - } - return SCPE_OK; - -/* CMPC, CMPCI - - Operands (CMPC): - R0, R1 = source1 string descriptor - R2, R3 = source2 string descriptor - R4<7:0> = fill character - Operands (CMPCI): - A1LNT, A1ADR = source1 string descriptor - A2LNT, A2ADR = source2 string descriptor - A3LNT<7:0> = fill character - - Condition codes: - NZVC = set from src1 - src2 at mismatch, or - = 0100 if equal - - Registers (CMPC only): - R0:R1 = unmatched source1 substring descriptor - R2:R3 = unmatched source2 substring descriptor -*/ - - case 0144: /* inline */ - if (!fpd) { /* FPD clear? */ - WriteW (R[0], ((SP - 10) & 0177777) | dsenable); - WriteW (R[1], ((SP - 8) & 0177777) | dsenable); - WriteW (R[2], ((SP - 6) & 0177777) | dsenable); - WriteW (R[3], ((SP - 4) & 0177777) | dsenable); - WriteW (R[4], ((SP - 2) & 0177777) | dsenable); - SP = (SP - 10) & 0177777; /* push R0 - R4 */ - R[0] = A1LNT; /* args to registers */ - R[1] = A1ADR; - R[2] = A2LNT; - R[3] = A2ADR; - R[4] = A3LNT; - } /* fall through */ - case 044: /* register */ - fpd = 1; /* set FPD */ - R[4] = R[4] & 0377; /* mask fill */ - c = t = 0; - for (i = 0; (R[0] || R[2]); ) { /* until cnts == 0 */ - if (R[0]) /* get src1 or fill */ - c = ReadB (R[1] | dsenable); - else c = R[4]; - if (R[2]) /* get src2 or fill */ - t = ReadB (R[3] | dsenable); - else t = R[4]; - if (c != t) /* if diff, done */ - break; - if (R[0]) { /* if more src1 */ - R[0]--; /* decr count, */ - R[1] = (R[1] + 1) & 0177777; /* incr addr */ - } - if (R[2]) { /* if more src2 */ - R[2]--; /* decr count, */ - R[3] = (R[3] + 1) & 0177777; /* incr addr */ - } - if ((++i >= INT_TEST) && (R[0] || R[2])) { /* test for intr? */ - if (cis_int_test (i, old_PC, &st)) - return st; - i = 0; - } - } - j = c - t; /* last chars read */ - N = GET_SIGN_B (j); /* set cc's */ - Z = GET_Z (j); - V = GET_SIGN_B ((c ^ t) & (~t ^ j)); - C = (c < t); - fpd = 0; /* instr done */ - if (op & INLINE) { /* inline? */ - R[0] = ReadW (SP | dsenable); /* restore R0 - R4 */ - R[1] = ReadW (((SP + 2) & 0177777) | dsenable); - R[2] = ReadW (((SP + 4) & 0177777) | dsenable); - R[3] = ReadW (((SP + 6) & 0177777) | dsenable); - R[4] = ReadW (((SP + 8) & 0177777) | dsenable); - SP = (SP + 10) & 0177777; - } - return SCPE_OK; - -/* MATC, MATCI - - Operands (MATC): - R0, R1 = source string descriptor - R2, R3 = substring descriptor - Operands (MATCI): - A1LNT, A1ADR = source1 string descriptor - A2LNT, A2ADR = source2 string descriptor - - Condition codes: - NZ = set from R0 - VC = 0 - - Registers: - R0:R1 = source substring descriptor for match - - Notes: - - If the string is zero length, and the substring is not, - the outer loop exits immediately, and the result is - "no match" - - If the substring is zero length, the inner loop always - exits immediately, and the result is a "match" - - If the string is zero length, and the substring is as - well, the outer loop executes, the inner loop exits - immediately, and the result is a match, but the result - is the length of the string (zero), or "no match" -*/ - - case 0145: /* inline */ - if (!fpd) { /* FPD clear? */ - WriteW (R[2], ((SP - 4) & 0177777) | dsenable); - WriteW (R[3], ((SP - 2) & 0177777) | dsenable); - SP = (SP - 4) & 0177777; /* push R2, R3 */ - R[0] = A1LNT; /* args to registers */ - R[1] = A1ADR; - R[2] = A2LNT; - R[3] = A2ADR; - } /* fall through */ - case 0045: /* register */ - fpd = 1; - for (match = 0; R[0] >= R[2]; ) { /* loop thru string */ - for (i = 0, match = 1; match && (i < R[2]); i++) { - c = ReadB (((R[1] + i) & 0177777) | dsenable); - t = ReadB (((R[3] + i) & 0177777) | dsenable); - match = (c == t); /* end for substring */ - } - if (match) /* exit if match */ - break; - R[0]--; /* on to next char */ - R[1] = (R[1] + 1) & 0177777; - if (cis_int_test (i, old_PC, &st)) - return st; - } - if (!match) { /* if no match */ - R[1] = (R[1] + R[0]) & 0177777; - R[0] = 0; - } - N = GET_SIGN_W (R[0]); - Z = GET_Z (R[0]); - V = C = 0; - fpd = 0; /* instr done */ - if (op & INLINE) { /* inline? */ - R[2] = ReadW (SP | dsenable); /* restore R2, R3 */ - R[3] = ReadW (((SP + 2) & 0177777) | dsenable); - SP = (SP + 4) & 0177777; - } - return SCPE_OK; - -/* ADDN, SUBN, ADDP, SUBP, ADDNI, SUBNI, ADDPI, SUBPI - - Operands: - A1LNT, A1ADR = source1 string descriptor - A2LNT, A2ADR = source2 string descriptor - A3LNT, A3ADR = destination string descriptor - - Condition codes: - NZV = set from result - C = 0 - - Registers (ADDN, ADDP, SUBN, SUBP only): - R0:R3 = 0 -*/ - - case 050: case 051: case 070: case 071: - case 0150: case 0151: case 0170: case 0171: - ReadDstr (A1, &src1, op); /* get source1 */ - ReadDstr (A2, &src2, op); /* get source2 */ - if (op & 1) /* sub? invert sign */ - src1.sign = src1.sign ^ 1; - if (src1.sign ^ src2.sign) { /* opp signs? sub */ - if (CmpDstr (&src1, &src2) < 0) { /* src1 < src2? */ - SubDstr (&src1, &src2, &dst); /* src2 - src1 */ - dst.sign = src2.sign; /* sign = src2 */ - } - else { - SubDstr (&src2, &src1, &dst); /* src1 - src2 */ - dst.sign = src1.sign; /* sign = src1 */ - } - V = 0; /* can't carry */ - } - else { /* addition */ - V = AddDstr (&src1, &src2, &dst, 0); /* add magnitudes */ - dst.sign = src1.sign; /* set result sign */ - } - C = 0; - WriteDstr (A3, &dst, op); /* store result */ - if ((op & INLINE) == 0) /* if reg, clr reg */ - R[0] = R[1] = R[2] = R[3] = 0; - return SCPE_OK; - -/* MULP, MULPI - - Operands: - A1LNT, A1ADR = source1 string descriptor - A2LNT, A2ADR = source2 string descriptor - A3LNT, A3ADR = destination string descriptor - - Condition codes: - NZV = set from result - C = 0 - - Registers (MULP only): - R0:R3 = 0 -*/ - - case 074: case 0174: - dst = Dstr0; /* clear result */ - if (ReadDstr (A1, &src1, op) && ReadDstr (A2, &src2, op)) { - dst.sign = src1.sign ^ src2.sign; /* sign of result */ - accum = Dstr0; /* clear accum */ - NibbleRshift (&src1, 1, 0); /* shift out sign */ - CreateTable (&src1, mptable); /* create *1, *2, ... */ - for (i = 1; i < (DSTRLNT * 8); i++) { /* 31 iterations */ - digit = (src2.val[i / 8] >> ((i % 8) * 4)) & 0xF; - if (digit > 0) /* add in digit*mpcnd */ - AddDstr (&mptable[digit], &accum, &accum, 0); - nc = NibbleRshift (&accum, 1, 0); /* ac right 4 */ - NibbleRshift (&dst, 1, nc); /* result right 4 */ - } - V = TestDstr (&accum) != 0; /* if ovflo, set V */ - } - else V = 0; /* result = 0 */ - C = 0; /* C = 0 */ - WriteDstr (A3, &dst, op); /* store result */ - if ((op & INLINE) == 0) /* if reg, clr reg */ - R[0] = R[1] = R[2] = R[3] = 0; - return SCPE_OK; - -/* DIVP, DIVPI - - Operands: - A1LNT, A1ADR = divisor string descriptor - A2LNT, A2ADR = dividend string descriptor - A3LNT, A3ADR = destination string descriptor - - Condition codes: - NZV = set from result - C = set if divide by zero - - Registers (DIVP only): - R0:R3 = 0 -*/ - - case 075: case 0175: - ldivr = ReadDstr (A1, &src1, op); /* get divisor */ - if (ldivr == 0) { /* divisor = 0? */ - V = C = 1; /* set cc's */ - return SCPE_OK; - } - ldivr = LntDstr (&src1, ldivr); /* get exact length */ - ldivd = ReadDstr (A2, &src2, op); /* get dividend */ - ldivd = LntDstr (&src2, ldivd); /* get exact length */ - dst = Dstr0; /* clear dest */ - NibbleRshift (&src1, 1, 0); /* right justify ops */ - NibbleRshift (&src2, 1, 0); - if ((t = ldivd - ldivr) >= 0) { /* any divide to do? */ - WordLshift (&src1, t / 8); /* align divr to divd */ - NibbleLshift (&src1, t % 8); - CreateTable (&src1, mptable); /* create *1, *2, ... */ - for (i = 0; i <= t; i++) { /* divide loop */ - for (digit = 9; digit > 0; digit--) { /* find digit */ - if (CmpDstr (&src2, &mptable[digit]) >= 0) { - SubDstr (&mptable[digit], &src2, &src2); - dst.val[0] = dst.val[0] | digit; - break; - } /* end if */ - } /* end for */ - NibbleLshift (&src2, 1); /* shift dividend */ - NibbleLshift (&dst, 1); /* shift quotient */ - } /* end divide loop */ - dst.sign = src1.sign ^ src2.sign; /* calculate sign */ - } /* end if */ - V = C = 0; - WriteDstr (A3, &dst, op); /* store result */ - if ((op & INLINE) == 0) /* if reg, clr reg */ - R[0] = R[1] = R[2] = R[3] = 0; - return SCPE_OK; - -/* CMPN, CMPP, CMPNI, CMPPI - - Operands: - A1LNT, A1ADR = source1 string descriptor - A2LNT, A2ADR = source2 string descriptor - - Condition codes: - NZ = set from comparison - VC = 0 - - Registers (CMPN, CMPP only): - R0:R3 = 0 -*/ - - case 052: case 072: case 0152: case 0172: - ReadDstr (A1, &src1, op); /* get source1 */ - ReadDstr (A2, &src2, op); /* get source2 */ - N = Z = V = C = 0; - if (src1.sign != src2.sign) N = src1.sign; - else { - t = CmpDstr (&src1, &src2); /* compare strings */ - if (t < 0) - N = (src1.sign? 0: 1); - else if (t > 0) - N = (src1.sign? 1: 0); - else Z = 1; - } - if ((op & INLINE) == 0) /* if reg, clr reg */ - R[0] = R[1] = R[2] = R[3] = 0; - return SCPE_OK; - -/* ASHN, ASHP, ASHNI, ASHPI - - Operands: - A1LNT, A1ADR = source string descriptor - A2LNT, A2ADR = destination string descriptor - A3LNT<11:8> = rounding digit - A3LNT<7:0> = shift count - - Condition codes: - NZV = set from result - C = 0 - - Registers (ASHN, ASHP only): - R0:R1, R4 = 0 -*/ - - case 056: case 076: case 0156: case 0176: - ReadDstr (A1, &src1, op); /* get source */ - V = C = 0; /* init cc's */ - shift = GET_ASHLNT (A3LNT); /* get shift count */ - if (shift & ASHSGN) { /* right shift? */ - shift = (ASHLNT_M + 1 - shift); /* !shift! */ - WordRshift (&src1, shift / 8); /* do word shifts */ - NibbleRshift (&src1, shift % 8, 0); /* do nibble shifts */ - t = GET_ASHRND (A3LNT); /* get rounding digit */ - if ((t + (src1.val[0] & 0xF)) > 9) /* rounding needed? */ - AddDstr (&src1, &Dstr1, &src1, 0); /* round */ - src1.val[0] = src1.val[0] & ~0xF; /* clear sign */ - } /* end right shift */ - else if (shift) { /* left shift? */ - if (WordLshift (&src1, shift / 8)) /* do word shifts */ - V = 1; - if (NibbleLshift (&src1, shift % 8)) /* do nibble shifts */ - V = 1; - } /* end left shift */ - WriteDstr (A2, &src1, op); /* store result */ - if ((op & INLINE) == 0) /* if reg, clr reg */ - R[0] = R[1] = R[4] = 0; - return SCPE_OK; - -/* CVTPN, CVTPNI - - Operands: - A1LNT, A1ADR = source string descriptor - A2LNT, A2ADR = destination string descriptor - - Condition codes: - NZV = set from result - C = 0 - - Registers (CVTPN only): - R0:R1 = 0 -*/ - - case 054: case 0154: - ReadDstr (A1, &src1, PACKED); /* get source */ - V = C = 0; /* init cc's */ - WriteDstr (A2, &src1, NUMERIC); /* write dest */ - if ((op & INLINE) == 0) /* if reg, clr reg */ - R[0] = R[1] = 0; - return SCPE_OK; - -/* CVTNP, CVTNPI - - Operands: - A1LNT, A1ADR = source string descriptor - A2LNT, A2ADR = destination string descriptor - - Condition codes: - NZV = set from result - C = 0 - - Registers (CVTNP only): - R0:R1 = 0 -*/ - - case 055: case 0155: - ReadDstr (A1, &src1, NUMERIC); /* get source */ - V = C = 0; /* init cc's */ - WriteDstr (A2, &src1, PACKED); /* write dest */ - if ((op & INLINE) == 0) /* if reg, clr reg */ - R[0] = R[1] = 0; - return SCPE_OK; - -/* CVTNL, CVTPL, CVTNLI, CVTPLI - - Operands: - A1LNT, A1ADR = source string descriptor - A2LNT = destination address (inline only) - - Condition codes: - NZV = set from result - C = source < 0 and result != 0 - - Registers (CVTNL, CVTPL only): - R0:R1 = 0 - R2:R3 = result -*/ - - case 053: case 073: case 0153: case 0173: - ReadDstr (A1, &src1, op); /* get source */ - V = result = 0; /* clear V, result */ - for (i = (DSTRLNT * 8) - 1; i > 0; i--) { /* loop thru digits */ - digit = (src1.val[i / 8] >> ((i % 8) * 4)) & 0xF; - if (digit || result || V) { /* skip initial 0's */ - if (result >= MAXDVAL) - V = 1; - result = (result * 10) + digit; - if (result < digit) - V = 1; - } /* end if */ - } /* end for */ - if (src1.sign) - result = (~result + 1) & 0xFFFFFFFF; - N = GET_SIGN_L (result); - Z = GET_Z (result); - V = V | (N ^ src1.sign); /* overflow if +2**31 */ - C = src1.sign && (Z == 0); /* set C based on std */ - if (op & INLINE) { /* inline? */ - WriteW (result & 0177777, A2LNT | dsenable); - WriteW ((result >> 16) & 0177777, - ((A2LNT + 2) & 0177777) | dsenable); - } - else { - R[0] = R[1] = 0; - R[2] = (result >> 16) & 0177777; - R[3] = result & 0177777; - } - return SCPE_OK; - -/* CVTLN, CVTLP, CVTLNI, CVTLPI - - Operands: - A1LNT, A1ADR = destination string descriptor - A2LNT, A2ADR = source long (CVTLNI, CVTLPI) - VAX format - R2:R3 = source long (CVTLN, CVTLP) - EIS format - - Condition codes: - NZV = set from result - C = 0 - - Registers (CVTLN, CVTLP only) - R2:R3 = 0 -*/ - - case 057: case 077: - result = (R[2] << 16) | R[3]; /* op in EIS format */ - R[2] = R[3] = 0; /* clear registers */ - goto CVTLx; /* join common code */ - case 0157: case 0177: - result = (A2ADR << 16) | A2LNT; /* op in VAX format */ - CVTLx: - dst = Dstr0; /* clear result */ - if ((dst.sign = GET_SIGN_L (result))) - result = (~result + 1) & 0xFFFFFFFF; - for (i = 1; (i < (DSTRLNT * 8)) && result; i++) { - digit = result % 10; - result = result / 10; - dst.val[i / 8] = dst.val[i / 8] | (digit << ((i % 8) * 4)); - } - V = C = 0; - WriteDstr (A1, &dst, op); /* write result */ - return SCPE_OK; - - default: - setTRAP (TRAP_ILL); - break; - } /* end case */ -return SCPE_OK; -} /* end cis */ - -/* Get decimal string - - Arguments: - dscr = decimal string descriptor - src = decimal string structure - flag = numeric/packed flag - - The routine returns the length in int32's of the non-zero part of - the string. - - This routine plays fast and loose with operand checking, as did the - original 11/23 microcode (half of which I wrote). In particular, - - - If the flag specifies packed, the type is not checked at all. - The sign of an unsigned string is assumed to be 0xF (an - alternative for +). - - If the flag specifies numeric, packed types will be treated - as unsigned zoned. - - For separate, only the '-' sign is checked, not the '+'. - - However, to simplify the code elsewhere, digits are range checked, - and bad digits are replaced with 0's. -*/ - -int32 ReadDstr (int32 *dscr, DSTR *src, int32 flag) -{ -int32 c, i, end, lnt, type, t = 0; - -*src = Dstr0; /* clear result */ -type = GET_DTYP (dscr[0]); /* get type */ -lnt = GET_DLNT (dscr[0]); /* get string length */ -if (flag & PACKED) { /* packed? */ - end = lnt / 2; /* last byte */ - for (i = 0; i <= end; i++) { /* loop thru string */ - c = ReadB (((dscr[1] + end - i) & 0177777) | dsenable); - if (i == 0) /* save sign */ - t = c & 0xF; - if ((i == end) && ((lnt & 1) == 0)) - c = c & 0xF; - if (c >= 0xA0) /* check hi digit */ - c = c & 0xF; - if ((c & 0xF) >= 0xA) /* check lo digit */ - c = c & 0xF0; - src->val[i / 4] = src->val[i / 4] | (c << ((i % 4) * 8)); - } /* end for */ - if ((t == 0xB) || (t == 0xD)) /* if -, set sign */ - src->sign = 1; - src->val[0] = src->val[0] & ~0xF; /* clear sign */ - } /* end packed */ -else { /* numeric */ - if (type >= TS) src->sign = (ReadB ((((type == TS)? - dscr[1] + lnt: dscr[1] - 1) & 0177777) | dsenable) == '-'); - for (i = 1; i <= lnt; i++) { /* loop thru string */ - c = ReadB (((dscr[1] + lnt - i) & 0177777) | dsenable); - if ((i == 1) && (type == XZ) && ((c & 0xF0) == 0x70)) - src->sign = 1; /* signed zoned */ - else if (((i == 1) && (type == TO)) || - ((i == lnt) && (type == LO))) { - c = overbin[c & 0177]; /* get sign and digit */ - src->sign = c >> 7; /* set sign */ - } - c = c & 0xF; /* get digit */ - if (c > 9) /* range check */ - c = 0; - src->val[i / 8] = src->val[i / 8] | (c << ((i % 8) * 4)); - } /* end for */ - } /* end numeric */ -return TestDstr (src); /* clean -0 */ -} - -/* Store decimal string - - Arguments: - dsrc = decimal string descriptor - src = decimal string structure - flag = numeric/packed flag - - PSW.NZ are also set to their proper values - PSW.V will be set on overflow; it must be initialized elsewhere - (to allow for external overflow calculations) - - The rules for the stored sign and the PSW sign are: - - - Stored sign is negative if input is negative, string type - is signed, and the result is non-zero or there was overflow - - PSW sign is negative if input is negative, string type is - signed, and the result is non-zero - - Thus, the stored sign and the PSW sign will differ in one case: - a negative zero generated by overflow is stored with a negative - sign, but PSW.N is clear -*/ - -void WriteDstr (int32 *dscr, DSTR *dst, int32 flag) -{ -int32 c, i, limit, end, type, lnt; -uint32 mask; -static uint32 masktab[8] = { - 0xFFFFFFF0, 0xFFFFFF00, 0xFFFFF000, 0xFFFF0000, - 0xFFF00000, 0xFF000000, 0xF0000000, 0x00000000 - }; -static int32 unsignedtab[8] = { 0, 1, 0, 0, 0, 0, 0, 1 }; - -type = GET_DTYP (dscr[0]); /* get type */ -lnt = GET_DLNT (dscr[0]); /* get string length */ -mask = 0; /* can't ovflo */ -Z = 1; /* assume all 0's */ -limit = lnt / 8; /* limit for test */ -for (i = 0; i < DSTRLNT; i++) { /* loop thru value */ - if (i == limit) /* at limit, get mask */ - mask = masktab[lnt % 8]; - else if (i > limit) /* beyond, all ovflo */ - mask = 0xFFFFFFFF; - if (dst->val[i] & mask) /* test for ovflo */ - V = 1; - if ((dst->val[i] = dst->val[i] & ~mask)) /* test nz */ - Z = 0; - } -dst->sign = dst->sign & ~unsignedtab[type] & ~(Z & ~V); -N = dst->sign & ~Z; /* N = sign, if ~zero */ - -if (flag & PACKED) { /* packed? */ - end = lnt / 2; /* end of string */ - if (type == UP) - dst->val[0] = dst->val[0] | 0xF; - else dst->val[0] = dst->val[0] | 0xC | dst->sign; - for (i = 0; i <= end; i++) { /* store string */ - c = (dst->val[i / 4] >> ((i % 4) * 8)) & 0xFF; - WriteB (c, ((dscr[1] + end - i) & 0177777) | dsenable); - } /* end for */ - } /* end packed */ -else { - if (type >= TS) WriteB (dst->sign? '-': '+', (((type == TS)? - dscr[1] + lnt: dscr[1] - 1) & 0177777) | dsenable); - for (i = 1; i <= lnt; i++) { /* store string */ - c = (dst->val[i / 8] >> ((i % 8) * 4)) & 0xF; /* get digit */ - if ((i == 1) && (type == XZ) && dst->sign) - c = c | 0x70; /* signed zoned */ - else if (((i == 1) && (type == TO)) || - ((i == lnt) && (type == LO))) - c = binover[dst->sign][c]; /* get sign and digit */ - else c = c | 0x30; /* default */ - WriteB (c, ((dscr[1] + lnt - i) & 0177777) |dsenable ); - } /* end for */ - } /* end numeric */ -return; -} - -/* Add decimal string magnitudes - - Arguments: - s1 = source1 decimal string - s2 = source2 decimal string - ds = destination decimal string - cy = carry in - Output = 1 if carry, 0 if no carry - - This algorithm courtesy Anton Chernoff, circa 1992 or even earlier. - - We trace the history of a pair of adjacent digits to see how the - carry is fixed; each parenthesized item is a 4b digit. - - Assume we are adding: - - (a)(b) I - + (x)(y) J - - First compute I^J: - - (a^x)(b^y) TMP - - Note that the low bit of each digit is the same as the low bit of - the sum of the digits, ignoring the carry, since the low bit of the - sum is the xor of the bits. - - Now compute I+J+66 to get decimal addition with carry forced left - one digit: - - (a+x+6+carry mod 16)(b+y+6 mod 16) SUM - - Note that if there was a carry from b+y+6, then the low bit of the - left digit is different from the expected low bit from the xor. - If we xor this SUM into TMP, then the low bit of each digit is 1 - if there was a carry, and 0 if not. We need to subtract 6 from each - digit that did not have a carry, so take ~(SUM ^ TMP) & 0x11, shift - it right 4 to the digits that are affected, and subtract 6*adjustment - (actually, shift it right 3 and subtract 3*adjustment). -*/ - -int32 AddDstr (DSTR *s1, DSTR *s2, DSTR *ds, int32 cy) -{ -int32 i; -uint32 sm1, sm2, tm1, tm2, tm3, tm4; - -for (i = 0; i < DSTRLNT; i++) { /* loop low to high */ - tm1 = s1->val[i] ^ (s2->val[i] + cy); /* xor operands */ - sm1 = s1->val[i] + (s2->val[i] + cy); /* sum operands */ - sm2 = sm1 + 0x66666666; /* force carry out */ - cy = ((sm1 < s1->val[i]) || (sm2 < sm1)); /* check for overflow */ - tm2 = tm1 ^ sm2; /* get carry flags */ - tm3 = (tm2 >> 3) | (cy << 29); /* compute adjustment */ - tm4 = 0x22222222 & ~tm3; /* clear where carry */ - ds->val[i] = sm2 - (3 * tm4); /* final result */ - } -return cy; -} - -/* Subtract decimal string magnitudes - - Arguments: - s1 = source1 decimal string - s2 = source2 decimal string - ds = destination decimal string - Outputs: s2 - s1 in ds - - Note: the routine assumes that s1 <= s2 - -*/ - -void SubDstr (DSTR *s1, DSTR *s2, DSTR *ds) -{ -int32 i; -DSTR compl; - -for (i = 0; i < DSTRLNT; i++) - compl.val[i] = 0x99999999 - s1->val[i]; -AddDstr (&compl, s2, ds, 1); /* s1 + ~s2 + 1 */ -return; -} - -/* Compare decimal string magnitudes - - Arguments: - s1 = source1 decimal string - s2 = source2 decimal string - Output = 1 if >, 0 if =, -1 if < -*/ - -int32 CmpDstr (DSTR *s1, DSTR *s2) -{ -int32 i; - -for (i = DSTRMAX; i >=0; i--) { - if (s1->val[i] > s2->val[i]) - return 1; - if (s1->val[i] < s2->val[i]) - return -1; - } -return 0; -} - -/* Test decimal string for zero - - Arguments: - dsrc = decimal string structure - - Returns the non-zero length of the string, in int32 units - If the string is zero, the sign is cleared -*/ - -int32 TestDstr (DSTR *dsrc) -{ -int32 i; - -for (i = DSTRMAX; i >= 0; i--) { - if (dsrc->val[i]) - return (i + 1); - } -dsrc->sign = 0; -return 0; -} - -/* Get exact length of decimal string - - Arguments: - dsrc = decimal string structure - nz = result from TestDstr -*/ - -int32 LntDstr (DSTR *dsrc, int32 nz) -{ -int32 i; - -if (nz == 0) - return 0; -for (i = 7; i >= 0; i--) { - if ((dsrc->val[nz - 1] >> (i * 4)) & 0xF) - break; - } -return ((nz - 1) * 8) + i; -} - -/* Create table of multiples - - Arguments: - dsrc = base decimal string structure - mtable[10] = array of decimal string structures - - Note that dsrc has a high order zero nibble; this - guarantees that the largest multiple won't overflow. - Also note that mtable[0] is not filled in. -*/ - -void CreateTable (DSTR *dsrc, DSTR mtable[10]) -{ -int32 (i); - -mtable[1] = *dsrc; -for (i = 2; i < 10; i++) - AddDstr (&mtable[1], &mtable[i-1], &mtable[i], 0); -return; -} - -/* Word shift right - - Arguments: - dsrc = decimal string structure - sc = shift count -*/ - -void WordRshift (DSTR *dsrc, int32 sc) -{ -int32 i; - -if (sc) { - for (i = 0; i < DSTRLNT; i++) { - if ((i + sc) < DSTRLNT) - dsrc->val[i] = dsrc->val[i + sc]; - else dsrc->val[i] = 0; - } - } -return; -} - -/* Word shift left - - Arguments: - dsrc = decimal string structure - sc = shift count -*/ - -int32 WordLshift (DSTR *dsrc, int32 sc) -{ -int32 i, c; - -c = 0; -if (sc) { - for (i = DSTRMAX; i >= 0; i--) { - if (i >= sc) - dsrc->val[i] = dsrc->val[i - sc]; - else { - c |= dsrc->val[i]; - dsrc->val[i] = 0; - } - } - } -return c; -} - -/* Nibble shift decimal string right - - Arguments: - dsrc = decimal string structure - sc = shift count - cin = carry in -*/ - -uint32 NibbleRshift (DSTR *dsrc, int32 sc, uint32 cin) -{ -int32 i, s, nc; - -if ((s = sc * 4)) { - for (i = DSTRMAX; i >= 0; i--) { - nc = (dsrc->val[i] << (32 - s)) & 0xFFFFFFFF; - dsrc->val[i] = ((dsrc->val[i] >> s) | - cin) & 0xFFFFFFFF; - cin = nc; - } - return cin; - } -return 0; -} - -/* Nibble shift decimal string left - - Arguments: - dsrc = decimal string structure - sc = shift count -*/ - -uint32 NibbleLshift (DSTR *dsrc, int32 sc) -{ -int32 i, s; -uint32 nc, cin; - -cin = 0; -if ((s = sc * 4)) { - for (i = 0; i < DSTRLNT; i++) { - nc = dsrc->val[i] >> (32 - s); - dsrc->val[i] = ((dsrc->val[i] << s) | cin) & 0xFFFFFFFF; - cin = nc; - } - return cin; - } -return 0; -} - -/* Common setup routine for MOVC class instructions */ - -int32 movx_setup (int32 op, int32 *arg) -{ -int32 mvlnt, t; - -if (CPUT (CPUT_44)) { /* 11/44? */ - ReadMB (((SP - 0200) & 0177777) | dsenable); /* probe both blocks */ - ReadMB (((SP - 0100) & 0177777) | dsenable); /* in 64W stack area */ - } -if (op & INLINE) { /* inline */ - mvlnt = (A1LNT < A2LNT)? A1LNT: A2LNT; - WriteW (mvlnt, ((SP - 14) & 0177777) | dsenable); /* push move length */ - WriteW (R[0], ((SP - 12) & 0177777) | dsenable); /* push R0 - R5 */ - WriteW (R[1], ((SP - 10) & 0177777) | dsenable); - WriteW (R[2], ((SP - 8) & 0177777) | dsenable); - WriteW (R[3], ((SP - 6) & 0177777) | dsenable); - WriteW (R[4], ((SP - 4) & 0177777) | dsenable); - WriteW (R[5], ((SP - 2) & 0177777) | dsenable); - SP = (SP - 14) & 0177777; - R[0] = A1LNT; /* args to registers */ - R[1] = A1ADR; - R[2] = A2LNT; - R[3] = A2ADR; - R[4] = A3LNT; - R[5] = A3ADR & 0177777; - } -else { /* register */ - mvlnt = (R[0] < R[2])? R[0]: R[2]; - WriteW (mvlnt, ((SP - 2) & 0177777) | dsenable); /* push move length */ - SP = (SP - 2) & 0177777; - } -fpd = 1; -t = R[0] - R[2]; /* src.lnt - dst.lnt */ -N = GET_SIGN_W (t); /* set cc's from diff */ -Z = GET_Z (t); -V = GET_SIGN_W ((R[0] ^ R[2]) & (~R[2] ^ t)); -C = (R[0] < R[2]); -return mvlnt; -} - -/* Common cleanup routine for MOVC class instructions */ - -void movx_cleanup (int32 op) -{ -SP = (SP + 2) & 0177777; /* discard mvlnt */ -if (op & INLINE) { /* inline? */ - R[0] = ReadW (SP | dsenable); /* restore R0 - R5 */ - R[1] = ReadW (((SP + 2) & 0177777) | dsenable); - R[2] = ReadW (((SP + 4) & 0177777) | dsenable); - R[3] = ReadW (((SP + 6) & 0177777) | dsenable); - R[4] = ReadW (((SP + 8) & 0177777) | dsenable); - R[5] = ReadW (((SP + 10) & 0177777) | dsenable); - SP = (SP + 12) & 0177777; - } -else R[1] = R[2] = R[3] = 0; /* reg, clear R1 - R3 */ -fpd = 0; /* instr done */ -return; -} - -/* Test for CIS mid-instruction interrupt */ - -t_bool cis_int_test (int32 cycles, int32 oldpc, t_stat *st) -{ -while (cycles >= 0) { /* until delay done */ - if (sim_interval > cycles) { /* event > delay */ - sim_interval = sim_interval - cycles; - break; - } - else { /* event <= delay */ - cycles = cycles - sim_interval; /* decr delay */ - sim_interval = 0; /* process event */ - *st = sim_process_event (); - trap_req = calc_ints (ipl, trap_req); /* recalc int req */ - if ((*st != SCPE_OK) || /* bad status or */ - trap_req & TRAP_INT) { /* interrupt? */ - PC = oldpc; /* back out */ - return TRUE; - } /* end if stop */ - } /* end else event */ - } /* end while delay */ -return FALSE; -} diff --git a/PDP11/pdp11_cpu.c b/PDP11/pdp11_cpu.c deleted file mode 100644 index 053561be..00000000 --- a/PDP11/pdp11_cpu.c +++ /dev/null @@ -1,3197 +0,0 @@ -/* pdp11_cpu.c: PDP-11 CPU simulator - - Copyright (c) 1993-2018, 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. - - cpu PDP-11 CPU - - 04-Jun-18 RMS Removed CPU model entries for UC15 (Mark Pizzolato) - 04-Dec-16 RMS Removed duplicate IDLE entries in MTAB - 30-Aug-16 RMS Fixed overloading of -d in ex/mod - 14-Mar-16 RMS Added UC15 support - 06-Mar-16 RMS Fixed bug in history virtual addressing - 30-Dec-15 RMS Added NOBEVENT option for 11/03, 11/23 - 29-Dec-15 RMS Call build_dib_tab during reset (Mark Pizzolato) - 05-Dec-13 RMS Fixed bug in CSM (John Dundas) - 23-Oct-13 RMS Fixed PS behavior on initialization and boot - 10-Apr-13 RMS MMR1 does not track PC changes (Johnny Billquist) - 29-Apr-12 RMS Fixed compiler warning (Mark Pizzolato) - 19-Mar-12 RMS Fixed declaration of sim_switches (Mark Pizzolato) - 29-Dec-08 RMS Fixed failure to clear cpu_bme on RESET (Walter Mueller) - 22-Apr-08 RMS Fixed MMR0 treatment in RESET (Walter Mueller) - 02-Feb-08 RMS Fixed DMA memory address limit test (John Dundas) - 28-Apr-07 RMS Removed clock initialization - 27-Oct-06 RMS Added idle support - 18-Oct-06 RMS Fixed bug in ASH -32 C value - 24-May-06 RMS Added instruction history - 03-May-06 RMS Fixed XOR operand fetch order for 11/70-style systems - 22-Sep-05 RMS Fixed declarations (Sterling Garwood) - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 19-May-05 RMS Replaced WAIT clock queue check with API call - 19-Jan-05 RMS Fixed bug(s) in RESET for 11/70 (Tim Chapman) - 22-Dec-04 RMS Fixed WAIT to work in all modes (John Dundas) - 02-Oct-04 RMS Added model emulation - 25-Jan-04 RMS Removed local debug logging support - 29-Dec-03 RMS Formalized 18b Qbus support - 21-Dec-03 RMS Added autoconfiguration controls - 05-Jun-03 RMS Fixed bugs in memory size table - 12-Mar-03 RMS Added logical name support - 01-Feb-03 RMS Changed R display to follow PSW, added SP display - 19-Jan-03 RMS Changed mode definitions for Apple Dev Kit conflict - 05-Jan-03 RMS Added memory size restore support - 17-Oct-02 RMS Fixed bug in examine/deposit (Hans Pufal) - 08-Oct-02 RMS Revised to build dib_tab dynamically - Added SHOW IOSPACE - 09-Sep-02 RMS Added KW11P support - 14-Jul-02 RMS Fixed bug in MMR0 error status load - 03-Jun-02 RMS Fixed relocation add overflow, added PS<15:12> = 1111 - special case logic to MFPI and removed it from MTPI - (John Dundas) - 29-Apr-02 RMS More fixes to DIV and ASH/ASHC (John Dundas) - 28-Apr-02 RMS Fixed bugs in illegal instruction 000010 and in - write-only memory pages (Wolfgang Helbig) - 21-Apr-02 RMS Fixed bugs in DIV by zero, DIV overflow, TSTSET, RTS, - ASHC -32, and red zone trap (John Dundas) - 04-Mar-02 RMS Changed double operand evaluation order for M+ - 23-Feb-02 RMS Fixed bug in MAINT, CPUERR, MEMERR read - 28-Jan-02 RMS Revised for multiple timers; fixed calc_MMR1 macros - 06-Jan-02 RMS Revised enable/disable support - 30-Dec-01 RMS Added old PC queue - 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 - 26-Aug-01 RMS Added DZ11 support - 10-Aug-01 RMS Removed register from declarations - 17-Jul-01 RMS Fixed warning from VC++ 6.0 - 01-Jun-01 RMS Added DZ11 interrupts - 23-Apr-01 RMS Added RK611 support - 05-Apr-01 RMS Added TS11/TSV05 support - 05-Mar-01 RMS Added clock calibration support - 11-Feb-01 RMS Added DECtape support - 25-Jan-01 RMS Fixed 4M memory definition (Eric Smith) - 14-Apr-99 RMS Changed t_addr to unsigned - 18-Aug-98 RMS Added CIS support - 09-May-98 RMS Fixed bug in DIV overflow test - 19-Jan-97 RMS Added RP/RM support - 06-Apr-96 RMS Added dynamic memory sizing - 29-Feb-96 RMS Added TM11 support - 17-Jul-94 RMS Corrected updating of MMR1 if MMR0 locked - - The register state for the PDP-11 is: - - REGFILE[0:5][0] general register set - REGFILE[0:5][1] alternate general register set - STACKFILE[4] stack pointers for kernel, supervisor, unused, user - PC program counter - PSW processor status word - <15:14> = CM current processor mode - <13:12> = PM previous processor mode - <11> = RS register set select - <8> = FPD first part done (CIS) - <7:5> = IPL interrupt priority level - <4> = TBIT trace trap enable - <3:0> = NZVC condition codes - FR[0:5] floating point accumulators - FPS floating point status register - FEC floating exception code - FEA floating exception address - MMR0,1,2,3 memory management control registers - APRFILE[0:63] memory management relocation registers for - kernel, supervisor, unused, user - <31:16> = PAR processor address registers - <15:0> = PDR processor data registers - PIRQ processor interrupt request register - CPUERR CPU error register - MEMERR memory system error register - CCR cache control register - MAINT maintenance register - HITMISS cache status register - SR switch register - DR display register - - The PDP-11 has many instruction formats: - - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ double operand - | opcode | source spec | dest spec | 010000:067777 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 110000:167777 - - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ register + operand - | opcode | src reg| dest spec | 004000:004777 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 070000:077777 - - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ single operand - | opcode | dest spec | 000100:000177 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 000300:000377 - 005000:007777 - 105000:107777 - - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ single register - | opcode |dest reg| 000200:000207 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 000230:000237 - - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ no operand - | opcode | 000000:000007 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ branch - | opcode | branch displacement | 000400:003477 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 100000:103477 - - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ EMT/TRAP - | opcode | trap code | 104000:104777 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ cond code operator - | opcode | immediate | 000240:000277 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - An operand specifier consists of an addressing mode and a register. - The addressing modes are: - - 0 register direct R op = R - 1 register deferred (R) op = M[R] - 2 autoincrement (R)+ op = M[R]; R = R + length - 3 autoincrement deferred @(R)+ op = M[M[R]]; R = R + 2 - 4 autodecrement -(R) R = R - length; op = M[R] - 5 autodecrement deferred @-(R) R = R - 2; op = M[M[R]] - 6 displacement d(R) op = M[R + disp] - 7 displacement deferred @d(R) op = M[M[R + disp]] - - There are eight general registers, R0-R7. R6 is the stack pointer, - R7 the PC. The combination of addressing modes with R7 yields: - - 27 immediate #n op = M[PC]; PC = PC + 2 - 37 absolute @#n op = M[M[PC]]; PC = PC + 2 - 67 relative d(PC) op = M[PC + disp] - 77 relative deferred @d(PC) op = M[M[PC + disp]] - - This routine is the instruction decode routine for the PDP-11. It - is called from the simulator control program to execute instructions - in simulated memory, starting at the simulated PC. It runs until an - enabled exception is encountered. - - General notes: - - 1. Virtual address format. PDP-11 memory management uses the 16b - virtual address, the type of reference (instruction or data), and - the current mode, to construct the 22b physical address. To - package this conveniently, the simulator uses a 19b pseudo virtual - address, consisting of the 16b virtual address prefixed with the - current mode and ispace/dspace indicator. These are precalculated - as isenable and dsenable for ispace and dspace, respectively, and - must be recalculated whenever MMR0, MMR3, or PSW changes. - - 2. Traps and interrupts. Variable trap_req bit-encodes all possible - traps. In addition, an interrupt pending bit is encoded as the - lowest priority trap. Traps are processed by trap_vec and trap_clear, - which provide the vector and subordinate traps to clear, respectively. - - Array int_req[0:7] bit encodes all possible interrupts. It is masked - under the interrupt priority level, ipl. If any interrupt request - is not masked, the interrupt bit is set in trap_req. While most - interrupts are handled centrally, a device can supply an interrupt - acknowledge routine. - - 3. PSW handling. The PSW is kept as components, for easier access. - Because the PSW can be explicitly written as address 17777776, - all instructions must update PSW before executing their last write. - - 4. Adding I/O devices. These modules must be modified: - - pdp11_defs.h add device address and interrupt definitions - pdp11_sys.c add to sim_devices table entry -*/ - -/* Definitions */ - -#include "pdp11_defs.h" -#include "pdp11_cpumod.h" - -#define PCQ_SIZE 64 /* must be 2**n */ -#define PCQ_MASK (PCQ_SIZE - 1) -#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC -#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)? (((val) << 8) | MMR1): (val)) -#define GET_SIGN_W(v) (((v) >> 15) & 1) -#define GET_SIGN_B(v) (((v) >> 7) & 1) -#define GET_Z(v) ((v) == 0) -#define JMP_PC(x) PCQ_ENTRY; PC = (x) -#define BRANCH_F(x) PCQ_ENTRY; PC = (PC + (((x) + (x)) & 0377)) & 0177777 -#define BRANCH_B(x) PCQ_ENTRY; PC = (PC + (((x) + (x)) | 0177400)) & 0177777 -#define last_pa (cpu_unit.u4) /* auto save/rest */ -#define UNIT_V_MSIZE (UNIT_V_UF + 0) /* dummy */ -#define UNIT_MSIZE (1u << UNIT_V_MSIZE) - -#define HIST_MIN 64 -#define HIST_MAX (1u << 18) -#define HIST_VLD 1 /* make PC odd */ -#define HIST_ILNT 4 /* max inst length */ - -typedef struct { - uint16 pc; - uint16 psw; - uint16 src; - uint16 dst; - uint16 sp; - uint16 pad; - uint16 inst[HIST_ILNT]; - } InstHistory; - -/* Global state */ - -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 */ -int32 R[8] = { 0 }; /* working registers */ -int32 PSW = 0; /* PSW */ - int32 cm = 0; /* current mode */ - int32 pm = 0; /* previous mode */ - int32 rs = 0; /* register set */ - int32 fpd = 0; /* first part done */ - int32 ipl = 0; /* int pri level */ - int32 tbit = 0; /* trace flag */ - int32 N = 0, Z = 0, V = 0, C = 0; /* condition codes */ -int32 wait_state = 0; /* wait state */ -int32 trap_req = 0; /* trap requests */ -int32 int_req[IPL_HLVL] = { 0 }; /* interrupt requests */ -int32 PIRQ = 0; /* programmed int req */ -int32 STKLIM = 0; /* stack limit */ -fpac_t FR[6] = { {0} }; /* fp accumulators */ -int32 FPS = 0; /* fp status */ -int32 FEC = 0; /* fp exception code */ -int32 FEA = 0; /* fp exception addr */ -int32 APRFILE[64] = { 0 }; /* PARs/PDRs */ -int32 MMR0 = 0; /* MMR0 - status */ -int32 MMR1 = 0; /* MMR1 - R+/-R */ -int32 MMR2 = 0; /* MMR2 - saved PC */ -int32 MMR3 = 0; /* MMR3 - 22b status */ -int32 cpu_bme = 0; /* bus map enable */ -int32 cpu_astop = 0; /* address stop */ -int32 isenable = 0, dsenable = 0; /* i, d space flags */ -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 autcon_enb = 1; /* autoconfig enable */ -uint32 cpu_model = INIMODEL; /* CPU model */ -uint32 cpu_type = 1u << INIMODEL; /* model as bit mask */ -uint32 cpu_opt = INIOPTNS; /* CPU options */ -uint16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ -int32 pcq_p = 0; /* PC queue ptr */ -REG *pcq_r = NULL; /* PC queue reg ptr */ -jmp_buf save_env; /* abort handler */ -int32 hst_p = 0; /* history pointer */ -int32 hst_lnt = 0; /* history length */ -InstHistory *hst = NULL; /* instruction history */ -int32 dsmask[4] = { MMR3_KDS, MMR3_SDS, 0, MMR3_UDS }; /* dspace enables */ - -extern int32 CPUERR, MAINT; -extern CPUTAB cpu_tab[]; - -/* 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_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat cpu_show_virt (FILE *st, UNIT *uptr, int32 val, void *desc); -int32 GeteaB (int32 spec); -int32 GeteaW (int32 spec); -int32 relocR (int32 addr); -int32 relocW (int32 addr); -void relocR_test (int32 va, int32 apridx); -void relocW_test (int32 va, int32 apridx); -t_bool PLF_test (int32 va, int32 apr); -void reloc_abort (int32 err, int32 apridx); -int32 ReadE (int32 addr); -int32 ReadW (int32 addr); -int32 ReadB (int32 addr); -int32 ReadMW (int32 addr); -int32 ReadMB (int32 addr); -void WriteW (int32 data, int32 addr); -void WriteB (int32 data, int32 addr); -void PWriteW (int32 data, int32 addr); -void PWriteB (int32 data, int32 addr); -void set_r_display (int32 rs, int32 cm); -t_stat CPU_wr (int32 data, int32 addr, int32 access); -void set_stack_trap (int32 adr); -int32 get_PSW (void); -void put_PSW (int32 val, t_bool prot); -void put_PIRQ (int32 val); - -extern void fp11 (int32 IR); -extern t_stat cis11 (int32 IR); -extern t_stat fis11 (int32 IR); -extern t_stat build_dib_tab (void); -extern t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc); -extern t_stat set_autocon (UNIT *uptr, int32 val, char *cptr, void *desc); -extern t_stat show_autocon (FILE *st, UNIT *uptr, int32 val, void *desc); -extern t_stat iopageR (int32 *data, uint32 addr, int32 access); -extern t_stat iopageW (int32 data, uint32 addr, int32 access); -extern int32 calc_ints (int32 nipl, int32 trq); -extern int32 get_vector (int32 nipl); - -/* Trap data structures */ - -int32 trap_vec[TRAP_V_MAX] = { /* trap req to vector */ - VEC_RED, VEC_ODD, VEC_MME, VEC_NXM, - VEC_PAR, VEC_PRV, VEC_ILL, VEC_BPT, - VEC_IOT, VEC_EMT, VEC_TRAP, VEC_TRC, - VEC_YEL, VEC_PWRFL, VEC_FPE - }; - -int32 trap_clear[TRAP_V_MAX] = { /* trap clears */ - TRAP_RED+TRAP_PAR+TRAP_YEL+TRAP_TRC+TRAP_ODD+TRAP_NXM, - TRAP_ODD+TRAP_PAR+TRAP_YEL+TRAP_TRC, - TRAP_MME+TRAP_PAR+TRAP_YEL+TRAP_TRC, - TRAP_NXM+TRAP_PAR+TRAP_YEL+TRAP_TRC, - TRAP_PAR+TRAP_TRC, TRAP_PRV+TRAP_TRC, - TRAP_ILL+TRAP_TRC, TRAP_BPT+TRAP_TRC, - TRAP_IOT+TRAP_TRC, TRAP_EMT+TRAP_TRC, - TRAP_TRAP+TRAP_TRC, TRAP_TRC, - TRAP_YEL, TRAP_PWRFL, TRAP_FPE - }; - -/* CPU data structures - - cpu_dev CPU device descriptor - cpu_unit CPU unit descriptor - cpu_reg CPU register list - cpu_mod CPU modifier list -*/ - -UNIT cpu_unit = { UDATA (NULL, UNIT_FIX|UNIT_BINK, INIMEMSIZE) }; - -REG cpu_reg[] = { - { ORDATA (PC, saved_PC, 16) }, - { ORDATA (R0, REGFILE[0][0], 16) }, - { ORDATA (R1, REGFILE[1][0], 16) }, - { ORDATA (R2, REGFILE[2][0], 16) }, - { ORDATA (R3, REGFILE[3][0], 16) }, - { ORDATA (R4, REGFILE[4][0], 16) }, - { ORDATA (R5, REGFILE[5][0], 16) }, - { ORDATA (SP, STACKFILE[MD_KER], 16) }, - { ORDATA (R00, REGFILE[0][0], 16) }, - { ORDATA (R01, REGFILE[1][0], 16) }, - { ORDATA (R02, REGFILE[2][0], 16) }, - { ORDATA (R03, REGFILE[3][0], 16) }, - { ORDATA (R04, REGFILE[4][0], 16) }, - { ORDATA (R05, REGFILE[5][0], 16) }, - { ORDATA (R10, REGFILE[0][1], 16) }, - { ORDATA (R11, REGFILE[1][1], 16) }, - { ORDATA (R12, REGFILE[2][1], 16) }, - { ORDATA (R13, REGFILE[3][1], 16) }, - { ORDATA (R14, REGFILE[4][1], 16) }, - { ORDATA (R15, REGFILE[5][1], 16) }, - { ORDATA (KSP, STACKFILE[MD_KER], 16) }, - { ORDATA (SSP, STACKFILE[MD_SUP], 16) }, - { ORDATA (USP, STACKFILE[MD_USR], 16) }, - { ORDATA (PSW, PSW, 16) }, - { GRDATA (CM, PSW, 8, 2, PSW_V_CM) }, - { GRDATA (PM, PSW, 8, 2, PSW_V_PM) }, - { FLDATA (RS, PSW, PSW_V_RS) }, - { FLDATA (FPD, PSW, PSW_V_FPD) }, - { GRDATA (IPL, PSW, 8, 3, PSW_V_IPL) }, - { FLDATA (T, PSW, PSW_V_TBIT) }, - { FLDATA (N, PSW, PSW_V_N) }, - { FLDATA (Z, PSW, PSW_V_Z) }, - { FLDATA (V, PSW, PSW_V_V) }, - { FLDATA (C, PSW, PSW_V_C) }, - { ORDATA (PIRQ, PIRQ, 16) }, - { ORDATA (STKLIM, STKLIM, 16) }, - { ORDATA (FAC0H, FR[0].h, 32) }, - { ORDATA (FAC0L, FR[0].l, 32) }, - { ORDATA (FAC1H, FR[1].h, 32) }, - { ORDATA (FAC1L, FR[1].l, 32) }, - { ORDATA (FAC2H, FR[2].h, 32) }, - { ORDATA (FAC2L, FR[2].l, 32) }, - { ORDATA (FAC3H, FR[3].h, 32) }, - { ORDATA (FAC3L, FR[3].l, 32) }, - { ORDATA (FAC4H, FR[4].h, 32) }, - { ORDATA (FAC4L, FR[4].l, 32) }, - { ORDATA (FAC5H, FR[5].h, 32) }, - { ORDATA (FAC5L, FR[5].l, 32) }, - { ORDATA (FPS, FPS, 16) }, - { ORDATA (FEA, FEA, 16) }, - { ORDATA (FEC, FEC, 4) }, - { ORDATA (MMR0, MMR0, 16) }, - { ORDATA (MMR1, MMR1, 16) }, - { ORDATA (MMR2, MMR2, 16) }, - { ORDATA (MMR3, MMR3, 16) }, - { GRDATA (KIPAR0, APRFILE[000], 8, 16, 16) }, - { GRDATA (KIPDR0, APRFILE[000], 8, 16, 0) }, - { GRDATA (KIPAR1, APRFILE[001], 8, 16, 16) }, - { GRDATA (KIPDR1, APRFILE[001], 8, 16, 0) }, - { GRDATA (KIPAR2, APRFILE[002], 8, 16, 16) }, - { GRDATA (KIPDR2, APRFILE[002], 8, 16, 0) }, - { GRDATA (KIPAR3, APRFILE[003], 8, 16, 16) }, - { GRDATA (KIPDR3, APRFILE[003], 8, 16, 0) }, - { GRDATA (KIPAR4, APRFILE[004], 8, 16, 16) }, - { GRDATA (KIPDR4, APRFILE[004], 8, 16, 0) }, - { GRDATA (KIPAR5, APRFILE[005], 8, 16, 16) }, - { GRDATA (KIPDR5, APRFILE[005], 8, 16, 0) }, - { GRDATA (KIPAR6, APRFILE[006], 8, 16, 16) }, - { GRDATA (KIPDR6, APRFILE[006], 8, 16, 0) }, - { GRDATA (KIPAR7, APRFILE[007], 8, 16, 16) }, - { GRDATA (KIPDR7, APRFILE[007], 8, 16, 0) }, - { GRDATA (KDPAR0, APRFILE[010], 8, 16, 16) }, - { GRDATA (KDPDR0, APRFILE[010], 8, 16, 0) }, - { GRDATA (KDPAR1, APRFILE[011], 8, 16, 16) }, - { GRDATA (KDPDR1, APRFILE[011], 8, 16, 0) }, - { GRDATA (KDPAR2, APRFILE[012], 8, 16, 16) }, - { GRDATA (KDPDR2, APRFILE[012], 8, 16, 0) }, - { GRDATA (KDPAR3, APRFILE[013], 8, 16, 16) }, - { GRDATA (KDPDR3, APRFILE[013], 8, 16, 0) }, - { GRDATA (KDPAR4, APRFILE[014], 8, 16, 16) }, - { GRDATA (KDPDR4, APRFILE[014], 8, 16, 0) }, - { GRDATA (KDPAR5, APRFILE[015], 8, 16, 16) }, - { GRDATA (KDPDR5, APRFILE[015], 8, 16, 0) }, - { GRDATA (KDPAR6, APRFILE[016], 8, 16, 16) }, - { GRDATA (KDPDR6, APRFILE[016], 8, 16, 0) }, - { GRDATA (KDPAR7, APRFILE[017], 8, 16, 16) }, - { GRDATA (KDPDR7, APRFILE[017], 8, 16, 0) }, - { GRDATA (SIPAR0, APRFILE[020], 8, 16, 16) }, - { GRDATA (SIPDR0, APRFILE[020], 8, 16, 0) }, - { GRDATA (SIPAR1, APRFILE[021], 8, 16, 16) }, - { GRDATA (SIPDR1, APRFILE[021], 8, 16, 0) }, - { GRDATA (SIPAR2, APRFILE[022], 8, 16, 16) }, - { GRDATA (SIPDR2, APRFILE[022], 8, 16, 0) }, - { GRDATA (SIPAR3, APRFILE[023], 8, 16, 16) }, - { GRDATA (SIPDR3, APRFILE[023], 8, 16, 0) }, - { GRDATA (SIPAR4, APRFILE[024], 8, 16, 16) }, - { GRDATA (SIPDR4, APRFILE[024], 8, 16, 0) }, - { GRDATA (SIPAR5, APRFILE[025], 8, 16, 16) }, - { GRDATA (SIPDR5, APRFILE[025], 8, 16, 0) }, - { GRDATA (SIPAR6, APRFILE[026], 8, 16, 16) }, - { GRDATA (SIPDR6, APRFILE[026], 8, 16, 0) }, - { GRDATA (SIPAR7, APRFILE[027], 8, 16, 16) }, - { GRDATA (SIPDR7, APRFILE[027], 8, 16, 0) }, - { GRDATA (SDPAR0, APRFILE[030], 8, 16, 16) }, - { GRDATA (SDPDR0, APRFILE[030], 8, 16, 0) }, - { GRDATA (SDPAR1, APRFILE[031], 8, 16, 16) }, - { GRDATA (SDPDR1, APRFILE[031], 8, 16, 0) }, - { GRDATA (SDPAR2, APRFILE[032], 8, 16, 16) }, - { GRDATA (SDPDR2, APRFILE[032], 8, 16, 0) }, - { GRDATA (SDPAR3, APRFILE[033], 8, 16, 16) }, - { GRDATA (SDPDR3, APRFILE[033], 8, 16, 0) }, - { GRDATA (SDPAR4, APRFILE[034], 8, 16, 16) }, - { GRDATA (SDPDR4, APRFILE[034], 8, 16, 0) }, - { GRDATA (SDPAR5, APRFILE[035], 8, 16, 16) }, - { GRDATA (SDPDR5, APRFILE[035], 8, 16, 0) }, - { GRDATA (SDPAR6, APRFILE[036], 8, 16, 16) }, - { GRDATA (SDPDR6, APRFILE[036], 8, 16, 0) }, - { GRDATA (SDPAR7, APRFILE[037], 8, 16, 16) }, - { GRDATA (SDPDR7, APRFILE[037], 8, 16, 0) }, - { GRDATA (UIPAR0, APRFILE[060], 8, 16, 16) }, - { GRDATA (UIPDR0, APRFILE[060], 8, 16, 0) }, - { GRDATA (UIPAR1, APRFILE[061], 8, 16, 16) }, - { GRDATA (UIPDR1, APRFILE[061], 8, 16, 0) }, - { GRDATA (UIPAR2, APRFILE[062], 8, 16, 16) }, - { GRDATA (UIPDR2, APRFILE[062], 8, 16, 0) }, - { GRDATA (UIPAR3, APRFILE[063], 8, 16, 16) }, - { GRDATA (UIPDR3, APRFILE[063], 8, 16, 0) }, - { GRDATA (UIPAR4, APRFILE[064], 8, 16, 16) }, - { GRDATA (UIPDR4, APRFILE[064], 8, 16, 0) }, - { GRDATA (UIPAR5, APRFILE[065], 8, 16, 16) }, - { GRDATA (UIPDR5, APRFILE[065], 8, 16, 0) }, - { GRDATA (UIPAR6, APRFILE[066], 8, 16, 16) }, - { GRDATA (UIPDR6, APRFILE[066], 8, 16, 0) }, - { GRDATA (UIPAR7, APRFILE[067], 8, 16, 16) }, - { GRDATA (UIPDR7, APRFILE[067], 8, 16, 0) }, - { GRDATA (UDPAR0, APRFILE[070], 8, 16, 16) }, - { GRDATA (UDPDR0, APRFILE[070], 8, 16, 0) }, - { GRDATA (UDPAR1, APRFILE[071], 8, 16, 16) }, - { GRDATA (UDPDR1, APRFILE[071], 8, 16, 0) }, - { GRDATA (UDPAR2, APRFILE[072], 8, 16, 16) }, - { GRDATA (UDPDR2, APRFILE[072], 8, 16, 0) }, - { GRDATA (UDPAR3, APRFILE[073], 8, 16, 16) }, - { GRDATA (UDPDR3, APRFILE[073], 8, 16, 0) }, - { GRDATA (UDPAR4, APRFILE[074], 8, 16, 16) }, - { GRDATA (UDPDR4, APRFILE[074], 8, 16, 0) }, - { GRDATA (UDPAR5, APRFILE[075], 8, 16, 16) }, - { GRDATA (UDPDR5, APRFILE[075], 8, 16, 0) }, - { GRDATA (UDPAR6, APRFILE[076], 8, 16, 16) }, - { GRDATA (UDPDR6, APRFILE[076], 8, 16, 0) }, - { GRDATA (UDPAR7, APRFILE[077], 8, 16, 16) }, - { GRDATA (UDPDR7, APRFILE[077], 8, 16, 0) }, - { BRDATA (IREQ, int_req, 8, 32, IPL_HLVL), REG_RO }, - { ORDATA (TRAPS, trap_req, TRAP_V_MAX) }, - { FLDATA (WAIT, wait_state, 0) }, - { FLDATA (WAIT_ENABLE, wait_enable, 0), REG_HIDDEN }, - { ORDATA (STOP_TRAPS, stop_trap, TRAP_V_MAX) }, - { FLDATA (STOP_VECA, stop_vecabort, 0) }, - { FLDATA (STOP_SPA, stop_spabort, 0) }, - { FLDATA (AUTOCON, autcon_enb, 0), REG_HRO }, - { BRDATA (PCQ, pcq, 8, 16, PCQ_SIZE), REG_RO+REG_CIRC }, - { ORDATA (PCQP, pcq_p, 6), REG_HRO }, - { ORDATA (WRU, sim_int_char, 8) }, - { ORDATA (MODEL, cpu_model, 16), REG_HRO }, - { ORDATA (OPTIONS, cpu_opt, 32), REG_HRO }, - { NULL} - }; - -MTAB cpu_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "TYPE", NULL, - NULL, &cpu_show_model }, -#if !defined (UC15) - { MTAB_XTD|MTAB_VDV, MOD_1103, NULL, "11/03", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, MOD_1104, NULL, "11/04", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, MOD_1105, NULL, "11/05", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, MOD_1120, NULL, "11/20", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, MOD_1123, NULL, "11/23", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, MOD_1123P, NULL, "11/23+", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, MOD_1124, NULL, "11/24", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, MOD_1134, NULL, "11/34", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, MOD_1140, NULL, "11/40", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, MOD_1144, NULL, "11/44", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, MOD_1145, NULL, "11/45", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, MOD_1153, NULL, "11/53", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, MOD_1160, NULL, "11/60", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, MOD_1170, NULL, "11/70", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, MOD_1173, NULL, "11/73", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, MOD_1173B, NULL, "11/73B", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, MOD_1183, NULL, "11/83", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, MOD_1184, NULL, "11/84", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, MOD_1193, NULL, "11/93", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, MOD_1194, NULL, "11/94", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, MOD_1173, NULL, "Q22", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, MOD_1184, NULL, "URH11", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, MOD_1170, NULL, "URH70", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, MOD_1145, NULL, "U18", &cpu_set_model }, - { MTAB_XTD|MTAB_VDV, OPT_EIS, NULL, "EIS", &cpu_set_opt }, - { MTAB_XTD|MTAB_VDV, OPT_EIS, NULL, "NOEIS", &cpu_clr_opt }, - { MTAB_XTD|MTAB_VDV, OPT_FIS, NULL, "FIS", &cpu_set_opt }, - { MTAB_XTD|MTAB_VDV, OPT_FIS, NULL, "NOFIS", &cpu_clr_opt }, - { MTAB_XTD|MTAB_VDV, OPT_FPP, NULL, "FPP", &cpu_set_opt }, - { MTAB_XTD|MTAB_VDV, OPT_FPP, NULL, "NOFPP", &cpu_clr_opt }, - { MTAB_XTD|MTAB_VDV, OPT_CIS, NULL, "CIS", &cpu_set_opt }, - { MTAB_XTD|MTAB_VDV, OPT_CIS, NULL, "NOCIS", &cpu_clr_opt }, - { MTAB_XTD|MTAB_VDV, OPT_MMU, NULL, "MMU", &cpu_set_opt }, - { MTAB_XTD|MTAB_VDV, OPT_MMU, NULL, "NOMMU", &cpu_clr_opt }, - { MTAB_XTD|MTAB_VDV, OPT_BVT, NULL, "BEVENT", &cpu_set_opt }, - { MTAB_XTD|MTAB_VDV, OPT_BVT, NULL, "NOBEVENT", &cpu_clr_opt }, - { 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, 65536, NULL, "64K", &cpu_set_size}, - { UNIT_MSIZE, 98304, NULL, "96K", &cpu_set_size}, - { UNIT_MSIZE, 131072, NULL, "128K", &cpu_set_size}, - { UNIT_MSIZE, 196608, NULL, "192K", &cpu_set_size}, - { UNIT_MSIZE, 262144, NULL, "256K", &cpu_set_size}, - { UNIT_MSIZE, 393216, NULL, "384K", &cpu_set_size}, - { UNIT_MSIZE, 524288, NULL, "512K", &cpu_set_size}, - { UNIT_MSIZE, 786432, NULL, "768K", &cpu_set_size}, - { UNIT_MSIZE, 1048576, NULL, "1024K", &cpu_set_size}, - { UNIT_MSIZE, 1572864, NULL, "1536K", &cpu_set_size}, - { UNIT_MSIZE, 2097152, NULL, "2048K", &cpu_set_size}, - { UNIT_MSIZE, 3145728, NULL, "3072K", &cpu_set_size}, - { UNIT_MSIZE, 4186112, NULL, "4096K", &cpu_set_size}, - { UNIT_MSIZE, 1048576, NULL, "1M", &cpu_set_size}, - { UNIT_MSIZE, 2097152, NULL, "2M", &cpu_set_size}, - { UNIT_MSIZE, 3145728, NULL, "3M", &cpu_set_size}, - { UNIT_MSIZE, 4186112, NULL, "4M", &cpu_set_size}, - { MTAB_XTD|MTAB_VDV, 1, "AUTOCONFIG", "AUTOCONFIG", - &set_autocon, &show_autocon }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "NOAUTOCONFIG", - &set_autocon, NULL }, -#else - { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size}, - { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size}, -#endif - { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "IOSPACE", NULL, - NULL, &show_iospace }, - { MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", - &cpu_set_hist, &cpu_show_hist }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "VIRTUAL", NULL, - NULL, &cpu_show_virt }, - { 0 } - }; - -DEVICE cpu_dev = { - "CPU", &cpu_unit, cpu_reg, cpu_mod, - 1, 8, 22, 2, 8, 16, - &cpu_ex, &cpu_dep, &cpu_reset, - NULL, NULL, NULL, - NULL, DEV_DYNM, 0, - NULL, &cpu_set_size, NULL - }; - -t_stat sim_instr (void) -{ -int abortval, i; -volatile int32 trapea; /* used by setjmp */ -t_stat reason; - -/* Restore register state - - 1. PSW components - 2. Active register file based on PSW - 3. Active stack pointer based on PSW - 4. Memory management control flags - 5. Interrupt system -*/ - -reason = build_dib_tab (); /* build, chk dib_tab */ -if (reason != SCPE_OK) - return reason; -if (MEMSIZE >= (cpu_tab[cpu_model].maxm - IOPAGESIZE)) /* mem size >= max - io page? */ - MEMSIZE = cpu_tab[cpu_model].maxm - IOPAGESIZE; /* max - io page */ -cpu_type = 1u << cpu_model; /* reset type mask */ -cpu_bme = (MMR3 & MMR3_BME) && (cpu_opt & OPT_UBM); /* map enabled? */ -PC = saved_PC; -put_PSW (PSW, 0); /* set PSW, call calc_xs */ -for (i = 0; i < 6; i++) - R[i] = REGFILE[i][rs]; -SP = STACKFILE[cm]; -isenable = calc_is (cm); -dsenable = calc_ds (cm); -put_PIRQ (PIRQ); /* rewrite PIRQ */ -STKLIM = STKLIM & STKLIM_RW; /* clean up STKLIM */ -MMR0 = MMR0 | MMR0_IC; /* usually on */ - -trap_req = calc_ints (ipl, trap_req); /* upd int req */ -trapea = 0; -reason = 0; - -/* Abort handling - - If an abort occurs in memory management or memory access, the lower - level routine executes a longjmp to this area OUTSIDE the main - simulation loop. The longjmp specifies a trap mask which is OR'd - into the trap_req register. Simulation then resumes at the fetch - phase, and the trap is sprung. - - Aborts which occur within a trap sequence (trapea != 0) require - special handling. If the abort occured on the stack pushes, and - the mode (encoded in trapea) is kernel, an "emergency" kernel - stack is created at 4, and a red zone stack trap taken. - - All variables used in setjmp processing, or assumed to be valid - after setjmp, must be volatile or global. -*/ - -abortval = setjmp (save_env); /* set abort hdlr */ -if (abortval != 0) { - trap_req = trap_req | abortval; /* or in trap flag */ - if ((trapea > 0) && stop_vecabort) - reason = STOP_VECABORT; - if ((trapea < 0) && /* stack push abort? */ - (CPUT (STOP_STKA) || stop_spabort)) - reason = STOP_SPABORT; - if (trapea == ~MD_KER) { /* kernel stk abort? */ - setTRAP (TRAP_RED); - setCPUERR (CPUE_RED); - STACKFILE[MD_KER] = 4; - if (cm == MD_KER) - SP = 4; - } - } - -/* Main instruction fetch/decode loop - - Check for traps or interrupts. If trap, locate the vector and check - for stop condition. If interrupt, locate the vector. -*/ - -while (reason == 0) { - - int32 IR, srcspec, srcreg, dstspec, dstreg; - int32 src, src2, dst, ea; - int32 i, t, sign, oldrs, trapnum; - - if (cpu_astop) { - cpu_astop = 0; - reason = SCPE_STOP; - break; - } - - 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) { /* trap set? */ - trapea = trap_vec[trapnum]; /* get vec, clr */ - trap_req = trap_req & ~trap_clear[trapnum]; - 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 */ - } /* end if trapea */ - -/* Process a trap or interrupt - - 1. Exit wait state - 2. Save the current SP and PSW - 3. Read the new PC, new PSW from trapea, kernel data space - 4. Get the mode and stack selected by the new PSW - 5. Push the old PC and PSW on the new stack - 6. Update SP, PSW, and PC - 7. If not stack overflow, check for stack overflow -*/ - - wait_state = 0; /* exit wait state */ - STACKFILE[cm] = SP; - PSW = get_PSW (); /* assemble PSW */ - oldrs = rs; - if (CPUT (HAS_MMTR)) { /* 45,70? */ - if (update_MM) /* save vector */ - MMR2 = trapea; - MMR0 = MMR0 & ~MMR0_IC; /* clear IC */ - } - src = ReadW (trapea | calc_ds (MD_KER)); /* new PC */ - src2 = ReadW ((trapea + 2) | calc_ds (MD_KER)); /* new PSW */ - t = (src2 >> PSW_V_CM) & 03; /* new cm */ - trapea = ~t; /* flag pushes */ - WriteW (PSW, ((STACKFILE[t] - 2) & 0177777) | calc_ds (t)); - WriteW (PC, ((STACKFILE[t] - 4) & 0177777) | calc_ds (t)); - trapea = 0; /* clear trap flag */ - src2 = (src2 & ~PSW_PM) | (cm << PSW_V_PM); /* insert prv mode */ - put_PSW (src2, 0); /* call calc_is,ds */ - if (rs != oldrs) { /* if rs chg, swap */ - for (i = 0; i < 6; i++) { - REGFILE[i][oldrs] = R[i]; - R[i] = REGFILE[i][rs]; - } - } - SP = (STACKFILE[cm] - 4) & 0177777; /* update SP, PC */ - isenable = calc_is (cm); - dsenable = calc_ds (cm); - trap_req = calc_ints (ipl, trap_req); - JMP_PC (src); - if ((cm == MD_KER) && (SP < (STKLIM + STKL_Y)) && - (trapnum != TRAP_V_RED) && (trapnum != TRAP_V_YEL)) - set_stack_trap (SP); - MMR0 = MMR0 | MMR0_IC; /* back to instr */ - continue; /* end if traps */ - } - -/* Fetch and decode next instruction */ - - if (tbit) - setTRAP (TRAP_TRC); - if (wait_state) { /* wait state? */ - sim_idle (TMR_CLK, TRUE); - continue; - } - - if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - continue; - } - - if (update_MM) { /* if mm not frozen */ - MMR1 = 0; - MMR2 = PC; - } - IR = ReadE (PC | isenable); /* fetch instruction */ - sim_interval = sim_interval - 1; - srcspec = (IR >> 6) & 077; /* src, dst specs */ - dstspec = IR & 077; - srcreg = (srcspec <= 07); /* src, dst = rmode? */ - dstreg = (dstspec <= 07); - if (hst_lnt) { /* record history? */ - t_value val; - uint32 i; - static int32 swmap[4] = { - SWMASK ('K') | SWMASK ('V'), SWMASK ('S') | SWMASK ('V'), - SWMASK ('U') | SWMASK ('V'), SWMASK ('U') | SWMASK ('V') - }; - hst[hst_p].pc = PC | HIST_VLD; - hst[hst_p].sp = SP; - hst[hst_p].psw = get_PSW (); - hst[hst_p].src = R[srcspec & 07]; - hst[hst_p].dst = R[dstspec & 07]; - hst[hst_p].inst[0] = IR; - for (i = 1; i < HIST_ILNT; i++) { - if (cpu_ex (&val, (PC + (i << 1)) & 0177777, &cpu_unit, swmap[cm & 03])) - hst[hst_p].inst[i] = 0; - else hst[hst_p].inst[i] = (uint16) val; - } - hst_p = (hst_p + 1); - if (hst_p >= hst_lnt) - hst_p = 0; - } - PC = (PC + 2) & 0177777; /* incr PC, mod 65k */ - switch ((IR >> 12) & 017) { /* decode IR<15:12> */ - -/* Opcode 0: no operands, specials, branches, JSR, SOPs */ - - case 000: - switch ((IR >> 6) & 077) { /* decode IR<11:6> */ - case 000: /* no operand */ - if (IR >= 000010) { /* 000010 - 000077 */ - setTRAP (TRAP_ILL); /* illegal */ - break; - } - switch (IR) { /* decode IR<2:0> */ - case 0: /* HALT */ - if ((cm == MD_KER) && - (!CPUT (CPUT_J) || ((MAINT & MAINT_HTRAP) == 0))) - reason = STOP_HALT; - else if (CPUT (HAS_HALT4)) { /* priv trap? */ - setTRAP (TRAP_PRV); - setCPUERR (CPUE_HALT); - } - else setTRAP (TRAP_ILL); /* no, ill inst */ - break; - case 1: /* WAIT */ - wait_state = 1; - break; - case 3: /* BPT */ - setTRAP (TRAP_BPT); - break; - case 4: /* IOT */ - setTRAP (TRAP_IOT); - break; - case 5: /* RESET */ - if (cm == MD_KER) { - reset_all (2); /* skip CPU, sys reg */ - PIRQ = 0; /* clear PIRQ */ - STKLIM = 0; /* clear STKLIM */ - MMR0 = 0; /* clear MMR0 */ - MMR3 = 0; /* clear MMR3 */ - cpu_bme = 0; /* (also clear bme) */ - for (i = 0; i < IPL_HLVL; i++) - int_req[i] = 0; - trap_req = trap_req & ~TRAP_INT; - dsenable = calc_ds (cm); - } - break; - case 6: /* RTT */ - if (!CPUT (HAS_RTT)) { - setTRAP (TRAP_ILL); - break; - } - case 2: /* RTI */ - src = ReadW (SP | dsenable); - src2 = ReadW (((SP + 2) & 0177777) | dsenable); - STACKFILE[cm] = SP = (SP + 4) & 0177777; - oldrs = rs; - put_PSW (src2, (cm != MD_KER)); /* store PSW, prot */ - if (rs != oldrs) { - for (i = 0; i < 6; i++) { - REGFILE[i][oldrs] = R[i]; - R[i] = REGFILE[i][rs]; - } - } - SP = STACKFILE[cm]; - isenable = calc_is (cm); - dsenable = calc_ds (cm); - trap_req = calc_ints (ipl, trap_req); - JMP_PC (src); - if (CPUT (HAS_RTT) && tbit && /* RTT impl? */ - (IR == 000002)) - setTRAP (TRAP_TRC); /* RTI immed trap */ - break; - case 7: /* MFPT */ - if (CPUT (HAS_MFPT)) /* implemented? */ - R[0] = cpu_tab[cpu_model].mfpt; /* get type */ - else setTRAP (TRAP_ILL); - break; - } /* end switch no ops */ - break; /* end case no ops */ - - case 001: /* JMP */ - if (dstreg) - setTRAP (CPUT (HAS_JREG4)? TRAP_PRV: TRAP_ILL); - else { - dst = GeteaW (dstspec) & 0177777; /* get eff addr */ - if (CPUT (CPUT_05|CPUT_20) && /* 11/05, 11/20 */ - ((dstspec & 070) == 020)) /* JMP (R)+? */ - dst = R[dstspec & 07]; /* use post incr */ - JMP_PC (dst); - } - break; /* end JMP */ - - case 002: /* RTS et al*/ - if (IR < 000210) { /* RTS */ - dstspec = dstspec & 07; - JMP_PC (R[dstspec]); - R[dstspec] = ReadW (SP | dsenable); - if (dstspec != 6) - SP = (SP + 2) & 0177777; - break; - } /* end if RTS */ - if (IR < 000230) { - setTRAP (TRAP_ILL); - break; - } - if (IR < 000240) { /* SPL */ - if (CPUT (HAS_SPL)) { - if (cm == MD_KER) - ipl = IR & 07; - trap_req = calc_ints (ipl, trap_req); - } - else setTRAP (TRAP_ILL); - break; - } /* end if SPL */ - if (IR < 000260) { /* clear CC */ - if (IR & 010) - N = 0; - if (IR & 004) - Z = 0; - if (IR & 002) - V = 0; - if (IR & 001) - C = 0; - break; - } /* end if clear CCs */ - if (IR & 010) /* set CC */ - N = 1; - if (IR & 004) - Z = 1; - if (IR & 002) - V = 1; - if (IR & 001) - C = 1; - break; /* end case RTS et al */ - - case 003: /* SWAB */ - dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); - dst = ((dst & 0377) << 8) | ((dst >> 8) & 0377); - N = GET_SIGN_B (dst & 0377); - Z = GET_Z (dst & 0377); - if (!CPUT (CPUT_20)) - V = 0; - C = 0; - if (dstreg) - R[dstspec] = dst; - else PWriteW (dst, last_pa); - break; /* end SWAB */ - - case 004: case 005: /* BR */ - BRANCH_F (IR); - break; - - case 006: case 007: /* BR */ - BRANCH_B (IR); - break; - - case 010: case 011: /* BNE */ - if (Z == 0) { - BRANCH_F (IR); - } - break; - - case 012: case 013: /* BNE */ - if (Z == 0) { - BRANCH_B (IR); - } - break; - - case 014: case 015: /* BEQ */ - if (Z) { - BRANCH_F (IR); - } - break; - - case 016: case 017: /* BEQ */ - if (Z) { - BRANCH_B (IR); - } - break; - - case 020: case 021: /* BGE */ - if ((N ^ V) == 0) { - BRANCH_F (IR); - } - break; - - case 022: case 023: /* BGE */ - if ((N ^ V) == 0) { - BRANCH_B (IR); - } - break; - - case 024: case 025: /* BLT */ - if (N ^ V) { - BRANCH_F (IR); - } - break; - - case 026: case 027: /* BLT */ - if (N ^ V) { - BRANCH_B (IR); - } - break; - - case 030: case 031: /* BGT */ - if ((Z | (N ^ V)) == 0) { - BRANCH_F (IR); - } - break; - - case 032: case 033: /* BGT */ - if ((Z | (N ^ V)) == 0) { BRANCH_B (IR); } - break; - - case 034: case 035: /* BLE */ - if (Z | (N ^ V)) { - BRANCH_F (IR); - } - break; - - case 036: case 037: /* BLE */ - if (Z | (N ^ V)) { - BRANCH_B (IR); - } - break; - - case 040: case 041: case 042: case 043: /* JSR */ - case 044: case 045: case 046: case 047: - if (dstreg) - setTRAP (CPUT (HAS_JREG4)? TRAP_PRV: TRAP_ILL); - else { - srcspec = srcspec & 07; - dst = GeteaW (dstspec); - if (CPUT (CPUT_05|CPUT_20) && /* 11/05, 11/20 */ - ((dstspec & 070) == 020)) /* JSR (R)+? */ - dst = R[dstspec & 07]; /* use post incr */ - SP = (SP - 2) & 0177777; - if (update_MM) - MMR1 = calc_MMR1 (0366); - WriteW (R[srcspec], SP | dsenable); - if ((cm == MD_KER) && (SP < (STKLIM + STKL_Y))) - set_stack_trap (SP); - R[srcspec] = PC; - JMP_PC (dst & 0177777); - } - break; /* end JSR */ - - case 050: /* CLR */ - N = V = C = 0; - Z = 1; - if (dstreg) - R[dstspec] = 0; - else WriteW (0, GeteaW (dstspec)); - break; - - case 051: /* COM */ - dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); - dst = dst ^ 0177777; - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - V = 0; - C = 1; - if (dstreg) - R[dstspec] = dst; - else PWriteW (dst, last_pa); - break; - - case 052: /* INC */ - dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); - dst = (dst + 1) & 0177777; - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - V = (dst == 0100000); - if (dstreg) - R[dstspec] = dst; - else PWriteW (dst, last_pa); - break; - - case 053: /* DEC */ - dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); - dst = (dst - 1) & 0177777; - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - V = (dst == 077777); - if (dstreg) - R[dstspec] = dst; - else PWriteW (dst, last_pa); - break; - - case 054: /* NEG */ - dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); - dst = (-dst) & 0177777; - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - V = (dst == 0100000); - C = Z ^ 1; - if (dstreg) - R[dstspec] = dst; - else PWriteW (dst, last_pa); - break; - - case 055: /* ADC */ - dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); - dst = (dst + C) & 0177777; - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - V = (C && (dst == 0100000)); - C = C & Z; - if (dstreg) - R[dstspec] = dst; - else PWriteW (dst, last_pa); - break; - - case 056: /* SBC */ - dst = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); - dst = (dst - C) & 0177777; - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - V = (C && (dst == 077777)); - C = (C && (dst == 0177777)); - if (dstreg) - R[dstspec] = dst; - else PWriteW (dst, last_pa); - break; - - case 057: /* TST */ - dst = dstreg? R[dstspec]: ReadW (GeteaW (dstspec)); - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - V = C = 0; - break; - - case 060: /* ROR */ - src = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); - dst = (src >> 1) | (C << 15); - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - C = (src & 1); - V = N ^ C; - if (dstreg) - R[dstspec] = dst; - else PWriteW (dst, last_pa); - break; - - case 061: /* ROL */ - src = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); - dst = ((src << 1) | C) & 0177777; - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - C = GET_SIGN_W (src); - V = N ^ C; - if (dstreg) - R[dstspec] = dst; - else PWriteW (dst, last_pa); - break; - - case 062: /* ASR */ - src = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); - dst = (src >> 1) | (src & 0100000); - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - C = (src & 1); - V = N ^ C; - if (dstreg) - R[dstspec] = dst; - else PWriteW (dst, last_pa); - break; - - case 063: /* ASL */ - src = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); - dst = (src << 1) & 0177777; - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - C = GET_SIGN_W (src); - V = N ^ C; - if (dstreg) - R[dstspec] = dst; - else PWriteW (dst, last_pa); - break; - -/* Notes: - - MxPI must mask GeteaW returned address to force ispace - - MxPI must set MMR1 for SP recovery in case of fault -*/ - - case 064: /* MARK */ - if (CPUT (HAS_MARK)) { - i = (PC + dstspec + dstspec) & 0177777; - JMP_PC (R[5]); - R[5] = ReadW (i | dsenable); - SP = (i + 2) & 0177777; - } - else setTRAP (TRAP_ILL); - break; - - case 065: /* MFPI */ - if (CPUT (HAS_MXPY)) { - if (dstreg) { - if ((dstspec == 6) && (cm != pm)) - dst = STACKFILE[pm]; - else dst = R[dstspec]; - } - else { - i = ((cm == pm) && (cm == MD_USR))? (int32)calc_ds (pm): (int32)calc_is (pm); - dst = ReadW ((GeteaW (dstspec) & 0177777) | i); - } - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - V = 0; - SP = (SP - 2) & 0177777; - if (update_MM) - MMR1 = calc_MMR1 (0366); - WriteW (dst, SP | dsenable); - if ((cm == MD_KER) && (SP < (STKLIM + STKL_Y))) - set_stack_trap (SP); - } - else setTRAP (TRAP_ILL); - break; - - case 066: /* MTPI */ - if (CPUT (HAS_MXPY)) { - dst = ReadW (SP | dsenable); - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - V = 0; - SP = (SP + 2) & 0177777; - if (update_MM) MMR1 = 026; - if (dstreg) { - if ((dstspec == 6) && (cm != pm)) - STACKFILE[pm] = dst; - else R[dstspec] = dst; - } - else WriteW (dst, (GeteaW (dstspec) & 0177777) | calc_is (pm)); - } - else setTRAP (TRAP_ILL); - break; - - case 067: /* SXT */ - if (CPUT (HAS_SXS)) { - dst = N? 0177777: 0; - Z = N ^ 1; - V = 0; - if (dstreg) - R[dstspec] = dst; - else WriteW (dst, GeteaW (dstspec)); - } - else setTRAP (TRAP_ILL); - break; - - case 070: /* CSM */ - if (CPUT (HAS_CSM) && (MMR3 & MMR3_CSM) && (cm != MD_KER)) { - dst = dstreg? R[dstspec]: ReadW (GeteaW (dstspec)); - PSW = get_PSW () & ~PSW_CC; /* PSW, cc = 0 */ - STACKFILE[cm] = SP; - WriteW (PSW, ((SP - 2) & 0177777) | calc_ds (MD_SUP)); - WriteW (PC, ((SP - 4) & 0177777) | calc_ds (MD_SUP)); - WriteW (dst, ((SP - 6) & 0177777) | calc_ds (MD_SUP)); - SP = (SP - 6) & 0177777; - pm = cm; - cm = MD_SUP; - tbit = 0; - isenable = calc_is (cm); - dsenable = calc_ds (cm); - PC = ReadW (010 | isenable); - } - else setTRAP (TRAP_ILL); - break; - - case 072: /* TSTSET */ - if (CPUT (HAS_TSWLK) && !dstreg) { - dst = ReadMW (GeteaW (dstspec)); - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - V = 0; - C = (dst & 1); - R[0] = dst; /* R[0] <- dst */ - PWriteW (R[0] | 1, last_pa); /* dst <- R[0] | 1 */ - } - else setTRAP (TRAP_ILL); - break; - - case 073: /* WRTLCK */ - if (CPUT (HAS_TSWLK) && !dstreg) { - N = GET_SIGN_W (R[0]); - Z = GET_Z (R[0]); - V = 0; - WriteW (R[0], GeteaW (dstspec)); - } - else setTRAP (TRAP_ILL); - break; - - default: - setTRAP (TRAP_ILL); - break; - } /* end switch SOPs */ - break; /* end case 000 */ - -/* Opcodes 01 - 06: double operand word instructions - - J-11 (and F-11) optimize away register source operand decoding. - As a result, dop R,+/-(R) use the modified version of R as source. - Most (but not all) other PDP-11's fetch the source operand before - any destination operand decoding. - - Add: v = [sign (src) = sign (src2)] and [sign (src) != sign (result)] - Cmp: v = [sign (src) != sign (src2)] and [sign (src2) = sign (result)] -*/ - - case 001: /* MOV */ - if (CPUT (IS_SDSD) && srcreg && !dstreg) { /* R,not R */ - ea = GeteaW (dstspec); - dst = R[srcspec]; - } - else { - dst = srcreg? R[srcspec]: ReadW (GeteaW (srcspec)); - if (!dstreg) - ea = GeteaW (dstspec); - } - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - V = 0; - if (dstreg) - R[dstspec] = dst; - else WriteW (dst, ea); - break; - - case 002: /* CMP */ - if (CPUT (IS_SDSD) && srcreg && !dstreg) { /* R,not R */ - src2 = ReadW (GeteaW (dstspec)); - src = R[srcspec]; - } - else { - src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec)); - src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec)); - } - dst = (src - src2) & 0177777; - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - V = GET_SIGN_W ((src ^ src2) & (~src2 ^ dst)); - C = (src < src2); - break; - - case 003: /* BIT */ - if (CPUT (IS_SDSD) && srcreg && !dstreg) { /* R,not R */ - src2 = ReadW (GeteaW (dstspec)); - src = R[srcspec]; - } - else { - src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec)); - src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec)); - } - dst = src2 & src; - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - V = 0; - break; - - case 004: /* BIC */ - if (CPUT (IS_SDSD) && srcreg && !dstreg) { /* R,not R */ - src2 = ReadMW (GeteaW (dstspec)); - src = R[srcspec]; - } - else { - src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec)); - src2 = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); - } - dst = src2 & ~src; - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - V = 0; - if (dstreg) - R[dstspec] = dst; - else PWriteW (dst, last_pa); - break; - - case 005: /* BIS */ - if (CPUT (IS_SDSD) && srcreg && !dstreg) { /* R,not R */ - src2 = ReadMW (GeteaW (dstspec)); - src = R[srcspec]; - } - else { - src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec)); - src2 = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); - } - dst = src2 | src; - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - V = 0; - if (dstreg) - R[dstspec] = dst; - else PWriteW (dst, last_pa); - break; - - case 006: /* ADD */ - if (CPUT (IS_SDSD) && srcreg && !dstreg) { /* R,not R */ - src2 = ReadMW (GeteaW (dstspec)); - src = R[srcspec]; - } - else { - src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec)); - src2 = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); - } - dst = (src2 + src) & 0177777; - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - V = GET_SIGN_W ((~src ^ src2) & (src ^ dst)); - C = (dst < src); - if (dstreg) - R[dstspec] = dst; - else PWriteW (dst, last_pa); - break; - -/* Opcode 07: EIS, FIS, CIS - - Notes: - - The code assumes that the host int length is at least 32 bits. - - MUL carry: C is set if the (signed) result doesn't fit in 16 bits. - - Divide has three error cases: - 1. Divide by zero. - 2. Divide largest negative number by -1. - 3. (Signed) quotient doesn't fit in 16 bits. - Cases 1 and 2 must be tested in advance, to avoid C runtime errors. - - ASHx left: overflow if the bits shifted out do not equal the sign - of the result (convert shift out to 1/0, xor against sign). - - ASHx right: if right shift sign extends, then the shift and - conditional or of shifted -1 is redundant. If right shift zero - extends, then the shift and conditional or does sign extension. -*/ - - case 007: - srcspec = srcspec & 07; - switch ((IR >> 9) & 07) { /* decode IR<11:9> */ - - case 0: /* MUL */ - if (!CPUO (OPT_EIS)) { - setTRAP (TRAP_ILL); - break; - } - src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec)); - src = R[srcspec]; - if (GET_SIGN_W (src2)) - src2 = src2 | ~077777; - if (GET_SIGN_W (src)) - src = src | ~077777; - dst = src * src2; - R[srcspec] = (dst >> 16) & 0177777; - R[srcspec | 1] = dst & 0177777; - N = (dst < 0); - Z = GET_Z (dst); - V = 0; - C = ((dst > 077777) || (dst < -0100000)); - break; - - case 1: /* DIV */ - if (!CPUO (OPT_EIS)) { - setTRAP (TRAP_ILL); - break; - } - src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec)); - src = (((uint32) R[srcspec]) << 16) | R[srcspec | 1]; - if (src2 == 0) { - N = 0; /* J11,11/70 compat */ - Z = V = C = 1; /* N = 0, Z = 1 */ - break; - } - if ((((uint32)src) == 020000000000) && (src2 == 0177777)) { - V = 1; /* J11,11/70 compat */ - N = Z = C = 0; /* N = Z = 0 */ - break; - } - if (GET_SIGN_W (src2)) - src2 = src2 | ~077777; - if (GET_SIGN_W (R[srcspec])) - src = src | ~017777777777; - dst = src / src2; - N = (dst < 0); /* N set on 32b result */ - if ((dst > 077777) || (dst < -0100000)) { - V = 1; /* J11,11/70 compat */ - Z = C = 0; /* Z = C = 0 */ - break; - } - R[srcspec] = dst & 0177777; - R[srcspec | 1] = (src - (src2 * dst)) & 0177777; - Z = GET_Z (dst); - V = C = 0; - break; - - case 2: /* ASH */ - if (!CPUO (OPT_EIS)) { - setTRAP (TRAP_ILL); - break; - } - src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec)); - src2 = src2 & 077; - sign = GET_SIGN_W (R[srcspec]); - src = sign? R[srcspec] | ~077777: R[srcspec]; - if (src2 == 0) { /* [0] */ - dst = src; - V = C = 0; - } - else if (src2 <= 15) { /* [1,15] */ - dst = src << src2; - i = (src >> (16 - src2)) & 0177777; - V = (i != ((dst & 0100000)? 0177777: 0)); - C = (i & 1); - } - else if (src2 <= 31) { /* [16,31] */ - dst = 0; - V = (src != 0); - C = (src << (src2 - 16)) & 1; - } - else if (src2 == 32) { /* [32] = -32 */ - dst = -sign; - V = 0; - C = sign; - } - else { /* [33,63] = -31,-1 */ - dst = (src >> (64 - src2)) | (-sign << (src2 - 32)); - V = 0; - C = ((src >> (63 - src2)) & 1); - } - dst = R[srcspec] = dst & 0177777; - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - break; - - case 3: /* ASHC */ - if (!CPUO (OPT_EIS)) { - setTRAP (TRAP_ILL); - break; - } - src2 = dstreg? R[dstspec]: ReadW (GeteaW (dstspec)); - src2 = src2 & 077; - sign = GET_SIGN_W (R[srcspec]); - src = (((uint32) R[srcspec]) << 16) | R[srcspec | 1]; - if (src2 == 0) { /* [0] */ - dst = src; - V = C = 0; - } - else if (src2 <= 31) { /* [1,31] */ - dst = ((uint32) src) << src2; - i = (src >> (32 - src2)) | (-sign << src2); - V = (i != ((dst & 020000000000)? -1: 0)); - C = (i & 1); - } - else if (src2 == 32) { /* [32] = -32 */ - dst = -sign; - V = 0; - C = sign; - } - else { /* [33,63] = -31,-1 */ - dst = (src >> (64 - src2)) | (-sign << (src2 - 32)); - V = 0; - C = ((src >> (63 - src2)) & 1); - } - i = R[srcspec] = (dst >> 16) & 0177777; - dst = R[srcspec | 1] = dst & 0177777; - N = GET_SIGN_W (i); - Z = GET_Z (dst | i); - break; - - case 4: /* XOR */ - if (CPUT (HAS_SXS)) { - if (CPUT (IS_SDSD) && !dstreg) { /* R,not R */ - src2 = ReadMW (GeteaW (dstspec)); - src = R[srcspec]; - } - else { - src = R[srcspec]; - src2 = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); - } - dst = src ^ src2; - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - V = 0; - if (dstreg) - R[dstspec] = dst; - else PWriteW (dst, last_pa); - } - else setTRAP (TRAP_ILL); - break; - - case 5: /* FIS */ - if (CPUO (OPT_FIS)) - fis11 (IR); - else setTRAP (TRAP_ILL); - break; - - case 6: /* CIS */ - if (CPUT (CPUT_60) && (cm == MD_KER) && /* 11/60 MED? */ - (IR == 076600)) { - ReadE (PC | isenable); /* read immediate */ - PC = (PC + 2) & 0177777; - } - else if (CPUO (OPT_CIS)) /* CIS option? */ - reason = cis11 (IR); - else setTRAP (TRAP_ILL); - break; - - case 7: /* SOB */ - if (CPUT (HAS_SXS)) { - R[srcspec] = (R[srcspec] - 1) & 0177777; - if (R[srcspec]) { - JMP_PC ((PC - dstspec - dstspec) & 0177777); - } - } - else setTRAP (TRAP_ILL); - break; - } /* end switch EIS */ - break; /* end case 007 */ - -/* Opcode 10: branches, traps, SOPs */ - - case 010: - switch ((IR >> 6) & 077) { /* decode IR<11:6> */ - - case 000: case 001: /* BPL */ - if (N == 0) { - BRANCH_F (IR); - } - break; - - case 002: case 003: /* BPL */ - if (N == 0) { - BRANCH_B (IR); - } - break; - - case 004: case 005: /* BMI */ - if (N) { - BRANCH_F (IR); - } - break; - - case 006: case 007: /* BMI */ - if (N) { - BRANCH_B (IR); - } - break; - - case 010: case 011: /* BHI */ - if ((C | Z) == 0) { - BRANCH_F (IR); - } - break; - - case 012: case 013: /* BHI */ - if ((C | Z) == 0) { - BRANCH_B (IR); - } - break; - - case 014: case 015: /* BLOS */ - if (C | Z) { - BRANCH_F (IR); - } - break; - - case 016: case 017: /* BLOS */ - if (C | Z) { - BRANCH_B (IR); - } - break; - - case 020: case 021: /* BVC */ - if (V == 0) { - BRANCH_F (IR); - } - break; - - case 022: case 023: /* BVC */ - if (V == 0) { - BRANCH_B (IR); - } - break; - - case 024: case 025: /* BVS */ - if (V) { - BRANCH_F (IR); - } - break; - - case 026: case 027: /* BVS */ - if (V) { - BRANCH_B (IR); - } - break; - - case 030: case 031: /* BCC */ - if (C == 0) { - BRANCH_F (IR); - } - break; - - case 032: case 033: /* BCC */ - if (C == 0) { - BRANCH_B (IR); - } - break; - - case 034: case 035: /* BCS */ - if (C) { - BRANCH_F (IR); - } - break; - - case 036: case 037: /* BCS */ - if (C) { - BRANCH_B (IR); - } - break; - - case 040: case 041: case 042: case 043: /* EMT */ - setTRAP (TRAP_EMT); - break; - - case 044: case 045: case 046: case 047: /* TRAP */ - setTRAP (TRAP_TRAP); - break; - - case 050: /* CLRB */ - N = V = C = 0; - Z = 1; - if (dstreg) - R[dstspec] = R[dstspec] & 0177400; - else WriteB (0, GeteaB (dstspec)); - break; - - case 051: /* COMB */ - dst = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec)); - dst = (dst ^ 0377) & 0377; - N = GET_SIGN_B (dst); - Z = GET_Z (dst); - V = 0; - C = 1; - if (dstreg) - R[dstspec] = (R[dstspec] & 0177400) | dst; - else PWriteB (dst, last_pa); - break; - - case 052: /* INCB */ - dst = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec)); - dst = (dst + 1) & 0377; - N = GET_SIGN_B (dst); - Z = GET_Z (dst); - V = (dst == 0200); - if (dstreg) - R[dstspec] = (R[dstspec] & 0177400) | dst; - else PWriteB (dst, last_pa); - break; - - case 053: /* DECB */ - dst = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec)); - dst = (dst - 1) & 0377; - N = GET_SIGN_B (dst); - Z = GET_Z (dst); - V = (dst == 0177); - if (dstreg) - R[dstspec] = (R[dstspec] & 0177400) | dst; - else PWriteB (dst, last_pa); - break; - - case 054: /* NEGB */ - dst = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec)); - dst = (-dst) & 0377; - N = GET_SIGN_B (dst); - Z = GET_Z (dst); - V = (dst == 0200); - C = (Z ^ 1); - if (dstreg) - R[dstspec] = (R[dstspec] & 0177400) | dst; - else PWriteB (dst, last_pa); - break; - - case 055: /* ADCB */ - dst = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec)); - dst = (dst + C) & 0377; - N = GET_SIGN_B (dst); - Z = GET_Z (dst); - V = (C && (dst == 0200)); - C = C & Z; - if (dstreg) - R[dstspec] = (R[dstspec] & 0177400) | dst; - else PWriteB (dst, last_pa); - break; - - case 056: /* SBCB */ - dst = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec)); - dst = (dst - C) & 0377; - N = GET_SIGN_B (dst); - Z = GET_Z (dst); - V = (C && (dst == 0177)); - C = (C && (dst == 0377)); - if (dstreg) - R[dstspec] = (R[dstspec] & 0177400) | dst; - else PWriteB (dst, last_pa); - break; - - case 057: /* TSTB */ - dst = dstreg? R[dstspec] & 0377: ReadB (GeteaB (dstspec)); - N = GET_SIGN_B (dst); - Z = GET_Z (dst); - V = C = 0; - break; - - case 060: /* RORB */ - src = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec)); - dst = ((src & 0377) >> 1) | (C << 7); - N = GET_SIGN_B (dst); - Z = GET_Z (dst); - C = (src & 1); - V = N ^ C; - if (dstreg) - R[dstspec] = (R[dstspec] & 0177400) | dst; - else PWriteB (dst, last_pa); - break; - - case 061: /* ROLB */ - src = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec)); - dst = ((src << 1) | C) & 0377; - N = GET_SIGN_B (dst); - Z = GET_Z (dst); - C = GET_SIGN_B (src & 0377); - V = N ^ C; - if (dstreg) - R[dstspec] = (R[dstspec] & 0177400) | dst; - else PWriteB (dst, last_pa); - break; - - case 062: /* ASRB */ - src = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec)); - dst = ((src & 0377) >> 1) | (src & 0200); - N = GET_SIGN_B (dst); - Z = GET_Z (dst); - C = (src & 1); - V = N ^ C; - if (dstreg) - R[dstspec] = (R[dstspec] & 0177400) | dst; - else PWriteB (dst, last_pa); - break; - - case 063: /* ASLB */ - src = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec)); - dst = (src << 1) & 0377; - N = GET_SIGN_B (dst); - Z = GET_Z (dst); - C = GET_SIGN_B (src & 0377); - V = N ^ C; - if (dstreg) - R[dstspec] = (R[dstspec] & 0177400) | dst; - else PWriteB (dst, last_pa); - break; - -/* Notes: - - MTPS cannot alter the T bit - - MxPD must mask GeteaW returned address, dspace is from cm not pm - - MxPD must set MMR1 for SP recovery in case of fault -*/ - - case 064: /* MTPS */ - if (CPUT (HAS_MXPS)) { - dst = dstreg? R[dstspec]: ReadB (GeteaB (dstspec)); - if (cm == MD_KER) { - ipl = (dst >> PSW_V_IPL) & 07; - trap_req = calc_ints (ipl, trap_req); - } - N = (dst >> PSW_V_N) & 01; - Z = (dst >> PSW_V_Z) & 01; - V = (dst >> PSW_V_V) & 01; - C = (dst >> PSW_V_C) & 01; - } - else setTRAP (TRAP_ILL); - break; - - case 065: /* MFPD */ - if (CPUT (HAS_MXPY)) { - if (dstreg) { - if ((dstspec == 6) && (cm != pm)) - dst = STACKFILE[pm]; - else dst = R[dstspec]; - } - else dst = ReadW ((GeteaW (dstspec) & 0177777) | calc_ds (pm)); - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - V = 0; - SP = (SP - 2) & 0177777; - if (update_MM) - MMR1 = calc_MMR1 (0366); - WriteW (dst, SP | dsenable); - if ((cm == MD_KER) && (SP < (STKLIM + STKL_Y))) - set_stack_trap (SP); - } - else setTRAP (TRAP_ILL); - break; - - case 066: /* MTPD */ - if (CPUT (HAS_MXPY)) { - dst = ReadW (SP | dsenable); - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - V = 0; - SP = (SP + 2) & 0177777; - if (update_MM) - MMR1 = 026; - if (dstreg) { - if ((dstspec == 6) && (cm != pm)) - STACKFILE[pm] = dst; - else R[dstspec] = dst; - } - else WriteW (dst, (GeteaW (dstspec) & 0177777) | calc_ds (pm)); - } - else setTRAP (TRAP_ILL); - break; - - case 067: /* MFPS */ - if (CPUT (HAS_MXPS)) { - dst = get_PSW () & 0377; - N = GET_SIGN_B (dst); - Z = GET_Z (dst); - V = 0; - if (dstreg) - R[dstspec] = (dst & 0200)? 0177400 | dst: dst; - else WriteB (dst, GeteaB (dstspec)); - } - else setTRAP (TRAP_ILL); - break; - - default: - setTRAP (TRAP_ILL); - break; - } /* end switch SOPs */ - break; /* end case 010 */ - -/* Opcodes 11 - 16: double operand byte instructions - - Cmp: v = [sign (src) != sign (src2)] and [sign (src2) = sign (result)] - Sub: v = [sign (src) != sign (src2)] and [sign (src) = sign (result)] -*/ - - case 011: /* MOVB */ - if (CPUT (IS_SDSD) && srcreg && !dstreg) { /* R,not R */ - ea = GeteaB (dstspec); - dst = R[srcspec] & 0377; - } - else { - dst = srcreg? R[srcspec] & 0377: ReadB (GeteaB (srcspec)); - if (!dstreg) - ea = GeteaB (dstspec); - } - N = GET_SIGN_B (dst); - Z = GET_Z (dst); - V = 0; - if (dstreg) - R[dstspec] = (dst & 0200)? 0177400 | dst: dst; - else WriteB (dst, ea); - break; - - case 012: /* CMPB */ - if (CPUT (IS_SDSD) && srcreg && !dstreg) { /* R,not R */ - src2 = ReadB (GeteaB (dstspec)); - src = R[srcspec] & 0377; - } - else { - src = srcreg? R[srcspec] & 0377: ReadB (GeteaB (srcspec)); - src2 = dstreg? R[dstspec] & 0377: ReadB (GeteaB (dstspec)); - } - dst = (src - src2) & 0377; - N = GET_SIGN_B (dst); - Z = GET_Z (dst); - V = GET_SIGN_B ((src ^ src2) & (~src2 ^ dst)); - C = (src < src2); - break; - - case 013: /* BITB */ - if (CPUT (IS_SDSD) && srcreg && !dstreg) { /* R,not R */ - src2 = ReadB (GeteaB (dstspec)); - src = R[srcspec] & 0377; - } - else { - src = srcreg? R[srcspec] & 0377: ReadB (GeteaB (srcspec)); - src2 = dstreg? R[dstspec] & 0377: ReadB (GeteaB (dstspec)); - } - dst = (src2 & src) & 0377; - N = GET_SIGN_B (dst); - Z = GET_Z (dst); - V = 0; - break; - - case 014: /* BICB */ - if (CPUT (IS_SDSD) && srcreg && !dstreg) { /* R,not R */ - src2 = ReadMB (GeteaB (dstspec)); - src = R[srcspec]; - } - else { - src = srcreg? R[srcspec]: ReadB (GeteaB (srcspec)); - src2 = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec)); - } - dst = (src2 & ~src) & 0377; - N = GET_SIGN_B (dst); - Z = GET_Z (dst); - V = 0; - if (dstreg) - R[dstspec] = (R[dstspec] & 0177400) | dst; - else PWriteB (dst, last_pa); - break; - - case 015: /* BISB */ - if (CPUT (IS_SDSD) && srcreg && !dstreg) { /* R,not R */ - src2 = ReadMB (GeteaB (dstspec)); - src = R[srcspec]; - } - else { - src = srcreg? R[srcspec]: ReadB (GeteaB (srcspec)); - src2 = dstreg? R[dstspec]: ReadMB (GeteaB (dstspec)); - } - dst = (src2 | src) & 0377; - N = GET_SIGN_B (dst); - Z = GET_Z (dst); - V = 0; - if (dstreg) - R[dstspec] = (R[dstspec] & 0177400) | dst; - else PWriteB (dst, last_pa); - break; - - case 016: /* SUB */ - if (CPUT (IS_SDSD) && srcreg && !dstreg) { /* R,not R */ - src2 = ReadMW (GeteaW (dstspec)); - src = R[srcspec]; - } - else { - src = srcreg? R[srcspec]: ReadW (GeteaW (srcspec)); - src2 = dstreg? R[dstspec]: ReadMW (GeteaW (dstspec)); - } - dst = (src2 - src) & 0177777; - N = GET_SIGN_W (dst); - Z = GET_Z (dst); - V = GET_SIGN_W ((src ^ src2) & (~src ^ dst)); - C = (src2 < src); - if (dstreg) - R[dstspec] = dst; - else PWriteW (dst, last_pa); - break; - -/* Opcode 17: floating point */ - - case 017: - if (CPUO (OPT_FPP)) - fp11 (IR); /* call fpp */ - else setTRAP (TRAP_ILL); - break; /* end case 017 */ - } /* end switch op */ - } /* end main loop */ - -/* Simulation halted */ - -PSW = get_PSW (); -for (i = 0; i < 6; i++) - REGFILE[i][rs] = R[i]; -STACKFILE[cm] = SP; -saved_PC = PC & 0177777; -pcq_r->qptr = pcq_p; /* update pc q ptr */ -set_r_display (rs, cm); -return reason; -} - -/* Effective address calculations - - Inputs: - spec = specifier <5:0> - Outputs: - ea = effective address - <15:0> = virtual address - <16> = instruction/data data space - <18:17> = mode - - Data space calculation: the PDP-11 features both instruction and data - spaces. Instruction space contains the instruction and any sequential - add ons (eg, immediates, absolute addresses). Data space contains all - data operands and indirect addresses. If data space is enabled, then - memory references are directed according to these rules: - - Mode Index ref Indirect ref Direct ref - 10..16 na na data - 17 na na instruction - 20..26 na na data - 27 na na instruction - 30..36 na data data - 37 na instruction (absolute) data - 40..46 na na data - 47 na na instruction - 50..56 na data data - 57 na instruction data - 60..67 instruction na data - 70..77 instruction data data - - According to the PDP-11 Architecture Handbook, MMR1 records all - autoincrement and autodecrement operations, including those which - explicitly reference the PC. For the J-11, this is only true for - autodecrement operands, autodecrement deferred operands, and - autoincrement destination operands that involve a write to memory. - The simulator follows the Handbook, for simplicity. - - Notes: - - - dsenable will direct a reference to data space if data space is enabled - - ds will direct a reference to data space if data space is enabled AND if - the specifier register is not PC; this is used for 17, 27, 37, 47, 57 - - Modes 2x, 3x, 4x, and 5x must update MMR1 if updating enabled - - Modes 46 and 56 must check for stack overflow if kernel mode -*/ - -/* Effective address calculation for words */ - -int32 GeteaW (int32 spec) -{ -int32 adr, reg, ds; - -reg = spec & 07; /* register number */ -ds = (reg == 7)? isenable: dsenable; /* dspace if not PC */ -switch (spec >> 3) { /* decode spec<5:3> */ - - default: /* can't get here */ - case 1: /* (R) */ - return (R[reg] | ds); - - case 2: /* (R)+ */ - R[reg] = ((adr = R[reg]) + 2) & 0177777; - if (update_MM && (reg != 7)) - MMR1 = calc_MMR1 (020 | reg); - return (adr | ds); - - case 3: /* @(R)+ */ - R[reg] = ((adr = R[reg]) + 2) & 0177777; - if (update_MM && (reg != 7)) - MMR1 = calc_MMR1 (020 | reg); - adr = ReadW (adr | ds); - return (adr | dsenable); - - case 4: /* -(R) */ - adr = R[reg] = (R[reg] - 2) & 0177777; - if (update_MM && (reg != 7)) - MMR1 = calc_MMR1 (0360 | reg); - if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y))) - set_stack_trap (adr); - return (adr | ds); - - case 5: /* @-(R) */ - adr = R[reg] = (R[reg] - 2) & 0177777; - if (update_MM && (reg != 7)) - MMR1 = calc_MMR1 (0360 | reg); - if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y))) - set_stack_trap (adr); - adr = ReadW (adr | ds); - return (adr | dsenable); - - case 6: /* d(r) */ - adr = ReadW (PC | isenable); - PC = (PC + 2) & 0177777; - return (((R[reg] + adr) & 0177777) | dsenable); - - case 7: /* @d(R) */ - adr = ReadW (PC | isenable); - PC = (PC + 2) & 0177777; - adr = ReadW (((R[reg] + adr) & 0177777) | dsenable); - return (adr | dsenable); - } /* end switch */ -} - -/* Effective address calculation for bytes */ - -int32 GeteaB (int32 spec) -{ -int32 adr, reg, ds, delta; - -reg = spec & 07; /* reg number */ -ds = (reg == 7)? isenable: dsenable; /* dspace if not PC */ -switch (spec >> 3) { /* decode spec<5:3> */ - - default: /* can't get here */ - case 1: /* (R) */ - return (R[reg] | ds); - - case 2: /* (R)+ */ - delta = 1 + (reg >= 6); /* 2 if R6, PC */ - R[reg] = ((adr = R[reg]) + delta) & 0177777; - if (update_MM && (reg != 7)) - MMR1 = calc_MMR1 ((delta << 3) | reg); - return (adr | ds); - - case 3: /* @(R)+ */ - R[reg] = ((adr = R[reg]) + 2) & 0177777; - if (update_MM && (reg != 7)) - MMR1 = calc_MMR1 (020 | reg); - adr = ReadW (adr | ds); - return (adr | dsenable); - - case 4: /* -(R) */ - delta = 1 + (reg >= 6); /* 2 if R6, PC */ - adr = R[reg] = (R[reg] - delta) & 0177777; - if (update_MM && (reg != 7)) - MMR1 = calc_MMR1 ((((-delta) & 037) << 3) | reg); - if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y))) - set_stack_trap (adr); - return (adr | ds); - - case 5: /* @-(R) */ - adr = R[reg] = (R[reg] - 2) & 0177777; - if (update_MM && (reg != 7)) - MMR1 = calc_MMR1 (0360 | reg); - if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y))) - set_stack_trap (adr); - adr = ReadW (adr | ds); - return (adr | dsenable); - - case 6: /* d(r) */ - adr = ReadW (PC | isenable); - PC = (PC + 2) & 0177777; - return (((R[reg] + adr) & 0177777) | dsenable); - - case 7: /* @d(R) */ - adr = ReadW (PC | isenable); - PC = (PC + 2) & 0177777; - adr = ReadW (((R[reg] + adr) & 0177777) | dsenable); - return (adr | dsenable); - } /* end switch */ -} - -/* Read byte and word routines, read only and read-modify-write versions - - Inputs: - va = virtual address, <18:16> = mode, I/D space - Outputs: - data = data read from memory or I/O space -*/ - -int32 ReadE (int32 va) -{ -int32 pa, data; - -if ((va & 1) && CPUT (HAS_ODD)) { /* odd address? */ - setCPUERR (CPUE_ODD); - ABORT (TRAP_ODD); - } -pa = relocR (va); /* relocate */ -if (ADDR_IS_MEM (pa)) /* memory address? */ - return RdMemW (pa); -if ((pa < IOPAGEBASE) || /* not I/O address */ - (CPUT (CPUT_J) && (pa >= IOBA_CPU))) { /* or J11 int reg? */ - setCPUERR (CPUE_NXM); - ABORT (TRAP_NXM); - } -if (iopageR (&data, pa, READ) != SCPE_OK) { /* invalid I/O addr? */ - setCPUERR (CPUE_TMO); - ABORT (TRAP_NXM); - } -return data; -} - -int32 ReadW (int32 va) -{ -int32 pa, data; - -if ((va & 1) && CPUT (HAS_ODD)) { /* odd address? */ - setCPUERR (CPUE_ODD); - ABORT (TRAP_ODD); - } -pa = relocR (va); /* relocate */ -if (ADDR_IS_MEM (pa)) /* memory address? */ - return RdMemW (pa); -if (pa < IOPAGEBASE) { /* not I/O address? */ - setCPUERR (CPUE_NXM); - ABORT (TRAP_NXM); - } -if (iopageR (&data, pa, READ) != SCPE_OK) { /* invalid I/O addr? */ - setCPUERR (CPUE_TMO); - ABORT (TRAP_NXM); - } -return data; -} - -int32 ReadB (int32 va) -{ -int32 pa, data; - -pa = relocR (va); /* relocate */ -if (ADDR_IS_MEM (pa)) /* memory address? */ - return RdMemB (pa); -if (pa < IOPAGEBASE) { /* not I/O address? */ - setCPUERR (CPUE_NXM); - ABORT (TRAP_NXM); - } -if (iopageR (&data, pa, READ) != SCPE_OK) { /* invalid I/O addr? */ - setCPUERR (CPUE_TMO); - ABORT (TRAP_NXM); - } -return ((va & 1)? data >> 8: data) & 0377; -} - -int32 ReadMW (int32 va) -{ -int32 data; - -if ((va & 1) && CPUT (HAS_ODD)) { /* odd address? */ - setCPUERR (CPUE_ODD); - ABORT (TRAP_ODD); - } -last_pa = relocW (va); /* reloc, wrt chk */ -if (ADDR_IS_MEM (last_pa)) /* memory address? */ - return RdMemW (last_pa); -if (last_pa < IOPAGEBASE) { /* not I/O address? */ - setCPUERR (CPUE_NXM); - ABORT (TRAP_NXM); - } -if (iopageR (&data, last_pa, READ) != SCPE_OK) { /* invalid I/O addr? */ - setCPUERR (CPUE_TMO); - ABORT (TRAP_NXM); - } -return data; -} - -int32 ReadMB (int32 va) -{ -int32 data; - -last_pa = relocW (va); /* reloc, wrt chk */ -if (ADDR_IS_MEM (last_pa)) - return RdMemB (last_pa); -if (last_pa < IOPAGEBASE) { /* not I/O address? */ - setCPUERR (CPUE_NXM); - ABORT (TRAP_NXM); - } -if (iopageR (&data, last_pa, READ) != SCPE_OK) { /* invalid I/O addr? */ - setCPUERR (CPUE_TMO); - ABORT (TRAP_NXM); - } -return ((va & 1)? data >> 8: data) & 0377; -} - -/* Write byte and word routines - - Inputs: - data = data to be written - va = virtual address, <18:16> = mode, I/D space, or - pa = physical address - Outputs: none -*/ - -void WriteW (int32 data, int32 va) -{ -int32 pa; - -if ((va & 1) && CPUT (HAS_ODD)) { /* odd address? */ - setCPUERR (CPUE_ODD); - ABORT (TRAP_ODD); - } -pa = relocW (va); /* relocate */ -if (ADDR_IS_MEM (pa)) { /* memory address? */ - WrMemW (pa, data); - return; - } -if (pa < IOPAGEBASE) { /* not I/O address? */ - setCPUERR (CPUE_NXM); - ABORT (TRAP_NXM); - } -if (iopageW (data, pa, WRITE) != SCPE_OK) { /* invalid I/O addr? */ - setCPUERR (CPUE_TMO); - ABORT (TRAP_NXM); - } -return; -} - -void WriteB (int32 data, int32 va) -{ -int32 pa; - -pa = relocW (va); /* relocate */ -if (ADDR_IS_MEM (pa)) { /* memory address? */ - WrMemB (pa, data); - return; - } -if (pa < IOPAGEBASE) { /* not I/O address? */ - setCPUERR (CPUE_NXM); - ABORT (TRAP_NXM); - } -if (iopageW (data, pa, WRITEB) != SCPE_OK) { /* invalid I/O addr? */ - setCPUERR (CPUE_TMO); - ABORT (TRAP_NXM); - } -return; -} - -void PWriteW (int32 data, int32 pa) -{ -if (ADDR_IS_MEM (pa)) { /* memory address? */ - WrMemW (pa, data); - return; - } -if (pa < IOPAGEBASE) { /* not I/O address? */ - setCPUERR (CPUE_NXM); - ABORT (TRAP_NXM); - } -if (iopageW (data, pa, WRITE) != SCPE_OK) { /* invalid I/O addr? */ - setCPUERR (CPUE_TMO); - ABORT (TRAP_NXM); - } -return; -} - -void PWriteB (int32 data, int32 pa) -{ -if (ADDR_IS_MEM (pa)) { /* memory address? */ - WrMemB (pa, data); - return; - } -if (pa < IOPAGEBASE) { /* not I/O address? */ - setCPUERR (CPUE_NXM); - ABORT (TRAP_NXM); - } -if (iopageW (data, pa, WRITEB) != SCPE_OK) { /* invalid I/O addr? */ - setCPUERR (CPUE_TMO); - ABORT (TRAP_NXM); - } -return; -} - -/* Relocate virtual address, read access - - Inputs: - va = virtual address, <18:16> = mode, I/D space - Outputs: - pa = physical address - On aborts, this routine aborts back to the top level simulator - with an appropriate trap code. - - Notes: - - The 'normal' read codes (010, 110) are done in-line; all - others in a subroutine - - APRFILE[UNUSED] is all zeroes, forcing non-resident abort - - Aborts must update MMR0<15:13,6:1> if updating is enabled -*/ - -int32 relocR (int32 va) -{ -int32 apridx, apr, pa; - -if (MMR0 & MMR0_MME) { /* if mmgt */ - apridx = (va >> VA_V_APF) & 077; /* index into APR */ - apr = APRFILE[apridx]; /* with va<18:13> */ - if ((apr & PDR_PRD) != 2) /* not 2, 6? */ - relocR_test (va, apridx); /* long test */ - if (PLF_test (va, apr)) /* pg lnt error? */ - reloc_abort (MMR0_PL, apridx); - pa = ((va & VA_DF) + ((apr >> 10) & 017777700)) & PAMASK; - if ((MMR3 & MMR3_M22E) == 0) { - pa = pa & 0777777; - if (pa >= 0760000) - pa = 017000000 | pa; - } - } -else { - pa = va & 0177777; /* mmgt off */ - if (pa >= 0160000) - pa = 017600000 | pa; - } -return pa; -} - -/* Read relocation, access control field != read only or read/write - - ACF value 11/45,11/70 all others - - 0 abort NR abort NR - 1 trap - - 2 ok ok - 3 abort NR - - 4 trap abort NR - 5 ok - - 6 ok ok - 7 abort NR - -*/ - -void relocR_test (int32 va, int32 apridx) -{ -int32 apr, err; - -err = 0; /* init status */ -apr = APRFILE[apridx]; /* get APR */ -switch (apr & PDR_ACF) { /* case on ACF */ - - case 1: case 4: /* trap read */ - if (CPUT (HAS_MMTR)) { /* traps implemented? */ - APRFILE[apridx] = APRFILE[apridx] | PDR_A; /* set A */ - if (MMR0 & MMR0_TENB) { /* traps enabled? */ - if (update_MM) /* update MMR0 */ - MMR0 = (MMR0 & ~MMR0_PAGE) | (apridx << MMR0_V_PAGE); - MMR0 = MMR0 | MMR0_TRAP; /* set trap flag */ - setTRAP (TRAP_MME); /* set trap */ - } - return; /* continue op */ - } /* not impl, abort NR */ - case 0: case 3: case 7: /* non-resident */ - err = MMR0_NR; /* set MMR0 */ - break; /* go test PLF, abort */ - - case 2: case 5: case 6: /* readable */ - return; /* continue */ - } /* end switch */ - -if (PLF_test (va, apr)) /* pg lnt error? */ - err = err | MMR0_PL; -reloc_abort (err, apridx); -return; -} - -t_bool PLF_test (int32 va, int32 apr) -{ -int32 dbn = va & VA_BN; /* extr block num */ -int32 plf = (apr & PDR_PLF) >> 2; /* extr page length */ - -return ((apr & PDR_ED)? (dbn < plf): (dbn > plf)); /* pg lnt error? */ -} - -void reloc_abort (int32 err, int32 apridx) -{ -if (update_MM) MMR0 = /* update MMR0 */ - (MMR0 & ~MMR0_PAGE) | (apridx << MMR0_V_PAGE); -APRFILE[apridx] = APRFILE[apridx] | PDR_A; /* set A */ -MMR0 = MMR0 | err; /* set aborts */ -ABORT (TRAP_MME); /* abort ref */ -return; -} - -/* Relocate virtual address, write access - - Inputs: - va = virtual address, <18:16> = mode, I/D space - Outputs: - pa = physical address - On aborts, this routine aborts back to the top level simulator - with an appropriate trap code. - - Notes: - - The 'normal' write code (110) is done in-line; all others - in a subroutine - - APRFILE[UNUSED] is all zeroes, forcing non-resident abort - - Aborts must update MMR0<15:13,6:1> if updating is enabled -*/ - -int32 relocW (int32 va) -{ -int32 apridx, apr, pa; - -if (MMR0 & MMR0_MME) { /* if mmgt */ - apridx = (va >> VA_V_APF) & 077; /* index into APR */ - apr = APRFILE[apridx]; /* with va<18:13> */ - if ((apr & PDR_ACF) != 6) /* not writeable? */ - relocW_test (va, apridx); /* long test */ - if (PLF_test (va, apr)) /* pg lnt error? */ - reloc_abort (MMR0_PL, apridx); - APRFILE[apridx] = apr | PDR_W; /* set W */ - pa = ((va & VA_DF) + ((apr >> 10) & 017777700)) & PAMASK; - if ((MMR3 & MMR3_M22E) == 0) { - pa = pa & 0777777; - if (pa >= 0760000) - pa = 017000000 | pa; - } - } -else { - pa = va & 0177777; /* mmgt off */ - if (pa >= 0160000) - pa = 017600000 | pa; - } -return pa; -} - -/* Write relocation, access control field != read/write - - ACF value 11/45,11/70 all others - - 0 abort NR abort NR - 1 abort RO - - 2 abort RO abort RO - 3 abort NR - - 4 trap abort NR - 5 trap - - 6 ok ok - 7 abort NR - -*/ - -void relocW_test (int32 va, int32 apridx) -{ -int32 apr, err; - -err = 0; /* init status */ -apr = APRFILE[apridx]; /* get APR */ -switch (apr & PDR_ACF) { /* case on ACF */ - - case 4: case 5: /* trap write */ - if (CPUT (HAS_MMTR)) { /* traps implemented? */ - APRFILE[apridx] = APRFILE[apridx] | PDR_A; /* set A */ - if (MMR0 & MMR0_TENB) { /* traps enabled? */ - if (update_MM) /* update MMR0 */ - MMR0 = (MMR0 & ~MMR0_PAGE) | (apridx << MMR0_V_PAGE); - MMR0 = MMR0 | MMR0_TRAP; /* set trap flag */ - setTRAP (TRAP_MME); /* set trap */ - } - return; /* continue op */ - } /* not impl, abort NR */ - case 0: case 3: case 7: /* non-resident */ - err = MMR0_NR; /* MMR0 status */ - break; /* go test PLF, abort */ - - case 1: case 2: /* read only */ - err = MMR0_RO; /* MMR0 status */ - break; - - case 6: /* read/write */ - return; /* continue */ - } /* end switch */ -if (PLF_test (va, apr)) /* pg lnt error? */ - err = err | MMR0_PL; -reloc_abort (err, apridx); -return; -} - -/* Relocate virtual address, console access - - Inputs: - va = virtual address - sw = switches - Outputs: - pa = physical address - On aborts, this routine returns MAXMEMSIZE -*/ - -int32 relocC (int32 va, int32 sw) -{ -int32 mode, dbn, plf, apridx, apr, pa; - -if (MMR0 & MMR0_MME) { /* if mmgt */ - if (sw & SWMASK ('K')) - mode = MD_KER; - else if (sw & SWMASK ('S')) - mode = MD_SUP; - else if (sw & SWMASK ('U')) - mode = MD_USR; - else if (sw & SWMASK ('P')) - mode = (PSW >> PSW_V_PM) & 03; - else mode = (PSW >> PSW_V_CM) & 03; - va = va | ((sw & SWMASK ('T'))? calc_ds (mode): calc_is (mode)); - apridx = (va >> VA_V_APF) & 077; /* index into APR */ - apr = APRFILE[apridx]; /* with va<18:13> */ - dbn = va & VA_BN; /* extr block num */ - plf = (apr & PDR_PLF) >> 2; /* extr page length */ - if ((apr & PDR_PRD) == 0) /* not readable? */ - return MAXMEMSIZE; - if ((apr & PDR_ED)? dbn < plf: dbn > plf) - return MAXMEMSIZE; - pa = ((va & VA_DF) + ((apr >> 10) & 017777700)) & PAMASK; - if ((MMR3 & MMR3_M22E) == 0) { - pa = pa & 0777777; - if (pa >= 0760000) - pa = 017000000 | pa; - } - } -else { - pa = va & 0177777; /* mmgt off */ - if (pa >= 0160000) - pa = 017600000 | pa; - } -return pa; -} - -/* Memory management registers - - MMR0 17777572 read/write, certain bits unimplemented or read only - MMR1 17777574 read only - MMR2 17777576 read only - MMR3 17777516 read/write, certain bits unimplemented -*/ - -t_stat MMR012_rd (int32 *data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 3) { /* decode pa<2:1> */ - - case 0: /* SR */ - return SCPE_NXM; - - case 1: /* MMR0 */ - *data = MMR0 & cpu_tab[cpu_model].mm0; - break; - - case 2: /* MMR1 */ - *data = MMR1; - break; - - case 3: /* MMR2 */ - *data = MMR2; - break; - } /* end switch pa */ - -return SCPE_OK; -} - -t_stat MMR012_wr (int32 data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 3) { /* decode pa<2:1> */ - - case 0: /* DR */ - return SCPE_NXM; - - case 1: /* MMR0 */ - if (access == WRITEB) - data = (pa & 1)? (MMR0 & 0377) | (data << 8): (MMR0 & ~0377) | data; - data = data & cpu_tab[cpu_model].mm0; - MMR0 = (MMR0 & ~MMR0_WR) | (data & MMR0_WR); - return SCPE_OK; - - default: /* MMR1, MMR2 */ - return SCPE_OK; - } /* end switch pa */ -} - -t_stat MMR3_rd (int32 *data, int32 pa, int32 access) /* MMR3 */ -{ -*data = MMR3 & cpu_tab[cpu_model].mm3; -return SCPE_OK; -} - -t_stat MMR3_wr (int32 data, int32 pa, int32 access) /* MMR3 */ -{ -if (pa & 1) - return SCPE_OK; -MMR3 = data & cpu_tab[cpu_model].mm3; -cpu_bme = (MMR3 & MMR3_BME) && (cpu_opt & OPT_UBM); -dsenable = calc_ds (cm); -return SCPE_OK; -} - -/* PARs and PDRs. These are grouped in I/O space as follows: - - 17772200 - 17772276 supervisor block - 17772300 - 17772376 kernel block - 17777600 - 17777676 user block - - Within each block, the subblocks are I PDR's, D PDR's, I PAR's, D PAR's - - Thus, the algorithm for converting between I/O space addresses and - APRFILE indices is as follows: - - idx<3:0> = dspace'page = pa<4:1> - par = PDR vs PAR = pa<5> - idx<5:4> = ker/sup/user = pa<8>'~pa<6> - - Note: the A,W bits are read only; they are cleared by any write to an APR -*/ - -t_stat APR_rd (int32 *data, int32 pa, int32 access) -{ -t_stat left, idx; - -idx = (pa >> 1) & 017; /* dspace'page */ -left = (pa >> 5) & 1; /* PDR vs PAR */ -if ((pa & 0100) == 0) /* 1 for super, user */ - idx = idx | 020; -if (pa & 0400) /* 1 for user only */ - idx = idx | 040; -if (left) - *data = (APRFILE[idx] >> 16) & cpu_tab[cpu_model].par; -else *data = APRFILE[idx] & cpu_tab[cpu_model].pdr; -return SCPE_OK; -} - -t_stat APR_wr (int32 data, int32 pa, int32 access) -{ -int32 left, idx, curr; - -idx = (pa >> 1) & 017; /* dspace'page */ -left = (pa >> 5) & 1; /* PDR vs PAR */ -if ((pa & 0100) == 0) /* 1 for super, user */ - idx = idx | 020; -if (pa & 0400) /* 1 for user only */ - idx = idx | 040; -if (left) - curr = (APRFILE[idx] >> 16) & cpu_tab[cpu_model].par; -else curr = APRFILE[idx] & cpu_tab[cpu_model].pdr; -if (access == WRITEB) - data = (pa & 1)? (curr & 0377) | (data << 8): (curr & ~0377) | data; -if (left) - APRFILE[idx] = ((APRFILE[idx] & 0177777) | - (((uint32) (data & cpu_tab[cpu_model].par)) << 16)) & ~(PDR_A|PDR_W); -else APRFILE[idx] = ((APRFILE[idx] & ~0177777) | - (data & cpu_tab[cpu_model].pdr)) & ~(PDR_A|PDR_W); -return SCPE_OK; -} - -/* Explicit PSW read */ - -t_stat PSW_rd (int32 *data, int32 pa, int32 access) -{ -if (access == READC) - *data = PSW; -else *data = get_PSW (); -return SCPE_OK; -} - -/* Assemble PSW from pieces */ - -int32 get_PSW (void) -{ -return (cm << PSW_V_CM) | (pm << PSW_V_PM) | - (rs << PSW_V_RS) | (fpd << PSW_V_FPD) | - (ipl << PSW_V_IPL) | (tbit << PSW_V_TBIT) | - (N << PSW_V_N) | (Z << PSW_V_Z) | - (V << PSW_V_V) | (C << PSW_V_C); -} - -/* Explicit PSW write - T-bit may be protected */ - -t_stat PSW_wr (int32 data, int32 pa, int32 access) -{ -int32 i, curr, oldrs; - -if (access == WRITEC) { /* console access? */ - PSW = data & cpu_tab[cpu_model].psw; - return SCPE_OK; - } -curr = get_PSW (); /* get current */ -oldrs = rs; /* save reg set */ -STACKFILE[cm] = SP; /* save curr SP */ -if (access == WRITEB) data = (pa & 1)? - (curr & 0377) | (data << 8): (curr & ~0377) | data; -if (!CPUT (HAS_EXPT)) /* expl T writes? */ - data = (data & ~PSW_TBIT) | (curr & PSW_TBIT); /* no, use old T */ -put_PSW (data, 0); /* call calc_is,ds */ -if (rs != oldrs) { /* switch reg set */ - for (i = 0; i < 6; i++) { - REGFILE[i][oldrs] = R[i]; - R[i] = REGFILE[i][rs]; - } - } -SP = STACKFILE[cm]; /* switch SP */ -isenable = calc_is (cm); -dsenable = calc_ds (cm); -return SCPE_OK; -} - -/* Store pieces of new PSW - implements RTI/RTT protection */ - -void put_PSW (int32 val, t_bool prot) -{ -val = val & cpu_tab[cpu_model].psw; /* mask off invalid bits */ -if (prot) { /* protected? */ - cm = cm | ((val >> PSW_V_CM) & 03); /* or to cm,pm,rs */ - pm = pm | ((val >> PSW_V_PM) & 03); /* can't change ipl */ - rs = rs | ((val >> PSW_V_RS) & 01); - } -else { - cm = (val >> PSW_V_CM) & 03; /* write cm,pm,rs,ipl */ - pm = (val >> PSW_V_PM) & 03; - rs = (val >> PSW_V_RS) & 01; - ipl = (val >> PSW_V_IPL) & 07; - } -fpd = (val >> PSW_V_FPD) & 01; /* always writeable */ -tbit = (val >> PSW_V_TBIT) & 01; -N = (val >> PSW_V_N) & 01; -Z = (val >> PSW_V_Z) & 01; -V = (val >> PSW_V_V) & 01; -C = (val >> PSW_V_C) & 01; -return; -} - -/* PIRQ write routine */ - -void put_PIRQ (int32 val) -{ -int32 pl; - -PIRQ = val & PIRQ_RW; -pl = 0; -if (PIRQ & PIRQ_PIR1) { - SET_INT (PIR1); - pl = 0042; - } -else CLR_INT (PIR1); -if (PIRQ & PIRQ_PIR2) { - SET_INT (PIR2); - pl = 0104; - } -else CLR_INT (PIR2); -if (PIRQ & PIRQ_PIR3) { - SET_INT (PIR3); - pl = 0146; - } -else CLR_INT (PIR3); -if (PIRQ & PIRQ_PIR4) { - SET_INT (PIR4); - pl = 0210; - } -else CLR_INT (PIR4); -if (PIRQ & PIRQ_PIR5) { - SET_INT (PIR5); - pl = 0252; - } -else CLR_INT (PIR5); -if (PIRQ & PIRQ_PIR6) { - SET_INT (PIR6); - pl = 0314; - } -else CLR_INT (PIR6); -if (PIRQ & PIRQ_PIR7) { - SET_INT (PIR7); - pl = 0356; - } -else CLR_INT (PIR7); -PIRQ = PIRQ | pl; -return; -} - -/* Stack trap routine */ - -void set_stack_trap (int32 adr) -{ -if (CPUT (HAS_STKLF)) { /* fixed stack? */ - setTRAP (TRAP_YEL); /* always yellow trap */ - setCPUERR (CPUE_YEL); - } -else if (CPUT (HAS_STKLR)) { /* register limit? */ - if (adr >= (STKLIM + STKL_R)) { /* yellow zone? */ - setTRAP (TRAP_YEL); /* still yellow trap */ - setCPUERR (CPUE_YEL); - } - else { /* red zone abort */ - setCPUERR (CPUE_RED); - STACKFILE[MD_KER] = 4; - SP = 4; - ABORT (TRAP_RED); - } - } -return; /* no stack limit */ -} - -/* Reset routine */ - -t_stat cpu_reset (DEVICE *dptr) -{ -PIRQ = 0; -STKLIM = 0; -if (CPUT (CPUT_T)) /* T11? */ - PSW = 000340; /* start at IPL 7 */ -else PSW = 0; /* else at IPL 0 */ -MMR0 = 0; -MMR1 = 0; -MMR2 = 0; -MMR3 = 0; -trap_req = 0; -wait_state = 0; -if (M == NULL) - M = (uint16 *) calloc (MEMSIZE >> 1, sizeof (uint16)); -if (M == NULL) - return SCPE_MEM; -pcq_r = find_reg ("PCQ", NULL, dptr); -if (pcq_r) - pcq_r->qptr = 0; -else return SCPE_IERR; -sim_brk_types = sim_brk_dflt = SWMASK ('E'); -set_r_display (0, MD_KER); -return build_dib_tab (); -} - -/* Boot setup routine */ - -void cpu_set_boot (int32 pc) -{ -saved_PC = pc; -PSW = 000340; -return; -} - -/* Memory examine */ - -t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) -{ -int32 iodata; -t_stat stat; - -if (vptr == NULL) - return SCPE_ARG; -if (sw & SWMASK ('V')) { /* -v */ - if (addr >= VASIZE) - return SCPE_NXM; - addr = relocC (addr, sw); /* relocate */ - if (addr >= MAXMEMSIZE) - return SCPE_REL; - } -if (ADDR_IS_MEM (addr)) { - *vptr = RdMemW (addr) & 0177777; - return SCPE_OK; - } -if (addr < IOPAGEBASE) - return SCPE_NXM; -stat = iopageR (&iodata, addr, READC); -*vptr = iodata; -return stat; -} - -/* Memory deposit */ - -t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) -{ -if (sw & SWMASK ('V')) { /* -v */ - if (addr >= VASIZE) - return SCPE_NXM; - addr = relocC (addr, sw); /* relocate */ - if (addr >= MAXMEMSIZE) - return SCPE_REL; - } -if (ADDR_IS_MEM (addr)) { - WrMemW (addr, val & 0177777); - return SCPE_OK; - } -if (addr < IOPAGEBASE) - return SCPE_NXM; -return iopageW ((int32) val, addr, WRITEC); -} - -/* Set R, SP register display addresses */ - -void set_r_display (int32 rs, int32 cm) -{ -REG *rptr; -int32 i; - -rptr = find_reg ("R0", NULL, &cpu_dev); -if (rptr == NULL) - return; -for (i = 0; i < 6; i++, rptr++) - rptr->loc = (void *) ®FILE[i][rs]; -rptr->loc = (void *) &STACKFILE[cm]; -return; -} - -/* Set history */ - -t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 i, lnt; -t_stat r; - -if (cptr == NULL) { - for (i = 0; i < hst_lnt; i++) - hst[i].pc = 0; - hst_p = 0; - return SCPE_OK; - } -lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r); -if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) - return SCPE_ARG; -hst_p = 0; -if (hst_lnt) { - free (hst); - hst_lnt = 0; - hst = NULL; - } -if (lnt) { - hst = (InstHistory *) calloc (lnt, sizeof (InstHistory)); - if (hst == NULL) - return SCPE_MEM; - hst_lnt = lnt; - } -return SCPE_OK; -} - -/* Show history */ - -t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -int32 j, k, di, lnt, ir; -char *cptr = (char *) desc; -t_value sim_eval[HIST_ILNT]; -t_stat r; -InstHistory *h; - -if (hst_lnt == 0) /* enabled? */ - return SCPE_NOFNC; -if (cptr) { - lnt = (int32) get_uint (cptr, 10, hst_lnt, &r); - if ((r != SCPE_OK) || (lnt == 0)) - return SCPE_ARG; - } -else lnt = hst_lnt; -di = hst_p - lnt; /* work forward */ -if (di < 0) - di = di + hst_lnt; -fprintf (st, "PC SP PSW src dst IR\n\n"); -for (k = 0; k < lnt; k++) { /* print specified */ - h = &hst[(di++) % hst_lnt]; /* entry pointer */ - if (h->pc & HIST_VLD) { /* instruction? */ - ir = h->inst[0]; - fprintf (st, "%06o %06o %06o|", h->pc & ~HIST_VLD, h->sp, h->psw); - if (((ir & 0070000) != 0) || /* dops, eis, fpp */ - ((ir & 0177000) == 0004000)) /* jsr */ - fprintf (st, "%06o %06o ", h->src, h->dst); - else if ((ir >= 0000100) && /* not no opnd */ - (((ir & 0007700) < 0000300) || /* not branch */ - ((ir & 0007700) >= 0004000))) - fprintf (st, " %06o ", h->dst); - else fprintf (st, " "); - for (j = 0; j < HIST_ILNT; j++) - sim_eval[j] = h->inst[j]; - if ((fprint_sym (st, h->pc & ~HIST_VLD, sim_eval, &cpu_unit, SWMASK ('M'))) > 0) - fprintf (st, "(undefined) %06o", h->inst[0]); - fputc ('\n', st); /* end line */ - } /* end else instruction */ - } /* end for */ -return SCPE_OK; -} - -/* Virtual address translation */ - -t_stat cpu_show_virt (FILE *of, UNIT *uptr, int32 val, void *desc) -{ -t_stat r; -char *cptr = (char *) desc; -uint32 va, pa; - -if (cptr) { - va = (uint32) get_uint (cptr, 8, VAMASK, &r); - if (r == SCPE_OK) { - pa = relocC (va, sim_switches); /* relocate */ - if (pa < MAXMEMSIZE) - fprintf (of, "Virtual %-o = physical %-o\n", va, pa); - else fprintf (of, "Virtual %-o is not valid\n", va); - return SCPE_OK; - } - } -fprintf (of, "Invalid argument\n"); -return SCPE_OK; -} diff --git a/PDP11/pdp11_cpumod.c b/PDP11/pdp11_cpumod.c deleted file mode 100644 index c45d4360..00000000 --- a/PDP11/pdp11_cpumod.c +++ /dev/null @@ -1,1255 +0,0 @@ -/* pdp11_cpumod.c: PDP-11 CPU model-specific features - - Copyright (c) 2004-2016, 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. - - system PDP-11 model-specific registers - - 04-Mar-16 RMS Fixed maximum memory sizes to exclude IO page - 14-Mar-16 RMS Modified to keep cpu_memsize in sync with MEMSIZE - 06-Jun-13 RMS Fixed change model to set memory size last - 20-May-08 RMS Added JCSR default for KDJ11B, KDJ11E - 22-Apr-08 RMS Fixed write behavior of 11/70 MBRK, LOSIZE, HISIZE - (Walter Mueller) - 29-Apr-07 RMS Don't run bus setup routine during RESTORE - 30-Aug-05 RMS Added additional 11/60 registers - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 15-Feb-05 RMS Fixed bug in SHOW MODEL (Sergey Okhapkin) - 19-Jan-05 RMS Added variable SYSID, MBRK write (Tim Chapman) - - This module includes CPU- and system-specific registers, such as the Unibus - map and control registers on 22b Unibus systems, the board registers for the - F11- and J11-based systems, and the system registers for the PDP-11/44, - PDP-11/45, PDP-11/60, and PDP-11/70. Most registers are implemented at - a minimum level: just enough to satisfy the machine identification code - in the various operating systems. -*/ - -#include "pdp11_defs.h" -#include "pdp11_cpumod.h" -#include - -/* Byte write macros for system registers */ - -#define ODD_IGN(cur) \ - if ((access == WRITEB) && (pa & 1)) \ - return SCPE_OK -#define ODD_WO(cur) \ - if ((access == WRITEB) && (pa & 1)) \ - cur = cur << 8 -#define ODD_MRG(prv,cur) \ - if (access == WRITEB) \ - cur =((pa & 1)? (((prv) & 0377) | ((cur) & 0177400)) : \ - (((prv) & 0177400) | ((cur) & 0377))) - -int32 SR = 0; /* switch register */ -int32 DR = 0; /* display register */ -int32 MBRK = 0; /* 11/70 microbreak */ -int32 SYSID = 0x1234; /* 11/70 system ID */ -int32 WCS = 0; /* 11/60 WCS control */ -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; /* maint reg */ -int32 JCSR = 0; /* J11 control */ -int32 JCSR_dflt = 0; /* J11 boot ctl def */ -int32 JPCR = 0; /* J11 page ctrl */ -int32 JASR = 0; /* J11 addtl status */ -int32 UDCR = 0; /* UBA diag ctrl */ -int32 UDDR = 0; /* UBA diag data */ -int32 UCSR = 0; /* UBA control */ -int32 uba_last = 0; /* UBA last mapped */ -int32 ub_map[UBM_LNT_LW] = { 0 }; /* UBA map array */ -int32 toy_state = 0; -uint8 toy_data[TOY_LNT] = { 0 }; -static int32 clk_tps_map[4] = { 60, 60, 50, 800 }; - -extern uint16 *M; -extern int32 R[8]; -extern DEVICE cpu_dev; -extern UNIT cpu_unit; -extern int32 STKLIM, PIRQ; -extern uint32 cpu_model, cpu_type, cpu_opt; -extern int32 clk_fie, clk_fnxm, clk_tps, clk_default; - -t_stat CPU24_rd (int32 *data, int32 addr, int32 access); -t_stat CPU24_wr (int32 data, int32 addr, int32 access); -t_stat CPU44_rd (int32 *data, int32 addr, int32 access); -t_stat CPU44_wr (int32 data, int32 addr, int32 access); -t_stat CPU45_rd (int32 *data, int32 addr, int32 access); -t_stat CPU45_wr (int32 data, int32 addr, int32 access); -t_stat CPU60_rd (int32 *data, int32 addr, int32 access); -t_stat CPU60_wr (int32 data, int32 addr, int32 access); -t_stat CPU70_rd (int32 *data, int32 addr, int32 access); -t_stat CPU70_wr (int32 data, int32 addr, int32 access); -t_stat CPUJ_rd (int32 *data, int32 addr, int32 access); -t_stat CPUJ_wr (int32 data, int32 addr, int32 access); -t_stat REG_rd (int32 *data, int32 addr, int32 access); -t_stat REG_wr (int32 data, int32 addr, int32 access); -t_stat SR_rd (int32 *data, int32 addr, int32 access); -t_stat DR_wr (int32 data, int32 addr, int32 access); -t_stat CTLFB_rd (int32 *data, int32 addr, int32 access); -t_stat CTLFB_wr (int32 data, int32 addr, int32 access); -t_stat CTLJB_rd (int32 *data, int32 addr, int32 access); -t_stat CTLJB_wr (int32 data, int32 addr, int32 access); -t_stat CTLJD_rd (int32 *data, int32 addr, int32 access); -t_stat CTLJD_wr (int32 data, int32 addr, int32 access); -t_stat CTLJE_rd (int32 *data, int32 addr, int32 access); -t_stat CTLJE_wr (int32 data, int32 addr, int32 access); -t_stat UBA24_rd (int32 *data, int32 addr, int32 access); -t_stat UBA24_wr (int32 data, int32 addr, int32 access); -t_stat UBAJ_rd (int32 *data, int32 addr, int32 access); -t_stat UBAJ_wr (int32 data, int32 addr, int32 access); -t_stat sys_reset (DEVICE *dptr); -int32 toy_read (void); -void toy_write (int32 bit); -uint8 toy_set (int32 val); -t_stat sys_set_jclk_dflt (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat sys_show_jclk_dflt (FILE *st, UNIT *uptr, int32 val, void *desc); - -extern t_stat PSW_rd (int32 *data, int32 addr, int32 access); -extern t_stat PSW_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 MMR012_rd (int32 *data, int32 addr, int32 access); -extern t_stat 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 void put_PIRQ (int32 val); - -/* Fixed I/O address table entries */ - -DIB psw_dib = { IOBA_PSW, IOLN_PSW, &PSW_rd, &PSW_wr, 0 }; -DIB cpuj_dib = { IOBA_CPU, IOLN_CPU, &CPUJ_rd, &CPUJ_wr, 0 }; -DIB cpu24_dib = { IOBA_CPU, IOLN_CPU, &CPU24_rd, &CPU24_wr, 0 }; -DIB cpu44_dib = { IOBA_CPU, IOLN_CPU, &CPU44_rd, &CPU44_wr, 0 }; -DIB cpu45_dib = { IOBA_CPU, IOLN_CPU, &CPU45_rd, &CPU45_wr, 0 }; -DIB cpu60_dib = { IOBA_CPU, IOLN_CPU, &CPU60_rd, &CPU60_wr, 0 }; -DIB cpu70_dib = { IOBA_CPU, IOLN_CPU, &CPU70_rd, &CPU70_wr, 0 }; -DIB reg_dib = { IOBA_GPR, IOLN_GPR, ®_rd, ®_wr, 0 }; -DIB ctlfb_dib = { IOBA_CTL, IOLN_CTL, &CTLFB_rd, &CTLFB_wr }; -DIB ctljb_dib = { IOBA_CTL, IOLN_CTL, &CTLJB_rd, &CTLJB_wr }; -DIB ctljd_dib = { IOBA_CTL, IOLN_CTL, &CTLJD_rd, &CTLJD_wr }; -DIB ctlje_dib = { IOBA_CTL, IOLN_CTL, &CTLJE_rd, &CTLJE_wr }; -DIB uba24_dib = { IOBA_UCTL, IOLN_UCTL, &UBA24_rd, &UBA24_wr }; -DIB ubaj_dib = {IOBA_UCTL, IOLN_UCTL, &UBAJ_rd, &UBAJ_wr }; -DIB supv_dib = { IOBA_SUP, IOLN_SUP, &APR_rd, &APR_wr, 0 }; -DIB kipdr_dib = { IOBA_KIPDR, IOLN_KIPDR, &APR_rd, &APR_wr, 0 }; -DIB kdpdr_dib = { IOBA_KDPDR, IOLN_KDPDR, &APR_rd, &APR_wr, 0 }; -DIB kipar_dib = { IOBA_KIPAR, IOLN_KIPAR, &APR_rd, &APR_wr, 0 }; -DIB kdpar_dib = { IOBA_KDPAR, IOLN_KDPAR, &APR_rd, &APR_wr, 0 }; -DIB uipdr_dib = { IOBA_UIPDR, IOLN_UIPDR, &APR_rd, &APR_wr, 0 }; -DIB udpdr_dib = { IOBA_UDPDR, IOLN_UDPDR, &APR_rd, &APR_wr, 0 }; -DIB uipar_dib = { IOBA_UIPAR, IOLN_UIPAR, &APR_rd, &APR_wr, 0 }; -DIB udpar_dib = { IOBA_UDPAR, IOLN_UDPAR, &APR_rd, &APR_wr, 0 }; -DIB sr_dib = { IOBA_SR, IOLN_SR, &SR_rd, NULL, 0 }; -DIB dr_dib = { IOBA_SR, IOLN_SR, NULL, &DR_wr, 0 }; -DIB mmr012_dib = { IOBA_MMR012, IOLN_MMR012, &MMR012_rd, &MMR012_wr, 0 }; -DIB mmr3_dib = { IOBA_MMR3, IOLN_MMR3, &MMR3_rd, &MMR3_wr, 0 }; -DIB ubm_dib = { IOBA_UBM, IOLN_UBM, &ubm_rd, &ubm_wr, 0 }; - -CPUTAB cpu_tab[MOD_MAX] = { - { "11/03", SOP_1103, OPT_1103, MEMSIZE64K, PSW_1103, - 0, 0, 0, 0, 0 }, - { "11/04", SOP_1104, OPT_1104, MEMSIZE64K, PSW_1104, - 0, 0, 0, 0, 0 }, - { "11/05", SOP_1105, OPT_1105, MEMSIZE64K, PSW_1105, - 0, 0, 0, 0, 0 }, - { "11/20", SOP_1120, OPT_1120, MEMSIZE64K, PSW_1120, - 0, 0, 0, 0, 0 }, - { "11/23", SOP_1123, OPT_1123, MAXMEMSIZE, PSW_F, - MFPT_F, PAR_F, PDR_F, MM0_F, MM3_F }, - { "11/23+", SOP_1123P, OPT_1123P, MAXMEMSIZE, PSW_F, - MFPT_F, PAR_F, PDR_F, MM0_F, MM3_F }, - { "11/24", SOP_1124, OPT_1124, MAXMEMSIZE, PSW_F, - MFPT_F, PAR_F, PDR_F, MM0_F, MM3_F }, - { "11/34", SOP_1134, OPT_1134, UNIMEMSIZE, PSW_1134, - 0, PAR_1134, PDR_1134, MM0_1134, 0 }, - { "11/40", SOP_1140, OPT_1140, UNIMEMSIZE, PSW_1140, - 0, PAR_1140, PDR_1140, MM0_1140, 0 }, - { "11/44", SOP_1144, OPT_1144, MAXMEMSIZE, PSW_1144, - MFPT_44, PAR_1144, PDR_1144, MM0_1144, MM3_1144 }, - { "11/45", SOP_1145, OPT_1145, UNIMEMSIZE, PSW_1145, - 0, PAR_1145, PDR_1145, MM0_1145, MM3_1145 }, - { "11/60", SOP_1160, OPT_1160, UNIMEMSIZE, PSW_1160, - 0, PAR_1160, PDR_1160, MM0_1160, 0 }, - { "11/70", SOP_1170, OPT_1170, MAXMEMSIZE, PSW_1170, - 0, PAR_1170, PDR_1170, MM0_1170, MM3_1170 }, - { "11/73", SOP_1173, OPT_1173, MAXMEMSIZE, PSW_J, - MFPT_J, PAR_J, PDR_J, MM0_J, MM3_J }, - { "11/53", SOP_1153, OPT_1153, MAXMEMSIZE, PSW_J, - MFPT_J, PAR_J, PDR_J, MM0_J, MM3_J }, - { "11/73B", SOP_1173B, OPT_1173B, MAXMEMSIZE, PSW_J, - MFPT_J, PAR_J, PDR_J, MM0_J, MM3_J }, - { "11/83", SOP_1183, OPT_1183, MAXMEMSIZE, PSW_J, - MFPT_J, PAR_J, PDR_J, MM0_J, MM3_J }, - { "11/84", SOP_1184, OPT_1184, MAXMEMSIZE, PSW_J, - MFPT_J, PAR_J, PDR_J, MM0_J, MM3_J }, - { "11/93", SOP_1193, OPT_1193, MAXMEMSIZE, PSW_J, - MFPT_J, PAR_J, PDR_J, MM0_J, MM3_J }, - { "11/94", SOP_1194, OPT_1194, MAXMEMSIZE, PSW_J, - MFPT_J, PAR_J, PDR_J, MM0_J, MM3_J } - }; - -CNFTAB cnf_tab[] = { - { HAS_PSW, 0, &psw_dib }, /* PSW */ - { CPUT_J, 0, &cpuj_dib }, /* CPU control */ - { CPUT_24, 0, &cpu24_dib }, - { CPUT_44, 0, &cpu44_dib }, - { CPUT_45, 0, &cpu45_dib }, - { CPUT_60, 0, &cpu60_dib }, - { CPUT_70, 0, &cpu70_dib }, - { HAS_IOSR, 0, ®_dib }, - { CPUT_23P, 0, &ctlfb_dib }, /* board ctls */ - { CPUT_JB, 0, &ctljb_dib }, - { CPUT_53, 0, &ctljd_dib }, - { CPUT_JE, 0, &ctlje_dib }, - { CPUT_24, 0, &uba24_dib }, /* UBA */ - { CPUT_JU, 0, &ubaj_dib }, - { 0, OPT_MMU, &kipdr_dib }, /* MMU */ - { 0, OPT_MMU, &kipar_dib }, - { 0, OPT_MMU, &uipdr_dib }, - { 0, OPT_MMU, &uipar_dib }, - { 0, OPT_MMU, &mmr012_dib }, /* MMR0-2 */ - { HAS_MMR3, 0, &mmr3_dib }, /* MMR3 */ - { 0, OPT_UBM, &ubm_dib }, /* Unibus map */ - { HAS_SID, 0, &kdpdr_dib }, /* supv, I/D */ - { HAS_SID, 0, &kdpar_dib }, - { HAS_SID, 0, &supv_dib }, - { HAS_SID, 0, &udpdr_dib }, - { HAS_SID, 0, &udpar_dib }, - { HAS_SR, 0, &sr_dib }, /* SR */ - { HAS_DR, 0, &dr_dib }, /* DR */ - { 0, 0, NULL } - }; - -static const char *opt_name[] = { - "Unibus", "Qbus", "EIS", "NOEIS", "FIS", "NOFIS", - "FPP", "NOFPP", "CIS", "NOCIS", "MMU", "NOMMU", - "RH11", "RH70", "PARITY", "NOPARITY", "Unibus map", "No map", - "BEVENT enabled", "BEVENT disabled", NULL - }; - -static const char *jcsr_val[4] = { - "LINE", "50HZ", "60HZ", "800HZ" - }; - -/* SYSTEM data structures - - sys_dev SYSTEM device descriptor - sys_unit SYSTEM unit descriptor - sys_reg SYSTEM register list -*/ - -UNIT sys_unit = { UDATA (NULL, 0, 0) }; - -REG sys_reg[] = { - { ORDATA (SR, SR, 16) }, - { ORDATA (DR, DR, 16) }, - { ORDATA (MEMERR, MEMERR, 16) }, - { ORDATA (CCR, CCR, 16) }, - { ORDATA (MAINT, MAINT, 16) }, - { ORDATA (HITMISS, HITMISS, 16) }, - { ORDATA (CPUERR, CPUERR, 16) }, - { ORDATA (MBRK, MBRK, 16) }, - { ORDATA (WCS, WCS, 16) }, - { ORDATA (SYSID, SYSID, 16) }, - { ORDATA (JCSR, JCSR, 16) }, - { ORDATA (JCSR_DFLT, JCSR_dflt, 16), REG_HRO }, - { ORDATA (JPCR, JPCR, 16) }, - { ORDATA (JASR, JASR, 16) }, - { ORDATA (UDCR, UDCR, 16) }, - { ORDATA (UDDR, UDDR, 16) }, - { ORDATA (UCSR, UCSR, 16) }, - { ORDATA (ULAST, uba_last, 23) }, - { BRDATA (UBMAP, ub_map, 8, 22, UBM_LNT_LW) }, - { DRDATA (TOY_STATE, toy_state, 6), REG_HRO }, - { BRDATA (TOY_DATA, toy_data, 8, 8, TOY_LNT), REG_HRO }, - { NULL} - }; - -MTAB sys_mod[] = { - { MTAB_XTD|MTAB_VDV|MTAB_NMO, 0, "JCLK_DFLT", "JCLK_DFLT", - &sys_set_jclk_dflt, &sys_show_jclk_dflt }, - { 0 } - }; - -DEVICE sys_dev = { - "SYSTEM", &sys_unit, sys_reg, sys_mod, - 1, 0, 0, 0, 0, 0, - NULL, NULL, &sys_reset, - NULL, NULL, NULL, - NULL, 0, 0, - NULL, NULL, NULL - }; - -/* Switch and display registers - many */ - -t_stat SR_rd (int32 *data, int32 pa, int32 access) -{ -*data = SR; -return SCPE_OK; -} - -t_stat DR_wr (int32 data, int32 pa, int32 access) -{ -DR = data; -return SCPE_OK; -} - -/* GPR's - 11/04, 11/05 */ - -t_stat REG_rd (int32 *data, int32 pa, int32 access) -{ -*data = R[pa & 07]; -return SCPE_OK; -} - -t_stat REG_wr (int32 data, int32 pa, int32 access) -{ -int32 reg = pa & 07; - -if (access == WRITE) - R[reg] = data; -else if (pa & 1) - R[reg] = (R[reg] & 0377) | (data << 8); -else R[reg] = (R[reg] & ~0377) | data; -return SCPE_OK; -} - -/* CPU control registers - 11/24 */ - -t_stat CPU24_rd (int32 *data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 017) { /* decode pa<4:1> */ - - case 013: /* CPUERR */ - *data = 0; - return SCPE_OK; - } /* end switch PA */ - -*data = 0; -return SCPE_NXM; /* unimplemented */ -} - -t_stat CPU24_wr (int32 data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 017) { /* decode pa<4:1> */ - - case 013: /* CPUERR */ - return SCPE_OK; - } /* end switch pa */ - -return SCPE_NXM; /* unimplemented */ -} - -/* CPU control registers - 11/44 */ - -t_stat CPU44_rd (int32 *data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 017) { /* decode pa<4:1> */ - - case 002: /* MEMERR */ - *data = MEMERR; - return SCPE_OK; - - case 003: /* CCR */ - *data = CCR & CCR44_RD; - return SCPE_OK; - - case 004: /* MAINT */ - *data = MAINT & CMR44_RD; - return SCPE_OK; - - case 005: /* Hit/miss */ - *data = HITMISS; - return SCPE_OK; - - case 006: /* CDR */ - *data = 0; - return SCPE_OK; - - case 013: /* CPUERR */ - if (CPUERR & CPUE_YEL) /* 11/44 stack err */ - CPUERR = (CPUERR & ~CPUE_YEL) | CPUE_RED; /* in <2> not <3> */ - if (CPUERR & (CPUE_ODD|CPUE_NXM|CPUE_TMO)) /* additional flag */ - CPUERR = CPUERR | CPUE44_BUSE; - *data = CPUERR & CPUE_IMP; - return SCPE_OK; - - case 015: /* PIRQ */ - *data = PIRQ; - return SCPE_OK; - } /* end switch PA */ - -*data = 0; -return SCPE_NXM; /* unimplemented */ -} - -t_stat CPU44_wr (int32 data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 017) { /* decode pa<4:1> */ - - case 002: /* MEMERR */ - MEMERR = 0; - return SCPE_OK; - - case 003: /* CCR */ - ODD_MRG (CCR, data); - CCR = data & CCR44_WR; - return SCPE_OK; - - case 004: /* MAINT */ - ODD_MRG (MAINT, data); - MAINT = data & CMR44_WR; - return SCPE_OK; - - case 005: /* Hit/miss */ - return SCPE_OK; - - case 013: /* CPUERR */ - CPUERR = 0; - return SCPE_OK; - - case 015: /* PIRQ */ - ODD_WO (data); - put_PIRQ (data); - return SCPE_OK; - } - -return SCPE_NXM; /* unimplemented */ -} - -/* CPU control registers - 11/45 */ - -t_stat CPU45_rd (int32 *data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 017) { /* decode pa<4:1> */ - - case 014: /* MBRK */ - *data = MBRK; - return SCPE_OK; - - case 015: /* PIRQ */ - *data = PIRQ; - return SCPE_OK; - - case 016: /* STKLIM */ - *data = STKLIM & STKLIM_RW; - return SCPE_OK; - } /* end switch PA */ - -*data = 0; -return SCPE_NXM; /* unimplemented */ -} - -t_stat CPU45_wr (int32 data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 017) { /* decode pa<4:1> */ - - case 015: /* PIRQ */ - ODD_WO (data); - put_PIRQ (data); - return SCPE_OK; - - case 016: /* STKLIM */ - ODD_WO (data); - STKLIM = data & STKLIM_RW; - return SCPE_OK; - } /* end switch pa */ - -return SCPE_NXM; /* unimplemented */ -} - -/* CPU control registers - 11/60 */ - -t_stat CPU60_rd (int32 *data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 017) { /* decode pa<4:1> */ - - case 000: /* WCS */ - *data = WCS & WCS60_RD; - return SCPE_OK; - - case 002: /* MEMERR */ - *data = MEMERR & MEME60_RD; - return SCPE_OK; - - case 003: /* CCR */ - *data = CCR & CCR60_RD; - return SCPE_OK; - - case 005: /* Hit/miss */ - *data = HITMISS; - return SCPE_OK; - - case 013: /* CPUERR */ - if (CPUERR & CPUE_NXM) /* TMO only */ - CPUERR = (CPUERR & ~CPUE_NXM) | CPUE_TMO; - *data = CPUERR & CPUE60_RD; - return SCPE_OK; - - case 016: /* STKLIM */ - *data = STKLIM & STKLIM_RW; - return SCPE_OK; - } /* end switch PA */ - -*data = 0; -return SCPE_NXM; /* unimplemented */ -} - -t_stat CPU60_wr (int32 data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 017) { /* decode pa<4:1> */ - - case 000: /* WCS */ - WCS = data & WCS60_WR; - return SCPE_OK; - - case 002: /* MEMERR */ - MEMERR = 0; - return SCPE_OK; - - case 003: /* CCR */ - ODD_IGN (data); - CCR = data & CCR60_WR; - return SCPE_OK; - - case 005: /* Hit/miss */ - return SCPE_OK; - - case 013: /* CPUERR */ - CPUERR = 0; - return SCPE_OK; - - case 014: /* MBRK */ - MBRK = data & MBRK60_WR; - return SCPE_OK; - - case 016: /* STKLIM */ - ODD_WO (data); - STKLIM = data & STKLIM_RW; - return SCPE_OK; - } /* end switch pa */ - -return SCPE_NXM; /* unimplemented */ -} - -/* CPU control registers - 11/70 */ - -t_stat CPU70_rd (int32 *data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 017) { /* decode pa<4:1> */ - - case 000: /* low error */ - *data = 0; - return SCPE_OK; - - case 001: /* high error */ - *data = 0; - return SCPE_OK; - - case 002: /* MEMERR */ - *data = MEMERR; - return SCPE_OK; - - case 003: /* CCR */ - *data = CCR; - return SCPE_OK; - - case 004: /* MAINT */ - *data = 0; - return SCPE_OK; - - case 005: /* Hit/miss */ - *data = HITMISS; - return SCPE_OK; - - case 010: /* low size */ - *data = (MEMSIZE >> 6) - 1; - return SCPE_OK; - - case 011: /* high size */ - *data = 0; - return SCPE_OK; - - case 012: /* system ID */ - *data = SYSID; - return SCPE_OK; - - case 013: /* CPUERR */ - *data = CPUERR & CPUE_IMP; - return SCPE_OK; - - case 014: /* MBRK */ - *data = MBRK; - return SCPE_OK; - - case 015: /* PIRQ */ - *data = PIRQ; - return SCPE_OK; - - case 016: /* STKLIM */ - *data = STKLIM & STKLIM_RW; - return SCPE_OK; - } /* end switch PA */ - -*data = 0; -return SCPE_NXM; /* unimplemented */ -} - -t_stat CPU70_wr (int32 data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 017) { /* decode pa<4:1> */ - - case 002: /* MEMERR */ - ODD_WO (data); - MEMERR = MEMERR & ~data; - return SCPE_OK; - - case 003: /* CCR */ - ODD_MRG (CCR, data); - CCR = data; - return SCPE_OK; - - case 004: /* MAINT */ - return SCPE_OK; - - case 005: /* Hit/miss */ - return SCPE_OK; - - case 010: /* low size */ - return SCPE_OK; - - case 011: /* high size */ - return SCPE_OK; - - case 013: /* CPUERR */ - CPUERR = 0; - return SCPE_OK; - - case 014: /* MBRK */ - ODD_IGN (data); - MBRK = data & MBRK70_WR; - return SCPE_OK; - - case 015: /* PIRQ */ - ODD_WO (data); - put_PIRQ (data); - return SCPE_OK; - - case 016: /* STKLIM */ - ODD_WO (data); - STKLIM = data & STKLIM_RW; - return SCPE_OK; - } /* end switch pa */ - -return SCPE_NXM; /* unimplemented */ -} - -/* CPU control registers - J11 */ - -t_stat CPUJ_rd (int32 *data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 017) { /* decode pa<4:1> */ - - case 002: /* MEMERR */ - *data = MEMERR; - return SCPE_OK; - - case 003: /* CCR */ - *data = CCR; - return SCPE_OK; - - case 004: /* MAINT */ - *data = MAINT | MAINT_NOFPA | MAINT_BPOK | (UNIBUS? MAINT_U: MAINT_Q); - if (CPUT (CPUT_53)) - *data |= MAINT_KDJD | MAINT_POROM; - if (CPUT (CPUT_73)) - *data |= MAINT_KDJA | MAINT_POODT; - if (CPUT (CPUT_73B|CPUT_83|CPUT_84)) - *data |= MAINT_KDJB | MAINT_POROM; - if (CPUT (CPUT_93|CPUT_94)) - *data |= MAINT_KDJE | MAINT_POROM; - return SCPE_OK; - - case 005: /* Hit/miss */ - if (CPUT (CPUT_73B)) /* must be 0 for 73B */ - *data = 0; - else *data = HITMISS | 010; /* must be nz for 11/8X */ - return SCPE_OK; - - case 013: /* CPUERR */ - *data = CPUERR & CPUE_IMP; - return SCPE_OK; - - case 015: /* PIRQ */ - *data = PIRQ; - return SCPE_OK; - } /* end switch PA */ - -*data = 0; -return SCPE_NXM; /* unimplemented */ -} - -t_stat CPUJ_wr (int32 data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 017) { /* decode pa<4:1> */ - - case 002: /* MEMERR */ - MEMERR = 0; - return SCPE_OK; - - case 003: /* CCR */ - ODD_MRG (CCR, data); - CCR = data; - return SCPE_OK; - - case 004: /* MAINT */ - return SCPE_OK; - - case 005: /* Hit/miss */ - return SCPE_OK; - - case 013: /* CPUERR */ - CPUERR = 0; - return SCPE_OK; - - case 015: /* PIRQ */ - ODD_WO (data); - put_PIRQ (data); - return SCPE_OK; - } /* end switch pa */ - -return SCPE_NXM; /* unimplemented */ -} - -/* Board control registers - KDF11B */ - -t_stat CTLFB_rd (int32 *data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 03) { /* decode pa<2:1> */ - - case 0: /* PCR */ - *data = JPCR & PCRFB_RW; - return SCPE_OK; - - case 1: /* MAINT */ - *data = MAINT; - return SCPE_OK; - - case 2: /* CDR */ - *data = SR & CDRFB_RD; - return SCPE_OK; - } - -*data = 0; -return SCPE_NXM; -} - -t_stat CTLFB_wr (int32 data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 03) { /* decode pa<2:1> */ - - case 0: /* PCR */ - ODD_MRG (JPCR, data); - JPCR = data & PCRFB_RW; - return SCPE_OK; - case 1: /* MAINT */ - ODD_MRG (MAINT, data); - MAINT = data; - return SCPE_OK; - case 2: /* CDR */ - ODD_WO (data); - DR = data & CDRFB_WR; - return SCPE_OK; - } - -return SCPE_NXM; -} - -/* Board control registers - KDJ11B */ - -t_stat CTLJB_rd (int32 *data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 03) { /* decode pa<2:1> */ - - case 0: /* CSR */ - *data = JCSR & CSRJB_RD; - return SCPE_OK; - - case 1: /* PCR */ - *data = JPCR & PCRJB_RW; - return SCPE_OK; - - case 2: /* CDR */ - *data = SR & CDRJB_RD; - return SCPE_OK; - } - -*data = 0; -return SCPE_NXM; -} - -t_stat CTLJB_wr (int32 data, int32 pa, int32 access) -{ -int32 t; - -switch ((pa >> 1) & 03) { /* decode pa<2:1> */ - - case 0: /* CSR */ - ODD_MRG (JCSR, data); - JCSR = (JCSR & ~CSRJB_WR) | (data & CSRJB_WR); - if (JCSR & CSRJ_LTCI) /* force LTC int enb? */ - clk_fie = 1; - else clk_fie = 0; - if (JCSR & CSRJ_LTCD) /* force LTC reg nxm? */ - clk_fnxm = 1; - else clk_fnxm = 0; - t = CSRJ_LTCSEL (JCSR); /* get freq sel */ - if (t) - clk_tps = clk_tps_map[t]; - else clk_tps = clk_default; - return SCPE_OK; - - case 1: /* PCR */ - ODD_MRG (JPCR, data); - JPCR = data & PCRJB_RW; - return SCPE_OK; - - case 2: /* CDR */ - ODD_WO (data); - DR = data & CDRJB_WR; - return SCPE_OK; - } - -return SCPE_NXM; -} - -/* Board control registers - KDJ11D */ - -t_stat CTLJD_rd (int32 *data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 03) { /* decode pa<2:1> */ - - case 0: /* CSR */ - *data = JCSR & CSRJD_RD; - return SCPE_OK; - } - -*data = 0; -return SCPE_NXM; -} - -t_stat CTLJD_wr (int32 data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 03) { /* decode pa<2:1> */ - - case 0: /* CSR */ - ODD_MRG (JCSR, data); - JCSR = (JCSR & ~CSRJD_WR) | (data & CSRJD_WR); - return SCPE_OK; - } - -return SCPE_NXM; -} - -/* Board control registers - KDJ11E */ - -t_stat CTLJE_rd (int32 *data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 03) { /* decode pa<2:1> */ - - case 0: /* CSR */ - *data = JCSR & CSRJE_RD; - return SCPE_OK; - - case 1: /* PCR */ - *data = JPCR & PCRJE_RW; - return SCPE_OK; - - case 2: /* CDR */ - *data = SR & CDRJE_RD; - return SCPE_OK; - - case 3: /* ASR */ - JASR = (JASR & ~ASRJE_TOY) | (toy_read () << ASRJE_V_TOY); - *data = JASR & ASRJE_RW; - return SCPE_OK; - } - -*data = 0; -return SCPE_NXM; -} - -t_stat CTLJE_wr (int32 data, int32 pa, int32 access) -{ -int32 t; - -switch ((pa >> 1) & 03) { /* decode pa<2:1> */ - - case 0: /* CSR */ - ODD_MRG (JCSR, data); - JCSR = (JCSR & ~CSRJE_WR) | (data & CSRJE_WR); - if (JCSR & CSRJ_LTCI) /* force LTC int enb? */ - clk_fie = 1; - else clk_fie = 0; - if (JCSR & CSRJ_LTCD) /* force LTC reg nxm? */ - clk_fnxm = 1; - else clk_fnxm = 0; - t = CSRJ_LTCSEL (JCSR); /* get freq sel */ - if (t) - clk_tps = clk_tps_map[t]; - else clk_tps = clk_default; - return SCPE_OK; - - case 1: /* PCR */ - ODD_MRG (JPCR, data); - JPCR = data & PCRJE_RW; - return SCPE_OK; - - case 2: /* CDR */ - ODD_WO (data); - DR = data & CDRJE_WR; - return SCPE_OK; - - case 3: /* ASR */ - ODD_MRG (JASR, data); - JASR = data & ASRJE_RW; - toy_write (ASRJE_TOYBIT (JASR)); - return SCPE_OK; - } - -return SCPE_NXM; -} - -/* Unibus adapter registers - KT24 */ - -t_stat UBA24_rd (int32 *data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 03) { /* decode pa<2:1> */ - - case 2: /* LMAL */ - *data = uba_last & LMAL_RD; - return SCPE_OK; - case 3: /* LMAH */ - *data = uba_last & LMAH_RD; - return SCPE_OK; - } - -*data = 0; -return SCPE_NXM; -} - -t_stat UBA24_wr (int32 data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 03) { /* decode pa<2:1> */ - - case 3: /* ASR */ - ODD_IGN (data); - uba_last = (uba_last & ~LMAH_WR) | ((data & LMAH_WR) << 16); - return SCPE_OK; - } - -return SCPE_NXM; -} - -/* Unibus registers - KTJ11B */ - -t_stat UBAJ_rd (int32 *data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 03) { /* decode pa<2:1> */ - - case 0: /* DCR */ - *data = UDCR & DCRKTJ_RD; - return SCPE_OK; - - case 1: /* DDR */ - *data = UDDR & DDRKTJ_RW; - return SCPE_OK; - - case 2: /* CSR */ - *data = UCSR & MCRKTJ_RD; - return SCPE_OK; - } - -*data = 0; -return SCPE_NXM; -} - -t_stat UBAJ_wr (int32 data, int32 pa, int32 access) -{ -switch ((pa >> 1) & 03) { /* decode pa<2:1> */ - - case 0: /* DCR */ - ODD_MRG (UDCR, data); - UDCR = (UDCR & ~DCRKTJ_WR) | (data & DCRKTJ_WR); - return SCPE_OK; - - case 1: /* DDR */ - ODD_MRG (UDDR, data); - UDDR = data & DDRKTJ_RW;; - return SCPE_OK; - - case 2: /* CSR */ - ODD_MRG (UCSR, data); - UCSR = (UCSR & ~MCRKTJ_WR) | (data & MCRKTJ_WR); - return SCPE_OK; - } - -return SCPE_NXM; -} - -/* KDJ11E TOY routines */ - -int32 toy_read (void) -{ -time_t curr; -struct tm *ctm; -int32 bit; - -if (toy_state == 0) { - curr = time (NULL); /* get curr time */ - if (curr == (time_t) -1) /* error? */ - return 0; - ctm = localtime (&curr); /* decompose */ - if (ctm == NULL) /* error? */ - return 0; - toy_data[TOY_HSEC] = 0x50; - toy_data[TOY_SEC] = toy_set (ctm->tm_sec); - toy_data[TOY_MIN] = toy_set (ctm->tm_min); - toy_data[TOY_HR] = toy_set (ctm->tm_hour); - toy_data[TOY_DOW] = toy_set (ctm->tm_wday); - toy_data[TOY_DOM] = toy_set (ctm->tm_mday); - toy_data[TOY_MON] = toy_set (ctm->tm_mon + 1); - toy_data[TOY_YR] = toy_set (ctm->tm_year % 100); - } -bit = toy_data[toy_state >> 3] >> (toy_state & 07); -toy_state = (toy_state + 1) % (TOY_LNT * 8); -return (bit & 1); -} - -void toy_write (int32 bit) -{ -toy_state = 0; -return; -} - -uint8 toy_set (int32 val) -{ -uint32 d1, d2; - -d1 = val / 10; -d2 = val % 10; -return (uint8) ((d1 << 4) | d2); -} - -/* Build I/O space entries for CPU */ - -t_stat cpu_build_dib (void) -{ -int32 i; -t_stat r; - -for (i = 0; cnf_tab[i].dib != NULL; i++) { /* loop thru config tab */ - if (((cnf_tab[i].cpum == 0) || (cpu_type & cnf_tab[i].cpum)) && - ((cnf_tab[i].optm == 0) || (cpu_opt & cnf_tab[i].optm))) { - if ((r = build_ubus_tab (&cpu_dev, cnf_tab[i].dib)))/* add to dispatch tab */ - return r; - } - } -return SCPE_OK; -} - -/* Set/show CPU model */ - -t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (cptr != NULL) - return SCPE_ARG; -if (val >= MOD_MAX) - return SCPE_IERR; -if (val == (int32) cpu_model) - return SCPE_OK; -cpu_model = val; -cpu_type = 1u << cpu_model; -cpu_opt = cpu_tab[cpu_model].std; -cpu_set_bus (cpu_opt); -if (MEMSIZE > cpu_tab[val].maxm) - cpu_set_size (uptr, cpu_tab[val].maxm, NULL, NULL); -if (MEMSIZE > cpu_tab[val].maxm) - return SCPE_INCOMP; -reset_all (0); /* reset world */ -return SCPE_OK; -} - -t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -uint32 i, all_opt; - -fprintf (st, "%s", cpu_tab[cpu_model].name); -all_opt = cpu_tab[cpu_model].opt; -for (i = 0; opt_name[2 * i] != NULL; i++) { - if ((all_opt >> i) & 1) - fprintf (st, ", %s", - ((cpu_opt >> i) & 1)? opt_name[2 * i]: opt_name[(2 * i) + 1]); - } -return SCPE_OK; -} - -/* Set/clear CPU option */ - -t_stat cpu_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (cptr) - return SCPE_ARG; -if ((val & cpu_tab[cpu_model].opt) == 0) - return SCPE_ARG; -cpu_opt = cpu_opt | val; -return SCPE_OK; -} - -t_stat cpu_clr_opt (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (cptr) - return SCPE_ARG; -if ((val & cpu_tab[cpu_model].opt) == 0) - return SCPE_ARG; -cpu_opt = cpu_opt & ~val; -return SCPE_OK; -} - -/* Memory allocation */ - -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 mc = 0; -uint32 i, clim; -uint16 *nM; - -if ((val <= 0) || - (val > ((int32) cpu_tab[cpu_model].maxm)) || - ((val & 07777) != 0)) - return SCPE_ARG; -if (val > ((int32) (cpu_tab[cpu_model].maxm - IOPAGESIZE))) - val = (int32) (cpu_tab[cpu_model].maxm - IOPAGESIZE); -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 = (uint16 *) calloc (val >> 1, sizeof (uint16)); -if (nM == NULL) - return SCPE_MEM; -clim = (((t_addr) val) < MEMSIZE)? (uint32)val: MEMSIZE; -for (i = 0; i < clim; i = i + 2) - nM[i >> 1] = M[i >> 1]; -free (M); -M = nM; -MEMSIZE = val; -if (!(sim_switches & SIM_SW_REST)) /* unless restore, */ - cpu_set_bus (cpu_opt); /* alter periph config */ -return SCPE_OK; -} - -/* Bus configuration, disable Unibus or Qbus devices */ - -t_stat cpu_set_bus (int32 opt) -{ -DEVICE *dptr; -uint32 i, mask; - -if (opt & BUS_U) /* Unibus variant? */ - mask = DEV_UBUS; -else if (MEMSIZE <= UNIMEMSIZE) /* 18b Qbus devices? */ - mask = DEV_QBUS | DEV_Q18; -else mask = DEV_QBUS; /* must be 22b */ -for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { - if ((dptr->flags & DEV_DISABLE) && /* disable-able? */ - !(dptr->flags & DEV_DIS) && /* enabled? */ - ((dptr->flags & mask) == 0)) { /* not allowed? */ - sim_printf ("Disabling %s\n", sim_dname (dptr)); - dptr->flags = dptr->flags | DEV_DIS; - } - } -return SCPE_OK; -} - -/* System reset */ - -t_stat sys_reset (DEVICE *dptr) -{ -int32 i; - -CCR = 0; -HITMISS = 0; -CPUERR = 0; -MEMERR = 0; -if (!CPUT (CPUT_J)) - MAINT = 0; -MBRK = 0; -WCS = 0; -if (CPUT (CPUT_JB|CPUT_JE)) - JCSR = JCSR_dflt; -else JCSR = 0; -JPCR = 0; -JASR = 0; -UDCR = 0; -UDDR = 0; -UCSR = 0; -uba_last = 0; -DR = 0; -toy_state = 0; -for (i = 0; i < UBM_LNT_LW; i++) - ub_map[i] = 0; -for (i = 0; i < TOY_LNT; i++) - toy_data[i] = 0; -return SCPE_OK; -} - -/* Set/show JCLK default values */ - -t_stat sys_set_jclk_dflt (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -uint32 i; - -if ((CPUT (CPUT_JB|CPUT_JE)) && cptr) { - for (i = 0; i < 4; i++) { - if (strncmp (cptr, jcsr_val[i], strlen (cptr)) == 0) { - JCSR_dflt = i << CSRJ_V_LTCSEL; - return SCPE_OK; - } - } - } -return SCPE_ARG; -} - -t_stat sys_show_jclk_dflt (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -if (CPUT (CPUT_JB|CPUT_JE)) - fprintf (st, "JCLK default=%s\n", jcsr_val[CSRJ_LTCSEL (JCSR_dflt)]); -else fprintf (st, "Not implemented\n"); -return SCPE_OK; -} diff --git a/PDP11/pdp11_cpumod.h b/PDP11/pdp11_cpumod.h deleted file mode 100644 index e8d8ace2..00000000 --- a/PDP11/pdp11_cpumod.h +++ /dev/null @@ -1,302 +0,0 @@ -/* pdp11_cpumod.h: PDP-11 CPU model definitions - - Copyright (c) 2004-2015, Robert M Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - 30-Dec-15 RMS Added 11/03, 11/23 BEVENT disable - 22-Apr-08 RMS Added 11/70 MBRK register - 30-Aug-05 RMS Added additional 11/60 registers -*/ - -#ifndef PDP11_CPUMOD_H_ -#define PDP11_CPUMOD_H_ 0 - -#define SOP_1103 (BUS_Q|OPT_BVT) -#define OPT_1103 (OPT_EIS|OPT_FIS|OPT_BVT) -#define PSW_1103 0000377 - -#define SOP_1104 (BUS_U) -#define OPT_1104 0 -#define PSW_1104 0000377 - -#define SOP_1105 (BUS_U) -#define OPT_1105 0 -#define PSW_1105 0000377 - -#define SOP_1120 (BUS_U) -#define OPT_1120 0 -#define PSW_1120 0000377 - -#define SOP_1123 (BUS_Q|OPT_EIS|OPT_FPP|OPT_MMU|OPT_BVT) -#define OPT_1123 (OPT_FPP|OPT_CIS|OPT_BVT) -#define PSW_F 0170777 -#define PAR_F 0177777 -#define PDR_F 0077516 -#define MM0_F 0160157 -#define MM3_F 0000060 - -#define SOP_1123P (BUS_Q|OPT_EIS|OPT_FPP|OPT_MMU) -#define OPT_1123P (OPT_FPP|OPT_CIS) - -#define SOP_1124 (BUS_U|OPT_EIS|OPT_FPP|OPT_MMU|OPT_UBM) -#define OPT_1124 (OPT_FPP|OPT_CIS) - -#define SOP_1134 (BUS_U|OPT_EIS|OPT_MMU) -#define OPT_1134 (OPT_FPP) -#define PSW_1134 0170377 -#define PAR_1134 0007777 -#define PDR_1134 0077516 -#define MM0_1134 0160557 - -#define SOP_1140 (BUS_U|OPT_EIS|OPT_MMU) -#define OPT_1140 (OPT_FIS) -#define PSW_1140 0170377 -#define PAR_1140 0007777 -#define PDR_1140 0077516 -#define MM0_1140 0160557 - -#define SOP_1144 (BUS_U|OPT_EIS|OPT_FPP|OPT_MMU|OPT_UBM) -#define OPT_1144 (OPT_FPP|OPT_CIS) -#define PSW_1144 0170777 -#define PAR_1144 0177777 -#define PDR_1144 0177516 -#define MM0_1144 0160557 -#define MM3_1144 0000077 - -#define SOP_1145 (BUS_U|OPT_EIS|OPT_FPP|OPT_MMU|OPT_RH11) -#define OPT_1145 (OPT_FPP) -#define PSW_1145 0174377 -#define PAR_1145 0007777 -#define PDR_1145 0077717 -#define MM0_1145 0171777 -#define MM3_1145 0000007 - -#define SOP_1160 (BUS_U|OPT_EIS|OPT_FPP|OPT_MMU) -#define OPT_1160 0 -#define PSW_1160 0170377 -#define PAR_1160 0007777 -#define PDR_1160 0077516 -#define MM0_1160 0160557 - -#define SOP_1170 (BUS_U|OPT_EIS|OPT_FPP|OPT_MMU|OPT_UBM) -#define OPT_1170 (OPT_FPP|OPT_RH11) -#define PSW_1170 0174377 -#define PAR_1170 0177777 -#define PDR_1170 0077717 -#define MM0_1170 0171777 -#define MM3_1170 0000067 - -#define SOP_1173 (BUS_Q|OPT_EIS|OPT_FPP|OPT_MMU) -#define OPT_1173 (OPT_CIS) -#define PSW_J 0174777 -#define PAR_J 0177777 -#define PDR_J 0177516 -#define MM0_J 0160177 -#define MM3_J 0000077 - -#define SOP_1153 (BUS_Q|OPT_EIS|OPT_FPP|OPT_MMU) -#define OPT_1153 (OPT_CIS) - -#define SOP_1173B (BUS_Q|OPT_EIS|OPT_FPP|OPT_MMU) -#define OPT_1173B (OPT_CIS) - -#define SOP_1183 (BUS_Q|OPT_EIS|OPT_FPP|OPT_MMU) -#define OPT_1183 (OPT_CIS) - -#define SOP_1184 (BUS_U|OPT_EIS|OPT_FPP|OPT_MMU|OPT_UBM|OPT_RH11) -#define OPT_1184 (OPT_CIS) - -#define SOP_1193 (BUS_Q|OPT_EIS|OPT_FPP|OPT_MMU) -#define OPT_1193 (OPT_CIS) - -#define SOP_1194 (BUS_U|OPT_EIS|OPT_FPP|OPT_MMU|OPT_UBM|OPT_RH11) -#define OPT_1194 (OPT_CIS) - -#define MOD_MAX 20 - -/* MFPT codes */ - -#define MFPT_44 1 -#define MFPT_F 3 -#define MFPT_T 4 -#define MFPT_J 5 - -/* KDF11B specific register */ - -#define PCRFB_RW 0037477 /* page ctrl reg */ - -#define CDRFB_RD 0000377 /* config reg */ -#define CDRFB_WR 0000017 - -/* KT24 Unibus map specific registers */ - -#define LMAL_RD 0177777 /* last mapped low */ - -#define LMAH_RD 0000177 /* last mapped high */ -#define LMAH_WR 0000100 - -/* 11/44 specific registers */ - -#define CCR44_RD 0033315 /* cache control */ -#define CCR44_WR 0003315 - -#define CMR44_RD 0177437 /* cache maint */ -#define CMR44_WR 0000037 - -#define CPUE44_BUSE 0004000 - -/* 11/60 specific registers */ - -#define WCS60_RD 0161776 /* WCS control */ -#define WCS60_WR 0061676 - -#define MEME60_RD 0100340 /* memory error */ - -#define CCR60_RD 0000315 /* cache control */ -#define CCR60_WR 0000115 - -#define MBRK60_WR 0007777 /* microbreak */ - -#define CPUE60_RD (CPUE_ODD|CPUE_TMO|CPUE_RED) - -/* 11/70 specific registers */ - -#define MBRK70_WR 0000377 /* microbreak */ - -/* J11 specific registers */ - -/* 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_KDJA (1 << MAINT_V_TYP) /* KDJ11A */ -#define MAINT_KDJB (2 << MAINT_V_TYP) /* KDJ11B */ -#define MAINT_KDJD (4 << MAINT_V_TYP) /* KDJ11D */ -#define MAINT_KDJE (5 << MAINT_V_TYP) /* KDJ11E */ -#define MAINT_V_HTRAP 3 /* trap 4 on HALT */ -#define MAINT_HTRAP (1 << MAINT_V_HTRAP) -#define MAINT_V_POM 1 /* power on option */ -#define MAINT_POODT (0 << MAINT_V_POM) /* power up ODT */ -#define MAINT_POROM (2 << MAINT_V_POM) /* power up ROM */ -#define MAINT_V_BPOK 0 /* power OK */ -#define MAINT_BPOK (1 << MAINT_V_BPOK) - -/* KDJ11B control */ - -#define CSRJB_RD 0177767 -#define CSRJB_WR 0037767 -#define CSRJ_LTCI 0020000 /* force LTC int */ -#define CSRJ_LTCD 0010000 /* disable LTC reg */ -#define CSRJ_V_LTCSEL 10 -#define CSRJ_M_LTCSEL 03 -#define CSRJ_LTCSEL(x) (((x) >> CSRJ_V_LTCSEL) & CSRJ_M_LTCSEL) -#define CSRJ_HBREAK 0001000 /* halt on break */ - -#define PCRJB_RW 0077176 /* page ctrl reg */ - -#define CDRJB_RD 0000377 /* config register */ -#define CDRJB_WR 0000377 - -/* KDJ11D control */ - -#define CSRJD_RD 0157777 /* native register */ -#define CSRJD_WR 0000377 -#define CSRJD_15M 0040000 /* 1.5M mem on board */ - -/* KDJ11E control */ - -#define CSRJE_RD 0137360 /* control reg */ -#define CSRJE_WR 0037370 - -#define PCRJE_RW 0177376 /* page ctrl reg */ - -#define CDRJE_RD 0000377 /* config register */ -#define CDRJE_WR 0000077 - -#define ASRJE_RW 0030462 /* additional status */ -#define ASRJE_V_TOY 8 -#define ASRJE_TOY (1u << ASRJE_V_TOY) /* TOY serial bit */ -#define ASRJE_TOYBIT(x) (((x) >> ASRJE_V_TOY) & 1) - -/* KDJ11E TOY clock */ - -#define TOY_HSEC 0 -#define TOY_SEC 1 -#define TOY_MIN 2 -#define TOY_HR 3 -#define TOY_DOW 4 -#define TOY_DOM 5 -#define TOY_MON 6 -#define TOY_YR 7 -#define TOY_LNT 8 - -/* KTJ11B Unibus map */ - -#define DCRKTJ_RD 0100616 /* diag control */ -#define DCRKTJ_WR 0000416 - -#define DDRKTJ_RW 0177777 /* diag data */ - -#define MCRKTJ_RD 0000377 /* control register */ -#define MCRKTJ_WR 0000177 - -/* Data tables */ - -struct cpu_table { - char *name; /* model name */ - uint32 std; /* standard flags */ - uint32 opt; /* set/clear flags */ - uint32 maxm; /* max memory */ - uint32 psw; /* PSW mask */ - uint32 mfpt; /* MFPT code */ - uint32 par; /* PAR mask */ - uint32 pdr; /* PDR mask */ - uint32 mm0; /* MMR0 mask */ - uint32 mm3; /* MMR3 mask */ - }; - -typedef struct cpu_table CPUTAB; - -struct conf_table { - uint32 cpum; - uint32 optm; - DIB *dib; - }; - -typedef struct conf_table CNFTAB; - -/* Prototypes */ - -t_stat cpu_set_model (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_show_model (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat cpu_set_opt (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_clr_opt (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_bus (int32 opt); - -#endif diff --git a/PDP11/pdp11_cr.c b/PDP11/pdp11_cr.c deleted file mode 100644 index 04fff9fe..00000000 --- a/PDP11/pdp11_cr.c +++ /dev/null @@ -1,1801 +0,0 @@ -/* pdp11_cr.c: CR/CM/CD-11/CD20 card reader simulator - - Copyright (c) 2005-2017, John A. Dundas III - Portions derived from work by Douglas W. Jones, jones@cs.uiowa.edu - Portions derived from work by Robert M Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of the Author shall - not be used in advertising or otherwise to promote the sale, use - or other dealings in this Software without prior written - authorization from the Author. - - ------------------------------------------------------------------------------ - - cr CR11/CD11/CD20 punched and mark sense card reader for SIMH - The CR11 controller is also compatible with the CM11-F, CME11, and CMS11. - - Information necessary to create this simulation was gathered from - a number of sources including: - - CR11 Card Reader System Manual, DEC-11-HCRB-D - http://www.bitsavers.org/pdf/dec/unibus/DEC-11-HCRB-D_CR11_Mar72.pdf - Various editions of the Peripherals Handbook - OpenVMS VAX Card Reader, Line Printer, and LPA11-K I/O User's - Reference Manual, AA-PVXGA-TE - http://h71000.www7.hp.com/DOC/73final/documentation/pdf/OVMS_VAX_CARD_LP_REF.pdf - OpenVMS System Manager's Manual, Volume 1: Essentials - http://h71000.www7.hp.com/DOC/732FINAL/aa-pv5mh-tk/aa-pv5mh-tk.PDF - CRDRIVER.LIS - CR11 Card Reader Driver, X-9, graciously made available - by HP - Various RSTS manuals - RT-11 Software Support Manual - RT-11 System Reference Manual, DEC-11-ORUGA-C-D - Professor Douglas W. Jones's web site: - http://www.cs.uiowa.edu/~jones/cards/ - Paul Mattes' x026 keypunch simulator - http://x3270.bgp.nu/x026.html - CD2SER.MAC - TOPS-10 card reader driver source - http://pdp-10.trailing-edge.com/custsupcuspmar86_bb-x130b-sb/02/cd2ser.mac - CDRIVE.MAC - TOPS GALAXY card reader spooler - http://pdp-10.trailing-edge.com/BB-BT99U-BB_1990/03/10,7/galaxy/cdrive/cdrive.mac - SPRINT.MAC - TOPS GALAXY control card interpreter - http://pdp-10.trailing-edge.com/BB-H138C-BM/01/galaxy-sources/sprint.mac - CDKSDV.MAC - TOPS-20 card reader driver source - http://pdp-10.trailing-edge.com/BB-Y393K-SM/01/monitor-sources/cdksdv.mac - PROKS.MAC - TOPS-20 bit definitions - http://pdp-10.trailing-edge.com/BB-Y393K-SM/01/monitor-sources/proks.mac - - The Card Image format code and documentation is adapted from Prof. - Jones's site, with his permission. Please see his site for additional - documentation as well as the card image utilities referenced in - his documentation (cardmake, cardlist, etc.). - http://www.cs.uiowa.edu/~jones/cards/format.html - - Known limitations: - 1. Need a copy of the CR bootstrap (and some way to test it) - 2. Need a copy of the XXDP+ test deck - 3. No testing under RSX; volunteers needed - 4. No testing under Ultrix or Unix for PDP-11; volunteers needed - 5. No testing under Ultrix or Unix for VAX; volunteers needed - 6. The simulator implements a single controller/reader combination - - Operating System Notes - - RT-11 (and CTS-300) support one CR11 or CM11, but no CD11. - - VMS supports multiple CR11 controllers, but no CD11. - - RSTS/E supports either the CR11/CM11 or CD11 but not both in - the same SIL. It appears to support only one unit. - - For RSX there exists a CR/CM task handler. Is there a CD - handler? - - To-do (RSX): The CR11 unit works as a regular device (ie, - you can PIP from it) but it does not work well as a job - input device (it works just once, somwhow the CRP processor - gets stuck). - - Don't have any information about Unix or Ultrix-11 yet. Same - for VAX Unices. - - TOPS: only the CD20 variant of the CD11 is supported. CD20 implies - ECOs (at least) for Data Buffer status and augmented image mode. - - Revision History: - 19-Jan-17 RMS CR11 is BR6, CD11 is BR4 - 14-Mar-16 RMS Added UC15 support (CR11 only) - 30-Mar-15 RMS Backported from GitHub master; removed extended - help and Qbus support - 23-Feb-13 JGP Added DEC version of the 026 codepage - Fixed the handling of the CR11 error bits after - a control register write. - Added logic reset after RESET button press - Commented and reestructured code (to supress - dangling elses) - 03-Jan-10 JAD Eliminate gcc warnings - 01-Feb-07 RMS Added PDP-10 support - 12-May-06 JAD Modify the DEBUG code to use the SIMH DEBUG_x - macros. Modify the UNIT structure to include - the DEBUG bit. - Mark the trans[] array contents constant. - Make device data structures static and constant - as appropriate. - 18-Mar-05 JAD Slight optimization for blank punches recognizing - that blank is 0 in all character encodings. - 17-Mar-05 JAD Completely initialize ascii_code correctly. - Define the end of deck punch code separately from - the cardcode.i file. - Make initTranslation() set a pointer to the correct - punch code table to use. Modify card read functions - to use this table pointer. - 16-Mar-05 JAD Make certain switches passed to the ATTACH command - are valid; return error on any others. - Make default unit wait time compatible with default - device specification. - Implement SET TRANSLATION=value. Still need to - modify the H2ASCII table used for text files; - currently hard-coded to 029. - 24-Feb-05 JAD Allow the maintenance bits in CRM to clear as - well as set status bits. Not sure this is the - correct behavior, though, without more documentation. - Catch three more places to spin down the blower - correctly. - Zero the CDDB and CRM at INIT. - 17-Feb-05 JAD When the hopper empties, a pick check should - be generated 300ms later. They are simultaneous - for now. - Make sure readColumnBinary() generates a complete - EOF card. - 08-Feb-05 JAD Replace blowerWait with different times for blower - spin up and down. - 06-Feb-05 JAD After DETACH: mark CD offline, set appropriate - blower state. - Make sure unit wait time is recalculated every - time cpm is set. - 04-Feb-05 JAD Better tracking of blower state throughout driver. - Make sure IE gets cleared for CR at INIT. - Normalize error response in read routines. - Finish condition handling for column binary. - 02-Feb-05 JAD Remove Qbus support; Unibus only. - Support ATTACH switches: - A - ASCII, B - column binary, I - Card Image - If none given, check for .TXT or .CBN; if none, - examine file for magic header. - Finer granularity to blower state. Expose this - variable to examine/deposit from SIMH. - Preliminary implementation of support for - column binary format. - 24-Jan-05 JAD Make AUTOEOF work as a surrogate for the EOF - button of a CD11 reader. May need to separate - this later, though. - Partial implementation of DATAERR for CD11. - Implement the Rev. J mods (as best I understand - them) to the CD11 affecting the CDDB used as a - second status register. - 23-Jan-05 JAD Preliminary clean-up of CD state transitions. - Tested with RSTS/E (V9.1-05). - 22-Jan-05 JAD Finish CR state transitions; should be close now. - Tested with RSTS/E (V9.1-05), RT-11 (V5.3), and - VAX/VMS (V7.2). - 19-Jan-05 JAD Add bounds to the RATE command; also default and - help a la the XQ driver. - Improved handling of empty files. - 17-Jan-05 JAD Add the CR maintenance register. - 16-Jan-05 JAD Add preliminary CD11 support. - Simulate the STOP and RESET switches. - 14-Jan-05 JAD Add the ability to automatically generate an 'EOF' - card recognized by DEC operating systems when - reading ASCII files. - 08-Jan-05 JAD Original creation and testing -*/ - -/* Configuration notes: - * Keep VM_arch symbols here and use them only to select features. - * CR attributes use generic symbols so device support is easy to change, - * e.g. if software is discovered that uses a previously unsupported option. - * Conventions: - * *_ONLY (AND *_req) means feature * is unconditionally present/required. - * *_OK means feature * is selectable at runtime. - * neither means feature is not present. - * To support only one controller model, define _ONLY. - * To support more than one, define them all as _OK. - * Don't mix "_ONLY" and "_OK" for the same feature. You won't like it. - * - * The CD/CR will work on any UNIBUS, and the CR will also work on a QBUS. - * The configuration options used here are more restrictive to reflect - * known software support, as this reduces user configuration errors/confusion. - */ - - -#if defined (VM_PDP10) /* PDP10 version */ -#include "pdp10_defs.h" -extern int32 int_req; -#define IPL_CD (IPL_CR) /* use same for CD */ -#define INT_V_CD (INT_V_CR) -#define INT_CD (INT_CR) -#define DFLT_QB (0) -#define DFLT_TYPE (UNIT_CD20) /* CD20 (CD11) only */ -#define DFLT_IVCL (IVCL(CD)) -#define DFLT_CPM 1200 -#define CD20_ONLY (1) -#define AIECO_REQ (1) /* Requires Augmented Image ECO */ -#elif defined (VM_VAX) /* VAX version */ -#include "vax_defs.h" -extern int32 int_req[IPL_HLVL]; -#define IPL_CD (IPL_CR) /* use same for CD */ -#define INT_V_CD (INT_V_CR) -#define INT_CD (INT_CR) -#define DFLT_QB (DEV_QBUS) /* CR11 is programmed I/O only, Qbus OK */ -#define DFLT_TYPE (UNIT_CR11) /* CR11 only */ -#define DFLT_IVCL (IVCL(CR)) -#define DFLT_CPM 285 -#define CR11_ONLY (1) -#else /* PDP-11 version */ -#include "pdp11_defs.h" -extern int32 int_req[IPL_HLVL]; -#define DFLT_QB (DEV_QBUS) /* CR11 is programmed I/O only, Qbus OK */ -#define DFLT_TYPE (UNIT_CR11) /* Default, but changable */ -#define DFLT_IVCL (IVCL(CR)) -#define DFLT_CPM 285 -#if defined (UC15) -#define CR11_ONLY (1) -#else -#define CR11_OK (1) /* only on real PDP-11 */ -#define CD11_OK (1) -#define CD20_OK (1) -#define AIECO_OK (1) /* Augmented Image ECO optional */ -#endif -#endif - -/* **** No VM_xxx macros should be referenced after this line **** */ - -/* create a int32 constant from four characters */ -#define I4C(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) -#define I4C_CBN I4C ('C','B','N',' ') -#define I4C_H80 I4C ('H','8','0',' ') -#define I4C_H82 I4C ('H','8','2',' ') -#define I4C_H40 I4C ('H','4','0',' ') - -#define UNIT_V_TYPE (UNIT_V_UF + 0) /* Bit-encoded 2-bit field */ -#define UNIT_TYPE (3u << UNIT_V_TYPE) -#define UNIT_CR11 (1u << UNIT_V_TYPE) -#define UNIT_CD20 (2u << UNIT_V_TYPE) - -#define UNIT_V_AUTOEOF (UNIT_V_UF + 2) -#define UNIT_AUTOEOF (1u << UNIT_V_AUTOEOF) -#define UNIT_V_RDCHECK (UNIT_V_UF + 3) -#define UNIT_RDCHECK (1u << UNIT_V_RDCHECK) -#define UNIT_V_AIECO (UNIT_V_UF + 4) -#define UNIT_AIECO (1u << UNIT_V_AIECO) - -/* Tests for which device is being emulated. - * Note that CD20 is a CD11 + mandatory ECOs. CD11_CTL will be true for both. - */ -#if defined (CD11_ONLY) || defined (CD20_ONLY) -#define CR11_CTL(up) (0) -#define CD11_CTL(up) (1) -#elif defined (CR11_ONLY) -#define CR11_CTL(up) (1) -#define CD11_CTL(up) (0) -#else -#define CR11_CTL(up) ((up)->flags & UNIT_CR11) -#define CD11_CTL(up) (!CR11_CTL(up)) -#endif - -#if defined (CD20_ONLY) -#define CD20_CTL(up) (1) -#elif defined (CD20_OK) -#define CD20_CTL(up) ((up)->flags & UNIT_CD20) -#else -#define CD20_CTL(up) (0) -#endif - -/* Configuration */ -#if defined (AIECO_REQ) -#define DFLT_AIECO (UNIT_AIECO) -#else -#define DFLT_AIECO (0) -#endif - -#include -#define CR_ER (00404) -#include "pdp11_cr_dat.h" -#define PUNCH_EOD (07417) -#define PUNCH_SPACE (0) /* same for all encodings */ - -/* CR */ -/* also use CSR_ERR, CSR_IE, and CSR_GO */ -#define CRCSR_V_CRDDONE 14 /* card done */ -#define CRCSR_V_SUPPLY 13 /* supply error */ -#define CRCSR_V_RDCHK 12 /* reader check */ -#define CRCSR_V_TIMERR 11 /* timing error */ -#define CRCSR_V_ONLINE 10 /* on line */ -#define CRCSR_V_BUSY 9 /* busy reading */ -#define CRCSR_V_OFFLINE 8 /* off line AKA READY? */ -#define CRCSR_V_COLRDY 7 /* column ready */ -#define CRCSR_V_EJECT 1 /* ignore card */ - -#define CRCSR_CRDDONE (1u << CRCSR_V_CRDDONE) -#define CRCSR_SUPPLY (1u << CRCSR_V_SUPPLY) -#define CRCSR_RDCHK (1u << CRCSR_V_RDCHK) -#define CRCSR_TIMERR (1u << CRCSR_V_TIMERR) -#define CRCSR_ONLINE (1u << CRCSR_V_ONLINE) -#define CRCSR_BUSY (1u << CRCSR_V_BUSY) -#define CRCSR_OFFLINE (1u << CRCSR_V_OFFLINE) -#define CRCSR_COLRDY (1u << CRCSR_V_COLRDY) -#define CRCSR_EJECT (1u << CRCSR_V_EJECT) - -#define CRCSR_IMP (CSR_ERR | CRCSR_CRDDONE | CRCSR_SUPPLY | \ - CRCSR_RDCHK | CRCSR_TIMERR | CRCSR_ONLINE | \ - CRCSR_BUSY | CRCSR_OFFLINE | CRCSR_COLRDY | \ - CSR_IE | CRCSR_EJECT) -#define CRCSR_RW (CSR_IE | CRCSR_EJECT | CSR_GO) /* read/write */ - -#define CRM_V_MAINT 15 /* enable maint funct */ -#define CRM_V_BUSY 14 -#define CRM_V_READY 13 -#define CRM_V_HOPPER 12 - -#define CRM_MAINT (1u << CRM_V_MAINT) -#define CRM_BUSY (1u << CRM_V_BUSY) -#define CRM_READY (1u << CRM_V_READY) -#define CRM_HOPPER (1u << CRM_V_HOPPER) - -/* CD */ -/* also use CSR_ERR, CSR_IE, and CSR_GO */ -/* ERR */ -#define CDCSR_V_RDRCHK 14 /* reader check: HOPPER,STACK,PICK,READ */ -#define CDCSR_V_EOF 13 /* CD11-E EOF button */ -#define CDCSR_V_OFFLINE 12 /* off line */ -#define CDCSR_V_DATAERR 11 /* data packing error */ -#define CDCSR_V_LATE 10 /* data late */ -#define CDCSR_V_NXM 9 /* non-existent memory */ -#define CDCSR_V_PWRCLR 8 /* power clear */ -#define CDCSR_V_RDY 7 /* ready */ -/* IE */ -#define CDCSR_V_XBA17 5 /* NPR bus address bits<17:16> */ -#define CDCSR_V_XBA16 4 -#define CDCSR_V_ONLINE 3 /* on line transition */ -#define CDCSR_V_HOPPER 2 /* hopper check */ -#define CDCSR_V_PACK 1 /* data packing */ -/* GO */ - -#define CDCSR_RDRCHK (1u << CDCSR_V_RDRCHK) -#define CDCSR_EOF (1u << CDCSR_V_EOF) -#define CDCSR_OFFLINE (1u << CDCSR_V_OFFLINE) -#define CDCSR_DATAERR (1u << CDCSR_V_DATAERR) -#define CDCSR_LATE (1u << CDCSR_V_LATE) -#define CDCSR_NXM (1u << CDCSR_V_NXM) -#define CDCSR_PWRCLR (1u << CDCSR_V_PWRCLR) -#define CDCSR_RDY (1u << CDCSR_V_RDY) -#define CDCSR_XBA17 (1u << CDCSR_V_XBA17) -#define CDCSR_XBA16 (1u << CDCSR_V_XBA16) -#define CDCSR_ONLINE (1u << CDCSR_V_ONLINE) -#define CDCSR_HOPPER (1u << CDCSR_V_HOPPER) -#define CDCSR_PACK (1u << CDCSR_V_PACK) - -#define CDCSR_ANYERR (CDCSR_RDRCHK | CDCSR_EOF | CDCSR_OFFLINE | CDCSR_DATAERR | CDCSR_LATE | CDCSR_NXM) - -#define CDCSR_IMP (CSR_ERR | CDCSR_RDRCHK | CDCSR_EOF | CDCSR_OFFLINE | \ - CDCSR_DATAERR | CDCSR_LATE | CDCSR_NXM | \ - CDCSR_PWRCLR | CDCSR_RDY | CSR_IE | \ - CDCSR_XBA17 | CDCSR_XBA16 | CDCSR_ONLINE | \ - CDCSR_HOPPER | CDCSR_PACK | CSR_GO) - -#define CDCSR_RW (CDCSR_PWRCLR | CSR_IE | CDCSR_XBA17 | CDCSR_XBA16 | \ - CDCSR_PACK | CSR_GO) - -/* CD11 second status register bits. Valid only when not busy. All - * also set CDCSR_RDRCK (and CSR_ERR) - */ - -#define CDDB_V_READ 14 /* Read check (extra punches, not readER check) */ -#define CDDB_V_PICK 13 /* Pick check (card present, not grabbed) */ -#define CDDB_V_STACK 12 /* Card did not arrive in stacker */ - -/* N.B. Per TOPS-20 driver, which references CD11 manual and printset: - * Stacker full is indicated by: - * CDCSR_RDRCHK && !(CDDB_READ|CDDB_PICK|CDDB_STACK) - */ -#define CDDB_READ (1U << CDDB_V_READ) -#define CDDB_PICK (1u << CDDB_V_PICK) -#define CDDB_STACK (1u << CDDB_V_STACK) - - -/* Blower state values */ -#define BLOW_OFF (0) /* steady state off */ -#define BLOW_START (1) /* starting up */ -#define BLOW_ON (2) /* steady state on */ -#define BLOW_STOP (3) /* shutting down */ - -/* Card Reader state */ -static const char *cardFormat = "unknown"; -static t_bool (*readRtn)(UNIT *, int16 *, char *, char *); -static char ascii_code[4096]; /* 2^12 possible values */ -static int currCol; /* current column when reading */ -static int colStart; /* starting column */ -static int colEnd; /* ending column */ -static const int *codeTbl = /* punch translation table */ -#if defined(CD20_ONLY) || (defined(DFLT_TYPE) && (DFLT_TYPE == UNIT_CD20)) - o29_decascii_code; -#else - o29_code; -#endif -static struct trans { - const char *const name; - const int *table; -} transcodes[] = { - { "DEFAULT", o29_code, }, - { "026", o26_dec_code, }, - { "026FTN", o26_ftn_code, }, - { "026DECASCII", o26_decascii_code, }, - { "029", o29_code, }, - { "EBCDIC", EBCDIC_code, }, - { "026DEC", o26_dec_code, }, - { "029DECASCII", o29_decascii_code }, -}; -#define NTRANS (sizeof transcodes /sizeof transcodes[0]) - -static int32 blowerState = BLOW_OFF; /* reader vacuum/blower motor */ -static int32 spinUp = 3000000; /* blower spin-up time: 3 seconds (usec) */ -static int32 spinDown = 2000000; /* blower spin-down time: 2 seconds (usec) */ -static int EOFcard = 0; /* played special card yet? */ -static t_bool eofPending = FALSE; /* Manual EOF switch pressed */ -static int32 cpm = DFLT_CPM; /* reader rate: cards per minute */ -static int schedule_svc=0; /* Re-schedule service if true */ -/* card image in various formats */ -static int16 hcard[82]; /* Hollerith format */ -static char ccard[82]; /* DEC compressed format */ -static char acard[82]; /* ASCII format */ -/* CR/CM registers */ -static int32 crs = CSR_ERR | CRCSR_OFFLINE | CRCSR_SUPPLY; /* control/status */ -static int32 crb1 = 0; /* 12-bit Hollerith characters */ -static int32 crb2 = 0; /* 8-bit compressed characters */ -static int32 crm = 0; /* CMS maintenance register */ -/* CD registers */ -static int32 cdst = CSR_ERR | CDCSR_OFFLINE | CDCSR_HOPPER; /* Control/status - off-line until attached */ -static int32 cdcc = 0; /* column count */ -static int32 cdba = 0; /* current address, low 16 bits */ -static int32 cddb = 0; /* data, 2nd status */ -static int32 cddbs = 0; /* second status bits (or with cddb) */ - -/* forward references */ -static void setupCardFile (UNIT *, int32); -t_stat cr_rd (int32 *, int32, int32); -t_stat cr_wr (int32, int32, int32); -int32 cr_intac(void); -t_stat cr_svc (UNIT *); -t_stat cr_reset (DEVICE *); -t_stat cr_attach (UNIT *, char *); -t_stat cr_detach (UNIT *); -t_stat cr_set_type (UNIT *, int32, char *, void *); -t_stat cr_set_aieco (UNIT *, int32, char *, void *); -t_stat cr_show_format (FILE *, UNIT *, int32, void *); -t_stat cr_set_rate (UNIT *, int32, char *, void *); -t_stat cr_show_rate (FILE *, UNIT *, int32, void *); -t_stat cr_set_reset (UNIT *, int32, char *, void *); -t_stat cr_set_stop (UNIT *, int32, char *, void *); -t_stat cr_set_eof (UNIT *, int32, char *, void *); -t_stat cr_show_eof (FILE *, UNIT *, int32, void *); -t_stat cr_set_trans (UNIT *, int32, char*, void *); -t_stat cr_show_trans (FILE *, UNIT *, int32, void *); -static t_stat cr_help (FILE *st, DEVICE *dptr, UNIT *uptr, int32 flag, const char *cptr); -const char *cr_description (DEVICE *dptr); -void cr_set_int (void); -void cr_clr_int (void); - -/* CR data structures - - cr_dib CR device information block - cr_unit CR unit descriptor - cr_reg CR register list - cr_mod CR modifier table - cr_dev CR device descriptor -*/ - -static DIB cr_dib = { IOBA_CR, IOLN_CR, &cr_rd, &cr_wr, - 1, DFLT_IVCL, VEC_CR, { cr_intac } }; - -static UNIT cr_unit = { - UDATA (&cr_svc, - UNIT_ATTABLE+UNIT_SEQ+UNIT_ROABLE+UNIT_DISABLE+ - DFLT_TYPE+UNIT_AUTOEOF+UNIT_RDCHECK+DFLT_AIECO, 0), - (60 * 1000000) / (DFLT_CPM * 80) }; - -static REG cr_reg[] = { - { GRDATA (BUF, cr_unit.buf, DEV_RDX, 8, 0) }, -#if defined (CR11_OK) || defined (CR11_ONLY) - { GRDATA (CRS, crs, DEV_RDX, 16, 0) }, - { GRDATA (CRB1, crb1, DEV_RDX, 16, 0) }, - { GRDATA (CRB2, crb2, DEV_RDX, 16, 0) }, - { GRDATA (CRM, crm, DEV_RDX, 16, 0) }, - { FLDATA (INTCR, IREQ (CR), INT_V_CR) }, -#endif -#if defined (CD11_OK) || defined (CD11_ONLY) || defined (CD20_OK) || defined (CD20_ONLY) - { GRDATA (CDST, cdst, DEV_RDX, 16, 0) }, - { GRDATA (CDCC, cdcc, DEV_RDX, 16, 0) }, - { GRDATA (CDBA, cdba, DEV_RDX, 16, 0) }, - { GRDATA (CDDB, cddb, DEV_RDX, 16, 0) }, - { FLDATA (INTCD, IREQ (CD), INT_V_CD) }, -#endif - { GRDATA (BLOWER, blowerState, DEV_RDX, 2, 0) }, - { FLDATA (ERR, crs, CSR_V_ERR) }, - { FLDATA (IE, crs, CSR_V_IE) }, - { DRDATA (POS, cr_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, cr_unit.wait, 24), PV_LEFT }, - { GRDATA (DEVADDR, cr_dib.ba, DEV_RDX, 32, 0), REG_HRO }, - { GRDATA (DEVVEC, cr_dib.vec, DEV_RDX, 16, 0), REG_HRO }, - { GRDATA (DEVVLOC, cr_dib.vloc, DEV_RDX, 16, 0), REG_HRO }, - { NULL } }; - -static char *translation_help = NULL; -static MTAB cr_mod[] = { -#if defined (CR11_OK) - { UNIT_TYPE, UNIT_CR11, "CR11", "CR11", - &cr_set_type, NULL, NULL }, -#endif -#if defined (CD11_OK) - { UNIT_TYPE, 0, "CD11", "CD11", - &cr_set_type, NULL, NULL }, -#endif -#if defined (CD20_OK) - { UNIT_TYPE, UNIT_CD20, "CD20", "CD20", - &cr_set_type, NULL, NULL }, -#endif -#if defined (CR11_ONLY) || defined (CD11_ONLY) || defined (CD20_ONLY) - { UNIT_TYPE, UNIT_CR11, "CR11", NULL, }, - { UNIT_TYPE, 0, "CD11", NULL, }, - { UNIT_TYPE, UNIT_CD20, "CD20", NULL, }, -#endif -#if defined (AIECO_OK) - { (UNIT_TYPE|UNIT_AIECO), (UNIT_CD20|UNIT_AIECO), "augmented image ECO", "AIECO", - &cr_set_aieco, NULL, NULL }, - { (UNIT_TYPE|UNIT_AIECO), (UNIT_CD20|0), "standard", "NOAIECO", - &cr_set_aieco, NULL, NULL }, -#endif - { UNIT_AUTOEOF, UNIT_AUTOEOF, "auto EOF", "AUTOEOF", - NULL, NULL, NULL }, - { UNIT_AUTOEOF, 0, "no auto EOF", "NOAUTOEOF", - NULL, NULL, NULL }, -#if !defined (CR11_ONLY) - { UNIT_RDCHECK, UNIT_RDCHECK, "read check", "RDCHECK", - NULL, NULL, NULL }, - { UNIT_RDCHECK, 0, "no read check", "NORDCHECK", - NULL, NULL, NULL }, -#endif - /* card reader STOP switch */ - { MTAB_XTD|MTAB_VDV, 0, NULL, "STOP", - &cr_set_stop, NULL, NULL }, - /* card reader RESET switch */ - { MTAB_XTD|MTAB_VDV, 0, NULL, "RESET", - &cr_set_reset, NULL, NULL }, -#if !defined (CR11_ONLY) - /* card reader EOF switch */ - { MTAB_XTD|MTAB_VDV, MTAB_XTD|MTAB_VDV, "EOF pending", "EOF", - &cr_set_eof, &cr_show_eof, NULL }, -#endif - { MTAB_XTD|MTAB_VUN, 0, "FORMAT", NULL, - NULL, &cr_show_format, NULL }, - { MTAB_XTD|MTAB_VDV, 006, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", - &set_vec, &show_vec, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "RATE", "RATE={DEFAULT|200..1200}", - &cr_set_rate, &cr_show_rate, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "TRANSLATION", - NULL, - &cr_set_trans, &cr_show_trans, NULL }, - { 0 } }; - -DEVICE cr_dev = { - "CR", &cr_unit, (REG *) &cr_reg, (MTAB *) &cr_mod, - 1, 10, 31, 1, DEV_RDX, 8, - NULL, NULL, &cr_reset, - NULL, &cr_attach, &cr_detach, - &cr_dib, DEV_DISABLE | DEV_DIS | DFLT_QB | DEV_UBUS | DEV_DEBUG - }; - -/* Utility routines */ - -/* -These functions read a "card" from a virtual deck file (passed in -fp) and fill in three arrays. The first array 'hcard' contains the -12-bit binary image of the punch in each column; the second array -'ccard' contains the 8-bit DEC encoded representation of the -corresponding column; the third array 'acard' contains the ASCII -representation (if possible) of the character. The routines return -TRUE if a card was read (possibly with errors) and FALSE if the -"hopper is empty" (EOF) or fatal file errors prevented any portion -of a card from being read. - -Note that the hopper becomes empty when the last card moves to the -read station. Thus hopper empty without an error means that data -from that card is valid. Thus hopper empty is first signalled when -the NEXT card read would return EOF. Reads after that will return -some error bit. - -Errors other than EOF are signaled out of band in the controller -state variables. Possible errors are data in columns 0 or 81 -(signalled as read check; currently these columns are ignored), or -any file errors (signalled as motion check). - -Might rethink this. Should probably treat file errors as "pick -check". Retry 3 times. After that, give up with error. - -*/ - -/* Common handling for end of file and errors on input */ - -static t_bool fileEOF ( UNIT *uptr, - int16 *hcard, - char *ccard, - char *acard, - int32 cddbsBits ) -{ - int col; - - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "hopper empty-eof\n"); - - if (!EOFcard && (uptr->flags & UNIT_AUTOEOF) && !ferror(uptr->fileref)) { - EOFcard = -1; - /* Generate EOD card, which empties the hopper */ - for (col = 1; col <= 8; col++) { - hcard[col] = PUNCH_EOD; - ccard[col] = (char)h2c_code[PUNCH_EOD]; - acard[col] = ' '; - } - while (col <= colEnd) { - hcard[col] = PUNCH_SPACE; - ccard[col] = PUNCH_SPACE; - acard[col] = ' '; - col++; - } - /* The CR11 doesn't set SUPPPLY at this time, but waits until the EOF card is done. */ - cdst |= CDCSR_HOPPER; - return (TRUE); - } - - /* Not auto EOF, or EOF already handled. This is an attempt to read - * with an empty hopper. Report a pick, read or stacker check as well - * as hopper empty to indicate that no data was transfered. One might - * think that cdcc unchanged would be sufficient, but that's not what - * the OSs check. - */ - - crs |= CSR_ERR | CRCSR_SUPPLY | CRCSR_OFFLINE; - crs &= ~(CRCSR_COLRDY | CRCSR_ONLINE); - - cdst |= CSR_ERR | CDCSR_RDRCHK | CDCSR_HOPPER; - cddbs |= cddbsBits; - - if (((uptr->flags & UNIT_AUTOEOF) || eofPending) && !ferror(uptr->fileref)) { - cdst |= CDCSR_EOF; - eofPending = FALSE; - } - return (FALSE); -} - -static t_bool readCardImage ( UNIT *uptr, - int16 *hcard, - char *ccard, - char *acard ) -{ - int c1, c2, c3, col; - FILE *fp = uptr->fileref; - - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "readCardImage pos %d\n", (int) ftell (fp)); - do { - /* get card header bytes */ - c1 = fgetc (fp); - c2 = fgetc (fp); - c3 = fgetc (fp); - uptr->pos = ftell (fp); - /* check for EOF */ - if (c1 == EOF) - return fileEOF (uptr, hcard, ccard, acard, CDDB_PICK); - - /* check for valid card header */ - if ((c2 == EOF) || (c3 == EOF) || ((c1 & c2 & c3 & 0x80) == 0) ) { - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "header error\n"); - /* unexpected EOF or format problems */ - return fileEOF (uptr, hcard, ccard, acard, CDDB_READ); - } - - /* Read card image into internal buffer */ - - assert (colStart < colEnd); - assert (colStart >= 0); - assert (colEnd <= 81); - for (col = colStart; col < colEnd; ) { - int16 i; - int c1, c2, c3; - /* get 3 bytes */ - c1 = fgetc (fp); - c2 = fgetc (fp); - c3 = fgetc (fp); - uptr->pos = ftell (fp); - if (ferror (fp) || (c1 == EOF) || (c2 == EOF) || (c3 == EOF)) { - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "file error\n"); - /* signal error; unexpected EOF, format problems, or file error(s) */ - return fileEOF (uptr, hcard, ccard, acard, ferror(fp)? CDDB_READ: CDDB_PICK); - } - /* convert to 2 columns */ - i = ((c1 << 4) | ( c2 >> 4)) & 0xFFF; - hcard[col] = i; - ccard[col] = (char)h2c_code[i]; - acard[col] = ascii_code[i]; - col++; - - i = (((c2 & 017) << 8) | c3) & 0xFFF; - hcard[col] = i; - ccard[col] = (char)h2c_code[i]; - acard[col] = ascii_code[i]; - col++; - } - } while ((c3 & 0x3f) == 0x3f); /* Skip metacards (Revised Jones spec) */ - - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "successfully loaded card\n"); - return (TRUE); -} - -static t_bool readColumnBinary ( UNIT *uptr, - int16 *hcard, - char *ccard, - char *acard ) -{ - int col; - FILE *fp = uptr->fileref; - - for (col = colStart; col <= colEnd; col++) { - int c1, c2; - uint16 i; - c1 = fgetc (fp); - c2 = fgetc (fp); - uptr->pos = ftell (fp); - if (c1 == EOF) - return fileEOF (uptr, hcard, ccard, acard, CDDB_PICK); - if ((c2 == EOF) || ferror(fp)) - return fileEOF (uptr, hcard, ccard, acard, CDDB_READ); - i = (c1 & 077) | ((c2 & 077) << 6); - hcard[col] = i; - ccard[col] = (char)h2c_code[i]; - acard[col] = ascii_code[i]; - } - return (TRUE); -} - -/* - -Should this routine perform special handling of non-printable, -(e.g., control) characters or characters that have no encoded -representation? (In DEC026/DEC029 they all do...) - -*/ - -static t_bool readCardASCII ( UNIT *uptr, - int16 *hcard, - char *ccard, - char *acard ) -{ - int c = 0, col, peek; - FILE *fp = uptr->fileref; - - assert (colStart < colEnd); - assert (colStart >= 1); - assert (colEnd <= 80); - - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "readCardASCII\n"); - for (col = colStart; col <= colEnd; ) { - switch (c = fgetc (fp)) { - case EOF: - if (ferror (fp)) { - uptr->pos = ftell (fp); - return fileEOF (uptr, hcard, ccard, acard, CDDB_READ); - } - if (col == colStart) { - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "hopper empty\n"); - uptr->pos = ftell (fp); - return fileEOF (uptr, hcard, ccard, acard, CDDB_PICK); - } - /* fall through */ - case '\r': - peek = fgetc (uptr->fileref); - if ((peek != EOF) && (peek != '\n')) - ungetc (peek, uptr->fileref); - goto fill; - case '\n': - peek = fgetc (uptr->fileref); - if ((peek != EOF) && (peek != '\r')) - ungetc (peek, uptr->fileref); - fill: - while (col <= colEnd) { - hcard[col] = PUNCH_SPACE; - ccard[col] = PUNCH_SPACE; - acard[col] = ' '; - col++; - } - break; - case '\t': - do { - hcard[col] = PUNCH_SPACE; - ccard[col] = PUNCH_SPACE; - acard[col] = ' '; - col++; - } while (((col & 07) != 1) && (col <= colEnd)); - break; - default: - hcard[col] = (uint16)codeTbl[c & 0177]; - /* check for unrepresentable ASCII characters */ - if (hcard[col] == CR_ER) { - cdst |= CDCSR_DATAERR; - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, - "error character at column %d (%c)\n", - col, c & 0177); - } - ccard[col] = (char)h2c_code[hcard[col]]; - acard[col] = (char)c; - col++; - break; - } - } - /* silently truncate/flush long lines, or flag over-length card? */ - if (c != '\n' && c != '\r') { - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "truncating card\n"); - c = fgetc (fp); - while (c != EOF) { - if ((c == '\n') || (c == '\r')) { - peek = fgetc (uptr->fileref); - if (peek == EOF) - break; - if (((c == '\n') && (peek != '\r')) || ((c == '\r') && (peek != '\n'))) - ungetc (peek, uptr->fileref); - break; - } - c = fgetc (fp); - } - } - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "successfully loaded card\n"); - uptr->pos = ftell (fp); - return (TRUE); -} - -/* - -Initialize the binary translation table. Generally called when a -new deck is attached but could be set manually as well. - -*/ - -static void initTranslation (void) -{ - int32 i; - - memset (ascii_code, '~', sizeof (ascii_code)); - for (i = 0; i < 0177; i++) - ascii_code[codeTbl[i]] = (char)i; -} - -/* - -Examine the command switches, file extension, and virtual card deck -file to determine the format. Set up the global variables -appropriately. Rewind ASCII files to the beginning - -*/ - -static void setupCardFile ( UNIT *uptr, - int32 switches ) -{ - int32 i; - - if (switches & SWMASK ('A')) - i = 0; - else if (switches & SWMASK ('B')) - i = I4C_CBN; - else if (switches & SWMASK ('I')) - goto read_header; - else if (match_ext (uptr->filename, "TXT")) - i = 0; - else if (match_ext (uptr->filename, "CBN")) - i = I4C_CBN; - else { -read_header: - /* look for card image magic file number */ - i = fgetc (uptr->fileref); - i = (i << 8) | fgetc (uptr->fileref); - i = (i << 8) | fgetc (uptr->fileref); - i = (i << 8) | ' '; - } - switch (i) { - case I4C_H80: - colStart = 1; - colEnd = 80; - cardFormat = "card image"; - readRtn = readCardImage; - break; - case I4C_H82: - colStart = 0; - colEnd = 81; - cardFormat = "card image"; - readRtn = readCardImage; - break; - case I4C_H40: - colStart = 1; - colEnd = 40; - cardFormat = "card image"; - readRtn = readCardImage; - break; - case I4C_CBN: - colStart = 1; - colEnd = 80; - cardFormat = "column binary"; - readRtn = readColumnBinary; - break; - default: - colStart = 1; - colEnd = 80; - cardFormat = "ASCII"; - readRtn = readCardASCII; - fseek (uptr->fileref, 0L, SEEK_SET); - break; - } - initTranslation (); - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "colStart = %d, colEnd = %d\n", - colStart, colEnd); - cr_unit.pos = ftell (uptr->fileref); -} - -/* Card reader routines - - cr_rd I/O page read - cr_wr I/O page write - cr_svc process event (reader ready) - cr_reset process reset - cr_attach process attach - cr_detach process detach -*/ - -t_stat cr_rd ( int32 *data, - int32 PA, - int32 access ) -{ - switch ((PA >> 1) & 03) { - case 0: /* CSR */ - if (cdst & (CDCSR_ANYERR)) - cdst |= CSR_ERR; - else - cdst &= ~CSR_ERR; - *data = (CR11_CTL(&cr_unit)) ? - crs & CRCSR_IMP : cdst & CDCSR_IMP; - /* CR: if error removed, clear 15, 14, 11, 10 */ - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "cr_rd crs %06o cdst %06o\n", - crs, cdst); - break; - case 1: - /* Get word of data from crb1 (Hollerith code) or CD11 CC */ - *data = (CR11_CTL(&cr_unit)) ? crb1 : cdcc; - crs &= ~CRCSR_COLRDY; - if (DEBUG_PRS (cr_dev)) { - if (CR11_CTL(&cr_unit)) - fprintf (sim_deb, "cr_rd crb1 %06o '%c' %d\n", - crb1, cr_unit.buf, cr_unit.buf); - else - fprintf (sim_deb, "cr_rd cdcc %06o\n", cdcc); - } - /* Does crb1 clear after read? Implied by VMS driver. */ - crb1 = 0; - break; - case 2: - /* Get word of data from crb2 (DEC Compressed) or CD11 BA */ - *data = (CR11_CTL(&cr_unit)) ? crb2 : cdba; - crs &= ~CRCSR_COLRDY; - if (DEBUG_PRS (cr_dev)) { - if (CR11_CTL(&cr_unit)) - fprintf (sim_deb, "cr_rd crb2 %06o\n", crb2); - else - fprintf (sim_deb, "\r\ncr_rd cdba %06o\n", cdba); - } - crb2 = 0; /* see note for crb1 */ - break; - case 3: - default: - if (CR11_CTL(&cr_unit)) /* CR11 maintenance */ - *data = crm; - else /* CD11 data buffer/status. Note this implementation returns extended - * status even while busy (rather than the zone). Might be wrong. - */ - *data = 0100000 | (cddbs & (CDDB_READ|CDDB_PICK|CDDB_STACK)) | - ((crs & CRCSR_BUSY) ? - cddb & 0777 : 0777); - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "cr_rd crm %06o cddb %06o data %06o\n", - crm, cddb, *data); - break; - } - return (SCPE_OK); -} - -t_stat cr_wr ( int32 data, - int32 PA, - int32 access ) -{ - int curr_crs = crs; /* Save current crs to recover status */ - - switch ((PA >> 1) & 03) { - case 0: - if (CR11_CTL(&cr_unit)) { - /* ignore high-byte writes */ - if (PA & 1) - break; - /* fixup data for low byte write */ - if (access == WRITEB) - data = (crs & ~0377) | (data & 0377); - if (!(data & CSR_IE)) - cr_clr_int (); - crs = (crs & ~CRCSR_RW) | (data & CRCSR_RW); - /* Clear status bits after CSR load */ - crs &= ~(CSR_ERR | CRCSR_ONLINE | CRCSR_CRDDONE | CRCSR_TIMERR); - if (crs & CRCSR_OFFLINE) - crs |= CSR_ERR; - /* - * Read card requested: - * Check if there was any error which required an operator - * intervention, and if so, reassert the corresponding - * error bits and assert interrupt. - * (Expected by the VMS CRDRIVER) - */ - if (data & CSR_GO) { - if (curr_crs & (CRCSR_SUPPLY | CRCSR_RDCHK | CRCSR_OFFLINE)) { - crs |= CSR_ERR | (curr_crs & (CRCSR_SUPPLY | CRCSR_RDCHK | - CRCSR_OFFLINE)); - if (crs & CSR_IE) cr_set_int (); - } - if (blowerState != BLOW_ON) { - blowerState = BLOW_START; - sim_activate (&cr_unit, spinUp); - } else { - sim_activate (&cr_unit, cr_unit.wait); - } - } - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "cr_wr data %06o crs %06o\n", - data, crs); - } else { /* CD11 */ - if (access == WRITEB) - data = (PA & 1)? (((data & 0xff)<<8) | (cdst & 0x00ff)): - ((data & 0x00ff) | (cdst & 0xFF00)); - - if (data & CDCSR_PWRCLR) { - cr_clr_int (); - sim_cancel (&cr_unit); - cdcc = 0; - cdba = 0; - cddb = 0; - cddbs = 0; - if (!(cr_unit.flags & UNIT_ATT)) { /* Clear troublesome bits, but leave error/offline */ - cdst &= ~(CSR_IE | CDCSR_DATAERR | CDCSR_LATE | CDCSR_NXM | CDCSR_RDY | - CDCSR_XBA17 | CDCSR_XBA16 | CDCSR_ONLINE | CDCSR_PACK); - cdst |= CSR_ERR | CDCSR_OFFLINE | CDCSR_RDRCHK; - cddbs |= CDDB_STACK; - break; - } - - crs &= ~CRCSR_BUSY; - cdst &= (CDCSR_OFFLINE | CDCSR_RDY | CDCSR_HOPPER); - if( (cr_unit.flags & UNIT_ATT) && !feof(cr_unit.fileref) && !ferror(cr_unit.fileref) ) - cdst &= ~(CDCSR_HOPPER); - if (cdst & (CDCSR_ANYERR)) - cdst |= CSR_ERR; - cdst |= CDCSR_RDY; - break; - } - - if (data & CSR_GO) { - /* To simplify the service code, don't start if CDCC == 0. - * In the hardware, it's not sensible... - */ - if ((crs & CRCSR_BUSY) || (cdcc == 0)) { - cdst |= (CDCSR_RDRCHK | CDCSR_HOPPER | CSR_ERR); - } else { - cdst &= ~(CDCSR_RDRCHK | CDCSR_DATAERR | CDCSR_LATE | CDCSR_NXM | CDCSR_RDY | CDCSR_ONLINE); - cdst = (cdst & ~(CDCSR_EOF | CSR_IE | CDCSR_XBA17 | CDCSR_XBA16 | CDCSR_PACK | CDCSR_HOPPER)) - | (data & (CDCSR_EOF | CSR_IE | CDCSR_XBA17 | CDCSR_XBA16 | CDCSR_PACK)); - cddbs &= ~(CDDB_READ|CDDB_PICK|CDDB_STACK); - - /* Always attempt to start. If not attached, errors will set after delay */ - if (!(cdst & CDCSR_HOPPER) ) - cdst &= ~(CSR_ERR); - if (blowerState != BLOW_ON) { - blowerState = BLOW_START; - sim_activate (&cr_unit, spinUp); - } else { - sim_activate (&cr_unit, cr_unit.wait); - } - } - } else { - cdst = (cdst & ~(CSR_ERR | CDCSR_RDRCHK | CDCSR_EOF | CDCSR_DATAERR | CDCSR_LATE | - CDCSR_NXM | CSR_IE | CDCSR_XBA17 | CDCSR_XBA16 | CDCSR_ONLINE | CDCSR_PACK)) - |(data & (CSR_ERR | CDCSR_RDRCHK | CDCSR_EOF | CDCSR_DATAERR | CDCSR_LATE | - CDCSR_NXM | CSR_IE | CDCSR_XBA17 | CDCSR_XBA16 | CDCSR_ONLINE | CDCSR_PACK)); - } - /* Apparently the hardware does not set int if ready/online are already set. If it did, TOPS-10's driver wouldn't work */ - if (!(cdst & CSR_IE)) - cr_clr_int (); - - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "cr_wr data %06o cdst %06o\n", - data, cdst); - } - break; - case 1: - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "cr_wr cdcc %06o\n", data); - if (CD11_CTL(&cr_unit)) - cdcc = data & 0177777; - break; - case 2: - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "cr_wr crba %06o\n", data); - if (CD11_CTL(&cr_unit)) - cdba = data & 0177777; - break; - case 3: - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "cr_wr cddb/crm %06o\n", data); - /* ignore writes to cddb */ - if (CD11_CTL(&cr_unit)) - break; - - /* fixup data for byte writes and read-modify-write */ - if (access == WRITEB) - data = (PA & 1) ? - (crm & 0377) | (data << 8) : - (crm & ~0377) | (data & 0377); - crm = data & 0177777; - /* not 100% certain how these work */ - if (!(crm & CRM_MAINT)) - break; - crs = (crm & CRM_BUSY) ? - (crs | CRCSR_BUSY) : (crs & ~CRCSR_BUSY); - crs = (crm & CRM_READY) ? - (crs | CRCSR_OFFLINE) : (crs & ~CRCSR_OFFLINE); - crs = (crm & CRM_HOPPER) ? - (crs | CRCSR_SUPPLY | CRCSR_RDCHK) : - (crs & ~(CRCSR_SUPPLY | CRCSR_RDCHK)); - crb1 = crm & 07777; /* load low 12 bits */ - break; - default: - /* can't happen */ - break; - } - return (SCPE_OK); -} - -/* - * Interrupt acknowledge routine - * Reschedule service routine if needed (based on - * schedule_svc flag). - * Do the actual scheduling just for the CR11 (VAX/PDP11). The PDP10 does - * not seem to call this entry point. - */ - -int32 cr_intac() { - if CR11_CTL(&cr_unit) { - if (schedule_svc) { - sim_activate (&cr_unit, cr_unit.wait); - schedule_svc = 0; - } - } - return cr_dib.vec; /* Constant interrupt vector */ -} - -/* -Enter the service routine once for each column read from the card. -CR state bits drive this primarily (see _BUSY and _CRDDONE). However, -when in CD mode, also execute one column of DMA input. -*/ -t_stat cr_svc ( UNIT *uptr ) -{ - uint32 pa; - uint8 c; - uint16 w; - int n; - - /* Blower stopping: set it to OFF and do nothing */ - if (blowerState == BLOW_STOP) { - blowerState = BLOW_OFF; - return (SCPE_OK); - } - /* Blower starting: set it to ON and do regular service */ - if (blowerState == BLOW_START) - blowerState = BLOW_ON; - - /* (almost) anything we do now will cause a CR (But not a CD) interrupt */ - if ((CR11_CTL(uptr)) && (crs & CSR_IE)) - cr_set_int (); - - /* Unit not attached, or error status while idle */ - if (!(uptr->flags & UNIT_ATT) || (!(crs & CRCSR_BUSY) && ((CR11_CTL(uptr)?crs : cdst) & CSR_ERR))) { - if (CD11_CTL(uptr)) { - if (!(uptr->flags & UNIT_ATT)){ - cdst |= (CDCSR_HOPPER | CDCSR_RDRCHK | CDCSR_OFFLINE | CSR_ERR); - cddbs |= CDDB_STACK; - } - if (cdst & CSR_IE) - cr_set_int (); - } - return (SCPE_OK); - } - - /* End of card: unit busy and column past end column */ - if ((crs & CRCSR_BUSY) && (currCol > colEnd)) { - /* clear busy state and set card done bit */ - crs &= ~(CRCSR_BUSY | CRCSR_COLRDY); - crs |= CRCSR_CRDDONE; - - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "cr_svc card done\n"); - - /* Check CD11 error status that stops transfers */ - if (CD11_CTL(uptr) && (cdst & (CDCSR_LATE | CDCSR_NXM))) { - cdst |= CSR_ERR | CDCSR_OFFLINE | CDCSR_RDY | CDCSR_RDRCHK; - cr_set_int (); - return (SCPE_OK); - } - - if (CR11_CTL(uptr)) - return (SCPE_OK); - - /* If a CD11 gets this far, an interrupt is required. If CDCC != 0, - * continue reading the next card. - */ - cr_set_int (); - if (cdcc == 0) - return (SCPE_OK); - } - - /* If unit is not busy: try to read a card */ - if (!(crs & CRCSR_BUSY)) { - crs &= ~CRCSR_CRDDONE; /* This line WAS commented out - JGP 2013.02.05 */ - - /* Call the appropriate read card routine. - * If no card is read (FALSE return), we tried to read with an empty hopper. - * The card read routine set the appropriate error bits. Shutdown. - */ - if (!readRtn (uptr, hcard, ccard, acard)) { - blowerState = BLOW_STOP; - if (CD11_CTL(uptr)) { -readFault: - cdst |= CDCSR_RDY; - if (cdst & (CDCSR_RDRCHK | CDCSR_HOPPER)) - cdst |= CSR_ERR | CDCSR_OFFLINE; - if (cdst & CSR_IE) - cr_set_int (); - - } else { - /* - * CR11 handling: assert SUPPLY and ERROR bits, - * put de device offline and DO NOT TRIGGER AN INTERRUPT - * (if the interrupt is asserted RSX and VMS will get 80 - * bytes of garbage, and RSX could crash). - */ - if (crs & (CRCSR_RDCHK | CRCSR_SUPPLY)) { - crs |= CSR_ERR | CRCSR_OFFLINE; - crs &= ~(CRCSR_ONLINE | CRCSR_BUSY | CRCSR_CRDDONE); - cr_clr_int (); - } - } - sim_activate (uptr, spinDown); - return (SCPE_OK); - } - - /* Card read: reset column counter and assert BUSY */ - currCol = colStart; - crs |= CRCSR_BUSY; - - /* Update status if this read emptied hopper. - * The CR11 doesn't set SUPPLY until after the last card is read. - */ - - /* I/O error status bits have been set during read. - * Look ahead to see if another card is in file. - */ - n = feof (uptr->fileref); - if (n) - n = EOF; - else { - n = fgetc (uptr->fileref); - if (n != EOF) - ungetc (n, uptr->fileref); - } - - if ((n == EOF) && ((EOFcard > 0) || !(uptr->flags & UNIT_AUTOEOF))) { - /* EOF and generated EOFcard sent or not an autoEOF unit. - * Set status to reflect last card taken. - */ - cdst |= (CDCSR_RDRCHK | CSR_ERR | CDCSR_OFFLINE | CDCSR_HOPPER); - if (eofPending) { - cdst |= CDCSR_EOF; - eofPending = FALSE; - } - } - - if (EOFcard) - EOFcard = 1; - - - if (CD11_CTL(uptr)) { - /* Handle read check: punches in col 0 or 81/last (DEC only did 80 cols, but...) */ - if ((uptr->flags & UNIT_RDCHECK) && - (((colStart == 0) && (hcard[0] != 0)) || ((colEnd & 1) && (hcard[colEnd] != 0)))) { - cdst |= (CDCSR_RDRCHK | CSR_ERR); - cddbs |= CDDB_READ; - if (1) /* 0 if read check should transfer card */ - goto readFault; - } - /* CDDB_PICK, CDDB_STACK, buf = acard[currCol] & 0377; /* Helpful for debug: ASCII value */ - - /* CD11 specific code follows */ - if (CD11_CTL(uptr)) { - pa = cdba | ((cdst & 060) << 12); -/* -The implementation of _NXM here is not quite the same as I interpret -the (limited) documentaiton I have to indicate. However the effect -should be similar. Documentation indicates that once _NXM is set, -further NPR requests are inhibited though the card is allowed to -read until completion. This implies that CDBA and the XBA bits are -incremented accordingly, even though no data transfer occurs. This -code detects and flags the NXM condition but allows attempts at -subsequent memory writes, thus insuring the address registers are -incremented properly. If this causes problems, I'll fix it. -*/ - if (cdst & CDCSR_PACK) - cddb = c = ccard[currCol] & 0377; - else - cddb = w = hcard[currCol] & 07777; /* Punched zones: <12><11><0><1><2><3><4><5><6><7><8><9> */ - - if (cdcc == 0) /* Transfer requires CC non-zero */ - cdst |= CDCSR_LATE; - else { - if (cdst & CDCSR_PACK) { - if (Map_WriteB (pa, 1, &c)) - cdst |= CDCSR_NXM; - pa = (pa + 1) & 0777777; - } else { - /* "Augmented Image" - provides full column binary and packed encoding in 15 bits. - * Bits <14:12> encode which zone, if any, of 1-7 is punched. 0 => none, otherwise zone #. - * Bit 15 set indicates that more than one punch occured in zones 1-7; in this case the packed - * encoding is not valid. (Card may be binary data.) - * This was probably an ECO to the CD11. TOPS-10/20 depend on it, so it's definitely in the CD20. - */ - if (uptr->flags & UNIT_AIECO) { - uint16 z; - w |= ((ccard[currCol] & 07) << 12); /* Encode zones 1..7 - same as 'packed' format */ - z = w & 0774; - if ((z & -z) != z) /* More than one punch in 1..7 */ - w |= 0100000; /* sets Hollerith (encoding) failure (not an error) */ - } - if (Map_WriteW (pa, 2, &w)) - cdst |= CDCSR_NXM; - pa = (pa + 2) & 0777777; - } - cdba = pa & 0177777; - cdst = (cdst & ~(CDCSR_XBA17|CDCSR_XBA16)) | - ((pa & 0600000) >> 12); - cdcc = (cdcc + 1) & 0177777; - /* Interrupt at end of buffer; read continues to end of card. - * If this is the last column, defer interrupt so end doesn't interrupt again. - */ - if ((cdcc == 0) && (cdst & CSR_IE) && (currCol < colEnd)) - cr_set_int (); - } - } else { /* CR11 */ - /* Handle EJECT bit: if set DO NOT assert COLRDY */ - /* nor interrupt */ - if ((crs & CRCSR_EJECT)) { - cr_clr_int (); - } else { - crs |= CRCSR_COLRDY; - } - } - - /* CD11 and CR11 */ - currCol++; /* advance the column counter */ - - /* Schedule next service cycle */ - /* CR11 (VAX/PDP11): just raise the schedule_svc flag; the intack - * routine will do the actual rescheduling. - * CD11/20 (PDP10): Do the rescheduling (the intack seems to do nothing) - */ - if (CD11_CTL(uptr)) { - sim_activate (uptr, uptr->wait); - } else { - schedule_svc = 1; - } - return (SCPE_OK); -} - -t_stat cr_reset ( DEVICE *dptr ) -{ - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "cr_reset\n"); - - if (!translation_help) { - size_t i; - const char trans_hlp[] = "TRANSLATION={"; - size_t size = sizeof(trans_hlp) +1; - - for ( i = 0; i < NTRANS; i++ ) - size += strlen (transcodes[i].name)+1; - translation_help = (char *)malloc (size ); - strcpy(translation_help, trans_hlp); - for (i = 0; i < NTRANS; i++) { - strcat(translation_help, transcodes[i].name); - strcat(translation_help,"|"); - } - strcpy(translation_help+strlen(translation_help)-1, "}"); - for (i = 0; i < (sizeof cr_mod / sizeof cr_mod[0]); i++ ) - if (cr_mod[i].pstring && !strcmp(cr_mod[i].pstring, "TRANSLATION")) { - cr_mod[i].mstring = translation_help; - break; - } - } - cr_unit.buf = 0; - currCol = 1; - crs &= ~(CSR_ERR|CRCSR_CRDDONE|CRCSR_TIMERR|CRCSR_ONLINE|CRCSR_BUSY| - CRCSR_COLRDY|CSR_IE|CRCSR_EJECT|CSR_GO); - if (crs & (CRCSR_OFFLINE)) - crs |= CSR_ERR; - crb1 = 0; - crb2 = 0; - crm = 0; - cdst &= ~(CSR_ERR|CDCSR_RDRCHK|CDCSR_EOF|CDCSR_DATAERR|CDCSR_LATE| - CDCSR_NXM|CSR_IE|CDCSR_XBA17|CDCSR_XBA16|CDCSR_ONLINE| - CDCSR_PACK|CSR_GO); - cdst |= CDCSR_RDY; - if (cdst & CDCSR_ANYERR) - cdst |= CSR_ERR; - cdcc = 0; - cdba = 0; - cddb = 0; - /* ATTACHed doesn't mean ONLINE; set CR reset (pushing the reset switch) - * is what puts the reader on-line. Reset doesn't control fingers. - */ - if ((cr_unit.flags & UNIT_ATT) && !feof (cr_unit.fileref)) { - if (!(crs & CRCSR_OFFLINE)) - crs |= CRCSR_ONLINE; /* non-standard */ - crs &= ~(CRCSR_RDCHK | CRCSR_SUPPLY ); - cdst &= ~(CDCSR_RDRCHK | CDCSR_HOPPER); - cddbs = 0; - } else { - cdst |= CSR_ERR | CDCSR_RDRCHK | CDCSR_HOPPER; - cddbs |= CDDB_STACK; - crs |= CSR_ERR | CRCSR_RDCHK | CRCSR_SUPPLY; - } - sim_cancel (&cr_unit); /* deactivate unit */ - if (blowerState != BLOW_OFF) { - blowerState = BLOW_STOP; - sim_activate (&cr_unit, spinDown); - } - EOFcard = 0; - CLR_INT (CR); - CLR_INT (CD); - /* TBD: flush current card */ - /* init uptr->wait ? */ - return auto_config (dptr->name, 1); -} - -/* -Handle the interface status and SIMH portion of the ATTACH. Another -routine is used to evaluate the file and initialize other state -globals correctly. -*/ - -#define MASK (SWMASK('A')|SWMASK('B')|SWMASK('I')|SWMASK('R')) - -/* Attach unit */ -/* This should simulate physically putting a stack of cards into the hopper */ -/* No bits should change, nor an interrupt should be asserted */ -/* This is a change of behaviour respect to the previous code */ -t_stat cr_attach ( UNIT *uptr, - char *cptr ) -{ - t_stat reason; - - if (sim_switches & ~MASK) - return (SCPE_INVSW); - /* file must previously exist; kludge */ - sim_switches |= SWMASK ('R'); - reason = attach_unit (uptr, cptr); - if(uptr->flags & UNIT_ATT) { - setupCardFile(uptr, sim_switches); - } - - return (reason); -} - -/* Detach unit: assert SUPPLY and OFFLINE bits (and ERR) */ -t_stat cr_detach ( UNIT *uptr ) -{ - crs |= CSR_ERR | CRCSR_SUPPLY | CRCSR_OFFLINE; - /* interrupt? */ - crs &= ~CRCSR_ONLINE; - cdst |= CSR_ERR | CDCSR_HOPPER | CDCSR_OFFLINE; - cardFormat = "unknown"; - if (blowerState != BLOW_OFF) { - blowerState = BLOW_STOP; - sim_activate (uptr, spinDown); - } - return (detach_unit (uptr)); -} - -void cr_set_int (void) -{ -if (CR11_CTL (&cr_unit)) { - SET_INT (CR); - } -else { - SET_INT (CD); - } -return; -} - -void cr_clr_int (void) -{ -if (CR11_CTL (&cr_unit)) { - CLR_INT (CR); - } -else { - CLR_INT (CD); - } -return; -} - - -#if defined (CR11_OK) || defined (CD11_OK) || defined (CD20_OK) -t_stat cr_set_type ( UNIT *uptr, - int32 val, - char *cptr, - void *desc ) -{ - DEVICE *dptr = find_dev_from_unit (uptr); - DIB *dibp; - - /* disallow type change if currently attached */ - - if (uptr->flags & UNIT_ATT) - return (SCPE_NOFNC); - if (dptr == NULL) - return (SCPE_IERR); - if ((dibp = (DIB *) dptr->ctxt) == NULL) - return (SCPE_IERR); - cpm = (val & UNIT_CR11) ? 285 : ((val & UNIT_CD20)? 1200 :1000); - uptr->wait = (60 * 1000000) / (cpm * 80); /* Time between columns in usec. - * Readers are rated in card/min for 80 column cards */ - transcodes[0].table = (val & UNIT_CD20)? o29_decascii_code : o29_code; - dibp->vloc = (val & UNIT_CR11)? IVCL (CR): IVCL (CD); - - return (SCPE_OK); -} -#endif - -#if defined (AIECO_OK) -t_stat cr_set_aieco ( UNIT *uptr, - int32 val, - char *cptr, - void *desc ) -{ - /* disallow eco change if currently attached or not CD20 */ - - if (uptr->flags & UNIT_ATT || !CD20_CTL(uptr)) - return (SCPE_NOFNC); - - uptr->flags = (uptr->flags & ~UNIT_AIECO) | (val & UNIT_AIECO); - return (SCPE_OK); -} -#endif - -t_stat cr_show_format ( FILE *st, - UNIT *uptr, - int32 val, - void *desc ) -{ - fprintf (st, "%s format", cardFormat); - return (SCPE_OK); -} - -t_stat cr_set_rate ( UNIT *uptr, - int32 val, - char *cptr, - void *desc ) -{ - t_stat status = SCPE_OK; - int32 i; - - if (!cptr) - return (SCPE_MISVAL); - if (strcmp (cptr, "DEFAULT") == 0) - i = CR11_CTL(uptr) ? 285 : (CD20_CTL(uptr)? 1200 :1000); - else - i = (int32) get_uint (cptr, 10, 0xFFFFFFFF, &status); - if (status == SCPE_OK) { - if (i < 200 || i > 1200) - status = SCPE_ARG; - else { - cpm = i; - uptr->wait = (60 * 1000000) / (cpm * 80); /* Time between columns in usec. - * Readers are rated in card/min for 80 column cards */ - } - } - return (status); -} - -t_stat cr_show_rate ( FILE *st, - UNIT *uptr, - int32 val, - void *desc ) -{ - fprintf (st, "%d cards per minute", cpm); - return (SCPE_OK); -} - -/* simulate pressing the card reader RESET button */ -/* Per CR11 docs, transition to ONLINE, reset card */ -/* reader logic. */ -/* RESET is somewhat of a misnomer; START is the function */ - -t_stat cr_set_reset ( UNIT *uptr, - int32 val, - char *cptr, - void *desc ) -{ - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "cr_set_reset\n"); -/* - Ignore the RESET switch while a read cycle is in progress or the - unit simply is not attached. - */ - if ((crs & CRCSR_BUSY) || !(uptr->flags & UNIT_ATT)) - return (SCPE_OK); - - /* if no errors, signal transition to on line */ - crs |= CRCSR_ONLINE; - /* Clear error bits */ - crs &= ~(CSR_ERR|CRCSR_CRDDONE|CRCSR_SUPPLY|CRCSR_RDCHK|CRCSR_TIMERR| - CRCSR_OFFLINE|CRCSR_BUSY|CRCSR_COLRDY|CRCSR_EJECT|CSR_GO); - cdst |= CDCSR_ONLINE; - cdst &= ~(CSR_ERR | CDCSR_OFFLINE | CDCSR_RDRCHK | CDCSR_HOPPER | - CDCSR_EOF); - /* I don't think the hardware clears these errors, but TOPS-10 seems to expect it. - * Since we know the reader is idle, and this is OPR intervention, it seems safe. - */ - cdst &= ~(CDCSR_LATE | CDCSR_NXM); - - /* Assert interrupt if interrupts enabled */ - if ((CR11_CTL(uptr)?crs : cdst) & CSR_IE) { - cr_set_int (); - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "cr_set_reset setting interrupt\n"); - } - - /* Reset controller status */ - cr_unit.buf = 0; - currCol = 1; - crb1 = 0; - crb2 = 0; - cdcc = 0; - cdba = 0; - cddb = 0; - cddbs = 0; - EOFcard = 0; - - /* start up the blower if the hopper is not empty - if (blowerState != BLOW_ON) { - blowerState = BLOW_START; - sim_activate (uptr, spinUp); - } - */ - return (SCPE_OK); -} - -/* simulate pressing the card reader STOP button */ - -t_stat cr_set_stop ( UNIT *uptr, - int32 val, - char *cptr, - void *desc ) -{ - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "set_stop\n"); - crs &= ~CRCSR_ONLINE; - crs |= CSR_ERR | CRCSR_OFFLINE; - cdst |= CSR_ERR | CDCSR_OFFLINE; - /* CD11 does not appear to interrupt on STOP. */ - if (CR11_CTL(uptr) && (crs & CSR_IE)) - cr_set_int (); - if (blowerState != BLOW_OFF) { - blowerState = BLOW_STOP; - } - return (SCPE_OK); -} - -/* simulate pressing the card reader EOF button */ - -t_stat cr_set_eof ( UNIT *uptr, - int32 val, - char *cptr, - void *desc ) -{ - if (DEBUG_PRS (cr_dev)) - fprintf (sim_deb, "set_eof\n"); - eofPending = 1; - - return (SCPE_OK); -} - -t_stat cr_show_eof ( FILE *st, - UNIT *uptr, - int32 val, - void *desc ) -{ - fprintf (st, (eofPending? "EOF pending": "no EOF pending")); - return (SCPE_OK); -} - -t_stat cr_set_trans ( UNIT *uptr, - int32 val, - char *cptr, - void *desc ) -{ - size_t i; - - if (!cptr) - return (SCPE_MISVAL); - - for (i = 0; i < NTRANS; i++) { - if (strcmp (cptr, transcodes[i].name) == 0) - break; - } - if (i >= NTRANS) - return (SCPE_ARG); - codeTbl = transcodes[i].table; - initTranslation (); /* reinitialize tables */ - return (SCPE_OK); -} - -t_stat cr_show_trans ( FILE *st, - UNIT *uptr, - int32 val, - void *desc ) -{ - size_t i; - - for (i = 1; i < NTRANS; i++ ) - if (transcodes[i].table == codeTbl) { - fprintf (st, "translation=%s", transcodes[i].name); - return SCPE_OK; - } - fprintf (st, "translation=%s", transcodes[0].name); - return (SCPE_OK); -} diff --git a/PDP11/pdp11_cr_dat.h b/PDP11/pdp11_cr_dat.h deleted file mode 100644 index de3fb153..00000000 --- a/PDP11/pdp11_cr_dat.h +++ /dev/null @@ -1,682 +0,0 @@ -/* pdp11_cr_dat.h - * - * card code arrays are indexed by 7-bit ASCII code, and - * give corresponding 12-bit card codes using the indicated - * collating sequence. - * - * CR_ER should be externally defined, either as an illegal - * card code (on conversion from ASCII to card codes) or as - * a code with a bit set outside the least significant 12. - * - * author: Douglas Jones, jones@cs.uiowa.edu - * revisions: - * March 5, 1996 - * Feb 18, 1997 to add 026 and EBCDIC converstion tables - * Jan 10, 2005, (JAD) Added 'static const' to the array - * definitions. - * Jan 11, 2005, (JAD) Create the h2c_code array. - * Jan 14, 2005, (JAD) Added the special DEC code for 'end of deck' - * (12-11-0-1-6-7-8-9) to the o29_code array at position 26. (^Z). - * Should I add this to the other arrays? - * Feb 24, 2007, (JGP) Added the DEC version of the 026 codepage and - * fixed some DEC029 codes. - */ - -/* DEC's version of the IBM 029 kepunch encoding, (thus avoiding IBM's - use of non-ASCII punctuation), based on that given in the appendix - to Digital's "Small Computer Handbook, 1973", and augmented to - translate lower case to upper case. As a result of this modification, - inversion of this table should be done with care! */ -static const int o29_code[] = { - CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER, /* control */ - CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER, /* chars */ - CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER, /* control */ - CR_ER,CR_ER,07417,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER, /* chars */ - 00000,04006,00006,00102,02102,01042,04000,00022, /* !"#$%&' */ - 04022,02022,02042,04012,01102,02000,04102,01400, /* ()*+,-./ */ - 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ - 00002,00001,00202,02012,04042,00012,01012,01006, /* 89:;<=>? */ - 00042,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ - 01004,01002,01001,04202,02006,02202,04006,01022, /* XYZ[\]^_ */ - CR_ER,04400,04200,04100,04040,04020,04010,04004, /* `abcdefg */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* hijklmno */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* pqrstuvw */ - 01004,01002,01001,04000,CR_ER,02000,CR_ER,CR_ER /* xyz{|}~ */ - }; - -/* Bare bones 026 kepunch encodings */ -static const int o26_ftn_code[] = { - CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER, /* control */ - CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER, /* chars */ - CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER, /* control */ - CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER, /* chars */ - 00000,CR_ER,CR_ER,CR_ER,02102,CR_ER,CR_ER,00042, /* !"#$%&' */ - 01042,04042,02042,04000,01102,02000,04102,01400, /* ()*+,-./ */ - 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ - 00002,00001,CR_ER,CR_ER,CR_ER,00102,CR_ER,CR_ER, /* 89:;<=>? */ - CR_ER,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ - 01004,01002,01001,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER, /* XYZ[\]^_ */ - CR_ER,04400,04200,04100,04040,04020,04010,04004, /* `abcdefg */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* hijklmno */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* pqrstuvw */ - 01004,01002,01001,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER /* xyz{|}~ */ - }; - -static const int o26_comm_code[] = { - CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER, /* control */ - CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER, /* chars */ - CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER, /* control */ - CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER, /* chars */ - 00000,CR_ER,CR_ER,00102,02102,01042,04000,CR_ER, /* !"#$%&' */ - CR_ER,CR_ER,02042,CR_ER,01102,02000,04102,01400, /* ()*+,-./ */ - 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ - 00002,00001,CR_ER,CR_ER,04042,CR_ER,CR_ER,CR_ER, /* 89:;<=>? */ - 00042,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ - 01004,01002,01001,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER, /* XYZ[\]^_ */ - CR_ER,04400,04200,04100,04040,04020,04010,04004, /* `abcdefg */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* hijklmno */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* pqrstuvw */ - 01004,01002,01001,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER /* xyz{|}~ */ - }; - -/* 026DEC translation, according to RSX-11M-PLUS and Micro/RSX */ -/* I/O Drivers Reference manual - AA-JS11A-TC */ -static const int o26_dec_code[] = { - CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER, /* control */ - CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER, /* chars */ - CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER, /* control */ - CR_ER,CR_ER,07417,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER, /* chars */ - 00000,04006,01022,01102,02102,01006,02006,00012, /* !"#$%&' */ - 01042,04042,02042,04000,01102,02000,04102,01400, /* ()*+,-./ */ - 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ - 00002,00001,02202,01202,04012,00102,02012,04202, /* 89:;<=>? */ - 00042,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ - 01004,01002,01001,02022,00006,04022,00022,00202, /* XYZ[\]^_ */ - CR_ER,04400,04200,04100,04040,04020,04010,04004, /* `abcdefg */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* hijklmno */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* pqrstuvw */ - 01004,01002,01001,04000,CR_ER,02000,CR_ER,CR_ER /* xyz{|}~ */ - }; - -/* FULL EBCDIC, from Appendix C of System 360 Programming by Alex Thomas, - 1977, Reinhart Press, San Francisco. Codes not in that table have been - left compatable with DEC's 029 table. Some control codes have been - left out */ -static const int EBCDIC_code[] = { - 05403,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER, /* control */ - 02011,04021,01021,CR_ER,04041,02021,CR_ER,CR_ER, /* chars */ - CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER, /* control */ - CR_ER,CR_ER,CR_ER,CR_ER,01201,CR_ER,CR_ER,CR_ER, /* chars */ - 00000,02202,00006,00102,02102,01042,04000,00022, /* !"#$%&' */ - 04022,02022,02042,04012,01102,02000,04102,01400, /* ()*+,-./ */ - 01000,00400,00200,00100,00040,00020,00010,00004, /* 01234567 */ - 00002,00001,00202,02012,04042,00012,01012,01006, /* 89:;<=>? */ - 00042,04400,04200,04100,04040,04020,04010,04004, /* @ABCDEFG */ - 04002,04001,02400,02200,02100,02040,02020,02010, /* HIJKLMNO */ - 02004,02002,02001,01200,01100,01040,01020,01010, /* PQRSTUVW */ - 01004,01002,01001,04202,02006,01202,04006,01022, /* XYZ[\]^_ */ - CR_ER,05400,05200,05100,05040,05020,05010,05004, /* `abcdefg */ - 05002,05001,06400,06200,06100,06040,06020,06010, /* hijklmno */ - 06004,06002,06001,03200,03100,03040,03020,03010, /* pqrstuvw */ - 03004,03002,03001,CR_ER,CR_ER,CR_ER,CR_ER,CR_ER /* xyz{|}~ */ - }; -/* DEC's 026 code extended to full 7-bit ASCII, as used in the DECsystem-10. */ -static const int o26_decascii_code[] = { - 05403, 04401, 04201, 04101, 00005, 01023, 01013, 01007, - 02011, 04021, 01021, 04103, 04043, 04023, 04013, 04007, - 06403, 02401, 02201, 02101, 00043, 00023, 00201, 01011, - 02003, 02403, 00007, 01005, 02043, 02023, 02013, 02007, - 00000, 04006, 01022, 01012, 02102, 01006, 02006, 00012, - 01042, 04042, 02042, 04000, 01102, 02000, 04102, 01400, - 01000, 00400, 00200, 00100, 00040, 00020, 00010, 00004, - 00002, 00001, 02202, 01202, 04012, 00102, 02012, 04202, - 00042, 04400, 04200, 04100, 04040, 04020, 04010, 04004, - 04002, 04001, 02400, 02200, 02100, 02040, 02020, 02010, - 02004, 02002, 02001, 01200, 01100, 01040, 01020, 01010, - 01004, 01002, 01001, 02022, 00006, 04022, 00022, 00202, - 00402, 05400, 05200, 05100, 05040, 05020, 05010, 05004, - 05002, 05001, 06400, 06200, 06100, 06040, 06020, 06010, - 06004, 06002, 06001, 03200, 03100, 03040, 03020, 03010, - 03004, 03002, 03001, 05000, 06000, 03000, 03400, 04005, -}; -/* DEC's 029 code extended to full 7-bit ASCII, as used in the DECsystem-10. */ -static const int o29_decascii_code[] = { - 05403, 04401, 04201, 04101, 00005, 01023, 01013, 01007, - 02011, 04021, 01021, 04103, 04043, 04023, 04013, 04007, - 06403, 02401, 02201, 02101, 00043, 00023, 00201, 01011, - 02003, 02403, 00007, 01005, 02043, 02023, 02013, 02007, - 00000, 04006, 00006, 00102, 02102, 01042, 04000, 00022, - 04022, 02022, 02042, 04012, 01102, 02000, 04102, 01400, - 01000, 00400, 00200, 00100, 00040, 00020, 00010, 00004, - 00002, 00001, 00202, 02012, 04042, 00012, 01012, 01006, - 00042, 04400, 04200, 04100, 04040, 04020, 04010, 04004, - 04002, 04001, 02400, 02200, 02100, 02040, 02020, 02010, - 02004, 02002, 02001, 01200, 01100, 01040, 01020, 01010, - 01004, 01002, 01001, 04202, 01202, 02202, 02006, 01022, - 00402, 05400, 05200, 05100, 05040, 05020, 05010, 05004, - 05002, 05001, 06400, 06200, 06100, 06040, 06020, 06010, - 06004, 06002, 06001, 03200, 03100, 03040, 03020, 03010, - 03004, 03002, 03001, 05000, 06000, 03000, 03400, 04005, -}; -static const int h2c_code[4096] = { - 0000, 0020, 0010, 0030, 0007, 0027, 0017, 0037, - 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, - 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0004, 0024, 0014, 0034, 0007, 0027, 0017, 0037, - 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, - 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0002, 0022, 0012, 0032, 0007, 0027, 0017, 0037, - 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, - 0006, 0026, 0016, 0036, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0001, 0021, 0011, 0031, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0005, 0025, 0015, 0035, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0003, 0023, 0013, 0033, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0007, 0027, 0017, 0037, 0007, 0027, 0017, 0037, - 0040, 0060, 0050, 0070, 0047, 0067, 0057, 0077, - 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, - 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0044, 0064, 0054, 0074, 0047, 0067, 0057, 0077, - 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, - 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0042, 0062, 0052, 0072, 0047, 0067, 0057, 0077, - 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, - 0046, 0066, 0056, 0076, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0041, 0061, 0051, 0071, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0045, 0065, 0055, 0075, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0043, 0063, 0053, 0073, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0047, 0067, 0057, 0077, 0047, 0067, 0057, 0077, - 0100, 0120, 0110, 0130, 0107, 0127, 0117, 0137, - 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, - 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0104, 0124, 0114, 0134, 0107, 0127, 0117, 0137, - 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, - 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0102, 0122, 0112, 0132, 0107, 0127, 0117, 0137, - 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, - 0106, 0126, 0116, 0136, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0101, 0121, 0111, 0131, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0105, 0125, 0115, 0135, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0103, 0123, 0113, 0133, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0107, 0127, 0117, 0137, 0107, 0127, 0117, 0137, - 0140, 0160, 0150, 0170, 0147, 0167, 0157, 0177, - 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, - 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0144, 0164, 0154, 0174, 0147, 0167, 0157, 0177, - 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, - 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0142, 0162, 0152, 0172, 0147, 0167, 0157, 0177, - 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, - 0146, 0166, 0156, 0176, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0141, 0161, 0151, 0171, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0145, 0165, 0155, 0175, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0143, 0163, 0153, 0173, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0147, 0167, 0157, 0177, 0147, 0167, 0157, 0177, - 0200, 0220, 0210, 0230, 0207, 0227, 0217, 0237, - 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, - 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0204, 0224, 0214, 0234, 0207, 0227, 0217, 0237, - 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, - 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0202, 0222, 0212, 0232, 0207, 0227, 0217, 0237, - 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, - 0206, 0226, 0216, 0236, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0201, 0221, 0211, 0231, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0205, 0225, 0215, 0235, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0203, 0223, 0213, 0233, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0207, 0227, 0217, 0237, 0207, 0227, 0217, 0237, - 0240, 0260, 0250, 0270, 0247, 0267, 0257, 0277, - 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, - 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0244, 0264, 0254, 0274, 0247, 0267, 0257, 0277, - 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, - 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0242, 0262, 0252, 0272, 0247, 0267, 0257, 0277, - 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, - 0246, 0266, 0256, 0276, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0241, 0261, 0251, 0271, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0245, 0265, 0255, 0275, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0243, 0263, 0253, 0273, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0247, 0267, 0257, 0277, 0247, 0267, 0257, 0277, - 0300, 0320, 0310, 0330, 0307, 0327, 0317, 0337, - 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, - 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0304, 0324, 0314, 0334, 0307, 0327, 0317, 0337, - 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, - 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0302, 0322, 0312, 0332, 0307, 0327, 0317, 0337, - 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, - 0306, 0326, 0316, 0336, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0301, 0321, 0311, 0331, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0305, 0325, 0315, 0335, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0303, 0323, 0313, 0333, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0307, 0327, 0317, 0337, 0307, 0327, 0317, 0337, - 0340, 0360, 0350, 0370, 0347, 0367, 0357, 0377, - 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, - 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0344, 0364, 0354, 0374, 0347, 0367, 0357, 0377, - 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, - 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0342, 0362, 0352, 0372, 0347, 0367, 0357, 0377, - 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, - 0346, 0366, 0356, 0376, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0341, 0361, 0351, 0371, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0345, 0365, 0355, 0375, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0343, 0363, 0353, 0373, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, - 0347, 0367, 0357, 0377, 0347, 0367, 0357, 0377, -}; diff --git a/PDP11/pdp11_dc.c b/PDP11/pdp11_dc.c deleted file mode 100644 index bf34b2ac..00000000 --- a/PDP11/pdp11_dc.c +++ /dev/null @@ -1,617 +0,0 @@ -/* pdp11_dc.c: PDP-11 DC11 multiple terminal interface simulator - - Copyright (c) 1993-2016, 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. - - dci,dco DC11 terminal input/output - - 03-Jan-2016 RMS Changed output default to 7B - 11-Oct-2013 RMS Poll DCI immediately after attach to pick up connect - 18-Apr-2012 RMS Modified to use clock coscheduling - 17-Aug-2011 RMS Added AUTOCONFIGURE modifier - 19-Nov-2008 RMS Revised for common TMXR show routines - Revised to autoconfigure vectors - - The simulator supports both hardwired and modem-like behavior. If modem - control is not enabled, carrier detect, ring, and carrier change are - never set. -*/ - -#if defined (VM_PDP10) /* PDP10 version */ -#error "DC11 is not supported on the PDP-10!" - -#elif defined (VM_VAX) /* VAX version */ -#error "DC11 is not supported on the VAX!" - -#else /* PDP-11 version */ -#include "pdp11_defs.h" -#endif -#include "sim_sock.h" -#include "sim_tmxr.h" - -#define DCX_MASK (DCX_LINES - 1) - -/* Parity and modem control */ - -#define DCX_V_OPAR (TTUF_V_UF + 0) -#define DCX_V_EPAR (TTUF_V_UF + 1) -#define DCX_V_MDM (TTUF_V_UF + 2) -#define DCX_OPAR (1u << DCX_V_OPAR) -#define DCX_EPAR (1u << DCX_V_EPAR) -#define DCX_MDM (1u << DCX_V_MDM) - -/* registers */ - -#define DCICSR_RD 0173777 -#define DCICSR_WR 0003533 -#define DCICSR_DTR 0000001 /* DTR (RW) */ -#define DCICSR_XBR 0000002 /* xmit brk (RWNI) */ -#define DCICSR_CDT 0000004 /* car det (RO) */ -#define DCICSR_PAR 0000040 /* odd par (RO) */ -#define DCICSR_OVR 0010000 /* overrun (RO) */ -#define DCICSR_RNG 0020000 /* ring (RO) */ -#define DCICSR_CCH 0040000 /* car change (RO) */ -#define DCICSR_ALLERR (DCICSR_OVR|DCICSR_RNG|DCICSR_CCH) -#define DCICSR_ERR 0100000 /* error */ -#define DCOCSR_RD 0100737 -#define DCOCSR_WR 0000535 -#define DCOCSR_RTS 0000001 /* req to send (RW) */ -#define DCOCSR_CTS 0000002 /* clr to send (RO) */ -#define DCOCSR_MNT 0000004 /* maint (RWNI) */ - -extern int32 int_req[IPL_HLVL]; -extern int32 tmxr_poll; - -uint16 dci_csr[DCX_LINES] = { 0 }; /* control/status */ -uint8 dci_buf[DCX_LINES] = { 0 }; -uint32 dci_ireq = 0; -uint16 dco_csr[DCX_LINES] = { 0 }; /* control/status */ -uint8 dco_buf[DCX_LINES] = { 0 }; -uint32 dco_ireq = 0; -TMLN dcx_ldsc[DCX_LINES] = { {0} }; /* line descriptors */ -TMXR dcx_desc = { DCX_LINES, 0, 0, dcx_ldsc }; /* mux descriptor */ - -static const uint8 odd_par[] = { - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 00 */ - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 10 */ - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 20 */ - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 30 */ - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 40 */ - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 50 */ - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 60 */ - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 70 */ - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* 80 */ - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* 90 */ - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* A0 */ - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* B0 */ - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* C0 */ - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* D0 */ - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80, /* E0 */ - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, - 0x80, 0, 0, 0x80, 0, 0x80, 0x80, 0, /* F0 */ - 0, 0x80, 0x80, 0, 0x80, 0, 0, 0x80 - }; - -t_stat dcx_rd (int32 *data, int32 PA, int32 access); -t_stat dcx_wr (int32 data, int32 PA, int32 access); -t_stat dcx_reset (DEVICE *dptr); -t_stat dci_svc (UNIT *uptr); -t_stat dco_svc (UNIT *uptr); -t_stat dcx_attach (UNIT *uptr, char *cptr); -t_stat dcx_detach (UNIT *uptr); -t_stat dcx_set_lines (UNIT *uptr, int32 val, char *cptr, void *desc); -void dcx_enbdis (int32 dis); -void dci_clr_int (int32 ln); -void dci_set_int (int32 ln); -int32 dci_iack (void); -void dco_clr_int (int32 ln); -void dco_set_int (int32 ln); -int32 dco_iack (void); -void dcx_reset_ln (int32 ln); - -/* DCI data structures - - dci_dev DCI device descriptor - dci_unit DCI unit descriptor - dci_reg DCI register list -*/ - -DIB dci_dib = { - IOBA_DC, IOLN_DC, &dcx_rd, &dcx_wr, - 2, IVCL (DCI), VEC_DCI, { &dci_iack, &dco_iack } - }; - -UNIT dci_unit = { UDATA (&dci_svc, 0, 0), SERIAL_IN_WAIT }; - -REG dci_reg[] = { - { BRDATA (BUF, dci_buf, DEV_RDX, 8, DCX_LINES) }, - { BRDATA (CSR, dci_csr, DEV_RDX, 16, DCX_LINES) }, - { GRDATA (IREQ, dci_ireq, DEV_RDX, DCX_LINES, 0) }, - { DRDATA (LINES, dcx_desc.lines, 6), REG_HRO }, - { GRDATA (DEVADDR, dci_dib.ba, DEV_RDX, 32, 0), REG_HRO }, - { GRDATA (DEVIOLN, dci_dib.lnt, DEV_RDX, 32, 0), REG_HRO }, - { GRDATA (DEVVEC, dci_dib.vec, DEV_RDX, 16, 0), REG_HRO }, - { NULL } - }; - -MTAB dci_mod[] = { - { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", - &tmxr_dscln, NULL, &dcx_desc }, - { UNIT_ATT, UNIT_ATT, "summary", NULL, - NULL, &tmxr_show_summ, (void *) &dcx_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, - NULL, &tmxr_show_cstat, (void *) &dcx_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, - NULL, &tmxr_show_cstat, (void *) &dcx_desc }, - { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, - &set_addr, &show_addr, NULL }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE", - &set_addr_flt, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 1, "VECTOR", NULL, - &set_vec, &show_vec_mux, (void *) &dcx_desc }, - { MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES", - &dcx_set_lines, &tmxr_show_lines, (void *) &dcx_desc }, - { 0 } - }; - -DEVICE dci_dev = { - "DCI", &dci_unit, dci_reg, dci_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &dcx_reset, - NULL, &dcx_attach, &dcx_detach, - &dci_dib, DEV_FLTA | DEV_UBUS | DEV_QBUS | DEV_DISABLE | DEV_DIS - }; - -/* DCO data structures - - dco_dev DCO device descriptor - dco_unit DCO unit descriptor - dco_reg DCO register list -*/ - -UNIT dco_unit[] = { - { UDATA (&dco_svc, TT_MODE_7B+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, - { UDATA (&dco_svc, TT_MODE_7B+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, - { UDATA (&dco_svc, TT_MODE_7B+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, - { UDATA (&dco_svc, TT_MODE_7B+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, - { UDATA (&dco_svc, TT_MODE_7B+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, - { UDATA (&dco_svc, TT_MODE_7B+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, - { UDATA (&dco_svc, TT_MODE_7B+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, - { UDATA (&dco_svc, TT_MODE_7B+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, - { UDATA (&dco_svc, TT_MODE_7B+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, - { UDATA (&dco_svc, TT_MODE_7B+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, - { UDATA (&dco_svc, TT_MODE_7B+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, - { UDATA (&dco_svc, TT_MODE_7B+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, - { UDATA (&dco_svc, TT_MODE_7B+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, - { UDATA (&dco_svc, TT_MODE_7B+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, - { UDATA (&dco_svc, TT_MODE_7B+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT }, - { UDATA (&dco_svc, TT_MODE_7B+DCX_EPAR+DCX_MDM, 0), SERIAL_OUT_WAIT } - }; - -REG dco_reg[] = { - { BRDATA (BUF, dco_buf, DEV_RDX, 8, DCX_LINES) }, - { BRDATA (CSR, dco_csr, DEV_RDX, 16, DCX_LINES) }, - { GRDATA (IREQ, dco_ireq, DEV_RDX, DCX_LINES, 0) }, - { URDATA (TIME, dco_unit[0].wait, 10, 31, 0, - DCX_LINES, PV_LEFT) }, - { NULL } - }; - -MTAB dco_mod[] = { - { TT_MODE, TT_MODE_UC, "UC", "UC", NULL }, - { TT_MODE, TT_MODE_7B, "7b", "7B", NULL }, - { TT_MODE, TT_MODE_8B, "8b", "8B", NULL }, - { TT_MODE, TT_MODE_7P, "7p", "7P", NULL }, - { DCX_OPAR+DCX_EPAR, 0, "no parity", "NOPARITY", NULL }, - { DCX_OPAR+DCX_EPAR, DCX_OPAR, "odd parity", "ODDPARITY", NULL }, - { DCX_OPAR+DCX_EPAR, DCX_EPAR, "even parity", "EVENPARITY", NULL }, - { DCX_MDM, 0, "no dataset", "NODATASET", NULL }, - { DCX_MDM, DCX_MDM, "dataset", "DATASET", NULL }, - { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT", - &tmxr_dscln, NULL, &dcx_desc }, - { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG", - &tmxr_set_log, &tmxr_show_log, &dcx_desc }, - { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG", - &tmxr_set_nolog, NULL, &dcx_desc }, - { 0 } - }; - -DEVICE dco_dev = { - "DCO", dco_unit, dco_reg, dco_mod, - DCX_LINES, 10, 31, 1, 8, 8, - NULL, NULL, &dcx_reset, - NULL, NULL, NULL, - NULL, DEV_UBUS | DEV_DISABLE | DEV_DIS - }; - -/* Terminal input routines */ - -t_stat dcx_rd (int32 *data, int32 PA, int32 access) -{ -int32 ln = ((PA - dci_dib.ba) >> 3) & DCX_MASK; - -switch ((PA >> 1) & 03) { /* decode PA<2:1> */ - - case 00: /* dci csr */ - if (dci_csr[ln] & DCICSR_ALLERR) - dci_csr[ln] |= DCICSR_ERR; - else dci_csr[ln] &= ~DCICSR_ERR; - *data = dci_csr[ln] & DCICSR_RD; - dci_csr[ln] &= ~(CSR_DONE|DCICSR_ALLERR|DCICSR_ERR); - return SCPE_OK; - - case 01: /* dci buf */ - dci_clr_int (ln); - *data = dci_buf[ln]; - sim_activate_abs (&dci_unit, dci_unit.wait); - return SCPE_OK; - - case 02: /* dco csr */ - *data = dco_csr[ln] & DCOCSR_RD; - return SCPE_OK; - - case 03: /* dco buf */ - *data = dco_buf[ln]; - return SCPE_OK; - } /* end switch PA */ - -return SCPE_NXM; -} - -t_stat dcx_wr (int32 data, int32 PA, int32 access) -{ -int32 ln = ((PA - dci_dib.ba) >> 3) & DCX_MASK; -TMLN *lp = &dcx_ldsc[ln]; - -switch ((PA >> 1) & 03) { /* decode PA<2:1> */ - - case 00: /* dci csr */ - if (access == WRITEB) /* byte write? */ - data = (PA & 1)? - (dci_csr[ln] & 0377) | (data << 8): - (dci_csr[ln] & ~0377) | data; - if ((data & CSR_IE) == 0) /* clr ie? */ - dci_clr_int (ln); /* clr int req */ - else if ((dci_csr[ln] & (CSR_DONE + CSR_IE)) == CSR_DONE) - dci_set_int (ln); - if (((data ^ dci_csr[ln]) & DCICSR_DTR) && /* DTR change? */ - (dco_unit[ln].flags & DCX_MDM)) { /* modem ctl? */ - if (data & DCICSR_DTR) { /* setting DTR? */ - if (lp->conn) { /* ringing? */ - dci_csr[ln] = (dci_csr[ln] & ~DCICSR_RNG) | - (DCICSR_CDT|DCICSR_CCH|DCICSR_ERR); - dco_csr[ln] |= DCOCSR_CTS; /* set CDT,CCH,CTS */ - if (data & CSR_IE) /* if ie, req int */ - dci_set_int (ln); - } - } /* end DTR 0->1 */ - else { /* clearing DTR */ - if (lp->conn) { /* connected? */ - tmxr_linemsg (lp, "\r\nLine hangup\r\n"); - tmxr_reset_ln (lp); /* reset line */ - if (dci_csr[ln] & DCICSR_CDT) { /* carrier det? */ - dci_csr[ln] |= (DCICSR_CCH|DCICSR_ERR); - if (data & CSR_IE) /* if ie, req int */ - dci_set_int (ln); - } - } - dci_csr[ln] &= ~(DCICSR_CDT|DCICSR_RNG); - dco_csr[ln] &= ~DCOCSR_CTS; /* clr CDT,RNG,CTS */ - } /* end DTR 1->0 */ - } /* end DTR chg+modem */ - dci_csr[ln] = (uint16) ((dci_csr[ln] & ~DCICSR_WR) | (data & DCICSR_WR)); - return SCPE_OK; - - case 01: /* dci buf */ - return SCPE_OK; - - case 02: /* dco csr */ - if (access == WRITEB) /* byte write? */ - data = (PA & 1)? - (dco_csr[ln] & 0377) | (data << 8): - (dco_csr[ln] & ~0377) | data; - if ((data & CSR_IE) == 0) /* clr ie? */ - dco_clr_int (ln); /* clr int req */ - else if ((dco_csr[ln] & (CSR_DONE + CSR_IE)) == CSR_DONE) - dco_set_int (ln); - dco_csr[ln] = (uint16) ((dco_csr[ln] & ~DCOCSR_WR) | (data & DCOCSR_WR)); - return SCPE_OK; - - case 03: /* dco buf */ - if ((PA & 1) == 0) - dco_buf[ln] = data & 0377; - dco_csr[ln] &= ~CSR_DONE; /* clr done */ - dco_clr_int (ln); /* clr int req */ - sim_activate (&dco_unit[ln], dco_unit[ln].wait); - return SCPE_OK; - } /* end switch PA */ - -return SCPE_NXM; -} - -/* Terminal input service */ - -t_stat dci_svc (UNIT *uptr) -{ -int32 ln, c, temp; - -if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ - return SCPE_OK; -sim_activate (uptr, clk_cosched (tmxr_poll)); /* continue poll */ -ln = tmxr_poll_conn (&dcx_desc); /* look for connect */ -if (ln >= 0) { /* got one? */ - dcx_ldsc[ln].rcve = 1; /* set rcv enb */ - if (dco_unit[ln].flags & DCX_MDM) { /* modem control? */ - if (dci_csr[ln] & DCICSR_DTR) /* DTR already set? */ - dci_csr[ln] |= (DCICSR_CDT|DCICSR_CCH|DCICSR_ERR); - else dci_csr[ln] |= (DCICSR_RNG|DCICSR_ERR); /* no, ring */ - if (dci_csr[ln] & CSR_IE) /* if ie, */ - dci_set_int (ln); /* req int */ - } - else dco_csr[ln] |= DCOCSR_CTS; /* just connect */ - } -tmxr_poll_rx (&dcx_desc); /* poll for input */ -for (ln = 0; ln < DCX_LINES; ln++) { /* loop thru lines */ - if (dcx_ldsc[ln].conn) { /* connected? */ - if ((temp = tmxr_getc_ln (&dcx_ldsc[ln])) && /* get char */ - !(temp & SCPE_BREAK)) { /* not break? */ - c = sim_tt_inpcvt (temp, TT_GET_MODE (dco_unit[ln].flags)); - if (dci_csr[ln] & CSR_DONE) /* overrun? */ - dci_csr[ln] |= DCICSR_OVR; - else dci_csr[ln] |= CSR_DONE; /* set done */ - if (dci_csr[ln] & CSR_IE) /* if ie, */ - dci_set_int (ln); /* req int */ - if (dco_unit[ln].flags & DCX_OPAR) /* odd parity */ - c = (c & 0177) | odd_par[c & 0177]; - else if (dco_unit[ln].flags & DCX_EPAR) /* even parity */ - c = (c & 0177) | (odd_par[c & 0177] ^ 0200); - dci_buf[ln] = (uint8)c; - if ((c & 0200) == odd_par[c & 0177]) /* odd par? */ - dci_csr[ln] |= DCICSR_PAR; - else dci_csr[ln] &= ~DCICSR_PAR; - } - } - else { /* disconnected */ - if ((dco_unit[ln].flags & DCX_MDM) && /* modem control? */ - (dci_csr[ln] & DCICSR_CDT)) { /* carrier detect? */ - dci_csr[ln] |= (DCICSR_CCH|DCICSR_ERR); /* carrier change */ - if (dci_csr[ln] & CSR_IE) /* if ie, */ - dci_set_int (ln); /* req int */ - } - dci_csr[ln] &= ~(DCICSR_CDT|DCICSR_RNG); /* clr CDT,RNG,CTS */ - dco_csr[ln] &= ~DCOCSR_CTS; - } - } -return SCPE_OK; -} - -/* Terminal output service */ - -t_stat dco_svc (UNIT *uptr) -{ -int32 c; -int32 ln = uptr - dco_unit; /* line # */ - -if (dcx_ldsc[ln].conn) { /* connected? */ - if (dcx_ldsc[ln].xmte) { /* tx enabled? */ - TMLN *lp = &dcx_ldsc[ln]; /* get line */ - c = sim_tt_outcvt (dco_buf[ln], TT_GET_MODE (dco_unit[ln].flags)); - if (c >= 0) /* output char */ - tmxr_putc_ln (lp, c); - tmxr_poll_tx (&dcx_desc); /* poll xmt */ - } - else { - tmxr_poll_tx (&dcx_desc); /* poll xmt */ - sim_activate (uptr, dco_unit[ln].wait); /* wait */ - return SCPE_OK; - } - } -dco_csr[ln] |= CSR_DONE; /* set done */ -if (dco_csr[ln] & CSR_IE) /* ie set? */ - dco_set_int (ln); /* req int */ -return SCPE_OK; -} - -/* Interrupt routines */ - -void dci_clr_int (int32 ln) -{ -dci_ireq &= ~(1 << ln); /* clr mux rcv int */ -if (dci_ireq == 0) /* all clr? */ - CLR_INT (DCI); -else SET_INT (DCI); /* no, set intr */ -return; -} - -void dci_set_int (int32 ln) -{ -dci_ireq |= (1 << ln); /* clr mux rcv int */ -SET_INT (DCI); /* set master intr */ -return; -} - -int32 dci_iack (void) -{ -int32 ln; - -for (ln = 0; ln < DCX_LINES; ln++) { /* find 1st line */ - if (dci_ireq & (1 << ln)) { - dci_clr_int (ln); /* clear intr */ - return (dci_dib.vec + (ln * 010)); /* return vector */ - } - } -return 0; -} - -void dco_clr_int (int32 ln) -{ -dco_ireq &= ~(1 << ln); /* clr mux rcv int */ -if (dco_ireq == 0) /* all clr? */ - CLR_INT (DCO); -else SET_INT (DCO); /* no, set intr */ -return; -} - -void dco_set_int (int32 ln) -{ -dco_ireq |= (1 << ln); /* clr mux rcv int */ -SET_INT (DCO); /* set master intr */ -return; -} - -int32 dco_iack (void) -{ -int32 ln; - -for (ln = 0; ln < DCX_LINES; ln++) { /* find 1st line */ - if (dco_ireq & (1 << ln)) { - dco_clr_int (ln); /* clear intr */ - return (dci_dib.vec + (ln * 010) + 4); /* return vector */ - } - } -return 0; -} - -/* Reset */ - -t_stat dcx_reset (DEVICE *dptr) -{ -int32 ln; - -dcx_enbdis (dptr->flags & DEV_DIS); /* sync enables */ -sim_cancel (&dci_unit); /* assume stop */ -if (dci_unit.flags & UNIT_ATT) /* if attached, */ - sim_activate (&dci_unit, tmxr_poll); /* activate */ -for (ln = 0; ln < DCX_LINES; ln++) /* for all lines */ - dcx_reset_ln (ln); -return auto_config (dci_dev.name, dcx_desc.lines); /* auto config */ -} - -/* Reset individual line */ - -void dcx_reset_ln (int32 ln) -{ -dci_buf[ln] = 0; /* clear buf */ -dci_csr[ln] = 0; -dco_buf[ln] = 0; /* clear buf */ -dco_csr[ln] = CSR_DONE; -sim_cancel (&dco_unit[ln]); /* deactivate */ -dci_clr_int (ln); -dco_clr_int (ln); -return; -} - -/* Attach master unit */ - -t_stat dcx_attach (UNIT *uptr, char *cptr) -{ -t_stat r; - -r = tmxr_attach (&dcx_desc, uptr, cptr); /* attach */ -if (r != SCPE_OK) /* error? */ - return r; -sim_activate (uptr, 0); /* start poll at once */ -return SCPE_OK; -} - -/* Detach master unit */ - -t_stat dcx_detach (UNIT *uptr) -{ -int32 i; -t_stat r; - -r = tmxr_detach (&dcx_desc, uptr); /* detach */ -for (i = 0; i < DCX_LINES; i++) /* all lines, */ - dcx_ldsc[i].rcve = 0; /* disable rcv */ -sim_cancel (uptr); /* stop poll */ -return r; -} - -/* Enable/disable device */ - -void dcx_enbdis (int32 dis) -{ -if (dis) { - dci_dev.flags = dci_dev.flags | DEV_DIS; - dco_dev.flags = dco_dev.flags | DEV_DIS; - } -else { - dci_dev.flags = dci_dev.flags & ~DEV_DIS; - dco_dev.flags = dco_dev.flags & ~DEV_DIS; - } -return; -} - -/* Change number of lines */ - -t_stat dcx_set_lines (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 newln, i, t; -t_stat r; - -if (cptr == NULL) - return SCPE_ARG; -newln = get_uint (cptr, 10, DCX_LINES, &r); -if ((r != SCPE_OK) || (newln == dcx_desc.lines)) - return r; -if (newln == 0) - return SCPE_ARG; -if (newln < dcx_desc.lines) { - for (i = newln, t = 0; i < dcx_desc.lines; i++) - t = t | dcx_ldsc[i].conn; - if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE)) - return SCPE_OK; - for (i = newln; i < dcx_desc.lines; i++) { - if (dcx_ldsc[i].conn) { - tmxr_linemsg (&dcx_ldsc[i], "\r\nOperator disconnected line\r\n"); - tmxr_reset_ln (&dcx_ldsc[i]); /* reset line */ - } - dco_unit[i].flags |= UNIT_DIS; - dcx_reset_ln (i); - } - } -else { - for (i = dcx_desc.lines; i < newln; i++) { - dco_unit[i].flags &= ~UNIT_DIS; - dcx_reset_ln (i); - } - } -dcx_desc.lines = newln; -dci_dib.lnt = newln * 010; /* upd IO page lnt */ -return auto_config (dci_dev.name, newln); /* auto config */ -} diff --git a/PDP11/pdp11_defs.h b/PDP11/pdp11_defs.h deleted file mode 100644 index 89737084..00000000 --- a/PDP11/pdp11_defs.h +++ /dev/null @@ -1,927 +0,0 @@ -/* pdp11_defs.h: PDP-11 simulator definitions - - Copyright (c) 1993-2017, 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 author gratefully acknowledges the help of Max Burnet, Megan Gentry, - and John Wilson in resolving questions about the PDP-11 - - 10-Feb-17 RMS Fixed RJS11 register block length (Mark Hill) - 19-Jan-17 RMS Moved CR11 to BR6, leaving CD11 at BR4 (Mark Pizzolato) - 10-Mar-16 RMS Added UC15 support - 30-Dec-15 RMS Added NOBVT option - 23-Oct-13 RMS Added cpu_set_boot prototype - 02-Sep-13 RMS Added third Massbus adapter and RS drive - 12-Dec-12 RMS Fixed base address for RQB, RQC, RQD - 11-Dec-11 RMS Fixed priority of PIRQ vs IO; added INT_INTERNALn - 22-May-10 RMS Added check for 64b definitions - 19-Nov-08 RMS Moved I/O support routines to I/O library - 16-May-08 RMS Added KE11A, DC11 support - 02-Feb-08 RMS Fixed DMA memory address limit test (John Dundas) - 25-Jan-08 RMS Added RC11, KG11A support (John Dundas) - 16-Dec-06 RMS Added TA11 support - 29-Oct-06 RMS Added clock coscheduling - 06-Jul-06 RMS Added multiple KL11/DL11 support - 26-Jun-06 RMS Added RF11 support - 24-May-06 RMS Added 11/44 DR support (CIS diagnostic) - 17-May-06 RMS Added CR11/CD11 support (John Dundas) - 30-Sep-04 RMS Added Massbus support - Removed Map_Addr prototype - Removed map argument from Unibus routines - Added framework for model selection - 28-May-04 RMS Added DHQ support - 25-Jan-04 RMS Removed local debug logging support - 22-Dec-03 RMS Added second DEUNA/DELUA support - 18-Oct-03 RMS Added DECtape off reel message - 19-May-03 RMS Revised for new conditional compilation - 05-Apr-03 RMS Fixed bug in MMR1 update (Tim Stark) - 28-Feb-03 RMS Added TM logging support - 19-Jan-03 RMS Changed mode definitions for Apple Dev Kit conflict - 11-Nov-02 RMS Changed log definitions to be VAX compatible - 10-Oct-02 RMS Added vector information to DIB - Changed DZ11 vector to Unibus standard - Added DEQNA/DELQA, DEUNA/DELUA support - Added multiple RQDX3, autoconfigure support - 12-Sep-02 RMS Added TMSCP, KW11P,and RX211 support - 28-Apr-02 RMS Clarified PDF ACF mnemonics - 22-Apr-02 RMS Added HTRAP, BPOK maint register flags, MT_MAXFR - 06-Mar-02 RMS Changed system type to KDJ11A - 20-Jan-02 RMS Added multiboard DZ11 support - 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 - 01-Jun-01 RMS Added DZ11 support - 23-Apr-01 RMS Added RK611 support - 05-Apr-01 RMS Added TS11/TSV05 support - 10-Feb-01 RMS Added DECtape support -*/ - -#ifndef PDP11_DEFS_H -#define PDP11_DEFS_H 0 - -#ifndef VM_PDP11 -#define VM_PDP11 0 -#endif - -#include "sim_defs.h" /* simulator defns */ -#include - -#if defined(USE_INT64) || defined(USE_ADDR64) -#error "PDP-11 does not support 64b values!" -#endif - -/* Architectural constants */ - -#define STKL_R 0340 /* stack limit */ -#define STKL_Y 0400 -#define VASIZE 0200000 /* 2**16 */ -#define VAMASK (VASIZE - 1) /* 2**16 - 1 */ -#define MEMSIZE64K 0200000 /* 2**16 */ -#define UNIMEMSIZE 001000000 /* 2**18 */ -#define UNIMASK (UNIMEMSIZE - 1) /* 2**18 - 1 */ -#define IOPAGEBASE 017760000 /* 2**22 - 2**13 */ -#define IOPAGESIZE 000020000 /* 2**13 */ -#define IOPAGEMASK (IOPAGESIZE - 1) /* 2**13 - 1 */ -#define MAXMEMSIZE 020000000 /* 2**22 */ -#define PAMASK (MAXMEMSIZE - 1) /* 2**22 - 1 */ -#define MEMSIZE (cpu_unit.capac) -#define DMASK 0177777 - -/* CPU models */ - -#define MOD_1103 0 -#define MOD_1104 1 -#define MOD_1105 2 -#define MOD_1120 3 -#define MOD_1123 4 -#define MOD_1123P 5 -#define MOD_1124 6 -#define MOD_1134 7 -#define MOD_1140 8 -#define MOD_1144 9 -#define MOD_1145 10 -#define MOD_1160 11 -#define MOD_1170 12 -#define MOD_1173 13 -#define MOD_1153 14 -#define MOD_1173B 15 -#define MOD_1183 16 -#define MOD_1184 17 -#define MOD_1193 18 -#define MOD_1194 19 -#define MOD_T 20 - -#define CPUT_03 (1u << MOD_1103) /* LSI-11 */ -#define CPUT_04 (1u << MOD_1104) /* 11/04 */ -#define CPUT_05 (1u << MOD_1105) /* 11/05 */ -#define CPUT_20 (1u << MOD_1120) /* 11/20 */ -#define CPUT_23 (1u << MOD_1123) /* 11/23 */ -#define CPUT_23P (1u << MOD_1123P) /* 11/23+ */ -#define CPUT_24 (1u << MOD_1124) /* 11/24 */ -#define CPUT_34 (1u << MOD_1134) /* 11/34 */ -#define CPUT_40 (1u << MOD_1140) /* 11/40 */ -#define CPUT_44 (1u << MOD_1144) /* 11/44 */ -#define CPUT_45 (1u << MOD_1145) /* 11/45 */ -#define CPUT_60 (1u << MOD_1160) /* 11/60 */ -#define CPUT_70 (1u << MOD_1170) /* 11/70 */ -#define CPUT_73 (1u << MOD_1173) /* 11/73 */ -#define CPUT_53 (1u << MOD_1153) /* 11/53 */ -#define CPUT_73B (1u << MOD_1173B) /* 11/73B */ -#define CPUT_83 (1u << MOD_1183) /* 11/83 */ -#define CPUT_84 (1u << MOD_1184) /* 11/84 */ -#define CPUT_93 (1u << MOD_1193) /* 11/93 */ -#define CPUT_94 (1u << MOD_1194) /* 11/94 */ -#define CPUT_T (1u << MOD_T) /* T-11 */ - -#define CPUT_F (CPUT_23|CPUT_23P|CPUT_24) /* all F11's */ -#define CPUT_J (CPUT_53|CPUT_73|CPUT_73B| \ - CPUT_83|CPUT_84|CPUT_93|CPUT_94) -#define CPUT_JB (CPUT_73B|CPUT_83|CPUT_84) /* KDJ11B */ -#define CPUT_JE (CPUT_93|CPUT_94) /* KDJ11E */ -#define CPUT_JU (CPUT_84|CPUT_94) /* KTJ11B UBA */ -#define CPUT_ALL 0xFFFFFFFF - -/* CPU options */ - -#define BUS_U (1u << 0) /* Unibus */ -#define BUS_Q (0) /* Qbus */ -#define OPT_EIS (1u << 1) /* EIS */ -#define OPT_FIS (1u << 2) /* FIS */ -#define OPT_FPP (1u << 3) /* FPP */ -#define OPT_CIS (1u << 4) /* CIS */ -#define OPT_MMU (1u << 5) /* MMU */ -#define OPT_RH11 (1u << 6) /* RH11 */ -#define OPT_PAR (1u << 7) /* parity */ -#define OPT_UBM (1u << 8) /* UBM */ -#define OPT_BVT (1u << 9) /* BEVENT */ - -#define CPUT(x) ((cpu_type & (x)) != 0) -#define CPUO(x) ((cpu_opt & (x)) != 0) -#define UNIBUS (cpu_opt & BUS_U) - -/* Feature sets - - SDSD source addr, dest addr, source fetch, dest fetch - SR switch register - DR display register - RTT RTT instruction - SXS SXT, XOR, SOB instructions - MARK MARK instruction - SPL SPL instruction - MXPY MTPI, MTPD, MFPI, MFPD instructions - MXPS MTPS, MFPS instructions - MFPT MFPT instruction - CSM CSM instruction - TSWLK TSTSET, WRLCK instructions - PSW PSW register - EXPT explicit PSW writes can alter T-bit - IOSR general registers readable from programs in IO space - 2REG dual register set - MMR3 MMR3 register - MMTR mem mgt traps - STKLR STKLIM register - STKLF fixed stack limit - SID supervisor mode, I/D spaces - ODD odd address trap - HALT4 halt in kernel mode traps to 4 - JREG4 JMP/JSR R traps to 4 - STKA stop on stack abort - LTCR LTC CSR - LTCM LTC CSR<7> -*/ - -#define IS_SDSD (CPUT_20|CPUT_F|CPUT_40|CPUT_60|CPUT_J|CPUT_T) -#define HAS_SR (CPUT_04|CPUT_05|CPUT_20|CPUT_34|CPUT_40| \ - CPUT_44|CPUT_45|CPUT_60|CPUT_70) -#define HAS_DR (CPUT_04|CPUT_05|CPUT_20|CPUT_24|CPUT_34| \ - CPUT_40|CPUT_44|CPUT_45|CPUT_60|CPUT_70) -#define HAS_RTT (CPUT_03|CPUT_04|CPUT_F|CPUT_34|CPUT_40| \ - CPUT_44|CPUT_45|CPUT_60|CPUT_70|CPUT_J|CPUT_T) -#define HAS_SXS (CPUT_03|CPUT_F|CPUT_34|CPUT_40|CPUT_44| \ - CPUT_45|CPUT_60|CPUT_70|CPUT_J|CPUT_T) -#define HAS_MARK (CPUT_03|CPUT_F|CPUT_34|CPUT_40|CPUT_44| \ - CPUT_45|CPUT_60|CPUT_70|CPUT_J) -#define HAS_SPL (CPUT_44|CPUT_45|CPUT_70|CPUT_J) -#define HAS_MXPY (CPUT_F|CPUT_34|CPUT_40|CPUT_44|CPUT_45| \ - CPUT_60|CPUT_70|CPUT_J) -#define HAS_MXPS (CPUT_03|CPUT_F|CPUT_34|CPUT_J|CPUT_T) -#define HAS_MFPT (CPUT_F|CPUT_44|CPUT_J|CPUT_T) -#define HAS_CSM (CPUT_44|CPUT_J) -#define HAS_TSWLK (CPUT_J) -#define HAS_PSW (CPUT_04|CPUT_05|CPUT_20|CPUT_F|CPUT_34|CPUT_40| \ - CPUT_44|CPUT_45|CPUT_60|CPUT_70|CPUT_J) -#define HAS_EXPT (CPUT_04|CPUT_05|CPUT_20) -#define HAS_IOSR (CPUT_04|CPUT_05) -#define HAS_2REG (CPUT_45|CPUT_70|CPUT_J) -#define HAS_MMR3 (CPUT_F|CPUT_44|CPUT_45|CPUT_70|CPUT_J) -#define HAS_MMTR (CPUT_45|CPUT_70) -#define HAS_STKLR (CPUT_45|CPUT_60|CPUT_70) -#define HAS_STKLF (CPUT_04|CPUT_05|CPUT_20|CPUT_F|CPUT_34| \ - CPUT_40|CPUT_44|CPUT_J) -#define HAS_SID (CPUT_44|CPUT_45|CPUT_70|CPUT_J) -#define HAS_ODD (CPUT_04|CPUT_05|CPUT_20|CPUT_34|CPUT_40| \ - CPUT_44|CPUT_45|CPUT_60|CPUT_70|CPUT_J) -#define HAS_HALT4 (CPUT_44|CPUT_45|CPUT_70|CPUT_J) -#define HAS_JREG4 (CPUT_03|CPUT_04|CPUT_05|CPUT_20|CPUT_F| \ - CPUT_34|CPUT_40|CPUT_60|CPUT_T) -#define STOP_STKA (CPUT_03|CPUT_04|CPUT_05|CPUT_20|CPUT_34|CPUT_44) -#define HAS_LTCR (CPUT_04|CPUT_05|CPUT_20|CPUT_23P|CPUT_24| \ - CPUT_34|CPUT_40|CPUT_44|CPUT_45|CPUT_60| \ - CPUT_70|CPUT_J) -#define HAS_LTCM (CPUT_04|CPUT_05|CPUT_20|CPUT_24|CPUT_34| \ - CPUT_40|CPUT_44|CPUT_45|CPUT_60|CPUT_70|CPUT_J) - -/* Protection modes */ - -#define MD_KER 0 -#define MD_SUP 1 -#define MD_UND 2 -#define MD_USR 3 - -/* I/O access modes */ - -#define READ 0 -#define READC 1 /* read console */ -#define WRITE 2 -#define WRITEC 3 /* write console */ -#define WRITEB 4 - -/* PSW */ - -#define PSW_V_C 0 /* condition codes */ -#define PSW_V_V 1 -#define PSW_V_Z 2 -#define PSW_V_N 3 -#define PSW_V_TBIT 4 /* trace trap */ -#define PSW_V_IPL 5 /* int priority */ -#define PSW_V_FPD 8 /* first part done */ -#define PSW_V_RS 11 /* register set */ -#define PSW_V_PM 12 /* previous mode */ -#define PSW_V_CM 14 /* current mode */ -#define PSW_CC 017 -#define PSW_TBIT (1 << PSW_V_TBIT) -#define PSW_PM (3 << PSW_V_PM) - -/* FPS */ - -#define FPS_V_C 0 /* condition codes */ -#define FPS_V_V 1 -#define FPS_V_Z 2 -#define FPS_V_N 3 -#define FPS_V_T 5 /* truncate */ -#define FPS_V_L 6 /* long */ -#define FPS_V_D 7 /* double */ -#define FPS_V_IC 8 /* ic err int */ -#define FPS_V_IV 9 /* overflo err int */ -#define FPS_V_IU 10 /* underflo err int */ -#define FPS_V_IUV 11 /* undef var err int */ -#define FPS_V_ID 14 /* int disable */ -#define FPS_V_ER 15 /* error */ - -/* PIRQ */ - -#define PIRQ_PIR1 0001000 -#define PIRQ_PIR2 0002000 -#define PIRQ_PIR3 0004000 -#define PIRQ_PIR4 0010000 -#define PIRQ_PIR5 0020000 -#define PIRQ_PIR6 0040000 -#define PIRQ_PIR7 0100000 -#define PIRQ_IMP 0177356 /* implemented bits */ -#define PIRQ_RW 0177000 /* read/write bits */ - -/* STKLIM */ - -#define STKLIM_RW 0177400 - -/* MMR0 */ - -#define MMR0_MME 0000001 /* mem mgt enable */ -#define MMR0_V_PAGE 1 /* offset to pageno */ -#define MMR0_M_PAGE 077 /* mask for pageno */ -#define MMR0_PAGE (MMR0_M_PAGE << MMR0_V_PAGE) -#define MMR0_IC 0000200 /* instr complete */ -#define MMR0_MAINT 0000400 /* maintenance */ -#define MMR0_TENB 0001000 /* trap enable */ -#define MMR0_TRAP 0010000 /* mem mgt trap */ -#define MMR0_RO 0020000 /* read only error */ -#define MMR0_PL 0040000 /* page lnt error */ -#define MMR0_NR 0100000 /* no access error */ -#define MMR0_FREEZE 0160000 /* if set, no update */ -#define MMR0_WR 0171401 /* writeable bits */ - -/* MMR3 */ - -#define MMR3_UDS 001 /* user dspace enbl */ -#define MMR3_SDS 002 /* super dspace enbl */ -#define MMR3_KDS 004 /* krnl dspace enbl */ -#define MMR3_CSM 010 /* CSM enable */ -#define MMR3_M22E 020 /* 22b mem mgt enbl */ -#define MMR3_BME 040 /* DMA bus map enbl */ - -/* PAR */ - -#define PAR_18B 0007777 /* 18b addressing */ -#define PAR_22B 0177777 /* 22b addressing */ - -/* PDR */ - -#define PDR_ACF 0000007 /* access control */ -#define PDR_ACS 0000006 /* 2b access control */ -#define PDR_ED 0000010 /* expansion dir */ -#define PDR_W 0000100 /* written flag */ -#define PDR_A 0000200 /* access flag */ -#define PDR_PLF 0077400 /* page lnt field */ -#define PDR_NOC 0100000 /* don't cache */ - -#define PDR_PRD 0000003 /* page readable if 2 */ - -/* Virtual address */ - -#define VA_DF 0017777 /* displacement */ -#define VA_BN 0017700 /* block number */ -#define VA_V_APF 13 /* offset to APF */ -#define VA_V_DS 16 /* offset to space */ -#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_PAGSIZE (UBM_M_OFF + 1) /* page size */ -#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 */ -#define CPUE_YEL 0010 /* yellow stack */ -#define CPUE_TMO 0020 /* IO page nxm */ -#define CPUE_NXM 0040 /* memory nxm */ -#define CPUE_ODD 0100 /* odd address */ -#define CPUE_HALT 0200 /* HALT not kernel */ -#define CPUE_IMP 0374 /* implemented bits */ - -/* Floating point accumulators */ - -typedef struct { - uint32 l; /* low 32b */ - uint32 h; /* high 32b */ - } fpac_t; - -/* Device CSRs */ - -#define CSR_V_GO 0 /* go */ -#define CSR_V_IE 6 /* interrupt enable */ -#define CSR_V_DONE 7 /* done */ -#define CSR_V_BUSY 11 /* busy */ -#define CSR_V_ERR 15 /* error */ -#define CSR_GO (1u << CSR_V_GO) -#define CSR_IE (1u << CSR_V_IE) -#define CSR_DONE (1u << CSR_V_DONE) -#define CSR_BUSY (1u << CSR_V_BUSY) -#define CSR_ERR (1u << CSR_V_ERR) - -/* Trap masks, descending priority order, following J-11 - An interrupt summary bit is kept with traps, to minimize overhead -*/ - -#define TRAP_V_RED 0 /* red stk abort 4 */ -#define TRAP_V_ODD 1 /* odd address 4 */ -#define TRAP_V_MME 2 /* mem mgt 250 */ -#define TRAP_V_NXM 3 /* nx memory 4 */ -#define TRAP_V_PAR 4 /* parity err 114 */ -#define TRAP_V_PRV 5 /* priv inst 4 */ -#define TRAP_V_ILL 6 /* illegal inst 10 */ -#define TRAP_V_BPT 7 /* BPT 14 */ -#define TRAP_V_IOT 8 /* IOT 20 */ -#define TRAP_V_EMT 9 /* EMT 30 */ -#define TRAP_V_TRAP 10 /* TRAP 34 */ -#define TRAP_V_TRC 11 /* T bit 14 */ -#define TRAP_V_YEL 12 /* stack 4 */ -#define TRAP_V_PWRFL 13 /* power fail 24 */ -#define TRAP_V_FPE 14 /* fpe 244 */ -#define TRAP_V_MAX 15 /* intr = max trp # */ -#define TRAP_RED (1u << TRAP_V_RED) -#define TRAP_ODD (1u << TRAP_V_ODD) -#define TRAP_MME (1u << TRAP_V_MME) -#define TRAP_NXM (1u << TRAP_V_NXM) -#define TRAP_PAR (1u << TRAP_V_PAR) -#define TRAP_PRV (1u << TRAP_V_PRV) -#define TRAP_ILL (1u << TRAP_V_ILL) -#define TRAP_BPT (1u << TRAP_V_BPT) -#define TRAP_IOT (1u << TRAP_V_IOT) -#define TRAP_EMT (1u << TRAP_V_EMT) -#define TRAP_TRAP (1u << TRAP_V_TRAP) -#define TRAP_TRC (1u << TRAP_V_TRC) -#define TRAP_YEL (1u << TRAP_V_YEL) -#define TRAP_PWRFL (1u << TRAP_V_PWRFL) -#define TRAP_FPE (1u << TRAP_V_FPE) -#define TRAP_INT (1u << TRAP_V_MAX) -#define TRAP_ALL ((1u << TRAP_V_MAX) - 1) /* all traps */ - -#define VEC_RED 0004 /* trap vectors */ -#define VEC_ODD 0004 -#define VEC_MME 0250 -#define VEC_NXM 0004 -#define VEC_PAR 0114 -#define VEC_PRV 0004 -#define VEC_ILL 0010 -#define VEC_BPT 0014 -#define VEC_IOT 0020 -#define VEC_EMT 0030 -#define VEC_TRAP 0034 -#define VEC_TRC 0014 -#define VEC_YEL 0004 -#define VEC_PWRFL 0024 -#define VEC_FPE 0244 - -/* 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_RQ (TRAP_V_MAX + 6) /* RQDX3 panic */ -#define STOP_SANITY (TRAP_V_MAX + 7) /* sanity timer exp */ -#define STOP_DTOFF (TRAP_V_MAX + 8) /* DECtape off reel */ -#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* cond error return */ - -/* Timers */ - -#define TMR_CLK 0 /* line clock */ -#define TMR_PCLK 1 /* KW11P */ - -/* IO parameters */ - -#define DZ_MUXES 4 /* max # of DZ muxes */ -#define DZ_LINES 8 /* lines per DZ mux */ -#define VH_MUXES 4 /* max # of VH muxes */ -#define DLX_LINES 16 /* max # of KL11/DL11's */ -#define DCX_LINES 16 /* max # of DC11's */ -#define MT_MAXFR (1 << 16) /* magtape max rec */ -#define AUTO_LNT 34 /* autoconfig ranks */ -#define DIB_MAX 100 /* max DIBs */ - -#define DEV_V_UBUS (DEV_V_UF + 0) /* Unibus */ -#define DEV_V_QBUS (DEV_V_UF + 1) /* Qbus */ -#define DEV_V_Q18 (DEV_V_UF + 2) /* Qbus with <= 256KB */ -#define DEV_V_FLTA (DEV_V_UF + 3) /* flt addr */ -#define DEV_V_MBUS (DEV_V_UF + 4) /* Massbus */ -#define DEV_V_FFUF (DEV_V_UF + 5) /* first free flag */ -#define DEV_UBUS (1u << DEV_V_UBUS) -#define DEV_QBUS (1u << DEV_V_QBUS) -#define DEV_Q18 (1u << DEV_V_Q18) -#define DEV_FLTA (1u << DEV_V_FLTA) -#define DEV_MBUS (1u << DEV_V_MBUS) - -#define DEV_RDX 8 /* default device radix */ - -/* Device information block */ - -#define VEC_DEVMAX 4 /* max device vec */ - -struct pdp_dib { - uint32 ba; /* base addr */ - uint32 lnt; /* length */ - t_stat (*rd)(int32 *dat, int32 ad, int32 md); - t_stat (*wr)(int32 dat, int32 ad, int32 md); - int32 vnum; /* vectors: number */ - int32 vloc; /* locator */ - int32 vec; /* value */ - int32 (*ack[VEC_DEVMAX])(void); /* ack routines */ - }; - -typedef struct pdp_dib DIB; - -/* I/O page layout - XUB, RQB,RQC,RQD float based on number of DZ's */ - -#define IOBA_DZ (IOPAGEBASE + 000100) /* DZ11 */ -#define IOLN_DZ 010 -#define IOBA_XUB (IOPAGEBASE + 000330 + (020 * (DZ_MUXES / 2))) -#define IOLN_XUB 010 -#define IOBA_RQB (IOPAGEBASE + 000334 + (020 * (DZ_MUXES / 2))) -#define IOLN_RQB 004 -#define IOBA_RQC (IOBA_RQB + IOLN_RQB) -#define IOLN_RQC 004 -#define IOBA_RQD (IOBA_RQC + IOLN_RQC) -#define IOLN_RQD 004 -#define IOBA_VH (IOPAGEBASE + 000440) /* DHQ11 */ -#define IOLN_VH 020 -#define IOBA_UCA (IOPAGEBASE + 007770) /* UC15 DR11 #1 */ -#define IOLN_UCA 006 -#define IOBA_UCB (IOPAGEBASE + 007760) /* UC15 DR11 #2 */ -#define IOLN_UCB 006 -#define IOBA_UBM (IOPAGEBASE + 010200) /* Unibus map */ -#define IOLN_UBM (UBM_LNT_LW * sizeof (int32)) -#define IOBA_RS (IOPAGEBASE + 012040) /* RHC: RS03/RS04 */ -#define IOLN_RS 034 -#define IOBA_KG (IOPAGEBASE + 010700) /* KG11-A */ -#define IOLN_KG 006 -#define IOBA_RQ (IOPAGEBASE + 012150) /* RQDX3 */ -#define IOLN_RQ 004 -#define IOBA_SUP (IOPAGEBASE + 012200) /* supervisor APR's */ -#define IOLN_SUP 0100 -#define IOBA_KIPDR (IOPAGEBASE + 012300) /* kernel APR's */ -#define IOLN_KIPDR 020 -#define IOBA_KDPDR (IOPAGEBASE + 012320) -#define IOLN_KDPDR 020 -#define IOBA_KIPAR (IOPAGEBASE + 012340) -#define IOLN_KIPAR 020 -#define IOBA_KDPAR (IOPAGEBASE + 012360) -#define IOLN_KDPAR 020 -#define IOBA_TU (IOPAGEBASE + 012440) /* RHB: TU */ -#define IOLN_TU 040 -#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_PCLK (IOPAGEBASE + 012540) /* KW11P */ -#define IOLN_PCLK 006 -#define IOBA_DC (IOPAGEBASE + 014000) /* DC11 */ -#define IOLN_DC (DCX_LINES * 010) -#define IOBA_RL (IOPAGEBASE + 014400) /* RL11 */ -#define IOLN_RL 012 -#define IOBA_XQ (IOPAGEBASE + 014440) /* DEQNA/DELQA */ -#define IOLN_XQ 020 -#define IOBA_XQB (IOPAGEBASE + 014460) /* 2nd DEQNA/DELQA */ -#define IOLN_XQB 020 -#define IOBA_TQ (IOPAGEBASE + 014500) /* TMSCP */ -#define IOLN_TQ 004 -#define IOBA_XU (IOPAGEBASE + 014510) /* DEUNA/DELUA */ -#define IOLN_XU 010 -#define IOBA_DL (IOPAGEBASE + 016500) /* extra KL11/DL11 */ -#define IOLN_DL (DLX_LINES * 010) -#define IOBA_RP (IOPAGEBASE + 016700) /* RHA: RP/RM */ -#define IOLN_RP 054 -#define IOBA_CR (IOPAGEBASE + 017160) /* CD/CR/CM */ -#define IOLN_CR 010 -#define IOBA_RX (IOPAGEBASE + 017170) /* RX11 */ -#define IOLN_RX 004 -#define IOBA_RY (IOPAGEBASE + 017170) /* RY11 */ -#define IOLN_RY 004 -#define IOBA_KE (IOPAGEBASE + 017300) /* KE11-A */ -#define IOLN_KE 020 -#define IOBA_TC (IOPAGEBASE + 017340) /* TC11 */ -#define IOLN_TC 012 -#define IOBA_QDSS (IOPAGEBASE + 017400) /* QDSS */ -#define IOLN_QDSS 002 -#define IOBA_RK (IOPAGEBASE + 017400) /* RK11 */ -#define IOLN_RK 020 -#define IOBA_RC (IOPAGEBASE + 017440) /* RC11/RS64 */ -#define IOLN_RC 020 -#define IOBA_HK (IOPAGEBASE + 017440) /* RK611 */ -#define IOLN_HK 040 -#define IOBA_RF (IOPAGEBASE + 017460) /* RF11 */ -#define IOLN_RF 020 -#define IOBA_TA (IOPAGEBASE + 017500) /* TA11 */ -#define IOLN_TA 004 -#define IOBA_LPT (IOPAGEBASE + 017514) /* LP11 */ -#define IOLN_LPT 004 -#define IOBA_CTL (IOPAGEBASE + 017520) /* board ctrl */ -#define IOLN_CTL 010 -#define IOBA_CLK (IOPAGEBASE + 017546) /* KW11L */ -#define IOLN_CLK 002 -#define IOBA_PTR (IOPAGEBASE + 017550) /* PC11 reader */ -#define IOLN_PTR 004 -#define IOBA_PTP (IOPAGEBASE + 017554) /* PC11 punch */ -#define IOLN_PTP 004 -#define IOBA_TTI (IOPAGEBASE + 017560) /* DL11 rcv */ -#define IOLN_TTI 004 -#define IOBA_TTO (IOPAGEBASE + 017564) /* DL11 xmt */ -#define IOLN_TTO 004 -#define IOBA_SR (IOPAGEBASE + 017570) /* SR */ -#define IOLN_SR 002 -#define IOBA_MMR012 (IOPAGEBASE + 017572) /* MMR0-2 */ -#define IOLN_MMR012 006 -#define IOBA_UIPDR (IOPAGEBASE + 017600) /* user APR's */ -#define IOLN_UIPDR 020 -#define IOBA_UDPDR (IOPAGEBASE + 017620) -#define IOLN_UDPDR 020 -#define IOBA_UIPAR (IOPAGEBASE + 017640) -#define IOLN_UIPAR 020 -#define IOBA_UDPAR (IOPAGEBASE + 017660) -#define IOLN_UDPAR 020 -#define IOBA_GPR (IOPAGEBASE + 017700) /* GPR's */ -#define IOLN_GPR 010 -#define IOBA_UCTL (IOPAGEBASE + 017730) /* UBA ctrl */ -#define IOLN_UCTL 010 -#define IOBA_CPU (IOPAGEBASE + 017740) /* CPU reg */ -#define IOLN_CPU 036 -#define IOBA_PSW (IOPAGEBASE + 017776) /* PSW */ -#define IOLN_PSW 002 - -/* Interrupt assignments; within each level, priority is right to left - PIRQn has the highest priority with a level and is always bit <0> - On level 6, the clock is second highest priority */ - -#define IPL_HLVL 8 /* # int levels */ -#define IPL_HMIN 4 /* lowest IO int level */ - -#define INT_V_PIR7 0 /* BR7 */ -#define INT_V_UCA 1 - -#define INT_V_PIR6 0 /* BR6 */ -#define INT_V_CLK 1 -#define INT_V_PCLK 2 -#define INT_V_DTA 3 -#define INT_V_TA 4 -#define INT_V_CR 5 /* CR11 */ - -#define INT_V_PIR5 0 /* BR5 */ -#define INT_V_RK 1 -#define INT_V_RL 2 -#define INT_V_RX 3 -#define INT_V_TM 4 -#define INT_V_RP 5 -#define INT_V_TS 6 -#define INT_V_HK 7 -#define INT_V_RQ 8 -#define INT_V_DZRX 9 -#define INT_V_DZTX 10 -#define INT_V_TQ 11 -#define INT_V_RY 12 -#define INT_V_XQ 13 -#define INT_V_XU 14 -#define INT_V_TU 15 -#define INT_V_RF 16 -#define INT_V_RC 17 -#define INT_V_RS 18 -#define INT_V_UCB 19 - -#define INT_V_PIR4 0 /* BR4 */ -#define INT_V_TTI 1 -#define INT_V_TTO 2 -#define INT_V_PTR 3 -#define INT_V_PTP 4 -#define INT_V_LPT 5 -#define INT_V_VHRX 6 -#define INT_V_VHTX 7 -#define INT_V_CD 8 /* CD11 */ -#define INT_V_DLI 9 -#define INT_V_DLO 10 -#define INT_V_DCI 11 -#define INT_V_DCO 12 - -#define INT_V_PIR3 0 /* BR3 */ -#define INT_V_PIR2 0 /* BR2 */ -#define INT_V_PIR1 0 /* BR1 */ - -#define INT_PIR7 (1u << INT_V_PIR7) -#define INT_UCB (1u << INT_V_UCB) -#define INT_PIR6 (1u << INT_V_PIR6) -#define INT_CLK (1u << INT_V_CLK) -#define INT_PCLK (1u << INT_V_PCLK) -#define INT_DTA (1u << INT_V_DTA) -#define INT_TA (1u << INT_V_TA) -#define INT_CR (1u << INT_V_CR) -#define INT_PIR5 (1u << INT_V_PIR5) -#define INT_RK (1u << INT_V_RK) -#define INT_RL (1u << INT_V_RL) -#define INT_RX (1u << INT_V_RX) -#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_RQ (1u << INT_V_RQ) -#define INT_DZRX (1u << INT_V_DZRX) -#define INT_DZTX (1u << INT_V_DZTX) -#define INT_TQ (1u << INT_V_TQ) -#define INT_RY (1u << INT_V_RY) -#define INT_XQ (1u << INT_V_XQ) -#define INT_XU (1u << INT_V_XU) -#define INT_TU (1u << INT_V_TU) -#define INT_RF (1u << INT_V_RF) -#define INT_RC (1u << INT_V_RC) -#define INT_RS (1u << INT_V_RS) -#define INT_UCA (1u << INT_V_UCA) -#define INT_PIR4 (1u << INT_V_PIR4) -#define INT_TTI (1u << INT_V_TTI) -#define INT_TTO (1u << INT_V_TTO) -#define INT_PTR (1u << INT_V_PTR) -#define INT_PTP (1u << INT_V_PTP) -#define INT_LPT (1u << INT_V_LPT) -#define INT_VHRX (1u << INT_V_VHRX) -#define INT_VHTX (1u << INT_V_VHTX) -#define INT_CD (1u << INT_V_CD) -#define INT_DLI (1u << INT_V_DLI) -#define INT_DLO (1u << INT_V_DLO) -#define INT_DCI (1u << INT_V_DCI) -#define INT_DCO (1u << INT_V_DCO) -#define INT_PIR3 (1u << INT_V_PIR3) -#define INT_PIR2 (1u << INT_V_PIR2) -#define INT_PIR1 (1u << INT_V_PIR1) - -#define INT_INTERNAL7 (INT_PIR7) -#define INT_INTERNAL6 (INT_PIR6 | INT_CLK) -#define INT_INTERNAL5 (INT_PIR5) -#define INT_INTERNAL4 (INT_PIR4) -#define INT_INTERNAL3 (INT_PIR3) -#define INT_INTERNAL2 (INT_PIR2) -#define INT_INTERNAL1 (INT_PIR1) - -#define IPL_UCB 7 /* int pri levels */ -#define IPL_CLK 6 -#define IPL_PCLK 6 -#define IPL_DTA 6 -#define IPL_TA 6 -#define IPL_CR 6 -#define IPL_RK 5 -#define IPL_RL 5 -#define IPL_RX 5 -#define IPL_TM 5 -#define IPL_RP 5 -#define IPL_TS 5 -#define IPL_HK 5 -#define IPL_RQ 5 -#define IPL_DZRX 5 -#define IPL_DZTX 5 -#define IPL_TQ 5 -#define IPL_RY 5 -#define IPL_XQ 5 -#define IPL_XU 5 -#define IPL_TU 5 -#define IPL_RF 5 -#define IPL_RC 5 -#define IPL_RS 5 -#define IPL_UCA 5 -#define IPL_PTR 4 -#define IPL_PTP 4 -#define IPL_TTI 4 -#define IPL_TTO 4 -#define IPL_LPT 4 -#define IPL_VHRX 4 -#define IPL_VHTX 4 -#define IPL_CD 4 -#define IPL_DLI 4 -#define IPL_DLO 4 -#define IPL_DCI 4 -#define IPL_DCO 4 - -#define IPL_PIR7 7 -#define IPL_PIR6 6 -#define IPL_PIR5 5 -#define IPL_PIR4 4 -#define IPL_PIR3 3 -#define IPL_PIR2 2 -#define IPL_PIR1 1 - -/* Device 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_PCLK 0104 -#define VEC_XQ 0120 -#define VEC_XU 0120 -#define VEC_RQ 0154 -#define VEC_RL 0160 -#define VEC_LPT 0200 -#define VEC_RF 0204 -#define VEC_RS 0204 -#define VEC_HK 0210 -#define VEC_RC 0210 -#define VEC_RK 0220 -#define VEC_DTA 0214 -#define VEC_TM 0224 -#define VEC_TS 0224 -#define VEC_TU 0224 -#define VEC_CR 0230 -#define VEC_RP 0254 -#define VEC_TQ 0260 -#define VEC_TA 0260 -#define VEC_RX 0264 -#define VEC_RY 0264 -#define VEC_DLI 0300 -#define VEC_DLO 0304 -#define VEC_DCI 0300 -#define VEC_DCO 0304 -#define VEC_DZRX 0300 -#define VEC_DZTX 0304 -#define VEC_VHRX 0310 -#define VEC_CD 0230 -#define VEC_VHTX 0314 -#define VEC_UCA 0300 -#define VEC_UCB 0310 - -/* Interrupt macros */ - -#define IVCL(dv) ((IPL_##dv * 32) + INT_V_##dv) -#define IREQ(dv) int_req[IPL_##dv] -#define SET_INT(dv) int_req[IPL_##dv] = int_req[IPL_##dv] | (INT_##dv) -#define CLR_INT(dv) int_req[IPL_##dv] = int_req[IPL_##dv] & ~(INT_##dv) - -/* Massbus definitions */ - -#define MBA_NUM 3 /* number of MBA's */ -#define MBA_RP 0 /* MBA for RP */ -#define MBA_TU 1 /* MBA for TU */ -#define MBA_RS 2 /* MBA for RS */ -#define MBA_RMASK 037 /* max 32 reg */ -#define MBE_NXD 1 /* nx drive */ -#define MBE_NXR 2 /* nx reg */ -#define MBE_GOE 3 /* err on GO */ - -/* CPU and FPU macros */ - -#define update_MM ((MMR0 & MMR0_FREEZE) == 0) -#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] - -/* Function prototypes */ - -int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf); -int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf); -int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf); -int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf); - -int32 mba_rdbufW (uint32 mbus, int32 bc, uint16 *buf); -int32 mba_wrbufW (uint32 mbus, int32 bc, uint16 *buf); -int32 mba_chbufW (uint32 mbus, int32 bc, uint16 *buf); -int32 mba_get_bc (uint32 mbus); -int32 mba_get_csr (uint32 mbus); -void mba_upd_ata (uint32 mbus, uint32 val); -void mba_set_exc (uint32 mbus); -void mba_set_don (uint32 mbus); -void mba_set_enbdis (uint32 mb, t_bool dis); -t_stat mba_show_num (FILE *st, UNIT *uptr, int32 val, void *desc); - -int32 clk_cosched (int32 wait); - -void cpu_set_boot (int32 pc); - -#include "pdp11_io_lib.h" - -#if defined (UC15) /* UC15 */ -#define INIMODEL MOD_1105 -#define INIOPTNS SOP_1105 -#define INIMEMSIZE 00040000 /* 16KB */ -#define ADDR_IS_MEM(x) (((uint32) (x)) < uc15_memsize) - -#define RdMemW(pa) uc15_RdMemW (pa) -#define RdMemB(pa) uc15_RdMemB (pa) -#define WrMemW(pa,d) uc15_WrMemW (pa, d) -#define WrMemB(pa, d) uc15_WrMemB (pa, d) - -uint32 uc15_memsize; -int32 uc15_RdMemW (int32 pa); -int32 uc15_RdMemB (int32 pa); -void uc15_WrMemW (int32 pa, int32 d); -void uc15_WrMemB (int32 pa, int32 d); -int32 Map_Read18 (uint32 ba, int32 bc, uint32 *buf); -int32 Map_Write18 (uint32 ba, int32 bc, uint32 *buf); - -#else /* PDP-11 */ - -#define INIMODEL MOD_1173 -#define INIOPTNS SOP_1173 -#define INIMEMSIZE 001000000 /* 2**18 */ -#define ADDR_IS_MEM(x) (((t_addr) (x)) < MEMSIZE) - -#define RdMemW(pa) (M[(pa) >> 1]) -#define RdMemB(pa) ((((pa) & 1)? M[(pa) >> 1] >> 8: M[(pa) >> 1]) & 0377) -#define WrMemW(pa,d) M[(pa) >> 1] = (d) -#define WrMemB(pa,d) M[(pa) >> 1] = ((pa) & 1)? \ - ((M[(pa) >> 1] & 0377) | (((d) & 0377) << 8)): \ - ((M[(pa) >> 1] & ~0377) | ((d) & 0377)) - -#endif - -#endif diff --git a/PDP11/pdp11_dl.c b/PDP11/pdp11_dl.c deleted file mode 100644 index 4e2646c2..00000000 --- a/PDP11/pdp11_dl.c +++ /dev/null @@ -1,576 +0,0 @@ -/* pdp11_dl.c: PDP-11 multiple terminal interface simulator - - Copyright (c) 1993-2013, 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. - - dli,dlo DL11 terminal input/output - - 11-Oct-2013 RMS Poll DLI immediately after attach to pick up connect - 18-Apr-2012 RMS Modified to use clock coscheduling - 17-Aug-2011 RMS Added AUTOCONFIGURE modifier - 19-Nov-2008 RMS Revised for common TMXR show routines - Revised to autoconfigure vectors - 20-May-2008 RMS Added modem control support -*/ - -#if defined (VM_PDP10) /* PDP10 version */ -#error "DL11 is not supported on the PDP-10!" - -#elif defined (VM_VAX) /* VAX version */ -#error "DL11 is not supported on the VAX!" - -#else /* PDP-11 version */ -#include "pdp11_defs.h" -#endif -#include "sim_sock.h" -#include "sim_tmxr.h" - -#define DLX_MASK (DLX_LINES - 1) -#define DLI_RCI 0 /* rcv ints */ -#define DLI_DSI 1 /* dset ints */ - -/* Modem control */ - -#define DLX_V_MDM (TTUF_V_UF + 0) -#define DLX_MDM (1u << DLX_V_MDM) - -/* registers */ - -#define DLICSR_DSI 0100000 /* dataset int, RO */ -#define DLICSR_RNG 0040000 /* ring, RO */ -#define DLICSR_CTS 0020000 /* CTS, RO */ -#define DLICSR_CDT 0010000 /* CDT, RO */ -#define DLICSR_SEC 0002000 /* sec rcv, RONI */ -#define DLICSR_DSIE 0000040 /* DSI ie, RW */ -#define DLICSR_SECX 0000010 /* sec xmt, RWNI */ -#define DLICSR_RTS 0000004 /* RTS, RW */ -#define DLICSR_DTR 0000002 /* DTR, RW */ -#define DLICSR_RD (CSR_DONE|CSR_IE) /* DL11C */ -#define DLICSR_WR (CSR_IE) -#define DLICSR_RD_M (DLICSR_DSI|DLICSR_RNG|DLICSR_CTS|DLICSR_CDT|DLICSR_SEC| \ - CSR_DONE|CSR_IE|DLICSR_DSIE|DLICSR_SECX|DLICSR_RTS|DLICSR_DTR) -#define DLICSR_WR_M (CSR_IE|DLICSR_DSIE|DLICSR_SECX|DLICSR_RTS|DLICSR_DTR) -#define DLIBUF_ERR 0100000 -#define DLIBUF_OVR 0040000 -#define DLIBUF_RBRK 0020000 -#define DLIBUF_RD (DLIBUF_ERR|DLIBUF_OVR|DLIBUF_RBRK|0377) -#define DLOCSR_MNT 0000004 /* maint, RWNI */ -#define DLOCSR_XBR 0000001 /* xmit brk, RWNI */ -#define DLOCSR_RD (CSR_DONE|CSR_IE|DLOCSR_MNT|DLOCSR_XBR) -#define DLOCSR_WR (CSR_IE|DLOCSR_MNT|DLOCSR_XBR) - -extern int32 int_req[IPL_HLVL]; -extern int32 tmxr_poll; - -uint16 dli_csr[DLX_LINES] = { 0 }; /* control/status */ -uint16 dli_buf[DLX_LINES] = { 0 }; -uint32 dli_ireq[2] = { 0, 0}; -uint16 dlo_csr[DLX_LINES] = { 0 }; /* control/status */ -uint8 dlo_buf[DLX_LINES] = { 0 }; -uint32 dlo_ireq = 0; -TMLN dlx_ldsc[DLX_LINES] = { {0} }; /* line descriptors */ -TMXR dlx_desc = { DLX_LINES, 0, 0, dlx_ldsc }; /* mux descriptor */ - -t_stat dlx_rd (int32 *data, int32 PA, int32 access); -t_stat dlx_wr (int32 data, int32 PA, int32 access); -t_stat dlx_reset (DEVICE *dptr); -t_stat dli_svc (UNIT *uptr); -t_stat dlo_svc (UNIT *uptr); -t_stat dlx_attach (UNIT *uptr, char *cptr); -t_stat dlx_detach (UNIT *uptr); -t_stat dlx_set_lines (UNIT *uptr, int32 val, char *cptr, void *desc); -void dlx_enbdis (int32 dis); -void dli_clr_int (int32 ln, uint32 wd); -void dli_set_int (int32 ln, uint32 wd); -int32 dli_iack (void); -void dlo_clr_int (int32 ln); -void dlo_set_int (int32 ln); -int32 dlo_iack (void); -void dlx_reset_ln (int32 ln); - -/* DLI data structures - - dli_dev DLI device descriptor - dli_unit DLI unit descriptor - dli_reg DLI register list -*/ - -DIB dli_dib = { - IOBA_DL, IOLN_DL, &dlx_rd, &dlx_wr, - 2, IVCL (DLI), VEC_DLI, { &dli_iack, &dlo_iack } - }; - -UNIT dli_unit = { UDATA (&dli_svc, 0, 0), SERIAL_IN_WAIT }; - -REG dli_reg[] = { - { BRDATA (BUF, dli_buf, DEV_RDX, 16, DLX_LINES) }, - { BRDATA (CSR, dli_csr, DEV_RDX, 16, DLX_LINES) }, - { DRDATA (TIME, dli_unit.wait, 24), PV_LEFT }, - { GRDATA (IREQ, dli_ireq[DLI_RCI], DEV_RDX, DLX_LINES, 0) }, - { GRDATA (DSI, dli_ireq[DLI_DSI], DEV_RDX, DLX_LINES, 0) }, - { DRDATA (LINES, dlx_desc.lines, 6), REG_HRO }, - { GRDATA (DEVADDR, dli_dib.ba, DEV_RDX, 32, 0), REG_HRO }, - { GRDATA (DEVIOLN, dli_dib.lnt, DEV_RDX, 32, 0), REG_HRO }, - { GRDATA (DEVVEC, dli_dib.vec, DEV_RDX, 16, 0), REG_HRO }, - { NULL } - }; - -MTAB dli_mod[] = { - { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", - &tmxr_dscln, NULL, &dlx_desc }, - { UNIT_ATT, UNIT_ATT, "summary", NULL, - NULL, &tmxr_show_summ, (void *) &dlx_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, - NULL, &tmxr_show_cstat, (void *) &dlx_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, - NULL, &tmxr_show_cstat, (void *) &dlx_desc }, - { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, - &set_addr, &show_addr, NULL }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE", - &set_addr_flt, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 1, "VECTOR", NULL, - &set_vec, &show_vec_mux, (void *) &dlx_desc }, - { MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES", - &dlx_set_lines, &tmxr_show_lines, (void *) &dlx_desc }, - { 0 } - }; - -DEVICE dli_dev = { - "DLI", &dli_unit, dli_reg, dli_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &dlx_reset, - NULL, &dlx_attach, &dlx_detach, - &dli_dib, DEV_FLTA | DEV_UBUS | DEV_QBUS | DEV_DISABLE | DEV_DIS - }; - -/* DLO data structures - - dlo_dev DLO device descriptor - dlo_unit DLO unit descriptor - dlo_reg DLO register list -*/ - -UNIT dlo_unit[] = { - { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT }, - { UDATA (&dlo_svc, TT_MODE_UC, 0), SERIAL_OUT_WAIT } - }; - -REG dlo_reg[] = { - { BRDATA (BUF, dlo_buf, DEV_RDX, 8, DLX_LINES) }, - { BRDATA (CSR, dlo_csr, DEV_RDX, 16, DLX_LINES) }, - { GRDATA (IREQ, dlo_ireq, DEV_RDX, DLX_LINES, 0) }, - { URDATA (TIME, dlo_unit[0].wait, 10, 31, 0, - DLX_LINES, PV_LEFT) }, - { NULL } - }; - -MTAB dlo_mod[] = { - { TT_MODE, TT_MODE_UC, "UC", "UC", NULL }, - { TT_MODE, TT_MODE_7B, "7b", "7B", NULL }, - { TT_MODE, TT_MODE_8B, "8b", "8B", NULL }, - { TT_MODE, TT_MODE_7P, "7p", "7P", NULL }, - { DLX_MDM, 0, "no dataset", "NODATASET", NULL }, - { DLX_MDM, DLX_MDM, "dataset", "DATASET", NULL }, - { MTAB_XTD|MTAB_VUN, 0, NULL, "DISCONNECT", - &tmxr_dscln, NULL, &dlx_desc }, - { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, "LOG", "LOG", - &tmxr_set_log, &tmxr_show_log, &dlx_desc }, - { MTAB_XTD|MTAB_VUN|MTAB_NC, 0, NULL, "NOLOG", - &tmxr_set_nolog, NULL, &dlx_desc }, - { 0 } - }; - -DEVICE dlo_dev = { - "DLO", dlo_unit, dlo_reg, dlo_mod, - DLX_LINES, 10, 31, 1, 8, 8, - NULL, NULL, &dlx_reset, - NULL, NULL, NULL, - NULL, DEV_UBUS | DEV_QBUS | DEV_DISABLE | DEV_DIS - }; - -/* Terminal input routines */ - -t_stat dlx_rd (int32 *data, int32 PA, int32 access) -{ -int32 ln = ((PA - dli_dib.ba) >> 3) & DLX_MASK; - -switch ((PA >> 1) & 03) { /* decode PA<2:1> */ - - case 00: /* tti csr */ - *data = dli_csr[ln] & - ((dlo_unit[ln].flags & DLX_MDM)? DLICSR_RD_M: DLICSR_RD); - dli_csr[ln] &= ~DLICSR_DSI; /* clr DSI flag */ - dli_clr_int (ln, DLI_DSI); /* clr dset int req */ - return SCPE_OK; - - case 01: /* tti buf */ - *data = dli_buf[ln] & DLIBUF_RD; - dli_csr[ln] &= ~CSR_DONE; /* clr rcv done */ - dli_clr_int (ln, DLI_RCI); /* clr rcv int req */ - sim_activate_abs (&dli_unit, dli_unit.wait); - return SCPE_OK; - - case 02: /* tto csr */ - *data = dlo_csr[ln] & DLOCSR_RD; - return SCPE_OK; - - case 03: /* tto buf */ - *data = dlo_buf[ln]; - return SCPE_OK; - } /* end switch PA */ - -return SCPE_NXM; -} - -t_stat dlx_wr (int32 data, int32 PA, int32 access) -{ -int32 ln = ((PA - dli_dib.ba) >> 3) & DLX_MASK; -TMLN *lp = &dlx_ldsc[ln]; - -switch ((PA >> 1) & 03) { /* decode PA<2:1> */ - - case 00: /* tti csr */ - if (PA & 1) /* odd byte RO */ - return SCPE_OK; - if ((data & CSR_IE) == 0) - dli_clr_int (ln, DLI_RCI); - else if ((dli_csr[ln] & (CSR_DONE + CSR_IE)) == CSR_DONE) - dli_set_int (ln, DLI_RCI); - if (dlo_unit[ln].flags & DLX_MDM) { /* modem control */ - if ((data & DLICSR_DSIE) == 0) - dli_clr_int (ln, DLI_DSI); - else if ((dli_csr[ln] & (DLICSR_DSI|DLICSR_DSIE)) == DLICSR_DSI) - dli_set_int (ln, DLI_DSI); - if ((data ^ dli_csr[ln]) & DLICSR_DTR) { /* DTR change? */ - if ((data & DLICSR_DTR) && lp->conn) { /* setting DTR? */ - dli_csr[ln] = (dli_csr[ln] & ~DLICSR_RNG) | - (DLICSR_CDT|DLICSR_CTS|DLICSR_DSI); - if (data & DLICSR_DSIE) /* if ie, req int */ - dli_set_int (ln, DLI_DSI); - } /* end DTR 0->1 + ring */ - else { /* clearing DTR */ - if (lp->conn) { /* connected? */ - tmxr_linemsg (lp, "\r\nLine hangup\r\n"); - tmxr_reset_ln (lp); /* reset line */ - if (dli_csr[ln] & DLICSR_CDT) { /* carrier det? */ - dli_csr[ln] |= DLICSR_DSI; - if (data & DLICSR_DSIE) /* if ie, req int */ - dli_set_int (ln, DLI_DSI); - } - } - dli_csr[ln] &= ~(DLICSR_CDT|DLICSR_RNG|DLICSR_CTS); - /* clr CDT,RNG,CTS */ - } /* end DTR 1->0 */ - } /* end DTR chg */ - dli_csr[ln] = (uint16) ((dli_csr[ln] & ~DLICSR_WR_M) | (data & DLICSR_WR_M)); - } /* end modem */ - dli_csr[ln] = (uint16) ((dli_csr[ln] & ~DLICSR_WR) | (data & DLICSR_WR)); - return SCPE_OK; - - case 01: /* tti buf */ - return SCPE_OK; - - case 02: /* tto csr */ - if (PA & 1) - return SCPE_OK; - if ((data & CSR_IE) == 0) - dlo_clr_int (ln); - else if ((dlo_csr[ln] & (CSR_DONE + CSR_IE)) == CSR_DONE) - dlo_set_int (ln); - dlo_csr[ln] = (uint16) ((dlo_csr[ln] & ~DLOCSR_WR) | (data & DLOCSR_WR)); - return SCPE_OK; - - case 03: /* tto buf */ - if ((PA & 1) == 0) - dlo_buf[ln] = data & 0377; - dlo_csr[ln] &= ~CSR_DONE; - dlo_clr_int (ln); - sim_activate (&dlo_unit[ln], dlo_unit[ln].wait); - return SCPE_OK; - } /* end switch PA */ - -return SCPE_NXM; -} - -/* Terminal input service */ - -t_stat dli_svc (UNIT *uptr) -{ -int32 ln, c, temp; - -if ((uptr->flags & UNIT_ATT) == 0) /* attached? */ - return SCPE_OK; -sim_activate (uptr, clk_cosched (tmxr_poll)); /* continue poll */ -ln = tmxr_poll_conn (&dlx_desc); /* look for connect */ -if (ln >= 0) { /* got one? rcv enb */ - dlx_ldsc[ln].rcve = 1; - if (dlo_unit[ln].flags & DLX_MDM) { /* modem control? */ - if (dli_csr[ln] & DLICSR_DTR) /* DTR already set? */ - dli_csr[ln] |= (DLICSR_CDT|DLICSR_CTS|DLICSR_DSI); - else dli_csr[ln] |= (DLICSR_RNG|DLICSR_DSI); /* no, ring */ - if (dli_csr[ln] & DLICSR_DSIE) /* if ie, */ - dli_set_int (ln, DLI_DSI); /* req int */ - } /* end modem */ - } /* end new conn */ -tmxr_poll_rx (&dlx_desc); /* poll for input */ -for (ln = 0; ln < DLX_LINES; ln++) { /* loop thru lines */ - if (dlx_ldsc[ln].conn) { /* connected? */ - if ((temp = tmxr_getc_ln (&dlx_ldsc[ln]))) { /* get char */ - if (temp & SCPE_BREAK) /* break? */ - c = DLIBUF_ERR|DLIBUF_RBRK; - else c = sim_tt_inpcvt (temp, TT_GET_MODE (dlo_unit[ln].flags)); - if (dli_csr[ln] & CSR_DONE) - c |= DLIBUF_ERR|DLIBUF_OVR; - else dli_csr[ln] |= CSR_DONE; - if (dli_csr[ln] & CSR_IE) - dli_set_int (ln, DLI_RCI); - dli_buf[ln] = (uint16)c; - } - } - else if (dlo_unit[ln].flags & DLX_MDM) { /* discpnn & modem? */ - if (dli_csr[ln] & DLICSR_CDT) { /* carrier detect? */ - dli_csr[ln] |= DLICSR_DSI; /* dataset change */ - if (dli_csr[ln] & DLICSR_DSIE) /* if ie, */ - dli_set_int (ln, DLI_DSI); /* req int */ - } - dli_csr[ln] &= ~(DLICSR_CDT|DLICSR_RNG|DLICSR_CTS); - /* clr CDT,RNG,CTS */ - } - } -return SCPE_OK; -} - -/* Terminal output service */ - -t_stat dlo_svc (UNIT *uptr) -{ -int32 c; -int32 ln = uptr - dlo_unit; /* line # */ - -if (dlx_ldsc[ln].conn) { /* connected? */ - if (dlx_ldsc[ln].xmte) { /* tx enabled? */ - TMLN *lp = &dlx_ldsc[ln]; /* get line */ - c = sim_tt_outcvt (dlo_buf[ln], TT_GET_MODE (dlo_unit[ln].flags)); - if (c >= 0) /* output char */ - tmxr_putc_ln (lp, c); - tmxr_poll_tx (&dlx_desc); /* poll xmt */ - } - else { - tmxr_poll_tx (&dlx_desc); /* poll xmt */ - sim_activate (uptr, dlo_unit[ln].wait); /* wait */ - return SCPE_OK; - } - } -dlo_csr[ln] |= CSR_DONE; /* set done */ -if (dlo_csr[ln] & CSR_IE) - dlo_set_int (ln); -return SCPE_OK; -} - -/* Interrupt routines */ - -void dli_clr_int (int32 ln, uint32 wd) -{ -dli_ireq[wd] &= ~(1 << ln); /* clr rcv/dset int */ -if ((dli_ireq[DLI_RCI] | dli_ireq[DLI_DSI]) == 0) /* all clr? */ - CLR_INT (DLI); /* all clr? */ -else SET_INT (DLI); /* no, set intr */ -return; -} - -void dli_set_int (int32 ln, uint32 wd) -{ -dli_ireq[wd] |= (1 << ln); /* set rcv/dset int */ -SET_INT (DLI); /* set master intr */ -return; -} - -int32 dli_iack (void) -{ -int32 ln; - -for (ln = 0; ln < DLX_LINES; ln++) { /* find 1st line */ - if ((dli_ireq[DLI_RCI] | dli_ireq[DLI_DSI]) & (1 << ln)) { - dli_clr_int (ln, DLI_RCI); /* clr both req */ - dli_clr_int (ln, DLI_DSI); - return (dli_dib.vec + (ln * 010)); /* return vector */ - } - } -return 0; -} - -void dlo_clr_int (int32 ln) -{ -dlo_ireq &= ~(1 << ln); /* clr xmit int */ -if (dlo_ireq == 0) /* all clr? */ - CLR_INT (DLO); -else SET_INT (DLO); /* no, set intr */ -return; -} - -void dlo_set_int (int32 ln) -{ -dlo_ireq |= (1 << ln); /* set xmit int */ -SET_INT (DLO); /* set master intr */ -return; -} - -int32 dlo_iack (void) -{ -int32 ln; - -for (ln = 0; ln < DLX_LINES; ln++) { /* find 1st line */ - if (dlo_ireq & (1 << ln)) { - dlo_clr_int (ln); /* clear intr */ - return (dli_dib.vec + (ln * 010) + 4); /* return vector */ - } - } -return 0; -} - -/* Reset */ - -t_stat dlx_reset (DEVICE *dptr) -{ -int32 ln; - -dlx_enbdis (dptr->flags & DEV_DIS); /* sync enables */ -sim_cancel (&dli_unit); /* assume stop */ -if (dli_unit.flags & UNIT_ATT) /* if attached, */ - sim_activate (&dli_unit, tmxr_poll); /* activate */ -for (ln = 0; ln < DLX_LINES; ln++) /* for all lines */ - dlx_reset_ln (ln); -return auto_config (dli_dev.name, dlx_desc.lines); /* auto config */ -} - -/* Reset individual line */ - -void dlx_reset_ln (int32 ln) -{ -dli_buf[ln] = 0; /* clear buf */ -if (dlo_unit[ln].flags & DLX_MDM) /* modem */ - dli_csr[ln] &= DLICSR_DTR; /* dont clr DTR */ -else dli_csr[ln] = 0; -dlo_buf[ln] = 0; /* clear buf */ -dlo_csr[ln] = CSR_DONE; -sim_cancel (&dlo_unit[ln]); /* deactivate */ -dli_clr_int (ln, DLI_RCI); -dli_clr_int (ln, DLI_DSI); -dlo_clr_int (ln); -return; -} - -/* Attach master unit */ - -t_stat dlx_attach (UNIT *uptr, char *cptr) -{ -t_stat r; - -r = tmxr_attach (&dlx_desc, uptr, cptr); /* attach */ -if (r != SCPE_OK) /* error */ - return r; -sim_activate (uptr, 0); /* start poll at once */ -return SCPE_OK; -} - -/* Detach master unit */ - -t_stat dlx_detach (UNIT *uptr) -{ -int32 i; -t_stat r; - -r = tmxr_detach (&dlx_desc, uptr); /* detach */ -for (i = 0; i < DLX_LINES; i++) /* all lines, */ - dlx_ldsc[i].rcve = 0; /* disable rcv */ -sim_cancel (uptr); /* stop poll */ -return r; -} - -/* Enable/disable device */ - -void dlx_enbdis (int32 dis) -{ -if (dis) { - dli_dev.flags = dli_dev.flags | DEV_DIS; - dlo_dev.flags = dlo_dev.flags | DEV_DIS; - } -else { - dli_dev.flags = dli_dev.flags & ~DEV_DIS; - dlo_dev.flags = dlo_dev.flags & ~DEV_DIS; - } -return; -} - -/* Change number of lines */ - -t_stat dlx_set_lines (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 newln, i, t; -t_stat r; - -if (cptr == NULL) - return SCPE_ARG; -newln = get_uint (cptr, 10, DLX_LINES, &r); -if ((r != SCPE_OK) || (newln == dlx_desc.lines)) - return r; -if (newln == 0) - return SCPE_ARG; -if (newln < dlx_desc.lines) { - for (i = newln, t = 0; i < dlx_desc.lines; i++) - t = t | dlx_ldsc[i].conn; - if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE)) - return SCPE_OK; - for (i = newln; i < dlx_desc.lines; i++) { - if (dlx_ldsc[i].conn) { - tmxr_linemsg (&dlx_ldsc[i], "\r\nOperator disconnected line\r\n"); - tmxr_reset_ln (&dlx_ldsc[i]); /* reset line */ - } - dlo_unit[i].flags |= UNIT_DIS; - dlx_reset_ln (i); - } - } -else { - for (i = dlx_desc.lines; i < newln; i++) { - dlo_unit[i].flags &= ~UNIT_DIS; - dlx_reset_ln (i); - } - } -dlx_desc.lines = newln; -dli_dib.lnt = newln * 010; /* upd IO page lnt */ -return auto_config (dli_dev.name, newln); /* auto config */ -} diff --git a/PDP11/pdp11_dz.c b/PDP11/pdp11_dz.c deleted file mode 100644 index d146a895..00000000 --- a/PDP11/pdp11_dz.c +++ /dev/null @@ -1,712 +0,0 @@ -/* pdp11_dz.c: DZ11 terminal multiplexor simulator - - Copyright (c) 2001-2008, 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. - - dz DZ11 terminal multiplexor - - 29-Dec-08 RMS Added MTAB_NC to SET LOG command (Walter Mueller) - 19-Nov-08 RMS Revised for common TMXR show routines - 18-Jun-07 RMS Added UNIT_IDLE flag - 29-Oct-06 RMS Synced poll and clock - 22-Nov-05 RMS Revised for new terminal processing routines - 07-Jul-05 RMS Removed extraneous externs - 15-Jun-05 RMS Revised for new autoconfigure interface - 04-Apr-04 RMS Added per-line logging - 05-Jan-04 RMS Revised for tmxr library changes - 19-May-03 RMS Revised for new conditional compilation scheme - 09-May-03 RMS Added network device flag - 22-Dec-02 RMS Added break (framing error) support - 31-Oct-02 RMS Added 8b support - 12-Oct-02 RMS Added autoconfigure support - 29-Sep-02 RMS Fixed bug in set number of lines routine - Added variable vector support - New data structures - 22-Apr-02 RMS Updated for changes in sim_tmxr - 28-Apr-02 RMS Fixed interrupt acknowledge, fixed SHOW DZ ADDRESS - 14-Jan-02 RMS Added multiboard support - 30-Dec-01 RMS Added show statistics, set disconnect - Removed statistics registers - 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 - 03-Oct-01 RMS Added support for BSD-style "ringless" modems - 27-Sep-01 RMS Fixed bug in xmte initialization - 17-Sep-01 RMS Added separate autodisconnect switch - 16-Sep-01 RMS Fixed modem control bit offsets -*/ - -#if defined (VM_PDP10) /* PDP10 version */ -#include "pdp10_defs.h" -#define RANK_DZ 0 /* no autoconfig */ -#define DZ_8B_DFLT 0 -extern int32 int_req; - -#elif defined (VM_VAX) /* VAX version */ -#include "vax_defs.h" -#define DZ_8B_DFLT TT_MODE_8B -extern int32 int_req[IPL_HLVL]; - -#else /* PDP-11 version */ -#include "pdp11_defs.h" -#define DZ_8B_DFLT TT_MODE_8B -extern int32 int_req[IPL_HLVL]; -#endif - -#include "sim_sock.h" -#include "sim_tmxr.h" - -#if !defined (DZ_MUXES) -#define DZ_MUXES 1 -#endif -#if !defined (DZ_LINES) -#define DZ_LINES 8 -#endif - -#define DZ_MNOMASK (DZ_MUXES - 1) /* mask for mux no */ -#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 */ - -/* DZCSR - 160100 - control/status register */ - -#define CSR_MAINT 0000010 /* maint - NI */ -#define CSR_CLR 0000020 /* clear */ -#define CSR_MSE 0000040 /* master scan enb */ -#define CSR_RIE 0000100 /* rcv int enb */ -#define CSR_RDONE 0000200 /* rcv done - RO */ -#define CSR_V_TLINE 8 /* xmit line - RO */ -#define CSR_TLINE (DZ_LNOMASK << CSR_V_TLINE) -#define CSR_SAE 0010000 /* silo alm enb */ -#define CSR_SA 0020000 /* silo alm - RO */ -#define CSR_TIE 0040000 /* xmit int enb */ -#define CSR_TRDY 0100000 /* xmit rdy - RO */ -#define CSR_RW (CSR_MSE | CSR_RIE | CSR_SAE | CSR_TIE) -#define CSR_MBZ (0004003 | CSR_CLR | CSR_MAINT) - -#define CSR_GETTL(x) (((x) >> CSR_V_TLINE) & DZ_LNOMASK) -#define CSR_PUTTL(x,y) x = ((x) & ~CSR_TLINE) | (((y) & DZ_LNOMASK) << CSR_V_TLINE) - -/* DZRBUF - 160102 - receive buffer, read only */ - -#define RBUF_CHAR 0000377 /* rcv char */ -#define RBUF_V_RLINE 8 /* rcv line */ -#define RBUF_PARE 0010000 /* parity err - NI */ -#define RBUF_FRME 0020000 /* frame err */ -#define RBUF_OVRE 0040000 /* overrun err - NI */ -#define RBUF_VALID 0100000 /* rcv valid */ -#define RBUF_MBZ 0004000 - -/* DZLPR - 160102 - line parameter register, write only, word access only */ - -#define LPR_V_LINE 0 /* line */ -#define LPR_LPAR 0007770 /* line pars - NI */ -#define LPR_RCVE 0010000 /* receive enb */ -#define LPR_GETLN(x) (((x) >> LPR_V_LINE) & DZ_LNOMASK) - -/* DZTCR - 160104 - transmission control register */ - -#define TCR_V_XMTE 0 /* xmit enables */ -#define TCR_V_DTR 8 /* DTRs */ - -/* DZMSR - 160106 - modem status register, read only */ - -#define MSR_V_RI 0 /* ring indicators */ -#define MSR_V_CD 8 /* carrier detect */ - -/* DZTDR - 160106 - transmit data, write only */ - -#define TDR_CHAR 0000377 /* xmit char */ -#define TDR_V_TBR 8 /* xmit break - NI */ - -extern int32 IREQ (HLVL); -extern int32 sim_switches; -extern FILE *sim_log; -extern int32 tmxr_poll; /* calibrated delay */ - -uint16 dz_csr[DZ_MUXES] = { 0 }; /* csr */ -uint16 dz_rbuf[DZ_MUXES] = { 0 }; /* rcv buffer */ -uint16 dz_lpr[DZ_MUXES] = { 0 }; /* line param */ -uint16 dz_tcr[DZ_MUXES] = { 0 }; /* xmit control */ -uint16 dz_msr[DZ_MUXES] = { 0 }; /* modem status */ -uint16 dz_tdr[DZ_MUXES] = { 0 }; /* xmit data */ -uint8 dz_sae[DZ_MUXES] = { 0 }; /* silo alarm enabled */ -uint32 dz_rxi = 0; /* rcv interrupts */ -uint32 dz_txi = 0; /* xmt interrupts */ -int32 dz_mctl = 0; /* modem ctrl enabled */ -int32 dz_auto = 0; /* autodiscon enabled */ -TMLN dz_ldsc[DZ_MUXES * DZ_LINES] = { 0 }; /* line descriptors */ -TMXR dz_desc = { DZ_MUXES * DZ_LINES, 0, 0, dz_ldsc }; /* mux descriptor */ - -DEVICE dz_dev; -t_stat dz_rd (int32 *data, int32 PA, int32 access); -t_stat dz_wr (int32 data, int32 PA, int32 access); -int32 dz_rxinta (void); -int32 dz_txinta (void); -t_stat dz_svc (UNIT *uptr); -t_stat dz_reset (DEVICE *dptr); -t_stat dz_attach (UNIT *uptr, char *cptr); -t_stat dz_detach (UNIT *uptr); -t_stat dz_clear (int32 dz, t_bool flag); -int32 dz_getc (int32 dz); -void dz_update_rcvi (void); -void dz_update_xmti (void); -void dz_clr_rxint (int32 dz); -void dz_set_rxint (int32 dz); -void dz_clr_txint (int32 dz); -void dz_set_txint (int32 dz); -t_stat dz_setnl (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat dz_set_log (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat dz_set_nolog (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat dz_show_log (FILE *st, UNIT *uptr, int32 val, void *desc); - -/* DZ data structures - - dz_dev DZ device descriptor - dz_unit DZ unit list - dz_reg DZ register list -*/ - -DIB dz_dib = { - IOBA_DZ, IOLN_DZ * DZ_MUXES, &dz_rd, &dz_wr, - 2, IVCL (DZRX), VEC_DZRX, { &dz_rxinta, &dz_txinta } - }; - -UNIT dz_unit = { UDATA (&dz_svc, UNIT_IDLE|UNIT_ATTABLE|DZ_8B_DFLT, 0) }; - -REG dz_reg[] = { - { BRDATA (CSR, dz_csr, DEV_RDX, 16, DZ_MUXES) }, - { BRDATA (RBUF, dz_rbuf, DEV_RDX, 16, DZ_MUXES) }, - { BRDATA (LPR, dz_lpr, DEV_RDX, 16, DZ_MUXES) }, - { BRDATA (TCR, dz_tcr, DEV_RDX, 16, DZ_MUXES) }, - { BRDATA (MSR, dz_msr, DEV_RDX, 16, DZ_MUXES) }, - { BRDATA (TDR, dz_tdr, DEV_RDX, 16, DZ_MUXES) }, - { BRDATA (SAENB, dz_sae, DEV_RDX, 1, DZ_MUXES) }, - { GRDATA (RXINT, dz_rxi, DEV_RDX, DZ_MUXES, 0) }, - { GRDATA (TXINT, dz_txi, DEV_RDX, DZ_MUXES, 0) }, - { FLDATA (MDMCTL, dz_mctl, 0) }, - { FLDATA (AUTODS, dz_auto, 0) }, - { GRDATA (DEVADDR, dz_dib.ba, DEV_RDX, 32, 0), REG_HRO }, - { GRDATA (DEVVEC, dz_dib.vec, DEV_RDX, 16, 0), REG_HRO }, - { NULL } - }; - -MTAB dz_mod[] = { - { TT_MODE, TT_MODE_7B, "7b", "7B", NULL }, - { TT_MODE, TT_MODE_8B, "8b", "8B", NULL }, - { TT_MODE, TT_MODE_7P, "7p", "7P", NULL }, - { MTAB_XTD | MTAB_VDV, 1, NULL, "DISCONNECT", - &tmxr_dscln, NULL, &dz_desc }, - { UNIT_ATT, UNIT_ATT, "summary", NULL, - NULL, &tmxr_show_summ, (void *) &dz_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, - NULL, &tmxr_show_cstat, (void *) &dz_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, - NULL, &tmxr_show_cstat, (void *) &dz_desc }, - { MTAB_XTD|MTAB_VDV, 010, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, DZ_LINES, "VECTOR", "VECTOR", - &set_vec, &show_vec_mux, (void *) &dz_desc }, -#if !defined (VM_PDP10) - { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE", - &set_addr_flt, NULL, NULL }, -#endif - { MTAB_XTD | MTAB_VDV, 0, "LINES", "LINES", - &dz_setnl, &tmxr_show_lines, (void *) &dz_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NC, 0, NULL, "LOG", - &dz_set_log, NULL, &dz_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NC, 0, NULL, "NOLOG", - &dz_set_nolog, NULL, &dz_desc }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "LOG", NULL, - NULL, &dz_show_log, &dz_desc }, - { 0 } - }; - -DEVICE dz_dev = { - "DZ", &dz_unit, dz_reg, dz_mod, - 1, DEV_RDX, 8, 1, DEV_RDX, 8, - &tmxr_ex, &tmxr_dep, &dz_reset, - NULL, &dz_attach, &dz_detach, - &dz_dib, DEV_FLTA | DEV_DISABLE | DEV_NET | DEV_UBUS | DEV_QBUS - }; - -/* IO dispatch routines, I/O addresses 177601x0 - 177601x7 */ - -t_stat dz_rd (int32 *data, int32 PA, int32 access) -{ -int32 dz = ((PA - dz_dib.ba) >> 3) & DZ_MNOMASK; /* get mux num */ - -switch ((PA >> 1) & 03) { /* case on PA<2:1> */ - - case 00: /* CSR */ - *data = dz_csr[dz] = dz_csr[dz] & ~CSR_MBZ; - break; - - case 01: /* RBUF */ - dz_csr[dz] = dz_csr[dz] & ~CSR_SA; /* clr silo alarm */ - if (dz_csr[dz] & CSR_MSE) { /* scanner on? */ - dz_rbuf[dz] = dz_getc (dz); /* get top of silo */ - if (!dz_rbuf[dz]) /* empty? re-enable */ - dz_sae[dz] = 1; - tmxr_poll_rx (&dz_desc); /* poll input */ - dz_update_rcvi (); /* update rx intr */ - } - else { - dz_rbuf[dz] = 0; /* no data */ - dz_update_rcvi (); /* no rx intr */ - } - *data = dz_rbuf[dz]; - break; - - case 02: /* TCR */ - *data = dz_tcr[dz]; - break; - - case 03: /* MSR */ - *data = dz_msr[dz]; - break; - } - -return SCPE_OK; -} - -t_stat dz_wr (int32 data, int32 PA, int32 access) -{ -int32 dz = ((PA - dz_dib.ba) >> 3) & DZ_MNOMASK; /* get mux num */ -int32 i, c, line; -TMLN *lp; - -switch ((PA >> 1) & 03) { /* case on PA<2:1> */ - - case 00: /* CSR */ - if (access == WRITEB) data = (PA & 1)? /* byte? merge */ - (dz_csr[dz] & 0377) | (data << 8): - (dz_csr[dz] & ~0377) | data; - if (data & CSR_CLR) /* clr? reset */ - dz_clear (dz, FALSE); - if (data & CSR_MSE) /* MSE? start poll */ - sim_activate (&dz_unit, clk_cosched (tmxr_poll)); - else dz_csr[dz] &= ~(CSR_SA | CSR_RDONE | CSR_TRDY); - if ((data & CSR_RIE) == 0) /* RIE = 0? */ - dz_clr_rxint (dz); - else if (((dz_csr[dz] & CSR_IE) == 0) && /* RIE 0->1? */ - ((dz_csr[dz] & CSR_SAE)? - (dz_csr[dz] & CSR_SA): (dz_csr[dz] & CSR_RDONE))) - dz_set_rxint (dz); - if ((data & CSR_TIE) == 0) /* TIE = 0? */ - dz_clr_txint (dz); - else if (((dz_csr[dz] & CSR_TIE) == 0) && (dz_csr[dz] & CSR_TRDY)) - dz_set_txint (dz); - dz_csr[dz] = (dz_csr[dz] & ~CSR_RW) | (data & CSR_RW); - break; - - case 01: /* LPR */ - dz_lpr[dz] = data; - line = (dz * DZ_LINES) + LPR_GETLN (data); /* get line num */ - lp = &dz_ldsc[line]; /* get line desc */ - if (dz_lpr[dz] & LPR_RCVE) /* rcv enb? on */ - lp->rcve = 1; - else lp->rcve = 0; /* else line off */ - tmxr_poll_rx (&dz_desc); /* poll input */ - dz_update_rcvi (); /* update rx intr */ - break; - - case 02: /* TCR */ - if (access == WRITEB) data = (PA & 1)? /* byte? merge */ - (dz_tcr[dz] & 0377) | (data << 8): - (dz_tcr[dz] & ~0377) | data; - if (dz_mctl) { /* modem ctl? */ - dz_msr[dz] |= ((data & 0177400) & /* dcd |= dtr & ring */ - ((dz_msr[dz] & DZ_LMASK) << MSR_V_CD)); - dz_msr[dz] &= ~(data >> TCR_V_DTR); /* ring &= ~dtr */ - if (dz_auto) { /* auto disconnect? */ - int32 drop; - drop = (dz_tcr[dz] & ~data) >> TCR_V_DTR; /* drop = dtr & ~data */ - for (i = 0; i < DZ_LINES; i++) { /* drop hangups */ - line = (dz * DZ_LINES) + i; /* get line num */ - lp = &dz_ldsc[line]; /* get line desc */ - if (lp->conn && (drop & (1 << i))) { - tmxr_linemsg (lp, "\r\nLine hangup\r\n"); - tmxr_reset_ln (lp); /* reset line, cdet */ - dz_msr[dz] &= ~(1 << (i + MSR_V_CD)); - } /* end if drop */ - } /* end for */ - } /* end if auto */ - } /* end if modem */ - dz_tcr[dz] = data; - tmxr_poll_tx (&dz_desc); /* poll output */ - dz_update_xmti (); /* update int */ - break; - - case 03: /* TDR */ - if (PA & 1) { /* odd byte? */ - dz_tdr[dz] = (dz_tdr[dz] & 0377) | (data << 8); /* just save */ - break; - } - dz_tdr[dz] = data; - if (dz_csr[dz] & CSR_MSE) { /* enabled? */ - line = (dz * DZ_LINES) + CSR_GETTL (dz_csr[dz]); - lp = &dz_ldsc[line]; /* get line desc */ - c = sim_tt_outcvt (dz_tdr[dz], TT_GET_MODE (dz_unit.flags)); - if (c >= 0) /* store char */ - tmxr_putc_ln (lp, c); - tmxr_poll_tx (&dz_desc); /* poll output */ - dz_update_xmti (); /* update int */ - } - break; - } - -return SCPE_OK; -} - -/* Unit service routine - - The DZ11 polls to see if asynchronous activity has occurred and now - needs to be processed. The polling interval is controlled by the clock - simulator, so for most environments, it is calibrated to real time. - Typical polling intervals are 50-60 times per second. - - The simulator assumes that software enables all of the multiplexors, - or none of them. -*/ - -t_stat dz_svc (UNIT *uptr) -{ -int32 dz, t, newln; - -for (dz = t = 0; dz < DZ_MUXES; dz++) /* check enabled */ - t = t | (dz_csr[dz] & CSR_MSE); -if (t) { /* any enabled? */ - newln = tmxr_poll_conn (&dz_desc); /* poll connect */ - if ((newln >= 0) && dz_mctl) { /* got a live one? */ - dz = newln / DZ_LINES; /* get mux num */ - if (dz_tcr[dz] & (1 << (newln + TCR_V_DTR))) /* DTR set? */ - dz_msr[dz] |= (1 << (newln + MSR_V_CD)); /* set cdet */ - else dz_msr[dz] |= (1 << newln); /* set ring */ - } - tmxr_poll_rx (&dz_desc); /* poll input */ - dz_update_rcvi (); /* upd rcv intr */ - tmxr_poll_tx (&dz_desc); /* poll output */ - dz_update_xmti (); /* upd xmt intr */ - sim_activate (uptr, clk_cosched (tmxr_poll)); /* reactivate */ - } -return SCPE_OK; -} - -/* Get first available character for mux, if any */ - -int32 dz_getc (int32 dz) -{ -uint32 i, line, c; - -for (i = c = 0; (i < DZ_LINES) && (c == 0); i++) { /* loop thru lines */ - line = (dz * DZ_LINES) + i; /* get line num */ - c = tmxr_getc_ln (&dz_ldsc[line]); /* test for input */ - if (c & SCPE_BREAK) /* break? frame err */ - c = RBUF_VALID | RBUF_FRME; - if (c) /* or in line # */ - c = c | (i << RBUF_V_RLINE); - } /* end for */ -return c; -} - -/* Update receive interrupts */ - -void dz_update_rcvi (void) -{ -int32 i, dz, line, scnt[DZ_MUXES]; -TMLN *lp; - -for (dz = 0; dz < DZ_MUXES; dz++) { /* loop thru muxes */ - scnt[dz] = 0; /* clr input count */ - for (i = 0; i < DZ_LINES; i++) { /* poll lines */ - line = (dz * DZ_LINES) + i; /* get line num */ - lp = &dz_ldsc[line]; /* get line desc */ - scnt[dz] = scnt[dz] + tmxr_rqln (lp); /* sum buffers */ - if (dz_mctl && !lp->conn) /* if disconn */ - dz_msr[dz] &= ~(1 << (i + MSR_V_CD)); /* reset car det */ - } - } -for (dz = 0; dz < DZ_MUXES; dz++) { /* loop thru muxes */ - if (scnt[dz] && (dz_csr[dz] & CSR_MSE)) { /* input & enabled? */ - dz_csr[dz] |= CSR_RDONE; /* set done */ - if (dz_sae[dz] && (scnt[dz] >= DZ_SILO_ALM)) { /* alm enb & cnt hi? */ - dz_csr[dz] |= CSR_SA; /* set status */ - dz_sae[dz] = 0; /* disable alarm */ - } - } - else dz_csr[dz] &= ~CSR_RDONE; /* no, clear done */ - if ((dz_csr[dz] & CSR_RIE) && /* int enable */ - ((dz_csr[dz] & CSR_SAE)? - (dz_csr[dz] & CSR_SA): (dz_csr[dz] & CSR_RDONE))) - dz_set_rxint (dz); /* and alm/done? */ - else dz_clr_rxint (dz); /* no, clear int */ - } -return; -} - -/* Update transmit interrupts */ - -void dz_update_xmti (void) -{ -int32 dz, linemask, i, j, line; - -for (dz = 0; dz < DZ_MUXES; dz++) { /* loop thru muxes */ - linemask = dz_tcr[dz] & DZ_LMASK; /* enabled lines */ - dz_csr[dz] &= ~CSR_TRDY; /* assume not rdy */ - j = CSR_GETTL (dz_csr[dz]); /* start at current */ - for (i = 0; i < DZ_LINES; i++) { /* loop thru lines */ - j = (j + 1) & DZ_LNOMASK; /* next line */ - line = (dz * DZ_LINES) + j; /* get line num */ - if ((linemask & (1 << j)) && dz_ldsc[line].xmte) { - CSR_PUTTL (dz_csr[dz], j); /* put ln in csr */ - dz_csr[dz] |= CSR_TRDY; /* set xmt rdy */ - break; - } - } - if ((dz_csr[dz] & CSR_TIE) && (dz_csr[dz] & CSR_TRDY)) /* ready plus int? */ - dz_set_txint (dz); - else dz_clr_txint (dz); /* no int req */ - } -return; -} - -/* Interrupt routines */ - -void dz_clr_rxint (int32 dz) -{ -dz_rxi = dz_rxi & ~(1 << dz); /* clr mux rcv int */ -if (dz_rxi == 0) /* all clr? */ - CLR_INT (DZRX); -else SET_INT (DZRX); /* no, set intr */ -return; -} - -void dz_set_rxint (int32 dz) -{ -dz_rxi = dz_rxi | (1 << dz); /* set mux rcv int */ -SET_INT (DZRX); /* set master intr */ -return; -} - -int32 dz_rxinta (void) -{ -int32 dz; - -for (dz = 0; dz < DZ_MUXES; dz++) { /* find 1st mux */ - if (dz_rxi & (1 << dz)) { - dz_clr_rxint (dz); /* clear intr */ - return (dz_dib.vec + (dz * 010)); /* return vector */ - } - } -return 0; -} - -void dz_clr_txint (int32 dz) -{ -dz_txi = dz_txi & ~(1 << dz); /* clr mux xmt int */ -if (dz_txi == 0) /* all clr? */ - CLR_INT (DZTX); -else SET_INT (DZTX); /* no, set intr */ -return; -} - -void dz_set_txint (int32 dz) -{ -dz_txi = dz_txi | (1 << dz); /* set mux xmt int */ -SET_INT (DZTX); /* set master intr */ -return; -} - -int32 dz_txinta (void) -{ -int32 dz; - -for (dz = 0; dz < DZ_MUXES; dz++) { /* find 1st mux */ - if (dz_txi & (1 << dz)) { - dz_clr_txint (dz); /* clear intr */ - return (dz_dib.vec + 4 + (dz * 010)); /* return vector */ - } - } -return 0; -} - -/* Device reset */ - -t_stat dz_clear (int32 dz, t_bool flag) -{ -int32 i, line; - -dz_csr[dz] = 0; /* clear CSR */ -dz_rbuf[dz] = 0; /* silo empty */ -dz_lpr[dz] = 0; /* no params */ -if (flag) /* INIT? clr all */ - dz_tcr[dz] = 0; -else dz_tcr[dz] &= ~0377; /* else save dtr */ -dz_tdr[dz] = 0; -dz_sae[dz] = 1; /* alarm on */ -dz_clr_rxint (dz); /* clear int */ -dz_clr_txint (dz); -for (i = 0; i < DZ_LINES; i++) { /* loop thru lines */ - line = (dz * DZ_LINES) + i; - if (!dz_ldsc[line].conn) /* set xmt enb */ - dz_ldsc[line].xmte = 1; - dz_ldsc[line].rcve = 0; /* clr rcv enb */ - } -return SCPE_OK; -} - -t_stat dz_reset (DEVICE *dptr) -{ -int32 i, ndev; - -for (i = 0; i < DZ_MUXES; i++) /* init muxes */ - dz_clear (i, TRUE); -dz_rxi = dz_txi = 0; /* clr master int */ -CLR_INT (DZRX); -CLR_INT (DZTX); -sim_cancel (&dz_unit); /* stop poll */ -ndev = ((dptr->flags & DEV_DIS)? 0: (dz_desc.lines / DZ_LINES)); -return auto_config (dptr->name, ndev); /* auto config */ -} - -/* Attach */ - -t_stat dz_attach (UNIT *uptr, char *cptr) -{ -t_stat r; -extern int32 sim_switches; - -dz_mctl = dz_auto = 0; /* modem ctl off */ -r = tmxr_attach (&dz_desc, uptr, cptr); /* attach mux */ -if (r != SCPE_OK) /* error? */ - return r; -if (sim_switches & SWMASK ('M')) { /* modem control? */ - dz_mctl = 1; - printf ("Modem control activated\n"); - if (sim_log) - fprintf (sim_log, "Modem control activated\n"); - if (sim_switches & SWMASK ('A')) { /* autodisconnect? */ - dz_auto = 1; - printf ("Auto disconnect activated\n"); - if (sim_log) - fprintf (sim_log, "Auto disconnect activated\n"); - } - } -return SCPE_OK; -} - -/* Detach */ - -t_stat dz_detach (UNIT *uptr) -{ -return tmxr_detach (&dz_desc, uptr); -} - -/* SET LINES processor */ - -t_stat dz_setnl (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 newln, i, t, ndev; -t_stat r; - -if (cptr == NULL) - return SCPE_ARG; -newln = (int32) get_uint (cptr, 10, (DZ_MUXES * DZ_LINES), &r); -if ((r != SCPE_OK) || (newln == dz_desc.lines)) - return r; -if ((newln == 0) || (newln % DZ_LINES)) - return SCPE_ARG; -if (newln < dz_desc.lines) { - for (i = newln, t = 0; i < dz_desc.lines; i++) - t = t | dz_ldsc[i].conn; - if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE)) - return SCPE_OK; - for (i = newln; i < dz_desc.lines; i++) { - if (dz_ldsc[i].conn) { - tmxr_linemsg (&dz_ldsc[i], "\r\nOperator disconnected line\r\n"); - tmxr_reset_ln (&dz_ldsc[i]); /* reset line */ - } - if ((i % DZ_LINES) == (DZ_LINES - 1)) - dz_clear (i / DZ_LINES, TRUE); /* reset mux */ - } - } -dz_dib.lnt = (newln / DZ_LINES) * IOLN_DZ; /* set length */ -dz_desc.lines = newln; -ndev = ((dz_dev.flags & DEV_DIS)? 0: (dz_desc.lines / DZ_LINES)); -return auto_config (dz_dev.name, ndev); /* auto config */ -} - -/* SET LOG processor */ - -t_stat dz_set_log (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -char *tptr; -t_stat r; -int32 ln; - -if (cptr == NULL) - return SCPE_ARG; -tptr = strchr (cptr, '='); -if ((tptr == NULL) || (*tptr == 0)) - return SCPE_ARG; -*tptr++ = 0; -ln = (int32) get_uint (cptr, 10, (DZ_MUXES * DZ_LINES), &r); -if ((r != SCPE_OK) || (ln >= dz_desc.lines)) - return SCPE_ARG; -return tmxr_set_log (NULL, ln, tptr, desc); -} - -/* SET NOLOG processor */ - -t_stat dz_set_nolog (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -t_stat r; -int32 ln; - -if (cptr == NULL) - return SCPE_ARG; -ln = (int32) get_uint (cptr, 10, (DZ_MUXES * DZ_LINES), &r); -if ((r != SCPE_OK) || (ln >= dz_desc.lines)) - return SCPE_ARG; -return tmxr_set_nolog (NULL, ln, NULL, desc); -} - -/* SHOW LOG processor */ - -t_stat dz_show_log (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -int32 i; - -for (i = 0; i < dz_desc.lines; i++) { - fprintf (st, "line %d: ", i); - tmxr_show_log (st, NULL, i, desc); - fprintf (st, "\n"); - } -return SCPE_OK; -} - - - diff --git a/PDP11/pdp11_fp.c b/PDP11/pdp11_fp.c deleted file mode 100644 index f21185c0..00000000 --- a/PDP11/pdp11_fp.c +++ /dev/null @@ -1,1349 +0,0 @@ -/* pdp11_fp.c: PDP-11 floating point simulator (32b version) - - Copyright (c) 1993-2018, 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. - - 28-May-18 RMS Fixed FPCHG macro to avoid undefined operation (Mark Pizzolato) - 24-Mar-15 RMS MMR1 does not track register changes (Johnny Billquist) - 20-Apr-13 RMS MMR1 does not track PC changes (Johnny Billquist) - 22-Sep-05 RMS Fixed declarations (Sterling Garwood) - 04-Oct-04 RMS Added FIS instructions - 19-Jan-03 RMS Changed mode definitions for Apple Dev Kit conflict - 08-Oct-02 RMS Fixed macro definitions - 05-Jun-98 RMS Fixed implementation specific shift bugs - 20-Apr-98 RMS Fixed bug in MODf integer truncation - 17-Apr-98 RMS Fixed bug in STCfi range check - 16-Apr-98 RMS Fixed bugs in STEXP, STCfi, round/pack - 09-Apr-98 RMS Fixed bug in LDEXP - 04-Apr-98 RMS Fixed bug in MODf condition codes - - This module simulates the PDP-11 floating point unit (FP11 series). - It is called from the instruction decoder for opcodes 170000:177777. - - The floating point unit recognizes three instruction formats: - - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ no operand - | 1 1 1 1| 0 0 0 0 0 0| opcode | 170000: - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 170077 - - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ one operand - | 1 1 1 1| 0 0 0| opcode | dest spec | 170100: - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 170777 - - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ register + operand - | 1 1 1 1| opcode | fac | dest spec | 171000: - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ 177777 - - The instruction space is further extended through use of the floating - point status register (FPS) mode bits. Three mode bits affect how - instructions are interpreted: - - FPS_D if 0, floating registers are single precision - if 1, floating registers are double precision - - FPS_L if 0, integer operands are word - if 1, integer operands are longword - - FPS_T if 0, floating operations are rounded - if 1, floating operations are truncated - - FPS also contains the condition codes for the floating point unit, - and exception enable bits for individual error conditions. Exceptions - cause a trap through 0244, unless the individual exception, or all - exceptions, are disabled. Illegal address mode, undefined variable, - and divide by zero NOP the current instruction; all other exceptions - permit the instruction to complete. - - Floating point specifiers are similar to integer specifiers, with - the length of the operand being up to 8 bytes. In two specific cases, - the floating point unit reads or writes only two bytes, rather than - the length specified by the operand type: - - register for integers, only 16b are accessed; if the - operand is 32b, these are the high order 16b - of the operand - - immediate for integers or floating point, only 16b are - accessed; if the operand is 32b or 64b, these - are the high order 16b of the operand. - - The FP11 cannot update MMR1 on specifier changes, because the - quantity field is too narrow for +8 or -8. Instead, the simulator - records changes to be made and only commits them at instruction - completion. Instructions that can overwrite a general register - (STFPS, STST, STEXP, STCFi in mode 0) need not check for conflicts; - in mode 0, no general register changes occur in the specifier flow. -*/ - -#include "pdp11_defs.h" - -/* Floating point status register */ - -#define FPS_ER (1u << FPS_V_ER) /* error */ -#define FPS_ID (1u << FPS_V_ID) /* interrupt disable */ -#define FPS_IUV (1u << FPS_V_IUV) /* int on undef var */ -#define FPS_IU (1u << FPS_V_IU) /* int on underflow */ -#define FPS_IV (1u << FPS_V_IV) /* int on overflow */ -#define FPS_IC (1u << FPS_V_IC) /* int on conv error */ -#define FPS_D (1u << FPS_V_D) /* single/double */ -#define FPS_L (1u << FPS_V_L) /* word/long */ -#define FPS_T (1u << FPS_V_T) /* round/truncate */ -#define FPS_N (1u << FPS_V_N) -#define FPS_Z (1u << FPS_V_Z) -#define FPS_V (1u << FPS_V_V) -#define FPS_C (1u << FPS_V_C) -#define FPS_CC (FPS_N + FPS_Z + FPS_V + FPS_C) -#define FPS_RW (FPS_ER + FPS_ID + FPS_IUV + FPS_IU + FPS_IV + \ - FPS_IC + FPS_D + FPS_L + FPS_T + FPS_CC) - -/* Floating point exception codes */ - -#define FEC_OP 2 /* illegal op/mode */ -#define FEC_DZRO 4 /* divide by zero */ -#define FEC_ICVT 6 /* conversion error */ -#define FEC_OVFLO 8 /* overflow */ -#define FEC_UNFLO 10 /* underflow */ -#define FEC_UNDFV 12 /* undef variable */ - -/* Floating point format, all assignments 32b relative */ - -#define FP_V_SIGN (63 - 32) /* high lw: sign */ -#define FP_V_EXP (55 - 32) /* exponent */ -#define FP_V_HB FP_V_EXP /* hidden bit */ -#define FP_V_F0 (48 - 32) /* fraction 0 */ -#define FP_V_F1 (32 - 32) /* fraction 1 */ -#define FP_V_FROUND (31 - 32) /* f round point */ -#define FP_V_F2 16 /* low lw: fraction 2 */ -#define FP_V_F3 0 /* fraction 3 */ -#define FP_V_DROUND (-1) /* d round point */ -#define FP_M_EXP 0377 -#define FP_SIGN (1u << FP_V_SIGN) -#define FP_EXP (FP_M_EXP << FP_V_EXP) -#define FP_HB (1u << FP_V_HB) -#define FP_FRACH ((1u << FP_V_HB) - 1) -#define FP_FRACL 0xFFFFFFFF -#define FP_BIAS 0200 /* exponent bias */ -#define FP_GUARD 3 /* guard bits */ - -/* Data lengths */ - -#define WORD 2 -#define LONG 4 -#define QUAD 8 - -/* Reg change word */ - -#define FPCHG(v,r) ((int32)((((uint32)(v)) << FPCHG_V_VAL) | (r))) -#define FPCHG_REG 07 /* register number */ -#define FPCHG_V_VAL 3 /* offset to value */ -#define FPCHG_GETREG(x) ((x) & FPCHG_REG) -#define FPCHG_GETVAL(x) ((x) >> FPCHG_V_VAL) - -/* Double precision operations on 64b quantities */ - -#define F_LOAD(qd,ac,ds) \ - ds.h = ac.h; ds.l = (qd)? ac.l: 0 -#define F_LOAD_P(qd,ac,ds) \ - ds->h = ac.h; ds->l = (qd)? ac.l: 0 -#define F_LOAD_FRAC(qd,ac,ds) \ - ds.h = (ac.h & FP_FRACH) | FP_HB; \ - ds.l = (qd)? ac.l: 0 -#define F_STORE(qd,sr,ac) \ - ac.h = sr.h; if ((qd)) ac.l = sr.l -#define F_STORE_P(qd,sr,ac) \ - ac.h = sr->h; if ((qd)) ac.l = sr->l -#define F_GET_FRAC_P(sr,ds) \ - ds.l = sr->l; \ - ds.h = (sr->h & FP_FRACH) | FP_HB -#define F_ADD(s2,s1,ds) \ - ds.l = (s1.l + s2.l) & 0xFFFFFFFF; \ - ds.h = (s1.h + s2.h + (ds.l < s2.l)) & 0xFFFFFFFF -#define F_SUB(s2,s1,ds) \ - ds.h = (s1.h - s2.h - (s1.l < s2.l)) & 0xFFFFFFFF; \ - ds.l = (s1.l - s2.l) & 0xFFFFFFFF -#define F_LT(x,y) ((x.h < y.h) || ((x.h == y.h) && (x.l < y.l))) -#define F_LT_AP(x,y) (((x->h & ~FP_SIGN) < (y->h & ~FP_SIGN)) || \ - (((x->h & ~FP_SIGN) == (y->h & ~FP_SIGN)) && (x->l < y->l))) -#define F_LSH_V(sr,n,ds) \ - ds.h = (((n) >= 32)? (sr.l << ((n) - 32)): \ - (sr.h << (n)) | ((sr.l >> (32 - (n))) & and_mask[n])) \ - & 0xFFFFFFFF; \ - ds.l = ((n) >= 32)? 0: (sr.l << (n)) & 0xFFFFFFFF -#define F_RSH_V(sr,n,ds) \ - ds.l = (((n) >= 32)? (sr.h >> ((n) - 32)) & and_mask[64 - (n)]: \ - ((sr.l >> (n)) & and_mask[32 - (n)]) | \ - (sr.h << (32 - (n)))) & 0xFFFFFFFF; \ - ds.h = ((n) >= 32)? 0: \ - ((sr.h >> (n)) & and_mask[32 - (n)]) & 0xFFFFFFFF - -/* For the constant shift macro, arguments must in the range [2,31] */ - -#define F_LSH_1(ds) ds.h = ((ds.h << 1) | ((ds.l >> 31) & 1)) & 0xFFFFFFFF; \ - ds.l = (ds.l << 1) & 0xFFFFFFFF -#define F_RSH_1(ds) ds.l = ((ds.l >> 1) & 0x7FFFFFFF) | ((ds.h & 1) << 31); \ - ds.h = ((ds.h >> 1) & 0x7FFFFFFF) -#define F_LSH_K(sr,n,ds) \ - ds.h = ((sr.h << (n)) | ((sr.l >> (32 - (n))) & and_mask[n])) \ - & 0xFFFFFFFF; \ - ds.l = (sr.l << (n)) & 0xFFFFFFFF -#define F_RSH_K(sr,n,ds) \ - ds.l = (((sr.l >> (n)) & and_mask[32 - (n)]) | \ - (sr.h << (32 - (n)))) & 0xFFFFFFFF; \ - ds.h = ((sr.h >> (n)) & and_mask[32 - (n)]) & 0xFFFFFFFF -#define F_LSH_GUARD(ds) F_LSH_K(ds,FP_GUARD,ds) -#define F_RSH_GUARD(ds) F_RSH_K(ds,FP_GUARD,ds) - -#define GET_BIT(ir,n) (((ir) >> (n)) & 1) -#define GET_SIGN(ir) GET_BIT((ir), FP_V_SIGN) -#define GET_EXP(ir) (((ir) >> FP_V_EXP) & FP_M_EXP) -#define GET_SIGN_L(ir) GET_BIT((ir), 31) -#define GET_SIGN_W(ir) GET_BIT((ir), 15) - -extern jmp_buf save_env; -extern uint32 cpu_type; -extern int32 FEC, FEA, FPS; -extern int32 CPUERR, trap_req; -extern int32 N, Z, V, C; -extern int32 R[8]; -extern int32 STKLIM; -extern int32 cm, isenable, dsenable, MMR0, MMR1; -extern fpac_t FR[6]; - -fpac_t zero_fac = { 0, 0 }; -fpac_t one_fac = { 1, 0 }; -fpac_t fround_fac = { (1u << (FP_V_FROUND + 32)), 0 }; -fpac_t fround_guard_fac = { 0, (1u << (FP_V_FROUND + FP_GUARD)) }; -fpac_t dround_guard_fac = { (1u << (FP_V_DROUND + FP_GUARD)), 0 }; -fpac_t fmask_fac = { 0xFFFFFFFF, (1u << (FP_V_HB + FP_GUARD + 1)) - 1 }; -static const uint32 and_mask[33] = { 0, - 0x1, 0x3, 0x7, 0xF, - 0x1F, 0x3F, 0x7F, 0xFF, - 0x1FF, 0x3FF, 0x7FF, 0xFFF, - 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF, - 0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF, - 0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF, - 0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF, - 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF - }; -int32 backup_PC; -int32 fp_change; - -int32 fpnotrap (int32 code); -int32 GeteaFW (int32 spec); -int32 GeteaFP (int32 spec, int32 len); -uint32 ReadI (int32 addr, int32 spec, int32 len); -t_bool ReadFP (fpac_t *fac, int32 addr, int32 spec, int32 len); -void WriteI (int32 data, int32 addr, int32 spec, int32 len); -void WriteFP (fpac_t *data, int32 addr, int32 spec, int32 len); -int32 setfcc (int32 old_status, int32 result_high, int32 newV); -int32 addfp11 (fpac_t *src1, fpac_t *src2); -int32 mulfp11 (fpac_t *src1, fpac_t *src2); -int32 divfp11 (fpac_t *src1, fpac_t *src2); -int32 modfp11 (fpac_t *src1, fpac_t *src2, fpac_t *frac); -void frac_mulfp11 (fpac_t *src1, fpac_t *src2); -int32 roundfp11 (fpac_t *src); -int32 round_and_pack (fpac_t *fac, int32 exp, fpac_t *frac, int r); - -extern int32 ReadW (int32 addr); -extern void WriteW (int32 data, int32 addr); -extern void set_stack_trap (int32 adr); - -/* Set up for instruction decode and execution */ - -void fp11 (int32 IR) -{ -int32 dst, ea, ac, dstspec; -int32 i, qdouble, lenf, leni; -int32 newV, exp, sign; -fpac_t fac, fsrc, modfrac; -static const uint32 i_limit[2][2] = { - { 0x80000000, 0x80010000 }, - { 0x80000000, 0x80000001 } - }; - -backup_PC = PC; /* save PC for FEA */ -fp_change = 0; /* assume no reg chg */ -ac = (IR >> 6) & 03; /* fac is IR<7:6> */ -dstspec = IR & 077; -qdouble = FPS & FPS_D; -lenf = qdouble? QUAD: LONG; -switch ((IR >> 8) & 017) { /* decode IR<11:8> */ - - case 000: - switch (ac) { /* decode IR<7:6> */ - - case 0: /* specials */ - if (IR == 0170000) { /* CFCC */ - N = (FPS >> PSW_V_N) & 1; - Z = (FPS >> PSW_V_Z) & 1; - V = (FPS >> PSW_V_V) & 1; - C = (FPS >> PSW_V_C) & 1; - } - else if (IR == 0170001) /* SETF */ - FPS = FPS & ~FPS_D; - else if (IR == 0170002) /* SETI */ - FPS = FPS & ~FPS_L; - else if (IR == 0170011) /* SETD */ - FPS = FPS | FPS_D; - else if (IR == 0170012) /* SETL */ - FPS = FPS | FPS_L; - else fpnotrap (FEC_OP); - break; - - case 1: /* LDFPS */ - dst = (dstspec <= 07)? R[dstspec]: ReadW (GeteaFW (dstspec)); - FPS = dst & FPS_RW; - break; - - case 2: /* STFPS */ - FPS = FPS & FPS_RW; - if (dstspec <= 07) - R[dstspec] = FPS; - else WriteW (FPS, GeteaFW (dstspec)); - break; - - case 3: /* STST */ - if (dstspec <= 07) - R[dstspec] = FEC; - else WriteI ((FEC << 16) | FEA, GeteaFP (dstspec, LONG), - dstspec, LONG); - break; - } /* end switch <7:6> */ - break; /* end case 0 */ - - case 001: - switch (ac) { /* decode IR<7:6> */ - - case 0: /* CLRf */ - WriteFP (&zero_fac, GeteaFP (dstspec, lenf), dstspec, lenf); - FPS = (FPS & ~FPS_CC) | FPS_Z; - break; - - case 1: /* TSTf */ - if (ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf)) - FPS = setfcc (FPS, fsrc.h, 0); - break; - - case 2: /* ABSf */ - if (ReadFP (&fsrc, ea = GeteaFP (dstspec, lenf), dstspec, lenf)) { - if (GET_EXP (fsrc.h) == 0) - fsrc = zero_fac; - else fsrc.h = fsrc.h & ~FP_SIGN; - WriteFP (&fsrc, ea, dstspec, lenf); - FPS = setfcc (FPS, fsrc.h, 0); - } - break; - - case 3: /* NEGf */ - if (ReadFP (&fsrc, ea = GeteaFP (dstspec, lenf), dstspec, lenf)) { - if (GET_EXP (fsrc.h) == 0) - fsrc = zero_fac; - else fsrc.h = fsrc.h ^ FP_SIGN; - WriteFP (&fsrc, ea, dstspec, lenf); - FPS = setfcc (FPS, fsrc.h, 0); - } - break; - } /* end switch <7:6> */ - break; /* end case 1 */ - - case 005: /* LDf */ - if (ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf)) { - F_STORE (qdouble, fsrc, FR[ac]); - FPS = setfcc (FPS, fsrc.h, 0); - } - break; - - case 010: /* STf */ - F_LOAD (qdouble, FR[ac], fac); - WriteFP (&fac, GeteaFP (dstspec, lenf), dstspec, lenf); - break; - - case 017: /* LDCff' */ - if (ReadFP (&fsrc, GeteaFP (dstspec, 12 - lenf), dstspec, 12 - lenf)) { - if (GET_EXP (fsrc.h) == 0) - fsrc = zero_fac; - if ((FPS & (FPS_D + FPS_T)) == 0) - newV = roundfp11 (&fsrc); - else newV = 0; - F_STORE (qdouble, fsrc, FR[ac]); - FPS = setfcc (FPS, fsrc.h, newV); - } - break; - - case 014: /* STCff' */ - F_LOAD (qdouble, FR[ac], fac); - if (GET_EXP (fac.h) == 0) - fac = zero_fac; - if ((FPS & (FPS_D + FPS_T)) == FPS_D) - newV = roundfp11 (&fac); - else newV = 0; - WriteFP (&fac, GeteaFP (dstspec, 12 - lenf), dstspec, 12 - lenf); - FPS = setfcc (FPS, fac.h, newV); - break; - - case 007: /* CMPf */ - if (ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf)) { - F_LOAD (qdouble, FR[ac], fac); - if (GET_EXP (fsrc.h) == 0) - fsrc = zero_fac; - if (GET_EXP (fac.h) == 0) - fac = zero_fac; - if ((fsrc.h == fac.h) && (fsrc.l == fac.l)) { /* equal? */ - FPS = (FPS & ~FPS_CC) | FPS_Z; - if ((fsrc.h | fsrc.l) == 0) { /* zero? */ - F_STORE (qdouble, zero_fac, FR[ac]); - } - } - else { /* unequal */ - FPS = (FPS & ~FPS_CC) | ((fsrc.h >> (FP_V_SIGN - PSW_V_N)) & FPS_N); - if ((GET_SIGN (fsrc.h ^ fac.h) == 0) && (fac.h != 0) && - F_LT (fsrc, fac)) - FPS = FPS ^ FPS_N; - } - } - break; - - case 015: /* LDEXP */ - dst = (dstspec <= 07)? R[dstspec]: ReadW (GeteaFW (dstspec)); - F_LOAD (qdouble, FR[ac], fac); - fac.h = (fac.h & ~FP_EXP) | (((dst + FP_BIAS) & FP_M_EXP) << FP_V_EXP); - newV = 0; - if ((dst > 0177) && (dst <= 0177600)) { - if (dst < 0100000) { - if (fpnotrap (FEC_OVFLO)) - fac = zero_fac; - newV = FPS_V; - } - else { - if (fpnotrap (FEC_UNFLO)) - fac = zero_fac; - } - } - F_STORE (qdouble, fac, FR[ac]); - FPS = setfcc (FPS, fac.h, newV); - break; - - case 012: /* STEXP */ - dst = (GET_EXP (FR[ac].h) - FP_BIAS) & 0177777; - N = GET_SIGN_W (dst); - Z = (dst == 0); - V = 0; - C = 0; - FPS = (FPS & ~FPS_CC) | (N << PSW_V_N) | (Z << PSW_V_Z); - if (dstspec <= 07) - R[dstspec] = dst; - else WriteW (dst, GeteaFW (dstspec)); - break; - - case 016: /* LDCif */ - leni = FPS & FPS_L? LONG: WORD; - if (dstspec <= 07) - fac.l = R[dstspec] << 16; - else fac.l = ReadI (GeteaFP (dstspec, leni), dstspec, leni); - fac.h = 0; - if (fac.l) { - if ((sign = GET_SIGN_L (fac.l))) - fac.l = (fac.l ^ 0xFFFFFFFF) + 1; - for (i = 0; GET_SIGN_L (fac.l) == 0; i++) - fac.l = fac.l << 1; - exp = ((FPS & FPS_L)? FP_BIAS + 32: FP_BIAS + 16) - i; - fac.h = (sign << FP_V_SIGN) | (exp << FP_V_EXP) | - ((fac.l >> (31 - FP_V_HB)) & FP_FRACH); - fac.l = (fac.l << (FP_V_HB + 1)) & FP_FRACL; - if ((FPS & (FPS_D + FPS_T)) == 0) - roundfp11 (&fac); - } - F_STORE (qdouble, fac, FR[ac]); - FPS = setfcc (FPS, fac.h, 0); - break; - - case 013: /* STCfi */ - sign = GET_SIGN (FR[ac].h); /* get sign, */ - exp = GET_EXP (FR[ac].h); /* exponent, */ - F_LOAD_FRAC (qdouble, FR[ac], fac); /* fraction */ - if (FPS & FPS_L) { - leni = LONG; - i = FP_BIAS + 32; - } - else { - leni = WORD; - i = FP_BIAS + 16; - } - C = 0; - if (exp <= FP_BIAS) - dst = 0; - else if (exp > i) { - dst = 0; - C = 1; - } - else { - F_RSH_V (fac, FP_V_HB + 1 + i - exp, fsrc); - if (leni == WORD) - fsrc.l = fsrc.l & ~0177777; - if (fsrc.l >= i_limit[leni == LONG][sign]) { - dst = 0; - C = 1; - } - else { - dst = fsrc.l; - if (sign) - dst = -dst; - } - } - N = GET_SIGN_L (dst); - Z = (dst == 0); - V = 0; - if (C) - fpnotrap (FEC_ICVT); - FPS = (FPS & ~FPS_CC) | (N << PSW_V_N) | - (Z << PSW_V_Z) | (C << PSW_V_C); - if (dstspec <= 07) - R[dstspec] = (dst >> 16) & 0177777; - else WriteI (dst, GeteaFP (dstspec, leni), dstspec, leni); - break; - - case 002: /* MULf */ - if (ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf)) { - F_LOAD (qdouble, FR[ac], fac); - newV = mulfp11 (&fac, &fsrc); - F_STORE (qdouble, fac, FR[ac]); - FPS = setfcc (FPS, fac.h, newV); - } - break; - - case 003: /* MODf */ - if (ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf)) { - F_LOAD (qdouble, FR[ac], fac); - newV = modfp11 (&fac, &fsrc, &modfrac); - F_STORE (qdouble, fac, FR[ac | 1]); - F_STORE (qdouble, modfrac, FR[ac]); - FPS = setfcc (FPS, modfrac.h, newV); - } - break; - - case 004: /* ADDf */ - if (ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf)) { - F_LOAD (qdouble, FR[ac], fac); - newV = addfp11 (&fac, &fsrc); - F_STORE (qdouble, fac, FR[ac]); - FPS = setfcc (FPS, fac.h, newV); - } - break; - - case 006: /* SUBf */ - if (ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf)) { - F_LOAD (qdouble, FR[ac], fac); - if (GET_EXP (fsrc.h) != 0) - fsrc.h = fsrc.h ^ FP_SIGN; - newV = addfp11 (&fac, &fsrc); - F_STORE (qdouble, fac, FR[ac]); - FPS = setfcc (FPS, fac.h, newV); - } - break; - - case 011: /* DIVf */ - if (ReadFP (&fsrc, GeteaFP (dstspec, lenf), dstspec, lenf)) { - F_LOAD (qdouble, FR[ac], fac); - if (GET_EXP (fsrc.h) == 0) /* divide by zero? */ - fpnotrap (FEC_DZRO); - else { /* no, do divide */ - newV = divfp11 (&fac, &fsrc); - F_STORE (qdouble, fac, FR[ac]); - FPS = setfcc (FPS, fac.h, newV); - } - } - break; - } /* end switch fop */ - -/* Now process any general register modification */ - -if (fp_change != 0) { - int32 reg = FPCHG_GETREG (fp_change); /* get register */ - int32 val = FPCHG_GETVAL (fp_change); /* get value */ - if (val & 020) /* negative? */ - val = val | (-16); /* ensure proper sext */ - R[reg] = (R[reg] + val) & 0177777; /* commit change */ - } -return; -} - -/* Effective address calculation for word integers */ - -int32 GeteaFW (int32 spec) -{ -int32 adr, reg, ds; - -reg = spec & 07; /* register number */ -ds = (reg == 7)? isenable: dsenable; /* dspace if not PC */ -switch (spec >> 3) { /* decode spec<5:3> */ - - default: /* can't get here */ - case 1: /* (R) */ - return (R[reg] | ds); - - case 2: /* (R)+ */ - adr = R[reg]; /* post increment */ - if (reg == 7) /* commit PC chg now */ - R[reg] = (R[reg] + 2) & 0177777; - else fp_change = FPCHG (2, reg); /* others, update later */ - return (adr | ds); - - case 3: /* @(R)+ */ - adr = R[reg]; /* post increment */ - if (reg == 7) /* commit PC chg now */ - R[reg] = (R[reg] + 2) & 0177777; - else fp_change = FPCHG (2, reg); /* others, update later */ - adr = ReadW (adr | ds); - return (adr | dsenable); - - case 4: /* -(R) */ - adr = (R[reg] - 2) & 0177777; /* predecrement */ - if (reg == 7) /* commit PC chg now */ - R[reg] = adr; - else fp_change = FPCHG (-2, reg); /* others, update later */ - if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y))) - set_stack_trap (adr); - return (adr | ds); - - case 5: /* @-(R) */ - adr = (R[reg] - 2) & 0177777; /* predecrement */ - if (reg == 7) /* commit PC chg now */ - R[reg] = adr; - else fp_change = FPCHG (-2, reg); /* others, update later */ - if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y))) - set_stack_trap (adr); - adr = ReadW (adr | ds); - return (adr | dsenable); - - case 6: /* d(r) */ - adr = ReadW (PC | isenable); - PC = (PC + 2) & 0177777; - return (((R[reg] + adr) & 0177777) | dsenable); - - case 7: /* @d(R) */ - adr = ReadW (PC | isenable); - PC = (PC + 2) & 0177777; - adr = ReadW (((R[reg] + adr) & 0177777) | dsenable); - return (adr | dsenable); - } /* end switch */ -} - -/* Effective address calculation for fp operands - - Inputs: - spec = specifier - len = length - Outputs: - VA = virtual address - - Warnings: - - Do not call this routine for integer mode 0 operands - - Do not call this routine more than once per instruction - - Note that for modes 06 and 07, it is OKAY to bail out of the FP - instruction immediately; no general register updates can occur. -*/ - -int32 GeteaFP (int32 spec, int32 len) -{ -int32 adr, reg, ds; - -reg = spec & 07; /* reg number */ -ds = (reg == 7)? isenable: dsenable; /* dspace if not PC */ -switch (spec >> 3) { /* case on spec */ - - case 0: /* floating AC */ - if (reg >= 06) { - fpnotrap (FEC_OP); - ABORT (TRAP_INT); /* scuttle instr */ - } - return 0; - - case 1: /* (R) */ - return (R[reg] | ds); - - case 2: /* (R)+ */ - adr = R[reg]; /* post increment */ - if (reg == 7) /* commit PC chg now */ - R[reg] = (R[reg] + 2) & 0177777; - else fp_change = FPCHG (len, reg); /* others, update later */ - return (adr | ds); - - case 3: /* @(R)+ */ - adr = R[reg]; /* post increment */ - if (reg == 7) /* commit PC chg now */ - R[reg] = (R[reg] + 2) & 0177777; - else fp_change = FPCHG (2, reg); /* others, update later */ - adr = ReadW (adr | ds); - return (adr | dsenable); - - case 4: /* -(R) */ - adr = (R[reg] - len) & 0177777; /* predecrement */ - if (reg == 7) /* commit PC chg now */ - R[reg] = adr; - else fp_change = FPCHG (-len, reg); /* others, udpate later */ - if ((reg == 6) && (cm == MD_KER) && (adr < (STKLIM + STKL_Y))) - set_stack_trap (adr); - return (adr | ds); - - case 5: /* @-(R) */ - adr = (R[reg] - 2) & 0177777; /* predecrement */ - if (reg == 7) /* commit PC chg now */ - R[reg] = adr; - else fp_change = FPCHG (-2, reg); /* others, update later */ - if ((reg == 6) && (cm == MD_KER) && ((adr - 2) < (STKLIM + STKL_Y))) - set_stack_trap (adr); - adr = ReadW (adr | ds); - return (adr | dsenable); - - case 6: /* d(r) */ - adr = ReadW (PC | isenable); - PC = (PC + 2) & 0177777; - return (((R[reg] + adr) & 0177777) | dsenable); - - case 7: /* @d(R) */ - adr = ReadW (PC | isenable); - PC = (PC + 2) & 0177777; - adr = ReadW (((R[reg] + adr) & 0177777) | dsenable); - return (adr | dsenable); - } /* end switch */ - -return 0; -} - -/* Read integer operand - - Inputs: - VA = virtual address, VA<18:16> = mode, I/D space - spec = specifier - len = length (2/4 bytes) - Outputs: - data = data read from memory or I/O space -*/ - -uint32 ReadI (int32 VA, int32 spec, int32 len) -{ -if ((len == WORD) || (spec == 027)) - return (ReadW (VA) << 16); -return ((ReadW (VA) << 16) | - ReadW ((VA & ~0177777) | ((VA + 2) & 0177777))); -} - -/* Read floating operand - - Inputs: - fptr = pointer to output - VA = virtual address, VA<18:16> = mode, I/D space - spec = specifier - len = length (4/8 bytes) - Output: - TRUE if read succeeded - FALSE if instruction must be NOP'd -*/ - -t_bool ReadFP (fpac_t *fptr, int32 VA, int32 spec, int32 len) -{ -int32 exta; - -if (spec <= 07) { - F_LOAD_P (len == QUAD, FR[spec], fptr); - return TRUE; - } -if (spec == 027) { - fptr->h = (ReadW (VA) << FP_V_F0); - fptr->l = 0; - } -else { - exta = VA & ~0177777; - fptr->h = (ReadW (VA) << FP_V_F0) | - (ReadW (exta | ((VA + 2) & 0177777)) << FP_V_F1); - if (len == QUAD) fptr->l = - (ReadW (exta | ((VA + 4) & 0177777)) << FP_V_F2) | - (ReadW (exta | ((VA + 6) & 0177777)) << FP_V_F3); - else fptr->l = 0; - } -if ((GET_SIGN (fptr->h) != 0) && - (GET_EXP (fptr->h) == 0) && - (fpnotrap (FEC_UNDFV) == 0)) - return FALSE; -return TRUE; -} - -/* Write integer result - - Inputs: - data = data to be written - VA = virtual address, VA<18:16> = mode, I/D space - spec = specifier - len = length - Outputs: none -*/ - -void WriteI (int32 data, int32 VA, int32 spec, int32 len) -{ -WriteW ((data >> 16) & 0177777, VA); -if ((len == WORD) || (spec == 027)) - return; -WriteW (data & 0177777, (VA & ~0177777) | ((VA + 2) & 0177777)); -return; -} - -/* Write floating result - - Inputs: - fptr = pointer to data to be written - VA = virtual address, VA<18:16> = mode, I/D space - spec = specifier - len = length - Outputs: none -*/ - -void WriteFP (fpac_t *fptr, int32 VA, int32 spec, int32 len) -{ -int32 exta; - -if (spec <= 07) { - F_STORE_P (len == QUAD, fptr, FR[spec]); - return; - } -WriteW ((fptr->h >> FP_V_F0) & 0177777, VA); -if (spec == 027) - return; -exta = VA & ~0177777; -WriteW ((fptr->h >> FP_V_F1) & 0177777, exta | ((VA + 2) & 0177777)); -if (len == LONG) - return; -WriteW ((fptr->l >> FP_V_F2) & 0177777, exta | ((VA + 4) & 0177777)); -WriteW ((fptr->l >> FP_V_F3) & 0177777, exta | ((VA + 6) & 0177777)); -return; -} - -/* FIS instructions */ - -t_stat fis11 (int32 IR) -{ -int32 reg, exta; -fpac_t fac, fsrc; - -reg = IR & 07; /* isolate reg */ -if (reg == 7) /* choose I,D */ - exta = isenable; -else exta = dsenable; -if (IR & 000740) { /* defined? */ - if (CPUT (CPUT_03)) /* 11/03 reads word */ - ReadW (exta | R[reg]); - ABORT (TRAP_ILL); - } -FEC = 0; /* no errors */ -FPS = FPS_IU|FPS_IV; /* trap ovf,unf */ - -fsrc.h = (ReadW (exta | R[reg]) << FP_V_F0) | - (ReadW (exta | ((R[reg] + 2) & 0177777)) << FP_V_F1); -fsrc.l = 0; -fac.h = (ReadW (exta | ((R[reg] + 4) & 0177777)) << FP_V_F0) | - (ReadW (exta | ((R[reg] + 6) & 0177777)) << FP_V_F1); -fac.l = 0; -if (GET_SIGN (fsrc.h) && (GET_EXP (fsrc.h) == 0)) /* clean 0's */ - fsrc.h = fsrc.l = 0; -if (GET_SIGN (fac.h) && (GET_EXP (fac.l) == 0)) - fac.h = fac.l = 0; - -N = Z = V = C = 0; /* clear cc's */ -switch ((IR >> 3) & 3) { /* case IR<5:3> */ - - case 0: /* FAD */ - addfp11 (&fac, &fsrc); - break; - - case 1: /* FSUB */ - if (fsrc.h != 0) /* invert sign */ - fsrc.h = fsrc.h ^ FP_SIGN; - addfp11 (&fac, &fsrc); - break; - - case 2: /* FMUL */ - mulfp11 (&fac, &fsrc); - break; - - case 3: /* FDIV */ - if (fsrc.h == 0) { /* div by 0? */ - V = N = C = 1; /* set cc's */ - setTRAP (TRAP_FPE); /* set trap */ - return SCPE_OK; - } - else divfp11 (&fac, &fsrc); - break; - } - -if (FEC == 0) { /* no err? */ - WriteW ((fac.h >> FP_V_F0) & 0177777, exta | ((R[reg] + 4) & 0177777)); - WriteW ((fac.h >> FP_V_F1) & 0177777, exta | ((R[reg] + 6) & 0177777)); - R[reg] = (R[reg] + 4) & 0177777; /* pop stack */ - N = (GET_SIGN (fac.h) != 0); /* set N,Z */ - Z = (fac.h == 0); - } -else if (FEC == FEC_OVFLO) /* ovf? trap set */ - V = 1; -else if (FEC == FEC_UNFLO) /* unf? trap set */ - V = N = 1; -else return SCPE_IERR; /* what??? */ -return SCPE_OK; -} - -/* Floating point add - - Inputs: - facp = pointer to src1 (output) - fsrcp = pointer to src2 - Outputs: - ovflo = overflow variable -*/ - -int32 addfp11 (fpac_t *facp, fpac_t *fsrcp) -{ -int32 facexp, fsrcexp, ediff; -fpac_t facfrac, fsrcfrac; - -if (F_LT_AP (facp, fsrcp)) { /* if !fac! < !fsrc! */ - facfrac = *facp; - *facp = *fsrcp; /* swap operands */ - *fsrcp = facfrac; - } -facexp = GET_EXP (facp->h); /* get exponents */ -fsrcexp = GET_EXP (fsrcp->h); -if (facexp == 0) { /* fac = 0? */ - *facp = fsrcexp? *fsrcp: zero_fac; /* result fsrc or 0 */ - return 0; - } -if (fsrcexp == 0) /* fsrc = 0? no op */ - return 0; -ediff = facexp - fsrcexp; /* exponent diff */ -if (ediff >= 60) /* too big? no op */ - return 0; -F_GET_FRAC_P (facp, facfrac); /* get fractions */ -F_GET_FRAC_P (fsrcp, fsrcfrac); -F_LSH_GUARD (facfrac); /* guard fractions */ -F_LSH_GUARD (fsrcfrac); -if (GET_SIGN (facp->h) != GET_SIGN (fsrcp->h)) { /* signs different? */ - if (ediff) { /* sub, shf fsrc */ - F_RSH_V (fsrcfrac, ediff, fsrcfrac); - } - F_SUB (fsrcfrac, facfrac, facfrac); /* sub fsrc from fac */ - if ((facfrac.h | facfrac.l) == 0) { /* result zero? */ - *facp = zero_fac; /* no overflow */ - return 0; - } - if (ediff <= 1) { /* big normalize? */ - if ((facfrac.h & (0x00FFFFFF << FP_GUARD)) == 0) { - F_LSH_K (facfrac, 24, facfrac); - facexp = facexp - 24; - } - if ((facfrac.h & (0x00FFF000 << FP_GUARD)) == 0) { - F_LSH_K (facfrac, 12, facfrac); - facexp = facexp - 12; - } - if ((facfrac.h & (0x00FC0000 << FP_GUARD)) == 0) { - F_LSH_K (facfrac, 6, facfrac); - facexp = facexp - 6; - } - } - while (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD) == 0) { - F_LSH_1 (facfrac); - facexp = facexp - 1; - } - } -else { - if (ediff) { - F_RSH_V (fsrcfrac, ediff, fsrcfrac); /* add, shf fsrc */ - } - F_ADD (fsrcfrac, facfrac, facfrac); /* add fsrc to fac */ - if (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD + 1)) { - F_RSH_1 (facfrac); /* carry out, shift */ - facexp = facexp + 1; - } - } -return round_and_pack (facp, facexp, &facfrac, 1); -} - -/* Floating point multiply - - Inputs: - facp = pointer to src1 (output) - fsrcp = pointer to src2 - Outputs: - ovflo = overflow indicator -*/ - -int32 mulfp11 (fpac_t *facp, fpac_t *fsrcp) -{ -int32 facexp, fsrcexp; -fpac_t facfrac, fsrcfrac; - -facexp = GET_EXP (facp->h); /* get exponents */ -fsrcexp = GET_EXP (fsrcp->h); -if ((facexp == 0) || (fsrcexp == 0)) { /* test for zero */ - *facp = zero_fac; - return 0; - } -F_GET_FRAC_P (facp, facfrac); /* get fractions */ -F_GET_FRAC_P (fsrcp, fsrcfrac); -facexp = facexp + fsrcexp - FP_BIAS; /* calculate exp */ -facp->h = facp->h ^ fsrcp->h; /* calculate sign */ -frac_mulfp11 (&facfrac, &fsrcfrac); /* multiply fracs */ - -/* Multiplying two numbers in the range [.5,1) produces a result in the - range [.25,1). Therefore, at most one bit of normalization is required - to bring the result back to the range [.5,1). -*/ - -if (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD) == 0) { - F_LSH_1 (facfrac); - facexp = facexp - 1; - } -return round_and_pack (facp, facexp, &facfrac, 1); -} - -/* Floating point mod - - Inputs: - facp = pointer to src1 (integer result) - fsrcp = pointer to src2 - fracp = pointer to fractional result - Outputs: - ovflo = overflow indicator - - See notes on multiply for initial operation -*/ - -int32 modfp11 (fpac_t *facp, fpac_t *fsrcp, fpac_t *fracp) -{ -int32 facexp, fsrcexp; -fpac_t facfrac, fsrcfrac, fmask; - -facexp = GET_EXP (facp->h); /* get exponents */ -fsrcexp = GET_EXP (fsrcp->h); -if ((facexp == 0) || (fsrcexp == 0)) { /* test for zero */ - *fracp = zero_fac; - *facp = zero_fac; - return 0; - } -F_GET_FRAC_P (facp, facfrac); /* get fractions */ -F_GET_FRAC_P (fsrcp, fsrcfrac); -facexp = facexp + fsrcexp - FP_BIAS; /* calculate exp */ -fracp->h = facp->h = facp->h ^ fsrcp->h; /* calculate sign */ -frac_mulfp11 (&facfrac, &fsrcfrac); /* multiply fracs */ - -/* Multiplying two numbers in the range [.5,1) produces a result in the - range [.25,1). Therefore, at most one bit of normalization is required - to bring the result back to the range [.5,1). -*/ - -if (GET_BIT (facfrac.h, FP_V_HB + FP_GUARD) == 0) { - F_LSH_1 (facfrac); - facexp = facexp - 1; - } - -/* There are three major cases of MODf: - - 1. Exp <= FP_BIAS (all fraction). Return 0 as integer, product as - fraction. Underflow can occur. - 2. Exp > FP_BIAS + #fraction bits (all integer). Return product as - integer, 0 as fraction. Overflow can occur. - 3. FP_BIAS < exp <= FP_BIAS + #fraction bits. Separate integer and - fraction and return both. Neither overflow nor underflow can occur. -*/ - -if (facexp <= FP_BIAS) { /* case 1 */ - *facp = zero_fac; - return round_and_pack (fracp, facexp, &facfrac, 1); - } -if (facexp > ((FPS & FPS_D)? FP_BIAS + 56: FP_BIAS + 24)) { - *fracp = zero_fac; /* case 2 */ - return round_and_pack (facp, facexp, &facfrac, 0); - } -F_RSH_V (fmask_fac, facexp - FP_BIAS, fmask); /* shift mask */ -fsrcfrac.l = facfrac.l & fmask.l; /* extract fraction */ -fsrcfrac.h = facfrac.h & fmask.h; -if ((fsrcfrac.h | fsrcfrac.l) == 0) - *fracp = zero_fac; -else { - F_LSH_V (fsrcfrac, facexp - FP_BIAS, fsrcfrac); - fsrcexp = FP_BIAS; - if ((fsrcfrac.h & (0x00FFFFFF << FP_GUARD)) == 0) { - F_LSH_K (fsrcfrac, 24, fsrcfrac); - fsrcexp = fsrcexp - 24; - } - if ((fsrcfrac.h & (0x00FFF000 << FP_GUARD)) == 0) { - F_LSH_K (fsrcfrac, 12, fsrcfrac); - fsrcexp = fsrcexp - 12; - } - if ((fsrcfrac.h & (0x00FC0000 << FP_GUARD)) == 0) { - F_LSH_K (fsrcfrac, 6, fsrcfrac); - fsrcexp = fsrcexp - 6; - } - while (GET_BIT (fsrcfrac.h, FP_V_HB + FP_GUARD) == 0) { - F_LSH_1 (fsrcfrac); - fsrcexp = fsrcexp - 1; - } - round_and_pack (fracp, fsrcexp, &fsrcfrac, 1); - } -facfrac.l = facfrac.l & ~fmask.l; -facfrac.h = facfrac.h & ~fmask.h; -return round_and_pack (facp, facexp, &facfrac, 0); -} - -/* Fraction multiply - - Inputs: - f1p = pointer to multiplier (output) - f2p = pointer to multiplicand fraction - - Note: the inputs are unguarded; the output is guarded. - - This routine performs a classic shift-and-add multiply. The low - order bit of the multiplier is tested; if 1, the multiplicand is - added into the high part of the double precision result. The - result and the multiplier are both shifted right 1. - - For the 24b x 24b case, this routine develops 48b of result. - For the 56b x 56b case, this routine only develops the top 64b - of the the result. Because the inputs are normalized fractions, - the interesting part of the result is the high 56+guard bits. - Everything shifted off to the right, beyond 64b, plays no part - in rounding or the result. - - There are many possible optimizations in this routine: scanning - for groups of zeroes, particularly in the 56b x 56b case; using - "extended multiply" capability if available in the hardware. -*/ - -void frac_mulfp11 (fpac_t *f1p, fpac_t *f2p) -{ -fpac_t result, mpy, mpc; -int32 i; - -result = zero_fac; /* clear result */ -mpy = *f1p; /* get operands */ -mpc = *f2p; -F_LSH_GUARD (mpc); /* guard multipicand */ -if ((mpy.l | mpc.l) == 0) { /* 24b x 24b? */ - for (i = 0; i < 24; i++) { - if (mpy.h & 1) - result.h = result.h + mpc.h; - F_RSH_1 (result); - mpy.h = mpy.h >> 1; - } - } -else { - if (mpy.l != 0) { /* 24b x 56b? */ - for (i = 0; i < 32; i++) { - if (mpy.l & 1) { - F_ADD (mpc, result, result); - } - F_RSH_1 (result); - mpy.l = mpy.l >> 1; - } - } - for (i = 0; i < 24; i++) { - if (mpy.h & 1) { - F_ADD (mpc, result, result); - } - F_RSH_1 (result); - mpy.h = mpy.h >> 1; - } - } -*f1p = result; -return; -} - -/* Floating point divide - - Inputs: - facp = pointer to dividend (output) - fsrcp = pointer to divisor - Outputs: - ovflo = overflow indicator - - Source operand must be checked for zero by caller! -*/ - -int32 divfp11 (fpac_t *facp, fpac_t *fsrcp) -{ -int32 facexp, fsrcexp, i, count, qd; -fpac_t facfrac, fsrcfrac, quo; - -fsrcexp = GET_EXP (fsrcp->h); /* get divisor exp */ -facexp = GET_EXP (facp->h); /* get dividend exp */ -if (facexp == 0) { /* test for zero */ - *facp = zero_fac; /* result zero */ - return 0; - } -F_GET_FRAC_P (facp, facfrac); /* get fractions */ -F_GET_FRAC_P (fsrcp, fsrcfrac); -F_LSH_GUARD (facfrac); /* guard fractions */ -F_LSH_GUARD (fsrcfrac); -facexp = facexp - fsrcexp + FP_BIAS + 1; /* calculate exp */ -facp->h = facp->h ^ fsrcp->h; /* calculate sign */ -qd = FPS & FPS_D; -count = FP_V_HB + FP_GUARD + (qd? 33: 1); /* count = 56b/24b */ - -quo = zero_fac; -for (i = count; (i > 0) && ((facfrac.h | facfrac.l) != 0); i--) { - F_LSH_1 (quo); /* shift quotient */ - if (!F_LT (facfrac, fsrcfrac)) { /* divd >= divr? */ - F_SUB (fsrcfrac, facfrac, facfrac); /* divd - divr */ - if (qd) /* double or single? */ - quo.l = quo.l | 1; - else quo.h = quo.h | 1; - } - F_LSH_1 (facfrac); /* shift divd */ - } -if (i > 0) { /* early exit? */ - F_LSH_V (quo, i, quo); - } - -/* Dividing two numbers in the range [.5,1) produces a result in the - range [.5,2). Therefore, at most one bit of normalization is required - to bring the result back to the range [.5,1). The choice of counts - and quotient bit positions makes this work correctly. -*/ - -if (GET_BIT (quo.h, FP_V_HB + FP_GUARD) == 0) { - F_LSH_1 (quo); - facexp = facexp - 1; - } -return round_and_pack (facp, facexp, &quo, 1); -} - -/* Update floating condition codes - Note that FC is only set by STCfi via the integer condition codes - - Inputs: - oldst = current status - result = high result - newV = new V - Outputs: - newst = new status -*/ - -int32 setfcc (int32 oldst, int32 result, int32 newV) -{ -oldst = (oldst & ~FPS_CC) | newV; -if (GET_SIGN (result)) - oldst = oldst | FPS_N; -if (GET_EXP (result) == 0) - oldst = oldst | FPS_Z; -return oldst; -} - -/* Round (in place) floating point number to f_floating - - Inputs: - fptr = pointer to floating number - Outputs: - ovflow = overflow -*/ - -int32 roundfp11 (fpac_t *fptr) -{ -fpac_t outf; - -outf = *fptr; /* get argument */ -F_ADD (fround_fac, outf, outf); /* round */ -if (GET_SIGN (outf.h ^ fptr->h)) { /* flipped sign? */ - outf.h = (outf.h ^ FP_SIGN) & 0xFFFFFFFF; /* restore sign */ - if (fpnotrap (FEC_OVFLO)) /* if no int, clear */ - *fptr = zero_fac; - else *fptr = outf; /* return rounded */ - return FPS_V; /* overflow */ - } -*fptr = outf; /* round was ok */ -return 0; /* no overflow */ -} - -/* Round result of calculation, test overflow, pack - - Input: - facp = pointer to result, sign in place - exp = result exponent, right justified - fracp = pointer to result fraction, right justified with - guard bits - r = round (1) or truncate (0) - Outputs: - ovflo = overflow indicator -*/ - -int32 round_and_pack (fpac_t *facp, int32 exp, fpac_t *fracp, int r) -{ -fpac_t frac; - -frac = *fracp; /* get fraction */ -if (r && ((FPS & FPS_T) == 0)) { - if (FPS & FPS_D) { - F_ADD (dround_guard_fac, frac, frac); - } - else { - F_ADD (fround_guard_fac, frac, frac); - } - if (GET_BIT (frac.h, FP_V_HB + FP_GUARD + 1)) { - F_RSH_1 (frac); - exp = exp + 1; - } - } -F_RSH_GUARD (frac); -facp->l = frac.l & FP_FRACL; -facp->h = (facp->h & FP_SIGN) | ((exp & FP_M_EXP) << FP_V_EXP) | - (frac.h & FP_FRACH); -if (exp > 0377) { - if (fpnotrap (FEC_OVFLO)) - *facp = zero_fac; - return FPS_V; - } -if ((exp <= 0) && (fpnotrap (FEC_UNFLO))) - *facp = zero_fac; -return 0; -} - -/* Process floating point exception - - Inputs: - code = exception code - Outputs: - int = FALSE if interrupt enabled, TRUE if disabled -*/ - -int32 fpnotrap (int32 code) -{ -static const int32 test_code[] = { 0, 0, 0, FPS_IC, FPS_IV, FPS_IU, FPS_IUV }; - -if ((code >= FEC_ICVT) && - (code <= FEC_UNDFV) && - ((FPS & test_code[code >> 1]) == 0)) - return TRUE; -FPS = FPS | FPS_ER; -FEC = code; -FEA = (backup_PC - 2) & 0177777; -if ((FPS & FPS_ID) == 0) - setTRAP (TRAP_FPE); -return FALSE; -} diff --git a/PDP11/pdp11_hk.c b/PDP11/pdp11_hk.c deleted file mode 100644 index 03c6e7c5..00000000 --- a/PDP11/pdp11_hk.c +++ /dev/null @@ -1,1382 +0,0 @@ -/* pdp11_hk.c - RK611/RK06/RK07 disk controller - - Copyright (c) 1993-2013, Robert M Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PUHKOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - hk RK611/RK06/RK07 disk - - 23-Oct-13 RMS Revised for new boot setup routine - 01-Sep-13 RMS Revised error handling to command-response model - Revised interrupt logic to follow the hardware - 10-Jun-13 RMS Fixed bug to write through end of sector (Oleg Safiullin) - 18-Apr-13 RMS Fixed ATN setting on errors - Changed wrong drive type to status, not fatal error - 10-Dec-12 RMS Fixed interrupt logic and CCLR unit cancellation - 19-Mar-12 RMS Fixed declaration of cpu_opt (Mark Pizzolato) - 29-Apr-07 RMS NOP and DCLR (at least) do not check drive type [wrong] - MR2 and MR3 only updated on NOP - 17-Nov-05 RMS Removed unused variable - 13-Nov-05 RMS Fixed overlapped seek interaction with NOP, DCLR, PACK - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 07-Jul-05 RMS Removed extraneous externs - 18-Mar-05 RMS Added attached test to detach routine - 03-Oct-04 RMS Revised Unibus interface - RMS Fixed state of output ready for M+ - 26-Mar-04 RMS Fixed warnings with -std=c99 - 25-Jan-04 RMS Revised for device debug support - 04-Jan-04 RMS Changed sim_fsize calling sequence - 29-Dec-03 RMS Added 18b Qbus support - 25-Apr-03 RMS Revised for extended file support - - The RK611 functions only in 18b Unibus systems with I/O maps. The Emulex - SC02/C was a Qbus work-alike with a unique extension to 22b addressing. It - was only supported in Ultrix-11 and other third party software. - - This module includes ideas from a previous implementation by Fred Van Kempen. - However, the interrupt logic has been rewritten to follow the bug-for-bug - peculiarities of the RK611 controller. -*/ - -#if defined (VM_PDP10) /* PDP10 version */ -#error "RK611 is not supported on the PDP-10!" - -#elif defined (VM_VAX) /* VAX version */ -#include "vax_defs.h" - -#else /* PDP-11 version */ -#include "pdp11_defs.h" -extern uint32 cpu_opt; -#endif - -extern uint16 *M; - -#define HK_NUMDR 8 /* #drives */ -#define HK_NUMCY6 411 /* cyl/drive */ -#define HK_NUMCY7 815 /* cyl/drive */ -#define HK_NUMSF 3 /* tracks/cyl */ -#define HK_NUMSC 22 /* sectors/track */ -#define HK_NUMWD 256 /* words/sector */ -#define RK06_SIZE (HK_NUMCY6*HK_NUMSF*HK_NUMSC*HK_NUMWD) -#define RK07_SIZE (HK_NUMCY7*HK_NUMSF*HK_NUMSC*HK_NUMWD) -#define HK_SIZE(x) (((x)->flags & UNIT_DTYPE)? RK07_SIZE: RK06_SIZE) -#define HK_CYL(x) (((x)->flags & UNIT_DTYPE)? HK_NUMCY7: HK_NUMCY6) -#define HK_MAXFR (1 << 16) - -/* Flags in the unit flags word */ - -#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */ -#define UNIT_V_AUTO (UNIT_V_UF + 2) /* autosize */ -#define UNIT_V_DUMMY (UNIT_V_UF + 3) /* dummy flag */ -#define UNIT_WLK (1 << UNIT_V_WLK) -#define UNIT_DTYPE (1 << UNIT_V_DTYPE) -#define UNIT_RK06 (0 << UNIT_V_DTYPE) -#define UNIT_RK07 (1 << UNIT_V_DTYPE) -#define UNIT_AUTO (1 << UNIT_V_AUTO) -#define UNIT_DUMMY (1 << UNIT_V_DUMMY) -#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */ - -/* Parameters in the unit descriptor */ - -#define CYL u3 /* current cylinder */ -#define FNC u4 /* function */ - -/* HKCS1 - 177440 - control/status 1 ^ = calculated dynamically */ - -#define CS1_GO CSR_GO /* go */ -#define CS1_V_FNC 1 /* function pos */ -#define CS1_M_FNC 017 /* function mask */ -#define CS1_FNC (CS1_M_FNC << CS1_V_FNC) -#define FNC_NOP 000 /* no operation */ -#define FNC_PACK 001 /* pack acknowledge */ -#define FNC_DCLR 002 /* drive clear */ -#define FNC_UNLOAD 003 /* unload */ -#define FNC_START 004 /* start */ -#define FNC_RECAL 005 /* recalibrate */ -#define FNC_OFFSET 006 /* offset */ -#define FNC_SEEK 007 /* seek */ -#define FNC_XFER 010 -#define FNC_READ 010 /* read */ -#define FNC_WRITE 011 /* write */ -#define FNC_WRITEH 013 /* write w/ headers */ -#define FNC_READH 012 /* read w/ headers */ -#define FNC_WCHK 014 /* write check */ -#define FNC_2ND 020 /* 2nd state flag */ -#define CS1_SPA 0000040 /* spare */ -#define CS1_IE CSR_IE /* int enable */ -#define CS1_DONE CSR_DONE /* ready */ -#define CS1_V_UAE 8 /* Unibus addr ext */ -#define CS1_M_UAE 03 -#define CS1_UAE (CS1_M_UAE << CS1_V_UAE) -#define CS1_DT 0002000 /* drive type */ -#define CS1_CTO 0004000 /* ctrl timeout NI */ -#define CS1_FMT 0010000 /* 16b/18b NI */ -#define CS1_PAR 0020000 /* par err NI */ -#define CS1_DI 0040000 /* ^drive intr */ -#define CS1_ERR 0100000 /* error */ -#define CS1_CCLR 0100000 /* ctrl clear */ -#define CS1_RW (CS1_DT|CS1_UAE|CS1_IE|CS1_SPA|CS1_FNC) -#define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC) -#define GET_UAE(x) (((x) >> CS1_V_UAE) & CS1_M_UAE) -#define PUT_UAE(x,n) (((x) & ~ CS1_UAE) | (((n) << CS1_V_UAE) & CS1_UAE)) - -/* HKWC - 177442 - word count */ - -/* HKBA - 177444 - base address */ - -#define BA_MBZ 0000001 /* must be zero */ - -/* HKDA - 177446 - sector/track */ - -#define DA_V_SC 0 /* sector pos */ -#define DA_M_SC 037 /* sector mask */ -#define DA_V_SF 8 /* track pos */ -#define DA_M_SF 007 /* track mask */ -#define DA_MBZ 0174340 -#define GET_SC(x) (((x) >> DA_V_SC) & DA_M_SC) -#define GET_SF(x) (((x) >> DA_V_SF) & DA_M_SF) - -/* HKCS2 - 177450 - control/status 2 */ - -#define CS2_V_UNIT 0 /* unit pos */ -#define CS2_M_UNIT 07 /* unit mask */ -#define CS2_UNIT (CS2_M_UNIT << CS2_V_UNIT) -#define CS2_RLS 0000010 /* release NI */ -#define CS2_UAI 0000020 /* addr inhibit */ -#define CS2_CLR 0000040 /* controller clear */ -#define CS2_IR 0000100 /* input ready */ -#define CS2_OR 0000200 /* output ready */ -#define CS2_UFE 0000400 /* unit field err NI */ -#define CS2_MDS 0001000 /* multidrive sel NI */ -#define CS2_PGE 0002000 /* program err */ -#define CS2_NEM 0004000 /* nx mem err */ -#define CS2_NED 0010000 /* nx drive err */ -#define CS2_PE 0020000 /* parity err NI */ -#define CS2_WCE 0040000 /* write check err */ -#define CS2_DLT 0100000 /* data late NI */ -#define CS2_MBZ (CS2_CLR) -#define CS2_RW 0000037 -#define CS2_ERR (CS2_UFE | CS2_MDS | CS2_PGE | CS2_NEM | \ - CS2_NED | CS2_PE | CS2_WCE | CS2_DLT ) -#define GET_UNIT(x) (((x) >> CS2_V_UNIT) & CS2_M_UNIT) - -/* HKDS - 177452 - drive status ^ = calculated dynamically */ - -#define DS_DRA 0000001 /* ^drive avail */ -#define DS_OF 0000004 /* ^offset mode */ -#define DS_ACLO 0000010 /* ^AC LO NI */ -#define DS_SPLS 0000020 /* ^speed loss NI */ -#define DS_DOT 0000040 /* ^off track NI */ -#define DS_VV 0000100 /* volume valid */ -#define DS_RDY 0000200 /* ^drive ready */ -#define DS_DT 0000400 /* ^drive type */ -#define DS_WRL 0004000 /* ^write locked */ -#define DS_PIP 0020000 /* pos in progress */ -#define DS_ATA 0040000 /* attention active */ -#define DS_VLD 0100000 /* ^status valid */ -#define DS_MBZ 0013002 - -/* HKER - 177454 - error status */ - -#define ER_ILF 0000001 /* illegal func */ -#define ER_SKI 0000002 /* seek incomp */ -#define ER_NXF 0000004 /* non-exec func */ -#define ER_PAR 0000010 /* parity err */ -#define ER_FER 0000020 /* format err */ -#define ER_DTY 0000040 /* drive type err */ -#define ER_ECH 0000100 /* ECC hard err NI */ -#define ER_BSE 0000200 /* bad sector err NI */ -#define ER_HCR 0000400 /* hdr CRC err NI */ -#define ER_AOE 0001000 /* addr ovflo err */ -#define ER_IAE 0002000 /* invalid addr err */ -#define ER_WLE 0004000 /* write lock err */ -#define ER_DTE 0010000 /* drive time err NI */ -#define ER_OPI 0020000 /* op incomplete */ -#define ER_UNS 0040000 /* drive unsafe */ -#define ER_DCK 0100000 /* data check NI */ - -/* HKAS - 177456 - attention summary/offset */ - -#define AS_U0 0000400 /* unit 0 flag */ -#define AS_OF 0000277 /* offset mask */ - -/* HKDC - 177460 - desired cylinder */ - -#define DC_V_CY 0 /* cylinder pos */ -#define DC_M_CY 0001777 /* cylinder mask */ -#define DC_MBZ 0176000 -#define GET_CY(x) (((x) >> DC_V_CY) & DC_M_CY) -#define GET_DA(c,fs) ((((GET_CY (c) * HK_NUMSF) + \ - GET_SF (fs)) * HK_NUMSC) + GET_SC (fs)) - -/* Spare - 177462 - read/write */ - -#define XM_KMASK 0177700 /* Qbus XM key mask */ -#define XM_KEY 0022000 /* Qbus XM "key" */ -#define XM_MMASK 0000077 /* Qbus XM mask */ -#define SC02C (!UNIBUS && ((hkspr & XM_KMASK) == XM_KEY)) - -/* HKDB - 177464 - read/write */ - -/* HKMR - 177466 - maintenance register 1 */ - -#define MR_V_MS 0 /* message select */ -#define MR_M_MS 03 -#define MR_MS (MR_M_MS << MR_V_MS) -#define GET_MS(x) (((x) >> MR_V_MS) & MR_M_MS) -#define MR_PAR 0000020 /* force even parity */ -#define MR_DMD 0000040 /* diagnostic mode */ -#define MR_RW 0001777 - -/* HKEC1 - 177470 - ECC status 1 - always reads as 0 */ -/* HKEC2 - 177472 - ECC status 2 - always reads as 0 */ - -/* HKMR2 - 177474 - maintenance register 2 */ - -#define AX_V_UNIT 0 /* unit #, all msgs */ -#define AX_PAR 0100000 /* parity, all msgs */ - -#define A0_DRA 0000040 /* drive avail */ -#define A0_VV 0000100 /* vol valid */ -#define A0_RDY 0000200 /* drive ready */ -#define A0_DT 0000400 /* drive type */ -#define A0_FMT 0001000 /* format NI */ -#define A0_OF 0002000 /* offset mode */ -#define A0_WRL 0004000 /* write lock */ -#define A0_SPO 0010000 /* spindle on */ -#define A0_PIP 0020000 /* pos in prog */ -#define A0_ATA 0040000 /* attention */ - -#define A1_SRV 0000020 /* servo */ -#define A1_HHM 0000040 /* heads home */ -#define A1_BHM 0000100 /* brushes home */ -#define A1_DOR 0000200 /* door latched */ -#define A1_CAR 0000400 /* cartridge present */ -#define A1_SPD 0001000 /* speed ok */ -#define A1_FWD 0002000 /* seek fwd */ -#define A1_REV 0004000 /* seek rev */ -#define A1_LDH 0010000 /* loading heads NI */ -#define A1_RTZ 0020000 /* return to zero */ -#define A1_UNL 0040000 /* unloading heads */ - -#define A2_V_DIF 4 /* cyl diff */ -#define A2_M_DIF 0777 - -#define A3_V_SNO 3 /* serial # */ - -/* HKMR3 - 177476 - maintenance register 3 */ - -#define B0_IAE 0000040 /* invalid addr */ -#define B0_ACLO 0000100 /* AC LO NI */ -#define B0_FLT 0000200 /* fault */ -#define B0_NXF 0000400 /* non exec fnc */ -#define B0_CDP 0001000 /* msg parity err */ -#define B0_SKI 0002000 /* seek incomp */ -#define B0_WLE 0004000 /* write lock err */ -#define B0_SLO 0010000 /* speed low NI */ -#define B0_OFT 0020000 /* off track NI */ -#define B0_UNS 0040000 /* rw unsafe NI */ - -#define B1_SCE 0000020 /* sector err NI */ -#define B1_NWC 0000040 /* no write curr NI */ -#define B1_NWT 0000100 /* no write trans NI */ -#define B1_HFL 0000200 /* head fault NI */ -#define B1_MHS 0000400 /* multiselect NI */ -#define B1_IDX 0001000 /* index err NI */ -#define B1_TRI 0002000 /* tribit err NI */ -#define B1_SVE 0004000 /* servo err NI */ -#define B1_SKI 0010000 /* seek no mot */ -#define B1_LIM 0020000 /* seek limit NI */ -#define B1_SVU 0040000 /* servo unsafe NI */ - -#define B2_V_CYL 4 /* cylinder */ - -#define B3_V_SEC 4 /* sector */ -#define B3_V_DHA 9 /* decoded head */ - -/* Read header */ - -#define RDH1_V_CYL 0 /* cylinder */ -#define RDH2_V_SEC 0 /* sector */ -#define RDH2_V_DHA 5 /* decoded head */ -#define RDH2_GOOD 0140000 /* good sector flags */ - -/* Debug detail levels */ - -#define HKDEB_OPS 001 /* transactions */ -#define HKDEB_RRD 002 /* reg reads */ -#define HKDEB_RWR 004 /* reg writes */ - -extern int32 int_req[IPL_HLVL]; - -uint16 *hkxb = NULL; /* xfer buffer */ -int32 hkcs1 = 0; /* control/status 1 */ -int32 hkwc = 0; /* word count */ -int32 hkba = 0; /* bus address */ -int32 hkda = 0; /* track/sector */ -int32 hkcs2 = 0; /* control/status 2 */ -int32 hkds[HK_NUMDR] = { 0 }; /* drive status */ -int32 hker[HK_NUMDR] = { 0 }; /* error status */ -int32 hkof = 0; /* offset */ -int32 hkmr = 0; /* maint registers */ -int32 hkmr2 = 0; -int32 hkmr3 = 0; -int32 hkdc = 0; /* cylinder */ -int32 hkspr = 0; /* spare */ -int32 hkci = 0; /* ctlr interrupt */ -int32 hkdi = 0; /* drive interrupt */ -int32 hkei = 0; /* error interrupt */ -int32 hk_cwait = 5; /* command time */ -int32 hk_swait = 10; /* seek time */ -int32 hk_rwait = 10; /* rotate time */ -int32 hk_min2wait = 300; /* min time to 2nd int */ -int16 hkdb[3] = { 0 }; /* data buffer silo */ -int16 hk_off[HK_NUMDR] = { 0 }; /* saved offset */ -int16 hk_dif[HK_NUMDR] = { 0 }; /* cylinder diff */ -static const uint8 reg_in_drive[16] = { - 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -static const char* reg_name[] = { - "HKCS1", "HKWC", "HKBA", "HKDA", - "HKCS2", "HKDS", "HKER", "HKAS", - "HKDC", "spare", "HKDB", "HKMR", - "HKEC1", "HKEC2", "HKMR2", "HKMR3" }; - -t_stat hk_rd (int32 *data, int32 PA, int32 access); -t_stat hk_wr (int32 data, int32 PA, int32 access); -t_stat hk_svc (UNIT *uptr); -t_stat hk_reset (DEVICE *dptr); -t_stat hk_boot (int32 unitno, DEVICE *dptr); -t_stat hk_attach (UNIT *uptr, char *cptr); -t_stat hk_detach (UNIT *uptr); -int32 hk_inta (void); -int32 hk_rdmr2 (int32 msg); -int32 hk_rdmr3 (int32 msg); -void update_hkcs (int32 flags, int32 drv); -void update_hkds (int32 drv); -void hk_err (int32 cs1e, int32 cs2e, int32 drve, int32 drv); -void hk_go (int32 drv); -t_stat hk_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat hk_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc); - -/* HK data structures - - hk_dev HK device descriptor - hk_unit HK unit list - hk_reg HK register list - hk_mod HK modifier list -*/ - -DIB hk_dib = { - IOBA_HK, IOLN_HK, &hk_rd, &hk_wr, - 1, IVCL (HK), VEC_HK, { &hk_inta } - }; - -UNIT hk_unit[] = { - { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - UNIT_ROABLE+UNIT_RK06, RK06_SIZE) }, - { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - UNIT_ROABLE+UNIT_RK06, RK06_SIZE) }, - { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - UNIT_ROABLE+UNIT_RK06, RK06_SIZE) }, - { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - UNIT_ROABLE+UNIT_RK06, RK06_SIZE) }, - { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - UNIT_ROABLE+UNIT_RK06, RK06_SIZE) }, - { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - UNIT_ROABLE+UNIT_RK06, RK06_SIZE) }, - { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - UNIT_ROABLE+UNIT_RK06, RK06_SIZE) }, - { UDATA (&hk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - UNIT_ROABLE+UNIT_RK06, RK06_SIZE) } - }; - -REG hk_reg[] = { - { GRDATA (HKCS1, hkcs1, DEV_RDX, 16, 0) }, - { GRDATA (HKWC, hkwc, DEV_RDX, 16, 0) }, - { GRDATA (HKBA, hkba, DEV_RDX, 16, 0) }, - { GRDATA (HKDA, hkda, DEV_RDX, 16, 0) }, - { GRDATA (HKCS2, hkcs2, DEV_RDX, 16, 0) }, - { BRDATA (HKDS, hkds, DEV_RDX, 16, HK_NUMDR) }, - { BRDATA (HKER, hker, DEV_RDX, 16, HK_NUMDR) }, - { BRDATA (HKDB, hkdb, DEV_RDX, 16, 3) }, - { GRDATA (HKDC, hkdc, DEV_RDX, 16, 0) }, - { GRDATA (HKOF, hkof, DEV_RDX, 8, 0) }, - { GRDATA (HKMR, hkmr, DEV_RDX, 16, 0) }, - { GRDATA (HKMR2, hkmr2, DEV_RDX, 16, 0), REG_RO }, - { GRDATA (HKMR3, hkmr3, DEV_RDX, 16, 0), REG_RO }, - { GRDATA (HKSPR, hkspr, DEV_RDX, 16, 0) }, - { FLDATA (HKCI, hkci, 0) }, - { FLDATA (HKDI, hkdi, 0) }, - { FLDATA (HKEI, hkei, 0) }, - { FLDATA (INT, IREQ (HK), INT_V_HK) }, - { FLDATA (ERR, hkcs1, CSR_V_ERR) }, - { FLDATA (DONE, hkcs1, CSR_V_DONE) }, - { FLDATA (IE, hkcs1, CSR_V_IE) }, - { DRDATA (CTIME, hk_cwait, 24), REG_NZ + PV_LEFT }, - { DRDATA (STIME, hk_swait, 24), REG_NZ + PV_LEFT }, - { DRDATA (RTIME, hk_rwait, 24), REG_NZ + PV_LEFT }, - { DRDATA (M2TIME, hk_min2wait, 24), REG_NZ + PV_LEFT }, - { DRDATA (MIN2TIME, hk_min2wait, 24), REG_NZ + PV_LEFT + REG_HRO }, - { URDATA (FNC, hk_unit[0].FNC, DEV_RDX, 5, 0, - HK_NUMDR, REG_HRO) }, - { URDATA (CYL, hk_unit[0].CYL, DEV_RDX, 10, 0, - HK_NUMDR, REG_HRO) }, - { BRDATA (OFFSET, hk_off, DEV_RDX, 16, HK_NUMDR), REG_HRO }, - { BRDATA (CYLDIF, hk_dif, DEV_RDX, 16, HK_NUMDR), REG_HRO }, - { URDATA (CAPAC, hk_unit[0].capac, 10, T_ADDR_W, 0, - HK_NUMDR, PV_LEFT | REG_HRO) }, - { GRDATA (DEVADDR, hk_dib.ba, DEV_RDX, 32, 0), REG_HRO }, - { GRDATA (DEVVEC, hk_dib.vec, DEV_RDX, 16, 0), REG_HRO }, - { NULL } - }; - -MTAB hk_mod[] = { - { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, - { UNIT_DUMMY, 0, NULL, "BADBLOCK", &hk_set_bad }, - { (UNIT_DTYPE+UNIT_ATT), UNIT_RK06 + UNIT_ATT, - "RK06", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), UNIT_RK07 + UNIT_ATT, - "RK07", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), UNIT_RK06, - "RK06", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), UNIT_RK07, - "RK07", NULL, NULL }, - { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL }, - { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL }, - { (UNIT_AUTO+UNIT_DTYPE), UNIT_RK06, - NULL, "RK06", &hk_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), UNIT_RK07, - NULL, "RK07", &hk_set_size }, - { MTAB_XTD|MTAB_VDV, 0040, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", - &set_vec, &show_vec, NULL }, - { 0 } - }; - -DEBTAB hk_deb[] = { - { "OPS", HKDEB_OPS }, - { "RRD", HKDEB_RRD }, - { "RWR", HKDEB_RWR }, - { NULL, 0 } - }; - -DEVICE hk_dev = { - "HK", hk_unit, hk_reg, hk_mod, - HK_NUMDR, DEV_RDX, 24, 1, DEV_RDX, 16, - NULL, NULL, &hk_reset, - &hk_boot, &hk_attach, &hk_detach, - &hk_dib, DEV_DISABLE | DEV_UBUS | DEV_Q18 | DEV_DEBUG, 0, - hk_deb, NULL, 0 - }; - -/* I/O dispatch routines, I/O addresses 17777440 - 17777476 */ - -t_stat hk_rd (int32 *data, int32 PA, int32 access) -{ -int32 drv, i, j; - -drv = GET_UNIT (hkcs2); /* get current unit */ -j = (PA >> 1) & 017; /* get reg offset */ -if (reg_in_drive[j] && (hk_unit[drv].flags & UNIT_DIS)) { /* nx disk */ - hk_err (CS1_ERR|CS1_DONE, CS2_NED, 0, drv); /* set err, stop op */ - *data = 0; - return SCPE_OK; - } - -update_hkcs (0, drv); /* update status */ -switch (j) { /* decode PA<4:1> */ - - case 000: /* HKCS1 */ - *data = (hkcs1 & ~CS1_DI) | (hkdi? CS1_DI: 0); /* DI dynamic */ - break; - - case 001: /* HKWC */ - *data = hkwc; - break; - - case 002: /* HKBA */ - *data = hkba = hkba & ~BA_MBZ; - break; - - case 003: /* HKDA */ - *data = hkda = hkda & ~DA_MBZ; - break; - - case 004: /* HKCS2 */ - *data = hkcs2 = (hkcs2 & ~CS2_MBZ) | CS2_IR; - break; - - case 005: /* HKDS */ - *data = hkds[drv]; - break; - - case 006: /* HKER */ - *data = hker[drv]; - break; - - case 007: /* HKAS */ - *data = hkof; - for (i = 0; i < HK_NUMDR; i++) { - if (hkds[i] & DS_ATA) - *data = *data | (AS_U0 << i); - } - break; - - case 010: /* HKDC */ - *data = hkdc = hkdc & ~DC_MBZ; - break; - - case 011: /* spare */ - *data = hkspr; - break; - - case 012: /* HKDB */ - *data = hkdb[0]; /* top of silo */ - hkdb[0] = hkdb[1]; /* ripple silo */ - hkdb[1] = hkdb[2]; - hkdb[2] = 0; /* just for READH */ - break; - - case 013: /* HKMR */ - *data = hkmr; - break; - - case 014: /* HKEC1 */ - case 015: /* HKEC2 */ - *data = 0; /* no ECC */ - break; - - case 016: /* HKMR2 */ - *data = hkmr2; - break; - - case 017: /* HKMR3 */ - *data = hkmr3; - break; - } - -if (DEBUG_PRI (hk_dev, HKDEB_RRD)) - fprintf (sim_deb, ">>HK%d read: %s=%o\n", drv, reg_name[j], *data); -return SCPE_OK; -} - -t_stat hk_wr (int32 data, int32 PA, int32 access) -{ -int32 drv, i, j; - -drv = GET_UNIT (hkcs2); /* get current unit */ -j = (PA >> 1) & 017; /* get reg offset */ -if (reg_in_drive[j] && (hk_unit[drv].flags & UNIT_DIS)) { /* nx disk */ - hk_err (CS1_ERR|CS1_DONE, CS2_NED, 0, drv); /* set err, stop op */ - return SCPE_OK; - } -if ((hkcs1 & CS1_GO) && /* busy? */ - !(((j == 0) && (data & CS1_CCLR)) || /* not cclr or sclr? */ - ((j == 4) && (data & CS2_CLR)))) { - hk_err (CS1_ERR|CS1_DONE, CS2_PGE, 0, drv); /* set err, stop op */ - return SCPE_OK; - } - -if (DEBUG_PRI (hk_dev, HKDEB_RWR)) - fprintf (sim_deb, ">>HK%d write: %s=%o\n", drv, reg_name[j], data); -switch (j) { /* decode PA<4:1> */ - - case 000: /* HKCS1 */ - if (data & CS1_CCLR) { /* controller reset? */ - hkcs1 = CS1_DONE; /* CS1 = done */ - hkcs2 = CS2_IR; /* CS2 = ready */ - hkmr = hkmr2 = hkmr3 = 0; /* maint = 0 */ - hkda = hkdc = 0; - hkba = hkwc = 0; - hkspr = hkof = 0; - hkci = hkdi = hkei = 0; /* clr int flops */ - for (i = 0; i < HK_NUMDR; i++) { /* stop data xfr */ - if (sim_is_active (&hk_unit[i]) && - ((hk_unit[i].FNC & CS1_M_FNC) >= FNC_XFER)) - sim_cancel (&hk_unit[i]); - } - drv = 0; - break; - } - if (((data & CS1_IE) != 0) && ((data & CS1_DONE) != 0)) - hkci = 1; /* set ctlr intr */ - hkcs1 = (hkcs1 & ~CS1_RW) | (data & CS1_RW); /* merge data */ - if (SC02C) - hkspr = (hkspr & ~CS1_M_UAE) | GET_UAE (hkcs1); - if (((data & CS1_GO) != 0) && ((hkcs1 & CS1_ERR) == 0)) - hk_go (drv); /* go & ~err? */ - break; - - case 001: /* HKWC */ - hkwc = data; - break; - - case 002: /* HKBA */ - hkba = data & ~BA_MBZ; - break; - - case 003: /* HKDA */ - hkda = data & ~DA_MBZ; - break; - - case 004: /* HKCS2 */ - if (data & CS2_CLR) /* init? */ - hk_reset (&hk_dev); - else hkcs2 = (hkcs2 & ~CS2_RW) | (data & CS2_RW) | CS2_IR; - drv = GET_UNIT (hkcs2); - break; - - case 007: /* HKAS */ - hkof = data & AS_OF; - break; - - case 010: /* HKDC */ - hkdc = data & ~DC_MBZ; - break; - - case 011: /* spare */ - hkspr = data; - if (SC02C) /* SC02C? upd UAE */ - hkcs1 = PUT_UAE (hkcs1, hkspr & 03); - break; - - case 012: /* HKDB */ - hkdb[0] = data; - break; - - case 013: /* HKMR */ - hkmr = data & MR_RW; - break; - - default: /* all others RO */ - break; - } /* end switch */ - -update_hkcs (0, drv); /* update status */ -return SCPE_OK; -} - -/* Initiate operation - go set, not previously set */ - -void hk_go (int32 drv) -{ -int32 fnc, t; -t_bool dte; -UNIT *uptr; - -static uint8 fnc_dte[16] = { - 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 - }; -static uint8 fnc_nxf[16] = { - 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0 - }; -static uint8 fnc_att[16] = { - 0, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 - }; -static uint8 fnc_rdy[16] = { - 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0 - }; -static uint8 fnc_cyl[16] = { - 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0 - }; - -fnc = GET_FNC (hkcs1); -if (DEBUG_PRI (hk_dev, HKDEB_OPS)) - fprintf (sim_deb, ">>HK%d strt: fnc=%o, cs1=%o, cs2=%o, ds=%o, er=%o, cyl=%o, da=%o, ba=%o, wc=%o\n", - drv, fnc, hkcs1, hkcs2, hkds[drv], hker[drv], hkdc, hkda, hkba, hkwc); -uptr = hk_dev.units + drv; /* get unit */ -dte = ((hkcs1 & CS1_DT) !=0) != ((uptr->flags & UNIT_DTYPE) != 0); - -if (fnc != FNC_NOP) /* !nop, clr msg sel */ - hkmr = hkmr & ~MR_MS; -if (uptr->flags & UNIT_DIS) { /* nx unit? */ - hk_err (CS1_ERR|CS1_DONE, CS2_NED, 0, drv); /* set err, no op */ - return; - } -if ((hkcs1 & CS1_FMT) != 0) { /* 18b format? */ - hk_err (CS1_ERR|CS1_DONE, 0, ER_FER, drv); /* set err, no op */ - return; - } -if (fnc_dte[fnc] && dte) { /* need drv match ? */ - hker[drv] = hker[drv] | ER_DTY; /* drive type mismatch? */ - hk_err (CS1_ERR|CS1_DONE, 0, ER_DTY, drv); /* set err, no op */ - } -if (fnc_nxf[fnc] && ((hkds[drv] & DS_VV) == 0)) { /* need vol valid? */ - hkds[drv] = hkds[drv] | DS_ATA; /* set ATTN */ - hk_err (CS1_ERR|CS1_DI|CS1_DONE, 0, ER_NXF, drv); /* set err, no op */ - return; - } -if (fnc_att[fnc] && !(uptr->flags & UNIT_ATT)) { /* need attached? */ - hkds[drv] = hkds[drv] | DS_ATA; /* set ATTN */ - hk_err (CS1_ERR|CS1_DI|CS1_DONE, 0, ER_UNS, drv); /* set err, no op */ - return; - } -if (fnc_rdy[fnc] && sim_is_active (uptr)) /* need inactive? */ - return; -if (fnc_cyl[fnc] && /* need valid cyl */ - ((GET_CY (hkdc) >= HK_CYL (uptr)) || /* bad cylinder */ - (GET_SF (hkda) >= HK_NUMSF))) { /* bad surface */ - hk_err (CS1_ERR|CS1_DONE, 0, ER_SKI|ER_IAE, drv); /* set err, no op */ - return; - } - -hkcs1 = (hkcs1 | CS1_GO) & ~CS1_DONE; /* set go, clear done */ -hkci = hkdi = hkei = 0; /* clear all intr */ -CLR_INT (HK); - -switch (fnc) { /* case on function */ - -/* Instantaneous functions (unit may be busy, can't schedule thread, - can't overwrite unit function field) */ - - case FNC_NOP: /* no operation */ - hkmr2 = hk_rdmr2 (GET_MS (hkmr)); /* get serial msgs */ - hkmr3 = hk_rdmr3 (GET_MS (hkmr)); - if (dte) /* drive type err? */ - hk_err (CS1_ERR|CS1_DONE, 0, ER_DTY, drv); - else update_hkcs (CS1_DONE, drv); /* done */ - break; - - case FNC_DCLR: /* drive clear */ - hkds[drv] &= ~DS_ATA; /* clr ATA */ - hker[drv] = 0; /* clr err */ - if (dte) /* drive type err? */ - hk_err (CS1_ERR|CS1_DONE, 0, ER_DTY, drv); - else update_hkcs (CS1_DONE, drv); /* done */ - break; - - case FNC_PACK: /* pack acknowledge */ - hkds[drv] = hkds[drv] | DS_VV; /* set volume valid */ - update_hkcs (CS1_DONE, drv); /* done */ - break; - -/* "Fast functions" finish in less than 15 usec */ - - case FNC_START: /* start spindle */ - case FNC_UNLOAD: /* unload */ - uptr->FNC = fnc; /* save function */ - sim_activate (uptr, hk_cwait); /* schedule */ - return; - -/* Positioning functions provide two interrupts - an immediate interrupt - on ctrl done and a second one (if ctrl ready) when the seek is complete */ - - case FNC_OFFSET: /* offset mode */ - case FNC_RECAL: /* recalibrate */ - case FNC_SEEK: /* seek */ - hkds[drv] = hkds[drv] | DS_PIP; /* set positioning */ - uptr->FNC = fnc; /* save function */ - sim_activate (uptr, hk_cwait); /* schedule */ - return; - -/* Data transfer functions lock the controller for the duration */ - - case FNC_WRITEH: /* write headers */ - case FNC_WRITE: /* write */ - hk_off[drv] = 0; /* clr offset */ - case FNC_WCHK: /* write check */ - case FNC_READ: /* read */ - case FNC_READH: /* read headers */ - if (GET_SC (hkda) >= HK_NUMSC) { /* invalid sector? */ - hk_err (CS1_ERR|CS1_DONE, 0, ER_OPI, drv); /* set err, no op */ - return; - } - hk_dif[drv] = hkdc - uptr->CYL; /* cyl diff */ - t = abs (hk_dif[drv]); /* |cyl diff| */ - uptr->FNC = fnc; /* save function */ - sim_activate (uptr, hk_rwait + (hk_swait * t)); /* schedule */ - uptr->CYL = hkdc; /* update cyl */ - return; - - default: - hk_err (CS1_ERR|CS1_DONE, 0, ER_ILF, drv); /* not supported */ - break; - } -return; -} - -/* Service unit timeout - - Complete movement or data transfer command - Unit must exist - can't remove an active unit - Unit must be attached - detach cancels in progress operations -*/ - -t_stat hk_svc (UNIT *uptr) -{ -int32 i, t, dc, fnc, err; -int32 wc, awc, da; -uint32 drv, ba; -uint16 comp; - -drv = (uint32) (uptr - hk_dev.units); /* get drv number */ -fnc = uptr->FNC & CS1_M_FNC; /* get function */ -switch (fnc) { /* case on function */ - -/* Fast commands - start spindle only provides one interrupt - because ATTACH implicitly spins up the drive */ - - case FNC_UNLOAD: /* unload */ - hk_detach (uptr); /* detach unit */ - case FNC_START: /* start spindle */ - update_hkcs (CS1_DONE, drv); /* done */ - break; - -/* Positioning commands provide two interrupts, an immediate controller done - and a delayed drive interrupt */ - - case FNC_OFFSET: /* offset */ - if (uptr->FNC & FNC_2ND) { /* 2nd int? */ - hkds[drv] = (hkds[drv] & ~DS_PIP) | DS_ATA; /* upd sta */ - update_hkcs (CS1_DI, drv); /* ATN set */ - } - else { - uptr->FNC = uptr->FNC | FNC_2ND; /* second state */ - hk_off[drv] = hkof & AS_OF; /* save offset */ - sim_activate (uptr, hk_min2wait); /* wait for compl */ - update_hkcs (CS1_DONE, drv); /* done */ - } - break; - - case FNC_RECAL: /* recalibrate */ - case FNC_SEEK: /* seek */ - if (uptr->FNC & FNC_2ND) { /* 2nd int? */ - hkds[drv] = (hkds[drv] & ~DS_PIP) | DS_ATA; /* upd sta */ - update_hkcs (CS1_DI, drv); /* ATN set */ - } - else { - uptr->FNC = uptr->FNC | FNC_2ND; /* second state */ - hk_off[drv] = 0; /* clr offset */ - dc = (fnc == FNC_SEEK)? hkdc: 0; /* get cyl */ - hk_dif[drv] = dc - uptr->CYL; /* cyl diff */ - t = abs (hk_dif[drv]) * hk_swait; /* |cyl diff| */ - if (t < hk_min2wait) /* min time */ - t = hk_min2wait; - uptr->CYL = dc; /* save cyl */ - sim_activate (uptr, t); /* schedule */ - update_hkcs (CS1_DONE, drv); /* done */ - } - break; - -/* Data transfer commands only generate one interrupt */ - - case FNC_READH: - hkdb[0] = uptr->CYL << RDH1_V_CYL; /* first word */ - hkdb[1] = (GET_SC (hkda) << RDH2_V_SEC) | /* second word */ - (1 << (GET_SF (hkda) + RDH2_V_DHA)) | RDH2_GOOD; - hkdb[2] = hkdb[0] ^ hkdb[1]; /* checksum */ - update_hkcs (CS1_DONE, drv); /* done */ - break; - - case FNC_WRITE: /* write */ - if (uptr->flags & UNIT_WPRT) { /* write locked? */ - hk_err (CS1_ERR|CS1_DONE, 0, ER_WLE, drv); /* set err, stop op */ - return SCPE_OK; - } - case FNC_WCHK: /* write check */ - case FNC_READ: /* read */ - if (SC02C) /* 22b addr? */ - ba = ((hkspr & XM_MMASK) << 16) | hkba; - else ba = (GET_UAE (hkcs1) << 16) | hkba; /* no, 18b addr */ - da = GET_DA (hkdc, hkda) * HK_NUMWD; /* get disk addr */ - wc = 0200000 - hkwc; /* get true wc */ - - if ((da + wc) > HK_SIZE (uptr)) { /* disk overrun? */ - hker[drv] = hker[drv] | ER_AOE; /* set err */ - hkds[drv] = hkds[drv] | DS_ATA; /* set attn */ - wc = HK_SIZE (uptr) - da; /* trim xfer */ - if (da >= HK_SIZE (uptr)) { /* none left? */ - update_hkcs (CS1_DONE, drv); /* then done */ - break; - } - } - - err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET); - if (uptr->FNC == FNC_WRITE) { /* write? */ - if (hkcs2 & CS2_UAI) { /* no addr inc? */ - if (t = Map_ReadW (ba, 2, &comp)) { /* get 1st wd */ - wc = 0; /* NXM, no xfr */ - hk_err (CS1_ERR, CS2_NEM, 0, drv); - } - for (i = 0; i < wc; i++) - hkxb[i] = comp; - } - else { /* normal */ - if (t = Map_ReadW (ba, wc << 1, hkxb)) { /* get buf */ - wc = wc - (t >> 1); /* NXM, adj wc */ - hk_err (CS1_ERR, CS2_NEM, 0, drv); - } - ba = ba + (wc << 1); /* adv ba */ - } - awc = (wc + (HK_NUMWD - 1)) & ~(HK_NUMWD - 1); - for (i = wc; i < awc; i++) /* fill buf */ - hkxb[i] = 0; - if (wc && !err) { /* write buf */ - fxwrite (hkxb, sizeof (uint16), awc, uptr->fileref); - err = ferror (uptr->fileref); - } - } /* end if wr */ - else if (uptr->FNC == FNC_READ) { /* read? */ - i = fxread (hkxb, sizeof (uint16), wc, uptr->fileref); - err = ferror (uptr->fileref); - for ( ; i < wc; i++) /* fill buf */ - hkxb[i] = 0; - if (hkcs2 & CS2_UAI) { /* no addr inc? */ - if (t = Map_WriteW (ba, 2, &hkxb[wc - 1])) { - wc = 0; /* NXM, no xfr */ - hk_err (CS1_ERR, CS2_NEM, 0, drv); - } - } - else { /* normal */ - if (t = Map_WriteW (ba, wc << 1, hkxb)) { /* put buf */ - wc = wc - (t >> 1); /* NXM, adj wc */ - hk_err (CS1_ERR, CS2_NEM, 0, drv); - } - ba = ba + (wc << 1); /* adv ba */ - } - } /* end if read */ - else { /* wchk */ - i = fxread (hkxb, sizeof (uint16), wc, uptr->fileref); - err = ferror (uptr->fileref); - for ( ; i < wc; i++) /* fill buf */ - hkxb[i] = 0; - awc = wc; - for (wc = 0; wc < awc; wc++) { /* loop thru buf */ - if (Map_ReadW (ba, 2, &comp)) { /* read word */ - hk_err (CS1_ERR, CS2_NEM, 0, drv); - break; - } - if (comp != hkxb[wc]) { /* compare wd */ - hk_err (CS1_ERR, CS2_WCE, 0, drv); - break; - } - if ((hkcs2 & CS2_UAI) == 0) - ba = ba + 2; - } - } /* end else wchk */ - - hkwc = (hkwc + wc) & 0177777; /* final word count */ - hkba = (ba & 0177777) & ~BA_MBZ; /* lower 16b */ - hkcs1 = PUT_UAE (hkcs1, ba >> 16); /* upper 2b */ - if (SC02C) /* SC02C? upper 6b */ - hkspr = (hkspr & ~XM_MMASK) | ((ba >> 16) & XM_MMASK); - da = da + wc + (HK_NUMWD - 1); - da = da / HK_NUMWD; - hkda = da % HK_NUMSC; - da = da / HK_NUMSC; - hkda = hkda | ((da % HK_NUMSF) << DA_V_SF); - hkdc = da / HK_NUMSF; - - if (err != 0) { /* error? */ - hk_err (CS1_ERR|CS1_DONE, 0, ER_PAR, drv); /* set drive error */ - perror ("HK I/O error"); - clearerr (uptr->fileref); - return SCPE_IOERR; - } - - case FNC_WRITEH: /* write headers stub */ - update_hkcs (CS1_DONE, drv); /* set done */ - break; - } /* end case func */ - -return SCPE_OK; -} - -/* Controller status update - - Update drive status - Update HKCS1 - Check for done transition - clock CI from IE - set DI if any ATN bits set - Check for DI set if no transition but DONE is set - Update interrupt request -*/ - -void update_hkcs (int32 flag, int32 drv) -{ -int32 i; -int32 old_hkcs1 = hkcs1; - -update_hkds (drv); /* upd drv status */ -hkcs1 = (hkcs1 & (CS1_ERR|CS1_DT|CS1_UAE|CS1_DONE|CS1_IE|CS1_SPA|CS1_FNC|CS1_GO)) | - (flag & ~CS1_DI); -if ((hkcs1 & CS1_DONE) != 0) { /* done? */ - hkcs1 = hkcs1 & ~CS1_GO; /* clear go */ - if ((old_hkcs1 & CS1_DONE) == 0) { /* done 0->1? */ - hkci = (hkcs1 & CS1_IE)? 1: 0; /* clk CI from IE */ - for (i = 0; i < HK_NUMDR; i++) { /* if ATA, set DI */ - if (hkds[i] & DS_ATA) - hkdi = 1; - } - } - else if ((flag & CS1_DI) != 0) /* done set; new ATN? */ - hkdi = 1; /* set drv int */ - } -else hkdi = 0; /* not done, clr DI */ -if (((hkcs1 & CS1_IE) != 0) && (hkci || hkdi || hkei)) /* int enab & set? */ - SET_INT (HK); -else CLR_INT (HK); -if (DEBUG_PRI (hk_dev, HKDEB_OPS)) { /* debug info? */ - if (flag & CS1_DONE) /* set done? */ - fprintf (sim_deb, - ">>HK%d done: fnc=%o, cs1=%o, cs2=%o, ds=%o, er=%o, cyl=%o, da=%o, ba=%o, wc=%o, ci=%d, di=%d\n", - drv, GET_FNC (hkcs1), hkcs1, hkcs2, hkds[drv], hker[drv], hkdc, hkda, hkba, hkwc, hkci, hkdi); - if (flag & CS1_DI) /* set ATA? */ - fprintf (sim_deb, - ">>HK%d ATA: fnc=%o, cs1=%o, cs2=%o, ds=%o, er=%o, cyl=%o, da=%o, ba=%o, wc=%o, ci=%d, di=%d\n", - drv, GET_FNC (hkcs1), hkcs1, hkcs2, hkds[drv], hker[drv], hkdc, hkda, hkba, hkwc, hkci, hkdi); - } -return; -} - -/* Drive status update */ - -void update_hkds (int32 drv) -{ -if (hk_unit[drv].flags & UNIT_DIS) { /* disabled? */ - hkds[drv] = hker[drv] = 0; /* all clear */ - return; - } -hkds[drv] = (hkds[drv] & (DS_VV | DS_PIP | DS_ATA)) | DS_VLD | DS_DRA; -if (hk_unit[drv].flags & UNIT_RK07) - hkds[drv] = hkds[drv] | DS_DT; -if (hk_unit[drv].flags & UNIT_ATT) { /* attached? */ - if (!sim_is_active (&hk_unit[drv])) /* not busy? */ - hkds[drv] = hkds[drv] | DS_RDY; /* set RDY */ - if (hk_off[drv]) /* offset? set OF */ - hkds[drv] = hkds[drv] | DS_OF; - if (hk_unit[drv].flags & UNIT_WPRT) /* write locked? */ - hkds[drv] = hkds[drv] | DS_WRL; /* set WRL */ - } -else hkds[drv] = hkds[drv] & ~(DS_PIP | DS_VV); /* no, clr PIP,VV */ -return; -} - -/* Set errors */ - -void hk_err (int32 cs1e, int32 cs2e, int32 drve, int32 drv) -{ -hker[drv] = hker[drv] | drve; /* set drv error */ -hkcs2 = hkcs2 | cs2e; /* set cs2 err */ -if ((cs1e & CS1_ERR) != 0) /* set combined err? */ - hkei = 1; /* then set EI */ -if ((cs1e & CS1_DONE) != 0) /* set done? */ - update_hkcs (CS1_ERR|CS1_DONE, drv); /* stop now */ -else hkcs1 = hkcs1 | cs1e; /* no, just upd */ -return; -} - -/* Interrupt routine */ - -int32 hk_inta (void) -{ -hkci = hkdi = hkei = 0; /* clear all flops */ -return hk_dib.vec; /* return vector */ -} - -/* Diagnostic registers - - It's unclear whether the drivers actually use these values, but the - Emulex controller bothers to implement them, so we will too */ - -int32 hk_mrpar (int32 v) -{ -int32 bit, wrk; - -wrk = v & 077777; /* par on 15b */ -v = wrk | ((hkmr & MR_PAR)? 0: AX_PAR); /* even/odd */ -while (wrk) { /* while 1's */ - bit = wrk & (-wrk); /* lowest 1 */ - wrk = wrk & ~bit; /* clear */ - v = v ^ AX_PAR; /* xor parity */ - } -return v; -} - -int32 hk_rdmr2 (int32 msg) -{ -int32 drv = GET_UNIT (hkcs2); -int32 v = drv << AX_V_UNIT; -UNIT *uptr = hk_dev.units + drv; -int32 fnc = uptr->FNC & CS1_M_FNC; - -switch (msg) { - - case 0: /* message A0 */ - v = v | ((hkds[drv] & DS_ATA)? A0_ATA: 0) | - ((hkds[drv] & DS_PIP)? A0_PIP: 0) | - ((uptr->flags & UNIT_WPRT)? A0_WRL: 0) | - ((hk_off[drv])? A0_OF: 0) | - ((uptr->flags & UNIT_RK07)? A0_DT: 0) | - ((hkds[drv] & DS_VV)? A0_VV: 0) | A0_DRA; - if (uptr->flags & UNIT_ATT) - v = v | A0_SPO | (!sim_is_active (uptr)? A0_RDY: 0); - break; - - case 1: /* message A1 */ - if (uptr->flags & UNIT_ATT) { - if (sim_is_active (uptr)) { - if (fnc == FNC_UNLOAD) - v = v | A1_UNL; - else if (fnc == FNC_RECAL) - v = v | A1_RTZ; - else if (fnc == FNC_SEEK) { - if (hk_dif[drv] < 0) - v = v | A1_REV; - if (hk_dif[drv] > 0) - v = v | A1_FWD; - } - } - v = v | (A1_SPD|A1_CAR|A1_DOR|A1_HHM|A1_SRV); - } - else v = v | A1_HHM; - break; - - case 2: /* message A2 */ - if (hkds[drv] & DS_OF) - v = v | ((hk_off[drv] & A2_M_DIF) << A2_V_DIF); - else v = v | ((hk_dif[drv] & A2_M_DIF) << A2_V_DIF); - break; - - case 3: /* message A3 */ - v = v | ((012340 + v) << A3_V_SNO); - break; - } - -return hk_mrpar (v); -} - -int32 hk_rdmr3 (int32 msg) -{ -int32 drv = GET_UNIT (hkcs2); -int32 v = msg & 03; - -switch (msg) { - - case 0: /* message B0 */ - v = v | ((hker[drv] & ER_WLE)? (B0_WLE | B0_FLT): 0) | - ((hker[drv] & ER_SKI)? (B0_SKI | B0_FLT): 0) | - ((hker[drv] & ER_NXF)? (B0_NXF | B0_FLT): 0) | - ((hker[drv] & ER_IAE)? (B0_IAE | B0_FLT): 0); - break; - - case 1: /* message B1 */ - v = v | ((hker[drv] & ER_SKI)? B1_SKI: 0) | - ((hker[drv] & ER_UNS)? B1_SVE: 0); - break; - - case 2: /* message B2 */ - v = v | (hk_unit[drv].CYL << B2_V_CYL); - break; - - case 3: /* message B3 */ - v = v | (GET_SC (hkda) << B3_V_SEC) | - (1 << (GET_SF (hkda) + B3_V_DHA)); - break; - } - -return hk_mrpar (v); -} - -/* Device reset */ - -t_stat hk_reset (DEVICE *dptr) -{ -int32 i; -UNIT *uptr; - -hkcs1 = CS1_DONE; /* set done */ -hkcs2 = CS2_IR; /* clear state */ -hkmr = hkmr2 = hkmr3 = 0; -hkda = hkdc = 0; -hkba = hkwc = 0; -hkof = hkspr = 0; -hkci = hkdi = hkei = 0; /* clear intr flops */ -CLR_INT (HK); /* clear intr req */ -for (i = 0; i < HK_NUMDR; i++) { /* stop operations */ - uptr = hk_dev.units + i; - sim_cancel (uptr); - if (uptr->flags & UNIT_ATT) - hkds[i] = hkds[i] & (DS_VV | DS_DT); - else hkds[i] = 0; - uptr->CYL = uptr->FNC = 0; /* clear state */ - hk_dif[i] = 0; - hk_off[i] = 0; - hker[i] = 0; - } /* clear errors */ -if (hkxb == NULL) - hkxb = (uint16 *) calloc (HK_MAXFR, sizeof (uint16)); -if (hkxb == NULL) - return SCPE_MEM; -return SCPE_OK; -} - -/* Device attach */ - -t_stat hk_attach (UNIT *uptr, char *cptr) -{ -uint32 drv, p; -t_stat r; -int32 old_hkds; - -uptr->capac = HK_SIZE (uptr); -r = attach_unit (uptr, cptr); /* attach unit */ -if (r != SCPE_OK) /* error? */ - return r; -drv = (uint32) (uptr - hk_dev.units); /* get drv number */ -old_hkds = hkds[drv]; /* save hkds */ -hkds[drv] = DS_ATA | DS_RDY | - ((uptr->flags & UNIT_WPRT)? DS_WRL: 0) | - ((uptr->flags & UNIT_DTYPE)? DS_DT: 0); -hker[drv] = 0; /* upd drv status */ -hk_off[drv] = 0; -hk_dif[drv] = 0; -uptr->CYL = 0; -if ((old_hkds & DS_ATA) == 0) /* ATN transition? */ - update_hkcs (CS1_DI, drv); /* upd ctlr status */ - -p = sim_fsize (uptr->fileref); /* get file size */ -if (p == 0) { /* new disk image? */ - if (uptr->flags & UNIT_RO) - return SCPE_OK; - return pdp11_bad_block (uptr, HK_NUMSC, HK_NUMWD); - } -if ((uptr->flags & UNIT_AUTO) == 0) /* autosize? */ - return SCPE_OK; -if (p > (RK06_SIZE * sizeof (uint16))) { - uptr->flags = uptr->flags | UNIT_RK07; - uptr->capac = RK07_SIZE; - } -else { - uptr->flags = uptr->flags & ~UNIT_RK07; - uptr->capac = RK06_SIZE; - } -return SCPE_OK; -} - -/* Device detach */ - -t_stat hk_detach (UNIT *uptr) -{ -uint32 drv; -int32 old_hkds; - -if (!(uptr->flags & UNIT_ATT)) /* attached? */ - return SCPE_OK; -drv = (uint32) (uptr - hk_dev.units); /* get drv number */ -old_hkds = hkds[drv]; -hkds[drv] = (hkds[drv] & ~(DS_RDY | DS_WRL | DS_VV | DS_OF | DS_PIP)) | DS_ATA; -if (sim_is_active (uptr)) { /* unit active? */ - sim_cancel (uptr); /* cancel operation */ - hker[drv] = hker[drv] | ER_OPI; /* set drive error */ - if ((uptr->FNC & FNC_2ND) == 0) /* expecting done? */ - update_hkcs (CS1_ERR|CS1_DONE, drv); /* set done */ - } -if ((old_hkds & DS_ATA) == 0) /* ATN transition? */ - update_hkcs (CS1_DI, drv); /* upd ctlr status */ -return detach_unit (uptr); -} - -/* Set size command validation routine */ - -t_stat hk_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (uptr->flags & UNIT_ATT) - return SCPE_ALATT; -uptr->capac = val? RK07_SIZE: RK06_SIZE; -return SCPE_OK; -} - -/* Set bad block routine */ - -t_stat hk_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -return pdp11_bad_block (uptr, HK_NUMSC, HK_NUMWD); -} - -#if defined (VM_PDP11) - -/* Device bootstrap - does not clear CSR when done */ - -#define BOOT_START 02000 /* start */ -#define BOOT_ENTRY (BOOT_START + 002) /* entry */ -#define BOOT_UNIT (BOOT_START + 010) /* unit number */ -#define BOOT_CSR (BOOT_START + 014) /* CSR */ -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) - -static const uint16 boot_rom[] = { - 0042115, /* "MD" */ - 0012706, BOOT_START, /* mov #boot_start, sp */ - 0012700, 0000000, /* mov #unit, r0 */ - 0012701, 0177440, /* mov #HKCS1, r1 */ - 0012761, 0000040, 0000010, /* mov #CS2_CLR, 10(r1) ; reset */ - 0010061, 0000010, /* mov r0, 10(r1) ; set unit */ - 0016102, 0000012, /* mov 12(r1), r2 ; drv typ */ - 0100375, /* bpl .-4 ; valid? */ - 0042702, 0177377, /* bic #177377, r2 ; clr rest */ - 0006302, /* asl r2 ; move */ - 0006302, /* asl r2 */ - 0012703, 0000003, /* mov #pack+go, r3 */ - 0050203, /* bis r2, r3 ; merge type */ - 0010311, /* mov r3, (r1); ; pack ack */ - 0105711, /* tstb (r1) ; wait */ - 0100376, /* bpl .-2 */ - 0012761, 0177000, 0000002, /* mov #-512.,2(r1) ; set wc */ - 0005061, 0000004, /* clr 4(r1) ; clr ba */ - 0005061, 0000006, /* clr 6(r1) ; clr da */ - 0005061, 0000020, /* clr 20(r1) ; clr cyl */ - 0012703, 0000021, /* mov #read+go, r3 */ - 0050203, /* bis r2, r3 ; merge type */ - 0010311, /* mov r3, (r1); ; read */ - 0105711, /* tstb (r1) ; wait */ - 0100376, /* bpl .-2 */ - 0005002, /* clr R2 */ - 0005003, /* clr R3 */ - 0012704, BOOT_START+020, /* mov #start+020, r4 */ - 0005005, /* clr R5 */ - 0005007 /* clr PC */ - }; - -t_stat hk_boot (int32 unitno, DEVICE *dptr) -{ -size_t i; - -for (i = 0; i < BOOT_LEN; i++) - M[(BOOT_START >> 1) + i] = boot_rom[i]; -M[BOOT_UNIT >> 1] = unitno & CS2_M_UNIT; -M[BOOT_CSR >> 1] = hk_dib.ba & DMASK; -cpu_set_boot (BOOT_ENTRY); -return SCPE_OK; -} - -#else - -t_stat hk_boot (int32 unitno, DEVICE *dptr) -{ -return SCPE_NOFNC; -} - -#endif diff --git a/PDP11/pdp11_io.c b/PDP11/pdp11_io.c deleted file mode 100644 index 06f99974..00000000 --- a/PDP11/pdp11_io.c +++ /dev/null @@ -1,383 +0,0 @@ -/* pdp11_io.c: PDP-11 I/O simulator - - Copyright (c) 1993-2012, 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. - - 27-Mar-12 RMS Fixed order of int_internal (Jordi Guillaumes i Pons) - 19-Mar-12 RMS Fixed declaration of cpu_opt (Mark Pizzolato) - 12-Dec-11 RMS Fixed Qbus interrupts to treat all IO devices as BR4 - 19-Nov-08 RMS Moved I/O support routines to I/O library - 16-May-08 RMS Added multiple DC11 support - Renamed DL11 in autoconfigure - 02-Feb-08 RMS Fixed DMA memory address limit test (John Dundas) - 06-Jul-06 RMS Added multiple KL11/DL11 support - 15-Oct-05 RMS Fixed bug in autoconfiguration (missing XU) - 25-Jul-05 RMS Revised autoconfiguration algorithm and interface - 30-Sep-04 RMS Revised Unibus interface - 28-May-04 RMS Revised I/O dispatching (John Dundas) - 25-Jan-04 RMS Removed local debug logging support - 21-Dec-03 RMS Fixed bug in autoconfigure vector assignment; added controls - 21-Nov-03 RMS Added check for interrupt slot conflict (Dave Hittner) - 12-Mar-03 RMS Added logical name support - 08-Oct-02 RMS Trimmed I/O bus addresses - Added support for dynamic tables - Added show I/O space, autoconfigure routines - 12-Sep-02 RMS Added support for TMSCP, KW11P, RX211 - 26-Jan-02 RMS Revised for multiple DZ's - 06-Jan-02 RMS Revised I/O access, enable/disable support - 11-Dec-01 RMS Moved interrupt debug code - 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 uint32 cpu_opt; -extern int32 cpu_bme; -extern int32 trap_req, ipl; -extern int32 cpu_log; -extern int32 autcon_enb; -extern int32 uba_last; -extern DEVICE cpu_dev; -extern UNIT cpu_unit; - -int32 calc_ints (int32 nipl, int32 trq); - -extern t_stat cpu_build_dib (void); -extern void init_mbus_tab (void); -extern t_stat build_mbus_tab (DEVICE *dptr, DIB *dibp); - -/* I/O data structures */ - -t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md); -t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md); - -int32 int_vec[IPL_HLVL][32]; /* int req to vector */ -int32 (*int_ack[IPL_HLVL][32])(void); /* int ack routines */ - -static const int32 pirq_bit[7] = { - INT_V_PIR1, INT_V_PIR2, INT_V_PIR3, INT_V_PIR4, - INT_V_PIR5, INT_V_PIR6, INT_V_PIR7 - }; - -static const int32 int_internal[IPL_HLVL] = { - 0, INT_INTERNAL1, INT_INTERNAL2, INT_INTERNAL3, - INT_INTERNAL4, INT_INTERNAL5, INT_INTERNAL6, INT_INTERNAL7 - }; - -/* 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, uint32 pa, int32 access) -{ -int32 idx; -t_stat stat; - -idx = (pa & IOPAGEMASK) >> 1; -if (iodispR[idx]) { - stat = iodispR[idx] (data, pa, access); - trap_req = calc_ints (ipl, trap_req); - return stat; - } -return SCPE_NXM; -} - -t_stat iopageW (int32 data, uint32 pa, int32 access) -{ -int32 idx; -t_stat stat; - -idx = (pa & IOPAGEMASK) >> 1; -if (iodispW[idx]) { - stat = iodispW[idx] (data, pa, access); - trap_req = calc_ints (ipl, trap_req); - return stat; - } -return SCPE_NXM; -} - -/* Calculate interrupt outstanding - In a Qbus system, all device interrupts are treated as BR4 */ - -int32 calc_ints (int32 nipl, int32 trq) -{ -int32 i, t; -t_bool all_int = (UNIBUS || (nipl < IPL_HMIN)); - -for (i = IPL_HLVL - 1; i > nipl; i--) { - t = all_int? int_req[i]: (int_req[i] & int_internal[i]); - if (t) - return (trq | TRAP_INT); - } -return (trq & ~TRAP_INT); -} - -/* Find vector for highest priority interrupt - In a Qbus system, all device interrupts are treated as BR4 */ - -int32 get_vector (int32 nipl) -{ -int32 i, j, t, vec; -t_bool all_int = (UNIBUS || (nipl < IPL_HMIN)); - -for (i = IPL_HLVL - 1; i > nipl; i--) { /* loop thru lvls */ - t = all_int? int_req[i]: (int_req[i] & int_internal[i]); - 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]; - 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. - These routines are only reachable if a Unibus map is configured. -*/ - -t_stat ubm_rd (int32 *data, int32 addr, int32 access) -{ -int32 pg = (addr >> 2) & UBM_M_PN; - -*data = (addr & 2)? ((ub_map[pg] >> 16) & 077): - (ub_map[pg] & 0177776); -return SCPE_OK; -} - -t_stat ubm_wr (int32 data, int32 addr, int32 access) -{ -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; -} - -/* Mapped memory access routines for DMA devices */ - -#define BUSMASK ((UNIBUS)? UNIMASK: PAMASK) - -/* Map I/O address to memory address - caller checks cpu_bme */ - -uint32 Map_Addr (uint32 ba) -{ -int32 pg = UBM_GETPN (ba); /* map entry */ -int32 off = UBM_GETOFF (ba); /* offset */ - -if (pg != UBM_M_PN) /* last page? */ - uba_last = (ub_map[pg] + off) & PAMASK; /* no, use map */ -else uba_last = (IOPAGEBASE + off) & PAMASK; /* yes, use fixed */ -return uba_last; -} - -/* 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 - - These routines are used only for Unibus and Qbus devices. - Massbus devices have their own IO routines. As a result, - the historic 'map' parameter is no longer needed. - - - In a U18 configuration, the map is always disabled. - Device addresses are trimmed to 18b. - - In a U22 configuration, the map is always configured - (although it may be disabled). Device addresses are - trimmed to 18b. - - In a Qbus configuration, the map is always disabled. - Device addresses are trimmed to 22b. -*/ - -int32 Map_ReadB (uint32 ba, int32 bc, uint8 *buf) -{ -uint32 alim, lim, ma; - -ba = ba & BUSMASK; /* trim address */ -lim = ba + bc; -if (cpu_bme) { /* map enabled? */ - for ( ; ba < lim; ba++) { /* by bytes */ - ma = Map_Addr (ba); /* map addr */ - if (!ADDR_IS_MEM (ma)) /* NXM? err */ - return (lim - ba); - *buf++ = (uint8) RdMemB (ma); /* get byte */ - } - return 0; - } -else { /* physical */ - if (ADDR_IS_MEM (lim)) /* end ok? */ - alim = lim; - else if (ADDR_IS_MEM (ba)) /* no, strt ok? */ - alim = MEMSIZE; - else return bc; /* no, err */ - for ( ; ba < alim; ba++) { /* by bytes */ - *buf++ = (uint8) RdMemB (ba); /* get byte */ - } - return (lim - alim); - } -} - -int32 Map_ReadW (uint32 ba, int32 bc, uint16 *buf) -{ -uint32 alim, lim, ma; - -ba = (ba & BUSMASK) & ~01; /* trim, align addr */ -lim = ba + (bc & ~01); -if (cpu_bme) { /* map enabled? */ - for (; ba < lim; ba = ba + 2) { /* by words */ - ma = Map_Addr (ba); /* map addr */ - if (!ADDR_IS_MEM (ma)) /* NXM? err */ - return (lim - ba); - *buf++ = (uint16) RdMemW (ma); - } - return 0; - } -else { /* physical */ - if (ADDR_IS_MEM (lim)) /* end ok? */ - alim = lim; - else if (ADDR_IS_MEM (ba)) /* no, strt ok? */ - alim = MEMSIZE; - else return bc; /* no, err */ - for ( ; ba < alim; ba = ba + 2) { /* by words */ - *buf++ = (uint16) RdMemW (ba); - } - return (lim - alim); - } -} - -int32 Map_WriteB (uint32 ba, int32 bc, uint8 *buf) -{ -uint32 alim, lim, ma; - -ba = ba & BUSMASK; /* trim address */ -lim = ba + bc; -if (cpu_bme) { /* map enabled? */ - for ( ; ba < lim; ba++) { /* by bytes */ - ma = Map_Addr (ba); /* map addr */ - if (!ADDR_IS_MEM (ma)) /* NXM? err */ - return (lim - ba); - WrMemB (ma, ((uint16) *buf++)); - } - return 0; - } -else { /* physical */ - if (ADDR_IS_MEM (lim)) /* end ok? */ - alim = lim; - else if (ADDR_IS_MEM (ba)) /* no, strt ok? */ - alim = MEMSIZE; - else return bc; /* no, err */ - for ( ; ba < alim; ba++) { /* by bytes */ - WrMemB (ba, ((uint16) *buf++)); - } - return (lim - alim); - } -} - -int32 Map_WriteW (uint32 ba, int32 bc, uint16 *buf) -{ -uint32 alim, lim, ma; - -ba = (ba & BUSMASK) & ~01; /* trim, align addr */ -lim = ba + (bc & ~01); -if (cpu_bme) { /* map enabled? */ - for (; ba < lim; ba = ba + 2) { /* by words */ - ma = Map_Addr (ba); /* map addr */ - if (!ADDR_IS_MEM (ma)) /* NXM? err */ - return (lim - ba); - WrMemW (ma, *buf++); - } - return 0; - } -else { /* physical */ - if (ADDR_IS_MEM (lim)) /* end ok? */ - alim = lim; - else if (ADDR_IS_MEM (ba)) /* no, strt ok? */ - alim = MEMSIZE; - else return bc; /* no, err */ - for ( ; ba < alim; ba = ba + 2) { /* by words */ - WrMemW (ba, *buf++); - } - return (lim - alim); - } -} - -/* Build tables from device list */ - -t_stat build_dib_tab (void) -{ -int32 i; -DEVICE *dptr; -DIB *dibp; -t_stat r; - -init_ubus_tab (); /* init Unibus tables */ -init_mbus_tab (); /* init Massbus tables */ -for (i = 0; i < 7; i++) /* seed PIRQ intr */ - int_vec[i + 1][pirq_bit[i]] = VEC_PIRQ; -if ((r = cpu_build_dib ())) /* build CPU entries */ - return r; -for (i = 0; (dptr = sim_devices[i]) != NULL; i++) { /* loop thru dev */ - dibp = (DIB *) dptr->ctxt; /* get DIB */ - if (dibp && !(dptr->flags & DEV_DIS)) { /* defined, enabled? */ - if (dptr->flags & DEV_MBUS) { /* Massbus? */ - if ((r = build_mbus_tab (dptr, dibp))) /* add to Mbus tab */ - return r; - } - else { /* no, Unibus */ - if ((r = build_ubus_tab (dptr, dibp))) /* add to Unibus tab */ - return r; - } - } /* end if enabled */ - } /* end for */ -return SCPE_OK; -} diff --git a/PDP11/pdp11_io_lib.c b/PDP11/pdp11_io_lib.c deleted file mode 100644 index 359d6433..00000000 --- a/PDP11/pdp11_io_lib.c +++ /dev/null @@ -1,549 +0,0 @@ -/* pdp11_io_lib.c: Unibus/Qbus common support routines - - Copyright (c) 1993-2017, 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. -*/ - -#if defined (VM_PDP10) /* PDP10 version */ -#include "pdp10_defs.h" - -#elif defined (VM_VAX) /* VAX version */ -#include "vax_defs.h" - -#else /* PDP-11 version */ -#include "pdp11_defs.h" -#endif -#include "sim_sock.h" -#include "sim_tmxr.h" - -extern int32 autcon_enb; -extern int32 int_vec[IPL_HLVL][32]; -extern int32 (*int_ack[IPL_HLVL][32])(void); -extern t_stat (*iodispR[IOPAGESIZE >> 1])(int32 *dat, int32 ad, int32 md); -extern t_stat (*iodispW[IOPAGESIZE >> 1])(int32 dat, int32 ad, int32 md); - -extern t_stat build_dib_tab (void); - -static DIB *iodibp[IOPAGESIZE >> 1]; - -/* Enable/disable autoconfiguration */ - -t_stat set_autocon (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (cptr != NULL) - return SCPE_ARG; -autcon_enb = val; -return auto_config (NULL, 0); -} - -/* Show autoconfiguration status */ - -t_stat show_autocon (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -fprintf (st, "autoconfiguration "); -fprintf (st, autcon_enb? "enabled": "disabled"); -return SCPE_OK; -} - -/* Change device address */ - -t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -DEVICE *dptr; -DIB *dibp; -uint32 newba; -t_stat r; - -if (cptr == NULL) - return SCPE_ARG; -if ((val == 0) || (uptr == NULL)) - return SCPE_IERR; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if (dibp == NULL) - return SCPE_IERR; -newba = (uint32) get_uint (cptr, DEV_RDX, IOPAGEBASE+IOPAGEMASK, &r); /* get new */ -if (r != SCPE_OK) - return r; -if ((newba <= IOPAGEBASE) || /* > IO page base? */ - (newba % ((uint32) val))) /* check modulus */ - return SCPE_ARG; -dibp->ba = newba; /* store */ -dptr->flags = dptr->flags & ~DEV_FLTA; /* not floating */ -autcon_enb = 0; /* autoconfig off */ -return SCPE_OK; -} - -/* Show device address */ - -t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -DEVICE *dptr; -DIB *dibp; -uint32 radix = DEV_RDX; - -if (uptr == NULL) - return SCPE_IERR; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if ((dibp == NULL) || (dibp->ba <= IOPAGEBASE)) - return SCPE_IERR; -if (sim_switches & SWMASK ('H')) - radix = 16; -if (sim_switches & SWMASK ('O')) - radix = 8; -fprintf (st, "address="); -fprint_val (st, (t_value) dibp->ba, DEV_RDX, 32, PV_LEFT); -if (radix != DEV_RDX) { - fprintf (st, "("); - fprint_val (st, (t_value) dibp->ba, radix, 32, PV_LEFT); - fprintf (st, ")"); - } -if (dibp->lnt > 1) { - fprintf (st, "-"); - fprint_val (st, (t_value) dibp->ba + dibp->lnt - 1, DEV_RDX, 32, PV_LEFT); - if (radix != DEV_RDX) { - fprintf (st, "("); - fprint_val (st, (t_value) dibp->ba + dibp->lnt - 1, radix, 32, PV_LEFT); - fprintf (st, ")"); - } - } -if (dptr->flags & DEV_FLTA) - fprintf (st, "*"); -return SCPE_OK; -} - -/* Set address floating */ - -t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -DEVICE *dptr; - -if (cptr != NULL) - return SCPE_ARG; -if (uptr == NULL) - return SCPE_IERR; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; -dptr->flags = dptr->flags | DEV_FLTA; /* floating */ -return auto_config (NULL, 0); /* autoconfigure */ -} - -/* Change device vector */ - -t_stat set_vec (UNIT *uptr, int32 arg, char *cptr, void *desc) -{ -DEVICE *dptr; -DIB *dibp; -uint32 newvec; -t_stat r; - -if (cptr == NULL) - return SCPE_ARG; -if (uptr == NULL) - return SCPE_IERR; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if (dibp == NULL) - return SCPE_IERR; -newvec = (uint32) get_uint (cptr, DEV_RDX, VEC_Q + 01000, &r); -if ((r != SCPE_OK) || (newvec == VEC_Q) || - ((newvec + (dibp->vnum * 4)) >= (VEC_Q + 01000)) || - (newvec & ((dibp->vnum > 1)? 07: 03))) - return SCPE_ARG; -dibp->vec = newvec; -dptr->flags = dptr->flags & ~DEV_FLTA; /* not floating */ -autcon_enb = 0; /* autoconfig off */ -return SCPE_OK; -} - -/* Show device vector */ - -t_stat show_vec (FILE *st, UNIT *uptr, int32 arg, void *desc) -{ -DEVICE *dptr; -DIB *dibp; -uint32 vec, numvec, br_lvl, radix = DEV_RDX; - -if (uptr == NULL) - return SCPE_IERR; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if (dibp == NULL) - return SCPE_IERR; -if (sim_switches & SWMASK ('H')) - radix = 16; -if (sim_switches & SWMASK ('O')) - radix = 8; -vec = dibp->vec; -if (arg) - numvec = arg; -else numvec = dibp->vnum; -if (vec == 0) - fprintf (st, "no vector"); -else { - fprintf (st, "vector="); - fprint_val (st, (t_value) vec, DEV_RDX, 16, PV_LEFT); - if (radix != DEV_RDX) { - fprintf (st, "("); - fprint_val (st, (t_value) vec, radix, 16, PV_LEFT); - fprintf (st, ")"); - } - if (numvec > 1) { - fprintf (st, "-"); - fprint_val (st, (t_value) vec + (4 * (numvec - 1)), DEV_RDX, 16, PV_LEFT); - if (radix != DEV_RDX) { - fprintf (st, "("); - fprint_val (st, (t_value) vec + (4 * (numvec - 1)), radix, 16, PV_LEFT); - fprintf (st, ")"); - } - } - } -br_lvl = dibp->vloc / 32; -if (br_lvl < 4) /* VAXen do 0-3, others 4-7 */ - br_lvl = br_lvl + 4; -fprintf (st, ", BR%d", br_lvl); -return SCPE_OK; -} - -/* Show vector for terminal multiplexor */ - -t_stat show_vec_mux (FILE *st, UNIT *uptr, int32 arg, void *desc) -{ -TMXR *mp = (TMXR *) desc; - -if ((mp == NULL) || (arg == 0)) - return SCPE_IERR; -return show_vec (st, uptr, ((mp->lines * 2) / arg), desc); -} - -/* Init Unibus tables */ - -void init_ubus_tab (void) -{ -size_t i, j; - -for (i = 0; i < IPL_HLVL; i++) { /* clear intr tab */ - for (j = 0; j < 32; j++) { - int_vec[i][j] = 0; - int_ack[i][j] = NULL; - } - } -for (i = 0; i < (IOPAGESIZE >> 1); i++) { /* clear dispatch tab */ - iodispR[i] = NULL; - iodispW[i] = NULL; - iodibp[i] = NULL; - } -return; -} - -/* Build Unibus tables */ - -t_stat build_ubus_tab (DEVICE *dptr, DIB *dibp) -{ -int32 i, idx, vec, ilvl, ibit; - -if ((dptr == NULL) || (dibp == NULL)) /* validate args */ - return SCPE_IERR; -if (dibp->vnum > VEC_DEVMAX) - return SCPE_IERR; -for (i = 0; i < dibp->vnum; i++) { /* loop thru vec */ - idx = dibp->vloc + i; /* vector index */ - vec = dibp->vec? (dibp->vec + (i * 4)): 0; /* vector addr */ - ilvl = idx / 32; - ibit = idx % 32; - if ((int_ack[ilvl][ibit] && dibp->ack[i] && /* conflict? */ - (int_ack[ilvl][ibit] != dibp->ack[i])) || - (int_vec[ilvl][ibit] && vec && - (int_vec[ilvl][ibit] != vec))) { - sim_printf ("Device %s interrupt slot conflict at %d\n", - sim_dname (dptr), idx); - return SCPE_STOP; - } - if (dibp->ack[i]) - int_ack[ilvl][ibit] = dibp->ack[i]; - else if (vec) - int_vec[ilvl][ibit] = vec; - } -for (i = 0; i < (int32) dibp->lnt; i = i + 2) { /* create entries */ - idx = ((dibp->ba + i) & IOPAGEMASK) >> 1; /* index into disp */ - if ((iodispR[idx] && dibp->rd && /* conflict? */ - (iodispR[idx] != dibp->rd)) || - (iodispW[idx] && dibp->wr && - (iodispW[idx] != dibp->wr))) { - printf ("Device %s address conflict at \n", sim_dname (dptr)); - fprint_val (stdout, (t_value) dibp->ba, DEV_RDX, 32, PV_LEFT); - if (sim_log) { - fprintf (sim_log, "Device %s address conflict at \n", sim_dname (dptr)); - fprint_val (sim_log, (t_value) dibp->ba, DEV_RDX, 32, PV_LEFT); - } - return SCPE_STOP; - } - if (dibp->rd) /* set rd dispatch */ - iodispR[idx] = dibp->rd; - if (dibp->wr) /* set wr dispatch */ - iodispW[idx] = dibp->wr; - iodibp[idx] = dibp; /* remember DIB */ - } -return SCPE_OK; -} - -/* Show IO space */ - -t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -uint32 i, j; -DEVICE *dptr; -DIB *dibp; - -if (build_dib_tab ()) /* build IO page */ - return SCPE_OK; -for (i = 0, dibp = NULL; i < (IOPAGESIZE >> 1); i++) { /* loop thru entries */ - if (iodibp[i] && (iodibp[i] != dibp)) { /* new block? */ - dibp = iodibp[i]; /* DIB for block */ - for (j = 0, dptr = NULL; sim_devices[j] != NULL; j++) { - if (((DIB*) sim_devices[j]->ctxt) == dibp) { - dptr = sim_devices[j]; /* locate device */ - break; - } /* end if */ - } /* end for j */ - fprint_val (st, (t_value) dibp->ba, DEV_RDX, 32, PV_LEFT); - fprintf (st, " - "); - fprint_val (st, (t_value) dibp->ba + dibp->lnt - 1, DEV_RDX, 32, PV_LEFT); - fprintf (st, "%c\t%s\n", /* print block entry */ - (dptr && (dptr->flags & DEV_FLTA))? '*': ' ', - dptr? sim_dname (dptr): "CPU"); - } /* end if */ - } /* end for i */ -return SCPE_OK; -} - -/* Autoconfiguration - - The table reflects the MicroVAX 3900 microcode, with one addition - the - number of controllers field handles devices where multiple instances - are simulated through a single DEVICE structure (e.g., DZ, VH). - - A minus number of vectors indicates a field that should be calculated - but not placed in the DIB (RQ, TQ dynamic vectors) */ - -#define AUTO_MAXC 4 -#define AUTO_CSRBASE 0010 -#define AUTO_VECBASE 0300 - -typedef struct { - char *dnam[AUTO_MAXC]; - int32 numc; - int32 numv; - uint32 amod; - uint32 vmod; - uint32 fixa[AUTO_MAXC]; - uint32 fixv[AUTO_MAXC]; - } AUTO_CON; - -AUTO_CON auto_tab[] = { - { { "DCI" }, DCX_LINES, 2, 0, 8, { 0 } }, /* DC11 - fx CSRs */ - { { "DLI" }, DLX_LINES, 2, 0, 8, { 0 } }, /* KL11/DL11/DLV11 - fx CSRs */ - { { NULL }, 1, 2, 0, 8, { 0 } }, /* DLV11J - fx CSRs */ - { { NULL }, 1, 2, 8, 8 }, /* DJ11 */ - { { NULL }, 1, 2, 16, 8 }, /* DH11 */ - { { NULL }, 1, 2, 8, 8 }, /* DQ11 */ - { { NULL }, 1, 2, 8, 8 }, /* DU11 */ - { { NULL }, 1, 2, 8, 8 }, /* DUP11 */ - { { NULL }, 10, 2, 8, 8 }, /* LK11A */ - { { NULL }, 1, 2, 8, 8 }, /* DMC11 */ - { { "DZ" }, DZ_MUXES, 2, 8, 8 }, /* DZ11 */ - { { NULL }, 1, 2, 8, 8 }, /* KMC11 */ - { { NULL }, 1, 2, 8, 8 }, /* LPP11 */ - { { NULL }, 1, 2, 8, 8 }, /* VMV21 */ - { { NULL }, 1, 2, 16, 8 }, /* VMV31 */ - { { NULL }, 1, 2, 8, 8 }, /* DWR70 */ - { { "RL", "RLB" }, 1, 1, 8, 4, {IOBA_RL}, {VEC_RL} }, /* RL11 */ - { { "TS", "TSB", "TSC", "TSD" }, 1, 1, 0, 4, /* TS11 */ - {IOBA_TS, IOBA_TS + 4, IOBA_TS + 8, IOBA_TS + 12}, - {VEC_TS} }, - { { NULL }, 1, 2, 16, 8 }, /* LPA11K */ - { { NULL }, 1, 2, 8, 8 }, /* KW11C */ - { { NULL }, 1, 1, 8, 8 }, /* reserved */ - { { "RX", "RY" }, 1, 1, 8, 4, {IOBA_RX} , {VEC_RX} }, /* RX11/RX211 */ - { { NULL }, 1, 1, 8, 4 }, /* DR11W */ - { { NULL }, 1, 1, 8, 4, { 0, 0 }, { 0 } }, /* DR11B - fx CSRs,vec */ - { { NULL }, 1, 2, 8, 8 }, /* DMP11 */ - { { NULL }, 1, 2, 8, 8 }, /* DPV11 */ - { { NULL }, 1, 2, 8, 8 }, /* ISB11 */ - { { NULL }, 1, 2, 16, 8 }, /* DMV11 */ - { { "XU", "XUB" }, 1, 1, 8, 4, {IOBA_XU}, {VEC_XU} }, /* DEUNA */ - { { "XQ", "XQB" }, 1, 1, 0, 4, /* DEQNA */ - {IOBA_XQ,IOBA_XQB}, {VEC_XQ} }, - { { "RQ", "RQB", "RQC", "RQD" }, 1, -1, 4, 4, /* RQDX3 */ - {IOBA_RQ}, {VEC_RQ} }, - { { NULL }, 1, 8, 32, 4 }, /* DMF32 */ - { { NULL }, 1, 2, 16, 8 }, /* KMS11 */ - { { NULL }, 1, 1, 16, 4 }, /* VS100 */ - { { "TQ", "TQB" }, 1, -1, 4, 4, {IOBA_TQ}, {VEC_TQ} }, /* TQK50 */ - { { NULL }, 1, 2, 16, 8 }, /* KMV11 */ - { { "VH" }, VH_MUXES, 2, 16, 8 }, /* DHU11/DHQ11 */ - { { NULL }, 1, 6, 32, 4 }, /* DMZ32 */ - { { NULL }, 1, 6, 32, 4 }, /* CP132 */ - { { NULL }, 1, 2, 64, 8, { 0 } }, /* QVSS - fx CSR */ - { { NULL }, 1, 1, 8, 4 }, /* VS31 */ - { { NULL }, 1, 1, 0, 4, { 0 } }, /* LNV11 - fx CSR */ - { { NULL }, 1, 1, 16, 4 }, /* LNV21/QPSS */ - { { NULL }, 1, 1, 8, 4, { 0 } }, /* QTA - fx CSR */ - { { NULL }, 1, 1, 8, 4 }, /* DSV11 */ - { { NULL }, 1, 2, 8, 8 }, /* CSAM */ - { { NULL }, 1, 2, 8, 8 }, /* ADV11C */ - { { NULL }, 1, 0, 8, 0 }, /* AAV11C */ - { { NULL }, 1, 2, 8, 8, { 0 }, { 0 } }, /* AXV11C - fx CSR,vec */ - { { NULL }, 1, 2, 4, 8, { 0 } }, /* KWV11C - fx CSR */ - { { NULL }, 1, 2, 8, 8, { 0 } }, /* ADV11D - fx CSR */ - { { NULL }, 1, 2, 8, 8, { 0 } }, /* AAV11D - fx CSR */ - { { "QDSS" }, 1, 3, 0, 16, {IOBA_QDSS} }, /* QDSS - fx CSR */ - { { NULL }, -1 } /* end table */ -}; - -t_stat auto_config (char *name, int32 nctrl) -{ -uint32 csr = IOPAGEBASE + AUTO_CSRBASE; -uint32 vec = VEC_Q + AUTO_VECBASE; -AUTO_CON *autp; -DEVICE *dptr; -DIB *dibp; -uint32 j, k, vmask, amask; - -if (autcon_enb == 0) /* enabled? */ - return SCPE_OK; -if (name) { /* updating? */ - if (nctrl < 0) - return SCPE_ARG; - for (autp = auto_tab; autp->numc >= 0; autp++) { - for (j = 0; (j < AUTO_MAXC) && autp->dnam[j]; j++) { - if (strcmp (name, autp->dnam[j]) == 0) - autp->numc = nctrl; - } - } - } -for (autp = auto_tab; autp->numc >= 0; autp++) { /* loop thru table */ - if (autp->amod) { /* floating csr? */ - amask = autp->amod - 1; - csr = (csr + amask) & ~amask; /* align csr */ - } - for (j = k = 0; (j < AUTO_MAXC) && autp->dnam[j]; j++) { - if (autp->dnam[j] == NULL) /* no device? */ - continue; - dptr = find_dev (autp->dnam[j]); /* find ctrl */ - if ((dptr == NULL) || /* enabled, floating? */ - (dptr->flags & DEV_DIS) || - !(dptr->flags & DEV_FLTA)) - continue; - dibp = (DIB *) dptr->ctxt; /* get DIB */ - if (dibp == NULL) /* not there??? */ - return SCPE_IERR; - if (autp->amod) { /* dyn csr needed? */ - if (autp->fixa[k]) /* fixed csr avail? */ - dibp->ba = autp->fixa[k]; /* use it */ - else { /* no fixed left */ - dibp->ba = csr; /* set CSR */ - csr += (autp->numc * autp->amod); /* next CSR */ - } /* end else */ - } /* end if dyn csr */ - if (autp->numv && autp->vmod) { /* dyn vec needed? */ - uint32 numv = abs (autp->numv); /* get num vec */ - if (autp->fixv[k]) { /* fixed vec avail? */ - if (autp->numv > 0) - dibp->vec = autp->fixv[k]; /* use it */ - } - else { /* no fixed left */ - vmask = autp->vmod - 1; - vec = (vec + vmask) & ~vmask; /* align vector */ - if (autp->numv > 0) - dibp->vec = vec; /* set vector */ - vec += (autp->numc * numv * 4); - } /* end else */ - } /* end if dyn vec */ - k++; /* next instance */ - } /* end for j */ - if (autp->amod) /* flt CSR? gap */ - csr = csr + 2; - } /* end for i */ -return SCPE_OK; -} - -/* Factory bad block table creation routine - - This routine writes a DEC standard 044 compliant bad block table on the - last track of the specified unit. The bad block table consists of 10 - repetitions of the same table, formatted as follows: - - words 0-1 pack id number - words 2-3 cylinder/sector/surface specifications - : - words n-n+1 end of table (-1,-1) - - Inputs: - uptr = pointer to unit - sec = number of sectors per surface - wds = number of words per sector - Outputs: - sta = status code -*/ - -t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds) -{ -int32 i; -t_addr da; -uint16 *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 ("Overwrite last track? [N]", FALSE)) - return SCPE_OK; -da = (uptr->capac - (sec * wds)) * sizeof (uint16); -if (sim_fseek (uptr->fileref, da, SEEK_SET)) - return SCPE_IOERR; -if ((buf = (uint16 *) malloc (wds * sizeof (uint16))) == NULL) - return SCPE_MEM; -buf[0] = buf[1] = 012345u; -buf[2] = buf[3] = 0; -for (i = 4; i < wds; i++) - buf[i] = 0177777u; -for (i = 0; (i < sec) && (i < 10); i++) - sim_fwrite (buf, sizeof (uint16), wds, uptr->fileref); -free (buf); -if (ferror (uptr->fileref)) - return SCPE_IOERR; -return SCPE_OK; -} diff --git a/PDP11/pdp11_io_lib.h b/PDP11/pdp11_io_lib.h deleted file mode 100644 index 4dc3828f..00000000 --- a/PDP11/pdp11_io_lib.h +++ /dev/null @@ -1,44 +0,0 @@ -/* pdp11_io_lib.h: Unibus/Qbus common support routines header file - - Copyright (c) 1993-2017, 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. -*/ - -#ifndef PDP11_IO_LIB_H_ -#define PDP11_IO_LIB_H_ 0 - -t_stat set_autocon (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat show_autocon (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat set_addr (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat show_addr (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat set_addr_flt (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat set_vec (UNIT *uptr, int32 arg, char *cptr, void *desc); -t_stat show_vec (FILE *st, UNIT *uptr, int32 arg, void *desc); -t_stat show_vec_mux (FILE *st, UNIT *uptr, int32 arg, void *desc); -t_stat show_iospace (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat auto_config (char *name, int32 nctrl); -t_stat pdp11_bad_block (UNIT *uptr, int32 sec, int32 wds); -void init_ubus_tab (void); -t_stat build_ubus_tab (DEVICE *dptr, DIB *dibp); - -#endif diff --git a/PDP11/pdp11_ke.c b/PDP11/pdp11_ke.c deleted file mode 100644 index d71e836f..00000000 --- a/PDP11/pdp11_ke.c +++ /dev/null @@ -1,347 +0,0 @@ -/* pdp11_ke.c: PDP-11/20 extended arithmetic element - - Copyright (c) 1993-2008, 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 ke_ACTION OF CONTRke_ACT, 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 code draws on prior work by Tim Shoppa and Brad Parker. My thanks for - to them for letting me use their work. - - EAE PDP-11/20 extended arithmetic element -*/ - -#include "pdp11_defs.h" - -#define GET_SIGN_L(v) (((v) >> 31) & 1) -#define GET_SIGN_W(v) (((v) >> 15) & 1) -#define GET_SIGN_B(v) (((v) >> 7) & 1) - -/* KE11A I/O address offsets 0177300 - 0177316 */ - -#define KE_DIV 000 /* divide */ -#define KE_AC 002 /* accumulator */ -#define KE_MQ 004 /* MQ */ -#define KE_MUL 006 /* multiply */ -#define KE_SC 010 /* step counter */ -#define KE_NOR 012 /* normalize */ -#define KE_LSH 014 /* logical shift */ -#define KE_ASH 016 /* arithmetic shift */ - -/* Status register */ - -#define KE_SR_C 0001 /* carry */ -#define KE_SR_SXT 0002 /* AC<15:0> = MQ<15> */ -#define KE_SR_Z 0004 /* AC = MQ = 0 */ -#define KE_SR_MQZ 0010 /* MQ = 0 */ -#define KE_SR_ACZ 0020 /* AC = 0 */ -#define KE_SR_ACM1 0040 /* AC = 177777 */ -#define KE_SR_N 0100 /* last op negative */ -#define KE_SR_NXV 0200 /* last op ovf XOR N */ -#define KE_SR_DYN (KE_SR_SXT|KE_SR_Z|KE_SR_MQZ|KE_SR_ACZ|KE_SR_ACM1) - -/* Visible state */ - -uint32 ke_AC = 0; -uint32 ke_MQ = 0; -uint32 ke_SC = 0; -uint32 ke_SR = 0; - -t_stat ke_rd (int32 *data, int32 PA, int32 access); -t_stat ke_wr (int32 data, int32 PA, int32 access); -t_stat ke_reset (DEVICE *dptr); -uint32 ke_set_SR (void); - -DIB ke_dib = { IOBA_KE, IOLN_KE, &ke_rd, &ke_wr, 0 }; - -UNIT ke_unit = { - UDATA (NULL, UNIT_DISABLE, 0) - }; - -REG ke_reg[] = { - { ORDATA (AC, ke_AC, 16) }, - { ORDATA (MQ, ke_MQ, 16) }, - { ORDATA (SC, ke_SC, 6) }, - { ORDATA (SR, ke_SR, 8) }, - { NULL } - }; - -MTAB ke_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, - NULL, &show_addr, NULL }, - { 0 } - }; - -DEVICE ke_dev = { - "KE", &ke_unit, ke_reg, ke_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &ke_reset, - NULL, NULL, NULL, - &ke_dib, DEV_DISABLE | DEV_DIS | DEV_UBUS - }; - -/* KE read - reads are always 16b, to even addresses */ - -t_stat ke_rd (int32 *data, int32 PA, int32 access) -{ -switch (PA & 016) { /* decode PA<3:1> */ - - case KE_AC: /* AC */ - *data = ke_AC; - break; - - case KE_MQ: /* MQ */ - *data = ke_MQ; - break; - - case KE_NOR: /* norm (SC) */ - *data = ke_SC; - break; - - case KE_SC: /* SR/SC */ - *data = (ke_set_SR () << 8) | ke_SC; - break; - - default: - *data = 0; - break; - } - -return SCPE_OK; -} - -/* KE write - writes trigger actual arithmetic */ - -t_stat ke_wr (int32 data, int32 PA, int32 access) -{ -int32 quo, t32, sout, sign; -uint32 absd, absr; - -switch (PA & 017) { /* decode PA<3:0> */ - - case KE_DIV: /* divide */ - if ((access == WRITEB) && GET_SIGN_B (data)) /* byte write? */ - data |= 0177400; /* sext data to 16b */ - ke_SR = 0; /* N = V = C = 0 */ - t32 = (ke_AC << 16) | ke_MQ; /* 32b divd */ - if (GET_SIGN_W (ke_AC)) /* sext (divd) */ - t32 = t32 | ~017777777777; - if (GET_SIGN_W (data)) /* sext (divr) */ - data = data | ~077777; - absd = abs (t32); - absr = abs (data); - if ((absd >> 16) >= absr) { /* divide fails? */ - -/* Based on the documentation, here's what has happened: - - SC = 16. - SR = (AC<15> == data<15>) - AC'MQ = (AC'MQ << 1) | SR - AC = SR? AC - data: AC + data - SR = (AC<15> == data<15>) - SC = SC - 1 - stop -*/ - - sign = GET_SIGN_W (ke_AC ^ data) ^ 1; /* 1 if signs match */ - ke_AC = (ke_AC << 1) | (ke_MQ >> 15); - ke_AC = (sign? ke_AC - data: ke_AC + data) & DMASK; - ke_MQ = ((ke_MQ << 1) | sign) & DMASK; - if (GET_SIGN_W (ke_AC ^ data) == 0) /* 0 if signs match */ - ke_SR |= KE_SR_C; - ke_SC = 15; /* SC clocked once */ - ke_SR |= KE_SR_NXV; /* set overflow */ - } - else { - ke_SC = 0; - quo = t32 / data; - ke_MQ = quo & DMASK; /* MQ has quo */ - ke_AC = (t32 % data) & DMASK; /* AC has rem */ - if ((quo > 32767) || (quo < -32768)) /* quo overflow? */ - ke_SR |= KE_SR_NXV; /* set overflow */ - } - if (GET_SIGN_W (ke_MQ)) /* result negative? */ - ke_SR ^= (KE_SR_N | KE_SR_NXV); /* N = 1, compl NXV */ - break; - - case KE_AC: /* AC */ - if ((access == WRITEB) && GET_SIGN_B (data)) /* byte write? */ - data |= 0177400; /* sext data to 16b */ - ke_AC = data; - break; - - case KE_AC + 1: /* AC odd byte */ - ke_AC = (ke_AC & 0377) | (data << 8); - break; - - case KE_MQ: /* MQ */ - if ((access == WRITEB) && GET_SIGN_B (data)) /* byte write? */ - data |= 0177400; /* sext data to 16b */ - ke_MQ = data; - if (GET_SIGN_W (ke_MQ)) /* sext MQ to AC */ - ke_AC = 0177777; - else ke_AC = 0; - break; - - case KE_MQ + 1: /* MQ odd byte */ - ke_MQ = (ke_MQ & 0377) | (data << 8); - if (GET_SIGN_W (ke_MQ)) /* sext MQ to AC */ - ke_AC = 0177777; - else ke_AC = 0; - break; - - case KE_MUL: /* multiply */ - if ((access == WRITEB) && GET_SIGN_B (data)) /* byte write? */ - data |= 0177400; /* sext data to 16b */ - ke_SC = 0; - if (GET_SIGN_W (data)) /* sext operands */ - data |= ~077777; - t32 = ke_MQ; - if (GET_SIGN_W (t32)) - t32 |= ~077777; - t32 = t32 * data; - ke_AC = (t32 >> 16) & DMASK; - ke_MQ = t32 & DMASK; - if (GET_SIGN_W (ke_AC)) /* result negative? */ - ke_SR = KE_SR_N | KE_SR_NXV; /* N = 1, V = C = 0 */ - else ke_SR = 0; /* N = 0, V = C = 0 */ - break; - - case KE_SC: /* SC */ - if (access == WRITEB) /* ignore byte writes */ - return SCPE_OK; - ke_SR = (data >> 8) & (KE_SR_NXV|KE_SR_N|KE_SR_C); - ke_SC = data & 077; - break; - - case KE_NOR: /* normalize */ - for (ke_SC = 0; ke_SC < 31; ke_SC++) { /* max 31 shifts */ - if (((ke_AC == 0140000) && (ke_MQ == 0)) || /* special case? */ - (GET_SIGN_W (ke_AC ^ (ke_AC << 1)))) /* AC<15> != AC<14>? */ - break; - ke_AC = ((ke_AC << 1) | (ke_MQ >> 15)) & DMASK; - ke_MQ = (ke_MQ << 1) & DMASK; - } - if (GET_SIGN_W (ke_AC)) /* result negative? */ - ke_SR = KE_SR_N | KE_SR_NXV; /* N = 1, V = C = 0 */ - else ke_SR = 0; /* N = 0, V = C = 0 */ - break; - - case KE_LSH: /* logical shift */ - ke_SC = 0; - ke_SR = 0; /* N = V = C = 0 */ - data = data & 077; /* 6b shift count */ - if (data != 0) { - t32 = (ke_AC << 16) | ke_MQ; /* 32b operand */ - if ((sign = GET_SIGN_W (ke_AC))) /* sext operand */ - t32 = t32 | ~017777777777; - if (data < 32) { /* [1,31] - left */ - sout = (t32 >> (32 - data)) | (-sign << data); - t32 = ((uint32) t32) << data; /* do shift (zext) */ - if (sout != (GET_SIGN_L (t32)? -1: 0)) /* bits lost = sext? */ - ke_SR |= KE_SR_NXV; /* no, V = 1 */ - if (sout & 1) /* last bit lost = 1? */ - ke_SR |= KE_SR_C; /* yes, C = 1 */ - } - else { /* [32,63] = -32,-1 */ - if ((t32 >> (63 - data)) & 1) /* last bit lost = 1? */ - ke_SR |= KE_SR_C; /* yes, C = 1*/ - t32 = (data != 32)? ((uint32) t32) >> (64 - data): 0; - } - ke_AC = (t32 >> 16) & DMASK; - ke_MQ = t32 & DMASK; - } - if (GET_SIGN_W (ke_AC)) /* result negative? */ - ke_SR ^= (KE_SR_N | KE_SR_NXV); /* N = 1, compl NXV */ - break; - -/* EAE ASH differs from EIS ASH and cannot use the same overflow test */ - - case KE_ASH: /* arithmetic shift */ - ke_SC = 0; - ke_SR = 0; /* N = V = C = 0 */ - data = data & 077; /* 6b shift count */ - if (data != 0) { - t32 = (ke_AC << 16) | ke_MQ; /* 32b operand */ - if ((sign = GET_SIGN_W (ke_AC))) /* sext operand */ - t32 = t32 | ~017777777777; - if (data < 32) { /* [1,31] - left */ - sout = (t32 >> (31 - data)) | (-sign << data); - t32 = (t32 & 020000000000) | ((t32 << data) & 017777777777); - if (sout != (GET_SIGN_L (t32)? -1: 0)) /* bits lost = sext? */ - ke_SR |= KE_SR_NXV; /* no, V = 1 */ - if (sout & 1) /* last bit lost = 1? */ - ke_SR |= KE_SR_C; /* yes, C = 1 */ - } - else { /* [32,63] = -32,-1 */ - if ((t32 >> (63 - data)) & 1) /* last bit lost = 1? */ - ke_SR |= KE_SR_C; /* yes, C = 1 */ - t32 = (data != 32)? /* special case 32 */ - (((uint32) t32) >> (64 - data)) | (-sign << (data - 32)): - -sign; - } - ke_AC = (t32 >> 16) & DMASK; - ke_MQ = t32 & DMASK; - } - if (GET_SIGN_W (ke_AC)) /* result negative? */ - ke_SR ^= (KE_SR_N | KE_SR_NXV); /* N = 1, compl NXV */ - break; - - default: /* all others ignored */ - return SCPE_OK; - } /* end switch PA */ - -ke_set_SR (); -return SCPE_OK; -} - -/* Update status register based on current AC, MQ */ - -uint32 ke_set_SR (void) -{ -ke_SR &= ~KE_SR_DYN; /* clr dynamic bits */ -if (ke_MQ == 0) /* MQ == 0? */ - ke_SR |= KE_SR_MQZ; -if (ke_AC == 0) { /* AC == 0? */ - ke_SR |= KE_SR_ACZ; - if (GET_SIGN_W (ke_MQ) == 0) /* MQ positive? */ - ke_SR |= KE_SR_SXT; - if (ke_MQ == 0) /* MQ zero? */ - ke_SR |= KE_SR_Z; - } -if (ke_AC == 0177777) { /* AC == 177777? */ - ke_SR |= KE_SR_ACM1; - if (GET_SIGN_W (ke_MQ) == 1) /* MQ negative? */ - ke_SR |= KE_SR_SXT; - } -return ke_SR; -} - -/* Reset routine */ - -t_stat ke_reset (DEVICE *dptr) -{ -ke_SR = 0; -ke_SC = 0; -ke_AC = 0; -ke_MQ = 0; -return SCPE_OK; -} diff --git a/PDP11/pdp11_kg.c b/PDP11/pdp11_kg.c deleted file mode 100644 index 7fb2f75e..00000000 --- a/PDP11/pdp11_kg.c +++ /dev/null @@ -1,482 +0,0 @@ -/* pdp11_kg.c - Communications Arithmetic Option KG11-A - - Copyright (c) 2007-2010, John A. Dundas III - - 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 the author shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the author. - - kg KG11-A Communications Arithmetic Option (M7251) - - 03-Jan-10 JAD Eliminate gcc warnings - 08-Jan-08 JAD First public release integrated with SIMH V3.7-3. - 09-Dec-07 JAD SIMH-style debugging. - Finished validating against real hardware. - Support for up to 8 units, the maximum. - Keep all module data in the UNIT structure. - Clean up bit and mask definitions. - 01-Dec-07 JAD Now work on the corner cases that the - diagnostic does not check. - CLR does not clear the QUO bit. - Correct SR write logic. - 29-Nov-07 JAD Original implementation and testing based on - an idea from 07-Jul-03. Passes the ZKGAB0 - diagnostic. - - Information necessary to create this simulation was gathered from - a number of sources including: - - KG11-A Exclusive-OR and CRC block check manual, DEC-11-HKGAA-B-D - - Maintenance print set - - A Painless Guide to CRC Error Detection Algorithms, Ross N. Williams - - - The original PDP-11 instruction set, as implemented in the /20, - /15, /10, and /5, did not include XOR. [One of the differences - tables incorrectly indicates the /04 does not implement this - instruction.] This device implements XOR, XORB, and a variety of - CRCs. - - The maintenance prints indicate that the device was probably available - starting in late 1971. May need to check further. The first edition - of the manual was May 1972. - - The device was still sold at least as late as mid-1982 according - to the PDP-11 Systems and Options Summary. RSTS/E included support - for up to 8 units in support of the 2780 emulation or for use with - DP11, DU11, or DUP11. The device appears to have been retired by - 1983-03, and possibly earlier. - - I/O Page Registers - - SR 7707x0 (read-write) status - BCC 7707x2 (read-only) BCC (block check character) - DR 7707x4 (write-only) data - - Vector: none - - Priority: none - - The KG11-A is a programmed-I/O, non-interrupting device. Therefore - no vector or bus request level are necessary. It is a Unibus device - but since it does not address memory itself (it only presents - registers in the I/O page) it is compatible with extended Unibus - machines (22-bit) as well as traditional Unibus. - - Implements 5 error detection codes: - LRC-8 - LRC-16 - CRC-12 - CRC-16 - CRC-CCITT -*/ - -#if !defined (VM_PDP11) -#error "KG11 is not supported!" -#endif -#include "pdp11_defs.h" - -extern REG cpu_reg[]; -extern int32 R[]; - -#ifndef KG_UNITS -#define KG_UNITS (8) -#endif - -/* Control and Status Register */ - -#define KGSR_V_QUO (8) /* RO */ -#define KGSR_V_DONE (7) /* RO */ -#define KGSR_V_SEN (6) /* R/W shift enable */ -#define KGSR_V_STEP (5) /* W */ -#define KGSR_V_CLR (4) /* W */ -#define KGSR_V_DDB (3) /* R/W double data byte */ -#define KGSR_V_CRCIC (2) /* R/W */ -#define KGSR_V_LRC (1) /* R/W */ -#define KGSR_V_16 (0) /* R/W */ - -#define KGSR_M_QUO (1u << KGSR_V_QUO) -#define KGSR_M_DONE (1u << KGSR_V_DONE) -#define KGSR_M_SEN (1u << KGSR_V_SEN) -#define KGSR_M_STEP (1u << KGSR_V_STEP) -#define KGSR_M_CLR (1u << KGSR_V_CLR) -#define KGSR_M_DDB (1u << KGSR_V_DDB) -#define KGSR_M_CRCIC (1u << KGSR_V_CRCIC) -#define KGSR_M_LRC (1u << KGSR_V_LRC) -#define KGSR_M_16 (1u << KGSR_V_16) - -#define KG_SR_RDMASK (KGSR_M_QUO | KGSR_M_DONE | KGSR_M_SEN | KGSR_M_DDB | \ - KGSR_M_CRCIC | KGSR_M_LRC | KGSR_M_16) -#define KG_SR_WRMASK (KGSR_M_SEN | KGSR_M_DDB | KGSR_M_CRCIC | \ - KGSR_M_LRC | KGSR_M_16) - -#define KG_SR_POLYMASK (KGSR_M_CRCIC|KGSR_M_LRC|KGSR_M_16) - -/* Unit structure redefinitions */ -#define SR u3 -#define BCC u4 -#define DR u5 -#define PULSCNT u6 - -#define POLY_LRC8 (0x0008) -#define POLY_LRC16 (0x0080) -#define POLY_CRC12 (0x0f01) -#define POLY_CRC16 (0xa001) -#define POLY_CCITT (0x8408) - -static const struct { - uint16 poly; - uint16 pulses; - const char * const name; -} config[] = { - /* DDB=0 */ - { POLY_CRC12, 6, "CRC-12" }, - { POLY_CRC16, 8, "CRC-16" }, - { POLY_LRC8, 8, "LRC-8" }, - { POLY_LRC16, 8, "LRC-16" }, - { 0, 0, "undefined" }, - { POLY_CCITT, 8, "CRC-CCITT" }, - { 0, 0, "undefined" }, - { 0, 0, "undefined" }, - /* DDB=1 */ - { POLY_CRC12, 12, "CRC-12" }, - { POLY_CRC16, 16, "CRC-16" }, - { POLY_LRC8, 16, "LRC-8" }, - { POLY_LRC16, 16, "LRC-16" }, - { 0, 0, "undefined" }, - { POLY_CCITT, 16, "CRC-CCITT" }, - { 0, 0, "undefined" }, - { 0, 0, "undefined" } -}; - -/* Forward declarations */ - -static t_stat kg_rd (int32 *, int32, int32); -static t_stat kg_wr (int32, int32, int32); -static t_stat kg_reset (DEVICE *); -static void do_poly (int, t_bool); -static t_stat set_units (UNIT *, int32, char *, void *); - -/* 16-bit rotate right */ - -#define ROR(n,v) (((v >> n) & DMASK) | ((v << (16 - n)) & DMASK)) - -/* 8-bit rotate right */ - -#define RORB(n,v) (((v & 0377) >> n) | ((v << (8 - n)) & 0377)) - -/* KG data structures - - kg_dib KG PDP-11 device information block - kg_unit KG unit descriptor - kg_reg KG register list - kg_mod KG modifiers table - kg_debug KG debug names table - kg_dev KG device descriptor -*/ - -static DIB kg_dib = { - IOBA_KG, - (IOLN_KG + 2) * KG_UNITS, - &kg_rd, - &kg_wr, - 0, 0, 0, { NULL } -}; - -static UNIT kg_unit[] = { - { UDATA (NULL, 0, 0) }, - { UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) }, - { UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) }, - { UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) }, - { UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) }, - { UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) }, - { UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) }, - { UDATA (NULL, UNIT_DISABLE + UNIT_DIS, 0) }, -}; - -static const REG kg_reg[] = { - { ORDATA (SR0, kg_unit[0].SR, 16) }, - { ORDATA (SR1, kg_unit[1].SR, 16) }, - { ORDATA (SR2, kg_unit[2].SR, 16) }, - { ORDATA (SR3, kg_unit[3].SR, 16) }, - { ORDATA (SR4, kg_unit[4].SR, 16) }, - { ORDATA (SR5, kg_unit[5].SR, 16) }, - { ORDATA (SR6, kg_unit[6].SR, 16) }, - { ORDATA (SR7, kg_unit[7].SR, 16) }, - { ORDATA (BCC0, kg_unit[0].BCC, 16) }, - { ORDATA (BCC1, kg_unit[1].BCC, 16) }, - { ORDATA (BCC2, kg_unit[2].BCC, 16) }, - { ORDATA (BCC3, kg_unit[3].BCC, 16) }, - { ORDATA (BCC4, kg_unit[4].BCC, 16) }, - { ORDATA (BCC5, kg_unit[5].BCC, 16) }, - { ORDATA (BCC6, kg_unit[6].BCC, 16) }, - { ORDATA (BCC7, kg_unit[7].BCC, 16) }, - { ORDATA (DR0, kg_unit[0].DR, 16) }, - { ORDATA (DR1, kg_unit[1].DR, 16) }, - { ORDATA (DR2, kg_unit[2].DR, 16) }, - { ORDATA (DR3, kg_unit[3].DR, 16) }, - { ORDATA (DR4, kg_unit[4].DR, 16) }, - { ORDATA (DR5, kg_unit[5].DR, 16) }, - { ORDATA (DR6, kg_unit[6].DR, 16) }, - { ORDATA (DR7, kg_unit[7].DR, 16) }, - { ORDATA (PULSCNT0, kg_unit[0].PULSCNT, 16) }, - { ORDATA (PULSCNT1, kg_unit[1].PULSCNT, 16) }, - { ORDATA (PULSCNT2, kg_unit[2].PULSCNT, 16) }, - { ORDATA (PULSCNT3, kg_unit[3].PULSCNT, 16) }, - { ORDATA (PULSCNT4, kg_unit[4].PULSCNT, 16) }, - { ORDATA (PULSCNT5, kg_unit[5].PULSCNT, 16) }, - { ORDATA (PULSCNT6, kg_unit[6].PULSCNT, 16) }, - { ORDATA (PULSCNT7, kg_unit[7].PULSCNT, 16) }, - { ORDATA (DEVADDR, kg_dib.ba, 32), REG_HRO }, - { NULL } -}; - -static const MTAB kg_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, NULL, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "UNITS=0..8", &set_units, NULL, NULL }, - { 0 } -}; - -#define DBG_REG (01) -#define DBG_POLY (02) -#define DBG_CYCLE (04) - -static const DEBTAB kg_debug[] = { - {"REG", DBG_REG}, - {"POLY", DBG_POLY}, - {"CYCLE", DBG_CYCLE}, - {0}, -}; - -DEVICE kg_dev = { - "KG", (UNIT *) &kg_unit, (REG *) kg_reg, (MTAB *) kg_mod, - KG_UNITS, 8, 16, 2, 8, 16, - NULL, /* examine */ - NULL, /* deposit */ - &kg_reset, /* reset */ - NULL, /* boot */ - NULL, /* attach */ - NULL, /* detach */ - &kg_dib, - DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG, - 0, /* debug control */ - (DEBTAB *) &kg_debug, /* debug flags */ - NULL, /* memory size chage */ - NULL /* logical name */ -}; - /* KG I/O address routines */ - -static t_stat kg_rd (int32 *data, int32 PA, int32 access) -{ - int unit = (PA >> 3) & 07; - - if ((unit >= KG_UNITS) || (kg_unit[unit].flags & UNIT_DIS)) - return (SCPE_NXM); - switch ((PA >> 1) & 03) { - - case 00: /* SR */ - if (DEBUG_PRI(kg_dev, DBG_REG)) - fprintf (sim_deb, ">>KG%d: rd SR %06o, PC %06o\n", - unit, kg_unit[unit].SR, PC); - *data = kg_unit[unit].SR & KG_SR_RDMASK; - break; - - case 01: /* BCC */ - if (DEBUG_PRI(kg_dev, DBG_REG)) - fprintf (sim_deb, ">>KG%d rd BCC %06o, PC %06o\n", - unit, kg_unit[unit].BCC, PC); - *data = kg_unit[unit].BCC & DMASK; - break; - - case 02: /* DR */ - break; - - default: - break; - } - return (SCPE_OK); -} - -static t_stat kg_wr (int32 data, int32 PA, int32 access) -{ - int setup; - int unit = (PA >> 3) & 07; - - if ((unit >= KG_UNITS) || (kg_unit[unit].flags & UNIT_DIS)) - return (SCPE_NXM); - switch ((PA >> 1) & 03) { - - case 00: /* SR */ - if (access == WRITEB) - data = (PA & 1) ? - (kg_unit[unit].SR & 0377) | (data << 8) : - (kg_unit[unit].SR & ~0377) | data; - if (DEBUG_PRI(kg_dev, DBG_REG)) - fprintf (sim_deb, ">>KG%d: wr SR %06o, PC %06o\n", - unit, data, PC); - if (data & KGSR_M_CLR) { - kg_unit[unit].PULSCNT = 0; /* not sure about this */ - kg_unit[unit].BCC = 0; - kg_unit[unit].SR |= KGSR_M_DONE; - } - setup = (kg_unit[unit].SR & 017) ^ (data & 017); - kg_unit[unit].SR = (kg_unit[unit].SR & ~KG_SR_WRMASK) | - (data & KG_SR_WRMASK); - /* if low 4b changed, reset C1 & C2 */ - if (setup) { - kg_unit[unit].PULSCNT = 0; - if (DEBUG_PRI(kg_dev, DBG_POLY)) - fprintf (sim_deb, ">>KG%d poly %s %d\n", - unit, config[data & 017].name, config[data & 017].pulses); - } - if (data & KGSR_M_SEN) - break; - if (data & KGSR_M_STEP) { - do_poly (unit, TRUE); - break; - } - break; - - case 01: /* BCC */ - break; /* ignored */ - - case 02: /* DR */ - if (access == WRITEB) - data = (PA & 1) ? - (kg_unit[unit].DR & 0377) | (data << 8) : - (kg_unit[unit].DR & ~0377) | data; - kg_unit[unit].DR = data & DMASK; - if (DEBUG_PRI(kg_dev, DBG_REG)) - fprintf (sim_deb, ">>KG%d: wr DR %06o, data %06o, PC %06o\n", - unit, kg_unit[unit].DR, data, PC); - kg_unit[unit].SR &= ~KGSR_M_DONE; - -/* In a typical device, this is normally where we would use sim_activate() - to initiate an I/O to be completed later. The KG is a little - different. When it was first introduced, it's computation operation - completed before another instruction could execute (on early PDP-11s), - and software often took "advantage" of this fact by not bothering - to check the status of the DONE bit. In reality, the execution - time of the polynomial is dependent upon the width of the poly; if - 8 bits 1us, if 16 bits, 2us. Since known existing software will - break if we actually defer the computation, it is performed immediately - instead. However this could easily be made into a run-time option, - if there were software to validate correct operation. */ - - if (kg_unit[unit].SR & KGSR_M_SEN) - do_poly (unit, FALSE); - break; - - default: - break; - } - return (SCPE_OK); -} - -/* KG reset */ - -static t_stat kg_reset (DEVICE *dptr) -{ - int i; - - if (DEBUG_PRI(kg_dev, DBG_REG)) - fprintf (sim_deb, ">>KG: reset PC %06o\n", PC); - for (i = 0; i < KG_UNITS; i++) { - kg_unit[i].SR = KGSR_M_DONE; - kg_unit[i].BCC = 0; - kg_unit[i].PULSCNT = 0; - } - return (SCPE_OK); -} - -static void cycleOneBit (int unit) -{ - int quo; - - if (DEBUG_PRI(kg_dev, DBG_CYCLE)) - fprintf (sim_deb, ">>KG%d: cycle s BCC %06o DR %06o\n", - unit, kg_unit[unit].BCC, kg_unit[unit].DR); - if (kg_unit[unit].SR & KGSR_M_DONE) - return; - if ((kg_unit[unit].SR & KG_SR_POLYMASK) == 0) - kg_unit[unit].BCC = (kg_unit[unit].BCC & 077) | - ((kg_unit[unit].BCC >> 2) & 07700); - kg_unit[unit].SR &= ~KGSR_M_QUO; - quo = (kg_unit[unit].BCC & 01) ^ (kg_unit[unit].DR & 01); - kg_unit[unit].BCC = (kg_unit[unit].BCC & ~01) | quo; - if (kg_unit[unit].SR & KGSR_M_LRC) - kg_unit[unit].BCC = (kg_unit[unit].SR & KGSR_M_16) ? - ROR(1, kg_unit[unit].BCC) : - RORB(1, kg_unit[unit].BCC); - else - kg_unit[unit].BCC = (kg_unit[unit].BCC & 01) ? - (kg_unit[unit].BCC >> 1) ^ config[kg_unit[unit].SR & 07].poly : - kg_unit[unit].BCC >> 1; - kg_unit[unit].DR >>= 1; - kg_unit[unit].SR |= quo << KGSR_V_QUO; - if ((kg_unit[unit].SR & KG_SR_POLYMASK) == 0) - kg_unit[unit].BCC = (kg_unit[unit].BCC & 077) | - ((kg_unit[unit].BCC & 07700) << 2); - kg_unit[unit].PULSCNT++; - if (kg_unit[unit].PULSCNT >= config[kg_unit[unit].SR & 017].pulses) - kg_unit[unit].SR |= KGSR_M_DONE; - if (DEBUG_PRI(kg_dev, DBG_CYCLE)) - fprintf (sim_deb, ">>KG%d: cycle e BCC %06o DR %06o\n", - unit, kg_unit[unit].BCC, kg_unit[unit].DR); -} - -static void do_poly (int unit, t_bool step) -{ - if (kg_unit[unit].SR & KGSR_M_DONE) - return; - if (step) - cycleOneBit (unit); - else { - while (!(kg_unit[unit].SR & KGSR_M_DONE)) - cycleOneBit (unit); - } -} - -static t_stat set_units (UNIT *u, int32 val, char *s, void *desc) -{ - uint32 i, units; - t_stat stat; - - if (s == NULL) - return (SCPE_ARG); - units = get_uint (s, 10, KG_UNITS, &stat); - if (stat != SCPE_OK) - return (stat); - if (units == 0) - return SCPE_ARG; - if (units == kg_dev.numunits) - return SCPE_OK; - for (i = 0; i < KG_UNITS; i++) { - if (i < units) - kg_unit[i].flags &= ~UNIT_DIS; - else - kg_unit[i].flags |= UNIT_DIS; - } - kg_dev.numunits = units; - kg_reset (&kg_dev); - return (SCPE_OK); -} diff --git a/PDP11/pdp11_lp.c b/PDP11/pdp11_lp.c deleted file mode 100644 index 750b0f17..00000000 --- a/PDP11/pdp11_lp.c +++ /dev/null @@ -1,198 +0,0 @@ -/* pdp11_lp.c: PDP-11 line printer simulator - - Copyright (c) 1993-2008, 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 LP11 line printer - - 19-Jan-07 RMS Added UNIT_TEXT flag - 07-Jul-05 RMS Removed extraneous externs - 19-May-03 RMS Revised for new conditional compilation scheme - 25-Apr-03 RMS Revised for extended file support - 29-Sep-02 RMS Added vector change/display support - New data structures - 30-May-02 RMS Widened POS to 32b - 06-Jan-02 RMS Added enable/disable support - 09-Nov-01 RMS Added VAX support - 07-Sep-01 RMS Revised interrupt mechanism - 30-Oct-00 RMS Standardized register naming -*/ - -#if defined (VM_PDP10) /* PDP10 version */ -#error "LP11 is not supported on the PDP-10!" - -#elif defined (VM_VAX) /* VAX version */ -#include "vax_defs.h" - -#else /* PDP-11 version */ -#include "pdp11_defs.h" -#endif - -#define LPTCSR_IMP (CSR_ERR + CSR_DONE + CSR_IE) /* implemented */ -#define LPTCSR_RW (CSR_IE) /* read/write */ - -extern int32 int_req[IPL_HLVL]; - -int32 lpt_csr = 0; /* control/status */ -int32 lpt_stopioe = 0; /* stop on error */ - -t_stat lpt_rd (int32 *data, int32 PA, int32 access); -t_stat lpt_wr (int32 data, int32 PA, int32 access); -t_stat lpt_svc (UNIT *uptr); -t_stat lpt_reset (DEVICE *dptr); -t_stat lpt_attach (UNIT *uptr, char *ptr); -t_stat lpt_detach (UNIT *uptr); - -/* LPT data structures - - lpt_dev LPT device descriptor - lpt_unit LPT unit descriptor - lpt_reg LPT register list -*/ - -DIB lpt_dib = { - IOBA_LPT, IOLN_LPT, &lpt_rd, &lpt_wr, - 1, IVCL (LPT), VEC_LPT, { NULL } - }; - -UNIT lpt_unit = { - UDATA (&lpt_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_TEXT, 0), SERIAL_OUT_WAIT - }; - -REG lpt_reg[] = { - { GRDATA (BUF, lpt_unit.buf, DEV_RDX, 8, 0) }, - { GRDATA (CSR, lpt_csr, DEV_RDX, 16, 0) }, - { FLDATA (INT, IREQ (LPT), INT_V_LPT) }, - { FLDATA (ERR, lpt_csr, CSR_V_ERR) }, - { FLDATA (DONE, lpt_csr, CSR_V_DONE) }, - { FLDATA (IE, lpt_csr, CSR_V_IE) }, - { DRDATA (POS, lpt_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, lpt_unit.wait, 24), PV_LEFT }, - { FLDATA (STOP_IOE, lpt_stopioe, 0) }, - { GRDATA (DEVADDR, lpt_dib.ba, DEV_RDX, 32, 0), REG_HRO }, - { GRDATA (DEVVEC, lpt_dib.vec, DEV_RDX, 16, 0), REG_HRO }, - { NULL } - }; - -MTAB lpt_mod[] = { - { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", - &set_vec, &show_vec, NULL }, - { 0 } - }; - -DEVICE lpt_dev = { - "LPT", &lpt_unit, lpt_reg, lpt_mod, - 1, 10, 31, 1, DEV_RDX, 8, - NULL, NULL, &lpt_reset, - NULL, &lpt_attach, &lpt_detach, - &lpt_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS - }; - -/* Line printer routines - - lpt_rd I/O page read - lpt_wr I/O page write - lpt_svc process event (printer ready) - lpt_reset process reset - lpt_attach process attach - lpt_detach process detach -*/ - -t_stat lpt_rd (int32 *data, int32 PA, int32 access) -{ -if ((PA & 02) == 0) /* csr */ - *data = lpt_csr & LPTCSR_IMP; -else *data = lpt_unit.buf; /* buffer */ -return SCPE_OK; -} - -t_stat lpt_wr (int32 data, int32 PA, int32 access) -{ -if ((PA & 02) == 0) { /* csr */ - if (PA & 1) - return SCPE_OK; - if ((data & CSR_IE) == 0) - CLR_INT (LPT); - else if ((lpt_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) - SET_INT (LPT); - lpt_csr = (lpt_csr & ~LPTCSR_RW) | (data & LPTCSR_RW); - } -else { /* buffer */ - if ((PA & 1) == 0) - lpt_unit.buf = data & 0177; - lpt_csr = lpt_csr & ~CSR_DONE; - CLR_INT (LPT); - if ((lpt_unit.buf == 015) || (lpt_unit.buf == 014) || - (lpt_unit.buf == 012)) sim_activate (&lpt_unit, lpt_unit.wait); - else sim_activate (&lpt_unit, 0); - } -return SCPE_OK; -} - -t_stat lpt_svc (UNIT *uptr) -{ -lpt_csr = lpt_csr | CSR_ERR | CSR_DONE; -if (lpt_csr & CSR_IE) - SET_INT (LPT); -if ((uptr->flags & UNIT_ATT) == 0) - return IORETURN (lpt_stopioe, SCPE_UNATT); -fputc (uptr->buf & 0177, uptr->fileref); -uptr->pos = ftell (uptr->fileref); -if (ferror (uptr->fileref)) { - perror ("LPT I/O error"); - clearerr (uptr->fileref); - return SCPE_IOERR; - } -lpt_csr = lpt_csr & ~CSR_ERR; -return SCPE_OK; -} - -t_stat lpt_reset (DEVICE *dptr) -{ -lpt_unit.buf = 0; -lpt_csr = CSR_DONE; -if ((lpt_unit.flags & UNIT_ATT) == 0) - lpt_csr = lpt_csr | CSR_ERR; -CLR_INT (LPT); -sim_cancel (&lpt_unit); /* deactivate unit */ -return SCPE_OK; -} - -t_stat lpt_attach (UNIT *uptr, char *cptr) -{ -t_stat reason; - -lpt_csr = lpt_csr & ~CSR_ERR; -reason = attach_unit (uptr, cptr); -if ((lpt_unit.flags & UNIT_ATT) == 0) - lpt_csr = lpt_csr | CSR_ERR; -return reason; -} - -t_stat lpt_detach (UNIT *uptr) -{ -lpt_csr = lpt_csr | CSR_ERR; -return detach_unit (uptr); -} diff --git a/PDP11/pdp11_mscp.h b/PDP11/pdp11_mscp.h deleted file mode 100644 index 224fdce0..00000000 --- a/PDP11/pdp11_mscp.h +++ /dev/null @@ -1,518 +0,0 @@ -/* pdp11_mscp.h: DEC MSCP and TMSCP definitionsn - - Copyright (c) 2001-2008, 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. - - 24-Oct-12 MB Added working map base address - 09-Jan-03 RMS Tape read/write end pkt is longer than disk read/write - 20-Sep-02 RMS Merged TMSCP definitions -*/ - -#ifndef PDP11_MSCP_H_ -#define PDP11_MSCP_H_ 0 - -/* Misc constants */ - -#define UID_DISK 2 /* disk class */ -#define UID_TAPE 3 /* tape class */ - -/* Opcodes */ - -#define OP_ABO 1 /* b: abort */ -#define OP_GCS 2 /* b: get command status */ -#define OP_GUS 3 /* b: get unit status */ -#define OP_SCC 4 /* b: set controller char */ -#define OP_AVL 8 /* b: available */ -#define OP_ONL 9 /* b: online */ -#define OP_SUC 10 /* b: set unit char */ -#define OP_DAP 11 /* b: det acc paths - nop */ -#define OP_ACC 16 /* b: access */ -#define OP_CCD 17 /* d: compare - nop */ -#define OP_ERS 18 /* b: erase */ -#define OP_FLU 19 /* d: flush - nop */ -#define OP_ERG 22 /* t: erase gap */ -#define OP_CMP 32 /* b: compare */ -#define OP_RD 33 /* b: read */ -#define OP_WR 34 /* b: write */ -#define OP_WTM 36 /* t: write tape mark */ -#define OP_POS 37 /* t: reposition */ -#define OP_FMT 47 /* d: format */ -#define OP_AVA 64 /* b: unit now avail */ -#define OP_END 0x80 /* b: end flag */ - -/* Modifiers */ - -#define MD_EXP 0x8000 /* d: express NI */ -#define MD_CMP 0x4000 /* b: compare NI */ -#define MD_CSE 0x2000 /* b: clr ser err */ -#define MD_ERR 0x1000 /* d: force error NI*/ -#define MD_CDL 0x1000 /* t: clr data lost NI*/ -#define MD_SCH 0x0800 /* t: supr cache NI */ -#define MD_SEC 0x0200 /* b: supr err corr NI */ -#define MD_SER 0x0100 /* b: supr err rec NI */ -#define MD_DLE 0x0080 /* t: detect LEOT */ -#define MD_IMM 0x0040 /* t: immediate NI */ -#define MD_EXA 0x0020 /* b: excl access NI */ -#define MD_SHD 0x0010 /* d: shadow NI */ -#define MD_UNL 0x0010 /* t avl: unload */ -#define MD_ERW 0x0008 /* t wr: enb rewrite */ -#define MD_REV 0x0008 /* t rd, pos: reverse */ -#define MD_SWP 0x0004 /* b suc: enb set wrp */ -#define MD_OBC 0x0004 /* t: pos: obj count */ -#define MD_IMF 0x0002 /* d onl: ign fmte NI */ -#define MD_RWD 0x0002 /* t pos: rewind */ -#define MD_ACL 0x0002 /* t avl: all class NI */ -#define MD_NXU 0x0001 /* b gus: next unit */ -#define MD_RIP 0x0001 /* d onl: allow rip NI */ -#define MD_SPD 0x0001 /* d avl: spin-down */ - -/* End flags */ - -#define EF_LOG 0x0020 /* b: error log */ -#define EF_SXC 0x0010 /* b: serious exc */ -#define EF_EOT 0x0008 /* end of tape */ -#define EF_PLS 0x0004 /* pos lost */ -#define EF_DLS 0x0002 /* cached data lost NI */ - -/* Controller flags */ - -#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 /* d: ctrl bad blk repl */ -#define UF_CAC 0x8000 /* t: cache write back */ -#define UF_WPH 0x2000 /* b: wr prot hwre */ -#define UF_WPS 0x1000 /* b: wr prot swre */ -#define UF_SCH 0x0800 /* t: supr cache NI */ -#define UF_EXA 0x0400 /* b: exclusive NI */ -#define UF_WPD 0x0100 /* b: wr prot data NI */ -#define UF_RMV 0x0080 /* d: removable */ -#define UF_WBN 0x0040 /* t: write back NI */ -#define UF_VSS 0x0020 /* t: supr var speed NI */ -#define UF_VSU 0x0010 /* t: var speed unit NI */ -#define UF_EWR 0x0008 /* t: enh wr recovery NI */ -#define UF_CMW 0x0002 /* cmp writes NI */ -#define UF_CMR 0x0001 /* cmp reads NI */ - -/* Error log flags */ - -#define LF_SUC 0x0080 /* b: successful */ -#define LF_CON 0x0040 /* b: continuing */ -#define LF_BBR 0x0020 /* d: bad blk repl NI */ -#define LF_RCT 0x0010 /* d: err in repl NI */ -#define LF_SNR 0x0001 /* b: seq # reset */ - -/* Error log formats */ - -#define FM_CNT 0 /* b: port lf err */ -#define FM_BAD 1 /* b: bad host addr */ -#define FM_DSK 2 /* d: disk xfer */ -#define FM_SDI 3 /* d: SDI err */ -#define FM_SDE 4 /* d: sm disk err */ -#define FM_TAP 5 /* t: tape errors */ -#define FM_RPL 9 /* d: bad blk repl */ - -/* Status codes */ - -#define ST_SUC 0 /* b: successful */ -#define ST_CMD 1 /* b: invalid cmd */ -#define ST_ABO 2 /* b: aborted cmd */ -#define ST_OFL 3 /* b: unit offline */ -#define ST_AVL 4 /* b: unit avail */ -#define ST_MFE 5 /* b: media fmt err */ -#define ST_WPR 6 /* b: write prot err */ -#define ST_CMP 7 /* b: compare err */ -#define ST_DAT 8 /* b: data err */ -#define ST_HST 9 /* b: host acc err */ -#define ST_CNT 10 /* b: ctrl err */ -#define ST_DRV 11 /* b: drive err */ -#define ST_FMT 12 /* t: formatter err */ -#define ST_BOT 13 /* t: BOT encountered */ -#define ST_TMK 14 /* t: tape mark */ -#define ST_RDT 16 /* t: record trunc */ -#define ST_POL 17 /* t: pos lost */ -#define ST_SXC 18 /* b: serious exc */ -#define ST_LED 19 /* t: LEOT detect */ -#define ST_BBR 20 /* d: bad block */ -#define ST_DIA 31 /* b: diagnostic */ -#define ST_V_SUB 5 /* subcode */ -#define ST_V_INV 8 /* invalid op */ - -/* Status subcodes */ - -#define SB_SUC_IGN (1 << ST_V_SUB) /* t: unload ignored */ -#define SB_SUC_ON (8 << ST_V_SUB) /* b: already online */ -#define SB_SUC_EOT (32 << ST_V_SUB) /* t: EOT encountered */ -#define SB_SUC_RO (128 << ST_V_SUB) /* t: read only */ -#define SB_OFL_NV (1 << ST_V_SUB) /* b: no volume */ -#define SB_OFL_INOP (2 << ST_V_SUB) /* t: inoperative */ -#define SB_AVL_INU (32 << ST_V_SUB) /* b: in use */ -#define SB_WPR_SW (128 << ST_V_SUB) /* b: swre wlk */ -#define SB_WPR_HW (256 << ST_V_SUB) /* b: hwre wlk */ -#define SB_HST_OA (1 << ST_V_SUB) /* b: odd addr */ -#define SB_HST_OC (2 << ST_V_SUB) /* d: odd count */ -#define SB_HST_NXM (3 << ST_V_SUB) /* b: nx memory */ -#define SB_HST_PAR (4 << ST_V_SUB) /* b: parity err */ -#define SB_HST_PTE (5 << ST_V_SUB) /* b: mapping err */ -#define SB_DAT_RDE (7 << ST_V_SUB) /* t: read err */ - -/* Status invalid command subcodes */ - -#define I_OPCD (8 << ST_V_INV) /* inv opcode */ -#define I_FLAG (9 << ST_V_INV) /* inv flags */ -#define I_MODF (10 << ST_V_INV) /* inv modifier */ -#define I_BCNT (12 << ST_V_INV) /* inv byte cnt */ -#define I_LBN (28 << ST_V_INV) /* inv LBN */ -#define I_VRSN (12 << ST_V_INV) /* inv version */ -#define I_FMTI (28 << ST_V_INV) /* inv format */ - -/* Tape format flags */ - -#define TF_9TK 0x0100 /* 9 track */ -#define TF_9TK_NRZ 0x0001 /* 800 bpi */ -#define TF_9TK_PE 0x0002 /* 1600 bpi */ -#define TF_9TK_GRP 0x0004 /* 6250 bpi */ -#define TF_CTP 0x0200 /* TK50 */ -#define TF_CTP_LO 0x0001 /* low density */ -#define TF_CTP_HI 0x0002 /* hi density */ -#define TF_3480 0x0300 /* 3480 */ -#define TF_WOD 0x0400 /* RV80 */ - -/* Packet formats - note that all packet lengths must be multiples of 4 bytes */ - -/* Command packet header */ - -#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 -#define CMD_OPC_V_FLG 8 /* flags */ -#define CMD_OPC_M_FLG 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 - -/* Erase packet - min size */ - -#define ERS_LNT 12 - -/* Erase gap - min size */ - -#define ERG_LNT 12 - -/* Flush - 10 W status (8 undefined) */ - -#define FLU_LNT 32 -/* 8 - 15 *//* reserved */ -#define FLU_POSL 16 /* position */ -#define FLU_POSH 17 - -/* Write tape mark - 10W status (8 undefined) */ - -#define WTM_LNT 32 -/* 8 - 15 *//* reserved */ -#define WTM_POSL 16 /* position */ -#define WTM_POSH 17 - -/* Get command status packet - 2 W parameter, 4 W 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 (disk), 16W status (tape) */ - -#define GUS_LNT_D 48 -#define GUS_LNT_T 44 -#define GUS_MLUN 8 /* mlun */ -#define GUS_UFL 9 /* flags */ -#define GUS_RSVL 10 /* reserved */ -#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_UVER 23 /* unit version */ - -/* Disk specific status */ - -#define GUS_SHUN 18 /* shadowing */ -#define GUS_SHST 19 -#define GUS_TRK 20 /* track */ -#define GUS_GRP 21 /* group */ -#define GUS_CYL 22 /* cylinder */ -#define GUS_RCTS 24 /* RCT size */ -#define GUS_RBSC 25 /* RBNs, copies */ - -/* Tape specific status */ - -#define GUS_FMT 18 /* format */ -#define GUS_SPEED 19 /* speed */ -#define GUS_MENU 20 /* menu */ -#define GUS_CAP 21 /* capacity */ -#define GUS_FVER 22 /* fmtr version */ - -#define GUS_UIDD_V_MOD 0 /* unit model */ -#define GUS_UIDD_V_CLS 8 /* unit class */ -#define GUS_RB_V_RBNS 0 /* RBNs/track */ -#define GUS_RB_V_RCTC 8 /* RCT copies */ - -/* Unit online - 2 W parameter, 16 W status (disk or tape) */ - -#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 - -/* Disk specific status */ - -#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 - -/* Tape specific status */ - -#define ONL_FMT 18 /* format */ -#define ONL_SPD 19 /* speed */ -#define ONL_MAXL 20 /* max rec size */ -#define ONL_MAXH 21 -#define ONL_NREC 22 /* noise rec */ -#define ONL_RSVE 23 /* reserved */ - -#define ONL_UIDD_V_MOD 0 /* unit model */ -#define ONL_UIDD_V_CLS 8 /* unit class */ - -/* 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 - -/* Reposition - 4 W parameters, 10 W status */ - -#define POS_LNT 32 -#define POS_RCL 8 /* record cnt */ -#define POS_RCH 9 -#define POS_TMCL 10 /* tape mk cnt */ -#define POS_TMCH 11 -/* reserved 12 - 15 */ -#define POS_POSL 16 /* position */ -#define POS_POSH 17 - -/* Data transfer packet - 10 W parameters (disk), 6W parameters (tape), - 10 W status (disk), 12W status (tape) */ - -#define RW_LNT_D 32 -#define RW_LNT_T 36 -#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 */ - -/* Disk specific parameters */ - -#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 -#define RW_WMPL 24 /* working map */ -#define RW_WMPH 25 - -/* Tape specific status */ - -#define RW_POSL 16 /* position */ -#define RW_POSH 17 -#define RW_RSZL 18 /* record size */ -#define RW_RSZH 19 - -/* Error log packet header */ - -#define ELP_REFL 2 /* ref # */ -#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_D2 23 -#define DTE_D3 24 -#define DTE_D4 25 - -/* Disk specific status */ - -#define DTE_SCYL 19 /* cylinder */ -#define DTE_VSNL 20 /* vol ser # */ -#define DTE_VSNH 21 -#define DTE_D1 22 /* dev params */ - -/* Tape specific status */ - -#define DTE_RETR 19 /* retry */ -#define DTE_POSL 20 /* position */ -#define DTE_POSH 21 -#define DTE_FVER 22 /* formatter ver */ - -#define DTE_CIDD_V_MOD 0 /* ctrl model */ -#define DTE_CIDD_V_CLS 8 /* ctrl class */ -#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 - -#endif diff --git a/PDP11/pdp11_pclk.c b/PDP11/pdp11_pclk.c deleted file mode 100644 index d8fc48ed..00000000 --- a/PDP11/pdp11_pclk.c +++ /dev/null @@ -1,317 +0,0 @@ -/* pdp11_pclk.c: KW11P programmable clock simulator - - Copyright (c) 1993-2008, Robert M Supnik - Written by John Dundas, used with his gracious permission - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - pclk KW11P line frequency clock - - 20-May-08 RMS Standardized clock delay at 1mips - 18-Jun-07 RMS Added UNIT_IDLE flag - 07-Jul-05 RMS Removed extraneous externs - - KW11-P Programmable Clock - - I/O Page Registers: - - CSR 17 772 540 - CSB 17 772 542 - CNT 17 772 544 - - Vector: 0104 - - Priority: BR6 - - ** Theory of Operation ** - - A real KW11-P is built around the following major components: - - 16-bit up/down counter - - 16-bit count set buffer - - 9-bit control and status register - - clocks: crystal controlled (1) 100 kHz and (2) 10 kHz clocks, - (3) a 50/60 Hz line frequency clock, and (4) an analog signal - input trigger - This software emulator for SIMH implements all of the above with - the exception of the external input trigger, which is arbitrarily - wired to 10Hz. - - Operation of this emulator is rather simplistic as compared to the - actual device. The register read and write routines are responsible - for copying internal state from the simulated device to the operating - program. Clock state variables are altered in the write routine - as well as the desired clock ticking rate. Possible rates are - given in the table below. - - Rate Bit 2 Bit 1 - 100 kHz 0 0 - 10 kHz 0 1 - Line frequency 1 0 - External 1 1 - - I think SIMH would have a hard time actually keeping up with a 100 - kHz ticking rate. I haven't tried this to verify, though. - - The clock service routine (pclk_svc) is responsible for ticking - the clock. The routine does implement up/down, repeat vs. - single-interrupt, and single clocking (maintenance). The routine - updates the internal state according to the options selected and - signals interrupts when appropriate. - - For a complete description of the device, please see DEC-11-HPWB-D - KW11-P Programmable Real-Time Clock Manual. - - ** Notes ** - - 1. The device is disabled by default. - - 2. Use XXDP V2.5 test program ZKWBJ1.BIC; loads at 1000, starts at - 1100? Seems to execute the first few tests correctly then waits - for input from the console. I don't have a description of how this - diagnostic works and thus don't know how to proceed from that point. - - 3. The read and write routines don't do anything with odd address - accesses. The manual says that byte writes don't work. - - 4. RSTS can use this clock in place of the standard KW11-L line - frequency clock. In order to do this, use the DEFAULT response in - the OPTION: dialog. To the Preferred clock prompt answer "P". - Then you have the option of line frequency "L" or some multiple of - 50 between 50 and 1000 to use the programmable portion of the clock. - - 5. This is really a Unibus peripheral and thus doesn't actually make - sense within a J-11 system as there never was a Qbus version of - this to the best of my knowledge. However the OSs I have tried - don't appear to exhibit any dissonance between this option and the - processor/bus emulation. I think the options that would make - somewhat more sense in a Qbus environment the KWV11-C and/or KWV11-S. - I don't know if any of the -11 OSs contained support for using - these as the system clock, though. -*/ - -#include "pdp11_defs.h" - -#define PCLKCSR_RDMASK 0100377 /* readable */ -#define PCLKCSR_WRMASK 0000137 /* writeable */ - -#define UNIT_V_LINE50HZ (UNIT_V_UF + 0) -#define UNIT_LINE50HZ (1 << UNIT_V_LINE50HZ) - -/* CSR - 17772540 */ - -#define CSR_V_FIX 5 /* single tick */ -#define CSR_V_UPDN 4 /* down/up */ -#define CSR_V_MODE 3 /* single/repeat */ -#define CSR_FIX (1u << CSR_V_FIX) -#define CSR_UPDN (1u << CSR_V_UPDN) -#define CSR_MODE (1u << CSR_V_MODE) -#define CSR_V_RATE 1 /* rate */ -#define CSR_M_RATE 03 -#define CSR_GETRATE(x) (((x) >> CSR_V_RATE) & CSR_M_RATE) - -extern int32 int_req[IPL_HLVL]; - -uint32 pclk_csr = 0; /* control/status */ -uint32 pclk_csb = 0; /* count set buffer */ -uint32 pclk_ctr = 0; /* counter */ -static uint32 rate[4] = { 100000, 10000, 60, 10 }; /* ticks per second */ -static uint32 xtim[4] = { 10, 100, 16667, 100000 }; /* nominal time delay */ - -t_stat pclk_rd (int32 *data, int32 PA, int32 access); -t_stat pclk_wr (int32 data, int32 PA, int32 access); -t_stat pclk_svc (UNIT *uptr); -t_stat pclk_reset (DEVICE *dptr); -t_stat pclk_set_line (UNIT *uptr, int32 val, char *cptr, void *desc); -void pclk_tick (void); - -/* PCLK data structures - - pclk_dev PCLK device descriptor - pclk_unit PCLK unit descriptor - pclk_reg PCLK register list -*/ - -DIB pclk_dib = { - IOBA_PCLK, IOLN_PCLK, &pclk_rd, &pclk_wr, - 1, IVCL (PCLK), VEC_PCLK, { NULL } - }; - -UNIT pclk_unit = { UDATA (&pclk_svc, UNIT_IDLE, 0) }; - -REG pclk_reg[] = { - { ORDATA (CSR, pclk_csr, 16) }, - { ORDATA (CSB, pclk_csb, 16) }, - { ORDATA (CNT, pclk_ctr, 16) }, - { FLDATA (INT, IREQ (PCLK), INT_V_PCLK) }, - { FLDATA (OVFL, pclk_csr, CSR_V_ERR) }, - { FLDATA (DONE, pclk_csr, CSR_V_DONE) }, - { FLDATA (IE, pclk_csr, CSR_V_IE) }, - { FLDATA (UPDN, pclk_csr, CSR_V_UPDN) }, - { FLDATA (MODE, pclk_csr, CSR_V_MODE) }, - { FLDATA (RUN, pclk_csr, CSR_V_GO) }, - { BRDATA (TIME, xtim, 10, 32, 4), REG_NZ + PV_LEFT }, - { BRDATA (TPS, rate, 10, 32, 4), REG_NZ + PV_LEFT }, - { DRDATA (CURTIM, pclk_unit.wait, 32), REG_HRO }, - { ORDATA (DEVADDR, pclk_dib.ba, 32), REG_HRO }, - { ORDATA (DEVVEC, pclk_dib.vec, 16), REG_HRO }, - { NULL } - }; - -MTAB pclk_mod[] = { - { UNIT_LINE50HZ, UNIT_LINE50HZ, "50 Hz", "50HZ", &pclk_set_line }, - { UNIT_LINE50HZ, 0, "60 Hz", "60HZ", &pclk_set_line }, - { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, - NULL, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", - &set_vec, &show_vec, NULL }, - { 0 } - }; - -DEVICE pclk_dev = { - "PCLK", &pclk_unit, pclk_reg, pclk_mod, - 1, 0, 0, 0, 0, 0, - NULL, NULL, &pclk_reset, - NULL, NULL, NULL, - &pclk_dib, DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS - }; - -/* Clock I/O address routines */ - -t_stat pclk_rd (int32 *data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 03) { - - case 00: /* CSR */ - *data = pclk_csr & PCLKCSR_RDMASK; /* return CSR */ - pclk_csr = pclk_csr & ~(CSR_ERR | CSR_DONE); /* clr err, done */ - CLR_INT (PCLK); /* clr intr */ - break; - - case 01: /* buffer */ - *data = 0; /* read only */ - break; - - case 02: /* counter */ - *data = pclk_ctr & DMASK; /* return counter */ - break; - } - -return SCPE_OK; -} - -t_stat pclk_wr (int32 data, int32 PA, int32 access) -{ -int32 old_csr = pclk_csr; -int32 rv; - -switch ((PA >> 1) & 03) { - - case 00: /* CSR */ - pclk_csr = data & PCLKCSR_WRMASK; /* clear and write */ - CLR_INT (PCLK); /* clr intr */ - rv = CSR_GETRATE (pclk_csr); /* new rate */ - pclk_unit.wait = xtim[rv]; /* new delay */ - if ((pclk_csr & CSR_GO) == 0) { /* stopped? */ - sim_cancel (&pclk_unit); /* cancel */ - if (data & CSR_FIX) /* fix? tick */ - pclk_tick (); - } - else if (((old_csr & CSR_GO) == 0) || /* run 0 -> 1? */ - (rv != CSR_GETRATE (old_csr))) { /* rate change? */ - sim_cancel (&pclk_unit); /* cancel */ - sim_activate (&pclk_unit, /* start clock */ - sim_rtcn_init (pclk_unit.wait, TMR_PCLK)); - } - break; - - case 01: /* buffer */ - pclk_csb = pclk_ctr = data; /* store ctr */ - pclk_csr = pclk_csr & ~(CSR_ERR | CSR_DONE); /* clr err, done */ - CLR_INT (PCLK); /* clr intr */ - break; - - case 02: /* counter */ - break; /* read only */ - } - -return SCPE_OK; -} - -/* Clock tick (automatic or manual) */ - -void pclk_tick (void) -{ -if (pclk_csr & CSR_UPDN) /* up or down? */ - pclk_ctr = (pclk_ctr + 1) & DMASK; /* 1 = up */ -else pclk_ctr = (pclk_ctr - 1) & DMASK; /* 0 = down */ -if (pclk_ctr == 0) { /* reached zero? */ - if (pclk_csr & CSR_DONE) /* done already set? */ - pclk_csr = pclk_csr | CSR_ERR; /* set error */ - else pclk_csr = pclk_csr | CSR_DONE; /* else set done */ - if (pclk_csr & CSR_IE) /* if IE, set int */ - SET_INT (PCLK); - if (pclk_csr & CSR_MODE) /* if rpt, reload */ - pclk_ctr = pclk_csb; - else { - pclk_csb = 0; /* else clr ctr */ - pclk_csr = pclk_csr & ~CSR_GO; /* and clr go */ - } - } -return; -} - -/* Clock service */ - -t_stat pclk_svc (UNIT *uptr) -{ -int32 rv; - -pclk_tick (); /* tick clock */ -if ((pclk_csr & CSR_GO) == 0) /* done? */ - return SCPE_OK; -rv = CSR_GETRATE (pclk_csr); /* get rate */ -sim_activate (&pclk_unit, sim_rtcn_calb (rate[rv], TMR_PCLK)); -return SCPE_OK; -} - -/* Clock reset */ - -t_stat pclk_reset (DEVICE *dptr) -{ -pclk_csr = 0; /* clear reg */ -pclk_csb = 0; -pclk_ctr = 0; -CLR_INT (PCLK); /* clear int */ -sim_cancel (&pclk_unit); /* cancel */ -pclk_unit.wait = xtim[0]; /* reset delay */ -return SCPE_OK; -} - -/* Set line frequency */ - -t_stat pclk_set_line (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (val == UNIT_LINE50HZ) - rate[2] = 50; -else rate[2] = 60; -return SCPE_OK; -} diff --git a/PDP11/pdp11_pt.c b/PDP11/pdp11_pt.c deleted file mode 100644 index 803c0a45..00000000 --- a/PDP11/pdp11_pt.c +++ /dev/null @@ -1,367 +0,0 @@ -/* pdp11_pt.c: PC11 paper tape reader/punch simulator - - Copyright (c) 1993-2008, Robert M Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - ptr paper tape reader - ptp paper tape punch - - 07-Jul-05 RMS Removed extraneous externs - 19-May-03 RMS Revised for new conditional compilation scheme - 25-Apr-03 RMS Revised for extended file support - 12-Sep-02 RMS Split off from pdp11_stddev.c -*/ - -#if defined (VM_PDP10) /* PDP10 version */ -#include "pdp10_defs.h" -#define PT_DIS DEV_DIS -extern int32 int_req; - -#elif defined (VM_VAX) /* VAX version */ -#include "vax_defs.h" -#define PT_DIS DEV_DIS -extern int32 int_req[IPL_HLVL]; - -#else /* PDP-11 version */ -#include "pdp11_defs.h" -#define PT_DIS 0 -extern int32 int_req[IPL_HLVL]; -#endif - -#define PTRCSR_IMP (CSR_ERR+CSR_BUSY+CSR_DONE+CSR_IE) /* paper tape reader */ -#define PTRCSR_RW (CSR_IE) -#define PTPCSR_IMP (CSR_ERR + CSR_DONE + CSR_IE) /* paper tape punch */ -#define PTPCSR_RW (CSR_IE) - -int32 ptr_csr = 0; /* control/status */ -int32 ptr_stopioe = 0; /* stop on error */ -int32 ptp_csr = 0; /* control/status */ -int32 ptp_stopioe = 0; /* stop on error */ - -t_stat ptr_rd (int32 *data, int32 PA, int32 access); -t_stat ptr_wr (int32 data, int32 PA, int32 access); -t_stat ptr_svc (UNIT *uptr); -t_stat ptr_reset (DEVICE *dptr); -t_stat ptr_attach (UNIT *uptr, char *ptr); -t_stat ptr_detach (UNIT *uptr); -t_stat ptp_rd (int32 *data, int32 PA, int32 access); -t_stat ptp_wr (int32 data, int32 PA, int32 access); -t_stat ptp_svc (UNIT *uptr); -t_stat ptp_reset (DEVICE *dptr); -t_stat ptp_attach (UNIT *uptr, char *ptr); -t_stat ptp_detach (UNIT *uptr); - -/* PTR data structures - - ptr_dev PTR device descriptor - ptr_unit PTR unit descriptor - ptr_reg PTR register list -*/ - -DIB ptr_dib = { - IOBA_PTR, IOLN_PTR, &ptr_rd, &ptr_wr, - 1, IVCL (PTR), VEC_PTR, { NULL } - }; - -UNIT ptr_unit = { - UDATA (&ptr_svc, UNIT_SEQ+UNIT_ATTABLE+UNIT_ROABLE, 0), - SERIAL_IN_WAIT - }; - -REG ptr_reg[] = { - { GRDATA (BUF, ptr_unit.buf, DEV_RDX, 8, 0) }, - { GRDATA (CSR, ptr_csr, DEV_RDX, 16, 0) }, - { FLDATA (INT, int_req, INT_V_PTR) }, - { FLDATA (ERR, ptr_csr, CSR_V_ERR) }, - { FLDATA (BUSY, ptr_csr, CSR_V_BUSY) }, - { FLDATA (DONE, ptr_csr, CSR_V_DONE) }, - { FLDATA (IE, ptr_csr, CSR_V_IE) }, - { DRDATA (POS, ptr_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, ptr_unit.wait, 24), PV_LEFT }, - { FLDATA (STOP_IOE, ptr_stopioe, 0) }, - { GRDATA (DEVADDR, ptr_dib.ba, DEV_RDX, 32, 0), REG_HRO }, - { GRDATA (DEVVEC, ptr_dib.vec, DEV_RDX, 16, 0), REG_HRO }, - { NULL } - }; - -MTAB ptr_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, - NULL, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, - NULL, &show_vec, NULL }, - { 0 } - }; - -DEVICE ptr_dev = { - "PTR", &ptr_unit, ptr_reg, ptr_mod, - 1, 10, 31, 1, DEV_RDX, 8, - NULL, NULL, &ptr_reset, - NULL, &ptr_attach, &ptr_detach, - &ptr_dib, DEV_DISABLE | PT_DIS | DEV_UBUS | DEV_QBUS - }; - -/* PTP data structures - - ptp_dev PTP device descriptor - ptp_unit PTP unit descriptor - ptp_reg PTP register list -*/ - -DIB ptp_dib = { - IOBA_PTP, IOLN_PTP, &ptp_rd, &ptp_wr, - 1, IVCL (PTP), VEC_PTP, { NULL } - }; - -UNIT ptp_unit = { - UDATA (&ptp_svc, UNIT_SEQ+UNIT_ATTABLE, 0), SERIAL_OUT_WAIT - }; - -REG ptp_reg[] = { - { GRDATA (BUF, ptp_unit.buf, DEV_RDX, 8, 0) }, - { GRDATA (CSR, ptp_csr, DEV_RDX, 16, 0) }, - { FLDATA (INT, int_req, INT_V_PTP) }, - { FLDATA (ERR, ptp_csr, CSR_V_ERR) }, - { FLDATA (DONE, ptp_csr, CSR_V_DONE) }, - { FLDATA (IE, ptp_csr, CSR_V_IE) }, - { DRDATA (POS, ptp_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, ptp_unit.wait, 24), PV_LEFT }, - { FLDATA (STOP_IOE, ptp_stopioe, 0) }, - { GRDATA (DEVADDR, ptp_dib.ba, DEV_RDX, 32, 0), REG_HRO }, - { GRDATA (DEVVEC, ptp_dib.vec, DEV_RDX, 16, 0), REG_HRO }, - { NULL } - }; - -MTAB ptp_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, - NULL, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, - NULL, &show_vec, NULL }, - { 0 } - }; - -DEVICE ptp_dev = { - "PTP", &ptp_unit, ptp_reg, ptp_mod, - 1, 10, 31, 1, DEV_RDX, 8, - NULL, NULL, &ptp_reset, - NULL, &ptp_attach, &ptp_detach, - &ptp_dib, DEV_DISABLE | PT_DIS | DEV_UBUS | DEV_QBUS - }; - -/* Paper tape reader I/O address routines */ - -t_stat ptr_rd (int32 *data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 01) { /* decode PA<1> */ - - case 0: /* ptr csr */ - *data = ptr_csr & PTRCSR_IMP; - return SCPE_OK; - - case 1: /* ptr buf */ - ptr_csr = ptr_csr & ~CSR_DONE; - CLR_INT (PTR); - *data = ptr_unit.buf & 0377; - return SCPE_OK; - } - -return SCPE_NXM; /* can't get here */ -} - -t_stat ptr_wr (int32 data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 01) { /* decode PA<1> */ - - case 0: /* ptr csr */ - if (PA & 1) - return SCPE_OK; - if ((data & CSR_IE) == 0) - CLR_INT (PTR); - else if (((ptr_csr & CSR_IE) == 0) && (ptr_csr & (CSR_ERR | CSR_DONE))) - SET_INT (PTR); - if (data & CSR_GO) { - ptr_csr = (ptr_csr & ~CSR_DONE) | CSR_BUSY; - CLR_INT (PTR); - if (ptr_unit.flags & UNIT_ATT) /* data to read? */ - sim_activate (&ptr_unit, ptr_unit.wait); - else sim_activate (&ptr_unit, 0); /* error if not */ - } - ptr_csr = (ptr_csr & ~PTRCSR_RW) | (data & PTRCSR_RW); - return SCPE_OK; - - case 1: /* ptr buf */ - return SCPE_OK; - } /* end switch PA */ - -return SCPE_NXM; /* can't get here */ -} - -/* Paper tape reader service */ - -t_stat ptr_svc (UNIT *uptr) -{ -int32 temp; - -ptr_csr = (ptr_csr | CSR_ERR) & ~CSR_BUSY; -if (ptr_csr & CSR_IE) SET_INT (PTR); -if ((ptr_unit.flags & UNIT_ATT) == 0) - return IORETURN (ptr_stopioe, SCPE_UNATT); -if ((temp = getc (ptr_unit.fileref)) == EOF) { - if (feof (ptr_unit.fileref)) { - if (ptr_stopioe) - sim_printf ("PTR end of file\n"); - else return SCPE_OK; - } - else perror ("PTR I/O error"); - clearerr (ptr_unit.fileref); - return SCPE_IOERR; - } -ptr_csr = (ptr_csr | CSR_DONE) & ~CSR_ERR; -ptr_unit.buf = temp & 0377; -ptr_unit.pos = ptr_unit.pos + 1; -return SCPE_OK; -} - -/* Paper tape reader support routines */ - -t_stat ptr_reset (DEVICE *dptr) -{ -ptr_unit.buf = 0; -ptr_csr = 0; -if ((ptr_unit.flags & UNIT_ATT) == 0) - ptr_csr = ptr_csr | CSR_ERR; -CLR_INT (PTR); -sim_cancel (&ptr_unit); -return SCPE_OK; -} - -t_stat ptr_attach (UNIT *uptr, char *cptr) -{ -t_stat reason; - -reason = attach_unit (uptr, cptr); -if ((ptr_unit.flags & UNIT_ATT) == 0) - ptr_csr = ptr_csr | CSR_ERR; -else ptr_csr = ptr_csr & ~CSR_ERR; -return reason; -} - -t_stat ptr_detach (UNIT *uptr) -{ -ptr_csr = ptr_csr | CSR_ERR; -return detach_unit (uptr); -} - -/* Paper tape punch I/O address routines */ - -t_stat ptp_rd (int32 *data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 01) { /* decode PA<1> */ - - case 0: /* ptp csr */ - *data = ptp_csr & PTPCSR_IMP; - return SCPE_OK; - - case 1: /* ptp buf */ - *data = ptp_unit.buf; - return SCPE_OK; - } - -return SCPE_NXM; /* can't get here */ -} - -t_stat ptp_wr (int32 data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 01) { /* decode PA<1> */ - - case 0: /* ptp csr */ - if (PA & 1) - return SCPE_OK; - if ((data & CSR_IE) == 0) - CLR_INT (PTP); - else if (((ptp_csr & CSR_IE) == 0) && (ptp_csr & (CSR_ERR | CSR_DONE))) - SET_INT (PTP); - ptp_csr = (ptp_csr & ~PTPCSR_RW) | (data & PTPCSR_RW); - return SCPE_OK; - - case 1: /* ptp buf */ - if ((PA & 1) == 0) - ptp_unit.buf = data & 0377; - ptp_csr = ptp_csr & ~CSR_DONE; - CLR_INT (PTP); - if (ptp_unit.flags & UNIT_ATT) /* file to write? */ - sim_activate (&ptp_unit, ptp_unit.wait); - else sim_activate (&ptp_unit, 0); /* error if not */ - return SCPE_OK; - } /* end switch PA */ - -return SCPE_NXM; /* can't get here */ -} - -/* Paper tape punch service */ - -t_stat ptp_svc (UNIT *uptr) -{ -ptp_csr = ptp_csr | CSR_ERR | CSR_DONE; -if (ptp_csr & CSR_IE) - SET_INT (PTP); -if ((ptp_unit.flags & UNIT_ATT) == 0) - return IORETURN (ptp_stopioe, SCPE_UNATT); -if (putc (ptp_unit.buf, ptp_unit.fileref) == EOF) { - perror ("PTP I/O error"); - clearerr (ptp_unit.fileref); - return SCPE_IOERR; - } -ptp_csr = ptp_csr & ~CSR_ERR; -ptp_unit.pos = ptp_unit.pos + 1; -return SCPE_OK; -} - -/* Paper tape punch support routines */ - -t_stat ptp_reset (DEVICE *dptr) -{ -ptp_unit.buf = 0; -ptp_csr = CSR_DONE; -if ((ptp_unit.flags & UNIT_ATT) == 0) - ptp_csr = ptp_csr | CSR_ERR; -CLR_INT (PTP); -sim_cancel (&ptp_unit); /* deactivate unit */ -return SCPE_OK; -} - -t_stat ptp_attach (UNIT *uptr, char *cptr) -{ -t_stat reason; - -reason = attach_unit (uptr, cptr); -if ((ptp_unit.flags & UNIT_ATT) == 0) - ptp_csr = ptp_csr | CSR_ERR; -else ptp_csr = ptp_csr & ~CSR_ERR; -return reason; -} - -t_stat ptp_detach (UNIT *uptr) -{ -ptp_csr = ptp_csr | CSR_ERR; -return detach_unit (uptr); -} diff --git a/PDP11/pdp11_rc.c b/PDP11/pdp11_rc.c deleted file mode 100644 index ec125acf..00000000 --- a/PDP11/pdp11_rc.c +++ /dev/null @@ -1,582 +0,0 @@ -/* pdp11_rc.c: RC11/RS64 fixed head disk simulator - - Copyright (c) 2007-2013, John A. Dundas III - - 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 the author shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the author. - - rc RC11/RS64 fixed head disk - - 03-Dec-13 RMS Added explicit void * cast - 28-Dec-07 JAD Correct extraction of unit number from da in rc_svc. - Clear _all_ error bits when a new operation starts. - Passes all diagnostics in all configurations. - 25-Dec-07 JAD Compute the CRC-16 of the last sector read via - a READ or WCHK. - 20-Dec-07 JAD Correctly simulate rotation over the selected - track for RCLA. Also update the register - correctly during I/O operations. - Insure function activation time is non-zero. - Handle unit number wrap correctly. - 19-Dec-07 JAD Iterate over a full sector regardless of the - actual word count so that RCDA ends correctly. - Honor the read-only vs. read-write status of the - attached file. - 16-Dec-07 JAD The RCDA must be checked for validity when it is - written to, not just when GO is received. - 15-Dec-07 JAD Better handling of disk address errors and the RCLA - register. - Add more registers to the visible device state. - 07-Jan-07 JAD Initial creation and testing. Adapted from pdp11_rf.c. - - The RS64 is a head-per-track disk. To minimize overhead, the entire RC11 - is buffered in memory. Up to 4 RS64 "platters" may be controlled by one - RC11 for a total of 262,144 words (65536kW/platter). [Later in time the - RK611 was assigned the same CSR address.] - - Diagnostic routines: - ZRCAB0.BIC - passes w/1-4 platters - ZRCBB0.BIC - passes w/1-4 platters - ZRCCB0.BIC - passes w/1-4 platters - Note that the diagnostics require R/W disks (i.e., will destroy any - existing data). - - For regression, must pass all three diagnostics configured for 1-4 - platters for a total of 12 tests. - - Information necessary to create this simulation was gathered from the - PDP11 Peripherals Handbook, 1973-74 edition. - - One timing parameter is provided: - - rc_time Minimum I/O operation time, must be non-zero -*/ - -#if !defined (VM_PDP11) -#error "RC11 is not supported!" -#endif -#include "pdp11_defs.h" -#include - -#define UNIT_V_AUTO (UNIT_V_UF + 0) /* autosize */ -#define UNIT_V_PLAT (UNIT_V_UF + 1) /* #platters - 1 */ -#define UNIT_M_PLAT 03 -#define UNIT_GETP(x) ((((x) >> UNIT_V_PLAT) & UNIT_M_PLAT) + 1) -#define UNIT_AUTO (1 << UNIT_V_AUTO) -#define UNIT_PLAT (UNIT_M_PLAT << UNIT_V_PLAT) - -/* Constants */ - -#define RC_NUMWD (32*64) /* words/track */ -#define RC_NUMTR 32 /* tracks/disk */ -#define RC_DKSIZE (RC_NUMTR * RC_NUMWD) /* words/disk */ -#define RC_NUMDK 4 /* disks/controller */ -#define RC_WMASK (RC_NUMWD - 1) /* word mask */ - -/* Parameters in the unit descriptor */ - -#define FUNC u4 /* function */ - -/* Control and status register (RCCS) */ - -#define RCCS_ERR (CSR_ERR) /* error */ -#define RCCS_DATA 0040000 /* data error */ -#define RCCS_ADDR 0020000 /* address error */ -#define RCCS_WLK 0010000 /* write lock */ -#define RCCS_NED 0004000 /* nx disk */ -#define RCCS_WCHK 0002000 /* write check */ -#define RCCS_INH 0001000 /* inhibit CA incr */ -#define RCCS_ABO 0000400 /* abort */ -#define RCCS_DONE (CSR_DONE) -#define RCCS_IE (CSR_IE) -#define RCCS_M_MEX 0000003 /* memory extension */ -#define RCCS_V_MEX 4 -#define RCCS_MEX (RCCS_M_MEX << RCCS_V_MEX) -#define RCCS_MAINT 0000010 /* maint */ -#define RCCS_M_FUNC 0000003 /* function */ -#define RFNC_LAH 0 -#define RFNC_WRITE 1 -#define RFNC_READ 2 -#define RFNC_WCHK 3 -#define RCCS_V_FUNC 1 -#define RCCS_FUNC (RCCS_M_FUNC << RCCS_V_FUNC) -#define RCCS_GO 0000001 - -#define RCCS_ALLERR (RCCS_DATA|RCCS_ADDR|RCCS_WLK|RCCS_NED|RCCS_WCHK) -#define RCCS_W (RCCS_INH | RCCS_ABO |RCCS_IE | RCCS_MEX | RCCS_MAINT | \ - RCCS_FUNC | RCCS_GO) - -/* Disk error status register (RCER) */ - -#define RCER_DLT 0100000 /* data late */ -#define RCER_CHK 0040000 /* block check */ -#define RCER_SYNC 0020000 /* data sync */ -#define RCER_NXM 0010000 /* nonexistant memory */ -#define RCER_TRK 0001000 /* track error */ -#define RCER_APAR 0000200 /* address parity */ -#define RCER_SADDR 0000100 /* sync address */ -#define RCER_OVFL 0000040 /* disk overflow */ -#define RCER_MIS 0000020 /* missed transfer */ - -/* Lood Ahead Register (RCLA) */ - -#define RCLA_BADD 0100000 /* bad address */ - -/* extract device operation code */ -#define GET_FUNC(x) (((x) >> RCCS_V_FUNC) & RCCS_M_FUNC) -/* extract memory extension address (bits 17,18) */ -#define GET_MEX(x) (((x) & RCCS_MEX) << (16 - RCCS_V_MEX)) -#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \ - ((double) RC_NUMWD))) - -extern int32 int_req[IPL_HLVL]; -extern int32 R[]; - -static uint32 rc_la = 0; /* look-ahead */ -static uint32 rc_da = 0; /* disk address */ -static uint32 rc_er = 0; /* error status */ -static uint32 rc_cs = 0; /* command and status */ -static uint32 rc_wc = 0; /* word count */ -static uint32 rc_ca = 0; /* current address */ -static uint32 rc_maint = 0; /* maintenance */ -static uint32 rc_db = 0; /* data buffer */ -static uint32 rc_wlk = 0; /* write lock */ -static uint32 rc_time = 16; /* inter-word time: 16us */ -static uint32 rc_stopioe = 1; /* stop on error */ - -/* forward references */ - -static t_stat rc_rd (int32 *, int32, int32); -static t_stat rc_wr (int32, int32, int32); -static t_stat rc_svc (UNIT *); -static t_stat rc_reset (DEVICE *); -static t_stat rc_attach (UNIT *, char *); -static t_stat rc_set_size (UNIT *, int32, char *, void *); -static uint32 update_rccs (uint32, uint32); - -/* RC11 data structures - - rc_dev RC device descriptor - rc_unit RC unit descriptor - rc_reg RC register list -*/ - -static DIB rc_dib = { - IOBA_RC, - IOLN_RC, - &rc_rd, - &rc_wr, - 1, IVCL (RC), VEC_RC, { NULL } -}; - -static UNIT rc_unit = { - UDATA (&rc_svc, UNIT_FIX + UNIT_ATTABLE + UNIT_BUFABLE + - UNIT_MUSTBUF + UNIT_ROABLE + UNIT_BINK, RC_DKSIZE) -}; - -static const REG rc_reg[] = { - { ORDATA (RCLA, rc_la, 16) }, - { ORDATA (RCDA, rc_da, 16) }, - { ORDATA (RCER, rc_er, 16) }, - { ORDATA (RCCS, rc_cs, 16) }, - { ORDATA (RCWC, rc_wc, 16) }, - { ORDATA (RCCA, rc_ca, 16) }, - { ORDATA (RCMN, rc_maint, 16) }, - { ORDATA (RCDB, rc_db, 16) }, - { ORDATA (RCWLK, rc_wlk, 32) }, - { FLDATA (INT, IREQ (RC), INT_V_RC) }, - { FLDATA (ERR, rc_cs, CSR_V_ERR) }, - { FLDATA (DONE, rc_cs, CSR_V_DONE) }, - { FLDATA (IE, rc_cs, CSR_V_IE) }, - { DRDATA (TIME, rc_time, 24), REG_NZ + PV_LEFT }, - { FLDATA (STOP_IOE, rc_stopioe, 0) }, - { ORDATA (DEVADDR, rc_dib.ba, 32), REG_HRO }, - { ORDATA (DEVVEC, rc_dib.vec, 16), REG_HRO }, - { NULL } -}; - -static const MTAB rc_mod[] = { - { UNIT_PLAT, (0 << UNIT_V_PLAT), NULL, "1P", &rc_set_size }, - { UNIT_PLAT, (1 << UNIT_V_PLAT), NULL, "2P", &rc_set_size }, - { UNIT_PLAT, (2 << UNIT_V_PLAT), NULL, "3P", &rc_set_size }, - { UNIT_PLAT, (3 << UNIT_V_PLAT), NULL, "4P", &rc_set_size }, - { UNIT_AUTO, UNIT_AUTO, "autosize", "AUTOSIZE", NULL }, - { MTAB_XTD|MTAB_VDV, 020, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", - &set_vec, &show_vec, NULL }, - { 0 } -}; - -DEVICE rc_dev = { - "RC", &rc_unit, (REG *) rc_reg, (MTAB *) rc_mod, - 1, 8, 21, 1, 8, 16, - NULL, /* examine */ - NULL, /* deposit */ - &rc_reset, /* reset */ - NULL, /* boot */ - &rc_attach, /* attach */ - NULL, /* detach */ - &rc_dib, - DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG -}; - -/* I/O dispatch routine, I/O addresses 17777440 - 17777456 */ - -static t_stat rc_rd (int32 *data, int32 PA, int32 access) -{ - uint32 t; - - switch ((PA >> 1) & 07) { /* decode PA<3:1> */ - - case 0: /* RCLA */ - t = rc_la & 017777; - if ((rc_cs & RCCS_NED) || (rc_er & RCER_OVFL)) - t |= RCLA_BADD; - *data = t; - /* simulate sequential rotation about the current track */ - rc_la = (rc_la & ~077) | ((rc_la + 1) & 077); - if (DEBUG_PRS (rc_dev)) - fprintf (sim_deb, ">>RC rd: RCLA %06o\n", rc_la); - break; - - case 1: /* RCDA */ - *data = rc_da; - if (DEBUG_PRS (rc_dev)) - fprintf (sim_deb, ">>RC rd: RCDA %06o, PC %06o\n", - rc_da, PC); - break; - - case 2: /* RCER */ - *data = rc_er; - if (DEBUG_PRS (rc_dev)) - fprintf (sim_deb, ">>RC rd: RCER %06o\n", rc_er); - break; - - case 3: /* RCCS */ - *data = update_rccs (0, 0) & ~(RCCS_ABO | RCCS_GO); - if (DEBUG_PRS (rc_dev)) - fprintf (sim_deb, ">>RC rd: RCCS %06o\n", *data); - break; - - case 4: /* RCWC */ - *data = rc_wc; - if (DEBUG_PRS (rc_dev)) - fprintf (sim_deb, ">>RC rd: RCWC %06o\n", rc_wc); - break; - - case 5: /* RCCA */ - *data = rc_ca; - if (DEBUG_PRS (rc_dev)) - fprintf (sim_deb, ">>RC rd: RCCA %06o\n", rc_ca); - break; - - case 6: /* RCMN */ - *data = rc_maint; - if (DEBUG_PRS (rc_dev)) - fprintf (sim_deb, ">>RC rd: RCMN %06o\n", rc_maint); - break; - - case 7: /* RCDB */ - *data = rc_db; - if (DEBUG_PRS (rc_dev)) - fprintf (sim_deb, ">>RC rd: RCDB %06o\n", rc_db); - break; - - default: - return (SCPE_NXM); /* can't happen */ - } /* end switch */ - return (SCPE_OK); -} - -static t_stat rc_wr (int32 data, int32 PA, int32 access) -{ - int32 t; - - switch ((PA >> 1) & 07) { /* decode PA<3:1> */ - - case 0: /* RCLA */ - if (DEBUG_PRS (rc_dev)) - fprintf (sim_deb, ">>RC wr: RCLA\n"); - break; /* read only */ - - case 1: /* RCDA */ - if (access == WRITEB) - data = (PA & 1) ? - (rc_da & 0377) | (data << 8) : - (rc_da & ~0377) | data; - rc_da = data & 017777; - rc_cs &= ~RCCS_NED; - update_rccs (0, 0); - /* perform unit select */ - if (((rc_da >> 11) & 03) >= UNIT_GETP(rc_unit.flags)) - update_rccs (RCCS_NED, 0); - else - rc_la = rc_da; - if (DEBUG_PRS (rc_dev)) - fprintf (sim_deb, ">>RC wr: RCDA %06o, PC %06o\n", - rc_da, PC); - break; - - case 2: /* RCER */ - if (DEBUG_PRS (rc_dev)) - fprintf (sim_deb, ">>RC wr: RCER\n"); - break; /* read only */ - - case 3: /* RCCS */ - if (access == WRITEB) - data = (PA & 1) ? - (rc_cs & 0377) | (data << 8) : - (rc_cs & ~0377) | data; - if (data & RCCS_ABO) { - update_rccs (RCCS_DONE, 0); - sim_cancel (&rc_unit); - } - if ((data & RCCS_IE) == 0) /* int disable? */ - CLR_INT (RC); /* clr int request */ - else if ((rc_cs & (RCCS_DONE | RCCS_IE)) == RCCS_DONE) - SET_INT (RC); /* set int request */ - rc_cs = (rc_cs & ~RCCS_W) | (data & RCCS_W); /* merge */ - if ((rc_cs & RCCS_DONE) && (data & RCCS_GO)) { /* new function? */ - rc_unit.FUNC = GET_FUNC (data); /* save function */ - t = (rc_da & RC_WMASK) - GET_POS (rc_time); /* delta to new loc */ - if (t <= 0) /* wrap around? */ - t = t + RC_NUMWD; - sim_activate (&rc_unit, t * rc_time); /* schedule op */ - /* clear error indicators for new operation */ - rc_cs &= ~(RCCS_ALLERR | RCCS_ERR | RCCS_DONE); - rc_er = 0; - CLR_INT (RC); - if (DEBUG_PRS (rc_dev)) - fprintf (sim_deb, ">>RC start: cs = %o, da = %o, ma = %o, wc = %o\n", - update_rccs (0, 0), rc_da, - GET_MEX (rc_cs) | rc_ca, rc_wc); - } - break; - - case 4: /* RCWC */ - if (access == WRITEB) - data = (PA & 1) ? - (rc_wc & 0377) | (data << 8) : - (rc_wc & ~0377) | data; - rc_wc = data & DMASK; - if (DEBUG_PRS (rc_dev)) - fprintf (sim_deb, ">>RC wr: RCWC %06o, PC %06o\n", - rc_wc, PC); - break; - - case 5: /* RCCA */ - /* TBD: write byte fixup? */ - rc_ca = data & 0177776; - if (DEBUG_PRS (rc_dev)) - fprintf (sim_deb, ">>RC wr: RCCA %06o\n", rc_ca); - break; - - case 6: /* RCMN */ - /* TBD: write byte fixup? */ - rc_maint = data & 0177700; - if (DEBUG_PRS (rc_dev)) - fprintf (sim_deb, ">>RC wr: RCMN %06o\n", rc_maint); - break; - - case 7: /* RCDB */ - if (DEBUG_PRS (rc_dev)) - fprintf (sim_deb, ">>RC wr: RCDB\n"); - break; /* read only */ - - default: /* can't happen */ - return (SCPE_NXM); - } /* end switch */ - update_rccs (0, 0); - return (SCPE_OK); -} - -/* sector (32W) CRC-16 */ - -static uint32 sectorCRC (const uint16 *data) -{ - uint32 crc, i, j, d; - - crc = 0; - for (i = 0; i < 32; i++) { - d = *data++; - /* cribbed from KG11-A */ - for (j = 0; j < 16; j++) { - crc = (crc & ~01) | ((crc & 01) ^ (d & 01)); - crc = (crc & 01) ? (crc >> 1) ^ 0120001 : crc >> 1; - d >>= 1; - } - } - return (crc); -} - -/* Unit service - - Note that for reads and writes, memory addresses wrap around in the - current field. This code assumes the entire disk is buffered. -*/ - -static t_stat rc_svc (UNIT *uptr) -{ - uint32 ma, da, t, u_old, u_new, last_da = 0; - uint16 dat; - uint16 *fbuf = (uint16 *) uptr->filebuf; - - if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */ - update_rccs (RCCS_NED | RCCS_DONE, 0); /* nx disk */ - return (IORETURN (rc_stopioe, SCPE_UNATT)); - } - - ma = GET_MEX (rc_cs) | rc_ca; /* 18b mem addr */ - da = rc_da * RC_NUMTR; /* sector->word offset */ - u_old = (da >> 16) & 03; /* save starting unit# */ - do { - u_new = (da >> 16) & 03; - if (u_new < u_old) { /* unit # overflow? */ - update_rccs (RCCS_NED, RCER_OVFL); - break; - } - if (u_new >= UNIT_GETP(uptr->flags)) { /* disk overflow? */ - update_rccs (RCCS_NED, 0); - break; - } - if (uptr->FUNC == RFNC_READ) { /* read? */ - last_da = da & ~037; - dat = fbuf[da]; /* get disk data */ - rc_db = dat; - if (Map_WriteW (ma, 2, &dat)) { /* store mem, nxm? */ - update_rccs (0, RCER_NXM); - break; - } - } else if (uptr->FUNC == RFNC_WCHK) { /* write check? */ - last_da = da & ~037; - rc_db = fbuf[da]; /* get disk data */ - if (Map_ReadW (ma, 2, &dat)) { /* read mem, nxm? */ - update_rccs (0, RCER_NXM); - break; - } - if (rc_db != dat) { /* miscompare? */ - update_rccs (RCCS_WCHK, 0); - break; - } - } else if (uptr->FUNC == RFNC_WRITE) { /* write */ - t = (da >> 15) & 037; - if (((rc_wlk >> t) & 1) || - (uptr->flags & UNIT_RO)) { /* write locked? */ - update_rccs (RCCS_WLK, 0); - break; - } - /* not locked */ - if (Map_ReadW (ma, 2, &dat)) { /* read mem, nxm? */ - update_rccs (0, RCER_NXM); - break; - } - fbuf[da] = dat; /* write word */ - rc_db = dat; - if (da >= uptr->hwmark) - uptr->hwmark = da + 1; - } else { /* look ahead */ - break; /* no op for now */ - } - rc_wc = (rc_wc + 1) & DMASK; /* incr word count */ - da = (da + 1) & 0777777; /* incr disk addr */ - if ((rc_cs & RCCS_INH) == 0) /* inhibit clear? */ - ma = (ma + 2) & UNIMASK; /* incr mem addr */ - } while (rc_wc != 0); /* brk if wc */ - rc_ca = ma & DMASK; /* split ma */ - rc_cs = (rc_cs & ~RCCS_MEX) | ((ma >> (16 - RCCS_V_MEX)) & RCCS_MEX); - da += 31; - rc_da = (da >> 5) & 017777; - /* CRC of last 32W, if necessary */ - if ((uptr->FUNC == RFNC_READ) || (uptr->FUNC == RFNC_WCHK)) - rc_db = sectorCRC (&fbuf[last_da]); - if (uptr->FUNC != RFNC_LAH) - rc_la = rc_da; - update_rccs (RCCS_DONE, 0); - if (DEBUG_PRS (rc_dev)) - fprintf (sim_deb, ">>RC done: cs = %o, da = %o, ma = %o, wc = %o\n", - rc_cs, rc_da, rc_ca, rc_wc); - return (SCPE_OK); -} - -/* Update CS register */ - -static uint32 update_rccs (uint32 newcs, uint32 newer) -{ - uint32 oldcs = rc_cs; - - rc_er |= newer; /* update RCER */ - rc_cs |= newcs; /* update CS */ - if ((rc_cs & RCCS_ALLERR) || (rc_er != 0)) /* update CS */ - rc_cs |= RCCS_ERR; - else - rc_cs &= ~RCCS_ERR; - if ((rc_cs & RCCS_IE) && /* IE and */ - (rc_cs & RCCS_DONE) && !(oldcs & RCCS_DONE)) /* done 0->1? */ - SET_INT (RC); - return (rc_cs); -} - -/* Reset routine */ - -static t_stat rc_reset (DEVICE *dptr) -{ - rc_cs = RCCS_DONE; - rc_la = rc_da = 0; - rc_er = 0; - rc_wc = 0; - rc_ca = 0; - rc_maint = 0; - rc_db = 0; - CLR_INT (RC); - sim_cancel (&rc_unit); - return (SCPE_OK); -} - -/* Attach routine */ - -static t_stat rc_attach (UNIT *uptr, char *cptr) -{ - uint32 sz, p; - static const uint32 ds_bytes = RC_DKSIZE * sizeof (int16); - - if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize_name (cptr))) { - p = (sz + ds_bytes - 1) / ds_bytes; - if (p >= RC_NUMDK) - p = RC_NUMDK - 1; - uptr->flags = (uptr->flags & ~UNIT_PLAT) | (p << UNIT_V_PLAT); - } - uptr->capac = UNIT_GETP (uptr->flags) * RC_DKSIZE; - return (attach_unit (uptr, cptr)); -} - -/* Change disk size */ - -static t_stat rc_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ - if (val < 0) - return (SCPE_IERR); - if (uptr->flags & UNIT_ATT) - return (SCPE_ALATT); - uptr->capac = UNIT_GETP (val) * RC_DKSIZE; - uptr->flags = uptr->flags & ~UNIT_AUTO; - return (SCPE_OK); -} diff --git a/PDP11/pdp11_rf.c b/PDP11/pdp11_rf.c deleted file mode 100644 index 7cc1471d..00000000 --- a/PDP11/pdp11_rf.c +++ /dev/null @@ -1,504 +0,0 @@ -/* pdp11_rf.c: RF11 fixed head disk simulator - - Copyright (c) 2006-2017, 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. - - rf RF11 fixed head disk - - 13-Feb-17 RMS Fixed CSR address in boot code (Paul Koning) - 23-Oct-13 RMS Revised for new boot setup routine - 03-Sep-13 RMS Added explicit void * cast - Added WC to debug printout - 19-Mar-12 RMS Fixed bug in updating mem addr extension (Peter Schorn) - 25-Dec-06 RMS Fixed bug in unit mask (John Dundas) - 26-Jun-06 RMS Cloned from RF08 simulator - - The RF11 is a head-per-track disk. To minimize overhead, the entire RF11 - is buffered in memory. - - Two timing parameters are provided: - - rf_time Interword timing, must be non-zero - rf_burst Burst mode, if 0, DMA occurs cycle by cycle; otherwise, - DMA occurs in a burst -*/ - -#include "pdp11_defs.h" -#include - -#define UNIT_V_AUTO (UNIT_V_UF + 0) /* autosize */ -#define UNIT_V_PLAT (UNIT_V_UF + 1) /* #platters - 1 */ -#define UNIT_M_PLAT (RF_NUMDK - 1) -#define UNIT_GETP(x) ((((x) >> UNIT_V_PLAT) & UNIT_M_PLAT) + 1) -#define UNIT_AUTO (1 << UNIT_V_AUTO) -#define UNIT_PLAT (UNIT_M_PLAT << UNIT_V_PLAT) - -/* Constants */ - -#define RF_NUMWD 2048 /* words/track */ -#define RF_NUMTR 128 /* tracks/disk */ -#define RF_DKSIZE (RF_NUMTR * RF_NUMWD) /* words/disk */ -#define RF_NUMDK 8 /* disks/controller */ -#define RF_WMASK (RF_NUMWD - 1) /* word mask */ - -/* Parameters in the unit descriptor */ - -#define FUNC u4 /* function */ - -/* Status register */ - -#define RFCS_ERR (CSR_ERR) /* error */ -#define RFCS_FRZ 0040000 /* error freeze */ -#define RFCS_WCHK 0020000 /* write check */ -#define RFCS_DPAR 0010000 /* data parity (ni) */ -#define RFCS_NED 0004000 /* nx disk */ -#define RFCS_WLK 0002000 /* write lock */ -#define RFCS_MXFR 0001000 /* missed xfer (ni) */ -#define RFCS_CLR 0000400 /* clear */ -#define RFCS_DONE (CSR_DONE) -#define RFCS_IE (CSR_IE) -#define RFCS_M_MEX 0000003 /* memory extension */ -#define RFCS_V_MEX 4 -#define RFCS_MEX (RFCS_M_MEX << RFCS_V_MEX) -#define RFCS_MAINT 0000010 /* maint */ -#define RFCS_M_FUNC 0000003 /* function */ -#define RFNC_NOP 0 -#define RFNC_WRITE 1 -#define RFNC_READ 2 -#define RFNC_WCHK 3 -#define RFCS_V_FUNC 1 -#define RFCS_FUNC (RFCS_M_FUNC << RFCS_V_FUNC) -#define RFCS_GO 0000001 -#define RFCS_ALLERR (RFCS_FRZ|RFCS_WCHK|RFCS_DPAR|RFCS_NED|RFCS_WLK|RFCS_MXFR) -#define RFCS_W (RFCS_IE|RFCS_MEX|RFCS_FUNC) - -/* Current memory address */ - -#define RFCMA_RW 0177776 - -/* Address extension */ - -#define RFDAE_ALLERR 0176000 -#define RFDAE_NXM 0002000 -#define RFDAE_INH 0000400 /* addr inhibit */ -#define RFDAE_RLAT 0000200 /* req late */ -#define RFDAE_DAE 0000077 /* extension */ -#define RFDAE_R 0176677 -#define RFDAE_W 0000677 - -#define GET_FUNC(x) (((x) >> RFCS_V_FUNC) & RFCS_M_FUNC) -#define GET_MEX(x) (((x) & RFCS_MEX) << (16 - RFCS_V_MEX)) -#define GET_DEX(x) (((x) & RFDAE_DAE) << 16) -#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \ - ((double) RF_NUMWD))) - -extern uint16 *M; -extern int32 int_req[IPL_HLVL]; - -uint32 rf_cs = 0; /* status register */ -uint32 rf_cma = 0; -uint32 rf_wc = 0; -uint32 rf_da = 0; /* disk address */ -uint32 rf_dae = 0; -uint32 rf_dbr = 0; -uint32 rf_maint = 0; -uint32 rf_wlk = 0; /* write lock */ -uint32 rf_time = 10; /* inter-word time */ -uint32 rf_burst = 1; /* burst mode flag */ -uint32 rf_stopioe = 1; /* stop on error */ - -t_stat rf_rd (int32 *data, int32 PA, int32 access); -t_stat rf_wr (int32 data, int32 PA, int32 access); -int32 rf_inta (void); -t_stat rf_svc (UNIT *uptr); -t_stat rf_reset (DEVICE *dptr); -t_stat rf_boot (int32 unitno, DEVICE *dptr); -t_stat rf_attach (UNIT *uptr, char *cptr); -t_stat rf_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -uint32 update_rfcs (uint32 newcs, uint32 newdae); - -/* RF11 data structures - - rf_dev RF device descriptor - rf_unit RF unit descriptor - rf_reg RF register list -*/ - -DIB rf_dib = { - IOBA_RF, IOLN_RF, &rf_rd, &rf_wr, - 1, IVCL (RF), VEC_RF, NULL - }; - - -UNIT rf_unit = { - UDATA (&rf_svc, UNIT_FIX+UNIT_ATTABLE+ - UNIT_BUFABLE+UNIT_MUSTBUF, RF_DKSIZE) - }; - -REG rf_reg[] = { - { ORDATA (RFCS, rf_cs, 16) }, - { ORDATA (RFWC, rf_wc, 16) }, - { ORDATA (RFCMA, rf_cma, 16) }, - { ORDATA (RFDA, rf_da, 16) }, - { ORDATA (RFDAE, rf_dae, 16) }, - { ORDATA (RFDBR, rf_dbr, 16) }, - { ORDATA (RFMR, rf_maint, 16) }, - { ORDATA (RFWLK, rf_wlk, 32) }, - { FLDATA (INT, IREQ (RF), INT_V_RF) }, - { FLDATA (ERR, rf_cs, CSR_V_ERR) }, - { FLDATA (DONE, rf_cs, CSR_V_DONE) }, - { FLDATA (IE, rf_cs, CSR_V_IE) }, - { DRDATA (TIME, rf_time, 24), REG_NZ + PV_LEFT }, - { FLDATA (BURST, rf_burst, 0) }, - { FLDATA (STOP_IOE, rf_stopioe, 0) }, - { ORDATA (DEVADDR, rf_dib.ba, 32), REG_HRO }, - { ORDATA (DEVVEC, rf_dib.vec, 16), REG_HRO }, - { NULL } - }; - -MTAB rf_mod[] = { - { UNIT_PLAT, (0 << UNIT_V_PLAT), NULL, "1P", &rf_set_size }, - { UNIT_PLAT, (1 << UNIT_V_PLAT), NULL, "2P", &rf_set_size }, - { UNIT_PLAT, (2 << UNIT_V_PLAT), NULL, "3P", &rf_set_size }, - { UNIT_PLAT, (3 << UNIT_V_PLAT), NULL, "4P", &rf_set_size }, - { UNIT_PLAT, (4 << UNIT_V_PLAT), NULL, "5P", &rf_set_size }, - { UNIT_PLAT, (5 << UNIT_V_PLAT), NULL, "6P", &rf_set_size }, - { UNIT_PLAT, (6 << UNIT_V_PLAT), NULL, "7P", &rf_set_size }, - { UNIT_PLAT, (7 << UNIT_V_PLAT), NULL, "8P", &rf_set_size }, - { UNIT_AUTO, UNIT_AUTO, "autosize", "AUTOSIZE", NULL }, - { MTAB_XTD|MTAB_VDV, 020, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", - &set_vec, &show_vec, NULL }, - { 0 } - }; - -DEVICE rf_dev = { - "RF", &rf_unit, rf_reg, rf_mod, - 1, 8, 21, 1, 8, 16, - NULL, NULL, &rf_reset, - &rf_boot, &rf_attach, NULL, - &rf_dib, DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG - }; - -/* I/O dispatch routine, I/O addresses 17777460 - 17777476 */ - -t_stat rf_rd (int32 *data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 07) { /* decode PA<3:1> */ - - case 0: /* RFCS */ - *data = update_rfcs (0, 0); /* update RFCS */ - break; - - case 1: /* RFWC */ - *data = rf_wc; - break; - - case 2: /* RFCMA */ - *data = rf_cma & RFCMA_RW; - break; - - case 3: /* RFDA */ - *data = rf_da; - break; - - case 4: /* RFDAE */ - *data = rf_dae & RFDAE_R; - break; - - case 5: /* RFDBR */ - *data = rf_dbr; - break; - - case 6: /* RFMR */ - *data = rf_maint; - break; - - case 7: /* RFADS */ - *data = GET_POS (rf_time); - break; - } /* end switch */ -return SCPE_OK; -} - -t_stat rf_wr (int32 data, int32 PA, int32 access) -{ -int32 t, fnc; - -switch ((PA >> 1) & 07) { /* decode PA<3:1> */ - - case 0: /* RFCS */ - if (access == WRITEB) - data = (PA & 1)? (rf_cs & 0377) | (data << 8): (rf_cs & ~0377) | data; - if (data & RFCS_CLR) /* clear? */ - rf_reset (&rf_dev); - if ((data & RFCS_IE) == 0) /* int disable? */ - CLR_INT (RF); /* clr int request */ - else if ((rf_cs & (RFCS_DONE + RFCS_IE)) == RFCS_DONE) - SET_INT (RF); /* set int request */ - rf_cs = (rf_cs & ~RFCS_W) | (data & RFCS_W); /* merge */ - if ((rf_cs & RFCS_DONE) && (data & RFCS_GO) && /* new function? */ - ((fnc = GET_FUNC (rf_cs)) != RFNC_NOP)) { - rf_unit.FUNC = fnc; /* save function */ - t = (rf_da & RF_WMASK) - GET_POS (rf_time); /* delta to new loc */ - if (t < 0) /* wrap around? */ - t = t + RF_NUMWD; - sim_activate (&rf_unit, t * rf_time); /* schedule op */ - rf_cs &= ~(RFCS_WCHK|RFCS_DPAR|RFCS_NED|RFCS_WLK|RFCS_MXFR|RFCS_DONE); - CLR_INT (RF); - if (DEBUG_PRS (rf_dev)) - fprintf (sim_deb, ">>RF start: cs = %o, da = %o, ma = %o, wc = %o\n", - update_rfcs (0, 0), GET_DEX (rf_dae) | rf_da, GET_MEX (rf_cs) | rf_cma, rf_wc); - } - break; - - case 1: /* RFWC */ - if (access == WRITEB) - data = (PA & 1)? (rf_wc & 0377) | (data << 8): (rf_wc & ~0377) | data; - rf_wc = data; - break; - - case 2: /* RFCMA */ - if (access == WRITEB) - data = (PA & 1)? (rf_cma & 0377) | (data << 8): (rf_cma & ~0377) | data; - rf_cma = data & RFCMA_RW; - break; - - case 3: /* RFDA */ - if (access == WRITEB) - data = (PA & 1)? (rf_da & 0377) | (data << 8): (rf_da & ~0377) | data; - rf_da = data; - break; - - case 4: /* RFDAE */ - if (access == WRITEB) - data = (PA & 1)? (rf_dae & 0377) | (data << 8): (rf_dae & ~0377) | data; - rf_dae = (rf_dae & ~RFDAE_W) | (data & RFDAE_W); - break; - - case 5: /* RFDBR */ - rf_dbr = data; - break; - - case 6: /* RFMR */ - rf_maint = data; - break; - - case 7: /* RFADS */ - break; /* read only */ - } /* end switch */ - -update_rfcs (0, 0); -return SCPE_OK; -} - -/* Unit service - - Note that for reads and writes, memory addresses wrap around in the - current field. This code assumes the entire disk is buffered. -*/ - -t_stat rf_svc (UNIT *uptr) -{ -uint32 ma, da, t; -uint16 dat; -uint16 *fbuf = (uint16 *) uptr->filebuf; - -if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */ - update_rfcs (RFCS_NED|RFCS_DONE, 0); /* nx disk */ - return IORETURN (rf_stopioe, SCPE_UNATT); - } - -ma = GET_MEX (rf_cs) | rf_cma; /* 18b mem addr */ -da = GET_DEX (rf_dae) | rf_da; /* 22b disk addr */ -do { - if (da >= rf_unit.capac) { /* disk overflow? */ - update_rfcs (RFCS_NED, 0); - break; - } - if (uptr->FUNC == RFNC_READ) { /* read? */ - dat = fbuf[da]; /* get disk data */ - rf_dbr = dat; - if (Map_WriteW (ma, 2, &dat)) { /* store mem, nxm? */ - update_rfcs (0, RFDAE_NXM); - break; - } - } - else if (uptr->FUNC == RFNC_WCHK) { /* write check? */ - rf_dbr = fbuf[da]; /* get disk data */ - if (Map_ReadW (ma, 2, &dat)) { /* read mem, nxm? */ - update_rfcs (0, RFDAE_NXM); - break; - } - if (rf_dbr != dat) { /* miscompare? */ - update_rfcs (RFCS_WCHK, 0); - break; - } - } - else { /* write */ - t = (da >> 15) & 037; - if ((rf_wlk >> t) & 1) { /* write locked? */ - update_rfcs (RFCS_WLK, 0); - break; - } - else { /* not locked */ - if (Map_ReadW (ma, 2, &dat)) { /* read mem, nxm? */ - update_rfcs (0, RFDAE_NXM); - break; - } - fbuf[da] = dat; /* write word */ - rf_dbr = dat; - if (da >= uptr->hwmark) - uptr->hwmark = da + 1; - } - } - da = (da + 1) & 017777777; /* incr disk addr */ - if ((rf_dae & RFDAE_INH) == 0) /* inhibit clear? */ - ma = (ma + 2) & UNIMASK; /* incr mem addr */ - rf_wc = (rf_wc + 1) & DMASK; /* incr word count */ - } while ((rf_wc != 0) && (rf_burst != 0)); /* brk if wc, no brst */ - -rf_da = da & DMASK; /* split da */ -rf_dae = (rf_dae & ~RFDAE_DAE) | ((rf_da >> 16) & RFDAE_DAE); -rf_cma = ma & DMASK; /* split ma */ -rf_cs = (rf_cs & ~RFCS_MEX) | ((ma >> (16 - RFCS_V_MEX)) & RFCS_MEX); -if ((rf_wc != 0) && ((rf_cs & RFCS_ERR) == 0)) /* more to do? */ - sim_activate (&rf_unit, rf_time); /* sched next */ -else { - update_rfcs (RFCS_DONE, 0); - if (DEBUG_PRS (rf_dev)) - fprintf (sim_deb, ">>RF done: cs = %o, dae = %o, da = %o, ma = %o, wc = %o\n", - rf_cs, rf_dae, rf_da, rf_cma, rf_wc); - } -return SCPE_OK; -} - -/* Update CS register */ - -uint32 update_rfcs (uint32 newcs, uint32 newdae) -{ -uint32 oldcs = rf_cs; -uint32 da = GET_DEX (rf_dae) | rf_da; - -rf_dae |= newdae; /* update DAE */ -rf_cs |= newcs; /* update CS */ -if (da >= rf_unit.capac) /* update CS */ - rf_cs |= RFCS_NED; -else rf_cs &= ~RFCS_NED; -if (rf_dae & RFDAE_ALLERR) /* update CS */ - rf_cs |= RFCS_FRZ; -else rf_cs &= ~RFCS_FRZ; -if (rf_cs & RFCS_ALLERR) /* update CS */ - rf_cs |= RFCS_ERR; -else rf_cs &= ~RFCS_ERR; -if ((rf_cs & RFCS_IE) && /* IE and */ - (rf_cs & RFCS_DONE) &&!(oldcs & RFCS_DONE)) /* done 0->1? */ - SET_INT (RF); -return rf_cs; -} - -/* Reset routine */ - -t_stat rf_reset (DEVICE *dptr) -{ -rf_cs = RFCS_DONE; -rf_da = rf_dae = 0; -rf_dbr = 0; -rf_cma = 0; -rf_wc = 0; -rf_maint = 0; -CLR_INT (RF); -sim_cancel (&rf_unit); -return SCPE_OK; -} - -/* Bootstrap routine */ - -/* Device bootstrap */ - -#define BOOT_START 02000 /* start */ -#define BOOT_ENTRY (BOOT_START + 002) /* entry */ -#define BOOT_CSR (BOOT_START + 010) /* CSR */ -#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint16)) - -static const uint16 boot_rom[] = { - 0043113, /* "FD" */ - 0012706, BOOT_START, /* MOV #boot_start, SP */ - 0012701, 0177472, /* MOV #RFCS+12, R1 ; csr block */ - 0005041, /* CLR -(R1) ; clear dae */ - 0005041, /* CLR -(R1), ; clear da */ - 0005041, /* CLR -(R1), ; clear cma */ - 0012741, 0177000, /* MOV #-256.*2, -(R1) ; load wc */ - 0012741, 0000005, /* MOV #READ+GO, -(R1) ; read & go */ - 0005002, /* CLR R2 */ - 0005003, /* CLR R3 */ - 0012704, BOOT_START+020, /* MOV #START+20, R4 */ - 0005005, /* CLR R5 */ - 0105711, /* TSTB (R1) */ - 0100376, /* BPL .-2 */ - 0105011, /* CLRB (R1) */ - 0005007 /* CLR PC */ - }; - -t_stat rf_boot (int32 unitno, DEVICE *dptr) -{ -size_t i; - -for (i = 0; i < BOOT_LEN; i++) - M[(BOOT_START >> 1) + i] = boot_rom[i]; -M[BOOT_CSR >> 1] = (rf_dib.ba & DMASK) + 012; -cpu_set_boot (BOOT_ENTRY); -return SCPE_OK; -} - -/* Attach routine */ - -t_stat rf_attach (UNIT *uptr, char *cptr) -{ -uint32 sz, p; -uint32 ds_bytes = RF_DKSIZE * sizeof (int16); - -if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize_name (cptr))) { - p = (sz + ds_bytes - 1) / ds_bytes; - if (p >= RF_NUMDK) - p = RF_NUMDK - 1; - uptr->flags = (uptr->flags & ~UNIT_PLAT) | - (p << UNIT_V_PLAT); - } -uptr->capac = UNIT_GETP (uptr->flags) * RF_DKSIZE; -return attach_unit (uptr, cptr); -} - -/* Change disk size */ - -t_stat rf_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (val < 0) - return SCPE_IERR; -if (uptr->flags & UNIT_ATT) - return SCPE_ALATT; -uptr->capac = UNIT_GETP (val) * RF_DKSIZE; -uptr->flags = uptr->flags & ~UNIT_AUTO; -return SCPE_OK; -} diff --git a/PDP11/pdp11_rh.c b/PDP11/pdp11_rh.c deleted file mode 100644 index 548b4946..00000000 --- a/PDP11/pdp11_rh.c +++ /dev/null @@ -1,910 +0,0 @@ -/* pdp11_rh.c: PDP-11 Massbus adapter simulator - - Copyright (c) 2005-2013, 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. - - rha, rhb RH11/RH70 Massbus adapter - - 02-Sep-13 RMS Added third Massbus adapter, debug printouts - 19-Mar-12 RMS Fixed declaration of cpu_opt (Mark Pizzolato) - 02-Feb-08 RMS Fixed DMA memory address limit test (John Dundas) - 17-May-07 RMS Moved CS1 drive enable to devices - 21-Nov-05 RMS Added enable/disable routine - 07-Jul-05 RMS Removed extraneous externs - - WARNING: The interupt logic of the RH11/RH70 is unusual and must be - simulated with great precision. The RH11 has an internal interrupt - request flop, CSTB INTR, which is controlled as follows: - - - Writing IE and DONE simultaneously sets CSTB INTR - - Controller clear, INIT, and interrupt acknowledge clear CSTB INTR - (and also clear IE) - - A transition of DONE from 0 to 1 sets CSTB INTR from IE - - The output of CSTB INTR is OR'd with the AND of RPCS1 to - create the interrupt request signal. Thus, - - - The DONE interrupt is edge sensitive, but the SC interrupt is - level sensitive. - - The DONE interrupt, once set, is not disabled if IE is cleared, - but the SC interrupt is. -*/ - -#if defined (VM_PDP10) /* PDP10 version */ -#error "PDP-10 uses pdp10_rp.c and pdp10_tu.c!" - -#elif defined (VM_VAX) /* VAX version */ -#error "VAX uses vax780_mba.c!" - -#else /* PDP-11 version */ -#include "pdp11_defs.h" -#endif - -/* CS1 - base + 000 - control/status 1 */ - -#define CS1_OF 0 -#define CS1_GO CSR_GO /* go */ -#define CS1_V_FNC 1 /* function pos */ -#define CS1_M_FNC 037 /* function mask */ -#define CS1_FNC (CS1_M_FNC << CS1_V_FNC) -#define FNC_XFER 024 /* >=? data xfr */ -#define CS1_IE CSR_IE /* int enable */ -#define CS1_DONE CSR_DONE /* ready */ -#define CS1_V_UAE 8 /* Unibus addr ext */ -#define CS1_M_UAE 03 -#define CS1_UAE (CS1_M_UAE << CS1_V_UAE) -#define CS1_MCPE 0020000 /* Mbus par err NI */ -#define CS1_TRE 0040000 /* transfer err */ -#define CS1_SC 0100000 /* special cond */ -#define CS1_MBZ 0012000 -#define CS1_DRV (CS1_FNC | CS1_GO) -#define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC) - -/* WC - base + 002 - word count */ - -#define WC_OF 1 - -/* BA - base + 004 - base address */ - -#define BA_OF 2 -#define BA_MBZ 0000001 /* must be zero */ - -/* CS2 - base + 010 - control/status 2 */ - -#define CS2_OF 3 -#define CS2_V_UNIT 0 /* unit pos */ -#define CS2_M_UNIT 07 /* unit mask */ -#define CS2_UNIT (CS2_M_UNIT << CS2_V_UNIT) -#define CS2_UAI 0000010 /* addr inhibit */ -#define CS2_PAT 0000020 /* parity test NI */ -#define CS2_CLR 0000040 /* controller clear */ -#define CS2_IR 0000100 /* input ready */ -#define CS2_OR 0000200 /* output ready */ -#define CS2_MDPE 0000400 /* Mbus par err NI */ -#define CS2_MXF 0001000 /* missed xfer NI */ -#define CS2_PGE 0002000 /* program err */ -#define CS2_NEM 0004000 /* nx mem err */ -#define CS2_NED 0010000 /* nx drive err */ -#define CS2_PE 0020000 /* parity err NI */ -#define CS2_WCE 0040000 /* write check err */ -#define CS2_DLT 0100000 /* data late NI */ -#define CS2_MBZ (CS2_CLR) -#define CS2_RW (CS2_UNIT | CS2_UAI | CS2_PAT | CS2_MXF | CS2_PE) -#define CS2_ERR (CS2_MDPE | CS2_MXF | CS2_PGE | CS2_NEM | \ - CS2_NED | CS2_PE | CS2_WCE | CS2_DLT) -#define GET_UNIT(x) (((x) >> CS2_V_UNIT) & CS2_M_UNIT) - -/* DB - base + 022 - data buffer */ - -#define DB_OF 4 - -/* BAE - base + 050/34 - bus address extension */ - -#define BAE_OF 5 -#define AE_M_MAE 0 /* addr ext pos */ -#define AE_V_MAE 077 /* addr ext mask */ -#define AE_MBZ 0177700 - -/* CS3 - base + 052/36 - control/status 3 */ - -#define CS3_OF 6 -#define CS3_APE 0100000 /* addr perr - NI */ -#define CS3_DPO 0040000 /* data perr odd - NI */ -#define CS3_DPE 0020000 /* data perr even - NI */ -#define CS3_WCO 0010000 /* wchk err odd */ -#define CS3_WCE 0004000 /* wchk err even */ -#define CS3_DBL 0002000 /* dbl word xfer - NI */ -#define CS3_IPCK 0000017 /* wrong par - NI */ -#define CS3_ERR (CS3_APE|CS3_DPO|CS3_DPE|CS3_WCO|CS3_WCE) -#define CS3_MBZ 0001660 -#define CS3_RW (CS1_IE | CS3_IPCK) - -#define MBA_OFSMASK 077 /* max 32 reg */ -#define INT 0000 /* int reg flag */ -#define EXT 0100 /* ext reg flag */ - -/* Declarations */ - -#define RH11 (cpu_opt & OPT_RH11) - -typedef struct { - uint32 cs1; /* ctrl/status 1 */ - uint32 wc; /* word count */ - uint32 ba; /* bus addr */ - uint32 cs2; /* ctrl/status 2 */ - uint32 db; /* data buffer */ - uint32 bae; /* addr ext */ - uint32 cs3; /* ctrl/status 3 */ - uint32 iff; /* int flip flop */ - } MBACTX; - -MBACTX massbus[MBA_NUM]; - -extern uint32 cpu_opt; -extern int32 cpu_bme; -extern uint16 *M; -extern int32 int_req[IPL_HLVL]; -extern UNIT cpu_unit; - -t_stat mba_reset (DEVICE *dptr); -t_stat mba_rd (int32 *val, int32 pa, int32 access); -t_stat mba_wr (int32 val, int32 pa, int32 access); -t_stat mba_set_type (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat mba_show_type (FILE *st, UNIT *uptr, int32 val, void *desc); -int32 mba0_inta (void); -int32 mba1_inta (void); -int32 mba2_inta (void); -void mba_set_int (uint32 mb); -void mba_clr_int (uint32 mb); -void mba_upd_cs1 (uint32 set, uint32 clr, uint32 mb); -void mba_set_cs2 (uint32 flg, uint32 mb); -int32 mba_map_pa (int32 pa, int32 *ofs); - - -extern uint32 Map_Addr (uint32 ba); - -/* Massbus register dispatches */ - -static t_stat (*mbregR[MBA_NUM])(int32 *dat, int32 ad, int32 md); -static t_stat (*mbregW[MBA_NUM])(int32 dat, int32 ad, int32 md); -static int32 (*mbabort[MBA_NUM])(void); - -/* Unibus to register offset map */ - -static int32 mba_mapofs[(MBA_OFSMASK + 1) >> 1] = { - INT|0, INT|1, INT|2, EXT|5, INT|3, EXT|1, EXT|2, EXT|4, - EXT|7, INT|4, EXT|3, EXT|6, EXT|8, EXT|9, EXT|10, EXT|11, - EXT|12, EXT|13, EXT|14, EXT|15, EXT|16, EXT|17, EXT|18, EXT|19, - EXT|20, EXT|21, EXT|22, EXT|23, EXT|24, EXT|25, EXT|26, EXT|27 - }; - -/* Massbus adapter data structures - - mbax_dev RHx device descriptor - mbax_unit RHx units - mbax_reg RHx register list -*/ - -DIB mba0_dib = { - IOBA_RP, IOLN_RP, &mba_rd, &mba_wr, - 1, IVCL (RP), VEC_RP, { &mba0_inta } - }; - -UNIT mba0_unit = { UDATA (NULL, 0, 0) }; - -REG mba0_reg[] = { - { ORDATA (CS1, massbus[0].cs1, 16) }, - { ORDATA (WC, massbus[0].wc, 16) }, - { ORDATA (BA, massbus[0].ba, 16) }, - { ORDATA (CS2, massbus[0].cs2, 16) }, - { ORDATA (DB, massbus[0].db, 16) }, - { ORDATA (BAE, massbus[0].bae, 6) }, - { ORDATA (CS3, massbus[0].cs3, 16) }, - { FLDATA (IFF, massbus[0].iff, 0) }, - { FLDATA (INT, IREQ (RP), INT_V_RP) }, - { FLDATA (SC, massbus[0].cs1, CSR_V_ERR) }, - { FLDATA (DONE, massbus[0].cs1, CSR_V_DONE) }, - { FLDATA (IE, massbus[0].cs1, CSR_V_IE) }, - { ORDATA (DEVADDR, mba0_dib.ba, 32), REG_HRO }, - { ORDATA (DEVVEC, mba0_dib.vec, 16), REG_HRO }, - { NULL } - }; - -MTAB mba0_mod[] = { - { MTAB_XTD|MTAB_VDV, 0100, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", - &set_vec, &show_vec, NULL }, - { 0 } - }; - -DIB mba1_dib = { - IOBA_TU, IOLN_TU, &mba_rd, &mba_wr, - 1, IVCL (TU), VEC_TU, { &mba1_inta } - }; - -UNIT mba1_unit = { UDATA (NULL, 0, 0) }; - -REG mba1_reg[] = { - { ORDATA (CS1, massbus[1].cs1, 16) }, - { ORDATA (WC, massbus[1].wc, 16) }, - { ORDATA (BA, massbus[1].ba, 16) }, - { ORDATA (CS2, massbus[1].cs2, 16) }, - { ORDATA (DB, massbus[1].db, 16) }, - { ORDATA (BAE, massbus[1].bae, 6) }, - { ORDATA (CS3, massbus[1].cs3, 16) }, - { FLDATA (IFF, massbus[1].iff, 0) }, - { FLDATA (INT, IREQ (TU), INT_V_TU) }, - { FLDATA (SC, massbus[1].cs1, CSR_V_ERR) }, - { FLDATA (DONE, massbus[1].cs1, CSR_V_DONE) }, - { FLDATA (IE, massbus[1].cs1, CSR_V_IE) }, - { ORDATA (DEVADDR, mba1_dib.ba, 32), REG_HRO }, - { ORDATA (DEVVEC, mba1_dib.vec, 16), REG_HRO }, - { NULL } - }; - -MTAB mba1_mod[] = { - { MTAB_XTD|MTAB_VDV, 0040, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", - &set_vec, &show_vec, NULL }, - { 0 } - }; - -DIB mba2_dib = { - IOBA_RS, IOLN_RS, &mba_rd, &mba_wr, - 1, IVCL (RS), VEC_RS, { &mba2_inta } - }; - -UNIT mba2_unit = { UDATA (NULL, 0, 0) }; - -REG mba2_reg[] = { - { ORDATA (CS1, massbus[2].cs1, 16) }, - { ORDATA (WC, massbus[2].wc, 16) }, - { ORDATA (BA, massbus[2].ba, 16) }, - { ORDATA (CS2, massbus[2].cs2, 16) }, - { ORDATA (DB, massbus[2].db, 16) }, - { ORDATA (BAE, massbus[2].bae, 6) }, - { ORDATA (CS3, massbus[2].cs3, 16) }, - { FLDATA (IFF, massbus[2].iff, 0) }, - { FLDATA (INT, IREQ (RS), INT_V_RS) }, - { FLDATA (SC, massbus[2].cs1, CSR_V_ERR) }, - { FLDATA (DONE, massbus[2].cs1, CSR_V_DONE) }, - { FLDATA (IE, massbus[2].cs1, CSR_V_IE) }, - { ORDATA (DEVADDR, mba2_dib.ba, 32), REG_HRO }, - { ORDATA (DEVVEC, mba2_dib.vec, 16), REG_HRO }, - { NULL } - }; - -MTAB mba2_mod[] = { - { MTAB_XTD|MTAB_VDV, 0040, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", - &set_vec, &show_vec, NULL }, - { 0 } - }; - -DEVICE mba_dev[] = { - { - "RHA", &mba0_unit, mba0_reg, mba0_mod, - 1, 0, 0, 0, 0, 0, - NULL, NULL, &mba_reset, - NULL, NULL, NULL, - &mba0_dib, DEV_DEBUG | DEV_DISABLE | DEV_UBUS | DEV_QBUS - }, - { - "RHB", &mba1_unit, mba1_reg, mba1_mod, - 1, 0, 0, 0, 0, 0, - NULL, NULL, &mba_reset, - NULL, NULL, NULL, - &mba1_dib, DEV_DEBUG | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS - }, - { - "RHC", &mba2_unit, mba2_reg, mba2_mod, - 1, 0, 0, 0, 0, 0, - NULL, NULL, &mba_reset, - NULL, NULL, NULL, - &mba2_dib, DEV_DEBUG | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS - } - }; - -/* Read Massbus adapter register */ - -t_stat mba_rd (int32 *val, int32 pa, int32 mode) -{ -int32 ofs, dat, mb, drv; -t_stat r; - -mb = mba_map_pa (pa, &ofs); /* get mb number */ -if ((mb < 0) || (ofs < 0)) /* valid? */ - return SCPE_NXM; -drv = GET_UNIT (massbus[mb].cs2); /* get drive */ -mba_upd_cs1 (0, 0, mb); /* update CS1 */ - -if (ofs & EXT) { /* external? */ - if (!mbregR[mb]) /* device there? */ - return SCPE_NXM; - r = mbregR[mb] (val, ofs & ~EXT, drv); /* call device */ - if (r == MBE_NXD) /* nx drive? */ - mba_set_cs2 (CS2_NED, mb); - else if (r == MBE_NXR) /* nx reg? */ - return SCPE_NXM; - return SCPE_OK; - } - -switch (ofs) { /* case on reg */ - - case CS1_OF: /* CS1 */ - if (!mbregR[mb]) /* nx device? */ - return SCPE_NXM; - r = mbregR[mb] (&dat, ofs, drv); /* get dev cs1 */ - if (r == MBE_NXD) /* nx drive? */ - mba_set_cs2 (CS2_NED, mb); - *val = massbus[mb].cs1 | dat; - break; - - case WC_OF: /* WC */ - *val = massbus[mb].wc; - break; - - case BA_OF: /* BA */ - *val = massbus[mb].ba & ~BA_MBZ; - break; - - case CS2_OF: /* CS2 */ - *val = massbus[mb].cs2 = (massbus[mb].cs2 & ~CS2_MBZ) | CS2_IR | CS2_OR; - break; - - case DB_OF: /* DB */ - *val = massbus[mb].db; - break; - - case BAE_OF: /* BAE */ - *val = massbus[mb].bae = massbus[mb].bae & ~AE_MBZ; - break; - - case CS3_OF: /* CS3 */ - *val = massbus[mb].cs3 = (massbus[mb].cs3 & ~(CS1_IE | CS3_MBZ)) | - (massbus[mb].cs1 & CS1_IE); - break; - - default: /* huh? */ - return SCPE_NXM; - } - -return SCPE_OK; -} - -t_stat mba_wr (int32 val, int32 pa, int32 access) -{ -int32 ofs, cs1f, drv, mb; -t_stat r; -t_bool cs1dt; - -mb = mba_map_pa (pa, &ofs); /* get mb number */ -if ((mb < 0) || (ofs < 0)) /* valid? */ - return SCPE_NXM; -drv = GET_UNIT (massbus[mb].cs2); /* get drive */ - -if (ofs & EXT) { /* external? */ - if (!mbregW[mb]) /* device there? */ - return SCPE_NXM; - if ((access == WRITEB) && (pa & 1)) /* byte writes */ - val = val << 8; /* don't work */ - r = mbregW[mb] (val, ofs & ~EXT, drv); /* write dev reg */ - if (r == MBE_NXD) /* nx drive? */ - mba_set_cs2 (CS2_NED, mb); - else if (r == MBE_NXR) /* nx reg? */ - return SCPE_NXM; - mba_upd_cs1 (0, 0, mb); /* update status */ - return SCPE_OK; - } - -cs1f = 0; /* no int on cs1 upd */ -switch (ofs) { /* case on reg */ - - case CS1_OF: /* CS1 */ - if (!mbregW[mb]) /* device exist? */ - return SCPE_NXM; - if ((access == WRITEB) && (pa & 1)) - val = val << 8; - if (val & CS1_TRE) { /* error clear? */ - massbus[mb].cs1 &= ~CS1_TRE; /* clr CS1 */ - massbus[mb].cs2 &= ~CS2_ERR; /* clr CS2<15:8> */ - massbus[mb].cs3 &= ~CS3_ERR; /* clr CS3<15:11> */ - } - if ((access == WRITE) || (pa & 1)) { /* hi byte write? */ - if (massbus[mb].cs1 & CS1_DONE) /* done set? */ - massbus[mb].cs1 = (massbus[mb].cs1 & ~CS1_UAE) | (val & CS1_UAE); - } - if ((access == WRITE) || !(pa & 1)) { /* lo byte write? */ - if ((val & CS1_DONE) && (val & CS1_IE)) /* to DONE+IE? */ - massbus[mb].iff = 1; /* set CSTB INTR */ - massbus[mb].cs1 = (massbus[mb].cs1 & ~CS1_IE) | (val & CS1_IE); - cs1dt = (val & CS1_GO) && (GET_FNC (val) >= FNC_XFER); - if (cs1dt && ((massbus[mb].cs1 & CS1_DONE) == 0)) /* dt, done clr? */ - mba_set_cs2 (CS2_PGE, mb); /* prgm error */ - else { - r = mbregW[mb] (val & 077, ofs, drv); /* write dev CS1 */ - if (r == MBE_NXD) /* nx drive? */ - mba_set_cs2 (CS2_NED, mb); - else if (r == MBE_NXR) /* nx reg? */ - return SCPE_NXM; - else if (cs1dt && (r == SCPE_OK)) { /* xfer, no err? */ - massbus[mb].cs1 &= ~(CS1_TRE | CS1_MCPE | CS1_DONE); - massbus[mb].cs2 &= ~CS2_ERR; /* clear errors */ - massbus[mb].cs3 &= ~(CS3_ERR | CS3_DBL); - if (DEBUG_PRS (mba_dev[mb])) - fprintf (sim_deb, ">>RH%d STRT: cs1=%o, cs2=%o,ba=%o, wc=%o\n", - mb, massbus[mb].cs1, massbus[mb].cs2, massbus[mb].ba, massbus[mb].wc); - } - } - } - massbus[mb].cs3 = (massbus[mb].cs3 & ~CS1_IE) | /* update CS3 */ - (massbus[mb].cs1 & CS1_IE); - massbus[mb].bae = (massbus[mb].bae & ~CS1_M_UAE) | /* update BAE */ - ((massbus[mb].cs1 >> CS1_V_UAE) & CS1_M_UAE); - break; - - case WC_OF: /* WC */ - if (access == WRITEB) - val = (pa & 1)? - (massbus[mb].wc & 0377) | (val << 8): - (massbus[mb].wc & ~0377) | val; - massbus[mb].wc = val; - break; - - case BA_OF: /* BA */ - if (access == WRITEB) - val = (pa & 1)? - (massbus[mb].ba & 0377) | (val << 8): - (massbus[mb].ba & ~0377) | val; - massbus[mb].ba = val & ~BA_MBZ; - break; - - case CS2_OF: /* CS2 */ - if ((access == WRITEB) && (pa & 1)) - val = val << 8; - if (val & CS2_CLR) /* init? */ - mba_reset (&mba_dev[mb]); - else { - if ((val & ~massbus[mb].cs2) & (CS2_PE | CS2_MXF)) - cs1f = CS1_SC; /* diagn intr */ - if (access == WRITEB) /* merge val */ - val = (massbus[mb].cs2 & ((pa & 1)? 0377: 0177400)) | val; - massbus[mb].cs2 = (massbus[mb].cs2 & ~CS2_RW) | - (val & CS2_RW) | CS2_IR | CS2_OR; - } - break; - - case DB_OF: /* DB */ - if (access == WRITEB) - val = (pa & 1)? - (massbus[mb].db & 0377) | (val << 8): - (massbus[mb].db & ~0377) | val; - massbus[mb].db = val; - break; - - case BAE_OF: /* BAE */ - if ((access == WRITEB) && (pa & 1)) - break; - massbus[mb].bae = val & ~AE_MBZ; - massbus[mb].cs1 = (massbus[mb].cs1 & ~CS1_UAE) | /* update CS1 */ - ((massbus[mb].bae << CS1_V_UAE) & CS1_UAE); - break; - - case CS3_OF: /* CS3 */ - if ((access == WRITEB) && (pa & 1)) - break; - massbus[mb].cs3 = (massbus[mb].cs3 & ~CS3_RW) | (val & CS3_RW); - massbus[mb].cs1 = (massbus[mb].cs1 & ~CS1_IE) | /* update CS1 */ - (massbus[mb].cs3 & CS1_IE); - break; - - default: - return SCPE_NXM; - } - -mba_upd_cs1 (cs1f, 0, mb); /* update status */ -return SCPE_OK; -} - -/* Massbus I/O routines - - mb_rdbufW - fetch word buffer from memory - mb_wrbufW - store word buffer into memory - mb_chbufW - compare word buffer with memory - - Returns number of bytes successfully transferred/checked -*/ - -int32 mba_rdbufW (uint32 mb, int32 bc, uint16 *buf) -{ -int32 i, j, ba, mbc, pbc; -uint32 pa; - -bc = bc & ~1; /* bc even */ -if (mb >= MBA_NUM) /* valid MBA? */ - return 0; -ba = (massbus[mb].bae << 16) | massbus[mb].ba; /* get busaddr */ -mbc = (0200000 - massbus[mb].wc) << 1; /* MB byte count */ -if (bc > mbc) /* use smaller */ - bc = mbc; -for (i = 0; i < bc; i = i + pbc) { /* loop by pages */ - if (RH11 && cpu_bme) /* map addr */ - pa = Map_Addr (ba); - else pa = ba; - if (!ADDR_IS_MEM (pa)) { /* NXM? */ - mba_set_cs2 (CS2_NEM, mb); /* set error */ - break; - } - pbc = UBM_PAGSIZE - UBM_GETOFF (pa); /* left in page */ - if (pbc > (bc - i)) /* limit to rem xfr */ - pbc = bc - i; - for (j = 0; j < pbc; j = j + 2) { /* loop by words */ - *buf++ = M[pa >> 1]; /* fetch word */ - if (!(massbus[mb].cs2 & CS2_UAI)) { /* if not inhb */ - ba = ba + 2; /* incr ba, pa */ - pa = pa + 2; - } - } - } -massbus[mb].wc = (massbus[mb].wc + (bc >> 1)) & DMASK; /* update wc */ -massbus[mb].ba = ba & DMASK; /* update ba */ -massbus[mb].bae = (ba >> 16) & ~AE_MBZ; /* upper 6b */ -massbus[mb].cs1 = (massbus[mb].cs1 & ~ CS1_UAE) | /* update CS1 */ - ((massbus[mb].bae << CS1_V_UAE) & CS1_UAE); -return i; -} - -int32 mba_wrbufW (uint32 mb, int32 bc, uint16 *buf) -{ -int32 i, j, ba, mbc, pbc; -uint32 pa; - -bc = bc & ~1; /* bc even */ -if (mb >= MBA_NUM) /* valid MBA? */ - return 0; -ba = (massbus[mb].bae << 16) | massbus[mb].ba; /* get busaddr */ -mbc = (0200000 - massbus[mb].wc) << 1; /* MB byte count */ -if (bc > mbc) /* use smaller */ - bc = mbc; -for (i = 0; i < bc; i = i + pbc) { /* loop by pages */ - if (RH11 && cpu_bme) /* map addr */ - pa = Map_Addr (ba); - else pa = ba; - if (!ADDR_IS_MEM (pa)) { /* NXM? */ - mba_set_cs2 (CS2_NEM, mb); /* set error */ - break; - } - pbc = UBM_PAGSIZE - UBM_GETOFF (pa); /* left in page */ - if (pbc > (bc - i)) /* limit to rem xfr */ - pbc = bc - i; - for (j = 0; j < pbc; j = j + 2) { /* loop by words */ - M[pa >> 1] = *buf++; /* put word */ - if (!(massbus[mb].cs2 & CS2_UAI)) { /* if not inhb */ - ba = ba + 2; /* incr ba, pa */ - pa = pa + 2; - } - } - } -massbus[mb].wc = (massbus[mb].wc + (bc >> 1)) & DMASK; /* update wc */ -massbus[mb].ba = ba & DMASK; /* update ba */ -massbus[mb].bae = (ba >> 16) & ~AE_MBZ; /* upper 6b */ -massbus[mb].cs1 = (massbus[mb].cs1 & ~ CS1_UAE) | /* update CS1 */ - ((massbus[mb].bae << CS1_V_UAE) & CS1_UAE); -return i; -} - -int32 mba_chbufW (uint32 mb, int32 bc, uint16 *buf) -{ -int32 i, j, ba, mbc, pbc; -uint32 pa; - -bc = bc & ~1; /* bc even */ -if (mb >= MBA_NUM) /* valid MBA? */ - return 0; -ba = (massbus[mb].bae << 16) | massbus[mb].ba; /* get busaddr */ -mbc = (0200000 - massbus[mb].wc) << 1; /* MB byte count */ -if (bc > mbc) /* use smaller */ - bc = mbc; -for (i = 0; i < bc; i = i + pbc) { /* loop by pages */ - if (RH11 && cpu_bme) pa = Map_Addr (ba); /* map addr */ - else pa = ba; - if (!ADDR_IS_MEM (pa)) { /* NXM? */ - mba_set_cs2 (CS2_NEM, mb); /* set error */ - break; - } - pbc = UBM_PAGSIZE - UBM_GETOFF (pa); /* left in page */ - if (pbc > (bc - i)) /* limit to rem xfr */ - pbc = bc - i; - for (j = 0; j < pbc; j = j + 2) { /* loop by words */ - massbus[mb].db = *buf++; /* get dev word */ - if (M[pa >> 1] != massbus[mb].db) { /* miscompare? */ - mba_set_cs2 (CS2_WCE, mb); /* set error */ - massbus[mb].cs3 = massbus[mb].cs3 | /* set even/odd */ - ((pa & 1)? CS3_WCO: CS3_WCE); - break; - } - if (!(massbus[mb].cs2 & CS2_UAI)) { /* if not inhb */ - ba = ba + 2; /* incr ba, pa */ - pa = pa + 2; - } - } - } -massbus[mb].wc = (massbus[mb].wc + (bc >> 1)) & DMASK; /* update wc */ -massbus[mb].ba = ba & DMASK; /* update ba */ -massbus[mb].bae = (ba >> 16) & ~AE_MBZ; /* upper 6b */ -massbus[mb].cs1 = (massbus[mb].cs1 & ~ CS1_UAE) | /* update CS1 */ - ((massbus[mb].bae << CS1_V_UAE) & CS1_UAE); -return i; -} - -/* Device access, status, and interrupt routines */ - -void mba_set_don (uint32 mb) -{ -mba_upd_cs1 (CS1_DONE, 0, mb); -if (DEBUG_PRS (mba_dev[mb])) - fprintf (sim_deb, ">>RH%d DONE: cs1=%o, cs2=%o,ba=%o, wc=%o\n", - mb, massbus[mb].cs1, massbus[mb].cs2, massbus[mb].ba, massbus[mb].wc); -return; -} - -void mba_upd_ata (uint32 mb, uint32 val) -{ -if (val) - mba_upd_cs1 (CS1_SC, 0, mb); -else mba_upd_cs1 (0, CS1_SC, mb); -return; -} - -void mba_set_exc (uint32 mb) -{ -mba_upd_cs1 (CS1_TRE | CS1_DONE, 0, mb); -return; -} - -int32 mba_get_bc (uint32 mb) -{ -if (mb >= MBA_NUM) - return 0; -return ((0200000 - massbus[mb].wc) << 1); -} - -int32 mba_get_csr (uint32 mb) -{ -DIB *dibp; - -if (mb >= MBA_NUM) - return 0; -dibp = (DIB *) mba_dev[mb].ctxt; -return dibp->ba; -} - -void mba_set_int (uint32 mb) -{ -DIB *dibp; - -if (mb >= MBA_NUM) - return; -dibp = (DIB *) mba_dev[mb].ctxt; -int_req[dibp->vloc >> 5] |= (1 << (dibp->vloc & 037)); -return; -} - -void mba_clr_int (uint32 mb) -{ -DIB *dibp; - -if (mb >= MBA_NUM) - return; -dibp = (DIB *) mba_dev[mb].ctxt; -int_req[dibp->vloc >> 5] &= ~(1 << (dibp->vloc & 037)); -return; -} - -void mba_upd_cs1 (uint32 set, uint32 clr, uint32 mb) -{ -if (mb >= MBA_NUM) - return; -if ((set & ~massbus[mb].cs1) & CS1_DONE) /* DONE 0 to 1? */ - massbus[mb].iff = (massbus[mb].cs1 & CS1_IE)? 1: 0; /* CSTB INTR <- IE */ -massbus[mb].cs1 = (massbus[mb].cs1 & ~(clr | CS1_MCPE | CS1_MBZ | CS1_DRV)) | set; -if (massbus[mb].cs2 & CS2_ERR) - massbus[mb].cs1 = massbus[mb].cs1 | CS1_TRE | CS1_SC; -else if (massbus[mb].cs1 & CS1_TRE) - massbus[mb].cs1 = massbus[mb].cs1 | CS1_SC; -if (massbus[mb].iff || - ((massbus[mb].cs1 & CS1_SC) && - (massbus[mb].cs1 & CS1_DONE) && - (massbus[mb].cs1 & CS1_IE))) - mba_set_int (mb); -else mba_clr_int (mb); -return; -} - -void mba_set_cs2 (uint32 flag, uint32 mb) -{ -if (mb >= MBA_NUM) - return; -massbus[mb].cs2 = massbus[mb].cs2 | flag; -mba_upd_cs1 (0, 0, mb); -return; -} - -/* Interrupt acknowledge */ - -int32 mba0_inta (void) -{ -massbus[0].cs1 &= ~CS1_IE; /* clear int enable */ -massbus[0].cs3 &= ~CS1_IE; /* in both registers */ -massbus[0].iff = 0; /* clear CSTB INTR */ -return mba0_dib.vec; /* acknowledge */ -} - -int32 mba1_inta (void) -{ -massbus[1].cs1 &= ~CS1_IE; /* clear int enable */ -massbus[1].cs3 &= ~CS1_IE; /* in both registers */ -massbus[1].iff = 0; /* clear CSTB INTR */ -return mba1_dib.vec; /* acknowledge */ -} - -int32 mba2_inta (void) -{ -massbus[2].cs1 &= ~CS1_IE; /* clear int enable */ -massbus[2].cs3 &= ~CS1_IE; /* in both registers */ -massbus[2].iff = 0; /* clear CSTB INTR */ -return mba2_dib.vec; /* acknowledge */ -} - -/* Map physical address to Massbus number, offset */ - -int32 mba_map_pa (int32 pa, int32 *ofs) -{ -int32 i, uo, ba, lnt; -DIB *dibp; - -for (i = 0; i < MBA_NUM; i++) { /* loop thru ctrls */ - dibp = (DIB *) mba_dev[i].ctxt; /* get DIB */ - ba = dibp->ba; - lnt = dibp->lnt; - if ((pa >= ba) && /* in range? */ - (pa < (ba + lnt))) { - if (pa < (ba + (lnt - 4))) { /* not last two? */ - uo = ((pa - ba) & MBA_OFSMASK) >> 1; /* get Unibus offset */ - *ofs = mba_mapofs[uo]; /* map thru PROM */ - return i; /* return ctrl idx */ - } - else if (RH11) /* RH11? done */ - return -1; - else { /* RH70 */ - uo = (pa - (ba + (lnt - 4))) >> 1; /* offset relative */ - *ofs = BAE_OF + uo; /* to BAE */ - return i; - } - } - } -return -1; -} - -/* Reset Massbus adapter */ - -t_stat mba_reset (DEVICE *dptr) -{ -uint32 mb; - -mb = dptr - mba_dev; -if (mb >= MBA_NUM) - return SCPE_NOFNC; -massbus[mb].cs1 = CS1_DONE; -massbus[mb].wc = 0; -massbus[mb].ba = 0; -massbus[mb].cs2 = 0; -massbus[mb].db = 0; -massbus[mb].bae= 0; -massbus[mb].cs3 = 0; -massbus[mb].iff = 0; -mba_clr_int (mb); -if (mbabort[mb]) - mbabort[mb] (); -return SCPE_OK; -} - -/* Enable/disable Massbus adapter */ - -void mba_set_enbdis (uint32 mb, t_bool dis) -{ -t_bool orig; -if (mb >= MBA_NUM) /* valid MBA? */ - return; -orig = mba_dev[mb].flags & DEV_DIS; -if (dis) - mba_dev[mb].flags |= DEV_DIS; -else mba_dev[mb].flags &= ~DEV_DIS; -if (orig ^ dis) - mba_reset (&mba_dev[mb]); /* reset on change */ -return; -} - -/* Show Massbus adapter number */ - -t_stat mba_show_num (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -DEVICE *dptr = find_dev_from_unit (uptr); -DIB *dibp; - -if (dptr == NULL) - return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if (dibp == NULL) - return SCPE_IERR; -fprintf (st, "Massbus adapter %d", dibp->ba); -return SCPE_OK; -} - -/* Init Mbus tables */ - -void init_mbus_tab (void) -{ -uint32 i; - -for (i = 0; i < MBA_NUM; i++) { - mbregR[i] = NULL; - mbregW[i] = NULL; - mbabort[i] = NULL; - } -return; -} - -/* Build dispatch tables */ - -t_stat build_mbus_tab (DEVICE *dptr, DIB *dibp) -{ -uint32 idx; - -if ((dptr == NULL) || (dibp == NULL)) /* validate args */ - return SCPE_IERR; -idx = dibp->ba; /* Mbus # */ -if (idx >= MBA_NUM) - return SCPE_STOP; -if ((mbregR[idx] && dibp->rd && /* conflict? */ - (mbregR[idx] != dibp->rd)) || - (mbregW[idx] && dibp->wr && - (mbregW[idx] != dibp->wr)) || - (mbabort[idx] && dibp->ack[0] && - (mbabort[idx] != dibp->ack[0]))) { - sim_printf ("Massbus %s assignment conflict at %d\n", - sim_dname (dptr), dibp->ba); - return SCPE_STOP; - } -if (dibp->rd) /* set rd dispatch */ - mbregR[idx] = dibp->rd; -if (dibp->wr) /* set wr dispatch */ - mbregW[idx] = dibp->wr; -if (dibp->ack[0]) /* set abort dispatch */ - mbabort[idx] = dibp->ack[0]; -return SCPE_OK; -} - diff --git a/PDP11/pdp11_rk.c b/PDP11/pdp11_rk.c deleted file mode 100644 index 7fa12e40..00000000 --- a/PDP11/pdp11_rk.c +++ /dev/null @@ -1,791 +0,0 @@ -/* pdp11_rk.c: RK11/RKV11 cartridge disk simulator - - Copyright (c) 1993-2016, 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. - - rk RK11/RKV11/RK05 cartridge disk - - 12-Mar-16 RMS Revised to support UC15 (18b IO) - 23-Oct-13 RMS Revised for new boot setup routine - 06-Sep-13 RMS Fixed RKDS content for non-existent disk (Mark Pizzolato) - 20-Mar-09 RMS Fixed bug in read header (Walter F Mueller) - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 07-Jul-05 RMS Removed extraneous externs - 30-Sep-04 RMS Revised Unibus interface - 24-Jan-04 RMS Added increment inhibit, overrun detection, formatting - 29-Dec-03 RMS Added RKV11 support - 29-Sep-02 RMS Added variable address support to bootstrap - Added vector change/display support - Revised mapping mnemonics - New data structures - 26-Jan-02 RMS Revised bootstrap to conform to M9312 - 06-Jan-02 RMS Revised enable/disable support - 30-Nov-01 RMS Added read only unit, extended SET/SHOW support - 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 - 15-Feb-01 RMS Corrected bootstrap string - 29-Jun-96 RMS Added unit disable support - - The RK11 is an eight drive cartridge disk subsystem. An RK05 drive - consists of 203 cylinders, each with 2 surfaces containing 12 sectors - of 512 bytes. - - The most complicated part of the RK11 controller is the concept of - interrupt "polling". While only one read or write can occur at a - time, the controller supports multiple seeks. When a seek completes, - if done is set the drive attempts to interrupt. If an interrupt is - already pending, the interrupt is "queued" until it can be processed. - When an interrupt occurs, RKDS<15:13> is loaded with the number of the - interrupting drive. - - To implement this structure, and to assure that read/write interrupts - take priority over seek interrupts, the controller contains an - interrupt queue, rkintq, with a bit for a controller interrupt and - then one for each drive. In addition, the drive number of the last - non-seeking drive is recorded in last_drv. -*/ - -#include "pdp11_defs.h" - -/* Constants */ - -#if defined (UC15) - -#define RKCONTR uint32 /* container format */ -#define RKWRDSZ 18 /* word width */ -#define MAP_RDW(a,b,c) Map_Read18 (a, b, c) -#define MAP_WRW(a,b,c) Map_Write18 (a, b, c) - -#else - -#define RKCONTR uint16 -#define RKWRDSZ 16 -#define MAP_RDW(a,b,c) Map_ReadW (a, b, c) -#define MAP_WRW(a,b,c) Map_WriteW (a, b, c) - -#endif - -#define RK_NUMWD 256 /* words/sector */ -#define RK_NUMSC 12 /* sectors/surface */ -#define RK_NUMSF 2 /* surfaces/cylinder */ -#define RK_NUMCY 203 /* cylinders/drive */ -#define RK_NUMTR (RK_NUMCY * RK_NUMSF) /* tracks/drive */ -#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_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 */ - -#define UNIT_V_HWLK (UNIT_V_UF + 0) /* hwre write lock */ -#define UNIT_V_SWLK (UNIT_V_UF + 1) /* swre write lock */ -#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 */ - -#define CYL u3 /* current cylinder */ -#define FUNC u4 /* function */ - -/* RKDS */ - -#define RKDS_SC 0000017 /* sector counter */ -#define RKDS_ON_SC 0000020 /* on sector */ -#define RKDS_WLK 0000040 /* write locked */ -#define RKDS_RWS 0000100 /* rd/wr/seek ready */ -#define RKDS_RDY 0000200 /* drive ready */ -#define RKDS_SC_OK 0000400 /* SC valid */ -#define RKDS_INC 0001000 /* seek incomplete */ -#define RKDS_UNSAFE 0002000 /* unsafe */ -#define RKDS_RK05 0004000 /* RK05 */ -#define RKDS_PWR 0010000 /* power low */ -#define RKDS_ID 0160000 /* drive ID */ -#define RKDS_V_ID 13 - -/* RKER */ - -#define RKER_WCE 0000001 /* write check */ -#define RKER_CSE 0000002 /* checksum */ -#define RKER_NXS 0000040 /* nx sector */ -#define RKER_NXC 0000100 /* nx cylinder */ -#define RKER_NXD 0000200 /* nx drive */ -#define RKER_TE 0000400 /* timing error */ -#define RKER_DLT 0001000 /* data late */ -#define RKER_NXM 0002000 /* nx memory */ -#define RKER_PGE 0004000 /* programming error */ -#define RKER_SKE 0010000 /* seek error */ -#define RKER_WLK 0020000 /* write lock */ -#define RKER_OVR 0040000 /* overrun */ -#define RKER_DRE 0100000 /* drive error */ -#define RKER_IMP 0177743 /* implemented */ -#define RKER_SOFT (RKER_WCE+RKER_CSE) /* soft errors */ -#define RKER_HARD 0177740 /* hard errors */ - -/* RKCS */ - -#define RKCS_M_FUNC 0000007 /* function */ -#define RKCS_CTLRESET 0 -#define RKCS_WRITE 1 -#define RKCS_READ 2 -#define RKCS_WCHK 3 -#define RKCS_SEEK 4 -#define RKCS_RCHK 5 -#define RKCS_DRVRESET 6 -#define RKCS_WLK 7 -#define RKCS_V_FUNC 1 -#define RKCS_MEX 0000060 /* memory extension */ -#define RKCS_V_MEX 4 -#define RKCS_SSE 0000400 /* stop on soft err */ -#define RKCS_FMT 0002000 /* format */ -#define RKCS_INH 0004000 /* inhibit increment */ -#define RKCS_SCP 0020000 /* search complete */ -#define RKCS_HERR 0040000 /* hard error */ -#define RKCS_ERR 0100000 /* error */ -#define RKCS_REAL 0026776 /* kept here */ -#define RKCS_RW 0006576 /* read/write */ -#define GET_FUNC(x) (((x) >> RKCS_V_FUNC) & RKCS_M_FUNC) - -/* RKDA */ - -#define RKDA_V_SECT 0 /* sector */ -#define RKDA_M_SECT 017 -#define RKDA_V_TRACK 4 /* track */ -#define RKDA_M_TRACK 0777 -#define RKDA_V_CYL 5 /* cylinder */ -#define RKDA_M_CYL 0377 -#define RKDA_V_DRIVE 13 /* drive */ -#define RKDA_M_DRIVE 07 -#define RKDA_DRIVE (RKDA_M_DRIVE << RKDA_V_DRIVE) -#define GET_SECT(x) (((x) >> RKDA_V_SECT) & RKDA_M_SECT) -#define GET_CYL(x) (((x) >> RKDA_V_CYL) & RKDA_M_CYL) -#define GET_TRACK(x) (((x) >> RKDA_V_TRACK) & RKDA_M_TRACK) -#define GET_DRIVE(x) (((x) >> RKDA_V_DRIVE) & RKDA_M_DRIVE) -#define GET_DA(x) ((GET_TRACK (x) * RK_NUMSC) + GET_SECT (x)) - -/* RKBA */ - -#define RKBA_IMP 0177776 /* implemented */ - -#define RK_MIN 10 -#define MAX(x,y) (((x) > (y))? (x): (y)) - -extern int32 int_req[IPL_HLVL]; - -RKCONTR *rkxb = NULL; /* xfer buffer */ -int32 rkcs = 0; /* control/status */ -int32 rkds = 0; /* drive status */ -int32 rkba = 0; /* memory address */ -int32 rkda = 0; /* disk address */ -int32 rker = 0; /* error status */ -int32 rkwc = 0; /* word count */ -int32 rkintq = 0; /* interrupt queue */ -int32 last_drv = 0; /* last r/w drive */ -int32 rk_stopioe = 1; /* stop on error */ -int32 rk_swait = 10; /* seek time */ -int32 rk_rwait = 10; /* rotate time */ - -DEVICE rk_dev; -t_stat rk_rd (int32 *data, int32 PA, int32 access); -t_stat rk_wr (int32 data, int32 PA, int32 access); -int32 rk_inta (void); -t_stat rk_svc (UNIT *uptr); -t_stat rk_reset (DEVICE *dptr); -void rk_go (void); -void rk_set_done (int32 error); -void rk_clr_done (void); -t_stat rk_boot (int32 unitno, DEVICE *dptr); - -/* RK11 data structures - - rk_dev RK device descriptor - rk_unit RK unit list - rk_reg RK register list - rk_mod RK modifier list -*/ - -DIB rk_dib = { - IOBA_RK, IOLN_RK, &rk_rd, &rk_wr, - 1, IVCL (RK), VEC_RK, { &rk_inta } - }; - -UNIT rk_unit[] = { - { UDATA (&rk_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - 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) }, - { ORDATA (RKDA, rkda, 16) }, - { ORDATA (RKBA, rkba, 16) }, - { ORDATA (RKWC, rkwc, 16) }, - { ORDATA (RKDS, rkds, 16) }, - { ORDATA (RKER, rker, 16) }, - { ORDATA (INTQ, rkintq, 9) }, - { ORDATA (DRVN, last_drv, 3) }, - { FLDATA (INT, IREQ (RK), INT_V_RK) }, - { FLDATA (ERR, rkcs, CSR_V_ERR) }, - { FLDATA (DONE, rkcs, CSR_V_DONE) }, - { FLDATA (IE, rkcs, CSR_V_IE) }, - { DRDATA (STIME, rk_swait, 24), PV_LEFT }, - { DRDATA (RTIME, rk_rwait, 24), PV_LEFT }, - { FLDATA (STOP_IOE, rk_stopioe, 0) }, - { ORDATA (DEVADDR, rk_dib.ba, 32), REG_HRO }, - { ORDATA (DEVVEC, rk_dib.vec, 16), REG_HRO }, - { NULL } - }; - -MTAB rk_mod[] = { - { UNIT_HWLK, 0, "write enabled", "WRITEENABLED", NULL }, - { UNIT_HWLK, UNIT_HWLK, "write locked", "LOCKED", NULL }, - { MTAB_XTD|MTAB_VDV, 020, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", - &set_vec, &show_vec, NULL }, - { 0 } - }; - -DEVICE rk_dev = { - "RK", rk_unit, rk_reg, rk_mod, - RK_NUMDR, 8, 24, 1, 8, RKWRDSZ, - NULL, NULL, &rk_reset, - &rk_boot, NULL, NULL, - &rk_dib, DEV_DISABLE | DEV_UBUS | DEV_Q18 - }; - -/* I/O dispatch routine, I/O addresses 17777400 - 17777416 - - 17777400 RKDS read only, constructed from "id'd drive" - plus current drive status flags - 17777402 RKER read only, set as operations progress, - cleared by INIT or CONTROL RESET - 17777404 RKCS read/write - 17777406 RKWC read/write - 17777410 RKBA read/write - 17777412 RKDA read/write - 17777414 RKMR read/write, unimplemented - 17777416 RKDB read only, unimplemented -*/ - -t_stat rk_rd (int32 *data, int32 PA, int32 access) -{ -UNIT *uptr; - -switch ((PA >> 1) & 07) { /* decode PA<3:1> */ - - case 0: /* RKDS: read only */ - rkds = rkds & RKDS_ID; /* identified unit */ - uptr = rk_dev.units + GET_DRIVE (rkda); /* selected unit */ - if (!(uptr->flags & UNIT_DIS)) { /* not disabled? */ - rkds = rkds | RKDS_RK05 | RKDS_SC_OK | /* random sector */ - (rand () % RK_NUMSC); - if (uptr->flags & UNIT_ATT) /* attached? */ - rkds = rkds | RKDS_RDY; - if (!sim_is_active (uptr)) /* idle? */ - rkds = rkds | RKDS_RWS; - if (uptr->flags & UNIT_WPRT) /* write locked? */ - rkds = rkds | RKDS_WLK; - if (GET_SECT (rkda) == (rkds & RKDS_SC)) - rkds = rkds | RKDS_ON_SC; - } - *data = rkds; - return SCPE_OK; - - case 1: /* RKER: read only */ - *data = rker & RKER_IMP; - return SCPE_OK; - - case 2: /* RKCS */ - rkcs = rkcs & RKCS_REAL; - if (rker) /* update err flags */ - rkcs = rkcs | RKCS_ERR; - if (rker & RKER_HARD) - rkcs = rkcs | RKCS_HERR; - *data = rkcs; - return SCPE_OK; - - case 3: /* RKWC */ - *data = rkwc; - return SCPE_OK; - - case 4: /* RKBA */ - *data = rkba & RKBA_IMP; - return SCPE_OK; - - case 5: /* RKDA */ - *data = rkda; - return SCPE_OK; - - default: - *data = 0; - return SCPE_OK; - } /* end switch */ -} - -t_stat rk_wr (int32 data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 07) { /* decode PA<3:1> */ - - case 0: /* RKDS: read only */ - return SCPE_OK; - - case 1: /* RKER: read only */ - return SCPE_OK; - - case 2: /* RKCS */ - rkcs = rkcs & RKCS_REAL; - if (access == WRITEB) - data = (PA & 1)? (rkcs & 0377) | (data << 8): (rkcs & ~0377) | data; - if ((data & CSR_IE) == 0) { /* int disable? */ - rkintq = 0; /* clr int queue */ - CLR_INT (RK); /* clr int request */ - } - else if ((rkcs & (CSR_DONE + CSR_IE)) == CSR_DONE) { - rkintq = rkintq | RK_CTLI; /* queue ctrl int */ - SET_INT (RK); /* set int request */ - } - rkcs = (rkcs & ~RKCS_RW) | (data & RKCS_RW); - if ((rkcs & CSR_DONE) && (data & CSR_GO)) /* new function? */ - rk_go (); - return SCPE_OK; - - case 3: /* RKWC */ - if (access == WRITEB) - data = (PA & 1)? (rkwc & 0377) | (data << 8): (rkwc & ~0377) | data; - rkwc = data; - return SCPE_OK; - - case 4: /* RKBA */ - if (access == WRITEB) - data = (PA & 1)? (rkba & 0377) | (data << 8): (rkba & ~0377) | data; - rkba = data & RKBA_IMP; - return SCPE_OK; - - case 5: /* RKDA */ - if ((rkcs & CSR_DONE) == 0) - return SCPE_OK; - if (access == WRITEB) - data = (PA & 1)? (rkda & 0377) | (data << 8): (rkda & ~0377) | data; - rkda = data; - return SCPE_OK; - - default: - return SCPE_OK; - } /* end switch */ -} - -/* Initiate new function */ - -void rk_go (void) -{ -int32 i, sect, cyl, func; -UNIT *uptr; - -func = GET_FUNC (rkcs); /* get function */ -if (func == RKCS_CTLRESET) { /* control reset? */ - rker = 0; /* clear errors */ - rkda = 0; - rkba = 0; - rkcs = CSR_DONE; - rkintq = 0; /* clr int queue */ - CLR_INT (RK); /* clr int request */ - return; - } -rker = rker & ~RKER_SOFT; /* clear soft errors */ -if (rker == 0) /* redo summary */ - rkcs = rkcs & ~RKCS_ERR; -rkcs = rkcs & ~RKCS_SCP; /* clear sch compl */ -rk_clr_done (); /* clear done */ -last_drv = GET_DRIVE (rkda); /* get drive no */ -uptr = rk_dev.units + last_drv; /* select unit */ -if (uptr->flags & UNIT_DIS) { /* not present? */ - rk_set_done (RKER_NXD); - return; - } -if (((uptr->flags & UNIT_ATT) == 0) || /* not att or busy? */ - sim_is_active (uptr)) { - rk_set_done (RKER_DRE); - return; - } -if ((rkcs & RKCS_FMT) && /* format and */ - (func != RKCS_READ) && (func != RKCS_WRITE)) { /* not read or write? */ - rk_set_done (RKER_PGE); - return; - } -if ((func == RKCS_WRITE) && /* write and locked? */ - (uptr->flags & UNIT_WPRT)) { - rk_set_done (RKER_WLK); - return; - } -if (func == RKCS_WLK) { /* write lock? */ - uptr->flags = uptr->flags | UNIT_SWLK; - rk_set_done (0); - return; - } -if (func == RKCS_DRVRESET) { /* drive reset? */ - uptr->flags = uptr->flags & ~UNIT_SWLK; - cyl = sect = 0; - func = RKCS_SEEK; - } -else { - sect = GET_SECT (rkda); - cyl = GET_CYL (rkda); - } -if (sect >= RK_NUMSC) { /* bad sector? */ - rk_set_done (RKER_NXS); - return; - } -if (cyl >= RK_NUMCY) { /* bad cyl? */ - rk_set_done (RKER_NXC); - return; - } -i = abs (cyl - uptr->CYL) * rk_swait; /* seek time */ -if (func == RKCS_SEEK) { /* seek? */ - rk_set_done (0); /* set done */ - sim_activate (uptr, MAX (RK_MIN, i)); /* schedule */ - } -else sim_activate (uptr, i + rk_rwait); -uptr->FUNC = func; /* save func */ -uptr->CYL = cyl; /* put on cylinder */ -return; -} - -/* Service unit timeout - - If seek in progress, complete seek command - Else complete data transfer command - - The unit control block contains the function and disk address for - the current command. -*/ - -t_stat rk_svc (UNIT *uptr) -{ -int32 i, drv, err, awc, wc, cma, cda, t; -int32 da, cyl, track, sect; -uint32 ma; -RKCONTR comp; - -drv = (int32) (uptr - rk_dev.units); /* get drv number */ -if (uptr->FUNC == RKCS_SEEK) { /* seek */ - rkcs = rkcs | RKCS_SCP; /* set seek done */ - if (rkcs & CSR_IE) { /* ints enabled? */ - rkintq = rkintq | RK_SCPI (drv); /* queue request */ - if (rkcs & CSR_DONE) - SET_INT (RK); - } - else { - rkintq = 0; /* clear queue */ - 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); - } -sect = GET_SECT (rkda); /* get sector, cyl */ -cyl = GET_CYL (rkda); -if (sect >= RK_NUMSC) { /* bad sector? */ - rk_set_done (RKER_NXS); - return SCPE_OK; - } -if (cyl >= RK_NUMCY) { /* bad cyl? */ - rk_set_done (RKER_NXC); - return SCPE_OK; - } -ma = ((rkcs & RKCS_MEX) << (16 - RKCS_V_MEX)) | rkba; /* get mem addr */ -da = GET_DA (rkda) * RK_NUMWD; /* get disk addr */ -wc = 0200000 - rkwc; /* get wd cnt */ -if ((da + wc) > (int32) uptr->capac) { /* overrun? */ - wc = uptr->capac - da; /* trim transfer */ - rker = rker | RKER_OVR; /* set overrun err */ - } - -err = fseek (uptr->fileref, da * sizeof (RKCONTR), SEEK_SET); -if (wc && (err == 0)) { /* seek ok? */ - switch (uptr->FUNC) { /* case on function */ - - case RKCS_READ: /* read */ - if (rkcs & RKCS_FMT) { /* format? */ - for (i = 0, cda = da; i < wc; i++) { /* fill buffer with cyl #s */ - if (cda >= (int32) uptr->capac) { /* overrun? */ - rker = rker | RKER_OVR; /* set overrun err */ - wc = i; /* trim transfer */ - break; - } - rkxb[i] = (uint16)(((cda / RK_NUMWD) / (RK_NUMSF * RK_NUMSC)) << RKDA_V_CYL); - cda = cda + RK_NUMWD; /* next sector */ - } /* end for wc */ - } /* end if format */ - else { /* normal read */ - i = fxread (rkxb, sizeof (RKCONTR), wc, uptr->fileref); - err = ferror (uptr->fileref); /* read file */ - for ( ; i < wc; i++) /* fill buf */ - rkxb[i] = 0; - } - if (rkcs & RKCS_INH) { /* incr inhibit? */ - if ((t = MAP_WRW (ma, 2, &rkxb[wc - 1]))) { /* store last */ - rker = rker | RKER_NXM; /* NXM? set flag */ - wc = 0; /* no transfer */ - } - } - else { /* normal store */ - if ((t = MAP_WRW (ma, wc << 1, rkxb))) { /* store buf */ - rker = rker | RKER_NXM; /* NXM? set flag */ - wc = wc - t; /* adj wd cnt */ - } - } - break; /* end read */ - - case RKCS_WRITE: /* write */ - if (rkcs & RKCS_INH) { /* incr inhibit? */ - if ((t = MAP_RDW (ma, 2, &comp))) { /* get 1st word */ - rker = rker | RKER_NXM; /* NXM? set flag */ - wc = 0; /* no transfer */ - } - for (i = 0; i < wc; i++) /* all words same */ - rkxb[i] = comp; - } - else { /* normal fetch */ - if ((t = MAP_RDW (ma, wc << 1, rkxb))) { /* 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++) /* end of blk */ - rkxb[i] = 0; - fxwrite (rkxb, sizeof (RKCONTR), awc, uptr->fileref); - err = ferror (uptr->fileref); - } - break; /* end write */ - - case RKCS_WCHK: /* write check */ - i = fxread (rkxb, sizeof (RKCONTR), wc, uptr->fileref); - if ((err = ferror (uptr->fileref))) { /* read error? */ - wc = 0; /* no transfer */ - break; - } - for ( ; i < wc; i++) /* fill buf */ - rkxb[i] = 0; - awc = wc; /* save wc */ - for (wc = 0, cma = ma; wc < awc; wc++) { /* loop thru buf */ - if (MAP_RDW (cma, 2, &comp)) { /* 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; - } - if (!(rkcs & RKCS_INH)) /* next mem addr */ - cma = cma + 2; - } /* end for */ - break; /* end wcheck */ - - default: /* read check */ - break; - } /* end switch */ - } /* end else */ - -rkwc = (rkwc + wc) & 0177777; /* final word count */ -if (!(rkcs & RKCS_INH)) /* final byte addr */ - ma = ma + (wc << 1); -rkba = ma & RKBA_IMP; /* lower 16b */ -rkcs = (rkcs & ~RKCS_MEX) | ((ma >> (16 - RKCS_V_MEX)) & RKCS_MEX); -if ((uptr->FUNC == RKCS_READ) && (rkcs & RKCS_FMT)) /* read format? */ - da = da + (wc * RK_NUMWD); /* count by sectors */ -else da = da + wc + (RK_NUMWD - 1); /* count by words */ -track = (da / RK_NUMWD) / RK_NUMSC; -sect = (da / RK_NUMWD) % RK_NUMSC; -rkda = (rkda & RKDA_DRIVE) | (track << RKDA_V_TRACK) | (sect << RKDA_V_SECT); -rk_set_done (0); - -if (err != 0) { /* error? */ - perror ("RK I/O error"); - clearerr (uptr->fileref); - return SCPE_IOERR; - } -return SCPE_OK; -} - -/* Interrupt state change routines - - rk_set_done set done and possibly errors - rk_clr_done clear done - rk_inta acknowledge intererupt -*/ - -void rk_set_done (int32 error) -{ -rkcs = rkcs | CSR_DONE; /* set done */ -if (error != 0) { - rker = rker | error; /* update error */ - if (rker) /* update err flags */ - rkcs = rkcs | RKCS_ERR; - if (rker & RKER_HARD) - rkcs = rkcs | RKCS_HERR; - } -if (rkcs & CSR_IE) { /* int enable? */ - rkintq = rkintq | RK_CTLI; /* set ctrl int */ - SET_INT (RK); /* request int */ - } -else { - rkintq = 0; /* clear queue */ - CLR_INT (RK); - } -return; -} - -void rk_clr_done (void) -{ -rkcs = rkcs & ~CSR_DONE; /* clear done */ -rkintq = rkintq & ~RK_CTLI; /* clear ctl int */ -CLR_INT (RK); /* clear int req */ -return; -} - -int32 rk_inta (void) -{ -int32 i; - -for (i = 0; i <= RK_NUMDR; i++) { /* loop thru intq */ - if (rkintq & (1u << i)) { /* bit i set? */ - rkintq = rkintq & ~(1u << i); /* clear bit i */ - if (rkintq) { /* queue next */ - SET_INT (RK); - } - rkds = (rkds & ~RKDS_ID) | /* id drive */ - (((i == 0)? last_drv: i - 1) << RKDS_V_ID); - return rk_dib.vec; /* return vector */ - } - } -rkintq = 0; /* clear queue */ -return 0; /* passive release */ -} - -/* Device reset */ - -t_stat rk_reset (DEVICE *dptr) -{ -int32 i; -UNIT *uptr; - -rkcs = CSR_DONE; -rkda = rkba = rker = rkds = 0; -rkintq = last_drv = 0; -CLR_INT (RK); -for (i = 0; i < RK_NUMDR; i++) { - uptr = rk_dev.units + i; - sim_cancel (uptr); - uptr->CYL = uptr->FUNC = 0; - uptr->flags = uptr->flags & ~UNIT_SWLK; - } -if (rkxb == NULL) - rkxb = (RKCONTR *) calloc (RK_MAXFR, sizeof (RKCONTR)); -if (rkxb == NULL) - return SCPE_MEM; -return SCPE_OK; -} - -/* Device bootstrap */ - -#if defined (UC15) - -t_stat rk_boot (int32 unitno, DEVICE *dptr) -{ -return SCPE_NOFNC; -} - -#else - -#define BOOT_START 02000 /* start */ -#define BOOT_ENTRY (BOOT_START + 002) /* entry */ -#define BOOT_UNIT (BOOT_START + 010) /* unit number */ -#define BOOT_CSR (BOOT_START + 032) /* CSR */ -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) - -static const uint16 boot_rom[] = { - 0042113, /* "KD" */ - 0012706, BOOT_START, /* MOV #boot_start, SP */ - 0012700, 0000000, /* MOV #unit, R0 ; unit number */ - 0010003, /* MOV R0, R3 */ - 0000303, /* SWAB R3 */ - 0006303, /* ASL R3 */ - 0006303, /* ASL R3 */ - 0006303, /* ASL R3 */ - 0006303, /* ASL R3 */ - 0006303, /* ASL R3 */ - 0012701, 0177412, /* MOV #RKDA, R1 ; csr */ - 0010311, /* MOV R3, (R1) ; load da */ - 0005041, /* CLR -(R1) ; clear ba */ - 0012741, 0177000, /* MOV #-256.*2, -(R1) ; load wc */ - 0012741, 0000005, /* MOV #READ+GO, -(R1) ; read & go */ - 0005002, /* CLR R2 */ - 0005003, /* CLR R3 */ - 0012704, BOOT_START+020, /* MOV #START+20, R4 */ - 0005005, /* CLR R5 */ - 0105711, /* TSTB (R1) */ - 0100376, /* BPL .-2 */ - 0105011, /* CLRB (R1) */ - 0005007 /* CLR PC */ - }; - -t_stat rk_boot (int32 unitno, DEVICE *dptr) -{ -size_t i; -extern uint16 *M; /* memory */ - -for (i = 0; i < BOOT_LEN; i++) - M[(BOOT_START >> 1) + i] = boot_rom[i]; -M[BOOT_UNIT >> 1] = unitno & RK_M_NUMDR; -M[BOOT_CSR >> 1] = (rk_dib.ba & DMASK) + 012; -cpu_set_boot (BOOT_ENTRY); -return SCPE_OK; -} - -#endif \ No newline at end of file diff --git a/PDP11/pdp11_rl.c b/PDP11/pdp11_rl.c deleted file mode 100644 index 2b02d674..00000000 --- a/PDP11/pdp11_rl.c +++ /dev/null @@ -1,1207 +0,0 @@ -/* pdp11_rl.c: RL11 (RLV12) cartridge disk simulator - - Copyright (c) 1993-2013, 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 RL11(RLV12)/RL01/RL02 cartridge disk - - 23-Oct-13 RMS Revised for new boot setup routine - 24-Mar-11 JAD Various changes to support diagnostics, including: - - distinguish between RLV11 & 12 - - more complete drive state - - improved head position tracking - - implement MAINT command of RLV11/12 - - always respect unit disable flag - New commands added: - SHOW RLn DSTATE - SET RLn LOAD/UNLOAD - SET RLn OPEN/CLOSED - SET RLn BRUSH/NOBRUSH - SET RLn ONLINE/OFFLINE - SET RL RLV11/RLV12 (PDP-11 only) - SET RL DEBUG/NODEBUG - 22-Sep-05 RMS Fixed declarations (Sterling Garwood) - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 07-Jul-05 RMS Removed extraneous externs - 30-Sep-04 RMS Revised Unibus interface - 04-Jan-04 RMS Changed sim_fsize calling sequence - 19-May-03 RMS Revised for new conditional compilation scheme - 25-Apr-03 RMS Revised for extended file support - 29-Sep-02 RMS Added variable address support to bootstrap - Added vector change/display support - Revised mapping nomenclature - New data structures - 26-Jan-02 RMS Revised bootstrap to conform to M9312 - 06-Jan-02 RMS Revised enable/disable support - 30-Nov-01 RMS Added read only, extended SET/SHOW support - 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 - 26-Apr-01 RMS Added device enable/disable support - 25-Mar-01 RMS Fixed block fill calculation - 15-Feb-01 RMS Corrected bootstrap string - 12-Nov-97 RMS Added bad block table command - 25-Nov-96 RMS Default units to autosize - 29-Jun-96 RMS Added unit disable support - - The RL11 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 RLV12 is a - controller variant which supports 22b direct addressing. - - 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 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 (VM_PDP10) /* PDP10 version */ -#error "RL11 is not supported on the PDP-10!" - -#elif defined (VM_VAX) /* VAX version */ -#include "vax_defs.h" - -#else /* PDP-11 version */ -#include "pdp11_defs.h" -extern uint32 cpu_opt; -extern UNIT cpu_unit; -#endif - -/* Constants */ - -#define RL_NUMWD (128) /* words/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 (RL_NUMSC * RL_NUMWD) /* max transfer */ -#define RL01_SIZE (RL_NUMCY * RL_NUMSF * RL_NUMSC * RL_NUMWD) /* words/drive */ -#define RL02_SIZE (RL01_SIZE * 2) /* words/drive */ - -/* Device flags */ - -#define DEV_V_RLV11 (DEV_V_UF + 7) /* RLV11 */ -#define DEV_RLV11 (1u << DEV_V_RLV11) - -/* Flags in the unit flags word */ - -#define UNIT_V_WLK (UNIT_V_UF + 0) /* hwre write lock */ -#define UNIT_V_RL02 (UNIT_V_UF + 1) /* RL01 vs RL02 */ -#define UNIT_V_AUTO (UNIT_V_UF + 2) /* autosize enable */ -#define UNIT_V_DUMMY (UNIT_V_UF + 3) /* dummy flag, for SET BADBLOCK */ -#define UNIT_V_OFFL (UNIT_V_UF + 4) /* unit off line */ -#define UNIT_V_BRUSH (UNIT_V_UF + 5) /* unit has brushes */ -#define UNIT_BRUSH (1u << UNIT_V_BRUSH) -#define UNIT_OFFL (1u << UNIT_V_OFFL) -#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 protected */ - -/* Parameters in the unit descriptor */ - -#define TRK u3 /* current track:head:sector */ -#define STAT u4 /* status */ -#define FNC u5 /* function */ - -/* RLDS, NI = not implemented, * = kept in STAT, ^ = kept in TRK , ! = kept in uptr */ - -#define RLDS_M_STATE (07) -#define RLDS_LOAD (0) /* no cartridge */ -#define RLDS_SPIN (1) /* spin-up */ -#define RLDS_BRUSH (2) /* brush cycle *! */ -#define RLDS_HLOAD (3) /* load heads */ -#define RLDS_SEEK (4) /* drive seeking * */ -#define RLDS_LOCK (5) /* lock on * */ -#define RLDS_UNL (6) /* unload heads */ -#define RLDS_DOWN (7) /* spin-down */ -#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_RL02 (0000200) /* RL02 ! */ -#define RLDS_DSE (0000400) /* drv sel err */ -#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 * */ -#define RLDS_WLK (0020000) /* wr locked ! */ -#define RLDS_HCE (0040000) /* hd curr err NI */ -#define RLDS_WDE (0100000) /* wr data err NI */ -#define RLDS_ERR (RLDS_WDE|RLDS_HCE|RLDS_STO|RLDS_SPE|RLDS_WGE| \ - RLDS_VCK|RLDS_DSE) /* errors bits */ - -/* RLCS */ - -#define RLCS_DRDY (0000001) /* drive ready */ -#define RLCS_M_FUNC (0000007) /* function */ -#define RLCS_NOP (0) -#define RLCS_WCHK (1) -#define RLCS_GSTA (2) -#define RLCS_SEEK (3) -#define RLCS_RHDR (4) -#define RLCS_WRITE (5) -#define RLCS_READ (6) -#define RLCS_RNOHDR (7) -#define RLCS_SPECIAL (8) /* internal function, drive state */ -#define RLCS_V_FUNC (1) -#define RLCS_M_MEX (03) /* memory extension */ -#define RLCS_V_MEX (4) -#define RLCS_MEX (RLCS_M_MEX << RLCS_V_MEX) -#define RLCS_M_DRIVE (03) -#define RLCS_V_DRIVE (8) -#define RLCS_INCMP (0002000) /* incomplete */ -#define RLCS_CRC (0004000) /* CRC error */ -#define RLCS_HCRC (RLCS_CRC|RLCS_INCMP) /* header CRC error */ -#define RLCS_DLT (0010000) /* data late */ -#define RLCS_HDE (RLCS_DLT|RLCS_INCMP) /* header not found error */ -#define RLCS_NXM (0020000) /* non-exist memory */ -#define RLCS_PAR (RLCS_NXM|RLCS_INCMP) /* parity error */ -#define RLCS_DRE (0040000) /* drive error */ -#define RLCS_ERR (0100000) /* error summary */ -#define RLCS_ALLERR (RLCS_ERR|RLCS_DRE|RLCS_NXM|RLCS_HDE|RLCS_CRC|RLCS_INCMP) -#define RLCS_RW (0001776) /* read/write */ -#define GET_FUNC(x) (((x) >> RLCS_V_FUNC) & RLCS_M_FUNC) -#define GET_DRIVE(x) (((x) >> RLCS_V_DRIVE) & RLCS_M_DRIVE) - -/* RLDA */ - -#define RLDA_GS (0000002) /* get status */ -#define RLDA_SK_DIR (0000004) /* direction */ -#define RLDA_GS_CLR (0000010) /* clear errors */ -#define RLDA_SK_HD (0000020) /* head select */ - -#define RLDA_V_SECT (0) /* sector */ -#define RLDA_M_SECT (077) -#define RLDA_V_TRACK (6) /* track */ -#define RLDA_M_TRACK (01777) -#define RLDA_HD0 (0 << RLDA_V_TRACK) -#define RLDA_HD1 (1u << RLDA_V_TRACK) -#define RLDA_V_CYL (7) /* cylinder */ -#define RLDA_M_CYL (0777) -#define RLDA_TRACK (RLDA_M_TRACK << RLDA_V_TRACK) -#define RLDA_CYL (RLDA_M_CYL << RLDA_V_CYL) -#define GET_SECT(x) (((x) >> RLDA_V_SECT) & RLDA_M_SECT) -#define GET_CYL(x) (((x) >> RLDA_V_CYL) & RLDA_M_CYL) -#define GET_TRACK(x) (((x) >> RLDA_V_TRACK) & RLDA_M_TRACK) -#define GET_DA(x) ((GET_TRACK (x) * RL_NUMSC) + GET_SECT (x)) - -/* RLBA */ - -#define RLBA_IMP (0177777) /* implemented */ - -/* RLBAE */ - -#define RLBAE_IMP (0000077) /* implemented */ - -extern int32 int_req[IPL_HLVL]; - -uint16 *rlxb = NULL; /* xfer buffer */ -int32 rlcs = 0; /* control/status */ -int32 rlba = 0; /* memory address */ -int32 rlbae = 0; /* mem addr extension */ -int32 rlda = 0; /* disk addr */ -uint16 rlmp = 0, rlmp1 = 0, rlmp2 = 0; /* mp register queue */ -int32 rl_swait = 10; /* seek wait */ -int32 rl_rwait = 10; /* rotate wait */ -int32 rl_stopioe = 1; /* stop on error */ - -/* forward references */ -t_stat rl_rd (int32 *data, int32 PA, int32 access); -t_stat rl_wr (int32 data, int32 PA, int32 access); -t_stat rl_svc (UNIT *uptr); -t_stat rl_reset (DEVICE *dptr); -void rl_set_done (int32 error); -t_stat rl_boot (int32 unitno, DEVICE *dptr); -t_stat rl_attach (UNIT *uptr, char *cptr); -t_stat rl_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc); -static void rlv_maint (void); -t_stat rl_detach (UNIT *uptr); -t_stat rl_set_cover (UNIT *, int32, char *, void *); -t_stat rl_show_cover (FILE *, UNIT *, int32, void *); -t_stat rl_set_load (UNIT *, int32, char *, void *); -t_stat rl_show_load (FILE *, UNIT *, int32, void *); -t_stat rl_show_dstate (FILE *, UNIT *, int32, void *); -#if defined (VM_PDP11) -t_stat rl_set_ctrl (UNIT *uptr, int32 val, char *cptr, void *desc); -#endif -t_stat rl_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc); - -/* RL11 data structures - - rl_dev RL device descriptor - rl_unit RL unit list - rl_reg RL register list - rl_mod RL modifier list -*/ - -static DIB rl_dib = { - IOBA_RL, IOLN_RL, &rl_rd, &rl_wr, - 1, IVCL (RL), VEC_RL, { NULL } }; - -static UNIT rl_unit[] = { - { 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) } - }; - -static const REG rl_reg[] = { - { GRDATA (RLCS, rlcs, DEV_RDX, 16, 0) }, - { GRDATA (RLDA, rlda, DEV_RDX, 16, 0) }, - { GRDATA (RLBA, rlba, DEV_RDX, 16, 0) }, - { GRDATA (RLBAE, rlbae, DEV_RDX, 6, 0) }, - { GRDATA (RLMP, rlmp, DEV_RDX, 16, 0) }, - { GRDATA (RLMP1, rlmp1, DEV_RDX, 16, 0) }, - { GRDATA (RLMP2, rlmp2, DEV_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 }, - { URDATA (CAPAC, rl_unit[0].capac, 10, T_ADDR_W, 0, - RL_NUMDR, PV_LEFT + REG_HRO) }, - { FLDATA (STOP_IOE, rl_stopioe, 0) }, - { GRDATA (DEVADDR, rl_dib.ba, DEV_RDX, 32, 0), REG_HRO }, - { GRDATA (DEVVEC, rl_dib.vec, DEV_RDX, 16, 0), REG_HRO }, - { NULL } - }; - -static const MTAB rl_mod[] = { -#if defined (VM_PDP11) - { MTAB_XTD|MTAB_VDV, (DEV_RLV11|DEV_Q18), "", "RLV11", &rl_set_ctrl, &rl_show_ctrl, NULL}, - { MTAB_XTD|MTAB_VDV, 0, NULL, "RLV12", &rl_set_ctrl, NULL, NULL}, -#endif - { UNIT_OFFL, 0, "on line", "ONLINE", NULL, NULL }, - { UNIT_OFFL, UNIT_OFFL, "off line", "OFFLINE", NULL, NULL }, - { UNIT_BRUSH, 0, NULL, "NOBRUSH", NULL, NULL }, - { UNIT_BRUSH, UNIT_BRUSH, "has brushes", "BRUSH", NULL, NULL }, - - { MTAB_XTD|MTAB_VUN|MTAB_NMO, RLDS_CVO, "open", "OPEN", &rl_set_cover, &rl_show_cover, NULL }, - { MTAB_XTD|MTAB_VUN, 0, NULL, "CLOSED", &rl_set_cover, NULL, NULL }, - { MTAB_XTD|MTAB_VUN|MTAB_NMO, 0, "load", "LOAD", &rl_set_load, &rl_show_load, NULL }, - { MTAB_XTD|MTAB_VUN, 1, NULL, "UNLOAD", &rl_set_load, NULL, NULL }, - { MTAB_XTD|MTAB_VUN|MTAB_NMO, 0, "DSTATE", NULL, NULL, &rl_show_dstate, NULL }, - - { UNIT_WLK, 0, "write enabled", "WRITEENABLED", 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 }, - { MTAB_XTD|MTAB_VDV, 010, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", - &set_vec, &show_vec, NULL }, - { 0 } - }; - -DEVICE rl_dev = { - "RL", (UNIT *) &rl_unit, (REG *) rl_reg, (MTAB *) rl_mod, - RL_NUMDR, DEV_RDX, 24, 1, DEV_RDX, 16, - NULL, NULL, &rl_reset, - &rl_boot, &rl_attach, &rl_detach, - &rl_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS | DEV_DEBUG - }; - -/* Drive states */ -static const char * const state[] = { - "Load Cartridge", "Spin Up", "Brush", "Load Heads", - "Seek", "Lock On", "Unload Heads", "Spin Down" -}; - -/* I/O dispatch routines, I/O addresses 17774400 - 17774411 - - 17774400 RLCS read/write - 17774402 RLBA read/write - 17774404 RLDA read/write - 17774406 RLMP read/write - 17774410 RLBAE read/write -*/ - -t_stat rl_rd (int32 *data, int32 PA, int32 access) -{ -UNIT *uptr; - -switch ((PA >> 1) & 07) { /* decode PA<2:1> */ - - case 0: /* RLCS */ - rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX); -/* -The DRDY signal is sent by the selected drive to indicate that it -is ready to read or write or seek. It is sent when the heads are -not moving and are locked onto a cylinder. This is continuously -monitored by the drive and controller. [EK-0RL11-TD-001, p. 3-8] -Use the DS bits to determine if the drive has any outstanding I/O -operations and set DRDY as appropriate. - -This seems to imply that only a Seek operation (not Read/Write) -causes ready to be false. -*/ - uptr = rl_dev.units + GET_DRIVE (rlcs); - if ((uptr->flags & UNIT_OFFL) || (uptr->STAT & RLDS_VCK)) { - rlcs |= RLCS_DRE; - rlcs &= ~RLCS_DRDY; - } else if (sim_is_active (uptr) || (uptr->flags & UNIT_DIS) || - ((uptr->STAT & RLDS_M_STATE) != RLDS_LOCK)) - rlcs &= ~RLCS_DRDY; - else - rlcs |= RLCS_DRDY; /* see if ready */ -/* -Make sure the error summary bit properly reflects the sum of other -errors. -*/ - if (rlcs & RLCS_ALLERR) - rlcs |= RLCS_ERR; - *data = rlcs; - if (DEBUG_PRS (rl_dev)) - fprintf (sim_deb, ">>RL rd: RLCS %06o\n", rlcs); - break; - - case 1: /* RLBA */ - *data = rlba & RLBA_IMP; - break; - - case 2: /* RLDA */ - *data = rlda; - break; - - case 3: /* RLMP */ - *data = rlmp; - rlmp = rlmp1; /* ripple data */ - rlmp1 = rlmp2; - break; - - case 4: /* RLBAE */ - if (UNIBUS || (rl_dev.flags & DEV_RLV11)) /* not in RL11/RLV11 */ - return SCPE_NXM; - *data = rlbae & RLBAE_IMP; - break; - - default: - return (SCPE_NXM); - } /* end switch */ - -return SCPE_OK; -} - -t_stat rl_wr (int32 data, int32 PA, int32 access) -{ -int32 curr, offs, newc, maxc, tim; -UNIT *uptr; - -switch ((PA >> 1) & 07) { /* decode PA<2:1> */ - - case 0: /* RLCS */ - rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX); - uptr = rl_dev.units + GET_DRIVE (data); /* get new drive */ - if (access == WRITEB) - data = (PA & 1)? (rlcs & 0377) | (data << 8): (rlcs & ~0377) | data; - if (DEBUG_PRS (rl_dev)) - fprintf (sim_deb, ">>RL wr: RLCS %06o new %06o\n", rlcs, data); - rlcs = (rlcs & ~RLCS_RW) | (data & RLCS_RW); - rlbae = (rlbae & ~RLCS_M_MEX) | ((rlcs >> RLCS_V_MEX) & RLCS_M_MEX); -/* -Commands to the controller are only executed with the CRDY (DONE) -bit is cleared by software. If set, check for interrupts and return. -*/ - if (data & CSR_DONE) { /* ready set? */ - if ((data & CSR_IE) == 0) - CLR_INT (RL); - else if ((rlcs & (CSR_DONE + CSR_IE)) == CSR_DONE) - SET_INT (RL); - return SCPE_OK; - } - - CLR_INT (RL); /* clear interrupt */ - rlcs &= ~RLCS_ALLERR; /* clear errors */ - switch (GET_FUNC (rlcs)) { /* case on RLCS<3:1> */ - case RLCS_NOP: /* nop */ - if (!UNIBUS) /* RLV1x has MAINT command */ - rlv_maint (); - rl_set_done (0); - break; - case RLCS_SEEK: /* seek */ - if ((uptr->flags & (UNIT_DIS|UNIT_OFFL)) || (!(uptr->flags & UNIT_ATT))) { - rl_set_done (RLCS_ERR | RLCS_INCMP); - uptr->STAT |= RLDS_STO; - break; - } - curr = GET_CYL (uptr->TRK); /* current cylinder */ - offs = GET_CYL (rlda); /* offset */ - if (rlda & RLDA_SK_DIR) { /* in or out? */ - newc = curr + offs; /* out */ - maxc = (uptr->flags & UNIT_RL02)? - RL_NUMCY * 2: RL_NUMCY; - if (newc >= maxc) - newc = maxc - 1; - } else { - newc = curr - offs; /* in */ - if (newc < 0) - newc = 0; - } - /* enter velocity mode? only if a different cylinder */ - if (newc != curr) - uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_SEEK; /* move the positioner */ -/* TBD: if a head switch, sector should be RL_NUMSC/2? */ - uptr->TRK = (newc << RLDA_V_CYL) | /* put on track */ - ((rlda & RLDA_SK_HD)? RLDA_HD1: RLDA_HD0); -/* -Real timing: -min 6.5ms, max 15ms for head switch, -max 17ms for 1 track seek w/head switch -55ms avg seek -100ms max seek -*/ - tim = abs (newc - curr); - if (tim == 0) - tim++; - tim *= rl_swait; - if (DEBUG_PRS (rl_dev)) - fprintf (sim_deb, ">>RL SEEK: drv %d, dist %d, head sw %d, tim %d\n", - (int32) (uptr - rl_dev.units), - abs (newc - curr), (rlda & RLDA_SK_HD), tim); - uptr->FNC = RLCS_SEEK; - sim_activate (uptr, tim); /* must be > 0 */ - rl_set_done (0); /* ctrlr is ready */ - break; - case RLCS_GSTA: - if (!(rlda & RLDA_GS)) { /* GS bit must be set */ - rl_set_done (RLCS_ERR | RLCS_INCMP); /* OPI; request error */ - return (SCPE_OK); - } - if (rlda & RLDA_GS_CLR) /* reset errors? */ - uptr->STAT &= ~RLDS_ERR; - /* develop drive state */ - rlmp = (uint16)(uptr->STAT | (uptr->TRK & RLDS_HD)); - if (uptr->flags & UNIT_RL02) - rlmp |= RLDS_RL02; - if (uptr->flags & UNIT_WPRT) - rlmp |= RLDS_WLK; - if (uptr->flags & (UNIT_DIS | UNIT_OFFL)) { - rlmp |= RLDS_DSE; - rl_set_done (RLCS_DRE | RLCS_INCMP); - } - rlmp2 = rlmp1 = rlmp; - if (DEBUG_PRS (rl_dev)) - fprintf (sim_deb, ">>RL GSTA: rlds=%06o drv=%ld\n", - rlmp, (long)(uptr - rl_dev.units)); - rl_set_done (0); /* done */ - break; - default: /* data transfer */ - if ((uptr->flags & (UNIT_DIS|UNIT_OFFL)) || (!(uptr->flags & UNIT_ATT))) { - rl_set_done (RLCS_INCMP); - break; - } -/* -EK-0RL11-TD-001, p2-3: "If the CPU software initiates another -operation on a drive that is busy seeking, the controller will -suspend the operation until the seek is completed." - -Check for the condition where there is an outstanding operation but -the program is requesting another operation without waiting for -drive ready. If so, remove the previous queue entry, complete the -operation now, and queue the next operation. -*/ - if (sim_is_active (uptr)) { - sim_cancel (uptr); - rl_svc (uptr); - } - uptr->FNC = GET_FUNC (rlcs); - sim_activate (uptr, rl_swait); /* activate unit */ - break; - } /* end switch func */ - break; /* end case RLCS */ -/* -Contrary to what the RL01/RL02 User Guide (EK-RL012-UG-006, p.4-5) -says, bit 0 can be written and read (as 1) on an RLV12 (verified -2011-01-05). Not sure about the RLV11. -*/ - case 1: /* RLBA */ - if (access == WRITEB) - data = (PA & 1)? (rlba & 0377) | (data << 8): (rlba & ~0377) | data; - rlba = data & (UNIBUS ? 0177776 : 0177777); - if (DEBUG_PRS (rl_dev)) - fprintf (sim_deb, ">>RL wr: RLBA %06o\n", rlba); - break; - - case 2: /* RLDA */ - if (access == WRITEB) - data = (PA & 1)? (rlda & 0377) | (data << 8): (rlda & ~0377) | data; - rlda = data; - if (DEBUG_PRS (rl_dev)) - fprintf (sim_deb, ">>RL wr: RLDA %06o\n", rlda); - break; - - case 3: /* RLMP */ - if (access == WRITEB) - data = (PA & 1)? (rlmp & 0377) | (data << 8): (rlmp & ~0377) | data; - rlmp = rlmp1 = rlmp2 = (uint16)data; - if (DEBUG_PRS (rl_dev)) - fprintf (sim_deb, ">>RL wr: RLMP %06o\n", rlmp); - break; - - case 4: /* RLBAE */ - if (UNIBUS || (rl_dev.flags & DEV_RLV11)) /* not in RL11/RLV11 */ - return SCPE_NXM; - if (PA & 1) - return SCPE_OK; - rlbae = data & RLBAE_IMP; - rlcs = (rlcs & ~RLCS_MEX) | ((rlbae & RLCS_M_MEX) << RLCS_V_MEX); - if (DEBUG_PRS (rl_dev)) - fprintf (sim_deb, ">>RL wr: RLBAE %06o\n", rlbae); - break; - default: - return (SCPE_NXM); - } /* end switch */ - -return SCPE_OK; -} - -/* CRC16 as implemented by the DEC 9401 chip */ -static uint16 calcCRC (const int wc, const uint16 *data) -{ - uint32 crc, j, d; - int32 i; - - crc = 0; - for (i = 0; i < wc; i++) { - d = *data++; - /* cribbed from KG11-A */ - for (j = 0; j < 16; j++) { - crc = (crc & ~01) | ((crc & 01) ^ (d & 01)); - crc = (crc & 01) ? (crc >> 1) ^ 0120001 : crc >> 1; - d >>= 1; - } - } - return (uint16)crc; -} - -/* -Perform the maintenance function of the RLV1x; this is fully described -on pages 4-14 and 4-15 of EK-RL012-UG-006. Note that the description -of this in EK-RLV12-UG-002 (p.5-3) contains a typo, the constant -for -511 is incorrect. -*/ -static void rlv_maint (void) -{ - int32 i; - uint32 ma; - uint16 w; - - if (DEBUG_PRS (rl_dev)) - fprintf (sim_deb, ">>RL maint: RLDA %06o\n", rlda); - /* 1: check internal logic */ - rlda = (rlda & ~0377) | ((rlda + 1) & 0377); - - /* 2: check internal logic */ - rlda = (rlda & ~0377) | ((rlda + 1) & 0377); - - /* 3: check DMA transfers */ - ma = (rlbae << 16) | rlba; /* get mem addr */ - /* xfer 256 words to FIFO */ - if (DEBUG_PRS (rl_dev)) - fprintf (sim_deb, ">>RL maint: RLMP %06o\n", rlmp); - if (rlmp != 0177001) { /* must be exactly -511 */ - rlcs |= RLCS_ERR | RLCS_HDE; /* HNF error */ - return; - } - for (i = 0; i < 256; i++) { - if (Map_ReadW (ma, 2, &rlxb[i])) { /* mem wd */ - rlcs |= RLCS_ERR | RLCS_NXM; /* nxm */ - break; - } - ma += 2; - rlmp++; - } - /* xfer 255 words from FIFO */ - for (i = 0; i < 255; i++) { - if (Map_WriteW (ma, 2, &rlxb[i])) { /* store buffer */ - rlcs |= RLCS_ERR | RLCS_NXM; /* nxm */ - break; - } - ma += 2; - rlmp++; - } - rlda = (rlda & ~0377) | ((rlda + 1) & 0377); - rlbae = (ma >> 16) & RLBAE_IMP; /* upper 6b */ - rlba = ma & RLBA_IMP; /* lower 16b */ - - /* 4: check the CRC of (DAR + 3) */ - w = (uint16)rlda; - rlxb[0] = calcCRC (1, &w); /* calculate CRC */ - rlda = (rlda & ~0377) | ((rlda + 1) & 0377); - - /* 5: check the CRC of (DAR + 4) */ - w = (uint16)rlda; - rlxb[1] = calcCRC (1, &w); /* calculate CRC */ - rlda = (rlda & ~0377) | ((rlda + 1) & 0377); - - /* 6: check the CRC of (CRC of DAR + 4) */ - w = rlxb[1]; - rlxb[1] = calcCRC (1, &w); /* calculate CRC */ - rlmp = rlxb[0]; - rlmp1 = rlxb[1]; - rlda = (rlda & ~0377) | ((rlda + 1) & 0377); -} - -/* 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, maxwc, t; -int32 i, da, awc; -uint32 ma; -uint16 comp; -static const char * const funcname[] = { - "NOP", "WCK", "GSTA", "SEEK", - "RHDR", "WT", "RD", "RNOHDR", "SPECIAL", -}; - -if (DEBUG_PRS (rl_dev)) { - if (uptr->FNC == RLCS_SPECIAL) - fprintf (sim_deb, ">>RL svc: func=SPECIAL(%s) drv=%d\n", - state[uptr->STAT & RLDS_M_STATE], (int32) (uptr - rl_dev.units)); - else - fprintf (sim_deb, ">>RL svc: func=%s drv=%d rlda=%06o\n", - funcname[uptr->FNC], (int32) (uptr - rl_dev.units), rlda); -} - -/* really shouldn't happen... */ -if ((uptr->FNC == RLCS_GSTA) || (uptr->FNC == RLCS_NOP)) { - rl_set_done (0); - return (SCPE_OK); - } - -/* -This situation occurs when the drive (not controller) state needs -to transition from one state to another. The state bits indicate -the state the drive is currently in. -*/ - -if (uptr->FNC == RLCS_SPECIAL) { - switch (uptr->STAT & RLDS_M_STATE) { -/* -The LOAD state is a little different. We can stay in LOAD until -the user hits the RUN (LOAD) button, at which time we should come -here to transition to the next state and begin the startup process. -*/ - case RLDS_LOAD: - /* load pressed, spinning up */ - if (!(uptr->STAT & RLDS_CVO)) { - uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_SPIN; - /* actual time is 45-50 seconds from press to Lock */ - sim_activate (uptr, 200 * rl_swait); - uptr->STAT &= ~RLDS_HDO; - uptr->STAT |= RLDS_BHO; - } - break; -/* -Original RL01 drives would transition to the Brush Cycle, but this -was removed in a later ECO. -*/ - case RLDS_SPIN: /* spun up, load brushes or heads */ - if (uptr->flags & UNIT_BRUSH) { - uptr->STAT &= ~RLDS_BHO; - uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_BRUSH; - } else { - uptr->STAT |= RLDS_BHO; - uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_HLOAD; - } - sim_activate (uptr, 200 * rl_swait); - break; - case RLDS_BRUSH: - uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_HLOAD; - uptr->STAT |= RLDS_BHO; - sim_activate (uptr, 200 * rl_swait); - break; - case RLDS_HLOAD: /* heads loaded, seek to home */ - uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_SEEK; - sim_activate (uptr, 200 * rl_swait); - uptr->STAT |= RLDS_BHO | RLDS_HDO; - uptr->TRK = 0; - break; - case RLDS_SEEK: /* home found, lock on */ - /* enter postion mode */ - uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_LOCK; - /* sim_activate (uptr, rl_swait); */ - break; - case RLDS_LOCK: /* tracking, nothing to do */ - /* illuminate ready lamp */ - break; -/* -Initiated by depressing the Run (LOAD) switch. -*/ - case RLDS_UNL: /* unload pressed, heads unloaded, spin down */ - uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_DOWN; - uptr->STAT &= ~RLDS_HDO; /* retract heads */ - /* actual time is ~30 seconds */ - sim_activate (uptr, 200 * rl_swait); - break; - case RLDS_DOWN: /* OK to open cover */ - uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_LOAD; - uptr->STAT |= RLDS_BHO | RLDS_VCK; - break; - default: - ; /* can't happen */ - } - return (SCPE_OK); -} - -if ((uptr->flags & UNIT_ATT) == 0) { /* attached? */ - uptr->STAT |= RLDS_SPE; /* spin error */ - rl_set_done (RLCS_ERR | RLCS_INCMP); /* flag error */ - return IORETURN (rl_stopioe, SCPE_UNATT); - } - -if ((uptr->FNC == RLCS_WRITE) && (uptr->flags & UNIT_WPRT)) { - uptr->STAT |= RLDS_WGE; /* write and locked */ - rl_set_done (RLCS_ERR | RLCS_DRE); - return SCPE_OK; - } - -if (uptr->FNC == RLCS_SEEK) { /* seek? */ - /* enter position mode */ - uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_LOCK; /* heads locked on cyl */ - return (SCPE_OK); - } - -if (uptr->FNC == RLCS_RHDR) { /* read header? */ - uint16 hdr[2]; - hdr[0] = rlmp = uptr->TRK & 0177777; - hdr[1] = rlmp1 = 0; - rlmp2 = calcCRC (2, &hdr[0]); /* calculate header CRC */ - rl_set_done (0); /* done */ - /* simulate sequential rotation about the current track */ - uptr->TRK = (uptr->TRK & ~RLDA_M_SECT) | - ((uptr->TRK + 1) & RLDA_M_SECT); - if (GET_SECT (uptr->TRK) >= RL_NUMSC) /* end of track? */ - uptr->TRK &= ~RLDA_M_SECT; /* wrap to 0 */ - return (SCPE_OK); - } - -if (uptr->FNC == RLCS_RNOHDR) { - if (GET_SECT (uptr->TRK) >= RL_NUMSC) { - rl_set_done (RLCS_ERR | RLCS_HDE); /* wrong cylinder? */ - return (SCPE_OK); - } - da = GET_DA (uptr->TRK) * RL_NUMWD; /* get disk addr */ - maxwc = (RL_NUMSC - GET_SECT (uptr->TRK)) * RL_NUMWD; /* max transfer */ -} else { - /* bad cyl or sector? */ - if (((uptr->TRK & RLDA_CYL) != (rlda & RLDA_CYL)) || (GET_SECT (rlda) >= RL_NUMSC)) { - rl_set_done (RLCS_ERR | RLCS_HDE | RLCS_INCMP); /* wrong cylinder? */ - return (SCPE_OK); - } - da = GET_DA (rlda) * RL_NUMWD; /* get disk addr */ - maxwc = (RL_NUMSC - GET_SECT (rlda)) * RL_NUMWD; /* max transfer */ -} - -ma = (rlbae << 16) | rlba; /* get mem addr */ -wc = 0200000 - rlmp; /* get true wc */ - -if (wc > maxwc) /* track overrun? */ - wc = maxwc; -err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET); - -if (DEBUG_PRS (rl_dev)) - fprintf (sim_deb, ">>RL svc: cyl %d, sect %d, wc %d, maxwc %d, err %d\n", - GET_CYL (rlda), GET_SECT (rlda), wc, maxwc, err); - - if ((uptr->FNC >= RLCS_READ) && (err == 0)) { /* read (no hdr)? */ - i = fxread (rlxb, sizeof (int16), wc, uptr->fileref); - err = ferror (uptr->fileref); - for ( ; i < wc; i++) /* fill buffer */ - rlxb[i] = 0; - if ((t = Map_WriteW (ma, wc << 1, rlxb))) { /* store buffer */ - rlcs = rlcs | RLCS_ERR | RLCS_NXM; /* nxm */ - wc = wc - t; /* adjust wc */ - } - } /* end read */ - -else -if ((uptr->FNC == RLCS_WRITE) && (err == 0)) { /* write? */ - if ((t = Map_ReadW (ma, wc << 1, rlxb))) { /* 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++) /* end of blk */ - rlxb[i] = 0; - fxwrite (rlxb, sizeof (int16), awc, uptr->fileref); - err = ferror (uptr->fileref); - } - } /* end write */ - -else -if ((uptr->FNC == RLCS_WCHK) && (err == 0)) { /* write check? */ - i = fxread (rlxb, sizeof (int16), wc, uptr->fileref); - err = ferror (uptr->fileref); - for ( ; i < wc; i++) /* fill buffer */ - rlxb[i] = 0; - awc = wc; /* save wc */ - for (wc = 0; (err == 0) && (wc < awc); wc++) { /* loop thru buf */ - if (Map_ReadW (ma + (wc << 1), 2, &comp)) { /* 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 */ - -/* Complete Write Check, Write, Read, Read no header */ -rlmp = (rlmp + wc) & 0177777; /* final word count */ -if (rlmp != 0) /* completed? */ - rlcs |= RLCS_ERR | RLCS_INCMP | RLCS_HDE; - -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); - -/* -If we ran off the end of the track, return 40 in rlda, but keep -track over a legitimate sector (0)? -*/ -rlda += ((wc + (RL_NUMWD - 1)) / RL_NUMWD); -/* update head pos */ -if (uptr->FNC == RLCS_RNOHDR) - uptr->TRK = (uptr->TRK & ~RLDA_M_SECT) | - ((uptr->TRK + ((wc + (RL_NUMWD - 1)) / RL_NUMWD)) & RLDA_M_SECT); -else - uptr->TRK = rlda; -if (GET_SECT (uptr->TRK) >= RL_NUMSC) - uptr->TRK &= ~RLDA_M_SECT; /* wrap to 0 */ - -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) -{ -rlcs |= status | CSR_DONE; /* set done */ -if (rlcs & CSR_IE) - SET_INT (RL); -else CLR_INT (RL); -} - -/* Device reset - - Note that the RL11 does NOT recalibrate its drives on RESET -*/ - -t_stat rl_reset (DEVICE *dptr) -{ -int32 i; -UNIT *uptr; - -rlcs = CSR_DONE; -rlda = rlba = rlbae = rlmp = rlmp1 = rlmp2 = 0; -CLR_INT (RL); -for (i = 0; i < RL_NUMDR; i++) { - uptr = rl_dev.units + i; - sim_cancel (uptr); - uptr->STAT &= ~RLDS_ERR; - } -if (rlxb == NULL) - rlxb = (uint16 *) calloc (RL_MAXFR, sizeof (uint16)); -if (rlxb == NULL) - return SCPE_MEM; -return SCPE_OK; -} - -/* Attach routine */ - -t_stat rl_attach (UNIT *uptr, char *cptr) -{ -uint32 p; -t_stat r; - -uptr->capac = (uptr->flags & UNIT_RL02)? RL02_SIZE: RL01_SIZE; -r = attach_unit (uptr, cptr); /* attach unit */ -if (r != SCPE_OK) /* error? */ - return r; -/* -For compatibility with existing SIMH behavior, set the drive state -as if the load procedure had already executed. -*/ -uptr->TRK = 0; /* cylinder 0 */ -uptr->STAT = RLDS_HDO | RLDS_BHO | RLDS_VCK | RLDS_LOCK; /* new volume */ -if ((p = sim_fsize (uptr->fileref)) == 0) { /* new disk image? */ - if (uptr->flags & UNIT_RO) /* if ro, done */ - return SCPE_OK; - return pdp11_bad_block (uptr, RL_NUMSC, RL_NUMWD); - } -if ((uptr->flags & UNIT_AUTO) == 0) /* autosize? */ - return SCPE_OK; -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; -} - -t_stat rl_detach (UNIT *uptr) -{ -t_stat stat; - -sim_cancel (uptr); -stat = detach_unit (uptr); -uptr->STAT = RLDS_BHO | RLDS_LOAD; -return (stat); -} - -/* 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; -} - -/* Set bad block routine */ - -t_stat rl_set_bad (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -return pdp11_bad_block (uptr, RL_NUMSC, RL_NUMWD); -} - -t_stat rl_set_cover (UNIT *uptr, int32 val, char *cptr, void *desc) -{ - /* allowed only if in LOAD state */ - if ((uptr->STAT & RLDS_M_STATE) != RLDS_LOAD) - return (SCPE_NOFNC); - uptr->STAT = (uptr->STAT & ~RLDS_CVO) | val; - return (SCPE_OK); -} - -t_stat rl_show_cover (FILE *st, UNIT *uptr, int32 val, void *desc) -{ - fprintf (st, "cover %s", (uptr->STAT & RLDS_CVO) ? "open" : "closed"); - return (SCPE_OK); -} - -/* simulate the LOAD button on the drive */ -t_stat rl_set_load (UNIT *uptr, int32 val, char *cptr, void *desc) -{ - if (val == 0) { /* LOAD */ - if (uptr->STAT & RLDS_CVO) /* cover open? */ - return (SCPE_NOFNC); - /* spin error if no cartridge loaded */ - if (!(uptr->flags & UNIT_ATT)) { - uptr->STAT |= RLDS_SPE; - return (SCPE_NOFNC); - } - /* state load? */ - uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_LOAD; - } else { /* UNLOAD */ - if ((uptr->STAT & RLDS_M_STATE) != RLDS_LOCK) - return (SCPE_OK); - uptr->STAT = (uptr->STAT & ~RLDS_M_STATE) | RLDS_UNL; - } - uptr->FNC = RLCS_SPECIAL; - sim_activate (uptr, 10 * rl_swait); - return (SCPE_OK); -} - -t_stat rl_show_load (FILE *st, UNIT *uptr, int32 val, void *desc) -{ - fprintf (st, "load %s", - ((uptr->STAT & RLDS_M_STATE) != RLDS_LOAD) ? "set" : "reset"); - return (SCPE_OK); -} - -t_stat rl_show_dstate (FILE *st, UNIT *uptr, int32 val, void *desc) -{ - int32 cnt; - - fprintf (st, "drive state: %s\n", state[(uptr->STAT & RLDS_M_STATE)]); - fprintf (st, "brushes: %s, heads: %s, cover: %s\n", - (uptr->STAT & RLDS_BHO) ? "home" : "out", - (uptr->STAT & RLDS_HDO) ? "out" : "in", - (uptr->STAT & RLDS_CVO) ? "open" : "closed"); - fprintf (st, "vck:%c, wge:%c, spe:%c\n", - (uptr->STAT & RLDS_VCK) ? '1' : '0', - (uptr->STAT & RLDS_WGE) ? '1' : '0', - (uptr->STAT & RLDS_SPE) ? '1' : '0'); - if (uptr->flags & UNIT_ATT) { - if ((cnt = sim_activate_time (uptr)) != 0) - fprintf (st, "FNC: %d, %d\n", uptr->FNC, cnt); - else - fputs ("FNC: none\n", st); - fprintf (st, "TRK: track=%d, cyl=%d, hd=%c, sect=%d\n", - GET_TRACK (uptr->TRK), GET_CYL (uptr->TRK), - (uptr->TRK & RLDA_HD1) ? '1' : '0', - GET_SECT (uptr->TRK)); - } - return (SCPE_OK); -} - -#if defined (VM_PDP11) - -/* Handle SET RL RLV12|RLV11 */ -t_stat rl_set_ctrl (UNIT *uptr, int32 val, char *cptr, void *desc) -{ - if (UNIBUS) - return (SCPE_NOFNC); - if ((val & DEV_RLV11) && (MEMSIZE > UNIMEMSIZE)) - return (SCPE_NOFNC); - rl_dev.flags = (rl_dev.flags & ~(DEV_RLV11|DEV_Q18)) | val; - return (SCPE_OK); -} - -#endif - -/* SHOW RL will display the controller type */ -t_stat rl_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc) -{ - const char *s = "RLV12"; - - if (UNIBUS) - s = "RL11"; - else if (rl_dev.flags & DEV_RLV11) - s = "RLV11"; - fputs (s, st); - return (SCPE_OK); -} - -/* Device bootstrap */ - -#if defined (VM_PDP11) - -#define BOOT_START 02000 /* start */ -#define BOOT_ENTRY (BOOT_START + 002) /* entry */ -#define BOOT_UNIT (BOOT_START + 010) /* unit number */ -#define BOOT_CSR (BOOT_START + 020) /* CSR */ -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) - -static const uint16 boot_rom[] = { - 0042114, /* "LD" */ - 0012706, BOOT_START, /* MOV #boot_start, SP */ - 0012700, 0000000, /* MOV #unit, R0 */ - 0010003, /* MOV R0, R3 */ - 0000303, /* SWAB R3 */ - 0012701, 0174400, /* MOV #RLCS, R1 ; csr */ - 0012761, 0000013, 0000004, /* MOV #13, 4(R1) ; clr err */ - 0052703, 0000004, /* BIS #4, R3 ; unit+gstat */ - 0010311, /* MOV R3, (R1) ; issue cmd */ - 0105711, /* TSTB (R1) ; wait */ - 0100376, /* BPL .-2 */ - 0105003, /* CLRB R3 */ - 0052703, 0000010, /* BIS #10, R3 ; unit+rdhdr */ - 0010311, /* MOV R3, (R1) ; issue cmd */ - 0105711, /* TSTB (R1) ; wait */ - 0100376, /* BPL .-2 */ - 0016102, 0000006, /* MOV 6(R1), R2 ; get hdr */ - 0042702, 0000077, /* BIC #77, R2 ; clr sector */ - 0005202, /* INC R2 ; magic bit */ - 0010261, 0000004, /* MOV R2, 4(R1) ; seek to 0 */ - 0105003, /* CLRB R3 */ - 0052703, 0000006, /* BIS #6, R3 ; unit+seek */ - 0010311, /* MOV R3, (R1) ; issue cmd */ - 0105711, /* TSTB (R1) ; wait */ - 0100376, /* BPL .-2 */ - 0005061, 0000002, /* CLR 2(R1) ; clr ba */ - 0005061, 0000004, /* CLR 4(R1) ; clr da */ - 0012761, 0177000, 0000006, /* MOV #-512., 6(R1) ; set wc */ - 0105003, /* CLRB R3 */ - 0052703, 0000014, /* BIS #14, R3 ; unit+read */ - 0010311, /* MOV R3, (R1) ; issue cmd */ - 0105711, /* TSTB (R1) ; wait */ - 0100376, /* BPL .-2 */ - 0042711, 0000377, /* BIC #377, (R1) */ - 0005002, /* CLR R2 */ - 0005003, /* CLR R3 */ - 0012704, BOOT_START+020, /* MOV #START+20, R4 */ - 0005005, /* CLR R5 */ - 0005007 /* CLR PC */ - }; - -t_stat rl_boot (int32 unitno, DEVICE *dptr) -{ -size_t i; -extern uint16 *M; - -for (i = 0; i < BOOT_LEN; i++) - M[(BOOT_START >> 1) + i] = boot_rom[i]; -M[BOOT_UNIT >> 1] = unitno & RLCS_M_DRIVE; -M[BOOT_CSR >> 1] = rl_dib.ba & 0177777; -cpu_set_boot (BOOT_ENTRY); -return SCPE_OK; -} - -#else - -t_stat rl_boot (int32 unitno, DEVICE *dptr) -{ -return SCPE_NOFNC; -} - -#endif diff --git a/PDP11/pdp11_rp.c b/PDP11/pdp11_rp.c deleted file mode 100644 index 5fa27e42..00000000 --- a/PDP11/pdp11_rp.c +++ /dev/null @@ -1,1107 +0,0 @@ -/* pdp11_rp.c - RP04/05/06/07 RM02/03/05/80 Massbus disk controller - - Copyright (c) 1993-2017, 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. - - rp RH/RP/RM moving head disks - - 13-Mar-17 RMS Annotated intentional fall through in switch - 23-Oct-13 RMS Revised for new boot setup routine - 08-Dec-12 RMS UNLOAD shouldn't set ATTN (Mark Pizzolato) - 17-May-07 RMS CS1 DVA resides in device, not MBA - 21-Nov-05 RMS Enable/disable device also enables/disables Massbus adapter - 12-Nov-05 RMS Fixed DriveClear, does not clear disk address - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 18-Mar-05 RMS Added attached test to detach routine - 12-Sep-04 RMS Cloned from pdp11_rp.c - - Note: The VMS driver and the RP controller documentation state that - - ER2 = offset 8 - SN = offset 12 - - But the TOPS-10 and TOPS-20 drivers, and the RP schematics state that - - SN = offset 8 - ER2 = offset 12 - - The simulation follows the schematics. The VMS drivers defines but does - not use these offsets, and the error logger follows the schematics. -*/ - -#if defined (VM_PDP10) -#error "PDP-10 uses pdp10_rp.c!" - -#elif defined (VM_PDP11) -#include "pdp11_defs.h" -#define INIT_DTYPE RM03_DTYPE -#define INIT_SIZE RM03_SIZE - -#elif defined (VM_VAX) -#include "vax_defs.h" -#define INIT_DTYPE RP06_DTYPE -#define INIT_SIZE RP06_SIZE -#define DMASK 0xFFFF -#if (!UNIBUS) -#error "Qbus not supported!" -#endif - -#endif - -#include - -#define RP_CTRL 0 /* ctrl is RP */ -#define RM_CTRL 1 /* ctrl is RM */ -#define RP_NUMDR 8 /* #drives */ -#define RP_NUMWD 256 /* words/sector */ -#define RP_MAXFR (1 << 16) /* max transfer */ -#define GET_SECTOR(x,d) ((int) fmod (sim_gtime() / ((double) (x)), \ - ((double) drv_tab[d].sect))) -#define RM_OF (MBA_RMASK + 1) - -/* Flags in the unit flags word */ - -#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_V_DTYPE (UNIT_V_UF + 1) /* disk type */ -#define UNIT_M_DTYPE 7 -#define UNIT_V_AUTO (UNIT_V_UF + 4) /* autosize */ -#define UNIT_V_DUMMY (UNIT_V_UF + 5) /* dummy flag */ -#define UNIT_WLK (1 << UNIT_V_WLK) -#define UNIT_DTYPE (UNIT_M_DTYPE << UNIT_V_DTYPE) -#define UNIT_AUTO (1 << UNIT_V_AUTO) -#define UNIT_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 */ - -#define CYL u3 /* current cylinder */ - -/* RPCS1, RMCS1 - control/status 1 - offset 0 */ - -#define RP_CS1_OF 0 -#define RM_CS1_OF (0 + RM_OF) -#define CS1_GO CSR_GO /* go */ -#define CS1_V_FNC 1 /* function pos */ -#define CS1_M_FNC 037 /* function mask */ -#define CS1_N_FNC (CS1_M_FNC + 1) -#define FNC_NOP 000 /* no operation */ -#define FNC_UNLOAD 001 /* unload */ -#define FNC_SEEK 002 /* seek */ -#define FNC_RECAL 003 /* recalibrate */ -#define FNC_DCLR 004 /* drive clear */ -#define FNC_RELEASE 005 /* port release */ -#define FNC_OFFSET 006 /* offset */ -#define FNC_RETURN 007 /* return to center */ -#define FNC_PRESET 010 /* read-in preset */ -#define FNC_PACK 011 /* pack acknowledge */ -#define FNC_SEARCH 014 /* search */ -#define FNC_XFER 024 /* >=? data xfr */ -#define FNC_WCHK 024 /* write check */ -#define FNC_WRITE 030 /* write */ -#define FNC_WRITEH 031 /* write w/ headers */ -#define FNC_READ 034 /* read */ -#define FNC_READH 035 /* read w/ headers */ -#define CS1_RW 076 -#define CS1_DVA 04000 /* drive avail */ -#define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC) - -/* RPDS, RMDS - drive status - offset 1 */ - -#define RP_DS_OF 1 -#define RM_DS_OF (1 + RM_OF) -#define DS_OFM 0000001 /* offset mode */ -#define DS_VV 0000100 /* volume valid */ -#define DS_RDY 0000200 /* drive ready */ -#define DS_DPR 0000400 /* drive present */ -#define DS_PGM 0001000 /* programable NI */ -#define DS_LST 0002000 /* last sector */ -#define DS_WRL 0004000 /* write locked */ -#define DS_MOL 0010000 /* medium online */ -#define DS_PIP 0020000 /* pos in progress */ -#define DS_ERR 0040000 /* error */ -#define DS_ATA 0100000 /* attention active */ -#define DS_MBZ 0000076 - -/* RPER1, RMER1 - error status 1 - offset 2 */ - -#define RP_ER1_OF 2 -#define RM_ER1_OF (2 + RM_OF) -#define ER1_ILF 0000001 /* illegal func */ -#define ER1_ILR 0000002 /* illegal register */ -#define ER1_RMR 0000004 /* reg mod refused */ -#define ER1_PAR 0000010 /* parity err */ -#define ER1_FER 0000020 /* format err NI */ -#define ER1_WCF 0000040 /* write clk fail NI */ -#define ER1_ECH 0000100 /* ECC hard err NI */ -#define ER1_HCE 0000200 /* hdr comp err NI */ -#define ER1_HCR 0000400 /* hdr CRC err NI */ -#define ER1_AOE 0001000 /* addr ovflo err */ -#define ER1_IAE 0002000 /* invalid addr err */ -#define ER1_WLE 0004000 /* write lock err */ -#define ER1_DTE 0010000 /* drive time err NI */ -#define ER1_OPI 0020000 /* op incomplete */ -#define ER1_UNS 0040000 /* drive unsafe */ -#define ER1_DCK 0100000 /* data check NI */ - -/* RPMR, RMMR - maintenace register - offset 3*/ - -#define RP_MR_OF 3 -#define RM_MR_OF (3 + RM_OF) - -/* RPAS, RMAS - attention summary - offset 4 */ - -#define RP_AS_OF 4 -#define RM_AS_OF (4 + RM_OF) -#define AS_U0 0000001 /* unit 0 flag */ - -/* RPDA, RMDA - sector/track - offset 5 */ - -#define RP_DA_OF 5 -#define RM_DA_OF (5 + RM_OF) -#define DA_V_SC 0 /* sector pos */ -#define DA_M_SC 077 /* sector mask */ -#define DA_V_SF 8 /* track pos */ -#define DA_M_SF 077 /* track mask */ -#define DA_MBZ 0140300 -#define GET_SC(x) (((x) >> DA_V_SC) & DA_M_SC) -#define GET_SF(x) (((x) >> DA_V_SF) & DA_M_SF) - -/* RPDT, RMDT - drive type - offset 6 */ - -#define RP_DT_OF 6 -#define RM_DT_OF (6 + RM_OF) - -/* RPLA, RMLA - look ahead register - offset 7 */ - -#define RP_LA_OF 7 -#define RM_LA_OF (7 + RM_OF) -#define LA_V_SC 6 /* sector pos */ - -/* RPSN, RMSN - serial number - offset 8 */ - -#define RP_SN_OF 8 -#define RM_SN_OF (8 + RM_OF) - -/* RPOF, RMOF - offset register - offset 9 */ - -#define RP_OF_OF 9 -#define RM_OF_OF (9 + RM_OF) -#define OF_HCI 0002000 /* hdr cmp inh NI */ -#define OF_ECI 0004000 /* ECC inhibit NI */ -#define OF_F22 0010000 /* format NI */ -#define OF_MBZ 0161400 - -/* RPDC, RMDC - desired cylinder - offset 10 */ - -#define RP_DC_OF 10 -#define RM_DC_OF (10 + RM_OF) -#define DC_V_CY 0 /* cylinder pos */ -#define DC_M_CY 01777 /* cylinder mask */ -#define DC_MBZ 0176000 -#define GET_CY(x) (((x) >> DC_V_CY) & DC_M_CY) -#define GET_DA(c,fs,d) ((((GET_CY (c) * drv_tab[d].surf) + \ - GET_SF (fs)) * drv_tab[d].sect) + GET_SC (fs)) - -/* RPCC - current cylinder - offset 11 - RMHR - holding register - offset 11 */ - -#define RP_CC_OF 11 -#define RM_HR_OF (11 + RM_OF) - -/* RPER2 - error status 2 - drive unsafe conditions - unimplemented - offset 12 - RMMR2 - maintenance register - unimplemented - offset 12 */ - -#define RP_ER2_OF 12 -#define RM_MR2_OF (12 + RM_OF) - -/* RPER3 - error status 3 - more unsafe conditions - unimplemented - offset 13 - RMER2 - error status 2 - unimplemented - offset 13 */ - -#define RP_ER3_OF 13 -#define RM_ER2_OF (13 + RM_OF) - -/* RPEC1, RMEC1 - ECC status 1 - unimplemented - offset 14 */ - -#define RP_EC1_OF 14 -#define RM_EC1_OF (14 + RM_OF) - -/* RPEC2, RMEC1 - ECC status 2 - unimplemented - offset 15 */ - -#define RP_EC2_OF 15 -#define RM_EC2_OF (15 + RM_OF) - -/* This controller supports many different disk drive types: - - type #sectors/ #surfaces/ #cylinders/ - surface cylinder drive - - RM02/3 32 5 823 =67MB - RP04/5 22 19 411 =88MB - RM80 31 14 559 =124MB - RP06 22 19 815 =176MB - RM05 32 19 823 =256MB - RP07 50 32 630 =516MB - - In theory, each drive can be a different type. The size field in - each unit selects the drive capacity for each drive and thus the - drive type. DISKS MUST BE DECLARED IN ASCENDING SIZE. - - Note: the RP07, despite its designation, belongs to the RM family -*/ - -#define RM03_DTYPE 0 -#define RM03_SECT 32 -#define RM03_SURF 5 -#define RM03_CYL 823 -#define RM03_DEV 020024 -#define RM03_SIZE (RM03_SECT * RM03_SURF * RM03_CYL * RP_NUMWD) - -#define RP04_DTYPE 1 -#define RP04_SECT 22 -#define RP04_SURF 19 -#define RP04_CYL 411 -#define RP04_DEV 020020 -#define RP04_SIZE (RP04_SECT * RP04_SURF * RP04_CYL * RP_NUMWD) - -#define RM80_DTYPE 2 -#define RM80_SECT 31 -#define RM80_SURF 14 -#define RM80_CYL 559 -#define RM80_DEV 020026 -#define RM80_SIZE (RM80_SECT * RM80_SURF * RM80_CYL * RP_NUMWD) - -#define RP06_DTYPE 3 -#define RP06_SECT 22 -#define RP06_SURF 19 -#define RP06_CYL 815 -#define RP06_DEV 020022 -#define RP06_SIZE (RP06_SECT * RP06_SURF * RP06_CYL * RP_NUMWD) - -#define RM05_DTYPE 4 -#define RM05_SECT 32 -#define RM05_SURF 19 -#define RM05_CYL 823 -#define RM05_DEV 020027 -#define RM05_SIZE (RM05_SECT * RM05_SURF * RM05_CYL * RP_NUMWD) - -#define RP07_DTYPE 5 -#define RP07_SECT 50 -#define RP07_SURF 32 -#define RP07_CYL 630 -#define RP07_DEV 020042 -#define RP07_SIZE (RP07_SECT * RP07_SURF * RP07_CYL * RP_NUMWD) - -struct drvtyp { - int32 sect; /* sectors */ - int32 surf; /* surfaces */ - int32 cyl; /* cylinders */ - int32 size; /* #blocks */ - int32 devtype; /* device type */ - int32 ctrl; /* ctrl type */ - }; - -static struct drvtyp drv_tab[] = { - { RM03_SECT, RM03_SURF, RM03_CYL, RM03_SIZE, RM03_DEV, RM_CTRL }, - { RP04_SECT, RP04_SURF, RP04_CYL, RP04_SIZE, RP04_DEV, RP_CTRL }, - { RM80_SECT, RM80_SURF, RM80_CYL, RM80_SIZE, RM80_DEV, RM_CTRL }, - { RP06_SECT, RP06_SURF, RP06_CYL, RP06_SIZE, RP06_DEV, RP_CTRL }, - { RM05_SECT, RM05_SURF, RM05_CYL, RM05_SIZE, RM05_DEV, RM_CTRL }, - { RP07_SECT, RP07_SURF, RP07_CYL, RP07_SIZE, RP07_DEV, RM_CTRL }, - { 0 } - }; - -uint16 *rpxb = NULL; /* xfer buffer */ -uint16 rpcs1[RP_NUMDR] = { 0 }; /* control/status 1 */ -uint16 rpda[RP_NUMDR] = { 0 }; /* track/sector */ -uint16 rpds[RP_NUMDR] = { 0 }; /* drive status */ -uint16 rper1[RP_NUMDR] = { 0 }; /* error status 1 */ -uint16 rmhr[RP_NUMDR] = { 0 }; /* holding reg */ -uint16 rpmr[RP_NUMDR] = { 0 }; /* maint reg */ -uint16 rmmr2[RP_NUMDR] = { 0 }; /* maint reg 2 */ -uint16 rpof[RP_NUMDR] = { 0 }; /* offset */ -uint16 rpdc[RP_NUMDR] = { 0 }; /* cylinder */ -uint16 rper2[RP_NUMDR] = { 0 }; /* error status 2 */ -uint16 rper3[RP_NUMDR] = { 0 }; /* error status 3 */ -uint16 rpec1[RP_NUMDR] = { 0 }; /* ECC correction 1 */ -uint16 rpec2[RP_NUMDR] = { 0 }; /* ECC correction 2 */ -int32 rp_stopioe = 1; /* stop on error */ -int32 rp_swait = 26; /* seek time */ -int32 rp_rwait = 10; /* rotate time */ -static const char *rp_fname[CS1_N_FNC] = { - "NOP", "UNLD", "SEEK", "RECAL", "DCLR", "RLS", "OFFS", "RETN", - "PRESET", "PACK", "12", "13", "SCH", "15", "16", "17", - "20", "21", "22", "23", "WRCHK", "25", "26", "27", - "WRITE", "WRHDR", "32", "33", "READ", "RDHDR", "36", "37" - }; - -t_stat rp_mbrd (int32 *data, int32 ofs, int32 drv); -t_stat rp_mbwr (int32 data, int32 ofs, int32 drv); -t_stat rp_svc (UNIT *uptr); -t_stat rp_reset (DEVICE *dptr); -t_stat rp_attach (UNIT *uptr, char *cptr); -t_stat rp_detach (UNIT *uptr); -t_stat rp_boot (int32 unitno, DEVICE *dptr); -void rp_set_er (int32 flg, int32 drv); -void rp_clr_as (int32 mask); -void rp_update_ds (int32 flg, int32 drv); -t_stat rp_go (int32 drv); -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); -int32 rp_abort (void); - -/* RP data structures - - rp_dev RP device descriptor - rp_unit RP unit list - rp_reg RP register list - rp_mod RP modifier list -*/ - -DIB rp_dib = { MBA_RP, 0, &rp_mbrd, &rp_mbwr, 0, 0, 0, { &rp_abort } }; - -UNIT rp_unit[] = { - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - UNIT_ROABLE+(INIT_DTYPE << UNIT_V_DTYPE), INIT_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - UNIT_ROABLE+(INIT_DTYPE << UNIT_V_DTYPE), INIT_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - UNIT_ROABLE+(INIT_DTYPE << UNIT_V_DTYPE), INIT_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - UNIT_ROABLE+(INIT_DTYPE << UNIT_V_DTYPE), INIT_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - UNIT_ROABLE+(INIT_DTYPE << UNIT_V_DTYPE), INIT_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - UNIT_ROABLE+(INIT_DTYPE << UNIT_V_DTYPE), INIT_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - UNIT_ROABLE+(INIT_DTYPE << UNIT_V_DTYPE), INIT_SIZE) }, - { UDATA (&rp_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_AUTO+ - UNIT_ROABLE+(INIT_DTYPE << UNIT_V_DTYPE), INIT_SIZE) } - }; - -REG rp_reg[] = { - { BRDATA (CS1, rpcs1, DEV_RDX, 16, RP_NUMDR) }, - { BRDATA (DA, rpda, DEV_RDX, 16, RP_NUMDR) }, - { BRDATA (DS, rpds, DEV_RDX, 16, RP_NUMDR) }, - { BRDATA (ER1, rper1, DEV_RDX, 16, RP_NUMDR) }, - { BRDATA (HR, rmhr, DEV_RDX, 16, RP_NUMDR) }, - { BRDATA (OF, rpof, DEV_RDX, 16, RP_NUMDR) }, - { BRDATA (DC, rpdc, DEV_RDX, 16, RP_NUMDR) }, - { BRDATA (ER2, rper2, DEV_RDX, 16, RP_NUMDR) }, - { BRDATA (ER3, rper3, DEV_RDX, 16, RP_NUMDR) }, - { BRDATA (EC1, rpec1, DEV_RDX, 16, RP_NUMDR) }, - { BRDATA (EC2, rpec2, DEV_RDX, 16, RP_NUMDR) }, - { BRDATA (MR, rpmr, DEV_RDX, 16, RP_NUMDR) }, - { BRDATA (MR2, rmmr2, DEV_RDX, 16, RP_NUMDR) }, - { DRDATA (STIME, rp_swait, 24), REG_NZ + PV_LEFT }, - { DRDATA (RTIME, rp_rwait, 24), REG_NZ + PV_LEFT }, - { URDATA (CAPAC, rp_unit[0].capac, 10, T_ADDR_W, 0, - RP_NUMDR, PV_LEFT | REG_HRO) }, - { FLDATA (STOP_IOE, rp_stopioe, 0) }, - { GRDATA (CTRLTYPE, rp_dib.lnt, DEV_RDX, 16, 0), REG_HRO }, - { NULL } - }; - -MTAB rp_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "MASSBUS", "MASSBUS", NULL, &mba_show_num }, - { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, - { UNIT_DUMMY, 0, NULL, "BADBLOCK", &rp_set_bad }, - { (UNIT_DTYPE+UNIT_ATT), (RM03_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, - "RM03", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (RP04_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, - "RP04", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (RM80_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, - "RM80", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (RP06_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, - "RP06", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (RM05_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, - "RM05", NULL, NULL }, - { (UNIT_DTYPE+UNIT_ATT), (RP07_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, - "RP07", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RM03_DTYPE << UNIT_V_DTYPE), - "RM03", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RP04_DTYPE << UNIT_V_DTYPE), - "RP04", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RM80_DTYPE << UNIT_V_DTYPE), - "RM80", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RP06_DTYPE << UNIT_V_DTYPE), - "RP06", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RM05_DTYPE << UNIT_V_DTYPE), - "RM05", NULL, NULL }, - { (UNIT_AUTO+UNIT_DTYPE+UNIT_ATT), (RP07_DTYPE << UNIT_V_DTYPE), - "RP07", NULL, NULL }, - { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL }, - { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL }, - { (UNIT_AUTO+UNIT_DTYPE), (RM03_DTYPE << UNIT_V_DTYPE), - NULL, "RM03", &rp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (RP04_DTYPE << UNIT_V_DTYPE), - NULL, "RP04", &rp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (RM80_DTYPE << UNIT_V_DTYPE), - NULL, "RM80", &rp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (RP06_DTYPE << UNIT_V_DTYPE), - NULL, "RP06", &rp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (RM05_DTYPE << UNIT_V_DTYPE), - NULL, "RM05", &rp_set_size }, - { (UNIT_AUTO+UNIT_DTYPE), (RP07_DTYPE << UNIT_V_DTYPE), - NULL, "RP07", &rp_set_size }, - { 0 } - }; - -DEVICE rp_dev = { - "RP", rp_unit, rp_reg, rp_mod, - RP_NUMDR, DEV_RDX, 30, 1, DEV_RDX, 16, - NULL, NULL, &rp_reset, - &rp_boot, &rp_attach, &rp_detach, - &rp_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS | DEV_MBUS | DEV_DEBUG - }; - -/* Massbus register read */ - -t_stat rp_mbrd (int32 *data, int32 ofs, int32 drv) -{ -uint32 val, dtype, i; -UNIT *uptr; - -rp_update_ds (0, drv); /* update ds */ -uptr = rp_dev.units + drv; /* get unit */ -if (uptr->flags & UNIT_DIS) { /* nx disk */ - *data = 0; - return MBE_NXD; - } -dtype = GET_DTYPE (uptr->flags); /* get drive type */ -ofs = ofs & MBA_RMASK; /* mask offset */ -if (drv_tab[dtype].ctrl == RM_CTRL) /* RM? convert */ - ofs = ofs + RM_OF; - -switch (ofs) { /* decode offset */ - - case RP_CS1_OF: case RM_CS1_OF: /* RPCS1 */ - val = (rpcs1[drv] & CS1_RW) | CS1_DVA; /* DVA always set */ - break; - - case RP_DA_OF: case RM_DA_OF: /* RPDA */ - val = rpda[drv] = rpda[drv] & ~DA_MBZ; - break; - - case RP_DS_OF: case RM_DS_OF: /* RPDS */ - val = rpds[drv]; - break; - - case RP_ER1_OF: case RM_ER1_OF: /* RPER1 */ - val = rper1[drv]; - break; - - case RP_AS_OF: case RM_AS_OF: /* RPAS */ - val = 0; - for (i = 0; i < RP_NUMDR; i++) { - if (rpds[i] & DS_ATA) - val |= (AS_U0 << i); - } - break; - - case RP_LA_OF: case RM_LA_OF: /* RPLA */ - val = GET_SECTOR (rp_rwait, dtype) << LA_V_SC; - break; - - case RP_MR_OF: case RM_MR_OF: /* RPMR */ - val = rpmr[drv]; - break; - - case RP_DT_OF: case RM_DT_OF: /* RPDT */ - val = drv_tab[dtype].devtype; - break; - - case RP_SN_OF: case RM_SN_OF: /* RPSN */ - val = 020 | (drv + 1); - break; - - case RP_OF_OF: case RM_OF_OF: /* RPOF */ - val = rpof[drv] = rpof[drv] & ~OF_MBZ; - break; - - case RP_DC_OF: case RM_DC_OF: /* RPDC */ - val = rpdc[drv] = rpdc[drv] & ~DC_MBZ; - break; - - case RP_CC_OF: /* RPCC */ - val = rp_unit[drv].CYL; - break; - - case RP_ER2_OF: case RM_ER2_OF: /* RPER2 */ - val = rper2[drv]; - break; - - case RP_ER3_OF: /* RPER3 */ - val = rper3[drv]; - break; - - case RP_EC1_OF: case RM_EC1_OF: /* RPEC1 */ - val = rpec1[drv]; - break; - - case RP_EC2_OF: case RM_EC2_OF: /* RPEC2 */ - val = rpec2[drv]; - break; - - case RM_HR_OF: /* RMHR */ - val = rmhr[drv] ^ DMASK; - break; - - case RM_MR2_OF: /* RHMR2 */ - val = rmmr2[drv]; - break; - - default: /* all others */ - *data = 0; - return MBE_NXR; - } - -*data = val; -return SCPE_OK; -} - -/* Massbus register write */ - -t_stat rp_mbwr (int32 data, int32 ofs, int32 drv) -{ -int32 dtype; -UNIT *uptr; - -uptr = rp_dev.units + drv; /* get unit */ -if (uptr->flags & UNIT_DIS) /* nx disk */ - return MBE_NXD; -if ((ofs != RP_AS_OF) && sim_is_active (uptr)) { /* unit busy? */ - rp_set_er (ER1_RMR, drv); /* won't write */ - rp_update_ds (0, drv); - return SCPE_OK; - } -rmhr[drv] = data; /* save write */ -dtype = GET_DTYPE (uptr->flags); /* get drive type */ -ofs = ofs & MBA_RMASK; /* mask offset */ -if (drv_tab[dtype].ctrl == RM_CTRL) /* RM? convert */ - ofs = ofs + RM_OF; - -switch (ofs) { /* decode PA<5:1> */ - - case RP_CS1_OF: case RM_CS1_OF: /* RPCS1 */ - rpcs1[drv] = data & CS1_RW; - if (data & CS1_GO) /* start op */ - return rp_go (drv); - break; - - case RP_DA_OF: case RM_DA_OF: /* RPDA */ - rpda[drv] = data & ~DA_MBZ; - break; - - case RP_AS_OF: case RM_AS_OF: /* RPAS */ - rp_clr_as (data); - break; - - case RP_MR_OF: case RM_MR_OF: /* RPMR */ - rpmr[drv] = data; - break; - - case RP_OF_OF: case RM_OF_OF: /* RPOF */ - rpof[drv] = data & ~OF_MBZ; - break; - - case RP_DC_OF: case RM_DC_OF: /* RPDC */ - rpdc[drv] = data & ~DC_MBZ; - break; - - case RM_MR2_OF: /* RMMR2 */ - rmmr2[drv] = data; - break; - - case RP_ER1_OF: case RM_ER1_OF: /* RPER1 */ - case RP_DS_OF: case RM_DS_OF: /* RPDS */ - case RP_LA_OF: case RM_LA_OF: /* RPLA */ - case RP_DT_OF: case RM_DT_OF: /* RPDT */ - case RP_SN_OF: case RM_SN_OF: /* RPSN */ - case RP_CC_OF: /* RPCC */ - case RP_ER2_OF: case RM_ER2_OF: /* RPER2 */ - case RP_ER3_OF: /* RPER3 */ - case RP_EC1_OF: case RM_EC1_OF: /* RPEC1 */ - case RP_EC2_OF: case RM_EC2_OF: /* RPEC2 */ - case RM_HR_OF: /* RMHR */ - break; /* read only */ - - default: /* all others */ - return MBE_NXR; - } /* end switch */ - -rp_update_ds (0, drv); /* update status */ -return SCPE_OK; -} - -/* Initiate operation - unit not busy, function set */ - -t_stat rp_go (int32 drv) -{ -int32 dc, fnc, dtype, t; -UNIT *uptr; - -fnc = GET_FNC (rpcs1[drv]); /* get function */ -if (DEBUG_PRS (rp_dev)) - fprintf (sim_deb, ">>RP%d STRT: fnc=%s, ds=%o, cyl=%o, da=%o, er=%o\n", - drv, rp_fname[fnc], rpds[drv], rpdc[drv], rpda[drv], rper1[drv]); -uptr = rp_dev.units + drv; /* get unit */ -rp_clr_as (AS_U0 << drv); /* clear attention */ -dtype = GET_DTYPE (uptr->flags); /* get drive type */ -dc = rpdc[drv]; /* assume seek, sch */ -if ((fnc != FNC_DCLR) && (rpds[drv] & DS_ERR)) { /* err & ~clear? */ - rp_set_er (ER1_ILF, drv); /* not allowed */ - rp_update_ds (DS_ATA, drv); /* set attention */ - return MBE_GOE; - } - -switch (fnc) { /* case on function */ - - case FNC_DCLR: /* drive clear */ - rper1[drv] = rper2[drv] = rper3[drv] = 0; /* clear errors */ - rpec2[drv] = 0; /* clear EC2 */ - if (drv_tab[dtype].ctrl == RM_CTRL) /* RM? */ - rpmr[drv] = 0; /* clear maint */ - else rpec1[drv] = 0; /* RP, clear EC1 */ - case FNC_NOP: /* no operation */ - case FNC_RELEASE: /* port release */ - return SCPE_OK; - - case FNC_PRESET: /* read-in preset */ - rpdc[drv] = 0; /* clear disk addr */ - rpda[drv] = 0; - rpof[drv] = 0; /* clear offset */ - case FNC_PACK: /* pack acknowledge */ - rpds[drv] = rpds[drv] | DS_VV; /* set volume valid */ - return SCPE_OK; - - case FNC_OFFSET: /* offset mode */ - case FNC_RETURN: - if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ - rp_set_er (ER1_UNS, drv); /* unsafe */ - break; - } - rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */ - sim_activate (uptr, rp_swait); /* time operation */ - return SCPE_OK; - - case FNC_UNLOAD: /* unload */ - if (drv_tab[dtype].ctrl == RM_CTRL) { /* RM? */ - rp_set_er (ER1_ILF, drv); /* not supported */ - break; - } - rp_detach (uptr); /* detach unit */ - return SCPE_OK; - - case FNC_RECAL: /* recalibrate */ - dc = 0; /* seek to 0 */ - case FNC_SEEK: /* seek */ - case FNC_SEARCH: /* search */ - if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ - rp_set_er (ER1_UNS, drv); /* unsafe */ - break; - } - if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */ - (GET_SF (rpda[drv]) >= drv_tab[dtype].surf) || /* bad surface */ - (GET_SC (rpda[drv]) >= drv_tab[dtype].sect)) { /* or bad sector? */ - rp_set_er (ER1_IAE, drv); - break; - } - rpds[drv] = (rpds[drv] & ~DS_RDY) | DS_PIP; /* set positioning */ - t = abs (dc - uptr->CYL); /* cyl diff */ - if (t == 0) /* min time */ - t = 1; - sim_activate (uptr, rp_swait * t); /* schedule */ - uptr->CYL = dc; /* save cylinder */ - return SCPE_OK; - - case FNC_WRITEH: /* write headers */ - case FNC_WRITE: /* write */ - case FNC_WCHK: /* write check */ - case FNC_READ: /* read */ - case FNC_READH: /* read headers */ - if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ - rp_set_er (ER1_UNS, drv); /* unsafe */ - break; - } - if ((GET_CY (dc) >= drv_tab[dtype].cyl) || /* bad cylinder */ - (GET_SF (rpda[drv]) >= drv_tab[dtype].surf) || /* bad surface */ - (GET_SC (rpda[drv]) >= drv_tab[dtype].sect)) { /* or bad sector? */ - rp_set_er (ER1_IAE, drv); - break; - } - rpds[drv] = rpds[drv] & ~DS_RDY; /* clear drive rdy */ - sim_activate (uptr, rp_rwait + (rp_swait * abs (dc - uptr->CYL))); - uptr->CYL = dc; /* save cylinder */ - return SCPE_OK; - - default: /* all others */ - rp_set_er (ER1_ILF, drv); /* not supported */ - break; - } - -rp_update_ds (DS_ATA, drv); /* set attn, req int */ -return MBE_GOE; -} - -/* Abort opertion - there is a data transfer in progress */ - -int32 rp_abort (void) -{ -return rp_reset (&rp_dev); -} - -/* Service unit timeout - - Complete movement or data transfer command - Unit must exist - can't remove an active unit - Unit must be attached - detach cancels in progress operations -*/ - -t_stat rp_svc (UNIT *uptr) -{ -int32 i, fnc, dtype, drv, err; -int32 wc, abc, awc, mbc, da; - -dtype = GET_DTYPE (uptr->flags); /* get drive type */ -drv = (int32) (uptr - rp_dev.units); /* get drv number */ -da = GET_DA (rpdc[drv], rpda[drv], dtype) * RP_NUMWD; /* get disk addr */ -fnc = GET_FNC (rpcs1[drv]); /* get function */ - -if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ - rp_set_er (ER1_UNS, drv); /* set drive error */ - if (fnc >= FNC_XFER) /* xfr? set done */ - mba_set_don (rp_dib.ba); - rp_update_ds (DS_ATA, drv); /* set attn */ - return (rp_stopioe? SCPE_UNATT: SCPE_OK); - } -rpds[drv] = (rpds[drv] & ~DS_PIP) | DS_RDY; /* change drive status */ - -switch (fnc) { /* case on function */ - - case FNC_OFFSET: /* offset */ - rp_update_ds (DS_OFM | DS_ATA, drv); - break; - - case FNC_RETURN: /* return to centerline */ - rpds[drv] = rpds[drv] & ~DS_OFM; /* clear offset, set attn */ - rp_update_ds (DS_ATA, drv); - break; - - case FNC_UNLOAD: /* unload */ - rp_detach (uptr); /* detach unit */ - break; - - case FNC_RECAL: /* recalibrate */ - case FNC_SEARCH: /* search */ - case FNC_SEEK: /* seek */ - rp_update_ds (DS_ATA, drv); - break; - - case FNC_WRITE: /* write */ - if (uptr->flags & UNIT_WPRT) { /* write locked? */ - rp_set_er (ER1_WLE, drv); /* set drive error */ - mba_set_exc (rp_dib.ba); /* set exception */ - rp_update_ds (DS_ATA, drv); /* set attn */ - return SCPE_OK; - } /* fall through */ - case FNC_WCHK: /* write check */ - case FNC_READ: /* read */ - case FNC_READH: /* read headers */ - err = fseek (uptr->fileref, da * sizeof (int16), SEEK_SET); - mbc = mba_get_bc (rp_dib.ba); /* get byte count */ - wc = (mbc + 1) >> 1; /* convert to words */ - if ((da + wc) > drv_tab[dtype].size) { /* disk overrun? */ - rp_set_er (ER1_AOE, drv); /* set err */ - wc = drv_tab[dtype].size - da; /* trim xfer */ - mbc = wc << 1; /* trim mb count */ - if (da >= drv_tab[dtype].size) { /* none left? */ - mba_set_exc (rp_dib.ba); /* set exception */ - rp_update_ds (DS_ATA, drv); /* set attn */ - break; - } - } - if (fnc == FNC_WRITE) { /* write? */ - abc = mba_rdbufW (rp_dib.ba, mbc, rpxb); /* get buffer */ - wc = (abc + 1) >> 1; /* actual # wds */ - awc = (wc + (RP_NUMWD - 1)) & ~(RP_NUMWD - 1); - for (i = wc; i < awc; i++) /* fill buf */ - rpxb[i] = 0; - if (wc && !err) { /* write buf */ - fxwrite (rpxb, sizeof (uint16), awc, uptr->fileref); - err = ferror (uptr->fileref); - } - } /* end if wr */ - else { /* read or wchk */ - awc = fxread (rpxb, sizeof (uint16), wc, uptr->fileref); - err = ferror (uptr->fileref); - for (i = awc; i < wc; i++) /* fill buf */ - rpxb[i] = 0; - if (fnc == FNC_WCHK) /* write check? */ - mba_chbufW (rp_dib.ba, mbc, rpxb); /* check vs mem */ - else mba_wrbufW (rp_dib.ba, mbc, rpxb); /* store in mem */ - } /* end if read */ - da = da + wc + (RP_NUMWD - 1); - if (da >= drv_tab[dtype].size) - rpds[drv] = rpds[drv] | DS_LST; - da = da / RP_NUMWD; - rpda[drv] = da % drv_tab[dtype].sect; - da = da / drv_tab[dtype].sect; - rpda[drv] = rpda[drv] | ((da % drv_tab[dtype].surf) << DA_V_SF); - rpdc[drv] = da / drv_tab[dtype].surf; - uptr->CYL = rpdc[drv]; - - if (err != 0) { /* error? */ - rp_set_er (ER1_PAR, drv); /* set drive error */ - mba_set_exc (rp_dib.ba); /* set exception */ - rp_update_ds (DS_ATA, drv); - perror ("RP I/O error"); - clearerr (uptr->fileref); - return SCPE_IOERR; - } - - case FNC_WRITEH: /* write headers stub */ - mba_set_don (rp_dib.ba); /* set done */ - rp_update_ds (0, drv); /* update ds */ - break; - } /* end case func */ - -if (DEBUG_PRS (rp_dev)) - fprintf (sim_deb, ">>RP%d DONE: fnc=%s, ds=%o, cyl=%o, da=%o, er=%d\n", - drv, rp_fname[fnc], rpds[drv], rpdc[drv], rpda[drv], rper1[drv]); -return SCPE_OK; -} - -/* Set drive error */ - -void rp_set_er (int32 flag, int32 drv) -{ -rper1[drv] = rper1[drv] | flag; -rpds[drv] = rpds[drv] | DS_ATA; -mba_upd_ata (rp_dib.ba, 1); -return; -} - -/* Clear attention flags */ - -void rp_clr_as (int32 mask) -{ -uint32 i, as; - -for (i = as = 0; i < RP_NUMDR; i++) { - if (mask & (AS_U0 << i)) - rpds[i] &= ~DS_ATA; - if (rpds[i] & DS_ATA) - as = 1; - } -mba_upd_ata (rp_dib.ba, as); -return; -} - -/* Drive status update */ - -void rp_update_ds (int32 flag, int32 drv) -{ -if (rp_unit[drv].flags & UNIT_DIS) - rpds[drv] = rper1[drv] = 0; -else rpds[drv] = (rpds[drv] | DS_DPR) & ~DS_PGM; -if (rp_unit[drv].flags & UNIT_ATT) - rpds[drv] = rpds[drv] | DS_MOL; -else rpds[drv] = rpds[drv] & ~(DS_MOL | DS_VV | DS_RDY); -if (rper1[drv] | rper2[drv] | rper3[drv]) - rpds[drv] = rpds[drv] | DS_ERR; -else rpds[drv] = rpds[drv] & ~DS_ERR; -rpds[drv] = rpds[drv] | flag; -if (flag & DS_ATA) - mba_upd_ata (rp_dib.ba, 1); -return; -} - -/* Device reset */ - -t_stat rp_reset (DEVICE *dptr) -{ -int32 i; -UNIT *uptr; - -mba_set_enbdis (MBA_RP, rp_dev.flags & DEV_DIS); -for (i = 0; i < RP_NUMDR; i++) { - uptr = rp_dev.units + i; - sim_cancel (uptr); - uptr->CYL = 0; - if (uptr->flags & UNIT_ATT) - rpds[i] = (rpds[i] & DS_VV) | DS_DPR | DS_RDY | DS_MOL | - ((uptr->flags & UNIT_WPRT)? DS_WRL: 0); - else if (uptr->flags & UNIT_DIS) - rpds[i] = 0; - else rpds[i] = DS_DPR; - rpcs1[i] = 0; - rper1[i] = 0; - rpof[i] = 0; - rpdc[i] = 0; - rpda[i] = 0; - rpmr[i] = 0; - rper2[i] = 0; - rper3[i] = 0; - rpec1[i] = 0; - rpec2[i] = 0; - rmmr2[i] = 0; - rmhr[i] = 0; - } -if (rpxb == NULL) - rpxb = (uint16 *) calloc (RP_MAXFR, sizeof (uint16)); -if (rpxb == NULL) - return SCPE_MEM; -return SCPE_OK; -} - -/* Device attach */ - -t_stat rp_attach (UNIT *uptr, char *cptr) -{ -int32 drv, i, p; -t_stat r; - -uptr->capac = drv_tab[GET_DTYPE (uptr->flags)].size; -r = attach_unit (uptr, cptr); /* attach unit */ -if (r != SCPE_OK) /* error? */ - return r; -drv = (int32) (uptr - rp_dev.units); /* get drv number */ -rpds[drv] = DS_MOL | DS_RDY | DS_DPR | /* upd drv status */ - ((uptr->flags & UNIT_WPRT)? DS_WRL: 0); -rper1[drv] = 0; -rp_update_ds (DS_ATA, drv); /* upd ctlr status */ - -if ((p = sim_fsize (uptr->fileref)) == 0) { /* new disk image? */ - if (uptr->flags & UNIT_RO) - return SCPE_OK; - return pdp11_bad_block (uptr, - drv_tab[GET_DTYPE (uptr->flags)].sect, RP_NUMWD); - } -if ((uptr->flags & UNIT_AUTO) == 0) /* autosize? */ - return SCPE_OK; -for (i = 0; drv_tab[i].sect != 0; i++) { - if (p <= (drv_tab[i].size * (int) sizeof (int16))) { - uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (i << UNIT_V_DTYPE); - uptr->capac = drv_tab[i].size; - return SCPE_OK; - } - } -return SCPE_OK; -} - -/* Device detach */ - -t_stat rp_detach (UNIT *uptr) -{ -int32 drv; -extern int32 sim_is_running; - -if (!(uptr->flags & UNIT_ATT)) /* attached? */ - return SCPE_OK; -drv = (int32) (uptr - rp_dev.units); /* get drv number */ -rpds[drv] = rpds[drv] & ~(DS_MOL | DS_RDY | DS_WRL | DS_VV | DS_OFM); -if (!sim_is_running) /* from console? */ - rp_update_ds (DS_ATA, drv); /* request intr */ -return detach_unit (uptr); -} - -/* Set size command validation routine */ - -t_stat rp_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 dtype = GET_DTYPE (val); - -if (uptr->flags & UNIT_ATT) - return SCPE_ALATT; -uptr->capac = drv_tab[dtype].size; -return SCPE_OK; -} - -/* Set bad block routine */ - -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); -} - -/* Boot routine */ - -#if defined (VM_PDP11) - -#define BOOT_START 02000 /* start */ -#define BOOT_ENTRY (BOOT_START + 002) /* entry */ -#define BOOT_UNIT (BOOT_START + 010) /* unit number */ -#define BOOT_CSR (BOOT_START + 014) /* CSR */ -#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint16)) - -static const uint16 boot_rom[] = { - 0042102, /* "BD" */ - 0012706, BOOT_START, /* mov #boot_start, sp */ - 0012700, 0000000, /* mov #unit, r0 */ - 0012701, 0176700, /* mov #RPCS1, r1 */ - 0012761, 0000040, 0000010, /* mov #CS2_CLR, 10(r1) ; reset */ - 0010061, 0000010, /* mov r0, 10(r1) ; set unit */ - 0012711, 0000021, /* mov #RIP+GO, (r1) ; pack ack */ - 0012761, 0010000, 0000032, /* mov #FMT16B, 32(r1) ; 16b mode */ - 0012761, 0177000, 0000002, /* mov #-512., 2(r1) ; set wc */ - 0005061, 0000004, /* clr 4(r1) ; clr ba */ - 0005061, 0000006, /* clr 6(r1) ; clr da */ - 0005061, 0000034, /* clr 34(r1) ; clr cyl */ - 0012711, 0000071, /* mov #READ+GO, (r1) ; read */ - 0105711, /* tstb (r1) ; wait */ - 0100376, /* bpl .-2 */ - 0005002, /* clr R2 */ - 0005003, /* clr R3 */ - 0012704, BOOT_START+020, /* mov #start+020, r4 */ - 0005005, /* clr R5 */ - 0105011, /* clrb (r1) */ - 0005007 /* clr PC */ - }; - -t_stat rp_boot (int32 unitno, DEVICE *dptr) -{ -int32 i; -extern uint16 *M; -UNIT *uptr = rp_dev.units + unitno; - -for (i = 0; i < BOOT_LEN; i++) - M[(BOOT_START >> 1) + i] = boot_rom[i]; -M[BOOT_UNIT >> 1] = unitno & (RP_NUMDR - 1); -M[BOOT_CSR >> 1] = mba_get_csr (rp_dib.ba) & DMASK; -if (drv_tab[GET_DTYPE (uptr->flags)].ctrl == RP_CTRL) - M[BOOT_START >> 1] = 042102; /* "BD" */ -else M[BOOT_START >> 1] = 042122; /* "RD" */ -cpu_set_boot (BOOT_ENTRY); -return SCPE_OK; -} - -#else - -t_stat rp_boot (int32 unitno, DEVICE *dptr) -{ -return SCPE_NOFNC; -} - -#endif diff --git a/PDP11/pdp11_rq.c b/PDP11/pdp11_rq.c deleted file mode 100644 index ffbdb085..00000000 --- a/PDP11/pdp11_rq.c +++ /dev/null @@ -1,2646 +0,0 @@ -/* pdp11_rq.c: MSCP disk controller simulator - - Copyright (c) 2002-2018, 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 - - 28-May-18 RMS Changed to avoid nested comment warnings (Mark Pizzolato) - 23-Oct-13 RMS Revised for new boot setup routine - 17-Mar-13 RMS Fixed bug in ABORT link walk loop (Dave Bryan) - 14-Jan-09 JH Added support for RD32 disc drive - 18-Jun-07 RMS Added UNIT_IDLE flag to timer thread - 31-Oct-05 RMS Fixed address width for large files - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 22-Jul-05 RMS Fixed warning from Solaris C (Doug Gwyn) - 17-Jan-05 RMS Added more RA and RD disks - 31-Oct-04 RMS Added -L switch (LBNs) to RAUSER size specification - 01-Oct-04 RMS Revised Unibus interface - Changed to identify as UDA50 in Unibus configurations - Changed width to be 16b in all configurations - Changed default timing for VAX - 24-Jul-04 RMS VAX controllers luns start with 0 (Andreas Cejna) - 05-Feb-04 RMS Revised for file I/O library - 25-Jan-04 RMS Revised for device debug support - 12-Jan-04 RMS Fixed bug in interrupt control (Tom Evans) - 07-Oct-03 RMS Fixed problem with multiple RAUSER drives - 17-Sep-03 RMS Fixed MB to LBN conversion to be more accurate - 11-Jul-03 RMS Fixed bug in user disk size (Chaskiel M Grundman) - 19-May-03 RMS Revised for new conditional compilation scheme - 25-Apr-03 RMS Revised for extended file support - 14-Mar-03 RMS Fixed variable size interaction with save/restore - 27-Feb-03 RMS Added user-defined drive support - 26-Feb-03 RMS Fixed bug in vector calculation for VAXen - 22-Feb-03 RMS Fixed ordering bug in queue process - 12-Oct-02 RMS Added multicontroller support - 29-Sep-02 RMS Changed addressing to 18b in Unibus mode - Added variable address support to bootstrap - Added vector display support - Fixed status code in HBE error log - Consolidated MSCP/TMSCP header file - New data structures - 16-Aug-02 RMS Removed unused variables (David Hittner) - 04-May-02 RMS Fixed bug in polling loop for queued operations - 26-Mar-02 RMS Fixed bug, reset routine cleared UF_WPH - 09-Mar-02 RMS Adjusted delays for M+ timing bugs - 04-Mar-02 RMS Added delays to initialization for M+, RSTS/E - 16-Feb-02 RMS Fixed bugs in host timeout logic, boot - 26-Jan-02 RMS Revised bootstrap to conform to M9312 - 06-Jan-02 RMS Revised enable/disable support - 30-Dec-01 RMS Revised show routines - 19-Dec-01 RMS Added bigger drives - 17-Dec-01 RMS Added queue process -*/ - -#if defined (VM_PDP10) /* PDP10 version */ -#error "RQDX3 not supported on PDP-10!" - -#elif defined (VM_VAX) /* VAX version */ -#include "vax_defs.h" -#define RQ_QTIME 100 -#define RQ_XTIME 200 -#define OLDPC fault_PC -extern int32 fault_PC; - -#else /* PDP-11 version */ -#include "pdp11_defs.h" -#define RQ_QTIME 200 -#define RQ_XTIME 500 -#define OLDPC MMR2 -extern int32 MMR2; -extern uint32 cpu_opt; -#endif - -#if !defined (RQ_NUMCT) -#define RQ_NUMCT 4 -#elif (RQ_NUMCT > 4) -#error "Assertion failure: RQ_NUMCT exceeds 4" -#endif - -#include "pdp11_uqssp.h" -#include "pdp11_mscp.h" - -#define UF_MSK (UF_CMR|UF_CMW) /* settable flags */ - -#define RQ_SH_MAX 24 /* max display wds */ -#define RQ_SH_PPL 8 /* wds per line */ -#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_SH_ALL 017 /* show all */ - -#define RQ_CLASS 1 /* RQ class */ -#define RQU_UQPM 6 /* UB port model */ -#define RQQ_UQPM 19 /* QB port model */ -#define RQ_UQPM (UNIBUS? RQU_UQPM: RQQ_UQPM) -#define RQU_MODEL 6 /* UB MSCP ctrl model */ -#define RQQ_MODEL 19 /* QB MSCP ctrl model */ -#define RQ_MODEL (UNIBUS? RQU_MODEL: RQQ_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 0x1F -#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 GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & UNIT_M_DTYPE) -#define cpkt u3 /* current packet */ -#define pktq u4 /* packet queue */ -#define uf buf /* settable unit flags */ -#define cnum wait /* controller index */ -#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write prot */ -#define RQ_RMV(u) ((drv_tab[GET_DTYPE (u->flags)].flgs & RQDF_RMV)? \ - UF_RMV: 0) -#define RQ_WPH(u) (((drv_tab[GET_DTYPE (u->flags)].flgs & RQDF_RO) || \ - (u->flags & UNIT_WPRT))? UF_WPH: 0) - -#define CST_S1 0 /* init stage 1 */ -#define CST_S1_WR 1 /* stage 1 wrap */ -#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 ERR 0 /* must be SCPE_OK! */ -#define OK 1 - -#define RQ_TIMER (RQ_NUMDR) -#define RQ_QUEUE (RQ_TIMER + 1) - -/* Internal packet management. The real RQDX3 manages its packets as true - linked lists. However, use of actual addresses in structures won't work - 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; cp defines controller */ - -#define GETP(p,w,f) ((cp->pak[p].d[w] >> w##_V_##f) & w##_M_##f) -#define GETP32(p,w) (((uint32) cp->pak[p].d[w]) | \ - (((uint32) cp->pak[p].d[(w)+1]) << 16)) -#define PUTP32(p,w,x) cp->pak[p].d[w] = (x) & 0xFFFF; \ - cp->pak[p].d[(w)+1] = ((x) >> 16) & 0xFFFF - -/* Disk formats. An RQDX3 disk 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 (x = not implemented): - - 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 - RD32 17 6 820 6 1 4*8 83204 -x RD33 17 7 1170 ? ? ? 138565 - RD53 17 8 1024 8 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. - - RA60 42(+1) 6 1600 6 1 1008 400176 -x RA70 33(+1) 11 1507+ 11 1 ? 547041 - RA81 51(+1) 14 1258 14 1 2856 891072 - RA82 57(+1) 15 1435 15 1 3420 1216665 - RA71 51(+1) 14 1921 14 1 1428 1367310 - RA72 51(+1) 20 1921 20 1 2040 1953300 - RA90 69(+1) 13 2656 13 1 1794 2376153 - RA92 73(+1) 13 3101 13 1 949 2940951 -x RA73 70(+1) 21 2667+ 21 1 ? 3920490 - - Each drive can be a different type. The drive field in the - unit flags specified the drive type and thus, indirectly, - the drive 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 3480 /* cyl 1427-1430 */ -#define RA82_DBN 3480 /* cyl 1431-1434 */ -#define RA82_LBN 1216665 /* 57*15*1423 */ -#define RA82_RCTS 3420 /* cyl 1423-1426 */ -#define RA82_RCTC 1 -#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 2080 /* cyl 1917-1918? */ -#define RA72_DBN 2080 /* cyl 1920-1921? */ -#define RA72_LBN 1953300 /* 51*20*1915 */ -#define RA72_RCTS 2040 /* cyl 1915-1916? */ -#define RA72_RCTC 1 -#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 1820 /* cyl 2651-2652? */ -#define RA90_DBN 1820 /* cyl 2653-2654? */ -#define RA90_LBN 2376153 /* 69*13*2649 */ -#define RA90_RCTS 1794 /* cyl 2649-2650? */ -#define RA90_RCTC 1 -#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 788 -#define RA92_LBN 2940951 /* 73*13*3099 */ -#define RA92_RCTS 949 /* cyl 3099? */ -#define RA92_RCTC 1 -#define RA92_RBN 40287 /* 1 *13*3099 */ -#define RA92_MOD 29 -#define RA92_MED 0x2564105C -#define RA92_FLGS RQDF_SDI - -#define RA8U_DTYPE 12 /* user defined */ -#define RA8U_SECT 57 /* from RA82 */ -#define RA8U_SURF 15 -#define RA8U_CYL 1435 /* from RA82 */ -#define RA8U_TPG RA8U_SURF -#define RA8U_GPC 1 -#define RA8U_XBN 0 -#define RA8U_DBN 0 -#define RA8U_LBN 1216665 /* from RA82 */ -#define RA8U_RCTS 400 -#define RA8U_RCTC 8 -#define RA8U_RBN 21345 -#define RA8U_MOD 11 /* RA82 */ -#define RA8U_MED 0x25641052 /* RA82 */ -#define RA8U_FLGS RQDF_SDI -#define RA8U_MINC 10000 /* min cap LBNs */ -#define RA8U_MAXC 4000000 /* max cap LBNs */ -#define RA8U_EMAXC 2000000000 /* ext max cap */ - -#define RA60_DTYPE 13 /* SDI drive */ -#define RA60_SECT 42 /* +1 spare/track */ -#define RA60_SURF 6 -#define RA60_CYL 1600 /* 0-1587 user */ -#define RA60_TPG RA60_SURF -#define RA60_GPC 1 -#define RA60_XBN 1032 /* cyl 1592-1595 */ -#define RA60_DBN 1032 /* cyl 1596-1599 */ -#define RA60_LBN 400176 /* 42*6*1588 */ -#define RA60_RCTS 1008 /* cyl 1588-1591 */ -#define RA60_RCTC 1 -#define RA60_RBN 9528 /* 1 *6*1588 */ -#define RA60_MOD 4 -#define RA60_MED 0x22A4103C -#define RA60_FLGS (RQDF_RMV | RQDF_SDI) - -#define RA81_DTYPE 14 /* SDI drive */ -#define RA81_SECT 51 /* +1 spare/track */ -#define RA81_SURF 14 -#define RA81_CYL 1258 /* 0-1247 user */ -#define RA81_TPG RA81_SURF -#define RA81_GPC 1 -#define RA81_XBN 2436 /* cyl 1252-1254? */ -#define RA81_DBN 2436 /* cyl 1255-1256? */ -#define RA81_LBN 891072 /* 51*14*1248 */ -#define RA81_RCTS 2856 /* cyl 1248-1251? */ -#define RA81_RCTC 1 -#define RA81_RBN 17472 /* 1 *14*1248 */ -#define RA81_MOD 5 -#define RA81_MED 0x25641051 -#define RA81_FLGS RQDF_SDI - -#define RA71_DTYPE 15 /* SDI drive */ -#define RA71_SECT 51 /* +1 spare/track */ -#define RA71_SURF 14 -#define RA71_CYL 1921 /* 0-1914 user */ -#define RA71_TPG RA71_SURF -#define RA71_GPC 1 -#define RA71_XBN 1456 /* cyl 1917-1918? */ -#define RA71_DBN 1456 /* cyl 1919-1920? */ -#define RA71_LBN 1367310 /* 51*14*1915 */ -#define RA71_RCTS 1428 /* cyl 1915-1916? */ -#define RA71_RCTC 1 -#define RA71_RBN 26810 /* 1 *14*1915 */ -#define RA71_MOD 40 -#define RA71_MED 0x25641047 -#define RA71_FLGS RQDF_SDI - -#define RD32_DTYPE 16 -#define RD32_SECT 17 -#define RD32_SURF 6 -#define RD32_CYL 820 -#define RD32_TPG RD32_SURF -#define RD32_GPC 1 -#define RD32_XBN 54 -#define RD32_DBN 48 -#define RD32_LBN 83204 -#define RD32_RCTS 4 -#define RD32_RCTC 8 -#define RD32_RBN 200 -#define RD32_MOD 15 -#define RD32_MED 0x25644020 -#define RD32_FLGS 0 - -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 */ - uint32 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 */ - char *name; /* name */ - }; - -#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), "RX50" }, { RQ_DRV (RX33), "RX33" }, - { RQ_DRV (RD51), "RD51" }, { RQ_DRV (RD31), "RD31" }, - { RQ_DRV (RD52), "RD52" }, { RQ_DRV (RD53), "RD53" }, - { RQ_DRV (RD54), "RD54" }, { RQ_DRV (RA82), "RA82" }, - { RQ_DRV (RRD40), "RRD40" }, { RQ_DRV (RA72), "RA72" }, - { RQ_DRV (RA90), "RA90" }, { RQ_DRV (RA92), "RA92" }, - { RQ_DRV (RA8U), "RAUSER" }, { RQ_DRV (RA60), "RA60" }, - { RQ_DRV (RA81), "RA81" }, { RQ_DRV (RA71), "RA71" }, - { RQ_DRV (RD32), "RD32" }, - { 0 } - }; - -extern int32 int_req[IPL_HLVL]; -extern int32 tmr_poll, clk_tps; -extern UNIT cpu_unit; - -uint16 *rqxb = NULL; /* xfer buffer */ -int32 rq_itime = 200; /* init time, except */ -int32 rq_itime4 = 10; /* stage 4 */ -int32 rq_qtime = RQ_QTIME; /* queue time */ -int32 rq_xtime = RQ_XTIME; /* transfer time */ - -typedef struct { - uint32 cnum; /* ctrl number */ - uint32 ubase; /* unit base */ - uint32 sa; /* status, addr */ - uint32 saw; /* written data */ - uint32 s1dat; /* S1 data */ - uint32 comm; /* comm region */ - uint32 csta; /* ctrl state */ - uint32 perr; /* last error */ - uint32 cflgs; /* ctrl flags */ - uint32 irq; /* intr request */ - uint32 prgi; /* purge int */ - uint32 pip; /* poll in progress */ - int32 freq; /* free list */ - int32 rspq; /* resp list */ - uint32 pbsy; /* #busy pkts */ - uint32 credits; /* credits */ - uint32 hat; /* host timer */ - uint32 htmo; /* host timeout */ - struct uq_ring cq; /* cmd ring */ - struct uq_ring rq; /* rsp ring */ - struct rqpkt pak[RQ_NPKTS]; /* packet queue */ - } MSC; - -DEVICE rq_dev, rqb_dev, rqc_dev,rqd_dev; - -t_stat rq_rd (int32 *data, int32 PA, int32 access); -t_stat rq_wr (int32 data, int32 PA, int32 access); -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, DEVICE *dptr); -t_stat rq_set_wlk (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat rq_set_type (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat rq_show_type (FILE *st, UNIT *uptr, int32 val, 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 (MSC *cp); -t_bool rq_mscp (MSC *cp, int32 pkt, t_bool q); -t_bool rq_abo (MSC *cp, int32 pkt, t_bool q); -t_bool rq_avl (MSC *cp, int32 pkt, t_bool q); -t_bool rq_fmt (MSC *cp, int32 pkt, t_bool q); -t_bool rq_gcs (MSC *cp, int32 pkt, t_bool q); -t_bool rq_gus (MSC *cp, int32 pkt, t_bool q); -t_bool rq_onl (MSC *cp, int32 pkt, t_bool q); -t_bool rq_rw (MSC *cp, int32 pkt, t_bool q); -t_bool rq_scc (MSC *cp, int32 pkt, t_bool q); -t_bool rq_suc (MSC *cp, int32 pkt, t_bool q); -t_bool rq_plf (MSC *cp, uint32 err); -t_bool rq_dte (MSC *cp, UNIT *uptr, uint32 err); -t_bool rq_hbe (MSC *cp, UNIT *uptr); -t_bool rq_una (MSC *cp, int32 un); -t_bool rq_deqf (MSC *cp, int32 *pkt); -int32 rq_deqh (MSC *cp, int32 *lh); -void rq_enqh (MSC *cp, int32 *lh, int32 pkt); -void rq_enqt (MSC *cp, int32 *lh, int32 pkt); -t_bool rq_getpkt (MSC *cp, int32 *pkt); -t_bool rq_putpkt (MSC *cp, int32 pkt, t_bool qt); -t_bool rq_getdesc (MSC *cp, struct uq_ring *ring, uint32 *desc); -t_bool rq_putdesc (MSC *cp, struct uq_ring *ring, uint32 desc); -int32 rq_rw_valid (MSC *cp, int32 pkt, UNIT *uptr, uint32 cmd); -t_bool rq_rw_end (MSC *cp, UNIT *uptr, uint32 flg, uint32 sts); -void rq_putr (MSC *cp, int32 pkt, uint32 cmd, uint32 flg, - uint32 sts, uint32 lnt, uint32 typ); -void rq_putr_unit (MSC *cp, int32 pkt, UNIT *uptr, uint32 lu, t_bool all); -void rq_setf_unit (MSC *cp, int32 pkt, UNIT *uptr); -void rq_init_int (MSC *cp); -void rq_ring_int (MSC *cp, struct uq_ring *ring); -t_bool rq_fatal (MSC *cp, uint32 err); -UNIT *rq_getucb (MSC *cp, uint32 lu); -int32 rq_map_pa (uint32 pa); -void rq_setint (MSC *cp); -void rq_clrint (MSC *cp); -int32 rq_inta (void); - -/* RQ data structures - - rq_dev RQ device descriptor - rq_unit RQ unit list - rq_reg RQ register list - rq_mod RQ modifier list -*/ - -MSC rq_ctx = { 0 }; - -DIB rq_dib = { - IOBA_RQ, IOLN_RQ, &rq_rd, &rq_wr, - 1, IVCL (RQ), 0, { &rq_inta } - }; - -UNIT rq_unit[] = { - { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ - (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_IDLE|UNIT_DIS, 0) }, - { UDATA (&rq_quesvc, UNIT_DIS, 0) } - }; - -REG rq_reg[] = { - { GRDATA (SA, rq_ctx.sa, DEV_RDX, 16, 0) }, - { GRDATA (SAW, rq_ctx.saw, DEV_RDX, 16, 0) }, - { GRDATA (S1DAT, rq_ctx.s1dat, DEV_RDX, 16, 0) }, - { GRDATA (COMM, rq_ctx.comm, DEV_RDX, 22, 0) }, - { GRDATA (CQBA, rq_ctx.cq.ba, DEV_RDX, 22, 0) }, - { GRDATA (CQLNT, rq_ctx.cq.lnt, DEV_RDX, 8, 2), REG_NZ }, - { GRDATA (CQIDX, rq_ctx.cq.idx, DEV_RDX, 8, 2) }, - { GRDATA (RQBA, rq_ctx.rq.ba, DEV_RDX, 22, 0) }, - { GRDATA (RQLNT, rq_ctx.rq.lnt, DEV_RDX, 8, 2), REG_NZ }, - { GRDATA (RQIDX, rq_ctx.rq.idx, DEV_RDX, 8, 2) }, - { DRDATA (FREE, rq_ctx.freq, 5) }, - { DRDATA (RESP, rq_ctx.rspq, 5) }, - { DRDATA (PBSY, rq_ctx.pbsy, 5) }, - { GRDATA (CFLGS, rq_ctx.cflgs, DEV_RDX, 16, 0) }, - { GRDATA (CSTA, rq_ctx.csta, DEV_RDX, 4, 0) }, - { GRDATA (PERR, rq_ctx.perr, DEV_RDX, 9, 0) }, - { DRDATA (CRED, rq_ctx.credits, 5) }, - { DRDATA (HAT, rq_ctx.hat, 17) }, - { DRDATA (HTMO, rq_ctx.htmo, 17) }, - { FLDATA (PRGI, rq_ctx.prgi, 0), REG_HIDDEN }, - { FLDATA (PIP, rq_ctx.pip, 0), REG_HIDDEN }, - { FLDATA (INT, rq_ctx.irq, 0) }, - { DRDATA (ITIME, rq_itime, 24), PV_LEFT + REG_NZ }, - { DRDATA (I4TIME, rq_itime4, 24), PV_LEFT + REG_NZ }, - { DRDATA (QTIME, rq_qtime, 24), PV_LEFT + REG_NZ }, - { DRDATA (XTIME, rq_xtime, 24), PV_LEFT + REG_NZ }, - { BRDATA (PKTS, rq_ctx.pak, DEV_RDX, 16, RQ_NPKTS * (RQ_PKT_SIZE_W + 1)) }, - { URDATA (CPKT, rq_unit[0].cpkt, 10, 5, 0, RQ_NUMDR, 0) }, - { URDATA (PKTQ, rq_unit[0].pktq, 10, 5, 0, RQ_NUMDR, 0) }, - { URDATA (UFLG, rq_unit[0].uf, DEV_RDX, 16, 0, RQ_NUMDR, 0) }, - { URDATA (CAPAC, rq_unit[0].capac, 10, T_ADDR_W, 0, RQ_NUMDR, PV_LEFT | REG_HRO) }, - { GRDATA (DEVADDR, rq_dib.ba, DEV_RDX, 32, 0), REG_HRO }, - { GRDATA (DEVVEC, rq_dib.vec, DEV_RDX, 16, 0), REG_HRO }, - { DRDATA (DEVLBN, drv_tab[RA8U_DTYPE].lbn, 22), REG_HRO }, - { NULL } - }; - -MTAB rq_mod[] = { - { UNIT_WLK, 0, NULL, "WRITEENABLED", &rq_set_wlk }, - { UNIT_WLK, UNIT_WLK, NULL, "LOCKED", &rq_set_wlk }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, RQ_SH_RI, "RINGS", NULL, - NULL, &rq_show_ctrl, 0 }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, RQ_SH_FR, "FREEQ", NULL, - NULL, &rq_show_ctrl, 0 }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, RQ_SH_RS, "RESPQ", NULL, - NULL, &rq_show_ctrl, 0 }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, RQ_SH_UN, "UNITQ", NULL, - NULL, &rq_show_ctrl, 0 }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, RQ_SH_ALL, "ALL", NULL, - NULL, &rq_show_ctrl, 0 }, - { MTAB_XTD | MTAB_VUN | MTAB_NMO, 0, "UNITQ", NULL, - NULL, &rq_show_unitq, 0 }, - { MTAB_XTD | MTAB_VUN, 0, "WRITE", NULL, - NULL, &rq_show_wlk, NULL }, - { MTAB_XTD | MTAB_VUN, RX50_DTYPE, NULL, "RX50", - &rq_set_type, NULL, NULL }, - { MTAB_XTD | MTAB_VUN, RX33_DTYPE, NULL, "RX33", - &rq_set_type, NULL, NULL }, - { MTAB_XTD | MTAB_VUN, RD31_DTYPE, NULL, "RD31", - &rq_set_type, NULL, NULL }, - { MTAB_XTD | MTAB_VUN, RD32_DTYPE, NULL, "RD32", - &rq_set_type, NULL, NULL }, - { MTAB_XTD | MTAB_VUN, RD51_DTYPE, NULL, "RD51", - &rq_set_type, NULL, NULL }, - { MTAB_XTD | MTAB_VUN, RD52_DTYPE, NULL, "RD52", - &rq_set_type, NULL, NULL }, - { MTAB_XTD | MTAB_VUN, RD53_DTYPE, NULL, "RD53", - &rq_set_type, NULL, NULL }, - { MTAB_XTD | MTAB_VUN, RD54_DTYPE, NULL, "RD54", - &rq_set_type, NULL, NULL }, - { MTAB_XTD | MTAB_VUN, RA60_DTYPE, NULL, "RA60", - &rq_set_type, NULL, NULL }, - { MTAB_XTD | MTAB_VUN, RA81_DTYPE, NULL, "RA81", - &rq_set_type, NULL, NULL }, - { MTAB_XTD | MTAB_VUN, RA82_DTYPE, NULL, "RA82", - &rq_set_type, NULL, NULL }, - { MTAB_XTD | MTAB_VUN, RRD40_DTYPE, NULL, "RRD40", - &rq_set_type, NULL, NULL }, - { MTAB_XTD | MTAB_VUN, RRD40_DTYPE, NULL, "CDROM", - &rq_set_type, NULL, NULL }, - { MTAB_XTD | MTAB_VUN, RA71_DTYPE, NULL, "RA71", - &rq_set_type, NULL, NULL }, - { MTAB_XTD | MTAB_VUN, RA72_DTYPE, NULL, "RA72", - &rq_set_type, NULL, NULL }, - { MTAB_XTD | MTAB_VUN, RA90_DTYPE, NULL, "RA90", - &rq_set_type, NULL, NULL }, - { MTAB_XTD | MTAB_VUN, RA92_DTYPE, NULL, "RA92", - &rq_set_type, NULL, NULL }, - { MTAB_XTD | MTAB_VUN, RA8U_DTYPE, NULL, "RAUSER", - &rq_set_type, NULL, NULL }, - { MTAB_XTD | MTAB_VUN, 0, "TYPE", NULL, - NULL, &rq_show_type, NULL }, -#if defined (VM_PDP11) - { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, NULL }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE", - &set_addr_flt, NULL, NULL }, -#else - { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL, - NULL, &show_addr, NULL }, -#endif - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, - NULL, &show_vec, NULL }, - { 0 } - }; - -DEVICE rq_dev = { - "RQ", rq_unit, rq_reg, rq_mod, - RQ_NUMDR + 2, DEV_RDX, T_ADDR_W, 2, DEV_RDX, 16, - NULL, NULL, &rq_reset, - &rq_boot, &rq_attach, &rq_detach, - &rq_dib, DEV_FLTA | DEV_DISABLE | DEV_UBUS | DEV_QBUS | DEV_DEBUG - }; - -/* RQB data structures - - rqb_dev RQB device descriptor - rqb_unit RQB unit list - rqb_reg RQB register list - rqb_mod RQB modifier list -*/ - -MSC rqb_ctx = { 1 }; - -DIB rqb_dib = { - IOBA_RQB, IOLN_RQB, &rq_rd, &rq_wr, - 1, IVCL (RQ), 0, { &rq_inta } - }; - -UNIT rqb_unit[] = { - { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ - (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, - { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ - (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, - { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ - (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, - { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ - (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, - { UDATA (&rq_tmrsvc, UNIT_DIS, 0) }, - { UDATA (&rq_quesvc, UNIT_DIS, 0) } - }; - -REG rqb_reg[] = { - { GRDATA (SA, rqb_ctx.sa, DEV_RDX, 16, 0) }, - { GRDATA (SAW, rqb_ctx.saw, DEV_RDX, 16, 0) }, - { GRDATA (S1DAT, rqb_ctx.s1dat, DEV_RDX, 16, 0) }, - { GRDATA (COMM, rqb_ctx.comm, DEV_RDX, 22, 0) }, - { GRDATA (CQBA, rqb_ctx.cq.ba, DEV_RDX, 22, 0) }, - { GRDATA (CQLNT, rqb_ctx.cq.lnt, DEV_RDX, 8, 2), REG_NZ }, - { GRDATA (CQIDX, rqb_ctx.cq.idx, DEV_RDX, 8, 2) }, - { GRDATA (RQBA, rqb_ctx.rq.ba, DEV_RDX, 22, 0) }, - { GRDATA (RQLNT, rqb_ctx.rq.lnt, DEV_RDX, 8, 2), REG_NZ }, - { GRDATA (RQIDX, rqb_ctx.rq.idx, DEV_RDX, 8, 2) }, - { DRDATA (FREE, rqb_ctx.freq, 5) }, - { DRDATA (RESP, rqb_ctx.rspq, 5) }, - { DRDATA (PBSY, rqb_ctx.pbsy, 5) }, - { GRDATA (CFLGS, rqb_ctx.cflgs, DEV_RDX, 16, 0) }, - { GRDATA (CSTA, rqb_ctx.csta, DEV_RDX, 4, 0) }, - { GRDATA (PERR, rqb_ctx.perr, DEV_RDX, 9, 0) }, - { DRDATA (CRED, rqb_ctx.credits, 5) }, - { DRDATA (HAT, rqb_ctx.hat, 17) }, - { DRDATA (HTMO, rqb_ctx.htmo, 17) }, - { FLDATA (PRGI, rqb_ctx.prgi, 0), REG_HIDDEN }, - { FLDATA (PIP, rqb_ctx.pip, 0), REG_HIDDEN }, - { FLDATA (INT, rqb_ctx.irq, 0) }, - { BRDATA (PKTS, rqb_ctx.pak, DEV_RDX, 16, RQ_NPKTS * (RQ_PKT_SIZE_W + 1)) }, - { URDATA (CPKT, rqb_unit[0].cpkt, 10, 5, 0, RQ_NUMDR, 0) }, - { URDATA (PKTQ, rqb_unit[0].pktq, 10, 5, 0, RQ_NUMDR, 0) }, - { URDATA (UFLG, rqb_unit[0].uf, DEV_RDX, 16, 0, RQ_NUMDR, 0) }, - { URDATA (CAPAC, rqb_unit[0].capac, 10, 31, 0, RQ_NUMDR, PV_LEFT | REG_HRO) }, - { GRDATA (DEVADDR, rqb_dib.ba, DEV_RDX, 32, 0), REG_HRO }, - { GRDATA (DEVVEC, rqb_dib.vec, DEV_RDX, 16, 0), REG_HRO }, - { NULL } - }; - -DEVICE rqb_dev = { - "RQB", rqb_unit, rqb_reg, rq_mod, - RQ_NUMDR + 2, DEV_RDX, T_ADDR_W, 2, DEV_RDX, 16, - NULL, NULL, &rq_reset, - &rq_boot, &rq_attach, &rq_detach, - &rqb_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG - }; - -/* RQC data structures - - rqc_dev RQC device descriptor - rqc_unit RQC unit list - rqc_reg RQC register list - rqc_mod RQC modifier list -*/ - -MSC rqc_ctx = { 2 }; - -DIB rqc_dib = { - IOBA_RQC, IOLN_RQC, &rq_rd, &rq_wr, - 1, IVCL (RQ), 0, { &rq_inta } - }; - -UNIT rqc_unit[] = { - { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ - (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, - { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ - (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, - { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ - (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, - { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ - (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, - { UDATA (&rq_tmrsvc, UNIT_DIS, 0) }, - { UDATA (&rq_quesvc, UNIT_DIS, 0) } - }; - -REG rqc_reg[] = { - { GRDATA (SA, rqc_ctx.sa, DEV_RDX, 16, 0) }, - { GRDATA (SAW, rqc_ctx.saw, DEV_RDX, 16, 0) }, - { GRDATA (S1DAT, rqc_ctx.s1dat, DEV_RDX, 16, 0) }, - { GRDATA (COMM, rqc_ctx.comm, DEV_RDX, 22, 0) }, - { GRDATA (CQBA, rqc_ctx.cq.ba, DEV_RDX, 22, 0) }, - { GRDATA (CQLNT, rqc_ctx.cq.lnt, DEV_RDX, 8, 2), REG_NZ }, - { GRDATA (CQIDX, rqc_ctx.cq.idx, DEV_RDX, 8, 2) }, - { GRDATA (RQBA, rqc_ctx.rq.ba, DEV_RDX, 22, 0) }, - { GRDATA (RQLNT, rqc_ctx.rq.lnt, DEV_RDX, 8, 2), REG_NZ }, - { GRDATA (RQIDX, rqc_ctx.rq.idx, DEV_RDX, 8, 2) }, - { DRDATA (FREE, rqc_ctx.freq, 5) }, - { DRDATA (RESP, rqc_ctx.rspq, 5) }, - { DRDATA (PBSY, rqc_ctx.pbsy, 5) }, - { GRDATA (CFLGS, rqc_ctx.cflgs, DEV_RDX, 16, 0) }, - { GRDATA (CSTA, rqc_ctx.csta, DEV_RDX, 4, 0) }, - { GRDATA (PERR, rqc_ctx.perr, DEV_RDX, 9, 0) }, - { DRDATA (CRED, rqc_ctx.credits, 5) }, - { DRDATA (HAT, rqc_ctx.hat, 17) }, - { DRDATA (HTMO, rqc_ctx.htmo, 17) }, - { FLDATA (PRGI, rqc_ctx.prgi, 0), REG_HIDDEN }, - { FLDATA (PIP, rqc_ctx.pip, 0), REG_HIDDEN }, - { FLDATA (INT, rqc_ctx.irq, 0) }, - { BRDATA (PKTS, rqc_ctx.pak, DEV_RDX, 16, RQ_NPKTS * (RQ_PKT_SIZE_W + 1)) }, - { URDATA (CPKT, rqc_unit[0].cpkt, 10, 5, 0, RQ_NUMDR, 0) }, - { URDATA (PKTQ, rqc_unit[0].pktq, 10, 5, 0, RQ_NUMDR, 0) }, - { URDATA (UFLG, rqc_unit[0].uf, DEV_RDX, 16, 0, RQ_NUMDR, 0) }, - { URDATA (CAPAC, rqc_unit[0].capac, 10, 31, 0, RQ_NUMDR, PV_LEFT | REG_HRO) }, - { GRDATA (DEVADDR, rqc_dib.ba, DEV_RDX, 32, 0), REG_HRO }, - { GRDATA (DEVVEC, rqc_dib.vec, DEV_RDX, 16, 0), REG_HRO }, - { NULL } - }; - -DEVICE rqc_dev = { - "RQC", rqc_unit, rqc_reg, rq_mod, - RQ_NUMDR + 2, DEV_RDX, T_ADDR_W, 2, DEV_RDX, 16, - NULL, NULL, &rq_reset, - &rq_boot, &rq_attach, &rq_detach, - &rqc_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG - }; - -/* RQD data structures - - rqd_dev RQ device descriptor - rqd_unit RQ unit list - rqd_reg RQ register list - rqd_mod RQ modifier list -*/ - -MSC rqd_ctx = { 3 }; - -DIB rqd_dib = { - IOBA_RQD, IOLN_RQD, &rq_rd, &rq_wr, - 1, IVCL (RQ), 0, { &rq_inta } - }; - -UNIT rqd_unit[] = { - { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ - (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, - { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ - (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, - { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ - (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, - { UDATA (&rq_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+UNIT_ROABLE+ - (RD54_DTYPE << UNIT_V_DTYPE), RQ_SIZE (RD54)) }, - { UDATA (&rq_tmrsvc, UNIT_DIS, 0) }, - { UDATA (&rq_quesvc, UNIT_DIS, 0) } - }; - -REG rqd_reg[] = { - { GRDATA (SA, rqd_ctx.sa, DEV_RDX, 16, 0) }, - { GRDATA (SAW, rqd_ctx.saw, DEV_RDX, 16, 0) }, - { GRDATA (S1DAT, rqd_ctx.s1dat, DEV_RDX, 16, 0) }, - { GRDATA (COMM, rqd_ctx.comm, DEV_RDX, 22, 0) }, - { GRDATA (CQBA, rqd_ctx.cq.ba, DEV_RDX, 22, 0) }, - { GRDATA (CQLNT, rqd_ctx.cq.lnt, DEV_RDX, 8, 2), REG_NZ }, - { GRDATA (CQIDX, rqd_ctx.cq.idx, DEV_RDX, 8, 2) }, - { GRDATA (RQBA, rqd_ctx.rq.ba, DEV_RDX, 22, 0) }, - { GRDATA (RQLNT, rqd_ctx.rq.lnt, DEV_RDX, 8, 2), REG_NZ }, - { GRDATA (RQIDX, rqd_ctx.rq.idx, DEV_RDX, 8, 2) }, - { DRDATA (FREE, rqd_ctx.freq, 5) }, - { DRDATA (RESP, rqd_ctx.rspq, 5) }, - { DRDATA (PBSY, rqd_ctx.pbsy, 5) }, - { GRDATA (CFLGS, rqd_ctx.cflgs, DEV_RDX, 16, 0) }, - { GRDATA (CSTA, rqd_ctx.csta, DEV_RDX, 4, 0) }, - { GRDATA (PERR, rqd_ctx.perr, DEV_RDX, 9, 0) }, - { DRDATA (CRED, rqd_ctx.credits, 5) }, - { DRDATA (HAT, rqd_ctx.hat, 17) }, - { DRDATA (HTMO, rqd_ctx.htmo, 17) }, - { FLDATA (PRGI, rqd_ctx.prgi, 0), REG_HIDDEN }, - { FLDATA (PIP, rqd_ctx.pip, 0), REG_HIDDEN }, - { FLDATA (INT, rqd_ctx.irq, 0) }, - { BRDATA (PKTS, rqd_ctx.pak, DEV_RDX, 16, RQ_NPKTS * (RQ_PKT_SIZE_W + 1)) }, - { URDATA (CPKT, rqd_unit[0].cpkt, 10, 5, 0, RQ_NUMDR, 0) }, - { URDATA (PKTQ, rqd_unit[0].pktq, 10, 5, 0, RQ_NUMDR, 0) }, - { URDATA (UFLG, rqd_unit[0].uf, DEV_RDX, 16, 0, RQ_NUMDR, 0) }, - { URDATA (CAPAC, rqd_unit[0].capac, 10, 31, 0, RQ_NUMDR, PV_LEFT | REG_HRO) }, - { GRDATA (DEVADDR, rqd_dib.ba, DEV_RDX, 32, 0), REG_HRO }, - { GRDATA (DEVVEC, rqd_dib.vec, DEV_RDX, 16, 0), REG_HRO }, - { NULL } - }; - -DEVICE rqd_dev = { - "RQD", rqd_unit, rqd_reg, rq_mod, - RQ_NUMDR + 2, DEV_RDX, T_ADDR_W, 2, DEV_RDX, 16, - NULL, NULL, &rq_reset, - &rq_boot, &rq_attach, &rq_detach, - &rqd_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG - }; - -static DEVICE *rq_devmap[RQ_NUMCT] = { - &rq_dev, &rqb_dev, &rqc_dev, &rqd_dev - }; - -static MSC *rq_ctxmap[RQ_NUMCT] = { - &rq_ctx, &rqb_ctx, &rqc_ctx, &rqd_ctx - }; - -/* I/O dispatch routines, I/O addresses 17772150 - 17772152 - - base + 0 IP read/write - base + 2 SA read/write -*/ - -t_stat rq_rd (int32 *data, int32 PA, int32 access) -{ -int32 cidx = rq_map_pa ((uint32) PA); -MSC *cp = rq_ctxmap[cidx]; -DEVICE *dptr = rq_devmap[cidx]; - -if (cidx < 0) - return SCPE_IERR; -switch ((PA >> 1) & 01) { /* decode PA<1> */ - - case 0: /* IP */ - *data = 0; /* reads zero */ - if (cp->csta == CST_S3_PPB) /* waiting for poll? */ - rq_step4 (cp); - else if (cp->csta == CST_UP) { /* if up */ - if (DEBUG_PRD (dptr)) - fprintf (sim_deb, ">>RQ%c: poll started, PC=%X\n", - 'A' + cp->cnum, OLDPC); - cp->pip = 1; /* poll host */ - sim_activate (dptr->units + RQ_QUEUE, rq_qtime); - } - break; - - case 1: /* SA */ - *data = cp->sa; - break; - } - -return SCPE_OK; -} - -t_stat rq_wr (int32 data, int32 PA, int32 access) -{ -int32 cidx = rq_map_pa ((uint32) PA); -MSC *cp = rq_ctxmap[cidx]; -DEVICE *dptr = rq_devmap[cidx]; - -if (cidx < 0) - return SCPE_IERR; -switch ((PA >> 1) & 01) { /* decode PA<1> */ - - case 0: /* IP */ - rq_reset (rq_devmap[cidx]); /* init device */ - if (DEBUG_PRD (dptr)) - fprintf (sim_deb, ">>RQ%c: initialization started\n", - 'A' + cp->cnum); - break; - - case 1: /* SA */ - cp->saw = data; - if (cp->csta < CST_S4) /* stages 1-3 */ - sim_activate (dptr->units + RQ_QUEUE, rq_itime); - else if (cp->csta == CST_S4) /* stage 4 (fast) */ - sim_activate (dptr->units + RQ_QUEUE, rq_itime4); - break; - } - -return SCPE_OK; -} - -/* Map physical address to device context */ - -int32 rq_map_pa (uint32 pa) -{ -int32 i; -DEVICE *dptr; -DIB *dibp; - -for (i = 0; i < RQ_NUMCT; i++) { /* loop thru ctrls */ - dptr = rq_devmap[i]; /* get device */ - dibp = (DIB *) dptr->ctxt; /* get DIB */ - if ((pa >= dibp->ba) && /* in range? */ - (pa < (dibp->ba + dibp->lnt))) - return i; /* return ctrl idx */ - } -return -1; -} - -/* Transition to step 4 - init communications region */ - -t_bool rq_step4 (MSC *cp) -{ -int32 i, lnt; -uint32 base; -uint16 zero[SA_COMM_MAX >> 1]; - -cp->rq.ioff = SA_COMM_RI; /* set intr offset */ -cp->rq.ba = cp->comm; /* set rsp q base */ -cp->rq.lnt = SA_S1H_RQ (cp->s1dat) << 2; /* get resp q len */ -cp->cq.ioff = SA_COMM_CI; /* set intr offset */ -cp->cq.ba = cp->comm + cp->rq.lnt; /* set cmd q base */ -cp->cq.lnt = SA_S1H_CQ (cp->s1dat) << 2; /* get cmd q len */ -cp->cq.idx = cp->rq.idx = 0; /* clear q idx's */ -if (cp->prgi) - base = cp->comm + SA_COMM_QQ; -else base = cp->comm + SA_COMM_CI; -lnt = cp->comm + cp->cq.lnt + cp->rq.lnt - base; /* comm lnt */ -if (lnt > SA_COMM_MAX) /* paranoia */ - lnt = SA_COMM_MAX; -for (i = 0; i < (lnt >> 1); i++) /* clr buffer */ - zero[i] = 0; -if (Map_WriteW (base, lnt, zero)) /* zero comm area */ - return rq_fatal (cp, PE_QWE); /* error? */ -cp->sa = SA_S4 | (RQ_UQPM << SA_S4C_V_MOD) | /* send step 4 */ - (RQ_SVER << SA_S4C_V_VER); -cp->csta = CST_S4; /* set step 4 */ -rq_init_int (cp); /* poke host */ -return OK; -} - -/* Queue service - invoked when any of the queues (host queue, unit - queues, response queue) require servicing. Also invoked during - initialization to provide some delay to the next step. - - Process at most one item off each unit queue - If the unit queues were empty, process at most one item off the host 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; -UNIT *nuptr; -MSC *cp = rq_ctxmap[uptr->cnum]; -DEVICE *dptr = rq_devmap[uptr->cnum]; -DIB *dibp = (DIB *) dptr->ctxt; - -if (cp->csta < CST_UP) { /* still init? */ - switch (cp->csta) { /* controller state? */ - - case CST_S1: /* need S1 reply */ - if (cp->saw & SA_S1H_VL) { /* valid? */ - if (cp->saw & SA_S1H_WR) { /* wrap? */ - cp->sa = cp->saw; /* echo data */ - cp->csta = CST_S1_WR; /* endless loop */ - } - else { - cp->s1dat = cp->saw; /* save data */ - dibp->vec = (cp->s1dat & SA_S1H_VEC) << 2; /* get vector */ - if (dibp->vec) /* if nz, bias */ - dibp->vec = dibp->vec + VEC_Q; - cp->sa = SA_S2 | SA_S2C_PT | SA_S2C_EC (cp->s1dat); - cp->csta = CST_S2; /* now in step 2 */ - rq_init_int (cp); /* intr if req */ - } - } /* end if valid */ - break; - - case CST_S1_WR: /* wrap mode */ - cp->sa = cp->saw; /* echo data */ - break; - - case CST_S2: /* need S2 reply */ - cp->comm = cp->saw & SA_S2H_CLO; /* get low addr */ - cp->prgi = cp->saw & SA_S2H_PI; /* get purge int */ - cp->sa = SA_S3 | SA_S3C_EC (cp->s1dat); - cp->csta = CST_S3; /* now in step 3 */ - rq_init_int (cp); /* intr if req */ - break; - - case CST_S3: /* need S3 reply */ - cp->comm = ((cp->saw & SA_S3H_CHI) << 16) | cp->comm; - if (cp->saw & SA_S3H_PP) { /* purge/poll test? */ - cp->sa = 0; /* put 0 */ - cp->csta = CST_S3_PPA; /* wait for 0 write */ - } - else rq_step4 (cp); /* send step 4 */ - break; - - case CST_S3_PPA: /* need purge test */ - if (cp->saw) /* data not zero? */ - rq_fatal (cp, PE_PPF); - else cp->csta = CST_S3_PPB; /* wait for poll */ - break; - - case CST_S4: /* need S4 reply */ - if (cp->saw & SA_S4H_GO) { /* go set? */ - if (DEBUG_PRD (dptr)) - fprintf (sim_deb, ">>RQ%c: initialization complete\n", 'A' + cp->cnum); - cp->csta = CST_UP; /* we're up */ - cp->sa = 0; /* clear SA */ - sim_activate (dptr->units + RQ_TIMER, tmr_poll * clk_tps); - if ((cp->saw & SA_S4H_LF) - && cp->perr) rq_plf (cp, cp->perr); - cp->perr = 0; - } - break; - } /* end switch */ - - return SCPE_OK; - } /* end if */ - -for (i = 0; i < RQ_NUMDR; i++) { /* chk unit q's */ - nuptr = dptr->units + i; /* ptr to unit */ - if (nuptr->cpkt || (nuptr->pktq == 0)) - continue; - pkt = rq_deqh (cp, &nuptr->pktq); /* get top of q */ - if (!rq_mscp (cp, pkt, FALSE)) /* process */ - return SCPE_OK; - } -if ((pkt == 0) && cp->pip) { /* polling? */ - if (!rq_getpkt (cp, &pkt)) /* get host pkt */ - return SCPE_OK; - if (pkt) { /* got one? */ - if (DEBUG_PRD (dptr)) { - fprintf (sim_deb, ">>RQ%c: cmd=%04X, mod=%04X, unit=%d, ", - 'A' + cp->cnum, cp->pak[pkt].d[CMD_OPC], - cp->pak[pkt].d[CMD_MOD], cp->pak[pkt].d[CMD_UN]); - fprintf (sim_deb, "bc=%04X%04X, ma=%04X%04X, lbn=%04X%04X\n", - cp->pak[pkt].d[RW_BCH], cp->pak[pkt].d[RW_BCL], - cp->pak[pkt].d[RW_BAH], cp->pak[pkt].d[RW_BAL], - cp->pak[pkt].d[RW_LBNH], cp->pak[pkt].d[RW_LBNL]); - } - if (GETP (pkt, UQ_HCTC, TYP) != UQ_TYP_SEQ) /* seq packet? */ - return rq_fatal (cp, PE_PIE); /* no, term thread */ - cnid = GETP (pkt, UQ_HCTC, CID); /* get conn ID */ - if (cnid == UQ_CID_MSCP) { /* MSCP packet? */ - if (!rq_mscp (cp, pkt, TRUE)) /* proc, q non-seq */ - return SCPE_OK; - } - else if (cnid == UQ_CID_DUP) { /* DUP packet? */ - rq_putr (cp, pkt, OP_END, 0, ST_CMD | I_OPCD, RSP_LNT, UQ_TYP_SEQ); - if (!rq_putpkt (cp, pkt, TRUE)) /* ill cmd */ - return SCPE_OK; - } - else return rq_fatal (cp, PE_ICI); /* no, term thread */ - } /* end if pkt */ - else cp->pip = 0; /* discontinue poll */ - } /* end if pip */ -if (cp->rspq) { /* resp q? */ - pkt = rq_deqh (cp, &cp->rspq); /* get top of q */ - if (!rq_putpkt (cp, pkt, FALSE)) /* send to host */ - return SCPE_OK; - } /* end if resp q */ -if (pkt) /* more to do? */ - sim_activate (uptr, rq_qtime); -return SCPE_OK; /* done */ -} - -/* Clock service (roughly once per second) */ - -t_stat rq_tmrsvc (UNIT *uptr) -{ -int32 i; -UNIT *nuptr; -MSC *cp = rq_ctxmap[uptr->cnum]; -DEVICE *dptr = rq_devmap[uptr->cnum]; - -sim_activate (uptr, tmr_poll * clk_tps); /* reactivate */ -for (i = 0; i < RQ_NUMDR; i++) { /* poll */ - nuptr = dptr->units + i; - if ((nuptr->flags & UNIT_ATP) && /* ATN pending? */ - (nuptr->flags & UNIT_ATT) && /* still online? */ - (cp->cflgs & CF_ATN)) { /* wanted? */ - if (!rq_una (cp, i)) - return SCPE_OK; - } - nuptr->flags = nuptr->flags & ~UNIT_ATP; - } -if ((cp->hat > 0) && (--cp->hat == 0)) /* host timeout? */ - rq_fatal (cp, PE_HAT); /* fatal err */ -return SCPE_OK; -} - -/* MSCP packet handling */ - -t_bool rq_mscp (MSC *cp, int32 pkt, t_bool q) -{ -uint32 sts, cmd = GETP (pkt, CMD_OPC, OPC); - -switch (cmd) { - - case OP_ABO: /* abort */ - return rq_abo (cp, pkt, q); - - case OP_AVL: /* avail */ - return rq_avl (cp, pkt, q); - - case OP_FMT: /* format */ - return rq_fmt (cp, pkt, q); - - case OP_GCS: /* get cmd status */ - return rq_gcs (cp, pkt, q); - - case OP_GUS: /* get unit status */ - return rq_gus (cp, pkt, q); - - case OP_ONL: /* online */ - return rq_onl (cp, pkt, q); - - case OP_SCC: /* set ctrl char */ - return rq_scc (cp, pkt, q); - - case OP_SUC: /* set unit char */ - return rq_suc (cp, pkt, q); - - case OP_ACC: /* access */ - case OP_CMP: /* compare */ - case OP_ERS: /* erase */ - case OP_RD: /* read */ - case OP_WR: /* write */ - return rq_rw (cp, 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 (cp, pkt, cmd, 0, sts, RSP_LNT, UQ_TYP_SEQ); -return rq_putpkt (cp, pkt, TRUE); -} - -/* Abort a command - 1st parameter is ref # of cmd to abort */ - -t_bool rq_abo (MSC *cp, int32 pkt, t_bool q) -{ -uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */ -uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ -uint32 ref = GETP32 (pkt, ABO_REFL); /* cmd ref # */ -int32 tpkt, prv; -UNIT *uptr; -DEVICE *dptr = rq_devmap[cp->cnum]; - -tpkt = 0; /* set no mtch */ -if (uptr = rq_getucb (cp, lu)) { /* get unit */ - if (uptr->cpkt && /* curr pkt? */ - (GETP32 (uptr->cpkt, CMD_REFL) == ref)) { /* match ref? */ - tpkt = uptr->cpkt; /* save match */ - uptr->cpkt = 0; /* gonzo */ - sim_cancel (uptr); /* cancel unit */ - sim_activate (dptr->units + RQ_QUEUE, rq_qtime); - } - else if (uptr->pktq && /* head of q? */ - (GETP32 (uptr->pktq, CMD_REFL) == ref)) { /* match ref? */ - tpkt = uptr->pktq; /* save match */ - uptr->pktq = cp->pak[tpkt].link; /* unlink */ - } - else if (prv = uptr->pktq) { /* srch pkt q */ - while (tpkt = cp->pak[prv].link) { /* walk list */ - if (GETP32 (tpkt, RSP_REFL) == ref) { /* match? unlink */ - cp->pak[prv].link = cp->pak[tpkt].link; - break; - } - prv = tpkt; /* no match, next */ - } - } - if (tpkt) { /* found target? */ - uint32 tcmd = GETP (tpkt, CMD_OPC, OPC); /* get opcode */ - rq_putr (cp, tpkt, tcmd | OP_END, 0, ST_ABO, RSP_LNT, UQ_TYP_SEQ); - if (!rq_putpkt (cp, tpkt, TRUE)) - return ERR; - } - } /* end if unit */ -rq_putr (cp, pkt, cmd | OP_END, 0, ST_SUC, ABO_LNT, UQ_TYP_SEQ); -return rq_putpkt (cp, pkt, TRUE); -} - -/* Unit available - set unit status to available - defer if q'd cmds */ - -t_bool rq_avl (MSC *cp, int32 pkt, t_bool q) -{ -uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */ -uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ -uint32 sts; -UNIT *uptr; - -if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ - if (q && uptr->cpkt) { /* need to queue? */ - rq_enqt (cp, &uptr->pktq, pkt); /* do later */ - return OK; - } - uptr->flags = uptr->flags & ~UNIT_ONL; /* not online */ - uptr->uf = 0; /* clr flags */ - sts = ST_SUC; /* success */ - } -else sts = ST_OFL; /* offline */ -rq_putr (cp, pkt, cmd | OP_END, 0, sts, AVL_LNT, UQ_TYP_SEQ); -return rq_putpkt (cp, pkt, TRUE); -} - -/* Get command status - only interested in active xfr cmd */ - -t_bool rq_gcs (MSC *cp, int32 pkt, t_bool q) -{ -uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */ -uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ -uint32 ref = GETP32 (pkt, GCS_REFL); /* ref # */ -int32 tpkt; -UNIT *uptr; - -if ((uptr = rq_getucb (cp, lu)) && /* valid lu? */ - (tpkt = uptr->cpkt) && /* queued pkt? */ - (GETP32 (tpkt, CMD_REFL) == ref) && /* match ref? */ - (GETP (tpkt, CMD_OPC, OPC) >= OP_ACC)) { /* rd/wr cmd? */ - cp->pak[pkt].d[GCS_STSL] = cp->pak[tpkt].d[RW_WBCL]; - cp->pak[pkt].d[GCS_STSH] = cp->pak[tpkt].d[RW_WBCH]; - } -else { - cp->pak[pkt].d[GCS_STSL] = 0; /* return 0 */ - cp->pak[pkt].d[GCS_STSH] = 0; - } -rq_putr (cp, pkt, cmd | OP_END, 0, ST_SUC, GCS_LNT, UQ_TYP_SEQ); -return rq_putpkt (cp, pkt, TRUE); -} - -/* Get unit status */ - -t_bool rq_gus (MSC *cp, int32 pkt, t_bool q) -{ -uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */ -uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ -uint32 dtyp, sts, rbpar; -UNIT *uptr; - -if (cp->pak[pkt].d[CMD_MOD] & MD_NXU) { /* next unit? */ - if (lu >= (cp->ubase + RQ_NUMDR)) { /* end of range? */ - lu = 0; /* reset to 0 */ - cp->pak[pkt].d[RSP_UN] = lu; - } - } -if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ - if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ - sts = ST_OFL | SB_OFL_NV; /* offl no vol */ - else if (uptr->flags & UNIT_ONL) /* online */ - sts = ST_SUC; - else sts = ST_AVL; /* avail */ - rq_putr_unit (cp, pkt, uptr, lu, FALSE); /* fill unit fields */ - dtyp = GET_DTYPE (uptr->flags); /* get drive type */ - if (drv_tab[dtyp].rcts) /* ctrl bad blk? */ - rbpar = 1; - else rbpar = 0; /* fill geom, bblk */ - cp->pak[pkt].d[GUS_TRK] = drv_tab[dtyp].sect; - cp->pak[pkt].d[GUS_GRP] = drv_tab[dtyp].tpg; - cp->pak[pkt].d[GUS_CYL] = drv_tab[dtyp].gpc; - cp->pak[pkt].d[GUS_UVER] = 0; - cp->pak[pkt].d[GUS_RCTS] = drv_tab[dtyp].rcts; - cp->pak[pkt].d[GUS_RBSC] = - (rbpar << GUS_RB_V_RBNS) | (rbpar << GUS_RB_V_RCTC); - } -else sts = ST_OFL; /* offline */ -cp->pak[pkt].d[GUS_SHUN] = lu; /* shadowing */ -cp->pak[pkt].d[GUS_SHST] = 0; -rq_putr (cp, pkt, cmd | OP_END, 0, sts, GUS_LNT_D, UQ_TYP_SEQ); -return rq_putpkt (cp, pkt, TRUE); -} - -/* Unit online - defer if q'd commands */ - -t_bool rq_onl (MSC *cp, int32 pkt, t_bool q) -{ -uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */ -uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ -uint32 sts; -UNIT *uptr; - -if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ - if (q && uptr->cpkt) { /* need to queue? */ - rq_enqt (cp, &uptr->pktq, pkt); /* do later */ - return OK; - } - if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ - sts = ST_OFL | SB_OFL_NV; /* offl no vol */ - else if (uptr->flags & UNIT_ONL) /* already online? */ - sts = ST_SUC | SB_SUC_ON; - else { /* mark online */ - sts = ST_SUC; - uptr->flags = uptr->flags | UNIT_ONL; - rq_setf_unit (cp, pkt, uptr); /* hack flags */ - } - rq_putr_unit (cp, pkt, uptr, lu, TRUE); /* set fields */ - } -else sts = ST_OFL; /* offline */ -cp->pak[pkt].d[ONL_SHUN] = lu; /* shadowing */ -cp->pak[pkt].d[ONL_SHST] = 0; -rq_putr (cp, pkt, cmd | OP_END, 0, sts, ONL_LNT, UQ_TYP_SEQ); -return rq_putpkt (cp, pkt, TRUE); -} - -/* Set controller characteristics */ - -t_bool rq_scc (MSC *cp, int32 pkt, t_bool q) -{ -int32 sts, cmd; - -if (cp->pak[pkt].d[SCC_MSV]) { /* MSCP ver = 0? */ - sts = ST_CMD | I_VRSN; /* no, lose */ - cmd = 0; - } -else { - sts = ST_SUC; /* success */ - cmd = GETP (pkt, CMD_OPC, OPC); /* get opcode */ - cp->cflgs = (cp->cflgs & CF_RPL) | /* hack ctrl flgs */ - cp->pak[pkt].d[SCC_CFL]; - if (cp->htmo = cp->pak[pkt].d[SCC_TMO]) /* set timeout */ - cp->htmo = cp->htmo + 2; /* if nz, round up */ - cp->pak[pkt].d[SCC_CFL] = cp->cflgs; /* return flags */ - cp->pak[pkt].d[SCC_TMO] = RQ_DCTMO; /* ctrl timeout */ - cp->pak[pkt].d[SCC_VER] = (RQ_HVER << SCC_VER_V_HVER) | - (RQ_SVER << SCC_VER_V_SVER); - cp->pak[pkt].d[SCC_CIDA] = 0; /* ctrl ID */ - cp->pak[pkt].d[SCC_CIDB] = 0; - cp->pak[pkt].d[SCC_CIDC] = 0; - cp->pak[pkt].d[SCC_CIDD] = (RQ_CLASS << SCC_CIDD_V_CLS) | - (RQ_MODEL << SCC_CIDD_V_MOD); - cp->pak[pkt].d[SCC_MBCL] = 0; /* max bc */ - cp->pak[pkt].d[SCC_MBCH] = 0; - } -rq_putr (cp, pkt, cmd | OP_END, 0, sts, SCC_LNT, UQ_TYP_SEQ); -return rq_putpkt (cp, pkt, TRUE); -} - -/* Set unit characteristics - defer if q'd commands */ - -t_bool rq_suc (MSC *cp, int32 pkt, t_bool q) -{ -uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */ -uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ -uint32 sts; -UNIT *uptr; - -if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ - if (q && uptr->cpkt) { /* need to queue? */ - rq_enqt (cp, &uptr->pktq, pkt); /* do later */ - return OK; - } - if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ - sts = ST_OFL | SB_OFL_NV; /* offl no vol */ - else { /* avail or onl */ - sts = ST_SUC; - rq_setf_unit (cp, pkt, uptr); /* hack flags */ - } - rq_putr_unit (cp, pkt, uptr, lu, TRUE); /* set fields */ - } -else sts = ST_OFL; /* offline */ -cp->pak[pkt].d[ONL_SHUN] = lu; /* shadowing */ -cp->pak[pkt].d[ONL_SHST] = 0; -rq_putr (cp, pkt, cmd | OP_END, 0, sts, SUC_LNT, UQ_TYP_SEQ); -return rq_putpkt (cp, pkt, TRUE); -} - -/* Format command - floppies only */ - -t_bool rq_fmt (MSC *cp, int32 pkt, t_bool q) -{ -uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */ -uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ -uint32 sts; -UNIT *uptr; - -if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ - if (q && uptr->cpkt) { /* need to queue? */ - rq_enqt (cp, &uptr->pktq, pkt); /* do later */ - return OK; - } - if (GET_DTYPE (uptr->flags) != RX33_DTYPE) /* RX33? */ - sts = ST_CMD | I_OPCD; /* no, err */ - else if ((cp->pak[pkt].d[FMT_IH] & 0100000) == 0) /* magic bit set? */ - sts = ST_CMD | I_FMTI; /* no, err */ - else if ((uptr->flags & UNIT_ATT) == 0) /* offline? */ - sts = ST_OFL | SB_OFL_NV; /* no vol */ - else if (uptr->flags & UNIT_ONL) { /* online? */ - uptr->flags = uptr->flags & ~UNIT_ONL; - uptr->uf = 0; /* clear flags */ - sts = ST_AVL | SB_AVL_INU; /* avail, in use */ - } - else if (RQ_WPH (uptr)) /* write prot? */ - sts = ST_WPR | SB_WPR_HW; /* can't fmt */ - else sts = ST_SUC; /*** for now ***/ - } -else sts = ST_OFL; /* offline */ -rq_putr (cp, pkt, cmd | OP_END, 0, sts, FMT_LNT, UQ_TYP_SEQ); -return rq_putpkt (cp, pkt, TRUE); -} - -/* Data transfer commands */ - -t_bool rq_rw (MSC *cp, int32 pkt, t_bool q) -{ -uint32 lu = cp->pak[pkt].d[CMD_UN]; /* unit # */ -uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ -uint32 sts; -UNIT *uptr; - -if (uptr = rq_getucb (cp, lu)) { /* unit exist? */ - if (q && uptr->cpkt) { /* need to queue? */ - rq_enqt (cp, &uptr->pktq, pkt); /* do later */ - return OK; - } - sts = rq_rw_valid (cp, pkt, uptr, cmd); /* validity checks */ - if (sts == 0) { /* ok? */ - uptr->cpkt = pkt; /* op in progress */ - cp->pak[pkt].d[RW_WBAL] = cp->pak[pkt].d[RW_BAL]; - cp->pak[pkt].d[RW_WBAH] = cp->pak[pkt].d[RW_BAH]; - cp->pak[pkt].d[RW_WBCL] = cp->pak[pkt].d[RW_BCL]; - cp->pak[pkt].d[RW_WBCH] = cp->pak[pkt].d[RW_BCH]; - cp->pak[pkt].d[RW_WBLL] = cp->pak[pkt].d[RW_LBNL]; - cp->pak[pkt].d[RW_WBLH] = cp->pak[pkt].d[RW_LBNH]; - sim_activate (uptr, rq_xtime); /* activate */ - return OK; /* done */ - } - } -else sts = ST_OFL; /* offline */ -cp->pak[pkt].d[RW_BCL] = cp->pak[pkt].d[RW_BCH] = 0; /* bad packet */ -rq_putr (cp, pkt, cmd | OP_END, 0, sts, RW_LNT_D, UQ_TYP_SEQ); -return rq_putpkt (cp, pkt, TRUE); -} - -/* Validity checks */ - -int32 rq_rw_valid (MSC *cp, 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 = (uint32) (uptr->capac / RQ_NUMBY); /* 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 */ - (cp->pak[pkt].d[RW_BAL] & 1)) /* odd address? */ - return (ST_HST | SB_HST_OA); /* host buf odd */ -if (bc & 1) /* odd byte cnt? */ - return (ST_HST | SB_HST_OC); -if (bc & 0xF0000000) /* 'reasonable' bc? */ - return (ST_CMD | I_BCNT); -// 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) /* bc must be 512 */ - return (ST_CMD | I_BCNT); - } -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 (RQ_WPH (uptr)) /* hwre wlk? */ - return (ST_WPR | SB_WPR_HW); - } -return 0; /* success! */ -} - -/* Unit service for data transfer commands */ - -t_stat rq_svc (UNIT *uptr) -{ -MSC *cp = rq_ctxmap[uptr->cnum]; - -uint32 i, t, tbc, abc, wwc; -uint32 err = 0; -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 */ -t_addr da = ((t_addr) bl) * RQ_NUMBY; /* disk addr */ - -if ((cp == NULL) || (pkt == 0)) /* what??? */ - return STOP_RQ; -tbc = (bc > RQ_MAXFR)? RQ_MAXFR: bc; /* trim cnt to max */ - -if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ - rq_rw_end (cp, uptr, 0, ST_OFL | SB_OFL_NV); /* offl no vol */ - return SCPE_OK; - } -if (bc == 0) { /* no xfer? */ - rq_rw_end (cp, uptr, 0, ST_SUC); /* ok by me... */ - return SCPE_OK; - } - -if ((cmd == OP_ERS) || (cmd == OP_WR)) { /* write op? */ - if (RQ_WPH (uptr)) { - rq_rw_end (cp, uptr, 0, ST_WPR | SB_WPR_HW); - return SCPE_OK; - } - if (uptr->uf & UF_WPS) { - rq_rw_end (cp, uptr, 0, ST_WPR | SB_WPR_SW); - return SCPE_OK; - } - } - -if (cmd == OP_ERS) { /* erase? */ - wwc = ((tbc + (RQ_NUMBY - 1)) & ~(RQ_NUMBY - 1)) >> 1; - for (i = 0; i < wwc; i++) /* clr buf */ - rqxb[i] = 0; - err = sim_fseek (uptr->fileref, da, SEEK_SET); /* set pos */ - if (!err) - sim_fwrite (rqxb, sizeof (int16), wwc, uptr->fileref); - err = ferror (uptr->fileref); /* end if erase */ - } - -else if (cmd == OP_WR) { /* write? */ - t = Map_ReadW (ba, tbc, rqxb); /* 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 = sim_fseek (uptr->fileref, da, SEEK_SET); - if (!err) - sim_fwrite (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 (cp, uptr)) /* post err log */ - rq_rw_end (cp, uptr, EF_LOG, ST_HST | SB_HST_NXM); - return SCPE_OK; /* end else wr */ - } - } - -else { - err = sim_fseek (uptr->fileref, da, SEEK_SET); /* set pos */ - if (!err) { - i = sim_fread (rqxb, sizeof (int16), tbc >> 1, uptr->fileref); - for ( ; i < (tbc >> 1); i++) /* fill */ - rqxb[i] = 0; - err = ferror (uptr->fileref); - } - if ((cmd == OP_RD) && !err) { /* read? */ - if (t = Map_WriteW (ba, tbc, rqxb)) { /* store, nxm? */ - PUTP32 (pkt, RW_WBCL, bc - (tbc - t)); /* adj bc */ - PUTP32 (pkt, RW_WBAL, ba + (tbc - t)); /* adj ba */ - if (rq_hbe (cp, uptr)) /* post err log */ - rq_rw_end (cp, uptr, EF_LOG, ST_HST | SB_HST_NXM); - return SCPE_OK; - } - } - else if ((cmd == OP_CMP) && !err) { /* compare? */ - uint8 dby, mby; - for (i = 0; i < tbc; i++) { /* loop */ - if (Map_ReadB (ba + i, 1, &mby)) { /* fetch, nxm? */ - PUTP32 (pkt, RW_WBCL, bc - i); /* adj bc */ - PUTP32 (pkt, RW_WBAL, bc - i); /* adj ba */ - if (rq_hbe (cp, uptr)) /* post err log */ - rq_rw_end (cp, uptr, EF_LOG, ST_HST | SB_HST_NXM); - return SCPE_OK; - } - dby = (rqxb[i >> 1] >> ((i & 1)? 8: 0)) & 0xFF; - if (mby != dby) { /* cmp err? */ - PUTP32 (pkt, RW_WBCL, bc - i); /* adj bc */ - rq_rw_end (cp, uptr, 0, ST_CMP); /* done */ - return SCPE_OK; /* exit */ - } /* end if */ - } /* end for */ - } /* end else if */ - } /* end else read */ -if (err != 0) { /* error? */ - if (rq_dte (cp, uptr, ST_DRV)) /* post err log */ - rq_rw_end (cp, uptr, EF_LOG, ST_DRV); /* if ok, report err */ - perror ("RQ I/O error"); - clearerr (uptr->fileref); - 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) /* more? resched */ - sim_activate (uptr, rq_xtime); -else rq_rw_end (cp, uptr, 0, ST_SUC); /* done! */ -return SCPE_OK; -} - -/* Transfer command complete */ - -t_bool rq_rw_end (MSC *cp, 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 */ -DEVICE *dptr = rq_devmap[uptr->cnum]; - -uptr->cpkt = 0; /* done */ -PUTP32 (pkt, RW_BCL, bc - wbc); /* bytes processed */ -cp->pak[pkt].d[RW_WBAL] = 0; /* clear temps */ -cp->pak[pkt].d[RW_WBAH] = 0; -cp->pak[pkt].d[RW_WBCL] = 0; -cp->pak[pkt].d[RW_WBCH] = 0; -cp->pak[pkt].d[RW_WBLL] = 0; -cp->pak[pkt].d[RW_WBLH] = 0; -rq_putr (cp, pkt, cmd | OP_END, flg, sts, RW_LNT_D, UQ_TYP_SEQ); /* fill pkt */ -if (!rq_putpkt (cp, pkt, TRUE)) /* send pkt */ - return ERR; -if (uptr->pktq) /* more to do? */ - sim_activate (dptr->units + RQ_QUEUE, rq_qtime); /* activate thread */ -return OK; -} - -/* Data transfer error log packet */ - -t_bool rq_dte (MSC *cp, UNIT *uptr, uint32 err) -{ -int32 pkt, tpkt; -uint32 lu, dtyp, lbn, ccyl, csurf, csect, t; - -if ((cp->cflgs & CF_THS) == 0) /* logging? */ - return OK; -if (!rq_deqf (cp, &pkt)) /* get log pkt */ - return ERR; -tpkt = uptr->cpkt; /* rw pkt */ -lu = cp->pak[tpkt].d[CMD_UN]; /* unit # */ -lbn = GETP32 (tpkt, RW_WBLL); /* recent LBN */ -dtyp = GET_DTYPE (uptr->flags); /* drv type */ -if (drv_tab[dtyp].flgs & RQDF_SDI) /* SDI? ovhd @ end */ - t = 0; -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 */ - -cp->pak[pkt].d[ELP_REFL] = cp->pak[tpkt].d[CMD_REFL]; /* copy cmd ref */ -cp->pak[pkt].d[ELP_REFH] = cp->pak[tpkt].d[CMD_REFH]; -cp->pak[pkt].d[ELP_UN] = lu; /* copy unit */ -cp->pak[pkt].d[ELP_SEQ] = 0; /* clr seq # */ -cp->pak[pkt].d[DTE_CIDA] = 0; /* ctrl ID */ -cp->pak[pkt].d[DTE_CIDB] = 0; -cp->pak[pkt].d[DTE_CIDC] = 0; -cp->pak[pkt].d[DTE_CIDD] = (RQ_CLASS << DTE_CIDD_V_CLS) | - (RQ_MODEL << DTE_CIDD_V_MOD); -cp->pak[pkt].d[DTE_VER] = (RQ_HVER << DTE_VER_V_HVER) | - (RQ_SVER << DTE_VER_V_SVER); -cp->pak[pkt].d[DTE_MLUN] = lu; /* MLUN */ -cp->pak[pkt].d[DTE_UIDA] = lu; /* unit ID */ -cp->pak[pkt].d[DTE_UIDB] = 0; -cp->pak[pkt].d[DTE_UIDC] = 0; -cp->pak[pkt].d[DTE_UIDD] = (UID_DISK << DTE_UIDD_V_CLS) | - (drv_tab[dtyp].mod << DTE_UIDD_V_MOD); -cp->pak[pkt].d[DTE_UVER] = 0; /* unit versn */ -cp->pak[pkt].d[DTE_SCYL] = ccyl; /* cylinder */ -cp->pak[pkt].d[DTE_VSNL] = 01234 + lu; /* vol ser # */ -cp->pak[pkt].d[DTE_VSNH] = 0; -cp->pak[pkt].d[DTE_D1] = 0; -cp->pak[pkt].d[DTE_D2] = csect << DTE_D2_V_SECT; /* geometry */ -cp->pak[pkt].d[DTE_D3] = (ccyl << DTE_D3_V_CYL) | - (csurf << DTE_D3_V_SURF); -rq_putr (cp, pkt, FM_SDE, LF_SNR, err, DTE_LNT, UQ_TYP_DAT); -return rq_putpkt (cp, pkt, TRUE); -} - -/* Host bus error log packet */ - -t_bool rq_hbe (MSC *cp, UNIT *uptr) -{ -int32 pkt, tpkt; - -if ((cp->cflgs & CF_THS) == 0) /* logging? */ - return OK; -if (!rq_deqf (cp, &pkt)) /* get log pkt */ - return ERR; -tpkt = uptr->cpkt; /* rw pkt */ -cp->pak[pkt].d[ELP_REFL] = cp->pak[tpkt].d[CMD_REFL]; /* copy cmd ref */ -cp->pak[pkt].d[ELP_REFH] = cp->pak[tpkt].d[CMD_REFH]; -cp->pak[pkt].d[ELP_UN] = cp->pak[tpkt].d[CMD_UN]; /* copy unit */ -cp->pak[pkt].d[ELP_SEQ] = 0; /* clr seq # */ -cp->pak[pkt].d[HBE_CIDA] = 0; /* ctrl ID */ -cp->pak[pkt].d[HBE_CIDB] = 0; -cp->pak[pkt].d[HBE_CIDC] = 0; -cp->pak[pkt].d[HBE_CIDD] = (RQ_CLASS << DTE_CIDD_V_CLS) | - (RQ_MODEL << DTE_CIDD_V_MOD); -cp->pak[pkt].d[HBE_VER] = (RQ_HVER << HBE_VER_V_HVER) | /* versions */ - (RQ_SVER << HBE_VER_V_SVER); -cp->pak[pkt].d[HBE_RSV] = 0; -cp->pak[pkt].d[HBE_BADL] = cp->pak[tpkt].d[RW_WBAL]; /* bad addr */ -cp->pak[pkt].d[HBE_BADH] = cp->pak[tpkt].d[RW_WBAH]; -rq_putr (cp, pkt, FM_BAD, LF_SNR, ST_HST | SB_HST_NXM, HBE_LNT, UQ_TYP_DAT); -return rq_putpkt (cp, pkt, TRUE); -} - -/* Port last failure error log packet */ - -t_bool rq_plf (MSC *cp, uint32 err) -{ -int32 pkt; - -if (!rq_deqf (cp, &pkt)) /* get log pkt */ - return ERR; -cp->pak[pkt].d[ELP_REFL] = 0; /* ref = 0 */ -cp->pak[pkt].d[ELP_REFH] = 0; -cp->pak[pkt].d[ELP_UN] = 0; /* no unit */ -cp->pak[pkt].d[ELP_SEQ] = 0; /* no seq */ -cp->pak[pkt].d[PLF_CIDA] = 0; /* cntl ID */ -cp->pak[pkt].d[PLF_CIDB] = 0; -cp->pak[pkt].d[PLF_CIDC] = 0; -cp->pak[pkt].d[PLF_CIDD] = (RQ_CLASS << PLF_CIDD_V_CLS) | - (RQ_MODEL << PLF_CIDD_V_MOD); -cp->pak[pkt].d[PLF_VER] = (RQ_SVER << PLF_VER_V_SVER) | - (RQ_HVER << PLF_VER_V_HVER); -cp->pak[pkt].d[PLF_ERR] = err; -rq_putr (cp, pkt, FM_CNT, LF_SNR, ST_CNT, PLF_LNT, UQ_TYP_DAT); -cp->pak[pkt].d[UQ_HCTC] |= (UQ_CID_DIAG << UQ_HCTC_V_CID); -return rq_putpkt (cp, pkt, TRUE); -} - -/* Unit now available attention packet */ - -int32 rq_una (MSC *cp, int32 un) -{ -int32 pkt; -uint32 lu = cp->ubase + un; -UNIT *uptr = rq_getucb (cp, lu); - -if (uptr == NULL) /* huh? */ - return OK; -if (!rq_deqf (cp, &pkt)) /* get log pkt */ - return ERR; -cp->pak[pkt].d[RSP_REFL] = 0; /* ref = 0 */ -cp->pak[pkt].d[RSP_REFH] = 0; -cp->pak[pkt].d[RSP_UN] = lu; -cp->pak[pkt].d[RSP_RSV] = 0; -rq_putr_unit (cp, pkt, uptr, lu, FALSE); /* fill unit fields */ -rq_putr (cp, pkt, OP_AVA, 0, 0, UNA_LNT, UQ_TYP_SEQ); /* fill std fields */ -return rq_putpkt (cp, pkt, TRUE); -} - -/* List handling - - 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 (MSC *cp, int32 *pkt) -{ -if (cp->freq == 0) /* no free pkts?? */ - return rq_fatal (cp, PE_NSR); -cp->pbsy = cp->pbsy + 1; /* cnt busy pkts */ -*pkt = cp->freq; /* head of list */ -cp->freq = cp->pak[cp->freq].link; /* next */ -return OK; -} - -int32 rq_deqh (MSC *cp, int32 *lh) -{ -int32 ptr = *lh; /* head of list */ - -if (ptr) /* next */ - *lh = cp->pak[ptr].link; -return ptr; -} - -void rq_enqh (MSC *cp, int32 *lh, int32 pkt) -{ -if (pkt == 0) /* any pkt? */ - return; -cp->pak[pkt].link = *lh; /* link is old lh */ -*lh = pkt; /* pkt is new lh */ -return; -} - -void rq_enqt (MSC *cp, int32 *lh, int32 pkt) -{ -if (pkt == 0) /* any pkt? */ - return; -cp->pak[pkt].link = 0; /* it will be tail */ -if (*lh == 0) /* if empty, enqh */ - *lh = pkt; -else { - uint32 ptr = *lh; /* chase to end */ - while (cp->pak[ptr].link) - ptr = cp->pak[ptr].link; - cp->pak[ptr].link = pkt; /* enq at tail */ - } -return; -} - -/* Packet and descriptor handling */ - -/* Get packet from command ring */ - -t_bool rq_getpkt (MSC *cp, int32 *pkt) -{ -uint32 addr, desc; - -if (!rq_getdesc (cp, &cp->cq, &desc)) /* get cmd desc */ - return ERR; -if ((desc & UQ_DESC_OWN) == 0) { /* none */ - *pkt = 0; /* pkt = 0 */ - return OK; /* no error */ - } -if (!rq_deqf (cp, pkt)) /* get cmd pkt */ - return ERR; -cp->hat = 0; /* dsbl hst timer */ -addr = desc & UQ_ADDR; /* get Q22 addr */ -if (Map_ReadW (addr + UQ_HDR_OFF, RQ_PKT_SIZE, cp->pak[*pkt].d)) - return rq_fatal (cp, PE_PRE); /* read pkt */ -return rq_putdesc (cp, &cp->cq, desc); /* release desc */ -} - -/* Put packet to response ring - note the clever hack about credits. - 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 (MSC *cp, int32 pkt, t_bool qt) -{ -uint32 addr, desc, lnt, cr; -DEVICE *dptr = rq_devmap[cp->cnum]; - -if (pkt == 0) /* any packet? */ - return OK; -if (DEBUG_PRD (dptr)) - fprintf (sim_deb, ">>RQ%c: rsp=%04X, sts=%04X\n", 'A' + cp->cnum, - cp->pak[pkt].d[RSP_OPF], cp->pak[pkt].d[RSP_STS]); -if (!rq_getdesc (cp, &cp->rq, &desc)) /* get rsp desc */ - return ERR; -if ((desc & UQ_DESC_OWN) == 0) { /* not valid? */ - if (qt) /* normal? q tail */ - rq_enqt (cp, &cp->rspq, pkt); - else rq_enqh (cp, &cp->rspq, pkt); /* resp q call */ - sim_activate (dptr->units + RQ_QUEUE, rq_qtime); /* activate q thrd */ - return OK; - } -addr = desc & UQ_ADDR; /* get Q22 addr */ -lnt = cp->pak[pkt].d[UQ_HLNT] - UQ_HDR_OFF; /* size, with hdr */ -if ((GETP (pkt, UQ_HCTC, TYP) == UQ_TYP_SEQ) && /* seq packet? */ - (GETP (pkt, CMD_OPC, OPC) & OP_END)) { /* end packet? */ - cr = (cp->credits >= 14)? 14: cp->credits; /* max 14 credits */ - cp->credits = cp->credits - cr; /* decr credits */ - cp->pak[pkt].d[UQ_HCTC] |= ((cr + 1) << UQ_HCTC_V_CR); - } -if (Map_WriteW (addr + UQ_HDR_OFF, lnt, cp->pak[pkt].d)) - return rq_fatal (cp, PE_PWE); /* write pkt */ -rq_enqh (cp, &cp->freq, pkt); /* pkt is free */ -cp->pbsy = cp->pbsy - 1; /* decr busy cnt */ -if (cp->pbsy == 0) /* idle? strt hst tmr */ - cp->hat = cp->htmo; -return rq_putdesc (cp, &cp->rq, desc); /* release desc */ -} - -/* Get a descriptor from the host */ - -t_bool rq_getdesc (MSC *cp, struct uq_ring *ring, uint32 *desc) -{ -uint32 addr = ring->ba + ring->idx; -uint16 d[2]; - -if (Map_ReadW (addr, 4, d)) /* fetch desc */ - return rq_fatal (cp, PE_QRE); /* err? dead */ -*desc = ((uint32) d[0]) | (((uint32) d[1]) << 16); -return OK; -} - -/* Return a descriptor to the host, clearing owner bit - If rings transitions from "empty" to "not empty" or "full" to - "not full", and interrupt bit was set, interrupt the host. - Actually, test whether previous ring entry was owned by host. -*/ - -t_bool rq_putdesc (MSC *cp, struct uq_ring *ring, uint32 desc) -{ -uint32 prvd, newd = (desc & ~UQ_DESC_OWN) | UQ_DESC_F; -uint32 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)) /* store desc */ - return rq_fatal (cp, PE_QWE); /* err? dead */ -if (desc & UQ_DESC_F) { /* was F set? */ - if (ring->lnt <= 4) /* lnt = 1? intr */ - rq_ring_int (cp, ring); - else { /* prv desc */ - prva = ring->ba + ((ring->idx - 4) & (ring->lnt - 1)); - if (Map_ReadW (prva, 4, d)) /* read prv */ - return rq_fatal (cp, PE_QRE); - prvd = ((uint32) d[0]) | (((uint32) d[1]) << 16); - if (prvd & UQ_DESC_OWN) - rq_ring_int (cp, ring); - } - } -ring->idx = (ring->idx + 4) & (ring->lnt - 1); -return OK; -} - -/* Get unit descriptor for logical unit */ - -UNIT *rq_getucb (MSC *cp, uint32 lu) -{ -DEVICE *dptr = rq_devmap[cp->cnum]; -UNIT *uptr; - -if ((lu < cp->ubase) || (lu >= (cp->ubase + RQ_NUMDR))) - return NULL; -uptr = dptr->units + (lu % RQ_NUMDR); -if (uptr->flags & UNIT_DIS) - return NULL; -return uptr; -} - -/* Hack unit flags */ - -void rq_setf_unit (MSC *cp, int32 pkt, UNIT *uptr) -{ -uptr->uf = cp->pak[pkt].d[ONL_UFL] & UF_MSK; /* settable flags */ -if ((cp->pak[pkt].d[CMD_MOD] & MD_SWP) && /* swre wrp enb? */ - (cp->pak[pkt].d[ONL_UFL] & UF_WPS)) /* swre wrp on? */ - uptr->uf = uptr->uf | UF_WPS; /* simon says... */ -return; -} - -/* Unit response fields */ - -void rq_putr_unit (MSC *cp, int32 pkt, UNIT *uptr, uint32 lu, t_bool all) -{ -uint32 dtyp = GET_DTYPE (uptr->flags); /* get drive type */ -uint32 maxlbn = (uint32) (uptr->capac / RQ_NUMBY); /* get max lbn */ - -cp->pak[pkt].d[ONL_MLUN] = lu; /* unit */ -cp->pak[pkt].d[ONL_UFL] = uptr->uf | UF_RPL | RQ_WPH (uptr) | RQ_RMV (uptr); -cp->pak[pkt].d[ONL_RSVL] = 0; /* reserved */ -cp->pak[pkt].d[ONL_RSVH] = 0; -cp->pak[pkt].d[ONL_UIDA] = lu; /* UID low */ -cp->pak[pkt].d[ONL_UIDB] = 0; -cp->pak[pkt].d[ONL_UIDC] = 0; -cp->pak[pkt].d[ONL_UIDD] = (UID_DISK << ONL_UIDD_V_CLS) | - (drv_tab[dtyp].mod << ONL_UIDD_V_MOD); /* UID hi */ -PUTP32 (pkt, ONL_MEDL, drv_tab[dtyp].med); /* media type */ -if (all) { /* if long form */ - PUTP32 (pkt, ONL_SIZL, maxlbn); /* user LBNs */ - cp->pak[pkt].d[ONL_VSNL] = 01234 + lu; /* vol serial # */ - cp->pak[pkt].d[ONL_VSNH] = 0; - } -return; -} - -/* UQ_HDR and RSP_OP fields */ - -void rq_putr (MSC *cp, int32 pkt, uint32 cmd, uint32 flg, - uint32 sts, uint32 lnt, uint32 typ) -{ -cp->pak[pkt].d[RSP_OPF] = (cmd << RSP_OPF_V_OPC) | /* set cmd, flg */ - (flg << RSP_OPF_V_FLG); -cp->pak[pkt].d[RSP_STS] = sts; -cp->pak[pkt].d[UQ_HLNT] = lnt; /* length */ -cp->pak[pkt].d[UQ_HCTC] = (typ << UQ_HCTC_V_TYP) | /* type, cid */ - (UQ_CID_MSCP << UQ_HCTC_V_CID); /* clr credits */ -return; -} - -/* Post interrupt during init */ - -void rq_init_int (MSC *cp) -{ -if ((cp->s1dat & SA_S1H_IE) && /* int enab & */ - (cp->s1dat & SA_S1H_VEC)) /* ved set? int */ - rq_setint (cp); -return; -} - -/* Post interrupt during putpkt - note that NXMs are ignored! */ - -void rq_ring_int (MSC *cp, struct uq_ring *ring) -{ -uint32 iadr = cp->comm + ring->ioff; /* addr intr wd */ -uint16 flag = 1; - -Map_WriteW (iadr, 2, &flag); /* write flag */ -if (cp->s1dat & SA_S1H_VEC) /* if enb, intr */ - rq_setint (cp); -return; -} - -/* Set RQ interrupt */ - -void rq_setint (MSC *cp) -{ -cp->irq = 1; /* set ctrl int */ -SET_INT (RQ); /* set master int */ -return; -} - -/* Clear RQ interrupt */ - -void rq_clrint (MSC *cp) -{ -int32 i; -MSC *ncp; - -cp->irq = 0; /* clr ctrl int */ -for (i = 0; i < RQ_NUMCT; i++) { /* loop thru ctrls */ - ncp = rq_ctxmap[i]; /* get context */ - if (ncp->irq) { /* other interrupt? */ - SET_INT (RQ); /* yes, set master */ - return; - } - } -CLR_INT (RQ); /* no, clr master */ -return; -} - -/* Return interrupt vector */ - -int32 rq_inta (void) -{ -int32 i; -MSC *ncp; -DEVICE *dptr; -DIB *dibp; - -for (i = 0; i < RQ_NUMCT; i++) { /* loop thru ctrl */ - ncp = rq_ctxmap[i]; /* get context */ - if (ncp->irq) { /* ctrl int set? */ - dptr = rq_devmap[i]; /* get device */ - dibp = (DIB *) dptr->ctxt; /* get DIB */ - rq_clrint (ncp); /* clear int req */ - return dibp->vec; /* return vector */ - } - } -return 0; /* no intr req */ -} - -/* Fatal error */ - -t_bool rq_fatal (MSC *cp, uint32 err) -{ -DEVICE *dptr = rq_devmap[cp->cnum]; - -if (DEBUG_PRD (dptr)) - fprintf (sim_deb, ">>RQ%c: fatal err=%X\n", 'A' + cp->cnum, err); -rq_reset (rq_devmap[cp->cnum]); /* reset device */ -cp->sa = SA_ER | err; /* SA = dead code */ -cp->csta = CST_DEAD; /* state = dead */ -cp->perr = err; /* save error */ -return ERR; -} - -/* 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) /* not on read only */ - return SCPE_NOFNC; -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->flags & UNIT_WPRT) - fprintf (st, "write locked"); -else fprintf (st, "write enabled"); -return SCPE_OK; -} - -/* Set unit type (and capacity if user defined) */ - -t_stat rq_set_type (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -uint32 cap; -uint32 max = sim_taddr_64? RA8U_EMAXC: RA8U_MAXC; -t_stat r; - -if ((val < 0) || ((val != RA8U_DTYPE) && cptr)) - return SCPE_ARG; -if (uptr->flags & UNIT_ATT) - return SCPE_ALATT; -if (cptr) { - cap = (uint32) get_uint (cptr, 10, 0xFFFFFFFF, &r); - if ((sim_switches & SWMASK ('L')) == 0) - cap = cap * 1954; - if ((r != SCPE_OK) || (cap < RA8U_MINC) || (cap >= max)) - return SCPE_ARG; - drv_tab[val].lbn = cap; - } -uptr->flags = (uptr->flags & ~UNIT_DTYPE) | (val << UNIT_V_DTYPE); -uptr->capac = ((t_addr) drv_tab[val].lbn) * RQ_NUMBY; -return SCPE_OK; -} - -/* Show unit type */ - -t_stat rq_show_type (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -fprintf (st, "%s", drv_tab[GET_DTYPE (uptr->flags)].name); -return SCPE_OK; -} - -/* Device attach */ - -t_stat rq_attach (UNIT *uptr, char *cptr) -{ -MSC *cp = rq_ctxmap[uptr->cnum]; -t_stat r; - -r = attach_unit (uptr, cptr); -if (r != SCPE_OK) - return r; -if (cp->csta == CST_UP) - uptr->flags = uptr->flags | UNIT_ATP; -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 = 0; /* clr unit flgs */ -return SCPE_OK; -} - -/* Device reset */ - -t_stat rq_reset (DEVICE *dptr) -{ -int32 i, j, cidx; -UNIT *uptr; -MSC *cp; -DIB *dibp = (DIB *) dptr->ctxt; - -for (i = 0, cidx = -1; i < RQ_NUMCT; i++) { /* find ctrl num */ - if (rq_devmap[i] == dptr) - cidx = i; - } -if (cidx < 0) /* not found??? */ - return SCPE_IERR; -cp = rq_ctxmap[cidx]; /* get context */ -cp->cnum = cidx; /* init index */ - -#if defined (VM_VAX) /* VAX */ -cp->ubase = 0; /* unit base = 0 */ -#else /* PDP-11 */ -cp->ubase = cidx * RQ_NUMDR; /* init unit base */ -#endif - -cp->csta = CST_S1; /* init stage 1 */ -cp->s1dat = 0; /* no S1 data */ -dibp->vec = 0; /* no vector */ -cp->comm = 0; /* no comm region */ -if (UNIBUS) /* Unibus? */ - cp->sa = SA_S1 | SA_S1C_DI | SA_S1C_MP; -else cp->sa = SA_S1 | SA_S1C_Q22 | SA_S1C_DI | SA_S1C_MP; /* init SA val */ -cp->cflgs = CF_RPL; /* ctrl flgs off */ -cp->htmo = RQ_DHTMO; /* default timeout */ -cp->hat = cp->htmo; /* default timer */ -cp->cq.ba = cp->cq.lnt = cp->cq.idx = 0; /* clr cmd ring */ -cp->rq.ba = cp->rq.lnt = cp->rq.idx = 0; /* clr rsp ring */ -cp->credits = (RQ_NPKTS / 2) - 1; /* init credits */ -cp->freq = 1; /* init free list */ -for (i = 0; i < RQ_NPKTS; i++) { /* all pkts free */ - if (i) - cp->pak[i].link = (i + 1) & RQ_M_NPKTS; - else cp->pak[i].link = 0; - for (j = 0; j < RQ_PKT_SIZE_W; j++) - cp->pak[i].d[j] = 0; - } -cp->rspq = 0; /* no q'd rsp pkts */ -cp->pbsy = 0; /* all pkts free */ -cp->pip = 0; /* not polling */ -rq_clrint (cp); /* clr intr req */ -for (i = 0; i < (RQ_NUMDR + 2); i++) { /* init units */ - uptr = dptr->units + i; - sim_cancel (uptr); /* clr activity */ - uptr->cnum = cidx; /* set ctrl index */ - uptr->flags = uptr->flags & ~(UNIT_ONL | UNIT_ATP); - uptr->uf = 0; /* clr unit flags */ - uptr->cpkt = uptr->pktq = 0; /* clr pkt q's */ - } -if (rqxb == NULL) - rqxb = (uint16 *) calloc (RQ_MAXFR >> 1, sizeof (uint16)); -if (rqxb == NULL) - return SCPE_MEM; -return auto_config (0, 0); /* run autoconfig */ -} - -/* Device bootstrap */ - -#if defined (VM_PDP11) - -#define BOOT_START 016000 /* start */ -#define BOOT_ENTRY (BOOT_START + 002) /* entry */ -#define BOOT_UNIT (BOOT_START + 010) /* unit number */ -#define BOOT_CSR (BOOT_START + 014) /* CSR */ -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) - -static const uint16 boot_rom[] = { - - 0042125, /* st: "UD" */ - - /* Four step init process */ - - 0012706, 0016000, /* mov #st,sp */ - 0012700, 0000000, /* mov #unit,r0 */ - 0012701, 0172150, /* mov #172150, r1 ; ip addr */ - 0012704, 0016162, /* 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 */ - - 0005011, /* done: clr (r1) ; for M+ */ - 0005003, /* clr r3 */ - 0012704, BOOT_START+020, /* mov #st+020,r4 */ - 0005005, /* clr r5 */ - 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, DEVICE *dptr) -{ -int32 i; -extern uint16 *M; -DIB *dibp = (DIB *) dptr->ctxt; - -for (i = 0; i < BOOT_LEN; i++) - M[(BOOT_START >> 1) + i] = boot_rom[i]; -M[BOOT_UNIT >> 1] = unitno & 3; -M[BOOT_CSR >> 1] = dibp->ba & DMASK; -cpu_set_boot (BOOT_ENTRY); -return SCPE_OK; -} - -#else - -t_stat rq_boot (int32 unitno, DEVICE *dptr) -{ -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\n", - rp->ba, rp->idx >> 2, rp->lnt >> 2); -#else -fprintf (st, "ring, base = %x, index = %d, length = %d\n", - rp->ba, rp->idx >> 2, rp->lnt >> 2); -#endif -for (i = 0; i < (rp->lnt >> 2); i++) { - if (Map_ReadW (rp->ba + (i << 2), 4, d)) { - fprintf (st, " %3d: non-existent memory\n", i); - break; - } - desc = ((uint32) d[0]) | (((uint32) d[1]) << 16); -#if defined (VM_PDP11) - fprintf (st, " %3d: %011o\n", i, desc); -#else - fprintf (st, " %3d: %08x\n", i, desc); -#endif - } -return; -} - -void rq_show_pkt (FILE *st, MSC *cp, int32 pkt) -{ -int32 i, j; -uint32 cr = GETP (pkt, UQ_HCTC, CR); -uint32 typ = GETP (pkt, UQ_HCTC, TYP); -uint32 cid = GETP (pkt, UQ_HCTC, CID); - -fprintf (st, "packet %d, credits = %d, type = %d, cid = %d\n", - pkt, cr, typ, cid); -for (i = 0; i < RQ_SH_MAX; i = i + RQ_SH_PPL) { - fprintf (st, " %2d:", i); - for (j = i; j < (i + RQ_SH_PPL); j++) -#if defined (VM_PDP11) - fprintf (st, " %06o", cp->pak[pkt].d[j]); -#else - fprintf (st, " %04x", cp->pak[pkt].d[j]); -#endif - fprintf (st, "\n"); - } -return; -} - -t_stat rq_show_unitq (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -MSC *cp = rq_ctxmap[uptr->cnum]; -DEVICE *dptr = rq_devmap[uptr->cnum]; -int32 pkt, u; - -u = (int32) (uptr - dptr->units); -if (cp->csta != CST_UP) { - fprintf (st, "Controller is not initialized\n"); - return SCPE_OK; - } -if ((uptr->flags & UNIT_ONL) == 0) { - if (uptr->flags & UNIT_ATT) - fprintf (st, "Unit %d is available\n", u); - else fprintf (st, "Unit %d is offline\n", u); - return SCPE_OK; - } -if (uptr->cpkt) { - fprintf (st, "Unit %d current ", u); - rq_show_pkt (st, cp, uptr->cpkt); - if (pkt = uptr->pktq) { - do { - fprintf (st, "Unit %d queued ", u); - rq_show_pkt (st, cp, pkt); - } while (pkt = cp->pak[pkt].link); - } - } -else fprintf (st, "Unit %d queues are empty\n", u); -return SCPE_OK; -} - -t_stat rq_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -MSC *cp = rq_ctxmap[uptr->cnum]; -DEVICE *dptr = rq_devmap[uptr->cnum]; -int32 i, pkt; - -if (cp->csta != CST_UP) { - fprintf (st, "Controller is not initialized\n"); - return SCPE_OK; - } -if (val & RQ_SH_RI) { - if (cp->pip) - fprintf (st, "Polling in progress, host timer = %d\n", cp->hat); - else fprintf (st, "Host timer = %d\n", cp->hat); - fprintf (st, "Command "); - rq_show_ring (st, &cp->cq); - fprintf (st, "Response "); - rq_show_ring (st, &cp->rq); - } -if (val & RQ_SH_FR) { - if (pkt = cp->freq) { - for (i = 0; pkt != 0; i++, pkt = cp->pak[pkt].link) { - if (i == 0) - fprintf (st, "Free queue = %d", pkt); - else if ((i % 16) == 0) - fprintf (st, ",\n %d", pkt); - else fprintf (st, ", %d", pkt); - } - fprintf (st, "\n"); - } - else fprintf (st, "Free queue is empty\n"); - } -if (val & RQ_SH_RS) { - if (pkt = cp->rspq) { - do { - fprintf (st, "Response "); - rq_show_pkt (st, cp, pkt); - } while (pkt = cp->pak[pkt].link); - } - else fprintf (st, "Response queue is empty\n"); - } -if (val & RQ_SH_UN) { - for (i = 0; i < RQ_NUMDR; i++) - rq_show_unitq (st, dptr->units + i, 0, desc); - } -return SCPE_OK; -} diff --git a/PDP11/pdp11_rs.c b/PDP11/pdp11_rs.c deleted file mode 100644 index 7cde80b7..00000000 --- a/PDP11/pdp11_rs.c +++ /dev/null @@ -1,694 +0,0 @@ -/* pdp11_rs.c - RS03/RS04 Massbus disk controller - - Copyright (c) 2013-2017, 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. - - rs RS03/RS04 fixed head disks - - 13-Mar-17 RMS Annotated intentional fall through in switch - 23-Oct-13 RMS Revised for new boot setup routine -*/ - -#if defined (VM_PDP10) -#error "RS03/RS04 not supported on the PDP-10!" - -#elif defined (VM_PDP11) -#include "pdp11_defs.h" -#define DEV_RADIX 8 - -#elif defined (VM_VAX) -#error "RS03/RS04 not supported on the VAX!" -#endif - -#include - -#define RS_NUMDR 8 /* #drives */ -#define RS03_NUMWD 64 /* words/sector */ -#define RS04_NUMWD 128 /* words/sector */ -#define RS_NUMSC 64 /* sectors/track */ -#define RS_NUMTK 64 /* tracks/disk */ -#define RS_MAXFR (1 << 16) /* max transfer */ -#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \ - ((double) (RS03_NUMWD * RS_NUMSC)))) -#define RS03_ID 0 -#define RS04_ID 2 -#define RS03_SIZE (RS_NUMTK * RS_NUMSC * RS03_NUMWD) -#define RS04_SIZE (RS_NUMTK * RS_NUMSC * RS04_NUMWD) -#define RS_NUMWD(d) ((d)? RS04_NUMWD: RS03_NUMWD) -#define RS_SIZE(d) ((d)? RS04_SIZE: RS03_SIZE) - -/* Flags in the unit flags word */ - -#define UNIT_V_DTYPE (UNIT_V_UF + 0) /* disk type */ -#define RS03_DTYPE (0) -#define RS04_DTYPE (1) -#define UNIT_V_AUTO (UNIT_V_UF + 1) /* autosize */ -#define UNIT_V_WLK (UNIT_V_UF + 2) /* write lock */ -#define UNIT_DTYPE (1 << UNIT_V_DTYPE) -#define UNIT_AUTO (1 << UNIT_V_AUTO) -#define UNIT_WLK (1 << UNIT_V_WLK) -#define GET_DTYPE(x) (((x) >> UNIT_V_DTYPE) & 1) - -/* RSCS1 - control/status 1 - offset 0 */ - -#define RS_CS1_OF 0 -#define CS1_GO CSR_GO /* go */ -#define CS1_V_FNC 1 /* function pos */ -#define CS1_M_FNC 037 /* function mask */ -#define CS1_N_FNC (CS1_M_FNC + 1) -#define FNC_NOP 000 /* no operation */ -#define FNC_DCLR 004 /* drive clear */ -#define FNC_SEARCH 014 /* search */ -#define FNC_XFR 020 /* divide line for xfr */ -#define FNC_WCHK 024 /* write check */ -#define FNC_WRITE 030 /* write */ -#define FNC_READ 034 /* read */ -#define CS1_RW 076 -#define CS1_DVA 04000 /* drive avail */ -#define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC) - -/* RSDS - drive status - offset 1 */ - -#define RS_DS_OF 1 -#define DS_RDY 0000200 /* drive ready */ -#define DS_DPR 0000400 /* drive present */ -#define DS_LST 0002000 /* last sector */ -#define DS_WLK 0004000 /* write locked */ -#define DS_MOL 0010000 /* medium online */ -#define DS_PIP 0020000 /* pos in progress */ -#define DS_ERR 0040000 /* error */ -#define DS_ATA 0100000 /* attention active */ -#define DS_MBZ 0001177 - -/* RSER - error status - offset 2 */ - -#define RS_ER_OF 2 -#define ER_ILF 0000001 /* illegal func */ -#define ER_ILR 0000002 /* illegal register */ -#define ER_RMR 0000004 /* reg mod refused */ -#define ER_PAR 0000010 /* parity err */ -#define ER_AOE 0001000 /* addr ovflo err */ -#define ER_IAE 0002000 /* invalid addr err */ -#define ER_WLE 0004000 /* write lock err NI */ -#define ER_DTE 0010000 /* drive time err NI */ -#define ER_OPI 0020000 /* op incomplete */ -#define ER_UNS 0040000 /* drive unsafe */ -#define ER_DCK 0100000 /* data check NI */ -#define ER_MBZ 0000760 - -/* RSMR - maintenace register - offset 3 */ - -#define RS_MR_OF 3 - -/* RSAS - attention summary - offset 4 */ - -#define RS_AS_OF 4 -#define AS_U0 0000001 /* unit 0 flag */ - -/* RSDA - sector/track - offset 5 - All 16b are RW, but only <14:12> are tested for "invalid" address */ - -#define RS_DA_OF 5 -#define DA_V_SC 0 /* sector pos */ -#define DA_M_SC 077 /* sector mask */ -#define DA_V_TK 6 /* track pos */ -#define DA_M_TK 077 /* track mask */ -#define GET_SC(x) (((x) >> DA_V_SC) & DA_M_SC) -#define GET_TK(x) (((x) >> DA_V_TK) & DA_M_TK) -#define DA_INV 0070000 /* inv addr */ -#define DA_IGN 0100000 /* ignored */ - -/* RSDT - drive type - offset 6 */ - -#define RS_DT_OF 6 - -/* RSLA - look ahead register - offset 7 */ - -#define RS_LA_OF 7 - -/* This controller supports two disk drive types: - - type #words/ #sectors/ #tracks/ - sector track drive - - RS03 64 64 64 =256KW - RS04 128 64 640 =512KW - - In theory, each drive can be a different type. The size field in - each unit selects the drive capacity for each drive and thus the - drive type. -*/ - -uint16 rscs1[RS_NUMDR] = { 0 }; /* control/status 1 */ -uint16 rsda[RS_NUMDR] = { 0 }; /* track/sector */ -uint16 rsds[RS_NUMDR] = { 0 }; /* drive status */ -uint16 rser[RS_NUMDR] = { 0 }; /* error status */ -uint16 rsmr[RS_NUMDR] = { 0 }; /* maint register */ -uint8 rswlk[RS_NUMDR] = { 0 }; /* wlk switches */ -int32 rs_stopioe = 1; /* stop on error */ -int32 rs_wait = 10; /* rotate time */ -static const char *rs_fname[CS1_N_FNC] = { - "NOP", "01", "02", "03", "DCLR", "05", "06", "07", - "10", "11", "12", "13", "SCH", "15", "16", "17", - "20", "21", "22", "23", "WRCHK", "25", "26", "27", - "WRITE", "31", "32", "33", "READ", "35", "36", "37" - }; - -t_stat rs_mbrd (int32 *data, int32 ofs, int32 drv); -t_stat rs_mbwr (int32 data, int32 ofs, int32 drv); -t_stat rs_svc (UNIT *uptr); -t_stat rs_reset (DEVICE *dptr); -t_stat rs_attach (UNIT *uptr, char *cptr); -t_stat rs_detach (UNIT *uptr); -t_stat rs_boot (int32 unitno, DEVICE *dptr); -void rs_set_er (int32 flg, int32 drv); -void rs_clr_as (int32 mask); -void rs_update_ds (int32 flg, int32 drv); -t_stat rs_go (int32 drv); -t_stat rs_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -int32 rs_abort (void); - -/* RS data structures - - rs_dev RS device descriptor - rs_unit RS unit list - rs_reg RS register list - rs_mod RS modifier list -*/ - -DIB rs_dib = { MBA_RS, 0, &rs_mbrd, &rs_mbwr, 0, 0, 0, { &rs_abort } }; - -UNIT rs_unit[] = { - { UDATA (&rs_svc, UNIT_FIX|UNIT_ATTABLE|UNIT_DISABLE|UNIT_AUTO+ - UNIT_BUFABLE|UNIT_MUSTBUF|(RS04_DTYPE << UNIT_V_DTYPE), RS04_SIZE) }, - { UDATA (&rs_svc, UNIT_FIX|UNIT_ATTABLE|UNIT_DISABLE|UNIT_AUTO+ - UNIT_BUFABLE|UNIT_MUSTBUF|(RS04_DTYPE << UNIT_V_DTYPE), RS04_SIZE) }, - { UDATA (&rs_svc, UNIT_FIX|UNIT_ATTABLE|UNIT_DISABLE|UNIT_AUTO+ - UNIT_BUFABLE|UNIT_MUSTBUF|(RS04_DTYPE << UNIT_V_DTYPE), RS04_SIZE) }, - { UDATA (&rs_svc, UNIT_FIX|UNIT_ATTABLE|UNIT_DISABLE|UNIT_AUTO+ - UNIT_BUFABLE|UNIT_MUSTBUF|(RS04_DTYPE << UNIT_V_DTYPE), RS04_SIZE) }, - { UDATA (&rs_svc, UNIT_FIX|UNIT_ATTABLE|UNIT_DISABLE|UNIT_AUTO+ - UNIT_BUFABLE|UNIT_MUSTBUF|(RS04_DTYPE << UNIT_V_DTYPE), RS04_SIZE) }, - { UDATA (&rs_svc, UNIT_FIX|UNIT_ATTABLE|UNIT_DISABLE|UNIT_AUTO+ - UNIT_BUFABLE|UNIT_MUSTBUF|(RS04_DTYPE << UNIT_V_DTYPE), RS04_SIZE) }, - { UDATA (&rs_svc, UNIT_FIX|UNIT_ATTABLE|UNIT_DISABLE|UNIT_AUTO+ - UNIT_BUFABLE|UNIT_MUSTBUF|(RS04_DTYPE << UNIT_V_DTYPE), RS04_SIZE) }, - { UDATA (&rs_svc, UNIT_FIX|UNIT_ATTABLE|UNIT_DISABLE|UNIT_AUTO+ - UNIT_BUFABLE|UNIT_MUSTBUF|(RS04_DTYPE << UNIT_V_DTYPE), RS04_SIZE) } - }; - -REG rs_reg[] = { - { BRDATA (CS1, rscs1, DEV_RDX, 16, RS_NUMDR) }, - { BRDATA (DA, rsda, DEV_RDX, 16, RS_NUMDR) }, - { BRDATA (DS, rsds, DEV_RDX, 16, RS_NUMDR) }, - { BRDATA (ER, rser, DEV_RDX, 16, RS_NUMDR) }, - { BRDATA (MR, rsmr, DEV_RDX, 16, RS_NUMDR) }, - { BRDATA (WLKS, rswlk, DEV_RDX, 6, RS_NUMDR) }, - { DRDATA (TIME, rs_wait, 24), REG_NZ + PV_LEFT }, - { URDATA (CAPAC, rs_unit[0].capac, 10, T_ADDR_W, 0, - RS_NUMDR, PV_LEFT | REG_HRO) }, - { FLDATA (STOP_IOE, rs_stopioe, 0) }, - { NULL } - }; - -MTAB rs_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "MASSBUS", "MASSBUS", NULL, &mba_show_num }, - { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { UNIT_WLK, UNIT_WLK, "write lockable", "LOCKABLE", NULL }, - { (UNIT_DTYPE|UNIT_ATT), (RS03_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, - "RS03", NULL, NULL }, - { (UNIT_DTYPE|UNIT_ATT), (RS04_DTYPE << UNIT_V_DTYPE) + UNIT_ATT, - "RS04", NULL, NULL }, - { (UNIT_AUTO|UNIT_DTYPE|UNIT_ATT), (RS03_DTYPE << UNIT_V_DTYPE), - "RS03", NULL, NULL }, - { (UNIT_AUTO|UNIT_DTYPE|UNIT_ATT), (RS04_DTYPE << UNIT_V_DTYPE), - "RS04", NULL, NULL }, - { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL }, - { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL }, - { (UNIT_AUTO|UNIT_DTYPE), (RS03_DTYPE << UNIT_V_DTYPE), - NULL, "RS03", &rs_set_size }, - { (UNIT_AUTO|UNIT_DTYPE), (RS04_DTYPE << UNIT_V_DTYPE), - NULL, "RS04", &rs_set_size }, - { 0 } - }; - -DEVICE rs_dev = { - "RS", rs_unit, rs_reg, rs_mod, - RS_NUMDR, DEV_RADIX, 19, 1, DEV_RADIX, 16, - NULL, NULL, &rs_reset, - &rs_boot, &rs_attach, &rs_detach, - &rs_dib, DEV_DISABLE|DEV_DIS|DEV_UBUS|DEV_QBUS|DEV_MBUS|DEV_DEBUG - }; - -/* Massbus register read */ - -t_stat rs_mbrd (int32 *data, int32 ofs, int32 drv) -{ -uint32 val, dtype, i; -UNIT *uptr; - -rs_update_ds (0, drv); /* update ds */ -uptr = rs_dev.units + drv; /* get unit */ -if (uptr->flags & UNIT_DIS) { /* nx disk */ - *data = 0; - return MBE_NXD; - } -dtype = GET_DTYPE (uptr->flags); /* get drive type */ -ofs = ofs & MBA_RMASK; /* mask offset */ - -switch (ofs) { /* decode offset */ - - case RS_CS1_OF: /* RSCS1 */ - val = (rscs1[drv] & CS1_RW) | CS1_DVA; /* DVA always set */ - break; - - case RS_DA_OF: /* RSDA */ - val = rsda[drv]; - break; - - case RS_DS_OF: /* RSDS */ - val = rsds[drv] & ~DS_MBZ; - break; - - case RS_ER_OF: /* RSER */ - val = rser[drv] & ~ER_MBZ; - break; - - case RS_AS_OF: /* RSAS */ - val = 0; - for (i = 0; i < RS_NUMDR; i++) { - if (rsds[i] & DS_ATA) - val |= (AS_U0 << i); - } - break; - - case RS_LA_OF: /* RSLA */ - val = GET_POS (rs_wait); - break; - - case RS_MR_OF: /* RSMR */ - val = rsmr[drv]; - break; - - case RS_DT_OF: /* RSDT */ - val = dtype? RS04_ID: RS03_ID; - break; - - default: /* all others */ - *data = 0; - return MBE_NXR; - } - -*data = val; -return SCPE_OK; -} - -/* Massbus register write */ - -t_stat rs_mbwr (int32 data, int32 ofs, int32 drv) -{ -UNIT *uptr; - -uptr = rs_dev.units + drv; /* get unit */ -if (uptr->flags & UNIT_DIS) /* nx disk */ - return MBE_NXD; -if ((ofs != RS_AS_OF) && sim_is_active (uptr)) { /* unit busy? */ - rs_set_er (ER_RMR, drv); /* won't write */ - rs_update_ds (0, drv); - return SCPE_OK; - } -ofs = ofs & MBA_RMASK; /* mask offset */ - -switch (ofs) { /* decode PA<5:1> */ - - case RS_CS1_OF: /* RSCS1 */ - rscs1[drv] = data & CS1_RW; - if (data & CS1_GO) /* start op */ - return rs_go (drv); - break; - - case RS_DA_OF: /* RSDA */ - rsda[drv] = (uint16) data; - break; - - case RS_AS_OF: /* RSAS */ - rs_clr_as (data); - break; - - case RS_MR_OF: /* RSMR */ - rsmr[drv] = (uint16) data; - break; - - case RS_ER_OF: /* RSER */ - case RS_DS_OF: /* RSDS */ - case RS_LA_OF: /* RSLA */ - case RS_DT_OF: /* RSDT */ - break; /* read only */ - - default: /* all others */ - return MBE_NXR; - } /* end switch */ - -rs_update_ds (0, drv); /* update status */ -return SCPE_OK; -} - -/* Initiate operation - unit not busy, function set */ - -t_stat rs_go (int32 drv) -{ -int32 fnc, t; -UNIT *uptr; - -fnc = GET_FNC (rscs1[drv]); /* get function */ -if (DEBUG_PRS (rs_dev)) - fprintf (sim_deb, ">>RS%d STRT: fnc=%s, ds=%o, da=%o, er=%o\n", - drv, rs_fname[fnc], rsds[drv], rsda[drv], rser[drv]); -uptr = rs_dev.units + drv; /* get unit */ -rs_clr_as (AS_U0 << drv); /* clear attention */ -if ((fnc != FNC_DCLR) && (rsds[drv] & DS_ERR)) { /* err & ~clear? */ - rs_set_er (ER_ILF, drv); /* not allowed */ - rs_update_ds (DS_ATA, drv); /* set attention */ - return MBE_GOE; - } - -switch (fnc) { /* case on function */ - - case FNC_DCLR: /* drive clear */ - rser[drv] = 0; /* clear errors */ - case FNC_NOP: /* no operation */ - return SCPE_OK; - - case FNC_SEARCH: /* search */ - case FNC_WRITE: /* write */ - case FNC_WCHK: /* write check */ - case FNC_READ: /* read */ - if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ - rs_set_er (ER_UNS, drv); /* unsafe */ - break; - } - if (rsda[drv] & DA_INV) { /* bad address? */ - rs_set_er (ER_IAE, drv); - break; - } - rsds[drv] = rsds[drv] & ~DS_RDY; /* clr drive rdy */ - if (fnc == FNC_SEARCH) /* search? */ - rsds[drv] = rsds[drv] | DS_PIP; /* set PIP */ - t = abs (rsda[drv] - GET_POS (rs_wait)); /* pos diff */ - if (t < 1) /* min time */ - t = 1; - sim_activate (uptr, rs_wait * t); /* schedule */ - return SCPE_OK; - - default: /* all others */ - rs_set_er (ER_ILF, drv); /* not supported */ - break; - } - -rs_update_ds (DS_ATA, drv); /* set attn, req int */ -return MBE_GOE; -} - -/* Abort opertion - there is a data transfer in progress */ - -int32 rs_abort (void) -{ -return rs_reset (&rs_dev); -} - -/* Service unit timeout - - Complete search or data transfer command - Unit must exist - can't remove an active unit - Drives are buffered in memory - no IO errors -*/ - -t_stat rs_svc (UNIT *uptr) -{ -int32 i, fnc, dtype, drv; -int32 wc, abc, awc, mbc, da; -uint16 *fbuf = (uint16 *)uptr->filebuf; - -dtype = GET_DTYPE (uptr->flags); /* get drive type */ -drv = (int32) (uptr - rs_dev.units); /* get drv number */ -da = rsda[drv] * RS_NUMWD (dtype); /* get disk addr */ -fnc = GET_FNC (rscs1[drv]); /* get function */ - -if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ - rs_set_er (ER_UNS, drv); /* set drive error */ - if (fnc >= FNC_XFR) /* xfr? set done */ - mba_set_don (rs_dib.ba); - rs_update_ds (DS_ATA, drv); /* set attn */ - return (rs_stopioe? SCPE_UNATT: SCPE_OK); - } -rsds[drv] = (rsds[drv] & ~DS_PIP) | DS_RDY; /* change drive status */ - -switch (fnc) { /* case on function */ - - case FNC_SEARCH: /* search */ - rs_update_ds (DS_ATA, drv); - break; - - case FNC_WRITE: /* write */ - if ((uptr->flags & UNIT_WLK) && /* write locked? */ - (GET_TK (rsda[drv]) <= (int32) rswlk[drv])) { - rs_set_er (ER_WLE, drv); /* set drive error */ - mba_set_exc (rs_dib.ba); /* set exception */ - rs_update_ds (DS_ATA, drv); /* set attn */ - return SCPE_OK; - } /* fall through */ - case FNC_WCHK: /* write check */ - case FNC_READ: /* read */ - if (rsda[drv] & DA_INV) { /* bad addr? */ - rs_set_er (ER_IAE, drv); /* set error */ - mba_set_exc (rs_dib.ba); /* set exception */ - rs_update_ds (DS_ATA, drv); /* set attn */ - break; - } - fbuf = fbuf + da; /* ptr into buffer */ - mbc = mba_get_bc (rs_dib.ba); /* get byte count */ - wc = (mbc + 1) >> 1; /* convert to words */ - if ((da + wc) > RS_SIZE (dtype)) { /* disk overrun? */ - rs_set_er (ER_AOE, drv); /* set err */ - wc = RS_SIZE (dtype) - da; /* trim xfer */ - mbc = wc << 1; /* trim mb count */ - } - if (fnc == FNC_WRITE) { /* write? */ - abc = mba_rdbufW (rs_dib.ba, mbc, fbuf); /* rd mem to buf */ - wc = (abc + 1) >> 1; /* actual # wds */ - awc = (wc + (RS_NUMWD (dtype) - 1)) & ~(RS_NUMWD (dtype) - 1); - for (i = wc; i < awc; i++) /* fill buf */ - fbuf[i] = 0; - if ((da + awc) > (int32) uptr->hwmark) /* update hw mark*/ - uptr->hwmark = da + awc; - } /* end if wr */ - else if (fnc == FNC_READ) /* read */ - mba_wrbufW (rs_dib.ba, mbc, fbuf); /* wri buf to mem */ - else mba_chbufW (rs_dib.ba, mbc, fbuf); /* check vs mem */ - - da = da + wc + (RS_NUMWD (dtype) - 1); - if (da >= RS_SIZE (dtype)) - rsds[drv] = rsds[drv] | DS_LST; - rsda[drv] = (uint16)(da / RS_NUMWD (dtype)); - mba_set_don (rs_dib.ba); /* set done */ - rs_update_ds (0, drv); /* update ds */ - break; - } /* end case func */ - -if (DEBUG_PRS (rs_dev)) - fprintf (sim_deb, ">>RS%d DONE: fnc=%s, ds=%o, da=%o, er=%d\n", - drv, rs_fname[fnc], rsds[drv], rsda[drv], rser[drv]); -return SCPE_OK; -} - -/* Set drive error */ - -void rs_set_er (int32 flag, int32 drv) -{ -rser[drv] = rser[drv] | flag; -rsds[drv] = rsds[drv] | DS_ATA; -mba_upd_ata (rs_dib.ba, 1); -return; -} - -/* Clear attention flags */ - -void rs_clr_as (int32 mask) -{ -uint32 i, as; - -for (i = as = 0; i < RS_NUMDR; i++) { - if (mask & (AS_U0 << i)) - rsds[i] &= ~DS_ATA; - if (rsds[i] & DS_ATA) - as = 1; - } -mba_upd_ata (rs_dib.ba, as); -return; -} - -/* Drive status update */ - -void rs_update_ds (int32 flag, int32 drv) -{ -if (flag & DS_ATA) - mba_upd_ata (rs_dib.ba, 1); -if (rs_unit[drv].flags & UNIT_DIS) { - rsds[drv] = rser[drv] = 0; - return; - } -else rsds[drv] = (rsds[drv] | DS_DPR) & ~(DS_ERR | DS_WLK); -if (rs_unit[drv].flags & UNIT_ATT) { - rsds[drv] = rsds[drv] | DS_MOL; - if ((rs_unit[drv].flags & UNIT_WLK) && - (GET_TK (rsda[drv]) <= (int32) rswlk[drv])) - rsds[drv] = rsds[drv] | DS_WLK; - } -if (rser[drv]) - rsds[drv] = rsds[drv] | DS_ERR; -rsds[drv] = rsds[drv] | flag; -return; -} - -/* Device reset */ - -t_stat rs_reset (DEVICE *dptr) -{ -int32 i; -UNIT *uptr; - -mba_set_enbdis (MBA_RS, rs_dev.flags & DEV_DIS); -for (i = 0; i < RS_NUMDR; i++) { - uptr = rs_dev.units + i; - sim_cancel (uptr); - rscs1[i] = 0; - rser[i] = 0; - rsda[i] = 0; - rsmr[i] = 0; - rsds[i] = DS_RDY; - rs_update_ds (0, i); /* upd drive status */ - } -return SCPE_OK; -} - -/* Device attach */ - -t_stat rs_attach (UNIT *uptr, char *cptr) -{ -int32 drv, p; -t_stat r; - -uptr->capac = RS_SIZE (GET_DTYPE (uptr->flags)); -r = attach_unit (uptr, cptr); /* attach unit */ -if (r != SCPE_OK) /* error? */ - return r; -drv = (int32) (uptr - rs_dev.units); /* get drv number */ -rsds[drv] = DS_MOL | DS_RDY | DS_DPR; /* upd drv status */ -rser[drv] = 0; -rs_update_ds (DS_ATA, drv); /* upd drive status */ - -if ((uptr->flags & UNIT_AUTO) == 0) /* autosize? */ - return SCPE_OK; -p = sim_fsize (uptr->fileref); /* get file size */ -if (((p + 1) >> 1) <= RS03_SIZE) { - uptr->flags &= ~UNIT_DTYPE; - uptr->capac = RS03_SIZE; - } -else { - uptr->flags |= UNIT_DTYPE; - uptr->capac = RS04_SIZE; - } -return SCPE_OK; -} - -/* Device detach */ - -t_stat rs_detach (UNIT *uptr) -{ -int32 drv; - -if (!(uptr->flags & UNIT_ATT)) /* attached? */ - return SCPE_OK; -drv = (int32) (uptr - rs_dev.units); /* get drv number */ -rsds[drv] = 0; -if (!sim_is_running) /* from console? */ - rs_update_ds (DS_ATA, drv); /* request intr */ -return detach_unit (uptr); -} - -/* Set size command validation routine */ - -t_stat rs_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 dtype = GET_DTYPE (val); - -if (uptr->flags & UNIT_ATT) - return SCPE_ALATT; -uptr->capac = RS_SIZE (dtype); -return SCPE_OK; -} - -/* Set bad block routine */ - -/* Boot routine */ - -#define BOOT_START 02000 /* start */ -#define BOOT_ENTRY (BOOT_START + 002) /* entry */ -#define BOOT_UNIT (BOOT_START + 010) /* unit number */ -#define BOOT_CSR (BOOT_START + 014) /* CSR */ -#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint16)) - -static const uint16 boot_rom[] = { - 0042123, /* "SD" */ - 0012706, BOOT_START, /* mov #boot_start, sp */ - 0012700, 0000000, /* mov #unit, r0 */ - 0012701, 0172040, /* mov #RSCS1, r1 */ - 0012761, 0000040, 0000010, /* mov #CS2_CLR, 10(r1) ; reset */ - 0010061, 0000010, /* mov r0, 10(r1) ; set unit */ - 0012761, 0177000, 0000002, /* mov #-512., 2(r1) ; set wc */ - 0005061, 0000004, /* clr 4(r1) ; clr ba */ - 0005061, 0000006, /* clr 6(r1) ; clr da */ - 0012711, 0000071, /* mov #READ+GO, (r1) ; read */ - 0105711, /* tstb (r1) ; wait */ - 0100376, /* bpl .-2 */ - 0005002, /* clr R2 */ - 0005003, /* clr R3 */ - 0012704, BOOT_START+020, /* mov #start+020, r4 */ - 0005005, /* clr R5 */ - 0105011, /* clrb (r1) */ - 0005007 /* clr PC */ - }; - -t_stat rs_boot (int32 unitno, DEVICE *dptr) -{ -size_t i; -extern uint16 *M; - -for (i = 0; i < BOOT_LEN; i++) - M[(BOOT_START >> 1) + i] = boot_rom[i]; -M[BOOT_UNIT >> 1] = unitno & (RS_NUMDR - 1); -M[BOOT_CSR >> 1] = mba_get_csr (rs_dib.ba) & DMASK; -cpu_set_boot (BOOT_ENTRY); -return SCPE_OK; -} - diff --git a/PDP11/pdp11_rx.c b/PDP11/pdp11_rx.c deleted file mode 100644 index ce4192cd..00000000 --- a/PDP11/pdp11_rx.c +++ /dev/null @@ -1,535 +0,0 @@ -/* pdp11_rx.c: RX11/RX01 floppy disk simulator - - Copyright (c) 1993-2013, 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. - - rx RX11/RX01 floppy disk - - 23-Oct-13 RMS Revised for new boot setup routine - 03-Sep-13 RMS Added explicit void * cast - 07-Jul-05 RMS Removed extraneous externs - 12-Oct-02 RMS Added autoconfigure support - 08-Oct-02 RMS Added variable address support to bootstrap - Added vector change/display support - Revised state machine based on RX211 - New data structures - Fixed reset of disabled device - 26-Jan-02 RMS Revised bootstrap to conform to M9312 - 06-Jan-02 RMS Revised enable/disable support - 30-Nov-01 RMS Added read only unit, extended SET/SHOW support - 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 - 13-Apr-01 RMS Revised for register arrays - 15-Feb-01 RMS Corrected bootstrap string - 14-Apr-99 RMS Changed t_addr to unsigned - - An RX01 diskette consists of 77 tracks, each with 26 sectors of 128B. - Tracks are numbered 0-76, sectors 1-26. -*/ - -#include "pdp11_defs.h" - -#define RX_NUMTR 77 /* tracks/disk */ -#define RX_M_TRACK 0377 -#define RX_NUMSC 26 /* sectors/track */ -#define RX_M_SECTOR 0177 -#define RX_NUMBY 128 /* bytes/sector */ -#define RX_SIZE (RX_NUMTR * RX_NUMSC * RX_NUMBY) /* bytes/disk */ -#define RX_NUMDR 2 /* drives/controller */ -#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 */ -#define RWDT 2 /* rw, track next */ -#define RWXFR 3 /* rw, transfer */ -#define FILL 4 /* fill buffer */ -#define EMPTY 5 /* empty buffer */ -#define CMD_COMPLETE 6 /* set done next */ -#define INIT_COMPLETE 7 /* init compl next */ - -#define RXCS_V_FUNC 1 /* function */ -#define RXCS_M_FUNC 7 -#define RXCS_FILL 0 /* fill buffer */ -#define RXCS_EMPTY 1 /* empty buffer */ -#define RXCS_WRITE 2 /* write sector */ -#define RXCS_READ 3 /* read sector */ -#define RXCS_RXES 5 /* read status */ -#define RXCS_WRDEL 6 /* write del data */ -#define RXCS_ECODE 7 /* read error code */ -#define RXCS_V_DRV 4 /* drive select */ -#define RXCS_V_DONE 5 /* done */ -#define RXCS_V_IE 6 /* intr enable */ -#define RXCS_V_TR 7 /* xfer request */ -#define RXCS_V_INIT 14 /* init */ -#define RXCS_V_ERR 15 /* error */ -#define RXCS_FUNC (RXCS_M_FUNC << RXCS_V_FUNC) -#define RXCS_DRV (1u << RXCS_V_DRV) -#define RXCS_DONE (1u << RXCS_V_DONE) -#define RXCS_IE (1u << RXCS_V_IE) -#define RXCS_TR (1u << RXCS_V_TR) -#define RXCS_INIT (1u << RXCS_V_INIT) -#define RXCS_ERR (1u << RXCS_V_ERR) -#define RXCS_ROUT (RXCS_ERR+RXCS_TR+RXCS_IE+RXCS_DONE) -#define RXCS_IMP (RXCS_ROUT+RXCS_DRV+RXCS_FUNC) -#define RXCS_RW (RXCS_IE) /* read/write */ -#define RXCS_GETFNC(x) (((x) >> RXCS_V_FUNC) & RXCS_M_FUNC) - -#define RXES_CRC 0001 /* CRC error */ -#define RXES_PAR 0002 /* parity error */ -#define RXES_ID 0004 /* init done */ -#define RXES_WLK 0010 /* write protect */ -#define RXES_DD 0100 /* deleted data */ -#define RXES_DRDY 0200 /* drive ready */ - -#define TRACK u3 /* current track */ -#define CALC_DA(t,s) (((t) * RX_NUMSC) + ((s) - 1)) * RX_NUMBY - -extern int32 int_req[IPL_HLVL]; - -int32 rx_csr = 0; /* control/status */ -int32 rx_dbr = 0; /* data buffer */ -int32 rx_esr = 0; /* error status */ -int32 rx_ecode = 0; /* error code */ -int32 rx_track = 0; /* desired track */ -int32 rx_sector = 0; /* desired sector */ -int32 rx_state = IDLE; /* controller state */ -int32 rx_stopioe = 1; /* stop on error */ -int32 rx_cwait = 100; /* command time */ -int32 rx_swait = 10; /* seek, per track */ -int32 rx_xwait = 1; /* tr set time */ -uint8 rx_buf[RX_NUMBY] = { 0 }; /* sector buffer */ -int32 rx_bptr = 0; /* buffer pointer */ -int32 rx_enb = 1; /* device enable */ - -t_stat rx_rd (int32 *data, int32 PA, int32 access); -t_stat rx_wr (int32 data, int32 PA, int32 access); -t_stat rx_svc (UNIT *uptr); -t_stat rx_reset (DEVICE *dptr); -t_stat rx_boot (int32 unitno, DEVICE *dptr); -void rx_done (int32 esr_flags, int32 new_ecode); - -/* RX11 data structures - - rx_dev RX device descriptor - rx_unit RX unit list - rx_reg RX register list - rx_mod RX modifier list -*/ - -DIB rx_dib = { - IOBA_RX, IOLN_RX, &rx_rd, &rx_wr, - 1, IVCL (RX), VEC_RX, { NULL } - }; - -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) } - }; - -REG rx_reg[] = { - { ORDATA (RXCS, rx_csr, 16) }, - { ORDATA (RXDB, rx_dbr, 8) }, - { ORDATA (RXES, rx_esr, 8) }, - { ORDATA (RXERR, rx_ecode, 8) }, - { ORDATA (RXTA, rx_track, 8) }, - { ORDATA (RXSA, rx_sector, 8) }, - { DRDATA (STAPTR, rx_state, 3), REG_RO }, - { DRDATA (BUFPTR, rx_bptr, 7) }, - { FLDATA (INT, IREQ (RX), INT_V_RX) }, - { FLDATA (ERR, rx_csr, RXCS_V_ERR) }, - { FLDATA (TR, rx_csr, RXCS_V_TR) }, - { FLDATA (IE, rx_csr, RXCS_V_IE) }, - { FLDATA (DONE, rx_csr, RXCS_V_DONE) }, - { DRDATA (CTIME, rx_cwait, 24), PV_LEFT }, - { DRDATA (STIME, rx_swait, 24), PV_LEFT }, - { DRDATA (XTIME, rx_xwait, 24), PV_LEFT }, - { FLDATA (STOP_IOE, rx_stopioe, 0) }, - { BRDATA (SBUF, rx_buf, 8, 8, RX_NUMBY) }, - { ORDATA (DEVADDR, rx_dib.ba, 32), REG_HRO }, - { ORDATA (DEVVEC, rx_dib.vec, 16), REG_HRO }, - { NULL } - }; - -MTAB rx_mod[] = { - { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, -#if defined (VM_PDP11) - { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, NULL }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE", - &set_addr_flt, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", - &set_vec, &show_vec, NULL }, -#else - { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", - NULL, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", - NULL, &show_vec, NULL }, -#endif - { 0 } - }; - -DEVICE rx_dev = { - "RX", rx_unit, rx_reg, rx_mod, - RX_NUMDR, 8, 20, 1, 8, 8, - NULL, NULL, &rx_reset, - &rx_boot, NULL, NULL, - &rx_dib, DEV_FLTA | DEV_DISABLE | DEV_UBUS | DEV_QBUS - }; - -/* I/O dispatch routine, I/O addresses 17777170 - 17777172 - - 17777170 floppy CSR - 17777172 floppy data register -*/ - -t_stat rx_rd (int32 *data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 1) { /* decode PA<1> */ - - case 0: /* RXCS */ - rx_csr = rx_csr & RXCS_IMP; /* clear junk */ - *data = rx_csr & RXCS_ROUT; - break; - - case 1: /* RXDB */ - if ((rx_state == EMPTY) && (rx_csr & RXCS_TR)) {/* empty? */ - sim_activate (&rx_unit[0], rx_xwait); - rx_csr = rx_csr & ~RXCS_TR; /* clear xfer */ - } - *data = rx_dbr; /* return data */ - break; - } /* end switch PA */ - -return SCPE_OK; -} - -t_stat rx_wr (int32 data, int32 PA, int32 access) -{ -int32 drv; - -switch ((PA >> 1) & 1) { /* decode PA<1> */ - -/* Writing RXCS, three cases: - 1. Writing INIT, reset device - 2. Idle and writing new function - - clear error, done, transfer ready, int req - - save int enable, function, drive - - start new function - 3. Otherwise, write IE and update interrupts -*/ - - case 0: /* RXCS */ - rx_csr = rx_csr & RXCS_IMP; /* clear junk */ - if (access == WRITEB) data = (PA & 1)? /* write byte? */ - (rx_csr & 0377) | (data << 8): (rx_csr & ~0377) | data; - if (data & RXCS_INIT) { /* initialize? */ - rx_reset (&rx_dev); /* reset device */ - return SCPE_OK; /* end if init */ - } - if ((data & CSR_GO) && (rx_state == IDLE)) { /* new function? */ - rx_csr = data & (RXCS_IE + RXCS_DRV + RXCS_FUNC); - drv = ((rx_csr & RXCS_DRV)? 1: 0); /* reselect drive */ - rx_bptr = 0; /* clear buf pointer */ - switch (RXCS_GETFNC (data)) { /* case on func */ - - case RXCS_FILL: - rx_state = FILL; /* state = fill */ - rx_csr = rx_csr | RXCS_TR; /* xfer is ready */ - break; - - case RXCS_EMPTY: - rx_state = EMPTY; /* state = empty */ - sim_activate (&rx_unit[drv], rx_xwait); - break; - - case RXCS_READ: case RXCS_WRITE: case RXCS_WRDEL: - rx_state = RWDS; /* state = get sector */ - rx_csr = rx_csr | RXCS_TR; /* xfer is ready */ - rx_esr = rx_esr & RXES_ID; /* clear errors */ - break; - - default: - rx_state = CMD_COMPLETE; /* state = cmd compl */ - sim_activate (&rx_unit[drv], rx_cwait); - break; - } /* end switch func */ - return SCPE_OK; - } /* end if GO */ - if ((data & RXCS_IE) == 0) - CLR_INT (RX); - else if ((rx_csr & (RXCS_DONE + RXCS_IE)) == RXCS_DONE) - SET_INT (RX); - rx_csr = (rx_csr & ~RXCS_RW) | (data & RXCS_RW); - break; /* end case RXCS */ - -/* Accessing RXDB, two cases: - 1. Write idle, write - 2. Write not idle and TR set, state dependent -*/ - - case 1: /* RXDB */ - if ((PA & 1) || ((rx_state != IDLE) && ((rx_csr & RXCS_TR) == 0))) - return SCPE_OK; /* if ~IDLE, need tr */ - rx_dbr = data & 0377; /* save data */ - if ((rx_state != IDLE) && (rx_state != EMPTY)) { - drv = ((rx_csr & RXCS_DRV)? 1: 0); /* select drive */ - sim_activate (&rx_unit[drv], rx_xwait); /* sched event */ - rx_csr = rx_csr & ~RXCS_TR; /* clear xfer */ - } - break; /* end case RXDB */ - } /* end switch PA */ - -return SCPE_OK; -} - -/* Unit service; the action to be taken depends on the transfer state: - - IDLE Should never get here - RWDS Save sector, set TR, set RWDT - RWDT Save track, set RWXFR - RWXFR Read/write buffer - FILL copy ir to rx_buf[rx_bptr], advance ptr - if rx_bptr > max, finish command, else set tr - EMPTY if rx_bptr > max, finish command, else - copy rx_buf[rx_bptr] to ir, advance ptr, set tr - CMD_COMPLETE copy requested data to ir, finish command - INIT_COMPLETE read drive 0, track 1, sector 1 to buffer, finish command - - For RWDT and CMD_COMPLETE, the input argument is the selected drive; - otherwise, it is drive 0. -*/ - -t_stat rx_svc (UNIT *uptr) -{ -int32 i, func; -uint32 da; -int8 *fbuf = (int8 *) uptr->filebuf; - -func = RXCS_GETFNC (rx_csr); /* get function */ -switch (rx_state) { /* case on state */ - - case IDLE: /* idle */ - return SCPE_IERR; /* done */ - - case EMPTY: /* empty buffer */ - if (rx_bptr >= RX_NUMBY) /* done all? */ - rx_done (0, 0); - else { - rx_dbr = rx_buf[rx_bptr]; /* get next */ - rx_bptr = rx_bptr + 1; - rx_csr = rx_csr | RXCS_TR; /* set xfer */ - } - break; - - case FILL: /* fill buffer */ - rx_buf[rx_bptr] = (uint8)rx_dbr; /* write next */ - rx_bptr = rx_bptr + 1; - if (rx_bptr < RX_NUMBY) /* more? set xfer */ - rx_csr = rx_csr | RXCS_TR; - else rx_done (0, 0); /* else done */ - break; - - case RWDS: /* wait for sector */ - rx_sector = rx_dbr & RX_M_SECTOR; /* save sector */ - rx_csr = rx_csr | RXCS_TR; /* set xfer */ - rx_state = RWDT; /* advance state */ - return SCPE_OK; - - case RWDT: /* wait for track */ - rx_track = rx_dbr & RX_M_TRACK; /* save track */ - rx_state = RWXFR; - sim_activate (uptr, /* sched done */ - rx_swait * abs (rx_track - uptr->TRACK)); - return SCPE_OK; - - case RWXFR: - if ((uptr->flags & UNIT_BUF) == 0) { /* not buffered? */ - rx_done (0, 0110); /* done, error */ - return IORETURN (rx_stopioe, SCPE_UNATT); - } - if (rx_track >= RX_NUMTR) { /* bad track? */ - rx_done (0, 0040); /* done, error */ - break; - } - uptr->TRACK = rx_track; /* now on track */ - if ((rx_sector == 0) || (rx_sector > RX_NUMSC)) { /* bad sect? */ - rx_done (0, 0070); /* done, error */ - break; - } - da = CALC_DA (rx_track, rx_sector); /* get disk address */ - if (func == RXCS_WRDEL) /* del data? */ - rx_esr = rx_esr | RXES_DD; - if (func == RXCS_READ) { /* read? */ - for (i = 0; i < RX_NUMBY; i++) - rx_buf[i] = fbuf[da + i]; - } - else { - if (uptr->flags & UNIT_WPRT) { /* write and locked? */ - rx_done (RXES_WLK, 0100); /* done, error */ - break; - } - for (i = 0; i < RX_NUMBY; i++) /* write */ - fbuf[da + i] = rx_buf[i]; - da = da + RX_NUMBY; - if (da > uptr->hwmark) - uptr->hwmark = da; - } - rx_done (0, 0); /* done */ - break; - - case CMD_COMPLETE: /* command complete */ - if (func == RXCS_ECODE) { /* read ecode? */ - rx_dbr = rx_ecode; /* set dbr */ - rx_done (0, -1); /* don't update */ - } - else rx_done (0, 0); - break; - - case INIT_COMPLETE: /* init complete */ - rx_unit[0].TRACK = 1; /* drive 0 to trk 1 */ - rx_unit[1].TRACK = 0; /* drive 1 to trk 0 */ - if ((rx_unit[0].flags & UNIT_BUF) == 0) { /* not buffered? */ - rx_done (RXES_ID, 0010); /* init done, error */ - break; - } - da = CALC_DA (1, 1); /* track 1, sector 1 */ - for (i = 0; i < RX_NUMBY; i++) /* read sector */ - rx_buf[i] = fbuf[da + i]; - rx_done (RXES_ID, 0); /* set done */ - if ((rx_unit[1].flags & UNIT_ATT) == 0) - rx_ecode = 0020; - break; - } /* end case state */ - -return SCPE_OK; -} - -/* Command complete. Set done and put final value in interface register, - request interrupt if needed, return to IDLE state. -*/ - -void rx_done (int32 esr_flags, int32 new_ecode) -{ -int32 drv = (rx_csr & RXCS_DRV)? 1: 0; - -rx_state = IDLE; /* now idle */ -rx_csr = rx_csr | RXCS_DONE; /* set done */ -if (rx_csr & RXCS_IE) SET_INT (RX); /* if ie, intr */ -rx_esr = (rx_esr | esr_flags) & ~RXES_DRDY; -if (rx_unit[drv].flags & UNIT_ATT) - rx_esr = rx_esr | RXES_DRDY; -if (new_ecode > 0) /* test for error */ - rx_csr = rx_csr | RXCS_ERR; -if (new_ecode < 0) /* don't update? */ - return; -rx_ecode = new_ecode; /* update ecode */ -rx_dbr = rx_esr; /* update RXDB */ -return; -} - -/* Device initialization. The RX is one of the few devices that schedules - an I/O transfer as part of its initialization. -*/ - -t_stat rx_reset (DEVICE *dptr) -{ -rx_csr = rx_dbr = 0; /* clear regs */ -rx_esr = rx_ecode = 0; /* clear error */ -rx_track = rx_sector = 0; /* clear addr */ -rx_state = IDLE; /* ctrl idle */ -CLR_INT (RX); /* clear int req */ -sim_cancel (&rx_unit[1]); /* cancel drive 1 */ -if (dptr->flags & DEV_DIS) /* disabled? */ - sim_cancel (&rx_unit[0]); -else if (rx_unit[0].flags & UNIT_BUF) { /* attached? */ - rx_state = INIT_COMPLETE; /* yes, sched init */ - sim_activate (&rx_unit[0], rx_swait * abs (1 - rx_unit[0].TRACK)); - } -else rx_done (0, 0010); /* no, error */ -return auto_config (0, 0); /* run autoconfig */ -} - -/* Device bootstrap */ - -#define BOOT_START 02000 /* start */ -#define BOOT_ENTRY (BOOT_START + 002) /* entry */ -#define BOOT_UNIT (BOOT_START + 010) /* unit number */ -#define BOOT_CSR (BOOT_START + 026) /* CSR */ -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) - -static const uint16 boot_rom[] = { - 042130, /* "XD" */ - 0012706, BOOT_START, /* MOV #boot_start, SP */ - 0012700, 0000000, /* MOV #unit, R0 ; unit number */ - 0010003, /* MOV R0, R3 */ - 0006303, /* ASL R3 */ - 0006303, /* ASL R3 */ - 0006303, /* ASL R3 */ - 0006303, /* ASL R3 */ - 0012701, 0177170, /* MOV #RXCS, R1 ; csr */ - 0032711, 0000040, /* BITB #40, (R1) ; ready? */ - 0001775, /* BEQ .-4 */ - 0052703, 0000007, /* BIS #READ+GO, R3 */ - 0010311, /* MOV R3, (R1) ; read & go */ - 0105711, /* TSTB (R1) ; xfr ready? */ - 0100376, /* BPL .-2 */ - 0012761, 0000001, 0000002, /* MOV #1, 2(R1) ; sector */ - 0105711, /* TSTB (R1) ; xfr ready? */ - 0100376, /* BPL .-2 */ - 0012761, 0000001, 0000002, /* MOV #1, 2(R1) ; track */ - 0005003, /* CLR R3 */ - 0032711, 0000040, /* BITB #40, (R1) ; ready? */ - 0001775, /* BEQ .-4 */ - 0012711, 0000003, /* MOV #EMPTY+GO, (R1) ; empty & go */ - 0105711, /* TSTB (R1) ; xfr, done? */ - 0001776, /* BEQ .-2 */ - 0100003, /* BPL .+010 */ - 0116123, 0000002, /* MOVB 2(R1), (R3)+ ; move byte */ - 0000772, /* BR .-012 */ - 0005002, /* CLR R2 */ - 0005003, /* CLR R3 */ - 0012704, BOOT_START+020, /* MOV #START+20, R4 */ - 0005005, /* CLR R5 */ - 0005007 /* CLR R7 */ - }; - -t_stat rx_boot (int32 unitno, DEVICE *dptr) -{ -size_t i; -extern uint16 *M; - -for (i = 0; i < BOOT_LEN; i++) - M[(BOOT_START >> 1) + i] = boot_rom[i]; -M[BOOT_UNIT >> 1] = unitno & RX_M_NUMDR; -M[BOOT_CSR >> 1] = rx_dib.ba & DMASK; -cpu_set_boot (BOOT_ENTRY); -return SCPE_OK; -} diff --git a/PDP11/pdp11_ry.c b/PDP11/pdp11_ry.c deleted file mode 100644 index abf78326..00000000 --- a/PDP11/pdp11_ry.c +++ /dev/null @@ -1,702 +0,0 @@ -/* pdp11_ry.c: RX211/RXV21/RX02 floppy disk simulator - - Copyright (c) 1993-2013, Robert M Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - ry RX211/RXV21/RX02 floppy disk - - 23-Oct-13 RMS Revised for new boot setup routine - 03-Sep-13 RMS Added explicit void * cast - 15-May-06 RMS Fixed bug in autosize attach (David Gesswein) - 07-Jul-05 RMS Removed extraneous externs - 18-Feb-05 RMS Fixed bug in boot code (Graham Toal) - 30-Sep-04 RMS Revised Unibus interface - 21-Mar-04 RMS Added VAX support - 29-Dec-03 RMS Added RXV21 support - 19-May-03 RMS Revised for new conditional compilation scheme - 25-Apr-03 RMS Revised for extended file support - 14-Mar-03 RMS Fixed variable size interaction with save/restore - 03-Mar-03 RMS Fixed autosizing - 12-Oct-02 RMS Added autoconfigure support - - An RX02 diskette consists of 77 tracks, each with 26 sectors of 256B. - Tracks are numbered 0-76, sectors 1-26. -*/ - -#if defined (VM_PDP10) /* PDP10 version */ -#include "pdp10_defs.h" -extern int32 int_req; -#define DEV_DISI DEV_DIS - -#elif defined (VM_VAX) /* VAX version */ -#include "vax_defs.h" -extern int32 int_req[IPL_HLVL]; -#define DEV_DISI 0 - -#else /* PDP-11 version */ -#include "pdp11_defs.h" -extern int32 int_req[IPL_HLVL]; -#define DEV_DISI DEV_DIS -#endif - -#define RX_NUMTR 77 /* tracks/disk */ -#define RX_M_TRACK 0377 -#define RX_NUMSC 26 /* sectors/track */ -#define RX_M_SECTOR 0177 -#define RX_NUMBY 128 -#define RX_SIZE (RX_NUMTR * RX_NUMSC * RX_NUMBY) -#define RY_NUMBY 256 /* bytes/sector */ -#define RY_SIZE (RX_NUMTR * RX_NUMSC * RY_NUMBY) -#define RX_NUMDR 2 /* drives/controller */ -#define RX_M_NUMDR 01 -#define UNIT_V_WLK (UNIT_V_UF) /* write locked */ -#define UNIT_V_DEN (UNIT_V_UF + 1) /* double density */ -#define UNIT_V_AUTO (UNIT_V_UF + 2) /* autosize */ -#define UNIT_WLK (1u << UNIT_V_WLK) -#define UNIT_DEN (1u << UNIT_V_DEN) -#define UNIT_AUTO (1u << UNIT_V_AUTO) -#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ - -#define IDLE 0 /* idle state */ -#define RWDS 1 /* rw, sect next */ -#define RWDT 2 /* rw, track next */ -#define RWXFR 3 /* rw, transfer */ -#define FEWC 4 /* fill empty, wc next */ -#define FEBA 5 /* fill empty, ba next */ -#define FEXFR 6 /* fill empty, transfer */ -#define SDCNF 7 /* set dens, conf next */ -#define SDXFR 8 /* set dens, transfer */ -#define ESBA 9 /* ext sta, ba next */ -#define ESXFR 10 /* ext sta, transfer */ -#define CMD_COMPLETE 11 /* set done next */ -#define INIT_COMPLETE 12 /* init compl next */ - -#define RYCS_V_FUNC 1 /* function */ -#define RYCS_M_FUNC 7 -#define RYCS_FILL 0 /* fill buffer */ -#define RYCS_EMPTY 1 /* empty buffer */ -#define RYCS_WRITE 2 /* write sector */ -#define RYCS_READ 3 /* read sector */ -#define RYCS_SDEN 4 /* set density */ -#define RYCS_RYES 5 /* read status */ -#define RYCS_WRDEL 6 /* write del data */ -#define RYCS_ESTAT 7 /* read ext status */ -#define RYCS_V_DRV 4 /* drive select */ -#define RYCS_V_DONE 5 /* done */ -#define RYCS_V_IE 6 /* int enable */ -#define RYCS_V_TR 7 /* xfer request */ -#define RYCS_V_DEN 8 /* density select */ -#define RYCS_V_RY 11 /* RX02 flag */ -#define RYCS_V_UAE 12 /* addr ext */ -#define RYCS_M_UAE 03 -#define RYCS_V_INIT 14 /* init */ -#define RYCS_V_ERR 15 /* error */ -#define RYCS_FUNC (RYCS_M_FUNC << RYCS_V_FUNC) -#define RYCS_DRV (1u << RYCS_V_DRV) -#define RYCS_DONE (1u << RYCS_V_DONE) -#define RYCS_IE (1u << RYCS_V_IE) -#define RYCS_TR (1u << RYCS_V_TR) -#define RYCS_DEN (1u << RYCS_V_DEN) -#define RYCS_RY (1u << RYCS_V_RY) -#define RYCS_UAE (RYCS_M_UAE << RYCS_V_UAE) -#define RYCS_INIT (1u << RYCS_V_INIT) -#define RYCS_ERR (1u << RYCS_V_ERR) -#define RYCS_IMP (RYCS_ERR+RYCS_UAE+RYCS_DEN+RYCS_TR+RYCS_IE+\ - RYCS_DONE+RYCS_DRV+RYCS_FUNC) -#define RYCS_RW (RYCS_UAE+RYCS_DEN+RYCS_IE+RYCS_DRV+RYCS_FUNC) -#define RYCS_GETFNC(x) (((x) >> RYCS_V_FUNC) & RYCS_M_FUNC) -#define RYCS_GETUAE(x) (((x) >> RYCS_V_UAE) & RYCS_M_UAE) - -#define RYES_CRC 00001 /* CRC error NI */ -#define RYES_ID 00004 /* init done */ -#define RYES_ACLO 00010 /* ACLO NI */ -#define RYES_DERR 00020 /* density err */ -#define RYES_DDEN 00040 /* drive density */ -#define RYES_DD 00100 /* deleted data */ -#define RYES_DRDY 00200 /* drive ready */ -#define RYES_USEL 00400 /* unit selected */ -#define RYES_WCO 02000 /* wc overflow */ -#define RYES_NXM 04000 /* nxm */ -#define RYES_ERR (RYES_NXM|RYES_WCO|RYES_DERR|RYES_ACLO|RYES_CRC) - -#define TRACK u3 /* current track */ -#define CALC_DA(t,s,b) (((t) * RX_NUMSC) + ((s) - 1)) * b - -int32 ry_csr = 0; /* control/status */ -int32 ry_dbr = 0; /* data buffer */ -int32 ry_esr = 0; /* error status */ -int32 ry_ecode = 0; /* error code */ -int32 ry_track = 0; /* desired track */ -int32 ry_sector = 0; /* desired sector */ -int32 ry_ba = 0; /* bus addr */ -int32 ry_wc = 0; /* word count */ -int32 ry_state = IDLE; /* controller state */ -int32 ry_stopioe = 1; /* stop on error */ -int32 ry_cwait = 100; /* command time */ -int32 ry_swait = 10; /* seek, per track */ -int32 ry_xwait = 1; /* tr set time */ -uint8 rx2xb[RY_NUMBY] = { 0 }; /* sector buffer */ - -t_stat ry_rd (int32 *data, int32 PA, int32 access); -t_stat ry_wr (int32 data, int32 PA, int32 access); -t_stat ry_svc (UNIT *uptr); -t_stat ry_reset (DEVICE *dptr); -t_stat ry_boot (int32 unitno, DEVICE *dptr); -void ry_done (int32 esr_flags, int32 new_ecode); -t_stat ry_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat ry_attach (UNIT *uptr, char *cptr); - -/* RY11 data structures - - ry_dev RY device descriptor - ry_unit RY unit list - ry_reg RY register list - ry_mod RY modifier list -*/ - -DIB ry_dib = { - IOBA_RY, IOLN_RY, &ry_rd, &ry_wr, - 1, IVCL (RY), VEC_RY, { NULL } - }; - -UNIT ry_unit[] = { - { UDATA (&ry_svc, UNIT_DEN+UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, - RY_SIZE) }, - { UDATA (&ry_svc, UNIT_DEN+UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, - RY_SIZE) } - }; - -REG ry_reg[] = { - { GRDATA (RYCS, ry_csr, DEV_RDX, 16, 0) }, - { GRDATA (RYBA, ry_ba, DEV_RDX, 16, 0) }, - { GRDATA (RYWC, ry_wc, DEV_RDX, 8, 0) }, - { GRDATA (RYDB, ry_dbr, DEV_RDX, 16, 0) }, - { GRDATA (RYES, ry_esr, DEV_RDX, 12, 0) }, - { GRDATA (RYERR, ry_ecode, DEV_RDX, 8, 0) }, - { GRDATA (RYTA, ry_track, DEV_RDX, 8, 0) }, - { GRDATA (RYSA, ry_sector, DEV_RDX, 8, 0) }, - { DRDATA (STAPTR, ry_state, 4), REG_RO }, - { FLDATA (INT, IREQ (RY), INT_V_RY) }, - { FLDATA (ERR, ry_csr, RYCS_V_ERR) }, - { FLDATA (TR, ry_csr, RYCS_V_TR) }, - { FLDATA (IE, ry_csr, RYCS_V_IE) }, - { FLDATA (DONE, ry_csr, RYCS_V_DONE) }, - { DRDATA (CTIME, ry_cwait, 24), PV_LEFT }, - { DRDATA (STIME, ry_swait, 24), PV_LEFT }, - { DRDATA (XTIME, ry_xwait, 24), PV_LEFT }, - { BRDATA (SBUF, rx2xb, 8, 8, RY_NUMBY) }, - { FLDATA (STOP_IOE, ry_stopioe, 0) }, - { URDATA (CAPAC, ry_unit[0].capac, 10, T_ADDR_W, 0, - RX_NUMDR, REG_HRO | PV_LEFT) }, - { GRDATA (DEVADDR, ry_dib.ba, DEV_RDX, 32, 0), REG_HRO }, - { GRDATA (DEVVEC, ry_dib.vec, DEV_RDX, 16, 0), REG_HRO }, - { NULL } - }; - -MTAB ry_mod[] = { - { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, - { (UNIT_DEN+UNIT_ATT), UNIT_ATT, "single density", NULL, NULL }, - { (UNIT_DEN+UNIT_ATT), (UNIT_DEN+UNIT_ATT), "double density", NULL, NULL }, - { (UNIT_AUTO+UNIT_DEN+UNIT_ATT), 0, "single density", NULL, NULL }, - { (UNIT_AUTO+UNIT_DEN+UNIT_ATT), UNIT_DEN, "double density", NULL, NULL }, - { (UNIT_AUTO+UNIT_ATT), UNIT_AUTO, "autosize", NULL, NULL }, - { UNIT_AUTO, UNIT_AUTO, NULL, "AUTOSIZE", NULL }, - { (UNIT_AUTO+UNIT_DEN), 0, NULL, "SINGLE", &ry_set_size }, - { (UNIT_AUTO+UNIT_DEN), UNIT_DEN, NULL, "DOUBLE", &ry_set_size }, -#if defined (VM_PDP11) - { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, NULL }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE", - &set_addr_flt, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", - &set_vec, &show_vec, NULL }, -#else - { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", - NULL, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", - NULL, &show_vec, NULL }, -#endif - { 0 } - }; - -DEVICE ry_dev = { - "RY", ry_unit, ry_reg, ry_mod, - RX_NUMDR, DEV_RDX, 20, 1, DEV_RDX, 8, - NULL, NULL, &ry_reset, - &ry_boot, &ry_attach, NULL, - &ry_dib, DEV_FLTA | DEV_DISABLE | DEV_DISI | DEV_UBUS | DEV_Q18 - }; - -/* I/O dispatch routine, I/O addresses 17777170 - 17777172 - - 17777170 floppy CSR - 17777172 floppy data register -*/ - -t_stat ry_rd (int32 *data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 1) { /* decode PA<1> */ - - case 0: /* RYCS */ - ry_csr = (ry_csr & RYCS_IMP) | RYCS_RY; /* clear junk */ - *data = ry_csr; - break; - - case 1: /* RYDB */ - *data = ry_dbr; /* return data */ - break; - } /* end switch PA */ - -return SCPE_OK; -} - -t_stat ry_wr (int32 data, int32 PA, int32 access) -{ -int32 drv; - -switch ((PA >> 1) & 1) { /* decode PA<1> */ - -/* Writing RYCS, three cases: - 1. Writing INIT, reset device - 2. Idle and writing new function - - clear error, done, transfer ready, int req - - save int enable, function, drive - - start new function - 3. Otherwise, write IE and update interrupts -*/ - - case 0: /* RYCS */ - ry_csr = (ry_csr & RYCS_IMP) | RYCS_RY; /* clear junk */ - if (access == WRITEB) data = (PA & 1)? /* write byte? */ - (ry_csr & 0377) | (data << 8): (ry_csr & ~0377) | data; - if (data & RYCS_INIT) { /* initialize? */ - ry_reset (&ry_dev); /* reset device */ - return SCPE_OK; /* end if init */ - } - if ((data & CSR_GO) && (ry_state == IDLE)) { /* new function? */ - ry_csr = (data & RYCS_RW) | RYCS_RY; - drv = ((ry_csr & RYCS_DRV)? 1: 0); /* reselect drv */ - switch (RYCS_GETFNC (data)) { - - case RYCS_FILL: case RYCS_EMPTY: - ry_state = FEWC; /* state = get wc */ - ry_csr = ry_csr | RYCS_TR; /* xfer is ready */ - break; - - case RYCS_SDEN: - ry_state = SDCNF; /* state = get conf */ - ry_csr = ry_csr | RYCS_TR; /* xfer is ready */ - break; - - case RYCS_ESTAT: - ry_state = ESBA; /* state = get ba */ - ry_csr = ry_csr | RYCS_TR; /* xfer is ready */ - break; - - case RYCS_READ: case RYCS_WRITE: case RYCS_WRDEL: - ry_state = RWDS; /* state = get sector */ - ry_csr = ry_csr | RYCS_TR; /* xfer is ready */ - ry_esr = ry_esr & RYES_ID; /* clear errors */ - ry_ecode = 0; - break; - - default: - ry_state = CMD_COMPLETE; /* state = cmd compl */ - sim_activate (&ry_unit[drv], ry_cwait); - break; - } /* end switch func */ - return SCPE_OK; - } /* end if GO */ - if ((data & RYCS_IE) == 0) - CLR_INT (RY); - else if ((ry_csr & (RYCS_DONE + RYCS_IE)) == RYCS_DONE) - SET_INT (RY); - ry_csr = (ry_csr & ~RYCS_RW) | (data & RYCS_RW); - break; /* end case RYCS */ - -/* Accessing RYDB, two cases: - 1. Write idle, write - 2. Write not idle and TR set, state dependent -*/ - - case 1: /* RYDB */ - if ((PA & 1) || ((ry_state != IDLE) && ((ry_csr & RYCS_TR) == 0))) - return SCPE_OK; /* if ~IDLE, need tr */ - ry_dbr = data; /* save data */ - if (ry_state != IDLE) { - drv = ((ry_csr & RYCS_DRV)? 1: 0); /* select drv */ - sim_activate (&ry_unit[drv], ry_xwait); /* sched event */ - ry_csr = ry_csr & ~RYCS_TR; /* clear xfer */ - } - break; /* end case RYDB */ - } /* end switch PA */ - -return SCPE_OK; -} - -/* Unit service; the action to be taken depends on the transfer state: - - IDLE Should never get here - FEWC Save word count, set TR, set FEBA - FEBA Save bus address, set FEXFR - FEXFR Fill/empty buffer - RWDS Save sector, set TR, set RWDT - RWDT Save track, set RWXFR - RWXFR Read/write buffer - SDCNF Check confirmation, set SDXFR - SDXFR Erase disk - CMD_COMPLETE copy requested data to ir, finish command - INIT_COMPLETE read drive 0, track 1, sector 1 to buffer, finish command -*/ - -t_stat ry_svc (UNIT *uptr) -{ -int32 i, t, func, bps; -static uint8 estat[8]; -uint32 ba, da; -int8 *fbuf = (int8 *) uptr->filebuf; - -func = RYCS_GETFNC (ry_csr); /* get function */ -bps = (ry_csr & RYCS_DEN)? RY_NUMBY: RX_NUMBY; /* get sector size */ -ba = (RYCS_GETUAE (ry_csr) << 16) | ry_ba; /* get mem addr */ -switch (ry_state) { /* case on state */ - - case IDLE: /* idle */ - return SCPE_IERR; - - case FEWC: /* word count */ - ry_wc = ry_dbr & 0377; /* save WC */ - ry_csr = ry_csr | RYCS_TR; /* set TR */ - ry_state = FEBA; /* next state */ - return SCPE_OK; - - case FEBA: /* buffer address */ - ry_ba = ry_dbr; /* save buf addr */ - ry_state = FEXFR; /* next state */ - sim_activate (uptr, ry_cwait); /* schedule xfer */ - return SCPE_OK; - - case FEXFR: /* transfer */ - if ((ry_wc << 1) > bps) { /* wc too big? */ - ry_done (RYES_WCO, 0230); /* error */ - break; - } - if (func == RYCS_FILL) { /* fill? read */ - for (i = 0; i < RY_NUMBY; i++) - rx2xb[i] = 0; - t = Map_ReadB (ba, ry_wc << 1, rx2xb); - } - else t = Map_WriteB (ba, ry_wc << 1, rx2xb); - ry_wc = t >> 1; /* adjust wc */ - ry_done (t? RYES_NXM: 0, 0); /* done */ - break; - - case RWDS: /* wait for sector */ - ry_sector = ry_dbr & RX_M_SECTOR; /* save sector */ - ry_csr = ry_csr | RYCS_TR; /* set xfer */ - ry_state = RWDT; /* advance state */ - return SCPE_OK; - - case RWDT: /* wait for track */ - ry_track = ry_dbr & RX_M_TRACK; /* save track */ - ry_state = RWXFR; /* next state */ - sim_activate (uptr, /* sched xfer */ - ry_swait * abs (ry_track - uptr->TRACK)); - return SCPE_OK; - - case RWXFR: /* read/write */ - if ((uptr->flags & UNIT_BUF) == 0) { /* not buffered? */ - ry_done (0, 0110); /* done, error */ - return IORETURN (ry_stopioe, SCPE_UNATT); - } - if (ry_track >= RX_NUMTR) { /* bad track? */ - ry_done (0, 0040); /* done, error */ - break; - } - uptr->TRACK = ry_track; /* now on track */ - if ((ry_sector == 0) || (ry_sector > RX_NUMSC)) { /* bad sect? */ - ry_done (0, 0070); /* done, error */ - break; - } - if (((uptr->flags & UNIT_DEN) != 0) ^ - ((ry_csr & RYCS_DEN) != 0)) { /* densities agree? */ - ry_done (RYES_DERR, 0240); /* no, error */ - break; - } - da = CALC_DA (ry_track, ry_sector, bps); /* get disk address */ - if (func == RYCS_WRDEL) /* del data? */ - ry_esr = ry_esr | RYES_DD; - if (func == RYCS_READ) { /* read? */ - for (i = 0; i < bps; i++) - rx2xb[i] = fbuf[da + i]; - } - else { - if (uptr->flags & UNIT_WPRT) { /* write and locked? */ - ry_done (0, 0100); /* done, error */ - break; - } - for (i = 0; i < bps; i++) /* write */ - fbuf[da + i] = rx2xb[i]; - da = da + bps; - if (da > uptr->hwmark) - uptr->hwmark = da; - } - ry_done (0, 0); /* done */ - break; - - case SDCNF: /* confirm set density */ - if ((ry_dbr & 0377) != 0111) { /* confirmed? */ - ry_done (0, 0250); /* no, error */ - break; - } - ry_state = SDXFR; /* next state */ - sim_activate (uptr, ry_cwait * 100); /* schedule operation */ - break; - - case SDXFR: /* erase disk */ - for (i = 0; i < (int32) uptr->capac; i++) - fbuf[i] = 0; - uptr->hwmark = (uint32) uptr->capac; - if (ry_csr & RYCS_DEN) - uptr->flags = uptr->flags | UNIT_DEN; - else uptr->flags = uptr->flags & ~UNIT_DEN; - ry_done (0, 0); - break; - - - case ESBA: - ry_ba = ry_dbr; /* save WC */ - ry_state = ESXFR; /* next state */ - sim_activate (uptr, ry_cwait); /* schedule xfer */ - return SCPE_OK; - - case ESXFR: - estat[0] = ry_ecode; /* fill 8B status */ - estat[1] = ry_wc; - estat[2] = (uint8)ry_unit[0].TRACK; - estat[3] = (uint8)ry_unit[1].TRACK; - estat[4] = ry_track; - estat[5] = ry_sector; - estat[6] = ((ry_csr & RYCS_DRV)? 0200: 0) | - ((ry_unit[1].flags & UNIT_DEN)? 0100: 0) | - ((uptr->flags & UNIT_ATT)? 0040: 0) | - ((ry_unit[0].flags & UNIT_DEN)? 0020: 0) | - ((ry_csr & RYCS_DEN)? 0001: 0); - estat[7] = (uint8)uptr->TRACK; - t = Map_WriteB (ba, 8, estat); /* DMA to memory */ - ry_done (t? RYES_NXM: 0, 0); /* done */ - break; - - case CMD_COMPLETE: /* command complete */ - ry_done (0, 0); - break; - - case INIT_COMPLETE: /* init complete */ - ry_unit[0].TRACK = 1; /* drive 0 to trk 1 */ - ry_unit[1].TRACK = 0; /* drive 1 to trk 0 */ - if ((uptr->flags & UNIT_BUF) == 0) { /* not buffered? */ - ry_done (RYES_ID, 0010); /* init done, error */ - break; - } - da = CALC_DA (1, 1, bps); /* track 1, sector 1 */ - for (i = 0; i < bps; i++) /* read sector */ - rx2xb[i] = fbuf[da + i]; - ry_done (RYES_ID, 0); /* set done */ - if ((ry_unit[1].flags & UNIT_ATT) == 0) - ry_ecode = 0020; - break; - } /* end case state */ - -return SCPE_OK; -} - -/* Command complete. Set done and put final value in interface register, - request interrupt if needed, return to IDLE state. -*/ - -void ry_done (int32 esr_flags, int32 new_ecode) -{ -int32 drv = (ry_csr & RYCS_DRV)? 1: 0; - -ry_state = IDLE; /* now idle */ -ry_csr = ry_csr | RYCS_DONE; /* set done */ -if (ry_csr & CSR_IE) /* if ie, intr */ - SET_INT (RY); -ry_esr = (ry_esr | esr_flags) & ~(RYES_USEL|RYES_DDEN|RYES_DRDY); -if (drv) /* updates RYES */ - ry_esr = ry_esr | RYES_USEL; -if (ry_unit[drv].flags & UNIT_ATT) { - ry_esr = ry_esr | RYES_DRDY; - if (ry_unit[drv].flags & UNIT_DEN) - ry_esr = ry_esr | RYES_DDEN; - } -if ((new_ecode > 0) || (ry_esr & RYES_ERR)) /* test for error */ - ry_csr = ry_csr | RYCS_ERR; -ry_ecode = new_ecode; /* update ecode */ -ry_dbr = ry_esr; /* update RYDB */ -return; -} - -/* Device initialization. The RY is one of the few devices that schedules - an I/O transfer as part of its initialization. -*/ - -t_stat ry_reset (DEVICE *dptr) -{ -ry_csr = ry_dbr = 0; /* clear registers */ -ry_esr = ry_ecode = 0; /* clear error */ -ry_ba = ry_wc = 0; /* clear wc, ba */ -ry_track = ry_sector = 0; /* clear trk, sector */ -ry_state = IDLE; /* ctrl idle */ -CLR_INT (RY); /* clear int req */ -sim_cancel (&ry_unit[1]); /* cancel drive 1 */ -if (dptr->flags & UNIT_DIS) /* disabled? */ - sim_cancel (&ry_unit[0]); -else if (ry_unit[0].flags & UNIT_BUF) { /* attached? */ - ry_state = INIT_COMPLETE; /* yes, sched init */ - sim_activate (&ry_unit[0], ry_swait * abs (1 - ry_unit[0].TRACK)); - } -else ry_done (RYES_ID, 0010); /* no, error */ -return auto_config (0, 0); /* run autoconfig */ -} - -/* Attach routine */ - -t_stat ry_attach (UNIT *uptr, char *cptr) -{ -uint32 sz; - -if ((uptr->flags & UNIT_AUTO) && (sz = sim_fsize_name (cptr))) { - if (sz > RX_SIZE) - uptr->flags = uptr->flags | UNIT_DEN; - else uptr->flags = uptr->flags & ~UNIT_DEN; - } -uptr->capac = (uptr->flags & UNIT_DEN)? RY_SIZE: RX_SIZE; -return attach_unit (uptr, cptr); -} - -/* Set size routine */ - -t_stat ry_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (uptr->flags & UNIT_ATT) - return SCPE_ALATT; -uptr->capac = val? RY_SIZE: RX_SIZE; -return SCPE_OK; -} - -/* Device bootstrap */ - -#if defined (VM_PDP11) - -#define BOOT_START 02000 /* start */ -#define BOOT_ENTRY (BOOT_START + 002) /* entry */ -#define BOOT_UNIT (BOOT_START + 010) /* unit number */ -#define BOOT_CSR (BOOT_START + 026) /* CSR */ -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) - -static const uint16 boot_rom[] = { - 042131, /* "YD" */ - 0012706, BOOT_START, /* MOV #boot_start, SP */ - 0012700, 0000000, /* MOV #unit, R0 ; unit number */ - 0010003, /* MOV R0, R3 */ - 0006303, /* ASL R3 */ - 0006303, /* ASL R3 */ - 0006303, /* ASL R3 */ - 0006303, /* ASL R3 */ - 0012701, 0177170, /* MOV #RYCS, R1 ; csr */ - 0005002, /* CLR R2 ; ba */ - 0005004, /* CLR R4 ; density */ - 0012705, 0000001, /* MOV #1, R5 ; sector */ - 0005104, /* DN: COM R4 ; compl dens */ - 0042704, 0177377, /* BIC #177377, R4 ; clr rest */ - 0032711, 0000040, /* RD: BIT #40, (R1) ; ready? */ - 0001775, /* BEQ .-4 */ - 0012746, 0000007, /* MOV #READ+GO, -(SP) */ - 0050316, /* BIS R3, (SP) ; or unit */ - 0050416, /* BIS R4, (SP) ; or density */ - 0012611, /* MOV (SP)+, (R1) ; read & go */ - 0105711, /* TSTB (R1) ; xfr ready? */ - 0100376, /* BPL .-2 */ - 0010561, 0000002, /* MOV R5, 2(R1) ; sector */ - 0105711, /* TSTB (R1) ; xfr ready? */ - 0100376, /* BPL .-2 */ - 0012761, 0000001, 0000002, /* MOV #1, 2(R1) ; track */ - 0032711, 0000040, /* BIT #40, (R1) ; ready? */ - 0001775, /* BEQ .-4 */ - 0005711, /* TST (R1) ; error? */ - 0100003, /* BEQ OK */ - 0005704, /* TST R4 ; single? */ - 0001345, /* BNE DN ; no, try again */ - 0000000, /* HALT ; dead */ - 0012746, 0000003, /* OK: MOV #EMPTY+GO, -(SP); empty & go */ - 0050416, /* BIS R4, (SP) ; or density */ - 0012611, /* MOV (SP)+, (R1) ; read & go */ - 0105711, /* TSTB (R1) ; xfr, done? */ - 0001776, /* BPL .-2 */ - 0012746, 0000100, /* MOV #100, -(SP) ; assume sd */ - 0005704, /* TST R4 ; test dd */ - 0001401, /* BEQ .+4 */ - 0006316, /* ASL (SP) ; dd, double */ - 0011661, 0000002, /* MOV (SP), 2(R1) ; wc */ - 0105711, /* TSTB (R1) ; xfr, done? */ - 0001776, /* BPL .-2 */ - 0010261, 0000002, /* MOV R2, 2(R1) ; ba */ - 0032711, 0000040, /* BIT #40, (R1) ; ready? */ - 0001775, /* BEQ .-4 */ - 0061602, /* ADD (SP), R2 ; cvt wd to byte */ - 0062602, /* ADD (SP)+, R2 ; adv buf addr */ - 0122525, /* CMPB (R5)+, (R5)+ ; sect += 2 */ - 0020527, 0000007, /* CMP R5, #7 ; end? */ - 0101715, /* BLOS RD ; read next */ - 0005002, /* CLR R2 */ - 0005003, /* CLR R3 */ - 0012704, BOOT_START+020, /* MOV #START+20, R4 */ - 0005005, /* CLR R5 */ - 0005007 /* CLR R7 */ - }; - -t_stat ry_boot (int32 unitno, DEVICE *dptr) -{ -size_t i; -extern uint16 *M; - -if ((ry_unit[unitno & RX_M_NUMDR].flags & UNIT_DEN) == 0) - return SCPE_NOFNC; -for (i = 0; i < BOOT_LEN; i++) - M[(BOOT_START >> 1) + i] = boot_rom[i]; -M[BOOT_UNIT >> 1] = unitno & RX_M_NUMDR; -M[BOOT_CSR >> 1] = ry_dib.ba & DMASK; -cpu_set_boot (BOOT_ENTRY); -return SCPE_OK; -} - -#else - -t_stat ry_boot (int32 unitno, DEVICE *dptr) -{ -return SCPE_NOFNC; -} - -#endif diff --git a/PDP11/pdp11_stddev.c b/PDP11/pdp11_stddev.c deleted file mode 100644 index a3bbfc71..00000000 --- a/PDP11/pdp11_stddev.c +++ /dev/null @@ -1,510 +0,0 @@ -/* pdp11_stddev.c: PDP-11 standard I/O devices simulator - - Copyright (c) 1993-2016, 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. - - tti,tto DL11 terminal input/output - clk KW11L (and other) line frequency clock - - 25-Sep-16 RMS Added Dave Gesswein's fix to prevent data loss - 02-Jan-16 RMS Changed TTO default to 7B - 30-Dec-15 RMS Added NOBEVENT support - 18-Apr-12 RMS Modified to use clock coscheduling - 20-May-08 RMS Standardized clock delay at 1mips - 18-Jun-07 RMS Added UNIT_IDLE flag to console input, clock - 29-Oct-06 RMS Synced keyboard and clock - Added clock coscheduling support - 05-Jul-06 RMS Added UC only support for early DOS/RSTS - 22-Nov-05 RMS Revised for new terminal processing routines - 22-Sep-05 RMS Fixed declarations (Sterling Garwood) - 07-Jul-05 RMS Removed extraneous externs - 11-Oct-04 RMS Added clock model dependencies - 28-May-04 RMS Removed SET TTI CTRL-C - 29-Dec-03 RMS Added console backpressure support - 25-Apr-03 RMS Revised for extended file support - 01-Mar-03 RMS Added SET/SHOW CLOCK FREQ, SET TTI CTRL-C - 22-Nov-02 RMS Changed terminal default to 7B for UNIX - 01-Nov-02 RMS Added 7B/8B support to terminal - 29-Sep-02 RMS Added vector display support - Split out paper tape - Split DL11 dibs - 30-May-02 RMS Widened POS to 32b - 26-Jan-02 RMS Revised for multiple timers - 09-Jan-02 RMS Fixed bugs in KW11L (John Dundas) - 06-Jan-02 RMS Split I/O address routines, revised enable/disable support - 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 - 04-Jul-01 RMS Added DZ11 support - 05-Mar-01 RMS Added clock calibration support - 30-Oct-00 RMS Standardized register order - 25-Jun-98 RMS Fixed bugs in paper tape error handling -*/ - -#include "pdp11_defs.h" - -#define TTICSR_IMP (CSR_DONE + CSR_IE) /* terminal input */ -#define TTICSR_RW (CSR_IE) -#define TTOCSR_IMP (CSR_DONE + CSR_IE) /* terminal output */ -#define TTOCSR_RW (CSR_IE) -#define CLKCSR_IMP (CSR_DONE + CSR_IE) /* real-time clock */ -#define CLKCSR_RW (CSR_IE) -#define CLK_DELAY 16667 - -extern int32 int_req[IPL_HLVL]; -extern uint32 cpu_type, cpu_opt; - -int32 tti_csr = 0; /* control/status */ -int32 tto_csr = 0; /* control/status */ -int32 clk_csr = 0; /* control/status */ -int32 clk_tps = 60; /* ticks/second */ -int32 clk_default = 60; /* default ticks/second */ -int32 clk_fie = 0; /* force IE = 1 */ -int32 clk_fnxm = 0; /* force NXM on reg */ -int32 tmxr_poll = CLK_DELAY; /* term mux poll */ -int32 tmr_poll = CLK_DELAY; /* timer poll */ - -t_stat tti_rd (int32 *data, int32 PA, int32 access); -t_stat tti_wr (int32 data, int32 PA, int32 access); -t_stat tti_svc (UNIT *uptr); -t_stat tti_reset (DEVICE *dptr); -t_stat tto_rd (int32 *data, int32 PA, int32 access); -t_stat tto_wr (int32 data, int32 PA, int32 access); -t_stat tto_svc (UNIT *uptr); -t_stat tto_reset (DEVICE *dptr); -t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat clk_rd (int32 *data, int32 PA, int32 access); -t_stat clk_wr (int32 data, int32 PA, int32 access); -t_stat clk_svc (UNIT *uptr); -int32 clk_inta (void); -t_stat clk_reset (DEVICE *dptr); -t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc); - -/* TTI data structures - - tti_dev TTI device descriptor - tti_unit TTI unit descriptor - tti_reg TTI register list -*/ - -DIB tti_dib = { - IOBA_TTI, IOLN_TTI, &tti_rd, &tti_wr, - 1, IVCL (TTI), VEC_TTI, { NULL } - }; - -UNIT tti_unit = { UDATA (&tti_svc, UNIT_IDLE, 0), KBD_POLL_WAIT }; - -REG tti_reg[] = { - { ORDATA (BUF, tti_unit.buf, 8) }, - { ORDATA (CSR, tti_csr, 16) }, - { FLDATA (INT, IREQ (TTI), INT_V_TTI) }, - { FLDATA (ERR, tti_csr, CSR_V_ERR) }, - { FLDATA (DONE, tti_csr, CSR_V_DONE) }, - { FLDATA (IE, tti_csr, CSR_V_IE) }, - { DRDATA (POS, tti_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, tti_unit.wait, 24), PV_LEFT+REG_NZ }, - { NULL } - }; - -MTAB tti_mod[] = { - { TT_MODE, TT_MODE_UC, "UC", "UC", &tty_set_mode }, - { TT_MODE, TT_MODE_7B, "7b", "7B", &tty_set_mode }, - { TT_MODE, TT_MODE_8B, "8b", "8B", &tty_set_mode }, - { TT_MODE, TT_MODE_7P, "7b", NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, - NULL, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, - NULL, &show_vec, NULL }, - { 0 } - }; - -DEVICE tti_dev = { - "TTI", &tti_unit, tti_reg, tti_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &tti_reset, - NULL, NULL, NULL, - &tti_dib, DEV_UBUS | DEV_QBUS - }; - -/* TTO data structures - - tto_dev TTO device descriptor - tto_unit TTO unit descriptor - tto_reg TTO register list -*/ - -DIB tto_dib = { - IOBA_TTO, IOLN_TTO, &tto_rd, &tto_wr, - 1, IVCL (TTO), VEC_TTO, { NULL } - }; - -UNIT tto_unit = { UDATA (&tto_svc, TT_MODE_7B, 0), SERIAL_OUT_WAIT }; - -REG tto_reg[] = { - { ORDATA (BUF, tto_unit.buf, 8) }, - { ORDATA (CSR, tto_csr, 16) }, - { FLDATA (INT, IREQ (TTO), INT_V_TTO) }, - { FLDATA (ERR, tto_csr, CSR_V_ERR) }, - { FLDATA (DONE, tto_csr, CSR_V_DONE) }, - { FLDATA (IE, tto_csr, CSR_V_IE) }, - { DRDATA (POS, tto_unit.pos, T_ADDR_W), PV_LEFT }, - { DRDATA (TIME, tto_unit.wait, 24), PV_LEFT }, - { NULL } - }; - -MTAB tto_mod[] = { - { TT_MODE, TT_MODE_UC, "UC", "UC", &tty_set_mode }, - { TT_MODE, TT_MODE_7B, "7b", "7B", &tty_set_mode }, - { TT_MODE, TT_MODE_8B, "8b", "8B", &tty_set_mode }, - { TT_MODE, TT_MODE_7P, "7p", "7P", &tty_set_mode }, - { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, - NULL, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, - NULL, &show_vec, NULL }, - { 0 } - }; - -DEVICE tto_dev = { - "TTO", &tto_unit, tto_reg, tto_mod, - 1, 10, 31, 1, 8, 8, - NULL, NULL, &tto_reset, - NULL, NULL, NULL, - &tto_dib, DEV_UBUS | DEV_QBUS - }; - -/* CLK data structures - - clk_dev CLK device descriptor - clk_unit CLK unit descriptor - clk_reg CLK register list -*/ - -DIB clk_dib = { - IOBA_CLK, IOLN_CLK, &clk_rd, &clk_wr, - 1, IVCL (CLK), VEC_CLK, { &clk_inta } - }; - -UNIT clk_unit = { UDATA (&clk_svc, UNIT_IDLE, 0), CLK_DELAY }; - -REG clk_reg[] = { - { ORDATA (CSR, clk_csr, 16) }, - { FLDATA (INT, IREQ (CLK), INT_V_CLK) }, - { FLDATA (DONE, clk_csr, CSR_V_DONE) }, - { FLDATA (IE, clk_csr, CSR_V_IE) }, - { DRDATA (TIME, clk_unit.wait, 24), REG_NZ + PV_LEFT }, - { DRDATA (TPS, clk_tps, 16), PV_LEFT + REG_HRO }, - { DRDATA (DEFTPS, clk_default, 16), PV_LEFT + REG_HRO }, - { FLDATA (FIE, clk_fie, 0), REG_HIDDEN }, - { FLDATA (FNXM, clk_fnxm, 0), REG_HIDDEN }, - { NULL } - }; - -MTAB clk_mod[] = { - { MTAB_XTD|MTAB_VDV, 50, NULL, "50HZ", - &clk_set_freq, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 60, NULL, "60HZ", - &clk_set_freq, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "FREQUENCY", NULL, - NULL, &clk_show_freq, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "ADDRESS", NULL, - NULL, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, - NULL, &show_vec, NULL }, - { 0 } - }; - -DEVICE clk_dev = { - "CLK", &clk_unit, clk_reg, clk_mod, - 1, 0, 0, 0, 0, 0, - NULL, NULL, &clk_reset, - NULL, NULL, NULL, - &clk_dib, DEV_UBUS | DEV_QBUS - }; - -/* Terminal input address routines */ - -t_stat tti_rd (int32 *data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 01) { /* decode PA<1> */ - - case 00: /* tti csr */ - *data = tti_csr & TTICSR_IMP; - return SCPE_OK; - - case 01: /* tti buf */ - tti_csr = tti_csr & ~CSR_DONE; - CLR_INT (TTI); - *data = tti_unit.buf & 0377; - sim_activate_abs (&tti_unit, tti_unit.wait); /* check soon for more input */ - return SCPE_OK; - } /* end switch PA */ - -return SCPE_NXM; -} - -t_stat tti_wr (int32 data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 01) { /* decode PA<1> */ - - case 00: /* tti csr */ - if (PA & 1) - return SCPE_OK; - if ((data & CSR_IE) == 0) - CLR_INT (TTI); - else if ((tti_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) - SET_INT (TTI); - tti_csr = (tti_csr & ~TTICSR_RW) | (data & TTICSR_RW); - return SCPE_OK; - - case 01: /* tti buf */ - return SCPE_OK; - } /* end switch PA */ - -return SCPE_NXM; -} - -/* Terminal input service */ - -t_stat tti_svc (UNIT *uptr) -{ -int32 c; - -sim_activate (uptr, clk_cosched (tmr_poll)); /* continue poll */ -if ((c = sim_poll_kbd ()) < SCPE_KFLAG) /* no char or error? */ - return c; -if (c & SCPE_BREAK) /* break? */ - uptr->buf = 0; -else uptr->buf = sim_tt_inpcvt (c, TT_GET_MODE (uptr->flags)); -uptr->pos = uptr->pos + 1; -tti_csr = tti_csr | CSR_DONE; -if (tti_csr & CSR_IE) - SET_INT (TTI); -return SCPE_OK; -} - -/* Terminal input reset */ - -t_stat tti_reset (DEVICE *dptr) -{ -tti_unit.buf = 0; -tti_csr = 0; -CLR_INT (TTI); -sim_activate (&tti_unit, tmr_poll); -return SCPE_OK; -} - -/* Terminal output address routines */ - -t_stat tto_rd (int32 *data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 01) { /* decode PA<1> */ - - case 00: /* tto csr */ - *data = tto_csr & TTOCSR_IMP; - return SCPE_OK; - - case 01: /* tto buf */ - *data = tto_unit.buf; - return SCPE_OK; - } /* end switch PA */ - -return SCPE_NXM; -} - -t_stat tto_wr (int32 data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 01) { /* decode PA<1> */ - - case 00: /* tto csr */ - if (PA & 1) - return SCPE_OK; - if ((data & CSR_IE) == 0) - CLR_INT (TTO); - else if ((tto_csr & (CSR_DONE + CSR_IE)) == CSR_DONE) - SET_INT (TTO); - tto_csr = (tto_csr & ~TTOCSR_RW) | (data & TTOCSR_RW); - return SCPE_OK; - - case 01: /* tto buf */ - if ((PA & 1) == 0) - tto_unit.buf = data & 0377; - tto_csr = tto_csr & ~CSR_DONE; - CLR_INT (TTO); - sim_activate (&tto_unit, tto_unit.wait); - return SCPE_OK; - } /* end switch PA */ - -return SCPE_NXM; -} - -/* Terminal output service */ - -t_stat tto_svc (UNIT *uptr) -{ -int32 c; -t_stat r; - -c = sim_tt_outcvt (uptr->buf, TT_GET_MODE (uptr->flags)); -if (c >= 0) { - if ((r = sim_putchar_s (c)) != SCPE_OK) { /* output; error? */ - sim_activate (uptr, uptr->wait); /* try again */ - return ((r == SCPE_STALL)? SCPE_OK: r); /* !stall? report */ - } - } -tto_csr = tto_csr | CSR_DONE; -if (tto_csr & CSR_IE) - SET_INT (TTO); -uptr->pos = uptr->pos + 1; -return SCPE_OK; -} - -/* Terminal output reset */ - -t_stat tto_reset (DEVICE *dptr) -{ -tto_unit.buf = 0; -tto_csr = CSR_DONE; -CLR_INT (TTO); -sim_cancel (&tto_unit); /* deactivate unit */ -return SCPE_OK; -} - -t_stat tty_set_mode (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -tti_unit.flags = (tti_unit.flags & ~TT_MODE) | val; -tto_unit.flags = (tto_unit.flags & ~TT_MODE) | val; -return SCPE_OK; -} - -/* The line time clock has a few twists and turns through the history of 11's - - LSI-11 no CSR - LSI-11/23 (KDF11A) no CSR - PDP-11/23+ (KDF11B) no monitor bit - PDP-11/24 (KDF11U) monitor bit clears on IAK -*/ - -/* Clock I/O address routines */ - -t_stat clk_rd (int32 *data, int32 PA, int32 access) -{ -if (clk_fnxm) /* not there??? */ - return SCPE_NXM; -if (CPUT (HAS_LTCM)) /* monitor bit? */ - *data = clk_csr & CLKCSR_IMP; -else *data = clk_csr & (CLKCSR_IMP & ~CSR_DONE); /* no, just IE */ -return SCPE_OK; -} - -t_stat clk_wr (int32 data, int32 PA, int32 access) -{ -if (clk_fnxm) /* not there??? */ - return SCPE_NXM; -if (PA & 1) - return SCPE_OK; -clk_csr = (clk_csr & ~CLKCSR_RW) | (data & CLKCSR_RW); -if (CPUT (HAS_LTCM) && ((data & CSR_DONE) == 0)) /* monitor bit? */ - clk_csr = clk_csr & ~CSR_DONE; /* clr if zero */ -if ((((clk_csr & CSR_IE) == 0) && !clk_fie) || /* unless IE+DONE */ - ((clk_csr & CSR_DONE) == 0)) /* clr intr */ - CLR_INT (CLK); -return SCPE_OK; -} - -/* Clock service */ - -t_stat clk_svc (UNIT *uptr) -{ -int32 t; - -clk_csr = clk_csr | CSR_DONE; /* set done */ -if ((clk_csr & CSR_IE) || clk_fie) - SET_INT (CLK); -t = sim_rtcn_calb (clk_tps, TMR_CLK); /* calibrate clock */ -sim_activate (&clk_unit, t); /* reactivate unit */ -tmr_poll = t; /* set timer poll */ -tmxr_poll = t; /* set mux poll */ -return SCPE_OK; -} - -/* Clock interrupt acknowledge */ - -int32 clk_inta (void) -{ -if (CPUT (CPUT_24)) - clk_csr = clk_csr & ~CSR_DONE; -return clk_dib.vec; -} - -/* Clock coscheduling routine */ - -int32 clk_cosched (int32 wait) -{ -int32 t; - -t = sim_is_active (&clk_unit); -return (t? t - 1: wait); -} - -/* Clock reset */ - -t_stat clk_reset (DEVICE *dptr) -{ -if (CPUT (HAS_LTCR)) /* reg there? */ - clk_fie = clk_fnxm = 0; -else { - clk_fnxm = 1; /* no LTCR, set nxm */ - clk_fie = CPUO (OPT_BVT); /* ie = 1 unless no BEVENT */ - } -clk_tps = clk_default; /* set default tps */ -clk_csr = CSR_DONE; /* set done */ -CLR_INT (CLK); -sim_rtcn_init (clk_unit.wait, TMR_CLK); /* init line clock */ -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; -} - -/* Set frequency */ - -t_stat clk_set_freq (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -if (cptr) - return SCPE_ARG; -if ((val != 50) && (val != 60)) - return SCPE_IERR; -clk_tps = clk_default = val; -return SCPE_OK; -} - -/* Show frequency */ - -t_stat clk_show_freq (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -fprintf (st, "%dHz", clk_tps); -return SCPE_OK; -} diff --git a/PDP11/pdp11_sys.c b/PDP11/pdp11_sys.c deleted file mode 100644 index f9e80bb6..00000000 --- a/PDP11/pdp11_sys.c +++ /dev/null @@ -1,1110 +0,0 @@ -/* pdp11_sys.c: PDP-11 simulator interface - - Copyright (c) 1993-2018, 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. - - 23-May-18 RMS Changed UC15 simulator name - 14-Mar-16 RMS Added UC15 support - 02-Sep-13 RMS Added third Massbus, RS03/RS04 - 29-Apr-12 RMS Fixed compiler warning (Mark Pizzolato) - 19-Nov-08 RMS Moved I/O support routines to I/O library - 15-May-08 RMS Added KE11-A, DC11 support - Renamed DL11 - 04-Feb-08 RMS Modified to allow -A, -B use with 8b devices - 25-Jan-08 RMS Added RC11, KG11A support from John Dundas - 10-Sep-07 RMS Cleaned up binary loader - 20-Dec-06 RMS Added TA11 support - 12-Nov-06 RMS Fixed operand order in EIS instructions (W.F.J. Mueller) - 14-Jul-06 RMS Reordered device list - 06-Jul-06 RMS Added multiple KL11/DL11 support - 26-Jun-06 RMS Added RF11 support - 17-May-06 RMS Added CR11/CD11 support (John Dundas) - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 22-Jul-05 RMS Fixed missing , in initializer (Doug Gwyn) - 22-Dec-03 RMS Added second DEUNA/DELUA support - 18-Oct-03 RMS Added DECtape off reel message - 06-May-03 RMS Added support for second DEQNA/DELQA - 09-Jan-03 RMS Added DELUA/DEUNA support - 17-Oct-02 RMS Fixed bugs in branch, SOB address parsing - 09-Oct-02 RMS Added DELQA support - 12-Sep-02 RMS Added TMSCP, KW11P, RX211 support, RAD50 examine - 29-Nov-01 RMS Added read only unit support - 17-Sep-01 RMS Removed multiconsole support - 26-Aug-01 RMS Added DZ11 - 20-Aug-01 RMS Updated bad block inquiry - 17-Jul-01 RMS Fixed warning from VC++ 6.0 - 27-May-01 RMS Added multiconsole support - 05-Apr-01 RMS Added support for TS11/TSV05 - 14-Mar-01 RMS Revised load/dump interface (again) - 11-Feb-01 RMS Added DECtape support - 30-Oct-00 RMS Added support for examine to file - 14-Apr-99 RMS Changed t_addr to unsigned - 09-Nov-98 RMS Fixed assignments of ROR/ROL (John Wilson) - 27-Oct-98 RMS V2.4 load interface - 08-Oct-98 RMS Fixed bug in bad block routine - 30-Mar-98 RMS Fixed bug in floating point display - 12-Nov-97 RMS Added bad block table routine -*/ - -#include "pdp11_defs.h" -#include - -extern DEVICE cpu_dev; -extern DEVICE sys_dev; -extern DEVICE ptr_dev; -extern DEVICE ptp_dev; -extern DEVICE tti_dev; -extern DEVICE tto_dev; -extern DEVICE lpt_dev; -extern DEVICE cr_dev; -extern DEVICE clk_dev; -extern DEVICE pclk_dev; -extern DEVICE dli_dev; -extern DEVICE dlo_dev; -extern DEVICE dci_dev; -extern DEVICE dco_dev; -extern DEVICE dz_dev; -extern DEVICE vh_dev; -extern DEVICE dt_dev; -extern DEVICE rc_dev; -extern DEVICE rf_dev; -extern DEVICE rk_dev; -extern DEVICE rl_dev; -extern DEVICE hk_dev; -extern DEVICE rx_dev; -extern DEVICE ry_dev; -extern DEVICE mba_dev[]; -extern DEVICE rp_dev; -extern DEVICE rs_dev; -extern DEVICE rq_dev, rqb_dev, rqc_dev, rqd_dev; -extern DEVICE tm_dev; -extern DEVICE tq_dev; -extern DEVICE ts_dev; -extern DEVICE tu_dev; -extern DEVICE ta_dev; -extern DEVICE xq_dev, xqb_dev; -extern DEVICE xu_dev, xub_dev; -extern DEVICE ke_dev; -extern DEVICE kg_dev; -extern DEVICE uca_dev, ucb_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 -*/ - -#if !defined (UC15) -char sim_name[] = "PDP-11"; -#else -char sim_name[] = "UC-15"; -#endif - -REG *sim_PC = &cpu_reg[0]; - -int32 sim_emax = 4; - -DEVICE *sim_devices[] = { - &cpu_dev, - &sys_dev, -#if !defined (UC15) - &mba_dev[0], - &mba_dev[1], - &mba_dev[2], - &clk_dev, - &pclk_dev, - &ptr_dev, - &ptp_dev, - &tti_dev, - &tto_dev, - &cr_dev, - &lpt_dev, - &dli_dev, - &dlo_dev, - &dci_dev, - &dco_dev, - &dz_dev, - &vh_dev, - &rc_dev, - &rf_dev, - &rk_dev, - &rl_dev, - &hk_dev, - &rx_dev, - &ry_dev, - &rp_dev, - &rs_dev, - &rq_dev, - &rqb_dev, - &rqc_dev, - &rqd_dev, - &dt_dev, - &tm_dev, - &ts_dev, - &tq_dev, - &tu_dev, - &ta_dev, - &xq_dev, - &xqb_dev, - &xu_dev, - &xub_dev, - &kg_dev, - &ke_dev, -#else - &clk_dev, - &tti_dev, - &tto_dev, - &cr_dev, - &lpt_dev, - &rk_dev, - &uca_dev, - &ucb_dev, -#endif - NULL - }; - -const char *sim_stop_messages[] = { - "Unknown error", - "Red stack trap", - "Odd address trap", - "Memory management trap", - "Non-existent memory trap", - "Parity error trap", - "Privilege trap", - "Illegal instruction trap", - "BPT trap", - "IOT trap", - "EMT trap", - "TRAP trap", - "Trace trap", - "Yellow stack trap", - "Powerfail trap", - "Floating point exception", - "HALT instruction", - "Breakpoint", - "Wait state", - "Trap vector fetch abort", - "Trap stack push abort", - "RQDX3 consistency error", - "Sanity timer expired", - "DECtape off reel" - }; - -/* Binary loader. - - Loader format consists of blocks, optionally preceded, separated, and - followed by zeroes. Each block consists of: - - 001 --- - xxx | - lo_count | - hi_count | - lo_origin > count bytes - hi_origin | - data byte | - : | - data byte --- - checksum - - If the byte count is exactly six, the block is the last on the tape, and - there is no checksum. If the origin is not 000001, then the origin is - the PC at which to start the program. -*/ - -t_stat sim_load (FILE *fileref, char *cptr, char *fnam, int flag) -{ -int32 c[6], d, i, cnt, csum; -uint32 org; - -if ((*cptr != 0) || (flag != 0)) - return SCPE_ARG; -do { /* block loop */ - csum = 0; /* init checksum */ - for (i = 0; i < 6; ) { /* 6 char header */ - if ((c[i] = getc (fileref)) == EOF) - return SCPE_FMT; - if ((i != 0) || (c[i] == 1)) /* 1st must be 1 */ - csum = csum + c[i++]; /* add into csum */ - } - cnt = (c[3] << 8) | c[2]; /* count */ - org = (c[5] << 8) | c[4]; /* origin */ - if (cnt < 6) /* invalid? */ - return SCPE_FMT; - if (cnt == 6) { /* end block? */ - if (org != 1) /* set PC? */ - saved_PC = org & 0177776; - return SCPE_OK; - } - for (i = 6; i < cnt; i++) { /* exclude hdr */ - if ((d = getc (fileref)) == EOF) /* data char */ - return SCPE_FMT; - csum = csum + d; /* add into csum */ - if (!ADDR_IS_MEM (org)) /* invalid addr? */ - return SCPE_NXM; - WrMemB (org, ((uint16) d)); - org = (org + 1) & 0177777; /* inc origin */ - } - if ((d = getc (fileref)) == EOF) /* get csum */ - return SCPE_FMT; - csum = csum + d; /* add in */ - } while ((csum & 0377) == 0); /* result mbz */ -return SCPE_CSUM; -} - -/* Symbol tables */ - -#define I_V_L 16 /* long mode */ -#define I_V_D 17 /* double mode */ -#define I_L (1 << I_V_L) -#define I_D (1 << I_V_D) - -/* Warning: for literals, the class number MUST equal the field width!! */ - -#define I_V_CL 18 /* class bits */ -#define I_M_CL 037 /* class mask */ -#define I_V_NPN 0 /* no operands */ -#define I_V_REG 1 /* reg */ -#define I_V_SOP 2 /* operand */ -#define I_V_3B 3 /* 3b literal */ -#define I_V_FOP 4 /* flt operand */ -#define I_V_AFOP 5 /* fac, flt operand */ -#define I_V_6B 6 /* 6b literal */ -#define I_V_BR 7 /* cond branch */ -#define I_V_8B 8 /* 8b literal */ -#define I_V_SOB 9 /* reg, disp */ -#define I_V_RSOP 10 /* reg, operand */ -#define I_V_ASOP 11 /* fac, operand */ -#define I_V_ASMD 12 /* fac, moded int op */ -#define I_V_DOP 13 /* double operand */ -#define I_V_CCC 14 /* CC clear */ -#define I_V_CCS 15 /* CC set */ -#define I_V_SOPR 16 /* operand, reg */ -#define I_NPN (I_V_NPN << I_V_CL) -#define I_REG (I_V_REG << I_V_CL) -#define I_3B (I_V_3B << I_V_CL) -#define I_SOP (I_V_SOP << I_V_CL) -#define I_FOP (I_V_FOP << I_V_CL) -#define I_6B (I_V_6B << I_V_CL) -#define I_BR (I_V_BR << I_V_CL) -#define I_8B (I_V_8B << I_V_CL) -#define I_AFOP (I_V_AFOP << I_V_CL) -#define I_ASOP (I_V_ASOP << I_V_CL) -#define I_RSOP (I_V_RSOP << I_V_CL) -#define I_SOB (I_V_SOB << I_V_CL) -#define I_ASMD (I_V_ASMD << I_V_CL) -#define I_DOP (I_V_DOP << I_V_CL) -#define I_CCC (I_V_CCC << I_V_CL) -#define I_CCS (I_V_CCS << I_V_CL) -#define I_SOPR (I_V_SOPR << I_V_CL) - -static const int32 masks[] = { -0177777, 0177770, 0177700, 0177770, -0177700+I_D, 0177400+I_D, 0177700, 0177400, -0177400, 0177000, 0177000, 0177400, -0177400+I_D+I_L, 0170000, 0177777, 0177777, -0177000 -}; - -static const char *opcode[] = { -"HALT","WAIT","RTI","BPT", -"IOT","RESET","RTT","MFPT", -"JMP","RTS","SPL", -"NOP","CLC","CLV","CLV CLC", -"CLZ","CLZ CLC","CLZ CLV","CLZ CLV CLC", -"CLN","CLN CLC","CLN CLV","CLN CLV CLC", -"CLN CLZ","CLN CLZ CLC","CLN CLZ CLC","CCC", -"NOP","SEC","SEV","SEV SEC", -"SEZ","SEZ SEC","SEZ SEV","SEZ SEV SEC", -"SEN","SEN SEC","SEN SEV","SEN SEV SEC", -"SEN SEZ","SEN SEZ SEC","SEN SEZ SEC","SCC", -"SWAB","BR","BNE","BEQ", -"BGE","BLT","BGT","BLE", -"JSR", -"CLR","COM","INC","DEC", -"NEG","ADC","SBC","TST", -"ROR","ROL","ASR","ASL", -"MARK","MFPI","MTPI","SXT", -"CSM", "TSTSET","WRTLCK", -"MOV","CMP","BIT","BIC", -"BIS","ADD", -"MUL","DIV","ASH","ASHC", -"XOR", -"FADD","FSUB","FMUL","FDIV", -"L2DR", -"MOVC","MOVRC","MOVTC", -"LOCC","SKPC","SCANC","SPANC", -"CMPC","MATC", -"ADDN","SUBN","CMPN","CVTNL", -"CVTPN","CVTNP","ASHN","CVTLN", -"L3DR", -"ADDP","SUBP","CMPP","CVTPL", -"MULP","DIVP","ASHP","CVTLP", -"MOVCI","MOVRCI","MOVTCI", -"LOCCI","SKPCI","SCANCI","SPANCI", -"CMPCI","MATCI", -"ADDNI","SUBNI","CMPNI","CVTNLI", -"CVTPNI","CVTNPI","ASHNI","CVTLNI", -"ADDPI","SUBPI","CMPPI","CVTPLI", -"MULPI","DIVPI","ASHPI","CVTLPI", -"SOB", -"BPL","BMI","BHI","BLOS", -"BVC","BVS","BCC","BCS", -"BHIS","BLO", /* encode only */ -"EMT","TRAP", -"CLRB","COMB","INCB","DECB", -"NEGB","ADCB","SBCB","TSTB", -"RORB","ROLB","ASRB","ASLB", -"MTPS","MFPD","MTPD","MFPS", -"MOVB","CMPB","BITB","BICB", -"BISB","SUB", -"CFCC","SETF","SETI","SETD","SETL", -"LDFPS","STFPS","STST", -"CLRF","CLRD","TSTF","TSTD", -"ABSF","ABSD","NEGF","NEGD", -"MULF","MULD","MODF","MODD", -"ADDF","ADDD","LDF","LDD", -"SUBF","SUBD","CMPF","CMPD", -"STF","STD","DIVF","DIVD", -"STEXP", -"STCFI","STCDI","STCFL","STCDL", -"STCFD","STCDF", -"LDEXP", -"LDCIF","LDCID","LDCLF","LDCLD", -"LDCFD","LDCDF", -NULL -}; - -static const int32 opc_val[] = { -0000000+I_NPN, 0000001+I_NPN, 0000002+I_NPN, 0000003+I_NPN, -0000004+I_NPN, 0000005+I_NPN, 0000006+I_NPN, 0000007+I_NPN, -0000100+I_SOP, 0000200+I_REG, 0000230+I_3B, -0000240+I_CCC, 0000241+I_CCC, 0000242+I_CCC, 0000243+I_NPN, -0000244+I_CCC, 0000245+I_NPN, 0000246+I_NPN, 0000247+I_NPN, -0000250+I_CCC, 0000251+I_NPN, 0000252+I_NPN, 0000253+I_NPN, -0000254+I_NPN, 0000255+I_NPN, 0000256+I_NPN, 0000257+I_CCC, -0000260+I_CCS, 0000261+I_CCS, 0000262+I_CCS, 0000263+I_NPN, -0000264+I_CCS, 0000265+I_NPN, 0000266+I_NPN, 0000267+I_NPN, -0000270+I_CCS, 0000271+I_NPN, 0000272+I_NPN, 0000273+I_NPN, -0000274+I_NPN, 0000275+I_NPN, 0000276+I_NPN, 0000277+I_CCS, -0000300+I_SOP, 0000400+I_BR, 0001000+I_BR, 0001400+I_BR, -0002000+I_BR, 0002400+I_BR, 0003000+I_BR, 0003400+I_BR, -0004000+I_RSOP, -0005000+I_SOP, 0005100+I_SOP, 0005200+I_SOP, 0005300+I_SOP, -0005400+I_SOP, 0005500+I_SOP, 0005600+I_SOP, 0005700+I_SOP, -0006000+I_SOP, 0006100+I_SOP, 0006200+I_SOP, 0006300+I_SOP, -0006400+I_6B, 0006500+I_SOP, 0006600+I_SOP, 0006700+I_SOP, -0007000+I_SOP, 0007200+I_SOP, 0007300+I_SOP, -0010000+I_DOP, 0020000+I_DOP, 0030000+I_DOP, 0040000+I_DOP, -0050000+I_DOP, 0060000+I_DOP, -0070000+I_SOPR, 0071000+I_SOPR, 0072000+I_SOPR, 0073000+I_SOPR, -0074000+I_RSOP, -0075000+I_REG, 0075010+I_REG, 0075020+I_REG, 0075030+I_REG, -0076020+I_REG, -0076030+I_NPN, 0076031+I_NPN, 0076032+I_NPN, -0076040+I_NPN, 0076041+I_NPN, 0076042+I_NPN, 0076043+I_NPN, -0076044+I_NPN, 0076045+I_NPN, -0076050+I_NPN, 0076051+I_NPN, 0076052+I_NPN, 0076053+I_NPN, -0076054+I_NPN, 0076055+I_NPN, 0076056+I_NPN, 0076057+I_NPN, -0076060+I_REG, -0076070+I_NPN, 0076071+I_NPN, 0076072+I_NPN, 0076073+I_NPN, -0076074+I_NPN, 0076075+I_NPN, 0076076+I_NPN, 0076077+I_NPN, -0076130+I_NPN, 0076131+I_NPN, 0076132+I_NPN, -0076140+I_NPN, 0076141+I_NPN, 0076142+I_NPN, 0076143+I_NPN, -0076144+I_NPN, 0076145+I_NPN, -0076150+I_NPN, 0076151+I_NPN, 0076152+I_NPN, 0076153+I_NPN, -0076154+I_NPN, 0076155+I_NPN, 0076156+I_NPN, 0076157+I_NPN, -0076170+I_NPN, 0076171+I_NPN, 0076172+I_NPN, 0076173+I_NPN, -0076174+I_NPN, 0076175+I_NPN, 0076176+I_NPN, 0076177+I_NPN, -0077000+I_SOB, -0100000+I_BR, 0100400+I_BR, 0101000+I_BR, 0101400+I_BR, -0102000+I_BR, 0102400+I_BR, 0103000+I_BR, 0103400+I_BR, -0103000+I_BR, 0103400+I_BR, -0104000+I_8B, 0104400+I_8B, -0105000+I_SOP, 0105100+I_SOP, 0105200+I_SOP, 0105300+I_SOP, -0105400+I_SOP, 0105500+I_SOP, 0105600+I_SOP, 0105700+I_SOP, -0106000+I_SOP, 0106100+I_SOP, 0106200+I_SOP, 0106300+I_SOP, -0106400+I_SOP, 0106500+I_SOP, 0106600+I_SOP, 0106700+I_SOP, -0110000+I_DOP, 0120000+I_DOP, 0130000+I_DOP, 0140000+I_DOP, -0150000+I_DOP, 0160000+I_DOP, -0170000+I_NPN, 0170001+I_NPN, 0170002+I_NPN, 0170011+I_NPN, 0170012+I_NPN, -0170100+I_SOP, 0170200+I_SOP, 0170300+I_SOP, -0170400+I_FOP, 0170400+I_FOP+I_D, 0170500+I_FOP, 0170500+I_FOP+I_D, -0170600+I_FOP, 0170600+I_FOP+I_D, 0170700+I_FOP, 0170700+I_FOP+I_D, -0171000+I_AFOP, 0171000+I_AFOP+I_D, 0171400+I_AFOP, 0171400+I_AFOP+I_D, -0172000+I_AFOP, 0172000+I_AFOP+I_D, 0172400+I_AFOP, 0172400+I_AFOP+I_D, -0173000+I_AFOP, 0173000+I_AFOP+I_D, 0173400+I_AFOP, 0173400+I_AFOP+I_D, -0174000+I_AFOP, 0174000+I_AFOP+I_D, 0174400+I_AFOP, 0174400+I_AFOP+I_D, -0175000+I_ASOP, -0175400+I_ASMD, 0175400+I_ASMD+I_D, 0175400+I_ASMD+I_L, 0175400+I_ASMD+I_D+I_L, -0176000+I_AFOP, 0176000+I_AFOP+I_D, -0176400+I_ASOP, -0177000+I_ASMD, 0177000+I_ASMD+I_D, 0177000+I_ASMD+I_L, 0177000+I_ASMD+I_D+I_L, -0177400+I_AFOP, 0177400+I_AFOP+I_D, --1 -}; - -static const char *rname [] = { - "R0", "R1", "R2", "R3", "R4", "R5", "SP", "PC" - }; - -static const char *fname [] = { - "F0", "F1", "F2", "F3", "F4", "F5", "?6", "?7" - }; - -static const char r50_to_asc[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ$._0123456789"; - -/* Specifier decode - - Inputs: - *of = output stream - addr = current PC - spec = specifier - nval = next word - flag = TRUE if decoding for CPU - iflag = TRUE if decoding integer instruction - Outputs: - count = -number of extra words retired -*/ - -int32 fprint_spec (FILE *of, t_addr addr, int32 spec, t_value nval, - int32 flag, int32 iflag) -{ -int32 reg, mode; -static const int32 rgwd[8] = { 0, 0, 0, 0, 0, 0, -1, -1 }; -static const int32 pcwd[8] = { 0, 0, -1, -1, 0, 0, -1, -1 }; - -reg = spec & 07; -mode = ((spec >> 3) & 07); -switch (mode) { - - case 0: - if (iflag) - fprintf (of, "%s", rname[reg]); - else fprintf (of, "%s", fname[reg]); - break; - - case 1: - fprintf (of, "(%s)", rname[reg]); - break; - - case 2: - if (reg != 7) - fprintf (of, "(%s)+", rname[reg]); - else fprintf (of, "#%-o", nval); - break; - - case 3: - if (reg != 7) - fprintf (of, "@(%s)+", rname[reg]); - else fprintf (of, "@#%-o", nval); - break; - - case 4: - fprintf (of, "-(%s)", rname[reg]); - break; - - case 5: - fprintf (of, "@-(%s)", rname[reg]); - break; - - case 6: - if ((reg != 7) || !flag) - fprintf (of, "%-o(%s)", nval, rname[reg]); - else fprintf (of, "%-o", (nval + addr + 4) & 0177777); - break; - - case 7: - if ((reg != 7) || !flag) - fprintf (of, "@%-o(%s)", nval, rname[reg]); - else fprintf (of, "@%-o", (nval + addr + 4) & 0177777); - break; - } /* end case */ - -return ((reg == 07)? pcwd[mode]: rgwd[mode]); -} - -/* 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 cflag, i, j, c1, c2, c3, inst, fac, srcm, srcr, dstm, dstr; -int32 bflag, l8b, brdisp, wd1, wd2; -extern int32 FPS; - -bflag = 0; /* assume 16b */ -cflag = (uptr == NULL) || (uptr == &cpu_unit); /* cpu? */ -if (!cflag) { /* not cpu? */ - DEVICE *dptr = find_dev_from_unit (uptr); - if (dptr == NULL) - return SCPE_IERR; - if (dptr->dwidth < 16) - bflag = 1; - } - -if (sw & SWMASK ('A')) { /* ASCII? */ - if (bflag) - c1 = val[0] & 0177; - else c1 = (val[0] >> ((addr & 1)? 8: 0)) & 0177; - fprintf (of, (c1 < 040)? "<%03o>": "%c", c1); - return 0; - } -if (sw & SWMASK ('B')) { /* byte? */ - if (bflag) - c1 = val[0] & 0177; - else c1 = (val[0] >> ((addr & 1)? 8: 0)) & 0377; - fprintf (of, "%o", c1); - return 0; - } -if (bflag) /* 16b only */ - return SCPE_ARG; - -if (sw & SWMASK ('C')) { /* character? */ - c1 = val[0] & 0177; - c2 = (val[0] >> 8) & 0177; - fprintf (of, (c1 < 040)? "<%03o>": "%c", c1); - fprintf (of, (c2 < 040)? "<%03o>": "%c", c2); - return -1; - } -if (sw & SWMASK ('R')) { /* radix 50? */ - if (val[0] > 0174777) /* max value */ - return SCPE_ARG; - c3 = val[0] % 050; - c2 = (val[0] / 050) % 050; - c1 = val[0] / (050 * 050); - fprintf (of, "%c%c%c", r50_to_asc[c1], - r50_to_asc[c2], r50_to_asc[c3]); - return -1; - } -if (!(sw & SWMASK ('M'))) - return SCPE_ARG; - -inst = val[0] | ((FPS << (I_V_L - FPS_V_L)) & I_L) | - ((FPS << (I_V_D - FPS_V_D)) & I_D); /* inst + fp mode */ -for (i = 0; opc_val[i] >= 0; i++) { /* loop thru ops */ - j = (opc_val[i] >> I_V_CL) & I_M_CL; /* get class */ - if ((opc_val[i] & 0777777) == (inst & masks[j])) { /* match? */ - srcm = (inst >> 6) & 077; /* opr fields */ - srcr = srcm & 07; - fac = srcm & 03; - dstm = inst & 077; - dstr = dstm & 07; - l8b = inst & 0377; - wd1 = wd2 = 0; - switch (j) { /* case on class */ - - case I_V_NPN: case I_V_CCC: case I_V_CCS: /* no operands */ - fprintf (of, "%s", opcode[i]); - break; - - case I_V_REG: /* reg */ - fprintf (of, "%s %-s", opcode[i], rname[dstr]); - break; - - case I_V_SOP: /* sop */ - fprintf (of, "%s ", opcode[i]); - wd1 = fprint_spec (of, addr, dstm, val[1], cflag, TRUE); - break; - - case I_V_3B: /* 3b */ - fprintf (of, "%s %-o", opcode[i], dstr); - break; - - case I_V_FOP: /* fop */ - fprintf (of, "%s ", opcode[i]); - wd1 = fprint_spec (of, addr, dstm, val[1], cflag, FALSE); - break; - - case I_V_AFOP: /* afop */ - fprintf (of, "%s %s,", opcode[i], fname[fac]); - wd1 = fprint_spec (of, addr, dstm, val[1], cflag, FALSE); - break; - - case I_V_6B: /* 6b */ - fprintf (of, "%s %-o", opcode[i], dstm); - break; - - case I_V_BR: /* cond branch */ - fprintf (of, "%s ", opcode[i]); - brdisp = (l8b + l8b + ((l8b & 0200)? 0177002: 2)) & 0177777; - if (cflag) - fprintf (of, "%-o", (addr + brdisp) & 0177777); - else if (brdisp < 01000) - fprintf (of, ".+%-o", brdisp); - else fprintf (of, ".-%-o", 0200000 - brdisp); - break; - - case I_V_8B: /* 8b */ - fprintf (of, "%s %-o", opcode[i], l8b); - break; - - case I_V_SOB: /* sob */ - fprintf (of, "%s %s,", opcode[i], rname[srcr]); - brdisp = (dstm * 2) - 2; - if (cflag) - fprintf (of, "%-o", (addr - brdisp) & 0177777); - else if (brdisp <= 0) - fprintf (of, ".+%-o", -brdisp); - else fprintf (of, ".-%-o", brdisp); - break; - - case I_V_RSOP: /* rsop */ - fprintf (of, "%s %s,", opcode[i], rname[srcr]); - wd1 = fprint_spec (of, addr, dstm, val[1], cflag, TRUE); - break; - - case I_V_SOPR: /* sopr */ - fprintf (of, "%s ", opcode[i]); - wd1 = fprint_spec (of, addr, dstm, val[1], cflag, TRUE); - fprintf (of, ",%s", rname[srcr]); - break; - - case I_V_ASOP: case I_V_ASMD: /* asop, asmd */ - fprintf (of, "%s %s,", opcode[i], fname[fac]); - wd1 = fprint_spec (of, addr, dstm, val[1], cflag, TRUE); - break; - - case I_V_DOP: /* dop */ - fprintf (of, "%s ", opcode[i]); - wd1 = fprint_spec (of, addr, srcm, val[1], cflag, TRUE); - fprintf (of, ","); - wd2 = fprint_spec (of, addr - wd1 - wd1, dstm, - val[1 - wd1], cflag, TRUE); - break; - } /* end case */ - return ((wd1 + wd2) * 2) - 1; - } /* end if */ - } /* end for */ -return SCPE_ARG; /* no match */ -} - -#define A_PND 100 /* # seen */ -#define A_MIN 040 /* -( seen */ -#define A_PAR 020 /* (Rn) seen */ -#define A_REG 010 /* Rn seen */ -#define A_PLS 004 /* + seen */ -#define A_NUM 002 /* number seen */ -#define A_REL 001 /* relative addr seen */ - -/* Register number - - Inputs: - *cptr = pointer to input string - *strings = pointer to register names - mchar = character to match after register name - Outputs: - rnum = 0..7 if a legitimate register - < 0 if error -*/ - -int32 get_reg (char *cptr, const char *strings[], char mchar) -{ -int32 i; - -if (*(cptr + 2) != mchar) - return -1; -for (i = 0; i < 8; i++) { - if (strncmp (cptr, strings[i], 2) == 0) - return i; - } -return -1; -} - -/* Number or memory address - - Inputs: - *cptr = pointer to input string - *dptr = pointer to output displacement - *pflag = pointer to accumulating flags - Outputs: - cptr = pointer to next character in input string - NULL if parsing error - - Flags: 0 (no result), A_NUM (number), A_REL (relative) -*/ - -char *get_addr (char *cptr, int32 *dptr, int32 *pflag) -{ -int32 val, minus; -char *tptr; - -minus = 0; - -if (*cptr == '.') { /* relative? */ - *pflag = *pflag | A_REL; - cptr++; - } -if (*cptr == '+') { /* +? */ - *pflag = *pflag | A_NUM; - cptr++; - } -if (*cptr == '-') { /* -? */ - *pflag = *pflag | A_NUM; - minus = 1; - cptr++; - } -errno = 0; -val = strtoul (cptr, &tptr, 8); -if (cptr == tptr) { /* no number? */ - if (*pflag == (A_REL + A_NUM)) /* .+, .-? */ - return NULL; - *dptr = 0; - return cptr; - } -if (errno || (*pflag == A_REL)) /* .n? */ - return NULL; -*dptr = (minus? -val: val) & 0177777; -*pflag = *pflag | A_NUM; -return tptr; -} - -/* Specifier decode - - Inputs: - *cptr = pointer to input string - addr = current PC - n1 = 0 if no extra word used - -1 if extra word used in prior decode - *sptr = pointer to output specifier - *dptr = pointer to output displacement - cflag = true if parsing for the CPU - iflag = true if integer specifier - Outputs: - status = = -1 extra word decoded - = 0 ok - = +1 error -*/ - -t_stat get_spec (char *cptr, t_addr addr, int32 n1, int32 *sptr, t_value *dptr, - int32 cflag, int32 iflag) -{ -int32 reg, indir, pflag, disp = 0; - -indir = 0; /* no indirect */ -pflag = 0; - -if (*cptr == '@') { /* indirect? */ - indir = 010; - cptr++; - } -if (*cptr == '#') { /* literal? */ - pflag = pflag | A_PND; - cptr++; - } -if (strncmp (cptr, "-(", 2) == 0) { /* autodecrement? */ - pflag = pflag | A_MIN; - cptr++; - } -else if ((cptr = get_addr (cptr, &disp, &pflag)) == NULL) - return 1; -if (*cptr == '(') { /* register index? */ - pflag = pflag | A_PAR; - if ((reg = get_reg (cptr + 1, rname, ')')) < 0) - return 1; - cptr = cptr + 4; - if (*cptr == '+') { /* autoincrement? */ - pflag = pflag | A_PLS; - cptr++; - } - } -else if ((reg = get_reg (cptr, iflag? rname: fname, 0)) >= 0) { - pflag = pflag | A_REG; - cptr = cptr + 2; - } -if (*cptr != 0) /* all done? */ - return 1; -switch (pflag) { /* case on syntax */ - - case A_REG: /* Rn, @Rn */ - *sptr = indir + reg; - return 0; - - case A_PAR: /* (Rn), @(Rn) */ - if (indir) { /* @(Rn) = @0(Rn) */ - *sptr = 070 + reg; - *dptr = 0; - return -1; - } - else *sptr = 010 + reg; - return 0; - - case A_PAR+A_PLS: /* (Rn)+, @(Rn)+ */ - *sptr = 020 + indir + reg; - return 0; - - case A_MIN+A_PAR: /* -(Rn), @-(Rn) */ - *sptr = 040 + indir + reg; - return 0; - - case A_NUM+A_PAR: /* d(Rn), @d(Rn) */ - *sptr = 060 + indir + reg; - *dptr = disp; - return -1; - - case A_PND+A_REL: case A_PND+A_REL+A_NUM: /* #.+n, @#.+n */ - if (!cflag) - return 1; - disp = (disp + addr) & 0177777; /* fall through */ - case A_PND+A_NUM: /* #n, @#n */ - *sptr = 027 + indir; - *dptr = disp; - return -1; - - case A_REL: case A_REL+A_NUM: /* .+n, @.+n */ - *sptr = 067 + indir; - *dptr = (disp - 4 + (2 * n1)) & 0177777; - return -1; - - case A_NUM: /* n, @n */ - if (cflag) { /* CPU - use rel */ - *sptr = 067 + indir; - *dptr = (disp - addr - 4 + (2 * n1)) & 0177777; - } - else { - if (indir) return 1; /* other - use abs */ - *sptr = 037; - *dptr = disp; - } - return -1; - - default: - return 1; - } /* end case */ -} - -/* 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 bflag, cflag, d, i, j, reg, spec, n1, n2, disp, pflag; -t_value by; -t_stat r; -char *tptr, gbuf[CBUFSIZE]; - -bflag = 0; /* assume 16b */ -cflag = (uptr == NULL) || (uptr == &cpu_unit); /* cpu? */ -if (!cflag) { /* not cpu? */ - DEVICE *dptr = find_dev_from_unit (uptr); - if (dptr == NULL) - return SCPE_IERR; - if (dptr->dwidth < 16) - bflag = 1; - } - -while (isspace (*cptr)) cptr++; /* absorb spaces */ -if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ - if (cptr[0] == 0) /* must have 1 char */ - return SCPE_ARG; - if (bflag) - val[0] = (t_value) cptr[0]; - else val[0] = (addr & 1)? - (val[0] & 0377) | (((t_value) cptr[0]) << 8): - (val[0] & ~0377) | ((t_value) cptr[0]); - return 0; - } -if (sw & SWMASK ('B')) { /* byte? */ - by = get_uint (cptr, 8, 0377, &r); /* get byte */ - if (r != SCPE_OK) - return SCPE_ARG; - if (bflag) - val[0] = by; - else val[0] = (addr & 1)? - (val[0] & 0377) | (by << 8): - (val[0] & ~0377) | by; - return 0; - } -if (bflag) - return SCPE_ARG; - -if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */ - if (cptr[0] == 0) /* must have 1 char */ - return SCPE_ARG; - val[0] = ((t_value) cptr[1] << 8) | (t_value) cptr[0]; - return -1; - } -if (sw & SWMASK ('R')) /* radix 50 */ - return SCPE_ARG; - -cptr = get_glyph (cptr, gbuf, 0); /* get opcode */ -n1 = n2 = pflag = 0; -for (i = 0; (opcode[i] != NULL) && (strcmp (opcode[i], gbuf) != 0) ; i++) ; -if (opcode[i] == NULL) - return SCPE_ARG; -val[0] = opc_val[i] & 0177777; /* get value */ -j = (opc_val[i] >> I_V_CL) & I_M_CL; /* get class */ - -switch (j) { /* case on class */ - - case I_V_NPN: /* no operand */ - break; - - case I_V_REG: /* register */ - cptr = get_glyph (cptr, gbuf, 0); /* get glyph */ - if ((reg = get_reg (gbuf, rname, 0)) < 0) - return SCPE_ARG; - val[0] = val[0] | reg; - break; - - case I_V_3B: case I_V_6B: case I_V_8B: /* xb literal */ - cptr = get_glyph (cptr, gbuf, 0); /* get literal */ - d = get_uint (gbuf, 8, (1 << j) - 1, &r); - if (r != SCPE_OK) - return SCPE_ARG; - val[0] = val[0] | d; /* put in place */ - break; - - case I_V_BR: /* cond br */ - cptr = get_glyph (cptr, gbuf, 0); /* get address */ - tptr = get_addr (gbuf, &disp, &pflag); /* parse */ - if ((tptr == NULL) || (*tptr != 0)) - return SCPE_ARG; - if ((pflag & A_REL) == 0) { - if (cflag) - disp = (disp - addr) & 0177777; - else return SCPE_ARG; - } - if ((disp & 1) || ((disp > 0400) && (disp < 0177402))) - return SCPE_ARG; - val[0] = val[0] | (((disp - 2) >> 1) & 0377); - break; - - case I_V_SOB: /* sob */ - cptr = get_glyph (cptr, gbuf, ','); /* get glyph */ - if ((reg = get_reg (gbuf, rname, 0)) < 0) - return SCPE_ARG; - val[0] = val[0] | (reg << 6); - cptr = get_glyph (cptr, gbuf, 0); /* get address */ - tptr = get_addr (gbuf, &disp, &pflag); /* parse */ - if ((tptr == NULL) || (*tptr != 0)) - return SCPE_ARG; - if ((pflag & A_REL) == 0) { - if (cflag) - disp = (disp - addr) & 0177777; - else return SCPE_ARG; - } - if ((disp & 1) || ((disp > 2) && (disp < 0177604))) - return SCPE_ARG; - val[0] = val[0] | (((2 - disp) >> 1) & 077); - break; - - case I_V_RSOP: /* reg, sop */ - cptr = get_glyph (cptr, gbuf, ','); /* get glyph */ - if ((reg = get_reg (gbuf, rname, 0)) < 0) - return SCPE_ARG; - val[0] = val[0] | (reg << 6); /* fall through */ - case I_V_SOP: /* sop */ - cptr = get_glyph (cptr, gbuf, 0); /* get glyph */ - if ((n1 = get_spec (gbuf, addr, 0, &spec, &val[1], cflag, TRUE)) > 0) - return SCPE_ARG; - val[0] = val[0] | spec; - break; - - case I_V_SOPR: /* dop, reg */ - cptr = get_glyph (cptr, gbuf, ','); /* get glyph */ - if ((n1 = get_spec (gbuf, addr, 0, &spec, &val[1], cflag, TRUE)) > 0) - return SCPE_ARG; - val[0] = val[0] | spec; - cptr = get_glyph (cptr, gbuf, 0); /* get glyph */ - if ((reg = get_reg (gbuf, rname, 0)) < 0) - return SCPE_ARG; - val[0] = val[0] | (reg << 6); - break; - - case I_V_AFOP: case I_V_ASOP: case I_V_ASMD: /* fac, (s)fop */ - cptr = get_glyph (cptr, gbuf, ','); /* get glyph */ - if ((reg = get_reg (gbuf, fname, 0)) < 0) - return SCPE_ARG; - if (reg > 3) - return SCPE_ARG; - val[0] = val[0] | (reg << 6); /* fall through */ - case I_V_FOP: /* fop */ - cptr = get_glyph (cptr, gbuf, 0); /* get glyph */ - if ((n1 = get_spec (gbuf, addr, 0, &spec, &val[1], cflag, - (j == I_V_ASOP) || (j == I_V_ASMD))) > 0) - return SCPE_ARG; - val[0] = val[0] | spec; - break; - - case I_V_DOP: /* double op */ - cptr = get_glyph (cptr, gbuf, ','); /* get glyph */ - if ((n1 = get_spec (gbuf, addr, 0, &spec, &val[1], cflag, TRUE)) > 0) - return SCPE_ARG; - val[0] = val[0] | (spec << 6); - cptr = get_glyph (cptr, gbuf, 0); /* get glyph */ - if ((n2 = get_spec (gbuf, addr, n1, &spec, &val[1 - n1], - cflag, TRUE)) > 0) - return SCPE_ARG; - val[0] = val[0] | spec; - break; - - case I_V_CCC: case I_V_CCS: /* cond code oper */ - for (cptr = get_glyph (cptr, gbuf, 0); gbuf[0] != 0; - cptr = get_glyph (cptr, gbuf, 0)) { - for (i = 0; (opcode[i] != NULL) && - (strcmp (opcode[i], gbuf) != 0) ; i++) - ; - if ((((opc_val[i] >> I_V_CL) & I_M_CL) != j) || - (opcode[i] == NULL)) - return SCPE_ARG; - val[0] = val[0] | (opc_val[i] & 0177777); - } - break; - - default: - return SCPE_ARG; - } - -if (*cptr != 0) /* junk at end? */ - return SCPE_ARG; -return ((n1 + n2) * 2) - 1; -} diff --git a/PDP11/pdp11_ta.c b/PDP11/pdp11_ta.c deleted file mode 100644 index 5036aad2..00000000 --- a/PDP11/pdp11_ta.c +++ /dev/null @@ -1,665 +0,0 @@ -/* pdp11_ta.c: PDP-11 cassette tape simulator - - Copyright (c) 2007-2016, 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 ATAION OF CONTRATA, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNETAION 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. - - ta TA11/TU60 cassette tape - - 10-Oct-16 RMS Fixed bad register definitions (Mark Pizzolato) - 23-Oct-13 RMS Revised for new boot setup routine - 06-Jun-13 RMS Reset must set RDY (Ian Hammond) - Added CAPS-11 bootstrap (Ian Hammond) - 06-Aug-07 RMS Foward op at BOT skips initial file gap - - Magnetic tapes are represented as a series of variable records - of the form: - - 32b byte count - byte 0 - byte 1 - : - byte n-2 - byte n-1 - 32b byte count - - If the byte count is odd, the record is padded with an extra byte - of junk. File marks are represented by a byte count of 0. - - Cassette format differs in one very significant way: it has file gaps - rather than file marks. If the controller spaces or reads into a file - gap and then reverses direction, the file gap is not seen again. This - is in contrast to magnetic tapes, where the file mark is a character - sequence and is seen again if direction is reversed. In addition, - cassettes have an initial file gap which is automatically skipped on - forward operations from beginning of tape. -*/ - -#include "pdp11_defs.h" -#include "sim_tape.h" - -#define TA_NUMDR 2 /* #drives */ -#define FNC u3 /* unit function */ -#define UST u4 /* unit status */ -#define TA_SIZE 93000 /* chars/tape */ -#define TA_MAXFR (TA_SIZE) /* max record lnt */ - -/* Control/status - TACS */ - -#define TACS_ERR (1 << CSR_V_ERR) /* error */ -#define TACS_CRC 0040000 /* CRC */ -#define TACS_BEOT 0020000 /* BOT/EOT */ -#define TACS_WLK 0010000 /* write lock */ -#define TACS_EOF 0004000 /* end file */ -#define TACS_TIM 0002000 /* timing */ -#define TACS_EMP 0001000 /* empty */ -#define TACS_V_UNIT 8 /* unit */ -#define TACS_M_UNIT (TA_NUMDR - 1) -#define TACS_UNIT (TACS_M_UNIT << TACS_V_UNIT) -#define TACS_TR (1 << CSR_V_DONE) /* transfer req */ -#define TACS_IE (1 << CSR_V_IE) /* interrupt enable */ -#define TACS_RDY 0000040 /* ready */ -#define TACS_ILBS 0000020 /* start CRC */ -#define TACS_V_FNC 1 /* function */ -#define TACS_M_FNC 07 -#define TACS_WFG 00 -#define TACS_WRITE 01 -#define TACS_READ 02 -#define TACS_SRF 03 -#define TACS_SRB 04 -#define TACS_SFF 05 -#define TACS_SFB 06 -#define TACS_REW 07 -#define TACS_2ND 010 -#define TACS_3RD 030 -#define TACS_FNC (TACS_M_FNC << TACS_V_FNC) -#define TACS_GO (1 << CSR_V_GO) /* go */ -#define TACS_W (TACS_UNIT|TACS_IE|TACS_ILBS|TACS_FNC) -#define TACS_XFRERR (TACS_ERR|TACS_CRC|TACS_WLK|TACS_EOF|TACS_TIM) -#define GET_UNIT(x) (((x) >> TACS_V_UNIT) & TACS_M_UNIT) -#define GET_FNC(x) (((x) >> TACS_V_FNC) & TACS_M_FNC) - -/* Function code flags */ - -#define OP_WRI 01 /* op is a write */ -#define OP_REV 02 /* op is rev motion */ -#define OP_FWD 04 /* op is fwd motion */ - -/* Unit status flags */ - -#define UST_REV (OP_REV) /* last op was rev */ -#define UST_GAP 01 /* last op hit gap */ - -extern int32 int_req[IPL_HLVL]; - -uint32 ta_cs = 0; /* control/status */ -uint32 ta_idb = 0; /* input data buf */ -uint32 ta_odb = 0; /* output data buf */ -uint32 ta_write = 0; /* TU60 write flag */ -uint32 ta_bptr = 0; /* buf ptr */ -uint32 ta_blnt = 0; /* buf length */ -int32 ta_stime = 1000; /* start time */ -int32 ta_ctime = 100; /* char latency */ -uint32 ta_stopioe = 1; /* stop on error */ -uint8 *ta_xb = NULL; /* transfer buffer */ -static uint8 ta_fnc_tab[TACS_M_FNC + 1] = { - OP_WRI|OP_FWD, OP_WRI|OP_FWD, OP_FWD, OP_REV, - OP_REV , OP_FWD, OP_FWD, 0 - }; - -t_stat ta_rd (int32 *data, int32 PA, int32 access); -t_stat ta_wr (int32 data, int32 PA, int32 access); -t_stat ta_svc (UNIT *uptr); -t_stat ta_reset (DEVICE *dptr); -t_stat ta_attach (UNIT *uptr, char *cptr); -t_stat ta_detach (UNIT *uptr); -t_stat ta_boot (int32 unitno, DEVICE *dptr); -void ta_go (void); -t_stat ta_map_err (UNIT *uptr, t_stat st); -UNIT *ta_busy (void); -void ta_set_tr (void); -uint32 ta_updsta (UNIT *uptr); -uint32 ta_crc (uint8 *buf, uint32 cnt); - -/* TA data structures - - ta_dev TA device descriptor - ta_unit TA unit list - ta_reg TA register list - ta_mod TA modifier list -*/ - -DIB ta_dib = { - IOBA_TA, IOLN_TA, &ta_rd, &ta_wr, - 1, IVCL (TA), VEC_TA, { NULL } - }; - -UNIT ta_unit[] = { - { UDATA (&ta_svc, UNIT_ATTABLE+UNIT_ROABLE, TA_SIZE) }, - { UDATA (&ta_svc, UNIT_ATTABLE+UNIT_ROABLE, TA_SIZE) }, - }; - -REG ta_reg[] = { - { ORDATA (TACS, ta_cs, 16) }, - { ORDATA (TAIDB, ta_idb, 8) }, - { ORDATA (TAODB, ta_odb, 8) }, - { FLDATA (WRITE, ta_write, 0) }, - { FLDATA (INT, IREQ (TA), INT_V_TA) }, - { FLDATA (ERR, ta_cs, CSR_V_ERR) }, - { FLDATA (TR, ta_cs, CSR_V_DONE) }, - { FLDATA (IE, ta_cs, CSR_V_IE) }, - { DRDATA (BPTR, ta_bptr, 17) }, - { DRDATA (BLNT, ta_blnt, 17) }, - { DRDATA (STIME, ta_stime, 24), PV_LEFT + REG_NZ }, - { DRDATA (CTIME, ta_ctime, 24), PV_LEFT + REG_NZ }, - { FLDATA (STOP_IOE, ta_stopioe, 0) }, - { URDATA (UFNC, ta_unit[0].FNC, 8, 5, 0, TA_NUMDR, REG_HRO) }, - { URDATA (UST, ta_unit[0].UST, 8, 2, 0, TA_NUMDR, REG_HRO) }, - { URDATA (POS, ta_unit[0].pos, 10, T_ADDR_W, 0, - TA_NUMDR, PV_LEFT | REG_RO) }, - { ORDATA (DEVADDR, ta_dib.ba, 32), REG_HRO }, - { ORDATA (DEVVEC, ta_dib.vec, 16), REG_HRO }, - { NULL } - }; - -MTAB ta_mod[] = { - { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, -// { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT", -// &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, - { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", NULL, - NULL, &sim_tape_show_capac, NULL }, - { MTAB_XTD|MTAB_VDV, IOLN_TA, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", - &set_vec, &show_vec, NULL }, - { 0 } - }; - -DEVICE ta_dev = { - "TA", ta_unit, ta_reg, ta_mod, - TA_NUMDR, 10, 31, 1, 8, 8, - NULL, NULL, &ta_reset, - &ta_boot, &ta_attach, &ta_detach, - &ta_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG | DEV_UBUS - }; - -/* I/O dispatch routines, I/O addresses 17777500 - 17777503 - - 17777500 TACS read/write - 17777502 TADB read/write -*/ - -t_stat ta_rd (int32 *data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 01) { /* decode PA<1> */ - - case 0: /* TACSR */ - *data = ta_updsta (NULL); /* update status */ - break; - - case 1: /* TADB */ - *data = ta_idb; /* return byte */ - ta_cs &= ~TACS_TR; /* clear tra req */ - ta_updsta (NULL); - break; - } - -return SCPE_OK; -} - -t_stat ta_wr (int32 data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 01) { /* decode PA<1> */ - - case 0: /* TACS */ - if (access == WRITEB) data = (PA & 1)? /* byte write? */ - (ta_cs & 0377) | (data << 8): /* merge old */ - (ta_cs & ~0377) | data; - ta_cs = (ta_cs & ~TACS_W) | (data & TACS_W); /* merge new */ - if ((data & CSR_GO) && !ta_busy ()) /* go, not busy? */ - ta_go (); /* start operation */ - if (ta_cs & TACS_ILBS) /* ILBS inhibits TR */ - ta_cs &= ~TACS_TR; - break; - - case 1: /* TADB */ - if (PA & 1) /* ignore odd byte */ - break; - ta_odb = data; /* return byte */ - ta_cs &= ~TACS_TR; /* clear tra req */ - break; - } /* end switch */ - -ta_updsta (NULL); /* update status */ -return SCPE_OK; -} - -/* Start a new operation - cassette is not busy */ - -void ta_go (void) -{ -UNIT *uptr = ta_dev.units + GET_UNIT (ta_cs); -uint32 fnc = GET_FNC (ta_cs); -uint32 flg = ta_fnc_tab[fnc]; -uint32 old_ust = uptr->UST; - -if (DEBUG_PRS (ta_dev)) fprintf (sim_deb, - ">>TA start: op=%o, old_sta = %o, pos=%d\n", - fnc, uptr->UST, uptr->pos); -ta_cs &= ~(TACS_XFRERR|TACS_EMP|TACS_TR|TACS_RDY); /* clr err, tr, rdy */ -ta_bptr = 0; /* init buffer */ -ta_blnt = 0; -if ((uptr->flags & UNIT_ATT) == 0) { - ta_cs |= TACS_ERR|TACS_EMP|TACS_RDY; - return; - } -if (flg & OP_WRI) { /* write op? */ - if (sim_tape_wrp (uptr)) { /* locked? */ - ta_cs |= TACS_ERR|TACS_WLK|TACS_RDY; /* don't start */ - return; - } - ta_odb = 0; - ta_write = 1; - } -else { - ta_idb = 0; - ta_write = 0; - } -ta_cs &= ~TACS_BEOT; /* tape in motion */ -uptr->FNC = fnc; /* save function */ -if ((fnc != TACS_REW) && !(flg & OP_WRI)) { /* spc/read cmd? */ - t_mtrlnt t; - t_stat st; - uptr->UST = flg & UST_REV; /* save direction */ - if (sim_tape_bot (uptr) && (flg & OP_FWD)) { /* spc/read fwd bot? */ - st = sim_tape_rdrecf (uptr, ta_xb, &t, TA_MAXFR); /* skip file gap */ - if (st != MTSE_TMK) /* not there? */ - sim_tape_rewind (uptr); /* restore tap pos */ - else old_ust = 0; /* defang next */ - } - if ((old_ust ^ uptr->UST) == (UST_REV|UST_GAP)) { /* reverse in gap? */ - if (uptr->UST) /* skip file gap */ - sim_tape_rdrecr (uptr, ta_xb, &t, TA_MAXFR); - else sim_tape_rdrecf (uptr, ta_xb, &t, TA_MAXFR); - if (DEBUG_PRS (ta_dev)) - fprintf (sim_deb, ">>TA skip gap: op=%o, old_sta = %o, pos=%d\n", - fnc, uptr->UST, uptr->pos); - } - } -else uptr->UST = 0; -sim_activate (uptr, ta_stime); /* schedule op */ -return; -} - -/* Unit service */ - -t_stat ta_svc (UNIT *uptr) -{ -uint32 i, crc; -uint32 flg = ta_fnc_tab[uptr->FNC & TACS_M_FNC]; -t_mtrlnt tbc; -t_stat st, r; - -if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ - ta_cs |= TACS_ERR|TACS_EMP|TACS_RDY; - ta_updsta (uptr); /* update status */ - return (ta_stopioe? SCPE_UNATT: SCPE_OK); - } -if (((flg & OP_FWD) && sim_tape_eot (uptr)) || /* illegal motion? */ - ((flg & OP_REV) && sim_tape_bot (uptr))) { - ta_cs |= TACS_ERR|TACS_BEOT|TACS_RDY; /* error */ - ta_updsta (uptr); - return SCPE_OK; - } - -r = SCPE_OK; -switch (uptr->FNC) { /* case on function */ - - case TACS_READ: /* read start */ - st = sim_tape_rdrecf (uptr, ta_xb, &ta_blnt, TA_MAXFR); /* get rec */ - if (st == MTSE_RECE) /* rec in err? */ - ta_cs |= TACS_ERR|TACS_CRC; - else if (st != MTSE_OK) { /* other error? */ - r = ta_map_err (uptr, st); /* map error */ - break; - } - crc = ta_crc (ta_xb, ta_blnt); /* calculate CRC */ - ta_xb[ta_blnt++] = (crc >> 8) & 0377; /* append to buffer */ - ta_xb[ta_blnt++] = crc & 0377; - uptr->FNC |= TACS_2ND; /* next state */ - sim_activate (uptr, ta_ctime); /* sched next char */ - return SCPE_OK; - - case TACS_READ|TACS_2ND: /* read char */ - if (ta_bptr < ta_blnt) /* more chars? */ - ta_idb = ta_xb[ta_bptr++]; - else { /* no */ - ta_idb = 0; - ta_cs |= TACS_ERR|TACS_CRC; /* overrun */ - break; /* tape stops */ - } - if (ta_cs & TACS_ILBS) { /* CRC seq? */ - uptr->FNC |= TACS_3RD; /* next state */ - sim_activate (uptr, ta_stime); /* sched CRC chk */ - } - else { - ta_set_tr (); /* set tra req */ - sim_activate (uptr, ta_ctime); /* sched next char */ - } - return SCPE_OK; - - case TACS_READ|TACS_3RD: /* second read CRC */ - if (ta_bptr != ta_blnt) { /* partial read? */ - crc = ta_crc (ta_xb, ta_bptr + 2); /* actual CRC */ - if (crc != 0) /* must be zero */ - ta_cs |= TACS_ERR|TACS_CRC; - } - break; /* read done */ - - case TACS_WRITE: /* write start */ - for (i = 0; i < TA_MAXFR; i++) /* clear buffer */ - ta_xb[i] = 0; - ta_set_tr (); /* set tra req */ - uptr->FNC |= TACS_2ND; /* next state */ - sim_activate (uptr, ta_ctime); /* sched next char */ - return SCPE_OK; - - case TACS_WRITE|TACS_2ND: /* write char */ - if (ta_cs & TACS_ILBS) { /* CRC seq? */ - uptr->FNC |= TACS_3RD; /* next state */ - sim_activate (uptr, ta_stime); /* sched wri done */ - } - else { - if ((ta_bptr < TA_MAXFR) && /* room in buf? */ - ((uptr->pos + ta_bptr) < uptr->capac)) /* room on tape? */ - ta_xb[ta_bptr++] = (uint8)ta_odb; /* store char */ - ta_set_tr (); /* set tra req */ - sim_activate (uptr, ta_ctime); /* sched next char */ - } - return SCPE_OK; - - case TACS_WRITE|TACS_3RD: /* write CRC */ - if (ta_bptr) { /* anything to write? */ - if ((st = sim_tape_wrrecf (uptr, ta_xb, ta_bptr)))/* write, err? */ - r = ta_map_err (uptr, st); /* map error */ - } - break; /* op done */ - - case TACS_WFG: /* write file gap */ - if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ - r = ta_map_err (uptr, st); /* map error */ - break; - - case TACS_REW: /* rewind */ - sim_tape_rewind (uptr); - ta_cs |= TACS_BEOT; /* bot, no error */ - break; - - case TACS_SRB: /* space rev blk */ - if ((st = sim_tape_sprecr (uptr, &tbc))) /* space rev, err? */ - r = ta_map_err (uptr, st); /* map error */ - break; - - case TACS_SRF: /* space rev file */ - while ((st = sim_tape_sprecr (uptr, &tbc)) == MTSE_OK) ; - if (st == MTSE_TMK) /* if tape mark, */ - ta_cs |= TACS_EOF; /* set EOF, no err */ - else r = ta_map_err (uptr, st); /* else map error */ - break; - - case TACS_SFB: /* space fwd blk */ - if ((st = sim_tape_sprecf (uptr, &tbc))) /* space rev, err? */ - r = ta_map_err (uptr, st); /* map error */ - ta_cs |= TACS_CRC; /* CRC sets, no err */ - break; - - case TACS_SFF: /* space fwd file */ - while ((st = sim_tape_sprecf (uptr, &tbc)) == MTSE_OK) ; - if (st == MTSE_TMK) /* if tape mark, */ - ta_cs |= TACS_EOF; /* set EOF, no err */ - else r = ta_map_err (uptr, st); /* else map error */ - break; - - default: /* never get here! */ - return SCPE_IERR; - } /* end case */ - -ta_cs |= TACS_RDY; /* set ready */ -ta_updsta (uptr); /* update status */ -if (DEBUG_PRS (ta_dev)) - fprintf (sim_deb, ">>TA done: op=%o, status = %o, dstatus = %o, pos=%d\n", - uptr->FNC, ta_cs, uptr->UST, uptr->pos); -return r; -} - -/* Update controller status */ - -uint32 ta_updsta (UNIT *uptr) -{ -if (uptr == NULL) { /* unit specified? */ - if ((uptr = ta_busy ()) == NULL) /* use busy */ - uptr = ta_dev.units + GET_UNIT (ta_cs); /* use sel unit */ - } -else if (ta_cs & TACS_EOF) /* save EOF */ - uptr->UST |= UST_GAP; -if (uptr->flags & UNIT_ATT) /* attached? */ - ta_cs &= ~TACS_EMP; -else ta_cs |= TACS_EMP|TACS_RDY; /* no, empty, ready */ -if ((ta_cs & TACS_IE) && /* int enabled? */ - (ta_cs & (TACS_TR|TACS_RDY))) /* req or ready? */ - SET_INT (TA); /* set int req */ -else CLR_INT (TA); /* no, clr int req */ -return ta_cs; -} - -/* Set transfer request */ - -void ta_set_tr (void) -{ -if (ta_cs & TACS_TR) /* flag still set? */ - ta_cs |= (TACS_ERR|TACS_TIM); -else ta_cs |= TACS_TR; /* set xfr req */ -if (ta_cs & TACS_IE) /* if ie, int req */ - SET_INT (TA); -return; -} - -/* Test if controller busy */ - -UNIT *ta_busy (void) -{ -uint32 u; -UNIT *uptr; - -for (u = 0; u < TA_NUMDR; u++) { /* loop thru units */ - uptr = ta_dev.units + u; - if (sim_is_active (uptr)) - return uptr; - } -return NULL; -} - -/* Calculate CRC on buffer */ - -uint32 ta_crc (uint8 *buf, uint32 cnt) -{ -uint32 crc, i, j; - -crc = 0; -for (i = 0; i < cnt; i++) { - crc = crc ^ (((uint32) buf[i]) << 8); - for (j = 0; j < 8; j++) { - if (crc & 1) - crc = (crc >> 1) ^ 0xA001; - else crc = crc >> 1; - } - } -return crc; -} - -/* Map error status */ - -t_stat ta_map_err (UNIT *uptr, t_stat st) -{ -switch (st) { - - case MTSE_FMT: /* illegal fmt */ - case MTSE_UNATT: /* unattached */ - ta_cs |= TACS_ERR|TACS_CRC; - case MTSE_OK: /* no error */ - return SCPE_IERR; /* never get here! */ - - case MTSE_TMK: /* end of file */ - ta_cs |= TACS_ERR|TACS_EOF; - break; - - case MTSE_IOERR: /* IO error */ - ta_cs |= TACS_ERR|TACS_CRC; /* set crc err */ - if (ta_stopioe) - return SCPE_IOERR; - break; - - case MTSE_INVRL: /* invalid rec lnt */ - ta_cs |= TACS_ERR|TACS_CRC; /* set crc err */ - return SCPE_MTRLNT; - - case MTSE_RECE: /* record in error */ - case MTSE_EOM: /* end of medium */ - ta_cs |= TACS_ERR|TACS_CRC; /* set crc err */ - break; - - case MTSE_BOT: /* reverse into BOT */ - ta_cs |= TACS_ERR|TACS_BEOT; /* set bot */ - break; - - case MTSE_WRP: /* write protect */ - ta_cs |= TACS_ERR|TACS_WLK; /* set wlk err */ - break; - } - -return SCPE_OK; -} - -/* Reset routine */ - -t_stat ta_reset (DEVICE *dptr) -{ -uint32 u; -UNIT *uptr; - -ta_cs = TACS_RDY; /* init sets RDY */ -ta_idb = 0; -ta_odb = 0; -ta_write = 0; -ta_bptr = 0; -ta_blnt = 0; -CLR_INT (TA); /* clear interrupt */ -for (u = 0; u < TA_NUMDR; u++) { /* loop thru units */ - uptr = ta_dev.units + u; - sim_cancel (uptr); /* cancel activity */ - sim_tape_reset (uptr); /* reset tape */ - } -if (ta_xb == NULL) - ta_xb = (uint8 *) calloc (TA_MAXFR + 2, sizeof (uint8)); -if (ta_xb == NULL) - return SCPE_MEM; -return SCPE_OK; -} - -/* Attach routine */ - -t_stat ta_attach (UNIT *uptr, char *cptr) -{ -t_stat r; - -r = sim_tape_attach (uptr, cptr); -if (r != SCPE_OK) - return r; -ta_updsta (NULL); -uptr->UST = 0; -return r; -} - -/* Detach routine */ - -t_stat ta_detach (UNIT* uptr) -{ -t_stat r; - -if (!(uptr->flags & UNIT_ATT)) /* check attached */ - return SCPE_OK; -r = sim_tape_detach (uptr); -ta_updsta (NULL); -uptr->UST = 0; -return r; -} - -/* Bootstrap routine */ - -#define BOOT_START 01000 /* start */ -#define BOOT_ENTRY (BOOT_START) -#define BOOT_CSR (BOOT_START + 002) /* CSR */ -#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint16)) - -static const uint16 boot_rom[] = { -0012700, /* mov #tacs,r0 */ -0177500, -0005010, /* clr (r0) */ -0010701, /* 3$: mov pc,r1 */ -0062701, /* add #20-here,r1 */ -0000052, -0012702, /* mov #375,r2 */ -0000375, -0112103, /* movb (r1)+,r3 */ -0112110, /* 5$: movb (r1)+,(r0) */ -0100413, /* bmi 15$ */ -0130310, /* 10$: bitb r3,(r0) */ -0001776, /* beq 10$ */ -0105202, /* incb r2 */ -0100772, /* bmi 5$ */ -0116012, /* movb 2(r0),r2 */ -0000002, -0120337, /* cmpb r3,@#0 */ -0000000, -0001767, /* beq 10$ */ -0000000, /* 12$: halt */ -0000755, /* br 3$ */ -0005710, /* 15$: tst (r0) */ -0100774, /* bmi 12$ */ -0005007, /* clr pc */ -0017640, /* $20: (data) */ -0002415, -0112024 -}; - -t_stat ta_boot (int32 unitno, DEVICE *dptr) -{ -size_t i; -extern uint16 *M; - -for (i = 0; i < BOOT_LEN; i++) - M[(BOOT_START >> 1) + i] = boot_rom[i]; -M[BOOT_CSR >> 1] = ta_dib.ba & DMASK; -cpu_set_boot (BOOT_ENTRY); -return SCPE_OK; -} \ No newline at end of file diff --git a/PDP11/pdp11_tc.c b/PDP11/pdp11_tc.c deleted file mode 100644 index c4c4f2dc..00000000 --- a/PDP11/pdp11_tc.c +++ /dev/null @@ -1,1381 +0,0 @@ -/* pdp11_tc.c: PDP-11 DECtape simulator - - Copyright (c) 1993-2017, 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. - - tc TC11/TU56 DECtape - - 15-Mar-17 RMS Fixed to defer error interrupts (Paul Koning) - 14-Mar-17 RMS Fixed spurious interrupt when setting GO (Paul Koning) - 04-Dec-16 RMS Revised to model TCCM correctly (Josh Dersch) - 23-Oct-13 RMS Revised for new boot setup routine - 23-Jun-06 RMS Fixed switch conflict in ATTACH - 10-Feb-06 RMS READ sets extended data bits in TCST (Alan Frisbie) - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 07-Jul-05 RMS Removed extraneous externs - 30-Sep-04 RMS Revised Unibus interface - 25-Jan-04 RMS Revised for device debug support - 09-Jan-04 RMS Changed sim_fsize calling sequence, added STOP_OFFR - 29-Dec-03 RMS Changed initial status to disabled (in Qbus system) - 18-Oct-03 RMS Fixed reverse checksum in read all - Added DECtape off reel message - Simplified timing - 25-Apr-03 RMS Revised for extended file support - 14-Mar-03 RMS Fixed variable size interaction with save/restore - 29-Sep-02 RMS Added variable address support to bootstrap - Added vector change/display support - Added 16b format support - New data structures - 30-May-02 RMS Widened POS to 32b - 26-Jan-02 RMS Revised bootstrap to conform to M9312 - 06-Jan-02 RMS Revised enable/disable support - 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 - 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 - 26-Apr-01 RMS Added device enable/disable support - 18-Apr-01 RMS Changed to rewind tape before boot - 16-Mar-01 RMS Fixed bug in interrupt after stop - 15-Mar-01 RMS Added 129th word to PDP-8 format - - PDP-11 DECtapes are represented in memory by fixed length buffer of 32b words. - Three file formats are supported: - - 18b/36b 256 words per block [256 x 18b] - 16b 256 words per block [256 x 16b] - 12b 129 words per block [129 x 12b] - - When a 16b or 12b DECtape file is read in, it is converted to 18b/36b format. - - DECtape motion is measured in 3b lines. Time between lines is 33.33us. - Tape density is nominally 300 lines per inch. The format of a DECtape (as - taken from the TD8E formatter) is: - - reverse end zone 8192 reverse end zone codes ~ 10 feet - reverse buffer 200 interblock codes - block 0 - : - block n - forward buffer 200 interblock codes - forward end zone 8192 forward end zone codes ~ 10 feet - - A block consists of five 18b header words, a tape-specific number of data - words, and five 18b trailer words. All systems except the PDP-8 use a - standard block length of 256 words; the PDP-8 uses a standard block length - of 86 words (x 18b = 129 words x 12b). - - Because a DECtape file only contains data, the simulator cannot support - write timing and mark track and can only do a limited implementation - of read all and write all. Read all assumes that the tape has been - conventionally written forward: - - header word 0 0 - header word 1 block number (for forward reads) - header words 2,3 0 - header word 4 checksum (for reverse reads) - : - trailer word 4 checksum (for forward reads) - trailer words 3,2 0 - trailer word 1 block number (for reverse reads) - trailer word 0 0 - - Write all writes only the data words and dumps the interblock words in the - bit bucket. -*/ - -#include "pdp11_defs.h" - -#define DT_NUMDR 8 /* #drives */ -#define DT_M_NUMDR (DT_NUMDR - 1) -#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_V_8FMT (UNIT_V_UF + 1) /* 12b format */ -#define UNIT_V_11FMT (UNIT_V_UF + 2) /* 16b format */ -#define UNIT_WLK (1 << UNIT_V_WLK) -#define UNIT_8FMT (1 << UNIT_V_8FMT) -#define UNIT_11FMT (1 << UNIT_V_11FMT) -#define STATE u3 /* unit state */ -#define LASTT u4 /* last time update */ -#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ - -/* System independent DECtape constants */ - -#define DT_LPERMC 6 /* lines per mark track */ -#define DT_BLKWD 1 /* blk no word in h/t */ -#define DT_CSMWD 4 /* checksum word in h/t */ -#define DT_HTWRD 5 /* header/trailer words */ -#define DT_EZLIN (8192 * DT_LPERMC) /* end zone length */ -#define DT_BFLIN (200 * DT_LPERMC) /* buffer length */ -#define DT_BLKLN (DT_BLKWD * DT_LPERMC) /* blk no line in h/t */ -#define DT_CSMLN (DT_CSMWD * DT_LPERMC) /* csum line in h/t */ -#define DT_HTLIN (DT_HTWRD * DT_LPERMC) /* header/trailer lines */ - -/* 16b, 18b, 36b DECtape constants */ - -#define D18_WSIZE 6 /* word size in lines */ -#define D18_BSIZE 256 /* block size in 18b */ -#define D18_TSIZE 578 /* tape size */ -#define D18_LPERB (DT_HTLIN + (D18_BSIZE * DT_WSIZE) + DT_HTLIN) -#define D18_FWDEZ (DT_EZLIN + (D18_LPERB * D18_TSIZE)) -#define D18_CAPAC (D18_TSIZE * D18_BSIZE) /* tape capacity */ -#define D16_FILSIZ (D18_TSIZE * D18_BSIZE * sizeof (int16)) - -/* 12b DECtape constants */ - -#define D8_WSIZE 4 /* word size in lines */ -#define D8_BSIZE 86 /* block size in 18b */ -#define D8_TSIZE 1474 /* tape size */ -#define D8_LPERB (DT_HTLIN + (D8_BSIZE * DT_WSIZE) + DT_HTLIN) -#define D8_FWDEZ (DT_EZLIN + (D8_LPERB * D8_TSIZE)) -#define D8_CAPAC (D8_TSIZE * D8_BSIZE) /* tape capacity */ - -#define D8_NBSIZE ((D8_BSIZE * D18_WSIZE) / D8_WSIZE) -#define D8_FILSIZ (D8_NBSIZE * D8_TSIZE * sizeof (int16)) - -/* This controller */ - -#define DT_CAPAC D18_CAPAC /* default */ -#define DT_WSIZE D18_WSIZE - -/* Calculated constants, per unit */ - -#define DTU_BSIZE(u) (((u)->flags & UNIT_8FMT)? D8_BSIZE: D18_BSIZE) -#define DTU_TSIZE(u) (((u)->flags & UNIT_8FMT)? D8_TSIZE: D18_TSIZE) -#define DTU_LPERB(u) (((u)->flags & UNIT_8FMT)? D8_LPERB: D18_LPERB) -#define DTU_FWDEZ(u) (((u)->flags & UNIT_8FMT)? D8_FWDEZ: D18_FWDEZ) -#define DTU_CAPAC(u) (((u)->flags & UNIT_8FMT)? D8_CAPAC: D18_CAPAC) - -#define DT_LIN2BL(p,u) (((p) - DT_EZLIN) / DTU_LPERB (u)) -#define DT_LIN2OF(p,u) (((p) - DT_EZLIN) % DTU_LPERB (u)) -#define DT_LIN2WD(p,u) ((DT_LIN2OF (p,u) - DT_HTLIN) / DT_WSIZE) -#define DT_BLK2LN(p,u) (((p) * DTU_LPERB (u)) + DT_EZLIN) -#define DT_QREZ(u) (((u)->pos) < DT_EZLIN) -#define DT_QFEZ(u) (((u)->pos) >= ((uint32) DTU_FWDEZ (u))) -#define DT_QEZ(u) (DT_QREZ (u) || DT_QFEZ (u)) - -/* TCST - 177340 - status register */ - -#define STA_END 0100000 /* end zone */ -#define STA_PAR 0040000 /* parity err */ -#define STA_MRK 0020000 /* mark trk err */ -#define STA_ILO 0010000 /* illegal op */ -#define STA_SEL 0004000 /* select err */ -#define STA_BLKM 0002000 /* block miss err */ -#define STA_DATM 0001000 /* data miss err */ -#define STA_NXM 0000400 /* nx mem err */ -#define STA_UPS 0000200 /* up to speed */ -#define STA_V_XD 0 /* extended data */ -#define STA_M_XD 03 -#define STA_ALLERR (STA_END | STA_PAR | STA_MRK | STA_ILO | \ - STA_SEL | STA_BLKM | STA_DATM | STA_NXM ) -#define STA_RWERR (STA_END | STA_PAR | STA_MRK | \ - STA_BLKM | STA_DATM | STA_NXM ) -#define STA_RW 0000003 -#define STA_GETXD(x) (((x) >> STA_V_XD) & STA_M_XD) - -/* TCCM - 177342 - command register */ - -/* #define CSR_ERR 0100000 */ -#define CSR_MNT 0020000 /* maint (unimpl) */ -#define CSR_INH 0010000 /* delay inhibit */ -#define CSR_DIR 0004000 /* reverse */ -#define CSR_V_UNIT 8 /* unit select */ -#define CSR_M_UNIT 07 -#define CSR_UNIT (CSR_M_UNIT << CSR_V_UNIT) -/* #define CSR_DONE 0000200 */ -/* #define CSR_IE 0000100 */ -#define CSR_V_MEX 4 /* mem extension */ -#define CSR_M_MEX 03 -#define CSR_MEX (CSR_M_MEX << CSR_V_MEX) -#define CSR_V_FNC 1 /* function */ -#define CSR_M_FNC 07 -#define FNC_STOP 00 /* stop all */ -#define FNC_SRCH 01 /* search */ -#define FNC_READ 02 /* read */ -#define FNC_RALL 03 /* read all */ -#define FNC_SSEL 04 /* stop selected */ -#define FNC_WMRK 05 /* write */ -#define FNC_WRIT 06 /* write all */ -#define FNC_WALL 07 /* write timing */ -/* define CSR_GO 0000001 */ -#define CSR_RW 0117576 /* read/write */ - -#define CSR_GETUNIT(x) (((x) >> CSR_V_UNIT) & CSR_M_UNIT) -#define CSR_GETMEX(x) (((x) >> CSR_V_MEX) & CSR_M_MEX) -#define CSR_GETFNC(x) (((x) >> CSR_V_FNC) & CSR_M_FNC) -#define CSR_INCMEX(x) (((x) & ~CSR_MEX) | (((x) + (1 << CSR_V_MEX)) & CSR_MEX)) - -/* TCWC - 177344 - word count */ - -/* TCBA - 177346 - bus address */ - -/* TCDT - 177350 - data */ - -/* DECtape state */ - -#define DTS_V_MOT 3 /* motion */ -#define DTS_M_MOT 07 -#define DTS_STOP 0 /* stopped */ -#define DTS_DECF 2 /* decel, fwd */ -#define DTS_DECR 3 /* decel, rev */ -#define DTS_ACCF 4 /* accel, fwd */ -#define DTS_ACCR 5 /* accel, rev */ -#define DTS_ATSF 6 /* @speed, fwd */ -#define DTS_ATSR 7 /* @speed, rev */ -#define DTS_DIR 01 /* dir mask */ -#define DTS_V_FNC 0 /* function */ -#define DTS_M_FNC 07 -#define DTS_OFR FNC_WMRK /* "off reel" */ -#define DTS_GETMOT(x) (((x) >> DTS_V_MOT) & DTS_M_MOT) -#define DTS_GETFNC(x) (((x) >> DTS_V_FNC) & DTS_M_FNC) -#define DTS_V_2ND 6 /* next state */ -#define DTS_V_3RD (DTS_V_2ND + DTS_V_2ND) /* next next */ -#define DTS_STA(y,z) (((y) << DTS_V_MOT) | ((z) << DTS_V_FNC)) -#define DTS_SETSTA(y,z) uptr->STATE = DTS_STA (y, z) -#define DTS_SET2ND(y,z) uptr->STATE = (uptr->STATE & 077) | \ - ((DTS_STA (y, z)) << DTS_V_2ND) -#define DTS_SET3RD(y,z) uptr->STATE = (uptr->STATE & 07777) | \ - ((DTS_STA (y, z)) << DTS_V_3RD) -#define DTS_NXTSTA(x) (x >> DTS_V_2ND) - -/* Logging */ - -#define LOG_MS 0x1 -#define LOG_RW 0x2 -#define LOG_BL 0x4 - -#define DT_SETDONE if ((tccm & (CSR_DONE|CSR_IE)) == CSR_IE) \ - SET_INT (DTA); \ - tccm = tccm | CSR_DONE -#define DT_CLRDONE CLR_INT (DTA); \ - tccm = tccm & ~CSR_DONE -#define ABS(x) (((x) < 0)? (-(x)): (x)) - -extern uint16 *M; /* memory */ -extern int32 int_req[IPL_HLVL]; -extern UNIT cpu_unit; - -int32 tcst = 0; /* status */ -int32 tccm = 0; /* command */ -int32 tcwc = 0; /* word count */ -int32 tcba = 0; /* bus address */ -int32 tcdt = 0; /* data */ -int32 dt_ctime = 100; /* fast cmd time */ -int32 dt_ltime = 12; /* interline time */ -int32 dt_dctime = 40000; /* decel time */ -int32 dt_substate = 0; -int32 dt_logblk = 0; -int32 dt_stopoffr = 0; - -t_stat dt_rd (int32 *data, int32 PA, int32 access); -t_stat dt_wr (int32 data, int32 PA, int32 access); -t_stat dt_svc (UNIT *uptr); -t_stat dt_svcdone (UNIT *uptr); -t_stat dt_reset (DEVICE *dptr); -t_stat dt_attach (UNIT *uptr, char *cptr); -t_stat dt_detach (UNIT *uptr); -t_stat dt_boot (int32 unitno, DEVICE *dptr); -void dt_deselect (int32 oldf); -void dt_newsa (int32 newf); -void dt_newfnc (UNIT *uptr, int32 newsta); -t_bool dt_setpos (UNIT *uptr); -void dt_schedez (UNIT *uptr, int32 dir); -void dt_seterr (UNIT *uptr, int32 e); -void dt_stopunit (UNIT *uptr); -int32 dt_comobv (int32 val); -int32 dt_csum (UNIT *uptr, int32 blk); -int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos); - -/* DT data structures - - dt_dev DT device descriptor - dt_unit DT unit list - dt_reg DT register list - dt_mod DT modifier list -*/ - -DIB dt_dib = { - IOBA_TC, IOLN_TC, &dt_rd, &dt_wr, - 1, IVCL (DTA), VEC_DTA, { NULL } - }; - -UNIT dt_unit[] = { - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE+UNIT_11FMT, DT_CAPAC) }, - { UDATA (&dt_svcdone, UNIT_DIS, 0) } - }; - -#define DT_TIMER (DT_NUMDR) - -REG dt_reg[] = { - { ORDATA (TCST, tcst, 16) }, - { ORDATA (TCCM, tccm, 16) }, - { ORDATA (TCWC, tcwc, 16) }, - { ORDATA (TCBA, tcba, 16) }, - { ORDATA (TCDT, tcdt, 16) }, - { FLDATA (INT, IREQ (DTA), INT_V_DTA) }, - { FLDATA (ERR, tccm, CSR_V_ERR) }, - { FLDATA (DONE, tccm, CSR_V_DONE) }, - { FLDATA (IE, tccm, CSR_V_DONE) }, - { DRDATA (CTIME, dt_ctime, 31), REG_NZ }, - { DRDATA (LTIME, dt_ltime, 31), REG_NZ }, - { DRDATA (DCTIME, dt_dctime, 31), REG_NZ }, - { ORDATA (SUBSTATE, dt_substate, 1) }, - { DRDATA (LBLK, dt_logblk, 12), REG_HIDDEN }, - { URDATA (POS, dt_unit[0].pos, 10, T_ADDR_W, 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) }, - { FLDATA (STOP_OFFR, dt_stopoffr, 0) }, - { ORDATA (DEVADDR, dt_dib.ba, 32), REG_HRO }, - { ORDATA (DEVVEC, dt_dib.vec, 16), REG_HRO }, - { NULL } - }; - -MTAB dt_mod[] = { - { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, - { UNIT_8FMT + UNIT_11FMT, 0, "18b", NULL, NULL }, - { UNIT_8FMT + UNIT_11FMT, UNIT_8FMT, "12b", NULL, NULL }, - { UNIT_8FMT + UNIT_11FMT, UNIT_11FMT, "16b", NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", - &set_vec, &show_vec, NULL }, - { 0 } - }; - -DEBTAB dt_deb[] = { - { "MOTION", LOG_MS }, - { "DATA", LOG_RW }, - { "BLOCK", LOG_BL }, - { NULL, 0 } - }; - -DEVICE dt_dev = { - "TC", dt_unit, dt_reg, dt_mod, - DT_NUMDR + 1, 8, 24, 1, 8, 18, - NULL, NULL, &dt_reset, - &dt_boot, &dt_attach, &dt_detach, - &dt_dib, DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG, 0, - dt_deb, NULL, NULL - }; - -/* IO dispatch routines, I/O addresses 17777340 - 17777350 - - Read hardware notes: - - - While the TCCM error bit is a real flop, it is supposed to reflect - the OR of the TCST error bits at all time, so it is updated on read. - - A read of TCDT while the function is RALL clears DONE. -*/ - -t_stat dt_rd (int32 *data, int32 PA, int32 access) -{ -int32 j, unum, mot, fnc; - -j = (PA >> 1) & 017; /* get reg offset */ -unum = CSR_GETUNIT (tccm); /* get drive */ -switch (j) { - - case 000: /* TCST */ - mot = DTS_GETMOT (dt_unit[unum].STATE); /* get motion */ - if (mot >= DTS_ATSF) /* set/clr speed */ - tcst = tcst | STA_UPS; - else tcst = tcst & ~STA_UPS; - *data = tcst; - break; - - case 001: /* TCCM */ - if (tcst & STA_ALLERR) /* set/clr error */ - tccm = tccm | CSR_ERR; - else tccm = tccm & ~CSR_ERR; - *data = tccm; - break; - - case 002: /* TCWC */ - *data = tcwc; - break; - - case 003: /* TCBA */ - *data = tcba; - break; - - case 004: /* TCDT */ - fnc = DTS_GETFNC (dt_unit[unum].STATE); /* get function */ - if (fnc == FNC_RALL) { /* read all? */ - DT_CLRDONE; /* clear done */ - } - *data = tcdt; - break; - } - -return SCPE_OK; -} - -/* Write hardware notes: - - - The TC11 behaves much more like a traditional DECtape controller - than a typical PDP11 peripheral. In particular, execution is - initiated/controlled by any write to TCCM, rather than setting - the GO (DO) bit. Unless the function is STOP or STOP ALL, writing - TCCM will put the selected tape in motion. - - Writing GO (DO) clears DONE (READY) and the error flops in TCST. - - Writing a 0 to ERROR clears the error flops in TCST. Because it - is write 0 to clear (later controllers used write 1 to clear), - the simulator has to know whether ERROR is actually written. - - STOP ALL ignores select errors. Every other function is rejected - if there is a select error. - - An illegal operation (setting ILO) will stop the selected tape. - - A write of TCDT while the function is RALL, WALL, or WTMK clears - DONE (READY). RALL should not be included, but it saved a gate - not to prevent it. - - Because DONE (READY) may not be clear when an operation completes - and DONE (READY) is set, the DT_SETDONE must test for DONE (READY) - not being already set. -*/ - -t_stat dt_wr (int32 data, int32 PA, int32 access) -{ -int32 i, j, unum, old_tccm, fnc; -UNIT *uptr; - -j = (PA >> 1) & 017; /* get reg offset */ -switch (j) { - - case 000: /* TCST */ - if ((access == WRITEB) && (PA & 1)) - break; - tcst = (tcst & ~STA_RW) | (data & STA_RW); - break; - - case 001: /* TCCM */ - old_tccm = tccm; /* save prior */ - if (access == WRITEB) - data = (PA & 1)? ((tccm & 0377) | (data << 8)): ((tccm & ~0377) | data); - if ((data & CSR_IE) == 0) /* clearing IE? */ - CLR_INT (DTA); /* clear intr */ - else if (((tccm & (CSR_DONE|CSR_IE)) == CSR_DONE) && /* set IE, DON'IE = DON? */ - ((data & CSR_GO) == 0)) /* and not setting GO? */ - SET_INT (DTA); /* set intr */ - tccm = (tccm & ~CSR_RW) | (data & CSR_RW); /* merge data */ - if ((data & CSR_GO) != 0) { /* GO (DO) set? */ - tcst = tcst & ~STA_ALLERR; /* clear errors */ - tccm = tccm & ~(CSR_ERR|CSR_DONE); /* clear done, err flops */ - } - else if (((data & CSR_ERR) == 0) && /* error bit clear? */ - ((access != WRITEB) || ((PA & 1) != 0))) { /* not write low byte? */ - tcst = tcst & ~STA_ALLERR; /* clear errors */ - tccm = tccm & ~CSR_ERR; /* clear err flop */ - } - if (((old_tccm ^ tccm) & CSR_UNIT) != 0) /* unit change? */ - dt_deselect (old_tccm); /* deselect all */ - unum = CSR_GETUNIT (tccm); /* get drive */ - fnc = CSR_GETFNC (tccm); /* get function */ - if (fnc == FNC_STOP) { /* stop all? */ - sim_activate (&dt_dev.units[DT_TIMER], dt_ctime); /* sched done */ - for (i = 0; i < DT_NUMDR; i++) /* loop thru units */ - dt_stopunit (dt_dev.units + i); /* stop unit */ - break; - } - uptr = dt_dev.units + unum; - if (uptr->flags & UNIT_DIS) /* disabled? */ - dt_seterr (uptr, STA_SEL); /* select err */ - if ((fnc == FNC_WMRK) || /* write mark? */ - ((fnc == FNC_WALL) && (uptr->flags & UNIT_WPRT)) || - ((fnc == FNC_WRIT) && (uptr->flags & UNIT_WPRT))) - dt_seterr (uptr, STA_ILO); /* illegal op */ - if ((tccm & CSR_ERR) != 0) { /* error? */ - dt_stopunit (uptr); /* stop the unit */ - DT_SETDONE; /* set done at once */ - } - else dt_newsa (tccm); /* new function */ - break; - - case 002: /* TCWC */ - tcwc = data; /* word write only! */ - break; - - case 003: /* TCBA */ - tcba = data; /* word write only! */ - break; - - case 004: /* TCDT */ - unum = CSR_GETUNIT (tccm); /* get drive */ - fnc = DTS_GETFNC (dt_unit[unum].STATE); /* get function */ - if (fnc == FNC_WALL) { /* write all? */ - DT_CLRDONE; /* clear done */ - } - tcdt = data; /* word write only! */ - break; - } - -return SCPE_OK; -} - -/* Unit deselect */ - -void dt_deselect (int32 oldf) -{ -int32 old_unit = CSR_GETUNIT (oldf); -UNIT *uptr = dt_dev.units + old_unit; -int32 old_mot = DTS_GETMOT (uptr->STATE); - -if (old_mot >= DTS_ATSF) /* at speed? */ - dt_newfnc (uptr, DTS_STA (old_mot, DTS_OFR)); -else if (old_mot >= DTS_ACCF) /* accelerating? */ - DTS_SET2ND (DTS_ATSF | (old_mot & DTS_DIR), DTS_OFR); -return; -} - -/* New operation - - 1. If function = stop - - if not already stopped or decelerating, schedule deceleration - - schedule command completion - 2. If change in direction, - - if not decelerating, schedule deceleration - - set accelerating (other dir) as next state - - set function as next next state - 3. If not accelerating or at speed, - - schedule acceleration - - set function as next state - 4. If not yet at speed, - - set function as next state - 5. If at speed, - - set function as current state, schedule function -*/ - -void dt_newsa (int32 newf) -{ -int32 new_unit, prev_mot, new_fnc; -int32 prev_dir, new_dir; -UNIT *uptr; - -new_unit = CSR_GETUNIT (newf); /* new, old units */ -uptr = dt_dev.units + new_unit; -if ((uptr->flags & UNIT_ATT) == 0) { /* new unit attached? */ - dt_seterr (uptr, STA_SEL); /* no, error */ - return; - } -prev_mot = DTS_GETMOT (uptr->STATE); /* previous motion */ -prev_dir = prev_mot & DTS_DIR; /* previous dir */ -new_fnc = CSR_GETFNC (newf); /* new function */ -new_dir = (newf & CSR_DIR) != 0; /* new di? */ - -if (new_fnc == FNC_SSEL) { /* stop unit? */ - sim_activate (&dt_dev.units[DT_TIMER], dt_ctime); /* sched done */ - dt_stopunit (uptr); /* stop unit */ - return; - } - -if (prev_mot == DTS_STOP) { /* start? */ - if (dt_setpos (uptr)) /* update pos */ - return; - sim_cancel (uptr); /* stop current */ - sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* sched accel */ - DTS_SETSTA (DTS_ACCF | new_dir, 0); /* state = accel */ - DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */ - return; - } - -if (prev_dir ^ new_dir) { /* dir chg? */ - dt_stopunit (uptr); /* stop unit */ - DTS_SET2ND (DTS_ACCF | new_dir, 0); /* next = accel */ - DTS_SET3RD (DTS_ATSF | new_dir, new_fnc); /* next next = fnc */ - return; - } - -if (prev_mot < DTS_ACCF) { /* not accel/at speed? */ - if (dt_setpos (uptr)) /* update pos */ - return; - sim_cancel (uptr); /* cancel cur */ - sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* sched accel */ - DTS_SETSTA (DTS_ACCF | new_dir, 0); /* state = accel */ - DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */ - return; - } - -if (prev_mot < DTS_ATSF) { /* not at speed? */ - DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */ - return; - } - -dt_newfnc (uptr, DTS_STA (DTS_ATSF | new_dir, new_fnc));/* state = fnc */ -return; -} - -/* Schedule new DECtape function - - This routine is only called if - - the selected unit is attached - - the selected unit is at speed (forward or backward) - - This routine - - updates the selected unit's position - - updates the selected unit's state - - schedules the new operation -*/ - -void dt_newfnc (UNIT *uptr, int32 newsta) -{ -int32 fnc, dir, blk, unum, relpos, newpos; -uint32 oldpos; - -oldpos = uptr->pos; /* save old pos */ -if (dt_setpos (uptr)) /* update pos */ - return; -uptr->STATE = newsta; /* update state */ -fnc = DTS_GETFNC (uptr->STATE); /* set variables */ -dir = DTS_GETMOT (uptr->STATE) & DTS_DIR; -unum = (int32) (uptr - dt_dev.units); -if (oldpos == uptr->pos) - uptr->pos = uptr->pos + (dir? -1: 1); -blk = DT_LIN2BL (uptr->pos, uptr); - -if (dir? DT_QREZ (uptr): DT_QFEZ (uptr)) { /* wrong ez? */ - dt_seterr (uptr, STA_END); /* set ez flag, stop */ - return; - } -dt_substate = 0; /* substate = normal */ -sim_cancel (uptr); /* cancel cur op */ -switch (fnc) { /* case function */ - - case DTS_OFR: /* off reel */ - if (dir) /* rev? < start */ - newpos = -1000; - else newpos = DTU_FWDEZ (uptr) + DT_EZLIN + 1000; /* fwd? > end */ - break; - - case FNC_SRCH: /* search */ - if (dir) - newpos = DT_BLK2LN ((DT_QFEZ (uptr)? DTU_TSIZE (uptr): blk), uptr) - - DT_BLKLN - DT_WSIZE; - else newpos = DT_BLK2LN ((DT_QREZ (uptr)? 0: blk + 1), uptr) + - DT_BLKLN + (DT_WSIZE - 1); - if (DEBUG_PRI (dt_dev, LOG_MS)) - fprintf (sim_deb, ">>DT%d: searching %s\n", unum, - (dir? "backward": "forward")); - break; - - case FNC_WRIT: /* write */ - case FNC_READ: /* read */ - if (DT_QEZ (uptr)) { /* in "ok" end zone? */ - if (dir) - newpos = DTU_FWDEZ (uptr) - DT_HTLIN - DT_WSIZE; - else newpos = DT_EZLIN + DT_HTLIN + (DT_WSIZE - 1); - break; - } - relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ - if ((relpos >= DT_HTLIN) && /* in data zone? */ - (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { - dt_seterr (uptr, STA_BLKM); - return; - } - if (dir) - newpos = DT_BLK2LN (((relpos >= (DTU_LPERB (uptr) - DT_HTLIN))? blk + 1: blk), uptr) - - DT_HTLIN - DT_WSIZE; - else newpos = DT_BLK2LN (((relpos < DT_HTLIN)? blk: blk + 1), uptr) + - DT_HTLIN + (DT_WSIZE - 1); - if (DEBUG_PRI (dt_dev, LOG_RW) || - (DEBUG_PRI (dt_dev, LOG_BL) && (blk == dt_logblk))) - fprintf (sim_deb, ">>DT%d: %s block %d %s\n", - unum, ((fnc == FNC_READ)? "read": "write"), - blk, (dir? "backward": "forward")); - break; - - case FNC_RALL: /* read all */ - case FNC_WALL: /* write all */ - if (DT_QEZ (uptr)) { /* in "ok" end zone? */ - if (dir) - newpos = DTU_FWDEZ (uptr) - DT_WSIZE; - else newpos = DT_EZLIN + (DT_WSIZE - 1); - } - else { - relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ - if (dir? (relpos < (DTU_LPERB (uptr) - DT_CSMLN)): /* switch in time? */ - (relpos >= DT_CSMLN)) { - dt_seterr (uptr, STA_BLKM); - return; - } - if (dir) - newpos = DT_BLK2LN (blk + 1, uptr) - DT_CSMLN - DT_WSIZE; - else newpos = DT_BLK2LN (blk, uptr) + DT_CSMLN + (DT_WSIZE - 1); - } - if (fnc == FNC_WALL) sim_activate /* write all? */ - (&dt_dev.units[DT_TIMER], dt_ctime); /* sched done */ - if (DEBUG_PRI (dt_dev, LOG_RW) || - (DEBUG_PRI (dt_dev, LOG_BL) && (blk == dt_logblk))) - fprintf (sim_deb, ">>DT%d: read all block %d %s\n", - unum, blk, (dir? "backward": "forward")); - break; - - default: - dt_seterr (uptr, STA_SEL); /* bad state */ - return; - } - -sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime); -return; -} - -/* Update DECtape position - - DECtape motion is modeled as a constant velocity, with linear - acceleration and deceleration. The motion equations are as follows: - - t = time since operation started - tmax = time for operation (accel, decel only) - v = at speed velocity in lines (= 1/dt_ltime) - - Then: - at speed dist = t * v - accel dist = (t^2 * v) / (2 * tmax) - decel dist = (((2 * t * tmax) - t^2) * v) / (2 * tmax) - - This routine uses the relative (integer) time, rather than the absolute - (floating point) time, to allow save and restore of the start times. -*/ - -t_bool dt_setpos (UNIT *uptr) -{ -uint32 new_time, ut, ulin, udelt; -int32 mot = DTS_GETMOT (uptr->STATE); -int32 unum, delta = 0; - -new_time = sim_grtime (); /* current time */ -ut = new_time - uptr->LASTT; /* elapsed time */ -if (ut == 0) /* no time gone? exit */ - return FALSE; -uptr->LASTT = new_time; /* update last time */ -switch (mot & ~DTS_DIR) { /* case on motion */ - - case DTS_STOP: /* stop */ - delta = 0; - break; - - case DTS_DECF: /* slowing */ - ulin = ut / (uint32) dt_ltime; - udelt = dt_dctime / dt_ltime; - delta = ((ulin * udelt * 2) - (ulin * ulin)) / (2 * udelt); - break; - - case DTS_ACCF: /* accelerating */ - ulin = ut / (uint32) dt_ltime; - udelt = (dt_dctime - (dt_dctime >> 2)) / dt_ltime; - delta = (ulin * ulin) / (2 * udelt); - break; - - case DTS_ATSF: /* at speed */ - delta = ut / (uint32) dt_ltime; - break; - } - -if (mot & DTS_DIR) /* update pos */ - uptr->pos = uptr->pos - delta; -else uptr->pos = uptr->pos + delta; -if (((int32) uptr->pos < 0) || - ((int32) uptr->pos > (DTU_FWDEZ (uptr) + DT_EZLIN))) { - detach_unit (uptr); /* off reel? */ - uptr->STATE = uptr->pos = 0; - unum = (int32) (uptr - dt_dev.units); - if ((unum == CSR_GETUNIT (tccm)) && (CSR_GETFNC (tccm) != FNC_STOP)) - dt_seterr (uptr, STA_SEL); /* error */ - return TRUE; - } -return FALSE; -} - -/* Command timer service after stop - set done */ - -t_stat dt_svcdone (UNIT *uptr) -{ -DT_SETDONE; -return SCPE_OK; -} - -/* Unit service - - Unit must be attached, detach cancels operation -*/ - -t_stat dt_svc (UNIT *uptr) -{ -int32 mot = DTS_GETMOT (uptr->STATE); -int32 dir = mot & DTS_DIR; -int32 fnc = DTS_GETFNC (uptr->STATE); -int32 *fbuf = (int32 *) uptr->filebuf; -int32 blk, wrd, relpos, dat; -uint32 ba, ma; -uint16 wbuf; - -/* Motion cases - - Decelerating - if next state != stopped, must be accel reverse - Accelerating - next state must be @speed, schedule function - At speed - do functional processing -*/ - -switch (mot) { - - case DTS_DECF: case DTS_DECR: /* decelerating */ - if (dt_setpos (uptr)) /* upd pos; off reel? */ - return IORETURN (dt_stopoffr, STOP_DTOFF); - uptr->STATE = DTS_NXTSTA (uptr->STATE); /* advance state */ - if (uptr->STATE) /* not stopped? */ - sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* reversing */ - return SCPE_OK; - - case DTS_ACCF: case DTS_ACCR: /* accelerating */ - dt_newfnc (uptr, DTS_NXTSTA (uptr->STATE)); /* adv state, sched */ - return SCPE_OK; - - case DTS_ATSF: case DTS_ATSR: /* at speed */ - break; /* check function */ - - default: /* other */ - dt_seterr (uptr, STA_SEL); /* state error */ - return SCPE_OK; - } - -/* Functional cases - - Search - transfer block number, schedule next block - Off reel - detach unit (it must be deselected) -*/ - -if (dt_setpos (uptr)) /* upd pos; off reel? */ - return IORETURN (dt_stopoffr, STOP_DTOFF); -if (DT_QEZ (uptr)) { /* in end zone? */ - dt_seterr (uptr, STA_END); /* end zone error */ - return SCPE_OK; - } -blk = DT_LIN2BL (uptr->pos, uptr); /* get block # */ - -switch (fnc) { /* at speed, check fnc */ - - case FNC_SRCH: /* search */ - tcdt = blk; /* set block # */ - dt_schedez (uptr, dir); /* sched end zone */ - DT_SETDONE; /* set done */ - break; - - case DTS_OFR: /* off reel */ - detach_unit (uptr); /* must be deselected */ - uptr->STATE = uptr->pos = 0; /* no visible action */ - break; - -/* Read - - If wc ovf has not occurred, inc ma, wc and copy word from tape to memory - If wc ovf, set flag - If not end of block, schedule next word - If end of block and not wc ovf, schedule next block - If end of block and wc ovf, set done, schedule end zone -*/ - - case FNC_READ: /* read */ - wrd = DT_LIN2WD (uptr->pos, uptr); /* get word # */ - if (!dt_substate) { /* !wc ovf? */ - ma = (CSR_GETMEX (tccm) << 16) | tcba; /* form 18b addr */ - ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */ - tcdt = wbuf = fbuf[ba] & DMASK; /* read word */ - tcst = (tcst & ~STA_M_XD) | ((fbuf[ma] >> 16) & STA_M_XD); - if (Map_WriteW (ma, 2, &wbuf)) { /* store, nxm? */ - dt_seterr (uptr, STA_NXM); - break; - } - tcwc = (tcwc + 1) & DMASK; /* incr MA, WC */ - tcba = (tcba + 2) & DMASK; - if (tcba <= 1) - tccm = CSR_INCMEX (tccm); - if (tcwc == 0) - dt_substate = 1; - } - if (wrd != (dir? 0: DTU_BSIZE (uptr) - 1)) /* not end blk? */ - sim_activate (uptr, DT_WSIZE * dt_ltime); - else if (dt_substate) { /* wc ovf? */ - dt_schedez (uptr, dir); /* sched end zone */ - DT_SETDONE; /* set done */ - } - else sim_activate (uptr, ((2 * DT_HTLIN) + DT_WSIZE) * dt_ltime); - break; - -/* Write - - If wc ovf has not occurred, inc ma, wc - Copy word from memory (or 0, to fill block) to tape - If wc ovf, set flag - If not end of block, schedule next word - If end of block and not wc ovf, schedule next block - If end of block and wc ovf, set done, schedule end zone -*/ - - case FNC_WRIT: /* write */ - wrd = DT_LIN2WD (uptr->pos, uptr); /* get word # */ - if (dt_substate) /* wc ovf? fill */ - tcdt = 0; - else { - ma = (CSR_GETMEX (tccm) << 16) | tcba; /* form 18b addr */ - if (Map_ReadW (ma, 2, &wbuf)) { /* fetch word */ - dt_seterr (uptr, STA_NXM); - break; - } - tcdt = wbuf; /* get word */ - tcwc = (tcwc + 1) & DMASK; /* incr MA, WC */ - tcba = (tcba + 2) & DMASK; - if (tcba <= 1) - tccm = CSR_INCMEX (tccm); - } - ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */ - fbuf[ba] = tcdt; /* write word */ - if (ba >= uptr->hwmark) - uptr->hwmark = ba + 1; - if (tcwc == 0) - dt_substate = 1; - if (wrd != (dir? 0: DTU_BSIZE (uptr) - 1)) /* not end blk? */ - sim_activate (uptr, DT_WSIZE * dt_ltime); - else if (dt_substate) { /* wc ovf? */ - dt_schedez (uptr, dir); /* sched end zone */ - DT_SETDONE; - } - else sim_activate (uptr, ((2 * DT_HTLIN) + DT_WSIZE) * dt_ltime); - break; - -/* Read all - read current header or data word */ - - case FNC_RALL: - if (tccm & CSR_DONE) { /* done set? */ - dt_seterr (uptr, STA_DATM); /* data miss */ - break; - } - relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ - if ((relpos >= DT_HTLIN) && /* in data zone? */ - (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { - wrd = DT_LIN2WD (uptr->pos, uptr); - ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */ - dat = fbuf[ba]; /* get tape word */ - } - else dat = dt_gethdr (uptr, blk, relpos); /* get hdr */ - if (dir) /* rev? comp obv */ - dat = dt_comobv (dat); - tcdt = dat & DMASK; /* low 16b */ - tcst = (tcst & ~STA_M_XD) | ((dat >> 16) & STA_M_XD); - sim_activate (uptr, DT_WSIZE * dt_ltime); - DT_SETDONE; /* set done */ - break; - -/* Write all - write current header or data word */ - - case FNC_WALL: - if (tccm & CSR_DONE) { /* done set? */ - dt_seterr (uptr, STA_DATM); /* data miss */ - break; - } - relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ - if ((relpos >= DT_HTLIN) && /* in data zone? */ - (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { - wrd = DT_LIN2WD (uptr->pos, uptr); - dat = (STA_GETXD (tcst) << 16) | tcdt; /* get data word */ - if (dir) /* rev? comp obv */ - dat = dt_comobv (dat); - ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */ - fbuf[ba] = dat; /* write word */ - if (ba >= uptr->hwmark) - uptr->hwmark = ba + 1; - } -/* else *//* ignore hdr */ - sim_activate (uptr, DT_WSIZE * dt_ltime); - DT_SETDONE; /* set done */ - break; - - default: - dt_seterr (uptr, STA_SEL); /* impossible state */ - break; - } -return SCPE_OK; -} - -/* Utility routines */ - -/* Set error flag - Done must be deferred to allow time for interrupt setup (RSTS V4) -*/ - -void dt_seterr (UNIT *uptr, int32 e) -{ -int32 mot = DTS_GETMOT (uptr->STATE); - -tcst = tcst | e; /* set error flag */ -tccm = tccm | CSR_ERR; -if (!(tccm & CSR_DONE)) { /* not done? */ - sim_activate (&dt_dev.units[DT_TIMER], dt_ctime); /* sched done */ - } -if (mot >= DTS_ACCF) { /* ~stopped or stopping? */ - sim_cancel (uptr); /* cancel activity */ - if (dt_setpos (uptr)) /* update position */ - return; - sim_activate (uptr, dt_dctime); /* sched decel */ - DTS_SETSTA (DTS_DECF | (mot & DTS_DIR), 0); /* state = decel */ - } -else DTS_SETSTA (mot, 0); /* clear 2nd, 3rd */ -return; -} - -/* Stop unit */ - -void dt_stopunit (UNIT *uptr) -{ -int32 mot = DTS_GETMOT (uptr->STATE); -int32 dir = mot & DTS_DIR; - -if (mot == DTS_STOP) return; /* already stopped? */ -if ((mot & ~DTS_DIR) != DTS_DECF) { /* !already stopping? */ - if (dt_setpos (uptr)) /* update pos */ - return; - sim_cancel (uptr); /* stop current */ - sim_activate (uptr, dt_dctime); /* schedule decel */ - } -DTS_SETSTA (DTS_DECF | dir, 0); /* state = decel */ -return; -} - -/* Schedule end zone */ - -void dt_schedez (UNIT *uptr, int32 dir) -{ -int32 newpos; - -if (dir) /* rev? rev ez */ - newpos = DT_EZLIN - DT_WSIZE; -else newpos = DTU_FWDEZ (uptr) + DT_WSIZE; /* fwd? fwd ez */ -sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime); -return; -} - -/* Complement obverse routine (18b) */ - -int32 dt_comobv (int32 dat) -{ -dat = dat ^ 0777777; /* compl obverse */ -dat = ((dat >> 15) & 07) | ((dat >> 9) & 070) | - ((dat >> 3) & 0700) | ((dat & 0700) << 3) | - ((dat & 070) << 9) | ((dat & 07) << 15); -return dat; -} - -/* Checksum routine */ - -int32 dt_csum (UNIT *uptr, int32 blk) -{ -int32 *fbuf = (int32 *) uptr->filebuf; -int32 ba = blk * DTU_BSIZE (uptr); -int32 i, csum, wrd; - -csum = 077; /* init csum */ -for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */ - wrd = fbuf[ba + i] ^ 0777777; /* get ~word */ - csum = csum ^ (wrd >> 12) ^ (wrd >> 6) ^ wrd; - } -return (csum & 077); -} - -/* Get header word (18b) */ - -int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos) -{ -int32 wrd = relpos / DT_WSIZE; - -if (wrd == DT_BLKWD) /* fwd blknum */ - return blk; -if (wrd == DT_CSMWD) /* rev csum */ - return 077; -if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_CSMWD - 1)) /* fwd csum */ - return (dt_csum (uptr, blk) << 12); -if (wrd == (2 * DT_HTWRD + DTU_BSIZE (uptr) - DT_BLKWD - 1)) /* rev blkno */ - return dt_comobv (blk); -return 0; /* all others */ -} - -/* Reset routine */ - -t_stat dt_reset (DEVICE *dptr) -{ -int32 i, prev_mot; -UNIT *uptr; - -for (i = 0; i < DT_NUMDR; i++) { /* stop all activity */ - uptr = dt_dev.units + i; - if (sim_is_running) { /* RESET? */ - prev_mot = DTS_GETMOT (uptr->STATE); /* get motion */ - if ((prev_mot & ~DTS_DIR) > DTS_DECF) { /* accel or spd? */ - if (dt_setpos (uptr)) /* update pos */ - continue; - sim_cancel (uptr); - sim_activate (uptr, dt_dctime); /* sched decel */ - DTS_SETSTA (DTS_DECF | (prev_mot & DTS_DIR), 0); - } - } - else { - sim_cancel (uptr); /* sim reset */ - uptr->STATE = 0; - uptr->LASTT = sim_grtime (); - } - } -tcst = tcwc = tcba = tcdt = 0; /* clear reg */ -tccm = CSR_DONE; -CLR_INT (DTA); /* clear int req */ -return SCPE_OK; -} - -/* Device bootstrap */ - -#define BOOT_START 02000 /* start */ -#define BOOT_ENTRY (BOOT_START + 002) /* entry */ -#define BOOT_UNIT (BOOT_START + 010) /* unit number */ -#define BOOT_CSR (BOOT_START + 020) /* CSR */ -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) - -static const uint16 boot_rom[] = { - 0042124, /* "TD" */ - 0012706, BOOT_START, /* MOV #boot_start, SP */ - 0012700, 0000000, /* MOV #unit, R0 ; unit number */ - 0010003, /* MOV R0, R3 */ - 0000303, /* SWAB R3 */ - 0012701, 0177342, /* MOV #TCCM, R1 ; csr */ - 0012702, 0004003, /* RW: MOV #4003, R2 ; rev+rnum+go */ - 0050302, /* BIS R3, R2 */ - 0010211, /* MOV R2, (R1) ; load csr */ - 0032711, 0100200, /* BIT #100200, (R1) ; wait */ - 0001775, /* BEQ .-4 */ - 0100370, /* BPL RW ; no err, cont */ - 0005761, 0177776, /* TST -2(R1) ; end zone? */ - 0100036, /* BPL ER ; no, err */ - 0012702, 0000003, /* MOV #3, R2 ; rnum+go */ - 0050302, /* BIS R3, R2 */ - 0010211, /* MOV R2, (R1) ; load csr */ - 0032711, 0100200, /* BIT #100200, (R1) ; wait */ - 0001775, /* BEQ .-4 */ - 0100426, /* BMI ER ; err, die */ - 0005761, 0000006, /* TST 6(R1) ; blk 0? */ - 0001023, /* BNE ER ; no, die */ - 0012761, 0177000, 0000002, /* MOV #-256.*2, 2(R1) ; load wc */ - 0005061, 0000004, /* CLR 4(R1) ; clear ba */ - 0012702, 0000005, /* MOV #READ+GO, R2 ; read & go */ - 0050302, /* BIS R3, R2 */ - 0010211, /* MOV R2, (R1) ; load csr */ - 0005002, /* CLR R2 */ - 0005003, /* CLR R3 */ - 0012704, BOOT_START+020, /* MOV #START+20, R4 */ - 0005005, /* CLR R5 */ - 0032711, 0100200, /* BIT #100200, (R1) ; wait */ - 0001775, /* BEQ .-4 */ - 0100401, /* BMI ER ; err, die */ - 0005007, /* CLR PC */ - 0012711, 0000001, /* ER: MOV #1, (R1) ; stop all */ - 0000000 /* HALT */ - }; - -t_stat dt_boot (int32 unitno, DEVICE *dptr) -{ -size_t i; - -dt_unit[unitno].pos = DT_EZLIN; -for (i = 0; i < BOOT_LEN; i++) - M[(BOOT_START >> 1) + i] = boot_rom[i]; -M[BOOT_UNIT >> 1] = unitno & DT_M_NUMDR; -M[BOOT_CSR >> 1] = (dt_dib.ba & DMASK) + 02; -cpu_set_boot (BOOT_ENTRY); -return SCPE_OK; -} - -/* Attach routine - - Determine 12b, 16b, or 18b/36b format - Allocate buffer - If 12b, read 12b format and convert to 18b in buffer - If 16b, read 16b format and convert to 18b in buffer - If 18b/36b, read data into buffer -*/ - -t_stat dt_attach (UNIT *uptr, char *cptr) -{ -uint16 pdp8b[D8_NBSIZE]; -uint16 pdp11b[D18_BSIZE]; -uint32 ba, sz, k, *fbuf; -int32 u = uptr - dt_dev.units; -t_stat r; - -r = attach_unit (uptr, cptr); /* attach */ -if (r != SCPE_OK) /* fail? */ - return r; -if ((sim_switches & SIM_SW_REST) == 0) { /* not from rest? */ - uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT; /* default 16b */ - if (sim_switches & SWMASK ('T')) /* att 12b? */ - uptr->flags = (uptr->flags | UNIT_8FMT) & ~UNIT_11FMT; - else if (sim_switches & SWMASK ('F')) /* att 18b? */ - uptr->flags = uptr->flags & ~(UNIT_8FMT | UNIT_11FMT); - else if (!(sim_switches & SWMASK ('A')) && /* autosize? */ - ((sz = sim_fsize (uptr->fileref)) > D16_FILSIZ)) { - if (sz <= D8_FILSIZ) - uptr->flags = (uptr->flags | UNIT_8FMT) & ~UNIT_11FMT; - else uptr->flags = uptr->flags & ~(UNIT_8FMT | UNIT_11FMT); - } - } -uptr->capac = DTU_CAPAC (uptr); /* set capacity */ -uptr->filebuf = calloc (uptr->capac, sizeof (uint32)); -if (uptr->filebuf == NULL) { /* can't alloc? */ - detach_unit (uptr); - return SCPE_MEM; - } -fbuf = (uint32 *) uptr->filebuf; /* file buffer */ -sim_printf ("%s%d: ", sim_dname (&dt_dev), u); -if (uptr->flags & UNIT_8FMT) - sim_printf ("12b format"); -else if (uptr->flags & UNIT_11FMT) - sim_printf ("16b format"); -else sim_printf ("18b/36b format"); -sim_printf (", buffering file in memory\n"); -if (uptr->flags & UNIT_8FMT) { /* 12b? */ - for (ba = 0; ba < uptr->capac; ) { /* loop thru file */ - k = fxread (pdp8b, sizeof (int16), D8_NBSIZE, uptr->fileref); - if (k == 0) - break; - for ( ; k < D8_NBSIZE; k++) - pdp8b[k] = 0; - for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop thru blk */ - fbuf[ba] = ((uint32) (pdp8b[k] & 07777) << 6) | - ((uint32) (pdp8b[k + 1] >> 6) & 077); - fbuf[ba + 1] = ((uint32) (pdp8b[k + 1] & 077) << 12) | - ((uint32) pdp8b[k + 2] & 07777); - ba = ba + 2; - } /* end blk loop */ - } /* end file loop */ - uptr->hwmark = ba; - } /* end if */ -else if (uptr->flags & UNIT_11FMT) { /* 16b? */ - for (ba = 0; ba < uptr->capac; ) { /* loop thru file */ - k = fxread (pdp11b, sizeof (uint16), D18_BSIZE, uptr->fileref); - if (k == 0) - break; - for ( ; k < D18_BSIZE; k++) - pdp11b[k] = 0; - for (k = 0; k < D18_BSIZE; k++) - fbuf[ba++] = pdp11b[k]; - } - uptr->hwmark = ba; - } /* end elif */ -else uptr->hwmark = fxread (uptr->filebuf, sizeof (uint32), - uptr->capac, uptr->fileref); -uptr->flags = uptr->flags | UNIT_BUF; /* set buf flag */ -uptr->pos = DT_EZLIN; /* beyond leader */ -uptr->LASTT = sim_grtime (); /* last pos update */ -return SCPE_OK; -} - -/* Detach routine - - Cancel in progress operation - If 12b, convert 18b buffer to 12b and write to file - If 16b, convert 18b buffer to 16b and write to file - If 18b/36b, write buffer to file - Deallocate buffer -*/ - -t_stat dt_detach (UNIT* uptr) -{ -uint16 pdp8b[D8_NBSIZE]; -uint16 pdp11b[D18_BSIZE]; -uint32 ba, k, *fbuf; -int32 u = uptr - dt_dev.units; - -if (!(uptr->flags & UNIT_ATT)) - return SCPE_OK; -if (sim_is_active (uptr)) { /* active? cancel op */ - sim_cancel (uptr); - if ((u == CSR_GETUNIT (tccm)) && ((tccm & CSR_DONE) == 0)) { - tcst = tcst | STA_SEL; - tccm = tccm | CSR_ERR | CSR_DONE; - if (tccm & CSR_IE) - SET_INT (DTA); - } - uptr->STATE = uptr->pos = 0; - } -fbuf = (uint32 *) uptr->filebuf; /* file buffer */ -if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { /* any data? */ - sim_printf ("%s%d: writing buffer to file\n", sim_dname (&dt_dev), u); - rewind (uptr->fileref); /* start of file */ - if (uptr->flags & UNIT_8FMT) { /* 12b? */ - for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */ - for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop blk */ - pdp8b[k] = (fbuf[ba] >> 6) & 07777; - pdp8b[k + 1] = ((fbuf[ba] & 077) << 6) | - ((fbuf[ba + 1] >> 12) & 077); - pdp8b[k + 2] = fbuf[ba + 1] & 07777; - ba = ba + 2; - } /* end loop blk */ - fxwrite (pdp8b, sizeof (uint16), D8_NBSIZE, uptr->fileref); - if (ferror (uptr->fileref)) - break; - } /* end loop file */ - } /* end if 12b */ - else if (uptr->flags & UNIT_11FMT) { /* 16b? */ - for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */ - for (k = 0; k < D18_BSIZE; k++) /* loop blk */ - pdp11b[k] = fbuf[ba++] & DMASK; - fxwrite (pdp11b, sizeof (uint16), D18_BSIZE, uptr->fileref); - if (ferror (uptr->fileref)) - break; - } /* end loop file */ - } /* end if 16b */ - else fxwrite (uptr->filebuf, sizeof (uint32), /* write file */ - uptr->hwmark, uptr->fileref); - if (ferror (uptr->fileref)) perror ("I/O error"); - } /* end if hwmark */ -free (uptr->filebuf); /* release buf */ -uptr->flags = uptr->flags & ~UNIT_BUF; /* clear buf flag */ -uptr->filebuf = NULL; /* clear buf ptr */ -uptr->flags = (uptr->flags | UNIT_11FMT) & ~UNIT_8FMT; /* default fmt */ -uptr->capac = DT_CAPAC; /* default size */ -return detach_unit (uptr); -} diff --git a/PDP11/pdp11_tm.c b/PDP11/pdp11_tm.c deleted file mode 100644 index a0d85ad5..00000000 --- a/PDP11/pdp11_tm.c +++ /dev/null @@ -1,728 +0,0 @@ -/* pdp11_tm.c: PDP-11 magnetic tape simulator - - Copyright (c) 1993-2013, 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. - - tm TM11/TU10 magtape - - 23-Oct-13 RMS Revised for new boot setup routine - 16-Feb-06 RMS Added tape capacity checking - 31-Oct-05 RMS Fixed address width for large files - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 07-Jul-05 RMS Removed extraneous externs - 18-Mar-05 RMS Added attached test to detach routine - 07-Dec-04 RMS Added read-only file support - 30-Sep-04 RMS Revised Unibus interface - 25-Jan-04 RMS Revised for device debug support - 29-Dec-03 RMS Added 18b Qbus support - 25-Apr-03 RMS Revised for extended file support - 28-Mar-03 RMS Added multiformat support - 28-Feb-03 RMS Revised for magtape library, added logging - 30-Oct-02 RMS Revised BOT handling, added error record handling - 30-Sep-02 RMS Added variable address support to bootstrap - Added vector change/display support - Changed mapping mnemonics - New data structures - Updated error handling - 28-Aug-02 RMS Added end of medium support - 30-May-02 RMS Widened POS to 32b - 22-Apr-02 RMS Fixed max record length, first block bootstrap - (Jonathan Engdahl) - 26-Jan-02 RMS Revised bootstrap to conform to M9312 - 06-Jan-02 RMS Revised enable/disable support - 30-Nov-01 RMS Added read only unit, extended SET/SHOW support - 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 (Thord Nilson) - 07-Sep-01 RMS Revised device disable and interrupt mechanisms - 26-Apr-01 RMS Added device enable/disable support - 18-Apr-01 RMS Changed to rewind tape before boot - 14-Apr-99 RMS Changed t_addr to unsigned - 04-Oct-98 RMS V2.4 magtape format - 10-May-98 RMS Fixed bug with non-zero unit operation (Steven Schultz) - 09-May-98 RMS Fixed problems in bootstrap (Steven Schultz) - 10-Apr-98 RMS Added 2nd block bootstrap (John Holden) - 31-Jul-97 RMS Added bootstrap (Ethan Dicks) - 22-Jan-97 RMS V2.3 magtape format - 18-Jan-97 RMS Fixed double interrupt, error flag bugs - 29-Jun-96 RMS Added unit disable support - - Magnetic tapes are represented as a series of variable 8b records - of the form: - - 32b record length in bytes - exact number - byte 0 - byte 1 - : - byte n-2 - byte n-1 - 32b record length in bytes - exact number - - 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. -*/ - -#include "pdp11_defs.h" -#include "sim_tape.h" - -#define TM_NUMDR 8 /* #drives */ -#define USTAT u3 /* unit status */ - -/* Command - tm_cmd */ - -#define MTC_ERR (1 << CSR_V_ERR) /* error */ -#define MTC_V_DEN 13 /* density */ -#define MTC_M_DEN 03 -#define MTC_DEN (MTC_M_DEN << MTC_V_DEN) -#define MTC_INIT 0010000 /* init */ -#define MTC_LPAR 0004000 /* parity select */ -#define MTC_V_UNIT 8 /* unit */ -#define MTC_M_UNIT 07 -#define MTC_UNIT (MTC_M_UNIT << MTC_V_UNIT) -#define MTC_DONE (1 << CSR_V_DONE) /* done */ -#define MTC_IE (1 << CSR_V_IE) /* interrupt enable */ -#define MTC_V_EMA 4 /* ext mem address */ -#define MTC_M_EMA 03 -#define MTC_EMA (MTC_M_EMA << MTC_V_EMA) -#define MTC_V_FNC 1 /* function */ -#define MTC_M_FNC 07 -#define MTC_UNLOAD 00 -#define MTC_READ 01 -#define MTC_WRITE 02 -#define MTC_WREOF 03 -#define MTC_SPACEF 04 -#define MTC_SPACER 05 -#define MTC_WREXT 06 -#define MTC_REWIND 07 -#define MTC_FNC (MTC_M_FNC << MTC_V_FNC) -#define MTC_GO (1 << CSR_V_GO) /* go */ -#define MTC_RW (MTC_DEN | MTC_LPAR | MTC_UNIT | MTC_IE | \ - MTC_EMA | MTC_FNC) -#define GET_EMA(x) (((x) & MTC_EMA) << (16 - MTC_V_EMA)) -#define GET_UNIT(x) (((x) >> MTC_V_UNIT) & MTC_M_UNIT) -#define GET_FNC(x) (((x) >> MTC_V_FNC) & MTC_M_FNC) - -/* Status - stored in tm_sta or (*) uptr->USTAT or (+) calculated */ - -#define STA_ILL 0100000 /* illegal */ -#define STA_EOF 0040000 /* *end of file */ -#define STA_CRC 0020000 /* CRC error */ -#define STA_PAR 0010000 /* parity error */ -#define STA_DLT 0004000 /* data late */ -#define STA_EOT 0002000 /* +end of tape */ -#define STA_RLE 0001000 /* rec lnt error */ -#define STA_BAD 0000400 /* bad tape error */ -#define STA_NXM 0000200 /* non-existent mem */ -#define STA_ONL 0000100 /* *online */ -#define STA_BOT 0000040 /* *start of tape */ -#define STA_7TK 0000020 /* 7 track */ -#define STA_SDN 0000010 /* settle down */ -#define STA_WLK 0000004 /* *write locked */ -#define STA_REW 0000002 /* *rewinding */ -#define STA_TUR 0000001 /* +unit ready */ - -#define STA_CLR (STA_7TK | STA_SDN) /* always clear */ -#define STA_DYN (STA_EOF | STA_EOT | STA_ONL | STA_BOT | \ - STA_WLK | STA_REW | STA_TUR) /* dynamic */ -#define STA_EFLGS (STA_ILL | STA_EOF | STA_CRC | STA_PAR | \ - STA_DLT | STA_EOT | STA_RLE | STA_BAD | STA_NXM) - /* set error */ - -/* Read lines - tm_rdl */ - -#define RDL_CLK 0100000 /* 10 Khz clock */ - -extern uint16 *M; /* memory */ -extern int32 int_req[IPL_HLVL]; - -uint8 *tmxb = NULL; /* xfer buffer */ -int32 tm_sta = 0; /* status register */ -int32 tm_cmd = 0; /* command register */ -int32 tm_ca = 0; /* current address */ -int32 tm_bc = 0; /* byte count */ -int32 tm_db = 0; /* data buffer */ -int32 tm_rdl = 0; /* read lines */ -int32 tm_time = 10; /* record latency */ -int32 tm_stopioe = 1; /* stop on error */ - -t_stat tm_rd (int32 *data, int32 PA, int32 access); -t_stat tm_wr (int32 data, int32 PA, int32 access); -t_stat tm_svc (UNIT *uptr); -t_stat tm_reset (DEVICE *dptr); -t_stat tm_attach (UNIT *uptr, char *cptr); -t_stat tm_detach (UNIT *uptr); -t_stat tm_boot (int32 unitno, DEVICE *dptr); -void tm_go (UNIT *uptr); -int32 tm_updcsta (UNIT *uptr); -void tm_set_done (void); -t_stat tm_map_err (UNIT *uptr, t_stat st); -t_stat tm_vlock (UNIT *uptr, int32 val, char *cptr, void *desc); - -/* MT data structures - - tm_dev MT device descriptor - tm_unit MT unit list - tm_reg MT register list - tm_mod MT modifier list -*/ - -DIB tm_dib = { - IOBA_TM, IOLN_TM, &tm_rd, &tm_wr, - 1, IVCL (TM), VEC_TM, { NULL } - }; - -UNIT tm_unit[] = { - { UDATA (&tm_svc, UNIT_ATTABLE + UNIT_ROABLE +UNIT_DISABLE, 0) }, - { UDATA (&tm_svc, UNIT_ATTABLE + UNIT_ROABLE +UNIT_DISABLE, 0) }, - { UDATA (&tm_svc, UNIT_ATTABLE + UNIT_ROABLE +UNIT_DISABLE, 0) }, - { UDATA (&tm_svc, UNIT_ATTABLE + UNIT_ROABLE +UNIT_DISABLE, 0) }, - { UDATA (&tm_svc, UNIT_ATTABLE + UNIT_ROABLE +UNIT_DISABLE, 0) }, - { UDATA (&tm_svc, UNIT_ATTABLE + UNIT_ROABLE +UNIT_DISABLE, 0) }, - { UDATA (&tm_svc, UNIT_ATTABLE + UNIT_ROABLE +UNIT_DISABLE, 0) }, - { UDATA (&tm_svc, UNIT_ATTABLE + UNIT_ROABLE +UNIT_DISABLE, 0) } - }; - -REG tm_reg[] = { - { ORDATA (MTS, tm_sta, 16) }, - { ORDATA (MTC, tm_cmd, 16) }, - { ORDATA (MTBRC, tm_bc, 16) }, - { ORDATA (MTCMA, tm_ca, 16) }, - { ORDATA (MTD, tm_db, 8) }, - { ORDATA (MTRD, tm_rdl, 16) }, - { FLDATA (INT, IREQ (TM), INT_V_TM) }, - { FLDATA (ERR, tm_cmd, CSR_V_ERR) }, - { FLDATA (DONE, tm_cmd, CSR_V_DONE) }, - { FLDATA (IE, tm_cmd, CSR_V_IE) }, - { FLDATA (STOP_IOE, tm_stopioe, 0) }, - { DRDATA (TIME, tm_time, 24), PV_LEFT }, - { URDATA (UST, tm_unit[0].USTAT, 8, 16, 0, TM_NUMDR, 0) }, - { URDATA (POS, tm_unit[0].pos, 10, T_ADDR_W, 0, - TM_NUMDR, PV_LEFT | REG_RO) }, - { ORDATA (DEVADDR, tm_dib.ba, 32), REG_HRO }, - { ORDATA (DEVVEC, tm_dib.vec, 16), REG_HRO }, - { NULL } - }; - -MTAB tm_mod[] = { - { MTUF_WLK, 0, "write enabled", "WRITEENABLED", &tm_vlock }, - { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", &tm_vlock }, - { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT", - &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, - { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", "CAPACITY", - &sim_tape_set_capac, &sim_tape_show_capac, NULL }, - { MTAB_XTD|MTAB_VDV, 020, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", - &set_vec, &show_vec, NULL }, - { 0 } - }; - -DEVICE tm_dev = { - "TM", tm_unit, tm_reg, tm_mod, - TM_NUMDR, 10, T_ADDR_W, 1, 8, 8, - NULL, NULL, &tm_reset, - &tm_boot, &tm_attach, &tm_detach, - &tm_dib, DEV_DISABLE | DEV_UBUS | DEV_Q18 | DEV_DEBUG - }; - -/* I/O dispatch routines, I/O addresses 17772520 - 17772532 - - 17772520 MTS read only, constructed from tm_sta - plus current drive status flags - 17772522 MTC read/write - 17772524 MTBRC read/write - 17772526 MTCMA read/write - 17772530 MTD read/write - 17772532 MTRD read only -*/ - -t_stat tm_rd (int32 *data, int32 PA, int32 access) -{ -UNIT *uptr; - -uptr = tm_dev.units + GET_UNIT (tm_cmd); /* get unit */ -switch ((PA >> 1) & 07) { /* decode PA<3:1> */ - - case 0: /* MTS */ - *data = tm_updcsta (uptr); /* update status */ - break; - - case 1: /* MTC */ - tm_updcsta (uptr); /* update status */ - *data = tm_cmd; /* return command */ - break; - - case 2: /* MTBRC */ - *data = tm_bc; /* return byte count */ - break; - - case 3: /* MTCMA */ - *data = tm_ca; /* return mem addr */ - break; - - case 4: /* MTD */ - *data = tm_db; /* return data buffer */ - break; - - case 5: /* MTRD */ - tm_rdl = tm_rdl ^ RDL_CLK; /* "clock" ticks */ - *data = tm_rdl; - break; - - default: /* unimplemented */ - *data = 0; - break; - } - -return SCPE_OK; -} - -t_stat tm_wr (int32 data, int32 PA, int32 access) -{ -UNIT *uptr; - -switch ((PA >> 1) & 07) { /* decode PA<3:1> */ - - case 0: /* MTS: read only */ - break; - - case 1: /* MTC */ - uptr = tm_dev.units + GET_UNIT (tm_cmd); /* select unit */ - if ((tm_cmd & MTC_DONE) == 0) - tm_sta = tm_sta | STA_ILL; - else { - if (access == WRITEB) data = (PA & 1)? - (tm_cmd & 0377) | (data << 8): - (tm_cmd & ~0377) | data; - if (data & MTC_INIT) { /* init? */ - tm_reset (&tm_dev); /* reset device */ - return SCPE_OK; - } - if ((data & MTC_IE) == 0) /* int disable? */ - CLR_INT (TM); /* clr int request */ - else if ((tm_cmd & (MTC_ERR + MTC_DONE)) && !(tm_cmd & MTC_IE)) - SET_INT (TM); /* set int request */ - tm_cmd = (tm_cmd & ~MTC_RW) | (data & MTC_RW); - uptr = tm_dev.units + GET_UNIT (tm_cmd); /* new unit */ - if (data & MTC_GO) /* new function? */ - tm_go (uptr); - } - tm_updcsta (uptr); /* update status */ - break; - - case 2: /* MTBRC */ - if (access == WRITEB) - data = (PA & 1)? (tm_bc & 0377) | (data << 8): (tm_bc & ~0377) | data; - tm_bc = data; - break; - - case 3: /* MTCMA */ - if (access == WRITEB) - data = (PA & 1)? (tm_ca & 0377) | (data << 8): (tm_ca & ~0377) | data; - tm_ca = data; - break; - - case 4: /* MTD */ - if ((access == WRITEB) && (PA & 1)) - return SCPE_OK; - tm_db = data & 0377; - break; - } /* end switch */ - -return SCPE_OK; -} - -/* New magtape command */ - -void tm_go (UNIT *uptr) -{ -int32 f; - -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)) && - sim_tape_wrp (uptr))) { /* write locked? */ - tm_sta = tm_sta | STA_ILL; /* illegal */ - tm_set_done (); /* set done */ - return; - } -uptr->USTAT = uptr->USTAT & (STA_WLK | STA_ONL); /* clear status */ -tm_sta = 0; /* clear errors */ -if (f == MTC_UNLOAD) { /* unload? */ - uptr->USTAT = (uptr->USTAT | STA_REW) & ~STA_ONL; - detach_unit (uptr); /* set offline */ - } -else if (f == MTC_REWIND) /* rewind */ - uptr->USTAT = uptr->USTAT | STA_REW; /* rewinding */ -/* else *//* uncomment this else if rewind/unload don't set done */ -tm_cmd = tm_cmd & ~MTC_DONE; /* clear done */ -CLR_INT (TM); /* clear int */ -sim_activate (uptr, tm_time); /* start io */ -return; -} - -/* Unit service - - If rewind done, reposition to start of tape, set status - else, do operation, set done, interrupt -*/ - -t_stat tm_svc (UNIT *uptr) -{ -int32 f, t, u; -uint32 xma; -t_mtrlnt tbc, cbc; -t_stat st, r = SCPE_OK; - -u = (int32) (uptr - tm_dev.units); /* get unit number */ -f = GET_FNC (tm_cmd); /* get command */ -xma = GET_EMA (tm_cmd) | tm_ca; /* get mem addr */ -cbc = 0200000 - tm_bc; /* get bc */ - -if (uptr->USTAT & STA_REW) { /* rewind? */ - sim_tape_rewind (uptr); /* update position */ - if (uptr->flags & UNIT_ATT) /* still on line? */ - uptr->USTAT = STA_ONL | STA_BOT | (sim_tape_wrp (uptr)? STA_WLK: 0); - else uptr->USTAT = 0; - if (u == GET_UNIT (tm_cmd)) { /* selected? */ - tm_set_done (); /* set done */ - tm_updcsta (uptr); /* update status */ - } - return SCPE_OK; - } - -if ((uptr->flags & UNIT_ATT) == 0) { /* if not attached */ - uptr->USTAT = 0; /* unit off line */ - tm_sta = tm_sta | STA_ILL; /* illegal operation */ - tm_set_done (); /* set done */ - tm_updcsta (uptr); /* update status */ - return IORETURN (tm_stopioe, SCPE_UNATT); - } - -if (DEBUG_PRS (tm_dev)) - fprintf (sim_deb, ">>TM: op=%o, ma=%o, bc=%o, pos=%d\n", - f, xma, tm_bc, uptr->pos); -switch (f) { /* case on function */ - - case MTC_READ: /* read */ - st = sim_tape_rdrecf (uptr, tmxb, &tbc, MT_MAXFR); /* read rec */ - if (st == MTSE_RECE) /* rec in error? */ - tm_sta = tm_sta | STA_PAR; - else if (st != MTSE_OK) { /* other error? */ - r = tm_map_err (uptr, st); /* map error */ - break; - } - if (tbc > cbc) /* wrong size? */ - tm_sta = tm_sta | STA_RLE; - if (tbc < cbc) /* use smaller */ - cbc = tbc; - if ((t = Map_WriteB (xma, cbc, tmxb))) { /* 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 */ - break; - - case MTC_WRITE: /* write */ - case MTC_WREXT: /* write ext gap */ - if ((t = Map_ReadB (xma, cbc, tmxb))) { /* copy mem to buf */ - tm_sta = tm_sta | STA_NXM; /* NXM, set err */ - cbc = cbc - t; /* adj byte cnt */ - if (cbc == 0) /* no xfr? done */ - break; - } - if ((st = sim_tape_wrrecf (uptr, tmxb, cbc))) /* write rec, err? */ - r = tm_map_err (uptr, st); /* map error */ - else { - xma = (xma + cbc) & 0777777; /* inc bus addr */ - tm_bc = (tm_bc + cbc) & 0177777; /* inc byte cnt */ - } - break; - - case MTC_WREOF: /* write eof */ - if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ - r = tm_map_err (uptr, st); /* map error */ - break; - - case MTC_SPACEF: /* space forward */ - do { - tm_bc = (tm_bc + 1) & 0177777; /* incr wc */ - if ((st = sim_tape_sprecf (uptr, &tbc))) { /* spc rec fwd, err? */ - r = tm_map_err (uptr, st); /* map error */ - break; - } - } while (tm_bc != 0); - break; - - case MTC_SPACER: /* space reverse */ - do { - tm_bc = (tm_bc + 1) & 0177777; /* incr wc */ - if ((st = sim_tape_sprecr (uptr, &tbc))) { /* spc rec rev, err? */ - r = tm_map_err (uptr, st); /* map error */ - break; - } - } while (tm_bc != 0); - break; - } /* end case */ - -tm_cmd = (tm_cmd & ~MTC_EMA) | ((xma >> (16 - MTC_V_EMA)) & MTC_EMA); -tm_ca = xma & 0177777; /* update mem addr */ -tm_set_done (); /* set done */ -tm_updcsta (uptr); /* update status */ -if (DEBUG_PRS (tm_dev)) - fprintf (sim_deb, ">>TM: sta=%o, ma=%o, bc=%o, pos=%d\n", - tm_sta, tm_ca, tm_bc, uptr->pos); -return r; -} - -/* Update controller status */ - -int32 tm_updcsta (UNIT *uptr) -{ -tm_sta = (tm_sta & ~(STA_DYN | STA_CLR)) | (uptr->USTAT & STA_DYN); -if (sim_tape_eot (uptr)) - tm_sta = tm_sta | STA_EOT; -if (sim_is_active (uptr)) - tm_sta = tm_sta & ~STA_TUR; -else tm_sta = tm_sta | STA_TUR; -if (tm_sta & STA_EFLGS) - tm_cmd = tm_cmd | MTC_ERR; -else tm_cmd = tm_cmd & ~MTC_ERR; -if ((tm_cmd & MTC_IE) == 0) - CLR_INT (TM); -return tm_sta; -} - -/* Set done */ - -void tm_set_done (void) -{ -tm_cmd = tm_cmd | MTC_DONE; -if (tm_cmd & MTC_IE) - SET_INT (TM); -return; -} - -/* Map tape error status */ - -t_stat tm_map_err (UNIT *uptr, t_stat st) -{ -switch (st) { - - case MTSE_FMT: /* illegal fmt */ - case MTSE_UNATT: /* not attached */ - tm_sta = tm_sta | STA_ILL; - case MTSE_OK: /* no error */ - return SCPE_IERR; - - case MTSE_TMK: /* tape mark */ - uptr->USTAT = uptr->USTAT | STA_EOF; /* end of file */ - break; - - case MTSE_IOERR: /* IO error */ - tm_sta = tm_sta | STA_PAR; /* parity error */ - if (tm_stopioe) - return SCPE_IOERR; - break; - - case MTSE_INVRL: /* invalid rec lnt */ - tm_sta = tm_sta | STA_PAR; /* parity error */ - return SCPE_MTRLNT; - - case MTSE_RECE: /* record in error */ - tm_sta = tm_sta | STA_PAR; /* parity error */ - break; - - case MTSE_EOM: /* end of medium */ - tm_sta = tm_sta | STA_BAD; /* bad tape */ - break; - - case MTSE_BOT: /* reverse into BOT */ - uptr->USTAT = uptr->USTAT | STA_BOT; /* set status */ - break; - - case MTSE_WRP: /* write protect */ - tm_sta = tm_sta | STA_ILL; /* illegal operation */ - break; - } - -return SCPE_OK; -} - -/* Reset routine */ - -t_stat tm_reset (DEVICE *dptr) -{ -int32 u; -UNIT *uptr; - -tm_cmd = MTC_DONE; /* set done */ -tm_bc = tm_ca = tm_db = tm_sta = tm_rdl = 0; -CLR_INT (TM); /* clear interrupt */ -for (u = 0; u < TM_NUMDR; u++) { /* loop thru units */ - uptr = tm_dev.units + u; - sim_tape_reset (uptr); /* reset tape */ - sim_cancel (uptr); /* cancel activity */ - if (uptr->flags & UNIT_ATT) - uptr->USTAT = STA_ONL | (sim_tape_bot (uptr)? STA_BOT: 0) | - (sim_tape_wrp (uptr)? STA_WLK: 0); - else uptr->USTAT = 0; - } -if (tmxb == NULL) - tmxb = (uint8 *) calloc (MT_MAXFR, sizeof (uint8)); -if (tmxb == NULL) - return SCPE_MEM; -return SCPE_OK; -} - -/* Attach routine */ - -t_stat tm_attach (UNIT *uptr, char *cptr) -{ -t_stat r; -int32 u = uptr - tm_dev.units; - -r = sim_tape_attach (uptr, cptr); -if (r != SCPE_OK) - return r; -uptr->USTAT = STA_ONL | STA_BOT | (sim_tape_wrp (uptr)? STA_WLK: 0); -if (u == GET_UNIT (tm_cmd)) - tm_updcsta (uptr); -return r; -} - -/* Detach routine */ - -t_stat tm_detach (UNIT* uptr) -{ -int32 u = uptr - tm_dev.units; - -if (!(uptr->flags & UNIT_ATT)) - return SCPE_OK; -if (!sim_is_active (uptr)) - uptr->USTAT = 0; -if (u == GET_UNIT (tm_cmd)) - tm_updcsta (uptr); -return sim_tape_detach (uptr); -} - -/* Write lock/enable routine */ - -t_stat tm_vlock (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 u = uptr - tm_dev.units; - -if ((uptr->flags & UNIT_ATT) && - (val || sim_tape_wrp (uptr))) - uptr->USTAT = uptr->USTAT | STA_WLK; -else uptr->USTAT = uptr->USTAT & ~STA_WLK; -if (u == GET_UNIT (tm_cmd)) - tm_updcsta (uptr); -return SCPE_OK; -} - -/* Device bootstrap - - Magtape boot format changed over time. Originally, a boot tape - contained a boot loader in the first block. Eventually, the first - block was reserved for a tape label, and the second block was - expected to contain a boot loader. BSD and DEC operating systems - use the second block scheme, so it is the default. - - To boot from the first block, use boot -o (old). -*/ - -#define BOOT_START 016000 -#define BOOT_ENTRY (BOOT_START + 2) -#define BOOT_UNIT (BOOT_START + 010) -#define BOOT_CSR (BOOT_START + 014) -#define BOOT1_LEN (sizeof (boot1_rom) / sizeof (int16)) -#define BOOT2_LEN (sizeof (boot2_rom) / sizeof (int16)) - -static const uint16 boot1_rom[] = { - 0046524, /* boot_start: "TM" */ - 0012706, BOOT_START, /* mov #boot_start, sp */ - 0012700, 0000000, /* mov #unit_num, r0 */ - 0012701, 0172526, /* mov #172526, r1 ; mtcma */ - 0005011, /* clr (r1) */ - 0010141, /* mov r1, -(r1) ; mtbrc */ - 0010002, /* mov r0,r2 */ - 0000302, /* swab r2 */ - 0062702, 0060003, /* add #60003, r2 */ - 0010241, /* mov r2, -(r1) ; read + go */ - 0105711, /* tstb (r1) ; mtc */ - 0100376, /* bpl .-2 */ - 0005002, /* clr r2 */ - 0005003, /* clr r3 */ - 0012704, BOOT_START+020, /* mov #boot_start+20, r4 */ - 0005005, /* clr r5 */ - 0005007 /* clr r7 */ - }; - -static const uint16 boot2_rom[] = { - 0046524, /* boot_start: "TM" */ - 0012706, BOOT_START, /* mov #boot_start, sp */ - 0012700, 0000000, /* mov #unit_num, r0 */ - 0012701, 0172526, /* mov #172526, r1 ; mtcma */ - 0005011, /* clr (r1) */ - 0012741, 0177777, /* mov #-1, -(r1) ; mtbrc */ - 0010002, /* mov r0,r2 */ - 0000302, /* swab r2 */ - 0062702, 0060011, /* add #60011, r2 */ - 0010241, /* mov r2, -(r1) ; space + go */ - 0105711, /* tstb (r1) ; mtc */ - 0100376, /* bpl .-2 */ - 0010002, /* mov r0,r2 */ - 0000302, /* swab r2 */ - 0062702, 0060003, /* add #60003, r2 */ - 0010211, /* mov r2, (r1) ; read + go */ - 0105711, /* tstb (r1) ; mtc */ - 0100376, /* bpl .-2 */ - 0005002, /* clr r2 */ - 0005003, /* clr r3 */ - 0012704, BOOT_START+020, /* mov #boot_start+20, r4 */ - 0005005, /* clr r5 */ - 0005007 /* clr r7 */ - }; - -t_stat tm_boot (int32 unitno, DEVICE *dptr) -{ -size_t i; - -sim_tape_rewind (&tm_unit[unitno]); -if (sim_switches & SWMASK ('O')) { - for (i = 0; i < BOOT1_LEN; i++) - M[(BOOT_START >> 1) + i] = boot1_rom[i]; - } -else { - for (i = 0; i < BOOT2_LEN; i++) - M[(BOOT_START >> 1) + i] = boot2_rom[i]; - } -M[BOOT_UNIT >> 1] = (uint16)unitno; -M[BOOT_CSR >> 1] = (tm_dib.ba & DMASK) + 06; -cpu_set_boot (BOOT_ENTRY); -return SCPE_OK; -} diff --git a/PDP11/pdp11_tq.c b/PDP11/pdp11_tq.c deleted file mode 100644 index 251ad27b..00000000 --- a/PDP11/pdp11_tq.c +++ /dev/null @@ -1,2326 +0,0 @@ -/* pdp11_tq.c: TMSCP tape controller simulator - - Copyright (c) 2002-2018, Robert M Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - tq TQK50 tape controller - - 28-May-18 RMS Changed to avoid nested comment warnings (Mark Pizzolato) - 23-Oct-13 RMS Revised for new boot setup routine - 17-Mar-13 RMS Fixed bug in ABORT link walk loop (Dave Bryan) - 17-Aug-11 RMS Added CAPACITY modifier - 14-Jan-11 MP Various fixes discovered while exploring Ultrix issue: - - Set UNIT_SXC flag when a tape mark is encountered - during forward motion read operations - - Fixed logic which clears UNIT_SXC to check command - modifier - - Added CMF_WR flag to tq_cmf entry for OP_WTM - - Made non-immediate rewind positioning operations - take 2 seconds - - Added UNIT_IDLE flag to tq units - - Fixed debug output of tape file positions when they - are 64b - - Added more debug output after positioning operations. - - Added textual display of the command being performed - 23-Dec-10 RMS Fixed comments about register addresses - 18-Jun-07 RMS Added UNIT_IDLE flag to timer thread - 16-Feb-06 RMS Revised for new magtape capacity checking - 31-Oct-05 RMS Fixed address width for large files - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 22-Jul-05 RMS Fixed warning from Solaris C (Doug Gwyn) - 30-Sep-04 RMS Revised Unibus interface - 12-Jun-04 RMS Fixed bug in reporting write protect (Lyle Bickley) - 18-Apr-04 RMS Fixed TQK70 media ID and model byte (Robert Schaffrath) - 26-Mar-04 RMS Fixed warnings with -std=c99 - 25-Jan-04 RMS Revised for device debug support - 19-May-03 RMS Revised for new conditional compilation scheme - 25-Apr-03 RMS Revised for extended file support - 28-Mar-03 RMS Added multiformat support - 28-Feb-03 RMS Added variable controller, user-defined drive support - 26-Feb-03 RMS Fixed bug in vector calculation for VAXen - 22-Feb-03 RMS Fixed ordering bug in queue process - Fixed flags table to allow MD_CSE everywhere - 09-Jan-03 RMS Fixed bug in transfer end packet status - 17-Oct-02 RMS Fixed bug in read reverse (Hans Pufal) -*/ - -#if defined (VM_PDP10) /* PDP10 version */ -#error "TQK50 not supported on PDP-10!" - -#elif defined (VM_VAX) /* VAX version */ -#include "vax_defs.h" -#if (UNIBUS) -#define INIT_TYPE TQ8_TYPE -#define INIT_CAP TQ8_CAP -#else -#define INIT_TYPE TQ5_TYPE -#define INIT_CAP TQ5_CAP -#endif - -#else /* PDP-11 version */ -#include "pdp11_defs.h" -#define INIT_TYPE TQ5_TYPE -#define INIT_CAP TQ5_CAP -extern uint32 cpu_opt; -#endif - -#include "pdp11_uqssp.h" -#include "pdp11_mscp.h" -#include "sim_tape.h" - -#define UF_MSK (UF_SCH|UF_VSS|UF_CMR|UF_CMW) /* settable flags */ - -#define TQ_SH_MAX 24 /* max display wds */ -#define TQ_SH_PPL 8 /* wds per line */ -#define TQ_SH_DPL 4 /* desc per line */ -#define TQ_SH_RI 001 /* show rings */ -#define TQ_SH_FR 002 /* show free q */ -#define TQ_SH_RS 004 /* show resp q */ -#define TQ_SH_UN 010 /* show unit q's */ -#define TQ_SH_ALL 017 /* show all */ - -#define TQ_CLASS 1 /* TQK50 class */ -#define TQ_DHTMO 0 /* def host timeout */ -#define TQ_DCTMO 120 /* def ctrl timeout */ -#define TQ_NUMDR 4 /* # drives */ -#define TQ_MAXFR (1 << 16) /* max xfer */ - -#define UNIT_V_ONL (MTUF_V_UF + 0) /* online */ -#define UNIT_V_ATP (MTUF_V_UF + 1) /* attn pending */ -#define UNIT_V_SXC (MTUF_V_UF + 2) /* serious exc */ -#define UNIT_V_POL (MTUF_V_UF + 3) /* position lost */ -#define UNIT_V_TMK (MTUF_V_UF + 4) /* tape mark seen */ -#define UNIT_ONL (1 << UNIT_V_ONL) -#define UNIT_ATP (1 << UNIT_V_ATP) -#define UNIT_SXC (1 << UNIT_V_SXC) -#define UNIT_POL (1 << UNIT_V_POL) -#define UNIT_TMK (1 << UNIT_V_TMK) -#define cpkt u3 /* current packet */ -#define pktq u4 /* packet queue */ -#define uf buf /* settable unit flags */ -#define objp wait /* object position */ -#define TQ_WPH(u) ((sim_tape_wrp (u))? UF_WPH: 0) - -#define CST_S1 0 /* init stage 1 */ -#define CST_S1_WR 1 /* stage 1 wrap */ -#define CST_S2 2 /* init stage 2 */ -#define CST_S3 3 /* init stage 3 */ -#define CST_S3_PPA 4 /* stage 3 sa wait */ -#define CST_S3_PPB 5 /* stage 3 ip wait */ -#define CST_S4 6 /* stage 4 */ -#define CST_UP 7 /* online */ -#define CST_DEAD 8 /* fatal error */ - -#define tq_comm tq_rq.ba - -#define ERR 0 /* must be SCPE_OK! */ -#define OK 1 - -#define CMF_IMM 0x10000 /* immediate */ -#define CMF_SEQ 0x20000 /* sequential */ -#define CMF_WR 0x40000 /* write */ -#define CMF_RW 0x80000 /* resp to GCS */ - -/* Internal packet management */ - -#define TQ_NPKTS 32 /* # packets (pwr of 2) */ -#define TQ_M_NPKTS (TQ_NPKTS - 1) /* mask */ -#define TQ_PKT_SIZE_W 32 /* payload size (wds) */ -#define TQ_PKT_SIZE (TQ_PKT_SIZE_W * sizeof (int16)) - -struct tqpkt { - int16 link; /* link to next */ - uint16 d[TQ_PKT_SIZE_W]; /* data */ - }; - -/* Packet payload extraction and insertion */ - -#define GETP(p,w,f) ((tq_pkt[p].d[w] >> w##_V_##f) & w##_M_##f) -#define GETP32(p,w) (((uint32) tq_pkt[p].d[w]) | \ - (((uint32) tq_pkt[p].d[(w)+1]) << 16)) -#define PUTP32(p,w,x) tq_pkt[p].d[w] = (x) & 0xFFFF; \ - tq_pkt[p].d[(w)+1] = ((x) >> 16) & 0xFFFF - -/* Controller and device types - TQK50 must be swre rev 5 or later */ - -#define TQ5_TYPE 0 /* TK50 */ -#define TQ5_UQPM 3 /* UQ port ID */ -#define TQ5_CMOD 9 /* ctrl ID */ -#define TQ5_UMOD 3 /* unit ID */ -#define TQ5_MED 0x6D68B032 /* media ID */ -#define TQ5_CREV ((1 << 8) | 5) /* ctrl revs */ -#define TQ5_FREV 0 /* formatter revs */ -#define TQ5_UREV 0 /* unit revs */ -#define TQ5_CAP (94 * (1 << 20)) /* capacity */ -#define TQ5_FMT (TF_CTP|TF_CTP_LO) /* menu */ - -#define TQ7_TYPE 1 /* TK70 */ -#define TQ7_UQPM 14 /* UQ port ID */ -#define TQ7_CMOD 14 /* ctrl ID */ -#define TQ7_UMOD 14 /* unit ID */ -#define TQ7_MED 0x6D68B046 /* media ID */ -#define TQ7_CREV ((1 << 8) | 5) /* ctrl revs */ -#define TQ7_FREV 0 /* formatter revs */ -#define TQ7_UREV 0 /* unit revs */ -#define TQ7_CAP (300 * (1 << 20)) /* capacity */ -#define TQ7_FMT (TF_CTP|TF_CTP_LO) /* menu */ - -#define TQ8_TYPE 2 /* TU81 */ -#define TQ8_UQPM 5 /* UQ port ID */ -#define TQ8_CMOD 5 /* ctrl ID */ -#define TQ8_UMOD 2 /* unit ID */ -#define TQ8_MED 0x6D695051 /* media ID */ -#define TQ8_CREV ((1 << 8) | 5) /* ctrl revs */ -#define TQ8_FREV 0 /* formatter revs */ -#define TQ8_UREV 0 /* unit revs */ -#define TQ8_CAP (180 * (1 << 20)) /* capacity */ -#define TQ8_FMT (TF_9TK|TF_9TK_GRP) /* menu */ - -#define TQU_TYPE 3 /* TKuser defined */ -#define TQU_UQPM 3 /* UQ port ID */ -#define TQU_CMOD 9 /* ctrl ID */ -#define TQU_UMOD 3 /* unit ID */ -#define TQU_MED 0x6D68B032 /* media ID */ -#define TQU_CREV ((1 << 8) | 5) /* ctrl revs */ -#define TQU_FREV 0 /* formatter revs */ -#define TQU_UREV 0 /* unit revs */ -#define TQU_CAP (94 * (1 << 20)) /* capacity */ -#define TQU_FMT (TF_CTP|TF_CTP_LO) /* menu */ -#define TQU_MINC 30 /* min cap MB */ -#define TQU_MAXC 2000 /* max cap MB */ -#define TQU_EMAXC 2000000000 /* ext max cap MB */ - -#define TQ_DRV(d) \ - d##_UQPM, \ - d##_CMOD, d##_MED, d##_FMT, d##_CAP, \ - d##_UMOD, d##_CREV, d##_FREV, d##_UREV - -#define TEST_EOT(u) (sim_tape_eot (u)) - -struct drvtyp { - uint32 uqpm; /* UQ port model */ - uint32 cmod; /* ctrl model */ - uint32 med; /* MSCP media */ - uint32 fmt; /* flags */ - t_addr cap; /* capacity */ - uint32 umod; /* unit model */ - uint32 cver; - uint32 fver; - uint32 uver; - char *name; - }; - -static struct drvtyp drv_tab[] = { - { TQ_DRV (TQ5), "TK50" }, - { TQ_DRV (TQ7), "TK70" }, - { TQ_DRV (TQ8), "TU81" }, - { TQ_DRV (TQU), "TKUSER" }, - }; - -/* Data */ - -extern int32 int_req[IPL_HLVL]; -extern int32 tmr_poll, clk_tps; - -uint8 *tqxb = NULL; /* xfer buffer */ -uint32 tq_sa = 0; /* status, addr */ -uint32 tq_saw = 0; /* written data */ -uint32 tq_s1dat = 0; /* S1 data */ -uint32 tq_csta = 0; /* ctrl state */ -uint32 tq_perr = 0; /* last error */ -uint32 tq_cflgs = 0; /* ctrl flags */ -uint32 tq_prgi = 0; /* purge int */ -uint32 tq_pip = 0; /* poll in progress */ -struct uq_ring tq_cq = { 0 }; /* cmd ring */ -struct uq_ring tq_rq = { 0 }; /* rsp ring */ -struct tqpkt tq_pkt[TQ_NPKTS]; /* packet queue */ -int32 tq_freq = 0; /* free list */ -int32 tq_rspq = 0; /* resp list */ -uint32 tq_pbsy = 0; /* #busy pkts */ -uint32 tq_credits = 0; /* credits */ -uint32 tq_hat = 0; /* host timer */ -uint32 tq_htmo = TQ_DHTMO; /* host timeout */ -int32 tq_itime = 200; /* init time, except */ -int32 tq_itime4 = 10; /* stage 4 */ -int32 tq_qtime = 200; /* queue time */ -int32 tq_xtime = 500; /* transfer time */ -int32 tq_rwtime = 2000000; /* rewind time 2 sec (adjusted later) */ -int32 tq_typ = INIT_TYPE; /* device type */ - -/* Command table - legal modifiers (low 16b) and flags (high 16b) */ - -static uint32 tq_cmf[64] = { - 0, /* 0 */ - CMF_IMM, /* abort */ - CMF_IMM|MD_CSE, /* get cmd status */ - CMF_IMM|MD_CSE|MD_NXU, /* get unit status */ - CMF_IMM|MD_CSE, /* set ctrl char */ - 0, 0, 0, /* 5-7 */ - CMF_SEQ|MD_ACL|MD_CDL|MD_CSE|MD_EXA|MD_UNL, /* available */ - CMF_SEQ|MD_CDL|MD_CSE|MD_SWP|MD_EXA, /* online */ - CMF_SEQ|MD_CDL|MD_CSE|MD_SWP|MD_EXA, /* set unit char */ - CMF_IMM, /* define acc paths */ - 0, 0, 0, 0, /* 12-15 */ - CMF_SEQ|CMF_RW|MD_CDL|MD_CSE|MD_REV| /* access */ - MD_SCH|MD_SEC|MD_SER, - 0, /* 17 */ - CMF_SEQ|CMF_WR|MD_CDL|MD_CSE|MD_IMM, /* erase */ - CMF_SEQ|CMF_WR|MD_CDL|MD_CSE, /* flush */ - 0, 0, /* 20-21 */ - CMF_SEQ|CMF_WR|MD_CDL|MD_CSE|MD_IMM, /* erase gap */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 22-31 */ - CMF_SEQ|CMF_RW|MD_CDL|MD_CSE|MD_REV| /* compare */ - MD_SCH|MD_SEC|MD_SER, - CMF_SEQ|CMF_RW|MD_CDL|MD_CSE|MD_REV|MD_CMP| /* read */ - MD_SCH|MD_SEC|MD_SER, - CMF_SEQ|CMF_RW|CMF_WR|MD_CDL|MD_CSE|MD_IMM| /* write */ - MD_CMP|MD_ERW|MD_SEC|MD_SER, - 0, /* 35 */ - CMF_SEQ|CMF_WR|MD_CDL|MD_CSE|MD_IMM, /* wr tape mark */ - CMF_SEQ|MD_CDL|MD_CSE|MD_IMM|MD_OBC| /* reposition */ - MD_REV|MD_RWD|MD_DLE| - MD_SCH|MD_SEC|MD_SER, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 38-47 */ - 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0 - }; - -static char *tq_cmdname[] = { - "", /* 0 */ - "ABO", /* 1 b: abort */ - "GCS", /* 2 b: get command status */ - "GUS", /* 3 b: get unit status */ - "SCC", /* 4 b: set controller char */ - "","","", /* 5-7 */ - "AVL", /* 8 b: available */ - "ONL", /* 9 b: online */ - "SUC", /* 10 b: set unit char */ - "DAP", /* 11 b: det acc paths - nop */ - "","","","", /* 12-15 */ - "ACC", /* 16 b: access */ - "CCD", /* 17 d: compare - nop */ - "ERS", /* 18 b: erase */ - "FLU", /* 19 d: flush - nop */ - "","", /* 20-21 */ - "ERG", /* 22 t: erase gap */ - "","","","","","","","","", /* 23-31 */ - "CMP", /* 32 b: compare */ - "RD", /* 33 b: read */ - "WR", /* 34 b: write */ - "", /* 35 */ - "WTM", /* 36 t: write tape mark */ - "POS", /* 37 t: reposition */ - "","","","","","","","","", /* 38-46 */ - "FMT", /* 47 d: format */ - "","","","","","","","","","","","","","","","", /* 48-63 */ - "AVA", /* 64 b: unit now avail */ - }; - -/* Forward references */ - -DEVICE tq_dev; - -t_stat tq_rd (int32 *data, int32 PA, int32 access); -t_stat tq_wr (int32 data, int32 PA, int32 access); -t_stat tq_inta (void); -t_stat tq_svc (UNIT *uptr); -t_stat tq_tmrsvc (UNIT *uptr); -t_stat tq_quesvc (UNIT *uptr); -t_stat tq_reset (DEVICE *dptr); -t_stat tq_attach (UNIT *uptr, char *cptr); -t_stat tq_detach (UNIT *uptr); -t_stat tq_boot (int32 unitno, DEVICE *dptr); -t_stat tq_set_wlk (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat tq_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat tq_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat tq_show_unitq (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat tq_set_type (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat tq_show_type (FILE *st, UNIT *uptr, int32 val, void *desc); - -t_bool tq_step4 (void); -t_bool tq_mscp (int32 pkt, t_bool q); -t_bool tq_abo (int32 pkt); -t_bool tq_avl (int32 pkt); -t_bool tq_erase (int32 pkt); -t_bool tq_flu (int32 pkt); -t_bool tq_gcs (int32 pkt); -t_bool tq_gus (int32 pkt); -t_bool tq_onl (int32 pkt); -t_bool tq_pos (int32 pkt); -t_bool tq_rw (int32 pkt); -t_bool tq_scc (int32 pkt); -t_bool tq_suc (int32 pkt); -t_bool tq_wtm (int32 pkt); -t_bool tq_plf (uint32 err); -t_bool tq_dte (UNIT *uptr, uint32 err); -t_bool tq_hbe (UNIT *uptr, uint32 ba); -t_bool tq_una (UNIT *uptr); -uint32 tq_map_status (UNIT *uptr, t_stat st); -uint32 tq_spacef (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec); -uint32 tq_skipff (UNIT *uptr, uint32 cnt, uint32 *skipped); -uint32 tq_rdbuff (UNIT *uptr, t_mtrlnt *tbc); -uint32 tq_spacer (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec); -uint32 tq_skipfr (UNIT *uptr, uint32 cnt, uint32 *skipped); -uint32 tq_rdbufr (UNIT *uptr, t_mtrlnt *tbc); -t_bool tq_deqf (int32 *pkt); -int32 tq_deqh (int32 *lh); -void tq_enqh (int32 *lh, int32 pkt); -void tq_enqt (int32 *lh, int32 pkt); -t_bool tq_getpkt (int32 *pkt); -t_bool tq_putpkt (int32 pkt, t_bool qt); -t_bool tq_getdesc (struct uq_ring *ring, uint32 *desc); -t_bool tq_putdesc (struct uq_ring *ring, uint32 desc); -int32 tq_mot_valid (UNIT *uptr, uint32 cmd); -t_stat tq_mot_err (UNIT *uptr, uint32 rsiz); -t_bool tq_mot_end (UNIT *uptr, uint32 flg, uint32 sts, uint32 rsiz); -void tq_putr (int32 pkt, uint32 cmd, uint32 flg, uint32 sts, uint32 lnt, uint32 typ); -void tq_putr_unit (int32 pkt, UNIT *uptr, uint32 lu, t_bool all); -void tq_setf_unit (int32 pkt, UNIT *uptr); -uint32 tq_efl (UNIT *uptr); -void tq_init_int (void); -void tq_ring_int (struct uq_ring *ring); -t_bool tq_fatal (uint32 err); -UNIT *tq_getucb (uint32 lu); - -/* TQ data structures - - tq_dev TQ device descriptor - tq_unit TQ unit list - tq_reg TQ register list - tq_mod TQ modifier list -*/ - -DIB tq_dib = { - IOBA_TQ, IOLN_TQ, &tq_rd, &tq_wr, - 1, IVCL (TQ), 0, { &tq_inta } - }; - -UNIT tq_unit[] = { - { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, INIT_CAP) }, - { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, INIT_CAP) }, - { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, INIT_CAP) }, - { UDATA (&tq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE|UNIT_ROABLE, INIT_CAP) }, - { UDATA (&tq_tmrsvc, UNIT_IDLE|UNIT_DIS, 0) }, - { UDATA (&tq_quesvc, UNIT_IDLE|UNIT_DIS, 0) } - }; - -#define TQ_TIMER (TQ_NUMDR) -#define TQ_QUEUE (TQ_TIMER + 1) - -REG tq_reg[] = { - { GRDATA (SA, tq_sa, DEV_RDX, 16, 0) }, - { GRDATA (SAW, tq_saw, DEV_RDX, 16, 0) }, - { GRDATA (S1DAT, tq_s1dat, DEV_RDX, 16, 0) }, - { GRDATA (CQBA, tq_cq.ba, DEV_RDX, 22, 0) }, - { GRDATA (CQLNT, tq_cq.lnt, DEV_RDX, 8, 2), REG_NZ }, - { GRDATA (CQIDX, tq_cq.idx, DEV_RDX, 8, 2) }, - { GRDATA (TQBA, tq_rq.ba, DEV_RDX, 22, 0) }, - { GRDATA (TQLNT, tq_rq.lnt, DEV_RDX, 8, 2), REG_NZ }, - { GRDATA (TQIDX, tq_rq.idx, DEV_RDX, 8, 2) }, - { DRDATA (FREE, tq_freq, 5) }, - { DRDATA (RESP, tq_rspq, 5) }, - { DRDATA (PBSY, tq_pbsy, 5) }, - { GRDATA (CFLGS, tq_cflgs, DEV_RDX, 16, 0) }, - { GRDATA (CSTA, tq_csta, DEV_RDX, 4, 0) }, - { GRDATA (PERR, tq_perr, DEV_RDX, 9, 0) }, - { DRDATA (CRED, tq_credits, 5) }, - { DRDATA (HAT, tq_hat, 17) }, - { DRDATA (HTMO, tq_htmo, 17) }, - { URDATA (CPKT, tq_unit[0].cpkt, 10, 5, 0, TQ_NUMDR, 0) }, - { URDATA (PKTQ, tq_unit[0].pktq, 10, 5, 0, TQ_NUMDR, 0) }, - { URDATA (UFLG, tq_unit[0].uf, DEV_RDX, 16, 0, TQ_NUMDR, 0) }, - { URDATA (POS, tq_unit[0].pos, 10, T_ADDR_W, 0, TQ_NUMDR, 0) }, - { URDATA (OBJP, tq_unit[0].objp, 10, 32, 0, TQ_NUMDR, 0) }, - { FLDATA (PRGI, tq_prgi, 0), REG_HIDDEN }, - { FLDATA (PIP, tq_pip, 0), REG_HIDDEN }, - { FLDATA (INT, IREQ (TQ), INT_V_TQ) }, - { DRDATA (ITIME, tq_itime, 24), PV_LEFT + REG_NZ }, - { DRDATA (I4TIME, tq_itime4, 24), PV_LEFT + REG_NZ }, - { DRDATA (QTIME, tq_qtime, 24), PV_LEFT + REG_NZ }, - { DRDATA (XTIME, tq_xtime, 24), PV_LEFT + REG_NZ }, - { DRDATA (RWTIME, tq_rwtime, 32), PV_LEFT + REG_NZ }, - { BRDATA (PKTS, tq_pkt, DEV_RDX, 16, TQ_NPKTS * (TQ_PKT_SIZE_W + 1)) }, - { DRDATA (DEVTYPE, tq_typ, 2), REG_HRO }, - { DRDATA (DEVCAP, drv_tab[TQU_TYPE].cap, T_ADDR_W), PV_LEFT | REG_HRO }, - { GRDATA (DEVADDR, tq_dib.ba, DEV_RDX, 32, 0), REG_HRO }, - { GRDATA (DEVVEC, tq_dib.vec, DEV_RDX, 16, 0), REG_HRO }, - { NULL } - }; - -MTAB tq_mod[] = { - { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, - { MTAB_XTD | MTAB_VDV, TQ5_TYPE, NULL, "TK50", - &tq_set_type, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, TQ7_TYPE, NULL, "TK70", - &tq_set_type, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, TQ8_TYPE, NULL, "TU81", - &tq_set_type, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, TQU_TYPE, NULL, "TKUSER", - &tq_set_type, NULL, NULL }, - { MTAB_XTD | MTAB_VDV, 0, "TYPE", NULL, - NULL, &tq_show_type, NULL }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_RI, "RINGS", NULL, - NULL, &tq_show_ctrl, NULL }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_FR, "FREEQ", NULL, - NULL, &tq_show_ctrl, NULL }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_RS, "RESPQ", NULL, - NULL, &tq_show_ctrl, NULL }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_UN, "UNITQ", NULL, - NULL, &tq_show_ctrl, NULL }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, TQ_SH_ALL, "ALL", NULL, - NULL, &tq_show_ctrl, NULL }, - { MTAB_XTD | MTAB_VUN | MTAB_NMO, 0, "UNITQ", NULL, - NULL, &tq_show_unitq, NULL }, - { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT", - &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, - { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", "CAPACITY", - &sim_tape_set_capac, &sim_tape_show_capac, NULL }, -#if defined (VM_PDP11) - { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, NULL }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE", - &set_addr_flt, NULL, NULL }, -#else - { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL, - NULL, &show_addr, NULL }, -#endif - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, - NULL, &show_vec, NULL }, - { 0 } - }; - -DEVICE tq_dev = { - "TQ", tq_unit, tq_reg, tq_mod, - TQ_NUMDR + 2, 10, T_ADDR_W, 1, DEV_RDX, 8, - NULL, NULL, &tq_reset, - &tq_boot, &tq_attach, &tq_detach, - &tq_dib, DEV_DISABLE | DEV_UBUS | DEV_QBUS | DEV_DEBUG - }; - -/* I/O dispatch routines, I/O addresses 17774500 - 17774502 - - 17774500 IP read/write - 17774502 SA read/write -*/ - -t_stat tq_rd (int32 *data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 01) { /* decode PA<1> */ - case 0: /* IP */ - *data = 0; /* reads zero */ - if (tq_csta == CST_S3_PPB) /* waiting for poll? */ - tq_step4 (); - else if (tq_csta == CST_UP) { /* if up */ - tq_pip = 1; /* poll host */ - sim_activate (&tq_unit[TQ_QUEUE], tq_qtime); - } - break; - - case 1: /* SA */ - *data = tq_sa; - break; - } - -return SCPE_OK; -} - -t_stat tq_wr (int32 data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 01) { /* decode PA<1> */ - - case 0: /* IP */ - tq_reset (&tq_dev); /* init device */ - if (DEBUG_PRS (tq_dev)) - fprintf (sim_deb, ">>TQ: initialization started, time=%.0f\n", - sim_gtime ()); - break; - - case 1: /* SA */ - tq_saw = data; - if (tq_csta < CST_S4) /* stages 1-3 */ - sim_activate (&tq_unit[TQ_QUEUE], tq_itime); - else if (tq_csta == CST_S4) /* stage 4 (fast) */ - sim_activate (&tq_unit[TQ_QUEUE], tq_itime4); - break; - } - -return SCPE_OK; -} - -/* Transition to step 4 - init communications region */ - -t_bool tq_step4 (void) -{ -int32 i, lnt; -uint32 base; -uint16 zero[SA_COMM_MAX >> 1]; - -tq_rq.ioff = SA_COMM_RI; /* set intr offset */ -tq_rq.ba = tq_comm; /* set rsp q base */ -tq_rq.lnt = SA_S1H_RQ (tq_s1dat) << 2; /* get resp q len */ -tq_cq.ioff = SA_COMM_CI; /* set intr offset */ -tq_cq.ba = tq_comm + tq_rq.lnt; /* set cmd q base */ -tq_cq.lnt = SA_S1H_CQ (tq_s1dat) << 2; /* get cmd q len */ -tq_cq.idx = tq_rq.idx = 0; /* clear q idx's */ -if (tq_prgi) - base = tq_comm + SA_COMM_QQ; -else base = tq_comm + SA_COMM_CI; -lnt = tq_comm + tq_cq.lnt + tq_rq.lnt - base; /* comm lnt */ -if (lnt > SA_COMM_MAX) /* paranoia */ - lnt = SA_COMM_MAX; -for (i = 0; i < (lnt >> 1); i++) /* clr buffer */ - zero[i] = 0; -if (Map_WriteW (base, lnt, zero)) /* zero comm area */ - return tq_fatal (PE_QWE); /* error? */ -tq_sa = SA_S4 | (drv_tab[tq_typ].uqpm << SA_S4C_V_MOD) |/* send step 4 */ - ((drv_tab[tq_typ].cver & 0xFF) << SA_S4C_V_VER); -tq_csta = CST_S4; /* set step 4 */ -tq_init_int (); /* poke host */ -return OK; -} - -/* Queue service - invoked when any of the queues (host queue, unit - queues, response queue) require servicing. Also invoked during - initialization to provide some delay to the next step. - - Process at most one item off each unit queue - If the unit queues were empty, process at most one item off the host queue - Process at most one item off the response queue - - If all queues are idle, terminate thread -*/ - -t_stat tq_quesvc (UNIT *uptr) -{ -int32 i, cnid; -int32 pkt = 0; -UNIT *nuptr; - -if (tq_csta < CST_UP) { /* still init? */ - switch (tq_csta) { /* controller state? */ - - case CST_S1: /* need S1 reply */ - if (tq_saw & SA_S1H_VL) { /* valid? */ - if (tq_saw & SA_S1H_WR) { /* wrap? */ - tq_sa = tq_saw; /* echo data */ - tq_csta = CST_S1_WR; /* endless loop */ - } - else { - tq_s1dat = tq_saw; /* save data */ - tq_dib.vec = (tq_s1dat & SA_S1H_VEC) << 2; /* get vector */ - if (tq_dib.vec) /* if nz, bias */ - tq_dib.vec = tq_dib.vec + VEC_Q; - tq_sa = SA_S2 | SA_S2C_PT | SA_S2C_EC (tq_s1dat); - tq_csta = CST_S2; /* now in step 2 */ - tq_init_int (); /* intr if req */ - } - } /* end if valid */ - break; - - case CST_S1_WR: /* wrap mode */ - tq_sa = tq_saw; /* echo data */ - break; - - case CST_S2: /* need S2 reply */ - tq_comm = tq_saw & SA_S2H_CLO; /* get low addr */ - tq_prgi = tq_saw & SA_S2H_PI; /* get purge int */ - tq_sa = SA_S3 | SA_S3C_EC (tq_s1dat); - tq_csta = CST_S3; /* now in step 3 */ - tq_init_int (); /* intr if req */ - break; - - case CST_S3: /* need S3 reply */ - tq_comm = ((tq_saw & SA_S3H_CHI) << 16) | tq_comm; - if (tq_saw & SA_S3H_PP) { /* purge/poll test? */ - tq_sa = 0; /* put 0 */ - tq_csta = CST_S3_PPA; /* wait for 0 write */ - } - else tq_step4 (); /* send step 4 */ - break; - - case CST_S3_PPA: /* need purge test */ - if (tq_saw) /* data not zero? */ - tq_fatal (PE_PPF); - else tq_csta = CST_S3_PPB; /* wait for poll */ - break; - - case CST_S4: /* need S4 reply */ - if (tq_saw & SA_S4H_GO) { /* go set? */ - if (DEBUG_PRS (tq_dev)) - fprintf (sim_deb, ">>TQ: initialization complete\n"); - tq_csta = CST_UP; /* we're up */ - tq_sa = 0; /* clear SA */ - sim_activate (&tq_unit[TQ_TIMER], tmr_poll * clk_tps); - if ((tq_saw & SA_S4H_LF) && tq_perr) - tq_plf (tq_perr); - tq_perr = 0; - } - break; - } /* end switch */ - return SCPE_OK; - } /* end if */ - -for (i = 0; i < TQ_NUMDR; i++) { /* chk unit q's */ - nuptr = tq_dev.units + i; /* ptr to unit */ - if (nuptr->cpkt || (nuptr->pktq == 0)) - continue; - pkt = tq_deqh (&nuptr->pktq); /* get top of q */ - if (!tq_mscp (pkt, FALSE)) /* process */ - return SCPE_OK; - } -if ((pkt == 0) && tq_pip) { /* polling? */ - if (!tq_getpkt (&pkt)) /* get host pkt */ - return SCPE_OK; - if (pkt) { /* got one? */ - if (DEBUG_PRS (tq_dev)) { - UNIT *up = tq_getucb (tq_pkt[pkt].d[CMD_UN]); - fprintf (sim_deb, ">>TQ: cmd=%04X(%3s), mod=%04X, unit=%d, ", - tq_pkt[pkt].d[CMD_OPC], tq_cmdname[tq_pkt[pkt].d[CMD_OPC]&0x3f], tq_pkt[pkt].d[CMD_MOD], tq_pkt[pkt].d[CMD_UN]); - fprintf (sim_deb, "bc=%04X%04X, ma=%04X%04X", - tq_pkt[pkt].d[RW_BCH], tq_pkt[pkt].d[RW_BCL], - tq_pkt[pkt].d[RW_BAH], tq_pkt[pkt].d[RW_BAL]); - if (up) { - fprintf (sim_deb, ", pos="); - fprint_val (sim_deb, up->pos, 10, T_ADDR_W, PV_LEFT); - fprintf (sim_deb, ", obj=%d\n", up->objp); - } - else fprintf (sim_deb, "\n"); - fflush (sim_deb); - } - if (GETP (pkt, UQ_HCTC, TYP) != UQ_TYP_SEQ) /* seq packet? */ - return tq_fatal (PE_PIE); /* no, term thread */ - cnid = GETP (pkt, UQ_HCTC, CID); /* get conn ID */ - if (cnid == UQ_CID_TMSCP) { /* TMSCP packet? */ - if (!tq_mscp (pkt, TRUE)) /* proc, q non-seq */ - return SCPE_OK; - } - else if (cnid == UQ_CID_DUP) { /* DUP packet? */ - tq_putr (pkt, OP_END, 0, ST_CMD | I_OPCD, RSP_LNT, UQ_TYP_SEQ); - if (!tq_putpkt (pkt, TRUE)) /* ill cmd */ - return SCPE_OK; - } - else return tq_fatal (PE_ICI); /* no, term thread */ - } /* end if pkt */ - else tq_pip = 0; /* discontinue poll */ - } /* end if pip */ -if (tq_rspq) { /* resp q? */ - pkt = tq_deqh (&tq_rspq); /* get top of q */ - if (!tq_putpkt (pkt, FALSE)) /* send to host */ - return SCPE_OK; - } /* end if resp q */ -if (pkt) /* more to do? */ - sim_activate (&tq_unit[TQ_QUEUE], tq_qtime); -return SCPE_OK; /* done */ -} - -/* Clock service (roughly once per second) */ - -t_stat tq_tmrsvc (UNIT *uptr) -{ -int32 i; -UNIT *nuptr; - -sim_activate (uptr, tmr_poll * clk_tps); /* reactivate */ -for (i = 0; i < TQ_NUMDR; i++) { /* poll */ - nuptr = tq_dev.units + i; - if ((nuptr->flags & UNIT_ATP) && /* ATN pending? */ - (nuptr->flags & UNIT_ATT) && /* still online? */ - (tq_cflgs & CF_ATN)) { /* wanted? */ - if (!tq_una (nuptr)) - return SCPE_OK; - } - nuptr->flags = nuptr->flags & ~UNIT_ATP; - } -if ((tq_hat > 0) && (--tq_hat == 0)) /* host timeout? */ - tq_fatal (PE_HAT); /* fatal err */ -return SCPE_OK; -} - -/* MSCP packet handling */ - -t_bool tq_mscp (int32 pkt, t_bool q) -{ -uint32 sts; -uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* command */ -uint32 flg = GETP (pkt, CMD_OPC, FLG); /* flags */ -uint32 mdf = tq_pkt[pkt].d[CMD_MOD]; /* modifier */ -uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ -UNIT *uptr; - -if ((cmd >= 64) || (tq_cmf[cmd] == 0)) { /* invalid cmd? */ - cmd = OP_END; /* set end op */ - sts = ST_CMD | I_OPCD; /* ill op */ - } -else if (flg) { /* flags? */ - cmd = cmd | OP_END; /* set end flag */ - sts = ST_CMD | I_FLAG; /* ill flags */ - } -else if (mdf & ~tq_cmf[cmd]) { /* invalid mod? */ - cmd = cmd | OP_END; /* set end flag */ - sts = ST_CMD | I_MODF; /* ill mods */ - } -else { /* valid cmd */ - if (uptr = tq_getucb (lu)) { /* valid unit? */ - if (q && (tq_cmf[cmd] & CMF_SEQ) && /* queueing, seq, */ - (uptr->cpkt || uptr->pktq)) { /* and active? */ - tq_enqt (&uptr->pktq, pkt); /* do later */ - return OK; - } -// if (tq_cmf[cmd] & MD_CDL) /* clr cch lost? */ -// uptr->flags = uptr->flags & ~UNIT_CDL; - if ((mdf & MD_CSE) && (uptr->flags & UNIT_SXC)) /* clr ser exc? */ - uptr->flags = uptr->flags & ~UNIT_SXC; - } - switch (cmd) { - - case OP_ABO: /* abort */ - return tq_abo (pkt); - - case OP_AVL: /* avail */ - return tq_avl (pkt); - - case OP_GCS: /* get cmd status */ - return tq_gcs (pkt); - - case OP_GUS: /* get unit status */ - return tq_gus (pkt); - - case OP_ONL: /* online */ - return tq_onl (pkt); - - case OP_SCC: /* set ctrl char */ - return tq_scc (pkt); - - case OP_SUC: /* set unit char */ - return tq_suc (pkt); - - case OP_ERS: /* erase */ - case OP_ERG: /* erase gap */ - return tq_erase (pkt); - - case OP_FLU: /* flush */ - return tq_flu (pkt); - - case OP_POS: /* position */ - return tq_pos (pkt); - - case OP_WTM: /* write tape mark */ - return tq_wtm (pkt); - - case OP_ACC: /* access */ - case OP_CMP: /* compare */ - case OP_RD: /* read */ - case OP_WR: /* write */ - return tq_rw (pkt); - - case OP_DAP: - cmd = cmd | OP_END; /* set end flag */ - sts = ST_SUC; /* success */ - break; - - default: - cmd = OP_END; /* set end op */ - sts = ST_CMD | I_OPCD; /* ill op */ - break; - } /* end switch */ - } /* end else */ -tq_putr (pkt, cmd, 0, sts, RSP_LNT, UQ_TYP_SEQ); -return tq_putpkt (pkt, TRUE); -} - -/* Abort a command - 1st parameter is ref # of cmd to abort */ - -t_bool tq_abo (int32 pkt) -{ -uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ -uint32 ref = GETP32 (pkt, ABO_REFL); /* cmd ref # */ -int32 tpkt, prv; -UNIT *uptr; - -tpkt = 0; /* set no mtch */ -if (uptr = tq_getucb (lu)) { /* get unit */ - if (uptr->cpkt && /* curr pkt? */ - (GETP32 (uptr->cpkt, CMD_REFL) == ref)) { /* match ref? */ - tpkt = uptr->cpkt; /* save match */ - uptr->cpkt = 0; /* gonzo */ - sim_cancel (uptr); /* cancel unit */ - sim_activate (&tq_unit[TQ_QUEUE], tq_qtime); - } - else if (uptr->pktq && /* head of q? */ - (GETP32 (uptr->pktq, CMD_REFL) == ref)) { /* match ref? */ - tpkt = uptr->pktq; /* save match */ - uptr->pktq = tq_pkt[tpkt].link; /* unlink */ - } - else if (prv = uptr->pktq) { /* srch pkt q */ - while (tpkt = tq_pkt[prv].link) { /* walk list */ - if (GETP32 (tpkt, RSP_REFL) == ref) { /* match ref? */ - tq_pkt[prv].link = tq_pkt[tpkt].link; /* unlink */ - break; - } - prv = tpkt; /* no match, next */ - } - } - if (tpkt) { /* found target? */ - uint32 tcmd = GETP (tpkt, CMD_OPC, OPC); /* get opcode */ - tq_putr (tpkt, tcmd | OP_END, 0, ST_ABO, RSP_LNT, UQ_TYP_SEQ); - if (!tq_putpkt (tpkt, TRUE)) - return ERR; - } - } /* end if unit */ -tq_putr (pkt, OP_ABO | OP_END, 0, ST_SUC, ABO_LNT, UQ_TYP_SEQ); -return tq_putpkt (pkt, TRUE); -} - -/* Unit available - set unit status to available - Deferred if q'd cmds, bypassed if ser exc */ - -t_bool tq_avl (int32 pkt) -{ -uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ -uint32 mdf = tq_pkt[pkt].d[CMD_MOD]; /* modifiers */ -uint32 sts; -UNIT *uptr; - -if (uptr = tq_getucb (lu)) { /* unit exist? */ - if (uptr->flags & UNIT_SXC) /* ser exc pending? */ - sts = ST_SXC; - else { - uptr->flags = uptr->flags & ~(UNIT_ONL | UNIT_TMK | UNIT_POL); - sim_tape_rewind (uptr); /* rewind */ - uptr->uf = uptr->objp = 0; /* clr flags */ - if (uptr->flags & UNIT_ATT) { /* attached? */ - sts = ST_SUC; /* success */ - if (mdf & MD_UNL) /* unload? */ - tq_detach (uptr); - } - else sts = ST_OFL | SB_OFL_NV; /* no, offline */ - } - } -else sts = ST_OFL; /* offline */ -tq_putr (pkt, OP_AVL | OP_END, tq_efl (uptr), sts, AVL_LNT, UQ_TYP_SEQ); -return tq_putpkt (pkt, TRUE); -} - -/* Get command status - only interested in active xfr cmd */ - -t_bool tq_gcs (int32 pkt) -{ -uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ -uint32 ref = GETP32 (pkt, GCS_REFL); /* ref # */ -int32 tpkt; -UNIT *uptr; - -if ((uptr = tq_getucb (lu)) && /* valid lu? */ - (tpkt = uptr->cpkt) && /* queued pkt? */ - (GETP32 (tpkt, CMD_REFL) == ref) && /* match ref? */ - (tq_cmf[GETP (tpkt, CMD_OPC, OPC)] & CMF_RW)) { /* rd/wr cmd? */ - tq_pkt[pkt].d[GCS_STSL] = tq_pkt[tpkt].d[RW_BCL]; - tq_pkt[pkt].d[GCS_STSH] = tq_pkt[tpkt].d[RW_BCH]; - } -else tq_pkt[pkt].d[GCS_STSL] = tq_pkt[pkt].d[GCS_STSH] = 0; -tq_putr (pkt, OP_GCS | OP_END, 0, ST_SUC, GCS_LNT, UQ_TYP_SEQ); -return tq_putpkt (pkt, TRUE); -} - -/* Get unit status */ - -t_bool tq_gus (int32 pkt) -{ -uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ -uint32 sts; -UNIT *uptr; - -if (tq_pkt[pkt].d[CMD_MOD] & MD_NXU) { /* next unit? */ - if (lu >= TQ_NUMDR) { /* end of range? */ - lu = 0; /* reset to 0 */ - tq_pkt[pkt].d[RSP_UN] = lu; - } - } -if (uptr = tq_getucb (lu)) { /* unit exist? */ - if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ - sts = ST_OFL | SB_OFL_NV; /* offl no vol */ - else if (uptr->flags & UNIT_ONL) /* online */ - sts = ST_SUC; - else sts = ST_AVL; /* avail */ - tq_putr_unit (pkt, uptr, lu, FALSE); /* fill unit fields */ - tq_pkt[pkt].d[GUS_MENU] = drv_tab[tq_typ].fmt; /* format menu */ - tq_pkt[pkt].d[GUS_CAP] = 0; /* free capacity */ - tq_pkt[pkt].d[GUS_FVER] = drv_tab[tq_typ].fver; /* formatter version */ - tq_pkt[pkt].d[GUS_UVER] = drv_tab[tq_typ].uver; /* unit version */ - } -else sts = ST_OFL; /* offline */ -tq_putr (pkt, OP_GUS | OP_END, tq_efl (uptr), sts, GUS_LNT_T, UQ_TYP_SEQ); -return tq_putpkt (pkt, TRUE); -} - -/* Unit online - deferred if q'd commands */ - -t_bool tq_onl (int32 pkt) -{ -uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ -uint32 sts; -UNIT *uptr; - -if (uptr = tq_getucb (lu)) { /* unit exist? */ - if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ - sts = ST_OFL | SB_OFL_NV; /* offl no vol */ - else if (uptr->flags & UNIT_ONL) /* already online? */ - sts = ST_SUC | SB_SUC_ON; - else { - sts = ST_SUC; /* mark online */ - sim_tape_rewind (uptr); /* rewind */ - uptr->objp = 0; /* clear flags */ - uptr->flags = (uptr->flags | UNIT_ONL) & - ~(UNIT_TMK | UNIT_POL); /* onl, pos ok */ - tq_setf_unit (pkt, uptr); /* hack flags */ - } - tq_putr_unit (pkt, uptr, lu, TRUE); /* set fields */ - } -else sts = ST_OFL; /* offline */ -tq_putr (pkt, OP_ONL | OP_END, tq_efl (uptr), sts, ONL_LNT, UQ_TYP_SEQ); -return tq_putpkt (pkt, TRUE); -} - -/* Set controller characteristics */ - -t_bool tq_scc (int32 pkt) -{ -if (tq_pkt[pkt].d[SCC_MSV]) /* MSCP ver = 0? */ - tq_putr (pkt, 0, 0, ST_CMD | I_VRSN, SCC_LNT, UQ_TYP_SEQ); -else { - tq_cflgs = (tq_cflgs & CF_RPL) | /* hack ctrl flgs */ - tq_pkt[pkt].d[SCC_CFL]; - if (tq_htmo = tq_pkt[pkt].d[SCC_TMO]) /* set timeout */ - tq_htmo = tq_htmo + 2; /* if nz, round up */ - tq_pkt[pkt].d[SCC_CFL] = tq_cflgs; /* return flags */ - tq_pkt[pkt].d[SCC_TMO] = TQ_DCTMO; /* ctrl timeout */ - tq_pkt[pkt].d[SCC_VER] = drv_tab[tq_typ].cver; /* ctrl version */ - tq_pkt[pkt].d[SCC_CIDA] = 0; /* ctrl ID */ - tq_pkt[pkt].d[SCC_CIDB] = 0; - tq_pkt[pkt].d[SCC_CIDC] = 0; - tq_pkt[pkt].d[SCC_CIDD] = (TQ_CLASS << SCC_CIDD_V_CLS) | - (drv_tab[tq_typ].cmod << SCC_CIDD_V_MOD); - PUTP32 (pkt, SCC_MBCL, TQ_MAXFR); /* max bc */ - tq_putr (pkt, OP_SCC | OP_END, 0, ST_SUC, SCC_LNT, UQ_TYP_SEQ); - } -return tq_putpkt (pkt, TRUE); -} - -/* Set unit characteristics - defer if q'd commands */ - -t_bool tq_suc (int32 pkt) -{ -uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ -uint32 sts; -UNIT *uptr; - -if (uptr = tq_getucb (lu)) { /* unit exist? */ - if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ - sts = ST_OFL | SB_OFL_NV; /* offl no vol */ - else { - sts = ST_SUC; /* avail or onl */ - tq_setf_unit (pkt, uptr); /* hack flags */ - } - tq_putr_unit (pkt, uptr, lu, TRUE); /* set fields */ - } -else sts = ST_OFL; /* offline */ -tq_putr (pkt, OP_SUC | OP_END, 0, sts, SUC_LNT, UQ_TYP_SEQ); -return tq_putpkt (pkt, TRUE); -} - -/* Flush - sequential nop - deferred if q'd cmds, bypassed if ser exc */ - -t_bool tq_flu (int32 pkt) -{ -uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ -uint32 sts; -UNIT *uptr; - -if (uptr = tq_getucb (lu)) /* unit exist? */ - sts = tq_mot_valid (uptr, OP_FLU); /* validate req */ -else sts = ST_OFL; /* offline */ -tq_putr (pkt, OP_FLU | OP_END, tq_efl (uptr), sts, FLU_LNT, UQ_TYP_SEQ); -return tq_putpkt (pkt, TRUE); -} - -/* Erase, erase gap - deferred if q'd cmds, bypassed if ser exc */ - -t_bool tq_erase (int32 pkt) -{ -uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ -uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ -uint32 sts; -UNIT *uptr; - -if (uptr = tq_getucb (lu)) { /* unit exist? */ - sts = tq_mot_valid (uptr, cmd); /* validity checks */ - if (sts == ST_SUC) { /* ok? */ - uptr->cpkt = pkt; /* op in progress */ - sim_activate (uptr, tq_xtime); /* activate */ - return OK; /* done */ - } - } -else sts = ST_OFL; /* offline */ -tq_putr (pkt, cmd | OP_END, tq_efl (uptr), sts, ERS_LNT, UQ_TYP_SEQ); -return tq_putpkt (pkt, TRUE); -} - -/* Write tape mark - deferred if q'd cmds, bypassed if ser exc */ - -t_bool tq_wtm (int32 pkt) -{ -uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ -uint32 sts, objp = 0; -UNIT *uptr; - -if (uptr = tq_getucb (lu)) { /* unit exist? */ - objp = uptr->objp; /* position op */ - sts = tq_mot_valid (uptr, OP_WTM); /* validity checks */ - if (sts == ST_SUC) { /* ok? */ - uptr->cpkt = pkt; /* op in progress */ - sim_activate (uptr, tq_xtime); /* activate */ - return OK; /* done */ - } - } -else sts = ST_OFL; /* offline */ -PUTP32 (pkt, WTM_POSL, objp); /* set obj pos */ -tq_putr (pkt, OP_WTM | OP_END, tq_efl (uptr), sts, WTM_LNT, UQ_TYP_SEQ); -return tq_putpkt (pkt, TRUE); -} - -/* Position - deferred if q'd cmds, bypassed if ser exc */ - -t_bool tq_pos (int32 pkt) -{ -uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ -uint32 sts, objp = 0; -UNIT *uptr; - -if (uptr = tq_getucb (lu)) { /* unit exist? */ - objp = uptr->objp; /* position op */ - sts = tq_mot_valid (uptr, OP_POS); /* validity checks */ - if (sts == ST_SUC) { /* ok? */ - uptr->cpkt = pkt; /* op in progress */ - tq_rwtime = 2 * tmr_poll * clk_tps; /* 2 second rewind time */ - if ((tq_pkt[pkt].d[CMD_MOD] & MD_RWD) && /* rewind? */ - (!(tq_pkt[pkt].d[CMD_MOD] & MD_IMM))) /* !immediate? */ - sim_activate (uptr, tq_rwtime); /* use 2 sec rewind execute time */ - else /* otherwise */ - sim_activate (uptr, tq_xtime); /* use normal execute time */ - return OK; /* done */ - } - } -else sts = ST_OFL; /* offline */ -PUTP32 (pkt, POS_RCL, 0); /* clear #skipped */ -PUTP32 (pkt, POS_TMCL, 0); -PUTP32 (pkt, POS_POSL, objp); /* set obj pos */ -tq_putr (pkt, OP_POS | OP_END, tq_efl (uptr), sts, POS_LNT, UQ_TYP_SEQ); -return tq_putpkt (pkt, TRUE); -} - -/* Data transfer commands - deferred if q'd commands, bypassed if ser exc */ - -t_bool tq_rw (int32 pkt) -{ -uint32 lu = tq_pkt[pkt].d[CMD_UN]; /* unit # */ -uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* opcode */ -uint32 bc = GETP32 (pkt, RW_BCL); /* byte count */ -uint32 sts, objp = 0; -UNIT *uptr; - -if (uptr = tq_getucb (lu)) { /* unit exist? */ - objp = uptr->objp; /* position op */ - sts = tq_mot_valid (uptr, cmd); /* validity checks */ - if (sts == ST_SUC) { /* ok? */ - if ((bc == 0) || (bc > TQ_MAXFR)) { /* invalid? */ - uptr->flags = uptr->flags | UNIT_SXC; /* set ser exc */ - sts = ST_CMD | I_BCNT; - } - else { - uptr->cpkt = pkt; /* op in progress */ - sim_activate (uptr, tq_xtime); /* activate */ - return OK; /* done */ - } - } - } -else sts = ST_OFL; /* offline */ -PUTP32 (pkt, RW_BCL, 0); /* no bytes processed */ -PUTP32 (pkt, RW_POSL, objp); /* set obj pos */ -PUTP32 (pkt, RW_RSZL, 0); /* clr rec size */ -tq_putr (pkt, cmd | OP_END, tq_efl (uptr), sts, RW_LNT_T, UQ_TYP_SEQ); -return tq_putpkt (pkt, TRUE); -} - -/* Validity checks */ - -int32 tq_mot_valid (UNIT *uptr, uint32 cmd) -{ -if (uptr->flags & UNIT_SXC) /* ser exc pend? */ - return ST_SXC; -if ((uptr->flags & UNIT_ATT) == 0) /* not attached? */ - return (ST_OFL | SB_OFL_NV); /* offl no vol */ -if ((uptr->flags & UNIT_ONL) == 0) /* not online? */ - return ST_AVL; /* only avail */ -if (tq_cmf[cmd] & CMF_WR) { /* write op? */ - if (uptr->uf & UF_WPS) { /* swre wlk? */ - uptr->flags = uptr->flags | UNIT_SXC; /* set ser exc */ - return (ST_WPR | SB_WPR_SW); - } - if (TQ_WPH (uptr)) { /* hwre wlk? */ - uptr->flags = uptr->flags | UNIT_SXC; /* set ser exc */ - return (ST_WPR | SB_WPR_HW); - } - } -return ST_SUC; /* success! */ -} - -/* Unit service for motion commands */ - -t_stat tq_svc (UNIT *uptr) -{ -uint32 t, sts, sktmk, skrec; -t_mtrlnt i, tbc, wbc; -int32 pkt = uptr->cpkt; /* get packet */ -uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* get cmd */ -uint32 mdf = tq_pkt[pkt].d[CMD_MOD]; /* modifier */ -uint32 ba = GETP32 (pkt, RW_BAL); /* buf addr */ -t_mtrlnt bc = GETP32 (pkt, RW_BCL); /* byte count */ -uint32 nrec = GETP32 (pkt, POS_RCL); /* #rec to skip */ -uint32 ntmk = GETP32 (pkt, POS_TMCL); /* #tmk to skp */ - -if (pkt == 0) /* what??? */ - return SCPE_IERR; -if ((uptr->flags & UNIT_ATT) == 0) { /* not attached? */ - tq_mot_end (uptr, 0, ST_OFL | SB_OFL_NV, 0); /* offl no vol */ - return SCPE_OK; - } - -if (tq_cmf[cmd] & CMF_WR) { /* write op? */ - if (TQ_WPH (uptr)) { /* hwre write prot? */ - uptr->flags = uptr->flags | UNIT_SXC; /* set ser exc */ - tq_mot_end (uptr, 0, ST_WPR | SB_WPR_HW, 0); - return SCPE_OK; - } - if (uptr->uf & UF_WPS) { /* swre write prot? */ - uptr->flags = uptr->flags | UNIT_SXC; /* set ser exc */ - tq_mot_end (uptr, 0, ST_WPR | SB_WPR_SW, 0); - return SCPE_OK; - } - } -sts = ST_SUC; /* assume success */ -tbc = 0; /* assume zero rec */ -switch (cmd) { /* case on command */ - - case OP_RD:case OP_ACC:case OP_CMP: /* read-like op */ - if (mdf & MD_REV) /* read record */ - sts = tq_rdbufr (uptr, &tbc); - else sts = tq_rdbuff (uptr, &tbc); - if (sts == ST_DRV) { /* read error? */ - PUTP32 (pkt, RW_BCL, 0); /* no bytes processed */ - return tq_mot_err (uptr, tbc); /* log, done */ - } - if ((sts != ST_SUC) || (cmd == OP_ACC)) { /* error or access? */ - if (sts == ST_TMK) - uptr->flags = uptr->flags | UNIT_SXC; /* set ser exc */ - PUTP32 (pkt, RW_BCL, 0); /* no bytes processed */ - break; - } - if (tbc > bc) { /* tape rec > buf? */ - uptr->flags = uptr->flags | UNIT_SXC; /* serious exc */ - sts = ST_RDT; /* data truncated */ - wbc = bc; /* set working bc */ - } - else wbc = tbc; - if (cmd == OP_RD) { /* read? */ - if (t = Map_WriteB (ba, wbc, tqxb)) { /* store, nxm? */ - PUTP32 (pkt, RW_BCL, wbc - t); /* adj bc */ - if (tq_hbe (uptr, ba + wbc - t)) /* post err log */ - tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, tbc); - return SCPE_OK; /* end if nxm */ - } - } /* end if read */ - else { /* compare */ - uint8 mby, dby; - uint32 mba; - for (i = 0; i < wbc; i++) { /* loop */ - if (mdf & MD_REV) { /* reverse? */ - mba = ba + bc - 1 - i; /* mem addr */ - dby = tqxb[tbc - 1 - i]; /* byte */ - } - else { - mba = ba + i; - dby = tqxb[i]; - } - if (Map_ReadB (mba, 1, &mby)) { /* fetch, nxm? */ - PUTP32 (pkt, RW_BCL, i); /* adj bc */ - if (tq_hbe (uptr, mba)) /* post err log */ - tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, tbc); - return SCPE_OK; - } - if (mby != dby) { /* cmp err? */ - uptr->flags = uptr->flags | UNIT_SXC; /* ser exc */ - PUTP32 (pkt, RW_BCL, i); /* adj bc */ - tq_mot_end (uptr, 0, ST_CMP, tbc); - return SCPE_OK; /* exit */ - } - } /* end for */ - } /* end if compare */ - PUTP32 (pkt, RW_BCL, wbc); /* bytes read/cmp'd */ - break; - - case OP_WR: /* write */ - if (t = Map_ReadB (ba, bc, tqxb)) { /* fetch buf, nxm? */ - PUTP32 (pkt, RW_BCL, 0); /* no bytes xfer'd */ - if (tq_hbe (uptr, ba + bc - t)) /* post err log */ - tq_mot_end (uptr, EF_LOG, ST_HST | SB_HST_NXM, bc); - return SCPE_OK; /* end else wr */ - } - if (sim_tape_wrrecf (uptr, tqxb, bc)) /* write rec fwd, err? */ - return tq_mot_err (uptr, bc); /* log, end */ - uptr->objp = uptr->objp + 1; /* upd obj pos */ - if (TEST_EOT (uptr)) /* EOT on write? */ - uptr->flags = uptr->flags | UNIT_SXC; - uptr->flags = uptr->flags & ~UNIT_TMK; /* disable LEOT */ - tbc = bc; /* RW_BC is ok */ - break; - - case OP_WTM: /* write tape mark */ - if (sim_tape_wrtmk (uptr)) /* write tmk, err? */ - return tq_mot_err (uptr, 0); /* log, end */ - uptr->objp = uptr->objp + 1; /* incr obj cnt */ - case OP_ERG: /* erase gap */ - if (TEST_EOT (uptr)) /* EOT on write? */ - uptr->flags = uptr->flags | UNIT_SXC; - uptr->flags = uptr->flags & ~UNIT_TMK; /* disable LEOT */ - break; - - case OP_ERS: /* erase */ - if (sim_tape_wreom (uptr)) /* write eom, err? */ - return tq_mot_err (uptr, 0); /* log, end */ - sim_tape_rewind (uptr); /* rewind */ - uptr->objp = 0; - uptr->flags = uptr->flags & ~(UNIT_TMK | UNIT_POL); - break; - - case OP_POS: /* position */ - sktmk = skrec = 0; /* clr skipped */ - if (mdf & MD_RWD) { /* rewind? */ - sim_tape_rewind (uptr); - uptr->objp = 0; /* clr flags */ - uptr->flags = uptr->flags & ~(UNIT_TMK | UNIT_POL); - } - if (mdf & MD_OBC) { /* skip obj? */ - if (mdf & MD_REV) /* reverse? */ - sts = tq_spacer (uptr, nrec, &skrec, FALSE); - else sts = tq_spacef (uptr, nrec, &skrec, FALSE); - } - else { /* skip tmk, rec */ - if (mdf & MD_REV) - sts = tq_skipfr (uptr, ntmk, &sktmk); - else sts = tq_skipff (uptr, ntmk, &sktmk); - if (sts == ST_SUC) { /* tmk succeed? */ - if (mdf & MD_REV) /* reverse? */ - sts = tq_spacer (uptr, nrec, &skrec, TRUE); - else sts = tq_spacef (uptr, nrec, &skrec, TRUE); - if (sts == ST_TMK) - sktmk = sktmk + 1; - } - } - PUTP32 (pkt, POS_RCL, skrec); /* #rec skipped */ - PUTP32 (pkt, POS_TMCL, sktmk); /* #tmk skipped */ - if (DEBUG_PRS (tq_dev)) { - fprintf (sim_deb, ">>TQ: Position Done: mdf=%04X, nrec=%04X, ntmk=%04X, skrec=%04X, sktmk=%04X\n", - mdf, nrec, ntmk, skrec, sktmk); - fflush (sim_deb); - } - break; - - default: - return SCPE_IERR; - } - -tq_mot_end (uptr, 0, sts, tbc); /* done */ -return SCPE_OK; -} - -/* Motion command drive error */ - -t_stat tq_mot_err (UNIT *uptr, uint32 rsiz) -{ -uptr->flags = (uptr->flags | UNIT_SXC) & ~UNIT_TMK; /* serious exception */ -if (tq_dte (uptr, ST_DRV)) /* post err log */ - tq_mot_end (uptr, EF_LOG, ST_DRV, rsiz); /* if ok, report err */ -perror ("TQ I/O error"); -clearerr (uptr->fileref); -return SCPE_IOERR; -} - -/* Motion command complete */ - -t_bool tq_mot_end (UNIT *uptr, uint32 flg, uint32 sts, uint32 rsiz) -{ -int32 pkt = uptr->cpkt; /* packet */ -uint32 cmd = GETP (pkt, CMD_OPC, OPC); /* get cmd */ -uint32 lnt = RW_LNT_T; /* assume rw */ - -if (cmd == OP_ERG) /* set pkt lnt */ - lnt = ERG_LNT; -else if (cmd == OP_ERS) - lnt = ERS_LNT; -else if (cmd == OP_WTM) - lnt = WTM_LNT; -else if (cmd == OP_POS) - lnt = POS_LNT; - -uptr->cpkt = 0; /* done */ -if (lnt > ERG_LNT) { /* xfer cmd? */ - PUTP32 (pkt, RW_POSL, uptr->objp); /* position */ - PUTP32 (pkt, RW_RSZL, rsiz); /* record size */ - } -tq_putr (pkt, cmd | OP_END, flg | tq_efl (uptr), sts, lnt, UQ_TYP_SEQ); -if (!tq_putpkt (pkt, TRUE)) /* send pkt */ - return ERR; -if (uptr->pktq) /* more to do? */ - sim_activate (&tq_unit[TQ_QUEUE], tq_qtime); /* activate thread */ -return OK; -} - -/* Tape motion routines */ - -uint32 tq_map_status (UNIT *uptr, t_stat st) -{ -switch (st) { - - case MTSE_OK: - break; - - case MTSE_UNATT: - uptr->flags = uptr->flags | UNIT_SXC; - return (ST_OFL | SB_OFL_NV); - - case MTSE_FMT: - uptr->flags = uptr->flags | UNIT_SXC; - return ST_MFE; - - case MTSE_TMK: - uptr->flags = uptr->flags | UNIT_SXC; - return ST_TMK; - - case MTSE_INVRL: - uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL; - return ST_FMT; - - case MTSE_RECE: - case MTSE_IOERR: - uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL; - return ST_DRV; - - case MTSE_EOM: - uptr->flags = uptr->flags | UNIT_SXC | UNIT_POL; - return ST_DAT; - - case MTSE_BOT: - uptr->flags = (uptr->flags | UNIT_SXC) & ~UNIT_POL; - return ST_BOT; - - case MTSE_WRP: - uptr->flags = uptr->flags | UNIT_SXC; - return ST_WPR; - } - -return ST_SUC; -} - -uint32 tq_spacef (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec) -{ -t_stat st; -t_mtrlnt tbc; - -*skipped = 0; -while (*skipped < cnt) { /* loop */ - st = sim_tape_sprecf (uptr, &tbc); /* space rec fwd */ - if ((st != MTSE_OK) && (st != MTSE_TMK)) /* real error? */ - return tq_map_status (uptr, st); /* map status */ - uptr->objp = uptr->objp + 1; /* upd obj cnt */ - if (st == MTSE_TMK) { /* tape mark? */ - int32 pkt = uptr->cpkt; /* get pkt */ - if ((tq_pkt[pkt].d[CMD_MOD] & MD_DLE) && /* LEOT? */ - (uptr->flags & UNIT_TMK)) { - sim_tape_sprecr (uptr, &tbc); /* rev over tmk */ - uptr->flags = uptr->flags | UNIT_SXC; /* serious exc */ - return ST_LED; - } - uptr->flags = uptr->flags | UNIT_TMK; /* set TM seen */ - if (qrec) /* rec spc? stop */ - return ST_TMK; - } - else uptr->flags = uptr->flags & ~UNIT_TMK; /* clr TM seen */ - *skipped = *skipped + 1; /* # obj skipped */ - } -return ST_SUC; -} - -uint32 tq_skipff (UNIT *uptr, uint32 cnt, uint32 *skipped) -{ -uint32 st, skrec; - -*skipped = 0; -while (*skipped < cnt) { /* loop */ - st = tq_spacef (uptr, 0x7FFFFFFF, &skrec, TRUE); /* rec spc fwd */ - if (st == ST_TMK) /* count files */ - *skipped = *skipped + 1; - else if (st != ST_SUC) - return st; - } -return ST_SUC; -} - -uint32 tq_spacer (UNIT *uptr, uint32 cnt, uint32 *skipped, t_bool qrec) -{ -t_stat st; -t_mtrlnt tbc; - -*skipped = 0; -while (*skipped < cnt) { /* loop */ - st = sim_tape_sprecr (uptr, &tbc); /* spc rec rev */ - if ((st != MTSE_OK) && (st != MTSE_TMK)) /* real error? */ - return tq_map_status (uptr, st); /* map status */ - uptr->objp = uptr->objp - 1; /* upd obj cnt */ - if ((st == MTSE_TMK) && qrec) /* tape mark, stop? */ - return ST_TMK; - *skipped = *skipped + 1; /* # obj skipped */ - } -return ST_SUC; -} - -uint32 tq_skipfr (UNIT *uptr, uint32 cnt, uint32 *skipped) -{ -uint32 st, skrec; - -*skipped = 0; -while (*skipped < cnt) { /* loopo */ - st = tq_spacer (uptr, 0x7FFFFFFF, &skrec, TRUE); /* rec spc rev */ - if (st == ST_TMK) /* tape mark? */ - *skipped = *skipped + 1; - else if (st != 0) /* error? */ - return st; - } -return ST_SUC; -} - -/* Read buffer - can return ST_TMK, ST_FMT, or ST_DRV */ - -uint32 tq_rdbuff (UNIT *uptr, t_mtrlnt *tbc) -{ -t_stat st; - -st = sim_tape_rdrecf (uptr, tqxb, tbc, MT_MAXFR); /* read rec fwd */ -if (st == MTSE_TMK) { /* tape mark? */ - uptr->flags = uptr->flags | UNIT_SXC | UNIT_TMK; /* serious exc */ - uptr->objp = uptr->objp + 1; /* update obj cnt */ - return ST_TMK; - } -if (st != MTSE_OK) /* other error? */ - return tq_map_status (uptr, st); -uptr->flags = uptr->flags & ~UNIT_TMK; /* clr tape mark */ -uptr->objp = uptr->objp + 1; /* upd obj cnt */ -return ST_SUC; -} - -uint32 tq_rdbufr (UNIT *uptr, t_mtrlnt *tbc) -{ -t_stat st; - -st = sim_tape_rdrecr (uptr, tqxb, tbc, MT_MAXFR); /* read rec rev */ -if (st == MTSE_TMK) { /* tape mark? */ - uptr->flags = uptr->flags | UNIT_SXC; /* serious exc */ - uptr->objp = uptr->objp - 1; /* update obj cnt */ - return ST_TMK; - } -if (st != MTSE_OK) /* other error? */ - return tq_map_status (uptr, st); -uptr->objp = uptr->objp - 1; /* upd obj cnt */ -return ST_SUC; -} - -/* Data transfer error log packet */ - -t_bool tq_dte (UNIT *uptr, uint32 err) -{ -int32 pkt, tpkt; -uint32 lu; - -if ((tq_cflgs & CF_THS) == 0) /* logging? */ - return OK; -if (!tq_deqf (&pkt)) /* get log pkt */ - return ERR; -tpkt = uptr->cpkt; /* rw pkt */ -lu = tq_pkt[tpkt].d[CMD_UN]; /* unit # */ - -tq_pkt[pkt].d[ELP_REFL] = tq_pkt[tpkt].d[CMD_REFL]; /* copy cmd ref */ -tq_pkt[pkt].d[ELP_REFH] = tq_pkt[tpkt].d[CMD_REFH]; /* copy cmd ref */ -tq_pkt[pkt].d[ELP_UN] = lu; /* copy unit */ -tq_pkt[pkt].d[ELP_SEQ] = 0; /* clr seq # */ -tq_pkt[pkt].d[DTE_CIDA] = 0; /* ctrl ID */ -tq_pkt[pkt].d[DTE_CIDB] = 0; -tq_pkt[pkt].d[DTE_CIDC] = 0; -tq_pkt[pkt].d[DTE_CIDD] = (TQ_CLASS << DTE_CIDD_V_CLS) | - (drv_tab[tq_typ].cmod << DTE_CIDD_V_MOD); -tq_pkt[pkt].d[DTE_VER] = drv_tab[tq_typ].cver; /* ctrl ver */ -tq_pkt[pkt].d[DTE_MLUN] = lu; /* MLUN */ -tq_pkt[pkt].d[DTE_UIDA] = lu; /* unit ID */ -tq_pkt[pkt].d[DTE_UIDB] = 0; -tq_pkt[pkt].d[DTE_UIDC] = 0; -tq_pkt[pkt].d[DTE_UIDD] = (UID_TAPE << DTE_UIDD_V_CLS) | - (drv_tab[tq_typ].umod << DTE_UIDD_V_MOD); -tq_pkt[pkt].d[DTE_UVER] = drv_tab[tq_typ].uver; /* unit ver */ -PUTP32 (pkt, DTE_POSL, uptr->objp); /* position */ -tq_pkt[pkt].d[DTE_FVER] = drv_tab[tq_typ].fver; /* fmtr ver */ -tq_putr (pkt, FM_TAP, LF_SNR, err, DTE_LNT, UQ_TYP_DAT); -return tq_putpkt (pkt, TRUE); -} - -/* Host bus error log packet */ - -t_bool tq_hbe (UNIT *uptr, uint32 ba) -{ -int32 pkt, tpkt; - -if ((tq_cflgs & CF_THS) == 0) /* logging? */ - return OK; -if (!tq_deqf (&pkt)) /* get log pkt */ - return ERR; -tpkt = uptr->cpkt; /* rw pkt */ -tq_pkt[pkt].d[ELP_REFL] = tq_pkt[tpkt].d[CMD_REFL]; /* copy cmd ref */ -tq_pkt[pkt].d[ELP_REFH] = tq_pkt[tpkt].d[CMD_REFH]; /* copy cmd ref */ -tq_pkt[pkt].d[ELP_UN] = tq_pkt[tpkt].d[CMD_UN]; /* copy unit */ -tq_pkt[pkt].d[ELP_SEQ] = 0; /* clr seq # */ -tq_pkt[pkt].d[HBE_CIDA] = 0; /* ctrl ID */ -tq_pkt[pkt].d[HBE_CIDB] = 0; -tq_pkt[pkt].d[HBE_CIDC] = 0; -tq_pkt[pkt].d[DTE_CIDD] = (TQ_CLASS << DTE_CIDD_V_CLS) | - (drv_tab[tq_typ].cmod << DTE_CIDD_V_MOD); -tq_pkt[pkt].d[HBE_VER] = drv_tab[tq_typ].cver; /* ctrl ver */ -tq_pkt[pkt].d[HBE_RSV] = 0; -PUTP32 (pkt, HBE_BADL, ba); /* bad addr */ -tq_putr (pkt, FM_BAD, LF_SNR, ST_HST | SB_HST_NXM, HBE_LNT, UQ_TYP_DAT); -return tq_putpkt (pkt, TRUE); -} - -/* Port last failure error log packet */ - -t_bool tq_plf (uint32 err) -{ -int32 pkt; - -if (!tq_deqf (&pkt)) /* get log pkt */ - return ERR; -tq_pkt[pkt].d[ELP_REFL] = tq_pkt[pkt].d[ELP_REFH] = 0; /* ref = 0 */ -tq_pkt[pkt].d[ELP_UN] = tq_pkt[pkt].d[ELP_SEQ] = 0; /* no unit, seq */ -tq_pkt[pkt].d[PLF_CIDA] = 0; /* cntl ID */ -tq_pkt[pkt].d[PLF_CIDB] = 0; -tq_pkt[pkt].d[PLF_CIDC] = 0; -tq_pkt[pkt].d[PLF_CIDD] = (TQ_CLASS << PLF_CIDD_V_CLS) | - (drv_tab[tq_typ].cmod << PLF_CIDD_V_MOD); -tq_pkt[pkt].d[PLF_VER] = drv_tab[tq_typ].cver; -tq_pkt[pkt].d[PLF_ERR] = err; -tq_putr (pkt, FM_CNT, LF_SNR, ST_CNT, PLF_LNT, UQ_TYP_DAT); -tq_pkt[pkt].d[UQ_HCTC] |= (UQ_CID_DIAG << UQ_HCTC_V_CID); -return tq_putpkt (pkt, TRUE); -} - -/* Unit now available attention packet */ - -int32 tq_una (UNIT *uptr) -{ -int32 pkt; -uint32 lu; - -if (!tq_deqf (&pkt)) /* get log pkt */ - return ERR; -lu = (uint32) (uptr - tq_dev.units); /* get unit */ -tq_pkt[pkt].d[RSP_REFL] = tq_pkt[pkt].d[RSP_REFH] = 0; /* ref = 0 */ -tq_pkt[pkt].d[RSP_UN] = lu; -tq_pkt[pkt].d[RSP_RSV] = 0; -tq_putr_unit (pkt, uptr, lu, FALSE); /* fill unit fields */ -tq_putr (pkt, OP_AVA, 0, 0, UNA_LNT, UQ_TYP_SEQ); /* fill std fields */ -return tq_putpkt (pkt, TRUE); -} - -/* List handling - - tq_deqf - dequeue head of free list (fatal err if none) - tq_deqh - dequeue head of list - tq_enqh - enqueue at head of list - tq_enqt - enqueue at tail of list -*/ - -t_bool tq_deqf (int32 *pkt) -{ -if (tq_freq == 0) /* no free pkts?? */ - return tq_fatal (PE_NSR); -tq_pbsy = tq_pbsy + 1; /* cnt busy pkts */ -*pkt = tq_freq; /* head of list */ -tq_freq = tq_pkt[tq_freq].link; /* next */ -return OK; -} - -int32 tq_deqh (int32 *lh) -{ -int32 ptr = *lh; /* head of list */ - -if (ptr) /* next */ - *lh = tq_pkt[ptr].link; -return ptr; -} - -void tq_enqh (int32 *lh, int32 pkt) -{ -if (pkt == 0) /* any pkt? */ - return; -tq_pkt[pkt].link = *lh; /* link is old lh */ -*lh = pkt; /* pkt is new lh */ -return; -} - -void tq_enqt (int32 *lh, int32 pkt) -{ -if (pkt == 0) /* any pkt? */ - return; -tq_pkt[pkt].link = 0; /* it will be tail */ -if (*lh == 0) /* if empty, enqh */ - *lh = pkt; -else { - uint32 ptr = *lh; /* chase to end */ - while (tq_pkt[ptr].link) - ptr = tq_pkt[ptr].link; - tq_pkt[ptr].link = pkt; /* enq at tail */ - } -return; -} - -/* Packet and descriptor handling */ - -/* Get packet from command ring */ - -t_bool tq_getpkt (int32 *pkt) -{ -uint32 addr, desc; - -if (!tq_getdesc (&tq_cq, &desc)) /* get cmd desc */ - return ERR; -if ((desc & UQ_DESC_OWN) == 0) { /* none */ - *pkt = 0; /* pkt = 0 */ - return OK; /* no error */ - } -if (!tq_deqf (pkt)) /* get cmd pkt */ - return ERR; -tq_hat = 0; /* dsbl hst timer */ -addr = desc & UQ_ADDR; /* get Q22 addr */ -if (Map_ReadW (addr + UQ_HDR_OFF, TQ_PKT_SIZE, tq_pkt[*pkt].d)) - return tq_fatal (PE_PRE); /* read pkt */ -return tq_putdesc (&tq_cq, desc); /* release desc */ -} - -/* Put packet to response ring - note the clever hack about credits. - The controller sends all its credits to the host. Thereafter, it - supplies one credit for every response packet sent over. Simple! -*/ - -t_bool tq_putpkt (int32 pkt, t_bool qt) -{ -uint32 addr, desc, lnt, cr; - -if (pkt == 0) /* any packet? */ - return OK; -if (DEBUG_PRS (tq_dev)) { - UNIT *up = tq_getucb (tq_pkt[pkt].d[CMD_UN]); - fprintf (sim_deb, ">>TQ: rsp=%04X, sts=%04X", - tq_pkt[pkt].d[RSP_OPF], tq_pkt[pkt].d[RSP_STS]); - if (up) { - fprintf (sim_deb, ", pos="); - fprint_val (sim_deb, up->pos, 10, T_ADDR_W, PV_LEFT); - fprintf (sim_deb, ", obj=%d\n", up->objp); - } - else fprintf (sim_deb, "\n"); - fflush (sim_deb); - } -if (!tq_getdesc (&tq_rq, &desc)) /* get rsp desc */ - return ERR; -if ((desc & UQ_DESC_OWN) == 0) { /* not valid? */ - if (qt) /* normal? q tail */ - tq_enqt (&tq_rspq, pkt); - else tq_enqh (&tq_rspq, pkt); /* resp q call */ - sim_activate (&tq_unit[TQ_QUEUE], tq_qtime); /* activate q thrd */ - return OK; - } -addr = desc & UQ_ADDR; /* get Q22 addr */ -lnt = tq_pkt[pkt].d[UQ_HLNT] - UQ_HDR_OFF; /* size, with hdr */ -if ((GETP (pkt, UQ_HCTC, TYP) == UQ_TYP_SEQ) && /* seq packet? */ - (GETP (pkt, CMD_OPC, OPC) & OP_END)) { /* end packet? */ - cr = (tq_credits >= 14)? 14: tq_credits; /* max 14 credits */ - tq_credits = tq_credits - cr; /* decr credits */ - tq_pkt[pkt].d[UQ_HCTC] |= ((cr + 1) << UQ_HCTC_V_CR); - } -if (Map_WriteW (addr + UQ_HDR_OFF, lnt, tq_pkt[pkt].d)) - return tq_fatal (PE_PWE); /* write pkt */ -tq_enqh (&tq_freq, pkt); /* pkt is free */ -tq_pbsy = tq_pbsy - 1; /* decr busy cnt */ -if (tq_pbsy == 0) /* idle? strt hst tmr */ - tq_hat = tq_htmo; -return tq_putdesc (&tq_rq, desc); /* release desc */ -} - -/* Get a descriptor from the host */ - -t_bool tq_getdesc (struct uq_ring *ring, uint32 *desc) -{ -uint32 addr = ring->ba + ring->idx; -uint16 d[2]; - -if (Map_ReadW (addr, 4, d)) /* fetch desc */ - return tq_fatal (PE_QRE); /* err? dead */ -*desc = ((uint32) d[0]) | (((uint32) d[1]) << 16); -return OK; -} - -/* Return a descriptor to the host, clearing owner bit - If rings transitions from "empty" to "not empty" or "full" to - "not full", and interrupt bit was set, interrupt the host. - Actually, test whether previous ring entry was owned by host. -*/ - -t_bool tq_putdesc (struct uq_ring *ring, uint32 desc) -{ -uint32 prvd, newd = (desc & ~UQ_DESC_OWN) | UQ_DESC_F; -uint32 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)) /* store desc */ - return tq_fatal (PE_QWE); /* err? dead */ -if (desc & UQ_DESC_F) { /* was F set? */ - if (ring->lnt <= 4) /* lnt = 1? intr */ - tq_ring_int (ring); - else { - prva = ring->ba + /* prv desc */ - ((ring->idx - 4) & (ring->lnt - 1)); - if (Map_ReadW (prva, 4, d)) /* read prv */ - return tq_fatal (PE_QRE); - prvd = ((uint32) d[0]) | (((uint32) d[1]) << 16); - if (prvd & UQ_DESC_OWN) - tq_ring_int (ring); - } - } -ring->idx = (ring->idx + 4) & (ring->lnt - 1); -return OK; -} - -/* Get unit descriptor for logical unit - trivial now, - but eventually, hide multiboard complexities here */ - -UNIT *tq_getucb (uint32 lu) -{ -UNIT *uptr; - -if (lu >= TQ_NUMDR) - return NULL; -uptr = tq_dev.units + lu; -if (uptr->flags & UNIT_DIS) - return NULL; -return uptr; -} - -/* Hack unit flags */ - -void tq_setf_unit (int32 pkt, UNIT *uptr) -{ -uptr->uf = tq_pkt[pkt].d[ONL_UFL] & UF_MSK; /* settable flags */ -if ((tq_pkt[pkt].d[CMD_MOD] & MD_SWP) && /* swre wrp enb? */ - (tq_pkt[pkt].d[ONL_UFL] & UF_WPS)) /* swre wrp on? */ - uptr->uf = uptr->uf | UF_WPS; /* simon says... */ -return; -} - -/* Hack end flags */ - -uint32 tq_efl (UNIT *uptr) -{ -uint32 t = 0; - -if (uptr) { /* any unit? */ - if (uptr->flags & UNIT_POL) /* note pos lost */ - t = t | EF_PLS; - if (uptr->flags & UNIT_SXC) /* note ser exc */ - t = t | EF_SXC; - if (TEST_EOT (uptr)) /* note EOT */ - t = t | EF_EOT; - } -return t; -} - -/* Unit response fields */ - -void tq_putr_unit (int32 pkt, UNIT *uptr, uint32 lu, t_bool all) -{ -tq_pkt[pkt].d[ONL_MLUN] = lu; /* multi-unit */ -tq_pkt[pkt].d[ONL_UFL] = uptr->uf | TQ_WPH (uptr); /* unit flags */ -tq_pkt[pkt].d[ONL_UFL] |= tq_efl (uptr); /* end flags accordingly */ -tq_pkt[pkt].d[ONL_RSVL] = tq_pkt[pkt].d[ONL_RSVH] = 0; /* reserved */ -tq_pkt[pkt].d[ONL_UIDA] = lu; /* UID low */ -tq_pkt[pkt].d[ONL_UIDB] = 0; -tq_pkt[pkt].d[ONL_UIDC] = 0; -tq_pkt[pkt].d[ONL_UIDD] = (UID_TAPE << ONL_UIDD_V_CLS) | - (drv_tab[tq_typ].umod << ONL_UIDD_V_MOD); /* UID hi */ -PUTP32 (pkt, ONL_MEDL, drv_tab[tq_typ].med); /* media type */ -if (all) { /* if long form */ - tq_pkt[pkt].d[ONL_FMT] = drv_tab[tq_typ].fmt; /* format */ - tq_pkt[pkt].d[ONL_SPD] = 0; /* speed */ - PUTP32 (pkt, ONL_MAXL, TQ_MAXFR); /* max xfr */ - tq_pkt[pkt].d[ONL_NREC] = 0; /* noise rec */ - tq_pkt[pkt].d[ONL_RSVE] = 0; /* reserved */ - } -return; -} - -/* UQ_HDR and RSP_OP fields */ - -void tq_putr (int32 pkt, uint32 cmd, uint32 flg, uint32 sts, uint32 lnt, uint32 typ) -{ -tq_pkt[pkt].d[RSP_OPF] = (cmd << RSP_OPF_V_OPC) | /* set cmd, flg */ - (flg << RSP_OPF_V_FLG); -tq_pkt[pkt].d[RSP_STS] = sts; -tq_pkt[pkt].d[UQ_HLNT] = lnt; /* length */ -tq_pkt[pkt].d[UQ_HCTC] = (typ << UQ_HCTC_V_TYP) | /* type, cid */ - (UQ_CID_TMSCP << UQ_HCTC_V_CID); /* clr credits */ -return; -} - -/* Post interrupt during init */ - -void tq_init_int (void) -{ -if ((tq_s1dat & SA_S1H_IE) && tq_dib.vec) - SET_INT (TQ); -return; -} - -/* Post interrupt during putpkt - note that NXMs are ignored! */ - -void tq_ring_int (struct uq_ring *ring) -{ -uint32 iadr = tq_comm + ring->ioff; /* addr intr wd */ -uint16 flag = 1; - -Map_WriteW (iadr, 2, &flag); /* write flag */ -if (tq_dib.vec) /* if enb, intr */ - SET_INT (TQ); -return; -} - -/* Return interrupt vector */ - -int32 tq_inta (void) -{ -return tq_dib.vec; /* prog vector */ -} - -/* Fatal error */ - -t_bool tq_fatal (uint32 err) -{ -if (DEBUG_PRS (tq_dev)) - fprintf (sim_deb, ">>TQ: fatal err=%X\n", err); -tq_reset (&tq_dev); /* reset device */ -tq_sa = SA_ER | err; /* SA = dead code */ -tq_csta = CST_DEAD; /* state = dead */ -tq_perr = err; /* save error */ -return ERR; -} - -/* Device attach */ - -t_stat tq_attach (UNIT *uptr, char *cptr) -{ -t_stat r; - -r = sim_tape_attach (uptr, cptr); -if (r != SCPE_OK) - return r; -if (tq_csta == CST_UP) - uptr->flags = (uptr->flags | UNIT_ATP) & ~(UNIT_SXC | UNIT_POL | UNIT_TMK); -return SCPE_OK; -} - -/* Device detach */ - -t_stat tq_detach (UNIT *uptr) -{ -t_stat r; - -r = sim_tape_detach (uptr); /* detach unit */ -if (r != SCPE_OK) - return r; -uptr->flags = uptr->flags & ~(UNIT_ONL | UNIT_ATP | UNIT_SXC | UNIT_POL | UNIT_TMK); -uptr->uf = 0; /* clr unit flgs */ -return SCPE_OK; -} - -/* Device reset */ - -t_stat tq_reset (DEVICE *dptr) -{ -int32 i, j; -UNIT *uptr; - -tq_csta = CST_S1; /* init stage 1 */ -tq_s1dat = 0; /* no S1 data */ -tq_dib.vec = 0; /* no vector */ -if (UNIBUS) /* Unibus? */ - tq_sa = SA_S1 | SA_S1C_DI | SA_S1C_MP; -else tq_sa = SA_S1 | SA_S1C_Q22 | SA_S1C_DI | SA_S1C_MP; /* init SA val */ -tq_cflgs = CF_RPL; /* ctrl flgs off */ -tq_htmo = TQ_DHTMO; /* default timeout */ -tq_hat = tq_htmo; /* default timer */ -tq_cq.ba = tq_cq.lnt = tq_cq.idx = 0; /* clr cmd ring */ -tq_rq.ba = tq_rq.lnt = tq_rq.idx = 0; /* clr rsp ring */ -tq_credits = (TQ_NPKTS / 2) - 1; /* init credits */ -tq_freq = 1; /* init free list */ -for (i = 0; i < TQ_NPKTS; i++) { /* all pkts free */ - if (i) - tq_pkt[i].link = (i + 1) & TQ_M_NPKTS; - else tq_pkt[i].link = 0; - for (j = 0; j < TQ_PKT_SIZE_W; j++) - tq_pkt[i].d[j] = 0; - } -tq_rspq = 0; /* no q'd rsp pkts */ -tq_pbsy = 0; /* all pkts free */ -tq_pip = 0; /* not polling */ -CLR_INT (TQ); /* clr intr req */ -for (i = 0; i < TQ_NUMDR + 2; i++) { /* init units */ - uptr = tq_dev.units + i; - sim_cancel (uptr); /* clr activity */ - sim_tape_reset (uptr); - uptr->flags = uptr->flags & /* not online */ - ~(UNIT_ONL|UNIT_ATP|UNIT_SXC|UNIT_POL|UNIT_TMK); - uptr->uf = 0; /* clr unit flags */ - uptr->cpkt = uptr->pktq = 0; /* clr pkt q's */ - } -if (tqxb == NULL) - tqxb = (uint8 *) calloc (TQ_MAXFR, sizeof (uint8)); -if (tqxb == NULL) - return SCPE_MEM; -return SCPE_OK; -} - -/* Device bootstrap */ - -#if defined (VM_PDP11) - -#define BOOT_START 016000 /* start */ -#define BOOT_ENTRY (BOOT_START + 002) /* entry */ -#define BOOT_UNIT (BOOT_START + 010) /* unit number */ -#define BOOT_CSR (BOOT_START + 014) /* CSR */ -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) - -/* Data structure definitions */ - -#define B_CMDINT (BOOT_START - 01000) /* cmd int */ -#define B_RSPINT (B_CMDINT + 002) /* rsp int */ -#define B_RING (B_RSPINT + 002) /* ring base */ -#define B_RSPH (B_RING + 010) /* resp pkt hdr */ -#define B_TKRSP (B_RSPH + 004) /* resp pkt */ -#define B_CMDH (B_TKRSP + 060) /* cmd pkt hdr */ -#define B_TKCMD (B_CMDH + 004) /* cmd pkt */ -#define B_UNIT (B_TKCMD + 004) /* unit # */ - -static const uint16 boot_rom[] = { - - 0046525, /* ST: "UM" */ - - 0012706, 0016000, /* mov #st,sp */ - 0012700, 0000000, /* mov #unitno,r0 */ - 0012701, 0174500, /* mov #174500,r1 ; ip addr */ - 0005021, /* clr (r1)+ ; init */ - 0012704, 0004000, /* mov #4000,r4 ; s1 mask */ - 0005002, /* clr r2 */ - 0005022, /* 10$: clr (r2)+ ; clr up to boot */ - 0020237, BOOT_START - 2, /* cmp r2,#st-2 */ - 0103774, /* blo 10$ */ - 0012705, BOOT_START+0312, /* mov #cmdtbl,r5 ; addr of tbl */ - - /* Four step init process */ - - 0005711, /* 20$: tst (r1) ; err? */ - 0100001, /* bpl 30$ */ - 0000000, /* halt */ - 0030411, /* 30$: bit r4,(r1) ; step set? */ - 0001773, /* beq 20$ ; wait */ - 0012511, /* mov (r5)+,(r1) ; send next */ - 0006304, /* asl r4 ; next mask */ - 0100370, /* bpl 20$ ; s4 done? */ - - /* Set up rings, issue ONLINE, REWIND, READ */ - - 0012737, 0000400, B_CMDH + 2, /* mov #400,cmdh+2 ; VCID = 1 */ - 0012737, 0000044, B_CMDH, /* mov #36.,cmdh ; cmd pkt lnt */ - 0010037, B_UNIT, /* mov r0,unit ; unit # */ - 0012737, 0000011, B_TKCMD + 8, /* mov #11,tkcmd+8. ; online op */ - 0012737, 0020000, B_TKCMD + 10, /* mov #20000,tkcmd+10. ; clr ser ex */ - 0012702, B_RING, /* mov #ring,r2 ; init rings */ - 0012722, B_TKRSP, /* mov #tkrsp,(r2)+ ; rsp pkt addr */ - 0010203, /* mov r2,r3 ; save ring+2 */ - 0010423, /* mov r4,(r3)+ ; set TK own */ - 0012723, B_TKCMD, /* mov #tkcmd,(r3)+ ; cmd pkt addr */ - 0010423, /* mov r4,(r3)+ ; set TK own */ - 0005741, /* tst -(r1) ; start poll */ - 0005712, /* 40$: tst (r2) ; wait for resp */ - 0100776, /* bmi 40$ */ - 0105737, B_TKRSP + 10, /* tstb tkrsp+10. ; check stat */ - 0001401, /* beq 50$ */ - 0000000, /* halt */ - 0012703, B_TKCMD + 8, /* 50$: mov #tkcmd+8.,r3 */ - 0012723, 0000045, /* mov #45,(r3)+ ; reposition */ - 0012723, 0020002, /* mov #20002,(r3)+ ; rew, clr exc */ - 0012723, 0000001, /* mov #1,(r3)+ ; lo rec skp */ - 0005023, /* clr (r3)+ ; hi rec skp */ - 0005023, /* clr (r3)+ ; lo tmk skp */ - 0005023, /* clr (r3)+ ; hi tmk skp */ - 0010412, /* mov r4,(r2) ; TK own rsp */ - 0010437, B_RING + 6, /* mov r4,ring+6 ; TK own cmd */ - 0005711, /* tst (r1) ; start poll */ - 0005712, /* 60$: tst (r2) ; wait for resp */ - 0100776, /* bmi 60$ */ - 0105737, B_TKRSP + 10, /* tstb tkrsp+10. ; check stat */ - 0001401, /* beq 70$ */ - 0000000, /* halt */ - 0012703, B_TKCMD + 8, /* 70$: mov #tkcmd+8.,r3 */ - 0012723, 0000041, /* mov #41,(r3)+ ; read */ - 0012723, 0020000, /* mov #20000,(r3)+ ; clr exc */ - 0012723, 0001000, /* mov #512.,(r3)+ ; bc = 512 */ - 0005023, /* clr (r3)+ ; clr args */ - 0005023, /* clr (r3)+ ; ba = 0 */ - 0010412, /* mov r4,(r2) ; TK own rsp */ - 0010437, B_RING + 6, /* mov r4,ring+6 ; TK own cmd */ - 0005711, /* tst (r1) ; start poll */ - 0005712, /* 80$: tst (r2) ; wait for resp */ - 0100776, /* bmi 80$ */ - 0105737, B_TKRSP + 10, /* tstb tkrsp+10. ; check stat */ - 0001401, /* beq 90$ */ - 0000000, /* halt */ - - /* Boot block read in, jump to 0 - leave controller init'd */ - - 0005003, /* clr r3 */ - 0012704, BOOT_START+020, /* mov #st+020,r4 */ - 0005005, /* clr r5 */ - 0005007, /* clr pc */ - - 0100000, /* cmdtbl: init step 1 */ - B_RING, /* ring base */ - 0000000, /* high ring base */ - 0000001 /* go */ - }; - -t_stat tq_boot (int32 unitno, DEVICE *dptr) -{ -int32 i; -extern uint16 *M; - -for (i = 0; i < BOOT_LEN; i++) - M[(BOOT_START >> 1) + i] = boot_rom[i]; -M[BOOT_UNIT >> 1] = unitno & 3; -M[BOOT_CSR >> 1] = tq_dib.ba & DMASK; -cpu_set_boot (BOOT_ENTRY); -return SCPE_OK; -} - -#else - -t_stat tq_boot (int32 unitno, DEVICE *dptr) -{ -return SCPE_NOFNC; -} - -#endif - -/* Special show commands */ - -void tq_show_ring (FILE *st, struct uq_ring *rp) -{ -uint32 i, desc; -uint16 d[2]; - -#if defined (VM_PDP11) -fprintf (st, "ring, base = %o, index = %d, length = %d\n", - rp->ba, rp->idx >> 2, rp->lnt >> 2); -#else -fprintf (st, "ring, base = %x, index = %d, length = %d\n", - rp->ba, rp->idx >> 2, rp->lnt >> 2); -#endif -for (i = 0; i < (rp->lnt >> 2); i++) { - if (Map_ReadW (rp->ba + (i << 2), 4, d)) { - fprintf (st, " %3d: non-existent memory\n", i); - break; - } - desc = ((uint32) d[0]) | (((uint32) d[1]) << 16); -#if defined (VM_PDP11) - fprintf (st, " %3d: %011o\n", i, desc); -#else - fprintf (st, " %3d: %08x\n", i, desc); -#endif - } -return; -} - -void tq_show_pkt (FILE *st, int32 pkt) -{ -int32 i, j; -uint32 cr = GETP (pkt, UQ_HCTC, CR); -uint32 typ = GETP (pkt, UQ_HCTC, TYP); -uint32 cid = GETP (pkt, UQ_HCTC, CID); - -fprintf (st, "packet %d, credits = %d, type = %d, cid = %d\n", - pkt, cr, typ, cid); -for (i = 0; i < TQ_SH_MAX; i = i + TQ_SH_PPL) { - fprintf (st, " %2d:", i); - for (j = i; j < (i + TQ_SH_PPL); j++) -#if defined (VM_PDP11) - fprintf (st, " %06o", tq_pkt[pkt].d[j]); -#else - fprintf (st, " %04x", tq_pkt[pkt].d[j]); -#endif - fprintf (st, "\n"); - } -return; -} - -t_stat tq_show_unitq (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -int32 pkt, u = uptr - tq_dev.units; - -if (tq_csta != CST_UP) { - fprintf (st, "Controller is not initialized\n"); - return SCPE_OK; - } -if ((uptr->flags & UNIT_ONL) == 0) { - if (uptr->flags & UNIT_ATT) - fprintf (st, "Unit %d is available\n", u); - else fprintf (st, "Unit %d is offline\n", u); - return SCPE_OK; - } -if (uptr->cpkt) { - fprintf (st, "Unit %d current ", u); - tq_show_pkt (st, uptr->cpkt); - if (pkt = uptr->pktq) { - do { - fprintf (st, "Unit %d queued ", u); - tq_show_pkt (st, pkt); - } while (pkt = tq_pkt[pkt].link); - } - } -else fprintf (st, "Unit %d queues are empty\n", u); -return SCPE_OK; -} - -t_stat tq_show_ctrl (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -int32 i, pkt; - -if (tq_csta != CST_UP) { - fprintf (st, "Controller is not initialized\n"); - return SCPE_OK; - } -if (val & TQ_SH_RI) { - if (tq_pip) - fprintf (st, "Polling in progress, host timer = %d\n", tq_hat); - else fprintf (st, "Host timer = %d\n", tq_hat); - fprintf (st, "Command "); - tq_show_ring (st, &tq_cq); - fprintf (st, "Response "); - tq_show_ring (st, &tq_rq); - } -if (val & TQ_SH_FR) { - if (pkt = tq_freq) { - for (i = 0; pkt != 0; i++, pkt = tq_pkt[pkt].link) { - if (i == 0) - fprintf (st, "Free queue = %d", pkt); - else if ((i % 16) == 0) - fprintf (st, ",\n %d", pkt); - else fprintf (st, ", %d", pkt); - } - fprintf (st, "\n"); - } - else fprintf (st, "Free queue is empty\n"); - } -if (val & TQ_SH_RS) { - if (pkt = tq_rspq) { - do { - fprintf (st, "Response "); - tq_show_pkt (st, pkt); - } while (pkt = tq_pkt[pkt].link); - } - else fprintf (st, "Response queue is empty\n"); - } -if (val & TQ_SH_UN) { - for (i = 0; i < TQ_NUMDR; i++) - tq_show_unitq (st, &tq_unit[i], 0, NULL); - } -return SCPE_OK; -} - -/* Set controller type (and capacity for user-defined type) */ - -t_stat tq_set_type (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -uint32 i, cap; -uint32 max = sim_taddr_64? TQU_EMAXC: TQU_MAXC; -t_stat r; - -if ((val < 0) || (val > TQU_TYPE) || ((val != TQU_TYPE) && cptr)) - return SCPE_ARG; -for (i = 0; i < TQ_NUMDR; i++) { - if (tq_unit[i].flags & UNIT_ATT) - return SCPE_ALATT; - } -if (cptr) { - cap = (uint32) get_uint (cptr, 10, max, &r); - if ((r != SCPE_OK) || (cap < TQU_MINC)) - return SCPE_ARG; - drv_tab[TQU_TYPE].cap = ((t_addr) cap) << 20; - } -tq_typ = val; -for (i = 0; i < TQ_NUMDR; i++) - tq_unit[i].capac = drv_tab[tq_typ].cap; -return SCPE_OK; -} - -/* Show controller type and capacity */ - -t_stat tq_show_type (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -fprintf (st, "%s (%dMB)", drv_tab[tq_typ].name, (uint32) (drv_tab[tq_typ].cap >> 20)); -return SCPE_OK; -} diff --git a/PDP11/pdp11_ts.c b/PDP11/pdp11_ts.c deleted file mode 100644 index abd7157f..00000000 --- a/PDP11/pdp11_ts.c +++ /dev/null @@ -1,1171 +0,0 @@ -/* pdp11_ts.c: TS11/TSV05 magnetic tape simulator - - Copyright (c) 1993-2014, 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. - - ts TS11/TSV05 magtape - - 27-Oct-14 RMS Fixed bug in read forward with byte swap - 23-Oct-13 RMS Revised for new boot setup routine - 19-Mar-12 RMS Fixed declaration of cpu_opt (Mark Pizzolato) - 22-May-10 RMS Fixed t_addr printouts for 64b big-endian systems - (Mark Pizzolato) - 16-Feb-06 RMS Added tape capacity checking - 31-Oct-05 RMS Fixed address width for large files - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 07-Jul-05 RMS Removed extraneous externs - 18-Mar-05 RMS Added attached test to detach routine - 07-Dec-04 RMS Added read-only file support - 30-Sep-04 RMS Revised Unibus interface - 25-Jan-04 RMS Revised for device debug support - 19-May-03 RMS Revised for new conditional compilation scheme - 25-Apr-03 RMS Revised for extended file support - 28-Mar-03 RMS Added multiformat support - 28-Feb-03 RMS Revised to use magtape library - 30-Sep-02 RMS Added variable address support to bootstrap - Added vector change/display support - Fixed CTL unload/clean decode - Implemented XS0_MOT in extended status - New data structures, revamped error recovery - 28-Aug-02 RMS Added end of medium support - 30-May-02 RMS Widened POS to 32b - 22-Apr-02 RMS Added maximum record length protection - 04-Apr-02 RMS Fixed bug in residual frame count after space operation - 16-Feb-02 RMS Fixed bug in message header logic - 26-Jan-02 RMS Revised bootstrap to conform to M9312 - 06-Jan-02 RMS Revised enable/disable support - 30-Nov-01 RMS Added read only unit, extended SET/SHOW support - 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 - 19-Sep-01 RMS Fixed bug in bootstrap - 15-Sep-01 RMS Fixed bug in NXM test - 07-Sep-01 RMS Revised device disable and interrupt mechanism - 13-Jul-01 RMS Fixed bug in space reverse (Peter Schorn) - - Magnetic tapes are represented as a series of variable 8b records - of the form: - - 32b record length in bytes - exact number - byte 0 - byte 1 - : - byte n-2 - byte n-1 - 32b record length in bytes - exact number - - 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 (VM_PDP10) /* PDP10 version */ -#error "TS11 not supported on PDP10!" - -#elif defined (VM_VAX) /* VAX version */ -#include "vax_defs.h" -#define TS_DIS 0 /* on by default */ -#define DMASK 0xFFFF - -#else /* PDP-11 version */ -#include "pdp11_defs.h" -#define TS_DIS DEV_DIS /* off by default */ -extern uint32 cpu_opt; -#endif - -#include "sim_tape.h" -#define ADDRTEST (UNIBUS? 0177774: 0177700) - -/* TSBA/TSDB - 17772520: base address/data buffer register - - read: most recent memory address - write word: initiate command - write byte: diagnostic use -*/ - -/* TSSR - 17772522: subsystem status register - TSDBX - 17772523: extended address register - - read: return status - write word: initialize - write byte: if odd, set extended packet address register -*/ - -#define TSSR_SC 0100000 /* special condition */ -#define TSSR_RMR 0010000 /* reg mod refused */ -#define TSSR_NXM 0004000 /* nxm */ -#define TSSR_NBA 0002000 /* need buf addr */ -#define TSSR_V_EMA 8 /* mem addr<17:16> */ -#define TSSR_EMA 0001400 -#define TSSR_SSR 0000200 /* subsystem ready */ -#define TSSR_OFL 0000100 /* offline */ -#define TSSR_V_TC 1 /* term class */ -#define TSSR_M_TC 07 -#define TSSR_TC (TSSR_M_TC << TSSR_V_TC) -#define TC0 (0 << TSSR_V_TC) /* ok */ -#define TC1 (1 << TSSR_V_TC) /* attention */ -#define TC2 (2 << TSSR_V_TC) /* status alert */ -#define TC3 (3 << TSSR_V_TC) /* func reject */ -#define TC4 (4 << TSSR_V_TC) /* retry, moved */ -#define TC5 (5 << TSSR_V_TC) /* retry */ -#define TC6 (6 << TSSR_V_TC) /* pos lost */ -#define TC7 (7 << TSSR_V_TC) /* fatal err */ -#define TSSR_MBZ 0060060 -#define GET_TC(x) (((x) >> TSSR_V_TC) & TSSR_M_TC) - -#define TSDBX_M_XA 017 /* ext addr */ -#define TSDBX_BOOT 0000200 /* boot */ - -/* Command packet offsets */ - -#define CMD_PLNT 4 /* cmd pkt length */ -#define cmdhdr tscmdp[0] /* header */ -#define cmdadl tscmdp[1] /* address low */ -#define cmdadh tscmdp[2] /* address high */ -#define cmdlnt tscmdp[3] /* length */ - -/* Command packet header */ - -#define CMD_ACK 0100000 /* acknowledge */ -#define CMD_CVC 0040000 /* clear vol chk */ -#define CMD_OPP 0020000 /* opposite */ -#define CMD_SWP 0010000 /* swap bytes */ -#define CMD_V_MODE 8 /* mode */ -#define CMD_M_MODE 017 -#define CMD_IE 0000200 /* int enable */ -#define CMD_V_FNC 0 /* function */ -#define CMD_M_FNC 037 /* function */ -#define CMD_N_FNC (CMD_M_FNC + 1) -#define FNC_READ 001 /* read */ -#define FNC_WCHR 004 /* write char */ -#define FNC_WRIT 005 /* write */ -#define FNC_WSSM 006 /* write mem */ -#define FNC_POS 010 /* position */ -#define FNC_FMT 011 /* format */ -#define FNC_CTL 012 /* control */ -#define FNC_INIT 013 /* init */ -#define FNC_GSTA 017 /* get status */ -#define CMD_MBZ 0000140 -#define GET_FNC(x) (((x) >> CMD_V_FNC) & CMD_M_FNC) -#define GET_MOD(x) (((x) >> CMD_V_MODE) & CMD_M_MODE) - -/* Function test flags */ - -#define FLG_MO 001 /* motion */ -#define FLG_WR 002 /* write */ -#define FLG_AD 004 /* addr mem */ - -/* Message packet offsets */ - -#define MSG_PLNT 8 /* packet length */ -#define msghdr tsmsgp[0] /* header */ -#define msglnt tsmsgp[1] /* length */ -#define msgrfc tsmsgp[2] /* residual frame */ -#define msgxs0 tsmsgp[3] /* ext status 0 */ -#define msgxs1 tsmsgp[4] /* ext status 1 */ -#define msgxs2 tsmsgp[5] /* ext status 2 */ -#define msgxs3 tsmsgp[6] /* ext status 3 */ -#define msgxs4 tsmsgp[7] /* ext status 4 */ - -/* Message packet header */ - -#define MSG_ACK 0100000 /* acknowledge */ -#define MSG_MATN 0000000 /* attention */ -#define MSG_MILL 0000400 /* illegal */ -#define MSG_MNEF 0001000 /* non exec fnc */ -#define MSG_CEND 0000020 /* end */ -#define MSG_CFAIL 0000021 /* fail */ -#define MSG_CERR 0000022 /* error */ -#define MSG_CATN 0000023 /* attention */ - -/* Extended status register 0 */ - -#define XS0_TMK 0100000 /* tape mark */ -#define XS0_RLS 0040000 /* rec lnt short */ -#define XS0_LET 0020000 /* log end tape */ -#define XS0_RLL 0010000 /* rec lnt long */ -#define XS0_WLE 0004000 /* write lock err */ -#define XS0_NEF 0002000 /* non exec fnc */ -#define XS0_ILC 0001000 /* illegal cmd */ -#define XS0_ILA 0000400 /* illegal addr */ -#define XS0_MOT 0000200 /* tape has moved */ -#define XS0_ONL 0000100 /* online */ -#define XS0_IE 0000040 /* int enb */ -#define XS0_VCK 0000020 /* volume check */ -#define XS0_PET 0000010 /* 1600 bpi */ -#define XS0_WLK 0000004 /* write lock */ -#define XS0_BOT 0000002 /* BOT */ -#define XS0_EOT 0000001 /* EOT */ -#define XS0_ALLCLR 0177600 /* clear at start */ - -/* Extended status register 1 */ - -#define XS1_UCOR 0000002 /* uncorrectable */ - -/* Extended status register 2 */ - -#define XS2_XTF 0000200 /* ext features */ - -/* Extended status register 3 */ - -#define XS3_OPI 0000100 /* op incomplete */ -#define XS3_REV 0000040 /* reverse */ -#define XS3_RIB 0000001 /* reverse to BOT */ - -/* Extended status register 4 */ - -#define XS4_HDS 0100000 /* high density */ - -/* Write characteristics packet offsets */ - -#define WCH_PLNT 5 /* packet length */ -#define wchadl tswchp[0] /* address low */ -#define wchadh tswchp[1] /* address high */ -#define wchlnt tswchp[2] /* length */ -#define wchopt tswchp[3] /* options */ -#define wchxopt tswchp[4] /* ext options */ - -/* Write characteristics options */ - -#define WCH_ESS 0000200 /* stop dbl tmk */ -#define WCH_ENB 0000100 /* BOT = tmk */ -#define WCH_EAI 0000040 /* enb attn int */ -#define WCH_ERI 0000020 /* enb mrls int */ - -/* Write characteristics extended options */ - -#define WCHX_HDS 0000040 /* high density */ - -#define MAX(a,b) (((a) >= (b))? (a): (b)) -#define MAX_PLNT 8 /* max pkt length */ - -extern int32 int_req[IPL_HLVL]; -extern UNIT cpu_unit; - -uint8 *tsxb = NULL; /* xfer buffer */ -int32 tssr = 0; /* status register */ -int32 tsba = 0; /* mem addr */ -int32 tsdbx = 0; /* data buf ext */ -int32 tscmdp[CMD_PLNT] = { 0 }; /* command packet */ -int32 tsmsgp[MSG_PLNT] = { 0 }; /* message packet */ -int32 tswchp[WCH_PLNT] = { 0 }; /* wr char packet */ -int32 ts_ownc = 0; /* tape owns cmd */ -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 */ -static uint16 cpy_buf[MAX_PLNT]; /* copy buffer */ - -t_stat ts_rd (int32 *data, int32 PA, int32 access); -t_stat ts_wr (int32 data, int32 PA, int32 access); -t_stat ts_svc (UNIT *uptr); -t_stat ts_reset (DEVICE *dptr); -t_stat ts_attach (UNIT *uptr, char *cptr); -t_stat ts_detach (UNIT *uptr); -t_stat ts_boot (int32 unitno, DEVICE *dptr); -int32 ts_updtssr (int32 t); -int32 ts_updxs0 (int32 t); -void ts_cmpendcmd (int32 s0, int32 s1); -void ts_endcmd (int32 ssf, int32 xs0f, int32 msg); -int32 ts_map_status (t_stat st); - -/* TS data structures - - ts_dev TS device descriptor - ts_unit TS unit list - ts_reg TS register list - ts_mod TS modifier list -*/ - -DIB ts_dib = { - IOBA_TS, IOLN_TS, &ts_rd, &ts_wr, - 1, IVCL (TS), VEC_TS, { NULL } - }; - -UNIT ts_unit = { UDATA (&ts_svc, UNIT_ATTABLE + UNIT_ROABLE + UNIT_DISABLE, 0) }; - -REG ts_reg[] = { - { GRDATA (TSSR, tssr, DEV_RDX, 16, 0) }, - { GRDATA (TSBA, tsba, DEV_RDX, 22, 0) }, - { GRDATA (TSDBX, tsdbx, DEV_RDX, 8, 0) }, - { GRDATA (CHDR, cmdhdr, DEV_RDX, 16, 0) }, - { GRDATA (CADL, cmdadl, DEV_RDX, 16, 0) }, - { GRDATA (CADH, cmdadh, DEV_RDX, 16, 0) }, - { GRDATA (CLNT, cmdlnt, DEV_RDX, 16, 0) }, - { GRDATA (MHDR, msghdr, DEV_RDX, 16, 0) }, - { GRDATA (MRFC, msgrfc, DEV_RDX, 16, 0) }, - { GRDATA (MXS0, msgxs0, DEV_RDX, 16, 0) }, - { GRDATA (MXS1, msgxs1, DEV_RDX, 16, 0) }, - { GRDATA (MXS2, msgxs2, DEV_RDX, 16, 0) }, - { GRDATA (MXS3, msgxs3, DEV_RDX, 16, 0) }, - { GRDATA (MSX4, msgxs4, DEV_RDX, 16, 0) }, - { GRDATA (WADL, wchadl, DEV_RDX, 16, 0) }, - { GRDATA (WADH, wchadh, DEV_RDX, 16, 0) }, - { GRDATA (WLNT, wchlnt, DEV_RDX, 16, 0) }, - { GRDATA (WOPT, wchopt, DEV_RDX, 16, 0) }, - { GRDATA (WXOPT, wchxopt, DEV_RDX, 16, 0) }, - { FLDATA (INT, IREQ (TS), INT_V_TS) }, - { FLDATA (ATTN, ts_qatn, 0) }, - { FLDATA (BOOT, ts_bcmd, 0) }, - { FLDATA (OWNC, ts_ownc, 0) }, - { FLDATA (OWNM, ts_ownm, 0) }, - { DRDATA (TIME, ts_time, 24), PV_LEFT + REG_NZ }, - { DRDATA (POS, ts_unit.pos, T_ADDR_W), PV_LEFT + REG_RO }, - { GRDATA (DEVADDR, ts_dib.ba, DEV_RDX, 32, 0), REG_HRO }, - { GRDATA (DEVVEC, ts_dib.vec, DEV_RDX, 16, 0), REG_HRO }, - { NULL } - }; - -MTAB ts_mod[] = { - { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, - { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT", - &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, - { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", "CAPACITY", - &sim_tape_set_capac, &sim_tape_show_capac, NULL }, - { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", - &set_vec, &show_vec, NULL }, - { 0 } - }; - -DEVICE ts_dev = { - "TS", &ts_unit, ts_reg, ts_mod, - 1, 10, T_ADDR_W, 1, DEV_RDX, 8, - NULL, NULL, &ts_reset, - &ts_boot, &ts_attach, &ts_detach, - &ts_dib, DEV_DISABLE | TS_DIS | DEV_UBUS | DEV_QBUS | DEV_DEBUG - }; - -/* I/O dispatch routines, I/O addresses 17772520 - 17772522 - - 17772520 TSBA read/write - 17772522 TSSR read/write -*/ - -t_stat ts_rd (int32 *data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 01) { /* decode PA<1> */ - - case 0: /* TSBA */ - *data = tsba & DMASK; /* low 16b of ba */ - break; - case 1: /* TSSR */ - *data = tssr = ts_updtssr (tssr); /* update tssr */ - break; - } - -return SCPE_OK; -} - -t_stat ts_wr (int32 data, int32 PA, int32 access) -{ -int32 i, t; - -switch ((PA >> 1) & 01) { /* decode PA<1> */ - - case 0: /* TSDB */ - if ((tssr & TSSR_SSR) == 0) { /* ready? */ - tssr = tssr | TSSR_RMR; /* no, refuse */ - break; - } - tsba = ((tsdbx & TSDBX_M_XA) << 18) | /* form pkt addr */ - ((data & 03) << 16) | (data & 0177774); - tsdbx = 0; /* clr tsdbx */ - tssr = ts_updtssr (tssr & TSSR_NBA); /* clr ssr, err */ - msgxs0 = ts_updxs0 (msgxs0 & ~XS0_ALLCLR); /* clr, upd xs0 */ - msgrfc = msgxs1 = msgxs2 = msgxs3 = msgxs4 = 0; /* clr status */ - CLR_INT (TS); /* clr int req */ - t = Map_ReadW (tsba, CMD_PLNT << 1, cpy_buf); /* read cmd pkt */ - tsba = tsba + ((CMD_PLNT << 1) - t); /* incr tsba */ - if (t) { /* nxm? */ - ts_endcmd (TSSR_NXM + TC5, 0, MSG_ACK|MSG_MNEF|MSG_CFAIL); - return SCPE_OK; - } - for (i = 0; i < CMD_PLNT; i++) /* copy packet */ - tscmdp[i] = cpy_buf[i]; - ts_ownc = ts_ownm = 1; /* tape owns all */ - sim_activate (&ts_unit, ts_time); /* activate */ - break; - - case 1: /* TSSR */ - if (PA & 1) { /* TSDBX */ - if (UNIBUS) /* not in TS11 */ - return SCPE_OK; - if (tssr & TSSR_SSR) { /* ready? */ - tsdbx = data; /* save */ - if (data & TSDBX_BOOT) { - ts_bcmd = 1; - sim_activate (&ts_unit, ts_time); - } - } - else tssr = tssr | TSSR_RMR; /* no, err */ - } - else if (access == WRITE) /* reset */ - ts_reset (&ts_dev); - break; - } - -return SCPE_OK; -} - -/* Tape motion routines */ - -#define XTC(x,t) (((unsigned) (x) << 16) | (t)) -#define GET_X(x) (((x) >> 16) & 0177777) -#define GET_T(x) ((x) & 0177777) - -int32 ts_map_status (t_stat st) -{ -switch (st) { - - case MTSE_OK: - break; - - case MTSE_TMK: - msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ - return (XTC (XS0_TMK | XS0_RLS, TC2)); - - case MTSE_RECE: /* record in error */ - msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ - case MTSE_INVRL: /* invalid rec lnt */ - case MTSE_IOERR: /* IO error */ - msgxs1 = msgxs1 | XS1_UCOR; /* uncorrectable */ - return (XTC (XS0_RLS, TC6)); /* pos lost */ - - case MTSE_FMT: - case MTSE_UNATT: - case MTSE_EOM: /* end of medium */ - msgxs3 = msgxs3 | XS3_OPI; /* incomplete */ - return (XTC (XS0_RLS, TC6)); /* pos lost */ - - case MTSE_BOT: /* reverse into BOT */ - msgxs3 = msgxs3 | XS3_RIB; /* set status */ - return (XTC (XS0_BOT | XS0_RLS, TC2)); /* tape alert */ - - case MTSE_WRP: /* write protect */ - msgxs0 = msgxs0 | XS0_WLE | XS0_NEF; /* can't execute */ - return (XTC (XS0_WLE | XS0_NEF, TC3)); - } - -return 0; -} - -int32 ts_spacef (UNIT *uptr, int32 fc, t_bool upd) -{ -t_stat st; -t_mtrlnt tbc; - -do { - fc = (fc - 1) & DMASK; /* decr wc */ - if (upd) - msgrfc = fc; - if ((st = sim_tape_sprecf (uptr, &tbc))) /* space rec fwd, err? */ - return ts_map_status (st); /* map status */ - msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ - } while (fc != 0); -return 0; -} - -int32 ts_skipf (UNIT *uptr, int32 fc) -{ -t_stat st; -t_mtrlnt tbc; -t_bool tmkprv = FALSE; - -msgrfc = fc; -if (sim_tape_bot (uptr) && (wchopt & WCH_ENB)) - tmkprv = TRUE; -do { - st = sim_tape_sprecf (uptr, &tbc); /* space rec fwd */ - if (st == MTSE_TMK) { /* tape mark? */ - msgrfc = (msgrfc - 1) & DMASK; /* decr count */ - msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ - if (tmkprv && (wchopt & WCH_ESS)) /* 2nd tmk & ESS? */ - return (XTC ((msgrfc? XS0_RLS: 0) | - XS0_TMK | XS0_LET, TC2)); - tmkprv = TRUE; /* flag tmk */ - } - else if (st != MTSE_OK) - return ts_map_status (st); - else tmkprv = FALSE; /* not a tmk */ - msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ - } while (msgrfc != 0); -return 0; -} - -int32 ts_spacer (UNIT *uptr, int32 fc, t_bool upd) -{ -int32 st; -t_mtrlnt tbc; - -do { - fc = (fc - 1) & DMASK; /* decr wc */ - if (upd) - msgrfc = fc; - if ((st = sim_tape_sprecr (uptr, &tbc))) /* space rec rev, err? */ - return ts_map_status (st); /* map status */ - msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ - } while (fc != 0); -return 0; -} - -int32 ts_skipr (UNIT *uptr, int32 fc) -{ -t_stat st; -t_mtrlnt tbc; -t_bool tmkprv = FALSE; - -msgrfc = fc; -do { - st = sim_tape_sprecr (uptr, &tbc); /* space rec rev */ - if (st == MTSE_TMK) { /* tape mark? */ - msgrfc = (msgrfc - 1) & DMASK; /* decr count */ - msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ - if (tmkprv && (wchopt & WCH_ESS)) /* 2nd tmk & ESS? */ - return (XTC ((msgrfc? XS0_RLS: 0) | - XS0_TMK | XS0_LET, TC2)); - tmkprv = TRUE; /* flag tmk */ - } - else if (st != MTSE_OK) - return ts_map_status (st); - else tmkprv = FALSE; /* not a tmk */ - msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ - } while (msgrfc != 0); -return 0; -} - -int32 ts_readf (UNIT *uptr, uint32 fc) -{ -t_stat st; -t_mtrlnt i, t, tbc, wbc; -int32 wa; - -msgrfc = fc; -st = sim_tape_rdrecf (uptr, tsxb, &tbc, MT_MAXFR); /* read rec fwd */ -if (st != MTSE_OK) /* error? */ - return ts_map_status (st); -if (fc == 0) /* byte count */ - fc = 0200000; -tsba = (cmdadh << 16) | cmdadl; /* buf addr */ -wbc = (tbc > fc)? fc: tbc; /* cap buf size */ -msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ -if (cmdhdr & CMD_SWP) { /* swapped? */ - for (i = 0; i < wbc; i++) { /* copy buffer */ - wa = tsba ^ 1; /* apply OPP */ - if (Map_WriteB (wa, 1, &tsxb[i])) { /* store byte, nxm? */ - tssr = ts_updtssr (tssr | TSSR_NXM); /* set error */ - return (XTC (XS0_RLS, TC4)); - } - tsba = tsba + 1; - msgrfc = (msgrfc - 1) & DMASK; - } - } -else { - t = Map_WriteB (tsba, wbc, tsxb); /* store record */ - tsba = tsba + (wbc - t); /* update tsba */ - if (t) { /* nxm? */ - tssr = ts_updtssr (tssr | TSSR_NXM); /* set error */ - return (XTC (XS0_RLS, TC4)); - } - msgrfc = (msgrfc - (wbc - t)) & DMASK; /* update fc */ - } -if (msgrfc) /* buf too big? */ - return (XTC (XS0_RLS, TC2)); -if (tbc > wbc) /* rec too big? */ - return (XTC (XS0_RLL, TC2)); -return 0; -} - -int32 ts_readr (UNIT *uptr, uint32 fc) -{ -t_stat st; -t_mtrlnt i, tbc, wbc; -int32 wa; - -msgrfc = fc; -st = sim_tape_rdrecr (uptr, tsxb, &tbc, MT_MAXFR); /* read rec rev */ -if (st != MTSE_OK) /* error? */ - return ts_map_status (st); -if (fc == 0) /* byte count */ - fc = 0200000; -tsba = ((cmdadh << 16) | cmdadl) + fc; /* buf addr */ -wbc = (tbc > fc)? fc: tbc; /* cap buf size */ -msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ -for (i = wbc; i > 0; i--) { /* copy buffer */ - tsba = tsba - 1; - wa = (cmdhdr & CMD_SWP)? tsba ^ 1: tsba; /* apply OPP */ - if (Map_WriteB (wa, 1, &tsxb[i - 1])) { /* store byte, nxm? */ - tssr = ts_updtssr (tssr | TSSR_NXM); - return (XTC (XS0_RLS, TC4)); - } - msgrfc = (msgrfc - 1) & DMASK; - } -if (msgrfc) /* buf too big? */ - return (XTC (XS0_RLS, TC2)); -if (tbc > wbc) /* rec too big? */ - return (XTC (XS0_RLL, TC2)); -return 0; -} - -int32 ts_write (UNIT *uptr, int32 fc) -{ -int32 i, t; -uint32 wa; -t_stat st; - -msgrfc = fc; -if (fc == 0) /* byte count */ - fc = 0200000; -tsba = (cmdadh << 16) | cmdadl; /* buf addr */ -if (cmdhdr & CMD_SWP) { /* swapped? */ - for (i = 0; i < fc; i++) { /* copy mem to buf */ - wa = tsba ^ 1; /* apply OPP */ - if (Map_ReadB (wa, 1, &tsxb[i])) { /* fetch byte, nxm? */ - tssr = ts_updtssr (tssr | TSSR_NXM); - return TC5; - } - tsba = tsba + 1; - } - } -else { - t = Map_ReadB (tsba, fc, tsxb); /* fetch record */ - tsba = tsba + (fc - t); /* update tsba */ - if (t) { /* nxm? */ - tssr = ts_updtssr (tssr | TSSR_NXM); - return TC5; - } - } -if ((st = sim_tape_wrrecf (uptr, tsxb, fc))) /* write rec, err? */ - return ts_map_status (st); /* return status */ -msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ -msgrfc = 0; -if (sim_tape_eot (&ts_unit)) /* EOT on write? */ - return XTC (XS0_EOT, TC2); -return 0; -} - -int32 ts_wtmk (UNIT *uptr) -{ -t_stat st; - -if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ - return ts_map_status (st); /* return status */ -msgxs0 = msgxs0 | XS0_MOT; /* tape has moved */ -if (sim_tape_eot (&ts_unit)) /* EOT on write? */ - return XTC (XS0_EOT, TC2); -return XTC (XS0_TMK, TC0); -} - -/* Unit service */ - -t_stat ts_svc (UNIT *uptr) -{ -int32 i, t, bc, fnc, mod, st0, st1; - -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 */ - 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 27 */ - 0, 0, 0, 0, 0, 0, 0, 0 /* 30 - 37 */ - }; -static const int32 fnc_flg[CMD_N_FNC] = { - 0, FLG_MO+FLG_AD, 0, 0, 0, FLG_MO+FLG_WR+FLG_AD, FLG_AD, 0, - FLG_MO, FLG_MO+FLG_WR, FLG_MO, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, /* 20 - 27 */ - 0, 0, 0, 0, 0, 0, 0, 0 /* 30 - 37 */ - }; -static const char *fnc_name[CMD_N_FNC] = { - "0", "READ", "2", "3", "WCHR", "WRITE", "WSSM", "7", - "POS", "FMT", "CTL", "INIT", "14", "15", "16", "GSTA", - "20", "21", "22", "23", "24", "25", "26", "27", - "30", "31", "32", "33", "34", "35", "36", "37" - }; - -if (ts_bcmd) { /* boot? */ - ts_bcmd = 0; /* clear flag */ - sim_tape_rewind (uptr); /* rewind */ - if (uptr->flags & UNIT_ATT) { /* attached? */ - cmdlnt = cmdadh = cmdadl = 0; /* defang rd */ - ts_spacef (uptr, 1, FALSE); /* space fwd */ - ts_readf (uptr, 512); /* read blk */ - tssr = ts_updtssr (tssr | TSSR_SSR); - } - else tssr = ts_updtssr (tssr | TSSR_SSR | TC3); - if (cmdhdr & CMD_IE) - SET_INT (TS); - return SCPE_OK; - } - -if (!(cmdhdr & CMD_ACK)) { /* no acknowledge? */ - tssr = ts_updtssr (tssr | TSSR_SSR); /* set rdy, int */ - if (cmdhdr & CMD_IE) - SET_INT (TS); - ts_ownc = ts_ownm = 0; /* CPU owns all */ - return SCPE_OK; - } -fnc = GET_FNC (cmdhdr); /* get fnc+mode */ -mod = GET_MOD (cmdhdr); -if (DEBUG_PRS (ts_dev)) { - fprintf (sim_deb, ">>TS: cmd=%s, mod=%o, buf=%o, lnt=%d, pos=", - fnc_name[fnc], mod, cmdadl, cmdlnt); - fprint_val (sim_deb, ts_unit.pos, 10, T_ADDR_W, PV_LEFT); - fprintf (sim_deb, "\n"); - } -if ((fnc != FNC_WCHR) && (tssr & TSSR_NBA)) { /* ~wr chr & nba? */ - ts_endcmd (TC3, 0, 0); /* error */ - return SCPE_OK; - } -if (ts_qatn && (wchopt & WCH_EAI)) { /* attn pending? */ - ts_endcmd (TC1, 0, MSG_MATN | MSG_CATN); /* send attn msg */ - SET_INT (TS); /* set interrupt */ - ts_qatn = 0; /* not pending */ - return SCPE_OK; - } -if (cmdhdr & CMD_CVC) /* cvc? clr vck */ - msgxs0 = msgxs0 & ~XS0_VCK; -if ((cmdhdr & CMD_MBZ) || (mod >= fnc_mod[fnc])) { /* test mbz */ - ts_endcmd (TC3, XS0_ILC, MSG_ACK | MSG_MILL | MSG_CFAIL); - return SCPE_OK; - } -if ((fnc_flg[fnc] & FLG_MO) && /* mot+(vck|!att)? */ - ((msgxs0 & XS0_VCK) || !(uptr->flags & UNIT_ATT))) { - ts_endcmd (TC3, XS0_NEF, MSG_ACK | MSG_MNEF | MSG_CFAIL); - return SCPE_OK; - } -if ((fnc_flg[fnc] & FLG_WR) && /* write? */ - sim_tape_wrp (uptr)) { /* write lck? */ - ts_endcmd (TC3, XS0_WLE | XS0_NEF, MSG_ACK | MSG_MNEF | MSG_CFAIL); - return SCPE_OK; - } -if ((((fnc == FNC_READ) && (mod == 1)) || /* read rev */ - ((fnc == FNC_POS) && (mod & 1))) && /* space rev */ - sim_tape_bot (uptr)) { /* BOT? */ - ts_endcmd (TC3, XS0_NEF, MSG_ACK | MSG_MNEF | MSG_CFAIL); - return SCPE_OK; - } -if ((fnc_flg[fnc] & FLG_AD) && (cmdadh & ADDRTEST)) { /* buf addr > 22b? */ - ts_endcmd (TC3, XS0_ILA, MSG_ACK | MSG_MILL | MSG_CFAIL); - return SCPE_OK; - } - -st0 = st1 = 0; -switch (fnc) { /* case on func */ - - case FNC_INIT: /* init */ - if (!sim_tape_bot (uptr)) /* set if tape moves */ - msgxs0 = msgxs0 | XS0_MOT; - sim_tape_rewind (uptr); /* rewind */ - case FNC_WSSM: /* write mem */ - 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 & ADDRTEST) || (cmdadl & 1) || (cmdlnt < 6)) { - ts_endcmd (TSSR_NBA | TC3, XS0_ILA, 0); - break; - } - tsba = (cmdadh << 16) | cmdadl; - bc = ((WCH_PLNT << 1) > cmdlnt)? cmdlnt: WCH_PLNT << 1; - t = Map_ReadW (tsba, bc, cpy_buf); /* fetch packet */ - tsba = tsba + (bc - t); /* inc tsba */ - if (t) { /* nxm? */ - ts_endcmd (TSSR_NBA | TSSR_NXM | TC5, 0, 0); - return SCPE_OK; - } - for (i = 0; i < (bc / 2); i++) /* copy packet */ - tswchp[i] = cpy_buf[i]; - if ((wchlnt < ((MSG_PLNT - 1) * 2)) || (wchadh & 0177700) || (wchadl & 1)) - ts_endcmd (TSSR_NBA | TC3, 0, 0); - else { - msgxs2 = msgxs2 | XS2_XTF | 1; - tssr = ts_updtssr (tssr & ~TSSR_NBA); - ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); - } - return SCPE_OK; - - case FNC_CTL: /* control */ - switch (mod) { /* case mode */ - - case 00: /* msg buf rls */ - tssr = ts_updtssr (tssr | TSSR_SSR); /* set SSR */ - if (wchopt & WCH_ERI) - SET_INT (TS); - ts_ownc = 0; ts_ownm = 1; /* keep msg */ - break; - - case 01: /* rewind and unload */ - if (!sim_tape_bot (uptr)) /* if tape moves */ - msgxs0 = msgxs0 | XS0_MOT; - sim_tape_detach (uptr); /* unload */ - ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); - break; - - case 02: /* clean */ - ts_endcmd (TC0, 0, MSG_ACK | MSG_CEND); /* nop */ - break; - - case 03: /* undefined */ - ts_endcmd (TC3, XS0_ILC, MSG_ACK | MSG_MILL | MSG_CFAIL); - return SCPE_OK; - - case 04: /* rewind */ - if (!sim_tape_bot (uptr)) /* if tape moves */ - msgxs0 = msgxs0 | XS0_MOT; - sim_tape_rewind (uptr); - ts_endcmd (TC0, XS0_BOT, MSG_ACK | MSG_CEND); - break; - } - break; - - case FNC_READ: /* read */ - switch (mod) { /* case mode */ - - case 00: /* fwd */ - st0 = ts_readf (uptr, cmdlnt); /* read */ - break; - - case 01: /* back */ - st0 = ts_readr (uptr, cmdlnt); /* read */ - break; - - case 02: /* reread fwd */ - if (cmdhdr & CMD_OPP) { /* opposite? */ - st0 = ts_readr (uptr, cmdlnt); - st1 = ts_spacef (uptr, 1, FALSE); - } - else { - st0 = ts_spacer (uptr, 1, FALSE); - st1 = ts_readf (uptr, cmdlnt); - } - break; - - case 03: /* reread back */ - if (cmdhdr & CMD_OPP) { /* opposite */ - st0 = ts_readf (uptr, cmdlnt); - st1 = ts_spacer (uptr, 1, FALSE); - } - else { - st0 = ts_spacef (uptr, 1, FALSE); - st1 = ts_readr (uptr, cmdlnt); - } - break; - } - ts_cmpendcmd (st0, st1); - break; - - case FNC_WRIT: /* write */ - switch (mod) { /* case mode */ - - case 00: /* write */ - st0 = ts_write (uptr, cmdlnt); - break; - - case 01: /* rewrite */ - st0 = ts_spacer (uptr, 1, FALSE); - st1 = ts_write (uptr, cmdlnt); - break; - } - ts_cmpendcmd (st0, st1); - break; - - case FNC_FMT: /* format */ - switch (mod) { /* case mode */ - - case 00: /* write tmk */ - st0 = ts_wtmk (uptr); - break; - - case 01: /* erase */ - break; - - case 02: /* retry tmk */ - st0 = ts_spacer (uptr, 1, FALSE); - st1 = ts_wtmk (uptr); - break; - } - ts_cmpendcmd (st0, st1); - break; - - case FNC_POS: /* position */ - switch (mod) { /* case mode */ - - case 00: /* space fwd */ - st0 = ts_spacef (uptr, cmdadl, TRUE); - break; - - case 01: /* space rev */ - st0 = ts_spacer (uptr, cmdadl, TRUE); - break; - - case 02: /* space ffwd */ - st0 = ts_skipf (uptr, cmdadl); - break; - - case 03: /* space frev */ - st0 = ts_skipr (uptr, cmdadl); - break; - - case 04: /* rewind */ - if (!sim_tape_bot (uptr)) /* if tape moves */ - msgxs0 = msgxs0 | XS0_MOT; - sim_tape_rewind (uptr); - break; - } - ts_cmpendcmd (st0, 0); - break; - } - -return SCPE_OK; -} - -/* Utility routines */ - -int32 ts_updtssr (int32 t) -{ -t = (t & ~TSSR_EMA) | ((tsba >> (16 - TSSR_V_EMA)) & TSSR_EMA); -if (ts_unit.flags & UNIT_ATT) - t = t & ~TSSR_OFL; -else t = t | TSSR_OFL; -return (t & ~TSSR_MBZ); -} - -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 (sim_tape_wrp (&ts_unit)) - t = t | XS0_WLK; - if (sim_tape_bot (&ts_unit)) - t = (t | XS0_BOT) & ~XS0_EOT; - if (sim_tape_eot (&ts_unit)) - t = (t | XS0_EOT) & ~XS0_BOT; - } -else t = t & ~XS0_EOT; -if (cmdhdr & CMD_IE) - t = t | XS0_IE; -return t; -} - -void ts_cmpendcmd (int32 s0, int32 s1) -{ -int32 xs0, ssr, tc; -static const int32 msg[8] = { - MSG_ACK | MSG_CEND, MSG_ACK | MSG_MATN | MSG_CATN, - MSG_ACK | MSG_CEND, MSG_ACK | MSG_CFAIL, - MSG_ACK | MSG_CERR, MSG_ACK | MSG_CERR, - MSG_ACK | MSG_CERR, MSG_ACK | MSG_CERR - }; - -xs0 = GET_X (s0) | GET_X (s1); /* or XS0 errs */ -s0 = GET_T (s0); /* get SSR errs */ -s1 = GET_T (s1); -ssr = (s0 | s1) & ~TSSR_TC; /* or SSR errs */ -tc = MAX (GET_TC (s0), GET_TC (s1)); /* max term code */ -ts_endcmd (ssr | (tc << TSSR_V_TC), xs0, msg[tc]); /* end cmd */ -return; -} - -void ts_endcmd (int32 tc, int32 xs0, int32 msg) -{ -int32 i, t; - -msgxs0 = ts_updxs0 (msgxs0 | xs0); /* update XS0 */ -if (wchxopt & WCHX_HDS) /* update XS4 */ - msgxs4 = msgxs4 | XS4_HDS; -if (msg && !(tssr & TSSR_NBA)) { /* send end pkt */ - msghdr = msg; - msglnt = wchlnt - 4; /* exclude hdr, bc */ - tsba = (wchadh << 16) | wchadl; - for (i = 0; (i < MSG_PLNT) && (i < (wchlnt / 2)); i++) - cpy_buf[i] = (uint16) tsmsgp[i]; /* copy buffer */ - t = Map_WriteW (tsba, i << 1, cpy_buf); /* write to mem */ - tsba = tsba + ((i << 1) - t); /* incr tsba */ - if (t) { /* nxm? */ - tssr = tssr | TSSR_NXM; - tc = (tc & ~TSSR_TC) | TC4; - } - } -tssr = ts_updtssr (tssr | tc | TSSR_SSR | (tc? TSSR_SC: 0)); -if (cmdhdr & CMD_IE) - SET_INT (TS); -ts_ownm = 0; ts_ownc = 0; -if (DEBUG_PRS (ts_dev)) { - fprintf (sim_deb, ">>TS: sta=%o, tc=%o, rfc=%d, pos=", - msgxs0, GET_TC (tssr), msgrfc); - fprint_val (sim_deb, ts_unit.pos, 10, T_ADDR_W, PV_LEFT); - fprintf (sim_deb, "\n"); - } -return; -} - -/* Device reset */ - -t_stat ts_reset (DEVICE *dptr) -{ -int32 i; - -sim_tape_rewind (&ts_unit); -tsba = tsdbx = 0; -ts_ownc = ts_ownm = 0; -ts_bcmd = 0; -ts_qatn = 0; -tssr = ts_updtssr (TSSR_NBA | TSSR_SSR); -for (i = 0; i < CMD_PLNT; i++) - tscmdp[i] = 0; -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 = (uint8 *) calloc (MT_MAXFR, sizeof (uint8)); -if (tsxb == NULL) - return SCPE_MEM; -return SCPE_OK; -} - -/* Attach */ - -t_stat ts_attach (UNIT *uptr, char *cptr) -{ -t_stat r; - -r = sim_tape_attach (uptr, cptr); /* attach unit */ -if (r != SCPE_OK) /* error? */ - return r; -tssr = tssr & ~TSSR_OFL; /* clr offline */ -if ((tssr & TSSR_NBA) || !(wchopt & WCH_EAI)) /* attn msg? */ - return r; -if (ts_ownm) { /* own msg buf? */ - ts_endcmd (TC1, 0, MSG_MATN | MSG_CATN); /* send attn */ - SET_INT (TS); /* set interrupt */ - ts_qatn = 0; /* don't queue */ - } -else ts_qatn = 1; /* else queue */ -return r; -} - -/* Detach routine */ - -t_stat ts_detach (UNIT* uptr) -{ -t_stat r; - -if (!(uptr->flags & UNIT_ATT)) /* attached? */ - return SCPE_OK; -r = sim_tape_detach (uptr); /* detach unit */ -if (r != SCPE_OK) - return r; /* error? */ -tssr = tssr | TSSR_OFL; /* set offline */ -if ((tssr & TSSR_NBA) || !(wchopt & WCH_EAI)) /* attn msg? */ - return r; -if (ts_ownm) { /* own msg buf? */ - ts_endcmd (TC1, 0, MSG_MATN | MSG_CATN); /* send attn */ - SET_INT (TS); /* set interrupt */ - ts_qatn = 0; /* don't queue */ - } -else ts_qatn = 1; /* else queue */ -return r; -} - -/* Boot */ - -#if defined (VM_PDP11) -#define BOOT_START 01000 -#define BOOT_CSR0 (BOOT_START + 006) -#define BOOT_CSR1 (BOOT_START + 012) -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int16)) - -static const uint16 boot_rom[] = { - 0012706, 0001000, /* mov #boot_start, sp */ - 0012700, 0172520, /* mov #tsba, r0 */ - 0012701, 0172522, /* mov #tssr, r1 */ - 0005011, /* clr (r1) ; init, rew */ - 0105711, /* tstb (r1) ; wait */ - 0100376, /* bpl .-2 */ - 0012710, 0001070, /* mov #pkt1, (r0) ; set char */ - 0105711, /* tstb (r1) ; wait */ - 0100376, /* bpl .-2 */ - 0012710, 0001110, /* mov #pkt2, (r0) ; read, skip */ - 0105711, /* tstb (r1) ; wait */ - 0100376, /* bpl .-2 */ - 0012710, 0001110, /* mov #pkt2, (r0) ; read */ - 0105711, /* tstb (r1) ; wait */ - 0100376, /* bpl .-2 */ - 0005711, /* tst (r1) ; err? */ - 0100421, /* bmi hlt */ - 0005000, /* clr r0 */ - 0012704, 0001066+020, /* mov #sgnt+20, r4 */ - 0005007, /* clr r7 */ - 0046523, /* sgnt: "SM" */ - 0140004, /* pkt1: 140004, wcpk, 0, 8. */ - 0001100, - 0000000, - 0000010, - 0001122, /* wcpk: msg, 0, 14., 0 */ - 0000000, - 0000016, - 0000000, - 0140001, /* pkt2: 140001, 0, 0, 512. */ - 0000000, - 0000000, - 0001000, - 0000000 /* hlt: halt */ - /* msg: .blk 4 */ - }; - -t_stat ts_boot (int32 unitno, DEVICE *dptr) -{ -size_t i; -extern uint16 *M; - -sim_tape_rewind (&ts_unit); -for (i = 0; i < BOOT_LEN; i++) - M[(BOOT_START >> 1) + i] = boot_rom[i]; -M[BOOT_CSR0 >> 1] = ts_dib.ba & DMASK; -M[BOOT_CSR1 >> 1] = (ts_dib.ba & DMASK) + 02; -cpu_set_boot (BOOT_START); -return SCPE_OK; -} - -#else - -t_stat ts_boot (int32 unitno, DEVICE *dptr) -{ -return SCPE_NOFNC; -} -#endif diff --git a/PDP11/pdp11_tu.c b/PDP11/pdp11_tu.c deleted file mode 100644 index 58b924ad..00000000 --- a/PDP11/pdp11_tu.c +++ /dev/null @@ -1,1059 +0,0 @@ -/* pdp11_tu.c - PDP-11 TM02/TU16 TM03/TU45/TU77 Massbus magnetic tape controller - - Copyright (c) 1993-2017, 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. - - tu TM02/TM03 magtape - - 28-Dec-17 RMS Read tape mark must set Massbus EXC - 13-Mar-17 RMS Annotated fall through in switch - 23-Oct-13 RMS Revised for new boot setup routine - 18-Apr-11 MP Fixed t_addr printouts for 64b big-endian systems - 17-May-07 RMS CS1 DVA resides in device, not MBA - 29-Apr-07 RMS Fixed bug in setting FCE on TMK Naoki Hamada) - 16-Feb-06 RMS Added tape capacity checking - 12-Nov-05 RMS Changed default formatter to TM03 (for VMS) - 31-Oct-05 RMS Fixed address width for large files - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 31-Mar-05 RMS Fixed inaccuracies in error reporting - 18-Mar-05 RMS Added attached test to detach routine - 10-Sep-04 RMS Cloned from pdp10_tu.c - - Magnetic tapes are represented as a series of variable 8b records - of the form: - - 32b record length in bytes - exact number, sign = error - byte 0 - byte 1 - : - byte n-2 - byte n-1 - 32b record length in bytes - exact number, sign = error - - 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. -*/ - -#if defined (VM_PDP10) -#error "PDP-10 uses pdp10_tu.c!" - -#elif defined (VM_PDP11) -#include "pdp11_defs.h" -#define DEV_DIS_INIT DEV_DIS - -#elif defined (VM_VAX) -#include "vax_defs.h" -#define DEV_DIS_INIT 0 -#if (!UNIBUS) -#error "Qbus not supported!" -#endif - -#endif -#include "sim_tape.h" - -#define TU_NUMFM 1 /* #formatters */ -#define TU_NUMDR 8 /* #drives */ -#define USTAT u3 /* unit status */ -#define UDENS u4 /* unit density */ -#define UD_UNK 0 /* unknown */ -#define MT_MAXFR (1 << 16) /* max data buf */ -#define DEV_V_TM03 (DEV_V_FFUF + 0) /* TM02/TM03 */ -#define DEV_TM03 (1 << DEV_V_TM03) -#define UNIT_V_TYPE (MTUF_V_UF + 0) -#define UNIT_M_TYPE 03 -#define UNIT_TYPE (UNIT_M_TYPE << UNIT_V_TYPE) -#define UNIT_TE16 (0 << UNIT_V_TYPE) -#define UNIT_TU45 (1 << UNIT_V_TYPE) -#define UNIT_TU77 (2 << UNIT_V_TYPE) -#define GET_TYPE(x) (((x) >> UNIT_V_TYPE) & UNIT_M_TYPE) - -/* CS1 - offset 0 */ - -#define CS1_OF 0 -#define CS1_GO CSR_GO /* go */ -#define CS1_V_FNC 1 /* function pos */ -#define CS1_M_FNC 037 /* function mask */ -#define CS1_N_FNC (CS1_M_FNC + 1) -#define FNC_NOP 000 /* no operation */ -#define FNC_UNLOAD 001 /* unload */ -#define FNC_REWIND 003 /* rewind */ -#define FNC_FCLR 004 /* formatter clear */ -#define FNC_RIP 010 /* read in preset */ -#define FNC_ERASE 012 /* erase tape */ -#define FNC_WREOF 013 /* write tape mark */ -#define FNC_SPACEF 014 /* space forward */ -#define FNC_SPACER 015 /* space reverse */ -#define FNC_XFER 024 /* >=? data xfr */ -#define FNC_WCHKF 024 /* write check */ -#define FNC_WCHKR 027 /* write check rev */ -#define FNC_WRITE 030 /* write */ -#define FNC_READF 034 /* read forward */ -#define FNC_READR 037 /* read reverse */ -#define CS1_RW 077 -#define CS1_DVA 04000 /* drive avail */ -#define GET_FNC(x) (((x) >> CS1_V_FNC) & CS1_M_FNC) - -/* TUFS - formatter status - offset 1 - + indicates kept in drive status - ^ indicates calculated on the fly -*/ - -#define FS_OF 1 -#define FS_SAT 0000001 /* slave attention */ -#define FS_BOT 0000002 /* ^beginning of tape */ -#define FS_TMK 0000004 /* end of file */ -#define FS_ID 0000010 /* ID burst detected */ -#define FS_SLOW 0000020 /* slowing down NI */ -#define FS_PE 0000040 /* ^PE status */ -#define FS_SSC 0000100 /* slave stat change */ -#define FS_RDY 0000200 /* ^formatter ready */ -#define FS_FPR 0000400 /* formatter present */ -#define FS_EOT 0002000 /* +end of tape */ -#define FS_WRL 0004000 /* ^write locked */ -#define FS_MOL 0010000 /* ^medium online */ -#define FS_PIP 0020000 /* +pos in progress */ -#define FS_ERR 0040000 /* ^error */ -#define FS_ATA 0100000 /* attention active */ -#define FS_REW 0200000 /* +rewinding */ - -#define FS_DYN (FS_ERR | FS_PIP | FS_MOL | FS_WRL | FS_EOT | \ - FS_RDY | FS_PE | FS_BOT) - -/* TUER - error register - offset 2 */ - -#define ER_OF 2 -#define ER_ILF 0000001 /* illegal func */ -#define ER_ILR 0000002 /* illegal register */ -#define ER_RMR 0000004 /* reg mod refused */ -#define ER_MCP 0000010 /* Mbus cpar err NI */ -#define ER_FER 0000020 /* format sel err */ -#define ER_MDP 0000040 /* Mbus dpar err NI */ -#define ER_VPE 0000100 /* vert parity err */ -#define ER_CRC 0000200 /* CRC err NI */ -#define ER_NSG 0000400 /* non std gap err NI */ -#define ER_FCE 0001000 /* frame count err */ -#define ER_ITM 0002000 /* inv tape mark NI */ -#define ER_NXF 0004000 /* wlock or fnc err */ -#define ER_DTE 0010000 /* time err NI */ -#define ER_OPI 0020000 /* op incomplete */ -#define ER_UNS 0040000 /* drive unsafe */ -#define ER_DCK 0100000 /* data check NI */ - -/* TUMR - maintenance register - offset 03 */ - -#define MR_OF 3 -#define MR_RW 0177637 /* read/write */ - -/* TUAS - attention summary - offset 4 */ - -#define AS_OF 4 -#define AS_U0 0000001 /* unit 0 flag */ - -/* TUFC - offset 5 */ - -#define FC_OF 5 - -/* TUDT - drive type - offset 6 */ - -#define DT_OF 6 -#define DT_NSA 0100000 /* not sect addr */ -#define DT_TAPE 0040000 /* tape */ -#define DT_PRES 0002000 /* slave present */ -#define DT_TM03 0000040 /* TM03 formatter */ -#define DT_OFF 0000010 /* drive off */ -#define DT_TU16 0000011 /* TE16 */ -#define DT_TU45 0000012 /* TU45 */ -#define DT_TU77 0000014 /* TU77 */ - -/* TUCC - check character, read only - offset 7 */ - -#define CC_OF 7 -#define CC_MBZ 0177000 /* must be zero */ - -/* TUSN - serial number - offset 8 */ - -#define SN_OF 8 - -/* TUTC - tape control register - offset 9 */ - -#define TC_OF 9 -#define TC_V_UNIT 0 /* unit select */ -#define TC_M_UNIT 07 -#define TC_V_EVN 0000010 /* even parity */ -#define TC_V_FMT 4 /* format select */ -#define TC_M_FMT 017 -#define TC_STD 014 /* standard */ -#define TC_CDUMP 015 /* core dump */ -#define TC_V_DEN 8 /* density select */ -#define TC_M_DEN 07 -#define TC_800 3 /* 800 bpi */ -#define TC_1600 4 /* 1600 bpi */ -#define TC_AER 0010000 /* abort on error */ -#define TC_SAC 0020000 /* slave addr change */ -#define TC_FCS 0040000 /* frame count status */ -#define TC_ACC 0100000 /* accelerating NI */ -#define TC_RW 0013777 -#define TC_MBZ 0004000 -#define TC_RIP ((TC_800 << TC_V_DEN) | (TC_STD << TC_V_FMT)) -#define GET_DEN(x) (((x) >> TC_V_DEN) & TC_M_DEN) -#define GET_FMT(x) (((x) >> TC_V_FMT) & TC_M_FMT) -#define GET_DRV(x) (((x) >> TC_V_UNIT) & TC_M_UNIT) - -int32 tucs1 = 0; /* control/status 1 */ -int32 tufc = 0; /* frame count */ -int32 tufs = 0; /* formatter status */ -int32 tuer = 0; /* error status */ -int32 tucc = 0; /* check character */ -int32 tumr = 0; /* maint register */ -int32 tutc = 0; /* tape control */ -int32 tu_time = 10; /* record latency */ -int32 tu_stopioe = 1; /* stop on error */ -static uint8 *xbuf = NULL; /* xfer buffer */ -static uint16 *wbuf = NULL; -static int32 fmt_test[16] = { /* fmt valid */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0 - }; -static int32 dt_map[3] = { DT_TU16, DT_TU45, DT_TU77 }; -static char *tu_fname[CS1_N_FNC] = { - "NOP", "UNLD", "2", "REW", "FCLR", "5", "6", "7", - "RIP", "11", "ERASE", "WREOF", "SPCF", "SPCR", "16", "17", - "20", "21", "22", "23", "WRCHKF", "25", "26", "WRCHKR", - "WRITE", "31", "32", "33", "READF", "35", "36" "READR" - }; - -t_stat tu_mbrd (int32 *data, int32 PA, int32 fmtr); -t_stat tu_mbwr (int32 data, int32 PA, int32 fmtr); -t_stat tu_svc (UNIT *uptr); -t_stat tu_reset (DEVICE *dptr); -t_stat tu_attach (UNIT *uptr, char *cptr); -t_stat tu_detach (UNIT *uptr); -t_stat tu_boot (int32 unitno, DEVICE *dptr); -t_stat tu_set_fmtr (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat tu_show_fmtr (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat tu_go (int32 drv); -int32 tu_abort (void); -void tu_set_er (int32 flg); -void tu_clr_as (int32 mask); -void tu_update_fs (int32 flg, int32 drv); -t_stat tu_map_err (int32 drv, t_stat st, t_bool qdt); - -/* TU data structures - - tu_dev TU device descriptor - tu_unit TU unit list - tu_reg TU register list - tu_mod TU modifier list -*/ - -DIB tu_dib = { MBA_TU, 0, &tu_mbrd, &tu_mbwr,0, 0, 0, { &tu_abort } }; - -UNIT tu_unit[] = { - { 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[] = { - { GRDATA (CS1, tucs1, DEV_RDX, 6, 0) }, - { GRDATA (FC, tufc, DEV_RDX, 16, 0) }, - { GRDATA (FS, tufs, DEV_RDX, 16, 0) }, - { GRDATA (ER, tuer, DEV_RDX, 16, 0) }, - { GRDATA (CC, tucc, DEV_RDX, 16, 0) }, - { GRDATA (MR, tumr, DEV_RDX, 16, 0) }, - { GRDATA (TC, tutc, DEV_RDX, 16, 0) }, - { FLDATA (STOP_IOE, tu_stopioe, 0) }, - { DRDATA (TIME, tu_time, 24), PV_LEFT }, - { URDATA (UST, tu_unit[0].USTAT, DEV_RDX, 17, 0, TU_NUMDR, 0) }, - { URDATA (POS, tu_unit[0].pos, 10, T_ADDR_W, 0, - TU_NUMDR, PV_LEFT | REG_RO) }, - { NULL } - }; - -MTAB tu_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "MASSBUS", "MASSBUS", NULL, &mba_show_num }, -#if defined (VM_PDP11) - { MTAB_XTD|MTAB_VDV, 0, "FORMATTER", "TM02", - &tu_set_fmtr, &tu_show_fmtr }, - { MTAB_XTD|MTAB_VDV, 1, NULL, "TM03", - &tu_set_fmtr, NULL }, -#else - { MTAB_XTD|MTAB_VDV, 0, "FORMATTER", NULL, - NULL, &tu_show_fmtr }, -#endif - { MTUF_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { MTUF_WLK, MTUF_WLK, "write locked", "LOCKED", NULL }, - { UNIT_TYPE, UNIT_TE16, "TE16", "TE16", NULL }, - { UNIT_TYPE, UNIT_TU45, "TU45", "TU45", NULL }, - { UNIT_TYPE, UNIT_TU77, "TU77", "TU77", NULL }, - { MTAB_XTD|MTAB_VUN, 0, "FORMAT", "FORMAT", - &sim_tape_set_fmt, &sim_tape_show_fmt, NULL }, - { MTAB_XTD|MTAB_VUN, 0, "CAPACITY", "CAPACITY", - &sim_tape_set_capac, &sim_tape_show_capac, NULL }, - { 0 } - }; - -DEVICE tu_dev = { - "TU", tu_unit, tu_reg, tu_mod, - TU_NUMDR, 10, T_ADDR_W, 1, DEV_RDX, 8, - NULL, NULL, &tu_reset, - &tu_boot, &tu_attach, &tu_detach, - &tu_dib, DEV_MBUS|DEV_UBUS|DEV_QBUS|DEV_DEBUG|DEV_DISABLE|DEV_DIS_INIT|DEV_TM03 - }; - -/* Massbus register read */ - -t_stat tu_mbrd (int32 *data, int32 ofs, int32 fmtr) -{ -int32 drv; - -if (fmtr != 0) { /* only one fmtr */ - *data = 0; - return MBE_NXD; - } -drv = GET_DRV (tutc); /* get current unit */ -tu_update_fs (0, drv); /* update status */ - -switch (ofs) { /* decode offset */ - - case CS1_OF: /* MTCS1 */ - *data = (tucs1 & CS1_RW) | CS1_DVA; /* DVA always set */ - break; - - case FC_OF: /* MTFC */ - *data = tufc; - break; - - case FS_OF: /* MTFS */ - *data = tufs & 0177777; /* mask off rewind */ - break; - - case ER_OF: /* MTER */ - *data = tuer; - break; - - case AS_OF: /* MTAS */ - *data = (tufs & FS_ATA)? AS_U0: 0; - break; - - case CC_OF: /* MTCC */ - *data = tucc = tucc & ~CC_MBZ; - break; - - case MR_OF: /* MTMR */ - *data = tumr; - break; - - case DT_OF: /* MTDT */ - *data = DT_NSA | DT_TAPE | /* fmtr flags */ - ((tu_dev.flags & DEV_TM03)? DT_TM03: 0); - if (tu_unit[drv].flags & UNIT_DIS) - *data |= DT_OFF; - else *data |= DT_PRES | dt_map[GET_TYPE (tu_unit[drv].flags)]; - break; - - case SN_OF: /* MTSN */ - *data = (tu_unit[drv].flags & UNIT_DIS)? 0: 040 | (drv + 1); - break; - - case TC_OF: /* MTTC */ - *data = tutc = tutc & ~TC_MBZ; - break; - - default: /* all others */ - return MBE_NXR; - } - -return SCPE_OK; -} - -/* Massbus register write */ - -t_stat tu_mbwr (int32 data, int32 ofs, int32 fmtr) -{ -int32 drv; - -if (fmtr != 0) /* only one fmtr */ - return MBE_NXD; -drv = GET_DRV (tutc); /* get current unit */ - -switch (ofs) { /* decode PA<4:1> */ - - case CS1_OF: /* MTCS1 */ - if (tucs1 & CS1_GO) - tu_set_er (ER_RMR); - else { - tucs1 = data & CS1_RW; - if (tucs1 & CS1_GO) - return tu_go (drv); - } - break; - - case FC_OF: /* MTFC */ - if (tucs1 & CS1_GO) - tu_set_er (ER_RMR); - else { - tufc = data; - tutc = tutc | TC_FCS; /* set fc flag */ - } - break; - - case AS_OF: /* MTAS */ - tu_clr_as (data); - break; - - case MR_OF: /* MTMR */ - tumr = (tumr & ~MR_RW) | (data & MR_RW); - break; - - case TC_OF: /* MTTC */ - if (tucs1 & CS1_GO) - tu_set_er (ER_RMR); - else { - tutc = (tutc & ~TC_RW) | (data & TC_RW) | TC_SAC; - drv = GET_DRV (tutc); - } - break; - - case FS_OF: /* MTFS */ - case ER_OF: /* MTER */ - case CC_OF: /* MTCC */ - case DT_OF: /* MTDT */ - case SN_OF: /* MTSN */ - if (tucs1 & CS1_GO) - tu_set_er (ER_RMR); - break; /* read only */ - - default: /* all others */ - return MBE_NXR; - } /* end switch */ - -tu_update_fs (0, drv); -return SCPE_OK; -} - -/* New magtape command */ - -t_stat tu_go (int32 drv) -{ -int32 fnc, den; -UNIT *uptr; - -fnc = GET_FNC (tucs1); /* get function */ -den = GET_DEN (tutc); /* get density */ -uptr = tu_dev.units + drv; /* get unit */ -if (DEBUG_PRS (tu_dev)) { - fprintf (sim_deb, ">>TU%d STRT: fnc=%s, fc=%06o, fs=%06o, er=%06o, pos=", - drv, tu_fname[fnc], tufc, tufs, tuer); - fprint_val (sim_deb, uptr->pos, 10, T_ADDR_W, PV_LEFT); - fprintf (sim_deb, "\n"); - } -if ((fnc != FNC_FCLR) && /* not clear & err */ - ((tufs & FS_ERR) || sim_is_active (uptr))) { /* or in motion? */ - tu_set_er (ER_ILF); /* set err */ - tucs1 = tucs1 & ~CS1_GO; /* clear go */ - tu_update_fs (FS_ATA, drv); /* set attn */ - return MBE_GOE; - } -tu_clr_as (AS_U0); /* clear ATA */ -tutc = tutc & ~TC_SAC; /* clear addr change */ - -switch (fnc) { /* case on function */ - - case FNC_FCLR: /* drive clear */ - tuer = 0; /* clear errors */ - tutc = tutc & ~TC_FCS; /* clear fc status */ - tufs = tufs & ~(FS_SAT | FS_SSC | FS_ID | FS_ERR); - sim_cancel (uptr); /* reset drive */ - uptr->USTAT = 0; /* fall through */ - case FNC_NOP: - tucs1 = tucs1 & ~CS1_GO; /* no operation */ - return SCPE_OK; - - case FNC_RIP: /* read-in preset */ - tutc = TC_RIP; /* set tutc */ - sim_tape_rewind (&tu_unit[0]); /* rewind unit 0 */ - tu_unit[0].USTAT = 0; - tucs1 = tucs1 & ~CS1_GO; - tufs = tufs & ~FS_TMK; - return SCPE_OK; - - case FNC_UNLOAD: /* unload */ - if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ - tu_set_er (ER_UNS); - break; - } - detach_unit (uptr); - uptr->USTAT = FS_REW; - sim_activate (uptr, tu_time); - tucs1 = tucs1 & ~CS1_GO; - tufs = tufs & ~FS_TMK; - return SCPE_OK; - - case FNC_REWIND: - if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ - tu_set_er (ER_UNS); - break; - } - uptr->USTAT = FS_PIP | FS_REW; - sim_activate (uptr, tu_time); - tucs1 = tucs1 & ~CS1_GO; - tufs = tufs & ~FS_TMK; - return SCPE_OK; - - case FNC_SPACEF: - if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ - tu_set_er (ER_UNS); - break; - } - if (sim_tape_eot (uptr) || ((tutc & TC_FCS) == 0)) { - tu_set_er (ER_NXF); - break; - } - uptr->USTAT = FS_PIP; - goto GO_XFER; - - case FNC_SPACER: - if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ - tu_set_er (ER_UNS); - break; - } - if (sim_tape_bot (uptr) || ((tutc & TC_FCS) == 0)) { - tu_set_er (ER_NXF); - break; - } - uptr->USTAT = FS_PIP; - goto GO_XFER; - - case FNC_WCHKR: /* wchk = read */ - case FNC_READR: /* read rev */ - if (tufs & FS_BOT) { /* beginning of tape? */ - tu_set_er (ER_NXF); - break; - } - goto DATA_XFER; - - case FNC_WRITE: /* write */ - if (((tutc & TC_FCS) == 0) || /* frame cnt = 0? */ - ((den == TC_800) && (tufc > 0777765))) { /* NRZI, fc < 13? */ - tu_set_er (ER_NXF); - break; - } - case FNC_WREOF: /* write tape mark */ - case FNC_ERASE: /* erase */ - if (sim_tape_wrp (uptr)) { /* write locked? */ - tu_set_er (ER_NXF); - break; - } - case FNC_WCHKF: /* wchk = read */ - case FNC_READF: /* read */ - DATA_XFER: - if ((uptr->flags & UNIT_ATT) == 0) { /* unattached? */ - tu_set_er (ER_UNS); - break; - } - if (fmt_test[GET_FMT (tutc)] == 0) { /* invalid format? */ - tu_set_er (ER_FER); - break; - } - if (uptr->UDENS == UD_UNK) /* set dens */ - uptr->UDENS = den; - uptr->USTAT = 0; - GO_XFER: - tufs = tufs & ~(FS_TMK | FS_ID); /* clear eof, id */ - sim_activate (uptr, tu_time); - return SCPE_OK; - - default: /* all others */ - tu_set_er (ER_ILF); /* not supported */ - break; - } /* end case function */ - -tucs1 = tucs1 & ~CS1_GO; /* clear go */ -tu_update_fs (FS_ATA, drv); /* set attn */ -return MBE_GOE; -} - -/* Abort transfer */ - -int32 tu_abort (void) -{ -return tu_reset (&tu_dev); -} - -/* Unit service - - Complete movement or data transfer command - Unit must exist - can't remove an active unit - Unit must be attached - detach cancels in progress operations -*/ - -t_stat tu_svc (UNIT *uptr) -{ -int32 fnc, fmt, j, xbc; -int32 fc, drv; -t_mtrlnt i, tbc; -t_stat st, r = SCPE_OK; - -drv = (int32) (uptr - tu_dev.units); /* get drive # */ -if (uptr->USTAT & FS_REW) { /* rewind or unload? */ - sim_tape_rewind (uptr); /* rewind tape */ - uptr->USTAT = 0; /* clear status */ - tu_update_fs (FS_ATA | FS_SSC, drv); - return SCPE_OK; - } - -fnc = GET_FNC (tucs1); /* get command */ -fmt = GET_FMT (tutc); /* get format */ -fc = 0200000 - tufc; /* get frame count */ -uptr->USTAT = 0; /* clear status */ - -if ((uptr->flags & UNIT_ATT) == 0) { - tu_set_er (ER_UNS); /* set formatter error */ - if (fnc >= FNC_XFER) - mba_set_don (tu_dib.ba); - tu_update_fs (FS_ATA, drv); - return (tu_stopioe? SCPE_UNATT: SCPE_OK); - } -switch (fnc) { /* case on function */ - -/* Non-data transfer commands - set ATA when done */ - - case FNC_SPACEF: /* space forward */ - do { - tufc = (tufc + 1) & 0177777; /* incr fc */ - if ((st = sim_tape_sprecf (uptr, &tbc))) { /* space rec fwd, err? */ - r = tu_map_err (drv, st, 0); /* map error */ - break; - } - } while ((tufc != 0) && !sim_tape_eot (uptr)); - if (tufc != 0) - tu_set_er (ER_FCE); - else tutc = tutc & ~TC_FCS; - break; - - case FNC_SPACER: /* space reverse */ - do { - tufc = (tufc + 1) & 0177777; /* incr wc */ - if ((st = sim_tape_sprecr (uptr, &tbc))) { /* space rec rev, err? */ - r = tu_map_err (drv, st, 0); /* map error */ - break; - } - } while (tufc != 0); - if (tufc != 0) - tu_set_er (ER_FCE); - else tutc = tutc & ~TC_FCS; - break; - - case FNC_WREOF: /* write end of file */ - if ((st = sim_tape_wrtmk (uptr))) /* write tmk, err? */ - r = tu_map_err (drv, st, 0); /* map error */ - break; - - case FNC_ERASE: - if (sim_tape_wrp (uptr)) /* write protected? */ - r = tu_map_err (drv, MTSE_WRP, 0); /* map error */ - break; - -/* Unit service - data transfer commands */ - - case FNC_READF: /* read */ - case FNC_WCHKF: /* wcheck = read */ - tufc = 0; /* clear frame count */ - if ((uptr->UDENS == TC_1600) && sim_tape_bot (uptr)) - tufs = tufs | FS_ID; /* PE BOT? ID burst */ - if ((st = sim_tape_rdrecf (uptr, xbuf, &tbc, MT_MAXFR))) {/* read fwd */ - r = tu_map_err (drv, st, 1); /* map error */ - break; /* done */ - } - for (i = tbc; i < tbc + 4; i++) /* pad with 0's */ - xbuf[i] = 0; - if (fmt == TC_CDUMP) { /* core dump? */ - for (i = j = 0; i < tbc; i = i + 4) { - wbuf[j++] = ((uint16) xbuf[i] & 0xF) | - (((uint16) (xbuf[i + 1] & 0xF)) << 4) | - (((uint16) (xbuf[i + 2] & 0xF)) << 8) | - (((uint16) (xbuf[i + 3] & 0xf)) << 12); - } - xbc = (tbc + 1) >> 1; - } - else { /* standard */ - for (i = j = 0; i < tbc; i = i + 2) { - wbuf[j++] = ((uint16) xbuf[i]) | - (((uint16) xbuf[i + 1]) << 8); - } - xbc = tbc; - } - if (mba_get_bc (tu_dib.ba) > xbc) /* record short? */ - tu_set_er (ER_FCE); /* set FCE, ATN */ - if (fnc == FNC_WCHKF) - mba_chbufW (tu_dib.ba, xbc, wbuf); - else mba_wrbufW (tu_dib.ba, xbc, wbuf); - tufc = tbc & 0177777; - break; - - case FNC_WRITE: /* write */ - xbc = mba_rdbufW (tu_dib.ba, fc, wbuf); /* read buffer */ - if (xbc == 0) /* anything?? */ - break; - if (fmt == TC_CDUMP) { /* core dump? */ - for (i = j = 0; j < xbc; j = j + 1) { - xbuf[i++] = wbuf[j] & 0xF; - xbuf[i++] = (wbuf[j] >> 4) & 0xF; - xbuf[i++] = (wbuf[j] >> 8) & 0xF; - xbuf[i++] = (wbuf[j] >> 12) & 0xF; - } - tbc = (xbc + 1) >> 1; - } - else { /* standard */ - for (i = j = 0; j < xbc; j = j + 1) { - xbuf[i++] = wbuf[j] & 0377; - xbuf[i++] = (wbuf[j] >> 8) & 0377; - } - tbc = xbc; - } - if ((st = sim_tape_wrrecf (uptr, xbuf, tbc))) /* write rec, err? */ - r = tu_map_err (drv, st, 1); /* map error */ - else { - tufc = (tufc + tbc) & 0177777; - if (tufc == 0) - tutc = tutc & ~TC_FCS; - } - break; - - case FNC_READR: /* read reverse */ - case FNC_WCHKR: /* wcheck = read */ - tufc = 0; /* clear frame count */ - if ((st = sim_tape_rdrecr (uptr, xbuf + 4, &tbc, MT_MAXFR))) {/* read rev */ - r = tu_map_err (drv, st, 1); /* map error */ - break; /* done */ - } - for (i = 0; i < 4; i++) xbuf[i] = 0; /* pad with 0's */ - if (fmt == TC_CDUMP) { /* core dump? */ - for (i = tbc + 3, j = 0; i > 3; i = i - 4) { - wbuf[j++] = ((uint16) xbuf[i] & 0xF) | - (((uint16) (xbuf[i - 1] & 0xF)) << 4) | - (((uint16) (xbuf[i - 2] & 0xF)) << 8) | - (((uint16) (xbuf[i - 3] & 0xf)) << 12); - } - xbc = (tbc + 1) >> 1; - } - else { /* standard */ - for (i = tbc + 3, j = 0; i > 3; i = i - 2) { - wbuf[j++] = ((uint16) xbuf[i]) | - (((uint16) xbuf[i - 1]) << 8); - } - xbc = tbc; - } - if (mba_get_bc (tu_dib.ba) > xbc) /* record short? */ - tu_set_er (ER_FCE); /* set FCE, ATN */ - if (fnc == FNC_WCHKR) - mba_chbufW (tu_dib.ba, xbc, wbuf); - else mba_wrbufW (tu_dib.ba, xbc, wbuf); - tufc = tbc & 0177777; - break; - } /* end case */ - -tucs1 = tucs1 & ~CS1_GO; /* clear go */ -if (fnc >= FNC_XFER) { /* data xfer? */ - mba_set_don (tu_dib.ba); /* set done */ - tu_update_fs (0, drv); /* update fs */ - } -else tu_update_fs (FS_ATA, drv); /* no, set attn */ -if (DEBUG_PRS (tu_dev)) { - fprintf (sim_deb, ">>TU%d DONE: fnc=%s, fc=%06o, fs=%06o, er=%06o, pos=", - drv, tu_fname[fnc], tufc, tufs, tuer); - fprint_val (sim_deb, uptr->pos, 10, T_ADDR_W, PV_LEFT); - fprintf (sim_deb, ", r=%d\n", r); - } -return SCPE_OK; -} - -/* Set formatter error */ - -void tu_set_er (int32 flg) -{ -tuer = tuer | flg; -tufs = tufs | FS_ATA; -mba_upd_ata (tu_dib.ba, 1); -return; -} - -/* Clear attention */ - -void tu_clr_as (int32 mask) -{ -if (mask & AS_U0) - tufs = tufs & ~FS_ATA; -mba_upd_ata (tu_dib.ba, tufs & FS_ATA); -return; -} - -/* Formatter update status */ - -void tu_update_fs (int32 flg, int32 drv) -{ -int32 act = sim_is_active (&tu_unit[drv]); - -tufs = (tufs & ~FS_DYN) | FS_FPR | flg; -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 (sim_tape_wrp (&tu_unit[drv])) - tufs = tufs | FS_WRL; - if (!act) { - if (sim_tape_bot (&tu_unit[drv])) - tufs = tufs | FS_BOT; - if (sim_tape_eot (&tu_unit[drv])) - tufs = tufs | FS_EOT; - } - } -if (tuer) - tufs = tufs | FS_ERR; -if (tufs && !act) - tufs = tufs | FS_RDY; -if (flg & FS_ATA) - mba_upd_ata (tu_dib.ba, 1); -return; -} - -/* Map tape error status - - Note that tape mark on a data transfer sets FCE and Massbus EXC */ - -t_stat tu_map_err (int32 drv, t_stat st, t_bool qdt) -{ -switch (st) { - - case MTSE_FMT: /* illegal fmt */ - case MTSE_UNATT: /* not attached */ - tu_set_er (ER_NXF); /* can't execute */ - if (qdt) /* set exception */ - mba_set_exc (tu_dib.ba); - break; - - case MTSE_TMK: /* end of file */ - tufs = tufs | FS_TMK; /* set TMK status */ - if (qdt) { /* data transfer? */ - tu_set_er (ER_FCE); /* set FCE */ - mba_set_exc (tu_dib.ba); /* set exception*/ - } - break; - - case MTSE_IOERR: /* IO error */ - tu_set_er (ER_VPE); /* flag error */ - if (qdt) /* set exception */ - mba_set_exc (tu_dib.ba); - return (tu_stopioe? SCPE_IOERR: SCPE_OK); - - case MTSE_INVRL: /* invalid rec lnt */ - tu_set_er (ER_VPE); /* flag error */ - if (qdt) /* set exception */ - mba_set_exc (tu_dib.ba); - return SCPE_MTRLNT; - - case MTSE_RECE: /* record in error */ - tu_set_er (ER_CRC); /* set crc err */ - if (qdt) /* set exception */ - mba_set_exc (tu_dib.ba); - break; - - case MTSE_EOM: /* end of medium */ - tu_set_er (ER_OPI); /* incomplete */ - if (qdt) /* set exception */ - mba_set_exc (tu_dib.ba); - break; - - case MTSE_BOT: /* reverse into BOT */ - return SCPE_OK; - - case MTSE_WRP: /* write protect */ - tu_set_er (ER_NXF); /* can't execute */ - if (qdt) /* set exception */ - mba_set_exc (tu_dib.ba); - break; - - default: /* unknown error */ - return SCPE_IERR; - } - -return SCPE_OK; -} - -/* Reset routine */ - -t_stat tu_reset (DEVICE *dptr) -{ -int32 u; -UNIT *uptr; - -mba_set_enbdis (MBA_TU, tu_dev.flags & DEV_DIS); -tucs1 = 0; -tufc = 0; -tuer = 0; -tufs = FS_FPR | FS_RDY; -if (sim_switches & SWMASK ('P')) /* powerup? clr TC */ - tutc = 0; -else tutc = tutc & ~TC_FCS; /* no, clr */ -for (u = 0; u < TU_NUMDR; u++) { /* loop thru units */ - uptr = tu_dev.units + u; - sim_tape_reset (uptr); /* clear pos flag */ - sim_cancel (uptr); /* cancel activity */ - uptr->USTAT = 0; - } -if (xbuf == NULL) - xbuf = (uint8 *) calloc (MT_MAXFR + 4, sizeof (uint8)); -if (xbuf == NULL) - return SCPE_MEM; -if (wbuf == NULL) - wbuf = (uint16 *) calloc ((MT_MAXFR + 4) >> 1, sizeof (uint16)); -if (wbuf == NULL) - return SCPE_MEM; -return SCPE_OK; -} - -/* Attach routine */ - -t_stat tu_attach (UNIT *uptr, char *cptr) -{ -int32 drv = uptr - tu_dev.units, flg; -t_stat r; - -r = sim_tape_attach (uptr, cptr); -if (r != SCPE_OK) - return r; -uptr->USTAT = 0; /* clear unit status */ -uptr->UDENS = UD_UNK; /* unknown density */ -flg = FS_ATA | FS_SSC; /* set attention */ -if (GET_DRV (tutc) == drv) /* sel drv? set SAT */ - flg = flg | FS_SAT; -tu_update_fs (flg, drv); /* update status */ -return r; -} - -/* Detach routine */ - -t_stat tu_detach (UNIT* uptr) -{ -int32 drv = uptr - tu_dev.units; - -if (!(uptr->flags & UNIT_ATT)) /* attached? */ - return SCPE_OK; -uptr->USTAT = 0; /* clear status flags */ -tu_update_fs (FS_ATA | FS_SSC, drv); /* update status */ -return sim_tape_detach (uptr); -} - -/* Set/show formatter type */ - -t_stat tu_set_fmtr (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -DEVICE *dptr = find_dev_from_unit (uptr); - -if (cptr != NULL) - return SCPE_ARG; -if (dptr == NULL) - return SCPE_IERR; -if (val) - dptr->flags = dptr->flags | DEV_TM03; -else dptr->flags = dptr->flags & ~DEV_TM03; -return SCPE_OK; -} - -t_stat tu_show_fmtr (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -DEVICE *dptr = find_dev_from_unit (uptr); - -if (dptr == NULL) - return SCPE_IERR; -fprintf (st, "TM0%d", (dptr->flags & DEV_TM03? 3: 2)); -return SCPE_OK; -} - -/* Device bootstrap */ - -#if defined (PDP11) - -#elif defined (VM_PDP11) - -#define BOOT_START 016000 /* start */ -#define BOOT_ENTRY (BOOT_START + 002) /* entry */ -#define BOOT_UNIT (BOOT_START + 010) /* unit number */ -#define BOOT_CSR (BOOT_START + 014) /* CSR */ -#define BOOT_LEN (sizeof (boot_rom) / sizeof (uint16)) - -static const uint16 boot_rom[] = { - 0046515, /* "MM" */ - 0012706, BOOT_START, /* mov #boot_start, sp */ - 0012700, 0000000, /* mov #unit, r0 */ - 0012701, 0172440, /* mov #TUCS1, r1 */ - 0012761, 0000040, 0000010, /* mov #CS2_CLR, 10(r1) ; reset */ - 0012711, 0000021, /* mov #RIP+GO, (r1) ; rip */ - 0010004, /* mov r0, r4 */ - 0052704, 0002300, /* bis #2300, r4 ; set den */ - 0010461, 0000032, /* mov r4, 32(r1) ; set unit */ - 0012761, 0177777, 0000006, /* mov #-1, 6(r1) ; set fc */ - 0012711, 0000031, /* mov #SPCF+GO, (r1) ; skip rec */ - 0105761, 0000012, /* tstb 12 (r1) ; fmtr rdy? */ - 0100375, /* bpl .-4 */ - 0012761, 0177000, 0000002, /* mov #-1000, 2(r1) ; set wc */ - 0005061, 0000004, /* clr 4(r1) ; clr ba */ - 0005061, 0000006, /* clr 6(r1) ; clr fc */ - 0012711, 0000071, /* mov #READ+GO, (r1) ; read */ - 0105711, /* tstb (r1) ; wait */ - 0100376, /* bpl .-2 */ - 0005002, /* clr R2 */ - 0005003, /* clr R3 */ - 0012704, BOOT_START+020, /* mov #start+020, r4 */ - 0005005, /* clr R5 */ - 0105011, /* clrb (r1) */ - 0005007 /* clr PC */ - }; - -t_stat tu_boot (int32 unitno, DEVICE *dptr) -{ -size_t i; -extern uint16 *M; - -for (i = 0; i < BOOT_LEN; i++) - M[(BOOT_START >> 1) + i] = boot_rom[i]; -M[BOOT_UNIT >> 1] = unitno & (TU_NUMDR - 1); -M[BOOT_CSR >> 1] = mba_get_csr (tu_dib.ba) & DMASK; -cpu_set_boot (BOOT_ENTRY); -return SCPE_OK; -} - -#else - -t_stat tu_boot (int32 unitno, DEVICE *dptr) -{ -return SCPE_NOFNC; -} - -#endif diff --git a/PDP11/pdp11_uc15.c b/PDP11/pdp11_uc15.c deleted file mode 100644 index 1e85c8b0..00000000 --- a/PDP11/pdp11_uc15.c +++ /dev/null @@ -1,545 +0,0 @@ -/* pdp11_uc15.c: UC15 interface simulator - - Copyright (c) 2016, 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. - - uca DR11 #1 - ucb DR11 #2 - - The DR11Cs provide control communications with the DR15C in the PDP15. - - The PDP15 and UC15 use a master/slave communications protocol. - - The PDP15 initiates a request to the PDP11 by writing TCBP and - clearing TCBP acknowledge. This alerts/interrupts the PDP11. - - The PDP11 reads TCBP. This sets TCBP acknowledge, which is - not wired to interrupt on the PDP15. Note that TCBP has been - converted from a word address to a byte address by the way - the two systems are wired together. - - The PDP11 processes the request. - - The PDP11 signals completion by writing a vector into one of - four API request levels. - - The PDP15 is interrupted, and the request is considered complete. - - The UC15 must "call out" to the PDP15 to signal two conditions: - - the TCB pointer has been read - - an API interrupt is requested - - The DR15 must "call in" to the UC15 for two reasons: - - the TCBP has been written - - API interrupt status has changed - - The DR15 and UC15 use a shared memory section and ATOMIC operations - to communicate. Shared state is maintained in shared memory, with one - side having read/write access, the other read-only. Actions are - implemented by setting signals with an atomic compare-and-swap. - The signals may be polled with non-atomic operations but must be - verified with an atomic compare-and-swap. - - 21-Jul-18 RMS Fixed missing size multiplier in reset (Mark Pizzolato) -*/ - -#include "pdp11_defs.h" - -#include "sim_shmem.h" -#include "uc15_defs.h" - -/* Constants */ - -/* DR11 #1 */ - -#define UCAC_APID (CSR_DONE) -#define UCAB_V_TCBHI 0 -#define UCAB_M_TCBHI 03 -#define UCAB_API2 0000100 -#define UCAB_API0 0000200 -#define UCAB_V_LOCAL 8 -#define UCAB_M_LOCAL 07 -#define UCAB_API3 0040000 -#define UCAB_API1 0100000 - -/* DR11 #2 */ - -#define UCBC_NTCB (CSR_DONE) - -/* Declarations */ - -extern int32 int_req[IPL_HLVL]; -extern UNIT cpu_unit; -extern uint16 *M; - -int32 uca_csr = 0; /* DR11C #1 CSR */ -int32 uca_buf = 0; /* DR11C #1 input buffer */ -int32 ucb_csr = 0; -int32 ucb_buf = 0; -int32 uc15_poll = 3; /* polling interval */ -SHMEM *uc15_shmem = NULL; /* shared state identifier */ -int32 *uc15_shstate = NULL; /* shared state base */ -SHMEM *pdp15_shmem = NULL; /* PDP15 mem identifier */ -int32 *pdp15_mem = NULL; -uint32 uc15_memsize = 0; - -DEVICE uca_dev, ucb_dev; -t_stat uca_rd (int32 *data, int32 PA, int32 access); -t_stat uca_wr (int32 data, int32 PA, int32 access); -t_stat ucb_rd (int32 *data, int32 PA, int32 access); -t_stat ucb_wr (int32 data, int32 PA, int32 access); -t_stat uc15_reset (DEVICE *dptr); -t_stat uc15_svc (UNIT *uptr); -t_stat uc15_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); -t_stat uc15_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); -t_stat uc15_attach (UNIT *uptr, char *cptr); -t_stat uc15_detach (UNIT *uptr); - -void uc15_set_memsize (void); -int32 uc15_get_uca_buf (void); -t_stat uc15_api_req (int32 lvl, int32 vec); - -/* UC15 data structures - - uca_dev, ucb_dev UC15 device descriptor - uca_unit, ucb_unit UC15 unit descriptor - uca_reg, ucb reg UC15 register list - - The two DR11Cs must be separate devices because they interrupt at - different IPLs and must have different DIBs! -*/ - -DIB uca_dib = { - IOBA_UCA, IOLN_UCA, &uca_rd, &uca_wr, - 1, IVCL (UCA), VEC_UCA, { NULL } - }; - -UNIT uca_unit = { UDATA (&uc15_svc, 0, UNIT_ATTABLE) }; - -REG uca_reg[] = { - { ORDATA (CSR, uca_csr, 16) }, - { ORDATA (BUF, uca_buf, 16) }, - { FLDATA (APID, uca_csr, CSR_V_DONE) }, - { FLDATA (IE, uca_csr, CSR_V_IE) }, - { DRDATA (POLL, uc15_poll, 10), REG_NZ }, - { DRDATA (UCMEMSIZE, uc15_memsize, 18), REG_HRO }, - { NULL } - }; - -MTAB uc15_mod[] = { - { MTAB_XTD|MTAB_VDV, 006, "ADDRESS", "ADDRESS", - NULL, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", "VECTOR", - NULL, &show_vec, NULL }, - { 0 } - }; - -DEVICE uca_dev = { - "UCA", &uca_unit, uca_reg, uc15_mod, - 1, 8, 10, 1, 8, 32, - &uc15_ex, &uc15_dep, &uc15_reset, - NULL, &uc15_attach, &uc15_detach, - &uca_dib, DEV_DISABLE | DEV_DEBUG - }; - -DIB ucb_dib = { - IOBA_UCB, IOLN_UCB, &ucb_rd, &ucb_wr, - 1, IVCL (UCB), VEC_UCB, { NULL } - }; - -UNIT ucb_unit = { UDATA (NULL, 0, 0) }; - -REG ucb_reg[] = { - { ORDATA (CSR, ucb_csr, 16) }, - { ORDATA (BUF, ucb_buf, 16) }, - { FLDATA (NTCB, ucb_csr, CSR_V_DONE) }, - { FLDATA (IE, ucb_csr, CSR_V_IE) }, - { NULL } - }; - -DEVICE ucb_dev = { - "UCB", &ucb_unit, ucb_reg, uc15_mod, - 1, 8, 18, 1, 8, 18, - NULL, NULL, NULL, - NULL, NULL, NULL, - &ucb_dib, DEV_DISABLE - }; - -/* IO routines */ - -/* DR11 #1 */ - -t_stat uca_rd (int32 *data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 03) { /* case on PA<2:1> */ - -case 0: /* CSR */ - *data = uca_csr; - return SCPE_OK; - -case 1: /* output buffers */ - return SCPE_OK; - -case 2: /* input buffer */ - *data = uc15_get_uca_buf (); /* assemble buffer */ - return SCPE_OK; - } - -return SCPE_NXM; -} - -t_stat uca_wr (int32 data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 03) { /* case on PA<2:1> */ - -case 0: /* CSR */ - if (PA & 1) - return SCPE_OK; - if ((data & CSR_IE) == 0) - CLR_INT (UCA); - else if ((uca_csr & (UCAC_APID + CSR_IE)) == UCAC_APID) - SET_INT (UCA); - uca_csr = (uca_csr & ~CSR_IE) | (data & CSR_IE); - return SCPE_OK; - -case 1: /* output buffer */ - if (PA & 1) /* odd byte? API 1 */ - uc15_api_req (1, data & 0377); - else { - if (access == WRITE) /* full word? API 1 */ - uc15_api_req (1, (data >> 8) & 0377); - uc15_api_req (0, data & 0377); /* API 0 */ - } - return SCPE_OK; - -case 2: - return SCPE_OK; - } - -return SCPE_NXM; -} - -t_stat ucb_rd (int32 *data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 03) { /* case on PA<2:1> */ - -case 0: /* CSR */ - *data = ucb_csr; - return SCPE_OK; - -case 1: /* output buffers */ - return SCPE_OK; - -case 2: /* input buffer */ - *data = ucb_buf = (UC15_SHARED_RD (UC15_TCBP) << 1) & 0177777; - ucb_csr &= ~UCBC_NTCB; /* clear TCBP rdy */ - CLR_INT (UCB); /* clear int */ - UC15_ATOMIC_CAS (UC15_TCBP_RD, 0, 1); /* send ACK */ - if (DEBUG_PRS (uca_dev)) { - uint32 apiv, apil, fnc, tsk, pa; - t_bool spl; - - pa = ucb_buf + MEMSIZE; - apiv = RdMemB (pa); - apil = RdMemB (pa + 1); - fnc = RdMemB (pa + 2); - spl = (RdMemB (pa + 3) & 0200) != 0; - tsk = RdMemB (pa + 3) & 0177; - fprintf (sim_deb, ">> UC15: TCB rcvd, API = %o/%d, fnc = %o, %s task = %o, eventvar = %o\n", - apiv, apil, fnc, spl? "Spooled": "Unspooled", tsk, RdMemW (pa + 4)); - fprintf (sim_deb, "Additional parameters = %o %o %o %o %o\n", - RdMemW (pa + 6), RdMemW (pa + 8), RdMemW (pa + 10), RdMemW (pa + 12), RdMemW (pa + 14)); - } - return SCPE_OK; - } - -return SCPE_NXM; -} - -t_stat ucb_wr (int32 data, int32 PA, int32 access) -{ -switch ((PA >> 1) & 03) { /* case on PA<2:1> */ - -case 0: /* CSR */ - if (PA & 1) - return SCPE_OK; - if ((data & CSR_IE) == 0) /* IE = 0? */ - CLR_INT (UCB); - else if ((ucb_csr & (UCBC_NTCB + CSR_IE)) == UCBC_NTCB) - SET_INT (UCB); - ucb_csr = (ucb_csr & ~CSR_IE) | (data & CSR_IE); - return SCPE_OK; - -case 1: /* output buffer */ - if (PA & 1) /* odd byte? API 3*/ - uc15_api_req (3, data & 0377); - else { - if (access == WRITE) /* full word? API 3 */ - uc15_api_req (3, (data >> 8) & 0377); - uc15_api_req (2, data & 0377); /* API 2 */ - } - return SCPE_OK; - -case 2: - return SCPE_OK; - } - -return SCPE_NXM; -} - -/* Request PDP15 to take an API interrupt */ - -t_stat uc15_api_req (int32 lvl, int32 vec) -{ -UC15_SHARED_WR (UC15_API_VEC + (lvl * UC15_API_VEC_MUL), vec); -UC15_ATOMIC_CAS (UC15_API_REQ + (lvl * UC15_API_VEC_MUL), 0, 1); -if (DEBUG_PRS (uca_dev)) - fprintf (sim_deb, ">>UC15: API request sent, API = %o/%d\n", - vec, lvl); -return SCPE_OK; -} - -/* Routine to poll for state changes from PDP15 */ - -t_stat uc15_svc (UNIT *uptr) -{ -uint32 t; - -t = UC15_SHARED_RD (UC15_TCBP_WR); /* TCBP written? */ -if ((t != 0) && UC15_ATOMIC_CAS (UC15_TCBP_WR, 1, 0)) { /* for real? */ - ucb_csr |= UCBC_NTCB; /* set new TCB flag */ - if (ucb_csr & CSR_IE) - SET_INT (UCB); - uc15_set_memsize (); /* update mem size */ - } -t = UC15_SHARED_RD (UC15_API_UPD); /* API update? */ -if ((t != 0) && UC15_ATOMIC_CAS (UC15_API_UPD, 1, 0)) { /* for real? */ - uc15_get_uca_buf (); /* update UCA buf */ - } -sim_activate (uptr, uc15_poll); /* next poll */ -return SCPE_OK; -} - -/* Routine to assemble/update uca_buf - - Note that the PDP-15 and PDP-11 have opposite interpretations of - API requests. On the PDP-15, a "1" indicates an active request. - On the PDP-11, a "1" indicates request done (API inactive). -*/ - -int32 uc15_get_uca_buf (void) -{ -int32 i, t; -static int32 ucab_api[4] = - { UCAB_API0, UCAB_API1, UCAB_API2, UCAB_API3 }; - -t = UC15_SHARED_RD (UC15_TCBP); /* get TCB ptr */ -uca_buf = (t >> 15) & UCAB_M_TCBHI; /* PDP15 bits<1:2> */ -t = cpu_unit.capac >> 13; /* local mem in 4KW */ -uca_buf |= ((t & UCAB_M_LOCAL) << UCAB_V_LOCAL); -t = UC15_SHARED_RD (UC15_API_SUMM); /* get API summary */ -for (i = 0; i < 4; i++) { /* check 0..3 */ - if (((t >> i) & 1) == 0) /* level inactive? */ - uca_buf |= ucab_api[i]; /* set status bit */ - } -if ((t == 0) && ((uca_csr & UCAC_APID) == 0)) { /* API req now 0? */ - uca_csr |= UCAC_APID; /* set flag */ - if ((uca_csr & CSR_IE) != 0) /* if ie, req int */ - SET_INT (UCA); - } -return uca_buf; -} - -/* Routine to set overall memory limit for UC15 checking */ - -void uc15_set_memsize (void) -{ -uint32 t = UC15_SHARED_RD (UC15_PDP15MEM); /* get PDP15 memory size */ -if (t == 0) /* PDP15 not running? */ - t = PDP15_MAXMEM * 2; /* max mem in bytes */ -uc15_memsize = t + MEMSIZE; /* shared + local mem */ -if (uc15_memsize > (UNIMEMSIZE - IOPAGESIZE)) /* more than 18b? */ - uc15_memsize = UNIMEMSIZE - IOPAGESIZE; /* limit */ -return; -} - -/* Reset routine - - Aside from performing a device reset, this routine sets up shared - UC15 state and shared PDP15 main memory. It also reads the size - of PDP15 main memory (in PDP11 bytes) from the shared state region. -*/ - -t_stat uc15_reset (DEVICE *dptr) -{ -t_stat r; -void *basead; - -uca_csr = 0; -uca_buf = 0; -ucb_csr = 0; -ucb_buf = 0; -CLR_INT (UCA); -CLR_INT (UCB); -if (uc15_shmem == NULL) { /* allocate shared state */ - r = sim_shmem_open ("UC15SharedState", UC15_STATE_SIZE * sizeof (int32), &uc15_shmem, &basead); - if (r != SCPE_OK) - return r; - uc15_shstate = (int32 *) basead; - } -if (pdp15_shmem == NULL) { /* allocate shared memory */ - r = sim_shmem_open ("PDP15MainMemory", PDP15_MAXMEM * sizeof (int32), &pdp15_shmem, &basead); - if (r != SCPE_OK) - return r; - pdp15_mem = (int32 *) basead; - } -uc15_set_memsize (); -sim_activate (dptr->units, uc15_poll); /* start polling */ -return SCPE_OK; -} - -/* Shared state ex/mod routines for debug */ - -t_stat uc15_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) -{ -if (addr >= UC15_STATE_SIZE) - return SCPE_NXM; -if (vptr != NULL) - *vptr = UC15_SHARED_RD ((int32) addr); -return SCPE_OK; -} - -t_stat uc15_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) -{ -if (addr >= UC15_STATE_SIZE) - return SCPE_NXM; -UC15_SHARED_WR ((int32) addr, (int32) val); -return SCPE_OK; -} - -/* Fake attach routine to kill attach attempts */ - -t_stat uc15_attach (UNIT *uptr, char *cptr) -{ -return SCPE_NOFNC; -} - -/* Shutdown detach routine to release shared memories */ - -t_stat uc15_detach (UNIT *uptr) -{ -if ((sim_switches & SIM_SW_SHUT) == 0) /* only if shutdown */ - return SCPE_NOFNC; -sim_shmem_close (uc15_shmem); /* release shared state */ -sim_shmem_close (pdp15_shmem); /* release shared mem */ -return SCPE_OK; -} - -/* Physical read/write memory routines - Used by CPU and IO devices - Physical address is known to be legal - We can use MEMSIZE rather than cpu_memsize because configurations - were limited to 16KW of local memory - 8b and 16b writes clear the upper 2b of PDP-15 memory -*/ - -int32 uc15_RdMemW (int32 pa) -{ -if (((uint32) pa) < MEMSIZE) - return M[pa >> 1]; -else { - pa = pa - MEMSIZE; - return (pdp15_mem[pa >> 1] & DMASK); - } -} - -int32 uc15_RdMemB (int32 pa) -{ -if (((uint32) pa) < MEMSIZE) - return ((pa & 1)? (M[pa >> 1] >> 8): (M[pa >> 1] & 0377)); -else { - pa = pa - MEMSIZE; - return ((pa & 1)? (pdp15_mem[pa >> 1] >> 8): (pdp15_mem[pa >> 1] & 0377)); - } -} - -void uc15_WrMemW (int32 pa, int32 d) -{ -if (((uint32) pa) < MEMSIZE) - M[pa >> 1] = d; -else { - pa = pa - MEMSIZE; - pdp15_mem[pa >> 1] = d & DMASK; - } -return; -} - -void uc15_WrMemB (int32 pa, int32 d) -{ -if (((uint32) pa) < MEMSIZE) - M[pa >> 1] = (pa & 1)? - ((M[pa >> 1] & 0377) | ((d & 0377) << 8)): \ - ((M[pa >> 1] & ~0377) | (d & 0377)); -else { - pa = pa - MEMSIZE; - pdp15_mem[pa >> 1] = (pa & 1)? - ((pdp15_mem[pa >> 1] & 0377) | ((d & 0377) << 8)): \ - ((pdp15_mem[pa >> 1] & ~0377) | (d & 0377)); - } -return; -} - -/* 18b DMA routines - physical only */ - -int32 Map_Read18 (uint32 ba, int32 bc, uint32 *buf) -{ -uint32 alim, lim; - -ba = (ba & UNIMASK) & ~01; /* trim, align addr */ -lim = ba + (bc & ~01); -if (lim < uc15_memsize) /* end ok? */ - alim = lim; -else if (ba < uc15_memsize) /* no, strt ok? */ - alim = uc15_memsize; -else return bc; /* no, err */ -for ( ; ba < alim; ba = ba + 2) { /* by 18b words */ - if (ba < MEMSIZE) - *buf++ = M[ba >> 1]; - else *buf++ = pdp15_mem[(ba - MEMSIZE) >> 1] & 0777777; - } -return (lim - alim); -} - -int32 Map_Write18 (uint32 ba, int32 bc, uint32 *buf) -{ -uint32 alim, lim; - -ba = (ba & UNIMASK) & ~01; /* trim, align addr */ -lim = ba + (bc & ~01); -if (lim < uc15_memsize) /* end ok? */ - alim = lim; -else if (ba < uc15_memsize) /* no, strt ok? */ - alim = uc15_memsize; -else return bc; /* no, err */ -for ( ; ba < alim; ba = ba + 2) { /* by 18 bit words */ - if (ba < MEMSIZE) - M[ba >> 1] = *buf++ & DMASK; - else pdp15_mem[(ba - MEMSIZE) >> 1] = *buf++ & 0777777; - } -return (lim - alim); -} diff --git a/PDP11/pdp11_uqssp.h b/PDP11/pdp11_uqssp.h deleted file mode 100644 index a5848c25..00000000 --- a/PDP11/pdp11_uqssp.h +++ /dev/null @@ -1,169 +0,0 @@ -/* pdp11_uqssp.h: Unibus/Qbus storage systems port definitions file - - Copyright (c) 2001-2008, 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. - - 30-Aug-02 RMS Added TMSCP support -*/ - -#ifndef PDP11_UQSSP_H_ -#define PDP11_UQSSP_H_ 0 - -/* IP register - initialization and polling - - read - controller polls command queue - 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 { - int32 ioff; /* intr offset */ - uint32 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 /* MSCP */ -#define UQ_CID_TMSCP 1 /* TMSCP */ -#define UQ_CID_DUP 2 /* DUP */ -#define UQ_CID_DIAG 0xFF /* diagnostic */ - -#endif diff --git a/PDP11/pdp11_vh.c b/PDP11/pdp11_vh.c deleted file mode 100644 index 1e6616e4..00000000 --- a/PDP11/pdp11_vh.c +++ /dev/null @@ -1,1459 +0,0 @@ -/* pdp11_vh.c: DHQ11 asynchronous terminal multiplexor simulator - - Copyright (c) 2004-2018, John A. Dundas III - Portions derived from work by Robert M Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of the Author shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the Author. - - vh DHQ11 asynch multiplexor for SIMH - - 28-May-18 RMS Changed to avoid nested comment warnings (Mark Pizzolato) - 02-Jun-11 MP Added debugging support to trace register, interrupt - and data traffic (SET VH DEBUG[=REG;INT;XMT;RCV]) - Added SET LOG and SET NOLOG support for logging mux - traffic - Fixed SET VH LINES=n to correctly adjust the number - of lines available to be 8, 16, 24, or 32. - Fixed performance issue avoiding redundant polling - 03-Jan-10 JAD Eliminate gcc warnings - 24-Nov-08 JDB Removed tmxr_send_buffered_data declaration (now in sim_tmxr.h) - 19-Nov-08 RMS Revised for common TMXR show routines - 18-Jun-07 RMS Added UNIT_IDLE flag - 29-Oct-06 RMS Synced poll and clock - 07-Jul-05 RMS Removed extraneous externs - 15-Jun-05 RMS Revised for new autoconfigure interface - Fixed bug in vector display routine - 12-Jun-04 RMS Repair MS2SIMH macro to avoid divide by 0 bug - 08-Jun-04 JAD Repair vh_dev initialization; remove unused - variables, cast to avoid conversion confusion - 07-Jun-04 JAD Complete function prototypes of forward declarations. - Repair broken prototypes of vh_rd() and vh_wr() - Explicitly size integer declarations - 4-Jun-04 JAD Preliminary code: If operating in a PDP-11 Unibus - environment, force DHU mode - 29-May-04 JAD Make certain RX.TIMER is within allowable range - 25-May-04 JAD All time-based operations are scaled by tmxr_poll units - 23-May-04 JAD Change to fifo_get() and dq_tx_report() to avoid - gratuitous stack manipulation - 20-May-04 JAD Made modem control and auto-hangup unit flags - 19-May-04 JAD Fix problem with modem status where the line number - was not being included - 12-May-04 JAD Revised for updated tmxr interfaces - 28-Jan-04 JAD Original creation and testing - -I/O Page Registers - -CSR 17 760 440 (float) - -Vector: 300 (float) - -Priority: BR4 - -Rank: 32 - -*/ -/* MANY constants needed! */ - -#if defined (VM_VAX) -#include "vax_defs.h" -extern int32 int_req[IPL_HLVL]; -#endif - -#if defined (VM_PDP11) -#include "pdp11_defs.h" -extern int32 int_req[IPL_HLVL]; -extern uint32 cpu_opt; -#endif - -#include "sim_tmxr.h" - -/* imports from pdp11_stddev.c: */ -extern int32 tmxr_poll, clk_tps; -/* convert ms to SIMH time units based on tmxr_poll polls per second */ -#define MS2SIMH(ms) (((ms) * clk_tps) / 1000) - -#ifndef VH_MUXES -#define VH_MUXES (4) -#endif -#define VH_MNOMASK (VH_MUXES - 1) - -#define VH_LINES (8) - -#define UNIT_V_MODEDHU (UNIT_V_UF + 0) -#define UNIT_V_FASTDMA (UNIT_V_UF + 1) -#define UNIT_V_MODEM (UNIT_V_UF + 2) -#define UNIT_V_HANGUP (UNIT_V_UF + 3) -#define UNIT_MODEDHU (1 << UNIT_V_MODEDHU) -#define UNIT_FASTDMA (1 << UNIT_V_FASTDMA) -#define UNIT_MODEM (1 << UNIT_V_MODEM) -#define UNIT_HANGUP (1 << UNIT_V_HANGUP) - -/* VHCSR - 160440 - Control and Status Register */ - -#define CSR_M_IND_ADDR (017) -#define CSR_SKIP (1 << 4) -#define CSR_MASTER_RESET (1 << 5) -#define CSR_RXIE (1 << 6) -#define CSR_RX_DATA_AVAIL (1 << 7) -#define CSR_M_TX_LINE (017) -#define CSR_V_TX_LINE (8) -#define CSR_TX_DMA_ERR (1 << 12) -#define CSR_DIAG_FAIL (1 << 13) -#define CSR_TXIE (1 << 14) -#define CSR_TX_ACTION (1 << 15) -#define CSR_GETCHAN(x) ((x) & CSR_M_IND_ADDR) -#define CSR_RW \ - (CSR_TXIE|CSR_RXIE|CSR_SKIP|CSR_M_IND_ADDR|CSR_MASTER_RESET) -#define RESET_ABORT (052525) - -/* Receive Buffer (RBUF) */ - -#define FIFO_SIZE (256) -#define FIFO_ALARM (191) -#define FIFO_HALF (FIFO_SIZE / 2) -#define RBUF_M_RX_CHAR (0377) -#define RBUF_M_RX_LINE (07) -#define RBUF_V_RX_LINE (8) -#define RBUF_PARITY_ERR (1 << 12) -#define RBUF_FRAME_ERR (1 << 13) -#define RBUF_OVERRUN_ERR (1 << 14) -#define RBUF_DATA_VALID (1 << 15) -#define RBUF_GETLINE(x) (((x) >> RBUF_V_RX_LINE) & RBUF_M_RX_LINE) -#define RBUF_PUTLINE(x) ((x) << RBUF_V_RX_LINE) -#define RBUF_DIAG \ - (RBUF_PARITY_ERR|RBUF_FRAME_ERR|RBUF_OVERRUN_ERR) -#define XON (021) -#define XOFF (023) - -/* Transmit Character Register (TXCHAR) */ - -#define TXCHAR_M_CHAR (0377) -#define TXCHAR_TX_DATA_VALID (1 << 15) - -/* Receive Timer Register (RXTIMER) */ - -#define RXTIMER_M_RX_TIMER (0377) - -/* Line-Parameter Register (LPR) */ - -#define LPR_DISAB_XRPT (1 << 0) /* not impl. in real DHU */ -#define LPR_V_DIAG (1) -#define LPR_M_DIAG (03) -#define LPR_V_CHAR_LGTH (3) -#define LPR_M_CHAR_LGTH (03) -#define LPR_PARITY_ENAB (1 << 5) -#define LPR_EVEN_PARITY (1 << 6) -#define LPR_STOP_CODE (1 << 7) -#define LPR_V_RX_SPEED (8) -#define LPR_M_RX_SPEED (017) -#define LPR_V_TX_SPEED (12) -#define LPR_M_TX_SPEED (017) - -#define RATE_50 (0) -#define RATE_75 (1) -#define RATE_110 (2) -#define RATE_134 (3) -#define RATE_150 (4) -#define RATE_300 (5) -#define RATE_600 (6) -#define RATE_1200 (7) -#define RATE_1800 (8) -#define RATE_2000 (9) -#define RATE_2400 (10) -#define RATE_4800 (11) -#define RATE_7200 (12) -#define RATE_9600 (13) -#define RATE_19200 (14) -#define RATE_38400 (15) - -/* Line-Status Register (STAT) */ - -#define STAT_DHUID (1 << 8) /* mode: 0=DHV, 1=DHU */ -#define STAT_MDL (1 << 9) /* always 0, has modem support */ -#define STAT_CTS (1 << 11) /* CTS from modem */ -#define STAT_DCD (1 << 12) /* DCD from modem */ -#define STAT_RI (1 << 13) /* RI from modem */ -#define STAT_DSR (1 << 15) /* DSR from modem */ - -/* FIFO Size Register (FIFOSIZE) */ - -#define FIFOSIZE_M_SIZE (0377) - -/* FIFO Data Register (FIFODATA) */ - -#define FIFODATA_W0 (0377) -#define FIFODATA_V_W1 (8) -#define FIFODATA_M_W1 (0377) - -/* Line-Control Register (LNCTRL) */ - -#define LNCTRL_TX_ABORT (1 << 0) -#define LNCTRL_IAUTO (1 << 1) -#define LNCTRL_RX_ENA (1 << 2) -#define LNCTRL_BREAK (1 << 3) -#define LNCTRL_OAUTO (1 << 4) -#define LNCTRL_FORCE_XOFF (1 << 5) -#define LNCTRL_V_MAINT (6) -#define LNCTRL_M_MAINT (03) -#define LNCTRL_LINK_TYPE (1 << 8) /* 0=data leads only, 1=modem */ -#define LNCTRL_DTR (1 << 9) /* DTR to modem */ -#define LNCTRL_RTS (1 << 12) /* RTS to modem */ - -/* Transmit Buffer Address Register Number 1 (TBUFFAD1) */ - -/* Transmit Buffer Address Register Number 2 (TBUFFAD2) */ - -#define TB2_M_TBUFFAD (077) -#define TB2_TX_DMA_START (1 << 7) -#define TB2_TX_ENA (1 << 15) - -/* Transmit DMA Buffer Counter (TBUFFCT) */ - -/* Self-Test Error Codes */ - -#define SELF_NULL (0201) -#define SELF_SKIP (0203) -#define SELF_OCT (0211) -#define SELF_RAM (0225) -#define SELF_RCD (0231) -#define SELF_DRD (0235) - -#define BMP_OK (0305) -#define BMP_BAD (0307) - -/* Loopback types */ - -#define LOOP_NONE (0) -#define LOOP_H325 (1) -#define LOOP_H3101 (2) /* p.2-13 DHQ manual */ -/* Local storage */ - -static uint16 vh_csr[VH_MUXES] = { 0 }; /* CSRs */ -static uint16 vh_timer[VH_MUXES] = { 1 }; /* controller timeout */ -static uint16 vh_mcount[VH_MUXES] = { 0 }; -static uint32 vh_timeo[VH_MUXES] = { 0 }; -static uint32 vh_ovrrun[VH_MUXES] = { 0 }; /* line overrun bits */ -/* XOFF'd channels, one bit/channel */ -static uint32 vh_stall[VH_MUXES] = { 0 }; -static uint16 vh_loop[VH_MUXES] = { 0 }; /* loopback status */ - -/* One bit per controller: */ -static uint32 vh_rxi = 0; /* rcv interrupts */ -static uint32 vh_txi = 0; /* xmt interrupts */ -static uint32 vh_crit = 0; /* FIFO.CRIT */ - -static const int32 bitmask[4] = { 037, 077, 0177, 0377 }; - -/* RX FIFO state */ - -static int32 rbuf_idx[VH_MUXES] = { 0 };/* index into vh_rbuf */ -static uint32 vh_rbuf[VH_MUXES][FIFO_SIZE] = { { 0 } }; - -/* TXQ state */ - -#define TXQ_SIZE (16) -static int32 txq_idx[VH_MUXES] = { 0 }; -static uint32 vh_txq[VH_MUXES][TXQ_SIZE] = { { 0 } }; - -/* Need to extend the TMLN structure */ - -typedef struct { - TMLN *tmln; - uint16 lpr; /* line parameters */ - uint16 lnctrl; /* line control */ - uint16 lstat; /* line modem status */ - uint16 tbuffct; /* remaining character count */ - uint16 tbuf1; - uint16 tbuf2; - uint16 txchar; /* single character I/O */ -} TMLX; - -static TMLN vh_ldsc[VH_MUXES * VH_LINES] = { { 0 } }; -static TMXR vh_desc = { VH_MUXES * VH_LINES, 0, 0, vh_ldsc }; -static TMLX vh_parm[VH_MUXES * VH_LINES] = { { 0 } }; - -/* debugging bitmaps */ -#define DBG_REG 0x0001 /* trace read/write registers */ -#define DBG_INT 0x0002 /* display transfer requests */ -// #define DBG_XMT TMXR_DBG_XMT /* display Transmitted Data */ -// #define DBG_RCV TMXR_DBG_RCV /* display Received Data */ - -DEBTAB vh_debug[] = { - {"REG", DBG_REG}, - {"INT", DBG_INT}, -// {"XMT", DBG_XMT}, -// {"RCV", DBG_RCV}, - {0} -}; - -/* Forward references */ -static t_stat vh_rd (int32 *data, int32 PA, int32 access); -static t_stat vh_wr (int32 data, int32 PA, int32 access); -static t_stat vh_svc (UNIT *uptr); -static int32 vh_rxinta (void); -static int32 vh_txinta (void); -static t_stat vh_clear (int32 vh, t_bool flag); -static t_stat vh_reset (DEVICE *dptr); -static t_stat vh_attach (UNIT *uptr, char *cptr); -static t_stat vh_detach (UNIT *uptr); -static t_stat vh_show_detail (FILE *st, UNIT *uptr, int32 val, void *desc); -static t_stat vh_show_rbuf (FILE *st, UNIT *uptr, int32 val, void *desc); -static t_stat vh_show_txq (FILE *st, UNIT *uptr, int32 val, void *desc); -static t_stat vh_putc (int32 vh, TMLX *lp, int32 chan, int32 data); -static void doDMA (int32 vh, int32 chan); -static t_stat vh_setnl (UNIT *uptr, int32 val, char *cptr, void *desc); -static t_stat vh_set_log (UNIT *uptr, int32 val, char *cptr, void *desc); -static t_stat vh_set_nolog (UNIT *uptr, int32 val, char *cptr, void *desc); -static t_stat vh_show_log (FILE *st, UNIT *uptr, int32 val, void *desc); - -int32 tmxr_send_buffered_data (TMLN *lp); - -/* SIMH I/O Structures */ - -static DIB vh_dib = { - IOBA_VH, - IOLN_VH * VH_MUXES, - &vh_rd, /* read */ - &vh_wr, /* write */ - 2, /* # of vectors */ - IVCL (VHRX), - VEC_VHRX, - { &vh_rxinta, &vh_txinta } /* int. ack. routines */ -}; - -static UNIT vh_unit[VH_MUXES] = { - { UDATA (&vh_svc, UNIT_IDLE|UNIT_ATTABLE, 0) }, -}; - -static const REG vh_reg[] = { - { BRDATA (CSR, vh_csr, DEV_RDX, 16, VH_MUXES) }, - { GRDATA (DEVADDR, vh_dib.ba, DEV_RDX, 32, 0), REG_HRO }, - { GRDATA (DEVVEC, vh_dib.vec, DEV_RDX, 16, 0), REG_HRO }, - { NULL } -}; - -static const MTAB vh_mod[] = { - { UNIT_MODEDHU, 0, "DHV mode", "DHV", NULL }, - { UNIT_MODEDHU, UNIT_MODEDHU, "DHU mode", "DHU", NULL }, - { UNIT_FASTDMA, 0, NULL, "NORMAL", NULL }, - { UNIT_FASTDMA, UNIT_FASTDMA, "fast DMA", "FASTDMA", NULL }, - { UNIT_MODEM, 0, NULL, "NOMODEM", NULL }, - { UNIT_MODEM, UNIT_MODEM, "modem", "MODEM", NULL }, - { UNIT_HANGUP, 0, NULL, "NOHANGUP", NULL }, - { UNIT_HANGUP, UNIT_HANGUP, "hangup", "HANGUP", NULL }, - { MTAB_XTD|MTAB_VDV, 020, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, VH_LINES, "VECTOR", "VECTOR", - &set_vec, &show_vec_mux, (void *) &vh_desc }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "AUTOCONFIGURE", - &set_addr_flt, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "LINES", "LINES", - &vh_setnl, &tmxr_show_lines, (void *) &vh_desc }, - { UNIT_ATT, UNIT_ATT, "summary", NULL, - NULL, &tmxr_show_summ, (void *) &vh_desc }, - { MTAB_XTD|MTAB_VDV | MTAB_NMO, 1, "CONNECTIONS", NULL, - NULL, &tmxr_show_cstat, (void *) &vh_desc }, - { MTAB_XTD|MTAB_VDV | MTAB_NMO, 0, "STATISTICS", NULL, - NULL, &tmxr_show_cstat, (void *) &vh_desc }, - { MTAB_XTD|MTAB_VDV, 1, NULL, "DISCONNECT", - &tmxr_dscln, NULL, &vh_desc }, - { MTAB_XTD|MTAB_VDV | MTAB_NMO, 0, "DETAIL", NULL, - NULL, &vh_show_detail, NULL }, - { MTAB_XTD|MTAB_VDV | MTAB_NMO, 0, "RBUF", NULL, - NULL, &vh_show_rbuf, NULL }, - { MTAB_XTD|MTAB_VDV | MTAB_NMO, 0, "TXQ", NULL, - NULL, &vh_show_txq, NULL }, - { MTAB_XTD|MTAB_VDV | MTAB_NC, 0, NULL, "LOG", - &vh_set_log, NULL, &vh_desc }, - { MTAB_XTD|MTAB_VDV | MTAB_NC, 0, NULL, "NOLOG", - &vh_set_nolog, NULL, &vh_desc }, - { MTAB_XTD|MTAB_VDV | MTAB_NMO, 0, "LOG", NULL, - NULL, &vh_show_log, &vh_desc }, - { 0 } -}; - -DEVICE vh_dev = { - "VH", /* name */ - vh_unit, /* units */ - (REG *)vh_reg, /* registers */ - (MTAB *)vh_mod, /* modifiers */ - VH_MUXES, /* # units */ - DEV_RDX, /* address radix */ - 8, /* address width */ - 1, /* address increment */ - DEV_RDX, /* data radix */ - 8, /* data width */ - NULL, /* examine routine */ - NULL, /* deposit routine */ - &vh_reset, /* reset routine */ - NULL, /* boot routine */ - &vh_attach, /* attach routine */ - &vh_detach, /* detach routine */ - (void *)&vh_dib,/* context */ - DEV_FLTA | DEV_DISABLE | DEV_DIS |DEV_NET | DEV_QBUS | DEV_UBUS | DEV_DEBUG, /* flags */ - 0, vh_debug -}; - -/* Register names for Debug tracing */ -static char *vh_rd_dhv_regs[] = - {"CSR ", "RBUF ", "LPR ", "STAT ", "LNCTRL", "TBFAD1", "TBFAD2", "TBFCNT" }; -static char *vh_wr_dhv_regs[] = - {"CSR ", "TXCHAR", "LPR ", "STAT ", "LNCTRL", "TBFAD1", "TBFAD2", "TBFCNT" }; -static char *vh_rd_dhu_regs[] = - {"CSR ", "RBUF ", "LPR ", "FIFOSZ", "LNCTRL", "TBFAD1", "TBFAD2", "TBFCNT" }; -static char *vh_wr_dhu_regs[] = - {"CSR ", "RXTIMR", "LPR ", "FIFODT", "LNCTRL", "TBFAD1", "TBFAD2", "TBFCNT" }; - -/* Interrupt routines */ - -static void vh_clr_rxint ( int32 vh ) -{ - vh_rxi &= ~(1 << vh); - if (vh_rxi == 0) - CLR_INT (VHRX); - else - SET_INT (VHRX); -} - -static void vh_set_rxint ( int32 vh ) -{ - vh_rxi |= (1 << vh); - SET_INT (VHRX); -} - -/* RX interrupt ack. (bus cycle) */ - -static int32 vh_rxinta (void) -{ - int32 vh; - - for (vh = 0; vh < vh_desc.lines/VH_LINES; vh++) { - if (vh_rxi & (1 << vh)) { - sim_debug(DBG_INT, &vh_dev, "vh_rzinta(vh=%d)\n", vh); - vh_clr_rxint (vh); - return (vh_dib.vec + (vh * 010)); - } - } - return (0); -} - -static void vh_clr_txint ( int32 vh ) -{ - vh_txi &= ~(1 << vh); - if (vh_txi == 0) - CLR_INT (VHTX); - else - SET_INT (VHTX); -} - -static void vh_set_txint ( int32 vh ) -{ - vh_txi |= (1 << vh); - SET_INT (VHTX); -} - -/* TX interrupt ack. (bus cycle) */ - -static int32 vh_txinta (void) -{ - int32 vh; - - for (vh = 0; vh < vh_desc.lines/VH_LINES; vh++) { - if (vh_txi & (1 << vh)) { - sim_debug(DBG_INT, &vh_dev, "vh_txinta(vh=%d)\n", vh); - vh_clr_txint (vh); - return (vh_dib.vec + 4 + (vh * 010)); - } - } - return (0); -} -/* RX FIFO get/put routines */ - -/* return 0 on success, -1 on FIFO overflow */ - -static int32 fifo_put ( int32 vh, - TMLX *lp, - int32 data ) -{ - int32 status = 0; - - if (lp == NULL) - goto override; - /* this might have to move to vh_getc() */ - if ((lp->lnctrl & LNCTRL_OAUTO) && ((data & RBUF_DIAG) == 0)) { - TMLX *l0p; - /* implement transmitted data flow control */ - switch (data & 0377) { - case XON: - lp->tbuf2 |= TB2_TX_ENA; - goto common; - case XOFF: - lp->tbuf2 &= ~TB2_TX_ENA; - common: - /* find line 0 for this controller */ - l0p = &vh_parm[vh * VH_LINES]; - if (l0p->lpr & LPR_DISAB_XRPT) - return (0); - break; - default: - break; - } - } -/* BUG: which of the following 2 is correct? */ - /* if ((data & RBUF_DIAG) == RBUF_DIAG) */ - if (data & RBUF_DIAG) - goto override; - if (((lp->lnctrl >> LNCTRL_V_MAINT) & LNCTRL_M_MAINT) == 2) - goto override; - if (!(lp->lnctrl & LNCTRL_RX_ENA)) - return (0); -override: - vh_csr[vh] |= CSR_RX_DATA_AVAIL; - if (rbuf_idx[vh] < FIFO_SIZE) { - vh_rbuf[vh][rbuf_idx[vh]] = data; - rbuf_idx[vh] += 1; - } else { - vh_ovrrun[vh] |= (1 << RBUF_GETLINE (data)); - status = -1; - } - if (vh_csr[vh] & CSR_RXIE) { - if (vh_unit[vh].flags & UNIT_MODEDHU) { - /* was it a modem status change? */ - if ((data & RBUF_DIAG) == RBUF_DIAG) - vh_set_rxint (vh); - /* look for FIFO alarm @ 3/4 full */ - else if (rbuf_idx[vh] == FIFO_ALARM) - vh_set_rxint (vh); - else if (vh_timer[vh] == 0) - ; /* nothing, infinite timeout */ - else if (vh_timer[vh] == 1) - vh_set_rxint (vh); - else if (vh_timeo[vh] == 0) - vh_timeo[vh] = MS2SIMH (vh_timer[vh]) + 1; - } else { - /* Interrupt on transition _from_ an empty FIFO */ - if (rbuf_idx[vh] == 1) - vh_set_rxint (vh); - } - } - if (rbuf_idx[vh] > FIFO_ALARM) - vh_crit |= (1 << vh); - /* Implement RX FIFO-level flow control */ - if (lp != NULL) { - if ((lp->lnctrl & LNCTRL_FORCE_XOFF) || - ((vh_crit & (1 << vh)) && (lp->lnctrl & LNCTRL_IAUTO))) { - int32 chan = RBUF_GETLINE(data); - vh_stall[vh] ^= (1 << chan); - /* send XOFF every other character received */ - if (vh_stall[vh] & (1 << chan)) - vh_putc (vh, lp, chan, XOFF); - } - } - return (status); -} - -static int32 fifo_get ( int32 vh ) -{ - int32 data, i; - - if (rbuf_idx[vh] == 0) { - vh_csr[vh] &= ~CSR_RX_DATA_AVAIL; - return (0); - } - /* pick off the first character, mark valid */ - data = vh_rbuf[vh][0] | RBUF_DATA_VALID; - /* move the remainder up */ - rbuf_idx[vh] -= 1; - for (i = 0; i < rbuf_idx[vh]; i++) - vh_rbuf[vh][i] = vh_rbuf[vh][i + 1]; - /* rbuf_idx[vh] -= 1; */ - /* look for any previous overruns */ - if (vh_ovrrun[vh]) { - for (i = 0; i < VH_LINES; i++) { - if (vh_ovrrun[vh] & (1 << i)) { - fifo_put (vh, NULL, RBUF_OVERRUN_ERR | - RBUF_PUTLINE (i)); - vh_ovrrun[vh] &= ~(1 << i); - break; - } - } - } - /* recompute FIFO alarm condition */ - if ((rbuf_idx[vh] < FIFO_HALF) && (vh_crit & (1 << vh))) { - vh_crit &= ~(1 << vh); - /* send XON to all XOFF'd channels on this controller */ - for (i = 0; i < VH_LINES; i++) { - TMLX *lp = &vh_parm[(vh * VH_LINES) + i]; - if (lp->lnctrl & LNCTRL_FORCE_XOFF) - continue; - if (vh_stall[vh] & (1 << i)) { - vh_putc (vh, NULL, i, XON); - vh_stall[vh] &= ~(1 << i); - } - } - } - return (data & 0177777); -} -/* TX Q manipulation */ - -static int32 dq_tx_report ( int32 vh ) -{ - int32 data, i; - - if (txq_idx[vh] == 0) - return (0); - data = vh_txq[vh][0]; - txq_idx[vh] -= 1; - for (i = 0; i < txq_idx[vh]; i++) - vh_txq[vh][i] = vh_txq[vh][i + 1]; - /* txq_idx[vh] -= 1; */ - return (data & 0177777); -} - -static void q_tx_report ( int32 vh, - int32 data ) -{ - if (vh_csr[vh] & CSR_TXIE) - vh_set_txint (vh); - if (txq_idx[vh] >= TXQ_SIZE) { -/* BUG: which of the following 2 is correct? */ - dq_tx_report (vh); - /* return; */ - } - vh_txq[vh][txq_idx[vh]] = CSR_TX_ACTION | data; - txq_idx[vh] += 1; -} -/* Channel get/put routines */ - -static void HangupModem ( int32 vh, - TMLX *lp, - int32 chan ) -{ - if (vh_unit[vh].flags & UNIT_MODEM) - lp->lstat &= ~(STAT_DCD|STAT_DSR|STAT_CTS|STAT_RI); - if (lp->lnctrl & LNCTRL_LINK_TYPE) - /* RBUF<0> = 0 for modem status */ - fifo_put (vh, lp, RBUF_DIAG | - RBUF_PUTLINE (chan) | - ((lp->lstat >> 8) & 0376)); - /* BUG: check for overflow above */ -} - -/* TX a character on a line, regardless of the TX enable state */ - -static t_stat vh_putc ( int32 vh, - TMLX *lp, - int32 chan, - int32 data ) -{ - int32 val; - t_stat status = SCPE_OK; - - /* truncate to desired character length */ - data &= bitmask[(lp->lpr >> LPR_V_CHAR_LGTH) & LPR_M_CHAR_LGTH]; - switch ((lp->lnctrl >> LNCTRL_V_MAINT) & LNCTRL_M_MAINT) { - case 0: /* normal */ -#if 0 - /* check for (external) loopback setting */ - switch (vh_loop[vh]) { - default: - case LOOP_NONE: - break; - } -#endif - status = tmxr_putc_ln (lp->tmln, data); - if (status == SCPE_LOST) { - tmxr_reset_ln (lp->tmln); - HangupModem (vh, lp, chan); - } else if (status == SCPE_STALL) { - /* let's flush and try again */ - tmxr_send_buffered_data (lp->tmln); - status = tmxr_putc_ln (lp->tmln, data); - } - break; - case 1: /* auto echo */ - break; - case 2: /* local loopback */ - if (lp->lnctrl & LNCTRL_BREAK) - val = fifo_put (vh, lp, - RBUF_FRAME_ERR | RBUF_PUTLINE (chan)); - else - val = fifo_put (vh, lp, - RBUF_PUTLINE (chan) | data); - status = (val < 0) ? SCPE_TTMO : SCPE_OK; - break; - default: /* remote loopback */ - break; - } - return (status); -} - -/* Retrieve all stored input from TMXR and place in RX FIFO */ - -static void vh_getc ( int32 vh ) -{ - uint32 i, c; - TMLX *lp; - - for (i = 0; i < (uint32)VH_LINES; i++) { - lp = &vh_parm[(vh * VH_LINES) + i]; - while ((c = tmxr_getc_ln (lp->tmln)) != 0) { - if (c & SCPE_BREAK) { - fifo_put (vh, lp, - RBUF_FRAME_ERR | RBUF_PUTLINE (i)); - /* BUG: check for overflow above */ - } else { - c &= bitmask[(lp->lpr >> LPR_V_CHAR_LGTH) & - LPR_M_CHAR_LGTH]; - fifo_put (vh, lp, RBUF_PUTLINE (i) | c); - /* BUG: check for overflow above */ - } - } - } -} - -/* I/O dispatch routines */ - -static t_stat vh_rd ( int32 *data, - int32 PA, - int32 access ) -{ - int32 vh = ((PA - vh_dib.ba) >> 4) & VH_MNOMASK, line; - TMLX *lp; - - switch ((PA >> 1) & 7) { - case 0: /* CSR */ - *data = vh_csr[vh] | dq_tx_report (vh); - vh_csr[vh] &= ~0117400; /* clear the read-once bits */ - break; - case 1: /* RBUF */ - *data = fifo_get (vh); - break; - case 2: /* LPR */ - if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) { - *data = 0; - break; - } - line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); - lp = &vh_parm[line]; - *data = lp->lpr; - break; - case 3: /* STAT/FIFOSIZE */ - if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) { - *data = 0; - break; - } - line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); - lp = &vh_parm[line]; - *data = (lp->lstat & ~0377) | /* modem status */ -#if 0 - (64 - tmxr_tqln (lp->tmln)); -fprintf (stderr, "\rtqln %d\n", 64 - tmxr_tqln (lp->tmln)); -#else - 64; -#endif - break; - case 4: /* LNCTRL */ - if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) { - *data = 0; - break; - } - line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); - lp = &vh_parm[line]; - *data = lp->lnctrl; - break; - case 5: /* TBUFFAD1 */ - if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) { - *data = 0; - break; - } - line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); - lp = &vh_parm[line]; - *data = lp->tbuf1; - break; - case 6: /* TBUFFAD2 */ - if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) { - *data = 0; - break; - } - line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); - lp = &vh_parm[line]; - *data = lp->tbuf2; - break; - case 7: /* TBUFFCT */ - if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) { - *data = 0; - break; - } - line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); - lp = &vh_parm[line]; - *data = lp->tbuffct; - break; - default: - /* can't happen */ - break; - } - - sim_debug(DBG_REG, &vh_dev, "vh_rd(PA=0x%08X [%s], access=%d, data=0x%X)\n", PA, - ((vh_unit[vh].flags & UNIT_MODEDHU) ? vh_rd_dhu_regs : vh_rd_dhv_regs)[(PA >> 1) & 07], access, data); - - return (SCPE_OK); -} - -static t_stat vh_wr ( int32 data, - int32 PA, - int32 access ) -{ - int32 vh = ((PA - vh_dib.ba) >> 4) & VH_MNOMASK, line; - TMLX *lp; - - sim_debug(DBG_REG, &vh_dev, "vh_wr(PA=0x%08X [%s], access=%d, data=0x%X)\n", PA, - ((vh_unit[vh].flags & UNIT_MODEDHU) ? vh_wr_dhu_regs : vh_wr_dhv_regs)[(PA >> 1) & 07], access, data); - - switch ((PA >> 1) & 7) { - case 0: /* CSR, but no read-modify-write */ - if (access == WRITEB) - data = (PA & 1) ? - (vh_csr[vh] & 0377) | (data << 8) : - (vh_csr[vh] & ~0377) | (data & 0377); - if (data & CSR_MASTER_RESET) { - if ((vh_unit[vh].flags & UNIT_MODEDHU) && (data & CSR_SKIP)) - data &= ~CSR_MASTER_RESET; - if (vh == 0) /* Only start unit service on the first unit. Units are polled there */ - sim_activate (&vh_unit[vh], clk_cosched (tmxr_poll)); - /* vh_mcount[vh] = 72; */ /* 1.2 seconds */ - vh_mcount[vh] = MS2SIMH (1200); /* 1.2 seconds */ - } - if ((data & CSR_RXIE) == 0) - vh_clr_rxint (vh); - /* catch the RXIE transition if the FIFO is not empty */ - else if (((vh_csr[vh] & CSR_RXIE) == 0) && - (rbuf_idx[vh] != 0)) { - if (vh_unit[vh].flags & UNIT_MODEDHU) { - if (rbuf_idx[vh] > FIFO_ALARM) - vh_set_rxint (vh); - else if (vh_timer[vh] == 0) - ; - else if (vh_timer[vh] == 1) - vh_set_rxint (vh); - else if (vh_timeo[vh] == 0) - vh_timeo[vh] = MS2SIMH (vh_timer[vh]) + 1; - } else { - vh_set_rxint (vh); - } - } - if ((data & CSR_TXIE) == 0) - vh_clr_txint (vh); - else if (((vh_csr[vh] & CSR_TXIE) == 0) && - (txq_idx[vh] != 0)) - vh_set_txint (vh); - vh_csr[vh] = (vh_csr[vh] & ~((uint16) CSR_RW)) | (data & (uint16) CSR_RW); - break; - case 1: /* TXCHAR/RXTIMER */ - if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) - break; - if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) { - vh_mcount[vh] = 1; - break; - } - if (vh_unit[vh].flags & UNIT_MODEDHU) { - if (CSR_GETCHAN (vh_csr[vh]) != 0) - break; - if (access == WRITEB) - data = (PA & 1) ? - (vh_timer[vh] & 0377) | (data << 8) : - (vh_timer[vh] & ~0377) | (data & 0377); - vh_timer[vh] = data & 0377; -#if 0 - if (vh_csr[vh] & CSR_RXIE) { - if (rbuf_idx[vh] > FIFO_ALARM) - vh_set_rxint (vh); - else if (vh_timer[vh] == 0) - ; - else if (vh_timer[vh] == 1) - vh_set_rxint (vh); - else if (vh_timeo[vh] == 0) - vh_timeo[vh] = MS2SIMH (vh_timer[vh]) + 1; - } -#endif - } else { - line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); - lp = &vh_parm[line]; - if (access == WRITEB) - data = (PA & 1) ? - (lp->txchar & 0377) | (data << 8) : - (lp->txchar & ~0377) | (data & 0377); - lp->txchar = data; /* TXCHAR */ - if (lp->txchar & TXCHAR_TX_DATA_VALID) { - if (lp->tbuf2 & TB2_TX_ENA) - vh_putc (vh, lp, - CSR_GETCHAN (vh_csr[vh]), - lp->txchar); - q_tx_report (vh, - CSR_GETCHAN (vh_csr[vh]) << CSR_V_TX_LINE); - lp->txchar &= ~TXCHAR_TX_DATA_VALID; - } - } - break; - case 2: /* LPR */ - if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) { - vh_mcount[vh] = 1; - break; - } - if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) - break; - line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); - lp = &vh_parm[line]; - if (access == WRITEB) - data = (PA & 1) ? - (lp->lpr & 0377) | (data << 8) : - (lp->lpr & ~0377) | (data & 0377); - /* Modify only if CSR<3:0> == 0 */ - if (CSR_GETCHAN (vh_csr[vh]) != 0) - data &= ~LPR_DISAB_XRPT; - lp->lpr = data; - if (((lp->lpr >> LPR_V_DIAG) & LPR_M_DIAG) == 1) { - fifo_put (vh, lp, - RBUF_DIAG | - RBUF_PUTLINE (CSR_GETCHAN (vh_csr[vh])) | - BMP_OK); - /* BUG: check for overflow above */ - lp->lpr &= ~(LPR_M_DIAG << LPR_V_DIAG); - } - break; - case 3: /* STAT/FIFODATA */ - if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) { - vh_mcount[vh] = 1; - break; - } - if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) - break; - line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); - lp = &vh_parm[line]; - if (vh_unit[vh].flags & UNIT_MODEDHU) { - /* high byte writes not allowed */ - if (PA & 1) - break; - /* transmit 1 or 2 characters */ - if (!(lp->tbuf2 & TB2_TX_ENA)) - break; - vh_putc (vh, lp, CSR_GETCHAN (vh_csr[vh]), data); - q_tx_report (vh, CSR_GETCHAN (vh_csr[vh]) << CSR_V_TX_LINE); - if (access != WRITEB) - vh_putc (vh, lp, CSR_GETCHAN (vh_csr[vh]), - data >> 8); - } - break; - case 4: /* LNCTRL */ - if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) { - vh_mcount[vh] = 1; - break; - } - if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) - break; - line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); - lp = &vh_parm[line]; - if (access == WRITEB) - data = (PA & 1) ? - (lp->lnctrl & 0377) | (data << 8) : - (lp->lnctrl & ~0377) | (data & 0377); - /* catch the abort TX transition */ - if (!(lp->lnctrl & LNCTRL_TX_ABORT) && - (data & LNCTRL_TX_ABORT)) { - if ((lp->tbuf2 & TB2_TX_ENA) && - (lp->tbuf2 & TB2_TX_DMA_START)) { - lp->tbuf2 &= ~TB2_TX_DMA_START; - q_tx_report (vh, CSR_GETCHAN (vh_csr[vh]) << CSR_V_TX_LINE); - } - } - /* Implement program-initiated flow control */ - if ( (data & LNCTRL_FORCE_XOFF) && - !(lp->lnctrl & LNCTRL_FORCE_XOFF) ) { - if (!(lp->lnctrl & LNCTRL_IAUTO)) - vh_putc (vh, lp, CSR_GETCHAN (vh_csr[vh]), XOFF); - } else if ( !(data & LNCTRL_FORCE_XOFF) && - (lp->lnctrl & LNCTRL_FORCE_XOFF) ) { - if (!(lp->lnctrl & LNCTRL_IAUTO)) - vh_putc (vh, lp, CSR_GETCHAN (vh_csr[vh]), XON); - else if (!(vh_crit & (1 << vh)) && - (vh_stall[vh] & (1 << CSR_GETCHAN (vh_csr[vh])))) - vh_putc (vh, lp, CSR_GETCHAN (vh_csr[vh]), XON); - } - if ( (data & LNCTRL_IAUTO) && /* IAUTO 0->1 */ - !(lp->lnctrl & LNCTRL_IAUTO) ) { - if (!(lp->lnctrl & LNCTRL_FORCE_XOFF)) { - if (vh_crit & (1 << vh)) { - vh_putc (vh, lp, - CSR_GETCHAN (vh_csr[vh]), XOFF); - vh_stall[vh] |= (1 << CSR_GETCHAN (vh_csr[vh])); - } - } else { - /* vh_stall[vh] |= (1 << CSR_GETCHAN (vh_csr[vh])) */; - } - } else if ( !(data & LNCTRL_IAUTO) && - (lp->lnctrl & LNCTRL_IAUTO) ) { - if (!(lp->lnctrl & LNCTRL_FORCE_XOFF)) - vh_putc (vh, lp, CSR_GETCHAN (vh_csr[vh]), XON); - } - /* check modem control bits */ - if ( !(data & LNCTRL_DTR) && /* DTR 1->0 */ - (lp->lnctrl & LNCTRL_DTR)) { - if ((lp->tmln->conn) && (vh_unit[vh].flags & UNIT_HANGUP)) { - tmxr_linemsg (lp->tmln, "\r\nLine hangup\r\n"); - tmxr_reset_ln (lp->tmln); - } - HangupModem (vh, lp, CSR_GETCHAN (vh_csr[vh])); - } - lp->lnctrl = data; - lp->tmln->rcve = (data & LNCTRL_RX_ENA) ? 1 : 0; - tmxr_poll_rx (&vh_desc); - vh_getc (vh); - if (lp->lnctrl & LNCTRL_BREAK) - vh_putc (vh, lp, CSR_GETCHAN (vh_csr[vh]), 0); - break; - case 5: /* TBUFFAD1 */ - if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) { - vh_mcount[vh] = 1; - break; - } - if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) - break; - line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); - lp = &vh_parm[line]; - if (access == WRITEB) - data = (PA & 1) ? - (lp->tbuf1 & 0377) | (data << 8) : - (lp->tbuf1 & ~0377) | (data & 0377); - lp->tbuf1 = data; - break; - case 6: /* TBUFFAD2 */ - if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) { - vh_mcount[vh] = 1; - break; - } - if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) - break; - line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); - lp = &vh_parm[line]; - if (access == WRITEB) - data = (PA & 1) ? - (lp->tbuf2 & 0377) | (data << 8) : - (lp->tbuf2 & ~0377) | (data & 0377); - lp->tbuf2 = data; - /* if starting a DMA, clear DMA_ERR */ - if (vh_unit[vh].flags & UNIT_FASTDMA) { - doDMA (vh, CSR_GETCHAN (vh_csr[vh])); - tmxr_send_buffered_data (lp->tmln); - } - break; - case 7: /* TBUFFCT */ - if ((data == RESET_ABORT) && (vh_csr[vh] & CSR_MASTER_RESET)) { - vh_mcount[vh] = 1; - break; - } - if (CSR_GETCHAN (vh_csr[vh]) >= VH_LINES) - break; - line = (vh * VH_LINES) + CSR_GETCHAN (vh_csr[vh]); - lp = &vh_parm[line]; - if (access == WRITEB) - data = (PA & 1) ? - (lp->tbuffct & 0377) | (data << 8) : - (lp->tbuffct & ~0377) | (data & 0377); - lp->tbuffct = data; - break; - default: - /* can't happen */ - break; - } - return (SCPE_OK); -} - -static void doDMA ( int32 vh, - int32 chan ) -{ - int32 line, status; - uint32 pa; - TMLX *lp; - - line = (vh * VH_LINES) + chan; - lp = &vh_parm[line]; - if ((lp->tbuf2 & TB2_TX_ENA) && (lp->tbuf2 & TB2_TX_DMA_START)) { -/* BUG: should compare against available xmit buffer space */ - pa = lp->tbuf1; - pa |= (lp->tbuf2 & TB2_M_TBUFFAD) << 16; - status = chan << CSR_V_TX_LINE; - while (lp->tbuffct) { - uint8 buf; - if (Map_ReadB (pa, 1, &buf)) { - status |= CSR_TX_DMA_ERR; - lp->tbuffct = 0; - break; - } - if (vh_putc (vh, lp, chan, buf) != SCPE_OK) - break; - /* pa = (pa + 1) & PAMASK; */ - pa = (pa + 1) & ((1 << 22) - 1); - lp->tbuffct--; - } - lp->tbuf1 = pa & 0177777; - lp->tbuf2 = (lp->tbuf2 & ~TB2_M_TBUFFAD) | - ((pa >> 16) & TB2_M_TBUFFAD); - if (lp->tbuffct == 0) { - lp->tbuf2 &= ~TB2_TX_DMA_START; - q_tx_report (vh, status); - } - } -} - -/* Perform many of the functions of PROC2 */ - -static t_stat vh_svc ( UNIT *uptr ) -{ - int32 vh, newln, i; - - /* scan all muxes for countdown reset */ - for (vh = 0; vh < vh_desc.lines/VH_LINES; vh++) { - if (vh_csr[vh] & CSR_MASTER_RESET) { - if (vh_mcount[vh] != 0) - vh_mcount[vh] -= 1; - else - vh_clear (vh, FALSE); - } - } - /* sample every 10ms for modem changes (new connections) */ - newln = tmxr_poll_conn (&vh_desc); - if (newln >= 0) { - TMLX *lp; - int32 line; - vh = newln / VH_LINES; /* determine which mux */ - line = newln - (vh * VH_LINES); - lp = &vh_parm[newln]; - lp->lstat |= STAT_DSR | STAT_DCD | STAT_CTS; - if (!(lp->lnctrl & LNCTRL_DTR)) - lp->lstat |= STAT_RI; - if (lp->lnctrl & LNCTRL_LINK_TYPE) - fifo_put (vh, lp, RBUF_DIAG | - RBUF_PUTLINE (line) | - ((lp->lstat >> 8) & 0376)); - /* BUG: should check for overflow above */ - } - /* scan all muxes, lines for DMA to complete; start every 3.12ms */ - for (vh = 0; vh < vh_desc.lines/VH_LINES; vh++) { - for (i = 0; i < VH_LINES; i++) - doDMA (vh, i); - } - /* interrupt driven in a real DHQ */ - tmxr_poll_rx (&vh_desc); - for (vh = 0; vh < vh_desc.lines/VH_LINES; vh++) - vh_getc (vh); - tmxr_poll_tx (&vh_desc); - /* scan all DHU-mode muxes for RX FIFO timeout */ - for (vh = 0; vh < vh_desc.lines/VH_LINES; vh++) { - if (vh_unit[vh].flags & UNIT_MODEDHU) { - if (vh_timeo[vh] && (vh_csr[vh] & CSR_RXIE)) { - vh_timeo[vh] -= 1; - if ((vh_timeo[vh] == 0) && rbuf_idx[vh]) - vh_set_rxint (vh); - } - } - } - sim_activate (uptr, tmxr_poll); /* requeue ourselves */ - return (SCPE_OK); -} - -/* init a channel on a controller */ - -/* set for: -send/receive 9600 -8 data bits -1 stop bit -no parity -parity odd -auto-flow off -RX disabled -TX enabled -no break on line -no loopback -link type set to data-leads only -DTR & RTS off -DMA character counter 0 -DMA start address registers 0 -TX_DMA_START 0 -TX_ABORT 0 -auto-flow reports enabled -FIFO size set to 64 -*/ - -static void vh_init_chan ( int32 vh, - int32 chan ) -{ - int32 line; - TMLX *lp; - - line = (vh * VH_LINES) + chan; - lp = &vh_parm[line]; - lp->lpr = (RATE_9600 << LPR_V_TX_SPEED) | - (RATE_9600 << LPR_V_RX_SPEED) | - (03 << LPR_V_CHAR_LGTH); - lp->lnctrl = 0; - lp->lstat &= ~(STAT_MDL | STAT_DHUID | STAT_RI); - if (vh_unit[vh].flags & UNIT_MODEDHU) - lp->lstat |= STAT_DHUID | 64; - if (!(vh_unit[vh].flags & UNIT_MODEM)) - lp->lstat |= STAT_DSR | STAT_DCD | STAT_CTS; - lp->tmln->xmte = 1; - lp->tmln->rcve = 0; - lp->tbuffct = 0; - lp->tbuf1 = 0; - lp->tbuf2 = TB2_TX_ENA; - lp->txchar = 0; -} - -/* init a controller; flag true if BINIT, false if master.reset */ - -static t_stat vh_clear ( int32 vh, - t_bool flag ) -{ - int32 i; - - txq_idx[vh] = 0; - rbuf_idx[vh] = 0; - /* put 8 diag bytes in FIFO: 6 SELF_x, 2 circuit revision codes */ - if (vh_csr[vh] & CSR_SKIP) { - fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(0) | SELF_SKIP); - fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(1) | SELF_SKIP); - fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(2) | SELF_SKIP); - fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(3) | SELF_SKIP); - fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(4) | SELF_SKIP); - fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(5) | SELF_SKIP); - fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(6) | 0107); - fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(7) | 0105); - } else { - fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(0) | SELF_NULL); - fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(1) | SELF_NULL); - fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(2) | SELF_NULL); - fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(3) | SELF_NULL); - fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(4) | SELF_NULL); - fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(5) | SELF_NULL); - /* PROC2 ver. 1 */ - fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(6) | 0107); - /* PROC1 ver. 1 */ - fifo_put (vh, NULL, RBUF_DIAG | RBUF_PUTLINE(7) | 0105); - } - vh_csr[vh] &= ~(CSR_TX_ACTION|CSR_DIAG_FAIL|CSR_MASTER_RESET); - if (flag) - vh_csr[vh] &= ~(CSR_TXIE|CSR_RXIE|CSR_SKIP); - vh_csr[vh] |= CSR_TX_DMA_ERR | (CSR_M_TX_LINE << CSR_V_TX_LINE); - vh_clr_rxint (vh); - vh_clr_txint (vh); - vh_timer[vh] = 1; - vh_timeo[vh] = 0; - vh_ovrrun[vh] = 0; - for (i = 0; i < VH_LINES; i++) - vh_init_chan (vh, i); - vh_crit &= ~(1 << vh); - vh_stall[vh] = 0; - vh_loop[vh] = LOOP_NONE; - return (SCPE_OK); -} - -/* Reset all controllers. Used by BINIT and RESET. */ - -static t_stat vh_reset ( DEVICE *dptr ) -{ - int32 i; - - for (i = 0; i < vh_desc.lines; i++) - vh_parm[i].tmln = &vh_ldsc[i]; - for (i = 0; i < vh_desc.lines/VH_LINES; i++) { -#if defined (VM_PDP11) - /* if Unibus, force DHU mode */ - if (UNIBUS) - vh_unit[i].flags |= UNIT_MODEDHU; -#endif - vh_clear (i, TRUE); - } - vh_rxi = vh_txi = 0; - CLR_INT (VHRX); - CLR_INT (VHTX); - sim_cancel (&vh_unit[0]); - return (auto_config (dptr->name, (dptr->flags & DEV_DIS) ? 0 : vh_desc.lines/VH_LINES)); -} - - -static t_stat vh_attach ( UNIT *uptr, - char *cptr ) -{ - if (uptr == &vh_unit[0]) - return (tmxr_attach (&vh_desc, uptr, cptr)); - return (SCPE_NOATT); -} - -static t_stat vh_detach ( UNIT *uptr ) -{ - return (tmxr_detach (&vh_desc, uptr)); -} - -static void vh_detail_line ( FILE *st, - int32 vh, - int32 chan ) -{ - int32 line; - TMLX *lp; - - line = (vh * VH_LINES) + chan; - lp = &vh_parm[line]; - fprintf (st, "\tline %d\tlpr %06o, lnctrl %06o, lstat %06o\n", - chan, lp->lpr, lp->lnctrl, lp->lstat); - fprintf (st, "\t\ttbuffct %06o, tbuf1 %06o, tbuf2 %06o, txchar %06o\n", - lp->tbuffct, lp->tbuf1, lp->tbuf2, lp->txchar); - fprintf (st, "\t\ttmln rcve %d xmte %d\n", - lp->tmln->rcve, lp->tmln->xmte); -} - -static t_stat vh_show_detail ( FILE *st, - UNIT *uptr, - int32 val, - void *desc ) -{ - int32 i, j; - - fprintf (st, "VH:\trxi %d, txi %d\n", vh_rxi, vh_txi); - for (i = 0; i < vh_desc.lines/VH_LINES; i++) { - fprintf (st, "VH%d:\tmode %s, crit %d\n", i, - vh_unit[i].flags & UNIT_MODEDHU ? "DHU" : "DHV", - vh_crit & (1 << i)); - fprintf (st, "\tCSR %06o, mcount %d, rbuf_idx %d, txq_idx %d\n", - vh_csr[i], vh_mcount[i], rbuf_idx[i], txq_idx[i]); - for (j = 0; j < VH_LINES; j++) - vh_detail_line (st, i, j); - } - return (SCPE_OK); -} - -static t_stat vh_show_rbuf ( FILE *st, - UNIT *uptr, - int32 val, - void *desc ) -{ - int32 i; - - for (i = 0; i < rbuf_idx[0]; i++) - fprintf (st, "%03d: %06o\n", i, vh_rbuf[0][i]); - return (SCPE_OK); -} - -static t_stat vh_show_txq ( FILE *st, - UNIT *uptr, - int32 val, - void *desc ) -{ - int32 i; - - for (i = 0; i < txq_idx[0]; i++) - fprintf (st, "%02d: %06o\n\r", i, vh_txq[0][i]); - return (SCPE_OK); -} - -/* SET LINES processor */ - -static t_stat vh_setnl (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 newln, i, t, ndev; -t_stat r; - -if (cptr == NULL) - return SCPE_ARG; -newln = (int32) get_uint (cptr, 10, (VH_MUXES * VH_LINES), &r); -if ((r != SCPE_OK) || (newln == vh_desc.lines)) - return r; -if ((newln == 0) || (newln % VH_LINES)) - return SCPE_ARG; -if (newln < vh_desc.lines) { - for (i = newln, t = 0; i < vh_desc.lines; i++) - t = t | vh_ldsc[i].conn; - if (t && !get_yn ("This will disconnect users; proceed [N]?", FALSE)) - return SCPE_OK; - for (i = newln; i < vh_desc.lines; i++) { - if (vh_ldsc[i].conn) { - tmxr_linemsg (&vh_ldsc[i], "\r\nOperator disconnected line\r\n"); - tmxr_reset_ln (&vh_ldsc[i]); /* reset line */ - } - if ((i % VH_LINES) == (VH_LINES - 1)) - vh_clear (i / VH_LINES, TRUE); /* reset mux */ - } - } -vh_dib.lnt = (newln / VH_LINES) * IOLN_VH; /* set length */ -vh_desc.lines = newln; -ndev = ((vh_dev.flags & DEV_DIS)? 0: (vh_desc.lines / VH_LINES)); -vh_dev.numunits = (newln / VH_LINES); -return auto_config (vh_dev.name, ndev); /* auto config */ -} - -/* SET LOG processor */ - -static t_stat vh_set_log (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -char *tptr; -t_stat r; -int32 ln; - -if (cptr == NULL) - return SCPE_ARG; -tptr = strchr (cptr, '='); -if ((tptr == NULL) || (*tptr == 0)) - return SCPE_ARG; -*tptr++ = 0; -ln = (int32) get_uint (cptr, 10, (VH_MUXES * VH_LINES), &r); -if ((r != SCPE_OK) || (ln >= vh_desc.lines)) - return SCPE_ARG; -return tmxr_set_log (NULL, ln, tptr, desc); -} - -/* SET NOLOG processor */ - -static t_stat vh_set_nolog (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -t_stat r; -int32 ln; - -if (cptr == NULL) - return SCPE_ARG; -ln = (int32) get_uint (cptr, 10, (VH_MUXES * VH_LINES), &r); -if ((r != SCPE_OK) || (ln >= vh_desc.lines)) - return SCPE_ARG; -return tmxr_set_nolog (NULL, ln, NULL, desc); -} - -/* SHOW LOG processor */ - -static t_stat vh_show_log (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -int32 i; - -for (i = 0; i < vh_desc.lines; i++) { - fprintf (st, "line %d: ", i); - tmxr_show_log (st, NULL, i, desc); - fprintf (st, "\n"); - } -return SCPE_OK; -} diff --git a/PDP11/pdp11_xq.c b/PDP11/pdp11_xq.c deleted file mode 100644 index 1c5198bf..00000000 --- a/PDP11/pdp11_xq.c +++ /dev/null @@ -1,2853 +0,0 @@ -/* pdp11_xq.c: DEQNA/DELQA ethernet controller simulator - ------------------------------------------------------------------------------ - - Copyright (c) 2002-2007, David T. Hittner - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of the author shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the author. - - ------------------------------------------------------------------------------ - - This DEQNA/DELQA/DELQA-T simulation is based on: - Digital DELQA Users Guide, Part# EK-DELQA-UG-002 - Digital DEQNA Users Guide, Part# EK-DEQNA-UG-001 - Digital DELQA-Plus Addendum to DELQA Users Guide, Part# EK-DELQP-UG-001_Sep89.pdf - These manuals can be found online at: - http://www.bitsavers.org/pdf/dec/qbus - - Certain adaptations have been made because this is an emulation: - Ethernet transceiver power flag CSR<12> is ON when attached. - External Loopback does not go out to the physical adapter, it is - implemented more like an extended Internal Loopback - Time Domain Reflectometry (TDR) numbers are faked - The 10-second approx. hardware/software reset delay does not exist - Some physical ethernet receive events like Runts, Overruns, etc. are - never reported back, since the packet-level driver never sees them - - Certain advantages are derived from this emulation: - If the real ethernet controller is faster than 10Mbit/sec, the speed is - seen by the simulated cpu since there are no minimum response times. - - Known Bugs or Unsupported features, in priority order: - 1) PDP11 bootstrap - 2) MOP functionality not implemented - 3) Local packet processing not implemented - - Regression Tests: - VAX: 1. Console SHOW DEVICE - 2. VMS v7.2 boots/initializes/shows device - 3. VMS DECNET - SET HOST and COPY tests - 4. VMS MultiNet - SET HOST/TELNET and FTP tests - 5. VMS LAT - SET HOST/LAT tests - 6. VMS Cluster - SHOW CLUSTER, SHOW DEVICE, and cluster COPY tests - 7. Console boot into VMSCluster (>>>B XQAO) - 8. Console DELQA Diagnostic (>>>TEST 82) - - PDP11: 1. RT-11 v5.3 - FTPSB copy test - 2. RSTS/E v10.1 - detects/enables device - - ------------------------------------------------------------------------------ - - Modification history: - - 20-Apr-11 MP Fixed missing information from save/restore which - caused operations to not complete correctly after - a restore until the OS reset the controller. - 09-Dec-10 MP Added address conflict check during attach. - 06-Dec-10 MP Fixed loopback processing to correctly handle forward packets. - 29-Nov-10 MP Fixed interrupt dispatch issue which caused delivered packets - (in and out) to sometimes not interrupt the CPU after processing. - 07-Mar-08 MP Fixed the SCP visibile SA registers to always display the - ROM mac address, even after it is changed by SET XQ MAC=. - 07-Mar-08 MP Added changes so that the Console DELQA diagnostic (>>>TEST 82) - will succeed. - 03-Mar-08 MP Added DELQA-T (aka DELQA Plus) device emulation support. - 06-Feb-08 MP Added dropped frame statistics to record when the receiver discards - received packets due to the receiver being disabled, or due to the - XQ device's packet receive queue being full. - Fixed bug in receive processing when we're not polling. This could - cause receive processing to never be activated again if we don't - read all available packets via eth_read each time we get the - opportunity. - 31-Jan-08 MP Added the ability to Coalesce received packet interrupts. This - is enabled by SET XQ POLL=DELAY=nnn where nnn is a number of - microseconds to delay the triggering of an interrupt when a packet - is received. - 29-Jan-08 MP Added SET XQ POLL=DISABLE (aka SET XQ POLL=0) to operate without - polling for packet read completion. - 29-Jan-08 MP Changed the sanity and id timer mechanisms to use a separate timer - unit so that transmit and recieve activities can be dealt with - by the normal xq_svc routine. - Dynamically determine the timer polling rate based on the - calibrated tmr_poll and clk_tps values of the simulator. - 25-Jan-08 MP Enabled the SET XQ POLL to be meaningful if the simulator currently - doesn't support idling. - 25-Jan-08 MP Changed xq_debug_setup to use sim_debug instead of printf so that - all debug output goes to the same place. - 25-Jan-08 MP Restored the call to xq_svc after all successful calls to eth_write - to allow receive processing to happen before the next event - service time. This must have been inadvertently commented out - while other things were being tested. - 23-Jan-08 MP Added debugging support to display packet headers and packet data - 18-Jun-07 RMS Added UNIT_IDLE flag - 29-Oct-06 RMS Synced poll and clock - 27-Jan-06 RMS Fixed unaligned accesses in XQB (found by Doug Carman) - 07-Jan-06 RMS Fixed unaligned access bugs (found by Doug Carman) - 07-Sep-05 DTH Removed unused variable - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 01-Dec-04 DTH Added runtime attach prompt - 27-Feb-04 DTH Removed struct timeb deuggers - 31-Jan-04 DTH Replaced #ifdef debuggers with inline debugging - 19-Jan-04 DTH Combined service timers into one for efficiency - 16-Jan-04 DTH Added more info to SHOW MOD commands, added SET/SHOW XQ DEBUG - 13-Jan-04 DTH Corrected interrupt code with help from Tom Evans - 06-Jan-04 DTH Added protection against changing mac and type if attached - 05-Jan-04 DTH Moved most of xq_setmac to sim_ether - 26-Dec-03 DTH Moved ethernet show and queue functions to sim_ether - 03-Dec-03 DTH Added minimum name length to show xq eth - 25-Nov-03 DTH Reworked interrupts to fix broken XQB implementation - 19-Nov-03 MP Rearranged timer reset sequencing to allow for a device to be - disabled after it had been enabled. - 17-Nov-03 DTH Standardized #include of timeb.h - 28-Sep-03 MP - Fixed bug in xq_process_setup which would leave the - device in promiscuous or all multicast mode once it - ever had been there. - - Fixed output format in show_xq_sanity to end in "\n" - - Added display of All Multicast and promiscuous to - xq_show_filters - - The stuck in All Multicast or Promiscuous issue is - worse than previously thought. See comments in - xq_process_setup. - - Change xq_setmac to also allow ":" as a address - separator character, since sim_ether's eth_mac_fmt - formats them with this separator character. - - Changed xq_sw_reset to behave more like the set of - actions described in Table 3-6 of the DELQA manual. - The manual mentions "N/A" which I'm interpreting to - mean "Not Affected". - 05-Jun-03 DTH Added receive packet splitting - 03-Jun-03 DTH Added SHOW XQ FILTERS - 02-Jun-03 DTH Added SET/SHOW XQ STATS (packet statistics), runt & giant processing - 28-May-03 DTH Modified message queue for dynamic size to shrink executable - 28-May-03 MP Fixed bug in xq_setmac - 06-May-03 DTH Changed 32-bit t_addr to uint32 for v3.0 - Removed SET ADDRESS functionality - 05-May-03 DTH Added second controller - 26-Mar-03 DTH Added PDP11 bootrom loader - Adjusted xq_ex and xq_dev to allow pdp11 to look at bootrom - Patched bootrom to allow "pass" of diagnostics on RSTS/E - 06-Mar-03 DTH Corrected interrupts on IE state transition (code by Tom Evans) - Added interrupt clear on soft reset (first noted by Bob Supnik) - Removed interrupt when setting XL or RL (multiple people) - 16-Jan-03 DTH Merged Mark Pizzolato's enhancements with main source - Corrected PDP11 XQ_DEBUG compilation - 15-Jan-03 MP Fixed the number of units in the xq device structure. - 13-Jan-03 MP Reworked the timer management logic which initiated - the system id broadcast messages. The original - implementation triggered this on the CSR transition - of Receiver Enabled. This was an issue since the - it seems that at least VMS's XQ driver makes this - transition often and the resulting overhead reduces - the simulated CPU instruction execution throughput by - about 40%. I start the system id timer on device - reset and it fires once a second so that it can - leverage the reasonably recalibrated tmr_poll value. - 13-Jan-03 MP Changed the scheduling of xq_svc to leverage the - dynamically computed clock values to achieve an - approximate interval of 100 per second. This is - more than sufficient for normal system behaviour - expecially since we service receives with every - transmit. The previous fixed value of 2500 - attempted to get 200/sec but it was a guess that - didn't adapt. On faster host systems (possibly - most of them) the 2500 number spends too much time - polling. - 10-Jan-03 DTH Removed XQ_DEBUG dependency from Borland #pragmas - Added SET XQ BOOTROM command for PDP11s - 07-Jan-03 DTH Added pointer to online manuals - 02-Jan-03 DTH Added local packet processing - 30-Dec-02 DTH Added automatic system id broadcast - 27-Dec-02 DTH Merged Mark Pizzolato's enhancements with main source - 20-Dec-02 MP Fix bug that caused VMS system crashes when attempting cluster - operations. Added additional conditionally compiled debug - info needed to track down the issue. - 17-Dec-02 MP Added SIMH "registers" describing the Ethernet state - so this information can be recorded in a "saved" snapshot. - 05-Dec-02 MP Adjusted the rtime value from 100 to 2500 which increased the - available CPU cycles for Instruction execution by almost 100%. - This made sense after the below enhancements which, in general - caused the draining of the received data stream much more - agressively with less overhead. - 05-Dec-02 MP Added a call to xq_svc after all successful calls to eth_write - to allow receive processing to happen before the next event - service time. - 05-Dec-02 MP Restructured the flow of processing in xq_svc so that eth_read - is called repeatedly until either a packet isn't found or - there is no room for another one in the queue. Once that has - been done, xq_process_rdbl is called to pass the queued packets - into the simulated system as space is available there. - xq_process_rdbl is also called at the beginning of xq_svc to - drain the queue into the simulated system, making more room - available in the queue. No processing is done at all in - xq_svc if the receiver is disabled. - 04-Dec-02 MP Changed interface and usage to xq_insert_queue to pass - the packet to be inserted by reference. This avoids 3K bytes - of buffer copy operations for each packet received. Now only - copy actual received packet data. - 31-Oct-02 DTH Cleaned up pointer warnings (found by Federico Schwindt) - Corrected unattached and no network behavior - Added message when SHOW XQ ETH finds no devices - 23-Oct-02 DTH Beta 5 released - 22-Oct-02 DTH Added all_multicast and promiscuous support - 21-Oct-02 DTH Added write buffer max size check (code by Jason Thorpe) - Corrected copyright again - Implemented NXM testing and recovery - 16-Oct-02 DTH Beta 4 released - Added and debugged Sanity Timer code - Corrected copyright - 15-Oct-02 DTH Rollback to known good Beta3 and roll forward; TCP broken - 12-Oct-02 DTH Fixed VAX network bootstrap; setup packets must return TDR > 0 - 11-Oct-02 DTH Added SET/SHOW XQ TYPE and SET/SHOW XQ SANITY commands - 10-Oct-02 DTH Beta 3 released; Integrated with 2.10-0b1 - Fixed off-by-1 bug on xq->setup.macs[7..13] - Added xq_make_checksum - Added rejection of multicast addresses in SET XQ MAC - 08-Oct-02 DTH Beta 2 released; Integrated with 2.10-0p4 - Added variable vector (fixes PDP11) and copyrights - 03-Oct-02 DTH Beta version of xq/sim_ether released for SIMH 2.09-11 - 24-Sep-02 DTH Moved more code to Sim_Ether module, added SHOW ETH command - 23-Sep-02 DTH Added SET/SHOW MAC command - 22-Sep-02 DTH Multinet TCP/IP loaded, tests OK via SET HOST/TELNET - 20-Sep-02 DTH Cleaned up code fragments, fixed non-DECNET MAC use - 19-Sep-02 DTH DECNET finally stays up; successful SET HOST to another node - 15-Sep-02 DTH Added ethernet packet read/write - 13-Sep-02 DTH DECNET starts, but circuit keeps going up & down - 26-Aug-02 DTH DECNET loaded, returns device timeout - 22-Aug-02 DTH VMS 7.2 recognizes device as XQA0 - 18-Aug-02 DTH VAX sees device as XQA0; shows hardcoded MAC correctly - 15-Aug-02 DTH Started XQ simulation - - ------------------------------------------------------------------------------ -*/ - -#include -#include "pdp11_xq.h" -#include "pdp11_xq_bootrom.h" - -extern int32 tmxr_poll; -extern int32 tmr_poll, clk_tps; -extern t_bool sim_idle_enab; -extern FILE* sim_deb; -extern FILE *sim_log; -extern char* read_line (char *ptr, int32 size, FILE *stream); - -/* forward declarations */ -t_stat xq_rd(int32* data, int32 PA, int32 access); -t_stat xq_wr(int32 data, int32 PA, int32 access); -t_stat xq_svc(UNIT * uptr); -t_stat xq_tmrsvc(UNIT * uptr); -t_stat xq_reset (DEVICE * dptr); -t_stat xq_attach (UNIT * uptr, char * cptr); -t_stat xq_detach (UNIT * uptr); -t_stat xq_showmac (FILE* st, UNIT* uptr, int32 val, void* desc); -t_stat xq_setmac (UNIT* uptr, int32 val, char* cptr, void* desc); -t_stat xq_show_filters (FILE* st, UNIT* uptr, int32 val, void* desc); -t_stat xq_show_stats (FILE* st, UNIT* uptr, int32 val, void* desc); -t_stat xq_set_stats (UNIT* uptr, int32 val, char* cptr, void* desc); -t_stat xq_show_type (FILE* st, UNIT* uptr, int32 val, void* desc); -t_stat xq_set_type (UNIT* uptr, int32 val, char* cptr, void* desc); -t_stat xq_show_sanity (FILE* st, UNIT* uptr, int32 val, void* desc); -t_stat xq_set_sanity (UNIT* uptr, int32 val, char* cptr, void* desc); -t_stat xq_show_poll (FILE* st, UNIT* uptr, int32 val, void* desc); -t_stat xq_set_poll (UNIT* uptr, int32 val, char* cptr, void* desc); -t_stat xq_process_xbdl(CTLR* xq); -t_stat xq_dispatch_xbdl(CTLR* xq); -t_stat xq_process_turbo_rbdl(CTLR* xq); -t_stat xq_process_turbo_xbdl(CTLR* xq); -void xq_start_receiver(CTLR* xq); -void xq_stop_receiver(CTLR* xq); -void xq_sw_reset(CTLR* xq); -t_stat xq_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); -t_stat xq_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); -void xq_reset_santmr(CTLR* xq); -t_stat xq_boot_host(CTLR* xq); -t_stat xq_system_id(CTLR* xq, const ETH_MAC dst, uint16 receipt_id); -void xqa_read_callback(int status); -void xqb_read_callback(int status); -void xqa_write_callback(int status); -void xqb_write_callback(int status); -void xq_setint (CTLR* xq); -void xq_clrint (CTLR* xq); -int32 xq_int (void); -void xq_csr_set_clr(CTLR* xq, uint16 set_bits, uint16 clear_bits); - -struct xq_device xqa = { - xqa_read_callback, /* read callback routine */ - xqa_write_callback, /* write callback routine */ - {0x08, 0x00, 0x2B, 0xAA, 0xBB, 0xCC}, /* mac */ - XQ_T_DELQA_PLUS, /* type */ - XQ_T_DELQA, /* mode */ - XQ_SERVICE_INTERVAL, /* poll */ - 0, 0, /* coalesce */ - {0} /* sanity */ - }; - -struct xq_device xqb = { - xqb_read_callback, /* read callback routine */ - xqb_write_callback, /* write callback routine */ - {0x08, 0x00, 0x2B, 0xBB, 0xCC, 0xDD}, /* mac */ - XQ_T_DELQA_PLUS, /* type */ - XQ_T_DELQA, /* mode */ - XQ_SERVICE_INTERVAL, /* poll */ - 0, 0, /* coalesce */ - {0} /* sanity */ - }; - -/* SIMH device structures */ -DIB xqa_dib = { IOBA_XQ, IOLN_XQ, &xq_rd, &xq_wr, - 1, IVCL (XQ), 0, { &xq_int } }; - -UNIT xqa_unit[] = { - { UDATA (&xq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 2047) }, /* receive timer */ - { UDATA (&xq_tmrsvc, UNIT_IDLE|UNIT_DIS, 0) }, -}; - -REG xqa_reg[] = { - { GRDATA ( SA0, xqa.mac[0], XQ_RDX, 8, 0), REG_RO|REG_FIT}, - { GRDATA ( SA1, xqa.mac[1], XQ_RDX, 8, 0), REG_RO|REG_FIT}, - { GRDATA ( SA2, xqa.mac[2], XQ_RDX, 8, 0), REG_RO|REG_FIT}, - { GRDATA ( SA3, xqa.mac[3], XQ_RDX, 8, 0), REG_RO|REG_FIT}, - { GRDATA ( SA4, xqa.mac[4], XQ_RDX, 8, 0), REG_RO|REG_FIT}, - { GRDATA ( SA5, xqa.mac[5], XQ_RDX, 8, 0), REG_RO|REG_FIT}, - { GRDATA ( MX0, xqa.mac_checksum[0], XQ_RDX, 8, 0), REG_RO|REG_FIT}, - { GRDATA ( MX1, xqa.mac_checksum[1], XQ_RDX, 8, 0), REG_RO|REG_FIT}, - { GRDATA ( RBDL, xqa.rbdl[0], XQ_RDX, 16, 0), REG_FIT }, - { GRDATA ( RBDH, xqa.rbdl[1], XQ_RDX, 16, 0), REG_FIT }, - { GRDATA ( XBDL, xqa.xbdl[0], XQ_RDX, 16, 0), REG_FIT }, - { GRDATA ( XBDH, xqa.xbdl[1], XQ_RDX, 16, 0), REG_FIT }, - { GRDATA ( VAR, xqa.var, XQ_RDX, 16, 0), REG_FIT }, - { GRDATA ( CSR, xqa.csr, XQ_RDX, 16, 0), REG_FIT }, - { FLDATA ( INT, xqa.irq, 0) }, - { GRDATA ( TYPE, xqa.type, XQ_RDX, 32, 0), REG_FIT }, - { GRDATA ( MODE, xqa.mode, XQ_RDX, 32, 0), REG_FIT }, - { GRDATA ( POLL, xqa.poll, XQ_RDX, 16, 0), REG_HRO}, - { GRDATA ( CLAT, xqa.coalesce_latency, XQ_RDX, 16, 0), REG_HRO}, - { GRDATA ( CLATT, xqa.coalesce_latency_ticks, XQ_RDX, 16, 0), REG_HRO}, - { GRDATA ( RBDL_BA, xqa.rbdl_ba, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( XBDL_BA, xqa.xbdl_ba, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( SETUP_PRM, xqa.setup.promiscuous, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( SETUP_MLT, xqa.setup.multicast, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( SETUP_L1, xqa.setup.l1, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( SETUP_L2, xqa.setup.l2, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( SETUP_L3, xqa.setup.l3, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( SETUP_SAN, xqa.setup.sanity_timer, XQ_RDX, 32, 0), REG_HRO}, - { BRDATA ( SETUP_MACS, &xqa.setup.macs, XQ_RDX, 8, sizeof(xqa.setup.macs)), REG_HRO}, - { BRDATA ( STATS, &xqa.stats, XQ_RDX, 8, sizeof(xqa.setup.macs)), REG_HRO}, - { BRDATA ( TURBO_INIT, &xqa.init, XQ_RDX, 8, sizeof(xqa.init)), REG_HRO}, - { GRDATA ( SRR, xqa.srr, XQ_RDX, 16, 0), REG_FIT }, - { GRDATA ( SRQR, xqa.srqr, XQ_RDX, 16, 0), REG_FIT }, - { GRDATA ( IBA, xqa.iba, XQ_RDX, 32, 0), REG_FIT }, - { GRDATA ( ICR, xqa.icr, XQ_RDX, 16, 0), REG_FIT }, - { GRDATA ( IPEND, xqa.pending_interrupt, XQ_RDX, 16, 0), REG_FIT }, - { GRDATA ( TBINDX, xqa.tbindx, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( RBINDX, xqa.rbindx, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( IDTMR, xqa.idtmr, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( VECTOR, xqa_dib.vec, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( MUST_POLL, xqa.must_poll, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( SANT_ENAB, xqa.sanity.enabled, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( SANT_QSECS, xqa.sanity.quarter_secs, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( SANT_TIMR, xqa.sanity.timer, XQ_RDX, 32, 0), REG_HRO}, - { NULL }, -}; - -DIB xqb_dib = { IOBA_XQB, IOLN_XQB, &xq_rd, &xq_wr, - 1, IVCL (XQ), 0, { &xq_int } }; - -UNIT xqb_unit[] = { - { UDATA (&xq_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 2047) }, /* receive timer */ - { UDATA (&xq_tmrsvc, UNIT_IDLE|UNIT_DIS, 0) }, -}; - -REG xqb_reg[] = { - { GRDATA ( SA0, xqb.mac[0], XQ_RDX, 8, 0), REG_RO|REG_FIT}, - { GRDATA ( SA1, xqb.mac[1], XQ_RDX, 8, 0), REG_RO|REG_FIT}, - { GRDATA ( SA2, xqb.mac[2], XQ_RDX, 8, 0), REG_RO|REG_FIT}, - { GRDATA ( SA3, xqb.mac[3], XQ_RDX, 8, 0), REG_RO|REG_FIT}, - { GRDATA ( SA4, xqb.mac[4], XQ_RDX, 8, 0), REG_RO|REG_FIT}, - { GRDATA ( SA5, xqb.mac[5], XQ_RDX, 8, 0), REG_RO|REG_FIT}, - { GRDATA ( MX0, xqb.mac_checksum[0], XQ_RDX, 8, 0), REG_RO|REG_FIT}, - { GRDATA ( MX1, xqb.mac_checksum[1], XQ_RDX, 8, 0), REG_RO|REG_FIT}, - { GRDATA ( RBDL, xqb.rbdl[0], XQ_RDX, 16, 0), REG_FIT }, - { GRDATA ( RBDH, xqb.rbdl[1], XQ_RDX, 16, 0), REG_FIT }, - { GRDATA ( XBDL, xqb.xbdl[0], XQ_RDX, 16, 0), REG_FIT }, - { GRDATA ( XBDH, xqb.xbdl[1], XQ_RDX, 16, 0), REG_FIT }, - { GRDATA ( VAR, xqb.var, XQ_RDX, 16, 0), REG_FIT }, - { GRDATA ( CSR, xqb.csr, XQ_RDX, 16, 0), REG_FIT }, - { FLDATA ( INT, xqb.irq, 0) }, - { GRDATA ( TYPE, xqb.type, XQ_RDX, 32, 0), REG_FIT }, - { GRDATA ( MODE, xqb.mode, XQ_RDX, 32, 0), REG_FIT }, - { GRDATA ( POLL, xqb.poll, XQ_RDX, 16, 0), REG_HRO}, - { GRDATA ( CLAT, xqb.coalesce_latency, XQ_RDX, 16, 0), REG_HRO}, - { GRDATA ( CLATT, xqb.coalesce_latency_ticks, XQ_RDX, 16, 0), REG_HRO}, - { GRDATA ( RBDL_BA, xqb.rbdl_ba, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( XBDL_BA, xqb.xbdl_ba, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( SETUP_PRM, xqb.setup.promiscuous, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( SETUP_MLT, xqb.setup.multicast, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( SETUP_L1, xqb.setup.l1, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( SETUP_L2, xqb.setup.l2, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( SETUP_L3, xqb.setup.l3, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( SETUP_SAN, xqb.setup.sanity_timer, XQ_RDX, 32, 0), REG_HRO}, - { BRDATA ( SETUP_MACS, &xqb.setup.macs, XQ_RDX, 8, sizeof(xqb.setup.macs)), REG_HRO}, - { BRDATA ( STATS, &xqb.stats, XQ_RDX, 8, sizeof(xqa.setup.macs)), REG_HRO}, - { BRDATA ( TURBO_INIT, &xqb.init, XQ_RDX, 8, sizeof(xqb.init)), REG_HRO}, - { GRDATA ( SRR, xqb.srr, XQ_RDX, 16, 0), REG_FIT }, - { GRDATA ( SRQR, xqb.srqr, XQ_RDX, 16, 0), REG_FIT }, - { GRDATA ( IBA, xqb.iba, XQ_RDX, 32, 0), REG_FIT }, - { GRDATA ( ICR, xqb.icr, XQ_RDX, 16, 0), REG_FIT }, - { GRDATA ( IPEND, xqb.pending_interrupt, XQ_RDX, 16, 0), REG_FIT }, - { GRDATA ( TBINDX, xqb.tbindx, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( RBINDX, xqb.rbindx, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( IDTMR, xqb.idtmr, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( VECTOR, xqb_dib.vec, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( MUST_POLL, xqb.must_poll, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( SANT_ENAB, xqb.sanity.enabled, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( SANT_QSECS, xqb.sanity.quarter_secs, XQ_RDX, 32, 0), REG_HRO}, - { GRDATA ( SANT_TIMR, xqb.sanity.timer, XQ_RDX, 32, 0), REG_HRO}, - { NULL }, -}; - -MTAB xq_mod[] = { - { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL, - NULL, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, - NULL, &show_vec, NULL }, - { MTAB_XTD | MTAB_VDV, 0, "MAC", "MAC=xx:xx:xx:xx:xx:xx", - &xq_setmac, &xq_showmac, NULL }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "ETH", "ETH", - NULL, ð_show, NULL }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "FILTERS", "FILTERS", - NULL, &xq_show_filters, NULL }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATS", "STATS", - &xq_set_stats, &xq_show_stats, NULL }, - { MTAB_XTD | MTAB_VDV, 0, "TYPE", "TYPE={DEQNA|DELQA|DELQA-T}", - &xq_set_type, &xq_show_type, NULL }, -#ifdef USE_READER_THREAD - { MTAB_XTD | MTAB_VDV, 0, "POLL", "POLL={DEFAULT|DISABLED|4..2500|DELAY=nnn}", - &xq_set_poll, &xq_show_poll, NULL }, -#else - { MTAB_XTD | MTAB_VDV, 0, "POLL", "POLL={DEFAULT|DISABLED|4..2500}", - &xq_set_poll, &xq_show_poll, NULL }, -#endif - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "SANITY", "SANITY={ON|OFF}", - &xq_set_sanity, &xq_show_sanity, NULL }, - { 0 }, -}; - -DEBTAB xq_debug[] = { - {"TRACE", DBG_TRC}, - {"CSR", DBG_CSR}, - {"VAR", DBG_VAR}, - {"WARN", DBG_WRN}, - {"SETUP", DBG_SET}, - {"SANITY", DBG_SAN}, - {"REG", DBG_REG}, - {"PACKET", DBG_PCK}, - {"DATA", DBG_DAT}, - {"ETH", DBG_ETH}, - {0} -}; - -DEVICE xq_dev = { - "XQ", xqa_unit, xqa_reg, xq_mod, - 2, XQ_RDX, 11, 1, XQ_RDX, 16, - &xq_ex, &xq_dep, &xq_reset, - NULL, &xq_attach, &xq_detach, - &xqa_dib, DEV_FLTA | DEV_DISABLE | DEV_QBUS | DEV_DEBUG, - 0, xq_debug -}; - -DEVICE xqb_dev = { - "XQB", xqb_unit, xqb_reg, xq_mod, - 2, XQ_RDX, 11, 1, XQ_RDX, 16, - &xq_ex, &xq_dep, &xq_reset, - NULL, &xq_attach, &xq_detach, - &xqb_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_QBUS | DEV_DEBUG, - 0, xq_debug -}; - -CTLR xq_ctrl[] = { - {&xq_dev, xqa_unit, &xqa_dib, &xqa}, /* XQA controller */ - {&xqb_dev, xqb_unit, &xqb_dib, &xqb} /* XQB controller */ -}; - -const char* const xq_recv_regnames[] = { - "MAC0", "MAC1", "MAC2", "MAC3", "MAC4", "MAC5", "VAR", "CSR" -}; - -const char* const xqt_recv_regnames[] = { - "MAC0", "MAC1", "MAC2", "MAC3", "MAC4", "MAC5", "SRR", "" -}; - -const char* const xq_xmit_regnames[] = { - "XCR0", "XCR1", "RBDL-Lo", "RBDL-Hi", "XBDL-Lo", "XBDL-Hi", "VAR", "CSR" -}; - -const char* const xqt_xmit_regnames[] = { - "IBAL", "IBAH", "ICR", "", "SRQR", "", "", "ARQR" -}; - -const char* const xq_csr_bits[] = { - "RE", "SR", "NI", "BD", "XL", "RL", "IE", "XI", - "IL", "EL", "SE", "RR", "OK", "CA", "PE", "RI" -}; - -const char* const xq_var_bits[] = { - "ID", "RR", "V0", "V1", "V2", "V3", "V4", "V5", - "V6", "V7", "S1", "S2", "S3", "RS", "OS", "MS" -}; - -const char* const xq_srr_bits[] = { - "RS0", "RS1", "", "", "", "", "", "", - "", "TBL", "IME", "PAR", "NXM", "", "CHN", "FES" -}; - -/* internal debugging routines */ -void xq_debug_setup(CTLR* xq); -void xq_debug_turbo_setup(CTLR* xq); - -/*============================================================================*/ - -/* Multicontroller support */ - -CTLR* xq_unit2ctlr(UNIT* uptr) -{ - unsigned int i,j; - for (i=0; inumunits; j++) - if (&xq_ctrl[i].unit[j] == uptr) - return &xq_ctrl[i]; - /* not found */ - return 0; -} - -CTLR* xq_dev2ctlr(DEVICE* dptr) -{ - int i; - for (i=0; i= xq_ctrl[i].dib->ba) && (PA < (xq_ctrl[i].dib->ba + xq_ctrl[i].dib->lnt))) - return &xq_ctrl[i]; - /* not found */ - return 0; -} - -/*============================================================================*/ - -/* stop simh from reading non-existant unit data stream */ -t_stat xq_ex (t_value* vptr, t_addr addr, UNIT* uptr, int32 sw) -{ - /* on PDP-11, allow EX command to look at bootrom */ -#ifdef VM_PDP11 - if (addr <= sizeof(xq_bootrom)/2) - *vptr = xq_bootrom[addr]; - else - *vptr = 0; - return SCPE_OK; -#else - return SCPE_NOFNC; -#endif -} - -/* stop simh from writing non-existant unit data stream */ -t_stat xq_dep (t_value val, t_addr addr, UNIT* uptr, int32 sw) -{ - return SCPE_NOFNC; -} - -t_stat xq_showmac (FILE* st, UNIT* uptr, int32 val, void* desc) -{ - CTLR* xq = xq_unit2ctlr(uptr); - char buffer[20]; - - eth_mac_fmt((ETH_MAC*)xq->var->mac, buffer); - fprintf(st, "MAC=%s", buffer); - return SCPE_OK; -} - -void xq_make_checksum(CTLR* xq) -{ - /* checksum calculation routine detailed in vaxboot.zip/xqbtdrivr.mar */ - uint32 checksum = 0; - const uint32 wmask = 0xFFFF; - int i; - - for (i = 0; i < sizeof(ETH_MAC); i += 2) { - checksum <<= 1; - if (checksum > wmask) - checksum -= wmask; - checksum += (xq->var->mac[i] << 8) | xq->var->mac[i+1]; - if (checksum > wmask) - checksum -= wmask; - } - if (checksum == wmask) - checksum = 0; - - /* set checksum bytes */ - xq->var->mac_checksum[0] = checksum & 0xFF; - xq->var->mac_checksum[1] = checksum >> 8; -} - -t_stat xq_setmac (UNIT* uptr, int32 val, char* cptr, void* desc) -{ - t_stat status; - CTLR* xq = xq_unit2ctlr(uptr); - - if (!cptr) return SCPE_IERR; - if (uptr->flags & UNIT_ATT) return SCPE_ALATT; - status = eth_mac_scan(&xq->var->mac, cptr); - if (status != SCPE_OK) - return status; - - /* calculate mac checksum */ - xq_make_checksum(xq); - return SCPE_OK; -} - -t_stat xq_set_stats (UNIT* uptr, int32 val, char* cptr, void* desc) -{ - /* this sets all ints in the stats structure to the integer passed */ - CTLR* xq = xq_unit2ctlr(uptr); - - if (cptr) { - /* set individual stats to passed parameter value */ - int init = atoi(cptr); - int* stat_array = (int*) &xq->var->stats; - int elements = sizeof(struct xq_stats)/sizeof(int); - int i; - for (i=0; ivar->stats, 0, sizeof(struct xq_stats)); - } - return SCPE_OK; -} - -t_stat xq_show_stats (FILE* st, UNIT* uptr, int32 val, void* desc) -{ - char* fmt = " %-15s%d\n"; - CTLR* xq = xq_unit2ctlr(uptr); - - fprintf(st, "XQ Ethernet statistics:\n"); - fprintf(st, fmt, "Recv:", xq->var->stats.recv); - fprintf(st, fmt, "Dropped:", xq->var->stats.dropped + xq->var->ReadQ.loss); - fprintf(st, fmt, "Xmit:", xq->var->stats.xmit); - fprintf(st, fmt, "Xmit Fail:", xq->var->stats.fail); - fprintf(st, fmt, "Runts:", xq->var->stats.runt); - fprintf(st, fmt, "Oversize:", xq->var->stats.giant); - fprintf(st, fmt, "SW Reset:", xq->var->stats.reset); - fprintf(st, fmt, "Setup:", xq->var->stats.setup); - fprintf(st, fmt, "Loopback:", xq->var->stats.loop); - fprintf(st, fmt, "ReadQ count:", xq->var->ReadQ.count); - fprintf(st, fmt, "ReadQ high:", xq->var->ReadQ.high); - eth_show_dev(st, xq->var->etherface); - return SCPE_OK; -} - -t_stat xq_show_filters (FILE* st, UNIT* uptr, int32 val, void* desc) -{ - CTLR* xq = xq_unit2ctlr(uptr); - char buffer[20]; - int i; - - if (xq->var->mode == XQ_T_DELQA_PLUS) { - eth_mac_fmt(&xq->var->init.phys, buffer); - fprintf(st, "Physical Address=%s\n", buffer); - if (xq->var->etherface->hash_filter) { - fprintf(st, "Multicast Hash: "); - for (i=0; ivar->etherface->hash); ++i) - fprintf(st, "%02X ", xq->var->etherface->hash[i]); - fprintf(st, "\n"); - } - if (xq->var->init.mode & XQ_IN_MO_PRO) - fprintf(st, "Promiscuous Receive Mode\n"); - } else { - fprintf(st, "Filters:\n"); - for (i=0; ivar->setup.macs[i], buffer); - fprintf(st, " [%2d]: %s\n", i, buffer); - } - if (xq->var->setup.multicast) - fprintf(st, "All Multicast Receive Mode\n"); - if (xq->var->setup.promiscuous) - fprintf(st, "Promiscuous Receive Mode\n"); - } - return SCPE_OK; -} - -t_stat xq_show_type (FILE* st, UNIT* uptr, int32 val, void* desc) -{ - CTLR* xq = xq_unit2ctlr(uptr); - fprintf(st, "type="); - switch (xq->var->type) { - case XQ_T_DEQNA: fprintf(st, "DEQNA"); break; - case XQ_T_DELQA: fprintf(st, "DELQA"); break; - case XQ_T_DELQA_PLUS: fprintf(st, "DELQA-T"); break; - } - if (xq->var->type != xq->var->mode) { - fprintf(st, ",mode="); - switch (xq->var->mode) { - case XQ_T_DEQNA: fprintf(st, "DEQNA"); break; - case XQ_T_DELQA: fprintf(st, "DELQA"); break; - case XQ_T_DELQA_PLUS: fprintf(st, "DELQA-T"); break; - } - } - return SCPE_OK; -} - -t_stat xq_set_type (UNIT* uptr, int32 val, char* cptr, void* desc) -{ - CTLR* xq = xq_unit2ctlr(uptr); - if (!cptr) return SCPE_IERR; - if (uptr->flags & UNIT_ATT) return SCPE_ALATT; - - /* this assumes that the parameter has already been upcased */ - if (!strcmp(cptr, "DEQNA")) xq->var->type = XQ_T_DEQNA; - else if (!strcmp(cptr, "DELQA")) xq->var->type = XQ_T_DELQA; - else if (!strcmp(cptr, "DELQA-T")) xq->var->type = XQ_T_DELQA_PLUS; - else return SCPE_ARG; - xq->var->mode = XQ_T_DELQA; - if (xq->var->type == XQ_T_DEQNA) - xq->var->mode = XQ_T_DEQNA; - - return SCPE_OK; -} - -t_stat xq_show_poll (FILE* st, UNIT* uptr, int32 val, void* desc) -{ - CTLR* xq = xq_unit2ctlr(uptr); - if (xq->var->poll) - fprintf(st, "poll=%d", xq->var->poll); - else { - fprintf(st, "polling=disabled"); - if (xq->var->coalesce_latency) - fprintf(st, ",latency=%d", xq->var->coalesce_latency); - } - return SCPE_OK; -} - -t_stat xq_set_poll (UNIT* uptr, int32 val, char* cptr, void* desc) -{ - CTLR* xq = xq_unit2ctlr(uptr); - if (!cptr) return SCPE_IERR; - if (uptr->flags & UNIT_ATT) return SCPE_ALATT; - - /* this assumes that the parameter has already been upcased */ - if (!strcmp(cptr, "DEFAULT")) - xq->var->poll = XQ_SERVICE_INTERVAL; - else if ((!strcmp(cptr, "DISABLED")) || (!strncmp(cptr, "DELAY=", 6))) { - xq->var->poll = 0; - if (!strncmp(cptr, "DELAY=", 6)) { - int delay = 0; - if (1 != sscanf(cptr+6, "%d", &delay)) - return SCPE_ARG; - xq->var->coalesce_latency = delay; - xq->var->coalesce_latency_ticks = (tmr_poll * clk_tps * xq->var->coalesce_latency) / 1000000; - } - } - else { - int newpoll = 0; - if (1 != sscanf(cptr, "%d", &newpoll)) - return SCPE_ARG; - if ((newpoll == 0) || - ((!sim_idle_enab) && (newpoll >= 4) && (newpoll <= 2500))) - xq->var->poll = newpoll; - else - return SCPE_ARG; - } - - return SCPE_OK; -} - -t_stat xq_show_sanity (FILE* st, UNIT* uptr, int32 val, void* desc) -{ - CTLR* xq = xq_unit2ctlr(uptr); - - fprintf(st, "sanity="); - switch (xq->var->sanity.enabled) { - case 2: fprintf(st, "ON\n"); break; - default: fprintf(st, "OFF\n"); break; - } - return SCPE_OK; -} - -t_stat xq_set_sanity (UNIT* uptr, int32 val, char* cptr, void* desc) -{ - CTLR* xq = xq_unit2ctlr(uptr); - if (!cptr) return SCPE_IERR; - if (uptr->flags & UNIT_ATT) return SCPE_ALATT; - - /* this assumes that the parameter has already been upcased */ - if (!strcmp(cptr, "ON")) xq->var->sanity.enabled = 2; - else if (!strcmp(cptr, "OFF")) xq->var->sanity.enabled = 0; - else return SCPE_ARG; - - return SCPE_OK; -} - -/*============================================================================*/ - -t_stat xq_nxm_error(CTLR* xq) -{ - const uint16 set_bits = XQ_CSR_NI | XQ_CSR_XI | XQ_CSR_XL | XQ_CSR_RL; - sim_debug(DBG_WRN, xq->dev, "Non Existent Memory Error!\n"); - - if (xq->var->mode == XQ_T_DELQA_PLUS) { - /* set NXM and associated bits in SRR */ - xq->var->srr |= (XQ_SRR_FES | XQ_SRR_NXM); - xq_setint(xq); - } else - /* set NXM and associated bits in CSR */ - xq_csr_set_clr(xq, set_bits , 0); - return SCPE_OK; -} - -/* -** write callback -*/ -void xq_write_callback (CTLR* xq, int status) -{ - int32 wstatus; - const uint16 TDR = 100 + xq->var->write_buffer.len * 8; /* arbitrary value */ - uint16 write_success[2] = {0}; - uint16 write_failure[2] = {XQ_DSC_C}; - write_success[1] = TDR & 0x03FF; /* Does TDR get set on successful packets ?? */ - write_failure[1] = TDR & 0x03FF; /* TSW2<09:00> */ - - xq->var->stats.xmit += 1; - /* update write status words */ - if (status == 0) { /* success */ - if (DBG_PCK & xq->dev->dctrl) - eth_packet_trace_ex(xq->var->etherface, xq->var->write_buffer.msg, xq->var->write_buffer.len, "xq-write", DBG_DAT & xq->dev->dctrl, DBG_PCK); - wstatus = Map_WriteW(xq->var->xbdl_ba + 8, 4, write_success); - } else { /* failure */ - sim_debug(DBG_WRN, xq->dev, "Packet Write Error!\n"); - xq->var->stats.fail += 1; - wstatus = Map_WriteW(xq->var->xbdl_ba + 8, 4, write_failure); - } - if (wstatus) { - xq_nxm_error(xq); - return; - } - - /* update csr */ - xq_csr_set_clr(xq, XQ_CSR_XI, 0); - - /* reset sanity timer */ - xq_reset_santmr(xq); - - /* clear write buffer */ - xq->var->write_buffer.len = 0; - -} - -void xqa_write_callback (int status) -{ - xq_write_callback(&xq_ctrl[0], status); -} - -void xqb_write_callback (int status) -{ - xq_write_callback(&xq_ctrl[1], status); -} - -/* read registers: */ -t_stat xq_rd(int32* data, int32 PA, int32 access) -{ - CTLR* xq = xq_pa2ctlr(PA); - int index = (PA >> 1) & 07; /* word index */ - - sim_debug(DBG_REG, xq->dev, "xq_rd(PA=0x%08X [%s], access=%d)\n", PA, ((xq->var->mode == XQ_T_DELQA_PLUS) ? xqt_recv_regnames[index] : xq_recv_regnames[index]), access); - switch (index) { - case 0: - case 1: - /* return checksum in external loopback mode */ - if (xq->var->csr & XQ_CSR_EL) - *data = 0xFF00 | xq->var->mac_checksum[index]; - else - *data = 0xFF00 | xq->var->mac[index]; - break; - case 2: - case 3: - case 4: - case 5: - *data = 0xFF00 | xq->var->mac[index]; - break; - case 6: - if (xq->var->mode != XQ_T_DELQA_PLUS) { - sim_debug_u16(DBG_VAR, xq->dev, xq_var_bits, xq->var->var, xq->var->var, 0); - sim_debug (DBG_VAR, xq->dev, ", vec = 0%o\n", (xq->var->var & XQ_VEC_IV)); - *data = xq->var->var; - } else { - sim_debug_u16(DBG_VAR, xq->dev, xq_srr_bits, xq->var->srr, xq->var->srr, 0); - *data = xq->var->srr; - } - break; - case 7: - sim_debug_u16(DBG_CSR, xq->dev, xq_csr_bits, xq->var->csr, xq->var->csr, 1); - *data = xq->var->csr; - break; - } - return SCPE_OK; -} - - -/* dispatch ethernet read request - procedure documented in sec. 3.2.2 */ - -t_stat xq_process_rbdl(CTLR* xq) -{ - int32 rstatus, wstatus; - uint16 b_length, w_length, rbl; - uint32 address; - ETH_ITEM* item; - uint8* rbuf; - - if (xq->var->mode == XQ_T_DELQA_PLUS) - return xq_process_turbo_rbdl(xq); - - sim_debug(DBG_TRC, xq->dev, "xq_process_rdbl\n"); - - /* process buffer descriptors */ - while(1) { - - /* get receive bdl from memory */ - xq->var->rbdl_buf[0] = 0xFFFF; - wstatus = Map_WriteW(xq->var->rbdl_ba, 2, &xq->var->rbdl_buf[0]); - rstatus = Map_ReadW (xq->var->rbdl_ba + 2, 6, &xq->var->rbdl_buf[1]); - if (rstatus || wstatus) return xq_nxm_error(xq); - - /* invalid buffer? */ - if (~xq->var->rbdl_buf[1] & XQ_DSC_V) { - xq_csr_set_clr(xq, XQ_CSR_RL, 0); - return SCPE_OK; - } - - /* explicit chain buffer? */ - if (xq->var->rbdl_buf[1] & XQ_DSC_C) { - xq->var->rbdl_ba = ((xq->var->rbdl_buf[1] & 0x3F) << 16) | xq->var->rbdl_buf[2]; - continue; - } - - /* stop processing if nothing in read queue */ - if (!xq->var->ReadQ.count) break; - - /* get status words */ - rstatus = Map_ReadW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]); - if (rstatus) return xq_nxm_error(xq); - - /* get host memory address */ - address = ((xq->var->rbdl_buf[1] & 0x3F) << 16) | xq->var->rbdl_buf[2]; - - /* decode buffer length - two's complement (in words) */ - w_length = ~xq->var->rbdl_buf[3] + 1; - b_length = w_length * 2; - if (xq->var->rbdl_buf[1] & XQ_DSC_H) b_length -= 1; - if (xq->var->rbdl_buf[1] & XQ_DSC_L) b_length -= 1; - - item = &xq->var->ReadQ.item[xq->var->ReadQ.head]; - rbl = item->packet.len; - rbuf = item->packet.msg; - - /* see if packet must be size-adjusted or is splitting */ - if (item->packet.used) { - int used = item->packet.used; - rbl -= used; - rbuf = &item->packet.msg[used]; - } else { - /* adjust runt packets */ - if (rbl < ETH_MIN_PACKET) { - xq->var->stats.runt += 1; - sim_debug(DBG_WRN, xq->dev, "Runt detected, size = %d\n", rbl); - /* pad runts with zeros up to minimum size - this allows "legal" (size - 60) - processing of those weird short ARP packets that seem to occur occasionally */ - memset(&item->packet.msg[rbl], 0, ETH_MIN_PACKET-rbl); - rbl = ETH_MIN_PACKET; - }; - - /* adjust oversized packets */ - if (rbl > ETH_MAX_PACKET) { - xq->var->stats.giant += 1; - sim_debug(DBG_WRN, xq->dev, "Giant detected, size=%d\n", rbl); - /* trim giants down to maximum size - no documentation on how to handle the data loss */ - item->packet.len = ETH_MAX_PACKET; - rbl = ETH_MAX_PACKET; - }; - }; - - /* make sure entire packet fits in buffer - if not, will need to split into multiple buffers */ - if (rbl > b_length) - rbl = b_length; - item->packet.used += rbl; - - /* send data to host */ - wstatus = Map_WriteB(address, rbl, rbuf); - if (wstatus) return xq_nxm_error(xq); - - /* set receive size into RBL - RBL<10:8> maps into Status1<10:8>, - RBL<7:0> maps into Status2<7:0>, and Status2<15:8> (copy) */ - - xq->var->rbdl_buf[4] = 0; - switch (item->type) { - case 0: /* setup packet */ - xq->var->stats.setup += 1; - xq->var->rbdl_buf[4] = 0x2700; /* set esetup and RBL 10:8 */ - break; - case 1: /* loopback packet */ - xq->var->stats.loop += 1; - xq->var->rbdl_buf[4] = 0x2000; /* loopback flag */ - xq->var->rbdl_buf[4] |= (rbl & 0x0700); /* high bits of rbl */ - break; - case 2: /* normal packet */ - rbl -= 60; /* keeps max packet size in 11 bits */ - xq->var->rbdl_buf[4] = (rbl & 0x0700); /* high bits of rbl */ - break; - } - if (item->packet.used < item->packet.len) - xq->var->rbdl_buf[4] |= 0xC000; /* not last segment */ - xq->var->rbdl_buf[5] = ((rbl & 0x00FF) << 8) | (rbl & 0x00FF); - if (xq->var->ReadQ.loss) { - sim_debug(DBG_WRN, xq->dev, "ReadQ overflow!\n"); - xq->var->rbdl_buf[4] |= 0x0001; /* set overflow bit */ - xq->var->stats.dropped += xq->var->ReadQ.loss; - xq->var->ReadQ.loss = 0; /* reset loss counter */ - } - - /* update read status words*/ - wstatus = Map_WriteW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]); - if (wstatus) return xq_nxm_error(xq); - - /* remove packet from queue */ - if (item->packet.used >= item->packet.len) - ethq_remove(&xq->var->ReadQ); - - /* mark transmission complete */ - xq_csr_set_clr(xq, XQ_CSR_RI, 0); - - /* set to next bdl (implicit chain) */ - xq->var->rbdl_ba += 12; - - } /* while */ - - return SCPE_OK; -} - -t_stat xq_process_mop(CTLR* xq) -{ - uint32 address; - uint16 size; - int32 wstatus; - struct xq_meb* meb = (struct xq_meb*) &xq->var->write_buffer.msg[0200]; - const struct xq_meb* limit = (struct xq_meb*) &xq->var->write_buffer.msg[0400]; - - sim_debug(DBG_TRC, xq->dev, "xq_process_mop()\n"); - - if (xq->var->type == XQ_T_DEQNA) /* DEQNA's don't MOP */ - return SCPE_NOFNC; - - while ((meb->type != 0) && (meb < limit)) { - address = (meb->add_hi << 16) || (meb->add_mi << 8) || meb->add_lo; - size = (meb->siz_hi << 8) || meb->siz_lo; - - /* MOP stuff here - NOT YET FULLY IMPLEMENTED */ - sim_debug (DBG_WRN, xq->dev, "Processing MEB type: %d\n", meb->type); - switch (meb->type) { - case 0: /* MOP Termination */ - break; - case 1: /* MOP Read Ethernet Address */ - wstatus = Map_WriteB(address, sizeof(ETH_MAC), (uint8*) &xq->var->setup.macs[0]); - if (wstatus) return xq_nxm_error(xq); - break; - case 2: /* MOP Reset System ID */ - break; - case 3: /* MOP Read Last MOP Boot */ - break; - case 4: /* MOP Read Boot Password */ - break; - case 5: /* MOP Write Boot Password */ - break; - case 6: /* MOP Read System ID */ - break; - case 7: /* MOP Write System ID */ - break; - case 8: /* MOP Read Counters */ - break; - case 9: /* Mop Read/Clear Counters */ - break; - case 10: /* DELQA-PLUS Board ROM Version */ - if (xq->var->type == XQ_T_DELQA_PLUS) { - uint16 Delqa_Plus_ROM_Version[3] = {2, 0, 0}; /* 2.0.0 */ - wstatus = Map_WriteB(address, sizeof(Delqa_Plus_ROM_Version), (uint8*) Delqa_Plus_ROM_Version); - if (wstatus) return xq_nxm_error(xq); - } - break; - } /* switch */ - - /* process next meb */ - meb += sizeof(struct xq_meb); - - } /* while */ - return SCPE_OK; -} - -t_stat xq_process_setup(CTLR* xq) -{ - int i,j; - int count = 0; - float secs; - uint32 saved_debug = xq->dev->dctrl; - ETH_MAC zeros = {0, 0, 0, 0, 0, 0}; - ETH_MAC filters[XQ_FILTER_MAX + 1]; - - sim_debug(DBG_TRC, xq->dev, "xq_process_setup()\n"); - - /* temporarily turn on Ethernet debugging if setup debugging is enabled */ - if (xq->dev->dctrl & DBG_SET) - xq->dev->dctrl |= DBG_ETH; - - /* extract filter addresses from setup packet */ - memset(xq->var->setup.macs, '\0', sizeof(xq->var->setup.macs)); - for (i = 0; i < 7; i++) - for (j = 0; j < 6; j++) { - xq->var->setup.macs[i] [j] = xq->var->write_buffer.msg[(i + 01) + (j * 8)]; - if (xq->var->write_buffer.len > 112) - xq->var->setup.macs[i+7][j] = xq->var->write_buffer.msg[(i + 0101) + (j * 8)]; - } - - /* - Under VMS the setup packet that is passed to turn promiscuous - off after it has been on doesn't seem to follow the rules documented - in both the DEQNA and DELQA manuals. - These rules seem to say that setup packets less than 128 should only - modify the address filter set and probably not the All-Multicast and - Promiscuous modes, however, VMS V5-5 and V7.3 seem to send a 127 byte - packet to turn this functionality off. I'm not sure how real hardware - behaves in this case, since the only consequence is extra interrupt - load. To realize and retain the benefits of the newly added BPF - functionality in sim_ether, I've modified the logic implemented here - to disable Promiscuous mode when a "small" setup packet is processed. - I'm deliberately not modifying the All-Multicast mode the same way - since I don't have an observable case of its behavior. These two - different modes come from very different usage situations: - 1) Promiscuous mode is usually entered for relatively short periods - of time due to the needs of a specific application program which - is doing some sort of management/monitoring function (i.e. tcpdump) - 2) All-Multicast mode is only entered by the OS Kernel Port Driver - when it happens to have clients (usually network stacks or service - programs) which as a group need to listen to more multicast ethernet - addresses than the 12 (or so) which the hardware supports directly. - so, I believe that the All-Multicast mode, is first rarely used, and if - it ever is used, once set, it will probably be set either forever or for - long periods of time, and the additional interrupt processing load to - deal with the distinctly lower multicast traffic set is clearly lower than - that of the promiscuous mode. - */ - xq->var->setup.promiscuous = 0; - /* process high byte count */ - if (xq->var->write_buffer.len > 128) { - uint16 len = xq->var->write_buffer.len; - uint16 led, san; - - xq->var->setup.multicast = (0 != (len & XQ_SETUP_MC)); - xq->var->setup.promiscuous = (0 != (len & XQ_SETUP_PM)); - if (led = (len & XQ_SETUP_LD) >> 2) { - switch (led) { - case 1: xq->var->setup.l1 = 0; break; - case 2: xq->var->setup.l2 = 0; break; - case 3: xq->var->setup.l3 = 0; break; - } /* switch */ - } /* if led */ - - /* set sanity timer timeout */ - san = (len & XQ_SETUP_ST) >> 4; - switch(san) { - case 0: secs = 0.25; break; /* 1/4 second */ - case 1: secs = 1; break; /* 1 second */ - case 2: secs = 4; break; /* 4 seconds */ - case 3: secs = 16; break; /* 16 seconds */ - case 4: secs = 1 * 60; break; /* 1 minute */ - case 5: secs = 4 * 60; break; /* 4 minutes */ - case 6: secs = 16 * 60; break; /* 16 minutes */ - case 7: secs = 64 * 60; break; /* 64 minutes */ - } - xq->var->sanity.quarter_secs = (int) (secs * 4); - } - - /* finalize sanity timer state */ - if (xq->var->sanity.enabled != 2) { - if (xq->var->csr & XQ_CSR_SE) - xq->var->sanity.enabled = 1; - else - xq->var->sanity.enabled = 0; - } - xq_reset_santmr(xq); - - /* set ethernet filter */ - /* memcpy (filters[count++], xq->mac, sizeof(ETH_MAC)); */ - for (i = 0; i < XQ_FILTER_MAX; i++) - if (memcmp(zeros, &xq->var->setup.macs[i], sizeof(ETH_MAC))) - memcpy (filters[count++], xq->var->setup.macs[i], sizeof(ETH_MAC)); - eth_filter (xq->var->etherface, count, filters, xq->var->setup.multicast, xq->var->setup.promiscuous); - - /* process MOP information */ - if (xq->var->write_buffer.msg[0]) - xq_process_mop(xq); - - /* mark setup block valid */ - xq->var->setup.valid = 1; - - xq_debug_setup(xq); - - xq->dev->dctrl = saved_debug; /* restore original debugging */ - - return SCPE_OK; -} - -/* - Dispatch Write Operation - - The DELQA manual does not explicitly state whether or not multiple packets - can be written in one transmit operation, so a maximum of 1 packet is assumed. - - MP: Hmmm... Figure 3-1 on page 3-3 step 6 says that descriptors will be processed - until the end of the list is found. - -*/ -t_stat xq_process_xbdl(CTLR* xq) -{ - const uint16 implicit_chain_status[2] = {XQ_DSC_V | XQ_DSC_C, 1}; - const uint16 write_success[2] = {0, 1 /*Non-Zero TDR*/}; - uint16 b_length, w_length; - int32 rstatus, wstatus; - uint32 address; - t_stat status; - - sim_debug(DBG_TRC, xq->dev, "xq_process_xbdl()\n"); - - /* clear write buffer */ - xq->var->write_buffer.len = 0; - - /* process buffer descriptors until not valid */ - while (1) { - - /* Get transmit bdl from memory */ - rstatus = Map_ReadW (xq->var->xbdl_ba, 12, &xq->var->xbdl_buf[0]); - xq->var->xbdl_buf[0] = 0xFFFF; - wstatus = Map_WriteW(xq->var->xbdl_ba, 2, &xq->var->xbdl_buf[0]); - if (rstatus || wstatus) return xq_nxm_error(xq); - - /* invalid buffer? */ - if (~xq->var->xbdl_buf[1] & XQ_DSC_V) { - xq_csr_set_clr(xq, XQ_CSR_XL, 0); - sim_debug(DBG_WRN, xq->dev, "XBDL List empty\n"); - return SCPE_OK; - } - - /* compute host memory address */ - address = ((xq->var->xbdl_buf[1] & 0x3F) << 16) | xq->var->xbdl_buf[2]; - - /* decode buffer length - two's complement (in words) */ - w_length = ~xq->var->xbdl_buf[3] + 1; - b_length = w_length * 2; - if (xq->var->xbdl_buf[1] & XQ_DSC_H) b_length -= 1; - if (xq->var->xbdl_buf[1] & XQ_DSC_L) b_length -= 1; - - /* explicit chain buffer? */ - if (xq->var->xbdl_buf[1] & XQ_DSC_C) { - xq->var->xbdl_ba = address; - sim_debug(DBG_WRN, xq->dev, "XBDL chained buffer encountered: %d\n", b_length); - continue; - } - - /* add to transmit buffer, making sure it's not too big */ - if ((xq->var->write_buffer.len + b_length) > sizeof(xq->var->write_buffer.msg)) - b_length = (uint16)(sizeof(xq->var->write_buffer.msg) - xq->var->write_buffer.len); - rstatus = Map_ReadB(address, b_length, &xq->var->write_buffer.msg[xq->var->write_buffer.len]); - if (rstatus) return xq_nxm_error(xq); - xq->var->write_buffer.len += b_length; - - /* end of message? */ - if (xq->var->xbdl_buf[1] & XQ_DSC_E) { - if (((~xq->var->csr & XQ_CSR_RE) && ((~xq->var->csr & XQ_CSR_IL) || (xq->var->csr & XQ_CSR_EL))) || /* loopback */ - (xq->var->xbdl_buf[1] & XQ_DSC_S)) { /* or setup packet (forces loopback regardless of state) */ - if (xq->var->xbdl_buf[1] & XQ_DSC_S) { /* setup packet */ - status = xq_process_setup(xq); - - /* put packet in read buffer */ - ethq_insert (&xq->var->ReadQ, 0, &xq->var->write_buffer, status); - } else { /* loopback */ - /* put packet in read buffer */ - ethq_insert (&xq->var->ReadQ, 1, &xq->var->write_buffer, 0); - } - - /* update write status */ - wstatus = Map_WriteW(xq->var->xbdl_ba + 8, 4, (uint16*) write_success); - if (wstatus) return xq_nxm_error(xq); - - /* clear write buffer */ - xq->var->write_buffer.len = 0; - - /* reset sanity timer */ - xq_reset_santmr(xq); - - /* mark transmission complete */ - xq_csr_set_clr(xq, XQ_CSR_XI, 0); - - /* now trigger "read" of setup or loopback packet */ - if (~xq->var->csr & XQ_CSR_RL) - status = xq_process_rbdl(xq); - - } else { /* not loopback */ - - status = eth_write(xq->var->etherface, &xq->var->write_buffer, xq->var->wcallback); - if (status != SCPE_OK) /* not implemented or unattached */ - xq_write_callback(xq, 1); /* fake failure */ - else { - if (xq->var->coalesce_latency == 0) - xq_svc(&xq->unit[0]); /* service any received data */ - } - sim_debug(DBG_WRN, xq->dev, "XBDL completed processing write\n"); - - } /* loopback/non-loopback */ - - } else { /* not at end-of-message */ - - sim_debug(DBG_WRN, xq->dev, "XBDL processing implicit chain buffer segment\n"); - /* update bdl status words */ - wstatus = Map_WriteW(xq->var->xbdl_ba + 8, 4, (uint16*) implicit_chain_status); - if(wstatus) return xq_nxm_error(xq); - } - - /* set to next bdl (implicit chain) */ - xq->var->xbdl_ba += 12; - - } /* while */ -} - -t_stat xq_dispatch_rbdl(CTLR* xq) -{ - int i; - int32 rstatus, wstatus; - - sim_debug(DBG_TRC, xq->dev, "xq_dispatch_rbdl()\n"); - - /* mark receive bdl valid */ - xq_csr_set_clr(xq, 0, XQ_CSR_RL); - - /* init receive bdl buffer */ - for (i=0; i<6; i++) - xq->var->rbdl_buf[i] = 0; - - /* get address of first receive buffer */ - xq->var->rbdl_ba = ((xq->var->rbdl[1] & 0x3F) << 16) | (xq->var->rbdl[0] & ~01); - - /* get first receive buffer */ - xq->var->rbdl_buf[0] = 0xFFFF; - wstatus = Map_WriteW(xq->var->rbdl_ba, 2, &xq->var->rbdl_buf[0]); - rstatus = Map_ReadW (xq->var->rbdl_ba + 2, 6, &xq->var->rbdl_buf[1]); - if (rstatus || wstatus) return xq_nxm_error(xq); - - /* is buffer valid? */ - if (~xq->var->rbdl_buf[1] & XQ_DSC_V) { - xq_csr_set_clr(xq, XQ_CSR_RL, 0); - return SCPE_OK; - } - - /* process any waiting packets in receive queue */ - if (xq->var->ReadQ.count) - xq_process_rbdl(xq); - - return SCPE_OK; -} - -t_stat xq_dispatch_xbdl(CTLR* xq) -{ - int i; - t_stat status; - - sim_debug(DBG_TRC, xq->dev, "xq_dispatch_xbdl()\n"); - - /* mark transmit bdl valid */ - xq_csr_set_clr(xq, 0, XQ_CSR_XL); - - /* initialize transmit bdl buffers */ - for (i=0; i<6; i++) - xq->var->xbdl_buf[i] = 0; - - /* clear transmit buffer */ - xq->var->write_buffer.len = 0; - - /* get base address of first transmit descriptor */ - xq->var->xbdl_ba = ((xq->var->xbdl[1] & 0x3F) << 16) | (xq->var->xbdl[0] & ~01); - - /* process xbdl */ - status = xq_process_xbdl(xq); - - return status; -} - -t_stat xq_process_turbo_rbdl(CTLR* xq) -{ - int i; - t_stat status; - int descriptors_consumed = 0; - uint32 rdra = (xq->var->init.rdra_h << 16) | xq->var->init.rdra_l; - - sim_debug(DBG_TRC, xq->dev, "xq_process_turbo_rbdl()\n"); - - if ((xq->var->srr & XQ_SRR_RESP) != XQ_SRR_STRT) - return SCPE_OK; - - /* Process descriptors in the receive ring while the're available and we have packets */ - do { - uint32 address; - uint16 b_length, rbl; - ETH_ITEM* item; - uint8* rbuf; - - /* stop processing when nothing in read queue */ - if (!xq->var->ReadQ.count) - break; - - i = xq->var->rbindx; - - /* Get receive descriptor from memory */ - status = Map_ReadW (rdra+i*sizeof(xq->var->rring[i]), sizeof(xq->var->rring[i]), (uint16 *)&xq->var->rring[i]); - if (status != SCPE_OK) - return xq_nxm_error(xq); - - /* Done if Buffer not Owned */ - if (xq->var->rring[i].rmd3 & XQ_TMD3_OWN) - break; - - ++descriptors_consumed; - - /* Update ring index */ - xq->var->rbindx = (xq->var->rbindx + 1) % XQ_TURBO_RC_BCNT; - - address = ((xq->var->rring[i].hadr & 0x3F ) << 16) | xq->var->rring[i].ladr; - b_length = ETH_FRAME_SIZE; - - item = &xq->var->ReadQ.item[xq->var->ReadQ.head]; - rbl = item->packet.len + ETH_CRC_SIZE; - rbuf = item->packet.msg; - - /* see if packet must be size-adjusted or is splitting */ - if (item->packet.used) { - int used = item->packet.used; - rbl -= used; - rbuf = &item->packet.msg[used]; - } else { - /* adjust runt packets */ - if (rbl < ETH_MIN_PACKET) { - xq->var->stats.runt += 1; - sim_debug(DBG_WRN, xq->dev, "Runt detected, size = %d\n", rbl); - /* pad runts with zeros up to minimum size - this allows "legal" (size - 60) - processing of those weird short ARP packets that seem to occur occasionally */ - memset(&item->packet.msg[rbl], 0, ETH_MIN_PACKET-rbl); - rbl = ETH_MIN_PACKET; - }; - - /* adjust oversized packets */ - if (rbl > ETH_FRAME_SIZE) { - xq->var->stats.giant += 1; - sim_debug(DBG_WRN, xq->dev, "Giant detected, size=%d\n", rbl); - /* trim giants down to maximum size - no documentation on how to handle the data loss */ - item->packet.len = ETH_MAX_PACKET; - rbl = ETH_FRAME_SIZE; - }; - }; - - /* make sure entire packet fits in buffer - if not, will need to split into multiple buffers */ - if (rbl > b_length) - rbl = b_length; - item->packet.used += rbl; - - /* send data to host */ - status = Map_WriteB(address, rbl, rbuf); - if (status != SCPE_OK) - return xq_nxm_error(xq); - - /* set receive size into RBL - RBL<10:8> maps into Status1<10:8>, - RBL<7:0> maps into Status2<7:0>, and Status2<15:8> (copy) */ - xq->var->rring[i].rmd0 = 0; - xq->var->rring[i].rmd1 = rbl; - xq->var->rring[i].rmd2 = XQ_RMD2_RON | XQ_RMD2_TON; - if (0 == (item->packet.used - rbl)) - xq->var->rring[i].rmd0 |= XQ_RMD0_STP; /* Start of Packet */ - if (item->packet.used == (item->packet.len + ETH_CRC_SIZE)) - xq->var->rring[i].rmd0 |= XQ_RMD0_ENP; /* End of Packet */ - - if (xq->var->ReadQ.loss) { - xq->var->rring[i].rmd2 |= XQ_RMD2_MIS; - sim_debug(DBG_WRN, xq->dev, "ReadQ overflow!\n"); - xq->var->stats.dropped += xq->var->ReadQ.loss; - xq->var->ReadQ.loss = 0; /* reset loss counter */ - } - - Map_ReadW (rdra+(uint32)(((char *)(&xq->var->rring[xq->var->rbindx].rmd3))-((char *)&xq->var->rring)), sizeof(xq->var->rring[xq->var->rbindx].rmd3), (uint16 *)&xq->var->rring[xq->var->rbindx].rmd3); - if (xq->var->rring[xq->var->rbindx].rmd3 & XQ_RMD3_OWN) - xq->var->rring[i].rmd2 |= XQ_RMD2_EOR; - - /* Update receive descriptor in memory (only done after we've processed the contents) */ - /* Note: We're updating all but the end of the descriptor (which we never change) */ - /* AND the driver will be allowed to change once the changed tmd3 (ownership) */ - /* is noted so we avoid walking on its changes */ - xq->var->rring[i].rmd3 |= XQ_TMD3_OWN; /* Return Descriptor to Driver */ - status = Map_WriteW (rdra+i*sizeof(xq->var->rring[i]), sizeof(xq->var->rring[i])-8, (uint16 *)&xq->var->rring[i]); - if (status != SCPE_OK) - return xq_nxm_error(xq); - - /* remove packet from queue */ - if (item->packet.used >= item->packet.len) - ethq_remove(&xq->var->ReadQ); - } while (0 == (xq->var->rring[xq->var->rbindx].rmd3 & XQ_RMD3_OWN)); - - if (xq->var->rring[xq->var->rbindx].rmd3 & XQ_RMD3_OWN) - sim_debug(DBG_WRN, xq->dev, "xq_process_turbo_rbdl() - receive ring full\n"); - - if (descriptors_consumed) - /* Interrupt for Packet Reception Completion */ - xq_setint(xq); - - return SCPE_OK; -} - -t_stat xq_process_turbo_xbdl(CTLR* xq) -{ - int i; - t_stat status; - int descriptors_consumed = 0; - uint32 tdra = (xq->var->init.tdra_h << 16) | xq->var->init.tdra_l; - - sim_debug(DBG_TRC, xq->dev, "xq_process_turbo_xbdl()\n"); - - if ((xq->var->srr & XQ_SRR_RESP) != XQ_SRR_STRT) - return SCPE_OK; - - /* clear transmit buffer */ - xq->var->write_buffer.len = 0; - - /* Process each descriptor in the transmit ring */ - do { - uint32 address; - uint16 b_length; - - i = xq->var->tbindx; - - /* Get transmit descriptor from memory */ - status = Map_ReadW (tdra+i*sizeof(xq->var->xring[i]), sizeof(xq->var->xring[i]), (uint16 *)&xq->var->xring[i]); - if (status != SCPE_OK) - return xq_nxm_error(xq); - - if (xq->var->xring[i].tmd3 & XQ_TMD3_OWN) - break; - - /* Update ring index */ - xq->var->tbindx = (xq->var->tbindx + 1) % XQ_TURBO_XM_BCNT; - - ++descriptors_consumed; - address = ((xq->var->xring[i].hadr & 0x3F ) << 16) | xq->var->xring[i].ladr; - b_length = (xq->var->xring[i].tmd3 & XQ_TMD3_BCT); - - /* add to transmit buffer, making sure it's not too big */ - if ((xq->var->write_buffer.len + b_length) > sizeof(xq->var->write_buffer.msg)) - b_length = (uint16)(sizeof(xq->var->write_buffer.msg) - xq->var->write_buffer.len); - status = Map_ReadB(address, b_length, &xq->var->write_buffer.msg[xq->var->write_buffer.len]); - if (status != SCPE_OK) - return xq_nxm_error(xq); - - xq->var->write_buffer.len += b_length; - if (!(xq->var->xring[i].tmd3 & XQ_TMD3_FOT)) { - /* Process Loopback if in Loopback mode */ - if (xq->var->init.mode & XQ_IN_MO_LOP) { - if ((xq->var->init.mode & XQ_IN_MO_INT) || (xq->var->etherface)) { - /* put packet in read buffer */ - ethq_insert (&xq->var->ReadQ, 1, &xq->var->write_buffer, 0); - status = SCPE_OK; - } else { - /* External loopback fails when not connected */ - status = SCPE_NOFNC; - } - } else - status = eth_write(xq->var->etherface, &xq->var->write_buffer, NULL); - - xq->var->stats.xmit += 1; - if (status != SCPE_OK) { /* not implemented or unattached */ - sim_debug(DBG_WRN, xq->dev, "Packet Write Error!\n"); - xq->var->stats.fail += 1; - xq->var->xring[i].tmd0 = XQ_TMD0_ERR1; - xq->var->xring[i].tmd1 = 100 + xq->var->write_buffer.len * 8; /* arbitrary value */ - xq->var->xring[i].tmd1 |= XQ_TMD1_LCA; - } else { - if (DBG_PCK & xq->dev->dctrl) - eth_packet_trace_ex(xq->var->etherface, xq->var->write_buffer.msg, xq->var->write_buffer.len, "xq-write", DBG_DAT & xq->dev->dctrl, DBG_PCK); - xq->var->xring[i].tmd0 = 0; - xq->var->xring[i].tmd1 = 100 + xq->var->write_buffer.len * 8; /* arbitrary value */ - } - sim_debug(DBG_WRN, xq->dev, "XBDL completed processing write\n"); - /* clear transmit buffer */ - xq->var->write_buffer.len = 0; - xq->var->xring[i].tmd2 = XQ_TMD2_RON | XQ_TMD2_TON; - } - - Map_ReadW (tdra+(uint32)(((char *)(&xq->var->xring[xq->var->tbindx].tmd3))-((char *)&xq->var->xring)), sizeof(xq->var->xring[xq->var->tbindx].tmd3), (uint16 *)&xq->var->xring[xq->var->tbindx].tmd3); - if (xq->var->xring[xq->var->tbindx].tmd3 & XQ_TMD3_OWN) - xq->var->xring[i].tmd2 |= XQ_TMD2_EOR; - - /* Update transmit descriptor in memory (only done after we've processed the contents) */ - /* Note: We're updating all but the end of the descriptor (which we never change) */ - /* AND the driver will be allowed to change once the changed tmd3 (ownership) */ - /* is noted so we avoid walking on its changes */ - xq->var->xring[i].tmd3 |= XQ_TMD3_OWN; /* Return Descriptor to Driver */ - status = Map_WriteW (tdra+i*sizeof(xq->var->xring[i]), sizeof(xq->var->xring[i])-8, (uint16 *)&xq->var->xring[i]); - if (status != SCPE_OK) - return xq_nxm_error(xq); - - } while (0 == (xq->var->xring[xq->var->tbindx].tmd3 & XQ_TMD3_OWN)); - - if (descriptors_consumed) { - - /* Interrupt for Packet Transmission Completion */ - xq_setint(xq); - - if (xq->var->coalesce_latency == 0) - xq_svc(&xq->unit[0]); /* service any received data */ - } else { - /* There appears to be a bug in the VMS SCS/XQ driver when it uses chained - buffers to transmit a packet. It updates the transmit buffer ring in the - correct order (i.e. clearing the ownership on the last packet segment - first), but it writes a transmit request to the ARQR register after adjusting - the ownership of EACH buffer piece. This results in us being awakened once - and finding nothing to do. We ignore this and the next write the ARQR will - properly cause the packet transmission. - */ - sim_debug(DBG_WRN, xq->dev, "xq_process_turbo_xbdl() - Nothing to Transmit\n"); - } - - return status; -} - -t_stat xq_process_loopback(CTLR* xq, ETH_PACK* pack) -{ - ETH_PACK response; - ETH_MAC *physical_address; - t_stat status; - int offset = 16 + (pack->msg[14] | (pack->msg[15] << 8)); - int function = pack->msg[offset] | (pack->msg[offset+1] << 8); - - sim_debug(DBG_TRC, xq->dev, "xq_process_loopback()\n"); - - if (function != 2 /*forward*/) - return SCPE_NOFNC; - - /* create forward response packet */ - memcpy (&response, pack, sizeof(ETH_PACK)); - if (xq->var->mode == XQ_T_DELQA_PLUS) - physical_address = &xq->var->init.phys; - else - if (xq->var->setup.valid) - physical_address = &xq->var->setup.macs[0]; - else - physical_address = &xq->var->mac; - - /* The only packets we should be responding to are ones which - we received due to them being directed to our physical MAC address, - OR the Broadcast address OR to a Multicast address we're listening to - (we may receive others if we're in promiscuous mode, but shouldn't - respond to them) */ - if ((0 == (pack->msg[0]&1)) && /* Multicast or Broadcast */ - (0 != memcmp(physical_address, pack->msg, sizeof(ETH_MAC)))) - return SCPE_NOFNC; - - memcpy (&response.msg[0], &response.msg[offset+2], sizeof(ETH_MAC)); - memcpy (&response.msg[6], physical_address, sizeof(ETH_MAC)); - offset += 8 - 16; /* Account for the Ethernet Header and Offset value in this number */ - response.msg[14] = offset & 0xFF; - response.msg[15] = (offset >> 8) & 0xFF; - - /* send response packet */ - status = eth_write(xq->var->etherface, &response, NULL); - ++xq->var->stats.loop; - - if (DBG_PCK & xq->dev->dctrl) - eth_packet_trace_ex(xq->var->etherface, response.msg, response.len, ((function == 1) ? "xq-loopbackreply" : "xq-loopbackforward"), DBG_DAT & xq->dev->dctrl, DBG_PCK); - - return status; -} - -t_stat xq_process_remote_console (CTLR* xq, ETH_PACK* pack) -{ - t_stat status; - ETH_MAC source; - uint16 receipt; - int code = pack->msg[16]; - - sim_debug(DBG_TRC, xq->dev, "xq_process_remote_console()\n"); - - switch (code) { - case 0x05: /* request id */ - receipt = pack->msg[18] | (pack->msg[19] << 8); - memcpy(source, &pack->msg[6], sizeof(ETH_MAC)); - - /* send system id to requestor */ - status = xq_system_id (xq, source, receipt); - return status; - break; - case 0x06: /* boot */ - /* - NOTE: the verification field should be checked here against the - verification value established in the setup packet. If they match the - reboot should occur, otherwise nothing happens, and the packet - is passed on to the host. - - Verification is not implemented, since the setup packet processing code - isn't complete yet. - - Various values are also passed: processor, control, and software id. - These control the various boot parameters, however SIMH does not - have a mechanism to pass these to the host, so just reboot. - */ - - status = xq_boot_host(xq); - return status; - break; - } /* switch */ - - return SCPE_NOFNC; -} - -t_stat xq_process_local (CTLR* xq, ETH_PACK* pack) -{ - /* returns SCPE_OK if local processing occurred, - otherwise returns SCPE_NOFNC or some other code */ - int protocol; - - sim_debug(DBG_TRC, xq->dev, "xq_process_local()\n"); - /* DEQNA's have no local processing capability */ - if (xq->var->type == XQ_T_DEQNA) - return SCPE_NOFNC; - - protocol = pack->msg[12] | (pack->msg[13] << 8); - switch (protocol) { - case 0x0090: /* ethernet loopback */ - return xq_process_loopback(xq, pack); - break; - case 0x0260: /* MOP remote console */ - return xq_process_remote_console(xq, pack); - break; - } - return SCPE_NOFNC; -} - -void xq_read_callback(CTLR* xq, int status) -{ - xq->var->stats.recv += 1; - - if (DBG_PCK & xq->dev->dctrl) - eth_packet_trace_ex(xq->var->etherface, xq->var->read_buffer.msg, xq->var->read_buffer.len, "xq-recvd", DBG_DAT & xq->dev->dctrl, DBG_PCK); - - if ((xq->var->csr & XQ_CSR_RE) || (xq->var->mode == XQ_T_DELQA_PLUS)) { /* receiver enabled */ - - /* process any packets locally that can be */ - t_stat status = xq_process_local (xq, &xq->var->read_buffer); - - /* add packet to read queue */ - if (status != SCPE_OK) - ethq_insert(&xq->var->ReadQ, 2, &xq->var->read_buffer, status); - } else { - xq->var->stats.dropped += 1; - sim_debug(DBG_WRN, xq->dev, "packet received with receiver disabled\n"); - } -} - -void xqa_read_callback(int status) -{ - xq_read_callback(&xq_ctrl[0], status); -} - -void xqb_read_callback(int status) -{ - xq_read_callback(&xq_ctrl[1], status); -} - -void xq_sw_reset(CTLR* xq) -{ - const uint16 set_bits = XQ_CSR_XL | XQ_CSR_RL; - int i; - - sim_debug(DBG_TRC, xq->dev, "xq_sw_reset()\n"); - ++xq->var->stats.reset; - - /* Return DELQA-T to DELQA Normal mode */ - if (xq->var->type == XQ_T_DELQA_PLUS) { - xq->var->mode = XQ_T_DELQA; - xq->var->iba = xq->var->srr = 0; - } - - /* reset csr bits */ - xq_csr_set_clr(xq, set_bits, (uint16) ~set_bits); - - if (xq->var->etherface) - xq_csr_set_clr(xq, XQ_CSR_OK, 0); - - /* clear interrupt unconditionally */ - xq_clrint(xq); - - /* flush read queue */ - ethq_clear(&xq->var->ReadQ); - - /* clear setup info */ - xq->var->setup.multicast = 0; - xq->var->setup.promiscuous = 0; - if (xq->var->etherface) { - int count = 0; - ETH_MAC zeros = {0, 0, 0, 0, 0, 0}; - ETH_MAC filters[XQ_FILTER_MAX + 1]; - - /* set ethernet filter */ - /* memcpy (filters[count++], xq->mac, sizeof(ETH_MAC)); */ - for (i = 0; i < XQ_FILTER_MAX; i++) - if (memcmp(zeros, &xq->var->setup.macs[i], sizeof(ETH_MAC))) - memcpy (filters[count++], xq->var->setup.macs[i], sizeof(ETH_MAC)); - eth_filter (xq->var->etherface, count, filters, xq->var->setup.multicast, xq->var->setup.promiscuous); - } - - /* Stop receive polling until the receiver is reenabled */ - xq_stop_receiver(xq); - -} - -/* write registers: */ - -t_stat xq_wr_var(CTLR* xq, int32 data) -{ - uint16 save_var = xq->var->var; - sim_debug(DBG_REG, xq->dev, "xq_wr_var(data= 0x%08X\n", data); - - switch (xq->var->type) { - case XQ_T_DEQNA: - xq->var->var = (data & XQ_VEC_IV); - break; - case XQ_T_DELQA: - case XQ_T_DELQA_PLUS: - xq->var->var = (xq->var->var & XQ_VEC_RO) | (data & XQ_VEC_RW); - - /* if switching to DEQNA-LOCK mode clear VAR<14:10> */ - if (~xq->var->var & XQ_VEC_MS) { - xq->var->mode = XQ_T_DEQNA; - xq->var->var &= ~(XQ_VEC_OS | XQ_VEC_RS | XQ_VEC_ST); - } else { - xq->var->mode = XQ_T_DELQA; - } - - /* if Self Test is on, turn it off to signal completion */ - if (xq->var->var & XQ_VEC_RS) { - xq->var->var &= ~XQ_VEC_RS; - if (!xq->var->etherface) - xq->var->var |= XQ_VEC_S1; /* Indicate No Network Connection */ - else - xq->var->var &= ~XQ_VEC_ST; /* Set success Status */ - } - break; - } - - /* set vector of SIMH device */ - if (data & XQ_VEC_IV) - xq->dib->vec = (data & XQ_VEC_IV) + VEC_Q; - else - xq->dib->vec = 0; - - sim_debug_u16(DBG_VAR, xq->dev, xq_var_bits, save_var, xq->var->var, 1); - - return SCPE_OK; -} - -#ifdef VM_PDP11 -t_stat xq_process_bootrom (CTLR* xq) -{ - /* - NOTE: BOOT ROMs are a PDP-11ism, since they contain PDP-11 binary code. - the host is responsible for creating two *2KB* receive buffers. - - RSTS/E v10.1 source (INIONE.MAR/XHLOOK:) indicates that both the DEQNA and - DELQA will set receive status word 1 bits 15 & 14 on both packets. It also - states that a hardware bug in the DEQNA will set receive status word 1 bit 15 - (only) in the *third* receive buffer (oops!). - - RSTS/E v10.1 will run the Citizenship test from the bootrom after loading it. - Documentation on the Boot ROM can be found in INIQNA.MAR. - */ - - int32 rstatus, wstatus; - uint16 b_length, w_length; - uint32 address; - uint8* bootrom = (uint8*) xq_bootrom; - int i, checksum; - - sim_debug(DBG_TRC, xq->dev, "xq_process_bootrom()\n"); - - /* - RSTS/E v10.1 invokes the Citizenship tests in the Bootrom. For some - reason, the current state of the XQ emulator cannot pass these. So, - to get moving on RSTE/E support, we will replace the following line in - INIQNA.MAR/CITQNA:: - 70$: MOV (R2),R0 ;get the status word - with - 70$: CLR R0 ;force success - to cause the Citizenship test to return success to RSTS/E. - - At some point, the real problem (failure to pass citizenship diagnostics) - does need to be corrected to find incompatibilities in the emulation, and to - ultimately allow it to pass Digital hardware diagnostic tests. - */ - for (i=0; ivar->rbdl_buf[0] = 0xFFFF; - wstatus = Map_WriteW(xq->var->rbdl_ba, 2, &xq->var->rbdl_buf[0]); - rstatus = Map_ReadW (xq->var->rbdl_ba + 2, 6, &xq->var->rbdl_buf[1]); - if (rstatus || wstatus) return xq_nxm_error(xq); - - /* invalid buffer? */ - if (~xq->var->rbdl_buf[1] & XQ_DSC_V) { - xq_csr_set_clr(xq, XQ_CSR_RL, 0); - return SCPE_OK; - } - - /* get status words */ - rstatus = Map_ReadW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]); - if (rstatus) return xq_nxm_error(xq); - - /* get host memory address */ - address = ((xq->var->rbdl_buf[1] & 0x3F) << 16) | xq->var->rbdl_buf[2]; - - /* decode buffer length - two's complement (in words) */ - w_length = ~xq->var->rbdl_buf[3] + 1; - b_length = w_length * 2; - if (xq->var->rbdl_buf[1] & XQ_DSC_H) b_length -= 1; - if (xq->var->rbdl_buf[1] & XQ_DSC_L) b_length -= 1; - - /* make sure entire packet fits in buffer */ - assert(b_length >= sizeof(xq_bootrom)/2); - - /* send data to host */ - wstatus = Map_WriteB(address, sizeof(xq_bootrom)/2, bootrom); - if (wstatus) return xq_nxm_error(xq); - - /* update read status words */ - xq->var->rbdl_buf[4] = XQ_DSC_V | XQ_DSC_C; /* valid, chain */ - xq->var->rbdl_buf[5] = 0; - - /* update read status words*/ - wstatus = Map_WriteW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]); - if (wstatus) return xq_nxm_error(xq); - - /* set to next bdl (implicit chain) */ - xq->var->rbdl_ba += 12; - - /* --------------------------- bootrom part 2 -----------------------------*/ - - /* get receive bdl from memory */ - xq->var->rbdl_buf[0] = 0xFFFF; - wstatus = Map_WriteW(xq->var->rbdl_ba, 2, &xq->var->rbdl_buf[0]); - rstatus = Map_ReadW (xq->var->rbdl_ba + 2, 6, &xq->var->rbdl_buf[1]); - if (rstatus || wstatus) return xq_nxm_error(xq); - - /* invalid buffer? */ - if (~xq->var->rbdl_buf[1] & XQ_DSC_V) { - xq_csr_set_clr(xq, XQ_CSR_RL, 0); - return SCPE_OK; - } - - /* get status words */ - rstatus = Map_ReadW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]); - if (rstatus) return xq_nxm_error(xq); - - /* get host memory address */ - address = ((xq->var->rbdl_buf[1] & 0x3F) << 16) | xq->var->rbdl_buf[2]; - - /* decode buffer length - two's complement (in words) */ - w_length = ~xq->var->rbdl_buf[3] + 1; - b_length = w_length * 2; - if (xq->var->rbdl_buf[1] & XQ_DSC_H) b_length -= 1; - if (xq->var->rbdl_buf[1] & XQ_DSC_L) b_length -= 1; - - /* make sure entire packet fits in buffer */ - assert(b_length >= sizeof(xq_bootrom)/2); - - /* send data to host */ - wstatus = Map_WriteB(address, sizeof(xq_bootrom)/2, &bootrom[2048]); - if (wstatus) return xq_nxm_error(xq); - - /* update read status words */ - xq->var->rbdl_buf[4] = XQ_DSC_V | XQ_DSC_C; /* valid, chain */ - xq->var->rbdl_buf[5] = 0; - - /* update read status words*/ - wstatus = Map_WriteW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]); - if (wstatus) return xq_nxm_error(xq); - - /* set to next bdl (implicit chain) */ - xq->var->rbdl_ba += 12; - - /* --------------------------- bootrom part 3 -----------------------------*/ - - switch (xq->var->type) { - case XQ_T_DEQNA: - - /* get receive bdl from memory */ - xq->var->rbdl_buf[0] = 0xFFFF; - wstatus = Map_WriteW(xq->var->rbdl_ba, 2, &xq->var->rbdl_buf[0]); - rstatus = Map_ReadW (xq->var->rbdl_ba + 2, 6, &xq->var->rbdl_buf[1]); - if (rstatus || wstatus) return xq_nxm_error(xq); - - /* invalid buffer? */ - if (~xq->var->rbdl_buf[1] & XQ_DSC_V) { - xq_csr_set_clr(xq, XQ_CSR_RL, 0); - return SCPE_OK; - } - - /* get status words */ - rstatus = Map_ReadW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]); - if (rstatus) return xq_nxm_error(xq); - - /* update read status words */ - xq->var->rbdl_buf[4] = XQ_DSC_V; /* valid */ - xq->var->rbdl_buf[5] = 0; - - /* update read status words*/ - wstatus = Map_WriteW(xq->var->rbdl_ba + 8, 4, &xq->var->rbdl_buf[4]); - if (wstatus) return xq_nxm_error(xq); - - /* set to next bdl (implicit chain) */ - xq->var->rbdl_ba += 12; - break; - - default: - break; - } /* switch */ - - /* --------------------------- Done, finish up -----------------------------*/ - - /* mark transmission complete */ - xq_csr_set_clr(xq, XQ_CSR_RI, 0); - - /* reset sanity timer */ - xq_reset_santmr(xq); - - return SCPE_OK; -} -#endif /* ifdef VM_PDP11 */ - -t_stat xq_wr_csr(CTLR* xq, int32 data) -{ - uint16 set_bits = data & XQ_CSR_RW; /* set RW set bits */ - uint16 clr_bits = ((data ^ XQ_CSR_RW) & XQ_CSR_RW) /* clear RW cleared bits */ - | (data & XQ_CSR_W1) /* write 1 to clear bits */ - | ((data & XQ_CSR_XI) ? XQ_CSR_NI : 0); /* clearing XI clears NI */ - - sim_debug(DBG_REG, xq->dev, "xq_wr_csr(data=0x%08X)\n", data); - - /* reset controller when SR transitions to cleared */ - if (xq->var->csr & XQ_CSR_SR & ~data) { - xq_sw_reset(xq); - return SCPE_OK; - } - - /* start receiver when RE transitions to set */ - if (~xq->var->csr & XQ_CSR_RE & data) { - sim_debug(DBG_REG, xq->dev, "xq_wr_csr(data=0x%08X) - receiver started\n", data); - - /* start the read service timer or enable asynch reading as appropriate */ - xq_start_receiver(xq); - } - - /* stop receiver when RE transitions to clear */ - if (xq->var->csr & XQ_CSR_RE & ~data) { - sim_debug(DBG_REG, xq->dev, "xq_wr_csr(data=0x%08X) - receiver stopped\n", data); - - /* stop the read service timer or disable asynch reading as appropriate */ - xq_stop_receiver(xq); - } - - /* update CSR bits */ - xq_csr_set_clr (xq, set_bits, clr_bits); - -#ifdef VM_PDP11 - /* request boot/diagnostic rom? [PDP-11 only] */ - if ((xq->var->csr & XQ_CSR_BP) == XQ_CSR_BP) /* all bits must be on */ - xq_process_bootrom(xq); -#endif - - return SCPE_OK; -} - -void xq_start_receiver(CTLR* xq) -{ - if (!xq->var->etherface) - return; - - /* start the read service timer or enable asynch reading as appropriate */ - if (xq->var->must_poll) - sim_activate(xq->unit, (sim_idle_enab ? clk_cosched(tmxr_poll) : (tmr_poll*clk_tps)/xq->var->poll)); - else - if ((xq->var->poll == 0) || (xq->var->mode == XQ_T_DELQA_PLUS)) - eth_set_async(xq->var->etherface, xq->var->coalesce_latency_ticks); - else - sim_activate(xq->unit, (sim_idle_enab ? clk_cosched(tmxr_poll) : (tmr_poll*clk_tps)/xq->var->poll)); -} - -void xq_stop_receiver(CTLR* xq) -{ - sim_cancel(&xq->unit[0]); /* Stop Receiving */ - if (xq->var->etherface) - eth_clr_async(xq->var->etherface); -} - -t_stat xq_wr_srqr(CTLR* xq, int32 data) -{ - uint16 set_bits = data & XQ_SRQR_RW; /* set RW set bits */ - - sim_debug(DBG_REG, xq->dev, "xq_wr_srqr(data=0x%08X)\n", data); - - xq->var->srr = set_bits; - - switch (set_bits) { - case XQ_SRQR_STRT: { - t_stat status; - - xq->var->stats.setup += 1; - /* Get init block from memory */ - status = Map_ReadW (xq->var->iba, sizeof(xq->var->init), (uint16 *)&xq->var->init); - if (SCPE_OK != status) { - xq_nxm_error (xq); - } else { - uint32 saved_debug = xq->dev->dctrl; - - /* temporarily turn on Ethernet debugging if setup debugging is enabled */ - if (xq->dev->dctrl & DBG_SET) - xq->dev->dctrl |= DBG_ETH; - - xq_debug_turbo_setup(xq); - - xq->dib->vec = xq->var->init.vector + VEC_Q; - xq->var->tbindx = xq->var->rbindx = 0; - if ((xq->var->sanity.enabled) && (xq->var->init.options & XQ_IN_OP_HIT)) { - xq->var->sanity.quarter_secs = 4*xq->var->init.hit_timeout; - } - xq->var->icr = xq->var->init.options & XQ_IN_OP_INT; - status = eth_filter_hash (xq->var->etherface, 1, &xq->var->init.phys, 0, xq->var->init.mode & XQ_IN_MO_PRO, &xq->var->init.hash_filter); - - xq->dev->dctrl = saved_debug; /* restore original debugging */ - } - /* start the read service timer or enable asynch reading as appropriate */ - xq_start_receiver(xq); - break; - } - case XQ_SRQR_STOP: - xq_stop_receiver(xq); - break; - default: - break; - } - - /* All Writes to SRQR reset the Host Inactivity Timer */ - xq_reset_santmr(xq); - - /* Interrupt after this synchronous request completion */ - xq_setint(xq); - - return SCPE_OK; -} - -t_stat xq_wr_arqr(CTLR* xq, int32 data) -{ - sim_debug(DBG_REG, xq->dev, "xq_wr_arqr(data=0x%08X)\n", data); - - /* initiate transmit activity when requested */ - if (XQ_ARQR_TRQ & data) { - xq_process_turbo_xbdl (xq); - } - /* initiate transmit activity when requested */ - if (XQ_ARQR_RRQ & data) { - xq_process_turbo_rbdl (xq); - } - - /* reset controller when requested */ - if (XQ_ARQR_SR & data) { - xq_sw_reset(xq); - } - - /* All Writes to ARQR reset the Host Inactivity Timer */ - xq_reset_santmr(xq); - - return SCPE_OK; -} - -t_stat xq_wr_icr(CTLR* xq, int32 data) -{ - uint16 old_icr = xq->var->icr; - - sim_debug(DBG_REG, xq->dev, "xq_wr_icr(data=0x%08X)\n", data); - - xq->var->icr = data & XQ_ICR_ENA; - - if (xq->var->icr && !old_icr && xq->var->pending_interrupt) - xq_setint(xq); - - return SCPE_OK; -} - -t_stat xq_wr(int32 data, int32 PA, int32 access) -{ - CTLR* xq = xq_pa2ctlr(PA); - int index = (PA >> 1) & 07; /* word index */ - - sim_debug(DBG_REG, xq->dev, "xq_wr(data=0x%08X, PA=0x%08X[%s], access=%d)\n", data, PA, ((xq->var->mode == XQ_T_DELQA_PLUS) ? xqt_xmit_regnames[index] : xq_xmit_regnames[index]), access); - - switch (xq->var->mode) { - case XQ_T_DELQA_PLUS: - switch (index) { - case 0: /* IBAL */ - xq->var->iba = (xq->var->iba & 0xFFFF0000) | (data & 0xFFFF); - break; - case 1: /* IBAH */ - xq->var->iba = (xq->var->iba & 0xFFFF) | ((data & 0xFFFF) << 16); - break; - case 2: /* ICR */ - xq_wr_icr(xq, data); - break; - case 3: - break; - case 4: /* SRQR */ - xq_wr_srqr(xq, data); - break; - case 5: - break; - case 6: - break; - case 7: /* ARQR */ - xq_wr_arqr(xq, data); - break; - } - break; - default: /* DEQNA, DELQA Normal */ - switch (index) { - case 0: /* IBAL/XCR0 */ /* these should only be written on a DELQA-T */ - if (xq->var->type == XQ_T_DELQA_PLUS) - xq->var->iba = (xq->var->iba & 0xFFFF0000) | (data & 0xFFFF); - break; - case 1: /* IBAH/XCR1 */ - if (xq->var->type == XQ_T_DELQA_PLUS) { - if (((xq->var->iba & 0xFFFF) == 0x0BAF) && (data == 0xFF00)) { - xq->var->mode = XQ_T_DELQA_PLUS; - xq->var->srr = XQ_SRR_TRBO; - sim_cancel(xq->unit); /* Turn off receive processing until explicitly enabled */ - eth_clr_async(xq->var->etherface); - } - xq->var->iba = (xq->var->iba & 0xFFFF) | ((data & 0xFFFF) << 16); - } - break; - case 2: /* receive bdl low bits */ - xq->var->rbdl[0] = data; - break; - case 3: /* receive bdl high bits */ - xq->var->rbdl[1] = data; - xq_dispatch_rbdl(xq); /* start receive operation */ - break; - case 4: /* transmit bdl low bits */ - xq->var->xbdl[0] = data; - break; - case 5: /* transmit bdl high bits */ - xq->var->xbdl[1] = data; - xq_dispatch_xbdl(xq); /* start transmit operation */ - break; - case 6: /* vector address register */ - xq_wr_var(xq, data); - break; - case 7: /* control and status register */ - xq_wr_csr(xq, data); - break; - } - break; - } - return SCPE_OK; -} - - -/* reset device */ -t_stat xq_reset(DEVICE* dptr) -{ - t_stat status; - CTLR* xq = xq_dev2ctlr(dptr); - const uint16 set_bits = XQ_CSR_RL | XQ_CSR_XL; - - sim_debug(DBG_TRC, xq->dev, "xq_reset()\n"); - - /* calculate MAC checksum */ - xq_make_checksum(xq); - - /* init vector address register */ - switch (xq->var->type) { - case XQ_T_DEQNA: - xq->var->var = 0; - xq->var->mode = XQ_T_DEQNA; - break; - case XQ_T_DELQA: - case XQ_T_DELQA_PLUS: - xq->var->var = XQ_VEC_MS | XQ_VEC_OS; - xq->var->mode = XQ_T_DELQA; - break; - } - xq->dib->vec = 0; - - /* init control status register */ - xq_csr_set_clr(xq, set_bits, (uint16) ~set_bits); - - /* clear interrupts unconditionally */ - xq_clrint(xq); - - /* init read queue (first time only) */ - status = ethq_init(&xq->var->ReadQ, XQ_QUE_MAX); - if (status != SCPE_OK) - return status; - - /* clear read queue */ - ethq_clear(&xq->var->ReadQ); - - /* reset ethernet interface */ - if (xq->var->etherface) { - /* restore filter on ROM mac address */ - status = eth_filter (xq->var->etherface, 1, &xq->var->mac, 0, 0); - xq_csr_set_clr(xq, XQ_CSR_OK, 0); - - /* start service timer */ - sim_activate_abs(&xq->unit[1], (tmr_poll * clk_tps) / 4); - - /* stop the receiver */ - eth_clr_async(xq->var->etherface); - } - - /* stop the receiver */ - sim_cancel(xq->unit); - - /* set hardware sanity controls */ - if (xq->var->sanity.enabled) { - xq->var->sanity.quarter_secs = XQ_HW_SANITY_SECS * 4/*qsec*/; - } - - return auto_config (0, 0); /* run autoconfig */ -} - -void xq_reset_santmr(CTLR* xq) -{ - sim_debug(DBG_TRC, xq->dev, "xq_reset_santmr()\n"); - if (xq->var->sanity.enabled) { - sim_debug(DBG_SAN, xq->dev, "SANITY TIMER RESETTING, qsecs: %d\n", xq->var->sanity.quarter_secs); - - /* reset sanity countdown timer to max count */ - xq->var->sanity.timer = xq->var->sanity.quarter_secs; - } -} - -t_stat xq_boot_host(CTLR* xq) -{ - sim_debug(DBG_TRC, xq->dev, "xq_boot_host()\n"); - /* - The manual says the hardware should force the Qbus BDCOK low for - 3.6 microseconds, which will cause the host to reboot. - - Since the SIMH Qbus emulator does not have this functionality, we return - a special STOP_ code, and let the CPU stop dispatch routine decide - what the appropriate cpu-specific behavior should be. - */ - return STOP_SANITY; -} - -t_stat xq_system_id (CTLR* xq, const ETH_MAC dest, uint16 receipt_id) -{ - static uint16 receipt = 0; - ETH_PACK system_id; - uint8* const msg = &system_id.msg[0]; - t_stat status; - - sim_debug(DBG_TRC, xq->dev, "xq_system_id()\n"); - - /* reset system ID counter for next event */ - xq->var->idtmr = XQ_SYSTEM_ID_SECS * 4; - - if (xq->var->coalesce_latency) { - /* Adjust latency ticks based on calibrated timer values */ - xq->var->coalesce_latency_ticks = (tmr_poll * clk_tps * xq->var->coalesce_latency) / 1000000; - } - - if (xq->var->type == XQ_T_DEQNA) /* DELQA-only function */ - return SCPE_NOFNC; - - memset (&system_id, 0, sizeof(system_id)); - memcpy (&msg[0], dest, sizeof(ETH_MAC)); - memcpy (&msg[6], xq->var->setup.valid ? xq->var->setup.macs[0] : xq->var->mac, sizeof(ETH_MAC)); - msg[12] = 0x60; /* type */ - msg[13] = 0x02; /* type */ - msg[14] = 0x1C; /* character count */ - msg[15] = 0x00; /* character count */ - msg[16] = 0x07; /* code */ - msg[17] = 0x00; /* zero pad */ - if (receipt_id) { - msg[18] = receipt_id & 0xFF; /* receipt number */ - msg[19] = (receipt_id >> 8) & 0xFF; /* receipt number */ - } else { - msg[18] = receipt & 0xFF; /* receipt number */ - msg[19] = (receipt++ >> 8) & 0xFF; /* receipt number */ - } - - /* MOP VERSION */ - msg[20] = 0x01; /* type */ - msg[21] = 0x00; /* type */ - msg[22] = 0x03; /* length */ - msg[23] = 0x03; /* version */ - msg[24] = 0x01; /* eco */ - msg[25] = 0x00; /* user eco */ - - /* FUNCTION */ - msg[26] = 0x02; /* type */ - msg[27] = 0x00; /* type */ - msg[28] = 0x02; /* length */ - msg[29] = 0x00; /* value 1 ??? */ - msg[30] = 0x00; /* value 2 */ - - /* HARDWARE ADDRESS */ - msg[31] = 0x07; /* type */ - msg[32] = 0x00; /* type */ - msg[33] = 0x06; /* length */ - memcpy (&msg[34], xq->var->mac, sizeof(ETH_MAC)); /* ROM address */ - - /* DEVICE TYPE */ - msg[40] = 37; /* type */ - msg[41] = 0x00; /* type */ - msg[42] = 0x01; /* length */ - msg[43] = 0x11; /* value (0x11=DELQA) */ - if (xq->var->type == XQ_T_DELQA_PLUS) /* DELQA-T has different Device ID */ - msg[43] = 0x4B; /* value (0x4B(75)=DELQA-T) */ - - /* write system id */ - system_id.len = 60; - status = eth_write(xq->var->etherface, &system_id, NULL); - - if (DBG_PCK & xq->dev->dctrl) - eth_packet_trace_ex(xq->var->etherface, system_id.msg, system_id.len, "xq-systemid", DBG_DAT & xq->dev->dctrl, DBG_PCK); - - return status; -} - -/* -** service routine - used for ethernet reading loop -*/ -t_stat xq_svc(UNIT* uptr) -{ - CTLR* xq = xq_unit2ctlr(uptr); - - /* if the receiver is enabled */ - if ((xq->var->mode == XQ_T_DELQA_PLUS) || (xq->var->csr & XQ_CSR_RE)) { - t_stat status; - - /* First pump any queued packets into the system */ - if ((xq->var->ReadQ.count > 0) && ((xq->var->mode == XQ_T_DELQA_PLUS) || (~xq->var->csr & XQ_CSR_RL))) - xq_process_rbdl(xq); - - /* Now read and queue packets that have arrived */ - /* This is repeated as long as they are available */ - do { - /* read a packet from the ethernet - processing is via the callback */ - status = eth_read (xq->var->etherface, &xq->var->read_buffer, xq->var->rcallback); - } while (status); - - /* Now pump any still queued packets into the system */ - if ((xq->var->ReadQ.count > 0) && ((xq->var->mode == XQ_T_DELQA_PLUS) || (~xq->var->csr & XQ_CSR_RL))) - xq_process_rbdl(xq); - } - - /* resubmit service timer */ - if ((xq->var->must_poll) || (xq->var->poll && (xq->var->mode != XQ_T_DELQA_PLUS))) - sim_activate(uptr, (sim_idle_enab ? clk_cosched(tmxr_poll) : (tmr_poll*clk_tps)/xq->var->poll)); - - return SCPE_OK; -} - -/* -** service routine - used for timer based activities -*/ -t_stat xq_tmrsvc(UNIT* uptr) -{ - CTLR* xq = xq_unit2ctlr(uptr); - - /* has sanity timer expired? if so, reboot */ - if (xq->var->sanity.enabled) - if (--xq->var->sanity.timer <= 0) - if (xq->var->mode != XQ_T_DELQA_PLUS) - return xq_boot_host(xq); - else { /* DELQA-T Host Inactivity Timer expiration means switch out of DELQA-T mode */ - sim_debug(DBG_TRC, xq->dev, "xq_tmrsvc(DELQA-PLUS Host Inactivity Expired\n"); - xq->var->mode = XQ_T_DELQA; - xq->var->iba = xq->var->srr = 0; - xq->var->var = XQ_VEC_MS | XQ_VEC_OS; - } - - /* has system id timer expired? if so, do system id */ - if (--xq->var->idtmr <= 0) { - const ETH_MAC mop_multicast = {0xAB, 0x00, 0x00, 0x02, 0x00, 0x00}; - xq_system_id(xq, mop_multicast, 0); - } - - /* resubmit service timer */ - sim_activate(uptr, (tmr_poll * clk_tps) / 4); - - return SCPE_OK; -} - - -/* attach device: */ -t_stat xq_attach(UNIT* uptr, char* cptr) -{ - t_stat status; - char* tptr; - CTLR* xq = xq_unit2ctlr(uptr); - char buffer[80]; /* buffer for runtime input */ - - sim_debug(DBG_TRC, xq->dev, "xq_attach(cptr=%s)\n", cptr); - - /* runtime selection of ethernet port? */ - if (*cptr == '?') { /* I/O style derived from main() */ - memset (buffer, 0, sizeof(buffer)); /* clear read buffer */ - eth_show (stdout, uptr, 0, NULL); /* show ETH devices */ - printf ("Select device (ethX or )? "); /* prompt for device */ - cptr = read_line (buffer, sizeof(buffer), stdin); /* read command line */ - if (cptr == NULL) return SCPE_ARG; /* ignore EOF */ - if (*cptr == 0) return SCPE_ARG; /* ignore blank */ - } /* resume attaching */ - - tptr = (char *) malloc(strlen(cptr) + 1); - if (tptr == NULL) return SCPE_MEM; - strcpy(tptr, cptr); - - xq->var->etherface = (ETH_DEV *) malloc(sizeof(ETH_DEV)); - if (!xq->var->etherface) { - free(tptr); - return SCPE_MEM; - } - - status = eth_open(xq->var->etherface, cptr, xq->dev, DBG_ETH); - if (status != SCPE_OK) { - free(tptr); - free(xq->var->etherface); - xq->var->etherface = NULL; - return status; - } - if (xq->var->poll == 0) { - status = eth_set_async(xq->var->etherface, xq->var->coalesce_latency_ticks); - if (status != SCPE_OK) { - eth_close(xq->var->etherface); - free(tptr); - free(xq->var->etherface); - xq->var->etherface = NULL; - return status; - } - xq->var->must_poll = 0; - } else { - xq->var->must_poll = (SCPE_OK != eth_clr_async(xq->var->etherface)); - } - if (SCPE_OK != eth_check_address_conflict (xq->var->etherface, &xq->var->mac)) { - char buf[32]; - - eth_mac_fmt(&xq->var->mac, buf); /* format ethernet mac address */ - printf("%s: MAC Address Conflict on LAN for address %s, change the MAC address to a unique value\n", xq->dev->name, buf); - if (sim_log) fprintf (sim_log, "%s: MAC Address Conflict on LAN for address %s, change the MAC address to a unique value\n", xq->dev->name, buf); - eth_close(xq->var->etherface); - free(tptr); - free(xq->var->etherface); - xq->var->etherface = NULL; - return SCPE_NOATT; - } - uptr->filename = tptr; - uptr->flags |= UNIT_ATT; - - /* turn on transceiver power indicator */ - xq_csr_set_clr(xq, XQ_CSR_OK, 0); - - /* init read queue (first time only) */ - status = ethq_init(&xq->var->ReadQ, XQ_QUE_MAX); - if (status != SCPE_OK) { - eth_close(xq->var->etherface); - free(tptr); - free(xq->var->etherface); - xq->var->etherface = NULL; - return status; - } - - if (xq->var->mode == XQ_T_DELQA_PLUS) - eth_filter_hash (xq->var->etherface, 1, &xq->var->init.phys, 0, xq->var->init.mode & XQ_IN_MO_PRO, &xq->var->init.hash_filter); - else - if (xq->var->setup.valid) { - int i, count = 0; - ETH_MAC zeros = {0, 0, 0, 0, 0, 0}; - ETH_MAC filters[XQ_FILTER_MAX + 1]; - - for (i = 0; i < XQ_FILTER_MAX; i++) - if (memcmp(zeros, &xq->var->setup.macs[i], sizeof(ETH_MAC))) - memcpy (filters[count++], xq->var->setup.macs[i], sizeof(ETH_MAC)); - eth_filter (xq->var->etherface, count, filters, xq->var->setup.multicast, xq->var->setup.promiscuous); - } - else - /* reset the device with the new attach info */ - xq_reset(xq->dev); - - return SCPE_OK; -} - -/* detach device: */ - -t_stat xq_detach(UNIT* uptr) -{ - CTLR* xq = xq_unit2ctlr(uptr); - sim_debug(DBG_TRC, xq->dev, "xq_detach()\n"); - - if (uptr->flags & UNIT_ATT) { - eth_close (xq->var->etherface); - free(xq->var->etherface); - xq->var->etherface = NULL; - free(uptr->filename); - uptr->filename = NULL; - uptr->flags &= ~UNIT_ATT; - /* cancel service timers */ - sim_cancel(&xq->unit[0]); - sim_cancel(&xq->unit[1]); - } - - /* turn off transceiver power indicator */ - xq_csr_set_clr(xq, 0, XQ_CSR_OK); - - return SCPE_OK; -} - -void xq_setint(CTLR* xq) -{ - if (xq->var->mode == XQ_T_DELQA_PLUS) { - if (!xq->var->icr) { - xq->var->pending_interrupt = 1; - return; - } - xq->var->pending_interrupt = 0; - } - - sim_debug(DBG_TRC, xq->dev, "xq_setint() - Generate Interrupt\n"); - - xq->var->irq = 1; - SET_INT(XQ); - return; -} - -void xq_clrint(CTLR* xq) -{ - int i; - xq->var->irq = 0; /* set controller irq off */ - /* clear master interrupt? */ - for (i=0; iirq) { /* if any irqs enabled */ - SET_INT(XQ); /* set master interrupt on */ - return; - } - CLR_INT(XQ); /* clear master interrupt */ - return; -} - -int32 xq_int (void) -{ - int i; - for (i=0; ivar->irq) { /* if interrupt pending */ - xq_clrint(xq); /* clear interrupt */ - return xq->dib->vec; /* return vector */ - } - } - return 0; /* no interrupt request active */ -} - -void xq_csr_set_clr (CTLR* xq, uint16 set_bits, uint16 clear_bits) -{ - uint16 saved_csr = xq->var->csr; - - /* set the bits in the csr */ - xq->var->csr = (xq->var->csr | set_bits) & ~clear_bits; - - sim_debug_u16(DBG_CSR, xq->dev, xq_csr_bits, saved_csr, xq->var->csr, 1); - - /* check and correct the state of controller interrupt */ - - /* if IE is transitioning, process it */ - if ((saved_csr ^ xq->var->csr) & XQ_CSR_IE) { - - /* if IE transitioning low and interrupt set, clear interrupt */ - if ((clear_bits & XQ_CSR_IE) && xq->var->irq) - xq_clrint(xq); - - /* if IE transitioning high, and XI or RI is high, - set interrupt if interrupt is off */ - if ((set_bits & XQ_CSR_IE) && (xq->var->csr & XQ_CSR_XIRI) && !xq->var->irq) - xq_setint(xq); - - } else { /* IE is not transitioning */ - - /* if interrupts are enabled */ - if (xq->var->csr & XQ_CSR_IE) { - - /* if XI or RI transitioning high and interrupt off, set interrupt */ - if (((saved_csr ^ xq->var->csr) & (set_bits & XQ_CSR_XIRI)) && !xq->var->irq) { - xq_setint(xq); - - } else { - - /* if XI or RI transitioning low, and both XI and RI are now low, - clear interrupt if interrupt is on */ - if (((saved_csr ^ xq->var->csr) & (clear_bits & XQ_CSR_XIRI)) - && !(xq->var->csr & XQ_CSR_XIRI) - && xq->var->irq) - xq_clrint(xq); - } - - } /* IE enabled */ - - } /* IE transitioning */ -} - -/*============================================================================== -/ debugging routines -/=============================================================================*/ - - -void xq_debug_setup(CTLR* xq) -{ - int i; - char buffer[20]; - - if (!(sim_deb && (xq->dev->dctrl & DBG_SET))) - return; - - if (xq->var->write_buffer.msg[0]) - sim_debug(DBG_SET, xq->dev, "%s: setup> MOP info present!\n", xq->dev->name); - - for (i = 0; i < XQ_FILTER_MAX; i++) { - eth_mac_fmt(&xq->var->setup.macs[i], buffer); - sim_debug(DBG_SET, xq->dev, "%s: setup> set addr[%d]: %s\n", xq->dev->name, i, buffer); - } - - if (xq->var->write_buffer.len > 128) { - char buffer[20] = {0}; - uint16 len = xq->var->write_buffer.len; - if (len & XQ_SETUP_MC) strcat(buffer, "MC "); - if (len & XQ_SETUP_PM) strcat(buffer, "PM "); - if (len & XQ_SETUP_LD) strcat(buffer, "LD "); - if (len & XQ_SETUP_ST) strcat(buffer, "ST "); - sim_debug(DBG_SET, xq->dev, "%s: setup> Length [%d =0x%X, LD:%d, ST:%d] info: %s\n", - xq->dev->name, len, len, (len & XQ_SETUP_LD) >> 2, (len & XQ_SETUP_ST) >> 4, buffer); - } -} - -void xq_debug_turbo_setup(CTLR* xq) -{ - int i; - char buffer[64] = ""; - - if (!(sim_deb && (xq->dev->dctrl & DBG_SET))) - return; - - sim_debug(DBG_SET, xq->dev, "%s: setup> Turbo Initialization Block!\n", xq->dev->name); - - if (xq->var->init.mode & XQ_IN_MO_PRO) strcat(buffer, "PRO "); - if (xq->var->init.mode & XQ_IN_MO_INT) strcat(buffer, "INT "); - if (xq->var->init.mode & XQ_IN_MO_DRT) strcat(buffer, "DRC "); - if (xq->var->init.mode & XQ_IN_MO_DTC) strcat(buffer, "DTC "); - if (xq->var->init.mode & XQ_IN_MO_LOP) strcat(buffer, "LOP "); - sim_debug(DBG_SET, xq->dev, "%s: setup> set Mode: %s\n", xq->dev->name, buffer); - - eth_mac_fmt(&xq->var->init.phys, buffer); - sim_debug(DBG_SET, xq->dev, "%s: setup> set Physical MAC Address: %s\n", xq->dev->name, buffer); - - buffer[0] = '\0'; - for (i = 0; i < sizeof(xq->var->init.hash_filter); i++) - sprintf(&buffer[strlen(buffer)], "%02X ", xq->var->init.hash_filter[i]); - sim_debug(DBG_SET, xq->dev, "%s: setup> set Multicast Hash: %s\n", xq->dev->name, buffer); - - buffer[0] = '\0'; - if (xq->var->init.options & XQ_IN_OP_HIT) strcat(buffer, "HIT "); - if (xq->var->init.options & XQ_IN_OP_INT) strcat(buffer, "INT "); - sim_debug(DBG_SET, xq->dev, "%s: setup> set Options: %s\n", xq->dev->name, buffer); - - sim_debug(DBG_SET, xq->dev, "%s: setup> set Vector: %d =0x%X\n", - xq->dev->name, xq->var->init.vector, xq->var->init.vector); - - sim_debug(DBG_SET, xq->dev, "%s: setup> set Host Inactivity Timeout: %d seconds\n", - xq->dev->name, xq->var->init.hit_timeout); - - buffer[0] = '\0'; - for (i = 0; i < sizeof(xq->var->init.bootpassword); i++) - sprintf(&buffer[strlen(buffer)], "%02X ", xq->var->init.bootpassword[i]); - - sim_debug(DBG_SET, xq->dev, "%s: setup> set Boot Password: %s\n", xq->dev->name, buffer); - - sim_debug(DBG_SET, xq->dev, "%s: setup> set Receive Ring Buffer Address: %02X%04X\n", - xq->dev->name, xq->var->init.rdra_h, xq->var->init.rdra_l); - sim_debug(DBG_SET, xq->dev, "%s: setup> set Transmit Ring Buffer Address: %02X%04X\n", - xq->dev->name, xq->var->init.tdra_h, xq->var->init.tdra_l); -} diff --git a/PDP11/pdp11_xq.h b/PDP11/pdp11_xq.h deleted file mode 100644 index b71a725e..00000000 --- a/PDP11/pdp11_xq.h +++ /dev/null @@ -1,406 +0,0 @@ -/* pdp11_xq.h: DEQNA/DELQA ethernet controller information - ------------------------------------------------------------------------------ - - Copyright (c) 2002-2008, David T. Hittner - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of the author shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the author. - - ------------------------------------------------------------------------------ - - Modification history: - - 03-Mar-08 MP Added DELQA-T (aka DELQA Plus) device emulation support. - 06-Feb-08 MP Added dropped frame statistics to record when the receiver discards - received packets due to the receiver being disabled, or due to the - XQ device's packet receive queue being full. Also removed the - filter statistic counter since there was no code which ever set it. - 29-Jan-08 MP Dynamically determine the timer polling rate based on the - calibrated tmr_poll and clk_tps values of the simulator. - 23-Jan-08 MP Added debugging support to display packet headers and packet data - 07-Jul-05 RMS Removed extraneous externs - 20-Jan-04 DTH Added new sanity timer and system id timer - 19-Jan-04 DTH Added XQ_SERVICE_INTERVAL, poll - 09-Jan-04 DTH Added Boot PDP diagnostic definition, XI/RI combination - 26-Dec-03 DTH Moved ethernet queue definitions to sim_ether - 25-Nov-03 DTH Added interrupt request flag - 02-Jun-03 DTH Added struct xq_stats - 28-May-03 DTH Made xq_msg_que.item dynamic - 28-May-03 MP Optimized structures, removed rtime variable - 06-May-03 DTH Changed 32-bit t_addr to uint32 for v3.0 - 28-Apr-03 DTH Added callbacks for multicontroller identification - 25-Mar-03 DTH Removed bootrom field - no longer needed; Updated copyright - 15-Jan-03 DTH Merged Mark Pizzolato's changes into main source - 13-Jan-03 MP Added countdown for System Id multicast packets - 10-Jan-03 DTH Added bootrom field - 30-Dec-02 DTH Added setup valid field - 21-Oct-02 DTH Corrected copyright again - 15-Oct-02 DTH Fixed copyright, added sanity timer support - 10-Oct-02 DTH Added more setup fields and bitmasks - 08-Oct-02 DTH Integrated with 2.10-0p4, added variable vector and copyrights - 03-Oct-02 DTH Beta version of xq/sim_ether released for SIMH 2.09-11 - 15-Aug-02 DTH Started XQ simulation - - ------------------------------------------------------------------------------ -*/ - -#ifndef _PDP11_XQ_H -#define _PDP11_XQ_H - -#if defined (VM_PDP10) /* PDP10 version */ -#error "DEQNA/DELQA not supported on PDP10!" - -#elif defined (VM_VAX) /* VAX version */ -#include "vax_defs.h" -#define XQ_RDX 16 -#define XQ_WID 32 -extern int32 PSL; /* PSL */ -extern int32 fault_PC; /* fault PC */ -extern int32 int_req[IPL_HLVL]; - -#else /* PDP-11 version */ -#include "pdp11_defs.h" -#define XQ_RDX 8 -#define XQ_WID 16 -extern int32 int_req[IPL_HLVL]; -#endif - -#include "sim_ether.h" - -#define XQ_QUE_MAX 500 /* read queue size in packets */ -#define XQ_FILTER_MAX 14 /* number of filters allowed */ -#if defined(SIM_ASYNCH_IO) && defined(USE_READER_THREAD) -#define XQ_SERVICE_INTERVAL 0 /* polling interval - No Polling with Asynch I/O */ -#else -#define XQ_SERVICE_INTERVAL 100 /* polling interval - X per second */ -#endif -#define XQ_SYSTEM_ID_SECS 540 /* seconds before system ID timer expires */ -#define XQ_HW_SANITY_SECS 240 /* seconds before HW sanity timer expires */ -#define XQ_MAX_CONTROLLERS 2 /* maximum controllers allowed */ - -enum xq_type {XQ_T_DEQNA, XQ_T_DELQA, XQ_T_DELQA_PLUS}; - -struct xq_sanity { - int enabled; /* sanity timer enabled? 2=HW, 1=SW, 0=off */ - int quarter_secs; /* sanity timer value in 1/4 seconds */ - int timer; /* countdown timer */ -}; - -struct xq_setup { - int valid; /* is the setup block valid? */ - int promiscuous; /* promiscuous mode enabled */ - int multicast; /* enable all multicast addresses */ - int l1; /* first diagnostic led state */ - int l2; /* second diagnostic led state */ - int l3; /* third diagnostic led state */ - int sanity_timer; /* sanity timer value (encoded) */ - ETH_MAC macs[XQ_FILTER_MAX]; /* MAC addresses to respond to */ -}; - -struct xq_turbo_init_block { /* DELQA-T Initialization Block */ - uint16 mode; -#define XQ_IN_MO_PRO 0x8000 /* Promiscuous Mode */ -#define XQ_IN_MO_INT 0x0040 /* Internal Loopback Mode */ -#define XQ_IN_MO_DRT 0x0020 /* Disable Retry */ -#define XQ_IN_MO_DTC 0x0008 /* Disable Transmit CRC */ -#define XQ_IN_MO_LOP 0x0004 /* Loopback */ - ETH_MAC phys; /* Physical MAC Address */ - ETH_MULTIHASH hash_filter; /* 64bit LANCE Hash Filter for Multicast Address selection */ - uint16 rdra_l; - uint16 rdra_h; - uint16 tdra_l; - uint16 tdra_h; - uint16 options; -#define XQ_IN_OP_HIT 0x0002 /* Host Inactivity Timer Enable Flag */ -#define XQ_IN_OP_INT 0x0001 /* Interrupt Enable Flag*/ - uint16 vector; /* Interrupt Vector */ - uint16 hit_timeout; /* Host Inactivity Timer Timeout Value */ - uint8 bootpassword[6]; /* MOP Console Boot Password */ -}; - -/* DELQA-T Mode - Transmit Buffer Descriptor */ -struct transmit_buffer_descriptor { - uint16 tmd0; -#define XQ_TMD0_ERR1 0x4000 /* Error Summary. The OR of TMD1 (LC0, LCA, and RTR) */ -#define XQ_TMD0_MOR 0x1000 /* More than one retry on transmit */ -#define XQ_TMD0_ONE 0x0800 /* One retry on transmit */ -#define XQ_TMD0_DEF 0x0400 /* Deferral during transmit */ - uint16 tmd1; -#define XQ_TMD1_LCO 0x1000 /* Late collision on transmit - packet not transmitted */ -#define XQ_TMD1_LCA 0x0800 /* Loss of carrier on transmit - packet not transmitted */ -#define XQ_TMD1_RTR 0x0400 /* Retry error on transmit - packet not transmitted */ -#define XQ_TMD1_TDR 0x03FF /* Time Domain Reflectometry value */ - uint16 tmd2; -#define XQ_TMD2_ERR2 0x8000 /* Error Summary. The OR of TMD2 (BBL, CER, and MIS) */ -#define XQ_TMD2_BBL 0x4000 /* Babble error on transmit */ -#define XQ_TMD2_CER 0x2000 /* Collision error on transmit */ -#define XQ_TMD2_MIS 0x1000 /* Packet lost on receive */ -#define XQ_TMD2_EOR 0x0800 /* End Of Receive Ring Reached */ -#define XQ_TMD2_RON 0x0020 /* Receiver On */ -#define XQ_TMD2_TON 0x0010 /* Transmitter On */ - uint16 tmd3; -#define XQ_TMD3_OWN 0x8000 /* Ownership field. 0 = DELQA-T, 1 = Host Driver */ -#define XQ_TMD3_FOT 0x4000 /* First Of Two flag. 1 = first in chained, 0 = no chain or last in chain */ -#define XQ_TMD3_BCT 0x0FFF /* Byte Count */ - uint16 ladr; /* Low 16bits of Buffer Address */ - uint16 hadr; /* Most significant bits of the Buffer Address */ - uint16 hostuse1; - uint16 hostuse2; -}; -#define XQ_TURBO_XM_BCNT 12 /* Transmit Buffer Descriptor Count */ - -struct receive_buffer_descriptor { - uint16 rmd0; -#define XQ_RMD0_ERR3 0x4000 /* Error Summary. The OR of FRA, CRC, OFL and BUF */ -#define XQ_RMD0_FRA 0x2000 /* Framing error on receive */ -#define XQ_RMD0_OFL 0x1000 /* Overflow error on receive (Giant packet) */ -#define XQ_RMD0_CRC 0x0800 /* CRC error on receive */ -#define XQ_RMD0_BUF 0x0400 /* Internal device buffer error. Part of Giant packet lost */ -#define XQ_RMD0_STP 0x0200 /* Start of Packet Flag */ -#define XQ_RMD0_ENP 0x0100 /* End of Packet Flag */ - uint16 rmd1; -#define XQ_RMD1_MCNT 0x0FFF /* Message byte count (including CRC) */ - uint16 rmd2; -#define XQ_RMD2_ERR4 0x8000 /* Error Summary. The OR of RMD2 (RBL, CER, and MIS) */ -#define XQ_RMD2_BBL 0x4000 /* Babble error on transmit */ -#define XQ_RMD2_CER 0x2000 /* Collision error on transmit */ -#define XQ_RMD2_MIS 0x1000 /* Packet lost on receive */ -#define XQ_RMD2_EOR 0x0800 /* End Of Receive Ring Reached */ -#define XQ_RMD2_RON 0x0020 /* Receiver On */ -#define XQ_RMD2_TON 0x0010 /* Transmitter On */ - uint16 rmd3; -#define XQ_RMD3_OWN 0x8000 /* Ownership field. 0 = DELQA-T, 1 = Host Driver */ - uint16 ladr; /* Low 16bits of Buffer Address */ - uint16 hadr; /* Most significant bits of the Buffer Address */ - uint16 hostuse1; - uint16 hostuse2; -}; -#define XQ_TURBO_RC_BCNT 32 /* Receive Buffer Descriptor Count */ - -struct xq_stats { - int recv; /* received packets */ - int dropped; /* received packets dropped */ - int xmit; /* transmitted packets */ - int fail; /* transmit failed */ - int runt; /* runts */ - int reset; /* reset count */ - int giant; /* oversize packets */ - int setup; /* setup packets */ - int loop; /* loopback packets */ -}; - -#pragma pack(2) -struct xq_mop_counters { - uint16 seconds; /* Seconds since last zeroed */ - uint32 b_rcvd; /* Bytes Received */ - uint32 b_xmit; /* Bytes Transmitted */ - uint32 p_rcvd; /* Packets Received */ - uint32 p_xmit; /* Packets Transmitted */ - uint32 mb_rcvd; /* Multicast Bytes Received */ - uint32 mp_rcvd; /* Multicast Packets Received */ - uint32 p_x_col1; /* Packets Transmitted Initially Deferred */ - uint32 p_x_col2; /* Packets Transmitted after 2 attempts */ - uint32 p_x_col3; /* Packets Transmitted after 3+ attempts */ - uint16 p_x_fail; /* Transmit Packets Aborted (Send Failure) */ - uint16 p_x_f_bitmap; /* Transmit Packets Aborted (Send Failure) Bitmap */ -#define XQ_XF_RTRY 0x0001 /* Excessive Collisions */ -#define XQ_XF_LCAR 0x0002 /* Loss of Carrier */ -#define XQ_XF_MLEN 0x0010 /* Data Block Too Long */ -#define XQ_XF_LCOL 0x0020 /* Late Collision */ - uint16 p_r_fail; /* Packets received with Error (Receive Failure) */ - uint16 p_r_f_bitmap; /* Packets received with Error (Receive Failure) Bitmap */ -#define XQ_RF_CRC 0x0001 /* Block Check Error */ -#define XQ_RF_FRAM 0x0002 /* Framing Error */ -#define XQ_RF_MLEN 0x0004 /* Message Length Error */ - uint16 h_dest_err; /* Host Counter - Unrecognized Frame Destination Error */ - uint16 r_p_lost_i; /* Receive Packet Lost: Internal Buffer Error */ - uint16 r_p_lost_s; /* Receive Packet Lost: System Buffer Error (Unavailable or Truncated) */ - uint16 h_no_buf; /* Host Counter - User Buffer Unavailable */ - uint32 mb_xmit; /* Multicast Bytes Tramsmitted */ - uint16 reserved1; /* */ - uint16 reserved2; /* */ - uint16 babble; /* Babble Counter */ -}; -#pragma pack() - -struct xq_meb { /* MEB block */ - uint8 type; - uint8 add_lo; - uint8 add_mi; - uint8 add_hi; - uint8 siz_lo; - uint8 siz_hi; -}; - -struct xq_device { - /*+ initialized values - DO NOT MOVE */ - ETH_PCALLBACK rcallback; /* read callback routine */ - ETH_PCALLBACK wcallback; /* write callback routine */ - ETH_MAC mac; /* Hardware MAC address */ - enum xq_type type; /* controller type */ - enum xq_type mode; /* controller operating mode */ - uint16 poll; /* configured poll ethernet times/sec for receive */ - uint16 coalesce_latency; /* microseconds to hold-off interrupts when not polling */ - uint16 coalesce_latency_ticks; /* instructions in coalesce_latency microseconds */ - struct xq_sanity sanity; /* sanity timer information */ - /*- initialized values - DO NOT MOVE */ - - /* I/O register storage */ - - uint16 rbdl[2]; - uint16 xbdl[2]; - uint16 var; - uint16 csr; - - uint16 srr; /* Status and Response Register - DELQA-T only */ - uint16 srqr; /* Synchronous Request Register - DELQA-T only */ - uint32 iba; /* Init Block Address Register - DELQA-T only */ - uint16 icr; /* Interrupt Request Register - DELQA-T only */ - uint16 pending_interrupt; /* Pending Interrupt - DELQA-T only */ - struct xq_turbo_init_block - init; - struct transmit_buffer_descriptor - xring[XQ_TURBO_XM_BCNT]; /* Transmit Buffer Ring */ - uint32 tbindx; /* Transmit Buffer Ring Index */ - struct receive_buffer_descriptor - rring[XQ_TURBO_RC_BCNT]; /* Receive Buffer Ring */ - uint32 rbindx; /* Receive Buffer Ring Index */ - - uint32 irq; /* interrupt request flag */ - - /* buffers, etc. */ - struct xq_setup setup; - struct xq_stats stats; - uint8 mac_checksum[2]; - uint16 rbdl_buf[6]; - uint16 xbdl_buf[6]; - uint32 rbdl_ba; - uint32 xbdl_ba; - ETH_DEV* etherface; - ETH_PACK read_buffer; - ETH_PACK write_buffer; - ETH_QUE ReadQ; - int32 idtmr; /* countdown for ID Timer */ - uint32 must_poll; /* receiver must poll instead of counting on asynch polls */ -}; - -struct xq_controller { - DEVICE* dev; /* device block */ - UNIT* unit; /* unit block */ - DIB* dib; /* device interface block */ - struct xq_device* var; /* controller-specific variables */ -}; - -typedef struct xq_controller CTLR; - - -#define XQ_CSR_RI 0x8000 /* Receive Interrupt Request (RI) [RO/W1] */ -#define XQ_CSR_PE 0x4000 /* Parity Error in Host Memory (PE) [RO] */ -#define XQ_CSR_CA 0x2000 /* Carrier from Receiver Enabled (CA) [RO] */ -#define XQ_CSR_OK 0x1000 /* Ethernet Transceiver Power (OK) [RO] */ -#define XQ_CSR_RR 0x0800 /* Reserved : Set to Zero (RR) [RO] */ -#define XQ_CSR_SE 0x0400 /* Sanity Timer Enable (SE) [RW] */ -#define XQ_CSR_EL 0x0200 /* External Loopback (EL) [RW] */ -#define XQ_CSR_IL 0x0100 /* Internal Loopback (IL) [RW] */ -#define XQ_CSR_XI 0x0080 /* Transmit Interrupt Request (XI) [RO/W1] */ -#define XQ_CSR_IE 0x0040 /* Interrupt Enable (IE) [RW] */ -#define XQ_CSR_RL 0x0020 /* Receive List Invalid/Empty (RL) [RO] */ -#define XQ_CSR_XL 0x0010 /* Transmit List Invalid/Empty (XL) [RO] */ -#define XQ_CSR_BD 0x0008 /* Boot/Diagnostic ROM Load (BD) [RW] */ -#define XQ_CSR_NI 0x0004 /* NonExistant Memory Timeout (NXM) [RO] */ -#define XQ_CSR_SR 0x0002 /* Software Reset (SR) [RW] */ -#define XQ_CSR_RE 0x0001 /* Receiver Enable (RE) [RW] */ - -/* special access bitmaps */ -#define XQ_CSR_RO 0xF8B4 /* Read-Only bits */ -#define XQ_CSR_RW 0x074B /* Read/Write bits */ -#define XQ_CSR_W1 0x8080 /* Write-one-to-clear bits */ -#define XQ_CSR_BP 0x0208 /* Boot PDP diagnostic ROM */ -#define XQ_CSR_XIRI 0X8080 /* Transmit & Receive Interrupts */ - -#define XQ_VEC_MS 0x8000 /* Mode Select (MO) [RW] */ -#define XQ_VEC_OS 0x4000 /* Option Switch Setting (OS) [RO] */ -#define XQ_VEC_RS 0x2000 /* Request Self-Test (RS) [RW] */ -#define XQ_VEC_S3 0x1000 /* Self-Test Status (S3) [RO] */ -#define XQ_VEC_S2 0x0800 /* Self-Test Status (S2) [RO] */ -#define XQ_VEC_S1 0x0400 /* Self-Test Status (S1) [RO] */ -#define XQ_VEC_ST 0x1C00 /* Self-Test (S1 + S2 + S3) [RO] */ -#define XQ_VEC_IV 0x03FC /* Interrupt Vector (IV) [RW] */ -#define XQ_VEC_RR 0x0002 /* Reserved (RR) [RO] */ -#define XQ_VEC_ID 0x0001 /* Identity Test Bit (ID) [RW] */ - -/* special access bitmaps */ -#define XQ_VEC_RO 0x5C02 /* Read-Only bits */ -#define XQ_VEC_RW 0xA3FD /* Read/Write bits */ - -/* DEQNA - DELQA Normal Mode Buffer Descriptors */ -#define XQ_DSC_V 0x8000 /* Valid bit */ -#define XQ_DSC_C 0x4000 /* Chain bit */ -#define XQ_DSC_E 0x2000 /* End of Message bit [Transmit only] */ -#define XQ_DSC_S 0x1000 /* Setup bit [Transmit only] */ -#define XQ_DSC_L 0x0080 /* Low Byte Termination bit [Transmit only] */ -#define XQ_DSC_H 0x0040 /* High Byte Start bit [Transmit only] */ - -/* DEQNA - DELQA Normal Mode Setup Packet Flags */ -#define XQ_SETUP_MC 0x0001 /* multicast bit */ -#define XQ_SETUP_PM 0x0002 /* promiscuous bit */ -#define XQ_SETUP_LD 0x000C /* led bits */ -#define XQ_SETUP_ST 0x0070 /* sanity timer bits */ - -/* DELQA-T Mode - Status and Response Register (SRR) */ -#define XQ_SRR_FES 0x8000 /* Fatal Error Summary [RO] */ -#define XQ_SRR_CHN 0x4000 /* Chaining Error [RO] */ -#define XQ_SRR_NXM 0x1000 /* Non-Existant Memory Error [RO] */ -#define XQ_SRR_PAR 0x0800 /* Parity Error (Qbus) [RO] */ -#define XQ_SRR_IME 0x0400 /* Internal Memory Error [RO] */ -#define XQ_SRR_TBL 0x0200 /* Transmit Buffer Too Long Error [RO] */ -#define XQ_SRR_RESP 0x0003 /* Synchronous Response Field [RO] */ -#define XQ_SRR_TRBO 0x0001 /* Select Turbo Response [RO] */ -#define XQ_SRR_STRT 0x0002 /* Start Device Response [RO] */ -#define XQ_SRR_STOP 0x0003 /* Stop Device Response [RO] */ - -/* DELQA-T Mode - Synchronous Request Register (SRQR) */ -#define XQ_SRQR_STRT 0x0002 /* Start Device Request [WO] */ -#define XQ_SRQR_STOP 0x0003 /* Stop Device Request [WO] */ -#define XQ_SRQR_RW 0x0003 /* Writable Bits in SRQR [WO] */ - -/* DELQA-T Mode - Asynchronous Request Register (ARQR) */ -#define XQ_ARQR_TRQ 0x8000 /* Transmit Request [WO] */ -#define XQ_ARQR_RRQ 0x0080 /* Receieve Request [WO] */ -#define XQ_ARQR_SR 0x0002 /* Software Reset Request [WO] */ - -/* DELQA-T Mode - Interrupt Control Register (ICR) */ -#define XQ_ICR_ENA 0x0001 /* Interrupt Enabled [WO] */ - - -/* debugging bitmaps */ -#define DBG_TRC 0x0001 /* trace routine calls */ -#define DBG_REG 0x0002 /* trace read/write registers */ -#define DBG_CSR 0x0004 /* watch CSR */ -#define DBG_VAR 0x0008 /* watch VAR */ -#define DBG_WRN 0x0010 /* display warnings */ -#define DBG_SAN 0x0020 /* display sanity timer info */ -#define DBG_SET 0x0040 /* display setup info */ -#define DBG_PCK 0x0080 /* display packet headers */ -#define DBG_DAT 0x0100 /* display packet data */ -#define DBG_ETH 0x8000 /* debug ethernet device */ - -#endif /* _PDP11_XQ_H */ diff --git a/PDP11/pdp11_xq_bootrom.h b/PDP11/pdp11_xq_bootrom.h deleted file mode 100644 index 125b6c32..00000000 --- a/PDP11/pdp11_xq_bootrom.h +++ /dev/null @@ -1,312 +0,0 @@ -/* pdp11_xq_bootrom.h: DEQNA/DELQA bootrom data - ------------------------------------------------------------------------------ - - Copyright (c) 2003-2008, David T. Hittner - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of the author shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the author. - - ------------------------------------------------------------------------------ - - Modification history: - - 26-Mar-03 DTH Removed 'static' declaration - 23-Mar-03 DTH Created by extracting from merged DEQNA bootrom dumps - - ------------------------------------------------------------------------------ -*/ - -#ifndef _PDP11_XQ_BOOTROM_H -#define _PDP11_XQ_BOOTROM_H - -#ifdef VM_PDP11 - /* - Bootrom code is from merged file 23-334e5.bin, offset 050000, for 4096. bytes. - - Word 0: NOP - Word 1: Branch to extended primary boot - Word 2: Branch/Vector to Citizenship tests - Word 3: Offset from beginning to checksum word - - See INIQNA.MAR for further information on format and contents. - */ - - uint16 xq_bootrom[] = { - 0000240,0000423,0000546,0007776,0000520,0000000,0100000,0100000, - 0002000,0176000,0000000,0000000,0100000,0100000,0006000,0176000, - 0000000,0000000,0100000,0020000,0140000,0012706,0001776,0010046, - 0012761,0000014,0000004,0005061,0000006,0012761,0001010,0000016, - 0005000,0005300,0001376,0005061,0000016,0005000,0005300,0001376, - 0012761,0000002,0000016,0005061,0000016,0042767,0037777,0177664, - 0026767,0177660,0177702,0001057,0042767,0037777,0177652,0026767, - 0177646,0177664,0001050,0042767,0037777,0177650,0026767,0177644, - 0177646,0001041,0012704,0007776,0005003,0005002,0116200,0002000, - 0005202,0042700,0177400,0060003,0005304,0001370,0013700,0000006, - 0026003,0002000,0001020,0000137,0002010,0012702,0012000,0004767, - 0000040,0005700,0001010,0011602,0001002,0000167,0004530,0022702, - 0000777,0103001,0000112,0013703,0000012,0001401,0000113,0000000, - 0000776,0010637,0000764,0062701,0000016,0032761,0100000,0177776, - 0001421,0052761,0020000,0177776,0012703,0000777,0005000,0005300, - 0001376,0032761,0016000,0177776,0001405,0005303,0001370,0012700, - 0000200,0000454,0004767,0000136,0052711,0000002,0042711,0000002, - 0012703,0017777,0005303,0001376,0004567,0003514,0177700,0001014, - 0005712,0001014,0032762,0002000,0000050,0001402,0052711,0002000, - 0004567,0003464,0177622,0001402,0052712,0000100,0012711,0000002, - 0005011,0012703,0017777,0005303,0001376,0011100,0042700,0064000, - 0022700,0010060,0001402,0052712,0000100,0011200,0162701,0000016, - 0000207,0052400,0177652,0013746,0000034,0013746,0000036,0010703, - 0062703,0000210,0010337,0000034,0012737,0000340,0000036,0104400, - 0012637,0000036,0012637,0000034,0013700,0000762,0052700,0000340, - 0062703,0000010,0010337,0000004,0010037,0000006,0010637,0000766, - 0010137,0000772,0010237,0000770,0062703,0000012,0010337,0000024, - 0010037,0000026,0062703,0000022,0012761,0000774,0177776,0052761, - 0100000,0177776,0010337,0000774,0010037,0000776,0005062,0000002, - 0005012,0012700,0000162,0060200,0012704,0000112,0005020,0005304, - 0001375,0004567,0003202,0177666,0001434,0005262,0000002,0022762, - 0000002,0000002,0003355,0000207,0016637,0000002,0000762,0000006, - 0052712,0002000,0013706,0000764,0000207,0052712,0020000,0013706, - 0000766,0013701,0000772,0013702,0000770,0000207,0052712,0004000, - 0000002,0106427,0000000,0010103,0162703,0000016,0010204,0062704, - 0000012,0012705,0000006,0012300,0110024,0005305,0001374,0010204, - 0062704,0000012,0010405,0005724,0001004,0005724,0001002,0005714, - 0001421,0010504,0012700,0177777,0020024,0001016,0020024,0001014, - 0020014,0001410,0001011,0010504,0022724,0000252,0001003,0122714, - 0000004,0103002,0052712,0000001,0012700,0177777,0004767,0003314, - 0013705,0000774,0010703,0062703,0000044,0010337,0000774,0052711, - 0000100,0010461,0177772,0005000,0010061,0177774,0012703,0010000, - 0005303,0001376,0052712,0004000,0000207,0062706,0000004,0010537, - 0000774,0005200,0001767,0011100,0032700,0000200,0001763,0011400, - 0042700,0037777,0022700,0140000,0001355,0005764,0000010,0001752, - 0005764,0000012,0001747,0052711,0000002,0042711,0000002,0012711, - 0002000,0106437,0000762,0004567,0002576,0177666,0001402,0000207, - 0010703,0062703,0177160,0010362,0000002,0010362,0000006,0062703, - 0000005,0010362,0000004,0005062,0000010,0010203,0062703,0000162, - 0012700,0000002,0012705,0000006,0105023,0012704,0000007,0026262, - 0000004,0000006,0003003,0016262,0000002,0000006,0117223,0000006, - 0005262,0000006,0005304,0001363,0005305,0001356,0012704,0000020, - 0105023,0005304,0001375,0005300,0001345,0004567,0002432,0177705, - 0001403,0052712,0000002,0000207,0005262,0000010,0022762,0000764, - 0000010,0003323,0042761,0100000,0177776,0005062,0000006,0010204, - 0062704,0000163,0010462,0000010,0005304,0012703,0000060,0105024, - 0005303,0001375,0062762,0000010,0000002,0016262,0000010,0000002, - 0012762,0000060,0000004,0105062,0000012,0000261,0106162,0000012, - 0103041,0106162,0000012,0062762,0000010,0000002,0000433,0016204, - 0000010,0005304,0012703,0000060,0112724,0000377,0005303,0001374, - 0012762,0000060,0000004,0016262,0000010,0000002,0112762,0000377, - 0000012,0000241,0106162,0000012,0103405,0106162,0000012,0062762, - 0000010,0000002,0016204,0000002,0012703,0000007,0105064,0177770, - 0116224,0000012,0005303,0001372,0004567,0002154,0177750,0001402, - 0000167,0000414,0005762,0000006,0001011,0000241,0106172,0000002, - 0103010,0106072,0000002,0106072,0000002,0000403,0000261,0106172, - 0000002,0016204,0000010,0010203,0062703,0004362,0012700,0000006, - 0111423,0062704,0000010,0005300,0001373,0012711,0000001,0012700, - 0177775,0004767,0002352,0010461,0177766,0005061,0177770,0004767, - 0002372,0010461,0177772,0005061,0177774,0012700,0077777,0032711, - 0100000,0001003,0005300,0001373,0000523,0005000,0004567,0002412, - 0000000,0040000,0001115,0016204,0000010,0005204,0010203,0062703, - 0004362,0012700,0000006,0111423,0062704,0000010,0005300,0001373, - 0042711,0100200,0012700,0177775,0004767,0002224,0010461,0177766, - 0005061,0177770,0012700,0177775,0004767,0002240,0010461,0177772, - 0005061,0177774,0012700,0077777,0032711,0100000,0001003,0005300, - 0001373,0000454,0005000,0004567,0002260,0000000,0000000,0001040, - 0042711,0000001,0010204,0062704,0001362,0010205,0062705,0004362, - 0012700,0000006,0122425,0001024,0005300,0001374,0005362,0000004, - 0001007,0005762,0000006,0001034,0005262,0000006,0000167,0177256, - 0005762,0000006,0001002,0000167,0177222,0000261,0000167,0177304, - 0052712,0000004,0000405,0052712,0004000,0000402,0052712,0001004, - 0052761,0100000,0177776,0000207,0000074,0001422,0002752,0177777, - 0052761,0100000,0177776,0052711,0001000,0010703,0062703,0176046, - 0010362,0000002,0010362,0000006,0062703,0000004,0010362,0000004, - 0010703,0062703,0177726,0010362,0000010,0010203,0062703,0004362, - 0017205,0000010,0026262,0000004,0000006,0003003,0016262,0000002, - 0000006,0117223,0000006,0005262,0000006,0005305,0001363,0017200, - 0000010,0004567,0001536,0103425,0017200,0000010,0004567,0001752, - 0000000,0020000,0001401,0000003,0010204,0062704,0001362,0010205, - 0062705,0004362,0017200,0000010,0122425,0001003,0005300,0001374, - 0000403,0052712,0000010,0000207,0062762,0000002,0000010,0022772, - 0177777,0000010,0001402,0000167,0177620,0012700,0177770,0004767, - 0001536,0010461,0177766,0005061,0177770,0010203,0062703,0000040, - 0010304,0012700,0000010,0012723,0100000,0012723,0100000,0010213, - 0062723,0000012,0012723,0177777,0005023,0005023,0005300,0001363, - 0010403,0052763,0000200,0000002,0052763,0000300,0000016,0012763, - 0177776,0000022,0052763,0000100,0000032,0062763,0000002,0000034, - 0062763,0000004,0000050,0012763,0040000,0000062,0010363,0000064, - 0062763,0000074,0000064,0010363,0000100,0062763,0000070,0000100, - 0012763,0177776,0000102,0012763,0120000,0000112,0012763,0177775, - 0000116,0012763,0020000,0000126,0010461,0177772,0005061,0177774, - 0012700,0077777,0032711,0100000,0001005,0005300,0001373,0052712, - 0001000,0000411,0012700,0000020,0004567,0001376,0100000,0020000, - 0001405,0052712,0040000,0052712,0000020,0000207,0010203,0062703, - 0000040,0012700,0000010,0016305,0000000,0042705,0037777,0022705, - 0140000,0001357,0022700,0000004,0001403,0022700,0000001,0001007, - 0005763,0000010,0001346,0005763,0000012,0001343,0000424,0022700, - 0000002,0001405,0032763,0100000,0000010,0001733,0000414,0016305, - 0000010,0042705,0026417,0022705,0000000,0001323,0016305,0000012, - 0042705,0176000,0001716,0062703,0000014,0005300,0001324,0010203, - 0062703,0000012,0010204,0062704,0001362,0010405,0022324,0001303, - 0022324,0001301,0022324,0001277,0005724,0001275,0005724,0001273, - 0022524,0001271,0022524,0001267,0022524,0001265,0010203,0062703, - 0000162,0010305,0012700,0000113,0005023,0005300,0001375,0010204, - 0062704,0000012,0004767,0000046,0062705,0000020,0004767,0000036, - 0004567,0000444,0177674,0001401,0000207,0012700,0177777,0032711, - 0020000,0001423,0005300,0001373,0052712,0100000,0000207,0010446, - 0012700,0000006,0005205,0012703,0000007,0111425,0005303,0001375, - 0005204,0005300,0001367,0012604,0000207,0005712,0001017,0052711, - 0001400,0012700,0000056,0004767,0000132,0012700,0000074,0004567, - 0000522,0103005,0042712,0001000,0052712,0100000,0000207,0012700, - 0000074,0004767,0000156,0001761,0001403,0052712,0000040,0000207, - 0012700,0000074,0004767,0000232,0001370,0012700,0002734,0004767, - 0000042,0012700,0002752,0004567,0000432,0103757,0012700,0002752, - 0004767,0000100,0001766,0001351,0012700,0002752,0004767,0000162, - 0001344,0000207,0010203,0062703,0004362,0010204,0062704,0000012, - 0010405,0012423,0012423,0012423,0012523,0012523,0012523,0012723, - 0000220,0005023,0012723,0000001,0110023,0005300,0001375,0005062, - 0000002,0000207,0004567,0000542,0000000,0020000,0001004,0062716, - 0000002,0005712,0000207,0016200,0000050,0042700,0137777,0001010, - 0016200,0000030,0032700,0137777,0001003,0042712,0040000,0000757, - 0005262,0000002,0022762,0000144,0000002,0003751,0042712,0040000, - 0000750,0010204,0062704,0001362,0010205,0062705,0004362,0122425, - 0001002,0005300,0001374,0000207,0010200,0062700,0000162,0010046, - 0011500,0005300,0004767,0000270,0010461,0177766,0005061,0177770, - 0012500,0004767,0000306,0012764,0130000,0000002,0011664,0000004, - 0010461,0177772,0005061,0177774,0012704,0017777,0032711,0100000, - 0001010,0005304,0001373,0052712,0001000,0005726,0052712,0010000, - 0000430,0016500,0177776,0006300,0005400,0004567,0000274,0000000, - 0020000,0001363,0016500,0177776,0006300,0005400,0010204,0062704, - 0001362,0012603,0122423,0001352,0005300,0001374,0022714,0051343, - 0001345,0000205,0005046,0006000,0005516,0061600,0005400,0004767, - 0000076,0010461,0177766,0005061,0177770,0004767,0000116,0005726, - 0001403,0052764,0000200,0000002,0010461,0177772,0005061,0177774, - 0012703,0000777,0005000,0032711,0100000,0001010,0005300,0001376, - 0005303,0001371,0052712,0001000,0000261,0000401,0000241,0000205, - 0010203,0062703,0001362,0012704,0000200,0012723,0051343,0005304, - 0001374,0004567,0000020,0000020,0001362,0000207,0004567,0000006, - 0000040,0004362,0000207,0012503,0060203,0010304,0012723,0100000, - 0012723,0120000,0012513,0060223,0010023,0012723,0100000,0012723, - 0100000,0012723,0100000,0005023,0000205,0010046,0005000,0011104, - 0052711,0100200,0042704,0077401,0022704,0100260,0001401,0010700, - 0016204,0000040,0042704,0037777,0022704,0140000,0001401,0010700, - 0016204,0000050,0100002,0042704,0077777,0042704,0076417,0022504, - 0001401,0010700,0016204,0000052,0042704,0176000,0001001,0010700, - 0016204,0000020,0042704,0037777,0022704,0140000,0001401,0010700, - 0016204,0000030,0010446,0042704,0007777,0022504,0001401,0010700, - 0012604,0042704,0174377,0022762,0177775,0000046,0001002,0005726, - 0000415,0032762,0010000,0000042,0001401,0005004,0016203,0000032, - 0042703,0177400,0060304,0022604,0001401,0010700,0010003,0001402, - 0052712,0040000,0000205,0000005,0012706,0017776,0010616,0011646, - 0162716,0003056,0010703,0062703,0000014,0010337,0000004,0011100, - 0000401,0000000,0004767,0000230,0011605,0012725,0022410,0012725, - 0000401,0105025,0105025,0012725,0000621,0112725,0000002,0012702, - 0002752,0110225,0000302,0110225,0012702,0000013,0005000,0004767, - 0000452,0001350,0012702,0002756,0004767,0000660,0001046,0011603, - 0112304,0005302,0120427,0000002,0001404,0105704,0001335,0162702, - 0000004,0105713,0001402,0121300,0001030,0112300,0105200,0005302, - 0003410,0012305,0005723,0162702,0000004,0003403,0112325,0005302, - 0003375,0105704,0001417,0005003,0011605,0112725,0000012,0110025, - 0110325,0005005,0012702,0000003,0000722,0105700,0001673,0012703, - 0000001,0000762,0004767,0001232,0112346,0112366,0000001,0000207, - 0042761,0000002,0000016,0016605,0000002,0010504,0062704,0177720, - 0010466,0000004,0012702,0000020,0005024,0077202,0010504,0062704, - 0177760,0005065,0177722,0010465,0177724,0005065,0177742,0010465, - 0177744,0052765,0100000,0177722,0012702,0002756,0006202,0005402, - 0010265,0177726,0052765,0120000,0177742,0016604,0000004,0010467, - 0001324,0005067,0001322,0062704,0000020,0010467,0001314,0005067, - 0001312,0116167,0000000,0001262,0116167,0000002,0001255,0116167, - 0000004,0001250,0116167,0000006,0001243,0116167,0000010,0001236, - 0116167,0000012,0001231,0105267,0001232,0042761,0000002,0000016, - 0052761,0000400,0000016,0004767,0001104,0005065,0000002,0016744, - 0001174,0016744,0001166,0016744,0001160,0012744,0000000,0012744, - 0001000,0012744,0000253,0004767,0000046,0000207,0016605,0000002, - 0010504,0010244,0012744,0000540,0016744,0001122,0016744,0001114, - 0016744,0001106,0016744,0001060,0016744,0001052,0016744,0001044, - 0062705,0177740,0062702,0000016,0020227,0000074,0002003,0012702, - 0000074,0000407,0032702,0000001,0001404,0052765,0000200,0000002, - 0005202,0006202,0005402,0010265,0000006,0005065,0000010,0005065, - 0000012,0016761,0001024,0000010,0016761,0001020,0000012,0012704, - 0000204,0004767,0000610,0103012,0001404,0032765,0001000,0000010, - 0001354,0042765,0000200,0000002,0000244,0000207,0042765,0000200, - 0000002,0032702,0040004,0001401,0000000,0000207,0016605,0000002, - 0062705,0177720,0005065,0000010,0005065,0000012,0016761,0000706, - 0000004,0016761,0000702,0000006,0052761,0000001,0000016,0012704, - 0100004,0004767,0000470,0103030,0001355,0052761,0000002,0000016, - 0012767,0000253,0000576,0012767,0000400,0000572,0012767,0000000, - 0000566,0105267,0000616,0005000,0042761,0000002,0000016,0052761, - 0000400,0000016,0000244,0000207,0042761,0000001,0000016,0052761, - 0000002,0000016,0016605,0000002,0016502,0177776,0042761,0000002, - 0000016,0052761,0000400,0000016,0022765,0000540,0177774,0001041, - 0105767,0000520,0001015,0026765,0000456,0177772,0001267,0026765, - 0000444,0177770,0001263,0026765,0000432,0177766,0001257,0000207, - 0122715,0000003,0001253,0016567,0177766,0000410,0016567,0177770, - 0000404,0016567,0177772,0000400,0105067,0000430,0000244,0005000, - 0000207,0022765,0000220,0177774,0001423,0022765,0001140,0177774, - 0001225,0122715,0000005,0001222,0004767,0000262,0016464,0177776, - 0177770,0016464,0177774,0177766,0016464,0177772,0177764,0000437, - 0010504,0060204,0010503,0062703,0177720,0016302,0000010,0042702, - 0174377,0156302,0000012,0062702,0000056,0022724,0000002,0001027, - 0062765,0000010,0177776,0032714,0000001,0001021,0010503,0062703, - 0177760,0012423,0012423,0012423,0010504,0062704,0177774,0016744, - 0000234,0016744,0000226,0016744,0000220,0004767,0177122,0000167, - 0177272,0016737,0000156,0000030,0016737,0000152,0000032,0016737, - 0000146,0000034,0052761,0000002,0000016,0000264,0000207,0012703, - 0037777,0000241,0012702,0000220,0030461,0000016,0001006,0005303, - 0001376,0005302,0001371,0000261,0000207,0016102,0000016,0010261, - 0000016,0032765,0040000,0000010,0001401,0000261,0000207,0010546, - 0010703,0062703,0000050,0012702,0000030,0012325,0005725,0112325, - 0005302,0001375,0012605,0010504,0012702,0000034,0010244,0012744, - 0001140,0000207,0000253,0000400,0000000,0000007,0000001,0001403, - 0000000,0000002,0000402,0003400,0003000,0000000,0000000,0000000, - 0000144,0022401,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0000000, - 0000000,0000000,0000000,0000000,0000000,0000000,0000000,0102206 - }; -#endif /* VM_PDP11 */ - -#endif /* _PDP11_XQ_BOOTROM_H */ diff --git a/PDP11/pdp11_xu.c b/PDP11/pdp11_xu.c deleted file mode 100644 index f748bcc8..00000000 --- a/PDP11/pdp11_xu.c +++ /dev/null @@ -1,1706 +0,0 @@ -/* pdp11_xu.c: DEUNA/DELUA ethernet controller simulator - ------------------------------------------------------------------------------ - - Copyright (c) 2003-2018, David T. Hittner - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of the author shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the author. - - ------------------------------------------------------------------------------ - - This DEUNA/DELUA simulation is based on: - Digital DELUA Users Guide, Part# EK-DELUA-UG-002 - Digital DEUNA Users Guide, Part# EK-DEUNA-UG-001 - These manuals can be found online at: - http://www.bitsavers.org/pdf/dec/unibus - - Testing performed: - 1) Receives/Transmits single packet under custom RSX driver - 2) Passes RSTS 10.1 controller probe diagnostics during boot - 3) VMS 7.2 on VAX780 summary: - (May/2007: WinXP x64 host; MS VC++ 2005; SIMH v3.7-0 base; WinPcap 4.0) - LAT - SET HOST/LAT in/out - DECNET - SET HOST in/out, COPY in/out - TCP/IP - PING in/out; SET HOST/TELNET in/out, COPY/FTP in/out - Clustering - Successfully clustered with AlphaVMS 8.2 - 4) VMS 4.7 on VAX780 summary: - (Jan/2011: Win7 x64 host; MS VC++ 2008; SIMH v3.8-2 rc1 base; WinPcap 4.1) - LAT - SET HOST/LAT in (no outbound exists) - DECNET - SET HOST in/out, DIR in/out, COPY in/out - TCP/IP - no kit available to test - Clustering - not tested - 5) Runs VAX EVDWA diagnostic tests 1-10; tests 11-19 (M68000/ROM/RAM) fail - - Known issues: - 1) Most auxiliary commands are not implemented yet. - 2) System_ID broadcast is not implemented. - 3) There are residual Map_ReadB and Map_WriteB from the FvK version that - probably need to be converted to Map_ReadW and Map_WriteW calls. - 4) Some jerkiness seen during interactive I/O with remote systems; - this is probably attributable to changed polling times from when - the poll duration was standardized for idling support. - - ------------------------------------------------------------------------------ - - Modification history: - - 28-May-18 RMS Changed to avoid nested comment warnings (Mark Pizzolato) - 12-Jan-11 DTH Added SHOW XU FILTERS modifier - 11-Jan-11 DTH Corrected SELFTEST command, enabling use by VMS 3.7, VMS 4.7, and Ultrix 1.1 - 09-Dec-10 MP Added address conflict check during attach. - 06-Dec-10 MP Added loopback processing support - 30-Nov-10 MP Fixed the fact that no broadcast packets were received by the DEUNA - 15-Aug-08 MP Fixed transmitted packets to have the correct source MAC address. - Fixed incorrect address filter setting calling eth_filter(). - 23-Jan-08 MP Added debugging support to display packet headers and packet data - 18-Jun-07 RMS Added UNIT_IDLE flag - 03-May-07 DTH Added missing FC_RMAL command; cleared multicast on write - 29-Oct-06 RMS Synced poll and clock - 08-Dec-05 DTH Implemented ancilliary functions 022/023/024/025 - 18-Nov-05 DTH Corrected time between system ID packets - 07-Sep-05 DTH Corrected runt packet processing (found by Tim Chapman), - Removed unused variable - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 10-Mar-05 RMS Fixed equality test in RCSTAT (from Mark Hittinger) - 16-Jan-04 DTH Added more info to SHOW MOD commands - 09-Jan-04 DTH Made XU floating address so that XUB will float correctly - 08-Jan-04 DTH Added system_id message - 06-Jan-04 DTH Added protection against changing mac and type if attached - 05-Jan-04 DTH Moved most of xu_setmac to sim_ether - Implemented auxiliary function 12/13 - Added SET/SHOW XU STATS - 31-Dec-03 DTH RSTS 10.1 accepts controller during boot tests - Implemented chained buffers in transmit/receive processing - 29-Dec-03 DTH Primitive RSX packet sending succeeds - 23-Dec-03 DTH Implemented write function - 17-Dec-03 DTH Implemented read function - 05-May-03 DTH Started XU simulation - - core logic pirated from unreleased FvK PDP10 variant - - ------------------------------------------------------------------------------ -*/ - -#include "pdp11_xu.h" - -extern int32 tmxr_poll, tmr_poll, clk_tps, cpu_astop; -extern FILE *sim_log; - -t_stat xu_rd(int32* data, int32 PA, int32 access); -t_stat xu_wr(int32 data, int32 PA, int32 access); -t_stat xu_svc(UNIT * uptr); -t_stat xu_tmrsvc(UNIT * uptr); -t_stat xu_reset (DEVICE * dptr); -t_stat xu_attach (UNIT * uptr, char * cptr); -t_stat xu_detach (UNIT * uptr); -t_stat xu_showmac (FILE* st, UNIT* uptr, int32 val, void* desc); -t_stat xu_setmac (UNIT* uptr, int32 val, char* cptr, void* desc); -t_stat xu_show_stats (FILE* st, UNIT* uptr, int32 val, void* desc); -t_stat xu_set_stats (UNIT* uptr, int32 val, char* cptr, void* desc); -t_stat xu_show_type (FILE* st, UNIT* uptr, int32 val, void* desc); -t_stat xu_set_type (UNIT* uptr, int32 val, char* cptr, void* desc); -int32 xu_int (void); -t_stat xu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); -t_stat xu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); -void xua_read_callback(int status); -void xub_read_callback(int status); -void xua_write_callback(int status); -void xub_write_callback(int status); -void xu_setint (CTLR* xu); -void xu_clrint (CTLR* xu); -void xu_process_receive(CTLR* xu); -void xu_dump_rxring(CTLR* xu); -void xu_dump_txring(CTLR* xu); -t_stat xu_show_filters (FILE* st, UNIT* uptr, int32 val, void* desc); - -DIB xua_dib = { IOBA_XU, IOLN_XU, &xu_rd, &xu_wr, -1, IVCL (XU), VEC_XU, {&xu_int} }; - -UNIT xua_unit[] = { - { UDATA (&xu_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 0) }, /* receive timer */ - { UDATA (&xu_tmrsvc, UNIT_IDLE|UNIT_DIS, 0) } -}; - -struct xu_device xua = { - xua_read_callback, /* read callback routine */ - xua_write_callback, /* write callback routine */ - {0x08, 0x00, 0x2B, 0xCC, 0xDD, 0xEE}, /* mac */ - XU_T_DELUA /* type */ - }; - -MTAB xu_mod[] = { -#if defined (VM_PDP11) - { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", "ADDRESS", - &set_addr, &show_addr, NULL }, - { MTAB_XTD | MTAB_VDV, 0, NULL, "AUTOCONFIGURE", - &set_addr_flt, NULL, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, - &set_vec, &show_vec, NULL }, -#else - { MTAB_XTD|MTAB_VDV, 004, "ADDRESS", NULL, - NULL, &show_addr, NULL }, - { MTAB_XTD|MTAB_VDV, 0, "VECTOR", NULL, - NULL, &show_vec, NULL }, -#endif - { MTAB_XTD | MTAB_VDV, 0, "MAC", "MAC=xx:xx:xx:xx:xx:xx", - &xu_setmac, &xu_showmac, NULL }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "ETH", "ETH", - NULL, ð_show, NULL }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "STATS", "STATS", - &xu_set_stats, &xu_show_stats, NULL }, - { MTAB_XTD | MTAB_VDV | MTAB_NMO, 0, "FILTERS", "FILTERS", - NULL, &xu_show_filters, NULL }, - { MTAB_XTD | MTAB_VDV, 0, "TYPE", "TYPE={DEUNA|DELUA}", - &xu_set_type, &xu_show_type, NULL }, - { 0 }, -}; - -REG xua_reg[] = { - { NULL } }; - -DEBTAB xu_debug[] = { - {"TRACE", DBG_TRC}, - {"WARN", DBG_WRN}, - {"REG", DBG_REG}, - {"PACKET", DBG_PCK}, - {"DATA", DBG_DAT}, - {"ETH", DBG_ETH}, - {0} -}; - - -DEVICE xu_dev = { - "XU", xua_unit, xua_reg, xu_mod, - 2, XU_RDX, 8, 1, XU_RDX, 8, - &xu_ex, &xu_dep, &xu_reset, - NULL, &xu_attach, &xu_detach, - &xua_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG, - 0, xu_debug - }; - - -/* XUB does not exist in the PDP10 simulation */ -#if defined(IOBA_XUB) - -DIB xub_dib = { IOBA_XUB, IOLN_XUB, &xu_rd, &xu_wr, - 1, IVCL (XU), 0, { &xu_int } }; - -UNIT xub_unit[] = { - { UDATA (&xu_svc, UNIT_IDLE|UNIT_ATTABLE|UNIT_DISABLE, 0) } /* receive timer */ -}; - -struct xu_device xub = { - xub_read_callback, /* read callback routine */ - xub_write_callback, /* write callback routine */ - {0x08, 0x00, 0x2B, 0xDD, 0xEE, 0xFF}, /* mac */ - XU_T_DELUA /* type */ - }; - -REG xub_reg[] = { - { NULL } }; - -DEVICE xub_dev = { - "XUB", xub_unit, xub_reg, xu_mod, - 1, XU_RDX, 8, 1, XU_RDX, 8, - &xu_ex, &xu_dep, &xu_reset, - NULL, &xu_attach, &xu_detach, - &xub_dib, DEV_FLTA | DEV_DISABLE | DEV_DIS | DEV_UBUS | DEV_DEBUG, - 0, xu_debug -}; - -#define XU_MAX_CONTROLLERS 2 -CTLR xu_ctrl[] = { - {&xu_dev, xua_unit, &xua_dib, &xua} /* XUA controller */ - ,{&xub_dev, xub_unit, &xub_dib, &xub} /* XUB controller */ -}; -#else /* IOBA_XUB */ -#define XU_MAX_CONTROLLERS 1 -CTLR xu_ctrl[] = { - {&xu_dev, xua_unit, &xua_dib, &xua} /* XUA controller */ -}; -#endif /* IOBA_XUB */ - -/*============================================================================*/ - -/* Multicontroller support */ - -CTLR* xu_unit2ctlr(UNIT* uptr) -{ - int i; - unsigned int j; - for (i=0; inumunits; j++) - if (&xu_ctrl[i].unit[j] == uptr) - return &xu_ctrl[i]; - /* not found */ - return 0; -} - -CTLR* xu_dev2ctlr(DEVICE* dptr) -{ - int i; - for (i=0; i= xu_ctrl[i].dib->ba) && (PA < (xu_ctrl[i].dib->ba + xu_ctrl[i].dib->lnt))) - return &xu_ctrl[i]; - /* not found */ - return 0; -} - -/*============================================================================*/ - -/* stop simh from reading non-existant unit data stream */ -t_stat xu_ex (t_value* vptr, t_addr addr, UNIT* uptr, int32 sw) -{ - return SCPE_NOFNC; -} - -/* stop simh from writing non-existant unit data stream */ -t_stat xu_dep (t_value val, t_addr addr, UNIT* uptr, int32 sw) -{ - return SCPE_NOFNC; -} - -t_stat xu_showmac (FILE* st, UNIT* uptr, int32 val, void* desc) -{ - CTLR* xu = xu_unit2ctlr(uptr); - char buffer[20]; - - eth_mac_fmt((ETH_MAC*)xu->var->mac, buffer); - fprintf(st, "MAC=%s", buffer); - return SCPE_OK; -} - -t_stat xu_setmac (UNIT* uptr, int32 val, char* cptr, void* desc) -{ - t_stat status; - CTLR* xu = xu_unit2ctlr(uptr); - - if (!cptr) return SCPE_IERR; - if (uptr->flags & UNIT_ATT) return SCPE_ALATT; - status = eth_mac_scan(&xu->var->mac, cptr); - return status; -} - -t_stat xu_set_stats (UNIT* uptr, int32 val, char* cptr, void* desc) -{ - CTLR* xu = xu_unit2ctlr(uptr); - - /* set stats to zero, regardless of passed parameter */ - memset(&xu->var->stats, 0, sizeof(struct xu_stats)); - return SCPE_OK; -} - -t_stat xu_show_stats (FILE* st, UNIT* uptr, int32 val, void* desc) -{ - char* fmt = " %-26s%d\n"; - CTLR* xu = xu_unit2ctlr(uptr); - struct xu_stats* stats = &xu->var->stats; - - fprintf(st, "Ethernet statistics:\n"); - fprintf(st, fmt, "Seconds since cleared:", stats->secs); - fprintf(st, fmt, "Recv frames:", stats->frecv); - fprintf(st, fmt, "Recv dbytes:", stats->rbytes); - fprintf(st, fmt, "Xmit frames:", stats->ftrans); - fprintf(st, fmt, "Xmit dbytes:", stats->tbytes); - fprintf(st, fmt, "Recv frames(multicast):", stats->mfrecv); - fprintf(st, fmt, "Recv dbytes(multicast):", stats->mrbytes); - fprintf(st, fmt, "Xmit frames(multicast):", stats->mftrans); - fprintf(st, fmt, "Xmit dbytes(multicast):", stats->mtbytes); - fprintf(st, fmt, "Loopback forward Frames:", stats->loopf); - return SCPE_OK; -} - -t_stat xu_show_filters (FILE* st, UNIT* uptr, int32 val, void* desc) -{ - CTLR* xu = xu_unit2ctlr(uptr); - char buffer[20]; - int i; - - fprintf(st, "Filters:\n"); - for (i=0; ivar->setup.macs[i], buffer); - fprintf(st, " [%2d]: %s\n", i, buffer); - } - if (xu->var->setup.multicast) - fprintf(st, "All Multicast Receive Mode\n"); - if (xu->var->setup.promiscuous) - fprintf(st, "Promiscuous Receive Mode\n"); - return SCPE_OK; -} - -t_stat xu_show_type (FILE* st, UNIT* uptr, int32 val, void* desc) -{ - CTLR* xu = xu_unit2ctlr(uptr); - fprintf(st, "type="); - switch (xu->var->type) { - case XU_T_DEUNA: fprintf(st, "DEUNA"); break; - case XU_T_DELUA: fprintf(st, "DELUA"); break; - } - return SCPE_OK; -} - -t_stat xu_set_type (UNIT* uptr, int32 val, char* cptr, void* desc) -{ - CTLR* xu = xu_unit2ctlr(uptr); - if (!cptr) return SCPE_IERR; - if (uptr->flags & UNIT_ATT) return SCPE_ALATT; - - /* this assumes that the parameter has already been upcased */ - if (!strcmp(cptr, "DEUNA")) xu->var->type = XU_T_DEUNA; - else if (!strcmp(cptr, "DELUA")) xu->var->type = XU_T_DELUA; - else return SCPE_ARG; - - return SCPE_OK; -} - -/*============================================================================*/ - -void upd_stat16(uint16* stat, uint16 add) -{ - *stat += add; - /* did stat roll over? latches at maximum */ - if (*stat < add) - *stat = 0xFFFF; -} - -void upd_stat32(uint32* stat, uint32 add) -{ - *stat += add; - /* did stat roll over? latches at maximum */ - if (*stat < add) - *stat = 0xFFFFFFFF; -} - -void bit_stat16(uint16* stat, uint16 bits) -{ - *stat |= bits; -} - -t_stat xu_process_loopback(CTLR* xu, ETH_PACK* pack) -{ - ETH_PACK response; - ETH_MAC physical_address; - t_stat status; - int offset = 16 + (pack->msg[14] | (pack->msg[15] << 8)); - int function = pack->msg[offset] | (pack->msg[offset+1] << 8); - - sim_debug(DBG_TRC, xu->dev, "xu_process_loopback()\n"); - - if (function != 2 /*forward*/) - return SCPE_NOFNC; - - /* create forward response packet */ - memcpy (&response, pack, sizeof(ETH_PACK)); - memcpy (physical_address, xu->var->setup.macs[0], sizeof(ETH_MAC)); - - /* The only packets we should be responding to are ones which - we received due to them being directed to our physical MAC address, - OR the Broadcast address OR to a Multicast address we're listening to - (we may receive others if we're in promiscuous mode, but shouldn't - respond to them) */ - if ((0 == (pack->msg[0]&1)) && /* Multicast or Broadcast */ - (0 != memcmp(physical_address, pack->msg, sizeof(ETH_MAC)))) - return SCPE_NOFNC; - - - memcpy (&response.msg[0], &response.msg[offset+2], sizeof(ETH_MAC)); - memcpy (&response.msg[6], physical_address, sizeof(ETH_MAC)); - offset += 8; - response.msg[14] = offset & 0xFF; - response.msg[15] = (offset >> 8) & 0xFF; - - /* send response packet */ - status = eth_write(xu->var->etherface, &response, NULL); - ++xu->var->stats.loopf; - - if (DBG_PCK & xu->dev->dctrl) - eth_packet_trace_ex(xu->var->etherface, response.msg, response.len, ((function == 1) ? "xu-loopbackreply" : "xu-loopbackforward"), DBG_DAT & xu->dev->dctrl, DBG_PCK); - - return status; -} - -t_stat xu_process_local (CTLR* xu, ETH_PACK* pack) -{ - /* returns SCPE_OK if local processing occurred, - otherwise returns SCPE_NOFNC or some other code */ - int protocol; - - sim_debug(DBG_TRC, xu->dev, "xu_process_local()\n"); - - protocol = pack->msg[12] | (pack->msg[13] << 8); - switch (protocol) { - case 0x0090: /* ethernet loopback */ - return xu_process_loopback(xu, pack); - break; - case 0x0260: /* MOP remote console */ - return SCPE_NOFNC; /* not implemented yet */ - break; - } - return SCPE_NOFNC; -} - -void xu_read_callback(CTLR* xu, int status) -{ - if (DBG_PCK & xu->dev->dctrl) - eth_packet_trace_ex(xu->var->etherface, xu->var->read_buffer.msg, xu->var->read_buffer.len, "xu-recvd", DBG_DAT & xu->dev->dctrl, DBG_PCK); - - /* process any packets locally that can be */ - status = xu_process_local (xu, &xu->var->read_buffer); - - /* add packet to read queue */ - if (status != SCPE_OK) - ethq_insert(&xu->var->ReadQ, 2, &xu->var->read_buffer, 0); -} - -void xua_read_callback(int status) -{ - xu_read_callback(&xu_ctrl[0], status); -} - -void xub_read_callback(int status) -{ - xu_read_callback(&xu_ctrl[1], status); -} - -t_stat xu_system_id (CTLR* xu, const ETH_MAC dest, uint16 receipt_id) -{ - static uint16 receipt = 0; - ETH_PACK system_id; - uint8* const msg = &system_id.msg[0]; - t_stat status; - - sim_debug(DBG_TRC, xu->dev, "xu_system_id()\n"); - memset (&system_id, 0, sizeof(system_id)); - memcpy (&msg[0], dest, sizeof(ETH_MAC)); - memcpy (&msg[6], xu->var->setup.macs[0], sizeof(ETH_MAC)); - msg[12] = 0x60; /* type */ - msg[13] = 0x02; /* type */ - msg[14] = 0x1C; /* character count */ - msg[15] = 0x00; /* character count */ - msg[16] = 0x07; /* code */ - msg[17] = 0x00; /* zero pad */ - if (receipt_id) { - msg[18] = receipt_id & 0xFF; /* receipt number */ - msg[19] = (receipt_id >> 8) & 0xFF; /* receipt number */ - } else { - msg[18] = receipt & 0xFF; /* receipt number */ - msg[19] = (receipt++ >> 8) & 0xFF; /* receipt number */ - } - - /* MOP VERSION */ - msg[20] = 0x01; /* type */ - msg[21] = 0x00; /* type */ - msg[22] = 0x03; /* length */ - msg[23] = 0x03; /* version */ - msg[24] = 0x00; /* eco */ - msg[25] = 0x00; /* user eco */ - - /* FUNCTION */ - msg[26] = 0x02; /* type */ - msg[27] = 0x00; /* type */ - msg[28] = 0x02; /* length */ - msg[29] = 0x05; /* value 1 */ - msg[30] = 0x00; /* value 2 */ - - /* HARDWARE ADDRESS */ - msg[31] = 0x07; /* type */ - msg[32] = 0x00; /* type */ - msg[33] = 0x06; /* length */ - memcpy (&msg[34], xu->var->mac, sizeof(ETH_MAC)); /* ROM address */ - - /* DEVICE TYPE */ - msg[40] = 0x64; /* type */ - msg[41] = 0x00; /* type */ - msg[42] = 0x01; /* length */ - if (xu->var->type == XU_T_DEUNA) - msg[43] = 1; /* value (1=DEUNA) */ - else - msg[43] = 11; /* value (11=DELUA) */ - - /* write system id */ - system_id.len = 60; - status = eth_write(xu->var->etherface, &system_id, NULL); - if (DBG_PCK & xu->dev->dctrl) - eth_packet_trace_ex(xu->var->etherface, system_id.msg, system_id.len, "xu-systemid", DBG_DAT & xu->dev->dctrl, DBG_PCK); - - return status; -} - -t_stat xu_svc(UNIT* uptr) -{ - int queue_size; - CTLR* xu = xu_unit2ctlr(uptr); - - /* First pump any queued packets into the system */ - if ((xu->var->ReadQ.count > 0) && ((xu->var->pcsr1 & PCSR1_STATE) == STATE_RUNNING)) - xu_process_receive(xu); - - /* Now read and queue packets that have arrived */ - /* This is repeated as long as they are available and we have room */ - do - { - queue_size = xu->var->ReadQ.count; - /* read a packet from the ethernet - processing is via the callback */ - eth_read (xu->var->etherface, &xu->var->read_buffer, xu->var->rcallback); - } while (queue_size != xu->var->ReadQ.count); - - /* Now pump any still queued packets into the system */ - if ((xu->var->ReadQ.count > 0) && ((xu->var->pcsr1 & PCSR1_STATE) == STATE_RUNNING)) - xu_process_receive(xu); - - /* resubmit service timer if controller not halted */ - switch (xu->var->pcsr1 & PCSR1_STATE) { - case STATE_READY: - case STATE_RUNNING: - sim_activate(&xu->unit[0], clk_cosched(tmxr_poll)); - break; - }; - - return SCPE_OK; -} - -t_stat xu_tmrsvc(UNIT* uptr) -{ - CTLR* xu = xu_unit2ctlr(uptr); - const ETH_MAC mop_multicast = {0xAB, 0x00, 0x00, 0x02, 0x00, 0x00}; - const int one_second = clk_tps * tmr_poll; - - /* send identity packet when timer expires */ - if (--xu->var->idtmr <= 0) { - if ((xu->var->mode & MODE_DMNT) == 0) /* if maint msg is not disabled */ - xu_system_id(xu, mop_multicast, 0); /* then send ID packet */ - xu->var->idtmr = XU_ID_TIMER_VAL; /* reset timer */ - } - - /* update stats */ - upd_stat16 (&xu->var->stats.secs, 1); - - /* resubmit service timer */ - sim_activate(uptr, one_second); - - return SCPE_OK; -} - -void xu_write_callback (CTLR* xu, int status) -{ - xu->var->write_buffer.status = status; -} - -void xua_write_callback (int status) -{ - xu_write_callback(&xu_ctrl[0], status); -} - -void xub_write_callback (int status) -{ - xu_write_callback(&xu_ctrl[1], status); -} - -void xu_setclrint(CTLR* xu, int32 bits) -{ - if (xu->var->pcsr0 & 0xFF00) { /* if any interrupt bits on, */ - xu->var->pcsr0 |= PCSR0_INTR; /* turn master bit on */ - xu_setint(xu); /* and trigger interrupt */ - } else { - xu->var->pcsr0 &= ~PCSR0_INTR; /* ... or off */ - xu_clrint(xu); /* and clear interrupt if needed*/ - } -} - -t_stat xu_sw_reset (CTLR* xu) -{ - int i; - - sim_debug(DBG_TRC, xu->dev, "xu_sw_reset()\n"); - - /* Clear the registers. */ - xu->var->pcsr0 = PCSR0_DNI | PCSR0_INTR; - xu->var->pcsr1 = STATE_READY; - switch (xu->var->type) { - case XU_T_DELUA: - xu->var->pcsr1 |= TYPE_DELUA; - break; - case XU_T_DEUNA: - xu->var->pcsr1 |= TYPE_DEUNA; - if (!xu->var->etherface) /* if not attached, set transceiver powerfail */ - xu->var->pcsr1 |= PCSR1_XPWR; - break; - } - xu->var->pcsr2 = 0; - xu->var->pcsr3 = 0; - - /* Clear the parameters. */ - xu->var->mode = 0; - xu->var->pcbb = 0; - xu->var->stat = 0; - - /* clear read queue */ - ethq_clear(&xu->var->ReadQ); - - /* clear setup info */ - memset(&xu->var->setup, 0, sizeof(struct xu_setup)); - - /* clear network statistics */ - memset(&xu->var->stats, 0, sizeof(struct xu_stats)); - - /* reset ethernet interface */ - memcpy (xu->var->setup.macs[0], xu->var->mac, sizeof(ETH_MAC)); - for (i=0; i<6; i++) - xu->var->setup.macs[1][i] = 0xff; /* Broadcast Address */ - xu->var->setup.mac_count = 2; - if (xu->var->etherface) - eth_filter (xu->var->etherface, xu->var->setup.mac_count, - xu->var->setup.macs, xu->var->setup.multicast, - xu->var->setup.promiscuous); - - /* activate device if not disabled */ - if ((xu->dev->flags & DEV_DIS) == 0) { - sim_activate_abs(&xu->unit[0], clk_cosched (tmxr_poll)); - - /* start service timer */ - if (xu->var->etherface) - sim_activate_abs(&xu->unit[1], tmr_poll * clk_tps); - } - - /* clear load_server address */ - memset(xu->var->load_server, 0, sizeof(ETH_MAC)); - - return SCPE_OK; -} - -/* Reset device. */ -t_stat xu_reset(DEVICE* dptr) -{ - t_stat status; - CTLR* xu = xu_dev2ctlr(dptr); - - sim_debug(DBG_TRC, xu->dev, "xu_reset()\n"); - /* init read queue (first time only) */ - status = ethq_init (&xu->var->ReadQ, XU_QUE_MAX); - if (status != SCPE_OK) - return status; - - /* software reset controller */ - xu_sw_reset(xu); - - return auto_config (0, 0); /* run autoconfig */ -} - - -/* Perform one of the defined ancillary functions. */ -int32 xu_command(CTLR* xu) -{ - uint32 udbb; - int fnc, mtlen, i, j; - uint16 value, pltlen; - t_stat rstatus, wstatus, wstatus2, wstatus3; - struct xu_stats* stats = &xu->var->stats; - uint16* udb = xu->var->udb; - uint16* mac_w = (uint16*) xu->var->mac; - static const ETH_MAC zeros = {0,0,0,0,0,0}; - static const ETH_MAC mcast_load_server = {0xAB, 0x00, 0x00, 0x01, 0x00, 0x00}; - static char* command[] = { - "NO-OP", - "Start Microaddress", - "Read Default Physical Address", - "NO-OP", - "Read Physical Address", - "Write Physical Address", - "Read Multicast Address List", - "Write Multicast Address List", - "Read Descriptor Ring Format", - "Write Descriptor Ring Format", - "Read Counters", - "Read/Clear Counters", - "Read Mode Register", - "Write Mode Register", - "Read Status", - "Read/Clear Status", - "Dump Internal Memory", - "Load Internal Memory", - "Read System ID", - "Write System ID", - "Read Load Server Address", - "Write Load Server Address" - }; - - /* Grab the PCB from the host. */ - rstatus = Map_ReadW(xu->var->pcbb, 8, xu->var->pcb); - if (rstatus != 0) - return PCSR0_PCEI + 1; - - /* High 8 bits are defined as MBZ. */ - if (xu->var->pcb[0] & 0177400) - return PCSR0_PCEI; - - /* Decode the function to be performed. */ - fnc = xu->var->pcb[0] & 0377; - sim_debug(DBG_TRC, xu->dev, "xu_command(), Command: %s [0%o]\n", command[fnc], fnc); - - switch (fnc) { - case FC_NOOP: - break; - - case FC_RDPA: /* read default physical address */ - wstatus = Map_WriteB(xu->var->pcbb + 2, 6, xu->var->mac); - if (wstatus) - return PCSR0_PCEI + 1; - break; - - case FC_RPA: /* read current physical address */ - wstatus = Map_WriteB(xu->var->pcbb + 2, 6, (uint8*)&xu->var->setup.macs[0]); - if (wstatus) - return PCSR0_PCEI + 1; - break; - - case FC_WPA: /* write current physical address */ - rstatus = Map_ReadB(xu->var->pcbb + 2, 6, (uint8*)&xu->var->setup.macs[0]); - if (xu->var->pcb[1] & 1) - return PCSR0_PCEI; - break; - - case FC_RMAL: /* read multicast address list */ - mtlen = (xu->var->pcb[2] & 0xFF00) >> 8; - udbb = xu->var->pcb[1] | ((xu->var->pcb[2] & 03) << 16); - wstatus = Map_WriteB(udbb, mtlen * 3, (uint8*) &xu->var->setup.macs[2]); - break; - - case FC_WMAL: /* write multicast address list */ - mtlen = (xu->var->pcb[2] & 0xFF00) >> 8; - sim_debug(DBG_TRC, xu->dev, "FC_WAL: mtlen=%d\n", mtlen); - if (mtlen > 10) - return PCSR0_PCEI; - udbb = xu->var->pcb[1] | ((xu->var->pcb[2] & 03) << 16); - /* clear existing multicast list */ - for (i=2; ivar->setup.macs[i][j] = 0; - } - /* get multicast list from host */ - rstatus = Map_ReadB(udbb, mtlen * 6, (uint8*) &xu->var->setup.macs[2]); - if (rstatus == 0) { - xu->var->setup.mac_count = mtlen + 2; - eth_filter (xu->var->etherface, xu->var->setup.mac_count, - xu->var->setup.macs, xu->var->setup.multicast, - xu->var->setup.promiscuous); - } else { - xu->var->pcsr0 |= PCSR0_PCEI; - } - break; - - case FC_RRF: /* read ring format */ - if ((xu->var->pcb[1] & 1) || (xu->var->pcb[2] & 0374)) - return PCSR0_PCEI; - xu->var->udb[0] = xu->var->tdrb & 0177776; - xu->var->udb[1] = (xu->var->telen << 8) + ((xu->var->tdrb >> 16) & 3); - xu->var->udb[2] = xu->var->trlen; - xu->var->udb[3] = xu->var->rdrb & 0177776; - xu->var->udb[4] = (xu->var->relen << 8) + ((xu->var->rdrb >> 16) & 3); - xu->var->udb[5] = xu->var->rrlen; - - /* Write UDB to host memory. */ - udbb = xu->var->pcb[1] + ((xu->var->pcb[2] & 3) << 16); - wstatus = Map_WriteW(udbb, 12, xu->var->pcb); - if (wstatus != 0) - return PCSR0_PCEI+1; - break; - - case FC_WRF: /* write ring format */ - if ((xu->var->pcb[1] & 1) || (xu->var->pcb[2] & 0374)) - return PCSR0_PCEI; - if ((xu->var->pcsr1 & PCSR1_STATE) == STATE_RUNNING) - return PCSR0_PCEI; - - /* Read UDB into local memory. */ - udbb = xu->var->pcb[1] + ((xu->var->pcb[2] & 3) << 16); - rstatus = Map_ReadW(udbb, 12, xu->var->udb); - if (rstatus) - return PCSR0_PCEI+1; - - if ((xu->var->udb[0] & 1) || (xu->var->udb[1] & 0374) || - (xu->var->udb[3] & 1) || (xu->var->udb[4] & 0374) || - (xu->var->udb[5] < 2)) { - return PCSR0_PCEI; - } - - xu->var->tdrb = ((xu->var->udb[1] & 3) << 16) + (xu->var->udb[0] & 0177776); - xu->var->telen = (xu->var->udb[1] >> 8) & 0377; - xu->var->trlen = xu->var->udb[2]; - xu->var->rdrb = ((xu->var->udb[4] & 3) << 16) + (xu->var->udb[3] & 0177776); - xu->var->relen = (xu->var->udb[4] >> 8) & 0377; - xu->var->rrlen = xu->var->udb[5]; - xu->var->rxnext = 0; - xu->var->txnext = 0; -// xu_dump_rxring(xu); -// xu_dump_txring(xu); - - break; - - case FC_RDCTR: /* read counters */ - case FC_RDCLCTR: /* read and clear counters */ - /* prepare udb for stats transfer */ - memset(xu->var->udb, 0, sizeof(xu->var->udb)); - - /* place stats in udb */ - udb[0] = 68; /* udb length */ - udb[1] = stats->secs; /* seconds since zeroed */ - udb[2] = stats->frecv & 0xFFFF; /* frames received <15:00> */ - udb[3] = stats->frecv >> 16; /* frames received <31:16> */ - udb[4] = stats->mfrecv & 0xFFFF; /* multicast frames received <15:00> */ - udb[5] = stats->mfrecv >> 16; /* multicast frames received <31:16> */ - udb[6] = stats->rxerf; /* receive error status bits */ - udb[7] = stats->frecve; /* frames received with error */ - udb[8] = stats->rbytes & 0xFFFF; /* data bytes received <15:00> */ - udb[9] = stats->rbytes >> 16; /* data bytes received <31:16> */ - udb[10] = stats->mrbytes & 0xFFFF; /* multicast data bytes received <15:00> */ - udb[11] = stats->mrbytes >> 16; /* multicast data bytes received <31:16> */ - udb[12] = stats->rlossi; /* received frames lost - internal buffer */ - udb[13] = stats->rlossl; /* received frames lost - local buffer */ - udb[14] = stats->ftrans & 0xFFFF; /* frames transmitted <15:00> */ - udb[15] = stats->ftrans >> 16; /* frames transmitted <31:16> */ - udb[16] = stats->mftrans & 0xFFFF; /* multicast frames transmitted <15:00> */ - udb[17] = stats->mftrans >> 16; /* multicast frames transmitted <31:16> */ - udb[18] = stats->ftrans3 & 0xFFFF; /* frames transmitted 3+ tries <15:00> */ - udb[19] = stats->ftrans3 >> 16; /* frames transmitted 3+ tries <31:16> */ - udb[20] = stats->ftrans2 & 0xFFFF; /* frames transmitted 2 tries <15:00> */ - udb[21] = stats->ftrans2 >> 16; /* frames transmitted 2 tries <31:16> */ - udb[22] = stats->ftransd & 0xFFFF; /* frames transmitted deferred <15:00> */ - udb[23] = stats->ftransd >> 16; /* frames transmitted deferred <31:16> */ - udb[24] = stats->tbytes & 0xFFFF; /* data bytes transmitted <15:00> */ - udb[25] = stats->tbytes >> 16; /* data bytes transmitted <31:16> */ - udb[26] = stats->mtbytes & 0xFFFF; /* multicast data bytes transmitted <15:00> */ - udb[27] = stats->mtbytes >> 16; /* multicast data bytes transmitted <31:16> */ - udb[28] = stats->txerf; /* transmit frame error status bits */ - udb[29] = stats->ftransa; /* transmit frames aborted */ - udb[30] = stats->txccf; /* transmit collision check failure */ - udb[31] = 0; /* MBZ */ - udb[32] = stats->porterr; /* port driver error */ - udb[33] = stats->bablcnt; /* babble counter */ - - /* transfer udb to host */ - udbb = xu->var->pcb[1] + ((xu->var->pcb[2] & 3) << 16); - wstatus = Map_WriteW(udbb, 68, xu->var->udb); - if (wstatus) { - xu->var->pcsr0 |= PCSR0_PCEI; - } - - /* if clear function, clear network stats */ - if (fnc == FC_RDCLCTR) - memset(stats, 0, sizeof(struct xu_stats)); - break; - - case FC_RMODE: /* read mode register */ - value = xu->var->mode; - wstatus = Map_WriteW(xu->var->pcbb+2, 2, &value); - if (wstatus) - return PCSR0_PCEI + 1; - break; - - case FC_WMODE: /* write mode register */ - value = xu->var->mode; - xu->var->mode = xu->var->pcb[1]; - sim_debug(DBG_TRC, xu->dev, "FC_WMODE: mode=%04x\n", xu->var->mode); - - /* set promiscuous and multicast flags */ - xu->var->setup.promiscuous = (xu->var->mode & MODE_PROM) ? 1 : 0; - xu->var->setup.multicast = (xu->var->mode & MODE_ENAL) ? 1 : 0; - - /* if promiscuous or multicast flags changed, change filter */ - if ((value ^ xu->var->mode) & (MODE_PROM | MODE_ENAL)) - eth_filter (xu->var->etherface, xu->var->setup.mac_count, - xu->var->setup.macs, xu->var->setup.multicast, - xu->var->setup.promiscuous); - break; - - case FC_RSTAT: /* read extended status */ - case FC_RCSTAT: /* read and clear extended status */ - value = xu->var->stat; - wstatus = Map_WriteW(xu->var->pcbb+2, 2, &value); - value = 10; - wstatus2 = Map_WriteW(xu->var->pcbb+4, 2, &value); - value = 32; - wstatus3 = Map_WriteW(xu->var->pcbb+6, 2, &value); - if (wstatus + wstatus2 + wstatus3) - return PCSR0_PCEI + 1; - - if (fnc == FC_RCSTAT) - xu->var->stat &= 0377; /* clear high byte */ - break; - - case FC_RSID: /* read system id parameters */ - /* prepare udb for transfer */ - memset(xu->var->udb, 0, sizeof(xu->var->udb)); - - udb[11] = 0x260; /* type */ - udb[12] = 28/* + parameter size */; /* ccount */ - udb[13] = 7; /* code */ - udb[14] = 0; /* recnum */ - /* mop information */ - udb[15] = 1; /* mvtype */ - udb[16] = 0x0303; /* mvver + mvlen */ - udb[17] = 0; /* mvueco + mveco */ - /* function information */ - udb[18] = 2; /* ftype */ - udb[19] = 0x0502; /* fval1 + flen */ - udb[20] = 0x0700; /* hatype<07:00> + fval2 */ - udb[21] = 0x0600; /* halen + hatype<15:08> */ - /* built-in MAC address */ - udb[21] = mac_w[0]; /* HA<15:00> */ - udb[22] = mac_w[1]; /* HA<31:16> */ - udb[23] = mac_w[2]; /* HA<47:32> */ - udb[24] = 0x64; /* dtype */ - udb[25] = (11 << 8) + 1; /* dvalue + dlen */ - - /* transfer udb to host */ - udbb = xu->var->pcb[1] + ((xu->var->pcb[2] & 3) << 16); - wstatus = Map_WriteW(udbb, 52, xu->var->udb); - if (wstatus) - xu->var->pcsr0 |= PCSR0_PCEI; - break; - - case FC_WSID: /* write system id parameters */ - /* get udb base */ - udbb = xu->var->pcb[1] + ((xu->var->pcb[2] & 3) << 16); - /* get udb length */ - pltlen = xu->var->pcb[3]; - - /* transfer udb from host */ - rstatus = Map_ReadW(udbb, pltlen * 2, xu->var->udb); - if (rstatus) - return PCSR0_PCEI + 1; - - /* decode and store system ID fields , if we ever need to. - for right now, just return "success" */ - - break; - - case FC_RLSA: /* read load server address */ - if (memcmp(xu->var->load_server, zeros, sizeof(ETH_MAC))) { - /* not set, use default multicast load address */ - wstatus = Map_WriteB(xu->var->pcbb + 2, 6, (uint8*) mcast_load_server); - } else { - /* is set, use load_server */ - wstatus = Map_WriteB(xu->var->pcbb + 2, 6, xu->var->load_server); - } - if (wstatus) - return PCSR0_PCEI + 1; - break; - - - case FC_WLSA: /* write load server address */ - rstatus = Map_ReadB(xu->var->pcbb + 2, 6, xu->var->load_server); - if (rstatus) - return PCSR0_PCEI + 1; - break; - - default: /* Unknown (unimplemented) command. */ - printf("%s: unknown ancilliary command 0%o requested !\n", xu->dev->name, fnc); - return PCSR0_PCEI; - break; - - } /* switch */ - - return PCSR0_DNI; -} - -/* Transfer received packets into receive ring. */ -void xu_process_receive(CTLR* xu) -{ - uint32 segb, ba; - int slen, wlen, off; - t_stat rstatus, wstatus; - ETH_ITEM* item = 0; - int state = xu->var->pcsr1 & PCSR1_STATE; - int no_buffers = xu->var->pcsr0 & PCSR0_RCBI; - - sim_debug(DBG_TRC, xu->dev, "xu_process_receive(), buffers: %d\n", xu->var->rrlen); - -// xu_dump_rxring(xu); /* debug receive ring */ - - /* process only when in the running state, and host buffers are available */ - if ((state != STATE_RUNNING) || no_buffers) - return; - - /* check read queue for buffer loss */ - if (xu->var->ReadQ.loss) { - upd_stat16(&xu->var->stats.rlossl, (uint16) xu->var->ReadQ.loss); - xu->var->ReadQ.loss = 0; - } - - /* while there are still packets left to process in the queue */ - while (xu->var->ReadQ.count > 0) { - - /* get next receive buffer */ - ba = xu->var->rdrb + (xu->var->relen * 2) * xu->var->rxnext; - rstatus = Map_ReadW (ba, 8, xu->var->rxhdr); - if (rstatus) { - /* tell host bus read failed */ - xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_RRNG; - xu->var->pcsr0 |= PCSR0_SERI; - break; - } - - /* if buffer not owned by controller, exit [at end of ring] */ - if (!(xu->var->rxhdr[2] & RXR_OWN)) { - /* tell the host there are no more buffers */ - /* xu->var->pcsr0 |= PCSR0_RCBI; */ /* I don't think this is correct 08-dec-2005 dth */ - break; - } - - /* set buffer length and address */ - slen = xu->var->rxhdr[0]; - segb = xu->var->rxhdr[1] + ((xu->var->rxhdr[2] & 3) << 16); - - /* get first packet from receive queue */ - if (!item) { - item = &xu->var->ReadQ.item[xu->var->ReadQ.head]; - /* - * 2.11BSD does not seem to like small packets. - * For example.. an incoming ARP packet is: - * ETH dstaddr [6] - * ETH srcaddr [6] - * ETH type [2] - * ARP arphdr [8] - * ARP dstha [6] - * ARP dstpa [4] - * ARP srcha [6] - * ARP srcpa [4] - * - * for a total of 42 bytes. According to the 2.11BSD - * driver for DEUNA (if_de.c), this is not a legal size, - * and the packet is dropped. Therefore, we pad the - * thing to minimum size here. Stupid runts... - */ - if (item->packet.len < ETH_MIN_PACKET) { - int len = item->packet.len; - memset (&item->packet.msg[len], 0, ETH_MIN_PACKET - len); - item->packet.len = ETH_MIN_PACKET; - } - } - - /* is this the start of frame? */ - if (item->packet.used == 0) { - xu->var->rxhdr[2] |= RXR_STF; - off = 0; - } - - /* figure out chained packet size */ - wlen = item->packet.crc_len - item->packet.used; - if (wlen > slen) - wlen = slen; - - /* transfer chained packet to host buffer */ - wstatus = Map_WriteB (segb, wlen, &item->packet.msg[off]); - if (wstatus) { - /* error during write */ - xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_RRNG; - xu->var->pcsr0 |= PCSR0_SERI; - break; - } - - /* update chained counts */ - item->packet.used += wlen; - off += wlen; - - /* Is this the end-of-frame? */ - if (item->packet.used == item->packet.crc_len) { - /* mark end-of-frame */ - xu->var->rxhdr[2] |= RXR_ENF; - - /* - * Fill in the Received Message Length field. - * The documenation notes that the DEUNA actually performs - * a full CRC check on the data buffer, and adds this CRC - * value to the data, in the last 4 bytes. The question - * is: does MLEN include these 4 bytes, or not??? --FvK - * - * A quick look at the RSX Process Software driver shows - * that the CRC byte count(4) is added to MLEN, but does - * not show if the DEUNA/DELUA actually transfers the - * CRC bytes to the host buffers, since the driver never - * tries to use them. However, since the host max buffer - * size is only 1514, not 1518, I doubt the CRC is actually - * transferred in normal mode. Maybe CRC is transferred - * and used in Loopback mode.. -- DTH - * - * The VMS XEDRIVER indicates that CRC is transferred as - * part of the packet, and is included in the MLEN count. -- DTH - */ - xu->var->rxhdr[3] &= ~RXR_MLEN; - xu->var->rxhdr[3] |= (item->packet.crc_len); - if (xu->var->mode & MODE_DRDC) /* data chaining disabled */ - xu->var->rxhdr[3] |= RXR_NCHN; - - /* update stats */ - upd_stat32(&xu->var->stats.frecv, 1); - upd_stat32(&xu->var->stats.rbytes, item->packet.len - 14); - if (item->packet.msg[0] & 1) { /* multicast? */ - upd_stat32(&xu->var->stats.mfrecv, 1); - upd_stat32(&xu->var->stats.mrbytes, item->packet.len - 14); - } - - /* remove processed packet from the receive queue */ - ethq_remove (&xu->var->ReadQ); - item = 0; - - /* tell host we received a packet */ - xu->var->pcsr0 |= PCSR0_RXI; - } /* if end-of-frame */ - - /* give buffer back to host */ - xu->var->rxhdr[2] &= ~RXR_OWN; /* clear ownership flag */ - - /* update the ring entry in host memory. */ - wstatus = Map_WriteW (ba, 8, xu->var->rxhdr); - if (wstatus) { - /* tell host bus write failed */ - xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_RRNG; - xu->var->pcsr0 |= PCSR0_SERI; - /* if this was end-of-frame, log frame loss */ - if (xu->var->rxhdr[2] & RXR_ENF) - upd_stat16(&xu->var->stats.rlossi, 1); - } - - /* set to next receive ring buffer */ - xu->var->rxnext += 1; - if (xu->var->rxnext == xu->var->rrlen) - xu->var->rxnext = 0; - - } /* while */ - - /* if we failed to finish receiving the frame, flush the packet */ - if (item) { - ethq_remove(&xu->var->ReadQ); - upd_stat16(&xu->var->stats.rlossl, 1); - } - - /* set or clear interrupt, depending on what happened */ - xu_setclrint(xu, 0); -// xu_dump_rxring(xu); /* debug receive ring */ - -} - -void xu_process_transmit(CTLR* xu) -{ - uint32 segb, ba; - int slen, wlen, i, off, giant, runt; - t_stat rstatus, wstatus; - - sim_debug(DBG_TRC, xu->dev, "xu_process_transmit()\n"); -// xu_dump_txring(xu); /* debug receive ring */ - - for (;;) { - - /* get next transmit buffer */ - ba = xu->var->tdrb + (xu->var->telen * 2) * xu->var->txnext; - rstatus = Map_ReadW (ba, 8, xu->var->txhdr); - if (rstatus) { - /* tell host bus read failed */ - xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_TRNG; - xu->var->pcsr0 |= PCSR0_SERI; - break; - } - - /* if buffer not owned by controller, exit [at end of ring] */ - if (!(xu->var->txhdr[2] & TXR_OWN)) - break; - - /* set buffer length and address */ - slen = xu->var->txhdr[0]; - segb = xu->var->txhdr[1] + ((xu->var->txhdr[2] & 3) << 16); - wlen = slen; - - /* prepare to accumulate transmit information if start of frame */ - if (xu->var->txhdr[2] & TXR_STF) { - memset(&xu->var->write_buffer, 0, sizeof(ETH_PACK)); - off = giant = runt = 0; - } - - /* get packet data from host */ - if (xu->var->write_buffer.len + slen > ETH_MAX_PACKET) { - wlen = ETH_MAX_PACKET - xu->var->write_buffer.len; - giant = 1; - } - if (wlen > 0) { - rstatus = Map_ReadB(segb, wlen, &xu->var->write_buffer.msg[off]); - if (rstatus) { - /* tell host bus read failed */ - xu->var->stat |= STAT_ERRS | STAT_MERR | STAT_TMOT | STAT_TRNG; - xu->var->pcsr0 |= PCSR0_SERI; - break; - } - } - off += wlen; - xu->var->write_buffer.len += wlen; - - /* transmit packet when end-of-frame is reached */ - if (xu->var->txhdr[2] & TXR_ENF) { - - /* make sure packet is minimum length */ - if (xu->var->write_buffer.len < ETH_MIN_PACKET) { - xu->var->write_buffer.len = ETH_MIN_PACKET; /* pad packet to minimum length */ - if ((xu->var->mode & MODE_TPAD) == 0) /* if pad mode is NOT on, set runt error flag */ - runt = 1; - } - - /* As described in the DEUNA User Guide (Section 4.7), the DEUNA is responsible - for inserting the appropriate source MAC address in the outgoing packet header, - so we do that now. */ - memcpy(xu->var->write_buffer.msg+6, (uint8*)&xu->var->setup.macs[0], sizeof(ETH_MAC)); - - /* are we in internal loopback mode ? */ - if ((xu->var->mode & MODE_LOOP) && (xu->var->mode & MODE_INTL)) { - /* just put packet in receive buffer */ - ethq_insert (&xu->var->ReadQ, 1, &xu->var->write_buffer, 0); - } else { - /* transmit packet synchronously - write callback sets status */ - wstatus = eth_write(xu->var->etherface, &xu->var->write_buffer, xu->var->wcallback); - if (wstatus) - xu->var->pcsr0 |= PCSR0_PCEI; - else - if (DBG_PCK & xu->dev->dctrl) - eth_packet_trace_ex(xu->var->etherface, xu->var->write_buffer.msg, xu->var->write_buffer.len, "xu-write", DBG_DAT & xu->dev->dctrl, DBG_PCK); - } - - /* update transmit status in transmit buffer */ - if (xu->var->write_buffer.status != 0) { - /* failure */ - const uint16 tdr = 100 + wlen * 8; /* arbitrary value */ - xu->var->txhdr[3] |= TXR_RTRY; - xu->var->txhdr[3] |= tdr & TXR_TDR; - xu->var->txhdr[2] |= TXR_ERRS; - } - - /* was packet too big or too small? */ - if (giant || runt) { - xu->var->txhdr[3] |= TXR_BUFL; - xu->var->txhdr[2] |= TXR_ERRS; - } - - /* was packet self-addressed? */ - for (i=0; ivar->write_buffer.msg, xu->var->setup.macs[i], sizeof(ETH_MAC)) == 0) - xu->var->txhdr[2] |= TXR_MTCH; - - /* tell host we transmitted a packet */ - xu->var->pcsr0 |= PCSR0_TXI; - - /* update stats */ - upd_stat32(&xu->var->stats.ftrans, 1); - upd_stat32(&xu->var->stats.tbytes, xu->var->write_buffer.len - 14); - if (xu->var->write_buffer.msg[0] & 1) { /* multicast? */ - upd_stat32(&xu->var->stats.mftrans, 1); - upd_stat32(&xu->var->stats.mtbytes, xu->var->write_buffer.len - 14); - } - if (giant) - bit_stat16(&xu->var->stats.txerf, 0x10); - - } /* if end-of-frame */ - - - /* give buffer ownership back to host */ - xu->var->txhdr[2] &= ~TXR_OWN; - - /* update transmit buffer */ - wstatus = Map_WriteW (ba, 8, xu->var->txhdr); - if (wstatus) { - /* tell host bus write failed */ - xu->var->pcsr0 |= PCSR0_PCEI; - /* update stats */ - upd_stat16(&xu->var->stats.ftransa, 1); - break; - } - - /* set to next transmit ring buffer */ - xu->var->txnext += 1; - if (xu->var->txnext == xu->var->trlen) - xu->var->txnext = 0; - - } /* while */ -} - -void xu_port_command (CTLR* xu) -{ - char* msg; - int command = xu->var->pcsr0 & PCSR0_PCMD; - int state = xu->var->pcsr1 & PCSR1_STATE; - static char* commands[] = { - "NO-OP", - "GET PCBB", - "GET CMD", - "SELFTEST", - "START", - "BOOT", - "Reserved NO-OP", - "Reserved NO-OP", - "PDMD", - "Reserved NO-OP", - "Reserved NO-OP", - "Reserved NO-OP", - "Reserved NO-OP", - "Reserved NO-OP", - "HALT", - "STOP" - }; - - sim_debug(DBG_TRC, xu->dev, "xu_port_command(), Command = %s [0%o]\n", commands[command], command); - switch (command) { /* cases in order of most used to least used */ - case CMD_PDMD: /* POLLING DEMAND */ - /* process transmit buffers, receive buffers are done in the service timer */ - xu_process_transmit(xu); - xu->var->pcsr0 |= PCSR0_DNI; - break; - - case CMD_GETCMD: /* GET COMMAND */ - xu_command(xu); - xu->var->pcsr0 |= PCSR0_DNI; - break; - - case CMD_GETPCBB: /* GET PCB-BASE */ - xu->var->pcbb = (xu->var->pcsr3 << 16) | xu->var->pcsr2; - xu->var->pcsr0 |= PCSR0_DNI; - break; - - case CMD_SELFTEST: /* SELFTEST */ - /* - SELFTEST is a <=15-second self diagnostic test, setting various - error flags and the DONE (DNI) flag when complete. For simulation - purposes, signal completion immediately with no errors. This - inexact behavior could be incompatible with any guest machine - diagnostics that are expecting to be able to monitor the - controller's progress through the diagnostic testing. - */ - xu->var->pcsr0 |= PCSR0_DNI; - break; - - case CMD_START: /* START */ - if (state == STATE_READY) { - xu->var->pcsr1 &= ~PCSR1_STATE; - xu->var->pcsr1 |= STATE_RUNNING; - xu->var->pcsr0 |= PCSR0_DNI; - - /* reset ring pointers */ - xu->var->rxnext = 0; - xu->var->txnext = 0; - - } else - xu->var->pcsr0 |= PCSR0_PCEI; - break; - - case CMD_HALT: /* HALT */ - if ((state == STATE_READY) || (state == STATE_RUNNING)) { - sim_cancel (&xu->unit[0]); /* cancel service timer */ - xu->var->pcsr1 &= ~PCSR1_STATE; - xu->var->pcsr1 |= STATE_HALT; - xu->var->pcsr0 |= PCSR0_DNI; - } else - xu->var->pcsr0 |= PCSR0_PCEI; - break; - - case CMD_STOP: /* STOP */ - if (state == STATE_RUNNING) { - xu->var->pcsr1 &= ~PCSR1_STATE; - xu->var->pcsr1 |= STATE_READY; - xu->var->pcsr0 |= PCSR0_DNI; - } else - xu->var->pcsr0 |= PCSR0_PCEI; - break; - - case CMD_BOOT: /* BOOT */ - /* not implemented */ - msg = "%s: BOOT command not implemented!\n"; - printf (msg, xu->dev->name); - if (sim_log) fprintf(sim_log, msg, xu->dev->name); - - xu->var->pcsr0 |= PCSR0_PCEI; - break; - - case CMD_NOOP: /* NO-OP */ - /* NOOP does NOT set DNI */ - break; - - case CMD_RSV06: /* RESERVED */ - case CMD_RSV07: /* RESERVED */ - case CMD_RSV11: /* RESERVED */ - case CMD_RSV12: /* RESERVED */ - case CMD_RSV13: /* RESERVED */ - case CMD_RSV14: /* RESERVED */ - case CMD_RSV15: /* RESERVED */ - /* all reserved commands act as a no-op but set DNI */ - xu->var->pcsr0 |= PCSR0_DNI; - break; - } /* switch */ - - /* set interrupt if needed */ - xu_setclrint(xu, 0); -} - -t_stat xu_rd(int32 *data, int32 PA, int32 access) -{ - CTLR* xu = xu_pa2ctlr(PA); - int reg = (PA >> 1) & 03; - - switch (reg) { - case 00: - *data = xu->var->pcsr0; - break; - case 01: - *data = xu->var->pcsr1; - break; - case 02: - *data = xu->var->pcsr2; - break; - case 03: - *data = xu->var->pcsr3; - break; - } - sim_debug(DBG_REG, xu->dev, "xu_rd(), PCSR%d, data=%04x\n", reg, *data); - if (PA & 1) - sim_debug(DBG_WRN, xu->dev, "xu_rd(), Unexpected Odd address access of PCSR%d\n", reg); - return SCPE_OK; -} - -t_stat xu_wr(int32 data, int32 PA, int32 access) -{ - CTLR* xu = xu_pa2ctlr(PA); - int reg = (PA >> 1) & 03; - char desc[10]; - - switch (access) { - case WRITE : - strcpy(desc, "Word"); - break; - case WRITEB: - if (PA & 1) { - strcpy(desc, "ByteHi"); - } else { - strcpy(desc, "ByteLo"); - } - break; - default : - strcpy(desc, "Unknown"); - break; - } - sim_debug(DBG_REG, xu->dev, "xu_wr(), PCSR%d, data=%08x, PA=%08x, access=%d[%s]\n", reg, data, PA, access, desc); - switch (reg) { - case 00: - /* Clear write-one-to-clear interrupt bits */ - if (access == WRITEB) { - data &= 0377; - if (PA & 1) { - /* Handle WriteOneToClear trick. */ - xu->var->pcsr0 &= ~((data << 8) & 0177400); - - /* set/reset interrupt */ - xu_setclrint(xu, 0); - - /* Bail out early to avoid PCMD crap. */ - return SCPE_OK; - } - } else { /* access == WRITE [Word] */ - uint16 mask = data & 0xFF00; /* only interested in high byte */ - xu->var->pcsr0 &= ~mask; /* clear write-one-to-clear bits */ - } - /* RESET function requested? */ - if (data & PCSR0_RSET) { - xu_sw_reset(xu); - xu_setclrint(xu, 0); - return SCPE_OK; /* nothing else to do on reset */ - } - /* Handle the INTE interlock; if INTE changes state, no commands can occur */ - if ((xu->var->pcsr0 ^ data) & PCSR0_INTE) { - xu->var->pcsr0 ^= PCSR0_INTE; - xu->var->pcsr0 |= PCSR0_DNI; - if (xu->var->pcsr0 & PCSR0_INTE) { - sim_debug(DBG_TRC, xu->dev, "xu_wr(), Interrupts Enabled\n"); - } else { - sim_debug(DBG_TRC, xu->dev, "xu_wr(), Interrupts Disabled\n"); - } - } else { - /* Normal write, no interlock. */ - xu->var->pcsr0 &= ~PCSR0_PCMD; - xu->var->pcsr0 |= (data & PCSR0_PCMD); - xu_port_command(xu); - } - /* We might have changed the interrupt sys. */ - xu_setclrint(xu, 0); - break; - - case 01: - sim_debug(DBG_WRN, xu->dev, "xu_wr(), invalid write access on PCSR1!\n"); - break; - - case 02: - xu->var->pcsr2 = data & 0177776; /* store word, but not MBZ LSB */ - break; - - case 03: - xu->var->pcsr3 = data & 0000003; /* store significant bits */ - break; - } - return SCPE_OK; -} - - -/* attach device: */ -t_stat xu_attach(UNIT* uptr, char* cptr) -{ - t_stat status; - char* tptr; - CTLR* xu = xu_unit2ctlr(uptr); - - sim_debug(DBG_TRC, xu->dev, "xu_attach(cptr=%s)\n", cptr); - tptr = (char *) malloc(strlen(cptr) + 1); - if (tptr == NULL) return SCPE_MEM; - strcpy(tptr, cptr); - - xu->var->etherface = (ETH_DEV *) malloc(sizeof(ETH_DEV)); - if (!xu->var->etherface) { - free(tptr); - return SCPE_MEM; - } - - status = eth_open(xu->var->etherface, cptr, xu->dev, DBG_ETH); - if (status != SCPE_OK) { - free(tptr); - free(xu->var->etherface); - xu->var->etherface = 0; - return status; - } - if (SCPE_OK != eth_check_address_conflict (xu->var->etherface, &xu->var->mac)) { - char buf[32]; - - eth_mac_fmt(&xu->var->mac, buf); /* format ethernet mac address */ - printf("%s: MAC Address Conflict on LAN for address %s\n", xu->dev->name, buf); - if (sim_log) fprintf (sim_log, "%s: MAC Address Conflict on LAN for address %s\n", xu->dev->name, buf); - eth_close(xu->var->etherface); - free(tptr); - xu->var->etherface = 0; - return SCPE_NOATT; - } - uptr->filename = tptr; - uptr->flags |= UNIT_ATT; - eth_setcrc(xu->var->etherface, 1); /* enable CRC */ - - /* reset the device with the new attach info */ - xu_reset(xu->dev); - - return SCPE_OK; -} - -/* detach device: */ - -t_stat xu_detach(UNIT* uptr) -{ - CTLR* xu = xu_unit2ctlr(uptr); - sim_debug(DBG_TRC, xu->dev, "xu_detach()\n"); - - if (uptr->flags & UNIT_ATT) { - eth_close (xu->var->etherface); - free(xu->var->etherface); - xu->var->etherface = 0; - free(uptr->filename); - uptr->filename = NULL; - uptr->flags &= ~UNIT_ATT; - } - return SCPE_OK; -} - -void xu_setint(CTLR* xu) -{ - if (xu->var->pcsr0 & PCSR0_INTE) { - xu->var->irq = 1; - SET_INT(XU); - } - return; -} - -void xu_clrint(CTLR* xu) -{ - int i; - xu->var->irq = 0; /* set controller irq off */ - /* clear master interrupt? */ - for (i=0; iirq) { /* if any irqs enabled */ - SET_INT(XU); /* set master interrupt on */ - return; - } - CLR_INT(XU); /* clear master interrupt */ - return; -} - -int32 xu_int (void) -{ - int i; - for (i=0; ivar->irq) { /* if interrupt pending */ - xu_clrint(xu); /* clear interrupt */ - return xu->dib->vec; /* return vector */ - } - } - return 0; /* no interrupt request active */ -} - -/*============================================================================== -/ debugging routines -/=============================================================================*/ - -void xu_dump_rxring (CTLR* xu) -{ - int i; - int rrlen = xu->var->rrlen; - printf ("receive ring[%s]: base address: %08x headers: %d, header size: %d, current: %d\n", xu->dev->name, xu->var->rdrb, xu->var->rrlen, xu->var->relen, xu->var->rxnext); - for (i=0; ivar->rdrb + (xu->var->relen * 2) * i; - t_stat rstatus = Map_ReadW (ba, 8, rxhdr); /* get rxring entry[i] */ - int own = (rxhdr[2] & RXR_OWN) >> 15; - int len = rxhdr[0]; - uint32 addr = rxhdr[1] + ((rxhdr[2] & 3) << 16); - printf (" header[%d]: own:%d, len:%d, address:%08x data:{%04x,%04x,%04x,%04x}\n", i, own, len, addr, rxhdr[0], rxhdr[1], rxhdr[2], rxhdr[3]); - } -} - -void xu_dump_txring (CTLR* xu) -{ - int i; - int trlen = xu->var->trlen; - printf ("transmit ring[%s]: base address: %08x headers: %d, header size: %d, current: %d\n", xu->dev->name, xu->var->tdrb, xu->var->trlen, xu->var->telen, xu->var->txnext); - for (i=0; ivar->tdrb + (xu->var->telen * 2) * i; - t_stat tstatus = Map_ReadW (ba, 8, txhdr); /* get rxring entry[i] */ - int own = (txhdr[2] & RXR_OWN) >> 15; - int len = txhdr[0]; - uint32 addr = txhdr[1] + ((txhdr[2] & 3) << 16); - printf (" header[%d]: own:%d, len:%d, address:%08x data:{%04x,%04x,%04x,%04x}\n", i, own, len, addr, txhdr[0], txhdr[1], txhdr[2], txhdr[3]); - } -} diff --git a/PDP11/pdp11_xu.h b/PDP11/pdp11_xu.h deleted file mode 100644 index 83a49394..00000000 --- a/PDP11/pdp11_xu.h +++ /dev/null @@ -1,309 +0,0 @@ -/* pdp11_xu.h: DEUNA/DELUA ethernet controller information - ------------------------------------------------------------------------------ - - Copyright (c) 2003-2005, David T. Hittner - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of the author shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from the author. - - ------------------------------------------------------------------------------ - - Modification history: - - 23-Jan-08 MP Added debugging support to display packet headers and packet data - 08-Dec-05 DTH Added load_server, increased UDBSIZE for system ID parameters - 07-Jul-05 RMS Removed extraneous externs - 05-Jan-04 DTH Added network statistics - 31-Dec-03 DTH Added reserved states - 28-Dec-03 DTH Corrected MODE bitmasks - 23-Dec-03 DTH Corrected TXR and RXR bitmasks - 03-Dec-03 DTH Refitted to SIMH v3.0 platform - 05-May-03 DTH Started XU simulation - - ------------------------------------------------------------------------------ -*/ - -#ifndef _PDP11_XU_H -#define _PDP11_XU_H - - -#if defined (VM_PDP10) /* PDP10 version */ -#include "pdp10_defs.h" -#define XU_RDX 8 -#define XU_WID 16 -extern int32 int_req; - -#elif defined (VM_VAX) /* VAX version */ -#include "vax_defs.h" -#define XU_RDX 8 -#define XU_WID 16 -extern int32 int_req[IPL_HLVL]; - -#else /* PDP-11 version */ -#include "pdp11_defs.h" -#define XU_RDX 8 -#define XU_WID 16 -extern int32 int_req[IPL_HLVL]; -#endif /* VM_PDP10 */ - -#include "sim_ether.h" - -#define XU_QUE_MAX 500 /* message queue array */ -#define XU_FILTER_MAX 12 /* mac + broadcast + 10 multicast addrs */ -#define XU_SERVICE_INTERVAL 100 /* times per second */ -#define XU_ID_TIMER_VAL 540 /* 9 min * 60 sec */ -#define UDBSIZE 200 /* max size of UDB (in words) */ - -enum xu_type {XU_T_DEUNA, XU_T_DELUA}; - -struct xu_setup { - int promiscuous; /* promiscuous mode enabled */ - int multicast; /* enable all multicast addresses */ - int mac_count; /* number of multicast mac addresses */ - ETH_MAC macs[XU_FILTER_MAX]; /* MAC addresses to respond to */ -}; - -/* Network Statistics - - some of these will always be zero in the simulated environment, - since there is no ability for the sim_ether network driver to see - things like incoming runts, collision tests, babbling, etc. - */ -struct xu_stats { - uint16 secs; /* seconds since last clear */ - uint32 frecv; /* frames received */ - uint32 mfrecv; /* multicast frames received */ - uint16 rxerf; /* receive error flags */ - uint32 frecve; /* frames received with errors */ - uint32 rbytes; /* data bytes received */ - uint32 mrbytes; /* multicast data bytes received */ - uint16 rlossi; /* received frames lost - internal err */ - uint16 rlossl; /* received frames lost - local buffers */ - uint32 ftrans; /* frames transmitted */ - uint32 mftrans; /* multicast frames transmitted */ - uint32 ftrans3; /* frames transmitted with 3+ tries */ - uint32 ftrans2; /* frames transmitted - two tries */ - uint32 ftransd; /* frames transmitted - deferred */ - uint32 tbytes; /* data bytes transmitted */ - uint32 mtbytes; /* multicast data bytes transmitted */ - uint16 txerf; /* transmit error flags summary */ - uint16 ftransa; /* transmit frames aborted */ - uint16 txccf; /* transmit collision test failure */ - uint16 porterr; /* port driver errors */ - uint16 bablcnt; /* babble counter */ - uint32 loopf; /* loopback frames processed */ -}; - -struct xu_device { - /*+ initialized values - DO NOT MOVE */ - ETH_PCALLBACK rcallback; /* read callback routine */ - ETH_PCALLBACK wcallback; /* write callback routine */ - ETH_MAC mac; /* MAC address */ - enum xu_type type; /* controller type */ - /*- initialized values - DO NOT MOVE */ - - /* I/O register storage */ - uint32 irq; /* interrupt request flag */ - - /* buffers, etc. */ - ETH_DEV* etherface; - ETH_PACK read_buffer; - ETH_PACK write_buffer; - ETH_QUE ReadQ; - ETH_MAC load_server; /* load server address */ - int idtmr; /* countdown for ID Timer */ - int sectmr; /* countup for one second timer */ - struct xu_setup setup; - struct xu_stats stats; /* reportable network statistics */ - - /* copied from dec_deuna.h */ - uint16 pcsr0; /* primary DEUNA registers */ - uint16 pcsr1; - uint16 pcsr2; - uint16 pcsr3; - uint32 mode; /* mode register */ - uint32 pcbb; /* port command block base */ - uint32 stat; /* extended port status */ - - uint32 tdrb; /* transmit desc ring base */ - uint32 telen; /* transmit desc ring entry len */ - uint32 trlen; /* transmit desc ring length */ - uint32 txnext; /* transmit buffer pointer */ - uint32 rdrb; /* receive desc ring base */ - uint32 relen; /* receive desc ring entry len */ - uint32 rrlen; /* receive desc ring length */ - uint32 rxnext; /* receive buffer pointer */ - - uint16 pcb[4]; /* copy of Port Command Block */ - uint16 udb[UDBSIZE]; /* copy of Unibus Data Block */ - uint16 rxhdr[4]; /* content of RX ring entry, during wait */ - uint16 txhdr[4]; /* content of TX ring entry, during xmit */ -}; - -struct xu_controller { - DEVICE* dev; /* device block */ - UNIT* unit; /* unit block */ - DIB* dib; /* device interface block */ - struct xu_device* var; /* controller-specific variables */ -}; - -typedef struct xu_controller CTLR; - -/* PCSR0 register definitions */ -#define PCSR0_SERI 0100000 /* <15> Status Error Intr */ -#define PCSR0_PCEI 0040000 /* <14> Port Command Error Intr */ -#define PCSR0_RXI 0020000 /* <13> Receive Interrupt */ -#define PCSR0_TXI 0010000 /* <12> Transmit Interrupt */ -#define PCSR0_DNI 0004000 /* <11> Done Interrupt */ -#define PCSR0_RCBI 0002000 /* <10> Recv Buffer Unavail Intr */ -#define PCSR0_USCI 0000400 /* <08> Unsolicited State Chg Inter */ -#define PCSR0_INTR 0000200 /* <07> Interrupt Summary */ -#define PCSR0_INTE 0000100 /* <06> Interrupt Enable */ -#define PCSR0_RSET 0000040 /* <05> Reset */ -#define PCSR0_PCMD 0000017 /* <03:00> Port Command field */ - -/* PCSR0 Port Commands */ -#define CMD_NOOP 000 /* No-op */ -#define CMD_GETPCBB 001 /* Get PCB base */ -#define CMD_GETCMD 002 /* Get Command */ -#define CMD_SELFTEST 003 /* Self-test init */ -#define CMD_START 004 /* Start xmit/recv */ -#define CMD_BOOT 005 /* Boot */ -#define CMD_RSV06 006 /* Reserved */ -#define CMD_RSV07 007 /* Reserved */ -#define CMD_PDMD 010 /* Polling Demand */ -#define CMD_RSV11 011 /* Reserved */ -#define CMD_RSV12 012 /* Reserved */ -#define CMD_RSV13 013 /* Reserved */ -#define CMD_RSV14 014 /* Reserved */ -#define CMD_RSV15 015 /* Reserved */ -#define CMD_HALT 016 /* Halt */ -#define CMD_STOP 017 /* Stop */ - -/* PCSR1 register definitions */ -#define PCSR1_XPWR 0100000 /* <15> Tranceiver power failure */ -#define PCSR1_ICAB 0040000 /* <14> Port/Link cable failure */ -#define PCSR1_ECOD 0037400 /* <13:08> Self-test error code */ -#define PCSR1_PCTO 0000200 /* <07> Port Command Timeout */ -#define PCSR1_TYPE 0000160 /* <06:04> Interface type */ -#define PCSR1_STATE 0000017 /* <03:00> State: */ - -/* PCSR1 Types */ -#define TYPE_DEUNA (0 << 4) /* Controller is a DEUNA */ -#define TYPE_DELUA (1 << 4) /* Controller is a DELUA */ - -/* PCSR1 States */ -#define STATE_RESET 000 /* Reset */ -#define STATE_PLOAD 001 /* Primary Load */ -#define STATE_READY 002 /* Ready */ -#define STATE_RUNNING 003 /* Running */ -#define STATE_UHALT 005 /* UNIBUS Halted */ -#define STATE_NHALT 006 /* NI Halted */ -#define STATE_NUHALT 007 /* NI and UNIBUS Halted */ -#define STATE_HALT 010 /* Halted */ -#define STATE_SLOAD 017 /* Secondary Load */ - -/* Status register definitions */ -#define STAT_ERRS 0100000 /* <15> error summary */ -#define STAT_MERR 0040000 /* <14> multiple errors */ -#define STAT_BABL 0020000 /* <13> Transmitter on too long [DELUA only] */ -#define STAT_CERR 0010000 /* <12> collision test error */ -#define STAT_TMOT 0004000 /* <11> UNIBUS timeout */ -#define STAT_RRNG 0001000 /* <09> receive ring error */ -#define STAT_TRNG 0000400 /* <08> transmit ring error */ -#define STAT_PTCH 0000200 /* <07> ROM patch */ -#define STAT_RRAM 0000100 /* <06> running from RAM */ -#define STAT_RREV 0000077 /* <05:00> ROM version */ - -/* Mode definitions */ -#define MODE_PROM 0100000 /* <15> Promiscuous Mode */ -#define MODE_ENAL 0040000 /* <14> Enable All Multicasts */ -#define MODE_DRDC 0020000 /* <13> Disable Data Chaining */ -#define MODE_TPAD 0010000 /* <12> Transmit Msg Pad Enable */ -#define MODE_ECT 0004000 /* <11> Enable Collision Test */ -#define MODE_DMNT 0001000 /* <09> Disable Maint Message */ -#define MODE_INTL 0000200 /* <07> Internal Loopback [DELUA only] */ -#define MODE_DTCR 0000010 /* <03> Disable Transmit CRC */ -#define MODE_LOOP 0000004 /* <02> Internal Loopback Mode */ -#define MODE_HDPX 0000001 /* <00> Half-Duplex Mode */ - -/* Function Code definitions */ -#define FC_NOOP 0000000 /* no-op */ -#define FC_LSM 0000001 /* Load and Start Microaddress */ -#define FC_RDPA 0000002 /* Read Default Physical Address */ -#define FC_RPA 0000004 /* Read Physical Address */ -#define FC_WPA 0000005 /* Write Physical Address */ -#define FC_RMAL 0000006 /* Read Multicast Address List */ -#define FC_WMAL 0000007 /* Write Multicast Address List */ -#define FC_RRF 0000010 /* Read Ring Format */ -#define FC_WRF 0000011 /* Write Ring Format */ -#define FC_RDCTR 0000012 /* Read Counters */ -#define FC_RDCLCTR 0000013 /* Read and Clear Counters */ -#define FC_RMODE 0000014 /* Read Mode */ -#define FC_WMODE 0000015 /* Write Mode */ -#define FC_RSTAT 0000016 /* Read Status */ -#define FC_RCSTAT 0000017 /* Read and Clear Status */ -#define FC_DIM 0000020 /* Dump Internal Memory */ -#define FC_LIM 0000021 /* Load Internal Memory */ -#define FC_RSID 0000022 /* Read System ID parameters */ -#define FC_WSID 0000023 /* Write System ID parameters */ -#define FC_RLSA 0000024 /* Read Load Server Address */ -#define FC_WLSA 0000025 /* Write Load Server Address */ - -/* Transmitter Ring definitions */ -#define TXR_OWN 0100000 /* <15> we own it (1) */ -#define TXR_ERRS 0040000 /* <14> error summary */ -#define TXR_MTCH 0020000 /* <13> Station Match */ -#define TXR_MORE 0010000 /* <12> Mult Retries Needed */ -#define TXR_ONE 0004000 /* <11> One Collision */ -#define TXR_DEF 0002000 /* <10> Deferred */ -#define TXR_STF 0001000 /* <09> Start Of Frame */ -#define TXR_ENF 0000400 /* <08> End Of Frame */ -#define TXR_BUFL 0100000 /* <15> Buffer Length Error */ -#define TXR_UBTO 0040000 /* <14> UNIBUS TimeOut */ -#define TXR_UFLO 0020000 /* <13> Underflow Error */ -#define TXR_LCOL 0010000 /* <12> Late Collision */ -#define TXR_LCAR 0004000 /* <11> Lost Carrier */ -#define TXR_RTRY 0002000 /* <10> Retry Failure (16x) */ -#define TXR_TDR 0001777 /* <9:0> TDR value if RTRY=1 */ - -/* Receiver Ring definitions */ -#define RXR_OWN 0100000 /* <15> we own it (1) */ -#define RXR_ERRS 0040000 /* <14> Error Summary */ -#define RXR_FRAM 0020000 /* <13> Frame Error */ -#define RXR_OFLO 0010000 /* <12> Message Overflow */ -#define RXR_CRC 0004000 /* <11> CRC Check Error */ -#define RXR_STF 0001000 /* <09> Start Of Frame */ -#define RXR_ENF 0000400 /* <08> End Of Frame */ -#define RXR_BUFL 0100000 /* <15> Buffer Length error */ -#define RXR_UBTO 0040000 /* <14> UNIBUS TimeOut */ -#define RXR_NCHN 0020000 /* <13> No Data Chaining */ -#define RXR_OVRN 0010000 /* <12> Overrun Error [DELUA only] */ -#define RXR_MLEN 0007777 /* <11:0> Message Length */ - -/* debugging bitmaps */ -#define DBG_TRC 0x0001 /* trace routine calls */ -#define DBG_REG 0x0002 /* trace read/write registers */ -#define DBG_WRN 0x0004 /* display warnings */ -#define DBG_PCK 0x0080 /* display packet headers */ -#define DBG_DAT 0x0100 /* display packet data */ -#define DBG_ETH 0x8000 /* debug ethernet device */ - -#endif /* _PDP11_XU_H */ diff --git a/PDP11/txt2cbn.c b/PDP11/txt2cbn.c deleted file mode 100644 index f22415ec..00000000 --- a/PDP11/txt2cbn.c +++ /dev/null @@ -1,49 +0,0 @@ -#include - -#define ERROR 00404 -#include "pdp11_cr_dat.h" - -static int colStart = 1; /* starting column */ -static int colEnd = 80; /* ending column */ - -main () -{ - int col, c; - - while (1) { - for (col = colStart; col <= colEnd; ) { - switch (c = fgetc (stdin)) { - case EOF: - /* fall through */ - case '\n': - while (col <= colEnd) { - fputc (o29_code[' '] & 077, stdout); - fputc ((o29_code[' '] >> 6) & 077, stdout); - col++; - } - break; - case '\t': - do { - fputc (o29_code[' '] & 077, stdout); - fputc ((o29_code[' '] >> 6) & 077, stdout); - col++; - } while (((col & 07) != 1) && (col <= colEnd)); - break; - default: - fputc (o29_code[c] & 077, stdout); - fputc ((o29_code[c] >> 6) & 077, stdout); - col++; - break; - } - } - /* flush long lines, or flag over-length card */ - if (c != '\n' && c != EOF) { - printf ("overlength line\n"); - do c = fgetc (stdin); - while ((c != EOF) && (c != '\n')); - } - if (c == EOF) - break; - } - exit (1); -} diff --git a/PDP18B/pdp18b_cpu.c b/PDP18B/pdp18b_cpu.c deleted file mode 100644 index 98962378..00000000 --- a/PDP18B/pdp18b_cpu.c +++ /dev/null @@ -1,2416 +0,0 @@ -/* pdp18b_cpu.c: 18b PDP CPU simulator - - Copyright (c) 1993-2016, 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. - - cpu PDP-4/7/9/15 central processor - - 10-Mar-16 RMS Added 3-cycle databreak set/show routines - 07-Mar-16 RMS Revised to allocate memory dynamically - 28-Mar-15 RMS Revised to use sim_printf - 28-Apr-07 RMS Removed clock initialization - 26-Dec-06 RMS Fixed boundary test in KT15/XVM (Andrew Warkentin) - 30-Oct-06 RMS Added idle and infinite loop detection - 08-Oct-06 RMS Added RDCLK instruction - Fixed bug, PC off by one on fetch mem mmgt error - PDP-15 sets API 3 on mem mmgt trap (like PI) - PDP-15 sets API 4 on CAL only if 0-3 inactive - CAF clears memory management mode register - 27-Jun-06 RMS Reset clears AC, L, and MQ - 22-Sep-05 RMS Fixed declarations (Sterling Garwood) - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 22-Jul-05 RMS Removed AAS, error in V1 reference manual - 06-Nov-04 RMS Added =n to SHOW HISTORY - 26-Mar-04 RMS Fixed warning from -std=c99 - 14-Jan-04 RMS Fixed g_mode in XVM implementation - PDP-15 index, autoincrement generate 18b addresses - Revised IO device call interface - 31-Dec-03 RMS Fixed bug in cpu_set_hist - 02-Nov-03 RMS Changed PDP-9,-15 default to API - 26-Oct-03 RMS Fixed bug in PDP-4,-7,-9 autoincrement addressing - 19-Sep-03 RMS Changed instruction history to be dynamically sized - 31-Aug-03 RMS Added instruction history - Fixed PDP-15-specific implementation of API priorities - 16-Aug-03 RMS Fixed PDP-15-specific handling of EAE unsigned mul/div - 27-Jul-03 RMS Added FP15 support - Added XVM support - Added EAE option to PDP-4 - Added PDP-15 "re-entrancy ECO" - Fixed memory protect/skip interaction - Fixed CAF not to reset CPU - 12-Mar-03 RMS Added logical name support - 18-Feb-03 RMS Fixed three EAE bugs (Hans Pufal) - 05-Oct-02 RMS Added DIBs, device number support - 25-Jul-02 RMS Added DECtape support for PDP-4 - 06-Jan-02 RMS Revised enable/disable support - 30-Dec-01 RMS Added old PC queue - 30-Nov-01 RMS Added extended SET/SHOW support - 25-Nov-01 RMS Revised interrupt structure - 19-Sep-01 RMS Fixed bug in EAE (Dave Conroy) - 17-Sep-01 RMS Fixed typo in conditional - 10-Aug-01 RMS Removed register from declarations - 17-Jul-01 RMS Moved function prototype - 27-May-01 RMS Added second Teletype support, fixed bug in API - 18-May-01 RMS Added PDP-9,-15 API option - 16-May-01 RMS Fixed bugs in protection checks - 26-Apr-01 RMS Added device enable/disable support - 25-Jan-01 RMS Added DECtape support - 18-Dec-00 RMS Added PDP-9,-15 memm init register - 30-Nov-00 RMS Fixed numerous PDP-15 bugs - 14-Apr-99 RMS Changed t_addr to unsigned - - The 18b PDP family has five distinct architectural variants: PDP-1, - PDP-4, PDP-7, PDP-9, and PDP-15. Of these, the PDP-1 is so unique - as to require a different simulator. The PDP-4, PDP-7, PDP-9, and - PDP-15 are "upward compatible", with each new variant adding - distinct architectural features and incompatibilities. - - The register state for the 18b PDP's is: - - all AC<0:17> accumulator - all MQ<0:17> multiplier-quotient - all L link flag - all PC<0:x> program counter - all IORS I/O status register - PDP-7, PDP-9 EXTM extend mode - PDP-15 BANKM bank mode - PDP-7 USMD trap mode - PDP-9, PDP-15 USMD user mode - PDP-9, PDP-15 BR bounds register - PDP-15 RR relocation register - PDP-15 XVM MMR memory management register - PDP-15 XR index register - PDP-15 LR limit register - - The PDP-4, PDP-7, and PDP-9 have five instruction formats: memory - reference, load immediate, I/O transfer, EAE, and operate. The PDP-15 - adds a sixth, index operate, and a seventh, floating point. The memory - reference format for the PDP-4, PDP-7, and PDP-9, and for the PDP-15 - in bank mode, is: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | op |in| address | memory reference - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - The PDP-15 in page mode trades an address bit for indexing capability: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | op |in| X| address | memory reference - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - <0:3> mnemonic action - - 00 CAL JMS with MA = 20 - 04 DAC M[MA] = AC - 10 JMS M[MA] = L'mem'user'PC, PC = MA + 1 - 14 DZM M[MA] = 0 - 20 LAC AC = M[MA] - 24 XOR AC = AC ^ M[MA] - 30 ADD L'AC = AC + M[MA] one's complement - 34 TAD L'AC = AC + M[MA] - 40 XCT M[MA] is executed as an instruction - 44 ISZ M[MA] = M[MA] + 1, skip if M[MA] == 0 - 50 AND AC = AC & M[MA] - 54 SAD skip if AC != M[MA] - 60 JMP PC = MA - - On the PDP-4, PDP-7, and PDP-9, and the PDP-15 in bank mode, memory - reference instructions can access an address space of 32K words. The - address space is divided into four 8K word fields. An instruction can - directly address, via its 13b address, the entire current field. On the - PDP-4, PDP-7, and PDP-9, if extend mode is off, indirect addresses access - the current field; if on (or a PDP-15), they can access all 32K. - - On the PDP-15 in page mode, memory reference instructions can access - an address space of 128K words. The address is divided into four 32K - word blocks, each of which consists of eight 4K pages. An instruction - can directly address, via its 12b address, the current page. Indirect - addresses can access the current block. Indexed and autoincrement - addresses can access all 128K. - - On the PDP-4 and PDP-7, if an indirect address in in locations 00010- - 00017 of any field, the indirect address is incremented and rewritten - to memory before use. On the PDP-9 and PDP-15, only locations 00010- - 00017 of field zero autoincrement; special logic will redirect indirect - references to 00010-00017 to field zero, even if (on the PDP-9) extend - mode is off. - - The EAE format is: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 1 1 0 1| | | | | | | | | | | | | | | EAE - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | | | | | | | | | | | | | | - | | | | | | | | | | | | | +- or SC (3) - | | | | | | | | | | | | +---- or MQ (3) - | | | | | | | | | | | +------- compl MQ (3) - | | | | | | | | \______________/ - | | | | | | | | | - | | | | | \_____/ +--------- shift count - | | | | | | - | | | | | +---------------------- EAE command (3) - | | | | +---------------------------- clear AC (2) - | | | +------------------------------- or AC (2) - | | +---------------------------------- load EAE sign (1) - | +------------------------------------- clear MQ (1) - +---------------------------------------- load link (1) - - The I/O transfer format is: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 1 1 1 0 0 0| device | sdv |cl| pulse | I/O transfer - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - The IO transfer instruction sends the the specified pulse to the - specified I/O device and sub-device. The I/O device may take data - from the AC, return data to the AC, initiate or cancel operations, - or skip on status. On the PDP-4, PDP-7, and PDP-9, bits <4:5> - were designated as subdevice bits but were never used; the PDP-15 - requires them to be zero. - - On the PDP-15, the floating point format is: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 1 1 1 0 0 1| subopcode | floating point - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - |in| address | - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - Indirection is always single level. - - On the PDP-15, the index operate format is: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 1 1 1 0 1| subopcode | immediate | index operate - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - The index operate instructions provide various operations on the - index and limit registers. - - The operate format is: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 1 1 1 1 0| | | | | | | | | | | | | | operate - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | | | | | | | | | | | | | - | | | | | | | | | | | | +- CMA (3) - | | | | | | | | | | | +---- CML (3) - | | | | | | | | | | +------- OAS (3) - | | | | | | | | | +---------- RAL (3) - | | | | | | | | +------------- RAR (3) - | | | | | | | +---------------- HLT (4) - | | | | | | +------------------- SMA (1) - | | | | | +---------------------- SZA (1) - | | | | +------------------------- SNL (1) - | | | +---------------------------- invert skip (1) - | | +------------------------------- rotate twice (2) - | +---------------------------------- CLL (2) - +------------------------------------- CLA (2) - - The operate instruction can be microprogrammed to perform operations - on the AC and link. - - The load immediate format is: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 1 1 1 1 1| immediate | LAW - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - <0:4> mnemonic action - - 76 LAW AC = IR - - This routine is the instruction decode routine for the 18b PDP's. - 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 - unimplemented instruction and STOP_INST flag set - nested XCT's - I/O error in I/O simulator - - 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 - negative number is represented by the complement (XOR 0777777) of - its absolute value. Addition of 1's complement numbers requires - propagating the carry out of the high order bit back to the low - order bit. - - 4. Adding I/O devices. Three modules must be modified: - - pdp18b_defs.h add interrupt request definition - pdp18b_sys.c add sim_devices table entry -*/ - -#include "pdp18b_defs.h" - -#define SEXT(x) ((int32) (((x) & SIGN)? (x) | ~DMASK: (x) & DMASK)) - -#define UNIT_V_NOEAE (UNIT_V_UF + 0) /* EAE absent */ -#define UNIT_V_NOAPI (UNIT_V_UF + 1) /* API absent */ -#define UNIT_V_PROT (UNIT_V_UF + 2) /* protection */ -#define UNIT_V_RELOC (UNIT_V_UF + 3) /* relocation */ -#define UNIT_V_XVM (UNIT_V_UF + 4) /* XVM */ -#define UNIT_V_MSIZE (UNIT_V_UF + 5) /* dummy mask */ -#define UNIT_NOEAE (1 << UNIT_V_NOEAE) -#define UNIT_NOAPI (1 << UNIT_V_NOAPI) -#define UNIT_PROT (1 << UNIT_V_PROT) -#define UNIT_RELOC (1 << UNIT_V_RELOC) -#define UNIT_XVM (1 << UNIT_V_XVM) -#define UNIT_MSIZE (1 << UNIT_V_MSIZE) -#define OP_KSF 0700301 - -#define HIST_API 0x40000000 -#define HIST_PI 0x20000000 -#define HIST_PC 0x10000000 -#define HIST_MIN 64 -#define HIST_MAX 65536 -#define HIST_M_LVL 0x3F -#define HIST_V_LVL 6 - -typedef struct { - int32 pc; - int32 ir; - int32 ir1; - int32 lac; - int32 mq; - } InstHistory; - -#define XVM (cpu_unit.flags & UNIT_XVM) -#define RELOC (cpu_unit.flags & UNIT_RELOC) -#define PROT (cpu_unit.flags & UNIT_PROT) - -#if defined (PDP4) -#define EAE_DFLT UNIT_NOEAE -#else -#define EAE_DFLT 0 -#endif -#if defined (PDP4) || defined (PDP7) -#define API_DFLT UNIT_NOAPI -#define PROT_DFLT 0 -#define ASW_DFLT 017763 -#else -#define API_DFLT 0 -#define PROT_DFLT UNIT_PROT -#define ASW_DFLT 017720 -#endif - -int32 *M = NULL; /* memory */ -int32 LAC = 0; /* link'AC */ -int32 MQ = 0; /* MQ */ -int32 PC = 0; /* PC */ -int32 iors = 0; /* IORS */ -int32 ion = 0; /* int on */ -int32 ion_defer = 0; /* int defer */ -int32 ion_inh = 0; /* int inhibit */ -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 */ -int32 memm = 0; /* mem mode */ -#if defined (PDP15) -int32 memm_init = 1; /* mem init */ -#else -int32 memm_init = 0; -#endif -int32 usmd = 0; /* user mode */ -int32 usmd_buf = 0; /* user mode buffer */ -int32 usmd_defer = 0; /* user mode defer */ -int32 trap_pending = 0; /* trap pending */ -int32 emir_pending = 0; /* emir pending */ -int32 rest_pending = 0; /* restore pending */ -int32 BR = 0; /* mem mgt bounds */ -int32 RR = 0; /* mem mgt reloc */ -int32 MMR = 0; /* XVM mem mgt */ -int32 nexm = 0; /* nx mem flag */ -int32 prvn = 0; /* priv viol flag */ -int32 SC = 0; /* shift count */ -int32 eae_ac_sign = 0; /* EAE AC sign */ -int32 SR = 0; /* switch register */ -int32 ASW = ASW_DFLT; /* address switches */ -int32 XR = 0; /* index register */ -int32 LR = 0; /* limit register */ -int32 stop_inst = 0; /* stop on rsrv inst */ -int32 xct_max = 16; /* nested XCT limit */ -#if defined (PDP15) -int32 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ -#else -int16 pcq[PCQ_SIZE] = { 0 }; /* PC queue */ -#endif -int32 pcq_p = 0; /* PC queue ptr */ -REG *pcq_r = NULL; /* PC queue reg ptr */ -int32 hst_p = 0; /* history pointer */ -int32 hst_lnt = 0; /* history length */ -InstHistory *hst = NULL; /* instruction history */ - -t_bool build_dev_tab (void); -t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); -t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); -t_stat cpu_reset (DEVICE *dptr); -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc); -void cpu_caf (void); -void cpu_inst_hist (int32 addr, int32 inst); -void cpu_intr_hist (int32 flag, int32 lvl); -int32 upd_iors (void); -int32 api_eval (int32 *pend); -t_stat Read (int32 ma, int32 *dat, int32 cyc); -t_stat Write (int32 ma, int32 dat, int32 cyc); -t_stat Ia (int32 ma, int32 *ea, t_bool jmp); -int32 Incr_addr (int32 addr); -int32 Jms_word (int32 t); -#if defined (PDP15) -#define INDEX(i,x) if (!memm && ((i) & I_IDX)) \ - x = ((x) + XR) & DMASK -int32 Prot15 (int32 ma, t_bool bndchk); -int32 Reloc15 (int32 ma, int32 acc); -int32 RelocXVM (int32 ma, int32 acc); -extern t_stat fp15 (int32 ir); -extern int32 clk_task_upd (t_bool clr); -#else -#define INDEX(i,x) -#endif - -extern int32 clk (int32 dev, int32 pulse, int32 AC); - -int32 (*dev_tab[DEV_MAX])(int32 dev, int32 pulse, int32 AC); /* device dispatch */ - -int32 (*dev_iors[DEV_MAX])(void); /* IORS dispatch */ - -static const int32 api_ffo[256] = { - 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - -int32 api_vec[API_HLVL][32] = { - { ACH_PWRFL }, /* API 0 */ - { ACH_DTA, ACH_MTA, ACH_DRM, ACH_RF, ACH_RP, ACH_RB }, /* API 1 */ - { ACH_PTR, ACH_LPT, ACH_LPT }, /* API 2 */ - { ACH_CLK, ACH_TTI1, ACH_TTO1 } /* API 3 */ - }; - -/* CPU data structures - - cpu_dev CPU device descriptor - cpu_unit CPU unit - cpu_reg CPU register list - cpu_mod CPU modifier list -*/ - -UNIT cpu_unit = { - UDATA (NULL, UNIT_FIX+UNIT_BINK+EAE_DFLT+API_DFLT+PROT_DFLT, - MAXMEMSIZE) - }; - -REG cpu_reg[] = { - { ORDATA (PC, PC, ADDRSIZE) }, - { ORDATA (AC, LAC, 18) }, - { FLDATA (L, LAC, 18) }, - { ORDATA (MQ, MQ, 18) }, - { ORDATA (SC, SC, 6) }, - { FLDATA (EAE_AC_SIGN, eae_ac_sign, 18) }, - { ORDATA (SR, SR, 18) }, - { ORDATA (ASW, ASW, ADDRSIZE) }, - { ORDATA (IORS, iors, 18), REG_RO }, - { BRDATA (INT, int_hwre, 8, 32, API_HLVL+1), REG_RO }, - { FLDATA (INT_PEND, int_pend, 0), 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) - { FLDATA (APIENB, api_enb, 0) }, - { ORDATA (APIREQ, api_req, 8) }, - { ORDATA (APIACT, api_act, 8) }, - { ORDATA (BR, BR, ADDRSIZE) }, - { FLDATA (USMD, usmd, 0) }, - { FLDATA (USMDBUF, usmd_buf, 0) }, - { FLDATA (USMDDEF, usmd_defer, 0) }, - { FLDATA (NEXM, nexm, 0) }, - { FLDATA (PRVN, prvn, 0) }, - { FLDATA (TRAPP, trap_pending, 0) }, - { FLDATA (EXTM, memm, 0) }, - { FLDATA (EXTM_INIT, memm_init, 0) }, - { FLDATA (EMIRP, emir_pending, 0) }, - { FLDATA (RESTP, rest_pending, 0) }, - { FLDATA (PWRFL, int_hwre[API_PWRFL], INT_V_PWRFL) }, -#endif -#if defined (PDP15) - { FLDATA (ION_INH, ion_inh, 0) }, - { FLDATA (APIENB, api_enb, 0) }, - { ORDATA (APIREQ, api_req, 8) }, - { ORDATA (APIACT, api_act, 8) }, - { ORDATA (XR, XR, 18) }, - { ORDATA (LR, LR, 18) }, - { ORDATA (BR, BR, 18) }, - { ORDATA (RR, RR, 18) }, - { ORDATA (MMR, MMR, 18) }, - { FLDATA (USMD, usmd, 0) }, - { FLDATA (USMDBUF, usmd_buf, 0) }, - { FLDATA (USMDDEF, usmd_defer, 0) }, - { FLDATA (NEXM, nexm, 0) }, - { FLDATA (PRVN, prvn, 0) }, - { FLDATA (TRAPP, trap_pending, 0) }, - { FLDATA (BANKM, memm, 0) }, - { FLDATA (BANKM_INIT, memm_init, 0) }, - { FLDATA (RESTP, rest_pending, 0) }, - { FLDATA (PWRFL, int_hwre[API_PWRFL], INT_V_PWRFL) }, -#endif - { BRDATA (PCQ, pcq, 8, ADDRSIZE, PCQ_SIZE), REG_RO+REG_CIRC }, - { ORDATA (PCQP, pcq_p, 6), REG_HRO }, - { FLDATA (STOP_INST, stop_inst, 0) }, - { DRDATA (XCT_MAX, xct_max, 8), PV_LEFT + REG_NZ }, - { ORDATA (WRU, sim_int_char, 8) }, - { NULL } }; - -MTAB cpu_mod[] = { - { UNIT_NOEAE, UNIT_NOEAE, "no EAE", "NOEAE", NULL }, - { UNIT_NOEAE, 0, "EAE", "EAE", NULL }, -#if defined (PDP9) || defined (PDP15) - { UNIT_NOAPI, UNIT_NOAPI, "no API", "NOAPI", NULL }, - { UNIT_NOAPI, 0, "API", "API", NULL }, - { UNIT_PROT+UNIT_RELOC+UNIT_XVM, 0, "no memory protect", - "NOPROTECT", NULL }, - { UNIT_PROT+UNIT_RELOC+UNIT_XVM, UNIT_PROT, "memory protect", - "PROTECT", NULL }, -#endif -#if defined (PDP15) - { UNIT_PROT+UNIT_RELOC+UNIT_XVM, UNIT_PROT+UNIT_RELOC, - "memory relocation", "RELOCATION", NULL }, - { UNIT_PROT+UNIT_RELOC+UNIT_XVM, UNIT_PROT+UNIT_RELOC+UNIT_XVM, - "XVM", "XVM", NULL }, -#endif - { MTAB_XTD|MTAB_VDV, 0, "IDLE", "IDLE", &sim_set_idle, &sim_show_idle }, - { MTAB_XTD|MTAB_VDV, 0, NULL, "NOIDLE", &sim_clr_idle, NULL }, -#if defined (PDP4) - { UNIT_MSIZE, 4096, NULL, "4K", &cpu_set_size }, -#endif - { UNIT_MSIZE, 8192, NULL, "8K", &cpu_set_size }, -#if (MAXMEMSIZE > 8192) - { UNIT_MSIZE, 12288, NULL, "12K", &cpu_set_size }, - { UNIT_MSIZE, 16384, NULL, "16K", &cpu_set_size }, - { UNIT_MSIZE, 20480, NULL, "20K", &cpu_set_size }, - { UNIT_MSIZE, 24576, NULL, "24K", &cpu_set_size }, - { UNIT_MSIZE, 28672, NULL, "28K", &cpu_set_size }, - { UNIT_MSIZE, 32768, NULL, "32K", &cpu_set_size }, -#endif -#if (MAXMEMSIZE > 32768) - { UNIT_MSIZE, 49152, NULL, "48K", &cpu_set_size }, - { UNIT_MSIZE, 65536, NULL, "64K", &cpu_set_size }, - { UNIT_MSIZE, 81920, NULL, "80K", &cpu_set_size }, - { UNIT_MSIZE, 98304, NULL, "96K", &cpu_set_size }, - { UNIT_MSIZE, 114688, NULL, "112K", &cpu_set_size }, - { UNIT_MSIZE, 131072, NULL, "128K", &cpu_set_size }, -#endif - { MTAB_XTD|MTAB_VDV|MTAB_NMO|MTAB_SHP, 0, "HISTORY", "HISTORY", - &cpu_set_hist, &cpu_show_hist }, - { 0 } - }; - -DEVICE cpu_dev = { - "CPU", &cpu_unit, cpu_reg, cpu_mod, - 1, 8, ADDRSIZE, 1, 8, 18, - &cpu_ex, &cpu_dep, &cpu_reset, - NULL, NULL, NULL - }; - -t_stat sim_instr (void) -{ -int32 api_int, api_usmd, skp; -int32 iot_data, device, pulse; -int32 last_IR; -t_stat reason; - -if (build_dev_tab ()) /* build, chk tables */ - return SCPE_STOP; -PC = PC & AMASK; /* clean variables */ -LAC = LAC & LACMASK; -MQ = MQ & DMASK; -reason = 0; -last_IR = -1; -if (cpu_unit.flags & UNIT_NOAPI) /* no API? */ - api_enb = api_req = api_act = 0; -api_int = api_eval (&int_pend); /* eval API */ -api_usmd = 0; /* not API user cycle */ - -/* Main instruction fetch/decode loop */ - -while (reason == 0) { /* loop until halted */ - - int32 IR, MA, MB, esc, t, xct_count; - int32 link_init, fill; - - if (sim_interval <= 0) { /* check clock queue */ - if ((reason = sim_process_event ())) - break; - api_int = api_eval (&int_pend); /* eval API */ - } - -/* PDP-4 and PDP-7 traps and interrupts - - PDP-4 no trap - PDP-7 trap: extend mode forced on, M[0] = PC, PC = 2 - PDP-4, PDP-7 programmable interrupts only */ - -#if defined (PDP4) || defined (PDP7) -#if defined (PDP7) - - if (trap_pending) { /* trap pending? */ - PCQ_ENTRY; /* save old PC */ - MB = Jms_word (1); /* save state */ - ion = 0; /* interrupts off */ - memm = 1; /* extend on */ - emir_pending = trap_pending = 0; /* emir, trap off */ - usmd = usmd_buf = 0; /* user mode off */ - Write (0, MB, WR); /* save in 0 */ - PC = 2; /* fetch next from 2 */ - } - -#endif - - if (int_pend && ion && !ion_defer) { /* interrupt? */ - PCQ_ENTRY; /* save old PC */ - MB = Jms_word (usmd); /* save state */ - ion = 0; /* interrupts off */ - memm = 0; /* extend off */ - emir_pending = rest_pending = 0; /* emir, restore off */ - usmd = usmd_buf = 0; /* user mode off */ - Write (0, MB, WR); /* physical write */ - PC = 1; /* fetch next from 1 */ - } - - if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; - } - -#endif /* end PDP-4/PDP-7 */ - -/* PDP-9 and PDP-15 traps and interrupts - - PDP-9 trap: extend mode ???, M[0/20] = PC, PC = 0/21 - PDP-15 trap: bank mode unchanged, M[0/20] = PC, PC = 0/21 - PDP-9, PDP-15 API and program interrupts */ - -#if defined (PDP9) || defined (PDP15) - - if (trap_pending) { /* trap pending? */ - PCQ_ENTRY; /* save old PC */ - MB = Jms_word (1); /* save state */ - if (ion) { /* int on? */ - ion = 0; /* interrupts off */ - MA = 0; /* treat like PI */ -#if defined (PDP15) - ion_defer = 2; /* free instruction */ - if (!(cpu_unit.flags & UNIT_NOAPI)) { /* API? */ - api_act = api_act | API_ML3; /* set lev 3 active */ - api_int = api_eval (&int_pend); /* re-evaluate */ - } -#endif - } - else MA = 020; /* sortof like CAL */ - emir_pending = rest_pending = trap_pending = 0; /* emir,rest,trap off */ - usmd = usmd_buf = 0; /* user mode off */ - Write (MA, MB, WR); /* physical write */ - PC = MA + 1; /* fetch next */ - } - - if (api_int && !ion_defer) { /* API intr? */ - int32 i, lvl = api_int - 1; /* get req level */ - if (hst_lnt) /* record */ - cpu_intr_hist (HIST_API, lvl); - api_act = api_act | (API_ML0 >> lvl); /* set level active */ - if (lvl >= API_HLVL) { /* software req? */ - MA = ACH_SWRE + lvl - API_HLVL; /* vec = 40:43 */ - api_req = api_req & ~(API_ML0 >> lvl); /* remove request */ - } - else { - MA = 0; /* assume fails */ - 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 (&int_pend); /* no API int */ - api_usmd = usmd; /* API user mode cycle */ - usmd = usmd_buf = 0; /* user mode off */ - emir_pending = rest_pending = 0; /* emir, restore off */ - xct_count = 0; - Read (MA, &IR, FE); /* fetch instruction */ - goto xct_instr; - } - - if (int_pend && ion && !ion_defer && /* int pending, enabled? */ - !(api_enb && (api_act & API_MASKPI))) { /* API off or not masking PI? */ - PCQ_ENTRY; /* save old PC */ - if (hst_lnt) /* record */ - cpu_intr_hist (HIST_PI, 0); - MB = Jms_word (usmd); /* save state */ - ion = 0; /* interrupts off */ - ion_defer = 2; /* free instruction */ -#if defined (PDP9) /* PDP-9, */ - memm = 0; /* extend off */ -#else /* PDP-15 */ - if (!(cpu_unit.flags & UNIT_NOAPI)) { /* API? */ - api_act = api_act | API_ML3; /* set lev 3 active */ - api_int = api_eval (&int_pend); /* re-evaluate */ - } -#endif - emir_pending = rest_pending = 0; /* emir, restore off */ - usmd = usmd_buf = 0; /* user mode off */ - Write (0, MB, WR); /* physical write */ - PC = 1; /* fetch next from 1 */ - } - - if (sim_brk_summ && sim_brk_test (PC, SWMASK ('E'))) { /* breakpoint? */ - reason = STOP_IBKPT; /* stop simulation */ - break; - } - if (!usmd_defer) /* no IOT? load usmd */ - usmd = usmd_buf; - else usmd_defer = 0; /* cancel defer */ - -#endif /* PDP-9/PDP-15 */ - -/* Instruction fetch and address decode */ - - xct_count = 0; /* track nested XCT's */ - MA = PC; /* fetch at PC */ - if (Read (MA, &IR, FE)) /* fetch instruction */ - continue; - PC = Incr_addr (PC); /* increment PC */ - - xct_instr: /* label for API, XCT */ - if (hst_lnt) /* history? */ - cpu_inst_hist (MA, IR); - if (ion_defer) /* count down defer */ - ion_defer = ion_defer - 1; - if (sim_interval) - sim_interval = sim_interval - 1; - -#if defined (PDP15) /* PDP15 */ - - if (memm) /* bank mode dir addr */ - MA = (MA & B_EPCMASK) | (IR & B_DAMASK); - else MA = (MA & P_EPCMASK) | (IR & P_DAMASK); /* page mode dir addr */ - -#else /* others */ - - MA = (MA & B_EPCMASK) | (IR & B_DAMASK); /* bank mode only */ - -#endif - - switch ((IR >> 13) & 037) { /* decode IR<0:4> */ - -/* LAC: opcode 20 */ - - case 011: /* LAC, indir */ - if (Ia (MA, &MA, 0)) - break; - case 010: /* LAC, dir */ - INDEX (IR, MA); - if (Read (MA, &MB, RD)) - break; - LAC = (LAC & LINK) | MB; - break; - -/* DAC: opcode 04 */ - - case 003: /* DAC, indir */ - if (Ia (MA, &MA, 0)) - break; - case 002: /* DAC, dir */ - INDEX (IR, MA); - Write (MA, LAC & DMASK, WR); - break; - -/* DZM: opcode 14 */ - - case 007: /* DZM, indir */ - if (Ia (MA, &MA, 0)) - break; - case 006: /* DZM, direct */ - INDEX (IR, MA); - Write (MA, 0, WR); - break; - -/* AND: opcode 50 */ - - case 025: /* AND, ind */ - if (Ia (MA, &MA, 0)) - break; - case 024: /* AND, dir */ - INDEX (IR, MA); - if (Read (MA, &MB, RD)) - break; - LAC = LAC & (MB | LINK); - break; - -/* XOR: opcode 24 */ - - case 013: /* XOR, ind */ - if (Ia (MA, &MA, 0)) - break; - case 012: /* XOR, dir */ - INDEX (IR, MA); - if (Read (MA, &MB, RD)) - break; - LAC = LAC ^ MB; - break; - -/* ADD: opcode 30 */ - - case 015: /* ADD, indir */ - if (Ia (MA, &MA, 0)) - break; - case 014: /* ADD, dir */ - INDEX (IR, MA); - if (Read (MA, &MB, RD)) - break; - t = (LAC & DMASK) + MB; - if (t > DMASK) /* end around carry */ - t = (t + 1) & DMASK; - if (((~LAC ^ MB) & (LAC ^ t)) & SIGN) /* overflow? */ - LAC = LINK | t; /* set link */ - else LAC = (LAC & LINK) | t; - break; - -/* TAD: opcode 34 */ - - case 017: /* TAD, indir */ - if (Ia (MA, &MA, 0)) - break; - case 016: /* TAD, dir */ - INDEX (IR, MA); - if (Read (MA, &MB, RD)) - break; - LAC = (LAC + MB) & LACMASK; - break; - -/* ISZ: opcode 44 */ - - case 023: /* ISZ, indir */ - if (Ia (MA, &MA, 0)) - break; - case 022: /* ISZ, dir */ - INDEX (IR, MA); - if (Read (MA, &MB, RD)) - break; - MB = (MB + 1) & DMASK; - if (Write (MA, MB, WR)) - break; - if (MB == 0) - PC = Incr_addr (PC); - break; - -/* SAD: opcode 54 */ - - case 027: /* SAD, indir */ - if (Ia (MA, &MA, 0)) - break; - case 026: /* SAD, dir */ - INDEX (IR, MA); - if (Read (MA, &MB, RD)) - break; - if ((LAC & DMASK) != MB) - PC = Incr_addr (PC); - break; - -/* XCT: opcode 40 */ - - case 021: /* XCT, indir */ - if (Ia (MA, &MA, 0)) - break; - case 020: /* XCT, dir */ - INDEX (IR, MA); - if ((api_usmd | usmd) && (xct_count != 0)) { /* chained and usmd? */ - if (usmd) /* trap if usmd */ - prvn = trap_pending = 1; - break; /* nop if api_usmd */ - } - if (xct_count >= xct_max) { /* too many XCT's? */ - reason = STOP_XCT; - break; - } - xct_count = xct_count + 1; /* count XCT's */ -#if defined (PDP9) - ion_defer = 1; /* defer intr */ -#endif - if (Read (MA, &IR, FE)) /* fetch inst, mm err? */ - break; - goto xct_instr; /* go execute */ - -/* CAL: opcode 00 - api_usmd records whether usmd = 1 at start of API cycle - - On the PDP-4 and PDP-7, CAL (I) is exactly the same as JMS (I) 20 - On the PDP-9 and PDP-15, CAL clears user mode - On the PDP-9 and PDP-15 with API, CAL activates level 4 - On the PDP-15, CAL goes to absolute 20, regardless of mode */ - - case 001: case 000: /* CAL */ - t = usmd; /* save user mode */ -#if defined (PDP15) /* PDP15 */ - MA = 020; /* MA = abs 20 */ - ion_defer = 1; /* "free instruction" */ -#else /* others */ - if (memm) /* if ext, abs 20 */ - MA = 020; - else MA = (PC & B_EPCMASK) | 020; /* else bank-rel 20 */ -#endif -#if defined (PDP9) || defined (PDP15) - usmd = usmd_buf = 0; /* clear user mode */ - if ((cpu_unit.flags & UNIT_NOAPI) == 0) { /* if API, act lvl 4 */ -#if defined (PDP15) /* PDP15: if 0-3 inactive */ - if ((api_act & (API_ML0|API_ML1|API_ML2|API_ML3)) == 0) -#endif - api_act = api_act | API_ML4; - api_int = api_eval (&int_pend); - } -#endif - if (IR & I_IND) { /* indirect? */ - if (Ia (MA, &MA, 0)) - break; - } - PCQ_ENTRY; - MB = Jms_word (api_usmd | t); /* save state */ - Write (MA, MB, WR); - PC = Incr_addr (MA); - break; - -/* JMS: opcode 010 - api_usmd records whether usmd = 1 at start of API cycle */ - - case 005: /* JMS, indir */ - if (Ia (MA, &MA, 0)) - break; - case 004: /* JMS, dir */ - INDEX (IR, MA); - PCQ_ENTRY; -#if defined (PDP15) /* PDP15 */ - if (!usmd) /* "free instruction" */ - ion_defer = 1; -#endif - MB = Jms_word (api_usmd | usmd); /* save state */ - if (Write (MA, MB, WR)) - break; - PC = Incr_addr (MA) & AMASK; - break; - -/* JMP: opcode 60 */ - - case 031: /* JMP, indir */ - if (Ia (MA, &MA, 1)) - break; - INDEX (IR, MA); - PCQ_ENTRY; /* save old PC */ - PC = MA & AMASK; - break; - -/* JMP direct - check for idle */ - - case 030: /* JMP, dir */ - INDEX (IR, MA); - PCQ_ENTRY; /* save old PC */ - if (sim_idle_enab) { /* idling enabled? */ - t_bool iof = (ion_inh != 0) || /* IOF if inhibited */ - ((ion == 0) && (api_enb == 0)); /* or PI and api off */ - if (((MA ^ (PC - 2)) & AMASK) == 0) { /* 1) JMP *-1? */ - if (iof && (last_IR == OP_KSF) && /* iof, prv KSF, */ - !TST_INT (TTI)) /* no TTI flag? */ - sim_idle (0, FALSE); /* we're idle */ - } - else if (((MA ^ (PC - 1)) & AMASK) == 0) { /* 2) JMP *? */ - if (iof) /* iof? inf loop */ - reason = STOP_LOOP; - else sim_idle (0, FALSE); /* ion? idle */ - } - } /* end idle */ - PC = MA & AMASK; - break; - -/* OPR: opcode 74 */ - - case 037: /* OPR, indir */ - LAC = (LAC & LINK) | IR; /* LAW */ - break; - - case 036: /* OPR, dir */ - skp = 0; /* assume no skip */ - switch ((IR >> 6) & 017) { /* decode IR<8:11> */ - case 0: /* nop */ - break; - case 1: /* SMA */ - if ((LAC & SIGN) != 0) - skp = 1; - break; - case 2: /* SZA */ - if ((LAC & DMASK) == 0) - skp = 1; - break; - case 3: /* SZA | SMA */ - if (((LAC & DMASK) == 0) || ((LAC & SIGN) != 0)) - skp = 1; - break; - case 4: /* SNL */ - if (LAC >= LINK) - skp = 1; - break; - case 5: /* SNL | SMA */ - if (LAC >= SIGN) - skp = 1; - break; - case 6: /* SNL | SZA */ - if ((LAC >= LINK) || (LAC == 0)) - skp = 1; - break; - case 7: /* SNL | SZA | SMA */ - if ((LAC >= SIGN) || (LAC == 0)) - skp = 1; - break; - case 010: /* SKP */ - skp = 1; - break; - case 011: /* SPA */ - if ((LAC & SIGN) == 0) - skp = 1; - break; - case 012: /* SNA */ - if ((LAC & DMASK) != 0) - skp = 1; - break; - case 013: /* SNA & SPA */ - if (((LAC & DMASK) != 0) && ((LAC & SIGN) == 0)) - skp = 1; - break; - case 014: /* SZL */ - if (LAC < LINK) - skp = 1; - break; - case 015: /* SZL & SPA */ - if (LAC < SIGN) - skp = 1; - break; - case 016: /* SZL & SNA */ - if ((LAC < LINK) && (LAC != 0)) - skp = 1; - break; - case 017: /* SZL & SNA & SPA */ - if ((LAC < SIGN) && (LAC != 0)) - skp = 1; - break; - } /* end switch skips */ - - switch (((IR >> 9) & 014) | (IR & 03)) { /* IR<5:6,16:17> */ - case 0: /* NOP */ - break; - case 1: /* CMA */ - LAC = LAC ^ DMASK; - break; - case 2: /* CML */ - LAC = LAC ^ LINK; - break; - case 3: /* CML CMA */ - LAC = LAC ^ LACMASK; - break; - case 4: /* CLL */ - LAC = LAC & DMASK; - break; - case 5: /* CLL CMA */ - LAC = (LAC & DMASK) ^ DMASK; - break; - case 6: /* CLL CML = STL */ - LAC = LAC | LINK; - break; - case 7: /* CLL CML CMA */ - LAC = (LAC | LINK) ^ DMASK; - break; - case 010: /* CLA */ - LAC = LAC & LINK; - break; - case 011: /* CLA CMA = STA */ - LAC = LAC | DMASK; - break; - case 012: /* CLA CML */ - LAC = (LAC & LINK) ^ LINK; - break; - case 013: /* CLA CML CMA */ - LAC = (LAC | DMASK) ^ LINK; - break; - case 014: /* CLA CLL */ - LAC = 0; - break; - case 015: /* CLA CLL CMA */ - LAC = DMASK; - break; - case 016: /* CLA CLL CML */ - LAC = LINK; - break; - case 017: /* CLA CLL CML CMA */ - LAC = LACMASK; - break; - } /* end decode */ - - if (IR & 0000004) { /* OAS */ -#if defined (PDP9) || defined (PDP15) - if (usmd) /* trap if usmd */ - prvn = trap_pending = 1; - else if (!api_usmd) /* nop if api_usmd */ -#endif - LAC = LAC | SR; - } - - switch (((IR >> 8) & 04) | ((IR >> 3) & 03)) { /* decode IR<7,13:14> */ - case 1: /* RAL */ - LAC = ((LAC << 1) | (LAC >> 18)) & LACMASK; - break; - case 2: /* RAR */ - LAC = ((LAC >> 1) | (LAC << 18)) & LACMASK; - break; - case 3: /* RAL RAR */ -#if defined (PDP15) /* PDP-15 */ - LAC = (LAC + 1) & LACMASK; /* IAC */ -#else /* PDP-4,-7,-9 */ - reason = stop_inst; /* undefined */ -#endif - break; - case 5: /* RTL */ - LAC = ((LAC << 2) | (LAC >> 17)) & LACMASK; - break; - case 6: /* RTR */ - LAC = ((LAC >> 2) | (LAC << 17)) & LACMASK; - break; - case 7: /* RTL RTR */ -#if defined (PDP15) /* PDP-15 */ - LAC = ((LAC >> 9) & 0777) | ((LAC & 0777) << 9) | - (LAC & LINK); /* BSW */ -#else /* PDP-4,-7,-9 */ - reason = stop_inst; /* undefined */ -#endif - break; - } /* end switch rotate */ - - if (IR & 0000040) { /* HLT */ - if (usmd) /* trap if usmd */ - prvn = trap_pending = 1; - else if (!api_usmd) /* nop if api_usmd */ - reason = STOP_HALT; - } - if (skp) /* if skip, inc PC */ - PC = Incr_addr (PC); - break; /* end OPR */ - -/* EAE: opcode 64 - - The EAE is microprogrammed to execute variable length signed and - unsigned shift, multiply, divide, and normalize. Most commands are - controlled by a six bit step counter (SC). In the hardware, the step - counter is complemented on load and then counted up to zero; timing - guarantees an initial increment, which completes the two's complement - load. In the simulator, the SC is loaded normally and then counted - down to zero; the read SC command compensates. */ - - case 033: case 032: /* EAE */ - if (cpu_unit.flags & UNIT_NOEAE) /* disabled? */ - break; - if (IR & 0020000) /* IR<4>? AC0 to L */ - LAC = ((LAC << 1) & LINK) | (LAC & DMASK); - if (IR & 0010000) /* IR<5>? clear MQ */ - MQ = 0; - if ((IR & 0004000) && (LAC & SIGN)) /* IR<6> and minus? */ - eae_ac_sign = LINK; /* set eae_ac_sign */ - else eae_ac_sign = 0; /* if not, unsigned */ - if (IR & 0002000) /* IR<7>? or AC */ - MQ = (MQ | LAC) & DMASK; - else if (eae_ac_sign) /* if not, |AC| */ - LAC = LAC ^ DMASK; - if (IR & 0001000) /* IR<8>? clear AC */ - LAC = LAC & LINK; - link_init = LAC & LINK; /* link temporary */ - fill = link_init? DMASK: 0; /* fill = link */ - esc = IR & 077; /* get eff SC */ - switch ((IR >> 6) & 07) { /* case on IR<9:11> */ - - case 0: /* setup */ - if (IR & 04) /* IR<15>? ~MQ */ - MQ = MQ ^ DMASK; - if (IR & 02) /* IR<16>? or MQ */ - LAC = LAC | MQ; - if (IR & 01) /* IR<17>? or SC */ - LAC = LAC | ((-SC) & 077); - break; - -/* Multiply uses a shift and add algorithm. The PDP-15, unlike prior - implementations, factors IR<6> (signed multiply) into the calculation - of the result sign. */ - - case 1: /* multiply */ - if (Read (PC, &MB, FE)) /* get next word */ - break; - PC = Incr_addr (PC); /* increment PC */ - if (eae_ac_sign) /* EAE AC sign? ~MQ */ - MQ = MQ ^ DMASK; - LAC = LAC & DMASK; /* clear link */ - SC = esc; /* init SC */ - do { /* loop */ - if (MQ & 1) /* MQ<17>? add */ - LAC = LAC + MB; - MQ = (MQ >> 1) | ((LAC & 1) << 17); - LAC = LAC >> 1; /* shift AC'MQ right */ - SC = (SC - 1) & 077; /* decrement SC */ - } while (SC != 0); /* until SC = 0 */ -#if defined (PDP15) - if ((IR & 0004000) && (eae_ac_sign ^ link_init)) { -#else - if (eae_ac_sign ^ link_init) { /* result negative? */ -#endif - LAC = LAC ^ DMASK; - MQ = MQ ^ DMASK; - } - break; - -/* Divide uses a non-restoring divide. Divide uses a subtract and shift - algorithm. The quotient is generated in true form. The PDP-15, unlike - prior implementations, factors IR<6> (signed divide) into the calculation - of the result sign. */ - - case 3: /* divide */ - if (Read (PC, &MB, FE)) /* get next word */ - break; - PC = Incr_addr (PC); /* increment PC */ - if (eae_ac_sign) /* EAE AC sign? ~MQ */ - MQ = MQ ^ DMASK; - if ((LAC & DMASK) >= MB) { /* overflow? */ - LAC = (LAC - MB) | LINK; /* set link */ - break; - } - LAC = LAC & DMASK; /* clear link */ - t = 0; /* init loop */ - SC = esc; /* init SC */ - do { /* loop */ - if (t) - LAC = (LAC + MB) & LACMASK; - else LAC = (LAC - MB) & LACMASK; - t = (LAC >> 18) & 1; /* quotient bit */ - if (SC > 1) /* skip if last */ - LAC =((LAC << 1) | (MQ >> 17)) & LACMASK; - MQ = ((MQ << 1) | (t ^ 1)) & DMASK; /* shift in quo bit */ - SC = (SC - 1) & 077; /* decrement SC */ - } while (SC != 0); /* until SC = 0 */ - if (t) - LAC = (LAC + MB) & LACMASK; - if (eae_ac_sign) /* sgn rem = sgn divd */ - LAC = LAC ^ DMASK; -#if defined (PDP15) - if ((IR & 0004000) && (eae_ac_sign ^ link_init)) -#else - if (eae_ac_sign ^ link_init) /* result negative? */ -#endif - MQ = MQ ^ DMASK; - break; - -/* EAE shifts, whether left or right, fill from the link. If the - operand sign has been copied to the link, this provides correct - sign extension for one's complement numbers. */ - - case 4: /* normalize */ -#if defined (PDP15) - if (!usmd) /* free instructions */ - ion_defer = 2; -#endif - for (SC = esc; ((LAC & SIGN) == ((LAC << 1) & SIGN)); ) { - LAC = (LAC << 1) | ((MQ >> 17) & 1); - MQ = (MQ << 1) | (link_init >> 18); - SC = (SC - 1) & 077; - if (SC == 0) - break; - } - LAC = link_init | (LAC & DMASK); /* trim AC, restore L */ - MQ = MQ & DMASK; /* trim MQ */ - SC = SC & 077; /* trim SC */ - break; - - case 5: /* long right shift */ - if (esc < 18) { - MQ = ((LAC << (18 - esc)) | (MQ >> esc)) & DMASK; - LAC = ((fill << (18 - esc)) | (LAC >> esc)) & LACMASK; - } - else { - if (esc < 36) - MQ = ((fill << (36 - esc)) | (LAC >> (esc - 18))) & DMASK; - else MQ = fill; - LAC = link_init | fill; - } - SC = 0; /* clear step count */ - break; - - case 6: /* long left shift */ - if (esc < 18) { - LAC = link_init | (((LAC << esc) | (MQ >> (18 - esc))) & DMASK); - MQ = ((MQ << esc) | (fill >> (18 - esc))) & DMASK; - } - else { - if (esc < 36) - LAC = link_init | (((MQ << (esc - 18)) | (fill >> (36 - esc))) & DMASK); - else LAC = link_init | fill; - MQ = fill; - } - SC = 0; /* clear step count */ - break; - - case 7: /* AC left shift */ - if (esc < 18) - LAC = link_init | (((LAC << esc) | (fill >> (18 - esc))) & DMASK); - else LAC = link_init | fill; - SC = 0; /* clear step count */ - break; - } /* end switch IR */ - break; /* end case EAE */ - -/* PDP-15 index operates: opcode 72 */ - - case 035: /* index operates */ - -#if defined (PDP15) - t = (IR & 0400)? (IR | 0777000): (IR & 0377); /* sext immediate */ - switch ((IR >> 9) & 017) { /* case on IR<5:8> */ - case 001: /* PAX */ - XR = LAC & DMASK; - break; - case 002: /* PAL */ - LR = LAC & DMASK; - break; - case 003: /* AAC */ - LAC = (LAC & LINK) | ((LAC + t) & DMASK); - break; - case 004: /* PXA */ - LAC = (LAC & LINK) | XR; - break; - case 005: /* AXS */ - XR = (XR + t) & DMASK; - if (SEXT (XR) >= SEXT (LR)) - PC = Incr_addr (PC); - break; - case 006: /* PXL */ - LR = XR; - break; - case 010: /* PLA */ - LAC = (LAC & LINK) | LR; - break; - case 011: /* PLX */ - XR = LR; - break; - case 014: /* CLAC */ - LAC = LAC & LINK; - break; - case 015: /* CLX */ - XR = 0; - break; - case 016: /* CLLR */ - LR = 0; - break; - case 017: /* AXR */ - XR = (XR + t) & DMASK; - break; - } /* end switch IR */ - break; /* end case */ -#endif - -/* IOT: opcode 70 - - The 18b PDP's have different definitions of various control IOT's. - - IOT PDP-4 PDP-7 PDP-9 PDP-15 - - 700002 IOF IOF IOF IOF - 700022 undefined undefined undefined ORMM (XVM) - 700042 ION ION ION ION - 700024 undefined undefined undefined LDMM (XVM) - 700062 undefined ITON undefined undefined - 701701 undefined undefined MPSK MPSK - 701741 undefined undefined MPSNE MPSNE - 701702 undefined undefined MPCV MPCV - 701722 undefined undefined undefined MPRC (XVM) - 701742 undefined undefined MPEU MPEU - 701704 undefined undefined MPLD MPLD - 701724 undefined undefined undefined MPLR (KT15, XVM) - 701744 undefined undefined MPCNE MPCNE - 701764 undefined undefined undefined IPFH (XVM) - 703201 undefined undefined PFSF PFSF - 703301 undefined TTS TTS TTS - 703341 undefined SKP7 SKP7 SPCO - 703302 undefined CAF CAF CAF - 703304 undefined undefined DBK DBK - 703344 undefined undefined DBR DBR - 705501 undefined undefined SPI SPI - 705521 undefined undefined undefined ENB - 705502 undefined undefined RPL RPL - 705522 undefined undefined undefined INH - 705504 undefined undefined ISA ISA - 707701 undefined SEM SEM undefined - 707741 undefined undefined undefined SKP15 - 707761 undefined undefined undefined SBA - 707702 undefined EEM EEM undefined - 707742 undefined EMIR EMIR RES - 707762 undefined undefined undefined DBA - 707704 undefined LEM LEM undefined - 707764 undefined undefined undefined EBA */ - - case 034: /* IOT */ -#if defined (PDP15) - if (IR & 0010000) { /* floating point? */ - reason = fp15 (IR); /* process */ - break; - } -#endif - if ((api_usmd | usmd) && /* user, not XVM UIOT? */ - (!XVM || !(MMR & MM_UIOT))) { - if (usmd) /* trap if user */ - prvn = trap_pending = 1; - break; /* nop if api_usmd */ - } - device = (IR >> 6) & 077; /* device = IR<6:11> */ - pulse = IR & 067; /* pulse = IR<12:17> */ - if (IR & 0000010) /* clear AC? */ - LAC = LAC & LINK; - iot_data = LAC & DMASK; /* AC unchanged */ - -/* PDP-4 system IOT's */ - -#if defined (PDP4) - switch (device) { /* decode IR<6:11> */ - - case 0: /* CPU and clock */ - if (pulse == 002) /* IOF */ - ion = 0; - else if (pulse == 042) /* ION */ - ion = ion_defer = 1; - else iot_data = clk (device, pulse, iot_data); - break; -#endif - -/* PDP-7 system IOT's */ - -#if defined (PDP7) - switch (device) { /* decode IR<6:11> */ - - case 0: /* CPU and clock */ - if (pulse == 002) /* IOF */ - ion = 0; - else if (pulse == 042) /* ION */ - ion = ion_defer = 1; - else if (pulse == 062) /* ITON */ - usmd = usmd_buf = ion = ion_defer = 1; - else iot_data = clk (device, pulse, iot_data); - break; - - case 033: /* CPU control */ - if ((pulse == 001) || (pulse == 041)) - PC = Incr_addr (PC); - else if (pulse == 002) /* CAF - skip CPU */ - reset_all (1); - break; - - case 077: /* extended memory */ - if ((pulse == 001) && memm) - PC = Incr_addr (PC); - else if (pulse == 002) /* EEM */ - memm = 1; - else if (pulse == 042) /* EMIR */ - memm = emir_pending = 1; /* ext on, restore */ - else if (pulse == 004) /* LEM */ - memm = 0; - break; -#endif - -/* PDP-9 system IOT's */ - -#if defined (PDP9) - ion_defer = 1; /* delay interrupts */ - usmd_defer = 1; /* defer load user */ - switch (device) { /* decode IR<6:11> */ - - case 000: /* CPU and clock */ - if (pulse == 002) /* IOF */ - ion = 0; - else if (pulse == 042) /* ION */ - ion = ion_defer = 1; - else iot_data = clk (device, pulse, iot_data); - break; - - case 017: /* mem protection */ - if (PROT) { /* enabled? */ - if ((pulse == 001) && prvn) /* MPSK */ - PC = Incr_addr (PC); - else if ((pulse == 041) && nexm) /* MPSNE */ - PC = Incr_addr (PC); - else if (pulse == 002) /* MPCV */ - prvn = 0; - else if (pulse == 042) /* MPEU */ - usmd_buf = 1; - else if (pulse == 004) /* MPLD */ - BR = LAC & BRMASK; - else if (pulse == 044) /* MPCNE */ - nexm = 0; - } - else reason = stop_inst; - break; - - case 032: /* power fail */ - if ((pulse == 001) && (TST_INT (PWRFL))) - PC = Incr_addr (PC); - break; - - case 033: /* CPU control */ - if ((pulse == 001) || (pulse == 041)) - PC = Incr_addr (PC); - else if (pulse == 002) { /* CAF */ - reset_all (1); /* reset all exc CPU */ - cpu_caf (); /* CAF to CPU */ - } - else if (pulse == 044) /* DBR */ - rest_pending = 1; - if (((cpu_unit.flags & UNIT_NOAPI) == 0) && (pulse & 004)) { - int32 t = api_ffo[api_act & 0377]; - api_act = api_act & ~(API_ML0 >> t); - } - break; - - case 055: /* API control */ - if (cpu_unit.flags & UNIT_NOAPI) - reason = stop_inst; - else if (pulse == 001) { /* SPI */ - if (((LAC & SIGN) && api_enb) || - ((LAC & 0377) > api_act)) - iot_data = iot_data | IOT_SKP; - } - else if (pulse == 002) { /* RPL */ - iot_data = iot_data | (api_enb << 17) | - (api_req << 8) | api_act; - } - else if (pulse == 004) { /* ISA */ - api_enb = (iot_data & SIGN)? 1: 0; - api_req = api_req | ((LAC >> 8) & 017); /* swre levels only */ - api_act = api_act | (LAC & 0377); - } - break; - - case 077: /* extended memory */ - if ((pulse == 001) && memm) - PC = Incr_addr (PC); - else if (pulse == 002) /* EEM */ - memm = 1; - else if (pulse == 042) /* EMIR */ - memm = emir_pending = 1; /* ext on, restore */ - else if (pulse == 004) /* LEM */ - memm = 0; - break; -#endif - -/* PDP-15 system IOT's - includes "re-entrancy ECO" ENB/INH as standard */ - -#if defined (PDP15) - ion_defer = 1; /* delay interrupts */ - usmd_defer = 1; /* defer load user */ - switch (device) { /* decode IR<6:11> */ - - case 000: /* CPU and clock */ - if (pulse == 002) /* IOF */ - ion = 0; - else if (pulse == 042) /* ION */ - ion = ion_defer = 1; - else if (XVM && (pulse == 022)) /* ORMM/RDMM */ - iot_data = MMR; - else if (XVM && (pulse == 024)) /* LDMM */ - MMR = iot_data; - else iot_data = clk (device, pulse, iot_data); - break; - - case 017: /* mem protection */ - if (PROT) { /* enabled? */ - t = XVM? BRMASK_XVM: BRMASK; - if ((pulse == 001) && prvn) /* MPSK */ - PC = Incr_addr (PC); - else if ((pulse == 041) && nexm) /* MPSNE */ - PC = Incr_addr (PC); - else if (pulse == 002) /* MPCV */ - prvn = 0; - else if (pulse == 042) /* MPEU */ - usmd_buf = 1; - else if (XVM && (pulse == 062)) /* RDCLK */ - iot_data = clk_task_upd (TRUE); - else if (pulse == 004) /* MPLD */ - BR = LAC & t; - else if (RELOC && (pulse == 024)) /* MPLR */ - RR = LAC & t; - else if (pulse == 044) /* MPCNE */ - nexm = 0; - } - else reason = stop_inst; - break; - - case 032: /* power fail */ - if ((pulse == 001) && (TST_INT (PWRFL))) - PC = Incr_addr (PC); - break; - - case 033: /* CPU control */ - if ((pulse == 001) || (pulse == 041)) - PC = Incr_addr (PC); - else if (pulse == 002) { /* CAF */ - reset_all (2); /* reset all exc CPU, FP15 */ - cpu_caf (); /* CAF to CPU */ - } - else if (pulse == 044) /* DBR */ - rest_pending = 1; - if (((cpu_unit.flags & UNIT_NOAPI) == 0) && (pulse & 004)) { - int32 t = api_ffo[api_act & 0377]; - api_act = api_act & ~(API_ML0 >> t); - } - break; - - case 055: /* API control */ - if (cpu_unit.flags & UNIT_NOAPI) - reason = stop_inst; - else if (pulse == 001) { /* SPI */ - if (((LAC & SIGN) && api_enb) || - ((LAC & 0377) > api_act)) - iot_data = iot_data | IOT_SKP; - } - else if (pulse == 002) { /* RPL */ - iot_data = iot_data | (api_enb << 17) | - (api_req << 8) | api_act; - } - else if (pulse == 004) { /* ISA */ - api_enb = (iot_data & SIGN)? 1: 0; - api_req = api_req | ((LAC >> 8) & 017); /* swre levels only */ - api_act = api_act | (LAC & 0377); - } - else if (pulse == 021) /* ENB */ - ion_inh = 0; - else if (pulse == 022) /* INH */ - ion_inh = 1; - break; - - case 077: /* bank addressing */ - if ((pulse == 041) || ((pulse == 061) && memm)) - PC = Incr_addr (PC); /* SKP15, SBA */ - else if (pulse == 042) /* RES */ - rest_pending = 1; - else if (pulse == 062) /* DBA */ - memm = 0; - else if (pulse == 064) /* EBA */ - memm = 1; - break; -#endif - -/* IOT, continued */ - - default: /* devices */ - if (dev_tab[device]) /* defined? */ - iot_data = dev_tab[device] (device, pulse, iot_data); - else reason = stop_inst; /* stop on flag */ - break; - } /* end switch device */ - - LAC = LAC | (iot_data & DMASK); - if (iot_data & IOT_SKP) - PC = Incr_addr (PC); - if (iot_data >= IOT_REASON) - reason = iot_data >> IOT_V_REASON; - api_int = api_eval (&int_pend); /* eval API */ - break; /* end case IOT */ - } /* end switch opcode */ - - api_usmd = 0; /* API cycle over */ - last_IR = IR; /* save IR for next */ - } /* end while */ - -/* Simulation halted */ - -iors = upd_iors (); /* get IORS */ -pcq_r->qptr = pcq_p; /* update pc q ptr */ -return reason; -} - -/* Evaluate API */ - -int32 api_eval (int32 *pend) -{ -int32 i, hi; - -*pend = 0; /* assume no intr */ -#if defined (PDP15) /* PDP15 only */ -if (ion_inh) /* inhibited? */ - return 0; -#endif -for (i = 0; i < API_HLVL+1; i++) { /* any intr? */ - if (int_hwre[i]) - *pend = 1; - } -if (api_enb == 0) /* off? no req */ - return 0; -api_req = api_req & ~(API_ML0|API_ML1|API_ML2|API_ML3); /* clr req<0:3> */ -for (i = 0; i < API_HLVL; i++) { /* loop thru levels */ - if (int_hwre[i]) /* req on level? */ - api_req = api_req | (API_ML0 >> 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; -} - -/* Process IORS instruction */ - -int32 upd_iors (void) -{ -int32 d, p; - -d = (ion? IOS_ION: 0); /* ION */ -for (p = 0; dev_iors[p] != NULL; p++) /* loop thru table */ - d = d | dev_iors[p](); /* OR in results */ -return d; -} - -#if defined (PDP4) || defined (PDP7) - -/* Read, write, indirect, increment routines - On the PDP-4 and PDP-7, - There are autoincrement locations in every field. If a field - does not exist, it is impossible to generate an - autoincrement reference (all instructions are CAL). - Indirect addressing range is determined by extend mode. - JMP I with EMIR pending can only clear extend - There is no memory protection, nxm reads zero and ignores writes. */ - -t_stat Read (int32 ma, int32 *dat, int32 cyc) -{ -ma = ma & AMASK; -if (MEM_ADDR_OK (ma)) - *dat = M[ma] & DMASK; -else *dat = 0; -return MM_OK; -} - -t_stat Write (int32 ma, int32 dat, int32 cyc) -{ -ma = ma & AMASK; -if (MEM_ADDR_OK (ma)) - M[ma] = dat & DMASK; -return MM_OK; -} - -t_stat Ia (int32 ma, int32 *ea, t_bool jmp) -{ -int32 t; -t_stat sta = MM_OK; - -if ((ma & B_DAMASK & ~07) == 010) { /* autoindex? */ - Read (ma, &t, DF); /* add 1 before use */ - t = (t + 1) & DMASK; - sta = Write (ma, t, DF); - } -else sta = Read (ma, &t, DF); /* fetch indirect */ -if (jmp) { /* jmp i? */ - if (emir_pending && (((t >> 16) & 1) == 0)) - memm = 0; - emir_pending = rest_pending = 0; - } -if (memm) /* extend? 15b ia */ - *ea = t & IAMASK; -else *ea = (ma & B_EPCMASK) | (t & B_DAMASK); /* bank-rel ia */ -return sta; -} - -int32 Incr_addr (int32 ma) -{ -return ((ma & B_EPCMASK) | ((ma + 1) & B_DAMASK)); -} - -int32 Jms_word (int32 t) -{ -return (((LAC & LINK) >> 1) | ((memm & 1) << 16) | - ((t & 1) << 15) | (PC & IAMASK)); -} - -#endif - -#if defined (PDP9) - -/* Read, write, indirect, increment routines - On the PDP-9, - The autoincrement registers are in field zero only. Regardless - of extend mode, indirect addressing through 00010-00017 - will access absolute locations 00010-00017. - Indirect addressing range is determined by extend mode. If - extend mode is off, and autoincrementing is used, the - resolved address is in bank 0 (KG09B maintenance manual). - JMP I with EMIR pending can only clear extend - JMP I with DBK pending restores L, user mode, extend mode - Memory protection is implemented for foreground/background operation. */ - -t_stat Read (int32 ma, int32 *dat, int32 cyc) -{ -ma = ma & AMASK; -if (usmd) { /* user mode? */ - if (!MEM_ADDR_OK (ma)) { /* nxm? */ - nexm = prvn = trap_pending = 1; /* set flags, trap */ - *dat = 0; - return MM_ERR; - } - if ((cyc != DF) && (ma < BR)) { /* boundary viol? */ - prvn = trap_pending = 1; /* set flag, trap */ - *dat = 0; - return MM_ERR; - } - } -if (MEM_ADDR_OK (ma)) /* valid mem? ok */ - *dat = M[ma] & DMASK; -else { - *dat = 0; /* set flag, no trap */ - nexm = 1; - } -return MM_OK; -} - -t_stat Write (int32 ma, int32 dat, int32 cyc) -{ -ma = ma & AMASK; -if (usmd) { - if (!MEM_ADDR_OK (ma)) { /* nxm? */ - nexm = prvn = trap_pending = 1; /* set flags, trap */ - return MM_ERR; - } - if ((cyc != DF) && (ma < BR)) { /* boundary viol? */ - prvn = trap_pending = 1; /* set flag, trap */ - return MM_ERR; - } - } -if (MEM_ADDR_OK (ma)) /* valid mem? ok */ - M[ma] = dat & DMASK; -else nexm = 1; /* set flag, no trap */ -return MM_OK; -} - -t_stat Ia (int32 ma, int32 *ea, t_bool jmp) -{ -int32 t; -t_stat sta = MM_OK; - -if ((ma & B_DAMASK & ~07) == 010) { /* autoindex? */ - ma = ma & 017; /* always in bank 0 */ - Read (ma, &t, DF); /* +1 before use */ - t = (t + 1) & DMASK; - sta = Write (ma, t, DF); - } -else sta = Read (ma, &t, DF); -if (jmp) { /* jmp i? */ - if (emir_pending && (((t >> 16) & 1) == 0)) - memm = 0; - if (rest_pending) { /* restore pending? */ - LAC = ((t << 1) & LINK) | (LAC & DMASK); /* restore L */ - memm = (t >> 16) & 1; /* restore extend */ - usmd = usmd_buf = (t >> 15) & 1; /* restore user */ - } - emir_pending = rest_pending = 0; - } -if (memm) /* extend? 15b ia */ - *ea = t & IAMASK; -else *ea = (ma & B_EPCMASK) | (t & B_DAMASK); /* bank-rel ia */ -return sta; -} - -int32 Incr_addr (int32 ma) -{ -return ((ma & B_EPCMASK) | ((ma + 1) & B_DAMASK)); -} - -int32 Jms_word (int32 t) -{ -return (((LAC & LINK) >> 1) | ((memm & 1) << 16) | - ((t & 1) << 15) | (PC & IAMASK)); -} - -#endif - -#if defined (PDP15) - -/* Read, write, indirect, increment routines - On the PDP-15, - The autoincrement registers are in page zero only. Regardless - of bank mode, indirect addressing through 00010-00017 - will access absolute locations 00010-00017. - Indirect addressing range is determined by autoincrementing. - Any indirect can trigger a restore. - Memory protection is implemented for foreground/background operation. - Read and write mask addresses to 17b except for XVM systems */ - -t_stat Read (int32 ma, int32 *dat, int32 cyc) -{ -int32 pa; - -if (usmd) { /* user mode? */ - if (XVM) /* XVM relocation? */ - pa = RelocXVM (ma, REL_R); - else if (RELOC) /* PDP-15 relocation? */ - pa = Reloc15 (ma, REL_R); - else pa = Prot15 (ma, cyc == FE); /* PDP-15 prot, fetch only */ - if (pa < 0) { /* error? */ - *dat = 0; - return MM_ERR; - } - } -else pa = ma & AMASK; /* no prot or reloc */ -if (MEM_ADDR_OK (pa)) /* valid mem? ok */ - *dat = M[pa] & DMASK; -else { - nexm = 1; /* set flag, no trap */ - *dat = 0; - } -return MM_OK; -} - -t_stat Write (int32 ma, int32 dat, int32 cyc) -{ -int32 pa; - -if (usmd) { /* user mode? */ - if (XVM) /* XVM relocation? */ - pa = RelocXVM (ma, REL_W); - else if (RELOC) /* PDP-15 relocation? */ - pa = Reloc15 (ma, REL_W); - else pa = Prot15 (ma, cyc != DF); /* PDP-15 prot, !defer */ - if (pa < 0) /* error? */ - return MM_ERR; - } -else pa = ma & AMASK; /* no prot or reloc */ -if (MEM_ADDR_OK (pa)) /* valid mem? ok */ - M[pa] = dat & DMASK; -else nexm = 1; /* set flag, no trap */ -return MM_OK; -} - -/* XVM will do 18b defers if user_mode and G_Mode != 0 */ - -t_stat Ia (int32 ma, int32 *ea, t_bool jmp) -{ -int32 gmode, t; -int32 damask = memm? B_DAMASK: P_DAMASK; -static const int32 g_mask[4] = { MM_G_W0, MM_G_W1, MM_G_W2, MM_G_W3 }; -t_stat sta = MM_OK; - -if ((ma & damask & ~07) == 010) { /* autoincrement? */ - ma = ma & 017; /* always in bank 0 */ - Read (ma, &t, DF); /* +1 before use */ - t = (t + 1) & DMASK; - sta = Write (ma, t, DF); - } -else sta = Read (ma, &t, DF); -if (rest_pending) { /* restore pending? */ - LAC = ((t << 1) & LINK) | (LAC & DMASK); /* restore L */ - memm = (t >> 16) & 1; /* restore bank */ - usmd = usmd_buf = (t >> 15) & 1; /* restore user */ - emir_pending = rest_pending = 0; - } -gmode = MM_GETGM (MMR); /* get G_mode */ -if (usmd && XVM && gmode) /* XVM user mode? */ - *ea = t & g_mask[gmode]; /* mask ia to size */ -else if ((ma & damask & ~07) == 010) /* autoindex? */ - *ea = t & DMASK; -else *ea = (PC & BLKMASK) | (t & IAMASK); /* within 32K */ -return sta; -} - -int32 Incr_addr (int32 ma) -{ -if (memm) - return ((ma & B_EPCMASK) | ((ma + 1) & B_DAMASK)); -return ((ma & P_EPCMASK) | ((ma + 1) & P_DAMASK)); -} - -/* XVM will store all 18b of PC if user mode and G_mode != 0 */ - -int32 Jms_word (int32 t) -{ -if (usmd && XVM && (MMR & MM_GM)) - return PC; -return (((LAC & LINK) >> 1) | ((memm & 1) << 16) | - ((t & 1) << 15) | (PC & IAMASK)); -} - -/* PDP-15 protection (KM15 option) */ - -int32 Prot15 (int32 ma, t_bool bndchk) -{ -ma = ma & AMASK; /* 17b addressing */ -if (!MEM_ADDR_OK (ma)) { /* nxm? */ - nexm = prvn = trap_pending = 1; /* set flags, trap */ - return -1; - } -if (bndchk && (ma < BR)) { /* boundary viol? */ - prvn = trap_pending = 1; /* set flag, trap */ - return -1; - } -return ma; /* no relocation */ -} - -/* PDP-15 relocation and protection (KT15 option) */ - -int32 Reloc15 (int32 ma, int32 rc) -{ -int32 pa; - -ma = ma & AMASK; /* 17b addressing */ -if (ma > (BR | 0377)) { /* boundary viol? */ - if (rc != REL_C) /* set flag, trap */ - prvn = trap_pending = 1; - return -1; - } -pa = (ma + RR) & AMASK; /* relocate address */ -if (!MEM_ADDR_OK (pa)) { /* nxm? */ - if (rc != REL_C) /* set flags, trap */ - nexm = prvn = trap_pending = 1; - return -1; - } -return pa; -} - -/* XVM relocation and protection option */ - -int32 RelocXVM (int32 ma, int32 rc) -{ -int32 pa, gmode, slr; -static const int32 g_base[4] = { MM_G_B0, MM_G_B1, MM_G_B2, MM_G_B3 }; -static const int32 slr_lnt[4] = { MM_SLR_L0, MM_SLR_L1, MM_SLR_L2, MM_SLR_L3 }; - -gmode = MM_GETGM (MMR); /* get G_mode */ -slr = MM_GETSLR (MMR); /* get segment length */ -if (MMR & MM_RDIS) /* reloc disabled? */ - pa = ma; -else if ((MMR & MM_SH) && /* shared enabled and */ - (ma >= g_base[gmode]) && /* >= shared base and */ - (ma < (g_base[gmode] + slr_lnt[slr]))) { /* < shared end? */ - if (ma & 017400) { /* ESAS? */ - if ((rc == REL_W) && (MMR & MM_WP)) { /* write and protected? */ - prvn = trap_pending = 1; /* set flag, trap */ - return -1; - } - pa = (((MMR & MM_SBR_MASK) << 8) + ma) & DMASK; /* ESAS reloc */ - } - else pa = RR + (ma & 0377); /* no, ISAS reloc */ - } -else { - if (ma > (BR | 0377)) { /* normal reloc, viol? */ - if (rc != REL_C) /* set flag, trap */ - prvn = trap_pending = 1; - return -1; - } - pa = (RR + ma) & DMASK; /* relocate address */ - } -if (!MEM_ADDR_OK (pa)) { /* nxm? */ - if (rc != REL_C) /* set flags, trap */ - nexm = prvn = trap_pending = 1; - return -1; - } -return pa; -} - -#endif - -/* Reset routine */ - -t_stat cpu_reset (DEVICE *dptr) -{ -LAC = 0; -MQ = 0; -SC = 0; -eae_ac_sign = 0; -ion = ion_defer = ion_inh = 0; -CLR_INT (PWRFL); -api_enb = api_req = api_act = 0; -BR = 0; -RR = 0; -MMR = 0; -usmd = usmd_buf = usmd_defer = 0; -memm = memm_init; -nexm = prvn = trap_pending = 0; -emir_pending = rest_pending = 0; -if (M == NULL) - M = (int32 *) calloc (MEMSIZE, sizeof (int32)); -if (M == NULL) - return SCPE_MEM; -pcq_r = find_reg ("PCQ", NULL, dptr); -if (pcq_r) - pcq_r->qptr = 0; -else return SCPE_IERR; -sim_brk_types = sim_brk_dflt = SWMASK ('E'); -return SCPE_OK; -} - -/* CAF routine (CPU reset isn't called by CAF) */ - -void cpu_caf (void) -{ -api_enb = api_req = api_act = 0; /* reset API system */ -nexm = prvn = trap_pending = 0; /* reset MM system */ -usmd = usmd_buf = usmd_defer = 0; -MMR = 0; -return; -} - -/* Memory examine */ - -t_stat cpu_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) -{ -#if defined (PDP15) -if (usmd && (sw & SWMASK ('V'))) { - if (XVM) - addr = RelocXVM (addr, REL_C); - else if (RELOC) - addr = Reloc15 (addr, REL_C); - if (((int32) addr) < 0) - return STOP_MME; - } -#endif -if (addr >= MEMSIZE) - return SCPE_NXM; -if (vptr != NULL) - *vptr = M[addr] & DMASK; -return SCPE_OK; -} - -/* Memory deposit */ - -t_stat cpu_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) -{ -#if defined (PDP15) -if (usmd && (sw & SWMASK ('V'))) { - if (XVM) - addr = RelocXVM (addr, REL_C); - else if (RELOC) - addr = Reloc15 (addr, REL_C); - if (((int32) addr) < 0) - return STOP_MME; - } -#endif -if (addr >= MEMSIZE) - return SCPE_NXM; -M[addr] = val & DMASK; -return SCPE_OK; -} - -/* Change memory size */ - -t_stat cpu_set_size (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 mc = 0; -uint32 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; -} - -/* Change device number for a device */ - -t_stat set_devno (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -DEVICE *dptr; -DIB *dibp; -uint32 newdev; -t_stat r; - -if (cptr == NULL) - return SCPE_ARG; -if (uptr == NULL) - return SCPE_IERR; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if (dibp == NULL) - return SCPE_IERR; -newdev = get_uint (cptr, 8, DEV_MAX - 1, &r); /* get new */ -if ((r != SCPE_OK) || (newdev == dibp->dev)) - return r; -dibp->dev = newdev; /* store */ -return SCPE_OK; -} - -/* Show device number for a device */ - -t_stat show_devno (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -DEVICE *dptr; -DIB *dibp; - -if (uptr == NULL) - return SCPE_IERR; -dptr = find_dev_from_unit (uptr); -if (dptr == NULL) - return SCPE_IERR; -dibp = (DIB *) dptr->ctxt; -if (dibp == NULL) - return SCPE_IERR; -fprintf (st, "devno=%02o", dibp->dev); -if (dibp->num > 1) - fprintf (st, "-%2o", dibp->dev + dibp->num - 1); -return SCPE_OK; -} - -/* CPU device handler - should never get here! */ - -int32 bad_dev (int32 dev, int32 pulse, int32 AC) -{ -return (SCPE_IERR << IOT_V_REASON) | AC; /* broken! */ -} - -/* Build device dispatch table */ - -t_bool build_dev_tab (void) -{ -DEVICE *dptr; -DIB *dibp; -uint32 i, j, p; -static const uint8 std_dev[] = -#if defined (PDP4) - { 000 }; -#elif defined (PDP7) - { 000, 033, 077 }; -#else - { 000, 017, 033, 055, 077 }; -#endif - -for (i = 0; i < DEV_MAX; i++) { /* clr tables */ - dev_tab[i] = NULL; - dev_iors[i] = NULL; - } -for (i = 0; i < ((uint32) sizeof (std_dev)); i++) /* std entries */ - dev_tab[std_dev[i]] = &bad_dev; -for (i = p = 0; (dptr = sim_devices[i]) != NULL; i++) { /* add devices */ - dibp = (DIB *) dptr->ctxt; /* get DIB */ - if (dibp && !(dptr->flags & DEV_DIS)) { /* enabled? */ - if (dibp->iors) /* if IORS, add */ - dev_iors[p++] = dibp->iors; - for (j = 0; j < dibp->num; j++) { /* loop thru disp */ - if (dibp->dsp[j]) { /* any dispatch? */ - if (dev_tab[dibp->dev + j]) { /* already filled? */ - sim_printf ("%s device number conflict at %02o\n", - sim_dname (dptr), dibp->dev + j); - return TRUE; - } - dev_tab[dibp->dev + j] = dibp->dsp[j]; /* fill */ - } /* end if dsp */ - } /* end for j */ - } /* end if enb */ - } /* end for i */ -return FALSE; -} - -/* Set in memory 3-cycle databreak register */ - -t_stat set_3cyc_reg (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -t_stat r; -int32 newv; - -if (cptr == NULL) - return SCPE_ARG; -newv = (int32) get_uint (cptr, 8, 0777777, &r); -if (r != SCPE_OK) - return SCPE_ARG; -M[val] = newv; -return SCPE_OK; -} - -/* Show in-memory 3-cycle databreak register */ - -t_stat show_3cyc_reg (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -fprintf (st, "%s=", (char *) desc); -fprint_val (st, (t_value) M[val], 8, 18, PV_RZRO); -return SCPE_OK; -} - -/* Set history */ - -t_stat cpu_set_hist (UNIT *uptr, int32 val, char *cptr, void *desc) -{ -int32 i, lnt; -t_stat r; - -if (cptr == NULL) { - for (i = 0; i < hst_lnt; i++) - hst[i].pc = 0; - hst_p = 0; - return SCPE_OK; - } -lnt = (int32) get_uint (cptr, 10, HIST_MAX, &r); -if ((r != SCPE_OK) || (lnt && (lnt < HIST_MIN))) - return SCPE_ARG; -hst_p = 0; -if (hst_lnt) { - free (hst); - hst_lnt = 0; - hst = NULL; - } -if (lnt) { - hst = (InstHistory *) calloc (lnt, sizeof (InstHistory)); - if (hst == NULL) - return SCPE_MEM; - hst_lnt = lnt; - } -return SCPE_OK; -} - -/* Show history */ - -t_stat cpu_show_hist (FILE *st, UNIT *uptr, int32 val, void *desc) -{ -int32 l, j, k, di, lnt; -char *cptr = (char *) desc; -t_value sim_eval[2]; -t_stat r; -InstHistory *h; - -if (hst_lnt == 0) /* enabled? */ - return SCPE_NOFNC; -if (cptr) { - lnt = (int32) get_uint (cptr, 10, hst_lnt, &r); - if ((r != SCPE_OK) || (lnt == 0)) - return SCPE_ARG; - } -else lnt = hst_lnt; -di = hst_p - lnt; /* work forward */ -if (di < 0) - di = di + hst_lnt; -fprintf (st, "PC L AC MQ IR\n\n"); -for (k = 0; k < lnt; k++) { /* print specified */ - h = &hst[(di++) % hst_lnt]; /* entry pointer */ - if (h->pc & HIST_PC) { /* instruction? */ - l = (h->lac >> 18) & 1; /* link */ - fprintf (st, "%06o %o %06o %06o ", h->pc & AMASK, l, h->lac & DMASK, h->mq); - sim_eval[0] = h->ir; - sim_eval[1] = h->ir1; - if ((fprint_sym (st, h->pc & AMASK, sim_eval, &cpu_unit, SWMASK ('M'))) > 0) - fprintf (st, "(undefined) %06o", h->ir); - } /* end else instruction */ - else if (h->pc & (HIST_API | HIST_PI)) { /* interrupt event? */ - if (h->pc & HIST_PI) /* PI? */ - fprintf (st, "%06o PI LVL 0-4 =", h->pc & AMASK); - else fprintf (st, "%06o API %d LVL 0-4 =", h->pc & AMASK, h->mq); - for (j = API_HLVL; j >= 0; j--) - fprintf (st, " %02o", (h->ir >> (j * HIST_V_LVL)) & HIST_M_LVL); - } - else continue; /* invalid */ - fputc ('\n', st); /* end line */ - } /* end for */ -return SCPE_OK; -} - -/* Record events in history table */ - -void cpu_inst_hist (int32 addr, int32 inst) -{ -t_value word = 0; - -hst[hst_p].pc = addr | HIST_PC; -hst[hst_p].ir = inst; -if (cpu_ex (&word, (addr + 1) & AMASK, &cpu_unit, SWMASK ('V'))) - hst[hst_p].ir1 = 0; -else hst[hst_p].ir1 = word; -hst[hst_p].lac = LAC; -hst[hst_p].mq = MQ; -hst_p = (hst_p + 1); -if (hst_p >= hst_lnt) - hst_p = 0; -return; -} - -void cpu_intr_hist (int32 flag, int32 lvl) -{ -int32 j; - -hst[hst_p].pc = PC | flag; -hst[hst_p].ir = 0; -for (j = 0; j < API_HLVL+1; j++) - hst[hst_p].ir = (hst[hst_p].ir << HIST_V_LVL) | (int_hwre[j] & HIST_M_LVL); -hst[hst_p].ir1 = 0; -hst[hst_p].lac = 0; -hst[hst_p].mq = lvl; -hst_p = (hst_p + 1); -if (hst_p >= hst_lnt) - hst_p = 0; -return; -} diff --git a/PDP18B/pdp18b_defs.h b/PDP18B/pdp18b_defs.h deleted file mode 100644 index 10295046..00000000 --- a/PDP18B/pdp18b_defs.h +++ /dev/null @@ -1,568 +0,0 @@ -/* pdp18b_defs.h: 18b PDP simulator definitions - - Copyright (c) 1993-2016, 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-Mar-16 PLB Added GRAPHICS-2 support for PDP-7 UNIX - 10-Mar-16 RMS Added 3-cycle databreak set/show routines - 26-Feb-16 RMS Added RB09 to PDP-7 for Unix "v0" and RM09 to PDP-9 - 13-Sep-15 RMS Added DR15C - 18-Apr-12 RMS Added clk_cosched prototype - 22-May-10 RMS Added check for 64b definitions - 30-Oct-06 RMS Added infinite loop stop - 14-Jan-04 RMS Revised IO device call interface - 18-Oct-03 RMS Added DECtape off reel message - 18-Jul-03 RMS Added FP15 support - Added XVM support - Added EAE option for PDP-4 - 25-Apr-03 RMS Revised for extended file support - 04-Feb-03 RMS Added RB09, LP09 support - 22-Nov-02 RMS Added PDP-4 drum support - 05-Oct-02 RMS Added DIB structure - 25-Jul-02 RMS Added PDP-4 DECtape support - 10-Feb-02 RMS Added PDP-7 DECtape support - 25-Nov-01 RMS Revised interrupt structure - 27-May-01 RMS Added second Teletype support - 21-Jan-01 RMS Added DECtape support - 14-Apr-99 RMS Changed t_addr to unsigned - 02-Jan-96 RMS Added fixed head and moving head disks - 31-Dec-95 RMS Added memory management - 19-Mar-95 RMS Added dynamic memory size - - The author gratefully acknowledges the help of Craig St. Clair and - Deb Tevonian in locating archival material about the 18b PDP's, and of - Al Kossow and Max Burnet in making documentation and software available. -*/ - -#ifndef PDP18B_DEFS_H_ -#define PDP18B_DEFS_H_ 0 - -#include "sim_defs.h" /* simulator defns */ - -#if defined(USE_INT64) || defined(USE_ADDR64) -#error "18b PDP's do not support 64b values!" -#endif - -/* Models: only one should be defined - - model memory CPU options I/O options - - PDP4 8K Type 18 EAE Type 65 KSR-28 Teletype (Baudot) - ??Type 16 mem extension integral paper tape reader - Type 75 paper tape punch - integral real time clock - Type 62 line printer (Hollerith) - Type 550/555 DECtape - Type 24 serial drum - - PDP7 32K Type 177 EAE Type 649 KSR-33 Teletype - Type 148 mem extension Type 444 paper tape reader - Type 75 paper tape punch - integral real time clock - Type 647B line printer (sixbit) - Type 550/555 DECtape - Type 24 serial drum - RB09 fixed head disk (Unix V0 only) - Bell Labs GRAPHICS-2 (Unix V0 only) - - PDP9 32K KE09A EAE KSR-33 Teletype - KF09A auto pri intr PC09A paper tape reader and punch - KG09B mem extension integral real time clock - KP09A power detection Type 647D/E line printer (sixbit) - KX09A mem protection LP09 line printer (ASCII) - RF09/RS09 fixed head disk - RB09 fixed head disk - RM09 drum - TC59 magnetic tape - TC02/TU55 DECtape - LT09A additional Teletypes - - PDP15 128K KE15 EAE KSR-35 Teletype - KA15 auto pri intr PC15 paper tape reader and punch - KF15 power detection KW15 real time clock - KM15 mem protection LP09 line printer - KT15 mem relocation LP15 line printer - FP15 floating point RP15 disk pack - XVM option RF15/RF09 fixed head disk - TC59D magnetic tape - TC15/TU56 DECtape - LT15/LT19 additional Teletypes - DR15C parallel interface to UC15 - - ??Indicates not implemented. The PDP-4 manual refers to a memory - ??extension control; there is no documentation on it. -*/ - -#if !defined (PDP4) && !defined (PDP7) && !defined (PDP9) && !defined (PDP15) -#define PDP15 0 /* default to PDP-15 */ -#endif - -/* Simulator stop codes */ - -#define STOP_RSRV 1 /* must be 1 */ -#define STOP_HALT 2 /* HALT */ -#define STOP_IBKPT 3 /* breakpoint */ -#define STOP_XCT 4 /* nested XCT's */ -#define STOP_API 5 /* invalid API int */ -#define STOP_NONSTD 6 /* non-std dev num */ -#define STOP_MME 7 /* mem mgt error */ -#define STOP_FPDIS 8 /* fp inst, fpp disabled */ -#define STOP_DTOFF 9 /* DECtape off reel */ -#define STOP_LOOP 10 /* infinite loop */ - -/* Peripheral configuration */ - -#if defined (PDP4) -#define ADDRSIZE 13 -#define KSR28 0 /* Baudot terminal */ -#define TYPE62 0 /* Hollerith printer */ -#define TYPE550 0 /* DECtape */ -#define DRM 0 /* drum */ -#elif defined (PDP7) -#define ADDRSIZE 15 -#define TYPE647 0 /* sixbit printer */ -#define TYPE550 0 /* DECtape */ -#define DRM 0 /* drum */ -#define RB 0 /* fixed head disk */ -#define GRAPHICS2 0 /* BTL display */ -#elif defined (PDP9) -#define ADDRSIZE 15 -#define TYPE647 0 /* sixbit printer */ -#define LP09 0 /* ASCII printer */ -#define RB 0 /* fixed head disk */ -#define RF 0 /* fixed head disk */ -#define DRM 0 /* drum */ -#define MTA 0 /* magtape */ -#define TC02 0 /* DECtape */ -#define TTY1 4 /* second Teletype(s) */ -#define BRMASK 0076000 /* bounds mask */ -#elif defined (PDP15) -#define ADDRSIZE 17 -#define LP09 0 /* ASCII printer */ -#define LP15 0 /* DMA printer */ -#define RF 0 /* fixed head disk */ -#define RP 0 /* disk pack */ -#define MTA 0 /* magtape */ -#define TC02 0 /* DECtape */ -#define TTY1 16 /* second Teletype(s) */ -#define UC15 0 /* UC15 */ -#define BRMASK 0377400 /* bounds mask */ -#define BRMASK_XVM 0777400 /* bounds mask, XVM */ -#endif - -/* Memory */ - -#define AMASK ((1 << ADDRSIZE) - 1) /* address mask */ -#define IAMASK 077777 /* ind address mask */ -#define BLKMASK (AMASK & (~IAMASK)) /* block mask */ -#define MAXMEMSIZE (1 << ADDRSIZE) /* max memory size */ -#define MEMSIZE (cpu_unit.capac) /* actual memory size */ -#define MEM_ADDR_OK(x) (((uint32) (x)) < MEMSIZE) - -/* Instructions */ - -#define I_V_OP 14 /* opcode */ -#define I_M_OP 017 -#define I_V_IND 13 /* indirect */ -#define I_V_IDX 12 /* index */ -#define I_IND (1 << I_V_IND) -#define I_IDX (1 << I_V_IDX) -#define B_DAMASK 017777 /* bank mode address */ -#define B_EPCMASK (AMASK & ~B_DAMASK) -#define P_DAMASK 007777 /* page mode address */ -#define P_EPCMASK (AMASK & ~P_DAMASK) - -/* Memory cycles */ - -#define FE 0 -#define DF 1 -#define RD 2 -#define WR 3 - -/* Memory status codes */ - -#define MM_OK 0 -#define MM_ERR 1 - -/* Memory management relocation checks (PDP-15 KT15 and XVM only) */ - -#define REL_C -1 /* console */ -#define REL_R 0 /* read */ -#define REL_W 1 /* write */ - -/* Architectural constants */ - -#define DMASK 0777777 /* data mask */ -#define LINK (DMASK + 1) /* link */ -#define LACMASK (LINK | DMASK) /* link + data */ -#define SIGN 0400000 /* sign bit */ -#define OP_JMS 0100000 /* JMS */ -#define OP_JMP 0600000 /* JMP */ -#define OP_HLT 0740040 /* HLT */ - -/* IOT subroutine return codes */ - -#define IOT_V_SKP 18 /* skip */ -#define IOT_V_REASON 19 /* reason */ -#define IOT_SKP (1 << IOT_V_SKP) -#define IOT_REASON (1 << IOT_V_REASON) - -#define IORETURN(f,v) ((f)? (v): SCPE_OK) /* stop on error */ - -/* PC change queue */ - -#define PCQ_SIZE 64 /* must be 2**n */ -#define PCQ_MASK (PCQ_SIZE - 1) -#define PCQ_ENTRY pcq[pcq_p = (pcq_p - 1) & PCQ_MASK] = PC - -/* XVM memory management registers */ - -#define MM_RDIS 0400000 /* reloc disabled */ -#define MM_V_GM 15 /* G mode */ -#define MM_M_GM 03 -#define MM_GM (MM_M_GM << MM_V_GM) -#define MM_G_W0 0077777 /* virt addr width */ -#define MM_G_W1 0177777 -#define MM_G_W2 0777777 -#define MM_G_W3 0377777 -#define MM_G_B0 0060000 /* SAS base */ -#define MM_G_B1 0160000 -#define MM_G_B2 0760000 -#define MM_G_B3 0360000 -#define MM_UIOT 0040000 /* user mode IOT's */ -#define MM_WP 0020000 /* share write prot */ -#define MM_SH 0010000 /* share enabled */ -#define MM_V_SLR 10 /* segment length reg */ -#define MM_M_SLR 03 -#define MM_SLR_L0 001000 /* SAS length */ -#define MM_SLR_L1 002000 -#define MM_SLR_L2 010000 -#define MM_SLR_L3 020000 -#define MM_SBR_MASK 01777 /* share base reg */ -#define MM_GETGM(x) (((x) >> MM_V_GM) & MM_M_GM) -#define MM_GETSLR(x) (((x) >> MM_V_SLR) & MM_M_SLR) - -/* Device information block */ - -#define DEV_MAXBLK 8 /* max dev block */ -#define DEV_MAX 64 /* total devices */ - -typedef struct { - uint32 dev; /* base dev number */ - uint32 num; /* number of slots */ - int32 (*iors)(void); /* IORS responder */ - int32 (*dsp[DEV_MAXBLK])(int32 dev, int32 pulse, int32 dat); - } DIB; - -/* Standard device numbers */ - -#define DEV_PTR 001 /* paper tape reader */ -#define DEV_PTP 002 /* paper tape punch */ -#define DEV_TTI 003 /* console input */ -#define DEV_TTO 004 /* console output */ -#define DEV_TTI1 041 /* extra terminals */ -#define DEV_TTO1 040 -#define DEV_DRM 060 /* drum */ -#define DEV_DR 060 /* DR15 */ -#define DEV_RP 063 /* RP15 */ -#define DEV_LPT 065 /* line printer */ -#define DEV_RF 070 /* RF09 */ -#define DEV_RB 071 /* RB09 */ -#define DEV_MT 073 /* magtape */ -#define DEV_DTA 075 /* dectape */ - -#ifdef GRAPHICS2 -/* Bell Telephone Labs GRAPHICS-2 Display System ("as large as the PDP-7") - * Used by PDP-7 UNIX as a "Glass TTY" - */ -#define DEV_G2D1 005 /* Display Ctrl 1 */ -#define DEV_G2D 006 /* (Display Ctrl 2) */ -#define DEV_G2LP 007 /* (Light Pen) */ -#define DEV_G2DS 010 /* (Display Status) */ -#define DEV_G2D3 014 /* (Display Ctrl 3) */ -#define DEV_G2D4 034 /* (Display Ctrl 4) */ - -#define DEV_G2UNK 042 /* (???) */ -#define DEV_G2KB 043 /* Keyboard */ -#define DEV_G2BB 044 /* Button Box */ -#define DEV_G2IM 045 /* (PDP7 int. mask) */ - -/* PDP-7/9 to 201A Data Phone Interface - * (status bits retrieved with G2DS IOT) - * used for UNIX to GCOS Remote Job Entry - */ -#define DEV_DP 047 /* (Data Phone) */ -#endif - -/* Interrupt system - - The interrupt system can be modelled on either the flag driven system - of the PDP-4 and PDP-7 or the API driven system of the PDP-9 and PDP-15. - If flag based, API is hard to implement; if API based, IORS requires - extra code for implementation. I've chosen an API based model. - - API channel Device API priority Notes - - 00 software 4 4 - 01 software 5 5 - 02 software 6 6 - 03 software 7 7 - 04 TC02/TC15 1 - 05 TC59D 1 - 06 drum 1 PDP-9 only - 07 RB09 1 PDP-9 only - 10 paper tape reader 2 - 11 real time clock 3 - 12 power fail 0 - 13 memory parity 0 - 14 display 2 - 15 card reader 2 - 16 line printer 2 - 17 A/D converter 0 - 20 interprocessor buffer 3 - 21 360 link 3 PDP-9 only - 22 data phone 2 PDP-15 only - 23 RF09/RF15 1 - 24 RP15 1 PDP-15 only - 25 plotter 1 PDP-15 only - 26 - - 27 - - 30 - - 31 - - 32 - - 33 - - 34 LT15 TTO 3 PDP-15 only - 35 LT15 TTI 3 PDP-15 only - 36 - - 37 - - - The DR15C uses four API channels that are assigned by software. - - On the PDP-9, any API level active masks PI, and PI does not mask API. - On the PDP-15, only the hardware API levels active mask PI, and PI masks - the API software levels. */ - -#define API_ML0 0200 /* API masks: level 0 */ -#define API_ML1 0100 -#define API_ML2 0040 -#define API_ML3 0020 -#define API_ML4 0010 -#define API_ML5 0004 -#define API_ML6 0002 -#define API_ML7 0001 /* level 7 */ - -#if defined (PDP9) /* levels which mask PI */ -#define API_MASKPI (API_ML0|API_ML1|API_ML2|API_ML3|API_ML4|API_ML5|API_ML6|API_ML7) -#else -#define API_MASKPI (API_ML0|API_ML1|API_ML2|API_ML3) -#endif - -#define API_HLVL 4 /* hwre levels */ -#define ACH_SWRE 040 /* swre int vec */ - -/* 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_V_RB 5 /* RB disk */ - -#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_RB (1 << INT_V_RB) - -#define API_DTA 1 -#define API_MTA 1 -#define API_DRM 1 -#define API_RF 1 -#define API_RP 1 -#define API_RB 1 - -#define ACH_DTA 044 -#define ACH_MTA 045 -#define ACH_DRM 046 -#define ACH_RB 047 -#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_V_G2 3 /* BTL GRAPHICS-2 */ - -#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 - -#ifdef GRAPHICS2 -/* - * A PDP-9 version existed, - * but we're only interested simulating a PDP-7 without API - */ -#define INT_G2 (1 << INT_V_G2) -#define API_G2 4 -#endif - -/* 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) - -/* The DR15C uses the same relative bit position in all four interrupt levels. - This allows software to have a single definition for the interrupt bit position, - regardless of level. The standard macros cannot be used. */ - -#define INT_V_DR 9 /* to left of all */ -#define INT_DR (1 << INT_V_DR) -#define API_DR0 0 -#define API_DR1 1 -#define API_DR2 2 -#define API_DR3 3 - -/* I/O status flags for the IORS instruction - - bit PDP-4 PDP-7 PDP-9 PDP-15 - - 0 intr on intr on intr on intr on - 1 tape rdr flag* tape rdr flag* tape rdr flag* tape rdr flag* - 2 tape pun flag* tape pun flag* tape pun flag* tape pun flag* - 3 keyboard flag* keyboard flag* keyboard flag* keyboard flag* - 4 type out flag* type out flag* type out flag* type out flag* - 5 display flag* display flag* light pen flag* light pen flag* - 6 clk ovflo flag* clk ovflo flag* clk ovflo flag* clk ovflo flag* - 7 clk enable flag clk enable flag clk enable flag clk enable flag - 8 mag tape flag* mag tape flag* tape rdr empty* tape rdr empty* - 9 card rdr col* * tape pun empty tape pun empty - 10 card rdr ~busy DECtape flag* DECtape flag* - 11 card rdr error magtape flag* magtape flag* - 12 card rdr EOF disk pack flag* - 13 card pun row* DECdisk flag* DECdisk flag* - 14 card pun error lpt flag* - 15 lpt flag* lpt flag* lpt flag* - 16 lpt space flag* lpt error flag lpt error flag - 17 drum flag* drum flag* -*/ - -#define IOS_ION 0400000 /* interrupts on */ -#define IOS_PTR 0200000 /* tape reader */ -#define IOS_PTP 0100000 /* tape punch */ -#define IOS_TTI 0040000 /* keyboard */ -#define IOS_TTO 0020000 /* terminal */ -#define IOS_LPEN 0010000 /* light pen */ -#define IOS_CLK 0004000 /* clock */ -#define IOS_CLKON 0002000 /* clock enable */ -#define IOS_DTA 0000200 /* DECtape */ -#define IOS_RP 0000040 /* disk pack */ -#define IOS_RF 0000020 /* fixed head disk */ -#define IOS_DRM 0000001 /* drum */ -#if defined (PDP4) || defined (PDP7) -#define IOS_MTA 0001000 /* magtape */ -#define IOS_LPT 0000004 /* line printer */ -#define IOS_LPT1 0000002 /* line printer stat */ -#elif defined (PDP9) -#define IOS_PTRERR 0001000 /* reader empty */ -#define IOS_PTPERR 0000400 /* punch empty */ -#define IOS_MTA 0000100 /* magtape */ -#define IOS_LPT 0000004 /* line printer */ -#define IOS_LPT1 0000002 /* line printer stat */ -#elif defined (PDP15) -#define IOS_PTRERR 0001000 /* reader empty */ -#define IOS_PTPERR 0000400 /* punch empty */ -#define IOS_MTA 0000100 /* magtape */ -#define IOS_LPT 0000010 /* line printer */ -#define IOS_LPT1 0000000 /* not used */ -#endif - -/* Function prototypes */ - -t_stat set_devno (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat show_devno (FILE *st, UNIT *uptr, int32 val, void *desc); -t_stat set_3cyc_reg (UNIT *uptr, int32 val, char *cptr, void *desc); -t_stat show_3cyc_reg (FILE *st, UNIT *uptr, int32 val, void *desc); - -int32 clk_cosched (int32 wait); - -/* Translation tables */ - -extern const int32 asc_to_baud[128]; -extern const char baud_to_asc[64]; -extern const char fio_to_asc[64]; - -#endif diff --git a/PDP18B/pdp18b_diag.txt b/PDP18B/pdp18b_diag.txt deleted file mode 100644 index 74fbd1e4..00000000 --- a/PDP18B/pdp18b_diag.txt +++ /dev/null @@ -1,110 +0,0 @@ -18b PDP Diagnostics - -1. PDP-4 - -2. PDP-7 - -2.1 PDP-7 Instruction Test (Maindec 701) - -The diagnostic must be boot loaded, as it jumps dynamically out -of the RIM load process into its own loader. - -At start, set SR<1:16> to a non-zero value. The diagnostic -executes four HLT's as part of initial tests and then runs to -completion. Normal HLT is at 2623 (PC = 2624). - -sim> att -e ptr digital-7-54-m-rim.bin -sim> boot ptr - -HALT instruction, PC: 17670 (AND 17727) -sim> d sr 4 ; any even value between 2 and 377776 -sim> run 170 - -HALT instruction, PC: 00171 (CML CMA) -sim> ex ac,l -AC: 000000 -L: 0 -sim> c - -HALT instruction, PC: 00173 (SPA) -sim> ex ac,l -AC: 777777 -L: 1 -sim> c - -HALT instruction, PC: 00176 (SPA) -sim> ex ac,l -AC: 000000 -L: 0 -sim> c - -HALT instruction, PC: 00201 (LAC 4116) -sim> ex ac,l -AC: 000004 -L: 0 -sim> c - -HALT instruction, PC: 02624 (JMP 201) - -3. PDP-9 - -4. PDP-15 - -Operating Instructions, PDP-15 diagnostics - -MAINDEC-15-D0A1-PH Instruction test 1 - -Read in: 200 -Start: 200 -Breakpoint: 7274 for one pass - -MAINDEC-15-D0A2-PH Instruction test 1A - -Read in: 200 -Start: 200 -Breakpoint: 4437 for one pass - -MAINDEC-15-D0AA-PB Index register test - -Read in: 17700 (ignored, binary tape) -Start: 200 -Halts: at 214, set BANKM = 0 -Runs to: prints END at end of pass - -MAINDEC-15-D0BB-PH Instruction test 2 - -Read in: 200 -Start: 200 -SR: 1 to run clock test -Breakpoint: 6403 for one pass - -MAINDEC-15-D0CA-PH Memory address test - -Read in: 7200 -Start: 7200 -Breakpoint: 7577 for one pass - -MAINDEC-15-D0EA-PH JMP-Y interrupt test - -Read in: 7400 -Start: 7400 -Breakpoint: 7551 for one pass - -MAINDEC-15-D0FA-PH JMS-Y interrupt test - -Read in: 7400 -Start: 7400 -Breakpoint: 7577 for one pass - -MAINDEC-15-D0KA-PH ISZ test - -Read in: 200 -Start: 200 -Breakpoint: 7704 for one pass - -MAINDEC-15-D1CD-PB Extended memory test - -Read in: 200 (ignored, binary tape) -Start: 200 -Halts after printout, set SR = 30000 -Breakpoint: 563 for one pass diff --git a/PDP18B/pdp18b_dr15.c b/PDP18B/pdp18b_dr15.c deleted file mode 100644 index 6fae0b76..00000000 --- a/PDP18B/pdp18b_dr15.c +++ /dev/null @@ -1,339 +0,0 @@ -/* pdp18b_dr15.c: DR15C simulator - - Copyright (c) 2016, 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. - - dr PDP-15 DR15C interface for UC15 system - - The DR15C provides control communications with the DR11Cs in the UC15. - Its state consists of an 18b register (the Task Control Block Pointer), - a one bit flag (TCBP acknowledge, not wired to interrupt), four interrupt - requests wired to API, four interrupt vectors for the API levels, and an - API interrupt enable/disable flag. - - The PDP15 and UC15 use a master/save communications protocol. - - The PDP15 initiates a request to the PDP11 by writing TCBP and - clearing TCBP acknowledge. This alerts/interrupts the PDP11. - - The PDP11 reads TCBP. This sets TCBP acknowledge. - - The PDP11 processes the request. - - The PDP11 signals completion by writing a vector into one of - four API request levels. - - The PDP15 is interrupted, and the request is considered complete. - - The DR15 must "call out" to the UC15 to signal two conditions: - - a new TCBP has been written - - API requests have been updated - - The UC15 must "call in" to the DR15 for two reasons: - - the TCBP has been read - - an API interrupt is requested - - The DR15 and UC15 use a shared memory section and ATOMIC operations - to communicate. Shared state is maintained in shared memory, with one - side having read/write access, the other read-only. Actions are - implemented by setting signals with an atomic compare-and-swap. - The signals may be polled with non-atomic operations but must be - verified with an atomic compare-and-swap. - - Debug hooks - when DEBUG is turned on, the simulator will print - information relating to PIREX operation. -*/ - -#include "pdp18b_defs.h" -#include "sim_shmem.h" -#include "uc15_defs.h" - -/* Declarations */ - -extern int32 int_hwre[API_HLVL+1]; -extern int32 api_vec[API_HLVL][32]; -extern int32 *M; -extern UNIT cpu_unit; - -uint32 dr15_tcbp = 0; /* buffer = TCB ptr */ -int32 dr15_tcb_ack = 0; /* TCBP write ack */ -int32 dr15_ie = 0; /* int enable */ -uint32 dr15_int_req = 0; /* int req 0-3 */ -int32 dr15_poll = 3; /* polling interval */ -SHMEM *uc15_shmem = NULL; /* shared state identifier */ -int32 *uc15_shstate = NULL; /* shared state base */ -SHMEM *pdp15_shmem = NULL; /* PDP15 mem identifier */ - -DEVICE dr15_dev; -int32 dr60 (int32 dev, int32 pulse, int32 AC); -int32 dr61 (int32 dev, int32 pulse, int32 AC); -t_stat dr15_reset (DEVICE *dptr); -void dr15_set_clr_ie (int32 val); -t_stat dr15_svc (UNIT *uptr); -t_stat dr15_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw); -t_stat dr15_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw); -t_stat dr15_attach (UNIT *uptr, char *cptr); -t_stat dr15_detach (UNIT *uptr); - -t_stat uc15_new_api (int32 val); /* callouts */ -t_stat uc15_tcbp_wr (int32 val); - -/* DR15 data structures - - dr15_dev DR15 device descriptor - dr15_unit DR15 unit descriptor - dr15_reg DR15 register list -*/ - -DIB dr15_dib = { DEV_DR, 2 ,NULL, { &dr60, &dr61 } }; - -UNIT dr15_unit = { - UDATA (&dr15_svc, UNIT_FIX+UNIT_BINK+UNIT_ATTABLE, UC15_STATE_SIZE) - }; - -REG dr15_reg[] = { - { ORDATA (TCBP, dr15_tcbp, ADDRSIZE) }, - { FLDATA (TCBACK, dr15_tcb_ack, 0) }, - { FLDATA (IE, dr15_ie, 0) }, - { ORDATA (REQ, dr15_int_req, 4) }, - { FLDATA (API0, int_hwre[API_DR0], INT_V_DR) }, - { FLDATA (API1, int_hwre[API_DR1], INT_V_DR) }, - { FLDATA (API2, int_hwre[API_DR2], INT_V_DR) }, - { FLDATA (API3, int_hwre[API_DR3], INT_V_DR) }, - { ORDATA (APIVEC0, api_vec[API_DR0][INT_V_DR], 7) }, - { ORDATA (APIVEC1, api_vec[API_DR1][INT_V_DR], 7) }, - { ORDATA (APIVEC2, api_vec[API_DR2][INT_V_DR], 7) }, - { ORDATA (APIVEC3, api_vec[API_DR3][INT_V_DR], 7) }, - { DRDATA (POLL, dr15_poll, 10), REG_NZ }, - { ORDATA (DEVNO, dr15_dib.dev, 6), REG_HRO }, - { NULL } - }; - -MTAB dr15_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", NULL, &show_devno }, - { 0 } - }; - -DEVICE dr15_dev = { - "DR", &dr15_unit, dr15_reg, dr15_mod, - 1, 8, 10, 1, 8, 32, - &dr15_ex, &dr15_dep, &dr15_reset, - NULL, &dr15_attach, &dr15_detach, - &dr15_dib, DEV_DISABLE | DEV_DIS | DEV_DEBUG - }; - -/* IOT routines */ - -int32 dr60 (int32 dev, int32 pulse, int32 AC) -{ -int32 subdev = (pulse >> 4) & 03; - -if (((pulse & 01) != 0) && (dr15_tcb_ack != 0)) /* SIOA */ - AC |= IOT_SKP; -if ((pulse & 02) != 0) /* CIOP */ - dr15_tcb_ack = 0; -if ((pulse & 04) != 0) { /* LIOR */ - dr15_tcbp = AC & AMASK; /* top bit zero */ - uc15_tcbp_wr (dr15_tcbp); /* inform UC15 */ - } -return AC; -} - -int32 dr61 (int32 dev, int32 pulse, int32 AC) -{ -int32 subdev = (pulse >> 4) & 03; - -if (pulse & 01) { /* SAPIn */ - if (((dr15_int_req >> subdev) & 01) != 0) - AC = AC | IOT_SKP; - } -if (pulse & 02) { - if (subdev == 0) /* RDRS */ - AC |= dr15_ie; - else if (subdev == 1) - dr15_set_clr_ie (AC & 1); - } -if (pulse & 04) { /* CAPI */ - int32 old_int_req = dr15_int_req; - dr15_int_req &= ~(1 << subdev); /* clear local req */ - int_hwre[subdev] &= ~INT_DR; /* clear hwre req */ - if (dr15_int_req != old_int_req) /* state change? */ - uc15_new_api (dr15_int_req); /* inform UC15 */ - } -return AC; -} - -/* Set/clear interrupt enable */ - -void dr15_set_clr_ie (int32 val) -{ -int32 i; - -dr15_ie = val; -for (i = 0; i < 4; i++) { - if ((dr15_ie != 0) && (((dr15_int_req >> i) & 01) != 0)) - int_hwre[i] |= INT_DR; - else int_hwre[i] &= ~INT_DR; - } -return; -} - -/* Routines to inform UC15 of state changes */ - -t_stat uc15_new_api (int32 req) -{ -UC15_SHARED_WR (UC15_API_SUMM, req); /* new value */ -UC15_ATOMIC_CAS (UC15_API_UPD, 0, 1); /* signal UC15 */ -return SCPE_OK; -} - -t_stat uc15_tcbp_wr (int32 tcbp) -{ -UC15_SHARED_WR (UC15_TCBP, tcbp); /* new value */ -UC15_ATOMIC_CAS (UC15_TCBP_WR, 0, 1); /* signal UC15 */ -if (DEBUG_PRS (dr15_dev)) { - uint32 apiv, apil, fnc, tsk; - t_bool spl; - - apiv = (M[tcbp] >> 8) & 0377; - apil = M[tcbp] & 0377; - fnc = (M[tcbp + 1] >> 8) & 0377; - spl = (M[tcbp + 1] & 0200) != 0; - tsk = (M[tcbp + 1] & 0177); - fprintf (sim_deb, ">> DR15: TCB write, API = %o/%d, fnc = %o, %s task = %o, eventvar = %o\n", - apiv, apil, fnc, spl? "Spooled": "Unspooled", tsk, M[tcbp + 2]); - fprintf (sim_deb, "Additional parameters = %o %o %o %o %o\n", - M[tcbp + 3], M[tcbp + 4], M[tcbp + 5], M[tcbp + 6], M[tcbp + 7]); - } -return SCPE_OK; -} - -/* Routine to poll for state changes from UC15 */ - -t_stat dr15_svc (UNIT *uptr) -{ -int32 i, t; -uint32 old_int_req = dr15_int_req; - -t = UC15_SHARED_RD (UC15_TCBP_RD); /* TCBP read? */ -if ((t != 0) && UC15_ATOMIC_CAS (UC15_TCBP_RD, 1, 0)) /* for real? clear */ - dr15_tcb_ack = 1; /* set ack */ -for (i = 0; i < 4; i++) { /* API req */ - t = UC15_SHARED_RD (UC15_API_REQ + (i * UC15_API_VEC_MUL)); - if ((t != 0) && /* API req? for real? */ - UC15_ATOMIC_CAS (UC15_API_REQ + (i * UC15_API_VEC_MUL), 1, 0)) { - api_vec[i][INT_V_DR] = UC15_SHARED_RD (UC15_API_VEC + (i * UC15_API_VEC_MUL)) & 0177; - dr15_int_req |= (1u << i); - if (dr15_ie != 0) - int_hwre[i] |= INT_DR; - if (DEBUG_PRS (dr15_dev)) - fprintf (sim_deb, ">>DR15: API request, API = %o/%d\n", - api_vec[i][INT_V_DR], i); - } /* end if changed */ - } /* end for */ -if (dr15_int_req != old_int_req) /* changes? */ - uc15_new_api (dr15_int_req); /* inform UC15 */ -sim_activate (uptr, dr15_poll); /* next poll */ -return SCPE_OK; -} - -/* Reset routine - - Aside from performing a device reset, this routine sets up shared - UC15 state and shared PDP15 main memory. It also writes the size - of PDP15 main memory (in PDP11 bytes) into the shared state region. -*/ - -t_stat dr15_reset (DEVICE *dptr) -{ -int32 i; -t_stat r; -void *basead; - -dr15_int_req = 0; /* clear API req */ -dr15_ie = 1; /* IE inits to 1 */ -dr15_tcb_ack = 1; /* TCBP ack inits to 1 */ -dr15_int_req = 0; -for (i = 0; i < 4; i++) { /* clear intr and vectors */ - int_hwre[i] &= ~INT_DR; - api_vec[i][INT_V_DR] = 0; - } -sim_cancel (dptr->units); -if ((dptr->flags & DEV_DIS) != 0) /* disabled? */ - return SCPE_OK; - -if (uc15_shmem == NULL) { /* allocate shared state */ - r = sim_shmem_open ("UC15SharedState", UC15_STATE_SIZE * sizeof (int32), &uc15_shmem, &basead); - if (r != SCPE_OK) - return r; - uc15_shstate = (int32 *) basead; - } -if (pdp15_shmem == NULL) { /* allocate shared memory */ - r = sim_shmem_open ("PDP15MainMemory", MAXMEMSIZE * sizeof (int32), &pdp15_shmem, &basead); - if (r != SCPE_OK) - return r; - free (M); /* release normal memory */ - M = (int32 *) basead; - } -UC15_SHARED_WR (UC15_PDP15MEM, cpu_unit.capac << 1); /* write mem size to shared state */ -uc15_new_api (dr15_int_req); /* inform UC15 of new API (and mem) */ -sim_activate (dptr->units, dr15_poll); /* start polling */ -return SCPE_OK; -} - -/* Shared state ex/mod routines for debug */ - -t_stat dr15_ex (t_value *vptr, t_addr addr, UNIT *uptr, int32 sw) -{ -if (addr >= UC15_STATE_SIZE) - return SCPE_NXM; -if (vptr != NULL) { - if (uc15_shmem != NULL) - *vptr = UC15_SHARED_RD ((int32) addr); - else *vptr = 0; - } -return SCPE_OK; -} - -t_stat dr15_dep (t_value val, t_addr addr, UNIT *uptr, int32 sw) -{ -if (addr >= UC15_STATE_SIZE) - return SCPE_NXM; -if (uc15_shmem != NULL) - UC15_SHARED_WR ((int32) addr, (int32) val); -return SCPE_OK; -} - -/* Fake attach routine to kill attach attempts */ - -t_stat dr15_attach (UNIT *uptr, char *cptr) -{ -return SCPE_NOFNC; -} - -/* Shutdown detach routine to release shared memories */ - -t_stat dr15_detach (UNIT *uptr) -{ -if ((sim_switches & SIM_SW_SHUT) == 0) /* only if shutdown */ - return SCPE_NOFNC; -sim_shmem_close (uc15_shmem); /* release shared state */ -sim_shmem_close (pdp15_shmem); /* release shared mem */ -return SCPE_OK; -} - diff --git a/PDP18B/pdp18b_drm.c b/PDP18B/pdp18b_drm.c deleted file mode 100644 index 3778e1e5..00000000 --- a/PDP18B/pdp18b_drm.c +++ /dev/null @@ -1,261 +0,0 @@ -/* pdp18b_drm.c: drum head disk simulator - - Copyright (c) 1993-2016, 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. - - drm (PDP-4,PDP-7) Type 24 serial drum; (PDP-9) RM09 drum - - 07-Mar-16 RMS Revised for dynamically allocated memory - 26-Feb-16 RMS Added PDP-9 support; set default state to disabled - 03-Sep-13 RMS Added explicit void * cast - 14-Jan-04 RMS Revised IO device call interface - 26-Oct-03 RMS Cleaned up buffer copy code - 05-Dec-02 RMS Updated from Type 24 documentation - 22-Nov-02 RMS Added PDP-4 support - 05-Feb-02 RMS Added DIB, device number support - 03-Feb-02 RMS Fixed bug in reset routine (Robert Alan Byer) - 06-Jan-02 RMS Revised enable/disable support - 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 - - Variable drum sizes are not supported. -*/ - -#include "pdp18b_defs.h" -#include - -/* Constants */ - -#define DRM_NUMWDS 256 /* words/sector */ -#define DRM_NUMSC 2 /* sectors/track */ -#define DRM_NUMTR 256 /* tracks/drum */ -#define DRM_NUMDK 1 /* drum/controller */ -#define DRM_NUMWDT (DRM_NUMWDS * DRM_NUMSC) /* words/track */ -#define DRM_SIZE (DRM_NUMDK * DRM_NUMTR * DRM_NUMWDT) /* words/drum */ -#define DRM_SMASK ((DRM_NUMTR * DRM_NUMSC) - 1) /* sector mask */ - -/* Parameters in the unit descriptor */ - -#define FUNC u4 /* function */ -#define DRM_READ 000 /* read */ -#define DRM_WRITE 040 /* write */ - -#define GET_POS(x) ((int) fmod (sim_gtime() / ((double) (x)), \ - ((double) DRM_NUMWDT))) - -extern int32 *M; -extern int32 int_hwre[API_HLVL+1]; -extern UNIT cpu_unit; - -int32 drm_da = 0; /* track address */ -int32 drm_ma = 0; /* memory address */ -int32 drm_err = 0; /* error flag */ -int32 drm_wlk = 0; /* write lock */ -int32 drm_time = 10; /* inter-word time */ -int32 drm_stopioe = 1; /* stop on error */ - -DEVICE drm_dev; -int32 drm60 (int32 dev, int32 pulse, int32 AC); -int32 drm61 (int32 dev, int32 pulse, int32 AC); -int32 drm62 (int32 dev, int32 pulse, int32 AC); -int32 drm_iors (void); -t_stat drm_svc (UNIT *uptr); -t_stat drm_reset (DEVICE *dptr); -t_stat drm_boot (int32 unitno, DEVICE *dptr); - -/* DRM data structures - - drm_dev DRM device descriptor - drm_unit DRM unit descriptor - drm_reg DRM register list -*/ - -DIB drm_dib = { DEV_DRM, 3 ,&drm_iors, { &drm60, &drm61, &drm62 } }; - -UNIT drm_unit = { - UDATA (&drm_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_BUFABLE+UNIT_MUSTBUF, - DRM_SIZE) - }; - -REG drm_reg[] = { - { ORDATA (DA, drm_da, 9) }, - { ORDATA (MA, drm_ma, 16) }, - { 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 }, - { FLDATA (STOP_IOE, drm_stopioe, 0) }, - { ORDATA (DEVNO, drm_dib.dev, 6), REG_HRO }, - { NULL } - }; - -MTAB drm_mod[] = { - { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno }, - { 0 } - }; - -DEVICE drm_dev = { - "DRM", &drm_unit, drm_reg, drm_mod, - 1, 8, 20, 1, 8, 18, - NULL, NULL, &drm_reset, - &drm_boot, NULL, NULL, - &drm_dib, DEV_DISABLE + DEV_DIS - }; - -/* IOT routines */ - -int32 drm60 (int32 dev, int32 pulse, int32 AC) -{ -if ((pulse & 027) == 06) { /* DRLR, DRLW */ - drm_ma = AC & 0177777; /* load mem addr */ - drm_unit.FUNC = pulse & DRM_WRITE; /* save function */ - } -return AC; -} - -int32 drm61 (int32 dev, int32 pulse, int32 AC) -{ -int32 t; - -if (pulse & 001) { /* DRSF */ - if (TST_INT (DRM)) - AC = AC | IOT_SKP; - } -if (pulse & 002) { /* DRCF */ - CLR_INT (DRM); /* clear done */ - drm_err = 0; /* clear error */ - } -if (pulse & 004) { /* DRSS */ - drm_da = AC & DRM_SMASK; /* load sector # */ - t = ((drm_da % DRM_NUMSC) * DRM_NUMWDS) - GET_POS (drm_time); - if (t <= 0) /* wrap around? */ - t = t + DRM_NUMWDT; - sim_activate (&drm_unit, t * drm_time); /* schedule op */ - } -return AC; -} - -int32 drm62 (int32 dev, int32 pulse, int32 AC) -{ -int32 t; - -if (pulse & 001) { /* DRSN */ - if (drm_err == 0) - AC = AC | IOT_SKP; - } -if (pulse & 004) { /* DRCS */ - CLR_INT (DRM); /* clear done */ - drm_err = 0; /* clear error */ - t = ((drm_da % DRM_NUMSC) * DRM_NUMWDS) - GET_POS (drm_time); - if (t <= 0) /* wrap around? */ - t = t + DRM_NUMWDT; - sim_activate (&drm_unit, t * drm_time); /* schedule op */ - } -return AC; -} - -/* Unit service - - This code assumes the entire drum is buffered. -*/ - -t_stat drm_svc (UNIT *uptr) -{ -int32 i; -uint32 da; -int32 *fbuf = (int32 *) uptr->filebuf; - -if ((uptr->flags & UNIT_BUF) == 0) { /* not buf? abort */ - drm_err = 1; /* set error */ - SET_INT (DRM); /* set done */ - return IORETURN (drm_stopioe, SCPE_UNATT); - } - -da = drm_da * DRM_NUMWDS; /* compute dev addr */ -for (i = 0; i < DRM_NUMWDS; i++, da++) { /* do transfer */ - if (uptr->FUNC == DRM_READ) { /* read? */ - if (MEM_ADDR_OK (drm_ma)) /* if !nxm */ - M[drm_ma] = fbuf[da]; /* read word */ - } - else { /* write */ - if ((drm_wlk >> (drm_da >> 4)) & 1) - drm_err = 1; - else { /* not locked */ - fbuf[da] = M[drm_ma]; /* write word */ - if (da >= uptr->hwmark) - uptr->hwmark = da + 1; - } - } - drm_ma = (drm_ma + 1) & 0177777; /* incr mem addr */ - } -drm_da = (drm_da + 1) & DRM_SMASK; /* incr dev addr */ -SET_INT (DRM); /* set done */ -return SCPE_OK; -} - -/* Reset routine */ - -t_stat drm_reset (DEVICE *dptr) -{ -drm_da = drm_ma = drm_err = 0; -CLR_INT (DRM); /* clear done */ -sim_cancel (&drm_unit); -return SCPE_OK; -} - -/* IORS routine */ - -int32 drm_iors (void) -{ -return (TST_INT (DRM)? IOS_DRM: 0); -} - -/* Bootstrap routine */ - -#define BOOT_START 02000 -#define BOOT_LEN (sizeof (boot_rom) / sizeof (int)) - -static const int32 boot_rom[] = { - 0750000, /* CLA ; dev, mem addr */ - 0706006, /* DRLR ; load ma */ - 0706106, /* DRSS ; load da, start */ - 0706101, /* DRSF ; wait for done */ - 0602003, /* JMP .-1 */ - 0600000 /* JMP 0 ; enter boot */ - }; - -t_stat drm_boot (int32 unitno, DEVICE *dptr) -{ -size_t i; -extern int32 PC; - -if (drm_dib.dev != DEV_DRM) /* non-std addr? */ - return STOP_NONSTD; -for (i = 0; i < BOOT_LEN; i++) - M[BOOT_START + i] = boot_rom[i]; -PC = BOOT_START; -return SCPE_OK; -} diff --git a/PDP18B/pdp18b_dt.c b/PDP18B/pdp18b_dt.c deleted file mode 100644 index 86d390bd..00000000 --- a/PDP18B/pdp18b_dt.c +++ /dev/null @@ -1,1556 +0,0 @@ -/* pdp18b_dt.c: 18b DECtape simulator - - Copyright (c) 1993-2017, Robert M Supnik - - Permission is hereby granted, free of charge, to any person obtaining a - copy of this software and associated documentation files (the "Software"), - to deal in the Software without restriction, including without limitation - the rights to use, copy, modify, merge, publish, distribute, sublicense, - and/or sell copies of the Software, and to permit persons to whom the - Software is furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - ROBERT M SUPNIK BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER - IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN - CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Except as contained in this notice, the name of Robert M Supnik shall not be - used in advertising or otherwise to promote the sale, use or other dealings - in this Software without prior written authorization from Robert M Supnik. - - dt (PDP-4, PDP-7) Type 550/555 DECtape - (PDP-9) TC02/TU55 DECtape - (PDP-15) TC15/TU56 DECtape - - 15-Mar-17 RMS Fixed dt_seterr to clear successor states - 09-Mar-17 RMS Fixed dt_seterr to handle nx unit select (COVERITY) - 10-Mar-16 RMS Added 3-cycle databreak set/show entries - 07-Mar-16 RMS Revised for dynamically allocated memory - 13-Mar-15 RMS Added APIVEC register - 28-Mar-15 RMS Revised to use sim_printf - 23-Jun-06 RMS Fixed switch conflict in ATTACH - Revised Type 550 header based on DECTOG formatter - 13-Jun-06 RMS Fixed checksum calculation bug in Type 550 - 16-Aug-05 RMS Fixed C++ declaration and cast problems - 25-Jan-04 RMS Revised for device debug support - 14-Jan-04 RMS Revised IO device call interface - Changed sim_fsize calling sequence, added STOP_OFFR - 26-Oct-03 RMS Cleaned up buffer copy code - 18-Oct-03 RMS Fixed reverse checksum in read all - Added DECtape off reel message - Simplified timing - 25-Apr-03 RMS Revised for extended file support - 14-Mar-03 RMS Fixed variable size interaction with save/restore - 17-Oct-02 RMS Fixed bug in end of reel logic - 05-Oct-02 RMS Added DIB, device number support - 12-Sep-02 RMS Added 16b format support - 13-Aug-02 RMS Corrected Type 550 unit select logic - 25-Jul-02 RMS Added PDP-4 support - 30-May-02 RMS Widened POS to 32b - 10-Feb-02 RMS Added PDP-7 support - 06-Jan-02 RMS Revised enable/disable support - 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 - 26-Apr-01 RMS Added device enable/disable support - 15-Mar-01 RMS Added 129th word to PDP-8 format - - 18b DECtapes are represented in memory by fixed length buffer of 32b words. - Three file formats are supported: - - 18b/36b 256 words per block [256 x 18b] - 16b 256 words per block [256 x 16b] - 12b 129 words per block [129 x 12b] - - When a 16b or 12b DECtape file is read in, it is converted to 18b/36b format. - - DECtape motion is measured in 3b lines. Time between lines is 33.33us. - Tape density is nominally 300 lines per inch. The format of a DECtape (as - taken from the PDP-7 formatter) is: - - reverse end zone 7144 reverse end zone codes ~ 12 feet - reverse buffer 200 interblock codes - block 0 - : - block n - forward buffer 200 interblock codes - forward end zone 7144 forward end zone codes ~ 12 feet - - A block consists of five 18b header words, a tape-specific number of data - words, and five 18b trailer words. All systems except the PDP-8 use a - standard block length of 256 words; the PDP-8 uses a standard block length - of 86 words (x 18b = 129 words x 12b). PDP-4/7 DECtapes came in two - formats. The first 5 controllers used a 4 word header/trailer (missing - word 0/4). All later serial numbers used the standard header. The later, - standard header/trailer is simulated here. - - Because a DECtape file only contains data, the simulator cannot support - write timing and mark track and can only do a limited implementation - of read all and write all. Read all assumes that the tape has been - conventionally written forward: - - header word 0 0 - header word 1 block number (for forward reads) - header words 2,3 0 - header word 4 checksum (for reverse reads) - : - trailer word 4 checksum (for forward reads) - trailer words 3,2 0 - trailer word 1 block number (for reverse reads) - trailer word 0 0 - - Write all writes only the data words and dumps the interblock words in the - bit bucket. - - The Type 550 controller has a 4b unit select field, for units 1-8; the TC02 - has a 3b unit select field, with unit 8 being represented as 0. The code - assumes that the GETUNIT macro returns a unit number in the range of 0-7, - with 8 represented as 0, and an invalid unit as -1. -*/ - -#include "pdp18b_defs.h" - -#define DT_NUMDR 8 /* #drives */ -#define UNIT_V_WLK (UNIT_V_UF + 0) /* write locked */ -#define UNIT_V_8FMT (UNIT_V_UF + 1) /* 12b format */ -#define UNIT_V_11FMT (UNIT_V_UF + 2) /* 16b format */ -#define UNIT_WLK (1 << UNIT_V_WLK) -#define UNIT_8FMT (1 << UNIT_V_8FMT) -#define UNIT_11FMT (1 << UNIT_V_11FMT) -#define STATE u3 /* unit state */ -#define LASTT u4 /* last time update */ -#define DT_WC 030 /* word count */ -#define DT_CA 031 /* current addr */ -#define UNIT_WPRT (UNIT_WLK | UNIT_RO) /* write protect */ - -/* System independent DECtape constants */ - -#define DT_LPERMC 6 /* lines per mark track */ -#define DT_BLKWD 1 /* blk no word in h/t */ -#define DT_CSMWD 4 /* checksum word in h/t */ -#define DT_HTWRD 5 /* header/trailer words */ -#define DT_EZLIN (8192 * DT_LPERMC) /* end zone length */ -#define DT_BFLIN (200 * DT_LPERMC) /* buffer length */ -#define DT_BLKLN (DT_BLKWD * DT_LPERMC) /* blk no line in h/t */ -#define DT_CSMLN (DT_CSMWD * DT_LPERMC) /* csum line in h/t */ -#define DT_HTLIN (DT_HTWRD * DT_LPERMC) /* header/trailer lines */ - -/* 16b, 18b, 36b DECtape constants */ - -#define D18_WSIZE 6 /* word size in lines */ -#define D18_BSIZE 256 /* block size in 18b */ -#define D18_TSIZE 578 /* tape size */ -#define D18_LPERB (DT_HTLIN + (D18_BSIZE * DT_WSIZE) + DT_HTLIN) -#define D18_FWDEZ (DT_EZLIN + (D18_LPERB * D18_TSIZE)) -#define D18_CAPAC (D18_TSIZE * D18_BSIZE) /* tape capacity */ -#define D11_FILSIZ (D18_CAPAC * sizeof (int16)) - -/* 12b DECtape constants */ - -#define D8_WSIZE 4 /* word size in lines */ -#define D8_BSIZE 86 /* block size in 18b */ -#define D8_TSIZE 1474 /* tape size */ -#define D8_LPERB (DT_HTLIN + (D8_BSIZE * DT_WSIZE) + DT_HTLIN) -#define D8_FWDEZ (DT_EZLIN + (D8_LPERB * D8_TSIZE)) -#define D8_CAPAC (D8_TSIZE * D8_BSIZE) /* tape capacity */ - -#define D8_NBSIZE ((D8_BSIZE * D18_WSIZE) / D8_WSIZE) -#define D8_FILSIZ (D8_NBSIZE * D8_TSIZE * sizeof (int16)) - -/* This controller */ - -#define DT_CAPAC D18_CAPAC /* default */ -#define DT_WSIZE D18_WSIZE - -/* Calculated constants, per unit */ - -#define DTU_BSIZE(u) (((u)->flags & UNIT_8FMT)? D8_BSIZE: D18_BSIZE) -#define DTU_TSIZE(u) (((u)->flags & UNIT_8FMT)? D8_TSIZE: D18_TSIZE) -#define DTU_LPERB(u) (((u)->flags & UNIT_8FMT)? D8_LPERB: D18_LPERB) -#define DTU_FWDEZ(u) (((u)->flags & UNIT_8FMT)? D8_FWDEZ: D18_FWDEZ) -#define DTU_CAPAC(u) (((u)->flags & UNIT_8FMT)? D8_CAPAC: D18_CAPAC) - -#define DT_LIN2BL(p,u) (((p) - DT_EZLIN) / DTU_LPERB (u)) -#define DT_LIN2OF(p,u) (((p) - DT_EZLIN) % DTU_LPERB (u)) -#define DT_LIN2WD(p,u) ((DT_LIN2OF (p,u) - DT_HTLIN) / DT_WSIZE) -#define DT_BLK2LN(p,u) (((p) * DTU_LPERB (u)) + DT_EZLIN) -#define DT_QREZ(u) (((u)->pos) < DT_EZLIN) -#define DT_QFEZ(u) (((u)->pos) >= ((uint32) DTU_FWDEZ (u))) -#define DT_QEZ(u) (DT_QREZ (u) || DT_QFEZ (u)) - -/* Status register A */ - -#if defined (TC02) /* TC02/TC15 */ -#define DTA_V_UNIT 15 /* unit select */ -#define DTA_M_UNIT 07 -#define DTA_UNIT (DTA_M_UNIT << DTA_V_UNIT) -#define DTA_V_MOT 13 /* motion */ -#define DTA_M_MOT 03 -#define DTA_V_MODE 12 /* mode */ -#define DTA_V_FNC 9 /* function */ -#define DTA_M_FNC 07 -#define FNC_MOVE 00 /* move */ -#define FNC_SRCH 01 /* search */ -#define FNC_READ 02 /* read */ -#define FNC_RALL 03 /* read all */ -#define FNC_WRIT 04 /* write */ -#define FNC_WALL 05 /* write all */ -#define FNC_WMRK 06 /* write timing */ -#define DTA_V_ENB 8 /* int enable */ -#define DTA_V_CERF 7 /* clr error flag */ -#define DTA_V_CDTF 6 /* clr DECtape flag */ -#define DTA_FWDRV (1u << (DTA_V_MOT + 1)) -#define DTA_STSTP (1u << DTA_V_MOT) -#define DTA_MODE (1u << DTA_V_MODE) -#define DTA_ENB (1u << DTA_V_ENB) -#define DTA_CERF (1u << DTA_V_CERF) -#define DTA_CDTF (1u << DTA_V_CDTF) -#define DTA_RW (0777700 & ~(DTA_CERF | DTA_CDTF)) -#define DTA_GETUNIT(x) (((x) >> DTA_V_UNIT) & DTA_M_UNIT) -#define DT_UPDINT if ((dtsa & DTA_ENB) && (dtsb & (DTB_ERF | DTB_DTF))) \ - SET_INT (DTA); \ - else CLR_INT (DTA); - -#else /* Type 550 */ -#define DTA_V_UNIT 12 /* unit select */ -#define DTA_M_UNIT 017 -#define DTA_UNIT (DTA_M_UNIT << DTA_V_UNIT) -#define DTA_V_MOT 4 /* motion */ -#define DTA_M_MOT 03 -#define DTA_V_FNC 0 /* function */ -#define DTA_M_FNC 07 -#define FNC_MOVE 00 /* move */ -#define FNC_SRCH 01 /* search */ -#define FNC_READ 02 /* read */ -#define FNC_WRIT 03 /* write */ -#define FNC_RALL 05 /* read all */ -#define FNC_WALL 06 /* write all */ -#define FNC_WMRK 07 /* write timing */ -#define DTA_STSTP (1u << (DTA_V_MOT + 1)) -#define DTA_FWDRV (1u << DTA_V_MOT) -#define DTA_MODE 0 /* not implemented */ -#define DTA_RW 077 -#define DTA_GETUNIT(x) map_unit[(((x) >> DTA_V_UNIT) & DTA_M_UNIT)] -#define DT_UPDINT if (dtsb & (DTB_DTF | DTB_BEF | DTB_ERF)) \ - SET_INT (DTA); \ - else CLR_INT (DTA); -#endif - -#define DTA_GETMOT(x) (((x) >> DTA_V_MOT) & DTA_M_MOT) -#define DTA_GETFNC(x) (((x) >> DTA_V_FNC) & DTA_M_FNC) - -/* Status register B */ - -#if defined (TC02) /* TC02/TC15 */ -#define DTB_V_ERF 17 /* error flag */ -#define DTB_V_MRK 16 /* mark trk err */ -#define DTB_V_END 15 /* end zone err */ -#define DTB_V_SEL 14 /* select err */ -#define DTB_V_PAR 13 /* parity err */ -#define DTB_V_TIM 12 /* timing err */ -#define DTB_V_DTF 6 /* DECtape flag */ -#define DTB_ERF (1u << DTB_V_ERF) -#define DTB_MRK (1u << DTB_V_MRK) -#define DTB_END (1u << DTB_V_END) -#define DTB_SEL (1u << DTB_V_SEL) -#define DTB_PAR (1u << DTB_V_PAR) -#define DTB_TIM (1u << DTB_V_TIM) -#define DTB_DTF (1u << DTB_V_DTF) -#define DTB_ALLERR (DTB_ERF | DTB_MRK | DTB_END | DTB_SEL | \ - DTB_PAR | DTB_TIM) - -#else /* Type 550 */ -#define DTB_V_DTF 17 /* data flag */ -#define DTB_V_BEF 16 /* block end flag */ -#define DTB_V_ERF 15 /* error flag */ -#define DTB_V_END 14 /* end of tape */ -#define DTB_V_TIM 13 /* timing err */ -#define DTB_V_REV 12 /* reverse */ -#define DTB_V_GO 11 /* go */ -#define DTB_V_MRK 10 /* mark trk err */ -#define DTB_V_SEL 9 /* select err */ -#define DTB_DTF (1u << DTB_V_DTF) -#define DTB_BEF (1u << DTB_V_BEF) -#define DTB_ERF (1u << DTB_V_ERF) -#define DTB_END (1u << DTB_V_END) -#define DTB_TIM (1u << DTB_V_TIM) -#define DTB_REV (1u << DTB_V_REV) -#define DTB_GO (1u << DTB_V_GO) -#define DTB_MRK (1u << DTB_V_MRK) -#define DTB_SEL (1u << DTB_V_SEL) -#define DTB_ALLERR (DTB_END | DTB_TIM | DTB_MRK | DTB_SEL) -#endif - -/* DECtape state */ - -#define DTS_V_MOT 3 /* motion */ -#define DTS_M_MOT 07 -#define DTS_STOP 0 /* stopped */ -#define DTS_DECF 2 /* decel, fwd */ -#define DTS_DECR 3 /* decel, rev */ -#define DTS_ACCF 4 /* accel, fwd */ -#define DTS_ACCR 5 /* accel, rev */ -#define DTS_ATSF 6 /* @speed, fwd */ -#define DTS_ATSR 7 /* @speed, rev */ -#define DTS_DIR 01 /* dir mask */ -#define DTS_V_FNC 0 /* function */ -#define DTS_M_FNC 07 -#define DTS_OFR 7 /* "off reel" */ -#define DTS_GETMOT(x) (((x) >> DTS_V_MOT) & DTS_M_MOT) -#define DTS_GETFNC(x) (((x) >> DTS_V_FNC) & DTS_M_FNC) -#define DTS_V_2ND 6 /* next state */ -#define DTS_V_3RD (DTS_V_2ND + DTS_V_2ND) /* next next */ -#define DTS_STA(y,z) (((y) << DTS_V_MOT) | ((z) << DTS_V_FNC)) -#define DTS_SETSTA(y,z) uptr->STATE = DTS_STA (y, z) -#define DTS_SET2ND(y,z) uptr->STATE = (uptr->STATE & 077) | \ - ((DTS_STA (y, z)) << DTS_V_2ND) -#define DTS_SET3RD(y,z) uptr->STATE = (uptr->STATE & 07777) | \ - ((DTS_STA (y, z)) << DTS_V_3RD) -#define DTS_NXTSTA(x) (x >> DTS_V_2ND) - -/* Operation substates */ - -#define DTO_WCO 1 /* wc overflow */ -#define DTO_SOB 2 /* start of block */ - -/* Logging */ - -#define LOG_MS 001 /* move, search */ -#define LOG_RW 002 /* read, write */ -#define LOG_RA 004 /* read all */ -#define LOG_BL 010 /* block # lblk */ - -#define ABS(x) (((x) < 0)? (-(x)): (x)) - -extern int32 *M; -extern int32 int_hwre[API_HLVL+1]; -extern int32 api_vec[API_HLVL][32]; -extern UNIT cpu_unit; - -int32 dtsa = 0; /* status A */ -int32 dtsb = 0; /* status B */ -int32 dtdb = 0; /* data buffer */ -int32 dt_ltime = 12; /* interline time */ -int32 dt_dctime = 40000; /* decel time */ -int32 dt_substate = 0; -int32 dt_logblk = 0; -int32 dt_stopoffr = 0; /* stop on off reel */ -static const int32 map_unit[16] = { /* Type 550 unit map */ - -1, 1, 2, 3, 4, 5, 6, 7, - 0, -1, -1, -1, -1, -1, -1, -1 - }; - -DEVICE dt_dev; -int32 dt75 (int32 dev, int32 pulse, int32 dat); -int32 dt76 (int32 dev, int32 pulse, int32 dat); -int32 dt_iors (void); -t_stat dt_svc (UNIT *uptr); -t_stat dt_reset (DEVICE *dptr); -t_stat dt_attach (UNIT *uptr, char *cptr); -t_stat dt_detach (UNIT *uptr); -void dt_deselect (int32 oldf); -void dt_newsa (int32 newf); -void dt_newfnc (UNIT *uptr, int32 newsta); -t_bool dt_setpos (UNIT *uptr); -void dt_schedez (UNIT *uptr, int32 dir); -void dt_seterr (UNIT *uptr, int32 e); -int32 dt_comobv (int32 val); -int32 dt_csum (UNIT *uptr, int32 blk); -int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos); - -/* DT data structures - - dt_dev DT device descriptor - dt_unit DT unit list - dt_reg DT register list - dt_mod DT modifier list -*/ - -DIB dt_dib = { DEV_DTA, 2, &dt_iors, { &dt75, &dt76 } }; - -UNIT dt_unit[] = { - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, DT_CAPAC) }, - { UDATA (&dt_svc, UNIT_FIX+UNIT_ATTABLE+UNIT_DISABLE+ - UNIT_ROABLE, DT_CAPAC) } - }; - -REG dt_reg[] = { - { ORDATA (DTSA, dtsa, 18) }, - { ORDATA (DTSB, dtsb, 18) }, - { ORDATA (DTDB, dtdb, 18) }, - { FLDATA (INT, int_hwre[API_DTA], INT_V_DTA) }, -#if defined (DTA_V_ENB) - { FLDATA (ENB, dtsa, DTA_V_ENB) }, -#endif - { FLDATA (DTF, dtsb, DTB_V_DTF) }, -#if defined (DTB_V_BEF) - { FLDATA (BEF, dtsb, DTB_V_BEF) }, -#endif - { FLDATA (ERF, dtsb, DTB_V_ERF) }, - { DRDATA (LTIME, dt_ltime, 31), REG_NZ }, - { DRDATA (DCTIME, dt_dctime, 31), REG_NZ }, - { ORDATA (SUBSTATE, dt_substate, 2) }, - { DRDATA (LBLK, dt_logblk, 12), REG_HIDDEN }, - { URDATA (POS, dt_unit[0].pos, 10, T_ADDR_W, 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, T_ADDR_W, 0, - DT_NUMDR, REG_HRO) }, - { ORDATA (DEVNO, dt_dib.dev, 6), REG_HRO }, - { FLDATA (STOP_OFFR, dt_stopoffr, 0) }, -#if defined (TC02) - { ORDATA (APIVEC, api_vec[API_DTA][INT_V_DTA], 6), REG_HRO }, -#endif - { NULL } - }; - -MTAB dt_mod[] = { - { UNIT_WLK, 0, "write enabled", "WRITEENABLED", NULL }, - { UNIT_WLK, UNIT_WLK, "write locked", "LOCKED", NULL }, - { UNIT_8FMT + UNIT_11FMT, 0, "18b", NULL, NULL }, - { UNIT_8FMT + UNIT_11FMT, UNIT_8FMT, "12b", NULL, NULL }, - { UNIT_8FMT + UNIT_11FMT, UNIT_11FMT, "16b", NULL, NULL }, -#if defined (TC02) - { MTAB_XTD|MTAB_VDV|MTAB_NMO, DT_WC, "WC", "WC", &set_3cyc_reg, &show_3cyc_reg, "WC" }, - { MTAB_XTD|MTAB_VDV|MTAB_NMO, DT_CA, "CA", "CA", &set_3cyc_reg, &show_3cyc_reg, "CA" }, -#endif - { MTAB_XTD|MTAB_VDV, 0, "DEVNO", "DEVNO", &set_devno, &show_devno }, - { 0 } - }; - -DEBTAB dt_deb[] = { - { "MOTION", LOG_MS }, - { "DATA", LOG_RW }, - { "READALL", LOG_RA }, - { "BLOCK", LOG_BL }, - { NULL, 0 } - }; - -DEVICE dt_dev = { - "DT", dt_unit, dt_reg, dt_mod, - DT_NUMDR, 8, 24, 1, 8, 18, - NULL, NULL, &dt_reset, - NULL, &dt_attach, &dt_detach, - &dt_dib, DEV_DISABLE | DEV_DEBUG, 0, - dt_deb, NULL, NULL - }; - -/* IOT routines */ - -#if defined (TC02) /* TC02/TC15 */ -int32 dt75 (int32 dev, int32 pulse, int32 dat) -{ -int32 old_dtsa = dtsa, fnc; -UNIT *uptr; - -if (((pulse & 060) == 040) && (pulse & 05)) { /* select */ - if (pulse & 01) /* DTCA */ - dtsa = 0; - if (pulse & 02) /* DTRA!... */ - dat = dtsa; - if (pulse & 04) { /* DTXA */ - if ((dat & DTA_CERF) == 0) - dtsb = dtsb & ~DTB_ALLERR; - if ((dat & DTA_CDTF) == 0) - dtsb = dtsb & ~DTB_DTF; - dtsa = dtsa ^ (dat & DTA_RW); - } - if ((old_dtsa ^ dtsa) & DTA_UNIT) - dt_deselect (old_dtsa); - uptr = dt_dev.units + DTA_GETUNIT (dtsa); /* get unit */ - fnc = DTA_GETFNC (dtsa); /* get fnc */ - if (((uptr->flags) & UNIT_DIS) || /* disabled? */ - (fnc >= FNC_WMRK) || /* write mark? */ - ((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; - return dat; - } -if ((pulse & 067) == 042) /* DTRA */ - return dtsa; -if ((pulse & 067) == 061) /* DTEF */ - return ((dtsb & DTB_ERF)? IOT_SKP + dat: dat); -if ((pulse & 067) == 062) /* DTRB */ - return dtsb; -if ((pulse & 067) == 063) /* DTEF!DTRB */ - return ((dtsb & DTB_ERF)? IOT_SKP + dtsb: dtsb); -return dat; -} - -int32 dt76 (int32 dev, int32 pulse, int32 dat) -{ -if ((pulse & 01) && (dtsb & DTB_DTF)) /* DTDF */ - return IOT_SKP + dat; -return dat; -} - -#else /* Type 550 */ -int32 dt75 (int32 dev, int32 pulse, int32 dat) -{ -if (((pulse & 041) == 001) && (dtsb & DTB_DTF)) /* MMDF */ - dat = dat | IOT_SKP; -else if (((pulse & 041) == 041) && (dtsb & DTB_ERF)) /* MMEF */ - dat = dat | IOT_SKP; -if (pulse & 002) { /* MMRD */ - dat = (dat & ~DMASK) | dtdb; - dtsb = dtsb & ~(DTB_DTF | DTB_BEF); - } -if (pulse & 004) { /* MMWR */ - dtdb = dat & DMASK; - dtsb = dtsb & ~(DTB_DTF | DTB_BEF); - } -DT_UPDINT; -return dat; -} - -int32 dt76 (int32 dev, int32 pulse, int32 dat) -{ -int32 fnc, mot, unum; -UNIT *uptr = NULL; - -unum = DTA_GETUNIT (dtsa); /* get unit no */ -if (unum >= 0) /* get unit */ - uptr = dt_dev.units + unum; -if ((pulse & 001) && (dtsb & DTB_BEF)) /* MMBF */ - dat = dat | IOT_SKP; -if (pulse & 002) { /* MMRS */ - dtsb = dtsb & ~(DTB_REV | DTB_GO); /* clr rev, go */ - if (uptr) { /* valid unit? */ - mot = DTS_GETMOT (uptr->STATE); /* get motion */ - if (mot & DTS_DIR) /* rev? set */ - dtsb = dtsb | DTB_REV; - if ((mot >= DTS_ACCF) || (uptr->STATE & 0777700)) - dtsb = dtsb | DTB_GO; /* accel? go */ - } - dat = (dat & ~DMASK) | dtsb; - } -if ((pulse & 044) == 044) { /* MMSE */ - if ((dtsa ^ dat) & DTA_UNIT) /* new unit? */ - dt_deselect (dtsa); - dtsa = (dtsa & ~DTA_UNIT) | (dat & DTA_UNIT); - dtsb = dtsb & ~(DTB_DTF | DTB_BEF | DTB_ERF | DTB_ALLERR); - } -else if ((pulse & 044) == 004) { /* MMLC */ - dtsa = (dtsa & ~DTA_RW) | (dat & DTA_RW); /* load dtsa */ - dtsb = dtsb & ~(DTB_DTF | DTB_BEF | DTB_ERF | DTB_ALLERR); - fnc = DTA_GETFNC (dtsa); /* get fnc */ - if ((uptr == NULL) || /* invalid? */ - ((uptr->flags) & UNIT_DIS) || /* disabled? */ - (fnc >= FNC_WMRK) || /* write mark? */ - ((fnc == FNC_WRIT) && (uptr->flags & UNIT_WLK)) || - ((fnc == FNC_WALL) && (uptr->flags & UNIT_WLK))) - dt_seterr (uptr, DTB_SEL); /* select err */ - else dt_newsa (dtsa); - } -DT_UPDINT; -return dat; -} -#endif - -/* Unit deselect */ - -void dt_deselect (int32 oldf) -{ -int32 old_unit, old_mot; -UNIT *uptr; - -old_unit = DTA_GETUNIT (oldf); /* get unit no */ -if (old_unit < 0) /* invalid? */ - return; -uptr = dt_dev.units + old_unit; /* get unit */ -old_mot = DTS_GETMOT (uptr->STATE); -if (old_mot >= DTS_ATSF) /* at speed? */ - dt_newfnc (uptr, DTS_STA (old_mot, DTS_OFR)); -else if (old_mot >= DTS_ACCF) /* accelerating? */ - DTS_SET2ND (DTS_ATSF | (old_mot & DTS_DIR), DTS_OFR); -return; -} - -/* Command register change - - 1. If change in motion, stop to start - - schedule acceleration - - set function as next state - 2. If change in motion, start to stop - - if not already decelerating (could be reversing), - schedule deceleration - 3. If change in direction, - - if not decelerating, schedule deceleration - - set accelerating (other dir) as next state - - set function as next next state - 4. If not accelerating or at speed, - - schedule acceleration - - set function as next state - 5. If not yet at speed, - - set function as next state - 6. If at speed, - - set function as current state, schedule function -*/ - -void dt_newsa (int32 newf) -{ -int32 new_unit, prev_mot, new_fnc; -int32 prev_mving, new_mving, prev_dir, new_dir; -UNIT *uptr; - -new_unit = DTA_GETUNIT (newf); /* new unit */ -if (new_unit < 0) /* invalid? */ - return; -uptr = dt_dev.units + new_unit; -if ((uptr->flags & UNIT_ATT) == 0) { /* new unit attached? */ - dt_seterr (uptr, DTB_SEL); /* no, error */ - return; - } -prev_mot = DTS_GETMOT (uptr->STATE); /* previous motion */ -prev_mving = prev_mot != DTS_STOP; /* previous moving? */ -prev_dir = prev_mot & DTS_DIR; /* previous dir? */ -new_mving = (newf & DTA_STSTP) != 0; /* new moving? */ -new_dir = (newf & DTA_FWDRV) != 0; /* new dir? */ -new_fnc = DTA_GETFNC (newf); /* new function? */ - -if ((prev_mving | new_mving) == 0) /* stop to stop */ - return; - -if (new_mving & ~prev_mving) { /* start? */ - if (dt_setpos (uptr)) /* update pos */ - return; - sim_cancel (uptr); /* stop current */ - sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* sched accel */ - DTS_SETSTA (DTS_ACCF | new_dir, 0); /* state = accel */ - DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */ - return; - } - -if (prev_mving & ~new_mving) { /* stop? */ - if ((prev_mot & ~DTS_DIR) != DTS_DECF) { /* !already stopping? */ - if (dt_setpos (uptr)) /* update pos */ - return; - sim_cancel (uptr); /* stop current */ - sim_activate (uptr, dt_dctime); /* schedule decel */ - } - DTS_SETSTA (DTS_DECF | prev_dir, 0); /* state = decel */ - return; - } - -if (prev_dir ^ new_dir) { /* dir chg? */ - if ((prev_mot & ~DTS_DIR) != DTS_DECF) { /* !already stopping? */ - if (dt_setpos (uptr)) /* update pos */ - return; - sim_cancel (uptr); /* stop current */ - sim_activate (uptr, dt_dctime); /* schedule decel */ - } - DTS_SETSTA (DTS_DECF | prev_dir, 0); /* state = decel */ - DTS_SET2ND (DTS_ACCF | new_dir, 0); /* next = accel */ - DTS_SET3RD (DTS_ATSF | new_dir, new_fnc); /* next next = fnc */ - return; - } - -if (prev_mot < DTS_ACCF) { /* not accel/at speed? */ - if (dt_setpos (uptr)) /* update pos */ - return; - sim_cancel (uptr); /* cancel cur */ - sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* sched accel */ - DTS_SETSTA (DTS_ACCF | new_dir, 0); /* state = accel */ - DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */ - return; - } - -if (prev_mot < DTS_ATSF) { /* not at speed? */ - DTS_SET2ND (DTS_ATSF | new_dir, new_fnc); /* next = fnc */ - return; - } - -dt_newfnc (uptr, DTS_STA (DTS_ATSF | new_dir, new_fnc));/* state = fnc */ -return; -} - -/* Schedule new DECtape function - - This routine is only called if - - the selected unit is attached - - the selected unit is at speed (forward or backward) - - This routine - - updates the selected unit's position - - updates the selected unit's state - - schedules the new operation -*/ - -void dt_newfnc (UNIT *uptr, int32 newsta) -{ -int32 fnc, dir, blk, unum, newpos; -#if defined (TC02) -int32 relpos; -#endif -uint32 oldpos; - -oldpos = uptr->pos; /* save old pos */ -if (dt_setpos (uptr)) /* update pos */ - return; -uptr->STATE = newsta; /* update state */ -fnc = DTS_GETFNC (uptr->STATE); /* set variables */ -dir = DTS_GETMOT (uptr->STATE) & DTS_DIR; -unum = (int32) (uptr - dt_dev.units); -if (oldpos == uptr->pos) /* bump pos */ - uptr->pos = uptr->pos + (dir? -1: 1); -blk = DT_LIN2BL (uptr->pos, uptr); - -if (dir? DT_QREZ (uptr): DT_QFEZ (uptr)) { /* wrong ez? */ - dt_seterr (uptr, DTB_END); /* set ez flag, stop */ - return; - } -sim_cancel (uptr); /* cancel cur op */ -dt_substate = DTO_SOB; /* substate = block start */ -switch (fnc) { /* case function */ - - case DTS_OFR: /* off reel */ - if (dir) /* rev? < start */ - newpos = -1000; - else newpos = DTU_FWDEZ (uptr) + DT_EZLIN + 1000; /* fwd? > end */ - break; - - case FNC_MOVE: /* move */ - dt_schedez (uptr, dir); /* sched end zone */ - if (DEBUG_PRI (dt_dev, LOG_MS)) - fprintf (sim_deb, ">>DT%d: moving %s\n", - unum, (dir? "backward": "forward")); - return; /* done */ - - case FNC_SRCH: /* search */ - if (dir) - newpos = DT_BLK2LN ((DT_QFEZ (uptr)? - DTU_TSIZE (uptr): blk), uptr) - DT_BLKLN - DT_WSIZE; - else newpos = DT_BLK2LN ((DT_QREZ (uptr)? - 0: blk + 1), uptr) + DT_BLKLN + (DT_WSIZE - 1); - if (DEBUG_PRI (dt_dev, LOG_MS)) - fprintf (sim_deb, ">>DT%d: searching %s\n", unum, - (dir? "backward": "forward")); - break; - - case FNC_WRIT: /* write */ - case FNC_READ: /* read */ -#if defined (TC02) /* TC02/TC15 */ - if (DT_QEZ (uptr)) { /* in "ok" end zone? */ - if (dir) - newpos = DTU_FWDEZ (uptr) - DT_HTLIN - DT_WSIZE; - else newpos = DT_EZLIN + DT_HTLIN + (DT_WSIZE - 1); - break; - } - relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ - if ((relpos >= DT_HTLIN) && /* in data zone? */ - (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { - dt_seterr (uptr, DTB_SEL); - return; - } - if (dir) - newpos = DT_BLK2LN (((relpos >= (DTU_LPERB (uptr) - DT_HTLIN))? - blk + 1: blk), uptr) - DT_HTLIN - DT_WSIZE; - else newpos = DT_BLK2LN (((relpos < DT_HTLIN)? - blk: blk + 1), uptr) + DT_HTLIN + (DT_WSIZE - 1); - break; -#endif - - case FNC_RALL: /* read all */ - case FNC_WALL: /* write all */ - if (DT_QEZ (uptr)) { /* in "ok" end zone? */ - if (dir) - newpos = DTU_FWDEZ (uptr) - DT_WSIZE; - else newpos = DT_EZLIN + (DT_WSIZE - 1); - } - else { - newpos = ((uptr->pos) / DT_WSIZE) * DT_WSIZE; - if (!dir) - newpos = newpos + (DT_WSIZE - 1); - } - if (DEBUG_PRI (dt_dev, LOG_RA) || - (DEBUG_PRI (dt_dev, LOG_BL) && (blk == dt_logblk))) - fprintf (sim_deb, ">>DT%d: read all block %d %s%s\n", - unum, blk, (dir? "backward": "forward"), - ((dtsa & DTA_MODE)? " continuous]": " ")); - break; - - default: - dt_seterr (uptr, DTB_SEL); /* bad state */ - return; - } - -#if defined (TYPE550) /* Type 550 */ -if ((fnc == FNC_WRIT) || (fnc == FNC_WALL)) { /* write function? */ - dtsb = dtsb | DTB_DTF; /* set data flag */ - DT_UPDINT; - } -#endif - -sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime); -return; -} - -/* Update DECtape position - - DECtape motion is modeled as a constant velocity, with linear - acceleration and deceleration. The motion equations are as follows: - - t = time since operation started - tmax = time for operation (accel, decel only) - v = at speed velocity in lines (= 1/dt_ltime) - - Then: - at speed dist = t * v - accel dist = (t^2 * v) / (2 * tmax) - decel dist = (((2 * t * tmax) - t^2) * v) / (2 * tmax) - - This routine uses the relative (integer) time, rather than the absolute - (floating point) time, to allow save and restore of the start times. -*/ - -t_bool dt_setpos (UNIT *uptr) -{ -uint32 new_time, ut, ulin, udelt; -int32 mot = DTS_GETMOT (uptr->STATE); -int32 unum, delta; - -new_time = sim_grtime (); /* current time */ -ut = new_time - uptr->LASTT; /* elapsed time */ -if (ut == 0) /* no time gone? exit */ - return FALSE; -uptr->LASTT = new_time; /* update last time */ -switch (mot & ~DTS_DIR) { /* case on motion */ - - case DTS_STOP: /* stop */ - delta = 0; - break; - - case DTS_DECF: /* slowing */ - ulin = ut / (uint32) dt_ltime; - udelt = dt_dctime / dt_ltime; - delta = ((ulin * udelt * 2) - (ulin * ulin)) / (2 * udelt); - break; - - case DTS_ACCF: /* accelerating */ - ulin = ut / (uint32) dt_ltime; - udelt = (dt_dctime - (dt_dctime >> 2)) / dt_ltime; - delta = (ulin * ulin) / (2 * udelt); - break; - - case DTS_ATSF: /* at speed */ - delta = ut / (uint32) dt_ltime; - break; - } - -if (mot & DTS_DIR) /* update pos */ - uptr->pos = uptr->pos - delta; -else uptr->pos = uptr->pos + delta; -if (((int32) uptr->pos < 0) || - ((int32) uptr->pos > (DTU_FWDEZ (uptr) + DT_EZLIN))) { - detach_unit (uptr); /* off reel? */ - uptr->STATE = uptr->pos = 0; - unum = (int32) (uptr - dt_dev.units); - if (unum == DTA_GETUNIT (dtsa)) /* if selected, */ - dt_seterr (uptr, DTB_SEL); /* error */ - return TRUE; - } -return FALSE; -} - -/* Unit service - - Unit must be attached, detach cancels operation -*/ - -t_stat dt_svc (UNIT *uptr) -{ -int32 mot = DTS_GETMOT (uptr->STATE); -int32 dir = mot & DTS_DIR; -int32 fnc = DTS_GETFNC (uptr->STATE); -int32 *fbuf = (int32 *) uptr->filebuf; -int32 unum = uptr - dt_dev.units; -int32 blk, wrd, ma, relpos; -uint32 ba; - -/* Motion cases - - Decelerating - if next state != stopped, must be accel reverse - Accelerating - next state must be @speed, schedule function - At speed - do functional processing -*/ - -switch (mot) { - - case DTS_DECF: case DTS_DECR: /* decelerating */ - if (dt_setpos (uptr)) /* upd pos; off reel? */ - return IORETURN (dt_stopoffr, STOP_DTOFF); - uptr->STATE = DTS_NXTSTA (uptr->STATE); /* advance state */ - if (uptr->STATE) /* not stopped? */ - sim_activate (uptr, dt_dctime - (dt_dctime >> 2)); /* reversing */ - return SCPE_OK; - - case DTS_ACCF: case DTS_ACCR: /* accelerating */ - dt_newfnc (uptr, DTS_NXTSTA (uptr->STATE)); /* adv state, sched */ - return SCPE_OK; - - case DTS_ATSF: case DTS_ATSR: /* at speed */ - break; /* check function */ - - default: /* other */ - dt_seterr (uptr, DTB_SEL); /* state error */ - return SCPE_OK; - } - -/* Functional cases - - Move - must be at end zone - Search - transfer block number, schedule next block - Off reel - detach unit (it must be deselected) -*/ - -if (dt_setpos (uptr)) /* upd pos; off reel? */ - return IORETURN (dt_stopoffr, STOP_DTOFF); -if (DT_QEZ (uptr)) { /* in end zone? */ - dt_seterr (uptr, DTB_END); /* end zone error */ - return SCPE_OK; - } -blk = DT_LIN2BL (uptr->pos, uptr); /* get block # */ - -switch (fnc) { /* at speed, check fnc */ - - case FNC_MOVE: /* move */ - dt_seterr (uptr, DTB_END); /* end zone error */ - return SCPE_OK; - - case DTS_OFR: /* off reel */ - detach_unit (uptr); /* must be deselected */ - uptr->STATE = uptr->pos = 0; /* no visible action */ - break; - -/* TC02/TC15 service */ -/* Search */ - -#if defined (TC02) /* TC02/TC15 */ - - case FNC_SRCH: /* search */ - if (dtsb & DTB_DTF) { /* DTF set? */ - dt_seterr (uptr, DTB_TIM); /* timing error */ - return SCPE_OK; - } - sim_activate (uptr, DTU_LPERB (uptr) * dt_ltime);/* sched next block */ - M[DT_WC] = (M[DT_WC] + 1) & DMASK; /* inc WC */ - ma = M[DT_CA] & AMASK; /* get mem addr */ - if (MEM_ADDR_OK (ma)) /* store block # */ - M[ma] = blk; - if (((dtsa & DTA_MODE) == 0) || (M[DT_WC] == 0)) - dtsb = dtsb | DTB_DTF; /* set DTF */ - if (DEBUG_PRI (dt_dev, LOG_MS)) - fprintf (sim_deb, ">>DT%d: found block %d\n", unum, blk); - break; - -/* Read has four subcases - - Start of block, not wc ovf - check that DTF is clear, otherwise normal - Normal - increment MA, WC, copy word from tape to memory - if read dir != write dir, bits must be scrambled - if wc overflow, next state is wc overflow - if end of block, possibly set DTF, next state is start of block - Wc ovf, not start of block - - if end of block, possibly set DTF, next state is start of block - Wc ovf, start of block - if end of block reached, timing error, - otherwise, continue to next word -*/ - - case FNC_READ: /* read */ - wrd = DT_LIN2WD (uptr->pos, uptr); /* get word # */ - switch (dt_substate) { /* case on substate */ - - case DTO_SOB: /* start of block */ - if (dtsb & DTB_DTF) { /* DTF set? */ - dt_seterr (uptr, DTB_TIM); /* timing error */ - return SCPE_OK; - } - if (DEBUG_PRI (dt_dev, LOG_RW) || - (DEBUG_PRI (dt_dev, LOG_BL) && (blk == dt_logblk))) - fprintf (sim_deb, ">>DT%d: reading block %d %s%s\n", - unum, blk, (dir? "backward": "forward"), - ((dtsa & DTA_MODE)? " continuous": " ")); - dt_substate = 0; /* fall through */ - case 0: /* normal read */ - M[DT_WC] = (M[DT_WC] + 1) & DMASK; /* incr WC, CA */ - M[DT_CA] = (M[DT_CA] + 1) & DMASK; - ma = M[DT_CA] & AMASK; /* mem addr */ - ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */ - dtdb = fbuf[ba]; /* get tape word */ - if (dir) /* rev? comp obv */ - dtdb = dt_comobv (dtdb); - if (MEM_ADDR_OK (ma)) /* mem addr legal? */ - M[ma] = dtdb; - if (M[DT_WC] == 0) /* wc ovf? */ - dt_substate = DTO_WCO; - case DTO_WCO: /* wc ovf, not sob */ - if (wrd != (dir? 0: DTU_BSIZE (uptr) - 1)) /* not last? */ - sim_activate (uptr, DT_WSIZE * dt_ltime); - else { - dt_substate = dt_substate | DTO_SOB; - sim_activate (uptr, ((2 * DT_HTLIN) + DT_WSIZE) * dt_ltime); - if (((dtsa & DTA_MODE) == 0) || (M[DT_WC] == 0)) - dtsb = dtsb | DTB_DTF; /* set DTF */ - } - break; - - case DTO_WCO | DTO_SOB: /* next block */ - if (wrd == (dir? 0: DTU_BSIZE (uptr))) /* end of block? */ - dt_seterr (uptr, DTB_TIM); /* timing error */ - else sim_activate (uptr, DT_WSIZE * dt_ltime); - break; - } /* end case subst */ - break; - -/* Write has four subcases - - Start of block, not wc ovf - check that DTF is clear, set block direction - Normal - increment MA, WC, copy word from memory to tape - if wc overflow, next state is wc overflow - if end of block, possibly set DTF, next state is start of block - Wc ovf, not start of block - - copy 0 to tape - if end of block, possibly set DTF, next state is start of block - Wc ovf, start of block - schedule end zone -*/ - - case FNC_WRIT: /* write */ - wrd = DT_LIN2WD (uptr->pos, uptr); /* get word # */ - switch (dt_substate) { /* case on substate */ - - case DTO_SOB: /* start block */ - if (dtsb & DTB_DTF) { /* DTF set? */ - dt_seterr (uptr, DTB_TIM); /* timing error */ - return SCPE_OK; - } - if (DEBUG_PRI (dt_dev, LOG_RW) || - (DEBUG_PRI (dt_dev, LOG_BL) && (blk == dt_logblk))) - fprintf (sim_deb, ">>DT%d: writing block %d %s%s\n", unum, blk, - (dir? "backward": "forward"), - ((dtsa & DTA_MODE)? " continuous": " ")); - dt_substate = 0; /* fall through */ - case 0: /* normal write */ - M[DT_WC] = (M[DT_WC] + 1) & DMASK; /* incr WC, CA */ - M[DT_CA] = (M[DT_CA] + 1) & DMASK; - case DTO_WCO: /* wc ovflo */ - ma = M[DT_CA] & AMASK; /* mem addr */ - ba = (blk * DTU_BSIZE (uptr)) + wrd; /* buffer ptr */ - dtdb = dt_substate? 0: M[ma]; /* get word */ - if (dir) /* rev? comp obv */ - dtdb = dt_comobv (dtdb); - fbuf[ba] = dtdb; /* write word */ - if (ba >= uptr->hwmark) - uptr->hwmark = ba + 1; - if (M[DT_WC] == 0) - dt_substate = DTO_WCO; - if (wrd != (dir? 0: DTU_BSIZE (uptr) - 1)) /* not last? */ - sim_activate (uptr, DT_WSIZE * dt_ltime); - else { - dt_substate = dt_substate | DTO_SOB; - sim_activate (uptr, ((2 * DT_HTLIN) + DT_WSIZE) * dt_ltime); - if (((dtsa & DTA_MODE) == 0) || (M[DT_WC] == 0)) - dtsb = dtsb | DTB_DTF; /* set DTF */ - } - break; - - case DTO_WCO | DTO_SOB: /* all done */ - dt_schedez (uptr, dir); /* sched end zone */ - break; - } /* end case subst */ - break; - -/* Read all has two subcases - - Not word count overflow - increment MA, WC, copy word from tape to memory - Word count overflow - schedule end zone -*/ - - case FNC_RALL: /* read all */ - switch (dt_substate) { /* case on substate */ - - case 0: case DTO_SOB: /* read in progress */ - if (dtsb & DTB_DTF) { /* DTF set? */ - dt_seterr (uptr, DTB_TIM); /* timing error */ - return SCPE_OK; - } - relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ - M[DT_WC] = (M[DT_WC] + 1) & DMASK; /* incr WC, CA */ - M[DT_CA] = (M[DT_CA] + 1) & DMASK; - ma = M[DT_CA] & AMASK; /* mem addr */ - if ((relpos >= DT_HTLIN) && /* in data zone? */ - (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { - wrd = DT_LIN2WD (uptr->pos, uptr); - ba = (blk * DTU_BSIZE (uptr)) + wrd; - dtdb = fbuf[ba]; /* get tape word */ - } - else dtdb = dt_gethdr (uptr, blk, relpos); /* get hdr */ - if (dir) /* rev? comp obv */ - dtdb = dt_comobv (dtdb); - sim_activate (uptr, DT_WSIZE * dt_ltime); - if (MEM_ADDR_OK (ma)) /* mem addr legal? */ - M[ma] = dtdb; - if (M[DT_WC] == 0) - dt_substate = DTO_WCO; - if (((dtsa & DTA_MODE) == 0) || (M[DT_WC] == 0)) - dtsb = dtsb | DTB_DTF; /* set DTF */ - break; - - case DTO_WCO: case DTO_WCO | DTO_SOB: /* all done */ - dt_schedez (uptr, dir); /* sched end zone */ - break; - } /* end case substate */ - break; - -/* Write all has two subcases - - Not word count overflow - increment MA, WC, copy word from memory to tape - Word count overflow - schedule end zone -*/ - - case FNC_WALL: /* write all */ - switch (dt_substate) { /* case on substate */ - - case 0: case DTO_SOB: /* read in progress */ - if (dtsb & DTB_DTF) { /* DTF set? */ - dt_seterr (uptr, DTB_TIM); /* timing error */ - return SCPE_OK; - } - relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ - M[DT_WC] = (M[DT_WC] + 1) & DMASK; /* incr WC, CA */ - M[DT_CA] = (M[DT_CA] + 1) & DMASK; - ma = M[DT_CA] & AMASK; /* mem addr */ - if ((relpos >= DT_HTLIN) && /* in data zone? */ - (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { - dtdb = M[ma]; /* get mem word */ - if (dir) - dtdb = dt_comobv (dtdb); - wrd = DT_LIN2WD (uptr->pos, uptr); - ba = (blk * DTU_BSIZE (uptr)) + wrd; - fbuf[ba] = dtdb; /* write word */ - if (ba >= uptr->hwmark) - uptr->hwmark = ba + 1; - } - /* ignore hdr */ - sim_activate (uptr, DT_WSIZE * dt_ltime); - if (M[DT_WC] == 0) - dt_substate = DTO_WCO; - if (((dtsa & DTA_MODE) == 0) || (M[DT_WC] == 0)) - dtsb = dtsb | DTB_DTF; /* set DTF */ - break; - - case DTO_WCO: case DTO_WCO | DTO_SOB: /* all done */ - dt_schedez (uptr, dir); /* sched end zone */ - break; - } /* end case substate */ - break; - -/* Type 550 service */ -/* Search */ - -#else /* Type 550 */ - case FNC_SRCH: /* search */ - if (dtsb & DTB_DTF) { /* DTF set? */ - dt_seterr (uptr, DTB_TIM); /* timing error */ - return SCPE_OK; - } - sim_activate (uptr, DTU_LPERB (uptr) * dt_ltime);/* sched next block */ - dtdb = blk; /* store block # */ - dtsb = dtsb | DTB_DTF; /* set DTF */ - if (DEBUG_PRI (dt_dev, LOG_MS)) - fprintf (sim_deb, ">>DT%d: search found block %d\n", unum, blk); - break; - -/* Read and read all */ - - case FNC_READ: case FNC_RALL: - if (dtsb & DTB_DTF) { /* DTF set? */ - dt_seterr (uptr, DTB_TIM); /* timing error */ - return SCPE_OK; - } - sim_activate (uptr, DT_WSIZE * dt_ltime); /* sched next word */ - relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ - if ((relpos >= DT_HTLIN) && /* in data zone? */ - (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { - wrd = DT_LIN2WD (uptr->pos, uptr); - ba = (blk * DTU_BSIZE (uptr)) + wrd; - dtdb = fbuf[ba]; /* get tape word */ - dtsb = dtsb | DTB_DTF; /* set flag */ - } - else { - ma = (2 * DT_HTWRD) + DTU_BSIZE (uptr) - DT_CSMWD - 1; - wrd = relpos / DT_WSIZE; /* hdr start = wd 0 */ -#if defined (OLD_TYPE550) - if ((wrd == 0) || /* skip 1st, last */ - (wrd == ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - 1))) break; -#endif - if ((fnc == FNC_READ) && /* read, skip if not */ - (wrd != DT_CSMWD) && /* fwd, rev cksum */ - (wrd != ma)) - break; - dtdb = dt_gethdr (uptr, blk, relpos); - if (wrd == (dir? DT_CSMWD: ma)) /* at end csum? */ - dtsb = dtsb | DTB_BEF; /* end block */ - else dtsb = dtsb | DTB_DTF; /* else next word */ - } - if (dir) - dtdb = dt_comobv (dtdb); - break; - -/* Write and write all */ - - case FNC_WRIT: case FNC_WALL: - if (dtsb & DTB_DTF) { /* DTF set? */ - dt_seterr (uptr, DTB_TIM); /* timing error */ - return SCPE_OK; - } - sim_activate (uptr, DT_WSIZE * dt_ltime); /* sched next word */ - relpos = DT_LIN2OF (uptr->pos, uptr); /* cur pos in blk */ - if ((relpos >= DT_HTLIN) && /* in data zone? */ - (relpos < (DTU_LPERB (uptr) - DT_HTLIN))) { - wrd = DT_LIN2WD (uptr->pos, uptr); - ba = (blk * DTU_BSIZE (uptr)) + wrd; - if (dir) /* get data word */ - fbuf[ba] = dt_comobv (dtdb); - else fbuf[ba] = dtdb; - if (ba >= uptr->hwmark) - uptr->hwmark = ba + 1; - if (wrd == (dir? 0: DTU_BSIZE (uptr) - 1)) - dtsb = dtsb | DTB_BEF; /* end block */ - else dtsb = dtsb | DTB_DTF; /* else next word */ - } - else { - wrd = relpos / DT_WSIZE; /* hdr start = wd 0 */ -#if defined (OLD_TYPE550) - if ((wrd == 0) || /* skip 1st, last */ - (wrd == ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - 1))) break; -#endif - if ((fnc == FNC_WRIT) && /* wr, skip if !csm */ - (wrd != ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - DT_CSMWD - 1))) - break; - dtsb = dtsb | DTB_DTF; /* set flag */ - } - break; -#endif - - default: - dt_seterr (uptr, DTB_SEL); /* impossible state */ - break; - } /* end case function */ - -DT_UPDINT; /* update interrupts */ -return SCPE_OK; -} - -/* Utility routines */ - -/* Set error flag */ - -void dt_seterr (UNIT *uptr, int32 e) -{ -dtsa = dtsa & ~DTA_STSTP; /* clear go */ -dtsb = dtsb | DTB_ERF | e; /* set error flag */ -if (uptr != NULL) { /* valid select? */ - int32 mot = DTS_GETMOT (uptr->STATE); /* get motion */ - if (mot >= DTS_ACCF) { /* ~stopped or stopping? */ - sim_cancel (uptr); /* cancel activity */ - if (dt_setpos (uptr)) /* update position */ - return; - sim_activate (uptr, dt_dctime); /* sched decel */ - DTS_SETSTA (DTS_DECF | (mot & DTS_DIR), 0); /* state = decel */ - } - else DTS_SETSTA (mot, 0); /* clear 2nd, 3rd */ - } -DT_UPDINT; -return; -} - -/* Schedule end zone */ - -void dt_schedez (UNIT *uptr, int32 dir) -{ -int32 newpos; - -if (dir) /* rev? rev ez */ - newpos = DT_EZLIN - DT_WSIZE; -else newpos = DTU_FWDEZ (uptr) + DT_WSIZE; /* fwd? fwd ez */ -sim_activate (uptr, ABS (newpos - ((int32) uptr->pos)) * dt_ltime); -return; -} - -/* Complement obverse routine */ - -int32 dt_comobv (int32 dat) -{ -dat = dat ^ DMASK; /* compl obverse */ -dat = ((dat >> 15) & 07) | ((dat >> 9) & 070) | - ((dat >> 3) & 0700) | ((dat & 0700) << 3) | - ((dat & 070) << 9) | ((dat & 07) << 15); -return dat; -} - -/* Checksum routine */ - -int32 dt_csum (UNIT *uptr, int32 blk) -{ -int32 *fbuf = (int32 *) uptr->filebuf; -int32 ba = blk * DTU_BSIZE (uptr); -int32 i, csum, wrd; - -#if defined (TC02) /* TC02/TC15 */ -csum = 077; /* init csum */ -for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */ - wrd = fbuf[ba + i] ^ DMASK; /* get ~word */ - csum = csum ^ (wrd >> 12) ^ (wrd >> 6) ^ wrd; - } -return (csum & 077); -#else /* Type 550 */ -csum = 0777777; -for (i = 0; i < DTU_BSIZE (uptr); i++) { /* loop thru buf */ - wrd = fbuf[ba + i]; /* get word */ - csum = csum + wrd; /* 1's comp add */ - if (csum > DMASK) - csum = (csum + 1) & DMASK; - } -return (csum ^ DMASK); /* 1's comp res */ -#endif -} - -/* Get header word */ - -int32 dt_gethdr (UNIT *uptr, int32 blk, int32 relpos) -{ -int32 wrd = relpos / DT_WSIZE; - -if (wrd == DT_BLKWD) /* fwd blknum */ - return blk; -#if defined (TC02) /* TC02/TC15 */ -if (wrd == DT_CSMWD) /* rev csum */ - return 077; -if (wrd == ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - DT_CSMWD - 1)) /* fwd csum */ - return (dt_csum (uptr, blk) << 12); -#else /* Type 550 */ -if (wrd == DT_CSMWD) /* rev csum */ - return 0777777; -if (wrd == ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - DT_CSMWD - 1)) /* fwd csum */ - return (dt_csum (uptr, blk)); -#endif -if (wrd == ((2 * DT_HTWRD) + DTU_BSIZE (uptr) - DT_BLKWD - 1)) /* rev blkno */ - return dt_comobv (blk); -return 0; /* all others */ -} - -/* Reset routine */ - -t_stat dt_reset (DEVICE *dptr) -{ -int32 i, prev_mot; -UNIT *uptr; - -for (i = 0; i < DT_NUMDR; i++) { /* stop all drives */ - uptr = dt_dev.units + i; - if (sim_is_running) { /* CAF? */ - prev_mot = DTS_GETMOT (uptr->STATE); /* get motion */ - if ((prev_mot & ~DTS_DIR) > DTS_DECF) { /* accel or spd? */ - if (dt_setpos (uptr)) /* update pos */ - continue; - sim_cancel (uptr); - sim_activate (uptr, dt_dctime); /* sched decel */ - DTS_SETSTA (DTS_DECF | (prev_mot & DTS_DIR), 0); - } - } - else { - sim_cancel (uptr); /* sim reset */ - uptr->STATE = 0; - uptr->LASTT = sim_grtime (); - } - } -dtsa = dtsb = 0; /* clear status */ -DT_UPDINT; /* reset interrupt */ -return SCPE_OK; -} - -/* IORS routine */ - -int32 dt_iors (void) -{ -#if defined IOS_DTA -return ((dtsb & (DTB_ERF | DTB_DTF))? IOS_DTA: 0); -#else -return 0; -#endif -} - -/* Attach routine - - Determine 12b, 16b, or 18b/36b format - Allocate buffer - If 12b, read 12b format and convert to 18b in buffer - If 16b, read 16b format and convert to 18b in buffer - If 18b/36b, read data into buffer -*/ - -t_stat dt_attach (UNIT *uptr, char *cptr) -{ -uint16 pdp8b[D8_NBSIZE]; -uint16 pdp11b[D18_BSIZE]; -uint32 ba, sz, k, *fbuf; -int32 u = uptr - dt_dev.units; -t_stat r; - -r = attach_unit (uptr, cptr); /* attach */ -if (r != SCPE_OK) /* error? */ - return r; -if ((sim_switches & SIM_SW_REST) == 0) { /* not from rest? */ - uptr->flags = uptr->flags & ~(UNIT_8FMT | UNIT_11FMT); /* default 18b */ - if (sim_switches & SWMASK ('T')) /* att 12b? */ - uptr->flags = uptr->flags | UNIT_8FMT; - else if (sim_switches & SWMASK ('S')) /* att 16b? */ - uptr->flags = uptr->flags | UNIT_11FMT; - else if (!(sim_switches & SWMASK ('A')) && /* autosize? */ - (sz = sim_fsize (uptr->fileref))) { - if (sz == D8_FILSIZ) - uptr->flags = uptr->flags | UNIT_8FMT; - else if (sz == D11_FILSIZ) - uptr->flags = uptr->flags | UNIT_11FMT; - } - } -uptr->capac = DTU_CAPAC (uptr); /* set capacity */ -uptr->filebuf = calloc (uptr->capac, sizeof (uint32)); -if (uptr->filebuf == NULL) { /* can't alloc? */ - detach_unit (uptr); - return SCPE_MEM; - } -fbuf = (uint32 *) uptr->filebuf; /* file buffer */ -sim_printf ("%s%d: ", sim_dname (&dt_dev), u); -if (uptr->flags & UNIT_8FMT) - sim_printf ("12b format"); -else if (uptr->flags & UNIT_11FMT) - sim_printf ("16b format"); -else sim_printf ("18b/36b format"); -sim_printf (", buffering file in memory\n"); -if (uptr->flags & UNIT_8FMT) { /* 12b? */ - for (ba = 0; ba < uptr->capac; ) { /* loop thru file */ - k = fxread (pdp8b, sizeof (uint16), D8_NBSIZE, uptr->fileref); - if (k == 0) - break; - for ( ; k < D8_NBSIZE; k++) - pdp8b[k] = 0; - for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop thru blk */ - fbuf[ba] = ((uint32) (pdp8b[k] & 07777) << 6) | - ((uint32) (pdp8b[k + 1] >> 6) & 077); - fbuf[ba + 1] = ((uint32) (pdp8b[k + 1] & 077) << 12) | - ((uint32) pdp8b[k + 2] & 07777); - ba = ba + 2; /* end blk loop */ - } - } /* end file loop */ - uptr->hwmark = ba; - } /* end if */ -else if (uptr->flags & UNIT_11FMT) { /* 16b? */ - for (ba = 0; ba < uptr->capac; ) { /* loop thru file */ - k = fxread (pdp11b, sizeof (uint16), D18_BSIZE, uptr->fileref); - if (k == 0) - break; - for ( ; k < D18_BSIZE; k++) - pdp11b[k] = 0; - for (k = 0; k < D18_BSIZE; k++) - fbuf[ba++] = pdp11b[k]; - } - uptr->hwmark = ba; - } /* end elif */ -else uptr->hwmark = fxread (uptr->filebuf, sizeof (uint32), - uptr->capac, uptr->fileref); -uptr->flags = uptr->flags | UNIT_BUF; /* set buf flag */ -uptr->pos = DT_EZLIN; /* beyond leader */ -uptr->LASTT = sim_grtime (); /* last pos update */ -return SCPE_OK; -} - -/* Detach routine - - Cancel in progress operation - If 12b, convert 18b buffer to 12b and write to file - If 16b, convert 18b buffer to 16b and write to file - If 18b/36b, write buffer to file - Deallocate buffer -*/ - -t_stat dt_detach (UNIT* uptr) -{ -uint16 pdp8b[D8_NBSIZE]; -uint16 pdp11b[D18_BSIZE]; -uint32 ba, k, *fbuf; -int32 u = uptr - dt_dev.units; - -if (!(uptr->flags & UNIT_ATT)) - return SCPE_OK; -if (sim_is_active (uptr)) { - sim_cancel (uptr); - if ((u == DTA_GETUNIT (dtsa)) && (dtsa & DTA_STSTP)) { - dtsb = dtsb | DTB_ERF | DTB_SEL | DTB_DTF; - DT_UPDINT; - } - uptr->STATE = uptr->pos = 0; - } -fbuf = (uint32 *) uptr->filebuf; /* file buffer */ -if (uptr->hwmark && ((uptr->flags & UNIT_RO) == 0)) { /* any data? */ - sim_printf ("%s%d: writing buffer to file\n", sim_dname (&dt_dev), u); - rewind (uptr->fileref); /* start of file */ - if (uptr->flags & UNIT_8FMT) { /* 12b? */ - for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */ - for (k = 0; k < D8_NBSIZE; k = k + 3) { /* loop blk */ - pdp8b[k] = (fbuf[ba] >> 6) & 07777; - pdp8b[k + 1] = ((fbuf[ba] & 077) << 6) | - ((fbuf[ba + 1] >> 12) & 077); - pdp8b[k + 2] = fbuf[ba + 1] & 07777; - ba = ba + 2; - } /* end loop blk */ - fxwrite (pdp8b, sizeof (uint16), D8_NBSIZE, uptr->fileref); - if (ferror (uptr->fileref)) - break; - } /* end loop file */ - } /* end if 12b */ - else if (uptr->flags & UNIT_11FMT) { /* 16b? */ - for (ba = 0; ba < uptr->hwmark; ) { /* loop thru file */ - for (k = 0; k < D18_BSIZE; k++) /* loop blk */ - pdp11b[k] = fbuf[ba++] & 0177777; - fxwrite (pdp11b, sizeof (uint16), D18_BSIZE, uptr->fileref); - if (ferror (uptr->fileref)) - break; - } /* end loop file */ - } /* end if 16b */ - else fxwrite (uptr->filebuf, sizeof (uint32), /* write file */ - uptr->hwmark, uptr->fileref); - if (ferror (uptr->fileref)) - perror ("I/O error"); - } /* end if hwmark */ -free (uptr->filebuf); /* release buf */ -uptr->flags = uptr->flags & ~UNIT_BUF; /* clear buf flag */ -uptr->filebuf = NULL; /* clear buf ptr */ -uptr->flags = uptr->flags & ~(UNIT_8FMT | UNIT_11FMT); /* default fmt */ -uptr->capac = DT_CAPAC; /* default size */ -return detach_unit (uptr); -} diff --git a/PDP18B/pdp18b_fpp.c b/PDP18B/pdp18b_fpp.c deleted file mode 100644 index ffbf70d4..00000000 --- a/PDP18B/pdp18b_fpp.c +++ /dev/null @@ -1,909 +0,0 @@ -/* pdp18b_fpp.c: FP15 floating point processor simulator - - Copyright (c) 2003-2016, 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. - - fpp PDP-15 floating point processor - - 07-Mar-16 RMS Revised for dynamically allocated memory - 19-Mar-12 RMS Fixed declaration of pc queue (Mark Pizzolato) - 06-Jul-06 RMS Fixed bugs in left shift, multiply - 31-Oct-04 RMS Fixed URFST to mask low 9b of fraction - Fixed exception PC setting - 10-Apr-04 RMS JEA is 15b not 18b - - The FP15 instruction format is: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 1 1 1 0 0 1| subop | microcoded modifiers | floating point - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - |in| address | - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - Indirection is always single level. - - The FP15 supports four data formats: - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | S| 2's complement integer | A: integer - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | S| 2's complement integer (high) | A: extended integer - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | 2's complement integer (low) | A+1 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | fraction (low) |SE|2's complement exponent| A: single floating - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - |SF| fraction (high) | A+1 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - - 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - |SE| 2's complement exponent | A: double floating - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - |SF| fraction (high) | A+1 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - | fraction (low) | A+2 - +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ - -*/ - -#include "pdp18b_defs.h" - -/* Instruction */ - -#define FI_V_OP 8 /* subopcode */ -#define FI_M_OP 017 -#define FI_GETOP(x) (((x) >> FI_V_OP) & FI_M_OP) -#define FI_NOLOAD 0200 /* don't load */ -#define FI_DP 0100 /* single/double */ -#define FI_FP 0040 /* int/flt point */ -#define FI_NONORM 0020 /* don't normalize */ -#define FI_NORND 0010 /* don't round */ -#define FI_V_SGNOP 0 /* A sign change */ -#define FI_M_SGNOP 03 -#define FI_GETSGNOP(x) (((x) >> FI_V_SGNOP) & FI_M_SGNOP) - -/* Exception register */ - -#define JEA_V_SIGN 17 /* A sign */ -#define JEA_V_GUARD 16 /* guard */ -#define JEA_EAMASK 077777 /* exc address */ -#define JEA_OFF_OVF 0 /* ovf offset */ -#define JEA_OFF_UNF 2 /* unf offset */ -#define JEA_OFF_DIV 4 /* div offset */ -#define JEA_OFF_MM 6 /* mem mgt offset */ - -/* Status codes - must relate directly to JEA offsets */ - -#define FP_OK 0 /* no error - mbz */ -#define FP_OVF (JEA_OFF_OVF + 1) /* overflow */ -#define FP_UNF (JEA_OFF_UNF + 1) /* underflow */ -#define FP_DIV (JEA_OFF_DIV + 1) /* divide exception */ -#define FP_MM (JEA_OFF_MM + 1) /* mem mgt error */ - -/* Unpacked floating point fraction */ - -#define UFP_FH_CARRY 0400000 /* carry out */ -#define UFP_FH_NORM 0200000 /* normalized */ -#define UFP_FH_MASK 0377777 /* hi mask */ -#define UFP_FL_MASK 0777777 /* low mask */ -#define UFP_FL_SMASK 0777000 /* low mask, single */ -#define UFP_FL_SRND 0000400 /* round bit, single */ - -#define GET_SIGN(x) (((x) >> 17) & 1) -#define SEXT18(x) (((x) & SIGN)? ((x) | ~DMASK): ((x) & DMASK)) -#define SEXT9(x) (((x) & 0400)? ((x) | ~0377): ((x) & 0377)) - -enum fop { - FOP_TST, FOP_SUB, FOP_RSUB, FOP_MUL, - FOP_DIV, FOP_RDIV, FOP_LD, FOP_ST, - FOP_FLT, FOP_FIX, FOP_LFMQ, FOP_JEA, - FOP_ADD, FOP_BR, FOP_DIAG, FOP_UND - }; - -typedef struct { - int32 exp; /* exponent */ - int32 sign; /* sign */ - int32 hi; /* hi frac, 17b */ - int32 lo; /* lo frac, 18b */ - } UFP; - -static int32 fir; /* instruction */ -static int32 jea; /* exc address */ -static int32 fguard; /* guard bit */ -static int32 stop_fpp = STOP_RSRV; /* stop if fp dis */ -static UFP fma; /* FMA */ -static UFP fmb; /* FMB */ -static UFP fmq; /* FMQ - hi,lo only */ - -extern int32 *M; -#if defined (PDP15) -extern int32 pcq[PCQ_SIZE]; /* PC queue */ -#else -extern int16 pcq[PCQ_SIZE]; /* PC queue */ -#endif -extern int32 pcq_p; -extern int32 PC; -extern int32 trap_pending, usmd; - -t_stat fp15_reset (DEVICE *dptr); -t_stat fp15_opnd (int32 ir, int32 addr, UFP *a); -t_stat fp15_store (int32 ir, int32 addr, UFP *a); -t_stat fp15_iadd (int32 ir, UFP *a, UFP *b, t_bool sub); -t_stat fp15_imul (int32 ir, UFP *a, UFP *b); -t_stat fp15_idiv (int32 ir, UFP *a, UFP *b); -t_stat fp15_fadd (int32 ir, UFP *a, UFP *b, t_bool sub); -t_stat fp15_fmul (int32 ir, UFP *a, UFP *b); -t_stat fp15_fdiv (int32 ir, UFP *a, UFP *b); -t_stat fp15_fix (int32 ir, UFP *a); -t_stat fp15_norm (int32 ir, UFP *a, UFP *b, t_bool rnd); -t_stat fp15_exc (t_stat sta); -void fp15_asign (int32 ir, UFP *a); -void dp_add (UFP *a, UFP *b); -void dp_sub (UFP *a, UFP *b); -void dp_inc (UFP *a); -int32 dp_cmp (UFP *a, UFP *b); -void dp_mul (UFP *a, UFP *b); -void dp_lsh_1 (UFP *a, UFP *b); -void dp_rsh_1 (UFP *a, UFP *b); -void dp_dnrm_r (int32 ir, UFP *a, int32 sc); -void dp_swap (UFP *a, UFP *b); - -extern t_stat Read (int32 ma, int32 *dat, int32 cyc); -extern t_stat Write (int32 ma, int32 dat, int32 cyc); -extern int32 Incr_addr (int32 addr); -extern int32 Jms_word (int32 t); - -/* FPP data structures - - fpp_dev FPP device descriptor - fpp_unit FPP unit - fpp_reg FPP register list - fpp_mod FPP modifier list -*/ - -UNIT fpp_unit = { UDATA (NULL, 0, 0) }; - -REG fpp_reg[] = { - { ORDATA (FIR, fir, 12) }, - { ORDATA (EPA, fma.exp, 18) }, - { FLDATA (FMAS, fma.sign, 0) }, - { ORDATA (FMAH, fma.hi, 17) }, - { ORDATA (FMAL, fma.lo, 18) }, - { ORDATA (EPB, fmb.exp, 18) }, - { FLDATA (FMBS, fmb.sign, 0) }, - { ORDATA (FMBH, fmb.hi, 17) }, - { ORDATA (FMBL, fmb.lo, 18) }, - { FLDATA (FGUARD, fguard, 0) }, - { ORDATA (FMQH, fmq.hi, 17) }, - { ORDATA (FMQL, fmq.lo, 18) }, - { ORDATA (JEA, jea, 15) }, - { FLDATA (STOP_FPP, stop_fpp, 0) }, - { NULL } - }; - -DEVICE fpp_dev = { - "FPP", &fpp_unit, fpp_reg, NULL, - 1, 8, 1, 1, 8, 18, - NULL, NULL, &fp15_reset, - NULL, NULL, NULL, - NULL, DEV_DISABLE - }; - -/* Instruction decode for FP15 - - The CPU actually fetches the instruction and the word after. If the - instruction is 71XXXX, the CPU executes it as a NOP, and the FP15 fools - the CPU into thinking that the second word is also a NOP. - - Indirect addresses are resolved during fetch, unless the NOLOAD modifier - is set and the instruction is not a store. */ - -t_stat fp15 (int32 ir) -{ -int32 ar, ma, fop, dat; -t_stat sta = FP_OK; - -if (fpp_dev.flags & DEV_DIS) /* disabled? */ - return (stop_fpp? STOP_FPDIS: SCPE_OK); -fir = ir & 07777; /* save subop + mods */ -ma = PC; /* fetch next word */ -PC = Incr_addr (PC); -if (Read (ma, &ar, RD)) /* error? MM exc */ - return fp15_exc (FP_MM); -fop = FI_GETOP (fir); /* get subopcode */ -if ((ar & SIGN) && /* indirect? */ - ((fop == FOP_ST) || !(ir & FI_NOLOAD))) { /* store or load? */ - ma = ar & AMASK; /* fetch indirect */ - if (Read (ma, &ar, RD)) - return fp15_exc (FP_MM); - } -fma.exp = SEXT18 (fma.exp); /* sext exponents */ -fmb.exp = SEXT18 (fmb.exp); -switch (fop) { /* case on subop */ - - case FOP_TST: /* NOP */ - break; - - case FOP_SUB: /* subtract */ - if ((sta = fp15_opnd (fir, ar, &fmb))) /* fetch op to FMB */ - break; - if (fir & FI_FP) /* fp? */ - sta = fp15_fadd (fir, &fma, &fmb, 1); /* yes, fp sub */ - else sta = fp15_iadd (fir, &fma, &fmb, 1); /* no, int sub */ - break; - - case FOP_RSUB: /* reverse sub */ - fmb = fma; /* FMB <- FMA */ - if ((sta = fp15_opnd (fir, ar, &fma))) /* fetch op to FMA */ - break; - if (fir & FI_FP) /* fp? */ - sta = fp15_fadd (fir, &fma, &fmb, 1); /* yes, fp sub */ - else sta = fp15_iadd (fir, &fma, &fmb, 1); /* no, int sub */ - break; - - case FOP_MUL: /* multiply */ - if ((sta = fp15_opnd (fir, ar, &fmb))) /* fetch op to FMB */ - break; - if (fir & FI_FP) /* fp? */ - sta = fp15_fmul (fir, &fma, &fmb); /* yes, fp mul */ - else sta = fp15_imul (fir, &fma, &fmb); /* no, int mul */ - break; - - case FOP_DIV: /* divide */ - if ((sta = fp15_opnd (fir, ar, &fmb))) /* fetch op to FMB */ - break; - if ((sta = fp15_opnd (fir, ar, &fmb)))break; /* fetch op to FMB */ - if (fir & FI_FP) /* fp? */ - sta = fp15_fdiv (fir, &fma, &fmb); /* yes, fp div */ - else sta = fp15_idiv (fir, &fma, &fmb); /* no, int div */ - break; - - case FOP_RDIV: /* reverse divide */ - fmb = fma; /* FMB <- FMA */ - if ((sta = fp15_opnd (fir, ar, &fma))) /* fetch op to FMA */ - break; - if (fir & FI_FP) /* fp? */ - sta = fp15_fdiv (fir, &fma, &fmb); /* yes, fp div */ - else sta = fp15_idiv (fir, &fma, &fmb); /* no, int div */ - break; - - case FOP_LD: /* load */ - if ((sta = fp15_opnd (fir, ar, &fma))) /* fetch op to FMA */ - break; - fp15_asign (fir, &fma); /* modify A sign */ - if (fir & FI_FP) /* fp? */ - sta = fp15_norm (ir, &fma, NULL, 0); /* norm, no round */ - break; - - case FOP_ST: /* store */ - fp15_asign (fir, &fma); /* modify A sign */ - sta = fp15_store (fir, ar, &fma); /* store result */ - break; - - case FOP_FLT: /* float */ - if ((sta = fp15_opnd (fir, ar, &fma))) /* fetch op to FMA */ - break; - fma.exp = 35; - fp15_asign (fir, &fma); /* adjust A sign */ - sta = fp15_norm (ir, &fma, NULL, 0); /* norm, no found */ - break; - - case FOP_FIX: /* fix */ - if ((sta = fp15_opnd (fir, ar, &fma))) /* fetch op to FMA */ - break; - sta = fp15_fix (fir, &fma); /* fix */ - break; - - case FOP_LFMQ: /* load FMQ */ - if ((sta = fp15_opnd (fir, ar, &fma))) /* fetch op to FMA */ - break; - dp_swap (&fma, &fmq); /* swap FMA, FMQ */ - fp15_asign (fir, &fma); /* adjust A sign */ - if (fir & FI_FP) /* fp? */ - sta = fp15_norm (ir, &fma, &fmq, 0); /* yes, norm, no rnd */ - break; - - case FOP_JEA: /* JEA */ - if (ir & 0200) { /* store? */ - dat = jea | (fma.sign << JEA_V_SIGN) | (fguard << JEA_V_GUARD); - sta = Write (ar, dat, WR); - } - else { /* no, load */ - if ((sta = Read (ar, &dat, RD))) - break; - fguard = (dat >> JEA_V_GUARD) & 1; - jea = dat & JEA_EAMASK; - } - break; - - case FOP_ADD: /* add */ - if ((sta = fp15_opnd (fir, ar, &fmb))) /* fetch op to FMB */ - break; - if (fir & FI_FP) /* fp? */ - sta = fp15_fadd (fir, &fma, &fmb, 0); /* yes, fp add */ - else sta = fp15_iadd (fir, &fma, &fmb, 0); /* no, int add */ - break; - - case FOP_BR: /* branch */ - if (((fir & 001) && ((fma.hi | fma.lo) == 0)) || - ((fir & 002) && fma.sign) || - ((fir & 004) && !fma.sign) || - ((fir & 010) && ((fma.hi | fma.lo) != 0)) || - ((fir & 020) && fguard)) { /* cond met? */ - PCQ_ENTRY; /* save current PC */ - PC = (PC & BLKMASK) | (ar & IAMASK); /* branch within 32K */ - } - break; - - default: - break; - } /* end switch op */ - -fma.exp = fma.exp & DMASK; /* mask exp to 18b */ -fmb.exp = fmb.exp & DMASK; -if (sta != FP_OK) return fp15_exc (sta); /* error? */ -return SCPE_OK; -} - -/* Operand load and store */ - -t_stat fp15_opnd (int32 ir, int32 addr, UFP *fpn) -{ -int32 i, numwd, wd[3]; - -fguard = 0; /* clear guard */ -if (ir & FI_NOLOAD) /* no load? */ - return FP_OK; -if (ir & FI_FP) /* fp? at least 2 */ - numwd = 2; -else numwd = 1; /* else at least 1 */ -if (ir & FI_DP) /* dp? 1 more */ - numwd = numwd + 1; -for (i = 0; i < numwd; i++) { /* fetch words */ - if (Read (addr, &wd[i], RD)) - return FP_MM; - addr = (addr + 1) & AMASK; - } -if (ir & FI_FP) { /* fp? */ - fpn->sign = GET_SIGN (wd[1]); /* frac sign */ - fpn->hi = wd[1] & UFP_FH_MASK; /* frac high */ - if (ir & FI_DP) { /* dp? */ - fpn->exp = SEXT18 (wd[0]); /* exponent */ - fpn->lo = wd[2]; /* frac low */ - } - else { /* sp */ - fpn->exp = SEXT9 (wd[0]); /* exponent */ - fpn->lo = wd[0] & UFP_FL_SMASK; /* frac low */ - } - } -else { - fpn->sign = GET_SIGN (wd[0]); /* int, get sign */ - if (ir & FI_DP) { /* dp? */ - fpn->lo = wd[1]; /* 2 words */ - fpn->hi = wd[0]; - } - else { /* single */ - fpn->lo = wd[0]; /* 1 word */ - fpn->hi = fpn->sign? DMASK: 0; /* sign extended */ - } - if (fpn->sign) { /* negative? */ - fpn->lo = (-fpn->lo) & UFP_FL_MASK; /* take abs val */ - fpn->hi = (~fpn->hi + (fpn->lo == 0)) & UFP_FH_MASK; - } - } -return FP_OK; -} - -t_stat fp15_store (int32 ir, int32 addr, UFP *a) -{ -int32 i, numwd, wd[3]; -t_stat sta; - -fguard = 0; /* clear guard */ -if (ir & FI_FP) { /* fp? */ - if ((sta = fp15_norm (ir, a, NULL, 0))) /* normalize */ - return sta; - if (ir & FI_DP) { /* dp? */ - wd[0] = a->exp & DMASK; /* exponent */ - wd[1] = (a->sign << 17) | a->hi; /* hi frac */ - wd[2] = a->lo; /* low frac */ - numwd = 3; /* 3 words */ - } - else { /* single */ - if (!(ir & FI_NORND) && (a->lo & UFP_FL_SRND)) { /* round? */ - a->lo = (a->lo + UFP_FL_SRND) & UFP_FL_SMASK; - a->hi = (a->hi + (a->lo == 0)) & UFP_FH_MASK; - if ((a->hi | a->lo) == 0) { /* carry out? */ - a->hi = UFP_FH_NORM; /* shift back */ - a->exp = a->exp + 1; - } - } - if (a->exp > 0377) /* sp ovf? */ - return FP_OVF; - if (a->exp < -0400) /* sp unf? */ - return FP_UNF; - wd[0] = (a->exp & 0777) | (a->lo & UFP_FL_SMASK); /* low frac'exp */ - wd[1] = (a->sign << 17) | a->hi; /* hi frac */ - numwd = 2; /* 2 words */ - } - } -else { - fmb.lo = (-a->lo) & UFP_FL_MASK; /* 2's complement */ - fmb.hi = (~a->hi + (fmb.lo == 0)) & UFP_FH_MASK; /* to FMB */ - if (ir & FI_DP) { /* dp? */ - if (a->sign) { /* negative? */ - wd[0] = fmb.hi | SIGN; /* store FMB */ - wd[1] = fmb.lo; - } - else { /* pos, store FMA */ - wd[0] = a->hi; - wd[1] = a->lo; - } - numwd = 2; /* 2 words */ - } - else { /* single */ - if (a->hi || (a->lo & SIGN)) /* check int ovf */ - return FP_OVF; - if (a->sign) /* neg? store FMB */ - wd[0] = fmb.lo; - else wd[0] = a->lo; /* pos, store FMA */ - numwd = 1; /* 1 word */ - } - } -for (i = 0; i < numwd; i++) { /* store words */ - if (Write (addr, wd[i], WR)) - return FP_MM; - addr = (addr + 1) & AMASK; - } -return FP_OK; -} - -/* Integer arithmetic routines */ - -/* Integer add - overflow only on add, if carry out of high fraction */ - -t_stat fp15_iadd (int32 ir, UFP *a, UFP *b, t_bool sub) -{ -fmq.hi = fmq.lo = 0; /* clear FMQ */ -if (a->sign ^ b->sign ^ sub) /* eff subtract? */ - dp_sub (a, b); -else { - dp_add (a, b); /* no, add */ - if (a->hi & UFP_FH_CARRY) { /* carry out? */ - a->hi = a->hi & UFP_FH_MASK; /* mask to 35b */ - return FP_OVF; /* overflow */ - } - } -fp15_asign (ir, a); /* adjust A sign */ -return FP_OK; -} - -/* Integer multiply - overflow if high result (FMQ after swap) non-zero */ - -t_stat fp15_imul (int32 ir, UFP *a, UFP *b) -{ -a->sign = a->sign ^ b->sign; /* sign of result */ -dp_mul (a, b); /* a'FMQ <- a * b */ -dp_swap (a, &fmq); /* swap a, FMQ */ -if (fmq.hi | fmq.lo) /* FMQ != 0? ovf */ - return FP_OVF; -fp15_asign (ir, a); /* adjust A sign */ -return FP_OK; -} - -/* Integer divide - actually done as fraction divide - - - If divisor zero, error - - If dividend zero, done - - Normalize dividend and divisor together - - If divisor normalized but dividend not, result is zero - - If divisor not normalized, normalize and count shifts - - Do fraction divide for number of shifts, +1, steps - - Note that dp_lsh_1 returns a 72b result; the last right shift - guarantees a 71b remainder. The quotient cannot exceed 71b */ - -t_stat fp15_idiv (int32 ir, UFP *a, UFP *b) -{ -int32 i, sc; - -a->sign = a->sign ^ b->sign; /* sign of result */ -fmq.hi = fmq.lo = 0; /* clear quotient */ -a->exp = 0; /* clear a exp */ -if ((b->hi | b->lo) == 0) /* div by 0? */ - return FP_DIV; -if ((a->hi | a->lo) == 0) /* div into 0? */ - return FP_OK; -while (((a->hi & UFP_FH_NORM) == 0) && /* normalize divd */ - ((b->hi & UFP_FH_NORM) == 0)) { /* and divr */ - dp_lsh_1 (a, NULL); /* lsh divd, divr */ - dp_lsh_1 (b, NULL); /* can't carry out */ - } -if (!(a->hi & UFP_FH_NORM) && (b->hi & UFP_FH_NORM)) { /* divr norm, divd not? */ - dp_swap (a, &fmq); /* quo = 0 (fmq), rem = a */ - return FP_OK; - } -while ((b->hi & UFP_FH_NORM) == 0) { /* normalize divr */ - dp_lsh_1 (b, NULL); /* can't carry out */ - a->exp = a->exp + 1; /* count steps */ - } -sc = a->exp; -for (i = 0; i <= sc; i++) { /* n+1 steps */ - dp_lsh_1 (&fmq, NULL); /* left shift quo */ - if (dp_cmp (a, b) >= 0) { /* sub work? */ - dp_sub (a, b); /* a -= b */ - if (i == 0) /* first step? */ - a->exp = a->exp + 1; - fmq.lo = fmq.lo | 1; /* set quo bit */ - } - dp_lsh_1 (a, NULL); /* left shift divd */ - } -dp_rsh_1 (a, NULL); /* shift back */ -dp_swap (a, &fmq); /* swap a, FMQ */ -fp15_asign (ir, a); /* adjust A sign */ -return FP_OK; -} - -/* Floating point arithmetic routines */ - -/* Floating add - - Special add case, overflow if carry out increments exp out of range - - All cases, overflow/underflow detected in normalize */ - -t_stat fp15_fadd (int32 ir, UFP *a, UFP *b, t_bool sub) -{ -int32 ediff; - -fmq.hi = fmq.lo = 0; /* clear FMQ */ -ediff = a->exp - b->exp; /* exp diff */ -if (((a->hi | a->lo) == 0) || (ediff < -35)) { /* a = 0 or "small"? */ - *a = *b; /* rslt is b */ - a->sign = a->sign ^ sub; /* or -b if sub */ - } -else if (((b->hi | b->lo) != 0) && (ediff <= 35)) { /* b!=0 && ~"small"? */ - if (ediff > 0) /* |a| > |b|? dnorm b */ - dp_dnrm_r (ir, b, ediff); - else if (ediff < 0) { /* |a| < |b|? */ - a->exp = b->exp; /* b exp is rslt */ - dp_dnrm_r (ir, a, -ediff); /* denorm A */ - } - if (a->sign ^ b->sign ^ sub) /* eff sub? */ - dp_sub (a, b); - else { /* eff add */ - dp_add (a, b); /* add */ - if (a->hi & UFP_FH_CARRY) { /* carry out? */ - fguard = a->lo & 1; /* set guard */ - dp_rsh_1 (a, NULL); /* right shift */ - a->exp = a->exp + 1; /* incr exponent */ - if (!(ir & FI_NORND) && fguard) /* rounding? */ - dp_inc (a); - } - } - } /* end if b != 0 */ -fp15_asign (ir, a); /* adjust A sign */ -return fp15_norm (ir, a, NULL, 0); /* norm, no round */ -} - -/* Floating multiply - overflow/underflow detected in normalize */ - -t_stat fp15_fmul (int32 ir, UFP *a, UFP *b) -{ -a->sign = a->sign ^ b->sign; /* sign of result */ -a->exp = a->exp + b->exp; /* exp of result */ -dp_mul (a, b); /* mul fractions */ -fp15_asign (ir, a); /* adjust A sign */ -return fp15_norm (ir, a, &fmq, 1); /* norm and round */ -} - -/* Floating divide - overflow/underflow detected in normalize */ - -t_stat fp15_fdiv (int32 ir, UFP *a, UFP *b) -{ -int32 i; - -a->sign = a->sign ^ b->sign; /* sign of result */ -a->exp = a->exp - b->exp; /* exp of result */ -fmq.hi = fmq.lo = 0; /* clear quotient */ -if (!(b->hi & UFP_FH_NORM)) /* divr not norm? */ - return FP_DIV; -if (a->hi | a->lo) { /* divd non-zero? */ - fp15_norm (0, a, NULL, 0); /* normalize divd */ - for (i = 0; (fmq.hi & UFP_FH_NORM) == 0; i++) { /* until quo */ - dp_lsh_1 (&fmq, NULL); /* left shift quo */ - if (dp_cmp (a, b) >= 0) { /* sub work? */ - dp_sub (a, b); /* a = a - b */ - if (i == 0) - a->exp = a->exp + 1; - fmq.lo = fmq.lo | 1; /* set quo bit */ - } - dp_lsh_1 (a, NULL); /* left shift divd */ - } - dp_rsh_1 (a, NULL); /* shift back */ - dp_swap (a, &fmq); /* swap a, FMQ */ - } -fp15_asign (ir, a); /* adjust A sign */ -return fp15_norm (ir, a, &fmq, 1); /* norm and round */ -} - -/* Floating to integer - overflow only if exponent out of range */ - -t_stat fp15_fix (int32 ir, UFP *a) -{ -int32 i; - -fmq.hi = fmq.lo = 0; /* clear FMQ */ -if (a->exp > 35) /* exp > 35? ovf */ - return FP_OVF; -if (a->exp < 0) /* exp <0 ? rslt 0 */ - a->hi = a->lo = 0; -else { - for (i = a->exp; i < 35; i++) /* denorm frac */ - dp_rsh_1 (a, &fmq); - if (fmq.hi & UFP_FH_NORM) { /* last out = 1? */ - fguard = 1; /* set guard */ - if (!(ir & FI_NORND)) /* round */ - dp_inc (a); - } - } -fp15_asign (ir, a); /* adjust A sign */ -return FP_OK; -} - -/* Double precision routines */ - -/* Double precision add - returns 72b result (including carry) */ - -void dp_add (UFP *a, UFP *b) -{ -a->lo = (a->lo + b->lo) & UFP_FL_MASK; /* add low */ -a->hi = a->hi + b->hi + (a->lo < b->lo); /* add hi + carry */ -return; -} - -/* Double precision increment - returns 72b result (including carry) */ - -void dp_inc (UFP *a) -{ -a->lo = (a->lo + 1) & UFP_FL_MASK; /* inc low */ -a->hi = a->hi + (a->lo == 0); /* propagate carry */ -return; -} - -/* Double precision subtract - result always fits in 71b */ - -void dp_sub (UFP *a, UFP *b) -{ -if (dp_cmp (a,b) >= 0) { /* |a| >= |b|? */ - a->hi = (a->hi - b->hi - (a->lo < b->lo)) & UFP_FH_MASK; - a->lo = (a->lo - b->lo) & UFP_FL_MASK; /* a - b */ - } -else { - a->hi = (b->hi - a->hi - (b->lo < a->lo)) & UFP_FH_MASK; - a->lo = (b->lo - a->lo) & UFP_FL_MASK; /* b - a */ - a->sign = a->sign ^ 1; /* change a sign */ - } -return; -} - -/* Double precision compare - returns +1 (>), 0 (=), -1 (<) */ - -int32 dp_cmp (UFP *a, UFP *b) -{ -if (a->hi < b->hi) - return -1; -if (a->hi > b->hi) - return +1; -if (a->lo < b->lo) - return -1; -if (a->lo > b->lo) - return +1; -return 0; -} - -/* Double precision multiply - returns 70b result in a'fmq */ - -void dp_mul (UFP *a, UFP *b) -{ -int32 i; - -fmq.hi = a->hi; /* FMQ <- a */ -fmq.lo = a->lo; -a->hi = a->lo = 0; /* a <- 0 */ -if ((fmq.hi | fmq.lo) == 0) - return; -if ((b->hi | b->lo) == 0) { - fmq.hi = fmq.lo = 0; - return; - } -for (i = 0; i < 35; i++) { /* 35 iterations */ - if (fmq.lo & 1) /* FMQ<35>? a += b */ - dp_add (a, b); - dp_rsh_1 (a, &fmq); /* rsh a'FMQ */ - } -return; -} - -/* Double (quad) precision left shift - returns 72b (143b) result */ - -void dp_lsh_1 (UFP *a, UFP *b) -{ -int32 t = b? b->hi: 0; - -a->hi = (a->hi << 1) | ((a->lo >> 17) & 1); -a->lo = ((a->lo << 1) | ((t >> 16) & 1)) & UFP_FL_MASK; -if (b) { - b->hi = ((b->hi << 1) | ((b->lo >> 17) & 1)) & UFP_FH_MASK; - b->lo = (b->lo << 1) & UFP_FL_MASK; - } -return; -} - -/* Double (quad) precision right shift - returns 71b (142b) result */ - -void dp_rsh_1 (UFP *a, UFP *b) -{ -if (b) { - b->lo = (b->lo >> 1) | ((b->hi & 1) << 17); - b->hi = (b->hi >> 1) | ((a->lo & 1) << 16); - } -a->lo = (a->lo >> 1) | ((a->hi & 1) << 17); -a->hi = a->hi >> 1; -return; -} - -/* Double precision denormalize and round - returns 71b result */ - -void dp_dnrm_r (int32 ir, UFP *a, int32 sc) -{ -int32 i; - -if (sc <= 0) /* legit? */ - return; -for (i = 0; i < sc; i++) /* dnorm to fmq */ - dp_rsh_1 (a, &fmq); -if (!(ir & FI_NORND) && (fmq.hi & UFP_FH_NORM)) /* round & fmq<1>? */ - dp_inc (a); /* incr a */ -return; -} - -/* Double precision swap */ - -void dp_swap (UFP *a, UFP *b) -{ -int32 t; - -t = a->hi; /* swap fractions */ -a->hi = b->hi; -b->hi = t; -t = a->lo; -a->lo = b->lo; -b->lo = t; -return; -} - -/* Support routines */ - -void fp15_asign (int32 fir, UFP *a) -{ -int32 sgnop = FI_GETSGNOP (fir); - -switch (sgnop) { /* modify FMA sign */ - - case 1: - a->sign = 0; - break; - - case 2: - a->sign = 1; - break; - - case 3: - a->sign = a->sign ^ 1; - break; - - default: - break; - } - -return; -} - -/* FP15 normalization and rounding - - - Do normalization if enabled (NOR phase, part 1) - Normalization also does zero detect - - Do rounding if enabled (NOR phase, part 2) */ - -t_stat fp15_norm (int32 ir, UFP *a, UFP *b, t_bool rnd) -{ -a->hi = a->hi & UFP_FH_MASK; /* mask a */ -a->lo = a->lo & UFP_FL_MASK; -if (b) { /* if b, mask */ - b->hi = b->hi & UFP_FH_MASK; - b->lo = b->lo & UFP_FL_MASK; - } -if (!(ir & FI_NONORM)) { /* norm enabled? */ - if ((a->hi | a->lo) || (b && (b->hi | b->lo))) { /* frac != 0? */ - while ((a->hi & UFP_FH_NORM) == 0) { /* until norm */ - dp_lsh_1 (a, b); /* lsh a'b, no cry */ - a->exp = a->exp - 1; /* decr exp */ - } - } - else a->sign = a->exp = 0; /* true zero */ - } -if (rnd && b && (b->hi & UFP_FH_NORM)) { /* rounding? */ - fguard = 1; /* set guard */ - if (!(ir & FI_NORND)) { /* round enabled? */ - dp_inc (a); /* add 1 */ - if (a->hi & UFP_FH_CARRY) { /* carry out? */ - a->hi = UFP_FH_NORM; /* set hi bit */ - a->exp = a->exp + 1; /* incr exp */ - } - } - } -if (a->exp > (int32) 0377777) /* overflow? */ - return FP_OVF; -if (a->exp < (int32) -0400000) /* underflow? */ - return FP_UNF; -return FP_OK; -} - -/* Exception */ - -t_stat fp15_exc (t_stat sta) -{ -int32 ma, mb; - -if (sta == FP_MM) /* if mm, kill trap */ - trap_pending = 0; -ma = (jea & JEA_EAMASK) + sta - 1; /* JEA address */ -PCQ_ENTRY; /* record branch */ -PC = Incr_addr (PC); /* PC+1 for "JMS" */ -mb = Jms_word (usmd); /* form JMS word */ -if (Write (ma, mb, WR)) /* store */ - return SCPE_OK; -PC = (ma + 1) & IAMASK; /* new PC */ -return SCPE_OK; -} - -/* Reset routine */ - -t_stat fp15_reset (DEVICE *dptr) -{ -jea = 0; -fir = 0; -fguard = 0; -fma.exp = fma.hi = fma.lo = fma.sign = 0; -fmb.exp = fmb.hi = fmb.lo = fmb.sign = 0; -fmq.exp = fmq.hi = fmq.lo = fmq.sign = 0; -return SCPE_OK; -} diff --git a/PDP18B/pdp18b_g2tty.c b/PDP18B/pdp18b_g2tty.c deleted file mode 100644 index 82409b27..00000000 --- a/PDP18B/pdp18b_g2tty.c +++ /dev/null @@ -1,603 +0,0 @@ -/* pdp18b_g2tty.c: PDP-7/9 Bell Labs "GRAPHIC-2" subsystem as a TTY via TELNET - from 13-Sep-15 version of pdp18b_tt1.c - - Copyright (c) 1993-2015, Robert M Supnik - Copyright (c) 2016, Philip L Budne - - 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. - - Doug McIlroy had this to say about the Bell Labs PDP-7 Ken Thompson - created UNIX on: - - The pdp7 was cast off by the visual and acoustics research department. - Bill Ninke et al. built graphic II on it -- a graphics attachment as big - as the pdp7 itself. The disk was an amazing thing about 2' in diameter, - mounted on a horizontal axis. Mystery crashes bedeviled it until somebody - realized that the axis was perpendicular to the loading dock 4 floors - below. A 90-degree turn solved the problem. - - GRAPHICS-2 was a command list based graphics display system, - and included a light pen, a "button box" and status bits - for a "dataphone" interface to speak to a GECOS system. - - The UNIX-7 system driver only uses text display, and reserves 269 - words (holding two characters each; the buffer is 273 words, but - three contain display "setup" commands, and the final word in the - buffer must be a display "TRAP" instruction that ends the display - list). - - The UNIX system code triggers a refresh every 10 60Hz "ticks" of - the real time clock. This driver attempts to do detect new text - and send it to a user who has TELNETed in. - - Thoughts on implementing a web interface: - - 538 characters redisplaying at 6Hz (every 10 "ticks") gives a - bandwith requirement of only 26Kbit, and most refreshes won't - change the screen and could be suppressed. So it seems like it - would be reasonable to create a web interface. - - Make a SIMH TCP server port which implements a tiny HTTP server. - The base URL serves up a skeletal page with (lighted) buttons, - and a "display window". - - And either: - - 1) Use "AJAX": an (invisible)